Dash7Board Code Upgrade Protocol demonstration code.
Dependencies: modem_ref_helper CRC
Diff: main.cpp
- Revision:
- 0:5589104abba0
- Child:
- 1:dd4e18b267a1
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Thu Feb 01 11:42:42 2018 +0000 @@ -0,0 +1,240 @@ +// @autor: jeremie@wizzilab.com +// @date: 2017-12-14 + +#include "modem_ref_helper.h" +#include "modem_callbacks.h" +#include "files.h" +#include "crc.h" + +#define CHUNK_SIZE (128) + +Semaphore modem_ready(0); +Queue<touch_t, 8> g_file_modified; + +// CRC calculated on the incoming data stream +extern uint32_t stream_crc; + +const uint8_t default_root_key[] = {206, 87, 116, 11, 4, 30, 202, 254, 206, 87, 116, 11, 4, 30, 202, 254}; + +void print_resp(uint8_t id, int status) +{ + switch (status) + { + case ALP_ERR_NONE: + //PRINT("Resp[%d]: OK\n", id); + break; + case ALP_ERR_FILE_EXIST: + PRINT("Resp[%d]: Already registered\n", id); + break; + default: + PRINT("Resp[%d]: error %d\n", id, status); + break; + } +} + +modem_callbacks_t callbacks = { + .read = my_read, + .write = my_write, + .read_fprop = my_read_fprop, + .flush = my_flush, + .remove = my_delete, + .udata = my_udata, + .lqual = my_lqual, + .ldown = my_ldown, + .reset = my_reset, + .boot = my_boot +}; + +// Callback +void my_main_callback(uint8_t terminal, int8_t err, uint8_t id) +{ + (void)id; + + print_resp(id, err); + + if (terminal) + { + modem_ready.release(); + } +} + +void thread_file_modified() +{ + touch_t* touch; + osEvent evt; + Timer tim; + uint32_t total = 0; + uint32_t next_chunk = 0; + + uint8_t id = modem_get_id(my_main_callback); + + PRINT("Ready\n"); + + while (true) + { + evt = g_file_modified.get(); + touch = (evt.status == osEventMessage)? (touch_t*)evt.value.p : NULL; + ASSERT(touch != NULL, "NULL touch pointer!\n"); + + switch (touch->fid) + { + case FID_APP_CUP_CFG: + cup_cfg_t cup_cfg; + + ram_fs_read(FID_APP_CUP_CFG, 0, sizeof(cup_cfg_t), (uint8_t*)&cup_cfg); + + if (CUP_CMD_UPGRADE_FILE_START == cup_cfg.cmd) + { + PRINT("Enter upload mode. Watchdog %ds\n", cup_cfg.arch_nb); + + tim.reset(); + tim.start(); + total = 0; + next_chunk = 0; + stream_crc = 0; + + // Write to the modem CUP config file (as root) + // to enter upload mode + cup_cfg.cmd = CUP_CMD_UPGRADE_UPLOAD; + modem_write_file_root(FID_CUP_CFG, (uint8_t*)&cup_cfg, 0, 4, (uint8_t*)default_root_key, id); + modem_ready.wait(); + } + else if (CUP_CMD_UPGRADE_FILE_END == cup_cfg.cmd) + { + float time_s = tim.read(); + uint32_t expected_size = cup_cfg.src_offset; + uint32_t expected_crc = cup_cfg.signature; + + PRINT("Done. %d/%d bytes received in %.2f sec (%.2f kb/s)\r\n" + "Expected CRC 0x%08X. Stream CRC 0x%08X.\r\n", + total, expected_size, time_s, (total/time_s)/1024.0, + expected_crc, stream_crc); + + tim.stop(); + + // Compare expected crc with received data crc + if (stream_crc == expected_crc) + { + PRINT("Received complete binary.\n"); + } + else + { + PRINT("Missed or corrupted data in this session.\n"); + } + + + // Actual check is done here since we could have received some of the missed data in a previous session. + + /******************************/ + /* Compute CRC on saved data. */ + /******************************/ + + // If you have the full binary data, + // You can use this function to compute CRC + //binary_crc = crc32((char*)binary_data, expected_size); + + // Else just do a loop and a fast CRC on data chunks like in my_write + } + else + { + PRINT("CUP command 0x%04X\n", cup_cfg.cmd); + } + + break; + case FID_APP_CUP_CODE: + // Chunk data should be saved in my_write callback + PRINT("Got CUP code chunk length %d offset %d\n", touch->length, touch->offset); + + total += touch->length; + + if (next_chunk != touch->offset) + { + PRINT("Missed %d chunk(s) at offset %d (got offset %d)\n", (touch->offset - next_chunk) / CHUNK_SIZE, next_chunk, touch->offset); + } + next_chunk = touch->offset + touch->length; + + // Notify modem code file to reset upload watchdog + // else the device will exit upload mode after the watchdog timeout + modem_notify_file(FID_CUP_CODE, 0, 1, id); + modem_ready.wait(); + + break; + default: + PRINT("TOUCH FID %d OFF %d LEN %d\n", touch->fid, touch->offset, touch->length); + break; + } + + FREE(touch); + } +} + +/*** Main function ------------------------------------------------------------- ***/ +int main() { + // Start & initialize +#ifdef DEBUG_LED + DBG_OPEN(DEBUG_LED); +#else + DBG_OPEN(NC); +#endif + PRINT("\n" + "-----------------------------------------\n" + "---------------- Demo CUP ---------------\n" + "-----------------------------------------\n"); + + modem_helper_open(&callbacks); + + PRINT("--------------- APP infos ---------------\r\n"); + PRINT(" - Manufacturer ID: %08X\r\n", f_rev.manufacturer_id); + PRINT(" - Device ID: %08X\r\n", f_rev.device_id); + PRINT(" - Hardware version: %08X\r\n", f_rev.hw_version); + PRINT(" - Firmware version: v%d.%d.%d [%02X]\r\n", f_rev.fw_version.major, f_rev.fw_version.minor, f_rev.fw_version.patch, f_rev.fw_version.id); + PRINT(" - CUP max size: %d\r\n", f_rev.cup_max_size); + PRINT("-----------------------------------------\r\n"); + + uint8_t id = modem_get_id(my_main_callback); + + PRINT("Register Files\n"); + modem_update_file(FID_HOST_REV, (alp_file_header_t*)&h_rev, (uint8_t*)&f_rev); + modem_update_file(FID_APP_CUP_CFG, (alp_file_header_t*)&h_cup_cfg, (uint8_t*)&f_cup_cfg); + + // Declare the cup code file + // It needs a special handling of its data in my_write callback since we want to keep them. + // (can't be done with the current RAM file system) + modem_declare_file(FID_APP_CUP_CODE, (alp_file_header_t*)&h_cup_code, true, id); + modem_ready.wait(); + + PRINT("Start D7A Stack\n"); + //modem_activate_itf(ALP_ITF_TYPE_D7A, 24, 0, ALP_D7A_ISTAT_RESP | ALP_D7A_ISTAT_UNS, true, id); + modem_activate_itf(ALP_ITF_TYPE_D7A, 24, 0, 0, true, id); + modem_ready.wait(); + + PRINT("Notify Modem Version\n"); + modem_notify_file(D7A_FID_FIRMWARE_VERSION, 0, SIZE_HOST_REV, id); + modem_ready.wait(); + + PRINT("Notify Host Version\n"); + modem_notify_file(FID_HOST_REV, 0, SIZE_HOST_REV, id); + modem_ready.wait(); + + // id no longer needed + modem_free_id(id); + + // Start file modified thread + Thread th_file_modified(osPriorityNormal, 1024, NULL); + osStatus status = th_file_modified.start(thread_file_modified); + ASSERT(status == osOK, "Failed to start thread_file_modified (err: %d)\r\n", status); + +#ifdef DEBUG_LED + DigitalOut my_led(DEBUG_LED); +#endif + + // Set main task to lowest priority + osThreadSetPriority(osThreadGetId(), osPriorityIdle); + while(true) + { + Thread::wait(500); +#ifdef DEBUG_LED + my_led = !my_led; +#endif + } +} \ No newline at end of file