ESP32_WROOM_32D.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789
  1. #include "ESP32_WROOM_32D.h"
  2. #include <stdlib.h>
  3. #include <stdarg.h>
  4. extern int Flag3S;
  5. #define g_uMsgCmdFrameLen (6)
  6. extern uint8_t Devicenum;
  7. extern uint8_t g_wifi_rx_buf[WIFI_RX_BUF_SIZE];
  8. extern volatile uint32_t g_wifi_rx_last;
  9. extern volatile uint8_t g_wifi_rx_fault;
  10. extern volatile uint32_t g_wifi_rx_head;
  11. uint8_t wifi_tx_buf[WIFI_TX_BUF_SIZE];
  12. uint16_t wifi_tx_len;
  13. static int wifi_state = 0; //WiFi模块当前状态
  14. static int wifi_ack_delay = 0; //WiFi应答等待
  15. static int wifi_set_ssid = 0; //WiFi应答SSID设置
  16. uint32_t unlink_time = 0;
  17. extern uint32_t pc_link_timeout;
  18. char TCP_IP_PORT[8] = {"8001"};
  19. char MAC_ADDR[20] = {0};
  20. uint32_t broadDevFlag = 0;
  21. extern uint8_t pc_channel_recv;
  22. /* TX and AT transactions share one UART; only the initial CIPSEND may enter
  23. * WAIT_PROMPT. An uncertain timeout never sends another AT into data mode. */
  24. enum { TX_IDLE, TX_WAIT_PROMPT, TX_WAIT_RESULT, TX_FAULT };
  25. static unsigned tx_phase;
  26. static uint32_t at_started, tx_started;
  27. static uint32_t retry_started;
  28. static int retry_wait;
  29. static int at_pending, at_owner, at_retries;
  30. static int deferred_close, ap_found, link_is_tcp;
  31. static unsigned rx_line_len, rx_ipd_left, rx_ipd_accept, rx_frame_len;
  32. static uint32_t rx_last_byte;
  33. static char rx_line[256];
  34. static uint8_t rx_frame[CMD_BUF_SIZE + 9];
  35. static volatile uint8_t prov_request;
  36. static uint8_t prov_active, prov_step, prov_link, prov_bad, prov_ready;
  37. static uint32_t prov_started;
  38. static char prov_json[256];
  39. static unsigned prov_len;
  40. static void wifi_provision_process(void);
  41. static int wifi_provision_line(const char *line);
  42. static void wifi_provision_byte(uint8_t byte);
  43. static void wifi_line(const char *line);
  44. static void wifi_fault(const char *why);
  45. static void wifi_rx_reset(void)
  46. {
  47. rx_line_len = rx_ipd_left = rx_ipd_accept = rx_frame_len = 0;
  48. }
  49. static void wifi_enter(int state)
  50. {
  51. wifi_state = state;
  52. at_pending = 0;
  53. wifi_ack_delay = 0;
  54. at_retries = 0;
  55. retry_wait = 0;
  56. if (state != WIFI_TRANS) broadDevFlag = 0;
  57. }
  58. static void wifi_fault(const char *why)
  59. {
  60. if (tx_phase == TX_FAULT) return;
  61. Van_Device_Printf(VAN_LOG_WIFI, "\nWiFi uncertain UART phase: %s; reset ESP to recover\n", why);
  62. tx_phase = TX_FAULT;
  63. at_pending = 0;
  64. wifi_ack_delay = 0;
  65. wifi_tx_len = 0;
  66. broadDevFlag = 0;
  67. wifi_rx_reset();
  68. }
  69. uint16_t WriteComm2(char *data, uint16_t len)
  70. {
  71. return (uint16_t)HAL_UART_Transmit((UART_HandleTypeDef *)sysinf.ESPUart,
  72. (const uint8_t *)data, len, 1000);
  73. }
  74. void ESP32_Send_AT_Cmd(char *cmd, uint32_t time)
  75. {
  76. char buff[256];
  77. int n;
  78. if (tx_phase != TX_IDLE || at_pending) return;
  79. n = my_sprintf(buff, sizeof(buff), "%s\r\n", cmd);
  80. if (n < 0 || (unsigned)n >= sizeof(buff)) {
  81. Van_Device_Printf(VAN_LOG_WIFI, "\nAT command too long\n");
  82. return;
  83. }
  84. at_started = HAL_GetTick();
  85. wifi_ack_delay = time;
  86. at_owner = wifi_state;
  87. at_pending = 1;
  88. if (strncmp(cmd, "AT+CWJAP=", 9) && strncmp(cmd, "AT+CWSAP=", 9))
  89. Van_Device_Printf(VAN_LOG_WIFI, "\nW--> %s", buff);
  90. if (WriteComm2(buff, (uint16_t)n) != HAL_OK) wifi_fault("AT UART write");
  91. }
  92. void ESP32_AT(void)
  93. {
  94. ESP32_Send_AT_Cmd("AT",5000);
  95. }
  96. /*恢复出厂设置*/
  97. void ESP32_AT_Restore(void)
  98. {
  99. ESP32_Send_AT_Cmd("AT+RESTORE",500);
  100. }
  101. /*复位*/
  102. void ESP32_AT_RST(void)
  103. {
  104. ESP32_Send_AT_Cmd("AT+RST",8000);
  105. }
  106. /*上电自动连接AP*/
  107. void ESP32_AT_AUTOCONN(void)
  108. {
  109. ESP32_Send_AT_Cmd("AT+CWAUTOCONN=0",5000);
  110. }
  111. /*WIFI AP/STA/AP+STA模式选择*/
  112. void ESP32_Net_Mode_Choose(ENUM_Net_ModeTypeDef enumMode)
  113. {
  114. switch ( enumMode )
  115. {
  116. case STA:
  117. ESP32_Send_AT_Cmd ( "AT+CWMODE=1", 5000 );
  118. break;
  119. case AP:
  120. ESP32_Send_AT_Cmd ( "AT+CWMODE=2", 5000 );
  121. break;
  122. case STA_AP:
  123. ESP32_Send_AT_Cmd ( "AT+CWMODE=3", 5000 );
  124. break;
  125. default:
  126. break;
  127. }
  128. }
  129. /*WIFI加入AP*/
  130. void ESP32_JoinAP( char * pSSID, char * pPassWord, char * pMacAddr)
  131. {
  132. char cCmd [192];
  133. my_sprintf ( cCmd, sizeof(cCmd), "AT+CWJAP=\"%s\",\"%s\",\"%s\"", pSSID, pPassWord,pMacAddr);
  134. ESP32_Send_AT_Cmd( cCmd,5000 );
  135. }
  136. /*WIFI建立AP*/
  137. void ESP32_SetupAP( char * pSSID, char * pPassWord)
  138. {
  139. char cCmd [192];
  140. my_sprintf ( cCmd,sizeof(cCmd), "AT+CWSAP=\"%s\",\"%s\"", pSSID, pPassWord );
  141. ESP32_Send_AT_Cmd( cCmd, 5000 );
  142. }
  143. /*WIFI查询IP*/
  144. void ESP32_GetIp(void)
  145. {
  146. ESP32_Send_AT_Cmd( "AT+CIPSTA?", 5000 );
  147. }
  148. /*WIFI禁止自动连接*/
  149. void ESP32_DisAutoLink(void)
  150. {
  151. ESP32_Send_AT_Cmd( "AT+CWAUTOCONN=0", 5000 );
  152. }
  153. void ESP32_CWLAP(char * pSSID)
  154. {
  155. char cCmd [80];
  156. my_sprintf ( cCmd, sizeof(cCmd), "AT+CWLAP=\"%s\"", pSSID);
  157. ESP32_Send_AT_Cmd( cCmd, 5000 );
  158. }
  159. /*WIFI关闭回显*/
  160. void ESP32_EchoOff(void)
  161. {
  162. ESP32_Send_AT_Cmd( "ATE0", 5000 );
  163. }
  164. /*WIFI初始化*/
  165. void ESP32_Init(void)
  166. {
  167. ESP32_Send_AT_Cmd( "+++", 5000 );
  168. }
  169. /*WIFI 单/多连接*/
  170. void ESP32_Enable_MultipleId (uint8_t enumEnUnvarnishTx )
  171. {
  172. char cCmd [20];
  173. my_sprintf ( cCmd, sizeof(cCmd), "AT+CIPMUX=%d", ( enumEnUnvarnishTx ? 1 : 0 ) );
  174. ESP32_Send_AT_Cmd ( cCmd, 5000 );
  175. }
  176. /*WIFI AP作为服务端开启或关闭,1---开启服务:0---关闭服务*/
  177. void ESP32_AP_Server (uint8_t open)
  178. {
  179. char cCmd [192];
  180. my_sprintf ( cCmd,sizeof(cCmd), "AT+CIPSERVER=%d", open);
  181. ESP32_Send_AT_Cmd( cCmd, 5000 );
  182. }
  183. /*WIFI STA选择TCP或UDP协议*/
  184. void ESP32_Link_Server(ENUM_NetPro_TypeDef enumE, char * ip, char * ComNum, ENUM_ID_NO_TypeDef id)
  185. {
  186. char cStr [100] = { 0 }, cCmd [128];
  187. switch ( enumE )
  188. {
  189. case enumTCP:
  190. my_sprintf ( cStr, sizeof(cStr), "\"%s\",\"%s\",%s,6", "TCP", ip, ComNum );
  191. break;
  192. case enumUDP:
  193. my_sprintf ( cStr,sizeof(cStr), "\"%s\",\"%s\",%s,9090,0", "UDP", ip, ComNum );
  194. break;
  195. default:
  196. break;
  197. }
  198. if ( id < 5 )
  199. my_sprintf ( cCmd,sizeof(cCmd), "AT+CIPSTART=%d,%s", id, cStr);
  200. else
  201. my_sprintf ( cCmd, sizeof(cCmd), "AT+CIPSTART=%s", cStr );
  202. ESP32_Send_AT_Cmd ( cCmd,5000 );
  203. }
  204. /*WIFI透传*/
  205. void ESP32_UnvarnishSend ( void )
  206. {
  207. ESP32_Send_AT_Cmd( "AT+CIPMODE=1", 5000 );//设置透传模式
  208. }
  209. /*WIFI停止TCP*/
  210. void ESP32_STOPTCP ( ENUM_ID_NO_TypeDef id )
  211. {
  212. char cCmd [60];
  213. my_sprintf ( cCmd,sizeof(cCmd), "AT+CIPCLOSE=%d", id);
  214. ESP32_Send_AT_Cmd ( cCmd, 20000 );
  215. }
  216. /*退出透传*/
  217. void ESP32_ExitUnvarnishSend( void )
  218. {
  219. ESP32_Send_AT_Cmd("+++", 5000);
  220. }
  221. ///*设置默认波特率为460800*/
  222. //void ESP32_SET_BUAR(void)
  223. //{
  224. // ESP32_Send_AT_Cmd("AT+UART_DEF=460800,8,1,0,0","OK",NULL,500);
  225. //}
  226. int WIFI_ReSend(void)
  227. {
  228. char cmd[40];
  229. if (!wifi_tx_len) return 0;
  230. if ((!prov_active && wifi_state != WIFI_TRANS) || tx_phase == TX_FAULT) return -1;
  231. if (tx_phase != TX_IDLE || at_pending) return -2;
  232. if (wifi_tx_len > WIFI_TX_BUF_SIZE) return -3;
  233. my_sprintf(cmd, sizeof(cmd), "AT+CIPSEND=%d,%d", prov_active ? prov_link : 0, wifi_tx_len);
  234. ESP32_Send_AT_Cmd(cmd, 3000);
  235. if (tx_phase == TX_FAULT) return -4;
  236. at_pending = 0;
  237. tx_phase = TX_WAIT_PROMPT;
  238. tx_started = HAL_GetTick();
  239. return 0;
  240. }
  241. int WIFI_Send_Data(uint8_t *data, uint16_t len, uint8_t flag)
  242. {
  243. int ret;
  244. if (prov_active || wifi_state != WIFI_TRANS || tx_phase != TX_IDLE || at_pending) return -1;
  245. if (wifi_tx_len) return -2;
  246. if (!data || !len || len > WIFI_TX_BUF_SIZE) return -3;
  247. memcpy(wifi_tx_buf, data, len);
  248. wifi_tx_len = len;
  249. if (!flag) return 0;
  250. ret = WIFI_ReSend();
  251. return ret < 0 ? ret : len;
  252. }
  253. int WIFI_Send_MSG(uint8_t *head, uint8_t *data, uint8_t *crc, uint16_t len)
  254. {
  255. int ret;
  256. if (prov_active || wifi_state != WIFI_TRANS || tx_phase != TX_IDLE || at_pending || wifi_tx_len) return -1;
  257. if (!head || !crc || (!data && len) || len > WIFI_TX_BUF_SIZE - 8) return -2;
  258. memcpy(wifi_tx_buf, head, 6);
  259. if (len) memcpy(wifi_tx_buf + 6, data, len);
  260. memcpy(wifi_tx_buf + 6 + len, crc, 2);
  261. wifi_tx_len = len + 8;
  262. ret = WIFI_ReSend();
  263. return ret < 0 ? ret : len + 8;
  264. }
  265. int WIFI_SendIlde(void)
  266. {
  267. return !prov_active && wifi_state == WIFI_TRANS && tx_phase == TX_IDLE && !at_pending && wifi_tx_len == 0;
  268. }
  269. void WIFI_set_ssid(void)
  270. {
  271. wifi_set_ssid = 1;
  272. deferred_close = 1;
  273. }
  274. void WIFI_set_CloseConnect(void)
  275. {
  276. deferred_close = 1;
  277. }
  278. /* Retained helper, with a valid-range bound at every candidate position. */
  279. char *find_str_loop(void *src, int size, volatile uint32_t *start, uint32_t end, char *str)
  280. {
  281. unsigned offset, length, valid, i, pos;
  282. uint8_t *b = src;
  283. if (!src || !start || !str || size <= 0 || *start >= (unsigned)size || end >= (unsigned)size) return NULL;
  284. length = strlen(str);
  285. valid = (end + size - *start) % size;
  286. for (offset = 0; offset + length <= valid; ++offset) {
  287. pos = (*start + offset) % size;
  288. for (i = 0; i < length && b[(pos + i) % size] == (uint8_t)str[i]; ++i) {}
  289. if (i == length) {
  290. *start = (pos + length) % size;
  291. return (char *)(b + pos);
  292. }
  293. }
  294. return NULL;
  295. }
  296. /* Only a complete, bounded frame is passed to the project's DecodeNew.
  297. * A private linear window avoids its empty-ring ambiguity and preserves the
  298. * hardware RX cursor. DecodeNew owns checksum and protocol decoding. */
  299. static void wifi_frame_byte(uint8_t byte)
  300. {
  301. unsigned length, total, cursor;
  302. uint8_t payload[CMD_BUF_SIZE + 1];
  303. CmdMessage message;
  304. rx_frame[rx_frame_len++] = byte;
  305. while (rx_frame_len) {
  306. if (rx_frame[0] != 0xaa || (rx_frame_len > 1 && rx_frame[1] != 0x55)) goto discard;
  307. if (rx_frame_len < 6) return;
  308. length = rx_frame[4] | ((unsigned)rx_frame[5] << 8);
  309. if (length > CMD_BUF_SIZE) goto discard;
  310. total = length + 8;
  311. if (rx_frame_len < total) return;
  312. cursor = 0;
  313. memset(&message, 0, sizeof(message));
  314. if (DecodeNew(&message, payload, rx_frame, &cursor, total, sizeof(rx_frame)) <= 0) goto discard;
  315. payload[length] = 0;
  316. message.data = (char *)payload;
  317. /* Consume before dispatch: callbacks may request a close or enqueue TX. */
  318. rx_frame_len -= total;
  319. memmove(rx_frame, rx_frame + total, rx_frame_len);
  320. if (message.cmd == PC_CMD_SETIP && length >= 5 && memcmp(payload, "Mini7", 5) == 0) continue;
  321. sysinf.pc_channel_recv = PC_CONNECT_TYPE_WIFI;
  322. sysinf.pc_link_timeout = 0;
  323. Van_Device_Printf(VAN_LOG_WIFI, "\nWiFi RX cmd=%d len=%d", message.cmd, length);
  324. #ifdef ONECHIP_MINI_ONE
  325. if (message.cmd == UINON_CMD_THEROM_GET && length == 4) deal_mUnion_cmd(&message);
  326. else
  327. #endif
  328. query_pc_cmd(&message);
  329. continue;
  330. discard:
  331. --rx_frame_len;
  332. memmove(rx_frame, rx_frame + 1, rx_frame_len);
  333. }
  334. }
  335. static void wifi_rx_byte(uint8_t byte)
  336. {
  337. char *end, *begin;
  338. unsigned long id, length;
  339. if (rx_ipd_left) {
  340. --rx_ipd_left;
  341. if (rx_ipd_accept && tx_phase != TX_FAULT) {
  342. if (prov_active) wifi_provision_byte(byte);
  343. else wifi_frame_byte(byte);
  344. }
  345. return;
  346. }
  347. if (!rx_line_len && byte == '>') {
  348. wifi_line(">");
  349. return;
  350. }
  351. if (!rx_line_len && (byte == '\r' || byte == '\n' || byte == ' ')) return;
  352. if (rx_line_len == sizeof(rx_line) - 1) {
  353. wifi_fault("AT line overflow");
  354. return;
  355. }
  356. rx_line[rx_line_len++] = byte;
  357. rx_line[rx_line_len] = 0;
  358. if (byte == ':' && strncmp(rx_line, "+IPD,", 5) == 0) {
  359. begin = rx_line + 5;
  360. id = strtoul(begin, &end, 10);
  361. if (*begin < '0' || *begin > '9' || end == begin || *end != ',' || id > 4) goto malformed;
  362. begin = end + 1;
  363. length = strtoul(begin, &end, 10);
  364. if (*begin < '0' || *begin > '9' || end == begin || *end != ':' || end[1] || length > 65535) goto malformed;
  365. rx_ipd_left = length;
  366. rx_ipd_accept = (id == 0);
  367. if (prov_active) {
  368. rx_ipd_accept = (prov_step == 10 && id <= 4 && (!prov_len || prov_link == id));
  369. if (rx_ipd_accept) prov_link = (uint8_t)id;
  370. }
  371. rx_line_len = 0;
  372. return;
  373. }
  374. if (byte == '\n') {
  375. while (rx_line_len && (rx_line[rx_line_len - 1] == '\r' || rx_line[rx_line_len - 1] == '\n'))
  376. rx_line[--rx_line_len] = 0;
  377. wifi_line(rx_line);
  378. rx_line_len = 0;
  379. }
  380. return;
  381. malformed:
  382. wifi_fault("invalid +IPD header");
  383. }
  384. static void wifi_online(void)
  385. {
  386. wifi_enter(WIFI_TRANS);
  387. broadDevFlag = 1;
  388. sysinf.s10_flag = 1;
  389. }
  390. static void wifi_line(const char *line)
  391. {
  392. const char *p, *q;
  393. if (prov_active && wifi_provision_line(line)) return;
  394. if (at_pending && (!strcmp(line, "ERROR") || !strcmp(line, "FAIL")))
  395. Van_Device_Printf(VAN_LOG_WIFI, "\nWiFi AT state=%d reply=%s\n", wifi_state, line);
  396. if (strcmp(line, "ready") == 0) {
  397. tx_phase = TX_IDLE;
  398. wifi_tx_len = 0;
  399. wifi_rx_reset();
  400. wifi_enter(WIFI_POWERON);
  401. return;
  402. }
  403. if (tx_phase == TX_FAULT) return;
  404. if (strcmp(line, ">") == 0) {
  405. if (tx_phase != TX_WAIT_PROMPT) {
  406. Van_Device_Printf(VAN_LOG_WIFI, "\nWiFi unexpected prompt ignored\n");
  407. return;
  408. }
  409. tx_phase = TX_WAIT_RESULT;
  410. tx_started = HAL_GetTick();
  411. wifi_ack_delay = 7000; /* TCP SO_SNDTIMEO=6000 plus MCU margin. */
  412. if (WriteComm2((char *)wifi_tx_buf, wifi_tx_len) != HAL_OK) wifi_fault("payload UART write");
  413. return;
  414. }
  415. if (!strcmp(line, "SEND OK") || !strcmp(line, "SEND FAIL")) {
  416. if (tx_phase == TX_WAIT_RESULT) {
  417. Van_Device_Printf(VAN_LOG_WIFI, "\nW<-- %s\n", line);
  418. tx_phase = TX_IDLE;
  419. wifi_tx_len = 0;
  420. wifi_ack_delay = 0;
  421. }
  422. return;
  423. }
  424. /* CWJAP can disconnect the old association before joining the requested AP.
  425. * Wait for its final OK/FAIL instead of resetting an in-progress join. */
  426. if (!strcmp(line, "WIFI DISCONNECT") && wifi_state == WIFI_LINK_AP && at_pending)
  427. return;
  428. if (!strcmp(line, "0,CLOSED") || !strcmp(line, "CLOSED") || !strcmp(line, "WIFI DISCONNECT")) {
  429. if (tx_phase == TX_WAIT_PROMPT) {
  430. wifi_fault("closed before prompt");
  431. return;
  432. }
  433. tx_phase = TX_IDLE;
  434. wifi_tx_len = 0;
  435. rx_frame_len = 0;
  436. wifi_enter(!strcmp(line, "WIFI DISCONNECT") ? WIFI_POWEROFF : WIFI_LISTEN);
  437. return;
  438. }
  439. if (wifi_state == WIFI_CWLAP && strncmp(line, "+CWLAP:", 7) == 0) {
  440. /* Quoted strings are SSID and BSSID; RSSI between them is numeric. */
  441. p = strchr(line, '"');
  442. if (!p) return;
  443. q = strchr(p + 1, '"');
  444. if (!q) return;
  445. if ((unsigned)(q - p - 1) != strlen(sysinf.wifiname) ||
  446. memcmp(p + 1, sysinf.wifiname, q - p - 1)) return;
  447. p = strchr(q + 1, '"');
  448. if (!p) return;
  449. q = strchr(p + 1, '"');
  450. if (!q || q - p - 1 != 17) return;
  451. memcpy(MAC_ADDR, p + 1, 17);
  452. MAC_ADDR[17] = 0;
  453. ap_found = 1;
  454. return;
  455. }
  456. if (!strcmp(line, "ERROR") || !strcmp(line, "FAIL")) {
  457. if (tx_phase == TX_WAIT_PROMPT) {
  458. /* Explicit rejection: ESP did not enter data mode. Upper layer retries. */
  459. tx_phase = TX_IDLE;
  460. wifi_tx_len = 0;
  461. wifi_ack_delay = 0;
  462. } else if (tx_phase == TX_WAIT_RESULT) {
  463. wifi_fault("ERROR during payload transaction");
  464. } else if (at_pending) {
  465. at_pending = 0;
  466. wifi_ack_delay = 0;
  467. if (wifi_state == WIFI_TCPOPT) wifi_enter(WIFI_CLOSE);
  468. retry_wait = 1; retry_started = HAL_GetTick();
  469. }
  470. return;
  471. }
  472. if (strcmp(line, "OK") || !at_pending || at_owner != wifi_state) return;
  473. at_pending = 0;
  474. wifi_ack_delay = 0;
  475. switch (wifi_state) {
  476. case WIFI_POWEROFF: /* AT+RST's OK is not the boot-ready notification. */
  477. case WIFI_ERROR:
  478. at_pending = 1; at_started = HAL_GetTick(); wifi_ack_delay = 8000; break;
  479. case WIFI_POWERON: wifi_enter(WIFI_INIT); break;
  480. case WIFI_INIT: wifi_enter(WIFI_STATION); break;
  481. case WIFI_STATION: wifi_enter(WIFI_CWLAP); break;
  482. case WIFI_CWLAP:
  483. if (ap_found) wifi_enter(WIFI_DISAUTO);
  484. else {
  485. Van_Device_Printf(VAN_LOG_WIFI, "\nWiFi scan completed: configured SSID not found\n");
  486. retry_wait = 1; retry_started = HAL_GetTick();
  487. }
  488. break;
  489. case WIFI_DISAUTO: wifi_enter(WIFI_LINK_AP); break;
  490. case WIFI_LINK_AP: wifi_enter(WIFI_GET_IP); break;
  491. case WIFI_GET_IP:
  492. if (wifi_set_ssid) {
  493. char result = 1;
  494. wifi_set_ssid = 0;
  495. data_send_to_pc(PC_CMD_SETWIFI, &result, 1);
  496. }
  497. wifi_enter(WIFI_SETMUX); break;
  498. case WIFI_SETMUX: wifi_enter(WIFI_IPDINFO); break;
  499. case WIFI_IPDINFO: wifi_enter(WIFI_LISTEN); break;
  500. case WIFI_LISTEN:
  501. if (link_is_tcp) wifi_enter(WIFI_TCPOPT);
  502. else wifi_online();
  503. break;
  504. case WIFI_TCPOPT: wifi_online(); break;
  505. case WIFI_CLOSE:
  506. rx_frame_len = 0;
  507. wifi_enter(wifi_set_ssid ? WIFI_POWEROFF : WIFI_LISTEN);
  508. break;
  509. default: break;
  510. }
  511. }
  512. void WIFI_recv_deal(void)
  513. {
  514. unsigned budget = WIFI_RX_BUF_SIZE;
  515. if (g_wifi_rx_fault) {
  516. uint8_t cause = g_wifi_rx_fault;
  517. g_wifi_rx_fault = 0;
  518. g_wifi_rx_head = g_wifi_rx_last;
  519. wifi_fault((cause & 2) ? "UART hardware overrun" : "RX ring full");
  520. }
  521. while (budget-- && g_wifi_rx_head != g_wifi_rx_last) {
  522. uint8_t byte = g_wifi_rx_buf[g_wifi_rx_head];
  523. g_wifi_rx_head = (g_wifi_rx_head + 1) % WIFI_RX_BUF_SIZE;
  524. rx_last_byte = HAL_GetTick();
  525. wifi_rx_byte(byte);
  526. }
  527. if (rx_ipd_left && (uint32_t)(HAL_GetTick() - rx_last_byte) >= 3000)
  528. wifi_fault("incomplete +IPD");
  529. }
  530. void WIFI_send_deal(void)
  531. {
  532. uint32_t now = HAL_GetTick();
  533. if (tx_phase == TX_FAULT) return;
  534. if (retry_wait) {
  535. if ((uint32_t)(now - retry_started) < 2000u) return;
  536. retry_wait = 0;
  537. }
  538. if (tx_phase != TX_IDLE) {
  539. if ((uint32_t)(now - tx_started) >= (tx_phase == TX_WAIT_PROMPT ? 3000u : 7000u))
  540. wifi_fault(tx_phase == TX_WAIT_PROMPT ? "prompt timeout" : "SEND result timeout");
  541. return;
  542. }
  543. if (at_pending) {
  544. if ((uint32_t)(now - at_started) < (uint32_t)wifi_ack_delay) return;
  545. at_pending = 0;
  546. wifi_ack_delay = 0;
  547. Van_Device_Printf(VAN_LOG_WIFI, "\nAT timeout state=%d\n", wifi_state);
  548. }
  549. if (deferred_close) {
  550. deferred_close = 0;
  551. wifi_tx_len = 0;
  552. wifi_enter(wifi_set_ssid ? WIFI_POWEROFF : WIFI_CLOSE);
  553. }
  554. if (wifi_state == WIFI_TRANS) {
  555. if (wifi_tx_len) WIFI_ReSend();
  556. return;
  557. }
  558. if (++at_retries > MAX_RESEND_TIME) {
  559. if (wifi_set_ssid) {
  560. char result = (wifi_state == WIFI_CWLAP) ? 0xff : 0xfe;
  561. wifi_set_ssid = 0;
  562. data_send_to_pc(PC_CMD_SETWIFI, &result, 1);
  563. }
  564. wifi_enter(WIFI_POWEROFF);
  565. }
  566. switch (wifi_state) {
  567. case WIFI_POWEROFF:
  568. case WIFI_ERROR: ESP32_AT_RST(); break;
  569. case WIFI_POWERON: ESP32_AT(); break;
  570. case WIFI_INIT: ESP32_EchoOff(); break;
  571. case WIFI_STATION: ESP32_Net_Mode_Choose(STA); break;
  572. case WIFI_CWLAP: ap_found = 0; ESP32_CWLAP(sysinf.wifiname); break;
  573. case WIFI_DISAUTO: ESP32_DisAutoLink(); break;
  574. case WIFI_LINK_AP: ESP32_JoinAP(sysinf.wifiname, sysinf.password, MAC_ADDR); break;
  575. case WIFI_GET_IP: ESP32_GetIp(); break;
  576. case WIFI_SETMUX: ESP32_Enable_MultipleId(1); break;
  577. case WIFI_IPDINFO: ESP32_Send_AT_Cmd("AT+CIPDINFO=0", 3000); break;
  578. case WIFI_LISTEN:
  579. rx_frame_len = 0;
  580. link_is_tcp = sysinf.connectTcpFlag != 0;
  581. if (link_is_tcp) ESP32_Link_Server(enumTCP, sysinf.TCP_IP_Addr, sysinf.TCP_IP_PORT, Multiple_ID_0);
  582. else ESP32_Link_Server(enumUDP, User_ESP32_UDPServer_IP, User_ESP32_UDPServer_PORT, Multiple_ID_0);
  583. break;
  584. case WIFI_TCPOPT: ESP32_Send_AT_Cmd("AT+CIPTCPOPT=0,,,6000", 3000); break;
  585. case WIFI_CLOSE: ESP32_STOPTCP(Multiple_ID_0); break;
  586. default: wifi_enter(WIFI_POWEROFF); break;
  587. }
  588. }
  589. void WIFI_process(void)
  590. {
  591. WIFI_recv_deal();
  592. if (prov_request && !prov_active && tx_phase == TX_IDLE && !at_pending) {
  593. prov_request = 0; prov_active = 1; prov_step = 0;
  594. prov_len = prov_bad = prov_ready = 0;
  595. wifi_tx_len = 0; wifi_rx_reset(); wifi_enter(WIFI_POWEROFF);
  596. Van_Device_Printf(VAN_LOG_WIFI, "\nProvision start\n");
  597. }
  598. if (prov_active) wifi_provision_process();
  599. else WIFI_send_deal();
  600. }
  601. /* Keep the public formatter and make its length argument effective. */
  602. int my_sprintf(char *out, unsigned int size, const char *format, ...)
  603. {
  604. int n;
  605. va_list args;
  606. if (!out || !size || !format) return -1;
  607. va_start(args, format);
  608. n = vsnprintf(out, size, format, args);
  609. va_end(args);
  610. out[size - 1] = 0;
  611. return n;
  612. }
  613. static int wifi_prov_parse_json(const char *json, char *ssid, uint16_t ssidCap,
  614. char *pwd, uint16_t pwdCap)
  615. {
  616. cJSON *root = NULL;
  617. cJSON *it = NULL;
  618. int rlt = -1;
  619. if (json == NULL || json[0] != '{' || ssid == NULL || pwd == NULL)
  620. return -1;
  621. ssid[0] = '\0';
  622. pwd[0] = '\0';
  623. root = cJSON_Parse(json);
  624. if (root == NULL)
  625. return -1;
  626. it = cJSON_GetObjectItem(root, "ssid");
  627. if (it == NULL || !cJSON_IsString(it) || it->valuestring == NULL ||
  628. it->valuestring[0] == '\0')
  629. goto out; /* 必须包含非空ssid */
  630. if (strlen(it->valuestring) >= (size_t)ssidCap)
  631. goto out; /* ssid超长 */
  632. strcpy(ssid, it->valuestring);
  633. it = cJSON_GetObjectItem(root, "password");
  634. if (it != NULL && cJSON_IsString(it) && it->valuestring != NULL)
  635. {
  636. if (strlen(it->valuestring) >= (size_t)pwdCap)
  637. goto out; /* 密码超长 */
  638. strcpy(pwd, it->valuestring); /* 允许开放网络密码为空 */
  639. }
  640. rlt = 0;
  641. out:
  642. cJSON_Delete(root);
  643. return rlt;
  644. }
  645. /* SoftAP uses the same stream parser and CIPSEND transaction as STA. */
  646. uint8_t WIFI_provision_active(void) { return prov_active; }
  647. uint8_t WIFI_provision_request(void) {
  648. if (prov_active) return 0;
  649. prov_request = 1; return 1;
  650. }
  651. static void wifi_provision_byte(uint8_t byte) {
  652. if (prov_bad || prov_ready) return;
  653. if (prov_len >= sizeof(prov_json)-1) { prov_bad = 1; return; }
  654. if (byte == '\r' || byte == '\n') return;
  655. prov_json[prov_len++] = (char)byte;
  656. prov_json[prov_len] = 0;
  657. if (!rx_ipd_left && prov_len && prov_json[prov_len-1] == '}') prov_ready = 1;
  658. }
  659. static void wifi_provision_exit(void) {
  660. prov_active = 0; prov_step = 0; prov_len = 0;
  661. wifi_tx_len = 0; wifi_rx_reset(); wifi_enter(WIFI_POWEROFF);
  662. }
  663. static int wifi_provision_line(const char *line) {
  664. if (!strcmp(line, "ready")) {
  665. tx_phase = TX_IDLE; wifi_tx_len = 0; wifi_rx_reset();
  666. at_pending = 0; wifi_ack_delay = 0;
  667. prov_step = 1; prov_started = HAL_GetTick();
  668. return 1;
  669. }
  670. if (tx_phase != TX_IDLE) return 0; /* shared prompt/result handling */
  671. if (at_pending && !strcmp(line, "OK")) {
  672. if (prov_step == 0) return 1; /* reset must finish with ready */
  673. at_pending = 0; wifi_ack_delay = 0; ++prov_step;
  674. prov_started = HAL_GetTick(); return 1;
  675. }
  676. if (at_pending && (!strcmp(line, "ERROR") || !strcmp(line, "FAIL"))) {
  677. Van_Device_Printf(VAN_LOG_WIFI, "\nProvision command rejected step=%d\n", prov_step);
  678. wifi_provision_exit(); return 1;
  679. }
  680. return 1;
  681. }
  682. static void wifi_provision_process(void) {
  683. char cmd[160];
  684. uint32_t now = HAL_GetTick();
  685. if (tx_phase == TX_FAULT) return;
  686. if (tx_phase != TX_IDLE) {
  687. if ((uint32_t)(now-tx_started) >= (tx_phase == TX_WAIT_PROMPT ? 3000u : 7000u))
  688. wifi_fault("provision send timeout");
  689. return;
  690. }
  691. if (at_pending) {
  692. if ((uint32_t)(now-at_started) >= (uint32_t)wifi_ack_delay) {
  693. Van_Device_Printf(VAN_LOG_WIFI, "\nProvision command timeout step=%d\n", prov_step);
  694. wifi_provision_exit();
  695. }
  696. return;
  697. }
  698. switch (prov_step) {
  699. case 0: ESP32_Send_AT_Cmd("AT+RST",10000); break;
  700. case 1: ESP32_Send_AT_Cmd("ATE0",5000); break;
  701. case 2: ESP32_Send_AT_Cmd("AT+CWMODE=2",5000); break;
  702. case 3:
  703. my_sprintf(cmd,sizeof(cmd),"AT+CWSAP=\"%s\",\"%s\",6,3","OneChip_Mini7","test1234");
  704. ESP32_Send_AT_Cmd(cmd,5000); break;
  705. case 4: ESP32_Send_AT_Cmd("AT+CIPAP?",5000); break;
  706. case 5: ESP32_Send_AT_Cmd("AT+CWDHCP?",5000); break;
  707. case 6: ESP32_Send_AT_Cmd("AT+CIPMUX=1",5000); break;
  708. case 7: ESP32_Send_AT_Cmd("AT+CIPDINFO=0",5000); break;
  709. case 8: ESP32_Send_AT_Cmd("AT+CIPSERVER=1,8002",5000); break;
  710. case 9: prov_step=10; prov_started=now; break;
  711. case 10:
  712. if ((uint32_t)(now-prov_started)>=300000u) { wifi_provision_exit(); break; }
  713. if (prov_bad && !rx_ipd_left) {
  714. prov_len=prov_bad=prov_ready=0; break;
  715. }
  716. if (prov_ready && !rx_ipd_left) {
  717. char ssid[sizeof(sysinf.wifiname)], pwd[sizeof(sysinf.password)];
  718. int valid = wifi_prov_parse_json(prov_json,ssid,sizeof(ssid),pwd,sizeof(pwd)) == 0;
  719. if (valid) {
  720. strcpy(sysinf.wifiname,ssid); strcpy(sysinf.password,pwd);
  721. valid = cfg_save_cfg_param() != 0;
  722. }
  723. if (valid)
  724. my_sprintf((char *)wifi_tx_buf,sizeof(wifi_tx_buf),
  725. "{\"v\":1,\"status\":\"accepted\",\"sn\":\"%.7s\"}\r\n", sysinf.SN);
  726. else
  727. my_sprintf((char *)wifi_tx_buf,sizeof(wifi_tx_buf),
  728. "{\"v\":1,\"status\":\"rejected\",\"reason\":\"invalid\"}\r\n");
  729. wifi_tx_len = (uint16_t)strlen((char *)wifi_tx_buf);
  730. WIFI_ReSend(); prov_step = valid ? 11 : 12;
  731. }
  732. break;
  733. case 11: wifi_provision_exit(); break;
  734. case 12: prov_len=prov_bad=prov_ready=0; prov_step=10; prov_started=now; break;
  735. default: wifi_provision_exit(); break;
  736. }
  737. }