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:
2026-09-03 19:00:24 +08:00
parent a6c8cd8a71
commit fe4b9fabf8
7 changed files with 158 additions and 40 deletions
@@ -1029,9 +1029,11 @@ void DebugCmdRestoreFactory(int argc, char *argv[])
} }
DBG_LOG("Restore factory settings, GateWay Restart...\r\n"); DBG_LOG("Restore factory settings, GateWay Restart...\r\n");
memset((uint8_t *)&GateWay->ConfigPara, 0x00, sizeof(GWConfigPara_t)); /*仅擦除参数分区(扇区0~1),非全片擦除;擦除后参数区全0xFF,
WritePara((uint8_t *)&GateWay->ConfigPara, sizeof(GWConfigPara_t)); 重启后SavFlag无效自动加载Boot默认参数*/
rt_thread_delay(1000); for(uint32_t Sector = GATEWEY_PARA_SAV_SECTOR; Sector < LOG_INFO_START_SECTOR; Sector++) {
SpiFlashEraseSector(Sector * SPIFLASH_SECTORSIZE);
} rt_thread_delay(1000);
NVIC_SystemReset(); NVIC_SystemReset();
while(1); while(1);
} }
@@ -1623,7 +1625,7 @@ static void DebugCmdCali(int argc, char *argv[])
TrySendFullPowerCmd(GateWay, ret); TrySendFullPowerCmd(GateWay, ret);
} }
} }
else if(mac[2] == 0x02) { //RS485ͨѶ else if(mac[2] == 0x02) { //RS485通讯
if(GateWay->ConfigPara.Rs485Ch1.Enable == true && !GateWay->ConfigPara.Rs485Ch1.CommUnitEnable) { if(GateWay->ConfigPara.Rs485Ch1.Enable == true && !GateWay->ConfigPara.Rs485Ch1.CommUnitEnable) {
GateWay->ConfigPara.Rs485Ch1.RS485Send(Rs485Cmd, sizeof(CommUnitFrameHeader_t) + 2); GateWay->ConfigPara.Rs485Ch1.RS485Send(Rs485Cmd, sizeof(CommUnitFrameHeader_t) + 2);
DBG_LOG("Calibrate CommUnit: %s!\r\n", argv[1]); DBG_LOG("Calibrate CommUnit: %s!\r\n", argv[1]);
@@ -1752,7 +1754,7 @@ static void DebugLaserConfig(int argc, char *argv[])
} }
} }
} }
else if(mac[2] == 0x02) { //RS485ͨѶ else if(mac[2] == 0x02) { //RS485通讯
if(GateWay->ConfigPara.Rs485Ch1.Enable == true && !GateWay->ConfigPara.Rs485Ch1.CommUnitEnable) { if(GateWay->ConfigPara.Rs485Ch1.Enable == true && !GateWay->ConfigPara.Rs485Ch1.CommUnitEnable) {
GateWay->ConfigPara.Rs485Ch1.RS485Send(Rs485Cmd, len); GateWay->ConfigPara.Rs485Ch1.RS485Send(Rs485Cmd, len);
DBG_LOG("Control RS485 laser CommUnit: %s!\r\n", argv[1]); DBG_LOG("Control RS485 laser CommUnit: %s!\r\n", argv[1]);
@@ -418,6 +418,14 @@ void Sx1276LoRaLoopHandler(GateWayPara GateWay)
} }
void Sx1276LoRaSendBuffer(uint8_t* pucBuff, uint16_t ucLen) void Sx1276LoRaSendBuffer(uint8_t* pucBuff, uint16_t ucLen)
{ {
uint16_t TxDoneWaitCnt = 0;
/*LoRa发送是异步的(TxDone中断结束,IsrSx1276LoRaTxRx中将State恢复为IDLE)。
若上一帧仍在发送时再次调用本函数,下面设置STANDBY会把正在发送的帧截断,
导致先发出的应答丢失(传感器收不到注册应答),故先等待上一帧发送完成*/
while(LoRaPara.State == SX1276_TX && TxDoneWaitCnt < 2000) {
Ddl_Delay1ms(1);
TxDoneWaitCnt++;
}
LoRaPara.State = SX1276_BUSY; LoRaPara.State = SX1276_BUSY;
if (ucLen > LORA_BUFF_SIZE){ if (ucLen > LORA_BUFF_SIZE){
ucLen = LORA_BUFF_SIZE; ucLen = LORA_BUFF_SIZE;
@@ -667,3 +675,4 @@ bool LoraSetFreqCent(uint32_t FreqCent)
+1 -1
View File
@@ -1,4 +1,4 @@
#ifndef __PUBLIC_H #ifndef __PUBLIC_H
#define __PUBLIC_H #define __PUBLIC_H
#include "bsp.h" #include "bsp.h"
+1 -1
View File
@@ -4,7 +4,7 @@
#include "Public.h" #include "Public.h"
#include "DebugCmd.h" #include "DebugCmd.h"
#define SOFTWARE_VERSION 12 #define SOFTWARE_VERSION 13
#define HARDWARE_VERSION 12 #define HARDWARE_VERSION 12
extern bool MainDispEn; extern bool MainDispEn;
+25 -16
View File
@@ -615,22 +615,30 @@ int CommUnitAnalyze(GateWayPara GateWay, uint8_t *rData, uint16_t rLen, SendData
// if(CUHeader->PayloadLen < 2) // if(CUHeader->PayloadLen < 2)
// return -1; // return -1;
if(CommUnitIdx >= 0) { //设备存在 if(CommUnitIdx >= 0) { //设备存在
MAIN_DBG_LOG("\r\nCommUnit has already been registered! Mac:%02X-%02X-%02X-%02X-%02X-%02X\r\n", MAIN_DBG_LOG("\r\nCommUnit has already been registered! Mac:%02X-%02X-%02X-%02X-%02X-%02X\r\n",
CUHeader->DevMac[0], CUHeader->DevMac[1], CUHeader->DevMac[2], CUHeader->DevMac[3], CUHeader->DevMac[4], CUHeader->DevMac[5]); CUHeader->DevMac[0], CUHeader->DevMac[1], CUHeader->DevMac[2], CUHeader->DevMac[3], CUHeader->DevMac[4], CUHeader->DevMac[5]);
uint8_t ret = 1; uint8_t ret = 1;
GateWay->ConfigPara.CommUnitArray[CommUnitIdx].CommErrCnt = 0; CommUnitPara_t *pCU = &GateWay->ConfigPara.CommUnitArray[CommUnitIdx];
GateWay->ConfigPara.CommUnitArray[CommUnitIdx].ConfigFlag = true; bool ParaChanged = (pCU->CommErrCnt != 0 || pCU->ConfigFlag != true || pCU->CailFlag != false ||
GateWay->ConfigPara.CommUnitArray[CommUnitIdx].CailFlag = false; pCU->TimeSyncFlag != false || pCU->ContLaser != false || pCU->LaserOnOff != false ||
GateWay->ConfigPara.CommUnitArray[CommUnitIdx].TimeSyncFlag = false; pCU->FPOTimeFlag != false || pCU->FPOTimeConfirmed != true);
GateWay->ConfigPara.CommUnitArray[CommUnitIdx].ContLaser = false; pCU->CommErrCnt = 0;
GateWay->ConfigPara.CommUnitArray[CommUnitIdx].LaserOnOff = false; pCU->ConfigFlag = true;
GateWay->ConfigPara.CommUnitArray[CommUnitIdx].FPOTimeFlag = false; pCU->CailFlag = false;
GateWay->ConfigPara.CommUnitArray[CommUnitIdx].FPOTimeConfirmed = true; pCU->TimeSyncFlag = false;
WritePara((uint8_t *)&GateWay->ConfigPara, sizeof(GWConfigPara_t)); pCU->ContLaser = false;
CommUnitCmdSend(GateWay, CUHeader->DevMac, COMM_UNIT_CMD_REG, &ret, 1, Response); pCU->LaserOnOff = false;
return CommUnitIdx; pCU->FPOTimeFlag = false;
} pCU->FPOTimeConfirmed = true;
/*先发应答再写FlashWritePara需擦除2个扇区并写入约7KB参数(耗时百毫秒级),
若先写Flash,应答延迟过大,会超出传感器注册请求后的接收窗口导致其收不到回应;
参数无变化时跳过写入,避免传感器反复重注册时频繁擦写Flash*/
CommUnitCmdSend(GateWay, CUHeader->DevMac, COMM_UNIT_CMD_REG, &ret, 1, Response);
if(ParaChanged)
WritePara((uint8_t *)&GateWay->ConfigPara, sizeof(GWConfigPara_t));
return CommUnitIdx;
} }
for(int i = 0; i < COMMUNIT_NUM_MAX; i++) { for(int i = 0; i < COMMUNIT_NUM_MAX; i++) {
if(GateWay->ConfigPara.CommUnitArray[i].RegFlag == false) { if(GateWay->ConfigPara.CommUnitArray[i].RegFlag == false) {
CommUnitIdx = i; CommUnitIdx = i;
@@ -668,11 +676,11 @@ int CommUnitAnalyze(GateWayPara GateWay, uint8_t *rData, uint16_t rLen, SendData
GateWay->ConfigPara.CommUnitArray[i].CurFPOTimeStart = LW_DEV_FPO_TIME_START_DEFAULT; GateWay->ConfigPara.CommUnitArray[i].CurFPOTimeStart = LW_DEV_FPO_TIME_START_DEFAULT;
GateWay->ConfigPara.CommUnitArray[i].CurFPOTime = LW_DEV_FPO_TIME_DEFAULT; GateWay->ConfigPara.CommUnitArray[i].CurFPOTime = LW_DEV_FPO_TIME_DEFAULT;
GateWay->ConfigPara.CommUnitArray[i].FPOTimeFlag = false; GateWay->ConfigPara.CommUnitArray[i].FPOTimeFlag = false;
GateWay->ConfigPara.CommUnitArray[i].FPOTimeConfirmed = true; GateWay->ConfigPara.CommUnitArray[i].FPOTimeConfirmed = true;
WritePara((uint8_t *)&GateWay->ConfigPara, sizeof(GWConfigPara_t));
uint8_t ret = 1; uint8_t ret = 1;
//先发应答再写Flash,避免WritePara耗时导致应答延迟过大(原因同上)
CommUnitCmdSend(GateWay, CUHeader->DevMac, COMM_UNIT_CMD_REG, &ret, 1, Response); CommUnitCmdSend(GateWay, CUHeader->DevMac, COMM_UNIT_CMD_REG, &ret, 1, Response);
WritePara((uint8_t *)&GateWay->ConfigPara, sizeof(GWConfigPara_t));
if(GateWay->MuchRegFlag) { //网关已注册,向服务发送新设备添加指令 if(GateWay->MuchRegFlag) { //网关已注册,向服务发送新设备添加指令
PayLoadLen = (GateWay->ConfigPara.CommUnitArray[i].SensorN * 6) + 2; PayLoadLen = (GateWay->ConfigPara.CommUnitArray[i].SensorN * 6) + 2;
MegData = rt_malloc(PayLoadLen + 3); MegData = rt_malloc(PayLoadLen + 3);
@@ -1440,3 +1448,4 @@ int AuchRevCallBack(GateWayPara GateWay, uint8_t *rData, uint16_t rLen)
{ {
return _NetRevCallBack(GateWay, rData, rLen, &GateWay->AuchRegFlag); return _NetRevCallBack(GateWay, rData, rLen, &GateWay->AuchRegFlag);
} }
+63 -7
View File
@@ -75,8 +75,19 @@ void GateWayInit(void)
boot_para_t bootParam; boot_para_t bootParam;
dev_boot_read_param(&bootParam); dev_boot_read_param(&bootParam);
rt_kprintf("AppFlag: 0x%08x\r\n", bootParam.AppFlag); rt_kprintf("AppFlag: 0x%08x\r\n", bootParam.AppFlag);
/*升级完成后Boot会设AppFlag=APP_START_FLAG并清UpdateFlag=0, /*升级完成后BootAppFlag=APP_BOOT_UPGRADE_FLAG(每次升级均置位,不限首次)。
检测到升级异常(UpdateFlag仍为APP_UPDATE_FLAG 或 非首次且AppFlag无效)时擦外置Flash*/ 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 if(bootParam.UpdateFlag == APP_UPDATE_FLAG
|| (bootParam.FirstRunFlag == 0 && bootParam.AppFlag != APP_START_FLAG)) { || (bootParam.FirstRunFlag == 0 && bootParam.AppFlag != APP_START_FLAG)) {
rt_kprintf("Boot upgrade detected, erasing external Flash...\r\n"); rt_kprintf("Boot upgrade detected, erasing external Flash...\r\n");
@@ -85,8 +96,21 @@ void GateWayInit(void)
dev_boot_write_param(bootParam); dev_boot_write_param(bootParam);
} }
bool NeedSavePara = false;
int ret = ReadPara((uint8_t *)&GateWay.ConfigPara, sizeof(GWConfigPara_t)); 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)); memset((uint8_t *)&GateWay.ConfigPara, 0x00, sizeof(GWConfigPara_t));
GateWay.ConfigPara.SavFlag = LOG_SAV_FLAG; GateWay.ConfigPara.SavFlag = LOG_SAV_FLAG;
/*通道/服务器等默认参数全部从Boot参数区(BootPara_t)获取, 由Boot直接配置*/ /*通道/服务器等默认参数全部从Boot参数区(BootPara_t)获取, 由Boot直接配置*/
@@ -111,9 +135,7 @@ void GateWayInit(void)
GateWay.ConfigPara.Rs485Ch2.UpgradeEnable = false; GateWay.ConfigPara.Rs485Ch2.UpgradeEnable = false;
GateWay.ConfigPara.Rs485Ch2.CommUnitEnable = false; GateWay.ConfigPara.Rs485Ch2.CommUnitEnable = false;
GateWay.ConfigPara.Rs485Ch2.Power = false; GateWay.ConfigPara.Rs485Ch2.Power = false;
GateWay.ConfigPara.Rs485Ch1.RS485Send = RS485Ch1UartSend;
GateWay.ConfigPara.Rs485Ch2.RS485Send = RS485Ch2UartSend;
GateWay.ConfigPara.Lora.OnOff = true; GateWay.ConfigPara.Lora.OnOff = true;
GateWay.ConfigPara.Lora.ucChannel = 8; GateWay.ConfigPara.Lora.ucChannel = 8;
GateWay.ConfigPara.Lora.ucPower = 20; GateWay.ConfigPara.Lora.ucPower = 20;
@@ -125,6 +147,36 @@ void GateWayInit(void)
GateWay.ConfigPara.OutageFlag = false; 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编码从Boot参数区(BootPara_t.GwMac)获取, 由Boot从固定地址0x4000同步
(协议规定: Mac[0]=VerInfo, Mac[1:3]=PrjNum, Mac[4:5]=GwNum)*/ (协议规定: 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));
} }
WritePara((uint8_t *)&GateWay.ConfigPara, sizeof(GWConfigPara_t)); /*原实现开机无条件回写参数:一方面无谓增加一次擦写磨损;另一方面若读出的
是坏数据,回写会重新计算CRC把脏数据"洗白"成永久合法,无法自愈。
仅在参数被重置或清洗过时才落盘*/
if(NeedSavePara)
WritePara((uint8_t *)&GateWay.ConfigPara, sizeof(GWConfigPara_t));
LogInit(); LogInit();
+52 -10
View File
@@ -9,6 +9,28 @@
uint8_t flashtestbuff[SPIFLASH_SIZE]; uint8_t flashtestbuff[SPIFLASH_SIZE];
#endif #endif
/*SPI Flash操作互斥保护:ReadPara/WritePara/AddLog/SavLogNum会被多个线程
(Lora/RS485/Cat1/Eth/调试/主线程)并发调用,无保护时SPI事务交错会写坏参数镜像
(传感器注册风暴与网关向服务器注册并发写Flash即触发此问题)。
RT-Thread互斥量支持同线程递归持有(AddLog内调SavLogNum不会死锁)*/
static rt_mutex_t FlashMutex = RT_NULL;
static void FlashLock(void)
{
if(FlashMutex == RT_NULL) {
rt_enter_critical();
if(FlashMutex == RT_NULL)
FlashMutex = rt_mutex_create("flsmux", RT_IPC_FLAG_PRIO);
rt_exit_critical();
}
if(FlashMutex != RT_NULL)
rt_mutex_take(FlashMutex, RT_WAITING_FOREVER);
}
static void FlashUnlock(void)
{
if(FlashMutex != RT_NULL)
rt_mutex_release(FlashMutex);
}
static uint8_t SpiFlashReadByte(void) static uint8_t SpiFlashReadByte(void)
{ {
return Spi1SendReceive(0); return Spi1SendReceive(0);
@@ -107,7 +129,7 @@ void SpiFlashWriteAnyLengthData(uint8_t* wData, uint32_t wAddr, uint16_t wLen)
uint16_t FirstPageRemainSpace = SPIFLASH_PAGESIZE - (WriteAddr % SPIFLASH_PAGESIZE); uint16_t FirstPageRemainSpace = SPIFLASH_PAGESIZE - (WriteAddr % SPIFLASH_PAGESIZE);
// //判断是否跨扇区,跨扇区需要先擦除下一扇区 // //判断是否跨扇区,跨扇区需要先擦除下一扇区
CheckDelSecter(wAddr, wLen); // CheckDelSecter(wAddr, wLen);
if(wLen < FirstPageRemainSpace) { if(wLen < FirstPageRemainSpace) {
FirstPageWriteSize = wLen; //计算首页写入长度 FirstPageWriteSize = wLen; //计算首页写入长度
@@ -260,7 +282,8 @@ void LogInit(void)
void SavLogNum(uint32_t LogNum) void SavLogNum(uint32_t LogNum)
{ {
LogNumSav_t CLogSav; LogNumSav_t CLogSav;
FlashLock();
if(LogNum == 0) { if(LogNum == 0) {
LogNumIdx = 0; LogNumIdx = 0;
SetLogNum(0); SetLogNum(0);
@@ -268,21 +291,21 @@ void SavLogNum(uint32_t LogNum)
SetFirstLogStartAddr(LOG_SAV_START_SECTOR * SPIFLASH_SECTORSIZE); SetFirstLogStartAddr(LOG_SAV_START_SECTOR * SPIFLASH_SECTORSIZE);
SetLastLogEndAddr(LOG_SAV_START_SECTOR * SPIFLASH_SECTORSIZE); SetLastLogEndAddr(LOG_SAV_START_SECTOR * SPIFLASH_SECTORSIZE);
SpiFlashEraseSector(LOG_INFO_START_SECTOR * SPIFLASH_SECTORSIZE); SpiFlashEraseSector(LOG_INFO_START_SECTOR * SPIFLASH_SECTORSIZE);
FlashUnlock();
return; return;
} }
SetLogNum(LogNum); SetLogNum(LogNum);
CLogSav.Flag = LOG_INFO_SAV_FLAG; CLogSav.Flag = LOG_INFO_SAV_FLAG;
CLogSav.LogCnt = LogNum; CLogSav.LogCnt = LogNum;
CLogSav.FirstLogStartAddr = ReadFirstLogStartAddr(); CLogSav.FirstLogStartAddr = ReadFirstLogStartAddr();
CLogSav.LastLogEndAddr = ReadLastLogEndAddr(); CLogSav.LastLogEndAddr = ReadLastLogEndAddr();
if(LogNumIdx == 256) { if(LogNumIdx == 256) {
SpiFlashEraseSector(LOG_INFO_START_SECTOR * SPIFLASH_SECTORSIZE); SpiFlashEraseSector(LOG_INFO_START_SECTOR * SPIFLASH_SECTORSIZE);
LogNumIdx = 0; LogNumIdx = 0;
} }
SpiFlashWriteData((uint8_t *)&CLogSav, LogNumIdx * sizeof(LogNumSav_t) + LOG_INFO_START_SECTOR * SPIFLASH_SECTORSIZE, sizeof(LogNumSav_t)); SpiFlashWriteData((uint8_t *)&CLogSav, LogNumIdx * sizeof(LogNumSav_t) + LOG_INFO_START_SECTOR * SPIFLASH_SECTORSIZE, sizeof(LogNumSav_t));
LogNumIdx++; LogNumIdx++;
FlashUnlock();
} }
/***************************************************************************************** /*****************************************************************************************
@@ -363,6 +386,7 @@ void AddLog(uint8_t *wData, uint32_t wLen)
// uint32_t SectorN; // uint32_t SectorN;
LogHeader LogH; LogHeader LogH;
FlashLock();
LogH = (LogHeader)LogBuffTemp; LogH = (LogHeader)LogBuffTemp;
LogNum = ReadLogNum(); LogNum = ReadLogNum();
@@ -390,6 +414,7 @@ void AddLog(uint8_t *wData, uint32_t wLen)
SpiFlashWriteAnyLengthData(LogBuffTemp, LLEndAddr, LogSize); SpiFlashWriteAnyLengthData(LogBuffTemp, LLEndAddr, LogSize);
SavLogNum(LogNum); SavLogNum(LogNum);
FlashUnlock();
//Debug_Printf("Add LOG: %d,endaddr = %d\r\n", LogNum, ReadLastLogEndAddr()); //Debug_Printf("Add LOG: %d,endaddr = %d\r\n", LogNum, ReadLastLogEndAddr());
} }
@@ -468,8 +493,10 @@ int ReadLog(LogHeader Header, uint8_t **rData, uint32_t LogIdx)
* 返 回 值: 无 * 返 回 值: 无
*****************************************************************************************/ *****************************************************************************************/
int ReadPara(uint8_t *Para, uint32_t ParaLen) int ReadPara(uint8_t *Para, uint32_t ParaLen)
{ {
SpiFlashReadAnyLengthData(Para, GATEWEY_PARA_SAV_ADDR, ParaLen); //读取片尾数据 FlashLock();
SpiFlashReadAnyLengthData(Para, GATEWEY_PARA_SAV_ADDR, ParaLen);
FlashUnlock();
uint16_t Check = CRC_Modbus(CRC16_BASE, Para, ParaLen - 2); uint16_t Check = CRC_Modbus(CRC16_BASE, Para, ParaLen - 2);
GWConfigPara CfgPara = (GWConfigPara)Para; GWConfigPara CfgPara = (GWConfigPara)Para;
if(CfgPara->crc16 != Check) if(CfgPara->crc16 != Check)
@@ -485,14 +512,29 @@ int ReadPara(uint8_t *Para, uint32_t ParaLen)
* 返 回 值: 无 * 返 回 值: 无
*****************************************************************************************/ *****************************************************************************************/
int WritePara(uint8_t *Para, uint32_t ParaLen) int WritePara(uint8_t *Para, uint32_t ParaLen)
{ {
SpiFlashEraseSector(GATEWEY_PARA_SAV_ADDR); FlashLock();
/*参数区只能占用扇区0~1(8KB),扇区2为日志信息区(LogNumArray)。
参数越界会擦除日志簿记数据,此处直接拒绝写入*/
if(GATEWEY_PARA_SAV_ADDR + ParaLen > LOG_INFO_START_SECTOR * SPIFLASH_SECTORSIZE) {
FlashUnlock();
return -1;
}
uint16_t Check = CRC_Modbus(CRC16_BASE, Para, ParaLen - 2); uint16_t Check = CRC_Modbus(CRC16_BASE, Para, ParaLen - 2);
GWConfigPara CfgPara = (GWConfigPara)Para; GWConfigPara CfgPara = (GWConfigPara)Para;
CfgPara->crc16 = Check; CfgPara->crc16 = Check;
SpiFlashWriteAnyLengthData(Para, GATEWEY_PARA_SAV_ADDR, ParaLen); //读取片尾数据 /*擦除参数区覆盖的所有扇区(当前GWConfigPara_t约7.5KB,跨扇区0和1)。
原实现只擦扇区0,跨扇区部分依赖SpiFlashWriteAnyLengthData内部的
CheckDelSecter擦除,该函数会顺带改写日志系统的LastLogEndAddr等簿记
变量并可能误擦日志信息区,现已移除该调用,扇区擦除由本函数自行完成*/
uint32_t SectorCnt = (GATEWEY_PARA_SAV_ADDR + ParaLen + SPIFLASH_SECTORSIZE - 1) / SPIFLASH_SECTORSIZE;
for(uint32_t i = 0; i < SectorCnt; i++) {
SpiFlashEraseSector((GATEWEY_PARA_SAV_SECTOR + i) * SPIFLASH_SECTORSIZE);
}
SpiFlashWriteAnyLengthData(Para, GATEWEY_PARA_SAV_ADDR, ParaLen);
FlashUnlock();
return 0; return 0;
} }
/* USER CODE END */ /* USER CODE END */