1、开机按满 5s 绿灯先切配对快闪提示,松手才清绑定并进配网,继续按到 12s 仍可改道 OTA

2、app_led_init 提前到按键判定前,3s 常亮 / 5s 快闪 / 拒绝开机低电闪统一走灯效事件表,去掉开机阶段手搓 GPIO 闪烁
This commit is contained in:
2026-08-27 20:19:57 +08:00
parent 215e1be6bb
commit 026d6d5da7
5 changed files with 89 additions and 37 deletions
+34 -21
View File
@@ -2,11 +2,19 @@
* @file app_boot.c * @file app_boot.c
* @brief 深睡唤醒 / 上电按键判定实现 * @brief 深睡唤醒 / 上电按键判定实现
* @author cyWu <1917507415@qq.com> * @author cyWu <1917507415@qq.com>
* @date 2026.08.26 * @date 2026.08.27
* @version V1.1.0 * @version V1.4.0
* @history * @history
* - V1.0.0, 2026.08.25, cyWu, 首次发布,实现深睡唤醒按键判定(3s 开机 / 5s 配对) * - V1.0.0, 2026.08.25, cyWu, 首次发布,实现深睡唤醒按键判定(3s 开机 / 5s 配对)
* - V1.1.0, 2026.08.26, cyWu, 新增 12s 长按进 OTA、开机前低电量拦截 * - V1.1.0, 2026.08.26, cyWu, 新增 12s 长按进 OTA、开机前低电量拦截
* - V1.2.0, 2026.08.27, cyWu, 按满 5s 绿灯即按配对节奏快闪,松手才真正提交配网
* - V1.3.0, 2026.08.27, cyWu, 3s/5s 提示灯改直接复用 LED 事件库
* LED_EVENT_STANDBY/LED_EVENT_PAIRING),
* 不再手写一份闪烁定时逻辑
* - V1.4.0, 2026.08.27, cyWu, LED 事件库初始化提前到 usr_jb_init(调用本文件
* 前完成),本文件不再自己调 user_led_init
* 拒绝开机低电闪也改用新增的 LED_EVENT_BOOT_REJECT
* 事件,去掉手写的闪烁计次循环
******************************************************************************/ ******************************************************************************/
#include "app_boot.h" #include "app_boot.h"
@@ -15,6 +23,7 @@
#include "board_pin.h" #include "board_pin.h"
#include "app_main.h" #include "app_main.h"
#include "usr_le_api.h" #include "usr_le_api.h"
#include "led_manager.h"
#include "asm/power/power_api.h" #include "asm/power/power_api.h"
#include "asm/power/power_reset.h" #include "asm/power/power_reset.h"
@@ -62,18 +71,17 @@ static void boot_sleep(void)
} }
/** /**
* @brief 拒绝开机前的低电提示:红灯闪 BOARD_BOOT_LOWBAT_BLINK_N 下 * @brief 拒绝开机前的低电提示:红灯闪 BOARD_BOOT_LOWBAT_BLINK_N 下
* @note 直接挂 LED_EVENT_BOOT_REJECT,闪烁节奏/次数由 led_manager 的事件表
* 统一管理,这里只管等它闪完(事件闪完会自己删掉)
* @return 无 * @return 无
*/ */
static void boot_blink_low_battery(void) static void boot_blink_low_battery(void)
{ {
uint8_t i; LED_EventAdd(LED_EVENT_BOOT_REJECT);
while (LED_IsEventExist(LED_EVENT_BOOT_REJECT)) {
for (i = 0; i < BOARD_BOOT_LOWBAT_BLINK_N; i++) { clr_wdt();
bsp_led_red_set(1); user_led_handle();
boot_delay_ms(BOARD_BOOT_LOWBAT_ON_MS);
bsp_led_red_set(0);
boot_delay_ms(BOARD_BOOT_LOWBAT_OFF_MS);
} }
} }
@@ -134,15 +142,19 @@ static uint8_t boot_skip_key_wait(void)
/** /**
* @brief 等待并判定开机按键 * @brief 等待并判定开机按键
* @note 配对(5s)不再一到点就立即提交:需要继续按住观察是否会按到 12s * @note 配对(5s)不再一到点就立即提交:需要继续按住观察是否会按到 12s
* 触发 OTA,真正的配对提交放在松手那一刻做,行为上仍是“按满 5s * 触发 OTA,真正的配对提交放在松手那一刻做。按满 5s 绿灯先切到配对
* 再松手即进配对”,只是多给了继续按到 12s 改道 OTA 的机会。 * 快闪提示,行为上仍是“按满 5s 再松手即进配对”,只是多给了继续按到
* 12s 改道 OTA 的机会。
* 3s 常亮 / 5s 快闪直接复用 led_manager 的 LED_EVENT_STANDBY /
* LED_EVENT_PAIRING 事件(和正常运行时配对灯效完全一致的节奏),
* 不再手写一份闪烁定时。LED 事件库由调用方(usr_jb_init)在本函数
* 之前完成初始化,这里直接假定可用,跟 bsp_hw_init() 一个道理。
* @return 无(深睡分支不返回) * @return 无(深睡分支不返回)
*/ */
void app_boot_wait_key(void) void app_boot_wait_key(void)
{ {
uint32_t t0; uint32_t t0;
uint32_t elapsed; uint32_t elapsed;
uint8_t green_on = 0;
uint8_t pair_armed = 0; uint8_t pair_armed = 0;
usr_var.usr_goto_pair = 0; usr_var.usr_goto_pair = 0;
@@ -165,7 +177,6 @@ void app_boot_wait_key(void)
} }
t0 = timer_get_ms(); t0 = timer_get_ms();
bsp_led_all_off();
log_info("boot key hold, wait 3s on / 5s pair / 12s ota\n"); log_info("boot key hold, wait 3s on / 5s pair / 12s ota\n");
while (bsp_key_is_pressed()) { while (bsp_key_is_pressed()) {
@@ -179,19 +190,21 @@ void app_boot_wait_key(void)
return; return;
} }
/* 5s 只武装配对,真正提交放到松手那一刻,给继续按到 12s 改道 OTA 的机会 */ /* 5s 只武装配对并切到快闪,真正提交放到松手那一刻,给继续按到 12s 改道 OTA 的机会 */
if (!pair_armed && (elapsed >= BOARD_KEY_PAIR_MS)) { if (!pair_armed && (elapsed >= BOARD_KEY_PAIR_MS)) {
pair_armed = 1; pair_armed = 1;
log_info("boot hold %ums, pair armed (release now for pair, " LED_EventDelete(LED_EVENT_STANDBY);
LED_EventAdd(LED_EVENT_PAIRING);
log_info("boot hold %ums, pair hint blink (release now for pair, "
"keep holding to %ums for ota)\n", "keep holding to %ums for ota)\n",
(unsigned)elapsed, (unsigned)BOARD_KEY_OTA_MS); (unsigned)elapsed, (unsigned)BOARD_KEY_OTA_MS);
} } else if (!pair_armed && !LED_IsEventExist(LED_EVENT_STANDBY)
&& (elapsed >= BOARD_KEY_POWER_MS)) {
if (!green_on && (elapsed >= BOARD_KEY_POWER_MS)) { LED_EventAdd(LED_EVENT_STANDBY);
green_on = 1;
bsp_led_green_set(1);
log_info("boot hold 3s, will power on\n"); log_info("boot hold 3s, will power on\n");
} }
user_led_handle(); /* 按事件表当前状态刷新一次灯,闪烁节奏由事件配置自己算 */
} }
elapsed = timer_get_ms() - t0; elapsed = timer_get_ms() - t0;
+7 -6
View File
@@ -3,13 +3,14 @@
* @brief 深睡唤醒 / 上电按键判定:3s 开机,5s 配对,12s OTA,不足 3s 松手再睡; * @brief 深睡唤醒 / 上电按键判定:3s 开机,5s 配对,12s OTA,不足 3s 松手再睡;
* 开机前电量低于约 5% 且未充电时拒绝开机 * 开机前电量低于约 5% 且未充电时拒绝开机
* @author cyWu <1917507415@qq.com> * @author cyWu <1917507415@qq.com>
* @date 2026.08.26 * @date 2026.08.27
* @version V1.1.0 * @version V1.2.0
* @history * @history
* - V1.0.0, 2026.08.25, cyWu, 首次发布,实现深睡唤醒按键判定(3s 开机 / 5s 配对) * - V1.0.0, 2026.08.25, cyWu, 首次发布,实现深睡唤醒按键判定(3s 开机 / 5s 配对)
* - V1.1.0, 2026.08.26, cyWu, 新增 12s 长按进 OTA;新增开机前低电量 * - V1.1.0, 2026.08.26, cyWu, 新增 12s 长按进 OTA;新增开机前低电量
* BOARD_VBAT_SHUTDOWN_MV)拦截,仅闪 5 下红灯 * BOARD_VBAT_SHUTDOWN_MV)拦截,仅闪 5 下红灯
* 提示后继续深睡,不接受非充电状态下的开机 * 提示后继续深睡,不接受非充电状态下的开机
* - V1.2.0, 2026.08.27, cyWu, 按满 5s 绿灯即快闪提示,松手才真正提交配网
* *
* @note 必须在 BLE 协议栈起来、1ms 定时器启动之前调用。杰理 jiffies 此时 * @note 必须在 BLE 协议栈起来、1ms 定时器启动之前调用。杰理 jiffies 此时
* 往往 10ms 才跳一次,所以内部一律用 timer_get_ms 直接量时间, * 往往 10ms 才跳一次,所以内部一律用 timer_get_ms 直接量时间,
@@ -21,10 +22,10 @@
/** /**
* @brief 等待并判定开机按键:不足 3s 松手、或全程未按键,直接原地深睡(不返回); * @brief 等待并判定开机按键:不足 3s 松手、或全程未按键,直接原地深睡(不返回);
* 满 3s 视为正常开机;松手时已过 5s 视为开机并进入配对(内部会调用 * 满 3s 视为正常开机(绿灯常亮);按满 5s 绿灯改快闪提示“松手即配网”,
* app_pair_start);持续按满 12s 直接开机并进入 OTA(调用 * 真正清绑定 / 开绑定广播仍等松手(内部调用 app_pair_start);持续按满
* usr_app_ota_init)。若未充电且电量低于约 5%,则闪 5 下红灯后 * 12s 直接开机并进入 OTA(调用 usr_app_ota_init)。若未充电且电量低于
* 继续深睡,拒绝开机。 * 约 5%,则闪 5 下红灯后继续深睡,拒绝开机。
* @return 无(深睡分支通过 while(1) 喂狗不返回;其余情况正常返回) * @return 无(深睡分支通过 while(1) 喂狗不返回;其余情况正常返回)
*/ */
void app_boot_wait_key(void); void app_boot_wait_key(void);
+4 -1
View File
@@ -3,9 +3,11 @@
* @brief LED 事件框架:按通道掩码独立开关,红绿可同时亮 * @brief LED 事件框架:按通道掩码独立开关,红绿可同时亮
* @author cyWu <1917507415@qq.com> * @author cyWu <1917507415@qq.com>
* @date 2026.08.25 * @date 2026.08.25
* @version V1.0.0 * @version V1.1.0
* @history * @history
* - V1.0.0, 2026.08.25, cyWu, 首次发布,实现按通道掩码独立开关的 LED 事件框架 * - V1.0.0, 2026.08.25, cyWu, 首次发布,实现按通道掩码独立开关的 LED 事件框架
* - V1.1.0, 2026.08.27, cyWu, 新增 LED_EVENT_BOOT_REJECT(拒绝开机低电闪),
* 与运行时 LED_EVENT_EMPTY 参数解耦,各自独立可调
******************************************************************************/ ******************************************************************************/
#ifndef __LED_H__ #ifndef __LED_H__
@@ -53,6 +55,7 @@ typedef enum {
LED_EVENT_PAIR_FAIL, /**< 配对失败红绿交替 */ LED_EVENT_PAIR_FAIL, /**< 配对失败红绿交替 */
LED_EVENT_OTA, /**< OTA:红绿交替闪,直到升级结束/复位 */ LED_EVENT_OTA, /**< OTA:红绿交替闪,直到升级结束/复位 */
LED_EVENT_EMPTY, /**< 电量 5% 关机:关绿灯,红灯闪 5 下 */ LED_EVENT_EMPTY, /**< 电量 5% 关机:关绿灯,红灯闪 5 下 */
LED_EVENT_BOOT_REJECT, /**< 拒绝开机:电量过低,红灯闪 N 下后继续深睡 */
LED_EVENT_MAX LED_EVENT_MAX
} LED_Event_t; } LED_Event_t;
+31 -2
View File
@@ -2,10 +2,12 @@
* @file led_manager.c * @file led_manager.c
* @brief CBC2 灯事件:充电红与待机绿走不同通道,可同时亮 * @brief CBC2 灯事件:充电红与待机绿走不同通道,可同时亮
* @author cyWu <1917507415@qq.com> * @author cyWu <1917507415@qq.com>
* @date 2026.08.25 * @date 2026.08.27
* @version V1.0.0 * @version V1.1.0
* @history * @history
* - V1.0.0, 2026.08.25, cyWu, 首次发布,实现红绿独立通道灯事件表 * - V1.0.0, 2026.08.25, cyWu, 首次发布,实现红绿独立通道灯事件表
* - V1.1.0, 2026.08.27, cyWu, 新增 LED_EVENT_BOOT_REJECT:拒绝开机低电闪,
* 供 app_boot 在按键判定阶段直接复用事件库
******************************************************************************/ ******************************************************************************/
#include "led_manager.h" #include "led_manager.h"
@@ -21,6 +23,7 @@ static uint8_t led_pair_ok_handler(LED_Config_t *led_config);
static uint8_t led_pair_fail_handler(LED_Config_t *led_config); static uint8_t led_pair_fail_handler(LED_Config_t *led_config);
static uint8_t led_ota_handler(LED_Config_t *led_config); static uint8_t led_ota_handler(LED_Config_t *led_config);
static uint8_t led_empty_handler(LED_Config_t *led_config); static uint8_t led_empty_handler(LED_Config_t *led_config);
static uint8_t led_boot_reject_handler(LED_Config_t *led_config);
/** /**
* @brief 只改掩码里的通道,其它灯保持原样 * @brief 只改掩码里的通道,其它灯保持原样
@@ -139,6 +142,20 @@ static uint8_t led_empty_handler(LED_Config_t *led_config)
return 1; return 1;
} }
/**
* @brief 拒绝开机低电闪:闪完 N 下后删事件,随后调用方直接回深睡
* @param led_config 配置
* @return 1=还在闪,0=闪完已删事件
*/
static uint8_t led_boot_reject_handler(LED_Config_t *led_config)
{
if (LED_Update(led_config) == 0) {
LED_EventDelete(LED_EVENT_BOOT_REJECT);
return 0;
}
return 1;
}
/** /**
* @brief 注册回调并装载 CBC2 事件表(GPIO 已在 bsp_hw_init * @brief 注册回调并装载 CBC2 事件表(GPIO 已在 bsp_hw_init
* @return 无 * @return 无
@@ -259,6 +276,18 @@ void user_led_init(void)
.config.runNum = BOARD_LED_EMPTY_BLINK_N, .config.runNum = BOARD_LED_EMPTY_BLINK_N,
.ledEventHandler = led_empty_handler, .ledEventHandler = led_empty_handler,
}, },
[LED_EVENT_BOOT_REJECT] = {
/* 拒绝开机:电量过低,红灯闪 N 下,参数与运行时 EMPTY 独立解耦 */
.event = LED_EVENT_BOOT_REJECT,
.priority = PRIORITY_4,
.config.ledMask = LED_CHANNEL(LED_CH_RED),
.config.state = LED_BLINKING,
.config.blinkParams.orDer = 0, /* 先亮后灭 */
.config.blinkParams.onTime = BOARD_BOOT_LOWBAT_ON_MS,
.config.blinkParams.offTime = BOARD_BOOT_LOWBAT_OFF_MS,
.config.runNum = BOARD_BOOT_LOWBAT_BLINK_N,
.ledEventHandler = led_boot_reject_handler,
},
}; };
LED_SetStateInit(set_led_multi); LED_SetStateInit(set_led_multi);
+13 -7
View File
@@ -2,8 +2,8 @@
* @file usr_jb_main.c * @file usr_jb_main.c
* @brief CBC2 业务组合根:只做“先后调用谁、谁通知谁”,不含具体业务算法 * @brief CBC2 业务组合根:只做“先后调用谁、谁通知谁”,不含具体业务算法
* @author cyWu <1917507415@qq.com> * @author cyWu <1917507415@qq.com>
* @date 2026.08.25 * @date 2026.08.27
* @version V2.1.0 * @version V2.2.0
* @history * @history
* - V1.0.0, 2026.08.21, cyWu, 首次发布 * - V1.0.0, 2026.08.21, cyWu, 首次发布
* - V1.1.0, 2026.08.24, cyWu, 收口未接线模块;DP2 仅第 1 字节点动 1s * - V1.1.0, 2026.08.24, cyWu, 收口未接线模块;DP2 仅第 1 字节点动 1s
@@ -18,6 +18,9 @@
* 换向死区判定改用阈值检查而非精确计时, * 换向死区判定改用阈值检查而非精确计时,
* 取消专门的 1ms 高频档,全系统统一 20ms 节拍, * 取消专门的 1ms 高频档,全系统统一 20ms 节拍,
* 只保留"能不能休眠"这一个维度 * 只保留"能不能休眠"这一个维度
* - V2.2.0, 2026.08.27, cyWu, app_led_init() 提前到 app_boot_wait_key() 之前,
* 开机 3s/5s/拒绝开机低电闪直接用灯效事件表,
* 不用再各自摸裸 GPIO 手搓一份闪烁定时
* *
* @note 协议生成文件 jb_product.c 不要填业务。APP 下行写 gDevData。 * @note 协议生成文件 jb_product.c 不要填业务。APP 下行写 gDevData。
* usr_timer_loop 由 BLE 回调,勿再注册第二份。 * usr_timer_loop 由 BLE 回调,勿再注册第二份。
@@ -256,9 +259,12 @@ static void usr_log_boot_version(void)
/** /**
* @brief 业务初始化(在 BLE 栈起来之前由 app_main 调用) * @brief 业务初始化(在 BLE 栈起来之前由 app_main 调用)
* @note 内部会等按键 3s/5s;不足 3s 直接深睡,不会启动业务定时器。 * @note 内部会等按键 3s/5s;不足 3s 直接深睡,不会启动业务定时器。
* 按键判定只摸 bsp_hw 的裸 GPIO,不经过协议栈/灯效表/电机状态机, * 按键判定只摸 bsp_hw 的裸 GPIO 和 led_manager 的事件表(3s 常亮 /
* 所以只有 bsp_hw_init() 需要排在它前面——一旦判定要睡回去 * 5s 配对快闪 / 拒绝开机低电闪都要用灯),不经过协议栈/电机状态机
* boot_sleep() 原地喂狗不再返回,后面这些初始化不会被浪费。 * 所以 app_led_init() 要排在它前面(跟 bsp_hw_init() 一样)——一旦
* 判定要睡回去,boot_sleep() 原地喂狗不再返回,后面这些初始化不会
* 被浪费。app_led_init() 内部有已初始化判断,这里提前调不会导致
* 后面重复初始化出问题。
* @return 无 * @return 无
*/ */
void usr_jb_init(void) void usr_jb_init(void)
@@ -266,14 +272,14 @@ void usr_jb_init(void)
usr_log_boot_version(); /* UART 已在 app_main 起来,按键判定前就能看到版本 */ usr_log_boot_version(); /* UART 已在 app_main 起来,按键判定前就能看到版本 */
bsp_hw_init(); bsp_hw_init();
app_led_init(); /* 提前到按键判定之前:3s/5s/拒绝开机低电闪都要直接用灯效事件表 */
app_boot_wait_key(); /* 深睡分支不会返回;返回即代表确定要开机 */ app_boot_wait_key(); /* 深睡分支不会返回;返回即代表确定要开机 */
jbInit(); jbInit();
userInit(); userInit();
app_led_init();
if (usr_var.usr_goto_updata) { if (usr_var.usr_goto_updata) {
/* 开机 12s 已进 OTA灯表刚起来,立刻挂红绿交替 */ /* 开机 12s 已进 OTA:立刻挂红绿交替 */
app_led_request_ota(); app_led_request_ota();
} }
app_mode_init(); app_mode_init();