48b789c0c4
- bsp.c/h: 外部SPI Flash只读驱动(SPI1, 与App同总线Mode3) - main.c/h: BL_STASH_TO_B状态: AppSize门禁 -> 外部Flash逐8KB搬运B区 -> CRC校验 -> 进BL_COPY_TO_A复用现有搬运链 - 搬运幂等: 搬运中断电重启后B区仍有效自动重搬
645 lines
20 KiB
C
645 lines
20 KiB
C
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include "main.h"
|
||
|
||
/*设备唯一编码 - 固定在Flash 0x4000位置(协议规定: Mac[0]=VerInfo, Mac[1:3]=PrjNum, Mac[4:5]=GwNum)
|
||
参照hc32l170_boot方式用宏构造6字节MAC, 网关APP从该地址读取本机MAC编码*/
|
||
const uint8_t GwMacConst[6] __attribute__((section(".ARM.__at_0x00004000"))) = {
|
||
(0x80 | GATEWAY_VER_INFO), // Mac[0] = VerInfo: Bit7固定1, Bit6:0版本
|
||
(GATEWAY_PRJ_NUM >> 16) & 0xFF, // Mac[1]
|
||
(GATEWAY_PRJ_NUM >> 8) & 0xFF, // Mac[2]
|
||
GATEWAY_PRJ_NUM & 0xFF, // Mac[3]
|
||
(GATEWAY_GW_NUM >> 8) & 0xFF, // Mac[4]
|
||
GATEWAY_GW_NUM & 0xFF // Mac[5]
|
||
};
|
||
/*运行用MAC, 首次从0x4000读入, 之后从参数区同步*/
|
||
static uint8_t s_DevMac[6] = {0};
|
||
|
||
uint32_t pdwCrc32Tbl[256];
|
||
BootLoader_t BL;
|
||
|
||
/*****************************************************************************************
|
||
* 函数名称: InitCrc32Table
|
||
* 功能描述: CRC32查表初始化
|
||
*****************************************************************************************/
|
||
void InitCrc32Table(uint32_t* Crc32Tbl)
|
||
{
|
||
for(int wCnt = 0; wCnt < 256; wCnt++) {
|
||
uint32_t dwCrc = wCnt;
|
||
for(int ucCnt = 0; ucCnt < 8; ucCnt++) {
|
||
if(dwCrc & 1) {
|
||
dwCrc = (dwCrc >> 1) ^ 0xEDB88320;
|
||
}
|
||
else {
|
||
dwCrc >>= 1;
|
||
}
|
||
}
|
||
Crc32Tbl[wCnt] = dwCrc;
|
||
}
|
||
}
|
||
|
||
/*****************************************************************************************
|
||
* 函数名称: GetCrc32
|
||
* 功能描述: 计算指定区域CRC32校验值
|
||
*****************************************************************************************/
|
||
uint32_t GetCrc32(uint32_t BaseAddr, int dwLen)
|
||
{
|
||
uint32_t Data;
|
||
uint32_t dwCrc32Data = 0xFFFFFFFF;
|
||
for(int dwCnt = 0; dwCnt < dwLen; dwCnt++) {
|
||
Data = *((volatile uint8_t*)(BaseAddr + dwCnt));
|
||
uint32_t dwTbl = (dwCrc32Data ^ Data) & 0xFF;
|
||
dwCrc32Data = ((dwCrc32Data >> 8) & 0xFFFFFF) ^ pdwCrc32Tbl[dwTbl];
|
||
}
|
||
return ~dwCrc32Data;
|
||
}
|
||
|
||
/*****************************************************************************************
|
||
* 函数名称: CRC_Modbus
|
||
* 功能描述: Modbus CRC16校验
|
||
*****************************************************************************************/
|
||
uint16_t CRC_Modbus(uint16_t wBase, __IO uint8_t *para, uint16_t length)
|
||
{
|
||
uint16_t crc = 0xFFFF;
|
||
uint16_t index, i;
|
||
|
||
for(index = 0; index < length; index++) {
|
||
crc ^= para[index];
|
||
for(i = 0; i < 8; i++) {
|
||
if(crc & 1) {
|
||
crc >>= 1;
|
||
crc ^= wBase;
|
||
}
|
||
else {
|
||
crc >>= 1;
|
||
}
|
||
}
|
||
}
|
||
return crc;
|
||
}
|
||
|
||
/*****************************************************************************************
|
||
* 函数名称: JumpToApp
|
||
* 功能描述: 跳转APP
|
||
*****************************************************************************************/
|
||
static bool JumpToApp(uint32_t AppAddr)
|
||
{
|
||
uint32_t u32StackTop = *((__IO uint32_t *)AppAddr);
|
||
uint32_t JumpAddress;
|
||
func_ptr_t JumpToApplication;
|
||
|
||
if((u32StackTop > SRAM_BASE) && (u32StackTop <= (SRAM_BASE + SRAM_SIZE))) {
|
||
JumpAddress = *(__IO uint32_t *)(AppAddr + 4);
|
||
JumpToApplication = (func_ptr_t)JumpAddress;
|
||
|
||
/*关闭全局中断, 停SysTick, 禁用Boot用过的NVIC中断, 避免跳转后残留中断干扰APP启动*/
|
||
__disable_irq();
|
||
SysTick->CTRL = 0;
|
||
SysTick->LOAD = 0;
|
||
SysTick->VAL = 0;
|
||
NVIC_DisableIRQ(RS485CH1_UART_IRQn);
|
||
NVIC_DisableIRQ(RS485CH1_UART_EI_IRQn);
|
||
NVIC_ClearPendingIRQ(RS485CH1_UART_IRQn);
|
||
NVIC_ClearPendingIRQ(RS485CH1_UART_EI_IRQn);
|
||
__set_MSP(*((__IO uint32_t *)AppAddr));
|
||
JumpToApplication();
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
/*****************************************************************************************
|
||
* 函数名称: AppWriteFlash
|
||
* 功能描述: 写升级数据到Flash指定分区 (每包200字节, 尾部不足4字节按0xFF补齐)
|
||
* 参 数: BaseAddr 分区基址(B区), AddrOffset 分区内偏移, wData 数据, wLen 字节数
|
||
* 返 回 值: 无
|
||
*****************************************************************************************/
|
||
void AppWriteFlash(uint32_t BaseAddr, uint32_t AddrOffset, uint8_t *wData, int wLen)
|
||
{
|
||
int FullWords = wLen / 4;
|
||
int Remain = wLen % 4;
|
||
uint32_t Word;
|
||
|
||
FlashWrite(BaseAddr + AddrOffset, (uint32_t *)wData, FullWords);
|
||
if(Remain > 0) { /*末包尾字节补0xFF组字写入, 保证与AppSize逐字节CRC一致*/
|
||
Word = 0xFFFFFFFF;
|
||
memcpy(&Word, &wData[FullWords * 4], Remain);
|
||
FlashWrite(BaseAddr + AddrOffset + FullWords * 4, &Word, 1);
|
||
}
|
||
}
|
||
|
||
static uint32_t s_CopyBuf[FLASH_SECTOR_SIZE / 4]; /*搬运缓冲(8KB)*/
|
||
|
||
/*****************************************************************************************
|
||
* 函数名称: CopyAppBtoA
|
||
* 功能描述: 将B区已校验固件搬运到A区(逐扇区: 擦A→读B→写A), 完成后整包校验A区
|
||
* 参 数: 无
|
||
* 返 回 值: true=搬运并校验通过
|
||
*****************************************************************************************/
|
||
static bool CopyAppBtoA(void)
|
||
{
|
||
uint32_t TotalWords = (BL.Para.AppSize + 3) / 4; /*实际固件字数*/
|
||
uint32_t SecPerBank = FLASH_SECTOR_SIZE / 4;
|
||
uint32_t FullSectors = TotalWords / SecPerBank;
|
||
uint32_t RemainWords = TotalWords % SecPerBank;
|
||
uint32_t Sec, Base;
|
||
|
||
for(Sec = 0; Sec < FullSectors; Sec++) {
|
||
Base = APP_A_ADDRESS + Sec * FLASH_SECTOR_SIZE;
|
||
EraseFlash(Base, 1);
|
||
for(uint32_t i = 0; i < SecPerBank; i++) {
|
||
s_CopyBuf[i] = *((volatile uint32_t *)(APP_B_ADDRESS + Sec * FLASH_SECTOR_SIZE + i * 4));
|
||
}
|
||
FlashWrite(Base, s_CopyBuf, SecPerBank);
|
||
}
|
||
if(RemainWords > 0) {
|
||
Base = APP_A_ADDRESS + FullSectors * FLASH_SECTOR_SIZE;
|
||
EraseFlash(Base, 1);
|
||
for(uint32_t i = 0; i < RemainWords; i++) {
|
||
s_CopyBuf[i] = *((volatile uint32_t *)(APP_B_ADDRESS + FullSectors * FLASH_SECTOR_SIZE + i * 4));
|
||
}
|
||
FlashWrite(Base, s_CopyBuf, RemainWords);
|
||
}
|
||
/*整包校验A区*/
|
||
return (GetCrc32(APP_A_ADDRESS, BL.Para.AppSize) == BL.Para.Crc32Check);
|
||
}
|
||
|
||
static uint32_t s_StashBuf[FLASH_SECTOR_SIZE / 4]; /*外部Flash读缓冲(8KB)*/
|
||
|
||
/*****************************************************************************************
|
||
* 函数名称: StashToB
|
||
* 功能描述: Cat1远程升级: 将外部SPI Flash暂存区固件搬运到B区(逐8KB: 读外部2×4KB→擦写B区1×8KB)
|
||
* 参 数: 无
|
||
* 返 回 值: 无(搬运后由调用方CRC32校验B区)
|
||
*****************************************************************************************/
|
||
static void StashToB(void)
|
||
{
|
||
uint32_t TotalWords = (BL.Para.AppSize + 3) / 4; /*实际固件字数*/
|
||
uint32_t SecPerBank = FLASH_SECTOR_SIZE / 4;
|
||
uint32_t FullSectors = TotalWords / SecPerBank;
|
||
uint32_t RemainWords = TotalWords % SecPerBank;
|
||
uint32_t Sec, Base, SrcAddr;
|
||
|
||
for(Sec = 0; Sec < FullSectors; Sec++) {
|
||
Base = APP_B_ADDRESS + Sec * FLASH_SECTOR_SIZE;
|
||
SrcAddr = FLASH_FW_STASH_SECTOR * SPIFLASH_SECTORSIZE + Sec * FLASH_SECTOR_SIZE;
|
||
FeedDog();
|
||
ExtFlashRead(SrcAddr, (uint8_t *)s_StashBuf, FLASH_SECTOR_SIZE);
|
||
EraseFlash(Base, 1);
|
||
FlashWrite(Base, s_StashBuf, SecPerBank);
|
||
}
|
||
if(RemainWords > 0) {
|
||
Base = APP_B_ADDRESS + FullSectors * FLASH_SECTOR_SIZE;
|
||
SrcAddr = FLASH_FW_STASH_SECTOR * SPIFLASH_SECTORSIZE + FullSectors * FLASH_SECTOR_SIZE;
|
||
FeedDog();
|
||
ExtFlashRead(SrcAddr, (uint8_t *)s_StashBuf, RemainWords * 4);
|
||
EraseFlash(Base, 1);
|
||
FlashWrite(Base, s_StashBuf, RemainWords);
|
||
}
|
||
}
|
||
|
||
/*****************************************************************************************
|
||
* 函数名称: SendResponseCmd
|
||
* 功能描述: 发送响应帧 (0x7D + DevMac)
|
||
*****************************************************************************************/
|
||
static void SendResponseCmd(uint8_t Cmd, uint16_t PayLoad)
|
||
{
|
||
uint8_t sData[24];
|
||
uint16_t sLen;
|
||
uint16_t crc16;
|
||
FrameH Frame = (FrameH)sData;
|
||
|
||
Frame->Header = 0x7D;
|
||
memcpy(Frame->DevMac, s_DevMac, 6);
|
||
Frame->Cmd = Cmd;
|
||
|
||
if(Cmd == UPDATE_CMD_SLAVE_RES) {
|
||
Frame->PayloadLen = 1;
|
||
sData[sizeof(FrameHeader_t)] = (uint8_t)PayLoad;
|
||
}
|
||
else if(Cmd == UPDATE_CMD_SLAVE_REQ_DATA) {
|
||
Frame->PayloadLen = 4;
|
||
GDReq GDData = (GDReq)&sData[sizeof(FrameHeader_t)];
|
||
GDData->PackageIndex = PayLoad;
|
||
GDData->PackageNum = BL.AppPackageCnt;
|
||
}
|
||
sLen = sizeof(FrameHeader_t) + Frame->PayloadLen;
|
||
crc16 = CRC_Modbus(CRC16_BASE, sData, sLen);
|
||
sData[sLen++] = crc16 & 0xFF;
|
||
sData[sLen++] = (crc16 >> 8) & 0xFF;
|
||
|
||
RS485Ch1UartSend(sData, sLen);
|
||
}
|
||
|
||
/*****************************************************************************************
|
||
* 函数名称: AnalyzeData
|
||
* 功能描述: 解析接收帧 (0x81升级请求 / 0x82数据包)
|
||
*****************************************************************************************/
|
||
bool AnalyzeData(uint8_t *rData, uint16_t rLen)
|
||
{
|
||
uint16_t crc16, check;
|
||
|
||
check = CRC_Modbus(CRC16_BASE, rData, rLen - 2);
|
||
crc16 = (rData[rLen - 1] << 8) | rData[rLen - 2];
|
||
|
||
if(check != crc16) {
|
||
return false;
|
||
}
|
||
|
||
FrameH Frame = (FrameH)rData;
|
||
|
||
/*校验MAC地址是否匹配(支持广播全0xFF)*/
|
||
int ret = memcmp(Frame->DevMac, s_DevMac, 6);
|
||
if(ret != 0) {
|
||
bool isBroadcast = true;
|
||
for(int i = 0; i < 6; i++) {
|
||
if(Frame->DevMac[i] != 0xFF) {
|
||
isBroadcast = false;
|
||
break;
|
||
}
|
||
}
|
||
if(!isBroadcast) {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/*命令处理*/
|
||
if(Frame->Cmd == UPDATE_CMD_MASTER_REQ) {
|
||
if(BL.Status != BL_IDLE) {
|
||
return false;
|
||
}
|
||
UDReq UpData = (UDReq)&rData[sizeof(FrameHeader_t)];
|
||
/*固件大小合法性检查: 为0或超出B区容量时拒绝升级*/
|
||
if(UpData->AppSize == 0 || UpData->AppSize > APP_BANK_SIZE) {
|
||
return false;
|
||
}
|
||
BL.Para.AppFlag = 0;
|
||
BL.Para.UpdateFlag = APP_UPDATE_FLAG;
|
||
BL.Para.Crc32Check = UpData->AppCrc32;
|
||
BL.Para.PackageCnt = UpData->PackageNum;
|
||
BL.Para.AppSize = UpData->AppSize;
|
||
WriteBootPara(&BL.Para);
|
||
/*回0x01 ACK应答, 确认收到升级请求, 载荷=0x20*/
|
||
SendResponseCmd(UPDATE_CMD_SLAVE_RES, 0x20);
|
||
BL.BootLoader1mSDlyCnt = 20;
|
||
BL.Status = BL_RESET;
|
||
return true;
|
||
}
|
||
else if(Frame->Cmd == UPDATE_CMD_MASTRE_RES_DATA) {
|
||
if(BL.UpDateFlag == false) {
|
||
return false;
|
||
}
|
||
/*状态守卫: 仅下载状态接收数据, 防止搬运/复位阶段迟到包破坏B区*/
|
||
if(BL.Status != BL_GET_DATA && BL.Status != BL_WAIT_REV) {
|
||
return false;
|
||
}
|
||
DownRes DownData = (DownRes)&rData[sizeof(FrameHeader_t)];
|
||
if(BL.AppPackageIdx != DownData->PackageIndex) {
|
||
return false;
|
||
}
|
||
/*写数据到Flash*/
|
||
AppWriteFlash(APP_B_ADDRESS, BL.AppPackageIdx * 200, &rData[sizeof(FrameHeader_t) + sizeof(DownResponse_t)], DownData->DataLen);
|
||
BL.AppPackageIdx++;
|
||
BL.RevErrCnt = 0;
|
||
|
||
if(BL.AppPackageIdx < BL.AppPackageCnt) {
|
||
BL.Status = BL_GET_DATA;
|
||
BL.BootLoader1mSDlyCnt = 5;
|
||
}
|
||
else {
|
||
/*全部数据处理完成: 整包校验B区CRC32(此时尚未触碰A区, 原App完好)*/
|
||
uint32_t crc32 = GetCrc32(APP_B_ADDRESS, BL.Para.AppSize);
|
||
if(crc32 == BL.Para.Crc32Check) {
|
||
/*B区校验通过: 关闭接收, 进入搬运阶段(B→A), 搬运并校验A区后才置升级完成标记*/
|
||
BL.UpDateFlag = false;
|
||
BL.CopyRetryCnt = 0;
|
||
BL.Status = BL_COPY_TO_A;
|
||
}
|
||
else {
|
||
/*B区校验失败: A区未动, 恢复老App启动标志并复位, 主机可重新发起升级*/
|
||
BL.Para.AppFlag = APP_START_FLAG;
|
||
BL.Para.UpdateFlag = 0;
|
||
WriteBootPara(&BL.Para);
|
||
BL.UpDateFlag = false;
|
||
BL.BootLoader1mSDlyCnt = 100;
|
||
BL.Status = BL_RESET;
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
/*****************************************************************************************
|
||
* 函数名称: BootLoader1mSRoutine
|
||
* 功能描述: BootLoader 1ms定时(由SysTick中断调用)
|
||
*****************************************************************************************/
|
||
static void BootLoader1mSRoutine(void)
|
||
{
|
||
if(BL.BootLoader1mSDlyCnt) {
|
||
BL.BootLoader1mSDlyCnt--;
|
||
}
|
||
|
||
if(BL.UartRevTimeOutCnt > 0) {
|
||
BL.UartRevTimeOutCnt--;
|
||
}
|
||
|
||
BL.FeedDogDlyCnt++;
|
||
}
|
||
|
||
/*****************************************************************************************
|
||
* 函数名称: SysTick_IrqHandler
|
||
* 功能描述: SysTick中断
|
||
*****************************************************************************************/
|
||
void SysTick_IrqHandler(void)
|
||
{
|
||
BootLoader1mSRoutine();
|
||
}
|
||
|
||
/*****************************************************************************************
|
||
* 函数名称: FeedDogHandler
|
||
* 功能描述: 看门狗喂狗
|
||
*****************************************************************************************/
|
||
void FeedDogHandler(void)
|
||
{
|
||
if(BL.FeedDogDlyCnt >= 200) {
|
||
FeedDog();
|
||
BL.FeedDogDlyCnt = 0;
|
||
}
|
||
}
|
||
|
||
/*****************************************************************************************
|
||
* 函数名称: RS485Ch1RxIrqCallback
|
||
* 功能描述: RS485通道1接收中断回调(每字节), 组帧(0x7D)
|
||
*****************************************************************************************/
|
||
static uint16_t rLen;
|
||
static uint8_t rBuff[300];
|
||
static bool Header;
|
||
static uint16_t PayLen;
|
||
|
||
void RS485Ch1RxIrqCallback(uint8_t RxData)
|
||
{
|
||
if(BL.UartRevTimeOutCnt == 0) {
|
||
Header = false;
|
||
rLen = 0;
|
||
PayLen = 0;
|
||
}
|
||
BL.UartRevTimeOutCnt = 3;
|
||
|
||
if(Header == false && (RxData == 0x7D)) {
|
||
Header = true;
|
||
rLen = 0;
|
||
PayLen = 0;
|
||
rBuff[rLen++] = RxData;
|
||
}
|
||
else if(Header == true) {
|
||
if(rLen >= sizeof(rBuff)) {
|
||
Header = false;
|
||
rLen = 0;
|
||
return;
|
||
}
|
||
rBuff[rLen++] = RxData;
|
||
if(rLen == 9) {
|
||
PayLen = RxData;
|
||
if(PayLen > 256) {
|
||
Header = false;
|
||
rLen = 0;
|
||
return;
|
||
}
|
||
}
|
||
else if(rLen == sizeof(FrameHeader_t) + PayLen + 2) {
|
||
BL.RxLen = rLen;
|
||
memcpy(BL.RxBuff, rBuff, BL.RxLen);
|
||
BL.RxFlag = true;
|
||
Header = false;
|
||
rLen = 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
/*****************************************************************************************
|
||
* 函数名称: BootLoaderLoopHandler
|
||
* 功能描述: BootLoader主循环
|
||
*****************************************************************************************/
|
||
void BootLoaderLoopHandler(void)
|
||
{
|
||
/*帧解析 - BL_RESET状态下不处理新帧, 避免复位等待期被0x81打断*/
|
||
if(BL.RxFlag && BL.Status != BL_RESET) {
|
||
BL.RxFlag = false;
|
||
AnalyzeData(BL.RxBuff, BL.RxLen);
|
||
}
|
||
|
||
switch(BL.Status) {
|
||
case BL_IDLE:
|
||
break;
|
||
|
||
case BL_RESET:
|
||
if(BL.BootLoader1mSDlyCnt > 0) {
|
||
break;
|
||
}
|
||
NVIC_SystemReset();
|
||
break;
|
||
|
||
case BL_START_APP:
|
||
if(JumpToApp(APP_ADDRESS) == false) {
|
||
BL.Status = BL_IDLE;
|
||
}
|
||
break;
|
||
|
||
case BL_COPY_TO_A:
|
||
/*搬运B区已校验镜像到A区, 完成后整包校验A区*/
|
||
if(CopyAppBtoA()) {
|
||
/*搬运校验通过: 立即擦除B区作废镜像, 防止下次升级时B区残留被误判为断电续传而跳过下载*/
|
||
EraseFlash(APP_B_ADDRESS, APP_BANK_SECTORS);
|
||
/*置升级完成标记(每次升级均置位), App启动时擦除外部参数分区并恢复APP_START_FLAG*/
|
||
BL.Para.AppFlag = APP_BOOT_UPGRADE_FLAG;
|
||
BL.Para.UpdateFlag = 0;
|
||
WriteBootPara(&BL.Para);
|
||
BL.BootLoader1mSDlyCnt = 100;
|
||
BL.Status = BL_RESET;
|
||
}
|
||
else {
|
||
/*搬运后A区校验失败(B区仍有效): 重试一次搬运*/
|
||
if(BL.CopyRetryCnt++ < 1) {
|
||
break;
|
||
}
|
||
/*重试仍失败: 清标志停留等待主机重新升级*/
|
||
BL.Para.AppFlag = 0;
|
||
BL.Para.UpdateFlag = 0;
|
||
WriteBootPara(&BL.Para);
|
||
BL.Status = BL_IDLE;
|
||
}
|
||
break;
|
||
|
||
case BL_STASH_TO_B:
|
||
FeedDog();
|
||
/*固件大小非法: 无法搬运, 恢复老App(A区未动)并复位*/
|
||
if(BL.Para.AppSize == 0 || BL.Para.AppSize > APP_BANK_SIZE) {
|
||
BL.Para.AppFlag = APP_START_FLAG;
|
||
BL.Para.UpdateFlag = 0;
|
||
WriteBootPara(&BL.Para);
|
||
BL.BootLoader1mSDlyCnt = 100;
|
||
BL.Status = BL_RESET;
|
||
break;
|
||
}
|
||
/*外部SPI Flash暂存区→B区(逐8KB), StashToB幂等: 搬运中断电重启后自动重做*/
|
||
StashToB();
|
||
/*B区整包校验: 通过进搬运, 失败清标志回老App*/
|
||
if(GetCrc32(APP_B_ADDRESS, BL.Para.AppSize) == BL.Para.Crc32Check) {
|
||
BL.CopyRetryCnt = 0;
|
||
BL.Status = BL_COPY_TO_A;
|
||
}
|
||
else {
|
||
BL.Para.AppFlag = APP_START_FLAG;
|
||
BL.Para.UpdateFlag = 0;
|
||
WriteBootPara(&BL.Para);
|
||
BL.BootLoader1mSDlyCnt = 100;
|
||
BL.Status = BL_RESET;
|
||
}
|
||
break;
|
||
|
||
case BL_ERASE_FLASH:
|
||
FeedDog();
|
||
/*固件大小非法: 无法下载, 恢复老App(A区未动)并复位*/
|
||
if(BL.Para.AppSize == 0 || BL.Para.AppSize > APP_BANK_SIZE) {
|
||
BL.Para.AppFlag = APP_START_FLAG;
|
||
BL.Para.UpdateFlag = 0;
|
||
WriteBootPara(&BL.Para);
|
||
BL.BootLoader1mSDlyCnt = 100;
|
||
BL.Status = BL_RESET;
|
||
break;
|
||
}
|
||
/*先校验B区: 已有完整有效镜像则直接搬运(断电续传: 下载完未搬运/搬运中断电)*/
|
||
if(GetCrc32(APP_B_ADDRESS, BL.Para.AppSize) == BL.Para.Crc32Check) {
|
||
BL.CopyRetryCnt = 0;
|
||
BL.Status = BL_COPY_TO_A;
|
||
break;
|
||
}
|
||
/*B区无效: 仅擦除B区(A区保留原App), 逐包下载到B区*/
|
||
EraseFlash(APP_B_ADDRESS, APP_BANK_SECTORS);
|
||
FeedDog();
|
||
BL.Status = BL_GET_DATA;
|
||
BL.BootLoader1mSDlyCnt = 200;
|
||
BL.AppPackageCnt = BL.Para.PackageCnt;
|
||
BL.RevErrCnt = 0;
|
||
BL.UpDateFlag = true;
|
||
break;
|
||
|
||
case BL_GET_DATA:
|
||
if(BL.BootLoader1mSDlyCnt > 0) {
|
||
break;
|
||
}
|
||
/*请求下一包数据 - 通过RS485应答*/
|
||
SendResponseCmd(UPDATE_CMD_SLAVE_REQ_DATA, BL.AppPackageIdx);
|
||
BL.Status = BL_WAIT_REV;
|
||
BL.BootLoader1mSDlyCnt = 500;
|
||
break;
|
||
|
||
case BL_WAIT_REV:
|
||
if(BL.BootLoader1mSDlyCnt == 0) {
|
||
BL.Status = BL_GET_DATA_TIMEOUT;
|
||
}
|
||
break;
|
||
|
||
case BL_GET_DATA_TIMEOUT:
|
||
BL.RevErrCnt++;
|
||
if(BL.RevErrCnt < 3) {
|
||
BL.Status = BL_GET_DATA;
|
||
}
|
||
else {
|
||
/*下载超时: A区未动, 恢复老App启动标志并复位(设备回到可运行状态)*/
|
||
BL.Para.AppFlag = APP_START_FLAG;
|
||
BL.Para.UpdateFlag = 0;
|
||
WriteBootPara(&BL.Para);
|
||
BL.RevErrCnt = 0;
|
||
BL.UpDateFlag = false;
|
||
BL.BootLoader1mSDlyCnt = 100;
|
||
BL.Status = BL_RESET;
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
/*****************************************************************************************
|
||
* 函数名称: SetDefaultBootPara
|
||
* 功能描述: 填充BootPara_t中所有默认配置(服务器/Lora/通道/RS485), 由Boot直接配置
|
||
*****************************************************************************************/
|
||
static void SetDefaultBootPara(BootPara_t *Para)
|
||
{
|
||
Para->SvrAddr[0] = GATEWAY_SVR_ADDR0;
|
||
Para->SvrAddr[1] = GATEWAY_SVR_ADDR1;
|
||
Para->SvrAddr[2] = GATEWAY_SVR_ADDR2;
|
||
Para->SvrAddr[3] = GATEWAY_SVR_ADDR3;
|
||
Para->SvrPort = GATEWAY_SVR_PORT;
|
||
Para->LoraFreq = GATEWAY_LORA_FREQ;
|
||
Para->Much = GATEWAY_MUCH;
|
||
Para->Auch = GATEWAY_AUCH;
|
||
Para->Duch = GATEWAY_DUCH;
|
||
Para->CuchMask = GATEWAY_CUCH_MASK;
|
||
}
|
||
|
||
/*****************************************************************************************
|
||
* 函数名称: main
|
||
* 功能描述: 主函数
|
||
*****************************************************************************************/
|
||
int32_t main(void)
|
||
{
|
||
BSP_Init();
|
||
InitCrc32Table(pdwCrc32Tbl);
|
||
|
||
/*从固定地址0x4000读入网关MAC编码*/
|
||
memcpy(&s_DevMac[0], &GwMacConst[0], 6);
|
||
|
||
/*读取boot参数*/
|
||
ReadBootPara(&BL.Para);
|
||
|
||
/*设备判断*/
|
||
if(BL.Para.GwMac[0] == 0xFF && BL.Para.GwMac[1] == 0xFF) {
|
||
/*首次运行GwMac无效*/
|
||
if(BL.Para.FirstRunFlag == 0xFFFFFFFF) {
|
||
BL.Status = BL_START_APP;
|
||
}
|
||
else {
|
||
BL.Status = BL_IDLE;
|
||
}
|
||
BL.Para.AppFlag = 0;
|
||
BL.Para.UpdateFlag = 0;
|
||
BL.Para.FirstRunFlag = 0;
|
||
memcpy(&BL.Para.GwMac[0], &s_DevMac[0], 6);
|
||
SetDefaultBootPara(&BL.Para);
|
||
WriteBootPara(&BL.Para);
|
||
}
|
||
else {
|
||
/*更新MAC地址*/
|
||
memcpy(&s_DevMac[0], &BL.Para.GwMac[0], 6);
|
||
|
||
/*兼容旧参数区: 默认配置未写入(0xFF)时补默认值*/
|
||
if(BL.Para.SvrAddr[0] == 0xFF && BL.Para.SvrAddr[1] == 0xFF) {
|
||
SetDefaultBootPara(&BL.Para);
|
||
WriteBootPara(&BL.Para);
|
||
}
|
||
|
||
/*APP_BOOT_UPGRADE_FLAG也需直接启动App:升级完成后由App擦除外部参数分区,
|
||
若此处不放行,设备升级完会停留在BL_IDLE等待升级命令而无法启动*/
|
||
if(BL.Para.AppFlag == APP_START_FLAG || BL.Para.AppFlag == APP_BOOT_UPGRADE_FLAG) {
|
||
BL.Status = BL_START_APP;
|
||
}
|
||
else if(BL.Para.UpdateFlag == APP_UPDATE_SPI_FLAG) {
|
||
BL.Status = BL_STASH_TO_B; /*Cat1远程升级: 外部Flash暂存区→B区→A区*/
|
||
}
|
||
else if(BL.Para.UpdateFlag == APP_UPDATE_FLAG) {
|
||
BL.Status = BL_ERASE_FLASH;
|
||
}
|
||
else {
|
||
BL.Status = BL_IDLE;
|
||
}
|
||
}
|
||
|
||
while(1) {
|
||
FeedDogHandler();
|
||
BootLoaderLoopHandler();
|
||
}
|
||
}
|
||
|