Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(NetworkEvent lib) refactor network events handling #11115

Draft
wants to merge 7 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions docs/en/api/wifi.rst
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ 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);
wifi_event_id_t onEvent(WiFiEventCb, arduino_event_id_t = ARDUINO_EVENT_ANY);

Function pointer callback taking an event-ID-and-info struct:

Expand All @@ -73,26 +73,26 @@ Function pointer callback taking an event-ID-and-info struct:
} arduino_event_t;

typedef void (*WiFiEventSysCb)(arduino_event_t *);
wifi_event_id_t onEvent(WiFiEventSysCb, arduino_event_id_t = ARDUINO_EVENT_MAX);
wifi_event_id_t onEvent(WiFiEventSysCb, arduino_event_id_t = ARDUINO_EVENT_ANY);

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);
wifi_event_id_t onEvent(WiFiEventFuncCb, arduino_event_id_t = ARDUINO_EVENT_ANY);

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);
void removeEvent(WiFiEventCb, arduino_event_id_t = ARDUINO_EVENT_ANY);
void removeEvent(WiFiEventSysCb, arduino_event_id_t = ARDUINO_EVENT_ANY);
void removeEvent(wifi_event_id_t = ARDUINO_EVENT_ANY);

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 Wi-Fi events.
``ARDUINO_EVENT_ANY``, the callback will be invoked for all Wi-Fi events.

Any callback function is given the event type in a parameter.
Some of the possible callback function formats also take an
Expand Down
4 changes: 2 additions & 2 deletions libraries/Ethernet/src/ETH.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ esp_eth_handle_t ETHClass::handle() const {

void ETHClass::_onEthEvent(int32_t event_id, void *event_data) {
arduino_event_t arduino_event;
arduino_event.event_id = ARDUINO_EVENT_MAX;
arduino_event.event_id = ARDUINO_EVENT_ANY;

if (event_id == ETHERNET_EVENT_CONNECTED) {
log_v("%s Connected", desc());
Expand All @@ -118,7 +118,7 @@ void ETHClass::_onEthEvent(int32_t event_id, void *event_data) {
);
}

if (arduino_event.event_id < ARDUINO_EVENT_MAX) {
if (arduino_event.event_id != ARDUINO_EVENT_ANY) {
Network.postEvent(&arduino_event);
}
}
Expand Down
201 changes: 88 additions & 113 deletions libraries/Network/src/NetworkEvents.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,39 +3,24 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <algorithm>
#include "NetworkEvents.h"
#include "NetworkManager.h"
#include "esp_task.h"
#include "esp32-hal.h"

#ifndef ARDUINO_NETWORK_EVENT_TASK_STACK_SIZE
#define ARDUINO_NETWORK_EVENT_TASK_STACK_SIZE 4096
#endif

NetworkEvents::NetworkEvents() : _arduino_event_group(NULL), _arduino_event_queue(NULL), _arduino_event_task_handle(NULL) {}
ESP_EVENT_DEFINE_BASE(ARDUINO_EVENTS);

NetworkEvents::~NetworkEvents() {
if (_arduino_event_task_handle != NULL) {
vTaskDelete(_arduino_event_task_handle);
_arduino_event_task_handle = NULL;
}
if (_arduino_event_group != NULL) {
vEventGroupDelete(_arduino_event_group);
_arduino_event_group = NULL;
}
if (_arduino_event_queue != NULL) {
arduino_event_t *event = NULL;
// consume queue
while (xQueueReceive(_arduino_event_queue, &event, 0) == pdTRUE) {
delete event;
}
vQueueDelete(_arduino_event_queue);
_arduino_event_queue = NULL;
// unregister event bus handler
if (_evt_handler){
esp_event_handler_instance_unregister(ARDUINO_EVENTS, ESP_EVENT_ANY_ID, _evt_handler);
_evt_handler = nullptr;
}
}

static uint32_t _initial_bits = 0;

bool NetworkEvents::initNetworkEvents() {
if (!_arduino_event_group) {
_arduino_event_group = xEventGroupCreate();
Expand All @@ -46,108 +31,75 @@ bool NetworkEvents::initNetworkEvents() {
xEventGroupSetBits(_arduino_event_group, _initial_bits);
}

if (!_arduino_event_queue) {
_arduino_event_queue = xQueueCreate(32, sizeof(arduino_event_t *));
if (!_arduino_event_queue) {
log_e("Network Event Queue Create Failed!");
return false;
}
}

// create default ESP event loop
esp_err_t err = esp_event_loop_create_default();
if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) {
log_e("esp_event_loop_create_default failed!");
return err;
return false;
}

if (!_arduino_event_task_handle) {
xTaskCreateUniversal(
[](void *self) {
static_cast<NetworkEvents *>(self)->_checkForEvent();
},
"arduino_events", // label
ARDUINO_NETWORK_EVENT_TASK_STACK_SIZE, // event task's stack size
this, ESP_TASKD_EVENT_PRIO - 1, &_arduino_event_task_handle, ARDUINO_EVENT_RUNNING_CORE
// subscribe to default ESP event bus
if (!_evt_handler){
ESP_ERROR_CHECK(
esp_event_handler_instance_register(
ARDUINO_EVENTS, ESP_EVENT_ANY_ID,
[](void* self, esp_event_base_t base, int32_t id, void* data) { static_cast<NetworkEvents*>(self)->_evt_picker(id, reinterpret_cast<arduino_event_info_t*>(data)); },
this,
&_evt_handler
)
);
if (!_arduino_event_task_handle) {
log_e("Network Event Task Start Failed!");
return false;
}
}

return true;
}

bool NetworkEvents::postEvent(const arduino_event_t *data) {
if (data == NULL || _arduino_event_queue == NULL) {
return false;
}
arduino_event_t *event = new arduino_event_t();
if (event == NULL) {
log_e("Arduino Event Malloc Failed!");
return false;
}
bool NetworkEvents::postEvent(const arduino_event_t *data, TickType_t timeout) {
if (!data) return false;
esp_err_t err = esp_event_post(ARDUINO_EVENTS, static_cast<int32_t>(data->event_id), &data->event_info, sizeof(data->event_info), timeout);
if (err == ESP_OK)
return true;

memcpy(event, data, sizeof(arduino_event_t));
if (xQueueSend(_arduino_event_queue, &event, portMAX_DELAY) != pdPASS) {
log_e("Arduino Event Send Failed!");
delete event; // release mem on error
return false;
}
return true;
log_e("Arduino Event Send Failed!");
return false;
}

void NetworkEvents::_checkForEvent() {
// this task can't run without the queue
if (_arduino_event_queue == NULL) {
_arduino_event_task_handle = NULL;
vTaskDelete(NULL);
return;
}
bool NetworkEvents::postEvent(arduino_event_id_t event, const arduino_event_info_t *info, TickType_t timeout){
if (info)
return esp_event_post(ARDUINO_EVENTS, static_cast<int32_t>(event), info, sizeof(arduino_event_info_t), timeout) == pdTRUE;
else
return esp_event_post(ARDUINO_EVENTS, static_cast<int32_t>(event), NULL, 0, timeout) == pdTRUE;
}

for (;;) {
arduino_event_t *event = NULL;
// wait for an event on a queue
if (xQueueReceive(_arduino_event_queue, &event, portMAX_DELAY) != pdTRUE) {
continue;
}
if (event == NULL) {
continue;
}
log_v("Network Event: %d - %s", event->event_id, eventName(event->event_id));

void NetworkEvents::_evt_picker(int32_t id, arduino_event_info_t *info){
#if defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1
std::unique_lock<std::mutex> lock(_mtx);
std::lock_guard<std::mutex> lock(_mtx);
#endif // defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1

// iterate over registered callbacks
for (auto &i : _cbEventList) {
if (i.cb || i.fcb || i.scb) {
if (i.event == (arduino_event_id_t)event->event_id || i.event == ARDUINO_EVENT_MAX) {
if (i.cb) {
i.cb((arduino_event_id_t)event->event_id);
continue;
}

if (i.fcb) {
i.fcb((arduino_event_id_t)event->event_id, (arduino_event_info_t)event->event_info);
continue;
}

i.scb(event);
// iterate over registered callbacks
for (auto &i : _cbEventList) {
if (i.event == ARDUINO_EVENT_ANY || i.event == static_cast<arduino_event_id_t>(id)){

std::visit([id, info](auto&& arg){
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, NetworkEventReceiver>)
arg(static_cast<arduino_event_id_t>(id), info);
else if constexpr (std::is_same_v<T, NetworkEventCb>)
arg(static_cast<arduino_event_id_t>(id));
else if constexpr (std::is_same_v<T, NetworkEventFuncCb>)
if (info)
arg(static_cast<arduino_event_id_t>(id), *info);
else
arg(static_cast<arduino_event_id_t>(id), {});
else if constexpr (std::is_same_v<T, NetworkEventSysCb>){
// system event callback needs a ptr to struct
arduino_event_t event{static_cast<arduino_event_id_t>(id), {}};
if (info)
memcpy(&event.event_info, info, sizeof(arduino_event_info_t));
arg(&event);
}
}
}, i.cb_v);
}

#if defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1
lock.unlock();
#endif // defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1

// release the event object's memory
delete event;
}

vTaskDelete(NULL);
}

template<typename T, typename... U> static size_t getStdFunctionAddress(std::function<T(U...)> f) {
Expand All @@ -168,7 +120,7 @@ network_event_handle_t NetworkEvents::onEvent(NetworkEventCb cbEvent, arduino_ev
std::lock_guard<std::mutex> lock(_mtx);
#endif // defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1

_cbEventList.emplace_back(++_current_id, cbEvent, nullptr, nullptr, event);
_cbEventList.emplace_back(++_current_id, cbEvent, event);
return _cbEventList.back().id;
}

Expand All @@ -181,7 +133,7 @@ network_event_handle_t NetworkEvents::onEvent(NetworkEventFuncCb cbEvent, arduin
std::lock_guard<std::mutex> lock(_mtx);
#endif // defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1

_cbEventList.emplace_back(++_current_id, nullptr, cbEvent, nullptr, event);
_cbEventList.emplace_back(++_current_id, cbEvent, event);
return _cbEventList.back().id;
}

Expand All @@ -194,7 +146,7 @@ network_event_handle_t NetworkEvents::onEvent(NetworkEventSysCb cbEvent, arduino
std::lock_guard<std::mutex> lock(_mtx);
#endif // defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1

_cbEventList.emplace_back(++_current_id, nullptr, nullptr, cbEvent, event);
_cbEventList.emplace_back(++_current_id, cbEvent, event);
return _cbEventList.back().id;
}

Expand All @@ -207,7 +159,7 @@ network_event_handle_t NetworkEvents::onSysEvent(NetworkEventCb cbEvent, arduino
std::lock_guard<std::mutex> lock(_mtx);
#endif // defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1

_cbEventList.emplace(_cbEventList.begin(), ++_current_id, cbEvent, nullptr, nullptr, event);
_cbEventList.emplace(_cbEventList.begin(), ++_current_id, cbEvent, event);
return _cbEventList.front().id;
}

Expand All @@ -220,7 +172,7 @@ network_event_handle_t NetworkEvents::onSysEvent(NetworkEventFuncCb cbEvent, ard
std::lock_guard<std::mutex> lock(_mtx);
#endif // defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1

_cbEventList.emplace(_cbEventList.begin(), ++_current_id, nullptr, cbEvent, nullptr, event);
_cbEventList.emplace(_cbEventList.begin(), ++_current_id, cbEvent, event);
return _cbEventList.front().id;
}

Expand All @@ -233,7 +185,20 @@ network_event_handle_t NetworkEvents::onSysEvent(NetworkEventSysCb cbEvent, ardu
std::lock_guard<std::mutex> lock(_mtx);
#endif // defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1

_cbEventList.emplace(_cbEventList.begin(), ++_current_id, nullptr, nullptr, cbEvent, event);
_cbEventList.emplace(_cbEventList.begin(), ++_current_id, cbEvent, event);
return _cbEventList.front().id;
}

network_event_handle_t NetworkEvents::onSysEvent(NetworkEventReceiver cbEvent, arduino_event_id_t event){
if (!cbEvent) {
return 0;
}

#if defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1
std::lock_guard<std::mutex> lock(_mtx);
#endif // defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1

_cbEventList.emplace(_cbEventList.begin(), ++_current_id, cbEvent, event);
return _cbEventList.front().id;
}

Expand All @@ -250,7 +215,11 @@ void NetworkEvents::removeEvent(NetworkEventCb cbEvent, arduino_event_id_t event
std::remove_if(
_cbEventList.begin(), _cbEventList.end(),
[cbEvent, event](const NetworkEventCbList_t &e) {
return e.cb == cbEvent && e.event == event;
return e.event == event && std::visit([cbEvent](auto&& arg) -> bool {
if constexpr (std::is_same_v<NetworkEventCb, std::decay_t<decltype(arg)>>)
return cbEvent == arg;
else return false;
}, e.cb_v);
}
),
_cbEventList.end()
Expand All @@ -265,12 +234,15 @@ void NetworkEvents::removeEvent(NetworkEventFuncCb cbEvent, arduino_event_id_t e
#if defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1
std::lock_guard<std::mutex> lock(_mtx);
#endif // defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1

_cbEventList.erase(
std::remove_if(
_cbEventList.begin(), _cbEventList.end(),
[cbEvent, event](const NetworkEventCbList_t &e) {
return getStdFunctionAddress(e.fcb) == getStdFunctionAddress(cbEvent) && e.event == event;
return e.event == event && std::visit([cbEvent](auto&& arg) -> bool {
if constexpr (std::is_same_v<NetworkEventFuncCb, std::decay_t<decltype(arg)>>)
return getStdFunctionAddress(cbEvent) == getStdFunctionAddress(arg);
else return false;
}, e.cb_v);
}
),
_cbEventList.end()
Expand All @@ -290,7 +262,11 @@ void NetworkEvents::removeEvent(NetworkEventSysCb cbEvent, arduino_event_id_t ev
std::remove_if(
_cbEventList.begin(), _cbEventList.end(),
[cbEvent, event](const NetworkEventCbList_t &e) {
return e.scb == cbEvent && e.event == event;
return e.event == event && std::visit([cbEvent](auto&& arg) -> bool {
if constexpr (std::is_same_v<NetworkEventSysCb, std::decay_t<decltype(arg)>>)
return cbEvent == arg;
else return false;
}, e.cb_v);
}
),
_cbEventList.end()
Expand Down Expand Up @@ -354,7 +330,6 @@ int NetworkEvents::waitStatusBits(int bits, uint32_t timeout_ms) {
* @brief Convert arduino_event_id_t to a C string.
* @param [in] id The event id to be converted.
* @return A string representation of the event id.
* @note: arduino_event_id_t values as of Mar 2023 (arduino-esp32 r2.0.7) are: 0-39 (ARDUINO_EVENT_MAX=40) and are defined in WiFiGeneric.h.
*/
const char *NetworkEvents::eventName(arduino_event_id_t id) {
switch (id) {
Expand Down
Loading
Loading