/*******************************************************************************
* @file
* @brief Event System - A publish/subscribe inter-process communication API.
*******************************************************************************
* # License
* Copyright 2023 Silicon Laboratories Inc. www.silabs.com
*******************************************************************************
*
* SPDX-License-Identifier: Zlib
*
* The licensor of this software is Silicon Laboratories Inc.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
******************************************************************************/
#ifndef SL_EVENT_SYSTEM_H
#define SL_EVENT_SYSTEM_H
#include
#include "cmsis_os2.h"
#include "sl_slist.h"
#include "sl_status.h"
#include "sl_enum.h"
#include "sl_core.h"
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************//**
* @addtogroup event-system Event System
* @brief
* A publish/subscribe inter-process communication system.
* The source files for the event system software module are present under platform/common.
*
* @details
* ## Overview
* The event system is a software component enabling the development of event-driven
* software systems for Simplicity SDK based firmware's by managing publisher creation,
* event dispatching/filtering and event listening.
*
* The event system has multiple types of event classes that subscribers can listen to.
* Event classes identify the event source from which the event originates such as Bluetooth
* or Zigbee. See @ref sl_event_class_t.
*
* Subclasses further refine the event by offering information related to a particular
* functionality. A unique bit is assigned to each subclass which will have a specific meaning
* for each event publisher.
*
* ## Initialization
* The initialization of the event system occurs during the general system initialization.
* This happens when the application calls the sl_system_init() function. All the basic event system
* data structures will be initialized along with every publisher available in your project.
*
* ## Event subscription
*
* The event subscription takes place when the user establishes a communication pipeline
* between the listener and the publisher by calling @ref sl_event_subscribe.
* The user shall provide the type of event class that he wants to listen to, an event mask
* to further refine the set of events that he wants to listen to. Finally, an event queue must
* be created and initialized by the event listening code by using @ref sl_event_queue_create
* which will allocate the necessary memory and initialize an event system event queue.
* This queue is the main communication channel between the publisher and the listener.
*
* ## Event notification
*
* When a new event is generated, the publisher will enqueue it in the event listener
* provided queue. At this point, the listener will be able to recover this event by calling
* @ref sl_event_queue_get function. In the case where no event is ready for processing
* the calling process will pend on the message queue for a predetermined amount of time.
* After consuming the event, the @sl_event_process function must be called for each
* event instance. This will ensure that the memory and resources used by the event
* data structure is properly deallocated.
* @{
******************************************************************************/
/*******************************************************************************
********************************* TYPEDEFS ***********************************
******************************************************************************/
typedef osMessageQueueId_t sl_event_queue_t;
typedef void (*sl_event_free_data_cb_t)(void *data);
SL_ENUM(sl_event_class_t) {
SL_EVENT_CLASS_IRQ,
SL_EVENT_CLASS_BLUETOOTH,
SL_EVENT_CLASS_ZIGBEE,
SL_EVENT_CLASS_BLUETOOTH_MESH,
SL_EVENT_CLASS_MAX,
};
typedef struct {
sl_slist_node_t node;
uint32_t event_mask;
sl_event_queue_t event_queue;
} sl_event_subscriber_t;
typedef struct {
sl_slist_node_t node;
sl_event_class_t event_class;
sl_event_free_data_cb_t free_data_callback;
uint8_t subscriber_count;
sl_slist_node_t *subscribers;
bool is_registered;
} sl_event_publisher_t;
typedef struct {
sl_event_free_data_cb_t free_data_callback;
uint8_t reference_count;
void* event_data;
bool pre_allocated;
} sl_event_t;
/*******************************************************************************
******************************** PROTOTYPES ***********************************
******************************************************************************/
/*******************************************************************************
* @brief
* Initialize the event system.
******************************************************************************/
void sl_event_system_init(void);
/*******************************************************************************
* @brief
* Initialize a publisher context and register it in the event system
* with a given event class.
*
* @description
* Only one publisher context is allowed per event class.
*
* @param[in] publisher Pointer to a publisher context.
* @param[in] event_class The class of events published by the publisher.
* @param[in] free_data_callback Callback to free the publisher's event data.
*
* @return
* SL_STATUS_OK if successful, otherwise an error code is returned.
******************************************************************************/
sl_status_t sl_event_publisher_register(sl_event_publisher_t *publisher,
sl_event_class_t event_class,
sl_event_free_data_cb_t free_data_callback);
/*******************************************************************************
* @brief
* Unregister a publisher context from its event class.
*
* @description
* When a publisher context is unregistered, it can no longer publish messages
* until it is registered again. After a publisher context is unregistered, the
* event class it was registered with can be reused.
*
* @param[in] publisher Pointer to a publisher context.
*
* @return
* SL_STATUS_OK if successful, otherwise an error code is returned.
******************************************************************************/
sl_status_t sl_event_publisher_unregister(sl_event_publisher_t *publisher);
/*******************************************************************************
* @brief
* Publish an event, with data, within the event class of the publisher.
*
* @param[in] publisher Pointer to a publisher context.
* @param[in] event_mask Event mask corresponding to the type of event.
* @param[in] event_prio The priority of the event published.
* @param[in] event_data The event data.
*
* @return
* SL_STATUS_OK if successful, otherwise an error code is returned.
******************************************************************************/
sl_status_t sl_event_publish(sl_event_publisher_t *publisher,
uint32_t event_mask,
uint8_t event_prio,
void *event_data);
/*******************************************************************************
* @brief
* Publish an event, with data, with a pre-allocated event handle, within the
* event class of the publisher.
*
* @param[in] publisher Pointer to a publisher context.
* @param[in] event_mask Event mask corresponding to the type of event.
* @param[in] event_prio The priority of the event published.
* @param[in] event The pre-allocated event structure handle
* @param[in] event_data The event data.
*
* @return
* SL_STATUS_OK if successful, otherwise an error code is returned.
******************************************************************************/
sl_status_t sl_event_publish_static(sl_event_publisher_t *publisher,
uint32_t event_mask,
uint8_t event_prio,
sl_event_t* event,
void *event_data);
/*******************************************************************************
* @brief
* Subscribe to one or more events for a given event class.
*
* @description
* The subscribed event(s) is/are placed in the queue identified by event_queue.
*
* @param[in] event_class The class of events to subscribe to.
* @param[in] event_mask The event(s) to subscribe to.
* @param[in] event_queue The identifier of an event queue.
*
* @return
* SL_STATUS_OK if successful, otherwise an error code is returned.
******************************************************************************/
sl_status_t sl_event_subscribe(sl_event_class_t event_class,
uint32_t event_mask,
sl_event_queue_t event_queue);
/*******************************************************************************
* @brief
* Unsubscribe from one or more events for a given event class.
*
* @description
* The unsubscribed event(s) will no longer be placed in the queue identified
* by event_queue.
*
* @param[in] event_class The class of events to subscribe to.
* @param[in] event_mask The event(s) to subscribe to.
* @param[in] event_queue The identifier of an event queue.
*
* @return
* SL_STATUS_OK if successful, otherwise an error code is returned.
******************************************************************************/
sl_status_t sl_event_unsubscribe(sl_event_class_t event_class,
uint32_t event_mask,
sl_event_queue_t event_queue);
/*******************************************************************************
* @brief
* Signal to the event system that a subscriber has processed an event.
*
* @description
* This must be called by subscribers after consuming an event so that the
* event data may eventually be freed. The event reference passed to this
* function is nullified before returning.
*
* @param[in] event Pointer to an event reference.
*
* @return
* SL_STATUS_OK if successful, otherwise an error code is returned.
******************************************************************************/
sl_status_t sl_event_process(sl_event_t **event);
/*******************************************************************************
* @brief
* Create an event queue.
*
* @param[in] event_count The maximum number of events in the event queue.
* @param[out] event_queue The event queue that is created.
*
* @return
* SL_STATUS_OK if successful, otherwise an error code is returned.
******************************************************************************/
sl_status_t sl_event_queue_create(uint32_t event_count,
sl_event_queue_t *event_queue);
/*******************************************************************************
* @brief
* Delete an event queue.
*
* @param[in] event_queue The event queue to delete.
*
* @return
* SL_STATUS_OK if successful, otherwise an error code is returned.
*
* @note
* In the process of deleting an event queue, all events that the queue
* was subscribed to will be unsubscribed from.
******************************************************************************/
sl_status_t sl_event_queue_delete(sl_event_queue_t event_queue);
/*******************************************************************************
* @brief
* Get an event from an event queue.
*
* @param[in] event_queue The identifier of an event queue.
* @param[in] event_prio The priority of event(s) to get.
* @param[in] timeout Maximum time to pend on the event queue.
* @param[out] event The event reference retrieved from the event queue.
*
* @return
* SL_STATUS_OK if successful, otherwise an error code is returned.
******************************************************************************/
sl_status_t sl_event_queue_get(sl_event_queue_t event_queue,
uint8_t *event_prio,
uint32_t timeout,
sl_event_t **event);
/*******************************************************************************
* @brief
* Get the size of the event publisher structure.
*
* @return Size of the event publisher structure.
******************************************************************************/
size_t sl_event_publisher_get_size(void);
/*******************************************************************************
* @brief
* Allocate the publisher structure to the heap using the common memory
* manager with a long-term lifespan.
*
* @param[in] publisher address of a pointer to a publisher context
*
* @return
* SL_STATUS_OK if successful, otherwise an error code is returned.
******************************************************************************/
sl_status_t sl_event_publisher_alloc(sl_event_publisher_t **publisher);
/*******************************************************************************
* @brief
* Free a publisher context structure from the heap, as well as its list of
* subscriber entries using the common memory manager.
*
* @description
* Using this function to free a publisher context will also free its list of
* subscribers, which will cause subscribers to no longer receive events from
* the publisher context's event class.
*
* @param[in] publisher address of a pointer to a publisher context
*
* @return
* SL_STATUS_OK if successful, otherwise an error code is returned.
******************************************************************************/
sl_status_t sl_event_publisher_free(sl_event_publisher_t *publisher);
/*******************************************************************************
* @brief
* Get the size of the event structure.
*
* @return Size of the event structure.
******************************************************************************/
size_t sl_event_get_size(void);
/*******************************************************************************
* @brief
* Allocate the event structure to the heap using the common memory
* manager with a long-term lifespan.
*
* @param[in] event address of a pointer to an event struct
*
* @return
* SL_STATUS_OK if successful, otherwise an error code is returned.
******************************************************************************/
sl_status_t sl_event_alloc(sl_event_t **event);
/*******************************************************************************
* @brief
* Free an event structure from the heap using the common memory manager.
*
* @note
* Freeing an event structure that has not yet been processed by all
* subscribers will
*
* @param[in] event address of a pointer to an event struct
*
* @return
* SL_STATUS_OK if successful, otherwise an error code is returned.
******************************************************************************/
sl_status_t sl_event_free(sl_event_t *event);
/** @} (end addtogroup event-system) */
#ifdef __cplusplus
}
#endif
#endif /* SL_EVENT_SYSTEM_H */