mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2026-10-09 09:27:18 +00:00
* Improve documentation for view_port/view_dispatcher functions Add information about how some callbacks will be invoked, as well as which thread the invocation will occur on (this was motivated by some difficulty when attempting to reasoning about thread safety, as part of trying to write some FFI bindings). * Fix some spelling errors
357 lines
12 KiB
C
357 lines
12 KiB
C
/**
|
|
* @file event_loop.h
|
|
* @brief Furi Event Loop
|
|
*
|
|
* This module is designed to handle application event loop in fully
|
|
* asynchronous, reactive nature. On the low level this modules is
|
|
* inspired by epoll/kqueue concept, on the high level by asyncio
|
|
* event loop.
|
|
*
|
|
* This module is trying to best fit into Furi OS, so we don't
|
|
* provide any compatibility with other event driven APIs. But
|
|
* programming concepts are the same, except some runtime
|
|
* limitations from our side.
|
|
*
|
|
* @warning Only ONE instance of FuriEventLoop per thread is possible. ALL FuriEventLoop
|
|
* functions MUST be called from the same thread that the instance was created in.
|
|
*/
|
|
#pragma once
|
|
|
|
#include "base.h"
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/**
|
|
* @brief Enumeration of event types, flags and masks.
|
|
*
|
|
* Only one event direction (In or Out) can be used per subscription.
|
|
* An object can have no more than one subscription for each direction.
|
|
*
|
|
* Additional flags that modify the behaviour can be
|
|
* set using the bitwise OR operation (see flag description).
|
|
*/
|
|
typedef enum {
|
|
/**
|
|
* @brief Subscribe to In events.
|
|
*
|
|
* In events occur on the following conditions:
|
|
* - One or more items were inserted into a FuriMessageQueue,
|
|
* - Enough data has been written to a FuriStreamBuffer,
|
|
* - A FuriSemaphore has been released at least once,
|
|
* - A FuriMutex has been released.
|
|
*/
|
|
FuriEventLoopEventIn = 0x00000001U,
|
|
/**
|
|
* @brief Subscribe to Out events.
|
|
*
|
|
* Out events occur on the following conditions:
|
|
* - One or more items were removed from a FuriMessageQueue,
|
|
* - Any amount of data has been read out of a FuriStreamBuffer,
|
|
* - A FuriSemaphore has been acquired at least once,
|
|
* - A FuriMutex has been acquired.
|
|
*/
|
|
FuriEventLoopEventOut = 0x00000002U,
|
|
/**
|
|
* @brief Special value containing the event direction bits, used internally.
|
|
*/
|
|
FuriEventLoopEventMask = 0x00000003U,
|
|
/**
|
|
* @brief Use edge triggered events.
|
|
*
|
|
* By default, level triggered events are used. A level above zero
|
|
* is reported based on the following conditions:
|
|
*
|
|
* In events:
|
|
* - a FuriMessageQueue contains one or more items,
|
|
* - a FuriStreamBuffer contains one or more bytes,
|
|
* - a FuriSemaphore can be acquired at least once,
|
|
* - a FuriMutex can be acquired.
|
|
*
|
|
* Out events:
|
|
* - a FuriMessageQueue has at least one item of free space,
|
|
* - a FuriStreamBuffer has at least one byte of free space,
|
|
* - a FuriSemaphore has been acquired at least once,
|
|
* - a FuriMutex has been acquired.
|
|
*
|
|
* If this flag is NOT set, the event will be generated repeatedly until
|
|
* the level becomes zero (e.g. all items have been removed from
|
|
* a FuriMessageQueue in case of the "In" event, etc.)
|
|
*
|
|
* If this flag IS set, then the above check is skipped and the event
|
|
* is generated ONLY when a change occurs, with the event direction
|
|
* (In or Out) taken into account.
|
|
*/
|
|
FuriEventLoopEventFlagEdge = 0x00000004U,
|
|
/**
|
|
* @brief Automatically unsubscribe from events after one time.
|
|
*
|
|
* By default, events will be generated each time the specified conditions
|
|
* have been met. If this flag IS set, the event subscription will be cancelled
|
|
* upon the first occurred event and no further events will be generated.
|
|
*/
|
|
FuriEventLoopEventFlagOnce = 0x00000008U,
|
|
/**
|
|
* @brief Special value containing the event flag bits, used internally.
|
|
*/
|
|
FuriEventLoopEventFlagMask = 0xFFFFFFFCU,
|
|
/**
|
|
* @brief Special value to force the enum to 32-bit values.
|
|
*/
|
|
FuriEventLoopEventReserved = UINT32_MAX,
|
|
} FuriEventLoopEvent;
|
|
|
|
/** Anonymous message queue type */
|
|
typedef struct FuriEventLoop FuriEventLoop;
|
|
|
|
/** Allocate Event Loop instance
|
|
*
|
|
* Couple things to keep in mind:
|
|
* - You can have 1 event_loop per 1 thread
|
|
* - You can not use event_loop instance in the other thread
|
|
* - Do not use blocking API to query object delegated to Event Loop
|
|
*
|
|
* @return The Event Loop instance
|
|
*/
|
|
FuriEventLoop* furi_event_loop_alloc(void);
|
|
|
|
/** Free Event Loop instance
|
|
*
|
|
* @param instance The Event Loop instance
|
|
*/
|
|
void furi_event_loop_free(FuriEventLoop* instance);
|
|
|
|
/** Continuously poll for events
|
|
*
|
|
* Can be stopped with `furi_event_loop_stop`
|
|
*
|
|
* @param instance The Event Loop instance
|
|
*/
|
|
void furi_event_loop_run(FuriEventLoop* instance);
|
|
|
|
/** Stop Event Loop instance
|
|
*
|
|
* @param instance The Event Loop instance
|
|
*/
|
|
void furi_event_loop_stop(FuriEventLoop* instance);
|
|
|
|
/*
|
|
* Tick related API
|
|
*/
|
|
|
|
/** Tick callback type
|
|
*
|
|
* @param context The context for callback
|
|
*/
|
|
typedef void (*FuriEventLoopTickCallback)(void* context);
|
|
|
|
/** Set Event Loop tick callback
|
|
*
|
|
* Tick callback is called periodically after specified inactivity time.
|
|
* It acts like a low-priority timer: it will only fire if there is time
|
|
* left after processing the synchronization primitives and the regular timers.
|
|
* Therefore, it is not monotonic: ticks will be skipped if the event loop is busy.
|
|
*
|
|
* @param instance The Event Loop instance
|
|
* @param[in] interval The tick interval
|
|
* @param[in] callback The callback to call
|
|
* @param context The context for callback
|
|
*/
|
|
void furi_event_loop_tick_set(
|
|
FuriEventLoop* instance,
|
|
uint32_t interval,
|
|
FuriEventLoopTickCallback callback,
|
|
void* context);
|
|
|
|
/*
|
|
* Deferred function call API
|
|
*/
|
|
|
|
/**
|
|
* @brief Timer callback type for functions to be called in a deferred manner.
|
|
*
|
|
* @param[in,out] context pointer to a user-specific object that was provided during
|
|
* furi_event_loop_pend_callback() call
|
|
*/
|
|
typedef void (*FuriEventLoopPendingCallback)(void* context);
|
|
|
|
/**
|
|
* @brief Call a function when all preceding timer commands are processed
|
|
*
|
|
* This function may be useful to call another function when the event loop has been started.
|
|
*
|
|
* @param[in,out] instance pointer to the current FuriEventLoop instance
|
|
* @param[in] callback pointer to the callback to be executed when previous commands have been processed
|
|
* @param[in,out] context pointer to a user-specific object (will be passed to the callback)
|
|
*/
|
|
void furi_event_loop_pend_callback(
|
|
FuriEventLoop* instance,
|
|
FuriEventLoopPendingCallback callback,
|
|
void* context);
|
|
|
|
/*
|
|
* Event subscription/notification APIs
|
|
*/
|
|
|
|
typedef void FuriEventLoopObject;
|
|
|
|
/** Callback type for event loop events
|
|
*
|
|
* @param object The object that triggered the event
|
|
* @param context The context that was provided upon subscription
|
|
*/
|
|
typedef void (*FuriEventLoopEventCallback)(FuriEventLoopObject* object, void* context);
|
|
|
|
/** Callback type for event loop thread flag events
|
|
*
|
|
* @param context The context that was provided upon subscription
|
|
*/
|
|
typedef void (*FuriEventLoopThreadFlagsCallback)(void* context);
|
|
|
|
/** Opaque event flag type */
|
|
typedef struct FuriEventFlag FuriEventFlag;
|
|
|
|
/** Subscribe to event flag events
|
|
*
|
|
* @warning you can only have one subscription for one event type.
|
|
*
|
|
* @param instance The Event Loop instance
|
|
* @param event_flag The event flag to add
|
|
* @param[in] event The Event Loop event to trigger on
|
|
* @param[in] callback The callback to call on event
|
|
* @param context The context for callback
|
|
*/
|
|
|
|
void furi_event_loop_subscribe_event_flag(
|
|
FuriEventLoop* instance,
|
|
FuriEventFlag* event_flag,
|
|
FuriEventLoopEvent event,
|
|
FuriEventLoopEventCallback callback,
|
|
void* context);
|
|
|
|
/** Opaque message queue type */
|
|
typedef struct FuriMessageQueue FuriMessageQueue;
|
|
|
|
/** Subscribe to message queue events
|
|
*
|
|
* @warning you can only have one subscription for one event type.
|
|
*
|
|
* @param instance The Event Loop instance
|
|
* @param message_queue The message queue to add
|
|
* @param[in] event The Event Loop event to trigger on
|
|
* @param[in] callback The callback to call on event
|
|
* @param context The context for callback
|
|
*/
|
|
void furi_event_loop_subscribe_message_queue(
|
|
FuriEventLoop* instance,
|
|
FuriMessageQueue* message_queue,
|
|
FuriEventLoopEvent event,
|
|
FuriEventLoopEventCallback callback,
|
|
void* context);
|
|
|
|
/** Opaque stream buffer type */
|
|
typedef struct FuriStreamBuffer FuriStreamBuffer;
|
|
|
|
/** Subscribe to stream buffer events
|
|
*
|
|
* @warning you can only have one subscription for one event type.
|
|
*
|
|
* @param instance The Event Loop instance
|
|
* @param stream_buffer The stream buffer to add
|
|
* @param[in] event The Event Loop event to trigger on
|
|
* @param[in] callback The callback to call on event
|
|
* @param context The context for callback
|
|
*/
|
|
void furi_event_loop_subscribe_stream_buffer(
|
|
FuriEventLoop* instance,
|
|
FuriStreamBuffer* stream_buffer,
|
|
FuriEventLoopEvent event,
|
|
FuriEventLoopEventCallback callback,
|
|
void* context);
|
|
|
|
/** Opaque semaphore type */
|
|
typedef struct FuriSemaphore FuriSemaphore;
|
|
|
|
/** Subscribe to semaphore events
|
|
*
|
|
* @warning you can only have one subscription for one event type.
|
|
*
|
|
* @param instance The Event Loop instance
|
|
* @param semaphore The semaphore to add
|
|
* @param[in] event The Event Loop event to trigger on
|
|
* @param[in] callback The callback to call on event
|
|
* @param context The context for callback
|
|
*/
|
|
void furi_event_loop_subscribe_semaphore(
|
|
FuriEventLoop* instance,
|
|
FuriSemaphore* semaphore,
|
|
FuriEventLoopEvent event,
|
|
FuriEventLoopEventCallback callback,
|
|
void* context);
|
|
|
|
/** Opaque mutex type */
|
|
typedef struct FuriMutex FuriMutex;
|
|
|
|
/** Subscribe to mutex events
|
|
*
|
|
* @warning you can only have one subscription for one event type.
|
|
*
|
|
* @param instance The Event Loop instance
|
|
* @param mutex The mutex to add
|
|
* @param[in] event The Event Loop event to trigger on
|
|
* @param[in] callback The callback to call on event
|
|
* @param context The context for callback
|
|
*/
|
|
void furi_event_loop_subscribe_mutex(
|
|
FuriEventLoop* instance,
|
|
FuriMutex* mutex,
|
|
FuriEventLoopEvent event,
|
|
FuriEventLoopEventCallback callback,
|
|
void* context);
|
|
|
|
/** Subscribe to thread flag events of the current thread
|
|
*
|
|
* @param instance The Event Loop instance
|
|
* @param callback The callback to call when a flag has been set
|
|
* @param context The context for callback
|
|
*/
|
|
void furi_event_loop_subscribe_thread_flags(
|
|
FuriEventLoop* instance,
|
|
FuriEventLoopThreadFlagsCallback callback,
|
|
void* context);
|
|
|
|
/** Unsubscribe from thread flag events of the current thread
|
|
*
|
|
* @param instance The Event Loop instance
|
|
*/
|
|
void furi_event_loop_unsubscribe_thread_flags(FuriEventLoop* instance);
|
|
|
|
/** Unsubscribe from events (common)
|
|
*
|
|
* @param instance The Event Loop instance
|
|
* @param object The object to unsubscribe from
|
|
*/
|
|
void furi_event_loop_unsubscribe(FuriEventLoop* instance, FuriEventLoopObject* object);
|
|
|
|
/**
|
|
* @brief Checks if the loop is subscribed to an object of any kind
|
|
*
|
|
* @param instance Event Loop instance
|
|
* @param object Object to check
|
|
*/
|
|
bool furi_event_loop_is_subscribed(FuriEventLoop* instance, FuriEventLoopObject* object);
|
|
|
|
/**
|
|
* @brief Convenience function for `if(is_subscribed()) unsubscribe()`
|
|
*/
|
|
static inline void
|
|
furi_event_loop_maybe_unsubscribe(FuriEventLoop* instance, FuriEventLoopObject* object) {
|
|
if(furi_event_loop_is_subscribed(instance, object))
|
|
furi_event_loop_unsubscribe(instance, object);
|
|
}
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|