Program to update the D7A modem's firmware.

Dependencies:   modem_ref_helper DebouncedInterrupt

main.cpp

Committer:
Jeej
Date:
2016-11-15
Revision:
11:3c6ef9b1be8a
Parent:
10:a568511d470d
Child:
12:beabd59e0c35

File content as of revision 11:3c6ef9b1be8a:

#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
// For now root key size is always D7A_ROOT_KEY_SIZE (8)
uint8_t root_key[D7A_ROOT_KEY_SIZE] = CUP_DEFAULT_KEY;
uint8_t root_key_size = D7A_ROOT_KEY_SIZE; // XXX: Do not change this

// 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  = D10,
    .rx  = D2,
    .rts = D13,
    .cts = D9,
    .rx_buffer_size = 1024,
};

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

int main()
{
    d7a_revision_t rev;
    cup_cfg_t cup_cfg;
    uint32_t cup_offset;
    
    // Start & initialize
    DBG_OPEN();
    PRINT("\r\n-----------------------------------\r\n");
    PRINT("---------- D7A WM Updater ---------\r\n");
    PRINT("-----------------------------------\r\n");

    DebouncedInterrupt user_interrupt(USER_BUTTON);
    user_interrupt.attach(button_push_isr, IRQ_FALL, 200, true);

    d7a_open(&shield_config, A3, &callbacks);

    // Check modem revision
    D7A_READ(&rev, D7A_FID_FIRMWARE_VERSION, 0, sizeof(d7a_revision_t), NULL);
    
    // Read CUP config with root permissions
    D7A_READ(&cup_cfg, CUP_CFG_FID, 0, sizeof(cup_cfg_t), root_key);
    
    uint8_t hw_errors = 0;
    uint8_t fw_errors = 0;
    uint8_t errors = 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;
    
    hw_errors += check_parameter("Manufacturer ID...       ", rev.manufacturer_id, CUP_MFG_ID);
    hw_errors += check_parameter("Device ID...             ", rev.device_id, CUP_DEV_ID);
    hw_errors += check_parameter("Hardware version...      ", rev.hw_version, CUP_HW_ID);
    fw_errors += check_parameter("Firmware id...           ", rev.fw_version.id, CUP_FW_ID);
    
    if (version_old != version_new)
    {
        fw_errors += check_parameter("Firmware version major...", rev.fw_version.major, CUP_TARGET_FW_MAJOR);
        fw_errors += check_parameter("Firmware version minor...", rev.fw_version.minor, CUP_TARGET_FW_MINOR);
    
        PRINT("Checking CUP Slack...              ");
        
        cup_offset = (CUP_CODE_SIZE > cup_cfg.src_offset)? CUP_CODE_SIZE - cup_cfg.src_offset : 0;
        
        int32_t cup_slack = cup_cfg.key - cup_offset - CUP_DATA_SIZE;
        if (cup_slack < 0)
        {
            PRINT("Failed. (%d bytes short)\r\n", -cup_slack);
            fw_errors++;
        }
        else
        {
            PRINT("OK. (%d bytes)\r\n", cup_slack);
        }
    }
    
    PRINT("\r\n");
            
    if (hw_errors)
    {
        PRINT("Please, check that you chose the right Hardware in bin.h\r\n");
    }
    
    if (fw_errors)
    {
        PRINT("Please, check that you chose the right Revision in mbed revision tree.\r\n");
        PRINT("You are trying to upgrade from v%d.%d.%d 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);
        PRINT("You can only upgrade to another patch %d.%d.x --> %d.%d.y\r\nor to the next minor %d.%d.x --> %d.%d.0\r\n",
                rev.fw_version.major, rev.fw_version.minor,
                rev.fw_version.major, rev.fw_version.minor,
                rev.fw_version.major, rev.fw_version.minor,
                rev.fw_version.major, rev.fw_version.minor+1);
    }
    
    errors = hw_errors + fw_errors;
    
    if (errors)
    {
        PRINT("\r\nSelect the right parameters and recompile.\r\n");
    }
    else if (version_old == version_new)
    {
        PRINT("Your modem is up to date! (v%d.%d.%d)\r\n", 
                rev.fw_version.major, rev.fw_version.minor, rev.fw_version.patch);
    }
    else
    {
        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);
            PRINT("PRESS USER BUTTON TO CONFIRM...\r\n");
            button_user.wait();
            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);
            PRINT("PRESS USER BUTTON TO START DOWNGRADE...\r\n");
        }
        else
        {
            PRINT("Upgrading 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 UPGRADE...\r\n");
        }
        
        button_user.wait();
        cup_start_update(cup_offset);
    }
    
    // Set main task to lowest priority
    osThreadSetPriority(osThreadGetId(), osPriorityIdle);
    while(true)
    {
        // Wait to avoid beeing stuck in loop
        Thread::wait(200);
    }
}