Dash7Board Code Upgrade Protocol demonstration code.

Dependencies:   modem_ref_helper CRC

main.cpp

Committer:
Jeej
Date:
2020-05-28
Revision:
8:6b7d38139b43
Parent:
7:bfe920ee44f2
Child:
9:d110f2b86831

File content as of revision 8:6b7d38139b43:

// @autor: jeremie@wizzilab.com
// @date: 2017-12-14

#include "modem_ref_helper.h"
#include "modem_callbacks.h"
#include "files.h"
#include "crc.h"
#include "cup_app.h"

#define CHUNK_SIZE (128)

Semaphore modem_ready(0);
Queue<touch_t, 8> g_file_modified;

// CRC calculated on the incoming data stream
extern uint32_t stream_crc;
extern int32_t last_end;

const uint8_t default_root_key[] = DEFAULT_ROOT_KEY;

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
void my_main_callback(uint8_t terminal, int8_t err, uint8_t id)
{
    (void)id;
    
    if (ALP_ERR_NONE > err)
    {
        modem_print_error(ALP_ITF_TYPE_D7A, err);
    }

    if (terminal)
    {
        modem_ready.release();
    }
}

void thread_file_modified()
{
    touch_t* touch;
    osEvent evt;
    Timer tim;
    uint32_t total = 0;
    uint32_t next_chunk = 0;
    uint32_t chunks=0;
    
    uint8_t id = modem_get_id(my_main_callback);
    
    PRINT("Ready\n");
    
    while (true)
    {
        evt = g_file_modified.get();
        touch = (evt.status == osEventMessage)? (touch_t*)evt.value.p : NULL;
        ASSERT(touch != NULL, "NULL touch pointer!\n");
        
        switch (touch->fid)
        {
            case FID_APP_CUP_CFG_BCAST:
            {
                cup_cfg_bcast_header_t cup_cfg;
                
                ram_fs_read(FID_APP_CUP_CFG_BCAST, 0, sizeof(cup_cfg_bcast_header_t), (uint8_t*)&cup_cfg);
                        
                if (CUP_CMD_UPGRADE_FILE_START == cup_cfg.cmd)
                {
                    if (cup_cfg_bcast_init())
                    {
                        PRINT("Enter upload mode. Watchdog %ds\n", cup_cfg.to);
                        
                        tim.stop();
                        tim.reset();
                        total       = 0;
                        next_chunk  = 0;
                        stream_crc  = 0;
                        chunks      = 0;
                        
                        // Write to the modem CUP config file (as root)
                        // to enter upload mode
                        cup_cfg_t cup_start = {
                            .cmd = CUP_CMD_UPGRADE_UPLOAD,
                            .arch_nb = cup_cfg.to,
                            };
                        modem_write_file_root(FID_CUP_CFG, (uint8_t*)&cup_start, 0, 4, (uint8_t*)default_root_key, id);
                        modem_ready.acquire();
                    }
                    else
                    {
                        PRINT("Failed bcast init\n");
                    }
                }
                else
                {
                    PRINT("CUP command 0x%04X\n", cup_cfg.cmd);
                }
               
                break;
            }
            case FID_APP_CUP_CFG:
            {
                cup_cfg_t cup_cfg = { 0 };
                uint8_t* data = (uint8_t*)((uint8_t*)&cup_cfg + touch->offset);
                
                ram_fs_read(touch->fid, touch->offset, touch->length, data);
                
                if (CUP_CMD_UPGRADE_FILE_END == cup_cfg.cmd)
                {
                    PRINT("Done.\n");

                    // Actual check is done here since we could have received some of the missed data in a previous session.
                    
                    /******************************/
                    /* Compute CRC on saved data. */
                    /******************************/

                    // If you have the full binary data,
                    // You can use this function to compute CRC
                    //binary_crc = crc32((char*)binary_data, expected_size);
                    
                    // Else just do a loop and a fast CRC on data chunks like in my_write
                }
                else
                {
                    PRINT("CUP command 0x%04X\n", cup_cfg.cmd);
                }
                
                break;
            }
            case FID_APP_CUP_CODE:
            {
                cup_cfg_bcast_update(touch->offset, touch->length);

                // Chunk data should be saved in my_write callback
                
                // Notify modem code file to reset upload watchdog
                // else the device will exit upload mode after the watchdog timeout
                modem_notify_file(FID_CUP_CODE, 0, 1, id);
                modem_ready.acquire();
                
                break;
            }
            default:
                PRINT("TOUCH FID %d OFF %d LEN %d\n", touch->fid, touch->offset, touch->length);
                break;
        }
        
        FREE(touch);
    }
}

/*** Main function ------------------------------------------------------------- ***/
int main() {
    // Start & initialize
#ifdef DEBUG_LED
    DBG_OPEN(DEBUG_LED);
#else
    DBG_OPEN(NC);
#endif
    PRINT("\n"
          "-----------------------------------------\n"
          "---------------- Demo CUP ---------------\n"
          "-----------------------------------------\n");
              
    modem_helper_open(&callbacks);
    
    PRINT("--------------- APP infos ---------------\r\n");
    PRINT(" - Manufacturer ID:  %08X\r\n", f_rev.manufacturer_id);
    PRINT(" - Device ID:        %08X\r\n", f_rev.device_id);
    PRINT(" - Hardware version: %08X\r\n", f_rev.hw_version);
    PRINT(" - Firmware version: v%d.%d.%d [%02X]\r\n", f_rev.fw_version.major, f_rev.fw_version.minor, f_rev.fw_version.patch, f_rev.fw_version.id);
    PRINT(" - CUP max size:     %d\r\n", f_rev.cup_max_size);
    PRINT("-----------------------------------------\r\n");
    
    uint8_t id = modem_get_id(my_main_callback);

    PRINT("Register Files\n");
    modem_update_file(FID_HOST_REV, (alp_file_header_t*)&h_rev, (uint8_t*)&f_rev);
    modem_update_file(FID_APP_CUP_CFG, (alp_file_header_t*)&h_cup_cfg, (uint8_t*)&f_cup_cfg);
    modem_update_file(FID_APP_CUP_CFG_BCAST, (alp_file_header_t*)&h_cup_cfg_bcast, (uint8_t*)&f_cup_cfg_bcast);
    
    // Declare the cup code file
    // It needs a special handling of its data in my_write callback since we want to keep them.
    // (can't be done with the current RAM file system)
    modem_declare_file(FID_APP_CUP_CODE, (alp_file_header_t*)&h_cup_code, true, id);
    modem_ready.acquire();
    
    PRINT("Start D7A Stack\n");
    modem_activate_itf(ALP_ITF_TYPE_D7A, 24, 0,  ALP_D7A_ISTAT_RESP | ALP_D7A_ISTAT_UNS | ALP_D7A_ISTAT_EOP, true, id);
    modem_ready.acquire();
    
    PRINT("Notify Modem Version\n");
    modem_notify_file(D7A_FID_FIRMWARE_VERSION, 0, sizeof(revision_t), id);
    modem_ready.acquire();
    
    PRINT("Notify Host Version\n");
    modem_notify_host_rev(&f_rev, &h_rev, (uint8_t*)default_root_key);
    
    // id no longer needed
    modem_free_id(id);
        
    // Start file modified thread
    Thread th_file_modified(osPriorityNormal, 1024, NULL);
    osStatus status = th_file_modified.start(thread_file_modified);
    ASSERT(status == osOK, "Failed to start thread_file_modified (err: %d)\r\n", status);

#ifdef DEBUG_LED
    DigitalOut my_led(DEBUG_LED);
#endif
    
    // Set main task to lowest priority
    osThreadSetPriority(osThreadGetId(), osPriorityLow);
    while(true)
    {
        ThisThread::sleep_for(500);
#ifdef DEBUG_LED
        my_led = !my_led;
#endif
    }
}