Dash7Board Code Upgrade Protocol demonstration code.

Dependencies:   modem_ref_helper CRC

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