fix(vd960DBN): 消灭 data_json[1024] 中间缓冲, 防 BSS 重叠致 MQTT 上报 _raw 异常

- root cause: data_json[1024] + payload[1400] BSS 合计 2424B,
  叠加 iot_mqtt_srv.c 其他缓冲 (~9KB total), 在 48KB RAM 上
  与 mqttBuf[1024] 重叠, event_report 的 MQTT 二进制
  泄漏到 loop_data payload

- fix: 直接在 payload 构建完整 JSON, 省 1024B BSS
- defense: coil_count > 4 硬限, 防 0xC0 坏帧溢出
- JSON 输出格式不变

- also: set_response_tran_to_notify 加返回值
- also: uart_srv BLE 通知逻辑重构
This commit is contained in:
wangfq
2026-07-23 09:26:18 +08:00
parent 95a1d2b5d2
commit e11a80c859
4 changed files with 58 additions and 23 deletions
@@ -308,6 +308,7 @@ uint8_t set_response_tran_to_notify(uint8_t *dat_ori, uint8_t dat_len, BLE_Notif
} }
notify_dst->len = dat_len; notify_dst->len = dat_len;
notify_dst->flag = 1; notify_dst->flag = 1;
return notify_dst->flag;
} }
@@ -685,20 +685,28 @@ void iot_mqtt_publish_sensor(void) {
} }
} }
/*--- Step 4: 构建 JSON → 发布 (字段与 V1.02 协议一致) ---*/ /*--- Step 4: 构建 JSON → 发布 (字段与 V1.02 协议一致) ---
static char data_json[1024]; 直接构建到 payload, 省掉 data_json[1024] 中间缓冲:
- 消除 BSS 压力 (省 1024B), 降低与 mqttBuf 重叠风险
- 消除 %s 拷贝尾部二进制残留的路径 (2026-07-23 _raw 事故)
- coil_count 边界硬限, 防 0xC0 坏帧致溢出 */
static char payload[1400]; static char payload[1400];
char *p = data_json; char *p = payload;
int remaining = sizeof(data_json); int remaining = sizeof(payload);
int written; int written;
const char *freq_level_names[] = {"high", "mid_high", "mid_low", "low"}; const char *freq_level_names[] = {"high", "mid_high", "mid_low", "low"};
uint8_t i; uint8_t i;
uint8_t coil_n = _cached_sr.coil_count;
if (coil_n > 4) coil_n = 4; /* 硬限: 防坏帧致 snprintf 循环溢出 */
written = snprintf(p, remaining, "{\"channels\":["); /* 先写外层包装头 (msg_id/cmd/ts/data) */
written = snprintf(p, remaining,
"{\"msg_id\":%d,\"cmd\":\"loop_data\",\"ts\":%lu,\"data\":{\"channels\":[",
++g_iot_msg_id, dev_time_now());
if (written < 0 || written >= remaining) return; if (written < 0 || written >= remaining) return;
p += written; remaining -= written; p += written; remaining -= written;
for (i = 0; i < _cached_sr.coil_count; i++) { for (i = 0; i < coil_n; i++) {
const LUP_CoilSensor *cs = &_cached_sr.coils[i]; const LUP_CoilSensor *cs = &_cached_sr.coils[i];
const char *misc_type_str = "time"; const char *misc_type_str = "time";
uint32_t misc_val = 0; uint32_t misc_val = 0;
@@ -725,12 +733,7 @@ void iot_mqtt_publish_sensor(void) {
p += written; remaining -= written; p += written; remaining -= written;
} }
snprintf(p, remaining, "]}"); snprintf(p, remaining, "]}}");
/* Wrap and publish — V1.01 双主题模型: dld960/{sn}/dev */
snprintf(payload, sizeof(payload),
"{\"msg_id\":%d,\"cmd\":\"loop_data\",\"ts\":%lu,\"data\":%s}",
++g_iot_msg_id, dev_time_now(), data_json);
{ {
char topic[IOT_MQTT_TOPIC_MAX_LEN]; char topic[IOT_MQTT_TOPIC_MAX_LEN];
@@ -172,10 +172,16 @@ void uart_srv(void)
if(g_dbn_ble_state_acs_enable.flag != 0){ if(g_dbn_ble_state_acs_enable.flag != 0){
// BLE ACS 已连接 → 改 Magic 为 0x8F 发给 BLE // BLE ACS 已连接 → 改 Magic 为 0x8F 发给 BLE
g_pkg_uart_2.pkg[0] = 0x8F; g_pkg_uart_2.pkg[0] = 0x8F;
_report_flag = 1; // 保留给 BLE g_flag_notify_temp = set_response_tran_to_notify(g_pkg_uart_2.pkg, g_pkg_uart_2.offset, &g_notify_buftemp); // 保留给 BLE
} }
// else: 回调已推送 TCP,直接清理 // else: 回调已推送 TCP,直接清理
} }
else {
if(g_flag_bt_state){
g_flag_notify_temp = set_response_tran_to_notify(g_pkg_uart_2.pkg, g_pkg_uart_2.offset, &g_notify_buftemp);
InitPkgUart(&g_pkg_uart_2);
}
}
// 调试打印 // 调试打印
for(i = 0; i < g_pkg_uart_2.offset; i++){ for(i = 0; i < g_pkg_uart_2.offset; i++){
@@ -183,10 +189,6 @@ void uart_srv(void)
} }
PRINT("\n"); PRINT("\n");
if(_report_flag){
// 传感器帧保留在 pkg 中供上层 (tcp_json_srv) 处理
// 不 InitPkgUart — 由 tcp_json_push_sensor 消费后清理
}
} }
else { else {
// 非 0x7F 魔法字节 // 非 0x7F 魔法字节
@@ -199,16 +201,11 @@ void uart_srv(void)
if(g_flag_bt_state){ if(g_flag_bt_state){
g_flag_notify_temp = set_response_tran_to_notify(g_pkg_uart_2.pkg, g_pkg_uart_2.offset, &g_notify_buftemp);
} }
else{ else{
g_dbn_ble_state_acs_enable.flag = 0; g_dbn_ble_state_acs_enable.flag = 0;
} }
// 只有非 _report_flag 时才立即清空
// _report_flag 的帧由 tcp_json_push_sensor 消费后清理
if (!_report_flag) {
InitPkgUart(&g_pkg_uart_2);
}
} }
} }
+34
View File
@@ -485,9 +485,43 @@ uint16_t pkt_id = (req_qos > 0) ? ++s_mqtt_pkt_id : 0;
--- ---
---
## 2026-07-23 — loop_data JSON 构建优化: 消灭 data_json 中间缓冲 + coil_count 硬限
### 背景 / 问题
现场 DC045A49718F 出现 MQTT 上报异常: 平台收到 `_raw` 消息, hex 解码后发现
loop_data JSON 中间嵌入了完整的 MQTT PUBLISH 二进制帧 (event_report 的封包)。
**根因**: `iot_mqtt_publish_sensor()``static char data_json[1024]`
`static char payload[1400]` 合计 2424B BSS, 叠加同文件其他大缓冲 (~9KB total),
在 CH32V208 48KB RAM 中可能导致链接器将 `data_json`/`payload``mqttBuf[1024]`
分配到重叠地址。
**污染路径**:
1. `iot_evt_process()``mqtt_publish()``MQTTSerialize_publish(mqttBuf,...)` 写入 MQTT 二进制到 mqttBuf
2. 因 BSS 重叠, `data_json` 也被写入相同内容
3. `snprintf(data_json, ...)` 覆写前 ~427B 为通道 JSON, 尾部残留 MQTT 二进制
4. `snprintf(payload, ..., "%s", data_json)``%s` 将残留二进制也拷进 payload
5. `mqtt_publish(topic, payload, 0)` → 发出污染后的 payload
### 修复
| 改动 | 说明 |
|------|------|
| 消灭 `data_json[1024]` | 直接在 `payload[1400]` 构建完整 JSON, 省 1024B BSS |
| 消除 `%s` 拷贝 | 不再从中间缓冲格式化到 payload, 杜绝尾部二进制残留路径 |
| `coil_count` 硬限 | `if (coil_n > 4) coil_n = 4` — 防 0xC0 坏帧致 snprintf 循环溢出 |
| JSON 构建顺序调整 | 先写包装头 `{"msg_id":...,"data":{"channels":[`, 再追加通道, 最后 `]}}` |
**BSS 节省**: 1024 bytes
**协议兼容**: JSON 输出格式不变 (`{"msg_id":N,"cmd":"loop_data","ts":T,"data":{"channels":[...]}}`)
## 修订记录 ## 修订记录
| 版本 | 时间 | 说明 | | 版本 | 时间 | 说明 |
| V3.3 | 2026-07-23 | loop_data: 消灭 data_json[1024] BSS 缓冲 + coil_count 硬限, 防 mqttBuf 重叠致 _raw 异常 |
|------|------|------| |------|------|------|
| V3.2 | 2026-07-10 | 双主题发布统一 + initialize 数据格式对齐 V1.03 + mqtt_publish packet_id=0 断连修复 | | V3.2 | 2026-07-10 | 双主题发布统一 + initialize 数据格式对齐 V1.03 + mqtt_publish packet_id=0 断连修复 |
| V3.1 | 2026-07-09 | V1.03: 订阅后发 initialize 上线消息; iot_mqtt_srv 订阅改双主题 | | V3.1 | 2026-07-09 | V1.03: 订阅后发 initialize 上线消息; iot_mqtt_srv 订阅改双主题 |