shuichan_old/V1.4-Chinese/STM32F103_App1/HardWare/NETWORK/net_wifi.c

161 lines
5.5 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* 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 "reset_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;
/* WiFi 模块恢复出厂请求标志:由蓝牙 RECOVERY 命令(sys任务)置位,
* net 任务在 net_wifi_process 里执行——所有 UART4 操作都收口在 net 任务,
* 避免与 4G 切换/建链并发冲突 */
volatile uint8_t g_wifi_restore_req = 0;
static uint32_t s_ping_tick = 0;
/* 上行发布主题暂存 */
static char s_topic_up[48];
/*==== 阻塞建链:成功返回 0 并置 g_wifi_mqtt_ready ====
* 子顺序由 EEPROM 记忆的"上次成功联网方式"决定:
* 上次是配网热点 → 先查已存 AP 自动连接(CIPSTATUS, 10s)
* 然后统一:固定 SSID(60s 倒计时) → SmartConfig(60s 倒计时)
* 成功后按实际使用的方式更新 EEPROM 记忆NET_SaveMode */
int net_wifi_init(void)
{
log_info("> WiFi: 初始化...");
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;
int joined = 0;
uint8_t via_smart = 0; /* 1=本次用的是配网热点已存AP或SmartConfig */
/* 上次是配网热点成功的:模块里存着该热点密码,优先查自动连接 */
if (NET_GetLastMode() == NET_MODE_WIFI_SMART) {
if (esp_saved_ap_connected(10) == 0) {
joined = 1;
via_smart = 1;
}
}
/* 连代码里固定的 SSID/PASS */
if (!joined && esp_join_fixed_ap() == 0) {
joined = 1;
via_smart = 0;
}
/* 固定热点连不上:进 SmartConfig 智能配网ESP-Touch APP 广播密码) */
if (!joined) {
if (esp_smartconfig() == 0) {
joined = 1;
via_smart = 1;
} else {
log_warn("> WiFi: 所有 AP 连接方式均失败");
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");
/* 更新联网方式记忆(仅变化时写 EEPROM */
NET_SaveMode(via_smart ? NET_MODE_WIFI_SMART : NET_MODE_WIFI_FIXED);
/* 就绪后上报一次电量,与 4G 就绪行为对齐(同时标记首次发布成功) */
NET_publish_power(1);
return 0;
}
/*==== 非阻塞轮询:下行报文解析 + 心跳保活 ====*/
void net_wifi_process(void)
{
/* 恢复出厂请求(蓝牙 RECOVERY在 net 任务上下文执行,
* 不与本任务的建链/收发并发 */
if (g_wifi_restore_req) {
g_wifi_restore_req = 0;
log_warn("> WiFi: 收到恢复出厂请求,执行 AT+RESTORE 并重启");
g_net_tx_busy = 1;
g_wifi_mqtt_ready = 0;
reset_log_mark(RSN_CMD_RECOVERY);
if (esp_factory_restore() != 0) {
log_warn("> WiFi: RESTORE 失败,仍强制重启");
}
HAL_Delay(100);
NVIC_SystemReset();
}
if (!g_wifi_mqtt_ready) return;
int r;
while ((r = mqttc_process()) == 1) { }
if (r == -1) {
/* 收到 CLOSED服务器主动断开 TCP被平台踢下线直接复位重连 */
log_error("> WiFi: 连接被服务器关闭(被平台踢下线),系统复位");
reset_log_mark(RSN_KICKED);
HAL_Delay(100);
NVIC_SystemReset();
}
/* 15s 一次 PINGREQ上一帧 PINGREQ 未收到 PINGRESP 判断链 */
if (HAL_GetTick() - s_ping_tick >= 15000) {
if (g_mqttc_ping_outstanding) {
/* 心跳超时:服务器无响应(假在线/网络异常),直接复位重连 */
log_error("> WiFi: 心跳超时(服务器无响应),系统复位");
reset_log_mark(RSN_PING_TIMEOUT);
HAL_Delay(100);
NVIC_SystemReset();
}
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: 首次发布成功");
}
}