Files
JBao_Temp_Humi_Fan_FW/apps/usr_app/app_mode.c
T
wuchuyuan e324ebd99b 精简 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。
规格书与注释同步精简。
2026-08-31 17:57:52 +08:00

175 lines
5.3 KiB
C

/******************************************************************************
* @file app_mode.c
* @brief CBR3 工作模式实现(P1):通风 25/5 循环、强力 15min 一轮
* @author cyWu <1917507415@qq.com>
* @date 2026.08.31
* @version V1.1.0,实现状态机(规格书第 9 章):通风 25/5、强力 15min 后停、
* 手动档快照、退出语义、开机从周期头
*
* @note 模式激活时强制覆盖风扇档位(通风=1 档、强力=3 档、通风停段=0),
* DP2 由 app_fan_get_gear 上报真实档位(app_function_poll 同步)。
* 退出方式(规格书 9 章):短按切档(app_mode_stop)、APP 写档位、
* APP 写 mode=0(恢复进入模式前的手动档快照)、强力自然到点(风扇 0)。
* 开机恢复不存相位:从 25min 开段 / 15min 从头计。
******************************************************************************/
#include "app_mode.h"
#include "app_fan.h"
#include "app_nvm.h"
#include "board_pin.h"
#define LOG_TAG_CONST APP
#define LOG_TAG "[APP_MODE]"
#define LOG_INFO_ENABLE
#include "debug.h"
/** 通风循环段 */
typedef enum {
MODE_VENT_ON = 0, /**< 开段 25min,强制 1 档 */
MODE_VENT_OFF /**< 停段 5min,风扇 0 */
} ModeVentPhase_t;
/** 模式状态机上下文 */
typedef struct {
uint8_t mode; /**< 0=关闭 1=通风 2=强力 */
uint8_t phase; /**< 通风段;其它模式恒 0 */
uint32_t run_ms; /**< 当前段已运行毫秒 */
uint8_t saved_gear;/**< 进入模式前的手动档快照(APP 写 mode=0 时恢复) */
} AppModeCtx_t;
static AppModeCtx_t s_mode;
/**
* @brief 初始化模式状态机
* @return 无
*/
void app_mode_init(void)
{
#if !BOARD_MODE_ENABLE
log_info("mode disabled\n");
return;
#endif
s_mode.mode = 0;
s_mode.phase = 0;
s_mode.run_ms = 0;
s_mode.saved_gear = 0;
log_info("mode init\n");
}
/**
* @brief 推进模式状态机(每个业务 tick 调用)
* @param dt 距上次调用的毫秒数
* @return 无
*/
void app_mode_run(uint16_t dt)
{
#if !BOARD_MODE_ENABLE
(void)dt;
return;
#endif
switch (s_mode.mode) {
case 1: /* 通风:开 25min 强制 1 档,停 5min 风扇 0,循环 */
if (s_mode.phase == MODE_VENT_ON) {
app_fan_set_gear(1);
s_mode.run_ms += dt;
if (s_mode.run_ms >= BOARD_MODE_VENT_ON_MS) {
s_mode.phase = MODE_VENT_OFF;
s_mode.run_ms = 0;
app_fan_set_gear(0);
app_nvm_mark_dirty();
log_info("vent on 25min over, off 5min\n");
}
} else {
s_mode.run_ms += dt;
if (s_mode.run_ms >= BOARD_MODE_VENT_OFF_MS) {
s_mode.phase = MODE_VENT_ON;
s_mode.run_ms = 0;
app_fan_set_gear(1);
app_nvm_mark_dirty();
log_info("vent off 5min over, on 25min\n");
}
}
break;
case 2: /* 强力:强制 3 档,15min 到点风扇 0、mode 回 0 */
app_fan_set_gear(3);
s_mode.run_ms += dt;
if (s_mode.run_ms >= BOARD_MODE_POWER_ON_MS) {
log_info("power 15min over, mode=0 fan=0\n");
s_mode.mode = 0;
s_mode.phase = 0;
s_mode.run_ms = 0;
app_fan_set_gear(0);
app_nvm_mark_dirty();
}
break;
default:
break;
}
}
/**
* @brief APP 写 DP1 / 手动抢权 / 开机恢复:切到指定模式或退出
* @param mode 0=关闭模式(恢复手动档快照),1=通风,2=强力
* @note 模式 1/2 进入时快照当前实际档(即进入前的手动档),并立即强制档位;
* mode=0 时若原在模式中则恢复快照档。短按退出走 app_mode_stop()
* (不恢复快照,档位由短按逻辑立刻切到循环下一档)。
* @return 无
*/
void app_mode_set_manual(uint8_t mode)
{
#if !BOARD_MODE_ENABLE
(void)mode;
return;
#endif
if (mode > 2) {
mode = 0;
}
if (mode != 0) {
s_mode.saved_gear = app_fan_get_gear(); /* 快照进入前的手动档 */
s_mode.mode = mode;
s_mode.phase = MODE_VENT_ON;
s_mode.run_ms = 0; /* 不存相位:开机/手动切入都从周期头计 */
app_fan_set_gear((mode == 1) ? 1 : 3);
log_info("mode set %d, gear=%d\n", mode, app_fan_get_gear());
} else {
if (s_mode.mode != 0) {
/* 只在实际退出模式时恢复快照档,避免 load(0) 把恢复档清零 */
app_fan_set_gear(s_mode.saved_gear);
log_info("mode exit, restore gear=%d\n", s_mode.saved_gear);
}
s_mode.mode = 0;
s_mode.phase = 0;
s_mode.run_ms = 0;
}
app_nvm_mark_dirty();
}
/**
* @brief 查询当前逻辑模式
* @return 0/1/2
*/
uint8_t app_mode_get_active(void)
{
return s_mode.mode;
}
/**
* @brief 停止当前模式(短按退模式用:只清模式状态,不动风扇档位,
* 由调用方立刻切到循环下一档;关机流程则另行停风扇)
* @return 无
*/
void app_mode_stop(void)
{
#if !BOARD_MODE_ENABLE
return;
#endif
if (s_mode.mode != 0) {
app_nvm_mark_dirty();
}
s_mode.mode = 0;
s_mode.phase = 0;
s_mode.run_ms = 0;
}