新增 usr_app 产品逻辑:手动>定时>条件仲裁、条件控温湿、定时任务、数码管显示、 按键/LED、风扇档位、NVM 掉电恢复、配对与开关机,上电按规格恢复上次状态。 新增 usr_periph:AHT20、CT1642、板级引脚与硬件封装;见宝协议 cond_config 改为 7 字节编解码,并接入产品 DP。 补充《温湿度风扇_固件需求规格书》,工程加入对应源文件。 .gitignore 忽略 WorkBuddy/Cursor 本地会话
221 lines
6.6 KiB
C
221 lines
6.6 KiB
C
/******************************************************************************
|
||
* @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_loop(usr_timer_loop,
|
||
* BLE 线程)先落盘再关机
|
||
******************************************************************************/
|
||
|
||
#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_arbiter.h"
|
||
#include "app_cond.h"
|
||
#include "app_timer_task.h"
|
||
#include "app_th.h"
|
||
#include "app_disp.h"
|
||
#include "app_led.h"
|
||
#include "jb_product.h"
|
||
#include "system/includes.h"
|
||
#include <string.h>
|
||
|
||
#define LOG_TAG_CONST APP
|
||
#define LOG_TAG "[APP_FUNC]"
|
||
#define LOG_INFO_ENABLE
|
||
#include "debug.h"
|
||
|
||
/** 功能模块状态 */
|
||
typedef struct {
|
||
uint8_t app_power; /**< DP0:1=开机态(本产品无 APP 软关) */
|
||
uint8_t off_pending; /**< 1=长按已触发关机,等任务上下文落盘后再关机 */
|
||
} AppFunctionCtx_t;
|
||
|
||
static AppFunctionCtx_t s_func;
|
||
|
||
/**
|
||
* @brief 初始化功能模块状态
|
||
* @return 无
|
||
*/
|
||
void app_function_init(void)
|
||
{
|
||
s_func.app_power = 0;
|
||
s_func.off_pending = 0;
|
||
}
|
||
|
||
/**
|
||
* @brief 任务上下文周期处理(由 usr_timer_loop 500ms 调用)
|
||
* @note ⚠ 本函数是唯一允许做 VM 落盘与关机收口的地方:usr_timer_loop 跑在
|
||
* BLE 线程(sys_timer 同步接口,任务上下文,栈充足)。20ms 的
|
||
* usr_timer_tick 是硬件定时器中断上下文,禁止做这两件事。
|
||
* @return 无
|
||
*/
|
||
void app_function_loop(void)
|
||
{
|
||
app_nvm_flush(); /* 防抖满后真正写 VM(syscfg_write 必须在任务上下文) */
|
||
|
||
if (s_func.off_pending) {
|
||
s_func.off_pending = 0;
|
||
app_power_request_poweroff(); /* 落盘后再走关机流程 */
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 同步 DP(power 恒 1、fan_gear、mode、fault_code),每个业务 tick 调用
|
||
* @note DP3/DP4 温湿度在 userHandle(500ms)填;DP0 写忽略,运行中恒上报 1
|
||
* @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 */
|
||
if (app_th_is_fault()) {
|
||
gDevData.fault_code = 2;
|
||
} else if (app_disp_is_alarm()) {
|
||
gDevData.fault_code = 1;
|
||
} else {
|
||
gDevData.fault_code = 0;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @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() 只清模式、
|
||
* 不动档位(若用 set_manual(0) 会恢复模式前快照档,导致通风 1 档
|
||
* 短按跳到旧档+1 而非 2 档);配对进行中短按仍可切档
|
||
* @return 无
|
||
*/
|
||
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) */
|
||
g = (uint8_t)((g + 1) % 4); /* 1→2→3→0→1 */
|
||
app_fan_set_gear(g);
|
||
log_info("key short gear=%d\n", g);
|
||
}
|
||
|
||
/**
|
||
* @brief 长按 3s:请求软关机(配对中忽略,避免配到一半睡死,规格书 5.3)
|
||
* @note ⚠ 本回调在 usr_timer 20ms(硬件定时器中断上下文)执行,禁止直接
|
||
* 调 app_power_request_poweroff(其钩子会做 VM 落盘 → 栈溢出)。
|
||
* 只置 off_pending,由 app_function_loop(任务上下文)落盘后关机。
|
||
* @return 无
|
||
*/
|
||
void usr_on_key_long(void)
|
||
{
|
||
if (app_power_poweroff_pending()) {
|
||
return;
|
||
}
|
||
if (app_pair_is_active()) {
|
||
log_info("key hold 3s ignored, pairing\n");
|
||
return;
|
||
}
|
||
log_info("key hold 3s, poweroff pending (wait vm flush)\n");
|
||
s_func.off_pending = 1;
|
||
}
|
||
|
||
/**
|
||
* @brief 出厂重置:清业务 VM 与 RAM,保留 BLE 配对(规格书 14 章)
|
||
* @return 无
|
||
*/
|
||
void app_function_factory_reset(void)
|
||
{
|
||
uint8_t i;
|
||
uint8_t *c[7] = {
|
||
gDevData.cond_config1, gDevData.cond_config2, gDevData.cond_config3,
|
||
gDevData.cond_config4, gDevData.cond_config5, gDevData.cond_config6,
|
||
gDevData.cond_config7
|
||
};
|
||
uint8_t *tm[7] = {
|
||
gDevData.time_config1, gDevData.time_config2, gDevData.time_config3,
|
||
gDevData.time_config4, gDevData.time_config5, gDevData.time_config6,
|
||
gDevData.time_config7
|
||
};
|
||
|
||
app_nvm_reset();
|
||
app_arbiter_init();
|
||
app_cond_init();
|
||
app_timer_init();
|
||
app_mode_stop();
|
||
app_fan_set_gear(0);
|
||
gDevData.mode = 0;
|
||
gDevData.fan_gear = 0;
|
||
gDevData.cond_en = 0;
|
||
gDevData.time_en = 0;
|
||
gDevData.fault_en = 0;
|
||
gDevData.alarm_en = 0;
|
||
gDevData.fault_code = 0;
|
||
gDevData.alarm_code = 0;
|
||
for (i = 0; i < 7; i++) {
|
||
memset(c[i], 0, 7);
|
||
memset(tm[i], 0, 8);
|
||
}
|
||
log_info("factory reset: business vm cleared, pairing kept\n");
|
||
}
|