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:
@@ -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,4 +1,4 @@
|
|||||||
#ifndef __PUBLIC_H
|
#ifndef __PUBLIC_H
|
||||||
#define __PUBLIC_H
|
#define __PUBLIC_H
|
||||||
|
|
||||||
#include "bsp.h"
|
#include "bsp.h"
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
/*先发应答再写Flash:WritePara需擦除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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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,
|
/*升级完成后Boot置AppFlag=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,8 +135,6 @@ 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;
|
||||||
@@ -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();
|
||||||
|
|
||||||
|
|||||||
@@ -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; //计算首页写入长度
|
||||||
@@ -261,6 +283,7 @@ 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());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -469,7 +494,9 @@ 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)
|
||||||
@@ -486,13 +513,28 @@ 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 */
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user