bill.c 38 KB

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