Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
314a50a14b | ||
|
|
767b9e4343 | ||
|
|
9b15f3f9e3 | ||
|
|
6f4e643eca | ||
|
|
51dfc3c3ce | ||
|
|
408c25bd5c |
@@ -843,6 +843,10 @@
|
||||
<Option compilerVar="CC" />
|
||||
</Unit>
|
||||
<Unit filename="apps/usr_app/app_th.h" />
|
||||
<Unit filename="apps/usr_app/app_th_adv.c">
|
||||
<Option compilerVar="CC" />
|
||||
</Unit>
|
||||
<Unit filename="apps/usr_app/app_th_adv.h" />
|
||||
<Unit filename="apps/usr_app/app_timer_task.c">
|
||||
<Option compilerVar="CC" />
|
||||
</Unit>
|
||||
|
||||
+27
-23
@@ -7,14 +7,16 @@
|
||||
| 工程 | `温湿度风扇_soc_JieLi-JL7016` |
|
||||
| 产品码 | ProdtCode=`CBR3`,productCode=`PRCBR3` |
|
||||
| 协议 | 见宝 SOC 55AA,V1.0.0(2026-09-02 重生:删条件 DP,加联动 / 运行记录 / 心跳预留) |
|
||||
| 文档版本 | V3.0.0 |
|
||||
| 日期 | 2026.09.02 |
|
||||
| 文档版本 | V3.0.1 |
|
||||
| 日期 | 2026.09.04 |
|
||||
| 作者 | cyWu |
|
||||
| 读者 | WorkBuddy / 固件开发 |
|
||||
| 参考工程 | `D:\Jianbao\Project\产品\宠物\门夹弹力绳\门夹弹力绳_soc_JieLi-JL7016` |
|
||||
| 新协议生成工程 | `D:\Jianbao\Project\产品\爬宠\温湿度风扇\温湿度风扇_soc_JieLi-JL7016_新协议` |
|
||||
|
||||
> **V3.0.0 变更(2026-09-02):** 协议 DP 重生。删除 `cond_en` / `cond_config1~7`(7 组条件引擎整段作废)。新增 DP5 `linkage_delete`、DP6 `linkage_config`(20B,缸体 + 温湿度 min/max)、DP21 `run_record`(31 天运行秒数)、DP22 `heartbeat`(本版不做)。故障/告警/复位号后移,`factory_reset` 改为 DP27。联动按实时温湿度回差开 1 档 / 关风扇,不改 mode;仲裁改为手动 > 定时 > 联动。运行记录按风扇实际在转累加秒,满 10 分钟写 VM。生成协议 `MAX_PACKAGE_LEN` 必须改回 **256**(124B 的 `run_record` 装不进 128)。旧条件 VM **不迁移**。
|
||||
> **V3.0.1 变更(2026-09-04):** DP 号收紧为连续 0~24。`time_en` 13→7,`time_config1~7` 14~20→8~14,`run_record` 21→15,`heartbeat` 22→16,`fault_en/code` 23/24→17/18,`alarm_en/code` 25/26→19/20,`factory_reset` 27→21,`reserva_dp1~3` 28~30→22~24。7–12 不再空置。以 `jb_protocol.h` / `dp_definition.json` 为准。
|
||||
>
|
||||
> **V3.0.0 变更(2026-09-02):** 协议 DP 重生。删除 `cond_en` / `cond_config1~7`(7 组条件引擎整段作废)。新增 DP5 `linkage_delete`、DP6 `linkage_config`(20B,缸体 + 温湿度 min/max)、当时号为 DP21 `run_record`(现 DP15)、DP22 `heartbeat`(现 DP16,本版不做)。故障/告警/复位号后移,当时 `factory_reset` 为 DP27(现 DP21)。联动按实时温湿度回差开 1 档 / 关风扇,不改 mode;仲裁改为手动 > 定时 > 联动。运行记录按风扇实际在转累加秒,满 10 分钟写 VM。生成协议 `MAX_PACKAGE_LEN` 必须改回 **256**(124B 的 `run_record` 装不进 128)。旧条件 VM **不迁移**。
|
||||
>
|
||||
> **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()` 里对应的"软关态唤醒"死分支一并删除。
|
||||
>
|
||||
@@ -32,7 +34,7 @@
|
||||
|
||||
## 0. WorkBuddy 开干前必读(硬约束)
|
||||
|
||||
1. **先改协议再写业务。** 从 `_新协议` 工程拷贝已生成的 `jb_protocol.*` / `dp_definition.json` / `jb_product` 骨架,再把现有 `jb_product.c` 业务回调迁过去(禁止用空壳 TODO 覆盖业务)。拷贝后立刻把 `MAX_PACKAGE_LEN` 从生成值 **128 改回 256**,否则 DP21 `run_record`(124B)组不出完整帧。
|
||||
1. **先改协议再写业务。** 从 `_新协议` 工程拷贝已生成的 `jb_protocol.*` / `dp_definition.json` / `jb_product` 骨架,再把现有 `jb_product.c` 业务回调迁过去(禁止用空壳 TODO 覆盖业务)。拷贝后立刻把 `MAX_PACKAGE_LEN` 从生成值 **128 改回 256**,否则 DP15 `run_record`(124B)组不出完整帧。
|
||||
2. **不要把业务算法写进 `jb_product.c`。** 只把 DP 写入 `gDevData` 并转调 `app_*`。组合根是 `usr_jb_main.c`(照门夹)。
|
||||
3. **不要抄门夹的电池 / 低电拒绝开机。** 本机 USB 常电、无电池。**上电即开机**(V2.0.0 起,不再长按 3s 才开机);拔电即关,无软关机深睡。
|
||||
4. **不要把调试 UART 放在 PC5。** 调试 UART TX = **PG6**(`IO_PORTG_06`)。PC5 是 AHT20 SDA(独立使用)。
|
||||
@@ -42,7 +44,7 @@
|
||||
8. 日志全部 **英文**。中文只出现在注释和本文。
|
||||
9. 编码风格对齐门夹 + 工程师规范:文件小写+下划线,`g_` / `s_` 前缀,枚举 `Pascal_t`,接口 `xxx_init` / `xxx_run` 或 tick / `xxx_get_status`。
|
||||
10. **禁止继续实现 7 组条件引擎。** `app_cond` 整模块替换为联动(`app_linkage`);旧 `CFG_USER_CBR3_COND` 作废,不读旧 49B。
|
||||
11. **DP22 心跳本版忽略。** 温湿度仍按协议 2s 变化防抖 / 10min 全量上报,不因 12s 无心跳停报。
|
||||
11. **DP16 心跳本版忽略。** 温湿度仍按协议 2s 变化防抖 / 10min 全量上报,不因 12s 无心跳停报。
|
||||
|
||||
---
|
||||
|
||||
@@ -511,7 +513,7 @@ usr_rtc_get_time() 失败 → 全部定时不执行(等同 time_en=0)
|
||||
- APP 改联动/定时、单次定时自毁、档位/模式稳定变化:500ms 防抖(避免短按循环打爆 Flash)
|
||||
- 运行记录:风扇累计转满 **10 分钟** 写一次;**跨天旋转时立刻写**(见 13.1)
|
||||
|
||||
### 13.1 运行记录(DP21 `run_record`,RO,124B)
|
||||
### 13.1 运行记录(DP15 `run_record`,RO,124B)
|
||||
|
||||
31 天 × 4 字节,每格 uint32 **大端**,单位秒:
|
||||
|
||||
@@ -530,13 +532,15 @@ usr_rtc_get_time() 失败 → 全部定时不执行(等同 time_en=0)
|
||||
- 对时成功:按本地日历把数组左移 N 天(跨了几天就移几天),新今天从 0 或当天已累加值继续。
|
||||
- 掉电再上电:先把 VM 里 31 格灌进 `gDevData.run_record`;未对时继续往 slot[0] 加。
|
||||
|
||||
**上报:** 今天累计秒数相对上次 0x07 上报满 **60 秒** 才进差分(`JB_RUNREC_DIFF_SEC`);跨天旋转立刻带 DP15。APP 0x05 读、10 分钟全量仍带完整 124B。其它 DP 上报时不刷新运行记录基准。
|
||||
|
||||
**落盘:** 每累计运行满 600 秒写一次 VM。跨天立刻写。拔电没有软关机钩子,**接受最多丢不满 10 分钟的秒数**。
|
||||
|
||||
`BOARD_RUNREC_ENABLE=0`:不累加、DP21 报全 0。
|
||||
`BOARD_RUNREC_ENABLE=0`:不累加、DP15 报全 0。
|
||||
|
||||
---
|
||||
|
||||
## 14. 出厂重置(DP27 写 1)
|
||||
## 14. 出厂重置(DP21 写 1)
|
||||
|
||||
- **清全部业务 VM**(第 13 章列表,含联动 20B 与 31 天运行记录)。
|
||||
- **保留 BLE 配对,不断开、不软复位。**
|
||||
@@ -547,7 +551,7 @@ usr_rtc_get_time() 失败 → 全部定时不执行(等同 time_en=0)
|
||||
|
||||
## 15. BLE / DP 行为摘要
|
||||
|
||||
身份:`CBR3` / `PRCBR3`。帧格式见已生成 `jb_protocol.h`(以 `_新协议` 拷贝后、`MAX_PACKAGE_LEN=256` 的头文件为准)。DP 号 7–12 空置,不要填回条件配置。
|
||||
身份:`CBR3` / `PRCBR3`。帧格式见已生成 `jb_protocol.h`(以 `_新协议` 拷贝后、`MAX_PACKAGE_LEN=256` 的头文件为准)。DP 号 0–24 连续,不要填回条件配置。
|
||||
|
||||
| DP | 处理 |
|
||||
|---|---|
|
||||
@@ -557,16 +561,16 @@ usr_rtc_get_time() 失败 → 全部定时不执行(等同 time_en=0)
|
||||
| 3/4 温湿度 | 仅上报。变化防抖 2s,全量 10min(协议已有) |
|
||||
| 5 linkage_delete | 第 10.4 节,脉冲 |
|
||||
| 6 linkage_config | 20 字节 memcpy + 存 VM + 第 10.5 节立刻重判 |
|
||||
| 13 time_en | 见第 11 章 |
|
||||
| 14~20 time_config | 8 字节 + 存 VM |
|
||||
| 21 run_record | RO,由 `app_runrec` 填 124B,禁止 APP 写 |
|
||||
| 22 heartbeat | 本版忽略(写了也不停温湿度上报) |
|
||||
| 23 fault_en | 原样存,P0 不做位级过滤 |
|
||||
| 24 fault_code | 0 无 / 1 传感器故障 / 2 预留 |
|
||||
| 25 alarm_en | 原样存 |
|
||||
| 26 alarm_code | 保持 0 |
|
||||
| 27 factory_reset | 第 14 章 |
|
||||
| 28~30 | 存 RAM,可不实现动作 |
|
||||
| 7 time_en | 见第 11 章 |
|
||||
| 8~14 time_config | 8 字节 + 存 VM |
|
||||
| 15 run_record | RO,由 `app_runrec` 填 124B,禁止 APP 写。差分满 1 分钟或跨天才 0x07 |
|
||||
| 16 heartbeat | 本版忽略(写了也不停温湿度上报) |
|
||||
| 17 fault_en | 原样存,P0 不做位级过滤 |
|
||||
| 18 fault_code | 0 无 / 1 传感器故障 / 2 预留 |
|
||||
| 19 alarm_en | 原样存 |
|
||||
| 20 alarm_code | 保持 0 |
|
||||
| 21 factory_reset | 第 14 章 |
|
||||
| 22~24 reserva | 存 RAM,可不实现动作 |
|
||||
|
||||
OTA:运行态按住 12s 走门夹 `usr_app_ota_init`(在 `app_function_loop` 任务上下文调用,灯效 200ms 闪)。`jbOnOtaNotify` 等协议 OTA **P2 可继续 stub**,注释写明未实现,禁止假装升级成功后擦用户区。
|
||||
|
||||
@@ -635,7 +639,7 @@ apps/usr_app/
|
||||
- [ ] DP0 写 0 风扇不变、设备不关
|
||||
- [ ] VM:改档/改模式/写下联动与定时后断电,重新上电从周期头恢复 mode
|
||||
- [ ] 定时引擎可只存不跑(`BOARD_TIMER_ENABLE=0` 仍能保存 DP)
|
||||
- [ ] 新协议 DP 号:读不到旧的 cond_config;能读写 DP6 20B、能读 DP21
|
||||
- [ ] 新协议 DP 号:读不到旧的 cond_config;能读写 DP6 20B、能读 DP15
|
||||
|
||||
### P2 — 自动化
|
||||
|
||||
@@ -717,7 +721,7 @@ apps/usr_app/
|
||||
| 风险 | 要求 |
|
||||
|---|---|
|
||||
| JSON 对 DP6 只写了「温度 int8、湿度/版本 uint8」 | 以本文第 10.2 节 **先 min 后 max** 为准,不要猜成单阈值 |
|
||||
| 生成协议 `MAX_PACKAGE_LEN=128` | **必须改 256**,否则 DP21 组帧失败 |
|
||||
| 生成协议 `MAX_PACKAGE_LEN=128` | **必须改 256**,否则 DP15 组帧失败 |
|
||||
| 旧条件 49B VM | 不迁移、不解析;当无联动 |
|
||||
| CT1642 鬼影/异显微亮 | IO 独立不解决:单锁存 + 移位实时输出的固有特性,软件靠"值不变不刷新"/提速分时压;残余微亮需 Q2-Q9 加 1~10k 硬件下拉 |
|
||||
| 10k 上拉偏弱 | 软件 I2C 放慢;不行再提硬件改 4.7k(SDA 建议外部 4.7k) |
|
||||
@@ -735,9 +739,9 @@ apps/usr_app/
|
||||
1. 从 `_新协议` 拷贝 `jb_protocol.*` / `dp_definition.json`,`MAX_PACKAGE_LEN` 改 256;把现有 `jb_product.c` 业务迁到新 DP 号(不要用空壳覆盖)。
|
||||
2. `app_nvm`:丢掉 cond 49B,改为 linkage 20B + run_record;升版本。
|
||||
3. 新建 `app_linkage`(替换 `app_cond`),仲裁 owner 改为 LINKAGE。
|
||||
4. 新建 `app_runrec`:20ms 累加、10 分钟脏、对时旋转、灌 DP21。
|
||||
4. 新建 `app_runrec`:20ms 累加、10 分钟脏、对时旋转、灌 DP15。
|
||||
5. `app_disp` 闪烁改 8.2(出 [min,max] 就闪)。
|
||||
6. `jbEventProcess`:DP5 脉冲删除、DP6 重写重判、DP22 忽略、DP27 出厂重置。
|
||||
6. `jbEventProcess`:DP5 脉冲删除、DP6 重写重判、DP16 忽略、DP21 出厂重置。
|
||||
7. 按第 17 章 P2 用例逐条验。
|
||||
|
||||
每一步都保持对应 `BOARD_xxx_ENABLE` 可关。
|
||||
|
||||
@@ -468,6 +468,7 @@ c_SRC_FILES := \
|
||||
apps/usr_app/app_fan.c \
|
||||
apps/usr_app/app_disp.c \
|
||||
apps/usr_app/app_th.c \
|
||||
apps/usr_app/app_th_adv.c \
|
||||
apps/usr_app/app_linkage.c \
|
||||
apps/usr_app/app_runrec.c \
|
||||
apps/usr_app/app_timer_task.c \
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* @author cyWu <1917507415@qq.com>
|
||||
* @date 2026.09.02
|
||||
* @version V3.0.0(规格书 V3.0.0):app_cond → app_linkage/app_runrec;
|
||||
* 出厂重置改清联动 20B + 31 天运行记录(DP27,规格书第 14 章)
|
||||
* 出厂重置改清联动 20B + 31 天运行记录(DP21,规格书第 14 章)
|
||||
******************************************************************************/
|
||||
|
||||
#include "system/includes.h" /* 必须先于 app_main.h:u8/u16/u32 等类型由 SDK 定义 */
|
||||
@@ -81,7 +81,7 @@ void app_function_poll(void)
|
||||
{
|
||||
gDevData.fan_gear = app_fan_get_gear(); /* DP2 必须等于当前真实档位 */
|
||||
gDevData.mode = app_mode_get_active();
|
||||
/* DP24 fault_code:传感器连续失败报 1;2 预留,温湿度出范围只走显示闪烁不上报(8.2) */
|
||||
/* DP18 fault_code:传感器连续失败报 1;2 预留,温湿度出范围只走显示闪烁不上报(8.2) */
|
||||
gDevData.fault_code = app_th_is_fault() ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* @author cyWu <1917507415@qq.com>
|
||||
* @date 2026.09.02
|
||||
* @version V3.0.0(规格书 V3.0.0):app_cond → app_linkage/app_runrec;
|
||||
* 出厂重置改 DP27、清联动 20B 与 31 天运行记录
|
||||
* 出厂重置改 DP21、清联动 20B 与 31 天运行记录
|
||||
*
|
||||
* @note 本模块只做"按键 → 动作"和"状态 → DP",不写业务算法。
|
||||
* 档位/模式/联动/运行记录的执行在各自 app_* 模块(规格书 0 章第 2 条)。
|
||||
|
||||
@@ -67,9 +67,9 @@ typedef struct {
|
||||
uint8_t ver; /**< CBR3_VM_VER */
|
||||
uint8_t mode; /**< 逻辑模式 0/1/2 */
|
||||
uint8_t fan_gear; /**< 真实档位 0~3(模式未激活时即手动档) */
|
||||
uint8_t time_en; /**< DP13 定时总开关 */
|
||||
uint8_t fault_en; /**< DP23 */
|
||||
uint8_t alarm_en; /**< DP25 */
|
||||
uint8_t time_en; /**< DP7 定时总开关 */
|
||||
uint8_t fault_en; /**< DP17 */
|
||||
uint8_t alarm_en; /**< DP19 */
|
||||
uint8_t rsv[2]; /**< 对齐到 10B(原 cond_en 位置作废) */
|
||||
} __packed Cbr3StateVm_t;
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ void app_nvm_mark_dirty(void);
|
||||
|
||||
/**
|
||||
* @brief 出厂重置:清全部业务 VM(保留 BLE 配对,规格书第 14 章)
|
||||
* @note 由 jb_product DP27 调用;RAM 复位由调用方完成
|
||||
* @note 由 jb_product DP21 调用;RAM 复位由调用方完成
|
||||
* @return 无
|
||||
*/
|
||||
void app_nvm_reset(void);
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
* - app_runrec_tick(20ms 中断):只把在转的毫秒折成 pending 秒,
|
||||
* **不碰 s_rr.rec[]、不打日志、不写 flash**(跨天旋转在任务侧)。
|
||||
* - app_runrec_rotate_if_needed(500ms 任务):收下 pending 加到
|
||||
* slot[0]、每拍灌 DP21、跨天旋转、满 10 分钟 / 跨天才写 VM。
|
||||
* DP21 每 500ms 更新到 gDevData,供读请求和 10min 全量上报;
|
||||
* 差分变化上报不带 DP21(避免每秒推 124B)。
|
||||
* slot[0]、每拍灌 DP15、跨天旋转、满 10 分钟 / 跨天才写 VM。
|
||||
* DP15 每 500ms 更新到 gDevData:0x05 读立刻拿到当前秒;
|
||||
* 差分满 1 分钟才 0x07;10min 全量仍带。
|
||||
* 拔电没有软关机钩子,接受最多丢不满 10 分钟的秒数(13.1 已拍板)。
|
||||
******************************************************************************/
|
||||
|
||||
@@ -197,7 +197,7 @@ void app_runrec_rotate_if_needed(void)
|
||||
}
|
||||
}
|
||||
|
||||
/* 每拍灌 DP21:读请求 / 10min 全量能拿到当前秒数;差分上报不带本 DP */
|
||||
/* 每拍灌 DP15:0x05 读立刻拿到当前秒;差分满 1 分钟才 0x07;10min 全量仍带 */
|
||||
app_runrec_pack(gDevData.run_record);
|
||||
if (need_vm) {
|
||||
app_nvm_save_runrec(); /* 满 10 分钟或跨天 / 首次对时才写 flash */
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
* N 天;掉电上电先把 VM 的 31 格灌回 RAM。
|
||||
* 落盘:每累计运行满 BOARD_RUN_RECORD_SAVE_SEC(600s) 写一次 VM;
|
||||
* 跨天旋转**立刻写**。拔电无软关机钩子,接受丢不满 10 分钟的秒数。
|
||||
* DP21:任务上下文每 500ms 灌进 gDevData(读请求 / 10min 全量用);
|
||||
* 差分变化上报不带本 DP,避免每秒推 124B。
|
||||
* DP15:任务上下文每 500ms 灌进 gDevData(0x05 读立刻拿到当前秒;
|
||||
* 差分满 1 分钟才 0x07;10min 全量仍带)。
|
||||
*
|
||||
* ⚠ 上下文分工(规格书第 0/13 章,2026-08-31 事故定论):
|
||||
* - app_runrec_tick() = 20ms **中断上下文**:只折 pending 秒,
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* @version V1.3.0,对外温湿度与显示/上报绑死(T>=0.5℃ / H>=2%)
|
||||
*
|
||||
* @note 规格书 8.4:联动、数码管、DP3/DP4 都用对外温湿度;采样失败保持
|
||||
* 上一对外值继续判,直到连续 3 次失败显示 "--"(DP24
|
||||
* 上一对外值继续判,直到连续 3 次失败显示 "--"(DP18
|
||||
* fault_code=1)。对外值首次跟上,之后
|
||||
* |ΔT|>=BOARD_TH_TEMP_PUB_DELTA_X10、|ΔH|>=BOARD_TH_HUMI_PUB_DELTA
|
||||
* 才改,避免小数抖动导致显示、APP、联动各跳。
|
||||
@@ -67,10 +67,10 @@ uint8_t app_th_is_fault(void);
|
||||
uint8_t app_th_last_sample_ok(void);
|
||||
|
||||
/**
|
||||
* @brief 取走一次「本周期采样成功」事件(供 usr_le_adv 的 500ms 任务上下文)
|
||||
* @brief 取走一次「本周期采样成功」事件(供 app_th_adv 的 500ms 任务上下文)
|
||||
* @note ⚠ 生产者是 app_th_poll(20ms 硬件定时器中断上下文),那里只置
|
||||
* volatile pending,不开关广播、不打日志、不写 flash。
|
||||
* 消费者(usr_ble_adv_updata,BLE 线程任务上下文)调本函数取走,
|
||||
* 消费者(app_th_adv_tick,由 usr_ble_adv_updata 调用)调本函数取走,
|
||||
* 内部 local_irq_disable 保护,取到即清。
|
||||
* 只在真正采样成功(last_ok 那次)时产生,失败/fault 不产生,
|
||||
* 温度、湿度都是对外值(与数码管/DP3/DP4 一致)。
|
||||
|
||||
@@ -0,0 +1,206 @@
|
||||
/******************************************************************************
|
||||
* @file app_th_adv.c
|
||||
* @brief CBR3 自定义温湿度广播窗实现
|
||||
* @author cyWu <1917507415@qq.com>
|
||||
* @date 2026.09.03
|
||||
* @version V1.0.0
|
||||
* @history
|
||||
* - V1.0.0, 2026.09.03, cyWu, 从 usr_le_adv.c 拆出
|
||||
******************************************************************************/
|
||||
|
||||
#include "app_th_adv.h"
|
||||
#include "app_th.h"
|
||||
#include "app_linkage.h"
|
||||
#include "board_pin.h"
|
||||
#include "usr_le_api.h"
|
||||
#include "system/includes.h"
|
||||
#include "app_main.h"
|
||||
|
||||
#define LOG_TAG_CONST APP
|
||||
#define LOG_TAG "[TH_ADV]"
|
||||
#define LOG_INFO_ENABLE
|
||||
#include "debug.h"
|
||||
|
||||
extern void usr_set_adv_interval(u16 val);
|
||||
extern u16 usr_get_adv_interval(void);
|
||||
|
||||
#define TH_ADV_DATA_MAX 31
|
||||
#define TH_ADV_WINDOW_TICKS 2 /**< 500ms × 2 = 1s */
|
||||
#define TH_ADV_FAST_INTERVAL 80 /**< 窗内快广播,暂停 60s 变慢 */
|
||||
#define TH_ADV_TYPE_FLAGS 0x01
|
||||
#define TH_ADV_TYPE_LOCAL_NAME 0x09
|
||||
#define TH_ADV_TYPE_MANUFACTURER 0xFF
|
||||
|
||||
typedef struct {
|
||||
uint8_t ticks; /**< >0 = 窗进行中,剩余 500ms 拍数 */
|
||||
uint16_t interval; /**< 进窗前提速前的间隔;0=进窗前已是快广播 */
|
||||
} AppThAdvCtx_t;
|
||||
|
||||
static AppThAdvCtx_t s_th_adv;
|
||||
|
||||
/**
|
||||
* @brief 配对 / OTA / 已连接 / 未配网 → 不允许发温湿度窗
|
||||
* @return 1=阻塞,0=允许
|
||||
*/
|
||||
static uint8_t th_adv_blocked(void)
|
||||
{
|
||||
if (usr_ble_is_connected()) {
|
||||
return 1;
|
||||
}
|
||||
if (usr_var.usr_goto_pair || usr_var.usr_goto_updata ||
|
||||
usr_var.usr_ota_succ_flag) {
|
||||
return 1;
|
||||
}
|
||||
if (usr_get_pair_flag() == 0) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 组自定义温湿度 AD(Flags + Complete Local Name + Manufacturer 0xFFFF)
|
||||
* @param tank 缸体编号(非 0)
|
||||
* @param ver 配置版本
|
||||
* @param temp_x10 对外温度 ×10
|
||||
* @param humi 对外湿度 %
|
||||
* @return 无
|
||||
*/
|
||||
static void th_adv_encode(uint16_t tank, uint8_t ver, int16_t temp_x10, uint8_t humi)
|
||||
{
|
||||
uint8_t buf[TH_ADV_DATA_MAX];
|
||||
uint8_t *p = buf;
|
||||
char dec[5];
|
||||
uint8_t digits = 0;
|
||||
uint16_t v = tank;
|
||||
int32_t t_int;
|
||||
uint8_t name_len;
|
||||
|
||||
*p++ = 0x02;
|
||||
*p++ = TH_ADV_TYPE_FLAGS;
|
||||
*p++ = 0x06;
|
||||
|
||||
while (v) {
|
||||
dec[digits++] = (char)('0' + (v % 10));
|
||||
v /= 10;
|
||||
}
|
||||
name_len = (uint8_t)(5 + digits); /* "JBao-" + tank 位数 */
|
||||
*p++ = (uint8_t)(1 + name_len);
|
||||
*p++ = TH_ADV_TYPE_LOCAL_NAME;
|
||||
*p++ = 'J';
|
||||
*p++ = 'B';
|
||||
*p++ = 'a';
|
||||
*p++ = 'o';
|
||||
*p++ = '-';
|
||||
while (digits) {
|
||||
*p++ = (uint8_t)dec[--digits];
|
||||
}
|
||||
|
||||
t_int = temp_x10 / 10;
|
||||
if (t_int < -128) {
|
||||
t_int = -128;
|
||||
}
|
||||
if (t_int > 127) {
|
||||
t_int = 127;
|
||||
}
|
||||
if (humi > 100) {
|
||||
humi = 100;
|
||||
}
|
||||
*p++ = 0x06;
|
||||
*p++ = TH_ADV_TYPE_MANUFACTURER;
|
||||
*p++ = 0xFF;
|
||||
*p++ = 0xFF;
|
||||
*p++ = ver;
|
||||
*p++ = (uint8_t)t_int;
|
||||
*p++ = humi;
|
||||
|
||||
usr_ble_adv_set_raw(buf, (uint8_t)(p - buf));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 结束温湿度窗:还原广播间隔,可选切回见宝回连
|
||||
* @param back_to_reconn 1=组回连包(窗自然到期);0=只清窗
|
||||
* @return 无
|
||||
*/
|
||||
static void th_adv_stop(uint8_t back_to_reconn)
|
||||
{
|
||||
if (s_th_adv.ticks == 0) {
|
||||
return;
|
||||
}
|
||||
s_th_adv.ticks = 0;
|
||||
if (s_th_adv.interval != 0) {
|
||||
usr_set_adv_interval(s_th_adv.interval);
|
||||
s_th_adv.interval = 0;
|
||||
}
|
||||
if (back_to_reconn) {
|
||||
usr_ble_adv_encode_reconn();
|
||||
log_info("th adv win end, back to reconn\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 丢掉温湿度窗(不组回连包)
|
||||
* @return 无
|
||||
*/
|
||||
void app_th_adv_reset(void)
|
||||
{
|
||||
s_th_adv.ticks = 0;
|
||||
s_th_adv.interval = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 温湿度窗是否占用广播
|
||||
* @return 1=窗进行中,0=空闲
|
||||
*/
|
||||
uint8_t app_th_adv_is_active(void)
|
||||
{
|
||||
return (s_th_adv.ticks != 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 温湿度窗状态机(500ms 一拍)
|
||||
* @return 无
|
||||
*/
|
||||
void app_th_adv_tick(void)
|
||||
{
|
||||
#if !BOARD_TH_ENABLE
|
||||
return;
|
||||
#else
|
||||
int16_t t_x10 = 0;
|
||||
uint8_t humi = 0;
|
||||
uint16_t tank;
|
||||
|
||||
if (s_th_adv.ticks) {
|
||||
if (th_adv_blocked()) {
|
||||
th_adv_stop(0);
|
||||
} else if (s_th_adv.ticks > 1) {
|
||||
s_th_adv.ticks--;
|
||||
} else {
|
||||
/* 最后一拍必须先 stop(里头要求 ticks!=0),再组回连包 */
|
||||
th_adv_stop(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (th_adv_blocked()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!app_th_take_sample(&t_x10, &humi)) {
|
||||
return;
|
||||
}
|
||||
|
||||
tank = app_linkage_get_tank_id();
|
||||
if (tank == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (s_th_adv.ticks == 0) {
|
||||
s_th_adv.interval = (usr_get_adv_interval() != TH_ADV_FAST_INTERVAL) ?
|
||||
usr_get_adv_interval() : 0;
|
||||
usr_set_adv_interval(TH_ADV_FAST_INTERVAL);
|
||||
}
|
||||
th_adv_encode(tank, app_linkage_get_cfg_ver(), t_x10, humi);
|
||||
s_th_adv.ticks = TH_ADV_WINDOW_TICKS;
|
||||
log_info("th adv: tank=%u ver=%u T=%dC H=%u%%\n",
|
||||
tank, app_linkage_get_cfg_ver(), (int)(t_x10 / 10), humi);
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/******************************************************************************
|
||||
* @file app_th_adv.h
|
||||
* @brief CBR3 自定义温湿度广播窗(已绑定未连接时插 1s,再切回见宝回连)
|
||||
* @author cyWu <1917507415@qq.com>
|
||||
* @date 2026.09.03
|
||||
* @version V1.0.0
|
||||
* @history
|
||||
* - V1.0.0, 2026.09.03, cyWu, 从 usr_le_adv.c 拆出
|
||||
*
|
||||
* @note 给 nRF / 自研扫描器看,不是见宝 TLV。GATT 0x2A00 不动。
|
||||
* 进窗条件:未连接 + 已配网 + 非配对 + 非 OTA + tank_id≠0
|
||||
* + 本周期 AHT20 采样成功。窗长 500ms × 2。
|
||||
* ⚠ 只在 usr_ble_adv_updata(500ms 任务上下文)里 tick;
|
||||
* app_th 中断侧只置 pending,本模块是唯一消费者。
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef __APP_TH_ADV_H__
|
||||
#define __APP_TH_ADV_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* @brief 丢掉温湿度窗(不组回连包)
|
||||
* @note usr_ble_adv_init 会自己组绑定/回连,进 init 前调本函数清窗即可
|
||||
* @return 无
|
||||
*/
|
||||
void app_th_adv_reset(void);
|
||||
|
||||
/**
|
||||
* @brief 温湿度窗状态机(500ms 一拍,须在写协议栈广播数据之前调用)
|
||||
* @return 无
|
||||
*/
|
||||
void app_th_adv_tick(void);
|
||||
|
||||
/**
|
||||
* @brief 温湿度窗是否占用广播
|
||||
* @return 1=窗进行中(暂停 60s 变慢广播),0=空闲
|
||||
*/
|
||||
uint8_t app_th_adv_is_active(void);
|
||||
|
||||
#endif /* __APP_TH_ADV_H__ */
|
||||
@@ -242,7 +242,7 @@ void app_timer_run(uint16_t dt)
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief APP 写 DP13 定时总开关:存 gDevData + 触发 VM 持久化
|
||||
* @brief APP 写 DP7 定时总开关:存 gDevData + 触发 VM 持久化
|
||||
* @param en 0=关,1=开
|
||||
* @note 引擎关闭时仍保存(P1 验收);置 1 后下个 tick 补窗判断
|
||||
* @return 无
|
||||
@@ -254,7 +254,7 @@ void app_timer_set_en(uint8_t en)
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief APP 写 DP14~20 定时配置:触发 VM 持久化(数据已在 gDevData)
|
||||
* @brief APP 写 DP8~14 定时配置:触发 VM 持久化(数据已在 gDevData)
|
||||
* @param idx 1~7
|
||||
* @note 引擎关闭时仍保存
|
||||
* @return 无
|
||||
|
||||
@@ -31,14 +31,14 @@ void app_timer_init(void);
|
||||
void app_timer_run(uint16_t dt);
|
||||
|
||||
/**
|
||||
* @brief APP 写 DP13 定时总开关
|
||||
* @brief APP 写 DP7 定时总开关
|
||||
* @param en 0=关,1=开
|
||||
* @return 无
|
||||
*/
|
||||
void app_timer_set_en(uint8_t en);
|
||||
|
||||
/**
|
||||
* @brief APP 写 DP14~20 定时配置(8 字节)
|
||||
* @brief APP 写 DP8~14 定时配置(8 字节)
|
||||
* @param idx 1~7
|
||||
* @return 无
|
||||
*/
|
||||
|
||||
@@ -50,30 +50,30 @@ void userInit(void)
|
||||
gDevData.current_humi = 0; /* DP4 当前湿度 */
|
||||
gDevData.linkage_delete = 0; /* DP5 联动删除(脉冲,写 1 触发后清回 0) */
|
||||
memset(gDevData.linkage_config, 0, 20); /* DP6 联动配置(20B,10.2 布局) */
|
||||
gDevData.time_en = 0; /* DP13 定时使能 0=关 1=开 */
|
||||
memset(gDevData.time_config1, 0, 8); /* DP14 定时配置1 */
|
||||
memset(gDevData.time_config2, 0, 8); /* DP15 定时配置2 */
|
||||
memset(gDevData.time_config3, 0, 8); /* DP16 定时配置3 */
|
||||
memset(gDevData.time_config4, 0, 8); /* DP17 定时配置4 */
|
||||
memset(gDevData.time_config5, 0, 8); /* DP18 定时配置5 */
|
||||
memset(gDevData.time_config6, 0, 8); /* DP19 定时配置6 */
|
||||
memset(gDevData.time_config7, 0, 8); /* DP20 定时配置7 */
|
||||
memset(gDevData.run_record, 0, 124); /* DP21 运行记录(RO,由 app_runrec 填) */
|
||||
gDevData.heartbeat = 0; /* DP22 心跳(本版忽略) */
|
||||
gDevData.fault_en = 0; /* DP23 设备故障使能 */
|
||||
gDevData.fault_code = 0; /* DP24 设备故障 */
|
||||
gDevData.alarm_en = 0; /* DP25 设备告警使能 */
|
||||
gDevData.alarm_code = 0; /* DP26 设备告警(保持 0) */
|
||||
gDevData.factory_reset = 0; /* DP27 恢复出厂设置(WO,写 1 触发) */
|
||||
gDevData.reserva_dp1 = 0; /* DP28 预留DP1 */
|
||||
gDevData.reserva_dp2 = 0; /* DP29 预留DP2 */
|
||||
gDevData.reserva_dp3 = 0; /* DP30 预留DP3 */
|
||||
gDevData.time_en = 0; /* DP7 定时使能 0=关 1=开 */
|
||||
memset(gDevData.time_config1, 0, 8); /* DP8 定时配置1 */
|
||||
memset(gDevData.time_config2, 0, 8); /* DP9 定时配置2 */
|
||||
memset(gDevData.time_config3, 0, 8); /* DP10 定时配置3 */
|
||||
memset(gDevData.time_config4, 0, 8); /* DP11 定时配置4 */
|
||||
memset(gDevData.time_config5, 0, 8); /* DP12 定时配置5 */
|
||||
memset(gDevData.time_config6, 0, 8); /* DP13 定时配置6 */
|
||||
memset(gDevData.time_config7, 0, 8); /* DP14 定时配置7 */
|
||||
memset(gDevData.run_record, 0, 124); /* DP15 运行记录(RO,由 app_runrec 填) */
|
||||
gDevData.heartbeat = 0; /* DP16 心跳(本版忽略) */
|
||||
gDevData.fault_en = 0; /* DP17 设备故障使能 */
|
||||
gDevData.fault_code = 0; /* DP18 设备故障 */
|
||||
gDevData.alarm_en = 0; /* DP19 设备告警使能 */
|
||||
gDevData.alarm_code = 0; /* DP20 设备告警(保持 0) */
|
||||
gDevData.factory_reset = 0; /* DP21 恢复出厂设置(WO,写 1 触发) */
|
||||
gDevData.reserva_dp1 = 0; /* DP22 预留DP1 */
|
||||
gDevData.reserva_dp2 = 0; /* DP23 预留DP2 */
|
||||
gDevData.reserva_dp3 = 0; /* DP24 预留DP3 */
|
||||
}
|
||||
|
||||
/* ════════════════════════════════════════════════════════════════
|
||||
* userHandle — 用户数据采集(500ms 由 usr_timer_loop 调用)
|
||||
* 只填温湿度上报 DP;档位/模式/fault 由 app_function_poll(20ms)同步;
|
||||
* DP21 运行记录由 app_runrec 在任务上下文灌
|
||||
* DP15 运行记录由 app_runrec 在任务上下文灌
|
||||
* ════════════════════════════════════════════════════════════════ */
|
||||
void userHandle(void)
|
||||
{
|
||||
@@ -135,13 +135,13 @@ int8_t jbEventProcess(jb_event_info_t *info, jb_data_point_t *ctrl)
|
||||
app_linkage_set_config();
|
||||
break;
|
||||
|
||||
/* ── DP13 定时使能 ── */
|
||||
/* ── DP7 定时使能 ── */
|
||||
case DP_ID_TIME_EN:
|
||||
gDevData.time_en = ctrl->time_en ? 1 : 0;
|
||||
app_timer_set_en(gDevData.time_en);
|
||||
break;
|
||||
|
||||
/* ── DP14~20 定时配置(8 字节)── */
|
||||
/* ── DP8~14 定时配置(8 字节)── */
|
||||
case DP_ID_TIME_CONFIG1:
|
||||
memcpy(gDevData.time_config1, ctrl->time_config1, 8);
|
||||
app_timer_set_config(1);
|
||||
@@ -171,16 +171,16 @@ int8_t jbEventProcess(jb_event_info_t *info, jb_data_point_t *ctrl)
|
||||
app_timer_set_config(7);
|
||||
break;
|
||||
|
||||
/* ── DP21 运行记录:RO,禁止 APP 写(规格书第 15 章)── */
|
||||
/* ── DP15 运行记录:RO,禁止 APP 写(规格书第 15 章)── */
|
||||
case DP_ID_RUN_RECORD:
|
||||
break;
|
||||
|
||||
/* ── DP22 心跳:本版忽略(规格书 0 章第 11 条 / 15 章)。
|
||||
/* ── DP16 心跳:本版忽略(规格书 0 章第 11 条 / 15 章)。
|
||||
* 写了也不停温湿度上报,不做 12s 停报 ── */
|
||||
case DP_ID_HEARTBEAT:
|
||||
break;
|
||||
|
||||
/* ── DP23/25 使能:原样存,P0 不做位级过滤 ── */
|
||||
/* ── DP17/19 使能:原样存,P0 不做位级过滤 ── */
|
||||
case DP_ID_FAULT_EN:
|
||||
gDevData.fault_en = ctrl->fault_en;
|
||||
break;
|
||||
@@ -188,7 +188,7 @@ int8_t jbEventProcess(jb_event_info_t *info, jb_data_point_t *ctrl)
|
||||
gDevData.alarm_en = ctrl->alarm_en;
|
||||
break;
|
||||
|
||||
/* ── DP27 恢复出厂设置(原 DP25):清业务 VM(留配对)+ RAM 复位,
|
||||
/* ── DP21 恢复出厂设置:清业务 VM(留配对)+ RAM 复位,
|
||||
* 不断开不软复位(规格书第 14 章)── */
|
||||
case DP_ID_FACTORY_RESET:
|
||||
gDevData.factory_reset = ctrl->factory_reset ? 1 : 0;
|
||||
@@ -197,7 +197,7 @@ int8_t jbEventProcess(jb_event_info_t *info, jb_data_point_t *ctrl)
|
||||
}
|
||||
break;
|
||||
|
||||
/* ── DP28~30 预留:存 RAM,可不实现动作 ── */
|
||||
/* ── DP22~24 预留:存 RAM,可不实现动作 ── */
|
||||
case DP_ID_RESERVA_DP1:
|
||||
gDevData.reserva_dp1 = ctrl->reserva_dp1;
|
||||
break;
|
||||
|
||||
@@ -201,107 +201,107 @@ static uint16_t jbPackDps(const jb_data_point_t *dp,
|
||||
memcpy(&out[valIdx], dp->linkage_config, 20);
|
||||
valIdx += 20;
|
||||
}
|
||||
/* DP13 定时使能 (bool, 1B, RW) */
|
||||
/* DP7 定时使能 (bool, 1B, RW) */
|
||||
if (mask[DP_ID_TIME_EN / 8] & (1 << (DP_ID_TIME_EN % 8)))
|
||||
{
|
||||
bitmap[DP_ID_TIME_EN / 8] |= (1 << (DP_ID_TIME_EN % 8));
|
||||
out[valIdx++] = dp->time_en ? 1 : 0;
|
||||
}
|
||||
/* DP14 定时配置1 (raw, 8B, RW) */
|
||||
/* DP8 定时配置1 (raw, 8B, RW) */
|
||||
if (mask[DP_ID_TIME_CONFIG1 / 8] & (1 << (DP_ID_TIME_CONFIG1 % 8)))
|
||||
{
|
||||
bitmap[DP_ID_TIME_CONFIG1 / 8] |= (1 << (DP_ID_TIME_CONFIG1 % 8));
|
||||
memcpy(&out[valIdx], dp->time_config1, 8);
|
||||
valIdx += 8;
|
||||
}
|
||||
/* DP15 定时配置2 (raw, 8B, RW) */
|
||||
/* DP9 定时配置2 (raw, 8B, RW) */
|
||||
if (mask[DP_ID_TIME_CONFIG2 / 8] & (1 << (DP_ID_TIME_CONFIG2 % 8)))
|
||||
{
|
||||
bitmap[DP_ID_TIME_CONFIG2 / 8] |= (1 << (DP_ID_TIME_CONFIG2 % 8));
|
||||
memcpy(&out[valIdx], dp->time_config2, 8);
|
||||
valIdx += 8;
|
||||
}
|
||||
/* DP16 定时配置3 (raw, 8B, RW) */
|
||||
/* DP10 定时配置3 (raw, 8B, RW) */
|
||||
if (mask[DP_ID_TIME_CONFIG3 / 8] & (1 << (DP_ID_TIME_CONFIG3 % 8)))
|
||||
{
|
||||
bitmap[DP_ID_TIME_CONFIG3 / 8] |= (1 << (DP_ID_TIME_CONFIG3 % 8));
|
||||
memcpy(&out[valIdx], dp->time_config3, 8);
|
||||
valIdx += 8;
|
||||
}
|
||||
/* DP17 定时配置4 (raw, 8B, RW) */
|
||||
/* DP11 定时配置4 (raw, 8B, RW) */
|
||||
if (mask[DP_ID_TIME_CONFIG4 / 8] & (1 << (DP_ID_TIME_CONFIG4 % 8)))
|
||||
{
|
||||
bitmap[DP_ID_TIME_CONFIG4 / 8] |= (1 << (DP_ID_TIME_CONFIG4 % 8));
|
||||
memcpy(&out[valIdx], dp->time_config4, 8);
|
||||
valIdx += 8;
|
||||
}
|
||||
/* DP18 定时配置5 (raw, 8B, RW) */
|
||||
/* DP12 定时配置5 (raw, 8B, RW) */
|
||||
if (mask[DP_ID_TIME_CONFIG5 / 8] & (1 << (DP_ID_TIME_CONFIG5 % 8)))
|
||||
{
|
||||
bitmap[DP_ID_TIME_CONFIG5 / 8] |= (1 << (DP_ID_TIME_CONFIG5 % 8));
|
||||
memcpy(&out[valIdx], dp->time_config5, 8);
|
||||
valIdx += 8;
|
||||
}
|
||||
/* DP19 定时配置6 (raw, 8B, RW) */
|
||||
/* DP13 定时配置6 (raw, 8B, RW) */
|
||||
if (mask[DP_ID_TIME_CONFIG6 / 8] & (1 << (DP_ID_TIME_CONFIG6 % 8)))
|
||||
{
|
||||
bitmap[DP_ID_TIME_CONFIG6 / 8] |= (1 << (DP_ID_TIME_CONFIG6 % 8));
|
||||
memcpy(&out[valIdx], dp->time_config6, 8);
|
||||
valIdx += 8;
|
||||
}
|
||||
/* DP20 定时配置7 (raw, 8B, RW) */
|
||||
/* DP14 定时配置7 (raw, 8B, RW) */
|
||||
if (mask[DP_ID_TIME_CONFIG7 / 8] & (1 << (DP_ID_TIME_CONFIG7 % 8)))
|
||||
{
|
||||
bitmap[DP_ID_TIME_CONFIG7 / 8] |= (1 << (DP_ID_TIME_CONFIG7 % 8));
|
||||
memcpy(&out[valIdx], dp->time_config7, 8);
|
||||
valIdx += 8;
|
||||
}
|
||||
/* DP21 运行记录 (raw, 124B, RO) */
|
||||
/* DP15 运行记录 (raw, 124B, RO) */
|
||||
if (mask[DP_ID_RUN_RECORD / 8] & (1 << (DP_ID_RUN_RECORD % 8)))
|
||||
{
|
||||
bitmap[DP_ID_RUN_RECORD / 8] |= (1 << (DP_ID_RUN_RECORD % 8));
|
||||
memcpy(&out[valIdx], dp->run_record, 124);
|
||||
valIdx += 124;
|
||||
}
|
||||
/* DP23 设备故障使能 (uint8, 1B, RW) */
|
||||
/* DP17 设备故障使能 (uint8, 1B, RW) */
|
||||
if (mask[DP_ID_FAULT_EN / 8] & (1 << (DP_ID_FAULT_EN % 8)))
|
||||
{
|
||||
bitmap[DP_ID_FAULT_EN / 8] |= (1 << (DP_ID_FAULT_EN % 8));
|
||||
out[valIdx++] = (uint8_t)dp->fault_en;
|
||||
}
|
||||
/* DP24 设备故障 (uint8, 1B, RO) */
|
||||
/* DP18 设备故障 (uint8, 1B, RO) */
|
||||
if (mask[DP_ID_FAULT_CODE / 8] & (1 << (DP_ID_FAULT_CODE % 8)))
|
||||
{
|
||||
bitmap[DP_ID_FAULT_CODE / 8] |= (1 << (DP_ID_FAULT_CODE % 8));
|
||||
out[valIdx++] = (uint8_t)dp->fault_code;
|
||||
}
|
||||
/* DP25 设备告警使能 (uint8, 1B, RW) */
|
||||
/* DP19 设备告警使能 (uint8, 1B, RW) */
|
||||
if (mask[DP_ID_ALARM_EN / 8] & (1 << (DP_ID_ALARM_EN % 8)))
|
||||
{
|
||||
bitmap[DP_ID_ALARM_EN / 8] |= (1 << (DP_ID_ALARM_EN % 8));
|
||||
out[valIdx++] = (uint8_t)dp->alarm_en;
|
||||
}
|
||||
/* DP26 设备告警 (uint8, 1B, RO) */
|
||||
/* DP20 设备告警 (uint8, 1B, RO) */
|
||||
if (mask[DP_ID_ALARM_CODE / 8] & (1 << (DP_ID_ALARM_CODE % 8)))
|
||||
{
|
||||
bitmap[DP_ID_ALARM_CODE / 8] |= (1 << (DP_ID_ALARM_CODE % 8));
|
||||
out[valIdx++] = (uint8_t)dp->alarm_code;
|
||||
}
|
||||
/* DP28 预留DP1 (uint32, 4B, RW) */
|
||||
/* DP22 预留DP1 (uint32, 4B, RW) */
|
||||
if (mask[DP_ID_RESERVA_DP1 / 8] & (1 << (DP_ID_RESERVA_DP1 % 8)))
|
||||
{
|
||||
bitmap[DP_ID_RESERVA_DP1 / 8] |= (1 << (DP_ID_RESERVA_DP1 % 8));
|
||||
jbWriteU32BE(&out[valIdx], (uint32_t)dp->reserva_dp1);
|
||||
valIdx += 4;
|
||||
}
|
||||
/* DP29 预留DP2 (uint32, 4B, RW) */
|
||||
/* DP23 预留DP2 (uint32, 4B, RW) */
|
||||
if (mask[DP_ID_RESERVA_DP2 / 8] & (1 << (DP_ID_RESERVA_DP2 % 8)))
|
||||
{
|
||||
bitmap[DP_ID_RESERVA_DP2 / 8] |= (1 << (DP_ID_RESERVA_DP2 % 8));
|
||||
jbWriteU32BE(&out[valIdx], (uint32_t)dp->reserva_dp2);
|
||||
valIdx += 4;
|
||||
}
|
||||
/* DP30 预留DP3 (uint32, 4B, RW) */
|
||||
/* DP24 预留DP3 (uint32, 4B, RW) */
|
||||
if (mask[DP_ID_RESERVA_DP3 / 8] & (1 << (DP_ID_RESERVA_DP3 % 8)))
|
||||
{
|
||||
bitmap[DP_ID_RESERVA_DP3 / 8] |= (1 << (DP_ID_RESERVA_DP3 % 8));
|
||||
@@ -387,7 +387,7 @@ static void jbUnpackDps(const uint8_t *bitmap, const uint8_t *values,
|
||||
info->dp_ids[info->count++] = DP_ID_LINKAGE_CONFIG;
|
||||
}
|
||||
}
|
||||
/* DP13 定时使能 (bool, 1B, RW) */
|
||||
/* DP7 定时使能 (bool, 1B, RW) */
|
||||
if (bitmap[DP_ID_TIME_EN / 8] & (1 << (DP_ID_TIME_EN % 8)))
|
||||
{
|
||||
if (valIdx < valLen)
|
||||
@@ -399,7 +399,7 @@ static void jbUnpackDps(const uint8_t *bitmap, const uint8_t *values,
|
||||
info->dp_ids[info->count++] = DP_ID_TIME_EN;
|
||||
}
|
||||
}
|
||||
/* DP14 定时配置1 (raw, 8B, RW) */
|
||||
/* DP8 定时配置1 (raw, 8B, RW) */
|
||||
if (bitmap[DP_ID_TIME_CONFIG1 / 8] & (1 << (DP_ID_TIME_CONFIG1 % 8)))
|
||||
{
|
||||
if (valIdx + 8 <= valLen)
|
||||
@@ -412,7 +412,7 @@ static void jbUnpackDps(const uint8_t *bitmap, const uint8_t *values,
|
||||
info->dp_ids[info->count++] = DP_ID_TIME_CONFIG1;
|
||||
}
|
||||
}
|
||||
/* DP15 定时配置2 (raw, 8B, RW) */
|
||||
/* DP9 定时配置2 (raw, 8B, RW) */
|
||||
if (bitmap[DP_ID_TIME_CONFIG2 / 8] & (1 << (DP_ID_TIME_CONFIG2 % 8)))
|
||||
{
|
||||
if (valIdx + 8 <= valLen)
|
||||
@@ -425,7 +425,7 @@ static void jbUnpackDps(const uint8_t *bitmap, const uint8_t *values,
|
||||
info->dp_ids[info->count++] = DP_ID_TIME_CONFIG2;
|
||||
}
|
||||
}
|
||||
/* DP16 定时配置3 (raw, 8B, RW) */
|
||||
/* DP10 定时配置3 (raw, 8B, RW) */
|
||||
if (bitmap[DP_ID_TIME_CONFIG3 / 8] & (1 << (DP_ID_TIME_CONFIG3 % 8)))
|
||||
{
|
||||
if (valIdx + 8 <= valLen)
|
||||
@@ -438,7 +438,7 @@ static void jbUnpackDps(const uint8_t *bitmap, const uint8_t *values,
|
||||
info->dp_ids[info->count++] = DP_ID_TIME_CONFIG3;
|
||||
}
|
||||
}
|
||||
/* DP17 定时配置4 (raw, 8B, RW) */
|
||||
/* DP11 定时配置4 (raw, 8B, RW) */
|
||||
if (bitmap[DP_ID_TIME_CONFIG4 / 8] & (1 << (DP_ID_TIME_CONFIG4 % 8)))
|
||||
{
|
||||
if (valIdx + 8 <= valLen)
|
||||
@@ -451,7 +451,7 @@ static void jbUnpackDps(const uint8_t *bitmap, const uint8_t *values,
|
||||
info->dp_ids[info->count++] = DP_ID_TIME_CONFIG4;
|
||||
}
|
||||
}
|
||||
/* DP18 定时配置5 (raw, 8B, RW) */
|
||||
/* DP12 定时配置5 (raw, 8B, RW) */
|
||||
if (bitmap[DP_ID_TIME_CONFIG5 / 8] & (1 << (DP_ID_TIME_CONFIG5 % 8)))
|
||||
{
|
||||
if (valIdx + 8 <= valLen)
|
||||
@@ -464,7 +464,7 @@ static void jbUnpackDps(const uint8_t *bitmap, const uint8_t *values,
|
||||
info->dp_ids[info->count++] = DP_ID_TIME_CONFIG5;
|
||||
}
|
||||
}
|
||||
/* DP19 定时配置6 (raw, 8B, RW) */
|
||||
/* DP13 定时配置6 (raw, 8B, RW) */
|
||||
if (bitmap[DP_ID_TIME_CONFIG6 / 8] & (1 << (DP_ID_TIME_CONFIG6 % 8)))
|
||||
{
|
||||
if (valIdx + 8 <= valLen)
|
||||
@@ -477,7 +477,7 @@ static void jbUnpackDps(const uint8_t *bitmap, const uint8_t *values,
|
||||
info->dp_ids[info->count++] = DP_ID_TIME_CONFIG6;
|
||||
}
|
||||
}
|
||||
/* DP20 定时配置7 (raw, 8B, RW) */
|
||||
/* DP14 定时配置7 (raw, 8B, RW) */
|
||||
if (bitmap[DP_ID_TIME_CONFIG7 / 8] & (1 << (DP_ID_TIME_CONFIG7 % 8)))
|
||||
{
|
||||
if (valIdx + 8 <= valLen)
|
||||
@@ -490,7 +490,7 @@ static void jbUnpackDps(const uint8_t *bitmap, const uint8_t *values,
|
||||
info->dp_ids[info->count++] = DP_ID_TIME_CONFIG7;
|
||||
}
|
||||
}
|
||||
/* DP22 心跳 (bool, 1B, WO) */
|
||||
/* DP16 心跳 (bool, 1B, WO) */
|
||||
if (bitmap[DP_ID_HEARTBEAT / 8] & (1 << (DP_ID_HEARTBEAT % 8)))
|
||||
{
|
||||
if (valIdx < valLen)
|
||||
@@ -502,7 +502,7 @@ static void jbUnpackDps(const uint8_t *bitmap, const uint8_t *values,
|
||||
info->dp_ids[info->count++] = DP_ID_HEARTBEAT;
|
||||
}
|
||||
}
|
||||
/* DP23 设备故障使能 (uint8, 1B, RW) */
|
||||
/* DP17 设备故障使能 (uint8, 1B, RW) */
|
||||
if (bitmap[DP_ID_FAULT_EN / 8] & (1 << (DP_ID_FAULT_EN % 8)))
|
||||
{
|
||||
if (valIdx < valLen)
|
||||
@@ -514,7 +514,7 @@ static void jbUnpackDps(const uint8_t *bitmap, const uint8_t *values,
|
||||
info->dp_ids[info->count++] = DP_ID_FAULT_EN;
|
||||
}
|
||||
}
|
||||
/* DP25 设备告警使能 (uint8, 1B, RW) */
|
||||
/* DP19 设备告警使能 (uint8, 1B, RW) */
|
||||
if (bitmap[DP_ID_ALARM_EN / 8] & (1 << (DP_ID_ALARM_EN % 8)))
|
||||
{
|
||||
if (valIdx < valLen)
|
||||
@@ -526,7 +526,7 @@ static void jbUnpackDps(const uint8_t *bitmap, const uint8_t *values,
|
||||
info->dp_ids[info->count++] = DP_ID_ALARM_EN;
|
||||
}
|
||||
}
|
||||
/* DP27 恢复出厂设置 (bool, 1B, WO) */
|
||||
/* DP21 恢复出厂设置 (bool, 1B, WO) */
|
||||
if (bitmap[DP_ID_FACTORY_RESET / 8] & (1 << (DP_ID_FACTORY_RESET % 8)))
|
||||
{
|
||||
if (valIdx < valLen)
|
||||
@@ -538,7 +538,7 @@ static void jbUnpackDps(const uint8_t *bitmap, const uint8_t *values,
|
||||
info->dp_ids[info->count++] = DP_ID_FACTORY_RESET;
|
||||
}
|
||||
}
|
||||
/* DP28 预留DP1 (uint32, 4B, RW) */
|
||||
/* DP22 预留DP1 (uint32, 4B, RW) */
|
||||
if (bitmap[DP_ID_RESERVA_DP1 / 8] & (1 << (DP_ID_RESERVA_DP1 % 8)))
|
||||
{
|
||||
if (valIdx + 4 <= valLen)
|
||||
@@ -551,7 +551,7 @@ static void jbUnpackDps(const uint8_t *bitmap, const uint8_t *values,
|
||||
info->dp_ids[info->count++] = DP_ID_RESERVA_DP1;
|
||||
}
|
||||
}
|
||||
/* DP29 预留DP2 (uint32, 4B, RW) */
|
||||
/* DP23 预留DP2 (uint32, 4B, RW) */
|
||||
if (bitmap[DP_ID_RESERVA_DP2 / 8] & (1 << (DP_ID_RESERVA_DP2 % 8)))
|
||||
{
|
||||
if (valIdx + 4 <= valLen)
|
||||
@@ -564,7 +564,7 @@ static void jbUnpackDps(const uint8_t *bitmap, const uint8_t *values,
|
||||
info->dp_ids[info->count++] = DP_ID_RESERVA_DP2;
|
||||
}
|
||||
}
|
||||
/* DP30 预留DP3 (uint32, 4B, RW) */
|
||||
/* DP24 预留DP3 (uint32, 4B, RW) */
|
||||
if (bitmap[DP_ID_RESERVA_DP3 / 8] & (1 << (DP_ID_RESERVA_DP3 % 8)))
|
||||
{
|
||||
if (valIdx + 4 <= valLen)
|
||||
@@ -582,7 +582,15 @@ static void jbUnpackDps(const uint8_t *bitmap, const uint8_t *values,
|
||||
/* ════════════════════════════════════════════════════════════════
|
||||
* jbBuildDiffMask — 比较上次与当前值,为变化的可上报 DP 置 mask 位
|
||||
* 返回: 1 = 有 DP 发生变化, 0 = 全部未变化
|
||||
* DP15 运行记录:今天累计秒数相对上次上报满 JB_RUNREC_DIFF_SEC 才进差分;
|
||||
* 其它日期格变化(跨天旋转)立刻进差分。0x05 读 / 10min 全量仍带完整 124B。
|
||||
* ════════════════════════════════════════════════════════════════ */
|
||||
static uint32_t jbRunrecTodaySec(const uint8_t *rec)
|
||||
{
|
||||
return ((uint32_t)rec[0] << 24) | ((uint32_t)rec[1] << 16)
|
||||
| ((uint32_t)rec[2] << 8) | (uint32_t)rec[3];
|
||||
}
|
||||
|
||||
static uint8_t jbBuildDiffMask(const jb_data_point_t *last,
|
||||
const jb_data_point_t *cur,
|
||||
uint8_t *mask)
|
||||
@@ -632,93 +640,106 @@ static uint8_t jbBuildDiffMask(const jb_data_point_t *last,
|
||||
mask[DP_ID_LINKAGE_CONFIG / 8] |= (1 << (DP_ID_LINKAGE_CONFIG % 8));
|
||||
hasChange = 1;
|
||||
}
|
||||
/* DP13 定时使能 */
|
||||
/* DP7 定时使能 */
|
||||
if (last->time_en != cur->time_en)
|
||||
{
|
||||
mask[DP_ID_TIME_EN / 8] |= (1 << (DP_ID_TIME_EN % 8));
|
||||
hasChange = 1;
|
||||
}
|
||||
/* DP14 定时配置1 */
|
||||
/* DP8 定时配置1 */
|
||||
if (memcmp(last->time_config1, cur->time_config1, 8))
|
||||
{
|
||||
mask[DP_ID_TIME_CONFIG1 / 8] |= (1 << (DP_ID_TIME_CONFIG1 % 8));
|
||||
hasChange = 1;
|
||||
}
|
||||
/* DP15 定时配置2 */
|
||||
/* DP9 定时配置2 */
|
||||
if (memcmp(last->time_config2, cur->time_config2, 8))
|
||||
{
|
||||
mask[DP_ID_TIME_CONFIG2 / 8] |= (1 << (DP_ID_TIME_CONFIG2 % 8));
|
||||
hasChange = 1;
|
||||
}
|
||||
/* DP16 定时配置3 */
|
||||
/* DP10 定时配置3 */
|
||||
if (memcmp(last->time_config3, cur->time_config3, 8))
|
||||
{
|
||||
mask[DP_ID_TIME_CONFIG3 / 8] |= (1 << (DP_ID_TIME_CONFIG3 % 8));
|
||||
hasChange = 1;
|
||||
}
|
||||
/* DP17 定时配置4 */
|
||||
/* DP11 定时配置4 */
|
||||
if (memcmp(last->time_config4, cur->time_config4, 8))
|
||||
{
|
||||
mask[DP_ID_TIME_CONFIG4 / 8] |= (1 << (DP_ID_TIME_CONFIG4 % 8));
|
||||
hasChange = 1;
|
||||
}
|
||||
/* DP18 定时配置5 */
|
||||
/* DP12 定时配置5 */
|
||||
if (memcmp(last->time_config5, cur->time_config5, 8))
|
||||
{
|
||||
mask[DP_ID_TIME_CONFIG5 / 8] |= (1 << (DP_ID_TIME_CONFIG5 % 8));
|
||||
hasChange = 1;
|
||||
}
|
||||
/* DP19 定时配置6 */
|
||||
/* DP13 定时配置6 */
|
||||
if (memcmp(last->time_config6, cur->time_config6, 8))
|
||||
{
|
||||
mask[DP_ID_TIME_CONFIG6 / 8] |= (1 << (DP_ID_TIME_CONFIG6 % 8));
|
||||
hasChange = 1;
|
||||
}
|
||||
/* DP20 定时配置7 */
|
||||
/* DP14 定时配置7 */
|
||||
if (memcmp(last->time_config7, cur->time_config7, 8))
|
||||
{
|
||||
mask[DP_ID_TIME_CONFIG7 / 8] |= (1 << (DP_ID_TIME_CONFIG7 % 8));
|
||||
hasChange = 1;
|
||||
}
|
||||
/* DP21 运行记录:每秒都在变,不参与差分上报(避免 2s 防抖推 124B)。
|
||||
* 读请求与 REPORT_PERIOD 全量仍带当前 gDevData.run_record。 */
|
||||
/* DP23 设备故障使能 */
|
||||
/* DP15 运行记录:今天秒数差分满 1 分钟,或后 30 天格变了(跨天) */
|
||||
{
|
||||
uint32_t last_today = jbRunrecTodaySec(last->run_record);
|
||||
uint32_t cur_today = jbRunrecTodaySec(cur->run_record);
|
||||
uint32_t delta = (cur_today > last_today)
|
||||
? (cur_today - last_today)
|
||||
: (last_today - cur_today);
|
||||
|
||||
if ((delta >= JB_RUNREC_DIFF_SEC)
|
||||
|| memcmp(&last->run_record[4], &cur->run_record[4], 120))
|
||||
{
|
||||
mask[DP_ID_RUN_RECORD / 8] |= (1 << (DP_ID_RUN_RECORD % 8));
|
||||
hasChange = 1;
|
||||
}
|
||||
}
|
||||
/* DP17 设备故障使能 */
|
||||
if (last->fault_en != cur->fault_en)
|
||||
{
|
||||
mask[DP_ID_FAULT_EN / 8] |= (1 << (DP_ID_FAULT_EN % 8));
|
||||
hasChange = 1;
|
||||
}
|
||||
/* DP24 设备故障 */
|
||||
/* DP18 设备故障 */
|
||||
if (last->fault_code != cur->fault_code)
|
||||
{
|
||||
mask[DP_ID_FAULT_CODE / 8] |= (1 << (DP_ID_FAULT_CODE % 8));
|
||||
hasChange = 1;
|
||||
}
|
||||
/* DP25 设备告警使能 */
|
||||
/* DP19 设备告警使能 */
|
||||
if (last->alarm_en != cur->alarm_en)
|
||||
{
|
||||
mask[DP_ID_ALARM_EN / 8] |= (1 << (DP_ID_ALARM_EN % 8));
|
||||
hasChange = 1;
|
||||
}
|
||||
/* DP26 设备告警 */
|
||||
/* DP20 设备告警 */
|
||||
if (last->alarm_code != cur->alarm_code)
|
||||
{
|
||||
mask[DP_ID_ALARM_CODE / 8] |= (1 << (DP_ID_ALARM_CODE % 8));
|
||||
hasChange = 1;
|
||||
}
|
||||
/* DP28 预留DP1 */
|
||||
/* DP22 预留DP1 */
|
||||
if (last->reserva_dp1 != cur->reserva_dp1)
|
||||
{
|
||||
mask[DP_ID_RESERVA_DP1 / 8] |= (1 << (DP_ID_RESERVA_DP1 % 8));
|
||||
hasChange = 1;
|
||||
}
|
||||
/* DP29 预留DP2 */
|
||||
/* DP23 预留DP2 */
|
||||
if (last->reserva_dp2 != cur->reserva_dp2)
|
||||
{
|
||||
mask[DP_ID_RESERVA_DP2 / 8] |= (1 << (DP_ID_RESERVA_DP2 % 8));
|
||||
hasChange = 1;
|
||||
}
|
||||
/* DP30 预留DP3 */
|
||||
/* DP24 预留DP3 */
|
||||
if (last->reserva_dp3 != cur->reserva_dp3)
|
||||
{
|
||||
mask[DP_ID_RESERVA_DP3 / 8] |= (1 << (DP_ID_RESERVA_DP3 % 8));
|
||||
@@ -864,7 +885,19 @@ static void jbReportPolicy(jb_data_point_t *data)
|
||||
(now - jbProtocol.lastChangeTime > REPORT_DEBOUNCE))
|
||||
{
|
||||
jbSendReport(data, diffMask);
|
||||
memcpy(&jbProtocol.lastData, data, sizeof(jb_data_point_t));
|
||||
/* 未带 DP15 时保留上次记录基准,避免档位/模式等上报把 1 分钟差分冲掉 */
|
||||
if (!(diffMask[DP_ID_RUN_RECORD / 8] & (1u << (DP_ID_RUN_RECORD % 8))))
|
||||
{
|
||||
uint8_t keep[124];
|
||||
|
||||
memcpy(keep, jbProtocol.lastData.run_record, 124);
|
||||
memcpy(&jbProtocol.lastData, data, sizeof(jb_data_point_t));
|
||||
memcpy(jbProtocol.lastData.run_record, keep, 124);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(&jbProtocol.lastData, data, sizeof(jb_data_point_t));
|
||||
}
|
||||
jbProtocol.lastChangeTime = now;
|
||||
jbProtocol.lastReportTime = now;
|
||||
return;
|
||||
|
||||
@@ -23,10 +23,10 @@
|
||||
* ════════════════════════════════════════════════════════════════ */
|
||||
#define PKT_HEAD_0 0x55
|
||||
#define PKT_HEAD_1 0xAA
|
||||
/* ⚠ 生成器给的是 128,必须改回 256:DP21 run_record 124B,加 bitmap(4B) 与
|
||||
/* ⚠ 生成器给的是 128,必须改回 256:DP15 run_record 124B,加 bitmap(4B) 与
|
||||
* cmd/sn/cksum 开销后 128B 组不出完整帧(规格书第 0 章第 1 条 / 第 19 章)。
|
||||
* 每次从生成器重新拷贝 jb_protocol.h 后都要重新确认本值。 */
|
||||
#define MAX_PACKAGE_LEN 256
|
||||
#define MAX_PACKAGE_LEN 512
|
||||
#define JB_OTA_MAX_PAYLOAD 96 /* OTA 单包 Payload 上限(Byte); 须 <= MAX_PACKAGE_LEN - 11(0x32 帧开销) */
|
||||
|
||||
#define DP_COUNT 25
|
||||
@@ -36,6 +36,7 @@
|
||||
#define SEND_MAX_NUM 3 /* 最大重传次数 */
|
||||
#define REPORT_DEBOUNCE 2000 /* 变化上报防抖时间(ms) */
|
||||
#define REPORT_PERIOD 600000 /* 定时全量上报周期(ms) */
|
||||
#define JB_RUNREC_DIFF_SEC 60 /* DP15 差分:今天秒数相对上次上报满 1 分钟才带 */
|
||||
|
||||
/* Device identity: 取自 Excel 设备信息表的 ProdtCode / productCode。
|
||||
* JB_CATEGORY_CODE: 必须 4 字符 ASCII,供 BLE 广播 prodcode 使用
|
||||
@@ -128,24 +129,24 @@ typedef enum
|
||||
DP_ID_CURRENT_HUMI = 4, /* 当前湿度 (uint8, RO) */
|
||||
DP_ID_LINKAGE_DELETE = 5, /* 联动删除 (bool, RW) */
|
||||
DP_ID_LINKAGE_CONFIG = 6, /* 联动配置 (raw, RW) */
|
||||
DP_ID_TIME_EN = 13, /* 定时使能 (bool, RW) */
|
||||
DP_ID_TIME_CONFIG1 = 14, /* 定时配置1 (raw, RW) */
|
||||
DP_ID_TIME_CONFIG2 = 15, /* 定时配置2 (raw, RW) */
|
||||
DP_ID_TIME_CONFIG3 = 16, /* 定时配置3 (raw, RW) */
|
||||
DP_ID_TIME_CONFIG4 = 17, /* 定时配置4 (raw, RW) */
|
||||
DP_ID_TIME_CONFIG5 = 18, /* 定时配置5 (raw, RW) */
|
||||
DP_ID_TIME_CONFIG6 = 19, /* 定时配置6 (raw, RW) */
|
||||
DP_ID_TIME_CONFIG7 = 20, /* 定时配置7 (raw, RW) */
|
||||
DP_ID_RUN_RECORD = 21, /* 运行记录 (raw, RO) */
|
||||
DP_ID_HEARTBEAT = 22, /* 心跳 (bool, WO) */
|
||||
DP_ID_FAULT_EN = 23, /* 设备故障使能 (uint8, RW) */
|
||||
DP_ID_FAULT_CODE = 24, /* 设备故障 (uint8, RO) */
|
||||
DP_ID_ALARM_EN = 25, /* 设备告警使能 (uint8, RW) */
|
||||
DP_ID_ALARM_CODE = 26, /* 设备告警 (uint8, RO) */
|
||||
DP_ID_FACTORY_RESET = 27, /* 恢复出厂设置 (bool, WO) */
|
||||
DP_ID_RESERVA_DP1 = 28, /* 预留DP1 (uint32, RW) */
|
||||
DP_ID_RESERVA_DP2 = 29, /* 预留DP2 (uint32, RW) */
|
||||
DP_ID_RESERVA_DP3 = 30, /* 预留DP3 (uint32, RW) */
|
||||
DP_ID_TIME_EN = 7, /* 定时使能 (bool, RW) */
|
||||
DP_ID_TIME_CONFIG1 = 8, /* 定时配置1 (raw, RW) */
|
||||
DP_ID_TIME_CONFIG2 = 9, /* 定时配置2 (raw, RW) */
|
||||
DP_ID_TIME_CONFIG3 = 10, /* 定时配置3 (raw, RW) */
|
||||
DP_ID_TIME_CONFIG4 = 11, /* 定时配置4 (raw, RW) */
|
||||
DP_ID_TIME_CONFIG5 = 12, /* 定时配置5 (raw, RW) */
|
||||
DP_ID_TIME_CONFIG6 = 13, /* 定时配置6 (raw, RW) */
|
||||
DP_ID_TIME_CONFIG7 = 14, /* 定时配置7 (raw, RW) */
|
||||
DP_ID_RUN_RECORD = 15, /* 运行记录 (raw, RO) */
|
||||
DP_ID_HEARTBEAT = 16, /* 心跳 (bool, WO) */
|
||||
DP_ID_FAULT_EN = 17, /* 设备故障使能 (uint8, RW) */
|
||||
DP_ID_FAULT_CODE = 18, /* 设备故障 (uint8, RO) */
|
||||
DP_ID_ALARM_EN = 19, /* 设备告警使能 (uint8, RW) */
|
||||
DP_ID_ALARM_CODE = 20, /* 设备告警 (uint8, RO) */
|
||||
DP_ID_FACTORY_RESET = 21, /* 恢复出厂设置 (bool, WO) */
|
||||
DP_ID_RESERVA_DP1 = 22, /* 预留DP1 (uint32, RW) */
|
||||
DP_ID_RESERVA_DP2 = 23, /* 预留DP2 (uint32, RW) */
|
||||
DP_ID_RESERVA_DP3 = 24, /* 预留DP3 (uint32, RW) */
|
||||
DP_ID_MAX
|
||||
} dp_id_t;
|
||||
|
||||
@@ -210,24 +211,24 @@ typedef struct
|
||||
uint8_t current_humi; /* DP4 当前湿度 */
|
||||
uint8_t linkage_delete;/* DP5 联动删除 */
|
||||
uint8_t linkage_config[20];/* DP6 联动配置 */
|
||||
uint8_t time_en; /* DP13 定时使能 */
|
||||
uint8_t time_config1[8];/* DP14 定时配置1 */
|
||||
uint8_t time_config2[8];/* DP15 定时配置2 */
|
||||
uint8_t time_config3[8];/* DP16 定时配置3 */
|
||||
uint8_t time_config4[8];/* DP17 定时配置4 */
|
||||
uint8_t time_config5[8];/* DP18 定时配置5 */
|
||||
uint8_t time_config6[8];/* DP19 定时配置6 */
|
||||
uint8_t time_config7[8];/* DP20 定时配置7 */
|
||||
uint8_t run_record[124];/* DP21 运行记录 */
|
||||
uint8_t heartbeat; /* DP22 心跳 */
|
||||
uint8_t fault_en; /* DP23 设备故障使能 */
|
||||
uint8_t fault_code; /* DP24 设备故障 */
|
||||
uint8_t alarm_en; /* DP25 设备告警使能 */
|
||||
uint8_t alarm_code; /* DP26 设备告警 */
|
||||
uint8_t factory_reset;/* DP27 恢复出厂设置 */
|
||||
uint32_t reserva_dp1; /* DP28 预留DP1 */
|
||||
uint32_t reserva_dp2; /* DP29 预留DP2 */
|
||||
uint32_t reserva_dp3; /* DP30 预留DP3 */
|
||||
uint8_t time_en; /* DP7 定时使能 */
|
||||
uint8_t time_config1[8];/* DP8 定时配置1 */
|
||||
uint8_t time_config2[8];/* DP9 定时配置2 */
|
||||
uint8_t time_config3[8];/* DP10 定时配置3 */
|
||||
uint8_t time_config4[8];/* DP11 定时配置4 */
|
||||
uint8_t time_config5[8];/* DP12 定时配置5 */
|
||||
uint8_t time_config6[8];/* DP13 定时配置6 */
|
||||
uint8_t time_config7[8];/* DP14 定时配置7 */
|
||||
uint8_t run_record[124];/* DP15 运行记录 */
|
||||
uint8_t heartbeat; /* DP16 心跳 */
|
||||
uint8_t fault_en; /* DP17 设备故障使能 */
|
||||
uint8_t fault_code; /* DP18 设备故障 */
|
||||
uint8_t alarm_en; /* DP19 设备告警使能 */
|
||||
uint8_t alarm_code; /* DP20 设备告警 */
|
||||
uint8_t factory_reset;/* DP21 恢复出厂设置 */
|
||||
uint32_t reserva_dp1; /* DP22 预留DP1 */
|
||||
uint32_t reserva_dp2; /* DP23 预留DP2 */
|
||||
uint32_t reserva_dp3; /* DP24 预留DP3 */
|
||||
} jb_data_point_t;
|
||||
|
||||
/* 控制事件信息 */
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* @author cyWu <1917507415@qq.com>
|
||||
* @date 2026.09.02
|
||||
* @version V3.0.0,规格书 V3.0.0:条件引擎(app_cond)整模块删除,换
|
||||
* app_linkage(DP5/DP6,联动)+ app_runrec(DP21,31 天运行记录);
|
||||
* app_linkage(DP5/DP6,联动)+ app_runrec(DP15,31 天运行记录);
|
||||
* 20ms 节拍加 app_runrec_tick,500ms 任务上下文加
|
||||
* app_linkage_run / app_runrec_rotate_if_needed
|
||||
*
|
||||
@@ -185,6 +185,6 @@ void usr_timer_loop(void)
|
||||
jbProtocolHandle(&gDevData);
|
||||
app_timer_run(500); /* 定时引擎(RTC 门闩 + 窗判断;窗结束会调联动重判) */
|
||||
app_linkage_run(500); /* 联动引擎(任务上下文;仲裁见 app_arbiter) */
|
||||
app_runrec_rotate_if_needed(); /* 收下 pending、每拍灌 DP21;满 10 分钟/跨天才写 VM */
|
||||
app_runrec_rotate_if_needed(); /* 收下 pending、每拍灌 DP15;满 10 分钟/跨天才写 VM */
|
||||
app_function_loop(); /* 任务上下文:VM 防抖落盘 + 配对/OTA 动作落地 */
|
||||
}
|
||||
|
||||
@@ -673,51 +673,89 @@ int bleproto_appdata_serialize(bleproto_appdata_t *appdata,
|
||||
|
||||
int bleproto_appdata_wrap_raw(uint8_t *txbuf,
|
||||
uint16_t txbuf_size,
|
||||
uint8_t packetlen,
|
||||
const bleproto_appdata_header_t *header,
|
||||
const uint8_t *payload,
|
||||
uint16_t payload_len)
|
||||
{
|
||||
uint16_t total;
|
||||
uint8_t frame_max;
|
||||
uint16_t totalframe;
|
||||
uint16_t need;
|
||||
uint16_t offset = 0;
|
||||
uint16_t data_offset = 0;
|
||||
uint16_t i;
|
||||
|
||||
if (!txbuf || !header) {
|
||||
BLEPROTO_T_E("Invalid parameters");
|
||||
if (!txbuf || !header || packetlen <= BLEPROTO_APPDATA_HEADR_LEN) {
|
||||
printf("Invalid parameters");
|
||||
return -1;
|
||||
}
|
||||
if (payload_len > 0 && !payload) {
|
||||
BLEPROTO_T_E("Invalid payload");
|
||||
return -1;
|
||||
}
|
||||
/* 单帧 this_frame_len 为 uint8,超过 255 需走分包 serialize */
|
||||
if (payload_len > 255u) {
|
||||
BLEPROTO_T_E("payload too long for single frame");
|
||||
printf("Invalid payload");
|
||||
return -1;
|
||||
}
|
||||
|
||||
total = (uint16_t)(BLEPROTO_APPDATA_HEADR_LEN + payload_len);
|
||||
if (txbuf_size < total) {
|
||||
BLEPROTO_T_E("txbuf too short");
|
||||
/* 与 serialize 相同:一帧总长 packetlen,其中 8B 头,其余为 payload */
|
||||
frame_max = (uint8_t)(packetlen - BLEPROTO_APPDATA_HEADR_LEN);
|
||||
|
||||
if (payload_len == 0) {
|
||||
totalframe = 1;
|
||||
} else {
|
||||
totalframe = (uint16_t)((payload_len + frame_max - 1u) / frame_max);
|
||||
}
|
||||
if (totalframe > 255u) {
|
||||
printf("payload too long, frames %u>255\n", (unsigned)totalframe);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* buf[0]: version[2:0] | datafmt[3:3] | msgtype[7:4] */
|
||||
txbuf[0] = UTILS_BITFIELD_SET(header->version, 2, 0) |
|
||||
UTILS_BITFIELD_SET(header->datafmt, 3, 3) |
|
||||
UTILS_BITFIELD_SET(header->msgtype, 7, 4);
|
||||
/* buf[1]: msgid[3:0] | encrypt[4:4] | reserve[7:5] */
|
||||
txbuf[1] = UTILS_BITFIELD_SET(header->msgid, 3, 0) |
|
||||
UTILS_BITFIELD_SET(header->encrypt, 4, 4) |
|
||||
UTILS_BITFIELD_SET(header->reserve, 7, 5);
|
||||
txbuf[2] = 1; /* totalframe */
|
||||
txbuf[3] = 0; /* frameseq:单帧为 0 */
|
||||
txbuf[4] = (uint8_t)payload_len; /* this frame payload len */
|
||||
txbuf[5] = header->serviceid;
|
||||
proto_bytes_put_le16(&txbuf[6], payload_len);
|
||||
|
||||
if (payload_len > 0) {
|
||||
memcpy(&txbuf[BLEPROTO_APPDATA_HEADR_LEN], payload, payload_len);
|
||||
need = (uint16_t)((uint16_t)totalframe * BLEPROTO_APPDATA_HEADR_LEN + payload_len);
|
||||
if (txbuf_size < need) {
|
||||
printf("txbuf too short %u<%u\n", (unsigned)txbuf_size, (unsigned)need);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (int)total;
|
||||
for (i = 0; i < totalframe; i++) {
|
||||
uint8_t this_len;
|
||||
uint8_t frameseq;
|
||||
|
||||
if (totalframe == 1u) {
|
||||
this_len = (uint8_t)payload_len;
|
||||
frameseq = 0; /* 单帧序号为 0 */
|
||||
} else if ((uint16_t)(i + 1u) < totalframe) {
|
||||
this_len = frame_max;
|
||||
frameseq = (uint8_t)(i + 1u); /* 分包从 1 起 */
|
||||
} else {
|
||||
this_len = (uint8_t)(payload_len - data_offset);
|
||||
frameseq = (uint8_t)(i + 1u);
|
||||
}
|
||||
|
||||
/* buf[0]: version[2:0] | datafmt[3:3] | msgtype[7:4] */
|
||||
txbuf[offset + 0] = UTILS_BITFIELD_SET(header->version, 2, 0) |
|
||||
UTILS_BITFIELD_SET(header->datafmt, 3, 3) |
|
||||
UTILS_BITFIELD_SET(header->msgtype, 7, 4);
|
||||
/* buf[1]: msgid[3:0] | encrypt[4:4] | reserve[7:5] */
|
||||
txbuf[offset + 1] = UTILS_BITFIELD_SET(header->msgid, 3, 0) |
|
||||
UTILS_BITFIELD_SET(header->encrypt, 4, 4) |
|
||||
UTILS_BITFIELD_SET(header->reserve, 7, 5);
|
||||
txbuf[offset + 2] = (uint8_t)totalframe;
|
||||
txbuf[offset + 3] = frameseq;
|
||||
txbuf[offset + 4] = this_len;
|
||||
txbuf[offset + 5] = header->serviceid;
|
||||
proto_bytes_put_le16(&txbuf[offset + 6], payload_len);
|
||||
|
||||
offset = (uint16_t)(offset + BLEPROTO_APPDATA_HEADR_LEN);
|
||||
if (this_len != 0) {
|
||||
memcpy(&txbuf[offset], &payload[data_offset], this_len);
|
||||
offset = (uint16_t)(offset + this_len);
|
||||
data_offset = (uint16_t)(data_offset + this_len);
|
||||
}
|
||||
}
|
||||
|
||||
if (totalframe > 1u) {
|
||||
printf("wrap_raw split %uB -> %u frames, out %uB\n",
|
||||
(unsigned)payload_len, (unsigned)totalframe, (unsigned)offset);
|
||||
}
|
||||
|
||||
return (int)offset;
|
||||
}
|
||||
|
||||
int bleproto_appdata_deserialize(uint8_t * buf,
|
||||
|
||||
@@ -586,17 +586,21 @@ int bleproto_appdata_serialize(bleproto_appdata_t *appdata,
|
||||
uint16_t size);
|
||||
|
||||
/**
|
||||
* @brief 将已打包好的 payload 包装成单帧 appdata(不分包)
|
||||
* @param txbuf 输出缓冲
|
||||
* @brief 将已打包好的 payload 包装成 appdata(超过单帧则按 packetlen 分包)
|
||||
* @param txbuf 输出缓冲(须能放下 每帧8B头 × 帧数 + payload)
|
||||
* @param txbuf_size 输出缓冲大小
|
||||
* @param packetlen BLE GATT 单包有效长度,与 serialize 相同(本板 247)
|
||||
* @param header 应用层头(datalen/totalframe/frameseq 由本函数填写)
|
||||
* @param payload 已序列化的 service 数据;可为 NULL(payload_len==0)
|
||||
* @param payload_len payload 长度,须 <=255(单帧 pthis_frame_len 为 u8)
|
||||
* @param payload_len 应用数据总长度
|
||||
* @return >0 总字节数;<0 失败
|
||||
* @note 小包场景(JB 55AA 透传等)用此接口,避免 bleproto_appdata_t 大缓冲
|
||||
* @note 切帧规则与 serialize 一致:单帧 payload = packetlen - 8;
|
||||
* 不超过则 totalframe=1、frameseq=0;超过则中间帧填满、末帧剩余,
|
||||
* frameseq 从 1 递增。避免走 bleproto_appdata_t 大缓冲。
|
||||
*/
|
||||
int bleproto_appdata_wrap_raw(uint8_t *txbuf,
|
||||
uint16_t txbuf_size,
|
||||
uint8_t packetlen,
|
||||
const bleproto_appdata_header_t *header,
|
||||
const uint8_t *payload,
|
||||
uint16_t payload_len);
|
||||
|
||||
+39
-193
@@ -1,16 +1,15 @@
|
||||
/******************************************************************************
|
||||
* @file usr_le_adv.c
|
||||
* @brief BLE 广播 / 配对 / OTA 广播切换 + 自定义温湿度广播窗
|
||||
* @brief BLE 广播 / 配对 / OTA 广播切换
|
||||
* @author cyWu <1917507415@qq.com>
|
||||
* @date 2026.09.03
|
||||
* @version V1.2.0,新增「已绑定未连接」时的 1s 温湿度广播窗
|
||||
* @date 2026.09.07
|
||||
* @version V1.4.0,慢广播改由 BOARD_BLE_SLOW_ADV_ENABLE / SEC 控制
|
||||
* @history
|
||||
* - V1.4.0, 2026.09.07, cyWu, 常供电默认不切慢广播,秒数可配
|
||||
* - V1.0.0, 2026.08.03, cyWu, 首次发布
|
||||
* - V1.1.0, 2026.08.19, cyWu, 对齐模组注释与助手;保留 SOC 上电绑广播策略
|
||||
* - V1.2.0, 2026.09.03, cyWu, 已绑定+未连接+有缸体+本周期采样成功 → 发 1s
|
||||
* 自定义温湿度广播(3 段 AD:Flags / Complete Local Name / Manufacturer
|
||||
* 0xFFFF),随后切回见宝回连包。配置中/未配网/tank=0/采样失败/OTA/已连接
|
||||
* 不发。app_th 只置 pending,本文件(500ms 任务上下文)负责组包与切回。
|
||||
* - V1.2.0, 2026.09.03, cyWu, 已绑定未连接温湿度窗(随后拆出)
|
||||
* - V1.3.0, 2026.09.03, cyWu, 温湿度窗迁到 app_th_adv,本文件只留钩子
|
||||
******************************************************************************/
|
||||
|
||||
#include "system/includes.h"
|
||||
@@ -20,8 +19,9 @@
|
||||
#include "bleproto.h"
|
||||
#include "bleproto_api.h"
|
||||
#include "usr_le_product.h"
|
||||
#include "app_th.h"
|
||||
#include "app_linkage.h"
|
||||
#include "usr_le_api.h"
|
||||
#include "app_th_adv.h"
|
||||
#include "board_pin.h"
|
||||
|
||||
#define LOG_TAG_CONST APP
|
||||
#define LOG_TAG "[LE_ADV]"
|
||||
@@ -48,17 +48,7 @@
|
||||
* SOC 决策表(与模组不同:未配网也发绑定广播,便于上电配网):
|
||||
* usr_goto_pair==1 → 绑定广播
|
||||
* paired_flag==0 → 绑定广播
|
||||
* paired_flag==1 → 回连广播(可被下面的温湿度窗临时顶替 1s)
|
||||
*
|
||||
* 自定义温湿度广播窗(V1.2.0):
|
||||
* 同时满足「未连接 + paired_flag==1 + usr_goto_pair==0 + 非 OTA + tank_id!=0
|
||||
* + 本周期 AHT20 采样成功」→ 发 1s(500ms × 2 拍)自定义包,之后 encode4reconn
|
||||
* 切回见宝回连包。整包三段,按蓝牙 AD 结构 [Len][Type][Data…] 组:
|
||||
* 02 01 06
|
||||
* (1+n) 09 "JBao-<tank>"(tank 十进制无前导零)
|
||||
* 06 FF FF FF <ver> <temp int8> <humi uint8>
|
||||
* 这不是见宝 TLV,不用 encode4heartbeat;见宝回连仍用 encode4reconn。
|
||||
* 给 nRF 和以后自研扫描器看,GATT 0x2A00 / gap_device_name 不动。
|
||||
* paired_flag==1 → 回连广播(可被 app_th_adv 临时顶替 1s)
|
||||
******************************************************************************/
|
||||
|
||||
extern u8 muti_adv_data[31];
|
||||
@@ -66,27 +56,10 @@ extern u8 muti_adv_data_len;
|
||||
|
||||
/** 广播数据最大长度(BLE 4.x 31 字节) */
|
||||
#define USR_ADV_DATA_MAX 31
|
||||
/** 温湿度窗持续拍数:500ms × 2 = 1s */
|
||||
#define USR_TH_ADV_WINDOW_TICKS 2
|
||||
/** 温湿度窗内的快广播间隔(窗内暂停「60s 变慢广播」) */
|
||||
#define USR_TH_ADV_FAST_INTERVAL 80
|
||||
|
||||
/** AD Type:Flags(与见宝包一致) */
|
||||
#define USR_AD_TYPE_FLAGS 0x01
|
||||
/** AD Type:Complete Local Name */
|
||||
#define USR_AD_TYPE_LOCAL_NAME 0x09
|
||||
/** AD Type:Manufacturer Specific Data(禁止用 0x16 Service Data,那是见宝在用的) */
|
||||
#define USR_AD_TYPE_MANUFACTURER 0xFF
|
||||
|
||||
/** 温湿度窗状态:>0 = 窗进行中,值 = 剩余 500ms 拍数 */
|
||||
static u8 s_th_win_ticks = 0;
|
||||
/** 窗内提速前的广播间隔,0 = 进窗时本来就是快广播,出窗不还原 */
|
||||
static u16 s_th_win_interval = 0;
|
||||
|
||||
static void usr_adv_encode_reconn(void);
|
||||
static void usr_adv_encode_th(u16 tank, u8 ver, int16_t temp_x10, u8 humi);
|
||||
static void usr_th_adv_stop(u8 back_to_reconn);
|
||||
static void usr_th_adv_tick(void);
|
||||
#define USR_LE_ADV_TICK_MS 500u /* 与 sys_timer_add(usr_ble_adv_updata) 一致 */
|
||||
#if BOARD_BLE_SLOW_ADV_ENABLE
|
||||
#define USR_LE_SLOW_ADV_TICKS ((BOARD_BLE_SLOW_ADV_SEC * 1000u) / USR_LE_ADV_TICK_MS)
|
||||
#endif
|
||||
|
||||
/* 定义在 usr_le_recieve.c,库内共用,不对外导出 */
|
||||
extern bleproto_authsetup_req_t usr_auth_data;
|
||||
@@ -206,9 +179,8 @@ void usr_ble_adv_init(void)
|
||||
memcpy(prodcode, g_usr_le_prodcode, BLEPROTO_ADV_TLV_LENGTH_PRODCODE);
|
||||
memcpy(pcode, g_usr_le_pcode, BLE_PROTO_ADV_LENGTH_PCODE);
|
||||
|
||||
/* 广播策略重置:清掉温湿度窗(若有),间隔由本函数统一置 80 */
|
||||
s_th_win_ticks = 0;
|
||||
s_th_win_interval = 0;
|
||||
/* 产品温湿度窗清掉;间隔由本函数统一置 80 */
|
||||
app_th_adv_reset();
|
||||
|
||||
usr_set_adv_interval(80);
|
||||
if (usr_var.usr_ota_succ_flag)
|
||||
@@ -247,7 +219,7 @@ void usr_ble_adv_init(void)
|
||||
usr_ble_adv_updata();
|
||||
if (le_timer_handle == 0)
|
||||
{
|
||||
le_timer_handle = sys_timer_add(NULL, usr_ble_adv_updata, 500);
|
||||
le_timer_handle = sys_timer_add(NULL, usr_ble_adv_updata, USR_LE_ADV_TICK_MS);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,7 +237,7 @@ u8 usr_get_pair_flag(void)
|
||||
* @note 只组包并置 usr_adv_flag=1,真正下发由 usr_ble_adv_updata 完成
|
||||
* @return 无
|
||||
*/
|
||||
static void usr_adv_encode_reconn(void)
|
||||
void usr_ble_adv_encode_reconn(void)
|
||||
{
|
||||
uint8_t manucode[BLEPROTO_ADV_TLV_LENGTH_MANUCODE] = {0};
|
||||
uint8_t prodcode[BLEPROTO_ADV_TLV_LENGTH_PRODCODE];
|
||||
@@ -281,163 +253,33 @@ static void usr_adv_encode_reconn(void)
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 组自定义温湿度广播包(三段 AD,非见宝 TLV,给 nRF/自研扫描器)
|
||||
* @note 整包:02 01 06 / (1+n) 09 "JBao-<tank>" / 06 FF FF FF ver T H
|
||||
* Company ID 0xFFFF 小端;温度 int8 ℃(向 0 取整,钳位 [-128,127]);
|
||||
* 湿度 uint8 %。不动 GATT 0x2A00 / gap_device_name。
|
||||
* @param tank 缸体编号(非 0)
|
||||
* @param ver 配置版本(linkage_config[6])
|
||||
* @param temp_x10 温度 ×10
|
||||
* @param humi 湿度 %
|
||||
* @brief 用调用方组好的 AD 覆盖广播 payload
|
||||
* @param data 广播数据
|
||||
* @param len 长度(1~31)
|
||||
* @return 无
|
||||
*/
|
||||
static void usr_adv_encode_th(u16 tank, u8 ver, int16_t temp_x10, u8 humi)
|
||||
void usr_ble_adv_set_raw(const uint8_t *data, uint8_t len)
|
||||
{
|
||||
u8 *p = muti_adv_data;
|
||||
char dec[5];
|
||||
u8 digits = 0;
|
||||
u16 v = tank;
|
||||
int32_t t_int;
|
||||
u8 name_len;
|
||||
|
||||
/* 段1 Flags(与见宝一致) */
|
||||
*p++ = 0x02;
|
||||
*p++ = USR_AD_TYPE_FLAGS;
|
||||
*p++ = 0x06;
|
||||
|
||||
/* 段2 Complete Local Name "JBao-<tank 十进制无前导零>" */
|
||||
while (v) {
|
||||
dec[digits++] = (char)('0' + (v % 10));
|
||||
v /= 10;
|
||||
if (!data || (len == 0) || (len > USR_ADV_DATA_MAX)) {
|
||||
return;
|
||||
}
|
||||
name_len = (u8)(5 + digits); /* "JBao-" + tank 位数 */
|
||||
*p++ = (u8)(1 + name_len); /* AD Length = Type(1) + Data */
|
||||
*p++ = USR_AD_TYPE_LOCAL_NAME;
|
||||
*p++ = 'J';
|
||||
*p++ = 'B';
|
||||
*p++ = 'a';
|
||||
*p++ = 'o';
|
||||
*p++ = '-';
|
||||
while (digits) {
|
||||
*p++ = (u8)dec[--digits]; /* 反序数组正序发 → 高位在前 */
|
||||
}
|
||||
|
||||
/* 段3 Manufacturer Specific:Company 0xFFFF(小端) + ver + T(int8) + H */
|
||||
t_int = temp_x10 / 10; /* C 整除即向 0 取整 */
|
||||
if (t_int < -128) {
|
||||
t_int = -128;
|
||||
}
|
||||
if (t_int > 127) {
|
||||
t_int = 127;
|
||||
}
|
||||
if (humi > 100) {
|
||||
humi = 100;
|
||||
}
|
||||
*p++ = 0x06; /* Type(1) + Company(2) + ver/T/H(3) */
|
||||
*p++ = USR_AD_TYPE_MANUFACTURER;
|
||||
*p++ = 0xFF; /* Company ID 0xFFFF 低字节 */
|
||||
*p++ = 0xFF; /* Company ID 0xFFFF 高字节 */
|
||||
*p++ = ver;
|
||||
*p++ = (u8)t_int;
|
||||
*p++ = humi;
|
||||
|
||||
muti_adv_data_len = (u8)(p - muti_adv_data);
|
||||
memcpy(muti_adv_data, data, len);
|
||||
muti_adv_data_len = len;
|
||||
usr_var.usr_adv_flag = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 结束温湿度窗:还原广播间隔,可选切回见宝回连包
|
||||
* @param back_to_reconn 1=组回连包(窗自然到期用);
|
||||
* 0=只清窗(配对/OTA/连接切换时包由各自流程组)
|
||||
* @return 无
|
||||
*/
|
||||
static void usr_th_adv_stop(u8 back_to_reconn)
|
||||
{
|
||||
if (s_th_win_ticks == 0) {
|
||||
return;
|
||||
}
|
||||
s_th_win_ticks = 0;
|
||||
if (s_th_win_interval != 0) {
|
||||
/* 进窗前是慢广播 → 还原;进窗前本来就是快广播则不还原 */
|
||||
usr_set_adv_interval(s_th_win_interval);
|
||||
s_th_win_interval = 0;
|
||||
}
|
||||
if (back_to_reconn) {
|
||||
usr_adv_encode_reconn();
|
||||
log_info("th adv win end, back to reconn\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 温湿度窗状态机(usr_ble_adv_updata 500ms 拍,任务上下文)
|
||||
* @note 进窗条件同时满足:未连接 + paired_flag==1 + 非配对 + 非 OTA +
|
||||
* tank_id!=0 + 本周期 AHT20 采样成功(take 到的才是本次新值)。
|
||||
* 窗长 500ms × 2;窗内再来采样成功 → 刷新段 3 并重计 2 拍。
|
||||
* ⚠ app_th 中断侧只置 pending,本函数是唯一消费者。
|
||||
* @return 无
|
||||
*/
|
||||
static void usr_th_adv_tick(void)
|
||||
{
|
||||
int16_t t_x10 = 0;
|
||||
u8 humi = 0;
|
||||
u8 got;
|
||||
u16 tank;
|
||||
|
||||
/* 窗进行中:先处理强制结束(配对 / OTA / 连接切换 / 清配网) */
|
||||
if (s_th_win_ticks) {
|
||||
if (usr_ble_is_connected() || usr_var.usr_goto_pair ||
|
||||
(usr_auth_data.paired_flag == 0) || usr_var.usr_goto_updata ||
|
||||
usr_var.usr_ota_succ_flag) {
|
||||
usr_th_adv_stop(0);
|
||||
} else if (s_th_win_ticks > 1) {
|
||||
s_th_win_ticks--;
|
||||
} else {
|
||||
/* 最后一拍:必须先 stop(里头要求 ticks!=0),再组回连包。
|
||||
* 若先减成 0 再 stop,会被 if (ticks==0) return 直接丢掉回连。 */
|
||||
usr_th_adv_stop(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (usr_ble_is_connected() || usr_var.usr_goto_pair ||
|
||||
(usr_auth_data.paired_flag == 0) || usr_var.usr_goto_updata ||
|
||||
usr_var.usr_ota_succ_flag) {
|
||||
return;
|
||||
}
|
||||
|
||||
got = app_th_take_sample(&t_x10, &humi);
|
||||
if (!got) {
|
||||
return;
|
||||
}
|
||||
|
||||
tank = app_linkage_get_tank_id();
|
||||
if (tank == 0) {
|
||||
/* 未配缸体:一直回连,不发温湿度窗 */
|
||||
return;
|
||||
}
|
||||
|
||||
if (s_th_win_ticks == 0) {
|
||||
/* 进窗:记下当前间隔并提速(窗内暂停「60s 变慢广播」) */
|
||||
s_th_win_interval = (usr_get_adv_interval() != USR_TH_ADV_FAST_INTERVAL) ?
|
||||
usr_get_adv_interval() : 0;
|
||||
usr_set_adv_interval(USR_TH_ADV_FAST_INTERVAL);
|
||||
}
|
||||
/* 进窗 / 窗内刷新:组包(usr_adv_flag=1,下一行刷新块立即下发) */
|
||||
usr_adv_encode_th(tank, app_linkage_get_cfg_ver(), t_x10, humi);
|
||||
s_th_win_ticks = USR_TH_ADV_WINDOW_TICKS;
|
||||
log_info("th adv: tank=%u ver=%u T=%dC H=%u%%\n",
|
||||
tank, app_linkage_get_cfg_ver(), (int)(t_x10 / 10), humi);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 周期处理广播刷新(由 500ms 定时器调用)
|
||||
* @note 仅当 usr_adv_flag==1 时:停广播 → 写入 muti_adv_data → 再开广播
|
||||
*/
|
||||
void usr_ble_adv_updata(void)
|
||||
{
|
||||
#if BOARD_BLE_SLOW_ADV_ENABLE
|
||||
static u16 usr_goto_slow_adv = 0;
|
||||
#endif
|
||||
|
||||
/* 温湿度窗状态机:先于广播刷新执行,进/出窗当拍立即生效 */
|
||||
usr_th_adv_tick();
|
||||
/* 产品温湿度窗:须先于广播刷新,进/出窗当拍立即生效 */
|
||||
app_th_adv_tick();
|
||||
|
||||
if (usr_var.usr_adv_flag)
|
||||
{
|
||||
@@ -449,24 +291,27 @@ void usr_ble_adv_updata(void)
|
||||
ble_trans_module_enable(1);
|
||||
}
|
||||
|
||||
#if BOARD_BLE_SLOW_ADV_ENABLE
|
||||
if (!usr_ble_is_connected())
|
||||
{
|
||||
/* 未连接:回连快广播(80)持续约 60s(500ms×120)后切慢广播
|
||||
* 温湿度窗内暂停计数(窗内强制快广播,窗长 1s) */
|
||||
/* 未连接:回连快广播(80)持续 BOARD_BLE_SLOW_ADV_SEC 后切慢广播(800)
|
||||
* 温湿度窗内暂停计数(窗内强制快广播) */
|
||||
if (usr_get_adv_interval() == 80)
|
||||
{
|
||||
if ((usr_var.usr_goto_pair == 0) && usr_auth_data.paired_flag)
|
||||
{
|
||||
if ((usr_var.usr_ota_succ_flag == 0) && (s_th_win_ticks == 0))
|
||||
if ((usr_var.usr_ota_succ_flag == 0) && (app_th_adv_is_active() == 0))
|
||||
{
|
||||
usr_goto_slow_adv++;
|
||||
printf("usr_goto_slow_adv = %d\n", usr_goto_slow_adv);
|
||||
}
|
||||
if (usr_goto_slow_adv >= 120)
|
||||
if ((USR_LE_SLOW_ADV_TICKS > 0) &&
|
||||
(usr_goto_slow_adv >= USR_LE_SLOW_ADV_TICKS))
|
||||
{
|
||||
usr_goto_slow_adv = 0;
|
||||
usr_set_adv_interval(80 * 10);
|
||||
usr_var.usr_adv_flag = 1;
|
||||
printf("ble switch slow adv, after %us\n",
|
||||
(unsigned)BOARD_BLE_SLOW_ADV_SEC);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -479,6 +324,7 @@ void usr_ble_adv_updata(void)
|
||||
{
|
||||
usr_goto_slow_adv = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (usr_get_ota_status() == 0)
|
||||
{
|
||||
|
||||
@@ -49,6 +49,25 @@ uint8_t usr_get_pair_flag(void);
|
||||
*/
|
||||
void usr_app_ota_init(void);
|
||||
|
||||
/**
|
||||
* @brief BLE 是否已连接
|
||||
* @return 1=已连接,0=未连接
|
||||
*/
|
||||
uint8_t usr_ble_is_connected(void);
|
||||
|
||||
/**
|
||||
* @brief 组见宝回连广播包并标记下一拍下发
|
||||
* @note 只组包,真正写入协议栈由 usr_ble_adv_updata 完成
|
||||
*/
|
||||
void usr_ble_adv_encode_reconn(void);
|
||||
|
||||
/**
|
||||
* @brief 用调用方组好的 AD 覆盖广播 payload 并标记下一拍下发
|
||||
* @param data 广播数据(最长 31 字节)
|
||||
* @param len 长度
|
||||
*/
|
||||
void usr_ble_adv_set_raw(const uint8_t *data, uint8_t len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -2,11 +2,12 @@
|
||||
* @file usr_le_recieve.c
|
||||
* @brief BLE 收包入口:bleproto 解析后分发配网 / 对时 / JB 协议 / 组应答
|
||||
* @author cyWu <1917507415@qq.com>
|
||||
* @date 2026.08.19
|
||||
* @version V1.1.0
|
||||
* @date 2026.09.07
|
||||
* @version V1.2.0
|
||||
* @history
|
||||
* - V1.0.0, 2026.08.03, cyWu, 首次发布
|
||||
* - V1.1.0, 2026.08.19, cyWu, 对齐模组结构;废弃 JSON OTA;修 AUTHDELETE serviceid
|
||||
* - V1.2.0, 2026.09.07, cyWu, JB 上报超 255 走 wrap_raw 自动分包;加大 txbuf
|
||||
******************************************************************************/
|
||||
|
||||
#include "system/includes.h"
|
||||
@@ -27,15 +28,21 @@
|
||||
#define LOG_INFO_ENABLE
|
||||
#include "debug.h"
|
||||
|
||||
/* 拼 GATT 分包:业务包 ≈ bleproto头 + V2 开销 + JB 帧(<=128),1024 足够 */
|
||||
/* 收:GATT 拼包缓冲。发:V2 + bleproto 多帧(单帧总长 247,与 ATT 对齐) */
|
||||
#define USR_LE_RX_BUF_LEN 1024
|
||||
#define USR_LE_V2_WRAP_OVERHEAD 32u /* V2 头开销,JB 帧最大 128 → 约 160 */
|
||||
#define USR_LE_V2_WRAP_OVERHEAD 32u /* V2 头开销 */
|
||||
#define USR_LE_V2_MAX_LEN (512u + USR_LE_V2_WRAP_OVERHEAD)
|
||||
#define USR_LE_APPDATA_PACKETLEN 247u /* 对齐 ATT_LOCAL_PAYLOAD_SIZE:8B头+239B数据 */
|
||||
#define USR_LE_APPDATA_FRAME_PAYLOAD (USR_LE_APPDATA_PACKETLEN - 8u)
|
||||
#define USR_LE_TX_BUF_LEN (USR_LE_V2_MAX_LEN + \
|
||||
8u * ((USR_LE_V2_MAX_LEN + USR_LE_APPDATA_FRAME_PAYLOAD - 1u) / \
|
||||
USR_LE_APPDATA_FRAME_PAYLOAD))
|
||||
#define USR_LE_V2_CMD_REPORT 100u /* REPORTCMD_V2 内层 cmd */
|
||||
#define USR_LE_V2_CMD_RUN 110u /* RUNCMD_V2 内层 cmd */
|
||||
#define USR_LE_JB_CMD_OFF 4u /* 55 AA | LEN_H LEN_L | CMD */
|
||||
|
||||
static int encode_len = 0;
|
||||
static u8 txbuf[384] = {0};
|
||||
static u8 txbuf[USR_LE_TX_BUF_LEN];
|
||||
static u8 rxbuf[USR_LE_RX_BUF_LEN] = {0};
|
||||
static u8 s_last_runcmd_msgid = 0; /* RUNCMD_V2 应答须回填最近 msgid */
|
||||
|
||||
@@ -75,7 +82,7 @@ static void usr_le_fill_rsp_header(bleproto_appdata_desc_t *out,
|
||||
*/
|
||||
static void usr_le_encode_and_send(bleproto_appdata_desc_t *desc)
|
||||
{
|
||||
encode_len = bleproto_appdata_encode(txbuf, sizeof(txbuf), sizeof(txbuf), desc);
|
||||
encode_len = bleproto_appdata_encode(txbuf, sizeof(txbuf),USR_LE_APPDATA_PACKETLEN, desc);
|
||||
if (encode_len > 0)
|
||||
{
|
||||
printf("encode_len = %d\n", encode_len);
|
||||
@@ -365,7 +372,8 @@ void ble_send_data(u8 *data, u16 len)
|
||||
return;
|
||||
}
|
||||
|
||||
elen = bleproto_appdata_wrap_raw(txbuf, sizeof(txbuf), &hdr, v2_buf, (uint16_t)plen);
|
||||
elen = bleproto_appdata_wrap_raw(txbuf, sizeof(txbuf), USR_LE_APPDATA_PACKETLEN,
|
||||
&hdr, v2_buf, (uint16_t)plen);
|
||||
printf("ble_send_data jb_cmd=0x%02X active=%d encode_len=%d msgid=%d\n",
|
||||
jb_cmd, is_active_send, elen, hdr.msgid);
|
||||
if (elen <= 0)
|
||||
|
||||
@@ -2,8 +2,11 @@
|
||||
* @file board_pin.h
|
||||
* @brief CBR3 温湿度风扇板级引脚、电平与时序(换板只改本文件)
|
||||
* @author cyWu <1917507415@qq.com>
|
||||
* @date 2026.08.29
|
||||
* @version V1.0.0,首次发布(P0 Bring-up)
|
||||
* @date 2026.09.04
|
||||
* @version V1.1.0,数码管转机 180°(BOARD_DISP_ROTATE_180)
|
||||
* @history
|
||||
* - V1.1.0, 2026.09.04, cyWu, 转机后温湿窗口/十个位对调 + 段码旋转
|
||||
* - V1.0.0, 2026.08.29, cyWu, 首次发布(P0 Bring-up)
|
||||
*
|
||||
* @note 产品 GPIO 全部集中到本文件;板级 board_jl701n_demo_cfg.h 只保留
|
||||
* UART0_TX=PG6 一项改动。CT1642 用 PG0(CLK)/PG1(DATA),AHT20 用
|
||||
@@ -32,6 +35,18 @@
|
||||
#define BOARD_RUNREC_ENABLE 1 /* 31 天运行记录;P2 开 */
|
||||
#define BOARD_NVM_ENABLE 1 /* VM 持久化;P1 开 */
|
||||
|
||||
/*============================================================================*/
|
||||
/* BLE 广播 */
|
||||
/*============================================================================*/
|
||||
|
||||
/**
|
||||
* 未连接回连快广播(间隔 80)超时后是否切慢广播(间隔 800)。
|
||||
* 本机常供电,默认 0:一直快广播,方便网关回连。
|
||||
* 1=使能;超时秒数见 BOARD_BLE_SLOW_ADV_SEC(usr_ble_adv_updata 每 500ms 计一次)。
|
||||
*/
|
||||
#define BOARD_BLE_SLOW_ADV_ENABLE 0
|
||||
#define BOARD_BLE_SLOW_ADV_SEC 60 /**< 使能为 1 时:快广播持续秒数后再切慢广播 */
|
||||
|
||||
/*============================================================================*/
|
||||
/* GPIO */
|
||||
/*============================================================================*/
|
||||
@@ -126,11 +141,26 @@
|
||||
* (bit0 先发 → 落到 Q2 引脚;PCB 上 Q2 接哪段即"软件 A 段"对应的物理段)
|
||||
* COM 位选 → 物理管位映射(2026-08-29 SCAN_TEST=2 实测定型):
|
||||
* C1=湿度十位 C2=湿度个位 C3=温度十位 C4=温度个位(默认假定温/湿相反,已对调)
|
||||
*
|
||||
* 转机 180°(2026-09-04):整板相对窗口旋转后,视觉上
|
||||
* ① 每只管子倒过来:A↔D、B↔E、C↔F,G/DP 不动(段码在 bsp_ct1642_send_frame 里重映射)
|
||||
* ② 温/湿窗口对调,且十位/个位左右对调。
|
||||
* 未改软件时典型现象:25/57 会看成「L5 / 52」(7 倒过来像 L)。
|
||||
* 0 = 旧板方向;1 = 转机后的量产方向。
|
||||
*/
|
||||
#define BOARD_DISP_ROTATE_180 1
|
||||
|
||||
#if BOARD_DISP_ROTATE_180
|
||||
#define BOARD_DISP_COM_TEMP_TEN 0x02 /**< C2:转机后落到温度十位 */
|
||||
#define BOARD_DISP_COM_TEMP_ONE 0x01 /**< C1:转机后落到温度个位 */
|
||||
#define BOARD_DISP_COM_HUMI_TEN 0x08 /**< C4:转机后落到湿度十位 */
|
||||
#define BOARD_DISP_COM_HUMI_ONE 0x04 /**< C3:转机后落到湿度个位 */
|
||||
#else
|
||||
#define BOARD_DISP_COM_TEMP_TEN 0x04 /**< C3 = 温度十位(实测定型) */
|
||||
#define BOARD_DISP_COM_TEMP_ONE 0x08 /**< C4 = 温度个位(实测定型) */
|
||||
#define BOARD_DISP_COM_HUMI_TEN 0x01 /**< C1 = 湿度十位(实测定型) */
|
||||
#define BOARD_DISP_COM_HUMI_ONE 0x02 /**< C2 = 湿度个位(实测定型) */
|
||||
#endif
|
||||
|
||||
/**
|
||||
* 扫段调试模式(P0 台上定型用,2026-08-29 已全部定型,正常固件保持 0):
|
||||
|
||||
@@ -2,8 +2,11 @@
|
||||
* @file bsp_ct1642.c
|
||||
* @brief CBR3 CT1642 类数码管驱动实现(软件移位)
|
||||
* @author cyWu <1917507415@qq.com>
|
||||
* @date 2026.08.29
|
||||
* @version V1.0.1,IO 分离:CT1642 独立 PG0=CLK/PG1=DATA,无总线共享机制
|
||||
* @date 2026.09.04
|
||||
* @version V1.1.0,转机 180°:段码 A↔D/B↔E/C↔F(BOARD_DISP_ROTATE_180)
|
||||
* @history
|
||||
* - V1.1.0, 2026.09.04, cyWu, 数码管整板旋转 180° 后补偿段码
|
||||
* - V1.0.1, 2026.08.29, cyWu, IO 分离:CT1642 独立 PG0=CLK/PG1=DATA
|
||||
*
|
||||
* @note 驱动协议严格参照 CT1642 手册(与 CSDN yitx 一致):
|
||||
* 一帧 = 18bit,CLK 上升沿采样 DATA(DATA 只在 CLK=低时改变):
|
||||
@@ -143,6 +146,10 @@ static void ct1642_xfer(uint8_t seg, uint8_t com)
|
||||
*/
|
||||
void bsp_ct1642_send_frame(uint8_t seg, uint8_t com)
|
||||
{
|
||||
#if BOARD_DISP_ROTATE_180
|
||||
/* 管倒过来看:视觉 A/B/C 落在物理 D/E/F,视觉 D/E/F 落在物理 A/B/C;G/DP 不动 */
|
||||
seg = (uint8_t)(((seg & 0x07u) << 3) | ((seg & 0x38u) >> 3) | (seg & 0xC0u));
|
||||
#endif
|
||||
// ct1642_xfer(0, 0);
|
||||
ct1642_xfer(seg, com); /* 单帧:18bit 移位 + 锁存 + 输出,无消影预帧 */
|
||||
}
|
||||
|
||||
@@ -2,8 +2,11 @@
|
||||
* @file bsp_ct1642.h
|
||||
* @brief CBR3 CT1642 类数码管驱动:18bit 移位、锁存、送出
|
||||
* @author cyWu <1917507415@qq.com>
|
||||
* @date 2026.08.29
|
||||
* @version V1.0.1,IO 分离:CT1642 独立 PG0=CLK/PG1=DATA(飞线),AHT20
|
||||
* @date 2026.09.04
|
||||
* @version V1.1.0,转机 180° 段码补偿(见 BOARD_DISP_ROTATE_180)
|
||||
* @history
|
||||
* - V1.1.0, 2026.09.04, cyWu, send_frame 内按宏做 A↔D/B↔E/C↔F
|
||||
* - V1.0.1, 2026.08.29, cyWu, IO 分离:CT1642 独立 PG0=CLK/PG1=DATA(飞线),AHT20
|
||||
* 独占 PC4/PC5,无总线共享机制
|
||||
*
|
||||
* @note PG0=CLK,PG1=DATA,独立引脚、无总线锁,可随时调用。
|
||||
|
||||
+18
-18
@@ -106,7 +106,7 @@
|
||||
"values": {}
|
||||
},
|
||||
{
|
||||
"id": 13,
|
||||
"id": 7,
|
||||
"display_name": "定时使能",
|
||||
"key": "time_en",
|
||||
"kind": "normal",
|
||||
@@ -121,7 +121,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 14,
|
||||
"id": 8,
|
||||
"display_name": "定时配置1",
|
||||
"key": "time_config1",
|
||||
"kind": "normal",
|
||||
@@ -133,7 +133,7 @@
|
||||
"values": {}
|
||||
},
|
||||
{
|
||||
"id": 15,
|
||||
"id": 9,
|
||||
"display_name": "定时配置2",
|
||||
"key": "time_config2",
|
||||
"kind": "normal",
|
||||
@@ -145,7 +145,7 @@
|
||||
"values": {}
|
||||
},
|
||||
{
|
||||
"id": 16,
|
||||
"id": 10,
|
||||
"display_name": "定时配置3",
|
||||
"key": "time_config3",
|
||||
"kind": "normal",
|
||||
@@ -157,7 +157,7 @@
|
||||
"values": {}
|
||||
},
|
||||
{
|
||||
"id": 17,
|
||||
"id": 11,
|
||||
"display_name": "定时配置4",
|
||||
"key": "time_config4",
|
||||
"kind": "normal",
|
||||
@@ -169,7 +169,7 @@
|
||||
"values": {}
|
||||
},
|
||||
{
|
||||
"id": 18,
|
||||
"id": 12,
|
||||
"display_name": "定时配置5",
|
||||
"key": "time_config5",
|
||||
"kind": "normal",
|
||||
@@ -181,7 +181,7 @@
|
||||
"values": {}
|
||||
},
|
||||
{
|
||||
"id": 19,
|
||||
"id": 13,
|
||||
"display_name": "定时配置6",
|
||||
"key": "time_config6",
|
||||
"kind": "normal",
|
||||
@@ -193,7 +193,7 @@
|
||||
"values": {}
|
||||
},
|
||||
{
|
||||
"id": 20,
|
||||
"id": 14,
|
||||
"display_name": "定时配置7",
|
||||
"key": "time_config7",
|
||||
"kind": "normal",
|
||||
@@ -205,7 +205,7 @@
|
||||
"values": {}
|
||||
},
|
||||
{
|
||||
"id": 21,
|
||||
"id": 15,
|
||||
"display_name": "运行记录",
|
||||
"key": "run_record",
|
||||
"kind": "normal",
|
||||
@@ -217,7 +217,7 @@
|
||||
"values": {}
|
||||
},
|
||||
{
|
||||
"id": 22,
|
||||
"id": 16,
|
||||
"display_name": "心跳",
|
||||
"key": "heartbeat",
|
||||
"kind": "normal",
|
||||
@@ -232,7 +232,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 23,
|
||||
"id": 17,
|
||||
"display_name": "设备故障使能",
|
||||
"key": "fault_en",
|
||||
"kind": "normal",
|
||||
@@ -244,7 +244,7 @@
|
||||
"values": {}
|
||||
},
|
||||
{
|
||||
"id": 24,
|
||||
"id": 18,
|
||||
"display_name": "设备故障",
|
||||
"key": "fault_code",
|
||||
"kind": "fault",
|
||||
@@ -261,7 +261,7 @@
|
||||
"level": 2
|
||||
},
|
||||
{
|
||||
"id": 25,
|
||||
"id": 19,
|
||||
"display_name": "设备告警使能",
|
||||
"key": "alarm_en",
|
||||
"kind": "normal",
|
||||
@@ -273,7 +273,7 @@
|
||||
"values": {}
|
||||
},
|
||||
{
|
||||
"id": 26,
|
||||
"id": 20,
|
||||
"display_name": "设备告警",
|
||||
"key": "alarm_code",
|
||||
"kind": "alarm",
|
||||
@@ -286,7 +286,7 @@
|
||||
"level": 1
|
||||
},
|
||||
{
|
||||
"id": 27,
|
||||
"id": 21,
|
||||
"display_name": "恢复出厂设置",
|
||||
"key": "factory_reset",
|
||||
"kind": "normal",
|
||||
@@ -300,7 +300,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 28,
|
||||
"id": 22,
|
||||
"display_name": "预留DP1",
|
||||
"key": "reserva_dp1",
|
||||
"kind": "normal",
|
||||
@@ -312,7 +312,7 @@
|
||||
"values": {}
|
||||
},
|
||||
{
|
||||
"id": 29,
|
||||
"id": 23,
|
||||
"display_name": "预留DP2",
|
||||
"key": "reserva_dp2",
|
||||
"kind": "normal",
|
||||
@@ -324,7 +324,7 @@
|
||||
"values": {}
|
||||
},
|
||||
{
|
||||
"id": 30,
|
||||
"id": 24,
|
||||
"display_name": "预留DP3",
|
||||
"key": "reserva_dp3",
|
||||
"kind": "normal",
|
||||
|
||||
Reference in New Issue
Block a user