[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 | debug/** @skotopes | ||||||
| 
 | 
 | ||||||
| # local target |  | ||||||
| 
 |  | ||||||
| firmware/targets/local/** @glitchcore |  | ||||||
| 
 |  | ||||||
| # BLE | # BLE | ||||||
| 
 | 
 | ||||||
| firmware/targets/f4/ble-glue/** @skotopes | firmware/targets/f4/ble-glue/** @skotopes | ||||||
|  | |||||||
							
								
								
									
										10
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							| @ -32,16 +32,6 @@ jobs: | |||||||
|         with: |         with: | ||||||
|           run: /syntax_check.sh |           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 |       - name: Build F4 bootloader in docker | ||||||
|         uses: ./.github/actions/docker |         uses: ./.github/actions/docker | ||||||
|         with: |         with: | ||||||
|  | |||||||
| @ -25,14 +25,7 @@ Flipper Zero's firmware consists of two components: Bootloader and main firmware | |||||||
| 
 | 
 | ||||||
| ## Build from source | ## Build from source | ||||||
| 
 | 
 | ||||||
| You can run firmware locally (with HAL stub): | `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) | ||||||
| 
 |  | ||||||
| * `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) |  | ||||||
| 
 | 
 | ||||||
| # Links | # Links | ||||||
| * Task tracker: [Jira](https://flipperzero.atlassian.net/) | * Task tracker: [Jira](https://flipperzero.atlassian.net/) | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| #include "flipper_v2.h" | #include <furi.h> | ||||||
| #include <cli/cli.h> | #include <cli/cli.h> | ||||||
| #include <gui/gui.h> | #include <gui/gui.h> | ||||||
| #include "menu/menu.h" | #include "menu/menu.h" | ||||||
| @ -8,14 +8,15 @@ | |||||||
| #include <api-hal.h> | #include <api-hal.h> | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     FuriApp* handler; |     osThreadAttr_t app_thread_attr; | ||||||
|  |     osThreadId_t app_thread_id; | ||||||
|     Widget* widget; |     Widget* widget; | ||||||
|     const FlipperStartupApp* current_app; |     const FuriApplication* current_app; | ||||||
| } AppLoaderState; | } AppLoaderState; | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     AppLoaderState* state; |     AppLoaderState* state; | ||||||
|     const FlipperStartupApp* app; |     const FuriApplication* app; | ||||||
| } AppLoaderContext; | } AppLoaderContext; | ||||||
| 
 | 
 | ||||||
| // TODO add mutex for contex
 | // TODO add mutex for contex
 | ||||||
| @ -36,7 +37,7 @@ static void input_callback(InputEvent* input_event, void* _ctx) { | |||||||
|     AppLoaderState* ctx = (AppLoaderState*)_ctx; |     AppLoaderState* ctx = (AppLoaderState*)_ctx; | ||||||
| 
 | 
 | ||||||
|     if(input_event->state && input_event->input == InputBack) { |     if(input_event->state && input_event->input == InputBack) { | ||||||
|         furiac_kill(ctx->handler); |         osThreadTerminate(ctx->app_thread_id); | ||||||
|         widget_enabled_set(ctx->widget, false); |         widget_enabled_set(ctx->widget, false); | ||||||
|         api_hal_timebase_insomnia_exit(); |         api_hal_timebase_insomnia_exit(); | ||||||
|     } |     } | ||||||
| @ -54,7 +55,16 @@ static void handle_menu(void* _ctx) { | |||||||
|     api_hal_timebase_insomnia_enter(); |     api_hal_timebase_insomnia_enter(); | ||||||
| 
 | 
 | ||||||
|     ctx->state->current_app = ctx->app; |     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) { | 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"); |     cli_print("Starting furi application\r\n"); | ||||||
| 
 | 
 | ||||||
|     ctx->state->current_app = ctx->app; |     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"); |     cli_print("Press any key to kill application"); | ||||||
| 
 | 
 | ||||||
|     char c; |     char c; | ||||||
|     cli_read(&c, 1); |     cli_read(&c, 1); | ||||||
|     furiac_kill(ctx->state->handler); |     osThreadTerminate(ctx->state->app_thread_id); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void app_loader(void* p) { | void app_loader(void* p) { | ||||||
| @ -79,37 +98,23 @@ void app_loader(void* p) { | |||||||
|     furi_check(self_id); |     furi_check(self_id); | ||||||
| 
 | 
 | ||||||
|     AppLoaderState state; |     AppLoaderState state; | ||||||
|     state.handler = NULL; |     state.app_thread_id = NULL; | ||||||
| 
 | 
 | ||||||
|     state.widget = widget_alloc(); |     state.widget = widget_alloc(); | ||||||
|     widget_enabled_set(state.widget, false); |     widget_enabled_set(state.widget, false); | ||||||
|     widget_draw_callback_set(state.widget, render_callback, &state); |     widget_draw_callback_set(state.widget, render_callback, &state); | ||||||
|     widget_input_callback_set(state.widget, input_callback, &state); |     widget_input_callback_set(state.widget, input_callback, &state); | ||||||
| 
 | 
 | ||||||
|     ValueMutex* menu_mutex = furi_open("menu"); |     ValueMutex* menu_mutex = furi_record_open("menu"); | ||||||
|     if(menu_mutex == NULL) { |     Cli* cli = furi_record_open("cli"); | ||||||
|         printf("menu is not available\n"); |     Gui* gui = furi_record_open("gui"); | ||||||
|         furiac_exit(NULL); |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     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); |     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
 |     // Main menu
 | ||||||
|     with_value_mutex( |     with_value_mutex( | ||||||
|         menu_mutex, (Menu * menu) { |         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)); |                 AppLoaderContext* ctx = furi_alloc(sizeof(AppLoaderContext)); | ||||||
|                 ctx->state = &state; |                 ctx->state = &state; | ||||||
|                 ctx->app = &FLIPPER_APPS[i]; |                 ctx->app = &FLIPPER_APPS[i]; | ||||||
| @ -123,13 +128,11 @@ void app_loader(void* p) { | |||||||
|                         ctx)); |                         ctx)); | ||||||
| 
 | 
 | ||||||
|                 // Add cli command
 |                 // Add cli command
 | ||||||
|                 if(cli) { |                 string_t cli_name; | ||||||
|                     string_t cli_name; |                 string_init_set_str(cli_name, "app_"); | ||||||
|                     string_init_set_str(cli_name, "app_"); |                 string_cat_str(cli_name, FLIPPER_APPS[i].name); | ||||||
|                     string_cat_str(cli_name, FLIPPER_APPS[i].name); |                 cli_add_command(cli, string_get_cstr(cli_name), handle_cli, ctx); | ||||||
|                     cli_add_command(cli, string_get_cstr(cli_name), handle_cli, ctx); |                 string_clear(cli_name); | ||||||
|                     string_clear(cli_name); |  | ||||||
|                 } |  | ||||||
|             } |             } | ||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
| @ -157,7 +160,7 @@ void app_loader(void* p) { | |||||||
|             MenuItem* menu_plugins = |             MenuItem* menu_plugins = | ||||||
|                 menu_item_alloc_menu("Plugins", assets_icons_get(A_Plugins_14)); |                 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)); |                 AppLoaderContext* ctx = furi_alloc(sizeof(AppLoaderContext)); | ||||||
|                 ctx->state = &state; |                 ctx->state = &state; | ||||||
|                 ctx->app = &FLIPPER_PLUGINS[i]; |                 ctx->app = &FLIPPER_PLUGINS[i]; | ||||||
| @ -171,13 +174,11 @@ void app_loader(void* p) { | |||||||
|                         ctx)); |                         ctx)); | ||||||
| 
 | 
 | ||||||
|                 // Add cli command
 |                 // Add cli command
 | ||||||
|                 if(cli) { |                 string_t cli_name; | ||||||
|                     string_t cli_name; |                 string_init_set_str(cli_name, "app_"); | ||||||
|                     string_init_set_str(cli_name, "app_"); |                 string_cat_str(cli_name, FLIPPER_PLUGINS[i].name); | ||||||
|                     string_cat_str(cli_name, FLIPPER_PLUGINS[i].name); |                 cli_add_command(cli, string_get_cstr(cli_name), handle_cli, ctx); | ||||||
|                     cli_add_command(cli, string_get_cstr(cli_name), handle_cli, ctx); |                 string_clear(cli_name); | ||||||
|                     string_clear(cli_name); |  | ||||||
|                 } |  | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             menu_item_add(menu, menu_plugins); |             menu_item_add(menu, menu_plugins); | ||||||
|  | |||||||
							
								
								
									
										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 | #pragma once | ||||||
| 
 | 
 | ||||||
| #include "flipper.h" | #include <furi.h> | ||||||
|  | #include <assets_icons.h> | ||||||
| 
 | 
 | ||||||
| #ifdef APP_TEST | typedef void (*FlipperApplication)(void*); | ||||||
| void flipper_test_app(void* p); |  | ||||||
| #endif |  | ||||||
| 
 | 
 | ||||||
| void application_blink(void* p); | typedef struct { | ||||||
| void application_uart_write(void* p); |     const FlipperApplication app; | ||||||
| void application_ipc_display(void* p); |     const char* name; | ||||||
| void application_ipc_widget(void* p); |     const IconName icon; | ||||||
| void application_input_dump(void* p); | } 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); | extern const FuriApplication FLIPPER_PLUGINS[]; | ||||||
| void menu_task(void* p); | size_t FLIPPER_PLUGINS_size(); | ||||||
| 
 |  | ||||||
| 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 |  | ||||||
| }; |  | ||||||
|  | |||||||
| @ -2,6 +2,7 @@ APP_DIR		= $(PROJECT_ROOT)/applications | |||||||
| LIB_DIR 	= $(PROJECT_ROOT)/lib | LIB_DIR 	= $(PROJECT_ROOT)/lib | ||||||
| 
 | 
 | ||||||
| CFLAGS		+= -I$(APP_DIR) | CFLAGS		+= -I$(APP_DIR) | ||||||
|  | C_SOURCES	+= $(APP_DIR)/applications.c | ||||||
| 
 | 
 | ||||||
| # Use APP_* for autostart app
 | # Use APP_* for autostart app
 | ||||||
| # Use BUILD_* for add app to build
 | # 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) { | 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) { | void backlight_control(void* p) { | ||||||
|     // TODO open record
 |     // TODO open record
 | ||||||
|     const GpioPin* backlight_record = &backlight_gpio; |     const GpioPin* backlight_record = &backlight_gpio; | ||||||
| @ -14,20 +15,14 @@ void backlight_control(void* p) { | |||||||
|     gpio_init(backlight_record, GpioModeOutputPushPull); |     gpio_init(backlight_record, GpioModeOutputPushPull); | ||||||
|     gpio_write(backlight_record, true); |     gpio_write(backlight_record, true); | ||||||
| 
 | 
 | ||||||
|     StaticSemaphore_t event_descriptor; |  | ||||||
|     SemaphoreHandle_t update = xSemaphoreCreateCountingStatic(255, 0, &event_descriptor); |  | ||||||
| 
 |  | ||||||
|     // open record
 |     // open record
 | ||||||
|     PubSub* event_record = furi_open("input_events"); |     PubSub* event_record = furi_record_open("input_events"); | ||||||
|     furi_check(event_record); |     subscribe_pubsub(event_record, event_cb, (void*)osThreadGetId()); | ||||||
|     subscribe_pubsub(event_record, event_cb, (void*)update); |  | ||||||
| 
 |  | ||||||
|     // we ready to work
 |  | ||||||
|     furiac_ready(); |  | ||||||
| 
 | 
 | ||||||
|     while(1) { |     while(1) { | ||||||
|         // wait for event
 |         // 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); |             gpio_write(backlight_record, true); | ||||||
|         } else { |         } else { | ||||||
|             gpio_write(backlight_record, false); |             gpio_write(backlight_record, false); | ||||||
|  | |||||||
| @ -2,16 +2,23 @@ | |||||||
| 
 | 
 | ||||||
| Bt* bt_alloc() { | Bt* bt_alloc() { | ||||||
|     Bt* bt = furi_alloc(sizeof(Bt)); |     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_icon = assets_icons_get(I_Bluetooth_5x8); | ||||||
|     bt->statusbar_widget = widget_alloc(); |     bt->statusbar_widget = widget_alloc(); | ||||||
|     widget_set_width(bt->statusbar_widget, icon_get_width(bt->statusbar_icon)); |     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_draw_callback_set(bt->statusbar_widget, bt_draw_statusbar_callback, bt); | ||||||
|     widget_enabled_set(bt->statusbar_widget, false); |     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_icon = assets_icons_get(A_Bluetooth_14); | ||||||
|     bt->menu_item = menu_item_alloc_menu("Bluetooth", bt->menu_icon); |     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; |     return bt; | ||||||
| } | } | ||||||
| @ -33,23 +40,7 @@ void bt_cli_info(string_t args, void* context) { | |||||||
| void bt_task() { | void bt_task() { | ||||||
|     Bt* bt = bt_alloc(); |     Bt* bt = bt_alloc(); | ||||||
| 
 | 
 | ||||||
|     if(bt->cli) { |     furi_record_create("bt", bt); | ||||||
|         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(); |  | ||||||
| 
 | 
 | ||||||
|     api_hal_bt_init(); |     api_hal_bt_init(); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -2,10 +2,9 @@ | |||||||
| 
 | 
 | ||||||
| #include "bt.h" | #include "bt.h" | ||||||
| 
 | 
 | ||||||
| #include <cli/cli.h> | #include <furi.h> | ||||||
| 
 | 
 | ||||||
| #include <flipper.h> | #include <cli/cli.h> | ||||||
| #include <flipper_v2.h> |  | ||||||
| 
 | 
 | ||||||
| #include <gui/gui.h> | #include <gui/gui.h> | ||||||
| #include <gui/widget.h> | #include <gui/widget.h> | ||||||
| @ -15,6 +14,8 @@ | |||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     Cli* cli; |     Cli* cli; | ||||||
|  |     Gui* gui; | ||||||
|  |     ValueMutex* menu; | ||||||
|     // Status bar
 |     // Status bar
 | ||||||
|     Icon* statusbar_icon; |     Icon* statusbar_icon; | ||||||
|     Widget* statusbar_widget; |     Widget* statusbar_widget; | ||||||
| @ -26,3 +27,7 @@ typedef struct { | |||||||
| Bt* bt_alloc(); | Bt* bt_alloc(); | ||||||
| 
 | 
 | ||||||
| void bt_draw_statusbar_callback(Canvas* canvas, void* context); | 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.h" | ||||||
| 
 | #include <furi.h> | ||||||
| #include "cc1101-workaround/cc1101.h" | #include <gui/gui.h> | ||||||
|  | #include <input/input.h> | ||||||
| 
 | 
 | ||||||
| extern "C" void cli_print(const char* str); | 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) { | static void input_callback(InputEvent* input_event, void* ctx) { | ||||||
|     osMessageQueueId_t event_queue = (QueueHandle_t)ctx; |     osMessageQueueId_t event_queue = ctx; | ||||||
| 
 | 
 | ||||||
|     AppEvent event; |     AppEvent event; | ||||||
|     event.type = EventTypeKey; |     event.type = EventTypeKey; | ||||||
| @ -370,7 +371,7 @@ extern "C" void cc1101_workaround(void* p) { | |||||||
|     widget_input_callback_set(widget, input_callback, event_queue); |     widget_input_callback_set(widget, input_callback, event_queue); | ||||||
| 
 | 
 | ||||||
|     // Open GUI and register widget
 |     // Open GUI and register widget
 | ||||||
|     Gui* gui = (Gui*)furi_open("gui"); |     Gui* gui = (Gui*)furi_record_open("gui"); | ||||||
|     if(gui == NULL) { |     if(gui == NULL) { | ||||||
|         printf("[cc1101] gui is not available\n"); |         printf("[cc1101] gui is not available\n"); | ||||||
|         furiac_exit(NULL); |         furiac_exit(NULL); | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| #include "flipper_v2.h" | #include <furi.h> | ||||||
| #include "cc1101-workaround/cc1101.h" | #include "cc1101-workaround/cc1101.h" | ||||||
| #include "spi.h" | #include "spi.h" | ||||||
| #include <math.h> | #include <math.h> | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #include "flipper_v2.h" | #include <furi.h> | ||||||
| 
 | 
 | ||||||
| #define F_OSC 26e6 | #define F_OSC 26e6 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,8 +1,6 @@ | |||||||
| #include "cli_i.h" | #include "cli_i.h" | ||||||
| #include "cli_commands.h" | #include "cli_commands.h" | ||||||
| 
 | 
 | ||||||
| #include <api-hal-vcp.h> |  | ||||||
| 
 |  | ||||||
| Cli* cli_alloc() { | Cli* cli_alloc() { | ||||||
|     Cli* cli = furi_alloc(sizeof(Cli)); |     Cli* cli = furi_alloc(sizeof(Cli)); | ||||||
|     CliCommandDict_init(cli->commands); |     CliCommandDict_init(cli->commands); | ||||||
| @ -175,12 +173,7 @@ void cli_task(void* p) { | |||||||
|     // Init basic cli commands
 |     // Init basic cli commands
 | ||||||
|     cli_commands_init(cli); |     cli_commands_init(cli); | ||||||
| 
 | 
 | ||||||
|     if(!furi_create("cli", cli)) { |     furi_record_create("cli", cli); | ||||||
|         printf("[cli_task] cannot create the cli record\n"); |  | ||||||
|         furiac_exit(NULL); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     furiac_ready(); |  | ||||||
| 
 | 
 | ||||||
|     while(1) { |     while(1) { | ||||||
|         cli_process_input(cli); |         cli_process_input(cli); | ||||||
|  | |||||||
| @ -2,8 +2,7 @@ | |||||||
| 
 | 
 | ||||||
| #include "cli.h" | #include "cli.h" | ||||||
| 
 | 
 | ||||||
| #include <flipper.h> | #include <furi.h> | ||||||
| #include <flipper_v2.h> |  | ||||||
| 
 | 
 | ||||||
| #include <m-dict.h> | #include <m-dict.h> | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,12 +1,10 @@ | |||||||
| #include "flipper.h" | #include <furi.h> | ||||||
| #include "u8g2/u8g2.h" | #include "u8g2/u8g2.h" | ||||||
| 
 | 
 | ||||||
| extern TIM_HandleTypeDef SPEAKER_TIM; | extern TIM_HandleTypeDef SPEAKER_TIM; | ||||||
| 
 | 
 | ||||||
| void coreglitch_demo_0(void* p) { | void coreglitch_demo_0(void* p) { | ||||||
|     FuriRecordSubscriber* log = get_default_log(); |     printf("coreglitch demo!\n"); | ||||||
| 
 |  | ||||||
|     fuprintf(log, "coreglitch demo!\n"); |  | ||||||
| 
 | 
 | ||||||
|     float notes[] = { |     float notes[] = { | ||||||
|         0.0, |         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
 |     // State
 | ||||||
|     dolphin->state = dolphin_state_alloc(); |     dolphin->state = dolphin_state_alloc(); | ||||||
|     // Menu
 |     // Menu
 | ||||||
|     dolphin->menu_vm = furi_open("menu"); |     dolphin->menu_vm = furi_record_open("menu"); | ||||||
|     furi_check(dolphin->menu_vm); |  | ||||||
|     // GUI
 |     // GUI
 | ||||||
|     dolphin->idle_view_dispatcher = view_dispatcher_alloc(); |     dolphin->idle_view_dispatcher = view_dispatcher_alloc(); | ||||||
|     // First start View
 |     // First start View
 | ||||||
| @ -125,7 +124,7 @@ void dolphin_deed(Dolphin* dolphin, DolphinDeed deed) { | |||||||
| void dolphin_task() { | void dolphin_task() { | ||||||
|     Dolphin* dolphin = dolphin_alloc(); |     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); |     view_dispatcher_attach_to_gui(dolphin->idle_view_dispatcher, gui, ViewDispatcherTypeWindow); | ||||||
|     if(dolphin_state_load(dolphin->state)) { |     if(dolphin_state_load(dolphin->state)) { | ||||||
|         view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewIdleMain); |         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); |             model->butthurt = dolphin_state_get_butthurt(dolphin->state); | ||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
|     if(!furi_create("dolphin", dolphin)) { |     furi_record_create("dolphin", dolphin); | ||||||
|         printf("[dolphin_task] cannot create the dolphin record\n"); |  | ||||||
|         furiac_exit(NULL); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     furiac_ready(); |  | ||||||
| 
 | 
 | ||||||
|     DolphinEvent event; |     DolphinEvent event; | ||||||
|     while(1) { |     while(1) { | ||||||
|  | |||||||
| @ -4,7 +4,7 @@ | |||||||
| #include "dolphin_state.h" | #include "dolphin_state.h" | ||||||
| #include "dolphin_views.h" | #include "dolphin_views.h" | ||||||
| 
 | 
 | ||||||
| #include <flipper_v2.h> | #include <furi.h> | ||||||
| 
 | 
 | ||||||
| #include <gui/gui.h> | #include <gui/gui.h> | ||||||
| #include <gui/view_dispatcher.h> | #include <gui/view_dispatcher.h> | ||||||
|  | |||||||
| @ -1,6 +1,5 @@ | |||||||
| #include "dolphin_state.h" | #include "dolphin_state.h" | ||||||
| #include <api-hal-flash.h> | #include <furi.h> | ||||||
| #include <flipper_v2.h> |  | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     uint8_t magic; |     uint8_t magic; | ||||||
|  | |||||||
| @ -3,7 +3,8 @@ | |||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
| #include <stdbool.h> | #include <stdbool.h> | ||||||
| #include <gui/canvas.h> | #include <gui/canvas.h> | ||||||
| #include <flipper_v2.h> | #include <input/input.h> | ||||||
|  | #include <furi.h> | ||||||
| 
 | 
 | ||||||
| // Idle scree
 | // Idle scree
 | ||||||
| typedef enum { | typedef enum { | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| #include "flipper_v2.h" | #include <furi.h> | ||||||
| 
 | 
 | ||||||
| void rgb_set( | void rgb_set( | ||||||
|     bool r, |     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 <stdio.h> | ||||||
|  | #include <input/input.h> | ||||||
| 
 | 
 | ||||||
| typedef union { | typedef union { | ||||||
|     unsigned int packed; |     unsigned int packed; | ||||||
| @ -21,12 +22,10 @@ static void event_cb(const void* value, void* ctx) { | |||||||
| 
 | 
 | ||||||
| void application_input_dump(void* p) { | void application_input_dump(void* p) { | ||||||
|     // open record
 |     // open record
 | ||||||
|     ValueManager* state_record = furi_open("input_state"); |     ValueManager* state_record = furi_record_open("input_state"); | ||||||
|     furi_check(state_record); |  | ||||||
|     subscribe_pubsub(&state_record->pubsub, state_cb, NULL); |     subscribe_pubsub(&state_record->pubsub, state_cb, NULL); | ||||||
| 
 | 
 | ||||||
|     PubSub* event_record = furi_open("input_events"); |     PubSub* event_record = furi_record_open("input_events"); | ||||||
|     furi_check(event_record); |  | ||||||
|     subscribe_pubsub(event_record, event_cb, NULL); |     subscribe_pubsub(event_record, event_cb, NULL); | ||||||
| 
 | 
 | ||||||
|     printf("Example app [input dump]\n"); |     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) { | static void event_cb(const void* value, void* ctx) { | ||||||
|     const InputEvent* event = value; |     const InputEvent* event = value; | ||||||
| @ -38,8 +39,7 @@ void application_strobe(void* p) { | |||||||
|     ValueMutex delay_mutex; |     ValueMutex delay_mutex; | ||||||
|     init_mutex(&delay_mutex, &delay_time_holder, sizeof(delay_time_holder)); |     init_mutex(&delay_mutex, &delay_time_holder, sizeof(delay_time_holder)); | ||||||
| 
 | 
 | ||||||
|     PubSub* event_record = furi_open("input_events"); |     PubSub* event_record = furi_record_open("input_events"); | ||||||
|     furi_check(event_record); |  | ||||||
|     subscribe_pubsub(event_record, event_cb, &delay_mutex); |     subscribe_pubsub(event_record, event_cb, &delay_mutex); | ||||||
| 
 | 
 | ||||||
|     while(1) { |     while(1) { | ||||||
|  | |||||||
| @ -1,32 +1,14 @@ | |||||||
| #include "u8g2/u8g2.h" | #include "u8g2/u8g2.h" | ||||||
| #include "flipper.h" | #include <furi.h> | ||||||
| 
 | 
 | ||||||
| void u8g2_example(void* p) { | void u8g2_example(void* p) { | ||||||
|     FuriRecordSubscriber* log = get_default_log(); |  | ||||||
| 
 |  | ||||||
|     // open record
 |     // open record
 | ||||||
|     FuriRecordSubscriber* fb_record = |     u8g2_t* fb = furi_record_open("u8g2_fb"); | ||||||
|         furi_open_deprecated("u8g2_fb", false, false, NULL, NULL, NULL); |     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) { |     furiac_exit(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); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
| @ -1,6 +1,9 @@ | |||||||
| #include "u8g2/u8g2.h" | #include "u8g2/u8g2.h" | ||||||
| #include "qrcode/qrcode.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) { | void u8g2_DrawPixelSize(u8g2_t* u8g2, uint8_t x, uint8_t y, uint8_t size) { | ||||||
|     for(uint8_t px = 0; px < size; px++) { |     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) { | void u8g2_qrcode(void* p) { | ||||||
|     FuriRecordSubscriber* log = get_default_log(); |  | ||||||
| 
 |  | ||||||
|     // open record
 |     // open record
 | ||||||
|     FuriRecordSubscriber* fb_record = |     FuriRecordSubscriber* fb_record = | ||||||
|         furi_open_deprecated("u8g2_fb", false, false, NULL, NULL, NULL); |         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"); |     qrcode_initText(&qrcode, qrcodeBytes, qr_version, qr_error_correction, "HELLO FLIPPER"); | ||||||
| 
 | 
 | ||||||
|     if(fb_record == NULL) { |     if(fb_record == NULL) { | ||||||
|         fuprintf(log, "[widget] cannot create fb record\n"); |         printf("[widget] cannot create fb record\n"); | ||||||
|         furiac_exit(NULL); |         furiac_exit(NULL); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -70,3 +71,4 @@ void u8g2_qrcode(void* p) { | |||||||
|         delay(1); |         delay(1); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | */ | ||||||
| @ -1,7 +1,5 @@ | |||||||
| #include "flipper.h" | #include <furi.h> | ||||||
| #include <string.h> | #include <string.h> | ||||||
| #include "log.h" |  | ||||||
| #include "flipper_v2.h" |  | ||||||
| 
 | 
 | ||||||
| void application_uart_write(void* p) { | void application_uart_write(void* p) { | ||||||
|     // Red led for showing progress
 |     // Red led for showing progress
 | ||||||
| @ -11,12 +9,9 @@ void application_uart_write(void* p) { | |||||||
| 
 | 
 | ||||||
|     gpio_init(led_record, GpioModeOutputOpenDrain); |     gpio_init(led_record, GpioModeOutputOpenDrain); | ||||||
| 
 | 
 | ||||||
|     // get_default_log open "tty" record
 |  | ||||||
|     FuriRecordSubscriber* log = get_default_log(); |  | ||||||
| 
 |  | ||||||
|     // create buffer
 |     // create buffer
 | ||||||
|     const char test_string[] = "test\n"; |     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
 |     // for example, create counter and show its value
 | ||||||
|     uint8_t counter = 0; |     uint8_t counter = 0; | ||||||
|  | |||||||
| @ -1,4 +1,5 @@ | |||||||
| #include "flipper_v2.h" | #include <furi.h> | ||||||
|  | #include <input/input.h> | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     GpioPin* led; |     GpioPin* led; | ||||||
| @ -24,7 +25,7 @@ void application_vibro(void* p) { | |||||||
|     gpio_write(ctx.vibro, false); |     gpio_write(ctx.vibro, false); | ||||||
| 
 | 
 | ||||||
|     // subscribe on buttons
 |     // subscribe on buttons
 | ||||||
|     PubSub* event_record = furi_open("input_events"); |     PubSub* event_record = furi_record_open("input_events"); | ||||||
|     furi_check(event_record); |     furi_check(event_record); | ||||||
|     subscribe_pubsub(event_record, button_handler, &ctx); |     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 { | typedef struct { | ||||||
|     const char* name; |     const char* name; | ||||||
| @ -47,7 +49,7 @@ static void render_callback(Canvas* canvas, void* ctx) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void input_callback(InputEvent* input_event, 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; |     AppEvent event; | ||||||
|     event.type = EventTypeKey; |     event.type = EventTypeKey; | ||||||
| @ -74,11 +76,7 @@ void app_gpio_test(void* p) { | |||||||
|     widget_input_callback_set(widget, input_callback, event_queue); |     widget_input_callback_set(widget, input_callback, event_queue); | ||||||
| 
 | 
 | ||||||
|     // Open GUI and register widget
 |     // Open GUI and register widget
 | ||||||
|     Gui* gui = (Gui*)furi_open("gui"); |     Gui* gui = furi_record_open("gui"); | ||||||
|     if(gui == NULL) { |  | ||||||
|         printf("[gpio-tester] gui is not available\n"); |  | ||||||
|         furiac_exit(NULL); |  | ||||||
|     } |  | ||||||
|     gui_add_widget(gui, widget, GuiLayerFullscreen); |     gui_add_widget(gui, widget, GuiLayerFullscreen); | ||||||
| 
 | 
 | ||||||
|     // configure pin
 |     // configure pin
 | ||||||
|  | |||||||
| @ -1,8 +1,7 @@ | |||||||
| #include "canvas_i.h" | #include "canvas_i.h" | ||||||
| #include "icon_i.h" | #include "icon_i.h" | ||||||
| 
 | 
 | ||||||
| #include <flipper.h> | #include <furi.h> | ||||||
| #include <flipper_v2.h> |  | ||||||
| 
 | 
 | ||||||
| struct Canvas { | struct Canvas { | ||||||
|     u8g2_t fb; |     u8g2_t fb; | ||||||
|  | |||||||
| @ -5,6 +5,10 @@ | |||||||
| #include <gui/icon.h> | #include <gui/icon.h> | ||||||
| #include <assets_icons_i.h> | #include <assets_icons_i.h> | ||||||
| 
 | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     ColorWhite = 0x00, |     ColorWhite = 0x00, | ||||||
|     ColorBlack = 0x01, |     ColorBlack = 0x01, | ||||||
| @ -91,3 +95,7 @@ void canvas_draw_line(Canvas* canvas, uint8_t x1, uint8_t y1, uint8_t x2, uint8_ | |||||||
|  * Draw glyph |  * Draw glyph | ||||||
|  */ |  */ | ||||||
| void canvas_draw_glyph(Canvas* canvas, uint8_t x, uint8_t y, uint16_t ch); | 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 <stdint.h> | ||||||
| #include "canvas.h" | #include "canvas.h" | ||||||
| 
 | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| /*
 | /*
 | ||||||
|  * Draw scrollbar on canvas. |  * Draw scrollbar on canvas. | ||||||
|  * width 3px, height equal to canvas height |  * 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 |  * @param width, height - frame width and height | ||||||
|  */ |  */ | ||||||
| void elements_frame(Canvas* canvas, uint8_t x, uint8_t y, uint8_t width, uint8_t 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.h" | ||||||
| #include "gui_i.h" | #include "gui_i.h" | ||||||
| 
 | 
 | ||||||
| #include <flipper.h> | #include <furi.h> | ||||||
| #include <flipper_v2.h> |  | ||||||
| #include <m-array.h> | #include <m-array.h> | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| 
 | 
 | ||||||
| @ -207,13 +206,9 @@ Gui* gui_alloc() { | |||||||
| 
 | 
 | ||||||
| void gui_task(void* p) { | void gui_task(void* p) { | ||||||
|     Gui* gui = gui_alloc(); |     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
 |     // Forever dispatch
 | ||||||
|     while(1) { |     while(1) { | ||||||
|  | |||||||
| @ -3,6 +3,10 @@ | |||||||
| #include "widget.h" | #include "widget.h" | ||||||
| #include "canvas.h" | #include "canvas.h" | ||||||
| 
 | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| #define GUI_DISPLAY_WIDTH 128 | #define GUI_DISPLAY_WIDTH 128 | ||||||
| #define GUI_DISPLAY_HEIGHT 64 | #define GUI_DISPLAY_HEIGHT 64 | ||||||
| 
 | 
 | ||||||
| @ -40,3 +44,7 @@ void gui_add_widget(Gui* gui, Widget* widget, GuiLayer layer); | |||||||
|  * @remarks thread safe |  * @remarks thread safe | ||||||
|  */ |  */ | ||||||
| void gui_remove_widget(Gui* gui, Widget* widget); | void gui_remove_widget(Gui* gui, Widget* widget); | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| #include "gui_event.h" | #include "gui_event.h" | ||||||
| 
 | 
 | ||||||
| #include <flipper_v2.h> | #include <furi.h> | ||||||
| 
 | 
 | ||||||
| #define GUI_EVENT_MQUEUE_SIZE 8 | #define GUI_EVENT_MQUEUE_SIZE 8 | ||||||
| 
 | 
 | ||||||
| @ -45,7 +45,7 @@ GuiEvent* gui_event_alloc() { | |||||||
|     // osTimerStart(gui_event->timer, 1024 / 4);
 |     // osTimerStart(gui_event->timer, 1024 / 4);
 | ||||||
| 
 | 
 | ||||||
|     // Input
 |     // 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); |     furi_check(gui_event->input_event_record != NULL); | ||||||
|     subscribe_pubsub(gui_event->input_event_record, gui_event_input_events_callback, gui_event); |     subscribe_pubsub(gui_event->input_event_record, gui_event_input_events_callback, gui_event); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -3,6 +3,10 @@ | |||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
| #include <input/input.h> | #include <input/input.h> | ||||||
| 
 | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     GuiMessageTypeRedraw = 0x00, |     GuiMessageTypeRedraw = 0x00, | ||||||
|     GuiMessageTypeInput = 0x01, |     GuiMessageTypeInput = 0x01, | ||||||
| @ -23,3 +27,7 @@ void gui_event_free(GuiEvent* gui_event); | |||||||
| void gui_event_messsage_send(GuiEvent* gui_event, GuiMessage* message); | void gui_event_messsage_send(GuiEvent* gui_event, GuiMessage* message); | ||||||
| 
 | 
 | ||||||
| GuiMessage gui_event_message_next(GuiEvent* gui_event); | GuiMessage gui_event_message_next(GuiEvent* gui_event); | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | |||||||
| @ -1,8 +1,6 @@ | |||||||
| #include "icon_i.h" | #include "icon_i.h" | ||||||
| 
 | 
 | ||||||
| #include <cmsis_os2.h> | #include <furi.h> | ||||||
| #include <flipper.h> |  | ||||||
| #include <flipper_v2.h> |  | ||||||
| 
 | 
 | ||||||
| Icon* icon_alloc(const IconData* data) { | Icon* icon_alloc(const IconData* data) { | ||||||
|     Icon* icon = furi_alloc(sizeof(Icon)); |     Icon* icon = furi_alloc(sizeof(Icon)); | ||||||
|  | |||||||
| @ -3,6 +3,10 @@ | |||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
| #include <stdbool.h> | #include <stdbool.h> | ||||||
| 
 | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| typedef struct IconData IconData; | typedef struct IconData IconData; | ||||||
| typedef struct Icon Icon; | typedef struct Icon Icon; | ||||||
| 
 | 
 | ||||||
| @ -41,3 +45,7 @@ void icon_start_animation(Icon* icon); | |||||||
|  * Stop icon animation |  * Stop icon animation | ||||||
|  */ |  */ | ||||||
| void icon_stop_animation(Icon* icon); | void icon_stop_animation(Icon* icon); | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| #include "u8g2/u8g2.h" | #include "u8g2/u8g2.h" | ||||||
| #include "flipper.h" | #include <furi.h> | ||||||
| #include <main.h> | #include <main.h> | ||||||
| 
 | 
 | ||||||
| extern SPI_HandleTypeDef SPI_D; | 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
 |     // Function to define the logic level of the RESET line
 | ||||||
|     case U8X8_MSG_GPIO_RESET: |     case U8X8_MSG_GPIO_RESET: | ||||||
| #ifdef DEBUG | #ifdef DEBUG | ||||||
|         fuprintf(log, "[u8g2] rst %d\n", arg_int); |         printf("[u8g2] rst %d\n", arg_int); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|         // TODO change it to FuriRecord pin
 |         // 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: |     default: | ||||||
| #ifdef DEBUG | #ifdef DEBUG | ||||||
|         fufuprintf(log, "[u8g2] unknown io %d\n", msg); |         printf("[u8g2] unknown io %d\n", msg); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|         return 0; //A message was received which is not implemented, return 0 to indicate an error
 |         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) { |     switch(msg) { | ||||||
|     case U8X8_MSG_BYTE_SEND: |     case U8X8_MSG_BYTE_SEND: | ||||||
| #ifdef DEBUG | #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 | #endif | ||||||
| 
 | 
 | ||||||
|         // TODO change it to FuriRecord SPI
 |         // 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: |     case U8X8_MSG_BYTE_SET_DC: | ||||||
| #ifdef DEBUG | #ifdef DEBUG | ||||||
|         fuprintf(log, "[u8g2] dc %d\n", arg_int); |         printf("[u8g2] dc %d\n", arg_int); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|         // TODO change it to FuriRecord pin
 |         // 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: |     case U8X8_MSG_BYTE_INIT: | ||||||
| #ifdef DEBUG | #ifdef DEBUG | ||||||
|         fuprintf(log, "[u8g2] init\n"); |         printf("[u8g2] init\n"); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|         // TODO change it to FuriRecord pin
 |         // 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: |     case U8X8_MSG_BYTE_START_TRANSFER: | ||||||
| #ifdef DEBUG | #ifdef DEBUG | ||||||
|         fuprintf(log, "[u8g2] start\n"); |         printf("[u8g2] start\n"); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|         // TODO: SPI manager
 |         // 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: |     case U8X8_MSG_BYTE_END_TRANSFER: | ||||||
| #ifdef DEBUG | #ifdef DEBUG | ||||||
|         fuprintf(log, "[u8g2] end\n"); |         printf("[u8g2] end\n"); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|         asm("nop"); |         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: |     default: | ||||||
| #ifdef DEBUG | #ifdef DEBUG | ||||||
|         fuprintf(log, "[u8g2] unknown xfer %d\n", msg); |         printf("[u8g2] unknown xfer %d\n", msg); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|         return 0; |         return 0; | ||||||
|  | |||||||
| @ -3,6 +3,10 @@ | |||||||
| #include <input/input.h> | #include <input/input.h> | ||||||
| #include "canvas.h" | #include "canvas.h" | ||||||
| 
 | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| /* Hides drawing widget */ | /* Hides drawing widget */ | ||||||
| #define VIEW_NONE 0xFFFFFFFF | #define VIEW_NONE 0xFFFFFFFF | ||||||
| /* Ignore navigation event */ | /* Ignore navigation event */ | ||||||
| @ -127,3 +131,7 @@ void view_commit_model(View* view); | |||||||
|         ({ void __fn__ function_body __fn__; })(p); \ |         ({ void __fn__ function_body __fn__; })(p); \ | ||||||
|         view_commit_model(view);                    \ |         view_commit_model(view);                    \ | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | |||||||
| @ -3,6 +3,10 @@ | |||||||
| #include "view.h" | #include "view.h" | ||||||
| #include "gui.h" | #include "gui.h" | ||||||
| 
 | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| /* ViewDispatcher widget placement */ | /* ViewDispatcher widget placement */ | ||||||
| typedef enum { | typedef enum { | ||||||
|     ViewDispatcherTypeNone, /* Special layer for internal use only */ |     ViewDispatcherTypeNone, /* Special layer for internal use only */ | ||||||
| @ -43,3 +47,7 @@ void view_dispatcher_attach_to_gui( | |||||||
|     ViewDispatcher* view_dispatcher, |     ViewDispatcher* view_dispatcher, | ||||||
|     Gui* gui, |     Gui* gui, | ||||||
|     ViewDispatcherType type); |     ViewDispatcherType type); | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | |||||||
| @ -2,7 +2,7 @@ | |||||||
| 
 | 
 | ||||||
| #include "view_dispatcher.h" | #include "view_dispatcher.h" | ||||||
| #include "view_i.h" | #include "view_i.h" | ||||||
| #include <flipper_v2.h> | #include <furi.h> | ||||||
| #include <m-dict.h> | #include <m-dict.h> | ||||||
| 
 | 
 | ||||||
| DICT_DEF2(ViewDict, uint32_t, M_DEFAULT_OPLIST, View*, M_PTR_OPLIST) | DICT_DEF2(ViewDict, uint32_t, M_DEFAULT_OPLIST, View*, M_PTR_OPLIST) | ||||||
|  | |||||||
| @ -2,7 +2,7 @@ | |||||||
| 
 | 
 | ||||||
| #include "view.h" | #include "view.h" | ||||||
| #include "view_dispatcher_i.h" | #include "view_dispatcher_i.h" | ||||||
| #include <flipper_v2.h> | #include <furi.h> | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     void* data; |     void* data; | ||||||
|  | |||||||
| @ -1,8 +1,6 @@ | |||||||
| #include "widget_i.h" | #include "widget_i.h" | ||||||
| 
 | 
 | ||||||
| #include <cmsis_os.h> | #include <furi.h> | ||||||
| #include <flipper.h> |  | ||||||
| #include <flipper_v2.h> |  | ||||||
| 
 | 
 | ||||||
| #include "gui.h" | #include "gui.h" | ||||||
| #include "gui_i.h" | #include "gui_i.h" | ||||||
| @ -73,8 +71,6 @@ void widget_update(Widget* widget) { | |||||||
| 
 | 
 | ||||||
| void widget_gui_set(Widget* widget, Gui* gui) { | void widget_gui_set(Widget* widget, Gui* gui) { | ||||||
|     furi_assert(widget); |     furi_assert(widget); | ||||||
|     furi_assert(gui); |  | ||||||
| 
 |  | ||||||
|     widget->gui = gui; |     widget->gui = gui; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -3,6 +3,10 @@ | |||||||
| #include <input/input.h> | #include <input/input.h> | ||||||
| #include "canvas.h" | #include "canvas.h" | ||||||
| 
 | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| typedef struct Widget Widget; | 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. |  * Rendering will happen later after GUI system process signal. | ||||||
|  */ |  */ | ||||||
| void widget_update(Widget* widget); | void widget_update(Widget* widget); | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | |||||||
| @ -32,7 +32,7 @@ void AppiButton::run() { | |||||||
|                     printf("[ibutton] bye!\n"); |                     printf("[ibutton] bye!\n"); | ||||||
|                     // TODO remove all widgets create by app
 |                     // TODO remove all widgets create by app
 | ||||||
|                     widget_enabled_set(widget, false); |                     widget_enabled_set(widget, false); | ||||||
|                     furiac_exit(NULL); |                     osThreadExit(); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 if(event.value.input.state && event.value.input.input == InputLeft) { |                 if(event.value.input.state && event.value.input.input == InputLeft) { | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| #include <input/input.h> | #include <input/input.h> | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| #include <flipper_v2.h> | #include <furi.h> | ||||||
| 
 | 
 | ||||||
| #ifdef APP_NFC | #ifdef APP_NFC | ||||||
| void nfc_isr(void); | void nfc_isr(void); | ||||||
| @ -35,18 +35,10 @@ void input_task(void* p) { | |||||||
|         furiac_exit(NULL); |         furiac_exit(NULL); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if(!furi_create("input_state", &input_state_record)) { |     furi_record_create("input_state", &input_state_record); | ||||||
|         printf("[input_task] cannot create the input_state record\n"); |     furi_record_create("input_events", &input_events_record); | ||||||
|         furiac_exit(NULL); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if(!furi_create("input_events", &input_events_record)) { |  | ||||||
|         printf("[input_task] cannot create the input_events record\n"); |  | ||||||
|         furiac_exit(NULL); |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     // we ready to work
 |     // we ready to work
 | ||||||
|     furiac_ready(); |  | ||||||
|     initialized = true; |     initialized = true; | ||||||
| 
 | 
 | ||||||
|     // Force state update
 |     // Force state update
 | ||||||
|  | |||||||
| @ -1,6 +1,5 @@ | |||||||
| #pragma once | #pragma once | ||||||
| #include "flipper.h" | #include <furi.h> | ||||||
| #include "flipper_v2.h" |  | ||||||
| #include "irda-decoder-nec.h" | #include "irda-decoder-nec.h" | ||||||
| #include "irda-decoder-types.h" | #include "irda-decoder-types.h" | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,5 +1,7 @@ | |||||||
| #include "flipper.h" | #include <furi.h> | ||||||
| #include "flipper_v2.h" | #include <gui/gui.h> | ||||||
|  | #include <input/input.h> | ||||||
|  | 
 | ||||||
| #include "irda_nec.h" | #include "irda_nec.h" | ||||||
| #include "irda_samsung.h" | #include "irda_samsung.h" | ||||||
| #include "irda_protocols.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) { | static void input_callback(InputEvent* input_event, void* ctx) { | ||||||
|     osMessageQueueId_t event_queue = (QueueHandle_t)ctx; |     osMessageQueueId_t event_queue = ctx; | ||||||
| 
 | 
 | ||||||
|     AppEvent event; |     AppEvent event; | ||||||
|     event.type = EventTypeKey; |     event.type = EventTypeKey; | ||||||
| @ -271,11 +273,7 @@ void irda(void* p) { | |||||||
|     widget_input_callback_set(widget, input_callback, event_queue); |     widget_input_callback_set(widget, input_callback, event_queue); | ||||||
| 
 | 
 | ||||||
|     // Open GUI and register widget
 |     // 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); |  | ||||||
|     } |  | ||||||
|     gui_add_widget(gui, widget, GuiLayerFullscreen); |     gui_add_widget(gui, widget, GuiLayerFullscreen); | ||||||
| 
 | 
 | ||||||
|     // Red LED
 |     // Red LED
 | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| #include "flipper.h" | #include <furi.h> | ||||||
| #include "irda_nec.h" | #include "irda_nec.h" | ||||||
| #include "irda_protocols.h" | #include "irda_protocols.h" | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| #pragma once | #pragma once | ||||||
| #include "flipper.h" | #include <furi.h> | ||||||
| 
 | 
 | ||||||
| void ir_nec_send(uint16_t addr, uint8_t data); | 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_samsung.h" | ||||||
| #include "irda_protocols.h" | #include "irda_protocols.h" | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| #pragma once | #pragma once | ||||||
| #include "flipper.h" | #include <furi.h> | ||||||
| 
 | 
 | ||||||
| void ir_samsung_send(uint16_t addr, uint16_t data); | 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) { | void prepare_data(uint32_t ID, uint32_t VENDOR, uint8_t* data) { | ||||||
|     uint8_t value[10]; |     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; | 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) { | static void input_callback(InputEvent* input_event, void* ctx) { | ||||||
|     osMessageQueueId_t event_queue = (QueueHandle_t)ctx; |     osMessageQueueId_t event_queue = ctx; | ||||||
| 
 | 
 | ||||||
|     AppEvent event; |     AppEvent event; | ||||||
|     event.type = EventTypeKey; |     event.type = EventTypeKey; | ||||||
| @ -67,7 +68,7 @@ void comparator_trigger_callback(void* hcomp, void* comp_ctx) { | |||||||
| 
 | 
 | ||||||
|     // gpio_write(&debug_0, true);
 |     // gpio_write(&debug_0, true);
 | ||||||
| 
 | 
 | ||||||
|     osMessageQueueId_t event_queue = (QueueHandle_t)comp_ctx; |     osMessageQueueId_t event_queue = comp_ctx; | ||||||
| 
 | 
 | ||||||
|     AppEvent event; |     AppEvent event; | ||||||
|     event.type = EventTypeRx; |     event.type = EventTypeRx; | ||||||
| @ -202,11 +203,7 @@ void lf_rfid_workaround(void* p) { | |||||||
|     widget_input_callback_set(widget, input_callback, event_queue); |     widget_input_callback_set(widget, input_callback, event_queue); | ||||||
| 
 | 
 | ||||||
|     // Open GUI and register widget
 |     // 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); |  | ||||||
|     } |  | ||||||
|     gui_add_widget(gui, widget, GuiLayerFullscreen); |     gui_add_widget(gui, widget, GuiLayerFullscreen); | ||||||
| 
 | 
 | ||||||
|     AppEvent event; |     AppEvent event; | ||||||
|  | |||||||
| @ -1,9 +1,8 @@ | |||||||
| #include "menu.h" | #include "menu.h" | ||||||
| #include <cmsis_os.h> |  | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| #include <stdbool.h> | #include <stdbool.h> | ||||||
| 
 | 
 | ||||||
| #include <flipper_v2.h> | #include <furi.h> | ||||||
| #include <gui/gui.h> | #include <gui/gui.h> | ||||||
| #include <gui/elements.h> | #include <gui/elements.h> | ||||||
| 
 | 
 | ||||||
| @ -42,8 +41,7 @@ ValueMutex* menu_init() { | |||||||
|     menu->widget = widget_alloc(); |     menu->widget = widget_alloc(); | ||||||
| 
 | 
 | ||||||
|     // Open GUI and register fullscreen widget
 |     // Open GUI and register fullscreen widget
 | ||||||
|     Gui* gui = furi_open("gui"); |     Gui* gui = furi_record_open("gui"); | ||||||
|     furi_check(gui); |  | ||||||
|     gui_add_widget(gui, menu->widget, GuiLayerFullscreen); |     gui_add_widget(gui, menu->widget, GuiLayerFullscreen); | ||||||
| 
 | 
 | ||||||
|     widget_enabled_set(menu->widget, false); |     widget_enabled_set(menu->widget, false); | ||||||
| @ -237,12 +235,7 @@ void menu_task(void* p) { | |||||||
|         release_mutex(menu_mutex, menu); |         release_mutex(menu_mutex, menu); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if(!furi_create("menu", menu_mutex)) { |     furi_record_create("menu", menu_mutex); | ||||||
|         printf("[menu_task] cannot create the menu record\n"); |  | ||||||
|         furiac_exit(NULL); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     furiac_ready(); |  | ||||||
| 
 | 
 | ||||||
|     while(1) { |     while(1) { | ||||||
|         MenuMessage m = menu_event_next(menu_event); |         MenuMessage m = menu_event_next(menu_event); | ||||||
|  | |||||||
| @ -1,11 +1,9 @@ | |||||||
| #include "menu_event.h" | #include "menu_event.h" | ||||||
| 
 | 
 | ||||||
| #include <cmsis_os.h> |  | ||||||
| #include <string.h> | #include <string.h> | ||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
| 
 | 
 | ||||||
| #include <flipper.h> | #include <furi.h> | ||||||
| #include <flipper_v2.h> |  | ||||||
| 
 | 
 | ||||||
| #define MENU_MESSAGE_MQUEUE_SIZE 8 | #define MENU_MESSAGE_MQUEUE_SIZE 8 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,8 +1,7 @@ | |||||||
| #include "menu_item.h" | #include "menu_item.h" | ||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
| #include <string.h> | #include <string.h> | ||||||
| #include <flipper.h> | #include <furi.h> | ||||||
| #include <flipper_v2.h> |  | ||||||
| 
 | 
 | ||||||
| struct MenuItem { | struct MenuItem { | ||||||
|     MenuItemType type; |     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
 | // TODO float note freq
 | ||||||
| typedef enum { | typedef enum { | ||||||
| @ -302,7 +304,7 @@ static void render_callback(Canvas* canvas, void* ctx) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void input_callback(InputEvent* input_event, 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; |     MusicDemoEvent event; | ||||||
|     event.type = EventTypeKey; |     event.type = EventTypeKey; | ||||||
| @ -376,15 +378,11 @@ void music_player(void* p) { | |||||||
|     widget_input_callback_set(widget, input_callback, event_queue); |     widget_input_callback_set(widget, input_callback, event_queue); | ||||||
| 
 | 
 | ||||||
|     // Open GUI and register widget
 |     // 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); |  | ||||||
|     } |  | ||||||
|     gui_add_widget(gui, widget, GuiLayerFullscreen); |     gui_add_widget(gui, widget, GuiLayerFullscreen); | ||||||
| 
 | 
 | ||||||
|     // open input record
 |     // open input record
 | ||||||
|     PubSub* input_events_record = furi_open("input_events"); |     PubSub* input_events_record = furi_record_open("input_events"); | ||||||
|     // prepare "do nothing" event
 |     // prepare "do nothing" event
 | ||||||
|     InputEvent input_event = {InputRight, true}; |     InputEvent input_event = {InputRight, true}; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -16,8 +16,7 @@ Nfc* nfc_alloc() { | |||||||
|     nfc->worker = nfc_worker_alloc(nfc->message_queue); |     nfc->worker = nfc_worker_alloc(nfc->message_queue); | ||||||
| 
 | 
 | ||||||
|     nfc->icon = assets_icons_get(A_NFC_14); |     nfc->icon = assets_icons_get(A_NFC_14); | ||||||
|     nfc->menu_vm = furi_open("menu"); |     nfc->menu_vm = furi_record_open("menu"); | ||||||
|     furi_check(nfc->menu_vm); |  | ||||||
| 
 | 
 | ||||||
|     nfc->menu = menu_item_alloc_menu("NFC", nfc->icon); |     nfc->menu = menu_item_alloc_menu("NFC", nfc->icon); | ||||||
|     menu_item_subitem_add( |     menu_item_subitem_add( | ||||||
| @ -102,18 +101,13 @@ void nfc_start(Nfc* nfc, NfcView view_id, NfcWorkerState worker_state) { | |||||||
| void nfc_task(void* p) { | void nfc_task(void* p) { | ||||||
|     Nfc* nfc = nfc_alloc(); |     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); |     view_dispatcher_attach_to_gui(nfc->view_dispatcher, gui, ViewDispatcherTypeFullscreen); | ||||||
| 
 | 
 | ||||||
|     with_value_mutex( |     with_value_mutex( | ||||||
|         nfc->menu_vm, (Menu * menu) { menu_item_add(menu, nfc->menu); }); |         nfc->menu_vm, (Menu * menu) { menu_item_add(menu, nfc->menu); }); | ||||||
| 
 | 
 | ||||||
|     if(!furi_create("nfc", nfc)) { |     furi_record_create("nfc", nfc); | ||||||
|         printf("[nfc_task] cannot create nfc record\n"); |  | ||||||
|         furiac_exit(NULL); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     furiac_ready(); |  | ||||||
| 
 | 
 | ||||||
|     NfcMessage message; |     NfcMessage message; | ||||||
|     while(1) { |     while(1) { | ||||||
|  | |||||||
| @ -5,7 +5,7 @@ | |||||||
| #include "nfc_views.h" | #include "nfc_views.h" | ||||||
| #include "nfc_worker.h" | #include "nfc_worker.h" | ||||||
| 
 | 
 | ||||||
| #include <flipper_v2.h> | #include <furi.h> | ||||||
| 
 | 
 | ||||||
| #include <gui/gui.h> | #include <gui/gui.h> | ||||||
| #include <gui/view.h> | #include <gui/view.h> | ||||||
|  | |||||||
| @ -3,7 +3,7 @@ | |||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
| #include <stdbool.h> | #include <stdbool.h> | ||||||
| #include <gui/canvas.h> | #include <gui/canvas.h> | ||||||
| #include <flipper_v2.h> | #include <furi.h> | ||||||
| 
 | 
 | ||||||
| #include "nfc_types.h" | #include "nfc_types.h" | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -3,8 +3,7 @@ | |||||||
| #include "nfc_types.h" | #include "nfc_types.h" | ||||||
| #include "nfc_worker.h" | #include "nfc_worker.h" | ||||||
| 
 | 
 | ||||||
| #include <flipper_v2.h> | #include <furi.h> | ||||||
| #include <cmsis_os2.h> |  | ||||||
| #include <stdbool.h> | #include <stdbool.h> | ||||||
| 
 | 
 | ||||||
| #include <rfal_analogConfig.h> | #include <rfal_analogConfig.h> | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
| #include "power.h" | #include "power.h" | ||||||
| #include "power_views.h" | #include "power_views.h" | ||||||
| 
 | 
 | ||||||
| #include <flipper_v2.h> | #include <furi.h> | ||||||
| 
 | 
 | ||||||
| #include <menu/menu.h> | #include <menu/menu.h> | ||||||
| #include <menu/menu_item.h> | #include <menu/menu_item.h> | ||||||
| @ -12,8 +12,8 @@ | |||||||
| #include <gui/view_dispatcher.h> | #include <gui/view_dispatcher.h> | ||||||
| 
 | 
 | ||||||
| #include <assets_icons.h> | #include <assets_icons.h> | ||||||
| #include <api-hal-power.h> |  | ||||||
| #include <cli/cli.h> | #include <cli/cli.h> | ||||||
|  | #include <stm32wbxx.h> | ||||||
| 
 | 
 | ||||||
| struct Power { | struct Power { | ||||||
|     ViewDispatcher* view_dispatcher; |     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) { | void power_menu_off_callback(void* context) { | ||||||
|     api_hal_power_off(); |     api_hal_power_off(); | ||||||
| } | } | ||||||
| @ -71,10 +75,9 @@ void power_menu_info_callback(void* context) { | |||||||
| Power* power_alloc() { | Power* power_alloc() { | ||||||
|     Power* power = furi_alloc(sizeof(Power)); |     Power* power = furi_alloc(sizeof(Power)); | ||||||
| 
 | 
 | ||||||
|     power->menu_vm = furi_open("menu"); |     power->menu_vm = furi_record_open("menu"); | ||||||
|     furi_check(power->menu_vm); |  | ||||||
| 
 | 
 | ||||||
|     power->cli = furi_open("cli"); |     power->cli = furi_record_open("cli"); | ||||||
| 
 | 
 | ||||||
|     power->menu = menu_item_alloc_menu("Power", NULL); |     power->menu = menu_item_alloc_menu("Power", NULL); | ||||||
|     menu_item_subitem_add( |     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); |         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->usb_widget, GuiLayerStatusBarLeft); | ||||||
|     gui_add_widget(gui, power->battery_widget, GuiLayerStatusBarRight); |     gui_add_widget(gui, power->battery_widget, GuiLayerStatusBarRight); | ||||||
|     view_dispatcher_attach_to_gui(power->view_dispatcher, gui, ViewDispatcherTypeFullscreen); |     view_dispatcher_attach_to_gui(power->view_dispatcher, gui, ViewDispatcherTypeFullscreen); | ||||||
| @ -171,14 +174,9 @@ void power_task(void* p) { | |||||||
|     with_value_mutex( |     with_value_mutex( | ||||||
|         power->menu_vm, (Menu * menu) { menu_item_add(menu, power->menu); }); |         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(); |     api_hal_power_init(); | ||||||
| 
 | 
 | ||||||
|     furiac_ready(); |     furi_record_create("power", power); | ||||||
| 
 | 
 | ||||||
|     while(1) { |     while(1) { | ||||||
|         with_view_model( |         with_view_model( | ||||||
|  | |||||||
| @ -2,8 +2,8 @@ | |||||||
| 
 | 
 | ||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
| #include <stdbool.h> | #include <stdbool.h> | ||||||
|  | #include <furi.h> | ||||||
| #include <gui/canvas.h> | #include <gui/canvas.h> | ||||||
| #include <flipper_v2.h> |  | ||||||
| #include <gui/view.h> | #include <gui/view.h> | ||||||
| 
 | 
 | ||||||
| typedef enum { PowerViewInfo } PowerView; | typedef enum { PowerViewInfo } PowerView; | ||||||
| @ -24,8 +24,4 @@ typedef struct { | |||||||
|     uint8_t charge; |     uint8_t charge; | ||||||
| } PowerInfoModel; | } PowerInfoModel; | ||||||
| 
 | 
 | ||||||
| static uint32_t power_info_back_callback(void* context) { |  | ||||||
|     return VIEW_NONE; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void power_info_draw_callback(Canvas* canvas, void* context); | void power_info_draw_callback(Canvas* canvas, void* context); | ||||||
|  | |||||||
| @ -104,23 +104,21 @@ void SdTest::run() { | |||||||
| 
 | 
 | ||||||
|     app_ready(); |     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) { |     if(fs_api == NULL) { | ||||||
|         set_error({"cannot get sdcard api"}); |         set_error({"cannot get sdcard api"}); | ||||||
|         exit(); |         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
 | ||||||
|         // 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); | ||||||
|         auto cli_read_cb = cbc::obtain_connector<0>(this, &SdTest::cli_read_benchmark); |     cli_add_command(cli, "sd_read_test", cli_read_cb, this); | ||||||
|         cli_add_command(cli, "sd_read_test", cli_read_cb, this); |  | ||||||
| 
 | 
 | ||||||
|         auto cli_write_cb = cbc::obtain_connector<1>(this, &SdTest::cli_write_benchmark); |     auto cli_write_cb = cbc::obtain_connector<1>(this, &SdTest::cli_write_benchmark); | ||||||
|         cli_add_command(cli, "sd_write_test", cli_write_cb, this); |     cli_add_command(cli, "sd_write_test", cli_write_cb, this); | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     detect_sd_card(); |     detect_sd_card(); | ||||||
|     get_sd_card_info(); |     get_sd_card_info(); | ||||||
| @ -893,6 +891,7 @@ template <class T> void SdTest::set_text(std::initializer_list<T> list) { | |||||||
| 
 | 
 | ||||||
|     printf("------------------------\n"); |     printf("------------------------\n"); | ||||||
|     release_state(); |     release_state(); | ||||||
|  |     update_gui(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // render app
 | // render app
 | ||||||
|  | |||||||
| @ -480,22 +480,19 @@ void sd_filesystem(void* p) { | |||||||
|     SdApp* sd_app = sd_app_alloc(); |     SdApp* sd_app = sd_app_alloc(); | ||||||
|     FS_Api* fs_api = fs_api_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->widget, GuiLayerFullscreen); | ||||||
|     gui_add_widget(gui, sd_app->icon.widget, GuiLayerStatusBarLeft); |     gui_add_widget(gui, sd_app->icon.widget, GuiLayerStatusBarLeft); | ||||||
| 
 | 
 | ||||||
|     Cli* cli = furi_open("cli"); |     cli_add_command(cli, "sd_status", cli_sd_status, sd_app); | ||||||
| 
 |     cli_add_command(cli, "sd_format", cli_sd_format, sd_app); | ||||||
|     if(cli != NULL) { |     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
 |     // add api record
 | ||||||
|     if(!furi_create("sdcard", fs_api)) { |     furi_record_create("sdcard", fs_api); | ||||||
|         furiac_exit(NULL); |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     // init menu
 |     // init menu
 | ||||||
|     // TODO menu icon
 |     // 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)); |         menu_item, menu_item_alloc_function("Eject", NULL, app_sd_eject_callback, sd_app)); | ||||||
| 
 | 
 | ||||||
|     // add item to menu
 |     // add item to menu
 | ||||||
|     ValueMutex* menu_vm = furi_open("menu"); |  | ||||||
|     furi_check(menu_vm); |     furi_check(menu_vm); | ||||||
|     with_value_mutex( |     with_value_mutex( | ||||||
|         menu_vm, (Menu * menu) { menu_item_add(menu, menu_item); }); |         menu_vm, (Menu * menu) { menu_item_add(menu, menu_item); }); | ||||||
| 
 | 
 | ||||||
|     furiac_ready(); |  | ||||||
| 
 |  | ||||||
|     printf("[sd_filesystem] start\n"); |     printf("[sd_filesystem] start\n"); | ||||||
| 
 | 
 | ||||||
|  |     // add api record
 | ||||||
|  |     furi_record_create("sdcard", fs_api); | ||||||
|  | 
 | ||||||
|     // sd card cycle
 |     // sd card cycle
 | ||||||
|     bool sd_was_present = true; |     bool sd_was_present = true; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,6 +1,8 @@ | |||||||
| #pragma once | #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_FS_MAX_FILES _FS_LOCK | ||||||
| #define SD_STATE_LINES_COUNT 6 | #define SD_STATE_LINES_COUNT 6 | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| #include "flipper_v2.h" | #include <furi.h> | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     EventTypeTick, |     EventTypeTick, | ||||||
| @ -54,7 +54,7 @@ void template_app(void* p) { | |||||||
|     widget_input_callback_set(widget, input_callback, event_queue); |     widget_input_callback_set(widget, input_callback, event_queue); | ||||||
| 
 | 
 | ||||||
|     // Open GUI and register widget |     // Open GUI and register widget | ||||||
|     Gui* gui = (Gui*)furi_open("gui"); |     Gui* gui = furi_record_open("gui"); | ||||||
|     if(gui == NULL) { |     if(gui == NULL) { | ||||||
|         printf("gui is not available\n"); |         printf("gui is not available\n"); | ||||||
|         furiac_exit(NULL); |         furiac_exit(NULL); | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| #include "flipper_v2.h" | #include <furi.h> | ||||||
| #include "minunit.h" | #include "minunit.h" | ||||||
| 
 | 
 | ||||||
| static void furi_concurent_app(void* p) { | static void furi_concurent_app(void* p) { | ||||||
| @ -10,7 +10,9 @@ static void furi_concurent_app(void* p) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void test_furi_event() { | void test_furi_event() { | ||||||
|     Event event; |     mu_assert(false, "please reimplement or delete test"); | ||||||
|  | 
 | ||||||
|  |     /*Event event;
 | ||||||
| 
 | 
 | ||||||
|     mu_check(init_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
 |     // The event should not be signalled once it's processed
 | ||||||
|     mu_check(!wait_event_with_timeout(&event, 100)); |     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 <stdio.h> | ||||||
| #include <string.h> | #include <string.h> | ||||||
| #include "flipper_v2.h" | #include <furi.h> | ||||||
| #include "log.h" |  | ||||||
| 
 |  | ||||||
| #include "minunit.h" | #include "minunit.h" | ||||||
| 
 | 
 | ||||||
| const uint32_t context_value = 0xdeadbeef; | const uint32_t context_value = 0xdeadbeef; | ||||||
|  | |||||||
| @ -1,16 +1,14 @@ | |||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| #include <string.h> | #include <string.h> | ||||||
| #include "flipper.h" | #include <furi.h> | ||||||
| #include "flipper_v2.h" |  | ||||||
| #include "log.h" |  | ||||||
| #include "minunit.h" | #include "minunit.h" | ||||||
| 
 | 
 | ||||||
| void test_furi_create_open() { | void test_furi_create_open() { | ||||||
|     // 1. Create record
 |     // 1. Create record
 | ||||||
|     uint8_t test_data = 0; |     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
 |     // 2. Open it
 | ||||||
|     void* record = furi_open("test/holding"); |     void* record = furi_record_open("test/holding"); | ||||||
|     mu_assert_pointers_eq(record, &test_data); |     mu_assert_pointers_eq(record, &test_data); | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| #include "flipper_v2.h" | #include <furi.h> | ||||||
| #include "minunit.h" | #include "minunit.h" | ||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,7 +1,6 @@ | |||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| #include <string.h> | #include <string.h> | ||||||
| #include "flipper_v2.h" | #include <furi.h> | ||||||
| #include "log.h" |  | ||||||
| 
 | 
 | ||||||
| #include "minunit.h" | #include "minunit.h" | ||||||
| 
 | 
 | ||||||
| @ -88,6 +87,8 @@ void furi_concurent_app(void* p) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void test_furi_concurrent_access() { | void test_furi_concurrent_access() { | ||||||
|  |     mu_assert(false, "please reimplement or delete test"); | ||||||
|  |     /*
 | ||||||
|     // 1. Create holding record
 |     // 1. Create holding record
 | ||||||
|     ConcurrentValue value = {.a = 0, .b = 0}; |     ConcurrentValue value = {.a = 0, .b = 0}; | ||||||
|     ValueMutex mutex; |     ValueMutex mutex; | ||||||
| @ -123,4 +124,5 @@ void test_furi_concurrent_access() { | |||||||
|     mu_assert_int_eq(value.a, value.b); |     mu_assert_int_eq(value.a, value.b); | ||||||
| 
 | 
 | ||||||
|     mu_check(delete_mutex(&mutex)); |     mu_check(delete_mutex(&mutex)); | ||||||
|  |     */ | ||||||
| } | } | ||||||
| @ -1,7 +1,6 @@ | |||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| #include <string.h> | #include <string.h> | ||||||
| #include "flipper.h" | #include <furi.h> | ||||||
| #include "log.h" |  | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
| Test: creating and killing task | Test: creating and killing task | ||||||
| @ -24,6 +23,8 @@ void create_kill_app(void* p) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool test_furi_ac_create_kill() { | bool test_furi_ac_create_kill() { | ||||||
|  |     mu_assert(false, "please reimplement or delete test"); | ||||||
|  |     /*
 | ||||||
|     uint8_t counter = 0; |     uint8_t counter = 0; | ||||||
| 
 | 
 | ||||||
|     uint8_t value_a = counter; |     uint8_t value_a = counter; | ||||||
| @ -56,6 +57,7 @@ bool test_furi_ac_create_kill() { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return true; |     return true; | ||||||
|  |     */ | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  | |||||||
| @ -1,6 +1,5 @@ | |||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| #include "flipper.h" | #include <furi.h> | ||||||
| #include "log.h" |  | ||||||
| #include "minunit_vars.h" | #include "minunit_vars.h" | ||||||
| #include "minunit.h" | #include "minunit.h" | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,7 +1,5 @@ | |||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| #include "flipper.h" | #include <furi.h> | ||||||
| #include "flipper_v2.h" |  | ||||||
| #include "log.h" |  | ||||||
| 
 | 
 | ||||||
| // #include "flipper-core.h" TODO: Rust build disabled
 | // #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 "api-gpio.h" | ||||||
|  | #include <cmsis_os2.h> | ||||||
|  | #include <furi/record.h> | ||||||
| 
 | 
 | ||||||
| osMutexId_t gpioInitMutex; | osMutexId_t gpioInitMutex; | ||||||
| 
 | 
 | ||||||
| @ -37,7 +39,7 @@ void gpio_disable(GpioDisableRecord* gpio_record) { | |||||||
| 
 | 
 | ||||||
| // get GPIO record
 | // get GPIO record
 | ||||||
| ValueMutex* gpio_open_mutex(const char* name) { | 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
 |     // TODO disable gpio on app exit
 | ||||||
|     //if(gpio_mutex != NULL) flapp_on_exit(gpio_disable, gpio_mutex);
 |     //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
 | // get GPIO record and acquire mutex
 | ||||||
| GpioPin* gpio_open(const char* name) { | GpioPin* gpio_open(const char* name) { | ||||||
|     ValueMutex* gpio_mutex = gpio_open_mutex(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; |     return gpio_pin; | ||||||
| } | } | ||||||
| @ -1,7 +1,11 @@ | |||||||
| #pragma once | #pragma once | ||||||
| #include "flipper.h" | 
 | ||||||
| #include "flipper_v2.h" |  | ||||||
| #include "api-hal-gpio.h" | #include "api-hal-gpio.h" | ||||||
|  | #include <furi/valuemutex.h> | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     ValueMutex* gpio_mutex; |     ValueMutex* gpio_mutex; | ||||||
| @ -39,3 +43,7 @@ ValueMutex* gpio_open_mutex(const char* name); | |||||||
| 
 | 
 | ||||||
| // get GPIO record and acquire mutex
 | // 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 "api-interrupt-mgr.h" | ||||||
| 
 | 
 | ||||||
|  | #include <m-list.h> | ||||||
|  | #include <cmsis_os2.h> | ||||||
|  | 
 | ||||||
| LIST_DEF(list_interrupt, InterruptCallbackItem, M_POD_OPLIST); | LIST_DEF(list_interrupt, InterruptCallbackItem, M_POD_OPLIST); | ||||||
| list_interrupt_t interrupts; | list_interrupt_t interrupts; | ||||||
| osMutexId_t interrupt_list_mutex; | osMutexId_t interrupt_list_mutex; | ||||||
|  | |||||||
| @ -1,5 +1,10 @@ | |||||||
| #pragma once | #pragma once | ||||||
| #include "flipper_v2.h" | 
 | ||||||
|  | #include <stdbool.h> | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
| typedef void (*InterruptCallback)(void*, void*); | typedef void (*InterruptCallback)(void*, void*); | ||||||
| 
 | 
 | ||||||
| @ -19,3 +24,7 @@ bool api_interrupt_init(); | |||||||
| void api_interrupt_add(InterruptCallback callback, InterruptType type, void* context); | void api_interrupt_add(InterruptCallback callback, InterruptType type, void* context); | ||||||
| void api_interrupt_remove(InterruptCallback callback); | 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. | struct used for handling SPI info. | ||||||
| @ -134,3 +138,7 @@ 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 | CORE_DIR		= $(PROJECT_ROOT)/core | ||||||
| 
 | 
 | ||||||
| CFLAGS			+= -I$(CORE_DIR) | CFLAGS			+= -I$(CORE_DIR) -D_GNU_SOURCE | ||||||
| ASM_SOURCES		+= $(wildcard $(CORE_DIR)/*.s) | ASM_SOURCES		+= $(wildcard $(CORE_DIR)/*.s) | ||||||
| C_SOURCES		+= $(wildcard $(CORE_DIR)/*.c) | 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) | C_SOURCES		+= $(wildcard $(CORE_DIR)/api-hal/*.c) | ||||||
| CPP_SOURCES		+= $(wildcard $(CORE_DIR)/*.cpp) | 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 "check.h" | ||||||
| #include "api-hal-task.h" | #include "api-hal-task.h" | ||||||
|  | #include <stdio.h> | ||||||
| 
 | 
 | ||||||
| void __furi_abort(void); | 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()) { |     if(task_is_isr_context()) { | ||||||
|         printf(" in [ISR] context"); |         printf(" in [ISR] context"); | ||||||
|     } else { |     } else { | ||||||
|         FuriApp* app = find_task(xTaskGetCurrentTaskHandle()); |         // FuriApp* app = find_task(xTaskGetCurrentTaskHandle());
 | ||||||
| 
 | 
 | ||||||
|         if(app == NULL) { |         // if(app == NULL) {
 | ||||||
|             printf(", in [main] context"); |         //     printf(", in [main] context");
 | ||||||
|         } else { |         // } else {
 | ||||||
|             printf(", in [%s] app context", app->name); |         //     printf(", in [%s] app context", app->name);
 | ||||||
|         } |         // }
 | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     __furi_abort(); |     __furi_abort(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void __furi_abort(void) { | void __furi_abort(void) { | ||||||
|     taskDISABLE_INTERRUPTS(); |     __disable_irq(); | ||||||
|  |     asm("bkpt 1"); | ||||||
|     while(1) { |     while(1) { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -1,6 +1,8 @@ | |||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #include "flipper.h" | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
| // Find how to how get function's pretty name
 | // Find how to how get function's pretty name
 | ||||||
| #ifndef __FURI_CHECK_FUNC | #ifndef __FURI_CHECK_FUNC | ||||||
| @ -39,3 +41,7 @@ | |||||||
| 
 | 
 | ||||||
| void __furi_check(void); | 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