/* * Copyright (c) 2022 Rodrigo Peixoto * SPDX-License-Identifier: Apache-2.0 */ #include #include #include LOG_MODULE_DECLARE(zbus, CONFIG_ZBUS_LOG_LEVEL); int zbus_chan_add_obs(const struct zbus_channel *chan, const struct zbus_observer *obs, k_timeout_t timeout) { int err; struct zbus_observer_node *obs_nd, *tmp; struct zbus_channel_observation *observation; _ZBUS_ASSERT(!k_is_in_isr(), "ISR blocked"); _ZBUS_ASSERT(chan != NULL, "chan is required"); _ZBUS_ASSERT(obs != NULL, "obs is required"); err = k_sem_take(&chan->data->sem, timeout); if (err) { return err; } for (int16_t i = chan->data->observers_start_idx, limit = chan->data->observers_end_idx; i < limit; ++i) { STRUCT_SECTION_GET(zbus_channel_observation, i, &observation); __ASSERT(observation != NULL, "observation must be not NULL"); if (observation->obs == obs) { k_sem_give(&chan->data->sem); return -EEXIST; } } /* Check if the observer is already a runtime observer */ SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&chan->data->observers, obs_nd, tmp, node) { if (obs_nd->obs == obs) { k_sem_give(&chan->data->sem); return -EALREADY; } } struct zbus_observer_node *new_obs_nd = k_malloc(sizeof(struct zbus_observer_node)); if (new_obs_nd == NULL) { LOG_ERR("Could not allocate observer node the heap is full!"); k_sem_give(&chan->data->sem); return -ENOMEM; } new_obs_nd->obs = obs; sys_slist_append(&chan->data->observers, &new_obs_nd->node); k_sem_give(&chan->data->sem); return 0; } int zbus_chan_rm_obs(const struct zbus_channel *chan, const struct zbus_observer *obs, k_timeout_t timeout) { int err; struct zbus_observer_node *obs_nd, *tmp; struct zbus_observer_node *prev_obs_nd = NULL; _ZBUS_ASSERT(!k_is_in_isr(), "ISR blocked"); _ZBUS_ASSERT(chan != NULL, "chan is required"); _ZBUS_ASSERT(obs != NULL, "obs is required"); err = k_sem_take(&chan->data->sem, timeout); if (err) { return err; } SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&chan->data->observers, obs_nd, tmp, node) { if (obs_nd->obs == obs) { sys_slist_remove(&chan->data->observers, &prev_obs_nd->node, &obs_nd->node); k_free(obs_nd); k_sem_give(&chan->data->sem); return 0; } prev_obs_nd = obs_nd; } k_sem_give(&chan->data->sem); return -ENODATA; }