From b9427d4eba0f7102b9c1973955c0f823f727721a Mon Sep 17 00:00:00 2001 From: Ken Van Hoeylandt Date: Sat, 30 Dec 2023 12:39:07 +0100 Subject: [PATCH] App Loading via Loader (#1) * app loading wip * various improvements irq/isr stuff is now working lvgl locking where needed hello world now uses proper mutex for app unlocking etc? * various improvements * cmsis_esp improvements * implement interrupts --- README.md | 2 +- .../board_2432s024/board_2432s024_display.c | 5 +- .../board_2432s024/board_2432s024_touch.c | 4 +- components/cmsis_core/cmsis_compiler.h | 5 +- .../{cmsis_gcc_esp32.h => cmsis_esp.h} | 29 +- components/furi/src/api_lock.h | 19 ++ components/furi/src/app.c | 102 ++++++ components/furi/src/app_i.h | 23 ++ components/furi/src/app_manifest.h | 32 ++ components/furi/src/app_manifest_registry.c | 79 +++++ components/furi/src/app_manifest_registry.h | 23 ++ components/furi/src/check.c | 117 +------ components/furi/src/common_defines.h | 60 ---- components/furi/src/critical.c | 3 +- components/furi/src/critical.h | 22 ++ components/furi/src/event_flag.c | 2 +- components/furi/src/event_flag.h | 2 +- components/furi/src/furi.c | 30 ++ components/furi/src/furi.h | 28 ++ components/furi/src/furi_core.h | 12 + components/furi/src/furi_core_defines.h | 40 +++ .../furi/src/{base.h => furi_core_types.h} | 0 .../{core_defines.h => furi_extra_defines.h} | 0 components/furi/src/furi_hal_console.c | 6 +- components/furi/src/furi_hal_console.h | 2 - components/furi/src/kernel.c | 42 +-- components/furi/src/kernel.h | 4 +- components/furi/src/log.h | 22 ++ components/furi/src/message_queue.c | 14 +- components/furi/src/message_queue.h | 2 +- components/furi/src/mutex.c | 2 +- components/furi/src/mutex.h | 2 +- components/furi/src/record.c | 3 +- components/furi/src/record.h | 12 +- components/furi/src/semaphore.c | 53 +++- components/furi/src/semaphore.h | 37 ++- components/furi/src/stream_buffer.c | 4 +- components/furi/src/stream_buffer.h | 4 +- components/furi/src/thread.c | 2 +- components/furi/src/thread.h | 4 +- components/furi/src/timer.c | 18 +- components/furi/src/timer.h | 2 +- components/mlib/m-tuple.h | 4 +- components/nanobake/CMakeLists.txt | 9 +- components/nanobake/src/app.c | 19 -- components/nanobake/src/app.h | 41 --- components/nanobake/src/app_i.h | 13 - .../nanobake/src/applications/applications.c | 28 -- .../src/applications/applications_i.h | 23 -- .../src/applications/services/loader/loader.c | 17 - .../src/applications/services/loader/loader.h | 13 - .../system/system_info/system_info.c | 39 --- .../services/desktop/desktop.c | 11 +- .../services/desktop/desktop.h | 4 +- .../{applications => apps}/services/gui/gui.c | 15 +- .../{applications => apps}/services/gui/gui.h | 14 +- .../services/gui/gui_draw.c | 0 .../services/gui/gui_i.h | 0 .../services/gui/gui_input.c | 0 .../nanobake/src/apps/services/gui/icon.c | 13 + .../nanobake/src/apps/services/gui/icon.h | 11 + .../nanobake/src/apps/services/gui/icon_i.h | 10 + .../services/gui/view_port.c | 4 + .../services/gui/view_port.h | 0 .../services/gui/view_port_i.h | 0 .../services/gui/view_port_input.c | 0 .../services/gui/view_port_input.h | 0 .../src/apps/services/loader/loader.c | 290 ++++++++++++++++++ .../src/apps/services/loader/loader.h | 84 +++++ .../src/apps/services/loader/loader_i.h | 55 ++++ .../src/apps/system/system_info/system_info.c | 24 ++ .../system/system_info/system_info.h | 4 +- components/nanobake/src/devices.c | 2 +- components/nanobake/src/display.c | 4 +- components/nanobake/src/display.h | 5 +- components/nanobake/src/graphics.c | 4 +- components/nanobake/src/nanobake.c | 105 +++---- components/nanobake/src/nanobake.h | 7 +- components/nanobake/src/touch.c | 2 +- components/nanobake/src/touch.h | 2 +- main/src/hello_world/hello_world.c | 40 ++- main/src/hello_world/hello_world.h | 4 +- main/src/main.c | 9 + 83 files changed, 1180 insertions(+), 623 deletions(-) rename components/cmsis_core/{cmsis_gcc_esp32.h => cmsis_esp.h} (98%) create mode 100644 components/furi/src/api_lock.h create mode 100644 components/furi/src/app.c create mode 100644 components/furi/src/app_i.h create mode 100644 components/furi/src/app_manifest.h create mode 100644 components/furi/src/app_manifest_registry.c create mode 100644 components/furi/src/app_manifest_registry.h delete mode 100644 components/furi/src/common_defines.h create mode 100644 components/furi/src/critical.h create mode 100644 components/furi/src/furi.c create mode 100644 components/furi/src/furi.h create mode 100644 components/furi/src/furi_core.h create mode 100644 components/furi/src/furi_core_defines.h rename components/furi/src/{base.h => furi_core_types.h} (100%) rename components/furi/src/{core_defines.h => furi_extra_defines.h} (100%) create mode 100644 components/furi/src/log.h delete mode 100644 components/nanobake/src/app.c delete mode 100644 components/nanobake/src/app.h delete mode 100644 components/nanobake/src/app_i.h delete mode 100644 components/nanobake/src/applications/applications.c delete mode 100644 components/nanobake/src/applications/applications_i.h delete mode 100644 components/nanobake/src/applications/services/loader/loader.c delete mode 100644 components/nanobake/src/applications/services/loader/loader.h delete mode 100644 components/nanobake/src/applications/system/system_info/system_info.c rename components/nanobake/src/{applications => apps}/services/desktop/desktop.c (55%) rename components/nanobake/src/{applications => apps}/services/desktop/desktop.h (56%) rename components/nanobake/src/{applications => apps}/services/gui/gui.c (96%) rename components/nanobake/src/{applications => apps}/services/gui/gui.h (87%) rename components/nanobake/src/{applications => apps}/services/gui/gui_draw.c (100%) rename components/nanobake/src/{applications => apps}/services/gui/gui_i.h (100%) rename components/nanobake/src/{applications => apps}/services/gui/gui_input.c (100%) create mode 100644 components/nanobake/src/apps/services/gui/icon.c create mode 100644 components/nanobake/src/apps/services/gui/icon.h create mode 100644 components/nanobake/src/apps/services/gui/icon_i.h rename components/nanobake/src/{applications => apps}/services/gui/view_port.c (97%) rename components/nanobake/src/{applications => apps}/services/gui/view_port.h (100%) rename components/nanobake/src/{applications => apps}/services/gui/view_port_i.h (100%) rename components/nanobake/src/{applications => apps}/services/gui/view_port_input.c (100%) rename components/nanobake/src/{applications => apps}/services/gui/view_port_input.h (100%) create mode 100644 components/nanobake/src/apps/services/loader/loader.c create mode 100644 components/nanobake/src/apps/services/loader/loader.h create mode 100644 components/nanobake/src/apps/services/loader/loader_i.h create mode 100644 components/nanobake/src/apps/system/system_info/system_info.c rename components/nanobake/src/{applications => apps}/system/system_info/system_info.h (57%) diff --git a/README.md b/README.md index 594508cc..4a113de9 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ You might have to remove this setting if you're not using the Yellow Board descr See below for the supported hardware. Predefined configurations are available for: -- Yellow Board / 2432S024 +- Yellow Board / 2432S024 (capacitive touch variant) - (more will follow) ### Drivers diff --git a/components/board_2432s024/board_2432s024_display.c b/components/board_2432s024/board_2432s024_display.c index 3d9644f4..50e59261 100644 --- a/components/board_2432s024/board_2432s024_display.c +++ b/components/board_2432s024/board_2432s024_display.c @@ -31,7 +31,7 @@ IRAM_ATTR static bool prv_on_color_trans_done(esp_lcd_panel_io_handle_t io_handl return (need_yield == pdTRUE); } -static bool prv_create_display(DisplayDevice* display) { +static bool prv_create_display_device(DisplayDevice* display) { ESP_LOGI(TAG, "creating display"); gpio_config_t io_conf = { @@ -117,6 +117,7 @@ static bool prv_create_display(DisplayDevice* display) { display->vertical_resolution = LCD_VERTICAL_RESOLUTION; display->draw_buffer_height = LCD_DRAW_BUFFER_HEIGHT; display->bits_per_pixel = LCD_BITS_PER_PIXEL; + display->monochrome = false; return true; } @@ -124,6 +125,6 @@ static bool prv_create_display(DisplayDevice* display) { DisplayDriver board_2432s024_create_display_driver() { return (DisplayDriver) { .name = "ili9341_2432s024", - .create_display = &prv_create_display + .create_display_device = &prv_create_display_device }; } diff --git a/components/board_2432s024/board_2432s024_touch.c b/components/board_2432s024/board_2432s024_touch.c index 6a11c20f..09e2a921 100644 --- a/components/board_2432s024/board_2432s024_touch.c +++ b/components/board_2432s024/board_2432s024_touch.c @@ -9,7 +9,7 @@ #define TAG "2432s024_cst816" -static bool prv_create_touch(esp_lcd_panel_io_handle_t* io_handle, esp_lcd_touch_handle_t* touch_handle) { +static bool prv_create_touch_device(esp_lcd_panel_io_handle_t* io_handle, esp_lcd_touch_handle_t* touch_handle) { ESP_LOGI(TAG, "creating touch"); const i2c_config_t i2c_conf = { @@ -67,6 +67,6 @@ static bool prv_create_touch(esp_lcd_panel_io_handle_t* io_handle, esp_lcd_touch TouchDriver board_2432s024_create_touch_driver() { return (TouchDriver) { .name = "cst816s_2432s024", - .create_touch = &prv_create_touch + .create_touch_device = &prv_create_touch_device }; } diff --git a/components/cmsis_core/cmsis_compiler.h b/components/cmsis_core/cmsis_compiler.h index f2663f60..18efc844 100644 --- a/components/cmsis_core/cmsis_compiler.h +++ b/components/cmsis_core/cmsis_compiler.h @@ -52,12 +52,13 @@ #elif defined (__ti__) #include "cmsis_tiarmclang.h" +#elif defined (ESP_PLATFORM) + #include "cmsis_esp.h" /* * GNU Compiler */ #elif defined ( __GNUC__ ) - #include "cmsis_gcc_esp32.h" -// #include "cmsis_gcc.h" + #include "cmsis_gcc.h" /* diff --git a/components/cmsis_core/cmsis_gcc_esp32.h b/components/cmsis_core/cmsis_esp.h similarity index 98% rename from components/cmsis_core/cmsis_gcc_esp32.h rename to components/cmsis_core/cmsis_esp.h index 12fdcb89..5eb54bd2 100644 --- a/components/cmsis_core/cmsis_gcc_esp32.h +++ b/components/cmsis_core/cmsis_esp.h @@ -1,5 +1,5 @@ /**************************************************************************//** - * @file cmsis_gcc.h + * @file cmsis_esp.h * @brief CMSIS compiler GCC header file * @version V5.4.2 * @date 17. December 2022 @@ -25,6 +25,8 @@ #ifndef __CMSIS_GCC_H #define __CMSIS_GCC_H +#include "freertos/portmacro.h" + /* ignore some GCC warnings */ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsign-conversion" @@ -949,25 +951,19 @@ __STATIC_FORCEINLINE uint32_t __STLEX(uint32_t value, volatile uint32_t *ptr) /** \brief Enable IRQ Interrupts - \details Enables IRQ interrupts by clearing special-purpose register PRIMASK. - Can only be executed in Privileged modes. */ __STATIC_FORCEINLINE void __enable_irq(void) { - // TODO esp -// __ASM volatile ("cpsie i" : : : "memory"); + portENABLE_INTERRUPTS(); } /** \brief Disable IRQ Interrupts - \details Disables IRQ interrupts by setting special-purpose register PRIMASK. - Can only be executed in Privileged modes. */ __STATIC_FORCEINLINE void __disable_irq(void) { - // TODO esp -// __ASM volatile ("cpsid i" : : : "memory"); + portDISABLE_INTERRUPTS(); } @@ -1034,11 +1030,8 @@ __STATIC_FORCEINLINE void __TZ_set_CONTROL_NS(uint32_t control) */ __STATIC_FORCEINLINE uint32_t __get_IPSR(void) { - uint32_t result; - - result = 0; // TODO esp -// __ASM volatile ("MRS %0, ipsr" : "=r" (result) ); - return(result); + // TODO esp + return 0; } @@ -1050,7 +1043,6 @@ __STATIC_FORCEINLINE uint32_t __get_IPSR(void) __STATIC_FORCEINLINE uint32_t __get_APSR(void) { uint32_t result; - __ASM volatile ("MRS %0, apsr" : "=r" (result) ); return(result); } @@ -1212,11 +1204,8 @@ __STATIC_FORCEINLINE void __TZ_set_SP_NS(uint32_t topOfStack) */ __STATIC_FORCEINLINE uint32_t __get_PRIMASK(void) { - uint32_t result; - - result = 1U; // TODO esp -// __ASM volatile ("MRS %0, primask" : "=r" (result) ); - return(result); + // Not supported by ESP + return 0U; } diff --git a/components/furi/src/api_lock.h b/components/furi/src/api_lock.h new file mode 100644 index 00000000..079a1411 --- /dev/null +++ b/components/furi/src/api_lock.h @@ -0,0 +1,19 @@ +#pragma once +#include "furi.h" + +typedef FuriEventFlag* FuriApiLock; + +#define API_LOCK_EVENT (1U << 0) + +#define api_lock_alloc_locked() furi_event_flag_alloc() + +#define api_lock_wait_unlock(_lock) \ + furi_event_flag_wait(_lock, API_LOCK_EVENT, FuriFlagWaitAny, FuriWaitForever) + +#define api_lock_free(_lock) furi_event_flag_free(_lock) + +#define api_lock_unlock(_lock) furi_event_flag_set(_lock, API_LOCK_EVENT) + +#define api_lock_wait_unlock_and_free(_lock) \ + api_lock_wait_unlock(_lock); \ + api_lock_free(_lock); diff --git a/components/furi/src/app.c b/components/furi/src/app.c new file mode 100644 index 00000000..b9a0e7fd --- /dev/null +++ b/components/furi/src/app.c @@ -0,0 +1,102 @@ +#include "app_i.h" +#include "furi_core.h" +#include "log.h" +#include "furi_string.h" + +#define TAG "app" + +const char* prv_type_service = "service"; +const char* prv_type_system = "system"; +const char* prv_type_user = "user"; + +static FuriThreadPriority get_thread_priority(AppType type) { + switch (type) { + case AppTypeService: + return FuriThreadPriorityHighest; + case AppTypeSystem: + return FuriThreadPriorityHigh; + case AppTypeUser: + return FuriThreadPriorityNormal; + default: + furi_crash("no priority defined for app type"); + } +} + +const char* furi_app_type_to_string(AppType type) { + switch (type) { + case AppTypeService: + return prv_type_service; + case AppTypeSystem: + return prv_type_system; + case AppTypeUser: + return prv_type_user; + default: + furi_crash(); + } +} + +App* furi_app_alloc(const AppManifest* _Nonnull manifest) { + App app = { + .manifest = manifest, + .thread = NULL, + .ep_thread_args = NULL + }; + App* app_ptr = malloc(sizeof(App)); + return memcpy(app_ptr, &app, sizeof(App)); +} + +void furi_app_free(App* app) { + furi_assert(app); + + if(app->thread) { + furi_thread_join(app->thread); + furi_thread_free(app->thread); + } + + if (app->ep_thread_args) { + free(app->ep_thread_args); + app->ep_thread_args = NULL; + } + + free(app); +} + +FuriThread* furi_app_alloc_thread(App _Nonnull* app, const char* args) { + FURI_LOG_I( + TAG, + "Starting %s app \"%s\"", + furi_app_type_to_string(app->manifest->type), + app->manifest->name + ); + + // Free any previous app launching arguments + if (app->ep_thread_args) { + free(app->ep_thread_args); + } + + if (args) { + app->ep_thread_args = strdup(args); + } else { + app->ep_thread_args = NULL; + } + + FuriThread* thread = furi_thread_alloc_ex( + app->manifest->name, + app->manifest->stack_size, + app->manifest->entry_point, + app + ); + + if (app->manifest->type == AppTypeService) { + furi_thread_mark_as_service(thread); + } + + FuriString* app_name = furi_string_alloc(); + furi_thread_set_appid(thread, furi_string_get_cstr(app_name)); + furi_string_free(app_name); + + FuriThreadPriority priority = get_thread_priority(app->manifest->type); + furi_thread_set_priority(thread, priority); + + return thread; +} diff --git a/components/furi/src/app_i.h b/components/furi/src/app_i.h new file mode 100644 index 00000000..1090db51 --- /dev/null +++ b/components/furi/src/app_i.h @@ -0,0 +1,23 @@ +#pragma once + +#include "app_manifest.h" +#include "thread.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + FuriThread* thread; + const AppManifest* manifest; + void* ep_thread_args; +} App; + +const char* furi_app_type_to_string(AppType type); +FuriThread* furi_app_alloc_thread(App* _Nonnull app, const char* args); +App* furi_app_alloc(const AppManifest* _Nonnull manifest); +void furi_app_free(App* _Nonnull app); + +#ifdef __cplusplus +} +#endif diff --git a/components/furi/src/app_manifest.h b/components/furi/src/app_manifest.h new file mode 100644 index 00000000..a400e9bd --- /dev/null +++ b/components/furi/src/app_manifest.h @@ -0,0 +1,32 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + AppTypeService, + AppTypeSystem, + AppTypeUser +} AppType; + +typedef enum { + AppStackSizeNormal = 2048 +} AppStackSize; + +typedef int32_t (*AppEntryPoint)(void _Nonnull* parameter); + +typedef struct { + const char* _Nonnull id; + const char* _Nonnull name; + const char* _Nullable icon; + const AppType type; + const AppEntryPoint _Nullable entry_point; + const AppStackSize stack_size; +} AppManifest; + +#ifdef __cplusplus +} +#endif diff --git a/components/furi/src/app_manifest_registry.c b/components/furi/src/app_manifest_registry.c new file mode 100644 index 00000000..e17f9830 --- /dev/null +++ b/components/furi/src/app_manifest_registry.c @@ -0,0 +1,79 @@ +#include "app_manifest_registry.h" +#include "furi_core.h" +#include "m-dict.h" +#include "m_cstr_dup.h" +#include "mutex.h" + +#define TAG "app_registry" + +typedef struct { + const AppManifest* manifest; +} AppEntry; + +DICT_DEF2(AppManifestDict, const char*, M_CSTR_DUP_OPLIST, const AppManifest*, M_PTR_OPLIST) + +#define APP_REGISTRY_FOR_EACH(manifest_var_name, code_to_execute) \ + { \ + app_registry_lock(); \ + AppManifestDict_it_t it; \ + for (AppManifestDict_it(it, app_manifest_dict); !AppManifestDict_end_p(it); AppManifestDict_next(it)) { \ + const AppManifest* (manifest_var_name) = AppManifestDict_cref(it)->value; \ + code_to_execute; \ + } \ + app_registry_unlock(); \ + } + +AppManifestDict_t app_manifest_dict; +FuriMutex* mutex = NULL; + +void app_manifest_registry_init() { + furi_assert(mutex == NULL); + mutex = furi_mutex_alloc(FuriMutexTypeNormal); + AppManifestDict_init(app_manifest_dict); +} + +void app_registry_lock() { + furi_assert(mutex != NULL); + furi_mutex_acquire(mutex, FuriWaitForever); +} + +void app_registry_unlock() { + furi_assert(mutex != NULL); + furi_mutex_release(mutex); +} + +void app_manifest_registry_add(const AppManifest _Nonnull* manifest) { + FURI_LOG_I(TAG, "adding %s", manifest->id); + + app_registry_lock(); + AppManifestDict_set_at(app_manifest_dict, manifest->id, manifest); + app_registry_unlock(); +} + +void app_manifest_registry_remove(const AppManifest _Nonnull* manifest) { + FURI_LOG_I(TAG, "removing %s", manifest->id); + app_registry_lock(); + AppManifestDict_erase(app_manifest_dict, manifest->id); + app_registry_unlock(); +} + +const AppManifest _Nullable* app_manifest_registry_find_by_id(const char* id) { + app_registry_lock(); + const AppManifest _Nullable** manifest = AppManifestDict_get(app_manifest_dict, id); + app_registry_unlock(); + return (manifest != NULL) ? *manifest : NULL; +} + +void app_manifest_registry_for_each_of_type(AppType type, AppManifestCallback callback) { + APP_REGISTRY_FOR_EACH(manifest, { + if (manifest->type == type) { + callback(manifest); + } + }); +} + +void app_manifest_registry_for_each(AppManifestCallback callback) { + APP_REGISTRY_FOR_EACH(manifest, { + callback(manifest); + }); +} diff --git a/components/furi/src/app_manifest_registry.h b/components/furi/src/app_manifest_registry.h new file mode 100644 index 00000000..ef98461c --- /dev/null +++ b/components/furi/src/app_manifest_registry.h @@ -0,0 +1,23 @@ +#pragma once + +#include "app_manifest.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern const AppManifest* const INTERNAL_APP_MANIFESTS[]; +extern const size_t INTERNAL_APP_COUNT; + +typedef void (*AppManifestCallback)(const AppManifest*); + +void app_manifest_registry_init(); +void app_manifest_registry_add(const AppManifest _Nonnull* manifest); +void app_manifest_registry_remove(const AppManifest _Nonnull* manifest); +const AppManifest _Nullable* app_manifest_registry_find_by_id(const char* id); +void app_manifest_registry_for_each(AppManifestCallback callback); +void app_manifest_registry_for_each_of_type(AppType type, AppManifestCallback callback); + +#ifdef __cplusplus +} +#endif diff --git a/components/furi/src/check.c b/components/furi/src/check.c index f7bcf617..4bc6ddab 100644 --- a/components/furi/src/check.c +++ b/components/furi/src/check.c @@ -1,110 +1,29 @@ #include "check.h" -#include "common_defines.h" +#include "furi_core_defines.h" #include "furi_hal_console.h" #include #include #include -PLACE_IN_SECTION("MB_MEM2") -const char* __furi_check_message = NULL; -PLACE_IN_SECTION("MB_MEM2") -uint32_t __furi_check_registers[13] = {0}; - -/** Load r12 value to __furi_check_message and store registers to __furi_check_registers */ -/*#define GET_MESSAGE_AND_STORE_REGISTERS() \ - asm volatile("ldr r11, =__furi_check_message \n" \ - "str r12, [r11] \n" \ - "ldr r12, =__furi_check_registers \n" \ - "stm r12, {r0-r11} \n" \ - "str lr, [r12, #48] \n" \ - : \ - : \ - : "memory");*/ - -/** Restore registers and halt MCU - * - * - Always use it with GET_MESSAGE_AND_STORE_REGISTERS - * - If debugger is(was) connected this routine will raise bkpt - * - If debugger is not connected then endless loop - * - */ -/*#define RESTORE_REGISTERS_AND_HALT_MCU(debug) \ - register bool a0 asm("a0") = debug; \ - asm volatile("cbnz a0, with_debugger%= \n" \ - "ldr a12, =__furi_check_registers\n" \ - "ldm a12, {a0-a11} \n" \ - "loop%=: \n" \ - "wfi \n" \ - "b loop%= \n" \ - "with_debugger%=: \n" \ - "ldr a12, =__furi_check_registers\n" \ - "ldm a12, {a0-a11} \n" \ - "debug_loop%=: \n" \ - "bkpt 0x00 \n" \ - "wfi \n" \ - "b debug_loop%= \n" \ - : \ - : "a"(a0) \ - : "memory");*/ - -extern size_t xPortGetTotalHeapSize(void); - static void __furi_put_uint32_as_text(uint32_t data) { char tmp_str[] = "-2147483648"; itoa(data, tmp_str, 10); furi_hal_console_puts(tmp_str); } -static void __furi_put_uint32_as_hex(uint32_t data) { - char tmp_str[] = "0xFFFFFFFF"; - itoa(data, tmp_str, 16); - furi_hal_console_puts(tmp_str); -} - -static void __furi_print_register_info() { - // Print registers - for (uint8_t i = 0; i < 12; i++) { - furi_hal_console_puts("\r\n\tr"); - __furi_put_uint32_as_text(i); - furi_hal_console_puts(" : "); - __furi_put_uint32_as_hex(__furi_check_registers[i]); - } - - furi_hal_console_puts("\r\n\tlr : "); - __furi_put_uint32_as_hex(__furi_check_registers[12]); -} - static void __furi_print_stack_info() { furi_hal_console_puts("\r\n\tstack watermark: "); __furi_put_uint32_as_text(uxTaskGetStackHighWaterMark(NULL) * 4); } -static void __furi_print_bt_stack_info() { - /* - const FuriHalBtHardfaultInfo* fault_info = furi_hal_bt_get_hardfault_info(); - if(fault_info == NULL) { - furi_hal_console_puts("\r\n\tcore2: not faulted"); - } else { - furi_hal_console_puts("\r\n\tcore2: hardfaulted.\r\n\tPC: "); - __furi_put_uint32_as_hex(fault_info->source_pc); - furi_hal_console_puts("\r\n\tLR: "); - __furi_put_uint32_as_hex(fault_info->source_lr); - furi_hal_console_puts("\r\n\tSP: "); - __furi_put_uint32_as_hex(fault_info->source_sp); - } - */ -} - static void __furi_print_heap_info() { - /* - furi_hal_console_puts("\r\n\t heap total: "); - __furi_put_uint32_as_text(xPortGetTotalHeapSize()); - */ - furi_hal_console_puts("\r\n\t heap free: "); - __furi_put_uint32_as_text(xPortGetFreeHeapSize()); - furi_hal_console_puts("\r\n\t heap watermark: "); - __furi_put_uint32_as_text(xPortGetMinimumEverFreeHeapSize()); + furi_hal_console_puts("\r\n\theap total: "); + __furi_put_uint32_as_text(heap_caps_get_total_size(MALLOC_CAP_DEFAULT)); + furi_hal_console_puts("\r\n\theap free: "); + __furi_put_uint32_as_text(heap_caps_get_free_size(MALLOC_CAP_DEFAULT)); + furi_hal_console_puts("\r\n\theap min free: "); + __furi_put_uint32_as_text(heap_caps_get_minimum_free_size(MALLOC_CAP_DEFAULT)); } static void __furi_print_name(bool isr) { @@ -130,24 +49,13 @@ FURI_NORETURN void __furi_crash_implementation() { bool isr = FURI_IS_IRQ_MODE(); - if (__furi_check_message == NULL) { - __furi_check_message = "Fatal Error"; - } else if (__furi_check_message == (void*)__FURI_ASSERT_MESSAGE_FLAG) { - __furi_check_message = "furi_assert failed"; - } else if (__furi_check_message == (void*)__FURI_CHECK_MESSAGE_FLAG) { - __furi_check_message = "furi_check failed"; - } - furi_hal_console_puts("\r\n\033[0;31m[CRASH]"); __furi_print_name(isr); - furi_hal_console_puts(__furi_check_message); - __furi_print_register_info(); if (!isr) { __furi_print_stack_info(); } __furi_print_heap_info(); - __furi_print_bt_stack_info(); // Check if debug enabled by DAP // https://developer.arm.com/documentation/ddi0403/d/Debug-Architecture/ARMv7-M-Debug/Debug-register-support-in-the-SCS/Debug-Halting-Control-and-Status-Register--DHCSR?lang=en @@ -176,24 +84,13 @@ FURI_NORETURN void __furi_crash_implementation() { } FURI_NORETURN void __furi_halt_implementation() { __disable_irq(); - // GET_MESSAGE_AND_STORE_REGISTERS(); bool isr = FURI_IS_IRQ_MODE(); - if (__furi_check_message == NULL) { - __furi_check_message = "System halt requested."; - } - furi_hal_console_puts("\r\n\033[0;31m[HALT]"); __furi_print_name(isr); - furi_hal_console_puts(__furi_check_message); furi_hal_console_puts("\r\nSystem halted. Bye-bye!\r\n"); furi_hal_console_puts("\033[0m\r\n"); - // Check if debug enabled by DAP - // https://developer.arm.com/documentation/ddi0403/d/Debug-Architecture/ARMv7-M-Debug/Debug-register-support-in-the-SCS/Debug-Halting-Control-and-Status-Register--DHCSR?lang=en - // bool debug = CoreDebug->DHCSR & CoreDebug_DHCSR_C_DEBUGEN_Msk; - // RESTORE_REGISTERS_AND_HALT_MCU(true); - __builtin_unreachable(); } diff --git a/components/furi/src/common_defines.h b/components/furi/src/common_defines.h deleted file mode 100644 index b0062e65..00000000 --- a/components/furi/src/common_defines.h +++ /dev/null @@ -1,60 +0,0 @@ -#pragma once - -#include "core_defines.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -#ifndef FURI_WARN_UNUSED -#define FURI_WARN_UNUSED __attribute__((warn_unused_result)) -#endif - -#ifndef FURI_WEAK -#define FURI_WEAK __attribute__((weak)) -#endif - -#ifndef FURI_PACKED -#define FURI_PACKED __attribute__((packed)) -#endif - -#ifndef FURI_IS_IRQ_MASKED -#define FURI_IS_IRQ_MASKED() (__get_PRIMASK() != 0U) -#endif - -#ifndef FURI_IS_IRQ_MODE -#define FURI_IS_IRQ_MODE() (__get_IPSR() != 0U) -#endif - -#ifndef FURI_IS_ISR -#define FURI_IS_ISR() (FURI_IS_IRQ_MODE() || FURI_IS_IRQ_MASKED()) -#endif - -typedef struct { - uint32_t isrm; - bool from_isr; - bool kernel_running; -} __FuriCriticalInfo; - -__FuriCriticalInfo __furi_critical_enter(void); - -void __furi_critical_exit(__FuriCriticalInfo info); - -#ifndef FURI_CRITICAL_ENTER -#define FURI_CRITICAL_ENTER() __FuriCriticalInfo __furi_critical_info = __furi_critical_enter(); -#endif - -#ifndef FURI_CRITICAL_EXIT -#define FURI_CRITICAL_EXIT() __furi_critical_exit(__furi_critical_info); -#endif - -#ifndef FURI_CHECK_RETURN -#define FURI_CHECK_RETURN __attribute__((__warn_unused_result__)) -#endif - -#ifdef __cplusplus -} -#endif diff --git a/components/furi/src/critical.c b/components/furi/src/critical.c index 78836a59..26460127 100644 --- a/components/furi/src/critical.c +++ b/components/furi/src/critical.c @@ -1,4 +1,5 @@ -#include "common_defines.h" +#include "critical.h" +#include "furi_core_defines.h" #include #include diff --git a/components/furi/src/critical.h b/components/furi/src/critical.h new file mode 100644 index 00000000..76bc5a2c --- /dev/null +++ b/components/furi/src/critical.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include + +#ifndef FURI_CRITICAL_ENTER +#define FURI_CRITICAL_ENTER() __FuriCriticalInfo __furi_critical_info = __furi_critical_enter(); +#endif + +#ifndef FURI_CRITICAL_EXIT +#define FURI_CRITICAL_EXIT() __furi_critical_exit(__furi_critical_info); +#endif + +typedef struct { + uint32_t isrm; + bool from_isr; + bool kernel_running; +} __FuriCriticalInfo; + +__FuriCriticalInfo __furi_critical_enter(void); + +void __furi_critical_exit(__FuriCriticalInfo info); diff --git a/components/furi/src/event_flag.c b/components/furi/src/event_flag.c index c3d53062..08247db7 100644 --- a/components/furi/src/event_flag.c +++ b/components/furi/src/event_flag.c @@ -1,6 +1,6 @@ #include "event_flag.h" #include "check.h" -#include "common_defines.h" +#include "furi_core_defines.h" #include #include diff --git a/components/furi/src/event_flag.h b/components/furi/src/event_flag.h index 36b3e691..0f786249 100644 --- a/components/furi/src/event_flag.h +++ b/components/furi/src/event_flag.h @@ -4,7 +4,7 @@ */ #pragma once -#include "base.h" +#include "furi_core_types.h" #ifdef __cplusplus extern "C" { diff --git a/components/furi/src/furi.c b/components/furi/src/furi.c new file mode 100644 index 00000000..bb113de6 --- /dev/null +++ b/components/furi/src/furi.c @@ -0,0 +1,30 @@ +#include "furi.h" +#include "app_manifest_registry.h" +#include + +#include +#include + +static bool scheduler_was_running = false; + +void furi_init() { + furi_assert(!furi_kernel_is_irq()); + + if (xTaskGetSchedulerState() == taskSCHEDULER_RUNNING) { + vTaskSuspendAll(); + scheduler_was_running = true; + } + + furi_record_init(); + + xTaskResumeAll(); + +#if defined(__ARM_ARCH_7A__) && (__ARM_ARCH_7A__ == 0U) + /* Service Call interrupt might be configured before kernel start */ + /* and when its priority is lower or equal to BASEPRI, svc instruction */ + /* causes a Hard Fault. */ + NVIC_SetPriority(SVCall_IRQn, 0U); +#endif + + app_manifest_registry_init(); +} diff --git a/components/furi/src/furi.h b/components/furi/src/furi.h new file mode 100644 index 00000000..044d4b35 --- /dev/null +++ b/components/furi/src/furi.h @@ -0,0 +1,28 @@ +#pragma once + +#include + +#include "furi_core.h" + +#include "furi_string.h" +#include "event_flag.h" +#include "kernel.h" +#include "message_queue.h" +#include "mutex.h" +#include "pubsub.h" +#include "record.h" +#include "semaphore.h" +#include "stream_buffer.h" +#include "string.h" +#include "thread.h" +#include "timer.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void furi_init(); + +#ifdef __cplusplus +} +#endif diff --git a/components/furi/src/furi_core.h b/components/furi/src/furi_core.h new file mode 100644 index 00000000..0bb659d5 --- /dev/null +++ b/components/furi/src/furi_core.h @@ -0,0 +1,12 @@ +#pragma once + +#include +#include + +#include "check.h" +#include "critical.h" +#include "event_flag.h" +#include "furi_core_defines.h" +#include "furi_core_types.h" +#include "furi_extra_defines.h" +#include "log.h" diff --git a/components/furi/src/furi_core_defines.h b/components/furi/src/furi_core_defines.h new file mode 100644 index 00000000..38526a00 --- /dev/null +++ b/components/furi/src/furi_core_defines.h @@ -0,0 +1,40 @@ +#pragma once + +#include "freertos/portmacro.h" +#include "furi_extra_defines.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#ifndef FURI_WARN_UNUSED +#define FURI_WARN_UNUSED __attribute__((warn_unused_result)) +#endif + +#ifndef FURI_WEAK +#define FURI_WEAK __attribute__((weak)) +#endif + +#ifndef FURI_PACKED +#define FURI_PACKED __attribute__((packed)) +#endif + +// Used by portENABLE_INTERRUPTS and portDISABLE_INTERRUPTS? +#ifndef FURI_IS_IRQ_MODE +#define FURI_IS_IRQ_MODE() (xPortInIsrContext() == pdTRUE) +#endif + +#ifndef FURI_IS_ISR +#define FURI_IS_ISR() (FURI_IS_IRQ_MODE()) +#endif + +#ifndef FURI_CHECK_RETURN +#define FURI_CHECK_RETURN __attribute__((__warn_unused_result__)) +#endif + +#ifdef __cplusplus +} +#endif diff --git a/components/furi/src/base.h b/components/furi/src/furi_core_types.h similarity index 100% rename from components/furi/src/base.h rename to components/furi/src/furi_core_types.h diff --git a/components/furi/src/core_defines.h b/components/furi/src/furi_extra_defines.h similarity index 100% rename from components/furi/src/core_defines.h rename to components/furi/src/furi_extra_defines.h diff --git a/components/furi/src/furi_hal_console.c b/components/furi/src/furi_hal_console.c index 0fc06773..889690fc 100644 --- a/components/furi/src/furi_hal_console.c +++ b/components/furi/src/furi_hal_console.c @@ -1,10 +1,8 @@ #include "furi_hal_console.h" -#include "common_defines.h" +#include "furi_core.h" #include "furi_string.h" -#include -#include -#include +#include "esp_log.h" // TODO remove #define TAG "FuriHalConsole" diff --git a/components/furi/src/furi_hal_console.h b/components/furi/src/furi_hal_console.h index ce31a66b..3ce6d3f7 100644 --- a/components/furi/src/furi_hal_console.h +++ b/components/furi/src/furi_hal_console.h @@ -1,7 +1,5 @@ #pragma once -#include -#include #include #ifdef __cplusplus diff --git a/components/furi/src/kernel.c b/components/furi/src/kernel.c index 9d760ec7..c1c69ebd 100644 --- a/components/furi/src/kernel.c +++ b/components/furi/src/kernel.c @@ -1,34 +1,14 @@ #include "kernel.h" -#include "base.h" #include "check.h" -#include "common_defines.h" +#include "furi_core_defines.h" +#include "furi_core_types.h" #include #include #include -bool furi_kernel_is_irq_or_masked() { - bool irq = false; - BaseType_t state; - - if (FURI_IS_IRQ_MODE()) { - /* Called from interrupt context */ - irq = true; - } else { - /* Get FreeRTOS scheduler state */ - state = xTaskGetSchedulerState(); - - if (state != taskSCHEDULER_NOT_STARTED) { - /* Scheduler was started */ - if (FURI_IS_IRQ_MASKED()) { - /* Interrupts are masked */ - irq = true; - } - } - } - - /* Return context, 0: thread context, 1: IRQ context */ - return (irq); +bool furi_kernel_is_irq() { + return FURI_IS_IRQ_MODE(); } bool furi_kernel_is_running() { @@ -36,7 +16,7 @@ bool furi_kernel_is_running() { } int32_t furi_kernel_lock() { - furi_assert(!furi_kernel_is_irq_or_masked()); + furi_assert(!furi_kernel_is_irq()); int32_t lock; @@ -61,7 +41,7 @@ int32_t furi_kernel_lock() { } int32_t furi_kernel_unlock() { - furi_assert(!furi_kernel_is_irq_or_masked()); + furi_assert(!furi_kernel_is_irq()); int32_t lock; @@ -91,7 +71,7 @@ int32_t furi_kernel_unlock() { } int32_t furi_kernel_restore_lock(int32_t lock) { - furi_assert(!furi_kernel_is_irq_or_masked()); + furi_assert(!furi_kernel_is_irq()); switch (xTaskGetSchedulerState()) { case taskSCHEDULER_SUSPENDED: @@ -127,7 +107,7 @@ uint32_t furi_kernel_get_tick_frequency() { } void furi_delay_tick(uint32_t ticks) { - furi_assert(!furi_kernel_is_irq_or_masked()); + furi_assert(!furi_kernel_is_irq()); if (ticks == 0U) { taskYIELD(); } else { @@ -136,7 +116,7 @@ void furi_delay_tick(uint32_t ticks) { } FuriStatus furi_delay_until_tick(uint32_t tick) { - furi_assert(!furi_kernel_is_irq_or_masked()); + furi_assert(!furi_kernel_is_irq()); TickType_t tcnt, delay; FuriStatus stat; @@ -165,7 +145,7 @@ FuriStatus furi_delay_until_tick(uint32_t tick) { uint32_t furi_get_tick() { TickType_t ticks; - if (furi_kernel_is_irq_or_masked() != 0U) { + if (furi_kernel_is_irq() != 0U) { ticks = xTaskGetTickCountFromISR(); } else { ticks = xTaskGetTickCount(); @@ -183,7 +163,7 @@ uint32_t furi_ms_to_ticks(uint32_t milliseconds) { } void furi_delay_ms(uint32_t milliseconds) { - if (!FURI_IS_ISR() && xTaskGetSchedulerState() == taskSCHEDULER_RUNNING) { + if (xTaskGetSchedulerState() == taskSCHEDULER_RUNNING) { if (milliseconds > 0 && milliseconds < portMAX_DELAY - 1) { milliseconds += 1; } diff --git a/components/furi/src/kernel.h b/components/furi/src/kernel.h index b094c303..f6863d9d 100644 --- a/components/furi/src/kernel.h +++ b/components/furi/src/kernel.h @@ -4,7 +4,7 @@ */ #pragma once -#include "base.h" +#include "furi_core_types.h" #define configTICK_RATE_HZ_RAW 1000 @@ -27,7 +27,7 @@ extern "C" { * * @return true if CPU is in IRQ or kernel running and IRQ is masked */ -bool furi_kernel_is_irq_or_masked(); +bool furi_kernel_is_irq(); /** Check if kernel is running * diff --git a/components/furi/src/log.h b/components/furi/src/log.h new file mode 100644 index 00000000..09155ac8 --- /dev/null +++ b/components/furi/src/log.h @@ -0,0 +1,22 @@ +#pragma once + +#include "esp_log.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define FURI_LOG_E(tag, format, ...) \ + ESP_LOGE(tag, format, ##__VA_ARGS__) +#define FURI_LOG_W(tag, format, ...) \ + ESP_LOGW(tag, format, ##__VA_ARGS__) +#define FURI_LOG_I(tag, format, ...) \ + ESP_LOGI(tag, format, ##__VA_ARGS__) +#define FURI_LOG_D(tag, format, ...) \ + ESP_LOGD(tag, format, ##__VA_ARGS__) +#define FURI_LOG_T(tag, format, ...) \ + ESP_LOGT(tag, format, ##__VA_ARGS__) + +#ifdef __cplusplus +} +#endif diff --git a/components/furi/src/message_queue.c b/components/furi/src/message_queue.c index 322b43cc..b12825bb 100644 --- a/components/furi/src/message_queue.c +++ b/components/furi/src/message_queue.c @@ -6,7 +6,7 @@ #include FuriMessageQueue* furi_message_queue_alloc(uint32_t msg_count, uint32_t msg_size) { - furi_assert((furi_kernel_is_irq_or_masked() == 0U) && (msg_count > 0U) && (msg_size > 0U)); + furi_assert((furi_kernel_is_irq() == 0U) && (msg_count > 0U) && (msg_size > 0U)); QueueHandle_t handle = xQueueCreate(msg_count, msg_size); furi_check(handle); @@ -15,7 +15,7 @@ FuriMessageQueue* furi_message_queue_alloc(uint32_t msg_count, uint32_t msg_size } void furi_message_queue_free(FuriMessageQueue* instance) { - furi_assert(furi_kernel_is_irq_or_masked() == 0U); + furi_assert(furi_kernel_is_irq() == 0U); furi_assert(instance); vQueueDelete((QueueHandle_t)instance); @@ -29,7 +29,7 @@ furi_message_queue_put(FuriMessageQueue* instance, const void* msg_ptr, uint32_t stat = FuriStatusOk; - if (furi_kernel_is_irq_or_masked() != 0U) { + if (furi_kernel_is_irq() != 0U) { if ((hQueue == NULL) || (msg_ptr == NULL) || (timeout != 0U)) { stat = FuriStatusErrorParameter; } else { @@ -66,7 +66,7 @@ FuriStatus furi_message_queue_get(FuriMessageQueue* instance, void* msg_ptr, uin stat = FuriStatusOk; - if (furi_kernel_is_irq_or_masked() != 0U) { + if (furi_kernel_is_irq() != 0U) { if ((hQueue == NULL) || (msg_ptr == NULL) || (timeout != 0U)) { stat = FuriStatusErrorParameter; } else { @@ -132,7 +132,7 @@ uint32_t furi_message_queue_get_count(FuriMessageQueue* instance) { if (hQueue == NULL) { count = 0U; - } else if (furi_kernel_is_irq_or_masked() != 0U) { + } else if (furi_kernel_is_irq() != 0U) { count = uxQueueMessagesWaitingFromISR(hQueue); } else { count = uxQueueMessagesWaiting(hQueue); @@ -149,7 +149,7 @@ uint32_t furi_message_queue_get_space(FuriMessageQueue* instance) { if (mq == NULL) { space = 0U; - } else if (furi_kernel_is_irq_or_masked() != 0U) { + } else if (furi_kernel_is_irq() != 0U) { isrm = taskENTER_CRITICAL_FROM_ISR(); /* space = pxQueue->uxLength - pxQueue->uxMessagesWaiting; */ @@ -168,7 +168,7 @@ FuriStatus furi_message_queue_reset(FuriMessageQueue* instance) { QueueHandle_t hQueue = (QueueHandle_t)instance; FuriStatus stat; - if (furi_kernel_is_irq_or_masked() != 0U) { + if (furi_kernel_is_irq() != 0U) { stat = FuriStatusErrorISR; } else if (hQueue == NULL) { stat = FuriStatusErrorParameter; diff --git a/components/furi/src/message_queue.h b/components/furi/src/message_queue.h index 24b777de..f9cb9dae 100644 --- a/components/furi/src/message_queue.h +++ b/components/furi/src/message_queue.h @@ -4,7 +4,7 @@ */ #pragma once -#include "base.h" +#include "furi_core_types.h" #ifdef __cplusplus extern "C" { diff --git a/components/furi/src/mutex.c b/components/furi/src/mutex.c index f910e005..fc1db3cc 100644 --- a/components/furi/src/mutex.c +++ b/components/furi/src/mutex.c @@ -1,6 +1,6 @@ #include "mutex.h" #include "check.h" -#include "common_defines.h" +#include "furi_core_defines.h" #include #include diff --git a/components/furi/src/mutex.h b/components/furi/src/mutex.h index aa55fa7b..bd7c5956 100644 --- a/components/furi/src/mutex.h +++ b/components/furi/src/mutex.h @@ -4,7 +4,7 @@ */ #pragma once -#include "base.h" +#include "furi_core_types.h" #include "thread.h" #ifdef __cplusplus diff --git a/components/furi/src/record.c b/components/furi/src/record.c index 76e15908..5ea69527 100644 --- a/components/furi/src/record.c +++ b/components/furi/src/record.c @@ -2,9 +2,8 @@ #include "check.h" #include "event_flag.h" #include "mutex.h" - +#include "m-dict.h" #include "m_cstr_dup.h" -#include #define FURI_RECORD_FLAG_READY (0x1) diff --git a/components/furi/src/record.h b/components/furi/src/record.h index 748e0000..0c873c33 100644 --- a/components/furi/src/record.h +++ b/components/furi/src/record.h @@ -5,7 +5,7 @@ #pragma once -#include "core_defines.h" +#include "furi_extra_defines.h" #include #ifdef __cplusplus @@ -18,11 +18,11 @@ extern "C" { * @param variable_name the name of the variable that is used in the `code` * @param code the code to execute: consider putting it between {} */ -#define FURI_RECORD_TRANSACTION(record_name, variable_name, code) \ - { \ - Gui*(variable_name) = (Gui*)furi_record_open(record_name); \ - code; \ - furi_record_close(record_name); \ +#define FURI_RECORD_TRANSACTION(record_name, variable_type, variable_name, code) \ + { \ + variable_type (variable_name) = (variable_type)furi_record_open(record_name); \ + code; \ + furi_record_close(record_name); \ } /** Initialize record storage For internal use only. diff --git a/components/furi/src/semaphore.c b/components/furi/src/semaphore.c index dd2020da..b12d70ea 100644 --- a/components/furi/src/semaphore.c +++ b/components/furi/src/semaphore.c @@ -1,6 +1,6 @@ #include "semaphore.h" #include "check.h" -#include "common_defines.h" +#include "furi_core_defines.h" #include #include @@ -99,18 +99,41 @@ FuriStatus furi_semaphore_release(FuriSemaphore* instance) { return (stat); } -//uint32_t furi_semaphore_get_count(FuriSemaphore* instance) { -// furi_assert(instance); -// -// SemaphoreHandle_t hSemaphore = (SemaphoreHandle_t)instance; -// uint32_t count; -// -// if(FURI_IS_IRQ_MODE()) { +uint32_t furi_semaphore_get_count(FuriSemaphore* instance) { + furi_assert(instance); + + SemaphoreHandle_t hSemaphore = (SemaphoreHandle_t)instance; + uint32_t count; + + if(FURI_IS_IRQ_MODE()) { + furi_crash("not implemented"); // count = (uint32_t)uxSemaphoreGetCountFromISR(hSemaphore); -// } else { -// count = (uint32_t)uxSemaphoreGetCount(hSemaphore); -// } -// -// /* Return number of tokens */ -// return (count); -//} + } else { + count = (uint32_t)uxSemaphoreGetCount(hSemaphore); + } + + /* Return number of tokens */ + return (count); +} + +bool furi_semaphore_take(FuriSemaphore* instance, TickType_t timeout) { + furi_assert(instance); + SemaphoreHandle_t hSemaphore = (SemaphoreHandle_t)instance; + + if(FURI_IS_IRQ_MODE()) { + furi_crash("not implemented"); + } else { + return xSemaphoreTake(hSemaphore, timeout) == pdTRUE; + } +} + +bool furi_semaphore_give(FuriSemaphore* instance) { + furi_assert(instance); + SemaphoreHandle_t hSemaphore = (SemaphoreHandle_t)instance; + + if(FURI_IS_IRQ_MODE()) { + furi_crash("not implemented"); + } else { + return xSemaphoreGive(hSemaphore); + } +} diff --git a/components/furi/src/semaphore.h b/components/furi/src/semaphore.h index 30d3acc7..19b8d6c6 100644 --- a/components/furi/src/semaphore.h +++ b/components/furi/src/semaphore.h @@ -1,10 +1,6 @@ -/** - * @file semaphore.h - * FuriSemaphore - */ #pragma once -#include "base.h" +#include "furi_core_types.h" #include "thread.h" #ifdef __cplusplus @@ -45,13 +41,30 @@ FuriStatus furi_semaphore_acquire(FuriSemaphore* instance, uint32_t timeout); */ FuriStatus furi_semaphore_release(FuriSemaphore* instance); -///** Get semaphore count -// * -// * @param instance The pointer to FuriSemaphore instance -// * -// * @return Semaphore count -// */ -//uint32_t furi_semaphore_get_count(FuriSemaphore* instance); +/** Get semaphore count + * + * @param instance The pointer to FuriSemaphore instance + * + * @return Semaphore count + */ +uint32_t furi_semaphore_get_count(FuriSemaphore* instance); + +/** Wait for the semaphore to become available + * + * @param instance The pointer to FuriSemaphore instance + * @param timeout The maximum amount of ticks to wait for the semaphore to become available + * + * @return True if the semaphore became available. False on timeout. + */ +bool furi_semaphore_take(FuriSemaphore* instance, TickType_t timeout); + +/** Wait for the semaphore to become available + * + * @param instance The pointer to FuriSemaphore instance + * + * @return True if the semaphore became available. False on timeout. + */ +bool furi_semaphore_give(FuriSemaphore* instance); #ifdef __cplusplus } diff --git a/components/furi/src/stream_buffer.c b/components/furi/src/stream_buffer.c index f9726caf..2b0cc902 100644 --- a/components/furi/src/stream_buffer.c +++ b/components/furi/src/stream_buffer.c @@ -1,7 +1,7 @@ #include "stream_buffer.h" -#include "base.h" #include "check.h" -#include "common_defines.h" +#include "furi_core_defines.h" +#include "furi_core_types.h" #include #include diff --git a/components/furi/src/stream_buffer.h b/components/furi/src/stream_buffer.h index e27e897d..b0e2ae70 100644 --- a/components/furi/src/stream_buffer.h +++ b/components/furi/src/stream_buffer.h @@ -12,10 +12,10 @@ * interrupt that will read from the buffer (the reader). */ #pragma once +#include "furi_core_types.h" +#include #include #include -#include -#include "base.h" #ifdef __cplusplus extern "C" { diff --git a/components/furi/src/thread.c b/components/furi/src/thread.c index 252f6c9a..1dc4ef84 100644 --- a/components/furi/src/thread.c +++ b/components/furi/src/thread.c @@ -1,6 +1,6 @@ #include "thread.h" #include "check.h" -#include "common_defines.h" +#include "furi_core_defines.h" #include "furi_string.h" #include "kernel.h" diff --git a/components/furi/src/thread.h b/components/furi/src/thread.h index 121de55e..e85b44db 100644 --- a/components/furi/src/thread.h +++ b/components/furi/src/thread.h @@ -5,8 +5,8 @@ #pragma once -#include "base.h" -#include "common_defines.h" +#include "furi_core_defines.h" +#include "furi_core_types.h" #include #include diff --git a/components/furi/src/timer.c b/components/furi/src/timer.c index f796b49d..1e6ebb16 100644 --- a/components/furi/src/timer.c +++ b/components/furi/src/timer.c @@ -25,7 +25,7 @@ static void TimerCallback(TimerHandle_t hTimer) { } FuriTimer* furi_timer_alloc(FuriTimerCallback func, FuriTimerType type, void* context) { - furi_assert((furi_kernel_is_irq_or_masked() == 0U) && (func != NULL)); + furi_assert((furi_kernel_is_irq() == 0U) && (func != NULL)); TimerHandle_t hTimer; TimerCallback_t* callb; @@ -58,7 +58,7 @@ FuriTimer* furi_timer_alloc(FuriTimerCallback func, FuriTimerType type, void* co } void furi_timer_free(FuriTimer* instance) { - furi_assert(!furi_kernel_is_irq_or_masked()); + furi_assert(!furi_kernel_is_irq()); furi_assert(instance); TimerHandle_t hTimer = (TimerHandle_t)instance; @@ -80,7 +80,7 @@ void furi_timer_free(FuriTimer* instance) { } FuriStatus furi_timer_start(FuriTimer* instance, uint32_t ticks) { - furi_assert(!furi_kernel_is_irq_or_masked()); + furi_assert(!furi_kernel_is_irq()); furi_assert(instance); furi_assert(ticks < portMAX_DELAY); @@ -98,7 +98,7 @@ FuriStatus furi_timer_start(FuriTimer* instance, uint32_t ticks) { } FuriStatus furi_timer_restart(FuriTimer* instance, uint32_t ticks) { - furi_assert(!furi_kernel_is_irq_or_masked()); + furi_assert(!furi_kernel_is_irq()); furi_assert(instance); furi_assert(ticks < portMAX_DELAY); @@ -117,7 +117,7 @@ FuriStatus furi_timer_restart(FuriTimer* instance, uint32_t ticks) { } FuriStatus furi_timer_stop(FuriTimer* instance) { - furi_assert(!furi_kernel_is_irq_or_masked()); + furi_assert(!furi_kernel_is_irq()); furi_assert(instance); TimerHandle_t hTimer = (TimerHandle_t)instance; @@ -128,7 +128,7 @@ FuriStatus furi_timer_stop(FuriTimer* instance) { } uint32_t furi_timer_is_running(FuriTimer* instance) { - furi_assert(!furi_kernel_is_irq_or_masked()); + furi_assert(!furi_kernel_is_irq()); furi_assert(instance); TimerHandle_t hTimer = (TimerHandle_t)instance; @@ -138,7 +138,7 @@ uint32_t furi_timer_is_running(FuriTimer* instance) { } uint32_t furi_timer_get_expire_time(FuriTimer* instance) { - furi_assert(!furi_kernel_is_irq_or_masked()); + furi_assert(!furi_kernel_is_irq()); furi_assert(instance); TimerHandle_t hTimer = (TimerHandle_t)instance; @@ -148,7 +148,7 @@ uint32_t furi_timer_get_expire_time(FuriTimer* instance) { void furi_timer_pending_callback(FuriTimerPendigCallback callback, void* context, uint32_t arg) { BaseType_t ret = pdFAIL; - if (furi_kernel_is_irq_or_masked()) { + if (furi_kernel_is_irq()) { ret = xTimerPendFunctionCallFromISR(callback, context, arg, NULL); } else { ret = xTimerPendFunctionCall(callback, context, arg, FuriWaitForever); @@ -157,7 +157,7 @@ void furi_timer_pending_callback(FuriTimerPendigCallback callback, void* context } void furi_timer_set_thread_priority(FuriTimerThreadPriority priority) { - furi_assert(!furi_kernel_is_irq_or_masked()); + furi_assert(!furi_kernel_is_irq()); TaskHandle_t task_handle = xTimerGetTimerDaemonTaskHandle(); furi_check(task_handle); // Don't call this method before timer task start diff --git a/components/furi/src/timer.h b/components/furi/src/timer.h index 58efbe9d..9d381930 100644 --- a/components/furi/src/timer.h +++ b/components/furi/src/timer.h @@ -1,6 +1,6 @@ #pragma once -#include "base.h" +#include "furi_core_types.h" #ifdef __cplusplus extern "C" { diff --git a/components/mlib/m-tuple.h b/components/mlib/m-tuple.h index 55edc1ae..731dc2ab 100644 --- a/components/mlib/m-tuple.h +++ b/components/mlib/m-tuple.h @@ -363,8 +363,8 @@ namespace m_lib { function_name(name_t v \ M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \ { \ - M_CALL_CLEAR(oplist, v->name); \ - M_EMPLACE_CALL_FUNC(a, init_func, oplist, v->name, exp_emplace_type); \ + M_CALL_CLEAR(oplist, v->id); \ + M_EMPLACE_CALL_FUNC(a, init_func, oplist, v->id, exp_emplace_type); \ } diff --git a/components/nanobake/CMakeLists.txt b/components/nanobake/CMakeLists.txt index 61ad3de4..9be4bc94 100644 --- a/components/nanobake/CMakeLists.txt +++ b/components/nanobake/CMakeLists.txt @@ -1,10 +1,9 @@ idf_component_register( SRC_DIRS "src" - "src/applications" - "src/applications/system/system_info" - "src/applications/services/desktop" - "src/applications/services/loader" - "src/applications/services/gui" + "src/apps/system/system_info" + "src/apps/services/desktop" + "src/apps/services/loader" + "src/apps/services/gui" INCLUDE_DIRS "src" REQUIRES esp_lvgl_port esp_lcd esp_lcd_touch driver mlib cmsis_core furi ) diff --git a/components/nanobake/src/app.c b/components/nanobake/src/app.c deleted file mode 100644 index 98692b12..00000000 --- a/components/nanobake/src/app.c +++ /dev/null @@ -1,19 +0,0 @@ -#include "app_i.h" -#include "check.h" - -const char* prv_type_service = "service"; -const char* prv_type_system = "system"; -const char* prv_type_user = "user"; - -const char* nb_app_type_to_string(AppType type) { - switch (type) { - case SERVICE: - return prv_type_service; - case SYSTEM: - return prv_type_system; - case USER: - return prv_type_user; - default: - furi_crash(); - } -} diff --git a/components/nanobake/src/app.h b/components/nanobake/src/app.h deleted file mode 100644 index 524241a8..00000000 --- a/components/nanobake/src/app.h +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include "esp_err.h" -#include "lvgl.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define NB_APP_ID_LENGTH 32 -#define NB_APP_NAME_LENGTH 32 - -typedef enum { - SERVICE, - SYSTEM, - USER -} AppType; - -typedef enum { - NB_TASK_PRIORITY_DEFAULT = 10 -} AppPriority; - -typedef enum { - NB_TASK_STACK_SIZE_DEFAULT = 2048 -} AppStackSize; - -typedef int32_t (*AppEntryPoint)(void _Nonnull* parameter); - -typedef struct { - const char id[NB_APP_ID_LENGTH]; - const char name[NB_APP_NAME_LENGTH]; - const AppType type; - const AppEntryPoint _Nullable entry_point; - const AppStackSize stack_size; - const AppPriority priority; -} App; - -#ifdef __cplusplus -} -#endif diff --git a/components/nanobake/src/app_i.h b/components/nanobake/src/app_i.h deleted file mode 100644 index 7053643a..00000000 --- a/components/nanobake/src/app_i.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include "app.h" - -#ifdef __cplusplus -extern "C" { -#endif - -const char* nb_app_type_to_string(AppType type); - -#ifdef __cplusplus -} -#endif diff --git a/components/nanobake/src/applications/applications.c b/components/nanobake/src/applications/applications.c deleted file mode 100644 index 3ff2392f..00000000 --- a/components/nanobake/src/applications/applications.c +++ /dev/null @@ -1,28 +0,0 @@ -#include "applications_i.h" - -// System services -extern const App desktop_app; -extern const App gui_app; -extern const App loader_app; - -// System apps -extern const App system_info_app; - -const App* const NANOBAKE_SERVICES[] = { - &desktop_app, - &gui_app, - &loader_app -}; - -const size_t NANOBAKE_SERVICES_COUNT = sizeof(NANOBAKE_SERVICES) / sizeof(App*); - -const App* const NANOBAKE_SYSTEM_APPS[] = { - &system_info_app -}; - -const size_t NANOBAKE_SYSTEM_APPS_COUNT = sizeof(NANOBAKE_SYSTEM_APPS) / sizeof(App*); - -const OnSystemStart NANOBAKE_ON_SYSTEM_START[] = { -}; - -const size_t NANOBAKE_ON_SYSTEM_START_COUNT = sizeof(NANOBAKE_ON_SYSTEM_START) / sizeof(OnSystemStart); diff --git a/components/nanobake/src/applications/applications_i.h b/components/nanobake/src/applications/applications_i.h deleted file mode 100644 index b97b38cf..00000000 --- a/components/nanobake/src/applications/applications_i.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include "app.h" -#include "devices.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef void (*OnSystemStart)(Devices* hardware); - -extern const App* const NANOBAKE_SERVICES[]; -extern const size_t NANOBAKE_SERVICES_COUNT; - -extern const App* const NANOBAKE_SYSTEM_APPS[]; -extern const size_t NANOBAKE_SYSTEM_APPS_COUNT; - -extern const OnSystemStart NANOBAKE_ON_SYSTEM_START[]; -extern const size_t NANOBAKE_ON_SYSTEM_START_COUNT; - -#ifdef __cplusplus -} -#endif diff --git a/components/nanobake/src/applications/services/loader/loader.c b/components/nanobake/src/applications/services/loader/loader.c deleted file mode 100644 index cf2aab37..00000000 --- a/components/nanobake/src/applications/services/loader/loader.c +++ /dev/null @@ -1,17 +0,0 @@ -#include "loader.h" -#include "core_defines.h" - -static int32_t prv_loader_main(void* param) { - UNUSED(param); - printf("loader app init\n"); - return 0; -} - -const App loader_app = { - .id = "loader", - .name = "Loader", - .type = SERVICE, - .entry_point = &prv_loader_main, - .stack_size = NB_TASK_STACK_SIZE_DEFAULT, - .priority = NB_TASK_PRIORITY_DEFAULT -}; diff --git a/components/nanobake/src/applications/services/loader/loader.h b/components/nanobake/src/applications/services/loader/loader.h deleted file mode 100644 index 3f7dea52..00000000 --- a/components/nanobake/src/applications/services/loader/loader.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include "app.h" - -#ifdef __cplusplus -extern "C" { -#endif - -extern const App loader_app; - -#ifdef __cplusplus -} -#endif diff --git a/components/nanobake/src/applications/system/system_info/system_info.c b/components/nanobake/src/applications/system/system_info/system_info.c deleted file mode 100644 index 853286f1..00000000 --- a/components/nanobake/src/applications/system/system_info/system_info.c +++ /dev/null @@ -1,39 +0,0 @@ -#include "system_info.h" -#include "core_defines.h" -#include "nanobake.h" -#include "thread.h" - -static int32_t system_info_entry_point(void* param) { - UNUSED(param); - - // Wait for all apps to start - vTaskDelay(1000 / portTICK_PERIOD_MS); - - size_t system_service_count = nanobake_get_app_thread_count(); - printf("Running apps:\n"); - for (int i = 0; i < system_service_count; ++i) { - FuriThreadId thread_id = nanobake_get_app_thread_id(i); - const char* appid = furi_thread_get_appid(thread_id); - const char* name = furi_thread_get_name(thread_id); - bool is_suspended = furi_thread_is_suspended(thread_id); - const char* status = is_suspended ? "suspended" : "active"; - printf(" - [%s] %s (%s)\n", status, name, appid); - } - - printf( - "Heap memory available: %d / %d\n", - heap_caps_get_free_size(MALLOC_CAP_DEFAULT), - heap_caps_get_total_size(MALLOC_CAP_DEFAULT) - ); - - return 0; -} - -App system_info_app = { - .id = "systeminfo", - .name = "System Info", - .type = SYSTEM, - .entry_point = &system_info_entry_point, - .stack_size = NB_TASK_STACK_SIZE_DEFAULT, - .priority = NB_TASK_PRIORITY_DEFAULT -}; diff --git a/components/nanobake/src/applications/services/desktop/desktop.c b/components/nanobake/src/apps/services/desktop/desktop.c similarity index 55% rename from components/nanobake/src/applications/services/desktop/desktop.c rename to components/nanobake/src/apps/services/desktop/desktop.c index ca89a3d7..64e3fe57 100644 --- a/components/nanobake/src/applications/services/desktop/desktop.c +++ b/components/nanobake/src/apps/services/desktop/desktop.c @@ -1,6 +1,5 @@ #include "desktop.h" -#include "core_defines.h" -#include "devices.h" +#include "furi_extra_defines.h" static int32_t prv_desktop_main(void* param) { UNUSED(param); @@ -8,11 +7,11 @@ static int32_t prv_desktop_main(void* param) { return 0; } -const App desktop_app = { +const AppManifest desktop_app = { .id = "desktop", .name = "Desktop", - .type = SERVICE, + .icon = NULL, + .type = AppTypeService, .entry_point = &prv_desktop_main, - .stack_size = NB_TASK_STACK_SIZE_DEFAULT, - .priority = NB_TASK_PRIORITY_DEFAULT + .stack_size = AppStackSizeNormal }; diff --git a/components/nanobake/src/applications/services/desktop/desktop.h b/components/nanobake/src/apps/services/desktop/desktop.h similarity index 56% rename from components/nanobake/src/applications/services/desktop/desktop.h rename to components/nanobake/src/apps/services/desktop/desktop.h index aca20fe2..13ba7acb 100644 --- a/components/nanobake/src/applications/services/desktop/desktop.h +++ b/components/nanobake/src/apps/services/desktop/desktop.h @@ -1,12 +1,12 @@ #pragma once -#include "app.h" +#include "app_manifest.h" #ifdef __cplusplus extern "C" { #endif -extern const App desktop_app; +extern const AppManifest desktop_app; #ifdef __cplusplus } diff --git a/components/nanobake/src/applications/services/gui/gui.c b/components/nanobake/src/apps/services/gui/gui.c similarity index 96% rename from components/nanobake/src/applications/services/gui/gui.c rename to components/nanobake/src/apps/services/gui/gui.c index e0408a2d..3a48aa91 100644 --- a/components/nanobake/src/applications/services/gui/gui.c +++ b/components/nanobake/src/apps/services/gui/gui.c @@ -1,5 +1,6 @@ #include "check.h" -#include "core_defines.h" +#include "esp_lvgl_port.h" +#include "furi_extra_defines.h" #include "gui_i.h" #include "record.h" @@ -184,7 +185,11 @@ Gui* gui_alloc() { Gui* gui = malloc(sizeof(Gui)); gui->thread_id = furi_thread_get_current_id(); gui->mutex = furi_mutex_alloc(FuriMutexTypeNormal); + + furi_check(lvgl_port_lock(100)); gui->lvgl_parent = lv_scr_act(); + lvgl_port_unlock(); + gui->lockdown = false; furi_check(gui->mutex); for (size_t i = 0; i < GuiLayerMAX; i++) { @@ -231,11 +236,11 @@ __attribute((__noreturn__)) int32_t prv_gui_main(void* parameter) { } } -const App gui_app = { +const AppManifest gui_app = { .id = "gui", .name = "GUI", - .type = SERVICE, + .icon = NULL, + .type = AppTypeService, .entry_point = &prv_gui_main, - .stack_size = NB_TASK_STACK_SIZE_DEFAULT, - .priority = NB_TASK_PRIORITY_DEFAULT + .stack_size = AppStackSizeNormal }; diff --git a/components/nanobake/src/applications/services/gui/gui.h b/components/nanobake/src/apps/services/gui/gui.h similarity index 87% rename from components/nanobake/src/applications/services/gui/gui.h rename to components/nanobake/src/apps/services/gui/gui.h index e99864ca..62873a34 100644 --- a/components/nanobake/src/applications/services/gui/gui.h +++ b/components/nanobake/src/apps/services/gui/gui.h @@ -1,22 +1,13 @@ #pragma once -#include "app.h" -#include "lvgl.h" +#include "app_manifest.h" #include "view_port.h" #ifdef __cplusplus extern "C" { #endif -extern const App gui_app; - -/** Canvas Orientation */ -typedef enum { - CanvasOrientationHorizontal, - CanvasOrientationHorizontalFlip, - CanvasOrientationVertical, - CanvasOrientationVerticalFlip, -} CanvasOrientation; +extern const AppManifest gui_app; /** Gui layers */ typedef enum { @@ -36,7 +27,6 @@ typedef enum { typedef void (*GuiCanvasCommitCallback)( uint8_t* data, size_t size, - CanvasOrientation orientation, void* context ); diff --git a/components/nanobake/src/applications/services/gui/gui_draw.c b/components/nanobake/src/apps/services/gui/gui_draw.c similarity index 100% rename from components/nanobake/src/applications/services/gui/gui_draw.c rename to components/nanobake/src/apps/services/gui/gui_draw.c diff --git a/components/nanobake/src/applications/services/gui/gui_i.h b/components/nanobake/src/apps/services/gui/gui_i.h similarity index 100% rename from components/nanobake/src/applications/services/gui/gui_i.h rename to components/nanobake/src/apps/services/gui/gui_i.h diff --git a/components/nanobake/src/applications/services/gui/gui_input.c b/components/nanobake/src/apps/services/gui/gui_input.c similarity index 100% rename from components/nanobake/src/applications/services/gui/gui_input.c rename to components/nanobake/src/apps/services/gui/gui_input.c diff --git a/components/nanobake/src/apps/services/gui/icon.c b/components/nanobake/src/apps/services/gui/icon.c new file mode 100644 index 00000000..98f35b12 --- /dev/null +++ b/components/nanobake/src/apps/services/gui/icon.c @@ -0,0 +1,13 @@ +#include "icon_i.h" + +uint8_t icon_get_width(const Icon* instance) { + return instance->width; +} + +uint8_t icon_get_height(const Icon* instance) { + return instance->height; +} + +const uint8_t* icon_get_data(const Icon* instance) { + return instance->frames[0]; +} diff --git a/components/nanobake/src/apps/services/gui/icon.h b/components/nanobake/src/apps/services/gui/icon.h new file mode 100644 index 00000000..d2de599b --- /dev/null +++ b/components/nanobake/src/apps/services/gui/icon.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +struct Icon { + const uint8_t width; + const uint8_t height; + const uint8_t frame_count; + const uint8_t frame_rate; + const uint8_t* const* frames; +}; diff --git a/components/nanobake/src/apps/services/gui/icon_i.h b/components/nanobake/src/apps/services/gui/icon_i.h new file mode 100644 index 00000000..565dde34 --- /dev/null +++ b/components/nanobake/src/apps/services/gui/icon_i.h @@ -0,0 +1,10 @@ +#pragma once +#include "icon.h" + +typedef struct { + const uint8_t width; + const uint8_t height; + const uint8_t frame_count; + const uint8_t frame_rate; + const uint8_t* const* frames; +} Icon; diff --git a/components/nanobake/src/applications/services/gui/view_port.c b/components/nanobake/src/apps/services/gui/view_port.c similarity index 97% rename from components/nanobake/src/applications/services/gui/view_port.c rename to components/nanobake/src/apps/services/gui/view_port.c index 59b55ac0..bf516bc4 100644 --- a/components/nanobake/src/applications/services/gui/view_port.c +++ b/components/nanobake/src/apps/services/gui/view_port.c @@ -2,6 +2,7 @@ #include "gui.h" #include "gui_i.h" #include "view_port_i.h" +#include "esp_lvgl_port.h" #define TAG "viewport" @@ -88,7 +89,10 @@ void view_port_draw(ViewPort* view_port, lv_obj_t* parent) { furi_check(view_port->gui); if (view_port->draw_callback) { + furi_check(lvgl_port_lock(100)); lv_obj_clean(parent); + lvgl_port_unlock(); + view_port->draw_callback(parent, view_port->draw_callback_context); } diff --git a/components/nanobake/src/applications/services/gui/view_port.h b/components/nanobake/src/apps/services/gui/view_port.h similarity index 100% rename from components/nanobake/src/applications/services/gui/view_port.h rename to components/nanobake/src/apps/services/gui/view_port.h diff --git a/components/nanobake/src/applications/services/gui/view_port_i.h b/components/nanobake/src/apps/services/gui/view_port_i.h similarity index 100% rename from components/nanobake/src/applications/services/gui/view_port_i.h rename to components/nanobake/src/apps/services/gui/view_port_i.h diff --git a/components/nanobake/src/applications/services/gui/view_port_input.c b/components/nanobake/src/apps/services/gui/view_port_input.c similarity index 100% rename from components/nanobake/src/applications/services/gui/view_port_input.c rename to components/nanobake/src/apps/services/gui/view_port_input.c diff --git a/components/nanobake/src/applications/services/gui/view_port_input.h b/components/nanobake/src/apps/services/gui/view_port_input.h similarity index 100% rename from components/nanobake/src/applications/services/gui/view_port_input.h rename to components/nanobake/src/apps/services/gui/view_port_input.h diff --git a/components/nanobake/src/apps/services/loader/loader.c b/components/nanobake/src/apps/services/loader/loader.c new file mode 100644 index 00000000..5027ebe8 --- /dev/null +++ b/components/nanobake/src/apps/services/loader/loader.c @@ -0,0 +1,290 @@ +#include "loader.h" +#include "app_i.h" +#include "app_manifest.h" +#include "app_manifest_registry.h" +#include "loader_i.h" +#include +#include "esp_heap_caps.h" + +#define TAG "Loader" +#define LOADER_MAGIC_THREAD_VALUE 0xDEADBEEF + +LoaderStatus loader_start(Loader* loader, const char* id, const char* args, FuriString* error_message) { + LoaderMessage message; + LoaderMessageLoaderStatusResult result; + + message.type = LoaderMessageTypeStartByName; + message.start.id = id; + message.start.args = args; + message.start.error_message = error_message; + message.api_lock = api_lock_alloc_locked(); + message.status_value = &result; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); + api_lock_wait_unlock_and_free(message.api_lock); + return result.value; +} + +bool loader_lock(Loader* loader) { + LoaderMessage message; + LoaderMessageBoolResult result; + message.type = LoaderMessageTypeLock; + message.api_lock = api_lock_alloc_locked(); + message.bool_value = &result; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); + api_lock_wait_unlock_and_free(message.api_lock); + return result.value; +} + +void loader_unlock(Loader* loader) { + LoaderMessage message; + message.type = LoaderMessageTypeUnlock; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); +} + +bool loader_is_locked(Loader* loader) { + LoaderMessage message; + LoaderMessageBoolResult result; + message.type = LoaderMessageTypeIsLocked; + message.api_lock = api_lock_alloc_locked(); + message.bool_value = &result; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); + api_lock_wait_unlock_and_free(message.api_lock); + return result.value; +} + +FuriPubSub* loader_get_pubsub(Loader* loader) { + furi_assert(loader); + // it's safe to return pubsub without locking + // because it's never freed and loader is never exited + // also the loader instance cannot be obtained until the pubsub is created + return loader->pubsub; +} + +// callbacks + +static void loader_thread_state_callback(FuriThreadState thread_state, void* context) { + furi_assert(context); + + Loader* loader = context; + + if (thread_state == FuriThreadStateRunning) { + LoaderEvent event; + event.type = LoaderEventTypeApplicationStarted; + furi_pubsub_publish(loader->pubsub, &event); + } else if (thread_state == FuriThreadStateStopped) { + LoaderMessage message; + message.type = LoaderMessageTypeAppClosed; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); + } +} + +// implementation + +static Loader* loader_alloc() { + Loader* loader = malloc(sizeof(Loader)); + loader->pubsub = furi_pubsub_alloc(); + loader->queue = furi_message_queue_alloc(1, sizeof(LoaderMessage)); + loader->app_data.args = NULL; + loader->app_data.thread = NULL; + loader->app_data.app = NULL; + return loader; +} + +static void loader_start_app_thread(Loader* loader) { + // setup thread state callbacks + furi_thread_set_state_context(loader->app_data.thread, loader); + furi_thread_set_state_callback(loader->app_data.thread, loader_thread_state_callback); + + // start app thread + furi_thread_start(loader->app_data.thread); +} + +static void loader_log_status_error( + LoaderStatus status, + FuriString* error_message, + const char* format, + va_list args +) { + if (error_message) { + furi_string_vprintf(error_message, format, args); + FURI_LOG_E(TAG, "Status [%d]: %s", status, furi_string_get_cstr(error_message)); + } else { + FURI_LOG_E(TAG, "Status [%d]", status); + } +} + +static LoaderStatus loader_make_status_error( + LoaderStatus status, + FuriString* error_message, + const char* format, + ... +) { + va_list args; + va_start(args, format); + loader_log_status_error(status, error_message, format, args); + va_end(args); + return status; +} + +static LoaderStatus loader_make_success_status(FuriString* error_message) { + if (error_message) { + furi_string_set(error_message, "App started"); + } + + return LoaderStatusOk; +} + +static void loader_start_app( + Loader* loader, + const AppManifest* _Nonnull manifest, + const char* args +) { + FURI_LOG_I(TAG, "Starting %s", manifest->id); + + App* _Nonnull app = furi_app_alloc(manifest); + loader->app_data.app = app; + + FuriThread* thread = furi_app_alloc_thread(loader->app_data.app, args); + loader->app_data.app->thread = thread; + loader->app_data.thread = thread; + + loader_start_app_thread(loader); +} + +// process messages + +static bool loader_do_is_locked(Loader* loader) { + return loader->app_data.thread != NULL; +} + +static LoaderStatus loader_do_start_by_id( + Loader* loader, + const char* id, + const char* args, + FuriString* error_message +) { + // check lock + if (loader_do_is_locked(loader)) { + const char* current_thread_name = + furi_thread_get_name(furi_thread_get_id(loader->app_data.thread)); + return loader_make_status_error( + LoaderStatusErrorAppStarted, + error_message, + "Loader is locked, please close the \"%s\" first", + current_thread_name + ); + } + + const AppManifest* manifest = app_manifest_registry_find_by_id(id); + if (manifest == NULL) { + return loader_make_status_error( + LoaderStatusErrorUnknownApp, + error_message, + "Application \"%s\" not found", + id + ); + } + + loader_start_app(loader, manifest, args); + return loader_make_success_status(error_message); +} + +static bool loader_do_lock(Loader* loader) { + if (loader->app_data.thread) { + return false; + } + + loader->app_data.thread = (FuriThread*)LOADER_MAGIC_THREAD_VALUE; + return true; +} + +static void loader_do_unlock(Loader* loader) { + furi_check(loader->app_data.thread == (FuriThread*)LOADER_MAGIC_THREAD_VALUE); + loader->app_data.thread = NULL; +} + +static void loader_do_app_closed(Loader* loader) { + furi_assert(loader->app_data.thread); + + furi_thread_join(loader->app_data.thread); + FURI_LOG_I( + TAG, + "App %s returned: %li", + loader->app_data.app->manifest->id, + furi_thread_get_return_code(loader->app_data.thread) + ); + + if (loader->app_data.args) { + free(loader->app_data.args); + loader->app_data.args = NULL; + } + + if (loader->app_data.app) { + furi_app_free(loader->app_data.app); + loader->app_data.app = NULL; + } else { + assert(loader->app_data.thread == NULL); + furi_thread_free(loader->app_data.thread); + } + + loader->app_data.thread = NULL; + + FURI_LOG_I( + TAG, + "Application stopped. Free heap: %zu", + heap_caps_get_free_size(MALLOC_CAP_DEFAULT) + ); + + LoaderEvent event; + event.type = LoaderEventTypeApplicationStopped; + furi_pubsub_publish(loader->pubsub, &event); +} + +// app + +_Noreturn int32_t loader_main(void* p) { + UNUSED(p); + + Loader* loader = loader_alloc(); + furi_record_create(RECORD_LOADER, loader); + + LoaderMessage message; + while (true) { + if (furi_message_queue_get(loader->queue, &message, FuriWaitForever) == FuriStatusOk) { + switch (message.type) { + case LoaderMessageTypeStartByName: + message.status_value->value = loader_do_start_by_id( + loader, + message.start.id, + message.start.args, + message.start.error_message + ); + api_lock_unlock(message.api_lock); + break; + case LoaderMessageTypeIsLocked: + message.bool_value->value = loader_do_is_locked(loader); + api_lock_unlock(message.api_lock); + break; + case LoaderMessageTypeAppClosed: + loader_do_app_closed(loader); + break; + case LoaderMessageTypeLock: + message.bool_value->value = loader_do_lock(loader); + api_lock_unlock(message.api_lock); + break; + case LoaderMessageTypeUnlock: + loader_do_unlock(loader); + break; + } + } + } +} + +const AppManifest loader_app = { + .id = "loader", + .name = "Loader", + .icon = NULL, + .type = AppTypeService, + .entry_point = &loader_main, + .stack_size = AppStackSizeNormal +}; diff --git a/components/nanobake/src/apps/services/loader/loader.h b/components/nanobake/src/apps/services/loader/loader.h new file mode 100644 index 00000000..3df31ae8 --- /dev/null +++ b/components/nanobake/src/apps/services/loader/loader.h @@ -0,0 +1,84 @@ +#pragma once +#include "furi_core.h" +#include "furi_string.h" +#include "pubsub.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define RECORD_LOADER "loader" + +typedef struct Loader Loader; + +typedef enum { + LoaderStatusOk, + LoaderStatusErrorAppStarted, + LoaderStatusErrorUnknownApp, + LoaderStatusErrorInternal, +} LoaderStatus; + +typedef enum { + LoaderEventTypeApplicationStarted, + LoaderEventTypeApplicationStopped +} LoaderEventType; + +typedef struct { + LoaderEventType type; +} LoaderEvent; + +/** + * @brief Start application + * @param[in] instance loader instance + * @param[in] id application name or id + * @param[in] args application arguments + * @param[out] error_message detailed error message, can be NULL + * @return LoaderStatus + */ +LoaderStatus loader_start(Loader* instance, const char* id, const char* args, FuriString* error_message); + +/** + * @brief Start application with GUI error message + * @param[in] instance loader instance + * @param[in] name application name or id + * @param[in] args application arguments + * @return LoaderStatus + */ +//LoaderStatus loader_start_with_gui_error(Loader* loader, const char* name, const char* args); + +/** + * @brief Lock application start + * @param[in] instance loader instance + * @return true on success + */ +bool loader_lock(Loader* instance); + +/** + * @brief Unlock application start + * @param[in] instance loader instance + */ +void loader_unlock(Loader* instance); + +/** + * @brief Check if loader is locked + * @param[in] instance loader instance + * @return true if locked + */ +bool loader_is_locked(Loader* instance); + +/** + * @brief Show loader menu + * @param[in] instance loader instance + */ +void loader_show_menu(Loader* instance); + +/** + * @brief Get loader pubsub + * @param[in] instance loader instance + * @return FuriPubSub* + */ +FuriPubSub* loader_get_pubsub(Loader* instance); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/components/nanobake/src/apps/services/loader/loader_i.h b/components/nanobake/src/apps/services/loader/loader_i.h new file mode 100644 index 00000000..e51e5ff1 --- /dev/null +++ b/components/nanobake/src/apps/services/loader/loader_i.h @@ -0,0 +1,55 @@ +#pragma once +#include "api_lock.h" +#include "app_manifest.h" +#include "loader.h" +#include "message_queue.h" +#include "pubsub.h" +#include "thread.h" + +typedef struct { + char* args; + FuriThread* thread; + App* app; +} LoaderAppData; + +struct Loader { + FuriPubSub* pubsub; + FuriMessageQueue* queue; + LoaderAppData app_data; +}; + +typedef enum { + LoaderMessageTypeStartByName, + LoaderMessageTypeAppClosed, + LoaderMessageTypeLock, + LoaderMessageTypeUnlock, + LoaderMessageTypeIsLocked, +} LoaderMessageType; + +typedef struct { + const char* id; + const char* args; + FuriString* error_message; +} LoaderMessageStartById; + +typedef struct { + LoaderStatus value; +} LoaderMessageLoaderStatusResult; + +typedef struct { + bool value; +} LoaderMessageBoolResult; + +typedef struct { + FuriApiLock api_lock; + LoaderMessageType type; + + union { + LoaderMessageStartById start; + }; + + union { + LoaderMessageLoaderStatusResult* status_value; + LoaderMessageBoolResult* bool_value; + }; +} LoaderMessage; diff --git a/components/nanobake/src/apps/system/system_info/system_info.c b/components/nanobake/src/apps/system/system_info/system_info.c new file mode 100644 index 00000000..ab2f7bd9 --- /dev/null +++ b/components/nanobake/src/apps/system/system_info/system_info.c @@ -0,0 +1,24 @@ +#include "system_info.h" +#include "furi_extra_defines.h" +#include "thread.h" + +static int32_t system_info_entry_point(void* param) { + UNUSED(param); + + printf( + "Heap memory available: %d / %d\n", + heap_caps_get_free_size(MALLOC_CAP_DEFAULT), + heap_caps_get_total_size(MALLOC_CAP_DEFAULT) + ); + + return 0; +} + +AppManifest system_info_app = { + .id = "systeminfo", + .name = "System Info", + .icon = NULL, + .type = AppTypeSystem, + .entry_point = &system_info_entry_point, + .stack_size = AppStackSizeNormal +}; diff --git a/components/nanobake/src/applications/system/system_info/system_info.h b/components/nanobake/src/apps/system/system_info/system_info.h similarity index 57% rename from components/nanobake/src/applications/system/system_info/system_info.h rename to components/nanobake/src/apps/system/system_info/system_info.h index ac14272c..f86ee622 100644 --- a/components/nanobake/src/applications/system/system_info/system_info.h +++ b/components/nanobake/src/apps/system/system_info/system_info.h @@ -1,12 +1,12 @@ #pragma once -#include "app.h" +#include "app_manifest.h" #ifdef __cplusplus extern "C" { #endif -extern App system_info_app; +extern AppManifest system_info_app; #ifdef __cplusplus } diff --git a/components/nanobake/src/devices.c b/components/nanobake/src/devices.c index 20623438..613421f2 100644 --- a/components/nanobake/src/devices.c +++ b/components/nanobake/src/devices.c @@ -9,7 +9,7 @@ Devices nb_devices_create(Config _Nonnull* config) { furi_check(config->display_driver != NULL, "no display driver configured"); DisplayDriver display_driver = config->display_driver(); ESP_LOGI(TAG, "display with driver %s", display_driver.name); - DisplayDevice* display = nb_display_alloc(&display_driver); + DisplayDevice* display = nb_display_device_alloc(&display_driver); TouchDevice* touch = NULL; if (config->touch_driver != NULL) { diff --git a/components/nanobake/src/display.c b/components/nanobake/src/display.c index b7f6e469..5c20404f 100644 --- a/components/nanobake/src/display.c +++ b/components/nanobake/src/display.c @@ -1,10 +1,10 @@ #include "check.h" #include "display.h" -DisplayDevice _Nonnull* nb_display_alloc(DisplayDriver _Nonnull* driver) { +DisplayDevice _Nonnull* nb_display_device_alloc(DisplayDriver _Nonnull* driver) { DisplayDevice _Nonnull* display = malloc(sizeof(DisplayDevice)); memset(display, 0, sizeof(DisplayDevice)); - furi_check(driver->create_display(display), "failed to create display"); + furi_check(driver->create_display_device(display), "failed to create display"); furi_check(display->io_handle != NULL); furi_check(display->display_handle != NULL); furi_check(display->horizontal_resolution != 0); diff --git a/components/nanobake/src/display.h b/components/nanobake/src/display.h index 5a928562..ce7bca8a 100644 --- a/components/nanobake/src/display.h +++ b/components/nanobake/src/display.h @@ -16,20 +16,21 @@ typedef struct { bool mirror_x; bool mirror_y; bool swap_xy; + bool monochrome; } DisplayDevice; typedef bool (*CreateDisplay)(DisplayDevice* display); typedef struct { char name[32]; - CreateDisplay create_display; + CreateDisplay create_display_device; } DisplayDriver; /** * @param[in] driver * @return allocated display object */ -DisplayDevice _Nonnull* nb_display_alloc(DisplayDriver _Nonnull* driver); +DisplayDevice _Nonnull* nb_display_device_alloc(DisplayDriver _Nonnull* driver); #ifdef __cplusplus } diff --git a/components/nanobake/src/graphics.c b/components/nanobake/src/graphics.c index ca3d6619..fb2a685d 100644 --- a/components/nanobake/src/graphics.c +++ b/components/nanobake/src/graphics.c @@ -25,7 +25,7 @@ Lvgl nb_graphics_init(Devices _Nonnull* hardware) { .double_buffer = 0, .hres = display->horizontal_resolution, .vres = display->vertical_resolution, - .monochrome = false, + .monochrome = display->monochrome, .rotation = { .swap_xy = display->swap_xy, .mirror_x = display->mirror_x, @@ -37,6 +37,8 @@ Lvgl nb_graphics_init(Devices _Nonnull* hardware) { }; lv_disp_t _Nonnull* disp = lvgl_port_add_disp(&disp_cfg); + furi_check(disp != NULL, "failed to add display"); + lv_indev_t _Nullable* touch_indev = NULL; // Add touch diff --git a/components/nanobake/src/nanobake.c b/components/nanobake/src/nanobake.c index a89ce305..d5f6dd59 100644 --- a/components/nanobake/src/nanobake.c +++ b/components/nanobake/src/nanobake.c @@ -1,86 +1,61 @@ #include "nanobake.h" #include "app_i.h" -#include "applications/applications_i.h" +#include "app_manifest_registry.h" #include "devices_i.h" -#include "esp_log.h" +#include "furi.h" #include "graphics_i.h" -#include "m-list.h" -// Furi -#include "kernel.h" -#include "record.h" -#include "thread.h" - -M_LIST_DEF(thread_ids, FuriThreadId); #define TAG "nanobake" -thread_ids_t prv_thread_ids; +// System services +extern const AppManifest desktop_app; +extern const AppManifest gui_app; +extern const AppManifest loader_app; -static void prv_furi_init() { - // TODO: can we remove the suspend-resume logic? - if (xTaskGetSchedulerState() == taskSCHEDULER_RUNNING) { - vTaskSuspendAll(); - } - - furi_record_init(); - - xTaskResumeAll(); -} - -FuriThreadId nanobake_get_app_thread_id(size_t index) { - return *thread_ids_get(prv_thread_ids, index); -} - -size_t nanobake_get_app_thread_count() { - return thread_ids_size(prv_thread_ids); -} - -static void prv_start_app(const App _Nonnull* app) { - ESP_LOGI(TAG, "Starting %s app \"%s\"", nb_app_type_to_string(app->type), app->name); +// System apps +extern const AppManifest system_info_app; +void start_service(const AppManifest* _Nonnull manifest) { + // TODO: keep track of running services + FURI_LOG_I(TAG, "Starting service %s", manifest->name); FuriThread* thread = furi_thread_alloc_ex( - app->name, - app->stack_size, - app->entry_point, + manifest->name, + manifest->stack_size, + manifest->entry_point, NULL ); - - if (app->type == SERVICE) { - furi_thread_mark_as_service(thread); - } - - furi_thread_set_appid(thread, app->id); - furi_thread_set_priority(thread, app->priority); + furi_thread_mark_as_service(thread); + furi_thread_set_appid(thread, manifest->id); furi_thread_start(thread); - - FuriThreadId thread_id = furi_thread_get_id(thread); - thread_ids_push_back(prv_thread_ids, thread_id); } -__attribute__((unused)) extern void nanobake_start(Config _Nonnull* config) { - prv_furi_init(); +static void register_apps(Config* _Nonnull config) { + FURI_LOG_I(TAG, "Registering core apps"); + app_manifest_registry_add(&desktop_app); + app_manifest_registry_add(&gui_app); + app_manifest_registry_add(&loader_app); + app_manifest_registry_add(&system_info_app); + + FURI_LOG_I(TAG, "Registering user apps"); + for (size_t i = 0; i < config->apps_count; i++) { + app_manifest_registry_add(config->apps[i]); + } +} + +static void start_services() { + FURI_LOG_I(TAG, "Starting services"); + app_manifest_registry_for_each_of_type(AppTypeService, start_service); + FURI_LOG_I(TAG, "Startup complete"); +} + +__attribute__((unused)) extern void nanobake_start(Config* _Nonnull config) { + furi_init(); Devices hardware = nb_devices_create(config); /*NbLvgl lvgl =*/nb_graphics_init(&hardware); - thread_ids_init(prv_thread_ids); + register_apps(config); - ESP_LOGI(TAG, "Starting apps"); - - // Services - for (size_t i = 0; i < NANOBAKE_SERVICES_COUNT; i++) { - prv_start_app(NANOBAKE_SERVICES[i]); - } - - // System - for (size_t i = 0; i < NANOBAKE_SYSTEM_APPS_COUNT; i++) { - prv_start_app(NANOBAKE_SYSTEM_APPS[i]); - } - - // User - for (size_t i = 0; i < config->apps_count; i++) { - prv_start_app(config->apps[i]); - } - - ESP_LOGI(TAG, "Startup complete"); + start_services(); + // TODO: option to await starting services? } diff --git a/components/nanobake/src/nanobake.h b/components/nanobake/src/nanobake.h index c5c41d81..508613d4 100644 --- a/components/nanobake/src/nanobake.h +++ b/components/nanobake/src/nanobake.h @@ -1,9 +1,8 @@ #pragma once -#include "app.h" +#include "app_manifest.h" #include "devices.h" -#include "core_defines.h" -#include "base.h" +#include "furi_extra_defines.h" #ifdef __cplusplus extern "C" { @@ -21,7 +20,7 @@ typedef struct { const CreateTouchDriver _Nullable touch_driver; // List of user applications const size_t apps_count; - const App* const apps[]; + const AppManifest* const apps[]; } Config; __attribute__((unused)) extern void nanobake_start(Config _Nonnull* config); diff --git a/components/nanobake/src/touch.c b/components/nanobake/src/touch.c index b98f1998..b365c801 100644 --- a/components/nanobake/src/touch.c +++ b/components/nanobake/src/touch.c @@ -3,7 +3,7 @@ TouchDevice _Nonnull* nb_touch_alloc(TouchDriver _Nonnull* driver) { TouchDevice _Nonnull* touch = malloc(sizeof(TouchDevice)); - bool success = driver->create_touch( + bool success = driver->create_touch_device( &(touch->io_handle), &(touch->touch_handle) ); diff --git a/components/nanobake/src/touch.h b/components/nanobake/src/touch.h index 4ab70a2b..bb927c0c 100644 --- a/components/nanobake/src/touch.h +++ b/components/nanobake/src/touch.h @@ -11,7 +11,7 @@ typedef bool (*CreateTouch)(esp_lcd_panel_io_handle_t* io_handle, esp_lcd_touch_ typedef struct { char name[32]; - CreateTouch create_touch; + CreateTouch create_touch_device; } TouchDriver; typedef struct { diff --git a/main/src/hello_world/hello_world.c b/main/src/hello_world/hello_world.c index ca43addc..4cd366a6 100644 --- a/main/src/hello_world/hello_world.c +++ b/main/src/hello_world/hello_world.c @@ -1,22 +1,16 @@ #include "hello_world.h" -#include "applications/services/gui/gui.h" -#include "esp_log.h" +#include "furi.h" +#include "apps/services/gui/gui.h" #include "esp_lvgl_port.h" -#include "graphics.h" -#include "record.h" -static const char* TAG = "app_helloworld"; +static const char* TAG = "app_hello_world"; ViewPort* view_port = NULL; +FuriSemaphore* quit_lock = NULL; static void on_button_click(lv_event_t _Nonnull* event) { ESP_LOGI(TAG, "button clicked"); - - FURI_RECORD_TRANSACTION(RECORD_GUI, gui, { - gui_remove_view_port(gui, view_port); - view_port_free(view_port); - view_port = NULL; - }); + furi_semaphore_give(quit_lock); } // Main entry point for LVGL widget creation @@ -48,18 +42,32 @@ static int32_t app_main(void* param) { view_port_draw_callback_set(view_port, &app_lvgl, view_port); // The transaction automatically calls furi_record_open() and furi_record_close() - FURI_RECORD_TRANSACTION(RECORD_GUI, gui, { + FURI_RECORD_TRANSACTION(RECORD_GUI, Gui*, gui, { gui_add_view_port(gui, view_port, GuiLayerFullscreen); }) + // Wait for the button click to release the mutex (lock) + quit_lock = furi_semaphore_alloc(1, 0); + while (!furi_semaphore_take(quit_lock, UINT32_MAX)) { + // Do nothing + } + furi_semaphore_free(quit_lock); + quit_lock = NULL; + + FURI_RECORD_TRANSACTION(RECORD_GUI, Gui*, gui, { + gui_remove_view_port(gui, view_port); + view_port_free(view_port); + view_port = NULL; + }); + return 0; } -const App hello_world_app = { +const AppManifest hello_world_app = { .id = "helloworld", .name = "Hello World", - .type = USER, + .icon = NULL, + .type = AppTypeUser, .entry_point = &app_main, - .stack_size = NB_TASK_STACK_SIZE_DEFAULT, - .priority = NB_TASK_PRIORITY_DEFAULT + .stack_size = AppStackSizeNormal, }; diff --git a/main/src/hello_world/hello_world.h b/main/src/hello_world/hello_world.h index 53a47992..f2563e22 100644 --- a/main/src/hello_world/hello_world.h +++ b/main/src/hello_world/hello_world.h @@ -1,5 +1,5 @@ #pragma once -#include "app.h" +#include "app_manifest.h" -extern const App hello_world_app; +extern const AppManifest hello_world_app; diff --git a/main/src/main.c b/main/src/main.c index db3d9d9c..6a5bdaf2 100644 --- a/main/src/main.c +++ b/main/src/main.c @@ -1,4 +1,6 @@ #include "nanobake.h" +#include "record.h" +#include "apps/services/loader/loader.h" // Hardware #include "board_2432s024.h" @@ -17,4 +19,11 @@ __attribute__((unused)) void app_main(void) { }; nanobake_start(&config); + + FURI_RECORD_TRANSACTION(RECORD_LOADER, Loader*, loader, { + FuriString* error_message = furi_string_alloc(); + if (loader_start(loader, hello_world_app.id, NULL, error_message) != LoaderStatusOk) { + FURI_LOG_E(hello_world_app.id, "%s\r\n", furi_string_get_cstr(error_message)); + } + }); }