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