/****************************************************************************** * @file app_boot.c * @brief CBR3 上电按键判定实现(3s 开机 / 5s 配对 / 12s OTA) * @author cyWu <1917507415@qq.com> * @date 2026.08.29 * @version V1.0.0 * @history * - V1.0.0, 2026.08.29, cyWu, 首次发布(移植门夹:删 USB 直通、删低电拒绝) ******************************************************************************/ #include "app_boot.h" #include "app_pair.h" #include "bsp_hw.h" #include "board_pin.h" #include "app_main.h" #include "usr_le_api.h" #include "led_manager.h" #include "asm/power/power_api.h" #include "asm/power/power_reset.h" #define LOG_TAG_CONST APP #define LOG_TAG "[APP_BOOT]" #define LOG_INFO_ENABLE #include "debug.h" extern void clr_wdt(void); extern u32 timer_get_ms(void); /** * @brief 忙等若干毫秒,并喂狗 * @param ms 等待时长 * @return 无 */ static void boot_delay_ms(uint32_t ms) { uint32_t t0 = timer_get_ms(); while ((timer_get_ms() - t0) < ms) { clr_wdt(); } } /** * @brief BLE 起来前进深睡(业务定时器尚未启动),原地喂狗不返回 * @note power_set_soft_poweroff() 只是向 SDK 底层发起软关机请求(置个标志位), * 不是同步断电——真正切电源是底层电源管理在之后某个时机才执行的。 * 此时 BLE 栈、业务定时器都还没起来,如果直接 return,代码会接着把 * usr_jb_init 剩下的初始化跑完,等于白判定。所以必须用 while(1) 卡住: * 一边喂狗防止看门狗打断,一边等底层真正把电断掉。 * @return 无(不会返回) */ static void boot_sleep(void) { log_info("boot sleep\n"); bsp_hw_enter_sleep_io(); power_set_soft_poweroff(); while (1) { clr_wdt(); } } /** * @brief 等待并判定开机按键 * @note 配对(5s)不在到点时立即提交:继续按住观察是否会按到 12s 触发 OTA, * 真正的配对提交放在松手那一刻做。按满 5s 灯先切到配对快闪提示。 * 3s 常亮 / 5s 快闪直接复用 led_manager 的 LED_EVENT_STANDBY / * LED_EVENT_PAIRING 事件。LED 事件库由调用方(usr_jb_init)在本函数 * 之前完成初始化,这里直接假定可用。 * @return 无(深睡分支不返回) */ void app_boot_wait_key(void) { uint32_t t0; uint32_t elapsed; uint8_t pair_armed = 0; usr_var.usr_goto_pair = 0; /* ⚠ 无 USB 直通:插电/冷启动一律走按键判定(规格书 5.1)。 */ if (!bsp_key_is_pressed()) { log_info("boot no key, sleep\n"); boot_sleep(); } t0 = timer_get_ms(); log_info("boot key hold, wait 3s on / 5s pair / 12s ota\n"); while (bsp_key_is_pressed()) { elapsed = timer_get_ms() - t0; clr_wdt(); /* 12s 优先于配对:按满 12s 直接进 OTA,不再等松手 */ if (elapsed >= BOARD_KEY_OTA_MS) { log_info("boot hold %ums, power on + ota\n", (unsigned)elapsed); usr_app_ota_init(); return; } /* 5s 只武装配对并切到快闪,真正提交放到松手那一刻 */ if (!pair_armed && (elapsed >= BOARD_KEY_PAIR_MS)) { pair_armed = 1; 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", (unsigned)elapsed, (unsigned)BOARD_KEY_OTA_MS); } else if (!pair_armed && !LED_IsEventExist(LED_EVENT_STANDBY) && (elapsed >= BOARD_KEY_POWER_MS)) { LED_EventAdd(LED_EVENT_STANDBY); log_info("boot hold 3s, will power on\n"); } user_led_handle(); /* 按事件表当前状态刷新一次灯 */ } elapsed = timer_get_ms() - t0; if (elapsed < BOARD_KEY_POWER_MS) { log_info("boot hold %ums < 3s, sleep\n", (unsigned)elapsed); boot_sleep(); } /* 松手时已过 5s(且没按到 12s):提交配对;否则只是正常开机 */ if (pair_armed) { usr_var.usr_goto_pair = 1; usr_clear_pair_info_noreset(); app_pair_start(); log_info("boot hold %ums, power on + pair\n", (unsigned)elapsed); } else { log_info("boot hold %ums, power on\n", (unsigned)elapsed); } }