Add documentation on threading issues with WiFi.onEvent() to examples (#8081)
* Compile error if CONFIG_FREERTOS_HZ != 1000 * add a check at the CMake level, per feedback * fix a punctuation glitch * Remove `_Static_assert` per feedback * add documentation on threading issues with WiFi.onEvent() * more comments * thin out comments, add docs * Update WiFiProv.ino merge conflict issue fixed * Added the CLK type and MAC from eFuse to Ethernet begin * Fixed the order and arguments on the Ethernet begin function --------- Co-authored-by: Pedro Minatel <pedro.minatel@espressif.com> Co-authored-by: Pedro Minatel <pminatel@gmail.com>
This commit is contained in:
parent
7ecde87701
commit
67c027ce17
15 changed files with 148 additions and 33 deletions
|
|
@ -50,6 +50,102 @@ Common API
|
|||
|
||||
Here are the common APIs that are used for both modes, AP and STA.
|
||||
|
||||
onEvent (and removeEvent)
|
||||
*************************
|
||||
|
||||
Registers a caller-supplied function to be called when WiFi events
|
||||
occur. Several forms are available.
|
||||
|
||||
Function pointer callback taking the event ID:
|
||||
|
||||
.. code-block:: arduino
|
||||
|
||||
typedef void (*WiFiEventCb)(arduino_event_id_t);
|
||||
wifi_event_id_t onEvent(WiFiEventCb, arduino_event_id_t = ARDUINO_EVENT_MAX);
|
||||
|
||||
Function pointer callback taking an event-ID-and-info struct:
|
||||
|
||||
.. code-block:: arduino
|
||||
|
||||
typedef struct{
|
||||
arduino_event_id_t event_id;
|
||||
arduino_event_info_t event_info;
|
||||
} arduino_event_t;
|
||||
|
||||
typedef void (*WiFiEventSysCb)(arduino_event_t *);
|
||||
wifi_event_id_t onEvent(WiFiEventSysCb, arduino_event_id_t = ARDUINO_EVENT_MAX);
|
||||
|
||||
Callback using ``std::function`` taking event ID and info separately:
|
||||
|
||||
.. code-block:: arduino
|
||||
|
||||
typedef std::function<void(arduino_event_id_t, arduino_event_info_t)> WiFiEventFuncCb;
|
||||
wifi_event_id_t onEvent(WiFiEventFuncCb, arduino_event_id_t = ARDUINO_EVENT_MAX);
|
||||
|
||||
A similar set of functions are available to remove callbacks:
|
||||
|
||||
.. code-block:: arduino
|
||||
|
||||
void removeEvent(WiFiEventCb, arduino_event_id_t = ARDUINO_EVENT_MAX);
|
||||
void removeEvent(WiFiEventSysCb, arduino_event_id_t = ARDUINO_EVENT_MAX);
|
||||
void removeEvent(wifi_event_id_t = ARDUINO_EVENT_MAX);
|
||||
|
||||
In all cases, the subscribing function accepts an optional event type to
|
||||
invoke the callback only for that specific event; with the default
|
||||
``ARDUINO_EVENT_MAX``, the callback will be invoked for all WiFi events.
|
||||
|
||||
Any callback function is given the event type in a parameter.
|
||||
Some of the possible callback function formats also take an
|
||||
``arduino_event_info_t`` (or use ``arduino_event_t`` which includes both
|
||||
ID and info) which is a union of structs with additional information
|
||||
about different event types.
|
||||
|
||||
See
|
||||
`WiFiGeneric.h <https://github.com/espressif/arduino-esp32/blob/master/libraries/WiFi/src/WiFiGeneric.h>`_
|
||||
for the list of event types and "info" substructures, and also see a full
|
||||
example of event handling: `events example`_.
|
||||
|
||||
.. warning::
|
||||
|
||||
Event callback functions are invoked on a separate
|
||||
`thread <https://en.wikipedia.org/wiki/Thread_(computing)>`_
|
||||
(`FreeRTOS task <https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/freertos_idf.html#tasks>`_)
|
||||
independent of the main application thread that runs ``setup()`` and
|
||||
``loop()``. Callback functions must therefore be
|
||||
`thread-safe <https://en.wikipedia.org/wiki/Thread_safety>`_;
|
||||
they must not access shared/global variables directly without locking,
|
||||
and must only call similarly thread-safe functions.
|
||||
|
||||
Some core operations like ``Serial.print()`` are thread-safe but many
|
||||
functions are not. Notably, ``WiFi.onEvent()`` and ``WiFi.removeEvent()``
|
||||
are not thread-safe and should never be invoked from a callback thread.
|
||||
|
||||
setHostname (and getHostname)
|
||||
*****************************
|
||||
|
||||
Sets the name the DHCP client uses to identify itself. In a typical network
|
||||
setup this will be the name that shows up in the Wi-Fi router's device list.
|
||||
The hostname must be no longer than 32 characters.
|
||||
|
||||
.. code-block:: arduino
|
||||
|
||||
setHostname(const char *hostname);
|
||||
|
||||
If the hostname is never specified, a default one will be assigned based
|
||||
on the chip type and MAC address. The current hostname (default or custom)
|
||||
may be retrieved:
|
||||
|
||||
.. code-block:: arduino
|
||||
|
||||
const char *getHostname();
|
||||
|
||||
.. warning::
|
||||
|
||||
The ``setHostname()`` function must be called BEFORE WiFi is started with
|
||||
``WiFi.begin()``, ``WiFi.softAP()``, ``WiFi.mode()``, or ``WiFi.run()``.
|
||||
To change the name, reset WiFi with ``WiFi.mode(WIFI_MODE_NULL)``,
|
||||
then proceed with ``WiFi.setHostname(...)`` and restart WiFi from scratch.
|
||||
|
||||
useStaticBuffers
|
||||
****************
|
||||
|
||||
|
|
@ -552,6 +648,8 @@ To see how to use the ``WiFiScan``, take a look at the ``WiFiScan.ino`` example
|
|||
Examples
|
||||
--------
|
||||
|
||||
`Complete list of WiFi examples <https://github.com/espressif/arduino-esp32/tree/master/libraries/WiFi/examples>`_.
|
||||
|
||||
.. _ap example:
|
||||
|
||||
Wi-Fi AP Example
|
||||
|
|
@ -568,5 +666,10 @@ Wi-Fi STA Example
|
|||
.. literalinclude:: ../../../libraries/WiFi/examples/WiFiClient/WiFiClient.ino
|
||||
:language: arduino
|
||||
|
||||
References
|
||||
----------
|
||||
.. _events example:
|
||||
|
||||
Wi-Fi Events Example
|
||||
********************
|
||||
|
||||
.. literalinclude:: ../../../libraries/WiFi/examples/WiFiClientEvents/WiFiClientEvents.ino
|
||||
:language: arduino
|
||||
|
|
|
|||
|
|
@ -16,12 +16,14 @@
|
|||
|
||||
static bool eth_connected = false;
|
||||
|
||||
void onEvent(arduino_event_id_t event, arduino_event_info_t info)
|
||||
// WARNING: WiFiEvent is called from a separate FreeRTOS task (thread)!
|
||||
void WiFiEvent(WiFiEvent_t event)
|
||||
{
|
||||
switch (event) {
|
||||
case ARDUINO_EVENT_ETH_START:
|
||||
Serial.println("ETH Started");
|
||||
//set eth hostname here
|
||||
// The hostname must be set after the interface is started, but needs
|
||||
// to be set before DHCP, so set it from the event handler thread.
|
||||
ETH.setHostname("esp32-ethernet");
|
||||
break;
|
||||
case ARDUINO_EVENT_ETH_CONNECTED:
|
||||
|
|
@ -72,11 +74,10 @@ void testClient(const char * host, uint16_t port)
|
|||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
WiFi.onEvent(onEvent);
|
||||
WiFi.onEvent(WiFiEvent); // Will call WiFiEvent() from another thread.
|
||||
ETH.begin();
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
if (eth_connected) {
|
||||
|
|
|
|||
|
|
@ -5,21 +5,23 @@
|
|||
|
||||
#include <ETH.h>
|
||||
|
||||
#define ETH_TYPE ETH_PHY_TLK110
|
||||
#define ETH_ADDR 31
|
||||
#define ETH_MDC_PIN 23
|
||||
#define ETH_MDIO_PIN 18
|
||||
#define ETH_POWER_PIN 17
|
||||
#define ETH_CLK_MODE ETH_CLOCK_GPIO0_IN
|
||||
#define ETH_TYPE ETH_PHY_TLK110
|
||||
#define ETH_ADDR 31
|
||||
#define ETH_MDC_PIN 23
|
||||
#define ETH_MDIO_PIN 18
|
||||
#define ETH_POWER_PIN 17
|
||||
#define ETH_CLK_MODE ETH_CLOCK_GPIO0_IN
|
||||
|
||||
static bool eth_connected = false;
|
||||
|
||||
void onEvent(arduino_event_id_t event, arduino_event_info_t info)
|
||||
// WARNING: WiFiEvent is called from a separate FreeRTOS task (thread)!
|
||||
void WiFiEvent(WiFiEvent_t event)
|
||||
{
|
||||
switch (event) {
|
||||
case ARDUINO_EVENT_ETH_START:
|
||||
Serial.println("ETH Started");
|
||||
//set eth hostname here
|
||||
// The hostname must be set after the interface is started, but needs
|
||||
// to be set before DHCP, so set it from the event handler thread.
|
||||
ETH.setHostname("esp32-ethernet");
|
||||
break;
|
||||
case ARDUINO_EVENT_ETH_CONNECTED:
|
||||
|
|
@ -70,7 +72,7 @@ void testClient(const char * host, uint16_t port)
|
|||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
WiFi.onEvent(onEvent);
|
||||
WiFi.onEvent(WiFiEvent); // Will call WiFiEvent() from another thread.
|
||||
ETH.begin(ETH_TYPE, ETH_ADDR, ETH_MDC_PIN, ETH_MDIO_PIN, ETH_POWER_PIN, ETH_CLK_MODE);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ bool dimmer_state = true;
|
|||
// But, you can also define custom devices using the 'Device' base class object, as shown here
|
||||
static Device *my_device = NULL;
|
||||
|
||||
// WARNING: sysProvEvent is called from a separate FreeRTOS task (thread)!
|
||||
void sysProvEvent(arduino_event_t *sys_event)
|
||||
{
|
||||
switch (sys_event->event_id) {
|
||||
|
|
@ -105,7 +106,7 @@ void setup()
|
|||
|
||||
RMaker.start();
|
||||
|
||||
WiFi.onEvent(sysProvEvent);
|
||||
WiFi.onEvent(sysProvEvent); // Will call sysProvEvent() from another thread.
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
WiFiProv.beginProvision(WIFI_PROV_SCHEME_SOFTAP, WIFI_PROV_SCHEME_HANDLER_NONE, WIFI_PROV_SECURITY_1, pop, service_name);
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ bool power_state = true;
|
|||
// But, you can also define custom devices using the 'Device' base class object, as shown here
|
||||
static Device *my_device = NULL;
|
||||
|
||||
// WARNING: sysProvEvent is called from a separate FreeRTOS task (thread)!
|
||||
void sysProvEvent(arduino_event_t *sys_event)
|
||||
{
|
||||
switch (sys_event->event_id) {
|
||||
|
|
@ -170,7 +171,7 @@ void setup()
|
|||
|
||||
RMaker.start();
|
||||
|
||||
WiFi.onEvent(sysProvEvent);
|
||||
WiFi.onEvent(sysProvEvent); // Will call sysProvEvent() from another thread.
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
WiFiProv.beginProvision(WIFI_PROV_SCHEME_SOFTAP, WIFI_PROV_SCHEME_HANDLER_NONE, WIFI_PROV_SECURITY_1, pop, service_name);
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ LightSwitch switch_ch2 = {gpio_switch2, false};
|
|||
static Switch *my_switch1 = NULL;
|
||||
static Switch *my_switch2 = NULL;
|
||||
|
||||
// WARNING: sysProvEvent is called from a separate FreeRTOS task (thread)!
|
||||
void sysProvEvent(arduino_event_t *sys_event)
|
||||
{
|
||||
switch (sys_event->event_id) {
|
||||
|
|
@ -160,7 +161,7 @@ void setup()
|
|||
Serial.printf("\nStarting ESP-RainMaker\n");
|
||||
RMaker.start();
|
||||
|
||||
WiFi.onEvent(sysProvEvent);
|
||||
WiFi.onEvent(sysProvEvent); // Will call sysProvEvent() from another thread.
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
WiFiProv.beginProvision(WIFI_PROV_SCHEME_BLE, WIFI_PROV_SCHEME_HANDLER_FREE_BTDM, WIFI_PROV_SECURITY_1, pop, service_name);
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ bool switch_state = true;
|
|||
// fan, temperaturesensor.
|
||||
static Switch *my_switch = NULL;
|
||||
|
||||
// WARNING: sysProvEvent is called from a separate FreeRTOS task (thread)!
|
||||
void sysProvEvent(arduino_event_t *sys_event)
|
||||
{
|
||||
switch (sys_event->event_id) {
|
||||
|
|
@ -107,7 +108,7 @@ void setup()
|
|||
|
||||
RMaker.start();
|
||||
|
||||
WiFi.onEvent(sysProvEvent);
|
||||
WiFi.onEvent(sysProvEvent); // Will call sysProvEvent() from another thread.
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
WiFiProv.beginProvision(WIFI_PROV_SCHEME_SOFTAP, WIFI_PROV_SCHEME_HANDLER_NONE,
|
||||
WIFI_PROV_SECURITY_1, pop, service_name);
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ SemaphoreHandle_t ftmSemaphore;
|
|||
bool ftmSuccess = true;
|
||||
|
||||
// FTM report handler with the calculated data from the round trip
|
||||
// WARNING: This function is called from a separate FreeRTOS task (thread)!
|
||||
void onFtmReport(arduino_event_t *event) {
|
||||
const char * status_str[5] = {"SUCCESS", "UNSUPPORTED", "CONF_REJECTED", "NO_RESPONSE", "FAIL"};
|
||||
wifi_event_ftm_report_t * report = &event->event_info.wifi_ftm_report;
|
||||
|
|
@ -62,7 +63,7 @@ void setup() {
|
|||
// Create binary semaphore (initialized taken and can be taken/given from any thread/ISR)
|
||||
ftmSemaphore = xSemaphoreCreateBinary();
|
||||
|
||||
// Listen for FTM Report events
|
||||
// Will call onFtmReport() from another thread with FTM Report events.
|
||||
WiFi.onEvent(onFtmReport, ARDUINO_EVENT_WIFI_FTM_REPORT);
|
||||
|
||||
// Connect to AP that has FTM Enabled
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ String wpspin2string(uint8_t a[]){
|
|||
return (String)wps_pin;
|
||||
}
|
||||
|
||||
// WARNING: WiFiEvent is called from a separate FreeRTOS task (thread)!
|
||||
void WiFiEvent(WiFiEvent_t event, arduino_event_info_t info){
|
||||
switch(event){
|
||||
case ARDUINO_EVENT_WIFI_STA_START:
|
||||
|
|
@ -103,7 +104,7 @@ void setup(){
|
|||
Serial.begin(115200);
|
||||
delay(10);
|
||||
Serial.println();
|
||||
WiFi.onEvent(WiFiEvent);
|
||||
WiFi.onEvent(WiFiEvent); // Will call WiFiEvent() from another thread.
|
||||
WiFi.mode(WIFI_MODE_STA);
|
||||
Serial.println("Starting WPS");
|
||||
wpsInitConfig();
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ void onButton(){
|
|||
delay(100);
|
||||
}
|
||||
|
||||
// WARNING: WiFiEvent is called from a separate FreeRTOS task (thread)!
|
||||
void WiFiEvent(WiFiEvent_t event){
|
||||
switch(event) {
|
||||
case ARDUINO_EVENT_WIFI_AP_START:
|
||||
|
|
@ -112,7 +113,7 @@ void WiFiEvent(WiFiEvent_t event){
|
|||
void setup() {
|
||||
Serial.begin(115200);
|
||||
pinMode(0, INPUT_PULLUP);
|
||||
WiFi.onEvent(WiFiEvent);
|
||||
WiFi.onEvent(WiFiEvent); // Will call WiFiEvent() from another thread.
|
||||
Serial.print("ESP32 SDK: ");
|
||||
Serial.println(ESP.getSdkVersion());
|
||||
Serial.println("Press the button to select the next mode");
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@
|
|||
const char* ssid = "your-ssid";
|
||||
const char* password = "your-password";
|
||||
|
||||
|
||||
// WARNING: This function is called from a separate FreeRTOS task (thread)!
|
||||
void WiFiEvent(WiFiEvent_t event)
|
||||
{
|
||||
Serial.printf("[WiFi-event] event: %d\n", event);
|
||||
|
|
@ -132,6 +132,7 @@ void WiFiEvent(WiFiEvent_t event)
|
|||
default: break;
|
||||
}}
|
||||
|
||||
// WARNING: This function is called from a separate FreeRTOS task (thread)!
|
||||
void WiFiGotIP(WiFiEvent_t event, WiFiEventInfo_t info)
|
||||
{
|
||||
Serial.println("WiFi connected");
|
||||
|
|
@ -148,7 +149,8 @@ void setup()
|
|||
|
||||
delay(1000);
|
||||
|
||||
// Examples of different ways to register wifi events
|
||||
// Examples of different ways to register wifi events;
|
||||
// these handlers will be called from another thread.
|
||||
WiFi.onEvent(WiFiEvent);
|
||||
WiFi.onEvent(WiFiGotIP, WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_GOT_IP);
|
||||
WiFiEventId_t eventID = WiFi.onEvent([](WiFiEvent_t event, WiFiEventInfo_t info){
|
||||
|
|
|
|||
|
|
@ -64,16 +64,15 @@ void wifiConnectedLoop(){
|
|||
delay(9000);
|
||||
}
|
||||
|
||||
// WARNING: WiFiEvent is called from a separate FreeRTOS task (thread)!
|
||||
void WiFiEvent(WiFiEvent_t event){
|
||||
switch(event) {
|
||||
|
||||
case ARDUINO_EVENT_WIFI_AP_START:
|
||||
//can set ap hostname here
|
||||
WiFi.softAPsetHostname(AP_SSID);
|
||||
//enable ap ipv6 here
|
||||
WiFi.softAPenableIpV6();
|
||||
break;
|
||||
|
||||
case ARDUINO_EVENT_WIFI_STA_START:
|
||||
//set sta hostname here
|
||||
WiFi.setHostname(AP_SSID);
|
||||
|
|
@ -106,7 +105,7 @@ void WiFiEvent(WiFiEvent_t event){
|
|||
void setup(){
|
||||
Serial.begin(115200);
|
||||
WiFi.disconnect(true);
|
||||
WiFi.onEvent(WiFiEvent);
|
||||
WiFi.onEvent(WiFiEvent); // Will call WiFiEvent() from another thread.
|
||||
WiFi.mode(WIFI_MODE_APSTA);
|
||||
WiFi.softAP(AP_SSID);
|
||||
WiFi.begin(STA_SSID, STA_PASS);
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ void connectToWiFi(const char * ssid, const char * pwd){
|
|||
// delete old config
|
||||
WiFi.disconnect(true);
|
||||
//register event handler
|
||||
WiFi.onEvent(WiFiEvent);
|
||||
WiFi.onEvent(WiFiEvent); // Will call WiFiEvent() from another thread.
|
||||
|
||||
//Initiate connection
|
||||
WiFi.begin(ssid, pwd);
|
||||
|
|
@ -55,7 +55,7 @@ void connectToWiFi(const char * ssid, const char * pwd){
|
|||
Serial.println("Waiting for WIFI connection...");
|
||||
}
|
||||
|
||||
//wifi event handler
|
||||
// WARNING: WiFiEvent is called from a separate FreeRTOS task (thread)!
|
||||
void WiFiEvent(WiFiEvent_t event){
|
||||
switch(event) {
|
||||
case ARDUINO_EVENT_WIFI_STA_GOT_IP:
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@ This example allows Arduino users to choose either BLE or SOFTAP as the mode of
|
|||
|
||||
### WiFi.onEvent()
|
||||
|
||||
Using this API, users can register to receive WiFi Events and Provisioning Events.
|
||||
This API can be used to register a function to be called from another
|
||||
thread for WiFi Events and Provisioning Events.
|
||||
|
||||
### WiFi.beginProvision()
|
||||
|
||||
|
|
|
|||
|
|
@ -11,13 +11,13 @@ Note: This sketch takes up a lot of space for the app and may not be able to fla
|
|||
#include "WiFiProv.h"
|
||||
#include "WiFi.h"
|
||||
|
||||
// #define USE_SOFT_AP // Uncomment if you want to enforce using Soft AP method instead of BLE
|
||||
|
||||
const char * pop = "abcd1234"; // Proof of possession - otherwise called a PIN - string provided by the device, entered by user in the phone app
|
||||
// #define USE_SOFT_AP // Uncomment if you want to enforce using the Soft AP method instead of BLE
|
||||
const char * pop = "abcd1234"; // Proof of possession - otherwise called a PIN - string provided by the device, entered by the user in the phone app
|
||||
const char * service_name = "PROV_123"; // Name of your device (the Espressif apps expects by default device name starting with "Prov_")
|
||||
const char * service_key = NULL; // Password used for SofAP method (NULL = no password needed)
|
||||
bool reset_provisioned = true; // When true the library will automatically delete previously provisioned data.
|
||||
|
||||
// WARNING: SysProvEvent is called from a separate FreeRTOS task (thread)!
|
||||
void SysProvEvent(arduino_event_t *sys_event)
|
||||
{
|
||||
switch (sys_event->event_id) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue