资产监测设备之华大单片机Boot软件升级

Posted 瑞奇Ricky

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了资产监测设备之华大单片机Boot软件升级相关的知识,希望对你有一定的参考价值。

近期笔者在研究如何从软件方面提升资产监测设备的性能,从而提升用户的使用体验感。

资产监测设备的主要作用是帮助用户监测设备的实时位置、实时状态避免运动中的货物出现丢失等情况。环境监测设备在智慧物流方面发挥了重要的作用,例如在运输贵重货物过程中,只需要将该设备安装在货物中,用户即可远程了解货物的位置、货物是否出现暴力扔件、以及避免货物在运输过程中的丢失。

资产监测设备中的华大单片机,对该设备的工作发挥了重要的作用。笔者的软件团队对单片机进行了软件升级。

具体流程如下:
/**
** \\brief 上位机数据帧解析及处理
**
** \\param [in] None
**
** \\retval Ok APP程序升级完成,并接受到跳转至APP命令
** \\retval OperationInProgress 数据处理中
** \\retval Error 通讯错误
**
******************************************************************************/
en_result_t Modem_Process(void)
{
uint8_t u8Cmd, u8FlashAddrValid, u8Cnt, u8Ret;
uint16_t u16DataLength, u16PageNum, u16Ret;
uint32_t u32FlashAddr, u32FlashLength, u32Temp;
if (enFrameRecvStatus == FRAME_RECV_PROC_STATUS) //有数据帧待处理, enFrameRecvStatus值在串口中断中调整
{
u8Cmd = u8FrameData[PACKET_CMD_INDEX]; //获取帧指令码
if (PACKET_CMD_TYPE_DATA == u8FrameData[PACKET_TYPE_INDEX]) //如果是数据指令
{
u8FlashAddrValid = 0u;

        u32FlashAddr = u8FrameData[PACKET_ADDRESS_INDEX] +      //读取地址值
                       (u8FrameData[PACKET_ADDRESS_INDEX + 1] << 8)  +
                       (u8FrameData[PACKET_ADDRESS_INDEX + 2] << 16) +
                       (u8FrameData[PACKET_ADDRESS_INDEX + 3] << 24);
        if ((u32FlashAddr >= (FLASH_BASE + BOOT_SIZE)) && (u32FlashAddr < (FLASH_BASE + FLASH_SIZE)))  //如果地址值在有效范围内
        {
            u8FlashAddrValid = 1u;                              //标记地址有效
        }
    }

    switch (u8Cmd)                                              //根据指令码跳转执行
    {
        case  PACKET_CMD_HANDSHAKE    :                         //握手帧 指令码
            u8FrameData[PACKET_RESULT_INDEX] = PACKET_ACK_OK;   //返回状态为:正确
            Modem_SendFrame(&u8FrameData[0], PACKET_INSTRUCT_SEGMENT_SIZE);   //发送应答帧给上位机
            break;
        case  PACKET_CMD_ERASE_FLASH  :                         //擦除flash 指令码
            if ((u32FlashAddr % FLASH_SECTOR_SIZE) != 0)        //如果擦除地址不是页首地址
            {
                u8FlashAddrValid = 0u;                          //标记地址无效
            }

            if (1u == u8FlashAddrValid)                         //如果地址有效
            {
                u32Temp = u8FrameData[PACKET_DATA_INDEX] +      //获取待擦除flash尺寸
                          (u8FrameData[PACKET_DATA_INDEX + 1] << 8)  +
                          (u8FrameData[PACKET_DATA_INDEX + 2] << 16) +
                          (u8FrameData[PACKET_DATA_INDEX + 3] << 24);
                u16PageNum = FLASH_PageNumber(u32Temp);          //计算需擦除多少页
                for (u8Cnt=0; u8Cnt<u16PageNum; u8Cnt++)         //根据需要擦除指定数量的扇区
                {
                    u8Ret = Flash_EraseSector(u32FlashAddr + (u8Cnt * FLASH_SECTOR_SIZE));
                    if (Ok != u8Ret)                             //如果擦除失败,反馈上位机错误代码
                    {
                        u8FrameData[PACKET_RESULT_INDEX] = PACKET_ACK_ERROR;
                        break;
                    }
                }
                if (Ok == u8Ret)                                 //如果全部擦除成功,反馈上位机成功
                {
                    u8FrameData[PACKET_RESULT_INDEX] = PACKET_ACK_OK;
                }else                                            //如果擦除失败,反馈上位机错误超时标志
                {
                    u8FrameData[PACKET_RESULT_INDEX] = PACKET_ACK_TIMEOUT;
                }
            }
            else                                                 //地址无效,反馈上位机地址错误
            {
                u8FrameData[PACKET_RESULT_INDEX] = PACKET_ACK_ADDR_ERROR;
            }
            Modem_SendFrame(&u8FrameData[0], PACKET_INSTRUCT_SEGMENT_SIZE);             //发送应答帧到上位机
            break;
        case  PACKET_CMD_APP_DOWNLOAD :                          //数据下载 指令码
            if (1u == u8FlashAddrValid)                          //如果地址有效
            {
                u16DataLength = u8FrameData[FRAME_LENGTH_INDEX] + (u8FrameData[FRAME_LENGTH_INDEX + 1] << 8)
                                 - PACKET_INSTRUCT_SEGMENT_SIZE; //获取数据包中的数据长度(不包含指令码指令类型等等)
                if (u16DataLength > PACKET_DATA_SEGMENT_SIZE)    //如果数据长度大于最大长度
                {
                    u16DataLength = PACKET_DATA_SEGMENT_SIZE;    //设置数据最大值
                }
                u8Ret = Flash_WriteBytes(u32FlashAddr, (uint8_t *)&u8FrameData[PACKET_DATA_INDEX], u16DataLength); //把所有数据写入flash
                if (Ok != u8Ret)                                 //如果写数据失败       
                {
                    u8FrameData[PACKET_RESULT_INDEX] = PACKET_ACK_ERROR;                //反馈上位机错误 标志
                }
                else                                             //如果写数据成功
                {
                    u8FrameData[PACKET_RESULT_INDEX] = PACKET_ACK_OK;                   //反馈上位机成功 标志
                }
            }
            else                                                 //如果地址无效
            {
                u8FrameData[PACKET_RESULT_INDEX] = PACKET_ACK_ADDR_ERROR;               //反馈上位机地址错误
            }
            Modem_SendFrame(&u8FrameData[0], PACKET_INSTRUCT_SEGMENT_SIZE);             //发送应答帧到上位机
            break;
        case  PACKET_CMD_CRC_FLASH    :                          //查询flash校验值 指令码
            if (1u == u8FlashAddrValid)                          //如果地址有效
            {
                u32FlashLength = u8FrameData[PACKET_DATA_INDEX] +                 
                                (u8FrameData[PACKET_DATA_INDEX + 1] << 8)  +
                                (u8FrameData[PACKET_DATA_INDEX + 2] << 16) +
                                (u8FrameData[PACKET_DATA_INDEX + 3] << 24);             //获取待校验flash大小
                if ((u32FlashLength + u32FlashAddr) > (FLASH_BASE + FLASH_SIZE))        //如果flash长度超出有效范围
                {
                    u8FrameData[PACKET_RESULT_INDEX] = PACKET_ACK_FLASH_SIZE_ERROR;     //反馈上位机flash尺寸错误
                }else
                {
                    u16Ret = Cal_CRC16(((unsigned char *)u32FlashAddr), u32FlashLength);//读取flash指定区域的值并计算crc值
                    u8FrameData[PACKET_FLASH_CRC_INDEX] = (uint8_t)u16Ret;              //把crc值存储到应答帧
                    u8FrameData[PACKET_FLASH_CRC_INDEX+1] = (uint8_t)(u16Ret>>8);
                    u8FrameData[PACKET_RESULT_INDEX] = PACKET_ACK_OK;                   //反馈上位机成功 标志
                }
            }
            else                                                                        //如果地址无效
            {
                u8FrameData[PACKET_RESULT_INDEX] = PACKET_ACK_ADDR_ERROR;               //反馈上位机地址错误
            }
            Modem_SendFrame(&u8FrameData[0], PACKET_INSTRUCT_SEGMENT_SIZE+2);           //发送应答帧到上位机
            break;
        case  PACKET_CMD_JUMP_TO_APP  :                          //跳转至APP 指令码
            Flash_EraseSector(BOOT_PARA_ADDRESS);                //擦除BOOT parameter 扇区
            u8FrameData[PACKET_RESULT_INDEX] = PACKET_ACK_OK;    //反馈上位机成功
            Modem_SendFrame(&u8FrameData[0], PACKET_INSTRUCT_SEGMENT_SIZE);             //发送应答帧到上位机
            return Ok;                                           //APP更新完成,返回OK,接下来执行跳转函数,跳转至APP
        case  PACKET_CMD_APP_UPLOAD   :                          //数据上传
            if (1u == u8FlashAddrValid)                          //如果地址有效
            {
                u32Temp = u8FrameData[PACKET_DATA_INDEX] +
                          (u8FrameData[PACKET_DATA_INDEX + 1] << 8)  +
                          (u8FrameData[PACKET_DATA_INDEX + 2] << 16) +
                          (u8FrameData[PACKET_DATA_INDEX + 3] << 24);                   //读取上传数据长度
                if (u32Temp > PACKET_DATA_SEGMENT_SIZE)                                 //如果数据长度大于最大值
                {
                    u32Temp = PACKET_DATA_SEGMENT_SIZE;                                 //设置数据长度为最大值
                }
                Flash_ReadBytes(u32FlashAddr, (uint8_t *)&u8FrameData[PACKET_DATA_INDEX], u32Temp); //读flash数据
                u8FrameData[PACKET_RESULT_INDEX] = PACKET_ACK_OK;                       //反馈上位机成功 标志
                Modem_SendFrame(&u8FrameData[0], PACKET_INSTRUCT_SEGMENT_SIZE + u32Temp);//发送应答帧到上位机
            }
            else                                                  //如果地址无效
            {
                u8FrameData[PACKET_RESULT_INDEX] = PACKET_ACK_ADDR_ERROR;               //反馈上位机地址错误 标志
                Modem_SendFrame(&u8FrameData[0], PACKET_INSTRUCT_SEGMENT_SIZE);         //发送应答帧到上位机
            }
            break;
        case  PACKET_CMD_START_UPDATE :                           //启动APP更新(此指令正常在APP程序中调用)
            u8FrameData[PACKET_RESULT_INDEX] = PACKET_ACK_OK;     //反馈上位机成功 标志
            Modem_SendFrame(&u8FrameData[0], PACKET_INSTRUCT_SEGMENT_SIZE);             //发送应答帧到上位机
            break;
    }
    enFrameRecvStatus = FRAME_RECV_IDLE_STATUS;                   //帧数据处理完成,帧接收状态恢复到空闲状态
}

return OperationInProgress;                                       //返回,APP更新中。。。

}

同样从事软件工作相关的用户,对资产监测设备感兴趣的话可以参考该文档。

以上是关于资产监测设备之华大单片机Boot软件升级的主要内容,如果未能解决你的问题,请参考以下文章

资产监测设备中关于OTA升级串口应答帧处理

资产监测设备中HCL190FLAS擦写问题分析——BOOT

Yunxion资产监测设备之GNSS NEMA语句解析之GSA

在进行资产监测设备研发时,RTC的相关设计

资产监测设备使用时,设置具体指定日期天数计算

资产监测设备中C代码ifelse容易忽略的隐藏bug