From a7de4dfcde9d828c5efdb93cbfa344b51e4f0b03 Mon Sep 17 00:00:00 2001 From: wangfq Date: Tue, 7 Jul 2026 18:39:45 +0800 Subject: [PATCH] =?UTF-8?q?feat(vd960DBN):=20MQTT/TCP=20report=5Fconfig=20?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=AE=8C=E6=95=B47=E5=8F=82=E6=95=B0?= =?UTF-8?q?=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 ReportConfig 结构体 (sensor_type/enable/once/env_eval/interval/ack_required/timeout) - net_srv.c: MQTT report_config handler — 查询/设置均返回完整配置JSON - tcp_json_srv.c: TCP JSON handle_report_config 同步升级,兼容旧 active_report - iot_mqtt_srv.c: g_report_active → g_report_cfg.enable - g_report_active 全局变量替换为 g_report_cfg 结构体 --- .../APP/include/tcp_json_srv.h | 15 ++- .../APP/iot_mqtt_srv.c | 4 +- .../OnlyUpdateApp_Peripheral/APP/net_srv.c | 69 +++++++++++- .../APP/tcp_json_srv.c | 100 ++++++++++++++---- 4 files changed, 162 insertions(+), 26 deletions(-) diff --git a/vd960DBN/BLE/OnlyUpdateApp_Peripheral/APP/include/tcp_json_srv.h b/vd960DBN/BLE/OnlyUpdateApp_Peripheral/APP/include/tcp_json_srv.h index aeb900e..6e7c718 100644 --- a/vd960DBN/BLE/OnlyUpdateApp_Peripheral/APP/include/tcp_json_srv.h +++ b/vd960DBN/BLE/OnlyUpdateApp_Peripheral/APP/include/tcp_json_srv.h @@ -58,6 +58,19 @@ typedef struct { uint32_t deadline; // ms deadline for timeout } TcpJsonPending; +/*=========================================================================== + * Report Config + *===========================================================================*/ +typedef struct { + uint8_t enable; // 0=off, 1=on + uint8_t sensor_type; // Sensor type, default 12 + uint8_t once; // 0=periodic, 1=single report + uint8_t env_eval; // 0=skip, 1=environment evaluation + uint16_t interval; // Report interval in seconds + uint8_t ack_required; // 0=fire-and-forget, 1=ACK required + uint16_t timeout; // Timeout in ms +} ReportConfig; + /*=========================================================================== * Externs *===========================================================================*/ @@ -70,7 +83,7 @@ extern uint32_t g_json_last_comm_ts; // Last communication timestamp (ms) extern uint32_t g_json_last_connect_ts; // Last client connect timestamp (ms) extern uint8_t g_json_restart_count; // Auto-restart counter extern uint32_t g_json_restart_cooldown; // Cooldown deadline (ms) -extern uint8_t g_report_active; // 0=inactive 1=active report +extern ReportConfig g_report_cfg; // Active report configuration /*=========================================================================== * API diff --git a/vd960DBN/BLE/OnlyUpdateApp_Peripheral/APP/iot_mqtt_srv.c b/vd960DBN/BLE/OnlyUpdateApp_Peripheral/APP/iot_mqtt_srv.c index b101b8e..8c80b01 100644 --- a/vd960DBN/BLE/OnlyUpdateApp_Peripheral/APP/iot_mqtt_srv.c +++ b/vd960DBN/BLE/OnlyUpdateApp_Peripheral/APP/iot_mqtt_srv.c @@ -31,7 +31,7 @@ *===========================================================================*/ -extern uint8_t g_report_active; // from tcp_json_srv.c, 0=inactive 1=active +extern ReportConfig g_report_cfg; // from tcp_json_srv.c extern uint8_t SocketId_TCP; // from net_srv.c, MQTT socket created by WCHNET_CreateTcpMqttSocket uint8_t g_iot_socket = 0xFF; // MQTT TCP socket ID IotMqttState g_iot_state = IOT_STATE_DISCONNECTED; @@ -372,7 +372,7 @@ static void iot_process_recv(void) { *===========================================================================*/ void iot_mqtt_publish_sensor(void) { if (g_iot_state != IOT_STATE_READY) return; - if (!g_report_active) return; + if (!g_report_cfg.enable) return; /* 复用 g_pkg_uart_2 中的传感器帧 */ if (g_pkg_uart_2.flag == 0) return; diff --git a/vd960DBN/BLE/OnlyUpdateApp_Peripheral/APP/net_srv.c b/vd960DBN/BLE/OnlyUpdateApp_Peripheral/APP/net_srv.c index fca4de3..f3ebdd1 100644 --- a/vd960DBN/BLE/OnlyUpdateApp_Peripheral/APP/net_srv.c +++ b/vd960DBN/BLE/OnlyUpdateApp_Peripheral/APP/net_srv.c @@ -1251,7 +1251,74 @@ void manage_mqtt_recv_message(char * msg, int length) NVIC_SystemReset(); return; } - + + // --- report_config --- + if(strcmp(cmd_str, "report_config") == 0) { + char *data_buf = (char *)malloc(512); + if(data_buf) { + memset(data_buf, 0, 512); + simple_parse_json(msg, "\"data\"", data_buf); + + if(strlen(data_buf) > 0) { + // sensor_type (int) + memset(tmp, 0, sizeof(tmp)); + simple_parse_json(data_buf, "\"sensor_type\"", tmp); + if(strlen(tmp) > 0) g_report_cfg.sensor_type = (uint8_t)strtoul(tmp, NULL, 10); + + // enable (bool) + memset(tmp, 0, sizeof(tmp)); + simple_parse_json(data_buf, "\"enable\"", tmp); + if(strlen(tmp) > 0) g_report_cfg.enable = (uint8_t)(strstr(tmp, "true") ? 1 : 0); + + // once (bool) + memset(tmp, 0, sizeof(tmp)); + simple_parse_json(data_buf, "\"once\"", tmp); + if(strlen(tmp) > 0) g_report_cfg.once = (uint8_t)(strstr(tmp, "true") ? 1 : 0); + + // env_eval (bool) + memset(tmp, 0, sizeof(tmp)); + simple_parse_json(data_buf, "\"env_eval\"", tmp); + if(strlen(tmp) > 0) g_report_cfg.env_eval = (uint8_t)(strstr(tmp, "true") ? 1 : 0); + + // interval (int) + memset(tmp, 0, sizeof(tmp)); + simple_parse_json(data_buf, "\"interval\"", tmp); + if(strlen(tmp) > 0) g_report_cfg.interval = (uint16_t)strtoul(tmp, NULL, 10); + + // ack_required (bool) + memset(tmp, 0, sizeof(tmp)); + simple_parse_json(data_buf, "\"ack_required\"", tmp); + if(strlen(tmp) > 0) g_report_cfg.ack_required = (uint8_t)(strstr(tmp, "true") ? 1 : 0); + + // timeout (int) + memset(tmp, 0, sizeof(tmp)); + simple_parse_json(data_buf, "\"timeout\"", tmp); + if(strlen(tmp) > 0) g_report_cfg.timeout = (uint16_t)strtoul(tmp, NULL, 10); + } + free(data_buf); + } + + char resp[400]; + snprintf(resp, sizeof(resp), + "{\"msg_id\":%lu,\"cmd\":\"report_config\"," + "\"ts\":%lu,\"code\":0,\"msg\":\"success\"," + "\"data\":{" + "\"sensor_type\":%d,\"enable\":%s,\"once\":%s,\"env_eval\":%s," + "\"interval\":%u,\"ack_required\":%s,\"timeout\":%u}}", + msg_id, mstick() / 1000, + g_report_cfg.sensor_type, + g_report_cfg.enable ? "true" : "false", + g_report_cfg.once ? "true" : "false", + g_report_cfg.env_eval ? "true" : "false", + g_report_cfg.interval, + g_report_cfg.ack_required ? "true" : "false", + g_report_cfg.timeout); + mqtt_publish(resp_topic, resp, 1); + PRINT("IOT: report_config enable=%d interval=%u sensor=%d\n", + g_report_cfg.enable, g_report_cfg.interval, g_report_cfg.sensor_type); + return; + } + // --- 未支持的命令 --- { char resp[256]; diff --git a/vd960DBN/BLE/OnlyUpdateApp_Peripheral/APP/tcp_json_srv.c b/vd960DBN/BLE/OnlyUpdateApp_Peripheral/APP/tcp_json_srv.c index bc2045a..d7fc1e9 100644 --- a/vd960DBN/BLE/OnlyUpdateApp_Peripheral/APP/tcp_json_srv.c +++ b/vd960DBN/BLE/OnlyUpdateApp_Peripheral/APP/tcp_json_srv.c @@ -31,7 +31,7 @@ uint32_t g_json_auth_timer = 0; uint8_t g_json_pwd_retry = 0; uint32_t g_json_lockout_timer = 0; TcpJsonPending g_json_pending = {0, 0, 0, "", 0}; -uint8_t g_report_active = 0; // 0=不主动上报, 1=主动上报传感器数据 +ReportConfig g_report_cfg = {0}; // 上电默认关闭上报 uint32_t g_json_last_comm_ts = 0; // 最后通信时间戳 uint32_t g_json_last_connect_ts = 0; // 最后连接时间戳 uint8_t g_json_restart_count = 0; // 自动重启计数 @@ -555,29 +555,85 @@ static void handle_loop_param_query(uint8_t socket, uint32_t msg_id, const char PRINT("JSON: loop_param_query sent\n"); } -/* 4.15 report_config — 配置主动上报开关 */ +/* 4.15 report_config — 配置主动上报参数 */ static void handle_report_config(uint8_t socket, uint32_t msg_id, const char *json) { char *data = json_get_data_str(json); - if (!data) { - json_send_error(socket, msg_id, "report_config", JSON_CODE_PARAM_ERR, "missing data"); - return; - } + if (data) { + reset_tmp(); - // Parse active_report flag - reset_tmp(); - simple_parse_json(data, "\"active_report\"", g_tmp_value); - if (strlen(g_tmp_value) > 0) { - if (strstr(g_tmp_value, "true")) { - g_report_active = 1; - } else { - g_report_active = 0; + // sensor_type (int) + simple_parse_json(data, "\"sensor_type\"", g_tmp_value); + if (strlen(g_tmp_value) > 0) { + g_report_cfg.sensor_type = (uint8_t)strtoul(g_tmp_value, NULL, 10); } - } - free(data); - json_send_ok(socket, msg_id, "report_config", - g_report_active ? "{\"active_report\":true}" : "{\"active_report\":false}"); - PRINT("JSON: report_config active_report=%d\n", g_report_active); + // enable (bool) + memset(g_tmp_value, 0, sizeof(g_tmp_value)); + simple_parse_json(data, "\"enable\"", g_tmp_value); + if (strlen(g_tmp_value) > 0) { + g_report_cfg.enable = (uint8_t)(strstr(g_tmp_value, "true") ? 1 : 0); + } + + // once (bool) + memset(g_tmp_value, 0, sizeof(g_tmp_value)); + simple_parse_json(data, "\"once\"", g_tmp_value); + if (strlen(g_tmp_value) > 0) { + g_report_cfg.once = (uint8_t)(strstr(g_tmp_value, "true") ? 1 : 0); + } + + // env_eval (bool) + memset(g_tmp_value, 0, sizeof(g_tmp_value)); + simple_parse_json(data, "\"env_eval\"", g_tmp_value); + if (strlen(g_tmp_value) > 0) { + g_report_cfg.env_eval = (uint8_t)(strstr(g_tmp_value, "true") ? 1 : 0); + } + + // interval (int) + memset(g_tmp_value, 0, sizeof(g_tmp_value)); + simple_parse_json(data, "\"interval\"", g_tmp_value); + if (strlen(g_tmp_value) > 0) { + g_report_cfg.interval = (uint16_t)strtoul(g_tmp_value, NULL, 10); + } + + // ack_required (bool) + memset(g_tmp_value, 0, sizeof(g_tmp_value)); + simple_parse_json(data, "\"ack_required\"", g_tmp_value); + if (strlen(g_tmp_value) > 0) { + g_report_cfg.ack_required = (uint8_t)(strstr(g_tmp_value, "true") ? 1 : 0); + } + + // timeout (int) + memset(g_tmp_value, 0, sizeof(g_tmp_value)); + simple_parse_json(data, "\"timeout\"", g_tmp_value); + if (strlen(g_tmp_value) > 0) { + g_report_cfg.timeout = (uint16_t)strtoul(g_tmp_value, NULL, 10); + } + + // 兼容旧协议 active_report + memset(g_tmp_value, 0, sizeof(g_tmp_value)); + simple_parse_json(data, "\"active_report\"", g_tmp_value); + if (strlen(g_tmp_value) > 0) { + g_report_cfg.enable = (uint8_t)(strstr(g_tmp_value, "true") ? 1 : 0); + } + + free(data); + } + + char data_json[256]; + snprintf(data_json, sizeof(data_json), + "{\"sensor_type\":%d,\"enable\":%s,\"once\":%s,\"env_eval\":%s," + "\"interval\":%u,\"ack_required\":%s,\"timeout\":%u}", + g_report_cfg.sensor_type, + g_report_cfg.enable ? "true" : "false", + g_report_cfg.once ? "true" : "false", + g_report_cfg.env_eval ? "true" : "false", + g_report_cfg.interval, + g_report_cfg.ack_required ? "true" : "false", + g_report_cfg.timeout); + + json_send_ok(socket, msg_id, "report_config", data_json); + PRINT("JSON: report_config enable=%d interval=%u sensor=%d\\n", + g_report_cfg.enable, g_report_cfg.interval, g_report_cfg.sensor_type); } /* 4.16 loop_version_query — 获取地感MCU版本号 (CMD 0x4A) */ @@ -758,12 +814,12 @@ static int format_loop_param_json(char *buf, uint16_t buf_size, const LUP_ParamG static void json_sensor_callback(const uint8_t *pkg, uint16_t len) { PRINT("JSON: sensor_cb enter socket=%d auth=%d report=%d\n", - g_json_socket_listen, g_json_auth_state, g_report_active); + g_json_socket_listen, g_json_auth_state, g_report_cfg.enable); // Check: socket active, authed, report enabled if (g_json_socket_listen == 0xFF) { PRINT("JSON: sensor_cb skip: no socket\n"); return; } if (g_json_auth_state != JSON_STATE_AUTHED) { PRINT("JSON: sensor_cb skip: not authed\n"); return; } - if (!g_report_active) { PRINT("JSON: sensor_cb skip: report disabled\n"); return; } + if (!g_report_cfg.enable) { PRINT("JSON: sensor_cb skip: report disabled\\n"); return; } LUP_SensorReport sr; memset(&sr, 0, sizeof(sr)); @@ -1247,7 +1303,7 @@ void tcp_json_push_sensor(void) { // Check: socket active, authed, report enabled if (g_json_socket_listen == 0xFF) return; if (g_json_auth_state != JSON_STATE_AUTHED) return; - if (!g_report_active) return; // 主动上报未开启 + if (!g_report_cfg.enable) return; // 主动上报未开启 // Only proceed if g_pkg_uart_2 has data and it's a 0xC0 sensor report if (g_pkg_uart_2.flag == 0) return;