From 5bc543237e060d2b6250509d628f36e4aae1c1fe Mon Sep 17 00:00:00 2001 From: helei Date: Fri, 18 Sep 2026 14:56:01 +0800 Subject: [PATCH] =?UTF-8?q?=E7=A7=BB=E6=A4=8D4G=20MQTT=E4=B8=BB=E5=8A=A8?= =?UTF-8?q?=E5=81=A5=E5=BA=B7=E6=A3=80=E6=9F=A5(=E6=AF=8F60s=E6=9F=A5MQTTS?= =?UTF-8?q?TATU,=E8=BF=9E=E7=BB=AD3=E6=AC=A1=E4=B8=8D=E5=9C=A8=E7=BA=BF?= =?UTF-8?q?=E5=A4=8D=E4=BD=8D,OTA=E6=9C=9F=E9=97=B4=E6=9A=82=E5=81=9C;RSN?= =?UTF-8?q?=5FMQTT=5FLOST=3D18),=E6=A0=B9=E6=B2=BB=E6=96=AD=E7=BD=91?= =?UTF-8?q?=E5=81=87=E6=AD=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- STM32F103_App1/HardWare/CAR/air780e.c | 56 +++++++++++++++++++++ STM32F103_App1/HardWare/SYSINIT/reset_log.c | 1 + STM32F103_App1/m_app/boot_share.h | 1 + STM32F103_BootLoader/m_app/boot_share.h | 3 ++ 鐗堟湰璇存槑.md | 4 ++ 5 files changed, 65 insertions(+) diff --git a/STM32F103_App1/HardWare/CAR/air780e.c b/STM32F103_App1/HardWare/CAR/air780e.c index c42bec2..f5368f2 100644 --- a/STM32F103_App1/HardWare/CAR/air780e.c +++ b/STM32F103_App1/HardWare/CAR/air780e.c @@ -998,6 +998,61 @@ static void air780e_gps_poll(void) MqttInfoStr.ClientID, lon, lat); } +/*==== MQTT 主动健康检查: 每60s查询 AT+MQTTSTATU, 连续3次不在线则整机复位 ==== + * 背景: 被动等 CLOSED/+NO Service URC 可能漏接导致断网假死(1.5.11 现场故障), + * 这里主动查询兜底, 被动 URC 处理保留, 双通道互为备份。 + * 在 air780e_process 里调用(已持 net_at_lock), OTA 期间(g_net_tx_busy)跳过。 */ +#define MQTT_HEALTH_INTERVAL_MS 60000 /* 查询周期 */ +#define MQTT_HEALTH_FAIL_MAX 3 /* 连续失败上限 */ + +static void air780e_mqtt_health(void) +{ + static uint32_t s_hl_tick = 0; + static uint8_t s_hl_fail = 0; + + if (!g_air780e_mqtt_ready) { s_hl_tick = 0; s_hl_fail = 0; return; } + if (g_net_tx_busy) return; /* OTA 下载期间禁止插 AT */ + + uint32_t now = HAL_GetTick(); + if (s_hl_tick == 0) { s_hl_tick = now; return; } + if (now - s_hl_tick < MQTT_HEALTH_INTERVAL_MS) return; + s_hl_tick = now; + + U2_CopyIndex = 0; U2_CopyBuff[0] = 0; U2_CopyFlag = 0; + CAT1_printf("AT+MQTTSTATU"); + + int online = -1; /* -1=超时 0/2=离线 1=在线 */ + int t = 20; /* 最长 2s */ + while (--t) { + bg_delay(100); + if (U2_CopyFlag) { + /* 平台下行消息优先, 让 dispatch 处理, 本次不计失败 */ + if (strstr((char *)U2_CopyBuff, "+MSUB:")) return; + char *p = strstr((char *)U2_CopyBuff, "+MQTTSTATU"); + if (p) { + char *c = strchr(p, ':'); + if (c && c[1]) online = (c[1] == ' ') ? (c[2] - '0') : (c[1] - '0'); + break; + } + } + } + + if (online == 1) { + if (s_hl_fail) log_info("> 4G: MQTTSTATU 恢复在线"); + s_hl_fail = 0; + return; + } + s_hl_fail++; + if (online < 0) log_warn("> 4G: MQTTSTATU 查询超时 (%d/%d)", s_hl_fail, MQTT_HEALTH_FAIL_MAX); + else log_warn("> 4G: MQTTSTATU 离线(status=%d) (%d/%d)", online, s_hl_fail, MQTT_HEALTH_FAIL_MAX); + if (s_hl_fail >= MQTT_HEALTH_FAIL_MAX) { + log_error("> 4G 异常: MQTT 连接丢失(主动查询连续失败),复位"); + reset_log_mark(RSN_MQTT_LOST); + HAL_Delay(1000); + NVIC_SystemReset(); + } +} + /*==== Process ====*/ void air780e_process(void){ /* 循环处理缓冲区中所有完整 MQTT 消息 */ @@ -1006,5 +1061,6 @@ void air780e_process(void){ dispatch_one_mqtt_msg(); } air780e_gps_poll(); + air780e_mqtt_health(); } diff --git a/STM32F103_App1/HardWare/SYSINIT/reset_log.c b/STM32F103_App1/HardWare/SYSINIT/reset_log.c index 22930c2..542c924 100644 --- a/STM32F103_App1/HardWare/SYSINIT/reset_log.c +++ b/STM32F103_App1/HardWare/SYSINIT/reset_log.c @@ -57,6 +57,7 @@ static const char *reason_str(uint8_t r) case RSN_POWER_LOSS: return "外部断电(法拉电容记录)"; case RSN_4G_MODULE: return "4G模组异常自重启"; case RSN_OTA_FAIL: return "OTA失败中止"; + case RSN_MQTT_LOST: return "MQTT断开(主动查询)"; case RSN_SOFT_GENERIC: return "软件复位(未标记)"; default: return "未知"; } diff --git a/STM32F103_App1/m_app/boot_share.h b/STM32F103_App1/m_app/boot_share.h index ac828e7..f85bd13 100644 --- a/STM32F103_App1/m_app/boot_share.h +++ b/STM32F103_App1/m_app/boot_share.h @@ -39,6 +39,7 @@ typedef struct { #define RSN_4G_MODULE 15 /* 4G 模组异常自重启(boot.rom) */ #define RSN_SOFT_GENERIC 16 /* 软件复位(未标记细分原因,如 JLink 复位) */ #define RSN_OTA_FAIL 17 /* OTA 下载/前置检查失败,中止后复位 */ +#define RSN_MQTT_LOST 18 /* MQTT 断开(主动健康查询连续失败) */ static inline uint32_t boot_share_sum(const volatile boot_share_t *s) { diff --git a/STM32F103_BootLoader/m_app/boot_share.h b/STM32F103_BootLoader/m_app/boot_share.h index 10a1a00..dc0c038 100644 --- a/STM32F103_BootLoader/m_app/boot_share.h +++ b/STM32F103_BootLoader/m_app/boot_share.h @@ -37,6 +37,9 @@ typedef struct { #define RSN_CMD_RECOVERY 13 /* 串口 RECOVERY 命令 */ #define RSN_POWER_LOSS 14 /* 外部 12V 断电(法拉电容续航中记录) */ #define RSN_4G_MODULE 15 /* 4G 模组异常自重启(boot.rom) */ +#define RSN_SOFT_GENERIC 16 /* 软件复位(未细分原因, 如 JLink 复位) */ +#define RSN_OTA_FAIL 17 /* OTA 失败/前置检查失败, 中止复位 */ +#define RSN_MQTT_LOST 18 /* MQTT 断开(主动健康查询连续失败) */ static inline uint32_t boot_share_sum(const volatile boot_share_t *s) { diff --git a/鐗堟湰璇存槑.md b/鐗堟湰璇存槑.md index 07e3022..c9a1194 100644 --- a/鐗堟湰璇存槑.md +++ b/鐗堟湰璇存槑.md @@ -21,6 +21,10 @@ 鎺у埗鍛戒护鏀逛笁娈靛紡锛欶C03 棰勮锛堝垽瀹氬湪绾 + 蹇収鍛戒护鍓嶅弽棣堬級鈫 FC05 鈫 150ms 鈫 FC03 鏍¢獙璺冲彉锛 鍛戒护閾捐矾鏈缁堟棤搴旂瓟鍗冲垽绂荤嚎骞跺簲绛斿钩鍙 `ext relay board offline`锛屼笅娆″懡浠よ嚜鍔ㄩ噸鏂版帰娴嬫仮澶嶏紱 鏂數鎭㈠瑙﹀彂鐐逛笉鍙橈紙绂荤嚎鈫掍笂绾挎瘮瀵 EEPROM 閫愯矾琛ュ彂锛 +- **4G MQTT 涓诲姩鍋ュ悍妫鏌**锛堢Щ妞嶈嚜鑰佸伐绋 V1.6.6锛屾牴娌绘柇缃戝亣姝伙級锛歁QTT Ready 鍚庢瘡 60s 鏌ヤ竴娆 + `AT+MQTTSTATU`锛岃繛缁 3 娆′笉鍦ㄧ嚎锛堢绾/鏈璇/鏌ヨ瓒呮椂锛夋暣鏈哄浣嶏紱OTA 涓嬭浇鏈熼棿锛坓_net_tx_busy锛夋殏鍋滄煡璇紱 + 琚姩 URC 澶勭悊淇濈暀鍙屼繚闄╋紱鏂板澶嶄綅鍘熷洜鐮 RSN_MQTT_LOST(18)锛圔L 鐨 boot_share.h 鍚屾琛ラ綈 16/17/18锛夈 + WiFi 閫氶亾涓嶅姞鈥斺旇蒋浠 MQTT 蹇冭烦闃舵鏈韩灏辨槸涓诲姩鎺㈡祴锛屾棤"琚姩绛 URC"鐩插尯 - **缁х數鍣/鎶曞杺骞冲彴搴旂瓟鏂囨鍏ㄩ儴涓枃鍖**锛圲TF-8 瀛楄妭杞箟锛屽钩鍙板彧璁 UTF-8锛涚洿鎺ュ啓姹夊瓧=GBK 瀹炴祴涔辩爜锛夛細 璐熻浇鏂紑鎴栫户鐢靛櫒鎹熷潖 / 寮鍏陈锋姇鍠傚弬鏁版棤鏁 / 閲嶉噺鏈氨缁殏涓嶈兘鎶曞杺 / 鏈澶囨棤绉伴噸绉 / 鎵╁睍鏉夸笉鍦ㄧ嚎路蹇櫬锋棤搴旂瓟绛 - **鎸囦护搴旂瓟鏀瑰彲闈犲彂閫**锛堜慨澶"缁х數鍣ㄥ凡鍔ㄤ綔浣嗗钩鍙板搷搴旇秴鏃"锛夛細鏂板 `NET_publish_response_wait()`锛