bill.c 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480
  1. #include "board.h"
  2. #include "bill.h"
  3. #include "prj_com.h"
  4. #include "param.h"
  5. #include "rtc_run.h"
  6. #include "eeprom.h"
  7. #include "wdg_drv.h"
  8. #include "alarm.h"
  9. #include "tdc_tof.h"
  10. bill_run_t BillRun;
  11. CUR_FLOW_INDEX_DEF cum_flow_index;
  12. unsigned char save_cur_flow_flag; //
  13. res_bill_t bak_month_cum_flow;
  14. res_bill_t bak_day_cum_flow;
  15. res_bill_t bak_hour_cum_flow;
  16. bill_5min_ctrl_def bak_5min_cum_flow;
  17. uint8_t StartUp = 0;
  18. uint8_t global_settle_flag = 0;
  19. void bill_init(void)
  20. {
  21. BillRun.fw_use_hour = 0.0f;
  22. BillRun.fw_use_day = 0.0f;
  23. BillRun.fw_use_day = 0.0f;
  24. BillRun.fw_use_five_min = 0.0f;
  25. BillRun.bw_use_hour = 0.0f;
  26. BillRun.bw_use_day = 0.0f;
  27. BillRun.bw_use_month = 0.0f;
  28. BillRun.bw_use_five_min = 0.0f;
  29. BillRun.cum_flow = 0.0f;
  30. BillRun.fw_cum_flow = 0.0f;
  31. BillRun.bw_cum_flow = 0.0f;
  32. init_5min_cur_flow_bill();
  33. init_hour_cur_flow_bill();
  34. init_day_cur_flow_bill();
  35. init_month_cur_flow_bill();
  36. init_cur_flow_bill();
  37. }
  38. uint32_t cal_cur_flow(double cum)
  39. {
  40. uint64_t x = (uint64_t)cum;
  41. return (uint32_t)((x + 5000ULL) / 10000ULL);
  42. }
  43. uint32_t get_month_fw_used_bill(void)
  44. { // 获取月正向流量数据
  45. if (BillRun.fw_cum_flow <= bak_month_cum_flow.fw_cum_flow)
  46. return 0;
  47. else
  48. return cal_cur_flow(BillRun.fw_cum_flow) - cal_cur_flow(bak_month_cum_flow.fw_cum_flow); //
  49. }
  50. uint32_t get_month_bw_used_bill(void)
  51. { // 获取月反向流量
  52. if (BillRun.bw_cum_flow <= bak_month_cum_flow.bw_cum_flow)
  53. return 0;
  54. else
  55. return cal_cur_flow(BillRun.bw_cum_flow) - cal_cur_flow(bak_month_cum_flow.bw_cum_flow);
  56. }
  57. uint32_t get_day_fw_used_bill(void) // 月结和日结都是两位小数点m3 wxl2026-5-6
  58. { // 获取日正向流量数据
  59. if (BillRun.fw_cum_flow <= bak_day_cum_flow.fw_cum_flow)
  60. return 0;
  61. else
  62. return cal_cur_flow(BillRun.fw_cum_flow) - cal_cur_flow(bak_day_cum_flow.fw_cum_flow);
  63. }
  64. uint32_t get_day_bw_used_bill(void)
  65. { // 获取日反向流量
  66. if (BillRun.bw_cum_flow <= bak_day_cum_flow.bw_cum_flow)
  67. return 0;
  68. else
  69. return cal_cur_flow(BillRun.bw_cum_flow) - cal_cur_flow(bak_day_cum_flow.bw_cum_flow);
  70. }
  71. uint32_t get_hour_fw_used_bill(void)
  72. {
  73. // 获取小时正向流量数据
  74. if (BillRun.fw_cum_flow <= bak_hour_cum_flow.fw_cum_flow)
  75. return 0;
  76. else
  77. return (uint32_t)((BillRun.fw_cum_flow - bak_hour_cum_flow.fw_cum_flow) * 0.001);
  78. }
  79. uint32_t get_hour_bw_used_bill(void)
  80. { // 获取小时反向流量数据
  81. if (BillRun.bw_cum_flow <= bak_hour_cum_flow.bw_cum_flow)
  82. return 0;
  83. else
  84. return (uint32_t)((BillRun.bw_cum_flow - bak_hour_cum_flow.bw_cum_flow) * 0.001);
  85. }
  86. uint32_t get_5min_fw_used_bill(void)
  87. { // 获取5min正向流量数据
  88. if (BillRun.fw_cum_flow <= bak_5min_cum_flow.fw_cum_flow)
  89. return 0;
  90. else
  91. return (uint32_t)((BillRun.fw_cum_flow - bak_5min_cum_flow.fw_cum_flow) * 0.001);
  92. }
  93. uint32_t get_5min_bw_used_bill(void)
  94. { // 获取5min反向流量数据
  95. if (BillRun.bw_cum_flow <= bak_5min_cum_flow.bw_cum_flow)
  96. return 0;
  97. else
  98. return (uint32_t)((BillRun.bw_cum_flow - bak_5min_cum_flow.bw_cum_flow) * 0.001);
  99. }
  100. /////////////将瞬时流量转换为要求的比例//////////////////////////
  101. int32_t get_flow_rate_bill(void)
  102. { // 获取瞬时流速
  103. return (int32_t)(BillRun.flow_rate * 0.001 * 3600);
  104. }
  105. //////////////////////对外接口 从采样模块获取瞬时流量到bill 和以前的SetBillVol兼容///////////////////////////////////
  106. // fw_vol:正向瞬时流量
  107. // bw_vol:反向瞬时流量
  108. /////////////////////////////////////////////////////////
  109. void set_flow_rate_bill(double fw_vol, double bw_vol) // 当前月日小时5min累计流量累加
  110. {
  111. BillRun.flow_rate = (fw_vol > 0) ? fw_vol : bw_vol;
  112. }
  113. ///////////////////在采集计算中调用 获取当前流量累计数据当前流量累计值,///////////////////
  114. // 参数cum:绝对流量
  115. // 参数 fw_cum:正向流量
  116. // 参数 bw_cum:反向流量
  117. // 返回:无
  118. ////////////////////////////////////////////
  119. void set_cur_flow_bill(double cum, double fw_cum, double bw_cum)
  120. {
  121. BillRun.cum_flow = fw_cum - bw_cum;
  122. BillRun.fw_cum_flow = fw_cum;
  123. BillRun.bw_cum_flow = bw_cum;
  124. CumFlow = fw_cum - bw_cum;
  125. FwCumFlow = fw_cum;
  126. BwCumFlow = bw_cum;
  127. }
  128. /// 读取当前累计流量到指针参数,本模块对外输出/////////////
  129. void get_cur_flow_bill(double *cum, double *fw_cum, double *bw_cum)
  130. {
  131. *cum = CumFlow;
  132. *fw_cum = FwCumFlow;
  133. *bw_cum = BwCumFlow;
  134. }
  135. ////////////////保存月使用量///////////////////////
  136. /// 参数:年月日
  137. /// 无返回
  138. /////////////////////////////////////////
  139. void set_month_used_bill(uint8_t year, uint8_t month, uint8_t day)
  140. {
  141. uint32_t fw_used;
  142. uint32_t bw_used;
  143. bill_t month_bill;
  144. uint16_t len = sizeof(bill_t);
  145. uint32_t addr = MONTH_BILL_START_ADDR + len * MONTH_BILL_INDEX(year, month);
  146. if (CheckDateValid(year, month, day, 0, 0, 0) == 0)
  147. return;
  148. /////////////////////如果数据已经存在,则在原来的基础上累加////////////////////////////////////////
  149. uint8_t ret;
  150. ret = get_month_used_bill(year, month, &month_bill);
  151. if (ret == 0)
  152. {
  153. fw_used = month_bill.fw_used;
  154. bw_used = month_bill.bw_used;
  155. }
  156. else
  157. {
  158. fw_used = 0;
  159. bw_used = 0;
  160. }
  161. ////////////////////////////////////////////////////////////////////////////////////////////////////////
  162. fw_used += get_month_fw_used_bill();
  163. bw_used += get_month_bw_used_bill();
  164. month_bill.flag = 1;
  165. month_bill.date[0] = year;
  166. month_bill.date[1] = month;
  167. month_bill.date[2] = day;
  168. month_bill.fw_used = fw_used;
  169. month_bill.bw_used = bw_used;
  170. write_eeprom(addr, (uint8_t *)&month_bill, len);
  171. }
  172. /////////////////////保存日使用量////////////////////////////////
  173. // 参数 年月日
  174. ///////////////////////////////////////////////
  175. void set_day_used_bill(uint8_t year, uint8_t month, uint8_t day)
  176. {
  177. uint32_t fw_used;
  178. uint32_t bw_used;
  179. bill_t day_bill;
  180. uint16_t len = sizeof(bill_t);
  181. uint16_t days = days_from_leap_year_begin(month, day);
  182. uint32_t addr = DAY_BILL_START_ADDR + len * (days - 1);
  183. ///////////////////检查日期是否合法/////////////////////////////
  184. if (CheckDateValid(year, month, day, 0, 0, 0) == 0)
  185. return;
  186. ///////////////////检查是否存有相同的记录 有就加上/////////////////////////////
  187. uint8_t ret;
  188. ret = get_day_used_bill(year, month, day, &day_bill);
  189. if (ret == 0) // 数据合法,且年月日都相同
  190. {
  191. fw_used = day_bill.fw_used;
  192. bw_used = day_bill.bw_used;
  193. }
  194. else
  195. {
  196. fw_used = 0;
  197. bw_used = 0;
  198. }
  199. ////////////////////////////////////////////////////////////////////////////////
  200. fw_used += get_day_fw_used_bill();
  201. bw_used += get_day_bw_used_bill();
  202. day_bill.flag = 1;
  203. day_bill.date[0] = year;
  204. day_bill.date[1] = month;
  205. day_bill.date[2] = day;
  206. day_bill.fw_used = fw_used;
  207. day_bill.bw_used = bw_used;
  208. write_eeprom(addr, (uint8_t *)&day_bill, len);
  209. }
  210. ////////////////////保存小时使用量///////////////////////////////////
  211. /// 参数:年月日时
  212. /////////////////////////////////////////////////////////
  213. void set_hour_used_bill(uint8_t year, uint8_t month, uint8_t day, uint8_t hour)
  214. {
  215. uint32_t fw_used;
  216. uint32_t bw_used;
  217. uint32_t fr;
  218. hour_bill_t hour_bill;
  219. uint16_t len = sizeof(hour_bill_t);
  220. uint32_t addr = HOUR_BILL_START_ADDR + HOUR_BILL_INDEX(day, hour) * len;
  221. /////////////////////////////////检查时间是否合法///////////////////////////////////////
  222. if (CheckDateValid(year, month, day, hour, 0, 0) == 0)
  223. return; // 时间不合法
  224. /////////////////////////如果记录中存在相同日期的数据,则累加//////////////////////
  225. uint8_t ret;
  226. ret = get_hour_used_bill(year, month, day, hour, &hour_bill);
  227. if (ret == 0) // 数据合法且日期相同
  228. {
  229. fw_used = hour_bill.fw_used[0] + ((uint32_t)hour_bill.fw_used[1] << 8) + ((uint32_t)hour_bill.fw_used[2] << 16);
  230. bw_used = hour_bill.bw_used[0] + ((uint32_t)hour_bill.bw_used[1] << 8) + ((uint32_t)hour_bill.bw_used[2] << 16);
  231. fr = hour_bill.flow_rate[0] + ((uint32_t)hour_bill.flow_rate[1] << 8) + ((uint32_t)hour_bill.flow_rate[2] << 16);
  232. }
  233. else
  234. {
  235. fw_used = 0;
  236. bw_used = 0;
  237. fr = 0;
  238. }
  239. //////////////////////////////////////////////////////////////////////////////
  240. fw_used += get_hour_fw_used_bill();
  241. bw_used += get_hour_bw_used_bill();
  242. fr = (uint32_t)get_flow_rate_bill() > fr ? (uint32_t)get_flow_rate_bill() : fr;
  243. memset(&hour_bill, 0, sizeof(hour_bill_t));
  244. hour_bill.flag = 1;
  245. hour_bill.date[0] = year;
  246. hour_bill.date[1] = month;
  247. hour_bill.date[2] = day;
  248. hour_bill.date[3] = hour;
  249. hour_bill.fw_used[0] = (uint8_t)(fw_used);
  250. hour_bill.fw_used[1] = (uint8_t)(fw_used >> 8);
  251. hour_bill.fw_used[2] = (uint8_t)(fw_used >> 16);
  252. hour_bill.bw_used[0] = (uint8_t)(bw_used);
  253. hour_bill.bw_used[1] = (uint8_t)(bw_used >> 8);
  254. hour_bill.bw_used[2] = (uint8_t)(bw_used >> 16);
  255. hour_bill.flow_rate[0] = (uint8_t)(fr);
  256. hour_bill.flow_rate[1] = (uint8_t)(fr >> 8);
  257. hour_bill.flow_rate[2] = (uint8_t)(fr >> 16);
  258. if (Paramx.pressure_sensor == 1)
  259. {
  260. hour_bill.pressure = (uint8_t)(WaterPressure * 100);
  261. }
  262. else
  263. {
  264. hour_bill.pressure = 0x00; // 无压力传感器,修改为0
  265. }
  266. write_eeprom(addr, (uint8_t *)&hour_bill, len);
  267. }
  268. /////////////////保存5分钟使用量///////////////////////
  269. // 参数:年月日时分
  270. ///////////////////////////////////////////////
  271. void set_5min_used_bill(uint8_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute)
  272. {
  273. uint32_t fw_used;
  274. uint32_t bw_used;
  275. uint32_t fr;
  276. hour_bill_t bill;
  277. uint16_t len = sizeof(hour_bill_t);
  278. uint32_t addr = FIVE_MIN_BILL_START_ADDR + len * FIVE_MIN_BILL_INDEX(day, hour, minute);
  279. /////////////////////////////////检查时间是否合法///////////////////////////////////////
  280. if (CheckDateValid(year, month, day, hour, minute, 0) == 0)
  281. return;
  282. ////////////////////////////////////////////////////////////////////////////////////////
  283. uint8_t ret;
  284. ret = get_5min_used_bill(year, month, day, hour, minute, &bill);
  285. if (ret == 0)
  286. {
  287. fw_used = bill.fw_used[0] + ((uint32_t)bill.fw_used[1] << 8) + ((uint32_t)bill.fw_used[2] << 16);
  288. bw_used = bill.bw_used[0] + ((uint32_t)bill.bw_used[1] << 8) + ((uint32_t)bill.bw_used[2] << 16);
  289. fr = bill.flow_rate[0] + ((uint32_t)bill.flow_rate[1] << 8) + ((uint32_t)bill.flow_rate[2] << 16);
  290. }
  291. else
  292. {
  293. fw_used = 0;
  294. bw_used = 0;
  295. fr = 0;
  296. }
  297. ////////////////////////////////////////////////////////////////////////////////////////
  298. fw_used += get_5min_fw_used_bill();
  299. bw_used += get_5min_bw_used_bill();
  300. fr = (uint32_t)get_flow_rate_bill() > fr ? (uint32_t)get_flow_rate_bill() : fr;
  301. ////////////////////////////////////////////////////////////////////////////////////////
  302. bill.date[0] = year;
  303. bill.flag = 1;
  304. bill.date[0] = year;
  305. bill.date[1] = month; // num保存该小时内第几个5分钟数据
  306. bill.date[2] = day;
  307. bill.date[3] = hour;
  308. bill.fw_used[0] = (uint8_t)(fw_used);
  309. bill.fw_used[1] = (uint8_t)(fw_used >> 8);
  310. bill.fw_used[2] = (uint8_t)(fw_used >> 16);
  311. bill.bw_used[0] = (uint8_t)(bw_used);
  312. bill.bw_used[1] = (uint8_t)(bw_used >> 8);
  313. bill.bw_used[2] = (uint8_t)(bw_used >> 16);
  314. bill.flow_rate[0] = (uint8_t)(fr);
  315. bill.flow_rate[1] = (uint8_t)(fr >> 8);
  316. bill.flow_rate[2] = (uint8_t)(fr >> 16);
  317. if (Paramx.pressure_sensor == 1)
  318. {
  319. bill.pressure = (uint8_t)(WaterPressure * 100);
  320. }
  321. else
  322. {
  323. bill.pressure = 0x0; // 无压力传感器 ,修改为0x0
  324. }
  325. write_eeprom(addr, (uint8_t *)&bill, len);
  326. }
  327. /////////////////////////保存当前累计流量数据和时间,防止意外丢失///////////////////////////////
  328. // 无参数
  329. // 无返回值
  330. // 256点循环保存,最快10秒一次, 最慢5分钟一次
  331. ///////////////////////////////////////////////////////////////////////
  332. uint8_t save_5min_trik_flag = 0;
  333. void save_cur_flow_bill(void)
  334. {
  335. rtc_run_t *rr;
  336. bill_cum_flow_tx bill;
  337. if (global_settle_flag == 1) // 结算中,只有结算完成才保存新的底读
  338. return;
  339. get_rtc_run(&rr); // 获取当前时间
  340. if (rr->minute % 5 == 0)
  341. {
  342. save_5min_trik_flag++;
  343. }
  344. else
  345. {
  346. save_5min_trik_flag = 0;
  347. }
  348. if ((save_5min_trik_flag == 1) || ((BillRun.fw_cum_flow != cum_flow_index.fw || BillRun.bw_cum_flow != cum_flow_index.bw) && rr->second /*% 10*/ == 0) || save_cur_flow_flag == 1)
  349. { // 整5分钟或流量值发生变化
  350. }
  351. else
  352. return;
  353. save_cur_flow_flag = 0;
  354. memset(&bill, 0, sizeof(bill_cum_flow_tx)); // 初始化0
  355. bill.flag = 1;
  356. bill.date_time[0] = rr->year;
  357. bill.date_time[1] = rr->month;
  358. bill.date_time[2] = rr->day;
  359. bill.date_time[3] = rr->hour;
  360. bill.date_time[4] = rr->minute;
  361. bill.date_time[5] = rr->second;
  362. bill.date_time[6] = rr->week;
  363. bill.fw_cum_flow = BillRun.fw_cum_flow;
  364. bill.bw_cum_flow = BillRun.bw_cum_flow;
  365. cum_flow_index.fw = BillRun.fw_cum_flow;
  366. cum_flow_index.bw = BillRun.bw_cum_flow;
  367. bill.gcnt = cum_flow_index.cur_gcnt; // 保存当前累计序列值 long型有符号,用于读取时,找到最近一条记录的条件, 最大值为最新记录
  368. cum_flow_index.cur_gcnt++; // 累加当前序列,作为下次保存时使用
  369. cum_flow_index.npos %= MAX_CUM_FLOW_NUM;
  370. write_eeprom(CUM_FLOW_START_ADDR + cum_flow_index.npos * CUM_FLOW_SIZE, (uint8_t *)&bill, sizeof(bill_cum_flow_tx)); // 写锟斤拷锟斤拷锟斤拷
  371. cum_flow_index.npos++; // 存储位置后移
  372. cum_flow_index.npos %= MAX_CUM_FLOW_NUM; // 循环存储
  373. #ifdef DEBUG_BILL
  374. LOG("save_time %d-%d-%d %d:%d:%d fw = %f,bw = %f gcnt= %d, npos = %d\r\n", rr->year, rr->month, rr->day, rr->hour, rr->minute, rr->second, cum_flow_index.fw, cum_flow_index.bw, cum_flow_index.cur_gcnt, cum_flow_index.npos);
  375. #endif
  376. }
  377. ///////////////读取指定时间的月使用量///////////////////////////
  378. uint8_t get_month_used_bill(uint8_t year, uint8_t month, bill_t *bill)
  379. {
  380. memset(bill, 0, sizeof(bill_t));
  381. uint16_t len = sizeof(bill_t);
  382. uint32_t addr = MONTH_BILL_START_ADDR + len * MONTH_BILL_INDEX(year, month);
  383. uint8_t ret;
  384. ret = read_eeprom(addr, (uint8_t *)bill, len);
  385. if (ret != 0)
  386. return ret;
  387. if (bill->date[0] != year || bill->date[1] != month) // 读取的月份和日期不匹配
  388. {
  389. // memset(bill, 0, sizeof(bill_t));
  390. return 1;
  391. }
  392. return 0;
  393. }
  394. uint16_t get_days_from_year(uint8_t year, uint8_t month, uint8_t day)
  395. {
  396. uint16_t days = 0;
  397. uint8_t i;
  398. if (month == 0 || day == 0)
  399. return 0;
  400. for (i = 0; i < month - 1; i++)
  401. {
  402. days += monthday[i];
  403. if (i == 1 && year % 4 == 0)
  404. days++;
  405. }
  406. days = days + day - 1;
  407. return days;
  408. }
  409. /*
  410. int32_t get_days_between_now(uint8_t byear, uint8_t bmonth, uint8_t bday)
  411. {
  412. rtc_run_t *rr;
  413. get_rtc_run(&rr);
  414. int32_t adays, bdays;
  415. adays = rr->year * 366 + get_days_from_year(rr->year, rr->month, rr->day);
  416. bdays = byear * 366 + get_days_from_year(byear, bmonth, bday);
  417. return adays - bdays;
  418. } */
  419. int32_t get_days_between_now(uint8_t y2, uint8_t m2, uint8_t d2)
  420. {
  421. uint16_t i;
  422. uint32_t days1 = 0, days2 = 0;
  423. uint8_t monthDays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
  424. rtc_run_t *rr;
  425. get_rtc_run(&rr);
  426. uint8_t y1 = rr->year;
  427. uint8_t m1 = rr->month;
  428. uint8_t d1 = rr->day;
  429. // 计算日期1总天数
  430. for (i = 1; i < y1; i++)
  431. {
  432. if ((i % 4 == 0 && i % 100 != 0) || (i % 400 == 0))
  433. days1 += 366;
  434. else
  435. days1 += 365;
  436. }
  437. for (i = 1; i < m1; i++)
  438. {
  439. days1 += monthDays[i - 1];
  440. if (i == 2 && ((y1 % 4 == 0 && y1 % 100 != 0) || (y1 % 400 == 0)))
  441. days1++;
  442. }
  443. days1 += d1;
  444. // 日期1 - 日期2,自动产生正负
  445. for (i = 1; i < y2; i++)
  446. {
  447. if ((i % 4 == 0 && i % 100 != 0) || (i % 400 == 0))
  448. days2 += 366;
  449. else
  450. days2 += 365;
  451. }
  452. for (i = 1; i < m2; i++)
  453. {
  454. days2 += monthDays[i - 1];
  455. if (i == 2 && ((y2 % 4 == 0 && y2 % 100 != 0) || (y2 % 400 == 0)))
  456. days2++;
  457. }
  458. days2 += d2;
  459. // 日期1 - 日期2,自动产生正负
  460. return days1 - days2;
  461. }
  462. //////////////////读取指定时间的日使用量//////////////////////////
  463. uint8_t get_day_used_bill(uint8_t year, uint8_t month, uint8_t day, bill_t *bill)
  464. {
  465. uint16_t days = days_from_leap_year_begin(month, day);
  466. uint16_t len = sizeof(bill_t); // 16
  467. uint32_t addr = DAY_BILL_START_ADDR + len * (days - 1);
  468. #ifdef DEBUG_BILL2
  469. LOG("%d-%d\r\n", month, day);
  470. #endif
  471. memset(bill, 0, sizeof(bill_t));
  472. uint8_t ret = read_eeprom(addr, (uint8_t *)bill, len);
  473. if (ret != 0)
  474. return ret;
  475. if (bill->date[0] != year || bill->date[1] != month || bill->date[2] != day)
  476. return 1;
  477. return 0;
  478. }
  479. int32_t get_hours_between_now(uint8_t year, uint8_t month, uint8_t day, uint8_t hour)
  480. {
  481. int32_t hours;
  482. hours = 24 * get_days_between_now(year, month, day);
  483. rtc_run_t *rr;
  484. get_rtc_run(&rr);
  485. hours += (signed char)(rr->hour - hour);
  486. return hours;
  487. }
  488. ///////////////读取指定时间的小时使用量//////////////////////////
  489. uint8_t get_hour_used_bill(uint8_t year, uint8_t month, uint8_t day, uint8_t hour, hour_bill_t *bill)
  490. {
  491. uint16_t len = sizeof(hour_bill_t);
  492. uint32_t addr = HOUR_BILL_START_ADDR + HOUR_BILL_INDEX(day, hour) * len;
  493. memset(bill, 0, sizeof(hour_bill_t));
  494. // int32_t hours = get_hours_between_now(year,month,day,hour);
  495. // if(hours <= 0 || hours > 31 * 24)return 0;
  496. uint8_t ret;
  497. ret = read_eeprom(addr, (uint8_t *)bill, len);
  498. if (ret != 0)
  499. return ret;
  500. if (bill->date[0] != year || bill->date[1] != month || bill->date[2] != day || bill->date[3] != hour)
  501. return 1;
  502. return 0;
  503. }
  504. //////////////////读取指定时间的5分钟使用量////////////////////////////
  505. uint8_t get_5min_used_bill(uint8_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, hour_bill_t *bill)
  506. {
  507. uint16_t len = sizeof(hour_bill_t);
  508. uint32_t addr = FIVE_MIN_BILL_START_ADDR + len * FIVE_MIN_BILL_INDEX(day, hour, minute);
  509. memset(bill, 0, sizeof(hour_bill_t));
  510. uint8_t ret;
  511. ret = read_eeprom(addr, (uint8_t *)bill, len);
  512. if (ret != 0)
  513. return ret;
  514. if (bill->date[0] != year || bill->date[1] != month || bill->date[2] != day || bill->date[3] != hour)
  515. return 1;
  516. return 0;
  517. }
  518. ////////////数据累加和校验生成///////////////////////
  519. // 参数1:dat 指向数据指针
  520. // 参数2:len数据长度
  521. // 返回:单字节校验和
  522. /////////////////////////////////////////////////////
  523. uint8_t Sum8(uint8_t *dat, uint16_t len)
  524. {
  525. uint8_t sum = 0;
  526. while (len--)
  527. {
  528. sum += dat[len]; // 单字节累加
  529. }
  530. return sum; // 返回校验值
  531. }
  532. ///////////// 检查时间日期是否合法/////////////////////////
  533. // 参数:时间字符串 依次是年月日时分秒周
  534. // 异常:返回0 正常:返回1
  535. /////////////////////////////////////
  536. uint8_t CheckTime(uint8_t *date)
  537. {
  538. if (date[1] == 0 || date[1] > 12)
  539. return 0; // 月
  540. if (date[2] == 0 || date[2] > 31)
  541. return 0; // 日
  542. if (date[3] > 23)
  543. return 0; // 时
  544. if (date[4] > 59)
  545. return 0; // 分
  546. if (date[5] > 59)
  547. return 0; // 秒
  548. return 1;
  549. }
  550. /////////////////备用看门狗喂狗////////////////////////////////////
  551. void dog(void)
  552. {
  553. #ifdef APP_USING_SWDG
  554. WDG_Feed();
  555. #endif
  556. }
  557. ///////////////////上电初始化后读取当前流量值为累计初始流量///////////////////////////////////
  558. // 无参数
  559. // 无返回
  560. ////////////////////////////////////////////////////////////////////////////////
  561. void init_cur_flow_bill(void)
  562. {
  563. tm_t tm;
  564. cum_flow_index.cur_gcnt = 0; // 当前累计计数值 用于判断是否最新的记录,最大值为最新记录long型
  565. cum_flow_index.npos = 0; // 当前存储位置,用于写入时的地址寻址
  566. uint16_t i;
  567. uint8_t check;
  568. bill_cum_flow_tx cur_bill;
  569. for (i = 0; i < MAX_CUM_FLOW_NUM; i++)
  570. {
  571. read_eeprom(CUM_FLOW_START_ADDR + i * CUM_FLOW_SIZE, (uint8_t *)&cur_bill, sizeof(bill_cum_flow_tx)); // 依次读取每个记录
  572. if (cur_bill.flag == 1 // 有效标志 1:有效,其他无效
  573. && cur_bill.gcnt >= 0 // 计数器在正常范围内(long型 >0有效)
  574. && CheckTime(cur_bill.date_time) == 1)
  575. { // 时间有效
  576. if (cur_bill.gcnt >= cum_flow_index.cur_gcnt)
  577. {
  578. cum_flow_index.cur_gcnt = cur_bill.gcnt + 1; // 下一个要写入的序列号
  579. cum_flow_index.npos = ((i + 1) % MAX_CUM_FLOW_NUM); // 下一个要写入的相对地址
  580. cum_flow_index.fw = cur_bill.fw_cum_flow;
  581. cum_flow_index.bw = cur_bill.bw_cum_flow;
  582. tm.year = cur_bill.date_time[0];
  583. tm.month = cur_bill.date_time[1];
  584. tm.day = cur_bill.date_time[2];
  585. tm.hour = cur_bill.date_time[3];
  586. tm.min = cur_bill.date_time[4];
  587. tm.sec = cur_bill.date_time[5];
  588. }
  589. }
  590. feed_dog(); // 看门狗 防止复位
  591. }
  592. SetBillCumFlow(cum_flow_index.fw - cum_flow_index.bw, cum_flow_index.fw, cum_flow_index.bw); // 初始化当前流量数据
  593. CumFlow = cum_flow_index.fw - cum_flow_index.bw;
  594. FwCumFlow = cum_flow_index.fw;
  595. BwCumFlow = cum_flow_index.bw;
  596. #ifdef DEBUG_BILL
  597. LOG("init_cum_flow fw=%f,bw=%f,gcnt=%d, add=%d\r\n", cum_flow_index.fw, cum_flow_index.bw, cum_flow_index.cur_gcnt, cum_flow_index.npos);
  598. #endif
  599. // 初始化时间日期
  600. SetRtcTime(&tm);
  601. }
  602. //////////////////保存当前月存储时累积量/////////////////////////
  603. void set_month_cur_flow_bill(void)
  604. { // 只输入fw_cum_flow和bw_cum_flow
  605. rtc_run_t *rr;
  606. get_rtc_run(&rr); // 获取当前时间
  607. bak_month_cum_flow.date[0] = rr->year;
  608. bak_month_cum_flow.date[1] = rr->month;
  609. bak_month_cum_flow.date[2] = rr->day;
  610. bak_month_cum_flow.date[3] = rr->hour;
  611. bak_month_cum_flow.date[4] = rr->minute;
  612. bak_month_cum_flow.date[5] = rr->second;
  613. bak_month_cum_flow.flag = 1;
  614. // if (bak_month_cum_flow.bw_cum_flow == BillRun.bw_cum_flow && bak_month_cum_flow.fw_cum_flow == BillRun.fw_cum_flow)
  615. // return; // 无变化,不保存
  616. bak_month_cum_flow.fw_cum_flow = BillRun.fw_cum_flow;
  617. bak_month_cum_flow.bw_cum_flow = BillRun.bw_cum_flow;
  618. uint32_t addr = PRE_MONTH_COW_BAK_ADDR;
  619. write_eeprom(addr, (uint8_t *)&bak_month_cum_flow, sizeof(res_bill_t));
  620. }
  621. //////////////上电初始化时,读取上次保存的月累积量,作为下次参考/////////////////////////////////////
  622. void init_month_cur_flow_bill(void)
  623. { // 只输入fw_cum_flow和bw_cum_flow
  624. uint32_t addr = PRE_MONTH_COW_BAK_ADDR;
  625. res_bill_t bill;
  626. memset(&bak_month_cum_flow, 0, sizeof(res_bill_t));
  627. read_eeprom(addr, (uint8_t *)&bill, sizeof(res_bill_t));
  628. if (bill.flag == 1)
  629. {
  630. bak_month_cum_flow = bill;
  631. }
  632. }
  633. //////////////////////保存当前日存储的累计量//////////////////////////////////
  634. void set_day_cur_flow_bill(void)
  635. {
  636. rtc_run_t *rr;
  637. get_rtc_run(&rr); // 获取当前时间
  638. bak_day_cum_flow.date[0] = rr->year;
  639. bak_day_cum_flow.date[1] = rr->month;
  640. bak_day_cum_flow.date[2] = rr->day;
  641. bak_day_cum_flow.date[3] = rr->hour;
  642. bak_day_cum_flow.date[4] = rr->minute;
  643. bak_day_cum_flow.date[5] = rr->second;
  644. bak_day_cum_flow.flag = 1;
  645. // if (bak_day_cum_flow.bw_cum_flow == BillRun.bw_cum_flow && bak_day_cum_flow.fw_cum_flow == BillRun.fw_cum_flow)
  646. // return; // 无变化,不保存
  647. bak_day_cum_flow.fw_cum_flow = BillRun.fw_cum_flow;
  648. bak_day_cum_flow.bw_cum_flow = BillRun.bw_cum_flow;
  649. uint32_t addr = PRE_DAY_COW_BAK_ADDR;
  650. write_eeprom(addr, (uint8_t *)&bak_day_cum_flow, sizeof(res_bill_t));
  651. }
  652. ////////////////////上电初始化上次日存储的累积量//////////////////
  653. void init_day_cur_flow_bill(void)
  654. { // 只输入fw_cum_flow和bw_cum_flow
  655. uint32_t addr = PRE_DAY_COW_BAK_ADDR;
  656. res_bill_t bill;
  657. memset(&bak_day_cum_flow, 0, sizeof(res_bill_t));
  658. read_eeprom(addr, (uint8_t *)&bill, sizeof(res_bill_t));
  659. if (bill.flag == 1)
  660. {
  661. bak_day_cum_flow = bill;
  662. }
  663. }
  664. /////////////////////保存当前小时累积量///////////////////////////
  665. void set_hour_cur_flow_bill(void)
  666. { // 只输入fw_cum_flow和bw_cum_flow
  667. rtc_run_t *rr;
  668. get_rtc_run(&rr); // 获取当前时间
  669. bak_hour_cum_flow.date[0] = rr->year;
  670. bak_hour_cum_flow.date[1] = rr->month;
  671. bak_hour_cum_flow.date[2] = rr->day;
  672. bak_hour_cum_flow.date[3] = rr->hour;
  673. bak_hour_cum_flow.date[4] = rr->minute;
  674. bak_hour_cum_flow.date[5] = rr->second;
  675. // if (bak_hour_cum_flow.bw_cum_flow == BillRun.bw_cum_flow && bak_hour_cum_flow.fw_cum_flow == BillRun.fw_cum_flow)
  676. // return; // 无变化,不保存
  677. bak_hour_cum_flow.flag = 1;
  678. bak_hour_cum_flow.fw_cum_flow = BillRun.fw_cum_flow;
  679. bak_hour_cum_flow.bw_cum_flow = BillRun.bw_cum_flow;
  680. uint32_t addr = PRE_HOUR_COW_BAK_ADDR;
  681. write_eeprom(addr, (uint8_t *)&bak_hour_cum_flow, sizeof(res_bill_t));
  682. }
  683. ///////////////上电初始化上次小时累积量//////////////////
  684. void init_hour_cur_flow_bill(void)
  685. { // 只输入fw_cum_flow和bw_cum_flow
  686. uint32_t addr = PRE_HOUR_COW_BAK_ADDR;
  687. res_bill_t bill;
  688. memset(&bak_hour_cum_flow, 0, sizeof(res_bill_t));
  689. read_eeprom(addr, (uint8_t *)&bill, sizeof(res_bill_t));
  690. if (bill.flag == 1)
  691. {
  692. bak_hour_cum_flow = bill;
  693. }
  694. }
  695. void set_5min_cur_flow_bill(void)
  696. {
  697. // 1. 获取当前时间
  698. rtc_run_t *rr;
  699. get_rtc_run(&rr);
  700. // 2. 判断数据是否有变化 (可选:如果时间变了但流量没变,是否也要保存?通常流量计费以流量变化或时间周期为准)
  701. // 原逻辑仅比较流量,这里保持原逻辑,但注意:如果仅靠流量变化触发,可能会丢失纯时间流逝的记录。
  702. // 建议结合 app_bill_run 中的时间判断逻辑,确保每5分钟强制调用一次。
  703. bak_5min_cum_flow.date[0] = rr->year;
  704. bak_5min_cum_flow.date[1] = rr->month;
  705. bak_5min_cum_flow.date[2] = rr->day;
  706. bak_5min_cum_flow.date[3] = rr->hour;
  707. bak_5min_cum_flow.date[4] = rr->minute;
  708. bak_5min_cum_flow.date[5] = rr->second;
  709. // if (bak_5min_cum_flow.bw_cum_flow == BillRun.bw_cum_flow && bak_5min_cum_flow.fw_cum_flow == BillRun.fw_cum_flow)
  710. // {
  711. // return;
  712. // }
  713. // 3. 更新内存中的备份控制块的时间字段 (假设 bill_5min_ctrl_def 中有 date 字段,如果没有,需添加)
  714. // 注意:原代码 bak_5min_cum_flow 是 bill_5min_ctrl_def 类型
  715. // 如果该结构体没有 date 字段,建议添加 uint8_t date[6]; 以便快速比对
  716. bak_5min_cum_flow.bw_cum_flow = BillRun.bw_cum_flow;
  717. bak_5min_cum_flow.fw_cum_flow = BillRun.fw_cum_flow;
  718. // 4. 准备写入 EEPROM 的结构体
  719. uint32_t addr = PRE_5MIN_COW_BAK_ADDR + bak_5min_cum_flow.add_cnt * BAK_5MIN_SIZE;
  720. bak_5min_bill_t bill;
  721. memset(&bill, 0, sizeof(bak_5min_bill_t));
  722. bill.flag = 1;
  723. bill.global_cnt = bak_5min_cum_flow.global_cnt;
  724. bill.fw_cum_flow = BillRun.fw_cum_flow;
  725. bill.bw_cum_flow = BillRun.bw_cum_flow;
  726. write_eeprom(addr, (uint8_t *)&bill, sizeof(bak_5min_bill_t));
  727. // 5. 更新索引和计数器
  728. bak_5min_cum_flow.add_cnt++;
  729. bak_5min_cum_flow.add_cnt %= BAK_5MIN_NUM;
  730. bak_5min_cum_flow.global_cnt++;
  731. }
  732. void init_5min_cur_flow_bill(void)
  733. {
  734. uint32_t addr = PRE_5MIN_COW_BAK_ADDR;
  735. uint8_t i;
  736. int32_t gcnt = -1;
  737. bak_5min_bill_t bill;
  738. // 初始化内存控制块
  739. memset(&bak_5min_cum_flow, 0, sizeof(bill_5min_ctrl_def));
  740. memset(&bill, 0, sizeof(bak_5min_bill_t));
  741. for (i = 0; i < BAK_5MIN_NUM; i++)
  742. {
  743. // 读取 EEPROM
  744. read_eeprom(addr + i * BAK_5MIN_SIZE, (uint8_t *)&bill, sizeof(bak_5min_bill_t));
  745. // 检查标志位
  746. if (bill.flag == 1)
  747. {
  748. if (bill.global_cnt > gcnt)
  749. {
  750. // 恢复累积流量
  751. bak_5min_cum_flow.fw_cum_flow = bill.fw_cum_flow;
  752. bak_5min_cum_flow.bw_cum_flow = bill.bw_cum_flow;
  753. gcnt = bill.global_cnt;
  754. // 计算下一个写入位置
  755. bak_5min_cum_flow.add_cnt = i + 1;
  756. bak_5min_cum_flow.add_cnt %= BAK_5MIN_NUM;
  757. // 更新全局计数器
  758. bak_5min_cum_flow.global_cnt = gcnt + 1;
  759. }
  760. }
  761. }
  762. // 如果没有找到有效记录,使用当前系统时间和流量初始化
  763. if (gcnt == -1)
  764. {
  765. rtc_run_t *rr;
  766. get_rtc_run(&rr);
  767. bak_5min_cum_flow.fw_cum_flow = BillRun.fw_cum_flow;
  768. bak_5min_cum_flow.bw_cum_flow = BillRun.bw_cum_flow;
  769. bak_5min_cum_flow.add_cnt = 0;
  770. bak_5min_cum_flow.global_cnt = 0;
  771. }
  772. }
  773. //////////////////////获取当前时间到结构体tm_t指针////////////////////////
  774. void get_now_time(tm_t *tm)
  775. {
  776. rtc_run_t *rr;
  777. get_rtc_run(&rr);
  778. tm->year = rr->year;
  779. tm->month = rr->month;
  780. tm->day = rr->day;
  781. tm->hour = rr->hour;
  782. tm->min = rr->minute;
  783. tm->sec = rr->second;
  784. }
  785. ///////////////////////////获取上一个小时的时间/////////////////////////////////////////////////
  786. // 参数:tm_t指针
  787. // 返回:上一个小时的时间
  788. /////////////////////////////////////////////////////////////
  789. tm_t prev_hour(tm_t *date)
  790. {
  791. tm_t ndate = *date;
  792. if (ndate.hour != 0)
  793. {
  794. ndate.hour--;
  795. return ndate;
  796. }
  797. ndate.hour = 23;
  798. uint32_t sdate = prev_day((ndate.year << 16) + (ndate.month << 8) + ndate.day);
  799. ndate.day = (uint8_t)sdate;
  800. ndate.month = (uint8_t)(sdate >> 8);
  801. ndate.year = (uint8_t)(sdate >> 16);
  802. return ndate;
  803. }
  804. /**
  805. * 获取当前流量数据并更新账单信息
  806. * @param ntm 指向时间结构体的指针,包含年、月、日、时、分等信息
  807. */
  808. void get_cur_flow_data(tm_t *ntm)
  809. {
  810. if (global_settle_flag != 0) // 在设置更新的底读之前,先进行结算
  811. {
  812. global_settle_flag = 0;
  813. set_month_used_bill(ntm->year, ntm->month, ntm->day); // 设置月度已用账单
  814. set_day_used_bill(ntm->year, ntm->month, ntm->day); // 设置日度已用账单
  815. set_hour_used_bill(ntm->year, ntm->month, ntm->day, ntm->hour); // 设置小时已用账单
  816. set_5min_used_bill(ntm->year, ntm->month, ntm->day, ntm->hour, ntm->min); // 设置5分钟已用账单
  817. BillRun.fw_cum_flow = FwCumFlow; // 设置正向累计流量
  818. BillRun.bw_cum_flow = BwCumFlow;
  819. BillRun.flow_rate = FlowVol;
  820. set_month_cur_flow_bill();
  821. set_day_cur_flow_bill();
  822. set_hour_cur_flow_bill();
  823. set_5min_cur_flow_bill();
  824. }
  825. else
  826. {
  827. BillRun.fw_cum_flow = FwCumFlow;
  828. BillRun.bw_cum_flow = BwCumFlow;
  829. BillRun.flow_rate = FlowVol;
  830. }
  831. }
  832. void app_bill_run(void)
  833. {
  834. //
  835. #ifdef DEBUG_BILL
  836. // Debug_bill();
  837. /* if (StartUp == 5)
  838. {
  839. clear_all_record();
  840. clear_log();
  841. verify_clear_operations();
  842. while (1)
  843. ;
  844. } */
  845. #endif
  846. #ifdef DEBUG_LOG_WARM
  847. if (StartUp == 5)
  848. Debug_log();
  849. #endif
  850. if (StartUp < 250)
  851. StartUp++;
  852. if (StartUp < 5)
  853. return;
  854. tm_t ntm;
  855. uint32_t ndate;
  856. // 1. 获取当前时间,作为所有判断的基准
  857. get_now_time(&ntm);
  858. // 获取当前流量数据,用于计算差值
  859. get_cur_flow_data(&ntm);
  860. ////////////////////////////////// 月使用量记录 //////////////////////////////////
  861. // 判断依据:当前时间的年或月 与 备份的年月不一致
  862. if (bak_month_cum_flow.date[0] != ntm.year || bak_month_cum_flow.date[1] != ntm.month)
  863. {
  864. // 计算上个月的最后一天
  865. // ndate = (ntm.year << 16) | (ntm.month << 8) | 1; // 当前月1号
  866. // ndate = prev_day(ndate); // 回退一天,即上个月最后一天
  867. set_month_used_bill(bak_month_cum_flow.date[0], bak_month_cum_flow.date[1], bak_month_cum_flow.date[2]);
  868. // 使用备份的日期进行存储,无论是自然过度到第二月还是修改日期到新的月份,数据始终保存到老月份去
  869. // 更新备份:将当前累积流量保存为新的月度起始基准
  870. set_month_cur_flow_bill();
  871. #ifdef DEBUG_BILL
  872. LOG("%d-%d-%d write month bill\r\n", (uint8_t)(ndate >> 16), (uint8_t)(ndate >> 8), (uint8_t)(ndate));
  873. #endif
  874. }
  875. ////////////////////////////// 日使用量记录 ////////////////////////////////////////
  876. // 判断依据:当前时间的年月日 与 备份的年月日不一致
  877. // 注意:这里必须使用原始的 ntm,不能受下方小时逻辑影响
  878. if (bak_day_cum_flow.date[0] != ntm.year || bak_day_cum_flow.date[1] != ntm.month || bak_day_cum_flow.date[2] != ntm.day)
  879. {
  880. // 计算昨天
  881. // ndate = (ntm.year << 16) | (ntm.month << 8) | ntm.day;
  882. // ndate = prev_day(ndate);
  883. // 存储昨天的使用量
  884. // if ((uint8_t)(ndate >> 16) == bak_day_cum_flow.date[0] && (uint8_t)(ndate >> 8) == bak_day_cum_flow.date[1] && (uint8_t)(ndate) == bak_day_cum_flow.date[2])
  885. // if (ndate >= ((bak_day_cum_flow.date[0] << 16) | (bak_day_cum_flow.date[1] << 8) | bak_day_cum_flow.date[2]))
  886. //{ // 结算日期必须大于等于备份日期, 否则只更新基准,不记录使用量
  887. set_day_used_bill(bak_day_cum_flow.date[0], bak_day_cum_flow.date[1], bak_day_cum_flow.date[2]);
  888. //}
  889. // 更新备份:将当前累积流量保存为新的日度起始基准
  890. set_day_cur_flow_bill();
  891. #ifdef DEBUG_BILL
  892. LOG("%d-%d-%d write day bill\r\n", (uint8_t)(ndate >> 16), (uint8_t)(ndate >> 8), (uint8_t)(ndate));
  893. #endif
  894. }
  895. /////////////////////////////// 小时使用量记录 /////////////////////////////////////
  896. // 判断依据:当前时间的年月日时 与 备份的年月日时不一致
  897. if (bak_hour_cum_flow.date[0] != ntm.year || bak_hour_cum_flow.date[1] != ntm.month ||
  898. bak_hour_cum_flow.date[2] != ntm.day || bak_hour_cum_flow.date[3] != ntm.hour)
  899. {
  900. // tm_t prev_h_tm;
  901. // 计算上一个小时的时间,用于存入记录的数据头(表示该小时结束的时间点或归属)
  902. // 注意:不要直接修改 ntm,而是使用临时变量
  903. // prev_h_tm = ntm;
  904. // if (prev_h_tm.hour == 0)
  905. // {
  906. // // 如果当前是0点,上一个小时是昨天的23点
  907. // uint32_t prev_day_date = (prev_h_tm.year << 16) | (prev_h_tm.month << 8) | prev_h_tm.day;
  908. // prev_day_date = prev_day(prev_day_date);
  909. // prev_h_tm.year = (uint8_t)(prev_day_date >> 16);
  910. // prev_h_tm.month = (uint8_t)(prev_day_date >> 8);
  911. // prev_h_tm.day = (uint8_t)(prev_day_date);
  912. // prev_h_tm.hour = 23;
  913. // }
  914. // else
  915. // {
  916. // prev_h_tm.hour--;
  917. // }
  918. // 存储上一个小时的使用量
  919. // uint32_t baklong = ((bak_hour_cum_flow.date[0] << 24) | (bak_hour_cum_flow.date[1] << 16) | (bak_hour_cum_flow.date[2] << 8) | (bak_hour_cum_flow.date[3]));
  920. // uint32_t prevlong = ((prev_h_tm.year << 24) | (prev_h_tm.month << 16) | (prev_h_tm.day << 8) | (prev_h_tm.hour));
  921. // if (bak_hour_cum_flow.date[0] == prev_h_tm.year && bak_hour_cum_flow.date[1] == prev_h_tm.month && bak_hour_cum_flow.date[2] == prev_h_tm.day && bak_hour_cum_flow.date[3] == prev_h_tm.hour)
  922. // if (baklong <= prevlong)
  923. //{ // 备份的时间必须早于当前时间的上一个小时,才记录时结数据
  924. set_hour_used_bill(bak_hour_cum_flow.date[0], bak_hour_cum_flow.date[1], bak_hour_cum_flow.date[2], bak_hour_cum_flow.date[3]);
  925. //}
  926. // 更新备份:将当前累积流量保存为新的小时起始基准
  927. set_hour_cur_flow_bill();
  928. // #ifdef DEBUG_BILL
  929. // LOG("%d-%d-%d %d write hour bill\r\n", prev_h_tm.year, prev_h_tm.month, prev_h_tm.day, prev_h_tm.hour);
  930. // #endif
  931. }
  932. ////////////////////////////// 5min使用量记录 /////////////////////////////////////
  933. if (bak_5min_cum_flow.date[0] != ntm.year || bak_5min_cum_flow.date[1] != ntm.month ||
  934. bak_5min_cum_flow.date[2] != ntm.day || bak_5min_cum_flow.date[3] != ntm.hour ||
  935. bak_5min_cum_flow.date[4] / 5 != ntm.min / 5)
  936. {
  937. // tm_t bak_t;
  938. // bak_t.year = bak_5min_cum_flow.date[0];
  939. // bak_t.month = bak_5min_cum_flow.date[1];
  940. // bak_t.day = bak_5min_cum_flow.date[2];
  941. // bak_t.hour = bak_5min_cum_flow.date[3];
  942. // bak_t.min = bak_5min_cum_flow.date[4];
  943. // tm_t prev_5min_tm = get_prev_5min_tm(bak_t);
  944. // if (datecmp(bak_t, ntm) < 0) // 备份时间小于当前时间,则记录使用量
  945. //{
  946. set_5min_used_bill(bak_5min_cum_flow.date[0], bak_5min_cum_flow.date[1], bak_5min_cum_flow.date[2], bak_5min_cum_flow.date[3], bak_5min_cum_flow.date[4]);
  947. //}
  948. set_5min_cur_flow_bill();
  949. #ifdef DEBUG_BILL
  950. LOG("%d-%d-%d %d:%d write 5min bill\r\n", ntm.year, ntm.month, ntm.day, ntm.hour, ntm.min);
  951. #endif
  952. }
  953. save_cur_flow_bill();
  954. }
  955. #ifdef DEBUG_BILL
  956. /////////////调试bill各种计量用/////////////////
  957. unsigned short dbg_bill_cnt = 0;
  958. double debug_fw = 0, debug_bw = 0, debug_vol, debug_w;
  959. void Debug_bill(void)
  960. {
  961. dbg_bill_cnt++;
  962. /////////模拟计量/////////////
  963. get_cur_flow_bill(&debug_w, &debug_fw, &debug_bw);
  964. debug_fw += 10000; //*date.day;
  965. debug_bw += 10000; //*date.day;
  966. debug_w = 0;
  967. debug_vol = 50000; //+date.hour;
  968. set_cur_flow_bill(debug_w, debug_fw, debug_bw);
  969. ///////////test month///////////////////
  970. tm_t date, date2;
  971. if (dbg_bill_cnt == 1)
  972. {
  973. date.year = 26;
  974. date.month = 1;
  975. date.day = 1;
  976. date.hour = 0;
  977. date.min = 0;
  978. date.sec = 0;
  979. SetRtcTime(&date);
  980. }
  981. get_now_time(&date);
  982. #if DEBUG_SAVE_BAK == 1 // 1min
  983. if (date.sec >= 3 && date.sec <= 57)
  984. date.sec = 58;
  985. #elif DEBUG_5MIN_REC == 1 // 5min
  986. if (date.sec >= 3 && date.sec <= 20)
  987. {
  988. date.sec = 55 - date.min / 5;
  989. // if ((date.min % 5) != 0)
  990. // date.min = date.min - (date.min % 5);
  991. date.min += 4;
  992. date.min %= 60;
  993. }
  994. #elif DEBUG_HOUR_REC == 1 // 1hour
  995. if (date.sec >= 3 && date.sec <= 30)
  996. {
  997. date.sec = 58 - date.hour;
  998. // if((date.min != 0)date.min = 0;//date.min - (date.min%5);
  999. date.min = 59;
  1000. }
  1001. #elif DEBUG_DAY_REC == 1 // 1day
  1002. if (date.sec >= 3 && date.sec <= 20)
  1003. {
  1004. date.sec = 58 - date.day;
  1005. // if((date.min != 0)date.min = 0;//date.min - (date.min%5);
  1006. date.min = 59;
  1007. date.hour = 23;
  1008. }
  1009. #elif DEBUG_MONTH_REC == 1 // 1month
  1010. if (date.sec >= 3 && date.sec <= 40)
  1011. {
  1012. date.sec = 58 - date.month;
  1013. // if((date.min != 0)date.min = 0;//date.min - (date.min%5);
  1014. date.min = 59;
  1015. date.hour = 23;
  1016. date.day = monthday[date.month - 1];
  1017. if ((date.year % 4) == 0 && date.month == 2)
  1018. date.day += 1;
  1019. }
  1020. #endif
  1021. SetRtcTime(&date);
  1022. //}
  1023. if (dbg_bill_cnt > 1000)
  1024. while (1)
  1025. ;
  1026. /////////////////disp time//////////////////////
  1027. #ifdef DEBUG_DISP_TIME
  1028. rtc_run_t *rr;
  1029. get_rtc_run(&rr);
  1030. LOG("run_time:20%2d-%2d-%2d:%2d:%2d:%2d fw=%f,bw=%f\r\n", rr->year, rr->month, rr->day, rr->hour, rr->minute, rr->second, BillRun.fw_cum_flow, BillRun.bw_cum_flow); // 锟斤拷示时锟斤拷
  1031. #endif
  1032. }
  1033. #endif
  1034. int8_t SetRtcTime(tm_t *date)
  1035. {
  1036. if (date->month == 0 || date->month > 12)
  1037. return 2;
  1038. if (date->day == 0 || date->day > 31)
  1039. return 2;
  1040. if (date->hour > 23)
  1041. return 2;
  1042. if (date->min > 59)
  1043. return 2;
  1044. if (date->sec > 59)
  1045. return 2;
  1046. uint8_t year_bcd;
  1047. uint8_t month_bcd;
  1048. uint8_t day_bcd;
  1049. uint8_t second_bcd;
  1050. uint8_t minute_bcd;
  1051. uint8_t hour_bcd;
  1052. // year = ((NbAppFrame.data[4] << 8) | NbAppFrame.data[5]) % 2000;
  1053. year_bcd = OctToBcd((uint8_t)date->year); // 自取了低8位,8位二进制转换为
  1054. month_bcd = OctToBcd(date->month);
  1055. day_bcd = OctToBcd(date->day);
  1056. set_rtc_date(year_bcd, month_bcd, day_bcd); // 直接操作寄存器写入日期
  1057. hour_bcd = OctToBcd(date->hour);
  1058. minute_bcd = OctToBcd(date->min);
  1059. second_bcd = OctToBcd(date->sec);
  1060. set_rtc_time(hour_bcd, minute_bcd, second_bcd); // 保存时分秒
  1061. rtc_run_t tm;
  1062. tm.year = date->year;
  1063. tm.month = date->month;
  1064. tm.day = date->day;
  1065. tm.hour = date->hour;
  1066. tm.minute = date->min;
  1067. tm.second = date->sec;
  1068. set_rtc_run(&tm);
  1069. return 1;
  1070. }
  1071. void clear_log(void)
  1072. {
  1073. uint32_t addr = ALARM_START_ADDR;
  1074. // 计算日志区域的总大小
  1075. uint32_t end_addr = ALARM_START_ADDR + (uint32_t)MAX_ALARM_NUM * ALARM_DATA_SIZE;
  1076. if (end_addr <= addr)
  1077. {
  1078. LOG("Clear log error: Invalid address range.\r\n");
  1079. return;
  1080. }
  1081. uint32_t total_size = end_addr - addr;
  1082. // 定义单次写入块大小,与 clear_all_record 保持一致
  1083. // write_eeprom_para 内部缓冲区支持最大 128 字节有效数据
  1084. #define LOG_CLEAR_BLOCK_SIZE 128
  1085. uint8_t dat[LOG_CLEAR_BLOCK_SIZE];
  1086. memset(dat, 0xFF, LOG_CLEAR_BLOCK_SIZE);
  1087. LOG("Start clearing logs (%d bytes)...\r\n", total_size);
  1088. uint32_t processed = 0;
  1089. uint8_t last_progress = 0;
  1090. uint8_t ret;
  1091. while (processed < total_size)
  1092. {
  1093. // 计算本次实际写入长度
  1094. uint32_t remaining = total_size - processed;
  1095. uint16_t write_len = (remaining > LOG_CLEAR_BLOCK_SIZE) ? LOG_CLEAR_BLOCK_SIZE : (uint16_t)remaining;
  1096. // 执行写入
  1097. ret = write_eeprom_para(addr, dat, write_len);
  1098. if (ret != 0)
  1099. {
  1100. LOG("EEPROM log clear error at addr %d\r\n", addr);
  1101. // 可根据需求选择 break 或继续
  1102. }
  1103. addr += write_len;
  1104. processed += write_len;
  1105. // 计算进度百分比
  1106. uint8_t progress = (uint8_t)(processed * 100 / total_size);
  1107. // 每 10% 打印一次进度
  1108. if (progress >= last_progress + 10)
  1109. {
  1110. last_progress = progress;
  1111. LOG("Clearing logs... %d%%\r\n", progress);
  1112. // 重要:长时间操作需喂狗
  1113. #ifdef APP_USING_SWDG
  1114. WDG_Feed();
  1115. #endif
  1116. }
  1117. }
  1118. LOG("Clear log complete.\r\n");
  1119. }
  1120. extern void clr_max_flow_rate(void);
  1121. extern void clr_max_flow_rate_all(void);
  1122. void clear_all_record(void)
  1123. {
  1124. // 定义单次写入块大小 (128字节效率较高且栈安全)
  1125. clear_bottom_data(); // 底读设置为0,并保存
  1126. clr_max_flow_rate_all(); // 清最高瞬时流量
  1127. clr_bill_struct_data(); // 清除日结,月结等所有结算数据的基准累积量
  1128. // 下面是清除所有结算数据
  1129. #define CLEAR_BLOCK_SIZE 128
  1130. uint8_t dat[CLEAR_BLOCK_SIZE];
  1131. memset(dat, 0xFF, CLEAR_BLOCK_SIZE);
  1132. LOG("Start clearing all records and backups...\r\n");
  1133. // --- 第一部分:清除原有账单记录区域 (MONTH_BILL_START_ADDR 到 END_RECORD_ADDR) ---
  1134. uint32_t addr = MONTH_BILL_START_ADDR;
  1135. uint32_t end_addr = END_RECORD_ADDR;
  1136. if (end_addr > addr)
  1137. {
  1138. uint32_t total_size = end_addr - addr;
  1139. uint32_t processed = 0;
  1140. uint8_t last_progress = 0;
  1141. uint8_t ret;
  1142. LOG("Clearing Bill Records (0x%x - 0x%x)...\r\n", addr, end_addr);
  1143. while (processed < total_size)
  1144. {
  1145. uint32_t remaining = total_size - processed;
  1146. uint16_t write_len = (remaining > CLEAR_BLOCK_SIZE) ? CLEAR_BLOCK_SIZE : (uint16_t)remaining;
  1147. ret = write_eeprom_para(addr, dat, write_len);
  1148. if (ret != 0)
  1149. {
  1150. LOG("EEPROM clear error at addr %d\r\n", addr);
  1151. }
  1152. addr += write_len;
  1153. processed += write_len;
  1154. uint8_t progress = (uint8_t)(processed * 100 / total_size);
  1155. if (progress >= last_progress + 20)
  1156. {
  1157. last_progress = progress;
  1158. LOG(" Records: %d%%\r\n", progress);
  1159. #ifdef APP_USING_SWDG
  1160. WDG_Feed();
  1161. #endif
  1162. }
  1163. }
  1164. LOG("Bill Records cleared.\r\n");
  1165. }
  1166. // --- 第二部分:清除备份数据区域 (从 PRE_MONTH_COW_BAK_ADDR 开始) ---
  1167. // 计算备份区域的总长度:
  1168. // 1. 月/日/时备份: 3 * COW_BAK_DATA_SIZE (3 * 32 = 96 bytes)
  1169. // 2. 5分钟备份: BAK_5MIN_NUM * BAK_5MIN_SIZE (8 * 32 = 256 bytes)
  1170. // 总长度 = 96 + 256 = 352 bytes (0x160)
  1171. addr = PRE_MONTH_COW_BAK_ADDR;
  1172. uint32_t backup_total_size = (3 * COW_BAK_DATA_SIZE) + (BAK_5MIN_NUM * BAK_5MIN_SIZE);
  1173. if (backup_total_size > 0)
  1174. {
  1175. uint32_t processed = 0;
  1176. LOG("Clearing Backup Area (Start: 0x%x, Size: %d bytes)...\r\n", addr, backup_total_size);
  1177. while (processed < backup_total_size)
  1178. {
  1179. uint32_t remaining = backup_total_size - processed;
  1180. uint16_t write_len = (remaining > CLEAR_BLOCK_SIZE) ? CLEAR_BLOCK_SIZE : (uint16_t)remaining;
  1181. write_eeprom_para(addr, dat, write_len);
  1182. addr += write_len;
  1183. processed += write_len;
  1184. // 备份区域较小,每完成一次循环或最后喂狗即可,也可按比例打印
  1185. #ifdef APP_USING_SWDG
  1186. WDG_Feed();
  1187. #endif
  1188. }
  1189. LOG("Backup Area cleared.\r\n");
  1190. }
  1191. LOG("Clear all records and backups complete.\r\n");
  1192. }
  1193. void clear_bottom_data(void)
  1194. { // 清除底读
  1195. set_cur_flow_bill(0, 0, 0);
  1196. save_cur_flow_flag = 1;
  1197. }
  1198. #ifdef DEBUG_BILL
  1199. static uint8_t verify_eeprom_region(uint32_t start_addr, uint32_t size, const char *name)
  1200. {
  1201. #define VERIFY_BUF_SIZE 128
  1202. uint8_t buf[VERIFY_BUF_SIZE];
  1203. uint32_t processed = 0;
  1204. uint8_t ret = 0; // 0: OK, 1: Error
  1205. LOG("Verifying %s (Addr: 0x%x, Size: %d)... ", name, start_addr, size);
  1206. while (processed < size)
  1207. {
  1208. uint32_t remaining = size - processed;
  1209. uint16_t read_len = (remaining > VERIFY_BUF_SIZE) ? VERIFY_BUF_SIZE : (uint16_t)remaining;
  1210. // 批量读取
  1211. if (eeprom_MassRead(buf, start_addr + processed, read_len) != 0)
  1212. {
  1213. LOG("READ ERR\r\n");
  1214. return 1;
  1215. }
  1216. // 检查是否全为 0xFF
  1217. for (uint16_t i = 0; i < read_len; i++)
  1218. {
  1219. if (buf[i] != 0xFF)
  1220. {
  1221. LOG("FAIL at offset %d (Byte: 0x%X)\r\n", processed + i, buf[i]);
  1222. ret = 1;
  1223. // 可以选择继续检查以发现更多错误,或者直接返回
  1224. // return 1;
  1225. }
  1226. }
  1227. processed += read_len;
  1228. // 防止看门狗复位,特别是大区域验证时
  1229. #ifdef APP_USING_SWDG
  1230. if (processed % (VERIFY_BUF_SIZE * 10) == 0)
  1231. {
  1232. WDG_Feed();
  1233. }
  1234. #endif
  1235. }
  1236. if (ret == 0)
  1237. {
  1238. LOG("OK\r\n");
  1239. }
  1240. return ret;
  1241. }
  1242. /**
  1243. * @brief 验证清除操作的结果
  1244. */
  1245. void verify_clear_operations(void)
  1246. {
  1247. LOG("--- Start Verification of Clear Operations ---\r\n");
  1248. uint8_t err_cnt = 0;
  1249. // 1. 验证账单记录区域
  1250. if (END_RECORD_ADDR > MONTH_BILL_START_ADDR)
  1251. {
  1252. if (verify_eeprom_region(MONTH_BILL_START_ADDR, END_RECORD_ADDR - MONTH_BILL_START_ADDR, "Bill Records") != 0)
  1253. {
  1254. err_cnt++;
  1255. }
  1256. }
  1257. // 2. 验证备份区域 (从 PRE_MONTH_COW_BAK_ADDR 开始)
  1258. // 长度 = 月/日/时备份 (3 * 32) + 5分钟备份 (8 * 32) = 96 + 256 = 352 字节
  1259. uint32_t backup_size = (3 * COW_BAK_DATA_SIZE) + (BAK_5MIN_NUM * BAK_5MIN_SIZE);
  1260. if (verify_eeprom_region(PRE_MONTH_COW_BAK_ADDR, backup_size, "Backup Area") != 0)
  1261. {
  1262. err_cnt++;
  1263. }
  1264. // 3. 验证日志区域
  1265. uint32_t log_size = (uint32_t)MAX_ALARM_NUM * ALARM_DATA_SIZE;
  1266. if (verify_eeprom_region(ALARM_START_ADDR, log_size, "Alarm Logs") != 0)
  1267. {
  1268. err_cnt++;
  1269. }
  1270. if (err_cnt == 0)
  1271. {
  1272. LOG("--- All Verifications PASSED ---\r\n");
  1273. }
  1274. else
  1275. {
  1276. LOG("--- Verification FAILED with %d errors ---\r\n", err_cnt);
  1277. }
  1278. }
  1279. #endif
  1280. void clr_bill_struct_data(void)
  1281. {
  1282. memset(&bak_month_cum_flow, 0, sizeof(bak_month_cum_flow));
  1283. memset(&bak_day_cum_flow, 0, sizeof(bak_day_cum_flow));
  1284. memset(&bak_hour_cum_flow, 0, sizeof(bak_hour_cum_flow));
  1285. memset(bak_5min_cum_flow.date, 0, 6);
  1286. bak_5min_cum_flow.fw_cum_flow = 0;
  1287. bak_5min_cum_flow.bw_cum_flow = 0;
  1288. cum_flow_index.bw = 0;
  1289. cum_flow_index.fw = 0;
  1290. }
  1291. //// 检查日期是否有效
  1292. uint8_t CheckDateValid(uint8_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t min, uint8_t sec)
  1293. {
  1294. if (year >= 100 || month == 0 || month > 12 || day == 0 || day > 31 || hour > 23 || min > 59 || sec > 59)
  1295. return 0;
  1296. if (day > monthday[month - 1] + ((year % 4 == 0 && month == 2) ? 1 : 0))
  1297. return 0;
  1298. return 1;
  1299. }