Program to update the D7A modem's firmware.

Dependencies:   modem_ref_helper DebouncedInterrupt

main.cpp

Committer:
Jeej
Date:
2017-09-15
Revision:
21:308466f40058
Parent:
20:100143cecc41
Child:
22:f2b01e5e087e

File content as of revision 21:308466f40058:

#include "mbed.h"
#include "rtos.h"
#include "d7a.h"
#include "dbg.h"
#include "cup.h"
#include "DebouncedInterrupt.h"

// File IDs
#define D7A_FID_FIRMWARE_VERSION        (2)

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

// -----------------------------------------------
// Hardware configuration
// -----------------------------------------------
#if defined(TARGET_STM32L152RE)
    #define D7A_PIN_TX              (D10)
    #define D7A_PIN_RX              (D2)
    #define D7A_PIN_RTS             (D13)
    #define D7A_PIN_CTS             (D9)
    #define D7A_PIN_RESET           (A3)
    #define DEBUG_LED               (NC)
    #define DEBUG_BUTTON            (USER_BUTTON)
#elif defined(TARGET_STM32L432KC)
    #define D7A_PIN_TX              (D5)
    #define D7A_PIN_RX              (D4)
    #define D7A_PIN_RTS             (D11)
    #define D7A_PIN_CTS             (D10)
    #define D7A_PIN_RESET           (D12)
    #define DEBUG_LED               (D13) // LED1
    #define DEBUG_BUTTON            (D9)
#else
    #error "Please choose or add the right platform."
#endif

// callbacks structure
const d7a_callbacks_t callbacks = {
    .write_file = NULL,
    .read_file = NULL,
    .notif_done = NULL,
    .unsolicited_msg = NULL,
};

// Com configuration for the DASH7 shield
const d7a_com_config_t shield_config = {
    .tx  = D7A_PIN_TX,
    .rx  = D7A_PIN_RX,
    .rts = D7A_PIN_RTS,
    .cts = D7A_PIN_CTS,
};

// Semaphore for notifiying button presses
Semaphore button_user(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(cup_param_t* cup, cup_cfg_t* cup_cfg)
{
    //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_cfg->key - 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;
}

int main()
{
    bool bootloader;
    d7a_revision_t rev;
    cup_cfg_t cup_cfg;
    cup_param_t* cup = (cup_param_t*)&cup_modem;
    int32_t cup_slack;
    
    // Start & initialize
    DBG_OPEN(DEBUG_LED);
    PRINT("\r\n"
          "-----------------------------------\r\n"
          "---------- D7A WM Updater ---------\r\n"
          "-----------------------------------\r\n");

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

    d7a_open(&shield_config, D7A_PIN_RESET, &callbacks);
    
    do
    {
        // Check modem revision
        D7A_READ(&rev, D7A_FID_FIRMWARE_VERSION, 0, sizeof(d7a_revision_t), NULL);
        
        if (check_parameter("Manufacturer ID...       ", rev.manufacturer_id, cup->mfg_id))
        {
            print_check_rev();
            break;
        }
        
        if (check_parameter("Hardware version...      ", rev.hw_version&0x00FFFFFF, cup->hw_id))
        {
            print_check_hardware();
            break;
        }
        
        if (rev.device_id == BOOTLOADER_DEV_ID)
        {
            // Update bootloader
            PRINT("\r\n"
                  "/!\\ This modem has a 4.7.x bootloader firmware. /!\\\r\n"
                  "/!\\ Step 2/2: Upgrading to full modem firmware. /!\\\r\n"
                  );
            
            // Read CUP config with root permissions
            D7A_READ(&cup_cfg, cup->cfg_fid, 0, sizeof(cup_cfg_t), root_key);
            
            cup_slack = check_slack(cup, &cup_cfg);
            
            if (cup_slack < 0)
            {
                PRINT("/!\\ Not enough space for bootloader /!\\\r\n");
                break;
            }
                        
            cup_start_update(cup_slack);
        }
        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 (check_parameter("Firmware id...           ", rev.fw_version.id, cup->fw_id))
            {
                print_check_rev();
                break;
            }
            
            if (version_old != version_new)
            {
                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;
                }
            }
            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);
                break;
            }
            
            // Read CUP config with root permissions
            D7A_READ(&cup_cfg, cup->cfg_fid, 0, sizeof(cup_cfg_t), root_key);
            
            cup_slack = check_slack(cup, &cup_cfg);
            
            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((cup_param_t*)&cup_bootloader, &cup_cfg);
                
                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.wait();
#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.wait();
#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.wait();
#endif
            }
            else
            {
                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);
#ifdef DEBUG_BUTTON
                PRINT("PRESS USER BUTTON TO START UPGRADE...\r\n");
                button_user.wait();
#endif
            }
        
            cup_start_update(cup_slack, bootloader);
        }
    
    } while (0);
    
    // Set main task to lowest priority
    osThreadSetPriority(osThreadGetId(), osPriorityIdle);
    while(true)
    {
        // Wait to avoid beeing stuck in loop
        Thread::wait(200);
    }
}