Skip to content

fix (NetworkEvents lib) remove checks for duplicated event handlers #10376

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

Merged
merged 8 commits into from
Oct 24, 2024
325 changes: 135 additions & 190 deletions libraries/Network/src/NetworkEvents.cpp
Original file line number Diff line number Diff line change
@@ -8,28 +8,6 @@
#include "esp_task.h"
#include "esp32-hal.h"

typedef struct NetworkEventCbList {
static network_event_handle_t current_id;
network_event_handle_t id;
NetworkEventCb cb;
NetworkEventFuncCb fcb;
NetworkEventSysCb scb;
arduino_event_id_t event;

NetworkEventCbList() : id(current_id++), cb(NULL), fcb(NULL), scb(NULL), event(ARDUINO_EVENT_NONE) {}
} NetworkEventCbList_t;
network_event_handle_t NetworkEventCbList::current_id = 1;

// arduino dont like std::vectors move static here
static std::vector<NetworkEventCbList_t> cbEventList;

static void _network_event_task(void *arg) {
for (;;) {
((NetworkEvents *)arg)->checkForEvent();
}
vTaskDelete(NULL);
}

NetworkEvents::NetworkEvents() : _arduino_event_group(NULL), _arduino_event_queue(NULL), _arduino_event_task_handle(NULL) {}

NetworkEvents::~NetworkEvents() {
@@ -43,8 +21,9 @@ NetworkEvents::~NetworkEvents() {
}
if (_arduino_event_queue != NULL) {
arduino_event_t *event = NULL;
// consume queue
while (xQueueReceive(_arduino_event_queue, &event, 0) == pdTRUE) {
free(event);
delete event;
}
vQueueDelete(_arduino_event_queue);
_arduino_event_queue = NULL;
@@ -78,7 +57,14 @@ bool NetworkEvents::initNetworkEvents() {
}

if (!_arduino_event_task_handle) {
xTaskCreateUniversal(_network_event_task, "arduino_events", 4096, this, ESP_TASKD_EVENT_PRIO - 1, &_arduino_event_task_handle, ARDUINO_EVENT_RUNNING_CORE);
xTaskCreateUniversal(
[](void *self) {
static_cast<NetworkEvents *>(self)->_checkForEvent();
},
"arduino_events", // label
4096, // event task's stack size
this, ESP_TASKD_EVENT_PRIO - 1, &_arduino_event_task_handle, ARDUINO_EVENT_RUNNING_CORE
);
if (!_arduino_event_task_handle) {
log_e("Network Event Task Start Failed!");
return false;
@@ -88,66 +74,76 @@ bool NetworkEvents::initNetworkEvents() {
return true;
}

bool NetworkEvents::postEvent(arduino_event_t *data) {
bool NetworkEvents::postEvent(const arduino_event_t *data) {
if (data == NULL || _arduino_event_queue == NULL) {
return false;
}
arduino_event_t *event = (arduino_event_t *)malloc(sizeof(arduino_event_t));
arduino_event_t *event = new arduino_event_t();
if (event == NULL) {
log_e("Arduino Event Malloc Failed!");
return false;
}

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;
}

void NetworkEvents::checkForEvent() {
arduino_event_t *event = NULL;
void NetworkEvents::_checkForEvent() {
// this task can't run without the queue
if (_arduino_event_queue == NULL) {
_arduino_event_task_handle = NULL;
vTaskDelete(NULL);
return;
}
if (xQueueReceive(_arduino_event_queue, &event, portMAX_DELAY) != pdTRUE) {
return;
}
if (event == NULL) {
return;
}
log_v("Network Event: %d - %s", event->event_id, eventName(event->event_id));
for (uint32_t i = 0; i < cbEventList.size(); i++) {
NetworkEventCbList_t entry = cbEventList[i];
if (entry.cb || entry.fcb || entry.scb) {
if (entry.event == (arduino_event_id_t)event->event_id || entry.event == ARDUINO_EVENT_MAX) {
if (entry.cb) {
entry.cb((arduino_event_id_t)event->event_id);
} else if (entry.fcb) {
entry.fcb((arduino_event_id_t)event->event_id, (arduino_event_info_t)event->event_info);
} else {
entry.scb(event);

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));

#if defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1
std::unique_lock<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);
}
}
}
}
free(event);
}

uint32_t NetworkEvents::findEvent(NetworkEventCb cbEvent, arduino_event_id_t event) {
uint32_t i;
#if defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1
lock.unlock();
#endif // defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1

if (!cbEvent) {
return cbEventList.size();
// release the event object's memory
delete event;
}

for (i = 0; i < cbEventList.size(); i++) {
NetworkEventCbList_t entry = cbEventList[i];
if (entry.cb == cbEvent && entry.event == event) {
break;
}
}
return i;
vTaskDelete(NULL);
}

template<typename T, typename... U> static size_t getStdFunctionAddress(std::function<T(U...)> f) {
@@ -159,209 +155,158 @@ template<typename T, typename... U> static size_t getStdFunctionAddress(std::fun
return (size_t)fnPointer;
}

uint32_t NetworkEvents::findEvent(NetworkEventFuncCb cbEvent, arduino_event_id_t event) {
uint32_t i;

if (!cbEvent) {
return cbEventList.size();
}

for (i = 0; i < cbEventList.size(); i++) {
NetworkEventCbList_t entry = cbEventList[i];
if (getStdFunctionAddress(entry.fcb) == getStdFunctionAddress(cbEvent) && entry.event == event) {
break;
}
}
return i;
}

uint32_t NetworkEvents::findEvent(NetworkEventSysCb cbEvent, arduino_event_id_t event) {
uint32_t i;

if (!cbEvent) {
return cbEventList.size();
}

for (i = 0; i < cbEventList.size(); i++) {
NetworkEventCbList_t entry = cbEventList[i];
if (entry.scb == cbEvent && entry.event == event) {
break;
}
}
return i;
}

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

if (findEvent(cbEvent, event) < cbEventList.size()) {
log_w("Attempt to add duplicate event handler!");
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

NetworkEventCbList_t newEventHandler;
newEventHandler.cb = cbEvent;
newEventHandler.fcb = NULL;
newEventHandler.scb = NULL;
newEventHandler.event = event;
cbEventList.push_back(newEventHandler);
return newEventHandler.id;
_cbEventList.emplace_back(++_current_id, cbEvent, nullptr, nullptr, event);
return _cbEventList.back().id;
}

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

if (findEvent(cbEvent, event) < cbEventList.size()) {
log_w("Attempt to add duplicate event handler!");
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

NetworkEventCbList_t newEventHandler;
newEventHandler.cb = NULL;
newEventHandler.fcb = cbEvent;
newEventHandler.scb = NULL;
newEventHandler.event = event;
cbEventList.push_back(newEventHandler);
return newEventHandler.id;
_cbEventList.emplace_back(++_current_id, nullptr, cbEvent, nullptr, event);
return _cbEventList.back().id;
}

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

if (findEvent(cbEvent, event) < cbEventList.size()) {
log_w("Attempt to add duplicate event handler!");
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

NetworkEventCbList_t newEventHandler;
newEventHandler.cb = NULL;
newEventHandler.fcb = NULL;
newEventHandler.scb = cbEvent;
newEventHandler.event = event;
cbEventList.push_back(newEventHandler);
return newEventHandler.id;
_cbEventList.emplace_back(++_current_id, nullptr, nullptr, cbEvent, event);
return _cbEventList.back().id;
}

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

if (findEvent(cbEvent, event) < cbEventList.size()) {
log_w("Attempt to add duplicate event handler!");
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

NetworkEventCbList_t newEventHandler;
newEventHandler.cb = cbEvent;
newEventHandler.fcb = NULL;
newEventHandler.scb = NULL;
newEventHandler.event = event;
cbEventList.insert(cbEventList.begin(), newEventHandler);
return newEventHandler.id;
_cbEventList.emplace(_cbEventList.begin(), ++_current_id, cbEvent, nullptr, nullptr, event);
return _cbEventList.front().id;
}

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

if (findEvent(cbEvent, event) < cbEventList.size()) {
log_w("Attempt to add duplicate event handler!");
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

NetworkEventCbList_t newEventHandler;
newEventHandler.cb = NULL;
newEventHandler.fcb = cbEvent;
newEventHandler.scb = NULL;
newEventHandler.event = event;
cbEventList.insert(cbEventList.begin(), newEventHandler);
return newEventHandler.id;
_cbEventList.emplace(_cbEventList.begin(), ++_current_id, nullptr, cbEvent, nullptr, event);
return _cbEventList.front().id;
}

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

if (findEvent(cbEvent, event) < cbEventList.size()) {
log_w("Attempt to add duplicate event handler!");
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

NetworkEventCbList_t newEventHandler;
newEventHandler.cb = NULL;
newEventHandler.fcb = NULL;
newEventHandler.scb = cbEvent;
newEventHandler.event = event;
cbEventList.insert(cbEventList.begin(), newEventHandler);
return newEventHandler.id;
_cbEventList.emplace(_cbEventList.begin(), ++_current_id, nullptr, nullptr, cbEvent, event);
return _cbEventList.front().id;
}

void NetworkEvents::removeEvent(NetworkEventCb cbEvent, arduino_event_id_t event) {
uint32_t i;

if (!cbEvent) {
return;
}

i = findEvent(cbEvent, event);
if (i >= cbEventList.size()) {
log_w("Event handler not found!");
return;
}
#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(cbEventList.begin() + i);
_cbEventList.erase(
std::remove_if(
_cbEventList.begin(), _cbEventList.end(),
[cbEvent, event](const NetworkEventCbList_t &e) {
return e.cb == cbEvent && e.event == event;
}
),
_cbEventList.end()
);
}

void NetworkEvents::removeEvent(NetworkEventFuncCb cbEvent, arduino_event_id_t event) {
uint32_t i;

if (!cbEvent) {
return;
}

i = findEvent(cbEvent, event);
if (i >= cbEventList.size()) {
log_w("Event handler not found!");
return;
}
#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(cbEventList.begin() + i);
_cbEventList.erase(
std::remove_if(
_cbEventList.begin(), _cbEventList.end(),
[cbEvent, event](const NetworkEventCbList_t &e) {
return getStdFunctionAddress(e.fcb) == getStdFunctionAddress(cbEvent) && e.event == event;
}
),
_cbEventList.end()
);
}

void NetworkEvents::removeEvent(NetworkEventSysCb cbEvent, arduino_event_id_t event) {
uint32_t i;

if (!cbEvent) {
return;
}

i = findEvent(cbEvent, event);
if (i >= cbEventList.size()) {
log_w("Event handler not found!");
return;
}
#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(cbEventList.begin() + i);
_cbEventList.erase(
std::remove_if(
_cbEventList.begin(), _cbEventList.end(),
[cbEvent, event](const NetworkEventCbList_t &e) {
return e.scb == cbEvent && e.event == event;
}
),
_cbEventList.end()
);
}

void NetworkEvents::removeEvent(network_event_handle_t id) {
for (uint32_t i = 0; i < cbEventList.size(); i++) {
NetworkEventCbList_t entry = cbEventList[i];
if (entry.id == id) {
cbEventList.erase(cbEventList.begin() + i);
return;
}
}
log_w("Event handler not found!");
#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(),
[id](const NetworkEventCbList_t &e) {
return e.id == id;
}
),
_cbEventList.end()
);
}

int NetworkEvents::setStatusBits(int bits) {
@@ -380,7 +325,7 @@ int NetworkEvents::clearStatusBits(int bits) {
return xEventGroupClearBits(_arduino_event_group, bits);
}

int NetworkEvents::getStatusBits() {
int NetworkEvents::getStatusBits() const {
if (!_arduino_event_group) {
return _initial_bits;
}
180 changes: 154 additions & 26 deletions libraries/Network/src/NetworkEvents.h
Original file line number Diff line number Diff line change
@@ -16,6 +16,9 @@
#include "freertos/queue.h"
#include "freertos/semphr.h"
#include "freertos/event_groups.h"
#if defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1
#include <mutex>
#endif // defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1

#if SOC_WIFI_SUPPORTED
#include "esp_wifi_types.h"
@@ -24,16 +27,16 @@
#endif

#if SOC_WIFI_SUPPORTED
static const int WIFI_SCANNING_BIT = BIT0;
static const int WIFI_SCAN_DONE_BIT = BIT1;
constexpr int WIFI_SCANNING_BIT = BIT0;
constexpr int WIFI_SCAN_DONE_BIT = BIT1;
#endif

#define NET_HAS_IP6_GLOBAL_BIT 0

ESP_EVENT_DECLARE_BASE(ARDUINO_EVENTS);

typedef enum {
ARDUINO_EVENT_NONE,
ARDUINO_EVENT_NONE = 0,
ARDUINO_EVENT_ETH_START,
ARDUINO_EVENT_ETH_STOP,
ARDUINO_EVENT_ETH_CONNECTED,
@@ -42,43 +45,43 @@ typedef enum {
ARDUINO_EVENT_ETH_LOST_IP,
ARDUINO_EVENT_ETH_GOT_IP6,
#if SOC_WIFI_SUPPORTED
ARDUINO_EVENT_WIFI_OFF,
ARDUINO_EVENT_WIFI_OFF = 100,
ARDUINO_EVENT_WIFI_READY,
ARDUINO_EVENT_WIFI_SCAN_DONE,
ARDUINO_EVENT_WIFI_STA_START,
ARDUINO_EVENT_WIFI_FTM_REPORT,
ARDUINO_EVENT_WIFI_STA_START = 110,
ARDUINO_EVENT_WIFI_STA_STOP,
ARDUINO_EVENT_WIFI_STA_CONNECTED,
ARDUINO_EVENT_WIFI_STA_DISCONNECTED,
ARDUINO_EVENT_WIFI_STA_AUTHMODE_CHANGE,
ARDUINO_EVENT_WIFI_STA_GOT_IP,
ARDUINO_EVENT_WIFI_STA_GOT_IP6,
ARDUINO_EVENT_WIFI_STA_LOST_IP,
ARDUINO_EVENT_WIFI_AP_START,
ARDUINO_EVENT_WIFI_AP_START = 130,
ARDUINO_EVENT_WIFI_AP_STOP,
ARDUINO_EVENT_WIFI_AP_STACONNECTED,
ARDUINO_EVENT_WIFI_AP_STADISCONNECTED,
ARDUINO_EVENT_WIFI_AP_STAIPASSIGNED,
ARDUINO_EVENT_WIFI_AP_PROBEREQRECVED,
ARDUINO_EVENT_WIFI_AP_GOT_IP6,
ARDUINO_EVENT_WIFI_FTM_REPORT,
ARDUINO_EVENT_WPS_ER_SUCCESS,
ARDUINO_EVENT_WPS_ER_SUCCESS = 140,
ARDUINO_EVENT_WPS_ER_FAILED,
ARDUINO_EVENT_WPS_ER_TIMEOUT,
ARDUINO_EVENT_WPS_ER_PIN,
ARDUINO_EVENT_WPS_ER_PBC_OVERLAP,
ARDUINO_EVENT_SC_SCAN_DONE,
ARDUINO_EVENT_SC_SCAN_DONE = 150,
ARDUINO_EVENT_SC_FOUND_CHANNEL,
ARDUINO_EVENT_SC_GOT_SSID_PSWD,
ARDUINO_EVENT_SC_SEND_ACK_DONE,
ARDUINO_EVENT_PROV_INIT,
ARDUINO_EVENT_PROV_INIT = 160,
ARDUINO_EVENT_PROV_DEINIT,
ARDUINO_EVENT_PROV_START,
ARDUINO_EVENT_PROV_END,
ARDUINO_EVENT_PROV_CRED_RECV,
ARDUINO_EVENT_PROV_CRED_FAIL,
ARDUINO_EVENT_PROV_CRED_SUCCESS,
#endif
ARDUINO_EVENT_PPP_START,
ARDUINO_EVENT_PPP_START = 200,
ARDUINO_EVENT_PPP_STOP,
ARDUINO_EVENT_PPP_CONNECTED,
ARDUINO_EVENT_PPP_DISCONNECTED,
@@ -110,36 +113,123 @@ typedef union {
#endif
} arduino_event_info_t;

typedef struct {
/**
* @brief struct combines arduino event id and event's data object
*
*/
struct arduino_event_t {
arduino_event_id_t event_id;
arduino_event_info_t event_info;
} arduino_event_t;

typedef void (*NetworkEventCb)(arduino_event_id_t event);
typedef std::function<void(arduino_event_id_t event, arduino_event_info_t info)> NetworkEventFuncCb;
typedef void (*NetworkEventSysCb)(arduino_event_t *event);
};

typedef size_t network_event_handle_t;
// type aliases
using NetworkEventCb = void (*)(arduino_event_id_t event);
using NetworkEventFuncCb = std::function<void(arduino_event_id_t event, arduino_event_info_t info)>;
using NetworkEventSysCb = void (*)(arduino_event_t *event);
using network_event_handle_t = size_t;

/**
* @brief Class that provides network events callback handling
* it registers user callback functions for event handling,
* maintains the queue of events and propagates the event among subscribed callbacks
* callback are called in the context of a dedicated task consuming the queue
*
*/
class NetworkEvents {
public:
NetworkEvents();
~NetworkEvents();

/**
* @brief register callback function to be executed on arduino event(s)
* @note if same handler is registered twice or more than same handler would be called twice or more times
*
* @param cbEvent static callback function
* @param event event to process, any event by default
* @return network_event_handle_t
*/
network_event_handle_t onEvent(NetworkEventCb cbEvent, arduino_event_id_t event = ARDUINO_EVENT_MAX);

/**
* @brief register functional callback to be executed on arduino event(s)
* also used for lambda callbacks
* @note if same handler is registered twice or more than same handler would be called twice or more times
*
* @param cbEvent static callback function
* @param event event to process, any event by default
* @return network_event_handle_t
*/
network_event_handle_t onEvent(NetworkEventFuncCb cbEvent, arduino_event_id_t event = ARDUINO_EVENT_MAX);

/**
* @brief register static system callback to be executed on arduino event(s)
* callback function would be supplied with a pointer to arduino_event_t structure as an argument
*
* @note if same handler is registered twice or more than same handler would be called twice or more times
*
* @param cbEvent static callback function
* @param event event to process, any event by default
* @return network_event_handle_t
*/
network_event_handle_t onEvent(NetworkEventSysCb cbEvent, arduino_event_id_t event = ARDUINO_EVENT_MAX);

/**
* @brief unregister static function callback
* @note a better way to unregister callbacks is to save/unregister via network_event_handle_t
*
* @param cbEvent static callback function
* @param event event to process, any event by default
*/
void removeEvent(NetworkEventCb cbEvent, arduino_event_id_t event = ARDUINO_EVENT_MAX);
void removeEvent(NetworkEventFuncCb cbEvent, arduino_event_id_t event = ARDUINO_EVENT_MAX);

/**
* @brief unregister functional callback
* @note a better way to unregister callbacks is to save/unregister via network_event_handle_t
* @note this does not work for lambda's! Do unregister via network_event_handle_t
*
* @param cbEvent functional callback
* @param event event to process, any event by default
*/
void removeEvent(NetworkEventFuncCb cbEvent, arduino_event_id_t event = ARDUINO_EVENT_MAX)
__attribute__((deprecated("removing functional callbacks via pointer is deprecated, use removeEvent(network_event_handle_t) instead")));

/**
* @brief unregister static system function callback
* @note a better way to unregister callbacks is to save/unregister via network_event_handle_t
*
* @param cbEvent static callback function
* @param event event to process, any event by default
*/
void removeEvent(NetworkEventSysCb cbEvent, arduino_event_id_t event = ARDUINO_EVENT_MAX);

/**
* @brief unregister event callback via handler
*
* @param cbEvent static callback function
* @param event event to process, any event by default
*/
void removeEvent(network_event_handle_t event_handle);

const char *eventName(arduino_event_id_t id);
/**
* @brief get a human-readable name of an event by it's id
*
* @param id event id code
* @return const char* event name string
*/
static const char *eventName(arduino_event_id_t id);

void checkForEvent();
bool postEvent(arduino_event_t *event);
/**
* @brief post an event to the queue
* and propagade and event to subscribed handlers
* @note posting an event will trigger context switch from a lower priority task
*
* @param event a pointer to arduino_event_t struct
* @return true if event was queued susccessfuly
* @return false on memrory allocation error or queue is full
*/
bool postEvent(const arduino_event_t *event);

int getStatusBits();
int getStatusBits() const;
int waitStatusBits(int bits, uint32_t timeout_ms);
int setStatusBits(int bits);
int clearStatusBits(int bits);
@@ -155,15 +245,53 @@ class NetworkEvents {

protected:
bool initNetworkEvents();
uint32_t findEvent(NetworkEventCb cbEvent, arduino_event_id_t event);
uint32_t findEvent(NetworkEventFuncCb cbEvent, arduino_event_id_t event);
uint32_t findEvent(NetworkEventSysCb cbEvent, arduino_event_id_t event);
// same as onEvent() but places newly added handler at the beginning of registered events list
network_event_handle_t onSysEvent(NetworkEventCb cbEvent, arduino_event_id_t event = ARDUINO_EVENT_MAX);
// same as onEvent() but places newly added handler at the beginning of registered events list
network_event_handle_t onSysEvent(NetworkEventFuncCb cbEvent, arduino_event_id_t event = ARDUINO_EVENT_MAX);
// same as onEvent() but places newly added handler at the beginning of registered events list
network_event_handle_t onSysEvent(NetworkEventSysCb cbEvent, arduino_event_id_t event = ARDUINO_EVENT_MAX);

private:
/**
* @brief an object holds callback's definitions:
* - callback id
* - callback function pointers
* - binded event id
*
*/
struct NetworkEventCbList_t {
network_event_handle_t id;
NetworkEventCb cb;
NetworkEventFuncCb fcb;
NetworkEventSysCb scb;
arduino_event_id_t event;

explicit NetworkEventCbList_t(
network_event_handle_t id, NetworkEventCb cb = nullptr, NetworkEventFuncCb fcb = nullptr, NetworkEventSysCb scb = nullptr,
arduino_event_id_t event = ARDUINO_EVENT_MAX
)
: id(id), cb(cb), fcb(fcb), scb(scb), event(event) {}
};

// define initial id's value
network_event_handle_t _current_id{0};

EventGroupHandle_t _arduino_event_group;
QueueHandle_t _arduino_event_queue;
TaskHandle_t _arduino_event_task_handle;

// registered events callbacks container
std::vector<NetworkEventCbList_t> _cbEventList;

#if defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1
// container access mutex
std::mutex _mtx;
#endif // defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1

/**
* @brief task function that picks events from an event queue and calls registered callbacks
*
*/
void _checkForEvent();
};