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 == NET_IPPROTO_TCP)
54 #else
55 #define ESP_PROTO_PASSIVE(proto) \
56 	(proto == NET_IPPROTO_TCP || proto == NET_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 * 2 + WIFI_PSK_MAX_LEN * 2)
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 net_sockaddr src;
179 	struct net_sockaddr dst;
180 
181 	/* sem */
182 	union {
183 		/* handles blocking receive */
184 		struct k_sem sem_data_ready;
185 
186 		/* notifies about reaching 0 refcount */
187 		struct k_sem sem_free;
188 	};
189 
190 	/* work */
191 	struct k_work connect_work;
192 	struct k_work recvdata_work;
193 	struct k_work send_work;
194 	struct k_work close_work;
195 
196 	/* TX packets fifo */
197 	struct k_fifo tx_fifo;
198 
199 	/* net context */
200 	struct net_context *context;
201 	net_context_connect_cb_t connect_cb;
202 	net_context_recv_cb_t recv_cb;
203 
204 	/* callback data */
205 	void *conn_user_data;
206 	void *recv_user_data;
207 };
208 
209 enum esp_data_flag {
210 	EDF_STA_CONNECTING = BIT(1),
211 	EDF_STA_CONNECTED  = BIT(2),
212 	EDF_STA_LOCK       = BIT(3),
213 	EDF_AP_ENABLED     = BIT(4),
214 };
215 
216 /* driver data */
217 struct esp_data {
218 	struct net_if *net_iface;
219 
220 	uint8_t flags;
221 	uint8_t mode;
222 
223 	char conn_cmd[CONN_CMD_MAX_LEN];
224 	enum wifi_conn_status conn_status;
225 
226 	/* addresses  */
227 	struct net_in_addr ip;
228 	struct net_in_addr gw;
229 	struct net_in_addr nm;
230 	uint8_t mac_addr[6];
231 #if defined(ESP_MAX_DNS)
232 	struct net_sockaddr_in dns_addresses[ESP_MAX_DNS];
233 #endif
234 
235 	/* modem context */
236 	struct modem_context mctx;
237 
238 	/* modem interface */
239 	struct modem_iface_uart_data iface_data;
240 	uint8_t iface_rb_buf[MDM_RING_BUF_SIZE];
241 
242 	/* modem cmds */
243 	struct modem_cmd_handler_data cmd_handler_data;
244 	uint8_t cmd_match_buf[MDM_RECV_BUF_SIZE];
245 
246 	/* socket data */
247 	struct esp_socket sockets[ESP_MAX_SOCKETS];
248 	struct esp_socket *rx_sock;
249 
250 	/* work */
251 	struct k_work_q workq;
252 	struct k_work init_work;
253 	struct k_work_delayable ip_addr_work;
254 	struct k_work scan_work;
255 	struct k_work connect_work;
256 	struct k_work disconnect_work;
257 	struct k_work iface_status_work;
258 	struct k_work mode_switch_work;
259 	struct k_work dns_work;
260 
261 	scan_result_cb_t scan_cb;
262 	struct wifi_iface_status *wifi_status;
263 	struct k_sem wifi_status_sem;
264 
265 	/* semaphores */
266 	struct k_sem sem_tx_ready;
267 	struct k_sem sem_response;
268 	struct k_sem sem_if_ready;
269 	struct k_sem sem_if_up;
270 };
271 
272 int esp_offload_init(struct net_if *iface);
273 
274 struct esp_socket *esp_socket_get(struct esp_data *data,
275 				  struct net_context *context);
276 int esp_socket_put(struct esp_socket *sock);
277 void esp_socket_init(struct esp_data *data);
278 void esp_socket_close(struct esp_socket *sock);
279 void esp_socket_rx(struct esp_socket *sock, struct net_buf *buf,
280 		   size_t offset, size_t len);
281 void esp_socket_workq_stop_and_flush(struct esp_socket *sock);
282 struct esp_socket *esp_socket_ref(struct esp_socket *sock);
283 void esp_socket_unref(struct esp_socket *sock);
284 
285 static inline
esp_socket_ref_from_link_id(struct esp_data * data,uint8_t link_id)286 struct esp_socket *esp_socket_ref_from_link_id(struct esp_data *data,
287 					       uint8_t link_id)
288 {
289 	if (link_id >= ARRAY_SIZE(data->sockets)) {
290 		return NULL;
291 	}
292 
293 	return esp_socket_ref(&data->sockets[link_id]);
294 }
295 
esp_socket_flags_update(struct esp_socket * sock,atomic_val_t value,atomic_val_t mask)296 static inline atomic_val_t esp_socket_flags_update(struct esp_socket *sock,
297 						   atomic_val_t value,
298 						   atomic_val_t mask)
299 {
300 	atomic_val_t flags;
301 
302 	do {
303 		flags = atomic_get(&sock->flags);
304 	} while (!atomic_cas(&sock->flags, flags, (flags & ~mask) | value));
305 
306 	return flags;
307 }
308 
309 static inline
esp_socket_flags_clear_and_set(struct esp_socket * sock,atomic_val_t clear_flags,atomic_val_t set_flags)310 atomic_val_t esp_socket_flags_clear_and_set(struct esp_socket *sock,
311 					    atomic_val_t clear_flags,
312 					    atomic_val_t set_flags)
313 {
314 	return esp_socket_flags_update(sock, set_flags,
315 				       clear_flags | set_flags);
316 }
317 
esp_socket_flags_set(struct esp_socket * sock,atomic_val_t flags)318 static inline atomic_val_t esp_socket_flags_set(struct esp_socket *sock,
319 						atomic_val_t flags)
320 {
321 	return atomic_or(&sock->flags, flags);
322 }
323 
esp_socket_flags_test_and_clear(struct esp_socket * sock,atomic_val_t flags)324 static inline bool esp_socket_flags_test_and_clear(struct esp_socket *sock,
325 						   atomic_val_t flags)
326 {
327 	return (atomic_and(&sock->flags, ~flags) & flags);
328 }
329 
esp_socket_flags_test_and_set(struct esp_socket * sock,atomic_val_t flags)330 static inline bool esp_socket_flags_test_and_set(struct esp_socket *sock,
331 						 atomic_val_t flags)
332 {
333 	return (atomic_or(&sock->flags, flags) & flags);
334 }
335 
esp_socket_flags_clear(struct esp_socket * sock,atomic_val_t flags)336 static inline atomic_val_t esp_socket_flags_clear(struct esp_socket *sock,
337 						  atomic_val_t flags)
338 {
339 	return atomic_and(&sock->flags, ~flags);
340 }
341 
esp_socket_flags(struct esp_socket * sock)342 static inline atomic_val_t esp_socket_flags(struct esp_socket *sock)
343 {
344 	return atomic_get(&sock->flags);
345 }
346 
esp_socket_to_dev(struct esp_socket * sock)347 static inline struct esp_data *esp_socket_to_dev(struct esp_socket *sock)
348 {
349 	return CONTAINER_OF(sock - sock->idx, struct esp_data, sockets[0]);
350 }
351 
__esp_socket_work_submit(struct esp_socket * sock,struct k_work * work)352 static inline void __esp_socket_work_submit(struct esp_socket *sock,
353 					    struct k_work *work)
354 {
355 	struct esp_data *data = esp_socket_to_dev(sock);
356 
357 	k_work_submit_to_queue(&data->workq, work);
358 }
359 
esp_socket_work_submit(struct esp_socket * sock,struct k_work * work)360 static inline int esp_socket_work_submit(struct esp_socket *sock,
361 					  struct k_work *work)
362 {
363 	int ret = -EBUSY;
364 
365 	k_mutex_lock(&sock->lock, K_FOREVER);
366 	if (!(esp_socket_flags(sock) & ESP_SOCK_WORKQ_STOPPED)) {
367 		__esp_socket_work_submit(sock, work);
368 		ret = 0;
369 	}
370 	k_mutex_unlock(&sock->lock);
371 
372 	return ret;
373 }
374 
esp_socket_queue_tx(struct esp_socket * sock,struct net_pkt * pkt)375 static inline int esp_socket_queue_tx(struct esp_socket *sock,
376 				      struct net_pkt *pkt)
377 {
378 	int ret = -EBUSY;
379 
380 	k_mutex_lock(&sock->lock, K_FOREVER);
381 	if (!(esp_socket_flags(sock) & ESP_SOCK_WORKQ_STOPPED)) {
382 		k_fifo_put(&sock->tx_fifo, pkt);
383 		__esp_socket_work_submit(sock, &sock->send_work);
384 		ret = 0;
385 	}
386 	k_mutex_unlock(&sock->lock);
387 
388 	return ret;
389 }
390 
esp_socket_connected(struct esp_socket * sock)391 static inline bool esp_socket_connected(struct esp_socket *sock)
392 {
393 	return (esp_socket_flags(sock) & ESP_SOCK_CONNECTED) != 0;
394 }
395 
esp_flags_set(struct esp_data * dev,uint8_t flags)396 static inline void esp_flags_set(struct esp_data *dev, uint8_t flags)
397 {
398 	dev->flags |= flags;
399 }
400 
esp_flags_clear(struct esp_data * dev,uint8_t flags)401 static inline void esp_flags_clear(struct esp_data *dev, uint8_t flags)
402 {
403 	dev->flags &= (~flags);
404 }
405 
esp_flags_are_set(struct esp_data * dev,uint8_t flags)406 static inline bool esp_flags_are_set(struct esp_data *dev, uint8_t flags)
407 {
408 	return (dev->flags & flags) != 0;
409 }
410 
esp_socket_type(struct esp_socket * sock)411 static inline enum net_sock_type esp_socket_type(struct esp_socket *sock)
412 {
413 	return net_context_get_type(sock->context);
414 }
415 
esp_socket_ip_proto(struct esp_socket * sock)416 static inline enum net_ip_protocol esp_socket_ip_proto(struct esp_socket *sock)
417 {
418 	return net_context_get_proto(sock->context);
419 }
420 
esp_cmd_send(struct esp_data * data,const struct modem_cmd * handlers,size_t handlers_len,const char * buf,k_timeout_t timeout)421 static inline int esp_cmd_send(struct esp_data *data,
422 			       const struct modem_cmd *handlers,
423 			       size_t handlers_len, const char *buf,
424 			       k_timeout_t timeout)
425 {
426 	return modem_cmd_send(&data->mctx.iface, &data->mctx.cmd_handler,
427 			      handlers, handlers_len, buf, &data->sem_response,
428 			      timeout);
429 }
430 
431 void esp_connect_work(struct k_work *work);
432 void esp_recvdata_work(struct k_work *work);
433 void esp_close_work(struct k_work *work);
434 void esp_send_work(struct k_work *work);
435 
436 #ifdef __cplusplus
437 }
438 #endif
439 
440 #endif /* ZEPHYR_INCLUDE_DRIVERS_WIFI_ESP_AT_ESP_H_ */
441