优化程序架构

This commit is contained in:
2026-08-25 14:59:39 +08:00
parent d5ec6ecde0
commit 5252471aca
25 changed files with 2964 additions and 1608 deletions
+115 -760
View File
@@ -1,18 +1,27 @@
/******************************************************************************
* @file usr_jb_main.c
* @brief CBC2 业务主循环:按键 / 充电 / 电量 / 灯 / 6 档玩法 / 手动点动
* @brief CBC2 业务组合根:只做“先后调用谁、谁通知谁”,不含具体业务算法
* @author cyWu <1917507415@qq.com>
* @date 2026.08.25
* @version V1.4.0
* @version V2.0.0
* @history
* - V1.0.0, 2026.08.21, cyWu, 首次发布
* - V1.1.0, 2026.08.24, cyWu, 收口未接线模块;DP2 仅第 1 字节点动 1s
* - V1.2.0, 2026.08.24, cyWu, 按键:深睡 3s 开机、5s 开机+配对;开机中 3s 深睡
* - V1.3.0, 2026.08.24, cyWu, DP200=空闲,01/02 转,03 停
* - V1.4.0, 2026.08.25, cyWu, 空闲改可休眠定时器,系统才能进 sleep
* - V1.5.0, 2026.08.25, cyWu, LED/按键改充电板事件库,红绿可同时亮
* - V2.0.0, 2026.08.25, cyWu, 重构:电源/配对/开机/功能拆成独立模块,
* 本文件只剩初始化顺序、1ms 调度、模块间接线
*
* @note 协议生成文件 jb_product.c 不要填业务。APP 下行写 gDevData。
* usr_timer_loop 由 BLE 回调,勿再注册第二份。
* 具体业务逻辑请去对应模块找:
* app_power —— USB/充电/电量/深睡请求
* app_pair —— 配对会话计时
* app_boot —— 开机 3s/5s 按键判定
* app_function —— DP0/DP1/DP2 与按键动作
* app_led —— 灯效
******************************************************************************/
#include "system/includes.h"
@@ -28,18 +37,21 @@
#include "usr_le_product.h"
#include "usr_le_api.h"
#include "bsp_hw.h"
#include "app_led.h"
#include "app_power.h"
#include "app_pair.h"
#include "app_boot.h"
#include "app_function.h"
#include "app_mode.h"
#include "ui_manage.h"
#include "asm/power/power_api.h"
#include "asm/power/power_reset.h"
#include <string.h>
#include "app_led.h"
#include "key_manager.h"
#define LOG_TAG_CONST APP
#define LOG_TAG "[USR_JB]"
#define LOG_INFO_ENABLE
#include "debug.h"
extern void sys_enter_soft_poweroff(void *priv);
/* 向 usr_le_code 提供产品身份(换产品只改 jb_protocol.h 宏即可) */
const uint8_t g_usr_le_prodcode[USR_LE_PRODCODE_LEN] = {
JB_CATEGORY_CODE[0], JB_CATEGORY_CODE[1],
@@ -50,770 +62,66 @@ const uint8_t g_usr_le_pcode[USR_LE_PCODE_LEN] = {
JB_PRODUCT_CODE[3], JB_PRODUCT_CODE[4], JB_PRODUCT_CODE[5]
};
#define USR_TIMER_IDLE_MS 20 /**< 空闲节拍:可 sleep;按键 20ms 消抖对齐 */
/** 调度器状态,替代原来 2 个散落的 static */
typedef struct {
int timer_id;
uint8_t fast; /**< 1=1ms 高优(禁睡),0=空闲可休眠 */
} UsrSchedulerCtx_t;
static UsrSchedulerCtx_t s_sched;
static void usr_timer_1_ms(void *priv);
static void usr_timer_rearm(uint8_t fast);
void usr_timer_loop(void);
extern void clr_wdt(void);
extern u32 timer_get_ms(void);
static int jb_timer_id;
static uint8_t s_timer_fast; /**< 1=1ms 高优(禁睡),0=空闲可休眠 */
static uint8_t s_pairing; /**< 1=深睡 5s 进入配对中 */
static uint8_t s_play_mode; /**< 当前自动模式 0~6 */
static uint8_t s_key_raw;
static uint8_t s_key_cnt;
static uint8_t s_key_pressed;
static uint8_t s_boot_key_lock; /**< 上电按着键,松开前不当短按 */
static uint16_t s_key_hold_ms;
static uint16_t s_key_led_override_ms; /**< 切模式闪灯期间不显示配对快闪 */
static uint8_t s_req_poweroff;
static uint8_t s_usb_online;
static uint8_t s_charge_led; /**< 0=无 1=充电红 2=充满绿 */
static uint8_t s_charge_led_last;
static uint16_t s_full_ms;
static uint8_t s_app_power; /**< DP00=软关,电机/玩法停,BLE 仍在 */
static uint16_t s_bat_tick;
static uint16_t s_bat_acc;
static uint8_t s_bat_n;
static uint16_t s_bat_mv;
static uint8_t s_bat_pct;
static uint8_t s_low_bat;
static uint32_t s_low_ms;
static uint8_t s_empty_win;
static uint8_t s_low_enter_win;
static uint8_t s_low_exit_win;
static uint16_t s_bat_boot_ms;
static uint16_t s_bat_log_ms;
static uint8_t s_hand_busy; /**< 手动点动进行中 */
static uint8_t s_hand_cmd_last; /**< 边沿:同一 1/2 不重复启动 */
static uint16_t s_hand_ms;
static volatile uint8_t s_hand_write_pending; /**< DP2 刚写入(03 停转要靠事件) */
static volatile uint8_t s_hand_write_cmd;
static uint32_t s_pair_ms; /**< 配对已持续 ms,满 60s 判失败 */
/**
* @brief 毫秒累加,饱和到 0xFFFF
* @param v 当前值
* @param dt 增加量
* @return 累加结果
*/
static uint16_t usr_add_ms(uint16_t v, uint16_t dt)
{
uint32_t n = (uint32_t)v + dt;
return (n > 0xffffu) ? 0xffffu : (uint16_t)n;
}
#define BAT_SAMPLE_MS 100
#define BAT_AVG_N 8
#define BAT_BOOT_MS 3000 /* 上电 3s 内不因低电深睡 */
#define BAT_LOG_MS 10000
#define USR_TIMER_IDLE_MS 20 /* 空闲节拍:可 sleep;按键 20ms 消抖对齐 */
#define BAT_LOW_WIN 3 /* 连续约 2.4s 才进低电告警 */
#define BAT_EMPTY_WIN 5 /* 连续约 4s 才 3.2V 深睡 */
/**
* @brief 忙等若干毫秒,并喂狗
* @param ms 等待时长
* @brief USB 插拔的联动:插入即停电机,拔出即软关并刷新系统电源图标
* @param evt app_power_tick_1ms 上报的边沿事件
* @return 无
*/
static void usr_boot_delay_ms(uint32_t ms)
static void usr_on_power_evt(AppPowerEvt_t evt)
{
uint32_t t0 = timer_get_ms();
while ((timer_get_ms() - t0) < ms) {
clr_wdt();
switch (evt) {
case APP_POWER_EVT_USB_IN:
app_function_stop_all();
log_info("usb in, motor stop\n");
break;
case APP_POWER_EVT_USB_OUT:
app_function_soft_off();
break;
default:
break;
}
}
/**
* @brief BLE 起来前进深睡(1ms 定时器尚未启动
* @brief 深睡请求钩子:立即停电机、灯全灭(真正掉电在 50ms 后
* @return 无
*/
static void usr_boot_sleep(void)
static void usr_poweroff_request_hook(void)
{
log_info("boot sleep\n");
bsp_hw_enter_sleep_io();
power_set_soft_poweroff();
while (1) {
clr_wdt();
}
app_function_stop_all();
app_led_clear();
}
/**
* @brief 上电是否跳过 3s/5s 按键判定
* @return 1=USB / 软复位 / LVD / 看门狗,保持开机且不进配对
*/
static uint8_t usr_boot_skip_key_wait(void)
{
uint8_t i;
for (i = 0; i < 10; i++) {
if (bsp_chg_is_low() || bsp_vpwr_is_online()) {
log_info("boot usb, skip key wait\n");
return 1;
}
usr_boot_delay_ms(5);
}
if (cpu_reset_by_soft()
|| is_reset_source(MSYS_SOFT_RST)
|| is_reset_source(P33_SOFT_RST)
|| is_reset_source(P33_VDDIO_LVD_RST)
|| is_reset_source(P11_WDT_RST)) {
log_info("boot reset-keep, skip key wait\n");
return 1;
}
return 0;
}
/**
* @brief 深睡唤醒/上电:长按 3s 开机,长按 5s 开机并配对;不足 3s 松手再睡
* @note 必须在 BLE 起来之前调用。配对只置 usr_goto_pair,不调用 usr_goto_pair_mode
* @brief 深睡请求钩子:50ms 到点,真正进入深睡(不会返回)
* @return 无
*/
static void usr_boot_key_wait(void)
static void usr_poweroff_finalize_hook(void)
{
uint32_t t0;
uint32_t elapsed;
uint8_t green_on = 0;
usr_var.usr_goto_pair = 0;
s_pairing = 0;
s_pair_ms = 0;
if (usr_boot_skip_key_wait()) {
return;
}
if (!bsp_key_is_pressed()) {
log_info("boot no key, sleep\n");
usr_boot_sleep();
}
t0 = timer_get_ms();
bsp_led_all_off();
log_info("boot key hold, wait 3s on / 5s pair\n");
while (bsp_key_is_pressed()) {
elapsed = timer_get_ms() - t0;
clr_wdt();
if (elapsed >= BOARD_KEY_PAIR_MS) {
usr_var.usr_goto_pair = 1;
usr_clear_pair_info_noreset();
s_pairing = 1;
s_pair_ms = 0;
log_info("boot hold %ums, power on + pair\n", (unsigned)elapsed);
return;
}
if (!green_on && (elapsed >= BOARD_KEY_POWER_MS)) {
green_on = 1;
bsp_led_green_set(1);
log_info("boot hold 3s, will power on\n");
}
}
elapsed = timer_get_ms() - t0;
if (elapsed < BOARD_KEY_POWER_MS) {
log_info("boot hold %ums < 3s, sleep\n", (unsigned)elapsed);
usr_boot_sleep();
}
log_info("boot hold %ums, power on\n", (unsigned)elapsed);
}
/**
* @brief 停手动点动(走电机反转刹车)
* @return 无
*/
static void usr_hand_stop(void)
{
s_hand_busy = 0;
s_hand_ms = 0;
bsp_motor_set(BSP_MOTOR_STOP);
}
/**
* @brief 停手动 + 自动模式,并清 DP1
* @return 无
*/
static void usr_motor_all_stop(void)
{
s_play_mode = 0;
gDevData.play_mode = 0;
app_mode_stop();
usr_hand_stop();
}
/**
* @brief DP2 写入钩子(jb_product 薄适配调用,不在此驱电机)
* @param cmd 第 1 字节:0=空闲,1=顺时针,2=逆时针,3=停
* @return 无
*/
void usr_dp_hand_write(uint8_t cmd)
{
s_hand_write_cmd = cmd;
s_hand_write_pending = 1;
}
/**
* @brief 软关:电机停、DP0=0,等 APP/短按再开。不断 BLE
* @return 无
*/
static void usr_app_soft_off(void)
{
s_app_power = 0;
gDevData.power = 0;
s_play_mode = 0;
gDevData.play_mode = 0;
app_mode_stop();
usr_hand_stop();
log_info("soft off, wait APP power on\n");
}
/**
* @brief 切换自动模式 0~6
* @param mode 0=停转,1~6=对应玩法
* @return 无
*/
static void usr_play_mode_apply(uint8_t mode)
{
if (mode > 6) {
mode = 0;
}
if (s_usb_online || !s_app_power || s_req_poweroff || s_hand_busy || s_pairing) {
mode = 0;
}
s_play_mode = mode;
gDevData.play_mode = mode;
if (mode == 0) {
app_mode_stop();
} else {
app_mode_start(mode);
}
}
/**
* @brief 跟随 APP 下发的 DP1 自动模式
* @return 无
*/
static void usr_play_mode_poll(void)
{
uint8_t mode;
if (s_usb_online || !s_app_power || s_req_poweroff || s_hand_busy || s_pairing) {
return;
}
mode = gDevData.play_mode;
if (mode > 6) {
mode = 0;
gDevData.play_mode = 0;
}
if (mode == s_play_mode) {
return;
}
usr_play_mode_apply(mode);
log_info("APP play_mode=%d\n", mode);
}
/**
* @brief 跟随 APP 下发的 DP0 开关
* @return 无
*/
static void usr_app_power_poll(void)
{
if (s_usb_online || s_req_poweroff) {
return;
}
if (gDevData.power && !s_app_power) {
s_app_power = 1;
app_led_hint_power_on();
log_info("APP power on\n");
} else if (!gDevData.power && s_app_power) {
usr_app_soft_off();
}
}
/**
* @brief DP2 手动:只看第 1 字节。0=空闲,1=顺时针,2=逆时针,3=停
* @note 00 00 是 DP 默认值,不当停止。百分比/力度、DP3、DP4 预留不接。
* @return 无
*/
static void usr_hand_poll(void)
{
uint8_t cmd;
uint8_t got_write = s_hand_write_pending;
if (got_write) {
s_hand_write_pending = 0;
cmd = s_hand_write_cmd;
} else {
cmd = gDevData.hand_mode[0];
}
if (s_usb_online || !s_app_power || s_req_poweroff || s_pairing) {
if (s_hand_busy || (got_write && (cmd == 3))) {
usr_motor_all_stop();
}
s_hand_cmd_last = cmd;
return;
}
if (cmd == 0) {
s_hand_cmd_last = 0;
return;
}
if (cmd == 3) {
if (got_write || s_hand_busy || app_mode_get_active()) {
usr_motor_all_stop();
log_info("hand stop cmd=3\n");
}
s_hand_cmd_last = 3;
return;
}
if ((cmd == 1 || cmd == 2) && (got_write || (cmd != s_hand_cmd_last))) {
s_play_mode = 0;
gDevData.play_mode = 0;
app_mode_stop();
s_hand_busy = 1;
s_hand_ms = 0;
/* 1=顺时针收绳,2=逆时针放绳(BOARD_MOTOR_IN_INA_HIGH=1 */
bsp_motor_set((cmd == 1) ? BSP_MOTOR_IN : BSP_MOTOR_OUT);
log_info("hand cmd=%d %s until 03\n", cmd,
(cmd == 1) ? "cw" : "ccw");
}
s_hand_cmd_last = cmd;
}
/**
* @brief 手动运行时推进刹车;停转改由 DP2 写 03
* @return 无
*/
static void usr_hand_tick_1ms(uint16_t dt)
{
if (!s_hand_busy) {
return;
}
bsp_motor_brake_tick();
s_hand_ms = usr_add_ms(s_hand_ms, dt);
}
/**
* @brief 深睡入口(须在 1ms 高优定时器之外调用)
* @param priv 未使用
* @return 无
*/
static void usr_do_poweroff(void *priv)
{
(void)priv;
log_info("enter deep off\n");
app_mode_stop();
usr_hand_stop();
bsp_hw_enter_sleep_io();
sys_enter_soft_poweroff(NULL);
}
/**
* @brief 请求深睡:先停电机,50ms 后真正关机
* @return 无
*/
static void usr_key_request_poweroff(void)
{
if (s_req_poweroff) {
return;
}
s_req_poweroff = 1;
log_info("request deep off\n");
app_mode_stop();
usr_hand_stop();
bsp_led_all_off();
sys_timeout_add(NULL, usr_do_poweroff, 50);
}
/**
* @brief 电压换算电量:4.2V=100%3.2V=0%
* @param mv 电池电压,单位 mV
* @return 电量百分比,范围 0~100
*/
static uint8_t usr_bat_percent(uint16_t mv)
{
int32_t span = (int32_t)BOARD_VBAT_FULL_MV - (int32_t)BOARD_VBAT_EMPTY_MV;
int32_t pct;
if (mv <= BOARD_VBAT_EMPTY_MV) {
return 0;
}
if (mv >= BOARD_VBAT_FULL_MV) {
return 100;
}
pct = ((int32_t)mv - BOARD_VBAT_EMPTY_MV) * 100 / span;
if (pct < 0) {
pct = 0;
}
if (pct > 100) {
pct = 100;
}
return (uint8_t)pct;
}
/**
* @brief 电量采样与低电策略
* @note 电机运转时只记电压、不改百分比/告警,避免电流拉垮 VBAT 误报
* @return 无
*/
static void usr_bat_tick_1ms(uint16_t dt)
{
uint16_t mv;
uint8_t pct;
uint8_t motor_busy;
if (s_bat_boot_ms < BAT_BOOT_MS) {
s_bat_boot_ms = usr_add_ms(s_bat_boot_ms, dt);
}
s_bat_tick = usr_add_ms(s_bat_tick, dt);
if (s_bat_tick >= BAT_SAMPLE_MS) {
s_bat_tick = 0;
s_bat_acc += bsp_vbat_mv();
s_bat_n++;
if (s_bat_n >= BAT_AVG_N) {
mv = (uint16_t)(s_bat_acc / s_bat_n);
s_bat_acc = 0;
s_bat_n = 0;
s_bat_mv = mv;
motor_busy = (uint8_t)(app_mode_get_active() != 0 || s_hand_busy);
if (!motor_busy) {
pct = usr_bat_percent(mv);
if (pct != s_bat_pct) {
s_bat_pct = pct;
gDevData.battery = pct;
}
if (s_bat_boot_ms >= BAT_BOOT_MS) {
if (!s_usb_online && mv <= BOARD_VBAT_EMPTY_MV) {
if (s_empty_win < 0xFF) {
s_empty_win++;
}
if (s_empty_win >= BAT_EMPTY_WIN) {
s_low_bat = 1;
gDevData.alm_low_battery = 1;
if (!s_req_poweroff) {
log_info("vbat %dmV empty, deep off\n", mv);
usr_key_request_poweroff();
}
}
} else {
s_empty_win = 0;
}
if (mv < BOARD_VBAT_LOW_MV) {
s_low_exit_win = 0;
if (!s_low_bat && s_low_enter_win < 0xFF) {
s_low_enter_win++;
if (s_low_enter_win >= BAT_LOW_WIN) {
s_low_bat = 1;
s_low_ms = 0;
gDevData.alm_low_battery = 1;
log_info("low battery %dmV %d%%\n", mv, s_bat_pct);
}
}
} else if (mv > (BOARD_VBAT_LOW_MV + BOARD_VBAT_LOW_HYST_MV)) {
s_low_enter_win = 0;
if (s_low_bat) {
if (s_low_exit_win < 0xFF) {
s_low_exit_win++;
}
if (s_low_exit_win >= BAT_LOW_WIN) {
s_low_bat = 0;
s_low_ms = 0;
gDevData.alm_low_battery = 0;
log_info("battery recover %dmV %d%%\n", mv, s_bat_pct);
}
}
} else {
s_low_enter_win = 0;
s_low_exit_win = 0;
}
}
}
}
}
if (s_usb_online || s_req_poweroff || (s_bat_boot_ms < BAT_BOOT_MS)) {
s_low_ms = 0;
} else if (s_low_bat && (s_low_ms < BOARD_LOWBAT_SLEEP_MS)) {
s_low_ms += dt;
if (s_low_ms >= BOARD_LOWBAT_SLEEP_MS) {
s_low_ms = BOARD_LOWBAT_SLEEP_MS;
log_info("low battery 1min, deep off\n");
usr_key_request_poweroff();
}
}
s_bat_log_ms = usr_add_ms(s_bat_log_ms, dt);
if (s_bat_log_ms >= BAT_LOG_MS) {
s_bat_log_ms = 0;
log_info("bat %d%% %dmV alm=%d\n", s_bat_pct, s_bat_mv, s_low_bat);
}
}
/**
* @brief 短按:自动模式 0→1→…→6→0
* @return 无
*/
static void usr_key_on_click(void)
{
if (s_hand_busy) {
log_info("key click ignored, hand busy\n");
return;
}
usr_play_mode_apply((uint8_t)((s_play_mode + 1) % 7));
app_led_request_mode_blink();
s_key_led_override_ms = (uint16_t)((BOARD_LED_MODE_OFF_MS + BOARD_LED_MODE_ON_MS)
* BOARD_LED_MODE_BLINK_N + 50);
log_info("key click play_mode=%d\n", s_play_mode);
}
/**
* @brief 按键状态初值
* @return 无
*/
static void usr_key_init(void)
{
s_play_mode = 0;
s_boot_key_lock = bsp_key_is_pressed() ? 1 : 0;
s_key_pressed = s_boot_key_lock;
s_key_raw = s_key_pressed;
s_key_cnt = BOARD_KEY_DEBOUNCE_MS;
s_key_hold_ms = 0;
if (s_boot_key_lock) {
log_info("boot key held, wait release\n");
}
}
/**
* @brief 按键消抖:开机后 1s 内短按切模式,按住 3s 深睡;充电时忽略
* @note 开机中即使按满 5s 也不进配对。配对只在深睡长按 5s、BLE 起来前判定
* @return 无
*/
static void usr_key_tick_1ms(uint16_t dt)
{
uint8_t raw;
uint16_t hold_old;
if (s_req_poweroff) {
return;
}
raw = bsp_key_is_pressed();
if (raw == s_key_raw) {
if (s_key_cnt < BOARD_KEY_DEBOUNCE_MS) {
s_key_cnt = (uint8_t)usr_add_ms(s_key_cnt, dt);
if (s_key_cnt > BOARD_KEY_DEBOUNCE_MS) {
s_key_cnt = BOARD_KEY_DEBOUNCE_MS;
}
}
} else {
s_key_raw = raw;
s_key_cnt = 0;
}
if (s_key_cnt != BOARD_KEY_DEBOUNCE_MS) {
if (s_key_pressed && !s_boot_key_lock) {
s_key_hold_ms = usr_add_ms(s_key_hold_ms, dt);
}
return;
}
if (raw && !s_key_pressed) {
s_key_pressed = 1;
s_key_hold_ms = 0;
} else if (!raw && s_key_pressed) {
if (s_boot_key_lock) {
s_boot_key_lock = 0;
log_info("boot key released\n");
} else if (s_key_hold_ms < BOARD_KEY_CLICK_MS && s_key_hold_ms >= 10) {
if (s_usb_online) {
log_info("key click ignored, charging\n");
} else if (s_pairing) {
log_info("key click ignored, pairing\n");
} else if (!s_app_power) {
s_app_power = 1;
gDevData.power = 1;
app_led_hint_power_on();
log_info("key click cancel soft off\n");
} else {
usr_key_on_click();
}
}
s_key_pressed = 0;
s_key_hold_ms = 0;
}
if (s_key_pressed && !s_boot_key_lock) {
hold_old = s_key_hold_ms;
s_key_hold_ms = usr_add_ms(s_key_hold_ms, dt);
if ((hold_old < BOARD_KEY_POWER_MS) && (s_key_hold_ms >= BOARD_KEY_POWER_MS)) {
if (s_usb_online) {
log_info("key hold 3s ignored, charging\n");
} else if (s_pairing) {
log_info("key hold 3s ignored, pairing\n");
} else {
log_info("key hold 3s, poweroff\n");
usr_key_request_poweroff();
}
}
}
}
/**
* @brief 充电检测:CHG 低=充电中;VPWR 在且 CHG 高满 1s=充满;拔电软关
* @return 无
*/
static void usr_chg_tick_1ms(uint16_t dt)
{
uint8_t chg_low = bsp_chg_is_low();
uint8_t vpwr = bsp_vpwr_is_online();
uint8_t usb;
if (chg_low) {
s_full_ms = 0;
s_charge_led = 1;
gDevData.charge = CHARGE_1;
usb = 1;
} else if (vpwr) {
/* 拔电时 CHG 先变高、VPWR 还没掉,不能立刻当充满 */
s_full_ms = usr_add_ms(s_full_ms, dt);
if (s_full_ms >= BOARD_CHG_FULL_MS) {
s_charge_led = 2;
}
gDevData.charge = (s_charge_led == 1) ? CHARGE_1 : CHARGE_2;
usb = 1;
} else {
s_full_ms = 0;
s_charge_led = 0;
gDevData.charge = CHARGE_2;
usb = 0;
}
if (usb != s_usb_online) {
s_usb_online = usb;
log_info("usb %s vpwr=%d chg=%d mv=%d pair=%d goto=%d\n",
usb ? "in" : "out", vpwr, chg_low, bsp_vpwr_mv(),
usr_get_pair_flag(), usr_var.usr_goto_pair);
if (usb) {
app_mode_stop();
usr_hand_stop();
s_play_mode = 0;
gDevData.play_mode = 0;
log_info("usb in, motor stop\n");
} else {
ui_update_status(STATUS_NORMAL_POWER);
usr_app_soft_off();
}
}
usr_var.usr_power_charge_flag = s_usb_online ? 1 : 2;
if (s_charge_led != s_charge_led_last) {
s_charge_led_last = s_charge_led;
log_info("charge_led=%d chg=%d vpwr=%d mv=%d\n",
s_charge_led, chg_low, vpwr, bsp_vpwr_mv());
}
}
/**
* @brief 组装灯效上下文:充电 > 配对 > 软关灭灯 > 低电 > 切模式闪 > 绿灯
* @return 无
*/
static void usr_led_tick_1ms(uint16_t dt)
{
AppLedCtx_t led;
uint8_t paired;
if (s_req_poweroff) {
bsp_led_all_off();
return;
}
paired = usr_get_pair_flag();
if (s_pairing) {
if (paired) {
app_led_start_pair_result(1);
s_pairing = 0;
s_pair_ms = 0;
log_info("pair ok\n");
} else {
s_pair_ms += dt;
if (s_pair_ms >= BOARD_PAIR_TIMEOUT_MS) {
s_pairing = 0;
s_pair_ms = 0;
app_led_start_pair_result(0);
log_info("pair timeout 60s, stay on\n");
}
}
}
if (s_key_led_override_ms) {
if (s_key_led_override_ms > dt) {
s_key_led_override_ms = (uint16_t)(s_key_led_override_ms - dt);
} else {
s_key_led_override_ms = 0;
}
}
memset(&led, 0, sizeof(led));
led.charge_led = s_charge_led;
led.pairing = (uint8_t)(s_pairing && s_app_power && (s_key_led_override_ms == 0));
led.app_power = s_app_power;
led.low_bat = s_low_bat;
led.life_on = 1;
app_led_tick_1ms(&led, dt);
}
/**
* @brief 业务初始化(在 BLE 栈起来之前由 app_main 调用)
* @note 内部会等按键 3s/5s;不足 3s 直接深睡,不会启动 1ms 定时器
* @return 无
*/
void usr_jb_init(void)
{
jbInit();
userInit();
bsp_hw_init();
app_led_init();
app_mode_init();
usr_boot_key_wait();
usr_key_init();
s_app_power = 1;
gDevData.power = 1;
s_hand_busy = 0;
s_hand_cmd_last = 0;
s_hand_write_pending = 0;
s_hand_write_cmd = 0;
s_charge_led_last = 0xff;
usr_timer_rearm(0);
log_info("timer idle %ums, sleep ok\n", (unsigned)USR_TIMER_IDLE_MS);
}
/**
* @brief 电机/按键按住时用 1ms 高优定时器;空闲用可休眠节拍
* @return 1=需要 1ms 高优,0=可休眠
*/
static uint8_t usr_timer_should_fast(void)
{
if (s_hand_busy || s_key_pressed || s_req_poweroff) {
if (app_function_is_hand_busy() || bsp_key_is_pressed() || app_power_poweroff_pending()) {
return 1;
}
if (app_mode_get_active() || bsp_motor_is_busy()) {
@@ -829,53 +137,100 @@ static uint8_t usr_timer_should_fast(void)
*/
static void usr_timer_rearm(uint8_t fast)
{
if (jb_timer_id) {
usr_timer_del((u16)jb_timer_id);
jb_timer_id = 0;
if (s_sched.timer_id) {
usr_timer_del((u16)s_sched.timer_id);
s_sched.timer_id = 0;
}
s_timer_fast = fast;
s_sched.fast = fast;
if (fast) {
jb_timer_id = (int)sys_hi_timer_add(NULL, usr_timer_1_ms, 1);
s_sched.timer_id = (int)sys_hi_timer_add(NULL, usr_timer_1_ms, 1);
} else {
jb_timer_id = (int)sys_s_hi_timer_add(NULL, usr_timer_1_ms, USR_TIMER_IDLE_MS);
s_sched.timer_id = (int)sys_s_hi_timer_add(NULL, usr_timer_1_ms, USR_TIMER_IDLE_MS);
}
}
/**
* @brief 业务定时器:空闲可 sleep;玩法/点动时 1ms 且禁 sleep
* @param priv 未使用
* @note 禁止在这里直接 sys_enter_soft_poweroff
* @note 禁止在这里直接 sys_enter_soft_poweroff,一律走 app_power 的深睡钩子
* @return 无
*/
static void usr_timer_1_ms(void *priv)
{
uint16_t dt = s_timer_fast ? 1 : USR_TIMER_IDLE_MS;
uint16_t dt = s_sched.fast ? 1 : USR_TIMER_IDLE_MS;
uint16_t i;
uint8_t want;
AppPowerEvt_t pwr_evt;
(void)priv;
for (i = 0; i < dt; i++) {
jbTimerIrq();
}
usr_key_tick_1ms(dt);
usr_chg_tick_1ms(dt);
usr_bat_tick_1ms(dt);
usr_app_power_poll();
usr_hand_poll();
usr_play_mode_poll();
if (s_hand_busy) {
usr_hand_tick_1ms(dt);
if (!app_power_poweroff_pending()) {
user_key_scan(dt);
user_key_handle();
}
pwr_evt = app_power_tick_1ms(dt);
usr_on_power_evt(pwr_evt);
app_function_poll();
app_function_tick_1ms(dt);
if (app_power_poweroff_pending()) {
app_led_clear();
} else {
app_mode_run();
app_led_run(dt, app_function_is_power_on());
}
usr_led_tick_1ms(dt);
want = usr_timer_should_fast();
if (want != s_timer_fast) {
if (want != s_sched.fast) {
usr_timer_rearm(want);
}
}
/**
* @brief 业务初始化(在 BLE 栈起来之前由 app_main 调用)
* @note 内部会等按键 3s/5s;不足 3s 直接深睡,不会启动 1ms 定时器。
* 按键判定只摸 bsp_hw 的裸 GPIO,不经过协议栈/灯效表/电机状态机,
* 所以只有 bsp_hw_init() 需要排在它前面——一旦判定要睡回去,
* boot_sleep() 原地喂狗不再返回,后面这些初始化不会被浪费。
* @return 无
*/
void usr_jb_init(void)
{
bsp_hw_init();
app_boot_wait_key(); /* 深睡分支不会返回;返回即代表确定要开机 */
jbInit();
userInit();
app_led_init();
app_mode_init();
app_power_init();
app_power_set_hooks(usr_poweroff_request_hook, usr_poweroff_finalize_hook);
app_function_init();
user_key_init();
user_key_lock_if_held();
app_function_power_on_silent();
usr_timer_rearm(0);
log_info("timer idle %ums, sleep ok\n", (unsigned)USR_TIMER_IDLE_MS);
}
/**
* @brief DP2 写入钩子(jb_product 薄适配调用,不在此驱电机)
* @param cmd 第 1 字节:0=空闲,1=顺时针,2=逆时针,3=停
* @return 无
*/
void usr_dp_hand_write(uint8_t cmd)
{
app_function_dp_hand_write(cmd);
}
/**
* @brief BLE 收到见宝载荷,送入协议环形缓冲
* @param data 载荷指针