ESP IDF Wi Fi Stack Pratical Guide Practical
User Manual:
Open the PDF directly: View PDF
.
Page Count: 45
| Download | |
| Open PDF In Browser | View PDF |
ESP-IDF Wi-Fi Stack Practical Guide ESP-IDF V3.1 ESP-IDF Wi-Fi Stack Practical Guide The purpose of this guide is to provide a step-by-step tutorial for developing a network application using the Wi-Fi stack of ESP32-based boards, and it represents a supplement to the Wi-Fi API Reference and the Wi-Fi API Guidelines that can be found in the ESP-IDF Programming Guide. License Copyright © 2018 Riccardo BertiniLicensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Requirements To fully benefit from the contents of this guide, prior knowledge of the following topics is recommended: • • • • • • • • Network stack principles. Wi-Fi basics (concepts of SSID, BSSID, Wi-Fi channels, 802.11x protocols, authentication modes, etc.) Difference between the Station and the SoftAP modes (or sub-interfaces) of a Wi-Fi interface. ESP-IDF projects authoring (guide) ESP32 application startup flow (guide) ESP32 logging mechanism (guide) FreeRTOS tasks basics (guide) FreeRTOS event groups (guide) Structure of a Wi-Fi Application An application which uses the Wi-Fi networking functionalities offered by ESP32 boards can generally be divided into the following components: ESP-IDF Wi-Fi Stack Introduction Page 1 The collection of functions and data structures provided by the ESP-IDF to offer Wi-Fi networking functionalities represents the Wi-Fi Stack, which is implemented on top and directly manages the Wi-Fi interface, while at the application level a Wi-Fi application can be divided into the following two modules: Setup Module The Setup Module, whose purpose is to carry out the setup process of Wi-Fi networking on the device, consists of the following components: • A Wi-Fi Initializer Function, which represents the entry point of a Wi-Fi application and whose tasks are to initialize and configure the Wi-Fi stack and enable the device's Wi-Fi interface. • The Wi-Fi Events General Handler, which is a function called asynchronously by the Wi-Fi stack after its internal handlers each time a Wi-Fi event occurs and whose task is to pass each event with its provided additional information to its relative specific handler. • A set of Wi-Fi Events Specific Handlers, which are functions whose tasks are to perform the application-level handling of Wi-Fi events raised by the Wi-Fi stack and to start driver components when the appropriate requirements for their execution are met. Driver Module The Driver Module represents the part of the application that utilizes the features offered by the Wi-Fi stack to implement a certain service, and while its actual logic and structure depend on its purpose, its components can be generally divided into the following categories according to the Wi-Fi networking features they use, and so the requirements that must be met before their execution can begin: • The Station NoIP Driver Components are components that require the device's station interface to be connected to an access point (AP). • The Station IP Driver Components are components that require the device's station interface to be connected to an access point (AP) and to have an IP configuration set. • The SoftAP Driver Components are components that require the device's SoftAP interface to be enabled, and may rely on it having clients connected. The inter-task synchronization between the two modules is performed by using an Event Group, which represents an abstract type offered by the FreeRTOS kernel consisting of an array of bits which can be used as semaphores via the relative API. ESP-IDF Wi-Fi Stack Introduction Page 2 Code Premises Required Headers The minimal subset of libraries required to develop a Wi-Fi application, with their paths relative to the $ESP-IDF environment variable, is as follows: /*-- C standard libraries --*/ #include /*-- Environment-specific libraries --*/ #include "esp_system.h" #include "esp_log.h" #include "nvs_flash.h" #include "esp_wifi.h" #include "esp_event_loop.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/event_groups.h" #include "lwip/sockets.h" //C standard string library //ESP32 base system library //ESP32 logging library //ESP32 flash memory library //ESP32 main Wi-Fi library //ESP32 Wi-Fi events library //FreeRTOS base library //FreeRTOS tasks library //FreeRTOS event groups library //LwIP base library Wi-Fi Event Group The Wi-Fi event group used for inter-task synchronization purposes between the Setup and the Driver module and its flags used in the context of this guide are defined as follows: EventGroupHandle_t wifi_event_group; //Wi-Fi Event Group Handler /*-- Station interface Flags --*/ #define STA_ON BIT0 //Whether the Station interface is enabled or not #define STA_CONN BIT1 //Whether the Station interface is connected to an AP or not #define STA_GOTIP BIT2 //Whether the Station interface has an IP configuration set or not /*-- SoftAP interface Flags --*/ #define SOFTAP_ON BIT3 //Whether the SoftAP interface is enabled or not #define SOFTAP_CLI BIT4 //Whether the SoftAP interface has clients connected or not /*-- Driver Components Executions Flags --*/ //Indicate whether each driver component is running or not (where here a single component for each of the three driver categories is used) #define WIFI_DRIVER_STATION_NOIP BIT5 //Whether the Station NoIP drivers are running #define WIFI_DRIVER_STATION_IP BIT6 //Whether the Station IP drivers are running #define WIFI_DRIVER_SOFTAP BIT7 //Whether the SoftAP drivers are running Also note that within this guide the parameters used in the code examples are shown in capital letters and represent predefined constants (e.g. WIFI_STATION_SSID_PASSWORD, WIFI_SOFTAP_AUTHMODE, etc.), whose values in an actual project can be set for example by providing an appropriate Kconfig.projbuild configuration file and using the menuconfig utility. ESP-IDF Wi-Fi Stack Introduction Page 3 Setup Module The setup process of a Wi-Fi application is divided into a first phase relative to the inizializations and configurations required to enable Wi-Fi networking on a device, which are carried out by the Wi-Fi Initializer Function, and a second event-driven phase represented by the application-level handling of the Wi-Fi events raised by the Wi-Fi stack, which are carried out by the Wi-Fi Events General Handler and the set of Wi-Fi Events Specific Handlers. Wi-Fi Initializer Function The Wi-Fi Initializer Function represents the entry point of a Wi-Fi application, and its purposes are to initialize and configure the Wi-Fi stack and enable the Wi-Fi interface, which is performed through the following tasks: 1) Initialize the system flash storage By default the Wi-Fi stack stores its configuration in the system's flash memory, which consequently needs to be initialized beforehand by using the following function: //File nvs.flash.h esp_err_t nvs_flash_init(void) The ESP_ERR_NVS_NO_FREE_PAGES represents a recoverable error, whose recovery can be attempted by completely erasing the flash memory through the following function and then trying to initialize it again: //File nvs.flash.h esp_err_t nvs_flash_erase(void) No errors in this function can be recovered, so the initialization procedure of the system flash storage appears as follows: ESP-IDF Wi-Fi Stack Wi-Fi Initializer Function Page 4 esp_err_t wifi_init() { esp_err_t ret = nvs_flash_init(); //Flash storage initialization if(ret == ESP_ERR_NVS_NO_FREE_PAGES) //Error recovery attempt { ESP_ERROR_CHECK(nvs_flash_erase()); ret = nvs_flash_init(); } ESP_ERROR_CHECK(ret); //At this point if errors persist, it is not … possible to proceed with the program's execution } 2) Initialize the TCP/LwIP Stack Next we need to initialize the data structures relative to the TCP/LwIP stack and create the core LwIP task, which can be obtained by calling the following function: //File tcpip_adapter.h (automatically included by the previous headers) void tcpip_adapter_init(void) esp_err_t wifi_init() { … tcpip_adapter_init(); … } //Initialize the TCP/LwIP stack 3) Create the Wi-Fi Event Group Next we need to create the Wi-Fi event group, which can be allocated dynamically on the heap by calling the following function: //File event_groups.h typedef void* EventGroupHandle_t EventGroupHandle_t xEventGroupCreate(void) Where the return of the function represents the allocated event group's handler, which must be assigned to the mesh_event_group global variable that was previously defined. As for its bits, to describe the state of the Wi-Fi interface during the application's execution the following flags are used: Station interface Flags • A flag representing whether the Station interface is enabled or not • A flag representing whether the Station interface is connected to an AP or not • A flag representing whether the Station interface has an IP configuration set or not (STA_ON) (STA_CONN) (STA_GOTIP) SoftAP interface Flags • A flag representing whether the SoftAP interface is enabled or not • A flag representing whether the SoftAP interface has clients connected or not ESP-IDF Wi-Fi Stack Wi-Fi Initializer Function (SOFTAP_ON) (SOFTAP_CLI) Page 5 In addition to these flags, to allow the setup module to synchronize with the current state of the driver module an additional flag should be provided for each of its components, representing whether the component is currently being executed or not (this is to avoid creating undesidered duplicate tasks of the same component, we'll see in more detail later), and assuming a single component for each of the three driver categories previously discussed the following three additional flags are required: • A flag representing whether the Station NoIP driver component is currently being executed or not • A flag representing whether the Station IP driver component is currently being executed or not • A flag representing whether the SoftAP driver component is currently being executed or not (WIFI_DRIVER_STATION_NOIP) (WIFI_DRIVER_STATION_IP) (WIFI_DRIVER_SOFTAP) From here we can associate a bit to each required flag as shown earlier in the code premises. esp_err_t wifi_init() { … wifi_event_group = xEventGroupCreate(); … } //Create the Wi-Fi Event Group 4) Register the Wi-Fi Events General Handler Next we need to register in the Wi-Fi stack the function that must be called each time a Wi-Fi event occurs to perform the application-level handling of such event, i.e. the Wi-Fi Events General Handler function, and this is obtained by calling the following function: //File esp_event_loop.h esp_err_t esp_event_loop_init(system_event_cb_t cb, void* ctx) esp_err_t wifi_events_handler(void* ctx, system_event_t* event) { /* We'll see later */ } … esp_err_t wifi_init() { … //Register the Wi-Fi Events General Handler ESP_ERROR_CHECK(esp_event_loop_init(wifi_events_handler,NULL)); … } ESP-IDF Wi-Fi Stack Wi-Fi Initializer Function Page 6 5) Initialize the Wi-Fi Stack Next we need to initialize the Wi-Fi stack, which is obtained by calling the following function: //File esp_wifi.h typedef struct //Wi-Fi stack initialization parameters { system_event_handler_t event_handler; //Wi-Fi event handler wifi_osi_funcs_t* osi_funcs; //Wi-Fi OS functions wpa_crypto_funcs_t wpa_crypto_funcs; //Wi-Fi station crypto functions int static_rx_buf_num; //Wi-Fi static RX buffer number int dynamic_rx_buf_num; //Wi-Fi dynamic RX buffer number int tx_buf_type; //Wi-Fi TX buffer type int static_tx_buf_num; //Wi-Fi static TX buffer number int dynamic_tx_buf_num; //Wi-Fi dynamic TX buffer number int csi_enable; //Wi-Fi CSI enable flag int ampdu_rx_enable; //Wi-Fi AMPDU RX enable flag int ampdu_tx_enable; //Wi-Fi AMPDU TX enable flag int nvs_enable; //Wi-Fi NVS flash enable flag int nano_enable; //printf/scan family enable flag int tx_ba_win; //Wi-Fi Block Ack TX window size int rx_ba_win; //Wi-Fi Block Ack RX window size int wifi_task_core_id; //Wi-Fi Task Core ID int magic; //Wi-Fi init magic number } wifi_init_config_t; esp_err_t esp_wifi_init(const wifi_init_config_t* config) Generally the Wi-Fi Stack can be initialized to its default parameters, which is obtained by using the following macro: #define WIFI_INIT_CONFIG_DEFAULT() { .event_handler = &esp_event_send, .osi_funcs = &g_wifi_osi_funcs, .wpa_crypto_funcs = g_wifi_default_wpa_crypto_funcs, .static_rx_buf_num = CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM, .dynamic_rx_buf_num = CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM, .tx_buf_type = CONFIG_ESP32_WIFI_TX_BUFFER_TYPE, .static_tx_buf_num = WIFI_STATIC_TX_BUFFER_NUM, .dynamic_tx_buf_num = WIFI_DYNAMIC_TX_BUFFER_NUM, .csi_enable = WIFI_CSI_ENABLED, .ampdu_rx_enable = WIFI_AMPDU_RX_ENABLED, .ampdu_tx_enable = WIFI_AMPDU_TX_ENABLED, .nvs_enable = WIFI_NVS_ENABLED, .nano_enable = WIFI_NANO_FORMAT_ENABLED, .tx_ba_win = WIFI_DEFAULT_TX_BA_WIN, .rx_ba_win = WIFI_DEFAULT_RX_BA_WIN, .wifi_task_core_id = WIFI_TASK_CORE_ID, .magic = WIFI_INIT_CONFIG_MAGIC }; ESP-IDF Wi-Fi Stack Wi-Fi Initializer Function \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Page 7 esp_err_t wifi_init() { … wifi_init_config_t initcfg = WIFI_INIT_CONFIG_DEFAULT(); ESP_ERROR_CHECK(esp_wifi_init(&initcfg)); //Initialize the Wi-Fi Stack … } 6) Interface Modes Selection Next we must select the modes (or sub-interfaces) in which the Wi-Fi interface will be enabled later, which depend on the services and consequently the networking features required by the driver components, selection that can be performed by calling the following function: //File esp_wifi_types.h (automatically included by the previous headers) typedef enum { WIFI_MODE_NULL = 0, WIFI_MODE_STA, WIFI_MODE_AP, WIFI_MODE_APSTA, WIFI_MODE_MAX, } wifi_mode_t; //Interface Mode enumerates //NULL mode (do not use) //Station mode //SoftAP mode //Station + SoftAP mode //File esp_wifi.h esp_err_t esp_wifi_set_mode(wifi_mode_t mode) esp_err_t wifi_init() { … if(WIFI_STATION_ENABLE&&WIFI_SOFTAP_ENABLE) //If both interface ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_APSTA)); modes are selected else if(WIFI_STATION_ENABLE) //If only the station mode is selected ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); else if(WIFI_SOFTAP_ENABLE //If only the SoftAP mode is selected ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP)); else //If no mode is selected for the Wi-Fi interface abort(); the program's execution cannot continue … } ESP-IDF Wi-Fi Stack Wi-Fi Initializer Function Page 8 7) Interface Modes Base Configurations Next we must set the base configuration of the Wi-Fi interface modes that were selected for use previously, which are described by the following data structures: //File esp_wifi_types.h /*-- Station interface Base Configuration --*/ typedef struct //A set of information on the target AP the Station interface must { attempt to connect to once the Wi-Fi interface has been enabled uint8_t ssid[32]; //SSID of the target AP uint8_t password[64]; //Password of the target AP bool bssid_set; //If set the Station interface must attempt to connect only to the AP with the following specific BSSID uint8_t bssid[6]; //Specific BSSID of the target AP uint16_t listen_interval; //The number of DTIM periods the Station interface remains in the sleep state before checking whether it has frames pending to be received from its AP … (effective only if the maximum power saving mode } wifi_sta_config_t; is set for the station interface, we'll see later) /*-- SoftAP interface Base Configuration --*/ typedef enum { WIFI_AUTH_OPEN = 0, WIFI_AUTH_WEP, WIFI_AUTH_WPA_PSK, WIFI_AUTH_WPA2_PSK, WIFI_AUTH_WPA_WPA2_PSK, WIFI_AUTH_WPA2_ENTERPRISE, WIFI_AUTH_MAX } wifi_auth_mode_t; typedef struct { uint8_t ssid[32]; uint8_t ssid_len; uint8_t ssid_hidden; wifi_auth_mode_t authmode; uint8_t password[64]; uint8_t channel; uint8_t max_connection; uint16_t beacon_interval; } wifi_ap_config_t; //SoftAP authmode enumerates //Open (no authentication) //WEP (buggy, avoid) //WPA_PSK //WPA2_PSK //WPA_WPA2_PSK //WPA2_ENTERPRISE //SoftAP interface settings //SoftAP SSID //SoftAP SSID Length //Whether the SoftAP SSID should be hidden from its Wi-Fi beacon frames (default = 0, SSID visible) //The authentication protocol used by the SoftAP interface to associate clients //The password required from clients to connect to the SoftAP interface //The Wi-Fi channel used by the SoftAP interface //The maximum number of clients allowed to be connected simultaneously to the SoftAP interface (default and maximum = 4) //The sending interval in millisecond of the SoftAP Wi-Fi beacon frames (default = 100ms, max = 6000ms) //Wi-Fi interface mode base configuration union typedef union { wifi_sta_config_t sta; wifi_ap_config_t ap; } wifi_config_t; ESP-IDF Wi-Fi Stack //Holds a Wi-Fi interface mode base configuration (Station OR SoftAP) //Station mode Base Configuration //SoftAP mode Base Configuration Wi-Fi Initializer Function Page 9 Once the base configuration(s) of the interface mode(s) have been set, they can be applied by using the following function: //File esp_interface.h (automatically included by the previous headers) typedef enum { ESP_IF_WIFI_STA = 0, ESP_IF_WIFI_AP, ESP_IF_ETH, ESP_IF_MAX } esp_interface_t; //Networking interface enumerates //Wi-Fi Station interface //Wi-Fi SoftAP interface //Ethernet interface //File esp_wifi.h typedef esp_interface_t wifi_interface_t; esp_err_t esp_wifi_set_config(wifi_interface_t ifx_mode, wifi_config_t* base_config) Settings in an interface mode's base configuration that are left uninitialized will be set to their default values with the function call, and note that being the ESP32 Wi-Fi interface limited to a single active Wi-Fi channel, if both interface modes are enabled their Wi-Fi channel will coincide, where the Wi-Fi stack will always switch the SoftAP Wi-Fi channel onto the one currently used by the station interface. Also note that the Station interface base configuration can also be set after the Wi-Fi interface has been enabled by performing a Wi-Fi scan of the available APs (we'll see later). ESP-IDF Wi-Fi Stack Wi-Fi Initializer Function Page 10 esp_err_t wifi_init() { … //Station interface Base Configuration if(WIFI_STATION_ENABLE) { wifi_config_t station_config = {0}; //Stores the Station interface base configuration to apply //Set the Target AP's SSID strcpy((char*)station_config.sta.ssid,WIFI_STATION_AP_SSID); //Set the Target AP's Password strcpy((char*)station_config.sta.password,WIFI_STATION_AP_PASSWORD); //Whether to connect to a target AP with a specific BSSID if(WIFI_STATION_USE_SPECIFIC_BSSID) { station_config.sta.bssid_set = true; //Set the specific BSSID memcpy(station_config.sta.bssid,WIFI_STATION_SPECIFIC_BSSID,6); } //Apply the Station interface Base Configuration ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA,&station_config)); } //SoftAP interface Base Configuration if(WIFI_SOFTAP_ENABLE) { wifi_config_t softap_config = {0}; //Stores the SoftAP interface base configuration to apply //Set the SoftAP SSID strcpy((char*)softap_config.ap.ssid,WIFI_SOFTAP_SSID); //Set the SoftAP SSID Length softap_config.ap.ssid_len = strlen(WIFI_SOFTAP_SSID); //Whether to hide the SoftAP SSID from its Wi-Fi beacon frames if(WIFI_SOFTAP_SSID_HIDDEN) softap_config.ap.ssid_hidden = 1; //Set the SoftAP Authmode softap_config.ap.authmode = WIFI_SOFTAP_AUTHMODE; //Set the SoftAP Password strcpy((char*)softap_config.ap.password,WIFI_SOFTAP_PASSWORD); //Set the Wi-Fi channel to be used by the SoftAP interface softap_config.ap.channel = WIFI_SOFTAP_CHANNEL; //Set the SoftAP Maximum Connections softap_config.ap.max_connection = WIFI_SOFTAP_MAXCONNECTIONS; //Set the SoftAP Wi-Fi Beacon Sending Interval softap_config.ap.beacon_interval = WIFI_SOFTAP_BEACON_INTERVAL; //Apply the SoftAP interface Base Configuration ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_AP,&softap_config)); } … } ESP-IDF Wi-Fi Stack Wi-Fi Initializer Function Page 11 8) Other Interface Modes Settings (optional) Once their base configurations have been set it is possible to configure additional settings related to the Wi-Fi interface modes, such as: • Set a custom MAC address for an interface By default the Station interface uses as its MAC address the device Base MAC address burnt into the NIC's ROM, while the SoftAP interface uses the same address incremented by one in the least significant byte, although, if desired, it's possible to use custom MAC addresses for both interfaces by using the following function: //File esp_wifi.h esp_err_t esp_wifi_set_mac(wifi_interface_t ifx_mode, const uint8_t* mac[]) Note that the MAC addresses of a node's Station and SoftAP interfaces cannot coincide, and trying to do so will cause the function to return the ESP_ERR_WIFI_MAC error, and as an additional constraint the bit 0 of the most significant byte of the MAC address cannot be set (for example xA:xx:xx:xx:xx:xx is a valid address, while x5:xx:xx:xx:xx:xx is not). esp_err_t wifi_init() { … uint8_t mac[6]; //Used to set a custom MAC address for an interface //If a custom MAC address is used for the Station interface if(WIFI_STATION_USE_CUSTOM_MAC) { memcpy(mac,WIFI_STATION_CUSTOM_MAC,6); ESP_ERROR_CHECK(esp_wifi_set_mac(ESP_IF_WIFI_STA,mac)); } //If a custom MAC address is used for the SoftAP interface if(WIFI_SOFTAP_USE_CUSTOM_MAC) { memcpy(mac,WIFI_SOFTAP_CUSTOM_MAC,6); ESP_ERROR_CHECK(esp_wifi_set_mac(ESP_IF_WIFI_AP,mac)); } … } ESP-IDF Wi-Fi Stack Wi-Fi Initializer Function Page 12 • Set the Station interface Power Saving Mode To limit its power consumption the following power saving modes can be enabled for the station interface: • The minimum power saving mode, where the interface awakens every DTIM period to verify whether it has frames pending to be received by checking its associated AP's TIM map (default). • The maximum power saving mode, where the interface awakens every listen_interval DTIM periods to verify whether it has frames pending to be received by checking its associated AP's TIM map, where the listen_interval parameter was previously set in the station base configuration. The power saving mode to use on the Station interface can be selected via the following function: //File esp_wifi_types.h typedef enum { WIFI_PS_NONE, WIFI_PS_MIN_MODEM, WIFI_PS_MAX_MODEM, } wifi_ps_type_t; //Station interface power saving mode enumerates //No power saving //Minimum power saving mode (default) //Maximum power saving mode //File esp_wifi.h esp_err_t esp_wifi_set_ps(wifi_ps_type_t ps_mode) esp_err_t wifi_init() { … if(WIFI_STATION_ENABLE) //Set the Station interface power saving mode ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_STATION_POWERSAVING_MODE)); … } Please refer to the Wi-Fi API Reference for the full list of settings related to the Wi-Fi interface modes, where note that non-configured settings will be set to their default values once the Wi-Fi interface is enabled. ESP-IDF Wi-Fi Stack Wi-Fi Initializer Function Page 13 9) Interface Modes IP Settings (optional) The default IP configurations used by the Station and the SoftAP interfaces consist of the following: • The Station interface is configured to retrieve a dynamic IP configuration via its DHCP client as soon as it connects to an AP. • The SoftAP interface is configured with the following predefined IP configuration: Which represents a Class C IP address with no forwarding or name-resolution capabilities (also note that as of the current ESP-IDF version the SoftAP interface doesn't support a secondary DNS server set). Also note that, once the SoftAP interface is enabled, a DHCP server is started on it to offer its clients dynamic IP configurations, which are obtained from a pool derived from the interface's own IP configuration. From here, should their default IP configurations be unsuitable for the purposes of the application, it's possible to set custom static IP configurations for the interfaces by performing the following steps: Station interface custom Static IP Configuration To set a static IP configuration for the Station interface, its DHCP client must be preliminarly disabled, which is obtained by calling the following function: //File tcpip_adapter.h typedef enum { TCPIP_ADAPTER_IF_STA = 0, TCPIP_ADAPTER_IF_AP, TCPIP_ADAPTER_IF_ETH, TCPIP_ADAPTER_IF_MAX, } tcpip_adapter_if_t; //Network interfaces enumerates //Station interface //SoftAP interface //Ethernet interface esp_err_t tcpip_adapter_dhcpc_stop(tcpip_adapter_if_t tcpip_if) ESP-IDF Wi-Fi Stack Wi-Fi Initializer Function Page 14 Once the Station DHCP client has been disabled a static IP configuration can be set for the interface by using the following function: //File tcpip_adapter.h typedef struct //Interface IP configuration { ip4_addr_t ip; //Interface IP address ip4_addr_t netmask; //Interface Netmask ip4_addr_t gw; //Interface default Gateway } tcp_ip_adapter_ip_info_t; esp_err_t tcpip_adapter_set_ip_info(tcpip_adapter_if_t tcpip_if, tcpip_adapter_ip_info_t* ip_info) If desidered it's also possible to set the addresses of the Station interface primary and secondary DNS servers, which is obtained by using the following function: //File tcpip_adapter.h typedef enum { TCPIP_ADAPTER_DNS_MAIN = 0, TCPIP_ADAPTER_DNS_BACKUP, TCPIP_ADAPTER_DNS_FALLBACK, TCPIP_ADAPTER_DNS_MAX, } tcpip_adapter_dns_type_t; typedef struct { ip_addr_t ip; } tcp_ip_adapter_dns_info_t; //DNS Servers types enumerates //Primary (or main) DNS server //Secondary (or backup) DNS server //Fallback DNS server (Station interface only) //DNS server information //DNS server IP address esp_err_t tcpip_adapter_set_dns_info(tcpip_adapter_if_t tcpip_if, tcpip_adapter_dns_type_t type, tcpip_adapter_dns_info_t* addr) ESP-IDF Wi-Fi Stack Wi-Fi Initializer Function Page 15 SoftAP interface custom Static IP Configuration Before setting a (custom) static IP configuration for the SoftAP interface, its DHCP server must be temporarily disabled, which is obtained by calling the following function: //File tcpip_adapter.h esp_err_t tcpip_adapter_dhcps_stop(tcpip_adapter_if_t tcpip_if) Once its DHCP server has been disabled a custom static IP configuration and possibly the address of its primary DNS server can be set for the SoftAP interface by using the tcpip_adapter_set_ip_info() and the tcpip_adapter_set_dns_info() functions described earlier, after which its possible to re-enable its DHCP server (whose pool of dynamic IP configurations will be derived from the new interface IP configuration) by using the following function: //File tcpip_adapter.h esp_err_t tcpip_adapter_dhcps_start(tcpip_adapter_if_t tcpip_if) //File lwip/sockets.h int inet_pton(int af, const char* src, void* dst); //Converts an IP address from its presentational to its network form, i.e. from string to uint32_t ESP-IDF Wi-Fi Stack Wi-Fi Initializer Function Page 16 esp_err_t wifi_init() { … tcpip_adapter_ip_info_t ipinfo; tcpip_adapter_dns_type_t dnsaddr; //Used to set a custom static IP configuration for an interface //Used to set an interface's DNS servers addresses //If a static IP configuration is used for the Station interface if(WIFI_STATION_IPSTATIC) { //Stop the Station DHCP Client ESP_ERROR_CHECK(tcpip_adapter_dhcpc_stop(TCPIP_ADAPTER_IF_STA)); //Set the Station static IP configuration inet_pton(AF_INET,WIFI_STATION_STATIC_IP,&ipinfo.ip); inet_pton(AF_INET,WIFI_STATION_STATIC_NETMASK,&ipinfo.netmask); inet_pton(AF_INET,WIFI_STATION_STATIC_GATEWAY,&ipinfo.gw); ESP_ERROR_CHECK(tcpip_adapter_set_ip_info(TCPIP_ADAPTER_IF_STA,&ipinfo)); //Set the Station DNS servers inet_pton(AF_INET,WIFI_STATION_STATIC_DNS_PRIMARY,&dnsaddr); ESP_ERROR_CHECK(tcpip_adapter_set_dns_info(TCPIP_ADAPTER_IF_STA, TCPIP_ADAPTER_DNS_MAIN, &dnsaddr)); inet_pton(AF_INET,WIFI_STATION_STATIC_DNS_SECONDARY,&dnsaddr); ESP_ERROR_CHECK(tcpip_adapter_set_dns_info(TCPIP_ADAPTER_IF_STA, TCPIP_ADAPTER_DNS_BACKUP, &dnsaddr)); } //If a (custom) static IP configuration is used for the SoftAP interface if(WIFI_SOFTAP_IPSTATIC) { //Temporarily disable the SoftAP DHCP server ESP_ERROR_CHECK(tcpip_adapter_dhcps_stop(TCPIP_ADAPTER_IF_AP)); //Set the SoftAP static IP configuration inet_pton(AF_INET,WIFI_SOFTAP_STATIC_IP,&ipinfo.ip); inet_pton(AF_INET,WIFI_SOFTAP_STATIC_NETMASK,&ipinfo.netmask); inet_pton(AF_INET,WIFI_SOFTAP_STATIC_GATEWAY,&ipinfo.gw); ESP_ERROR_CHECK(tcpip_adapter_set_ip_info(TCPIP_ADAPTER_IF_AP,&ipinfo)); //Set the SoftAP primary DNS server inet_pton(AF_INET,WIFI_SOFTAP_STATIC_DNS_PRIMARY,&dnsaddr); ESP_ERROR_CHECK(tcpip_adapter_set_dns_info(TCPIP_ADAPTER_IF_AP, TCPIP_ADAPTER_DNS_MAIN, &dnsaddr)); //Re-enable the SoftAP DHCP server ESP_ERROR_CHECK(tcpip_adapter_dhcps_start(TCPIP_ADAPTER_IF_AP)); } … } Aside from their IP configurations it should also be pointed out that currently the ESP-IDF Wi-Fi stack doesn't offer any built-in functionality to tunnel IP packets between interface modes, thus limiting the possibility of using a board as a standalone access point. ESP-IDF Wi-Fi Stack Wi-Fi Initializer Function Page 17 10) Enable the Wi-Fi Interface Once the desidered interface modes configurations have been set, the Wi-Fi interface can be enabled in the modes previously selected via the esp_wifi_set_mode() function by calling the following function: //File esp_wifi.h esp_err_t esp_wifi_start(void) esp_err_t wifi_init() { … ESP_ERROR_CHECK(esp_wifi_start()); return ESP_OK; } //Enable the Wi-Fi interface //End of the Wi-Fi Initializer Function Once the esp_wifi_start() function returns successfully the Wi-Fi interface will be enabled in the mode(s) previously defined by the esp_wifi_set_mode() function call, which will cause the SYSTEM_EVENT_STA_START and/or the SYSTEM_EVENT_AP_START events to trigger in the Wi-Fi stack, thereby causing the Wi-Fi setup process to pass into its event-driven phase. ESP-IDF Wi-Fi Stack Wi-Fi Initializer Function Page 18 Summarizing, the tasks that must be performed by the Wi-Fi Initializer Function are: Also note that the majority of the Wi-Fi settings we have discussed so far can also be modified after the Wi-Fi interface has been enabled on a device, which may cause its Station and/or SoftAP interfaces to be restarted depending on the changes applied. ESP-IDF Wi-Fi Stack Wi-Fi Initializer Function Page 19 Event-driven Setup Phase Once the Wi-Fi interface has been enabled on a device, the Wi-Fi setup process enters its event-driven phase, which consists in the application-level handling of the Wi-Fi Events raised by the Wi-Fi Stack. A Wi-Fi Event can be represented as a set of conditions on the state of the Wi-Fi stack on the device which, other than evolving internally through the application's execution, is affected by the data received from the Wi-Fi interface, and once all the conditions representing an event have been met, such event will be raised by the Wi-Fi stack. Once raised, a Wi-Fi event is first handled internally in the Wi-Fi stack by its Specific Implicit Handler, which performs a set of Implicit Actions that depend on other conditions relative to the state of the Wi-Fi stack. Once its internal handling is complete, the event with its ID and a set of additional information are passed by the Wi-Fi stack at the application level to the Wi-Fi Events General Handler function previously registered via the esp_event_loop_init() function, which in turn will call, passing the additional information provided, the Specific Handler relative to such event, where the actual application-level handling of the event is performed, whose Typical Actions depend again on the state of the Wi-Fi stack, the additional information provided and possibly the intended logic of the setup process. The Wi-Fi events that can be raised by the Wi-Fi stack can be divided into Station Interface Events, which are relative to the Station interface, and SoftAP Interface Events, which are relative to the SoftAP interface. The full list of Wi-Fi events with their description, the implicit actions performed by their implicit handlers, the additional information passed at the application-level by the Wi-Fi stack, and the typical actions that should be performed by their specific handlers are summarized in the following table: ESP-IDF Wi-Fi Stack Wi-Fi Events Handling Page 20 ESP-IDF Wi-Fi Stack Wi-Fi Events Handling Page 21 Wi-Fi Events General Handler The ID and possible additional information on the Wi-Fi events that occur are passed by the Wi-Fi stack to the Wi-Fi Events General Handler using the following data structures: Wi-Fi Events ID Definitions //File esp_event_legacy.h (automatically included by the previous headers) typedef enum { /*-- Station Interface Events --*/ SYSTEM_EVENT_STA_START, SYSTEM_EVENT_STA_STOP, SYSTEM_EVENT_SCAN_DONE, SYSTEM_EVENT_STA_CONNECTED, SYSTEM_EVENT_STA_DISCONNECTED, SYSTEM_EVENT_STA_GOT_IP, SYSTEM_EVENT_STA_LOST_IP, SYSTEM_EVENT_STA_AUTHMODE_CHANGE, //Wi-Fi Events IDs /*-- SoftAP Interface Events --*/ SYSTEM_EVENT_AP_START, SYSTEM_EVENT_AP_STOP, SYSTEM_EVENT_AP_STACONNECTED, SYSTEM_EVENT_AP_STADISCONNECTED, … } system_event_id_t; ESP-IDF Wi-Fi Stack Wi-Fi Events Handling Page 22 Wi-Fi Events Additional Information Types Station Interface Events /*============================= SYSTEM_EVENT_SCAN_DONE =============================*/ //File esp_event_legacy.h typedef struct { uint8_t scan_id; //The ID of the Wi-Fi scan uint32_t status; //The return status of the Wi-Fi scan uint8_t number; //The number of APs that were found in the scan } system_event_sta_scan_done_t; /*=========================== SYSTEM_EVENT_STA_CONNECTED ===========================*/ //File esp_event_legacy.h typedef struct { uint8_t ssid[32]; //SSID of the AP the Station connected to uint8_t ssid_len; //SSID length of the AP the Station connected to uint8_t bssid[6]; //BSSID of the AP the Station connected to uint8_t channel; //Wi-Fi channel used by the AP the Station connected to wifi_auth_mode_t authmode; //The authmode used by the AP the Station connected to } system_event_sta_connected_t; /*========================== SYSTEM_EVENT_STA_DISCONNECTED ==========================*/ //File esp_event_legacy.h typedef struct { uint8_t ssid[32]; //SSID of the AP the Station disconnected from uint8_t ssid_len; //SSID length of the AP the Station disconnected from uint8_t bssid[6]; //BSSID of the AP the Station disconnected from uint8_t reason; //The reason for the disconnection (wifi_err_reason_t) } system_event_sta_disconnected_t; /*============================= SYSTEM_EVENT_STA_GOT_IP =============================*/ //File esp_event_legacy.h typedef struct { tcpip_adapter_ip_info_t ip_info; //IP configuration obtained by the Station interface bool ip_changed; //Whether this IP configuration } system_event_sta_got_ip_t; overrode a previous one /*============================= SYSTEM_EVENT_STA_GOT_IP =============================*/ //File esp_event_legacy.h typedef struct { wifi_authmode_t old_mode; //The AP old authmode wifi_authmode_t old_mode; //The AP new authmode } system_event_sta_authmode_change_t; ESP-IDF Wi-Fi Stack Wi-Fi Events Handling Page 23 SoftAP Interface Events /*========================== SYSTEM_EVENT_AP_STACONNECTED ==========================*/ //File esp_event_legacy.h typedef struct { uint8_t mac[6]; //The MAC address of the connected client uint_t aid; //The aid that was given by the SoftAP to the connected client } system_event_ap_staconnected_t; /*========================= SYSTEM_EVENT_AP_STADISCONNECTED =========================*/ //File esp_event_legacy.h typedef struct { uint8_t mac[6]; //The MAC address of the disconnected client uint_t aid; //The aid that was given by the SoftAP to the disconnected client } system_event_ap_stadisconnected_t; Wi-Fi Events Additional Information union typedef union //Wi-Fi Events additional information union { /*-- Station Interface Events additional information --*/ system_event_sta_scan_done_t scan_done; //SYSTEM_EVENT_SCAN_DONE system_event_sta_connected_t connected; //SYSTEM_EVENT_STA_CONNECTED system_event_sta_disconnected_t disconnected; //SYSTEM_EVENT_STA_DISCONNECTED system_event_sta_got_ip_t got_ip; //SYSTEM_EVENT_STA_GOT_IP system_event_sta_authmode_change_t auth_change; //SYSTEM_EVENT_STA_AUTHMODE_CHANGE /*-- SoftAP Interface Events additional information --*/ system_event_ap_staconnected_t sta_connected; //SYSTEM_EVENT_AP_STACONNECTED system_event_ap_stadisconnected_t sta_disconnected; //SYSTEM_EVENT_AP_STADISCONNECTED } system_event_info_t; Wi-Fi Events Summary Struct This represents the summary struct that is passed by the Wi-Fi stack to the Wi-Fi Events General Handler for the application-level handling of Wi-Fi events: typedef struct { system_event_id_t event_id; system_event_info_t event_info; } system_event_t; ESP-IDF Wi-Fi Stack //Summary struct passed by the Wi-Fi stack to the Wi-Fi Events General Handler //Event ID //Event-specific information (if applicable) Wi-Fi Events Handling Page 24 From here at the application level the Wi-Fi Events General Handler function should be declared as follows: esp_err_t wifi_events_handler(void* ctx, system_event_t* event) Where: • The ctx parameter is reserved for the user (it should typically be ignored within the function). • The event parameter represents the address of the summary struct passed by the Wi-Fi stack containing the information on the Wi-Fi event that has occured. Regarding its definition, as discussed before the task of the Wi-Fi Events General Handler consists in calling the specific handler relative to each event that occurs, passing it the additional information provided by the Wi-Fi stack where applicable, and therefore its general structure appears as follows: esp_err_t wifi_events_handler(void* ctx, system_event_t* event) { switch(event->event_id) { case EVENT1: wifi_EVENT1_handler(&event->event_info.EVENT1_t); //call EVENT1 specific handler break; case EVENT2: wifi_EVENT2_handler(&event->event_info.EVENT2_t); //call EVENT2 specific handler break; … case EVENTN: wifi_EVENTN_handler(&event->event_info.EVENTN_t); //call EVENTN specific handler break; default: ESP_LOGE(TAG,"Unknown Wi-Fi Event with ID: %u",event->event_id); break; } return ESP_OK; } So, considering the Wi-Fi events that can currently be raised by the Wi-Fi stack, the actual definition of the Wi-Fi Events General Handler appears as follows: ESP-IDF Wi-Fi Stack Wi-Fi Events Handling Page 25 esp_err_t wifi_events_handler(void* ctx, system_event_t* event) { switch(event->event_id) { /*-- Station Interface Events --*/ case SYSTEM_EVENT_STA_START: wifi_STA_START_handler(); break; case SYSTEM_EVENT_STA_STOP: wifi_STA_STOP_handler(); break; case SYSTEM_EVENT_SCAN_DONE: wifi_SCAN_DONE_handler(&event->event_info.scan_done); break; case SYSTEM_EVENT_STA_CONNECTED: wifi_STA_CONNECTED_handler(&event->event_info.connected); break; case SYSTEM_EVENT_STA_DISCONNECTED: wifi_STA_DISCONNECTED_handler(&event->event_info.disconnected); break; case SYSTEM_EVENT_STA_GOT_IP: wifi_STA_GOT_IP_handler(&event->event_info.got_ip); break; case SYSTEM_EVENT_STA_LOST_IP: wifi_STA_LOST_IP_handler(); break; case SYSTEM_EVENT_STA_AUTHMODE_CHANGE: wifi_STA_AUTHMODE_CHANGE_handler(&event->event_info.auth_change); break; /*-- SoftAP Interface Events --*/ case SYSTEM_EVENT_AP_START: wifi_AP_START_handler(); break; case SYSTEM_EVENT_AP_STACONNECTED: wifi_AP_STACONNECTED_handler(&event->event_info.sta_connected); break; case SYSTEM_EVENT_AP_STADISCONNECTED: wifi_AP_STADISCONNECTED_handler(&event->event_info.sta_disconnected); break; default: ESP_LOGE(TAG,"Unknown Wi-Fi Event with ID: %u",event->event_id); break; } return ESP_OK; } It should also be noted that depending on the Wi-Fi stack's configuration previously set via the Wi-Fi Initializer Function and the logic of the driver module, some Wi-Fi events may never be raised by the Wi-Fi stack, thus making their application-level handling unnecessary in specific contexts. ESP-IDF Wi-Fi Stack Wi-Fi Events Handling Page 26 Wi-Fi Events Specific Handlers Following the previous definition of the Wi-Fi Events General Handler, the Wi-Fi events specific handlers should be defined according to the following general structure: void wifi_EVENTi_handler(EVENTi_t* info) { /* Specific handler logic */ return; } where the info argument must be present only if additional information is provided by the Wi-Fi stack for the event, which as discussed before is passed by the Wi-Fi Events General Handler to the specific handler in question. Described below are the typical actions that should be performed by each Wi-Fi specific handler: Station Interface Events SYSTEM_EVENT_STA_START This event is raised after the Station interface has been enabled on the device, which is obtained by calling the esp_wifi_start() function after having set the Wi-Fi interface in STA or APSTA mode via the esp_wifi_set_mode() function. From here, while this event's implicit handler will have initialized the Station network interface, at the applicationlevel, in addition to setting the STA_ON flag in the Wi-Fi event group, it's either possible to perform a preliminary Wi-Fi scan to search for the available APs or attempt to directly connect the Station interface to the target AP specified in its base configuration. • If a preliminary Wi-Fi scan is desidered, this can be started by calling the following function: //File esp_wifi_types.h typedef enum //Wi-Fi Scan types { WIFI_SCAN_TYPE_ACTIVE = 0, //Active Wi-Fi scan (scan by sending a probe request) WIFI_SCAN_TYPE_PASSIVE, //Passive Wi-Fi scan (scan by waiting for a beacon } wifi_scan_type_t; frame without explicitly sending a probe request) typedef struct { uint32_t min; uint32_t max; } wifi_active_scan_time_t; //Active scan time per Wi-Fi channel //The minimum active scan time per Wi-Fi channel (default = 120ms) //The maximum active scan time per Wi-Fi channel (default = 120ms, must be <=1500ms) typedef struct { wifi_active_scan_time_t active; uint32_t passive; } wifi_scan_time_t; ESP-IDF Wi-Fi Stack //Scan time per Wi-Fi channel //Active scan time per Wi-Fi channel //Passive scan time per Wi-Fi channel (must be <=1500ms) Wi-Fi Events Specific Handlers Page 27 typedef struct { uint8_t* ssid; uint8_t* bssid; uint8_t channel; //Wi-Fi Scan configuration //Whether to scan for an AP with a specific SSID only //Whether to scan for an AP with a specific BSSID only //Whether to scan on a specific Wi-Fi channel only (1-13) or perform an all-channel scan (0, default) bool show_hidden; //Whether to include the APs with a hidden SSID in their Wi-Fi beacon frames in the scan results wifi_scan_type_t scan_type; //The type of the Wi-Fi scan to perform (active or passive) wifi_scan_time_t scan_time; //The scan time for each Wi-Fi channel } wifi_scan_config_t; esp_err_t esp_wifi_scan_start(const wifi_scan_config_t* scan_conf, bool block) From here, all that is needed to perform an active all-channel Wi-Fi scan with the default scan times, is to initialize the entire wifi_scan_config_t struct to "0", and the function itself should be used in its nonblocking version (block = false), since once the Wi-Fi scan is complete the SYSTEM_EVENT_SCAN_DONE event will be raised by the Wi-Fi stack, from whose specific handler it is possible to check the scan results. • If instead the Station interface should attempt to directly connect to the target AP specified in its base configuration, this can be done by calling the following function: //File esp_wifi.h esp_err_t esp_wifi_connect(void) ESP-IDF Wi-Fi Stack Wi-Fi Events Specific Handlers Page 28 This function implicitly performs an active all-channel Wi-Fi scan for the available APs without triggering the SYSTEM_EVENT_SCAN_DONE event where, if at the end of the scan the target AP specified in the Station base configuration has been found, a connection attempt will be performed (where the SYSTEM_EVENT_STA_CONNECTED event will be raised in case of success), otherwise if APs with hidden SSIDs have been found, the device will attempt to directly connect to each of them, and lastly if the target AP was not found a SYSTEM_EVENT_STA_DISCONNECTED event will be raised by the Wi-Fi stack. void wifi_STA_START_handler() { wifi_scan_config_t scan_config = {0}; } //Preliminary Wi-Fi Scan configuration xEventGroupSetBits(wifi_event_group,STA_ON);//Set the STA_ON flag if(WIFI_STATION_PRELIMINARY_SCAN) //If performing a preliminary Wi-Fi scan ESP_ERROR_CHECK(esp_wifi_scan_start(&scan_config,false)); else //Otherwise if attempting to ESP_ERROR_CHECK(esp_wifi_connect()); directly connect the Station return; interface to its target AP SYSTEM_EVENT_STA_STOP This event may be raised both because the Station interface was disabled intentionally by calling the esp_wifi_stop() function (we'll see later), or due to a fatal error in the Wi-Fi stack, and in addition to clearing the STA_ON flag in the Wi-Fi event group, should the disabling have occured unintentionally, as an error recovery attempt it is possible to try to re-enable the Station interface by calling the esp_wifi_start() function. Also note that the handling of errors that might occur in the application's logic due to the disabling of the Station interface is left entirely to the Driver Module. void wifi_STA_STOP_handler() { xEventGroupClearBits(wifi_event_group,STA_ON); //Clear the STA_ON flag if(/* unintentional */) //If the disabling was unintentional, ESP_ERROR_CHECK(esp_wifi_start()); try to reenable the Station interface return; } SYSTEM_EVENT_SCAN_DONE This event is raised after the Wi-Fi stack completes a Wi-Fi scan requested through the esp_wifi_scan_start() function, and from here if the scan was completed successfully (info->status == ESP_OK) and at least one AP was found (info->number > 0), to retrieve the information on the APs that were found in the scan, in addition to allocating the dynamic memory required to store it, the following function must be called: //File esp_wifi.h typedef struct //Information (record) on an AP that was found in the Wi-Fi scan { uint8_t ssid[33]; //AP SSID uint8_t bssid[6]; //AP BSSID wifi_auth_mode_t authmode; //AP Authmode uint8_t primary; //AP (primary) Wi-Fi channel int8_t rssi; //RSSI with the AP … } wifi_ap_record_t; ESP-IDF Wi-Fi Stack Wi-Fi Events Specific Handlers Page 29 esp_err_t esp_wifi_scan_get_ap_records(uint16_t* ap_num, wifi_ap_record_t* ap_info) From here, by parsing the records of the APs that were found in the scan and by applying a user's custom criteria, if a suitable AP to connect to is found, if it's not the target AP specified in the Station base configuration, such configuration should be updated with the AP's information, and then a connection attempt should be performed by using the esp_wifi_connect() function described earlier, while in all other cases, since no suitable AP to connect was found, a new Wi-Fi scan should be scheduled after a defined time interval to search again for an AP to connect to. void wifi_SCAN_DONE_handler(system_event_sta_scan_done_t* info) { wifi_scan_config_t scan_config = {0}; //Configuration of the Wi-Fi scan to perform should no suitable AP to connect to be found wifi_ap_record_t* ap_list = 0; //Used to dynamically store the found APs' records uint16_t ap_num = info->number; //Number of APs that were found in the Wi-Fi scan if((!info->status)&&ap_num) //If the Wi-Fi scan completed successfully { and at least one AP was found //Allocate the dynamic memory required to store the AP records ap_list = (wifi_ap_record_t*)malloc(ap_num*sizeof(wifi_ap_record_t)); //Retrieve the AP records from the Wi-Fi stack ESP_ERROR_CHECK(wifi_scan_get_ap_records(&ap_num,ap_list)); /* Parse the AP records for a suitable AP to connect the Station interface to */ if(/* a suitable AP to connect the Station interface to was found */) { if(/* the suitable AP differs from the Station target AP */) /* Update the Station base configuration with the information of the AP */ ESP_ERROR_CHECK(esp_wifi_connect()); } else //If no suitable AP to connect to was found, perform { another Wi-Fi scan after a defined interval vTaskDelay(WIFI_STATION_SCAN_RETRY_INTERVAL/portTICK_PERIOD_MS); ESP_ERROR_CHECK(esp_wifi_scan_start(&scan_config,false)); } free(ap_list); //Release the dynamic memory used to store the APs records } else //If the Wi-Fi scan returned an error or no APs were found, { perform another Wi-Fi scan after a defined interval vTaskDelay(WIFI_STATION_SCAN_RETRY_INTERVAL/portTICK_PERIOD_MS); ESP_ERROR_CHECK(esp_wifi_scan_start(&scan_config,false)); } return; } ESP-IDF Wi-Fi Stack Wi-Fi Events Specific Handlers Page 30 SYSTEM_EVENT_STA_CONNECTED This event is raised once the Station interface successfully connects to the AP specified in its base configuration via the esp_wifi_connect() function, and while this event's implicit handler, if not previously manually disabled, will have started the Station DHCP client to request a dynamic IP configuration for the interface, in the application-level handler, in addition to setting the STA_CONN flag in the Wi-Fi event group, the device's Station NoIP driver components, i.e. the driver components that require the device to be connected to an AP, can be started. void wifi_STA_CONNECTED_handler(system_event_sta_connected_t* info) { xEventGroupSetBits(wifi_event_group,STA_CONN); //Set the STA_CONN flag startStationNoIPDrivers(); //Start Station NoIP driver components return; } SYSTEM_EVENT_STA_DISCONNECTED This event is raised if the Station interface disconnects from its AP for any reason or if the esp_wifi_connect() function fails to connect the Station interface to the AP specified in its base configuration, where the two circumstances can be discriminated by checking and appropriately managing the STA_CONN flag in the Wi-Fi event group. From here, in addition to clearing the STA_CONN flag in the Wi-Fi event group if the Station interface disconnected from its AP, at the application-level, also based on the reason (info->reason) for the disconnection, it's possible to perform error recovery attempts consisting in either trying to re-connect the Station interface to the AP by calling the esp_wifi_connect() function or performing a Wi-Fi scan to search for a backup AP to fall back to, and note that again the handling of errors that might occur in the application's logic due to the Station interface becoming disconnected is left entirely to the Driver Module. void wifi_STA_DISCONNECTED_handler(system_event_sta_disconnected_t* info) { EventBits_t eventbits; //Used to check the flags in the Wi-Fi event group //If the STA_CONN flag is set, the Station interface disconnected from its AP if((eventbits = xEventGroupGetBits(wifi_event_group))>>1)&1) xEventGroupClearBits(wifi_event_group,STA_CONN); //Otherwise, the esp_wifi_connect() function failed to connect the Station interface to the AP specified in its base configuration if(/* unintentional */) { /* Error recovery attempts (try to re-connect the Station interface by calling the esp_wifi_connect() function or perform a Wi-Fi scan to search for an AP to fall back to */ } return; } ESP-IDF Wi-Fi Stack Wi-Fi Events Specific Handlers Page 31 SYSTEM_EVENT_STA_GOT_IP This event is raised if a Station interface which is connected to an AP obtains an IP configuration, which as discussed before can be retrieved both dynamically from its DHCP client or by previously applying a custom static IP configuration to the interface in the Wi-Fi Initializer Function. From here, while this event's implicit handler will have updated the Station IP configuration, in the applicationlevel handler, in addition to setting the STA_GOTIP flag in the Wi-Fi event group, the device Station IP driver components, i.e. the driver components that require a device's Station interface to be connected to an AP and have an IP configuration set, can be started. void wifi_STA_GOT_IP_handler(system_event_sta_got_ip_t* info) { xEventGroupSetBits(wifi_event_group,STA_GOTIP); //Set the STA_GOTIP flag startStationIPDrivers(); //Start Station IP driver components return; } SYSTEM_EVENT_STA_LOST_IP This event is raised should the lease time of the Station interface dynamic IP configuration expire, which also implies that its DHCP client failed to renew or otherwise retrieve a new IP configuration for the interface. From here, while this event's implicit handler will have reset the Station interface IP configuration, in the application-level handler, other than clearing the STA_GOTIP flag in the Wi-Fi event group, no further action is required, where again the handling of errors that might occur in the application's logic due to the Station interface having no longer an IP configuration set is left entirely to the Driver Module. void wifi_STA_LOST_IP_handler() { xEventGroupClearBits(wifi_event_group,STA_GOTIP); return; } //Clear the STA_GOTIP flag SYSTEM_EVENT_STA_AUTHMODE_CHANGE This event is raised should the AP the Station interface is connected to change its authentication protocol, where note that since this event's implicit handler performs no action this will cause the Station interface to eventually disconnect from its AP. From here in the application-level handler, supposing that the new authentication protocol is supported and the same password is used, it is possible to attempt to reconnect the Station interface to its AP after disconnecting from it, which can be obtained by calling the following function: //File esp_wifi.h esp_err_t esp_wifi_disconnect(void) Once the Station interface has disconnected from its AP, supposing that no reconnection attempts or a Wi-Fi scan fallback is performed in the SYSTEM_EVENT_STA_DISCONNECTED event specific handler, it is possible to attempt to reconnect the interface to its AP by using the esp_wifi_connect() function discussed previously. ESP-IDF Wi-Fi Stack Wi-Fi Events Specific Handlers Page 32 It should also be noted that, in the specific case the AP switched to no authentication (open), if a reconnection attempt is desired the password in the Station base configuration must be cleared beforehand. void wifi_STA_AUTHMODE_CHANGE_handler(system_event_sta_authmode_change_t* info) { wifi_config_t sta_config; //Possibly used to reset the password in the Station base configuration to allow it to reconnect to its AP should it have switched to an open authentication //If the AP the Station interface is connected to switched to an open authentication and a reconnection attempt is desired if((info->new_mode == WIFI_AUTH_OPEN)&&(/* is desired */)) { //Retrieve the Station base configuration (we'll see in more detail later) ESP_ERROR_CHECK(esp_wifi_get_config(ESP_IF_WIFI_STA,&sta_config)); //Reset the password in the Station base configuration sta_config.sta.password[0] = '\0'; //Update the password in the Station base configuration ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA,&sta_config)); } //Disconnect the Station interface from its AP ESP_ERROR_CHECK(esp_wifi_disconnect()); //Attempt to reconnect the Station interface to its AP (supposing such attempt is not already performed in the SYSTEM_EVENT_STA_DISCONNECTED event specific handler) ESP_ERROR_CHECK(esp_wifi_connect()); return; } SoftAP Interface Events SYSTEM_EVENT_AP_START This event is raised after the SoftAP interface has been enabled on the device, which is obtained by calling the esp_wifi_start() function after having set the Wi-Fi interface in AP or APSTA mode via the esp_wifi_set_mode() function. From here, while this event's implicit handler will have initialized the SoftAP network interface and, if not previously manually disabled, started its DHCP server, at the application-level, in addition to setting the SOFTAP_ON flag in the Wi-Fi event group, the device's Station SoftAP driver components, i.e. the driver components that require the SoftAP interface to be enabled, can be started. void wifi_AP_START_handler() { xEventGroupSetBits(wifi_event_group,SOFTAP_ON); startSoftAPDrivers(); return; } ESP-IDF Wi-Fi Stack //Set the SOFTAP_ON flag //Start SoftAP driver components Wi-Fi Events Specific Handlers Page 33 SYSTEM_EVENT_AP_STOP This event may be raised both because the SoftAP interface was disabled intentionally by calling the esp_wifi_stop() function (we'll see later), or due to a fatal error in the Wi-Fi stack, and in addition to clearing the SOFTAP_ON flag in the Wi-Fi event group, should the disabling have occured unintentionally, as an error recovery attempt it is possible to try to re-enable the SoftAP interface by calling the esp_wifi_start() function. Also note that the handling of errors that might occur in the application's logic due to the disabling of the SoftAP interface is left entirely to the Driver Module. void wifi_AP_STOP_handler() { xEventGroupClearBits(wifi_event_group,SOFTAP_ON); //Clear the SOFTAP_ON flag if(/* unintentional */) //If the disabling was unintentional, ESP_ERROR_CHECK(esp_wifi_start()); try to reenable the SoftAP interface return; } SYSTEM_EVENT_AP_STACONNECTED This event is raised when a new client successfully connects to the SoftAP interface, and apart from setting the SOFTAP_CLI flag in the Wi-Fi event group if it was not previously set (i.e. if it's the first client to connect to the SoftAP interface), no other action in required in the application-level handler of this event. void wifi_AP_STACONNECTED_handler(system_event_ap_staconnected_t* info) { EventBits_t eventbits; //Used to check the flags in the Wi-Fi event group //If the SOFTAP_CLI flag is not set in the Wi-Fi event group (i.e. this is the first client to connect to the SoftAP interface), set it if(!(((eventbits = xEventGroupGetBits(wifi_event_group))>>4)&1)) xEventGroupSetBits(wifi_event_group,SOFTAP_CLI); return; } SYSTEM_EVENT_AP_STADISCONNECTED This event is raised when a client disconnects from the SoftAP interface, and other than clearing the SOFTAP_CLI flag in the Wi-Fi event group if it was the last child to disconnect from the node (which can be determined by using the esp_wifi_ap_get_sta_list() function that will be discussed in detail later), no other action is required in the application-level handler of this event. void wifi_AP_STADISCONNECTED_handler(system_event_ap_stadisconnected_t* info) { wifi_sta_list_t clients; //Used to store information on the clients connected to the SoftAP interface //Retrieve information on the clients connected to the SoftAP interface ESP_ERROR_CHECK(esp_wifi_ap_get_sta_list(&clients)); //If no client is connected to the SoftAP interface, clear the SOFTAP_CLI flag if(clients.num == 0) xEventGroupClearBits(wifi_event_group,SOFTAP_CLI); return; } ESP-IDF Wi-Fi Stack Wi-Fi Events Specific Handlers Page 34 Driver Module Following our previous analysis of the Wi-Fi Events Specific Handlers, depending on their category the components constituting the Driver Module should be started: • The Station NoIP Driver Components, i.e. the driver components that require the device's Station interface to be connected to an access point, as soon as such connection is established (SYSTEM_EVENT_STA_CONNECTED). • The Station IP Driver Components, i.e. the driver components that require the device's Station interface to be connected to an access point and to have an IP configuration set, as soon as the Station interface acquires an IP configuration (SYSTEM_EVENT_STA_GOT_IP). • The SoftAP Driver Components, i.e. the driver components that require the device's SoftAP interface to be enabled, as soon as it is (SYSTEM_EVENT_AP_START), components that generally may also require the interface to have clients connected, which can be checked by polling the SOFTAP_CLI flag in the Wi-Fi event group. Note that, since the events that start the driver components can generally be raised multiple times during the application's execution, it's necessary for the setup module to keep track of which driver components are currently being executed to avoid creating undesidered duplicate tasks of the same components, and this can be obtained by providing in the Wi-Fi event group a flag for each driver component representing whether it is currently running or not, as was shown previously in the code premises section. From here the actual semantics of the synchronization of the execution of the driver module components is left to the programmer, where a simple yet blunt solution is given, in the specific handlers of events that start driver components, by previously checking and killing any existing tasks relative to the components they would start before actually creating them again, which can be obtained as follows: void stationNoIPDriverComponent_A() { /* Station NOIP driver component A logic */ … //Clear this driver component's execution flag in the Wi-Fi event group xEventGroupClearBits(wifi_event_group,WIFI_DRIVER_STATION_NOIP_A); vTaskDelete(NULL); //Delete this driver component's task } void stationNoIPDriverComponent_B() { /* Station NOIP driver component B logic */ … //Clear this driver component's execution flag in the Wi-Fi event group xEventGroupClearBits(wifi_event_group,WIFI_DRIVER_STATION_NOIP_B); vTaskDelete(NULL); //Delete this driver component's task } … ESP-IDF Wi-Fi Stack Driver Module Page 35 /* Called at the end of the SYSTEM_EVENT_STA_CONNECTED event specific handler */ void startStationNOIPDrivers() { EventBits_t eventbits; //Used to check the flags in the Wi-Fi event group static TaskHandle_t componentA_handler; //ComponentA driver task handler static TaskHandle_t componentB_handler; //ComponentB driver task handler /* For each driver component, if its relative task is running, kill it and set its flag in the Wi-Fi event group before starting its task */ if(((eventbits = xEventGroupGetBits(wifi_event_group))>> WIFI_DRIVER_STATION_NOIP_A)&1) vTaskDelete(componentA_handler); xEventGroupSetBits(wifi_event_group,WIFI_DRIVER_STATION_NOIP_A); xTaskCreate(stationNoIPDriverComponent_A,"StationNoIPdriverA", 4096,NULL,10,&componentA_handler); if(((eventbits = xEventGroupGetBits(wifi_event_group))>> WIFI_DRIVER_STATION_NOIP_B)&1) vTaskDelete(componentB_handler); xEventGroupSetBits(wifi_event_group,WIFI_DRIVER_STATION_NOIP_B); xTaskCreate(stationNoIPDriverComponent_A,"StationNoIPdriverA", 4096,NULL,10,&componentB_handler); } Also note that, as with all networking applications, the driver components should include routines for handling errors that may occur during their execution, which can be triggered by checking the return values of the Wi-Fi API functions used and/or the appropriate flags in the Wi-Fi event group, whose values as we have seen are asynchronously updated by the appropriate event specific handlers during the application's execution. ESP-IDF Wi-Fi Stack Driver Module Page 36 Wi-Fi API for the Driver Module Listed below are the functions offered by the ESP-IDF Wi-FI API organized into categories that can be used for developing the driver module of a Wi-Fi application: Station-specific API • Retrieve information on the AP the Station interface is connected to //File esp_wifi.h esp_err_t esp_wifi_sta_get_ap_info(wifi_ap_record_t* apinfo) void staAppDriver() { … wifi_ap_record_t apinfo; //Used to store information on the AP the Station interface is connected to ESP_ERROR_CHECK(esp_wifi_sta_get_ap_info(&apinfo)); … } SoftAP-specific API • Retrieve information on the clients connected to the SoftAP interface //File esp_wifi_types.h #define ESP_WIFI_MAX_CONN_NUM (10) //Maximum number of clients that can be simultaneously connected to the SoftAP interface typedef struct //Information on a client connected to the SoftAP interface { uint8_t mac[6]; //MAC address of the client int8_t rssi; //SoftAP's RSSI with the client … } wifi_sta_info_t; typedef struct //Information on the clients connected to the SoftAP interface { wifi_sta_info_t sta[ESP_WIFI_MAX_CONN_NUM]; //Client-specific information int num; //Number of clients connected to the SoftAP interface … } wifi_sta_list_t; ESP-IDF Wi-Fi Stack Driver Module Page 37 //File esp_wifi.h esp_err_t esp_wifi_ap_get_sta_list(wifi_sta_list_t* stalist) void softAPAppDriver() { … wifi_sta_info_t clients; //Used to store information on the clients connected to the SoftAP interface ESP_ERROR_CHECK(esp_wifi_ap_get_sta_list(&clients)); … } • Deauthenticate one or more clients from the SoftAP interface //File esp_wifi.h esp_err_t esp_wifi_deauth_sta(uint16_t aid) void softAPAppDriver() { … ESP_ERROR_CHECK(esp_wifi_deauth_sta(CLIENT_AID)); //Deauthenticate a client ESP_ERROR_CHECK(esp_wifi_deauth_sta(0)); //Deauthenticate all clients … } ESP-IDF Wi-Fi Stack Driver Module Page 38 Wi-Fi Configuration Retrieval API The following API allows to retrieve the configuration of the Wi-Fi stack on a device: • Retrieve the Wi-Fi interface modes (or sub-interfaces) selected for use //File esp_wifi.h esp_err_t esp_wifi_get_mode(wifi_mode_t* wifi_mode) void appDriver() { … wifi_mode_t wifi_mode; //Used to store the Wi-Fi interface modes selected for use (STA, AP or APSTA) ESP_ERROR_CHECK(esp_wifi_get_mode(&wifi_mode)); … } • Retrieve an interface mode's base configuration //File esp_wifi.h esp_err_t esp_wifi_get_config(wifi_interface_t ifx_mode, wifi_config_t* base_conf) ESP-IDF Wi-Fi Stack Driver Module Page 39 void appDriver() { … wifi_config_t sta_config; wifi_config_t softap_config; //Used to store an interface mode's base configuration ESP_ERROR_CHECK(esp_wifi_get_config(ESP_IF_WIFI_STA,&sta_config); ESP_ERROR_CHECK(esp_wifi_get_config(ESP_IF_WIFI_AP,&softap_conf); … } • Retrieve an interface mode's MAC address //File esp_wifi.h esp_err_t esp_wifi_get_mac(wifi_interface_t ifx_mode, uint8_t[] mac) void appDriver() { … uint8_t mac[6]; //Used to store an interface mode's MAC address ESP_ERROR_CHECK(esp_wifi_get_mac(ESP_IF_WIFI_STA,&mac));//Station MAC address … } • Retrieve the Power Saving Mode used on the Station interface //File esp_wifi.h esp_err_t esp_wifi_get_ps(wifi_ps_type_t* ps_mode) ESP-IDF Wi-Fi Stack Driver Module Page 40 void appDriver() { … wifi_ps_type_t sta_psmode; //Used to store the power saving mode used on the Station interface ESP_ERROR_CHECK(esp_wifi_get_ps(&sta_psmode); … } • Retrieve an interface mode's IP configuration //File tcpip_adapter.h esp_err_t tcpip_adapter_get_ip_info(tcpip_adapter_if_t tcpip_if, tcpip_adapter_ip_info_t* ip_info) void appDriver() { … tcpip_adapter_ip_info_t softap_ipinfo; //Used to store an interface mode's IP configuration ESP_ERROR_CHECK(tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_AP,&ipinfo)); … } • Retrieve the address of an interface mode's DNS server //File tcpip_adapter.h esp_err_t tcpip_adapter_get_dns_info(tcpip_adapter_if_t tcpip_if, tcpip_adapter_dns_type_t type, tcpip_adapter_dns_info_t* addr) ESP-IDF Wi-Fi Stack Driver Module Page 41 void appDriver() { … tcpip_adapter_dns_type_t dns_addr1; tcpip_adapter_dns_type_t dns_addr2; //Used to store the address of an interface mode's DNS server ESP_ERROR_CHECK(tcpip_adapter_get_dns_info(TCPIP_ADAPTER_IF_AP, //SoftAP TCPIP_ADAPTER_DNS_MAIN, Primary &dns_addr1)); DNS Server ESP_ERROR_CHECK(tcpip_adapter_get_dns_info(TCPIP_ADAPTER_IF_STA, //Station TCPIP_ADAPTER_DNS_BACKUP,Second. &dns_addr2)); DNS Server … } ESP-IDF Wi-Fi Stack Driver Module Page 42 Wi-Fi Stop API • Disable the Wi-Fi Interface //File esp_wifi.h esp_err_t esp_wifi_stop(void) Calling this function causes the disabling of the Wi-Fi interface modes that were selected for use via the esp_wifi_set_mode() function, causing the the SYSTEM_EVENT_STA_STOP and/or the SYSTEM_EVENT_AP_STOP events to be raised accordingly. void appDriver() { … ESP_ERROR_CHECK(esp_wifi_stop()); … } • Deinitialize the Wi-Fi Stack //File esp_wifi.h esp_err_t esp_wifi_deinit(void) This function, which can be called only if the Wi-Fi interface is disabled, causes the full release of the resources allocated to the device's Wi-Fi stack, and thus its complete deinitialization. void appDriver() { … ESP_ERROR_CHECK(esp_wifi_deinit()); … } ESP-IDF Wi-Fi Stack Driver Module Page 43
Source Exif Data:
File Type : PDF File Type Extension : pdf MIME Type : application/pdf PDF Version : 1.7 Linearized : No Page Mode : UseNone Has XFA : No Page Count : 45 XMP Toolkit : XMP Core 4.4.0-soda Format : application/pdf Creator Tool : PDF Architect 6 Modify Date : 2018:11:27 09:09:30+01:00 Create Date : 2018:11:27 07:54:52+01:00 Title : ESP-IDF Wi-Fi Stack Pratical Guide Creator : Riccardo Bertini Producer : Nuance PDF Create Author : Riccardo BertiniEXIF Metadata provided by EXIF.tools