ShipCentralControl/Anjiehui7_DTU/User/ext_data.c

839 lines
22 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
*********************************************************************************************************
* 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: 2021110180010TGGU2000010PSN: 2010000000020TGGU2000020
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));
}