/* net_wifi.c - WiFi 后端(网络层下的通道实现之一) * * 组成:esp8266.c (ESP-01S AT驱动/TCP透传) + mqtt_client.c (软件MQTT 3.1.1)。 * 连接顺序:硬件复位 → 等已存AP自动连接(20s) → 连固定SSID(60s) → * Smart Config 智能配网(60s) → 失败返回,由 network.c 切回 4G。 * 运行阶段:mqttc_process 解析下行报文,30s 心跳保活, * 断链(CLOSED/心跳超时) 清 ready,由 network.c 调度重连或切回 4G。 */ #include "net_wifi.h" #include "esp8266.h" #include "mqtt_client.h" #include "network.h" #include "air780e.h" /* bg_delay */ #include "uart.h" #include "log.h" #include "stdio.h" #include "string.h" volatile uint8_t g_wifi_mqtt_ready = 0; volatile uint8_t g_wifi_first_publish_ok = 0; static uint32_t s_ping_tick = 0; /* 上行发布主题暂存 */ static char s_topic_up[48]; /*==== 阻塞建链:成功返回 0 并置 g_wifi_mqtt_ready ====*/ int net_wifi_init(void) { log_info("> WiFi: init..."); g_wifi_mqtt_ready = 0; g_wifi_first_publish_ok = 0; esp_gpio_init(); UART4_StartRx(); if (esp_reset() != 0) return -1; if (esp_send_cmd("AT", "OK", 2000) != 0) return -1; esp_send_cmd("ATE0", "OK", 1000); /* 关回显,失败不致命 */ if (esp_send_cmd("AT+CWMODE=1", "OK", 2000) != 0) return -1; /* ① 优先等模块自动连接已保存的AP(SmartConfig/历史CWJAP保存的); ② 失败则连代码里固定的SSID(60s);③ 再失败进SmartConfig(60s) */ if (esp_wait_got_ip(20) != 0) { if (esp_join_fixed_ap() != 0) { if (esp_smartconfig() != 0) { log_warn("> WiFi: all AP attempts failed"); return -1; } } } /* TCP 透传到 MQTT 服务器 */ if (esp_enter_transparent(MqttInfoStr.ServerIP, MqttInfoStr.ServerPort) != 0) return -1; /* 软件 MQTT 建链 + 订阅下行主题 */ mqttc_init(MqttInfoStr.ClientID, MqttInfoStr.Username, MqttInfoStr.Passward); if (mqttc_connect() != 0) return -1; { char topic_down[48]; snprintf(topic_down, sizeof(topic_down), "%s%s", MqttInfoStr.Topic, MqttInfoStr.ClientID); if (mqttc_subscribe(topic_down) != 0) return -1; snprintf(s_topic_up, sizeof(s_topic_up), "/iot/data/up/%s", MqttInfoStr.ClientID); } g_wifi_mqtt_ready = 1; s_ping_tick = HAL_GetTick(); log_info("> WiFi: Ready"); /* 就绪后上报一次电量,与 4G 就绪行为对齐(同时标记首次发布成功) */ NET_publish_power(1); return 0; } /*==== 非阻塞轮询:下行报文解析 + 心跳保活 ====*/ void net_wifi_process(void) { if (!g_wifi_mqtt_ready) return; int r; while ((r = mqttc_process()) == 1) { } if (r == -1) { log_warn("> WiFi: TCP closed, need reconnect"); g_wifi_mqtt_ready = 0; return; } /* 30s 一次 PINGREQ;上一帧 PINGREQ 未收到 PINGRESP 判断链 */ if (HAL_GetTick() - s_ping_tick >= 30000) { if (g_mqttc_ping_outstanding) { log_warn("> WiFi: ping timeout, need reconnect"); g_wifi_mqtt_ready = 0; return; } s_ping_tick = HAL_GetTick(); mqttc_ping(); } } /*==== 上行发布 ====*/ void net_wifi_publish_up(const char *json) { if (!g_wifi_mqtt_ready) return; if (mqttc_publish(s_topic_up, json) == 0 && !g_wifi_first_publish_ok) { g_wifi_first_publish_ok = 1; log_info("> WiFi: first publish ok"); } }