精简 usr_app 架构:去掉关机/休眠死代码,按键复用 key.c 状态机,ISR 重活统一延后到任务上下文

Type-C 长供电、上电即工作、无软关机,删除 app_boot/app_power 及 DP0 开关相关逻辑,
去掉空占位 app_fan_run 和无效的 usr_timer_pick_mode/rearm(数码管 4ms 扫描已 priority=1,
系统本来就不会进低功耗)。按键 5s 配对 / 12s OTA 改走 key.c 长按分级,去掉自计时与 1~5s 死区。
新增 app_defer,NVM/配对/OTA 只在 ISR 置位、在 500ms 任务上下文落地,避免再在 usr_timer 里写 flash。
规格书与注释同步精简。
This commit is contained in:
2026-08-31 17:57:52 +08:00
parent 5cc7e9dbd6
commit e324ebd99b
51 changed files with 542 additions and 886 deletions
+70 -93
View File
@@ -2,31 +2,30 @@
* @file app_function.c
* @brief CBR3 功能总装实现
* @author cyWu <1917507415@qq.com>
* @date 2026.08.29
* @version V1.1.0
* @history
* - V1.0.0, 2026.08.29, cyWu, 首次发布
* - V1.1.0, 2026.08.31, cyWu, 长按关机改为延后到任务上下文执行:按键在
* usr_timer 20ms(硬件定时器中断上下文)里处理,直接调
* app_power_request_poweroff 会在中断里跑 VM 落盘(栈溢出复位);
* 现改为置 off_pending,由 app_function_loopusr_timer_loop
* BLE 线程)先落盘再关机
* @date 2026.08.31
* @version V2.2.0,上电即开机:短按切档;长按分级满 5s 提示→松手提交配对、
* 满 12s 到点进 OTA;配对/OTA 的实质动作(清绑定写 VM、
* usr_app_ota_init)统一放 app_function_loop(任务上下文)执行,
* 中断层只置标志;DP0 power 恒为开机态(规格书 0 章第 5 条:预留
* 不当开关),已删除 soft_off/is_power_on 等围绕"可关机"的死代码
******************************************************************************/
#include "system/includes.h" /* 必须先于 app_main.hu8/u16/u32 等类型由 SDK 定义 */
#include "app_function.h"
#include "app_power.h"
#include "app_pair.h"
#include "app_mode.h"
#include "app_fan.h"
#include "app_nvm.h"
#include "app_defer.h"
#include "app_arbiter.h"
#include "app_cond.h"
#include "app_timer_task.h"
#include "app_th.h"
#include "app_disp.h"
#include "app_led.h"
#include "app_main.h"
#include "usr_le_api.h"
#include "jb_product.h"
#include "system/includes.h"
#include <string.h>
#define LOG_TAG_CONST APP
@@ -34,49 +33,54 @@
#define LOG_INFO_ENABLE
#include "debug.h"
/** 功能模块状态 */
typedef struct {
uint8_t app_power; /**< DP01=开机态(本产品无 APP 软关) */
uint8_t off_pending; /**< 1=长按已触发关机,等任务上下文落盘后再关机 */
} AppFunctionCtx_t;
static AppFunctionCtx_t s_func;
/**
* @brief 初始化功能模块状态
* @note DP0 power 恒为开机态:规格书 0 章第 5 条"预留,不当开关"
* 协议层 DP0 写入本就忽略(jb_product.c),本产品无软关机,
* 这里写死一次即可,不需要额外状态字段
* @return 无
*/
void app_function_init(void)
{
s_func.app_power = 0;
s_func.off_pending = 0;
gDevData.power = 1;
}
/**
* @brief 任务上下文周期处理(由 usr_timer_loop 500ms 调用)
* @note ⚠ 本函数是唯一允许做 VM 落盘与关机收口的地方:usr_timer_loop 跑在
* BLE 线程(sys_timer 同步接口,任务上下文,栈充足)。20ms 的
* usr_timer_tick 是硬件定时器中断上下文,禁止做这两件事
* @note ⚠ 本函数是唯一允许做 VM 落盘、清绑定、OTA 启动的地方:
* usr_timer_loop 跑在 BLE 线程(sys_timer 同步接口,任务上下文,栈充足)。
* 20ms 的 usr_timer_tick 是硬件定时器中断上下文,做这些会栈溢出复位
* @return 无
*/
void app_function_loop(void)
{
app_nvm_flush(); /* 防抖满后真正写 VMsyscfg_write 必须在任务上下文) */
if (s_func.off_pending) {
s_func.off_pending = 0;
app_power_request_poweroff(); /* 落盘后再走关机流程 */
/* OTA 优先于配对:按满 12s 说明用户不是想配网,放弃本次清绑定 */
if (app_defer_take(APP_DEFER_OTA)) {
app_defer_cancel(APP_DEFER_PAIR);
usr_app_ota_init(); /* BLE 侧:置 usr_goto_updata + 1s 定时器切 OTA 广播 */
app_led_request_ota(); /* 200ms 闪,优先级最高 */
log_info("key hold 12s -> ota\n");
} else if (app_defer_take(APP_DEFER_PAIR)) {
/* ⚠ 真正发起配对广播:usr_goto_pair_mode 内部会断连+清绑定(写VM)+重发绑定广播
* 必须在任务上下文调用(写 VM)。仅置 usr_var.usr_goto_pair 标志无效——
* SDK adv 模块只消费 usr_goto_updata,不消费该标志,不会开广播。 */
usr_goto_pair_mode();
app_pair_start(); /* 起 120s 配对会话,灯交由 app_led_run 接管 */
app_led_clear_pair_hint();
log_info("key hold 5s -> pair\n");
}
}
/**
* @brief 同步 DPpower 恒 1、fan_gear、mode、fault_code),每个业务 tick 调用
* @note DP3/DP4 温湿度在 userHandle500ms)填;DP0 写忽略,运行中恒上报 1
* @brief 同步 DPfan_gear、mode、fault_code),每个业务 tick 调用
* @note DP3/DP4 温湿度在 userHandle500ms)填;DP0 power 不在这里同步,
* 恒为开机态,写死在 app_function_init
* @return 无
*/
void app_function_poll(void)
{
gDevData.power = (s_func.app_power) ? 1 : 0;
gDevData.fan_gear = app_fan_get_gear(); /* DP2 必须等于当前真实档位 */
gDevData.mode = app_mode_get_active();
/* 规格书 8.2/15:传感器故障优先 2;否则温湿度比较成立报 1 */
@@ -89,47 +93,6 @@ void app_function_poll(void)
}
}
/**
* @brief 停手动 + 模式,风扇关(关机请求 / 软关时用)
* @return 无
*/
void app_function_stop_all(void)
{
app_mode_stop();
app_fan_set_gear(0);
}
/**
* @brief 软关:风扇停、DP0=0(本产品 DP0 写忽略,软关仅按键 3s 触发)
* @return 无
*/
void app_function_soft_off(void)
{
s_func.app_power = 0;
gDevData.power = 0;
app_function_stop_all();
log_info("soft off\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 短按:风扇档位循环 1→2→3→0→1…(规格书 5.3)
* @note 立刻退出通风/强力改为手动档:用 app_mode_stop() 只清模式、
@@ -141,17 +104,6 @@ void usr_on_key_short(void)
{
uint8_t g;
if (app_power_poweroff_pending()) {
return;
}
if (!s_func.app_power) {
/* 软关态短按只唤醒,不切档(P0 无 APP 软关,保留分支) */
s_func.app_power = 1;
gDevData.power = 1;
app_led_hint_power_on();
return;
}
app_arbiter_manual_intervene(); /* 手动动作:释放条件/定时占用(12 章) */
app_mode_stop(); /* 退模式(不动档位,下面立刻切循环下一档) */
g = app_fan_get_gear(); /* 当前实际档:手动=手动档;模式中=模式强制档(1/3) */
@@ -161,23 +113,48 @@ void usr_on_key_short(void)
}
/**
* @brief 长按 3s:请求软关机(配对中忽略,避免配到一半睡死,规格书 5.3)
* @note 本回调在 usr_timer 20ms(硬件定时器中断上下文)执行,禁止直接
* 调 app_power_request_poweroff(其钩子会做 VM 落盘 → 栈溢出)
* 只置 off_pending,由 app_function_loop(任务上下文)落盘后关机。
* @brief 按住满 5s:切配对提示灯,提示"松手即配网,继续按到 12s 进 OTA"
* @note 本回调在 usr_timer 20ms(硬件定时器中断上下文)执行,只准动灯效事件
* (纯 RAM)。清绑定写 VM 在 app_function_loop 做
* @return 无
*/
void usr_on_key_long(void)
void usr_on_key_pair_hint(void)
{
if (app_power_poweroff_pending()) {
if (app_led_is_ota()) {
return; /* OTA 灯效最高优先级,不打断 */
}
app_led_hint_pair();
log_info("key hold 5s, pair hint (release to pair, keep to 12s for ota)\n");
}
/**
* @brief 按满 5s 后松手:提交配对(只置标志)
* @note ⚠ 本回调在 usr_timer 20ms(硬件定时器中断上下文)执行,只置标志。
* 清绑定(usr_clear_pair_info_noreset 会写 VM)放到任务上下文。
* @return 无
*/
void usr_on_key_pair_start(void)
{
if (app_led_is_ota()) {
return;
}
if (app_pair_is_active()) {
log_info("key hold 3s ignored, pairing\n");
return;
app_defer_request(APP_DEFER_PAIR);
log_info("key hold 5s released, pair pending\n");
}
/**
* @brief 按住满 12s:进 OTA(只置标志,到点即触发不等松手)
* @note ⚠ 本回调在 usr_timer 20ms(硬件定时器中断上下文)执行,只置标志。
* usr_app_ota_init 涉及 BLE 广播切换,放到任务上下文。
* @return 无
*/
void usr_on_key_ota_start(void)
{
if (app_led_is_ota()) {
return; /* 已在 OTA,不重复发起 */
}
log_info("key hold 3s, poweroff pending (wait vm flush)\n");
s_func.off_pending = 1;
app_defer_request(APP_DEFER_OTA);
log_info("key hold 12s, ota pending\n");
}
/**