Program to update the D7A modem's firmware.

Dependencies:   modem_ref_helper DebouncedInterrupt

main.cpp

Committer:
Jeej
Date:
2019-08-20
Revision:
32:e3ee65b5b835
Parent:
29:aa16a927f0eb
Child:
33:9cd782e2b423

File content as of revision 32:e3ee65b5b835:

#include "DebouncedInterrupt.h"
#include "modem_ref_helper.h"
#include "modem_callbacks.h"
#include "bin.h"
#include "cup.h"


// To udate your firmware:
// - Specify your root key
// - Choose your Hardware in bin.h
// - Program your NUCLEO with your modem stacked
// - Follow the instructions printed on the debug port


// This is the default root key
// if you have changed this key, please specify it here
uint8_t root_key[CUP_DEFAULT_KEY_SIZE] = CUP_DEFAULT_KEY;
uint8_t root_key_size = CUP_DEFAULT_KEY_SIZE;

// Semaphore for notifiying button presses
Semaphore button_user(0);
Semaphore modem_ready(0);

// Interrupt Service Routine on button press.
void button_push_isr( void )
{
    button_user.release();
}

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;
    }
}

void print_check_rev(void)
{
    PRINT("\r\n"
          "/!\\ Please, check that you are at the right commit in the mbed revision tree /!\\\r\n"
    );
}

void print_check_hardware(void)
{
    PRINT("Please, check that you chose the right Hardware in bin.h\r\n");
}

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;
}

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,
    .busy       = my_busy,
};

// Callback for g_main_id User
void my_main_callback(uint8_t terminal, int8_t err, uint8_t id)
{
    (void)id;
    
    if (terminal)
    {
        if (err)
        {
            PRINT("Done err %d\n", err);
            FLUSH();
            while(1);
        }
        modem_ready.release();
    }
    else if (err)
    {
        PRINT("Got err %d\n", err);
        FLUSH();
        while(1);
    }
}

uint8_t g_main_id;

int main()
{
    bool bootloader;
    revision_t rev;
    cup_param_t* cup = (cup_param_t*)&cup_modem;
    int32_t cup_slack = 0;
    
    // Start & initialize
#ifdef DEBUG_LED
    DBG_OPEN(DEBUG_LED);
#else
    DBG_OPEN(NC);
#endif
    PRINT("\r\n"
          "-----------------------------------------\r\n"
          "------------- D7A WM Updater ------------\r\n"
          "-----------------------------------------\r\n");
          
    PRINT("SystemCoreClock is %d Hz\r\n", SystemCoreClock);  

#ifdef DEBUG_BUTTON
    DebouncedInterrupt user_interrupt(DEBUG_BUTTON);
    user_interrupt.attach(button_push_isr, IRQ_FALL, 200, true);
#endif

    modem_helper_open(&callbacks);
    
    g_main_id = modem_get_id(my_main_callback);
    
    do
    {
        // Check modem revision
        modem_read_file(D7A_FID_FIRMWARE_VERSION, &rev, 0, sizeof(revision_t), g_main_id);
        modem_ready.acquire();
        
        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 == BOOTLOADER_DEV_ID)
        {
            // Update bootloader
            PRINT("\r\n"
                  "/!\\ This modem has a bootloader firmware.       /!\\\r\n"
                  "/!\\ Step 2/2: Upgrading to full modem firmware. /!\\\r\n"
                  );
            
            /*
            cup_slack = check_slack(rev.cup_max_size, cup->data_size);
            
            if (cup_slack < 0)
            {
                PRINT("/!\\ Not enough space for firmware /!\\\r\n");
                break;
            }
            */
            
            cup_start_update(0);
        }
        else
        {
            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;

            // Update modem
            if (check_parameter("Device ID...             ", rev.device_id, cup->dev_id))
            {
                print_check_rev();
                break;
            }
            
            if (version_old != version_new)
            {
                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
            {
                PRINT("\r\nYour modem is up to date! (v%d.%d.%d)\r\n",
                        rev.fw_version.major, rev.fw_version.minor, rev.fw_version.patch);
            }
            
            cup_slack = check_slack(rev.cup_max_size, cup->data_size);
            
            if (cup_slack < 0)
            {
                PRINT("\r\n"
                      "/!\\ Not enough space for full modem firmware binary. /!\\\r\n"
                      "/!\\ Checking for bootloader firmware.                /!\\\r\n"
                      "\r\n"
                );
                                
                cup_slack = check_slack(rev.cup_max_size, ((cup_param_t*)&cup_bootloader)->data_size);
                
                if (cup_slack < 0)
                {
                    PRINT("/!\\ Not enough space for bootloader /!\\\r\n");
                    break;
                }
                
                bootloader = true;
                
                PRINT("\r\n"
                      "/!\\ This update will be done in 2 steps.                              /!\\\r\n"
                      "/!\\ Step 1/2: Upgrading modem to bootloader.                          /!\\\r\n"
                      "/!\\ Do no push the reset button or turn off the board during upgrade. /!\\\r\n"
                      );
            }
            else
            {
                bootloader = false;
            }
            
            if (version_old > version_new)
            {
                PRINT("/!\\ Your modem is at a more recent version (v%d.%d.%d)/!\\\r\n"
                      "/!\\ Are you sure you want to downgrade to 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 CONFIRM...\r\n");
                button_user.acquire();
#endif
                PRINT("\r\nDowngrading 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 DOWNGRADE...\r\n");
                button_user.acquire();
#endif
            }
            else if (version_old != version_new)
            {
                PRINT("\r\nUpgrading 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
            }
            else
            {
#ifdef DEBUG_BUTTON
                PRINT("\r\nReseting 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);
                PRINT("PRESS USER BUTTON TO START RESET...\r\n");
                button_user.acquire();
#else
                // No button to stop code
                break;
#endif
            }
        
            cup_start_update(cup_slack, bootloader);
        }
    
    } while (0);
    
    // Set main task to lowest priority
    osThreadSetPriority(osThreadGetId(), osPriorityLow);
    while(true)
    {
        // Wait to avoid beeing stuck in loop
        ThisThread::sleep_for(200);
    }
}