wifi: esp32: add support to wifi api mgmt

Moved all MBEDTLS dependencies from prj.conf
to Kconfig as WiFi depends on it.

Update esp32 wifi driver to enable `samples/net/wifi`
to work. Commands as such as `wifi connect` and `wifi scan` are now
available.

Signed-off-by: Sylvio Alves <sylvio.alves@espressif.com>
This commit is contained in:
Sylvio Alves 2022-05-14 16:48:47 -03:00 committed by Fabio Baltieri
parent 59113dfde5
commit 7d9edc8bf0
8 changed files with 335 additions and 51 deletions

View file

@ -6,7 +6,12 @@ menuconfig WIFI_ESP32
depends on DT_HAS_ESPRESSIF_ESP32_WIFI_ENABLED
depends on !SMP
select THREAD_CUSTOM_DATA
select NET_L2_WIFI_MGMT
select WIFI_USE_NATIVE_NETWORKING
select MBEDTLS
select MBEDTLS_ENTROPY_ENABLED
select MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
select MBEDTLS_ECP_ALL_ENABLED
help
Enable ESP32 SoC WiFi support. Only supported in single
core mode because the network stack is not aware of SMP
@ -31,7 +36,6 @@ config ESP32_WIFI_STA_AUTO
config ESP32_WIFI_STA_RECONNECT
bool "WiFi connection retry"
default y
help
Set auto WiFI reconnection when disconnected.

View file

@ -26,17 +26,27 @@ LOG_MODULE_REGISTER(esp32_wifi, CONFIG_WIFI_LOG_LEVEL);
/* use global iface pointer to support any ethernet driver */
/* necessary for wifi callback functions */
static struct net_if *esp32_wifi_iface;
static struct esp32_wifi_runtime esp32_data;
enum esp32_state_flag {
ESP32_STA_STOPPED,
ESP32_STA_STARTED,
ESP32_STA_CONNECTING,
ESP32_STA_CONNECTED,
ESP32_AP_CONNECTED,
ESP32_AP_DISCONNECTED,
ESP32_AP_STOPPED,
};
struct esp32_wifi_runtime {
struct net_if *iface;
uint8_t mac_addr[6];
bool tx_err;
uint32_t tx_word;
int tx_pos;
uint8_t frame_buf[NET_ETH_MAX_FRAME_SIZE];
#if defined(CONFIG_NET_STATISTICS_ETHERNET)
struct net_stats_eth stats;
#endif
scan_result_cb_t scan_cb;
uint8_t state;
};
static void esp_wifi_event_task(void);
@ -59,15 +69,15 @@ esp_err_t esp_event_send_internal(esp_event_base_t event_base,
if (event_data_size > sizeof(evt.event_info)) {
LOG_ERR("MSG %d wont find %d > %d",
event_id, event_data_size, sizeof(evt.event_info));
return ESP_FAIL;
return -EIO;
}
memcpy(&evt.event_info, event_data, event_data_size);
k_msgq_put(&esp_wifi_msgq, &evt, K_FOREVER);
return ESP_OK;
return 0;
}
static int eth_esp32_send(const struct device *dev, struct net_pkt *pkt)
static int esp32_wifi_send(const struct device *dev, struct net_pkt *pkt)
{
struct esp32_wifi_runtime *data = dev->data;
const int pkt_len = net_pkt_get_len(pkt);
@ -91,14 +101,13 @@ static esp_err_t eth_esp32_rx(void *buffer, uint16_t len, void *eb)
if (esp32_wifi_iface == NULL) {
LOG_ERR("network interface unavailable");
return ESP_FAIL;
return -EIO;
}
pkt = net_pkt_rx_alloc_with_buffer(esp32_wifi_iface, len,
AF_UNSPEC, 0, K_NO_WAIT);
pkt = net_pkt_rx_alloc_with_buffer(esp32_wifi_iface, len, AF_UNSPEC, 0, K_MSEC(100));
if (!pkt) {
LOG_ERR("Failed to get net buffer");
return ESP_FAIL;
return -EIO;
}
if (net_pkt_write(pkt, buffer, len) < 0) {
@ -112,39 +121,108 @@ static esp_err_t eth_esp32_rx(void *buffer, uint16_t len, void *eb)
}
esp_wifi_internal_free_rx_buffer(eb);
return ESP_OK;
return 0;
pkt_unref:
net_pkt_unref(pkt);
return ESP_FAIL;
return -EIO;
}
static void scan_done_handler(void)
{
uint16_t aps = 0;
wifi_ap_record_t *ap_list_buffer;
struct wifi_scan_result res = { 0 };
esp_wifi_scan_get_ap_num(&aps);
if (!aps) {
LOG_INF("No Wi-Fi AP found");
goto out;
}
ap_list_buffer = k_malloc(aps * sizeof(wifi_ap_record_t));
if (ap_list_buffer == NULL) {
LOG_INF("Failed to malloc buffer to print scan results");
goto out;
}
if (esp_wifi_scan_get_ap_records(&aps, (wifi_ap_record_t *)ap_list_buffer) == ESP_OK) {
for (int k = 0; k < aps; k++) {
memset(&res, 0, sizeof(struct wifi_scan_result));
int ssid_len = strnlen(ap_list_buffer[k].ssid, WIFI_SSID_MAX_LEN);
res.ssid_length = ssid_len;
strncpy(res.ssid, ap_list_buffer[k].ssid, ssid_len);
res.rssi = ap_list_buffer[k].rssi;
res.channel = ap_list_buffer[k].primary;
res.security = WIFI_SECURITY_TYPE_NONE;
if (ap_list_buffer[k].authmode > WIFI_AUTH_OPEN) {
res.security = WIFI_SECURITY_TYPE_PSK;
}
if (esp32_data.scan_cb) {
esp32_data.scan_cb(esp32_data.iface, 0, &res);
/* ensure notifications get delivered */
k_yield();
}
}
}
k_free(ap_list_buffer);
out:
/* report end of scan event */
esp32_data.scan_cb(esp32_data.iface, 0, NULL);
esp32_data.scan_cb = NULL;
}
static void esp_wifi_event_task(void)
{
system_event_t evt;
uint8_t s_con_cnt = 0;
while (1) {
k_msgq_get(&esp_wifi_msgq, &evt, K_FOREVER);
switch (evt.event_id) {
case ESP32_WIFI_EVENT_STA_START:
LOG_INF("WIFI_EVENT_STA_START");
esp32_data.state = ESP32_STA_STARTED;
net_if_up(esp32_wifi_iface);
break;
case ESP32_WIFI_EVENT_STA_STOP:
LOG_INF("WIFI_EVENT_STA_STOP");
esp32_data.state = ESP32_STA_STOPPED;
net_if_down(esp32_wifi_iface);
break;
case ESP32_WIFI_EVENT_STA_CONNECTED:
LOG_INF("WIFI_EVENT_STA_CONNECTED");
net_eth_carrier_on(esp32_wifi_iface);
esp32_data.state = ESP32_STA_CONNECTED;
wifi_mgmt_raise_connect_result_event(esp32_wifi_iface, 0);
break;
case ESP32_WIFI_EVENT_STA_DISCONNECTED:
LOG_INF("WIFI_EVENT_STA_DISCONNECTED");
net_eth_carrier_off(esp32_wifi_iface);
if (IS_ENABLED(CONFIG_ESP32_WIFI_STA_RECONNECT)) {
esp_wifi_connect();
if (esp32_data.state == ESP32_STA_CONNECTED) {
wifi_mgmt_raise_disconnect_result_event(esp32_wifi_iface, 0);
} else {
wifi_mgmt_raise_disconnect_result_event(esp32_wifi_iface, -1);
}
esp32_data.state = ESP32_STA_STARTED;
break;
case ESP32_WIFI_EVENT_SCAN_DONE:
scan_done_handler();
break;
case ESP32_WIFI_EVENT_AP_STOP:
esp32_data.state = ESP32_AP_STOPPED;
break;
case ESP32_WIFI_EVENT_AP_STACONNECTED:
esp32_data.state = ESP32_AP_CONNECTED;
if (!s_con_cnt) {
esp_wifi_internal_reg_rxcb(WIFI_IF_AP, eth_esp32_rx);
}
s_con_cnt++;
break;
case ESP32_WIFI_EVENT_AP_STADISCONNECTED:
esp32_data.state = ESP32_AP_DISCONNECTED;
s_con_cnt--;
if (!s_con_cnt) {
esp_wifi_internal_reg_rxcb(WIFI_IF_AP, NULL);
}
break;
default:
@ -153,29 +231,170 @@ static void esp_wifi_event_task(void)
}
}
static void eth_esp32_init(struct net_if *iface)
static int esp32_wifi_disconnect(const struct device *dev)
{
struct esp32_wifi_runtime *data = dev->data;
int ret = esp_wifi_disconnect();
if (ret != ESP_OK) {
LOG_INF("Failed to disconnect from hotspot");
return -EAGAIN;
}
return 0;
}
static int esp32_wifi_connect(const struct device *dev,
struct wifi_connect_req_params *params)
{
struct esp32_wifi_runtime *data = dev->data;
int ret;
if (data->state == ESP32_STA_CONNECTING || data->state == ESP32_STA_CONNECTED) {
wifi_mgmt_raise_connect_result_event(esp32_wifi_iface, -1);
return -EALREADY;
}
if (data->state != ESP32_STA_STARTED) {
LOG_ERR("Wi-Fi not in station mode");
wifi_mgmt_raise_connect_result_event(esp32_wifi_iface, -1);
return -EIO;
}
data->state = ESP32_STA_CONNECTING;
wifi_config_t wifi_config;
memset(&wifi_config, 0, sizeof(wifi_config_t));
memcpy(wifi_config.sta.ssid, params->ssid, params->ssid_length);
wifi_config.sta.ssid[params->ssid_length] = '\0';
if (params->security == WIFI_SECURITY_TYPE_PSK) {
memcpy(wifi_config.sta.password, params->psk, params->psk_length);
wifi_config.sta.password[params->psk_length] = '\0';
wifi_config.sta.threshold.authmode = WIFI_AUTH_WPA2_PSK;
} else if (params->security == WIFI_SECURITY_TYPE_NONE) {
wifi_config.sta.threshold.authmode = WIFI_AUTH_OPEN;
} else {
LOG_ERR("Authentication method not supported");
return -EIO;
}
wifi_config.sta.pmf_cfg.capable = true;
wifi_config.sta.pmf_cfg.required = false;
ret = esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config);
ret |= esp_wifi_set_mode(WIFI_MODE_STA);
ret |= esp_wifi_connect();
if (ret != ESP_OK) {
LOG_ERR("Failed to connect to Wi-Fi access point");
return -EAGAIN;
}
return 0;
}
static int esp32_wifi_scan(const struct device *dev, scan_result_cb_t cb)
{
struct esp32_wifi_runtime *data = dev->data;
int ret = 0;
if (data->scan_cb != NULL) {
LOG_INF("Scan callback in progress");
return -EINPROGRESS;
}
data->scan_cb = cb;
wifi_scan_config_t scan_config = { 0 };
ret = esp_wifi_set_mode(WIFI_MODE_STA);
ret |= esp_wifi_scan_start(&scan_config, false);
if (ret != ESP_OK) {
LOG_ERR("Failed to start Wi-Fi scanning");
return -EAGAIN;
}
return 0;
};
static int esp32_wifi_ap_enable(const struct device *dev,
struct wifi_connect_req_params *params)
{
struct esp32_wifi_data *data = dev->data;
esp_err_t ret = 0;
/* Build Wi-Fi configuration for AP mode */
wifi_config_t wifi_config = {
.ap = {
.max_connection = 5,
},
};
strncpy((char *) wifi_config.ap.ssid, params->ssid, params->ssid_length);
if (params->psk_length == 0) {
memset(wifi_config.ap.password, 0, sizeof(wifi_config.ap.password));
wifi_config.ap.authmode = WIFI_AUTH_OPEN;
} else {
strncpy((char *) wifi_config.ap.password, params->psk, params->psk_length);
wifi_config.ap.authmode = WIFI_AUTH_WPA2_PSK;
}
/* Start Wi-Fi in AP mode with configuration built above */
ret = esp_wifi_set_mode(WIFI_MODE_AP);
ret |= esp_wifi_set_config(WIFI_IF_AP, &wifi_config);
ret = esp_wifi_start();
if (ret != ESP_OK) {
LOG_ERR("Failed to enable Wi-Fi AP mode");
return -EAGAIN;
}
return 0;
};
static int esp32_wifi_ap_disable(const struct device *dev)
{
struct esp32_wifi_data *data = dev->data;
esp_err_t err = esp_wifi_set_mode(WIFI_MODE_NULL);
ret |= esp_wifi_start();
if (ret != ESP_OK) {
LOG_ERR("Failed to disable Wi-Fi AP mode");
return -EAGAIN;
}
return 0;
};
static void esp32_wifi_init(struct net_if *iface)
{
const struct device *dev = net_if_get_device(iface);
struct esp32_wifi_runtime *dev_data = dev->data;
dev_data->iface = iface;
esp32_wifi_iface = iface;
dev_data->state = ESP32_STA_STOPPED;
/* Start interface when we are actually connected with WiFi network */
net_if_flag_set(iface, NET_IF_NO_AUTO_START);
/* Start interface when we are actually connected with Wi-Fi network */
esp_read_mac(dev_data->mac_addr, ESP_MAC_WIFI_STA);
/* Assign link local address. */
net_if_set_link_addr(iface,
dev_data->mac_addr, 6, NET_LINK_ETHERNET);
net_if_set_link_addr(iface, dev_data->mac_addr, 6, NET_LINK_ETHERNET);
ethernet_init(iface);
net_eth_carrier_on(esp32_wifi_iface);
esp_wifi_internal_reg_rxcb(ESP_IF_WIFI_STA, eth_esp32_rx);
}
#if defined(CONFIG_NET_STATISTICS_ETHERNET)
static struct net_stats_eth *eth_esp32_stats(const struct device *dev)
static struct net_stats_eth *esp32_wifi_stats(const struct device *dev)
{
struct esp32_wifi_runtime *data = dev->data;
@ -183,7 +402,7 @@ static struct net_stats_eth *eth_esp32_stats(const struct device *dev)
}
#endif
static int eth_esp32_dev_init(const struct device *dev)
static int esp32_wifi_dev_init(const struct device *dev)
{
esp_timer_init();
@ -197,40 +416,33 @@ static int eth_esp32_dev_init(const struct device *dev)
wifi_init_config_t config = WIFI_INIT_CONFIG_DEFAULT();
esp_err_t ret = esp_wifi_init(&config);
ret |= esp_wifi_set_mode(WIFI_MODE_STA);
ret |= esp_wifi_start();
if (IS_ENABLED(CONFIG_ESP32_WIFI_STA_AUTO)) {
wifi_config_t wifi_config = {
.sta = {
.ssid = CONFIG_ESP32_WIFI_SSID,
.password = CONFIG_ESP32_WIFI_PASSWORD,
},
};
ret = esp_wifi_set_mode(WIFI_MODE_STA);
ret |= esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config);
ret |= esp_wifi_connect();
}
if (ret != ESP_OK) {
LOG_ERR("Connect failed");
LOG_ERR("Failed to start Wi-Fi driver");
return -EIO;
}
return ret;
return 0;
}
static struct esp32_wifi_runtime eth_data;
static const struct net_wifi_mgmt_offload esp32_api = {
.wifi_iface.iface_api.init = eth_esp32_init,
.wifi_iface.send = eth_esp32_send,
.wifi_iface.iface_api.init = esp32_wifi_init,
.wifi_iface.send = esp32_wifi_send,
#if defined(CONFIG_NET_STATISTICS_ETHERNET)
.wifi_iface.get_stats = eth_esp32_stats,
.wifi_iface.get_stats = esp32_wifi_stats,
#endif
.scan = esp32_wifi_scan,
.connect = esp32_wifi_connect,
.disconnect = esp32_wifi_disconnect,
.ap_enable = esp32_wifi_ap_enable,
.ap_disable = esp32_wifi_ap_disable,
};
NET_DEVICE_DT_INST_DEFINE(0,
eth_esp32_dev_init, NULL,
&eth_data, NULL, CONFIG_ETH_INIT_PRIORITY,
esp32_wifi_dev_init, NULL,
&esp32_data, NULL, CONFIG_ETH_INIT_PRIORITY,
&esp32_api, ETHERNET_L2,
NET_L2_GET_CTX_TYPE(ETHERNET_L2), NET_ETH_MTU);

View file

@ -0,0 +1,11 @@
CONFIG_WIFI=y
CONFIG_HEAP_MEM_POOL_SIZE=98304
CONFIG_NETWORKING=y
CONFIG_NET_L2_ETHERNET=y
CONFIG_NET_IPV6=n
CONFIG_NET_IPV4=y
CONFIG_NET_DHCPV4=y
CONFIG_NET_LOG=y

View file

@ -0,0 +1,9 @@
/*
* Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd.
*
* SPDX-License-Identifier: Apache-2.0
*/
&wifi {
status = "okay";
};

View file

@ -0,0 +1,11 @@
CONFIG_WIFI=y
CONFIG_HEAP_MEM_POOL_SIZE=98304
CONFIG_NETWORKING=y
CONFIG_NET_L2_ETHERNET=y
CONFIG_NET_IPV6=n
CONFIG_NET_IPV4=y
CONFIG_NET_DHCPV4=y
CONFIG_NET_LOG=y

View file

@ -0,0 +1,9 @@
/*
* Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd.
*
* SPDX-License-Identifier: Apache-2.0
*/
&wifi {
status = "okay";
};

View file

@ -0,0 +1,19 @@
CONFIG_WIFI=y
CONFIG_HEAP_MEM_POOL_SIZE=37760
# when enabling NET_SHELL, the following
# helps to optimize memory footprint
CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=8
CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=8
CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM=8
CONFIG_ESP32_WIFI_IRAM_OPT=n
CONFIG_ESP32_WIFI_RX_IRAM_OPT=n
CONFIG_NETWORKING=y
CONFIG_NET_L2_ETHERNET=y
CONFIG_NET_IPV6=n
CONFIG_NET_IPV4=y
CONFIG_NET_DHCPV4=y
CONFIG_NET_LOG=y

View file

@ -0,0 +1,9 @@
/*
* Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd.
*
* SPDX-License-Identifier: Apache-2.0
*/
&wifi {
status = "okay";
};