Helper library to use modem_ref driver.
Dependencies: WizziCom WizziDebug ram_fs modem_ref
Dependents: D7A_Localisation D7A_1x_demo_send_file_data_and_forget D7A_1x_demo_CodeUpgradeProtocol D7A_1x_demo_LoRaWAN ... more
Diff: modem_cup/modem_cup.cpp
- Revision:
- 75:dad2f09cb870
diff -r 99c556ae5b35 -r dad2f09cb870 modem_cup/modem_cup.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/modem_cup/modem_cup.cpp Tue Sep 07 15:59:23 2021 +0000 @@ -0,0 +1,382 @@ +#include "DebouncedInterrupt.h" +#include "modem_cup.h" + +// Semaphore for notifiying button presses +static Semaphore button_user(0); +static Semaphore boot(0); + +uint8_t const modem_data[CUP_DATA_SIZE] = CUP_DATA; +uint8_t const libex_data[LIBEX_DATA_SIZE] = LIBEX_DATA; +uint8_t const bootloader_data[BOOTLOADER_DATA_SIZE] = BOOTLOADER_DATA; + +// Interrupt Service Routine on button press. +static void button_push_isr( void ) +{ + button_user.release(); +} + +static void cup_boot(u8 cause, u16 number) +{ + PRINT("Modem BOOT[%c] #%d\r\n", cause, number); + boot.release(); +} + +cup_param_t const cup_modem = { + .data = (uint8_t*)modem_data, + .cfg_fid = CUP_CFG_FID, + .code_fid = CUP_CODE_FID, + .code_size = CUP_CODE_SIZE, + .data_size = CUP_DATA_SIZE, + .local_mtu = CUP_LOCAL_MTU, + .nb_archives = CUP_NB_ARCHIVES, + .signature = CUP_SIGNATURE, + .mfg_id = CUP_MFG_ID, + .dev_id = CUP_DEV_ID, + .hw_id = CUP_HW_ID, + .fw_major = CUP_FW_MAJOR, + .fw_minor = CUP_FW_MINOR, + .fw_patch = CUP_FW_PATCH, + .fw_hash = CUP_FW_HASH, + .target_fw_major = CUP_TARGET_FW_MAJOR, + .target_fw_minor = CUP_TARGET_FW_MINOR, + .target_fw_patch = 0, + .target_fw_hash = 0, +}; + +cup_param_t const cup_libex = { + .data = (uint8_t*)libex_data, + .cfg_fid = CUP_CFG_FID, + .code_fid = CUP_CODE_FID, + .code_size = CUP_CODE_SIZE, + .data_size = LIBEX_DATA_SIZE, + .local_mtu = CUP_LOCAL_MTU, + .nb_archives = 1, + .signature = LIBEX_SIGNATURE, + .mfg_id = CUP_MFG_ID, + .dev_id = CUP_DEV_ID, + .hw_id = CUP_HW_ID, + .fw_major = CUP_FW_MAJOR, + .fw_minor = CUP_FW_MINOR, + .fw_patch = CUP_FW_PATCH, + .fw_hash = CUP_FW_HASH, + .target_fw_major = CUP_FW_MAJOR, + .target_fw_minor = CUP_FW_MINOR, + .target_fw_patch = CUP_FW_PATCH, + .target_fw_hash = CUP_FW_HASH, +}; + +cup_param_t const cup_bootloader = { + .data = (uint8_t*)bootloader_data, + .cfg_fid = BOOTLOADER_CFG_FID, + .code_fid = BOOTLOADER_CODE_FID, + .code_size = BOOTLOADER_CODE_SIZE, + .data_size = BOOTLOADER_DATA_SIZE, + .local_mtu = BOOTLOADER_LOCAL_MTU, + .nb_archives = BOOTLOADER_NB_ARCHIVES, + .signature = BOOTLOADER_SIGNATURE, + .mfg_id = BOOTLOADER_MFG_ID, + .dev_id = BOOTLOADER_DEV_ID, + .hw_id = BOOTLOADER_HW_ID, + .fw_major = BOOTLOADER_FW_MAJOR, + .fw_minor = BOOTLOADER_FW_MINOR, + .fw_patch = BOOTLOADER_FW_PATCH, + .fw_hash = BOOTLOADER_FW_HASH, + .target_fw_major = BOOTLOADER_TARGET_FW_MAJOR, + .target_fw_minor = BOOTLOADER_TARGET_FW_MINOR, +}; + +static void modem_cup_start_update(uint32_t offset, cup_param_t* cup) +{ + cup_cfg_t cfg = { + .cmd = 0x10AD, + .arch_nb = 20, + }; + + uint32_t fof = 0; + uint8_t percent = 0; + uint8_t percent_old = 255; + Timer tim; + int32_t rem; + float now = 0; + + float speed_before = 0; + float speed = 0; + int speed_data = 0; + + float time_before = 0; + float time_left = 0; + + float print_before = 0; + + rem = cup->data_size; + + // Start CUP + modem_write_file(cup->cfg_fid, (uint8_t*)&cfg, 0, 4); + + // Upload file + PRINT("Uploading %d bytes to CUP file. (offset %d)\r\n", cup->data_size, offset); + + tim.start(); + + while (rem > 0) + { + int32_t chunk = (rem > cup->local_mtu)? cup->local_mtu : rem; + modem_write_file(cup->code_fid, &(cup->data[fof]), fof + offset, chunk); + rem -= chunk; + fof += chunk; + + now = tim.read(); + speed_data += chunk; + + // Update speed + if (now - speed_before > 1.0 || speed_before == 0) + { + speed = (speed_data/(now - speed_before))/1024.0; + speed_before = now; + speed_data = 0; + } + + // Update time left + if (now - time_before > 0.2 || time_before == 0 || rem == 0) + { + time_before = now; + time_left = (rem / speed) / 1024.0; + } + + // Print + if (now - print_before > 0.1 || print_before == 0 || rem == 0) + { + percent = (100*fof)/cup->data_size; + print_before = now; + PRINT("\rUPLOADING NEW FIRMWARE %d/%d (%3d%%) %.2f kB/s %.0fs ", fof, cup->data_size, percent, speed, time_left); + } + } + + PRINT("\n"); + + float time_s = tim.read(); + PRINT("CUP: %d bytes written in %.2f sec (%.2f kB/s)\r\n", cup->data_size, time_s, (cup->data_size/time_s)/1024.0); + + // Force PFLASH-cache flushing + modem_flush_file(cup->code_fid); + + // Send Upgrade command + cfg.cmd = 0xC0D5; + cfg.arch_nb = cup->nb_archives; + cfg.src_offset = offset; + cfg.signature = cup->signature; + + modem_write_file(cup->cfg_fid, (uint8_t*)&cfg, 0, 12); + + PRINT("Waiting self reboot...\r\n"); + + boot.acquire(); +} + +static uint8_t check_parameter(const char* str, uint32_t param1, uint32_t param2) +{ + PRINT("Checking %s ", str); + if (param1 != param2) + { + PRINT("Failed. (0x%08X != 0x%08X)\r\n", param1, param2); + return 1; + } + else + { + PRINT("OK. (0x%08X)\r\n", param1); + return 0; + } +} + +static void print_check_rev(void) +{ + PRINT("\r\n" + "/!\\ Please, check that you are at the right commit in the mbed revision tree /!\\\r\n" + ); +} + +static void print_check_hardware(void) +{ + PRINT("Please, check that you chose the right Hardware in bin.h\r\n"); +} + +static int32_t check_slack(uint32_t cup_max_size, uint32_t cup_data_size) +{ + //PRINT("key: %d data: %d code: %d src: %d\r\n", cup_cfg->key, cup->data_size, cup->code_size, cup_cfg->src_offset); + PRINT("Checking CUP Slack... "); + + //int32_t data_size = (((cup->data_size/256)+1)*256); + int32_t cup_slack = cup_max_size - cup_data_size; + + cup_slack = ((cup_slack/256)*256); + + if (cup_slack < 0) + { + PRINT("Failed. (%d bytes short)\r\n", -cup_slack); + } + else + { + PRINT("OK. (%d bytes)\r\n", cup_slack); + } + + return cup_slack; +} + +static int modem_cup_check(revision_t* rev, cup_param_t* cup) +{ + int cup_slack = -1; + + do + { + // Check modem revision + if (check_parameter("Manufacturer ID... ", rev->manufacturer_id, cup->mfg_id)) + { + print_check_rev(); + break; + } + + if (check_parameter("Hardware version... ", rev->hw_version, cup->hw_id)) + { + print_check_hardware(); + break; + } + + if (rev->device_id != cup->dev_id) + { + // Update bootloader + PRINT("\r\n" + "/!\\ Not a modem firmware. /!\\\r\n" + ); + break; + } + else + { + // Update modem + if (check_parameter("Device ID... ", rev->device_id, cup->dev_id)) + { + print_check_rev(); + break; + } + + if (&cup_libex != cup) + { + PRINT("Checking Firmware version major... "); + if (rev->fw_version.major < cup->target_fw_major) + { + PRINT("Failed. (0x%08X != 0x%08X)\r\n", rev->fw_version.major, cup->target_fw_major); + print_check_rev(); + break; + } + else + { + PRINT("OK. (0x%08X)\r\n", rev->fw_version.major); + } + + PRINT("Checking Firmware version minor... "); + if (rev->fw_version.minor < cup->target_fw_minor && rev->fw_version.major == cup->target_fw_major) + { + PRINT("Failed. (0x%08X != 0x%08X)\r\n", rev->fw_version.minor, cup->target_fw_minor); + print_check_rev(); + break; + } + else + { + PRINT("OK. (0x%08X)\r\n", rev->fw_version.minor); + } + } + else + { + if (check_parameter("Firmware version major...", rev->fw_version.major, cup->target_fw_major)) + { + print_check_rev(); + break; + } + + if (check_parameter("Firmware version minor...", rev->fw_version.minor, cup->target_fw_minor)) + { + print_check_rev(); + break; + } + + if (check_parameter("Firmware version patch...", rev->fw_version.patch, cup->target_fw_patch)) + { + print_check_rev(); + break; + } + + if (check_parameter("Firmware version hash... ", rev->fw_version.hash, cup->target_fw_hash)) + { + print_check_rev(); + break; + } + } + + cup_slack = check_slack(rev->cup_max_size, cup->data_size); + + if (cup_slack < 0) + { + PRINT("\r\n" + "/!\\ Not enough space for modem firmware binary. /!\\\r\n" + "\r\n" + ); + break; + } + } + + return cup_slack; + + } while (0); + + FLUSH(); + while(true) + { + ThisThread::sleep_for(500); + } +} + +void modem_cup_update(revision_t* rev) +{ + bool bootloader; + cup_param_t* cup = (cup_param_t*)&cup_modem; + int32_t cup_slack = 0; + uint32_t version_old = (rev->fw_version.major << 24) | (rev->fw_version.minor << 16) | rev->fw_version.patch; + uint32_t version_new = (cup->fw_major << 24) | (cup->fw_minor << 16) | cup->fw_patch; + + if (version_old < version_new) + { +#ifdef DEBUG_BUTTON + DebouncedInterrupt user_interrupt(DEBUG_BUTTON); + user_interrupt.attach(button_push_isr, IRQ_FALL, 200, true); +#endif + modem_ref_set_boot_cb(cup_boot); + + cup_slack = modem_cup_check(rev, cup); + + PRINT("\r\nYour modem version is behind the recommended version for this driver."); + PRINT("\r\nUpgrading modem firmware: v%d.%d.%d --> v%d.%d.%d\r\n", + rev->fw_version.major, rev->fw_version.minor, rev->fw_version.patch, + cup->fw_major, cup->fw_minor, cup->fw_patch); +#ifdef DEBUG_BUTTON + PRINT("PRESS USER BUTTON TO START UPGRADE...\r\n"); + button_user.acquire(); +#endif + modem_cup_start_update(cup_slack, cup); + + if (LIBEX_NB_ARCHIVES) + { + ThisThread::sleep_for(500); + PRINT("Updating Libex...\r\n"); + + modem_read_file(D7A_FID_FIRMWARE_VERSION, (uint8_t*)rev, 0, sizeof(revision_t)); + + cup = (cup_param_t*)&cup_libex; + cup_slack = modem_cup_check(rev, cup); + + modem_cup_start_update(cup_slack, cup); + } + + PRINT("Restarting application...\r\n"); + FLUSH(); + NVIC_SystemReset(); + } +} \ No newline at end of file