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 "bsp/board.h"
#include "tusb.h" #include "tusb.h"
#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) #if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)
// ESP-IDF need "freertos/" prefix in include path. // ESP-IDF need "freertos/" prefix in include path.
// CFG_TUSB_OS_INC_PATH should be defined accordingly. // 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 // used to download image onto OTA partition
esp_ota_handle_t ota_handle = 0; 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 // Main
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
@ -118,6 +165,9 @@ int main(void)
vTaskStartScheduler(); vTaskStartScheduler();
#endif #endif
// create task to handle download progress
xTaskCreate(dl_task, "dl_task", 2 * 1024, NULL, 8, NULL);
ESP_LOGI(TAG, "DFU mode"); ESP_LOGI(TAG, "DFU mode");
return 0; 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) void tud_dfu_download_cb(uint8_t alt, uint16_t block_num, uint8_t const* data, uint16_t length)
{ {
esp_err_t rc; esp_err_t rc;
static bool dl_started = false;
ESP_LOGD(TAG, "download, alt=%u block=%u", alt, block_num); 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); ESP_LOGW(TAG, "download to invalid alt %u", alt);
tud_dfu_finish_flashing(DFU_STATUS_ERR_ADDRESS); tud_dfu_finish_flashing(DFU_STATUS_ERR_ADDRESS);
return; return;
} }
// get handle for OTA update if (0 == length) { // there is nothing to programm
if (0 == ota_handle) { // finish flashing
const esp_partition_t *ota_part = esp_ota_get_next_update_partition(NULL); if (ota_handle) {
if (NULL == ota_part) { rc = esp_ota_end(ota_handle);
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; ota_handle = 0;
tud_dfu_finish_flashing(DFU_STATUS_ERR_PROG); if (ESP_OK != rc) {
return; ESP_LOGE(TAG, "close OTA failed");
tud_dfu_finish_flashing(DFU_STATUS_ERR_PROG);
return;
}
} }
} dl_started = false;
xTimerChangePeriod(blinky_tm, pdMS_TO_TICKS(BLINK_DOWNLOAD), 0); 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
// 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;
tud_dfu_finish_flashing(DFU_STATUS_ERR_PROG); 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) // Invoked when download process is complete, received DFU_DNLOAD (wLength=0) following by DFU_GETSTATUS (state=Manifest)