Skip to content

Commit

Permalink
[FL-3841] FuriEventLoop Pt.2 (flipperdevices#3703)
Browse files Browse the repository at this point in the history
* Abstract primitive type from main logic in FuriEventLoop
* Remove message_queue_i.h
* Add stream buffer support for event loop
* Add semaphore support for event loop
* Add temporary unit test workaround
* Make the linter happy
* Add mutex support for event loop
* Implement event subscription and unsubscription while the event loop is running
* Implement edge events
* Fix leftover logical errors
* Add event loop timer example application
* Implement flag-based edge trigger and one-shot mode
* Add event loop mutex example application
* Only notify the event loop if stream buffer is at or above its trigger level
* Reformat comments
* Add event loop stream buffer example application
* Add event loop multiple elements example application
* Improve event loop flag names
* Remove redundant signal handler as it is already handled by the event loop
* Refactor Power service, improve ViewHolder
* Use ViewHolder instead of ViewDispatcher in About app
* Enable ViewDispatcher queue on construction, deprecate view_dispatcher_enable_queue()
* Remove all invocations of view_dispatcher_enable_queue()
* Remove app-scened-template
* Remove missing library from target.json
* Port Accessor app to ViewHolder
* Make the linter happy
* Add example_view_holder application, update ViewHolder docs
* Add example_view_dispatcher application, update ViewDispatcher docs
* Replace FuriSemaphore with FuriApiLock, remove workaround delay
* Fix logical error
* Fix another logical error
* Use the sources directive to speed up compilation
* Use constant define macro
* Improve FuriEventLoop documentation
* Improve FuriEventLoop documentation once more
* Bump API Version
* Gui: remove redundant checks from ViewDispatcher
* Gui: remove dead ifs from ViewDispatcher

Co-authored-by: Silent <CookiePLMonster@users.noreply.github.com>
Co-authored-by: hedger <hedger@users.noreply.github.com>
Co-authored-by: あく <alleteam@gmail.com>
  • Loading branch information
4 people committed Aug 10, 2024
1 parent 1e5dd00 commit bf6c6c2
Show file tree
Hide file tree
Showing 104 changed files with 2,093 additions and 1,751 deletions.
54 changes: 26 additions & 28 deletions applications/debug/accessor/accessor_view_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,45 +5,49 @@
AccessorAppViewManager::AccessorAppViewManager() {
event_queue = furi_message_queue_alloc(10, sizeof(AccessorEvent));

view_dispatcher = view_dispatcher_alloc();
auto callback = cbc::obtain_connector(this, &AccessorAppViewManager::previous_view_callback);
view_holder = view_holder_alloc();
auto callback =
cbc::obtain_connector(this, &AccessorAppViewManager::view_holder_back_callback);

// allocate views
submenu = submenu_alloc();
add_view(ViewType::Submenu, submenu_get_view(submenu));

popup = popup_alloc();
add_view(ViewType::Popup, popup_get_view(popup));

gui = static_cast<Gui*>(furi_record_open(RECORD_GUI));
view_dispatcher_attach_to_gui(view_dispatcher, gui, ViewDispatcherTypeFullscreen);
// set back callback
view_holder_set_back_callback(view_holder, callback, NULL);

// set previous view callback for all views
view_set_previous_callback(submenu_get_view(submenu), callback);
view_set_previous_callback(popup_get_view(popup), callback);
gui = static_cast<Gui*>(furi_record_open(RECORD_GUI));
view_holder_attach_to_gui(view_holder, gui);
}

AccessorAppViewManager::~AccessorAppViewManager() {
// remove views
view_dispatcher_remove_view(
view_dispatcher, static_cast<uint32_t>(AccessorAppViewManager::ViewType::Submenu));
view_dispatcher_remove_view(
view_dispatcher, static_cast<uint32_t>(AccessorAppViewManager::ViewType::Popup));

// remove current view
view_holder_set_view(view_holder, NULL);
// free view modules
furi_record_close(RECORD_GUI);
submenu_free(submenu);
popup_free(popup);

// free dispatcher
view_dispatcher_free(view_dispatcher);

// free view holder
view_holder_free(view_holder);
// free event queue
furi_message_queue_free(event_queue);
}

void AccessorAppViewManager::switch_to(ViewType type) {
view_dispatcher_switch_to_view(view_dispatcher, static_cast<uint32_t>(type));
View* view;

switch(type) {
case ViewType::Submenu:
view = submenu_get_view(submenu);
break;
case ViewType::Popup:
view = popup_get_view(popup);
break;
default:
furi_crash();
}

view_holder_set_view(view_holder, view);
}

Submenu* AccessorAppViewManager::get_submenu() {
Expand All @@ -65,16 +69,10 @@ void AccessorAppViewManager::send_event(AccessorEvent* event) {
furi_check(result == FuriStatusOk);
}

uint32_t AccessorAppViewManager::previous_view_callback(void*) {
void AccessorAppViewManager::view_holder_back_callback(void*) {
if(event_queue != NULL) {
AccessorEvent event;
event.type = AccessorEvent::Type::Back;
send_event(&event);
}

return VIEW_IGNORE;
}

void AccessorAppViewManager::add_view(ViewType view_type, View* view) {
view_dispatcher_add_view(view_dispatcher, static_cast<uint32_t>(view_type), view);
}
8 changes: 3 additions & 5 deletions applications/debug/accessor/accessor_view_manager.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#pragma once
#include <furi.h>
#include <gui/view_dispatcher.h>
#include <gui/view_holder.h>
#include <gui/modules/submenu.h>
#include <gui/modules/popup.h>
#include "accessor_event.h"
Expand All @@ -10,7 +10,6 @@ class AccessorAppViewManager {
enum class ViewType : uint8_t {
Submenu,
Popup,
Tune,
};

FuriMessageQueue* event_queue;
Expand All @@ -27,11 +26,10 @@ class AccessorAppViewManager {
Popup* get_popup(void);

private:
ViewDispatcher* view_dispatcher;
Gui* gui;
ViewHolder* view_holder;

uint32_t previous_view_callback(void* context);
void add_view(ViewType view_type, View* view);
void view_holder_back_callback(void* context);

// view elements
Submenu* submenu;
Expand Down
1 change: 0 additions & 1 deletion applications/debug/battery_test_app/battery_test_app.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ BatteryTestApp* battery_test_alloc(void) {

// View dispatcher
app->view_dispatcher = view_dispatcher_alloc();
view_dispatcher_enable_queue(app->view_dispatcher);
view_dispatcher_set_event_callback_context(app->view_dispatcher, app);
view_dispatcher_set_tick_event_callback(
app->view_dispatcher, battery_test_battery_info_update_model, 500);
Expand Down
1 change: 0 additions & 1 deletion applications/debug/bt_debug_app/bt_debug_app.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ BtDebugApp* bt_debug_app_alloc(void) {

// View dispatcher
app->view_dispatcher = view_dispatcher_alloc();
view_dispatcher_enable_queue(app->view_dispatcher);
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);

// Views
Expand Down
1 change: 0 additions & 1 deletion applications/debug/crash_test/crash_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ CrashTest* crash_test_alloc(void) {

instance->gui = furi_record_open(RECORD_GUI);
instance->view_dispatcher = view_dispatcher_alloc();
view_dispatcher_enable_queue(instance->view_dispatcher);
view_dispatcher_attach_to_gui(
instance->view_dispatcher, instance->gui, ViewDispatcherTypeFullscreen);

Expand Down
1 change: 0 additions & 1 deletion applications/debug/display_test/display_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,6 @@ DisplayTest* display_test_alloc(void) {

instance->gui = furi_record_open(RECORD_GUI);
instance->view_dispatcher = view_dispatcher_alloc();
view_dispatcher_enable_queue(instance->view_dispatcher);
view_dispatcher_attach_to_gui(
instance->view_dispatcher, instance->gui, ViewDispatcherTypeFullscreen);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ static void view_port_input_callback(InputEvent* input_event, void* context) {
furi_message_queue_put(app->input_queue, input_event, 0);
}

static bool input_queue_callback(FuriMessageQueue* queue, void* context) {
static bool input_queue_callback(FuriEventLoopObject* object, void* context) {
FuriMessageQueue* queue = object;
EventLoopBlinkTestApp* app = context;

InputEvent event;
Expand Down Expand Up @@ -144,7 +145,7 @@ int32_t event_loop_blink_test_app(void* arg) {
gui_add_view_port(gui, view_port, GuiLayerFullscreen);

furi_event_loop_tick_set(app.event_loop, 500, event_loop_tick_callback, &app);
furi_event_loop_message_queue_subscribe(
furi_event_loop_subscribe_message_queue(
app.event_loop, app.input_queue, FuriEventLoopEventIn, input_queue_callback, &app);

furi_event_loop_run(app.event_loop);
Expand All @@ -154,7 +155,7 @@ int32_t event_loop_blink_test_app(void* arg) {

furi_record_close(RECORD_GUI);

furi_event_loop_message_queue_unsubscribe(app.event_loop, app.input_queue);
furi_event_loop_unsubscribe(app.event_loop, app.input_queue);
furi_message_queue_free(app.input_queue);

for(size_t i = 0; i < TIMER_COUNT; ++i) {
Expand Down
2 changes: 0 additions & 2 deletions applications/debug/file_browser_test/file_browser_app.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@ FileBrowserApp* file_browser_app_alloc(char* arg) {
app->dialogs = furi_record_open(RECORD_DIALOGS);

app->view_dispatcher = view_dispatcher_alloc();
view_dispatcher_enable_queue(app->view_dispatcher);

app->scene_manager = scene_manager_alloc(&file_browser_scene_handlers, app);

view_dispatcher_set_event_callback_context(app->view_dispatcher, app);
Expand Down
1 change: 0 additions & 1 deletion applications/debug/lfrfid_debug/lfrfid_debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ static LfRfidDebug* lfrfid_debug_alloc(void) {

app->view_dispatcher = view_dispatcher_alloc();
app->scene_manager = scene_manager_alloc(&lfrfid_debug_scene_handlers, app);
view_dispatcher_enable_queue(app->view_dispatcher);
view_dispatcher_set_event_callback_context(app->view_dispatcher, app);
view_dispatcher_set_custom_event_callback(
app->view_dispatcher, lfrfid_debug_custom_event_callback);
Expand Down
1 change: 0 additions & 1 deletion applications/debug/locale_test/locale_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ static LocaleTestApp* locale_test_alloc(void) {

// View dispatcher
app->view_dispatcher = view_dispatcher_alloc();
view_dispatcher_enable_queue(app->view_dispatcher);
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);

// Views
Expand Down
1 change: 0 additions & 1 deletion applications/debug/rpc_debug_app/rpc_debug_app.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,6 @@ static RpcDebugApp* rpc_debug_app_alloc(void) {
view_dispatcher_set_tick_event_callback(
app->view_dispatcher, rpc_debug_app_tick_event_callback, 100);
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
view_dispatcher_enable_queue(app->view_dispatcher);

app->widget = widget_alloc();
view_dispatcher_add_view(
Expand Down
1 change: 0 additions & 1 deletion applications/debug/subghz_test/subghz_test_app.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ SubGhzTestApp* subghz_test_app_alloc(void) {
// View Dispatcher
app->view_dispatcher = view_dispatcher_alloc();
app->scene_manager = scene_manager_alloc(&subghz_test_scene_handlers, app);
view_dispatcher_enable_queue(app->view_dispatcher);

view_dispatcher_set_event_callback_context(app->view_dispatcher, app);
view_dispatcher_set_custom_event_callback(
Expand Down
1 change: 0 additions & 1 deletion applications/debug/text_box_view_test/text_box_view_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,6 @@ int32_t text_box_view_test_app(void* p) {
Gui* gui = furi_record_open(RECORD_GUI);
ViewDispatcher* view_dispatcher = view_dispatcher_alloc();
view_dispatcher_attach_to_gui(view_dispatcher, gui, ViewDispatcherTypeFullscreen);
view_dispatcher_enable_queue(view_dispatcher);

TextBoxViewTest instance = {
.text_box = text_box_alloc(),
Expand Down
1 change: 0 additions & 1 deletion applications/debug/uart_echo/uart_echo.c
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,6 @@ static UartEchoApp* uart_echo_app_alloc(uint32_t baudrate) {

// View dispatcher
app->view_dispatcher = view_dispatcher_alloc();
view_dispatcher_enable_queue(app->view_dispatcher);
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);

// Views
Expand Down
62 changes: 30 additions & 32 deletions applications/debug/unit_tests/tests/furi/furi_event_loop.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,24 @@ typedef struct {
uint32_t consumer_counter;
} TestFuriData;

bool test_furi_event_loop_producer_mq_callback(FuriMessageQueue* queue, void* context) {
bool test_furi_event_loop_producer_mq_callback(FuriEventLoopObject* object, void* context) {
furi_check(context);

TestFuriData* data = context;
furi_check(data->mq == queue, "Invalid queue");
furi_check(data->mq == object, "Invalid queue");

FURI_LOG_I(
TAG, "producer_mq_callback: %lu %lu", data->producer_counter, data->consumer_counter);

// Remove and add should not cause crash
// if(data->producer_counter == EVENT_LOOP_EVENT_COUNT/2) {
// furi_event_loop_message_queue_remove(data->producer_event_loop, data->mq);
// furi_event_loop_message_queue_add(
// data->producer_event_loop,
// data->mq,
// FuriEventLoopEventOut,
// test_furi_event_loop_producer_mq_callback,
// data);
// }
if(data->producer_counter == EVENT_LOOP_EVENT_COUNT / 2) {
furi_event_loop_unsubscribe(data->producer_event_loop, data->mq);
furi_event_loop_subscribe_message_queue(
data->producer_event_loop,
data->mq,
FuriEventLoopEventOut,
test_furi_event_loop_producer_mq_callback,
data);
}

if(data->producer_counter == EVENT_LOOP_EVENT_COUNT) {
furi_event_loop_stop(data->producer_event_loop);
Expand All @@ -61,7 +60,7 @@ int32_t test_furi_event_loop_producer(void* p) {
FURI_LOG_I(TAG, "producer start 1st run");

data->producer_event_loop = furi_event_loop_alloc();
furi_event_loop_message_queue_subscribe(
furi_event_loop_subscribe_message_queue(
data->producer_event_loop,
data->mq,
FuriEventLoopEventOut,
Expand All @@ -73,15 +72,15 @@ int32_t test_furi_event_loop_producer(void* p) {
// 2 EventLoop index, 0xFFFFFFFF - all possible flags, emulate uncleared flags
xTaskNotifyIndexed(xTaskGetCurrentTaskHandle(), 2, 0xFFFFFFFF, eSetBits);

furi_event_loop_message_queue_unsubscribe(data->producer_event_loop, data->mq);
furi_event_loop_unsubscribe(data->producer_event_loop, data->mq);
furi_event_loop_free(data->producer_event_loop);

FURI_LOG_I(TAG, "producer start 2nd run");

data->producer_counter = 0;
data->producer_event_loop = furi_event_loop_alloc();

furi_event_loop_message_queue_subscribe(
furi_event_loop_subscribe_message_queue(
data->producer_event_loop,
data->mq,
FuriEventLoopEventOut,
Expand All @@ -90,36 +89,35 @@ int32_t test_furi_event_loop_producer(void* p) {

furi_event_loop_run(data->producer_event_loop);

furi_event_loop_message_queue_unsubscribe(data->producer_event_loop, data->mq);
furi_event_loop_unsubscribe(data->producer_event_loop, data->mq);
furi_event_loop_free(data->producer_event_loop);

FURI_LOG_I(TAG, "producer end");

return 0;
}

bool test_furi_event_loop_consumer_mq_callback(FuriMessageQueue* queue, void* context) {
bool test_furi_event_loop_consumer_mq_callback(FuriEventLoopObject* object, void* context) {
furi_check(context);

TestFuriData* data = context;
furi_check(data->mq == queue);
furi_check(data->mq == object);

furi_delay_us(furi_hal_random_get() % 1000);
furi_check(furi_message_queue_get(data->mq, &data->consumer_counter, 0) == FuriStatusOk);

FURI_LOG_I(
TAG, "consumer_mq_callback: %lu %lu", data->producer_counter, data->consumer_counter);

// Remove and add should not cause crash
// if(data->producer_counter == EVENT_LOOP_EVENT_COUNT/2) {
// furi_event_loop_message_queue_remove(data->consumer_event_loop, data->mq);
// furi_event_loop_message_queue_add(
// data->consumer_event_loop,
// data->mq,
// FuriEventLoopEventIn,
// test_furi_event_loop_producer_mq_callback,
// data);
// }
if(data->consumer_counter == EVENT_LOOP_EVENT_COUNT / 2) {
furi_event_loop_unsubscribe(data->consumer_event_loop, data->mq);
furi_event_loop_subscribe_message_queue(
data->consumer_event_loop,
data->mq,
FuriEventLoopEventIn,
test_furi_event_loop_consumer_mq_callback,
data);
}

if(data->consumer_counter == EVENT_LOOP_EVENT_COUNT) {
furi_event_loop_stop(data->consumer_event_loop);
Expand All @@ -137,7 +135,7 @@ int32_t test_furi_event_loop_consumer(void* p) {
FURI_LOG_I(TAG, "consumer start 1st run");

data->consumer_event_loop = furi_event_loop_alloc();
furi_event_loop_message_queue_subscribe(
furi_event_loop_subscribe_message_queue(
data->consumer_event_loop,
data->mq,
FuriEventLoopEventIn,
Expand All @@ -149,14 +147,14 @@ int32_t test_furi_event_loop_consumer(void* p) {
// 2 EventLoop index, 0xFFFFFFFF - all possible flags, emulate uncleared flags
xTaskNotifyIndexed(xTaskGetCurrentTaskHandle(), 2, 0xFFFFFFFF, eSetBits);

furi_event_loop_message_queue_unsubscribe(data->consumer_event_loop, data->mq);
furi_event_loop_unsubscribe(data->consumer_event_loop, data->mq);
furi_event_loop_free(data->consumer_event_loop);

FURI_LOG_I(TAG, "consumer start 2nd run");

data->consumer_counter = 0;
data->consumer_event_loop = furi_event_loop_alloc();
furi_event_loop_message_queue_subscribe(
furi_event_loop_subscribe_message_queue(
data->consumer_event_loop,
data->mq,
FuriEventLoopEventIn,
Expand All @@ -165,7 +163,7 @@ int32_t test_furi_event_loop_consumer(void* p) {

furi_event_loop_run(data->consumer_event_loop);

furi_event_loop_message_queue_unsubscribe(data->consumer_event_loop, data->mq);
furi_event_loop_unsubscribe(data->consumer_event_loop, data->mq);
furi_event_loop_free(data->consumer_event_loop);

FURI_LOG_I(TAG, "consumer end");
Expand Down
Loading

0 comments on commit bf6c6c2

Please sign in to comment.