优化程序架构
This commit is contained in:
+115
-760
@@ -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, DP2:00=空闲,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; /**< DP0:0=软关,电机/玩法停,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 载荷指针
|
||||
|
||||
Reference in New Issue
Block a user