1 /*******************************************************************************
2 * @file
3 * @brief Event System - A publish/subscribe inter-process communication API.
4 *******************************************************************************
5 * # License
6 * <b>Copyright 2023 Silicon Laboratories Inc. www.silabs.com</b>
7 *******************************************************************************
8 *
9 * SPDX-License-Identifier: Zlib
10 *
11 * The licensor of this software is Silicon Laboratories Inc.
12 *
13 * This software is provided 'as-is', without any express or implied
14 * warranty. In no event will the authors be held liable for any damages
15 * arising from the use of this software.
16 *
17 * Permission is granted to anyone to use this software for any purpose,
18 * including commercial applications, and to alter it and redistribute it
19 * freely, subject to the following restrictions:
20 *
21 * 1. The origin of this software must not be misrepresented; you must not
22 * claim that you wrote the original software. If you use this software
23 * in a product, an acknowledgment in the product documentation would be
24 * appreciated but is not required.
25 * 2. Altered source versions must be plainly marked as such, and must not be
26 * misrepresented as being the original software.
27 * 3. This notice may not be removed or altered from any source distribution.
28 *
29 ******************************************************************************/
30
31 #ifndef SL_EVENT_SYSTEM_H
32 #define SL_EVENT_SYSTEM_H
33
34 #include <stdint.h>
35 #include "cmsis_os2.h"
36 #include "sl_slist.h"
37 #include "sl_status.h"
38 #include "sl_enum.h"
39 #include "sl_core.h"
40
41 #ifdef __cplusplus
42 extern "C" {
43 #endif
44
45 /***************************************************************************//**
46 * @addtogroup event-system Event System
47 * @brief
48 * A publish/subscribe inter-process communication system.
49 * The source files for the event system software module are present under platform/common.
50 *
51 * @details
52 * ## Overview
53 * The event system is a software component enabling the development of event-driven
54 * software systems for Simplicity SDK based firmware's by managing publisher creation,
55 * event dispatching/filtering and event listening.
56 *
57 * The event system has multiple types of event classes that subscribers can listen to.
58 * Event classes identify the event source from which the event originates such as Bluetooth
59 * or Zigbee. See @ref sl_event_class_t.
60 *
61 * Subclasses further refine the event by offering information related to a particular
62 * functionality. A unique bit is assigned to each subclass which will have a specific meaning
63 * for each event publisher.
64 *
65 * ## Initialization
66 * The initialization of the event system occurs during the general system initialization.
67 * This happens when the application calls the sl_system_init() function. All the basic event system
68 * data structures will be initialized along with every publisher available in your project.
69 *
70 * ## Event subscription
71 *
72 * The event subscription takes place when the user establishes a communication pipeline
73 * between the listener and the publisher by calling @ref sl_event_subscribe.
74 * The user shall provide the type of event class that he wants to listen to, an event mask
75 * to further refine the set of events that he wants to listen to. Finally, an event queue must
76 * be created and initialized by the event listening code by using @ref sl_event_queue_create
77 * which will allocate the necessary memory and initialize an event system event queue.
78 * This queue is the main communication channel between the publisher and the listener.
79 *
80 * ## Event notification
81 *
82 * When a new event is generated, the publisher will enqueue it in the event listener
83 * provided queue. At this point, the listener will be able to recover this event by calling
84 * @ref sl_event_queue_get function. In the case where no event is ready for processing
85 * the calling process will pend on the message queue for a predetermined amount of time.
86 * After consuming the event, the @sl_event_process function must be called for each
87 * event instance. This will ensure that the memory and resources used by the event
88 * data structure is properly deallocated.
89 * @{
90 ******************************************************************************/
91
92 /*******************************************************************************
93 ********************************* TYPEDEFS ***********************************
94 ******************************************************************************/
95 typedef osMessageQueueId_t sl_event_queue_t;
96 typedef void (*sl_event_free_data_cb_t)(void *data);
97
SL_ENUM(sl_event_class_t)98 SL_ENUM(sl_event_class_t) {
99 SL_EVENT_CLASS_IRQ,
100 SL_EVENT_CLASS_BLUETOOTH,
101 SL_EVENT_CLASS_ZIGBEE,
102 SL_EVENT_CLASS_BLUETOOTH_MESH,
103 SL_EVENT_CLASS_MAX,
104 };
105
106 typedef struct {
107 sl_slist_node_t node;
108 uint32_t event_mask;
109 sl_event_queue_t event_queue;
110 } sl_event_subscriber_t;
111
112 typedef struct {
113 sl_slist_node_t node;
114 sl_event_class_t event_class;
115 sl_event_free_data_cb_t free_data_callback;
116 uint8_t subscriber_count;
117 sl_slist_node_t *subscribers;
118 bool is_registered;
119 } sl_event_publisher_t;
120
121 typedef struct {
122 sl_event_free_data_cb_t free_data_callback;
123 uint8_t reference_count;
124 void* event_data;
125 bool pre_allocated;
126 } sl_event_t;
127
128 /*******************************************************************************
129 ******************************** PROTOTYPES ***********************************
130 ******************************************************************************/
131
132 /*******************************************************************************
133 * @brief
134 * Initialize the event system.
135 ******************************************************************************/
136 void sl_event_system_init(void);
137
138 /*******************************************************************************
139 * @brief
140 * Initialize a publisher context and register it in the event system
141 * with a given event class.
142 *
143 * @description
144 * Only one publisher context is allowed per event class.
145 *
146 * @param[in] publisher Pointer to a publisher context.
147 * @param[in] event_class The class of events published by the publisher.
148 * @param[in] free_data_callback Callback to free the publisher's event data.
149 *
150 * @return
151 * SL_STATUS_OK if successful, otherwise an error code is returned.
152 ******************************************************************************/
153 sl_status_t sl_event_publisher_register(sl_event_publisher_t *publisher,
154 sl_event_class_t event_class,
155 sl_event_free_data_cb_t free_data_callback);
156
157 /*******************************************************************************
158 * @brief
159 * Unregister a publisher context from its event class.
160 *
161 * @description
162 * When a publisher context is unregistered, it can no longer publish messages
163 * until it is registered again. After a publisher context is unregistered, the
164 * event class it was registered with can be reused.
165 *
166 * @param[in] publisher Pointer to a publisher context.
167 *
168 * @return
169 * SL_STATUS_OK if successful, otherwise an error code is returned.
170 ******************************************************************************/
171 sl_status_t sl_event_publisher_unregister(sl_event_publisher_t *publisher);
172
173 /*******************************************************************************
174 * @brief
175 * Publish an event, with data, within the event class of the publisher.
176 *
177 * @param[in] publisher Pointer to a publisher context.
178 * @param[in] event_mask Event mask corresponding to the type of event.
179 * @param[in] event_prio The priority of the event published.
180 * @param[in] event_data The event data.
181 *
182 * @return
183 * SL_STATUS_OK if successful, otherwise an error code is returned.
184 ******************************************************************************/
185 sl_status_t sl_event_publish(sl_event_publisher_t *publisher,
186 uint32_t event_mask,
187 uint8_t event_prio,
188 void *event_data);
189
190 /*******************************************************************************
191 * @brief
192 * Publish an event, with data, with a pre-allocated event handle, within the
193 * event class of the publisher.
194 *
195 * @param[in] publisher Pointer to a publisher context.
196 * @param[in] event_mask Event mask corresponding to the type of event.
197 * @param[in] event_prio The priority of the event published.
198 * @param[in] event The pre-allocated event structure handle
199 * @param[in] event_data The event data.
200 *
201 * @return
202 * SL_STATUS_OK if successful, otherwise an error code is returned.
203 ******************************************************************************/
204 sl_status_t sl_event_publish_static(sl_event_publisher_t *publisher,
205 uint32_t event_mask,
206 uint8_t event_prio,
207 sl_event_t* event,
208 void *event_data);
209
210 /*******************************************************************************
211 * @brief
212 * Subscribe to one or more events for a given event class.
213 *
214 * @description
215 * The subscribed event(s) is/are placed in the queue identified by event_queue.
216 *
217 * @param[in] event_class The class of events to subscribe to.
218 * @param[in] event_mask The event(s) to subscribe to.
219 * @param[in] event_queue The identifier of an event queue.
220 *
221 * @return
222 * SL_STATUS_OK if successful, otherwise an error code is returned.
223 ******************************************************************************/
224 sl_status_t sl_event_subscribe(sl_event_class_t event_class,
225 uint32_t event_mask,
226 sl_event_queue_t event_queue);
227
228 /*******************************************************************************
229 * @brief
230 * Unsubscribe from one or more events for a given event class.
231 *
232 * @description
233 * The unsubscribed event(s) will no longer be placed in the queue identified
234 * by event_queue.
235 *
236 * @param[in] event_class The class of events to subscribe to.
237 * @param[in] event_mask The event(s) to subscribe to.
238 * @param[in] event_queue The identifier of an event queue.
239 *
240 * @return
241 * SL_STATUS_OK if successful, otherwise an error code is returned.
242 ******************************************************************************/
243 sl_status_t sl_event_unsubscribe(sl_event_class_t event_class,
244 uint32_t event_mask,
245 sl_event_queue_t event_queue);
246
247 /*******************************************************************************
248 * @brief
249 * Signal to the event system that a subscriber has processed an event.
250 *
251 * @description
252 * This must be called by subscribers after consuming an event so that the
253 * event data may eventually be freed. The event reference passed to this
254 * function is nullified before returning.
255 *
256 * @param[in] event Pointer to an event reference.
257 *
258 * @return
259 * SL_STATUS_OK if successful, otherwise an error code is returned.
260 ******************************************************************************/
261 sl_status_t sl_event_process(sl_event_t **event);
262
263 /*******************************************************************************
264 * @brief
265 * Create an event queue.
266 *
267 * @param[in] event_count The maximum number of events in the event queue.
268 * @param[out] event_queue The event queue that is created.
269 *
270 * @return
271 * SL_STATUS_OK if successful, otherwise an error code is returned.
272 ******************************************************************************/
273 sl_status_t sl_event_queue_create(uint32_t event_count,
274 sl_event_queue_t *event_queue);
275
276 /*******************************************************************************
277 * @brief
278 * Delete an event queue.
279 *
280 * @param[in] event_queue The event queue to delete.
281 *
282 * @return
283 * SL_STATUS_OK if successful, otherwise an error code is returned.
284 *
285 * @note
286 * In the process of deleting an event queue, all events that the queue
287 * was subscribed to will be unsubscribed from.
288 ******************************************************************************/
289 sl_status_t sl_event_queue_delete(sl_event_queue_t event_queue);
290
291 /*******************************************************************************
292 * @brief
293 * Get an event from an event queue.
294 *
295 * @param[in] event_queue The identifier of an event queue.
296 * @param[in] event_prio The priority of event(s) to get.
297 * @param[in] timeout Maximum time to pend on the event queue.
298 * @param[out] event The event reference retrieved from the event queue.
299 *
300 * @return
301 * SL_STATUS_OK if successful, otherwise an error code is returned.
302 ******************************************************************************/
303 sl_status_t sl_event_queue_get(sl_event_queue_t event_queue,
304 uint8_t *event_prio,
305 uint32_t timeout,
306 sl_event_t **event);
307
308 /*******************************************************************************
309 * @brief
310 * Get the size of the event publisher structure.
311 *
312 * @return Size of the event publisher structure.
313 ******************************************************************************/
314 size_t sl_event_publisher_get_size(void);
315
316 /*******************************************************************************
317 * @brief
318 * Allocate the publisher structure to the heap using the common memory
319 * manager with a long-term lifespan.
320 *
321 * @param[in] publisher address of a pointer to a publisher context
322 *
323 * @return
324 * SL_STATUS_OK if successful, otherwise an error code is returned.
325 ******************************************************************************/
326 sl_status_t sl_event_publisher_alloc(sl_event_publisher_t **publisher);
327
328 /*******************************************************************************
329 * @brief
330 * Free a publisher context structure from the heap, as well as its list of
331 * subscriber entries using the common memory manager.
332 *
333 * @description
334 * Using this function to free a publisher context will also free its list of
335 * subscribers, which will cause subscribers to no longer receive events from
336 * the publisher context's event class.
337 *
338 * @param[in] publisher address of a pointer to a publisher context
339 *
340 * @return
341 * SL_STATUS_OK if successful, otherwise an error code is returned.
342 ******************************************************************************/
343 sl_status_t sl_event_publisher_free(sl_event_publisher_t *publisher);
344
345 /*******************************************************************************
346 * @brief
347 * Get the size of the event structure.
348 *
349 * @return Size of the event structure.
350 ******************************************************************************/
351 size_t sl_event_get_size(void);
352
353 /*******************************************************************************
354 * @brief
355 * Allocate the event structure to the heap using the common memory
356 * manager with a long-term lifespan.
357 *
358 * @param[in] event address of a pointer to an event struct
359 *
360 * @return
361 * SL_STATUS_OK if successful, otherwise an error code is returned.
362 ******************************************************************************/
363 sl_status_t sl_event_alloc(sl_event_t **event);
364
365 /*******************************************************************************
366 * @brief
367 * Free an event structure from the heap using the common memory manager.
368 *
369 * @note
370 * Freeing an event structure that has not yet been processed by all
371 * subscribers will
372 *
373 * @param[in] event address of a pointer to an event struct
374 *
375 * @return
376 * SL_STATUS_OK if successful, otherwise an error code is returned.
377 ******************************************************************************/
378 sl_status_t sl_event_free(sl_event_t *event);
379
380 /** @} (end addtogroup event-system) */
381
382 #ifdef __cplusplus
383 }
384 #endif
385
386 #endif /* SL_EVENT_SYSTEM_H */
387