#include "board.h" #include "bill.h" #include "prj_com.h" #include "param.h" #include "rtc_run.h" #include "eeprom.h" #include "wdg_drv.h" #include "alarm.h" #include "tdc_tof.h" bill_run_t BillRun; CUR_FLOW_INDEX_DEF cum_flow_index; unsigned char save_cur_flow_flag; // res_bill_t bak_month_cum_flow; res_bill_t bak_day_cum_flow; res_bill_t bak_hour_cum_flow; bill_5min_ctrl_def bak_5min_cum_flow; uint8_t StartUp = 0; uint8_t global_settle_flag = 0; void bill_init(void) { BillRun.fw_use_hour = 0.0f; BillRun.fw_use_day = 0.0f; BillRun.fw_use_day = 0.0f; BillRun.fw_use_five_min = 0.0f; BillRun.bw_use_hour = 0.0f; BillRun.bw_use_day = 0.0f; BillRun.bw_use_month = 0.0f; BillRun.bw_use_five_min = 0.0f; BillRun.cum_flow = 0.0f; BillRun.fw_cum_flow = 0.0f; BillRun.bw_cum_flow = 0.0f; init_5min_cur_flow_bill(); init_hour_cur_flow_bill(); init_day_cur_flow_bill(); init_month_cur_flow_bill(); init_cur_flow_bill(); } uint32_t get_month_fw_used_bill(void) { // 获取月正向流量数据 if (BillRun.fw_cum_flow <= bak_month_cum_flow.fw_cum_flow) return 0; else return (uint32_t)((BillRun.fw_cum_flow - bak_month_cum_flow.fw_cum_flow) * 0.0001); // 锟斤拷前锟桔计斤拷锟斤拷锟斤拷细锟斤拷锟斤拷奂平锟斤拷锟侥诧拷值 } uint32_t get_month_bw_used_bill(void) { // 获取月反向流量 if (BillRun.bw_cum_flow <= bak_month_cum_flow.bw_cum_flow) return 0; else return (uint32_t)((BillRun.bw_cum_flow - bak_month_cum_flow.bw_cum_flow) * 0.0001); } uint32_t get_day_fw_used_bill(void) // 月结和日结都是两位小数点m3 wxl2026-5-6 { // 获取日正向流量数据 if (BillRun.fw_cum_flow <= bak_day_cum_flow.fw_cum_flow) return 0; else return (uint32_t)((BillRun.fw_cum_flow - bak_day_cum_flow.fw_cum_flow) * 0.0001); } uint32_t get_day_bw_used_bill(void) { // 获取日反向流量 if (BillRun.bw_cum_flow <= bak_day_cum_flow.bw_cum_flow) return 0; else return (uint32_t)((BillRun.bw_cum_flow - bak_day_cum_flow.bw_cum_flow) * 0.0001); } uint32_t get_hour_fw_used_bill(void) { // 获取小时正向流量数据 if (BillRun.fw_cum_flow <= bak_hour_cum_flow.fw_cum_flow) return 0; else return (uint32_t)((BillRun.fw_cum_flow - bak_hour_cum_flow.fw_cum_flow) * 0.001); } uint32_t get_hour_bw_used_bill(void) { // 获取小时反向流量数据 if (BillRun.bw_cum_flow <= bak_hour_cum_flow.bw_cum_flow) return 0; else return (uint32_t)((BillRun.bw_cum_flow - bak_hour_cum_flow.bw_cum_flow) * 0.001); } uint32_t get_5min_fw_used_bill(void) { // 获取5min正向流量数据 if (BillRun.fw_cum_flow <= bak_5min_cum_flow.fw_cum_flow) return 0; else return (uint32_t)((BillRun.fw_cum_flow - bak_5min_cum_flow.fw_cum_flow) * 0.001); } uint32_t get_5min_bw_used_bill(void) { // 获取5min反向流量数据 if (BillRun.bw_cum_flow <= bak_5min_cum_flow.bw_cum_flow) return 0; else return (uint32_t)((BillRun.bw_cum_flow - bak_5min_cum_flow.bw_cum_flow) * 0.001); } /////////////将瞬时流量转换为要求的比例////////////////////////// int32_t get_flow_rate_bill(void) { // 获取瞬时流速 return (int32_t)(BillRun.flow_rate * 0.001 * 3600); } //////////////////////对外接口 从采样模块获取瞬时流量到bill 和以前的SetBillVol兼容/////////////////////////////////// // fw_vol:正向瞬时流量 // bw_vol:反向瞬时流量 ///////////////////////////////////////////////////////// void set_flow_rate_bill(double fw_vol, double bw_vol) // 当前月日小时5min累计流量累加 { BillRun.flow_rate = (fw_vol > 0) ? fw_vol : bw_vol; } ///////////////////在采集计算中调用 获取当前流量累计数据当前流量累计值,/////////////////// // 参数cum:绝对流量 // 参数 fw_cum:正向流量 // 参数 bw_cum:反向流量 // 返回:无 //////////////////////////////////////////// void set_cur_flow_bill(double cum, double fw_cum, double bw_cum) { BillRun.cum_flow = fw_cum - bw_cum; BillRun.fw_cum_flow = fw_cum; BillRun.bw_cum_flow = bw_cum; CumFlow = fw_cum - bw_cum; FwCumFlow = fw_cum; BwCumFlow = bw_cum; } /// 读取当前累计流量到指针参数,本模块对外输出///////////// void get_cur_flow_bill(double *cum, double *fw_cum, double *bw_cum) { *cum = CumFlow; *fw_cum = FwCumFlow; *bw_cum = BwCumFlow; } ////////////////保存月使用量/////////////////////// /// 参数:年月日 /// 无返回 ///////////////////////////////////////// void set_month_used_bill(uint8_t year, uint8_t month, uint8_t day) { uint32_t fw_used; uint32_t bw_used; bill_t month_bill; uint16_t len = sizeof(bill_t); uint32_t addr = MONTH_BILL_START_ADDR + len * MONTH_BILL_INDEX(year, month); fw_used = get_month_fw_used_bill(); bw_used = get_month_bw_used_bill(); month_bill.flag = 1; month_bill.date[0] = year; month_bill.date[1] = month; month_bill.date[2] = day; month_bill.fw_used = fw_used; month_bill.bw_used = bw_used; write_eeprom(addr, (uint8_t *)&month_bill, len); } /////////////////////保存日使用量//////////////////////////////// // 参数 年月日 /////////////////////////////////////////////// void set_day_used_bill(uint8_t year, uint8_t month, uint8_t day) { uint32_t fw_used; uint32_t bw_used; bill_t day_bill; uint16_t len = sizeof(bill_t); uint16_t days = days_from_leap_year_begin(month, day); uint32_t addr = DAY_BILL_START_ADDR + len * (days - 1); fw_used = get_day_fw_used_bill(); bw_used = get_day_bw_used_bill(); day_bill.flag = 1; day_bill.date[0] = year; day_bill.date[1] = month; day_bill.date[2] = day; day_bill.fw_used = fw_used; day_bill.bw_used = bw_used; write_eeprom(addr, (uint8_t *)&day_bill, len); } ////////////////////保存小时使用量/////////////////////////////////// /// 参数:年月日时 ///////////////////////////////////////////////////////// void set_hour_used_bill(uint8_t year, uint8_t month, uint8_t day, uint8_t hour) { uint32_t fw_used; uint32_t bw_used; uint32_t fr; hour_bill_t hour_bill; uint16_t len = sizeof(hour_bill_t); uint32_t addr = HOUR_BILL_START_ADDR + HOUR_BILL_INDEX(day, hour) * len; fw_used = get_hour_fw_used_bill(); bw_used = get_hour_bw_used_bill(); fr = (uint32_t)get_flow_rate_bill(); #ifdef DEBUG_BILL2 // fw_used = hour; // bw_used = 2 * hour; // fr = 3 * hour; #endif #ifdef DEBUG_BILL LOG("%d-%d-%d %d write hour bill fw= %d\r\n", year, month, day, hour, fw_used); #endif memset(&hour_bill, 0, sizeof(hour_bill_t)); hour_bill.flag = 1; hour_bill.date[0] = year; hour_bill.date[1] = month; hour_bill.date[2] = day; hour_bill.date[3] = hour; hour_bill.fw_used[0] = (uint8_t)(fw_used); hour_bill.fw_used[1] = (uint8_t)(fw_used >> 8); hour_bill.fw_used[2] = (uint8_t)(fw_used >> 16); hour_bill.bw_used[0] = (uint8_t)(bw_used); hour_bill.bw_used[1] = (uint8_t)(bw_used >> 8); hour_bill.bw_used[2] = (uint8_t)(bw_used >> 16); hour_bill.flow_rate[0] = (uint8_t)(fr); hour_bill.flow_rate[1] = (uint8_t)(fr >> 8); hour_bill.flow_rate[2] = (uint8_t)(fr >> 16); if (Paramx.pressure_sensor == 1) { hour_bill.pressure = (uint8_t)(WaterPressure * 100); } else { hour_bill.pressure = 0x00; // 无压力传感器,修改为0 } write_eeprom(addr, (uint8_t *)&hour_bill, len); } /////////////////保存5分钟使用量/////////////////////// // 参数:年月日时分 /////////////////////////////////////////////// void set_5min_used_bill(uint8_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute) { uint32_t fw_used; uint32_t bw_used; uint32_t fr; hour_bill_t bill; uint16_t len = sizeof(hour_bill_t); uint32_t addr = FIVE_MIN_BILL_START_ADDR + len * FIVE_MIN_BILL_INDEX(day, hour, minute); fw_used = get_5min_fw_used_bill(); bw_used = get_5min_bw_used_bill(); fr = (uint32_t)get_flow_rate_bill(); #ifdef DEBUG_BILL2 fw_used = minute * 10; bw_used = minute * 20; fr = minute * 5; #endif bill.flag = 1; bill.date[0] = year; bill.date[1] = month; // num保存该小时内第几个5分钟数据 bill.date[2] = day; bill.date[3] = hour; bill.fw_used[0] = (uint8_t)(fw_used); bill.fw_used[1] = (uint8_t)(fw_used >> 8); bill.fw_used[2] = (uint8_t)(fw_used >> 16); bill.bw_used[0] = (uint8_t)(bw_used); bill.bw_used[1] = (uint8_t)(bw_used >> 8); bill.bw_used[2] = (uint8_t)(bw_used >> 16); bill.flow_rate[0] = (uint8_t)(fr); bill.flow_rate[1] = (uint8_t)(fr >> 8); bill.flow_rate[2] = (uint8_t)(fr >> 16); if (Paramx.pressure_sensor == 1) { bill.pressure = (uint8_t)(WaterPressure * 100); } else { bill.pressure = 0x0; // 无压力传感器 ,修改为0x0 } write_eeprom(addr, (uint8_t *)&bill, len); } /////////////////////////保存当前累计流量数据和时间,防止意外丢失/////////////////////////////// // 无参数 // 无返回值 // 256点循环保存,最快10秒一次, 最慢5分钟一次 /////////////////////////////////////////////////////////////////////// uint8_t save_5min_trik_flag = 0; void save_cur_flow_bill(void) { rtc_run_t *rr; bill_cum_flow_tx bill; if (global_settle_flag == 1) // 结算中,只有结算完成才保存新的底读 return; get_rtc_run(&rr); // 获取当前时间 if (rr->minute % 5 == 0) { save_5min_trik_flag++; } else { save_5min_trik_flag = 0; } 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) { // 整5分钟或流量值发生变化 } else return; save_cur_flow_flag = 0; memset(&bill, 0, sizeof(bill_cum_flow_tx)); // 初始化0 bill.flag = 1; bill.date_time[0] = rr->year; bill.date_time[1] = rr->month; bill.date_time[2] = rr->day; bill.date_time[3] = rr->hour; bill.date_time[4] = rr->minute; bill.date_time[5] = rr->second; bill.date_time[6] = rr->week; bill.fw_cum_flow = BillRun.fw_cum_flow; bill.bw_cum_flow = BillRun.bw_cum_flow; cum_flow_index.fw = BillRun.fw_cum_flow; cum_flow_index.bw = BillRun.bw_cum_flow; bill.gcnt = cum_flow_index.cur_gcnt; // 保存当前累计序列值 long型有符号,用于读取时,找到最近一条记录的条件, 最大值为最新记录 cum_flow_index.cur_gcnt++; // 累加当前序列,作为下次保存时使用 cum_flow_index.npos %= MAX_CUM_FLOW_NUM; write_eeprom(CUM_FLOW_START_ADDR + cum_flow_index.npos * CUM_FLOW_SIZE, (uint8_t *)&bill, sizeof(bill_cum_flow_tx)); // 写锟斤拷锟斤拷锟斤拷 cum_flow_index.npos++; // 存储位置后移 cum_flow_index.npos %= MAX_CUM_FLOW_NUM; // 循环存储 #ifdef DEBUG_BILL 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); #endif } ///////////////读取指定时间的月使用量/////////////////////////// uint8_t get_month_used_bill(uint8_t year, uint8_t month, bill_t *bill) { rtc_run_t *rr; get_rtc_run(&rr); int16_t ms = (rr->year * 12 + rr->month) - (year * 12 + month); memset(bill, 0, sizeof(bill_t)); if (ms <= 0 || ms > MONTH_BILL_NUM) { // #ifdef DEBUG_BILL2 // LOG("month date out\r\n"); // #endif return 0; // 超出48个月 } // #ifdef DEBUG_BILL2 // LOG("month date ok\r\n"); // #endif uint16_t len = sizeof(bill_t); uint32_t addr = MONTH_BILL_START_ADDR + len * MONTH_BILL_INDEX(year, month); uint8_t ret; ret = read_eeprom(addr, (uint8_t *)bill, len); if (ret != 0) return ret; if (bill->date[0] != year || bill->date[1] != month) // 读取的月份和日期不匹配 { // memset(bill, 0, sizeof(bill_t)); return 1; } return 0; } uint16_t get_days_from_year(uint8_t year, uint8_t month, uint8_t day) { uint16_t days = 0; uint8_t i; if (month == 0 || day == 0) return 0; for (i = 0; i < month - 1; i++) { days += monthday[i]; if (i == 1 && year % 4 == 0) days++; } days = days + day - 1; return days; } /* int32_t get_days_between_now(uint8_t byear, uint8_t bmonth, uint8_t bday) { rtc_run_t *rr; get_rtc_run(&rr); int32_t adays, bdays; adays = rr->year * 366 + get_days_from_year(rr->year, rr->month, rr->day); bdays = byear * 366 + get_days_from_year(byear, bmonth, bday); return adays - bdays; } */ int32_t get_days_between_now(uint8_t y2, uint8_t m2, uint8_t d2) { uint16_t i; uint32_t days1 = 0, days2 = 0; uint8_t monthDays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; rtc_run_t *rr; get_rtc_run(&rr); uint8_t y1 = rr->year; uint8_t m1 = rr->month; uint8_t d1 = rr->day; // 计算日期1总天数 for (i = 1; i < y1; i++) { if ((i % 4 == 0 && i % 100 != 0) || (i % 400 == 0)) days1 += 366; else days1 += 365; } for (i = 1; i < m1; i++) { days1 += monthDays[i - 1]; if (i == 2 && ((y1 % 4 == 0 && y1 % 100 != 0) || (y1 % 400 == 0))) days1++; } days1 += d1; // 日期1 - 日期2,自动产生正负 for (i = 1; i < y2; i++) { if ((i % 4 == 0 && i % 100 != 0) || (i % 400 == 0)) days2 += 366; else days2 += 365; } for (i = 1; i < m2; i++) { days2 += monthDays[i - 1]; if (i == 2 && ((y2 % 4 == 0 && y2 % 100 != 0) || (y2 % 400 == 0))) days2++; } days2 += d2; // 日期1 - 日期2,自动产生正负 return days1 - days2; } //////////////////读取指定时间的日使用量////////////////////////// uint8_t get_day_used_bill(uint8_t month, uint8_t day, bill_t *bill) { uint16_t days = days_from_leap_year_begin(month, day); uint16_t len = sizeof(bill_t); uint32_t addr = DAY_BILL_START_ADDR + len * (days - 1); #ifdef DEBUG_BILL2 LOG("%d-%d\r\n", month, day); #endif memset(bill, 0, sizeof(bill_t)); uint8_t ret = read_eeprom(addr, (uint8_t *)bill, len); if (ret != 0) return ret; if (bill->date[1] != month || bill->date[2] != day) return 1; return 0; } int32_t get_hours_between_now(uint8_t year, uint8_t month, uint8_t day, uint8_t hour) { int32_t hours; hours = 24 * get_days_between_now(year, month, day); rtc_run_t *rr; get_rtc_run(&rr); hours += (signed char)(rr->hour - hour); return hours; } ///////////////读取指定时间的小时使用量////////////////////////// uint8_t get_hour_used_bill(uint8_t day, uint8_t hour, hour_bill_t *bill) { uint16_t len = sizeof(hour_bill_t); uint32_t addr = HOUR_BILL_START_ADDR + HOUR_BILL_INDEX(day, hour) * len; memset(bill, 0, sizeof(hour_bill_t)); // int32_t hours = get_hours_between_now(year,month,day,hour); // if(hours <= 0 || hours > 31 * 24)return 0; return read_eeprom(addr, (uint8_t *)bill, len); } //////////////////读取指定时间的5分钟使用量//////////////////////////// uint8_t get_5min_used_bill(uint8_t day, uint8_t hour, uint8_t minute, hour_bill_t *bill) { uint16_t len = sizeof(hour_bill_t); uint32_t addr = FIVE_MIN_BILL_START_ADDR + len * FIVE_MIN_BILL_INDEX(day, hour, minute); memset(bill, 0, sizeof(hour_bill_t)); return read_eeprom(addr, (uint8_t *)bill, len); } ////////////数据累加和校验生成/////////////////////// // 参数1:dat 指向数据指针 // 参数2:len数据长度 // 返回:单字节校验和 ///////////////////////////////////////////////////// uint8_t Sum8(uint8_t *dat, uint16_t len) { uint8_t sum = 0; while (len--) { sum += dat[len]; // 单字节累加 } return sum; // 返回校验值 } ///////////// 检查时间日期是否合法///////////////////////// // 参数:时间字符串 依次是年月日时分秒周 // 异常:返回0 正常:返回1 ///////////////////////////////////// uint8_t CheckTime(uint8_t *date) { if (date[1] == 0 || date[1] > 12) return 0; // 月 if (date[2] == 0 || date[2] > 31) return 0; // 日 if (date[3] > 23) return 0; // 时 if (date[4] > 59) return 0; // 分 if (date[5] > 59) return 0; // 秒 return 1; } /////////////////备用看门狗喂狗//////////////////////////////////// void dog(void) { #ifdef APP_USING_SWDG WDG_Feed(); #endif } ///////////////////上电初始化后读取当前流量值为累计初始流量/////////////////////////////////// // 无参数 // 无返回 //////////////////////////////////////////////////////////////////////////////// void init_cur_flow_bill(void) { tm_t tm; cum_flow_index.cur_gcnt = 0; // 当前累计计数值 用于判断是否最新的记录,最大值为最新记录long型 cum_flow_index.npos = 0; // 当前存储位置,用于写入时的地址寻址 uint16_t i; uint8_t check; bill_cum_flow_tx cur_bill; for (i = 0; i < MAX_CUM_FLOW_NUM; i++) { read_eeprom(CUM_FLOW_START_ADDR + i * CUM_FLOW_SIZE, (uint8_t *)&cur_bill, sizeof(bill_cum_flow_tx)); // 依次读取每个记录 if (cur_bill.flag == 1 // 有效标志 1:有效,其他无效 && cur_bill.gcnt >= 0 // 计数器在正常范围内(long型 >0有效) && CheckTime(cur_bill.date_time) == 1) { // 时间有效 if (cur_bill.gcnt >= cum_flow_index.cur_gcnt) { cum_flow_index.cur_gcnt = cur_bill.gcnt + 1; // 下一个要写入的序列号 cum_flow_index.npos = ((i + 1) % MAX_CUM_FLOW_NUM); // 下一个要写入的相对地址 cum_flow_index.fw = cur_bill.fw_cum_flow; cum_flow_index.bw = cur_bill.bw_cum_flow; tm.year = cur_bill.date_time[0]; tm.month = cur_bill.date_time[1]; tm.day = cur_bill.date_time[2]; tm.hour = cur_bill.date_time[3]; tm.min = cur_bill.date_time[4]; tm.sec = cur_bill.date_time[5]; } } feed_dog(); // 看门狗 防止复位 } SetBillCumFlow(cum_flow_index.fw - cum_flow_index.bw, cum_flow_index.fw, cum_flow_index.bw); // 初始化当前流量数据 CumFlow = cum_flow_index.fw - cum_flow_index.bw; FwCumFlow = cum_flow_index.fw; BwCumFlow = cum_flow_index.bw; #ifdef DEBUG_BILL 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); #endif // 初始化时间日期 SetRtcTime(&tm); } //////////////////保存当前月存储时累积量///////////////////////// void set_month_cur_flow_bill(void) { // 只输入fw_cum_flow和bw_cum_flow rtc_run_t *rr; get_rtc_run(&rr); // 获取当前时间 bak_month_cum_flow.date[0] = rr->year; bak_month_cum_flow.date[1] = rr->month; bak_month_cum_flow.date[2] = rr->day; bak_month_cum_flow.date[3] = rr->hour; bak_month_cum_flow.date[4] = rr->minute; bak_month_cum_flow.date[5] = rr->second; bak_month_cum_flow.flag = 1; // if (bak_month_cum_flow.bw_cum_flow == BillRun.bw_cum_flow && bak_month_cum_flow.fw_cum_flow == BillRun.fw_cum_flow) // return; // 无变化,不保存 bak_month_cum_flow.fw_cum_flow = BillRun.fw_cum_flow; bak_month_cum_flow.bw_cum_flow = BillRun.bw_cum_flow; uint32_t addr = PRE_MONTH_COW_BAK_ADDR; write_eeprom(addr, (uint8_t *)&bak_month_cum_flow, sizeof(res_bill_t)); } //////////////上电初始化时,读取上次保存的月累积量,作为下次参考///////////////////////////////////// void init_month_cur_flow_bill(void) { // 只输入fw_cum_flow和bw_cum_flow uint32_t addr = PRE_MONTH_COW_BAK_ADDR; res_bill_t bill; memset(&bak_month_cum_flow, 0, sizeof(res_bill_t)); read_eeprom(addr, (uint8_t *)&bill, sizeof(res_bill_t)); if (bill.flag == 1) { bak_month_cum_flow = bill; } } //////////////////////保存当前日存储的累计量////////////////////////////////// void set_day_cur_flow_bill(void) { rtc_run_t *rr; get_rtc_run(&rr); // 获取当前时间 bak_day_cum_flow.date[0] = rr->year; bak_day_cum_flow.date[1] = rr->month; bak_day_cum_flow.date[2] = rr->day; bak_day_cum_flow.date[3] = rr->hour; bak_day_cum_flow.date[4] = rr->minute; bak_day_cum_flow.date[5] = rr->second; bak_day_cum_flow.flag = 1; // if (bak_day_cum_flow.bw_cum_flow == BillRun.bw_cum_flow && bak_day_cum_flow.fw_cum_flow == BillRun.fw_cum_flow) // return; // 无变化,不保存 bak_day_cum_flow.fw_cum_flow = BillRun.fw_cum_flow; bak_day_cum_flow.bw_cum_flow = BillRun.bw_cum_flow; uint32_t addr = PRE_DAY_COW_BAK_ADDR; write_eeprom(addr, (uint8_t *)&bak_day_cum_flow, sizeof(res_bill_t)); } ////////////////////上电初始化上次日存储的累积量////////////////// void init_day_cur_flow_bill(void) { // 只输入fw_cum_flow和bw_cum_flow uint32_t addr = PRE_DAY_COW_BAK_ADDR; res_bill_t bill; memset(&bak_day_cum_flow, 0, sizeof(res_bill_t)); read_eeprom(addr, (uint8_t *)&bill, sizeof(res_bill_t)); if (bill.flag == 1) { bak_day_cum_flow = bill; } } /////////////////////保存当前小时累积量/////////////////////////// void set_hour_cur_flow_bill(void) { // 只输入fw_cum_flow和bw_cum_flow rtc_run_t *rr; get_rtc_run(&rr); // 获取当前时间 bak_hour_cum_flow.date[0] = rr->year; bak_hour_cum_flow.date[1] = rr->month; bak_hour_cum_flow.date[2] = rr->day; bak_hour_cum_flow.date[3] = rr->hour; bak_hour_cum_flow.date[4] = rr->minute; bak_hour_cum_flow.date[5] = rr->second; // if (bak_hour_cum_flow.bw_cum_flow == BillRun.bw_cum_flow && bak_hour_cum_flow.fw_cum_flow == BillRun.fw_cum_flow) // return; // 无变化,不保存 bak_hour_cum_flow.flag = 1; bak_hour_cum_flow.fw_cum_flow = BillRun.fw_cum_flow; bak_hour_cum_flow.bw_cum_flow = BillRun.bw_cum_flow; uint32_t addr = PRE_HOUR_COW_BAK_ADDR; write_eeprom(addr, (uint8_t *)&bak_hour_cum_flow, sizeof(res_bill_t)); } ///////////////上电初始化上次小时累积量////////////////// void init_hour_cur_flow_bill(void) { // 只输入fw_cum_flow和bw_cum_flow uint32_t addr = PRE_HOUR_COW_BAK_ADDR; res_bill_t bill; memset(&bak_hour_cum_flow, 0, sizeof(res_bill_t)); read_eeprom(addr, (uint8_t *)&bill, sizeof(res_bill_t)); if (bill.flag == 1) { bak_hour_cum_flow = bill; } } void set_5min_cur_flow_bill(void) { // 1. 获取当前时间 rtc_run_t *rr; get_rtc_run(&rr); // 2. 判断数据是否有变化 (可选:如果时间变了但流量没变,是否也要保存?通常流量计费以流量变化或时间周期为准) // 原逻辑仅比较流量,这里保持原逻辑,但注意:如果仅靠流量变化触发,可能会丢失纯时间流逝的记录。 // 建议结合 app_bill_run 中的时间判断逻辑,确保每5分钟强制调用一次。 bak_5min_cum_flow.date[0] = rr->year; bak_5min_cum_flow.date[1] = rr->month; bak_5min_cum_flow.date[2] = rr->day; bak_5min_cum_flow.date[3] = rr->hour; bak_5min_cum_flow.date[4] = rr->minute; bak_5min_cum_flow.date[5] = rr->second; // if (bak_5min_cum_flow.bw_cum_flow == BillRun.bw_cum_flow && bak_5min_cum_flow.fw_cum_flow == BillRun.fw_cum_flow) // { // return; // } // 3. 更新内存中的备份控制块的时间字段 (假设 bill_5min_ctrl_def 中有 date 字段,如果没有,需添加) // 注意:原代码 bak_5min_cum_flow 是 bill_5min_ctrl_def 类型 // 如果该结构体没有 date 字段,建议添加 uint8_t date[6]; 以便快速比对 bak_5min_cum_flow.bw_cum_flow = BillRun.bw_cum_flow; bak_5min_cum_flow.fw_cum_flow = BillRun.fw_cum_flow; // 4. 准备写入 EEPROM 的结构体 uint32_t addr = PRE_5MIN_COW_BAK_ADDR + bak_5min_cum_flow.add_cnt * BAK_5MIN_SIZE; bak_5min_bill_t bill; memset(&bill, 0, sizeof(bak_5min_bill_t)); bill.flag = 1; bill.global_cnt = bak_5min_cum_flow.global_cnt; bill.fw_cum_flow = BillRun.fw_cum_flow; bill.bw_cum_flow = BillRun.bw_cum_flow; write_eeprom(addr, (uint8_t *)&bill, sizeof(bak_5min_bill_t)); // 5. 更新索引和计数器 bak_5min_cum_flow.add_cnt++; bak_5min_cum_flow.add_cnt %= BAK_5MIN_NUM; bak_5min_cum_flow.global_cnt++; } void init_5min_cur_flow_bill(void) { uint32_t addr = PRE_5MIN_COW_BAK_ADDR; uint8_t i; int32_t gcnt = -1; bak_5min_bill_t bill; // 初始化内存控制块 memset(&bak_5min_cum_flow, 0, sizeof(bill_5min_ctrl_def)); memset(&bill, 0, sizeof(bak_5min_bill_t)); for (i = 0; i < BAK_5MIN_NUM; i++) { // 读取 EEPROM read_eeprom(addr + i * BAK_5MIN_SIZE, (uint8_t *)&bill, sizeof(bak_5min_bill_t)); // 检查标志位 if (bill.flag == 1) { if (bill.global_cnt > gcnt) { // 恢复累积流量 bak_5min_cum_flow.fw_cum_flow = bill.fw_cum_flow; bak_5min_cum_flow.bw_cum_flow = bill.bw_cum_flow; gcnt = bill.global_cnt; // 计算下一个写入位置 bak_5min_cum_flow.add_cnt = i + 1; bak_5min_cum_flow.add_cnt %= BAK_5MIN_NUM; // 更新全局计数器 bak_5min_cum_flow.global_cnt = gcnt + 1; } } } // 如果没有找到有效记录,使用当前系统时间和流量初始化 if (gcnt == -1) { rtc_run_t *rr; get_rtc_run(&rr); bak_5min_cum_flow.fw_cum_flow = BillRun.fw_cum_flow; bak_5min_cum_flow.bw_cum_flow = BillRun.bw_cum_flow; bak_5min_cum_flow.add_cnt = 0; bak_5min_cum_flow.global_cnt = 0; } } //////////////////////获取当前时间到结构体tm_t指针//////////////////////// void get_now_time(tm_t *tm) { rtc_run_t *rr; get_rtc_run(&rr); tm->year = rr->year; tm->month = rr->month; tm->day = rr->day; tm->hour = rr->hour; tm->min = rr->minute; tm->sec = rr->second; } ///////////////////////////获取上一个小时的时间///////////////////////////////////////////////// // 参数:tm_t指针 // 返回:上一个小时的时间 ///////////////////////////////////////////////////////////// tm_t prev_hour(tm_t *date) { tm_t ndate = *date; if (ndate.hour != 0) { ndate.hour--; return ndate; } ndate.hour = 23; uint32_t sdate = prev_day((ndate.year << 16) + (ndate.month << 8) + ndate.day); ndate.day = (uint8_t)sdate; ndate.month = (uint8_t)(sdate >> 8); ndate.year = (uint8_t)(sdate >> 16); return ndate; } void get_cur_flow_data(tm_t *ntm) { if (global_settle_flag != 0) // 在设置更新的底读之前,先进行结算 { global_settle_flag = 0; set_month_used_bill(ntm->year, ntm->month, ntm->day); // 设置月度已用账单 set_day_used_bill(ntm->year, ntm->month, ntm->day); // 设置日度已用账单 set_hour_used_bill(ntm->year, ntm->month, ntm->day, ntm->hour); // 设置小时已用账单 set_5min_used_bill(ntm->year, ntm->month, ntm->day, ntm->hour, ntm->min); // 设置5分钟已用账单 BillRun.fw_cum_flow = FwCumFlow; // 设置正向累计流量 BillRun.bw_cum_flow = BwCumFlow; BillRun.flow_rate = FlowVol; set_month_cur_flow_bill(); set_day_cur_flow_bill(); set_hour_cur_flow_bill(); set_5min_cur_flow_bill(); } else { BillRun.fw_cum_flow = FwCumFlow; BillRun.bw_cum_flow = BwCumFlow; BillRun.flow_rate = FlowVol; } } void app_bill_run(void) { // #ifdef DEBUG_BILL // Debug_bill(); /* if (StartUp == 5) { clear_all_record(); clear_log(); verify_clear_operations(); while (1) ; } */ #endif #ifdef DEBUG_LOG_WARM if (StartUp == 5) Debug_log(); #endif if (StartUp < 250) StartUp++; if (StartUp < 5) return; tm_t ntm; uint32_t ndate; // 1. 获取当前时间,作为所有判断的基准 get_now_time(&ntm); // 获取当前流量数据,用于计算差值 get_cur_flow_data(&ntm); ////////////////////////////////// 月使用量记录 ////////////////////////////////// // 判断依据:当前时间的年或月 与 备份的年月不一致 if (bak_month_cum_flow.date[0] != ntm.year || bak_month_cum_flow.date[1] != ntm.month) { // 计算上个月的最后一天 ndate = (ntm.year << 16) | (ntm.month << 8) | 1; // 当前月1号 ndate = prev_day(ndate); // 回退一天,即上个月最后一天 // 存储上个月的使用量,时间戳为上个月最后一天 // if ((uint8_t)(ndate >> 16) == bak_month_cum_flow.date[0] && (uint8_t)(ndate >> 8) == bak_month_cum_flow.date[1]) if ((ndate >> 8) >= ((bak_month_cum_flow.date[0] << 8) | bak_month_cum_flow.date[1])) { // 结算月份必须大于等于备份月份 set_month_used_bill((uint8_t)(ndate >> 16), (uint8_t)(ndate >> 8), (uint8_t)(ndate)); } // 更新备份:将当前累积流量保存为新的月度起始基准 set_month_cur_flow_bill(); #ifdef DEBUG_BILL LOG("%d-%d-%d write month bill\r\n", (uint8_t)(ndate >> 16), (uint8_t)(ndate >> 8), (uint8_t)(ndate)); #endif } ////////////////////////////// 日使用量记录 //////////////////////////////////////// // 判断依据:当前时间的年月日 与 备份的年月日不一致 // 注意:这里必须使用原始的 ntm,不能受下方小时逻辑影响 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) { // 计算昨天 ndate = (ntm.year << 16) | (ntm.month << 8) | ntm.day; ndate = prev_day(ndate); // 存储昨天的使用量 // 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]) if (ndate >= ((bak_day_cum_flow.date[0] << 16) | (bak_day_cum_flow.date[1] << 8) | bak_day_cum_flow.date[2])) { // 结算日期必须大于等于备份日期, 否则只更新基准,不记录使用量 set_day_used_bill((uint8_t)(ndate >> 16), (uint8_t)(ndate >> 8), (uint8_t)(ndate)); } // 更新备份:将当前累积流量保存为新的日度起始基准 set_day_cur_flow_bill(); #ifdef DEBUG_BILL LOG("%d-%d-%d write day bill\r\n", (uint8_t)(ndate >> 16), (uint8_t)(ndate >> 8), (uint8_t)(ndate)); #endif } /////////////////////////////// 小时使用量记录 ///////////////////////////////////// // 判断依据:当前时间的年月日时 与 备份的年月日时不一致 if (bak_hour_cum_flow.date[0] != ntm.year || bak_hour_cum_flow.date[1] != ntm.month || bak_hour_cum_flow.date[2] != ntm.day || bak_hour_cum_flow.date[3] != ntm.hour) { tm_t prev_h_tm; // 计算上一个小时的时间,用于存入记录的数据头(表示该小时结束的时间点或归属) // 注意:不要直接修改 ntm,而是使用临时变量 prev_h_tm = ntm; if (prev_h_tm.hour == 0) { // 如果当前是0点,上一个小时是昨天的23点 uint32_t prev_day_date = (prev_h_tm.year << 16) | (prev_h_tm.month << 8) | prev_h_tm.day; prev_day_date = prev_day(prev_day_date); prev_h_tm.year = (uint8_t)(prev_day_date >> 16); prev_h_tm.month = (uint8_t)(prev_day_date >> 8); prev_h_tm.day = (uint8_t)(prev_day_date); prev_h_tm.hour = 23; } else { prev_h_tm.hour--; } // 存储上一个小时的使用量 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])); uint32_t prevlong = ((prev_h_tm.year << 24) | (prev_h_tm.month << 16) | (prev_h_tm.day << 8) | (prev_h_tm.hour)); // 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) if (baklong <= prevlong) { // 备份的时间必须早于当前时间的上一个小时,才记录时结数据 set_hour_used_bill(prev_h_tm.year, prev_h_tm.month, prev_h_tm.day, prev_h_tm.hour); } // 更新备份:将当前累积流量保存为新的小时起始基准 set_hour_cur_flow_bill(); // #ifdef DEBUG_BILL // 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); // #endif } ////////////////////////////// 5min使用量记录 ///////////////////////////////////// if (bak_5min_cum_flow.date[0] != ntm.year || bak_5min_cum_flow.date[1] != ntm.month || bak_5min_cum_flow.date[2] != ntm.day || bak_5min_cum_flow.date[3] != ntm.hour || bak_5min_cum_flow.date[4] / 5 != ntm.min / 5) { tm_t bak_t; bak_t.year = bak_5min_cum_flow.date[0]; bak_t.month = bak_5min_cum_flow.date[1]; bak_t.day = bak_5min_cum_flow.date[2]; bak_t.hour = bak_5min_cum_flow.date[3]; bak_t.min = bak_5min_cum_flow.date[4]; // tm_t prev_5min_tm = get_prev_5min_tm(bak_t); if (datecmp(bak_t, ntm) < 0) // 备份时间小于当前时间,则记录使用量 { set_5min_used_bill(ntm.year, ntm.month, ntm.day, ntm.hour, ntm.min); } set_5min_cur_flow_bill(); #ifdef DEBUG_BILL LOG("%d-%d-%d %d:%d write 5min bill\r\n", ntm.year, ntm.month, ntm.day, ntm.hour, ntm.min); #endif } save_cur_flow_bill(); } #ifdef DEBUG_BILL /////////////调试bill各种计量用///////////////// unsigned short dbg_bill_cnt = 0; double debug_fw = 0, debug_bw = 0, debug_vol, debug_w; void Debug_bill(void) { dbg_bill_cnt++; /////////模拟计量///////////// get_cur_flow_bill(&debug_w, &debug_fw, &debug_bw); debug_fw += 10000; //*date.day; debug_bw += 10000; //*date.day; debug_w = 0; debug_vol = 50000; //+date.hour; set_cur_flow_bill(debug_w, debug_fw, debug_bw); ///////////test month/////////////////// tm_t date, date2; if (dbg_bill_cnt == 1) { date.year = 26; date.month = 1; date.day = 1; date.hour = 0; date.min = 0; date.sec = 0; SetRtcTime(&date); } get_now_time(&date); #if DEBUG_SAVE_BAK == 1 // 1min if (date.sec >= 3 && date.sec <= 57) date.sec = 58; #elif DEBUG_5MIN_REC == 1 // 5min if (date.sec >= 3 && date.sec <= 20) { date.sec = 55 - date.min / 5; // if ((date.min % 5) != 0) // date.min = date.min - (date.min % 5); date.min += 4; date.min %= 60; } #elif DEBUG_HOUR_REC == 1 // 1hour if (date.sec >= 3 && date.sec <= 30) { date.sec = 58 - date.hour; // if((date.min != 0)date.min = 0;//date.min - (date.min%5); date.min = 59; } #elif DEBUG_DAY_REC == 1 // 1day if (date.sec >= 3 && date.sec <= 20) { date.sec = 58 - date.day; // if((date.min != 0)date.min = 0;//date.min - (date.min%5); date.min = 59; date.hour = 23; } #elif DEBUG_MONTH_REC == 1 // 1month if (date.sec >= 3 && date.sec <= 40) { date.sec = 58 - date.month; // if((date.min != 0)date.min = 0;//date.min - (date.min%5); date.min = 59; date.hour = 23; date.day = monthday[date.month - 1]; if ((date.year % 4) == 0 && date.month == 2) date.day += 1; } #endif SetRtcTime(&date); //} if (dbg_bill_cnt > 1000) while (1) ; /////////////////disp time////////////////////// #ifdef DEBUG_DISP_TIME rtc_run_t *rr; get_rtc_run(&rr); 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); // 锟斤拷示时锟斤拷 #endif } #endif int8_t SetRtcTime(tm_t *date) { if (date->month == 0 || date->month > 12) return 2; if (date->day == 0 || date->day > 31) return 2; if (date->hour > 23) return 2; if (date->min > 59) return 2; if (date->sec > 59) return 2; uint8_t year_bcd; uint8_t month_bcd; uint8_t day_bcd; uint8_t second_bcd; uint8_t minute_bcd; uint8_t hour_bcd; // year = ((NbAppFrame.data[4] << 8) | NbAppFrame.data[5]) % 2000; year_bcd = OctToBcd((uint8_t)date->year); // 自取了低8位,8位二进制转换为 month_bcd = OctToBcd(date->month); day_bcd = OctToBcd(date->day); set_rtc_date(year_bcd, month_bcd, day_bcd); // 直接操作寄存器写入日期 hour_bcd = OctToBcd(date->hour); minute_bcd = OctToBcd(date->min); second_bcd = OctToBcd(date->sec); set_rtc_time(hour_bcd, minute_bcd, second_bcd); // 保存时分秒 rtc_run_t tm; tm.year = date->year; tm.month = date->month; tm.day = date->day; tm.hour = date->hour; tm.minute = date->min; tm.second = date->sec; set_rtc_run(&tm); return 1; } void clear_log(void) { uint32_t addr = ALARM_START_ADDR; // 计算日志区域的总大小 uint32_t end_addr = ALARM_START_ADDR + (uint32_t)MAX_ALARM_NUM * ALARM_DATA_SIZE; if (end_addr <= addr) { LOG("Clear log error: Invalid address range.\r\n"); return; } uint32_t total_size = end_addr - addr; // 定义单次写入块大小,与 clear_all_record 保持一致 // write_eeprom_para 内部缓冲区支持最大 128 字节有效数据 #define LOG_CLEAR_BLOCK_SIZE 128 uint8_t dat[LOG_CLEAR_BLOCK_SIZE]; memset(dat, 0xFF, LOG_CLEAR_BLOCK_SIZE); LOG("Start clearing logs (%d bytes)...\r\n", total_size); uint32_t processed = 0; uint8_t last_progress = 0; uint8_t ret; while (processed < total_size) { // 计算本次实际写入长度 uint32_t remaining = total_size - processed; uint16_t write_len = (remaining > LOG_CLEAR_BLOCK_SIZE) ? LOG_CLEAR_BLOCK_SIZE : (uint16_t)remaining; // 执行写入 ret = write_eeprom_para(addr, dat, write_len); if (ret != 0) { LOG("EEPROM log clear error at addr %d\r\n", addr); // 可根据需求选择 break 或继续 } addr += write_len; processed += write_len; // 计算进度百分比 uint8_t progress = (uint8_t)(processed * 100 / total_size); // 每 10% 打印一次进度 if (progress >= last_progress + 10) { last_progress = progress; LOG("Clearing logs... %d%%\r\n", progress); // 重要:长时间操作需喂狗 #ifdef APP_USING_SWDG WDG_Feed(); #endif } } LOG("Clear log complete.\r\n"); } extern void clr_max_flow_rate(void); extern void clr_max_flow_rate_all(void); void clear_all_record(void) { // 定义单次写入块大小 (128字节效率较高且栈安全) clear_bottom_data(); clr_max_flow_rate_all(); // 清最高瞬时流量 clr_bill_struct_data(); #define CLEAR_BLOCK_SIZE 128 uint8_t dat[CLEAR_BLOCK_SIZE]; memset(dat, 0xFF, CLEAR_BLOCK_SIZE); LOG("Start clearing all records and backups...\r\n"); // --- 第一部分:清除原有账单记录区域 (MONTH_BILL_START_ADDR 到 END_RECORD_ADDR) --- uint32_t addr = MONTH_BILL_START_ADDR; uint32_t end_addr = END_RECORD_ADDR; if (end_addr > addr) { uint32_t total_size = end_addr - addr; uint32_t processed = 0; uint8_t last_progress = 0; uint8_t ret; LOG("Clearing Bill Records (0x%x - 0x%x)...\r\n", addr, end_addr); while (processed < total_size) { uint32_t remaining = total_size - processed; uint16_t write_len = (remaining > CLEAR_BLOCK_SIZE) ? CLEAR_BLOCK_SIZE : (uint16_t)remaining; ret = write_eeprom_para(addr, dat, write_len); if (ret != 0) { LOG("EEPROM clear error at addr %d\r\n", addr); } addr += write_len; processed += write_len; uint8_t progress = (uint8_t)(processed * 100 / total_size); if (progress >= last_progress + 20) { last_progress = progress; LOG(" Records: %d%%\r\n", progress); #ifdef APP_USING_SWDG WDG_Feed(); #endif } } LOG("Bill Records cleared.\r\n"); } // --- 第二部分:清除备份数据区域 (从 PRE_MONTH_COW_BAK_ADDR 开始) --- // 计算备份区域的总长度: // 1. 月/日/时备份: 3 * COW_BAK_DATA_SIZE (3 * 32 = 96 bytes) // 2. 5分钟备份: BAK_5MIN_NUM * BAK_5MIN_SIZE (8 * 32 = 256 bytes) // 总长度 = 96 + 256 = 352 bytes (0x160) addr = PRE_MONTH_COW_BAK_ADDR; uint32_t backup_total_size = (3 * COW_BAK_DATA_SIZE) + (BAK_5MIN_NUM * BAK_5MIN_SIZE); if (backup_total_size > 0) { uint32_t processed = 0; LOG("Clearing Backup Area (Start: 0x%x, Size: %d bytes)...\r\n", addr, backup_total_size); while (processed < backup_total_size) { uint32_t remaining = backup_total_size - processed; uint16_t write_len = (remaining > CLEAR_BLOCK_SIZE) ? CLEAR_BLOCK_SIZE : (uint16_t)remaining; write_eeprom_para(addr, dat, write_len); addr += write_len; processed += write_len; // 备份区域较小,每完成一次循环或最后喂狗即可,也可按比例打印 #ifdef APP_USING_SWDG WDG_Feed(); #endif } LOG("Backup Area cleared.\r\n"); } LOG("Clear all records and backups complete.\r\n"); } void clear_bottom_data(void) { // 清除底读 set_cur_flow_bill(0, 0, 0); save_cur_flow_flag = 1; } #ifdef DEBUG_BILL static uint8_t verify_eeprom_region(uint32_t start_addr, uint32_t size, const char *name) { #define VERIFY_BUF_SIZE 128 uint8_t buf[VERIFY_BUF_SIZE]; uint32_t processed = 0; uint8_t ret = 0; // 0: OK, 1: Error LOG("Verifying %s (Addr: 0x%x, Size: %d)... ", name, start_addr, size); while (processed < size) { uint32_t remaining = size - processed; uint16_t read_len = (remaining > VERIFY_BUF_SIZE) ? VERIFY_BUF_SIZE : (uint16_t)remaining; // 批量读取 if (eeprom_MassRead(buf, start_addr + processed, read_len) != 0) { LOG("READ ERR\r\n"); return 1; } // 检查是否全为 0xFF for (uint16_t i = 0; i < read_len; i++) { if (buf[i] != 0xFF) { LOG("FAIL at offset %d (Byte: 0x%X)\r\n", processed + i, buf[i]); ret = 1; // 可以选择继续检查以发现更多错误,或者直接返回 // return 1; } } processed += read_len; // 防止看门狗复位,特别是大区域验证时 #ifdef APP_USING_SWDG if (processed % (VERIFY_BUF_SIZE * 10) == 0) { WDG_Feed(); } #endif } if (ret == 0) { LOG("OK\r\n"); } return ret; } /** * @brief 验证清除操作的结果 */ void verify_clear_operations(void) { LOG("--- Start Verification of Clear Operations ---\r\n"); uint8_t err_cnt = 0; // 1. 验证账单记录区域 if (END_RECORD_ADDR > MONTH_BILL_START_ADDR) { if (verify_eeprom_region(MONTH_BILL_START_ADDR, END_RECORD_ADDR - MONTH_BILL_START_ADDR, "Bill Records") != 0) { err_cnt++; } } // 2. 验证备份区域 (从 PRE_MONTH_COW_BAK_ADDR 开始) // 长度 = 月/日/时备份 (3 * 32) + 5分钟备份 (8 * 32) = 96 + 256 = 352 字节 uint32_t backup_size = (3 * COW_BAK_DATA_SIZE) + (BAK_5MIN_NUM * BAK_5MIN_SIZE); if (verify_eeprom_region(PRE_MONTH_COW_BAK_ADDR, backup_size, "Backup Area") != 0) { err_cnt++; } // 3. 验证日志区域 uint32_t log_size = (uint32_t)MAX_ALARM_NUM * ALARM_DATA_SIZE; if (verify_eeprom_region(ALARM_START_ADDR, log_size, "Alarm Logs") != 0) { err_cnt++; } if (err_cnt == 0) { LOG("--- All Verifications PASSED ---\r\n"); } else { LOG("--- Verification FAILED with %d errors ---\r\n", err_cnt); } } #endif void clr_bill_struct_data(void) { memset(&bak_month_cum_flow, 0, sizeof(bak_month_cum_flow)); memset(&bak_day_cum_flow, 0, sizeof(bak_day_cum_flow)); memset(&bak_hour_cum_flow, 0, sizeof(bak_hour_cum_flow)); bak_5min_cum_flow.fw_cum_flow = 0; bak_5min_cum_flow.bw_cum_flow = 0; cum_flow_index.bw = 0; cum_flow_index.fw = 0; }