param.c 54 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624
  1. #include <string.h>
  2. #include "eeprom.h"
  3. #include "prj_com.h"
  4. #include "bill.h"
  5. #include "tdc_tof.h"
  6. #include "param.h"
  7. #include "app_nb.h"
  8. #include "alarm.h"
  9. Param_t Paramx;
  10. uint8_t rewrite_para_flag = 0;
  11. // DIAMETER_AND_TEMP_COMPENSATION_DEF Temp_compensation;//其中的diameter保存的校验值
  12. const char SOFT_VER[5] = {
  13. 'V', VER_TYPE, VER_OPERATOR, VER_MODULE, VER_FIRMWARE};
  14. // EEPROM_MAX_WRITE_SIZE 125
  15. // EEPROM_PAGE_SIZE 256
  16. /****************************************************************/
  17. ////由于_read_eeprom write_eeprom是针对存bill记录的,最后一个字节
  18. /// 自动校验,写参数不能用,这里需另外增加/////////
  19. /*********************批量写入数据********************************/
  20. // 参数1:dat 指向要写入的数据指针
  21. // 参数2:addr写入到M24M01存储器的地址
  22. // 参数3:len写入数据的长度(字节单位)
  23. // 返回:1:成功
  24. ////////////////////////////////////////////////////////////////
  25. uint8_t eeprom_MassWrite(uint8_t *dat, uint32_t addr, uint16_t len) //
  26. {
  27. if (addr > EEPROM_MAX_SIZE - 1 || addr + len > EEPROM_MAX_SIZE)
  28. return 1;
  29. // 已经跨页
  30. // uint8_t num=(uint8_t)(EEPROM_PAGE_SIZE/EEPROM_MAX_WRITE_SIZE+1);//每页需写入的次数
  31. // LOG("len= %d",len);
  32. uint32_t add_end = addr + len; // 地址末尾
  33. uint16_t w_size; // 写入数据大小
  34. uint8_t ret = 0;
  35. while (addr < add_end)
  36. {
  37. if (addr / EEPROM_PAGE_SIZE == (addr + EEPROM_MAX_WRITE_SIZE - 1) / EEPROM_PAGE_SIZE)
  38. { // 还在本页内
  39. w_size = EEPROM_MAX_WRITE_SIZE; // 取写入长度为最大长度
  40. }
  41. else
  42. { // 最大写入长度已经超过本页
  43. w_size = EEPROM_PAGE_SIZE - (addr % EEPROM_PAGE_SIZE); // 取写入长度刚好到页边界
  44. }
  45. if (addr + w_size > add_end)
  46. { // 写入长度已超出实际写入边界
  47. w_size = add_end - addr; // 取实际写入长度
  48. }
  49. ret |= write_eeprom_para(addr, dat, w_size); // 这里要改,write_eeprom是专门为写记录准备的,最后一个字节是校验位
  50. addr += w_size; // 地址增加
  51. dat += w_size; // 写数据指针增加
  52. // LOG("addr= %d,size= %d\r\n",addr,w_size);
  53. }
  54. //}
  55. return ret;
  56. }
  57. /*******************批量读取数据********************************/
  58. // 参数1 dat:读取数据保存指针
  59. // 参数2 addr 读取数据eeprom起始地址
  60. // 参数3 len:读取长度
  61. // 返回:1:成功
  62. /***************************************************************/
  63. uint8_t eeprom_MassRead(uint8_t *dat, uint32_t addr, uint16_t len)
  64. {
  65. memset(dat, 0, len);
  66. uint16_t i;
  67. uint8_t ret = 0;
  68. if (addr > EEPROM_MAX_SIZE - 1 || addr + len > EEPROM_MAX_SIZE)
  69. { // 写入空间超过了最大地址范围
  70. return 1;
  71. }
  72. if (len > EEPROM_MAX_READ_SIZE)
  73. { // 超过最大写读取长度
  74. for (i = 0; i < len / EEPROM_MAX_READ_SIZE; i++)
  75. { // 每次读取最大长度
  76. ret |= read_eeprom_para(addr + i * EEPROM_MAX_READ_SIZE, dat + i * EEPROM_MAX_READ_SIZE, EEPROM_MAX_READ_SIZE); // 要改
  77. }
  78. if ((len % EEPROM_MAX_READ_SIZE) != 0)
  79. { // 整长度读完后,读取可能剩余的部分
  80. ret |= read_eeprom_para(addr + i * EEPROM_MAX_READ_SIZE, dat + i * EEPROM_MAX_READ_SIZE, len % EEPROM_MAX_READ_SIZE);
  81. }
  82. }
  83. else
  84. { // 未超过最大长度
  85. ret |= read_eeprom_para(addr, dat, len);
  86. }
  87. return ret;
  88. }
  89. #define DEFAULT_PATH_SKEW 0 // 超声波通道偏差修正系数
  90. #define DEFAULT_PIPE_COE 0.1168745 // COE系数
  91. #define DEFAULT_IMEI "000000000000000" // 默认IMEI
  92. #define DEFAULT_CCID "00000000000000000000" // 默认IMEI
  93. // 01234567890123456789
  94. #define DEFAULT_MUX_CH_NO1 0
  95. #define DEFAULT_MUX_CH_NO2 1
  96. #define DEFAULT_MUX_CH_NO3 2
  97. #define DEFAULT_MUX_CH_NO4 3
  98. void LoadDefaultParam(void) // 加载默认参数值
  99. {
  100. memset((uint8_t *)&Paramx, 0, sizeof(Param_t));
  101. Paramx.path_skew[0] = DEFAULT_PATH_SKEW;
  102. Paramx.path_skew[1] = DEFAULT_PATH_SKEW;
  103. Paramx.path_skew[2] = DEFAULT_PATH_SKEW;
  104. Paramx.path_skew[3] = DEFAULT_PATH_SKEW; // 通道修正系数
  105. Paramx.pipe_coe = DEFAULT_PIPE_COE; // coe系数
  106. // strcpy(Paramx.imei, DEFAULT_IMEI); // imei号
  107. // Paramx.imei[sizeof(DEFAULT_IMEI) - 1] = 0;
  108. // strcpy(Paramx.ccid, DEFAULT_CCID); // CCID号
  109. // Paramx.ccid[sizeof(DEFAULT_CCID) - 1] = 0;
  110. Paramx.mux_ch_no[0] = DEFAULT_MUX_CH_NO1;
  111. Paramx.mux_ch_no[1] = DEFAULT_MUX_CH_NO2;
  112. Paramx.mux_ch_no[2] = DEFAULT_MUX_CH_NO3;
  113. Paramx.mux_ch_no[3] = DEFAULT_MUX_CH_NO4; // 多路开关地址
  114. // Paramx.dev_id[0] = 0x00; //a6
  115. Paramx.dev_id[0] = 0x80; // bcd //a5
  116. Paramx.dev_id[1] = 0x55; // bcd
  117. Paramx.dev_id[2] = 0x60; // bcd
  118. Paramx.dev_id[3] = 0x10; // bcd
  119. Paramx.dev_id[4] = 0x00; // bcd
  120. Paramx.dev_id[5] = 0x03; // bcd//设备地址 A0
  121. Paramx.chan_num = 1; // 超声波通道数量
  122. Paramx.diameter = 25; // 直径
  123. Paramx.pressure_sensor = 2; // without pressure sensor 是否带压力传感器,默认不带
  124. Paramx.settlement_day = 0; // 结算日,默认 每月最后一天
  125. Paramx.report_base_hour = 0;
  126. Paramx.report_base_min = 0;
  127. Paramx.report_base_sec = 0; // 上报时间点
  128. Paramx.report_interval = 24 * 60; // 上报间隔 1天
  129. Paramx.high_temp_alarm_thres = 32767; // 高温报警阈值
  130. Paramx.low_temp_alarm_thres = -32768; // 低温报警阈值
  131. Paramx.large_flow_alarm_thres = 0; // 大流量报警阈值
  132. Paramx.large_flow_cnti_moni_time = 0; // 大流量持续时间
  133. Paramx.cnti_flow_cnti_moni_time = 0; // 持续流量报警时间
  134. Paramx.leak_flow_alarm_thres = 0; // 渗漏报警阈值
  135. Paramx.leak_flow_cnti_moni_time = 0; // 渗漏报警持续时间
  136. Paramx.high_press_alarm_thres = 0; // 高压力报警阈值
  137. Paramx.low_press_alarm_thres = 0; // 低压力报警阈值
  138. Paramx.main_server_ip[0] = 221;
  139. Paramx.main_server_ip[1] = 229;
  140. Paramx.main_server_ip[2] = 214;
  141. Paramx.main_server_ip[3] = 202; // 主服务器ip地址
  142. Paramx.main_server_port = 5683; // 主服务器端口号
  143. Paramx.sub_server_ip[0] = 221; // 备用服务器ip地址
  144. Paramx.sub_server_ip[1] = 229;
  145. Paramx.sub_server_ip[2] = 214;
  146. Paramx.sub_server_ip[3] = 202;
  147. Paramx.sub_server_port = 5683; // 备用服务器端口号
  148. Paramx.dma_report_start[0] = 0;
  149. Paramx.dma_report_start[1] = 0;
  150. Paramx.dma_report_start[2] = 0; // dma上报起始时间 时分秒
  151. Paramx.dma_report_end[0] = 0;
  152. Paramx.dma_report_end[1] = 0;
  153. Paramx.dma_report_end[2] = 0; // dma上报结束时间 时分秒
  154. Paramx.dma_interval = 0; // dma上报间隔 分钟单位
  155. Paramx.total_positive_water[0] = 0;
  156. Paramx.total_positive_water[1] = 0;
  157. Paramx.total_positive_water[2] = 0;
  158. Paramx.total_positive_water[3] = 0; // 表底读数
  159. uint16_t i, j;
  160. for (i = 0; i < CHECK_TEMP_POINT; i++)
  161. { // 8个流量等级 ,3个温度等级下的修正流速,用于查找当前流速落入哪个区间
  162. Paramx.check_spdLvl_c[i].spd_lvl[0] = GetSpdLvl(Q1);
  163. Paramx.check_spdLvl_c[i].spd_lvl[1] = GetSpdLvl(1.6 * Q1);
  164. Paramx.check_spdLvl_c[i].spd_lvl[2] = GetSpdLvl(3.2 * Q1);
  165. Paramx.check_spdLvl_c[i].spd_lvl[3] = GetSpdLvl(8 * Q1);
  166. Paramx.check_spdLvl_c[i].spd_lvl[4] = GetSpdLvl(0.1 * Q3);
  167. Paramx.check_spdLvl_c[i].spd_lvl[5] = GetSpdLvl(0.2 * Q3);
  168. Paramx.check_spdLvl_c[i].spd_lvl[6] = GetSpdLvl(0.35 * (1.6 * Q1 + Q3));
  169. Paramx.check_spdLvl_c[i].spd_lvl[7] = GetSpdLvl(Q3);
  170. // init c value is 1340
  171. for (j = 0; j < CHECK_POINT_NUM; j++)
  172. { // 8个流量等级 ,3个温度等级下的基础声速,修正声速
  173. Paramx.check_spdLvl_c[i].base_c[j] = CHECK_C_VALUE;
  174. Paramx.check_spdLvl_c[i].cur_c[j] = CHECK_C_VALUE;
  175. }
  176. }
  177. // float *fp = (float *)Quad_Cell_Ary;
  178. // for (i = 0; i < Quad_Cell_NUM * 5; i++)
  179. // {
  180. // *fp = 1;
  181. // fp++;
  182. // }
  183. Paramx.q_value = CHECK_Q_VALUE; // 默认Q值,影响check脉冲计算
  184. Paramx.para_len = sizeof(Paramx) - 8;
  185. Paramx.para_crc32 = com_crc32L_next(0xFFFFFFFFu, (uint8_t *)(&Paramx) + 8, sizeof(Param_t) - 8, 0xEDB88320); // 计算crc校验值
  186. // eeprom_MassWrite((uint8_t *)&Paramx,PARAMX_START_ADDR,sizeof(Param_t));
  187. // eeprom_MassRead((uint8_t *)&Paramx,PARAMX_START_ADDR,sizeof(Param_t));
  188. Paramx.b = 63;
  189. Paramx.n = 45;
  190. Paramx.q = 32;
  191. Paramx.r = 500;
  192. rewrite_para_flag |= 0x1;
  193. }
  194. void get_para_to_tdcitf(void) // 获取参数给tdcItf
  195. {
  196. uint8_t i;
  197. for (i = 0; i < MUX_CH_NUM; i++)
  198. TdcItf.path_skew[i] = Paramx.path_skew[i];
  199. TdcItf.pipe_coe = Paramx.pipe_coe;
  200. TdcItf.ch_num = Paramx.chan_num;
  201. if (TdcItf.ch_num == 1)
  202. {
  203. TdcItf.ch_bit_map = 1;
  204. }
  205. else if (TdcItf.ch_num == 2)
  206. {
  207. TdcItf.ch_bit_map = 3;
  208. }
  209. else if (TdcItf.ch_num == 4)
  210. {
  211. TdcItf.ch_bit_map = 0x0F;
  212. }
  213. for (i = 0; i < MUX_CH_NUM; i++)
  214. TdcItf.mux_ch_no[i] = Paramx.mux_ch_no[i];
  215. }
  216. // #define DEBUG_PARAM
  217. // #ifdef DEBUG_PARAM
  218. // uint8_t p1data[sizeof(Param_t)];
  219. // uint8_t p2data[sizeof(Param_t)];
  220. // uint8_t err_pos=0;
  221. // #endif
  222. void ParamInit(void) // 上电初始化
  223. {
  224. uint8_t i;
  225. if (init_eeprom_mutx_flag == 0)
  226. {
  227. eeprom_mutx_init(); // 创建eeprom操作的互斥信号量,未进入调度前,不能用
  228. }
  229. eeprom_MassRead((unsigned char *)&Paramx, PARAMX_START_ADDR, sizeof(Param_t)); // 读取参数
  230. // memcpy(p1data,&Paramx,sizeof(Param_t));
  231. uint32_t crc = com_crc32L_next(0xFFFFFFFFu, (uint8_t *)(&Paramx) + 8, sizeof(Param_t) - 8, 0xEDB88320);
  232. if (crc != Paramx.para_crc32) // wxl2026-5-8 校验错误时记录日志
  233. rewrite_para_flag |= 4;
  234. if (Paramx.para_len != sizeof(Paramx) - 8)
  235. {
  236. LoadDefaultParam(); // 加载默认参数
  237. }
  238. // Nb_Run_t *nb_run;
  239. // GetNbRun(&nb_run);
  240. // Paramx.imei[15] = 0; // 限制长度,防止溢出
  241. // strcpy(nb_run->imei, Paramx.imei);
  242. // Paramx.ccid[31] = 0; // 限制长度,防止溢出
  243. // strcpy(nb_run->ccid, Paramx.ccid);
  244. // Paramx.ver_type = VER_TYPE; // type, 1: ultrasound flow meter;
  245. // Paramx.ver_operator = VER_OPERATOR; // operator, 1: China Telecom;
  246. // Paramx.ver_module = VER_MODULE; // module, 1: HC32_BC28;
  247. // Paramx.ver_firmware = VER_FIRMWARE; // firmware version;//设备版本信息
  248. if (Paramx.chan_num != 1)
  249. {
  250. Paramx.chan_num = 1;
  251. rewrite_para_flag |= 1;
  252. }
  253. get_para_to_tdcitf(); // 获取参数到tdcitf结构体
  254. memset((uint8_t *)&PatchInfo, 0, sizeof(PATCH_INFO_DEF));
  255. if (Check_quad_cell_data_valid(QUAD_CELL_START_ADDR) == 0)
  256. { // wxl2026-4-16
  257. get_quad_cell_data(Quad_Cell_Ary); // wxl2026-4-14
  258. }
  259. else
  260. {
  261. rewrite_para_flag |= 0x2;
  262. }
  263. alarm_init();
  264. bill_init();
  265. init_eeprom_mutx_flag = 1;
  266. }
  267. ////////////检查参数时,发现参数不合法,加载默认参数后重新eeprom/////////////////
  268. void check_rewrite_para(void)
  269. {
  270. if (StartUp != 2) // 在第二秒开始判断参数正确性
  271. return;
  272. if (rewrite_para_flag & 0x1)
  273. {
  274. // 保存主参数
  275. eeprom_MassWrite((uint8_t *)&Paramx, PARAMX_START_ADDR, sizeof(Param_t));
  276. rewrite_para_flag |= 0x4;
  277. }
  278. if (rewrite_para_flag & 0x2)
  279. {
  280. // 保存主参数
  281. set_diameter_and_quad_cell_data(0, &Quad_Cell_Ary);
  282. }
  283. // crc校验错误写日志
  284. if (rewrite_para_flag & 0x4) // wxl2026-5-8
  285. {
  286. write_alarm(LOG_PARA_CRC_ERROR, 1, 5555);
  287. // memcpy(p2data,&Paramx,sizeof(Param_t));
  288. set_crc_check_para();
  289. // int i;
  290. /// for(i=0;i<sizeof(Param_t);i++)if(p1data[i]!=p2data[i])err_pos= i;
  291. }
  292. rewrite_para_flag = 0;
  293. }
  294. uint16_t GetSpdLvl(double flow_rate)
  295. { // 获取当前流速,用于查表
  296. return (uint16_t)(flow_rate * 1000000 / 3600 / TdcItf.pipe_coe);
  297. }
  298. // modified by yuewei 20260316 only use check_spdLvl_c[0] start
  299. // check temperature interval: 0~10/10~40/40 and above
  300. /*
  301. uint16_t CheckTempRangeIndex(float temp) {//获取温度等级索引号
  302. if (temp >= 40.0) {
  303. return 2;
  304. } if (temp >= 10.0) {
  305. return 1;
  306. }
  307. return 0;
  308. }
  309. */
  310. // 获取温度等级索引号,only use 0
  311. uint16_t CheckTempRangeIndex(float temp)
  312. {
  313. return 0;
  314. }
  315. // modified by yuewei 20260316 only use check_spdLvl_c[0] end
  316. /**************************************************/
  317. // 获取流速等级索引号,用于获取校正系数
  318. /***************************************************/
  319. #if 0
  320. uint8_t CheckCValueIndex(uint16_t temp_idx, uint16_t spdLvl) {
  321. uint8_t i;
  322. uint16_t mid;
  323. CheckSpdLvlC_t *p = &Paramx.check_spdLvl_c[temp_idx];
  324. if (spdLvl <= p->spd_lvl[0]) {
  325. return 0;
  326. }
  327. for (i = 0; i < CHECK_POINT_NUM - 1; i++) {
  328. mid = (p->spd_lvl[i + 1] + p->spd_lvl[i]) / 2;
  329. if (spdLvl >= p->spd_lvl[i] && spdLvl < mid) {
  330. return i;
  331. } else if (spdLvl >= mid && spdLvl < p->spd_lvl[i + 1]) {
  332. return i + 1;
  333. }
  334. }
  335. return CHECK_POINT_NUM - 1;
  336. }
  337. #endif
  338. #if 0
  339. uint8_t CheckCValueIndex(uint16_t temp_idx, uint16_t spdLvl)
  340. {
  341. // 1. Boundary safety limit, only 3 temperature intervals, actually use index 0 only
  342. if (temp_idx >= 3)
  343. {
  344. return 0;
  345. }
  346. CheckSpdLvlC_t *p = &Paramx.check_spdLvl_c[temp_idx];
  347. uint8_t i;
  348. // 2. Less than minimum speed level -> fixed return 0
  349. if (spdLvl <= p->spd_lvl[0])
  350. {
  351. return 0;
  352. }
  353. // 3. Direct interval judgment (hysteresis canceled)
  354. for (i = 0; i < CHECK_POINT_NUM - 1; i++)
  355. {
  356. // Directly match speed level interval
  357. if (spdLvl <= p->spd_lvl[i + 1])
  358. {
  359. return i;
  360. }
  361. }
  362. // 4. Greater than maximum speed level -> return last index
  363. return CHECK_POINT_NUM - 1;
  364. }
  365. #endif
  366. uint8_t CheckCValueIndex(uint16_t temp_idx, uint16_t spdLvl)
  367. {
  368. // 1. 温度区间安全限界,仅0/1/2有效
  369. if (temp_idx >= 3)
  370. {
  371. return 0;
  372. }
  373. CheckSpdLvlC_t *p = &Paramx.check_spdLvl_c[temp_idx];
  374. uint8_t i;
  375. uint8_t best_idx = 0;
  376. uint16_t min_diff;
  377. uint16_t curr_diff;
  378. spdLvl = spdLvl - 5;//add by yuewei 20260629
  379. // 初始化最小差值为第一个点差值
  380. if (spdLvl >= p->spd_lvl[0])
  381. min_diff = spdLvl - p->spd_lvl[0];
  382. else
  383. min_diff = p->spd_lvl[0] - spdLvl;
  384. // 遍历所有速度点,寻找差值最小的下标
  385. for (i = 1; i < CHECK_POINT_NUM; i++)
  386. {
  387. if (spdLvl >= p->spd_lvl[i])
  388. curr_diff = spdLvl - p->spd_lvl[i];
  389. else
  390. curr_diff = p->spd_lvl[i] - spdLvl;
  391. // 更新最小差值与最优索引
  392. if (curr_diff < min_diff)
  393. {
  394. min_diff = curr_diff;
  395. best_idx = i;
  396. }
  397. }
  398. return best_idx;
  399. }
  400. // 获取在不同温度和流速等级下的,声速修正系数
  401. float CheckFlowCorrectFactor(float temp, uint16_t spdLvl)
  402. {
  403. uint16_t temp_idx = CheckTempRangeIndex(temp);
  404. uint8_t c_idx = CheckCValueIndex(temp_idx, spdLvl);
  405. CheckSpdLvlC_t *p = &Paramx.check_spdLvl_c[temp_idx];
  406. uint16_t curr_c = p->cur_c[c_idx];
  407. uint16_t base_c = p->base_c[c_idx];
  408. LOG("spdLvl=%d,curr_c = %d,c_idx=%d\n", spdLvl, curr_c, c_idx);
  409. return ((float)curr_c * 1.0f) / (float)base_c;
  410. }
  411. uint32_t BillTime(uint8_t year, uint8_t month) // 确定结算日的上报时间(取)
  412. {
  413. uint8_t last_day = last_day_of_month(year, month);
  414. uint8_t day;
  415. if (Paramx.settlement_day == 0)
  416. {
  417. return 0;
  418. }
  419. if (Paramx.settlement_day > 0 && Paramx.settlement_day <= last_day)
  420. {
  421. day = Paramx.settlement_day;
  422. }
  423. else
  424. {
  425. day = last_day;
  426. }
  427. return ((day << 24) | (Paramx.report_base_hour << 16) |
  428. (Paramx.report_base_min << 8) | Paramx.report_base_sec); // 上报时分秒
  429. }
  430. /////////////////获取参数结构体指针//////////////////////
  431. // 输入参数:指向结构体指针的指针
  432. // 返回参数:无
  433. //////////////////////////////////////
  434. void GetParam(Param_t **para)
  435. {
  436. *para = &Paramx;
  437. }
  438. ///////////////////////保存所有参数//////////////////
  439. // 输入参数:无
  440. // 返回参数:无
  441. //////将内存中的param参数全部写入到eeprom中//////////
  442. void SaveParam(void)
  443. {
  444. uint32_t param_len = 0;
  445. uint32_t param_crc;
  446. uint8_t *data;
  447. uint8_t i;
  448. Nb_Run_t *nb_run;
  449. GetNbRun(&nb_run);
  450. Paramx.path_skew[0] = TdcItf.path_skew[0];
  451. Paramx.path_skew[1] = TdcItf.path_skew[1];
  452. Paramx.path_skew[2] = TdcItf.path_skew[2];
  453. Paramx.path_skew[3] = TdcItf.path_skew[3];
  454. Paramx.pipe_coe = TdcItf.pipe_coe;
  455. // memcpy(Paramx.imei, nb_run->imei, 16); // imei号保存
  456. // memcpy(Paramx.ccid, nb_run->ccid, 32); // ccid号保存
  457. memcpy(Paramx.mux_ch_no, TdcItf.mux_ch_no, sizeof(TdcItf.mux_ch_no)); // 多路开关地址
  458. Paramx.para_crc32 = com_crc32L_next(0xFFFFFFFFu, (uint8_t *)(&Paramx) + 8, sizeof(Param_t) - 8, 0xEDB88320);
  459. Paramx.para_len = sizeof(Paramx) - 8;
  460. eeprom_MassWrite((uint8_t *)&Paramx, PARAMX_START_ADDR, sizeof(Paramx));
  461. }
  462. /////////////////设置版本号 保存到eeprom中///////////////////////
  463. // 参数:版本号uchar
  464. // 返回:无
  465. ///////////////////////////////
  466. // void set_param_firmware_ver(uint8_t ver)
  467. //{ // 设置版本号
  468. // Paramx.ver_firmware = ver;
  469. // uint32_t addr = offsetof(Param_t, ver_firmware) + PARAMX_START_ADDR;
  470. // write_eeprom_para(addr, (uint8_t *)&ver, sizeof(ver));
  471. // set_crc_check_para();
  472. // }
  473. ////////////获取版本号//////////////
  474. // 参数:无
  475. // 返回:版本号数值uchar
  476. ////////////////////////
  477. uint8_t get_param_firmware_ver(void)
  478. { // 读取版本号
  479. return VER_FIRMWARE;
  480. }
  481. /////////////////获取超声波通道数/////////////////////
  482. /// 参数:无
  483. // 返回:超声波通道数
  484. /////////////////////////////////////
  485. uint8_t GetChNum(void)
  486. {
  487. uint8_t numb;
  488. get_channel_numb(&numb);
  489. return numb;
  490. }
  491. int8_t get_channel_numb(uint8_t *numb)
  492. { // 获取通道数
  493. *numb = Paramx.chan_num;
  494. return 0;
  495. }
  496. /////////////////////////////与红外通讯相关的设置和读取///////////////////////////////////////////
  497. //////////////////////////////////对paramx参数进行crc校验,并保存crc校验值////////////////////////////////////////////////////////////////
  498. // 参数:无
  499. // 返回0:正常 1:异常
  500. uint8_t set_crc_check_para(void)
  501. {
  502. Paramx.para_crc32 = com_crc32L_next(0xFFFFFFFFu, (uint8_t *)(&Paramx) + 8, sizeof(Param_t) - 8, 0xEDB88320);
  503. return write_eeprom_para(PARAMX_START_ADDR + offsetof(Param_t, para_crc32), (uint8_t *)&Paramx.para_crc32, sizeof(Paramx.para_crc32)); // 校验值长度
  504. return 0;
  505. }
  506. /////////////////////////检查新参数是否改变,如果改变则保存/////////////////////////////////////////////////
  507. // 参数1: new_para新参数值
  508. // 参数2: old_para原参数值
  509. // 参数3: len参数长度
  510. // 参数5:flag保存是否修改的标志1:修改了,0,未修改
  511. // 返回:0:保存成功 1:失败
  512. /////////////////////////////////////////////////////////////////////////////
  513. uint8_t set_para_if_nessary(void *new_para, void *old_para, uint8_t len, uint8_t *flag)
  514. {
  515. uint8_t *dat1 = new_para; // 转换为char型指针
  516. uint8_t *dat2 = old_para; // 转换为char型指针
  517. // if(memcmp(dat1,dat2,len)==0){//检查新数据和老数据是否一致
  518. // return 0;
  519. // }
  520. memcpy(dat2, dat1, len); // 更新参数值,在paramx中
  521. *flag = 1; // 参数更改标志,用于crc校验参考
  522. uint32_t addr = PARAMX_START_ADDR + (uint32_t)old_para - (uint32_t)&Paramx; // 取改参数在eeprom中的地址
  523. uint8_t ret;
  524. ret = write_eeprom_para(addr, dat1, len); // 返回写入是否成功标志 0:成功,1失败
  525. ret |= read_eeprom_para(addr, old_para, len); // 写入后读回来
  526. get_para_to_tdcitf();
  527. return 0;
  528. }
  529. //////////////////设置硬件参数参数////////////////////////////
  530. /// 参数:HardWarePara 包含 是否带压力传感器指示 pressure_sensor //
  531. // 关断参数:pipe_coe
  532. // 返回: 成功返回1, 失败返回2
  533. ///////////////////////////////////
  534. int8_t set_hardware_para(HardWareParaDef *HardWarePara)
  535. {
  536. uint8_t flag = 0, ret = 0;
  537. if (HardWarePara->pipe_coe <= 0)
  538. return 2; // 数据不合法
  539. if (HardWarePara->pressure_sensor != 1 && HardWarePara->pressure_sensor != 2)
  540. return 2;
  541. ret |= set_para_if_nessary(&HardWarePara->pipe_coe, &Paramx.pipe_coe, sizeof(Paramx.pipe_coe), &flag);
  542. ret |= set_para_if_nessary(&HardWarePara->pressure_sensor, &Paramx.pressure_sensor, sizeof(Paramx.pressure_sensor), &flag);
  543. if (flag == 1)
  544. { // 保存crc校验
  545. ret |= set_crc_check_para();
  546. }
  547. return (ret == 0 ? 0 : -1); // write_eeprom_para在成功写入后返回0,否则返回非零值
  548. }
  549. ////////////////////////读取硬件参数///////////////////////////////////
  550. // 参数:硬件参数指针HardWareParaDef
  551. // 返回:0:读取不成功, 1:读取成功
  552. ///////////////////////////////////////////////////////////////////////
  553. int8_t get_hardware_para(HardWareParaDef *HardWarePara)
  554. {
  555. HardWarePara->pipe_coe = Paramx.pipe_coe;
  556. HardWarePara->pressure_sensor = Paramx.pressure_sensor;
  557. return 0;
  558. }
  559. PATCH_INFO_DEF PatchInfo;
  560. ///////////////////设置表端开始升级信息//////////////////////////////////////////
  561. // 参数patch_info:表端升级相关信息指针
  562. // 返回:1:设置成功 2:版本号不匹配 3:升级包长度值超过允许长度
  563. /////////////////////////////////////////////////////////
  564. int8_t set_patch_info(PATCH_INFO_DEF *patch_info)
  565. {
  566. memset((uint8_t *)&PatchInfo, 0, sizeof(PATCH_INFO_DEF));
  567. if (patch_info->new_ver[4] <= patch_info->cur_ver[4] || patch_info->new_ver[0] != patch_info->cur_ver[0] || patch_info->new_ver[1] != patch_info->cur_ver[1] || patch_info->new_ver[2] != patch_info->cur_ver[2] || patch_info->new_ver[3] != patch_info->cur_ver[3])
  568. { // 新版本信息不合法
  569. return 2;
  570. }
  571. if (patch_info->cur_ver[0] != 'V')
  572. return 2;
  573. if (patch_info->cur_ver[1] != VER_TYPE)
  574. return 2;
  575. if (patch_info->cur_ver[2] != VER_OPERATOR)
  576. return 2;
  577. if (patch_info->cur_ver[3] != VER_MODULE)
  578. return 2;
  579. if (patch_info->cur_ver[4] != VER_FIRMWARE)
  580. return 2; // 差分包当前版本和正在运行的版本不一致
  581. if (patch_info->patch_len > DIFF_PATCH_PACKET_SIZE)
  582. return 3; // 长度超过写入最大长度
  583. memcpy(PatchInfo.cur_ver, patch_info->cur_ver, sizeof(patch_info->cur_ver)); // 保存当前版本号
  584. memcpy(PatchInfo.new_ver, patch_info->new_ver, sizeof(patch_info->new_ver)); // 保存新版本号
  585. PatchInfo.packet_crc = patch_info->packet_crc; // 数据的总校验值
  586. PatchInfo.patch_len = patch_info->patch_len; // 数据总长度
  587. PatchInfo.per_packet_len = patch_info->per_packet_len; // 固定512字节
  588. // PatchInfo.per_packet_len=patch_info->per_packet_len;//每包数据长度
  589. PatchInfo.update_status = 0x1; // 开始升级标志
  590. PatchInfo.cur_num = 1; // 当前升级包序号,初始0,第一包值=1
  591. PatchInfo.res_crc16 = 0; // 累计crc,没来一包数据校验一次,最后检查和中校验值是否相等
  592. PatchInfo.flash_addr_ptr = 0; // 当前flash写入地址
  593. LOG("packet num =%d,total size = %d\r\n",
  594. (patch_info->patch_len + PatchInfo.per_packet_len - 1) / PatchInfo.per_packet_len,
  595. patch_info->patch_len);
  596. return 1;
  597. }
  598. ////////////////////////////向flash写入差分包/////////////////////////////////////////
  599. ////DIFF_PACKET_DEF参数1 numb:包序号,从1开始
  600. // DIFF_PACKET_DEF参数2: len:差分包长度,目前默认是512byte
  601. // DIFF_PACKET_DEF参数3:data指针 指向要写入的差分包数据
  602. // 返回:1:成功写入 2:crc失败 6:未收到开始包 7:数据包序号不对
  603. //////////////////////////////////////////////////////////////////////////////
  604. // const uint8_t app_addr=0;
  605. uint8_t write_diff_patch_to_flash(DIFF_PACKET_DEF *Packet)
  606. {
  607. McuFlash_WP_t WP;
  608. uint8_t last_dat = 0;
  609. uint16_t write_len;
  610. if (PatchInfo.update_status != 1)
  611. return 0x6;
  612. if (Packet->packet_numb != PatchInfo.cur_num)
  613. return 6; // 不是下一个包
  614. //////////////////确定最后一帧及写入长度///////////////////
  615. Packet->packet_size = Packet->packet_size; // DIFF_PER_PACKET_SIZE;//固定
  616. if (Packet->packet_numb * PatchInfo.per_packet_len >= PatchInfo.patch_len)
  617. {
  618. last_dat = 1;
  619. write_len = (uint16_t)(PatchInfo.patch_len % PatchInfo.per_packet_len);
  620. }
  621. else
  622. {
  623. last_dat = 0; // 中间帧数据
  624. write_len = Packet->packet_size;
  625. }
  626. // write_len = Packet->packet_size;
  627. PatchInfo.res_crc16 = pack_crc_check(PatchInfo.res_crc16, Packet->data, write_len);
  628. if (Packet->packet_numb == 1)
  629. { // 第一包数据,先擦除
  630. #ifndef DEBUG_PATCH
  631. rt_enter_critical();
  632. // McuFlash_Unlock();
  633. McuFlash_EraseSegment(DIFF_PATCH_PACKET_START, DIFF_PATCH_PACKET_SIZE);
  634. // McuFlash_Lock();
  635. rt_exit_critical();
  636. #endif
  637. // erase_flash_memory(DIFF_PATCH_PACKET_START, DIFF_PATCH_PACKET_SIZE);
  638. }
  639. #ifndef DEBUG_PATCH
  640. write_flash_memory(Packet->data, DIFF_PATCH_PACKET_START + PatchInfo.flash_addr_ptr, write_len);
  641. #endif
  642. #ifdef APP_DEBUG_PRINT
  643. LOG("write patch num= %d\r\n", PatchInfo.cur_num);
  644. #endif
  645. PatchInfo.cur_num++;
  646. PatchInfo.flash_addr_ptr += write_len;
  647. if (last_dat == 1)
  648. { // 最后一包
  649. if (PatchInfo.res_crc16 != PatchInfo.packet_crc)
  650. {
  651. LOG("update data crc err pack:%d\r\n", Packet->packet_numb);
  652. return 2;
  653. }
  654. else
  655. {
  656. PatchInfo.update_status = 2; // 升级包写入结束,bootloader用该位判断是否需要升级,升级完成后将该位清零
  657. // 未升级的情况下,bootloader根据代码的完整程度和版本的新旧情况运行app
  658. // 写差分升级包升级的信息,供bootloader使用
  659. PatchInfo.run_app_ver_addr = (uint32_t)SOFT_VER;
  660. #ifndef DEBUG_PATCH
  661. erase_flash_memory(DIFF_UPDATE_INFO_START, DIFF_UPDATE_INFO_SIZE); // 写flash
  662. write_flash_memory((uint8_t *)&PatchInfo, DIFF_UPDATE_INFO_START, sizeof(PATCH_INFO_DEF));
  663. #endif
  664. LOG("last packet ok\r\n");
  665. NbRun.reset_mcu_cnt = 5;
  666. return 1; // 最后一包
  667. }
  668. }
  669. return 1; // 0x10;//中间包
  670. }
  671. //************设置主服务器和从服务器的ip地址和端口号******************************/
  672. // 参数dat:指向SERVER_IP_PORT_DEF结构体
  673. // 返回:成功返回1,失败返回2
  674. /////////////////////////////////////////////////////////////////////////////////
  675. int8_t set_server_ip_port_para(SERVER_IP_PORT_DEF *server_ip_para)
  676. {
  677. uint8_t flag = 0, ret = 0;
  678. // uint32_t addr;
  679. ret |= set_para_if_nessary(server_ip_para->main_server_ip, Paramx.main_server_ip, sizeof(Paramx.main_server_ip), &flag);
  680. ret |= set_para_if_nessary(&server_ip_para->main_server_port, &Paramx.main_server_port, sizeof(Paramx.main_server_port), &flag);
  681. ret |= set_para_if_nessary(server_ip_para->sub_server_ip, Paramx.sub_server_ip, sizeof(Paramx.sub_server_ip), &flag);
  682. ret |= set_para_if_nessary(&server_ip_para->sub_server_port, &Paramx.sub_server_port, sizeof(Paramx.sub_server_port), &flag);
  683. if (flag == 1)
  684. { // 保存crc校验
  685. // Paramx.para_crc32 = com_crc32L_next(0xFFFFFFFFu, (uint8_t *)(&Paramx+8), sizeof(Param_t)-8, 0xEDB88320);
  686. // ret|=write_eeprom_para(PARAMX_START_ADDR+offsetof(Param_t,para_crc32),(uint8_t *)&Paramx.para_crc32,sizeof(Paramx.para_crc32));//校验值长度
  687. ret |= set_crc_check_para();
  688. }
  689. return (ret == 0 ? 0 : -1); // write_eeprom_para在成功写入后返回0,否则返回非零值
  690. }
  691. ////////////////////////////读取主服务器和备用服务器ip地址和端口号/////////////////////////////
  692. // 参数server_ip_dat :SERVER_IP_PORT_DEF类型指针,用于保存主服务器和备用服务器的端口和ip地址信息
  693. //////////////////////////////////////////////////////////
  694. int8_t get_server_ip_port_para(SERVER_IP_PORT_DEF *server_ip_para)
  695. {
  696. memcpy(server_ip_para->main_server_ip, Paramx.main_server_ip, sizeof(Paramx.main_server_ip));
  697. server_ip_para->main_server_port = Paramx.main_server_port;
  698. memcpy(server_ip_para->sub_server_ip, Paramx.sub_server_ip, sizeof(Paramx.sub_server_ip));
  699. server_ip_para->sub_server_port = Paramx.sub_server_port;
  700. return 0;
  701. }
  702. ////////////////////////////设置定时上报周期和时间间隔/////////////////////////////////////////////////////
  703. // 参数:regular_report_para定时上报数据结构体,包含起始基准时间,间隔时间u\
  704. //返回:1:成功2:失败
  705. /////////////////////////////////////////////////////////////////////////////////////////////////////////
  706. int8_t set_regular_report_para(REGULAR_REPORT_DEF *regular_report_para)
  707. {
  708. uint8_t flag = 0, ret = 0;
  709. if (regular_report_para->report_base_hour > 23 || regular_report_para->report_base_min > 59 || regular_report_para->report_base_sec > 59)
  710. return 2;
  711. ret |= set_para_if_nessary(&regular_report_para->report_base_hour, &Paramx.report_base_hour, 3, &flag); // 年月日参数
  712. ret |= set_para_if_nessary(&regular_report_para->report_interval, &Paramx.report_interval, sizeof(Paramx.report_interval), &flag); // 时间间隔
  713. if (flag == 1)
  714. { // 保存crc校验
  715. ret |= set_crc_check_para();
  716. }
  717. return (ret == 0 ? 0 : -1);
  718. }
  719. /////////////////////////////读取定时上报周期和时间间隔信息//////////////////////////////////////////////
  720. // 参数regular_report_para保存定时上报数据结构体
  721. // 返回:1成功读取
  722. ////////////////////////////////////////////
  723. int8_t get_regular_report_para(REGULAR_REPORT_DEF *regular_report_para)
  724. {
  725. regular_report_para->report_base_hour = Paramx.report_base_hour;
  726. regular_report_para->report_base_min = Paramx.report_base_min;
  727. regular_report_para->report_base_sec = Paramx.report_base_sec;
  728. regular_report_para->report_interval = Paramx.report_interval;
  729. return 0;
  730. }
  731. ///////////////////////////////////设置DMA定时上报周期参数////////////////////////////////////////////////
  732. // 参数:dma_report_para dma参数结构体,包含dma起始时间结束时间和时间间隔参数
  733. // 返回:1:成功 2:失败
  734. ////////////////////////////////////////////////////////////////////////////////////
  735. int8_t set_dma_regular_report_para(DMA_REGULAR_REPORT_DEF *dma_report_para)
  736. {
  737. uint8_t flag = 0, ret = 0;
  738. // 判断数据是否在正常范围内
  739. if (dma_report_para->dma_report_start_hour > 23 || dma_report_para->dma_report_start_min > 59 || dma_report_para->dma_report_start_sec > 59)
  740. return 2;
  741. if (dma_report_para->dma_report_end_hour > 23 || dma_report_para->dma_report_end_min > 59 || dma_report_para->dma_report_end_sec > 59)
  742. return 2;
  743. ret |= set_para_if_nessary(dma_report_para, Paramx.dma_report_start, 8, &flag); // 参数整体保存
  744. if (flag == 1)
  745. { // 保存crc校验
  746. ret |= set_crc_check_para();
  747. }
  748. return (ret == 0 ? 0 : -1);
  749. }
  750. //////////////////////////////读取DMA定时上报参数///////////////////////////////////////////////////////
  751. // 参数: dma_report_para 参数保存结构体
  752. // 返回1:获取成功2:失败
  753. ////////////////////////////////////////////////////////////////////////////////////////
  754. int8_t get_dma_regular_report_para(DMA_REGULAR_REPORT_DEF *dma_report_para)
  755. {
  756. dma_report_para->dma_report_start_hour = Paramx.dma_report_start[0];
  757. dma_report_para->dma_report_start_min = Paramx.dma_report_start[1];
  758. dma_report_para->dma_report_start_sec = Paramx.dma_report_start[2];
  759. dma_report_para->dma_report_end_hour = Paramx.dma_report_end[0];
  760. dma_report_para->dma_report_end_min = Paramx.dma_report_end[1];
  761. dma_report_para->dma_report_end_sec = Paramx.dma_report_end[2];
  762. dma_report_para->dma_interval = Paramx.dma_interval;
  763. return 0;
  764. }
  765. ////////////////////////设置流量告警参数//////////////////////////////////////
  766. // 参数:flow_alarm_para流量告警参数结构体
  767. // 返回:1:设置成功 2:失败
  768. int8_t set_flow_alarm_para(FLOW_ALARM_PARA_DEF *flow_alarm_para)
  769. {
  770. uint8_t flag = 0, ret = 0;
  771. // 判断数据是否在正常范围内
  772. ret = set_para_if_nessary(flow_alarm_para, &Paramx.large_flow_alarm_thres, 14, &flag); // 参数整体保存
  773. if (flag == 1)
  774. { // 保存crc校验
  775. ret |= set_crc_check_para();
  776. }
  777. return (ret == 0 ?: -1);
  778. }
  779. ////////////////////////获取流量告警参数值/////////////////////////////////////////
  780. // 参数flow_alarm_para 保存流量参数
  781. // 返回:1:成功 2:失败
  782. //////////////////////////////////////////////////////
  783. int8_t get_flow_alarm_para(FLOW_ALARM_PARA_DEF *flow_alarm_para)
  784. {
  785. flow_alarm_para->large_flow_alarm_thres = Paramx.large_flow_alarm_thres;
  786. flow_alarm_para->large_flow_cnti_moni_time = Paramx.large_flow_cnti_moni_time;
  787. flow_alarm_para->cnti_flow_cnti_moni_time = Paramx.cnti_flow_cnti_moni_time;
  788. flow_alarm_para->leak_flow_alarm_thres = Paramx.leak_flow_alarm_thres;
  789. flow_alarm_para->leak_flow_cnti_moni_time = Paramx.leak_flow_cnti_moni_time;
  790. return 0;
  791. }
  792. /////////////////////设置压力表告警参数///////////////////////////////////////////////////
  793. // 参数:press_alarm_para 要设置的压力表报警参数数据指针
  794. // 返回:1:成功,2:失败
  795. ///////////////////////////////////////////////////////////////////////////////
  796. int8_t set_press_alarm_para(PRESS_ALARM_PARA_DEF *press_alarm_para)
  797. {
  798. uint8_t flag = 0, ret = 0;
  799. uint8_t dat[4];
  800. memset(dat, 0, 4);
  801. dat[0] = press_alarm_para->high_press_alarm_thres;
  802. dat[2] = press_alarm_para->low_press_alarm_thres;
  803. if (dat[0] < dat[2])
  804. return 3;
  805. // 判断数据是否在正常范围内
  806. ret = set_para_if_nessary(dat, &Paramx.high_press_alarm_thres, 4, &flag); // 参数整体保存
  807. if (flag == 1)
  808. { // 保存crc校验
  809. ret |= set_crc_check_para();
  810. }
  811. return (ret == 0 ? 0 : -1);
  812. }
  813. ////////////////////////获取压力报警参数//////////////////////////////////////////////////
  814. ////参数 press_alarm_para 存储压力报警参数值,包括高压力和低压力报警阈值
  815. // 返回 1:读取成功
  816. ////////////////////////////////////////////////////////////////////////////////////////////
  817. int8_t get_press_alarm_para(PRESS_ALARM_PARA_DEF *press_alarm_para)
  818. {
  819. press_alarm_para->high_press_alarm_thres = Paramx.high_press_alarm_thres;
  820. press_alarm_para->low_press_alarm_thres = Paramx.low_press_alarm_thres;
  821. return 0;
  822. }
  823. /////////////////////////设置温度告警参数//////////////////////////////////////
  824. /////参数: temp_alarm_para 指针包含要存储的温度报警参数 包括高温和低温报警阈值
  825. // 返回 1:成功 2:失败
  826. ////////////////////////////////////////////////////////////////////////////
  827. int8_t set_temp_alarm_para(TEMP_ALARM_PARA_DEF *temp_alarm_para)
  828. {
  829. uint8_t flag = 0, ret = 0;
  830. if (temp_alarm_para->high_temp_alarm_thres < temp_alarm_para->low_temp_alarm_thres)
  831. return 2;
  832. ret = set_para_if_nessary(temp_alarm_para, &Paramx.high_temp_alarm_thres, 4, &flag); // 参数整体保存
  833. if (flag == 1)
  834. { // 保存crc校验
  835. ret |= set_crc_check_para();
  836. }
  837. return (ret == 0 ? 0 : -1);
  838. }
  839. /////////////////////////获取温度告警参数//////////////////////////////////////
  840. /////参数: temp_alarm_para 指针,保存读出的参数
  841. // 返回 1:成功 2:失败
  842. ////////////////////////////////////////////////////////////////////////////
  843. int8_t get_temp_alarm_para(TEMP_ALARM_PARA_DEF *temp_alarm_para)
  844. {
  845. temp_alarm_para->high_temp_alarm_thres = Paramx.high_temp_alarm_thres;
  846. temp_alarm_para->low_temp_alarm_thres = Paramx.low_temp_alarm_thres;
  847. return 0;
  848. }
  849. ////////////////////////////设置表端结算日参数/////////////////////////////////////
  850. // 参数:要写入的表端结算日数据
  851. // 返回 1:成功 2:失败
  852. ////////////////////////////////////////////////////////////////////////////////////
  853. int8_t set_settlement_day_para(SETTLEMENT_DAY_DEF *settlement_day_para)
  854. {
  855. uint8_t flag = 0, ret = 0;
  856. if (settlement_day_para->settlement_day > 31)
  857. return 2;
  858. ret = set_para_if_nessary(settlement_day_para, &Paramx.settlement_day, 1, &flag); // 参数整体保存
  859. if (flag == 1)
  860. { // 保存crc校验
  861. ret |= set_crc_check_para();
  862. }
  863. return (ret == 0 ? 0 : -1);
  864. }
  865. ////////////////////////////读取表端结算日参数/////////////////////////////////////
  866. // 参数:要写入的表端结算日数据
  867. // 返回 1:成功 2:失败
  868. ////////////////////////////////////////////////////////////////////////////////////
  869. int8_t get_settlement_day_para(SETTLEMENT_DAY_DEF *settlement_day_para)
  870. {
  871. settlement_day_para->settlement_day = Paramx.settlement_day;
  872. return 0;
  873. }
  874. ///////////////////////////////设置表端底读///////////////////////////////////////////////////
  875. // 参数:指向表端底读数据指针
  876. // 返回:1:成功 2:失败
  877. //////////////////////////////////////////////////////////////////////////////////////////////
  878. int8_t set_meter_bottom_data(METER_BOTTOM_DEF *bottom_data)
  879. {
  880. uint8_t flag = 0, ret = 0;
  881. double base_read = (double)(uint32_t)((bottom_data->fw[3] << 24) |
  882. (bottom_data->fw[2] << 16) |
  883. (bottom_data->fw[1] << 8) |
  884. bottom_data->fw[0]);
  885. base_read *= 10000; // 0.01->0.000001//转换为0.000001单位
  886. FwCumFlow = base_read; // 更新当前流量和正向流量
  887. base_read = (double)(uint32_t)((bottom_data->bw[3] << 24) |
  888. (bottom_data->bw[2] << 16) |
  889. (bottom_data->bw[1] << 8) |
  890. bottom_data->bw[0]);
  891. base_read *= 10000; // 0.01->0.000001//转换为0.000001单位
  892. BwCumFlow = base_read;
  893. CumFlow = FwCumFlow - BwCumFlow;
  894. SetBillCumFlow(CumFlow, FwCumFlow, BwCumFlow); // 设置当前流量数据
  895. save_cur_flow_flag = 1; // 保存到当前值,循环存储
  896. return 0;
  897. }
  898. ////////////////////////读取前18个月月结数据//////////////////////////////////////////
  899. // 参数:月结数据指针,空间大小18*11
  900. // 成功返回1,失败返回2
  901. /////////////////////////////////////////////////////////////////////////////////////
  902. int8_t get_18month_record_data(uint8_t *data)
  903. {
  904. uint8_t i, ret = 0;
  905. bill_t bill;
  906. rtc_run_t *rr;
  907. get_rtc_run(&rr); // 当前时间
  908. uint8_t flag, j;
  909. uint32_t date = ((rr->year << 16) | (rr->month << 8));
  910. for (i = 0; i < 18; i++)
  911. {
  912. date = prev_month(date);
  913. flag = get_month_used_bill((uint8_t)(date >> 16), (uint8_t)(date >> 8), &bill);
  914. ret |= flag;
  915. if (flag != 0)
  916. {
  917. for (j = 0; j < 11; j++)
  918. data[i * 11 + j] = 0;
  919. continue;
  920. }
  921. data[i * 11] = 0x14;
  922. data[i * 11 + 1] = bill.date[0];
  923. data[i * 11 + 2] = bill.date[1]; //
  924. data[i * 11 + 3] = (unsigned char)(bill.fw_used);
  925. data[i * 11 + 4] = (unsigned char)(bill.fw_used >> 8);
  926. data[i * 11 + 5] = (unsigned char)(bill.fw_used >> 16);
  927. data[i * 11 + 6] = (unsigned char)(bill.fw_used >> 24); // 正向流量
  928. data[i * 11 + 7] = (unsigned char)(bill.bw_used);
  929. data[i * 11 + 8] = (unsigned char)(bill.bw_used >> 8);
  930. data[i * 11 + 9] = (unsigned char)(bill.bw_used >> 16);
  931. data[i * 11 + 10] = (unsigned char)(bill.bw_used >> 24); // 反向流量
  932. }
  933. if (ret != 0)
  934. return -1;
  935. else
  936. return 0;
  937. }
  938. ////////////////////////读取前30日日结数据//////////////////////////////////////////
  939. // 参数:日结数据指针,空间大小30*12
  940. // 成功返回1,失败返回2
  941. /////////////////////////////////////////////////////////////////////////////////////
  942. int8_t get_30day_record_data(uint8_t *data)
  943. {
  944. uint8_t i, ret = 0;
  945. bill_t bill;
  946. rtc_run_t *rr;
  947. get_rtc_run(&rr); // 当前时间
  948. uint32_t date = ((rr->year << 16) | (rr->month << 8) | rr->day);
  949. uint8_t flag, j;
  950. for (i = 0; i < 30; i++)
  951. {
  952. date = prev_day(date);
  953. flag = get_day_used_bill((uint8_t)(date >> 8), (uint8_t)date, &bill);
  954. ret |= flag;
  955. if ((uint8_t)(date >> 16) != bill.date[0] || (uint8_t)(date >> 8) != bill.date[1] || (uint8_t)(date & 0xff) != bill.date[2] // rec time is not intend to read
  956. || flag != 0)
  957. {
  958. ret |= 1;
  959. for (j = 0; j < 12; j++)
  960. data[i * 12 + j] = 0;
  961. continue;
  962. }
  963. data[i * 12] = 0x14; // 20
  964. data[i * 12 + 1] = bill.date[0]; // 年
  965. data[i * 12 + 2] = bill.date[1]; // 月
  966. data[i * 12 + 3] = bill.date[2]; // 日
  967. data[i * 12 + 4] = (unsigned char)(bill.fw_used);
  968. data[i * 12 + 5] = (unsigned char)(bill.fw_used >> 8);
  969. data[i * 12 + 6] = (unsigned char)(bill.fw_used >> 16);
  970. data[i * 12 + 7] = (unsigned char)(bill.fw_used >> 24);
  971. data[i * 12 + 8] = (unsigned char)(bill.bw_used);
  972. data[i * 12 + 9] = (unsigned char)(bill.bw_used >> 8);
  973. data[i * 12 + 10] = (unsigned char)(bill.bw_used >> 16);
  974. data[i * 12 + 11] = (unsigned char)(bill.bw_used >> 24);
  975. }
  976. if (ret != 0)
  977. return -1;
  978. else
  979. return 0;
  980. }
  981. ////////////////////////读取结数据//////////////////////////////////////////
  982. // 参数1:读取的年月日
  983. /////////////////////////////////////////////////////////////////////////////////////
  984. int8_t get_hour_record_data(uint8_t year, uint8_t month, uint8_t day, uint8_t *data)
  985. {
  986. uint8_t i;
  987. hour_bill_t bill;
  988. int32_t days;
  989. // 1. 默认填零
  990. memset(data, 0, 244);
  991. // 2. 检查时间有效性
  992. days = get_days_between_now(year, month, day);
  993. // 假设:有效范围为过去30天内(含今天,即0~30天)
  994. // 如果 get_days_between_now 返回负数表示未来,正数表示过去
  995. if (days < 0 || days > 30)
  996. {
  997. return 0; // 不在30天内,返回全零(已memset)
  998. }
  999. // 3. 读取数据
  1000. // 注意:请确认 get_hour_used_bill 的正确用法。
  1001. // 如果原代码 (uint8_t)date 是bug,这里应该传入正确的参数。
  1002. // 假设 get_hour_used_bill 需要 year, month, day, hour
  1003. // 由于我不知道 get_hour_used_bill 的确切签名,以下代码假设它需要修正以支持年月日
  1004. // 如果原系统确实只传 day 就能工作(例如底层驱动自动处理环形缓冲或当前月),则保留原调用方式但需注意局限性。
  1005. for (i = 0; i < 24; i++)
  1006. {
  1007. // 【重要】原代码这里强转 uint8_t 丢失了年月信息,极大概率是Bug。
  1008. // 如果 get_hour_used_bill 只能接受 uint8_t day,请确认它是否能正确读取指定年月的数据。
  1009. // 如果不能,你需要修改 get_hour_used_bill 或在此处提供完整日期上下文。
  1010. // 暂时沿用原调用方式,但加上注释警示
  1011. if (get_hour_used_bill(day, i, &bill) == 0)
  1012. {
  1013. if (bill.date[0] != year || bill.date[1] != month || bill.date[2] != day || bill.date[3] != i) // if rec time is not valid drop it
  1014. continue;
  1015. data[0] = 0x14; // 标记有效? 原代码在循环外设置 data[0]=0x14, 这里如果部分失败怎么处理?
  1016. // 原代码逻辑:只要进入else,data[0]就被设为0x14。
  1017. // 如果某个小时失败,bill是全零,拷贝进去也是零。
  1018. memcpy(&data[4 + i * 3], bill.fw_used, 3);
  1019. memcpy(&data[4 + 72 + i * 3], bill.bw_used, 3);
  1020. data[4 + 144 + i] = bill.pressure;
  1021. memcpy(&data[4 + 168 + i * 3], bill.flow_rate, 3);
  1022. }
  1023. // 如果读取失败,data对应位置保持为0(因为开头memset了)
  1024. }
  1025. // 设置头部信息,表示这是一条有效的记录结构(即使内容为0)
  1026. data[0] = 0x14;
  1027. data[1] = year;
  1028. data[2] = month;
  1029. data[3] = day;
  1030. return 0;
  1031. }
  1032. ////////////////////////////////比较两个时间的大小///////////////////////////////////////////
  1033. // 参数1,2,用于比较的两个时间结构体
  1034. // 返回:date1>date2时返回1,相等时返回0,date1<date2时返回-1
  1035. ///////////////////////////////////////////////////////////////////////////////////////////
  1036. int8_t datecmp(tm_t date1, tm_t date2)
  1037. {
  1038. if (date1.year > date2.year)
  1039. return 1;
  1040. else if (date1.year < date2.year)
  1041. return -1;
  1042. if (date1.month > date2.month)
  1043. return 1;
  1044. else if (date1.month < date2.month)
  1045. return -1;
  1046. if (date1.day > date2.day)
  1047. return 1;
  1048. else if (date1.day < date2.day)
  1049. return -1;
  1050. if (date1.hour > date2.hour)
  1051. return 1;
  1052. else if (date1.hour < date2.hour)
  1053. return -1;
  1054. if (date1.min > date2.min)
  1055. return 1;
  1056. else if (date1.min < date2.min)
  1057. return -1;
  1058. if (date1.sec > date2.sec)
  1059. return 1;
  1060. else if (date1.sec < date2.sec)
  1061. return -1;
  1062. return 0;
  1063. }
  1064. //////////////////////////////////获取5分钟密集数据///////////////////////////////////////////////////////////
  1065. // 参数get_5min_record_data:保存读取的起始时间和终止时间,
  1066. // 参数numb:读取的序号,0表示读取第一组数据,
  1067. // 返回1:表示读取成功 2:表示读取失败,3:读取成功,最后一帧数据
  1068. int8_t get_5min_record_data(GET_5MIN_REOCORD_DEF *get_5min_record_info, uint16_t numb, uint8_t *data)
  1069. {
  1070. uint8_t ret = 0;
  1071. uint8_t i;
  1072. hour_bill_t bill;
  1073. tm_t query_time; // 用户逻辑上的查询时间点(例如 10:00)
  1074. tm_t index_time; // 底层存储使用的索引时间点(例如 10:05)
  1075. tm_t start_time;
  1076. // 1. 初始化输出缓冲区
  1077. memset(data, 0, 24 * 16);
  1078. // 2. 解析起始时间 (用户传入的 start_time)
  1079. start_time.year = get_5min_record_info->start_time[0];
  1080. start_time.month = get_5min_record_info->start_time[1];
  1081. start_time.day = get_5min_record_info->start_time[2];
  1082. start_time.hour = get_5min_record_info->start_time[3];
  1083. start_time.min = get_5min_record_info->start_time[4];
  1084. start_time.sec = 0;
  1085. // 3. 计算当前页的起始查询时间
  1086. // 每页 24 个点 * 5 分钟 = 120 分钟 = 7200 秒
  1087. uint32_t offset_seconds = (uint32_t)numb * 24 * 5 * 60;
  1088. memcpy(&query_time, &start_time, sizeof(tm_t));
  1089. if (offset_seconds > 0)
  1090. {
  1091. time_add_secs(&query_time, &query_time, offset_seconds);
  1092. }
  1093. // 4. 循环读取 24 个点
  1094. for (i = 0; i < 24; i++)
  1095. {
  1096. // 【关键修正】:因为底层存储使用“区间末尾时间”作为标记
  1097. // 所以查询 10:00 的数据,实际要用 10:05 去查
  1098. memcpy(&index_time, &query_time, sizeof(tm_t));
  1099. time_add_secs(&index_time, &index_time, 5 * 60);
  1100. // 5. 调用底层读取函数
  1101. // 使用 index_time (末尾时间) 进行查询
  1102. // 【严重警告】:请确认 get_5min_used_bill 能正确处理 index_time 的年月!
  1103. // 如果它只能处理当前月,查询历史数据必错。
  1104. uint8_t flag = get_5min_used_bill(index_time.day, index_time.hour, index_time.min, &bill);
  1105. if (flag != 0)
  1106. {
  1107. // 读取失败,该点数据保持为 0
  1108. ret |= 1;
  1109. }
  1110. else if (bill.date[0] != index_time.year || bill.date[1] != index_time.month || bill.date[2] != index_time.day || bill.date[3] != index_time.hour)
  1111. {
  1112. ret |= 1;
  1113. }
  1114. else
  1115. {
  1116. // 填充数据
  1117. data[i * 16] = 0x14; // 标记有效
  1118. data[1 + i * 16] = bill.date[0];
  1119. data[2 + i * 16] = bill.date[1];
  1120. data[3 + i * 16] = bill.date[2];
  1121. data[4 + i * 16] = bill.date[3];
  1122. // 注意:这里返回给上层的分钟数,应该填 query_time.min (用户请求的逻辑时间)
  1123. // 还是 index_time.min (底层存储的物理时间)?
  1124. // 通常协议要求返回“数据所属的时间点”。如果用户查 10:00,期望看到 10:00 或 10:05?
  1125. // 根据原代码 logic: data[5 + i * 16] = (uint8_t)dest.min; (原代码用的是查询时间)
  1126. // 建议保持一致性,如果上层知道这是5分钟数据,通常展示开始时间或结束时间需统一。
  1127. // 这里暂且填入 index_time.min (10:05),因为这是数据的真实标记。
  1128. data[5 + i * 16] = index_time.min;
  1129. memcpy(&data[6 + i * 16], bill.fw_used, 10);
  1130. }
  1131. // 6. 移动到下一个查询点 (逻辑时间 + 5分钟)
  1132. time_add_secs(&query_time, &query_time, 5 * 60);
  1133. }
  1134. return ret ? -2 : 0;
  1135. }
  1136. //////////////////////////////读取日志信息///////////////////////////////////////////
  1137. // 参数:日志信息存储指针data, 一个30*13个字节
  1138. // 返回1:成功, 0:失败
  1139. /////////////////////////////////////////////////////////////////////////
  1140. int8_t get_log_record(uint8_t start, uint8_t num, uint8_t *data)
  1141. {
  1142. alarm_t alarm;
  1143. uint8_t i;
  1144. if (num > 30)
  1145. num = 30;
  1146. memset(data, 0, 30 * 13); // 先清零存储器
  1147. for (i = 0; i < num; i++)
  1148. {
  1149. if (read_alarm(start + i, &alarm) == 1)
  1150. { // 读取成功
  1151. memcpy(data, alarm.time, 7);
  1152. data[7] = alarm.err_no;
  1153. data[8] = alarm.type;
  1154. memcpy(&data[9], alarm.arg, 4);
  1155. }
  1156. data += 13;
  1157. }
  1158. return 0;
  1159. }
  1160. /////////////////////////////设置声道数/////////////////////////////////////////////
  1161. int8_t set_channel_numb(uint8_t *numb)
  1162. {
  1163. /*
  1164. if (*numb == 0 || *numb > 4)
  1165. return -2;
  1166. uint8_t flag = 0, ret = 0;
  1167. // 判断数据是否在正常范围内
  1168. ret = set_para_if_nessary(numb, &Paramx.chan_num, 1, &flag); // 参数整体保存
  1169. if (flag == 1)
  1170. { // 保存crc校验
  1171. ret |= set_crc_check_para();
  1172. }
  1173. return (ret == 0 ? 0 : -1);
  1174. */
  1175. return 0;
  1176. }
  1177. ////////////////////////////////读表地址/////////////////////////////////////////////////
  1178. int8_t get_device_addr(uint8_t *data)
  1179. {
  1180. memcpy(data, Paramx.dev_id, sizeof(Paramx.dev_id));
  1181. return 0;
  1182. }
  1183. ////////////////////////////////设置表地址////////////////////////////////////////////////
  1184. int8_t set_device_addr(uint8_t *data)
  1185. {
  1186. uint8_t flag = 0, ret = 0;
  1187. // 判断数据是否在正常范围内
  1188. ret = set_para_if_nessary(data, &Paramx.dev_id, 6, &flag); // 参数整体保存
  1189. if (flag == 1)
  1190. { // 保存crc校验
  1191. ret |= set_crc_check_para();
  1192. }
  1193. return (ret == 0 ? 0 : -1);
  1194. }
  1195. ////////////////////////////////设置流量参数////////////////////////////////////////////
  1196. // 参数flow_para指针保存8个流量数据,其中index成员是温度等级范围0~2
  1197. ////////////////////////////////////////////////////////////////////////////////////////
  1198. int8_t set_flow_para(FLOW_PARA_DEF *flow_para)
  1199. {
  1200. uint8_t flag = 0, ret = 0;
  1201. // 判断数据是否在正常范围内
  1202. uint8_t ser = CheckTempRangeIndex((float)flow_para->temp);
  1203. if (ser > 2)
  1204. return 2; // 温度等级确定的序号,一共3个温度等级
  1205. ret = set_para_if_nessary(flow_para->cur_c, Paramx.check_spdLvl_c[ser].cur_c, 16, &flag); // 参数整体保存
  1206. if (flag == 1)
  1207. { // 保存crc校验
  1208. ret |= set_crc_check_para();
  1209. }
  1210. return (ret == 0 ? 0 : -1);
  1211. }
  1212. /////////////////////////////读取流量参数///////////////////////////////////////////
  1213. // 参数flow_para指针保存流量信息,读取前应设置成员index值,范围0~2表示温度等级
  1214. ////////////////////////////////////////////////////////////////////////////////////
  1215. int8_t get_flow_para(FLOW_PARA_DEF *flow_para)
  1216. {
  1217. uint8_t i;
  1218. uint8_t ser = CheckTempRangeIndex((float)flow_para->temp);
  1219. for (i = 0; i < 8; i++)
  1220. {
  1221. flow_para->cur_c[i] = Paramx.check_spdLvl_c[ser].cur_c[i];
  1222. }
  1223. return 0;
  1224. }
  1225. /////////////////////////////////设置deltaTC流量参数/////////////////////////////////////////////////////////////
  1226. // 参数deltaTC_para保存相关参数,temp是温度值,整型
  1227. /////////////////////////////////////////////////////////////////////////////////
  1228. int8_t set_deltaTC_flow_para(DELTA_TC_FLOW_PARA_DEF *deltaTC_para)
  1229. {
  1230. uint8_t flag = 0, ret = 0;
  1231. const uint16_t base_data[8] = {1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340};
  1232. // 判断数据是否在正常范围内
  1233. uint8_t ser = CheckTempRangeIndex((float)deltaTC_para->temp);
  1234. if (ser > 2)
  1235. return 2; // 温度等级确定的序号,一共3个温度等级
  1236. ret = set_para_if_nessary(deltaTC_para->cur_c, Paramx.check_spdLvl_c[ser].cur_c, 16, &flag); // 参数整体保存
  1237. ret |= set_para_if_nessary(deltaTC_para->spd_lvl, Paramx.check_spdLvl_c[ser].spd_lvl, 16, &flag); // 参数整体保存
  1238. ret |= set_para_if_nessary((uint16_t *)base_data, Paramx.check_spdLvl_c[ser].base_c, 16, &flag); // 参数整体保存
  1239. if (flag == 1)
  1240. { // 保存crc校验
  1241. ret |= set_crc_check_para();
  1242. }
  1243. return (ret == 0 ? 0 : -1);
  1244. }
  1245. /////////////////////读取参数deltaTC_para参数///////////////////////////////////
  1246. ///////////////参数中temp是温度值,
  1247. // 返回1:成功 2:失败
  1248. //////////////////////////////////////////////////////////////////////////
  1249. int8_t get_deltaTC_flow_para(DELTA_TC_FLOW_PARA_DEF *deltaTC_para)
  1250. {
  1251. uint8_t ser = CheckTempRangeIndex((float)deltaTC_para->temp);
  1252. if (ser > 2)
  1253. return 2; // 超出范围
  1254. uint8_t i;
  1255. for (i = 0; i < 8; i++)
  1256. {
  1257. deltaTC_para->cur_c[i] = Paramx.check_spdLvl_c[ser].cur_c[i];
  1258. deltaTC_para->spd_lvl[i] = Paramx.check_spdLvl_c[ser].spd_lvl[i];
  1259. }
  1260. return 0;
  1261. }
  1262. ////////////////////////设置口径和温度补偿值////////////////////////////////////////////////////////
  1263. // 返回1:成功,2失败
  1264. /////////////////////////////////////////////////////////////////////////////////////////////////////
  1265. int8_t set_diameter_and_quad_cell_data(uint16_t diameter, void *quad_cell_data)
  1266. {
  1267. uint8_t flag = 0, ret = 0;
  1268. if (diameter != 0)
  1269. { // 添加不为零判断
  1270. ret = set_para_if_nessary(&diameter, &Paramx.diameter, sizeof(Paramx.diameter), &flag); // 保存直径数据
  1271. if (flag == 1)
  1272. { // 保存crc校验
  1273. ret |= set_crc_check_para();
  1274. }
  1275. }
  1276. ret |= eeprom_MassWrite(quad_cell_data, QUAD_CELL_START_ADDR, sizeof(Quad_Cell_t) * Quad_Cell_NUM);
  1277. get_quad_cell_data(Quad_Cell_Ary);
  1278. return (ret == 0 ? 0 : -1);
  1279. }
  1280. ////////////////////////读取温度补偿值 在初始化时调用////////////////////////////////////////////////////////
  1281. // 参数data指向要存储的参数 其中包括125个温度补偿数据和一个直径数据
  1282. // 返回1:成功,2失败
  1283. /////////////////////////////////////////////////////////////////////////////////////////////////////
  1284. int8_t get_quad_cell_data(void *quad_cell_data)
  1285. {
  1286. uint8_t ret = 0;
  1287. ret = eeprom_MassRead(quad_cell_data, QUAD_CELL_START_ADDR, sizeof(Quad_Cell_t) * Quad_Cell_NUM);
  1288. return ret;
  1289. }
  1290. ////////////////////// 判断温度补偿数据是否合法////////////////////////////////
  1291. // 合法返回 0, 不合法返回-1
  1292. //////////////////////////////////////////////////////
  1293. int8_t Check_quad_cell_data_valid(uint32_t quad_cell_addr)
  1294. {
  1295. float temp[4];
  1296. uint8_t i;
  1297. for (i = 0; i < (Quad_Cell_NUM * 5) / 4; i++)
  1298. {
  1299. eeprom_MassRead((uint8_t *)temp, (uint32_t)quad_cell_addr + i * sizeof(float) * 4, sizeof(float) * 4);
  1300. if (temp[0] < -100 || temp[0] > 50000 ||
  1301. temp[1] < -100 || temp[1] > 50000 ||
  1302. temp[2] < -100 || temp[2] > 50000 ||
  1303. temp[3] < -100 || temp[3] > 50000)
  1304. return -1;
  1305. }
  1306. return 0;
  1307. }
  1308. ///////////////////////设置自动匹配电平参数///////////////////////////////////////////////
  1309. // 参数指针data 包含比较器和比较器门槛和门槛宽度
  1310. /////////////////////////////////////////////////////////////////////////////////////
  1311. int8_t set_auto_match_level_para(AUTO_MATCH_LEVEL_PARA_DEF *data)
  1312. {
  1313. uint8_t flag = 0, ret = 0;
  1314. ret = set_para_if_nessary(data, &Paramx.cmp_thers, 30, &flag); // 保存直径数据
  1315. if (flag == 1)
  1316. { // 保存crc校验
  1317. ret |= set_crc_check_para();
  1318. }
  1319. return (ret == 0 ? 0 : -1);
  1320. }
  1321. /////////////保存skew参数/////////////////////
  1322. /////////////////////////////////
  1323. int8_t set_skew_para(SKEW_PARA_DEF *skew_para)
  1324. {
  1325. uint8_t flag = 0, ret = 0;
  1326. ret = set_para_if_nessary(skew_para, &Paramx.path_skew, 16, &flag); // 保存直径数据
  1327. if (flag == 1)
  1328. { // 保存crc校验
  1329. ret |= set_crc_check_para();
  1330. }
  1331. return (ret == 0 ? 0 : -1);
  1332. }
  1333. ////////////////////////////设置nb已选择频段标志/////////////////////////////////
  1334. int8_t set_nb_band(void)
  1335. {
  1336. uint8_t flag = 0, ret = 0;
  1337. uint8_t dat=0;
  1338. // 判断数据是否在正常范围内
  1339. ret = set_para_if_nessary(&dat, &Paramx.nb_band_flag, 1, &flag); // 参数整体保存
  1340. if (flag == 1)
  1341. { // 保存crc校验
  1342. ret |= set_crc_check_para();
  1343. }
  1344. return (ret == 0 ?: -1);
  1345. }
  1346. ////////////////////////////读取自动匹配电平参数/////////////////////////////////////////////
  1347. // 参数指针保存比较器和比较器门槛宽度数据
  1348. // 返回1读取成功
  1349. ////////////////////////////////////////////////////////////////////
  1350. int8_t get_auto_match_level_para(AUTO_MATCH_LEVEL_PARA_DEF *data)
  1351. {
  1352. memcpy((uint8_t *)data, Paramx.cmp_thers, sizeof(AUTO_MATCH_LEVEL_PARA_DEF));
  1353. return 0;
  1354. }
  1355. int8_t set_nbqr_para(NBQR_PARA_DEF *nbqr_para)
  1356. {
  1357. uint8_t flag = 0, ret = 0;
  1358. ret = set_para_if_nessary(nbqr_para, &Paramx.n, sizeof(NBQR_PARA_DEF), &flag); // 保存直径数据
  1359. if (flag == 1)
  1360. { // 保存crc校验
  1361. ret |= set_crc_check_para();
  1362. }
  1363. return (ret == 0 ? 0 : -1);
  1364. }
  1365. int8_t get_bnqr_para(NBQR_PARA_DEF *nbqr_para)
  1366. {
  1367. nbqr_para->n = Paramx.n;
  1368. nbqr_para->b = Paramx.b;
  1369. nbqr_para->q = Paramx.q;
  1370. nbqr_para->r = Paramx.r;
  1371. return 0;
  1372. }
  1373. uint16_t pack_crc_check(uint16_t prev_data, uint8_t *data, uint16_t len)
  1374. {
  1375. uint16_t i, crc;
  1376. uint8_t index;
  1377. for (i = 0; i < len; i++)
  1378. {
  1379. index = (uint8_t)(data[i] ^ (prev_data >> 8));
  1380. crc = (uint16_t)(ccitt_table[index] ^ (prev_data << 8));
  1381. prev_data = crc;
  1382. }
  1383. return crc;
  1384. }
  1385. ///////////////////1秒一次运行的一些零星任务//////////////////////
  1386. uint8_t rtc_1s_flag;
  1387. void run_clk_task_handler(void)
  1388. {
  1389. check_rewrite_para(); // 相关参数判断,不合法的重写eeprom
  1390. rtc_1s_flag=1;
  1391. }
  1392. //////////////////////////////////////
  1393. ///////////检查是否是新app第一次运行,如果是,则更新flash中的运行信息//////////////////
  1394. // 参数:无
  1395. // 返回:无
  1396. ////////////////////////////////////////////////////////////////////////////////////
  1397. void update_run_app_info(void)
  1398. {
  1399. if (StartUp != 5)
  1400. return;
  1401. PatchInfo = *(PATCH_INFO_DEF *)DIFF_UPDATE_INFO_START; // 整个结构体一起拷贝
  1402. #ifdef APP_DEBUG_PRINT
  1403. if (PatchInfo.update_status == 3)
  1404. {
  1405. LOG("new app first run\r\n");
  1406. }
  1407. else
  1408. {
  1409. LOG("old app run run\r\n");
  1410. }
  1411. LOG("cur ver = V%d.%d.%d.%d\r\n", VER_TYPE, VER_OPERATOR, VER_MODULE, VER_FIRMWARE);
  1412. #endif
  1413. if (PatchInfo.update_status != 0)
  1414. {
  1415. memset(&PatchInfo, 0, sizeof(PATCH_INFO_DEF));
  1416. write_flash_memory((uint8_t *)&PatchInfo, DIFF_UPDATE_INFO_START, sizeof(PATCH_INFO_DEF));
  1417. }
  1418. #ifndef DEBUG_RESET_LOG_NOT_SEND
  1419. write_alarm(LOG_MCU_RESET, 1, 5555); // wxl2026-5-8 非调试状态写入单片机复位事件日志
  1420. #endif
  1421. }
  1422. void write_flash_memory(uint8_t *data, uint32_t addr, uint32_t len)
  1423. {
  1424. McuFlash_WP_t WP;
  1425. feed_dog();
  1426. rt_enter_critical();
  1427. McuFlash_Unlock();
  1428. McuFlash_OpenWP(addr, &WP);
  1429. McuFlash_Buf2WP(data, len, &WP);
  1430. McuFlash_CloseWP(&WP);
  1431. McuFlash_Lock();
  1432. rt_exit_critical();
  1433. }
  1434. void erase_flash_memory(uint32_t addr, uint32_t size)
  1435. {
  1436. feed_dog();
  1437. rt_enter_critical();
  1438. McuFlash_Unlock();
  1439. McuFlash_EraseSegment(addr, size);
  1440. McuFlash_Lock();
  1441. rt_exit_critical();
  1442. }
  1443. const uint16_t ccitt_table[256] = {
  1444. 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
  1445. 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
  1446. 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
  1447. 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
  1448. 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
  1449. 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
  1450. 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
  1451. 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
  1452. 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
  1453. 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
  1454. 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
  1455. 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
  1456. 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
  1457. 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
  1458. 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
  1459. 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
  1460. 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
  1461. 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
  1462. 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
  1463. 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
  1464. 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
  1465. 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
  1466. 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
  1467. 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
  1468. 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
  1469. 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
  1470. 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
  1471. 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
  1472. 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
  1473. 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
  1474. 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
  1475. 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0};