/****************************************************************************** * @file app_led.c * @brief 灯效:绿=作业态、红=配对态;OTA / 配对失败临时占双灯(规格书 6 章) * @author cyWu <1917507415@qq.com> * @date 2026.09.09 * @version V1.0.0 * @history * - V1.0.0, 2026.09.09, cyWu, P0 独立通道版(不同于加热垫互斥灯) * * @note 红绿独立:喷淋/空闲只改绿灯,不要去关红灯;配网闪红灯时不要关绿灯。 * 只有 OTA 与配对失败动画临时占用双灯。事件表见 led_manager.c。 ******************************************************************************/ #include "app_led.h" #include "led_manager.h" #include "bsp_hw.h" #include "board_pin.h" #include "app_pair.h" #include "app_spray.h" #include "usr_le_api.h" #include "system/includes.h" #define LOG_TAG_CONST APP #define LOG_TAG "[APP_LED]" #define LOG_INFO_ENABLE #include "debug.h" typedef struct { uint8_t inited; /**< 1=已初始化 */ uint8_t ota; /**< 1=OTA 灯效中,app_led_run 只跑交替 */ uint8_t pair_hint; /**< 1=配网键已满 5s 但还没松手提交配对,维持红灯快闪 */ } AppLedCtx_t; static AppLedCtx_t s_led; /** * @brief 重新播放一次「一次性/限时」灯效,让它从第 0 帧重新开始 * @note 先 Delete 清空槽位再 Add,强制重新计时(见 led.c LED_EventAdd 语义) * @param evt 要重启的事件 * @return 无 */ static void led_restart(LED_Event_t evt) { LED_EventDelete(evt); LED_EventAdd(evt); } /** * @brief 灯效初始化 * @return APP_LED_OK=成功 */ AppLed_Ret_t app_led_init(void) { if (s_led.inited) { return APP_LED_OK; } #if BOARD_LED_ENABLE user_led_init(); s_led.ota = 0; s_led.pair_hint = 0; s_led.inited = 1; #else log_info("led disabled\n"); #endif return APP_LED_OK; } /** * @brief 查询模块是否已初始化 * @return APP_LED_OK=已初始化,APP_LED_ERR_NOT_INIT=未初始化 */ AppLed_Ret_t app_led_get_status(void) { return s_led.inited ? APP_LED_OK : APP_LED_ERR_NOT_INIT; } /** * @brief 配网键满 5s:红灯 100ms 快闪提示(绿灯按作业态照常,不受影响) * @return 无 */ void app_led_hint_pair(void) { if (!s_led.inited || s_led.ota) { return; } s_led.pair_hint = 1; LED_EventDelete(LED_EVENT_RED_PAIRED); /* 快闪盖过"已配对常亮"(同槽换事件) */ LED_EventAdd(LED_EVENT_RED_PAIRING); } /** * @brief 结束"将配网"提示,交回 app_led_run 按 app_pair / 配对标志接管 * @return 无 */ void app_led_clear_pair_hint(void) { s_led.pair_hint = 0; } /** * @brief 进入 OTA:清掉其它灯,挂红绿交替一直闪 * @return 无 */ void app_led_request_ota(void) { if (!s_led.inited) { return; } s_led.ota = 1; s_led.pair_hint = 0; /* 已改判 OTA,撤销配网提示 */ LED_EventAllDelete(); bsp_led_all_off(); LED_EventAdd(LED_EVENT_OTA); } /** * @brief 查询是否处于 OTA 灯效 * @return 1=OTA 灯效中,0=否 */ uint8_t app_led_is_ota(void) { return s_led.ota; } /** * @brief 按优先级刷新灯(20ms 业务节拍) * @param dt 距上次调用的毫秒数 * @return 无 */ void app_led_run(uint16_t dt) { AppPairEvt_t pair_evt; uint8_t high_event; if (!s_led.inited) { return; } #if BOARD_LED_ENABLE /* OTA 期间只跑红绿交替 */ if (s_led.ota) { LED_EventAdd(LED_EVENT_OTA); user_led_handle(); return; } /* 配对成功/失败是边沿事件,只在那一拍切灯效 */ pair_evt = app_pair_tick_1ms(dt); if (pair_evt == APP_PAIR_EVT_OK) { s_led.pair_hint = 0; LED_EventDelete(LED_EVENT_RED_PAIRING); LED_EventDelete(LED_EVENT_PAIR_FAIL); log_info("led pair ok -> red solid\n"); } else if (pair_evt == APP_PAIR_EVT_FAIL) { s_led.pair_hint = 0; LED_EventDelete(LED_EVENT_RED_PAIRED); LED_EventDelete(LED_EVENT_RED_PAIRING); led_restart(LED_EVENT_PAIR_FAIL); /* 交替 3s,播完自删回常态 */ log_info("led pair fail 3s\n"); } high_event = (uint8_t)(LED_IsEventExist(LED_EVENT_PAIR_FAIL) || LED_IsEventExist(LED_EVENT_OTA)); /* 常态双通道(高事件占双灯期间不 add,播完自删后下拍自动恢复) */ if (!high_event) { /* 红灯通道:快闪(提示/配对中) > 常亮(已配对) > 灭(未配对) */ if (s_led.pair_hint || app_pair_is_active()) { LED_EventAdd(LED_EVENT_RED_PAIRING); } else if (usr_get_pair_flag()) { LED_EventAdd(LED_EVENT_RED_PAIRED); } else { LED_EventDelete(LED_EVENT_RED_PAIRED); LED_EventDelete(LED_EVENT_RED_PAIRING); } /* 绿灯通道:作业态(含间隔)闪,否则常亮 */ if (app_spray_is_running()) { LED_EventAdd(LED_EVENT_GRN_SPRAY); } else { LED_EventAdd(LED_EVENT_GRN_IDLE); } } user_led_handle(); #endif } /** * @brief 清空全部灯事件并灭灯 * @return 无 */ void app_led_clear(void) { #if BOARD_LED_ENABLE LED_EventAllDelete(); bsp_led_all_off(); #endif }