1 /*
2 * Copyright (c) 2019 Tobias Svehagen
3 * Copyright (c) 2020 Grinn
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #define DT_DRV_COMPAT espressif_esp_at
9
10 #undef _POSIX_C_SOURCE
11 #define _POSIX_C_SOURCE 200809L
12
13 #include <zephyr/logging/log.h>
14 LOG_MODULE_REGISTER(wifi_esp_at, CONFIG_WIFI_LOG_LEVEL);
15
16 #include <zephyr/kernel.h>
17 #include <ctype.h>
18 #include <errno.h>
19 #include <zephyr/device.h>
20 #include <zephyr/init.h>
21 #include <stdlib.h>
22 #include <string.h>
23
24 #include <zephyr/drivers/gpio.h>
25 #include <zephyr/drivers/uart.h>
26
27 #include <zephyr/net/dns_resolve.h>
28 #include <zephyr/net/net_if.h>
29 #include <zephyr/net/net_ip.h>
30 #include <zephyr/net/net_offload.h>
31 #include <zephyr/net/wifi_mgmt.h>
32 #include <zephyr/net/conn_mgr/connectivity_wifi_mgmt.h>
33
34 #include "esp.h"
35
36 struct esp_config {
37 #if DT_INST_NODE_HAS_PROP(0, power_gpios)
38 const struct gpio_dt_spec power;
39 #endif
40 #if DT_INST_NODE_HAS_PROP(0, reset_gpios)
41 const struct gpio_dt_spec reset;
42 #endif
43 };
44
45 NET_BUF_POOL_DEFINE(mdm_recv_pool, MDM_RECV_MAX_BUF, MDM_RECV_BUF_SIZE,
46 0, NULL);
47
48 /* RX thread structures */
49 K_KERNEL_STACK_DEFINE(esp_rx_stack,
50 CONFIG_WIFI_ESP_AT_RX_STACK_SIZE);
51 struct k_thread esp_rx_thread;
52
53 /* RX thread work queue */
54 K_KERNEL_STACK_DEFINE(esp_workq_stack,
55 CONFIG_WIFI_ESP_AT_WORKQ_STACK_SIZE);
56
57 static const struct esp_config esp_driver_config = {
58 #if DT_INST_NODE_HAS_PROP(0, power_gpios)
59 .power = GPIO_DT_SPEC_INST_GET(0, power_gpios),
60 #endif
61 #if DT_INST_NODE_HAS_PROP(0, reset_gpios)
62 .reset = GPIO_DT_SPEC_INST_GET(0, reset_gpios),
63 #endif
64 };
65 struct esp_data esp_driver_data;
66
esp_configure_hostname(struct esp_data * data)67 static void esp_configure_hostname(struct esp_data *data)
68 {
69 #if defined(CONFIG_NET_HOSTNAME_ENABLE)
70 char cmd[sizeof("AT+CWHOSTNAME=\"\"") + NET_HOSTNAME_MAX_LEN];
71
72 snprintk(cmd, sizeof(cmd), "AT+CWHOSTNAME=\"%s\"", net_hostname_get());
73 cmd[sizeof(cmd) - 1] = '\0';
74
75 esp_cmd_send(data, NULL, 0, cmd, ESP_CMD_TIMEOUT);
76 #else
77 ARG_UNUSED(data);
78 #endif
79 }
80
esp_mode_from_flags(struct esp_data * data)81 static inline uint8_t esp_mode_from_flags(struct esp_data *data)
82 {
83 uint8_t flags = data->flags;
84 uint8_t mode = 0;
85
86 if (flags & (EDF_STA_CONNECTED | EDF_STA_LOCK)) {
87 mode |= ESP_MODE_STA;
88 }
89
90 if (flags & EDF_AP_ENABLED) {
91 mode |= ESP_MODE_AP;
92 }
93
94 /*
95 * ESP AT 1.7 does not allow to disable radio, so enter STA mode
96 * instead.
97 */
98 if (IS_ENABLED(CONFIG_WIFI_ESP_AT_VERSION_1_7) &&
99 mode == ESP_MODE_NONE) {
100 mode = ESP_MODE_STA;
101 }
102
103 return mode;
104 }
105
esp_mode_switch(struct esp_data * data,uint8_t mode)106 static int esp_mode_switch(struct esp_data *data, uint8_t mode)
107 {
108 char cmd[] = "AT+"_CWMODE"=X";
109 int err;
110
111 cmd[sizeof(cmd) - 2] = ('0' + mode);
112 LOG_DBG("Switch to mode %hhu", mode);
113
114 err = esp_cmd_send(data, NULL, 0, cmd, ESP_CMD_TIMEOUT);
115 if (err) {
116 LOG_WRN("Failed to switch to mode %d: %d", (int) mode, err);
117 }
118
119 return err;
120 }
121
esp_mode_switch_if_needed(struct esp_data * data)122 static int esp_mode_switch_if_needed(struct esp_data *data)
123 {
124 uint8_t new_mode = esp_mode_from_flags(data);
125 uint8_t old_mode = data->mode;
126 int err;
127
128 if (old_mode == new_mode) {
129 return 0;
130 }
131
132 data->mode = new_mode;
133
134 err = esp_mode_switch(data, new_mode);
135 if (err) {
136 return err;
137 }
138
139 if (!(old_mode & ESP_MODE_STA) && (new_mode & ESP_MODE_STA)) {
140 /*
141 * Hostname change is applied only when STA is enabled.
142 */
143 esp_configure_hostname(data);
144 }
145
146 return 0;
147 }
148
esp_mode_switch_submit_if_needed(struct esp_data * data)149 static void esp_mode_switch_submit_if_needed(struct esp_data *data)
150 {
151 if (data->mode != esp_mode_from_flags(data)) {
152 k_work_submit_to_queue(&data->workq, &data->mode_switch_work);
153 }
154 }
155
esp_mode_switch_work(struct k_work * work)156 static void esp_mode_switch_work(struct k_work *work)
157 {
158 struct esp_data *data =
159 CONTAINER_OF(work, struct esp_data, mode_switch_work);
160
161 (void)esp_mode_switch_if_needed(data);
162 }
163
esp_mode_flags_set(struct esp_data * data,uint8_t flags)164 static inline int esp_mode_flags_set(struct esp_data *data, uint8_t flags)
165 {
166 esp_flags_set(data, flags);
167
168 return esp_mode_switch_if_needed(data);
169 }
170
esp_mode_flags_clear(struct esp_data * data,uint8_t flags)171 static inline int esp_mode_flags_clear(struct esp_data *data, uint8_t flags)
172 {
173 esp_flags_clear(data, flags);
174
175 return esp_mode_switch_if_needed(data);
176 }
177
178 /*
179 * Modem Response Command Handlers
180 */
181
182 /* Handler: OK */
MODEM_CMD_DEFINE(on_cmd_ok)183 MODEM_CMD_DEFINE(on_cmd_ok)
184 {
185 struct esp_data *dev = CONTAINER_OF(data, struct esp_data,
186 cmd_handler_data);
187
188 modem_cmd_handler_set_error(data, 0);
189 k_sem_give(&dev->sem_response);
190
191 return 0;
192 }
193
194 /* Handler: ERROR */
MODEM_CMD_DEFINE(on_cmd_error)195 MODEM_CMD_DEFINE(on_cmd_error)
196 {
197 struct esp_data *dev = CONTAINER_OF(data, struct esp_data,
198 cmd_handler_data);
199
200 modem_cmd_handler_set_error(data, -EIO);
201 k_sem_give(&dev->sem_response);
202
203 return 0;
204 }
205
206 /* RX thread */
esp_rx(void * p1,void * p2,void * p3)207 static void esp_rx(void *p1, void *p2, void *p3)
208 {
209 ARG_UNUSED(p2);
210 ARG_UNUSED(p3);
211
212 struct esp_data *data = p1;
213
214 while (true) {
215 /* wait for incoming data */
216 modem_iface_uart_rx_wait(&data->mctx.iface, K_FOREVER);
217
218 modem_cmd_handler_process(&data->mctx.cmd_handler, &data->mctx.iface);
219
220 /* give up time if we have a solid stream of data */
221 k_yield();
222 }
223 }
224
str_unquote(char * str)225 static char *str_unquote(char *str)
226 {
227 char *end;
228
229 if (str[0] != '"') {
230 return str;
231 }
232
233 str++;
234
235 end = strrchr(str, '"');
236 if (end != NULL) {
237 *end = 0;
238 }
239
240 return str;
241 }
242
243 /* +CIPSTAMAC:"xx:xx:xx:xx:xx:xx" */
MODEM_CMD_DEFINE(on_cmd_cipstamac)244 MODEM_CMD_DEFINE(on_cmd_cipstamac)
245 {
246 struct esp_data *dev = CONTAINER_OF(data, struct esp_data,
247 cmd_handler_data);
248 char *mac;
249 int err;
250
251 mac = str_unquote(argv[0]);
252 err = net_bytes_from_str(dev->mac_addr, sizeof(dev->mac_addr), mac);
253 if (err) {
254 LOG_ERR("Failed to parse MAC address");
255 }
256
257 return 0;
258 }
259
esp_pull_quoted(char ** str,char * str_end,char ** unquoted)260 static int esp_pull_quoted(char **str, char *str_end, char **unquoted)
261 {
262 if (**str != '"') {
263 return -EAGAIN;
264 }
265
266 (*str)++;
267
268 *unquoted = *str;
269
270 while (*str < str_end) {
271 if (**str == '"') {
272 **str = '\0';
273 (*str)++;
274
275 if (**str == ',') {
276 (*str)++;
277 }
278
279 return 0;
280 }
281
282 (*str)++;
283 }
284
285 return -EAGAIN;
286 }
287
esp_pull(char ** str,char * str_end)288 static int esp_pull(char **str, char *str_end)
289 {
290 while (*str < str_end) {
291 if (**str == ',' || **str == ':' || **str == '\r' || **str == '\n') {
292 char last_c = **str;
293
294 **str = '\0';
295
296 if (last_c == ',' || last_c == ':') {
297 (*str)++;
298 }
299
300 return 0;
301 }
302
303 (*str)++;
304 }
305
306 return -EAGAIN;
307 }
308
esp_pull_raw(char ** str,char * str_end,char ** raw)309 static int esp_pull_raw(char **str, char *str_end, char **raw)
310 {
311 *raw = *str;
312
313 return esp_pull(str, str_end);
314 }
315
esp_pull_long(char ** str,char * str_end,long * value)316 static int esp_pull_long(char **str, char *str_end, long *value)
317 {
318 char *str_begin = *str;
319 int err;
320 char *endptr;
321
322 err = esp_pull(str, str_end);
323 if (err) {
324 return err;
325 }
326
327 *value = strtol(str_begin, &endptr, 10);
328 if (endptr == str_begin) {
329 LOG_ERR("endptr == str_begin");
330 return -EBADMSG;
331 }
332
333 return 0;
334 }
335
336 /* +CWLAP:(sec,ssid,rssi,channel) */
337 /* with: CONFIG_WIFI_ESP_AT_SCAN_MAC_ADDRESS: +CWLAP:<ecn>,<ssid>,<rssi>,<mac>,<ch>*/
MODEM_CMD_DIRECT_DEFINE(on_cmd_cwlap)338 MODEM_CMD_DIRECT_DEFINE(on_cmd_cwlap)
339 {
340 struct esp_data *dev = CONTAINER_OF(data, struct esp_data,
341 cmd_handler_data);
342 struct wifi_scan_result res = { 0 };
343 char cwlap_buf[sizeof("\"0\",\"\",-100,\"xx:xx:xx:xx:xx:xx\",12") +
344 WIFI_SSID_MAX_LEN * 2 + 1];
345 char *ecn;
346 char *ssid;
347 char *mac;
348 char *channel;
349 long rssi;
350 long ecn_id;
351 int err;
352
353 len = net_buf_linearize(cwlap_buf, sizeof(cwlap_buf) - 1,
354 data->rx_buf, 0, sizeof(cwlap_buf) - 1);
355 cwlap_buf[len] = '\0';
356
357 char *str = &cwlap_buf[sizeof("+CWJAP:(") - 1];
358 char *str_end = cwlap_buf + len;
359
360 err = esp_pull_raw(&str, str_end, &ecn);
361 if (err) {
362 return err;
363 }
364
365 ecn_id = strtol(ecn, NULL, 10);
366 if (ecn_id == 0) {
367 res.security = WIFI_SECURITY_TYPE_NONE;
368 } else {
369 res.security = WIFI_SECURITY_TYPE_PSK;
370 }
371
372 err = esp_pull_quoted(&str, str_end, &ssid);
373 if (err) {
374 return err;
375 }
376
377 err = esp_pull_long(&str, str_end, &rssi);
378 if (err) {
379 return err;
380 }
381
382 if (strlen(ssid) > WIFI_SSID_MAX_LEN) {
383 return -EBADMSG;
384 }
385
386 res.ssid_length = MIN(sizeof(res.ssid), strlen(ssid));
387 memcpy(res.ssid, ssid, res.ssid_length);
388
389 res.rssi = rssi;
390
391 if (IS_ENABLED(CONFIG_WIFI_ESP_AT_SCAN_MAC_ADDRESS)) {
392 err = esp_pull_quoted(&str, str_end, &mac);
393 if (err) {
394 return err;
395 }
396
397 res.mac_length = WIFI_MAC_ADDR_LEN;
398 if (net_bytes_from_str(res.mac, sizeof(res.mac), mac) < 0) {
399 LOG_ERR("Invalid MAC address");
400 res.mac_length = 0;
401 }
402 }
403
404 err = esp_pull_raw(&str, str_end, &channel);
405 if (err) {
406 return err;
407 }
408
409 res.channel = strtol(channel, NULL, 10);
410
411 if (dev->scan_cb) {
412 dev->scan_cb(dev->net_iface, 0, &res);
413 }
414
415 return str - cwlap_buf;
416 }
417
418 /* +CWJAP:(ssid,bssid,channel,rssi) */
MODEM_CMD_DIRECT_DEFINE(on_cmd_cwjap)419 MODEM_CMD_DIRECT_DEFINE(on_cmd_cwjap)
420 {
421 struct esp_data *dev = CONTAINER_OF(data, struct esp_data,
422 cmd_handler_data);
423 struct wifi_iface_status *status = dev->wifi_status;
424 char cwjap_buf[sizeof("\"\",\"xx:xx:xx:xx:xx:xx\",12,-100") +
425 WIFI_SSID_MAX_LEN * 2 + 1];
426 uint8_t flags = dev->flags;
427 char *ssid;
428 char *bssid;
429 char *channel;
430 char *rssi;
431 int err;
432
433 len = net_buf_linearize(cwjap_buf, sizeof(cwjap_buf) - 1,
434 data->rx_buf, 0, sizeof(cwjap_buf) - 1);
435 cwjap_buf[len] = '\0';
436
437 char *str = &cwjap_buf[sizeof("+CWJAP:") - 1];
438 char *str_end = cwjap_buf + len;
439
440 status->band = WIFI_FREQ_BAND_2_4_GHZ;
441 status->iface_mode = WIFI_MODE_INFRA;
442
443 if (flags & EDF_STA_CONNECTED) {
444 status->state = WIFI_STATE_COMPLETED;
445 } else if (flags & EDF_STA_CONNECTING) {
446 status->state = WIFI_STATE_SCANNING;
447 } else {
448 status->state = WIFI_STATE_DISCONNECTED;
449 }
450
451 err = esp_pull_quoted(&str, str_end, &ssid);
452 if (err) {
453 return err;
454 }
455
456 err = esp_pull_quoted(&str, str_end, &bssid);
457 if (err) {
458 return err;
459 }
460
461 err = esp_pull_raw(&str, str_end, &channel);
462 if (err) {
463 return err;
464 }
465
466 err = esp_pull_raw(&str, str_end, &rssi);
467 if (err) {
468 return err;
469 }
470
471 strncpy(status->ssid, ssid, sizeof(status->ssid));
472 status->ssid_len = strnlen(status->ssid, sizeof(status->ssid));
473
474 err = net_bytes_from_str(status->bssid, sizeof(status->bssid), bssid);
475 if (err) {
476 LOG_WRN("Invalid MAC address");
477 memset(status->bssid, 0x0, sizeof(status->bssid));
478 }
479
480 status->channel = strtol(channel, NULL, 10);
481 status->rssi = strtol(rssi, NULL, 10);
482
483 return str - cwjap_buf;
484 }
485
esp_dns_work(struct k_work * work)486 static void esp_dns_work(struct k_work *work)
487 {
488 #if defined(ESP_MAX_DNS)
489 struct esp_data *data = CONTAINER_OF(work, struct esp_data, dns_work);
490 struct dns_resolve_context *dnsctx;
491 struct sockaddr_in *addrs = data->dns_addresses;
492 const struct sockaddr *dns_servers[ESP_MAX_DNS + 1] = {};
493 size_t i;
494 int err;
495
496 for (i = 0; i < ESP_MAX_DNS; i++) {
497 if (!addrs[i].sin_addr.s_addr) {
498 break;
499 }
500 dns_servers[i] = (struct sockaddr *) &addrs[i];
501 }
502
503 dnsctx = dns_resolve_get_default();
504 err = dns_resolve_reconfigure(dnsctx, NULL, dns_servers);
505 if (err) {
506 LOG_ERR("Could not set DNS servers: %d", err);
507 }
508
509 LOG_DBG("DNS resolver reconfigured");
510 #endif
511 }
512
513 /* +CIPDNS:enable[,"DNS IP1"[,"DNS IP2"[,"DNS IP3"]]] */
MODEM_CMD_DEFINE(on_cmd_cipdns)514 MODEM_CMD_DEFINE(on_cmd_cipdns)
515 {
516 #if defined(ESP_MAX_DNS)
517 struct esp_data *dev = CONTAINER_OF(data, struct esp_data,
518 cmd_handler_data);
519 struct sockaddr_in *addrs = dev->dns_addresses;
520 char **servers = (char **)argv + 1;
521 size_t num_servers = argc - 1;
522 size_t valid_servers = 0;
523 size_t i;
524 int err;
525
526 for (i = 0; i < ESP_MAX_DNS; i++) {
527 if (i >= num_servers) {
528 addrs[i].sin_addr.s_addr = 0;
529 break;
530 }
531
532 servers[i] = str_unquote(servers[i]);
533 LOG_DBG("DNS[%zu]: %s", i, servers[i]);
534
535 err = net_addr_pton(AF_INET, servers[i], &addrs[i].sin_addr);
536 if (err) {
537 LOG_ERR("Invalid DNS address: %s",
538 servers[i]);
539 addrs[i].sin_addr.s_addr = 0;
540 break;
541 }
542
543 addrs[i].sin_family = AF_INET;
544 addrs[i].sin_port = htons(53);
545
546 valid_servers++;
547 }
548
549 if (valid_servers) {
550 k_work_submit(&dev->dns_work);
551 }
552 #endif
553
554 return 0;
555 }
556
557 static const struct modem_cmd response_cmds[] = {
558 MODEM_CMD("OK", on_cmd_ok, 0U, ""), /* 3GPP */
559 MODEM_CMD("ERROR", on_cmd_error, 0U, ""), /* 3GPP */
560 };
561
MODEM_CMD_DEFINE(on_cmd_wifi_connected)562 MODEM_CMD_DEFINE(on_cmd_wifi_connected)
563 {
564 struct esp_data *dev = CONTAINER_OF(data, struct esp_data,
565 cmd_handler_data);
566
567 if (esp_flags_are_set(dev, EDF_STA_CONNECTED)) {
568 return 0;
569 }
570
571 esp_flags_set(dev, EDF_STA_CONNECTED);
572 wifi_mgmt_raise_connect_result_event(dev->net_iface, 0);
573 net_if_dormant_off(dev->net_iface);
574
575 return 0;
576 }
577
esp_mgmt_disconnect_work(struct k_work * work)578 static void esp_mgmt_disconnect_work(struct k_work *work)
579 {
580 struct esp_socket *sock;
581 struct esp_data *dev;
582
583 dev = CONTAINER_OF(work, struct esp_data, disconnect_work);
584
585 /* Cleanup any sockets that weren't closed */
586 for (int i = 0; i < ARRAY_SIZE(dev->sockets); i++) {
587 sock = &dev->sockets[i];
588 if (esp_socket_connected(sock)) {
589 LOG_WRN("Socket %d left open, manually closing", i);
590 esp_socket_close(sock);
591 }
592 }
593
594 esp_flags_clear(dev, EDF_STA_CONNECTED);
595 esp_mode_switch_submit_if_needed(dev);
596
597 #if defined(CONFIG_NET_NATIVE_IPV4)
598 net_if_ipv4_addr_rm(dev->net_iface, &dev->ip);
599 #endif
600 if (!esp_flags_are_set(dev, EDF_AP_ENABLED)) {
601 net_if_dormant_on(dev->net_iface);
602 }
603 wifi_mgmt_raise_disconnect_result_event(dev->net_iface, 0);
604 }
605
MODEM_CMD_DEFINE(on_cmd_wifi_disconnected)606 MODEM_CMD_DEFINE(on_cmd_wifi_disconnected)
607 {
608 struct esp_data *dev = CONTAINER_OF(data, struct esp_data,
609 cmd_handler_data);
610
611 if (esp_flags_are_set(dev, EDF_STA_CONNECTED)) {
612 k_work_submit_to_queue(&dev->workq, &dev->disconnect_work);
613 }
614
615 return 0;
616 }
617
618 /*
619 * +CIPSTA:ip:"<ip>"
620 * +CIPSTA:gateway:"<ip>"
621 * +CIPSTA:netmask:"<ip>"
622 */
MODEM_CMD_DEFINE(on_cmd_cipsta)623 MODEM_CMD_DEFINE(on_cmd_cipsta)
624 {
625 struct esp_data *dev = CONTAINER_OF(data, struct esp_data,
626 cmd_handler_data);
627 char *ip;
628
629 ip = str_unquote(argv[1]);
630
631 if (!strcmp(argv[0], "ip")) {
632 net_addr_pton(AF_INET, ip, &dev->ip);
633 } else if (!strcmp(argv[0], "gateway")) {
634 net_addr_pton(AF_INET, ip, &dev->gw);
635 } else if (!strcmp(argv[0], "netmask")) {
636 net_addr_pton(AF_INET, ip, &dev->nm);
637 } else {
638 LOG_WRN("Unknown IP type %s", argv[0]);
639 }
640
641 return 0;
642 }
643
esp_ip_addr_work(struct k_work * work)644 static void esp_ip_addr_work(struct k_work *work)
645 {
646 struct k_work_delayable *dwork = k_work_delayable_from_work(work);
647 struct esp_data *dev = CONTAINER_OF(dwork, struct esp_data,
648 ip_addr_work);
649 int ret;
650
651 static const struct modem_cmd cmds[] = {
652 MODEM_CMD("+"_CIPSTA":", on_cmd_cipsta, 2U, ":"),
653 };
654 static const struct modem_cmd dns_cmds[] = {
655 MODEM_CMD_ARGS_MAX("+CIPDNS:", on_cmd_cipdns, 1U, 3U, ","),
656 };
657
658 ret = esp_cmd_send(dev, cmds, ARRAY_SIZE(cmds), "AT+"_CIPSTA"?",
659 ESP_CMD_TIMEOUT);
660 if (ret < 0) {
661 LOG_WRN("Failed to query IP settings: ret %d", ret);
662 k_work_reschedule_for_queue(&dev->workq, &dev->ip_addr_work,
663 K_SECONDS(5));
664 return;
665 }
666
667 #if defined(CONFIG_NET_NATIVE_IPV4)
668 /* update interface addresses */
669 #if defined(CONFIG_WIFI_ESP_AT_IP_STATIC)
670 net_if_ipv4_addr_add(dev->net_iface, &dev->ip, NET_ADDR_MANUAL, 0);
671 #else
672 net_if_ipv4_addr_add(dev->net_iface, &dev->ip, NET_ADDR_DHCP, 0);
673 #endif
674 net_if_ipv4_set_gw(dev->net_iface, &dev->gw);
675 net_if_ipv4_set_netmask_by_addr(dev->net_iface, &dev->ip, &dev->nm);
676 #endif
677
678 if (IS_ENABLED(CONFIG_WIFI_ESP_AT_DNS_USE)) {
679 ret = esp_cmd_send(dev, dns_cmds, ARRAY_SIZE(dns_cmds),
680 "AT+CIPDNS?", ESP_CMD_TIMEOUT);
681 if (ret) {
682 LOG_WRN("DNS fetch failed: %d", ret);
683 }
684 }
685 }
686
MODEM_CMD_DEFINE(on_cmd_got_ip)687 MODEM_CMD_DEFINE(on_cmd_got_ip)
688 {
689 struct esp_data *dev = CONTAINER_OF(data, struct esp_data,
690 cmd_handler_data);
691
692 k_work_reschedule_for_queue(&dev->workq, &dev->ip_addr_work,
693 K_SECONDS(1));
694
695 return 0;
696 }
697
MODEM_CMD_DEFINE(on_cmd_connect)698 MODEM_CMD_DEFINE(on_cmd_connect)
699 {
700 struct esp_socket *sock;
701 struct esp_data *dev;
702 uint8_t link_id;
703
704 link_id = data->match_buf[0] - '0';
705
706 dev = CONTAINER_OF(data, struct esp_data, cmd_handler_data);
707 sock = esp_socket_ref_from_link_id(dev, link_id);
708 if (!sock) {
709 LOG_ERR("No socket for link %d", link_id);
710 return 0;
711 }
712
713 esp_socket_unref(sock);
714
715 return 0;
716 }
717
MODEM_CMD_DEFINE(on_cmd_closed)718 MODEM_CMD_DEFINE(on_cmd_closed)
719 {
720 struct esp_socket *sock;
721 struct esp_data *dev;
722 uint8_t link_id;
723 atomic_val_t old_flags;
724
725 link_id = data->match_buf[0] - '0';
726
727 LOG_DBG("Link %d closed", link_id);
728
729 dev = CONTAINER_OF(data, struct esp_data, cmd_handler_data);
730 sock = esp_socket_ref_from_link_id(dev, link_id);
731 if (!sock) {
732 LOG_ERR("No socket for link %d", link_id);
733 return 0;
734 }
735
736 old_flags = esp_socket_flags_clear_and_set(sock,
737 ESP_SOCK_CONNECTED, ESP_SOCK_CLOSE_PENDING);
738
739 if (!(old_flags & ESP_SOCK_CONNECTED)) {
740 LOG_DBG("Link %d already closed", link_id);
741 goto socket_unref;
742 }
743
744 if (!(old_flags & ESP_SOCK_CLOSE_PENDING)) {
745 esp_socket_work_submit(sock, &sock->close_work);
746 }
747
748 socket_unref:
749 esp_socket_unref(sock);
750
751 return 0;
752 }
753
754 /*
755 * Passive mode: "+IPD,<id>,<len>\r\n"
756 * Other: "+IPD,<id>,<len>:<data>"
757 */
758 #define MIN_IPD_LEN (sizeof("+IPD,I,0E") - 1)
759 #define MAX_IPD_LEN (sizeof("+IPD,I,4294967295,\"\",65535E") - 1) + NET_IPV4_ADDR_LEN
760
cmd_ipd_parse_hdr(struct esp_data * dev,struct esp_socket ** sock,struct net_buf * buf,uint16_t len,int * data_offset,long * data_len)761 static int cmd_ipd_parse_hdr(struct esp_data *dev,
762 struct esp_socket **sock,
763 struct net_buf *buf, uint16_t len,
764 int *data_offset, long *data_len)
765 {
766 char ipd_buf[MAX_IPD_LEN + 1];
767 char *str;
768 char *str_end;
769 long link_id;
770 size_t frags_len;
771 size_t match_len;
772 int err;
773
774 frags_len = net_buf_frags_len(buf);
775
776 /* Wait until minimum cmd length is available */
777 if (frags_len < MIN_IPD_LEN) {
778 return -EAGAIN;
779 }
780
781 match_len = net_buf_linearize(ipd_buf, MAX_IPD_LEN,
782 buf, 0, MAX_IPD_LEN);
783
784 ipd_buf[match_len] = 0;
785 if (ipd_buf[len] != ',' || ipd_buf[len + 2] != ',') {
786 LOG_ERR("Invalid IPD: %s", ipd_buf);
787 return -EBADMSG;
788 }
789
790 str = &ipd_buf[len + 1];
791 str_end = &ipd_buf[match_len];
792
793 err = esp_pull_long(&str, str_end, &link_id);
794 if (err) {
795 if (err == -EAGAIN && match_len >= MAX_IPD_LEN) {
796 LOG_ERR("Failed to pull %s", "link_id");
797 return -EBADMSG;
798 }
799
800 return err;
801 }
802
803 err = esp_pull_long(&str, str_end, data_len);
804 if (err) {
805 if (err == -EAGAIN && match_len >= MAX_IPD_LEN) {
806 LOG_ERR("Failed to pull %s", "data_len");
807 return -EBADMSG;
808 }
809
810 return err;
811 }
812
813 *sock = esp_socket_ref_from_link_id(dev, link_id);
814
815 if (!*sock) {
816 LOG_ERR("No socket for link %ld", link_id);
817 *data_offset = (str - ipd_buf);
818 return -ENOTCONN;
819 }
820
821 if (!ESP_PROTO_PASSIVE(esp_socket_ip_proto(*sock)) &&
822 IS_ENABLED(CONFIG_WIFI_ESP_AT_CIPDINFO_USE)) {
823 struct sockaddr_in *recv_addr =
824 (struct sockaddr_in *) &(*sock)->context->remote;
825 char *remote_ip;
826 long port;
827
828 err = esp_pull_quoted(&str, str_end, &remote_ip);
829 if (err) {
830 if (err == -EAGAIN && match_len >= MAX_IPD_LEN) {
831 LOG_ERR("Failed to pull remote_ip");
832 err = -EBADMSG;
833 }
834 goto socket_unref;
835 }
836
837 err = esp_pull_long(&str, str_end, &port);
838 if (err) {
839 if (err == -EAGAIN && match_len >= MAX_IPD_LEN) {
840 LOG_ERR("Failed to pull port");
841 err = -EBADMSG;
842 }
843 goto socket_unref;
844 }
845
846 err = net_addr_pton(AF_INET, remote_ip, &recv_addr->sin_addr);
847 if (err) {
848 LOG_ERR("Invalid IP address");
849 err = -EBADMSG;
850 goto socket_unref;
851 }
852
853 recv_addr->sin_family = AF_INET;
854 recv_addr->sin_port = htons(port);
855 }
856
857 *data_offset = (str - ipd_buf);
858
859 return 0;
860
861 socket_unref:
862 esp_socket_unref(*sock);
863
864 return err;
865 }
866
MODEM_CMD_DIRECT_DEFINE(on_cmd_ipd)867 MODEM_CMD_DIRECT_DEFINE(on_cmd_ipd)
868 {
869 struct esp_data *dev = CONTAINER_OF(data, struct esp_data,
870 cmd_handler_data);
871 struct esp_socket *sock;
872 int data_offset;
873 long data_len;
874 int err;
875 int ret;
876
877 err = cmd_ipd_parse_hdr(dev, &sock, data->rx_buf, len,
878 &data_offset, &data_len);
879 if (err) {
880 if (err == -EAGAIN) {
881 return -EAGAIN;
882 }
883
884 return len;
885 }
886
887 /*
888 * When using passive TCP, the data itself is not included in the +IPD
889 * command but must be polled with AT+CIPRECVDATA.
890 */
891 if (ESP_PROTO_PASSIVE(esp_socket_ip_proto(sock))) {
892 esp_socket_work_submit(sock, &sock->recvdata_work);
893 ret = data_offset;
894 goto socket_unref;
895 }
896
897 /* Do we have the whole message? */
898 if (data_offset + data_len > net_buf_frags_len(data->rx_buf)) {
899 ret = -EAGAIN;
900 goto socket_unref;
901 }
902
903 esp_socket_rx(sock, data->rx_buf, data_offset, data_len);
904
905 ret = data_offset + data_len;
906
907 socket_unref:
908 esp_socket_unref(sock);
909
910 return ret;
911 }
912
MODEM_CMD_DEFINE(on_cmd_busy_sending)913 MODEM_CMD_DEFINE(on_cmd_busy_sending)
914 {
915 LOG_WRN("Busy sending");
916 return 0;
917 }
918
MODEM_CMD_DEFINE(on_cmd_busy_processing)919 MODEM_CMD_DEFINE(on_cmd_busy_processing)
920 {
921 LOG_WRN("Busy processing");
922 return 0;
923 }
924
925 /*
926 * The 'ready' command is sent when device has booted and is ready to receive
927 * commands. It is only expected after a reset of the device.
928 */
MODEM_CMD_DEFINE(on_cmd_ready)929 MODEM_CMD_DEFINE(on_cmd_ready)
930 {
931 struct esp_data *dev = CONTAINER_OF(data, struct esp_data,
932 cmd_handler_data);
933 k_sem_give(&dev->sem_if_ready);
934
935
936 if (net_if_is_carrier_ok(dev->net_iface)) {
937 net_if_dormant_on(dev->net_iface);
938 net_if_carrier_off(dev->net_iface);
939 LOG_ERR("Unexpected reset");
940 }
941
942 if (esp_flags_are_set(dev, EDF_STA_CONNECTING)) {
943 wifi_mgmt_raise_connect_result_event(dev->net_iface, -1);
944 } else if (esp_flags_are_set(dev, EDF_STA_CONNECTED)) {
945 wifi_mgmt_raise_disconnect_result_event(dev->net_iface, 0);
946 }
947
948 dev->flags = 0;
949 dev->mode = 0;
950
951 #if defined(CONFIG_NET_NATIVE_IPV4)
952 net_if_ipv4_addr_rm(dev->net_iface, &dev->ip);
953 #endif
954 k_work_submit_to_queue(&dev->workq, &dev->init_work);
955
956 return 0;
957 }
958
959 #if defined(CONFIG_WIFI_ESP_AT_FETCH_VERSION)
960
cmd_version_log(struct modem_cmd_handler_data * data,const char * type,const char * version)961 static int cmd_version_log(struct modem_cmd_handler_data *data,
962 const char *type, const char *version)
963 {
964 LOG_INF("%s: %s", type, version);
965
966 return 0;
967 }
968
MODEM_CMD_DEFINE(on_cmd_at_version)969 MODEM_CMD_DEFINE(on_cmd_at_version)
970 {
971 return cmd_version_log(data, "AT version", argv[0]);
972 }
973
MODEM_CMD_DEFINE(on_cmd_sdk_version)974 MODEM_CMD_DEFINE(on_cmd_sdk_version)
975 {
976 return cmd_version_log(data, "SDK version", argv[0]);
977 }
978
MODEM_CMD_DEFINE(on_cmd_compile_time)979 MODEM_CMD_DEFINE(on_cmd_compile_time)
980 {
981 return cmd_version_log(data, "compile time", argv[0]);
982 }
983
MODEM_CMD_DEFINE(on_cmd_bin_version)984 MODEM_CMD_DEFINE(on_cmd_bin_version)
985 {
986 return cmd_version_log(data, "Bin version", argv[0]);
987 }
988
989 #endif /* CONFIG_WIFI_ESP_AT_FETCH_VERSION */
990
991 static const struct modem_cmd unsol_cmds[] = {
992 MODEM_CMD("WIFI CONNECTED", on_cmd_wifi_connected, 0U, ""),
993 MODEM_CMD("WIFI DISCONNECT", on_cmd_wifi_disconnected, 0U, ""),
994 MODEM_CMD("WIFI GOT IP", on_cmd_got_ip, 0U, ""),
995 MODEM_CMD("0,CONNECT", on_cmd_connect, 0U, ""),
996 MODEM_CMD("1,CONNECT", on_cmd_connect, 0U, ""),
997 MODEM_CMD("2,CONNECT", on_cmd_connect, 0U, ""),
998 MODEM_CMD("3,CONNECT", on_cmd_connect, 0U, ""),
999 MODEM_CMD("4,CONNECT", on_cmd_connect, 0U, ""),
1000 MODEM_CMD("0,CLOSED", on_cmd_closed, 0U, ""),
1001 MODEM_CMD("1,CLOSED", on_cmd_closed, 0U, ""),
1002 MODEM_CMD("2,CLOSED", on_cmd_closed, 0U, ""),
1003 MODEM_CMD("3,CLOSED", on_cmd_closed, 0U, ""),
1004 MODEM_CMD("4,CLOSED", on_cmd_closed, 0U, ""),
1005 MODEM_CMD("busy s...", on_cmd_busy_sending, 0U, ""),
1006 MODEM_CMD("busy p...", on_cmd_busy_processing, 0U, ""),
1007 MODEM_CMD("ready", on_cmd_ready, 0U, ""),
1008 #if defined(CONFIG_WIFI_ESP_AT_FETCH_VERSION)
1009 MODEM_CMD("AT version:", on_cmd_at_version, 1U, ""),
1010 MODEM_CMD("SDK version:", on_cmd_sdk_version, 1U, ""),
1011 MODEM_CMD("Compile time", on_cmd_compile_time, 1U, ""),
1012 MODEM_CMD("Bin version:", on_cmd_bin_version, 1U, ""),
1013 #endif
1014 MODEM_CMD_DIRECT("+IPD", on_cmd_ipd),
1015 };
1016
esp_mgmt_iface_status_work(struct k_work * work)1017 static void esp_mgmt_iface_status_work(struct k_work *work)
1018 {
1019 struct esp_data *data = CONTAINER_OF(work, struct esp_data, iface_status_work);
1020 struct wifi_iface_status *status = data->wifi_status;
1021 int ret;
1022 static const struct modem_cmd cmds[] = {
1023 MODEM_CMD_DIRECT("+CWJAP:", on_cmd_cwjap),
1024 };
1025
1026 ret = esp_cmd_send(data, cmds, ARRAY_SIZE(cmds), "AT+CWJAP?",
1027 ESP_IFACE_STATUS_TIMEOUT);
1028 if (ret < 0) {
1029 LOG_WRN("Failed to request STA status: ret %d", ret);
1030 status->state = WIFI_STATE_UNKNOWN;
1031 }
1032
1033 k_sem_give(&data->wifi_status_sem);
1034 }
1035
esp_mgmt_iface_status(const struct device * dev,struct wifi_iface_status * status)1036 static int esp_mgmt_iface_status(const struct device *dev,
1037 struct wifi_iface_status *status)
1038 {
1039 struct esp_data *data = dev->data;
1040
1041 memset(status, 0x0, sizeof(*status));
1042
1043 status->state = WIFI_STATE_UNKNOWN;
1044 status->band = WIFI_FREQ_BAND_UNKNOWN;
1045 status->iface_mode = WIFI_MODE_UNKNOWN;
1046 status->link_mode = WIFI_LINK_MODE_UNKNOWN;
1047 status->security = WIFI_SECURITY_TYPE_UNKNOWN;
1048 status->mfp = WIFI_MFP_UNKNOWN;
1049
1050 if (!net_if_is_carrier_ok(data->net_iface)) {
1051 status->state = WIFI_STATE_INTERFACE_DISABLED;
1052 return 0;
1053 }
1054
1055 data->wifi_status = status;
1056 k_sem_init(&data->wifi_status_sem, 0, 1);
1057
1058 k_work_submit_to_queue(&data->workq, &data->iface_status_work);
1059
1060 k_sem_take(&data->wifi_status_sem, K_FOREVER);
1061
1062 return 0;
1063 }
1064
esp_mgmt_scan_work(struct k_work * work)1065 static void esp_mgmt_scan_work(struct k_work *work)
1066 {
1067 struct esp_data *dev;
1068 int ret;
1069 static const struct modem_cmd cmds[] = {
1070 MODEM_CMD_DIRECT("+CWLAP:", on_cmd_cwlap),
1071 };
1072
1073 dev = CONTAINER_OF(work, struct esp_data, scan_work);
1074
1075 ret = esp_mode_flags_set(dev, EDF_STA_LOCK);
1076 if (ret < 0) {
1077 goto out;
1078 }
1079 ret = esp_cmd_send(dev,
1080 cmds, ARRAY_SIZE(cmds),
1081 ESP_CMD_CWLAP,
1082 ESP_SCAN_TIMEOUT);
1083 esp_mode_flags_clear(dev, EDF_STA_LOCK);
1084 LOG_DBG("ESP Wi-Fi scan: cmd = %s", ESP_CMD_CWLAP);
1085
1086 if (ret < 0) {
1087 LOG_ERR("Failed to scan: ret %d", ret);
1088 }
1089
1090 out:
1091 dev->scan_cb(dev->net_iface, 0, NULL);
1092 dev->scan_cb = NULL;
1093 }
1094
esp_mgmt_scan(const struct device * dev,struct wifi_scan_params * params,scan_result_cb_t cb)1095 static int esp_mgmt_scan(const struct device *dev,
1096 struct wifi_scan_params *params,
1097 scan_result_cb_t cb)
1098 {
1099 struct esp_data *data = dev->data;
1100
1101 ARG_UNUSED(params);
1102
1103 if (data->scan_cb != NULL) {
1104 return -EINPROGRESS;
1105 }
1106
1107 if (!net_if_is_carrier_ok(data->net_iface)) {
1108 return -EIO;
1109 }
1110
1111 data->scan_cb = cb;
1112
1113 k_work_submit_to_queue(&data->workq, &data->scan_work);
1114
1115 return 0;
1116 };
1117
MODEM_CMD_DEFINE(on_cmd_fail)1118 MODEM_CMD_DEFINE(on_cmd_fail)
1119 {
1120 struct esp_data *dev = CONTAINER_OF(data, struct esp_data,
1121 cmd_handler_data);
1122
1123 modem_cmd_handler_set_error(data, -EIO);
1124 k_sem_give(&dev->sem_response);
1125
1126 return 0;
1127 }
1128
esp_mgmt_connect_work(struct k_work * work)1129 static void esp_mgmt_connect_work(struct k_work *work)
1130 {
1131 struct esp_data *dev;
1132 int ret;
1133 static const struct modem_cmd cmds[] = {
1134 MODEM_CMD("FAIL", on_cmd_fail, 0U, ""),
1135 };
1136
1137 dev = CONTAINER_OF(work, struct esp_data, connect_work);
1138
1139 ret = esp_mode_flags_set(dev, EDF_STA_LOCK);
1140 if (ret < 0) {
1141 goto out;
1142 }
1143
1144 ret = esp_cmd_send(dev, cmds, ARRAY_SIZE(cmds), dev->conn_cmd,
1145 ESP_CONNECT_TIMEOUT);
1146
1147 memset(dev->conn_cmd, 0, sizeof(dev->conn_cmd));
1148
1149 if (ret < 0) {
1150 net_if_dormant_on(dev->net_iface);
1151 if (esp_flags_are_set(dev, EDF_STA_CONNECTED)) {
1152 esp_flags_clear(dev, EDF_STA_CONNECTED);
1153 wifi_mgmt_raise_disconnect_result_event(dev->net_iface,
1154 0);
1155 } else {
1156 wifi_mgmt_raise_connect_result_event(dev->net_iface,
1157 ret);
1158 }
1159 } else if (!esp_flags_are_set(dev, EDF_STA_CONNECTED)) {
1160 esp_flags_set(dev, EDF_STA_CONNECTED);
1161 wifi_mgmt_raise_connect_result_event(dev->net_iface, 0);
1162 net_if_dormant_off(dev->net_iface);
1163 }
1164
1165 esp_mode_flags_clear(dev, EDF_STA_LOCK);
1166
1167 out:
1168 esp_flags_clear(dev, EDF_STA_CONNECTING);
1169 }
1170
esp_conn_cmd_append(struct esp_data * data,size_t * off,const char * chunk,size_t chunk_len)1171 static int esp_conn_cmd_append(struct esp_data *data, size_t *off,
1172 const char *chunk, size_t chunk_len)
1173 {
1174 char *str_end = &data->conn_cmd[sizeof(data->conn_cmd)];
1175 char *str = &data->conn_cmd[*off];
1176 const char *chunk_end = chunk + chunk_len;
1177
1178 for (; chunk < chunk_end; chunk++) {
1179 if (str_end - str < 1) {
1180 return -ENOSPC;
1181 }
1182
1183 *str = *chunk;
1184 str++;
1185 }
1186
1187 *off = str - data->conn_cmd;
1188
1189 return 0;
1190 }
1191
1192 #define esp_conn_cmd_append_literal(data, off, chunk) \
1193 esp_conn_cmd_append(data, off, chunk, sizeof(chunk) - 1)
1194
esp_conn_cmd_escape_and_append(struct esp_data * data,size_t * off,const char * chunk,size_t chunk_len)1195 static int esp_conn_cmd_escape_and_append(struct esp_data *data, size_t *off,
1196 const char *chunk, size_t chunk_len)
1197 {
1198 char *str_end = &data->conn_cmd[sizeof(data->conn_cmd)];
1199 char *str = &data->conn_cmd[*off];
1200 const char *chunk_end = chunk + chunk_len;
1201
1202 for (; chunk < chunk_end; chunk++) {
1203 switch (*chunk) {
1204 case ',':
1205 case '\\':
1206 case '"':
1207 if (str_end - str < 2) {
1208 return -ENOSPC;
1209 }
1210
1211 *str = '\\';
1212 str++;
1213
1214 break;
1215 }
1216
1217 if (str_end - str < 1) {
1218 return -ENOSPC;
1219 }
1220
1221 *str = *chunk;
1222 str++;
1223 }
1224
1225 *off = str - data->conn_cmd;
1226
1227 return 0;
1228 }
1229
esp_mgmt_connect(const struct device * dev,struct wifi_connect_req_params * params)1230 static int esp_mgmt_connect(const struct device *dev,
1231 struct wifi_connect_req_params *params)
1232 {
1233 struct esp_data *data = dev->data;
1234 size_t off = 0;
1235 int err;
1236
1237 if (!net_if_is_carrier_ok(data->net_iface) ||
1238 !net_if_is_admin_up(data->net_iface)) {
1239 return -EIO;
1240 }
1241
1242 if (esp_flags_are_set(data, EDF_STA_CONNECTED | EDF_STA_CONNECTING)) {
1243 return -EALREADY;
1244 }
1245
1246 esp_flags_set(data, EDF_STA_CONNECTING);
1247
1248 err = esp_conn_cmd_append_literal(data, &off, "AT+"_CWJAP"=\"");
1249 if (err) {
1250 return err;
1251 }
1252
1253 err = esp_conn_cmd_escape_and_append(data, &off,
1254 params->ssid, params->ssid_length);
1255 if (err) {
1256 return err;
1257 }
1258
1259 err = esp_conn_cmd_append_literal(data, &off, "\",\"");
1260 if (err) {
1261 return err;
1262 }
1263
1264 if (params->security == WIFI_SECURITY_TYPE_PSK) {
1265 err = esp_conn_cmd_escape_and_append(data, &off,
1266 params->psk, params->psk_length);
1267 if (err) {
1268 return err;
1269 }
1270 }
1271
1272 err = esp_conn_cmd_append_literal(data, &off, "\"");
1273 if (err) {
1274 return err;
1275 }
1276
1277 k_work_submit_to_queue(&data->workq, &data->connect_work);
1278
1279 return 0;
1280 }
1281
esp_mgmt_disconnect(const struct device * dev)1282 static int esp_mgmt_disconnect(const struct device *dev)
1283 {
1284 struct esp_data *data = dev->data;
1285 int ret;
1286
1287 ret = esp_cmd_send(data, NULL, 0, "AT+CWQAP", ESP_CMD_TIMEOUT);
1288
1289 return ret;
1290 }
1291
esp_mgmt_ap_enable(const struct device * dev,struct wifi_connect_req_params * params)1292 static int esp_mgmt_ap_enable(const struct device *dev,
1293 struct wifi_connect_req_params *params)
1294 {
1295 char cmd[sizeof("AT+"_CWSAP"=\"\",\"\",xx,x") + WIFI_SSID_MAX_LEN +
1296 WIFI_PSK_MAX_LEN];
1297 struct esp_data *data = dev->data;
1298 int ecn = 0, len, ret;
1299
1300 ret = esp_mode_flags_set(data, EDF_AP_ENABLED);
1301 if (ret < 0) {
1302 LOG_ERR("Failed to enable AP mode, ret %d", ret);
1303 return ret;
1304 }
1305
1306 len = snprintk(cmd, sizeof(cmd), "AT+"_CWSAP"=\"");
1307 memcpy(&cmd[len], params->ssid, params->ssid_length);
1308 len += params->ssid_length;
1309
1310 if (params->security == WIFI_SECURITY_TYPE_PSK) {
1311 len += snprintk(&cmd[len], sizeof(cmd) - len, "\",\"");
1312 memcpy(&cmd[len], params->psk, params->psk_length);
1313 len += params->psk_length;
1314 ecn = 3;
1315 } else {
1316 len += snprintk(&cmd[len], sizeof(cmd) - len, "\",\"");
1317 }
1318
1319 snprintk(&cmd[len], sizeof(cmd) - len, "\",%d,%d", params->channel,
1320 ecn);
1321
1322 ret = esp_cmd_send(data, NULL, 0, cmd, ESP_CMD_TIMEOUT);
1323
1324 net_if_dormant_off(data->net_iface);
1325
1326 return ret;
1327 }
1328
esp_mgmt_ap_disable(const struct device * dev)1329 static int esp_mgmt_ap_disable(const struct device *dev)
1330 {
1331 struct esp_data *data = dev->data;
1332
1333 if (!esp_flags_are_set(data, EDF_STA_CONNECTED)) {
1334 net_if_dormant_on(data->net_iface);
1335 }
1336
1337 return esp_mode_flags_clear(data, EDF_AP_ENABLED);
1338 }
1339
esp_init_work(struct k_work * work)1340 static void esp_init_work(struct k_work *work)
1341 {
1342 struct esp_data *dev;
1343 int ret;
1344 static const struct setup_cmd setup_cmds[] = {
1345 SETUP_CMD_NOHANDLE("AT"),
1346 /* turn off echo */
1347 SETUP_CMD_NOHANDLE("ATE0"),
1348 SETUP_CMD_NOHANDLE("AT+UART_CUR="_UART_CUR),
1349 #if DT_INST_NODE_HAS_PROP(0, target_speed)
1350 };
1351 static const struct setup_cmd setup_cmds_target_baudrate[] = {
1352 SETUP_CMD_NOHANDLE("AT"),
1353 #endif
1354 #if defined(CONFIG_WIFI_ESP_AT_FETCH_VERSION)
1355 SETUP_CMD_NOHANDLE("AT+GMR"),
1356 #endif
1357 #if defined(CONFIG_WIFI_ESP_AT_VERSION_1_7)
1358 SETUP_CMD_NOHANDLE(ESP_CMD_CWMODE(STA)),
1359 #endif
1360 #if defined(CONFIG_WIFI_ESP_AT_IP_STATIC)
1361 /* enable Static IP Config */
1362 SETUP_CMD_NOHANDLE(ESP_CMD_DHCP_ENABLE(STATION, 0)),
1363 SETUP_CMD_NOHANDLE(ESP_CMD_SET_IP(CONFIG_WIFI_ESP_AT_IP_ADDRESS,
1364 CONFIG_WIFI_ESP_AT_IP_GATEWAY,
1365 CONFIG_WIFI_ESP_AT_IP_MASK)),
1366 #else
1367 /* enable DHCP */
1368 SETUP_CMD_NOHANDLE(ESP_CMD_DHCP_ENABLE(STATION, 1)),
1369 #endif
1370 /* enable multiple socket support */
1371 SETUP_CMD_NOHANDLE("AT+CIPMUX=1"),
1372
1373 SETUP_CMD_NOHANDLE(
1374 ESP_CMD_CWLAPOPT(ESP_CMD_CWLAPOPT_ORDERED, ESP_CMD_CWLAPOPT_MASK)),
1375
1376 #if !defined(CONFIG_WIFI_ESP_AT_VERSION_1_7)
1377 SETUP_CMD_NOHANDLE(ESP_CMD_CWMODE(STA)),
1378 SETUP_CMD_NOHANDLE("AT+CWAUTOCONN=0"),
1379 SETUP_CMD_NOHANDLE(ESP_CMD_CWMODE(NONE)),
1380 #endif
1381 #if defined(CONFIG_WIFI_ESP_AT_PASSIVE_MODE)
1382 SETUP_CMD_NOHANDLE("AT+CIPRECVMODE=1"),
1383 #endif
1384 #if defined(CONFIG_WIFI_ESP_AT_CIPDINFO_USE)
1385 SETUP_CMD_NOHANDLE("AT+CIPDINFO=1"),
1386 #endif
1387 SETUP_CMD("AT+"_CIPSTAMAC"?", "+"_CIPSTAMAC":",
1388 on_cmd_cipstamac, 1U, ""),
1389 };
1390
1391 dev = CONTAINER_OF(work, struct esp_data, init_work);
1392
1393 ret = modem_cmd_handler_setup_cmds(&dev->mctx.iface,
1394 &dev->mctx.cmd_handler, setup_cmds,
1395 ARRAY_SIZE(setup_cmds),
1396 &dev->sem_response,
1397 ESP_INIT_TIMEOUT);
1398 if (ret < 0) {
1399 LOG_ERR("Init failed %d", ret);
1400 return;
1401 }
1402
1403 #if DT_INST_NODE_HAS_PROP(0, target_speed)
1404 static const struct uart_config uart_config = {
1405 .baudrate = DT_INST_PROP(0, target_speed),
1406 .parity = UART_CFG_PARITY_NONE,
1407 .stop_bits = UART_CFG_STOP_BITS_1,
1408 .data_bits = UART_CFG_DATA_BITS_8,
1409 .flow_ctrl = DT_PROP(ESP_BUS, hw_flow_control) ?
1410 UART_CFG_FLOW_CTRL_RTS_CTS : UART_CFG_FLOW_CTRL_NONE,
1411 };
1412
1413 ret = uart_configure(DEVICE_DT_GET(DT_INST_BUS(0)), &uart_config);
1414 if (ret < 0) {
1415 LOG_ERR("Baudrate change failed %d", ret);
1416 return;
1417 }
1418
1419 /* arbitrary sleep period to give ESP enough time to reconfigure */
1420 k_sleep(K_MSEC(100));
1421
1422 ret = modem_cmd_handler_setup_cmds(&dev->mctx.iface,
1423 &dev->mctx.cmd_handler,
1424 setup_cmds_target_baudrate,
1425 ARRAY_SIZE(setup_cmds_target_baudrate),
1426 &dev->sem_response,
1427 ESP_INIT_TIMEOUT);
1428 if (ret < 0) {
1429 LOG_ERR("Init failed %d", ret);
1430 return;
1431 }
1432 #endif
1433
1434 net_if_set_link_addr(dev->net_iface, dev->mac_addr,
1435 sizeof(dev->mac_addr), NET_LINK_ETHERNET);
1436
1437 if (IS_ENABLED(CONFIG_WIFI_ESP_AT_VERSION_1_7)) {
1438 /* This is the mode entered in above setup commands */
1439 dev->mode = ESP_MODE_STA;
1440
1441 /*
1442 * In case of ESP 1.7 this is the first time CWMODE is entered
1443 * STA mode, so request hostname change now.
1444 */
1445 esp_configure_hostname(dev);
1446 }
1447
1448 LOG_INF("ESP Wi-Fi ready");
1449
1450 /* L1 network layer (physical layer) is up */
1451 net_if_carrier_on(dev->net_iface);
1452
1453 k_sem_give(&dev->sem_if_up);
1454 }
1455
esp_reset(const struct device * dev)1456 static int esp_reset(const struct device *dev)
1457 {
1458 struct esp_data *data = dev->data;
1459 int ret = -EAGAIN;
1460
1461 if (net_if_is_carrier_ok(data->net_iface)) {
1462 net_if_carrier_off(data->net_iface);
1463 }
1464
1465 #if DT_INST_NODE_HAS_PROP(0, power_gpios)
1466 const struct esp_config *config = dev->config;
1467
1468 gpio_pin_set_dt(&config->power, 0);
1469 k_sleep(K_MSEC(100));
1470 gpio_pin_set_dt(&config->power, 1);
1471 #elif DT_INST_NODE_HAS_PROP(0, reset_gpios)
1472 const struct esp_config *config = dev->config;
1473
1474 gpio_pin_set_dt(&config->reset, 1);
1475 k_sleep(K_MSEC(100));
1476 gpio_pin_set_dt(&config->reset, 0);
1477 #else
1478 #if DT_INST_NODE_HAS_PROP(0, external_reset)
1479 /* Wait to see if the interface comes up by itself */
1480 ret = k_sem_take(&data->sem_if_ready, K_MSEC(CONFIG_WIFI_ESP_AT_RESET_TIMEOUT));
1481 #endif
1482 int retries = 3;
1483
1484 /* Don't need to run this if the interface came up by itself */
1485 while ((ret != 0) && retries--) {
1486 ret = modem_cmd_send(&data->mctx.iface, &data->mctx.cmd_handler,
1487 NULL, 0, "AT+RST", &data->sem_if_ready,
1488 K_MSEC(CONFIG_WIFI_ESP_AT_RESET_TIMEOUT));
1489 if (ret == 0 || ret != -ETIMEDOUT) {
1490 break;
1491 }
1492 }
1493
1494 if (ret < 0) {
1495 LOG_ERR("Failed to reset device: %d", ret);
1496 return -EAGAIN;
1497 }
1498 #endif
1499 LOG_INF("Waiting for interface to come up");
1500
1501 ret = k_sem_take(&data->sem_if_up, ESP_INIT_TIMEOUT);
1502 if (ret == -EAGAIN) {
1503 LOG_ERR("Timeout waiting for interface");
1504 }
1505
1506 return ret;
1507 }
1508
esp_iface_init(struct net_if * iface)1509 static void esp_iface_init(struct net_if *iface)
1510 {
1511 esp_offload_init(iface);
1512
1513 /* Not currently connected to a network */
1514 net_if_dormant_on(iface);
1515 }
1516
esp_offload_get_type(void)1517 static enum offloaded_net_if_types esp_offload_get_type(void)
1518 {
1519 return L2_OFFLOADED_NET_IF_TYPE_WIFI;
1520 }
1521
1522 static const struct wifi_mgmt_ops esp_mgmt_ops = {
1523 .scan = esp_mgmt_scan,
1524 .connect = esp_mgmt_connect,
1525 .disconnect = esp_mgmt_disconnect,
1526 .ap_enable = esp_mgmt_ap_enable,
1527 .ap_disable = esp_mgmt_ap_disable,
1528 .iface_status = esp_mgmt_iface_status,
1529 };
1530
1531 static const struct net_wifi_mgmt_offload esp_api = {
1532 .wifi_iface.iface_api.init = esp_iface_init,
1533 .wifi_iface.get_type = esp_offload_get_type,
1534 .wifi_mgmt_api = &esp_mgmt_ops,
1535 };
1536
1537 static int esp_init(const struct device *dev);
1538
1539 /* The network device must be instantiated above the init function in order
1540 * for the struct net_if that the macro declares to be visible inside the
1541 * function. An `extern` declaration does not work as the struct is static.
1542 */
1543 NET_DEVICE_DT_INST_OFFLOAD_DEFINE(0, esp_init, NULL,
1544 &esp_driver_data, &esp_driver_config,
1545 CONFIG_WIFI_INIT_PRIORITY, &esp_api,
1546 ESP_MTU);
1547
1548 CONNECTIVITY_WIFI_MGMT_BIND(Z_DEVICE_DT_DEV_ID(DT_DRV_INST(0)));
1549
esp_init(const struct device * dev)1550 static int esp_init(const struct device *dev)
1551 {
1552 #if DT_INST_NODE_HAS_PROP(0, power_gpios) || DT_INST_NODE_HAS_PROP(0, reset_gpios)
1553 const struct esp_config *config = dev->config;
1554 #endif
1555 struct esp_data *data = dev->data;
1556 int ret = 0;
1557
1558 k_sem_init(&data->sem_tx_ready, 0, 1);
1559 k_sem_init(&data->sem_response, 0, 1);
1560 k_sem_init(&data->sem_if_ready, 0, 1);
1561 k_sem_init(&data->sem_if_up, 0, 1);
1562
1563 k_work_init(&data->init_work, esp_init_work);
1564 k_work_init_delayable(&data->ip_addr_work, esp_ip_addr_work);
1565 k_work_init(&data->scan_work, esp_mgmt_scan_work);
1566 k_work_init(&data->connect_work, esp_mgmt_connect_work);
1567 k_work_init(&data->disconnect_work, esp_mgmt_disconnect_work);
1568 k_work_init(&data->iface_status_work, esp_mgmt_iface_status_work);
1569 k_work_init(&data->mode_switch_work, esp_mode_switch_work);
1570 if (IS_ENABLED(CONFIG_WIFI_ESP_AT_DNS_USE)) {
1571 k_work_init(&data->dns_work, esp_dns_work);
1572 }
1573
1574 esp_socket_init(data);
1575
1576 /* initialize the work queue */
1577 k_work_queue_start(&data->workq, esp_workq_stack,
1578 K_KERNEL_STACK_SIZEOF(esp_workq_stack),
1579 K_PRIO_COOP(CONFIG_WIFI_ESP_AT_WORKQ_THREAD_PRIORITY),
1580 NULL);
1581 k_thread_name_set(&data->workq.thread, "esp_workq");
1582
1583 /* cmd handler */
1584 const struct modem_cmd_handler_config cmd_handler_config = {
1585 .match_buf = &data->cmd_match_buf[0],
1586 .match_buf_len = sizeof(data->cmd_match_buf),
1587 .buf_pool = &mdm_recv_pool,
1588 .alloc_timeout = K_NO_WAIT,
1589 .eol = "\r\n",
1590 .user_data = NULL,
1591 .response_cmds = response_cmds,
1592 .response_cmds_len = ARRAY_SIZE(response_cmds),
1593 .unsol_cmds = unsol_cmds,
1594 .unsol_cmds_len = ARRAY_SIZE(unsol_cmds),
1595 };
1596
1597 ret = modem_cmd_handler_init(&data->mctx.cmd_handler, &data->cmd_handler_data,
1598 &cmd_handler_config);
1599 if (ret < 0) {
1600 goto error;
1601 }
1602
1603 /* modem interface */
1604 const struct modem_iface_uart_config uart_config = {
1605 .rx_rb_buf = &data->iface_rb_buf[0],
1606 .rx_rb_buf_len = sizeof(data->iface_rb_buf),
1607 .dev = DEVICE_DT_GET(DT_INST_BUS(0)),
1608 .hw_flow_control = DT_PROP(ESP_BUS, hw_flow_control),
1609 };
1610
1611 /* The context must be registered before the serial port is initialised. */
1612 data->mctx.driver_data = data;
1613 ret = modem_context_register(&data->mctx);
1614 if (ret < 0) {
1615 LOG_ERR("Error registering modem context: %d", ret);
1616 goto error;
1617 }
1618
1619 ret = modem_iface_uart_init(&data->mctx.iface, &data->iface_data, &uart_config);
1620 if (ret < 0) {
1621 goto error;
1622 }
1623
1624 /* pin setup */
1625 #if DT_INST_NODE_HAS_PROP(0, power_gpios)
1626 ret = gpio_pin_configure_dt(&config->power, GPIO_OUTPUT_INACTIVE);
1627 if (ret < 0) {
1628 LOG_ERR("Failed to configure %s pin", "power");
1629 goto error;
1630 }
1631 #endif
1632 #if DT_INST_NODE_HAS_PROP(0, reset_gpios)
1633 ret = gpio_pin_configure_dt(&config->reset, GPIO_OUTPUT_INACTIVE);
1634 if (ret < 0) {
1635 LOG_ERR("Failed to configure %s pin", "reset");
1636 goto error;
1637 }
1638 #endif
1639
1640 /* start RX thread */
1641 k_thread_create(&esp_rx_thread, esp_rx_stack,
1642 K_KERNEL_STACK_SIZEOF(esp_rx_stack),
1643 esp_rx,
1644 data, NULL, NULL,
1645 K_PRIO_COOP(CONFIG_WIFI_ESP_AT_RX_THREAD_PRIORITY), 0,
1646 K_NO_WAIT);
1647 k_thread_name_set(&esp_rx_thread, "esp_rx");
1648
1649 /* Retrieve associated network interface so asynchronous messages can be processed early */
1650 data->net_iface = NET_IF_GET(Z_DEVICE_DT_DEV_ID(DT_DRV_INST(0)), 0);
1651
1652 /* Reset the modem */
1653 ret = esp_reset(dev);
1654
1655 error:
1656 return ret;
1657 }
1658