fix(flash,upgrade): 注册应答/Flash并发/参数校验修复+升级后擦参数分区+注释统一UTF-8
- 注册应答先发后写Flash,重复注册参数无变化时跳过写入;SX1276发送前等待上一帧TxDone,防止应答帧被下一帧截断 - SPI Flash操作增加互斥锁(ReadPara/WritePara/AddLog/SavLogNum),修复多线程并发写坏参数镜像 - WritePara自行擦除参数区全部扇区并加越界保护;移除通用写函数中的日志簿记副作用(双擦+LastLogEndAddr污染) - 开机参数加载增加CRC校验与通讯单元表语义清洗;修复忽略ReadPara返回值导致坏镜像放行并被回写洗白的问题 - RS485Send函数指针每次开机重设,不再从Flash恢复旧固件代码地址 - Boot升级完成置APP_BOOT_UPGRADE_FLAG,App启动时仅擦外部参数分区(扇区0~1,历史日志保留)并恢复标志 - 参数SavFlag绑定PARA_LAYOUT_VER布局版本戳,布局变更自动回退默认参数 - res gxjt改为仅擦参数分区,不再触发全片扫描 - 全部源码注释统一UTF-8(无BOM),修复历史GBK/UTF-8混合编码及乱码字符 - 软件版本 1.2 -> 1.3
This commit is contained in:
@@ -75,8 +75,19 @@ void GateWayInit(void)
|
||||
boot_para_t bootParam;
|
||||
dev_boot_read_param(&bootParam);
|
||||
rt_kprintf("AppFlag: 0x%08x\r\n", bootParam.AppFlag);
|
||||
/*升级完成后Boot会设AppFlag=APP_START_FLAG并清UpdateFlag=0,
|
||||
检测到升级异常(UpdateFlag仍为APP_UPDATE_FLAG 或 非首次且AppFlag无效)时擦外置Flash*/
|
||||
/*升级完成后Boot置AppFlag=APP_BOOT_UPGRADE_FLAG(每次升级均置位,不限首次)。
|
||||
App启动时据此擦除参数分区(仅扇区0~1,非全片擦除)并恢复APP_START_FLAG;
|
||||
随后ReadPara读到0xFF→SavFlag无效→自动加载默认参数,传感器重新注册。
|
||||
须在下方升级异常检测之前处理,避免AppFlag!=APP_START_FLAG误触发全片擦除*/
|
||||
if(bootParam.AppFlag == APP_BOOT_UPGRADE_FLAG) {
|
||||
rt_kprintf("Upgrade done, erasing parameter partition...\r\n");
|
||||
for(uint32_t Sector = GATEWEY_PARA_SAV_SECTOR; Sector < LOG_INFO_START_SECTOR; Sector++) {
|
||||
SpiFlashEraseSector(Sector * SPIFLASH_SECTORSIZE);
|
||||
}
|
||||
bootParam.AppFlag = APP_START_FLAG;
|
||||
dev_boot_write_param(bootParam);
|
||||
}
|
||||
/*检测升级异常(UpdateFlag仍为APP_UPDATE_FLAG 或 非首次且AppFlag无效)时擦外置Flash*/
|
||||
if(bootParam.UpdateFlag == APP_UPDATE_FLAG
|
||||
|| (bootParam.FirstRunFlag == 0 && bootParam.AppFlag != APP_START_FLAG)) {
|
||||
rt_kprintf("Boot upgrade detected, erasing external Flash...\r\n");
|
||||
@@ -85,8 +96,21 @@ void GateWayInit(void)
|
||||
dev_boot_write_param(bootParam);
|
||||
}
|
||||
|
||||
bool NeedSavePara = false;
|
||||
int ret = ReadPara((uint8_t *)&GateWay.ConfigPara, sizeof(GWConfigPara_t));
|
||||
if(GateWay.ConfigPara.SavFlag != LOG_SAV_FLAG) {
|
||||
/*ReadPara返回-1表示CRC校验失败(参数镜像损坏)。原实现只检查SavFlag:
|
||||
SavFlag位于结构体最前部,"部分损坏"的镜像(前部有效后部乱码)恰好保留合法
|
||||
SavFlag,坏数据会被整体装入RAM——正是culs显示后面设备参数乱码的根源。
|
||||
CRC失败必须回退默认参数,让传感器走重新注册流程*/
|
||||
if(ret != 0) {
|
||||
rt_kprintf("Para CRC Error, reset to default!\r\n");
|
||||
}
|
||||
if(ret != 0 || GateWay.ConfigPara.SavFlag != LOG_SAV_FLAG) {
|
||||
/*CRC正常但SavFlag无效:flash参数为空(全新设备/曾执行res gxjt/Boot整片擦除后),
|
||||
打印区分于CRC错误路径,便于现场排障判断走的是默认参数还是正常恢复*/
|
||||
if(ret == 0)
|
||||
rt_kprintf("Para empty, load default!\r\n");
|
||||
NeedSavePara = true;
|
||||
memset((uint8_t *)&GateWay.ConfigPara, 0x00, sizeof(GWConfigPara_t));
|
||||
GateWay.ConfigPara.SavFlag = LOG_SAV_FLAG;
|
||||
/*通道/服务器等默认参数全部从Boot参数区(BootPara_t)获取, 由Boot直接配置*/
|
||||
@@ -111,9 +135,7 @@ void GateWayInit(void)
|
||||
GateWay.ConfigPara.Rs485Ch2.UpgradeEnable = false;
|
||||
GateWay.ConfigPara.Rs485Ch2.CommUnitEnable = false;
|
||||
GateWay.ConfigPara.Rs485Ch2.Power = false;
|
||||
GateWay.ConfigPara.Rs485Ch1.RS485Send = RS485Ch1UartSend;
|
||||
GateWay.ConfigPara.Rs485Ch2.RS485Send = RS485Ch2UartSend;
|
||||
|
||||
|
||||
GateWay.ConfigPara.Lora.OnOff = true;
|
||||
GateWay.ConfigPara.Lora.ucChannel = 8;
|
||||
GateWay.ConfigPara.Lora.ucPower = 20;
|
||||
@@ -125,6 +147,36 @@ void GateWayInit(void)
|
||||
|
||||
GateWay.ConfigPara.OutageFlag = false;
|
||||
}
|
||||
else {
|
||||
/*防御被"洗白"的脏数据(镜像部分损坏但CRC合法):对通讯单元表做语义校验,
|
||||
清除无效条目,避免乱码条目占用注册槽位导致新设备注册不上*/
|
||||
for(int i = 0; i < COMMUNIT_NUM_MAX; i++) {
|
||||
CommUnitPara_t *CU = &GateWay.ConfigPara.CommUnitArray[i];
|
||||
uint8_t RegByte;
|
||||
memcpy(&RegByte, &CU->RegFlag, 1); //绕过编译器对bool取值0/1的假定,读取原始字节
|
||||
bool EntryValid = (RegByte == 0 || RegByte == 1);
|
||||
if(EntryValid && RegByte == 1) {
|
||||
bool MacAllFF = true, MacAll00 = true;
|
||||
for(int j = 0; j < 6; j++) {
|
||||
if(CU->Mac[0][j] != 0xFF) MacAllFF = false;
|
||||
if(CU->Mac[0][j] != 0x00) MacAll00 = false;
|
||||
}
|
||||
if(CU->SensorN == 0 || CU->SensorN > SENSOR_NUM_MAX || MacAllFF || MacAll00)
|
||||
EntryValid = false;
|
||||
}
|
||||
if(!EntryValid) {
|
||||
memset(CU, 0x00, sizeof(CommUnitPara_t));
|
||||
NeedSavePara = true;
|
||||
}
|
||||
}
|
||||
if(NeedSavePara)
|
||||
rt_kprintf("CommUnit table dirty, cleaned!\r\n");
|
||||
}
|
||||
|
||||
/*函数指针不允许从Flash恢复:正常加载路径下RS485Send来自旧固件写入Flash的
|
||||
代码地址,固件升级后代码布局变化会使该指针失效(野指针)。每次开机统一重设*/
|
||||
GateWay.ConfigPara.Rs485Ch1.RS485Send = RS485Ch1UartSend;
|
||||
GateWay.ConfigPara.Rs485Ch2.RS485Send = RS485Ch2UartSend;
|
||||
|
||||
/*网关MAC编码从Boot参数区(BootPara_t.GwMac)获取, 由Boot从固定地址0x4000同步
|
||||
(协议规定: Mac[0]=VerInfo, Mac[1:3]=PrjNum, Mac[4:5]=GwNum)*/
|
||||
@@ -212,7 +264,11 @@ void GateWayInit(void)
|
||||
//WritePara((uint8_t *)&GateWay.ConfigPara, sizeof(GWConfigPara_t));
|
||||
}
|
||||
|
||||
WritePara((uint8_t *)&GateWay.ConfigPara, sizeof(GWConfigPara_t));
|
||||
/*原实现开机无条件回写参数:一方面无谓增加一次擦写磨损;另一方面若读出的
|
||||
是坏数据,回写会重新计算CRC把脏数据"洗白"成永久合法,无法自愈。
|
||||
仅在参数被重置或清洗过时才落盘*/
|
||||
if(NeedSavePara)
|
||||
WritePara((uint8_t *)&GateWay.ConfigPara, sizeof(GWConfigPara_t));
|
||||
|
||||
LogInit();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user