dfu: use task to handle download

This commit is contained in:
King Kévin 2022-07-24 15:51:30 +02:00
parent d120cb1c24
commit 78a85cdb5b
1 changed files with 76 additions and 30 deletions

View File

@ -31,7 +31,6 @@
#include "bsp/board.h"
#include "tusb.h"
#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)
// ESP-IDF need "freertos/" prefix in include path.
// CFG_TUSB_OS_INC_PATH should be defined accordingly.
@ -88,6 +87,54 @@ void usb_device_task(void* param);
// used to download image onto OTA partition
esp_ota_handle_t ota_handle = 0;
// download blocks to program
static uint8_t dl_block[CFG_TUD_DFU_XFER_BUFSIZE] = {0};
static uint16_t dl_block_len = 0;
static uint16_t dl_block_num = 0;
// task taking care of flashing during download
// note: esp_ota_begin erase flash, which takes too long to be in tud_dfu_download_cb, causing a USB timeout, thus it's in a task
static void dl_task(void* arg)
{
esp_err_t rc;
while (true) {
if (dl_block_len) { // we received a new block
// get handle for OTA update
if (0 == ota_handle) {
const esp_partition_t *ota_part = esp_ota_get_next_update_partition(NULL);
if (NULL == ota_part) {
ESP_LOGE(TAG, "OTA not found");
tud_dfu_finish_flashing(DFU_STATUS_ERR_PROG);
return;
}
rc = esp_ota_begin(ota_part, OTA_SIZE_UNKNOWN, &ota_handle);
if (ESP_OK != rc) {
ESP_LOGE(TAG, "init OTA failed");
esp_ota_abort(ota_handle);
ota_handle = 0;
tud_dfu_finish_flashing(DFU_STATUS_ERR_ERASE);
return;
}
}
// write data to partition
rc = esp_ota_write_with_offset(ota_handle, dl_block, dl_block_len, dl_block_num * CFG_TUD_DFU_XFER_BUFSIZE);
if (ESP_OK != rc) {
ESP_LOGE(TAG, "writing OTA failed");
esp_ota_abort(ota_handle);
ota_handle = 0;
tud_dfu_finish_flashing(DFU_STATUS_ERR_WRITE);
return;
}
dl_block_len = 0; // ready for next block
tud_dfu_finish_flashing(DFU_STATUS_OK); // flashing op for download complete without error
} else { // no new block
vTaskDelay(1); // allow other tasks to run (and watchdog reset)
}
}
}
//--------------------------------------------------------------------+
// Main
//--------------------------------------------------------------------+
@ -118,6 +165,9 @@ int main(void)
vTaskStartScheduler();
#endif
// create task to handle download progress
xTaskCreate(dl_task, "dl_task", 2 * 1024, NULL, 8, NULL);
ESP_LOGI(TAG, "DFU mode");
return 0;
@ -196,46 +246,42 @@ uint32_t tud_dfu_get_timeout_cb(uint8_t alt, uint8_t state)
void tud_dfu_download_cb(uint8_t alt, uint16_t block_num, uint8_t const* data, uint16_t length)
{
esp_err_t rc;
static bool dl_started = false;
ESP_LOGD(TAG, "download, alt=%u block=%u", alt, block_num);
if (alt > 0)
{
if (alt > 0) {
ESP_LOGW(TAG, "download to invalid alt %u", alt);
tud_dfu_finish_flashing(DFU_STATUS_ERR_ADDRESS);
return;
}
// get handle for OTA update
if (0 == ota_handle) {
const esp_partition_t *ota_part = esp_ota_get_next_update_partition(NULL);
if (NULL == ota_part) {
ESP_LOGE(TAG, "OTA not found");
tud_dfu_finish_flashing(DFU_STATUS_ERR_PROG);
return;
}
rc = esp_ota_begin(ota_part, OTA_SIZE_UNKNOWN, &ota_handle);
if (ESP_OK != rc) {
ESP_LOGE(TAG, "init OTA failed");
esp_ota_abort(ota_handle);
if (0 == length) { // there is nothing to programm
// finish flashing
if (ota_handle) {
rc = esp_ota_end(ota_handle);
ota_handle = 0;
tud_dfu_finish_flashing(DFU_STATUS_ERR_PROG);
return;
if (ESP_OK != rc) {
ESP_LOGE(TAG, "close OTA failed");
tud_dfu_finish_flashing(DFU_STATUS_ERR_PROG);
return;
}
}
}
xTimerChangePeriod(blinky_tm, pdMS_TO_TICKS(BLINK_DOWNLOAD), 0);
// write data to partition
rc = esp_ota_write_with_offset(ota_handle, data, length, block_num * CFG_TUD_DFU_XFER_BUFSIZE);
if (ESP_OK != rc) {
ESP_LOGE(TAG, "writing OTA failed");
esp_ota_abort(ota_handle);
ota_handle = 0;
dl_started = false;
tud_dfu_finish_flashing(DFU_STATUS_OK); // flashing op for download complete without error
} else if (length > CFG_TUD_DFU_XFER_BUFSIZE) { // more data than we can handle
tud_dfu_finish_flashing(DFU_STATUS_ERR_PROG);
return;
} else if (dl_block_len) { // there is already a block to programm
tud_dfu_finish_flashing(DFU_STATUS_ERR_STALLEDPKT);
} else { // all is fine to programm
if (!dl_started) {
xTimerChangePeriod(blinky_tm, pdMS_TO_TICKS(BLINK_DOWNLOAD), 0);
dl_started = true;
}
memcpy(dl_block, data, length); // copy data for dl_task
dl_block_num = block_num; // remember offset
dl_block_len = length; // notitfy dl_task block is ready
}
// flashing op for download complete without error
tud_dfu_finish_flashing(DFU_STATUS_OK);
}
// Invoked when download process is complete, received DFU_DNLOAD (wLength=0) following by DFU_GETSTATUS (state=Manifest)