You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
trezor-firmware/core/embed/lib/ble/dfu.c

138 lines
3.4 KiB

/*
* This file is part of the Trezor project, https://trezor.io/
*
* Copyright (c) SatoshiLabs
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "common.h"
#include TREZOR_BOARD
#include "ble_hal.h"
#include "common.h"
#include "dfu.h"
#include "fwu.h"
const uint32_t TIMEOUT_MS = 2000;
static TFwu sFwu;
static uint32_t tick_start = 0;
void txFunction(struct SFwu *fwu, uint8_t *buf, uint8_t len);
static uint8_t readData(uint8_t *data, int maxLen);
void dfu_init(void) {}
dfu_result_t dfu_update_process(void) {
while (1) {
// Can send 4 chars...
// (On a microcontroller, you'd use the TX Empty interrupt or test a
// register.)
fwuCanSendData(&sFwu, 4);
// Data available? Get up to 4 bytes...
// (On a microcontroller, you'd use the RX Available interrupt or test a
// register.)
uint8_t rxBuf[4];
uint8_t rxLen = readData(rxBuf, 4);
if (rxLen > 0) {
fwuDidReceiveData(&sFwu, rxBuf, rxLen);
}
// Give the firmware update module a timeslot to continue the process.
EFwuProcessStatus status = fwuYield(&sFwu, 0);
if (status == FWU_STATUS_COMPLETION) {
ble_reset();
return DFU_SUCCESS;
}
if (status == FWU_STATUS_FAILURE) {
return DFU_FAIL;
}
if (hal_ticks_ms() - tick_start > TIMEOUT_MS) {
return DFU_FAIL;
}
if (fwuIsReadyForChunk(&sFwu)) {
return DFU_NEXT_CHUNK;
}
}
}
dfu_result_t dfu_update_init(uint8_t *data, uint32_t len, uint32_t binary_len) {
sFwu.commandObject = data;
sFwu.commandObjectLen = len;
sFwu.dataObject = NULL;
sFwu.dataObjectLen = binary_len;
sFwu.txFunction = txFunction;
sFwu.responseTimeoutMillisec = TIMEOUT_MS;
if (!ble_reset_to_bootloader()) {
return DFU_FAIL;
}
tick_start = hal_ticks_ms();
// Prepare the firmware update process.
fwuInit(&sFwu);
// Start the firmware update process.
fwuExec(&sFwu);
return dfu_update_process();
}
dfu_result_t dfu_update_chunk(uint8_t *data, uint32_t len) {
tick_start = hal_ticks_ms();
fwuSendChunk(&sFwu, data, len);
return dfu_update_process();
}
dfu_result_t dfu_update_do(uint8_t *datfile, uint32_t datfile_len,
uint8_t *binfile, uint32_t binfile_len) {
uint32_t chunk_offset = 0;
uint32_t rem_data = binfile_len;
dfu_result_t res = dfu_update_init(datfile, datfile_len, binfile_len);
while (res == DFU_NEXT_CHUNK) {
// Send the next chunk of the data object.
uint32_t chunk_size = 4096;
if (rem_data < 4096) {
chunk_size = rem_data;
rem_data = 0;
} else {
rem_data -= 4096;
}
res = dfu_update_chunk(&binfile[chunk_offset], chunk_size);
chunk_offset += chunk_size;
}
return res;
}
void txFunction(struct SFwu *fwu, uint8_t *buf, uint8_t len) {
ble_comm_send(buf, len);
}
static uint8_t readData(uint8_t *data, int maxLen) {
return ble_comm_receive(data, maxLen);
}