diff --git a/include/zephyr/zbus/zbus.h b/include/zephyr/zbus/zbus.h index e5657c0a5493..478268d85b4c 100644 --- a/include/zephyr/zbus/zbus.h +++ b/include/zephyr/zbus/zbus.h @@ -81,6 +81,10 @@ struct zbus_channel { #if defined(CONFIG_ZBUS_CHANNEL_NAME) || defined(__DOXYGEN__) /** Channel name. */ const char *name; +#endif +#if defined(CONFIG_ZBUS_CHANNEL_ID) || defined(__DOXYGEN__) + /** Unique numeric channel identifier. */ + uint32_t id; #endif /** Message reference. Represents the message's reference that points to the actual * shared memory region. @@ -263,6 +267,34 @@ struct zbus_channel_observation { #define _ZBUS_RUNTIME_OBSERVERS_DECL(_name) #endif /* CONFIG_ZBUS_RUNTIME_OBSERVERS */ +#define _ZBUS_MESSAGE_NAME(_name) _CONCAT(_zbus_message_, _name) + +/* clang-format off */ +#define _ZBUS_CHAN_DEFINE(_name, _id, _type, _validator, _user_data) \ + static struct zbus_channel_data _CONCAT(_zbus_chan_data_, _name) = { \ + .observers_start_idx = -1, \ + .observers_end_idx = -1, \ + .sem = Z_SEM_INITIALIZER(_CONCAT(_zbus_chan_data_, _name).sem, 1, 1), \ + IF_ENABLED(CONFIG_ZBUS_PRIORITY_BOOST, \ + (.highest_observer_priority = ZBUS_MIN_THREAD_PRIORITY,)) \ + IF_ENABLED(CONFIG_ZBUS_RUNTIME_OBSERVERS, \ + (.observers = SYS_SLIST_STATIC_INIT( \ + &_CONCAT(_zbus_chan_data_, _name).observers),)) \ + }; \ + static K_MUTEX_DEFINE(_CONCAT(_zbus_mutex_, _name)); \ + _ZBUS_CPP_EXTERN const STRUCT_SECTION_ITERABLE(zbus_channel, _name) = { \ + ZBUS_CHANNEL_NAME_INIT(_name) /* Maybe removed */ \ + IF_ENABLED(CONFIG_ZBUS_CHANNEL_ID, (.id = _id,)) \ + .message = &_ZBUS_MESSAGE_NAME(_name), \ + .message_size = sizeof(_type), \ + .user_data = _user_data, \ + .validator = _validator, \ + .data = &_CONCAT(_zbus_chan_data_, _name), \ + IF_ENABLED(ZBUS_MSG_SUBSCRIBER_NET_BUF_POOL_ISOLATION, \ + (.msg_subscriber_pool = &_zbus_msg_subscribers_pool,)) \ + } +/* clang-format on */ + /** @endcond */ /* clang-format off */ @@ -328,7 +360,11 @@ struct zbus_channel_observation { */ #define ZBUS_OBSERVERS(...) __VA_ARGS__ -/* clang-format off */ +/** + * @def ZBUS_CHAN_ID_INVALID + * This macro indicates the channel does not have a unique ID. + */ +#define ZBUS_CHAN_ID_INVALID UINT32_MAX /** * @brief Zbus channel definition. @@ -345,37 +381,37 @@ struct zbus_channel_observation { * first the highest priority. * @param _init_val The message initialization. */ -#define ZBUS_CHAN_DEFINE(_name, _type, _validator, _user_data, _observers, _init_val) \ - static _type _CONCAT(_zbus_message_, _name) = _init_val; \ - static struct zbus_channel_data _CONCAT(_zbus_chan_data_, _name) = { \ - .observers_start_idx = -1, \ - .observers_end_idx = -1, \ - .sem = Z_SEM_INITIALIZER(_CONCAT(_zbus_chan_data_, _name).sem, 1, 1), \ - IF_ENABLED(CONFIG_ZBUS_PRIORITY_BOOST, ( \ - .highest_observer_priority = ZBUS_MIN_THREAD_PRIORITY, \ - )) \ - IF_ENABLED(CONFIG_ZBUS_RUNTIME_OBSERVERS, ( \ - .observers = SYS_SLIST_STATIC_INIT( \ - &_CONCAT(_zbus_chan_data_, _name).observers), \ - )) \ - }; \ - static K_MUTEX_DEFINE(_CONCAT(_zbus_mutex_, _name)); \ - _ZBUS_CPP_EXTERN const STRUCT_SECTION_ITERABLE(zbus_channel, _name) = { \ - ZBUS_CHANNEL_NAME_INIT(_name) /* Maybe removed */ \ - .message = &_CONCAT(_zbus_message_, _name), \ - .message_size = sizeof(_type), \ - .user_data = _user_data, \ - .validator = _validator, \ - .data = &_CONCAT(_zbus_chan_data_, _name), \ - IF_ENABLED(ZBUS_MSG_SUBSCRIBER_NET_BUF_POOL_ISOLATION, ( \ - .msg_subscriber_pool = &_zbus_msg_subscribers_pool, \ - )) \ - }; \ - /* Extern declaration of observers */ \ - ZBUS_OBS_DECLARE(_observers); \ - /* Create all channel observations from observers list */ \ +#define ZBUS_CHAN_DEFINE(_name, _type, _validator, _user_data, _observers, _init_val) \ + static _type _ZBUS_MESSAGE_NAME(_name) = _init_val; \ + _ZBUS_CHAN_DEFINE(_name, ZBUS_CHAN_ID_INVALID, _type, _validator, _user_data); \ + /* Extern declaration of observers */ \ + ZBUS_OBS_DECLARE(_observers); \ + /* Create all channel observations from observers list */ \ + FOR_EACH_FIXED_ARG_NONEMPTY_TERM(_ZBUS_CHAN_OBSERVATION, (;), _name, _observers) + +/** + * @brief Zbus channel definition with numeric identifier. + * + * This macro defines a channel. + * + * @param _name The channel's name. + * @param _id The channel's unique numeric identifier. + * @param _type The Message type. It must be a struct or union. + * @param _validator The validator function. + * @param _user_data A pointer to the user data. + * + * @see struct zbus_channel + * @param _observers The observers list. The sequence indicates the priority of the observer. The + * first the highest priority. + * @param _init_val The message initialization. + */ +#define ZBUS_CHAN_DEFINE_WITH_ID(_name, _id, _type, _validator, _user_data, _observers, _init_val) \ + static _type _ZBUS_MESSAGE_NAME(_name) = _init_val; \ + _ZBUS_CHAN_DEFINE(_name, _id, _type, _validator, _user_data); \ + /* Extern declaration of observers */ \ + ZBUS_OBS_DECLARE(_observers); \ + /* Create all channel observations from observers list */ \ FOR_EACH_FIXED_ARG_NONEMPTY_TERM(_ZBUS_CHAN_OBSERVATION, (;), _name, _observers) -/* clang-format on */ /** * @brief Initialize a message. @@ -386,10 +422,7 @@ struct zbus_channel_observation { * @param[in] _val Variadic with the initial values. ``ZBUS_INIT(0)`` means ``{0}``, as * ZBUS_INIT(.a=10, .b=30) means ``{.a=10, .b=30}``. */ -#define ZBUS_MSG_INIT(_val, ...) \ - { \ - _val, ##__VA_ARGS__ \ - } +#define ZBUS_MSG_INIT(_val, ...) {_val, ##__VA_ARGS__} /* clang-format off */ @@ -638,6 +671,20 @@ static inline const char *zbus_chan_name(const struct zbus_channel *chan) #endif +#if defined(CONFIG_ZBUS_CHANNEL_ID) || defined(__DOXYGEN__) + +/** + * @brief Retrieve a zbus channel from its numeric identifier + * + * @param channel_id Unique channel ID from @ref ZBUS_CHAN_DEFINE_WITH_ID + * + * @retval NULL If channel with ID @a channel_id does not exist. + * @retval chan Channel pointer with ID @a channel_id otherwise. + */ +const struct zbus_channel *zbus_chan_from_id(uint32_t channel_id); + +#endif + /** * @brief Get the reference for a channel message directly. * diff --git a/subsys/zbus/Kconfig b/subsys/zbus/Kconfig index 8f742b8bd99c..9cd518c6215b 100644 --- a/subsys/zbus/Kconfig +++ b/subsys/zbus/Kconfig @@ -16,6 +16,9 @@ config ZBUS_CHANNELS_SYS_INIT_PRIORITY config ZBUS_CHANNEL_NAME bool "Channel name field" +config ZBUS_CHANNEL_ID + bool "Channel identifier field" + config ZBUS_OBSERVER_NAME bool "Observer name field" diff --git a/subsys/zbus/zbus.c b/subsys/zbus/zbus.c index 78f8ce99fd4e..e4defffbc57b 100644 --- a/subsys/zbus/zbus.c +++ b/subsys/zbus/zbus.c @@ -75,10 +75,53 @@ int _zbus_init(void) ++(curr->data->observers_end_idx); } +#if defined(CONFIG_ZBUS_CHANNEL_ID) + STRUCT_SECTION_FOREACH(zbus_channel, chan) { + /* Check for duplicate channel IDs */ + if (chan->id == ZBUS_CHAN_ID_INVALID) { + continue; + } + /* Iterate over all previous channels */ + STRUCT_SECTION_FOREACH(zbus_channel, chan_prev) { + if (chan_prev == chan) { + break; + } + if (chan->id == chan_prev->id) { +#if defined(CONFIG_ZBUS_CHANNEL_NAME) + LOG_WRN("Channels %s and %s have matching IDs (%d)", chan->name, + chan_prev->name, chan->id); +#else + LOG_WRN("Channels %p and %p have matching IDs (%d)", chan, + chan_prev, chan->id); +#endif /* CONFIG_ZBUS_CHANNEL_NAME */ + } + } + } +#endif /* CONFIG_ZBUS_CHANNEL_ID */ + return 0; } SYS_INIT(_zbus_init, APPLICATION, CONFIG_ZBUS_CHANNELS_SYS_INIT_PRIORITY); +#if defined(CONFIG_ZBUS_CHANNEL_ID) + +const struct zbus_channel *zbus_chan_from_id(uint32_t channel_id) +{ + if (channel_id == ZBUS_CHAN_ID_INVALID) { + return NULL; + } + STRUCT_SECTION_FOREACH(zbus_channel, chan) { + if (chan->id == channel_id) { + /* Found matching channel */ + return chan; + } + } + /* No matching channel exists */ + return NULL; +} + +#endif /* CONFIG_ZBUS_CHANNEL_ID */ + static inline int _zbus_notify_observer(const struct zbus_channel *chan, const struct zbus_observer *obs, k_timepoint_t end_time, struct net_buf *buf)