[FL-140] Core api dynamic records (#296)
* SYSTEM: tickless mode with deep sleep. * Move FreeRTOS ticks to lptim2 * API: move all sumbodules init routines to one place. Timebase: working lptim2 at tick source. * API Timebase: lp-timer routines, timer access safe zones prediction and synchronization. FreeRTOS: adjust configuration for tickless mode. * NFC: support for tickless mode. * API Timebase: improve tick error handling in IRQ. Apploader: use insomnia mode to run applications. * BLE: prevent sleep while core2 starting * HAL: nap while in insomnia mode * init records work * try to implement record delete * tests and flapp * flapp subsystem * new core functions to get app stat, simplify core code * fix thread termination * add strdup to core * fix tests * Refactoring: remove all unusued parts, update API usage, aggreagate API sources and headers, new record storage * Refactoring: update furi record api usage, cleanup code * Fix broken merge for freertos apps * Core, Target: fix compilation warnings * Drop firmware target local * HAL Timebase, Power, Clock: semaphore guarded access to clock and power modes, better sleep mode. * SD-Filesystem: wait for all deps to arrive before adding widget. Core, BLE: disable debug dump to serial. * delete old app example-ipc * delete old app fatfs list * fix strobe app, add input header * delete old display driver * comment old app qr-code * fix sd-card test, add forced widget update * remove unused new core test * increase heap to 128k * comment and assert old core tests * fix syntax Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
This commit is contained in:
		
							parent
							
								
									6c4983c6b6
								
							
						
					
					
						commit
						8f9b2513ff
					
				
							
								
								
									
										4
									
								
								.github/CODEOWNERS
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.github/CODEOWNERS
									
									
									
									
										vendored
									
									
								
							| @ -19,10 +19,6 @@ firmware/targets/f4/api-hal/api-hal-boot.c @skotopes | ||||
| 
 | ||||
| debug/** @skotopes | ||||
| 
 | ||||
| # local target | ||||
| 
 | ||||
| firmware/targets/local/** @glitchcore | ||||
| 
 | ||||
| # BLE | ||||
| 
 | ||||
| firmware/targets/f4/ble-glue/** @skotopes | ||||
|  | ||||
							
								
								
									
										10
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							| @ -32,16 +32,6 @@ jobs: | ||||
|         with: | ||||
|           run: /syntax_check.sh | ||||
| 
 | ||||
|       - name: Build local testing firmware in docker | ||||
|         uses: ./.github/actions/docker | ||||
|         with: | ||||
|           run: make -C firmware TARGET=local | ||||
| 
 | ||||
|       - name: Run local tests | ||||
|         uses: ./.github/actions/docker | ||||
|         with: | ||||
|           run: make -C firmware TARGET=local APP_TEST=1 run | ||||
| 
 | ||||
|       - name: Build F4 bootloader in docker | ||||
|         uses: ./.github/actions/docker | ||||
|         with: | ||||
|  | ||||
| @ -25,14 +25,7 @@ Flipper Zero's firmware consists of two components: Bootloader and main firmware | ||||
| 
 | ||||
| ## Build from source | ||||
| 
 | ||||
| You can run firmware locally (with HAL stub): | ||||
| 
 | ||||
| * `docker-compose exec dev make -C firmware TARGET=local APP_TEST=1 run` for running tests | ||||
| * `docker-compose exec dev make -C firmware TARGET=local APP_*=1 run` for running examples (see `applications/applications.mk` for list of applications/examples) | ||||
| 
 | ||||
| Or on your flipper: | ||||
| 
 | ||||
| `docker-compose exec dev make -C firmware TARGET=f4 APP_*=1 flash` for build and flash dev board (see `applications/applications.mk` for list of applications/examples) | ||||
| `docker-compose exec dev make -C firmware TARGET=f4 APP_RELEASE=1 flash` for build and flash dev board (see `applications/applications.mk` for list of applications/examples) | ||||
| 
 | ||||
| # Links | ||||
| * Task tracker: [Jira](https://flipperzero.atlassian.net/) | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| #include "flipper_v2.h" | ||||
| #include <furi.h> | ||||
| #include <cli/cli.h> | ||||
| #include <gui/gui.h> | ||||
| #include "menu/menu.h" | ||||
| @ -8,14 +8,15 @@ | ||||
| #include <api-hal.h> | ||||
| 
 | ||||
| typedef struct { | ||||
|     FuriApp* handler; | ||||
|     osThreadAttr_t app_thread_attr; | ||||
|     osThreadId_t app_thread_id; | ||||
|     Widget* widget; | ||||
|     const FlipperStartupApp* current_app; | ||||
|     const FuriApplication* current_app; | ||||
| } AppLoaderState; | ||||
| 
 | ||||
| typedef struct { | ||||
|     AppLoaderState* state; | ||||
|     const FlipperStartupApp* app; | ||||
|     const FuriApplication* app; | ||||
| } AppLoaderContext; | ||||
| 
 | ||||
| // TODO add mutex for contex
 | ||||
| @ -36,7 +37,7 @@ static void input_callback(InputEvent* input_event, void* _ctx) { | ||||
|     AppLoaderState* ctx = (AppLoaderState*)_ctx; | ||||
| 
 | ||||
|     if(input_event->state && input_event->input == InputBack) { | ||||
|         furiac_kill(ctx->handler); | ||||
|         osThreadTerminate(ctx->app_thread_id); | ||||
|         widget_enabled_set(ctx->widget, false); | ||||
|         api_hal_timebase_insomnia_exit(); | ||||
|     } | ||||
| @ -54,7 +55,16 @@ static void handle_menu(void* _ctx) { | ||||
|     api_hal_timebase_insomnia_enter(); | ||||
| 
 | ||||
|     ctx->state->current_app = ctx->app; | ||||
|     ctx->state->handler = furiac_start(ctx->app->app, ctx->app->name, NULL); | ||||
|     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 = 1024; | ||||
|     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); | ||||
| } | ||||
| 
 | ||||
| static void handle_cli(string_t args, void* _ctx) { | ||||
| @ -65,13 +75,22 @@ static void handle_cli(string_t args, void* _ctx) { | ||||
|     cli_print("Starting furi application\r\n"); | ||||
| 
 | ||||
|     ctx->state->current_app = ctx->app; | ||||
|     ctx->state->handler = furiac_start(ctx->app->app, ctx->app->name, NULL); | ||||
|     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 = 1024; | ||||
|     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); | ||||
| 
 | ||||
|     cli_print("Press any key to kill application"); | ||||
| 
 | ||||
|     char c; | ||||
|     cli_read(&c, 1); | ||||
|     furiac_kill(ctx->state->handler); | ||||
|     osThreadTerminate(ctx->state->app_thread_id); | ||||
| } | ||||
| 
 | ||||
| void app_loader(void* p) { | ||||
| @ -79,37 +98,23 @@ void app_loader(void* p) { | ||||
|     furi_check(self_id); | ||||
| 
 | ||||
|     AppLoaderState state; | ||||
|     state.handler = NULL; | ||||
|     state.app_thread_id = NULL; | ||||
| 
 | ||||
|     state.widget = widget_alloc(); | ||||
|     widget_enabled_set(state.widget, false); | ||||
|     widget_draw_callback_set(state.widget, render_callback, &state); | ||||
|     widget_input_callback_set(state.widget, input_callback, &state); | ||||
| 
 | ||||
|     ValueMutex* menu_mutex = furi_open("menu"); | ||||
|     if(menu_mutex == NULL) { | ||||
|         printf("menu is not available\n"); | ||||
|         furiac_exit(NULL); | ||||
|     } | ||||
|     ValueMutex* menu_mutex = furi_record_open("menu"); | ||||
|     Cli* cli = furi_record_open("cli"); | ||||
|     Gui* gui = furi_record_open("gui"); | ||||
| 
 | ||||
|     Cli* cli = furi_open("cli"); | ||||
| 
 | ||||
|     // Open GUI and register widget
 | ||||
|     Gui* gui = furi_open("gui"); | ||||
|     if(gui == NULL) { | ||||
|         printf("gui is not available\n"); | ||||
|         furiac_exit(NULL); | ||||
|     } | ||||
|     gui_add_widget(gui, state.widget, GuiLayerFullscreen); | ||||
| 
 | ||||
|     // FURI startup
 | ||||
|     const size_t flipper_app_count = sizeof(FLIPPER_APPS) / sizeof(FLIPPER_APPS[0]); | ||||
|     const size_t flipper_plugins_count = sizeof(FLIPPER_PLUGINS) / sizeof(FLIPPER_PLUGINS[0]); | ||||
| 
 | ||||
|     // Main menu
 | ||||
|     with_value_mutex( | ||||
|         menu_mutex, (Menu * menu) { | ||||
|             for(size_t i = 0; i < flipper_app_count; i++) { | ||||
|             for(size_t i = 0; i < FLIPPER_APPS_size(); i++) { | ||||
|                 AppLoaderContext* ctx = furi_alloc(sizeof(AppLoaderContext)); | ||||
|                 ctx->state = &state; | ||||
|                 ctx->app = &FLIPPER_APPS[i]; | ||||
| @ -123,13 +128,11 @@ void app_loader(void* p) { | ||||
|                         ctx)); | ||||
| 
 | ||||
|                 // Add cli command
 | ||||
|                 if(cli) { | ||||
|                     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); | ||||
|                     string_clear(cli_name); | ||||
|                 } | ||||
|                 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); | ||||
|                 string_clear(cli_name); | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
| @ -157,7 +160,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_count; i++) { | ||||
|             for(size_t i = 0; i < FLIPPER_PLUGINS_size(); i++) { | ||||
|                 AppLoaderContext* ctx = furi_alloc(sizeof(AppLoaderContext)); | ||||
|                 ctx->state = &state; | ||||
|                 ctx->app = &FLIPPER_PLUGINS[i]; | ||||
| @ -171,13 +174,11 @@ void app_loader(void* p) { | ||||
|                         ctx)); | ||||
| 
 | ||||
|                 // Add cli command
 | ||||
|                 if(cli) { | ||||
|                     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); | ||||
|                     string_clear(cli_name); | ||||
|                 } | ||||
|                 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); | ||||
|                 string_clear(cli_name); | ||||
|             } | ||||
| 
 | ||||
|             menu_item_add(menu, menu_plugins); | ||||
| @ -186,4 +187,4 @@ void app_loader(void* p) { | ||||
|     printf("[app loader] start\n"); | ||||
| 
 | ||||
|     osThreadSuspend(self_id); | ||||
| } | ||||
| } | ||||
|  | ||||
							
								
								
									
										220
									
								
								applications/applications.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										220
									
								
								applications/applications.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,220 @@ | ||||
| #include "applications.h" | ||||
| 
 | ||||
| #ifdef APP_TEST | ||||
| void flipper_test_app(void* p); | ||||
| #endif | ||||
| 
 | ||||
| void application_blink(void* p); | ||||
| void application_uart_write(void* p); | ||||
| void application_ipc_display(void* p); | ||||
| void application_ipc_widget(void* p); | ||||
| void application_input_dump(void* p); | ||||
| void display_u8g2(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); | ||||
| 
 | ||||
| const FuriApplication FLIPPER_SERVICES[] = { | ||||
| #ifdef APP_DISPLAY | ||||
|     {.app = display_u8g2, .name = "display_u8g2", .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_CLI | ||||
|     {.app = cli_task, .name = "cli_task", .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_EXAMPLE_BLINK | ||||
|     {.app = application_blink, .name = "blink", .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_INPUT | ||||
|     {.app = input_task, .name = "input_task", .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_EXAMPLE_INPUT_DUMP | ||||
|     {.app = application_input_dump, .name = "input dump", .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_GUI | ||||
|     {.app = backlight_control, .name = "backlight_control", .icon = A_Plugins_14}, | ||||
|     {.app = gui_task, .name = "gui_task", .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_MENU | ||||
|     {.app = menu_task, .name = "menu_task", .icon = A_Plugins_14}, | ||||
|     {.app = app_loader, .name = "app_loader", .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_SD_FILESYSTEM | ||||
|     {.app = sd_filesystem, .name = "sd_filesystem", .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_DOLPHIN | ||||
|     {.app = dolphin_task, .name = "dolphin_task", .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_POWER | ||||
|     {.app = power_task, .name = "power_task", .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_BT | ||||
|     {.app = bt_task, .name = "bt_task", .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_CC1101 | ||||
|     {.app = cc1101_workaround, .name = "cc1101 workaround", .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_LF_RFID | ||||
|     {.app = lf_rfid_workaround, .name = "lf rfid workaround", .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_IRDA | ||||
|     {.app = irda, .name = "irda", .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_NFC | ||||
|     {.app = nfc_task, .name = "nfc_task", .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_TEST | ||||
|     {.app = flipper_test_app, .name = "test app", .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_EXAMPLE_IPC | ||||
|     {.app = application_ipc_display, .name = "ipc display", .icon = A_Plugins_14}, | ||||
|     {.app = application_ipc_widget, .name = "ipc widget", .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_EXAMPLE_QRCODE | ||||
|     {.app = u8g2_qrcode, .name = "u8g2_qrcode", .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_EXAMPLE_FATFS | ||||
|     {.app = fatfs_list, .name = "fatfs_list", .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_EXAMPLE_DISPLAY | ||||
|     {.app = u8g2_example, .name = "u8g2_example", .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_SPEAKER_DEMO | ||||
|     {.app = coreglitch_demo_0, .name = "coreglitch_demo_0", .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_SD_TEST | ||||
|     {.app = sd_card_test, .name = "sd_card_test", .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_MUSIC_PLAYER | ||||
|     {.app = music_player, .name = "music player", .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_IBUTTON | ||||
|     {.app = app_ibutton, .name = "ibutton", .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_GPIO_DEMO | ||||
|     {.app = app_gpio_test, .name = "gpio test", .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_FLOOPPER_BLOOPPER | ||||
|     {.app = floopper_bloopper, .name = "Floopper Bloopper", .icon = A_Games_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_SDNFC | ||||
|     {.app = sdnfc, .name = "sdnfc", .icon = A_Plugins_14}, | ||||
| #endif | ||||
| }; | ||||
| 
 | ||||
| size_t FLIPPER_SERVICES_size() { | ||||
|     return sizeof(FLIPPER_SERVICES) / sizeof(FuriApplication); | ||||
| } | ||||
| 
 | ||||
| // Main menu APP
 | ||||
| const FuriApplication FLIPPER_APPS[] = { | ||||
| #ifdef BUILD_CC1101 | ||||
|     {.app = cc1101_workaround, .name = "Sub-1 GHz", .icon = A_Sub1ghz_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef BUILD_LF_RFID | ||||
|     {.app = lf_rfid_workaround, .name = "125 kHz RFID", .icon = A_125khz_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef BUILD_IRDA | ||||
|     {.app = irda, .name = "Infrared", .icon = A_Infrared_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef BUILD_IBUTTON | ||||
|     {.app = app_ibutton, .name = "iButton", .icon = A_iButton_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef BUILD_GPIO_DEMO | ||||
|     {.app = app_gpio_test, .name = "GPIO", .icon = A_GPIO_14}, | ||||
| #endif | ||||
| }; | ||||
| 
 | ||||
| size_t FLIPPER_APPS_size() { | ||||
|     return sizeof(FLIPPER_APPS) / sizeof(FuriApplication); | ||||
| } | ||||
| 
 | ||||
| // Plugin menu
 | ||||
| const FuriApplication FLIPPER_PLUGINS[] = { | ||||
| #ifdef BUILD_EXAMPLE_BLINK | ||||
|     {.app = application_blink, .name = "blink", .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef BUILD_EXAMPLE_INPUT_DUMP | ||||
|     {.app = application_input_dump, .name = "input dump", .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef BUILD_SPEAKER_DEMO | ||||
|     {.app = coreglitch_demo_0, .name = "coreglitch_demo_0", .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef BUILD_SD_TEST | ||||
|     {.app = sd_card_test, .name = "sd_card_test", .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef BUILD_VIBRO_DEMO | ||||
|     {.app = application_vibro, .name = "application_vibro", .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef BUILD_MUSIC_PLAYER | ||||
|     {.app = music_player, .name = "music player", .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef BUILD_FLOOPPER_BLOOPPER | ||||
|     {.app = floopper_bloopper, .name = "Floopper Bloopper", .icon = A_Games_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef BUILD_SDNFC | ||||
|     {.app = sdnfc, .name = "sdnfc", .icon = A_Plugins_14}, | ||||
| #endif | ||||
| }; | ||||
| 
 | ||||
| size_t FLIPPER_PLUGINS_size() { | ||||
|     return sizeof(FLIPPER_PLUGINS) / sizeof(FuriApplication); | ||||
| } | ||||
| @ -1,296 +1,21 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include "flipper.h" | ||||
| #include <furi.h> | ||||
| #include <assets_icons.h> | ||||
| 
 | ||||
| #ifdef APP_TEST | ||||
| void flipper_test_app(void* p); | ||||
| #endif | ||||
| typedef void (*FlipperApplication)(void*); | ||||
| 
 | ||||
| void application_blink(void* p); | ||||
| void application_uart_write(void* p); | ||||
| void application_ipc_display(void* p); | ||||
| void application_ipc_widget(void* p); | ||||
| void application_input_dump(void* p); | ||||
| typedef struct { | ||||
|     const FlipperApplication app; | ||||
|     const char* name; | ||||
|     const IconName icon; | ||||
| } FuriApplication; | ||||
| 
 | ||||
| void display_u8g2(void* p); | ||||
| extern const FuriApplication FLIPPER_SERVICES[]; | ||||
| size_t FLIPPER_SERVICES_size(); | ||||
| 
 | ||||
| void u8g2_example(void* p); | ||||
| extern const FuriApplication FLIPPER_APPS[]; | ||||
| size_t FLIPPER_APPS_size(); | ||||
| 
 | ||||
| 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); | ||||
| 
 | ||||
| const FlipperStartupApp FLIPPER_STARTUP[] = { | ||||
| #ifdef APP_DISPLAY | ||||
|     {.app = display_u8g2, .name = "display_u8g2", .libs = {0}, .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_CLI | ||||
|     {.app = cli_task, .name = "cli_task", .libs = {0}, .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_EXAMPLE_BLINK | ||||
|     {.app = application_blink, | ||||
|      .name = "blink", | ||||
|      .libs = {1, FURI_LIB{"input_task"}}, | ||||
|      .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_INPUT | ||||
|     {.app = input_task, .name = "input_task", .libs = {0}, .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_EXAMPLE_INPUT_DUMP | ||||
|     {.app = application_input_dump, | ||||
|      .name = "input dump", | ||||
|      .libs = {1, FURI_LIB{"input_task"}}, | ||||
|      .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_GUI | ||||
|     {.app = backlight_control, | ||||
|      .name = "backlight_control", | ||||
|      .libs = {1, FURI_LIB{"input_task"}}, | ||||
|      .icon = A_Plugins_14}, | ||||
|     {.app = gui_task, .name = "gui_task", .libs = {0}, .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_MENU | ||||
|     {.app = menu_task, | ||||
|      .name = "menu_task", | ||||
|      .libs = {1, FURI_LIB{"gui_task"}}, | ||||
|      .icon = A_Plugins_14}, | ||||
|     {.app = app_loader, | ||||
|      .name = "app_loader", | ||||
|      .libs = {2, FURI_LIB{"menu_task", "cli_task"}}, | ||||
|      .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_SD_FILESYSTEM | ||||
|     {.app = sd_filesystem, | ||||
|      .name = "sd_filesystem", | ||||
|      .libs = {1, FURI_LIB{"menu_task"}}, | ||||
|      .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_DOLPHIN | ||||
|     {.app = dolphin_task, | ||||
|      .name = "dolphin_task", | ||||
|      .libs = {1, FURI_LIB{"menu_task"}}, | ||||
|      .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_POWER | ||||
|     {.app = power_task, | ||||
|      .name = "power_task", | ||||
|      .libs = {2, FURI_LIB{"cli_task", "gui_task"}}, | ||||
|      .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_BT | ||||
|     {.app = bt_task, .name = "bt_task", .libs = {1, FURI_LIB{"cli_task"}}, .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_CC1101 | ||||
|     {.app = cc1101_workaround, | ||||
|      .name = "cc1101 workaround", | ||||
|      .libs = {1, FURI_LIB{"gui_task"}}, | ||||
|      .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_LF_RFID | ||||
|     {.app = lf_rfid_workaround, | ||||
|      .name = "lf rfid workaround", | ||||
|      .libs = {1, FURI_LIB{"gui_task"}}, | ||||
|      .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_IRDA | ||||
|     {.app = irda, .name = "irda", .libs = {1, FURI_LIB{"gui_task"}}, .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_NFC | ||||
|     {.app = nfc_task, .name = "nfc_task", .libs = {1, FURI_LIB{"menu_task"}}, .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_TEST | ||||
|     {.app = flipper_test_app, .name = "test app", .libs = {0}, .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_EXAMPLE_IPC | ||||
|     {.app = application_ipc_display, .name = "ipc display", .libs = {0}, .icon = A_Plugins_14}, | ||||
|     {.app = application_ipc_widget, .name = "ipc widget", .libs = {0}, .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_EXAMPLE_QRCODE | ||||
|     {.app = u8g2_qrcode, | ||||
|      .name = "u8g2_qrcode", | ||||
|      .libs = {1, FURI_LIB{"display_u8g2"}}, | ||||
|      .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_EXAMPLE_FATFS | ||||
|     {.app = fatfs_list, | ||||
|      .name = "fatfs_list", | ||||
|      .libs = {2, FURI_LIB{"display_u8g2", "input_task"}}, | ||||
|      .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_EXAMPLE_DISPLAY | ||||
|     {.app = u8g2_example, | ||||
|      .name = "u8g2_example", | ||||
|      .libs = {1, FURI_LIB{"display_u8g2"}}, | ||||
|      .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_SPEAKER_DEMO | ||||
|     {.app = coreglitch_demo_0, .name = "coreglitch_demo_0", .libs = {0}, .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_SD_TEST | ||||
|     {.app = sd_card_test, | ||||
|      .name = "sd_card_test", | ||||
|      .libs = {2, FURI_LIB{"gui_task", "sd_filesystem"}}, | ||||
|      .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_MUSIC_PLAYER | ||||
|     {.app = music_player, | ||||
|      .name = "music player", | ||||
|      .libs = {1, FURI_LIB{"gui_task"}}, | ||||
|      .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_IBUTTON | ||||
|     {.app = app_ibutton, | ||||
|      .name = "ibutton", | ||||
|      .libs = {1, FURI_LIB{"gui_task"}}, | ||||
|      .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_GPIO_DEMO | ||||
|     {.app = app_gpio_test, | ||||
|      .name = "gpio test", | ||||
|      .libs = {1, FURI_LIB{"gui_task"}}, | ||||
|      .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_FLOOPPER_BLOOPPER | ||||
|     {.app = floopper_bloopper, | ||||
|      .name = "Floopper Bloopper", | ||||
|      .libs = {1, FURI_LIB{"gui_task"}}, | ||||
|      .icon = A_Games_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_SDNFC | ||||
|     {.app = sdnfc, .name = "sdnfc", .libs = {1, FURI_LIB{"gui_task"}}, .icon = A_Plugins_14}, | ||||
| #endif | ||||
| }; | ||||
| 
 | ||||
| // Main menu APP
 | ||||
| const FlipperStartupApp FLIPPER_APPS[] = { | ||||
| #ifdef BUILD_CC1101 | ||||
|     {.app = cc1101_workaround, | ||||
|      .name = "Sub-1 GHz", | ||||
|      .libs = {1, FURI_LIB{"gui_task"}}, | ||||
|      .icon = A_Sub1ghz_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef BUILD_LF_RFID | ||||
|     {.app = lf_rfid_workaround, | ||||
|      .name = "125 kHz RFID", | ||||
|      .libs = {1, FURI_LIB{"gui_task"}}, | ||||
|      .icon = A_125khz_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef BUILD_IRDA | ||||
|     {.app = irda, .name = "Infrared", .libs = {1, FURI_LIB{"gui_task"}}, .icon = A_Infrared_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef BUILD_IBUTTON | ||||
|     {.app = app_ibutton, | ||||
|      .name = "iButton", | ||||
|      .libs = {1, FURI_LIB{"gui_task"}}, | ||||
|      .icon = A_iButton_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef BUILD_GPIO_DEMO | ||||
|     {.app = app_gpio_test, .name = "GPIO", .libs = {1, FURI_LIB{"gui_task"}}, .icon = A_GPIO_14}, | ||||
| #endif | ||||
| }; | ||||
| 
 | ||||
| // Plugin menu
 | ||||
| const FlipperStartupApp FLIPPER_PLUGINS[] = { | ||||
| #ifdef BUILD_EXAMPLE_BLINK | ||||
|     {.app = application_blink, | ||||
|      .name = "blink", | ||||
|      .libs = {1, FURI_LIB{"input_task"}}, | ||||
|      .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef BUILD_EXAMPLE_INPUT_DUMP | ||||
|     {.app = application_input_dump, | ||||
|      .name = "input dump", | ||||
|      .libs = {1, FURI_LIB{"input_task"}}, | ||||
|      .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef BUILD_SPEAKER_DEMO | ||||
|     {.app = coreglitch_demo_0, .name = "coreglitch_demo_0", .libs = {0}, .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef BUILD_SD_TEST | ||||
|     {.app = sd_card_test, | ||||
|      .name = "sd_card_test", | ||||
|      .libs = {2, FURI_LIB{"gui_task", "sd_filesystem"}}, | ||||
|      .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef BUILD_VIBRO_DEMO | ||||
|     {.app = application_vibro, | ||||
|      .name = "application_vibro", | ||||
|      .libs = {1, FURI_LIB{"input_task"}}, | ||||
|      .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef BUILD_MUSIC_PLAYER | ||||
|     {.app = music_player, | ||||
|      .name = "music player", | ||||
|      .libs = {1, FURI_LIB{"gui_task"}}, | ||||
|      .icon = A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef BUILD_FLOOPPER_BLOOPPER | ||||
|     {.app = floopper_bloopper, | ||||
|      .name = "Floopper Bloopper", | ||||
|      .libs = {1, FURI_LIB{"gui_task"}}, | ||||
|      .icon = A_Games_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef BUILD_SDNFC | ||||
|     {.app = sdnfc, .name = "sdnfc", .libs = {1, FURI_LIB{"gui_task"}}, .icon = A_Plugins_14}, | ||||
| #endif | ||||
| }; | ||||
| extern const FuriApplication FLIPPER_PLUGINS[]; | ||||
| size_t FLIPPER_PLUGINS_size(); | ||||
|  | ||||
| @ -2,6 +2,7 @@ APP_DIR		= $(PROJECT_ROOT)/applications | ||||
| LIB_DIR 	= $(PROJECT_ROOT)/lib | ||||
| 
 | ||||
| CFLAGS		+= -I$(APP_DIR) | ||||
| C_SOURCES	+= $(APP_DIR)/applications.c | ||||
| 
 | ||||
| # Use APP_* for autostart app
 | ||||
| # Use BUILD_* for add app to build
 | ||||
|  | ||||
| @ -1,11 +1,12 @@ | ||||
| #include "flipper_v2.h" | ||||
| #include <furi.h> | ||||
| 
 | ||||
| #define BACKLIGHT_TIME 10000 | ||||
| #define BACKLIGHT_FLAG_ACTIVITY 0x00000001U | ||||
| 
 | ||||
| static void event_cb(const void* value, void* ctx) { | ||||
|     xSemaphoreGive((SemaphoreHandle_t*)ctx); | ||||
|     osThreadFlagsSet((osThreadId_t)ctx, BACKLIGHT_FLAG_ACTIVITY); | ||||
| } | ||||
| 
 | ||||
| const uint32_t BACKLIGHT_TIME = 10000; | ||||
| 
 | ||||
| void backlight_control(void* p) { | ||||
|     // TODO open record
 | ||||
|     const GpioPin* backlight_record = &backlight_gpio; | ||||
| @ -14,20 +15,14 @@ void backlight_control(void* p) { | ||||
|     gpio_init(backlight_record, GpioModeOutputPushPull); | ||||
|     gpio_write(backlight_record, true); | ||||
| 
 | ||||
|     StaticSemaphore_t event_descriptor; | ||||
|     SemaphoreHandle_t update = xSemaphoreCreateCountingStatic(255, 0, &event_descriptor); | ||||
| 
 | ||||
|     // open record
 | ||||
|     PubSub* event_record = furi_open("input_events"); | ||||
|     furi_check(event_record); | ||||
|     subscribe_pubsub(event_record, event_cb, (void*)update); | ||||
| 
 | ||||
|     // we ready to work
 | ||||
|     furiac_ready(); | ||||
|     PubSub* event_record = furi_record_open("input_events"); | ||||
|     subscribe_pubsub(event_record, event_cb, (void*)osThreadGetId()); | ||||
| 
 | ||||
|     while(1) { | ||||
|         // wait for event
 | ||||
|         if(xSemaphoreTake(update, BACKLIGHT_TIME) == pdTRUE) { | ||||
|         if(osThreadFlagsWait(BACKLIGHT_FLAG_ACTIVITY, osFlagsWaitAny, BACKLIGHT_TIME) == | ||||
|            BACKLIGHT_FLAG_ACTIVITY) { | ||||
|             gpio_write(backlight_record, true); | ||||
|         } else { | ||||
|             gpio_write(backlight_record, false); | ||||
|  | ||||
| @ -2,16 +2,23 @@ | ||||
| 
 | ||||
| Bt* bt_alloc() { | ||||
|     Bt* bt = furi_alloc(sizeof(Bt)); | ||||
|     bt->cli = furi_open("cli"); | ||||
| 
 | ||||
|     bt->cli = furi_record_open("cli"); | ||||
|     cli_add_command(bt->cli, "bt_info", bt_cli_info, bt); | ||||
|     bt->gui = furi_record_open("gui"); | ||||
|     bt->menu = furi_record_open("menu"); | ||||
| 
 | ||||
|     bt->statusbar_icon = assets_icons_get(I_Bluetooth_5x8); | ||||
|     bt->statusbar_widget = widget_alloc(); | ||||
|     widget_set_width(bt->statusbar_widget, icon_get_width(bt->statusbar_icon)); | ||||
|     widget_draw_callback_set(bt->statusbar_widget, bt_draw_statusbar_callback, bt); | ||||
|     widget_enabled_set(bt->statusbar_widget, false); | ||||
|     gui_add_widget(bt->gui, bt->statusbar_widget, GuiLayerStatusBarLeft); | ||||
| 
 | ||||
|     bt->menu_icon = assets_icons_get(A_Bluetooth_14); | ||||
|     bt->menu_item = menu_item_alloc_menu("Bluetooth", bt->menu_icon); | ||||
|     with_value_mutex( | ||||
|         bt->menu, (Menu * menu) { menu_item_add(menu, bt->menu_item); }); | ||||
| 
 | ||||
|     return bt; | ||||
| } | ||||
| @ -33,23 +40,7 @@ void bt_cli_info(string_t args, void* context) { | ||||
| void bt_task() { | ||||
|     Bt* bt = bt_alloc(); | ||||
| 
 | ||||
|     if(bt->cli) { | ||||
|         cli_add_command(bt->cli, "bt_info", bt_cli_info, bt); | ||||
|     } | ||||
| 
 | ||||
|     // TODO: add ValueMutex(bt) to "bt" record
 | ||||
|     if(!furi_create("bt", bt)) { | ||||
|         printf("[bt_task] unable to create bt record\n"); | ||||
|         furiac_exit(NULL); | ||||
|     } | ||||
| 
 | ||||
|     Gui* gui = furi_open("gui"); | ||||
|     gui_add_widget(gui, bt->statusbar_widget, GuiLayerStatusBarLeft); | ||||
| 
 | ||||
|     with_value_mutex( | ||||
|         furi_open("menu"), (Menu * menu) { menu_item_add(menu, bt->menu_item); }); | ||||
| 
 | ||||
|     furiac_ready(); | ||||
|     furi_record_create("bt", bt); | ||||
| 
 | ||||
|     api_hal_bt_init(); | ||||
| 
 | ||||
|  | ||||
| @ -2,10 +2,9 @@ | ||||
| 
 | ||||
| #include "bt.h" | ||||
| 
 | ||||
| #include <cli/cli.h> | ||||
| #include <furi.h> | ||||
| 
 | ||||
| #include <flipper.h> | ||||
| #include <flipper_v2.h> | ||||
| #include <cli/cli.h> | ||||
| 
 | ||||
| #include <gui/gui.h> | ||||
| #include <gui/widget.h> | ||||
| @ -15,6 +14,8 @@ | ||||
| 
 | ||||
| typedef struct { | ||||
|     Cli* cli; | ||||
|     Gui* gui; | ||||
|     ValueMutex* menu; | ||||
|     // Status bar
 | ||||
|     Icon* statusbar_icon; | ||||
|     Widget* statusbar_widget; | ||||
| @ -26,3 +27,7 @@ typedef struct { | ||||
| Bt* bt_alloc(); | ||||
| 
 | ||||
| void bt_draw_statusbar_callback(Canvas* canvas, void* context); | ||||
| 
 | ||||
| void bt_cli_info(string_t args, void* context); | ||||
| 
 | ||||
| void bt_draw_statusbar_callback(Canvas* canvas, void* context); | ||||
|  | ||||
| @ -1,6 +1,7 @@ | ||||
| #include "flipper.h" | ||||
| 
 | ||||
| #include "cc1101-workaround/cc1101.h" | ||||
| #include "cc1101.h" | ||||
| #include <furi.h> | ||||
| #include <gui/gui.h> | ||||
| #include <input/input.h> | ||||
| 
 | ||||
| extern "C" void cli_print(const char* str); | ||||
| 
 | ||||
| @ -335,7 +336,7 @@ static void render_callback(Canvas* canvas, void* ctx) { | ||||
| } | ||||
| 
 | ||||
| static void input_callback(InputEvent* input_event, void* ctx) { | ||||
|     osMessageQueueId_t event_queue = (QueueHandle_t)ctx; | ||||
|     osMessageQueueId_t event_queue = ctx; | ||||
| 
 | ||||
|     AppEvent event; | ||||
|     event.type = EventTypeKey; | ||||
| @ -370,7 +371,7 @@ extern "C" void cc1101_workaround(void* p) { | ||||
|     widget_input_callback_set(widget, input_callback, event_queue); | ||||
| 
 | ||||
|     // Open GUI and register widget
 | ||||
|     Gui* gui = (Gui*)furi_open("gui"); | ||||
|     Gui* gui = (Gui*)furi_record_open("gui"); | ||||
|     if(gui == NULL) { | ||||
|         printf("[cc1101] gui is not available\n"); | ||||
|         furiac_exit(NULL); | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| #include "flipper_v2.h" | ||||
| #include <furi.h> | ||||
| #include "cc1101-workaround/cc1101.h" | ||||
| #include "spi.h" | ||||
| #include <math.h> | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include "flipper_v2.h" | ||||
| #include <furi.h> | ||||
| 
 | ||||
| #define F_OSC 26e6 | ||||
| 
 | ||||
|  | ||||
| @ -1,8 +1,6 @@ | ||||
| #include "cli_i.h" | ||||
| #include "cli_commands.h" | ||||
| 
 | ||||
| #include <api-hal-vcp.h> | ||||
| 
 | ||||
| Cli* cli_alloc() { | ||||
|     Cli* cli = furi_alloc(sizeof(Cli)); | ||||
|     CliCommandDict_init(cli->commands); | ||||
| @ -175,12 +173,7 @@ void cli_task(void* p) { | ||||
|     // Init basic cli commands
 | ||||
|     cli_commands_init(cli); | ||||
| 
 | ||||
|     if(!furi_create("cli", cli)) { | ||||
|         printf("[cli_task] cannot create the cli record\n"); | ||||
|         furiac_exit(NULL); | ||||
|     } | ||||
| 
 | ||||
|     furiac_ready(); | ||||
|     furi_record_create("cli", cli); | ||||
| 
 | ||||
|     while(1) { | ||||
|         cli_process_input(cli); | ||||
|  | ||||
| @ -2,8 +2,7 @@ | ||||
| 
 | ||||
| #include "cli.h" | ||||
| 
 | ||||
| #include <flipper.h> | ||||
| #include <flipper_v2.h> | ||||
| #include <furi.h> | ||||
| 
 | ||||
| #include <m-dict.h> | ||||
| 
 | ||||
|  | ||||
| @ -1,12 +1,10 @@ | ||||
| #include "flipper.h" | ||||
| #include <furi.h> | ||||
| #include "u8g2/u8g2.h" | ||||
| 
 | ||||
| extern TIM_HandleTypeDef SPEAKER_TIM; | ||||
| 
 | ||||
| void coreglitch_demo_0(void* p) { | ||||
|     FuriRecordSubscriber* log = get_default_log(); | ||||
| 
 | ||||
|     fuprintf(log, "coreglitch demo!\n"); | ||||
|     printf("coreglitch demo!\n"); | ||||
| 
 | ||||
|     float notes[] = { | ||||
|         0.0, | ||||
|  | ||||
| @ -1,195 +0,0 @@ | ||||
| #include "u8g2/u8g2.h" | ||||
| #include "flipper.h" | ||||
| #include "main.h" | ||||
| 
 | ||||
| extern SPI_HandleTypeDef SPI_D; | ||||
| 
 | ||||
| // TODO: fix log
 | ||||
| #ifdef DEBUG | ||||
| #undef DEBUG | ||||
| #endif | ||||
| 
 | ||||
| // TODO rewrite u8g2 to pass thread-local context in this handlers
 | ||||
| 
 | ||||
| static uint8_t | ||||
| u8g2_gpio_and_delay_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_ptr) { | ||||
|     switch(msg) { | ||||
|     //Initialize SPI peripheral
 | ||||
|     case U8X8_MSG_GPIO_AND_DELAY_INIT: | ||||
|         /* HAL initialization contains all what we need so we can skip this part. */ | ||||
|         break; | ||||
| 
 | ||||
|     //Function which implements a delay, arg_int contains the amount of ms
 | ||||
|     case U8X8_MSG_DELAY_MILLI: | ||||
|         osDelay(arg_int); | ||||
|         break; | ||||
| 
 | ||||
|     //Function which delays 10us
 | ||||
|     case U8X8_MSG_DELAY_10MICRO: | ||||
|         delay_us(10); | ||||
|         break; | ||||
| 
 | ||||
|     //Function which delays 100ns
 | ||||
|     case U8X8_MSG_DELAY_100NANO: | ||||
|         asm("nop"); | ||||
|         break; | ||||
| 
 | ||||
|     // Function to define the logic level of the RESET line
 | ||||
|     case U8X8_MSG_GPIO_RESET: | ||||
| #ifdef DEBUG | ||||
|         fuprintf(log, "[u8g2] rst %d\n", arg_int); | ||||
| #endif | ||||
| 
 | ||||
|         // TODO change it to FuriRecord pin
 | ||||
|         HAL_GPIO_WritePin( | ||||
|             DISPLAY_RST_GPIO_Port, DISPLAY_RST_Pin, arg_int ? GPIO_PIN_SET : GPIO_PIN_RESET); | ||||
|         break; | ||||
| 
 | ||||
|     default: | ||||
| #ifdef DEBUG | ||||
|         fufuprintf(log, "[u8g2] unknown io %d\n", msg); | ||||
| #endif | ||||
| 
 | ||||
|         return 0; //A message was received which is not implemented, return 0 to indicate an error
 | ||||
|     } | ||||
| 
 | ||||
|     return 1; // command processed successfully.
 | ||||
| } | ||||
| 
 | ||||
| static uint8_t u8x8_hw_spi_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_ptr) { | ||||
|     switch(msg) { | ||||
|     case U8X8_MSG_BYTE_SEND: | ||||
| #ifdef DEBUG | ||||
|         fuprintf(log, "[u8g2] send %d bytes %02X\n", arg_int, ((uint8_t*)arg_ptr)[0]); | ||||
| #endif | ||||
| 
 | ||||
|         // TODO change it to FuriRecord SPI
 | ||||
|         HAL_SPI_Transmit(&SPI_D, (uint8_t*)arg_ptr, arg_int, 10000); | ||||
|         break; | ||||
| 
 | ||||
|     case U8X8_MSG_BYTE_SET_DC: | ||||
| #ifdef DEBUG | ||||
|         fuprintf(log, "[u8g2] dc %d\n", arg_int); | ||||
| #endif | ||||
| 
 | ||||
|         // TODO change it to FuriRecord pin
 | ||||
|         HAL_GPIO_WritePin( | ||||
|             DISPLAY_DI_GPIO_Port, DISPLAY_DI_Pin, arg_int ? GPIO_PIN_SET : GPIO_PIN_RESET); | ||||
|         break; | ||||
| 
 | ||||
|     case U8X8_MSG_BYTE_INIT: | ||||
| #ifdef DEBUG | ||||
|         fuprintf(log, "[u8g2] init\n"); | ||||
| #endif | ||||
| 
 | ||||
|         // TODO change it to FuriRecord pin
 | ||||
|         HAL_GPIO_WritePin(DISPLAY_CS_GPIO_Port, DISPLAY_CS_Pin, GPIO_PIN_RESET); | ||||
|         break; | ||||
| 
 | ||||
|     case U8X8_MSG_BYTE_START_TRANSFER: | ||||
| #ifdef DEBUG | ||||
|         fuprintf(log, "[u8g2] start\n"); | ||||
| #endif | ||||
| 
 | ||||
|         // TODO change it to FuriRecord pin
 | ||||
|         HAL_GPIO_WritePin(DISPLAY_CS_GPIO_Port, DISPLAY_CS_Pin, GPIO_PIN_RESET); | ||||
|         asm("nop"); | ||||
|         break; | ||||
| 
 | ||||
|     case U8X8_MSG_BYTE_END_TRANSFER: | ||||
| #ifdef DEBUG | ||||
|         fuprintf(log, "[u8g2] end\n"); | ||||
| #endif | ||||
| 
 | ||||
|         asm("nop"); | ||||
|         // TODO change it to FuriRecord pin
 | ||||
|         HAL_GPIO_WritePin(DISPLAY_CS_GPIO_Port, DISPLAY_CS_Pin, GPIO_PIN_SET); | ||||
|         break; | ||||
| 
 | ||||
|     default: | ||||
| #ifdef DEBUG | ||||
|         fuprintf(log, "[u8g2] unknown xfer %d\n", msg); | ||||
| #endif | ||||
| 
 | ||||
|         return 0; | ||||
|     } | ||||
| 
 | ||||
|     return 1; | ||||
| } | ||||
| 
 | ||||
| typedef struct { | ||||
|     SemaphoreHandle_t update; // queue to pass events from callback to app thread
 | ||||
|     FuriRecordSubscriber* log; // app logger
 | ||||
| } DisplayCtx; | ||||
| 
 | ||||
| static void handle_fb_change(const void* fb, size_t fb_size, void* raw_ctx) { | ||||
|     DisplayCtx* ctx = (DisplayCtx*)raw_ctx; // make right type
 | ||||
| 
 | ||||
|     // fuprintf(ctx->log, "[display_u8g2] change fb\n");
 | ||||
| 
 | ||||
|     // send update to app thread
 | ||||
|     xSemaphoreGive(ctx->update); | ||||
| } | ||||
| 
 | ||||
| void display_u8g2(void* p) { | ||||
|     FuriRecordSubscriber* log = get_default_log(); | ||||
| 
 | ||||
|     // TODO we need different app to contol backlight
 | ||||
|     HAL_GPIO_WritePin(DISPLAY_BACKLIGHT_GPIO_Port, DISPLAY_BACKLIGHT_Pin, GPIO_PIN_SET); | ||||
| 
 | ||||
|     u8g2_t _u8g2; | ||||
|     u8g2_Setup_st7565_erc12864_alt_f( | ||||
|         &_u8g2, U8G2_R0, u8x8_hw_spi_stm32, u8g2_gpio_and_delay_stm32); | ||||
|     u8g2_InitDisplay( | ||||
|         &_u8g2); // send init sequence to the display, display is in sleep mode after this
 | ||||
|     u8g2_SetContrast(&_u8g2, 36); | ||||
| 
 | ||||
|     if(!furi_create_deprecated("u8g2_fb", (void*)&_u8g2, sizeof(_u8g2))) { | ||||
|         fuprintf(log, "[display_u8g2] cannot create fb record\n"); | ||||
|         furiac_exit(NULL); | ||||
|     } | ||||
| 
 | ||||
|     StaticSemaphore_t event_descriptor; | ||||
|     // create stack-based counting semaphore
 | ||||
|     SemaphoreHandle_t update = xSemaphoreCreateCountingStatic(255, 0, &event_descriptor); | ||||
| 
 | ||||
|     if(update == NULL) { | ||||
|         fuprintf(log, "[display_u8g2] cannot create update semaphore\n"); | ||||
|         furiac_exit(NULL); | ||||
|     } | ||||
| 
 | ||||
|     // save log and event queue in context structure
 | ||||
|     DisplayCtx ctx = {.update = update, .log = log}; | ||||
| 
 | ||||
|     // subscribe to record. ctx will be passed to handle_fb_change
 | ||||
|     FuriRecordSubscriber* fb_record = | ||||
|         furi_open_deprecated("u8g2_fb", false, false, handle_fb_change, NULL, &ctx); | ||||
| 
 | ||||
|     if(fb_record == NULL) { | ||||
|         fuprintf(log, "[display] cannot open fb record\n"); | ||||
|         furiac_exit(NULL); | ||||
|     } | ||||
| 
 | ||||
|     u8g2_t* u8g2 = (u8g2_t*)furi_take(fb_record); | ||||
|     u8g2_SetPowerSave(u8g2, 0); // wake up display
 | ||||
|     u8g2_SendBuffer(u8g2); | ||||
|     furi_give(fb_record); | ||||
| 
 | ||||
|     // we ready to work
 | ||||
|     furiac_ready(); | ||||
| 
 | ||||
|     while(1) { | ||||
|         // wait for event
 | ||||
|         if(xSemaphoreTake(update, 10000) == pdTRUE) { | ||||
|             HAL_GPIO_WritePin(DISPLAY_BACKLIGHT_GPIO_Port, DISPLAY_BACKLIGHT_Pin, GPIO_PIN_SET); | ||||
| 
 | ||||
|             u8g2_t* u8g2 = (u8g2_t*)furi_take(fb_record); | ||||
|             u8g2_SetPowerSave(u8g2, 0); // wake up display
 | ||||
|             u8g2_SendBuffer(u8g2); | ||||
|             furi_give(fb_record); | ||||
|         } else { | ||||
|             // TODO we need different app to contol backlight
 | ||||
|             HAL_GPIO_WritePin(DISPLAY_BACKLIGHT_GPIO_Port, DISPLAY_BACKLIGHT_Pin, GPIO_PIN_RESET); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -67,8 +67,7 @@ Dolphin* dolphin_alloc() { | ||||
|     // State
 | ||||
|     dolphin->state = dolphin_state_alloc(); | ||||
|     // Menu
 | ||||
|     dolphin->menu_vm = furi_open("menu"); | ||||
|     furi_check(dolphin->menu_vm); | ||||
|     dolphin->menu_vm = furi_record_open("menu"); | ||||
|     // GUI
 | ||||
|     dolphin->idle_view_dispatcher = view_dispatcher_alloc(); | ||||
|     // First start View
 | ||||
| @ -125,7 +124,7 @@ void dolphin_deed(Dolphin* dolphin, DolphinDeed deed) { | ||||
| void dolphin_task() { | ||||
|     Dolphin* dolphin = dolphin_alloc(); | ||||
| 
 | ||||
|     Gui* gui = furi_open("gui"); | ||||
|     Gui* gui = furi_record_open("gui"); | ||||
|     view_dispatcher_attach_to_gui(dolphin->idle_view_dispatcher, gui, ViewDispatcherTypeWindow); | ||||
|     if(dolphin_state_load(dolphin->state)) { | ||||
|         view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewIdleMain); | ||||
| @ -138,12 +137,7 @@ void dolphin_task() { | ||||
|             model->butthurt = dolphin_state_get_butthurt(dolphin->state); | ||||
|         }); | ||||
| 
 | ||||
|     if(!furi_create("dolphin", dolphin)) { | ||||
|         printf("[dolphin_task] cannot create the dolphin record\n"); | ||||
|         furiac_exit(NULL); | ||||
|     } | ||||
| 
 | ||||
|     furiac_ready(); | ||||
|     furi_record_create("dolphin", dolphin); | ||||
| 
 | ||||
|     DolphinEvent event; | ||||
|     while(1) { | ||||
|  | ||||
| @ -4,7 +4,7 @@ | ||||
| #include "dolphin_state.h" | ||||
| #include "dolphin_views.h" | ||||
| 
 | ||||
| #include <flipper_v2.h> | ||||
| #include <furi.h> | ||||
| 
 | ||||
| #include <gui/gui.h> | ||||
| #include <gui/view_dispatcher.h> | ||||
|  | ||||
| @ -1,6 +1,5 @@ | ||||
| #include "dolphin_state.h" | ||||
| #include <api-hal-flash.h> | ||||
| #include <flipper_v2.h> | ||||
| #include <furi.h> | ||||
| 
 | ||||
| typedef struct { | ||||
|     uint8_t magic; | ||||
|  | ||||
| @ -3,7 +3,8 @@ | ||||
| #include <stdint.h> | ||||
| #include <stdbool.h> | ||||
| #include <gui/canvas.h> | ||||
| #include <flipper_v2.h> | ||||
| #include <input/input.h> | ||||
| #include <furi.h> | ||||
| 
 | ||||
| // Idle scree
 | ||||
| typedef enum { | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| #include "flipper_v2.h" | ||||
| #include <furi.h> | ||||
| 
 | ||||
| void rgb_set( | ||||
|     bool r, | ||||
|  | ||||
| @ -1,155 +0,0 @@ | ||||
| #include "u8g2/u8g2.h" | ||||
| #include "fatfs/ff.h" | ||||
| #include "flipper_v2.h" | ||||
| #include <stdio.h> | ||||
| 
 | ||||
| extern uint8_t BSP_SD_Init(); | ||||
| 
 | ||||
| // TODO currently we have small stack, so it will be static
 | ||||
| FuriRecordSubscriber* furi_log; | ||||
| #define STR_BUFFER_SIZE 128 | ||||
| char str_buffer[STR_BUFFER_SIZE]; | ||||
| uint8_t line_current = 0; | ||||
| uint16_t line_position = 0; | ||||
| 
 | ||||
| // TODO this should be in the target driver
 | ||||
| FATFS SD_FatFs; | ||||
| char SD_Path[4]; | ||||
| 
 | ||||
| typedef enum { | ||||
|     EventTypeStart, | ||||
|     EventTypeKey, | ||||
| } AppEventType; | ||||
| 
 | ||||
| typedef struct { | ||||
|     union { | ||||
|         InputEvent input; | ||||
|     } value; | ||||
|     AppEventType type; | ||||
| } AppEvent; | ||||
| 
 | ||||
| static void event_cb(const void* value, void* ctx) { | ||||
|     QueueHandle_t event_queue = (QueueHandle_t)ctx; | ||||
| 
 | ||||
|     AppEvent event; | ||||
|     event.type = EventTypeKey; | ||||
|     event.value.input = *(InputEvent*)value; | ||||
|     xQueueSend(event_queue, (void*)&event, 0); | ||||
| } | ||||
| 
 | ||||
| void fatfs_list(void* p) { | ||||
|     const uint8_t line_size = 10; | ||||
|     const uint8_t lines_on_display = 6; | ||||
| 
 | ||||
|     uint8_t bsp_result; | ||||
|     FRESULT result; | ||||
|     DIR dir; | ||||
|     FILINFO fno; | ||||
|     AppEvent event; | ||||
| 
 | ||||
|     QueueHandle_t event_queue = xQueueCreate(2, sizeof(AppEvent)); | ||||
| 
 | ||||
|     furi_log = get_default_log(); | ||||
|     fuprintf(furi_log, "[fatfs_list] app start\n"); | ||||
|     fuprintf(furi_log, "[fatfs_list] wait for sd insert\n"); | ||||
| 
 | ||||
|     while(!hal_gpio_read_sd_detect()) { | ||||
|         delay(100); | ||||
|     } | ||||
| 
 | ||||
|     fuprintf(furi_log, "[fatfs_list] sd inserted\n"); | ||||
| 
 | ||||
|     FuriRecordSubscriber* fb_record = | ||||
|         furi_open_deprecated("u8g2_fb", false, false, NULL, NULL, NULL); | ||||
|     if(fb_record == NULL) { | ||||
|         fuprintf(furi_log, "[fatfs_list] cannot create fb record\n"); | ||||
|         furiac_exit(NULL); | ||||
|     } | ||||
| 
 | ||||
|     PubSub* event_record = furi_open("input_events"); | ||||
|     if(event_record == NULL) { | ||||
|         fuprintf(furi_log, "[fatfs_list] cannot open input_events record\n"); | ||||
|         furiac_exit(NULL); | ||||
|     } | ||||
|     PubSubItem* subscription = subscribe_pubsub(event_record, event_cb, event_queue); | ||||
|     if(subscription == NULL) { | ||||
|         fuprintf(furi_log, "[fatfs_list] cannot register input_events callback\n"); | ||||
|         furiac_exit(NULL); | ||||
|     } | ||||
| 
 | ||||
|     bsp_result = BSP_SD_Init(); | ||||
| 
 | ||||
|     if(bsp_result != 0) { | ||||
|         fuprintf(furi_log, "[fatfs_list] SD card init error\n"); | ||||
|         furiac_exit(NULL); | ||||
|     } | ||||
| 
 | ||||
|     result = f_mount(&SD_FatFs, (TCHAR const*)SD_Path, 1); | ||||
| 
 | ||||
|     if(result != FR_OK) { | ||||
|         fuprintf(furi_log, "[fatfs_list] SD card mount error\n"); | ||||
|         furiac_exit(NULL); | ||||
|     } | ||||
| 
 | ||||
|     // ok, now we can work with sd card
 | ||||
| 
 | ||||
|     // send start event
 | ||||
|     event.type = EventTypeStart; | ||||
|     xQueueSend(event_queue, (void*)&event, 0); | ||||
| 
 | ||||
|     while(1) { | ||||
|         if(xQueueReceive(event_queue, (void*)&event, portMAX_DELAY)) { | ||||
|             // process buttons event
 | ||||
|             if(event.type == EventTypeKey) { | ||||
|                 // button pressed
 | ||||
|                 if(event.value.input.state == true) { | ||||
|                     if(event.value.input.input == InputUp && line_position > 0) { | ||||
|                         line_position--; | ||||
|                     } | ||||
|                     if(event.value.input.input == InputDown) { | ||||
|                         line_position++; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             line_current = 1; | ||||
| 
 | ||||
|             // open root dir
 | ||||
|             result = f_opendir(&dir, ""); | ||||
| 
 | ||||
|             while(1) { | ||||
|                 // read a directory item
 | ||||
|                 result = f_readdir(&dir, &fno); | ||||
| 
 | ||||
|                 if(result != FR_OK) { | ||||
|                     // cannot read dir
 | ||||
|                     break; | ||||
|                 } | ||||
| 
 | ||||
|                 if(fno.fname[0] == 0) { | ||||
|                     // Break on end of dir
 | ||||
|                     break; | ||||
|                 } | ||||
| 
 | ||||
|                 // draw files on display
 | ||||
|                 if(line_current > line_position && | ||||
|                    line_current <= (line_position + lines_on_display)) { | ||||
|                     if(fno.fattrib & AM_DIR) { | ||||
|                         snprintf(str_buffer, STR_BUFFER_SIZE, "DIR %s\n", fno.fname); | ||||
|                     } else { | ||||
|                         snprintf(str_buffer, STR_BUFFER_SIZE, "FIL %s\n", fno.fname); | ||||
|                     } | ||||
|                     fuprintf(furi_log, str_buffer); | ||||
|                 } | ||||
| 
 | ||||
|                 line_current++; | ||||
|             } | ||||
| 
 | ||||
|             result = f_closedir(&dir); | ||||
| 
 | ||||
|             furi_commit(fb_record); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     furiac_exit(NULL); | ||||
| } | ||||
| @ -1,5 +1,6 @@ | ||||
| #include "flipper_v2.h" | ||||
| #include <furi.h> | ||||
| #include <stdio.h> | ||||
| #include <input/input.h> | ||||
| 
 | ||||
| typedef union { | ||||
|     unsigned int packed; | ||||
| @ -21,12 +22,10 @@ static void event_cb(const void* value, void* ctx) { | ||||
| 
 | ||||
| void application_input_dump(void* p) { | ||||
|     // open record
 | ||||
|     ValueManager* state_record = furi_open("input_state"); | ||||
|     furi_check(state_record); | ||||
|     ValueManager* state_record = furi_record_open("input_state"); | ||||
|     subscribe_pubsub(&state_record->pubsub, state_cb, NULL); | ||||
| 
 | ||||
|     PubSub* event_record = furi_open("input_events"); | ||||
|     furi_check(event_record); | ||||
|     PubSub* event_record = furi_record_open("input_events"); | ||||
|     subscribe_pubsub(event_record, event_cb, NULL); | ||||
| 
 | ||||
|     printf("Example app [input dump]\n"); | ||||
|  | ||||
| @ -1,155 +0,0 @@ | ||||
| #include "flipper.h" | ||||
| #include <string.h> | ||||
| 
 | ||||
| #define FB_WIDTH 10 | ||||
| #define FB_HEIGHT 3 | ||||
| #define FB_SIZE (FB_WIDTH * FB_HEIGHT) | ||||
| 
 | ||||
| // context structure used for pass some object from app thread to callback
 | ||||
| typedef struct { | ||||
|     SemaphoreHandle_t events; // queue to pass events from callback to app thread
 | ||||
|     FuriRecordSubscriber* log; // app logger
 | ||||
| } IpcCtx; | ||||
| 
 | ||||
| static void handle_fb_change(const void* fb, size_t fb_size, void* raw_ctx) { | ||||
|     IpcCtx* ctx = (IpcCtx*)raw_ctx; // make right type
 | ||||
| 
 | ||||
|     fuprintf(ctx->log, "[cb] framebuffer updated\n"); | ||||
| 
 | ||||
|     // send event to app thread
 | ||||
|     xSemaphoreGive(ctx->events); | ||||
| 
 | ||||
|     // Attention! Please, do not make blocking operation like IO and waits inside callback
 | ||||
|     // Remember that callback execute in calling thread/context
 | ||||
| } | ||||
| 
 | ||||
| static void print_fb(char* fb, FuriRecordSubscriber* log) { | ||||
|     if(fb == NULL) return; | ||||
| 
 | ||||
|     /* draw framebuffer like this:
 | ||||
|     +==========+ | ||||
|     |          | | ||||
|     |          | | ||||
|     |          | | ||||
|     +==========+ | ||||
|     */ | ||||
| 
 | ||||
|     char row_buffer[FB_WIDTH + 1]; | ||||
|     row_buffer[FB_WIDTH] = '\0'; | ||||
| 
 | ||||
|     // FB layout is hardcoded here
 | ||||
|     fuprintf(log, "+==========+\n"); | ||||
|     for(uint8_t i = 0; i < FB_HEIGHT; i++) { | ||||
|         strncpy(row_buffer, &fb[FB_WIDTH * i], FB_WIDTH); | ||||
|         fuprintf(log, "|%s|\n", row_buffer); | ||||
|     } | ||||
|     fuprintf(log, "+==========+\n"); | ||||
| } | ||||
| 
 | ||||
| void application_ipc_display(void* p) { | ||||
|     // get logger
 | ||||
|     FuriRecordSubscriber* log = get_default_log(); | ||||
| 
 | ||||
|     // create ASCII "framebuffer"
 | ||||
|     // FB_WIDTH x FB_HEIGHT char buffer
 | ||||
|     char _framebuffer[FB_SIZE]; | ||||
| 
 | ||||
|     // init framebuffer by spaces
 | ||||
|     for(size_t i = 0; i < FB_SIZE; i++) { | ||||
|         _framebuffer[i] = ' '; | ||||
|     } | ||||
| 
 | ||||
|     // create record
 | ||||
|     if(!furi_create_deprecated("test_fb", (void*)_framebuffer, FB_SIZE)) { | ||||
|         fuprintf(log, "[display] cannot create fb record\n"); | ||||
|         furiac_exit(NULL); | ||||
|     } | ||||
| 
 | ||||
|     StaticSemaphore_t event_descriptor; | ||||
|     // create stack-based counting semaphore
 | ||||
|     SemaphoreHandle_t events = xSemaphoreCreateCountingStatic(255, 0, &event_descriptor); | ||||
| 
 | ||||
|     if(events == NULL) { | ||||
|         fuprintf(log, "[display] cannot create event semaphore\n"); | ||||
|         furiac_exit(NULL); | ||||
|     } | ||||
| 
 | ||||
|     // save log and event queue in context structure
 | ||||
|     IpcCtx ctx = {.events = events, .log = log}; | ||||
| 
 | ||||
|     // subscribe to record. ctx will be passed to handle_fb_change
 | ||||
|     FuriRecordSubscriber* fb_record = | ||||
|         furi_open_deprecated("test_fb", false, false, handle_fb_change, NULL, &ctx); | ||||
| 
 | ||||
|     if(fb_record == NULL) { | ||||
|         fuprintf(log, "[display] cannot open fb record\n"); | ||||
|         furiac_exit(NULL); | ||||
|     } | ||||
| 
 | ||||
| #ifdef HW_DISPLAY | ||||
|     // on Flipper target -- open screen
 | ||||
| 
 | ||||
|     // draw border
 | ||||
| 
 | ||||
| #else | ||||
|     // on Local target -- print "blank screen"
 | ||||
|     { | ||||
|         void* fb = furi_take(fb_record); | ||||
|         print_fb((char*)fb, log); | ||||
|         furi_give(fb_record); | ||||
|     } | ||||
| #endif | ||||
| 
 | ||||
|     while(1) { | ||||
|         // wait for event
 | ||||
|         if(xSemaphoreTake(events, portMAX_DELAY) == pdTRUE) { | ||||
|             fuprintf(log, "[display] get fb update\n\n"); | ||||
| 
 | ||||
| #ifdef HW_DISPLAY | ||||
| // on Flipper target draw the screen
 | ||||
| #else | ||||
|             // on local target just print
 | ||||
|             { | ||||
|                 void* fb = furi_take(fb_record); | ||||
|                 print_fb((char*)fb, log); | ||||
|                 furi_give(fb_record); | ||||
|             } | ||||
| #endif | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| // Widget application
 | ||||
| void application_ipc_widget(void* p) { | ||||
|     FuriRecordSubscriber* log = get_default_log(); | ||||
| 
 | ||||
|     // open record
 | ||||
|     FuriRecordSubscriber* fb_record = | ||||
|         furi_open_deprecated("test_fb", false, false, NULL, NULL, NULL); | ||||
| 
 | ||||
|     if(fb_record == NULL) { | ||||
|         fuprintf(log, "[widget] cannot create fb record\n"); | ||||
|         furiac_exit(NULL); | ||||
|     } | ||||
| 
 | ||||
|     uint8_t counter = 0; | ||||
| 
 | ||||
|     while(1) { | ||||
|         delay(120); | ||||
| 
 | ||||
|         // write some ascii demo here: '#'' symbol run on overall screen
 | ||||
|         char* fb = (char*)furi_take(fb_record); | ||||
| 
 | ||||
|         if(fb == NULL) furiac_exit(NULL); | ||||
| 
 | ||||
|         for(size_t i = 0; i < FB_SIZE; i++) { | ||||
|             fb[i] = ' '; | ||||
|         } | ||||
| 
 | ||||
|         fb[counter % FB_SIZE] = '#'; | ||||
| 
 | ||||
|         furi_commit(fb_record); | ||||
| 
 | ||||
|         counter++; | ||||
|     } | ||||
| } | ||||
| @ -1,4 +1,5 @@ | ||||
| #include "flipper_v2.h" | ||||
| #include <furi.h> | ||||
| #include <input.h> | ||||
| 
 | ||||
| static void event_cb(const void* value, void* ctx) { | ||||
|     const InputEvent* event = value; | ||||
| @ -38,8 +39,7 @@ void application_strobe(void* p) { | ||||
|     ValueMutex delay_mutex; | ||||
|     init_mutex(&delay_mutex, &delay_time_holder, sizeof(delay_time_holder)); | ||||
| 
 | ||||
|     PubSub* event_record = furi_open("input_events"); | ||||
|     furi_check(event_record); | ||||
|     PubSub* event_record = furi_record_open("input_events"); | ||||
|     subscribe_pubsub(event_record, event_cb, &delay_mutex); | ||||
| 
 | ||||
|     while(1) { | ||||
|  | ||||
| @ -1,32 +1,14 @@ | ||||
| #include "u8g2/u8g2.h" | ||||
| #include "flipper.h" | ||||
| #include <furi.h> | ||||
| 
 | ||||
| void u8g2_example(void* p) { | ||||
|     FuriRecordSubscriber* log = get_default_log(); | ||||
| 
 | ||||
|     // open record
 | ||||
|     FuriRecordSubscriber* fb_record = | ||||
|         furi_open_deprecated("u8g2_fb", false, false, NULL, NULL, NULL); | ||||
|     u8g2_t* fb = furi_record_open("u8g2_fb"); | ||||
|     u8g2_SetFont(fb, u8g2_font_6x10_mf); | ||||
|     u8g2_SetDrawColor(fb, 1); | ||||
|     u8g2_SetFontMode(fb, 1); | ||||
|     u8g2_DrawStr(fb, 2, 12, "hello world!"); | ||||
|     furi_record_close("u8g2_fb"); | ||||
| 
 | ||||
|     if(fb_record == NULL) { | ||||
|         fuprintf(log, "[widget] cannot create fb record\n"); | ||||
|         furiac_exit(NULL); | ||||
|     } | ||||
| 
 | ||||
|     while(1) { | ||||
|         u8g2_t* fb = furi_take(fb_record); | ||||
|         if(fb != NULL) { | ||||
|             u8g2_SetFont(fb, u8g2_font_6x10_mf); | ||||
|             u8g2_SetDrawColor(fb, 1); | ||||
|             u8g2_SetFontMode(fb, 1); | ||||
|             u8g2_DrawStr(fb, 2, 12, "hello world!"); | ||||
|         } | ||||
|         furi_commit(fb_record); | ||||
| 
 | ||||
|         if(fb != NULL) { | ||||
|             furiac_exit(NULL); | ||||
|         } | ||||
| 
 | ||||
|         delay(1); | ||||
|     } | ||||
|     furiac_exit(NULL); | ||||
| } | ||||
| @ -1,6 +1,9 @@ | ||||
| #include "u8g2/u8g2.h" | ||||
| #include "qrcode/qrcode.h" | ||||
| #include "flipper.h" | ||||
| #include <furi.h> | ||||
| 
 | ||||
| /*
 | ||||
| TODO: rework with new app api | ||||
| 
 | ||||
| void u8g2_DrawPixelSize(u8g2_t* u8g2, uint8_t x, uint8_t y, uint8_t size) { | ||||
|     for(uint8_t px = 0; px < size; px++) { | ||||
| @ -11,8 +14,6 @@ void u8g2_DrawPixelSize(u8g2_t* u8g2, uint8_t x, uint8_t y, uint8_t size) { | ||||
| } | ||||
| 
 | ||||
| void u8g2_qrcode(void* p) { | ||||
|     FuriRecordSubscriber* log = get_default_log(); | ||||
| 
 | ||||
|     // open record
 | ||||
|     FuriRecordSubscriber* fb_record = | ||||
|         furi_open_deprecated("u8g2_fb", false, false, NULL, NULL, NULL); | ||||
| @ -36,7 +37,7 @@ void u8g2_qrcode(void* p) { | ||||
|     qrcode_initText(&qrcode, qrcodeBytes, qr_version, qr_error_correction, "HELLO FLIPPER"); | ||||
| 
 | ||||
|     if(fb_record == NULL) { | ||||
|         fuprintf(log, "[widget] cannot create fb record\n"); | ||||
|         printf("[widget] cannot create fb record\n"); | ||||
|         furiac_exit(NULL); | ||||
|     } | ||||
| 
 | ||||
| @ -69,4 +70,5 @@ void u8g2_qrcode(void* p) { | ||||
| 
 | ||||
|         delay(1); | ||||
|     } | ||||
| } | ||||
| } | ||||
| */ | ||||
| @ -1,7 +1,5 @@ | ||||
| #include "flipper.h" | ||||
| #include <furi.h> | ||||
| #include <string.h> | ||||
| #include "log.h" | ||||
| #include "flipper_v2.h" | ||||
| 
 | ||||
| void application_uart_write(void* p) { | ||||
|     // Red led for showing progress
 | ||||
| @ -11,12 +9,9 @@ void application_uart_write(void* p) { | ||||
| 
 | ||||
|     gpio_init(led_record, GpioModeOutputOpenDrain); | ||||
| 
 | ||||
|     // get_default_log open "tty" record
 | ||||
|     FuriRecordSubscriber* log = get_default_log(); | ||||
| 
 | ||||
|     // create buffer
 | ||||
|     const char test_string[] = "test\n"; | ||||
|     furi_write(log, test_string, strlen(test_string)); | ||||
|     printf(test_string); | ||||
| 
 | ||||
|     // for example, create counter and show its value
 | ||||
|     uint8_t counter = 0; | ||||
|  | ||||
| @ -1,4 +1,5 @@ | ||||
| #include "flipper_v2.h" | ||||
| #include <furi.h> | ||||
| #include <input/input.h> | ||||
| 
 | ||||
| typedef struct { | ||||
|     GpioPin* led; | ||||
| @ -24,7 +25,7 @@ void application_vibro(void* p) { | ||||
|     gpio_write(ctx.vibro, false); | ||||
| 
 | ||||
|     // subscribe on buttons
 | ||||
|     PubSub* event_record = furi_open("input_events"); | ||||
|     PubSub* event_record = furi_record_open("input_events"); | ||||
|     furi_check(event_record); | ||||
|     subscribe_pubsub(event_record, button_handler, &ctx); | ||||
| 
 | ||||
|  | ||||
| @ -1 +1 @@ | ||||
| Subproject commit 25a2cc076c3162aad721e0d92009cfa7b9100c7a | ||||
| Subproject commit 621044255a8be4d2c3f342e2b22178a342ccbfe8 | ||||
| @ -1,4 +1,6 @@ | ||||
| #include "flipper_v2.h" | ||||
| #include <furi.h> | ||||
| #include <gui/gui.h> | ||||
| #include <input/input.h> | ||||
| 
 | ||||
| typedef struct { | ||||
|     const char* name; | ||||
| @ -47,7 +49,7 @@ static void render_callback(Canvas* canvas, void* ctx) { | ||||
| } | ||||
| 
 | ||||
| static void input_callback(InputEvent* input_event, void* ctx) { | ||||
|     osMessageQueueId_t event_queue = (QueueHandle_t)ctx; | ||||
|     osMessageQueueId_t event_queue = ctx; | ||||
| 
 | ||||
|     AppEvent event; | ||||
|     event.type = EventTypeKey; | ||||
| @ -74,11 +76,7 @@ void app_gpio_test(void* p) { | ||||
|     widget_input_callback_set(widget, input_callback, event_queue); | ||||
| 
 | ||||
|     // Open GUI and register widget
 | ||||
|     Gui* gui = (Gui*)furi_open("gui"); | ||||
|     if(gui == NULL) { | ||||
|         printf("[gpio-tester] gui is not available\n"); | ||||
|         furiac_exit(NULL); | ||||
|     } | ||||
|     Gui* gui = furi_record_open("gui"); | ||||
|     gui_add_widget(gui, widget, GuiLayerFullscreen); | ||||
| 
 | ||||
|     // configure pin
 | ||||
|  | ||||
| @ -1,8 +1,7 @@ | ||||
| #include "canvas_i.h" | ||||
| #include "icon_i.h" | ||||
| 
 | ||||
| #include <flipper.h> | ||||
| #include <flipper_v2.h> | ||||
| #include <furi.h> | ||||
| 
 | ||||
| struct Canvas { | ||||
|     u8g2_t fb; | ||||
|  | ||||
| @ -5,6 +5,10 @@ | ||||
| #include <gui/icon.h> | ||||
| #include <assets_icons_i.h> | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| typedef enum { | ||||
|     ColorWhite = 0x00, | ||||
|     ColorBlack = 0x01, | ||||
| @ -91,3 +95,7 @@ void canvas_draw_line(Canvas* canvas, uint8_t x1, uint8_t y1, uint8_t x2, uint8_ | ||||
|  * Draw glyph | ||||
|  */ | ||||
| void canvas_draw_glyph(Canvas* canvas, uint8_t x, uint8_t y, uint16_t ch); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
| @ -3,6 +3,10 @@ | ||||
| #include <stdint.h> | ||||
| #include "canvas.h" | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| /*
 | ||||
|  * Draw scrollbar on canvas. | ||||
|  * width 3px, height equal to canvas height | ||||
| @ -17,3 +21,7 @@ void elements_scrollbar(Canvas* canvas, uint8_t pos, uint8_t total); | ||||
|  * @param width, height - frame width and height | ||||
|  */ | ||||
| void elements_frame(Canvas* canvas, uint8_t x, uint8_t y, uint8_t width, uint8_t height); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
| @ -1,8 +1,7 @@ | ||||
| #include "gui.h" | ||||
| #include "gui_i.h" | ||||
| 
 | ||||
| #include <flipper.h> | ||||
| #include <flipper_v2.h> | ||||
| #include <furi.h> | ||||
| #include <m-array.h> | ||||
| #include <stdio.h> | ||||
| 
 | ||||
| @ -207,13 +206,9 @@ Gui* gui_alloc() { | ||||
| 
 | ||||
| void gui_task(void* p) { | ||||
|     Gui* gui = gui_alloc(); | ||||
|     // Create FURI record
 | ||||
|     if(!furi_create("gui", gui)) { | ||||
|         printf("[gui_task] cannot create the gui record\n"); | ||||
|         furiac_exit(NULL); | ||||
|     } | ||||
| 
 | ||||
|     furiac_ready(); | ||||
|     // Create FURI record
 | ||||
|     furi_record_create("gui", gui); | ||||
| 
 | ||||
|     // Forever dispatch
 | ||||
|     while(1) { | ||||
|  | ||||
| @ -3,6 +3,10 @@ | ||||
| #include "widget.h" | ||||
| #include "canvas.h" | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| #define GUI_DISPLAY_WIDTH 128 | ||||
| #define GUI_DISPLAY_HEIGHT 64 | ||||
| 
 | ||||
| @ -40,3 +44,7 @@ void gui_add_widget(Gui* gui, Widget* widget, GuiLayer layer); | ||||
|  * @remarks thread safe | ||||
|  */ | ||||
| void gui_remove_widget(Gui* gui, Widget* widget); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| #include "gui_event.h" | ||||
| 
 | ||||
| #include <flipper_v2.h> | ||||
| #include <furi.h> | ||||
| 
 | ||||
| #define GUI_EVENT_MQUEUE_SIZE 8 | ||||
| 
 | ||||
| @ -45,7 +45,7 @@ GuiEvent* gui_event_alloc() { | ||||
|     // osTimerStart(gui_event->timer, 1024 / 4);
 | ||||
| 
 | ||||
|     // Input
 | ||||
|     gui_event->input_event_record = furi_open("input_events"); | ||||
|     gui_event->input_event_record = furi_record_open("input_events"); | ||||
|     furi_check(gui_event->input_event_record != NULL); | ||||
|     subscribe_pubsub(gui_event->input_event_record, gui_event_input_events_callback, gui_event); | ||||
| 
 | ||||
|  | ||||
| @ -3,6 +3,10 @@ | ||||
| #include <stdint.h> | ||||
| #include <input/input.h> | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| typedef enum { | ||||
|     GuiMessageTypeRedraw = 0x00, | ||||
|     GuiMessageTypeInput = 0x01, | ||||
| @ -23,3 +27,7 @@ void gui_event_free(GuiEvent* gui_event); | ||||
| void gui_event_messsage_send(GuiEvent* gui_event, GuiMessage* message); | ||||
| 
 | ||||
| GuiMessage gui_event_message_next(GuiEvent* gui_event); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
| @ -1,8 +1,6 @@ | ||||
| #include "icon_i.h" | ||||
| 
 | ||||
| #include <cmsis_os2.h> | ||||
| #include <flipper.h> | ||||
| #include <flipper_v2.h> | ||||
| #include <furi.h> | ||||
| 
 | ||||
| Icon* icon_alloc(const IconData* data) { | ||||
|     Icon* icon = furi_alloc(sizeof(Icon)); | ||||
|  | ||||
| @ -3,6 +3,10 @@ | ||||
| #include <stdint.h> | ||||
| #include <stdbool.h> | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| typedef struct IconData IconData; | ||||
| typedef struct Icon Icon; | ||||
| 
 | ||||
| @ -41,3 +45,7 @@ void icon_start_animation(Icon* icon); | ||||
|  * Stop icon animation | ||||
|  */ | ||||
| void icon_stop_animation(Icon* icon); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| #include "u8g2/u8g2.h" | ||||
| #include "flipper.h" | ||||
| #include <furi.h> | ||||
| #include <main.h> | ||||
| 
 | ||||
| extern SPI_HandleTypeDef SPI_D; | ||||
| @ -34,7 +34,7 @@ uint8_t u8g2_gpio_and_delay_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, vo | ||||
|     // Function to define the logic level of the RESET line
 | ||||
|     case U8X8_MSG_GPIO_RESET: | ||||
| #ifdef DEBUG | ||||
|         fuprintf(log, "[u8g2] rst %d\n", arg_int); | ||||
|         printf("[u8g2] rst %d\n", arg_int); | ||||
| #endif | ||||
| 
 | ||||
|         // TODO change it to FuriRecord pin
 | ||||
| @ -44,7 +44,7 @@ uint8_t u8g2_gpio_and_delay_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, vo | ||||
| 
 | ||||
|     default: | ||||
| #ifdef DEBUG | ||||
|         fufuprintf(log, "[u8g2] unknown io %d\n", msg); | ||||
|         printf("[u8g2] unknown io %d\n", msg); | ||||
| #endif | ||||
| 
 | ||||
|         return 0; //A message was received which is not implemented, return 0 to indicate an error
 | ||||
| @ -57,7 +57,7 @@ uint8_t u8x8_hw_spi_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_ | ||||
|     switch(msg) { | ||||
|     case U8X8_MSG_BYTE_SEND: | ||||
| #ifdef DEBUG | ||||
|         fuprintf(log, "[u8g2] send %d bytes %02X\n", arg_int, ((uint8_t*)arg_ptr)[0]); | ||||
|         printf("[u8g2] send %d bytes %02X\n", arg_int, ((uint8_t*)arg_ptr)[0]); | ||||
| #endif | ||||
| 
 | ||||
|         // TODO change it to FuriRecord SPI
 | ||||
| @ -66,7 +66,7 @@ uint8_t u8x8_hw_spi_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_ | ||||
| 
 | ||||
|     case U8X8_MSG_BYTE_SET_DC: | ||||
| #ifdef DEBUG | ||||
|         fuprintf(log, "[u8g2] dc %d\n", arg_int); | ||||
|         printf("[u8g2] dc %d\n", arg_int); | ||||
| #endif | ||||
| 
 | ||||
|         // TODO change it to FuriRecord pin
 | ||||
| @ -76,7 +76,7 @@ uint8_t u8x8_hw_spi_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_ | ||||
| 
 | ||||
|     case U8X8_MSG_BYTE_INIT: | ||||
| #ifdef DEBUG | ||||
|         fuprintf(log, "[u8g2] init\n"); | ||||
|         printf("[u8g2] init\n"); | ||||
| #endif | ||||
| 
 | ||||
|         // TODO change it to FuriRecord pin
 | ||||
| @ -85,7 +85,7 @@ uint8_t u8x8_hw_spi_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_ | ||||
| 
 | ||||
|     case U8X8_MSG_BYTE_START_TRANSFER: | ||||
| #ifdef DEBUG | ||||
|         fuprintf(log, "[u8g2] start\n"); | ||||
|         printf("[u8g2] start\n"); | ||||
| #endif | ||||
| 
 | ||||
|         // TODO: SPI manager
 | ||||
| @ -98,7 +98,7 @@ uint8_t u8x8_hw_spi_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_ | ||||
| 
 | ||||
|     case U8X8_MSG_BYTE_END_TRANSFER: | ||||
| #ifdef DEBUG | ||||
|         fuprintf(log, "[u8g2] end\n"); | ||||
|         printf("[u8g2] end\n"); | ||||
| #endif | ||||
| 
 | ||||
|         asm("nop"); | ||||
| @ -112,7 +112,7 @@ uint8_t u8x8_hw_spi_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_ | ||||
| 
 | ||||
|     default: | ||||
| #ifdef DEBUG | ||||
|         fuprintf(log, "[u8g2] unknown xfer %d\n", msg); | ||||
|         printf("[u8g2] unknown xfer %d\n", msg); | ||||
| #endif | ||||
| 
 | ||||
|         return 0; | ||||
|  | ||||
| @ -3,6 +3,10 @@ | ||||
| #include <input/input.h> | ||||
| #include "canvas.h" | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| /* Hides drawing widget */ | ||||
| #define VIEW_NONE 0xFFFFFFFF | ||||
| /* Ignore navigation event */ | ||||
| @ -127,3 +131,7 @@ void view_commit_model(View* view); | ||||
|         ({ void __fn__ function_body __fn__; })(p); \ | ||||
|         view_commit_model(view);                    \ | ||||
|     } | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
| @ -3,6 +3,10 @@ | ||||
| #include "view.h" | ||||
| #include "gui.h" | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| /* ViewDispatcher widget placement */ | ||||
| typedef enum { | ||||
|     ViewDispatcherTypeNone, /* Special layer for internal use only */ | ||||
| @ -43,3 +47,7 @@ void view_dispatcher_attach_to_gui( | ||||
|     ViewDispatcher* view_dispatcher, | ||||
|     Gui* gui, | ||||
|     ViewDispatcherType type); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
| @ -2,7 +2,7 @@ | ||||
| 
 | ||||
| #include "view_dispatcher.h" | ||||
| #include "view_i.h" | ||||
| #include <flipper_v2.h> | ||||
| #include <furi.h> | ||||
| #include <m-dict.h> | ||||
| 
 | ||||
| DICT_DEF2(ViewDict, uint32_t, M_DEFAULT_OPLIST, View*, M_PTR_OPLIST) | ||||
|  | ||||
| @ -2,7 +2,7 @@ | ||||
| 
 | ||||
| #include "view.h" | ||||
| #include "view_dispatcher_i.h" | ||||
| #include <flipper_v2.h> | ||||
| #include <furi.h> | ||||
| 
 | ||||
| typedef struct { | ||||
|     void* data; | ||||
|  | ||||
| @ -1,8 +1,6 @@ | ||||
| #include "widget_i.h" | ||||
| 
 | ||||
| #include <cmsis_os.h> | ||||
| #include <flipper.h> | ||||
| #include <flipper_v2.h> | ||||
| #include <furi.h> | ||||
| 
 | ||||
| #include "gui.h" | ||||
| #include "gui_i.h" | ||||
| @ -73,8 +71,6 @@ void widget_update(Widget* widget) { | ||||
| 
 | ||||
| void widget_gui_set(Widget* widget, Gui* gui) { | ||||
|     furi_assert(widget); | ||||
|     furi_assert(gui); | ||||
| 
 | ||||
|     widget->gui = gui; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -3,6 +3,10 @@ | ||||
| #include <input/input.h> | ||||
| #include "canvas.h" | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| typedef struct Widget Widget; | ||||
| 
 | ||||
| /*
 | ||||
| @ -65,3 +69,7 @@ void widget_input_callback_set(Widget* widget, WidgetInputCallback callback, voi | ||||
|  * Rendering will happen later after GUI system process signal. | ||||
|  */ | ||||
| void widget_update(Widget* widget); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
| @ -32,7 +32,7 @@ void AppiButton::run() { | ||||
|                     printf("[ibutton] bye!\n"); | ||||
|                     // TODO remove all widgets create by app
 | ||||
|                     widget_enabled_set(widget, false); | ||||
|                     furiac_exit(NULL); | ||||
|                     osThreadExit(); | ||||
|                 } | ||||
| 
 | ||||
|                 if(event.value.input.state && event.value.input.input == InputLeft) { | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| #include <input/input.h> | ||||
| #include <stdio.h> | ||||
| #include <flipper_v2.h> | ||||
| #include <furi.h> | ||||
| 
 | ||||
| #ifdef APP_NFC | ||||
| void nfc_isr(void); | ||||
| @ -35,18 +35,10 @@ void input_task(void* p) { | ||||
|         furiac_exit(NULL); | ||||
|     } | ||||
| 
 | ||||
|     if(!furi_create("input_state", &input_state_record)) { | ||||
|         printf("[input_task] cannot create the input_state record\n"); | ||||
|         furiac_exit(NULL); | ||||
|     } | ||||
| 
 | ||||
|     if(!furi_create("input_events", &input_events_record)) { | ||||
|         printf("[input_task] cannot create the input_events record\n"); | ||||
|         furiac_exit(NULL); | ||||
|     } | ||||
|     furi_record_create("input_state", &input_state_record); | ||||
|     furi_record_create("input_events", &input_events_record); | ||||
| 
 | ||||
|     // we ready to work
 | ||||
|     furiac_ready(); | ||||
|     initialized = true; | ||||
| 
 | ||||
|     // Force state update
 | ||||
|  | ||||
| @ -1,6 +1,5 @@ | ||||
| #pragma once | ||||
| #include "flipper.h" | ||||
| #include "flipper_v2.h" | ||||
| #include <furi.h> | ||||
| #include "irda-decoder-nec.h" | ||||
| #include "irda-decoder-types.h" | ||||
| 
 | ||||
|  | ||||
| @ -1,5 +1,7 @@ | ||||
| #include "flipper.h" | ||||
| #include "flipper_v2.h" | ||||
| #include <furi.h> | ||||
| #include <gui/gui.h> | ||||
| #include <input/input.h> | ||||
| 
 | ||||
| #include "irda_nec.h" | ||||
| #include "irda_samsung.h" | ||||
| #include "irda_protocols.h" | ||||
| @ -185,7 +187,7 @@ static void render_callback(Canvas* canvas, void* ctx) { | ||||
| } | ||||
| 
 | ||||
| static void input_callback(InputEvent* input_event, void* ctx) { | ||||
|     osMessageQueueId_t event_queue = (QueueHandle_t)ctx; | ||||
|     osMessageQueueId_t event_queue = ctx; | ||||
| 
 | ||||
|     AppEvent event; | ||||
|     event.type = EventTypeKey; | ||||
| @ -271,11 +273,7 @@ void irda(void* p) { | ||||
|     widget_input_callback_set(widget, input_callback, event_queue); | ||||
| 
 | ||||
|     // Open GUI and register widget
 | ||||
|     Gui* gui = (Gui*)furi_open("gui"); | ||||
|     if(gui == NULL) { | ||||
|         printf("gui is not available\n"); | ||||
|         furiac_exit(NULL); | ||||
|     } | ||||
|     Gui* gui = furi_record_open("gui"); | ||||
|     gui_add_widget(gui, widget, GuiLayerFullscreen); | ||||
| 
 | ||||
|     // Red LED
 | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| #include "flipper.h" | ||||
| #include <furi.h> | ||||
| #include "irda_nec.h" | ||||
| #include "irda_protocols.h" | ||||
| 
 | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| #pragma once | ||||
| #include "flipper.h" | ||||
| #include <furi.h> | ||||
| 
 | ||||
| void ir_nec_send(uint16_t addr, uint8_t data); | ||||
| @ -1,4 +1,4 @@ | ||||
| #include "flipper.h" | ||||
| #include <furi.h> | ||||
| #include "irda_samsung.h" | ||||
| #include "irda_protocols.h" | ||||
| 
 | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| #pragma once | ||||
| #include "flipper.h" | ||||
| #include <furi.h> | ||||
| 
 | ||||
| void ir_samsung_send(uint16_t addr, uint16_t data); | ||||
| @ -1,4 +1,4 @@ | ||||
| #include "flipper_v2.h" | ||||
| #include <furi.h> | ||||
| 
 | ||||
| void prepare_data(uint32_t ID, uint32_t VENDOR, uint8_t* data) { | ||||
|     uint8_t value[10]; | ||||
|  | ||||
| @ -1,4 +1,5 @@ | ||||
| #include "flipper_v2.h" | ||||
| #include <furi.h> | ||||
| #include <gui/gui.h> | ||||
| 
 | ||||
| typedef enum { EventTypeTick, EventTypeKey, EventTypeRx } EventType; | ||||
| 
 | ||||
| @ -45,7 +46,7 @@ static void render_callback(Canvas* canvas, void* ctx) { | ||||
| } | ||||
| 
 | ||||
| static void input_callback(InputEvent* input_event, void* ctx) { | ||||
|     osMessageQueueId_t event_queue = (QueueHandle_t)ctx; | ||||
|     osMessageQueueId_t event_queue = ctx; | ||||
| 
 | ||||
|     AppEvent event; | ||||
|     event.type = EventTypeKey; | ||||
| @ -67,7 +68,7 @@ void comparator_trigger_callback(void* hcomp, void* comp_ctx) { | ||||
| 
 | ||||
|     // gpio_write(&debug_0, true);
 | ||||
| 
 | ||||
|     osMessageQueueId_t event_queue = (QueueHandle_t)comp_ctx; | ||||
|     osMessageQueueId_t event_queue = comp_ctx; | ||||
| 
 | ||||
|     AppEvent event; | ||||
|     event.type = EventTypeRx; | ||||
| @ -202,11 +203,7 @@ void lf_rfid_workaround(void* p) { | ||||
|     widget_input_callback_set(widget, input_callback, event_queue); | ||||
| 
 | ||||
|     // Open GUI and register widget
 | ||||
|     Gui* gui = (Gui*)furi_open("gui"); | ||||
|     if(gui == NULL) { | ||||
|         printf("gui is not available\n"); | ||||
|         furiac_exit(NULL); | ||||
|     } | ||||
|     Gui* gui = furi_record_open("gui"); | ||||
|     gui_add_widget(gui, widget, GuiLayerFullscreen); | ||||
| 
 | ||||
|     AppEvent event; | ||||
|  | ||||
| @ -1,9 +1,8 @@ | ||||
| #include "menu.h" | ||||
| #include <cmsis_os.h> | ||||
| #include <stdio.h> | ||||
| #include <stdbool.h> | ||||
| 
 | ||||
| #include <flipper_v2.h> | ||||
| #include <furi.h> | ||||
| #include <gui/gui.h> | ||||
| #include <gui/elements.h> | ||||
| 
 | ||||
| @ -42,8 +41,7 @@ ValueMutex* menu_init() { | ||||
|     menu->widget = widget_alloc(); | ||||
| 
 | ||||
|     // Open GUI and register fullscreen widget
 | ||||
|     Gui* gui = furi_open("gui"); | ||||
|     furi_check(gui); | ||||
|     Gui* gui = furi_record_open("gui"); | ||||
|     gui_add_widget(gui, menu->widget, GuiLayerFullscreen); | ||||
| 
 | ||||
|     widget_enabled_set(menu->widget, false); | ||||
| @ -237,12 +235,7 @@ void menu_task(void* p) { | ||||
|         release_mutex(menu_mutex, menu); | ||||
|     } | ||||
| 
 | ||||
|     if(!furi_create("menu", menu_mutex)) { | ||||
|         printf("[menu_task] cannot create the menu record\n"); | ||||
|         furiac_exit(NULL); | ||||
|     } | ||||
| 
 | ||||
|     furiac_ready(); | ||||
|     furi_record_create("menu", menu_mutex); | ||||
| 
 | ||||
|     while(1) { | ||||
|         MenuMessage m = menu_event_next(menu_event); | ||||
|  | ||||
| @ -1,11 +1,9 @@ | ||||
| #include "menu_event.h" | ||||
| 
 | ||||
| #include <cmsis_os.h> | ||||
| #include <string.h> | ||||
| #include <stdlib.h> | ||||
| 
 | ||||
| #include <flipper.h> | ||||
| #include <flipper_v2.h> | ||||
| #include <furi.h> | ||||
| 
 | ||||
| #define MENU_MESSAGE_MQUEUE_SIZE 8 | ||||
| 
 | ||||
|  | ||||
| @ -1,8 +1,7 @@ | ||||
| #include "menu_item.h" | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <flipper.h> | ||||
| #include <flipper_v2.h> | ||||
| #include <furi.h> | ||||
| 
 | ||||
| struct MenuItem { | ||||
|     MenuItemType type; | ||||
|  | ||||
| @ -1,4 +1,6 @@ | ||||
| #include "flipper_v2.h" | ||||
| #include <furi.h> | ||||
| #include <gui/gui.h> | ||||
| #include <input/input.h> | ||||
| 
 | ||||
| // TODO float note freq
 | ||||
| typedef enum { | ||||
| @ -302,7 +304,7 @@ static void render_callback(Canvas* canvas, void* ctx) { | ||||
| } | ||||
| 
 | ||||
| static void input_callback(InputEvent* input_event, void* ctx) { | ||||
|     osMessageQueueId_t event_queue = (QueueHandle_t)ctx; | ||||
|     osMessageQueueId_t event_queue = ctx; | ||||
| 
 | ||||
|     MusicDemoEvent event; | ||||
|     event.type = EventTypeKey; | ||||
| @ -376,15 +378,11 @@ void music_player(void* p) { | ||||
|     widget_input_callback_set(widget, input_callback, event_queue); | ||||
| 
 | ||||
|     // Open GUI and register widget
 | ||||
|     Gui* gui = (Gui*)furi_open("gui"); | ||||
|     if(gui == NULL) { | ||||
|         printf("gui is not available\n"); | ||||
|         furiac_exit(NULL); | ||||
|     } | ||||
|     Gui* gui = furi_record_open("gui"); | ||||
|     gui_add_widget(gui, widget, GuiLayerFullscreen); | ||||
| 
 | ||||
|     // open input record
 | ||||
|     PubSub* input_events_record = furi_open("input_events"); | ||||
|     PubSub* input_events_record = furi_record_open("input_events"); | ||||
|     // prepare "do nothing" event
 | ||||
|     InputEvent input_event = {InputRight, true}; | ||||
| 
 | ||||
|  | ||||
| @ -16,8 +16,7 @@ Nfc* nfc_alloc() { | ||||
|     nfc->worker = nfc_worker_alloc(nfc->message_queue); | ||||
| 
 | ||||
|     nfc->icon = assets_icons_get(A_NFC_14); | ||||
|     nfc->menu_vm = furi_open("menu"); | ||||
|     furi_check(nfc->menu_vm); | ||||
|     nfc->menu_vm = furi_record_open("menu"); | ||||
| 
 | ||||
|     nfc->menu = menu_item_alloc_menu("NFC", nfc->icon); | ||||
|     menu_item_subitem_add( | ||||
| @ -102,18 +101,13 @@ void nfc_start(Nfc* nfc, NfcView view_id, NfcWorkerState worker_state) { | ||||
| void nfc_task(void* p) { | ||||
|     Nfc* nfc = nfc_alloc(); | ||||
| 
 | ||||
|     Gui* gui = furi_open("gui"); | ||||
|     Gui* gui = furi_record_open("gui"); | ||||
|     view_dispatcher_attach_to_gui(nfc->view_dispatcher, gui, ViewDispatcherTypeFullscreen); | ||||
| 
 | ||||
|     with_value_mutex( | ||||
|         nfc->menu_vm, (Menu * menu) { menu_item_add(menu, nfc->menu); }); | ||||
| 
 | ||||
|     if(!furi_create("nfc", nfc)) { | ||||
|         printf("[nfc_task] cannot create nfc record\n"); | ||||
|         furiac_exit(NULL); | ||||
|     } | ||||
| 
 | ||||
|     furiac_ready(); | ||||
|     furi_record_create("nfc", nfc); | ||||
| 
 | ||||
|     NfcMessage message; | ||||
|     while(1) { | ||||
|  | ||||
| @ -5,7 +5,7 @@ | ||||
| #include "nfc_views.h" | ||||
| #include "nfc_worker.h" | ||||
| 
 | ||||
| #include <flipper_v2.h> | ||||
| #include <furi.h> | ||||
| 
 | ||||
| #include <gui/gui.h> | ||||
| #include <gui/view.h> | ||||
|  | ||||
| @ -3,7 +3,7 @@ | ||||
| #include <stdint.h> | ||||
| #include <stdbool.h> | ||||
| #include <gui/canvas.h> | ||||
| #include <flipper_v2.h> | ||||
| #include <furi.h> | ||||
| 
 | ||||
| #include "nfc_types.h" | ||||
| 
 | ||||
|  | ||||
| @ -3,8 +3,7 @@ | ||||
| #include "nfc_types.h" | ||||
| #include "nfc_worker.h" | ||||
| 
 | ||||
| #include <flipper_v2.h> | ||||
| #include <cmsis_os2.h> | ||||
| #include <furi.h> | ||||
| #include <stdbool.h> | ||||
| 
 | ||||
| #include <rfal_analogConfig.h> | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| #include "power.h" | ||||
| #include "power_views.h" | ||||
| 
 | ||||
| #include <flipper_v2.h> | ||||
| #include <furi.h> | ||||
| 
 | ||||
| #include <menu/menu.h> | ||||
| #include <menu/menu_item.h> | ||||
| @ -12,8 +12,8 @@ | ||||
| #include <gui/view_dispatcher.h> | ||||
| 
 | ||||
| #include <assets_icons.h> | ||||
| #include <api-hal-power.h> | ||||
| #include <cli/cli.h> | ||||
| #include <stm32wbxx.h> | ||||
| 
 | ||||
| struct Power { | ||||
|     ViewDispatcher* view_dispatcher; | ||||
| @ -47,6 +47,10 @@ void power_draw_battery_callback(Canvas* canvas, void* context) { | ||||
|         }); | ||||
| } | ||||
| 
 | ||||
| uint32_t power_info_back_callback(void* context) { | ||||
|     return VIEW_NONE; | ||||
| } | ||||
| 
 | ||||
| void power_menu_off_callback(void* context) { | ||||
|     api_hal_power_off(); | ||||
| } | ||||
| @ -71,10 +75,9 @@ void power_menu_info_callback(void* context) { | ||||
| Power* power_alloc() { | ||||
|     Power* power = furi_alloc(sizeof(Power)); | ||||
| 
 | ||||
|     power->menu_vm = furi_open("menu"); | ||||
|     furi_check(power->menu_vm); | ||||
|     power->menu_vm = furi_record_open("menu"); | ||||
| 
 | ||||
|     power->cli = furi_open("cli"); | ||||
|     power->cli = furi_record_open("cli"); | ||||
| 
 | ||||
|     power->menu = menu_item_alloc_menu("Power", NULL); | ||||
|     menu_item_subitem_add( | ||||
| @ -163,7 +166,7 @@ void power_task(void* p) { | ||||
|         cli_add_command(power->cli, "power_otg_off", power_cli_otg_off, power); | ||||
|     } | ||||
| 
 | ||||
|     Gui* gui = furi_open("gui"); | ||||
|     Gui* gui = furi_record_open("gui"); | ||||
|     gui_add_widget(gui, power->usb_widget, GuiLayerStatusBarLeft); | ||||
|     gui_add_widget(gui, power->battery_widget, GuiLayerStatusBarRight); | ||||
|     view_dispatcher_attach_to_gui(power->view_dispatcher, gui, ViewDispatcherTypeFullscreen); | ||||
| @ -171,14 +174,9 @@ void power_task(void* p) { | ||||
|     with_value_mutex( | ||||
|         power->menu_vm, (Menu * menu) { menu_item_add(menu, power->menu); }); | ||||
| 
 | ||||
|     if(!furi_create("power", power)) { | ||||
|         printf("[power_task] unable to create power record\n"); | ||||
|         furiac_exit(NULL); | ||||
|     } | ||||
| 
 | ||||
|     api_hal_power_init(); | ||||
| 
 | ||||
|     furiac_ready(); | ||||
|     furi_record_create("power", power); | ||||
| 
 | ||||
|     while(1) { | ||||
|         with_view_model( | ||||
|  | ||||
| @ -2,8 +2,8 @@ | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| #include <stdbool.h> | ||||
| #include <furi.h> | ||||
| #include <gui/canvas.h> | ||||
| #include <flipper_v2.h> | ||||
| #include <gui/view.h> | ||||
| 
 | ||||
| typedef enum { PowerViewInfo } PowerView; | ||||
| @ -24,8 +24,4 @@ typedef struct { | ||||
|     uint8_t charge; | ||||
| } PowerInfoModel; | ||||
| 
 | ||||
| static uint32_t power_info_back_callback(void* context) { | ||||
|     return VIEW_NONE; | ||||
| } | ||||
| 
 | ||||
| void power_info_draw_callback(Canvas* canvas, void* context); | ||||
|  | ||||
| @ -104,23 +104,21 @@ void SdTest::run() { | ||||
| 
 | ||||
|     app_ready(); | ||||
| 
 | ||||
|     fs_api = static_cast<FS_Api*>(furi_open("sdcard")); | ||||
|     fs_api = static_cast<FS_Api*>(furi_record_open("sdcard")); | ||||
| 
 | ||||
|     if(fs_api == NULL) { | ||||
|         set_error({"cannot get sdcard api"}); | ||||
|         exit(); | ||||
|     } | ||||
| 
 | ||||
|     Cli* cli = static_cast<Cli*>(furi_open("cli")); | ||||
|     Cli* cli = static_cast<Cli*>(furi_record_open("cli")); | ||||
| 
 | ||||
|     if(cli != NULL) { | ||||
|         // read_benchmark and write_benchmark signatures are same. so we must use tags
 | ||||
|         auto cli_read_cb = cbc::obtain_connector<0>(this, &SdTest::cli_read_benchmark); | ||||
|         cli_add_command(cli, "sd_read_test", cli_read_cb, this); | ||||
|     // read_benchmark and write_benchmark signatures are same. so we must use tags
 | ||||
|     auto cli_read_cb = cbc::obtain_connector<0>(this, &SdTest::cli_read_benchmark); | ||||
|     cli_add_command(cli, "sd_read_test", cli_read_cb, this); | ||||
| 
 | ||||
|         auto cli_write_cb = cbc::obtain_connector<1>(this, &SdTest::cli_write_benchmark); | ||||
|         cli_add_command(cli, "sd_write_test", cli_write_cb, this); | ||||
|     } | ||||
|     auto cli_write_cb = cbc::obtain_connector<1>(this, &SdTest::cli_write_benchmark); | ||||
|     cli_add_command(cli, "sd_write_test", cli_write_cb, this); | ||||
| 
 | ||||
|     detect_sd_card(); | ||||
|     get_sd_card_info(); | ||||
| @ -893,6 +891,7 @@ template <class T> void SdTest::set_text(std::initializer_list<T> list) { | ||||
| 
 | ||||
|     printf("------------------------\n"); | ||||
|     release_state(); | ||||
|     update_gui(); | ||||
| } | ||||
| 
 | ||||
| // render app
 | ||||
|  | ||||
| @ -480,22 +480,19 @@ void sd_filesystem(void* p) { | ||||
|     SdApp* sd_app = sd_app_alloc(); | ||||
|     FS_Api* fs_api = fs_api_alloc(); | ||||
| 
 | ||||
|     Gui* gui = furi_open("gui"); | ||||
|     Gui* gui = furi_record_open("gui"); | ||||
|     Cli* cli = furi_record_open("cli"); | ||||
|     ValueMutex* menu_vm = furi_record_open("menu"); | ||||
| 
 | ||||
|     gui_add_widget(gui, sd_app->widget, GuiLayerFullscreen); | ||||
|     gui_add_widget(gui, sd_app->icon.widget, GuiLayerStatusBarLeft); | ||||
| 
 | ||||
|     Cli* cli = furi_open("cli"); | ||||
| 
 | ||||
|     if(cli != NULL) { | ||||
|         cli_add_command(cli, "sd_status", cli_sd_status, sd_app); | ||||
|         cli_add_command(cli, "sd_format", cli_sd_format, sd_app); | ||||
|         cli_add_command(cli, "sd_info", cli_sd_info, sd_app); | ||||
|     } | ||||
|     cli_add_command(cli, "sd_status", cli_sd_status, sd_app); | ||||
|     cli_add_command(cli, "sd_format", cli_sd_format, sd_app); | ||||
|     cli_add_command(cli, "sd_info", cli_sd_info, sd_app); | ||||
| 
 | ||||
|     // add api record
 | ||||
|     if(!furi_create("sdcard", fs_api)) { | ||||
|         furiac_exit(NULL); | ||||
|     } | ||||
|     furi_record_create("sdcard", fs_api); | ||||
| 
 | ||||
|     // init menu
 | ||||
|     // TODO menu icon
 | ||||
| @ -510,15 +507,15 @@ void sd_filesystem(void* p) { | ||||
|         menu_item, menu_item_alloc_function("Eject", NULL, app_sd_eject_callback, sd_app)); | ||||
| 
 | ||||
|     // add item to menu
 | ||||
|     ValueMutex* menu_vm = furi_open("menu"); | ||||
|     furi_check(menu_vm); | ||||
|     with_value_mutex( | ||||
|         menu_vm, (Menu * menu) { menu_item_add(menu, menu_item); }); | ||||
| 
 | ||||
|     furiac_ready(); | ||||
| 
 | ||||
|     printf("[sd_filesystem] start\n"); | ||||
| 
 | ||||
|     // add api record
 | ||||
|     furi_record_create("sdcard", fs_api); | ||||
| 
 | ||||
|     // sd card cycle
 | ||||
|     bool sd_was_present = true; | ||||
| 
 | ||||
|  | ||||
| @ -1,6 +1,8 @@ | ||||
| #pragma once | ||||
| #include "flipper.h" | ||||
| #include "flipper_v2.h" | ||||
| 
 | ||||
| #include <furi.h> | ||||
| #include <gui/gui.h> | ||||
| #include <input/input.h> | ||||
| 
 | ||||
| #define SD_FS_MAX_FILES _FS_LOCK | ||||
| #define SD_STATE_LINES_COUNT 6 | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| #include "flipper_v2.h" | ||||
| #include <furi.h> | ||||
| 
 | ||||
| typedef enum { | ||||
|     EventTypeTick, | ||||
| @ -54,7 +54,7 @@ void template_app(void* p) { | ||||
|     widget_input_callback_set(widget, input_callback, event_queue); | ||||
| 
 | ||||
|     // Open GUI and register widget | ||||
|     Gui* gui = (Gui*)furi_open("gui"); | ||||
|     Gui* gui = furi_record_open("gui"); | ||||
|     if(gui == NULL) { | ||||
|         printf("gui is not available\n"); | ||||
|         furiac_exit(NULL); | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| #include "flipper_v2.h" | ||||
| #include <furi.h> | ||||
| #include "minunit.h" | ||||
| 
 | ||||
| static void furi_concurent_app(void* p) { | ||||
| @ -10,7 +10,9 @@ static void furi_concurent_app(void* p) { | ||||
| } | ||||
| 
 | ||||
| void test_furi_event() { | ||||
|     Event event; | ||||
|     mu_assert(false, "please reimplement or delete test"); | ||||
| 
 | ||||
|     /*Event event;
 | ||||
| 
 | ||||
|     mu_check(init_event(&event)); | ||||
| 
 | ||||
| @ -27,5 +29,5 @@ void test_furi_event() { | ||||
|     // The event should not be signalled once it's processed
 | ||||
|     mu_check(!wait_event_with_timeout(&event, 100)); | ||||
| 
 | ||||
|     mu_check(delete_event(&event)); | ||||
|     mu_check(delete_event(&event));*/ | ||||
| } | ||||
|  | ||||
| @ -1,8 +1,6 @@ | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #include "flipper_v2.h" | ||||
| #include "log.h" | ||||
| 
 | ||||
| #include <furi.h> | ||||
| #include "minunit.h" | ||||
| 
 | ||||
| const uint32_t context_value = 0xdeadbeef; | ||||
|  | ||||
| @ -1,16 +1,14 @@ | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #include "flipper.h" | ||||
| #include "flipper_v2.h" | ||||
| #include "log.h" | ||||
| #include <furi.h> | ||||
| #include "minunit.h" | ||||
| 
 | ||||
| void test_furi_create_open() { | ||||
|     // 1. Create record
 | ||||
|     uint8_t test_data = 0; | ||||
|     mu_check(furi_create("test/holding", (void*)&test_data)); | ||||
|     furi_record_create("test/holding", (void*)&test_data); | ||||
| 
 | ||||
|     // 2. Open it
 | ||||
|     void* record = furi_open("test/holding"); | ||||
|     void* record = furi_record_open("test/holding"); | ||||
|     mu_assert_pointers_eq(record, &test_data); | ||||
| } | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| #include "flipper_v2.h" | ||||
| #include <furi.h> | ||||
| #include "minunit.h" | ||||
| #include <stdint.h> | ||||
| 
 | ||||
|  | ||||
| @ -1,7 +1,6 @@ | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #include "flipper_v2.h" | ||||
| #include "log.h" | ||||
| #include <furi.h> | ||||
| 
 | ||||
| #include "minunit.h" | ||||
| 
 | ||||
| @ -88,6 +87,8 @@ void furi_concurent_app(void* p) { | ||||
| } | ||||
| 
 | ||||
| void test_furi_concurrent_access() { | ||||
|     mu_assert(false, "please reimplement or delete test"); | ||||
|     /*
 | ||||
|     // 1. Create holding record
 | ||||
|     ConcurrentValue value = {.a = 0, .b = 0}; | ||||
|     ValueMutex mutex; | ||||
| @ -123,4 +124,5 @@ void test_furi_concurrent_access() { | ||||
|     mu_assert_int_eq(value.a, value.b); | ||||
| 
 | ||||
|     mu_check(delete_mutex(&mutex)); | ||||
|     */ | ||||
| } | ||||
| @ -1,7 +1,6 @@ | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #include "flipper.h" | ||||
| #include "log.h" | ||||
| #include <furi.h> | ||||
| 
 | ||||
| /*
 | ||||
| Test: creating and killing task | ||||
| @ -24,6 +23,8 @@ void create_kill_app(void* p) { | ||||
| } | ||||
| 
 | ||||
| bool test_furi_ac_create_kill() { | ||||
|     mu_assert(false, "please reimplement or delete test"); | ||||
|     /*
 | ||||
|     uint8_t counter = 0; | ||||
| 
 | ||||
|     uint8_t value_a = counter; | ||||
| @ -56,6 +57,7 @@ bool test_furi_ac_create_kill() { | ||||
|     } | ||||
| 
 | ||||
|     return true; | ||||
|     */ | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  | ||||
| @ -1,6 +1,5 @@ | ||||
| #include <stdio.h> | ||||
| #include "flipper.h" | ||||
| #include "log.h" | ||||
| #include <furi.h> | ||||
| #include "minunit_vars.h" | ||||
| #include "minunit.h" | ||||
| 
 | ||||
|  | ||||
| @ -1,7 +1,5 @@ | ||||
| #include <stdio.h> | ||||
| #include "flipper.h" | ||||
| #include "flipper_v2.h" | ||||
| #include "log.h" | ||||
| #include <furi.h> | ||||
| 
 | ||||
| // #include "flipper-core.h" TODO: Rust build disabled
 | ||||
| 
 | ||||
|  | ||||
| @ -1,47 +0,0 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include "flipper.h" | ||||
| 
 | ||||
| // == Flipper Application control (flapp) ==
 | ||||
| 
 | ||||
| typedef FlappHandler uint32_t; // TODO
 | ||||
| 
 | ||||
| /*
 | ||||
| simply starts application. It call `app` entrypoint with `param` passed as argument | ||||
| Useful for daemon applications and pop-up. | ||||
| */ | ||||
| FlappHandler* flapp_start(void(app*)(void*), char* name, void* param); | ||||
| 
 | ||||
| /*
 | ||||
| swtich to other application. | ||||
| System **stop current app**, call `app` entrypoint with `param` passed | ||||
| as argument and save current application entrypoint to `prev` field in | ||||
| current application registry. Useful for UI or "active" application. | ||||
| */ | ||||
| FlappHandler* flapp_switch(void(app*)(void*), char* name, void* param); | ||||
| 
 | ||||
| /*
 | ||||
| Exit application | ||||
| stop current application (stop thread and clear application's stack), | ||||
| start application from `prev` entry in current application registry, | ||||
| cleanup current application registry. | ||||
| */ | ||||
| void flapp_exit(void* param); | ||||
| 
 | ||||
| /*
 | ||||
| stop specified `app` without returning to `prev` application. | ||||
| */ | ||||
| bool flapp_kill(FlappHandler* app); | ||||
| 
 | ||||
| /*
 | ||||
| If case one app depend on other, notify that app is ready. | ||||
| */ | ||||
| void flapp_ready(); | ||||
| 
 | ||||
| /*
 | ||||
| Register on-exit callback. | ||||
| It called before app will be killed. | ||||
| Not recommended to use in user scenario, only for system purpose | ||||
| (unregister callbacks, release mutexes, etc.) | ||||
| */ | ||||
| bool flapp_on_exit(void(cb*)(void*), void* ctx); | ||||
| @ -1,14 +0,0 @@ | ||||
| #include "furi.h" | ||||
| #include "furi-deprecated.h" | ||||
| 
 | ||||
| bool furi_create(const char* name, void* ptr) { | ||||
|     return furi_create_deprecated(name, ptr, sizeof(size_t)); | ||||
| } | ||||
| 
 | ||||
| void* furi_open(const char* name) { | ||||
|     FuriRecordSubscriber* record = furi_open_deprecated(name, false, false, NULL, NULL, NULL); | ||||
|     void* res = furi_take(record); | ||||
|     furi_give(record); | ||||
| 
 | ||||
|     return res; | ||||
| } | ||||
| @ -1,26 +0,0 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include "flipper.h" | ||||
| 
 | ||||
| /*
 | ||||
| == Flipper universal registry implementation (FURI) == | ||||
| 
 | ||||
| ## Requirements | ||||
| 
 | ||||
| * start daemon app | ||||
| * kill app | ||||
| * start child thread (kill when parent app was killed) | ||||
| * switch between UI apps | ||||
| */ | ||||
| 
 | ||||
| /*
 | ||||
| Create record. | ||||
| creates new record in registry and store pointer into it | ||||
| */ | ||||
| bool furi_create(const char* name, void* ptr); | ||||
| 
 | ||||
| /*
 | ||||
| Open record. | ||||
| get stored pointer by its name | ||||
| */ | ||||
| void* furi_open(const char* name); | ||||
| @ -1,4 +1,6 @@ | ||||
| #include "api-gpio.h" | ||||
| #include <cmsis_os2.h> | ||||
| #include <furi/record.h> | ||||
| 
 | ||||
| osMutexId_t gpioInitMutex; | ||||
| 
 | ||||
| @ -37,7 +39,7 @@ void gpio_disable(GpioDisableRecord* gpio_record) { | ||||
| 
 | ||||
| // get GPIO record
 | ||||
| ValueMutex* gpio_open_mutex(const char* name) { | ||||
|     ValueMutex* gpio_mutex = (ValueMutex*)furi_open(name); | ||||
|     ValueMutex* gpio_mutex = (ValueMutex*)furi_record_open(name); | ||||
| 
 | ||||
|     // TODO disable gpio on app exit
 | ||||
|     //if(gpio_mutex != NULL) flapp_on_exit(gpio_disable, gpio_mutex);
 | ||||
| @ -48,6 +50,6 @@ ValueMutex* gpio_open_mutex(const char* name) { | ||||
| // get GPIO record and acquire mutex
 | ||||
| GpioPin* gpio_open(const char* name) { | ||||
|     ValueMutex* gpio_mutex = gpio_open_mutex(name); | ||||
|     GpioPin* gpio_pin = acquire_mutex(gpio_mutex, FLIPPER_HELPER_TIMEOUT); | ||||
|     GpioPin* gpio_pin = acquire_mutex(gpio_mutex, osWaitForever); | ||||
|     return gpio_pin; | ||||
| } | ||||
| @ -1,7 +1,11 @@ | ||||
| #pragma once | ||||
| #include "flipper.h" | ||||
| #include "flipper_v2.h" | ||||
| 
 | ||||
| #include "api-hal-gpio.h" | ||||
| #include <furi/valuemutex.h> | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| typedef struct { | ||||
|     ValueMutex* gpio_mutex; | ||||
| @ -38,4 +42,8 @@ void gpio_disable(GpioDisableRecord* gpio_record); | ||||
| ValueMutex* gpio_open_mutex(const char* name); | ||||
| 
 | ||||
| // get GPIO record and acquire mutex
 | ||||
| GpioPin* gpio_open(const char* name); | ||||
| GpioPin* gpio_open(const char* name); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
| @ -1,5 +1,8 @@ | ||||
| #include "api-interrupt-mgr.h" | ||||
| 
 | ||||
| #include <m-list.h> | ||||
| #include <cmsis_os2.h> | ||||
| 
 | ||||
| LIST_DEF(list_interrupt, InterruptCallbackItem, M_POD_OPLIST); | ||||
| list_interrupt_t interrupts; | ||||
| osMutexId_t interrupt_list_mutex; | ||||
|  | ||||
| @ -1,5 +1,10 @@ | ||||
| #pragma once | ||||
| #include "flipper_v2.h" | ||||
| 
 | ||||
| #include <stdbool.h> | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| typedef void (*InterruptCallback)(void*, void*); | ||||
| 
 | ||||
| @ -18,4 +23,8 @@ typedef struct { | ||||
| bool api_interrupt_init(); | ||||
| void api_interrupt_add(InterruptCallback callback, InterruptType type, void* context); | ||||
| void api_interrupt_remove(InterruptCallback callback); | ||||
| void api_interrupt_call(InterruptType type, void* hw); | ||||
| void api_interrupt_call(InterruptType type, void* hw); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
| @ -1,4 +1,8 @@ | ||||
| #include "flipper_v2.h" | ||||
| #include <furi.h> | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| /*
 | ||||
| struct used for handling SPI info. | ||||
| @ -133,4 +137,8 @@ void cc1101_example() { | ||||
|     } | ||||
| } | ||||
| ``` | ||||
| */ | ||||
| */ | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
							
								
								
									
										48
									
								
								core/app.cpp
									
									
									
									
									
								
							
							
						
						
									
										48
									
								
								core/app.cpp
									
									
									
									
									
								
							| @ -1,48 +0,0 @@ | ||||
| #include <stdio.h> | ||||
| #include "flipper.h" | ||||
| #include "flipper_v2.h" | ||||
| 
 | ||||
| extern "C" { | ||||
| #include "log.h" | ||||
| #include "applications.h" | ||||
| #include "tty_uart.h" | ||||
| } | ||||
| 
 | ||||
| // for testing purpose
 | ||||
| uint32_t exitcode = 0; | ||||
| extern "C" void set_exitcode(uint32_t _exitcode) { | ||||
|     exitcode = _exitcode; | ||||
| } | ||||
| 
 | ||||
| extern "C" int app() { | ||||
|     init_flipper_api(); | ||||
|     register_tty_uart(); | ||||
| 
 | ||||
|     FuriRecordSubscriber* log = get_default_log(); | ||||
|     fuprintf(log, "\n=== Welcome to Flipper Zero! ===\n\n"); | ||||
| 
 | ||||
|     // FURI startup
 | ||||
|     const size_t flipper_app_count = sizeof(FLIPPER_STARTUP) / sizeof(FLIPPER_STARTUP[0]); | ||||
|     FuriApp* handlers[flipper_app_count]; | ||||
| 
 | ||||
|     for(size_t i = 0; i < flipper_app_count; i++) { | ||||
|         // TODO create a dependency tree and run tasks in the desired order
 | ||||
|         furiac_wait_libs(&FLIPPER_STARTUP[i].libs); | ||||
|         handlers[i] = furiac_start(FLIPPER_STARTUP[i].app, FLIPPER_STARTUP[i].name, NULL); | ||||
|     } | ||||
| 
 | ||||
|     bool is_alive = false; | ||||
|     do { | ||||
|         is_alive = false; | ||||
|         for(size_t i = 0; i < flipper_app_count; i++) { | ||||
|             if(handlers[i]->handler != NULL) { | ||||
|                 is_alive = true; | ||||
|             } | ||||
|         } | ||||
|         delay(500); | ||||
|     } while(is_alive); | ||||
| 
 | ||||
|     fuprintf(log, "\n=== Bye from Flipper Zero! ===\n\n"); | ||||
| 
 | ||||
|     return (int)exitcode; | ||||
| } | ||||
| @ -1,8 +1,8 @@ | ||||
| CORE_DIR		= $(PROJECT_ROOT)/core | ||||
| 
 | ||||
| CFLAGS			+= -I$(CORE_DIR) | ||||
| CFLAGS			+= -I$(CORE_DIR) -D_GNU_SOURCE | ||||
| ASM_SOURCES		+= $(wildcard $(CORE_DIR)/*.s) | ||||
| C_SOURCES		+= $(wildcard $(CORE_DIR)/*.c) | ||||
| C_SOURCES		+= $(wildcard $(CORE_DIR)/api-basic/*.c) | ||||
| C_SOURCES		+= $(wildcard $(CORE_DIR)/furi/*.c) | ||||
| C_SOURCES		+= $(wildcard $(CORE_DIR)/api-hal/*.c) | ||||
| CPP_SOURCES		+= $(wildcard $(CORE_DIR)/*.cpp) | ||||
|  | ||||
| @ -1,24 +0,0 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include "api-hal.h" | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| #include "main.h" | ||||
| #include "cmsis_os.h" | ||||
| #include "furi-deprecated.h" | ||||
| 
 | ||||
| #include "log.h" | ||||
| #include "input/input.h" | ||||
| 
 | ||||
| #include <stdio.h> | ||||
| 
 | ||||
| void set_exitcode(uint32_t _exitcode); | ||||
| 
 | ||||
| #define FURI_LIB (const char*[]) | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| @ -1,16 +0,0 @@ | ||||
| #pragma once | ||||
| #include "stdint.h" | ||||
| 
 | ||||
| // Arduino defines
 | ||||
| #define pinMode gpio_init | ||||
| #define digitalWrite gpio_write | ||||
| #define digitalRead gpio_read | ||||
| #define delayMicroseconds delay_us | ||||
| #define delay osDelay | ||||
| 
 | ||||
| #define OUTPUT GpioModeOutputPushPull | ||||
| #define INPUT GpioModeInput | ||||
| #define LOW false | ||||
| #define HIGH true | ||||
| 
 | ||||
| typedef uint8_t byte; | ||||
| @ -1,19 +0,0 @@ | ||||
| #include "flipper_v2.h" | ||||
| 
 | ||||
| bool init_flipper_api(void) { | ||||
|     bool no_errors = true; | ||||
| 
 | ||||
|     if(!furi_init()) { | ||||
|         no_errors = false; | ||||
|     } | ||||
| 
 | ||||
|     if(!gpio_api_init()) { | ||||
|         no_errors = false; | ||||
|     } | ||||
| 
 | ||||
|     if(!api_interrupt_init()) { | ||||
|         no_errors = false; | ||||
|     } | ||||
| 
 | ||||
|     return no_errors; | ||||
| } | ||||
| @ -1,33 +0,0 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include "flipper.h" | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| #include "api-basic/furi.h" | ||||
| //#include "api-basic/flapp.h"
 | ||||
| #include "cmsis_os2.h" | ||||
| #include "api-basic/valuemutex.h" | ||||
| #include "api-basic/pubsub.h" | ||||
| #include "api-basic/value-expanders.h" | ||||
| #include "api-basic/event.h" | ||||
| 
 | ||||
| #include "api-basic/memmgr.h" | ||||
| #include "api-basic/check.h" | ||||
| 
 | ||||
| #include "api-hal/api-gpio.h" | ||||
| #include "api-hal/api-interrupt-mgr.h" | ||||
| #include "api-hal-resources.h" | ||||
| 
 | ||||
| #include "gui/gui.h" | ||||
| 
 | ||||
| // tmeout for helper functions
 | ||||
| #define FLIPPER_HELPER_TIMEOUT 10 | ||||
| 
 | ||||
| bool init_flipper_api(void); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| @ -1,295 +0,0 @@ | ||||
| #include "furi-deprecated.h" | ||||
| #include <string.h> | ||||
| 
 | ||||
| // TODO: this file contains printf, that not implemented on uC target
 | ||||
| 
 | ||||
| #ifdef FURI_DEBUG | ||||
| #include <stdio.h> | ||||
| #endif | ||||
| 
 | ||||
| #define MAX_RECORD_COUNT 32 | ||||
| 
 | ||||
| static FuriRecord records[MAX_RECORD_COUNT]; | ||||
| static size_t current_buffer_idx = 0; | ||||
| osMutexId_t furi_core_mutex; | ||||
| 
 | ||||
| bool furi_init(void) { | ||||
|     furi_core_mutex = osMutexNew(NULL); | ||||
|     if(furi_core_mutex == NULL) return false; | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| // find record pointer by name
 | ||||
| static FuriRecord* find_record(const char* name) { | ||||
|     if(name == NULL) return NULL; | ||||
| 
 | ||||
|     FuriRecord* res = NULL; | ||||
|     for(size_t i = 0; i < MAX_RECORD_COUNT; i++) { | ||||
|         if(records[i].name != NULL && strcmp(name, records[i].name) == 0) { | ||||
|             res = &records[i]; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return res; | ||||
| } | ||||
| 
 | ||||
| // TODO: change open-create to only open
 | ||||
| bool furi_create_deprecated(const char* name, void* value, size_t size) { | ||||
| #ifdef FURI_DEBUG | ||||
|     printf("[FURI] creating %s record\n", name); | ||||
| #endif | ||||
| 
 | ||||
|     // acquire mutex to prevent simultaneous write to record with same index
 | ||||
|     if(osMutexAcquire(furi_core_mutex, osWaitForever) != osOK) { | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     FuriRecord* record = find_record(name); | ||||
| 
 | ||||
|     if(record != NULL) { | ||||
| #ifdef FURI_DEBUG | ||||
|         printf("[FURI] record already exist\n"); | ||||
| #endif | ||||
| 
 | ||||
|         record->value = value; | ||||
|         record->size = size; | ||||
| 
 | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     // record not exist, create new
 | ||||
| 
 | ||||
|     if(current_buffer_idx >= MAX_RECORD_COUNT) { | ||||
| // max record count exceed
 | ||||
| #ifdef FURI_DEBUG | ||||
|         printf("[FURI] create: max record count exceed\n"); | ||||
| #endif | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     records[current_buffer_idx].mute_counter = 0; | ||||
|     records[current_buffer_idx].mutex = | ||||
|         xSemaphoreCreateMutexStatic(&records[current_buffer_idx].mutex_buffer); | ||||
|     records[current_buffer_idx].value = value; | ||||
|     records[current_buffer_idx].size = size; | ||||
|     records[current_buffer_idx].name = name; | ||||
| 
 | ||||
|     for(size_t i = 0; i < MAX_RECORD_SUBSCRIBERS; i++) { | ||||
|         records[current_buffer_idx].subscribers[i].allocated = false; | ||||
|         records[current_buffer_idx].subscribers[i].ctx = NULL; | ||||
|     } | ||||
| 
 | ||||
|     current_buffer_idx++; | ||||
| 
 | ||||
|     osMutexRelease(furi_core_mutex); | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| FuriRecordSubscriber* furi_open_deprecated( | ||||
|     const char* name, | ||||
|     bool solo, | ||||
|     bool no_mute, | ||||
|     FlipperRecordCallback value_callback, | ||||
|     FlipperRecordStateCallback state_callback, | ||||
|     void* ctx) { | ||||
| #ifdef FURI_DEBUG | ||||
|     printf("[FURI] opening %s record\n", name); | ||||
| #endif | ||||
| 
 | ||||
|     // get furi record by name
 | ||||
|     FuriRecord* record = find_record(name); | ||||
| 
 | ||||
|     if(record == NULL) { | ||||
| // cannot find record
 | ||||
| #ifdef FURI_DEBUG | ||||
|         printf("[FURI] cannot find record %s\n", name); | ||||
| #endif | ||||
| 
 | ||||
|         // create record if not exist
 | ||||
|         if(!furi_create_deprecated(name, NULL, 0)) { | ||||
|             return NULL; | ||||
|         } | ||||
| 
 | ||||
|         record = find_record(name); | ||||
| 
 | ||||
|         if(record == NULL) { | ||||
|             return NULL; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // allocate subscriber
 | ||||
|     FuriRecordSubscriber* subscriber = NULL; | ||||
| 
 | ||||
|     for(size_t i = 0; i < MAX_RECORD_SUBSCRIBERS; i++) { | ||||
|         if(!record->subscribers[i].allocated) { | ||||
|             subscriber = &record->subscribers[i]; | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if(subscriber == NULL) { | ||||
| // cannot add subscriber (full)
 | ||||
| #ifdef FURI_DEBUG | ||||
|         printf("[FURI] open: cannot add subscriber (full)\n"); | ||||
| #endif | ||||
| 
 | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     // increase mute_counter
 | ||||
|     if(solo) { | ||||
|         record->mute_counter++; | ||||
|     } | ||||
| 
 | ||||
|     // set all parameters
 | ||||
|     subscriber->allocated = true; | ||||
|     subscriber->mute_counter = record->mute_counter; | ||||
|     subscriber->no_mute = no_mute; | ||||
|     subscriber->cb = value_callback; | ||||
|     subscriber->state_cb = state_callback; | ||||
|     subscriber->record = record; | ||||
|     subscriber->ctx = ctx; | ||||
| 
 | ||||
|     // register record in application
 | ||||
|     FuriApp* current_task = find_task(xTaskGetCurrentTaskHandle()); | ||||
| 
 | ||||
|     if(current_task != NULL) { | ||||
|         current_task->records[current_task->records_count] = record; | ||||
|         current_task->records_count++; | ||||
|     } else { | ||||
| #ifdef FURI_DEBUG | ||||
|         printf("[FURI] open: no current task\n"); | ||||
| #endif | ||||
|     } | ||||
| 
 | ||||
|     return subscriber; | ||||
| } | ||||
| 
 | ||||
| void furi_close(FuriRecordSubscriber* handler) { | ||||
| #ifdef FURI_DEBUG | ||||
|     printf("[FURI] closing %s record\n", handler->record->name); | ||||
| #endif | ||||
| 
 | ||||
|     // deallocate subscriber
 | ||||
|     handler->allocated = false; | ||||
| 
 | ||||
|     // set mute counter to next max value
 | ||||
|     uint8_t max_mute_counter = 0; | ||||
|     for(size_t i = 0; i < MAX_RECORD_SUBSCRIBERS; i++) { | ||||
|         if(handler->record->subscribers[i].allocated) { | ||||
|             if(handler->record->subscribers[i].mute_counter > max_mute_counter) { | ||||
|                 max_mute_counter = handler->record->subscribers[i].mute_counter; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     handler->record->mute_counter = max_mute_counter; | ||||
| } | ||||
| 
 | ||||
| static void furi_notify(FuriRecordSubscriber* handler, const void* value, size_t size) { | ||||
|     for(size_t i = 0; i < MAX_RECORD_SUBSCRIBERS; i++) { | ||||
|         if(handler->record->subscribers[i].allocated) { | ||||
|             if(handler->record->subscribers[i].cb != NULL) { | ||||
|                 handler->record->subscribers[i].cb( | ||||
|                     value, size, handler->record->subscribers[i].ctx); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void* furi_take(FuriRecordSubscriber* handler) { | ||||
|     if(handler == NULL || handler->record == NULL) return NULL; | ||||
| 
 | ||||
|     if(xSemaphoreTake(handler->record->mutex, portMAX_DELAY) == pdTRUE) { | ||||
|         return handler->record->value; | ||||
|     } else { | ||||
|         return NULL; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void furi_give(FuriRecordSubscriber* handler) { | ||||
|     if(handler == NULL || handler->record == NULL) return; | ||||
| 
 | ||||
|     xSemaphoreGive(handler->record->mutex); | ||||
| } | ||||
| 
 | ||||
| void furi_commit(FuriRecordSubscriber* handler) { | ||||
|     if(handler == NULL || handler->record == NULL) return; | ||||
| 
 | ||||
|     furi_notify(handler, handler->record->value, handler->record->size); | ||||
|     furi_give(handler); | ||||
| } | ||||
| 
 | ||||
| bool furi_read(FuriRecordSubscriber* handler, void* value, size_t size) { | ||||
| #ifdef FURI_DEBUG | ||||
|     printf("[FURI] read from %s\n", handler->record->name); | ||||
| #endif | ||||
| 
 | ||||
|     if(handler == NULL || handler->record == NULL || value == NULL) return false; | ||||
| 
 | ||||
|     if(size > handler->record->size) return false; | ||||
| 
 | ||||
|     // return false if read from pipe
 | ||||
|     if(handler->record->value == NULL) return false; | ||||
| 
 | ||||
|     furi_take(handler); | ||||
|     memcpy(value, handler->record->value, size); | ||||
|     furi_notify(handler, value, size); | ||||
|     furi_give(handler); | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool furi_write(FuriRecordSubscriber* handler, const void* value, size_t size) { | ||||
| #ifdef FURI_DEBUG | ||||
|     printf("[FURI] write to %s\n", handler->record->name); | ||||
| #endif | ||||
| 
 | ||||
|     if(handler == NULL || handler->record == NULL || value == NULL) { | ||||
| #ifdef FURI_DEBUG | ||||
|         printf( | ||||
|             "[FURI] write: null param %x %x\n", | ||||
|             (uint32_t)(size_t)handler, | ||||
|             (uint32_t)(size_t)value); | ||||
| #endif | ||||
| 
 | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     // check if closed
 | ||||
|     if(!handler->allocated) { | ||||
| #ifdef FURI_DEBUG | ||||
|         printf("[FURI] write: handler closed\n"); | ||||
| #endif | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     if(handler->record->value != NULL && size > handler->record->size) { | ||||
| #ifdef FURI_DEBUG | ||||
|         printf("[FURI] write: wrong size %d\n", (uint32_t)size); | ||||
| #endif | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     // check mute
 | ||||
|     if(handler->record->mute_counter != handler->mute_counter && !handler->no_mute) { | ||||
| #ifdef FURI_DEBUG | ||||
|         printf("[FURI] write: muted\n"); | ||||
| #endif | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     furi_take(handler); | ||||
|     if(handler->record->value != NULL) { | ||||
|         // real write to value
 | ||||
|         memcpy(handler->record->value, value, size); | ||||
| 
 | ||||
|         // notify subscribers
 | ||||
|         furi_notify(handler, handler->record->value, handler->record->size); | ||||
|     } else { | ||||
|         furi_notify(handler, value, size); | ||||
|     } | ||||
|     furi_give(handler); | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| @ -1,207 +0,0 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include "cmsis_os.h" | ||||
| 
 | ||||
| #ifdef HAVE_FREERTOS | ||||
| #include <semphr.h> | ||||
| #endif | ||||
| 
 | ||||
| #include <stdbool.h> | ||||
| #include <stdlib.h> | ||||
| #include <stdint.h> | ||||
| #include <string.h> | ||||
| #include <assert.h> | ||||
| 
 | ||||
| #include "assets_icons.h" | ||||
| 
 | ||||
| #define MAX_TASK_RECORDS 8 | ||||
| #define MAX_RECORD_SUBSCRIBERS 8 | ||||
| 
 | ||||
| inline static void* furi_alloc(size_t size) { | ||||
|     void* p = malloc(size); | ||||
|     assert(p); | ||||
|     return memset(p, 0, size); | ||||
| } | ||||
| 
 | ||||
| /// application is just a function
 | ||||
| typedef void (*FlipperApplication)(void*); | ||||
| 
 | ||||
| /// pointer to value callback function
 | ||||
| typedef void (*FlipperRecordCallback)(const void*, size_t, void*); | ||||
| 
 | ||||
| typedef enum { | ||||
|     FlipperRecordStateMute, ///< record open and mute this handler
 | ||||
|     FlipperRecordStateUnmute, ///< record unmuted
 | ||||
|     FlipperRecordStateDeleted ///< record owner halt
 | ||||
| } FlipperRecordState; | ||||
| 
 | ||||
| /// pointer to state callback function
 | ||||
| typedef void (*FlipperRecordStateCallback)(FlipperRecordState, void*); | ||||
| 
 | ||||
| struct _FuriRecord; | ||||
| 
 | ||||
| typedef struct { | ||||
|     bool allocated; | ||||
|     FlipperRecordCallback cb; ///< value cb
 | ||||
|     FlipperRecordStateCallback state_cb; ///< state cb
 | ||||
|     uint8_t mute_counter; ///< see "wiki/FURI#mute-algorithm"
 | ||||
|     bool no_mute; | ||||
|     struct _FuriRecord* record; ///< parent record
 | ||||
|     void* ctx; | ||||
| } FuriRecordSubscriber; | ||||
| 
 | ||||
| /// FURI record handler
 | ||||
| struct _FuriRecord { | ||||
|     const char* name; | ||||
|     void* value; | ||||
|     size_t size; | ||||
|     StaticSemaphore_t mutex_buffer; | ||||
|     SemaphoreHandle_t mutex; | ||||
|     uint8_t mute_counter; | ||||
|     FuriRecordSubscriber subscribers[MAX_RECORD_SUBSCRIBERS]; | ||||
| }; | ||||
| 
 | ||||
| typedef struct _FuriRecord FuriRecord; | ||||
| 
 | ||||
| /// store info about active task
 | ||||
| typedef struct { | ||||
|     const char* name; | ||||
|     FlipperApplication application; | ||||
|     const char* prev_name; | ||||
|     FlipperApplication prev; | ||||
|     TaskHandle_t handler; | ||||
|     uint8_t records_count; ///< count of records which task open
 | ||||
|     FuriRecord* records[MAX_TASK_RECORDS]; ///< list of records which task open
 | ||||
| 
 | ||||
|     bool ready; | ||||
| } FuriApp; | ||||
| 
 | ||||
| // application dependency info
 | ||||
| typedef struct { | ||||
|     uint8_t count; | ||||
|     const char** name; | ||||
| } FlipperAppLibrary; | ||||
| 
 | ||||
| // application startup info
 | ||||
| typedef struct { | ||||
|     FlipperApplication app; | ||||
|     const char* name; | ||||
|     FlipperAppLibrary libs; | ||||
|     IconName icon; | ||||
| } FlipperStartupApp; | ||||
| 
 | ||||
| // Init core
 | ||||
| bool furi_init(void); | ||||
| 
 | ||||
| /*!
 | ||||
| Simply starts application. | ||||
| It call app entrypoint with param passed as argument. | ||||
| Useful for daemon applications and pop-up. | ||||
| */ | ||||
| FuriApp* furiac_start(FlipperApplication app, const char* name, void* param); | ||||
| 
 | ||||
| /*!
 | ||||
| Swtich to other application. | ||||
| FURI stop current app, call app entrypoint with param passed as | ||||
| argument and save current application entrypoint to prev field | ||||
| in current application registry. | ||||
| Useful for UI or "active" application. | ||||
| */ | ||||
| void furiac_switch(FlipperApplication app, char* name, void* param); | ||||
| 
 | ||||
| /*!
 | ||||
| Stop current application | ||||
| (stop thread and clear application's stack), start application | ||||
| from prev entry in current application registry, cleanup current | ||||
| application registry. | ||||
| */ | ||||
| void furiac_exit(void* param); | ||||
| 
 | ||||
| /*!
 | ||||
| Mark application as prepared and ready to perform actions | ||||
| */ | ||||
| void furiac_ready(); | ||||
| 
 | ||||
| /* 
 | ||||
| Wait for the libraries we depend on | ||||
| */ | ||||
| void furiac_wait_libs(const FlipperAppLibrary* libs); | ||||
| 
 | ||||
| /*!
 | ||||
| Stop specified app without returning to prev application. | ||||
| */ | ||||
| bool furiac_kill(FuriApp* app); | ||||
| 
 | ||||
| // find task pointer by handle
 | ||||
| FuriApp* find_task(TaskHandle_t handler); | ||||
| 
 | ||||
| /*!
 | ||||
| Creates named FURI record. | ||||
| \param[in] name you can open this record anywhere | ||||
| \param[in] value pointer to data. | ||||
| \param[in] size size of data. | ||||
| If NULL, create FURI Pipe (only callbacks management, no data/mutex) | ||||
| 
 | ||||
| Returns false if registry have not enough memory for creating. | ||||
| */ | ||||
| bool furi_create_deprecated(const char* name, void* value, size_t size); | ||||
| 
 | ||||
| /*!
 | ||||
| Opens existing FURI record by name. | ||||
| Returns NULL if record does not exist. | ||||
| \param[in] solo if true another applications handlers set into "muted" state. | ||||
| When appication has exited or record has closed, all handlers is unmuted. | ||||
| It may be useful for concurrently acces to resources like framebuffer or beeper. | ||||
| \param[in] no_mute if true, another applications cannot mute this handler. | ||||
| */ | ||||
| FuriRecordSubscriber* furi_open_deprecated( | ||||
|     const char* name, | ||||
|     bool solo, | ||||
|     bool no_mute, | ||||
|     FlipperRecordCallback value_callback, | ||||
|     FlipperRecordStateCallback state_callback, | ||||
|     void* ctx); | ||||
| 
 | ||||
| /*!
 | ||||
| 
 | ||||
| */ | ||||
| void furi_close(FuriRecordSubscriber* handler); | ||||
| 
 | ||||
| /*!
 | ||||
| read message from record. | ||||
| Returns true if success, false otherwise (closed/non-existent record) | ||||
| Also return false if you try to read from FURI pipe | ||||
| 
 | ||||
| TODO: enum return value with execution status | ||||
| */ | ||||
| bool furi_read(FuriRecordSubscriber* record, void* data, size_t size); | ||||
| 
 | ||||
| /*!
 | ||||
| write message to record. | ||||
| Returns true if success, false otherwise (closed/non-existent record or muted). | ||||
| 
 | ||||
| TODO: enum return value with execution status | ||||
| */ | ||||
| bool furi_write(FuriRecordSubscriber* record, const void* data, size_t size); | ||||
| 
 | ||||
| /*!
 | ||||
| lock value mutex. | ||||
| It can be useful if records contain pointer to buffer which you want to change. | ||||
| You must call furi_give after operation on data and | ||||
| you shouldn't block executing between take and give calls | ||||
| 
 | ||||
| Returns pointer to data, NULL if closed/non-existent record or muted | ||||
| 
 | ||||
| TODO: enum return value with execution status | ||||
| */ | ||||
| void* furi_take(FuriRecordSubscriber* record); | ||||
| 
 | ||||
| /*!
 | ||||
| unlock value mutex. | ||||
| */ | ||||
| void furi_give(FuriRecordSubscriber* record); | ||||
| 
 | ||||
| /*!
 | ||||
| unlock value mutex and notify subscribers that data is chaned. | ||||
| */ | ||||
| void furi_commit(FuriRecordSubscriber* handler); | ||||
							
								
								
									
										36
									
								
								core/furi.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								core/furi.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,36 @@ | ||||
| #include "furi.h" | ||||
| #include <applications.h> | ||||
| 
 | ||||
| // for testing purpose
 | ||||
| uint32_t exitcode = 0; | ||||
| 
 | ||||
| void set_exitcode(uint32_t _exitcode) { | ||||
|     exitcode = _exitcode; | ||||
| } | ||||
| 
 | ||||
| void furi_init() { | ||||
|     gpio_api_init(); | ||||
|     api_interrupt_init(); | ||||
|     furi_record_init(); | ||||
|     furi_stdglue_init(); | ||||
| } | ||||
| 
 | ||||
| int systemd() { | ||||
|     furi_init(); | ||||
| 
 | ||||
|     // FURI startup
 | ||||
|     for(size_t i = 0; i < FLIPPER_SERVICES_size(); i++) { | ||||
|         osThreadAttr_t* attr = furi_alloc(sizeof(osThreadAttr_t)); | ||||
|         attr->name = FLIPPER_SERVICES[i].name; | ||||
|         attr->stack_size = 1024; | ||||
|         osThreadNew(FLIPPER_SERVICES[i].app, NULL, attr); | ||||
|     } | ||||
| 
 | ||||
|     while(1) { | ||||
|         osThreadSuspend(osThreadGetId()); | ||||
|     } | ||||
| 
 | ||||
|     printf("\n=== Bye from Flipper Zero! ===\n\n"); | ||||
| 
 | ||||
|     return (int)exitcode; | ||||
| } | ||||
							
								
								
									
										28
									
								
								core/furi.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								core/furi.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <cmsis_os2.h> | ||||
| 
 | ||||
| #include <furi/check.h> | ||||
| #include <furi/event.h> | ||||
| #include <furi/memmgr.h> | ||||
| #include <furi/pubsub.h> | ||||
| #include <furi/record.h> | ||||
| #include <furi/stdglue.h> | ||||
| #include <furi/value-expanders.h> | ||||
| #include <furi/valuemutex.h> | ||||
| 
 | ||||
| #include <api-hal/api-gpio.h> | ||||
| #include <api-hal/api-interrupt-mgr.h> | ||||
| 
 | ||||
| #include <api-hal.h> | ||||
| #include <stdlib.h> | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| #define furiac_exit(ptr) osThreadExit() | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| @ -1,5 +1,6 @@ | ||||
| #include "check.h" | ||||
| #include "api-hal-task.h" | ||||
| #include <stdio.h> | ||||
| 
 | ||||
| void __furi_abort(void); | ||||
| 
 | ||||
| @ -22,20 +23,21 @@ void __furi_check_debug(const char* file, int line, const char* function, const | ||||
|     if(task_is_isr_context()) { | ||||
|         printf(" in [ISR] context"); | ||||
|     } else { | ||||
|         FuriApp* app = find_task(xTaskGetCurrentTaskHandle()); | ||||
|         // FuriApp* app = find_task(xTaskGetCurrentTaskHandle());
 | ||||
| 
 | ||||
|         if(app == NULL) { | ||||
|             printf(", in [main] context"); | ||||
|         } else { | ||||
|             printf(", in [%s] app context", app->name); | ||||
|         } | ||||
|         // if(app == NULL) {
 | ||||
|         //     printf(", in [main] context");
 | ||||
|         // } else {
 | ||||
|         //     printf(", in [%s] app context", app->name);
 | ||||
|         // }
 | ||||
|     } | ||||
| 
 | ||||
|     __furi_abort(); | ||||
| } | ||||
| 
 | ||||
| void __furi_abort(void) { | ||||
|     taskDISABLE_INTERRUPTS(); | ||||
|     __disable_irq(); | ||||
|     asm("bkpt 1"); | ||||
|     while(1) { | ||||
|     } | ||||
| } | ||||
| @ -1,6 +1,8 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include "flipper.h" | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| // Find how to how get function's pretty name
 | ||||
| #ifndef __FURI_CHECK_FUNC | ||||
| @ -38,4 +40,8 @@ | ||||
| // !NDEBUG
 | ||||
| 
 | ||||
| void __furi_check(void); | ||||
| void __furi_check_debug(const char* file, int line, const char* function, const char* condition); | ||||
| void __furi_check_debug(const char* file, int line, const char* function, const char* condition); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 DrZlo13
						DrZlo13