Files
JBao_Door_Clamp_FW/apps/usr_app/app_function.c
T
wuchuyuan 93c1943992 1、充电时不再叠待机绿灯;意外复位不再跳过 3s 开机按键判定
2、电机停转去掉反接刹车改自由滑行,避免电流冲击触发 LVD 复位;
3、关机直接 power_set_soft_poweroff,跳过耳机 SDK 优雅关机流程,按键关机从十几秒压到瞬间掉电
2026-08-25 20:05:59 +08:00

340 lines
8.2 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/******************************************************************************
* @file app_function.c
* @brief 设备功能开关 + 自动玩法 + 手动点动 + 按键动作实现
* @author cyWu <1917507415@qq.com>
* @date 2026.08.25
* @version V1.0.0
* @history
* - V1.0.0, 2026.08.25, cyWu, 从 usr_jb_main 拆出
******************************************************************************/
#include "app_function.h"
#include "app_power.h"
#include "app_pair.h"
#include "app_mode.h"
#include "app_led.h"
#include "app_time_util.h"
#include "bsp_hw.h"
#include "jb_product.h"
#include "system/includes.h"
#define LOG_TAG_CONST APP
#define LOG_TAG "[APP_FUNC]"
#define LOG_INFO_ENABLE
#include "debug.h"
/** 功能模块总状态,替代原来一堆散落的 static 变量 */
typedef struct {
uint8_t app_power; /**< DP00=软关,电机/玩法停,BLE 仍在 */
uint8_t play_mode; /**< 当前自动模式 0~6 */
uint8_t hand_busy; /**< 手动点动进行中 */
uint8_t hand_cmd_last; /**< 边沿:同一 1/2 不重复启动 */
uint16_t hand_ms;
volatile uint8_t hand_write_pending; /**< DP2 刚写入(03 停转要靠事件) */
volatile uint8_t hand_write_cmd;
} AppFunctionCtx_t;
static AppFunctionCtx_t s_func;
static void function_hand_stop(void);
static void function_play_mode_apply(uint8_t mode);
static void function_play_mode_poll(void);
static void function_hand_poll(void);
static uint8_t function_on_click(void);
/**
* @brief 初始化功能模块状态
* @return 无
*/
void app_function_init(void)
{
memset(&s_func, 0, sizeof(s_func));
}
/**
* @brief DP2 写入钩子:仅记录第 1 字节,真正执行在 app_function_poll
* @param cmd 0=空闲,1=顺时针,2=逆时针,3=停
* @return 无
*/
void app_function_dp_hand_write(uint8_t cmd)
{
s_func.hand_write_cmd = cmd;
s_func.hand_write_pending = 1;
}
/**
* @brief 跟随 APP 下发的 DP0/DP1,并处理 DP2 手动点动
* @return 无
*/
void app_function_poll(void)
{
/* DP0APP 下发开关 */
if (!app_power_usb_online() && !app_power_poweroff_pending()) {
if (gDevData.power && !s_func.app_power) {
s_func.app_power = 1;
app_led_hint_power_on();
log_info("APP power on\n");
} else if (!gDevData.power && s_func.app_power) {
app_function_soft_off();
}
}
function_play_mode_poll();
function_hand_poll();
}
/**
* @brief 推进当前玩法节拍或手动刹车
* @param dt 距上次调用的毫秒数
* @return 无
*/
void app_function_tick_1ms(uint16_t dt)
{
if (s_func.hand_busy) {
bsp_motor_switch_tick();
s_func.hand_ms = app_add_ms(s_func.hand_ms, dt);
} else {
app_mode_run();
}
}
/**
* @brief 停手动点动(走电机反转刹车)
* @return 无
*/
static void function_hand_stop(void)
{
s_func.hand_busy = 0;
s_func.hand_ms = 0;
bsp_motor_set(BSP_MOTOR_STOP);
}
/**
* @brief 停手动 + 自动模式,并清 DP1
* @return 无
*/
void app_function_stop_all(void)
{
s_func.play_mode = 0;
gDevData.play_mode = 0;
app_mode_stop();
function_hand_stop();
}
/**
* @brief 软关:电机停、DP0=0,等 APP/短按再开。不断 BLE
* @return 无
*/
void app_function_soft_off(void)
{
s_func.app_power = 0;
gDevData.power = 0;
s_func.play_mode = 0;
gDevData.play_mode = 0;
app_mode_stop();
function_hand_stop();
log_info("soft off, wait APP power on\n");
}
/**
* @brief 上电默认开启功能(DP0=1),不带开机灯效提示
* @return 无
*/
void app_function_power_on_silent(void)
{
s_func.app_power = 1;
gDevData.power = 1;
}
/**
* @brief 查询功能开关状态(DP0)
* @return 1=开,0=关
*/
uint8_t app_function_is_power_on(void)
{
return s_func.app_power;
}
/**
* @brief 查询手动点动是否进行中
* @return 1=进行中,0=空闲
*/
uint8_t app_function_is_hand_busy(void)
{
return s_func.hand_busy;
}
/**
* @brief 查询当前自动玩法编号
* @return 0=停转,1~6=对应玩法
*/
uint8_t app_function_play_mode(void)
{
return s_func.play_mode;
}
/**
* @brief 切换自动模式 0~6
* @param mode 0=停转,1~6=对应玩法
* @return 无
*/
static void function_play_mode_apply(uint8_t mode)
{
if (mode > 6) {
mode = 0;
}
if (app_power_usb_online() || !s_func.app_power || app_power_poweroff_pending()
|| s_func.hand_busy || app_pair_is_active()) {
mode = 0;
}
s_func.play_mode = mode;
gDevData.play_mode = mode;
if (mode == 0) {
app_mode_stop();
} else {
app_mode_start(mode);
}
}
/**
* @brief 跟随 APP 下发的 DP1 自动模式
* @return 无
*/
static void function_play_mode_poll(void)
{
uint8_t mode;
if (app_power_usb_online() || !s_func.app_power || app_power_poweroff_pending()
|| s_func.hand_busy || app_pair_is_active()) {
return;
}
mode = gDevData.play_mode;
if (mode > 6) {
mode = 0;
gDevData.play_mode = 0;
}
if (mode == s_func.play_mode) {
return;
}
function_play_mode_apply(mode);
log_info("APP play_mode=%d\n", mode);
}
/**
* @brief DP2 手动:只看第 1 字节。0=空闲,1=顺时针,2=逆时针,3=停
* @note 00 00 是 DP 默认值,不当停止。百分比/力度、DP3、DP4 预留不接。
* @return 无
*/
static void function_hand_poll(void)
{
uint8_t cmd;
uint8_t got_write = s_func.hand_write_pending;
if (got_write) {
s_func.hand_write_pending = 0;
cmd = s_func.hand_write_cmd;
} else {
cmd = gDevData.hand_mode[0];
}
if (app_power_usb_online() || !s_func.app_power || app_power_poweroff_pending()
|| app_pair_is_active()) {
if (s_func.hand_busy || (got_write && (cmd == 3))) {
app_function_stop_all();
}
s_func.hand_cmd_last = cmd;
return;
}
if (cmd == 0) {
s_func.hand_cmd_last = 0;
return;
}
if (cmd == 3) {
if (got_write || s_func.hand_busy || app_mode_get_active()) {
app_function_stop_all();
log_info("hand stop cmd=3\n");
}
s_func.hand_cmd_last = 3;
return;
}
if ((cmd == 1 || cmd == 2) && (got_write || (cmd != s_func.hand_cmd_last))) {
s_func.play_mode = 0;
gDevData.play_mode = 0;
app_mode_stop();
s_func.hand_busy = 1;
s_func.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_func.hand_cmd_last = cmd;
}
/**
* @brief 短按:自动模式 0→1→…→6→0
* @return 1=已切换,0=手动点动中被忽略
*/
static uint8_t function_on_click(void)
{
if (s_func.hand_busy) {
log_info("key click ignored, hand busy\n");
return 0;
}
function_play_mode_apply((uint8_t)((s_func.play_mode + 1) % 7));
log_info("key click play_mode=%d\n", s_func.play_mode);
return 1;
}
/**
* @brief 短按回调:充电/配对忽略;软关时唤醒;否则切模式
* @return 无
*/
void usr_on_key_short(void)
{
if (app_power_poweroff_pending()) {
return;
}
if (app_power_usb_online()) {
log_info("key click ignored, charging\n");
return;
}
if (app_pair_is_active()) {
log_info("key click ignored, pairing\n");
return;
}
if (!s_func.app_power) {
s_func.app_power = 1;
gDevData.power = 1;
app_led_hint_power_on();
log_info("key click cancel soft off\n");
return;
}
if (function_on_click()) {
app_led_request_mode_blink();
}
}
/**
* @brief 长按 3s:运行中深睡(开机 3s/5s 不走这里)
* @return 无
*/
void usr_on_key_long(void)
{
if (app_power_poweroff_pending()) {
return;
}
if (app_power_usb_online()) {
log_info("key hold 3s ignored, charging\n");
return;
}
if (app_pair_is_active()) {
log_info("key hold 3s ignored, pairing\n");
return;
}
log_info("key hold 3s, poweroff\n");
app_power_request_poweroff();
}