diff --git a/vd960DBN/BLE/OnlyUpdateApp_Peripheral/APP/dbn_ble_srv.c b/vd960DBN/BLE/OnlyUpdateApp_Peripheral/APP/dbn_ble_srv.c index 86ad554..cc5dcdb 100644 --- a/vd960DBN/BLE/OnlyUpdateApp_Peripheral/APP/dbn_ble_srv.c +++ b/vd960DBN/BLE/OnlyUpdateApp_Peripheral/APP/dbn_ble_srv.c @@ -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->flag = 1; + return notify_dst->flag; } diff --git a/vd960DBN/BLE/OnlyUpdateApp_Peripheral/APP/iot_mqtt_srv.c b/vd960DBN/BLE/OnlyUpdateApp_Peripheral/APP/iot_mqtt_srv.c index fa77e84..5cf68c4 100644 --- a/vd960DBN/BLE/OnlyUpdateApp_Peripheral/APP/iot_mqtt_srv.c +++ b/vd960DBN/BLE/OnlyUpdateApp_Peripheral/APP/iot_mqtt_srv.c @@ -685,20 +685,28 @@ void iot_mqtt_publish_sensor(void) { } } - /*--- Step 4: 构建 JSON → 发布 (字段与 V1.02 协议一致) ---*/ - static char data_json[1024]; + /*--- Step 4: 构建 JSON → 发布 (字段与 V1.02 协议一致) --- + 直接构建到 payload, 省掉 data_json[1024] 中间缓冲: + - 消除 BSS 压力 (省 1024B), 降低与 mqttBuf 重叠风险 + - 消除 %s 拷贝尾部二进制残留的路径 (2026-07-23 _raw 事故) + - coil_count 边界硬限, 防 0xC0 坏帧致溢出 */ static char payload[1400]; - char *p = data_json; - int remaining = sizeof(data_json); + char *p = payload; + int remaining = sizeof(payload); int written; const char *freq_level_names[] = {"high", "mid_high", "mid_low", "low"}; 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; 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 char *misc_type_str = "time"; uint32_t misc_val = 0; @@ -725,12 +733,7 @@ void iot_mqtt_publish_sensor(void) { p += written; remaining -= written; } - 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); + snprintf(p, remaining, "]}}"); { char topic[IOT_MQTT_TOPIC_MAX_LEN]; diff --git a/vd960DBN/BLE/OnlyUpdateApp_Peripheral/APP/usart_biz.c b/vd960DBN/BLE/OnlyUpdateApp_Peripheral/APP/usart_biz.c index 85dfa37..e3c4030 100644 --- a/vd960DBN/BLE/OnlyUpdateApp_Peripheral/APP/usart_biz.c +++ b/vd960DBN/BLE/OnlyUpdateApp_Peripheral/APP/usart_biz.c @@ -172,10 +172,16 @@ void uart_srv(void) if(g_dbn_ble_state_acs_enable.flag != 0){ // BLE ACS 已连接 → 改 Magic 为 0x8F 发给 BLE 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 { + 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++){ @@ -183,10 +189,6 @@ void uart_srv(void) } PRINT("\n"); - if(_report_flag){ - // 传感器帧保留在 pkg 中供上层 (tcp_json_srv) 处理 - // 不 InitPkgUart — 由 tcp_json_push_sensor 消费后清理 - } } else { // 非 0x7F 魔法字节 @@ -199,16 +201,11 @@ void uart_srv(void) 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{ g_dbn_ble_state_acs_enable.flag = 0; } - // 只有非 _report_flag 时才立即清空 - // _report_flag 的帧由 tcp_json_push_sensor 消费后清理 - if (!_report_flag) { - InitPkgUart(&g_pkg_uart_2); - } } } diff --git a/vd960DBN/docs/devlog.md b/vd960DBN/docs/devlog.md index 3952722..b62cfdc 100644 --- a/vd960DBN/docs/devlog.md +++ b/vd960DBN/docs/devlog.md @@ -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.1 | 2026-07-09 | V1.03: 订阅后发 initialize 上线消息; iot_mqtt_srv 订阅改双主题 |