/* ********************************************************************************************************* * 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前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)); }