Files
HC32F460BootLoader/source/User/Src/main.c
T

484 lines
13 KiB
C
Raw Normal View History

2026-06-22 09:19:00 +08:00
#include <stdlib.h>
#include <string.h>
2026-06-22 09:19:00 +08:00
#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};
2026-06-22 09:19:00 +08:00
uint32_t pdwCrc32Tbl[256];
BootLoader_t BL;
2026-06-22 09:19:00 +08:00
/*****************************************************************************************
* 函数名称: InitCrc32Table
* 功能描述: CRC32查表初始化
*****************************************************************************************/
2026-06-22 09:19:00 +08:00
void InitCrc32Table(uint32_t* Crc32Tbl)
{
for(int wCnt = 0; wCnt < 256; wCnt++) {
2026-06-22 09:19:00 +08:00
uint32_t dwCrc = wCnt;
for(int ucCnt = 0; ucCnt < 8; ucCnt++) {
if(dwCrc & 1) {
2026-06-22 09:19:00 +08:00
dwCrc = (dwCrc >> 1) ^ 0xEDB88320;
}
else {
2026-06-22 09:19:00 +08:00
dwCrc >>= 1;
}
}
Crc32Tbl[wCnt] = dwCrc;
}
}
/*****************************************************************************************
* 函数名称: GetCrc32
* 功能描述: 计算APP区CRC32校验值
*****************************************************************************************/
2026-06-22 09:19:00 +08:00
uint32_t GetCrc32(int dwLen)
{
uint32_t Data;
uint32_t dwCrc32Data = 0xFFFFFFFF;
for(int dwCnt = 0; dwCnt < dwLen; dwCnt++) {
2026-06-22 09:19:00 +08:00
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校验
*****************************************************************************************/
2026-06-22 09:19:00 +08:00
uint16_t CRC_Modbus(uint16_t wBase, __IO uint8_t *para, uint16_t length)
{
uint16_t crc = 0xFFFF;
uint16_t index, i;
2026-06-22 09:19:00 +08:00
for(index = 0; index < length; index++) {
2026-06-22 09:19:00 +08:00
crc ^= para[index];
for(i = 0; i < 8; i++) {
if(crc & 1) {
crc >>= 1;
crc ^= wBase;
}
else {
2026-06-22 09:19:00 +08:00
crc >>= 1;
}
2026-06-22 09:19:00 +08:00
}
}
return crc;
}
/*****************************************************************************************
* 函数名称: JumpToApp
* 功能描述: 跳转APP
*****************************************************************************************/
2026-06-22 09:19:00 +08:00
static bool JumpToApp(uint32_t AppAddr)
{
uint32_t u32StackTop = *((__IO uint32_t *)AppAddr);
uint32_t JumpAddress;
func_ptr_t JumpToApplication;
2026-06-22 09:19:00 +08:00
if((u32StackTop > SRAM_BASE) && (u32StackTop <= (SRAM_BASE + SRAM_SIZE))) {
2026-06-22 09:19:00 +08:00
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));
2026-06-22 09:19:00 +08:00
JumpToApplication();
return true;
2026-06-22 09:19:00 +08:00
}
return false;
2026-06-22 09:19:00 +08:00
}
/*****************************************************************************************
* 函数名称: 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)
2026-06-22 09:19:00 +08:00
{
uint8_t sData[24];
uint16_t sLen;
2026-06-22 09:19:00 +08:00
uint16_t crc16;
FrameH Frame = (FrameH)sData;
Frame->Header = 0x7D;
memcpy(Frame->DevMac, s_DevMac, 6);
2026-06-22 09:19:00 +08:00
Frame->Cmd = Cmd;
if(Cmd == UPDATE_CMD_SLAVE_RES) {
2026-06-22 09:19:00 +08:00
Frame->PayloadLen = 1;
sData[sizeof(FrameHeader_t)] = (uint8_t)PayLoad;
2026-06-22 09:19:00 +08:00
}
else if(Cmd == UPDATE_CMD_SLAVE_REQ_DATA) {
2026-06-22 09:19:00 +08:00
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);
2026-06-22 09:19:00 +08:00
}
/*****************************************************************************************
* 函数名称: AnalyzeData
* 功能描述: 解析接收帧 (0x81升级请求 / 0x82数据包)
*****************************************************************************************/
2026-06-22 09:19:00 +08:00
bool AnalyzeData(uint8_t *rData, uint16_t rLen)
{
uint16_t crc16, check;
2026-06-22 09:19:00 +08:00
check = CRC_Modbus(CRC16_BASE, rData, rLen - 2);
crc16 = (rData[rLen - 1] << 8) | rData[rLen - 2];
2026-06-22 09:19:00 +08:00
if(check != crc16) {
return false;
}
2026-06-22 09:19:00 +08:00
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;
}
2026-06-22 09:19:00 +08:00
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);
2026-06-22 09:19:00 +08:00
BL.BootLoader1mSDlyCnt = 20;
BL.Status = BL_RESET;
return true;
2026-06-22 09:19:00 +08:00
}
else if(Frame->Cmd == UPDATE_CMD_MASTRE_RES_DATA) {
if(BL.UpDateFlag == false) {
2026-06-22 09:19:00 +08:00
return false;
}
2026-06-22 09:19:00 +08:00
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);
2026-06-22 09:19:00 +08:00
BL.AppPackageIdx++;
BL.RevErrCnt = 0;
2026-06-22 09:19:00 +08:00
if(BL.AppPackageIdx < BL.AppPackageCnt) {
BL.Status = BL_GET_DATA;
BL.BootLoader1mSDlyCnt = 5;
}
else {
/*全部数据处理完成, 校验CRC32*/
2026-06-22 09:19:00 +08:00
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;
2026-06-22 09:19:00 +08:00
BL.Para.UpdateFlag = 0;
WriteBootPara(&BL.Para);
BL.UpDateFlag = false;
BL.Status = BL_IDLE;
2026-06-22 09:19:00 +08:00
}
}
return true;
2026-06-22 09:19:00 +08:00
}
return false;
}
/*****************************************************************************************
* 函数名称: BootLoader1mSRoutine
* 功能描述: BootLoader 1ms定时(由SysTick中断调用)
*****************************************************************************************/
static void BootLoader1mSRoutine(void)
{
if(BL.BootLoader1mSDlyCnt) {
BL.BootLoader1mSDlyCnt--;
}
if(BL.UartRevTimeOutCnt > 0) {
BL.UartRevTimeOutCnt--;
}
BL.FeedDogDlyCnt++;
2026-06-22 09:19:00 +08:00
}
/*****************************************************************************************
* 函数名称: 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主循环
*****************************************************************************************/
2026-06-22 09:19:00 +08:00
void BootLoaderLoopHandler(void)
{
/*帧解析 - BL_RESET状态下不处理新帧, 避免复位等待期被0x81打断*/
if(BL.RxFlag && BL.Status != BL_RESET) {
2026-06-22 09:19:00 +08:00
BL.RxFlag = false;
AnalyzeData(BL.RxBuff, BL.RxLen);
}
switch(BL.Status) {
2026-06-22 09:19:00 +08:00
case BL_IDLE:
break;
2026-06-22 09:19:00 +08:00
case BL_RESET:
if(BL.BootLoader1mSDlyCnt > 0) {
break;
}
NVIC_SystemReset();
break;
2026-06-22 09:19:00 +08:00
case BL_START_APP:
if(JumpToApp(APP_ADDRESS) == false) {
BL.Status = BL_IDLE;
}
break;
2026-06-22 09:19:00 +08:00
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;
2026-06-22 09:19:00 +08:00
case BL_GET_DATA:
if(BL.BootLoader1mSDlyCnt > 0) {
2026-06-22 09:19:00 +08:00
break;
}
/*请求下一包数据 - 通过RS485应答*/
SendResponseCmd(UPDATE_CMD_SLAVE_REQ_DATA, BL.AppPackageIdx);
2026-06-22 09:19:00 +08:00
BL.Status = BL_WAIT_REV;
BL.BootLoader1mSDlyCnt = 500;
break;
2026-06-22 09:19:00 +08:00
case BL_WAIT_REV:
if(BL.BootLoader1mSDlyCnt == 0) {
BL.Status = BL_GET_DATA_TIMEOUT;
}
break;
2026-06-22 09:19:00 +08:00
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
* 功能描述: 主函数
*****************************************************************************************/
2026-06-22 09:19:00 +08:00
int32_t main(void)
{
BSP_Init();
InitCrc32Table(pdwCrc32Tbl);
/*从固定地址0x4000读入网关MAC编码*/
memcpy(&s_DevMac[0], &GwMacConst[0], 6);
/*读取boot参数*/
2026-06-22 09:19:00 +08:00
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;
}
2026-06-22 09:19:00 +08:00
BL.Para.AppFlag = 0;
BL.Para.UpdateFlag = 0;
BL.Para.FirstRunFlag = 0;
memcpy(&BL.Para.GwMac[0], &s_DevMac[0], 6);
SetDefaultBootPara(&BL.Para);
2026-06-22 09:19:00 +08:00
WriteBootPara(&BL.Para);
}
else {
/*更新MAC地址*/
memcpy(&s_DevMac[0], &BL.Para.GwMac[0], 6);
2026-06-22 09:19:00 +08:00
/*兼容旧参数区: 默认配置未写入(0xFF)时补默认值*/
if(BL.Para.SvrAddr[0] == 0xFF && BL.Para.SvrAddr[1] == 0xFF) {
SetDefaultBootPara(&BL.Para);
WriteBootPara(&BL.Para);
}
2026-06-22 09:19:00 +08:00
/*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;
2026-06-22 09:19:00 +08:00
}
else if(BL.Para.UpdateFlag == APP_UPDATE_FLAG) {
BL.Status = BL_ERASE_FLASH;
}
else {
BL.Status = BL_IDLE;
2026-06-22 09:19:00 +08:00
}
}
while(1) {
FeedDogHandler();
BootLoaderLoopHandler();
}
}
2026-06-22 09:19:00 +08:00