Merge branch 'release-candidate' into release
| @ -109,16 +109,6 @@ void AccessorApp::notify_green_blink() { | ||||
| 
 | ||||
| void AccessorApp::notify_success() { | ||||
|     notification_message(notification, &sequence_success); | ||||
| 
 | ||||
|     hal_pwm_set(0.5, 1760 / 2, &htim2, TIM_CHANNEL_2); | ||||
|     delay(100); | ||||
|     hal_pwm_stop(&htim2, TIM_CHANNEL_2); | ||||
| 
 | ||||
|     delay(100); | ||||
| 
 | ||||
|     hal_pwm_set(0.5, 1760, &htim2, TIM_CHANNEL_2); | ||||
|     delay(100); | ||||
|     hal_pwm_stop(&htim2, TIM_CHANNEL_2); | ||||
| } | ||||
| 
 | ||||
| /*************************** TEXT STORE *****************************/ | ||||
|  | ||||
| @ -11,6 +11,8 @@ volatile int WIEGAND::_bitCount = 0; | ||||
| int WIEGAND::_wiegandType = 0; | ||||
| 
 | ||||
| constexpr uint32_t clocks_in_ms = 64 * 1000; | ||||
| const GpioPin* pinD0 = &gpio_ext_pa4; | ||||
| const GpioPin* pinD1 = &gpio_ext_pa7; | ||||
| 
 | ||||
| WIEGAND::WIEGAND() { | ||||
| } | ||||
| @ -53,9 +55,6 @@ void WIEGAND::begin() { | ||||
|     _wiegandType = 0; | ||||
|     _bitCount = 0; | ||||
| 
 | ||||
|     const GpioPin* pinD0 = &gpio_ext_pa6; | ||||
|     const GpioPin* pinD1 = &gpio_ext_pa7; | ||||
| 
 | ||||
|     hal_gpio_init_simple(pinD0, GpioModeInterruptFall); // Set D0 pin as input
 | ||||
|     hal_gpio_init_simple(pinD1, GpioModeInterruptFall); // Set D1 pin as input
 | ||||
| 
 | ||||
| @ -64,11 +63,11 @@ void WIEGAND::begin() { | ||||
| } | ||||
| 
 | ||||
| void WIEGAND::end() { | ||||
|     hal_gpio_remove_int_callback(&gpio_ext_pa6); | ||||
|     hal_gpio_remove_int_callback(&gpio_ext_pa7); | ||||
|     hal_gpio_remove_int_callback(pinD0); | ||||
|     hal_gpio_remove_int_callback(pinD1); | ||||
| 
 | ||||
|     hal_gpio_init_simple(&gpio_ext_pa6, GpioModeAnalog); | ||||
|     hal_gpio_init_simple(&gpio_ext_pa7, GpioModeAnalog); | ||||
|     hal_gpio_init_simple(pinD0, GpioModeAnalog); | ||||
|     hal_gpio_init_simple(pinD1, GpioModeAnalog); | ||||
| } | ||||
| 
 | ||||
| void WIEGAND::ReadD0() { | ||||
|  | ||||
| @ -32,6 +32,7 @@ extern int32_t scened_app(void* p); | ||||
| extern int32_t storage_test_app(void* p); | ||||
| extern int32_t subghz_app(void* p); | ||||
| extern int32_t vibro_test_app(void* p); | ||||
| extern int32_t bt_debug_app(void* p); | ||||
| 
 | ||||
| // Plugins
 | ||||
| extern int32_t music_player_app(void* p); | ||||
| @ -48,6 +49,7 @@ extern void subghz_cli_init(); | ||||
| // Settings
 | ||||
| extern int32_t notification_settings_app(void* p); | ||||
| extern int32_t storage_settings_app(void* p); | ||||
| extern int32_t bt_settings_app(void* p); | ||||
| 
 | ||||
| const FlipperApplication FLIPPER_SERVICES[] = { | ||||
| /* Services */ | ||||
| @ -236,6 +238,10 @@ const FlipperApplication FLIPPER_DEBUG_APPS[] = { | ||||
| #ifdef APP_LF_RFID | ||||
|     {.app = lfrfid_debug_app, .name = "LF-RFID Debug", .stack_size = 1024, .icon = &A_125khz_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef SRV_BT | ||||
|     {.app = bt_debug_app, .name = "Bluetooth Debug", .stack_size = 1024, .icon = NULL}, | ||||
| #endif | ||||
| }; | ||||
| 
 | ||||
| const size_t FLIPPER_DEBUG_APPS_COUNT = sizeof(FLIPPER_DEBUG_APPS) / sizeof(FlipperApplication); | ||||
| @ -254,6 +260,10 @@ const FlipperApplication FLIPPER_SETTINGS_APPS[] = { | ||||
| #ifdef SRV_STORAGE | ||||
|     {.app = storage_settings_app, .name = "Storage", .stack_size = 2048, .icon = NULL}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef SRV_BT | ||||
|     {.app = bt_settings_app, .name = "Bluetooth", .stack_size = 1024, .icon = NULL}, | ||||
| #endif | ||||
| }; | ||||
| 
 | ||||
| const size_t FLIPPER_SETTINGS_APPS_COUNT = | ||||
|  | ||||
| @ -1,266 +0,0 @@ | ||||
| #include "bt_i.h" | ||||
| 
 | ||||
| uint32_t bt_view_exit(void* context) { | ||||
|     (void)context; | ||||
|     return VIEW_NONE; | ||||
| } | ||||
| 
 | ||||
| void bt_update_statusbar(void* arg) { | ||||
|     furi_assert(arg); | ||||
|     Bt* bt = arg; | ||||
|     BtMessage m = {.type = BtMessageTypeUpdateStatusbar}; | ||||
|     furi_check(osMessageQueuePut(bt->message_queue, &m, 0, osWaitForever) == osOK); | ||||
| } | ||||
| 
 | ||||
| void bt_update_param(void* arg) { | ||||
|     furi_assert(arg); | ||||
|     Bt* bt = arg; | ||||
|     BtMessage m; | ||||
|     if(bt->state.type == BtStateHoppingTx || bt->state.type == BtStateCarrierRxRunning) { | ||||
|         m.type = BtMessageTypeStartTestCarrier; | ||||
|     } else if(bt->state.type == BtStatePacketRunning) { | ||||
|         m.type = BtMessageTypeStartTestPacketRx; | ||||
|     } | ||||
|     furi_check(osMessageQueuePut(bt->message_queue, &m, 0, osWaitForever) == osOK); | ||||
| } | ||||
| 
 | ||||
| Bt* bt_alloc() { | ||||
|     Bt* bt = furi_alloc(sizeof(Bt)); | ||||
| 
 | ||||
|     bt->message_queue = osMessageQueueNew(8, sizeof(BtMessage), NULL); | ||||
|     bt->update_status_timer = osTimerNew(bt_update_statusbar, osTimerPeriodic, bt, NULL); | ||||
|     osTimerStart(bt->update_status_timer, 4000); | ||||
|     bt->update_param_timer = osTimerNew(bt_update_param, osTimerPeriodic, bt, NULL); | ||||
|     bt->gui = furi_record_open("gui"); | ||||
|     bt->menu = furi_record_open("menu"); | ||||
| 
 | ||||
|     bt->state.type = BtStateReady; | ||||
|     bt->state.param.channel = BtChannel2402; | ||||
|     bt->state.param.power = BtPower0dB; | ||||
|     bt->state.param.datarate = BtDataRate1M; | ||||
| 
 | ||||
|     bt->statusbar_view_port = view_port_alloc(); | ||||
|     view_port_set_width(bt->statusbar_view_port, 5); | ||||
|     view_port_draw_callback_set(bt->statusbar_view_port, bt_draw_statusbar_callback, bt); | ||||
|     view_port_enabled_set(bt->statusbar_view_port, false); | ||||
|     gui_add_view_port(bt->gui, bt->statusbar_view_port, GuiLayerStatusBarLeft); | ||||
| 
 | ||||
|     bt->menu_icon = icon_animation_alloc(&A_Bluetooth_14); | ||||
|     bt->menu_item = menu_item_alloc_menu("Bluetooth", bt->menu_icon); | ||||
|     menu_item_subitem_add( | ||||
|         bt->menu_item, menu_item_alloc_function("Carrier test", NULL, bt_menu_test_carrier, bt)); | ||||
|     menu_item_subitem_add( | ||||
|         bt->menu_item, | ||||
|         menu_item_alloc_function("Test packet TX", NULL, bt_menu_test_packet_tx, bt)); | ||||
|     menu_item_subitem_add( | ||||
|         bt->menu_item, menu_item_alloc_function("Start app", NULL, bt_menu_start_app, bt)); | ||||
|     menu_item_subitem_add( | ||||
|         bt->menu_item, | ||||
|         menu_item_alloc_function("Test packet RX", NULL, bt_menu_test_packet_rx, bt)); | ||||
| 
 | ||||
|     // Carrier test
 | ||||
|     bt->view_test_carrier = view_alloc(); | ||||
|     view_set_context(bt->view_test_carrier, bt); | ||||
|     view_set_draw_callback(bt->view_test_carrier, bt_view_test_carrier_draw); | ||||
|     view_allocate_model( | ||||
|         bt->view_test_carrier, ViewModelTypeLocking, sizeof(BtViewTestCarrierModel)); | ||||
|     view_set_input_callback(bt->view_test_carrier, bt_view_test_carrier_input); | ||||
| 
 | ||||
|     // Packet TX test
 | ||||
|     bt->view_test_packet_tx = view_alloc(); | ||||
|     view_set_context(bt->view_test_packet_tx, bt); | ||||
|     view_set_draw_callback(bt->view_test_packet_tx, bt_view_test_packet_tx_draw); | ||||
|     view_allocate_model( | ||||
|         bt->view_test_packet_tx, ViewModelTypeLocking, sizeof(BtViewTestPacketTxModel)); | ||||
|     view_set_input_callback(bt->view_test_packet_tx, bt_view_test_packet_tx_input); | ||||
| 
 | ||||
|     // Packet RX test
 | ||||
|     bt->view_test_packet_rx = view_alloc(); | ||||
|     view_set_context(bt->view_test_packet_rx, bt); | ||||
|     view_set_draw_callback(bt->view_test_packet_rx, bt_view_test_packet_rx_draw); | ||||
|     view_allocate_model( | ||||
|         bt->view_test_packet_rx, ViewModelTypeLocking, sizeof(BtViewTestPacketRxModel)); | ||||
|     view_set_input_callback(bt->view_test_packet_rx, bt_view_test_packet_rx_input); | ||||
| 
 | ||||
|     // Start app
 | ||||
|     bt->view_start_app = view_alloc(); | ||||
|     view_set_context(bt->view_start_app, bt); | ||||
|     view_set_draw_callback(bt->view_start_app, bt_view_app_draw); | ||||
|     view_set_previous_callback(bt->view_start_app, bt_view_exit); | ||||
| 
 | ||||
|     // View dispatcher
 | ||||
|     bt->view_dispatcher = view_dispatcher_alloc(); | ||||
|     view_dispatcher_add_view(bt->view_dispatcher, BtViewTestCarrier, bt->view_test_carrier); | ||||
|     view_dispatcher_add_view(bt->view_dispatcher, BtViewTestPacketTx, bt->view_test_packet_tx); | ||||
|     view_dispatcher_add_view(bt->view_dispatcher, BtViewTestPacketRx, bt->view_test_packet_rx); | ||||
|     view_dispatcher_add_view(bt->view_dispatcher, BtViewStartApp, bt->view_start_app); | ||||
| 
 | ||||
|     Gui* gui = furi_record_open("gui"); | ||||
|     view_dispatcher_attach_to_gui(bt->view_dispatcher, gui, ViewDispatcherTypeFullscreen); | ||||
| 
 | ||||
|     with_value_mutex( | ||||
|         bt->menu, (Menu * menu) { menu_item_add(menu, bt->menu_item); }); | ||||
|     return bt; | ||||
| } | ||||
| 
 | ||||
| void bt_draw_statusbar_callback(Canvas* canvas, void* context) { | ||||
|     canvas_draw_icon(canvas, 0, 0, &I_Bluetooth_5x8); | ||||
| } | ||||
| 
 | ||||
| void bt_menu_test_carrier(void* context) { | ||||
|     furi_assert(context); | ||||
|     Bt* bt = context; | ||||
|     bt->state.type = BtStateCarrierTx; | ||||
|     BtMessage message = { | ||||
|         .type = BtMessageTypeStartTestCarrier, | ||||
|         .param.channel = bt->state.param.channel, | ||||
|         .param.power = bt->state.param.power}; | ||||
|     furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK); | ||||
| } | ||||
| 
 | ||||
| void bt_menu_test_packet_tx(void* context) { | ||||
|     furi_assert(context); | ||||
|     Bt* bt = context; | ||||
|     bt->state.type = BtStatePacketSetup; | ||||
|     BtMessage message = { | ||||
|         .type = BtMessageTypeSetupTestPacketTx, | ||||
|         .param.channel = bt->state.param.channel, | ||||
|         .param.datarate = bt->state.param.datarate}; | ||||
|     furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK); | ||||
| } | ||||
| 
 | ||||
| void bt_menu_test_packet_rx(void* context) { | ||||
|     furi_assert(context); | ||||
|     Bt* bt = context; | ||||
|     bt->state.type = BtStatePacketSetup; | ||||
|     BtMessage message = { | ||||
|         .type = BtMessageTypeSetupTestPacketRx, | ||||
|         .param.channel = bt->state.param.channel, | ||||
|         .param.datarate = bt->state.param.datarate}; | ||||
|     furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK); | ||||
| } | ||||
| 
 | ||||
| void bt_menu_start_app(void* context) { | ||||
|     furi_assert(context); | ||||
|     Bt* bt = context; | ||||
|     bt->state.type = BtStateStartedApp; | ||||
|     BtMessage message = {.type = BtMessageTypeStartApp}; | ||||
|     furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK); | ||||
| } | ||||
| 
 | ||||
| int32_t bt_srv() { | ||||
|     Bt* bt = bt_alloc(); | ||||
| 
 | ||||
|     furi_record_create("bt", bt); | ||||
| 
 | ||||
|     furi_hal_bt_init(); | ||||
|     BtMessage message; | ||||
|     while(1) { | ||||
|         furi_check(osMessageQueueGet(bt->message_queue, &message, NULL, osWaitForever) == osOK); | ||||
|         if(message.type == BtMessageTypeStartTestCarrier) { | ||||
|             // Start carrier test
 | ||||
|             furi_hal_bt_stop_tone_tx(); | ||||
|             if(bt->state.type == BtStateCarrierTx) { | ||||
|                 furi_hal_bt_start_tone_tx(message.param.channel, message.param.power); | ||||
|             } else if(bt->state.type == BtStateHoppingTx) { | ||||
|                 bt->state.param.channel = | ||||
|                     bt_switch_channel(InputKeyRight, bt->state.param.channel); | ||||
|                 furi_hal_bt_start_tone_tx(bt->state.param.channel, bt->state.param.power); | ||||
|             } else if(bt->state.type == BtStateCarrierRxStart) { | ||||
|                 furi_hal_bt_start_packet_rx(bt->state.param.channel, bt->state.param.datarate); | ||||
|                 bt->state.type = BtStateCarrierRxRunning; | ||||
|             } else if(bt->state.type == BtStateCarrierRxRunning) { | ||||
|                 bt->state.param.rssi = furi_hal_bt_get_rssi(); | ||||
|             } | ||||
|             with_view_model( | ||||
|                 bt->view_test_carrier, (BtViewTestCarrierModel * model) { | ||||
|                     model->type = bt->state.type; | ||||
|                     model->channel = bt->state.param.channel; | ||||
|                     model->power = bt->state.param.power; | ||||
|                     model->rssi = bt->state.param.rssi; | ||||
|                     return true; | ||||
|                 }); | ||||
|             view_dispatcher_switch_to_view(bt->view_dispatcher, BtViewTestCarrier); | ||||
|         } else if(message.type == BtMessageTypeStopTestCarrier) { | ||||
|             if(bt->state.type == BtStateCarrierRxRunning) { | ||||
|                 furi_hal_bt_stop_packet_test(); | ||||
|             } else { | ||||
|                 furi_hal_bt_stop_tone_tx(); | ||||
|             } | ||||
|             bt->state.type = BtStateReady; | ||||
|         } else if(message.type == BtMessageTypeSetupTestPacketTx) { | ||||
|             // Update packet test setup
 | ||||
|             furi_hal_bt_stop_packet_test(); | ||||
|             with_view_model( | ||||
|                 bt->view_test_packet_tx, (BtViewTestPacketTxModel * model) { | ||||
|                     model->type = bt->state.type; | ||||
|                     model->channel = bt->state.param.channel; | ||||
|                     model->datarate = bt->state.param.datarate; | ||||
|                     return true; | ||||
|                 }); | ||||
|             view_dispatcher_switch_to_view(bt->view_dispatcher, BtViewTestPacketTx); | ||||
|         } else if(message.type == BtMessageTypeStartTestPacketTx) { | ||||
|             // Start sending packets
 | ||||
|             if(bt->state.type == BtStatePacketStart) { | ||||
|                 furi_hal_bt_start_packet_tx(message.param.channel, 1, message.param.datarate); | ||||
|             } else if(bt->state.type == BtStatePacketSetup) { | ||||
|                 furi_hal_bt_stop_packet_test(); | ||||
|                 bt->state.param.packets_sent = furi_hal_bt_get_transmitted_packets(); | ||||
|             } | ||||
|             with_view_model( | ||||
|                 bt->view_test_packet_tx, (BtViewTestPacketTxModel * model) { | ||||
|                     model->type = bt->state.type; | ||||
|                     model->channel = bt->state.param.channel; | ||||
|                     model->datarate = bt->state.param.datarate; | ||||
|                     model->packets_sent = bt->state.param.packets_sent; | ||||
|                     return true; | ||||
|                 }); | ||||
|             view_dispatcher_switch_to_view(bt->view_dispatcher, BtViewTestPacketTx); | ||||
|         } else if(message.type == BtMessageTypeSetupTestPacketRx) { | ||||
|             // Update packet test setup
 | ||||
|             furi_hal_bt_stop_packet_test(); | ||||
|             with_view_model( | ||||
|                 bt->view_test_packet_rx, (BtViewTestPacketRxModel * model) { | ||||
|                     model->type = bt->state.type; | ||||
|                     model->channel = bt->state.param.channel; | ||||
|                     model->datarate = bt->state.param.datarate; | ||||
|                     return true; | ||||
|                 }); | ||||
|             view_dispatcher_switch_to_view(bt->view_dispatcher, BtViewTestPacketRx); | ||||
|         } else if(message.type == BtMessageTypeStartTestPacketRx) { | ||||
|             // Start test rx
 | ||||
|             if(bt->state.type == BtStatePacketStart) { | ||||
|                 furi_hal_bt_start_packet_rx(message.param.channel, message.param.datarate); | ||||
|                 bt->state.type = BtStatePacketRunning; | ||||
|             } else if(bt->state.type == BtStatePacketRunning) { | ||||
|                 bt->state.param.rssi = furi_hal_bt_get_rssi(); | ||||
|             } else if(bt->state.type == BtStatePacketSetup) { | ||||
|                 bt->state.param.packets_received = furi_hal_bt_stop_packet_test(); | ||||
|             } | ||||
|             with_view_model( | ||||
|                 bt->view_test_packet_rx, (BtViewTestPacketRxModel * model) { | ||||
|                     model->type = bt->state.type; | ||||
|                     model->channel = bt->state.param.channel; | ||||
|                     model->datarate = bt->state.param.datarate; | ||||
|                     model->packets_received = bt->state.param.packets_received; | ||||
|                     model->rssi = bt->state.param.rssi; | ||||
|                     return true; | ||||
|                 }); | ||||
|             view_dispatcher_switch_to_view(bt->view_dispatcher, BtViewTestPacketRx); | ||||
|         } else if(message.type == BtMessageTypeStopTestPacket) { | ||||
|             // Stop test packet tx
 | ||||
|             furi_hal_bt_stop_packet_test(); | ||||
|             bt->state.type = BtStateReady; | ||||
|         } else if(message.type == BtMessageTypeStartApp) { | ||||
|             // Start app
 | ||||
|             view_dispatcher_switch_to_view(bt->view_dispatcher, BtViewStartApp); | ||||
|             if(furi_hal_bt_start_app()) { | ||||
|                 bt->state.type = BtStateStartedApp; | ||||
|             } | ||||
|         } else if(message.type == BtMessageTypeUpdateStatusbar) { | ||||
|             // Update statusbar
 | ||||
|             view_port_enabled_set(bt->statusbar_view_port, furi_hal_bt_is_alive()); | ||||
|         } | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
							
								
								
									
										94
									
								
								applications/bt/bt_debug_app/bt_debug_app.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						| @ -0,0 +1,94 @@ | ||||
| #include "bt_debug_app.h" | ||||
| 
 | ||||
| enum BtDebugSubmenuIndex { | ||||
|     BtDebugSubmenuIndexCarrierTest, | ||||
|     BtDebugSubmenuIndexPacketTest, | ||||
| }; | ||||
| 
 | ||||
| void bt_debug_submenu_callback(void* context, uint32_t index) { | ||||
|     furi_assert(context); | ||||
|     BtDebugApp* app = context; | ||||
|     if(index == BtDebugSubmenuIndexCarrierTest) { | ||||
|         view_dispatcher_switch_to_view(app->view_dispatcher, BtDebugAppViewCarrierTest); | ||||
|     } else if(index == BtDebugSubmenuIndexPacketTest) { | ||||
|         view_dispatcher_switch_to_view(app->view_dispatcher, BtDebugAppViewPacketTest); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| uint32_t bt_debug_exit(void* context) { | ||||
|     return VIEW_NONE; | ||||
| } | ||||
| 
 | ||||
| uint32_t bt_debug_start_view(void* context) { | ||||
|     return BtDebugAppViewSubmenu; | ||||
| } | ||||
| 
 | ||||
| BtDebugApp* bt_debug_app_alloc() { | ||||
|     BtDebugApp* app = furi_alloc(sizeof(BtDebugApp)); | ||||
|     // Gui
 | ||||
|     app->gui = furi_record_open("gui"); | ||||
| 
 | ||||
|     // View dispatcher
 | ||||
|     app->view_dispatcher = view_dispatcher_alloc(); | ||||
|     view_dispatcher_enable_queue(app->view_dispatcher); | ||||
|     view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); | ||||
| 
 | ||||
|     // Views
 | ||||
|     app->submenu = submenu_alloc(); | ||||
|     submenu_add_item( | ||||
|         app->submenu, | ||||
|         "Carrier test", | ||||
|         BtDebugSubmenuIndexCarrierTest, | ||||
|         bt_debug_submenu_callback, | ||||
|         app); | ||||
|     submenu_add_item( | ||||
|         app->submenu, "Packet test", BtDebugSubmenuIndexPacketTest, bt_debug_submenu_callback, app); | ||||
|     view_set_previous_callback(submenu_get_view(app->submenu), bt_debug_exit); | ||||
|     view_dispatcher_add_view( | ||||
|         app->view_dispatcher, BtDebugAppViewSubmenu, submenu_get_view(app->submenu)); | ||||
|     app->bt_carrier_test = bt_carrier_test_alloc(); | ||||
|     view_set_previous_callback( | ||||
|         bt_carrier_test_get_view(app->bt_carrier_test), bt_debug_start_view); | ||||
|     view_dispatcher_add_view( | ||||
|         app->view_dispatcher, | ||||
|         BtDebugAppViewCarrierTest, | ||||
|         bt_carrier_test_get_view(app->bt_carrier_test)); | ||||
|     app->bt_packet_test = bt_packet_test_alloc(); | ||||
|     view_set_previous_callback(bt_packet_test_get_view(app->bt_packet_test), bt_debug_start_view); | ||||
|     view_dispatcher_add_view( | ||||
|         app->view_dispatcher, | ||||
|         BtDebugAppViewPacketTest, | ||||
|         bt_packet_test_get_view(app->bt_packet_test)); | ||||
| 
 | ||||
|     // Switch to menu
 | ||||
|     view_dispatcher_switch_to_view(app->view_dispatcher, BtDebugAppViewSubmenu); | ||||
| 
 | ||||
|     return app; | ||||
| } | ||||
| 
 | ||||
| void bt_debug_app_free(BtDebugApp* app) { | ||||
|     furi_assert(app); | ||||
| 
 | ||||
|     // Free views
 | ||||
|     view_dispatcher_remove_view(app->view_dispatcher, BtDebugAppViewSubmenu); | ||||
|     submenu_free(app->submenu); | ||||
|     view_dispatcher_remove_view(app->view_dispatcher, BtDebugAppViewCarrierTest); | ||||
|     bt_carrier_test_free(app->bt_carrier_test); | ||||
|     view_dispatcher_remove_view(app->view_dispatcher, BtDebugAppViewPacketTest); | ||||
|     bt_packet_test_free(app->bt_packet_test); | ||||
|     view_dispatcher_free(app->view_dispatcher); | ||||
| 
 | ||||
|     // Close gui record
 | ||||
|     furi_record_close("gui"); | ||||
|     app->gui = NULL; | ||||
| 
 | ||||
|     // Free rest
 | ||||
|     free(app); | ||||
| } | ||||
| 
 | ||||
| int32_t bt_debug_app(void* p) { | ||||
|     BtDebugApp* app = bt_debug_app_alloc(); | ||||
|     view_dispatcher_run(app->view_dispatcher); | ||||
|     bt_debug_app_free(app); | ||||
|     return 0; | ||||
| } | ||||
							
								
								
									
										26
									
								
								applications/bt/bt_debug_app/bt_debug_app.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,26 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <furi.h> | ||||
| #include <gui/gui.h> | ||||
| #include <gui/view.h> | ||||
| #include <gui/view_dispatcher.h> | ||||
| 
 | ||||
| #include <gui/modules/submenu.h> | ||||
| #include "views/bt_carrier_test.h" | ||||
| #include "views/bt_packet_test.h" | ||||
| #include "../bt_settings.h" | ||||
| 
 | ||||
| typedef struct { | ||||
|     BtSettings settings; | ||||
|     Gui* gui; | ||||
|     ViewDispatcher* view_dispatcher; | ||||
|     Submenu* submenu; | ||||
|     BtCarrierTest* bt_carrier_test; | ||||
|     BtPacketTest* bt_packet_test; | ||||
| } BtDebugApp; | ||||
| 
 | ||||
| typedef enum { | ||||
|     BtDebugAppViewSubmenu, | ||||
|     BtDebugAppViewCarrierTest, | ||||
|     BtDebugAppViewPacketTest, | ||||
| } BtDebugAppView; | ||||
							
								
								
									
										188
									
								
								applications/bt/bt_debug_app/views/bt_carrier_test.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						| @ -0,0 +1,188 @@ | ||||
| #include "bt_carrier_test.h" | ||||
| #include "bt_test.h" | ||||
| #include "bt_test_types.h" | ||||
| #include "furi-hal-bt.h" | ||||
| 
 | ||||
| struct BtCarrierTest { | ||||
|     BtTest* bt_test; | ||||
|     BtTestParam* bt_param_channel; | ||||
|     BtTestMode mode; | ||||
|     BtTestChannel channel; | ||||
|     BtTestPower power; | ||||
|     osTimerId_t timer; | ||||
| }; | ||||
| 
 | ||||
| static BtTestParamValue bt_param_mode[] = { | ||||
|     {.value = BtTestModeRx, .str = "Rx"}, | ||||
|     {.value = BtTestModeTx, .str = "Tx"}, | ||||
|     {.value = BtTestModeTxHopping, .str = "Hopping Tx"}, | ||||
| }; | ||||
| 
 | ||||
| static BtTestParamValue bt_param_channel[] = { | ||||
|     {.value = BtTestChannel2402, .str = "2402 MHz"}, | ||||
|     {.value = BtTestChannel2440, .str = "2440 MHz"}, | ||||
|     {.value = BtTestChannel2480, .str = "2480 MHz"}, | ||||
| }; | ||||
| 
 | ||||
| static BtTestParamValue bt_param_power[] = { | ||||
|     {.value = BtPower0dB, .str = "0 dB"}, | ||||
|     {.value = BtPower2dB, .str = "2 dB"}, | ||||
|     {.value = BtPower4dB, .str = "4 dB"}, | ||||
|     {.value = BtPower6dB, .str = "6 dB"}, | ||||
| }; | ||||
| 
 | ||||
| static void bt_carrier_test_start(BtCarrierTest* bt_carrier_test) { | ||||
|     furi_assert(bt_carrier_test); | ||||
|     if(bt_carrier_test->mode == BtTestModeRx) { | ||||
|         furi_hal_bt_start_packet_rx(bt_carrier_test->channel, 1); | ||||
|         osTimerStart(bt_carrier_test->timer, 1024 / 4); | ||||
|     } else if(bt_carrier_test->mode == BtTestModeTxHopping) { | ||||
|         furi_hal_bt_start_tone_tx(bt_carrier_test->channel, bt_carrier_test->power); | ||||
|         osTimerStart(bt_carrier_test->timer, 2048); | ||||
|     } else if(bt_carrier_test->mode == BtTestModeTx) { | ||||
|         furi_hal_bt_start_tone_tx(bt_carrier_test->channel, bt_carrier_test->power); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static void bt_carrier_test_switch_channel(BtCarrierTest* bt_carrier_test) { | ||||
|     furi_assert(bt_carrier_test); | ||||
|     furi_hal_bt_stop_tone_tx(); | ||||
|     uint8_t channel_i = 0; | ||||
|     if(bt_carrier_test->channel == BtTestChannel2402) { | ||||
|         bt_carrier_test->channel = BtTestChannel2440; | ||||
|         channel_i = 1; | ||||
|     } else if(bt_carrier_test->channel == BtTestChannel2440) { | ||||
|         bt_carrier_test->channel = BtTestChannel2480; | ||||
|         channel_i = 2; | ||||
|     } else if(bt_carrier_test->channel == BtTestChannel2480) { | ||||
|         bt_carrier_test->channel = BtTestChannel2402; | ||||
|         channel_i = 0; | ||||
|     } | ||||
|     furi_hal_bt_start_tone_tx(bt_carrier_test->channel, bt_carrier_test->power); | ||||
|     bt_test_set_current_value_index(bt_carrier_test->bt_param_channel, channel_i); | ||||
|     bt_test_set_current_value_text( | ||||
|         bt_carrier_test->bt_param_channel, bt_param_channel[channel_i].str); | ||||
| } | ||||
| 
 | ||||
| static void bt_carrier_test_stop(BtCarrierTest* bt_carrier_test) { | ||||
|     furi_assert(bt_carrier_test); | ||||
|     if(bt_carrier_test->mode == BtTestModeTxHopping) { | ||||
|         furi_hal_bt_stop_tone_tx(); | ||||
|         osTimerStop(bt_carrier_test->timer); | ||||
|     } else if(bt_carrier_test->mode == BtTestModeTx) { | ||||
|         furi_hal_bt_stop_tone_tx(); | ||||
|     } else if(bt_carrier_test->mode == BtTestModeRx) { | ||||
|         furi_hal_bt_stop_packet_test(); | ||||
|         osTimerStop(bt_carrier_test->timer); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static uint32_t bt_carrier_test_param_changed(BtTestParam* param, BtTestParamValue* param_val) { | ||||
|     furi_assert(param); | ||||
|     uint8_t index = bt_test_get_current_value_index(param); | ||||
|     bt_test_set_current_value_text(param, param_val[index].str); | ||||
|     return param_val[index].value; | ||||
| } | ||||
| 
 | ||||
| static void bt_carrier_test_mode_changed(BtTestParam* param) { | ||||
|     BtCarrierTest* bt_carrier_test = bt_test_get_context(param); | ||||
|     bt_carrier_test_stop(bt_carrier_test); | ||||
|     bt_carrier_test->mode = bt_carrier_test_param_changed(param, bt_param_mode); | ||||
| } | ||||
| 
 | ||||
| static void bt_carrier_test_channel_changed(BtTestParam* param) { | ||||
|     BtCarrierTest* bt_carrier_test = bt_test_get_context(param); | ||||
|     bt_carrier_test_stop(bt_carrier_test); | ||||
|     bt_carrier_test->channel = bt_carrier_test_param_changed(param, bt_param_channel); | ||||
| } | ||||
| 
 | ||||
| static void bt_carrier_test_param_channel(BtTestParam* param) { | ||||
|     BtCarrierTest* bt_carrier_test = bt_test_get_context(param); | ||||
|     bt_carrier_test_stop(bt_carrier_test); | ||||
|     bt_carrier_test->power = bt_carrier_test_param_changed(param, bt_param_power); | ||||
| } | ||||
| 
 | ||||
| static void bt_carrier_test_change_state_callback(BtTestState state, void* context) { | ||||
|     furi_assert(context); | ||||
|     BtCarrierTest* bt_carrier_test = context; | ||||
|     furi_hal_bt_stop_tone_tx(); | ||||
|     if(state == BtTestStateStarted) { | ||||
|         bt_carrier_test_start(bt_carrier_test); | ||||
|     } else if(state == BtTestStateStopped) { | ||||
|         bt_carrier_test_stop(bt_carrier_test); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static void bt_carrier_test_exit_callback(void* context) { | ||||
|     furi_assert(context); | ||||
|     BtCarrierTest* bt_carrier_test = context; | ||||
|     bt_carrier_test_stop(bt_carrier_test); | ||||
| } | ||||
| 
 | ||||
| static void bt_test_carrier_timer_callback(void* context) { | ||||
|     furi_assert(context); | ||||
|     BtCarrierTest* bt_carrier_test = context; | ||||
|     if(bt_carrier_test->mode == BtTestModeRx) { | ||||
|         bt_test_set_rssi(bt_carrier_test->bt_test, furi_hal_bt_get_rssi()); | ||||
|     } else if(bt_carrier_test->mode == BtTestModeTxHopping) { | ||||
|         bt_carrier_test_switch_channel(bt_carrier_test); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| BtCarrierTest* bt_carrier_test_alloc() { | ||||
|     BtCarrierTest* bt_carrier_test = furi_alloc(sizeof(BtCarrierTest)); | ||||
|     bt_carrier_test->bt_test = bt_test_alloc(); | ||||
|     bt_test_set_context(bt_carrier_test->bt_test, bt_carrier_test); | ||||
|     bt_test_set_change_state_callback( | ||||
|         bt_carrier_test->bt_test, bt_carrier_test_change_state_callback); | ||||
|     bt_test_set_back_callback(bt_carrier_test->bt_test, bt_carrier_test_exit_callback); | ||||
| 
 | ||||
|     BtTestParam* param; | ||||
|     param = bt_test_param_add( | ||||
|         bt_carrier_test->bt_test, | ||||
|         "Mode", | ||||
|         SIZEOF_ARRAY(bt_param_mode), | ||||
|         bt_carrier_test_mode_changed, | ||||
|         bt_carrier_test); | ||||
|     bt_test_set_current_value_index(param, 0); | ||||
|     bt_test_set_current_value_text(param, bt_param_mode[0].str); | ||||
|     bt_carrier_test->mode = BtTestModeRx; | ||||
| 
 | ||||
|     param = bt_test_param_add( | ||||
|         bt_carrier_test->bt_test, | ||||
|         "Channel", | ||||
|         SIZEOF_ARRAY(bt_param_channel), | ||||
|         bt_carrier_test_channel_changed, | ||||
|         bt_carrier_test); | ||||
|     bt_test_set_current_value_index(param, 0); | ||||
|     bt_test_set_current_value_text(param, bt_param_channel[0].str); | ||||
|     bt_carrier_test->channel = BtTestChannel2402; | ||||
|     bt_carrier_test->bt_param_channel = param; | ||||
| 
 | ||||
|     param = bt_test_param_add( | ||||
|         bt_carrier_test->bt_test, | ||||
|         "Power", | ||||
|         SIZEOF_ARRAY(bt_param_power), | ||||
|         bt_carrier_test_param_channel, | ||||
|         bt_carrier_test); | ||||
|     bt_test_set_current_value_index(param, 0); | ||||
|     bt_test_set_current_value_text(param, bt_param_power[0].str); | ||||
|     bt_carrier_test->power = BtPower0dB; | ||||
| 
 | ||||
|     bt_carrier_test->timer = | ||||
|         osTimerNew(bt_test_carrier_timer_callback, osTimerPeriodic, bt_carrier_test, NULL); | ||||
| 
 | ||||
|     return bt_carrier_test; | ||||
| } | ||||
| 
 | ||||
| void bt_carrier_test_free(BtCarrierTest* bt_carrier_test) { | ||||
|     furi_assert(bt_carrier_test); | ||||
|     bt_test_free(bt_carrier_test->bt_test); | ||||
|     osTimerDelete(bt_carrier_test->timer); | ||||
|     free(bt_carrier_test); | ||||
| } | ||||
| 
 | ||||
| View* bt_carrier_test_get_view(BtCarrierTest* bt_carrier_test) { | ||||
|     furi_assert(bt_carrier_test); | ||||
|     return bt_test_get_view(bt_carrier_test->bt_test); | ||||
| } | ||||
							
								
								
									
										10
									
								
								applications/bt/bt_debug_app/views/bt_carrier_test.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,10 @@ | ||||
| #pragma once | ||||
| #include <gui/view.h> | ||||
| 
 | ||||
| typedef struct BtCarrierTest BtCarrierTest; | ||||
| 
 | ||||
| BtCarrierTest* bt_carrier_test_alloc(); | ||||
| 
 | ||||
| void bt_carrier_test_free(BtCarrierTest* bt_carrier_test); | ||||
| 
 | ||||
| View* bt_carrier_test_get_view(BtCarrierTest* bt_carrier_test); | ||||
							
								
								
									
										155
									
								
								applications/bt/bt_debug_app/views/bt_packet_test.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,155 @@ | ||||
| #include "bt_packet_test.h" | ||||
| #include "bt_test.h" | ||||
| #include "bt_test_types.h" | ||||
| #include "furi-hal-bt.h" | ||||
| 
 | ||||
| struct BtPacketTest { | ||||
|     BtTest* bt_test; | ||||
|     BtTestMode mode; | ||||
|     BtTestChannel channel; | ||||
|     BtTestDataRate data_rate; | ||||
|     osTimerId_t timer; | ||||
| }; | ||||
| 
 | ||||
| static BtTestParamValue bt_param_mode[] = { | ||||
|     {.value = BtTestModeRx, .str = "Rx"}, | ||||
|     {.value = BtTestModeTx, .str = "Tx"}, | ||||
| }; | ||||
| 
 | ||||
| static BtTestParamValue bt_param_channel[] = { | ||||
|     {.value = BtTestChannel2402, .str = "2402 MHz"}, | ||||
|     {.value = BtTestChannel2440, .str = "2440 MHz"}, | ||||
|     {.value = BtTestChannel2480, .str = "2480 MHz"}, | ||||
| }; | ||||
| 
 | ||||
| static BtTestParamValue bt_param_data_rate[] = { | ||||
|     {.value = BtDataRate1M, .str = "1 Mbps"}, | ||||
|     {.value = BtDataRate2M, .str = "2 Mbps"}, | ||||
| }; | ||||
| 
 | ||||
| static void bt_packet_test_start(BtPacketTest* bt_packet_test) { | ||||
|     furi_assert(bt_packet_test); | ||||
|     if(bt_packet_test->mode == BtTestModeRx) { | ||||
|         furi_hal_bt_start_packet_rx(bt_packet_test->channel, bt_packet_test->data_rate); | ||||
|         osTimerStart(bt_packet_test->timer, 1024 / 4); | ||||
|     } else if(bt_packet_test->mode == BtTestModeTx) { | ||||
|         furi_hal_bt_start_packet_tx(bt_packet_test->channel, 1, bt_packet_test->data_rate); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static void bt_packet_test_stop(BtPacketTest* bt_packet_test) { | ||||
|     furi_assert(bt_packet_test); | ||||
|     if(bt_packet_test->mode == BtTestModeTx) { | ||||
|         furi_hal_bt_stop_packet_test(); | ||||
|         bt_test_set_packets_tx(bt_packet_test->bt_test, furi_hal_bt_get_transmitted_packets()); | ||||
|     } else if(bt_packet_test->mode == BtTestModeRx) { | ||||
|         bt_test_set_packets_rx(bt_packet_test->bt_test, furi_hal_bt_stop_packet_test()); | ||||
|         osTimerStop(bt_packet_test->timer); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static uint32_t bt_packet_test_param_changed(BtTestParam* param, BtTestParamValue* param_val) { | ||||
|     furi_assert(param); | ||||
|     uint8_t index = bt_test_get_current_value_index(param); | ||||
|     bt_test_set_current_value_text(param, param_val[index].str); | ||||
|     return param_val[index].value; | ||||
| } | ||||
| 
 | ||||
| static void bt_packet_test_mode_changed(BtTestParam* param) { | ||||
|     BtPacketTest* bt_packet_test = bt_test_get_context(param); | ||||
|     bt_packet_test_stop(bt_packet_test); | ||||
|     bt_packet_test->mode = bt_packet_test_param_changed(param, bt_param_mode); | ||||
| } | ||||
| 
 | ||||
| static void bt_packet_test_channel_changed(BtTestParam* param) { | ||||
|     BtPacketTest* bt_packet_test = bt_test_get_context(param); | ||||
|     bt_packet_test_stop(bt_packet_test); | ||||
|     bt_packet_test->channel = bt_packet_test_param_changed(param, bt_param_channel); | ||||
| } | ||||
| 
 | ||||
| static void bt_packet_test_param_channel(BtTestParam* param) { | ||||
|     BtPacketTest* bt_packet_test = bt_test_get_context(param); | ||||
|     bt_packet_test_stop(bt_packet_test); | ||||
|     bt_packet_test->data_rate = bt_packet_test_param_changed(param, bt_param_data_rate); | ||||
| } | ||||
| 
 | ||||
| static void bt_packet_test_change_state_callback(BtTestState state, void* context) { | ||||
|     furi_assert(context); | ||||
|     BtPacketTest* bt_packet_test = context; | ||||
|     if(state == BtTestStateStarted) { | ||||
|         bt_packet_test_start(bt_packet_test); | ||||
|     } else if(state == BtTestStateStopped) { | ||||
|         bt_packet_test_stop(bt_packet_test); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static void bt_packet_test_exit_callback(void* context) { | ||||
|     furi_assert(context); | ||||
|     BtPacketTest* bt_packet_test = context; | ||||
|     bt_packet_test_stop(bt_packet_test); | ||||
| } | ||||
| 
 | ||||
| static void bt_test_packet_timer_callback(void* context) { | ||||
|     furi_assert(context); | ||||
|     BtPacketTest* bt_packet_test = context; | ||||
|     if(bt_packet_test->mode == BtTestModeRx) { | ||||
|         bt_test_set_rssi(bt_packet_test->bt_test, furi_hal_bt_get_rssi()); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| BtPacketTest* bt_packet_test_alloc() { | ||||
|     BtPacketTest* bt_packet_test = furi_alloc(sizeof(BtPacketTest)); | ||||
|     bt_packet_test->bt_test = bt_test_alloc(); | ||||
|     bt_test_set_context(bt_packet_test->bt_test, bt_packet_test); | ||||
|     bt_test_set_change_state_callback( | ||||
|         bt_packet_test->bt_test, bt_packet_test_change_state_callback); | ||||
|     bt_test_set_back_callback(bt_packet_test->bt_test, bt_packet_test_exit_callback); | ||||
| 
 | ||||
|     BtTestParam* param; | ||||
|     param = bt_test_param_add( | ||||
|         bt_packet_test->bt_test, | ||||
|         "Mode", | ||||
|         SIZEOF_ARRAY(bt_param_mode), | ||||
|         bt_packet_test_mode_changed, | ||||
|         bt_packet_test); | ||||
|     bt_test_set_current_value_index(param, 0); | ||||
|     bt_test_set_current_value_text(param, bt_param_mode[0].str); | ||||
|     bt_packet_test->mode = BtTestModeRx; | ||||
| 
 | ||||
|     param = bt_test_param_add( | ||||
|         bt_packet_test->bt_test, | ||||
|         "Channel", | ||||
|         SIZEOF_ARRAY(bt_param_channel), | ||||
|         bt_packet_test_channel_changed, | ||||
|         bt_packet_test); | ||||
|     bt_test_set_current_value_index(param, 0); | ||||
|     bt_test_set_current_value_text(param, bt_param_channel[0].str); | ||||
|     bt_packet_test->channel = BtTestChannel2402; | ||||
| 
 | ||||
|     param = bt_test_param_add( | ||||
|         bt_packet_test->bt_test, | ||||
|         "Data rate", | ||||
|         SIZEOF_ARRAY(bt_param_data_rate), | ||||
|         bt_packet_test_param_channel, | ||||
|         bt_packet_test); | ||||
|     bt_test_set_current_value_index(param, 0); | ||||
|     bt_test_set_current_value_text(param, bt_param_data_rate[0].str); | ||||
|     bt_packet_test->data_rate = BtDataRate1M; | ||||
| 
 | ||||
|     bt_packet_test->timer = | ||||
|         osTimerNew(bt_test_packet_timer_callback, osTimerPeriodic, bt_packet_test, NULL); | ||||
| 
 | ||||
|     return bt_packet_test; | ||||
| } | ||||
| 
 | ||||
| void bt_packet_test_free(BtPacketTest* bt_packet_test) { | ||||
|     furi_assert(bt_packet_test); | ||||
|     bt_test_free(bt_packet_test->bt_test); | ||||
|     osTimerDelete(bt_packet_test->timer); | ||||
|     free(bt_packet_test); | ||||
| } | ||||
| 
 | ||||
| View* bt_packet_test_get_view(BtPacketTest* bt_packet_test) { | ||||
|     furi_assert(bt_packet_test); | ||||
|     return bt_test_get_view(bt_packet_test->bt_test); | ||||
| } | ||||
							
								
								
									
										10
									
								
								applications/bt/bt_debug_app/views/bt_packet_test.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,10 @@ | ||||
| #pragma once | ||||
| #include <gui/view.h> | ||||
| 
 | ||||
| typedef struct BtPacketTest BtPacketTest; | ||||
| 
 | ||||
| BtPacketTest* bt_packet_test_alloc(); | ||||
| 
 | ||||
| void bt_packet_test_free(BtPacketTest* bt_packet_test); | ||||
| 
 | ||||
| View* bt_packet_test_get_view(BtPacketTest* bt_packet_test); | ||||
							
								
								
									
										422
									
								
								applications/bt/bt_debug_app/views/bt_test.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						| @ -0,0 +1,422 @@ | ||||
| #include "bt_test.h" | ||||
| 
 | ||||
| #include <gui/canvas.h> | ||||
| #include <gui/elements.h> | ||||
| #include <m-array.h> | ||||
| #include <m-string.h> | ||||
| #include <furi.h> | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| struct BtTestParam { | ||||
|     const char* label; | ||||
|     uint8_t current_value_index; | ||||
|     string_t current_value_text; | ||||
|     uint8_t values_count; | ||||
|     BtTestParamChangeCallback change_callback; | ||||
|     void* context; | ||||
| }; | ||||
| 
 | ||||
| ARRAY_DEF(BtTestParamArray, BtTestParam, M_POD_OPLIST); | ||||
| 
 | ||||
| struct BtTest { | ||||
|     View* view; | ||||
|     BtTestChangeStateCallback change_state_callback; | ||||
|     BtTestBackCallback back_callback; | ||||
|     void* context; | ||||
| }; | ||||
| 
 | ||||
| typedef struct { | ||||
|     BtTestState state; | ||||
|     BtTestParamArray_t params; | ||||
|     uint8_t position; | ||||
|     uint8_t window_position; | ||||
|     const char* message; | ||||
|     float rssi; | ||||
|     uint32_t packets_num_rx; | ||||
|     uint32_t packets_num_tx; | ||||
| } BtTestModel; | ||||
| 
 | ||||
| #define BT_TEST_START_MESSAGE "Ok - Start" | ||||
| #define BT_TEST_STOP_MESSAGE "Ok - Stop" | ||||
| 
 | ||||
| static void bt_test_process_up(BtTest* bt_test); | ||||
| static void bt_test_process_down(BtTest* bt_test); | ||||
| static void bt_test_process_left(BtTest* bt_test); | ||||
| static void bt_test_process_right(BtTest* bt_test); | ||||
| static void bt_test_process_ok(BtTest* bt_test); | ||||
| static void bt_test_process_back(BtTest* bt_test); | ||||
| 
 | ||||
| static void bt_test_draw_callback(Canvas* canvas, void* _model) { | ||||
|     BtTestModel* model = _model; | ||||
|     char info_str[32]; | ||||
| 
 | ||||
|     const uint8_t param_height = 16; | ||||
|     const uint8_t param_width = 123; | ||||
| 
 | ||||
|     canvas_clear(canvas); | ||||
| 
 | ||||
|     uint8_t position = 0; | ||||
|     BtTestParamArray_it_t it; | ||||
| 
 | ||||
|     canvas_set_font(canvas, FontSecondary); | ||||
|     for(BtTestParamArray_it(it, model->params); !BtTestParamArray_end_p(it); | ||||
|         BtTestParamArray_next(it)) { | ||||
|         uint8_t param_position = position - model->window_position; | ||||
|         uint8_t params_on_screen = 3; | ||||
|         uint8_t y_offset = 0; | ||||
| 
 | ||||
|         if(param_position < params_on_screen) { | ||||
|             const BtTestParam* param = BtTestParamArray_cref(it); | ||||
|             uint8_t param_y = y_offset + (param_position * param_height); | ||||
|             uint8_t param_text_y = param_y + param_height - 4; | ||||
| 
 | ||||
|             if(position == model->position) { | ||||
|                 canvas_set_color(canvas, ColorBlack); | ||||
|                 elements_slightly_rounded_box( | ||||
|                     canvas, 0, param_y + 1, param_width, param_height - 2); | ||||
|                 canvas_set_color(canvas, ColorWhite); | ||||
|             } else { | ||||
|                 canvas_set_color(canvas, ColorBlack); | ||||
|             } | ||||
| 
 | ||||
|             canvas_draw_str(canvas, 6, param_text_y, param->label); | ||||
| 
 | ||||
|             if(param->current_value_index > 0) { | ||||
|                 canvas_draw_str(canvas, 50, param_text_y, "<"); | ||||
|             } | ||||
| 
 | ||||
|             canvas_draw_str(canvas, 61, param_text_y, string_get_cstr(param->current_value_text)); | ||||
| 
 | ||||
|             if(param->current_value_index < (param->values_count - 1)) { | ||||
|                 canvas_draw_str(canvas, 113, param_text_y, ">"); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         position++; | ||||
|     } | ||||
| 
 | ||||
|     elements_scrollbar(canvas, model->position, BtTestParamArray_size(model->params)); | ||||
|     canvas_draw_str(canvas, 6, 60, model->message); | ||||
|     if(model->state == BtTestStateStarted) { | ||||
|         if(model->rssi != 0.0f) { | ||||
|             snprintf(info_str, sizeof(info_str), "RSSI:%3.1f dB", model->rssi); | ||||
|             canvas_draw_str_aligned(canvas, 124, 60, AlignRight, AlignBottom, info_str); | ||||
|         } | ||||
|     } else if(model->state == BtTestStateStopped) { | ||||
|         if(model->packets_num_rx) { | ||||
|             snprintf(info_str, sizeof(info_str), "%ld pack rcv", model->packets_num_rx); | ||||
|             canvas_draw_str_aligned(canvas, 124, 60, AlignRight, AlignBottom, info_str); | ||||
|         } else if(model->packets_num_tx) { | ||||
|             snprintf(info_str, sizeof(info_str), "%ld pack sent", model->packets_num_tx); | ||||
|             canvas_draw_str_aligned(canvas, 124, 60, AlignRight, AlignBottom, info_str); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static bool bt_test_input_callback(InputEvent* event, void* context) { | ||||
|     BtTest* bt_test = context; | ||||
|     furi_assert(bt_test); | ||||
|     bool consumed = false; | ||||
| 
 | ||||
|     if(event->type == InputTypeShort) { | ||||
|         switch(event->key) { | ||||
|         case InputKeyUp: | ||||
|             consumed = true; | ||||
|             bt_test_process_up(bt_test); | ||||
|             break; | ||||
|         case InputKeyDown: | ||||
|             consumed = true; | ||||
|             bt_test_process_down(bt_test); | ||||
|             break; | ||||
|         case InputKeyLeft: | ||||
|             consumed = true; | ||||
|             bt_test_process_left(bt_test); | ||||
|             break; | ||||
|         case InputKeyRight: | ||||
|             consumed = true; | ||||
|             bt_test_process_right(bt_test); | ||||
|             break; | ||||
|         case InputKeyOk: | ||||
|             consumed = true; | ||||
|             bt_test_process_ok(bt_test); | ||||
|             break; | ||||
|         case InputKeyBack: | ||||
|             consumed = false; | ||||
|             bt_test_process_back(bt_test); | ||||
|             break; | ||||
|         default: | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return consumed; | ||||
| } | ||||
| 
 | ||||
| void bt_test_process_up(BtTest* bt_test) { | ||||
|     with_view_model( | ||||
|         bt_test->view, (BtTestModel * model) { | ||||
|             uint8_t params_on_screen = 3; | ||||
|             if(model->position > 0) { | ||||
|                 model->position--; | ||||
|                 if(((model->position - model->window_position) < 1) && | ||||
|                    model->window_position > 0) { | ||||
|                     model->window_position--; | ||||
|                 } | ||||
|             } else { | ||||
|                 model->position = BtTestParamArray_size(model->params) - 1; | ||||
|                 if(model->position > (params_on_screen - 1)) { | ||||
|                     model->window_position = model->position - (params_on_screen - 1); | ||||
|                 } | ||||
|             } | ||||
|             return true; | ||||
|         }); | ||||
| } | ||||
| 
 | ||||
| void bt_test_process_down(BtTest* bt_test) { | ||||
|     with_view_model( | ||||
|         bt_test->view, (BtTestModel * model) { | ||||
|             uint8_t params_on_screen = 3; | ||||
|             if(model->position < (BtTestParamArray_size(model->params) - 1)) { | ||||
|                 model->position++; | ||||
|                 if((model->position - model->window_position) > (params_on_screen - 2) && | ||||
|                    model->window_position < | ||||
|                        (BtTestParamArray_size(model->params) - params_on_screen)) { | ||||
|                     model->window_position++; | ||||
|                 } | ||||
|             } else { | ||||
|                 model->position = 0; | ||||
|                 model->window_position = 0; | ||||
|             } | ||||
|             return true; | ||||
|         }); | ||||
| } | ||||
| 
 | ||||
| BtTestParam* bt_test_get_selected_param(BtTestModel* model) { | ||||
|     BtTestParam* param = NULL; | ||||
| 
 | ||||
|     BtTestParamArray_it_t it; | ||||
|     uint8_t position = 0; | ||||
|     for(BtTestParamArray_it(it, model->params); !BtTestParamArray_end_p(it); | ||||
|         BtTestParamArray_next(it)) { | ||||
|         if(position == model->position) { | ||||
|             break; | ||||
|         } | ||||
|         position++; | ||||
|     } | ||||
| 
 | ||||
|     param = BtTestParamArray_ref(it); | ||||
| 
 | ||||
|     furi_assert(param); | ||||
|     return param; | ||||
| } | ||||
| 
 | ||||
| void bt_test_process_left(BtTest* bt_test) { | ||||
|     BtTestParam* param; | ||||
|     with_view_model( | ||||
|         bt_test->view, (BtTestModel * model) { | ||||
|             param = bt_test_get_selected_param(model); | ||||
|             if(param->current_value_index > 0) { | ||||
|                 param->current_value_index--; | ||||
|                 if(param->change_callback) { | ||||
|                     model->state = BtTestStateStopped; | ||||
|                     model->message = BT_TEST_START_MESSAGE; | ||||
|                     model->rssi = 0.0f; | ||||
|                     model->packets_num_rx = 0; | ||||
|                     model->packets_num_tx = 0; | ||||
|                 } | ||||
|             } | ||||
|             return true; | ||||
|         }); | ||||
|     if(param->change_callback) { | ||||
|         param->change_callback(param); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void bt_test_process_right(BtTest* bt_test) { | ||||
|     BtTestParam* param; | ||||
|     with_view_model( | ||||
|         bt_test->view, (BtTestModel * model) { | ||||
|             param = bt_test_get_selected_param(model); | ||||
|             if(param->current_value_index < (param->values_count - 1)) { | ||||
|                 param->current_value_index++; | ||||
|                 if(param->change_callback) { | ||||
|                     model->state = BtTestStateStopped; | ||||
|                     model->message = BT_TEST_START_MESSAGE; | ||||
|                     model->rssi = 0.0f; | ||||
|                     model->packets_num_rx = 0; | ||||
|                     model->packets_num_tx = 0; | ||||
|                 } | ||||
|             } | ||||
|             return true; | ||||
|         }); | ||||
|     if(param->change_callback) { | ||||
|         param->change_callback(param); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void bt_test_process_ok(BtTest* bt_test) { | ||||
|     BtTestState state; | ||||
|     with_view_model( | ||||
|         bt_test->view, (BtTestModel * model) { | ||||
|             if(model->state == BtTestStateStarted) { | ||||
|                 model->state = BtTestStateStopped; | ||||
|                 model->message = BT_TEST_START_MESSAGE; | ||||
|                 model->rssi = 0.0f; | ||||
|                 model->packets_num_rx = 0; | ||||
|                 model->packets_num_tx = 0; | ||||
|             } else if(model->state == BtTestStateStopped) { | ||||
|                 model->state = BtTestStateStarted; | ||||
|                 model->message = BT_TEST_STOP_MESSAGE; | ||||
|             } | ||||
|             state = model->state; | ||||
|             return true; | ||||
|         }); | ||||
|     if(bt_test->change_state_callback) { | ||||
|         bt_test->change_state_callback(state, bt_test->context); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void bt_test_process_back(BtTest* bt_test) { | ||||
|     with_view_model( | ||||
|         bt_test->view, (BtTestModel * model) { | ||||
|             model->state = BtTestStateStopped; | ||||
|             model->rssi = 0.0f; | ||||
|             model->packets_num_rx = 0; | ||||
|             model->packets_num_tx = 0; | ||||
|             return false; | ||||
|         }); | ||||
|     if(bt_test->back_callback) { | ||||
|         bt_test->back_callback(bt_test->context); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| BtTest* bt_test_alloc() { | ||||
|     BtTest* bt_test = furi_alloc(sizeof(BtTest)); | ||||
|     bt_test->view = view_alloc(); | ||||
|     view_set_context(bt_test->view, bt_test); | ||||
|     view_allocate_model(bt_test->view, ViewModelTypeLocking, sizeof(BtTestModel)); | ||||
|     view_set_draw_callback(bt_test->view, bt_test_draw_callback); | ||||
|     view_set_input_callback(bt_test->view, bt_test_input_callback); | ||||
| 
 | ||||
|     with_view_model( | ||||
|         bt_test->view, (BtTestModel * model) { | ||||
|             model->state = BtTestStateStopped; | ||||
|             model->message = "Ok - Start"; | ||||
|             BtTestParamArray_init(model->params); | ||||
|             model->position = 0; | ||||
|             model->window_position = 0; | ||||
|             model->rssi = 0.0f; | ||||
|             model->packets_num_tx = 0; | ||||
|             model->packets_num_rx = 0; | ||||
|             return true; | ||||
|         }); | ||||
| 
 | ||||
|     return bt_test; | ||||
| } | ||||
| 
 | ||||
| void bt_test_free(BtTest* bt_test) { | ||||
|     furi_assert(bt_test); | ||||
| 
 | ||||
|     with_view_model( | ||||
|         bt_test->view, (BtTestModel * model) { | ||||
|             BtTestParamArray_it_t it; | ||||
|             for(BtTestParamArray_it(it, model->params); !BtTestParamArray_end_p(it); | ||||
|                 BtTestParamArray_next(it)) { | ||||
|                 string_clear(BtTestParamArray_ref(it)->current_value_text); | ||||
|             } | ||||
|             BtTestParamArray_clear(model->params); | ||||
|             return false; | ||||
|         }); | ||||
|     view_free(bt_test->view); | ||||
|     free(bt_test); | ||||
| } | ||||
| 
 | ||||
| View* bt_test_get_view(BtTest* bt_test) { | ||||
|     furi_assert(bt_test); | ||||
|     return bt_test->view; | ||||
| } | ||||
| 
 | ||||
| BtTestParam* bt_test_param_add( | ||||
|     BtTest* bt_test, | ||||
|     const char* label, | ||||
|     uint8_t values_count, | ||||
|     BtTestParamChangeCallback change_callback, | ||||
|     void* context) { | ||||
|     BtTestParam* param = NULL; | ||||
|     furi_assert(label); | ||||
|     furi_assert(bt_test); | ||||
| 
 | ||||
|     with_view_model( | ||||
|         bt_test->view, (BtTestModel * model) { | ||||
|             param = BtTestParamArray_push_new(model->params); | ||||
|             param->label = label; | ||||
|             param->values_count = values_count; | ||||
|             param->change_callback = change_callback; | ||||
|             param->context = context; | ||||
|             param->current_value_index = 0; | ||||
|             string_init(param->current_value_text); | ||||
|             return true; | ||||
|         }); | ||||
| 
 | ||||
|     return param; | ||||
| } | ||||
| 
 | ||||
| void bt_test_set_rssi(BtTest* bt_test, float rssi) { | ||||
|     furi_assert(bt_test); | ||||
|     with_view_model( | ||||
|         bt_test->view, (BtTestModel * model) { | ||||
|             model->rssi = rssi; | ||||
|             return true; | ||||
|         }); | ||||
| } | ||||
| 
 | ||||
| void bt_test_set_packets_tx(BtTest* bt_test, uint32_t packets_num) { | ||||
|     furi_assert(bt_test); | ||||
|     with_view_model( | ||||
|         bt_test->view, (BtTestModel * model) { | ||||
|             model->packets_num_tx = packets_num; | ||||
|             return true; | ||||
|         }); | ||||
| } | ||||
| 
 | ||||
| void bt_test_set_packets_rx(BtTest* bt_test, uint32_t packets_num) { | ||||
|     furi_assert(bt_test); | ||||
|     with_view_model( | ||||
|         bt_test->view, (BtTestModel * model) { | ||||
|             model->packets_num_rx = packets_num; | ||||
|             return true; | ||||
|         }); | ||||
| } | ||||
| 
 | ||||
| void bt_test_set_change_state_callback(BtTest* bt_test, BtTestChangeStateCallback callback) { | ||||
|     furi_assert(bt_test); | ||||
|     furi_assert(callback); | ||||
|     bt_test->change_state_callback = callback; | ||||
| } | ||||
| 
 | ||||
| void bt_test_set_back_callback(BtTest* bt_test, BtTestBackCallback callback) { | ||||
|     furi_assert(bt_test); | ||||
|     furi_assert(callback); | ||||
|     bt_test->back_callback = callback; | ||||
| } | ||||
| 
 | ||||
| void bt_test_set_context(BtTest* bt_test, void* context) { | ||||
|     furi_assert(bt_test); | ||||
|     bt_test->context = context; | ||||
| } | ||||
| 
 | ||||
| void bt_test_set_current_value_index(BtTestParam* param, uint8_t current_value_index) { | ||||
|     param->current_value_index = current_value_index; | ||||
| } | ||||
| 
 | ||||
| void bt_test_set_current_value_text(BtTestParam* param, const char* current_value_text) { | ||||
|     string_set_str(param->current_value_text, current_value_text); | ||||
| } | ||||
| 
 | ||||
| uint8_t bt_test_get_current_value_index(BtTestParam* param) { | ||||
|     return param->current_value_index; | ||||
| } | ||||
| 
 | ||||
| void* bt_test_get_context(BtTestParam* param) { | ||||
|     return param->context; | ||||
| } | ||||
							
								
								
									
										46
									
								
								applications/bt/bt_debug_app/views/bt_test.h
									
									
									
									
									
										Executable file
									
								
							
							
						
						| @ -0,0 +1,46 @@ | ||||
| #pragma once | ||||
| #include <gui/view.h> | ||||
| 
 | ||||
| typedef enum { | ||||
|     BtTestStateStarted, | ||||
|     BtTestStateStopped, | ||||
| } BtTestState; | ||||
| 
 | ||||
| typedef struct BtTest BtTest; | ||||
| typedef void (*BtTestChangeStateCallback)(BtTestState state, void* context); | ||||
| typedef void (*BtTestBackCallback)(void* context); | ||||
| typedef struct BtTestParam BtTestParam; | ||||
| typedef void (*BtTestParamChangeCallback)(BtTestParam* param); | ||||
| 
 | ||||
| BtTest* bt_test_alloc(); | ||||
| 
 | ||||
| void bt_test_free(BtTest* bt_test); | ||||
| 
 | ||||
| View* bt_test_get_view(BtTest* bt_test); | ||||
| 
 | ||||
| BtTestParam* bt_test_param_add( | ||||
|     BtTest* bt_test, | ||||
|     const char* label, | ||||
|     uint8_t values_count, | ||||
|     BtTestParamChangeCallback change_callback, | ||||
|     void* context); | ||||
| 
 | ||||
| void bt_test_set_change_state_callback(BtTest* bt_test, BtTestChangeStateCallback callback); | ||||
| 
 | ||||
| void bt_test_set_back_callback(BtTest* bt_test, BtTestBackCallback callback); | ||||
| 
 | ||||
| void bt_test_set_context(BtTest* bt_test, void* context); | ||||
| 
 | ||||
| void bt_test_set_rssi(BtTest* bt_test, float rssi); | ||||
| 
 | ||||
| void bt_test_set_packets_tx(BtTest* bt_test, uint32_t packets_num); | ||||
| 
 | ||||
| void bt_test_set_packets_rx(BtTest* bt_test, uint32_t packets_num); | ||||
| 
 | ||||
| void bt_test_set_current_value_index(BtTestParam* param, uint8_t current_value_index); | ||||
| 
 | ||||
| void bt_test_set_current_value_text(BtTestParam* param, const char* current_value_text); | ||||
| 
 | ||||
| uint8_t bt_test_get_current_value_index(BtTestParam* param); | ||||
| 
 | ||||
| void* bt_test_get_context(BtTestParam* param); | ||||
							
								
								
									
										30
									
								
								applications/bt/bt_debug_app/views/bt_test_types.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,30 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| typedef enum { | ||||
|     BtTestModeRx, | ||||
|     BtTestModeTx, | ||||
|     BtTestModeTxHopping, | ||||
| } BtTestMode; | ||||
| 
 | ||||
| typedef enum { | ||||
|     BtTestChannel2402 = 0, | ||||
|     BtTestChannel2440 = 19, | ||||
|     BtTestChannel2480 = 39, | ||||
| } BtTestChannel; | ||||
| 
 | ||||
| typedef enum { | ||||
|     BtPower0dB = 0x19, | ||||
|     BtPower2dB = 0x1B, | ||||
|     BtPower4dB = 0x1D, | ||||
|     BtPower6dB = 0x1F, | ||||
| } BtTestPower; | ||||
| 
 | ||||
| typedef enum { | ||||
|     BtDataRate1M = 1, | ||||
|     BtDataRate2M = 2, | ||||
| } BtTestDataRate; | ||||
| 
 | ||||
| typedef struct { | ||||
|     uint32_t value; | ||||
|     const char* str; | ||||
| } BtTestParamValue; | ||||
| @ -1,53 +0,0 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include "bt.h" | ||||
| #include "bt_views.h" | ||||
| #include "bt_types.h" | ||||
| 
 | ||||
| #include <furi.h> | ||||
| #include <furi-hal.h> | ||||
| 
 | ||||
| #include <cli/cli.h> | ||||
| 
 | ||||
| #include <gui/gui.h> | ||||
| #include <gui/view_port.h> | ||||
| #include <gui/view.h> | ||||
| #include <gui/view_dispatcher.h> | ||||
| 
 | ||||
| #include <menu/menu.h> | ||||
| #include <menu/menu_item.h> | ||||
| 
 | ||||
| struct Bt { | ||||
|     osMessageQueueId_t message_queue; | ||||
|     BtState state; | ||||
|     osTimerId_t update_status_timer; | ||||
|     osTimerId_t update_param_timer; | ||||
|     Gui* gui; | ||||
|     ValueMutex* menu; | ||||
|     // Status bar
 | ||||
|     ViewPort* statusbar_view_port; | ||||
|     // Menu
 | ||||
|     IconAnimation* menu_icon; | ||||
|     MenuItem* menu_item; | ||||
|     View* view_test_carrier; | ||||
|     View* view_test_packet_tx; | ||||
|     View* view_test_packet_rx; | ||||
|     View* view_start_app; | ||||
|     ViewDispatcher* view_dispatcher; | ||||
| }; | ||||
| 
 | ||||
| Bt* bt_alloc(); | ||||
| 
 | ||||
| void bt_draw_statusbar_callback(Canvas* canvas, void* context); | ||||
| 
 | ||||
| BtTestChannel bt_switch_channel(InputKey key, BtTestChannel inst_chan); | ||||
| 
 | ||||
| void bt_draw_statusbar_callback(Canvas* canvas, void* context); | ||||
| 
 | ||||
| void bt_menu_test_carrier(void* context); | ||||
| 
 | ||||
| void bt_menu_test_packet_tx(void* context); | ||||
| 
 | ||||
| void bt_menu_test_packet_rx(void* context); | ||||
| 
 | ||||
| void bt_menu_start_app(void* context); | ||||
							
								
								
									
										74
									
								
								applications/bt/bt_service/bt.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,74 @@ | ||||
| #include "bt_i.h" | ||||
| 
 | ||||
| #define BT_SERVICE_TAG "BT" | ||||
| 
 | ||||
| // static void bt_update_statusbar(void* arg) {
 | ||||
| //     furi_assert(arg);
 | ||||
| //     Bt* bt = arg;
 | ||||
| //     BtMessage m = {.type = BtMessageTypeUpdateStatusbar};
 | ||||
| //     furi_check(osMessageQueuePut(bt->message_queue, &m, 0, osWaitForever) == osOK);
 | ||||
| // }
 | ||||
| 
 | ||||
| static void bt_draw_statusbar_callback(Canvas* canvas, void* context) { | ||||
|     canvas_draw_icon(canvas, 0, 0, &I_Bluetooth_5x8); | ||||
| } | ||||
| 
 | ||||
| static ViewPort* bt_statusbar_view_port_alloc() { | ||||
|     ViewPort* statusbar_view_port = view_port_alloc(); | ||||
|     view_port_set_width(statusbar_view_port, 5); | ||||
|     view_port_draw_callback_set(statusbar_view_port, bt_draw_statusbar_callback, NULL); | ||||
|     view_port_enabled_set(statusbar_view_port, false); | ||||
|     return statusbar_view_port; | ||||
| } | ||||
| 
 | ||||
| Bt* bt_alloc() { | ||||
|     Bt* bt = furi_alloc(sizeof(Bt)); | ||||
|     // Load settings
 | ||||
|     if(!bt_settings_load(&bt->bt_settings)) { | ||||
|         bt_settings_save(&bt->bt_settings); | ||||
|     } | ||||
|     // Alloc queue
 | ||||
|     bt->message_queue = osMessageQueueNew(8, sizeof(BtMessage), NULL); | ||||
| 
 | ||||
|     // doesn't make sense if we waiting for transition on service start
 | ||||
|     // bt->update_status_timer = osTimerNew(bt_update_statusbar, osTimerPeriodic, bt, NULL);
 | ||||
|     // osTimerStart(bt->update_status_timer, 4000);
 | ||||
| 
 | ||||
|     // Setup statusbar view port
 | ||||
|     bt->statusbar_view_port = bt_statusbar_view_port_alloc(); | ||||
|     // Gui
 | ||||
|     bt->gui = furi_record_open("gui"); | ||||
|     gui_add_view_port(bt->gui, bt->statusbar_view_port, GuiLayerStatusBarLeft); | ||||
| 
 | ||||
|     return bt; | ||||
| } | ||||
| 
 | ||||
| int32_t bt_srv() { | ||||
|     Bt* bt = bt_alloc(); | ||||
|     furi_record_create("bt", bt); | ||||
|     furi_hal_bt_init(); | ||||
| 
 | ||||
|     if(!furi_hal_bt_wait_startup()) { | ||||
|         FURI_LOG_E(BT_SERVICE_TAG, "Core2 startup failed"); | ||||
|     } else { | ||||
|         view_port_enabled_set(bt->statusbar_view_port, true); | ||||
|         if(bt->bt_settings.enabled) { | ||||
|             bool bt_app_started = furi_hal_bt_start_app(); | ||||
|             if(!bt_app_started) { | ||||
|                 FURI_LOG_E(BT_SERVICE_TAG, "BT App start failed"); | ||||
|             } else { | ||||
|                 FURI_LOG_I(BT_SERVICE_TAG, "BT App started"); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     BtMessage message; | ||||
|     while(1) { | ||||
|         furi_check(osMessageQueueGet(bt->message_queue, &message, NULL, osWaitForever) == osOK); | ||||
|         if(message.type == BtMessageTypeUpdateStatusbar) { | ||||
|             // Update statusbar
 | ||||
|             view_port_enabled_set(bt->statusbar_view_port, furi_hal_bt_is_alive()); | ||||
|         } | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
							
								
								
									
										29
									
								
								applications/bt/bt_service/bt_i.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,29 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include "bt.h" | ||||
| 
 | ||||
| #include <furi.h> | ||||
| #include <furi-hal.h> | ||||
| 
 | ||||
| #include <gui/gui.h> | ||||
| #include <gui/view_port.h> | ||||
| #include <gui/view.h> | ||||
| 
 | ||||
| #include "../bt_settings.h" | ||||
| 
 | ||||
| typedef enum { | ||||
|     BtMessageTypeUpdateStatusbar, | ||||
| } BtMessageType; | ||||
| 
 | ||||
| typedef struct { | ||||
|     BtMessageType type; | ||||
|     void* param; | ||||
| } BtMessage; | ||||
| 
 | ||||
| struct Bt { | ||||
|     BtSettings bt_settings; | ||||
|     osMessageQueueId_t message_queue; | ||||
|     osTimerId_t update_status_timer; | ||||
|     Gui* gui; | ||||
|     ViewPort* statusbar_view_port; | ||||
| }; | ||||
							
								
								
									
										50
									
								
								applications/bt/bt_settings.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,50 @@ | ||||
| #include "bt_settings.h" | ||||
| #include <furi.h> | ||||
| #include <file-worker.h> | ||||
| 
 | ||||
| #define BT_SETTINGS_TAG "bt settings" | ||||
| #define BT_SETTINGS_PATH "/int/bt.settings" | ||||
| 
 | ||||
| bool bt_settings_load(BtSettings* bt_settings) { | ||||
|     furi_assert(bt_settings); | ||||
|     bool file_loaded = false; | ||||
|     BtSettings settings = {}; | ||||
| 
 | ||||
|     FURI_LOG_I(BT_SETTINGS_TAG, "Loading settings from \"%s\"", BT_SETTINGS_PATH); | ||||
|     FileWorker* file_worker = file_worker_alloc(true); | ||||
|     if(file_worker_open(file_worker, BT_SETTINGS_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) { | ||||
|         if(file_worker_read(file_worker, &settings, sizeof(settings))) { | ||||
|             file_loaded = true; | ||||
|         } | ||||
|     } | ||||
|     file_worker_free(file_worker); | ||||
| 
 | ||||
|     if(file_loaded) { | ||||
|         FURI_LOG_I(BT_SETTINGS_TAG, "Settings load success"); | ||||
|         if(settings.version != BT_SETTINGS_VERSION) { | ||||
|             FURI_LOG_E(BT_SETTINGS_TAG, "Settings version mismatch"); | ||||
|         } else { | ||||
|             osKernelLock(); | ||||
|             *bt_settings = settings; | ||||
|             osKernelUnlock(); | ||||
|         } | ||||
|     } else { | ||||
|         FURI_LOG_E(BT_SETTINGS_TAG, "Settings load failed"); | ||||
|     } | ||||
|     return file_loaded; | ||||
| } | ||||
| 
 | ||||
| bool bt_settings_save(BtSettings* bt_settings) { | ||||
|     furi_assert(bt_settings); | ||||
|     bool result = false; | ||||
| 
 | ||||
|     FileWorker* file_worker = file_worker_alloc(true); | ||||
|     if(file_worker_open(file_worker, BT_SETTINGS_PATH, FSAM_WRITE, FSOM_OPEN_ALWAYS)) { | ||||
|         if(file_worker_write(file_worker, bt_settings, sizeof(BtSettings))) { | ||||
|             FURI_LOG_I(BT_SETTINGS_TAG, "Settings saved to \"%s\"", BT_SETTINGS_PATH); | ||||
|             result = true; | ||||
|         } | ||||
|     } | ||||
|     file_worker_free(file_worker); | ||||
|     return result; | ||||
| } | ||||
							
								
								
									
										15
									
								
								applications/bt/bt_settings.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,15 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| #include <stdbool.h> | ||||
| 
 | ||||
| #define BT_SETTINGS_VERSION (0) | ||||
| 
 | ||||
| typedef struct { | ||||
|     uint8_t version; | ||||
|     bool enabled; | ||||
| } BtSettings; | ||||
| 
 | ||||
| bool bt_settings_load(BtSettings* bt_settings); | ||||
| 
 | ||||
| bool bt_settings_save(BtSettings* bt_settings); | ||||
							
								
								
									
										67
									
								
								applications/bt/bt_settings_app/bt_settings_app.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						| @ -0,0 +1,67 @@ | ||||
| #include "bt_settings_app.h" | ||||
| 
 | ||||
| static bool bt_settings_custom_event_callback(void* context, uint32_t event) { | ||||
|     furi_assert(context); | ||||
|     BtSettingsApp* app = context; | ||||
|     return scene_manager_handle_custom_event(app->scene_manager, event); | ||||
| } | ||||
| 
 | ||||
| static bool bt_settings_back_event_callback(void* context) { | ||||
|     furi_assert(context); | ||||
|     BtSettingsApp* app = context; | ||||
|     return scene_manager_handle_back_event(app->scene_manager); | ||||
| } | ||||
| 
 | ||||
| BtSettingsApp* bt_settings_app_alloc() { | ||||
|     BtSettingsApp* app = furi_alloc(sizeof(BtSettingsApp)); | ||||
| 
 | ||||
|     // Load settings
 | ||||
|     bt_settings_load(&app->settings); | ||||
|     app->gui = furi_record_open("gui"); | ||||
| 
 | ||||
|     app->view_dispatcher = view_dispatcher_alloc(); | ||||
|     app->scene_manager = scene_manager_alloc(&bt_settings_scene_handlers, app); | ||||
|     view_dispatcher_enable_queue(app->view_dispatcher); | ||||
|     view_dispatcher_set_event_callback_context(app->view_dispatcher, app); | ||||
| 
 | ||||
|     view_dispatcher_set_custom_event_callback( | ||||
|         app->view_dispatcher, bt_settings_custom_event_callback); | ||||
|     view_dispatcher_set_navigation_event_callback( | ||||
|         app->view_dispatcher, bt_settings_back_event_callback); | ||||
| 
 | ||||
|     view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); | ||||
| 
 | ||||
|     app->submenu = submenu_alloc(); | ||||
|     view_dispatcher_add_view( | ||||
|         app->view_dispatcher, BtSettingsAppViewSubmenu, submenu_get_view(app->submenu)); | ||||
|     app->dialog_ex = dialog_ex_alloc(); | ||||
|     view_dispatcher_add_view( | ||||
|         app->view_dispatcher, BtSettingsAppViewDialogEx, dialog_ex_get_view(app->dialog_ex)); | ||||
| 
 | ||||
|     scene_manager_next_scene(app->scene_manager, BtSettingsAppSceneStart); | ||||
|     return app; | ||||
| } | ||||
| 
 | ||||
| void bt_settings_app_free(BtSettingsApp* app) { | ||||
|     furi_assert(app); | ||||
|     // Submenu
 | ||||
|     view_dispatcher_remove_view(app->view_dispatcher, BtSettingsAppViewSubmenu); | ||||
|     submenu_free(app->submenu); | ||||
|     // Dialog
 | ||||
|     view_dispatcher_remove_view(app->view_dispatcher, BtSettingsAppViewDialogEx); | ||||
|     dialog_ex_free(app->dialog_ex); | ||||
|     // View dispatcher
 | ||||
|     view_dispatcher_free(app->view_dispatcher); | ||||
|     scene_manager_free(app->scene_manager); | ||||
|     // Records
 | ||||
|     furi_record_close("gui"); | ||||
|     free(app); | ||||
| } | ||||
| 
 | ||||
| extern int32_t bt_settings_app(void* p) { | ||||
|     BtSettingsApp* app = bt_settings_app_alloc(); | ||||
|     view_dispatcher_run(app->view_dispatcher); | ||||
|     bt_settings_save(&app->settings); | ||||
|     bt_settings_app_free(app); | ||||
|     return 0; | ||||
| } | ||||
							
								
								
									
										27
									
								
								applications/bt/bt_settings_app/bt_settings_app.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,27 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <furi.h> | ||||
| #include <gui/gui.h> | ||||
| #include <gui/view.h> | ||||
| #include <gui/view_dispatcher.h> | ||||
| #include <gui/scene_manager.h> | ||||
| 
 | ||||
| #include <gui/modules/submenu.h> | ||||
| #include <gui/modules/dialog_ex.h> | ||||
| 
 | ||||
| #include "../bt_settings.h" | ||||
| #include "scenes/bt_settings_scene.h" | ||||
| 
 | ||||
| typedef struct { | ||||
|     BtSettings settings; | ||||
|     Gui* gui; | ||||
|     SceneManager* scene_manager; | ||||
|     ViewDispatcher* view_dispatcher; | ||||
|     Submenu* submenu; | ||||
|     DialogEx* dialog_ex; | ||||
| } BtSettingsApp; | ||||
| 
 | ||||
| typedef enum { | ||||
|     BtSettingsAppViewSubmenu, | ||||
|     BtSettingsAppViewDialogEx, | ||||
| } BtSettingsAppView; | ||||
							
								
								
									
										30
									
								
								applications/bt/bt_settings_app/scenes/bt_settings_scene.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,30 @@ | ||||
| #include "bt_settings_scene.h" | ||||
| 
 | ||||
| // Generate scene on_enter handlers array
 | ||||
| #define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter, | ||||
| void (*const bt_settings_on_enter_handlers[])(void*) = { | ||||
| #include "bt_settings_scene_config.h" | ||||
| }; | ||||
| #undef ADD_SCENE | ||||
| 
 | ||||
| // Generate scene on_event handlers array
 | ||||
| #define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event, | ||||
| bool (*const bt_settings_on_event_handlers[])(void* context, SceneManagerEvent event) = { | ||||
| #include "bt_settings_scene_config.h" | ||||
| }; | ||||
| #undef ADD_SCENE | ||||
| 
 | ||||
| // Generate scene on_exit handlers array
 | ||||
| #define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit, | ||||
| void (*const bt_settings_on_exit_handlers[])(void* context) = { | ||||
| #include "bt_settings_scene_config.h" | ||||
| }; | ||||
| #undef ADD_SCENE | ||||
| 
 | ||||
| // Initialize scene handlers configuration structure
 | ||||
| const SceneManagerHandlers bt_settings_scene_handlers = { | ||||
|     .on_enter_handlers = bt_settings_on_enter_handlers, | ||||
|     .on_event_handlers = bt_settings_on_event_handlers, | ||||
|     .on_exit_handlers = bt_settings_on_exit_handlers, | ||||
|     .scene_num = BtSettingsAppSceneNum, | ||||
| }; | ||||
							
								
								
									
										29
									
								
								applications/bt/bt_settings_app/scenes/bt_settings_scene.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,29 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <gui/scene_manager.h> | ||||
| 
 | ||||
| // Generate scene id and total number
 | ||||
| #define ADD_SCENE(prefix, name, id) BtSettingsAppScene##id, | ||||
| typedef enum { | ||||
| #include "bt_settings_scene_config.h" | ||||
|     BtSettingsAppSceneNum, | ||||
| } BtSettingsAppScene; | ||||
| #undef ADD_SCENE | ||||
| 
 | ||||
| extern const SceneManagerHandlers bt_settings_scene_handlers; | ||||
| 
 | ||||
| // Generate scene on_enter handlers declaration
 | ||||
| #define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*); | ||||
| #include "bt_settings_scene_config.h" | ||||
| #undef ADD_SCENE | ||||
| 
 | ||||
| // Generate scene on_event handlers declaration
 | ||||
| #define ADD_SCENE(prefix, name, id) \ | ||||
|     bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event); | ||||
| #include "bt_settings_scene_config.h" | ||||
| #undef ADD_SCENE | ||||
| 
 | ||||
| // Generate scene on_exit handlers declaration
 | ||||
| #define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context); | ||||
| #include "bt_settings_scene_config.h" | ||||
| #undef ADD_SCENE | ||||
| @ -0,0 +1,2 @@ | ||||
| ADD_SCENE(bt_settings, start, Start) | ||||
| ADD_SCENE(bt_settings, disable_dialog, DisableDialog) | ||||
							
								
								
									
										44
									
								
								applications/bt/bt_settings_app/scenes/bt_settings_scene_disable_dialog.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						| @ -0,0 +1,44 @@ | ||||
| #include "../bt_settings_app.h" | ||||
| #include <furi-hal-boot.h> | ||||
| #include <furi-hal-power.h> | ||||
| 
 | ||||
| static void bt_setting_disable_dialog_callback(DialogExResult result, void* context) { | ||||
|     BtSettingsApp* app = context; | ||||
|     view_dispatcher_send_custom_event(app->view_dispatcher, result); | ||||
| } | ||||
| 
 | ||||
| void bt_settings_scene_disable_dialog_on_enter(void* context) { | ||||
|     BtSettingsApp* app = context; | ||||
|     DialogEx* dialog_ex = app->dialog_ex; | ||||
|     dialog_ex_set_text( | ||||
|         dialog_ex, "Reboot device\nto disable Bluetooth", 64, 32, AlignCenter, AlignCenter); | ||||
|     dialog_ex_set_left_button_text(dialog_ex, "Back"); | ||||
|     dialog_ex_set_right_button_text(dialog_ex, "Reboot"); | ||||
|     dialog_ex_set_result_callback(dialog_ex, bt_setting_disable_dialog_callback); | ||||
|     dialog_ex_set_context(dialog_ex, app); | ||||
| 
 | ||||
|     view_dispatcher_switch_to_view(app->view_dispatcher, BtSettingsAppViewDialogEx); | ||||
| } | ||||
| 
 | ||||
| bool bt_settings_scene_disable_dialog_on_event(void* context, SceneManagerEvent event) { | ||||
|     BtSettingsApp* app = context; | ||||
|     bool consumed = false; | ||||
| 
 | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         if(event.event == DialogExResultLeft) { | ||||
|             scene_manager_previous_scene(app->scene_manager); | ||||
|             consumed = true; | ||||
|         } else if(event.event == DialogExResultRight) { | ||||
|             app->settings.enabled = false; | ||||
|             bt_settings_save(&app->settings); | ||||
|             furi_hal_boot_set_mode(FuriHalBootModeNormal); | ||||
|             furi_hal_power_reset(); | ||||
|         } | ||||
|     } | ||||
|     return consumed; | ||||
| } | ||||
| 
 | ||||
| void bt_settings_scene_disable_dialog_on_exit(void* context) { | ||||
|     BtSettingsApp* app = context; | ||||
|     dialog_ex_clean(app->dialog_ex); | ||||
| } | ||||
							
								
								
									
										56
									
								
								applications/bt/bt_settings_app/scenes/bt_settings_scene_start.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						| @ -0,0 +1,56 @@ | ||||
| #include "../bt_settings_app.h" | ||||
| #include "furi-hal-bt.h" | ||||
| 
 | ||||
| enum BtSettingsAppStartSubmenuIndex { | ||||
|     BtSettingsAppStartSubmenuIndexEnable, | ||||
| }; | ||||
| 
 | ||||
| static void bt_settings_scene_start_submenu_callback(void* context, uint32_t index) { | ||||
|     BtSettingsApp* app = context; | ||||
|     view_dispatcher_send_custom_event(app->view_dispatcher, index); | ||||
| } | ||||
| 
 | ||||
| void bt_settings_scene_start_on_enter(void* context) { | ||||
|     BtSettingsApp* app = context; | ||||
|     Submenu* submenu = app->submenu; | ||||
| 
 | ||||
|     const char* submenu_label = app->settings.enabled ? "Disable" : "Enable"; | ||||
|     submenu_add_item( | ||||
|         submenu, | ||||
|         submenu_label, | ||||
|         BtSettingsAppStartSubmenuIndexEnable, | ||||
|         bt_settings_scene_start_submenu_callback, | ||||
|         app); | ||||
| 
 | ||||
|     view_dispatcher_switch_to_view(app->view_dispatcher, BtSettingsAppViewSubmenu); | ||||
| } | ||||
| 
 | ||||
| bool bt_settings_scene_start_on_event(void* context, SceneManagerEvent event) { | ||||
|     BtSettingsApp* app = context; | ||||
|     bool consumed = false; | ||||
| 
 | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         if(event.event == BtSettingsAppStartSubmenuIndexEnable) { | ||||
|             if(!app->settings.enabled) { | ||||
|                 app->settings.enabled = true; | ||||
|                 furi_hal_bt_start_app(); | ||||
|                 submenu_clean(app->submenu); | ||||
|                 submenu_add_item( | ||||
|                     app->submenu, | ||||
|                     "Disable", | ||||
|                     BtSettingsAppStartSubmenuIndexEnable, | ||||
|                     bt_settings_scene_start_submenu_callback, | ||||
|                     app); | ||||
|             } else { | ||||
|                 scene_manager_next_scene(app->scene_manager, BtSettingsAppSceneDisableDialog); | ||||
|             } | ||||
|             consumed = true; | ||||
|         } | ||||
|     } | ||||
|     return consumed; | ||||
| } | ||||
| 
 | ||||
| void bt_settings_scene_start_on_exit(void* context) { | ||||
|     BtSettingsApp* app = context; | ||||
|     submenu_clean(app->submenu); | ||||
| } | ||||
| @ -1,65 +0,0 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| typedef enum { | ||||
|     BtMessageTypeStartTestCarrier, | ||||
|     BtMessageTypeHoppingTx, | ||||
|     BtMessageTypeStopTestCarrier, | ||||
|     BtMessageTypeSetupTestPacketTx, | ||||
|     BtMessageTypeSetupTestPacketRx, | ||||
|     BtMessageTypeStartTestPacketTx, | ||||
|     BtMessageTypeStartTestPacketRx, | ||||
|     BtMessageTypeStopTestPacket, | ||||
|     BtMessageTypeStartApp, | ||||
|     BtMessageTypeUpdateStatusbar, | ||||
| } BtMessageType; | ||||
| 
 | ||||
| typedef enum { | ||||
|     BtStateReady, | ||||
|     BtStateCarrierTx, | ||||
|     BtStateHoppingTx, | ||||
|     BtStateCarrierRxStart, | ||||
|     BtStateCarrierRxRunning, | ||||
|     BtStatePacketSetup, | ||||
|     BtStatePacketStart, | ||||
|     BtStatePacketRunning, | ||||
|     BtStateStartedApp, | ||||
| } BtStateType; | ||||
| 
 | ||||
| typedef enum { | ||||
|     BtChannel2402 = 0, | ||||
|     BtChannel2440 = 19, | ||||
|     BtChannel2480 = 39, | ||||
| } BtTestChannel; | ||||
| 
 | ||||
| typedef enum { | ||||
|     BtPower0dB = 0x19, | ||||
|     BtPower2dB = 0x1B, | ||||
|     BtPower4dB = 0x1D, | ||||
|     BtPower6dB = 0x1F, | ||||
| } BtTestPower; | ||||
| 
 | ||||
| typedef enum { | ||||
|     BtDataRate1M = 1, | ||||
|     BtDataRate2M = 2, | ||||
| } BtTestDataRate; | ||||
| 
 | ||||
| typedef struct { | ||||
|     BtTestChannel channel; | ||||
|     BtTestPower power; | ||||
|     BtTestDataRate datarate; | ||||
|     float rssi; | ||||
|     uint16_t packets_sent; | ||||
|     uint16_t packets_received; | ||||
| } BtTestParam; | ||||
| 
 | ||||
| typedef struct { | ||||
|     BtMessageType type; | ||||
|     BtTestParam param; | ||||
| } BtMessage; | ||||
| 
 | ||||
| typedef struct { | ||||
|     BtStateType type; | ||||
|     BtTestParam param; | ||||
| } BtState; | ||||
| @ -1,250 +0,0 @@ | ||||
| #include "bt_views.h" | ||||
| 
 | ||||
| void bt_view_test_carrier_draw(Canvas* canvas, void* model) { | ||||
|     BtViewTestCarrierModel* m = model; | ||||
|     canvas_clear(canvas); | ||||
|     canvas_set_font(canvas, FontSecondary); | ||||
|     canvas_draw_str(canvas, 0, 12, "Performing Carrier test"); | ||||
|     if(m->type == BtStateCarrierTx) { | ||||
|         canvas_draw_str(canvas, 0, 24, "Manual Carrier TX"); | ||||
|     } else if(m->type == BtStateHoppingTx) { | ||||
|         canvas_draw_str(canvas, 0, 24, "Carrier TX Hopping mode"); | ||||
|     } else if(m->type == BtStateCarrierRxRunning) { | ||||
|         canvas_draw_str(canvas, 0, 24, "Manual Carrier RX"); | ||||
|     } | ||||
|     char buffer[32]; | ||||
|     snprintf(buffer, sizeof(buffer), "Channel:%d MHz", m->channel * 2 + 2402); | ||||
|     canvas_draw_str(canvas, 0, 36, buffer); | ||||
|     if(m->type == BtStateCarrierTx || m->type == BtStateHoppingTx) { | ||||
|         snprintf(buffer, sizeof(buffer), "Power:%d dB", m->power - BtPower0dB); | ||||
|     } else if(m->type == BtStateCarrierRxRunning) { | ||||
|         snprintf(buffer, sizeof(buffer), "RSSI: %3.1f dB", m->rssi); | ||||
|     } | ||||
|     canvas_draw_str(canvas, 0, 48, buffer); | ||||
| } | ||||
| 
 | ||||
| void bt_view_test_packet_rx_draw(Canvas* canvas, void* model) { | ||||
|     BtViewTestPacketRxModel* m = model; | ||||
|     canvas_clear(canvas); | ||||
|     canvas_set_font(canvas, FontSecondary); | ||||
|     canvas_draw_str(canvas, 0, 12, "Performing packets RX test"); | ||||
|     if(m->type == BtStatePacketSetup) { | ||||
|         canvas_draw_str(canvas, 0, 24, "Setup parameters. Ok to start"); | ||||
|     } else { | ||||
|         canvas_draw_str(canvas, 0, 24, "Receiving packets ..."); | ||||
|     } | ||||
|     char buffer[32]; | ||||
|     snprintf(buffer, sizeof(buffer), "Channel:%d MHz", m->channel * 2 + 2402); | ||||
|     canvas_draw_str(canvas, 0, 36, buffer); | ||||
|     snprintf(buffer, sizeof(buffer), "Datarate:%d Mbps", m->datarate); | ||||
|     canvas_draw_str(canvas, 0, 48, buffer); | ||||
|     if(m->type == BtStatePacketSetup) { | ||||
|         snprintf(buffer, sizeof(buffer), "%d packets received", m->packets_received); | ||||
|     } else { | ||||
|         snprintf(buffer, sizeof(buffer), "RSSI: %3.1f dB", m->rssi); | ||||
|     } | ||||
|     canvas_draw_str(canvas, 0, 60, buffer); | ||||
| } | ||||
| 
 | ||||
| void bt_view_test_packet_tx_draw(Canvas* canvas, void* model) { | ||||
|     BtViewTestPacketTxModel* m = model; | ||||
|     canvas_clear(canvas); | ||||
|     canvas_set_font(canvas, FontSecondary); | ||||
|     canvas_draw_str(canvas, 0, 12, "Packets send TX test"); | ||||
|     if(m->type == BtStatePacketSetup) { | ||||
|         canvas_draw_str(canvas, 0, 24, "Setup parameters. Ok to start"); | ||||
|     } else { | ||||
|         canvas_draw_str(canvas, 0, 24, "Sending packets ..."); | ||||
|     } | ||||
|     char buffer[32]; | ||||
|     snprintf(buffer, sizeof(buffer), "Channel:%d MHz", m->channel * 2 + 2402); | ||||
|     canvas_draw_str(canvas, 0, 36, buffer); | ||||
|     snprintf(buffer, sizeof(buffer), "Datarate:%d Mbps", m->datarate); | ||||
|     canvas_draw_str(canvas, 0, 48, buffer); | ||||
|     if(m->packets_sent && m->type == BtStatePacketSetup) { | ||||
|         snprintf(buffer, sizeof(buffer), "%d packets sent", m->packets_sent); | ||||
|         canvas_draw_str(canvas, 0, 60, buffer); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void bt_view_app_draw(Canvas* canvas, void* model) { | ||||
|     canvas_clear(canvas); | ||||
|     canvas_set_font(canvas, FontSecondary); | ||||
|     canvas_draw_str(canvas, 0, 12, "Start BLE app"); | ||||
| } | ||||
| 
 | ||||
| BtTestChannel bt_switch_channel(InputKey key, BtTestChannel inst_chan) { | ||||
|     uint8_t pos = 0; | ||||
|     BtTestChannel arr[] = {BtChannel2402, BtChannel2440, BtChannel2480}; | ||||
|     for(pos = 0; pos < sizeof(arr); pos++) { | ||||
|         if(arr[pos] == inst_chan) { | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|     if(key == InputKeyRight) { | ||||
|         pos = (pos + 1) % sizeof(arr); | ||||
|         return arr[pos]; | ||||
|     } else if(key == InputKeyLeft) { | ||||
|         if(pos) { | ||||
|             return arr[pos - 1]; | ||||
|         } else { | ||||
|             return arr[sizeof(arr) - 1]; | ||||
|         } | ||||
|     } | ||||
|     return arr[0]; | ||||
| } | ||||
| 
 | ||||
| bool bt_view_test_carrier_input(InputEvent* event, void* context) { | ||||
|     furi_assert(event); | ||||
|     furi_assert(context); | ||||
|     Bt* bt = context; | ||||
|     if(event->type == InputTypeShort) { | ||||
|         if(event->key == InputKeyBack) { | ||||
|             if(osTimerIsRunning(bt->update_param_timer)) { | ||||
|                 osTimerStop(bt->update_param_timer); | ||||
|             } | ||||
|             BtMessage m = {.type = BtMessageTypeStopTestCarrier}; | ||||
|             furi_check(osMessageQueuePut(bt->message_queue, &m, 0, osWaitForever) == osOK); | ||||
|             view_dispatcher_switch_to_view(bt->view_dispatcher, VIEW_NONE); | ||||
|             return true; | ||||
|         } else { | ||||
|             if(event->key == InputKeyRight || event->key == InputKeyLeft) { | ||||
|                 bt->state.param.channel = bt_switch_channel(event->key, bt->state.param.channel); | ||||
|             } else if(event->key == InputKeyUp) { | ||||
|                 if(bt->state.param.power < BtPower6dB) { | ||||
|                     bt->state.param.power += 2; | ||||
|                 } | ||||
|             } else if(event->key == InputKeyDown) { | ||||
|                 if(bt->state.param.power > BtPower0dB) { | ||||
|                     bt->state.param.power -= 2; | ||||
|                 } | ||||
|             } else if(event->key == InputKeyOk) { | ||||
|                 if(bt->state.type == BtStateCarrierTx) { | ||||
|                     bt->state.type = BtStateHoppingTx; | ||||
|                     osTimerStart(bt->update_param_timer, 2000); | ||||
|                 } else if(bt->state.type == BtStateHoppingTx) { | ||||
|                     osTimerStop(bt->update_param_timer); | ||||
|                     bt->state.type = BtStateCarrierRxStart; | ||||
|                     osTimerStart(bt->update_param_timer, 200); | ||||
|                 } else { | ||||
|                     osTimerStop(bt->update_param_timer); | ||||
|                     bt->state.type = BtStateCarrierTx; | ||||
|                 } | ||||
|             } | ||||
|             BtMessage m = { | ||||
|                 .type = BtMessageTypeStartTestCarrier, | ||||
|                 .param.channel = bt->state.param.channel, | ||||
|                 .param.power = bt->state.param.power}; | ||||
|             furi_check(osMessageQueuePut(bt->message_queue, &m, 0, osWaitForever) == osOK); | ||||
|             return true; | ||||
|         } | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| bool bt_view_test_packet_tx_input(InputEvent* event, void* context) { | ||||
|     furi_assert(event); | ||||
|     furi_assert(context); | ||||
|     Bt* bt = context; | ||||
|     if(event->type == InputTypeShort) { | ||||
|         if(event->key < InputKeyOk) { | ||||
|             // Process InputKeyUp, InputKeyDown, InputKeyLeft, InputKeyRight
 | ||||
|             if(event->key == InputKeyRight || event->key == InputKeyLeft) { | ||||
|                 bt->state.param.channel = bt_switch_channel(event->key, bt->state.param.channel); | ||||
|             } else if(event->key == InputKeyUp) { | ||||
|                 if(bt->state.param.datarate < BtDataRate2M) { | ||||
|                     bt->state.param.datarate += 1; | ||||
|                 } | ||||
|             } else if(event->key == InputKeyDown) { | ||||
|                 if(bt->state.param.datarate > BtDataRate1M) { | ||||
|                     bt->state.param.datarate -= 1; | ||||
|                 } | ||||
|             } | ||||
|             bt->state.type = BtStatePacketSetup; | ||||
|             BtMessage m = { | ||||
|                 .type = BtMessageTypeSetupTestPacketTx, | ||||
|                 .param.channel = bt->state.param.channel, | ||||
|                 .param.datarate = bt->state.param.datarate, | ||||
|             }; | ||||
|             furi_check(osMessageQueuePut(bt->message_queue, &m, 0, osWaitForever) == osOK); | ||||
|             return true; | ||||
|         } else if(event->key == InputKeyOk) { | ||||
|             if(bt->state.type == BtStatePacketSetup) { | ||||
|                 bt->state.type = BtStatePacketStart; | ||||
|             } else if(bt->state.type == BtStatePacketStart) { | ||||
|                 bt->state.type = BtStatePacketSetup; | ||||
|             } | ||||
|             BtMessage m = { | ||||
|                 .type = BtMessageTypeStartTestPacketTx, | ||||
|                 .param.channel = bt->state.param.channel, | ||||
|                 .param.datarate = bt->state.param.datarate, | ||||
|             }; | ||||
|             furi_check(osMessageQueuePut(bt->message_queue, &m, 0, osWaitForever) == osOK); | ||||
|             return true; | ||||
|         } else if(event->key == InputKeyBack) { | ||||
|             BtMessage m = { | ||||
|                 .type = BtMessageTypeStopTestPacket, | ||||
|             }; | ||||
|             furi_check(osMessageQueuePut(bt->message_queue, &m, 0, osWaitForever) == osOK); | ||||
|             view_dispatcher_switch_to_view(bt->view_dispatcher, VIEW_NONE); | ||||
|             return true; | ||||
|         } | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| bool bt_view_test_packet_rx_input(InputEvent* event, void* context) { | ||||
|     furi_assert(event); | ||||
|     furi_assert(context); | ||||
|     Bt* bt = context; | ||||
|     if(event->type == InputTypeShort) { | ||||
|         if(event->key < InputKeyOk) { | ||||
|             // Process InputKeyUp, InputKeyDown, InputKeyLeft, InputKeyRight
 | ||||
|             if(event->key == InputKeyRight || event->key == InputKeyLeft) { | ||||
|                 bt->state.param.channel = bt_switch_channel(event->key, bt->state.param.channel); | ||||
|             } else if(event->key == InputKeyUp) { | ||||
|                 if(bt->state.param.datarate < BtDataRate2M) { | ||||
|                     bt->state.param.datarate += 1; | ||||
|                 } | ||||
|             } else if(event->key == InputKeyDown) { | ||||
|                 if(bt->state.param.datarate > BtDataRate1M) { | ||||
|                     bt->state.param.datarate -= 1; | ||||
|                 } | ||||
|             } | ||||
|             bt->state.type = BtStatePacketSetup; | ||||
|             BtMessage m = { | ||||
|                 .type = BtMessageTypeSetupTestPacketRx, | ||||
|                 .param.channel = bt->state.param.channel, | ||||
|                 .param.datarate = bt->state.param.datarate, | ||||
|             }; | ||||
|             furi_check(osMessageQueuePut(bt->message_queue, &m, 0, osWaitForever) == osOK); | ||||
|             return true; | ||||
|         } else if(event->key == InputKeyOk) { | ||||
|             if(bt->state.type == BtStatePacketSetup) { | ||||
|                 bt->state.type = BtStatePacketStart; | ||||
|                 osTimerStart(bt->update_param_timer, 200); | ||||
|             } else if(bt->state.type == BtStatePacketRunning) { | ||||
|                 bt->state.type = BtStatePacketSetup; | ||||
|                 osTimerStop(bt->update_param_timer); | ||||
|             } | ||||
|             BtMessage m = { | ||||
|                 .type = BtMessageTypeStartTestPacketRx, | ||||
|                 .param.channel = bt->state.param.channel, | ||||
|                 .param.datarate = bt->state.param.datarate, | ||||
|             }; | ||||
|             furi_check(osMessageQueuePut(bt->message_queue, &m, 0, osWaitForever) == osOK); | ||||
|             return true; | ||||
|         } else if(event->key == InputKeyBack) { | ||||
|             if(osTimerIsRunning(bt->update_param_timer)) { | ||||
|                 osTimerStop(bt->update_param_timer); | ||||
|             } | ||||
|             BtMessage m = { | ||||
|                 .type = BtMessageTypeStopTestPacket, | ||||
|             }; | ||||
|             furi_check(osMessageQueuePut(bt->message_queue, &m, 0, osWaitForever) == osOK); | ||||
|             view_dispatcher_switch_to_view(bt->view_dispatcher, VIEW_NONE); | ||||
|             return true; | ||||
|         } | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
| @ -1,54 +0,0 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include "bt_i.h" | ||||
| #include "bt_types.h" | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| #include <stdbool.h> | ||||
| #include <gui/canvas.h> | ||||
| #include <furi.h> | ||||
| #include <gui/view_dispatcher.h> | ||||
| #include <gui/view.h> | ||||
| 
 | ||||
| typedef enum { | ||||
|     BtViewTestCarrier, | ||||
|     BtViewTestPacketTx, | ||||
|     BtViewTestPacketRx, | ||||
|     BtViewStartApp, | ||||
| } BtView; | ||||
| 
 | ||||
| typedef struct { | ||||
|     BtStateType type; | ||||
|     BtTestChannel channel; | ||||
|     BtTestPower power; | ||||
|     float rssi; | ||||
| } BtViewTestCarrierModel; | ||||
| 
 | ||||
| typedef struct { | ||||
|     BtStateType type; | ||||
|     BtTestChannel channel; | ||||
|     BtTestDataRate datarate; | ||||
|     uint16_t packets_sent; | ||||
| } BtViewTestPacketTxModel; | ||||
| 
 | ||||
| typedef struct { | ||||
|     BtStateType type; | ||||
|     BtTestChannel channel; | ||||
|     BtTestDataRate datarate; | ||||
|     float rssi; | ||||
|     uint16_t packets_received; | ||||
| } BtViewTestPacketRxModel; | ||||
| 
 | ||||
| void bt_view_test_carrier_draw(Canvas* canvas, void* model); | ||||
| 
 | ||||
| bool bt_view_test_carrier_input(InputEvent* event, void* context); | ||||
| 
 | ||||
| void bt_view_test_packet_tx_draw(Canvas* canvas, void* model); | ||||
| 
 | ||||
| bool bt_view_test_packet_tx_input(InputEvent* event, void* context); | ||||
| 
 | ||||
| void bt_view_test_packet_rx_draw(Canvas* canvas, void* model); | ||||
| 
 | ||||
| bool bt_view_test_packet_rx_input(InputEvent* event, void* context); | ||||
| 
 | ||||
| void bt_view_app_draw(Canvas* canvas, void* model); | ||||
| @ -332,12 +332,12 @@ void elements_string_fit_width(Canvas* canvas, string_t string, uint8_t width) { | ||||
|     furi_assert(string); | ||||
| 
 | ||||
|     uint16_t len_px = canvas_string_width(canvas, string_get_cstr(string)); | ||||
| 
 | ||||
|     if(len_px > width) { | ||||
|         size_t s_len = string_size(string); | ||||
|         uint8_t end_pos = s_len - ((len_px - width) / ((len_px / s_len) + 2) + 2); | ||||
| 
 | ||||
|         string_mid(string, 0, end_pos); | ||||
|         width -= canvas_string_width(canvas, "..."); | ||||
|         do { | ||||
|             string_left(string, string_size(string) - 1); | ||||
|             len_px = canvas_string_width(canvas, string_get_cstr(string)); | ||||
|         } while(len_px > width); | ||||
|         string_cat(string, "..."); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -78,13 +78,20 @@ static void button_menu_draw_common_button( | ||||
|     } else { | ||||
|         canvas_draw_rframe(canvas, item_x, item_y, ITEM_WIDTH, ITEM_HEIGHT, 5); | ||||
|     } | ||||
| 
 | ||||
|     string_t disp_str; | ||||
|     string_init_set_str(disp_str, text); | ||||
|     elements_string_fit_width(canvas, disp_str, ITEM_WIDTH - 6); | ||||
| 
 | ||||
|     canvas_draw_str_aligned( | ||||
|         canvas, | ||||
|         item_x + (ITEM_WIDTH / 2), | ||||
|         item_y + (ITEM_HEIGHT / 2), | ||||
|         AlignCenter, | ||||
|         AlignCenter, | ||||
|         text); | ||||
|         string_get_cstr(disp_str)); | ||||
| 
 | ||||
|     string_clear(disp_str); | ||||
| } | ||||
| 
 | ||||
| static void button_menu_view_draw_callback(Canvas* canvas, void* _model) { | ||||
| @ -110,7 +117,11 @@ static void button_menu_view_draw_callback(Canvas* canvas, void* _model) { | ||||
|         canvas_draw_icon(canvas, 28, 123, &I_IrdaArrowDown_4x8); | ||||
|     } | ||||
| 
 | ||||
|     canvas_draw_str_aligned(canvas, 32, 10, AlignCenter, AlignCenter, model->header); | ||||
|     string_t disp_str; | ||||
|     string_init_set_str(disp_str, model->header); | ||||
|     elements_string_fit_width(canvas, disp_str, ITEM_WIDTH - 6); | ||||
|     canvas_draw_str_aligned(canvas, 32, 10, AlignCenter, AlignCenter, string_get_cstr(disp_str)); | ||||
|     string_clear(disp_str); | ||||
| 
 | ||||
|     for(ButtonMenuItemArray_it(it, model->items); !ButtonMenuItemArray_end_p(it); | ||||
|         ButtonMenuItemArray_next(it), ++item_position) { | ||||
|  | ||||
							
								
								
									
										19
									
								
								applications/gui/modules/dialog_ex.c
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						| @ -243,3 +243,22 @@ void dialog_ex_set_right_button_text(DialogEx* dialog_ex, const char* text) { | ||||
|             return true; | ||||
|         }); | ||||
| } | ||||
| 
 | ||||
| void dialog_ex_clean(DialogEx* dialog_ex) { | ||||
|     furi_assert(dialog_ex); | ||||
|     TextElement clean_text_el = { | ||||
|         .text = NULL, .x = 0, .y = 0, .horizontal = AlignLeft, .vertical = AlignLeft}; | ||||
|     IconElement clean_icon_el = {.icon = NULL, .x = 0, .y = 0}; | ||||
|     with_view_model( | ||||
|         dialog_ex->view, (DialogExModel * model) { | ||||
|             model->header = clean_text_el; | ||||
|             model->text = clean_text_el; | ||||
|             model->icon = clean_icon_el; | ||||
|             model->left_text = NULL; | ||||
|             model->center_text = NULL; | ||||
|             model->right_text = NULL; | ||||
|             return true; | ||||
|         }); | ||||
|     dialog_ex->context = NULL; | ||||
|     dialog_ex->callback = NULL; | ||||
| } | ||||
|  | ||||
| @ -5,50 +5,51 @@ | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| /* Dialog anonymous structure */ | ||||
| /** Dialog anonymous structure */ | ||||
| typedef struct DialogEx DialogEx; | ||||
| 
 | ||||
| /* DialogEx result */ | ||||
| /** DialogEx result */ | ||||
| typedef enum { | ||||
|     DialogExResultLeft, | ||||
|     DialogExResultCenter, | ||||
|     DialogExResultRight, | ||||
| } DialogExResult; | ||||
| 
 | ||||
| /* DialogEx result callback type
 | ||||
| /** DialogEx result callback type
 | ||||
|  * @warning comes from GUI thread | ||||
|  */ | ||||
| typedef void (*DialogExResultCallback)(DialogExResult result, void* context); | ||||
| 
 | ||||
| /* Allocate and initialize dialog
 | ||||
|  * This dialog used to ask simple questions like Yes/ | ||||
| /** Allocate and initialize dialog
 | ||||
|  * This dialog used to ask simple questions | ||||
|  * @return DialogEx instance | ||||
|  */ | ||||
| DialogEx* dialog_ex_alloc(); | ||||
| 
 | ||||
| /* Deinitialize and free dialog
 | ||||
| /** Deinitialize and free dialog
 | ||||
|  * @param dialog - DialogEx instance | ||||
|  */ | ||||
| void dialog_ex_free(DialogEx* dialog_ex); | ||||
| 
 | ||||
| /* Get dialog view
 | ||||
| /** Get dialog view
 | ||||
|  * @param dialog - DialogEx instance | ||||
|  * @return View instance that can be used for embedding | ||||
|  */ | ||||
| View* dialog_ex_get_view(DialogEx* dialog_ex); | ||||
| 
 | ||||
| /* Set dialog result callback
 | ||||
| /** Set dialog result callback
 | ||||
|  * @param dialog_ex - DialogEx instance | ||||
|  * @param callback - result callback function | ||||
|  */ | ||||
| void dialog_ex_set_result_callback(DialogEx* dialog_ex, DialogExResultCallback callback); | ||||
| 
 | ||||
| /* Set dialog context
 | ||||
| /** Set dialog context
 | ||||
|  * @param dialog_ex - DialogEx instance | ||||
|  * @param context - context pointer, will be passed to result callback | ||||
|  */ | ||||
| void dialog_ex_set_context(DialogEx* dialog_ex, void* context); | ||||
| 
 | ||||
| /* Set dialog header text
 | ||||
| /** Set dialog header text
 | ||||
|  * If text is null, dialog header will not be rendered | ||||
|  * @param dialog - DialogEx instance | ||||
|  * @param text - text to be shown, can be multiline | ||||
| @ -63,7 +64,7 @@ void dialog_ex_set_header( | ||||
|     Align horizontal, | ||||
|     Align vertical); | ||||
| 
 | ||||
| /* Set dialog text
 | ||||
| /** Set dialog text
 | ||||
|  * If text is null, dialog text will not be rendered | ||||
|  * @param dialog - DialogEx instance | ||||
|  * @param text - text to be shown, can be multiline | ||||
| @ -78,7 +79,7 @@ void dialog_ex_set_text( | ||||
|     Align horizontal, | ||||
|     Align vertical); | ||||
| 
 | ||||
| /* Set dialog icon
 | ||||
| /** Set dialog icon
 | ||||
|  * If x or y is negative, dialog icon will not be rendered | ||||
|  * @param dialog - DialogEx instance | ||||
|  * @param x, y - icon position | ||||
| @ -86,27 +87,32 @@ void dialog_ex_set_text( | ||||
|  */ | ||||
| void dialog_ex_set_icon(DialogEx* dialog_ex, uint8_t x, uint8_t y, const Icon* icon); | ||||
| 
 | ||||
| /* Set left button text
 | ||||
| /** Set left button text
 | ||||
|  * If text is null, left button will not be rendered and processed | ||||
|  * @param dialog - DialogEx instance | ||||
|  * @param text - text to be shown | ||||
|  */ | ||||
| void dialog_ex_set_left_button_text(DialogEx* dialog_ex, const char* text); | ||||
| 
 | ||||
| /* Set center button text
 | ||||
| /** Set center button text
 | ||||
|  * If text is null, center button will not be rendered and processed | ||||
|  * @param dialog - DialogEx instance | ||||
|  * @param text - text to be shown | ||||
|  */ | ||||
| void dialog_ex_set_center_button_text(DialogEx* dialog_ex, const char* text); | ||||
| 
 | ||||
| /* Set right button text
 | ||||
| /** Set right button text
 | ||||
|  * If text is null, right button will not be rendered and processed | ||||
|  * @param dialog - DialogEx instance | ||||
|  * @param text - text to be shown | ||||
|  */ | ||||
| void dialog_ex_set_right_button_text(DialogEx* dialog_ex, const char* text); | ||||
| 
 | ||||
| /** Clean dialog
 | ||||
|  * @param dialog_ex DialogEx instance | ||||
|  */ | ||||
| void dialog_ex_clean(DialogEx* dialog_ex); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| @ -65,11 +65,18 @@ static void submenu_view_draw_callback(Canvas* canvas, void* _model) { | ||||
|             } else { | ||||
|                 canvas_set_color(canvas, ColorBlack); | ||||
|             } | ||||
| 
 | ||||
|             string_t disp_str; | ||||
|             string_init_set_str(disp_str, SubmenuItemArray_cref(it)->label); | ||||
|             elements_string_fit_width(canvas, disp_str, item_width - 20); | ||||
| 
 | ||||
|             canvas_draw_str( | ||||
|                 canvas, | ||||
|                 6, | ||||
|                 y_offset + (item_position * item_height) + item_height - 4, | ||||
|                 SubmenuItemArray_cref(it)->label); | ||||
|                 string_get_cstr(disp_str)); | ||||
| 
 | ||||
|             string_clear(disp_str); | ||||
|         } | ||||
| 
 | ||||
|         position++; | ||||
|  | ||||
							
								
								
									
										11
									
								
								applications/ibutton/scene/ibutton-scene-add-value.cpp
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						| @ -8,14 +8,9 @@ void iButtonSceneAddValue::on_enter(iButtonApp* app) { | ||||
|     iButtonAppViewManager* view_manager = app->get_view_manager(); | ||||
|     ByteInput* byte_input = view_manager->get_byte_input(); | ||||
|     auto callback = cbc::obtain_connector(this, &iButtonSceneAddValue::byte_input_callback); | ||||
| 
 | ||||
|     memcpy(this->new_key_data, app->get_key()->get_data(), app->get_key()->get_type_data_size()); | ||||
|     byte_input_set_result_callback( | ||||
|         byte_input, | ||||
|         callback, | ||||
|         NULL, | ||||
|         app, | ||||
|         app->get_key()->get_data(), | ||||
|         app->get_key()->get_type_data_size()); | ||||
|         byte_input, callback, NULL, app, this->new_key_data, app->get_key()->get_type_data_size()); | ||||
|     byte_input_set_header_text(byte_input, "Enter the key"); | ||||
| 
 | ||||
|     view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewByteInput); | ||||
| @ -45,6 +40,6 @@ void iButtonSceneAddValue::byte_input_callback(void* context) { | ||||
|     iButtonEvent event; | ||||
| 
 | ||||
|     event.type = iButtonEvent::Type::EventTypeByteEditResult; | ||||
| 
 | ||||
|     memcpy(app->get_key()->get_data(), this->new_key_data, app->get_key()->get_type_data_size()); | ||||
|     app->get_view_manager()->send_event(&event); | ||||
| } | ||||
| @ -1,5 +1,6 @@ | ||||
| #pragma once | ||||
| #include "ibutton-scene-generic.h" | ||||
| #include "../ibutton-key.h" | ||||
| 
 | ||||
| class iButtonSceneAddValue : public iButtonScene { | ||||
| public: | ||||
| @ -9,4 +10,5 @@ public: | ||||
| 
 | ||||
| private: | ||||
|     void byte_input_callback(void* context); | ||||
|     uint8_t new_key_data[IBUTTON_KEY_DATA_SIZE] = {}; | ||||
| }; | ||||
| @ -47,8 +47,8 @@ class IrdaAppRemoteManager { | ||||
|     std::string make_remote_name(const std::string& full_name) const; | ||||
| 
 | ||||
| public: | ||||
|     static inline const uint32_t max_button_name_length = 31; | ||||
|     static inline const uint32_t max_remote_name_length = 31; | ||||
|     static inline const uint32_t max_button_name_length = 22; | ||||
|     static inline const uint32_t max_remote_name_length = 22; | ||||
|     bool add_remote_with_button(const char* button_name, const IrdaAppSignal& signal); | ||||
|     bool add_button(const char* button_name, const IrdaAppSignal& signal); | ||||
| 
 | ||||
|  | ||||
| @ -238,7 +238,7 @@ static void loader_build_menu() { | ||||
|     with_value_mutex( | ||||
|         loader_instance->menu_vm, (Menu * menu) { | ||||
|             MenuItem* menu_debug = | ||||
|                 menu_item_alloc_menu("Debug tools", icon_animation_alloc(&A_Settings_14)); | ||||
|                 menu_item_alloc_menu("Debug tools", icon_animation_alloc(&A_Debug_14)); | ||||
| 
 | ||||
|             for(size_t i = 0; i < FLIPPER_DEBUG_APPS_COUNT; i++) { | ||||
|                 // Add menu item
 | ||||
|  | ||||
| @ -35,6 +35,7 @@ struct Nfc { | ||||
|     NotificationApp* notifications; | ||||
|     SceneManager* scene_manager; | ||||
|     NfcDevice dev; | ||||
|     NfcDeviceCommonData dev_edit_data; | ||||
| 
 | ||||
|     char text_store[NFC_TEXT_STORE_SIZE + 1]; | ||||
|     string_t text_box_store; | ||||
|  | ||||
| @ -40,6 +40,9 @@ const bool nfc_scene_save_name_on_event(void* context, SceneManagerEvent event) | ||||
|             if(nfc->dev.dev_name) { | ||||
|                 nfc_device_delete(&nfc->dev); | ||||
|             } | ||||
|             if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetUid)) { | ||||
|                 nfc->dev.dev_data.nfc_data = nfc->dev_edit_data; | ||||
|             } | ||||
|             memcpy(&nfc->dev.dev_name, nfc->text_store, strlen(nfc->text_store)); | ||||
|             if(nfc_device_save(&nfc->dev, nfc->text_store)) { | ||||
|                 scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess); | ||||
|  | ||||
| @ -14,13 +14,14 @@ const void nfc_scene_set_uid_on_enter(void* context) { | ||||
|     // Setup view
 | ||||
|     ByteInput* byte_input = nfc->byte_input; | ||||
|     byte_input_set_header_text(byte_input, "Enter uid in hex"); | ||||
|     nfc->dev_edit_data = nfc->dev.dev_data.nfc_data; | ||||
|     byte_input_set_result_callback( | ||||
|         byte_input, | ||||
|         nfc_scene_set_uid_byte_input_callback, | ||||
|         NULL, | ||||
|         nfc, | ||||
|         nfc->dev.dev_data.nfc_data.uid, | ||||
|         nfc->dev.dev_data.nfc_data.uid_len); | ||||
|         nfc->dev_edit_data.uid, | ||||
|         nfc->dev_edit_data.uid_len); | ||||
|     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewByteInput); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -98,18 +98,6 @@ const uint8_t *_I_Flipper_young_80x60[] = {_I_Flipper_young_80x60_0}; | ||||
| const uint8_t _I_DolphinFirstStart3_57x48_0[] = {0x00,0x00,0x00,0x80,0xFF,0x07,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x04,0x00,0x00,0xF8,0x03,0x01,0x00,0x00,0x08,0x00,0x00,0x04,0xBC,0x00,0x00,0x00,0x10,0x00,0x00,0x02,0xC0,0x00,0x00,0x00,0x20,0x00,0x00,0x02,0x00,0x01,0x00,0x00,0x20,0x00,0x00,0x02,0x00,0x02,0x00,0x38,0x40,0x00,0x00,0x02,0x00,0x04,0x00,0x3E,0x40,0x00,0x00,0xF4,0x03,0x08,0x80,0x07,0x80,0x00,0x00,0x5C,0x0D,0x10,0xE0,0x01,0x80,0x00,0x00,0xA8,0x3A,0x20,0xE0,0x00,0x00,0x01,0x00,0x58,0x55,0x00,0xC0,0x01,0x00,0x01,0x00,0xB0,0xAA,0x00,0x80,0x07,0x00,0x01,0x00,0x60,0x55,0x01,0x00,0x1E,0x00,0x01,0x0E,0xC0,0xAA,0x02,0xE0,0x5C,0x00,0x01,0x11,0x80,0x55,0x05,0x00,0xA9,0x00,0x01,0x21,0x00,0xAB,0x0A,0x00,0x56,0x07,0x01,0x41,0x00,0x56,0x15,0x00,0xEC,0x08,0x01,0x81,0x00,0xBF,0x2A,0x00,0x34,0x08,0x01,0x01,0xF1,0xC0,0x57,0x00,0x0C,0x08,0x01,0x02,0x0A,0x00,0xBE,0x00,0x04,0x08,0x01,0x02,0x06,0x00,0x78,0x83,0x02,0x04,0x01,0x02,0x0C,0x00,0xF0,0x7F,0x01,0x04,0x01,0x02,0xF4,0x01,0xFE,0x81,0x00,0x04,0x01,0x04,0x08,0xFF,0x6B,0x40,0x00,0x02,0x01,0x04,0x88,0x55,0x1D,0x40,0x00,0x02,0x01,0x04,0x50,0xAA,0x06,0x20,0x00,0x02,0x01,0x04,0x30,0xD4,0x01,0x20,0x00,0x01,0x01,0x04,0x10,0x68,0x00,0x10,0x00,0x01,0x01,0x04,0x18,0x18,0x00,0x10,0x00,0x01,0x01,0x08,0x18,0x06,0x80,0x10,0x00,0x01,0x01,0x08,0xE8,0x01,0x60,0x08,0x80,0x00,0x01,0x08,0x08,0x00,0x18,0x08,0x80,0x00,0x00,0x08,0x10,0x00,0x06,0x08,0x80,0x00,0x00,0x08,0x60,0xE0,0x01,0x08,0x80,0x00,0x00,0x08,0x80,0x1F,0x00,0x08,0x80,0x00,0x00,0x08,0x80,0x04,0x00,0x04,0x00,0x01,0x00,0x08,0x80,0x04,0x00,0x04,0x00,0x01,0x00,0x10,0x00,0x03,0x00,0x04,0x00,0x01,0x00,0x10,0x00,0x03,0x00,0x04,0x00,0x01,0x00,0x10,0x00,0x01,0x00,0x04,0x00,0x02,0x00,0x10,0x00,0x01,0x00,0x04,0x00,0x02,0x00,0x10,0x80,0x00,0x00,0x04,0x00,0x02,0x00,0x10,0x80,0x00,0x00,0x04,0x00,0x06,0x00,}; | ||||
| const uint8_t *_I_DolphinFirstStart3_57x48[] = {_I_DolphinFirstStart3_57x48_0}; | ||||
| 
 | ||||
| const uint8_t _I_Scanning_123x52_0[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x07,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xAC,0x03,0x18,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x56,0x05,0x60,0x00,0x00,0x00,0x80,0x02,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x81,0x0A,0x80,0x00,0x00,0x00,0x80,0x02,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x80,0x00,0x15,0x00,0x01,0x00,0x00,0x40,0x02,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x40,0x00,0x38,0x00,0x02,0x00,0x00,0x40,0x02,0x00,0x00,0x00,0x00,0x82,0x00,0x00,0x20,0x00,0x74,0x00,0x04,0x00,0x00,0x40,0x82,0x01,0x00,0x00,0x00,0x41,0x00,0x00,0x20,0x00,0x68,0x00,0x04,0x00,0x00,0x20,0x82,0x02,0x06,0x00,0x00,0x21,0x00,0x00,0x10,0x00,0xD0,0xE0,0x0F,0x00,0x00,0x20,0x82,0x02,0x0A,0x0C,0x80,0x20,0x08,0x00,0x10,0x00,0xA0,0x1C,0x10,0x00,0x00,0x20,0x82,0x02,0x0A,0x14,0x80,0x10,0x04,0x00,0x08,0xE0,0xD3,0x03,0x10,0x00,0x00,0x10,0x82,0x02,0x0A,0x14,0x80,0x10,0x02,0x00,0x08,0x90,0xA7,0x40,0x24,0x00,0x00,0x10,0x82,0x02,0x0A,0x14,0x80,0x10,0x02,0x00,0x08,0xC8,0x7F,0x84,0x28,0x00,0x00,0x10,0x84,0x02,0x0A,0xFF,0x80,0x10,0x02,0x00,0x88,0x67,0x3E,0x88,0x28,0x00,0x00,0x10,0x84,0xFA,0xFF,0xFF,0x80,0x10,0x02,0x00,0x44,0x64,0x2E,0x88,0x28,0x00,0x00,0x10,0xFC,0xAF,0xFF,0x15,0x80,0x10,0x04,0x00,0x44,0xE4,0x2F,0x88,0x2A,0x00,0x00,0x18,0xD4,0xDF,0x1F,0x14,0x80,0x20,0x08,0x00,0x44,0xE4,0x2F,0x50,0xFF,0x00,0xFE,0x1F,0xEC,0x3F,0x0A,0x14,0x00,0x21,0x00,0x00,0x44,0xC4,0x2F,0xEA,0x00,0x01,0x01,0x1A,0xFC,0x02,0x0A,0x14,0x00,0x41,0x00,0x00,0x84,0x88,0x2F,0x1D,0x00,0x82,0x7D,0x1E,0x84,0x02,0x0A,0x18,0x00,0x82,0x00,0x00,0x86,0x1F,0xC6,0x06,0x00,0x84,0x7D,0x16,0x84,0x02,0x0A,0x00,0x00,0x02,0x00,0x00,0x46,0xF5,0xC3,0x01,0x00,0x44,0x01,0x22,0x84,0x02,0x0C,0x00,0x00,0x04,0x00,0x00,0x87,0x0A,0x7C,0x00,0x00,0x44,0x03,0x22,0x88,0x02,0x00,0x00,0x00,0x08,0x00,0x00,0x45,0x05,0x08,0x00,0x7E,0xA4,0x03,0x42,0x88,0x02,0x00,0x00,0x00,0x10,0x00,0x00,0x86,0x06,0x00,0xC0,0x81,0xA5,0x07,0x42,0x08,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x30,0x00,0xD2,0xFF,0x81,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x0C,0x00,0xD2,0x1F,0x80,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x80,0x00,0x03,0x00,0xD1,0x1F,0x00,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0xE1,0x00,0x80,0xE9,0x0F,0x00,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x1E,0x00,0xC0,0xE8,0x0F,0x00,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x70,0xEE,0x0F,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x3C,0xF9,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0xAA,0x9F,0xF0,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x40,0x55,0xFD,0x5F,0xF0,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x80,0xEA,0xFF,0x3F,0xE0,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x40,0xD5,0xFF,0x1F,0xE0,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x80,0xAA,0xFF,0x0F,0xE0,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x55,0x55,0x03,0xF0,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0xAA,0xAA,0x00,0xB0,0x0A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x54,0x75,0x00,0x58,0x0D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0xA8,0x0F,0x00,0xA8,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x7C,0x00,0x00,0x5C,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0xAE,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x00,0xD7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0A,0x00,0x00,0x00,0x80,0x7B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0xC0,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0xF0,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x55,0x00,0x00,0x00,0xFC,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xAA,0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,}; | ||||
| const uint8_t *_I_Scanning_123x52[] = {_I_Scanning_123x52_0}; | ||||
| 
 | ||||
| const uint8_t _I_Quest_7x8_0[] = {0x1E,0x33,0x33,0x30,0x18,0x0C,0x00,0x0C,}; | ||||
| const uint8_t *_I_Quest_7x8[] = {_I_Quest_7x8_0}; | ||||
| 
 | ||||
| const uint8_t _I_Unlock_7x8_0[] = {0x1C,0x22,0x02,0x4F,0x67,0x73,0x79,0x3C,}; | ||||
| const uint8_t *_I_Unlock_7x8[] = {_I_Unlock_7x8_0}; | ||||
| 
 | ||||
| const uint8_t _I_Lock_7x8_0[] = {0x1C,0x22,0x22,0x7F,0x7F,0x77,0x7F,0x3E,}; | ||||
| const uint8_t *_I_Lock_7x8[] = {_I_Lock_7x8_0}; | ||||
| 
 | ||||
| const uint8_t _I_PassportBottom_128x17_0[] = {0x2C,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x8F,0x34,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x95,0x2C,0x00,0x00,0x00,0x00,0x00,0x00,0xA8,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0x9A,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x95,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0xA8,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0x9A,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x95,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0xA8,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0x9A,0xF2,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x8F,0xF9,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x0D,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x05,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x05,0xF2,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x3F,0x05,0xFA,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x1F,0x09,0x79,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0xD5,0x80,0x55,0xD5,0x00,0xF3,0xCC,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0x6A,0x00,0xAB,0x6A,0x00,0x06,0x86,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x3F,0x00,0xFE,0x3F,0x00,0xFC,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,}; | ||||
| const uint8_t *_I_PassportBottom_128x17[] = {_I_PassportBottom_128x17_0}; | ||||
| 
 | ||||
| @ -220,6 +208,12 @@ const uint8_t _A_Bluetooth_14_4[] = {0x10,0x00,0x30,0x00,0x51,0x00,0x92,0x00,0x9 | ||||
| const uint8_t _A_Bluetooth_14_5[] = {0x10,0x00,0x30,0x00,0x51,0x00,0x92,0x00,0x94,0x04,0x58,0x08,0x30,0x09,0x30,0x09,0x58,0x08,0x94,0x04,0x92,0x00,0x51,0x00,0x30,0x00,0x10,0x00,}; | ||||
| const uint8_t *_A_Bluetooth_14[] = {_A_Bluetooth_14_0,_A_Bluetooth_14_1,_A_Bluetooth_14_2,_A_Bluetooth_14_3,_A_Bluetooth_14_4,_A_Bluetooth_14_5}; | ||||
| 
 | ||||
| const uint8_t _A_Debug_14_0[] = {0x20,0x01,0xC1,0x20,0x22,0x11,0x24,0x09,0xD9,0x26,0x16,0x1A,0xD8,0x06,0xD8,0x06,0xD6,0x1A,0x19,0x26,0xE4,0x09,0xC2,0x10,0x01,0x20,0x00,0x00,}; | ||||
| const uint8_t _A_Debug_14_1[] = {0x20,0x01,0xC0,0x00,0x22,0x11,0x25,0x29,0xD8,0x06,0x16,0x1A,0xD9,0x26,0xD8,0x06,0xD4,0x0A,0x12,0x12,0xEA,0x15,0xC5,0x28,0x02,0x10,0x02,0x10,}; | ||||
| const uint8_t _A_Debug_14_2[] = {0x20,0x01,0xC0,0x00,0x20,0x01,0x24,0x09,0xDA,0x16,0x11,0x22,0xDC,0x0E,0xDA,0x16,0xD9,0x26,0x14,0x0A,0xF2,0x13,0xD1,0x22,0x08,0x04,0x06,0x18,}; | ||||
| const uint8_t _A_Debug_14_3[] = {0x22,0x11,0xC4,0x08,0x24,0x09,0x25,0x29,0xD9,0x26,0x12,0x12,0xDC,0x0E,0xD8,0x06,0xD8,0x06,0x14,0x0A,0xF4,0x0B,0xD2,0x12,0x19,0x26,0x06,0x18,}; | ||||
| const uint8_t *_A_Debug_14[] = {_A_Debug_14_0,_A_Debug_14_1,_A_Debug_14_2,_A_Debug_14_3}; | ||||
| 
 | ||||
| const uint8_t _A_FileManager_14_0[] = {0xFC,0x07,0x04,0x04,0xF4,0x05,0x04,0x04,0xF7,0x05,0x05,0x04,0xF5,0x3F,0x15,0x20,0x0D,0x20,0x0D,0x10,0x05,0x10,0x05,0x08,0x03,0x08,0xFE,0x07,}; | ||||
| const uint8_t _A_FileManager_14_1[] = {0x00,0x00,0x00,0x00,0xFC,0x07,0x04,0x04,0xF7,0x05,0x05,0x04,0xF5,0x3F,0x15,0x20,0x0D,0x20,0x0D,0x10,0x05,0x10,0x05,0x08,0x03,0x08,0xFE,0x07,}; | ||||
| const uint8_t _A_FileManager_14_2[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x07,0x05,0x04,0xF5,0x3F,0x15,0x20,0x0D,0x20,0x0D,0x10,0x05,0x10,0x05,0x08,0x03,0x08,0xFE,0x07,}; | ||||
| @ -423,6 +417,18 @@ const uint8_t *_I_Bluetooth_5x8[] = {_I_Bluetooth_5x8_0}; | ||||
| const uint8_t _I_Background_128x11_0[] = {0xFE,0x01,0x00,0x00,0x00,0x00,0x00,0xE0,0xFF,0xFF,0xFF,0x0F,0x00,0x00,0x00,0x00,0x01,0x03,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x7D,0x06,0x00,0x00,0x00,0x00,0x00,0x18,0xFF,0xB7,0x55,0x31,0x00,0x00,0x00,0x00,0x81,0xFC,0xFF,0xFF,0xFF,0xFF,0xFF,0x8F,0x00,0x00,0x00,0xE2,0xFF,0xFF,0xFF,0x7F,0x3D,0x01,0x00,0x00,0x00,0x00,0x00,0x40,0xB6,0xEA,0xFF,0x04,0x00,0x00,0x00,0x80,0x41,0xFE,0xFF,0xFF,0xAA,0xFE,0xFF,0x3F,0x01,0x00,0x00,0xF9,0xFF,0xFF,0xFF,0xAB,0x9F,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xF8,0xFF,0x7F,0x02,0x00,0x00,0x00,0x80,0x3E,0xFF,0xFF,0xFF,0xFF,0x55,0xFD,0x7F,0xFC,0xFF,0xFF,0x6C,0xFF,0xFF,0xFF,0xB5,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x80,0x01,0x00,0x00,0x00,0x80,0xC0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x03,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x80,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x00,0xFE,0xFF,0xFF,0xFF,0x7F,}; | ||||
| const uint8_t *_I_Background_128x11[] = {_I_Background_128x11_0}; | ||||
| 
 | ||||
| const uint8_t _I_Scanning_123x52_0[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x07,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xAC,0x03,0x18,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x56,0x05,0x60,0x00,0x00,0x00,0x80,0x02,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x81,0x0A,0x80,0x00,0x00,0x00,0x80,0x02,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x80,0x00,0x15,0x00,0x01,0x00,0x00,0x40,0x02,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x40,0x00,0x38,0x00,0x02,0x00,0x00,0x40,0x02,0x00,0x00,0x00,0x00,0x82,0x00,0x00,0x20,0x00,0x74,0x00,0x04,0x00,0x00,0x40,0x82,0x01,0x00,0x00,0x00,0x41,0x00,0x00,0x20,0x00,0x68,0x00,0x04,0x00,0x00,0x20,0x82,0x02,0x06,0x00,0x00,0x21,0x00,0x00,0x10,0x00,0xD0,0xE0,0x0F,0x00,0x00,0x20,0x82,0x02,0x0A,0x0C,0x80,0x20,0x08,0x00,0x10,0x00,0xA0,0x1C,0x10,0x00,0x00,0x20,0x82,0x02,0x0A,0x14,0x80,0x10,0x04,0x00,0x08,0xE0,0xD3,0x03,0x10,0x00,0x00,0x10,0x82,0x02,0x0A,0x14,0x80,0x10,0x02,0x00,0x08,0x90,0xA7,0x40,0x24,0x00,0x00,0x10,0x82,0x02,0x0A,0x14,0x80,0x10,0x02,0x00,0x08,0xC8,0x7F,0x84,0x28,0x00,0x00,0x10,0x84,0x02,0x0A,0xFF,0x80,0x10,0x02,0x00,0x88,0x67,0x3E,0x88,0x28,0x00,0x00,0x10,0x84,0xFA,0xFF,0xFF,0x80,0x10,0x02,0x00,0x44,0x64,0x2E,0x88,0x28,0x00,0x00,0x10,0xFC,0xAF,0xFF,0x15,0x80,0x10,0x04,0x00,0x44,0xE4,0x2F,0x88,0x2A,0x00,0x00,0x18,0xD4,0xDF,0x1F,0x14,0x80,0x20,0x08,0x00,0x44,0xE4,0x2F,0x50,0xFF,0x00,0xFE,0x1F,0xEC,0x3F,0x0A,0x14,0x00,0x21,0x00,0x00,0x44,0xC4,0x2F,0xEA,0x00,0x01,0x01,0x1A,0xFC,0x02,0x0A,0x14,0x00,0x41,0x00,0x00,0x84,0x88,0x2F,0x1D,0x00,0x82,0x7D,0x1E,0x84,0x02,0x0A,0x18,0x00,0x82,0x00,0x00,0x86,0x1F,0xC6,0x06,0x00,0x84,0x7D,0x16,0x84,0x02,0x0A,0x00,0x00,0x02,0x00,0x00,0x46,0xF5,0xC3,0x01,0x00,0x44,0x01,0x22,0x84,0x02,0x0C,0x00,0x00,0x04,0x00,0x00,0x87,0x0A,0x7C,0x00,0x00,0x44,0x03,0x22,0x88,0x02,0x00,0x00,0x00,0x08,0x00,0x00,0x45,0x05,0x08,0x00,0x7E,0xA4,0x03,0x42,0x88,0x02,0x00,0x00,0x00,0x10,0x00,0x00,0x86,0x06,0x00,0xC0,0x81,0xA5,0x07,0x42,0x08,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x30,0x00,0xD2,0xFF,0x81,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x0C,0x00,0xD2,0x1F,0x80,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x80,0x00,0x03,0x00,0xD1,0x1F,0x00,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0xE1,0x00,0x80,0xE9,0x0F,0x00,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x1E,0x00,0xC0,0xE8,0x0F,0x00,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x70,0xEE,0x0F,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x3C,0xF9,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0xAA,0x9F,0xF0,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x40,0x55,0xFD,0x5F,0xF0,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x80,0xEA,0xFF,0x3F,0xE0,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x40,0xD5,0xFF,0x1F,0xE0,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x80,0xAA,0xFF,0x0F,0xE0,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x55,0x55,0x03,0xF0,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0xAA,0xAA,0x00,0xB0,0x0A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x54,0x75,0x00,0x58,0x0D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0xA8,0x0F,0x00,0xA8,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x7C,0x00,0x00,0x5C,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0xAE,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x00,0xD7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0A,0x00,0x00,0x00,0x80,0x7B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0xC0,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0xF0,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x55,0x00,0x00,0x00,0xFC,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xAA,0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,}; | ||||
| const uint8_t *_I_Scanning_123x52[] = {_I_Scanning_123x52_0}; | ||||
| 
 | ||||
| const uint8_t _I_Quest_7x8_0[] = {0x1E,0x33,0x33,0x30,0x18,0x0C,0x00,0x0C,}; | ||||
| const uint8_t *_I_Quest_7x8[] = {_I_Quest_7x8_0}; | ||||
| 
 | ||||
| const uint8_t _I_Unlock_7x8_0[] = {0x1C,0x22,0x02,0x4F,0x67,0x73,0x79,0x3C,}; | ||||
| const uint8_t *_I_Unlock_7x8[] = {_I_Unlock_7x8_0}; | ||||
| 
 | ||||
| const uint8_t _I_Lock_7x8_0[] = {0x1C,0x22,0x22,0x7F,0x7F,0x77,0x7F,0x3E,}; | ||||
| const uint8_t *_I_Lock_7x8[] = {_I_Lock_7x8_0}; | ||||
| 
 | ||||
| const uint8_t _I_DolphinMafia_115x62_0[] = {0x00,0x00,0x00,0x00,0x80,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x01,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2F,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x15,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xAF,0x0A,0x00,0x40,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x55,0x15,0x00,0x80,0xF0,0xFF,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xAA,0x0A,0x00,0x80,0xFF,0xFF,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x55,0x15,0x00,0xFF,0xFF,0xFF,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xAA,0x2A,0xE0,0xFF,0xFF,0xFF,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x55,0x55,0xFC,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xAA,0xAA,0xFF,0xFF,0xFF,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x55,0xD5,0xFF,0x7F,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xAA,0xFA,0xFF,0x2B,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x55,0xFD,0x7F,0x05,0xE8,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xAB,0xFE,0xAF,0x00,0xF1,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x55,0xFF,0x15,0xE0,0x37,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xEB,0xFF,0x0A,0xFC,0x7F,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF6,0x7F,0x81,0xFF,0xEF,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0xFA,0xAF,0xE0,0x3F,0xEE,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0xFE,0x57,0xF8,0x0F,0xCE,0xFF,0x0F,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0xFF,0x2B,0xFC,0x1F,0x07,0x00,0x30,0x00,0x00,0x00,0x00,0x80,0x02,0x00,0xC0,0xFF,0x15,0xFC,0xFF,0x07,0x00,0xC0,0x00,0x00,0x00,0x00,0x20,0x02,0x00,0xE0,0xBF,0x0A,0xFC,0xFF,0x03,0x00,0x00,0x01,0x00,0x00,0x00,0x18,0x01,0x00,0xF8,0x5F,0x05,0xF8,0xFF,0x03,0x00,0x00,0x02,0x00,0x00,0x60,0x86,0x00,0x00,0xFC,0xAF,0x02,0xFA,0xFF,0x01,0x00,0x00,0x02,0x00,0x30,0x1D,0x40,0x00,0x00,0xFF,0x57,0x01,0xF5,0x7F,0x00,0x00,0xC0,0x02,0x00,0x08,0x00,0x30,0x00,0x80,0xFF,0xAB,0x80,0xEA,0x1F,0x00,0x00,0xE0,0xFB,0x03,0x04,0x00,0x0E,0x00,0xC0,0xFF,0x57,0x00,0xF5,0x03,0x00,0x00,0xF8,0x02,0x00,0x04,0x60,0x01,0x00,0xE0,0xFF,0x2B,0x80,0x0A,0x04,0x00,0x00,0xC6,0xC2,0x0F,0x04,0x03,0x00,0x00,0xF0,0xFF,0x16,0x00,0x05,0x08,0x00,0x80,0x01,0x02,0x00,0xF0,0x00,0x00,0x00,0xF0,0x3F,0x0A,0x80,0x02,0x00,0x00,0x60,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0xE0,0x03,0x06,0x00,0x03,0x00,0x00,0x1C,0x00,0x01,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x0A,0x00,0x82,0x00,0x00,0x03,0x80,0x00,0x00,0x24,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x82,0x00,0xE0,0x00,0x40,0x00,0x00,0x22,0x00,0x00,0x00,0x00,0x00,0x0A,0x00,0x00,0x03,0x1E,0x00,0x30,0x00,0x00,0x22,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0xFC,0x01,0x00,0x0E,0x00,0x00,0x22,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0xC0,0x01,0x00,0x00,0x21,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0xE1,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0xF8,0x10,0x03,0x00,0x00,0x00,0x80,0x01,0x00,0x00,0x00,0xF0,0x04,0x00,0x00,0x04,0x10,0x04,0x00,0x00,0x00,0xE0,0x03,0x00,0x00,0x00,0x0F,0x04,0x00,0x00,0x04,0x10,0x08,0x00,0x00,0x00,0xB0,0x01,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x04,0x10,0x08,0x00,0x00,0x00,0xD8,0xFF,0xFF,0xFF,0x3F,0x00,0x28,0x00,0x00,0x08,0x10,0x08,0x00,0x00,0x00,0xEC,0x01,0x00,0x00,0xE0,0x1F,0x28,0x00,0x00,0x10,0x10,0x08,0x00,0x00,0x00,0xD6,0x02,0x00,0x00,0x00,0x30,0x50,0x00,0x00,0x10,0x10,0x04,0x00,0x00,0x00,0xEB,0x05,0x00,0x00,0x00,0x50,0x50,0x00,0x00,0x10,0x20,0x02,0x00,0x00,0x80,0xD4,0x0A,0x00,0x00,0x00,0x90,0x50,0x00,0x00,0x08,0xC0,0x01,0x00,0x00,0x40,0xEA,0x15,0x00,0x00,0x00,0x08,0x61,0x00,0x00,0x0C,0x00,0x01,0x00,0x00,0x20,0xF4,0xFF,0xFF,0x01,0x00,0x08,0x62,0x00,0x00,0x12,0x80,0x00,0x00,0x00,0x10,0xEA,0x15,0x00,0xFE,0x00,0x08,0xE4,0x01,0x00,0x21,0x80,0x00,0x00,0x00,0x10,0xF4,0x0A,0x00,0x00,0x0F,0x04,0xA8,0x06,0xC0,0xC0,0x40,0x00,0x00,0x00,0x08,0xE8,0x05,0x00,0x00,0x30,0x04,0x50,0x19,0x38,0x01,0x47,0x00,0x00,0x00,0x04,0xF4,0x02,0x00,0x00,0xC0,0x04,0xC0,0xE2,0x07,0x06,0x38,0x00,0x00,0x00,0x04,0xF8,0x05,0x00,0x00,0x00,0x03,0x40,0x01,0x00,0x18,0x20,0x00,0x00,0x00,0x02,0xF0,0x02,0x00,0x00,0x00,0x00,0x80,0x02,0x00,0x60,0x10,0x00,0x00,0x00,0x02,0xF8,0x01,0x00,0x00,0x00,0x00,0x80,0x05,0x00,0x80,0x11,0x00,0x00,0x00,0x01,0xF0,0x02,0x00,0x00,0x00,0x00,0x80,0x0A,0x00,0x00,0x0E,0x00,0x00,0x00,}; | ||||
| const uint8_t *_I_DolphinMafia_115x62[] = {_I_DolphinMafia_115x62_0}; | ||||
| 
 | ||||
| @ -472,10 +478,6 @@ const Icon I_DolphinFirstStart8_56x51 = {.width=56,.height=51,.frame_count=1,.fr | ||||
| const Icon I_DolphinFirstStart7_61x51 = {.width=61,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_DolphinFirstStart7_61x51}; | ||||
| const Icon I_Flipper_young_80x60 = {.width=80,.height=60,.frame_count=1,.frame_rate=0,.frames=_I_Flipper_young_80x60}; | ||||
| const Icon I_DolphinFirstStart3_57x48 = {.width=57,.height=48,.frame_count=1,.frame_rate=0,.frames=_I_DolphinFirstStart3_57x48}; | ||||
| const Icon I_Scanning_123x52 = {.width=123,.height=52,.frame_count=1,.frame_rate=0,.frames=_I_Scanning_123x52}; | ||||
| const Icon I_Quest_7x8 = {.width=7,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Quest_7x8}; | ||||
| const Icon I_Unlock_7x8 = {.width=7,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Unlock_7x8}; | ||||
| const Icon I_Lock_7x8 = {.width=7,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Lock_7x8}; | ||||
| const Icon I_PassportBottom_128x17 = {.width=128,.height=17,.frame_count=1,.frame_rate=0,.frames=_I_PassportBottom_128x17}; | ||||
| const Icon I_DoorLeft_8x56 = {.width=8,.height=56,.frame_count=1,.frame_rate=0,.frames=_I_DoorLeft_8x56}; | ||||
| const Icon I_DoorLocked_10x56 = {.width=10,.height=56,.frame_count=1,.frame_rate=0,.frames=_I_DoorLocked_10x56}; | ||||
| @ -510,6 +512,7 @@ const Icon I_KeySaveSelected_24x11 = {.width=24,.height=11,.frame_count=1,.frame | ||||
| const Icon I_KeyBackspace_16x9 = {.width=16,.height=9,.frame_count=1,.frame_rate=0,.frames=_I_KeyBackspace_16x9}; | ||||
| const Icon A_125khz_14 = {.width=14,.height=14,.frame_count=4,.frame_rate=3,.frames=_A_125khz_14}; | ||||
| const Icon A_Bluetooth_14 = {.width=14,.height=14,.frame_count=6,.frame_rate=3,.frames=_A_Bluetooth_14}; | ||||
| const Icon A_Debug_14 = {.width=14,.height=14,.frame_count=4,.frame_rate=3,.frames=_A_Debug_14}; | ||||
| const Icon A_FileManager_14 = {.width=14,.height=14,.frame_count=10,.frame_rate=3,.frames=_A_FileManager_14}; | ||||
| const Icon A_GPIO_14 = {.width=14,.height=14,.frame_count=8,.frame_rate=3,.frames=_A_GPIO_14}; | ||||
| const Icon A_Games_14 = {.width=14,.height=14,.frame_count=9,.frame_rate=3,.frames=_A_Games_14}; | ||||
| @ -552,6 +555,10 @@ const Icon I_SDcardFail_11x8 = {.width=11,.height=8,.frame_count=1,.frame_rate=0 | ||||
| const Icon I_USBConnected_15x8 = {.width=15,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_USBConnected_15x8}; | ||||
| const Icon I_Bluetooth_5x8 = {.width=5,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Bluetooth_5x8}; | ||||
| const Icon I_Background_128x11 = {.width=128,.height=11,.frame_count=1,.frame_rate=0,.frames=_I_Background_128x11}; | ||||
| const Icon I_Scanning_123x52 = {.width=123,.height=52,.frame_count=1,.frame_rate=0,.frames=_I_Scanning_123x52}; | ||||
| const Icon I_Quest_7x8 = {.width=7,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Quest_7x8}; | ||||
| const Icon I_Unlock_7x8 = {.width=7,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Unlock_7x8}; | ||||
| const Icon I_Lock_7x8 = {.width=7,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Lock_7x8}; | ||||
| const Icon I_DolphinMafia_115x62 = {.width=115,.height=62,.frame_count=1,.frame_rate=0,.frames=_I_DolphinMafia_115x62}; | ||||
| const Icon I_DolphinExcited_64x63 = {.width=64,.height=63,.frame_count=1,.frame_rate=0,.frames=_I_DolphinExcited_64x63}; | ||||
| const Icon I_iButtonDolphinSuccess_109x60 = {.width=109,.height=60,.frame_count=1,.frame_rate=0,.frames=_I_iButtonDolphinSuccess_109x60}; | ||||
|  | ||||
| @ -29,10 +29,6 @@ extern const Icon I_DolphinFirstStart8_56x51; | ||||
| extern const Icon I_DolphinFirstStart7_61x51; | ||||
| extern const Icon I_Flipper_young_80x60; | ||||
| extern const Icon I_DolphinFirstStart3_57x48; | ||||
| extern const Icon I_Scanning_123x52; | ||||
| extern const Icon I_Quest_7x8; | ||||
| extern const Icon I_Unlock_7x8; | ||||
| extern const Icon I_Lock_7x8; | ||||
| extern const Icon I_PassportBottom_128x17; | ||||
| extern const Icon I_DoorLeft_8x56; | ||||
| extern const Icon I_DoorLocked_10x56; | ||||
| @ -67,6 +63,7 @@ extern const Icon I_KeySaveSelected_24x11; | ||||
| extern const Icon I_KeyBackspace_16x9; | ||||
| extern const Icon A_125khz_14; | ||||
| extern const Icon A_Bluetooth_14; | ||||
| extern const Icon A_Debug_14; | ||||
| extern const Icon A_FileManager_14; | ||||
| extern const Icon A_GPIO_14; | ||||
| extern const Icon A_Games_14; | ||||
| @ -109,6 +106,10 @@ extern const Icon I_SDcardFail_11x8; | ||||
| extern const Icon I_USBConnected_15x8; | ||||
| extern const Icon I_Bluetooth_5x8; | ||||
| extern const Icon I_Background_128x11; | ||||
| extern const Icon I_Scanning_123x52; | ||||
| extern const Icon I_Quest_7x8; | ||||
| extern const Icon I_Unlock_7x8; | ||||
| extern const Icon I_Lock_7x8; | ||||
| extern const Icon I_DolphinMafia_115x62; | ||||
| extern const Icon I_DolphinExcited_64x63; | ||||
| extern const Icon I_iButtonDolphinSuccess_109x60; | ||||
|  | ||||
							
								
								
									
										
											BIN
										
									
								
								assets/icons/MainMenu/Debug_14/frame_01.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.6 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/MainMenu/Debug_14/frame_02.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.6 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/MainMenu/Debug_14/frame_03.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.6 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/MainMenu/Debug_14/frame_04.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.6 KiB | 
							
								
								
									
										1
									
								
								assets/icons/MainMenu/Debug_14/frame_rate
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1 @@ | ||||
| 3 | ||||
| Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB | 
| Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB | 
| Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB | 
| Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB | 
| @ -4,13 +4,17 @@ RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install --no-instal | ||||
|         ca-certificates \ | ||||
|         build-essential \ | ||||
|         python3 \ | ||||
|         python3-lxml \ | ||||
|         git \ | ||||
|         clang-format-12 \ | ||||
|         dfu-util \ | ||||
|         openocd \ | ||||
|         srecord \ | ||||
|         libncurses5 \ | ||||
|         python-setuptools \ | ||||
|         libpython2.7-dev \ | ||||
|         libxml2-dev \ | ||||
|         libxslt1-dev \ | ||||
|         zlib1g-dev \ | ||||
|         wget && \ | ||||
|     apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* | ||||
| 
 | ||||
| @ -22,6 +26,9 @@ RUN wget --progress=dot:giga "https://developer.arm.com/-/media/Files/downloads/ | ||||
|     for file in * ; do ln -s "${PWD}/${file}" "/usr/bin/${file}" ; done && \ | ||||
|     cd / && arm-none-eabi-gcc -v && arm-none-eabi-gdb -v | ||||
| 
 | ||||
| RUN wget --progress=dot:giga -O - https://bootstrap.pypa.io/pip/2.7/get-pip.py | python2 && \ | ||||
|     pip install --no-cache-dir lxml==4.6.3 | ||||
| 
 | ||||
| RUN git clone https://github.com/rusdacent/hex2dfu.git && \ | ||||
|     cd hex2dfu && gcc hex2dfu.c ED25519/*.c -o hex2dfu && mv ./hex2dfu /usr/local/bin/hex2dfu  && \ | ||||
|     hex2dfu -h | ||||
|  | ||||
| @ -1,13 +1,5 @@ | ||||
| #!/bin/bash | ||||
| 
 | ||||
| # A hack for GitHub Actions to not install Rust twice | ||||
| if [ "$HOME" != "/root" ]; then | ||||
|     ln -sf /root/.rustup "$HOME/.rustup" | ||||
|     ln -sf /root/.cargo "$HOME/.cargo" | ||||
| fi | ||||
| 
 | ||||
| PATH="$HOME/.cargo/bin:${PATH}" | ||||
| 
 | ||||
| if [ -z "$1" ]; then | ||||
|     bash | ||||
| else | ||||
|  | ||||
| @ -43,7 +43,7 @@ bool furi_hal_bt_is_alive() { | ||||
|     return APPE_Status() == BleGlueStatusStarted; | ||||
| } | ||||
| 
 | ||||
| bool furi_hal_bt_wait_transition() { | ||||
| bool furi_hal_bt_wait_startup() { | ||||
|     uint8_t counter = 0; | ||||
|     while (APPE_Status() == BleGlueStatusStartup) { | ||||
|         osDelay(10); | ||||
| @ -56,7 +56,7 @@ bool furi_hal_bt_wait_transition() { | ||||
| } | ||||
| 
 | ||||
| bool furi_hal_bt_lock_flash() { | ||||
|     if (!furi_hal_bt_wait_transition()) { | ||||
|     if (!furi_hal_bt_wait_startup()) { | ||||
|         return false; | ||||
|     } | ||||
|     if (APPE_Status() == BleGlueStatusUninitialized) { | ||||
| @ -100,7 +100,7 @@ void furi_hal_bt_start_packet_rx(uint8_t channel, uint8_t datarate) { | ||||
| } | ||||
| 
 | ||||
| uint16_t furi_hal_bt_stop_packet_test() { | ||||
|     uint16_t num_of_packets; | ||||
|     uint16_t num_of_packets = 0; | ||||
|     hci_le_test_end(&num_of_packets); | ||||
|     return num_of_packets; | ||||
| } | ||||
|  | ||||
| @ -151,6 +151,7 @@ void hal_gpio_add_int_callback(const GpioPin* gpio, GpioExtiCallback cb, void* c | ||||
| 
 | ||||
|     __disable_irq(); | ||||
|     uint8_t pin_num = hal_gpio_get_pin_num(gpio); | ||||
|     furi_assert(gpio_interrupt[pin_num].callback == NULL); | ||||
|     gpio_interrupt[pin_num].callback = cb; | ||||
|     gpio_interrupt[pin_num].context = ctx; | ||||
|     gpio_interrupt[pin_num].ready = true; | ||||
|  | ||||
| @ -19,6 +19,9 @@ void furi_hal_bt_dump_state(string_t buffer); | ||||
| /** Get BT/BLE system component state */ | ||||
| bool furi_hal_bt_is_alive(); | ||||
| 
 | ||||
| /** Wait for Core2 startup */ | ||||
| bool furi_hal_bt_wait_startup(); | ||||
| 
 | ||||
| /**
 | ||||
|  * Lock shared access to flash controller | ||||
|  * @return true if lock was successful, false if not | ||||
|  | ||||
 Aleksandr Kutuzov
						Aleksandr Kutuzov