diff --git a/applications/app-loader/app-loader.c b/applications/app-loader/app-loader.c index df49b3e0..9c8349d5 100644 --- a/applications/app-loader/app-loader.c +++ b/applications/app-loader/app-loader.c @@ -8,20 +8,19 @@ #include typedef struct { - osThreadAttr_t app_thread_attr; - osThreadId_t app_thread_id; + FuriThread* thread; ViewPort* view_port; - const FuriApplication* current_app; + const FlipperApplication* current_app; } AppLoaderState; typedef struct { AppLoaderState* state; - const FuriApplication* app; + const FlipperApplication* app; } AppLoaderContext; // TODO add mutex for contex -static void render_callback(Canvas* canvas, void* _ctx) { +static void app_loader_render_callback(Canvas* canvas, void* _ctx) { AppLoaderState* ctx = (AppLoaderState*)_ctx; canvas_clear(canvas); @@ -33,77 +32,71 @@ static void render_callback(Canvas* canvas, void* _ctx) { canvas_draw_str(canvas, 2, 44, "press back to exit"); } -static void input_callback(InputEvent* input_event, void* _ctx) { +static void app_loader_input_callback(InputEvent* input_event, void* _ctx) { AppLoaderState* ctx = (AppLoaderState*)_ctx; if(input_event->type == InputTypeShort && input_event->key == InputKeyBack) { - osThreadTerminate(ctx->app_thread_id); - view_port_enabled_set(ctx->view_port, false); - api_hal_timebase_insomnia_exit(); + furi_thread_terminate(ctx->thread); } } -static void handle_menu(void* _ctx) { +static void app_loader_menu_callback(void* _ctx) { AppLoaderContext* ctx = (AppLoaderContext*)_ctx; if(ctx->app->app == NULL) return; view_port_enabled_set(ctx->state->view_port, true); - // TODO how to call this? - // furiac_wait_libs(&FLIPPER_STARTUP[i].libs); - api_hal_timebase_insomnia_enter(); + api_hal_power_insomnia_enter(); ctx->state->current_app = ctx->app; - ctx->state->app_thread_attr.name = ctx->app->name; - ctx->state->app_thread_attr.attr_bits = osThreadDetached; - ctx->state->app_thread_attr.cb_mem = NULL; - ctx->state->app_thread_attr.cb_size = 0; - ctx->state->app_thread_attr.stack_mem = NULL; - ctx->state->app_thread_attr.stack_size = ctx->app->stack_size; - ctx->state->app_thread_attr.priority = osPriorityNormal; - ctx->state->app_thread_attr.tz_module = 0; - ctx->state->app_thread_attr.reserved = 0; - ctx->state->app_thread_id = osThreadNew(ctx->app->app, NULL, &ctx->state->app_thread_attr); + + furi_thread_set_name(ctx->state->thread, ctx->app->name); + furi_thread_set_stack_size(ctx->state->thread, ctx->app->stack_size); + furi_thread_set_callback(ctx->state->thread, ctx->app->app); + furi_thread_start(ctx->state->thread); } -static void handle_cli(string_t args, void* _ctx) { +static void app_loader_cli_callback(string_t args, void* _ctx) { AppLoaderContext* ctx = (AppLoaderContext*)_ctx; if(ctx->app->app == NULL) return; printf("Starting furi application\r\n"); - ctx->state->current_app = ctx->app; - ctx->state->app_thread_attr.name = ctx->app->name; - ctx->state->app_thread_attr.attr_bits = osThreadDetached; - ctx->state->app_thread_attr.cb_mem = NULL; - ctx->state->app_thread_attr.cb_size = 0; - ctx->state->app_thread_attr.stack_mem = NULL; - ctx->state->app_thread_attr.stack_size = ctx->app->stack_size; - ctx->state->app_thread_attr.priority = osPriorityNormal; - ctx->state->app_thread_attr.tz_module = 0; - ctx->state->app_thread_attr.reserved = 0; - ctx->state->app_thread_id = osThreadNew(ctx->app->app, NULL, &ctx->state->app_thread_attr); + api_hal_power_insomnia_enter(); + + furi_thread_set_name(ctx->state->thread, ctx->app->name); + furi_thread_set_stack_size(ctx->state->thread, ctx->app->stack_size); + furi_thread_set_callback(ctx->state->thread, ctx->app->app); + furi_thread_start(ctx->state->thread); printf("Press any key to kill application"); char c; cli_read(&c, 1); - osThreadTerminate(ctx->state->app_thread_id); + furi_thread_terminate(ctx->state->thread); } -void app_loader(void* p) { - osThreadId_t self_id = osThreadGetId(); - furi_check(self_id); +void app_loader_thread_state_callback(FuriThreadState state, void* context) { + furi_assert(context); + AppLoaderState* app_loader_state = context; + if(state == FuriThreadStateStopped) { + view_port_enabled_set(app_loader_state->view_port, false); + api_hal_power_insomnia_exit(); + } +} +int32_t app_loader(void* p) { AppLoaderState state; - state.app_thread_id = NULL; + state.thread = furi_thread_alloc(); + furi_thread_set_state_context(state.thread, &state); + furi_thread_set_state_callback(state.thread, app_loader_thread_state_callback); state.view_port = view_port_alloc(); view_port_enabled_set(state.view_port, false); - view_port_draw_callback_set(state.view_port, render_callback, &state); - view_port_input_callback_set(state.view_port, input_callback, &state); + view_port_draw_callback_set(state.view_port, app_loader_render_callback, &state); + view_port_input_callback_set(state.view_port, app_loader_input_callback, &state); ValueMutex* menu_mutex = furi_record_open("menu"); Cli* cli = furi_record_open("cli"); @@ -114,7 +107,7 @@ void app_loader(void* p) { // Main menu with_value_mutex( menu_mutex, (Menu * menu) { - for(size_t i = 0; i < FLIPPER_APPS_size(); i++) { + for(size_t i = 0; i < FLIPPER_APPS_COUNT; i++) { AppLoaderContext* ctx = furi_alloc(sizeof(AppLoaderContext)); ctx->state = &state; ctx->app = &FLIPPER_APPS[i]; @@ -124,14 +117,14 @@ void app_loader(void* p) { menu_item_alloc_function( FLIPPER_APPS[i].name, assets_icons_get(FLIPPER_APPS[i].icon), - handle_menu, + app_loader_menu_callback, ctx)); // Add cli command string_t cli_name; string_init_set_str(cli_name, "app_"); string_cat_str(cli_name, FLIPPER_APPS[i].name); - cli_add_command(cli, string_get_cstr(cli_name), handle_cli, ctx); + cli_add_command(cli, string_get_cstr(cli_name), app_loader_cli_callback, ctx); string_clear(cli_name); } }); @@ -160,7 +153,7 @@ void app_loader(void* p) { MenuItem* menu_plugins = menu_item_alloc_menu("Plugins", assets_icons_get(A_Plugins_14)); - for(size_t i = 0; i < FLIPPER_PLUGINS_size(); i++) { + for(size_t i = 0; i < FLIPPER_PLUGINS_COUNT; i++) { AppLoaderContext* ctx = furi_alloc(sizeof(AppLoaderContext)); ctx->state = &state; ctx->app = &FLIPPER_PLUGINS[i]; @@ -170,14 +163,14 @@ void app_loader(void* p) { menu_item_alloc_function( FLIPPER_PLUGINS[i].name, assets_icons_get(FLIPPER_PLUGINS[i].icon), - handle_menu, + app_loader_menu_callback, ctx)); // Add cli command string_t cli_name; string_init_set_str(cli_name, "app_"); string_cat_str(cli_name, FLIPPER_PLUGINS[i].name); - cli_add_command(cli, string_get_cstr(cli_name), handle_cli, ctx); + cli_add_command(cli, string_get_cstr(cli_name), app_loader_cli_callback, ctx); string_clear(cli_name); } @@ -186,5 +179,9 @@ void app_loader(void* p) { printf("[app loader] start\r\n"); - osThreadSuspend(self_id); + while(1) { + osThreadSuspend(osThreadGetId()); + } + + return 0; } diff --git a/applications/applications.c b/applications/applications.c index 3f9ea08c..33977a67 100644 --- a/applications/applications.c +++ b/applications/applications.c @@ -1,41 +1,40 @@ #include "applications.h" #ifdef APP_TEST -void flipper_test_app(void* p); +int32_t flipper_test_app(void* p); #endif -void application_blink(void* p); -void application_uart_write(void* p); -void application_input_dump(void* p); -void u8g2_example(void* p); -void input_task(void* p); -void menu_task(void* p); -void coreglitch_demo_0(void* p); -void u8g2_qrcode(void* p); -void fatfs_list(void* p); -void gui_task(void* p); -void backlight_control(void* p); -void irda(void* p); -void app_loader(void* p); -void cc1101_workaround(void* p); -void lf_rfid_workaround(void* p); -void nfc_task(void* p); -void dolphin_task(void* p); -void power_task(void* p); -void bt_task(void* p); -void sd_card_test(void* p); -void application_vibro(void* p); -void app_gpio_test(void* p); -void app_ibutton(void* p); -void cli_task(void* p); -void music_player(void* p); -void sdnfc(void* p); -void floopper_bloopper(void* p); -void sd_filesystem(void* p); +int32_t application_blink(void* p); +int32_t application_uart_write(void* p); +int32_t application_input_dump(void* p); +int32_t u8g2_example(void* p); +int32_t input_task(void* p); +int32_t menu_task(void* p); +int32_t coreglitch_demo_0(void* p); +int32_t u8g2_qrcode(void* p); +int32_t gui_task(void* p); +int32_t backlight_control(void* p); +int32_t irda(void* p); +int32_t app_loader(void* p); +int32_t cc1101_workaround(void* p); +int32_t lf_rfid_workaround(void* p); +int32_t nfc_task(void* p); +int32_t dolphin_task(void* p); +int32_t power_task(void* p); +int32_t bt_task(void* p); +int32_t sd_card_test(void* p); +int32_t application_vibro(void* p); +int32_t app_gpio_test(void* p); +int32_t app_ibutton(void* p); +int32_t cli_task(void* p); +int32_t music_player(void* p); +int32_t sdnfc(void* p); +int32_t floopper_bloopper(void* p); +int32_t sd_filesystem(void* p); -void gui_test(void* p); +int32_t gui_test(void* p); -const FuriApplication FLIPPER_SERVICES[] = { +const FlipperApplication FLIPPER_SERVICES[] = { #ifdef APP_CLI {.app = cli_task, .name = "cli_task", .stack_size = 1024, .icon = A_Plugins_14}, #endif @@ -111,10 +110,6 @@ const FuriApplication FLIPPER_SERVICES[] = { {.app = u8g2_qrcode, .name = "u8g2_qrcode", .stack_size = 1024, .icon = A_Plugins_14}, #endif -#ifdef APP_EXAMPLE_FATFS - {.app = fatfs_list, .name = "fatfs_list", .stack_size = 1024, .icon = A_Plugins_14}, -#endif - #ifdef APP_EXAMPLE_DISPLAY {.app = u8g2_example, .name = "u8g2_example", .stack_size = 1024, .icon = A_Plugins_14}, #endif @@ -155,12 +150,10 @@ const FuriApplication FLIPPER_SERVICES[] = { #endif }; -size_t FLIPPER_SERVICES_size() { - return sizeof(FLIPPER_SERVICES) / sizeof(FuriApplication); -} +const size_t FLIPPER_SERVICES_COUNT = sizeof(FLIPPER_SERVICES) / sizeof(FlipperApplication); // Main menu APP -const FuriApplication FLIPPER_APPS[] = { +const FlipperApplication FLIPPER_APPS[] = { #ifdef BUILD_CC1101 {.app = cc1101_workaround, .name = "Sub-1 GHz", .stack_size = 1024, .icon = A_Sub1ghz_14}, #endif @@ -182,12 +175,10 @@ const FuriApplication FLIPPER_APPS[] = { #endif }; -size_t FLIPPER_APPS_size() { - return sizeof(FLIPPER_APPS) / sizeof(FuriApplication); -} +const size_t FLIPPER_APPS_COUNT = sizeof(FLIPPER_APPS) / sizeof(FlipperApplication); // Plugin menu -const FuriApplication FLIPPER_PLUGINS[] = { +const FlipperApplication FLIPPER_PLUGINS[] = { #ifdef BUILD_EXAMPLE_BLINK {.app = application_blink, .name = "blink", .stack_size = 1024, .icon = A_Plugins_14}, #endif @@ -231,6 +222,4 @@ const FuriApplication FLIPPER_PLUGINS[] = { #endif }; -size_t FLIPPER_PLUGINS_size() { - return sizeof(FLIPPER_PLUGINS) / sizeof(FuriApplication); -} +const size_t FLIPPER_PLUGINS_COUNT = sizeof(FLIPPER_PLUGINS) / sizeof(FlipperApplication); diff --git a/applications/applications.h b/applications/applications.h index bf60b7f3..e941a8c3 100644 --- a/applications/applications.h +++ b/applications/applications.h @@ -3,20 +3,27 @@ #include #include -typedef void (*FlipperApplication)(void*); - typedef struct { - const FlipperApplication app; + const FuriThreadCallback app; const char* name; const size_t stack_size; const IconName icon; -} FuriApplication; +} FlipperApplication; -extern const FuriApplication FLIPPER_SERVICES[]; -size_t FLIPPER_SERVICES_size(); +/* Services list + * Spawned on startup + */ +extern const FlipperApplication FLIPPER_SERVICES[]; +extern const size_t FLIPPER_SERVICES_COUNT; -extern const FuriApplication FLIPPER_APPS[]; -size_t FLIPPER_APPS_size(); +/* Apps list + * Spawned by app-loader + */ +extern const FlipperApplication FLIPPER_APPS[]; +extern const size_t FLIPPER_APPS_COUNT; -extern const FuriApplication FLIPPER_PLUGINS[]; -size_t FLIPPER_PLUGINS_size(); +/* Plugins list + * Spawned by app-loader + */ +extern const FlipperApplication FLIPPER_PLUGINS[]; +extern const size_t FLIPPER_PLUGINS_COUNT; diff --git a/applications/applications.mk b/applications/applications.mk index 9214f94a..73a66f19 100644 --- a/applications/applications.mk +++ b/applications/applications.mk @@ -78,15 +78,12 @@ endif APP_TEST ?= 0 ifeq ($(APP_TEST), 1) CFLAGS += -DAPP_TEST -C_SOURCES += $(APP_DIR)/tests/furiac_test.c C_SOURCES += $(APP_DIR)/tests/furi_record_test.c C_SOURCES += $(APP_DIR)/tests/test_index.c C_SOURCES += $(APP_DIR)/tests/minunit_test.c C_SOURCES += $(APP_DIR)/tests/furi_valuemutex_test.c C_SOURCES += $(APP_DIR)/tests/furi_pubsub_test.c C_SOURCES += $(APP_DIR)/tests/furi_memmgr_test.c -C_SOURCES += $(APP_DIR)/tests/furi_value_expanders_test.c -C_SOURCES += $(APP_DIR)/tests/furi_event_test.c endif APP_EXAMPLE_BLINK ?= 0 @@ -147,18 +144,6 @@ C_SOURCES += $(APP_DIR)/examples/u8g2_qrcode.c C_SOURCES += $(LIB_DIR)/qrcode/qrcode.c endif -APP_EXAMPLE_FATFS ?= 0 -ifeq ($(APP_EXAMPLE_FATFS), 1) -CFLAGS += -DAPP_EXAMPLE_FATFS -BUILD_EXAMPLE_FATFS = 1 -endif -BUILD_EXAMPLE_FATFS ?= 0 -ifeq ($(BUILD_EXAMPLE_FATFS), 1) -CFLAGS += -DBUILD_EXAMPLE_FATFS -C_SOURCES += $(APP_DIR)/examples/fatfs_list.c -APP_INPUT = 1 -endif - APP_CC1101 ?= 0 ifeq ($(APP_CC1101), 1) CFLAGS += -DAPP_CC1101 diff --git a/applications/backlight-control/backlight-control.c b/applications/backlight-control/backlight-control.c index ed412f91..d79160fb 100644 --- a/applications/backlight-control/backlight-control.c +++ b/applications/backlight-control/backlight-control.c @@ -7,7 +7,7 @@ static void event_cb(const void* value, void* ctx) { osThreadFlagsSet((osThreadId_t)ctx, BACKLIGHT_FLAG_ACTIVITY); } -void backlight_control(void* p) { +int32_t backlight_control(void* p) { // TODO open record const GpioPin* backlight_record = &backlight_gpio; @@ -28,4 +28,6 @@ void backlight_control(void* p) { gpio_write(backlight_record, false); } } + + return 0; } \ No newline at end of file diff --git a/applications/bt/bt.c b/applications/bt/bt.c index eb8c6d4c..de5b0b84 100644 --- a/applications/bt/bt.c +++ b/applications/bt/bt.c @@ -37,7 +37,7 @@ void bt_cli_info(string_t args, void* context) { string_clear(buffer); } -void bt_task() { +int32_t bt_task() { Bt* bt = bt_alloc(); furi_record_create("bt", bt); @@ -48,4 +48,6 @@ void bt_task() { view_port_enabled_set(bt->statusbar_view_port, api_hal_bt_is_alive()); osDelay(1024); } + + return 0; } diff --git a/applications/cc1101-workaround/cc1101-workaround.cpp b/applications/cc1101-workaround/cc1101-workaround.cpp index 2dfe86ff..dbb4f1c8 100644 --- a/applications/cc1101-workaround/cc1101-workaround.cpp +++ b/applications/cc1101-workaround/cc1101-workaround.cpp @@ -345,7 +345,7 @@ static void input_callback(InputEvent* input_event, void* ctx) { osMessageQueuePut(event_queue, &event, 0, 0); } -extern "C" void cc1101_workaround(void* p) { +extern "C" int32_t cc1101_workaround(void* p) { osMessageQueueId_t event_queue = osMessageQueueNew(8, sizeof(AppEvent), NULL); furi_check(event_queue); @@ -363,7 +363,7 @@ extern "C" void cc1101_workaround(void* p) { ValueMutex state_mutex; if(!init_mutex(&state_mutex, &_state, sizeof(State))) { printf("[cc1101] cannot create mutex\r\n"); - furiac_exit(NULL); + return 255; } ViewPort* view_port = view_port_alloc(); @@ -375,7 +375,7 @@ extern "C" void cc1101_workaround(void* p) { Gui* gui = (Gui*)furi_record_open("gui"); if(gui == NULL) { printf("[cc1101] gui is not available\r\n"); - furiac_exit(NULL); + return 255; } gui_add_view_port(gui, view_port, GuiLayerFullscreen); @@ -397,7 +397,7 @@ extern "C" void cc1101_workaround(void* p) { printf("[cc1101] init done: %d\r\n", address); } else { printf("[cc1101] init fail\r\n"); - furiac_exit(NULL); + return 255; } cc1101.SpiStrobe(CC1101_SIDLE); @@ -439,7 +439,7 @@ extern "C" void cc1101_workaround(void* p) { // TODO remove all view_ports create by app view_port_enabled_set(view_port, false); - furiac_exit(NULL); + return 255; } if(event.value.input.type == InputTypeShort && @@ -597,4 +597,6 @@ extern "C" void cc1101_workaround(void* p) { release_mutex(&state_mutex, state); view_port_update(view_port); } + + return 0; } \ No newline at end of file diff --git a/applications/cli/cli.c b/applications/cli/cli.c index 6220c73d..0f384377 100644 --- a/applications/cli/cli.c +++ b/applications/cli/cli.c @@ -172,7 +172,7 @@ void cli_add_command(Cli* cli, const char* name, CliCallback callback, void* con string_clear(name_str); } -void cli_task(void* p) { +int32_t cli_task(void* p) { Cli* cli = cli_alloc(); // Init basic cli commands @@ -184,4 +184,6 @@ void cli_task(void* p) { while(1) { cli_process_input(cli); } + + return 0; } diff --git a/applications/coreglitch_demo_0/coreglitch_demo_0.c b/applications/coreglitch_demo_0/coreglitch_demo_0.c index caf33405..ac4f24c3 100644 --- a/applications/coreglitch_demo_0/coreglitch_demo_0.c +++ b/applications/coreglitch_demo_0/coreglitch_demo_0.c @@ -3,7 +3,7 @@ extern TIM_HandleTypeDef SPEAKER_TIM; -void coreglitch_demo_0(void* p) { +int32_t coreglitch_demo_0(void* p) { printf("coreglitch demo!\r\n"); float notes[] = { @@ -47,4 +47,6 @@ void coreglitch_demo_0(void* p) { delay(100); } } + + return 0; } diff --git a/applications/dolphin/dolphin.c b/applications/dolphin/dolphin.c index 9a89f4ed..e3237f04 100644 --- a/applications/dolphin/dolphin.c +++ b/applications/dolphin/dolphin.c @@ -129,7 +129,7 @@ void dolphin_deed(Dolphin* dolphin, DolphinDeed deed) { furi_check(osMessageQueuePut(dolphin->event_queue, &event, 0, osWaitForever) == osOK); } -void dolphin_task() { +int32_t dolphin_task() { Dolphin* dolphin = dolphin_alloc(); Gui* gui = furi_record_open("gui"); @@ -163,4 +163,6 @@ void dolphin_task() { dolphin_state_save(dolphin->state); } } + + return 0; } diff --git a/applications/examples/blink.c b/applications/examples/blink.c index 1362f7d3..c07fb9be 100644 --- a/applications/examples/blink.c +++ b/applications/examples/blink.c @@ -12,7 +12,7 @@ void rgb_set( gpio_write(led_b, !b); } -void application_blink(void* p) { +int32_t application_blink(void* p) { // TODO open record const GpioPin* led_r_record = &led_gpio[0]; const GpioPin* led_g_record = &led_gpio[1]; @@ -41,4 +41,6 @@ void application_blink(void* p) { rgb_set(0, 0, 0, led_r_record, led_g_record, led_b_record); delay(500); } + + return 0; } \ No newline at end of file diff --git a/applications/examples/input_dump.c b/applications/examples/input_dump.c index 2284e90e..e99fad6b 100644 --- a/applications/examples/input_dump.c +++ b/applications/examples/input_dump.c @@ -13,7 +13,7 @@ static void event_cb(const void* value, void* ctx) { printf("event: %02x %s\r\n", event->key, event->type ? "pressed" : "released"); } -void application_input_dump(void* p) { +int32_t application_input_dump(void* p) { // open record PubSub* event_record = furi_record_open("input_events"); subscribe_pubsub(event_record, event_cb, NULL); @@ -23,4 +23,6 @@ void application_input_dump(void* p) { for(;;) { delay(100); } + + return 0; } diff --git a/applications/examples/u8g2_example.c b/applications/examples/u8g2_example.c index 8f745a87..e5370309 100644 --- a/applications/examples/u8g2_example.c +++ b/applications/examples/u8g2_example.c @@ -1,7 +1,7 @@ #include "u8g2/u8g2.h" #include -void u8g2_example(void* p) { +int32_t u8g2_example(void* p) { // open record u8g2_t* fb = furi_record_open("u8g2_fb"); u8g2_SetFont(fb, u8g2_font_6x10_mf); @@ -10,5 +10,5 @@ void u8g2_example(void* p) { u8g2_DrawStr(fb, 2, 12, "hello world!"); furi_record_close("u8g2_fb"); - furiac_exit(NULL); + return 0; } \ No newline at end of file diff --git a/applications/examples/u8g2_qrcode.c b/applications/examples/u8g2_qrcode.c index 7cc0b888..f71a0ca3 100644 --- a/applications/examples/u8g2_qrcode.c +++ b/applications/examples/u8g2_qrcode.c @@ -13,7 +13,7 @@ void u8g2_DrawPixelSize(u8g2_t* u8g2, uint8_t x, uint8_t y, uint8_t size) { } } -void u8g2_qrcode(void* p) { +int32_t u8g2_qrcode(void* p) { // open record FuriRecordSubscriber* fb_record = furi_open_deprecated("u8g2_fb", false, false, NULL, NULL, NULL); @@ -38,7 +38,7 @@ void u8g2_qrcode(void* p) { if(fb_record == NULL) { printf("[view_port] cannot create fb record\r\n"); - furiac_exit(NULL); + return 255; } u8g2_t* fb = furi_take(fb_record); @@ -63,12 +63,14 @@ void u8g2_qrcode(void* p) { } } } else { - furiac_exit(NULL); + return 255; } furi_commit(fb_record); delay(1); } + + return 0; } */ \ No newline at end of file diff --git a/applications/examples/uart_write.c b/applications/examples/uart_write.c index 7b6697ed..6e251edf 100644 --- a/applications/examples/uart_write.c +++ b/applications/examples/uart_write.c @@ -1,7 +1,7 @@ #include #include -void application_uart_write(void* p) { +int32_t application_uart_write(void* p) { // Red led for showing progress GpioPin led = {.pin = GPIO_PIN_8, .port = GPIOA}; // TODO open record @@ -29,4 +29,6 @@ void application_uart_write(void* p) { // delay with overall perion of 1s delay(950); } + + return 0; } \ No newline at end of file diff --git a/applications/examples/vibro.c b/applications/examples/vibro.c index fa4fdc2e..ab6c5727 100644 --- a/applications/examples/vibro.c +++ b/applications/examples/vibro.c @@ -21,7 +21,7 @@ static void button_handler(const void* value, void* _ctx) { } } -void application_vibro(void* p) { +int32_t application_vibro(void* p) { Ctx ctx = {.led = (GpioPin*)&led_gpio[1], .vibro = (GpioPin*)&vibro_gpio}; gpio_init(ctx.led, GpioModeOutputOpenDrain); @@ -37,4 +37,6 @@ void application_vibro(void* p) { while(1) { osDelay(osWaitForever); } + + return 0; } \ No newline at end of file diff --git a/applications/floopper-bloopper b/applications/floopper-bloopper index 598edd54..a68a7eb2 160000 --- a/applications/floopper-bloopper +++ b/applications/floopper-bloopper @@ -1 +1 @@ -Subproject commit 598edd54197d58b35d8cc2513549ddda3938fa38 +Subproject commit a68a7eb200712b24c16a62713a5d137152805cd1 diff --git a/applications/gpio-tester/gpio-tester.c b/applications/gpio-tester/gpio-tester.c index 76575868..982076e4 100644 --- a/applications/gpio-tester/gpio-tester.c +++ b/applications/gpio-tester/gpio-tester.c @@ -57,7 +57,7 @@ static void input_callback(InputEvent* input_event, void* ctx) { osMessageQueuePut(event_queue, &event, 0, 0); } -void app_gpio_test(void* p) { +int32_t app_gpio_test(void* p) { osMessageQueueId_t event_queue = osMessageQueueNew(8, sizeof(AppEvent), NULL); furi_check(event_queue); @@ -67,7 +67,7 @@ void app_gpio_test(void* p) { ValueMutex state_mutex; if(!init_mutex(&state_mutex, &_state, sizeof(State))) { printf("[gpio-tester] cannot create mutex\r\n"); - furiac_exit(NULL); + return 255; } ViewPort* view_port = view_port_alloc(); @@ -98,7 +98,7 @@ void app_gpio_test(void* p) { printf("[gpio-tester] bye!\r\n"); // TODO remove all view_ports create by app view_port_enabled_set(view_port, false); - furiac_exit(NULL); + return 0; } if(event.value.input.type == InputTypeShort && @@ -130,4 +130,6 @@ void app_gpio_test(void* p) { release_mutex(&state_mutex, state); view_port_update(view_port); } + + return 0; } diff --git a/applications/gui-test/gui-test.c b/applications/gui-test/gui-test.c index d4b713b3..f80b913e 100644 --- a/applications/gui-test/gui-test.c +++ b/applications/gui-test/gui-test.c @@ -92,7 +92,7 @@ void text_input_callback(void* context, char* text) { next_view(context); } -void gui_test(void* param) { +int32_t gui_test(void* param) { (void)param; GuiTester* gui_tester = gui_test_alloc(); @@ -154,4 +154,6 @@ void gui_test(void* param) { while(1) { osDelay(1000); } + + return 0; } \ No newline at end of file diff --git a/applications/gui/gui.c b/applications/gui/gui.c index c80ee1a1..2fffd182 100644 --- a/applications/gui/gui.c +++ b/applications/gui/gui.c @@ -280,7 +280,7 @@ Gui* gui_alloc() { return gui; } -void gui_task(void* p) { +int32_t gui_task(void* p) { Gui* gui = gui_alloc(); furi_record_create("gui", gui); @@ -302,4 +302,6 @@ void gui_task(void* p) { gui_redraw(gui); } } + + return 0; } diff --git a/applications/ibutton/ibutton.cpp b/applications/ibutton/ibutton.cpp index 8557d2d6..ca82444b 100644 --- a/applications/ibutton/ibutton.cpp +++ b/applications/ibutton/ibutton.cpp @@ -23,7 +23,7 @@ void AppiButton::run() { gpio_init(red_led_record, GpioModeOutputOpenDrain); gpio_init(green_led_record, GpioModeOutputOpenDrain); - api_hal_timebase_insomnia_enter(); + api_hal_power_insomnia_enter(); app_ready(); AppiButtonEvent event; @@ -35,9 +35,9 @@ void AppiButton::run() { event.value.input.key == InputKeyBack) { view_port_enabled_set(view_port, false); gui_remove_view_port(gui, view_port); - api_hal_timebase_insomnia_exit(); + api_hal_power_insomnia_exit(); - osThreadExit(); + return; } if(event.value.input.type == InputTypeShort && @@ -174,7 +174,8 @@ void AppiButton::switch_to_mode(uint8_t mode_index) { } // app enter function -extern "C" void app_ibutton(void* p) { +extern "C" int32_t app_ibutton(void* p) { AppiButton* app = new AppiButton(); app->run(); + return 0; } \ No newline at end of file diff --git a/applications/input/input.c b/applications/input/input.c index 92e8a0f4..975eb7a1 100644 --- a/applications/input/input.c +++ b/applications/input/input.c @@ -18,7 +18,7 @@ void input_isr(void* _pin, void* _ctx) { osThreadFlagsSet(input->thread, INPUT_THREAD_FLAG_ISR); } -void input_task() { +int32_t input_task() { input = furi_alloc(sizeof(Input)); input->thread = osThreadGetId(); init_pubsub(&input->event_pubsub); @@ -69,4 +69,6 @@ void input_task() { osThreadFlagsWait(INPUT_THREAD_FLAG_ISR, osFlagsWaitAny, osWaitForever); } } + + return 0; } diff --git a/applications/irda/irda.c b/applications/irda/irda.c index 0566d779..eab68267 100644 --- a/applications/irda/irda.c +++ b/applications/irda/irda.c @@ -234,7 +234,7 @@ void init_packet( state->packets[index].command = command; } -void irda(void* p) { +int32_t irda(void* p) { osMessageQueueId_t event_queue = osMessageQueueNew(32, sizeof(AppEvent), NULL); State _state; @@ -262,7 +262,7 @@ void irda(void* p) { ValueMutex state_mutex; if(!init_mutex(&state_mutex, &_state, sizeof(State))) { printf("cannot create mutex\r\n"); - furiac_exit(NULL); + return 255; } ViewPort* view_port = view_port_alloc(); @@ -316,7 +316,7 @@ void irda(void* p) { osMessageQueueDelete(event_queue); // exit - furiac_exit(NULL); + return 0; } if(event.value.input.type == InputTypeShort && diff --git a/applications/lf-rfid/lf-rfid.c b/applications/lf-rfid/lf-rfid.c index 382d5895..b5974531 100644 --- a/applications/lf-rfid/lf-rfid.c +++ b/applications/lf-rfid/lf-rfid.c @@ -160,7 +160,7 @@ static void extract_data(uint8_t* buf, uint8_t* customer, uint32_t* em_data) { *em_data = data; } -void lf_rfid_workaround(void* p) { +int32_t lf_rfid_workaround(void* p) { osMessageQueueId_t event_queue = osMessageQueueNew(8, sizeof(AppEvent), NULL); // create pin @@ -195,7 +195,7 @@ void lf_rfid_workaround(void* p) { ValueMutex state_mutex; if(!init_mutex(&state_mutex, &_state, sizeof(State))) { printf("cannot create mutex\r\n"); - furiac_exit(NULL); + return 255; } ViewPort* view_port = view_port_alloc(); @@ -293,7 +293,7 @@ void lf_rfid_workaround(void* p) { // TODO remove all view_ports create by app view_port_enabled_set(view_port, false); - furiac_exit(NULL); + return 255; } if(event.value.input.type == InputTypePress && @@ -356,4 +356,6 @@ void lf_rfid_workaround(void* p) { release_mutex(&state_mutex, state); } } + + return 0; } diff --git a/applications/menu/menu.c b/applications/menu/menu.c index b39363e6..cb81cdc6 100644 --- a/applications/menu/menu.c +++ b/applications/menu/menu.c @@ -35,7 +35,7 @@ ValueMutex* menu_init() { 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\r\n"); - furiac_exit(NULL); + furi_check(0); } // OpenGui record @@ -223,7 +223,7 @@ void menu_exit(Menu* menu) { menu_update(menu); } -void menu_task(void* p) { +int32_t menu_task(void* p) { ValueMutex* menu_mutex = menu_init(); MenuEvent* menu_event = NULL; @@ -267,4 +267,6 @@ void menu_task(void* p) { release_mutex(menu_mutex, menu); } + + return 0; } diff --git a/applications/music-player/music-player.c b/applications/music-player/music-player.c index 453724b3..2f0dc8c8 100644 --- a/applications/music-player/music-player.c +++ b/applications/music-player/music-player.c @@ -356,7 +356,7 @@ void music_player_thread(void* p) { } } -void music_player(void* p) { +int32_t music_player(void* p) { osMessageQueueId_t event_queue = osMessageQueueNew(8, sizeof(MusicDemoEvent), NULL); State _state; @@ -370,7 +370,7 @@ void music_player(void* p) { ValueMutex state_mutex; if(!init_mutex(&state_mutex, &_state, sizeof(State))) { printf("cannot create mutex\r\n"); - furiac_exit(NULL); + return 255; } ViewPort* view_port = view_port_alloc(); @@ -394,7 +394,7 @@ void music_player(void* p) { if(player == NULL) { printf("cannot create player thread\r\n"); - furiac_exit(NULL); + return 255; } MusicDemoEvent event; @@ -449,4 +449,6 @@ void music_player(void* p) { view_port_update(view_port); release_mutex(&state_mutex, state); } + + return 0; } diff --git a/applications/nfc/nfc.c b/applications/nfc/nfc.c index bc97a8e4..a2e45eaf 100644 --- a/applications/nfc/nfc.c +++ b/applications/nfc/nfc.c @@ -100,7 +100,7 @@ void nfc_start(Nfc* nfc, NfcView view_id, NfcWorkerState worker_state) { } } -void nfc_task(void* p) { +int32_t nfc_task(void* p) { Nfc* nfc = nfc_alloc(); Gui* gui = furi_record_open("gui"); @@ -142,4 +142,6 @@ void nfc_task(void* p) { }); } } + + return 0; } diff --git a/applications/nfc/nfc_i.h b/applications/nfc/nfc_i.h index 1bd985e7..9b8f074e 100644 --- a/applications/nfc/nfc_i.h +++ b/applications/nfc/nfc_i.h @@ -41,4 +41,4 @@ void nfc_menu_field_callback(void* context); void nfc_start(Nfc* nfc, NfcView view_id, NfcWorkerState worker_state); -void nfc_task(void* p); \ No newline at end of file +int32_t nfc_task(void* p); \ No newline at end of file diff --git a/applications/nfc/nfc_worker.c b/applications/nfc/nfc_worker.c index 59ac2601..88a3c5b3 100644 --- a/applications/nfc/nfc_worker.c +++ b/applications/nfc/nfc_worker.c @@ -55,7 +55,7 @@ void nfc_worker_change_state(NfcWorker* nfc_worker, NfcWorkerState state) { void nfc_worker_task(void* context) { NfcWorker* nfc_worker = context; - api_hal_timebase_insomnia_enter(); + api_hal_power_insomnia_enter(); rfalLowPowerModeStop(); if(nfc_worker->state == NfcWorkerStatePoll) { @@ -69,7 +69,7 @@ void nfc_worker_task(void* context) { nfc_worker_change_state(nfc_worker, NfcWorkerStateReady); - api_hal_timebase_insomnia_exit(); + api_hal_power_insomnia_exit(); osThreadExit(); } diff --git a/applications/power/power.c b/applications/power/power.c index 05a7c945..092d7f14 100644 --- a/applications/power/power.c +++ b/applications/power/power.c @@ -177,7 +177,7 @@ void power_cli_otg_off(string_t args, void* context) { api_hal_power_disable_otg(); } -void power_task(void* p) { +int32_t power_task(void* p) { (void)p; Power* power = power_alloc(); @@ -223,4 +223,6 @@ void power_task(void* p) { view_port_enabled_set(power->usb_view_port, api_hal_power_is_charging()); osDelay(1024); } + + return 0; } diff --git a/applications/sd-card-test/sd-card-test.cpp b/applications/sd-card-test/sd-card-test.cpp index 495cc28e..db996acb 100644 --- a/applications/sd-card-test/sd-card-test.cpp +++ b/applications/sd-card-test/sd-card-test.cpp @@ -904,7 +904,8 @@ void SdTest::render(Canvas* canvas) { } // app enter function -extern "C" void sd_card_test(void* p) { +extern "C" int32_t sd_card_test(void* p) { SdTest* app = new SdTest(); app->run(); + return 0; } \ No newline at end of file diff --git a/applications/sd-filesystem/sd-filesystem.c b/applications/sd-filesystem/sd-filesystem.c index 3f4b1818..0bb04aaa 100644 --- a/applications/sd-filesystem/sd-filesystem.c +++ b/applications/sd-filesystem/sd-filesystem.c @@ -101,9 +101,7 @@ SdApp* sd_app_alloc() { SdApp* sd_app = furi_alloc(sizeof(SdApp)); // init inner fs data - if(!_fs_init(&sd_app->info)) { - furiac_exit(NULL); - } + furi_check(_fs_init(&sd_app->info)); sd_app->event_queue = osMessageQueueNew(8, sizeof(InputEvent), NULL); @@ -476,7 +474,7 @@ static void cli_sd_info(string_t args, void* _ctx) { } } -void sd_filesystem(void* p) { +int32_t sd_filesystem(void* p) { SdApp* sd_app = sd_app_alloc(); FS_Api* fs_api = fs_api_alloc(); @@ -555,4 +553,6 @@ void sd_filesystem(void* p) { delay(1000); } + + return 0; } \ No newline at end of file diff --git a/applications/sd-nfc/sdnfc.cpp b/applications/sd-nfc/sdnfc.cpp index 032afa1b..159bb4d6 100644 --- a/applications/sd-nfc/sdnfc.cpp +++ b/applications/sd-nfc/sdnfc.cpp @@ -161,7 +161,8 @@ void AppSdNFC::blink_green() { } // app enter function -extern "C" void sdnfc(void* p) { +extern "C" int32_t sdnfc(void* p) { AppSdNFC* app = new AppSdNFC(); app->run(); + return 0; } \ No newline at end of file diff --git a/applications/template/template.c.example b/applications/template/template.c.example index 7cd7975b..fcb9bc9d 100644 --- a/applications/template/template.c.example +++ b/applications/template/template.c.example @@ -37,7 +37,7 @@ static void input_callback(InputEvent* input_event, void* ctx) { osMessageQueuePut(event_queue, &event, 0, 0); } -void template_app(void* p) { +int32_t template_app(void* p) { osMessageQueueId_t event_queue = osMessageQueueNew(8, sizeof(Event), NULL); State _state; @@ -45,7 +45,7 @@ void template_app(void* p) { ValueMutex state_mutex; if(!init_mutex(&state_mutex, &_state, sizeof(State))) { printf("cannot create mutex\r\n"); - furiac_exit(NULL); + return 255; } ViewPort* view_port = view_port_alloc(); @@ -57,7 +57,7 @@ void template_app(void* p) { Gui* gui = furi_record_open("gui"); if(gui == NULL) { printf("gui is not available\r\n"); - furiac_exit(NULL); + return 255; } gui_add_view_port(gui, view_port, /* specify UI layer */); @@ -99,4 +99,6 @@ void template_app(void* p) { release_mutex(&state_mutex, state); } + + return 0; } diff --git a/applications/tests/furi_event_test.c b/applications/tests/furi_event_test.c deleted file mode 100644 index 90335098..00000000 --- a/applications/tests/furi_event_test.c +++ /dev/null @@ -1,33 +0,0 @@ -#include -#include "minunit.h" - -static void furi_concurent_app(void* p) { - Event* event = p; - - signal_event(event); - - furiac_exit(NULL); -} - -void test_furi_event() { - mu_assert(false, "please reimplement or delete test"); - - /*Event event; - - mu_check(init_event(&event)); - - // The event should not be signalled right after creation - mu_check(!wait_event_with_timeout(&event, 100)); - - // Create second app - FuriApp* second_app __attribute__((unused)) = - furiac_start(furi_concurent_app, "furi concurent app", (void*)&event); - - // The event should be signalled now - mu_check(wait_event_with_timeout(&event, 100)); - - // The event should not be signalled once it's processed - mu_check(!wait_event_with_timeout(&event, 100)); - - mu_check(delete_event(&event));*/ -} diff --git a/applications/tests/furi_value_expanders_test.c b/applications/tests/furi_value_expanders_test.c deleted file mode 100644 index 361c52cb..00000000 --- a/applications/tests/furi_value_expanders_test.c +++ /dev/null @@ -1,145 +0,0 @@ -#include -#include "minunit.h" -#include - -typedef struct { - uint8_t red; - uint8_t green; - uint8_t blue; -} Rgb; - -static uint32_t rgb_final_state; - -static void rgb_clear(void* ctx, void* state) { - Rgb* rgb = state; - rgb->red = 0; - rgb->green = 0; - rgb->blue = 0; -} - -static void rgb_commit(void* ctx, void* state) { - Rgb* rgb = state; - rgb_final_state = ((uint32_t)rgb->red) | (((uint32_t)rgb->green) << 8) | - (((uint32_t)rgb->blue) << 16); -} - -static void set_red_composer(void* ctx, void* state) { - Rgb* rgb = state; - uint8_t* red = ctx; - - rgb->red = *red; -} - -void test_furi_value_composer() { - Rgb rgb = {0, 0, 0}; - ValueComposer composer; - Rgb layer1_rgb = {0, 0, 0}; - ValueMutex layer1_mutex; - uint8_t layer2_red = 0; - - rgb_final_state = 0xdeadbeef; - - mu_check(init_composer(&composer, &rgb)); - - mu_check(init_mutex(&layer1_mutex, &layer1_rgb, sizeof(layer1_rgb))); - - perform_compose(&composer, rgb_clear, rgb_commit, NULL); - mu_assert_int_eq(0xdeadbeef, rgb_final_state); - - ValueComposerHandle* layer1_handle = - add_compose_layer(&composer, COPY_COMPOSE, &layer1_mutex, UiLayerNotify); - mu_assert_pointers_not_eq(layer1_handle, NULL); - - // RGB state should be updated with the layer1 state - perform_compose(&composer, rgb_clear, rgb_commit, NULL); - mu_assert_int_eq(0x000000, rgb_final_state); - - layer2_red = 0xcc; - ValueComposerHandle* layer2_handle = - add_compose_layer(&composer, set_red_composer, &layer2_red, UiLayerAboveNotify); - mu_assert_pointers_not_eq(layer2_handle, NULL); - - // RGB state should be updated with the layer1 and layer2 state, in order - perform_compose(&composer, rgb_clear, rgb_commit, NULL); - mu_assert_int_eq(0x0000cc, rgb_final_state); - - // Change layer1 state - Rgb* state = acquire_mutex(&layer1_mutex, 0); - mu_assert_pointers_not_eq(state, NULL); - state->red = 0x12; - state->green = 0x34; - state->blue = 0x56; - release_mutex(&layer1_mutex, state); - - // Nothing should happen, we need to trigger composition request first - perform_compose(&composer, rgb_clear, rgb_commit, NULL); - mu_assert_int_eq(0x0000cc, rgb_final_state); - - request_compose(layer1_handle); - - perform_compose(&composer, rgb_clear, rgb_commit, NULL); - mu_assert_int_eq(0x5634cc, rgb_final_state); - - // Change layer2 state - layer2_red = 0xff; - - // Nothing should happen, we need to trigger composition request first - perform_compose(&composer, rgb_clear, rgb_commit, NULL); - mu_assert_int_eq(0x5634cc, rgb_final_state); - - request_compose(layer2_handle); - - perform_compose(&composer, rgb_clear, rgb_commit, NULL); - mu_assert_int_eq(0x5634ff, rgb_final_state); - - // Remove layer1 - mu_check(remove_compose_layer(layer1_handle)); - - perform_compose(&composer, rgb_clear, rgb_commit, NULL); - mu_assert_int_eq(0x0000ff, rgb_final_state); - - // Remove layer2 - mu_check(remove_compose_layer(layer2_handle)); - - perform_compose(&composer, rgb_clear, rgb_commit, NULL); - mu_assert_int_eq(0x000000, rgb_final_state); - - mu_check(delete_composer(&composer)); -} - -static const uint32_t notify_value_0 = 0x12345678; -static const uint32_t notify_value_1 = 0x11223344; - -static uint32_t pubsub_value = 0; - -void test_value_manager_handler(const void* arg, void* ctx) { - pubsub_value = *(uint32_t*)arg; -} - -void test_furi_value_manager() { - uint32_t value = 0; - ValueManager managed; - - mu_check(init_managed(&managed, &value, sizeof(value))); - - pubsub_value = 0; - - PubSubItem* test_pubsub_item; - test_pubsub_item = subscribe_pubsub(&managed.pubsub, test_value_manager_handler, 0); - mu_assert_pointers_not_eq(test_pubsub_item, NULL); - - mu_check(write_managed(&managed, (void*)¬ify_value_0, sizeof(notify_value_0), 100)); - - mu_assert_int_eq(pubsub_value, notify_value_0); - - uint32_t* ptr = acquire_mutex(&managed.value, 100); - mu_assert_pointers_not_eq(ptr, NULL); - - *ptr = notify_value_1; - - mu_check(commit_managed(&managed, ptr)); - - mu_assert_int_eq(pubsub_value, notify_value_1); - - mu_check(delete_managed(&managed)); -} diff --git a/applications/tests/furi_valuemutex_test.c b/applications/tests/furi_valuemutex_test.c index 7ea5f638..5a1125f5 100644 --- a/applications/tests/furi_valuemutex_test.c +++ b/applications/tests/furi_valuemutex_test.c @@ -60,7 +60,7 @@ void furi_concurent_app(void* p) { ValueMutex* mutex = (ValueMutex*)p; if(mutex == NULL) { printf("cannot open mutex\r\n"); - furiac_exit(NULL); + osThreadExit(); } for(size_t i = 0; i < 10; i++) { @@ -69,7 +69,7 @@ void furi_concurent_app(void* p) { if(value == NULL) { printf("cannot take record\r\n"); release_mutex(mutex, value); - furiac_exit(NULL); + osThreadExit(); } // emulate read-modify-write broken by context switching @@ -83,7 +83,7 @@ void furi_concurent_app(void* p) { release_mutex(mutex, value); } - furiac_exit(NULL); + osThreadExit(); } void test_furi_concurrent_access() { diff --git a/applications/tests/furiac_test.c b/applications/tests/furiac_test.c deleted file mode 100644 index 64fef937..00000000 --- a/applications/tests/furiac_test.c +++ /dev/null @@ -1,134 +0,0 @@ -#include -#include -#include - -/* -Test: creating and killing task - -1. create task -2. delay 10 ms -3. kill task -4. check that value changes -5. delay 2 ms -6. check that value stay unchanged -*/ - -void create_kill_app(void* p) { - // this app simply increase counter - uint8_t* counter = (uint8_t*)p; - while(1) { - *counter = *counter + 1; - delay(1); - } -} - -bool test_furi_ac_create_kill() { - mu_assert(false, "please reimplement or delete test"); - /* - uint8_t counter = 0; - - uint8_t value_a = counter; - - FuriApp* widget = furiac_start(create_kill_app, "create_kill_app", (void*)&counter); - if(widget == NULL) { - printf("create widget fail\r\n"); - return false; - } - - delay(10); - - if(!furiac_kill(widget)) { - printf("kill widget fail\r\n"); - return false; - } - - if(value_a == counter) { - printf("counter unchanged\r\n"); - return false; - } - - value_a = counter; - - delay(10); - - if(value_a != counter) { - printf("counter changes after kill (counter = %d vs %d)\n", value_a, counter); - return false; - } - - return true; - */ -} - -/* -Test: switch between tasks -1. init s -2. create task A, add 'A" to sequence' -3. switch to task B, add 'B' to sequence -4. exit from task B -> switch to A and add 'A' to sequence -5. cleanup: exit from task A -6. check sequence -*/ - -#define TEST_SWITCH_CONTEXT_SEQ_SIZE 8 - -typedef struct { - char sequence[TEST_SWITCH_CONTEXT_SEQ_SIZE]; - size_t count; -} TestSwitchSequence; - -void task_a(void*); -void task_b(void*); - -void task_a(void* p) { - // simply starts, add 'A' letter to sequence and switch - // if sequence counter = 0, call task B, exit otherwise - - TestSwitchSequence* seq = (TestSwitchSequence*)p; - - seq->sequence[seq->count] = 'A'; - seq->count++; - - if(seq->count == 1) { - furiac_switch(task_b, "task B", p); - - // if switch unsuccessfull, this code will executed - seq->sequence[seq->count] = 'x'; - seq->count++; - } else { - // add '/' symbol on exit - seq->sequence[seq->count] = '/'; - seq->count++; - furiac_exit(NULL); - } -} - -// application simply add 'B' end exit -void task_b(void* p) { - TestSwitchSequence* seq = (TestSwitchSequence*)p; - - seq->sequence[seq->count] = 'B'; - seq->count++; - - furiac_exit(p); -} - -bool test_furi_ac_switch_exit() { - // init sequence - TestSwitchSequence seq; - seq.count = 0; - - furiac_start(task_a, "task A", (void*)&seq); - // TODO how to check that all child task ends? - - delay(10); // wait while task do its work - - seq.sequence[seq.count] = '\0'; - - if(strcmp(seq.sequence, "ABA/") != 0) { - printf("wrong sequence: %s\n", seq.sequence); - return false; - } - - return true; -} \ No newline at end of file diff --git a/applications/tests/minunit_test.c b/applications/tests/minunit_test.c index 0fa28313..0a93ae7a 100644 --- a/applications/tests/minunit_test.c +++ b/applications/tests/minunit_test.c @@ -3,17 +3,11 @@ #include "minunit_vars.h" #include "minunit.h" -bool test_furi_ac_create_kill(); -bool test_furi_ac_switch_exit(); - // v2 tests void test_furi_create_open(); void test_furi_valuemutex(); void test_furi_concurrent_access(); void test_furi_pubsub(); -void test_furi_value_composer(); -void test_furi_value_manager(); -void test_furi_event(); void test_furi_memmgr(); @@ -31,14 +25,6 @@ MU_TEST(test_check) { mu_check(foo != 6); } -MU_TEST(mu_test_furi_ac_create_kill) { - mu_assert_int_eq(test_furi_ac_create_kill(), true); -} - -MU_TEST(mu_test_furi_ac_switch_exit) { - mu_assert_int_eq(test_furi_ac_switch_exit(), true); -} - // v2 tests MU_TEST(mu_test_furi_create_open) { test_furi_create_open(); @@ -62,30 +48,16 @@ MU_TEST(mu_test_furi_memmgr) { test_furi_memmgr(); } -MU_TEST(mu_test_furi_value_expanders) { - test_furi_value_composer(); - test_furi_value_manager(); -} - -MU_TEST(mu_test_furi_event) { - test_furi_event(); -} - MU_TEST_SUITE(test_suite) { MU_SUITE_CONFIGURE(&test_setup, &test_teardown); MU_RUN_TEST(test_check); - MU_RUN_TEST(mu_test_furi_ac_create_kill); - MU_RUN_TEST(mu_test_furi_ac_switch_exit); // v2 tests MU_RUN_TEST(mu_test_furi_create_open); MU_RUN_TEST(mu_test_furi_valuemutex); MU_RUN_TEST(mu_test_furi_concurrent_access); MU_RUN_TEST(mu_test_furi_pubsub); - MU_RUN_TEST(mu_test_furi_value_expanders); - MU_RUN_TEST(mu_test_furi_event); - MU_RUN_TEST(mu_test_furi_memmgr); } diff --git a/applications/tests/test_index.c b/applications/tests/test_index.c index 51bff386..2752ccb5 100644 --- a/applications/tests/test_index.c +++ b/applications/tests/test_index.c @@ -5,7 +5,7 @@ int run_minunit(); -void flipper_test_app(void* p) { +int32_t flipper_test_app(void* p) { // create pins GpioPin red = {.pin = LED_RED_Pin, .port = LED_RED_GPIO_Port}; GpioPin green = {.pin = LED_GREEN_Pin, .port = LED_GREEN_GPIO_Port}; @@ -38,7 +38,5 @@ void flipper_test_app(void* p) { gpio_write(blue_record, true); } - set_exitcode(exitcode); - - furiac_exit(NULL); + return 0; } \ No newline at end of file diff --git a/core/flipper.c b/core/flipper.c new file mode 100644 index 00000000..55b66027 --- /dev/null +++ b/core/flipper.c @@ -0,0 +1,26 @@ +#include "flipper.h" +#include +#include + +void flipper_init() { + printf("[flipper] Build date:" BUILD_DATE ". " + "Git Commit:" GIT_COMMIT ". " + "Git Branch:" GIT_BRANCH ". " + "Commit Number:" GIT_BRANCH_NUM "\r\n"); + + printf("[flipper] starting services\r\n"); + + for(size_t i = 0; i < FLIPPER_SERVICES_COUNT; i++) { + printf("[flipper] starting service %s\r\n", FLIPPER_SERVICES[i].name); + + FuriThread* thread = furi_thread_alloc(); + + furi_thread_set_name(thread, FLIPPER_SERVICES[i].name); + furi_thread_set_stack_size(thread, FLIPPER_SERVICES[i].stack_size); + furi_thread_set_callback(thread, FLIPPER_SERVICES[i].app); + + furi_thread_start(thread); + } + + printf("[flipper] services startup complete\r\n"); +} \ No newline at end of file diff --git a/core/flipper.h b/core/flipper.h new file mode 100644 index 00000000..5b277fac --- /dev/null +++ b/core/flipper.h @@ -0,0 +1,3 @@ +#pragma once + +void flipper_init(); diff --git a/core/furi.c b/core/furi.c index 2e04a468..d3df39ab 100644 --- a/core/furi.c +++ b/core/furi.c @@ -1,12 +1,4 @@ #include "furi.h" -#include - -// for testing purpose -uint32_t exitcode = 0; - -void set_exitcode(uint32_t _exitcode) { - exitcode = _exitcode; -} void furi_init() { gpio_api_init(); @@ -14,25 +6,3 @@ void furi_init() { furi_record_init(); furi_stdglue_init(); } - -int systemd() { - furi_init(); - printf("[systemd] furi initialized\r\n"); - // FURI startup - for(size_t i = 0; i < FLIPPER_SERVICES_size(); i++) { - printf("[systemd] starting service %s\r\n", FLIPPER_SERVICES[i].name); - osThreadAttr_t* attr = furi_alloc(sizeof(osThreadAttr_t)); - attr->name = FLIPPER_SERVICES[i].name; - attr->stack_size = FLIPPER_SERVICES[i].stack_size; - osThreadNew(FLIPPER_SERVICES[i].app, NULL, attr); - } - printf("[systemd] all services started\r\n"); - - while(1) { - osThreadSuspend(osThreadGetId()); - } - - printf("[systemd] === Bye from Flipper Zero! ===\r\n"); - - return (int)exitcode; -} \ No newline at end of file diff --git a/core/furi.h b/core/furi.h index 6512f9b2..86a865ad 100644 --- a/core/furi.h +++ b/core/furi.h @@ -3,12 +3,11 @@ #include #include -#include #include #include #include #include -#include +#include #include #include @@ -21,7 +20,7 @@ extern "C" { #endif -#define furiac_exit(ptr) osThreadExit() +void furi_init(); #ifdef __cplusplus } diff --git a/core/furi/event.c b/core/furi/event.c deleted file mode 100644 index 1fc9cbfd..00000000 --- a/core/furi/event.c +++ /dev/null @@ -1,24 +0,0 @@ -#include "event.h" -#include - -bool init_event(Event* event) { - event->semaphore_id = osSemaphoreNew(1, 0, NULL); - return event->semaphore_id != NULL; -} - -bool delete_event(Event* event) { - return osSemaphoreDelete(event->semaphore_id) == osOK; -} - -void signal_event(Event* event) { - // Ignore the result, as we do not care about repeated event signalling. - osSemaphoreRelease(event->semaphore_id); -} - -void wait_event(Event* event) { - wait_event_with_timeout(event, osWaitForever); -} - -bool wait_event_with_timeout(Event* event, uint32_t timeout_ms) { - return osSemaphoreAcquire(event->semaphore_id, timeout_ms) == osOK; -} diff --git a/core/furi/event.h b/core/furi/event.h deleted file mode 100644 index a7683bd1..00000000 --- a/core/furi/event.h +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - osSemaphoreId_t semaphore_id; -} Event; - -/* -Creates Event. -*/ -bool init_event(Event* event); - -/* -Free resources allocated by `init_event`. -This function doesn't free the memory occupied by `Event` itself. -*/ -bool delete_event(Event* event); - -/* -Signals the event. -If the event is already in "signalled" state, nothing happens. -*/ -void signal_event(Event* event); - -/* -Waits until the event is signalled. -*/ -void wait_event(Event* event); - -/* -Waits with a timeout until the event is signalled. -*/ -bool wait_event_with_timeout(Event* event, uint32_t timeout_ms); - -#ifdef __cplusplus -} -#endif diff --git a/core/furi/thread.c b/core/furi/thread.c new file mode 100644 index 00000000..81c0eeed --- /dev/null +++ b/core/furi/thread.c @@ -0,0 +1,122 @@ +#include "thread.h" +#include "memmgr.h" +#include "check.h" + +#include + +struct FuriThread { + FuriThreadState state; + int32_t ret; + + FuriThreadCallback callback; + void* context; + + FuriThreadStateCallback state_callback; + void* state_context; + + osThreadAttr_t attr; + osThreadId_t id; +}; + +void furi_thread_set_state(FuriThread* thread, FuriThreadState state) { + furi_assert(thread); + thread->state = state; + if(thread->state_callback) { + thread->state_callback(state, thread->state_context); + } +} + +void furi_thread_body(void* context) { + furi_assert(context); + FuriThread* thread = context; + + furi_assert(thread->state == FuriThreadStateStarting); + furi_thread_set_state(thread, FuriThreadStateRunning); + + thread->ret = thread->callback(thread->context); + + furi_assert(thread->state == FuriThreadStateRunning); + furi_thread_set_state(thread, FuriThreadStateStopped); + + osThreadExit(); +} + +FuriThread* furi_thread_alloc() { + FuriThread* thread = furi_alloc(sizeof(FuriThread)); + + return thread; +} + +void furi_thread_free(FuriThread* thread) { + furi_assert(thread); + furi_assert(thread->state == FuriThreadStateStopped); + + if(thread->attr.name) free((void*)thread->attr.name); + free(thread); +} + +void furi_thread_set_name(FuriThread* thread, const char* name) { + furi_assert(thread); + furi_assert(thread->state == FuriThreadStateStopped); + if(thread->attr.name) free((void*)thread->attr.name); + thread->attr.name = strdup(name); +} + +void furi_thread_set_stack_size(FuriThread* thread, size_t stack_size) { + furi_assert(thread); + furi_assert(thread->state == FuriThreadStateStopped); + thread->attr.stack_size = stack_size; +} + +void furi_thread_set_callback(FuriThread* thread, FuriThreadCallback callback) { + furi_assert(thread); + furi_assert(thread->state == FuriThreadStateStopped); + thread->callback = callback; +} + +void furi_thread_set_context(FuriThread* thread, void* context) { + furi_assert(thread); + furi_assert(thread->state == FuriThreadStateStopped); + thread->context = context; +} + +void furi_thread_set_state_callback(FuriThread* thread, FuriThreadStateCallback callback) { + furi_assert(thread); + furi_assert(thread->state == FuriThreadStateStopped); + thread->state_callback = callback; +} + +void furi_thread_set_state_context(FuriThread* thread, void* context) { + furi_assert(thread); + furi_assert(thread->state == FuriThreadStateStopped); + thread->state_context = context; +} + +bool furi_thread_start(FuriThread* thread) { + furi_assert(thread); + furi_assert(thread->callback); + furi_assert(thread->state == FuriThreadStateStopped); + furi_thread_set_state(thread, FuriThreadStateStarting); + thread->id = osThreadNew(furi_thread_body, thread, &thread->attr); + if(thread->id) { + return true; + } else { + furi_assert(thread->state == FuriThreadStateStarting); + furi_thread_set_state(thread, FuriThreadStateStopped); + return false; + } +} + +osStatus_t furi_thread_terminate(FuriThread* thread) { + furi_assert(thread); + osStatus_t ret = osThreadTerminate(thread->id); + if(ret == osOK) { + furi_thread_set_state(thread, FuriThreadStateStopped); + } + return ret; +} + +osStatus_t furi_thread_join(FuriThread* thread) { + furi_assert(thread); + return osThreadJoin(thread->id); +} diff --git a/core/furi/thread.h b/core/furi/thread.h new file mode 100644 index 00000000..6d502c21 --- /dev/null +++ b/core/furi/thread.h @@ -0,0 +1,102 @@ +#pragma once + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* FuriThreadState */ +typedef enum { + FuriThreadStateStopped, + FuriThreadStateStarting, + FuriThreadStateRunning, +} FuriThreadState; + +/* FuriThread anonymous structure */ +typedef struct FuriThread FuriThread; + +/* FuriThreadCallback + * Your callback to run in new thread + * @warning don't use osThreadExit + */ +typedef int32_t (*FuriThreadCallback)(void* context); + +/* FuriThread state change calback + * called upon thread state change + * @param state - new thread state + * @param context - callback context + */ +typedef void (*FuriThreadStateCallback)(FuriThreadState state, void* context); + +/* Allocate FuriThread + * @return FuriThread instance + */ +FuriThread* furi_thread_alloc(); + +/* Release FuriThread + * @param thread - FuriThread instance + */ +void furi_thread_free(FuriThread* thread); + +/* Set FuriThread name + * @param thread - FuriThread instance + * @param name - string + */ +void furi_thread_set_name(FuriThread* thread, const char* name); + +/* Set FuriThread stack size + * @param thread - FuriThread instance + * @param stack_size - stack size in bytes + */ +void furi_thread_set_stack_size(FuriThread* thread, size_t stack_size); + +/* Set FuriThread callback + * @param thread - FuriThread instance + * @param callback - FuriThreadCallback, called upon thread run + */ +void furi_thread_set_callback(FuriThread* thread, FuriThreadCallback callback); + +/* Set FuriThread context + * @param thread - FuriThread instance + * @param context - pointer to context for thread callback + */ +void furi_thread_set_context(FuriThread* thread, void* context); + +/* Set FuriThread state change callback + * @param thread - FuriThread instance + * @param callack - state change callback + */ +void furi_thread_set_state_callback(FuriThread* thread, FuriThreadStateCallback callback); + +/* Set FuriThread state change context + * @param thread - FuriThread instance + * @param context - pointer to context + */ +void furi_thread_set_state_context(FuriThread* thread, void* context); + +/* Start FuriThread + * @param thread - FuriThread instance + * @return true on success + */ +bool furi_thread_start(FuriThread* thread); + +/* Treminate FuriThread + * @param thread - FuriThread instance + * @return osStatus_t + * @warning terminating statefull thread is dangerous + * use only if you know what you doing + */ +osStatus_t furi_thread_terminate(FuriThread* thread); + +/* Join FuriThread + * @param thread - FuriThread instance + * @return osStatus_t + */ +osStatus_t furi_thread_join(FuriThread* thread); + +#ifdef __cplusplus +} +#endif diff --git a/core/furi/value-expanders.c b/core/furi/value-expanders.c deleted file mode 100644 index d5e49b8c..00000000 --- a/core/furi/value-expanders.c +++ /dev/null @@ -1,174 +0,0 @@ -#include "value-expanders.h" - -bool init_composer(ValueComposer* composer, void* value) { - if(!init_mutex(&composer->value, value, 0)) return false; - - for(size_t i = 0; i < sizeof(composer->layers) / sizeof(composer->layers[0]); i++) { - list_composer_cb_init(composer->layers[i]); - } - - // mutex without name, - // no attributes (unfortunatly robust mutex is not supported by FreeRTOS), - // with dynamic memory allocation - composer->mutex = osMutexNew(NULL); - if(composer->mutex == NULL) return false; - - if(!init_event(&composer->request)) return false; - - return true; -} - -bool delete_composer(ValueComposer* composer) { - if(osMutexAcquire(composer->mutex, osWaitForever) == osOK) { - bool result = true; - result &= delete_mutex(&composer->value); - - for(size_t i = 0; i < sizeof(composer->layers) / sizeof(composer->layers[0]); i++) { - list_composer_cb_clear(composer->layers[i]); - } - - result &= osMutexDelete(composer->mutex) == osOK; - - return result; - } else { - return false; - } -} - -ValueComposerHandle* -add_compose_layer(ValueComposer* composer, ValueComposerCallback cb, void* ctx, UiLayer layer) { - if(osMutexAcquire(composer->mutex, osWaitForever) == osOK) { - // put uninitialized item to the list - ValueComposerHandle* handle = list_composer_cb_push_raw(composer->layers[layer]); - - handle->cb = cb; - handle->ctx = ctx; - handle->layer = layer; - handle->composer = composer; - - // TODO unregister handle on app exit - //flapp_on_exit(remove_compose_layer, handle); - - osMutexRelease(composer->mutex); - - // Layers changed, request composition - signal_event(&composer->request); - - return handle; - } else { - return NULL; - } -} - -bool remove_compose_layer(ValueComposerHandle* handle) { - ValueComposer* composer = handle->composer; - - if(osMutexAcquire(composer->mutex, osWaitForever) == osOK) { - bool result = false; - - // iterate over items - list_composer_cb_it_t it; - for(list_composer_cb_it(it, composer->layers[handle->layer]); !list_composer_cb_end_p(it); - list_composer_cb_next(it)) { - const ValueComposerHandle* item = list_composer_cb_cref(it); - - // if the iterator is equal to our element - if(item == handle) { - list_composer_cb_remove(composer->layers[handle->layer], it); - result = true; - break; - } - } - - osMutexRelease(composer->mutex); - - // Layers changed, request composition - signal_event(&composer->request); - - return result; - } else { - return false; - } -} - -void request_compose(ValueComposerHandle* handle) { - ValueComposer* composer = handle->composer; - signal_event(&composer->request); -} - -void perform_compose( - ValueComposer* composer, - ValueComposerCallback start_cb, - ValueComposerCallback end_cb, - void* ctx) { - if(!wait_event_with_timeout(&composer->request, 0)) return; - - void* state = acquire_mutex(&composer->value, 0); - if(state == NULL) return; - - if(start_cb != NULL) start_cb(ctx, state); - perform_compose_internal(composer, state); - if(end_cb != NULL) end_cb(ctx, state); - - release_mutex(&composer->value, state); -} - -void perform_compose_internal(ValueComposer* composer, void* state) { - if(osMutexAcquire(composer->mutex, osWaitForever) == osOK) { - // Compose all levels for now - for(size_t i = 0; i < sizeof(composer->layers) / sizeof(composer->layers[0]); i++) { - // iterate over items - list_composer_cb_it_t it; - for(list_composer_cb_it(it, composer->layers[i]); !list_composer_cb_end_p(it); - list_composer_cb_next(it)) { - const ValueComposerHandle* h = list_composer_cb_cref(it); - h->cb(h->ctx, state); - } - } - - osMutexRelease(composer->mutex); - } -} - -void COPY_COMPOSE(void* ctx, void* state) { - read_mutex((ValueMutex*)ctx, state, 0, osWaitForever); -} - -bool init_managed(ValueManager* managed, void* value, size_t size) { - if(!init_pubsub(&managed->pubsub)) return false; - if(!init_mutex(&managed->value, value, size)) { - delete_pubsub(&managed->pubsub); - return false; - } - return true; -} - -bool delete_managed(ValueManager* managed) { - bool result = true; - result &= delete_mutex(&managed->value); - result &= delete_pubsub(&managed->pubsub); - return result; -} - -bool write_managed(ValueManager* managed, void* data, size_t len, uint32_t timeout) { - void* value = acquire_mutex(&managed->value, timeout); - if(value == NULL) return false; - - memcpy(value, data, len); - - notify_pubsub(&managed->pubsub, value); - - if(!release_mutex(&managed->value, value)) return false; - - return true; -} - -bool commit_managed(ValueManager* managed, void* value) { - if(value != managed->value.value) return false; - - notify_pubsub(&managed->pubsub, value); - - if(!release_mutex(&managed->value, value)) return false; - - return true; -} diff --git a/core/furi/value-expanders.h b/core/furi/value-expanders.h deleted file mode 100644 index aef4a117..00000000 --- a/core/furi/value-expanders.h +++ /dev/null @@ -1,115 +0,0 @@ -#pragma once - -#include "valuemutex.h" -#include "pubsub.h" -#include "event.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* -== Value composer == -*/ - -typedef struct ValueComposer ValueComposer; - -typedef void (*ValueComposerCallback)(void* ctx, void* state); - -typedef enum { UiLayerBelowNotify, UiLayerNotify, UiLayerAboveNotify } UiLayer; - -typedef struct { - ValueComposerCallback cb; - void* ctx; - UiLayer layer; - ValueComposer* composer; -} ValueComposerHandle; - -LIST_DEF(list_composer_cb, ValueComposerHandle, M_POD_OPLIST); - -struct ValueComposer { - ValueMutex value; - list_composer_cb_t layers[3]; - osMutexId_t mutex; - Event request; -}; - -void COPY_COMPOSE(void* ctx, void* state); - -bool init_composer(ValueComposer* composer, void* value); - -/* -Free resources allocated by `init_composer`. -This function doesn't free the memory occupied by `ValueComposer` itself. -*/ -bool delete_composer(ValueComposer* composer); - -ValueComposerHandle* -add_compose_layer(ValueComposer* composer, ValueComposerCallback cb, void* ctx, UiLayer layer); - -bool remove_compose_layer(ValueComposerHandle* handle); - -void request_compose(ValueComposerHandle* handle); - -/* -Perform composition if requested. - -`start_cb` and `end_cb` will be called before and after all layer callbacks, respectively. -Both `start_cb` and `end_cb` can be NULL. They can be used to set initial state (e.g. clear screen) -and commit the final state. -*/ -void perform_compose( - ValueComposer* composer, - ValueComposerCallback start_cb, - ValueComposerCallback end_cb, - void* ctx); - -/* -Perform composition. - -This function should be called with value mutex acquired. -This function is here for convenience, so that developers can write their own compose loops. -See `perform_compose` function body for an example. -*/ -void perform_compose_internal(ValueComposer* composer, void* state); - -// See [LED](LED-API) or [Display](Display-API) API for examples. - -/* -== ValueManager == - -More complicated concept is ValueManager. -It is like ValueMutex, but user can subscribe to value updates. - -First of all you can use value and pubsub part as showing above: -aquire/release mutex, read value, subscribe/unsubscribe pubsub. -There are two specific methods for ValueManager: write_managed, commit_managed -*/ - -typedef struct { - ValueMutex value; - PubSub pubsub; -} ValueManager; - -bool init_managed(ValueManager* managed, void* value, size_t size); - -/* -Free resources allocated by `init_managed`. -This function doesn't free the memory occupied by `ValueManager` itself. -*/ -bool delete_managed(ValueManager* managed); - -/* -acquire value, changes it and send notify with current value. -*/ -bool write_managed(ValueManager* managed, void* data, size_t len, uint32_t timeout); - -/* -commit_managed works as `release_mutex` but send notify with current value. -*/ -bool commit_managed(ValueManager* managed, void* value); - -#ifdef __cplusplus -} -#endif diff --git a/firmware/targets/api-hal-include/api-hal-power.h b/firmware/targets/api-hal-include/api-hal-power.h index 454e9642..1928342c 100644 --- a/firmware/targets/api-hal-include/api-hal-power.h +++ b/firmware/targets/api-hal-include/api-hal-power.h @@ -16,6 +16,25 @@ typedef enum { /* Initialize drivers */ void api_hal_power_init(); +/* Get current insomnia level + * @return insomnia level: 0 - no insomnia, >0 - insomnia, bearer count. + */ +uint16_t api_hal_power_insomnia_level(); + +/* Enter insomnia mode + * Prevents device from going to sleep + * @warning Internally increases insomnia level + * Must be paired with api_hal_power_insomnia_exit + */ +void api_hal_power_insomnia_enter(); + +/* Exit insomnia mode + * Allow device to go to sleep + * @warning Internally decreases insomnia level. + * Must be paired with api_hal_power_insomnia_enter + */ +void api_hal_power_insomnia_exit(); + /* Check if deep sleep availble */ bool api_hal_power_deep_available(); diff --git a/firmware/targets/api-hal-include/api-hal.h b/firmware/targets/api-hal-include/api-hal.h index 15b4a414..f60d610d 100644 --- a/firmware/targets/api-hal-include/api-hal.h +++ b/firmware/targets/api-hal-include/api-hal.h @@ -4,9 +4,9 @@ template struct STOP_EXTERNING_ME {}; #endif -#include "api-hal-resources.h" -#include "api-hal-timebase.h" #include "api-hal-boot.h" +#include "api-hal-os.h" +#include "api-hal-resources.h" #include "api-hal-gpio.h" #include "api-hal-delay.h" #include "api-hal-pwm.h" diff --git a/firmware/targets/f4/Src/app_freertos.c b/firmware/targets/f4/Src/app_freertos.c deleted file mode 100644 index 0eb71984..00000000 --- a/firmware/targets/f4/Src/app_freertos.c +++ /dev/null @@ -1,25 +0,0 @@ -#include -#include -#include -#include - -void systemd(void *argument); - -osThreadId_t systemdHandle; -const osThreadAttr_t systemd_attributes = { - .name = "systemd", - .priority = (osPriority_t) osPriorityNormal, - .stack_size = 1024 -}; - -void vApplicationStackOverflowHook(TaskHandle_t xTask, signed char *pcTaskName) { - /* Run time stack overflow checking is performed if - configCHECK_FOR_STACK_OVERFLOW is defined to 1 or 2. This hook function is - called if a stack overflow is detected. */ - asm("bkpt 1"); - while(1); -} - -void MX_FREERTOS_Init(void) { - systemdHandle = osThreadNew(systemd, NULL, &systemd_attributes); -} diff --git a/firmware/targets/f4/Src/main.c b/firmware/targets/f4/Src/main.c index 095b5188..8b68d032 100644 --- a/firmware/targets/f4/Src/main.c +++ b/firmware/targets/f4/Src/main.c @@ -1,25 +1,6 @@ -/* USER CODE BEGIN Header */ -/** - ****************************************************************************** - * @file : main.c - * @brief : Main program body - ****************************************************************************** - * @attention - * - *

© Copyright (c) 2020 STMicroelectronics. - * All rights reserved.

- * - * This software component is licensed by ST under Ultimate Liberty license - * SLA0044, the "License"; You may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * www.st.com/SLA0044 - * - ****************************************************************************** - */ -/* USER CODE END Header */ -/* Includes ------------------------------------------------------------------*/ #include "main.h" -#include "cmsis_os.h" + +#include "cmsis_os2.h" #include "adc.h" #include "aes.h" #include "comp.h" @@ -34,234 +15,141 @@ #include "usart.h" #include "usb_device.h" #include "gpio.h" - -/* Private includes ----------------------------------------------------------*/ -/* USER CODE BEGIN Includes */ #include "fatfs/fatfs.h" -#include "api-hal.h" -/* USER CODE END Includes */ -/* Private typedef -----------------------------------------------------------*/ -/* USER CODE BEGIN PTD */ +#include +#include +#include -/* USER CODE END PTD */ - -/* Private define ------------------------------------------------------------*/ -/* USER CODE BEGIN PD */ -/* USER CODE END PD */ - -/* Private macro -------------------------------------------------------------*/ -/* USER CODE BEGIN PM */ - -/* USER CODE END PM */ - -/* Private variables ---------------------------------------------------------*/ - -/* USER CODE BEGIN PV */ - -/* USER CODE END PV */ - -/* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); void MX_FREERTOS_Init(void); -/* USER CODE BEGIN PFP */ -/* USER CODE END PFP */ - -/* Private user code ---------------------------------------------------------*/ -/* USER CODE BEGIN 0 */ - -/* USER CODE END 0 */ - -/** - * @brief The application entry point. - * @retval int - */ int main(void) { - /* USER CODE BEGIN 1 */ + HAL_Init(); + SystemClock_Config(); - /* USER CODE END 1 */ + MX_GPIO_Init(); + MX_ADC1_Init(); + MX_I2C1_Init(); + MX_RTC_Init(); + MX_SPI1_Init(); + MX_SPI2_Init(); + MX_USART1_UART_Init(); + MX_USB_Device_Init(); + MX_TIM1_Init(); + MX_TIM2_Init(); + MX_TIM16_Init(); + MX_COMP1_Init(); + MX_RF_Init(); + MX_PKA_Init(); + MX_RNG_Init(); + MX_AES1_Init(); + MX_AES2_Init(); + MX_CRC_Init(); - /* MCU Configuration--------------------------------------------------------*/ + api_hal_init(); + MX_FATFS_Init(); + delay_us_init_DWT(); - /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ - HAL_Init(); + furi_init(); + // CMSIS initialization + osKernelInitialize(); + // Init flipper + flipper_init(); + // Start kernel + osKernelStart(); - /* USER CODE BEGIN Init */ - /* USER CODE END Init */ - - /* Configure the system clock */ - SystemClock_Config(); - - /* USER CODE BEGIN SysInit */ - - /* USER CODE END SysInit */ - - /* Initialize all configured peripherals */ - MX_GPIO_Init(); - MX_ADC1_Init(); - MX_I2C1_Init(); - MX_RTC_Init(); - MX_SPI1_Init(); - MX_SPI2_Init(); - MX_USART1_UART_Init(); - MX_USB_Device_Init(); - MX_TIM1_Init(); - MX_TIM2_Init(); - MX_TIM16_Init(); - MX_COMP1_Init(); - MX_RF_Init(); - MX_PKA_Init(); - MX_RNG_Init(); - MX_AES1_Init(); - MX_AES2_Init(); - MX_CRC_Init(); - /* USER CODE BEGIN 2 */ - api_hal_init(); - MX_FATFS_Init(); - delay_us_init_DWT(); - // Errata 2.2.9, Flash OPTVERR flag is always set after system reset - __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS); - /* USER CODE END 2 */ - - /* Init scheduler */ - osKernelInitialize(); /* Call init function for freertos objects (in freertos.c) */ - MX_FREERTOS_Init(); - /* Start scheduler */ - osKernelStart(); - - /* We should never get here as control is now taken by the scheduler */ - /* Infinite loop */ - /* USER CODE BEGIN WHILE */ - while (1) - { - /* USER CODE END WHILE */ - - /* USER CODE BEGIN 3 */ - } - /* USER CODE END 3 */ + while (1) {} } -/** - * @brief System Clock Configuration - * @retval None - */ void SystemClock_Config(void) { - RCC_OscInitTypeDef RCC_OscInitStruct = {0}; - RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; - RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0}; + RCC_OscInitTypeDef RCC_OscInitStruct = {0}; + RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; + RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0}; - /** Configure LSE Drive Capability - */ - HAL_PWR_EnableBkUpAccess(); - __HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_MEDIUMLOW); - /** Configure the main internal regulator output voltage - */ - __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); - /** Initializes the RCC Oscillators according to the specified parameters - * in the RCC_OscInitTypeDef structure. - */ - RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_HSE - |RCC_OSCILLATORTYPE_LSE; - RCC_OscInitStruct.HSEState = RCC_HSE_ON; - RCC_OscInitStruct.LSEState = RCC_LSE_ON; - RCC_OscInitStruct.HSIState = RCC_HSI_ON; - RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; - RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; - RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; - RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV2; - RCC_OscInitStruct.PLL.PLLN = 8; - RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; - RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2; - RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2; - if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) - { - Error_Handler(); - } - /** Configure the SYSCLKSource, HCLK, PCLK1 and PCLK2 clocks dividers - */ - RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK4|RCC_CLOCKTYPE_HCLK2 - |RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK - |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; - RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; - RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; - RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; - RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; - RCC_ClkInitStruct.AHBCLK2Divider = RCC_SYSCLK_DIV2; - RCC_ClkInitStruct.AHBCLK4Divider = RCC_SYSCLK_DIV1; + HAL_PWR_EnableBkUpAccess(); - if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3) != HAL_OK) - { - Error_Handler(); - } - /** Initializes the peripherals clocks - */ - PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SMPS|RCC_PERIPHCLK_RFWAKEUP - |RCC_PERIPHCLK_RTC|RCC_PERIPHCLK_USART1 - |RCC_PERIPHCLK_I2C1|RCC_PERIPHCLK_CLK48SEL - |RCC_PERIPHCLK_USB|RCC_PERIPHCLK_RNG - |RCC_PERIPHCLK_ADC; - PeriphClkInitStruct.PLLSAI1.PLLN = 6; - PeriphClkInitStruct.PLLSAI1.PLLP = RCC_PLLP_DIV2; - PeriphClkInitStruct.PLLSAI1.PLLQ = RCC_PLLQ_DIV2; - PeriphClkInitStruct.PLLSAI1.PLLR = RCC_PLLR_DIV2; - PeriphClkInitStruct.PLLSAI1.PLLSAI1ClockOut = RCC_PLLSAI1_USBCLK|RCC_PLLSAI1_ADCCLK; - PeriphClkInitStruct.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2; - PeriphClkInitStruct.I2c1ClockSelection = RCC_I2C1CLKSOURCE_PCLK1; - PeriphClkInitStruct.UsbClockSelection = RCC_USBCLKSOURCE_PLLSAI1; - PeriphClkInitStruct.RngClockSelection = RCC_RNGCLKSOURCE_CLK48; - PeriphClkInitStruct.AdcClockSelection = RCC_ADCCLKSOURCE_PLLSAI1; - PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE; - PeriphClkInitStruct.RFWakeUpClockSelection = RCC_RFWKPCLKSOURCE_LSE; - PeriphClkInitStruct.SmpsClockSelection = RCC_SMPSCLKSOURCE_HSE; - PeriphClkInitStruct.SmpsDivSelection = RCC_SMPSCLKDIV_RANGE1; - if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) - { - Error_Handler(); - } - /* USER CODE BEGIN Smps */ - /* USER CODE END Smps */ - /** Enables the Clock Security System - */ - HAL_RCC_EnableCSS(); - /** Enables the Clock Security System - */ - HAL_RCCEx_EnableLSECSS(); + __HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_MEDIUMLOW); + __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); + + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_HSE + |RCC_OSCILLATORTYPE_LSE; + RCC_OscInitStruct.HSEState = RCC_HSE_ON; + RCC_OscInitStruct.LSEState = RCC_LSE_ON; + RCC_OscInitStruct.HSIState = RCC_HSI_ON; + RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; + RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; + RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; + RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV2; + RCC_OscInitStruct.PLL.PLLN = 8; + RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; + RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2; + RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2; + if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { + Error_Handler(); + } + + RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK4|RCC_CLOCKTYPE_HCLK2 + |RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK + |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; + RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; + RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; + RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; + RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; + RCC_ClkInitStruct.AHBCLK2Divider = RCC_SYSCLK_DIV2; + RCC_ClkInitStruct.AHBCLK4Divider = RCC_SYSCLK_DIV1; + + if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3) != HAL_OK) { + Error_Handler(); + } + + PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SMPS|RCC_PERIPHCLK_RFWAKEUP + |RCC_PERIPHCLK_RTC|RCC_PERIPHCLK_USART1 + |RCC_PERIPHCLK_I2C1|RCC_PERIPHCLK_CLK48SEL + |RCC_PERIPHCLK_USB|RCC_PERIPHCLK_RNG + |RCC_PERIPHCLK_ADC; + PeriphClkInitStruct.PLLSAI1.PLLN = 6; + PeriphClkInitStruct.PLLSAI1.PLLP = RCC_PLLP_DIV2; + PeriphClkInitStruct.PLLSAI1.PLLQ = RCC_PLLQ_DIV2; + PeriphClkInitStruct.PLLSAI1.PLLR = RCC_PLLR_DIV2; + PeriphClkInitStruct.PLLSAI1.PLLSAI1ClockOut = RCC_PLLSAI1_USBCLK|RCC_PLLSAI1_ADCCLK; + PeriphClkInitStruct.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2; + PeriphClkInitStruct.I2c1ClockSelection = RCC_I2C1CLKSOURCE_PCLK1; + PeriphClkInitStruct.UsbClockSelection = RCC_USBCLKSOURCE_PLLSAI1; + PeriphClkInitStruct.RngClockSelection = RCC_RNGCLKSOURCE_CLK48; + PeriphClkInitStruct.AdcClockSelection = RCC_ADCCLKSOURCE_PLLSAI1; + PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE; + PeriphClkInitStruct.RFWakeUpClockSelection = RCC_RFWKPCLKSOURCE_LSE; + PeriphClkInitStruct.SmpsClockSelection = RCC_SMPSCLKSOURCE_HSE; + PeriphClkInitStruct.SmpsDivSelection = RCC_SMPSCLKDIV_RANGE1; + if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) { + Error_Handler(); + } + + // Enable CSS for both clocks + HAL_RCC_EnableCSS(); + HAL_RCCEx_EnableLSECSS(); } -/* USER CODE BEGIN 4 */ - -/* USER CODE END 4 */ - -/** - * @brief This function is executed in case of error occurrence. - * @retval None - */ -void Error_Handler(void) -{ - /* USER CODE BEGIN Error_Handler_Debug */ - /* User can add his own implementation to report the HAL error return state */ - asm("bkpt 1"); - /* USER CODE END Error_Handler_Debug */ +void Error_Handler(void) { + asm("bkpt 1"); + while(1) {} } #ifdef USE_FULL_ASSERT /** - * @brief Reports the name of the source file and the source line number - * where the assert_param error has occurred. - * @param file: pointer to the source file name - * @param line: assert_param error line source number - * @retval None - */ -void assert_failed(uint8_t *file, uint32_t line) -{ - /* USER CODE BEGIN 6 */ - /* User can add his own implementation to report the file name and line number, - tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ - /* USER CODE END 6 */ + * @brief Reports the name of the source file and the source line number + * where the assert_param error has occurred. + * @param file: pointer to the source file name + * @param line: assert_param error line source number + * @retval None + */ +void assert_failed(uint8_t *file, uint32_t line) { + /* USER CODE BEGIN 6 */ + /* User can add his own implementation to report the file name and line number, + tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ + /* USER CODE END 6 */ } #endif /* USE_FULL_ASSERT */ - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f4/api-hal/api-hal-os-timer.h b/firmware/targets/f4/api-hal/api-hal-os-timer.h new file mode 100644 index 00000000..a1e775b3 --- /dev/null +++ b/firmware/targets/f4/api-hal/api-hal-os-timer.h @@ -0,0 +1,95 @@ +#pragma once + +#include +#include + +static inline void assert(bool value) { + if (!value) asm("bkpt 1"); +} + +// Timer used for system ticks +#define API_HAL_OS_TIMER_MAX 0xFFFF +#define API_HAL_OS_TIMER_REG_LOAD_DLY 0x1 +#define API_HAL_OS_TIMER LPTIM2 +#define API_HAL_OS_TIMER_IRQ LPTIM2_IRQn +#define API_HAL_OS_TIMER_CLOCK_INIT() \ +{ \ + LL_RCC_SetLPTIMClockSource(LL_RCC_LPTIM2_CLKSOURCE_LSE); \ + LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_LPTIM2); \ +} \ + +static inline void api_hal_os_timer_init() { + API_HAL_OS_TIMER_CLOCK_INIT(); + + LL_LPTIM_Enable(API_HAL_OS_TIMER); + while(!LL_LPTIM_IsEnabled(API_HAL_OS_TIMER)) {} + + LL_LPTIM_SetClockSource(API_HAL_OS_TIMER, LL_LPTIM_CLK_SOURCE_INTERNAL); + LL_LPTIM_SetPrescaler(API_HAL_OS_TIMER, LL_LPTIM_PRESCALER_DIV1); + LL_LPTIM_SetPolarity(API_HAL_OS_TIMER, LL_LPTIM_OUTPUT_POLARITY_REGULAR); + LL_LPTIM_SetUpdateMode(API_HAL_OS_TIMER, LL_LPTIM_UPDATE_MODE_IMMEDIATE); + LL_LPTIM_SetCounterMode(API_HAL_OS_TIMER, LL_LPTIM_COUNTER_MODE_INTERNAL); + LL_LPTIM_TrigSw(API_HAL_OS_TIMER); + LL_LPTIM_SetInput1Src(API_HAL_OS_TIMER, LL_LPTIM_INPUT1_SRC_GPIO); + LL_LPTIM_SetInput2Src(API_HAL_OS_TIMER, LL_LPTIM_INPUT2_SRC_GPIO); + + NVIC_SetPriority(API_HAL_OS_TIMER_IRQ, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 15, 0)); + NVIC_EnableIRQ(API_HAL_OS_TIMER_IRQ); +} + +static inline uint32_t api_hal_os_timer_get_cnt() { + uint32_t counter = LL_LPTIM_GetCounter(API_HAL_OS_TIMER); + uint32_t counter_shadow = LL_LPTIM_GetCounter(API_HAL_OS_TIMER); + while(counter != counter_shadow) { + counter = counter_shadow; + counter_shadow = LL_LPTIM_GetCounter(API_HAL_OS_TIMER); + } + return counter; +} + +static inline bool api_hal_os_timer_arr_is_ok() { + return LL_LPTIM_IsActiveFlag_ARROK(API_HAL_OS_TIMER); +} + +static inline uint32_t api_hal_os_timer_get_arr() { + return LL_LPTIM_GetAutoReload(API_HAL_OS_TIMER);; +} + +static inline void api_hal_os_timer_set_arr(uint32_t value) { + value &= API_HAL_OS_TIMER_MAX; + if (value != api_hal_os_timer_get_arr()) { + assert(api_hal_os_timer_arr_is_ok()); + LL_LPTIM_ClearFlag_ARROK(API_HAL_OS_TIMER); + LL_LPTIM_SetAutoReload(API_HAL_OS_TIMER, value); + } +} + +static inline bool api_hal_os_timer_cmp_is_ok() { + return LL_LPTIM_IsActiveFlag_CMPOK(API_HAL_OS_TIMER); +} + +static inline uint32_t api_hal_os_timer_get_cmp() { + return LL_LPTIM_GetCompare(API_HAL_OS_TIMER); +} + +static inline void api_hal_os_timer_set_cmp(uint32_t value) { + value &= API_HAL_OS_TIMER_MAX; + if (value != api_hal_os_timer_get_cmp()) { + assert(api_hal_os_timer_cmp_is_ok()); + LL_LPTIM_ClearFlag_CMPOK(API_HAL_OS_TIMER); + LL_LPTIM_SetCompare(API_HAL_OS_TIMER, value); + } +} + +static inline bool api_hal_os_timer_is_safe() { + uint16_t cmp = api_hal_os_timer_get_cmp(); + uint16_t cnt = api_hal_os_timer_get_cnt(); + uint16_t margin = (cmp > cnt) ? cmp - cnt : cnt - cmp; + if (margin < 8) { + return false; + } + if (!api_hal_os_timer_cmp_is_ok()) { + return false; + } + return true; +} diff --git a/firmware/targets/f4/api-hal/api-hal-os.c b/firmware/targets/f4/api-hal/api-hal-os.c new file mode 100644 index 00000000..1415183e --- /dev/null +++ b/firmware/targets/f4/api-hal/api-hal-os.c @@ -0,0 +1,169 @@ +#include +#include +#include + +#include +#include + +#define API_HAL_OS_CLK_FREQUENCY 32768 +#define API_HAL_OS_TICK_PER_SECOND 1024 +#define API_HAL_OS_CLK_PER_TICK (API_HAL_OS_CLK_FREQUENCY / API_HAL_OS_TICK_PER_SECOND) +#define API_HAL_OS_TICK_PER_EPOCH (API_HAL_OS_TIMER_MAX / API_HAL_OS_CLK_PER_TICK) +#define API_HAL_OS_MAX_SLEEP (API_HAL_OS_TICK_PER_EPOCH - 1) + +#ifdef API_HAL_OS_DEBUG +#include +#define LED_GREEN_PORT GPIOA +#define LED_GREEN_PIN LL_GPIO_PIN_2 +#endif + +typedef struct { + // Tick counters + volatile uint32_t in_sleep; + volatile uint32_t in_awake; + // Error counters + volatile uint32_t sleep_error; + volatile uint32_t awake_error; +} ApiHalOs; + +ApiHalOs api_hal_os = { + .in_sleep = 0, + .in_awake = 0, + .sleep_error = 0, + .awake_error = 0, +}; + +void api_hal_os_init() { + api_hal_os_timer_init(); + LL_DBGMCU_APB1_GRP2_FreezePeriph(LL_DBGMCU_APB1_GRP2_LPTIM2_STOP); + + LL_LPTIM_EnableIT_CMPM(API_HAL_OS_TIMER); + LL_LPTIM_EnableIT_ARRM(API_HAL_OS_TIMER); + + LL_LPTIM_SetAutoReload(API_HAL_OS_TIMER, API_HAL_OS_TIMER_MAX); + LL_LPTIM_SetCompare(API_HAL_OS_TIMER, API_HAL_OS_CLK_PER_TICK); + + LL_LPTIM_StartCounter(API_HAL_OS_TIMER, LL_LPTIM_OPERATING_MODE_CONTINUOUS); +} + +void LPTIM2_IRQHandler(void) { + // Autoreload + const bool arrm_flag = LL_LPTIM_IsActiveFlag_ARRM(API_HAL_OS_TIMER); + if(arrm_flag) { + LL_LPTIM_ClearFLAG_ARRM(API_HAL_OS_TIMER); + } + if(LL_LPTIM_IsActiveFlag_CMPM(API_HAL_OS_TIMER)) { + LL_LPTIM_ClearFLAG_CMPM(API_HAL_OS_TIMER); + + // Store important value + uint16_t cnt = api_hal_os_timer_get_cnt(); + uint16_t cmp = api_hal_os_timer_get_cmp(); + uint16_t current_tick = cnt / API_HAL_OS_CLK_PER_TICK; + uint16_t compare_tick = cmp / API_HAL_OS_CLK_PER_TICK; + + // Calculate error + // happens when HAL or other high priority IRQ takes our time + int32_t error = (int32_t)compare_tick - current_tick; + api_hal_os.awake_error += ((error>0) ? error : -error); + + // Calculate and set next tick + uint16_t next_tick = current_tick + 1; + api_hal_os_timer_set_cmp(next_tick * API_HAL_OS_CLK_PER_TICK); + + // Notify OS + api_hal_os.in_awake ++; + if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) { + xPortSysTickHandler(); + } + } +} + +static inline uint32_t api_hal_os_sleep(TickType_t expected_idle_ticks) { + // Store important value before going to sleep + const uint16_t before_cnt = api_hal_os_timer_get_cnt(); + const uint16_t before_tick = before_cnt / API_HAL_OS_CLK_PER_TICK; + + // Calculate and set next wakeup compare value + const uint16_t expected_cnt = (before_tick + expected_idle_ticks - 2) * API_HAL_OS_CLK_PER_TICK; + api_hal_os_timer_set_cmp(expected_cnt); + + HAL_SuspendTick(); + // Go to stop2 mode +#ifdef API_HAL_OS_DEBUG + LL_GPIO_SetOutputPin(LED_GREEN_PORT, LED_GREEN_PIN); +#endif + api_hal_power_deep_sleep(); +#ifdef API_HAL_OS_DEBUG + LL_GPIO_ResetOutputPin(LED_GREEN_PORT, LED_GREEN_PIN); +#endif + + HAL_ResumeTick(); + + // Spin till we are in timer safe zone + while(!api_hal_os_timer_is_safe()) {} + + // Store current counter value, calculate current tick + const uint16_t after_cnt = api_hal_os_timer_get_cnt(); + const uint16_t after_tick = after_cnt / API_HAL_OS_CLK_PER_TICK; + + // Store and clear interrupt flags + // we don't want handler to be called after renabling IRQ + bool arrm_flag = LL_LPTIM_IsActiveFlag_ARRM(API_HAL_OS_TIMER); + + // Calculate and set next wakeup compare value + const uint16_t next_cmp = (after_tick + 1) * API_HAL_OS_CLK_PER_TICK; + api_hal_os_timer_set_cmp(next_cmp); + + // Calculate ticks count spent in sleep and perform sanity checks + int32_t completed_ticks = arrm_flag ? (int32_t)before_tick - after_tick : (int32_t)after_tick - before_tick; + + return completed_ticks; +} + +void vPortSuppressTicksAndSleep(TickType_t expected_idle_ticks) { + if (!api_hal_power_deep_available()) { + return; + } + + // Limit mount of ticks to maximum that timer can count + if (expected_idle_ticks > API_HAL_OS_MAX_SLEEP) { + expected_idle_ticks = API_HAL_OS_MAX_SLEEP; + } + + // Stop IRQ handling, no one should disturb us till we finish + __disable_irq(); + + // Confirm OS that sleep is still possible + // And check if timer is in safe zone + // (8 clocks till any IRQ event or ongoing synchronization) + if (eTaskConfirmSleepModeStatus() == eAbortSleep + || !api_hal_os_timer_is_safe()) { + __enable_irq(); + return; + } + + uint32_t completed_ticks = api_hal_os_sleep(expected_idle_ticks); + assert(completed_ticks >= 0); + + // Reenable IRQ + __enable_irq(); + + // Notify system about time spent in sleep + if (completed_ticks > 0) { + api_hal_os.in_sleep += completed_ticks; + if (completed_ticks > expected_idle_ticks) { + // We are late, count error + api_hal_os.sleep_error += (completed_ticks - expected_idle_ticks); + // Freertos is not happy when we overleep + // But we are not going to tell her + vTaskStepTick(expected_idle_ticks); + } else { + vTaskStepTick(completed_ticks); + } + } +} + +void vApplicationStackOverflowHook(TaskHandle_t xTask, signed char *pcTaskName) { + asm("bkpt 1"); + while(1) {}; +} diff --git a/firmware/targets/f4/api-hal/api-hal-os.h b/firmware/targets/f4/api-hal/api-hal-os.h new file mode 100644 index 00000000..45666889 --- /dev/null +++ b/firmware/targets/f4/api-hal/api-hal-os.h @@ -0,0 +1,17 @@ +#pragma once + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Initialize OS helpers + * Configure and start tick timer + */ +void api_hal_os_init(); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/firmware/targets/f4/api-hal/api-hal-power.c b/firmware/targets/f4/api-hal/api-hal-power.c index 73b55bf3..938ec85d 100644 --- a/firmware/targets/f4/api-hal/api-hal-power.c +++ b/firmware/targets/f4/api-hal/api-hal-power.c @@ -12,6 +12,8 @@ #include #include +volatile uint32_t api_hal_power_insomnia = 0; + void HAL_RCC_CSSCallback(void) { LL_RCC_ForceBackupDomainReset(); LL_RCC_ReleaseBackupDomainReset(); @@ -24,8 +26,20 @@ void api_hal_power_init() { bq25896_init(); } +uint16_t api_hal_power_insomnia_level() { + return api_hal_power_insomnia; +} + +void api_hal_power_insomnia_enter() { + api_hal_power_insomnia++; +} + +void api_hal_power_insomnia_exit() { + api_hal_power_insomnia--; +} + bool api_hal_power_deep_available() { - return api_hal_bt_is_alive(); + return api_hal_bt_is_alive() && api_hal_power_insomnia == 0; } void api_hal_power_deep_sleep() { diff --git a/firmware/targets/f4/api-hal/api-hal-timebase-timer.h b/firmware/targets/f4/api-hal/api-hal-timebase-timer.h deleted file mode 100644 index 78922047..00000000 --- a/firmware/targets/f4/api-hal/api-hal-timebase-timer.h +++ /dev/null @@ -1,95 +0,0 @@ -#pragma once - -#include -#include - -static inline void assert(bool value) { - if (!value) asm("bkpt 1"); -} - -// Timer used for system ticks -#define API_HAL_TIMEBASE_TIMER_MAX 0xFFFF -#define API_HAL_TIMEBASE_TIMER_REG_LOAD_DLY 0x1 -#define API_HAL_TIMEBASE_TIMER LPTIM2 -#define API_HAL_TIMEBASE_TIMER_IRQ LPTIM2_IRQn -#define API_HAL_TIMEBASE_TIMER_CLOCK_INIT() \ -{ \ - LL_RCC_SetLPTIMClockSource(LL_RCC_LPTIM2_CLKSOURCE_LSE); \ - LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_LPTIM2); \ -} \ - -static inline void api_hal_timebase_timer_init() { - API_HAL_TIMEBASE_TIMER_CLOCK_INIT(); - - LL_LPTIM_Enable(API_HAL_TIMEBASE_TIMER); - while(!LL_LPTIM_IsEnabled(API_HAL_TIMEBASE_TIMER)) {} - - LL_LPTIM_SetClockSource(API_HAL_TIMEBASE_TIMER, LL_LPTIM_CLK_SOURCE_INTERNAL); - LL_LPTIM_SetPrescaler(API_HAL_TIMEBASE_TIMER, LL_LPTIM_PRESCALER_DIV1); - LL_LPTIM_SetPolarity(API_HAL_TIMEBASE_TIMER, LL_LPTIM_OUTPUT_POLARITY_REGULAR); - LL_LPTIM_SetUpdateMode(API_HAL_TIMEBASE_TIMER, LL_LPTIM_UPDATE_MODE_IMMEDIATE); - LL_LPTIM_SetCounterMode(API_HAL_TIMEBASE_TIMER, LL_LPTIM_COUNTER_MODE_INTERNAL); - LL_LPTIM_TrigSw(API_HAL_TIMEBASE_TIMER); - LL_LPTIM_SetInput1Src(API_HAL_TIMEBASE_TIMER, LL_LPTIM_INPUT1_SRC_GPIO); - LL_LPTIM_SetInput2Src(API_HAL_TIMEBASE_TIMER, LL_LPTIM_INPUT2_SRC_GPIO); - - NVIC_SetPriority(API_HAL_TIMEBASE_TIMER_IRQ, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 15, 0)); - NVIC_EnableIRQ(API_HAL_TIMEBASE_TIMER_IRQ); -} - -static inline uint32_t api_hal_timebase_timer_get_cnt() { - uint32_t counter = LL_LPTIM_GetCounter(API_HAL_TIMEBASE_TIMER); - uint32_t counter_shadow = LL_LPTIM_GetCounter(API_HAL_TIMEBASE_TIMER); - while(counter != counter_shadow) { - counter = counter_shadow; - counter_shadow = LL_LPTIM_GetCounter(API_HAL_TIMEBASE_TIMER); - } - return counter; -} - -static inline bool api_hal_timebase_timer_arr_is_ok() { - return LL_LPTIM_IsActiveFlag_ARROK(API_HAL_TIMEBASE_TIMER); -} - -static inline uint32_t api_hal_timebase_timer_get_arr() { - return LL_LPTIM_GetAutoReload(API_HAL_TIMEBASE_TIMER);; -} - -static inline void api_hal_timebase_timer_set_arr(uint32_t value) { - value &= API_HAL_TIMEBASE_TIMER_MAX; - if (value != api_hal_timebase_timer_get_arr()) { - assert(api_hal_timebase_timer_arr_is_ok()); - LL_LPTIM_ClearFlag_ARROK(API_HAL_TIMEBASE_TIMER); - LL_LPTIM_SetAutoReload(API_HAL_TIMEBASE_TIMER, value); - } -} - -static inline bool api_hal_timebase_timer_cmp_is_ok() { - return LL_LPTIM_IsActiveFlag_CMPOK(API_HAL_TIMEBASE_TIMER); -} - -static inline uint32_t api_hal_timebase_timer_get_cmp() { - return LL_LPTIM_GetCompare(API_HAL_TIMEBASE_TIMER); -} - -static inline void api_hal_timebase_timer_set_cmp(uint32_t value) { - value &= API_HAL_TIMEBASE_TIMER_MAX; - if (value != api_hal_timebase_timer_get_cmp()) { - assert(api_hal_timebase_timer_cmp_is_ok()); - LL_LPTIM_ClearFlag_CMPOK(API_HAL_TIMEBASE_TIMER); - LL_LPTIM_SetCompare(API_HAL_TIMEBASE_TIMER, value); - } -} - -static inline bool api_hal_timebase_timer_is_safe() { - uint16_t cmp = api_hal_timebase_timer_get_cmp(); - uint16_t cnt = api_hal_timebase_timer_get_cnt(); - uint16_t margin = (cmp > cnt) ? cmp - cnt : cnt - cmp; - if (margin < 8) { - return false; - } - if (!api_hal_timebase_timer_cmp_is_ok()) { - return false; - } - return true; -} diff --git a/firmware/targets/f4/api-hal/api-hal-timebase.c b/firmware/targets/f4/api-hal/api-hal-timebase.c deleted file mode 100644 index 3e35b34a..00000000 --- a/firmware/targets/f4/api-hal/api-hal-timebase.c +++ /dev/null @@ -1,179 +0,0 @@ -#include -#include -#include - -#include -#include - -#define API_HAL_TIMEBASE_CLK_FREQUENCY 32768 -#define API_HAL_TIMEBASE_TICK_PER_SECOND 1024 -#define API_HAL_TIMEBASE_CLK_PER_TICK (API_HAL_TIMEBASE_CLK_FREQUENCY / API_HAL_TIMEBASE_TICK_PER_SECOND) -#define API_HAL_TIMEBASE_TICK_PER_EPOCH (API_HAL_TIMEBASE_TIMER_MAX / API_HAL_TIMEBASE_CLK_PER_TICK) -#define API_HAL_TIMEBASE_MAX_SLEEP (API_HAL_TIMEBASE_TICK_PER_EPOCH - 1) - -#ifdef API_HAL_TIMEBASE_DEBUG -#include -#define LED_GREEN_PORT GPIOA -#define LED_GREEN_PIN LL_GPIO_PIN_2 -#endif - -typedef struct { - // Sleep control - volatile uint16_t insomnia; - // Tick counters - volatile uint32_t in_sleep; - volatile uint32_t in_awake; - // Error counters - volatile uint32_t sleep_error; - volatile uint32_t awake_error; -} ApiHalTimbase; - -ApiHalTimbase api_hal_timebase = { - .insomnia = 0, - .in_sleep = 0, - .in_awake = 0, - .sleep_error = 0, - .awake_error = 0, -}; - -void api_hal_timebase_init() { - api_hal_timebase_timer_init(); - LL_DBGMCU_APB1_GRP2_FreezePeriph(LL_DBGMCU_APB1_GRP2_LPTIM2_STOP); - - LL_LPTIM_EnableIT_CMPM(API_HAL_TIMEBASE_TIMER); - LL_LPTIM_EnableIT_ARRM(API_HAL_TIMEBASE_TIMER); - - LL_LPTIM_SetAutoReload(API_HAL_TIMEBASE_TIMER, API_HAL_TIMEBASE_TIMER_MAX); - LL_LPTIM_SetCompare(API_HAL_TIMEBASE_TIMER, API_HAL_TIMEBASE_CLK_PER_TICK); - - LL_LPTIM_StartCounter(API_HAL_TIMEBASE_TIMER, LL_LPTIM_OPERATING_MODE_CONTINUOUS); -} - -uint16_t api_hal_timebase_insomnia_level() { - return api_hal_timebase.insomnia; -} - -void api_hal_timebase_insomnia_enter() { - api_hal_timebase.insomnia++; -} - -void api_hal_timebase_insomnia_exit() { - api_hal_timebase.insomnia--; -} - -void LPTIM2_IRQHandler(void) { - // Autoreload - const bool arrm_flag = LL_LPTIM_IsActiveFlag_ARRM(API_HAL_TIMEBASE_TIMER); - if(arrm_flag) { - LL_LPTIM_ClearFLAG_ARRM(API_HAL_TIMEBASE_TIMER); - } - if(LL_LPTIM_IsActiveFlag_CMPM(API_HAL_TIMEBASE_TIMER)) { - LL_LPTIM_ClearFLAG_CMPM(API_HAL_TIMEBASE_TIMER); - - // Store important value - uint16_t cnt = api_hal_timebase_timer_get_cnt(); - uint16_t cmp = api_hal_timebase_timer_get_cmp(); - uint16_t current_tick = cnt / API_HAL_TIMEBASE_CLK_PER_TICK; - uint16_t compare_tick = cmp / API_HAL_TIMEBASE_CLK_PER_TICK; - - // Calculate error - // happens when HAL or other high priority IRQ takes our time - int32_t error = (int32_t)compare_tick - current_tick; - api_hal_timebase.awake_error += ((error>0) ? error : -error); - - // Calculate and set next tick - uint16_t next_tick = current_tick + 1; - api_hal_timebase_timer_set_cmp(next_tick * API_HAL_TIMEBASE_CLK_PER_TICK); - - // Notify OS - api_hal_timebase.in_awake ++; - if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) { - xPortSysTickHandler(); - } - } -} - -static inline uint32_t api_hal_timebase_sleep(TickType_t expected_idle_ticks) { - // Store important value before going to sleep - const uint16_t before_cnt = api_hal_timebase_timer_get_cnt(); - const uint16_t before_tick = before_cnt / API_HAL_TIMEBASE_CLK_PER_TICK; - - // Calculate and set next wakeup compare value - const uint16_t expected_cnt = (before_tick + expected_idle_ticks - 2) * API_HAL_TIMEBASE_CLK_PER_TICK; - api_hal_timebase_timer_set_cmp(expected_cnt); - - HAL_SuspendTick(); - // Go to stop2 mode -#ifdef API_HAL_TIMEBASE_DEBUG - LL_GPIO_SetOutputPin(LED_GREEN_PORT, LED_GREEN_PIN); -#endif - api_hal_power_deep_sleep(); -#ifdef API_HAL_TIMEBASE_DEBUG - LL_GPIO_ResetOutputPin(LED_GREEN_PORT, LED_GREEN_PIN); -#endif - - HAL_ResumeTick(); - - // Spin till we are in timer safe zone - while(!api_hal_timebase_timer_is_safe()) {} - - // Store current counter value, calculate current tick - const uint16_t after_cnt = api_hal_timebase_timer_get_cnt(); - const uint16_t after_tick = after_cnt / API_HAL_TIMEBASE_CLK_PER_TICK; - - // Store and clear interrupt flags - // we don't want handler to be called after renabling IRQ - bool arrm_flag = LL_LPTIM_IsActiveFlag_ARRM(API_HAL_TIMEBASE_TIMER); - - // Calculate and set next wakeup compare value - const uint16_t next_cmp = (after_tick + 1) * API_HAL_TIMEBASE_CLK_PER_TICK; - api_hal_timebase_timer_set_cmp(next_cmp); - - // Calculate ticks count spent in sleep and perform sanity checks - int32_t completed_ticks = arrm_flag ? (int32_t)before_tick - after_tick : (int32_t)after_tick - before_tick; - - return completed_ticks; -} - -void vPortSuppressTicksAndSleep(TickType_t expected_idle_ticks) { - if (!api_hal_power_deep_available() || api_hal_timebase.insomnia) { - return; - } - - // Limit mount of ticks to maximum that timer can count - if (expected_idle_ticks > API_HAL_TIMEBASE_MAX_SLEEP) { - expected_idle_ticks = API_HAL_TIMEBASE_MAX_SLEEP; - } - - // Stop IRQ handling, no one should disturb us till we finish - __disable_irq(); - - // Confirm OS that sleep is still possible - // And check if timer is in safe zone - // (8 clocks till any IRQ event or ongoing synchronization) - if (eTaskConfirmSleepModeStatus() == eAbortSleep - || !api_hal_timebase_timer_is_safe()) { - __enable_irq(); - return; - } - - uint32_t completed_ticks = api_hal_timebase_sleep(expected_idle_ticks); - assert(completed_ticks >= 0); - - // Reenable IRQ - __enable_irq(); - - // Notify system about time spent in sleep - if (completed_ticks > 0) { - api_hal_timebase.in_sleep += completed_ticks; - if (completed_ticks > expected_idle_ticks) { - // We are late, count error - api_hal_timebase.sleep_error += (completed_ticks - expected_idle_ticks); - // Freertos is not happy when we overleep - // But we are not going to tell her - vTaskStepTick(expected_idle_ticks); - } else { - vTaskStepTick(completed_ticks); - } - } -} diff --git a/firmware/targets/f4/api-hal/api-hal-timebase.h b/firmware/targets/f4/api-hal/api-hal-timebase.h deleted file mode 100644 index 18bffde7..00000000 --- a/firmware/targets/f4/api-hal/api-hal-timebase.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#include - - -#ifdef __cplusplus -extern "C" { -#endif - -/* Initialize timebase - * Configure and start tick timer - */ -void api_hal_timebase_init(); - -/* Get current insomnia level - * @return insomnia level: 0 - no insomnia, >0 - insomnia, bearer count. - */ -uint16_t api_hal_timebase_insomnia_level(); - -/* Enter insomnia mode - * Prevents device from going to sleep - * @warning Internally increases insomnia level - * Must be paired with api_hal_timebase_insomnia_exit - */ -void api_hal_timebase_insomnia_enter(); - -/* Exit insomnia mode - * Allow device to go to sleep - * @warning Internally decreases insomnia level. - * Must be paired with api_hal_timebase_insomnia_enter - */ -void api_hal_timebase_insomnia_exit(); - - -#ifdef __cplusplus -} -#endif \ No newline at end of file diff --git a/firmware/targets/f4/api-hal/api-hal.c b/firmware/targets/f4/api-hal/api-hal.c index ccd55f75..2de80322 100644 --- a/firmware/targets/f4/api-hal/api-hal.c +++ b/firmware/targets/f4/api-hal/api-hal.c @@ -1,7 +1,7 @@ #include void api_hal_init() { - api_hal_timebase_init(); + api_hal_os_init(); api_hal_vcp_init(); api_hal_spi_init(); } \ No newline at end of file diff --git a/firmware/targets/f4/ble-glue/app_ble.c b/firmware/targets/f4/ble-glue/app_ble.c index 910a5a28..0b02e5b6 100644 --- a/firmware/targets/f4/ble-glue/app_ble.c +++ b/firmware/targets/f4/ble-glue/app_ble.c @@ -219,7 +219,7 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification( void *pckt ) } /* restart advertising */ Adv_Request(APP_BLE_FAST_ADV); - api_hal_timebase_insomnia_exit(); + api_hal_power_insomnia_exit(); } break; /* EVT_DISCONN_COMPLETE */ @@ -268,7 +268,7 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification( void *pckt ) break; case EVT_LE_CONN_COMPLETE: { - api_hal_timebase_insomnia_enter(); + api_hal_power_insomnia_enter(); hci_le_connection_complete_event_rp0 *connection_complete_event; /** diff --git a/firmware/targets/f4/ble-glue/app_entry.c b/firmware/targets/f4/ble-glue/app_entry.c index 4b12d474..394669b5 100644 --- a/firmware/targets/f4/ble-glue/app_entry.c +++ b/firmware/targets/f4/ble-glue/app_entry.c @@ -52,7 +52,7 @@ void APPE_Init() { HW_TS_Init(hw_ts_InitMode_Full, &hrtc); /**< Initialize the TimerServer */ // APPD_Init(); - api_hal_timebase_insomnia_enter(); + api_hal_power_insomnia_enter(); appe_Tl_Init(); /* Initialize all transport layers */ @@ -144,7 +144,7 @@ static void APPE_SysUserEvtRx( void * pPayload ) { } else { ble_glue_status = BleGlueStatusBroken; } - api_hal_timebase_insomnia_exit(); + api_hal_power_insomnia_exit(); } /************************************************************* diff --git a/firmware/targets/f4/target.mk b/firmware/targets/f4/target.mk index 620c2f89..5dabb134 100644 --- a/firmware/targets/f4/target.mk +++ b/firmware/targets/f4/target.mk @@ -14,9 +14,9 @@ FLASH_ADDRESS = 0x08000000 CFLAGS += -DNO_BOOTLOADER endif -API_HAL_TIMEBASE_DEBUG ?= 0 -ifeq ($(API_HAL_TIMEBASE_DEBUG), 1) -CFLAGS += -DAPI_HAL_TIMEBASE_DEBUG +API_HAL_OS_DEBUG ?= 0 +ifeq ($(API_HAL_OS_DEBUG), 1) +CFLAGS += -DAPI_HAL_OS_DEBUG endif OPENOCD_OPTS = -f interface/stlink.cfg -c "transport select hla_swd" -f ../debug/stm32wbx.cfg -c "stm32wbx.cpu configure -rtos auto" -c "init" diff --git a/lib/app-template/app-template.cpp b/lib/app-template/app-template.cpp index d085f0c5..7ae780a0 100644 --- a/lib/app-template/app-template.cpp +++ b/lib/app-template/app-template.cpp @@ -44,12 +44,12 @@ public: // with template variables class AppExample : public AppTemplate { public: - void run(); + uint8_t run(); void render(Canvas* canvas); }; // start app -void AppExample::run() { +uint8_t AppExample::run() { // here we dont need to acquire or release state // because before we call app_ready our application is "single threaded" state.example_data = 12; @@ -67,7 +67,7 @@ void AppExample::run() { // press events if(event.value.input.type == InputTypeShort && event.value.input.key == InputKeyBack) { printf("bye!\n"); - exit(); + return exit(); } if(event.value.input.type == InputTypeShort && event.value.input.key == InputKeyUp) { @@ -95,7 +95,7 @@ void AppExample::render(Canvas* canvas) { } // app enter function -extern "C" void app_cpp_example(void* p) { +extern "C" uint8_t app_cpp_example(void* p) { AppExample* app = new AppExample(); - app->run(); + return app->run(); } diff --git a/lib/app-template/app-template.h b/lib/app-template/app-template.h index ff9b9f3d..6f03e8aa 100644 --- a/lib/app-template/app-template.h +++ b/lib/app-template/app-template.h @@ -22,7 +22,7 @@ public: void release_state(void); bool get_event(TEvent* event, uint32_t timeout); void app_ready(void); - void exit(void); + uint8_t exit(void); void update_gui(void); }; @@ -34,7 +34,7 @@ template AppTemplate::AppTemplate() // TODO: use plain os mutex? if(!init_mutex(&state_mutex, &state, sizeof(TState))) { printf("cannot create mutex\n"); - furiac_exit(); + furi_check(0); } // open gui @@ -100,10 +100,10 @@ template void AppTemplate::app_read gui_add_view_port(gui, view_port, GuiLayerFullscreen); } -template void AppTemplate::exit(void) { +template uint8_t AppTemplate::exit(void) { // TODO remove all view_ports create by app view_port_enabled_set(view_port, false); - osThreadExit(); + return 255; } template void AppTemplate::update_gui(void) {