alarm.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. #include "alarm.h"
  2. #include "prj_com.h"
  3. #include "rtc_run.h"
  4. #include "eeprom.h"
  5. #include "bill.h"
  6. uint32_t alarm_bits;
  7. static uint8_t alarm_flag = 0;
  8. static uint8_t alarm_array[ERR_END * 2]; // 褰撳墠鐨勫疄鏃舵姤璀︾姸鎬?鍙戠敓鍚庡€?, 鍐欏叆鎶ヨ?﹀悗娓呴??
  9. static uint32_t alarm_args[ERR_END * 2]; // 鎶ヨ?︽椂浜х敓鐨勫弬鏁?
  10. static uint8_t alarm_write_ptr = 0;
  11. ALARM_INFO_DEF alarm_info;
  12. // 123
  13. // 123456789
  14. // 顶顶顶顶
  15. // 666
  16. /// 房东方
  17. ///////sfsdfgsdfsdfgsdfgsdfsdfgsdfg
  18. void alarm_init(void)
  19. {
  20. alarm_bits = 0;
  21. alarm_flag = 0;
  22. memset(alarm_array, 0, sizeof(alarm_array));
  23. memset(alarm_args, 0, sizeof(alarm_args));
  24. get_alarm_info(&alarm_info);
  25. }
  26. void get_alarm_info(ALARM_INFO_DEF *info)
  27. {
  28. uint32_t addr = ALARM_INFO_ADDR;
  29. uint8_t need_reset = 0;
  30. // 1. 尝试读取,并检查返回值(假设 read_eeprom_para 返回 0 表示成功)
  31. if (read_eeprom_para(addr, (uint8_t *)info, sizeof(ALARM_INFO_DEF)) != 0)
  32. {
  33. need_reset = 1; // 读取失败,强制重置
  34. }
  35. else
  36. {
  37. // 2. 基本合法性校验
  38. // 注意:num 可以等于 MAX_ALARM_NUM (满),所以用 > 而不是 >=
  39. if (info->start >= MAX_ALARM_NUM ||
  40. info->end >= MAX_ALARM_NUM ||
  41. info->num > MAX_ALARM_NUM ||
  42. info->flag != 0xaa)
  43. {
  44. need_reset = 1;
  45. }
  46. else
  47. {
  48. // 3. 【重要】一致性校验
  49. // 根据 start 和 end 重新计算理论上的 num
  50. uint8_t calculated_num;
  51. if (info->end >= info->start)
  52. {
  53. calculated_num = info->end - info->start;
  54. }
  55. else
  56. {
  57. calculated_num = MAX_ALARM_NUM - info->start + info->end;
  58. }
  59. // 如果存储的 num 与计算出的 num 不一致,说明数据损坏
  60. // 注意:这里有一个特例,如果缓冲区满,num 应该等于 MAX_ALARM_NUM
  61. // 但在环形队列中,仅凭 start/end 无法区分“空”和“满”(如果都不存 num)
  62. // 既然我们存了 num,就以 num 为准,但要确保 num 不超过 MAX
  63. // 更严格的校验是:如果 num < MAX,则 calculated_num 必须等于 num
  64. if (info->num < MAX_ALARM_NUM && calculated_num != info->num)
  65. {
  66. need_reset = 1;
  67. }
  68. // 如果 num == MAX_ALARM_NUM,我们信任它是满的,不做额外校验
  69. }
  70. }
  71. if (need_reset)
  72. {
  73. info->start = 0;
  74. info->end = 0;
  75. info->flag = 0xaa;
  76. info->num = 0;
  77. write_eeprom_para(addr, (uint8_t *)info, sizeof(ALARM_INFO_DEF));
  78. }
  79. }
  80. uint8_t get_alarm_num(void)
  81. {
  82. return alarm_info.num;
  83. }
  84. void all_alarm_status(uint32_t **bits)
  85. {
  86. *bits = &alarm_bits;
  87. }
  88. uint8_t alarm_status(uint8_t err_no)
  89. {
  90. return BIT_VAL(alarm_bits, err_no);
  91. }
  92. void write_alarm(uint8_t err_no, uint8_t type, uint32_t arg)
  93. {
  94. alarm_t alarm;
  95. rtc_run_t *rr;
  96. // 1. 获取当前时间
  97. get_rtc_run(&rr);
  98. // 2. 构建报警记录
  99. alarm.flag = 1;
  100. alarm.err_no = err_no;
  101. alarm.type = type;
  102. alarm.arg[0] = (uint8_t)arg;
  103. alarm.arg[1] = (uint8_t)(arg >> 8);
  104. alarm.arg[2] = (uint8_t)(arg >> 16);
  105. alarm.arg[3] = (uint8_t)(arg >> 24);
  106. alarm.time[0] = 0x14;
  107. alarm.time[1] = rr->year;
  108. alarm.time[2] = rr->month;
  109. alarm.time[3] = rr->day;
  110. alarm.time[4] = rr->hour;
  111. alarm.time[5] = rr->minute;
  112. alarm.time[6] = rr->second;
  113. // 3. 写入 EEPROM
  114. uint32_t addr = ALARM_START_ADDR + alarm_info.end * ALARM_DATA_SIZE;
  115. write_eeprom(addr, (uint8_t *)&alarm, sizeof(alarm_t));
  116. // 4. 更新指针
  117. uint8_t next_end = alarm_info.end + 1;
  118. if (next_end >= MAX_ALARM_NUM)
  119. {
  120. next_end = 0;
  121. }
  122. // 判断是否覆盖(缓冲区满)
  123. // 如果下一个写入位置追上了 start,说明缓冲区满了
  124. if (next_end == alarm_info.start)
  125. {
  126. // 移动 start 指针,丢弃最旧的一条数据
  127. alarm_info.start++;
  128. if (alarm_info.start >= MAX_ALARM_NUM)
  129. {
  130. alarm_info.start = 0;
  131. }
  132. // 关键点:满状态下,数量恒定为最大值
  133. alarm_info.num = MAX_ALARM_NUM;
  134. }
  135. else
  136. {
  137. // 缓冲区未满,数量加 1
  138. alarm_info.num++;
  139. }
  140. alarm_info.end = next_end;
  141. // 5. 保存元数据
  142. write_eeprom_para(ALARM_INFO_ADDR, (uint8_t *)&alarm_info, sizeof(ALARM_INFO_DEF));
  143. }
  144. uint8_t read_alarm(uint8_t num, alarm_t *alarm)
  145. {
  146. memset((uint8_t *)alarm, 0, sizeof(alarm_t));
  147. uint8_t ser = get_alarm_num(); // 获取当前有效数量
  148. // 如果请求的索引超出范围,返回失败
  149. if (num >= ser)
  150. return 0;
  151. // 计算物理索引:从 end-1 开始向前数 num 个
  152. // 加上 MAX_ALARM_NUM 再取模是为了处理负数下溢
  153. ser = (alarm_info.end - 1 - num + MAX_ALARM_NUM) % MAX_ALARM_NUM;
  154. uint32_t addr = ALARM_START_ADDR + ALARM_DATA_SIZE * ser;
  155. uint8_t ret = read_eeprom(addr, (uint8_t *)alarm, sizeof(alarm_t));
  156. return (ret == 0);
  157. }
  158. void set_alarm_info(uint8_t err_no, uint8_t type, uint32_t arg)
  159. {
  160. uint8_t idx;
  161. idx = ALARM_INDEX(err_no, type);
  162. alarm_array[idx] = 1;
  163. alarm_args[idx] = arg;
  164. alarm_flag = 1;
  165. }
  166. // type 1-alarm 0-alarm recovery
  167. void Alarm(uint8_t err_no, uint8_t type, uint32_t arg)
  168. {
  169. if (type)
  170. {
  171. if (!BIT_VAL(alarm_bits, err_no))
  172. {
  173. SET_BIT_WARN(alarm_bits, err_no);
  174. set_alarm_info(err_no, type, arg);
  175. }
  176. }
  177. else
  178. {
  179. if (BIT_VAL(alarm_bits, err_no))
  180. {
  181. RESET_BIT_WARN(alarm_bits, err_no);
  182. set_alarm_info(err_no, type, arg);
  183. }
  184. }
  185. }
  186. void AlarmHandle(void)
  187. {
  188. uint16_t i;
  189. uint8_t err_no;
  190. uint8_t type;
  191. if(StartUp < 10)return;//wxl2026-5-18
  192. if (alarm_flag == 0)
  193. {
  194. return;
  195. }
  196. for (i = 0; i < ERR_END * 2; i++)
  197. {
  198. if (alarm_array[i] == 1)
  199. {
  200. err_no = i >> 1;
  201. type = i % 2;
  202. write_alarm(err_no, type, alarm_args[i]);
  203. alarm_array[i] = 0;
  204. }
  205. }
  206. alarm_flag = 0;
  207. }