|  | /* | 
|  | * Copyright (c) 2019 Peter Bigot Consulting, LLC | 
|  | * Copyright (c) 2020 Nordic Semiconductor ASA | 
|  | * | 
|  | * SPDX-License-Identifier: Apache-2.0 | 
|  | */ | 
|  |  | 
|  | #ifndef ZEPHYR_INCLUDE_SYS_NOTIFY_H_ | 
|  | #define ZEPHYR_INCLUDE_SYS_NOTIFY_H_ | 
|  |  | 
|  | #include <kernel.h> | 
|  | #include <zephyr/types.h> | 
|  |  | 
|  | #ifdef __cplusplus | 
|  | extern "C" { | 
|  | #endif | 
|  |  | 
|  | struct sys_notify; | 
|  |  | 
|  | /* | 
|  | * Flag value that overwrites the method field when the operation has | 
|  | * completed. | 
|  | */ | 
|  | #define SYS_NOTIFY_METHOD_COMPLETED 0 | 
|  |  | 
|  | /* | 
|  | * Indicates that no notification will be provided. | 
|  | * | 
|  | * Callers must check for completions using | 
|  | * sys_notify_fetch_result(). | 
|  | * | 
|  | * See sys_notify_init_spinwait(). | 
|  | */ | 
|  | #define SYS_NOTIFY_METHOD_SPINWAIT 1 | 
|  |  | 
|  | /* | 
|  | * Select notification through @ref k_poll signal | 
|  | * | 
|  | * See sys_notify_init_signal(). | 
|  | */ | 
|  | #define SYS_NOTIFY_METHOD_SIGNAL 2 | 
|  |  | 
|  | /* | 
|  | * Select notification through a user-provided callback. | 
|  | * | 
|  | * See sys_notify_init_callback(). | 
|  | */ | 
|  | #define SYS_NOTIFY_METHOD_CALLBACK 3 | 
|  |  | 
|  | #define SYS_NOTIFY_METHOD_MASK 0x03U | 
|  | #define SYS_NOTIFY_METHOD_POS 0 | 
|  |  | 
|  | /** | 
|  | * @brief Identify the region of sys_notify flags available for | 
|  | * containing services. | 
|  | * | 
|  | * Bits of the flags field of the sys_notify structure at and above | 
|  | * this position may be used by extensions to the sys_notify | 
|  | * structure. | 
|  | * | 
|  | * These bits are intended for use by containing service | 
|  | * implementations to record client-specific information.  The bits | 
|  | * are cleared by sys_notify_validate().  Use of these does not | 
|  | * imply that the flags field becomes public API. | 
|  | */ | 
|  | #define SYS_NOTIFY_EXTENSION_POS 2 | 
|  |  | 
|  | /* | 
|  | * Mask isolating the bits of sys_notify::flags that are available | 
|  | * for extension. | 
|  | */ | 
|  | #define SYS_NOTIFY_EXTENSION_MASK (~BIT_MASK(SYS_NOTIFY_EXTENSION_POS)) | 
|  |  | 
|  | /** | 
|  | * @defgroup sys_notify_apis Asynchronous Notification APIs | 
|  | * @ingroup kernel_apis | 
|  | * @{ | 
|  | */ | 
|  |  | 
|  | /** | 
|  | * @brief Generic signature used to notify of result completion by | 
|  | * callback. | 
|  | * | 
|  | * Functions with this role may be invoked from any context including | 
|  | * pre-kernel, ISR, or cooperative or pre-emptible threads. | 
|  | * Compatible functions must be isr-ok and not sleep. | 
|  | * | 
|  | * Parameters that should generally be passed to such functions include: | 
|  | * | 
|  | * * a pointer to a specific client request structure, i.e. the one | 
|  | *   that contains the sys_notify structure. | 
|  | * * the result of the operation, either as passed to | 
|  | *   sys_notify_finalize() or extracted afterwards using | 
|  | *   sys_notify_fetch_result().  Expected values are | 
|  | *   service-specific, but the value shall be non-negative if the | 
|  | *   operation succeeded, and negative if the operation failed. | 
|  | */ | 
|  | typedef void (*sys_notify_generic_callback)(); | 
|  |  | 
|  | /** | 
|  | * @brief State associated with notification for an asynchronous | 
|  | * operation. | 
|  | * | 
|  | * Objects of this type are allocated by a client, which must use an | 
|  | * initialization function (e.g. sys_notify_init_signal()) to | 
|  | * configure them.  Generally the structure is a member of a | 
|  | * service-specific client structure, such as onoff_client. | 
|  | * | 
|  | * Control of the containing object transfers to the service provider | 
|  | * when a pointer to the object is passed to a service function that | 
|  | * is documented to take control of the object, such as | 
|  | * onoff_service_request().  While the service provider controls the | 
|  | * object the client must not change any object fields.  Control | 
|  | * reverts to the client: | 
|  | * * if the call to the service API returns an error; | 
|  | * * when operation completion is posted.  This may occur before the | 
|  | *   call to the service API returns. | 
|  | * | 
|  | * Operation completion is technically posted when the flags field is | 
|  | * updated so that sys_notify_fetch_result() returns success.  This | 
|  | * will happen before the signal is posted or callback is invoked. | 
|  | * Note that although the manager will no longer reference the | 
|  | * sys_notify object past this point, the containing object may have | 
|  | * state that will be referenced within the callback.  Where callbacks | 
|  | * are used control of the containing object does not revert to the | 
|  | * client until the callback has been invoked.  (Re-use within the | 
|  | * callback is explicitly permitted.) | 
|  | * | 
|  | * After control has reverted to the client the notify object must be | 
|  | * reinitialized for the next operation. | 
|  | * | 
|  | * The content of this structure is not public API to clients: all | 
|  | * configuration and inspection should be done with functions like | 
|  | * sys_notify_init_callback() and sys_notify_fetch_result(). | 
|  | * However, services that use this structure may access certain | 
|  | * fields directly. | 
|  | */ | 
|  | struct sys_notify { | 
|  | union method { | 
|  | /* Pointer to signal used to notify client. | 
|  | * | 
|  | * The signal value corresponds to the res parameter | 
|  | * of sys_notify_callback. | 
|  | */ | 
|  | struct k_poll_signal *signal; | 
|  |  | 
|  | /* Generic callback function for callback notification. */ | 
|  | sys_notify_generic_callback callback; | 
|  | } method; | 
|  |  | 
|  | /* | 
|  | * Flags recording information about the operation. | 
|  | * | 
|  | * Bits below SYS_NOTIFY_EXTENSION_POS are initialized by | 
|  | * async notify API init functions like | 
|  | * sys_notify_init_callback(), and must not by modified by | 
|  | * extensions or client code. | 
|  | * | 
|  | * Bits at and above SYS_NOTIFY_EXTENSION_POS are available | 
|  | * for use by service extensions while the containing object | 
|  | * is managed by the service.  They are not for client use, | 
|  | * are zeroed by the async notify API init functions, and will | 
|  | * be zeroed by sys_notify_finalize(). | 
|  | */ | 
|  | uint32_t volatile flags; | 
|  |  | 
|  | /* | 
|  | * The result of the operation. | 
|  | * | 
|  | * This is the value that was (or would be) passed to the | 
|  | * async infrastructure.  This field is the sole record of | 
|  | * success or failure for spin-wait synchronous operations. | 
|  | */ | 
|  | int volatile result; | 
|  | }; | 
|  |  | 
|  | /** @internal */ | 
|  | static inline uint32_t sys_notify_get_method(const struct sys_notify *notify) | 
|  | { | 
|  | uint32_t method = notify->flags >> SYS_NOTIFY_METHOD_POS; | 
|  |  | 
|  | return method & SYS_NOTIFY_METHOD_MASK; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @brief Validate and initialize the notify structure. | 
|  | * | 
|  | * This should be invoked at the start of any service-specific | 
|  | * configuration validation.  It ensures that the basic asynchronous | 
|  | * notification configuration is consistent, and clears the result. | 
|  | * | 
|  | * Note that this function does not validate extension bits (zeroed by | 
|  | * async notify API init functions like sys_notify_init_callback()). | 
|  | * It may fail to recognize that an uninitialized structure has been | 
|  | * passed because only method bits of flags are tested against method | 
|  | * settings.  To reduce the chance of accepting an uninititalized | 
|  | * operation service validation of structures that contain an | 
|  | * sys_notify instance should confirm that the extension bits are | 
|  | * set or cleared as expected. | 
|  | * | 
|  | * @retval 0 on successful validation and reinitialization | 
|  | * @retval -EINVAL if the configuration is not valid. | 
|  | */ | 
|  | int sys_notify_validate(struct sys_notify *notify); | 
|  |  | 
|  | /** | 
|  | * @brief Record and signal the operation completion. | 
|  | * | 
|  | * @param notify pointer to the notification state structure. | 
|  | * | 
|  | * @param res the result of the operation.  Expected values are | 
|  | * service-specific, but the value shall be non-negative if the | 
|  | * operation succeeded, and negative if the operation failed. | 
|  | * | 
|  | * @return If the notification is to be done by callback this returns | 
|  | * the generic version of the function to be invoked.  The caller must | 
|  | * immediately invoke that function with whatever arguments are | 
|  | * expected by the callback.  If notification is by spin-wait or | 
|  | * signal, the notification has been completed by the point this | 
|  | * function returns, and a null pointer is returned. | 
|  | */ | 
|  | sys_notify_generic_callback sys_notify_finalize(struct sys_notify *notify, | 
|  | int res); | 
|  |  | 
|  | /** | 
|  | * @brief Check for and read the result of an asynchronous operation. | 
|  | * | 
|  | * @param notify pointer to the object used to specify asynchronous | 
|  | * function behavior and store completion information. | 
|  | * | 
|  | * @param result pointer to storage for the result of the operation. | 
|  | * The result is stored only if the operation has completed. | 
|  | * | 
|  | * @retval 0 if the operation has completed. | 
|  | * @retval -EAGAIN if the operation has not completed. | 
|  | */ | 
|  | static inline int sys_notify_fetch_result(const struct sys_notify *notify, | 
|  | int *result) | 
|  | { | 
|  | __ASSERT_NO_MSG(notify != NULL); | 
|  | __ASSERT_NO_MSG(result != NULL); | 
|  | int rv = -EAGAIN; | 
|  |  | 
|  | if (sys_notify_get_method(notify) == SYS_NOTIFY_METHOD_COMPLETED) { | 
|  | rv = 0; | 
|  | *result = notify->result; | 
|  | } | 
|  |  | 
|  | return rv; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @brief Initialize a notify object for spin-wait notification. | 
|  | * | 
|  | * Clients that use this initialization receive no asynchronous | 
|  | * notification, and instead must periodically check for completion | 
|  | * using sys_notify_fetch_result(). | 
|  | * | 
|  | * On completion of the operation the client object must be | 
|  | * reinitialized before it can be re-used. | 
|  | * | 
|  | * @param notify pointer to the notification configuration object. | 
|  | */ | 
|  | static inline void sys_notify_init_spinwait(struct sys_notify *notify) | 
|  | { | 
|  | __ASSERT_NO_MSG(notify != NULL); | 
|  |  | 
|  | *notify = (struct sys_notify){ | 
|  | .flags = SYS_NOTIFY_METHOD_SPINWAIT, | 
|  | }; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @brief Initialize a notify object for (k_poll) signal notification. | 
|  | * | 
|  | * Clients that use this initialization will be notified of the | 
|  | * completion of operations through the provided signal. | 
|  | * | 
|  | * On completion of the operation the client object must be | 
|  | * reinitialized before it can be re-used. | 
|  | * | 
|  | * @note | 
|  | *   This capability is available only when @kconfig{CONFIG_POLL} is | 
|  | *   selected. | 
|  | * | 
|  | * @param notify pointer to the notification configuration object. | 
|  | * | 
|  | * @param sigp pointer to the signal to use for notification.  The | 
|  | * value must not be null.  The signal must be reset before the client | 
|  | * object is passed to the on-off service API. | 
|  | */ | 
|  | static inline void sys_notify_init_signal(struct sys_notify *notify, | 
|  | struct k_poll_signal *sigp) | 
|  | { | 
|  | __ASSERT_NO_MSG(notify != NULL); | 
|  | __ASSERT_NO_MSG(sigp != NULL); | 
|  |  | 
|  | *notify = (struct sys_notify){ | 
|  | .method = { | 
|  | .signal = sigp, | 
|  | }, | 
|  | .flags = SYS_NOTIFY_METHOD_SIGNAL, | 
|  | }; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @brief Initialize a notify object for callback notification. | 
|  | * | 
|  | * Clients that use this initialization will be notified of the | 
|  | * completion of operations through the provided callback.  Note that | 
|  | * callbacks may be invoked from various contexts depending on the | 
|  | * specific service; see @ref sys_notify_generic_callback. | 
|  | * | 
|  | * On completion of the operation the client object must be | 
|  | * reinitialized before it can be re-used. | 
|  | * | 
|  | * @param notify pointer to the notification configuration object. | 
|  | * | 
|  | * @param handler a function pointer to use for notification. | 
|  | */ | 
|  | static inline void sys_notify_init_callback(struct sys_notify *notify, | 
|  | sys_notify_generic_callback handler) | 
|  | { | 
|  | __ASSERT_NO_MSG(notify != NULL); | 
|  | __ASSERT_NO_MSG(handler != NULL); | 
|  |  | 
|  | *notify = (struct sys_notify){ | 
|  | .method = { | 
|  | .callback = handler, | 
|  | }, | 
|  | .flags = SYS_NOTIFY_METHOD_CALLBACK, | 
|  | }; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @brief Detect whether a particular notification uses a callback. | 
|  | * | 
|  | * The generic handler does not capture the signature expected by the | 
|  | * callback, and the translation to a service-specific callback must | 
|  | * be provided by the service.  This check allows abstracted services | 
|  | * to reject callback notification requests when the service doesn't | 
|  | * provide a translation function. | 
|  | * | 
|  | * @return true if and only if a callback is to be used for notification. | 
|  | */ | 
|  | static inline bool sys_notify_uses_callback(const struct sys_notify *notify) | 
|  | { | 
|  | __ASSERT_NO_MSG(notify != NULL); | 
|  |  | 
|  | return sys_notify_get_method(notify) == SYS_NOTIFY_METHOD_CALLBACK; | 
|  | } | 
|  |  | 
|  | /** @} */ | 
|  |  | 
|  | #ifdef __cplusplus | 
|  | } | 
|  | #endif | 
|  |  | 
|  | #endif /* ZEPHYR_INCLUDE_SYS_NOTIFY_H_ */ |