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

Revision:
75:dad2f09cb870
--- /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