1 /*
2 * Copyright (c) 2019 Tobias Svehagen
3 * Copyright (c) 2020 Grinn
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #ifndef ZEPHYR_INCLUDE_DRIVERS_WIFI_ESP_AT_ESP_H_
9 #define ZEPHYR_INCLUDE_DRIVERS_WIFI_ESP_AT_ESP_H_
10
11 #include <zephyr/kernel.h>
12 #include <zephyr/net/net_context.h>
13 #include <zephyr/net/net_if.h>
14 #include <zephyr/net/net_ip.h>
15 #include <zephyr/net/net_pkt.h>
16 #include <zephyr/net/wifi_mgmt.h>
17
18 #include "modem_context.h"
19 #include "modem_cmd_handler.h"
20 #include "modem_iface_uart.h"
21
22 #ifdef __cplusplus
23 extern "C" {
24 #endif
25
26 /* Define the commands that differ between the AT versions */
27 #if defined(CONFIG_WIFI_ESP_AT_VERSION_1_7)
28 #define _CWMODE "CWMODE_CUR"
29 #define _CWSAP "CWSAP_CUR"
30 #define _CWJAP "CWJAP_CUR"
31 #define _CIPSTA "CIPSTA_CUR"
32 #define _CIPSTAMAC "CIPSTAMAC_CUR"
33 #define _CIPRECVDATA "+CIPRECVDATA,"
34 #define _CIPRECVDATA_END ':'
35 #else
36 #define _CWMODE "CWMODE"
37 #define _CWSAP "CWSAP"
38 #define _CWJAP "CWJAP"
39 #define _CIPSTA "CIPSTA"
40 #define _CIPSTAMAC "CIPSTAMAC"
41 #define _CIPRECVDATA "+CIPRECVDATA:"
42 #define _CIPRECVDATA_END ','
43 #endif
44
45 /*
46 * Passive mode differs a bit between firmware versions and the macro
47 * ESP_PROTO_PASSIVE is therefore used to determine what protocol operates in
48 * passive mode. For AT version 1.7 passive mode only affects TCP but in AT
49 * version 2.0 it affects both TCP and UDP.
50 */
51 #if defined(CONFIG_WIFI_ESP_AT_PASSIVE_MODE)
52 #if defined(CONFIG_WIFI_ESP_AT_VERSION_1_7)
53 #define ESP_PROTO_PASSIVE(proto) (proto == IPPROTO_TCP)
54 #else
55 #define ESP_PROTO_PASSIVE(proto) \
56 (proto == IPPROTO_TCP || proto == IPPROTO_UDP)
57 #endif /* CONFIG_WIFI_ESP_AT_VERSION_1_7 */
58 #else
59 #define ESP_PROTO_PASSIVE(proto) 0
60 #endif /* CONFIG_WIFI_ESP_AT_PASSIVE_MODE */
61
62 #define ESP_BUS DT_INST_BUS(0)
63
64 #if DT_PROP(ESP_BUS, hw_flow_control) == 1
65 #define _FLOW_CONTROL "3"
66 #else
67 #define _FLOW_CONTROL "0"
68 #endif
69
70 #if DT_INST_NODE_HAS_PROP(0, target_speed)
71 #define _UART_BAUD DT_INST_PROP(0, target_speed)
72 #else
73 #define _UART_BAUD DT_PROP(ESP_BUS, current_speed)
74 #endif
75
76 #define _UART_CUR \
77 STRINGIFY(_UART_BAUD)",8,1,0,"_FLOW_CONTROL
78
79 #define CONN_CMD_MAX_LEN (sizeof("AT+"_CWJAP"=\"\",\"\"") + \
80 WIFI_SSID_MAX_LEN + WIFI_PSK_MAX_LEN)
81
82 #if defined(CONFIG_WIFI_ESP_AT_DNS_USE)
83 #define ESP_MAX_DNS MIN(3, CONFIG_DNS_RESOLVER_MAX_SERVERS)
84 #endif
85
86 #define ESP_MAX_SOCKETS 5
87
88 /* Maximum amount that can be sent with CIPSEND and read with CIPRECVDATA */
89 #define ESP_MTU 2048
90 #define CIPRECVDATA_MAX_LEN ESP_MTU
91
92 #define INVALID_LINK_ID 255
93
94 #define MDM_RING_BUF_SIZE CONFIG_WIFI_ESP_AT_MDM_RING_BUF_SIZE
95 #define MDM_RECV_MAX_BUF CONFIG_WIFI_ESP_AT_MDM_RX_BUF_COUNT
96 #define MDM_RECV_BUF_SIZE CONFIG_WIFI_ESP_AT_MDM_RX_BUF_SIZE
97
98 #define ESP_CMD_TIMEOUT K_SECONDS(10)
99 #define ESP_SCAN_TIMEOUT K_SECONDS(10)
100 #define ESP_CONNECT_TIMEOUT K_SECONDS(20)
101 #define ESP_IFACE_STATUS_TIMEOUT K_SECONDS(10)
102 #define ESP_INIT_TIMEOUT K_SECONDS(10)
103
104 #define ESP_MODE_NONE 0
105 #define ESP_MODE_STA 1
106 #define ESP_MODE_AP 2
107 #define ESP_MODE_STA_AP 3
108
109 #if defined(CONFIG_WIFI_ESP_AT_VERSION_1_7) || defined(CONFIG_WIFI_ESP_AT_VERSION_2_0)
110 #define ESP_CMD_CWMODE(mode) "AT+"_CWMODE"="STRINGIFY(_CONCAT(ESP_MODE_, mode))
111 #else
112 #define ESP_CMD_CWMODE(mode) "AT+"_CWMODE"="STRINGIFY(_CONCAT(ESP_MODE_, mode))",0"
113 #endif
114
115 #define ESP_CWDHCP_MODE_STATION "1"
116 #if defined(CONFIG_WIFI_ESP_AT_VERSION_1_7)
117 #define ESP_CWDHCP_MODE_SOFTAP "0"
118 #else
119 #define ESP_CWDHCP_MODE_SOFTAP "2"
120 #endif
121
122 #if defined(CONFIG_WIFI_ESP_AT_VERSION_1_7)
123 #define _ESP_CMD_DHCP_ENABLE(mode, enable) \
124 "AT+CWDHCP_CUR=" mode "," STRINGIFY(enable)
125 #else
126 #define _ESP_CMD_DHCP_ENABLE(mode, enable) \
127 "AT+CWDHCP=" STRINGIFY(enable) "," mode
128 #endif
129
130 #define ESP_CMD_DHCP_ENABLE(mode, enable) \
131 _ESP_CMD_DHCP_ENABLE(_CONCAT(ESP_CWDHCP_MODE_, mode), enable)
132
133 #define ESP_CMD_SET_IP(ip, gateway, mask) "AT+"_CIPSTA"=\"" \
134 ip "\",\"" gateway "\",\"" mask "\""
135
136 #if defined(CONFIG_WIFI_ESP_AT_SCAN_PASSIVE)
137 #define ESP_CMD_CWLAP "AT+CWLAP=,,,1,,"
138 #else
139 #define ESP_CMD_CWLAP "AT+CWLAP"
140 #endif
141
142 #if defined(CONFIG_WIFI_ESP_AT_SCAN_RESULT_RSSI_ORDERED)
143 #define ESP_CMD_CWLAPOPT_ORDERED "1"
144 #else
145 #define ESP_CMD_CWLAPOPT_ORDERED "0"
146 #endif
147
148 #if defined(CONFIG_WIFI_ESP_AT_SCAN_MAC_ADDRESS)
149 /* We need ecn,ssid,rssi,mac,channel */
150 #define ESP_CMD_CWLAPOPT_MASK "31"
151 #else
152 /* no mac: only need ecn,ssid,rssi,channel */
153 #define ESP_CMD_CWLAPOPT_MASK "23"
154 #endif
155
156 #define ESP_CMD_CWLAPOPT(sort, mask) "AT+CWLAPOPT=" sort "," mask
157
158 extern struct esp_data esp_driver_data;
159
160 enum esp_socket_flags {
161 ESP_SOCK_IN_USE = BIT(1),
162 ESP_SOCK_CONNECTING = BIT(2),
163 ESP_SOCK_CONNECTED = BIT(3),
164 ESP_SOCK_CLOSE_PENDING = BIT(4),
165 ESP_SOCK_WORKQ_STOPPED = BIT(5),
166 };
167
168 struct esp_socket {
169 /* internal */
170 struct k_mutex lock;
171 atomic_t refcount;
172
173 uint8_t idx;
174 uint8_t link_id;
175 atomic_t flags;
176
177 /* socket info */
178 struct sockaddr dst;
179
180 /* sem */
181 union {
182 /* handles blocking receive */
183 struct k_sem sem_data_ready;
184
185 /* notifies about reaching 0 refcount */
186 struct k_sem sem_free;
187 };
188
189 /* work */
190 struct k_work connect_work;
191 struct k_work recvdata_work;
192 struct k_work send_work;
193 struct k_work close_work;
194
195 /* TX packets fifo */
196 struct k_fifo tx_fifo;
197
198 /* net context */
199 struct net_context *context;
200 net_context_connect_cb_t connect_cb;
201 net_context_recv_cb_t recv_cb;
202
203 /* callback data */
204 void *conn_user_data;
205 void *recv_user_data;
206 };
207
208 enum esp_data_flag {
209 EDF_STA_CONNECTING = BIT(1),
210 EDF_STA_CONNECTED = BIT(2),
211 EDF_STA_LOCK = BIT(3),
212 EDF_AP_ENABLED = BIT(4),
213 };
214
215 /* driver data */
216 struct esp_data {
217 struct net_if *net_iface;
218
219 uint8_t flags;
220 uint8_t mode;
221
222 char conn_cmd[CONN_CMD_MAX_LEN];
223
224 /* addresses */
225 struct in_addr ip;
226 struct in_addr gw;
227 struct in_addr nm;
228 uint8_t mac_addr[6];
229 #if defined(ESP_MAX_DNS)
230 struct sockaddr_in dns_addresses[ESP_MAX_DNS];
231 #endif
232
233 /* modem context */
234 struct modem_context mctx;
235
236 /* modem interface */
237 struct modem_iface_uart_data iface_data;
238 uint8_t iface_rb_buf[MDM_RING_BUF_SIZE];
239
240 /* modem cmds */
241 struct modem_cmd_handler_data cmd_handler_data;
242 uint8_t cmd_match_buf[MDM_RECV_BUF_SIZE];
243
244 /* socket data */
245 struct esp_socket sockets[ESP_MAX_SOCKETS];
246 struct esp_socket *rx_sock;
247
248 /* work */
249 struct k_work_q workq;
250 struct k_work init_work;
251 struct k_work_delayable ip_addr_work;
252 struct k_work scan_work;
253 struct k_work connect_work;
254 struct k_work disconnect_work;
255 struct k_work iface_status_work;
256 struct k_work mode_switch_work;
257 struct k_work dns_work;
258
259 scan_result_cb_t scan_cb;
260 struct wifi_iface_status *wifi_status;
261 struct k_sem wifi_status_sem;
262
263 /* semaphores */
264 struct k_sem sem_tx_ready;
265 struct k_sem sem_response;
266 struct k_sem sem_if_ready;
267 struct k_sem sem_if_up;
268 };
269
270 int esp_offload_init(struct net_if *iface);
271
272 struct esp_socket *esp_socket_get(struct esp_data *data,
273 struct net_context *context);
274 int esp_socket_put(struct esp_socket *sock);
275 void esp_socket_init(struct esp_data *data);
276 void esp_socket_close(struct esp_socket *sock);
277 void esp_socket_rx(struct esp_socket *sock, struct net_buf *buf,
278 size_t offset, size_t len);
279 void esp_socket_workq_stop_and_flush(struct esp_socket *sock);
280 struct esp_socket *esp_socket_ref(struct esp_socket *sock);
281 void esp_socket_unref(struct esp_socket *sock);
282
283 static inline
esp_socket_ref_from_link_id(struct esp_data * data,uint8_t link_id)284 struct esp_socket *esp_socket_ref_from_link_id(struct esp_data *data,
285 uint8_t link_id)
286 {
287 if (link_id >= ARRAY_SIZE(data->sockets)) {
288 return NULL;
289 }
290
291 return esp_socket_ref(&data->sockets[link_id]);
292 }
293
esp_socket_flags_update(struct esp_socket * sock,atomic_val_t value,atomic_val_t mask)294 static inline atomic_val_t esp_socket_flags_update(struct esp_socket *sock,
295 atomic_val_t value,
296 atomic_val_t mask)
297 {
298 atomic_val_t flags;
299
300 do {
301 flags = atomic_get(&sock->flags);
302 } while (!atomic_cas(&sock->flags, flags, (flags & ~mask) | value));
303
304 return flags;
305 }
306
307 static inline
esp_socket_flags_clear_and_set(struct esp_socket * sock,atomic_val_t clear_flags,atomic_val_t set_flags)308 atomic_val_t esp_socket_flags_clear_and_set(struct esp_socket *sock,
309 atomic_val_t clear_flags,
310 atomic_val_t set_flags)
311 {
312 return esp_socket_flags_update(sock, set_flags,
313 clear_flags | set_flags);
314 }
315
esp_socket_flags_set(struct esp_socket * sock,atomic_val_t flags)316 static inline atomic_val_t esp_socket_flags_set(struct esp_socket *sock,
317 atomic_val_t flags)
318 {
319 return atomic_or(&sock->flags, flags);
320 }
321
esp_socket_flags_test_and_clear(struct esp_socket * sock,atomic_val_t flags)322 static inline bool esp_socket_flags_test_and_clear(struct esp_socket *sock,
323 atomic_val_t flags)
324 {
325 return (atomic_and(&sock->flags, ~flags) & flags);
326 }
327
esp_socket_flags_test_and_set(struct esp_socket * sock,atomic_val_t flags)328 static inline bool esp_socket_flags_test_and_set(struct esp_socket *sock,
329 atomic_val_t flags)
330 {
331 return (atomic_or(&sock->flags, flags) & flags);
332 }
333
esp_socket_flags_clear(struct esp_socket * sock,atomic_val_t flags)334 static inline atomic_val_t esp_socket_flags_clear(struct esp_socket *sock,
335 atomic_val_t flags)
336 {
337 return atomic_and(&sock->flags, ~flags);
338 }
339
esp_socket_flags(struct esp_socket * sock)340 static inline atomic_val_t esp_socket_flags(struct esp_socket *sock)
341 {
342 return atomic_get(&sock->flags);
343 }
344
esp_socket_to_dev(struct esp_socket * sock)345 static inline struct esp_data *esp_socket_to_dev(struct esp_socket *sock)
346 {
347 return CONTAINER_OF(sock - sock->idx, struct esp_data, sockets[0]);
348 }
349
__esp_socket_work_submit(struct esp_socket * sock,struct k_work * work)350 static inline void __esp_socket_work_submit(struct esp_socket *sock,
351 struct k_work *work)
352 {
353 struct esp_data *data = esp_socket_to_dev(sock);
354
355 k_work_submit_to_queue(&data->workq, work);
356 }
357
esp_socket_work_submit(struct esp_socket * sock,struct k_work * work)358 static inline int esp_socket_work_submit(struct esp_socket *sock,
359 struct k_work *work)
360 {
361 int ret = -EBUSY;
362
363 k_mutex_lock(&sock->lock, K_FOREVER);
364 if (!(esp_socket_flags(sock) & ESP_SOCK_WORKQ_STOPPED)) {
365 __esp_socket_work_submit(sock, work);
366 ret = 0;
367 }
368 k_mutex_unlock(&sock->lock);
369
370 return ret;
371 }
372
esp_socket_queue_tx(struct esp_socket * sock,struct net_pkt * pkt)373 static inline int esp_socket_queue_tx(struct esp_socket *sock,
374 struct net_pkt *pkt)
375 {
376 int ret = -EBUSY;
377
378 k_mutex_lock(&sock->lock, K_FOREVER);
379 if (!(esp_socket_flags(sock) & ESP_SOCK_WORKQ_STOPPED)) {
380 k_fifo_put(&sock->tx_fifo, pkt);
381 __esp_socket_work_submit(sock, &sock->send_work);
382 ret = 0;
383 }
384 k_mutex_unlock(&sock->lock);
385
386 return ret;
387 }
388
esp_socket_connected(struct esp_socket * sock)389 static inline bool esp_socket_connected(struct esp_socket *sock)
390 {
391 return (esp_socket_flags(sock) & ESP_SOCK_CONNECTED) != 0;
392 }
393
esp_flags_set(struct esp_data * dev,uint8_t flags)394 static inline void esp_flags_set(struct esp_data *dev, uint8_t flags)
395 {
396 dev->flags |= flags;
397 }
398
esp_flags_clear(struct esp_data * dev,uint8_t flags)399 static inline void esp_flags_clear(struct esp_data *dev, uint8_t flags)
400 {
401 dev->flags &= (~flags);
402 }
403
esp_flags_are_set(struct esp_data * dev,uint8_t flags)404 static inline bool esp_flags_are_set(struct esp_data *dev, uint8_t flags)
405 {
406 return (dev->flags & flags) != 0;
407 }
408
esp_socket_type(struct esp_socket * sock)409 static inline enum net_sock_type esp_socket_type(struct esp_socket *sock)
410 {
411 return net_context_get_type(sock->context);
412 }
413
esp_socket_ip_proto(struct esp_socket * sock)414 static inline enum net_ip_protocol esp_socket_ip_proto(struct esp_socket *sock)
415 {
416 return net_context_get_proto(sock->context);
417 }
418
esp_cmd_send(struct esp_data * data,const struct modem_cmd * handlers,size_t handlers_len,const char * buf,k_timeout_t timeout)419 static inline int esp_cmd_send(struct esp_data *data,
420 const struct modem_cmd *handlers,
421 size_t handlers_len, const char *buf,
422 k_timeout_t timeout)
423 {
424 return modem_cmd_send(&data->mctx.iface, &data->mctx.cmd_handler,
425 handlers, handlers_len, buf, &data->sem_response,
426 timeout);
427 }
428
429 void esp_connect_work(struct k_work *work);
430 void esp_recvdata_work(struct k_work *work);
431 void esp_close_work(struct k_work *work);
432 void esp_send_work(struct k_work *work);
433
434 #ifdef __cplusplus
435 }
436 #endif
437
438 #endif /* ZEPHYR_INCLUDE_DRIVERS_WIFI_ESP_AT_ESP_H_ */
439