feat(vd960DBN): MQTT/TCP report_config 支持完整7参数配置

- 新增 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 结构体
This commit is contained in:
wangfq
2026-07-07 18:39:45 +08:00
parent cd92f3e0c3
commit a7de4dfcde
4 changed files with 162 additions and 26 deletions
@@ -58,6 +58,19 @@ typedef struct {
uint32_t deadline; // ms deadline for timeout uint32_t deadline; // ms deadline for timeout
} TcpJsonPending; } 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 * 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 uint32_t g_json_last_connect_ts; // Last client connect timestamp (ms)
extern uint8_t g_json_restart_count; // Auto-restart counter extern uint8_t g_json_restart_count; // Auto-restart counter
extern uint32_t g_json_restart_cooldown; // Cooldown deadline (ms) 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 * API
@@ -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 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 uint8_t g_iot_socket = 0xFF; // MQTT TCP socket ID
IotMqttState g_iot_state = IOT_STATE_DISCONNECTED; IotMqttState g_iot_state = IOT_STATE_DISCONNECTED;
@@ -372,7 +372,7 @@ static void iot_process_recv(void) {
*===========================================================================*/ *===========================================================================*/
void iot_mqtt_publish_sensor(void) { void iot_mqtt_publish_sensor(void) {
if (g_iot_state != IOT_STATE_READY) return; if (g_iot_state != IOT_STATE_READY) return;
if (!g_report_active) return; if (!g_report_cfg.enable) return;
/* 复用 g_pkg_uart_2 中的传感器帧 */ /* 复用 g_pkg_uart_2 中的传感器帧 */
if (g_pkg_uart_2.flag == 0) return; if (g_pkg_uart_2.flag == 0) return;
@@ -1252,6 +1252,73 @@ void manage_mqtt_recv_message(char * msg, int length)
return; 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]; char resp[256];
@@ -31,7 +31,7 @@ uint32_t g_json_auth_timer = 0;
uint8_t g_json_pwd_retry = 0; uint8_t g_json_pwd_retry = 0;
uint32_t g_json_lockout_timer = 0; uint32_t g_json_lockout_timer = 0;
TcpJsonPending g_json_pending = {0, 0, 0, "", 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_comm_ts = 0; // 最后通信时间戳
uint32_t g_json_last_connect_ts = 0; // 最后连接时间戳 uint32_t g_json_last_connect_ts = 0; // 最后连接时间戳
uint8_t g_json_restart_count = 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"); 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) { static void handle_report_config(uint8_t socket, uint32_t msg_id, const char *json) {
char *data = json_get_data_str(json); char *data = json_get_data_str(json);
if (!data) { if (data) {
json_send_error(socket, msg_id, "report_config", JSON_CODE_PARAM_ERR, "missing data"); reset_tmp();
return;
// 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);
} }
// Parse active_report flag // enable (bool)
reset_tmp(); 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); simple_parse_json(data, "\"active_report\"", g_tmp_value);
if (strlen(g_tmp_value) > 0) { if (strlen(g_tmp_value) > 0) {
if (strstr(g_tmp_value, "true")) { g_report_cfg.enable = (uint8_t)(strstr(g_tmp_value, "true") ? 1 : 0);
g_report_active = 1;
} else {
g_report_active = 0;
} }
}
free(data);
json_send_ok(socket, msg_id, "report_config", free(data);
g_report_active ? "{\"active_report\":true}" : "{\"active_report\":false}"); }
PRINT("JSON: report_config active_report=%d\n", g_report_active);
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) */ /* 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) static void json_sensor_callback(const uint8_t *pkg, uint16_t len)
{ {
PRINT("JSON: sensor_cb enter socket=%d auth=%d report=%d\n", 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 // Check: socket active, authed, report enabled
if (g_json_socket_listen == 0xFF) { PRINT("JSON: sensor_cb skip: no socket\n"); return; } 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_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; LUP_SensorReport sr;
memset(&sr, 0, sizeof(sr)); memset(&sr, 0, sizeof(sr));
@@ -1247,7 +1303,7 @@ void tcp_json_push_sensor(void) {
// Check: socket active, authed, report enabled // Check: socket active, authed, report enabled
if (g_json_socket_listen == 0xFF) return; if (g_json_socket_listen == 0xFF) return;
if (g_json_auth_state != JSON_STATE_AUTHED) 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 // Only proceed if g_pkg_uart_2 has data and it's a 0xC0 sensor report
if (g_pkg_uart_2.flag == 0) return; if (g_pkg_uart_2.flag == 0) return;