精简 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
+4 -8
View File
@@ -796,10 +796,6 @@
<Option compilerVar="CC" />
</Unit>
<Unit filename="apps/usr_periph/bsp_aht20.h" />
<Unit filename="apps/usr_app/app_boot.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="apps/usr_app/app_boot.h" />
<Unit filename="apps/usr_app/app_cond.c">
<Option compilerVar="CC" />
</Unit>
@@ -832,14 +828,14 @@
<Option compilerVar="CC" />
</Unit>
<Unit filename="apps/usr_app/app_nvm.h" />
<Unit filename="apps/usr_app/app_defer.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="apps/usr_app/app_defer.h" />
<Unit filename="apps/usr_app/app_pair.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="apps/usr_app/app_pair.h" />
<Unit filename="apps/usr_app/app_power.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="apps/usr_app/app_power.h" />
<Unit filename="apps/usr_app/app_th.c">
<Option compilerVar="CC" />
</Unit>
+93 -60
View File
@@ -7,12 +7,18 @@
| 工程 | `温湿度风扇_soc_JieLi-JL7016` |
| 产品码 | ProdtCode=`CBR3`productCode=`PRCBR3` |
| 协议 | 见宝 SOC 55AAV1.0.0 |
| 文档版本 | V1.2.0 |
| 文档版本 | V2.2.0 |
| 日期 | 2026.08.31 |
| 作者 | cyWu |
| 读者 | WorkBuddy / 固件开发 |
| 参考工程 | `D:\Jianbao\Project\产品\宠物\门夹弹力绳\门夹弹力绳_soc_JieLi-JL7016` |
> **V2.2.0 变更(2026-08-31):** 顺着 V2.1.0 删 `app_power` 的思路,继续清掉同一类"保留但无调用者"的死代码:删除 `app_function_soft_off()` / `app_function_is_power_on()` / `app_function_power_on_silent()``gDevData.power` 恒为 1、写死在 `app_function_init()`(不再需要 `s_func.app_power` 状态字段);`usr_on_key_short()` 里对应的"软关态唤醒"死分支一并删除。
>
> **V2.1.0 变更(2026-08-31):** 关机功能确认彻底不存在(关机=拔电),**整模块删除 `app_power.c/.h`**(原 request/finalize 深睡钩子已无任何触发源,纯累赘代码);`usr_jb_main.c`/`app_function.c`/`app_disp.c` 里所有 `app_power_poweroff_pending()` 判断一并清理。同时把配对/OTA/NVM 落盘的"ISR 打标志"统一收进新模块 `app_defer.c/.h`(见 16 章)。
>
> **V2.0.0 变更(2026-08-31):** **上电即自动开机**,删除 `app_boot`(原阻塞式 3s/5s/12s 开机判定整模块移除)。按键语义改为运行态按住分级:**短按切档;按住 5s 松手清绑定进配对;按住 12s 到点即进 OTA;取消长按 3s 软关机**(拔电即关)。详见 5.1/5.2/5.3。
>
> **V1.2.0 变更(2026-08-31):** 风扇档位占空比按用户拍板改为 **1档 50%5000/10000)、2档 75%7500/10000**(原 35%/65%,第 5.3/7/17/18 章同步)。
>
> **V1.1.0 变更(2026-08-31):** IO 分离。CT1642 改走 **PG0(CLK)/PG1(DATA)**AHT20 独占 **PC4(SCL)/PC5(SDA)**,两路物理隔离,**删除 `bsp_bus` 共线分时机制**(原 8.3 节整体替换为"IO 独立")。同时把 2.2 节显示协议修正为实测 **18bit 帧**。
@@ -25,9 +31,9 @@
1. **先改协议再写业务。** Excel 里 `cond_config1~7` 已是 **7 字节**,当前工程 `jb_protocol.*` / `dp_definition.json` 仍是 6 字节。必须按 Excel 重新生成协议,禁止继续按 6 字节解析。
2. **不要把业务算法写进 `jb_product.c`。** 只把 DP 写入 `gDevData` 并转调 `app_*`。组合根是 `usr_jb_main.c`(照门夹)。
3. **不要抄门夹的电池 / USB 直通开机 / 低电拒绝开机。** 本机 USB 常电、无电池。插上电 **不会** 自动工作,必须长按 3s
3. **不要抄门夹的电池 / 低电拒绝开机。** 本机 USB 常电、无电池。**上电即开机**(V2.0.0 起,不再长按 3s 才开机);拔电即关,无软关机深睡
4. **不要把调试 UART 放在 PC5。** 调试 UART TX = **PG6**`IO_PORTG_06`)。PC5 是 AHT20 SDA(独立使用)。
5. **DP0 `power` 预留,不当开关。** 真开关只有按键 3s 软开关机。运行中上报 `power=1`,写忽略。
5. **DP0 `power` 预留,不当开关。** 上电恒为开机态(`power=1`),运行中上报 `power=1`,写忽略;停机靠短按切到 0 档或拔电
6. **CT1642 与 AHT20 已 IO 分离(V1.1.0)。** CT1642 走 PG0(CLK)/PG1(DATA)AHT20 走 PC4(SCL)/PC5(SDA),两路独立、无总线竞争,**不存在分时/总线锁**(见 8.3)。
7. 每个模块必须能用 `board_pin.h``BOARD_xxx_ENABLE` **单独关掉** 仍能编过、能配网上报(关掉的模块返回空操作)。
8. 日志全部 **英文**。中文只出现在注释和本文。
@@ -95,45 +101,48 @@ apps/earphone/app_main.c
└─ usr_rtc_init()
└─ usr_jb_init() ← 唯一组合根
bsp_hw_init()
app_led_init() ← 必须在开机等待之前
app_boot_wait_key() ← 3s/5s/12s,失败则 soft poweroff 不返回
app_led_init() ← 灯效事件表最先装载
jbInit() + userInit()
若 usr_goto_updata → OTA
app_nvm_load() ← 恢复 VM
app_fan_init()
app_disp_init()
app_th_init()
app_mode_init()
app_cond_init()
app_timer_init()
(上电即开机:无按键等待,不再有 app_boot)
app_fan_init() / app_disp_init()
usr_timer_add(app_disp_scan, 4ms, priority=1) ← CT1642 扫描,常驻
app_th_init() / app_mode_init() / app_arbiter_init()
app_cond_init() / app_timer_init()
app_nvm_init() + app_nvm_load() ← 恢复 VM
app_function_init()
user_key_init() + lock_if_held
usr_timer_rearm(20ms)
usr_timer_add(usr_timer_tick, 20ms, priority=1) ← 常驻,永不重挂
```
**20ms 业务节拍**`usr_timer_tick`与门夹相同,禁止再开 1ms ISR):
**20ms 业务节拍**`usr_timer_tick`硬件定时器中断上下文,禁止再开 1ms ISR):
1. `jbTimerIrq()` × dt
2. `user_key_scan` + `user_key_handle`
3. `app_th_poll`(内部 2s 才真正采;IO 分离后采集与显示互不干扰)
4. `app_cond_run` / `app_timer_run` / `app_mode_run`(仲裁见第 12 章)
5. `app_fan_run`
6. `app_disp_run`(闪烁、刷新)
7. `app_led_run`
8. `app_function_poll`(同步 DP
9. 重装定时器(按键按住 / 风扇转 / 关机流程中 → 不可睡)
1. `jbTimerIrq()` × dt
2. `user_key_scan` + `user_key_handle`
3. `app_th_poll`(内部 2s 才真正采;IO 分离后采集与显示互不干扰)
4. `app_mode_run`(通风/强力状态机;条件/定时引擎在 500ms 任务上下文,见下)
5. `app_disp_run`(闪烁、刷新)
6. `app_function_poll`(同步 DP
7. `app_nvm_tick`(变化检测 + 500ms 防抖计时,不写 flash
8. `app_led_run`
`usr_timer_loop()`BLE 500ms)只做:`userHandle()` 填温湿度 DP + `jbProtocolHandle()`
**priority 固定 1、只注册一次,不动态重挂**:本产品 Type-C 长供电,不需要低功耗;
`app_disp_scan` 本身就以 priority=1 常驻,系统本来就永远无法进入低功耗——
按业务状态动态切换 `usr_timer_tick` 自己的 priority 没有任何实际效果,已删除
(原 `usr_timer_pick_mode`/`usr_timer_rearm`,规格书 V2.3.0 起废弃)。
`usr_timer_loop()`BLE 500ms 任务上下文):`userHandle()` 填温湿度 DP、
`jbProtocolHandle()``app_cond_run()`/`app_timer_run()`(条件/定时引擎,
仲裁见第 12 章)、`app_function_loop()`(VM 落盘 + 配对/OTA 落地)。
可直接复用门夹源码(拷贝后改引脚/事件表,不要改框架语义):
| 复用 | 路径 | 改什么 |
|---|---|---|
| 按键 FSM | `key.c` / `key.h` / `key_manager.c` | 短按切档长按关机 |
| 按键 FSM | `key.c` / `key.h` / `key_manager.c` | 短按切档**按住分级 5s 配对 / 12s OTA**V2.0.0,无长按关机 |
| LED 事件库 | `led.c` / `led.h` / `led_manager.c` | 单灯 PC2,删红绿双通道 |
| 开机判定 | `app_boot.c` | **删除 USB 直通、低电拒绝** |
| ~~开机判定~~ | ~~`app_boot.c`~~ | **V2.0.0 已整模块删除**(上电即开机,判定下沉到 key_manager |
| 配对会话 | `app_pair.c` | 120s 超时,灯效改单灯 |
| 软关机 | `app_power.c` 精简 | 无电池、无充电;只保留 request/finalize |
| ~~软关机~~ | ~~`app_power.c`~~ | **V2.1.0 已整模块删除**:无电池、无充电,关机=拔电,无软件关机路径 |
| RTC | `usr_rtc.c` | 原样 |
| 协议骨架 | `usr_jb_proto` | 重生 7 字节条件 |
@@ -170,38 +179,57 @@ P0 建议先 `MODE/COND/TIMER/NVM=0`,台上只验按键、灯、PWM、数码
## 5. 电源与按键
### 5.1 关机 / 开机
### 5.1 上电 / 断电(V2.0.0 改:上电即开机
- 关机 = `power_set_soft_poweroff()`:风扇 PWM=0 并关 MCPWM,数码管锁存灭(全段灭),LED 灭,BLE 停。
- **插 USB / 冷启动不会自动进入工作态。** 必须按住 3s。
- DP0 不参与。不要用 APP 开关机。
- 无电池逻辑
- **插 USB / 冷启动直接进入工作态**,无需按键,无 3s 等待。上电流程:
`bsp_hw_init()``app_led_init()``jbInit()/userInit()` → 各 `app_*_init()`
`app_function_init()` 里写死 `gDevData.power=1`)→ `app_nvm_load()`
`user_key_init()` + `user_key_lock_if_held()` → 起 20ms 业务节拍
- **关机 = 拔电。** 已取消按键长按 3s 软关机(原 3s 与新的 5s/12s 时间轴直接冲突)。
`app_power.c` 的软关机能力(request/finalize + 关机前落盘)**V2.1.0 已整模块删除**
(无任何触发源,纯累赘代码);**V2.2.0** 进一步删除 `app_function_soft_off` /
`app_function_is_power_on` / `app_function_power_on_silent`(同样无调用者的
死代码,`power` 恒 1 不再需要状态字段)。
- 上电若键仍按着:`user_key_lock_if_held()` 只锁**短按**(防一上电就切档),
不锁长按分级 —— 所以"插电时就按住 5s"照样进配对。
- DP0 不参与开关机,运行中恒上报 `power=1`(写死,非每 tick 同步),写忽略。
- 无电池、无充电逻辑。
### 5.2 关机态按住(`app_boot.c`,用 `timer_get_ms()` 轮询,与运行态 FSM 分开
### 5.2 按住分级(运行态,`key_manager.c` 直接复用 `key.c` 长按/连按/释放事件
| 松开时已按住 | 行为 |
上电后**任意时刻**按住 PB1 都按同一套时序判定(不再有"关机态/开机态"两套):
| 按住时长 | 行为 |
|---|---|
| < 3000 ms | 继续软关机 |
| ≥ 3000 且 < 5000 ms | 正常开机,加载 VM,恢复上次 mode/gear 并从周期起点开跑 |
| 5000 且 < 12000 ms | 开机 + `usr_clear_pair_info` + 进配对(换手机用这条) |
| 12000 ms | 进 OTA门夹 `usr_app_ota_init` 路径 |
| < 5000 ms 松开 | 短按:切档(见 5.3 |
| 满 5000 ms(仍按住) | **只**切配对提示灯(100ms 快闪),**不清绑定** |
| 5s 后、12s 前松开 | 提交配对:`usr_goto_pair_mode()`(断连+清绑定+**重发绑定广播**)+ `app_pair_start()` 起 120s 会话(换手机用这条) |
| 12000 ms(仍按住,到点即触发) | 进 OTA`usr_app_ota_init`,不等松手;同时撤销本次配对 |
设计理由:配对刻意不在 5s 到点提交 —— 用户可能想继续按到 12s 进 OTA,
提前清绑定会误伤已配对的手机。
**上下文约束**:这几个回调跑在 20ms 硬件定时器中断上下文,只准置标志 +
切灯效(纯 RAM)。清绑定(写 VM)与 `usr_app_ota_init`BLE 广播切换)
一律延后到 `app_function_loop()`(500ms 任务上下文)执行 —— 违反会栈溢出软复位
2026-08-31 事故定论)。因此配对/OTA 的实际生效有最多 500ms 延迟。
按住过程 LED 提示(单灯):
-3s常亮(将开机
-5s100ms 闪(将配对
- ≥12s200ms 闪(将 OTA
开机后若键仍按着:`user_key_lock_if_held()`,直到松开才接受短按/长按。
-5s100ms 闪(将配网,松手生效
-12s200ms 闪(已进入 OTA
### 5.3 开机态按键
| 事件 | 行为 |
|---|---|
| 短按 | 风扇档位循环:1(50%) → 2(75%) → 3(100%) → 0(关风扇) → 1 … **立刻退出通风/强力**,改为手动档。设备仍开机,数码管继续刷 |
| 长按 3s | 请求软关机。VM **不清** |
| 短按<1s 松开) | 风扇档位循环:1(50%) → 2(75%) → 3(100%) → 0(关风扇) → 1 … **立刻退出通风/强力**,改为手动档。设备仍开机,数码管继续刷 |
| 按住 5s 后松开 | 清绑定 + 进配对(见 5.2) |
| 按住 12s | 进 OTA(见 5.2 |
| ~~长按 3s 软关机~~ | **V2.0.0 已取消**,拔电即关 |
配对进行中:长按关机可忽略(与门夹一致,避免配到一半睡死)。短按仍可切档
OTA 进行中:忽略配对/短按之外的重复分级(`app_led_is_ota()` 为 1 时不再重入)
配对进行中:短按仍可切档。
---
@@ -211,6 +239,7 @@ P0 建议先 `MODE/COND/TIMER/NVM=0`,台上只验按键、灯、PWM、数码
|---|---|---|
| 软关机 / 未开机 | 灭 | — |
| 正常开机 | 常亮 | 低 |
| 按住满 5s(待配网,未松手) | 100ms 亮 / 100ms 灭 | 中 |
| 配对中 | 100ms 亮 / 100ms 灭,直到成功或 120s 失败 | 中 |
| 配对成功 | 常亮(可保持 3s 再回到常亮,允许直接常亮) | 中 |
| 配对失败 | 200ms 闪 3s,然后常亮 | 中 |
@@ -232,9 +261,10 @@ LED **不** 表示风扇档位,**不** 表示温湿度告警(告警走数码
| 2 | 75% | 7500/10000(用户拍板 2026-08-31 |
| 3 | 100% | 10000/10000 |
- 模块接口建议`app_fan_init` / `app_fan_set_gear(uint8_t)` / `app_fan_get_gear` / `app_fan_run`
- 模块接口:`app_fan_init` / `app_fan_set_gear(uint8_t)` / `app_fan_get_gear`
- DP2 必须等于 **当前真实档位**(通风停 5 分钟那段报 0)。
- 换档无需软爬坡(P0 不做)。若 100% 上电冲击过大,允许后续加 200ms 爬升,不作为 P0 验收。
- 换档无需软爬坡(P0 不做,也不做占位接口)。若 100% 上电冲击过大,后续要加
200ms 爬升时再新增 `app_fan_run` 接口即可,不作为 P0 验收。
---
@@ -441,11 +471,11 @@ usr_rtc_get_time() 失败 → 全部定时不执行(等同 time_en=0)
- 条件作废标志、模式已运行秒数、AHT20 原始采样
- BLE 三元组(走现有 `CFG_USER_PAIR_INFO`,出厂重置 **不清**
开机 3s 成功后:加载上述字段,**按上次 mode/gear 从周期起点继续工作**。
上电(V2.0.0 起无需按键)后:加载上述字段,**按上次 mode/gear 从周期起点继续工作**。
首次上电(VM 无效):mode=0,gear=0,条件/定时全 0`cond_en=time_en=0`
写 VM 时机:APP 改配置后、单次定时自毁使能时、软关机前、档位/模式稳定变化时(可做 500ms 防抖,避免短按循环打爆 Flash)。
写 VM 时机:APP 改配置后、单次定时自毁使能时、档位/模式稳定变化时(可做 500ms 防抖,避免短按循环打爆 Flash)。
---
@@ -454,7 +484,7 @@ usr_rtc_get_time() 失败 → 全部定时不执行(等同 time_en=0)
- **清全部业务 VM**(第 13 章列表)。
- **保留 BLE 配对,不断开、不软复位。**
- RAM 中 mode=0gear=0,风扇停,条件/定时停止。
- 换机:用户关机后 **按 5s** 清配对进绑定广播。
- 换机:运行中 **按 5s 后松手** 清配对进绑定广播(见 5.2,无需关机)
---
@@ -478,7 +508,7 @@ usr_rtc_get_time() 失败 → 全部定时不执行(等同 time_en=0)
| 25 factory_reset | 第 14 章 |
| 26~28 | 存 RAM/VM 可不实现动作 |
OTA12s 开机走门夹 `usr_app_ota_init``jbOnOtaNotify` 等协议 OTA **P2 可继续 stub**,注释写明未实现,禁止假装升级成功后擦用户区。
OTA运行态按住 12s 走门夹 `usr_app_ota_init`(在 `app_function_loop` 任务上下文调用,灯效 200ms 闪)`jbOnOtaNotify` 等协议 OTA **P2 可继续 stub**,注释写明未实现,禁止假装升级成功后擦用户区。
配对超时 120s,失败保持开机。
@@ -495,11 +525,10 @@ apps/usr_periph/
usr_rtc.c/.h # 已有则保留
apps/usr_app/
key.c/.h, key_manager.c/.h # 拷贝门夹
key.c/.h, key_manager.c/.h # 拷贝门夹;短按切档 + 按住 5s/12s 分级
led.c/.h, led_manager.c/.h # 改单灯
app_boot.c/.h # 拷贝后删 USB/电池
app_led.c/.h
app_power.c/.h # 精简
app_led.c/.h # 含长按 5s "将配网"提示灯
app_defer.c/.h # ISR→任务上下文延后执行标志位(NVM/配对/OTA 统一收口)
app_pair.c/.h
app_fan.c/.h
app_disp.c/.h # 数值、闪烁、--
@@ -523,13 +552,17 @@ apps/usr_app/
**目标:** 两路 IOCT1642 显示 / AHT20 采集)、PWM、按键、灯可独立开关验证。
- [ ] `board_pin.h` + UART TX=PG6,打印正常,且不影响 PC5
- [ ] 关机态 3s 开机、&lt;3s 仍睡;开机态 3s 关机
- [ ] 短按四态循环,示波器/听感确认 50/75/100/0%
- [ ] 插电即开机(不按键,直接进工作态、数码管亮、LED 常亮)
- [ ] 长按 3s **不再**关机(已取消软关机按键入口)
- [ ] 短按(<5s 松手)四态循环,示波器/听感确认 50/75/100/0%
- [ ] 按住满 5s → 100ms 快闪;此时松手 → 清绑定进配对(APP 可搜到)
- [ ] 按住满 5s 不松手继续到 12s → 不进配对,直接进 OTA(200ms 闪)
- [ ] LED 开机常亮、模拟配对闪、模拟 OTA 闪(可用宏强制)
- [ ] CT1642 两管能稳定显示写死的 `25``60`,无鬼影
- [ ] AHT20 串口打印 ℃/%,CRC 正确;采数时数码管不闪、不乱码(IO 独立,无需锁存)
- [ ] `BOARD_TH_ENABLE=0` 时显示仍可刷;`BOARD_DISP_ENABLE=0` 时传感器仍可打印
- [ ] 12s 能进 OTA 广播(可先只打日志 + LED)
- [ ] 长按进配对/OTA 后不复位(验证动作确实走的任务上下文)
**P0 关闭:** `BOARD_MODE/COND/TIMER/NVM_ENABLE=0`
@@ -539,7 +572,7 @@ apps/usr_app/
- [ ] 通风 25/5、强力 15min 后停;短按立即退模式
- [ ] 超限闪(可用调试宏灌假温度)、失败 `--`
- [ ] DP0 写 0 风扇不变、设备不关
- [ ] VM:改档/改模式/写下条件定时后断电,3s 开机从周期头恢复 mode
- [ ] VM:改档/改模式/写下条件定时后断电,重新上电从周期头恢复 mode
- [ ] 定时引擎可只存不跑(`BOARD_TIMER_ENABLE=0` 仍能保存 DP
### P2 — 自动化
+2 -3
View File
@@ -394,9 +394,7 @@ c_SRC_FILES := \
apps/usr_app/key.c \
apps/usr_app/key_manager.c \
apps/usr_app/app_mode.c \
apps/usr_app/app_power.c \
apps/usr_app/app_pair.c \
apps/usr_app/app_boot.c \
apps/usr_app/app_function.c \
cpu/br28/adc_api.c \
cpu/br28/app_audio.c \
@@ -454,7 +452,8 @@ c_SRC_FILES := \
apps/usr_app/app_cond.c \
apps/usr_app/app_timer_task.c \
apps/usr_app/app_arbiter.c \
apps/usr_app/app_nvm.c
apps/usr_app/app_nvm.c \
apps/usr_app/app_defer.c
S_SRC_FILES := \
apps/earphone/sdk_version.z.S \
+1 -1
View File
@@ -326,7 +326,7 @@ void app_main()
usr_var.usr_power_charge_flag=2;
}
/* 配对只由 app_boot 长按 5s 置 usr_goto_pair;禁止上电清三元组(规格书 5.2 / 14 章) */
/* 配对只由运行态长按 5skey_manager 分级)置 usr_goto_pair;禁止上电清三元组(规格书 5.2 / 14 章) */
ui_manage_init();
ui_update_status(STATUS_POWERON);
+1 -3
View File
@@ -3,9 +3,7 @@
* @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
* @version V1.0.0,首次发布(P2
*
* @note 本模块是唯一模式占用源,运行在 usr_timer_loop(任务上下文)。
* 规则落地(规格书 12 章):
+1 -3
View File
@@ -3,9 +3,7 @@
* @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
* @version V1.0.0,首次发布(P2
*
* @note 把"谁在驱动模式"收成一处,避免 mode/cond/timer 互调成环。
* 唯一状态源是 ownerNONE/COND/TIMER+ 条件快照;
-132
View File
@@ -1,132 +0,0 @@
/******************************************************************************
* @file app_boot.c
* @brief CBR3 上电按键判定实现(3s 开机 / 5s 配对 / 12s OTA
* @author cyWu <1917507415@qq.com>
* @date 2026.08.29
* @version V1.0.0
* @history
* - V1.0.0, 2026.08.29, cyWu, 首次发布(移植门夹:删 USB 直通、删低电拒绝)
******************************************************************************/
#include "app_boot.h"
#include "app_pair.h"
#include "bsp_hw.h"
#include "board_pin.h"
#include "app_main.h"
#include "usr_le_api.h"
#include "led_manager.h"
#include "asm/power/power_api.h"
#include "asm/power/power_reset.h"
#define LOG_TAG_CONST APP
#define LOG_TAG "[APP_BOOT]"
#define LOG_INFO_ENABLE
#include "debug.h"
extern void clr_wdt(void);
extern u32 timer_get_ms(void);
/**
* @brief 忙等若干毫秒,并喂狗
* @param ms 等待时长
* @return 无
*/
static void boot_delay_ms(uint32_t ms)
{
uint32_t t0 = timer_get_ms();
while ((timer_get_ms() - t0) < ms) {
clr_wdt();
}
}
/**
* @brief BLE 起来前进深睡(业务定时器尚未启动),原地喂狗不返回
* @note power_set_soft_poweroff() 只是向 SDK 底层发起软关机请求(置个标志位),
* 不是同步断电——真正切电源是底层电源管理在之后某个时机才执行的。
* 此时 BLE 栈、业务定时器都还没起来,如果直接 return,代码会接着把
* usr_jb_init 剩下的初始化跑完,等于白判定。所以必须用 while(1) 卡住:
* 一边喂狗防止看门狗打断,一边等底层真正把电断掉。
* @return 无(不会返回)
*/
static void boot_sleep(void)
{
log_info("boot sleep\n");
bsp_hw_enter_sleep_io();
power_set_soft_poweroff();
while (1) {
clr_wdt();
}
}
/**
* @brief 等待并判定开机按键
* @note 配对(5s)不在到点时立即提交:继续按住观察是否会按到 12s 触发 OTA,
* 真正的配对提交放在松手那一刻做。按满 5s 灯先切到配对快闪提示。
* 3s 常亮 / 5s 快闪直接复用 led_manager 的 LED_EVENT_STANDBY /
* LED_EVENT_PAIRING 事件。LED 事件库由调用方(usr_jb_init)在本函数
* 之前完成初始化,这里直接假定可用。
* @return 无(深睡分支不返回)
*/
void app_boot_wait_key(void)
{
uint32_t t0;
uint32_t elapsed;
uint8_t pair_armed = 0;
usr_var.usr_goto_pair = 0;
/* ⚠ 无 USB 直通:插电/冷启动一律走按键判定(规格书 5.1)。 */
if (!bsp_key_is_pressed()) {
log_info("boot no key, sleep\n");
boot_sleep();
}
t0 = timer_get_ms();
log_info("boot key hold, wait 3s on / 5s pair / 12s ota\n");
while (bsp_key_is_pressed()) {
elapsed = timer_get_ms() - t0;
clr_wdt();
/* 12s 优先于配对:按满 12s 直接进 OTA,不再等松手 */
if (elapsed >= BOARD_KEY_OTA_MS) {
log_info("boot hold %ums, power on + ota\n", (unsigned)elapsed);
usr_app_ota_init();
return;
}
/* 5s 只武装配对并切到快闪,真正提交放到松手那一刻 */
if (!pair_armed && (elapsed >= BOARD_KEY_PAIR_MS)) {
pair_armed = 1;
LED_EventDelete(LED_EVENT_STANDBY);
LED_EventAdd(LED_EVENT_PAIRING);
log_info("boot hold %ums, pair hint blink (release now for pair, "
"keep holding to %ums for ota)\n",
(unsigned)elapsed, (unsigned)BOARD_KEY_OTA_MS);
} else if (!pair_armed && !LED_IsEventExist(LED_EVENT_STANDBY)
&& (elapsed >= BOARD_KEY_POWER_MS)) {
LED_EventAdd(LED_EVENT_STANDBY);
log_info("boot hold 3s, will power on\n");
}
user_led_handle(); /* 按事件表当前状态刷新一次灯 */
}
elapsed = timer_get_ms() - t0;
if (elapsed < BOARD_KEY_POWER_MS) {
log_info("boot hold %ums < 3s, sleep\n", (unsigned)elapsed);
boot_sleep();
}
/* 松手时已过 5s(且没按到 12s):提交配对;否则只是正常开机 */
if (pair_armed) {
usr_var.usr_goto_pair = 1;
usr_clear_pair_info_noreset();
app_pair_start();
log_info("boot hold %ums, power on + pair\n", (unsigned)elapsed);
} else {
log_info("boot hold %ums, power on\n", (unsigned)elapsed);
}
}
-28
View File
@@ -1,28 +0,0 @@
/******************************************************************************
* @file app_boot.h
* @brief CBR3 上电按键判定:3s 开机,5s 配对,12s OTA,不足 3s 松手再睡
* @author cyWu <1917507415@qq.com>
* @date 2026.08.29
* @version V1.0.0
* @history
* - V1.0.0, 2026.08.29, cyWu, 首次发布(移植门夹:删 USB 直通开机、删低电拒绝开机)
*
* @note 必须在 BLE 协议栈起来、业务定时器启动之前调用。杰理 jiffies 此时
* 往往 10ms 才跳一次,所以内部一律用 timer_get_ms 直接量时间。
* ⚠ 本产品 USB 常电、无电池:插电/冷启动【不会】自动进入工作态,
* 必须按住 3s(规格书 5.1/5.2)。门夹的 USB 直通开机逻辑禁止移植。
******************************************************************************/
#ifndef __APP_BOOT_H__
#define __APP_BOOT_H__
/**
* @brief 等待并判定开机按键:不足 3s 松手、或全程未按键,直接原地深睡(不返回);
* 满 3s 视为正常开机;按满 5s 绿灯改快闪提示"松手即配网",真正清绑定 /
* 开绑定广播仍等松手(内部调用 app_pair_start);持续按满 12s 直接开机
* 并进入 OTA(调用 usr_app_ota_init)。
* @return 无(深睡分支通过 while(1) 喂狗不返回;其余情况正常返回)
*/
void app_boot_wait_key(void);
#endif /* __APP_BOOT_H__ */
+4 -8
View File
@@ -2,14 +2,10 @@
* @file app_cond.c
* @brief CBR3 条件引擎(P2):7 组 7 字节条件,比较成立满时长触发模式
* @author cyWu <1917507415@qq.com>
* @date 2026.08.29
* @version V2.0.0
* @history
* - V1.0.0, 2026.08.29, cyWu, 首次发布(P0 stub
* - V1.1.0, 2026.08.31, cyWu, P1set_en/set_config 存 VM(引擎仍关)
* - V2.0.0, 2026.08.31, cyWu, P2 实现完整条件引擎(规格书第 10 章):
* 7 字节解析/AND 比较/时长累计(采样成功才累计)/触发/保持/
* 条件强力循环/后覆盖不回栈/手动作废(RAM)/快照恢复/闪烁喂真值
* @date 2026.08.31
* @version V2.0.0,完整条件引擎(规格书第 10 章):7 字节解析/AND 比较/时长
* 累计(采样成功才累计)/触发/保持/条件强力循环/后覆盖不回栈/手动
* 作废(RAM)/快照恢复/闪烁喂真值
*
* @note 运行上下文:app_cond_run 由 usr_timer_loop500ms,任务上下文)调用
* (规格书 8.4 时长按采样周期 2s 计,500ms 粒度足够;且触发时可能
+1 -3
View File
@@ -3,9 +3,7 @@
* @brief CBR3 条件引擎(P2):7 组 7 字节条件,比较成立满时长触发模式
* @author cyWu <1917507415@qq.com>
* @date 2026.08.29
* @version V1.0.0
* @history
* - V1.0.0, 2026.08.29, cyWu, 首次发布(P0 仅接口与 stub)
* @version V1.0.0,首次发布(P0 仅接口与 stub
*
* @note P2 实现(BOARD_COND_ENABLE=1)。字节布局见规格书 10.2:
* Byte0=使能 Byte1-2=温度阈值(int16 大端 ×10) Byte3=湿度阈值
+57
View File
@@ -0,0 +1,57 @@
/******************************************************************************
* @file app_defer.c
* @brief ISR→任务上下文的延后执行标志位实现
* @author cyWu <1917507415@qq.com>
* @date 2026.08.31
* @version V1.0.0,首次发布
******************************************************************************/
#include "system/includes.h"
#include "app_defer.h"
/** 位掩码,volatilerequest() 在中断上下文写,take()/is_pending()/cancel()
* 在任务上下文读写,两侧都用 local_irq_disable/enable 包一下读改写,
* 避免"任务侧正在清 A 位时中断侧设 B 位"这种读改写竞态把 B 位冲丢。 */
static volatile uint8_t s_flags;
void app_defer_request(AppDeferBit_t bit)
{
if (bit >= APP_DEFER_MAX) {
return;
}
local_irq_disable();
s_flags |= (uint8_t)(1u << bit);
local_irq_enable();
}
uint8_t app_defer_take(AppDeferBit_t bit)
{
uint8_t was_set;
if (bit >= APP_DEFER_MAX) {
return 0;
}
local_irq_disable();
was_set = (s_flags & (uint8_t)(1u << bit)) ? 1 : 0;
s_flags &= (uint8_t)~(1u << bit);
local_irq_enable();
return was_set;
}
uint8_t app_defer_is_pending(AppDeferBit_t bit)
{
if (bit >= APP_DEFER_MAX) {
return 0;
}
return (s_flags & (uint8_t)(1u << bit)) ? 1 : 0;
}
void app_defer_cancel(AppDeferBit_t bit)
{
if (bit >= APP_DEFER_MAX) {
return;
}
local_irq_disable();
s_flags &= (uint8_t)~(1u << bit);
local_irq_enable();
}
+59
View File
@@ -0,0 +1,59 @@
/******************************************************************************
* @file app_defer.h
* @brief ISR→任务上下文的延后执行标志位(统一收口 2026-08-31 复位事故教训)
* @author cyWu <1917507415@qq.com>
* @date 2026.08.31
* @version V1.0.0,首次发布
*
* @note ⚠ 硬约束:flash 擦写(syscfg_write)、BLE 广播切换、关机收口等"重活"
* 禁止在 usr_timer_add 的中断上下文回调(本产品 20ms usr_timer_tick /
* 按键长按回调)里直接执行,只能在 usr_timer_loopBLE 线程,任务
* 上下文,栈充足)里执行。之前每个模块各自发明一个 pending 标志
* off_pending/pair_pending/ota_pending/nvm 的 s_need_save),
* 容易被后来的功能遗漏这条红线——本模块把"打标志"这一步收成统一
* 接口:ISR 只准调 app_defer_request(),真正执行永远在
* app_function_loop() 里用 app_defer_take() 消费。
******************************************************************************/
#ifndef __APP_DEFER_H__
#define __APP_DEFER_H__
#include <stdint.h>
/** 延后动作位,新增一种"需要写flash/切广播/关机"的动作就加一项 */
typedef enum {
APP_DEFER_NVM_SAVE = 0, /**< VM 防抖到点,需要落盘 */
APP_DEFER_PAIR, /**< 长按 5s 松手,需要清绑定进配对 */
APP_DEFER_OTA, /**< 长按 12s 到点,需要进 OTA */
APP_DEFER_MAX
} AppDeferBit_t;
/**
* @brief 中断上下文调用:只置位,不做任何实际动作
* @param bit 要延后的动作
* @return 无
*/
void app_defer_request(AppDeferBit_t bit);
/**
* @brief 任务上下文调用:查询并清除标志(取出即消费,最多处理一次)
* @param bit 要消费的动作
* @return 1=之前挂起过(现在可以执行真正动作),0=没挂起
*/
uint8_t app_defer_take(AppDeferBit_t bit);
/**
* @brief 任务上下文调用:只查询是否挂起,不清除(多个动作互斥判断用)
* @param bit 要查询的动作
* @return 1=挂起中,0=未挂起
*/
uint8_t app_defer_is_pending(AppDeferBit_t bit);
/**
* @brief 任务上下文调用:撤销挂起(如 OTA 触发时要撤销配对)
* @param bit 要撤销的动作
* @return 无
*/
void app_defer_cancel(AppDeferBit_t bit);
#endif /* __APP_DEFER_H__ */
+4 -16
View File
@@ -2,14 +2,10 @@
* @file app_disp.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.0.1, 2026.08.29, cyWu, 改动态扫描:20ms 节拍只算数据写缓冲,
* 另起 BOARD_DISP_SCAN_MS 快节拍定时器轮询点亮 1 位,解决闪烁
* - V1.1.0, 2026.08.31, cyWu, P1 加告警闪烁:温度/湿度管独立 500ms 亮灭,
* BOARD_DISP_ALARM_TEST 宏可强制模拟超限;fault 时 "--" 优先
* @date 2026.08.31
* @version V1.1.0,动态扫描(20ms 算段码写缓冲 + BOARD_DISP_SCAN_MS 快节拍
* 轮询点亮 1 位)+ 告警闪烁(温度/湿度管独立 500ms 亮灭,
* BOARD_DISP_ALARM_TEST 宏可强制模拟超限;fault 时 "--" 优先)
*
* @note ⚠ CT1642 内部只有单个 12 位锁存器(4 位选 + 8 段码),无按位显示 RAM、
* 不自动扫描,一次只点亮当前锁存的那 1 位。要让 4 位都亮且不闪,必须由 MCU
@@ -22,7 +18,6 @@
#include "app_disp.h"
#include "app_th.h"
#include "app_power.h"
#include "bsp_ct1642.h"
#include "board_pin.h"
@@ -212,7 +207,6 @@ void app_disp_run(uint16_t dt)
* @note 必须短、不可阻塞。每次只发 1 帧,靠高频轮询让 4 位视觉同亮不闪。
* IO 分离后 CT1642 独占 PG0/PG1,与 AHT20 的 PC4/PC5 无总线竞争,
* 扫描回调无需锁、无跳过。
* 软关机流程:4 位全灭(com=0x00 → 所有 Cx 高,位选全关)。
* @return 无
*/
void app_disp_scan(void)
@@ -224,12 +218,6 @@ void app_disp_scan(void)
return;
}
/* 软关机流程:数码管锁存灭(规格书 5.1:风扇 0、数码管锁存灭、LED 灭) */
if (app_power_poweroff_pending()) {
bsp_ct1642_send_frame(0x00, 0x00); /* com=0x00 → 4 位全灭 */
return;
}
#if BOARD_DISP_SCAN_TEST == 1
/* 段扫描:4 位同显一段。⭐ 值变化才刷(无鬼影),com=0xF 四位全选同显。 */
static uint8_t seg = 0;
+4 -7
View File
@@ -2,13 +2,10 @@
* @file app_disp.h
* @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, P1 加告警闪烁:温度/湿度管独立 500ms 亮灭,
* 由 app_disp_set_temp/humi_alarm 驱动(P2 条件引擎喂真值,
* P1 可用 BOARD_DISP_ALARM_TEST 宏强制验证)
* @date 2026.08.31
* @version V1.1.0,加告警闪烁:温度/湿度管独立 500ms 亮灭,由
* app_disp_set_temp/humi_alarm 驱动(P2 条件引擎喂真值,也可用
* BOARD_DISP_ALARM_TEST 宏强制验证)
*
* @note 两块 2 位 7 段数码管:温度管整数 ℃、湿度管整数 %。DP 恒灭。
* 0~99 显示绝对值;<0 显示 -9~-1G 段负号);<-9 钳位 -9>99 钳位 99。
+2 -14
View File
@@ -2,10 +2,8 @@
* @file app_fan.c
* @brief CBR3 风扇档位实现
* @author cyWu <1917507415@qq.com>
* @date 2026.08.29
* @version V1.0.0
* @history
* - V1.0.0, 2026.08.29, cyWu, 首次发布
* @date 2026.08.31
* @version V1.1.0,删除 app_fan_run(P0 无动作的空占位,从未真正做过软爬坡)
******************************************************************************/
#include "app_fan.h"
@@ -70,13 +68,3 @@ uint8_t app_fan_get_gear(void)
{
return s_gear;
}
/**
* @brief 业务节拍(P0 无动作,保留接口供 P1 爬坡)
* @param dt 距上次调用的毫秒数
* @return 无
*/
void app_fan_run(uint16_t dt)
{
(void)dt;
}
+2 -11
View File
@@ -2,10 +2,8 @@
* @file app_fan.h
* @brief CBR3 风扇档位:0/1/2/3 → 0%/50%/75%/100%
* @author cyWu <1917507415@qq.com>
* @date 2026.08.29
* @version V1.0.0
* @history
* - V1.0.0, 2026.08.29, cyWu, 首次发布
* @date 2026.08.31
* @version V1.1.0,删除 app_fan_run(从未真正做过软爬坡的空占位)
******************************************************************************/
#ifndef __APP_FAN_H__
@@ -32,11 +30,4 @@ void app_fan_set_gear(uint8_t gear);
*/
uint8_t app_fan_get_gear(void);
/**
* @brief 业务节拍(P0 无动作,保留接口供 P1 爬坡)
* @param dt 距上次调用的毫秒数
* @return 无
*/
void app_fan_run(uint16_t dt);
#endif /* __APP_FAN_H__ */
+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");
}
/**
+26 -34
View File
@@ -1,11 +1,11 @@
/******************************************************************************
* @file app_function.h
* @brief CBR3 功能总装:按键动作(短按切档/长按关机+ DP 同步
* @brief CBR3 功能总装:按键动作(短按切档 / 长按 5s 配对 / 长按 12s OTA+ DP 同步
* @author cyWu <1917507415@qq.com>
* @date 2026.08.29
* @version V1.0.0
* @history
* - V1.0.0, 2026.08.29, cyWu, 首次发布(移植门夹语义重写)
* @date 2026.08.31
* @version V2.2.0,上电即开机:长按分级回调 usr_on_key_pair_hint/pair_start/
* ota_startDP0 power 恒为开机态(无软关机),已删除
* app_function_soft_off/is_power_on 等死代码
*
* @note 本模块只做"按键 → 动作"和"状态 → DP",不写业务算法。
* 档位/模式/条件的执行在各自 app_* 模块(规格书第 0 章第 2 条)。
@@ -23,44 +23,21 @@
void app_function_init(void);
/**
* @brief 同步 DPpower 恒 1、fan_gear、mode、fault_code),每个业务 tick 调用
* @brief 同步 DPfan_gear、mode、fault_code),每个业务 tick 调用
* @note DP0 power 不在这里同步:恒为开机态,写死在 app_function_init
* @return 无
*/
void app_function_poll(void);
/**
* @brief 任务上下文周期处理(由 usr_timer_loop 500ms 调用)
* @note ⚠ VM 落盘(syscfg_write)与关机收口只允许在这里做:usr_timer_loop
* @note ⚠ VM 落盘(syscfg_write)与配对/OTA 落地只允许在这里做:usr_timer_loop
* 跑在 BLE 线程(任务上下文,栈充足);usr_timer_tick 是硬件定时器
* 中断上下文,做这两件事会栈溢出复位。
* 中断上下文,做这会栈溢出复位。
* @return 无
*/
void app_function_loop(void);
/**
* @brief 停手动 + 模式,风扇关(关机请求 / 软关时用)
* @return 无
*/
void app_function_stop_all(void);
/**
* @brief 软关:风扇停、DP0=0(本产品 DP0 写忽略,软关仅按键 3s 触发)
* @return 无
*/
void app_function_soft_off(void);
/**
* @brief 上电默认开启功能(DP0=1),不带开机灯效提示
* @return 无
*/
void app_function_power_on_silent(void);
/**
* @brief 查询功能开关状态(DP0)
* @return 1=开,0=关
*/
uint8_t app_function_is_power_on(void);
/**
* @brief 业务层短按回调(key_manager 触发):档位 1→2→3→0→1…
* @return 无
@@ -68,10 +45,25 @@ uint8_t app_function_is_power_on(void);
void usr_on_key_short(void);
/**
* @brief 业务层长按 3s 回调(key_manager 触发):请求软关机
* @brief 业务层"按住满 5s"回调(key_manager 触发20ms 中断上下文)
* @note 只切提示灯,不清绑定
* @return 无
*/
void usr_on_key_long(void);
void usr_on_key_pair_hint(void);
/**
* @brief 业务层"按满 5s 后松手"回调(key_manager 触发,20ms 中断上下文)
* @note 只置标志:清绑定要写 VM,由 app_function_loop 在任务上下文执行
* @return 无
*/
void usr_on_key_pair_start(void);
/**
* @brief 业务层"按住满 12s"回调(key_manager 触发,20ms 中断上下文)
* @note 只置标志:usr_app_ota_init 由 app_function_loop 在任务上下文执行
* @return 无
*/
void usr_on_key_ota_start(void);
/**
* @brief 出厂重置:清业务 VM 与 RAM,保留 BLE 配对(规格书 14 章)
+31 -6
View File
@@ -2,10 +2,9 @@
* @file app_led.c
* @brief CBR3 灯效适配:单灯 PC2OTA/配对/常亮
* @author cyWu <1917507415@qq.com>
* @date 2026.08.29
* @version V1.0.0
* @history
* - V1.0.0, 2026.08.29, cyWu, 首次发布(移植门夹,删红绿双通道/充电/低电/空电)
* @date 2026.08.31
* @version V1.1.0,新增 s_pair_hint:长按满 5s 到松手提交配对这段窗口内维持
* 配对快闪,避免被 app_led_run 叠上开机常亮
******************************************************************************/
#include "app_led.h"
@@ -15,7 +14,8 @@
#include "app_pair.h"
static uint8_t s_initialized;
static uint8_t s_ota; /* 1=OTA 灯效中,app_led_run 不再叠其它灯 */
static uint8_t s_ota; /* 1=OTA 灯效中,app_led_run 不再叠其它灯 */
static uint8_t s_pair_hint; /* 1=长按已满 5s 但还没松手提交配对,维持配对快闪 */
/**
* @brief 重新播放一次「一次性/限时」灯效,让它从第 0 帧重新开始
@@ -64,6 +64,30 @@ void app_led_hint_power_on(void)
led_restart(LED_EVENT_STANDBY);
}
/**
* @brief 长按满 5s:挂配对快闪,提示"松手即配网,继续按到 12s 进 OTA"
* @return 无
*/
void app_led_hint_pair(void)
{
if (!s_initialized || s_ota) {
return;
}
s_pair_hint = 1;
LED_EventAllDelete();
bsp_led_set(0);
LED_EventAdd(LED_EVENT_PAIRING);
}
/**
* @brief 结束"将配网"提示,交回 app_led_run 按 app_pair 状态接管
* @return 无
*/
void app_led_clear_pair_hint(void)
{
s_pair_hint = 0;
}
/**
* @brief 进入 OTA:清掉其它灯,挂 200ms 闪一直闪
* @return 无
@@ -74,6 +98,7 @@ void app_led_request_ota(void)
return;
}
s_ota = 1;
s_pair_hint = 0; /* 已改判 OTA,撤销配网提示 */
LED_EventAllDelete();
bsp_led_set(0);
LED_EventAdd(LED_EVENT_OTA);
@@ -122,7 +147,7 @@ void app_led_run(uint16_t dt, uint8_t power_on)
if (!power_on) {
LED_EventDelete(LED_EVENT_STANDBY);
LED_EventDelete(LED_EVENT_PAIRING);
} else if (app_pair_is_active()) {
} else if (s_pair_hint || app_pair_is_active()) {
LED_EventAdd(LED_EVENT_PAIRING);
LED_EventDelete(LED_EVENT_STANDBY);
} else if (!LED_IsEventExist(LED_EVENT_PAIR_OK) && !LED_IsEventExist(LED_EVENT_PAIR_FAIL)) {
+16 -4
View File
@@ -2,10 +2,9 @@
* @file app_led.h
* @brief CBR3 灯效:单灯 PC2OTA/配对/常亮按优先级
* @author cyWu <1917507415@qq.com>
* @date 2026.08.29
* @version V1.0.0
* @history
* - V1.0.0, 2026.08.29, cyWu, 首次发布(移植门夹,删红绿双通道/充电/低电)
* @date 2026.08.31
* @version V1.1.0,新增长按 5s 的"将配网"提示灯(配对改由运行态长按触发,
* 需要在按住期间给反馈)
******************************************************************************/
#ifndef __APP_LED_H__
@@ -38,6 +37,19 @@ void app_led_run(uint16_t dt, uint8_t power_on);
*/
void app_led_hint_power_on(void);
/**
* @brief 长按满 5s 的"松手即配网"提示:清掉其它灯,挂配对快闪
* @note 此时还没清绑定(要等松手),只是给按住的用户一个反馈
* @return 无
*/
void app_led_hint_pair(void);
/**
* @brief 结束"将配网"提示(配对会话已由 app_pair 接管,或改判为 OTA
* @return 无
*/
void app_led_clear_pair_hint(void);
/**
* @brief 进入 OTA:清掉其它灯,挂 200ms 闪一直闪
* @return 无
+3 -6
View File
@@ -2,12 +2,9 @@
* @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 后停、手动档快照、退出语义、开机从周期头
* @date 2026.08.31
* @version V1.1.0,实现状态机(规格书第 9 章):通风 25/5、强力 15min 后停、
* 手动档快照、退出语义、开机从周期头
*
* @note 模式激活时强制覆盖风扇档位(通风=1 档、强力=3 档、通风停段=0),
* DP2 由 app_fan_get_gear 上报真实档位(app_function_poll 同步)。
+1 -3
View File
@@ -3,9 +3,7 @@
* @brief CBR3 工作模式:通风(25/5 循环)/ 强力(15min 一轮)
* @author cyWu <1917507415@qq.com>
* @date 2026.08.29
* @version V1.0.0
* @history
* - V1.0.0, 2026.08.29, cyWu, 首次发布(P0 仅接口与 stub,P1 实现状态机)
* @version V1.0.0,首次发布(P0 仅接口与 stub,P1 实现状态机)
*
* @note P1 语义(规格书第 9 章):mode=1 强制 1 档开 25min 停 5min 循环;
* mode=2 强制 3 档跑 15min 后风扇 0、mode 回 0。短按切档走
+12 -15
View File
@@ -2,11 +2,8 @@
* @file app_nvm.c
* @brief CBR3 VM 持久化实现(P1):mode/fan_gear/条件/定时/使能
* @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 实现:3 个 VM item + 防抖 + 立即写
* @date 2026.08.31
* @version V1.1.0,实现:3 个 VM item + 防抖 + 立即写
*
* @note VM item 分配在 syscfg 用户自定义区 [1~49]syscfg_id.h 已占用
* CFG_USER_PAIR_INFO=2 / CFG_USER_TIM_FLAG=3 / VM_ALARM*=4~24 /
@@ -19,7 +16,7 @@
* 减少 flash 磨损;首次上电(magic 不符)保持 gDevData 全 0 默认。
*
* 写入时机(规格书第 13 章):APP 改配置后(mark_dirty)、档位/模式
* 稳定变化(500ms 防抖)、软关机前(save 立即写)
* 稳定变化(500ms 防抖)。
*
* ⚠⚠ 上下文硬约束(2026-08-31 复位事故定论,勿再踩):
* usr_timer_add() 是**异步接口**,回调在**硬件定时器中断上下文**执行
@@ -29,14 +26,14 @@
* 绝对不能调 syscfg_write**VM 擦写 flash 栈用量大且中断里做
* flash 操作 → 栈溢出软复位;实测 APP 下发数据后 500ms 必崩)。
* - 真正写入由 app_nvm_flush() 在 usr_timer_loop()BLE 线程、
* 任务上下文、栈充足)执行usr_poweroff_request_hook 里的
* app_nvm_save() 也必须保证在任务上下文被调用(见 app_function_loop)。
* 任务上下文、栈充足)执行
* 另:nvm_write_item 的比较缓冲改 static,再省 128B 栈。
******************************************************************************/
#include "app_nvm.h"
#include "app_mode.h"
#include "app_fan.h"
#include "app_defer.h"
#include "jb_product.h"
#include "board_pin.h"
#include "system/includes.h"
@@ -81,8 +78,9 @@ typedef struct {
#if BOARD_NVM_ENABLE
static uint8_t s_dirty; /**< 1=防抖计时中 */
static uint8_t s_need_save; /**< 1=防抖已满,待任务上下文落盘 */
static uint16_t s_deb_ms; /**< 防抖计时 */
/* 防抖已满时用 app_defer_request(APP_DEFER_NVM_SAVE) 打标志,真正落盘
* 由 app_nvm_flush() 在任务上下文里 app_defer_take() 消费,见文件头说明 */
/* 上次已同步到 VM 的状态快照:变化检测基准(覆盖按键/APP/模式引擎所有入口) */
static uint8_t s_last_gear;
@@ -222,7 +220,7 @@ void app_nvm_init(void)
}
s_dirty = 0;
s_deb_ms = 0;
s_need_save = 0;
app_defer_cancel(APP_DEFER_NVM_SAVE);
#endif
}
@@ -254,7 +252,7 @@ void app_nvm_save(void)
nvm_write_time();
s_dirty = 0;
s_deb_ms = 0;
s_need_save = 0;
app_defer_cancel(APP_DEFER_NVM_SAVE);
nvm_sync_snapshot();
#endif
}
@@ -358,7 +356,7 @@ void app_nvm_tick(uint16_t dt)
if (s_deb_ms >= CBR3_VM_DEBOUNCE_MS) {
s_deb_ms = 0;
s_dirty = 0;
s_need_save = 1; /* 只置标志:等任务上下文 app_nvm_flush 真正落盘 */
app_defer_request(APP_DEFER_NVM_SAVE); /* 只置标志:真正落盘在 app_nvm_flush */
}
#endif
}
@@ -374,10 +372,9 @@ void app_nvm_flush(void)
#if !BOARD_NVM_ENABLE
return;
#else
if (!s_need_save) {
if (!app_defer_take(APP_DEFER_NVM_SAVE)) {
return;
}
s_need_save = 0;
app_nvm_save();
#endif
}
@@ -417,7 +414,7 @@ void app_nvm_reset(void)
syscfg_write(CFG_USER_CBR3_TIME, &tf, sizeof(tf));
s_dirty = 0;
s_deb_ms = 0;
s_need_save = 0;
app_defer_cancel(APP_DEFER_NVM_SAVE);
log_info("nvm factory reset, business vm cleared (pairing kept)\n");
#endif
}
+6 -11
View File
@@ -2,17 +2,13 @@
* @file app_nvm.h
* @brief CBR3 VM 持久化(P1 起):mode/fan_gear/条件/定时/使能
* @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 实现:3 个 VM item(状态/条件/定时)+ 500ms
* 防抖写入 + 立即写接口
* @date 2026.08.31
* @version V1.1.0,实现:3 个 VM item(状态/条件/定时)+ 500ms 防抖写入 +
* 立即写接口
*
* @note 存:mode、fan_gear、cond_en、cond_config1~7、time_en、time_config1~7、
* fault_en、alarm_en。不存:DP0、条件作废标志、模式已运行秒数、原始采样。
* 写 VM 时机:APP 改配置后、单次定时自毁、软关机前、档位/模式稳定变化
* 500ms 防抖)。
* 写 VM 时机:APP 改配置后、单次定时自毁、档位/模式稳定变化500ms 防抖)。
******************************************************************************/
#ifndef __APP_NVM_H__
@@ -27,9 +23,8 @@
void app_nvm_init(void);
/**
* @brief 立即保存全部业务字段到 VM(软关机前等关键时机调用)
* @note syscfg 写入不能在裸中断里调用;本函数由业务时基回调触发,
* 与 SDK norflash 缓存同步(sys_timeout 回调)同级,可安全执行
* @brief 立即保存全部业务字段到 VM
* @note syscfg 写入不能在裸中断里调用;只由 app_nvm_flush()(任务上下文)调用
* @return 无
*/
void app_nvm_save(void);
+1 -3
View File
@@ -3,9 +3,7 @@
* @brief 配对会话计时实现
* @author cyWu <1917507415@qq.com>
* @date 2026.08.25
* @version V1.0.0
* @history
* - V1.0.0, 2026.08.25, cyWu, 首次发布,实现配对会话计时与成功/超时判定
* @version V1.0.0,首次发布,实现配对会话计时与成功/超时判定
******************************************************************************/
#include "app_pair.h"
+1 -3
View File
@@ -3,9 +3,7 @@
* @brief 配对会话计时:开机配对窗口是否成功/超时,与 BLE 配对本身解耦
* @author cyWu <1917507415@qq.com>
* @date 2026.08.25
* @version V1.0.0
* @history
* - V1.0.0, 2026.08.25, cyWu, 首次发布,实现配对会话计时与成功/超时判定
* @version V1.0.0,首次发布,实现配对会话计时与成功/超时判定
*
* @note 真正的 BLE 广播/绑定逻辑在 usr_le_code;本模块只负责“进入配对后
* 120s 内 usr_get_pair_flag() 是否变 1”这件事,纯状态,不碰灯/按键。
-100
View File
@@ -1,100 +0,0 @@
/******************************************************************************
* @file app_power.c
* @brief CBR3 软关机生命周期实现:无电池、无充电
* @author cyWu <1917507415@qq.com>
* @date 2026.08.29
* @version V1.0.0
* @history
* - V1.0.0, 2026.08.29, cyWu, 首次发布(移植门夹精简:删 USB/充电/电量/低电)
******************************************************************************/
#include "app_power.h"
#include "system/includes.h"
#define LOG_TAG_CONST APP
#define LOG_TAG "[APP_PWR]"
#define LOG_INFO_ENABLE
#include "debug.h"
/** 电源模块总状态 */
typedef struct {
uint8_t req_poweroff;
AppPowerHook_t on_request;
AppPowerHook_t on_finalize;
} AppPowerCtx_t;
static AppPowerCtx_t s_power;
static void power_do_poweroff(void *priv);
/**
* @brief 初始化电源模块状态
* @return 无
*/
void app_power_init(void)
{
s_power.req_poweroff = 0;
s_power.on_request = NULL;
s_power.on_finalize = NULL;
}
/**
* @brief 注册深睡请求的两段式回调
* @param on_request 刚请求深睡时调用(停风扇;灯由调用方按关机类型决定)
* @param on_finalize 延时到点后调用(真正进深睡,不会返回)
* @return 无
*/
void app_power_set_hooks(AppPowerHook_t on_request, AppPowerHook_t on_finalize)
{
s_power.on_request = on_request;
s_power.on_finalize = on_finalize;
}
/**
* @brief 请求深睡(按键 3s 等):立即触发 on_request 钩子,50ms 后触发 on_finalize
* @return 无
*/
void app_power_request_poweroff(void)
{
if (s_power.req_poweroff) {
return; /* 已经在关机流程里,不要重复挂定时器 */
}
s_power.req_poweroff = 1;
log_info("request deep off\n");
if (s_power.on_request) {
s_power.on_request(); /* 立刻停风扇、灯全灭 */
}
sys_timeout_add(NULL, power_do_poweroff, 50); /* 给 GPIO 落稳一点再真正掉电 */
}
/**
* @brief 查询深睡请求是否已发起
* @return 1=已发起,0=未发起
*/
uint8_t app_power_poweroff_pending(void)
{
return s_power.req_poweroff;
}
/**
* @brief 当前这次关机是否为空电路径(本产品无电池,恒 0)
* @return 0
*/
uint8_t app_power_empty_off_pending(void)
{
return 0;
}
/**
* @brief 50ms 延时到点:真正进入深睡
* @param priv 未使用
* @return 无
*/
static void power_do_poweroff(void *priv)
{
(void)priv;
log_info("enter deep off\n");
if (s_power.on_finalize) {
s_power.on_finalize();
}
}
-55
View File
@@ -1,55 +0,0 @@
/******************************************************************************
* @file app_power.h
* @brief CBR3 软关机生命周期:无电池、无充电,只保留 request/finalize
* @author cyWu <1917507415@qq.com>
* @date 2026.08.29
* @version V1.0.0
* @history
* - V1.0.0, 2026.08.29, cyWu, 首次发布(移植门夹精简:删 USB/充电/电量/低电)
*
* @note 本产品 USB 常电、无电池,插电不会自动开机,必须长按 3s。
* SDK 层 TCFG_CHARGE 相关配置保留为板级模板默认,但业务层完全不
* 参与充电/电量逻辑(规格书第 0 章第 3 条)。
******************************************************************************/
#ifndef __APP_POWER_H__
#define __APP_POWER_H__
#include <stdint.h>
/** 深睡请求的钩子:on_request 立刻停执行体并按关机类型处理灯;on_finalize 真正掉电 */
typedef void (*AppPowerHook_t)(void);
/**
* @brief 初始化电源模块状态
* @return 无
*/
void app_power_init(void);
/**
* @brief 注册深睡请求的两段式回调
* @param on_request 刚请求深睡时调用(停风扇;灯由调用方按关机类型决定)
* @param on_finalize 延时到点后调用(真正进深睡,不会返回)
* @return 无
*/
void app_power_set_hooks(AppPowerHook_t on_request, AppPowerHook_t on_finalize);
/**
* @brief 请求深睡(按键 3s 等):立即触发 on_request 钩子,50ms 后触发 on_finalize
* @return 无
*/
void app_power_request_poweroff(void);
/**
* @brief 查询深睡请求是否已发起(发起后其它模块应停止响应新操作)
* @return 1=已发起,0=未发起
*/
uint8_t app_power_poweroff_pending(void);
/**
* @brief 当前这次关机是否为空电路径(本产品无电池,恒 0,保留接口)
* @return 0
*/
uint8_t app_power_empty_off_pending(void);
#endif /* __APP_POWER_H__ */
+1 -3
View File
@@ -3,9 +3,7 @@
* @brief CBR3 温湿度采集实现
* @author cyWu <1917507415@qq.com>
* @date 2026.08.29
* @version V1.0.0
* @history
* - V1.0.0, 2026.08.29, cyWu, 首次发布
* @version V1.0.0,首次发布
******************************************************************************/
#include "app_th.h"
+1 -3
View File
@@ -3,9 +3,7 @@
* @brief CBR3 温湿度采集:2s 周期、失败计数、最近有效值
* @author cyWu <1917507415@qq.com>
* @date 2026.08.29
* @version V1.0.0
* @history
* - V1.0.0, 2026.08.29, cyWu, 首次发布
* @version V1.0.0,首次发布
*
* @note 规格书 8.4:条件"持续时长"只在本次采样成功且比较成立时累加;
* 采样失败不累加、不清零;连续 3 次失败显示 "--" 且 fault_code=2。
+4 -8
View File
@@ -2,14 +2,10 @@
* @file app_timer_task.c
* @brief CBR3 定时引擎(P2):7 组 8 字节定时窗,RTC 门闩
* @author cyWu <1917507415@qq.com>
* @date 2026.08.29
* @version V2.0.0
* @history
* - V1.0.0, 2026.08.29, cyWu, 首次发布(P0 stub
* - V1.1.0, 2026.08.31, cyWu, P1set_en/set_config 存 VM(引擎仍关)
* - V2.0.0, 2026.08.31, cyWu, P2 实现完整定时引擎(规格书第 11 章):
* RTC 门闩(未对时一律不跑)/对时补窗/7 组窗判断(跨午夜、星期位图)/
* 窗内切模式/结束收口(风扇 0 mode 0)/单次自毁清使能写 VM
* @date 2026.08.31
* @version V2.0.0,完整定时引擎(规格书第 11 章):RTC 门闩(未对时一律不
* 跑)/对时补窗/7 组窗判断(跨午夜、星期位图)/窗内切模式/结束收口
* (风扇 0 mode 0)/单次自毁清使能写 VM
*
* @note 运行上下文:app_timer_run 由 usr_timer_loop500ms,任务上下文)
* 调用——窗判断分钟级精度足够,且单次自毁要写 VM(禁止中断上下文)。
+1 -3
View File
@@ -3,9 +3,7 @@
* @brief CBR3 定时引擎(P2):7 组 8 字节定时窗,RTC 门闩
* @author cyWu <1917507415@qq.com>
* @date 2026.08.29
* @version V1.0.0
* @history
* - V1.0.0, 2026.08.29, cyWu, 首次发布(P0 仅接口与 stub)
* @version V1.0.0,首次发布(P0 仅接口与 stub
*
* @note 文件名避开 usr_rtc。字节布局见规格书 11.1Byte0=使能 Byte1=模式
* Byte2=类型(0单次/1每天/2每周) Byte3=星期位图 Byte4-5=开始时/分
+1 -3
View File
@@ -3,9 +3,7 @@
* @brief 按键状态机实现
* @author cyWu <1917507415@qq.com>
* @date 2026.08.25
* @version V1.0.0
* @history
* - V1.0.0, 2026.08.25, cyWu, 首次发布,实现按键短按/长按/释放状态机
* @version V1.0.0,首次发布,实现按键短按/长按/释放状态机
******************************************************************************/
#include "key.h"
+1 -3
View File
@@ -3,9 +3,7 @@
* @brief 按键状态机:短按 / 长按 / 释放
* @author cyWu <1917507415@qq.com>
* @date 2026.08.25
* @version V1.0.0
* @history
* - V1.0.0, 2026.08.25, cyWu, 首次发布,实现按键短按/长按/释放状态机
* @version V1.0.0,首次发布,实现按键短按/长按/释放状态机
******************************************************************************/
#ifndef __KEY_H__
+50 -31
View File
@@ -1,11 +1,9 @@
/******************************************************************************
* @file key_manager.c
* @brief CBR3 按键:读 PB1,短按切档、长按 3s 关机交给 usr_jb_main
* @brief CBR3 按键:读 PB1,短按切档;按住分级 5s 配对 / 12s OTA
* @author cyWu <1917507415@qq.com>
* @date 2026.08.29
* @version V1.0.0
* @history
* - V1.0.0, 2026.08.29, cyWu, 首次发布(移植门夹,短按语义改切档)
* @date 2026.08.31
* @version V3.0.0,直接复用 key.c 原生长按/连按/释放事件做按住分级
******************************************************************************/
#include "system/includes.h"
@@ -18,10 +16,11 @@
#define LOG_INFO_ENABLE
#include "debug.h"
/** 模块状态,替代原来 2 个散落的 static */
/** 模块状态 */
typedef struct {
uint8_t initialized;
uint8_t boot_key_lock; /**< 1=开机判定时键还按着,等松开才认短按/长按 */
uint8_t boot_key_lock; /**< 1=上电时键还按着,等松开才认短按(不挡长按分级) */
uint8_t ota_fired; /**< 1=已到点触发 OTA,本次按住松手不再提交配对 */
} KeyManagerCtx_t;
static KeyManagerCtx_t s_km;
@@ -36,25 +35,13 @@ static uint8_t key_user_read(void)
}
/**
* @brief 松开:清掉开机按着键的锁
* @return 无
*/
static void key_user_release(void)
{
if (s_km.boot_key_lock) {
s_km.boot_key_lock = 0;
log_info("boot key released\n");
}
}
/**
* @brief 短按:开机未松手前忽略
* @brief 短按(SHORT_Event,松手时刻 <5s):上电未松手前忽略,否则切档
* @return 无
*/
static void key_user_short(void)
{
if (s_km.boot_key_lock) {
s_km.boot_key_lock = 0; /* 开机松手当成释放,不当短按切档 */
s_km.boot_key_lock = 0; /* 上电松手当成释放,不当短按切档 */
log_info("boot key released\n");
return;
}
@@ -62,15 +49,44 @@ static void key_user_short(void)
}
/**
* @brief 长按 3s:开机未松手前忽略,避免开机手还按着就关机
* @brief 长按到点(LONG_Event,满 5s 仍按住):挂配对提示灯
* @note ⚠ 跑在 usr_timer 20ms(硬件定时器中断上下文):只准打标志 + 切灯效
* 事件(纯 RAM)。清绑定(写 VM)留给 app_function_loop(任务上下文)。
* @return 无
*/
static void key_user_long(void)
static void key_user_pair_hint(void)
{
if (s_km.boot_key_lock) {
return; /* 开机手还按着,忽略这次 3s 长按,避免一开机就关机 */
usr_on_key_pair_hint();
}
/**
* @brief 连按到点(LAST_Event,满 12s 仍按住,到点即触发不等松手):进 OTA
* @note ⚠ 同上,只置标志;usr_app_ota_init 由 app_function_loop 执行。
* key.c 的 keyHandle 对 LAST_Event 不清 eventType,松手前每 20ms 都会
* 再派发一次,这里用 ota_fired 挡住重复调用。
* @return 无
*/
static void key_user_ota_start(void)
{
if (s_km.ota_fired) {
return;
}
usr_on_key_long();
s_km.ota_fired = 1;
usr_on_key_ota_start();
}
/**
* @brief 释放(RELEASE_Event,只有按满 ≥5s 才会触发):未进 OTA 则提交配对
* @note 按满 12s 已触发 OTA 的这次按住,松手不再提交配对(ota_fired 拦住)。
* @return 无
*/
static void key_user_release(void)
{
s_km.boot_key_lock = 0;
if (!s_km.ota_fired) {
usr_on_key_pair_start();
}
s_km.ota_fired = 0;
}
static keyCategory_t s_keys[USR_KEY_COUNT] = {
@@ -78,12 +94,13 @@ static keyCategory_t s_keys[USR_KEY_COUNT] = {
.fsm.keyShield = KEY_ENABLE,
.fsm.keyDownLevel = Bit_SET,
.fsm.eventType = NULL_Event,
.fsm.keyLongTime = BOARD_KEY_POWER_MS,
.fsm.keyLastTime = (BOARD_KEY_POWER_MS + 7000), /* 大于长按即可,不使用持续按 */
.fsm.keyLongTime = BOARD_KEY_PAIR_MS, /* 满 5s 仍按住 -> longPressCb */
.fsm.keyLastTime = BOARD_KEY_OTA_MS, /* 满 12s 仍按住 -> lastPressCb */
.fsm.keyReadValue = key_user_read,
.func.ShortPressCb = key_user_short,
.func.longPressCb = key_user_long,
.func.releasePressCb = key_user_release,
.func.longPressCb = key_user_pair_hint,
.func.lastPressCb = key_user_ota_start,
},
};
@@ -98,18 +115,20 @@ void user_key_init(void)
}
keyParaInit(s_keys);
s_km.boot_key_lock = 0;
s_km.ota_fired = 0;
s_km.initialized = 1;
}
/**
* @brief 开机判定结束后:键还按着则锁住,松开才认短按/长按
* @brief 上电后:键还按着则锁住短按,松开才认短按
* @note 只锁短按,**不锁长按分级**:上电就按住 5s 进配对是受支持的用法。
* @return 无
*/
void user_key_lock_if_held(void)
{
reset_key_Status(USR_KEY_USER);
if (bsp_key_is_pressed()) {
s_km.boot_key_lock = 1; /* 开机手还按着,等松开才认短按/长按,避免立刻关机 */
s_km.boot_key_lock = 1; /* 上电手还按着,等松开才认短按,避免一上电就切档 */
log_info("boot key held, wait release\n");
}
}
+20 -8
View File
@@ -1,11 +1,9 @@
/******************************************************************************
* @file key_manager.h
* @brief CBR3 单按键:短按切档,长按 3s 关机;开机 3s/5s/12s 不走本库
* @brief CBR3 单按键:短按切档,按住分级 5s 配对 / 12s OTA(无长按关机)
* @author cyWu <1917507415@qq.com>
* @date 2026.08.29
* @version V1.0.0
* @history
* - V1.0.0, 2026.08.29, cyWu, 首次发布(移植门夹,语义改切档/关机)
* @date 2026.08.31
* @version V3.0.0,直接复用 key.c 原生长按/连按/释放事件做按住分级
******************************************************************************/
#ifndef __KEY_MANAGER_H__
@@ -20,10 +18,24 @@
void usr_on_key_short(void);
/**
* @brief 业务层长按 3s 回调(app_function 实现)
* @brief 业务层"按住满 5s"回调(app_function 实现):切配对提示灯,尚未清绑定
* @return 无
*/
void usr_on_key_long(void);
void usr_on_key_pair_hint(void);
/**
* @brief 业务层"按满 5s 后松手"回调(app_function 实现):提交配对
* @note 只置标志;清绑定(写 VM)在 app_function_loop(任务上下文)执行
* @return 无
*/
void usr_on_key_pair_start(void);
/**
* @brief 业务层"按住满 12s"回调(app_function 实现):到点即进 OTA
* @note 只置标志;usr_app_ota_init 在 app_function_loop(任务上下文)执行
* @return 无
*/
void usr_on_key_ota_start(void);
/**
* @brief 装载按键表
@@ -32,7 +44,7 @@ void usr_on_key_long(void);
void user_key_init(void);
/**
* @brief 开机判定结束后:若键还按着则锁住,松开才认短按/长按
* @brief 上电后:若键还按着则锁住短按,松开才认短按(不挡长按分级)
* @return 无
*/
void user_key_lock_if_held(void);
+1 -3
View File
@@ -3,9 +3,7 @@
* @brief LED 事件框架实现:只改 ledMask 对应通道,红绿互不抢
* @author cyWu <1917507415@qq.com>
* @date 2026.08.25
* @version V1.0.0
* @history
* - V1.0.0, 2026.08.25, cyWu, 首次发布,实现按通道掩码独立开关的 LED 事件框架
* @version V1.0.0,首次发布,实现按通道掩码独立开关的 LED 事件框架
******************************************************************************/
#include "led.h"
+1 -5
View File
@@ -3,11 +3,7 @@
* @brief LED 事件框架:按通道掩码独立开关
* @author cyWu <1917507415@qq.com>
* @date 2026.08.31
* @version V1.2.0
* @history
* - V1.0.0, 2026.08.25, cyWu, 首次发布,实现按通道掩码独立开关的 LED 事件框架
* - V1.1.0, 2026.08.27, cyWu, 新增 LED_EVENT_BOOT_REJECT
* - V1.2.0, 2026.08.31, cyWu, CBR3 单灯:裁掉充电/低电/空电等门夹事件
* @version V1.2.0,CBR3 单灯:裁掉充电/低电/空电等门夹事件
******************************************************************************/
#ifndef __LED_H__
+1 -3
View File
@@ -3,9 +3,7 @@
* @brief CBR3 灯事件:单灯 PC2,高优先级覆盖低优先级
* @author cyWu <1917507415@qq.com>
* @date 2026.08.29
* @version V1.0.0
* @history
* - V1.0.0, 2026.08.29, cyWu, 首次发布(移植门夹,删红绿双通道改单灯)
* @version V1.0.0,首次发布(移植门夹,删红绿双通道改单灯)
*
* @note 灯效优先级(见规格书第 6 章,高者覆盖):
* OTA(200ms 闪) > 配对中(100ms 快闪) / 配对结果 > 正常开机常亮。
+1 -3
View File
@@ -3,9 +3,7 @@
* @brief CBR3 单 LEDPC2)通道与事件表
* @author cyWu <1917507415@qq.com>
* @date 2026.08.29
* @version V1.0.0
* @history
* - V1.0.0, 2026.08.29, cyWu, 首次发布(单灯版,删红绿双通道)
* @version V1.0.0,首次发布(单灯版,删红绿双通道)
******************************************************************************/
#ifndef __LED_MANAGER_H__
+33 -129
View File
@@ -2,21 +2,23 @@
* @file usr_jb_main.c
* @brief CBR3 业务组合根:只做"先后调用谁、谁通知谁",不含具体业务算法
* @author cyWu <1917507415@qq.com>
* @date 2026.08.29
* @version V1.0.0
* @history
* - V1.0.0, 2026.08.29, cyWu, 首次发布(移植门夹:删电池/USB,加风扇/显示/传感)
* @date 2026.08.31
* @version V2.3.0,上电即开机(无 app_boot);5s 配对 / 12s OTA 由 key_manager
* 长按分级触发;关机=拔电,已删除全部 app_power 软关机基础设施及
* DP0 开关相关死代码(power 恒 1,写死在 app_function_init);
* 删除 usr_timer_pick_mode/rearm 动态休眠调度(Type-C 长供电不
* 需要低功耗,且 app_disp_scan 常驻 priority=1 已让系统永远无法
* 休眠,该机制本来就没有实际效果),业务定时器改为一次性固定注册
*
* @note 协议生成文件 jb_product.c 不要填业务。APP 下行写 gDevData。
* usr_timer_loop 由 BLE 回调,勿再注册第二份。
* 具体业务逻辑去对应模块找:
* app_boot —— 开机 3s/5s/12s 按键判定
* app_power —— 软关机请求(无电池/充电)
* key_manager —— 短按切档 + 按住 5s 配对 / 12s OTA 分级
* app_pair —— 配对会话计时
* app_fan —— 风扇档位
* app_th —— AHT20 采样
* app_disp —— 数码管显示
* app_function —— 按键动作 + DP 同步
* app_function —— 按键动作 + DP 同步 + 配对/OTA 动作落地
******************************************************************************/
#include "system/includes.h"
@@ -32,9 +34,7 @@
#include "usr_le_product.h"
#include "usr_le_api.h"
#include "bsp_hw.h"
#include "app_power.h"
#include "app_pair.h"
#include "app_boot.h"
#include "app_function.h"
#include "app_fan.h"
#include "app_th.h"
@@ -46,7 +46,6 @@
#include "app_nvm.h"
#include "app_led.h"
#include "key_manager.h"
#include "asm/power/power_api.h"
#define LOG_TAG_CONST APP
#define LOG_TAG "[USR_JB]"
@@ -65,128 +64,39 @@ const uint8_t g_usr_le_pcode[USR_LE_PCODE_LEN] = {
#define USR_TIMER_IDLE_MS 20 /**< 全局统一节拍(规格书第 3 章,禁止再开 1ms ISR) */
/**
* @brief 业务节拍档位
* @note 全系统只用一种节拍周期(USR_TIMER_IDLE_MS),区别只在"能不能休眠"
*/
typedef enum {
USR_TICK_IDLE = 0, /**< 可休眠 */
USR_TICK_BLOCK_SLEEP /**< 禁止休眠(按键按住/风扇转/关机流程/配对/OTA) */
} UsrTickMode_t;
/** 调度器状态 */
typedef struct {
int timer_id;
UsrTickMode_t mode;
} UsrSchedulerCtx_t;
static UsrSchedulerCtx_t s_sched;
static void usr_timer_tick(void *priv);
static void usr_timer_rearm(UsrTickMode_t mode);
static void usr_log_boot_version(void);
/**
* @brief 软关机请求钩子:先落盘当前 mode/gear/配置,再停风扇、灯全灭
* @note ⚠ app_nvm_save() 必须在 app_function_stop_all() 之前调用:
* stop_all 会把 mode/gear 清 0,先存才能保住用户最后的运行状态
* (规格书 13 章:软关机前写 VM,开机恢复上次 mode/gear
* @return 无
*/
static void usr_poweroff_request_hook(void)
{
app_nvm_save(); /* 软关机前立即写 VM(不等待 500ms 防抖) */
app_function_stop_all();
app_led_clear();
}
/**
* @brief 软关机最终钩子:50ms 到点,真正进入深睡
* @note 不走 sys_enter_soft_poweroff():那是耳机 SDK 的优雅关机流程,实测慢。
* 本产品无 DAC/音频,直接进软关机(规格书 5.1:风扇 0、数码管锁存灭、
* LED 灭、BLE 停)。
* @return 无
*/
static void usr_poweroff_finalize_hook(void)
{
bsp_hw_enter_sleep_io();
power_set_soft_poweroff();
}
/**
* @brief 按当前业务状态判断能不能休眠
* @note 按键按住、风扇转、关机流程、配对中、OTA 灯效中 → 不能睡
* @return 本次应使用的档位
*/
static UsrTickMode_t usr_timer_pick_mode(void)
{
if (bsp_key_is_pressed() || app_power_poweroff_pending()
|| (app_fan_get_gear() != 0) || app_mode_get_active()
|| app_pair_is_active() || app_led_is_ota()) {
return USR_TICK_BLOCK_SLEEP;
}
return USR_TICK_IDLE;
}
/**
* @brief 切换业务定时器。priority=1 时系统无法 sleep;节拍周期恒为 USR_TIMER_IDLE_MS
* @param mode 目标档位
* @return 无
*/
static void usr_timer_rearm(UsrTickMode_t mode)
{
if (s_sched.timer_id) {
usr_timer_del((u16)s_sched.timer_id);
s_sched.timer_id = 0;
}
s_sched.mode = mode;
s_sched.timer_id = (int)usr_timer_add(NULL, usr_timer_tick, USR_TIMER_IDLE_MS,
(mode == USR_TICK_BLOCK_SLEEP) ? 1 : 0);
}
/**
* @brief 业务定时器:固定 USR_TIMER_IDLE_MS 一拍;忙时禁睡,空闲可睡
* @brief 业务定时器:固定 USR_TIMER_IDLE_MS 一拍,priority=1 常驻注册
* @param priv 未使用
* @note ⚠ 运行在硬件定时器时基上下文:禁止阻塞等待、禁止耗时操作。
* 关机请走 app_power 的钩子,不要在这里直接 power_set_soft_poweroff。
* priority 固定 1、只在 usr_jb_init 注册一次、永不重挂:本产品
* Type-C 长供电,不需要低功耗;且 app_disp_scanCT1642 4ms 扫描)
* 本就以 priority=1 常驻,系统本来就永远无法进入低功耗,动态切换
* 这里的 priority 没有任何实际效果,纯属多余的复杂度。
* @return 无
*/
static void usr_timer_tick(void *priv)
{
uint16_t dt = USR_TIMER_IDLE_MS;
uint16_t i;
UsrTickMode_t want;
(void)priv;
for (i = 0; i < dt; i++) {
jbTimerIrq();
}
if (!app_power_poweroff_pending()) {
user_key_scan(dt);
user_key_handle(); /* 长按 3s 会在这里同步触发 app_power_request_poweroff() */
}
app_th_poll(dt); /* 内部 2s 才真正采;IO 分离后采集与显示互不干扰 */
user_key_scan(dt); /* 内部完成 5s/12s 长按分级,只置标志 */
user_key_handle(); /* 派发短按:切档 */
app_th_poll(dt); /* 每2s采集一次温湿度 */
app_mode_run(dt); /* 通风/强力状态机(20ms 计时精度;条件/定时在 500ms 任务上下文) */
app_fan_run(dt); /* P0 无动作 */
app_disp_run(dt); /* 刷新显示(告警闪烁) */
app_function_poll(); /* 同步 DP */
app_nvm_tick(dt); /* 档位/模式/配置变化检测 + 500ms 防抖计时(不写 flash!) */
/* OTA 灯效期间最高优先级;关机流程中灯灭 */
if (app_led_is_ota()) {
app_led_run(dt, app_function_is_power_on());
} else if (app_power_poweroff_pending()) {
app_led_clear();
} else {
app_led_run(dt, app_function_is_power_on());
}
want = usr_timer_pick_mode(); /* 判断能不能休眠 */
if (want != s_sched.mode) {
usr_timer_rearm(want);
}
/* OTA 灯效期间最高优先级;power_on 恒 1(DP0 预留不当开关,规格书 0 章第 5 条) */
app_led_run(dt, 1);
}
/**
@@ -203,31 +113,25 @@ static void usr_log_boot_version(void)
/**
* @brief 业务初始化(在 BLE 栈起来之前由 app_main 调用)
* @note 内部会等按键 3s/5s/12s;不足 3s 直接深睡,不会启动业务定时器。
* app_led_init() 排在 app_boot_wait_key() 前面:3s/5s 提示灯要用
* LED 事件表(规格书 5.2)。boot 深睡分支不返回,后面初始化不会浪费
* @note ⚠ 上电即开机(规格书 5.1,2026-08-31 改):不再等待按键,插电/冷启动
* 直接进入工作态。5s 配对 / 12s OTA 改由运行态 key_manager 长按分级
* 触发,动作在 app_function_loop(任务上下文)落地,故此处无需判定
* app_led_init() 仍排在最前:后面模块的日志/灯效都依赖事件表已装载。
* @return 无
*/
void usr_jb_init(void)
{
usr_log_boot_version(); /* UART 已在 app_main 起来,按键判定前就能看到版本 */
usr_log_boot_version(); /* UART 已在 app_main 起来,最先能看到版本 */
bsp_hw_init();
app_led_init(); /* 提前到按键判定之前:3s 常亮/5s 配对闪都要用灯效事件表 */
app_boot_wait_key(); /* 深睡分支不会返回;返回即代表确定要开机 */
app_led_init(); /* 先于一切业务:灯效事件表要最先装载 */
jbInit();
userInit();
if (usr_var.usr_goto_updata) {
/* 开机 12s 已进 OTA:立刻挂 200ms 闪 */
app_led_request_ota();
}
app_fan_init();
app_disp_init();
/* CT1642 无内部扫描 RAM4ms 快节拍轮询 4 位。priority=1 会挡住系统 sleep
* USB 常电产品故意如此:管子必须持续扫描,否则肉眼闪。勿改成 priority=0。 */
usr_timer_add(NULL, app_disp_scan, BOARD_DISP_SCAN_MS, 1);
app_th_init();
app_mode_init();
@@ -237,16 +141,16 @@ void usr_jb_init(void)
app_nvm_init();
app_nvm_load();
app_power_init();
app_power_set_hooks(usr_poweroff_request_hook, usr_poweroff_finalize_hook);
app_function_init();
user_key_init();
/* 上电时键若还按着:只锁短按(避免一上电就切档),长按 5s/12s 分级照常生效,
* 所以"插电时就按住 5s 进配对"这一用法仍然成立 */
user_key_lock_if_held();
app_function_power_on_silent();
usr_timer_rearm(USR_TICK_IDLE);
log_info("timer idle %ums, sleep ok\n", (unsigned)USR_TIMER_IDLE_MS);
/* priority=1 常驻注册,永不重挂(Type-C 长供电不需要低功耗,见 usr_timer_tick */
usr_timer_add(NULL, usr_timer_tick, USR_TIMER_IDLE_MS, 1);
log_info("timer started, period=%ums\n", (unsigned)USR_TIMER_IDLE_MS);
}
/**
@@ -267,7 +171,7 @@ void usr_jb_le_recieve_data(u8 *data, u16 len)
* (BLE 线程,栈充足),与 20ms 的 usr_timer_tickusr_timer_add 异步
* 接口 = 硬件定时器中断上下文,栈极小)不同。
* **所有重量级/自动化引擎必须放这里**:条件/定时引擎(500ms 粒度对
* 2s 采样与分钟级时长足够,且单次自毁要写 VM)、VM 落盘、关机收口
* 2s 采样与分钟级时长足够,且单次自毁要写 VM)、VM 落盘、配对/OTA 落地
* 禁止放进 usr_timer_tick——曾因在 20ms 中断里调 syscfg_write 栈溢出软复位。
* @return 无
*/
@@ -277,5 +181,5 @@ void usr_timer_loop(void)
jbProtocolHandle(&gDevData);
app_cond_run(500); /* 条件引擎(任务上下文;条件/定时仲裁见 app_arbiter */
app_timer_run(500); /* 定时引擎(任务上下文;RTC 门闩 + 窗判断) */
app_function_loop(); /* 任务上下文:VM 防抖落盘 + 延后关机收口 */
app_function_loop(); /* 任务上下文:VM 防抖落盘 + 配对/OTA 动作落地 */
}
+10 -7
View File
@@ -3,9 +3,7 @@
* @brief CBR3 温湿度风扇板级引脚、电平与时序(换板只改本文件)
* @author cyWu <1917507415@qq.com>
* @date 2026.08.29
* @version V1.0.0
* @history
* - V1.0.0, 2026.08.29, cyWu, 首次发布(P0 Bring-up
* @version V1.0.0,首次发布(P0 Bring-up
*
* @note 产品 GPIO 全部集中到本文件;板级 board_jl701n_demo_cfg.h 只保留
* UART0_TX=PG6 一项改动。CT1642 用 PG0(CLK)/PG1(DATA)AHT20 用
@@ -54,10 +52,15 @@
/* 按键 / 开机 */
/*============================================================================*/
#define BOARD_KEY_CLICK_MS 1000 /**< 开机后:按下 <1s 松开为短按切档 */
#define BOARD_KEY_POWER_MS 3000 /**< 关机态:按住 3s 开机;开机态:按住 3s 关机 */
#define BOARD_KEY_PAIR_MS 5000 /**< 关机态:按住 5s 开机并进配对 */
#define BOARD_KEY_OTA_MS 12000 /**< 关机态:按住 12s 开机并进 OTA */
/**
* 直接作为 key.c 状态机的 keyLongTime/keyLastTime 使用:
* 松手时刻 <BOARD_KEY_PAIR_MS → SHORT_Event,切档(见 5.3
* 按住满 BOARD_KEY_PAIR_MS → LONG_Event(仍按住),切配对提示灯
* 按住满 BOARD_KEY_OTA_MS → LAST_Event(仍按住,到点即触发),进 OTA
* 按满 5s~12s 后松手 → RELEASE_Event,提交配对
*/
#define BOARD_KEY_PAIR_MS 5000 /**< keyLongTime:满 5s 挂配对提示灯 */
#define BOARD_KEY_OTA_MS 12000 /**< keyLastTime:满 12s 到点直接进 OTA */
#define BOARD_KEY_DEBOUNCE_MS 20 /**< 按键消抖 */
#define BOARD_PAIR_TIMEOUT_MS (120u * 1000u) /**< 配对超时 120s,失败后保持开机 */
+3 -10
View File
@@ -3,16 +3,9 @@
* @brief CBR3 AHT20 软件 I2C 驱动实现
* @author cyWu <1917507415@qq.com>
* @date 2026.08.29
* @version V1.0.3
* @history
* - V1.0.0, 2026.08.29, cyWu, 首次发布
* - V1.0.1, 2026.08.29, cyWu, 修复 SCL 高电平期间推挽输出 SDA 导致的假 STOP
* (读数据必 CRC fail 的根因);补 AHT20 0x71 校准检查 + 0xBE 初始化
* - V1.0.2, 2026.08.29, cyWu, 排障结束:回退诊断代码(电平自检/地址扫描/IN 直读),
* 保留时序修复、内部上拉依赖、总线恢复、0x71/0xBE 初始化流程
* - V1.0.3, 2026.08.29, cyWu, IO 分离:AHT20 独占 PC4(SCL)/PC5(SDA),删除
* bsp_bus 共线锁与 measure_start/finish 拆分锁,采集恢复一次完成;
* PC4/PC5 上拉配置从 bsp_bus_init 移入本文件 init
* @version V1.0.3IO 分离:AHT20 独占 PC4(SCL)/PC5(SDA),无总线共享锁,
* 采集一次完成;修复 SCL 高电平期间推挽输出 SDA 导致的假 STOP,
* 补 0x71 校准检查 + 0xBE 初始化
******************************************************************************/
#include "bsp_aht20.h"
+2 -7
View File
@@ -3,13 +3,8 @@
* @brief CBR3 AHT20 温湿度传感器:软件 I2C + 测量 + CRC8
* @author cyWu <1917507415@qq.com>
* @date 2026.08.29
* @version V1.0.3
* @history
* - V1.0.0, 2026.08.29, cyWu, 首次发布
* - V1.0.1, 2026.08.29, cyWu, 修复 SCL 高电平期间推挽输出 SDA 导致的假 STOP
* - V1.0.2, 2026.08.29, cyWu, 回退诊断代码,保留时序修复/上拉/总线恢复/0x71 校准
* - V1.0.3, 2026.08.29, cyWu, IO 分离:AHT20 独占 PC4(SCL)/PC5(SDA),删除
* bsp_bus 共线锁与 measure_start/finish 拆分锁,恢复一次完成采集
* @version V1.0.3IO 分离:AHT20 独占 PC4(SCL)/PC5(SDA),无总线共享锁,
* 恢复一次完成采集;含 SCL 高电平假 STOP 修复与 0x71 校准检查
*
* @note I2C 7 位地址 0x38(写 0x70 / 读 0x71)。测量命令 0xAC 0x33 0x00
* 等 ≥80ms 后读 7 字节:Status + 20bit 湿度 + 20bit 温度 + CRC8。
+1 -6
View File
@@ -3,12 +3,7 @@
* @brief CBR3 CT1642 类数码管驱动实现(软件移位)
* @author cyWu <1917507415@qq.com>
* @date 2026.08.29
* @version V1.0.1
* @history
* - V1.0.0, 2026.08.29, cyWu, 首次发布
* - V1.0.1, 2026.08.29, cyWu, IO 分离:CT1642 独立 PG0=CLK/PG1=DATA,删除
* bsp_bus 共线机制;删调试遗留 latch/show4/scan_seg/scan_com
* 新增 bsp_ct1642_init()
* @version V1.0.1IO 分离:CT1642 独立 PG0=CLK/PG1=DATA,无总线共享机制
*
* @note 驱动协议严格参照 CT1642 手册(与 CSDN yitx 一致):
* 一帧 = 18bitCLK 上升沿采样 DATADATA 只在 CLK=低时改变):
+2 -6
View File
@@ -3,12 +3,8 @@
* @brief CBR3 CT1642 类数码管驱动:18bit 移位、锁存、送出
* @author cyWu <1917507415@qq.com>
* @date 2026.08.29
* @version V1.0.1
* @history
* - V1.0.0, 2026.08.29, cyWu, 首次发布
* - V1.0.1, 2026.08.29, cyWu, IO 分离:CT1642 独立 PG0=CLK/PG1=DATA(飞线),
* AHT20 独占 PC4/PC5,删除 bsp_bus 共线机制;删调试遗留
* latch/show4/scan_seg/scan_com,新增 bsp_ct1642_init()
* @version V1.0.1IO 分离:CT1642 独立 PG0=CLK/PG1=DATA(飞线),AHT20
* 独占 PC4/PC5,无总线共享机制
*
* @note PG0=CLKPG1=DATA,独立引脚、无总线锁,可随时调用。
* 协议:一帧 18bitC1-C4 位选 + 6 位保留 + Q2-Q9 段码),CLK 上升沿采样
+1 -3
View File
@@ -3,9 +3,7 @@
* @brief CBR3 板级 GPIO / MCPWMLED、按键、风扇
* @author cyWu <1917507415@qq.com>
* @date 2026.08.29
* @version V1.0.0
* @history
* - V1.0.0, 2026.08.29, cyWu, 首次发布(移植门夹:删电机/充电/电量,改单 LED + 风扇 PWM)
* @version V1.0.0,首次发布(移植门夹:删电机/充电/电量,改单 LED + 风扇 PWM)
*
* @note CT1642 在 PG0/PG1、AHT20 在 PC4/PC5,各自独立驱动,
* bsp_hw 只管 LED/KEY/FAN,不碰这两组脚。
+1 -3
View File
@@ -3,9 +3,7 @@
* @brief CBR3 板级硬件:LED / 按键 / 风扇 PWM
* @author cyWu <1917507415@qq.com>
* @date 2026.08.29
* @version V1.0.0
* @history
* - V1.0.0, 2026.08.29, cyWu, 首次发布(移植门夹:删电机/充电/电量,改单 LED + 风扇 PWM)
* @version V1.0.0,首次发布(移植门夹:删电机/充电/电量,改单 LED + 风扇 PWM)
******************************************************************************/
#ifndef __BSP_HW_H__
+1 -4
View File
@@ -3,10 +3,7 @@
* @brief 板级 RTC 外设实现(BR28 硬件 rtc_dev_ops
* @author cyWu <1917507415@qq.com>
* @date 2026.08.19
* @version V1.1.0
* @history
* - V1.0.0, 2026.08.19, cyWu, 从模组固件移植至 SOC SDK
* - V1.1.0, 2026.08.19, cyWu, 精简公共接口与缓存逻辑
* @version V1.1.0,从模组固件移植至 SOC SDK,精简公共接口与缓存逻辑
******************************************************************************/
#include "system/includes.h"
+2 -4
View File
@@ -3,10 +3,8 @@
* @brief 板级 RTC:硬件对时 + 客户读本地日历
* @author cyWu <1917507415@qq.com>
* @date 2026.08.19
* @version V1.1.0
* @history
* - V1.0.0, 2026.08.19, cyWu, 从模组固件移植至 SOC SDK
* - V1.1.0, 2026.08.19, cyWu, 精简接口;usr_rtc_get_time 返回本地日历
* @version V1.1.0,从模组固件移植至 SOC SDK;精简接口,usr_rtc_get_time
* 返回本地日历
******************************************************************************/
#ifndef __USR_RTC_H__
@@ -10,7 +10,7 @@ copy ..\..\ota.bin .
copy ..\..\anc_coeff.bin .
copy ..\..\anc_gains.bin .
..\..\isd_download.exe ..\..\isd_config.ini -tonorflash -dev br28 -boot 0x120000 -div8 -wait 300 -uboot ..\..\uboot.boot -app ..\..\app.bin -res ..\..\cfg_tool.bin tone.cfg p11_code.bin -uboot_compress
..\..\isd_download.exe ..\..\isd_config.ini -tonorflash -dev br28 -boot 0x120000 -div8 -wait 300 -uboot ..\..\uboot.boot -app ..\..\app.bin -res ..\..\cfg_tool.bin tone.cfg p11_code.bin -uboot_compress -key RS-5B88.key
:: -format all -key RS-5B88.key
::-reboot 2500