mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-07-29 02:08:10 -07:00
FurEventLoop: add support for FuriEventFlag, simplify API (#3958)
* Core: event_flag, removing duplicate code * event_loop: add support furi_event_flags * Examples: add missing free in event loop examples * Furi: fix event flag * Sync api symbols * Unit_test: evet_loop_event_flags * Fix multiple waiting list elements handling * Unit_test: add event_loop_event_flag test * FURI: event_loop add restrictions * Fix multiple waiting lists items for good * Improve FuriEventLoop unit tests * Abolish callback return value * Remove return value from callback signature * Use bool level value instead of int32_t * Add unit tests for FuriStreamBuffer * Add unit tests for FuriSemaphore * Speed up test execution * Improve docs * Add a stub for furi os-level primitives * Add more checks for edge cases * Allow event loop notification from ISR * Bump api version Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com> Co-authored-by: Georgii Surkov <georgii.surkov@outlook.com> Co-authored-by: Georgii Surkov <37121527+gsurkov@users.noreply.github.com>
This commit is contained in:
+85
-50
@@ -101,36 +101,39 @@ void furi_event_loop_free(FuriEventLoop* instance) {
|
||||
}
|
||||
|
||||
static inline FuriEventLoopProcessStatus
|
||||
furi_event_loop_poll_process_level_event(FuriEventLoopItem* item) {
|
||||
if(!item->contract->get_level(item->object, item->event)) {
|
||||
return FuriEventLoopProcessStatusComplete;
|
||||
} else if(item->callback(item->object, item->callback_context)) {
|
||||
return FuriEventLoopProcessStatusIncomplete;
|
||||
} else {
|
||||
return FuriEventLoopProcessStatusAgain;
|
||||
}
|
||||
furi_event_loop_process_edge_event(FuriEventLoopItem* item) {
|
||||
FuriEventLoopProcessStatus status = FuriEventLoopProcessStatusComplete;
|
||||
item->callback(item->object, item->callback_context);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static inline FuriEventLoopProcessStatus
|
||||
furi_event_loop_poll_process_edge_event(FuriEventLoopItem* item) {
|
||||
if(item->callback(item->object, item->callback_context)) {
|
||||
return FuriEventLoopProcessStatusComplete;
|
||||
} else {
|
||||
return FuriEventLoopProcessStatusAgain;
|
||||
furi_event_loop_process_level_event(FuriEventLoopItem* item) {
|
||||
FuriEventLoopProcessStatus status = FuriEventLoopProcessStatusComplete;
|
||||
if(item->contract->get_level(item->object, item->event)) {
|
||||
item->callback(item->object, item->callback_context);
|
||||
|
||||
if(item->contract->get_level(item->object, item->event)) {
|
||||
status = FuriEventLoopProcessStatusIncomplete;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static inline FuriEventLoopProcessStatus
|
||||
furi_event_loop_poll_process_event(FuriEventLoop* instance, FuriEventLoopItem* item) {
|
||||
furi_event_loop_process_event(FuriEventLoop* instance, FuriEventLoopItem* item) {
|
||||
FuriEventLoopProcessStatus status;
|
||||
|
||||
if(item->event & FuriEventLoopEventFlagOnce) {
|
||||
furi_event_loop_unsubscribe(instance, item->object);
|
||||
}
|
||||
|
||||
if(item->event & FuriEventLoopEventFlagEdge) {
|
||||
status = furi_event_loop_poll_process_edge_event(item);
|
||||
status = furi_event_loop_process_edge_event(item);
|
||||
} else {
|
||||
status = furi_event_loop_poll_process_level_event(item);
|
||||
status = furi_event_loop_process_level_event(item);
|
||||
}
|
||||
|
||||
if(item->owner == NULL) {
|
||||
@@ -140,7 +143,7 @@ static inline FuriEventLoopProcessStatus
|
||||
return status;
|
||||
}
|
||||
|
||||
static void furi_event_loop_process_waiting_list(FuriEventLoop* instance) {
|
||||
static inline FuriEventLoopItem* furi_event_loop_get_waiting_item(FuriEventLoop* instance) {
|
||||
FuriEventLoopItem* item = NULL;
|
||||
|
||||
FURI_CRITICAL_ENTER();
|
||||
@@ -152,27 +155,42 @@ static void furi_event_loop_process_waiting_list(FuriEventLoop* instance) {
|
||||
|
||||
FURI_CRITICAL_EXIT();
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
static inline void furi_event_loop_sync_flags(FuriEventLoop* instance) {
|
||||
FURI_CRITICAL_ENTER();
|
||||
|
||||
if(!WaitingList_empty_p(instance->waiting_list)) {
|
||||
xTaskNotifyIndexed(
|
||||
(TaskHandle_t)instance->thread_id,
|
||||
FURI_EVENT_LOOP_FLAG_NOTIFY_INDEX,
|
||||
FuriEventLoopFlagEvent,
|
||||
eSetBits);
|
||||
}
|
||||
|
||||
FURI_CRITICAL_EXIT();
|
||||
}
|
||||
|
||||
static void furi_event_loop_process_waiting_list(FuriEventLoop* instance) {
|
||||
FuriEventLoopItem* item = furi_event_loop_get_waiting_item(instance);
|
||||
if(!item) return;
|
||||
|
||||
while(true) {
|
||||
FuriEventLoopProcessStatus ret = furi_event_loop_poll_process_event(instance, item);
|
||||
FuriEventLoopProcessStatus status = furi_event_loop_process_event(instance, item);
|
||||
|
||||
if(ret == FuriEventLoopProcessStatusComplete) {
|
||||
// Event processing complete, break from loop
|
||||
break;
|
||||
} else if(ret == FuriEventLoopProcessStatusIncomplete) {
|
||||
// Event processing incomplete more processing needed
|
||||
} else if(ret == FuriEventLoopProcessStatusAgain) { //-V547
|
||||
furi_event_loop_item_notify(item);
|
||||
break;
|
||||
// Unsubscribed from inside the callback, delete item
|
||||
} else if(ret == FuriEventLoopProcessStatusFreeLater) { //-V547
|
||||
furi_event_loop_item_free(item);
|
||||
break;
|
||||
} else {
|
||||
furi_crash();
|
||||
}
|
||||
if(status == FuriEventLoopProcessStatusComplete) {
|
||||
// Event processing complete, do nothing
|
||||
} else if(status == FuriEventLoopProcessStatusIncomplete) {
|
||||
// Event processing incomplete, put item back in waiting list
|
||||
furi_event_loop_item_notify(item);
|
||||
} else if(status == FuriEventLoopProcessStatusFreeLater) { //-V547
|
||||
// Unsubscribed from inside the callback, delete item
|
||||
furi_event_loop_item_free(item);
|
||||
} else {
|
||||
furi_crash();
|
||||
}
|
||||
|
||||
furi_event_loop_sync_flags(instance);
|
||||
}
|
||||
|
||||
static void furi_event_loop_restore_flags(FuriEventLoop* instance, uint32_t flags) {
|
||||
@@ -239,14 +257,28 @@ void furi_event_loop_run(FuriEventLoop* instance) {
|
||||
}
|
||||
}
|
||||
|
||||
static void furi_event_loop_notify(FuriEventLoop* instance, FuriEventLoopFlag flag) {
|
||||
if(FURI_IS_IRQ_MODE()) {
|
||||
BaseType_t yield = pdFALSE;
|
||||
|
||||
(void)xTaskNotifyIndexedFromISR(
|
||||
(TaskHandle_t)instance->thread_id,
|
||||
FURI_EVENT_LOOP_FLAG_NOTIFY_INDEX,
|
||||
flag,
|
||||
eSetBits,
|
||||
&yield);
|
||||
|
||||
portYIELD_FROM_ISR(yield);
|
||||
|
||||
} else {
|
||||
(void)xTaskNotifyIndexed(
|
||||
(TaskHandle_t)instance->thread_id, FURI_EVENT_LOOP_FLAG_NOTIFY_INDEX, flag, eSetBits);
|
||||
}
|
||||
}
|
||||
|
||||
void furi_event_loop_stop(FuriEventLoop* instance) {
|
||||
furi_check(instance);
|
||||
|
||||
xTaskNotifyIndexed(
|
||||
(TaskHandle_t)instance->thread_id,
|
||||
FURI_EVENT_LOOP_FLAG_NOTIFY_INDEX,
|
||||
FuriEventLoopFlagStop,
|
||||
eSetBits);
|
||||
furi_event_loop_notify(instance, FuriEventLoopFlagStop);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -268,11 +300,7 @@ void furi_event_loop_pend_callback(
|
||||
|
||||
PendingQueue_push_front(instance->pending_queue, item);
|
||||
|
||||
xTaskNotifyIndexed(
|
||||
(TaskHandle_t)instance->thread_id,
|
||||
FURI_EVENT_LOOP_FLAG_NOTIFY_INDEX,
|
||||
FuriEventLoopFlagPending,
|
||||
eSetBits);
|
||||
furi_event_loop_notify(instance, FuriEventLoopFlagPending);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -328,6 +356,17 @@ static void furi_event_loop_object_subscribe(
|
||||
* Public specialized subscription API
|
||||
*/
|
||||
|
||||
void furi_event_loop_subscribe_event_flag(
|
||||
FuriEventLoop* instance,
|
||||
FuriEventFlag* event_flag,
|
||||
FuriEventLoopEvent event,
|
||||
FuriEventLoopEventCallback callback,
|
||||
void* context) {
|
||||
extern const FuriEventLoopContract furi_event_flag_event_loop_contract;
|
||||
furi_event_loop_object_subscribe(
|
||||
instance, event_flag, &furi_event_flag_event_loop_contract, event, callback, context);
|
||||
}
|
||||
|
||||
void furi_event_loop_subscribe_message_queue(
|
||||
FuriEventLoop* instance,
|
||||
FuriMessageQueue* message_queue,
|
||||
@@ -491,11 +530,7 @@ static void furi_event_loop_item_notify(FuriEventLoopItem* instance) {
|
||||
|
||||
FURI_CRITICAL_EXIT();
|
||||
|
||||
xTaskNotifyIndexed(
|
||||
(TaskHandle_t)owner->thread_id,
|
||||
FURI_EVENT_LOOP_FLAG_NOTIFY_INDEX,
|
||||
FuriEventLoopFlagEvent,
|
||||
eSetBits);
|
||||
furi_event_loop_notify(owner, FuriEventLoopFlagEvent);
|
||||
}
|
||||
|
||||
static bool furi_event_loop_item_is_waiting(FuriEventLoopItem* instance) {
|
||||
|
||||
Reference in New Issue
Block a user