839 lines
22 KiB
C
839 lines
22 KiB
C
/*
|
||
*********************************************************************************************************
|
||
* IAR Development Kits
|
||
* on the
|
||
*
|
||
* M451
|
||
*
|
||
* Filename : ext_data.c
|
||
* Version : V1.00
|
||
* Programmer(s) : Qian Xianghong
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* INCLUDE FILES
|
||
*********************************************************************************************************
|
||
*/
|
||
#include "includes.h"
|
||
|
||
// 存储和上传到服务报文的循环缓冲(FRAM和SFlash存储)
|
||
loopbuff_t RF_DataM, RF_TranM;
|
||
// 上传数据的锁
|
||
SemaphoreHandle_t RF_TranLock = NULL; // 二值信号量句柄
|
||
|
||
ext_gps_t Ext_GPS;
|
||
|
||
ext_data_t Ext_Data_Rec, Ext_Data_Rec1;
|
||
|
||
ext_count_t bottleCnt, boxCnt;
|
||
ext_bottle_idx_t bottlePSN[FRAM_BOTTLE_COUNT];
|
||
ext_box_idx_t boxTGGU[FRAM_BOX_COUNT];
|
||
ext_box_idx_t boxPSN[FRAM_BOX_COUNT];
|
||
|
||
// 铁电和SFlash一致性记录
|
||
fram_sflash_valid_t FRAM_SFlash_valid = {0};
|
||
fram_sflash_valid_t SFlash_FRAM_valid = {0};
|
||
|
||
// 关联铁电和SFlash的一致性(用相对时间和绝对时间作为标记)
|
||
void CheckFramSFlashValid(uint32_t relative_time)
|
||
{
|
||
if(FRAM_SFlash_valid.offset_seconds == 0)
|
||
{
|
||
// 写入铁电
|
||
FRAM_SFlash_valid.relative_time = relative_time;
|
||
FRAM_SFlash_valid.offset_seconds = RTC_offsetSeconds;
|
||
FRAM_SaveInfo(FRAM_SFLASH_VALID_INFO_BASE, (uint8_t *) &FRAM_SFlash_valid, sizeof(fram_sflash_valid_t));
|
||
// 写入SFlash
|
||
SFlash_FRAM_valid.relative_time = relative_time;
|
||
SFlash_FRAM_valid.offset_seconds = RTC_offsetSeconds;
|
||
SFlash_SaveInfo(SFLASH_FRAM_VALID_INFO_BASE, (uint8_t *) &SFlash_FRAM_valid, sizeof(fram_sflash_valid_t));
|
||
}
|
||
}
|
||
|
||
// TODO: 将精简数据转换成上传数据
|
||
void cacl_gprs_tran_data(ext_data_t *pGprs, data_sample_t *sample)
|
||
{
|
||
rf_app_data_t *pData = (rf_app_data_t *) pGprs->payload;
|
||
|
||
// 先计算其它数据
|
||
memset(sample, 0, sizeof(data_sample_t));
|
||
|
||
// 计算理论值
|
||
Calculate_Theoretical_Params(pData->Sensor.bottle_type, pData->d, pData->L, pData->chargePct, pData->density * 0.001);
|
||
sample->volumeTotal = Theoretical_Param.v - Theoretical_Param.v0;
|
||
if(pData->Sensor.staDiff == RF_SENSOR_STATUS_NORMAL)
|
||
{
|
||
if(pData->Sensor.measure_type == 1) // 称重
|
||
{
|
||
// 容积百分比
|
||
sample->volumePct = pData->diff;
|
||
// 体积
|
||
sample->volume = sample->volumeTotal * (sample->volumePct * 0.0001);
|
||
// 质量
|
||
sample->weight = Vol2Quantity(sample->volume, pData->density * 0.001);
|
||
}
|
||
else
|
||
{
|
||
if(pData->Sensor.measure_type == 0) // 差压
|
||
{
|
||
sample->diff = pData->diff * 0.01;
|
||
// 液位
|
||
sample->height = Diff2Level(sample->diff, pData->Sensor.bottle_type, pData->d, pData->L); // 单位mm
|
||
}
|
||
else // 电容
|
||
{
|
||
sample->height = pData->diff;
|
||
}
|
||
|
||
// 体积
|
||
sample->volume = Level2Vol(sample->height, pData->Sensor.bottle_type, pData->d, pData->L);
|
||
// 质量
|
||
sample->weight = Vol2Quantity(sample->volume, pData->density * 0.001);
|
||
// 充装比
|
||
sample->volumePct = (float) sample->volume / sample->volumeTotal * 10000;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 将一个数据加入队列
|
||
// RF_DataM和RF_TranM用一个存储区,写指针始终相同,读指针可能不同
|
||
void Data_PutToQueue(ext_data_t *pGprs)
|
||
{
|
||
int32_t nextPtr;
|
||
uint32_t second1, second2;
|
||
rf_app_data_t *pData = (rf_app_data_t *) pGprs->payload;
|
||
int16_t idx;
|
||
ext_data_t tran;
|
||
static data_sample_t sample;
|
||
S_RTC_TIME_DATA_T sRTC;
|
||
char tggu[16], mmWC[8], kg[8], pct[8], press[8], tempr[8];
|
||
ext_bottle_t bottleRec;
|
||
|
||
// 如果中继器有定位,且采集时间和当前时间相差在30分钟之内,用中继器的定位取代设备端的定位
|
||
second1 = Calc_SecondsFromYear(INITIAL_YEAR, dcBuff.dtuData.sysTime.year + 2000, dcBuff.dtuData.sysTime.month,
|
||
dcBuff.dtuData.sysTime.day, dcBuff.dtuData.sysTime.hour, dcBuff.dtuData.sysTime.minute, dcBuff.dtuData.sysTime.second);
|
||
second2 = pGprs->recvTime - pData->relative_time;
|
||
if(dcBuff.dtuData.posState && (second1 + 1800 < second2 || second2 + 1800 < second1))
|
||
{
|
||
pData->longitude = dcBuff.dtuData.longitude;
|
||
pData->latitude = dcBuff.dtuData.latitude;
|
||
}
|
||
|
||
// TODO: 将精简数据转换成上传数据
|
||
cacl_gprs_tran_data(pGprs, &sample);
|
||
pGprs->volumePct = sample.volumePct;
|
||
pGprs->volume = sample.volume;
|
||
// 判断是否满足报警条件
|
||
pGprs->warn = 0;
|
||
if(dcBuff.configBottle.fullPct > 0 && pData->Sensor.staDiff == RF_SENSOR_STATUS_NORMAL && sample.volumePct >= dcBuff.configBottle.fullPct)
|
||
pGprs->warn = 1;
|
||
else if(dcBuff.configBottle.emptyPct > 0 && pData->Sensor.staDiff == RF_SENSOR_STATUS_NORMAL && sample.volumePct <= dcBuff.configBottle.emptyPct)
|
||
pGprs->warn = 1;
|
||
else if(dcBuff.configBottle.warnPressH > 0 && pData->Sensor.staPress == RF_SENSOR_STATUS_NORMAL && pData->press >= dcBuff.configBottle.warnPressH)
|
||
pGprs->warn = 1;
|
||
else if(dcBuff.configBottle.warnPress > 0 && pData->Sensor.staPress == RF_SENSOR_STATUS_NORMAL && pData->press <= dcBuff.configBottle.warnPress)
|
||
pGprs->warn = 1;
|
||
else if(dcBuff.configBottle.warnTemprH > -300 && pData->Sensor.staETempr1 == RF_SENSOR_STATUS_NORMAL && pData->tempr >= dcBuff.configBottle.warnTemprH)
|
||
pGprs->warn = 1;
|
||
else if(dcBuff.configBottle.warnTempr > -300 && pData->Sensor.staETempr1 == RF_SENSOR_STATUS_NORMAL && pData->tempr <= dcBuff.configBottle.warnTempr)
|
||
pGprs->warn = 1;
|
||
else if(dcBuff.configBottle.warnVolt > 0 && pData->voltage <= dcBuff.configBottle.warnVolt)
|
||
pGprs->warn = 1;
|
||
|
||
// 判断是否故障
|
||
pGprs->fault = 0;
|
||
if(pData->Sensor.staDiff == RF_SENSOR_STATUS_UNDERFLOW || pData->Sensor.staDiff == RF_SENSOR_STATUS_OVERFLOW)
|
||
pGprs->fault = 1;
|
||
else if(pData->Sensor.staPress == RF_SENSOR_STATUS_UNDERFLOW || pData->Sensor.staPress == RF_SENSOR_STATUS_OVERFLOW)
|
||
pGprs->fault = 1;
|
||
else if(pData->Sensor.staETempr1 == RF_SENSOR_STATUS_UNDERFLOW || pData->Sensor.staETempr1 == RF_SENSOR_STATUS_OVERFLOW)
|
||
pGprs->fault = 1;
|
||
|
||
// 移动写指针
|
||
nextPtr = LoopBuff_GetNextPtr(&RF_DataM, RF_DataM.info.wtPtr);
|
||
|
||
// 如果发送队列已满
|
||
if(nextPtr == RF_TranM.info.rdPtr)
|
||
{
|
||
// 移动读指针(丢弃第一条数据)
|
||
RF_TranM.info.rdPtr = LoopBuff_GetNextPtr(&RF_TranM, RF_TranM.info.rdPtr);
|
||
}
|
||
// 如果数据队列已满
|
||
if(nextPtr == RF_DataM.info.rdPtr)
|
||
{
|
||
// 读出第一条记录
|
||
SFlash_LoadInfo(LoopBuff_GetDataPos(&RF_DataM, RF_DataM.info.rdPtr), (uint8_t *) &tran, sizeof(ext_data_t));
|
||
|
||
// 修改储罐档案
|
||
idx = Ext_Lookup_Bottle_PSN(tran.oriPSN, bottleCnt.count);
|
||
if(idx >= 0)
|
||
{
|
||
FRAM_BufferRead(FRAM_BOTTLE_DATA_BASE + sizeof(ext_bottle_t) * bottlePSN[idx].recNo, (uint8_t *) &bottleRec, sizeof(ext_bottle_t));
|
||
if(bottleRec.lastData == RF_DataM.info.rdPtr)
|
||
{
|
||
bottleRec.lastData = -1;
|
||
FRAM_BufferWrite(FRAM_BOTTLE_DATA_BASE + sizeof(ext_bottle_t) * bottlePSN[idx].recNo, (uint8_t *) &bottleRec, sizeof(ext_bottle_t));
|
||
}
|
||
}
|
||
|
||
// 移动读指针(丢弃第一条数据)
|
||
RF_DataM.info.rdPtr = LoopBuff_GetNextPtr(&RF_DataM, RF_DataM.info.rdPtr);
|
||
}
|
||
|
||
// 建立单向链表,以提高查询速度(双向链表需要反复擦写SFlash)
|
||
// 支持从后往前(按时间倒序)查,结束条件为以下3种之一:
|
||
// 1. 无前一条记录;2. 前一条记录PSN不符;3. 前一条记录的时间戳比当前记录大
|
||
pGprs->prevData = -1;
|
||
|
||
// 查找储罐档案
|
||
idx = Ext_Lookup_Bottle_PSN(pGprs->oriPSN, bottleCnt.count);
|
||
if(idx >= 0)
|
||
{
|
||
FRAM_BufferRead(FRAM_BOTTLE_DATA_BASE + sizeof(ext_bottle_t) * bottlePSN[idx].recNo, (uint8_t *) &bottleRec, sizeof(ext_bottle_t));
|
||
pGprs->prevData = bottleRec.lastData;
|
||
|
||
// 修改储罐档案
|
||
bottleRec.lastData = RF_DataM.info.wtPtr;
|
||
bottleRec.warn = pGprs->warn;
|
||
bottleRec.fault = pGprs->fault;
|
||
bottleRec.recvTime = pGprs->recvTime;
|
||
|
||
FRAM_BufferWrite(FRAM_BOTTLE_DATA_BASE + sizeof(ext_bottle_t) * bottlePSN[idx].recNo, (uint8_t *) &bottleRec, sizeof(ext_bottle_t));
|
||
}
|
||
|
||
// 将新数据加到最后
|
||
SFlash_SaveInfo(LoopBuff_GetDataPos(&RF_DataM, RF_DataM.info.wtPtr), (uint8_t *) pGprs, sizeof(ext_data_t));
|
||
|
||
// 保存到铁电
|
||
RF_DataM.info.wtPtr = nextPtr;
|
||
FRAM_SaveInfo(RF_DataM.info_base, (uint8_t *) &RF_DataM.info, sizeof(RF_DataM.info));
|
||
RF_TranM.info.wtPtr = nextPtr;
|
||
FRAM_SaveInfo(RF_TranM.info_base, (uint8_t *) &RF_TranM.info, sizeof(RF_TranM.info));
|
||
|
||
// 加入首页显示
|
||
Wakeup_CalcUTCTime(pGprs->recvTime - pData->relative_time, &sRTC);
|
||
idx = Ext_Lookup_Box_PSN(pGprs->oriPSN, boxCnt.count);
|
||
if(idx >= 0)
|
||
strcpy(tggu, boxPSN[idx].TGGU);
|
||
else
|
||
strcpy(tggu, "");
|
||
if(pData->Sensor.staDiff == RF_SENSOR_STATUS_NOCONNECT)
|
||
{
|
||
strcpy(mmWC, "---");
|
||
strcpy(kg, "---");
|
||
strcpy(pct, "---");
|
||
}
|
||
else if(pData->Sensor.staDiff == RF_SENSOR_STATUS_UNDERFLOW)
|
||
{
|
||
strcpy(mmWC, "-EE");
|
||
strcpy(kg, "-EE");
|
||
strcpy(pct, "-EE");
|
||
}
|
||
else if(pData->Sensor.staDiff == RF_SENSOR_STATUS_OVERFLOW)
|
||
{
|
||
strcpy(mmWC, "+EE");
|
||
strcpy(kg, "+EE");
|
||
strcpy(pct, "+EE");
|
||
}
|
||
else
|
||
{
|
||
sprintf(mmWC, "%d", (uint32_t) KPa2mmH2O(pData->diff * 0.01));
|
||
sprintf(kg, "%d", Vol2Quantity(pGprs->volume, pData->density * 0.001));
|
||
sprintf(pct, "%.1f", pGprs->volumePct * 0.01);
|
||
}
|
||
if(pData->Sensor.staPress == RF_SENSOR_STATUS_NOCONNECT)
|
||
strcpy(press, "---");
|
||
else if(pData->Sensor.staPress == RF_SENSOR_STATUS_UNDERFLOW)
|
||
strcpy(press, "-EE");
|
||
else if(pData->Sensor.staPress == RF_SENSOR_STATUS_OVERFLOW)
|
||
strcpy(press, "+EE");
|
||
else
|
||
sprintf(press, "%.2f", pData->press * 0.001);
|
||
if(pData->Sensor.staETempr1 == RF_SENSOR_STATUS_NOCONNECT)
|
||
strcpy(tempr, "---");
|
||
else if(pData->Sensor.staETempr1 == RF_SENSOR_STATUS_UNDERFLOW)
|
||
strcpy(tempr, "-EE");
|
||
else if(pData->Sensor.staETempr1 == RF_SENSOR_STATUS_OVERFLOW)
|
||
strcpy(tempr, "+EE");
|
||
else
|
||
sprintf(tempr, "%d", pData->tempr);
|
||
sprintf(gridAll.rowStr[0], " %02d-%02d %02d:%02d %11s %7s %7s %5s %7s %6s %2s %2s 20%02d%02d%02d%02d%03d",
|
||
sRTC.u32Month, sRTC.u32Day, sRTC.u32Hour, sRTC.u32Minute,
|
||
tggu, mmWC, kg, pct, press, tempr, (pGprs->warn ? "W" : ""), (pGprs->fault ? "F" : ""),
|
||
pGprs->oriPSN[0], pGprs->oriPSN[1], pGprs->oriPSN[2], pGprs->oriPSN[3], (pGprs->oriPSN[4] << 8) | pGprs->oriPSN[5]);
|
||
Form_ScrollGrid(&gridAll);
|
||
|
||
// 加入报警页显示
|
||
if(pGprs->warn || pGprs->fault)
|
||
{
|
||
strcpy(gridWarn.rowStr[0], gridAll.rowStr[0]);
|
||
Form_ScrollGrid(&gridWarn);
|
||
}
|
||
|
||
// 声光报警
|
||
if(pGprs->warn && !IS_ALARM_ON())
|
||
KZ_ALARM_ON();
|
||
|
||
// 加入485发送缓冲
|
||
LoopBuff_PutItem(&Modbus_SendM, (uint8_t *) pGprs);
|
||
// 发消息给任务
|
||
xSemaphoreGive(Modbus_SendQ);
|
||
}
|
||
|
||
void Data_Open()
|
||
{
|
||
int16_t i, j, len;
|
||
uint8_t clearData = 0;
|
||
ext_bottle_t bottleRec;
|
||
ext_box_t boxRec;
|
||
|
||
// 创建消息队列
|
||
|
||
// 以下2个缓冲区共用存储区(RF_DataM为历史记录不删除,RF_TranM为上传成功以后删除)
|
||
LoopBuff_Create(&RF_DataM, sizeof(ext_data_t), SFLASH_DATA_COUNT, FRAM_DATA_INFO_BASE, SFLASH_DATA_BASE);
|
||
LoopBuff_Create(&RF_TranM, sizeof(ext_data_t), SFLASH_DATA_COUNT, FRAM_TRAN_INFO_BASE, SFLASH_DATA_BASE);
|
||
|
||
// 创建互斥锁
|
||
RF_TranLock = xSemaphoreCreateBinary();
|
||
xSemaphoreGive(RF_TranLock);
|
||
|
||
#if 0
|
||
// 测试代码,手动建立几个储罐档案
|
||
bottleCnt.count = 500;
|
||
for(i = 0; i < bottleCnt.count; i++)
|
||
{
|
||
memset(&bottleRec, 0, sizeof(ext_bottle_t));
|
||
bottleRec.PSN[0] = 10;
|
||
bottleRec.PSN[3] = (10 + i * 10) / 1000;
|
||
bottleRec.PSN[4] = ((10 + i * 10) % 1000) >> 8;
|
||
bottleRec.PSN[5] = ((10 + i * 10) % 1000) & 0xFF;
|
||
bottleRec.lastData = -1;
|
||
FRAM_BufferWrite(FRAM_BOTTLE_DATA_BASE + sizeof(ext_bottle_t) * i, (uint8_t *) &bottleRec, sizeof(ext_bottle_t));
|
||
}
|
||
FRAM_SaveInfo(FRAM_BOTTLE_INFO_BASE, (uint8_t *) &bottleCnt, sizeof(ext_count_t));
|
||
#endif
|
||
|
||
#if 0
|
||
// 测试代码,清除储罐档案
|
||
bottleCnt.count = 0;
|
||
//FRAM_SaveInfo(FRAM_BOTTLE_INFO_BASE, (uint8_t *) &bottleCnt, sizeof(ext_count_t));
|
||
FRAM_SaveInfo(0, 0, FRAM_SIZE);
|
||
|
||
#endif
|
||
|
||
#if 1
|
||
// 测试代码,手动建立几个储罐扩展档案
|
||
boxCnt.count = 500;
|
||
for(i = 0; i < boxCnt.count; i++)
|
||
{
|
||
memset(&boxRec, 0, sizeof(ext_box_t));
|
||
boxRec.PSN[0] = 26;
|
||
boxRec.PSN[3] = (0 + i * 1) / 1000;
|
||
boxRec.PSN[4] = ((0 + i * 1) % 1000) >> 8;
|
||
boxRec.PSN[5] = ((0 + i * 1) % 1000) & 0xFF;
|
||
strcpy(boxRec.TGGU, "TGGU2000000");
|
||
boxRec.TGGU[7] = '0' + (0 + i) / 100;
|
||
boxRec.TGGU[8] = '0' + (0 + i) % 100 / 10;
|
||
boxRec.TGGU[9] = '0' + (0 + i) % 10;
|
||
FRAM_BufferWrite(FRAM_BOX_DATA_BASE + sizeof(ext_box_t) * i, (uint8_t *) &boxRec, sizeof(ext_box_t));
|
||
}
|
||
FRAM_SaveInfo(FRAM_BOX_INFO_BASE, (uint8_t *) &boxCnt, sizeof(ext_count_t));
|
||
#endif
|
||
|
||
// 从铁电读取储罐档案,建立按PSN的索引
|
||
FRAM_LoadInfo(FRAM_BOTTLE_INFO_BASE, (uint8_t *) &bottleCnt, sizeof(ext_count_t));
|
||
for(i = 0; i < bottleCnt.count; i++)
|
||
{
|
||
FRAM_BufferRead(FRAM_BOTTLE_DATA_BASE + sizeof(ext_bottle_t) * i, (uint8_t *) &bottleRec, sizeof(ext_bottle_t));
|
||
memmove(bottlePSN[i].PSN, bottleRec.PSN, 6);
|
||
bottlePSN[i].recNo = i;
|
||
}
|
||
Ext_Sort_Bottle_PSN(bottlePSN, 0, bottleCnt.count - 1);
|
||
|
||
// 从铁电读取储罐扩展档案,建立按TGGU的索引
|
||
FRAM_LoadInfo(FRAM_BOX_INFO_BASE, (uint8_t *) &boxCnt, sizeof(ext_count_t));
|
||
for(i = 0; i < boxCnt.count; i++)
|
||
{
|
||
FRAM_BufferRead(FRAM_BOX_DATA_BASE + sizeof(ext_box_t) * i, (uint8_t *) &boxRec, sizeof(ext_box_t));
|
||
// 转换成大写
|
||
len = strlen(boxRec.TGGU);
|
||
for(j = 0; j < len; j++)
|
||
{
|
||
if(boxRec.TGGU[j] >= 'a' && boxRec.TGGU[j] <= 'z')
|
||
boxRec.TGGU[j] -= 32;
|
||
}
|
||
strcpy(boxTGGU[i].TGGU, boxRec.TGGU);
|
||
memmove(boxTGGU[i].PSN, boxRec.PSN, 6);
|
||
boxTGGU[i].recNo = i;
|
||
strcpy(boxPSN[i].TGGU, boxRec.TGGU);
|
||
memmove(boxPSN[i].PSN, boxRec.PSN, 6);
|
||
boxPSN[i].recNo = i;
|
||
}
|
||
Ext_Sort_Box_TGGU(boxTGGU, 0, boxCnt.count - 1);
|
||
Ext_Sort_Box_PSN(boxPSN, 0, boxCnt.count - 1);
|
||
|
||
// 从FRAM读取记录信息,并检查是否合法
|
||
FRAM_LoadInfo(RF_DataM.info_base, (uint8_t *) &RF_DataM.info, sizeof(RF_DataM.info));
|
||
FRAM_LoadInfo(RF_TranM.info_base, (uint8_t *) &RF_TranM.info, sizeof(RF_TranM.info));
|
||
if(RF_DataM.info.rdPtr > RF_DataM.maxItemCount || RF_TranM.info.rdPtr > RF_TranM.maxItemCount
|
||
|| RF_DataM.info.wtPtr > RF_DataM.maxItemCount || RF_DataM.maxItemCount != RF_TranM.maxItemCount
|
||
|| RF_DataM.data_base != RF_TranM.data_base || RF_DataM.itemSize != RF_TranM.itemSize
|
||
|| RF_DataM.info.wtPtr != RF_TranM.info.wtPtr)
|
||
{
|
||
clearData = 1;
|
||
}
|
||
|
||
// 从FRAM和SFlash分别读取一致性记录,并比较是否一致
|
||
if(!FRAM_LoadInfo(FRAM_SFLASH_VALID_INFO_BASE, (uint8_t *) &FRAM_SFlash_valid, sizeof(fram_sflash_valid_t))
|
||
|| !SFlash_LoadInfo(SFLASH_FRAM_VALID_INFO_BASE, (uint8_t *) &SFlash_FRAM_valid, sizeof(fram_sflash_valid_t))
|
||
|| FRAM_SFlash_valid.relative_time != SFlash_FRAM_valid.relative_time
|
||
|| FRAM_SFlash_valid.offset_seconds != SFlash_FRAM_valid.offset_seconds)
|
||
{
|
||
// 如不一致,铁电里面的记录无效
|
||
clearData = 1;
|
||
// 清除一致性记录,待获取到UTC时间时重新设置
|
||
memset(&FRAM_SFlash_valid, 0, sizeof(fram_sflash_valid_t));
|
||
memset(&SFlash_FRAM_valid, 0, sizeof(fram_sflash_valid_t));
|
||
}
|
||
|
||
// 清除历史数据
|
||
if(clearData)
|
||
{
|
||
memset(&RF_TranM.info, 0, sizeof(RF_TranM.info));
|
||
FRAM_SaveInfo(RF_TranM.info_base, (uint8_t *) &RF_TranM.info, sizeof(RF_TranM.info));
|
||
memset(&RF_DataM.info, 0, sizeof(RF_DataM.info));
|
||
FRAM_SaveInfo(RF_DataM.info_base, (uint8_t *) &RF_DataM.info, sizeof(RF_DataM.info));
|
||
for(i = 0; i < bottleCnt.count; i++)
|
||
{
|
||
FRAM_BufferRead(FRAM_BOTTLE_DATA_BASE + sizeof(ext_bottle_t) * i, (uint8_t *) &bottleRec, sizeof(ext_bottle_t));
|
||
bottleRec.lastData = -1;
|
||
bottleRec.warn = 0;
|
||
bottleRec.fault = 0;
|
||
FRAM_BufferWrite(FRAM_BOTTLE_DATA_BASE + sizeof(ext_bottle_t) * i, (uint8_t *) &bottleRec, sizeof(ext_bottle_t));
|
||
}
|
||
}
|
||
}
|
||
|
||
// 根据PSN查找档案序号,没有则返回-1
|
||
int16_t Ext_Lookup_Bottle_PSN(uint8_t PSN[], int16_t cnt)
|
||
{
|
||
int16_t i0 = 0;
|
||
int16_t i1 = cnt - 1;
|
||
int16_t i;
|
||
|
||
int16_t cmp;
|
||
|
||
if(cnt <= 0)
|
||
return -1;
|
||
|
||
while(1)
|
||
{
|
||
i = (i0 + i1) / 2;
|
||
cmp = memcmp(PSN, bottlePSN[i].PSN, 6);
|
||
if(cmp == 0)
|
||
return i;
|
||
if(cmp > 0)
|
||
{
|
||
if(i == i1)
|
||
return -1;
|
||
i0 = i + 1;
|
||
}
|
||
else
|
||
{
|
||
if(i == i0)
|
||
return -1;
|
||
i1 = i - 1;
|
||
}
|
||
}
|
||
|
||
return -1;
|
||
}
|
||
|
||
// 根据箱主序号查找档案序号,没有则返回-1
|
||
int16_t Ext_Lookup_Box_TGGU(char TGGU[], int16_t cnt)
|
||
{
|
||
int16_t i0 = 0;
|
||
int16_t i1 = cnt - 1;
|
||
int16_t i;
|
||
|
||
int16_t cmp;
|
||
|
||
if(cnt <= 0)
|
||
return -1;
|
||
|
||
while(1)
|
||
{
|
||
i = (i0 + i1) / 2;
|
||
cmp = strcmp(TGGU, boxTGGU[i].TGGU);
|
||
if(cmp == 0)
|
||
return i;
|
||
if(cmp > 0)
|
||
{
|
||
if(i == i1)
|
||
return -1;
|
||
i0 = i + 1;
|
||
}
|
||
else
|
||
{
|
||
if(i == i0)
|
||
return -1;
|
||
i1 = i - 1;
|
||
}
|
||
}
|
||
|
||
return -1;
|
||
}
|
||
|
||
// 根据PSN查找箱主序号,没有则返回-1
|
||
int16_t Ext_Lookup_Box_PSN(uint8_t PSN[], int16_t cnt)
|
||
{
|
||
int16_t i0 = 0;
|
||
int16_t i1 = cnt - 1;
|
||
int16_t i;
|
||
|
||
int16_t cmp;
|
||
|
||
if(cnt <= 0)
|
||
return -1;
|
||
|
||
while(1)
|
||
{
|
||
i = (i0 + i1) / 2;
|
||
cmp = memcmp(PSN, boxPSN[i].PSN, 6);
|
||
if(cmp == 0)
|
||
return i;
|
||
if(cmp > 0)
|
||
{
|
||
if(i == i1)
|
||
return -1;
|
||
i0 = i + 1;
|
||
}
|
||
else
|
||
{
|
||
if(i == i0)
|
||
return -1;
|
||
i1 = i - 1;
|
||
}
|
||
}
|
||
|
||
return -1;
|
||
}
|
||
|
||
// 快速排序法
|
||
int16_t partition_bottle_psn(ext_bottle_idx_t a[], int16_t lo, int16_t hi)
|
||
{
|
||
int16_t i = lo;
|
||
int16_t j = hi + 1;
|
||
ext_bottle_idx_t tmp;
|
||
|
||
while(1)
|
||
{
|
||
while(memcmp(a[++i].PSN, a[lo].PSN, 6) < 0)
|
||
{
|
||
if(i == hi)
|
||
break;
|
||
}
|
||
|
||
while(memcmp(a[--j].PSN, a[lo].PSN, 6) > 0);
|
||
|
||
if(i >= j)
|
||
break;
|
||
|
||
tmp = a[i];
|
||
a[i] = a[j];
|
||
a[j] = tmp;
|
||
}
|
||
|
||
tmp = a[lo];
|
||
a[lo] = a[j];
|
||
a[j] = tmp;
|
||
|
||
return j;
|
||
}
|
||
|
||
void Ext_Sort_Bottle_PSN(ext_bottle_idx_t a[], int16_t lo, int16_t hi)
|
||
{
|
||
#if 0
|
||
// 快速排序,递归函数在任务里需要Stack太大
|
||
int16_t j;
|
||
|
||
if(hi <= lo)
|
||
return;
|
||
|
||
j = partition_bottle_psn(a, lo, hi);
|
||
Ext_Sort_Bottle_PSN(a, lo, j - 1);
|
||
Ext_Sort_Bottle_PSN(a, j + 1, hi);
|
||
#else
|
||
// 冒泡排序
|
||
int16_t i, j, k;
|
||
ext_bottle_idx_t tmp;
|
||
|
||
for(i = 0; i < hi; i++)
|
||
{
|
||
// 找出后面最小的值
|
||
k = i;
|
||
for(j = i + 1; j <= hi; j++)
|
||
{
|
||
if(memcmp(a[j].PSN, a[k].PSN, 6) < 0)
|
||
k = j;
|
||
}
|
||
|
||
// 交换
|
||
if(k != i)
|
||
{
|
||
tmp = a[k];
|
||
a[k] = a[i];
|
||
a[i] = tmp;
|
||
}
|
||
}
|
||
#endif
|
||
}
|
||
|
||
// 快速排序法
|
||
int16_t partition_box_tggu(ext_box_idx_t a[], int16_t lo, int16_t hi)
|
||
{
|
||
int16_t i = lo;
|
||
int16_t j = hi + 1;
|
||
ext_box_idx_t tmp;
|
||
|
||
while(1)
|
||
{
|
||
while(strcmp(a[++i].TGGU, a[lo].TGGU) < 0)
|
||
{
|
||
if(i == hi)
|
||
break;
|
||
}
|
||
|
||
while(strcmp(a[--j].TGGU, a[lo].TGGU) > 0);
|
||
|
||
if(i >= j)
|
||
break;
|
||
|
||
tmp = a[i];
|
||
a[i] = a[j];
|
||
a[j] = tmp;
|
||
}
|
||
|
||
tmp = a[lo];
|
||
a[lo] = a[j];
|
||
a[j] = tmp;
|
||
|
||
return j;
|
||
}
|
||
|
||
void Ext_Sort_Box_TGGU(ext_box_idx_t a[], int16_t lo, int16_t hi)
|
||
{
|
||
#if 0
|
||
// 快速排序,递归函数在任务里需要Stack太大
|
||
int16_t j;
|
||
|
||
if(hi <= lo)
|
||
return;
|
||
|
||
j = partition_box_tggu(a, lo, hi);
|
||
Ext_Sort_Box_TGGU(a, lo, j - 1);
|
||
Ext_Sort_Box_TGGU(a, j + 1, hi);
|
||
#else
|
||
// 冒泡排序
|
||
int16_t i, j, k;
|
||
ext_box_idx_t tmp;
|
||
|
||
for(i = 0; i < hi; i++)
|
||
{
|
||
// 找出后面最小的值
|
||
k = i;
|
||
for(j = i + 1; j <= hi; j++)
|
||
{
|
||
if(strcmp(a[j].TGGU, a[k].TGGU) < 0)
|
||
k = j;
|
||
}
|
||
|
||
// 交换
|
||
if(k != i)
|
||
{
|
||
tmp = a[k];
|
||
a[k] = a[i];
|
||
a[i] = tmp;
|
||
}
|
||
}
|
||
#endif
|
||
}
|
||
|
||
// 快速排序法
|
||
int16_t partition_box_psn(ext_box_idx_t a[], int16_t lo, int16_t hi)
|
||
{
|
||
int16_t i = lo;
|
||
int16_t j = hi + 1;
|
||
ext_box_idx_t tmp;
|
||
|
||
while(1)
|
||
{
|
||
while(memcmp(a[++i].PSN, a[lo].PSN, 6) < 0)
|
||
{
|
||
if(i == hi)
|
||
break;
|
||
}
|
||
|
||
while(memcmp(a[--j].PSN, a[lo].PSN, 6) > 0);
|
||
|
||
if(i >= j)
|
||
break;
|
||
|
||
tmp = a[i];
|
||
a[i] = a[j];
|
||
a[j] = tmp;
|
||
}
|
||
|
||
tmp = a[lo];
|
||
a[lo] = a[j];
|
||
a[j] = tmp;
|
||
|
||
return j;
|
||
}
|
||
|
||
void Ext_Sort_Box_PSN(ext_box_idx_t a[], int16_t lo, int16_t hi)
|
||
{
|
||
#if 0
|
||
// 快速排序,递归函数在任务里需要Stack太大
|
||
int16_t j;
|
||
|
||
if(hi <= lo)
|
||
return;
|
||
|
||
j = partition_box_psn(a, lo, hi);
|
||
Ext_Sort_Box_PSN(a, lo, j - 1);
|
||
Ext_Sort_Box_PSN(a, j + 1, hi);
|
||
#else
|
||
// 冒泡排序
|
||
int16_t i, j, k;
|
||
ext_box_idx_t tmp;
|
||
|
||
for(i = 0; i < hi; i++)
|
||
{
|
||
// 找出后面最小的值
|
||
k = i;
|
||
for(j = i + 1; j <= hi; j++)
|
||
{
|
||
if(memcmp(a[j].PSN, a[k].PSN, 6) < 0)
|
||
k = j;
|
||
}
|
||
|
||
// 交换
|
||
if(k != i)
|
||
{
|
||
tmp = a[k];
|
||
a[k] = a[i];
|
||
a[i] = tmp;
|
||
}
|
||
}
|
||
#endif
|
||
}
|
||
|
||
// 更新从服务器下载的罐箱档案
|
||
// 数据格式为"<PSN后11位>,<罐箱号>;<PSN后11位>,<罐箱号>;....." (PSN前2位固定为"20")
|
||
// 如"21110180010,TGGU2000010;10000000020,TGGU2000020"
|
||
// 表示2个储罐:PSN: 2021110180010(TGGU2000010);PSN: 2010000000020(TGGU2000020)
|
||
void Ext_Update_Boxes(char *buff)
|
||
{
|
||
int16_t count = 0, len = strlen(buff);
|
||
char *pChr;
|
||
char record[32], psn[16];
|
||
ext_box_t boxRec;
|
||
|
||
// 先删除所有储罐档案,以免在更新过程中出现数据混乱
|
||
boxCnt.count = 0;
|
||
|
||
while(len > 0)
|
||
{
|
||
// 先用';'查找一条记录
|
||
pChr = strchr(buff, ';');
|
||
if(pChr)
|
||
{
|
||
if(pChr >= buff + sizeof(record)) // 数据有误, 终止更新
|
||
break;
|
||
strncpy(record, buff, pChr - buff);
|
||
record[pChr - buff] = 0;
|
||
buff++; // 分号占的位置
|
||
}
|
||
else // 最后一条记录
|
||
{
|
||
if(len >= sizeof(record)) // 数据有误, 终止更新
|
||
break;
|
||
strcpy(record, buff);
|
||
}
|
||
|
||
// 更新循环条件
|
||
buff += strlen(record);
|
||
len = strlen(buff);
|
||
|
||
// 初始化记录
|
||
memset(&boxRec, 0, sizeof(ext_box_t));
|
||
|
||
// 再用','查找字段
|
||
pChr = strchr(record, ',');
|
||
if(!pChr || pChr != record + 11) // 数据有误, 终止更新
|
||
break;
|
||
strncpy(psn, record, pChr - record);
|
||
psn[pChr - record] = 0;
|
||
|
||
if(strlen(pChr + 1) >= sizeof(boxRec.TGGU)) // 数据有误, 终止更新
|
||
break;
|
||
strcpy(boxRec.TGGU, pChr + 1);
|
||
|
||
// 检查数据是否合法
|
||
pChr = psn;
|
||
while(*pChr)
|
||
{
|
||
if(!isdigit(*pChr)) // 数据有误, 终止更新
|
||
{
|
||
len = 0;
|
||
break;
|
||
}
|
||
pChr++;
|
||
}
|
||
|
||
// 转换成大写
|
||
pChr = boxRec.TGGU;
|
||
while(*pChr)
|
||
{
|
||
if(*pChr >= 'a' && *pChr <= 'z')
|
||
*pChr -= 32;
|
||
pChr++;
|
||
}
|
||
|
||
// 添加记录
|
||
boxRec.PSN[5] = atoi(psn + 8) & 0xFF;
|
||
boxRec.PSN[4] = atoi(psn + 8) >> 8;
|
||
psn[8] = 0;
|
||
boxRec.PSN[3] = atoi(psn + 6);
|
||
psn[6] = 0;
|
||
boxRec.PSN[2] = atoi(psn + 4);
|
||
psn[4] = 0;
|
||
boxRec.PSN[1] = atoi(psn + 2);
|
||
psn[2] = 0;
|
||
boxRec.PSN[0] = atoi(psn);
|
||
FRAM_BufferWrite(FRAM_BOX_DATA_BASE + sizeof(ext_box_t) * count, (uint8_t *) &boxRec, sizeof(ext_box_t));
|
||
|
||
// 更新索引信息
|
||
strcpy(boxTGGU[count].TGGU, boxRec.TGGU);
|
||
memmove(boxTGGU[count].PSN, boxRec.PSN, 6);
|
||
boxTGGU[count].recNo = count;
|
||
strcpy(boxPSN[count].TGGU, boxRec.TGGU);
|
||
memmove(boxPSN[count].PSN, boxRec.PSN, 6);
|
||
boxPSN[count].recNo = count;
|
||
|
||
// 总数加1
|
||
count++;
|
||
}
|
||
|
||
// 重建索引
|
||
Ext_Sort_Box_TGGU(boxTGGU, 0, count - 1);
|
||
Ext_Sort_Box_PSN(boxPSN, 0, count - 1);
|
||
|
||
// 更新储罐总数
|
||
boxCnt.count = count;
|
||
FRAM_SaveInfo(FRAM_BOX_INFO_BASE, (uint8_t *) &boxCnt, sizeof(ext_count_t));
|
||
}
|