#include "ESP32_WROOM_32D.h" #include #include extern int Flag3S; #define g_uMsgCmdFrameLen (6) extern uint8_t Devicenum; extern uint8_t g_wifi_rx_buf[WIFI_RX_BUF_SIZE]; extern volatile uint32_t g_wifi_rx_last; extern volatile uint8_t g_wifi_rx_fault; extern volatile uint32_t g_wifi_rx_head; uint8_t wifi_tx_buf[WIFI_TX_BUF_SIZE]; uint16_t wifi_tx_len; static int wifi_state = 0; //WiFi模块当前状态 static int wifi_ack_delay = 0; //WiFi应答等待 static int wifi_set_ssid = 0; //WiFi应答SSID设置 uint32_t unlink_time = 0; extern uint32_t pc_link_timeout; char TCP_IP_PORT[8] = {"8001"}; char MAC_ADDR[20] = {0}; uint32_t broadDevFlag = 0; extern uint8_t pc_channel_recv; /* TX and AT transactions share one UART; only the initial CIPSEND may enter * WAIT_PROMPT. An uncertain timeout never sends another AT into data mode. */ enum { TX_IDLE, TX_WAIT_PROMPT, TX_WAIT_RESULT, TX_FAULT }; static unsigned tx_phase; static uint32_t at_started, tx_started; static uint32_t retry_started; static int retry_wait; static int at_pending, at_owner, at_retries; static int deferred_close, ap_found, link_is_tcp; static unsigned rx_line_len, rx_ipd_left, rx_ipd_accept, rx_frame_len; static uint32_t rx_last_byte; static char rx_line[256]; static uint8_t rx_frame[CMD_BUF_SIZE + 9]; static volatile uint8_t prov_request; static uint8_t prov_active, prov_step, prov_link, prov_bad, prov_ready; static uint32_t prov_started; static char prov_json[256]; static unsigned prov_len; static void wifi_provision_process(void); static int wifi_provision_line(const char *line); static void wifi_provision_byte(uint8_t byte); static void wifi_line(const char *line); static void wifi_fault(const char *why); static void wifi_rx_reset(void) { rx_line_len = rx_ipd_left = rx_ipd_accept = rx_frame_len = 0; } static void wifi_enter(int state) { wifi_state = state; at_pending = 0; wifi_ack_delay = 0; at_retries = 0; retry_wait = 0; if (state != WIFI_TRANS) broadDevFlag = 0; } static void wifi_fault(const char *why) { if (tx_phase == TX_FAULT) return; Van_Device_Printf(VAN_LOG_WIFI, "\nWiFi uncertain UART phase: %s; reset ESP to recover\n", why); tx_phase = TX_FAULT; at_pending = 0; wifi_ack_delay = 0; wifi_tx_len = 0; broadDevFlag = 0; wifi_rx_reset(); } uint16_t WriteComm2(char *data, uint16_t len) { return (uint16_t)HAL_UART_Transmit((UART_HandleTypeDef *)sysinf.ESPUart, (const uint8_t *)data, len, 1000); } void ESP32_Send_AT_Cmd(char *cmd, uint32_t time) { char buff[256]; int n; if (tx_phase != TX_IDLE || at_pending) return; n = my_sprintf(buff, sizeof(buff), "%s\r\n", cmd); if (n < 0 || (unsigned)n >= sizeof(buff)) { Van_Device_Printf(VAN_LOG_WIFI, "\nAT command too long\n"); return; } at_started = HAL_GetTick(); wifi_ack_delay = time; at_owner = wifi_state; at_pending = 1; if (strncmp(cmd, "AT+CWJAP=", 9) && strncmp(cmd, "AT+CWSAP=", 9)) Van_Device_Printf(VAN_LOG_WIFI, "\nW--> %s", buff); if (WriteComm2(buff, (uint16_t)n) != HAL_OK) wifi_fault("AT UART write"); } void ESP32_AT(void) { ESP32_Send_AT_Cmd("AT",5000); } /*恢复出厂设置*/ void ESP32_AT_Restore(void) { ESP32_Send_AT_Cmd("AT+RESTORE",500); } /*复位*/ void ESP32_AT_RST(void) { ESP32_Send_AT_Cmd("AT+RST",8000); } /*上电自动连接AP*/ void ESP32_AT_AUTOCONN(void) { ESP32_Send_AT_Cmd("AT+CWAUTOCONN=0",5000); } /*WIFI AP/STA/AP+STA模式选择*/ void ESP32_Net_Mode_Choose(ENUM_Net_ModeTypeDef enumMode) { switch ( enumMode ) { case STA: ESP32_Send_AT_Cmd ( "AT+CWMODE=1", 5000 ); break; case AP: ESP32_Send_AT_Cmd ( "AT+CWMODE=2", 5000 ); break; case STA_AP: ESP32_Send_AT_Cmd ( "AT+CWMODE=3", 5000 ); break; default: break; } } /*WIFI加入AP*/ void ESP32_JoinAP( char * pSSID, char * pPassWord, char * pMacAddr) { char cCmd [192]; my_sprintf ( cCmd, sizeof(cCmd), "AT+CWJAP=\"%s\",\"%s\",\"%s\"", pSSID, pPassWord,pMacAddr); ESP32_Send_AT_Cmd( cCmd,5000 ); } /*WIFI建立AP*/ void ESP32_SetupAP( char * pSSID, char * pPassWord) { char cCmd [192]; my_sprintf ( cCmd,sizeof(cCmd), "AT+CWSAP=\"%s\",\"%s\"", pSSID, pPassWord ); ESP32_Send_AT_Cmd( cCmd, 5000 ); } /*WIFI查询IP*/ void ESP32_GetIp(void) { ESP32_Send_AT_Cmd( "AT+CIPSTA?", 5000 ); } /*WIFI禁止自动连接*/ void ESP32_DisAutoLink(void) { ESP32_Send_AT_Cmd( "AT+CWAUTOCONN=0", 5000 ); } void ESP32_CWLAP(char * pSSID) { char cCmd [80]; my_sprintf ( cCmd, sizeof(cCmd), "AT+CWLAP=\"%s\"", pSSID); ESP32_Send_AT_Cmd( cCmd, 5000 ); } /*WIFI关闭回显*/ void ESP32_EchoOff(void) { ESP32_Send_AT_Cmd( "ATE0", 5000 ); } /*WIFI初始化*/ void ESP32_Init(void) { ESP32_Send_AT_Cmd( "+++", 5000 ); } /*WIFI 单/多连接*/ void ESP32_Enable_MultipleId (uint8_t enumEnUnvarnishTx ) { char cCmd [20]; my_sprintf ( cCmd, sizeof(cCmd), "AT+CIPMUX=%d", ( enumEnUnvarnishTx ? 1 : 0 ) ); ESP32_Send_AT_Cmd ( cCmd, 5000 ); } /*WIFI AP作为服务端开启或关闭,1---开启服务:0---关闭服务*/ void ESP32_AP_Server (uint8_t open) { char cCmd [192]; my_sprintf ( cCmd,sizeof(cCmd), "AT+CIPSERVER=%d", open); ESP32_Send_AT_Cmd( cCmd, 5000 ); } /*WIFI STA选择TCP或UDP协议*/ void ESP32_Link_Server(ENUM_NetPro_TypeDef enumE, char * ip, char * ComNum, ENUM_ID_NO_TypeDef id) { char cStr [100] = { 0 }, cCmd [128]; switch ( enumE ) { case enumTCP: my_sprintf ( cStr, sizeof(cStr), "\"%s\",\"%s\",%s,6", "TCP", ip, ComNum ); break; case enumUDP: my_sprintf ( cStr,sizeof(cStr), "\"%s\",\"%s\",%s,9090,0", "UDP", ip, ComNum ); break; default: break; } if ( id < 5 ) my_sprintf ( cCmd,sizeof(cCmd), "AT+CIPSTART=%d,%s", id, cStr); else my_sprintf ( cCmd, sizeof(cCmd), "AT+CIPSTART=%s", cStr ); ESP32_Send_AT_Cmd ( cCmd,5000 ); } /*WIFI透传*/ void ESP32_UnvarnishSend ( void ) { ESP32_Send_AT_Cmd( "AT+CIPMODE=1", 5000 );//设置透传模式 } /*WIFI停止TCP*/ void ESP32_STOPTCP ( ENUM_ID_NO_TypeDef id ) { char cCmd [60]; my_sprintf ( cCmd,sizeof(cCmd), "AT+CIPCLOSE=%d", id); ESP32_Send_AT_Cmd ( cCmd, 20000 ); } /*退出透传*/ void ESP32_ExitUnvarnishSend( void ) { ESP32_Send_AT_Cmd("+++", 5000); } ///*设置默认波特率为460800*/ //void ESP32_SET_BUAR(void) //{ // ESP32_Send_AT_Cmd("AT+UART_DEF=460800,8,1,0,0","OK",NULL,500); //} int WIFI_ReSend(void) { char cmd[40]; if (!wifi_tx_len) return 0; if ((!prov_active && wifi_state != WIFI_TRANS) || tx_phase == TX_FAULT) return -1; if (tx_phase != TX_IDLE || at_pending) return -2; if (wifi_tx_len > WIFI_TX_BUF_SIZE) return -3; my_sprintf(cmd, sizeof(cmd), "AT+CIPSEND=%d,%d", prov_active ? prov_link : 0, wifi_tx_len); ESP32_Send_AT_Cmd(cmd, 3000); if (tx_phase == TX_FAULT) return -4; at_pending = 0; tx_phase = TX_WAIT_PROMPT; tx_started = HAL_GetTick(); return 0; } int WIFI_Send_Data(uint8_t *data, uint16_t len, uint8_t flag) { int ret; if (prov_active || wifi_state != WIFI_TRANS || tx_phase != TX_IDLE || at_pending) return -1; if (wifi_tx_len) return -2; if (!data || !len || len > WIFI_TX_BUF_SIZE) return -3; memcpy(wifi_tx_buf, data, len); wifi_tx_len = len; if (!flag) return 0; ret = WIFI_ReSend(); return ret < 0 ? ret : len; } int WIFI_Send_MSG(uint8_t *head, uint8_t *data, uint8_t *crc, uint16_t len) { int ret; if (prov_active || wifi_state != WIFI_TRANS || tx_phase != TX_IDLE || at_pending || wifi_tx_len) return -1; if (!head || !crc || (!data && len) || len > WIFI_TX_BUF_SIZE - 8) return -2; memcpy(wifi_tx_buf, head, 6); if (len) memcpy(wifi_tx_buf + 6, data, len); memcpy(wifi_tx_buf + 6 + len, crc, 2); wifi_tx_len = len + 8; ret = WIFI_ReSend(); return ret < 0 ? ret : len + 8; } int WIFI_SendIlde(void) { return !prov_active && wifi_state == WIFI_TRANS && tx_phase == TX_IDLE && !at_pending && wifi_tx_len == 0; } void WIFI_set_ssid(void) { wifi_set_ssid = 1; deferred_close = 1; } void WIFI_set_CloseConnect(void) { deferred_close = 1; } /* Retained helper, with a valid-range bound at every candidate position. */ char *find_str_loop(void *src, int size, volatile uint32_t *start, uint32_t end, char *str) { unsigned offset, length, valid, i, pos; uint8_t *b = src; if (!src || !start || !str || size <= 0 || *start >= (unsigned)size || end >= (unsigned)size) return NULL; length = strlen(str); valid = (end + size - *start) % size; for (offset = 0; offset + length <= valid; ++offset) { pos = (*start + offset) % size; for (i = 0; i < length && b[(pos + i) % size] == (uint8_t)str[i]; ++i) {} if (i == length) { *start = (pos + length) % size; return (char *)(b + pos); } } return NULL; } /* Only a complete, bounded frame is passed to the project's DecodeNew. * A private linear window avoids its empty-ring ambiguity and preserves the * hardware RX cursor. DecodeNew owns checksum and protocol decoding. */ static void wifi_frame_byte(uint8_t byte) { unsigned length, total, cursor; uint8_t payload[CMD_BUF_SIZE + 1]; CmdMessage message; rx_frame[rx_frame_len++] = byte; while (rx_frame_len) { if (rx_frame[0] != 0xaa || (rx_frame_len > 1 && rx_frame[1] != 0x55)) goto discard; if (rx_frame_len < 6) return; length = rx_frame[4] | ((unsigned)rx_frame[5] << 8); if (length > CMD_BUF_SIZE) goto discard; total = length + 8; if (rx_frame_len < total) return; cursor = 0; memset(&message, 0, sizeof(message)); if (DecodeNew(&message, payload, rx_frame, &cursor, total, sizeof(rx_frame)) <= 0) goto discard; payload[length] = 0; message.data = (char *)payload; /* Consume before dispatch: callbacks may request a close or enqueue TX. */ rx_frame_len -= total; memmove(rx_frame, rx_frame + total, rx_frame_len); if (message.cmd == PC_CMD_SETIP && length >= 5 && memcmp(payload, "Mini7", 5) == 0) continue; sysinf.pc_channel_recv = PC_CONNECT_TYPE_WIFI; sysinf.pc_link_timeout = 0; Van_Device_Printf(VAN_LOG_WIFI, "\nWiFi RX cmd=%d len=%d", message.cmd, length); #ifdef ONECHIP_MINI_ONE if (message.cmd == UINON_CMD_THEROM_GET && length == 4) deal_mUnion_cmd(&message); else #endif query_pc_cmd(&message); continue; discard: --rx_frame_len; memmove(rx_frame, rx_frame + 1, rx_frame_len); } } static void wifi_rx_byte(uint8_t byte) { char *end, *begin; unsigned long id, length; if (rx_ipd_left) { --rx_ipd_left; if (rx_ipd_accept && tx_phase != TX_FAULT) { if (prov_active) wifi_provision_byte(byte); else wifi_frame_byte(byte); } return; } if (!rx_line_len && byte == '>') { wifi_line(">"); return; } if (!rx_line_len && (byte == '\r' || byte == '\n' || byte == ' ')) return; if (rx_line_len == sizeof(rx_line) - 1) { wifi_fault("AT line overflow"); return; } rx_line[rx_line_len++] = byte; rx_line[rx_line_len] = 0; if (byte == ':' && strncmp(rx_line, "+IPD,", 5) == 0) { begin = rx_line + 5; id = strtoul(begin, &end, 10); if (*begin < '0' || *begin > '9' || end == begin || *end != ',' || id > 4) goto malformed; begin = end + 1; length = strtoul(begin, &end, 10); if (*begin < '0' || *begin > '9' || end == begin || *end != ':' || end[1] || length > 65535) goto malformed; rx_ipd_left = length; rx_ipd_accept = (id == 0); if (prov_active) { rx_ipd_accept = (prov_step == 10 && id <= 4 && (!prov_len || prov_link == id)); if (rx_ipd_accept) prov_link = (uint8_t)id; } rx_line_len = 0; return; } if (byte == '\n') { while (rx_line_len && (rx_line[rx_line_len - 1] == '\r' || rx_line[rx_line_len - 1] == '\n')) rx_line[--rx_line_len] = 0; wifi_line(rx_line); rx_line_len = 0; } return; malformed: wifi_fault("invalid +IPD header"); } static void wifi_online(void) { wifi_enter(WIFI_TRANS); broadDevFlag = 1; sysinf.s10_flag = 1; } static void wifi_line(const char *line) { const char *p, *q; if (prov_active && wifi_provision_line(line)) return; if (at_pending && (!strcmp(line, "ERROR") || !strcmp(line, "FAIL"))) Van_Device_Printf(VAN_LOG_WIFI, "\nWiFi AT state=%d reply=%s\n", wifi_state, line); if (strcmp(line, "ready") == 0) { tx_phase = TX_IDLE; wifi_tx_len = 0; wifi_rx_reset(); wifi_enter(WIFI_POWERON); return; } if (tx_phase == TX_FAULT) return; if (strcmp(line, ">") == 0) { if (tx_phase != TX_WAIT_PROMPT) { Van_Device_Printf(VAN_LOG_WIFI, "\nWiFi unexpected prompt ignored\n"); return; } tx_phase = TX_WAIT_RESULT; tx_started = HAL_GetTick(); wifi_ack_delay = 7000; /* TCP SO_SNDTIMEO=6000 plus MCU margin. */ if (WriteComm2((char *)wifi_tx_buf, wifi_tx_len) != HAL_OK) wifi_fault("payload UART write"); return; } if (!strcmp(line, "SEND OK") || !strcmp(line, "SEND FAIL")) { if (tx_phase == TX_WAIT_RESULT) { Van_Device_Printf(VAN_LOG_WIFI, "\nW<-- %s\n", line); tx_phase = TX_IDLE; wifi_tx_len = 0; wifi_ack_delay = 0; } return; } /* CWJAP can disconnect the old association before joining the requested AP. * Wait for its final OK/FAIL instead of resetting an in-progress join. */ if (!strcmp(line, "WIFI DISCONNECT") && wifi_state == WIFI_LINK_AP && at_pending) return; if (!strcmp(line, "0,CLOSED") || !strcmp(line, "CLOSED") || !strcmp(line, "WIFI DISCONNECT")) { if (tx_phase == TX_WAIT_PROMPT) { wifi_fault("closed before prompt"); return; } tx_phase = TX_IDLE; wifi_tx_len = 0; rx_frame_len = 0; wifi_enter(!strcmp(line, "WIFI DISCONNECT") ? WIFI_POWEROFF : WIFI_LISTEN); return; } if (wifi_state == WIFI_CWLAP && strncmp(line, "+CWLAP:", 7) == 0) { /* Quoted strings are SSID and BSSID; RSSI between them is numeric. */ p = strchr(line, '"'); if (!p) return; q = strchr(p + 1, '"'); if (!q) return; if ((unsigned)(q - p - 1) != strlen(sysinf.wifiname) || memcmp(p + 1, sysinf.wifiname, q - p - 1)) return; p = strchr(q + 1, '"'); if (!p) return; q = strchr(p + 1, '"'); if (!q || q - p - 1 != 17) return; memcpy(MAC_ADDR, p + 1, 17); MAC_ADDR[17] = 0; ap_found = 1; return; } if (!strcmp(line, "ERROR") || !strcmp(line, "FAIL")) { if (tx_phase == TX_WAIT_PROMPT) { /* Explicit rejection: ESP did not enter data mode. Upper layer retries. */ tx_phase = TX_IDLE; wifi_tx_len = 0; wifi_ack_delay = 0; } else if (tx_phase == TX_WAIT_RESULT) { wifi_fault("ERROR during payload transaction"); } else if (at_pending) { at_pending = 0; wifi_ack_delay = 0; if (wifi_state == WIFI_TCPOPT) wifi_enter(WIFI_CLOSE); retry_wait = 1; retry_started = HAL_GetTick(); } return; } if (strcmp(line, "OK") || !at_pending || at_owner != wifi_state) return; at_pending = 0; wifi_ack_delay = 0; switch (wifi_state) { case WIFI_POWEROFF: /* AT+RST's OK is not the boot-ready notification. */ case WIFI_ERROR: at_pending = 1; at_started = HAL_GetTick(); wifi_ack_delay = 8000; break; case WIFI_POWERON: wifi_enter(WIFI_INIT); break; case WIFI_INIT: wifi_enter(WIFI_STATION); break; case WIFI_STATION: wifi_enter(WIFI_CWLAP); break; case WIFI_CWLAP: if (ap_found) wifi_enter(WIFI_DISAUTO); else { Van_Device_Printf(VAN_LOG_WIFI, "\nWiFi scan completed: configured SSID not found\n"); retry_wait = 1; retry_started = HAL_GetTick(); } break; case WIFI_DISAUTO: wifi_enter(WIFI_LINK_AP); break; case WIFI_LINK_AP: wifi_enter(WIFI_GET_IP); break; case WIFI_GET_IP: if (wifi_set_ssid) { char result = 1; wifi_set_ssid = 0; data_send_to_pc(PC_CMD_SETWIFI, &result, 1); } wifi_enter(WIFI_SETMUX); break; case WIFI_SETMUX: wifi_enter(WIFI_IPDINFO); break; case WIFI_IPDINFO: wifi_enter(WIFI_LISTEN); break; case WIFI_LISTEN: if (link_is_tcp) wifi_enter(WIFI_TCPOPT); else wifi_online(); break; case WIFI_TCPOPT: wifi_online(); break; case WIFI_CLOSE: rx_frame_len = 0; wifi_enter(wifi_set_ssid ? WIFI_POWEROFF : WIFI_LISTEN); break; default: break; } } void WIFI_recv_deal(void) { unsigned budget = WIFI_RX_BUF_SIZE; if (g_wifi_rx_fault) { uint8_t cause = g_wifi_rx_fault; g_wifi_rx_fault = 0; g_wifi_rx_head = g_wifi_rx_last; wifi_fault((cause & 2) ? "UART hardware overrun" : "RX ring full"); } while (budget-- && g_wifi_rx_head != g_wifi_rx_last) { uint8_t byte = g_wifi_rx_buf[g_wifi_rx_head]; g_wifi_rx_head = (g_wifi_rx_head + 1) % WIFI_RX_BUF_SIZE; rx_last_byte = HAL_GetTick(); wifi_rx_byte(byte); } if (rx_ipd_left && (uint32_t)(HAL_GetTick() - rx_last_byte) >= 3000) wifi_fault("incomplete +IPD"); } void WIFI_send_deal(void) { uint32_t now = HAL_GetTick(); if (tx_phase == TX_FAULT) return; if (retry_wait) { if ((uint32_t)(now - retry_started) < 2000u) return; retry_wait = 0; } if (tx_phase != TX_IDLE) { if ((uint32_t)(now - tx_started) >= (tx_phase == TX_WAIT_PROMPT ? 3000u : 7000u)) wifi_fault(tx_phase == TX_WAIT_PROMPT ? "prompt timeout" : "SEND result timeout"); return; } if (at_pending) { if ((uint32_t)(now - at_started) < (uint32_t)wifi_ack_delay) return; at_pending = 0; wifi_ack_delay = 0; Van_Device_Printf(VAN_LOG_WIFI, "\nAT timeout state=%d\n", wifi_state); } if (deferred_close) { deferred_close = 0; wifi_tx_len = 0; wifi_enter(wifi_set_ssid ? WIFI_POWEROFF : WIFI_CLOSE); } if (wifi_state == WIFI_TRANS) { if (wifi_tx_len) WIFI_ReSend(); return; } if (++at_retries > MAX_RESEND_TIME) { if (wifi_set_ssid) { char result = (wifi_state == WIFI_CWLAP) ? 0xff : 0xfe; wifi_set_ssid = 0; data_send_to_pc(PC_CMD_SETWIFI, &result, 1); } wifi_enter(WIFI_POWEROFF); } switch (wifi_state) { case WIFI_POWEROFF: case WIFI_ERROR: ESP32_AT_RST(); break; case WIFI_POWERON: ESP32_AT(); break; case WIFI_INIT: ESP32_EchoOff(); break; case WIFI_STATION: ESP32_Net_Mode_Choose(STA); break; case WIFI_CWLAP: ap_found = 0; ESP32_CWLAP(sysinf.wifiname); break; case WIFI_DISAUTO: ESP32_DisAutoLink(); break; case WIFI_LINK_AP: ESP32_JoinAP(sysinf.wifiname, sysinf.password, MAC_ADDR); break; case WIFI_GET_IP: ESP32_GetIp(); break; case WIFI_SETMUX: ESP32_Enable_MultipleId(1); break; case WIFI_IPDINFO: ESP32_Send_AT_Cmd("AT+CIPDINFO=0", 3000); break; case WIFI_LISTEN: rx_frame_len = 0; link_is_tcp = sysinf.connectTcpFlag != 0; if (link_is_tcp) ESP32_Link_Server(enumTCP, sysinf.TCP_IP_Addr, sysinf.TCP_IP_PORT, Multiple_ID_0); else ESP32_Link_Server(enumUDP, User_ESP32_UDPServer_IP, User_ESP32_UDPServer_PORT, Multiple_ID_0); break; case WIFI_TCPOPT: ESP32_Send_AT_Cmd("AT+CIPTCPOPT=0,,,6000", 3000); break; case WIFI_CLOSE: ESP32_STOPTCP(Multiple_ID_0); break; default: wifi_enter(WIFI_POWEROFF); break; } } void WIFI_process(void) { WIFI_recv_deal(); if (prov_request && !prov_active && tx_phase == TX_IDLE && !at_pending) { prov_request = 0; prov_active = 1; prov_step = 0; prov_len = prov_bad = prov_ready = 0; wifi_tx_len = 0; wifi_rx_reset(); wifi_enter(WIFI_POWEROFF); Van_Device_Printf(VAN_LOG_WIFI, "\nProvision start\n"); } if (prov_active) wifi_provision_process(); else WIFI_send_deal(); } /* Keep the public formatter and make its length argument effective. */ int my_sprintf(char *out, unsigned int size, const char *format, ...) { int n; va_list args; if (!out || !size || !format) return -1; va_start(args, format); n = vsnprintf(out, size, format, args); va_end(args); out[size - 1] = 0; return n; } 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; } /* SoftAP uses the same stream parser and CIPSEND transaction as STA. */ uint8_t WIFI_provision_active(void) { return prov_active; } uint8_t WIFI_provision_request(void) { if (prov_active) return 0; prov_request = 1; return 1; } static void wifi_provision_byte(uint8_t byte) { if (prov_bad || prov_ready) return; if (prov_len >= sizeof(prov_json)-1) { prov_bad = 1; return; } if (byte == '\r' || byte == '\n') return; prov_json[prov_len++] = (char)byte; prov_json[prov_len] = 0; if (!rx_ipd_left && prov_len && prov_json[prov_len-1] == '}') prov_ready = 1; } static void wifi_provision_exit(void) { prov_active = 0; prov_step = 0; prov_len = 0; wifi_tx_len = 0; wifi_rx_reset(); wifi_enter(WIFI_POWEROFF); } static int wifi_provision_line(const char *line) { if (!strcmp(line, "ready")) { tx_phase = TX_IDLE; wifi_tx_len = 0; wifi_rx_reset(); at_pending = 0; wifi_ack_delay = 0; prov_step = 1; prov_started = HAL_GetTick(); return 1; } if (tx_phase != TX_IDLE) return 0; /* shared prompt/result handling */ if (at_pending && !strcmp(line, "OK")) { if (prov_step == 0) return 1; /* reset must finish with ready */ at_pending = 0; wifi_ack_delay = 0; ++prov_step; prov_started = HAL_GetTick(); return 1; } if (at_pending && (!strcmp(line, "ERROR") || !strcmp(line, "FAIL"))) { Van_Device_Printf(VAN_LOG_WIFI, "\nProvision command rejected step=%d\n", prov_step); wifi_provision_exit(); return 1; } return 1; } static void wifi_provision_process(void) { char cmd[160]; uint32_t now = HAL_GetTick(); if (tx_phase == TX_FAULT) return; if (tx_phase != TX_IDLE) { if ((uint32_t)(now-tx_started) >= (tx_phase == TX_WAIT_PROMPT ? 3000u : 7000u)) wifi_fault("provision send timeout"); return; } if (at_pending) { if ((uint32_t)(now-at_started) >= (uint32_t)wifi_ack_delay) { Van_Device_Printf(VAN_LOG_WIFI, "\nProvision command timeout step=%d\n", prov_step); wifi_provision_exit(); } return; } switch (prov_step) { case 0: ESP32_Send_AT_Cmd("AT+RST",10000); break; case 1: ESP32_Send_AT_Cmd("ATE0",5000); break; case 2: ESP32_Send_AT_Cmd("AT+CWMODE=2",5000); break; case 3: my_sprintf(cmd,sizeof(cmd),"AT+CWSAP=\"%s\",\"%s\",6,3","OneChip_Mini7","test1234"); ESP32_Send_AT_Cmd(cmd,5000); break; case 4: ESP32_Send_AT_Cmd("AT+CIPAP?",5000); break; case 5: ESP32_Send_AT_Cmd("AT+CWDHCP?",5000); break; case 6: ESP32_Send_AT_Cmd("AT+CIPMUX=1",5000); break; case 7: ESP32_Send_AT_Cmd("AT+CIPDINFO=0",5000); break; case 8: ESP32_Send_AT_Cmd("AT+CIPSERVER=1,8002",5000); break; case 9: prov_step=10; prov_started=now; break; case 10: if ((uint32_t)(now-prov_started)>=300000u) { wifi_provision_exit(); break; } if (prov_bad && !rx_ipd_left) { prov_len=prov_bad=prov_ready=0; break; } if (prov_ready && !rx_ipd_left) { char ssid[sizeof(sysinf.wifiname)], pwd[sizeof(sysinf.password)]; int valid = wifi_prov_parse_json(prov_json,ssid,sizeof(ssid),pwd,sizeof(pwd)) == 0; if (valid) { strcpy(sysinf.wifiname,ssid); strcpy(sysinf.password,pwd); valid = cfg_save_cfg_param() != 0; } if (valid) my_sprintf((char *)wifi_tx_buf,sizeof(wifi_tx_buf), "{\"v\":1,\"status\":\"accepted\",\"sn\":\"%.7s\"}\r\n", sysinf.SN); else my_sprintf((char *)wifi_tx_buf,sizeof(wifi_tx_buf), "{\"v\":1,\"status\":\"rejected\",\"reason\":\"invalid\"}\r\n"); wifi_tx_len = (uint16_t)strlen((char *)wifi_tx_buf); WIFI_ReSend(); prov_step = valid ? 11 : 12; } break; case 11: wifi_provision_exit(); break; case 12: prov_len=prov_bad=prov_ready=0; prov_step=10; prov_started=now; break; default: wifi_provision_exit(); break; } }