/* * Hardware Detection Module - v2.3 * * 功能:检测硬件外设状态 * - 倾倒开关(PB10引脚下降沿中断检测,100ms轮询) * - 雨控检测(PC0输出高电平,PC1输入检测,每30秒检测一次) * - 单线程设计,优先级9,确保倾倒检测及时响应 * * Version: 2.3.0 */ /*********************↓ include ↓************************/ #define DBG_TAG "HW" #define DBG_LVL DBG_INFO #include #include #include #include #include "ecode.h" #include "ym310_protecl.h" /* for sys_sta and sys_sta */ /*********************↑ include ↑************************/ /*********************↓ define ↓************************/ /* 倾倒开关配置 */ #define TILT_SWITCH_PIN GET_PIN(B, 10) /* PB10引脚 */ #define TILT_IRQ_MODE PIN_IRQ_MODE_FALLING /* 下降沿触发 */ #define TILT_DEBOUNCE_MS 50 /* 防抖时间(毫秒) */ #define TILT_CLEAR_TIMEOUT_MS (60 * 1000) /* 保护清除时间(毫秒)- 60秒 */ #define TILT_POLL_INTERVAL_MS 100 /* 轮询周期(毫秒) */ #define TILT_TRIGGER_MS 1000 /* 持续触发时间(毫秒)- 1秒 */ // /* 雨控检测配置 */ #define RAIN_OUT_PIN GET_PIN(C, 0) /* PC0 输出引脚 */ #define RAIN_IN_PIN GET_PIN(C, 1) /* PC1 输入引脚 */ #define RAIN_DETECT_INTERVAL_MS (20 * 1000) /* 检测间隔(毫秒)- 30秒 */ #define RAIN_CLEAR_TIMEOUT_MS (3 * 60 * 1000) /* 保护清除时间(毫秒)- 3分钟 */ #define RAIN_POWER_ON_DELAY_MS (10 * 1000) /* 上电后延迟(毫秒) */ /*********************↑ define ↑************************/ /*********************↓ 静态变量 ↓************************/ /* 倾倒开关相关 */ static rt_tick_t s_tilt_last_tick = 0; /* 上次触发时间 */ static rt_tick_t s_tilt_start_tick = 0; /* 当前倾倒开始时间 */ static struct rt_semaphore tilt_sem; /* 中断信号量 */ static rt_tick_t s_tilt_trigger_start = 0; /* 倾倒持续开始时间(新增)*/ /* 雨控检测相关 */ static rt_tick_t s_rain_last_detect_tick = 0; /* 上次检测时间 */ static rt_tick_t s_rain_start_tick = 0; /* 雨控开始时间 */ /* 线程相关 */ static rt_thread_t s_hw_thread = RT_NULL; /* 工作线程句柄 */ static rt_bool_t s_hw_running = RT_FALSE; /* 线程运行标志 */ /*********************↑ 静态变量 ↑************************/ extern SYS_STATUS sys_sta; extern void report_now(void); /*********************↓ 倾倒开关函数 ↓***********************/ /** * @brief 倾倒开关中断服务函数 */ static void tilt_isr(void *args) { rt_tick_t current_tick = rt_tick_get(); /* 防抖处理 */ if ((current_tick - s_tilt_last_tick) < rt_tick_from_millisecond(TILT_DEBOUNCE_MS)) { return; } s_tilt_last_tick = current_tick; /* 通知工作线程处理 */ rt_sem_release(&tilt_sem); } /** * @brief 处理倾倒开关检测(持续1秒才触发保护) */ static void tilt_process(void) { int pin_level; uint32_t now_ms; uint32_t elapsed; pin_level = rt_pin_read(TILT_SWITCH_PIN); now_ms = rt_tick_get_millisecond(); /* ========== 触发逻辑:持续1秒触发保护 ========== */ if (pin_level == PIN_LOW) { /* 倾倒状态:开始计时或继续计时 */ if (s_tilt_trigger_start == 0) { s_tilt_trigger_start = now_ms; LOG_D("[TILT] Tilt detected, start counting..."); } elapsed = now_ms - s_tilt_trigger_start; if (elapsed >= TILT_TRIGGER_MS) { /* 持续倾倒超过1秒,触发保护 */ if (sys_sta.tilt_protect != VALID) { sys_sta.tilt_protect = VALID; s_tilt_start_tick = now_ms; /* 记录保护触发时间 */ LOG_W("[TILT] Triggered! Tilt持续 %lu ms, protect = VALID", elapsed); Recode_e_code(e_tilt_trigger, 1, "倾倒开关触发"); gpio_lamp_ctrl(0); gpio_hv_ctrl(0); report_now(); } /* 保护已触发,不需要额外操作 */ } } else { /* 非倾倒状态:重置触发计时器 */ if (s_tilt_trigger_start != 0) { LOG_D("[TILT] Tilt cleared, reset counter"); s_tilt_trigger_start = 0; } } /* ========== 清除逻辑:倾倒恢复后60秒清除保护 ========== */ if (sys_sta.tilt_protect == VALID) { if (pin_level != PIN_LOW) { /* 当前未倾倒,开始或继续清除计时 */ if (s_tilt_start_tick == 0) { /* 刚恢复,开始计时 */ s_tilt_start_tick = now_ms; LOG_D("[TILT] Recovered, start clear countdown"); } elapsed = now_ms - s_tilt_start_tick; if (elapsed >= TILT_CLEAR_TIMEOUT_MS) { /* 恢复时间达到60秒,清除保护 */ sys_sta.tilt_protect = 0; s_tilt_start_tick = 0; s_tilt_trigger_start = 0; LOG_I("[TILT] Protect cleared after %d sec", TILT_CLEAR_TIMEOUT_MS / 1000); Recode_e_code(e_tilt_restore, 0, "倾倒保护清除"); rt_thread_mdelay(1000); report_now(); } } else { /* 当前仍在倾倒,重置清除计时器(不清除保护)*/ if (s_tilt_start_tick != 0) { LOG_D("[TILT] Still tilted, reset clear timer"); s_tilt_start_tick = 0; } } } } /** * @brief 初始化倾倒开关 */ static void tilt_init(void) { rt_err_t ret; int pin_level; // LOG_I("[TILT] Initializing on PB10..."); ret = rt_sem_init(&tilt_sem, "tilt_sem", 0, RT_IPC_FLAG_FIFO); if (ret != RT_EOK) { LOG_E("[TILT] Failed to init semaphore"); return; } rt_pin_mode(TILT_SWITCH_PIN, PIN_MODE_INPUT_PULLUP); pin_level = rt_pin_read(TILT_SWITCH_PIN); if (pin_level == PIN_LOW) { LOG_W("[TILT] Initially TRIGGERED!"); sys_sta.tilt_protect = VALID; s_tilt_start_tick = rt_tick_get(); Recode_e_code(e_tilt_trigger, 1, "倾倒开关初始状态为触发"); gpio_lamp_ctrl(0); gpio_hv_ctrl(0); report_now(); } else { // LOG_I("[TILT] Initially normal"); sys_sta.tilt_protect = 0; s_tilt_start_tick = 0; } ret = rt_pin_attach_irq(TILT_SWITCH_PIN, TILT_IRQ_MODE, tilt_isr, NULL); if (ret != RT_EOK) { LOG_E("[TILT] Failed to attach IRQ"); return; } ret = rt_pin_irq_enable(TILT_SWITCH_PIN, PIN_IRQ_ENABLE); if (ret != RT_EOK) { LOG_E("[TILT] Failed to enable IRQ"); return; } // LOG_I("[TILT] Initialized (poll %dms, clear after %d sec)", // TILT_POLL_INTERVAL_MS, TILT_CLEAR_TIMEOUT_MS / 1000); } /*********************↑ 倾倒开关函数 ↑***********************/ /*********************↓ 雨控检测函数 ↓***********************/ /** * @brief 执行一次雨控检测 * @return 1:有雨,0:无雨 */ static int rain_detect_once(void) { int result = 0; int in_level = rt_pin_read(RAIN_IN_PIN); if (in_level == PIN_LOW) { result = 1; LOG_D("[RAIN] Detected! PC1=LOW"); } else { LOG_D("[RAIN] No rain, PC1=HIGH"); } rt_pin_mode(RAIN_OUT_PIN, PIN_MODE_INPUT); return result; } /** * @brief 处理雨控检测 */ static void rain_process(void) { int has_rain; rt_tick_t now = rt_tick_get(); static rt_tick_t ready = 0; if ((now - s_rain_last_detect_tick) < rt_tick_from_millisecond(RAIN_DETECT_INTERVAL_MS)) { return; } if (ready == 0) { // LOG_I(" RAIN:time take "); ready = now; } rt_pin_mode(RAIN_OUT_PIN, PIN_MODE_OUTPUT); rt_pin_write(RAIN_OUT_PIN, PIN_HIGH); rt_pin_mode(RAIN_IN_PIN, PIN_MODE_INPUT_PULLUP); if ((now - ready) < rt_tick_from_millisecond(RAIN_POWER_ON_DELAY_MS)) { return; } // LOG_I(" RAIN:time start "); ready = 0; s_rain_last_detect_tick = now; has_rain = rain_detect_once(); if (has_rain) { if (sys_sta.rain_protect != VALID) { sys_sta.rain_protect = VALID; s_rain_start_tick = now; // LOG_W("[RAIN] Detected! protect = VALID"); Recode_e_code(e_rain_trigger, 1, "雨控触发"); rt_thread_mdelay(1000); report_now(); } else { s_rain_start_tick = now; LOG_D("[RAIN] Persists, protect extended"); } } else { if (sys_sta.rain_protect == VALID && s_rain_start_tick != 0) { if ((now - s_rain_start_tick) >= rt_tick_from_millisecond(RAIN_CLEAR_TIMEOUT_MS)) { sys_sta.rain_protect = 0; s_rain_start_tick = 0; LOG_I("[RAIN] Protect cleared after %d min", RAIN_CLEAR_TIMEOUT_MS / 60000); Recode_e_code(e_rain_restore, 0, "雨控保护清除"); rt_thread_mdelay(1000); report_now(); } } } } /** * @brief 初始化雨控检测 */ static void rain_init(void) { // LOG_I("[RAIN] Initializing..."); rt_pin_mode(RAIN_OUT_PIN, PIN_MODE_INPUT); rt_pin_mode(RAIN_IN_PIN, PIN_MODE_INPUT_PULLUP); int has_rain = rain_detect_once(); if (has_rain) { LOG_W("[RAIN] Initially detected!"); sys_sta.rain_protect = VALID; s_rain_start_tick = rt_tick_get(); Recode_e_code(e_rain_trigger, 1, "雨控初始状态为触发"); } else { // LOG_I("[RAIN] Initially normal"); sys_sta.rain_protect = 0; s_rain_start_tick = 0; } s_rain_last_detect_tick = rt_tick_get(); // LOG_I("[RAIN] Initialized (detect every %d sec, clear after %d min)", // RAIN_DETECT_INTERVAL_MS / 1000, RAIN_CLEAR_TIMEOUT_MS / 60000); } /*********************↑ 雨控检测函数 ↑***********************/ /*********************↓ 工作线程 ↓***********************/ /** * @brief 硬件检测工作线程(优先级9,确保倾倒及时响应) */ static void hw_work_handler(void *parameter) { // LOG_I("Hardware monitor thread started (priority 9)"); while (1) { if (rt_sem_take(&tilt_sem, rt_tick_from_millisecond(TILT_POLL_INTERVAL_MS)) == RT_EOK) { tilt_process(); } tilt_process(); rain_process(); rt_thread_mdelay(30); } LOG_I("Hardware monitor thread stopped"); } /** * @brief 启动硬件检测 */ static void hw_monitor_start(void) { if (s_hw_thread != RT_NULL) { LOG_D("Hardware monitor already running"); return; } tilt_init(); rain_init(); s_hw_running = RT_TRUE; s_hw_thread = rt_thread_create("hw_mon", hw_work_handler, NULL, 1024, 9, 10); if (s_hw_thread == RT_NULL) { LOG_E("Failed to create hardware monitor thread"); s_hw_running = RT_FALSE; return; } rt_thread_startup(s_hw_thread); // LOG_I("Hardware monitor started (priority 9)"); } /*********************↑ 工作线程 ↑***********************/ /*********************↓ 自动初始化 ↓***********************/ static int hw_detect_auto_init(void) { hw_monitor_start(); return 0; } INIT_APP_EXPORT(hw_detect_auto_init); /*********************↑ 自动初始化 ↑***********************/ /*********************↓ MSH命令 ↓***********************/ /** * @brief MSH命令:查看倾倒开关状态 */ static void cmd_tilt_status(int argc, char **argv) { rt_kprintf("\n========== TILT SWITCH ==========\n"); rt_kprintf("Protect: %s\n", sys_sta.tilt_protect == VALID ? "ACTIVE" : "INACTIVE"); rt_kprintf("Pin level: %s\n", rt_pin_read(TILT_SWITCH_PIN) == PIN_LOW ? "LOW" : "HIGH"); rt_kprintf("Poll interval: %d ms\n", TILT_POLL_INTERVAL_MS); rt_kprintf("Clear timeout: %d sec\n", TILT_CLEAR_TIMEOUT_MS / 1000); if (sys_sta.tilt_protect == VALID && s_tilt_start_tick != 0) { rt_tick_t elapsed = rt_tick_get() - s_tilt_start_tick; rt_kprintf("Duration: %d sec\n", elapsed / RT_TICK_PER_SECOND); } rt_kprintf("================================\n"); if (argc >= 2 && strcmp(argv[1], "clear") == 0) { if (sys_sta.tilt_protect == VALID) { sys_sta.tilt_protect = 0; s_tilt_start_tick = 0; LOG_I("[TILT] Manually cleared"); Recode_e_code(e_tilt_restore, 0, "倾倒保护手动清除"); rt_kprintf("Protect cleared\n"); } else { rt_kprintf("Protect not active\n"); } } } MSH_CMD_EXPORT(cmd_tilt_status, Show tilt status.Usage : cmd_tilt_status[clear]); /** * @brief MSH命令:查看雨控检测状态 */ static void cmd_rain_status(int argc, char **argv) { rt_kprintf("\n========== RAIN SENSOR ==========\n"); rt_kprintf("Protect: %s\n", sys_sta.rain_protect == VALID ? "ACTIVE" : "INACTIVE"); rt_kprintf("Detect interval: %d sec\n", RAIN_DETECT_INTERVAL_MS / 1000); rt_kprintf("Clear timeout: %d min\n", RAIN_CLEAR_TIMEOUT_MS / 60000); if (sys_sta.rain_protect == VALID && s_rain_start_tick != 0) { rt_tick_t elapsed = rt_tick_get() - s_rain_start_tick; rt_kprintf("Duration: %d sec\n", elapsed / RT_TICK_PER_SECOND); } rt_kprintf("================================\n"); if (argc >= 2 && strcmp(argv[1], "detect") == 0) { int result = rain_detect_once(); rt_kprintf("Manual detect: %s\n", result ? "RAIN DETECTED" : "NO RAIN"); } if (argc >= 2 && strcmp(argv[1], "clear") == 0) { if (sys_sta.rain_protect == VALID) { sys_sta.rain_protect = 0; s_rain_start_tick = 0; LOG_I("[RAIN] Manually cleared"); Recode_e_code(e_rain_restore, 0, "雨控保护手动清除"); rt_kprintf("Protect cleared\n"); } else { rt_kprintf("Protect not active\n"); } } } MSH_CMD_EXPORT(cmd_rain_status, Show rain status.Usage : cmd_rain_status[detect | clear]); /*********************↑ MSH命令 ↑***********************/