zephyr/drivers/wifi/esp/esp.h
Tobias Svehagen 7b5f6bc660 drivers: wifi: Add ESP8266 and ESP32 wifi modem driver
This adds support for the Espressif ESP8266 and ESP32 devices to be used
as peripherals on a UART.

There are two main AT command versions that can be selected, 1.7 and
2.0. Since they behave a bit different it is important to select the
one that matches the used in the firmware on your device.

When downloading large amounts of data it is highly recommended to
enable CONFIG_ESP_PASSIVE_TCP and flow control on the UART so that
data is not lost due to UART speed or receive buffer size.

Currently unsupported:
- Changing UDP endpoint with a sendto()
- Bind to a specific local port
- Server socket operations, ie listen() and accept()

Official AT firmware for ESP8266 and ESP32 can be found at:
https://github.com/espressif/esp-at

Signed-off-by: Tobias Svehagen <tobias.svehagen@gmail.com>
2020-03-21 19:08:02 +02:00

217 lines
4.7 KiB
C

/*
* Copyright (c) 2019 Tobias Svehagen
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_INCLUDE_DRIVERS_WIFI_ESP_H_
#define ZEPHYR_INCLUDE_DRIVERS_WIFI_ESP_H_
#include <kernel.h>
#include <net/net_context.h>
#include <net/net_if.h>
#include <net/net_ip.h>
#include <net/net_pkt.h>
#include <net/wifi_mgmt.h>
#include "modem_context.h"
#include "modem_cmd_handler.h"
#include "modem_iface_uart.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Define the commands that differ between the AT versions */
#if defined(CONFIG_WIFI_ESP_AT_VERSION_1_7)
#define _CWMODE "CWMODE_CUR"
#define _CWSAP "CWSAP_CUR"
#define _CWJAP "CWJAP_CUR"
#define _CIPSTA "CIPSTA_CUR"
#define _CIPSTAMAC "CIPSTAMAC_CUR"
#else
#define _CWMODE "CWMODE"
#define _CWSAP "CWSAP"
#define _CWJAP "CWJAP"
#define _CIPSTA "CIPSTA"
#define _CIPSTAMAC "CIPSTAMAC"
#endif
#if DT_INST_0_ESPRESSIF_ESP_WIFI_UART_FLOW_CONTROL == 1
#define _FLOW_CONTROL "3"
#else
#define _FLOW_CONTROL "0"
#endif
#define _UART_CUR \
STRINGIFY(DT_INST_0_ESPRESSIF_ESP_WIFI_UART_SPEED)",8,1,0,"_FLOW_CONTROL
#define CONN_CMD_MAX_LEN (sizeof("AT+"_CWJAP"=\"\",\"\"") + \
WIFI_SSID_MAX_LEN + WIFI_PSK_MAX_LEN)
#define ESP_MAX_SOCKETS 5
/* Maximum amount that can be sent with CIPSEND and read with CIPRECVDATA */
#define ESP_MTU 2048
#define CIPRECVDATA_MAX_LEN ESP_MTU
#define INVALID_LINK_ID 255
#define MDM_RING_BUF_SIZE 1024
#define MDM_RECV_MAX_BUF 30
#define MDM_RECV_BUF_SIZE 128
#define CMD_BUF_ALLOC_TIMEOUT K_SECONDS(1)
#define ESP_CMD_TIMEOUT K_SECONDS(10)
#define ESP_SCAN_TIMEOUT K_SECONDS(10)
#define ESP_CONNECT_TIMEOUT K_SECONDS(20)
#define ESP_INIT_TIMEOUT K_SECONDS(10)
extern struct esp_data esp_driver_data;
enum esp_socket_flags {
ESP_SOCK_IN_USE = BIT(1),
ESP_SOCK_CONNECTING = BIT(2),
ESP_SOCK_CONNECTED = BIT(3)
};
struct esp_socket {
/* internal */
u8_t idx;
u8_t link_id;
u8_t flags;
/* socket info */
sa_family_t family;
enum net_sock_type type;
enum net_ip_protocol ip_proto;
struct sockaddr src;
struct sockaddr dst;
/* for +CIPRECVDATA */
size_t bytes_avail;
/* packets */
struct k_fifo fifo_rx_pkt;
struct net_pkt *tx_pkt;
/* sem */
struct k_sem sem_data_ready;
/* work */
struct k_work connect_work;
struct k_work send_work;
struct k_work recv_work;
struct k_work recvdata_work;
/* net context */
struct net_context *context;
net_context_connect_cb_t connect_cb;
net_context_send_cb_t send_cb;
net_context_recv_cb_t recv_cb;
/* callback data */
void *conn_user_data;
void *send_user_data;
void *recv_user_data;
};
enum esp_data_flag {
EDF_STA_CONNECTING = BIT(1),
EDF_STA_CONNECTED = BIT(2)
};
/* driver data */
struct esp_data {
struct net_if *net_iface;
u8_t flags;
char conn_cmd[CONN_CMD_MAX_LEN];
/* addresses */
struct in_addr ip;
struct in_addr gw;
struct in_addr nm;
u8_t mac_addr[6];
/* modem context */
struct modem_context mctx;
/* modem interface */
struct modem_iface_uart_data iface_data;
u8_t iface_isr_buf[MDM_RECV_BUF_SIZE];
u8_t iface_rb_buf[MDM_RING_BUF_SIZE];
/* modem cmds */
struct modem_cmd_handler_data cmd_handler_data;
u8_t cmd_read_buf[MDM_RECV_BUF_SIZE];
u8_t cmd_match_buf[MDM_RECV_BUF_SIZE];
/* socket data */
struct esp_socket sockets[ESP_MAX_SOCKETS];
struct esp_socket *rx_sock;
/* work */
struct k_work_q workq;
struct k_work init_work;
struct k_delayed_work ip_addr_work;
struct k_work scan_work;
struct k_work connect_work;
scan_result_cb_t scan_cb;
/* response semaphore */
struct k_sem sem_tx_ready;
struct k_sem sem_response;
struct k_sem sem_if_up;
};
int esp_offload_init(struct net_if *iface);
struct net_pkt *esp_prepare_pkt(struct esp_data *dev, struct net_buf *src,
size_t offset, size_t len);
struct esp_socket *esp_socket_get();
int esp_socket_put(struct esp_socket *sock);
struct esp_socket *esp_socket_from_link_id(struct esp_data *data,
u8_t link_id);
void esp_socket_init(struct esp_data *data);
static inline struct esp_data *esp_socket_to_dev(struct esp_socket *sock)
{
return CONTAINER_OF(sock - sock->idx, struct esp_data, sockets);
}
static inline bool esp_socket_in_use(struct esp_socket *sock)
{
return (sock->flags & ESP_SOCK_IN_USE) != 0;
}
static inline bool esp_socket_connected(struct esp_socket *sock)
{
return (sock->flags & ESP_SOCK_CONNECTED) != 0;
}
static inline void esp_flag_set(struct esp_data *dev,
enum esp_data_flag flag)
{
dev->flags |= flag;
}
static inline void esp_flag_clear(struct esp_data *dev,
enum esp_data_flag flag)
{
dev->flags &= (~flag);
}
static inline bool esp_flag_is_set(struct esp_data *dev,
enum esp_data_flag flag)
{
return (dev->flags & flag) != 0;
}
#ifdef __cplusplus
}
#endif
#endif /* ZEPHYR_INCLUDE_DRIVERS_WIFI_ESP_H_ */