fix(vd960DBN): 联网复位事故 — OTA 命令缓冲合并 union (RAM 90% 栈余量不足)
现象: SUBACK 后收平台 report_config (PUBLISH len=197) → HardFault → NVIC_SystemReset (RST_REASON 0x10000000 = SFT, 非 IWDG) → 死循环复位 根因: RAM 90.02% + 6 个 OTA 分支独立 static resp[256~400] + hexbuf[513] 共 ~2.5KB BSS → 栈余量被挤 → iot_handle_publish 深调用链栈溢出 (局部栈改 static 是伪优化: BSS↑=栈余量↓; 正解是 union 复用减总量) 修复: - iot_mqtt_srv.c: 6 resp + hexbuf 合并函数级 static union _ota_io (~2KB 省) - ota_srv.c: _chunk_buf/_fs_frame 合并 union (~260B 省) + 删无用变量 验证: 语法 0 错误; gcc 隔离单测 10/10; 待板级确认 RAM 回 ~88% 不再复位
This commit is contained in:
@@ -449,6 +449,12 @@ static int iot_mqtt_publish(const char *topic, const char *payload,
|
||||
/* 处理一条收到的 MQTT PUBLISH 消息 */
|
||||
static void iot_handle_publish(const char *topic, uint8_t *payload, int payload_len) {
|
||||
static char json[IOT_MQTT_RECV_BUF_LEN]; // static: 避免 1KB 栈开销
|
||||
/* OTA 命令 IO 缓冲 (V1.08): 各分支响应组包 + ota_data hex 提取共用
|
||||
(RAM 90% 环境: 6 个独立 static 数组 ~2.5KB 挤栈, 合并 union 省 ~2KB) */
|
||||
static union {
|
||||
char resp[512]; /* ota_* 命令响应 JSON */
|
||||
char hexbuf[512 + 1]; /* ota_data hex 字符串 (512 hex + NUL) */
|
||||
} _ota_io;
|
||||
int copy_len = payload_len < (int)sizeof(json) - 1 ? payload_len : (int)sizeof(json) - 1;
|
||||
memcpy(json, payload, copy_len);
|
||||
json[copy_len] = '\0';
|
||||
@@ -710,7 +716,6 @@ static void iot_handle_publish(const char *topic, uint8_t *payload, int payload_
|
||||
|
||||
} else if (strcmp(cmd_str, "ota_begin") == 0) {
|
||||
/* V1.08: 开启 OTA 会话 / 断点续传定位 (Loop MCU 远程 OTA, 先存后刷) */
|
||||
static char resp[400]; /* static: RAM 90% 下防栈峰值 (历史 .bss 挤栈事故) */
|
||||
uint32_t size = 0, crc32 = 0;
|
||||
char version[16] = {0};
|
||||
uint8_t force = 0;
|
||||
@@ -730,7 +735,7 @@ static void iot_handle_publish(const char *topic, uint8_t *payload, int payload_
|
||||
rc = ota_cmd_begin(size, crc32, version, force);
|
||||
if (rc == 0) {
|
||||
const OtaMeta *m = ota_meta();
|
||||
snprintf(resp, sizeof(resp),
|
||||
snprintf(_ota_io.resp, sizeof(_ota_io.resp),
|
||||
"{\"msg_id\":%lu,\"cmd\":\"ota_begin\",\"ts\":%lu,\"code\":0,\"msg\":\"success\","
|
||||
"\"data\":{\"target\":\"loop\",\"slot\":\"%s\",\"offset\":%lu,\"received\":%lu,"
|
||||
"\"size\":%lu,\"crc32\":%lu,\"state\":\"%s\"}}",
|
||||
@@ -740,18 +745,16 @@ static void iot_handle_publish(const char *topic, uint8_t *payload, int payload_
|
||||
(unsigned long)m->size, (unsigned long)m->crc32,
|
||||
ota_state_str((uint8_t)m->state));
|
||||
} else {
|
||||
snprintf(resp, sizeof(resp),
|
||||
snprintf(_ota_io.resp, sizeof(_ota_io.resp),
|
||||
"{\"msg_id\":%lu,\"cmd\":\"ota_begin\",\"ts\":%lu,\"code\":1,\"msg\":\"param error\","
|
||||
"\"data\":{\"target\":\"loop\",\"err_code\":%d}}",
|
||||
msg_id, dev_time_now(), (rc == 3) ? 2 : 4);
|
||||
}
|
||||
iot_mqtt_publish(resp_topic, resp, strlen(resp), 1);
|
||||
iot_mqtt_publish(resp_topic, _ota_io.resp, strlen(_ota_io.resp), 1);
|
||||
PRINT("IOT: ota_begin size=%lu rc=%d\n", (unsigned long)size, rc);
|
||||
|
||||
} else if (strcmp(cmd_str, "ota_data") == 0) {
|
||||
/* V1.08: 分片下发 (256B/片, 单片 CRC32; 重复片幂等, 乱序拒收指示续传) */
|
||||
static char resp[400];
|
||||
static char hexbuf[512 + 1]; /* 512 hex 最大, static 防栈峰值 */
|
||||
const char *hp;
|
||||
uint32_t offset = 0, crc32 = 0;
|
||||
int rc;
|
||||
@@ -763,37 +766,36 @@ static void iot_handle_publish(const char *topic, uint8_t *payload, int payload_
|
||||
if (strlen(tmp) > 0) crc32 = (uint32_t)strtoul(tmp, NULL, 10);
|
||||
/* hex 值提取: data 对象内字段是 "data":"...", 顶层 data 对象是 "data":{ — 前者唯一 */
|
||||
hp = strstr(json, "\"data\":\"");
|
||||
memset(hexbuf, 0, sizeof(hexbuf));
|
||||
memset(_ota_io.hexbuf, 0, sizeof(_ota_io.hexbuf));
|
||||
if (hp) {
|
||||
hp += 8; /* 跳过 "data":" */
|
||||
strncpy(hexbuf, hp, sizeof(hexbuf) - 1);
|
||||
{ char *q = strchr(hexbuf, '"'); if (q) *q = '\0'; }
|
||||
strncpy(_ota_io.hexbuf, hp, sizeof(_ota_io.hexbuf) - 1);
|
||||
{ char *q = strchr(_ota_io.hexbuf, '"'); if (q) *q = '\0'; }
|
||||
}
|
||||
rc = ota_cmd_data(offset, crc32, hexbuf);
|
||||
rc = ota_cmd_data(offset, crc32, _ota_io.hexbuf);
|
||||
if (rc == 0) {
|
||||
const OtaMeta *m = ota_meta();
|
||||
snprintf(resp, sizeof(resp),
|
||||
snprintf(_ota_io.resp, sizeof(_ota_io.resp),
|
||||
"{\"msg_id\":%lu,\"cmd\":\"ota_data\",\"ts\":%lu,\"code\":0,\"msg\":\"success\","
|
||||
"\"data\":{\"offset\":%lu,\"received\":%lu}}",
|
||||
msg_id, dev_time_now(), (unsigned long)offset, (unsigned long)m->received);
|
||||
} else if (rc == 1) {
|
||||
const OtaMeta *m = ota_meta();
|
||||
snprintf(resp, sizeof(resp),
|
||||
snprintf(_ota_io.resp, sizeof(_ota_io.resp),
|
||||
"{\"msg_id\":%lu,\"cmd\":\"ota_data\",\"ts\":%lu,\"code\":1,\"msg\":\"crc/gap error\","
|
||||
"\"data\":{\"err_code\":1,\"offset\":%lu,\"received\":%lu}}",
|
||||
msg_id, dev_time_now(), (unsigned long)m->received, (unsigned long)m->received);
|
||||
} else {
|
||||
snprintf(resp, sizeof(resp),
|
||||
snprintf(_ota_io.resp, sizeof(_ota_io.resp),
|
||||
"{\"msg_id\":%lu,\"cmd\":\"ota_data\",\"ts\":%lu,\"code\":3,\"msg\":\"busy\","
|
||||
"\"data\":{\"err_code\":2}}",
|
||||
msg_id, dev_time_now());
|
||||
}
|
||||
iot_mqtt_publish(resp_topic, resp, strlen(resp), 1);
|
||||
iot_mqtt_publish(resp_topic, _ota_io.resp, strlen(_ota_io.resp), 1);
|
||||
PRINT("IOT: ota_data offset=%lu rc=%d\n", (unsigned long)offset, rc);
|
||||
|
||||
} else if (strcmp(cmd_str, "ota_end") == 0) {
|
||||
/* V1.08: 结束下载, 全镜像 CRC32 复核 */
|
||||
static char resp[300];
|
||||
uint32_t crc32 = 0;
|
||||
int rc;
|
||||
memset(tmp, 0, sizeof(tmp));
|
||||
@@ -801,43 +803,41 @@ static void iot_handle_publish(const char *topic, uint8_t *payload, int payload_
|
||||
if (strlen(tmp) > 0) crc32 = (uint32_t)strtoul(tmp, NULL, 10);
|
||||
rc = ota_cmd_end(crc32);
|
||||
if (rc == 0) {
|
||||
snprintf(resp, sizeof(resp),
|
||||
snprintf(_ota_io.resp, sizeof(_ota_io.resp),
|
||||
"{\"msg_id\":%lu,\"cmd\":\"ota_end\",\"ts\":%lu,\"code\":0,\"msg\":\"success\","
|
||||
"\"data\":{\"crc_ok\":true}}",
|
||||
msg_id, dev_time_now());
|
||||
} else if (rc == 5) {
|
||||
snprintf(resp, sizeof(resp),
|
||||
snprintf(_ota_io.resp, sizeof(_ota_io.resp),
|
||||
"{\"msg_id\":%lu,\"cmd\":\"ota_end\",\"ts\":%lu,\"code\":5,\"msg\":\"crc mismatch\","
|
||||
"\"data\":{\"err_code\":5,\"crc_ok\":false}}",
|
||||
msg_id, dev_time_now());
|
||||
} else if (rc == 3) {
|
||||
snprintf(resp, sizeof(resp),
|
||||
snprintf(_ota_io.resp, sizeof(_ota_io.resp),
|
||||
"{\"msg_id\":%lu,\"cmd\":\"ota_end\",\"ts\":%lu,\"code\":3,\"msg\":\"busy\","
|
||||
"\"data\":{\"err_code\":2}}",
|
||||
msg_id, dev_time_now());
|
||||
} else {
|
||||
const OtaMeta *m = ota_meta();
|
||||
snprintf(resp, sizeof(resp),
|
||||
snprintf(_ota_io.resp, sizeof(_ota_io.resp),
|
||||
"{\"msg_id\":%lu,\"cmd\":\"ota_end\",\"ts\":%lu,\"code\":1,\"msg\":\"incomplete\","
|
||||
"\"data\":{\"offset\":%lu,\"received\":%lu}}",
|
||||
msg_id, dev_time_now(), (unsigned long)m->received, (unsigned long)m->received);
|
||||
}
|
||||
iot_mqtt_publish(resp_topic, resp, strlen(resp), 1);
|
||||
iot_mqtt_publish(resp_topic, _ota_io.resp, strlen(_ota_io.resp), 1);
|
||||
PRINT("IOT: ota_end rc=%d\n", rc);
|
||||
|
||||
} else if (strcmp(cmd_str, "ota_abort") == 0) {
|
||||
/* V1.08: 中止会话, 释放暂存 */
|
||||
static char resp[256];
|
||||
int rc = ota_cmd_abort();
|
||||
snprintf(resp, sizeof(resp),
|
||||
snprintf(_ota_io.resp, sizeof(_ota_io.resp),
|
||||
"{\"msg_id\":%lu,\"cmd\":\"ota_abort\",\"ts\":%lu,\"code\":%d,\"msg\":\"%s\"}",
|
||||
msg_id, dev_time_now(), (rc == 0) ? 0 : 1, (rc == 0) ? "success" : "internal error");
|
||||
iot_mqtt_publish(resp_topic, resp, strlen(resp), 1);
|
||||
iot_mqtt_publish(resp_topic, _ota_io.resp, strlen(_ota_io.resp), 1);
|
||||
PRINT("IOT: ota_abort rc=%d\n", rc);
|
||||
|
||||
} else if (strcmp(cmd_str, "ota_flash") == 0) {
|
||||
/* V1.08: 触发本地 ISP 刷写 (同步安全检查 → 异步执行) */
|
||||
static char resp[300];
|
||||
char slot_buf[8] = {0};
|
||||
uint8_t slot = 0, force = 0;
|
||||
int rc;
|
||||
@@ -850,27 +850,26 @@ static void iot_handle_publish(const char *topic, uint8_t *payload, int payload_
|
||||
if (strlen(tmp) > 0) force = (strcmp(tmp, "true") == 0);
|
||||
rc = ota_cmd_flash(slot, force);
|
||||
if (rc == 0) {
|
||||
snprintf(resp, sizeof(resp),
|
||||
snprintf(_ota_io.resp, sizeof(_ota_io.resp),
|
||||
"{\"msg_id\":%lu,\"cmd\":\"ota_flash\",\"ts\":%lu,\"code\":0,\"msg\":\"success, flashing async\"}",
|
||||
msg_id, dev_time_now());
|
||||
} else if (rc == 3) {
|
||||
snprintf(resp, sizeof(resp),
|
||||
snprintf(_ota_io.resp, sizeof(_ota_io.resp),
|
||||
"{\"msg_id\":%lu,\"cmd\":\"ota_flash\",\"ts\":%lu,\"code\":3,\"msg\":\"busy\","
|
||||
"\"data\":{\"err_code\":3}}",
|
||||
msg_id, dev_time_now());
|
||||
} else {
|
||||
snprintf(resp, sizeof(resp),
|
||||
snprintf(_ota_io.resp, sizeof(_ota_io.resp),
|
||||
"{\"msg_id\":%lu,\"cmd\":\"ota_flash\",\"ts\":%lu,\"code\":1,\"msg\":\"param error\"}",
|
||||
msg_id, dev_time_now());
|
||||
}
|
||||
iot_mqtt_publish(resp_topic, resp, strlen(resp), 1);
|
||||
iot_mqtt_publish(resp_topic, _ota_io.resp, strlen(_ota_io.resp), 1);
|
||||
PRINT("IOT: ota_flash slot=%d force=%d rc=%d\n", slot, force, rc);
|
||||
|
||||
} else if (strcmp(cmd_str, "ota_status") == 0) {
|
||||
/* V1.08: 查询 OTA 状态 (含刷写进度) */
|
||||
static char resp[400];
|
||||
const OtaMeta *m = ota_meta();
|
||||
snprintf(resp, sizeof(resp),
|
||||
snprintf(_ota_io.resp, sizeof(_ota_io.resp),
|
||||
"{\"msg_id\":%lu,\"cmd\":\"ota_status\",\"ts\":%lu,\"code\":0,\"msg\":\"success\","
|
||||
"\"data\":{\"target\":\"loop\",\"state\":\"%s\",\"slot\":\"%s\",\"size\":%lu,"
|
||||
"\"received\":%lu,\"crc32\":%lu,\"version\":\"%s\","
|
||||
@@ -881,7 +880,7 @@ static void iot_handle_publish(const char *topic, uint8_t *payload, int payload_
|
||||
m->version,
|
||||
(unsigned long)ota_flash_sent(), (unsigned long)ota_flash_total(),
|
||||
(unsigned long)m->last_result, (unsigned long)m->last_result);
|
||||
iot_mqtt_publish(resp_topic, resp, strlen(resp), 1);
|
||||
iot_mqtt_publish(resp_topic, _ota_io.resp, strlen(_ota_io.resp), 1);
|
||||
PRINT("IOT: ota_status state=%s\n", ota_state_str((uint8_t)m->state));
|
||||
|
||||
} else if (strcmp(cmd_str, "ssc_net_query") == 0) {
|
||||
|
||||
Reference in New Issue
Block a user