/****************************************************************************** * @file usr_led_status.c * @brief 状态指示灯实现 * @author cyWu <1917507415@qq.com> * @date 2026.08.03 * @version V1.0.0 * @history * - V1.0.0, 2026.08.03, cyWu, 首次发布 * * 显示规则: * 红灯(PA8):上电常亮;COM(DTR)打开时 1Hz 闪烁(优先于常亮) * 绿灯(PA7):BLE 已连接常亮;OTA 进行中 1Hz 闪烁(优先于常亮);否则熄灭 * * 依赖: * - BLE:usr_get_conn_service() != 0 * - COM:cdc_is_com_open() == 1(与 Dengle 暂停语义一致) * - OTA:usr_get_ota_status() == 0(dual_ota_idle=0 表示忙) ******************************************************************************/ #include "system/includes.h" #include "app_config.h" #include "asm/gpio.h" #include "usr_led_status.h" #if TCFG_USB_SLAVE_CDC_ENABLE #include "usb/device/cdc.h" #endif #define LOG_TAG_CONST APP #define LOG_TAG "[LED]" #define LOG_ERROR_ENABLE #define LOG_DEBUG_ENABLE #define LOG_INFO_ENABLE #define LOG_CLI_ENABLE #include "debug.h" /*============================================================================*/ /* 私有宏 (Private macros) */ /*============================================================================*/ #define USR_LED_GREEN_PIN IO_PORTA_07 /**< 绿灯 */ #define USR_LED_RED_PIN IO_PORTA_08 /**< 红灯 */ /** * LED 点亮电平:1=高电平点亮,0=低电平点亮 * 若实测灯反了,改此宏即可 */ #define USR_LED_ON_LEVEL (0) #define USR_LED_OFF_LEVEL (!(USR_LED_ON_LEVEL)) #define USR_LED_BLINK_HALF_MS (500) /**< 1Hz:亮/灭各 500ms */ #define USR_LED_HALF_TICKS (USR_LED_BLINK_HALF_MS / USR_LED_TICK_MS) /*============================================================================*/ /* 私有类型 (Private types) */ /*============================================================================*/ typedef enum { LED_MODE_OFF = 0, LED_MODE_ON, LED_MODE_BLINK } LedMode_t; /*============================================================================*/ /* 私有变量 (Private variables) */ /*============================================================================*/ static uint8_t s_initialized = 0; static u16 s_tick_timer = 0; static uint8_t s_blink_phase = 0; /**< 0=半周期灭侧,1=半周期亮侧 */ static uint8_t s_blink_cnt = 0; /**< 半周期内已走过的 tick 数 */ extern u16 usr_get_conn_service(void); extern u8 usr_get_ota_status(void); /*============================================================================*/ /* 私有函数声明 (Private function prototypes) */ /*============================================================================*/ static void usr_led_gpio_init(u32 pin); static void usr_led_set(u32 pin, uint8_t on); static uint8_t usr_led_is_com_open(void); static uint8_t usr_led_is_ble_conn(void); static uint8_t usr_led_is_ota_busy(void); static void usr_led_apply(u32 pin, LedMode_t mode); static void usr_led_tick(void *priv); /*============================================================================*/ /* 公有函数实现 (Public API implementation) */ /*============================================================================*/ /** * @brief 初始化状态灯 * @return UsrLed_Ret_t 错误码 */ UsrLed_Ret_t usr_led_status_init(void) { if (s_initialized) { return USR_LED_OK; } usr_led_gpio_init(USR_LED_GREEN_PIN); usr_led_gpio_init(USR_LED_RED_PIN); /* 上电:红灯常亮,绿灯熄灭 */ usr_led_set(USR_LED_RED_PIN, 1); usr_led_set(USR_LED_GREEN_PIN, 0); s_blink_phase = 1; s_blink_cnt = 0; s_initialized = 1; if (s_tick_timer == 0) { s_tick_timer = sys_timer_add(NULL, usr_led_tick, USR_LED_TICK_MS); } printf("usr_led_status_init ok (red=PA8 green=PA7)\n"); return USR_LED_OK; } /** * @brief 主处理:刷新红/绿灯显示模式 */ void usr_led_status_run(void) { LedMode_t red_mode; LedMode_t green_mode; if (!s_initialized) { return; } /* 红灯:COM 打开 → 闪烁;否则上电常亮 */ if (usr_led_is_com_open()) { red_mode = LED_MODE_BLINK; } else { red_mode = LED_MODE_ON; } /* 绿灯:OTA 忙 → 闪烁;BLE 已连 → 常亮;否则熄灭 */ if (usr_led_is_ota_busy()) { green_mode = LED_MODE_BLINK; } else if (usr_led_is_ble_conn()) { green_mode = LED_MODE_ON; } else { green_mode = LED_MODE_OFF; } /* 任一灯在闪时推进公共 1Hz 相位,保证同频同相 */ if (red_mode == LED_MODE_BLINK || green_mode == LED_MODE_BLINK) { s_blink_cnt++; if (s_blink_cnt >= USR_LED_HALF_TICKS) { s_blink_cnt = 0; s_blink_phase ^= 1; } } else { s_blink_cnt = 0; s_blink_phase = 1; } usr_led_apply(USR_LED_RED_PIN, red_mode); usr_led_apply(USR_LED_GREEN_PIN, green_mode); } /** * @brief 获取当前初始化状态 * @return UsrLed_Ret_t */ UsrLed_Ret_t usr_led_status_get_status(void) { if (!s_initialized) { return USR_LED_ERR_NOT_INIT; } return USR_LED_OK; } /*============================================================================*/ /* 私有函数实现 (Private functions) */ /*============================================================================*/ /** * @brief 配置 LED 引脚为推挽输出 * @param pin GPIO 宏(如 IO_PORTA_07) */ static void usr_led_gpio_init(u32 pin) { gpio_set_die(pin, 1); gpio_set_pull_up(pin, 0); gpio_set_pull_down(pin, 0); gpio_direction_output(pin, USR_LED_OFF_LEVEL); } /** * @brief 点亮/熄灭指定 LED * @param pin GPIO * @param on 1=亮,0=灭 */ static void usr_led_set(u32 pin, uint8_t on) { gpio_direction_output(pin, on ? USR_LED_ON_LEVEL : USR_LED_OFF_LEVEL); } /** * @brief COM 口是否打开(CDC DTR) * @return 1=已打开,0=未打开/无 CDC */ static uint8_t usr_led_is_com_open(void) { #if TCFG_USB_SLAVE_CDC_ENABLE return cdc_is_com_open() ? 1 : 0; #else return 0; #endif } /** * @brief BLE 是否已连接 * @return 1=已连接 */ static uint8_t usr_led_is_ble_conn(void) { return (usr_get_conn_service() != 0) ? 1 : 0; } /** * @brief 是否正在 OTA(usr_get_ota_status==0 表示忙) * @return 1=OTA 进行中 */ static uint8_t usr_led_is_ota_busy(void) { return (usr_get_ota_status() == 0) ? 1 : 0; } /** * @brief 按模式驱动单灯 * @param pin GPIO * @param mode 灭 / 常亮 / 闪烁 */ static void usr_led_apply(u32 pin, LedMode_t mode) { switch (mode) { case LED_MODE_ON: usr_led_set(pin, 1); break; case LED_MODE_BLINK: usr_led_set(pin, s_blink_phase); break; case LED_MODE_OFF: default: usr_led_set(pin, 0); break; } } /** * @brief sys_timer 回调:100ms 刷新一次 * @param priv 未使用 */ static void usr_led_tick(void *priv) { (void)priv; usr_led_status_run(); }