diff --git a/applications/app-loader/app-loader.c b/applications/app-loader/app-loader.c new file mode 100644 index 000000000..81a9d84c2 --- /dev/null +++ b/applications/app-loader/app-loader.c @@ -0,0 +1,120 @@ +#include "flipper_v2.h" +#include +#include "menu/menu.h" + +typedef struct { + FuriApp* handler; + Widget* widget; + FlipperStartupApp* current_app; +} AppLoaderState; + +typedef struct { + AppLoaderState* state; + FlipperStartupApp* app; +} AppLoaderContext; + +void render_callback(CanvasApi* canvas, void* _ctx) { + AppLoaderState* ctx = (AppLoaderState*)_ctx; + + canvas->clear(canvas); + canvas->set_color(canvas, ColorBlack); + canvas->set_font(canvas, FontPrimary); + canvas->draw_str(canvas, 2, 32, ctx->current_app->name); + + canvas->set_font(canvas, FontSecondary); + canvas->draw_str(canvas, 2, 44, "press back to exit"); +} + +void input_callback(InputEvent* input_event, void* _ctx) { + AppLoaderState* ctx = (AppLoaderState*)_ctx; + + if(input_event->state && input_event->input == InputBack) { + furiac_kill(ctx->handler); + widget_enabled_set(ctx->widget, false); + } +} + +void handle_menu(void* _ctx) { + AppLoaderContext* ctx = (AppLoaderContext*)_ctx; + + widget_enabled_set(ctx->state->widget, true); + + // TODO how to call this? + // furiac_wait_libs(&FLIPPER_STARTUP[i].libs); + + ctx->state->current_app = ctx->app; + ctx->state->handler = furiac_start(ctx->app->app, ctx->app->name, NULL); +} + +void application_blink(void* p); +void application_uart_write(void* p); +void application_input_dump(void* p); + +const FlipperStartupApp FLIPPER_APPS[] = { + {.app = application_blink, .name = "blink", .libs = {0}}, + {.app = application_uart_write, .name = "uart write", .libs = {0}}, + {.app = application_input_dump, .name = "input dump", .libs = {1, FURI_LIB{"input_task"}}}, +}; + +void app_loader(void* p) { + osThreadId_t self_id = osThreadGetId(); + assert(self_id); + + AppLoaderState state; + state.handler = NULL; + + state.widget = widget_alloc(); + assert(state.widget); + widget_enabled_set(state.widget, false); + widget_draw_callback_set(state.widget, render_callback, &state); + widget_input_callback_set(state.widget, input_callback, &state); + + ValueMutex* menu_mutex = furi_open("menu"); + if(menu_mutex == NULL) { + printf("menu is not available\n"); + furiac_exit(NULL); + } + + // Open GUI and register widget + GuiApi* gui = furi_open("gui"); + if(gui == NULL) { + printf("gui is not available\n"); + furiac_exit(NULL); + } + gui->add_widget(gui, state.widget, WidgetLayerFullscreen); + + { + Menu* menu = acquire_mutex_block(menu_mutex); + + // FURI startup + const size_t flipper_app_count = sizeof(FLIPPER_APPS) / sizeof(FLIPPER_APPS[0]); + + for(size_t i = 0; i < flipper_app_count; i++) { + AppLoaderContext* ctx = furi_alloc(sizeof(AppLoaderContext)); + ctx->state = &state; + ctx->app = &FLIPPER_APPS[i]; + + menu_item_add( + menu, menu_item_alloc_function(FLIPPER_APPS[i].name, NULL, handle_menu, ctx)); + } + + /* + menu_item_add(menu, menu_item_alloc_function("Sub 1 gHz", NULL, NULL, NULL)); + menu_item_add(menu, menu_item_alloc_function("125 kHz RFID", NULL, NULL, NULL)); + menu_item_add(menu, menu_item_alloc_function("Infrared", NULL, NULL, NULL)); + menu_item_add(menu, menu_item_alloc_function("I-Button", NULL, NULL, NULL)); + menu_item_add(menu, menu_item_alloc_function("USB", NULL, NULL, NULL)); + menu_item_add(menu, menu_item_alloc_function("Bluetooth", NULL, NULL, NULL)); + menu_item_add(menu, menu_item_alloc_function("GPIO / HW", NULL, NULL, NULL)); + menu_item_add(menu, menu_item_alloc_function("U2F", NULL, NULL, NULL)); + menu_item_add(menu, menu_item_alloc_function("Tamagotchi", NULL, NULL, NULL)); + menu_item_add(menu, menu_item_alloc_function("Plugins", NULL, NULL, NULL)); + */ + + release_mutex(menu_mutex, menu); + } + + printf("[app loader] start\n"); + + osThreadSuspend(self_id); +} \ No newline at end of file diff --git a/applications/applications.mk b/applications/applications.mk index 188a2abed..2f1c82ddd 100644 --- a/applications/applications.mk +++ b/applications/applications.mk @@ -16,6 +16,11 @@ APP_INPUT = 1 APP_GUI = 1 CFLAGS += -DAPP_MENU C_SOURCES += $(wildcard $(APP_DIR)/menu/*.c) +C_SOURCES += $(wildcard $(APP_DIR)/app-loader/*.c) + +APP_EXAMPLE_BLINK = 1 +APP_EXAMPLE_UART_WRITE = 1 +APP_EXAMPLE_INPUT_DUMP = 1 endif APP_TEST ?= 0 diff --git a/applications/menu/menu.c b/applications/menu/menu.c index a0261bf58..b305c4cb0 100644 --- a/applications/menu/menu.c +++ b/applications/menu/menu.c @@ -3,7 +3,6 @@ #include #include -#include #include #include @@ -25,23 +24,30 @@ struct Menu { void menu_widget_callback(CanvasApi* canvas, void* context); -Menu* menu_init() { +ValueMutex* menu_init() { Menu* menu = furi_alloc(sizeof(Menu)); // Event dispatcher menu->event = menu_event_alloc(); + ValueMutex* menu_mutex = furi_alloc(sizeof(ValueMutex)); + if(menu_mutex == NULL || !init_mutex(menu_mutex, menu, sizeof(Menu))) { + printf("[menu_task] cannot create menu mutex\n"); + furiac_exit(NULL); + } + // Allocate and configure widget menu->widget = widget_alloc(); - widget_draw_callback_set(menu->widget, menu_widget_callback, menu); - widget_input_callback_set(menu->widget, menu_event_input_callback, menu->event); // Open GUI and register fullscreen widget GuiApi* gui = furi_open("gui"); assert(gui); gui->add_widget(gui, menu->widget, WidgetLayerFullscreen); - return menu; + widget_draw_callback_set(menu->widget, menu_widget_callback, menu_mutex); + widget_input_callback_set(menu->widget, menu_event_input_callback, menu->event); + + return menu_mutex; } void menu_build_main(Menu* menu) { @@ -49,17 +55,6 @@ void menu_build_main(Menu* menu) { // Root point menu->root = menu_item_alloc_menu(NULL, NULL); - menu_item_add(menu, menu_item_alloc_function("Sub 1 gHz", NULL, NULL, NULL)); - menu_item_add(menu, menu_item_alloc_function("125 kHz RFID", NULL, NULL, NULL)); - menu_item_add(menu, menu_item_alloc_function("Infrared", NULL, NULL, NULL)); - menu_item_add(menu, menu_item_alloc_function("I-Button", NULL, NULL, NULL)); - menu_item_add(menu, menu_item_alloc_function("USB", NULL, NULL, NULL)); - menu_item_add(menu, menu_item_alloc_function("Bluetooth", NULL, NULL, NULL)); - menu_item_add(menu, menu_item_alloc_function("GPIO / HW", NULL, NULL, NULL)); - menu_item_add(menu, menu_item_alloc_function("U2F", NULL, NULL, NULL)); - menu_item_add(menu, menu_item_alloc_function("Tamagotchi", NULL, NULL, NULL)); - menu_item_add(menu, menu_item_alloc_function("Plugins", NULL, NULL, NULL)); - menu->settings = menu_item_alloc_menu("Setting", NULL); menu_item_subitem_add(menu->settings, menu_item_alloc_function("one", NULL, NULL, NULL)); menu_item_subitem_add(menu->settings, menu_item_alloc_function("two", NULL, NULL, NULL)); @@ -80,9 +75,8 @@ void menu_widget_callback(CanvasApi* canvas, void* context) { assert(canvas); assert(context); - Menu* menu = context; - - menu_event_lock(menu->event); + Menu* menu = acquire_mutex((ValueMutex*)context, 100); // wait 10 ms to get mutex + if(menu == NULL) return; // redraw fail if(!menu->current) { canvas->clear(canvas); @@ -102,7 +96,7 @@ void menu_widget_callback(CanvasApi* canvas, void* context) { } } - menu_event_unlock(menu->event); + release_mutex((ValueMutex*)context, menu); } void menu_update(Menu* menu) { @@ -172,10 +166,22 @@ void menu_exit(Menu* menu) { } void menu_task(void* p) { - Menu* menu = menu_init(); - menu_build_main(menu); + ValueMutex* menu_mutex = menu_init(); - if(!furi_create_deprecated("menu", menu, sizeof(menu))) { + MenuEvent* menu_event = NULL; + { + Menu* menu = acquire_mutex_block(menu_mutex); + assert(menu); + + menu_build_main(menu); + + // immutable thread-safe object + menu_event = menu->event; + + release_mutex(menu_mutex, menu); + } + + if(!furi_create("menu", menu_mutex)) { printf("[menu_task] cannot create the menu record\n"); furiac_exit(NULL); } @@ -183,10 +189,11 @@ void menu_task(void* p) { furiac_ready(); while(1) { - MenuMessage m = menu_event_next(menu->event); + MenuMessage m = menu_event_next(menu_event); + + Menu* menu = acquire_mutex_block(menu_mutex); if(!menu->current && m.type != MenuMessageTypeOk) { - continue; } else if(m.type == MenuMessageTypeUp) { menu_up(menu); } else if(m.type == MenuMessageTypeDown) { @@ -204,5 +211,7 @@ void menu_task(void* p) { } else { // TODO: fail somehow? } + + release_mutex(menu_mutex, menu); } } diff --git a/applications/menu/menu.h b/applications/menu/menu.h index 01c68be28..f8607fda1 100644 --- a/applications/menu/menu.h +++ b/applications/menu/menu.h @@ -1,5 +1,7 @@ #pragma once +#include "menu/menu_item.h" + typedef struct Menu Menu; typedef struct MenuItem MenuItem; diff --git a/applications/menu/menu_event.c b/applications/menu/menu_event.c index bd4799729..4470ffd6a 100644 --- a/applications/menu/menu_event.c +++ b/applications/menu/menu_event.c @@ -12,7 +12,6 @@ struct MenuEvent { osMessageQueueId_t mqueue; osTimerId_t timeout_timer; - osMutexId_t lock_mutex; }; void MenuEventimeout_callback(void* arg) { @@ -32,29 +31,15 @@ MenuEvent* menu_event_alloc() { osTimerNew(MenuEventimeout_callback, osTimerOnce, menu_event, NULL); assert(menu_event->timeout_timer); - menu_event->lock_mutex = osMutexNew(NULL); - assert(menu_event->lock_mutex); - - menu_event_lock(menu_event); - return menu_event; } void menu_event_free(MenuEvent* menu_event) { assert(menu_event); - menu_event_unlock(menu_event); assert(osMessageQueueDelete(menu_event->mqueue) == osOK); free(menu_event); } -void menu_event_lock(MenuEvent* menu_event) { - assert(osMutexAcquire(menu_event->lock_mutex, osWaitForever) == osOK); -} - -void menu_event_unlock(MenuEvent* menu_event) { - assert(osMutexRelease(menu_event->lock_mutex) == osOK); -} - void menu_event_activity_notify(MenuEvent* menu_event) { assert(menu_event); osTimerStart(menu_event->timeout_timer, 60000U); // 1m timeout, return to main @@ -63,10 +48,8 @@ void menu_event_activity_notify(MenuEvent* menu_event) { MenuMessage menu_event_next(MenuEvent* menu_event) { assert(menu_event); MenuMessage message; - menu_event_unlock(menu_event); while(osMessageQueueGet(menu_event->mqueue, &message, NULL, osWaitForever) != osOK) { }; - menu_event_lock(menu_event); return message; } diff --git a/applications/menu/menu_event.h b/applications/menu/menu_event.h index 858dc27b6..031b8f4e6 100644 --- a/applications/menu/menu_event.h +++ b/applications/menu/menu_event.h @@ -25,10 +25,6 @@ MenuEvent* menu_event_alloc(); void menu_event_free(MenuEvent* menu_event); -void menu_event_lock(MenuEvent* menu_event); - -void menu_event_unlock(MenuEvent* menu_event); - void menu_event_activity_notify(MenuEvent* menu_event); MenuMessage menu_event_next(MenuEvent* menu_event); diff --git a/applications/startup.h b/applications/startup.h index 847009dc2..e0a2683f8 100644 --- a/applications/startup.h +++ b/applications/startup.h @@ -2,8 +2,6 @@ #include "flipper.h" -#define FURI_LIB (const char*[]) - #ifdef APP_TEST void flipper_test_app(void* p); #endif @@ -27,6 +25,7 @@ void u8g2_qrcode(void* p); void fatfs_list(void* p); void gui_task(void* p); void backlight_control(void* p); +void app_loader(void* p); const FlipperStartupApp FLIPPER_STARTUP[] = { #ifdef APP_DISPLAY @@ -44,6 +43,7 @@ const FlipperStartupApp FLIPPER_STARTUP[] = { #ifdef APP_MENU {.app = menu_task, .name = "menu_task", .libs = {1, FURI_LIB{"gui_task"}}}, + {.app = app_loader, .name = "app_loader", .libs = {1, FURI_LIB{"menu_task"}}}, #endif // {.app = coreglitch_demo_0, .name = "coreglitch_demo_0", .libs = ""}, @@ -52,23 +52,11 @@ const FlipperStartupApp FLIPPER_STARTUP[] = { {.app = flipper_test_app, .name = "test app", .libs = {0}}, #endif -#ifdef APP_EXAMPLE_BLINK - {.app = application_blink, .name = "blink", .libs = {0}}, -#endif - -#ifdef APP_EXAMPLE_UART_WRITE - {.app = application_uart_write, .name = "uart write", .libs = {0}}, -#endif - #ifdef APP_EXAMPLE_IPC {.app = application_ipc_display, .name = "ipc display", .libs = {0}}, {.app = application_ipc_widget, .name = "ipc widget", .libs = {0}}, #endif -#ifdef APP_EXAMPLE_INPUT_DUMP - {.app = application_input_dump, .name = "input dump", .libs = {1, FURI_LIB{"input_task"}}}, -#endif - #ifdef APP_EXAMPLE_QRCODE {.app = u8g2_qrcode, .name = "u8g2_qrcode", .libs = {1, FURI_LIB{"display_u8g2"}}}, #endif diff --git a/core/flipper.h b/core/flipper.h index 8e4cd0985..6f867a5f8 100644 --- a/core/flipper.h +++ b/core/flipper.h @@ -16,6 +16,8 @@ extern "C" { } #endif +#include + // Arduino defines #define pinMode app_gpio_init @@ -32,3 +34,5 @@ extern "C" { #define HIGH true void set_exitcode(uint32_t _exitcode); + +#define FURI_LIB (const char*[]) diff --git a/core/flipper_v2.h b/core/flipper_v2.h index 9e3bc90e9..6d3fa47fb 100644 --- a/core/flipper_v2.h +++ b/core/flipper_v2.h @@ -1,5 +1,7 @@ #pragma once +#include "flipper.h" + #include "api-basic/furi.h" //#include "api-basic/flapp.h" #include "cmsis_os2.h"