net: openthread: Add state change callback list

Add a new callback list structure for state change information.

These APIs are meant to eventually replace the single callback API
provided by openthread_set_state_changed_cb().

This will allow multiple users to gain information about
OpenThread stage changes.

Note CONFIG_OPENTHREAD_MAX_STATECHANGE_HANDLERS
with OpenThread's otSetStateChangedCallback() API can also be
used to enable registration of multiple callbacks of this type but this
cannot be modified if a certified OpenThread binary is used in the
build.

Signed-off-by: Nick Ward <nick.ward@ftpsolutions.com.au>
This commit is contained in:
Nick Ward 2023-01-09 17:57:51 +11:00 committed by Carles Cufí
commit 583545b662
2 changed files with 105 additions and 4 deletions

View file

@ -15,6 +15,8 @@ LOG_MODULE_REGISTER(net_l2_openthread, CONFIG_OPENTHREAD_L2_LOG_LEVEL);
#include <net_private.h>
#include <zephyr/init.h>
#include <zephyr/sys/check.h>
#include <zephyr/sys/slist.h>
#include <zephyr/sys/util.h>
#include <zephyr/sys/__assert.h>
#include <version.h>
@ -174,6 +176,7 @@ void otSysEventSignalPending(void)
static void ot_state_changed_handler(uint32_t flags, void *context)
{
struct openthread_state_changed_cb *entry, *next;
struct openthread_context *ot_context = context;
NET_INFO("State changed! Flags: 0x%08" PRIx32 " Current role: %s",
@ -220,6 +223,12 @@ static void ot_state_changed_handler(uint32_t flags, void *context)
if (state_changed_cb) {
state_changed_cb(flags, context);
}
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&ot_context->state_change_cbs, entry, next, node) {
if (entry->state_changed_cb != NULL) {
entry->state_changed_cb(flags, ot_context, entry->user_data);
}
}
}
static void ot_receive_handler(otMessage *aMessage, void *context)
@ -491,11 +500,11 @@ int openthread_stop(struct openthread_context *ot_context)
static int openthread_init(struct net_if *iface)
{
struct openthread_context *ot_context = net_if_l2_data(iface);
struct k_work_queue_config q_cfg = {
.name = "openthread",
.no_yield = true,
};
otError err;
NET_DBG("openthread_init");
@ -524,9 +533,13 @@ static int openthread_init(struct net_if *iface)
otIp6SetReceiveFilterEnabled(ot_context->instance, true);
otIp6SetReceiveCallback(ot_context->instance,
ot_receive_handler, ot_context);
otSetStateChangedCallback(ot_context->instance,
&ot_state_changed_handler,
ot_context);
sys_slist_init(&ot_context->state_change_cbs);
err = otSetStateChangedCallback(ot_context->instance,
&ot_state_changed_handler,
ot_context);
if (err != OT_ERROR_NONE) {
NET_ERR("Could not set state changed callback: %d", err);
}
net_mgmt_init_event_callback(
&ip6_addr_cb, ipv6_addr_event_handler,
@ -612,6 +625,40 @@ struct otInstance *openthread_get_default_instance(void)
return ot_context ? ot_context->instance : NULL;
}
int openthread_state_changed_cb_register(struct openthread_context *ot_context,
struct openthread_state_changed_cb *cb)
{
CHECKIF(cb == NULL || cb->state_changed_cb == NULL) {
return -EINVAL;
}
openthread_api_mutex_lock(ot_context);
sys_slist_append(&ot_context->state_change_cbs, &cb->node);
openthread_api_mutex_unlock(ot_context);
return 0;
}
int openthread_state_changed_cb_unregister(struct openthread_context *ot_context,
struct openthread_state_changed_cb *cb)
{
bool removed;
CHECKIF(cb == NULL) {
return -EINVAL;
}
openthread_api_mutex_lock(ot_context);
removed = sys_slist_find_and_remove(&ot_context->state_change_cbs, &cb->node);
openthread_api_mutex_unlock(ot_context);
if (!removed) {
return -EALREADY;
}
return 0;
}
void openthread_set_state_changed_cb(otStateChangedCallback cb)
{
state_changed_cb = cb;