#include #include #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 * 功能描述: 计算APP区CRC32校验值 *****************************************************************************************/ uint32_t GetCrc32(int dwLen) { uint32_t Data; uint32_t dwCrc32Data = 0xFFFFFFFF; for(int dwCnt = 0; dwCnt < dwLen; dwCnt++) { Data = *((volatile uint8_t*)(APP_ADDRESS + 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 * 功能描述: 写APP数据到Flash (每包200字节) *****************************************************************************************/ void AppWriteFlash(uint32_t AddrOffset, uint8_t *wData, int wLen) { FlashWrite(APP_ADDRESS + AddrOffset, (uint32_t *)wData, wLen / 4); } /***************************************************************************************** * 函数名称: 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)]; 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; } DownRes DownData = (DownRes)&rData[sizeof(FrameHeader_t)]; if(BL.AppPackageIdx != DownData->PackageIndex) { return false; } /*写数据到Flash*/ AppWriteFlash(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 { /*全部数据处理完成, 校验CRC32*/ uint32_t crc32 = GetCrc32(BL.Para.AppSize); if(crc32 == BL.Para.Crc32Check) { /*置升级完成标记(每次升级均置位):Boot本身不擦除外部Flash, 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 { BL.Para.AppFlag = 0; BL.Para.UpdateFlag = 0; WriteBootPara(&BL.Para); BL.UpDateFlag = false; BL.Status = BL_IDLE; } } 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_ERASE_FLASH: FeedDog(); EraseFlash(); 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 { BL.Status = BL_IDLE; BL.Para.AppFlag = 0; BL.RevErrCnt = 0; BL.Para.UpdateFlag = 0; WriteBootPara(&BL.Para); BL.UpDateFlag = false; } 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_FLAG) { BL.Status = BL_ERASE_FLASH; } else { BL.Status = BL_IDLE; } } while(1) { FeedDogHandler(); BootLoaderLoopHandler(); } }