Merge pull request #10762 from gschorcht/esp32_esp_wifi_fix

cpu/esp32: esp_wifi netdev driver
This commit is contained in:
Sebastian Meiling 2019-01-17 17:38:59 +01:00 committed by GitHub
commit 495607d501
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 229 additions and 1188 deletions

View File

@ -28,6 +28,7 @@ endif
ifneq (,$(filter esp_wifi_any,$(USEMODULE)))
# add additional modules used for any WiFi interface
USEMODULE += esp_idf_heap
USEMODULE += esp_idf_wpa_supplicant_crypto
USEMODULE += esp_idf_wpa_supplicant_port
USEMODULE += esp_idf_nvs_flash

File diff suppressed because it is too large Load Diff

View File

@ -46,8 +46,9 @@
2. [SPIFFS Device](#esp32_spiffs_device)
8. [Network Interfaces](#esp32_network_interfaces)
1. [Ethernet MAC Network Interface](#esp32_ethernet_network_interface)
2. [ESP-NOW Network Interface](#esp32_esp_now_network_interface)
3. [Other Network Devices](#esp32_other_network_devices)
2. [WiFi Network Interface](#esp32_wifi_network_interface)
3. [ESP-NOW Network Interface](#esp32_esp_now_network_interface)
4. [Other Network Devices](#esp32_other_network_devices)
10. [Application-Specific Configurations](#esp32_application_specific_configurations)
1. [Make Variable ```CONFIGS```](#esp32_config_make_variable)
2. [Application-Specific Board Configuration](#esp32_application_specific_board_configuration)
@ -108,8 +109,8 @@ The following table gives a short reference in alphabetical order of modules th
Module | Default | Short description
----------|----------|-------------------
[esp_can](#esp32_can_interfaces) | not used | enable the ESP32 CAN device
[esp_eth](#esp32_ethernet_network_interface) | not used | enable the ESP32 EMAC network device
[esp_can](#esp32_can_interfaces) | not used | enable the CAN device
[esp_eth](#esp32_ethernet_network_interface) | not used | enable the Ethernet MAC (EMAC) network device
[esp_gdb](#esp32_debugging) | not used | enable the compilation with debug information for debugging
[esp_hw_counter](#esp32_timers) | not used | use hardware counters for RIOT timers
[esp_i2c_hw](#esp32_i2c_interfaces) | not used | use the i2C hardware implementation
@ -117,6 +118,7 @@ Module | Default | Short description
[esp_now](#esp32_esp_now_network_interface) | not used | enable the ESP-NOW network device
[esp_spi_ram](#esp32_spi_ram) | not used | enable SPI RAM
[esp_spiffs](#esp32_spiffs_device) | not used | enable SPIFFS for on-board flash memory
[esp_wifi](#esp32_wifi_network_interface) | not used | enable the Wifi network device
</center>
@ -190,7 +192,6 @@ The RIOT-OS for ESP32 SoCs supports the following features at the moment:
The implementation of RIOT-OS for ESP32 SOCs has the following limitations at the moment:
- Only <b>one core</b> (the PRO CPU) is used because RIOT does not support running multiple threads simultaneously.
- <b>AP-based WiFi</b> is experimental and not stable.
- RIOT modules <b>crypto</b> and <b>hashes</b> cannot be used together with modules <b>esp_now</b> and <b>esp_wifi</b>
- <b>Bluetooth</b> cannot be used at the moment.
- <b>Flash encryption</b> is not yet supported.
@ -390,14 +391,15 @@ Optional features of ESP32 can be enabled by ```USEMODULE``` definitions in the
Module | Description
-------|------------
esp_now | Use the built-in WiFi module with the ESP-NOW protocol as ```netdev``` network device, see section [ESP-NOW Network Interface](#esp32_esp_now_network_interface).
esp_eth | Use the Ethernet MAC (EMAC) interface as ```netdev``` network device, see section [Ethernet Network Interface](#esp32_ethernet_network_interface).
esp_can | Enable the CAN device, see section [CAN Interfaces](#esp32_can_interfaces).
esp_eth | Enable the Ethernet MAC (EMAC) interface as `netdev` network device, see section [Ethernet Network Interface](#esp32_ethernet_network_interface).
esp_gdb | Enable the compilation with debug information for debugging with [QEMU and GDB](#esp32_qemu_mode_and_gdb) (```QEMU=1```) or via [JTAG interface with OpenOCD](#esp32_jtag_debugging).
esp_i2c_hw | Use the hardware I2C implementation, see section [I2C Interfaces](#esp32_i2c_interfaces).
esp_idf_heap | Use the ESP-IDF heap implementation, see section [ESP-IDF Heap Implementation](#esp32_esp_idf_heap_implementation).
esp_now | Enable the built-in WiFi module with the ESP-NOW protocol as `netdev` network device, see section [ESP-NOW Network Interface](#esp32_esp_now_network_interface).
esp_spiffs | Enable the optional SPIFFS drive in on-board flash memory, see section [SPIFFS Device](#esp32_spiffs_device).
esp_spi_ram | Enable the optional SPI RAM, see section [SPI RAM Modules](#esp32_spi_ram).
esp_can | Enable the ESP32 CAN device, see section [CAN Interfaces](#esp32_can_interfaces).
esp_wifi | Enable the built-in WiFi module as `netdev` network device, see section [WiFi Network Interface](#esp32_wifi_network_interface).
</center>
@ -884,7 +886,7 @@ Please refer file ```$RIOTBASE/tests/unittests/test-spiffs/tests-spiffs.c``` for
ESP32 provides different built-in possibilities to realize network devices:
- <b>EMAC</b>, an Ethernet MAC implementation (requires an external PHY module)
- <b>ESP WiFi</b>, usual AP-based wireless LAN (not yet supported)
- <b>ESP WiFi</b>, usual AP-based wireless LAN
- <b>ESP-NOW</b>, a WiFi based AP-less and connectionless peer to peer communication protocol
- <b>ESP-MESH</b>, a WiFi based mesh technology (not yet supported)
@ -906,6 +908,50 @@ Otherwise, the application has to add the ```esp_eth``` module in its makefile w
@note
The board has to have one of the supported PHY modules to be able to use the Ethernet MAC module.
\anchor esp32_wifi_network_interface
## <a name="esp32_wifi_network_interface"> WiFi Network Interface </a> &nbsp;[[TOC](#esp32_toc)]
The RIOT port for ESP32 implements in module `esp_wifi` a `netdev` driver for
the built-in WiFi interface.
@note Due to symbol conflicts with the `crypto` and `hash` modules of RIOT
in module `esp_idf_wpa_supplicant_crypto`, which is required by module
`esp_wifi`, `esp_wifi` cannot be used for applications that use these modules.
Therefore, module `esp_wifi` is not automatically enabled when module
`netdev_default` is used. Instead, if necessary, the application has to add
the module `esp_wifi` in the Makefile.
```
USEMODULE += esp_wifi
```
Furthermore, the following configuration parameters have to be defined:
<center>
Parameter | Default | Description
:------------------|:--------------------------|:------------
ESP_WIFI_SSID | "RIOT_AP" | SSID of the AP to be used.
ESP_WIFI_PASS | "ThisistheRIOTporttoESP" | Passphrase used for the AP as clear text (max. 64 chars).
ESP_WIFI_STACKSIZE | #THREAD_STACKSIZE_DEFAULT |Stack size used for the WiFi netdev driver thread.
</center>
These configuration parameter definitions, as well as enabling the `esp_wifi`
module, can be done either in the makefile of the project or at make command
line, e.g.:
```
USEMODULE=esp_wifi \
CFLAGS='-DESP_WIFI_SSID=\"MySSID\" -DESP_WIFI_PASS=\"MyPassphrase\"' \
make -C examples/gnrc_networking BOARD=...
```
@note The Wifi network interface (module `esp_wifi`) and the
[ESP-NOW network interface](#esp32_esp_now_network_interface) (module `esp_now`)
can be used simultaneously, for example, to realize a border router for
a mesh network which uses ESP-NOW.
\anchor esp32_esp_now_network_interface
## <a name="esp32_esp_now_network_interface"> ESP-NOW Network Interface </a> &nbsp;[[TOC](#esp32_toc)]
@ -927,12 +973,16 @@ The following parameters are defined for ESP-NOW nodes. These parameters can be
Parameter | Default | Description
:---------|:--------|:-----------
ESP_NOW_SCAN_PERIOD | 10000000UL | Defines the period in us at which an node scans for other nodes in its range. The default period is 10 s.
ESP_NOW_SOFT_AP_PASSPHRASE | ThisistheRIOTporttoESP | Defines the passphrase (max. 64 chars) that is used for the SoftAP interface of an nodes. It has to be same for all nodes in one network.
ESP_NOW_SOFT_AP_PASS | "ThisistheRIOTporttoESP" | Defines the passphrase as clear text (max. 64 chars) that is used for the SoftAP interface of ESP-NOW nodes. It has to be same for all nodes in one network.
ESP_NOW_CHANNEL | 6 | Defines the channel that is used as the broadcast medium by all nodes together.
ESP_NOW_KEY | NULL | Defines a key that is used for encrypted communication between nodes. If it is NULL, encryption is disabled. The key has to be of type ```uint8_t[16]``` and has to be exactly 16 bytes long.
</center>
@note The ESP-NOW network interface (module `esp_now`) and the
[Wifi network interface](#esp32_wifi_network_interface) (module `esp_wifi`)
can be used simultaneously, for example, to realize a border router for
a mesh network which uses ESP-NOW.
## <a name="esp32_other_network_devices"> Other Network Devices </a> &nbsp;[[TOC](#esp32_toc)]

View File

@ -7,12 +7,46 @@
*/
/**
* @defgroup cpu_esp32_esp_wifi ESP WiFi netdev interface
* @defgroup cpu_esp32_esp_wifi ESP32 WiFi netdev interface
* @ingroup cpu_esp32
* @brief WiFi AP-based network device driver
*
* This module realizes a netdev interface using the built-in
* WiFi module and AP infrastructure.
* @brief Network device driver for the ESP32 WiFi interface
*
* @author Gunar Schorcht <gunar@schorcht.net>
This module realizes a `netdev` interface for the built-in WiFi interface
of ESP32. To enable the WiFi interface, module `esp_wifi` has to be used.
@note Due to symbol conflicts with the `crypto` and `hash` modules of RIOT
in module `esp_idf_wpa_supplicant_crypto`, which is required by module
`esp_wifi`, `esp_wifi` cannot be used for applications that use these modules.
Therefore, module `esp_wifi` is not automatically enabled when module
`netdev_default` is used. Instead, if necessary, the application has to add
the module `esp_wifi` in the Makefile.
```
USEMODULE += esp_wifi
```
Furthermore, the following configuration parameters have to be defined:
Configuration Parameter | Description
------------------------|------------
ESP_WIFI_SSID | SSID of the AP to be used.
ESP_WIFI_PASS | Passphrase used for the AP as clear text (max. 64 chars).
ESP_WIFI_STACKSIZE | Stack size used for the WiFi netdev driver thread.
These configuration parameter definitions, as well as enabling the `esp_wifi`
module, can be done either in the makefile of the project or at make command
line, e.g.:
```
USEMODULE=esp_wifi \
CFLAGS='-DESP_WIFI_SSID=\"MySSID\" -DESP_WIFI_PASS=\"MyPassphrase\"' \
make -C examples/gnrc_networking BOARD=...
```
@note The Wifi network interface (module `esp_wifi`) and the
\ref esp32_esp_now_network_interface "ESP-NOW network interface" (module `esp_now`)
can be used simultaneously, for example, to realize a border router for
a mesh network which uses ESP-NOW.
*/

View File

@ -11,7 +11,7 @@
* @{
*
* @file
* @brief Netdev interface for the ESP WiFi AP-based communication
* @brief Network device driver for the ESP32 WiFi interface
*
* @author Gunar Schorcht <gunar@schorcht.net>
*/
@ -72,18 +72,48 @@ extern esp_err_t esp_system_event_add_handler (system_event_cb_t handler,
esp_err_t _esp_wifi_rx_cb(void *buffer, uint16_t len, void *eb)
{
/*
* This callback function is executed in interrupt context but in the
* context of the wifi thread. That is, mutex_lock or msg_send can block.
*/
DEBUG("%s: buf=%p len=%d eb=%p\n", __func__, buffer, len, eb);
CHECK_PARAM_RET (buffer != NULL, -EINVAL);
CHECK_PARAM_RET (len <= ETHERNET_DATA_LEN, -EINVAL);
if ((buffer == NULL) || (len >= ETHERNET_DATA_LEN)) {
if (eb != NULL) {
esp_wifi_internal_free_rx_buffer(eb);
}
return ESP_ERR_INVALID_ARG;
}
mutex_lock(&_esp_wifi_dev.dev_lock);
critical_enter();
/* copy the buffer and free WiFi driver buffer */
memcpy(_esp_wifi_dev.rx_buf, buffer, len);
if (eb) {
esp_wifi_internal_free_rx_buffer(eb);
}
/*
* Because this function is not executed in interrupt context but in thread
* context, following msg_send could block on heavy network load, if frames
* are coming in faster than the ISR events can be handled. To avoid
* blocking during msg_send, we pretend we are in an ISR by incrementing
* the IRQ nesting counter. If IRQ nesting counter is greater 0, function
* irq_is_in returns true and the non-blocking version of msg_send is used.
*/
irq_interrupt_nesting++;
/* trigger netdev event to read the data */
_esp_wifi_dev.rx_len = len;
_esp_wifi_dev.event = SYSTEM_EVENT_WIFI_RX_DONE;
_esp_wifi_dev.netdev.event_callback(&_esp_wifi_dev.netdev, NETDEV_EVENT_ISR);
/* reset IRQ nesting counter */
irq_interrupt_nesting--;
critical_exit();
mutex_unlock(&_esp_wifi_dev.dev_lock);
return ESP_OK;
@ -94,48 +124,82 @@ esp_err_t _esp_wifi_rx_cb(void *buffer, uint16_t len, void *eb)
*/
static esp_err_t IRAM_ATTR _esp_system_event_handler(void *ctx, system_event_t *event)
{
esp_err_t result;
switch(event->event_id) {
case SYSTEM_EVENT_STA_START:
DEBUG("%s WiFi started\n", __func__);
result = esp_wifi_connect();
if (result != ESP_OK) {
LOG_TAG_ERROR("esp_wifi", "esp_wifi_connect failed with return "
"value %d\n", result);
}
break;
case SYSTEM_EVENT_SCAN_DONE:
DEBUG("%s WiFi scan done\n", __func__);
break;
case SYSTEM_EVENT_STA_CONNECTED:
DEBUG("%s WiFi connected\n", __func__);
/* register RX callback function */
esp_wifi_internal_reg_rxcb(ESP_IF_WIFI_STA, _esp_wifi_rx_cb);
_esp_wifi_dev.connected = true;
_esp_wifi_dev.event = SYSTEM_EVENT_ETH_CONNECTED;
_esp_wifi_dev.event = SYSTEM_EVENT_STA_CONNECTED;
_esp_wifi_dev.netdev.event_callback(&_esp_wifi_dev.netdev, NETDEV_EVENT_ISR);
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
DEBUG("%s WiFi disconnected\n", __func__);
DEBUG("%s WiFi disconnected from ssid %s, reason %d\n", __func__,
event->event_info.disconnected.ssid,
event->event_info.disconnected.reason);
/* unregister RX callback function */
esp_wifi_internal_reg_rxcb(ESP_IF_WIFI_STA, NULL);
_esp_wifi_dev.connected = false;
_esp_wifi_dev.event = SYSTEM_EVENT_ETH_DISCONNECTED;
_esp_wifi_dev.event = SYSTEM_EVENT_STA_DISCONNECTED;
_esp_wifi_dev.netdev.event_callback(&_esp_wifi_dev.netdev, NETDEV_EVENT_ISR);
/* call disconnect to reset internal state */
result = esp_wifi_disconnect();
if (result != ESP_OK) {
LOG_TAG_ERROR("esp_wifi", "esp_wifi_disconnect failed with "
"return value %d\n", result);
return result;
}
/* try to reconnect */
result = esp_wifi_connect();
if (result != ESP_OK) {
LOG_TAG_ERROR("esp_wifi", "esp_wifi_connect failed with "
"return value %d\n", result);
}
break;
default:
DEBUG("%s event %d\n", __func__, event->event_id);
break;
}
return ESP_OK;
}
/** TODO better place
* Default WiFi configuration, overwrite them with your configs
*/
#ifndef CONFIG_WIFI_STA_SSID
#define CONFIG_WIFI_STA_SSID "RIOT_AP"
#endif
#ifndef CONFIG_WIFI_STA_PASSWORD
#define CONFIG_WIFI_STA_PASSWORD "ThisistheRIOTporttoESP"
#endif
#ifndef CONFIG_WIFI_STA_CHANNEL
#define CONFIG_WIFI_STA_CHANNEL 0
#endif
#define CONFIG_WIFI_STA_SCAN_METHOD WIFI_ALL_CHANNEL_SCAN
#define CONFIG_WIFI_STA_SORT_METHOD WIFI_CONNECT_AP_BY_SIGNAL
#define CONFIG_WIFI_STA_RSSI -127
#define CONFIG_WIFI_STA_AUTHMODE WIFI_AUTH_WPA_WPA2_PSK
/* we use predefined station configuration */
static wifi_config_t wifi_config_sta = {
.sta = {
.ssid = ESP_WIFI_SSID,
.password = ESP_WIFI_PASS,
.channel = 0,
.scan_method = WIFI_ALL_CHANNEL_SCAN,
.sort_method = WIFI_CONNECT_AP_BY_SIGNAL,
.threshold.rssi = -127,
.threshold.authmode = WIFI_AUTH_WPA_WPA2_PSK
}
};
static void esp_wifi_setup (esp_wifi_netdev_t* dev)
{
@ -171,19 +235,6 @@ static void esp_wifi_setup (esp_wifi_netdev_t* dev)
/* TODO */
#endif
/* we use predefined station configuration */
wifi_config_t wifi_config_sta = {
.sta = {
.ssid = CONFIG_WIFI_STA_SSID,
.password = CONFIG_WIFI_STA_PASSWORD,
.channel = CONFIG_WIFI_STA_CHANNEL,
.scan_method = CONFIG_WIFI_STA_SCAN_METHOD,
.sort_method = CONFIG_WIFI_STA_SORT_METHOD,
.threshold.rssi = CONFIG_WIFI_STA_RSSI,
.threshold.authmode = CONFIG_WIFI_STA_AUTHMODE
}
};
result = esp_wifi_set_mode(WIFI_MODE_STA);
if (result != ESP_OK) {
LOG_TAG_ERROR("esp_wifi", "esp_wifi_set_mode failed with return value %d\n", result);
@ -214,12 +265,6 @@ static void esp_wifi_setup (esp_wifi_netdev_t* dev)
dev->connected = false;
mutex_init(&dev->dev_lock);
result = esp_wifi_connect();
if (result != ESP_OK) {
LOG_TAG_ERROR("esp_wifi", "esp_wifi_connect failed with return value %d\n", result);
return;
}
}
static int _esp_wifi_init(netdev_t *netdev)
@ -285,6 +330,7 @@ static int _esp_wifi_send(netdev_t *netdev, const iolist_t *iolist)
}
mutex_unlock(&dev->dev_lock);
return ret;
}
@ -298,7 +344,7 @@ static int _esp_wifi_recv(netdev_t *netdev, void *buf, size_t len, void *info)
mutex_lock(&dev->dev_lock);
uint8_t size = dev->rx_len;
uint16_t size = dev->rx_len;
if (!buf && !len) {
/* return the size without dropping received data */
@ -356,9 +402,12 @@ static int _esp_wifi_get(netdev_t *netdev, netopt_t opt, void *val, size_t max_l
esp_wifi_get_mac(ESP_MAC_WIFI_STA,(uint8_t *)val);
return ETHERNET_ADDR_LEN;
case NETOPT_IS_WIRED:
return true;
return false;
case NETOPT_LINK_CONNECTED:
return dev->connected;
assert(max_len == 1);
*((netopt_enable_t *)val) = (dev->connected) ? NETOPT_ENABLE
: NETOPT_DISABLE;
return 1;
default:
return netdev_eth_get(netdev, opt, val, max_len);
}

View File

@ -11,7 +11,7 @@
* @{
*
* @file
* @brief Netdev interface for the ESP WiFi AP-based communication
* @brief Network device driver for the ESP32 WiFi interface
*
* @author Gunar Schorcht <gunar@schorcht.net>
*/
@ -37,10 +37,10 @@ typedef struct
{
netdev_t netdev; /**< netdev parent struct */
uint8_t rx_len; /**< number of bytes received */
uint16_t rx_len; /**< number of bytes received */
uint8_t rx_buf[ETHERNET_DATA_LEN]; /**< receive buffer */
uint8_t tx_len; /**< number of bytes in transmit buffer */
uint16_t tx_len; /**< number of bytes in transmit buffer */
uint8_t tx_buf[ETHERNET_DATA_LEN]; /**< transmit buffer */
uint32_t event; /**< received event */

View File

@ -8,10 +8,11 @@
/**
* @ingroup cpu_esp32_esp_wifi
* @ingroup cpu_esp32_conf
* @{
*
* @file
* @brief Parameters for the netdev interface for ESP WiFi module
* @brief Parameters for the ESP32 WiFi netdev interface
*
* @author Gunar Schorcht <gunar@schorcht.net>
*/
@ -25,14 +26,33 @@
* @name Set default configuration parameters for the ESP WiFi netdev driver
* @{
*/
/**
* @brief The size of the stack used for the ESP WIFI netdev driver thread.
*/
#ifndef ESP_WIFI_STACKSIZE
/** The size of the stack used for the ESP WiFi netdev driver thread */
#define ESP_WIFI_STACKSIZE THREAD_STACKSIZE_DEFAULT
#define ESP_WIFI_STACKSIZE (THREAD_STACKSIZE_DEFAULT)
#endif
/**
* @brief The priority of the ESP WiFi netdev driver thread. Should not be changed.
*/
#ifndef ESP_WIFI_PRIO
/** The priority of the ESP WiFi netdev driver thread */
#define ESP_WIFI_PRIO GNRC_NETIF_PRIO
#define ESP_WIFI_PRIO (GNRC_NETIF_PRIO)
#endif
/**
* @brief SSID of the AP to be used.
*/
#ifndef ESP_WIFI_SSID
#define ESP_WIFI_SSID "RIOT_AP"
#endif
/**
* @brief Passphrase used for the AP as clear text (max. 64 chars).
*/
#ifndef ESP_WIFI_PASS
#define ESP_WIFI_PASS "ThisistheRIOTporttoESP"
#endif
/**@}*/

View File

@ -26,17 +26,22 @@ USEMODULE += esp_now
For ESP-NOW, ESP32 nodes are used in WiFi SoftAP + Station mode to advertise their SSID and become visible to other ESP32 nodes. The SSID of an ESP32 node is the concatenation of the prefix ```RIOT_ESP_``` with the MAC address of its SoftAP WiFi interface. The driver periodically scans all visible ESP32 nodes.
The following parameters are defined for ESP-NOW nodes. These parameters can be overriden by [application-specific board configurations](#esp32_application_specific_board_configuration).
The following parameters are defined for ESP-NOW nodes.
<center>
Parameter | Default | Description
:---------|:--------|:-----------
ESP_NOW_SCAN_PERIOD | 10000000UL | Defines the period in us at which an node scans for other nodes in its range. The default period is 10 s.
ESP_NOW_SOFT_AP_PASSPHRASE | ThisistheRIOTporttoESP | Defines the passphrase (max. 64 chars) that is used for the SoftAP interface of an nodes. It has to be same for all nodes in one network.
ESP_NOW_SOFT_AP_PASS | "ThisistheRIOTporttoESP" | Defines the passphrase as clear text (max. 64 chars) that is used for the SoftAP interface of ESP-NOW nodes. It has to be same for all nodes in one network.
ESP_NOW_CHANNEL | 6 | Defines the channel that is used as the broadcast medium by all nodes together.
ESP_NOW_KEY | NULL | Defines a key that is used for encrypted communication between nodes. If it is NULL, encryption is disabled. The key has to be of type ```uint8_t[16]``` and has to be exactly 16 bytes long.
</center>
@note The ESP-NOW network interface (module `esp_now`) and the
Wifi network interface (module `esp_wifi`)
can be used simultaneously, for example, to realize a border router for
a mesh network which uses ESP-NOW.
*/