接入温湿度风扇产品固件(仲裁/条件/定时/显示),并补齐规格书与外设驱动

新增 usr_app 产品逻辑:手动>定时>条件仲裁、条件控温湿、定时任务、数码管显示、
按键/LED、风扇档位、NVM 掉电恢复、配对与开关机,上电按规格恢复上次状态。
新增 usr_periph:AHT20、CT1642、板级引脚与硬件封装;见宝协议 cond_config
改为 7 字节编解码,并接入产品 DP。
补充《温湿度风扇_固件需求规格书》,工程加入对应源文件。
.gitignore 忽略 WorkBuddy/Cursor 本地会话
This commit is contained in:
2026-08-31 15:17:27 +08:00
parent 4cb7418a02
commit 5cc7e9dbd6
53 changed files with 7028 additions and 513 deletions
+159
View File
@@ -0,0 +1,159 @@
/******************************************************************************
* @file app_arbiter.c
* @brief CBR3 模式仲裁器实现(规格书第 12 章:手动 > 定时 > 条件)
* @author cyWu <1917507415@qq.com>
* @date 2026.08.31
* @version V1.0.0
* @history
* - V1.0.0, 2026.08.31, cyWu, 首次发布(P2
*
* @note 本模块是唯一模式占用源,运行在 usr_timer_loop(任务上下文)。
* 规则落地(规格书 12 章):
* - 手动动作 → manual_intervene()owner=NONE
* 条件引擎感知后作废本轮(RAM,须回安全再满时长才重新触发);
* 定时引擎感知后本窗剩余时间不自动抢回(等下一窗开始沿)。
* - 定时窗开始 → timer_take()(定时 > 条件,条件即使满时长也不开);
* - 条件触发 → cond_take()(仅 owner!=TIMER 允许;快照只存第一次);
* - 两路条件后触发覆盖 → 仍走 cond_take(),快照不变(不回栈)。
******************************************************************************/
#include "app_arbiter.h"
#include "app_mode.h"
#include "app_fan.h"
#define LOG_TAG_CONST APP
#define LOG_TAG "[ARB]"
#define LOG_INFO_ENABLE
#include "debug.h"
/** 仲裁器上下文 */
typedef struct {
ArbOwner_t owner; /**< 当前占用者 */
uint8_t snap_valid; /**< 条件快照是否有效 */
uint8_t snap_mode; /**< 快照模式(第一次条件抢权前) */
uint8_t snap_gear; /**< 快照档位 */
} AppArbiterCtx_t;
static AppArbiterCtx_t s_arb;
/**
* @brief 初始化仲裁器
* @return 无
*/
void app_arbiter_init(void)
{
s_arb.owner = ARB_OWNER_NONE;
s_arb.snap_valid = 0;
s_arb.snap_mode = 0;
s_arb.snap_gear = 0;
log_info("arbiter init\n");
}
/**
* @brief 当前模式占用者
* @return ArbOwner_t
*/
uint8_t app_arbiter_get_owner(void)
{
return (uint8_t)s_arb.owner;
}
/**
* @brief 手动动作统一入口:释放一切自动化占用
* @note 条件/定时引擎下个 tick 查 owner 感知后各自作废;不恢复快照
* (手动已接管,快照对应的用户状态已过时)
* @return 无
*/
void app_arbiter_manual_intervene(void)
{
if (s_arb.owner != ARB_OWNER_NONE) {
log_info("manual intervene, owner %d -> none\n", s_arb.owner);
}
s_arb.owner = ARB_OWNER_NONE;
}
/**
* @brief 条件引擎尝试占用
* @return 1=成功;0=定时占用中(规格书 12:定时 vs 条件 → 定时胜)
*/
uint8_t app_arbiter_cond_take(void)
{
if (s_arb.owner == ARB_OWNER_TIMER) {
return 0; /* 定时窗内条件不触发 */
}
if (!s_arb.snap_valid) {
/* 第一次条件抢权前快照用户状态;后覆盖/多次触发不改快照(10.3-6) */
s_arb.snap_mode = app_mode_get_active();
s_arb.snap_gear = app_fan_get_gear();
s_arb.snap_valid = 1;
log_info("cond take, snapshot mode=%d gear=%d\n", s_arb.snap_mode, s_arb.snap_gear);
}
s_arb.owner = ARB_OWNER_COND;
return 1;
}
/**
* @brief 条件是否仍在占用
* @return 1=owner==COND
*/
uint8_t app_arbiter_cond_active(void)
{
return (s_arb.owner == ARB_OWNER_COND) ? 1 : 0;
}
/**
* @brief 条件自然失效:恢复快照后调用(清 owner 与快照)
* @return 无
*/
void app_arbiter_cond_release(void)
{
if (s_arb.owner == ARB_OWNER_COND) {
s_arb.owner = ARB_OWNER_NONE;
}
s_arb.snap_valid = 0;
}
/**
* @brief 取条件快照
* @param mode 输出模式
* @param gear 输出档位
* @return 无
*/
void app_arbiter_cond_get_snapshot(uint8_t *mode, uint8_t *gear)
{
*mode = s_arb.snap_mode;
*gear = s_arb.snap_gear;
}
/**
* @brief 条件被手动打断:只清快照(不恢复、不清 owner)
* @return 无
*/
void app_arbiter_cond_snapshot_clear(void)
{
s_arb.snap_valid = 0;
}
/**
* @brief 定时窗开始占用(优先级高于条件)
* @return 1=成功
*/
uint8_t app_arbiter_timer_take(void)
{
if (s_arb.owner != ARB_OWNER_TIMER) {
log_info("timer take\n");
}
s_arb.owner = ARB_OWNER_TIMER;
return 1;
}
/**
* @brief 定时窗结束释放(调用方负责收口:风扇 0、mode 0)
* @return 无
*/
void app_arbiter_timer_release(void)
{
if (s_arb.owner == ARB_OWNER_TIMER) {
s_arb.owner = ARB_OWNER_NONE;
}
}