| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235 |
- #include "alarm.h"
- #include "prj_com.h"
- #include "rtc_run.h"
- #include "eeprom.h"
- #include "bill.h"
- uint32_t alarm_bits;
- static uint8_t alarm_flag = 0;
- static uint8_t alarm_array[ERR_END * 2]; // 褰撳墠鐨勫疄鏃舵姤璀︾姸鎬?鍙戠敓鍚庡€?, 鍐欏叆鎶ヨ?﹀悗娓呴??
- static uint32_t alarm_args[ERR_END * 2]; // 鎶ヨ?︽椂浜х敓鐨勫弬鏁?
- static uint8_t alarm_write_ptr = 0;
- ALARM_INFO_DEF alarm_info;
- // 123
- // 123456789
- // 顶顶顶顶
- // 666
- /// 房东方
- ///////sfsdfgsdfsdfgsdfgsdfsdfgsdfg
- void alarm_init(void)
- {
- alarm_bits = 0;
- alarm_flag = 0;
- memset(alarm_array, 0, sizeof(alarm_array));
- memset(alarm_args, 0, sizeof(alarm_args));
- get_alarm_info(&alarm_info);
- }
- void get_alarm_info(ALARM_INFO_DEF *info)
- {
- uint32_t addr = ALARM_INFO_ADDR;
- uint8_t need_reset = 0;
- // 1. 尝试读取,并检查返回值(假设 read_eeprom_para 返回 0 表示成功)
- if (read_eeprom_para(addr, (uint8_t *)info, sizeof(ALARM_INFO_DEF)) != 0)
- {
- need_reset = 1; // 读取失败,强制重置
- }
- else
- {
- // 2. 基本合法性校验
- // 注意:num 可以等于 MAX_ALARM_NUM (满),所以用 > 而不是 >=
- if (info->start >= MAX_ALARM_NUM ||
- info->end >= MAX_ALARM_NUM ||
- info->num > MAX_ALARM_NUM ||
- info->flag != 0xaa)
- {
- need_reset = 1;
- }
- else
- {
- // 3. 【重要】一致性校验
- // 根据 start 和 end 重新计算理论上的 num
- uint8_t calculated_num;
- if (info->end >= info->start)
- {
- calculated_num = info->end - info->start;
- }
- else
- {
- calculated_num = MAX_ALARM_NUM - info->start + info->end;
- }
- // 如果存储的 num 与计算出的 num 不一致,说明数据损坏
- // 注意:这里有一个特例,如果缓冲区满,num 应该等于 MAX_ALARM_NUM
- // 但在环形队列中,仅凭 start/end 无法区分“空”和“满”(如果都不存 num)
- // 既然我们存了 num,就以 num 为准,但要确保 num 不超过 MAX
- // 更严格的校验是:如果 num < MAX,则 calculated_num 必须等于 num
- if (info->num < MAX_ALARM_NUM && calculated_num != info->num)
- {
- need_reset = 1;
- }
- // 如果 num == MAX_ALARM_NUM,我们信任它是满的,不做额外校验
- }
- }
- if (need_reset)
- {
- info->start = 0;
- info->end = 0;
- info->flag = 0xaa;
- info->num = 0;
- write_eeprom_para(addr, (uint8_t *)info, sizeof(ALARM_INFO_DEF));
- }
- }
- uint8_t get_alarm_num(void)
- {
- return alarm_info.num;
- }
- void all_alarm_status(uint32_t **bits)
- {
- *bits = &alarm_bits;
- }
- uint8_t alarm_status(uint8_t err_no)
- {
- return BIT_VAL(alarm_bits, err_no);
- }
- void write_alarm(uint8_t err_no, uint8_t type, uint32_t arg)
- {
- alarm_t alarm;
- rtc_run_t *rr;
- // 1. 获取当前时间
- get_rtc_run(&rr);
- // 2. 构建报警记录
- alarm.flag = 1;
- alarm.err_no = err_no;
- alarm.type = type;
- alarm.arg[0] = (uint8_t)arg;
- alarm.arg[1] = (uint8_t)(arg >> 8);
- alarm.arg[2] = (uint8_t)(arg >> 16);
- alarm.arg[3] = (uint8_t)(arg >> 24);
- alarm.time[0] = 0x14;
- alarm.time[1] = rr->year;
- alarm.time[2] = rr->month;
- alarm.time[3] = rr->day;
- alarm.time[4] = rr->hour;
- alarm.time[5] = rr->minute;
- alarm.time[6] = rr->second;
- // 3. 写入 EEPROM
- uint32_t addr = ALARM_START_ADDR + alarm_info.end * ALARM_DATA_SIZE;
- write_eeprom(addr, (uint8_t *)&alarm, sizeof(alarm_t));
- // 4. 更新指针
- uint8_t next_end = alarm_info.end + 1;
- if (next_end >= MAX_ALARM_NUM)
- {
- next_end = 0;
- }
- // 判断是否覆盖(缓冲区满)
- // 如果下一个写入位置追上了 start,说明缓冲区满了
- if (next_end == alarm_info.start)
- {
- // 移动 start 指针,丢弃最旧的一条数据
- alarm_info.start++;
- if (alarm_info.start >= MAX_ALARM_NUM)
- {
- alarm_info.start = 0;
- }
- // 关键点:满状态下,数量恒定为最大值
- alarm_info.num = MAX_ALARM_NUM;
- }
- else
- {
- // 缓冲区未满,数量加 1
- alarm_info.num++;
- }
- alarm_info.end = next_end;
- // 5. 保存元数据
- write_eeprom_para(ALARM_INFO_ADDR, (uint8_t *)&alarm_info, sizeof(ALARM_INFO_DEF));
- }
- uint8_t read_alarm(uint8_t num, alarm_t *alarm)
- {
- memset((uint8_t *)alarm, 0, sizeof(alarm_t));
- uint8_t ser = get_alarm_num(); // 获取当前有效数量
- // 如果请求的索引超出范围,返回失败
- if (num >= ser)
- return 0;
- // 计算物理索引:从 end-1 开始向前数 num 个
- // 加上 MAX_ALARM_NUM 再取模是为了处理负数下溢
- ser = (alarm_info.end - 1 - num + MAX_ALARM_NUM) % MAX_ALARM_NUM;
- uint32_t addr = ALARM_START_ADDR + ALARM_DATA_SIZE * ser;
- uint8_t ret = read_eeprom(addr, (uint8_t *)alarm, sizeof(alarm_t));
- return (ret == 0);
- }
- void set_alarm_info(uint8_t err_no, uint8_t type, uint32_t arg)
- {
- uint8_t idx;
- idx = ALARM_INDEX(err_no, type);
- alarm_array[idx] = 1;
- alarm_args[idx] = arg;
- alarm_flag = 1;
- }
- // type 1-alarm 0-alarm recovery
- void Alarm(uint8_t err_no, uint8_t type, uint32_t arg)
- {
- if (type)
- {
- if (!BIT_VAL(alarm_bits, err_no))
- {
- SET_BIT_WARN(alarm_bits, err_no);
- set_alarm_info(err_no, type, arg);
- }
- }
- else
- {
- if (BIT_VAL(alarm_bits, err_no))
- {
- RESET_BIT_WARN(alarm_bits, err_no);
- set_alarm_info(err_no, type, arg);
- }
- }
- }
- void AlarmHandle(void)
- {
- uint16_t i;
- uint8_t err_no;
- uint8_t type;
- if(StartUp < 10)return;//wxl2026-5-18
- if (alarm_flag == 0)
- {
- return;
- }
- for (i = 0; i < ERR_END * 2; i++)
- {
- if (alarm_array[i] == 1)
- {
- err_no = i >> 1;
- type = i % 2;
- write_alarm(err_no, type, alarm_args[i]);
- alarm_array[i] = 0;
- }
- }
- alarm_flag = 0;
- }
|