Bluetooth Low Energy based Firmware Over The Air with Mbed. Mbed part is a external processor of the IoT devices and communicate with a Bluetooth module. The Bluetooth module have to support BLE and implement BLE FOTA profile designed by ours. BLE FOTA profile specification is available from our GIT hub wiki(https://github.com/sevencore/BLEFOTA).

Dependencies:   mbed

Fork of mbed_fota by KIM HyoengJun

Bluetooth Low Energy based Firmware Over The Air with Mbed. Mbed part is a external processor of the IoT devices and communicate with a Bluetooth module. The Bluetooth module have to support BLE and implement BLE FOTA profile designed by ours. BLE FOTA profile specification is available from our GIT hub wiki.

ext_fota/BleMsgHandler.cpp

Committer:
dudnwjs
Date:
2015-08-24
Revision:
11:1ed93accb3fb
Parent:
9:fcf91f563147

File content as of revision 11:1ed93accb3fb:

/**
 * @file BleMsgHandler.cpp
 * @brief Ble message handler ( Ble message is communication mathod between Mbed and DA14583 )
 * Copyright 2015 SEVENCORE Co., Ltd.
 *
 * @author HyeongJun Kim 
 * @version 1.0.0  
 * @date 2015-08-19
*/

#include "BleMsgHandler.h"
#include "dialog_fota_config.h"
#include "diss_task.h"
#include "fota_server_task.h"
#include "app_task.h"

/**
 ****************************************************************************************
 * @addtogroup ext_fota module
 * @brief Ble message Handler Class Mathod Definition.
 *
 * @{
 ****************************************************************************************
 */

extern "C" void mbed_reset();

namespace sevencore_fota{
    
/**
 ****************************************************************************************
 * @brief Ble message Handler Constructor.
 * @param[in] mbed serial class reference to device.
 * @detail Create SerialManager instance and Create inner MsgQueue
 ****************************************************************************************
 */
BleMsgHandler::BleMsgHandler(Serial *_device)
{
    print_flag = 0;
    device = _device;
    SerialM = new SerialManager(_device);
    MsgQ = new MsgQueue(512);
    memset(recv_msg,0,512);
}
/**
 ****************************************************************************************
 * @brief Ble message Handler Constructor.
 * @param[in] mbed serial class reference to device.
 * @param[in] mbed serial class reference to hostpc.
 * @detail Create SerialManager instance and Create inner MsgQueue
 ****************************************************************************************
 */
BleMsgHandler::BleMsgHandler(Serial *_device, Serial *_hostpc)
{
    print_flag = 1;
    device = _device;
    hostpc = _hostpc;
    SerialM = new SerialManager(_device,_hostpc);
    MsgQ = new MsgQueue(512);
    memset(recv_msg,0,512); 
}
/**
 ****************************************************************************************
 * @brief Ble message Handler Destructor.
 ****************************************************************************************
 */
BleMsgHandler::~BleMsgHandler(void)
{
    free(SerialM);
    free(MsgQ);
}
/**
 ****************************************************************************************
 * @brief Ble message handler Start title print function.
 ****************************************************************************************
 */
void BleMsgHandler::PrintTitle(void)
{
    if( print_flag == 1 )
        hostpc->printf("\nSevencore Fota : BleMsg Handler Start\n");
    //SerialM->ReceiveToSerialTest();
}
/**
 ****************************************************************************************
 * @brief Create ble message.
 * @param[in] 16byte ble message type. @ref structure 'ble_hdr' member 'bType'
 * @param[in] 16byte ble dest task id(number). @ref structure 'ble_hdr' member 'bDstid'
 * @param[in] 16byte ble source task id(number). @ref structure 'ble_hdr' member 'bSrcid'
 * @param[in] 16byte ble message data length. @ref structure 'ble_hdr' member 'bLength'
 * @param[in] input data pointer.
 * @param[in] message alloc output pointer.
 ****************************************************************************************
 */
void BleMsgHandler::BleMsgAlloc( unsigned short id,
                                 unsigned short dest_id,
                                 unsigned short src_id,
                                 unsigned short data_len,
                                 void *pdata,
                                 uint8_t *msg )
{
    memset(msg,0,sizeof(msg));
    msg[0] = 0x05;
    memcpy(&msg[1],&id,sizeof(unsigned short));
    memcpy(&msg[1+1*sizeof(unsigned short)],&dest_id,sizeof(unsigned short));
    memcpy(&msg[1+2*sizeof(unsigned short)],&src_id,sizeof(unsigned short));
    memcpy(&msg[1+3*sizeof(unsigned short)],&data_len,sizeof(unsigned short));
    memcpy(&msg[1+4*sizeof(unsigned short)],pdata,data_len);
}
/**
 ****************************************************************************************
 * @brief Send ble message to device.
 * @param[in] sending message pointer
 * @param[in] message size.
 ****************************************************************************************
 */
int BleMsgHandler::BleSendMsg(uint8_t *msg, unsigned short size)
{
   return  SerialM->SendToSerial(msg,size);
}
/**
 ****************************************************************************************
 * @brief Receive ble message from device.
 * @detail Received message insert inner MsgQueue
 ****************************************************************************************
 */
void BleMsgHandler::BleReceiveMsg(void)
{
    int receive_size = -1;//default
    while(receive_size == -1)
    {
        receive_size = SerialM->ReceiveToSerial(recv_msg);
    }
    
    uint8_t *msg;
    msg = new uint8_t[receive_size];
    memcpy(msg,recv_msg,receive_size);
    memset(recv_msg,0,512);
    MsgQ->EnQueue(msg);
}
/**
 ****************************************************************************************
 * @brief Get message from MsgQueue and Execute corresponding function.
 * @detail After get message, extract message type. Each message type connect corresponding function
 ****************************************************************************************
 */
void BleMsgHandler::BleMsgHandle(void)
{
    uint8_t *msg;
    ble_hdr msg_hdr;
    unsigned short paramPos = 1 + sizeof(msg_hdr);
    
    if( print_flag == 1)
        hostpc->printf("Ble-message Handle Function!\n");
    
    msg = (uint8_t*)MsgQ->DeQueue();
    memcpy(&msg_hdr, &msg[1], sizeof(msg_hdr));
    
    if( print_flag == 1 )
        hostpc->printf(" handle msg : id(%d), dst(%d), src(%d), len(%d) !\n",
         msg_hdr.bType, msg_hdr.bDstid, msg_hdr.bSrcid, msg_hdr.bLength);
    
    if (msg_hdr.bDstid != TASK_GTL){
        if( print_flag == 1)
            hostpc->printf("Dstid not TASK_GTL!\n");
        return;
    }
    
    switch( msg_hdr.bType )
    {
        case GAPM_CMP_EVT:
            if( print_flag == 1)
                    hostpc->printf("==> GAPM_CMP_EVT!!\n");
            HandleGapmCmpEvt(msg_hdr.bType,(struct gapm_cmp_evt *)&msg[paramPos],msg_hdr.bDstid,msg_hdr.bSrcid);
            break;
        case GAPM_DEVICE_READY_IND:
            if( print_flag == 1)
                    hostpc->printf("==> GAPM_DEVICE_READY_IND!!\n");
            gapm_device_ready_ind_handler(msg_hdr.bType,(struct gap_ready_evt *)&msg[paramPos],msg_hdr.bDstid,msg_hdr.bSrcid,this);
            break;
        case GAPM_ADV_REPORT_IND:
            if( print_flag == 1)
                    hostpc->printf("==> GAPM_ADV_REPORT_IND!!\n");
            gapm_adv_report_ind_handler(msg_hdr.bType,(struct gapm_adv_report_ind *)&msg[paramPos],msg_hdr.bDstid,msg_hdr.bSrcid);
            break;
        case GAPC_CMP_EVT:
            if( print_flag == 1)
                    hostpc->printf("==> GAPC_CMP_EVT!!\n");
            HandleGapcCmpEvt(msg_hdr.bType,(struct gapc_cmp_evt *)&msg[paramPos],msg_hdr.bDstid,msg_hdr.bSrcid);
            break;
        case GAPC_CONNECTION_REQ_IND:
            if( print_flag == 1)
                    hostpc->printf("==> GAPC_CONNECTION_REQ_IND!!\n");
            gapc_connection_req_ind_handler(msg_hdr.bType,(struct gapc_connection_req_ind *)&msg[paramPos],msg_hdr.bDstid,msg_hdr.bSrcid,this);
            break;
        case GAPC_DISCONNECT_IND:
            if( print_flag == 1)
                    hostpc->printf("==> GAPC_DISCONNECT_IND!!\n");
            gapc_disconnect_ind_handler(msg_hdr.bType,(struct gapc_disconnect_ind *)&msg[paramPos],msg_hdr.bDstid,msg_hdr.bSrcid,this);
            break;
        case DISS_CREATE_DB_CFM:
            if( print_flag == 1)
                    hostpc->printf("==> DISS_CREATE_DB_CFM!!\n");
            diss_create_db_cfm_handler(msg_hdr.bType,(struct diss_create_db_cfm *)&msg[paramPos],msg_hdr.bDstid,msg_hdr.bSrcid,this);
            break;
        case DISS_DISABLE_IND:
            if( print_flag == 1)
                    hostpc->printf("==> DISS_DISABLE_IND!!\n");
            break;
        case DISS_ERROR_IND:
            if ( print_flag == 1)
                hostpc->printf("Rcved DISS_ERROR_IND Msg\n");
            break;
        case FOTA_SERVER_CREATE_DB_CFM:
            if( print_flag == 1)
                    hostpc->printf("==> FOTA_SERVER_CREATE_DB_CFM!!\n");
            fota_server_create_db_cfm_handler(msg_hdr.bType,(struct fota_server_create_db_cfm *)&msg[paramPos],msg_hdr.bDstid,msg_hdr.bSrcid,this);
            break;
        case FOTA_SERVER_DISABLE_IND:
            if( print_flag == 1)
                    hostpc->printf("==> FOTA_SERVER_DISABLE_IND!!\n");
            break;
        case FOTA_SERVER_ERROR_IND:
            if ( print_flag == 1)
                hostpc->printf("Rcved FOTA_SERVER_ERROR_IND Msg\n");
            fota_server_data_flash_ind_handler(msg_hdr.bType,(struct fota_server_data_flash_ind *)&msg[paramPos],msg_hdr.bDstid,msg_hdr.bSrcid,this);
            break;    
        default:
            if( print_flag == 1)
                hostpc->printf("message Type Not Defined ! \n");
            break;
    }
}//gapc_disconnect_ind_handler(GAPC_DISCONNECT_IND),(GAPC_CONNECTION_REQ_IND)gapc_connection_req_ind_handler
/**
 ****************************************************************************************
 * @brief GAPM Command Event Handler.
 * @detail After get GAPM command, extract operation. Each operation connect corresponding function
 ****************************************************************************************
 */
void BleMsgHandler::HandleGapmCmpEvt(unsigned short msgid,
                    struct gapm_cmp_evt *param,
                    unsigned short dest_id,
                    unsigned short src_id)
{
    if (param->status == CO_ERROR_NO_ERROR)
    {
        switch(param->operation)
        {
            case GAPM_NO_OP:// No operation.
                break;
            case GAPM_RESET:// Reset BLE subsystem: LL and HL.
                if( print_flag == 1)
                    hostpc->printf("GAPM_RESET!! Start...\n");
                gapm_reset_completion_handler (msgid, (struct gapm_cmp_evt *)param, dest_id, src_id,this);
                break;
            case GAPM_CANCEL:// Cancel currently executed operation.
                if( print_flag == 1)
                    hostpc->printf("GAPM_CANCEL\n");
                break;
            case GAPM_SET_DEV_CONFIG:// Set device configuration
                if( print_flag == 1)
                    hostpc->printf("Adverting Start...\n");
                gapm_set_dev_config_completion_handler(msgid, (struct gapm_cmp_evt *)param, dest_id, src_id,this);
                break;
            case GAPM_SET_DEV_NAME: // Set device name
                if( print_flag == 1)
                    hostpc->printf("GAPM_SET_DEV_NAME\n");
                break;
            case GAPM_SET_CHANNEL_MAP:// Set device channel map
                if( print_flag == 1)
                    hostpc->printf("GAPM_SET_CHANNEL_MAP\n");
                break;
            case  GAPM_GET_DEV_NAME:// Get Local device name
                if( print_flag == 1)
                    hostpc->printf("GAPM_GET_DEV_NAME\n");
                break;
            case GAPM_GET_DEV_VERSION:// Get Local device version
                if( print_flag == 1)
                    hostpc->printf("GAPM_GET_DEV_VERSION\n");
                break;
            case GAPM_GET_DEV_BDADDR:// Get Local device BD Address
                if( print_flag == 1)
                    hostpc->printf("GAPM_GET_DEV_BDADDR\n");
                break;
            case GAPM_GET_WLIST_SIZE:// Get White List Size.
                if( print_flag == 1)
                    hostpc->printf("GAPM_GET_WLIST_SIZE\n");
                break;
            case GAPM_ADD_DEV_IN_WLIST:// Add devices in white list.
                if( print_flag == 1)
                    hostpc->printf("GAPM_ADD_DEV_IN_WLIST\n");
                break;
            case GAPM_RMV_DEV_FRM_WLIST:// Remove devices form white list.
                if( print_flag == 1)
                    hostpc->printf("GAPM_RMV_DEV_FRM_WLIST\n");
                break;
            case GAPM_CLEAR_WLIST:// Clear all devices from white list.
                if( print_flag == 1)
                    hostpc->printf("GAPM_CLEAR_WLIST\n");
                break;
            case GAPM_ADV_NON_CONN:// Start non connectable advertising
            case GAPM_ADV_UNDIRECT:// Start undirected connectable advertising
            case GAPM_ADV_DIRECT:// Start directed connectable advertising
                if( print_flag == 1)
                    hostpc->printf("GAPM_ADV_~\n");
                break;
            case GAPM_SCAN_ACTIVE:// Start active scan operation
            case GAPM_SCAN_PASSIVE:   // Start passive scan operation
                if( print_flag == 1)
                    hostpc->printf("GAPM_SCAN_~\n");
                break;
            case GAPM_CONNECTION_DIRECT:// Direct connection operation
                //break;
            case GAPM_CONNECTION_AUTO:// Automatic connection operation
                //break;
            case GAPM_CONNECTION_SELECTIVE:// Selective connection operation
                //break;
            case GAPM_CONNECTION_NAME_REQUEST:// Name Request operation (requires to start a direct connection)
                if( print_flag == 1)
                    hostpc->printf("GAPM_CONNECT_~\n");
                break;
            case GAPM_RESOLV_ADDR:// Resolve device address
                if( print_flag == 1)
                    hostpc->printf("GAPM_RESOLV_ADDR\n");
                break;
            case GAPM_GEN_RAND_ADDR:// Generate a random address
                if( print_flag == 1)
                    hostpc->printf("GAPM_GEN_RAND_ADDR\n");
                break;
            case GAPM_USE_ENC_BLOCK:// Use the controller's AES-128 block
                if( print_flag == 1)
                    hostpc->printf("GAPM_USE_ENC_BLOCK\n");
                break;
            case GAPM_GEN_RAND_NB:// Generate a 8-byte random number
                if( print_flag == 1)
                    hostpc->printf("GAPM_GEN_RAND_NB\n");
                break;
            case GAPM_DBG_GET_MEM_INFO:// Get memory usage
                if( print_flag == 1)
                    hostpc->printf("GAPM_GAPM_DBG_GET_MEM_INFO\n");
                break;
            case GAPM_PLF_RESET:// Perform a platform reset
                if( print_flag == 1)
                    hostpc->printf("GAPM_PLF_RESET\n");
                break;
            case GAPM_GET_DEV_ADV_TX_POWER:// Get device advertising power level
                if( print_flag == 1)
                    hostpc->printf("GAPM_GET_DEV_ADV_TX_POWER\n");
                break;
            default:
                if( print_flag == 1)
                    hostpc->printf("??????????????????????????\n");
                break;
        }
    }else{
        if( print_flag == 1)
            hostpc->printf("?status ERROR?\n");
    } 
}
/**
 ****************************************************************************************
 * @brief GAPC Command Event Handler.
 * @detail After get GAPC command, extract operation. Each operation connect corresponding function
 ****************************************************************************************
 */
void BleMsgHandler::HandleGapcCmpEvt(unsigned short msgid,
                    struct gapc_cmp_evt *param,
                    unsigned short dest_id,
                    unsigned short src_id)
{
     switch(param->operation)
    {
        case GAPC_NO_OP: // No operation
            break;
        case GAPC_DISCONNECT: // Disconnect link
            break;
        case GAPC_GET_PEER_NAME: // Retrieve name of peer device
            break; 
        case GAPC_GET_PEER_VERSION: // Retrieve peer device version info.
            break; 
        case GAPC_GET_PEER_FEATURES: // Retrieve peer device features.
            break; 
        case GAPC_GET_CON_RSSI: // Retrieve connection RSSI.
            break; 
        case GAPC_GET_PRIVACY: // Retrieve Privacy Info.
            break; 
        case GAPC_GET_RECON_ADDR: // Retrieve Reconnection Address Value.
            break; 
        case GAPC_SET_PRIVACY: // Set Privacy flag.
            break; 
        case GAPC_SET_RECON_ADDR: // Set Reconnection Address Value.
            break; 
        case GAPC_UPDATE_PARAMS: // Perform update of connection parameters.
            break; 
        case GAPC_BOND: // Start bonding procedure.
            break; 
        case GAPC_ENCRYPT: // Start encryption procedure.
            break; 
        case GAPC_SECURITY_REQ: // Start security request procedure
            break; 
        case GAPC_GET_CON_CHANNEL_MAP: // Retrieve Connection Channel MAP.
            break;
    }
}
/**
 ****************************************************************************************
 * @brief Debugging message output to hostpc.
 * @param[in] output char array pointer
 ****************************************************************************************
 */
void BleMsgHandler::HostPcPrint(char *str)
{
    if(print_flag == 1)
        hostpc->printf("%s",str);
}
/**
 ****************************************************************************************
 * @brief Receive test method
 ****************************************************************************************
 */
void BleMsgHandler::ReceiveToSerialTest(void)
{
    SerialM->ReceiveToSerialTest();
}
/**
 ****************************************************************************************
 * @brief Receive and Store Da14583 flash data.
 * @param[in] mbed binary file size
 * @param[in] mbed binary version string
 ****************************************************************************************
 */
void BleMsgHandler::FirmwareDataReceive(unsigned short code_size, char *version)
{
    unsigned short stored_data_cnt = 0;
    char path[20]="/local/";
    char databuf[FIRMWARE_DATA_FRAGMENT_SIZE]="/local/";
    if(print_flag == 1)
        hostpc->printf("\n!!File name = %s!! code_size = %d\n",version,code_size);
    strcat(databuf, version);
    strcat(databuf, ".BIN");      
    hostpc->printf("\n!!name = %s!\n",databuf);
    
    
    DIR *d = opendir("/local/");
    struct dirent *p;
    while ((p = readdir(d)) != NULL)
    {
            hostpc->printf("%s,%d\n", p->d_name,strcmp(strchr(p->d_name,'.')+1,"BIN"));
            if( strcmp(strchr(p->d_name,'.')+1,"BIN") == 0 ){
                strcat(path,p->d_name);
                hostpc->printf("%s\n",path);
                remove(path);
                strcpy(path,"/local/");
            }
    }
    closedir(d); 
            
    fp = fopen(databuf, "w");
    
    SerialM->DataReceive((uint8_t*)databuf,2);
    if(databuf[0] == 0x80 && databuf[1] == 0x46 ){
        if(print_flag == 1)
            hostpc->printf("\n!!Firmware Data Transmition Start!!\n");
    }else{
        if(print_flag == 1)
            hostpc->printf("\n!!Firmware Data Transmition ERROR!!\n");
    }
    
    memset(databuf,0,FIRMWARE_DATA_FRAGMENT_SIZE);
    
    while( stored_data_cnt < code_size )
    {
        if( code_size - stored_data_cnt >= FIRMWARE_DATA_FRAGMENT_SIZE ){
            SerialM->DataReceive((uint8_t*)databuf,FIRMWARE_DATA_FRAGMENT_SIZE);
            fwrite(databuf, 1, FIRMWARE_DATA_FRAGMENT_SIZE, fp);
            stored_data_cnt += FIRMWARE_DATA_FRAGMENT_SIZE;    
        }else{
            SerialM->DataReceive((uint8_t*)databuf, code_size - stored_data_cnt);
            fwrite(databuf, 1, code_size - stored_data_cnt, fp);
            stored_data_cnt = code_size ;
        }
        memset(databuf,0,FIRMWARE_DATA_FRAGMENT_SIZE);      
    }
    
    SerialM->DataReceive((uint8_t*)databuf,2);
    if(databuf[0] == 0x80 && databuf[1] == 0x46 ){
        if(print_flag == 1)
            hostpc->printf("\n!!Firmware Data Transmition END!!\n");
    }else{
        if(print_flag == 1)
            hostpc->printf("\n!!Firmware Data Transmition END ERROR!!\n");
    }
    fclose(fp);
    wait(5);
    if(print_flag == 1)
            hostpc->printf("\n!!RESET MBED!!\n");
    mbed_reset();
}
    


 
}//namespace
/// @} ext_fota module