|
@@ -12,6 +12,7 @@ extern uint8_t Devicenum;
|
|
|
extern uint8_t g_wifi_rx_buf[WIFI_RX_BUF_SIZE];
|
|
extern uint8_t g_wifi_rx_buf[WIFI_RX_BUF_SIZE];
|
|
|
extern uint32_t g_wifi_rx_last;
|
|
extern uint32_t g_wifi_rx_last;
|
|
|
extern uint32_t g_wifi_rx_head;
|
|
extern uint32_t g_wifi_rx_head;
|
|
|
|
|
+extern uint32_t g_wifi_rx_last_tick; /* 最近一次收到ESP数据的时间戳(10ms单位) */
|
|
|
uint8_t wifi_tx_buf[WIFI_TX_BUF_SIZE];
|
|
uint8_t wifi_tx_buf[WIFI_TX_BUF_SIZE];
|
|
|
uint16_t wifi_tx_len;
|
|
uint16_t wifi_tx_len;
|
|
|
|
|
|
|
@@ -741,10 +742,645 @@ void WIFI_send_deal(void)
|
|
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+/* ========================================================================
|
|
|
|
|
+ * 热点配网(SoftAP WiFi配网)状态机
|
|
|
|
|
+ * 触发 : 按键长按30s -> WIFI_provision_request() (usr_motor.c)
|
|
|
|
|
+ * 流程 : 复位ESP32 -> AP模式(AT+CWMODE=2) -> 建热点
|
|
|
|
|
+ * OneChip_Mini7 / test1234 (192.168.4.1/255.255.255.0)
|
|
|
|
|
+ * -> AT+CIPAP? 查询热点IP -> AT+CWDHCP? 查询DHCP状态
|
|
|
|
|
+ * -> AT+CIPMUX=1 -> AT+CIPSERVER=1,8002 启动TCP服务
|
|
|
|
|
+ * -> 手机连接热点,经TCP 8002下发:
|
|
|
|
|
+ * {"ssid":"Onechip_602","password":"onchip1003"}
|
|
|
|
|
+ * -> 解析JSON, ssid->sysinf.wifiname, password->sysinf.password
|
|
|
|
|
+ * -> cfg_save_cfg_param() 保存到Flash
|
|
|
|
|
+ * -> 复位ESP32进入正常STA模式(按新配置自动连接)
|
|
|
|
|
+ * 说明 : 热点地址192.168.4.1/255.255.255.0为ESP32 SoftAP默认值,无需配置
|
|
|
|
|
+ * ===================================================================== */
|
|
|
|
|
+#define WIFI_PROV_AP_SSID "OneChip_Mini7" /* 热点名称 */
|
|
|
|
|
+#define WIFI_PROV_AP_PWD "test1234" /* 热点密码 */
|
|
|
|
|
+#define WIFI_PROV_AP_CHANNEL 6 /* 信道 */
|
|
|
|
|
+#define WIFI_PROV_AP_ECN 3 /* 加密:3=WPA2_PSK */
|
|
|
|
|
+#define WIFI_PROV_TCP_PORT 8002 /* TCP服务端口 */
|
|
|
|
|
+
|
|
|
|
|
+#define WIFI_PROV_CMD_TIMEOUT 500 /* 单条AT指令超时:5s(10ms) */
|
|
|
|
|
+#define WIFI_PROV_RST_TIMEOUT 1000 /* AT+RST等待ready:10s */
|
|
|
|
|
+#define WIFI_PROV_LISTEN_TIMEOUT 30000 /* 等待配网数据总超时:300s */
|
|
|
|
|
+#define WIFI_PROV_MAX_RETRY 3 /* 指令失败重试次数 */
|
|
|
|
|
+#define WIFI_PROV_RX_IDLE_TIMEOUT 100 /* 无有效IPD残留数据清空时限:1s(10ms) */
|
|
|
|
|
+
|
|
|
|
|
+typedef enum
|
|
|
|
|
+{
|
|
|
|
|
+ WIFI_PROV_IDLE = 0, /* 空闲 */
|
|
|
|
|
+ WIFI_PROV_START, /* 启动初始化 */
|
|
|
|
|
+ WIFI_PROV_RST, /* 复位ESP32,重启进入AP主机模式 */
|
|
|
|
|
+ WIFI_PROV_WAIT_READY, /* 等待模块重启完成 */
|
|
|
|
|
+ WIFI_PROV_MODE, /* AT+CWMODE=2 设置AP模式 */
|
|
|
|
|
+ WIFI_PROV_SAP, /* AT+CWSAP 建立热点 */
|
|
|
|
|
+ WIFI_PROV_IP_Q, /* AT+CIPAP? 查询SoftAP接口IP(默认192.168.4.1) */
|
|
|
|
|
+ WIFI_PROV_DHCP_Q, /* AT+CWDHCP? 查询DHCP使能状态 */
|
|
|
|
|
+ WIFI_PROV_MUX, /* AT+CIPMUX=1 打开多连接 */
|
|
|
|
|
+ WIFI_PROV_SERVER, /* AT+CIPSERVER=1,8002 启动TCP服务 */
|
|
|
|
|
+ WIFI_PROV_LISTEN, /* 等待手机下发配网JSON */
|
|
|
|
|
+ WIFI_PROV_ACK_SEND, /* AT+CIPSEND 向手机应答 */
|
|
|
|
|
+ WIFI_PROV_ACK_DATA, /* 等待'>'并发送应答数据 */
|
|
|
|
|
+ WIFI_PROV_SAVE, /* 保存配置到Flash */
|
|
|
|
|
+ WIFI_PROV_DONE, /* 配网完成,复位进入正常模式 */
|
|
|
|
|
+} wifi_prov_state_t;
|
|
|
|
|
+
|
|
|
|
|
+static volatile uint8_t wifi_prov_request = 0; /* 配网请求标志(可被ISR置位) */
|
|
|
|
|
+static uint8_t wifi_prov_active = 0; /* 配网进行中 */
|
|
|
|
|
+static uint8_t wifi_prov_state = WIFI_PROV_IDLE;
|
|
|
|
|
+static uint8_t wifi_prov_retry = 0;
|
|
|
|
|
+static uint8_t wifi_prov_wait = 0; /* 1=正在等待应答 */
|
|
|
|
|
+static uint8_t wifi_prov_json_ok = 0; /* 解析到的配置是否有效 */
|
|
|
|
|
+static uint8_t wifi_prov_linkid = 0; /* TCP链路ID */
|
|
|
|
|
+static uint32_t wifi_prov_tick = 0; /* 起始时间戳(10ms单位) */
|
|
|
|
|
+static uint32_t wifi_prov_timeout = 0; /* 等待超时(10ms单位) */
|
|
|
|
|
+static char wifi_prov_ipd[WIFI_RX_BUF_SIZE];/* +IPD载荷累积缓存(JSON) */
|
|
|
|
|
+static uint16_t wifi_prov_ipd_len = 0;
|
|
|
|
|
+static char wifi_prov_ack[WIFI_RX_BUF_SIZE];/* 应答JSON */
|
|
|
|
|
+
|
|
|
|
|
+static void wifi_prov_enter(void);
|
|
|
|
|
+static void wifi_prov_exit(void);
|
|
|
|
|
+static void wifi_prov_abort(void);
|
|
|
|
|
+
|
|
|
|
|
+/* 配网进行中? */
|
|
|
|
|
+uint8_t WIFI_provision_active(void)
|
|
|
|
|
+{
|
|
|
|
|
+ return wifi_prov_active;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 请求进入热点配网模式(按键长按30s调用,允许在中断中调用) */
|
|
|
|
|
+uint8_t WIFI_provision_request(void)
|
|
|
|
|
+{
|
|
|
|
|
+ if (wifi_prov_active != 0)
|
|
|
|
|
+ return 0; /* 已在配网中 */
|
|
|
|
|
+ wifi_prov_request = 1;
|
|
|
|
|
+ return 1;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 配网状态机内部发送AT指令 */
|
|
|
|
|
+static void wifi_prov_send_cmd(const char *cmd, uint32_t timeout10ms)
|
|
|
|
|
+{
|
|
|
|
|
+ char buff[128] = {0};
|
|
|
|
|
+
|
|
|
|
|
+ strcpy(buff, cmd);
|
|
|
|
|
+ strcat(buff, "\r\n");
|
|
|
|
|
+ Van_Device_Printf(VAN_LOG_WIFI, "\nP--> %s", buff);
|
|
|
|
|
+ WriteComm2(buff, strlen(buff));
|
|
|
|
|
+
|
|
|
|
|
+ wifi_prov_wait = 1;
|
|
|
|
|
+ wifi_prov_tick = sysinf.conter10ms;
|
|
|
|
|
+ wifi_prov_timeout = timeout10ms;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 从ESP接收环中提取一个完整的+IPD报文载荷并追加到累积缓存
|
|
|
|
|
+ * 返回: 1=取到完整报文; 0=暂无完整报文(继续等待);
|
|
|
|
|
+ * -1=帧头/载荷异常(不打印、不清空、不消费,继续等待直到总超时退出) */
|
|
|
|
|
+static int wifi_prov_capture_ipd(void)
|
|
|
|
|
+{
|
|
|
|
|
+ uint32_t head = g_wifi_rx_head;
|
|
|
|
|
+ uint32_t last = g_wifi_rx_last;
|
|
|
|
|
+ uint32_t avail = (last + WIFI_RX_BUF_SIZE - head) % WIFI_RX_BUF_SIZE;
|
|
|
|
|
+ int pos = -1;
|
|
|
|
|
+ uint32_t i;
|
|
|
|
|
+
|
|
|
|
|
+ if (avail == 0)
|
|
|
|
|
+ return 0;
|
|
|
|
|
+
|
|
|
|
|
+ /* 查找"+IPD,"头 */
|
|
|
|
|
+ for (i = 0; (i + 5) <= avail; i++)
|
|
|
|
|
+ {
|
|
|
|
|
+ uint32_t p = (head + i) % WIFI_RX_BUF_SIZE;
|
|
|
|
|
+ if (g_wifi_rx_buf[p] == '+' &&
|
|
|
|
|
+ g_wifi_rx_buf[(p + 1) % WIFI_RX_BUF_SIZE] == 'I' &&
|
|
|
|
|
+ g_wifi_rx_buf[(p + 2) % WIFI_RX_BUF_SIZE] == 'P' &&
|
|
|
|
|
+ g_wifi_rx_buf[(p + 3) % WIFI_RX_BUF_SIZE] == 'D' &&
|
|
|
|
|
+ g_wifi_rx_buf[(p + 4) % WIFI_RX_BUF_SIZE] == ',')
|
|
|
|
|
+ {
|
|
|
|
|
+ pos = (int)i;
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if (pos < 0)
|
|
|
|
|
+ return 0; /* 缓冲内无+IPD报文 */
|
|
|
|
|
+
|
|
|
|
|
+ i = (uint32_t)(pos + 5);
|
|
|
|
|
+ if (i >= avail)
|
|
|
|
|
+ return 0; /* 帧头不完整,继续等待 */
|
|
|
|
|
+
|
|
|
|
|
+ /* 解析头: +IPD,<linkID>,<len>: */
|
|
|
|
|
+ if (g_wifi_rx_buf[(head + i) % WIFI_RX_BUF_SIZE] < '0' ||
|
|
|
|
|
+ g_wifi_rx_buf[(head + i) % WIFI_RX_BUF_SIZE] > '9')
|
|
|
|
|
+ return -1; /* linkid非数字,帧损坏 */
|
|
|
|
|
+ {
|
|
|
|
|
+ uint32_t linkid = 0;
|
|
|
|
|
+ while (i < avail &&
|
|
|
|
|
+ g_wifi_rx_buf[(head + i) % WIFI_RX_BUF_SIZE] >= '0' &&
|
|
|
|
|
+ g_wifi_rx_buf[(head + i) % WIFI_RX_BUF_SIZE] <= '9')
|
|
|
|
|
+ {
|
|
|
|
|
+ linkid = linkid * 10 + (uint32_t)(g_wifi_rx_buf[(head + i) % WIFI_RX_BUF_SIZE] - '0');
|
|
|
|
|
+ i++;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (i >= avail)
|
|
|
|
|
+ return 0; /* linkid未完,继续等待 */
|
|
|
|
|
+ if (g_wifi_rx_buf[(head + i) % WIFI_RX_BUF_SIZE] != ',')
|
|
|
|
|
+ return -1; /* 缺少逗号分隔,帧损坏 */
|
|
|
|
|
+ wifi_prov_linkid = (uint8_t)linkid;
|
|
|
|
|
+ i++;
|
|
|
|
|
+ if (i >= avail)
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ if (g_wifi_rx_buf[(head + i) % WIFI_RX_BUF_SIZE] < '0' ||
|
|
|
|
|
+ g_wifi_rx_buf[(head + i) % WIFI_RX_BUF_SIZE] > '9')
|
|
|
|
|
+ return -1; /* 长度非数字,帧损坏 */
|
|
|
|
|
+ {
|
|
|
|
|
+ uint32_t pktlen = 0;
|
|
|
|
|
+ while (i < avail &&
|
|
|
|
|
+ g_wifi_rx_buf[(head + i) % WIFI_RX_BUF_SIZE] >= '0' &&
|
|
|
|
|
+ g_wifi_rx_buf[(head + i) % WIFI_RX_BUF_SIZE] <= '9')
|
|
|
|
|
+ {
|
|
|
|
|
+ pktlen = pktlen * 10 + (uint32_t)(g_wifi_rx_buf[(head + i) % WIFI_RX_BUF_SIZE] - '0');
|
|
|
|
|
+ i++;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (i >= avail)
|
|
|
|
|
+ return 0; /* len未完,继续等待 */
|
|
|
|
|
+ if (g_wifi_rx_buf[(head + i) % WIFI_RX_BUF_SIZE] != ':')
|
|
|
|
|
+ return -1; /* 缺少冒号分隔,帧损坏 */
|
|
|
|
|
+ i++; /* 跳过 ':' */
|
|
|
|
|
+ if (pktlen == 0)
|
|
|
|
|
+ return -1; /* 空载荷异常 */
|
|
|
|
|
+ if (avail < i + pktlen)
|
|
|
|
|
+ return 0; /* 载荷尚未收完,继续等待 */
|
|
|
|
|
+
|
|
|
|
|
+ if ((uint16_t)(wifi_prov_ipd_len + pktlen) < sizeof(wifi_prov_ipd))
|
|
|
|
|
+ {
|
|
|
|
|
+ uint32_t k;
|
|
|
|
|
+ for (k = 0; k < pktlen; k++)
|
|
|
|
|
+ {
|
|
|
|
|
+ char c = (char)g_wifi_rx_buf[(head + i + k) % WIFI_RX_BUF_SIZE];
|
|
|
|
|
+ if (c == '\r' || c == '\n') /* 去掉行结束符 */
|
|
|
|
|
+ continue;
|
|
|
|
|
+ wifi_prov_ipd[wifi_prov_ipd_len++] = c;
|
|
|
|
|
+ }
|
|
|
|
|
+ wifi_prov_ipd[wifi_prov_ipd_len] = '\0';
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ /* 载荷超限无法累积: 丢弃该帧载荷,重新接收 */
|
|
|
|
|
+ wifi_prov_ipd_len = 0;
|
|
|
|
|
+ wifi_prov_ipd[0] = '\0';
|
|
|
|
|
+ }
|
|
|
|
|
+ /* 消费该报文 */
|
|
|
|
|
+ g_wifi_rx_head = (head + i + pktlen) % WIFI_RX_BUF_SIZE;
|
|
|
|
|
+ return 1;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 解析配网JSON: {"ssid":"xxx","password":"xxx"}
|
|
|
|
|
+ * 返回: 0=成功; -1=失败 */
|
|
|
|
|
+static int wifi_prov_parse_json(const char *json, char *ssid, uint16_t ssidCap,
|
|
|
|
|
+ char *pwd, uint16_t pwdCap)
|
|
|
|
|
+{
|
|
|
|
|
+ cJSON *root = NULL;
|
|
|
|
|
+ cJSON *it = NULL;
|
|
|
|
|
+ int rlt = -1;
|
|
|
|
|
+
|
|
|
|
|
+ if (json == NULL || json[0] != '{' || ssid == NULL || pwd == NULL)
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ ssid[0] = '\0';
|
|
|
|
|
+ pwd[0] = '\0';
|
|
|
|
|
+
|
|
|
|
|
+ root = cJSON_Parse(json);
|
|
|
|
|
+ if (root == NULL)
|
|
|
|
|
+ return -1;
|
|
|
|
|
+
|
|
|
|
|
+ it = cJSON_GetObjectItem(root, "ssid");
|
|
|
|
|
+ if (it == NULL || !cJSON_IsString(it) || it->valuestring == NULL ||
|
|
|
|
|
+ it->valuestring[0] == '\0')
|
|
|
|
|
+ goto out; /* 必须包含非空ssid */
|
|
|
|
|
+ if (strlen(it->valuestring) >= (size_t)ssidCap)
|
|
|
|
|
+ goto out; /* ssid超长 */
|
|
|
|
|
+ strcpy(ssid, it->valuestring);
|
|
|
|
|
+
|
|
|
|
|
+ it = cJSON_GetObjectItem(root, "password");
|
|
|
|
|
+ if (it != NULL && cJSON_IsString(it) && it->valuestring != NULL)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (strlen(it->valuestring) >= (size_t)pwdCap)
|
|
|
|
|
+ goto out; /* 密码超长 */
|
|
|
|
|
+ strcpy(pwd, it->valuestring); /* 允许开放网络密码为空 */
|
|
|
|
|
+ }
|
|
|
|
|
+ rlt = 0;
|
|
|
|
|
+
|
|
|
|
|
+out:
|
|
|
|
|
+ cJSON_Delete(root);
|
|
|
|
|
+ return rlt;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 生成应答JSON */
|
|
|
|
|
+static void wifi_prov_build_ack(uint8_t accepted, const char *reason)
|
|
|
|
|
+{
|
|
|
|
|
+ if (accepted)
|
|
|
|
|
+ {
|
|
|
|
|
+ my_sprintf(wifi_prov_ack, sizeof(wifi_prov_ack),
|
|
|
|
|
+ "{\"v\":1,\"status\":\"accepted\",\"sn\":\"%s\"}\r\n",
|
|
|
|
|
+ sysinf.SN);
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ if (reason == NULL)
|
|
|
|
|
+ reason = "invalid";
|
|
|
|
|
+ my_sprintf(wifi_prov_ack, sizeof(wifi_prov_ack),
|
|
|
|
|
+ "{\"v\":1,\"status\":\"rejected\",\"reason\":\"%s\"}\r\n",
|
|
|
|
|
+ reason);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 进入热点配网模式 */
|
|
|
|
|
+static void wifi_prov_enter(void)
|
|
|
|
|
+{
|
|
|
|
|
+ wifi_prov_active = 1;
|
|
|
|
|
+ wifi_prov_state = WIFI_PROV_START;
|
|
|
|
|
+ wifi_prov_retry = 0;
|
|
|
|
|
+ wifi_prov_wait = 0;
|
|
|
|
|
+ wifi_prov_linkid = 0;
|
|
|
|
|
+ wifi_prov_json_ok = 0;
|
|
|
|
|
+ wifi_prov_ipd_len = 0;
|
|
|
|
|
+ wifi_prov_ipd[0] = '\0';
|
|
|
|
|
+
|
|
|
|
|
+ memset(wifi_tx_buf, 0, sizeof(wifi_tx_buf));
|
|
|
|
|
+ wifi_tx_len = 0;
|
|
|
|
|
+ wifi_ack_delay = 0;
|
|
|
|
|
+ wifi_state = WIFI_POWEROFF; /* 暂停正常wifi流程 */
|
|
|
|
|
+ wifi_receive_clear();
|
|
|
|
|
+
|
|
|
|
|
+ Van_Device_Printf(VAN_LOG_WIFI,
|
|
|
|
|
+ "\r\n[Provision] enter, AP=%s pwd=%s port=%d",
|
|
|
|
|
+ WIFI_PROV_AP_SSID, WIFI_PROV_AP_PWD, WIFI_PROV_TCP_PORT);
|
|
|
|
|
+ beep_set(BEEP_SCANOK); /* 提示进入配网 */
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 退出热点配网,回到正常STA流程 */
|
|
|
|
|
+static void wifi_prov_exit(void)
|
|
|
|
|
+{
|
|
|
|
|
+ wifi_prov_active = 0;
|
|
|
|
|
+ wifi_prov_request = 0;
|
|
|
|
|
+ wifi_prov_state = WIFI_PROV_IDLE;
|
|
|
|
|
+ wifi_prov_wait = 0;
|
|
|
|
|
+ wifi_prov_ipd_len = 0;
|
|
|
|
|
+ wifi_prov_ipd[0] = '\0';
|
|
|
|
|
+
|
|
|
|
|
+ memset(wifi_tx_buf, 0, sizeof(wifi_tx_buf));
|
|
|
|
|
+ wifi_tx_len = 0;
|
|
|
|
|
+ wifi_ack_delay = 0;
|
|
|
|
|
+ wifi_receive_clear();
|
|
|
|
|
+
|
|
|
|
|
+ /* 交给正常流程:WIFI_POWEROFF会先AT+RST复位模块,再按新配置重连 */
|
|
|
|
|
+ WIFI_set_ssid();
|
|
|
|
|
+ Van_Device_Printf(VAN_LOG_WIFI, "\r\n[Provision] exit to normal STA");
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 配网失败,恢复到正常STA模式 */
|
|
|
|
|
+static void wifi_prov_abort(void)
|
|
|
|
|
+{
|
|
|
|
|
+ Van_Device_Printf(VAN_LOG_WIFI, "\r\n[Provision] abort, exit to normal STA");
|
|
|
|
|
+ wifi_prov_exit();
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 检查AT指令应答;收到OK后切到okState;出错则重试,超过次数退出配网
|
|
|
|
|
+ * 返回: 1=收到OK并已切状态; 0=仍在等待; -1=失败(已重发或已中止) */
|
|
|
|
|
+static int wifi_prov_check_cmd_resp(uint8_t okState)
|
|
|
|
|
+{
|
|
|
|
|
+ if (NULL != find_str_loop(g_wifi_rx_buf, WIFI_RX_BUF_SIZE, &g_wifi_rx_head,
|
|
|
|
|
+ g_wifi_rx_last, "OK\r\n"))
|
|
|
|
|
+ {
|
|
|
|
|
+ wifi_receive_clear();
|
|
|
|
|
+ wifi_prov_wait = 0;
|
|
|
|
|
+ wifi_prov_retry = 0;
|
|
|
|
|
+ wifi_prov_state = okState;
|
|
|
|
|
+ return 1;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (NULL != find_str_loop(g_wifi_rx_buf, WIFI_RX_BUF_SIZE, &g_wifi_rx_head,
|
|
|
|
|
+ g_wifi_rx_last, "ERROR") ||
|
|
|
|
|
+ (uint32_t)(sysinf.conter10ms - wifi_prov_tick) >= wifi_prov_timeout)
|
|
|
|
|
+ {
|
|
|
|
|
+ wifi_receive_clear();
|
|
|
|
|
+ wifi_prov_wait = 0;
|
|
|
|
|
+ if (++wifi_prov_retry < WIFI_PROV_MAX_RETRY)
|
|
|
|
|
+ return -1; /* 由状态机重发指令 */
|
|
|
|
|
+ wifi_prov_abort();
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ }
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 查询类AT指令处理: 发送AT+CIPAP?/AT+CWDHCP?后等待回复,收到OK(或超时)后
|
|
|
|
|
+ * 将完整应答打印到调试日志并切到okState状态
|
|
|
|
|
+ * 返回: 0=仍在等待; 1=已收到回复并切状态 */
|
|
|
|
|
+static uint8_t wifi_prov_query_done(uint8_t okState)
|
|
|
|
|
+{
|
|
|
|
|
+ char tmp[WIFI_RX_BUF_SIZE];
|
|
|
|
|
+ uint32_t head = g_wifi_rx_head;
|
|
|
|
|
+ uint32_t last = g_wifi_rx_last;
|
|
|
|
|
+ uint32_t n = 0;
|
|
|
|
|
+
|
|
|
|
|
+ if (wifi_prov_wait == 0)
|
|
|
|
|
+ return 0;
|
|
|
|
|
+
|
|
|
|
|
+ /* 线性化接收缓冲,便于查找与打印 */
|
|
|
|
|
+ while (head != last && n < (uint32_t)(WIFI_RX_BUF_SIZE - 1))
|
|
|
|
|
+ {
|
|
|
|
|
+ tmp[n++] = (char)g_wifi_rx_buf[head];
|
|
|
|
|
+ head = (head + 1) % WIFI_RX_BUF_SIZE;
|
|
|
|
|
+ }
|
|
|
|
|
+ tmp[n] = '\0';
|
|
|
|
|
+
|
|
|
|
|
+ if (strstr(tmp, "OK") != NULL ||
|
|
|
|
|
+ (uint32_t)(sysinf.conter10ms - wifi_prov_tick) >= wifi_prov_timeout)
|
|
|
|
|
+ {
|
|
|
|
|
+ /* 打印查询结果(含OK结尾),确认热点IP与DHCP状态 */
|
|
|
|
|
+ Van_Device_Printf(VAN_LOG_WIFI, "\r\n[Provision] <-%s", tmp);
|
|
|
|
|
+ wifi_receive_clear();
|
|
|
|
|
+ wifi_prov_wait = 0;
|
|
|
|
|
+ wifi_prov_retry = 0;
|
|
|
|
|
+ wifi_prov_state = okState;
|
|
|
|
|
+ return 1;
|
|
|
|
|
+ }
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 热点配网状态机主处理(每次进入WIFI_process调用) */
|
|
|
|
|
+static void wifi_prov_process(void)
|
|
|
|
|
+{
|
|
|
|
|
+ switch (wifi_prov_state)
|
|
|
|
|
+ {
|
|
|
|
|
+ case WIFI_PROV_IDLE:
|
|
|
|
|
+ default:
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
|
|
+ /* 启动初始化 */
|
|
|
|
|
+ case WIFI_PROV_START:
|
|
|
|
|
+ wifi_receive_clear();
|
|
|
|
|
+ wifi_prov_ipd_len = 0;
|
|
|
|
|
+ wifi_prov_ipd[0] = '\0';
|
|
|
|
|
+ wifi_prov_wait = 0;
|
|
|
|
|
+ wifi_prov_state = WIFI_PROV_RST;
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
|
|
+ /* 1. 复位ESP32,重启进入AP主机模式 */
|
|
|
|
|
+ case WIFI_PROV_RST:
|
|
|
|
|
+ wifi_prov_send_cmd("AT+RST", WIFI_PROV_RST_TIMEOUT);
|
|
|
|
|
+ wifi_prov_state = WIFI_PROV_WAIT_READY;
|
|
|
|
|
+ wifi_prov_retry = 0;
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
|
|
+ case WIFI_PROV_WAIT_READY:
|
|
|
|
|
+ if (NULL != find_str_loop(g_wifi_rx_buf, WIFI_RX_BUF_SIZE, &g_wifi_rx_head,
|
|
|
|
|
+ g_wifi_rx_last, "ready") ||
|
|
|
|
|
+ NULL != find_str_loop(g_wifi_rx_buf, WIFI_RX_BUF_SIZE, &g_wifi_rx_head,
|
|
|
|
|
+ g_wifi_rx_last, "boot"))
|
|
|
|
|
+ {
|
|
|
|
|
+ wifi_receive_clear();
|
|
|
|
|
+ wifi_prov_state = WIFI_PROV_MODE;
|
|
|
|
|
+ }
|
|
|
|
|
+ else if ((uint32_t)(sysinf.conter10ms - wifi_prov_tick) >= wifi_prov_timeout)
|
|
|
|
|
+ {
|
|
|
|
|
+ wifi_receive_clear();
|
|
|
|
|
+ if (++wifi_prov_retry < WIFI_PROV_MAX_RETRY)
|
|
|
|
|
+ wifi_prov_state = WIFI_PROV_RST; /* 重试复位 */
|
|
|
|
|
+ else
|
|
|
|
|
+ wifi_prov_abort();
|
|
|
|
|
+ }
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
|
|
+ /* 2. 设置AP模式 */
|
|
|
|
|
+ case WIFI_PROV_MODE:
|
|
|
|
|
+ if (wifi_prov_wait != 0)
|
|
|
|
|
+ wifi_prov_check_cmd_resp(WIFI_PROV_SAP);
|
|
|
|
|
+ else
|
|
|
|
|
+ wifi_prov_send_cmd("AT+CWMODE=2", WIFI_PROV_CMD_TIMEOUT);
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
|
|
+ /* 3. 建立热点: 名称OneChip_Mini7, 密码test1234 */
|
|
|
|
|
+ case WIFI_PROV_SAP:
|
|
|
|
|
+ {
|
|
|
|
|
+ char cStr[128] = {0};
|
|
|
|
|
+ if (wifi_prov_wait != 0)
|
|
|
|
|
+ wifi_prov_check_cmd_resp(WIFI_PROV_IP_Q);
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ my_sprintf(cStr, sizeof(cStr), "AT+CWSAP=\"%s\",\"%s\",%d,%d",
|
|
|
|
|
+ WIFI_PROV_AP_SSID, WIFI_PROV_AP_PWD,
|
|
|
|
|
+ WIFI_PROV_AP_CHANNEL, WIFI_PROV_AP_ECN);
|
|
|
|
|
+ wifi_prov_send_cmd(cStr, WIFI_PROV_CMD_TIMEOUT);
|
|
|
|
|
+ }
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /* 4. 查询SoftAP接口IP(默认192.168.4.1),确认热点地址 */
|
|
|
|
|
+ case WIFI_PROV_IP_Q:
|
|
|
|
|
+ if (wifi_prov_wait != 0)
|
|
|
|
|
+ wifi_prov_query_done(WIFI_PROV_DHCP_Q);
|
|
|
|
|
+ else
|
|
|
|
|
+ wifi_prov_send_cmd("AT+CIPAP?", WIFI_PROV_CMD_TIMEOUT);
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
|
|
+ /* 5. 查询DHCP使能状态(确认AP侧能分配192.168.4.x) */
|
|
|
|
|
+ case WIFI_PROV_DHCP_Q:
|
|
|
|
|
+ if (wifi_prov_wait != 0)
|
|
|
|
|
+ wifi_prov_query_done(WIFI_PROV_MUX);
|
|
|
|
|
+ else
|
|
|
|
|
+ wifi_prov_send_cmd("AT+CWDHCP?", WIFI_PROV_CMD_TIMEOUT);
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
|
|
+ /* 6. 打开多连接 */
|
|
|
|
|
+ case WIFI_PROV_MUX:
|
|
|
|
|
+ if (wifi_prov_wait != 0)
|
|
|
|
|
+ wifi_prov_check_cmd_resp(WIFI_PROV_SERVER);
|
|
|
|
|
+ else
|
|
|
|
|
+ wifi_prov_send_cmd("AT+CIPMUX=1", WIFI_PROV_CMD_TIMEOUT);
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
|
|
+ /* 7. 启动TCP服务端: 端口8002 */
|
|
|
|
|
+ case WIFI_PROV_SERVER:
|
|
|
|
|
+ {
|
|
|
|
|
+ char cStr[48] = {0};
|
|
|
|
|
+ if (wifi_prov_wait != 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (wifi_prov_check_cmd_resp(WIFI_PROV_LISTEN) == 1)
|
|
|
|
|
+ wifi_prov_tick = sysinf.conter10ms; /* 记录开始等待配网的时间 */
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ my_sprintf(cStr, sizeof(cStr), "AT+CIPSERVER=1,%d", WIFI_PROV_TCP_PORT);
|
|
|
|
|
+ wifi_prov_send_cmd(cStr, WIFI_PROV_CMD_TIMEOUT);
|
|
|
|
|
+ }
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /* 8. 等待手机经TCP下发配网JSON(总超时300s) */
|
|
|
|
|
+ case WIFI_PROV_LISTEN:
|
|
|
|
|
+ if ((uint32_t)(sysinf.conter10ms - wifi_prov_tick) >= WIFI_PROV_LISTEN_TIMEOUT)
|
|
|
|
|
+ {
|
|
|
|
|
+ Van_Device_Printf(VAN_LOG_WIFI, "\r\n[Provision] wait cfg timeout");
|
|
|
|
|
+ wifi_prov_wait = 0;
|
|
|
|
|
+ wifi_prov_state = WIFI_PROV_DONE; /* 超时未收到配置,直接退出 */
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ /* 接收并解析+IPD报文 */
|
|
|
|
|
+ {
|
|
|
|
|
+ int ipdRlt = wifi_prov_capture_ipd();
|
|
|
|
|
+ if (ipdRlt > 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (wifi_prov_ipd_len >= (uint16_t)(sizeof(wifi_prov_ipd) - 2))
|
|
|
|
|
+ {
|
|
|
|
|
+ /* 累积超限,丢弃重收 */
|
|
|
|
|
+ wifi_receive_clear();
|
|
|
|
|
+ wifi_prov_ipd_len = 0;
|
|
|
|
|
+ wifi_prov_ipd[0] = '\0';
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ /* 存在接收数据但未解析出有效+IPD,且距最近接收超1s: 打印残留并清空 */
|
|
|
|
|
+ if (g_wifi_rx_head != g_wifi_rx_last &&
|
|
|
|
|
+ (uint32_t)(sysinf.conter10ms - g_wifi_rx_last_tick) >= WIFI_PROV_RX_IDLE_TIMEOUT)
|
|
|
|
|
+ {
|
|
|
|
|
+ Van_Device_Printf(VAN_LOG_WIFI, "\r\n%s", g_wifi_rx_buf);
|
|
|
|
|
+ wifi_receive_clear();
|
|
|
|
|
+ wifi_prov_ipd_len = 0;
|
|
|
|
|
+ wifi_prov_ipd[0] = '\0';
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ /* 累积到完整JSON后解析 */
|
|
|
|
|
+ if (wifi_prov_ipd_len > 0 &&
|
|
|
|
|
+ wifi_prov_ipd[0] == '{' &&
|
|
|
|
|
+ wifi_prov_ipd[wifi_prov_ipd_len - 1] == '}')
|
|
|
|
|
+ {
|
|
|
|
|
+ char ssid[sizeof(sysinf.wifiname)];
|
|
|
|
|
+ char pwd[sizeof(sysinf.password)];
|
|
|
|
|
+ if (wifi_prov_parse_json(wifi_prov_ipd, ssid, (uint16_t)sizeof(ssid),
|
|
|
|
|
+ pwd, (uint16_t)sizeof(pwd)) == 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ memset(sysinf.wifiname, 0, sizeof(sysinf.wifiname));
|
|
|
|
|
+ memset(sysinf.password, 0, sizeof(sysinf.password));
|
|
|
|
|
+ strcpy(sysinf.wifiname, ssid);
|
|
|
|
|
+ strcpy(sysinf.password, pwd);
|
|
|
|
|
+ wifi_prov_json_ok = 1;
|
|
|
|
|
+ Van_Device_Printf(VAN_LOG_WIFI, "\r\n[Provision] got cfg: ssid=%s pwd=%s",
|
|
|
|
|
+ sysinf.wifiname, sysinf.password);
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ wifi_prov_json_ok = 0;
|
|
|
|
|
+ Van_Device_Printf(VAN_LOG_WIFI, "\r\n[Provision] bad json: %s",
|
|
|
|
|
+ wifi_prov_ipd);
|
|
|
|
|
+ }
|
|
|
|
|
+ wifi_prov_build_ack(wifi_prov_json_ok, "invalid");
|
|
|
|
|
+ wifi_prov_state = WIFI_PROV_ACK_SEND;
|
|
|
|
|
+ }
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
|
|
+ /* 9. 向手机应答(accepted/rejected) */
|
|
|
|
|
+ case WIFI_PROV_ACK_SEND:
|
|
|
|
|
+ {
|
|
|
|
|
+ char cStr[48] = {0};
|
|
|
|
|
+ Van_Device_Printf(VAN_LOG_WIFI, "\r\nack json: %s",
|
|
|
|
|
+ wifi_prov_ack);
|
|
|
|
|
+ wifi_receive_clear();
|
|
|
|
|
+ my_sprintf(cStr, sizeof(cStr), "AT+CIPSEND=%d,%d",
|
|
|
|
|
+ wifi_prov_linkid, (int)strlen(wifi_prov_ack));
|
|
|
|
|
+ wifi_prov_send_cmd(cStr, WIFI_PROV_CMD_TIMEOUT);
|
|
|
|
|
+ /* CIPSEND属非透传"先握手后发数": 复位wait,由ACK_DATA收到OK后真正发载荷 */
|
|
|
|
|
+ wifi_prov_wait = 0;
|
|
|
|
|
+ wifi_prov_state = WIFI_PROV_ACK_DATA;
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ case WIFI_PROV_ACK_DATA:
|
|
|
|
|
+ if (wifi_prov_wait == 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ /* 等待 'OK\r\n' 提示符后发送应答数据 */
|
|
|
|
|
+ if(NULL != find_str_loop(g_wifi_rx_buf, WIFI_RX_BUF_SIZE ,&g_wifi_rx_head, g_wifi_rx_last, "OK\r\n"))
|
|
|
|
|
+ {
|
|
|
|
|
+ wifi_receive_clear();
|
|
|
|
|
+ wifi_prov_wait = 1;
|
|
|
|
|
+ wifi_prov_tick = sysinf.conter10ms;
|
|
|
|
|
+ wifi_prov_timeout = WIFI_PROV_CMD_TIMEOUT;
|
|
|
|
|
+ WriteComm2(wifi_prov_ack, strlen(wifi_prov_ack));
|
|
|
|
|
+ }
|
|
|
|
|
+ else if (NULL != find_str_loop(g_wifi_rx_buf, WIFI_RX_BUF_SIZE, &g_wifi_rx_head,
|
|
|
|
|
+ g_wifi_rx_last, "ERROR") ||
|
|
|
|
|
+ NULL != find_str_loop(g_wifi_rx_buf, WIFI_RX_BUF_SIZE, &g_wifi_rx_head,
|
|
|
|
|
+ g_wifi_rx_last, "CLOSED") ||
|
|
|
|
|
+ (uint32_t)(sysinf.conter10ms - wifi_prov_tick) >= wifi_prov_timeout)
|
|
|
|
|
+ {
|
|
|
|
|
+ /* 应答失败或超时,继续后续流程 */
|
|
|
|
|
+ Van_Device_Printf(VAN_LOG_WIFI, "\r\n%s", g_wifi_rx_buf);
|
|
|
|
|
+ wifi_receive_clear();
|
|
|
|
|
+ wifi_prov_wait = 0;
|
|
|
|
|
+ wifi_prov_state = (wifi_prov_json_ok != 0) ? WIFI_PROV_SAVE : WIFI_PROV_LISTEN;
|
|
|
|
|
+ wifi_prov_ipd_len = 0;
|
|
|
|
|
+ wifi_prov_ipd[0] = '\0';
|
|
|
|
|
+ if (wifi_prov_json_ok == 0)
|
|
|
|
|
+ wifi_prov_tick = sysinf.conter10ms; /* 重新计时 */
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ /* 等待SEND OK */
|
|
|
|
|
+ if (NULL != find_str_loop(g_wifi_rx_buf, WIFI_RX_BUF_SIZE, &g_wifi_rx_head,
|
|
|
|
|
+ g_wifi_rx_last, "SEND OK") ||
|
|
|
|
|
+ NULL != find_str_loop(g_wifi_rx_buf, WIFI_RX_BUF_SIZE, &g_wifi_rx_head,
|
|
|
|
|
+ g_wifi_rx_last, "ERROR") ||
|
|
|
|
|
+ NULL != find_str_loop(g_wifi_rx_buf, WIFI_RX_BUF_SIZE, &g_wifi_rx_head,
|
|
|
|
|
+ g_wifi_rx_last, "CLOSED") ||
|
|
|
|
|
+ (uint32_t)(sysinf.conter10ms - wifi_prov_tick) >= wifi_prov_timeout)
|
|
|
|
|
+ {
|
|
|
|
|
+ Van_Device_Printf(VAN_LOG_WIFI, "\r\n%s", g_wifi_rx_buf);
|
|
|
|
|
+ wifi_receive_clear();
|
|
|
|
|
+ wifi_prov_wait = 0;
|
|
|
|
|
+ wifi_prov_state = (wifi_prov_json_ok != 0) ? WIFI_PROV_SAVE : WIFI_PROV_LISTEN;
|
|
|
|
|
+ wifi_prov_ipd_len = 0; /* 无效配置则清空缓存重新等待 */
|
|
|
|
|
+ wifi_prov_ipd[0] = '\0';
|
|
|
|
|
+ if (wifi_prov_json_ok == 0)
|
|
|
|
|
+ wifi_prov_tick = sysinf.conter10ms; /* 重新计时 */
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
|
|
+ /* 10. 保存配网参数到Flash */
|
|
|
|
|
+ case WIFI_PROV_SAVE:
|
|
|
|
|
+ {
|
|
|
|
|
+ uint8_t saveRlt = cfg_save_cfg_param();
|
|
|
|
|
+ Van_Device_Printf(VAN_LOG_WIFI, "\r\n[Provision] cfg_save_cfg_param=%d", saveRlt);
|
|
|
|
|
+ wifi_prov_state = WIFI_PROV_DONE;
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /* 11. 配网完成: 复位ESP32进入正常模式 */
|
|
|
|
|
+ case WIFI_PROV_DONE:
|
|
|
|
|
+ wifi_prov_exit();
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
|
|
|
//wifi任务
|
|
//wifi任务
|
|
|
void WIFI_process()
|
|
void WIFI_process()
|
|
|
{
|
|
{
|
|
|
|
|
+ /* 热点配网模式优先处理 */
|
|
|
|
|
+ if (wifi_prov_request != 0 || wifi_prov_active != 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (wifi_prov_request != 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ wifi_prov_request = 0;
|
|
|
|
|
+ wifi_prov_enter();
|
|
|
|
|
+ }
|
|
|
|
|
+ wifi_prov_process();
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
if(sysinf.pc_channel_recv == 2 && wifi_state > WIFI_SETMUX){
|
|
if(sysinf.pc_channel_recv == 2 && wifi_state > WIFI_SETMUX){
|
|
|
/*串口状态下,不走wifi处理*/
|
|
/*串口状态下,不走wifi处理*/
|