hw_detect.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  1. /*
  2. * Hardware Detection Module - v2.3
  3. *
  4. * 功能:检测硬件外设状态
  5. * - 倾倒开关(PB10引脚下降沿中断检测,100ms轮询)
  6. * - 雨控检测(PC0输出高电平,PC1输入检测,每30秒检测一次)
  7. * - 单线程设计,优先级9,确保倾倒检测及时响应
  8. *
  9. * Version: 2.3.0
  10. */
  11. /*********************↓ include ↓************************/
  12. #define DBG_TAG "HW"
  13. #define DBG_LVL DBG_INFO
  14. #include <rtdbg.h>
  15. #include <rtthread.h>
  16. #include <rtdevice.h>
  17. #include <board.h>
  18. #include "ecode.h"
  19. #include "ym310_protecl.h" /* for sys_sta and sys_sta */
  20. /*********************↑ include ↑************************/
  21. /*********************↓ define ↓************************/
  22. /* 倾倒开关配置 */
  23. #define TILT_SWITCH_PIN GET_PIN(B, 10) /* PB10引脚 */
  24. #define TILT_IRQ_MODE PIN_IRQ_MODE_FALLING /* 下降沿触发 */
  25. #define TILT_DEBOUNCE_MS 50 /* 防抖时间(毫秒) */
  26. #define TILT_CLEAR_TIMEOUT_MS (60 * 1000) /* 保护清除时间(毫秒)- 60秒 */
  27. #define TILT_POLL_INTERVAL_MS 100 /* 轮询周期(毫秒) */
  28. #define TILT_TRIGGER_MS 1000 /* 持续触发时间(毫秒)- 1秒 */ //
  29. /* 雨控检测配置 */
  30. #define RAIN_OUT_PIN GET_PIN(C, 0) /* PC0 输出引脚 */
  31. #define RAIN_IN_PIN GET_PIN(C, 1) /* PC1 输入引脚 */
  32. #define RAIN_DETECT_INTERVAL_MS (20 * 1000) /* 检测间隔(毫秒)- 30秒 */
  33. #define RAIN_CLEAR_TIMEOUT_MS (3 * 60 * 1000) /* 保护清除时间(毫秒)- 3分钟 */
  34. #define RAIN_POWER_ON_DELAY_MS (10 * 1000) /* 上电后延迟(毫秒) */
  35. /*********************↑ define ↑************************/
  36. /*********************↓ 静态变量 ↓************************/
  37. /* 倾倒开关相关 */
  38. static rt_tick_t s_tilt_last_tick = 0; /* 上次触发时间 */
  39. static rt_tick_t s_tilt_start_tick = 0; /* 当前倾倒开始时间 */
  40. static struct rt_semaphore tilt_sem; /* 中断信号量 */
  41. static rt_tick_t s_tilt_trigger_start = 0; /* 倾倒持续开始时间(新增)*/
  42. /* 雨控检测相关 */
  43. static rt_tick_t s_rain_last_detect_tick = 0; /* 上次检测时间 */
  44. static rt_tick_t s_rain_start_tick = 0; /* 雨控开始时间 */
  45. /* 线程相关 */
  46. static rt_thread_t s_hw_thread = RT_NULL; /* 工作线程句柄 */
  47. static rt_bool_t s_hw_running = RT_FALSE; /* 线程运行标志 */
  48. /*********************↑ 静态变量 ↑************************/
  49. extern SYS_STATUS sys_sta;
  50. extern void report_now(void);
  51. /*********************↓ 倾倒开关函数 ↓***********************/
  52. /**
  53. * @brief 倾倒开关中断服务函数
  54. */
  55. static void tilt_isr(void *args)
  56. {
  57. rt_tick_t current_tick = rt_tick_get();
  58. /* 防抖处理 */
  59. if ((current_tick - s_tilt_last_tick) < rt_tick_from_millisecond(TILT_DEBOUNCE_MS))
  60. {
  61. return;
  62. }
  63. s_tilt_last_tick = current_tick;
  64. /* 通知工作线程处理 */
  65. rt_sem_release(&tilt_sem);
  66. }
  67. /**
  68. * @brief 处理倾倒开关检测(持续1秒才触发保护)
  69. */
  70. static void tilt_process(void)
  71. {
  72. int pin_level;
  73. uint32_t now_ms;
  74. uint32_t elapsed;
  75. pin_level = rt_pin_read(TILT_SWITCH_PIN);
  76. now_ms = rt_tick_get_millisecond();
  77. /* ========== 触发逻辑:持续1秒触发保护 ========== */
  78. if (pin_level == PIN_LOW)
  79. {
  80. /* 倾倒状态:开始计时或继续计时 */
  81. if (s_tilt_trigger_start == 0)
  82. {
  83. s_tilt_trigger_start = now_ms;
  84. LOG_D("[TILT] Tilt detected, start counting...");
  85. }
  86. elapsed = now_ms - s_tilt_trigger_start;
  87. if (elapsed >= TILT_TRIGGER_MS)
  88. {
  89. /* 持续倾倒超过1秒,触发保护 */
  90. if (sys_sta.tilt_protect != VALID)
  91. {
  92. sys_sta.tilt_protect = VALID;
  93. s_tilt_start_tick = now_ms; /* 记录保护触发时间 */
  94. LOG_W("[TILT] Triggered! Tilt持续 %lu ms, protect = VALID", elapsed);
  95. Recode_e_code(e_tilt_trigger, 1, "倾倒开关触发");
  96. gpio_lamp_ctrl(0);
  97. gpio_hv_ctrl(0);
  98. report_now();
  99. }
  100. /* 保护已触发,不需要额外操作 */
  101. }
  102. }
  103. else
  104. {
  105. /* 非倾倒状态:重置触发计时器 */
  106. if (s_tilt_trigger_start != 0)
  107. {
  108. LOG_D("[TILT] Tilt cleared, reset counter");
  109. s_tilt_trigger_start = 0;
  110. }
  111. }
  112. /* ========== 清除逻辑:倾倒恢复后60秒清除保护 ========== */
  113. if (sys_sta.tilt_protect == VALID)
  114. {
  115. if (pin_level != PIN_LOW)
  116. {
  117. /* 当前未倾倒,开始或继续清除计时 */
  118. if (s_tilt_start_tick == 0)
  119. {
  120. /* 刚恢复,开始计时 */
  121. s_tilt_start_tick = now_ms;
  122. LOG_D("[TILT] Recovered, start clear countdown");
  123. }
  124. elapsed = now_ms - s_tilt_start_tick;
  125. if (elapsed >= TILT_CLEAR_TIMEOUT_MS)
  126. {
  127. /* 恢复时间达到60秒,清除保护 */
  128. sys_sta.tilt_protect = 0;
  129. s_tilt_start_tick = 0;
  130. s_tilt_trigger_start = 0;
  131. LOG_I("[TILT] Protect cleared after %d sec", TILT_CLEAR_TIMEOUT_MS / 1000);
  132. Recode_e_code(e_tilt_restore, 0, "倾倒保护清除");
  133. rt_thread_mdelay(1000);
  134. report_now();
  135. }
  136. }
  137. else
  138. {
  139. /* 当前仍在倾倒,重置清除计时器(不清除保护)*/
  140. if (s_tilt_start_tick != 0)
  141. {
  142. LOG_D("[TILT] Still tilted, reset clear timer");
  143. s_tilt_start_tick = 0;
  144. }
  145. }
  146. }
  147. }
  148. /**
  149. * @brief 初始化倾倒开关
  150. */
  151. static void tilt_init(void)
  152. {
  153. rt_err_t ret;
  154. int pin_level;
  155. // LOG_I("[TILT] Initializing on PB10...");
  156. ret = rt_sem_init(&tilt_sem, "tilt_sem", 0, RT_IPC_FLAG_FIFO);
  157. if (ret != RT_EOK)
  158. {
  159. LOG_E("[TILT] Failed to init semaphore");
  160. return;
  161. }
  162. rt_pin_mode(TILT_SWITCH_PIN, PIN_MODE_INPUT_PULLUP);
  163. pin_level = rt_pin_read(TILT_SWITCH_PIN);
  164. if (pin_level == PIN_LOW)
  165. {
  166. LOG_W("[TILT] Initially TRIGGERED!");
  167. sys_sta.tilt_protect = VALID;
  168. s_tilt_start_tick = rt_tick_get();
  169. Recode_e_code(e_tilt_trigger, 1, "倾倒开关初始状态为触发");
  170. gpio_lamp_ctrl(0);
  171. gpio_hv_ctrl(0);
  172. report_now();
  173. }
  174. else
  175. {
  176. // LOG_I("[TILT] Initially normal");
  177. sys_sta.tilt_protect = 0;
  178. s_tilt_start_tick = 0;
  179. }
  180. ret = rt_pin_attach_irq(TILT_SWITCH_PIN, TILT_IRQ_MODE, tilt_isr, NULL);
  181. if (ret != RT_EOK)
  182. {
  183. LOG_E("[TILT] Failed to attach IRQ");
  184. return;
  185. }
  186. ret = rt_pin_irq_enable(TILT_SWITCH_PIN, PIN_IRQ_ENABLE);
  187. if (ret != RT_EOK)
  188. {
  189. LOG_E("[TILT] Failed to enable IRQ");
  190. return;
  191. }
  192. // LOG_I("[TILT] Initialized (poll %dms, clear after %d sec)",
  193. // TILT_POLL_INTERVAL_MS, TILT_CLEAR_TIMEOUT_MS / 1000);
  194. }
  195. /*********************↑ 倾倒开关函数 ↑***********************/
  196. /*********************↓ 雨控检测函数 ↓***********************/
  197. /**
  198. * @brief 执行一次雨控检测
  199. * @return 1:有雨,0:无雨
  200. */
  201. static int rain_detect_once(void)
  202. {
  203. int result = 0;
  204. int in_level = rt_pin_read(RAIN_IN_PIN);
  205. if (in_level == PIN_LOW)
  206. {
  207. result = 1;
  208. LOG_D("[RAIN] Detected! PC1=LOW");
  209. }
  210. else
  211. {
  212. LOG_D("[RAIN] No rain, PC1=HIGH");
  213. }
  214. rt_pin_mode(RAIN_OUT_PIN, PIN_MODE_INPUT);
  215. return result;
  216. }
  217. /**
  218. * @brief 处理雨控检测
  219. */
  220. static void rain_process(void)
  221. {
  222. int has_rain;
  223. rt_tick_t now = rt_tick_get();
  224. static rt_tick_t ready = 0;
  225. if ((now - s_rain_last_detect_tick) < rt_tick_from_millisecond(RAIN_DETECT_INTERVAL_MS))
  226. {
  227. return;
  228. }
  229. if (ready == 0)
  230. {
  231. // LOG_I(" RAIN:time take ");
  232. ready = now;
  233. }
  234. rt_pin_mode(RAIN_OUT_PIN, PIN_MODE_OUTPUT);
  235. rt_pin_write(RAIN_OUT_PIN, PIN_HIGH);
  236. rt_pin_mode(RAIN_IN_PIN, PIN_MODE_INPUT_PULLUP);
  237. if ((now - ready) < rt_tick_from_millisecond(RAIN_POWER_ON_DELAY_MS))
  238. {
  239. return;
  240. }
  241. // LOG_I(" RAIN:time start ");
  242. ready = 0;
  243. s_rain_last_detect_tick = now;
  244. has_rain = rain_detect_once();
  245. if (has_rain)
  246. {
  247. if (sys_sta.rain_protect != VALID)
  248. {
  249. sys_sta.rain_protect = VALID;
  250. s_rain_start_tick = now;
  251. // LOG_W("[RAIN] Detected! protect = VALID");
  252. Recode_e_code(e_rain_trigger, 1, "雨控触发");
  253. rt_thread_mdelay(1000);
  254. report_now();
  255. }
  256. else
  257. {
  258. s_rain_start_tick = now;
  259. LOG_D("[RAIN] Persists, protect extended");
  260. }
  261. }
  262. else
  263. {
  264. if (sys_sta.rain_protect == VALID && s_rain_start_tick != 0)
  265. {
  266. if ((now - s_rain_start_tick) >= rt_tick_from_millisecond(RAIN_CLEAR_TIMEOUT_MS))
  267. {
  268. sys_sta.rain_protect = 0;
  269. s_rain_start_tick = 0;
  270. LOG_I("[RAIN] Protect cleared after %d min", RAIN_CLEAR_TIMEOUT_MS / 60000);
  271. Recode_e_code(e_rain_restore, 0, "雨控保护清除");
  272. rt_thread_mdelay(1000);
  273. report_now();
  274. }
  275. }
  276. }
  277. }
  278. /**
  279. * @brief 初始化雨控检测
  280. */
  281. static void rain_init(void)
  282. {
  283. // LOG_I("[RAIN] Initializing...");
  284. rt_pin_mode(RAIN_OUT_PIN, PIN_MODE_INPUT);
  285. rt_pin_mode(RAIN_IN_PIN, PIN_MODE_INPUT_PULLUP);
  286. int has_rain = rain_detect_once();
  287. if (has_rain)
  288. {
  289. LOG_W("[RAIN] Initially detected!");
  290. sys_sta.rain_protect = VALID;
  291. s_rain_start_tick = rt_tick_get();
  292. Recode_e_code(e_rain_trigger, 1, "雨控初始状态为触发");
  293. }
  294. else
  295. {
  296. // LOG_I("[RAIN] Initially normal");
  297. sys_sta.rain_protect = 0;
  298. s_rain_start_tick = 0;
  299. }
  300. s_rain_last_detect_tick = rt_tick_get();
  301. // LOG_I("[RAIN] Initialized (detect every %d sec, clear after %d min)",
  302. // RAIN_DETECT_INTERVAL_MS / 1000, RAIN_CLEAR_TIMEOUT_MS / 60000);
  303. }
  304. /*********************↑ 雨控检测函数 ↑***********************/
  305. /*********************↓ 工作线程 ↓***********************/
  306. /**
  307. * @brief 硬件检测工作线程(优先级9,确保倾倒及时响应)
  308. */
  309. static void hw_work_handler(void *parameter)
  310. {
  311. // LOG_I("Hardware monitor thread started (priority 9)");
  312. while (1)
  313. {
  314. if (rt_sem_take(&tilt_sem, rt_tick_from_millisecond(TILT_POLL_INTERVAL_MS)) == RT_EOK)
  315. {
  316. tilt_process();
  317. }
  318. tilt_process();
  319. rain_process();
  320. rt_thread_mdelay(30);
  321. }
  322. LOG_I("Hardware monitor thread stopped");
  323. }
  324. /**
  325. * @brief 启动硬件检测
  326. */
  327. static void hw_monitor_start(void)
  328. {
  329. if (s_hw_thread != RT_NULL)
  330. {
  331. LOG_D("Hardware monitor already running");
  332. return;
  333. }
  334. tilt_init();
  335. rain_init();
  336. s_hw_running = RT_TRUE;
  337. s_hw_thread = rt_thread_create("hw_mon", hw_work_handler, NULL,
  338. 1024, 9, 10);
  339. if (s_hw_thread == RT_NULL)
  340. {
  341. LOG_E("Failed to create hardware monitor thread");
  342. s_hw_running = RT_FALSE;
  343. return;
  344. }
  345. rt_thread_startup(s_hw_thread);
  346. // LOG_I("Hardware monitor started (priority 9)");
  347. }
  348. /*********************↑ 工作线程 ↑***********************/
  349. /*********************↓ 自动初始化 ↓***********************/
  350. static int hw_detect_auto_init(void)
  351. {
  352. hw_monitor_start();
  353. return 0;
  354. }
  355. INIT_APP_EXPORT(hw_detect_auto_init);
  356. /*********************↑ 自动初始化 ↑***********************/
  357. /*********************↓ MSH命令 ↓***********************/
  358. /**
  359. * @brief MSH命令:查看倾倒开关状态
  360. */
  361. static void cmd_tilt_status(int argc, char **argv)
  362. {
  363. rt_kprintf("\n========== TILT SWITCH ==========\n");
  364. rt_kprintf("Protect: %s\n", sys_sta.tilt_protect == VALID ? "ACTIVE" : "INACTIVE");
  365. rt_kprintf("Pin level: %s\n", rt_pin_read(TILT_SWITCH_PIN) == PIN_LOW ? "LOW" : "HIGH");
  366. rt_kprintf("Poll interval: %d ms\n", TILT_POLL_INTERVAL_MS);
  367. rt_kprintf("Clear timeout: %d sec\n", TILT_CLEAR_TIMEOUT_MS / 1000);
  368. if (sys_sta.tilt_protect == VALID && s_tilt_start_tick != 0)
  369. {
  370. rt_tick_t elapsed = rt_tick_get() - s_tilt_start_tick;
  371. rt_kprintf("Duration: %d sec\n", elapsed / RT_TICK_PER_SECOND);
  372. }
  373. rt_kprintf("================================\n");
  374. if (argc >= 2 && strcmp(argv[1], "clear") == 0)
  375. {
  376. if (sys_sta.tilt_protect == VALID)
  377. {
  378. sys_sta.tilt_protect = 0;
  379. s_tilt_start_tick = 0;
  380. LOG_I("[TILT] Manually cleared");
  381. Recode_e_code(e_tilt_restore, 0, "倾倒保护手动清除");
  382. rt_kprintf("Protect cleared\n");
  383. }
  384. else
  385. {
  386. rt_kprintf("Protect not active\n");
  387. }
  388. }
  389. }
  390. MSH_CMD_EXPORT(cmd_tilt_status, Show tilt status.Usage : cmd_tilt_status[clear]);
  391. /**
  392. * @brief MSH命令:查看雨控检测状态
  393. */
  394. static void cmd_rain_status(int argc, char **argv)
  395. {
  396. rt_kprintf("\n========== RAIN SENSOR ==========\n");
  397. rt_kprintf("Protect: %s\n", sys_sta.rain_protect == VALID ? "ACTIVE" : "INACTIVE");
  398. rt_kprintf("Detect interval: %d sec\n", RAIN_DETECT_INTERVAL_MS / 1000);
  399. rt_kprintf("Clear timeout: %d min\n", RAIN_CLEAR_TIMEOUT_MS / 60000);
  400. if (sys_sta.rain_protect == VALID && s_rain_start_tick != 0)
  401. {
  402. rt_tick_t elapsed = rt_tick_get() - s_rain_start_tick;
  403. rt_kprintf("Duration: %d sec\n", elapsed / RT_TICK_PER_SECOND);
  404. }
  405. rt_kprintf("================================\n");
  406. if (argc >= 2 && strcmp(argv[1], "detect") == 0)
  407. {
  408. int result = rain_detect_once();
  409. rt_kprintf("Manual detect: %s\n", result ? "RAIN DETECTED" : "NO RAIN");
  410. }
  411. if (argc >= 2 && strcmp(argv[1], "clear") == 0)
  412. {
  413. if (sys_sta.rain_protect == VALID)
  414. {
  415. sys_sta.rain_protect = 0;
  416. s_rain_start_tick = 0;
  417. LOG_I("[RAIN] Manually cleared");
  418. Recode_e_code(e_rain_restore, 0, "雨控保护手动清除");
  419. rt_kprintf("Protect cleared\n");
  420. }
  421. else
  422. {
  423. rt_kprintf("Protect not active\n");
  424. }
  425. }
  426. }
  427. MSH_CMD_EXPORT(cmd_rain_status, Show rain status.Usage : cmd_rain_status[detect | clear]);
  428. /*********************↑ MSH命令 ↑***********************/