Initial import
This commit is contained in:
@@ -0,0 +1,229 @@
|
||||
/******************************************************************************
|
||||
* @file app_boot.c
|
||||
* @brief 深睡唤醒 / 上电按键判定实现
|
||||
* @author cyWu <1917507415@qq.com>
|
||||
* @date 2026.08.27
|
||||
* @version V1.4.0
|
||||
* @history
|
||||
* - V1.0.0, 2026.08.25, cyWu, 首次发布,实现深睡唤醒按键判定(3s 开机 / 5s 配对)
|
||||
* - 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_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/charge.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);
|
||||
extern u8 is_ldo5v_wakeup(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 起来前进深睡(1ms 定时器尚未启动),原地喂狗不返回
|
||||
* @note power_set_soft_poweroff() 只是向 SDK 底层发起软关机请求(置个标志位),
|
||||
* 不是同步断电——仓库里其它调用点(如 app_power_manage.c)调用完都是
|
||||
* 正常往下走/return,真正切电源是底层电源管理在之后某个时机才执行的。
|
||||
* 此时 BLE 栈、1ms 业务定时器都还没起来,如果这里直接 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 拒绝开机前的低电提示:红灯闪 BOARD_BOOT_LOWBAT_BLINK_N 下
|
||||
* @note 直接挂 LED_EVENT_BOOT_REJECT,闪烁节奏/次数由 led_manager 的事件表
|
||||
* 统一管理,这里只管等它闪完(事件闪完会自己删掉)
|
||||
* @return 无
|
||||
*/
|
||||
static void boot_blink_low_battery(void)
|
||||
{
|
||||
LED_EventAdd(LED_EVENT_BOOT_REJECT);
|
||||
while (LED_IsEventExist(LED_EVENT_BOOT_REJECT)) {
|
||||
clr_wdt();
|
||||
user_led_handle();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 开机前电量判定:连续采样取均值,避免单次毛刺误判
|
||||
* @note 此时 app_battery/app_power 均未初始化,只能摸裸电压,不走那套
|
||||
* 滤波/缓冲算法;和运行中的自动关机(app_power)共用同一门限
|
||||
* BOARD_VBAT_SHUTDOWN_MV(约 5%),口径一致
|
||||
* @return 1=电量过低(约 <=5%),0=正常
|
||||
*/
|
||||
static uint8_t boot_battery_too_low(void)
|
||||
{
|
||||
uint32_t acc = 0;
|
||||
uint8_t i;
|
||||
const uint8_t n = 4;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
acc += bsp_vbat_mv();
|
||||
boot_delay_ms(5);
|
||||
}
|
||||
return (uint8_t)((acc / n) <= BOARD_VBAT_SHUTDOWN_MV);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 上电是否跳过 3s/5s 按键判定
|
||||
* @note 只有“真的断电后重新插电池 / 用户主动按键”才需要走 3s/5s 判定;
|
||||
* USB 在位、或者芯片自己意外重启的情况,都应该直接保持开机,
|
||||
* 否则用户会遇到“设备莫名关机、还要求重新按 3 秒才能开机”的怪现象。
|
||||
* @return 1=USB / 软复位 / LVD / 看门狗,保持开机且不进配对;0=需要走按键判定
|
||||
*/
|
||||
static uint8_t boot_skip_key_wait(void)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
/* LDO5V wake is latched by P33 and remains reliable while the live
|
||||
* voltage/CHG detectors are still settling after a soft-poweroff reset. */
|
||||
if (is_ldo5v_wakeup()) {
|
||||
log_info("boot ldo5v wake, skip key wait\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* USB 在位(充电口有电):说明是插着电源,不是用户凭空按键开机 */
|
||||
for (i = 0; i < 10; i++) {
|
||||
if (bsp_chg_is_low() || bsp_vpwr_is_online()
|
||||
|| get_ldo5v_online_hw()) {
|
||||
log_info("boot usb, skip key wait\n");
|
||||
return 1;
|
||||
}
|
||||
boot_delay_ms(5);
|
||||
}
|
||||
|
||||
// /* 以下都是“芯片自己意外重启了一下”,不是用户主动按开机键,
|
||||
// * 不能因此逼用户重新按键,否则相当于设备无故“关机”了一次 */
|
||||
// if (cpu_reset_by_soft() /* SDK 综合判断:是否软件复位 */
|
||||
// || is_reset_source(MSYS_SOFT_RST) /* 主系统软件复位(断言/异常/OTA 后重启等) */
|
||||
// || is_reset_source(P33_SOFT_RST) /* P33 软件复位,最常见的软复位入口 */
|
||||
// || is_reset_source(P33_VDDIO_LVD_RST) /* VDDIO 低压复位(电机启动拉低电压误触发) */
|
||||
// || is_reset_source(P11_WDT_RST)) { /* 看门狗复位(程序卡死被强制重启) */
|
||||
// log_info("boot reset-keep, skip key wait\n");
|
||||
// return 1;
|
||||
// }
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 等待并判定开机按键
|
||||
* @note 按满 5s 立即进入配对;继续按住到 12s 时直接转入 OTA。
|
||||
* 3s 常亮 / 5s 快闪直接复用 led_manager 的 LED_EVENT_STANDBY /
|
||||
* LED_EVENT_PAIRING 事件(和正常运行时配对灯效完全一致的节奏),
|
||||
* 不再手写一份闪烁定时。LED 事件库由调用方(usr_jb_init)在本函数
|
||||
* 之前完成初始化,这里直接假定可用,跟 bsp_hw_init() 一个道理。
|
||||
* @return 无(深睡分支不返回)
|
||||
*/
|
||||
void app_boot_wait_key(void)
|
||||
{
|
||||
uint32_t t0;
|
||||
uint32_t elapsed;
|
||||
uint8_t pair_started = 0;
|
||||
|
||||
usr_var.usr_goto_pair = 0;
|
||||
|
||||
/* USB 在位直接开机,不走 3s/5s/12s 按键判定 */
|
||||
if (boot_skip_key_wait()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!bsp_key_is_pressed()) {
|
||||
log_info("boot no key, sleep\n");
|
||||
boot_sleep();
|
||||
}
|
||||
|
||||
/* 未充电时电量过低:闪灯提示后继续深睡,不给开机 */
|
||||
if (boot_battery_too_low()) {
|
||||
log_info("boot battery <=5%%, blink %d and stay off\n", BOARD_BOOT_LOWBAT_BLINK_N);
|
||||
boot_blink_low_battery();
|
||||
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 立即进入配对;继续按住时仍检测 12s OTA。 */
|
||||
if (!pair_started && (elapsed >= BOARD_KEY_PAIR_MS)) {
|
||||
pair_started = 1;
|
||||
usr_var.usr_goto_pair = 1;
|
||||
usr_clear_pair_info_noreset();
|
||||
app_pair_start();
|
||||
LED_EventDelete(LED_EVENT_STANDBY);
|
||||
LED_EventAdd(LED_EVENT_PAIRING);
|
||||
log_info("boot hold %ums, power on + pair (keep holding to %ums for ota)\n",
|
||||
(unsigned)elapsed, (unsigned)BOARD_KEY_OTA_MS);
|
||||
} else if (!pair_started && !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 阈值提交;松手这里只记录普通开机。 */
|
||||
if (!pair_started) {
|
||||
log_info("boot hold %ums, power on\n", (unsigned)elapsed);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user