Files
JBao_Temp_Humi_Fan_FW/apps/usr_app/app_mode.c
T
wuchuyuan 5cc7e9dbd6 接入温湿度风扇产品固件(仲裁/条件/定时/显示),并补齐规格书与外设驱动
新增 usr_app 产品逻辑:手动>定时>条件仲裁、条件控温湿、定时任务、数码管显示、
按键/LED、风扇档位、NVM 掉电恢复、配对与开关机,上电按规格恢复上次状态。
新增 usr_periph:AHT20、CT1642、板级引脚与硬件封装;见宝协议 cond_config
改为 7 字节编解码,并接入产品 DP。
补充《温湿度风扇_固件需求规格书》,工程加入对应源文件。
.gitignore 忽略 WorkBuddy/Cursor 本地会话
2026-08-31 15:17:27 +08:00

178 lines
5.4 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_mode.c
* @brief CBR3 工作模式实现(P1):通风 25/5 循环、强力 15min 一轮
* @author cyWu <1917507415@qq.com>
* @date 2026.08.29
* @version V1.1.0
* @history
* - V1.0.0, 2026.08.29, cyWu, 首次发布(P0 stub
* - V1.1.0, 2026.08.31, cyWu, P1 实现状态机(规格书第 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;
}