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

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers modem_cup.cpp Source File

modem_cup.cpp

00001 #include "DebouncedInterrupt.h"
00002 #include "modem_cup.h"
00003 
00004 // Semaphore for notifiying button presses
00005 static Semaphore button_user(0);
00006 static Semaphore boot(0);
00007 
00008 uint8_t const modem_data[CUP_DATA_SIZE] = CUP_DATA;
00009 uint8_t const libex_data[LIBEX_DATA_SIZE] = LIBEX_DATA;
00010 uint8_t const bootloader_data[BOOTLOADER_DATA_SIZE] = BOOTLOADER_DATA;
00011 
00012 // Interrupt Service Routine on button press.
00013 static void button_push_isr( void )
00014 {
00015     button_user.release();
00016 }
00017 
00018 static void cup_boot(u8 cause, u16 number)
00019 {
00020     PRINT("Modem BOOT[%c] #%d\r\n", cause, number);
00021     boot.release();
00022 }
00023 
00024 cup_param_t const cup_modem = {
00025     .data            = (uint8_t*)modem_data,
00026     .cfg_fid         = CUP_CFG_FID,
00027     .code_fid        = CUP_CODE_FID,
00028     .code_size       = CUP_CODE_SIZE,
00029     .data_size       = CUP_DATA_SIZE,
00030     .local_mtu       = CUP_LOCAL_MTU,
00031     .nb_archives     = CUP_NB_ARCHIVES,
00032     .signature       = CUP_SIGNATURE,
00033     .mfg_id          = CUP_MFG_ID,
00034     .dev_id          = CUP_DEV_ID,
00035     .hw_id           = CUP_HW_ID,
00036     .fw_major        = CUP_FW_MAJOR,
00037     .fw_minor        = CUP_FW_MINOR,
00038     .fw_patch        = CUP_FW_PATCH,
00039     .fw_hash         = CUP_FW_HASH,
00040     .target_fw_major = CUP_TARGET_FW_MAJOR,
00041     .target_fw_minor = CUP_TARGET_FW_MINOR,
00042     .target_fw_patch = 0,
00043     .target_fw_hash  = 0,
00044 };
00045 
00046 cup_param_t const cup_libex = {
00047     .data            = (uint8_t*)libex_data,
00048     .cfg_fid         = CUP_CFG_FID,
00049     .code_fid        = CUP_CODE_FID,
00050     .code_size       = CUP_CODE_SIZE,
00051     .data_size       = LIBEX_DATA_SIZE,
00052     .local_mtu       = CUP_LOCAL_MTU,
00053     .nb_archives     = 1,
00054     .signature       = LIBEX_SIGNATURE,
00055     .mfg_id          = CUP_MFG_ID,
00056     .dev_id          = CUP_DEV_ID,
00057     .hw_id           = CUP_HW_ID,
00058     .fw_major        = CUP_FW_MAJOR,
00059     .fw_minor        = CUP_FW_MINOR,
00060     .fw_patch        = CUP_FW_PATCH,
00061     .fw_hash         = CUP_FW_HASH,
00062     .target_fw_major = CUP_FW_MAJOR,
00063     .target_fw_minor = CUP_FW_MINOR,
00064     .target_fw_patch = CUP_FW_PATCH,
00065     .target_fw_hash  = CUP_FW_HASH,
00066 };
00067 
00068 cup_param_t const cup_bootloader = {
00069     .data            = (uint8_t*)bootloader_data,
00070     .cfg_fid         = BOOTLOADER_CFG_FID,
00071     .code_fid        = BOOTLOADER_CODE_FID,
00072     .code_size       = BOOTLOADER_CODE_SIZE,
00073     .data_size       = BOOTLOADER_DATA_SIZE,
00074     .local_mtu       = BOOTLOADER_LOCAL_MTU,
00075     .nb_archives     = BOOTLOADER_NB_ARCHIVES,
00076     .signature       = BOOTLOADER_SIGNATURE,
00077     .mfg_id          = BOOTLOADER_MFG_ID,
00078     .dev_id          = BOOTLOADER_DEV_ID,
00079     .hw_id           = BOOTLOADER_HW_ID,
00080     .fw_major        = BOOTLOADER_FW_MAJOR,
00081     .fw_minor        = BOOTLOADER_FW_MINOR,
00082     .fw_patch        = BOOTLOADER_FW_PATCH,
00083     .fw_hash         = BOOTLOADER_FW_HASH,
00084     .target_fw_major = BOOTLOADER_TARGET_FW_MAJOR,
00085     .target_fw_minor = BOOTLOADER_TARGET_FW_MINOR,
00086 };
00087 
00088 static void modem_cup_start_update(uint32_t offset, cup_param_t* cup)
00089 {
00090     cup_cfg_t cfg = {
00091         .cmd = 0x10AD,
00092         .arch_nb = 20,
00093     };
00094     
00095     uint32_t fof = 0;
00096     uint8_t percent = 0;
00097     uint8_t percent_old = 255;
00098     Timer tim;
00099     int32_t rem;
00100     float now = 0;
00101     
00102     float speed_before = 0;
00103     float speed = 0;
00104     int speed_data = 0;
00105     
00106     float time_before = 0;
00107     float time_left = 0;
00108     
00109     float print_before = 0;
00110 
00111     rem = cup->data_size;
00112         
00113     // Start CUP
00114     modem_write_file(cup->cfg_fid, (uint8_t*)&cfg, 0, 4);
00115         
00116     // Upload file
00117     PRINT("Uploading %d bytes to CUP file. (offset %d)\r\n", cup->data_size, offset);
00118     
00119     tim.start();
00120     
00121     while (rem > 0)
00122     {
00123         int32_t chunk = (rem > cup->local_mtu)? cup->local_mtu : rem;
00124         modem_write_file(cup->code_fid, &(cup->data[fof]), fof + offset, chunk);
00125         rem -= chunk;
00126         fof += chunk;
00127         
00128         now = tim.read();
00129         speed_data += chunk;
00130         
00131         // Update speed
00132         if (now - speed_before > 1.0 || speed_before == 0)
00133         {
00134             speed = (speed_data/(now - speed_before))/1024.0;
00135             speed_before = now;
00136             speed_data = 0;
00137         }
00138         
00139         // Update time left
00140         if (now - time_before > 0.2 || time_before == 0 || rem == 0)
00141         {
00142             time_before = now;
00143             time_left = (rem / speed) / 1024.0;
00144         }
00145         
00146         // Print
00147         if (now - print_before > 0.1 || print_before == 0 || rem == 0)
00148         {
00149             percent = (100*fof)/cup->data_size;
00150             print_before = now;
00151             PRINT("\rUPLOADING NEW FIRMWARE %d/%d (%3d%%) %.2f kB/s %.0fs    ", fof, cup->data_size, percent, speed, time_left);
00152         }
00153     }
00154     
00155     PRINT("\n");
00156     
00157     float time_s = tim.read();
00158     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);
00159         
00160     // Force PFLASH-cache flushing
00161     modem_flush_file(cup->code_fid);
00162         
00163     // Send Upgrade command
00164     cfg.cmd = 0xC0D5;
00165     cfg.arch_nb = cup->nb_archives;
00166     cfg.src_offset = offset;
00167     cfg.signature = cup->signature;
00168         
00169     modem_write_file(cup->cfg_fid, (uint8_t*)&cfg, 0, 12);
00170     
00171     PRINT("Waiting self reboot...\r\n");
00172 
00173     boot.acquire();
00174 }
00175 
00176 static uint8_t check_parameter(const char* str, uint32_t param1, uint32_t param2)
00177 {
00178     PRINT("Checking %s ", str);
00179     if (param1 != param2)
00180     {
00181         PRINT("Failed. (0x%08X != 0x%08X)\r\n", param1, param2);
00182         return 1;
00183     }
00184     else
00185     {
00186         PRINT("OK. (0x%08X)\r\n", param1);
00187         return 0;
00188     }
00189 }
00190 
00191 static void print_check_rev(void)
00192 {
00193     PRINT("\r\n"
00194           "/!\\ Please, check that you are at the right commit in the mbed revision tree /!\\\r\n"
00195     );
00196 }
00197 
00198 static void print_check_hardware(void)
00199 {
00200     PRINT("Please, check that you chose the right Hardware in bin.h\r\n");
00201 }
00202 
00203 static int32_t check_slack(uint32_t cup_max_size, uint32_t cup_data_size)
00204 {
00205     //PRINT("key: %d data: %d code: %d src: %d\r\n", cup_cfg->key, cup->data_size, cup->code_size, cup_cfg->src_offset);
00206     PRINT("Checking CUP Slack...              ");
00207     
00208     //int32_t data_size = (((cup->data_size/256)+1)*256);
00209     int32_t cup_slack = cup_max_size - cup_data_size;
00210     
00211     cup_slack = ((cup_slack/256)*256);
00212     
00213     if (cup_slack < 0)
00214     {
00215         PRINT("Failed. (%d bytes short)\r\n", -cup_slack);
00216     }
00217     else
00218     {
00219         PRINT("OK. (%d bytes)\r\n", cup_slack);
00220     }
00221     
00222     return cup_slack;
00223 }
00224 
00225 static int modem_cup_check(revision_t* rev, cup_param_t* cup)
00226 {
00227     int cup_slack = -1;
00228     
00229     do
00230     {
00231         // Check modem revision
00232         if (check_parameter("Manufacturer ID...       ", rev->manufacturer_id, cup->mfg_id))
00233         {
00234             print_check_rev();
00235             break;
00236         }
00237         
00238         if (check_parameter("Hardware version...      ", rev->hw_version, cup->hw_id))
00239         {
00240             print_check_hardware();
00241             break;
00242         }
00243         
00244         if (rev->device_id != cup->dev_id)
00245         {
00246             // Update bootloader
00247             PRINT("\r\n"
00248                   "/!\\ Not a modem firmware.                      /!\\\r\n"
00249                   );
00250             break;
00251         }
00252         else
00253         {
00254             // Update modem
00255             if (check_parameter("Device ID...             ", rev->device_id, cup->dev_id))
00256             {
00257                 print_check_rev();
00258                 break;
00259             }
00260             
00261             if (&cup_libex != cup)
00262             {
00263                 PRINT("Checking Firmware version major... ");
00264                 if (rev->fw_version.major < cup->target_fw_major)
00265                 {
00266                     PRINT("Failed. (0x%08X != 0x%08X)\r\n", rev->fw_version.major, cup->target_fw_major);
00267                     print_check_rev();
00268                     break;
00269                 }
00270                 else
00271                 {
00272                     PRINT("OK. (0x%08X)\r\n", rev->fw_version.major);
00273                 }
00274                 
00275                 PRINT("Checking Firmware version minor... ");
00276                 if (rev->fw_version.minor < cup->target_fw_minor && rev->fw_version.major == cup->target_fw_major)
00277                 {
00278                     PRINT("Failed. (0x%08X != 0x%08X)\r\n", rev->fw_version.minor, cup->target_fw_minor);
00279                     print_check_rev();
00280                     break;
00281                 }
00282                 else
00283                 {
00284                     PRINT("OK. (0x%08X)\r\n", rev->fw_version.minor);
00285                 }
00286             }
00287             else
00288             {
00289                 if (check_parameter("Firmware version major...", rev->fw_version.major, cup->target_fw_major))
00290                 {
00291                     print_check_rev();
00292                     break;
00293                 }
00294                 
00295                 if (check_parameter("Firmware version minor...", rev->fw_version.minor, cup->target_fw_minor))
00296                 {
00297                     print_check_rev();
00298                     break;
00299                 }
00300                 
00301                 if (check_parameter("Firmware version patch...", rev->fw_version.patch, cup->target_fw_patch))
00302                 {
00303                     print_check_rev();
00304                     break;
00305                 }
00306                 
00307                 if (check_parameter("Firmware version hash... ", rev->fw_version.hash, cup->target_fw_hash))
00308                 {
00309                     print_check_rev();
00310                     break;
00311                 }
00312             }
00313             
00314             cup_slack = check_slack(rev->cup_max_size, cup->data_size);
00315             
00316             if (cup_slack < 0)
00317             {
00318                 PRINT("\r\n"
00319                       "/!\\ Not enough space for modem firmware binary.     /!\\\r\n"
00320                       "\r\n"
00321                 );
00322                 break;
00323             }
00324         }
00325         
00326         return cup_slack;
00327 
00328     } while (0);
00329     
00330     FLUSH();
00331     while(true)
00332     {
00333         ThisThread::sleep_for(500);
00334     }
00335 }
00336 
00337 void modem_cup_update(revision_t* rev)
00338 {
00339     bool bootloader;
00340     cup_param_t* cup = (cup_param_t*)&cup_modem;
00341     int32_t cup_slack = 0;
00342     uint32_t version_old = (rev->fw_version.major << 24) | (rev->fw_version.minor << 16) | rev->fw_version.patch;
00343     uint32_t version_new = (cup->fw_major << 24) | (cup->fw_minor << 16) | cup->fw_patch;
00344     
00345     if (version_old < version_new)
00346     {
00347 #ifdef DEBUG_BUTTON
00348         DebouncedInterrupt user_interrupt(DEBUG_BUTTON);
00349         user_interrupt.attach(button_push_isr, IRQ_FALL, 200, true);
00350 #endif
00351         modem_ref_set_boot_cb(cup_boot);
00352 
00353         cup_slack = modem_cup_check(rev, cup);
00354         
00355         PRINT("\r\nYour modem version is behind the recommended version for this driver.");
00356         PRINT("\r\nUpgrading modem firmware: v%d.%d.%d --> v%d.%d.%d\r\n", 
00357                 rev->fw_version.major, rev->fw_version.minor, rev->fw_version.patch,
00358                 cup->fw_major, cup->fw_minor, cup->fw_patch);
00359 #ifdef DEBUG_BUTTON
00360         PRINT("PRESS USER BUTTON TO START UPGRADE...\r\n");
00361         button_user.acquire();
00362 #endif
00363         modem_cup_start_update(cup_slack, cup);
00364         
00365         if (LIBEX_NB_ARCHIVES)
00366         {
00367             ThisThread::sleep_for(500);
00368             PRINT("Updating Libex...\r\n");
00369             
00370             modem_read_file(D7A_FID_FIRMWARE_VERSION, (uint8_t*)rev, 0, sizeof(revision_t));
00371             
00372             cup = (cup_param_t*)&cup_libex;
00373             cup_slack = modem_cup_check(rev, cup);
00374             
00375             modem_cup_start_update(cup_slack, cup);
00376         }
00377         
00378         PRINT("Restarting application...\r\n");
00379         FLUSH();
00380         NVIC_SystemReset();
00381     }
00382 }