[FL-1720] BLE GUI refactoring (#678)
* dialog_ex: add clean method, fix documentation * application: add bt debug and settings application * bt: add debug application * bt: add settings application * bt: rework bt service * bt debug: fix carrier debug app * assets: add debug animation to main menu * bt debug: fix bt packet test * bt service: rework bt service * bt: cleanup * Assets: fix spelling * Ble: wait for core 2 startup complete before initializing radio stack. * Accessor: remove dead code, switch port PA6 to PA4, because interrupt line 6 is used by down button. * FuriHal: assert interrupt line on add_int_callback. * Bt: update icon on core2 startup complete. Co-authored-by: あく <alleteam@gmail.com>
| @ -109,16 +109,6 @@ void AccessorApp::notify_green_blink() { | |||||||
| 
 | 
 | ||||||
| void AccessorApp::notify_success() { | void AccessorApp::notify_success() { | ||||||
|     notification_message(notification, &sequence_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 *****************************/ | /*************************** TEXT STORE *****************************/ | ||||||
|  | |||||||
| @ -11,6 +11,8 @@ volatile int WIEGAND::_bitCount = 0; | |||||||
| int WIEGAND::_wiegandType = 0; | int WIEGAND::_wiegandType = 0; | ||||||
| 
 | 
 | ||||||
| constexpr uint32_t clocks_in_ms = 64 * 1000; | constexpr uint32_t clocks_in_ms = 64 * 1000; | ||||||
|  | const GpioPin* pinD0 = &gpio_ext_pa4; | ||||||
|  | const GpioPin* pinD1 = &gpio_ext_pa7; | ||||||
| 
 | 
 | ||||||
| WIEGAND::WIEGAND() { | WIEGAND::WIEGAND() { | ||||||
| } | } | ||||||
| @ -53,9 +55,6 @@ void WIEGAND::begin() { | |||||||
|     _wiegandType = 0; |     _wiegandType = 0; | ||||||
|     _bitCount = 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(pinD0, GpioModeInterruptFall); // Set D0 pin as input
 | ||||||
|     hal_gpio_init_simple(pinD1, GpioModeInterruptFall); // Set D1 pin as input
 |     hal_gpio_init_simple(pinD1, GpioModeInterruptFall); // Set D1 pin as input
 | ||||||
| 
 | 
 | ||||||
| @ -64,11 +63,11 @@ void WIEGAND::begin() { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void WIEGAND::end() { | void WIEGAND::end() { | ||||||
|     hal_gpio_remove_int_callback(&gpio_ext_pa6); |     hal_gpio_remove_int_callback(pinD0); | ||||||
|     hal_gpio_remove_int_callback(&gpio_ext_pa7); |     hal_gpio_remove_int_callback(pinD1); | ||||||
| 
 | 
 | ||||||
|     hal_gpio_init_simple(&gpio_ext_pa6, GpioModeAnalog); |     hal_gpio_init_simple(pinD0, GpioModeAnalog); | ||||||
|     hal_gpio_init_simple(&gpio_ext_pa7, GpioModeAnalog); |     hal_gpio_init_simple(pinD1, GpioModeAnalog); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void WIEGAND::ReadD0() { | 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 storage_test_app(void* p); | ||||||
| extern int32_t subghz_app(void* p); | extern int32_t subghz_app(void* p); | ||||||
| extern int32_t vibro_test_app(void* p); | extern int32_t vibro_test_app(void* p); | ||||||
|  | extern int32_t bt_debug_app(void* p); | ||||||
| 
 | 
 | ||||||
| // Plugins
 | // Plugins
 | ||||||
| extern int32_t music_player_app(void* p); | extern int32_t music_player_app(void* p); | ||||||
| @ -48,6 +49,7 @@ extern void subghz_cli_init(); | |||||||
| // Settings
 | // Settings
 | ||||||
| extern int32_t notification_settings_app(void* p); | extern int32_t notification_settings_app(void* p); | ||||||
| extern int32_t storage_settings_app(void* p); | extern int32_t storage_settings_app(void* p); | ||||||
|  | extern int32_t bt_settings_app(void* p); | ||||||
| 
 | 
 | ||||||
| const FlipperApplication FLIPPER_SERVICES[] = { | const FlipperApplication FLIPPER_SERVICES[] = { | ||||||
| /* Services */ | /* Services */ | ||||||
| @ -236,6 +238,10 @@ const FlipperApplication FLIPPER_DEBUG_APPS[] = { | |||||||
| #ifdef APP_LF_RFID | #ifdef APP_LF_RFID | ||||||
|     {.app = lfrfid_debug_app, .name = "LF-RFID Debug", .stack_size = 1024, .icon = &A_125khz_14}, |     {.app = lfrfid_debug_app, .name = "LF-RFID Debug", .stack_size = 1024, .icon = &A_125khz_14}, | ||||||
| #endif | #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); | 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 | #ifdef SRV_STORAGE | ||||||
|     {.app = storage_settings_app, .name = "Storage", .stack_size = 2048, .icon = NULL}, |     {.app = storage_settings_app, .name = "Storage", .stack_size = 2048, .icon = NULL}, | ||||||
| #endif | #endif | ||||||
|  | 
 | ||||||
|  | #ifdef SRV_BT | ||||||
|  |     {.app = bt_settings_app, .name = "Bluetooth", .stack_size = 1024, .icon = NULL}, | ||||||
|  | #endif | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| const size_t FLIPPER_SETTINGS_APPS_COUNT = | 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(bt->bt_settings.enabled) { | ||||||
|  |         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); | ||||||
|  |             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); |  | ||||||
							
								
								
									
										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; |             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" { | extern "C" { | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| /* Dialog anonymous structure */ | /** Dialog anonymous structure */ | ||||||
| typedef struct DialogEx DialogEx; | typedef struct DialogEx DialogEx; | ||||||
| 
 | 
 | ||||||
| /* DialogEx result */ | /** DialogEx result */ | ||||||
| typedef enum { | typedef enum { | ||||||
|     DialogExResultLeft, |     DialogExResultLeft, | ||||||
|     DialogExResultCenter, |     DialogExResultCenter, | ||||||
|     DialogExResultRight, |     DialogExResultRight, | ||||||
| } DialogExResult; | } DialogExResult; | ||||||
| 
 | 
 | ||||||
| /* DialogEx result callback type
 | /** DialogEx result callback type
 | ||||||
|  * @warning comes from GUI thread |  * @warning comes from GUI thread | ||||||
|  */ |  */ | ||||||
| typedef void (*DialogExResultCallback)(DialogExResult result, void* context); | typedef void (*DialogExResultCallback)(DialogExResult result, void* context); | ||||||
| 
 | 
 | ||||||
| /* Allocate and initialize dialog
 | /** Allocate and initialize dialog
 | ||||||
|  * This dialog used to ask simple questions like Yes/ |  * This dialog used to ask simple questions | ||||||
|  |  * @return DialogEx instance | ||||||
|  */ |  */ | ||||||
| DialogEx* dialog_ex_alloc(); | DialogEx* dialog_ex_alloc(); | ||||||
| 
 | 
 | ||||||
| /* Deinitialize and free dialog
 | /** Deinitialize and free dialog
 | ||||||
|  * @param dialog - DialogEx instance |  * @param dialog - DialogEx instance | ||||||
|  */ |  */ | ||||||
| void dialog_ex_free(DialogEx* dialog_ex); | void dialog_ex_free(DialogEx* dialog_ex); | ||||||
| 
 | 
 | ||||||
| /* Get dialog view
 | /** Get dialog view
 | ||||||
|  * @param dialog - DialogEx instance |  * @param dialog - DialogEx instance | ||||||
|  * @return View instance that can be used for embedding |  * @return View instance that can be used for embedding | ||||||
|  */ |  */ | ||||||
| View* dialog_ex_get_view(DialogEx* dialog_ex); | View* dialog_ex_get_view(DialogEx* dialog_ex); | ||||||
| 
 | 
 | ||||||
| /* Set dialog result callback
 | /** Set dialog result callback
 | ||||||
|  * @param dialog_ex - DialogEx instance |  * @param dialog_ex - DialogEx instance | ||||||
|  * @param callback - result callback function |  * @param callback - result callback function | ||||||
|  */ |  */ | ||||||
| void dialog_ex_set_result_callback(DialogEx* dialog_ex, DialogExResultCallback callback); | void dialog_ex_set_result_callback(DialogEx* dialog_ex, DialogExResultCallback callback); | ||||||
| 
 | 
 | ||||||
| /* Set dialog context
 | /** Set dialog context
 | ||||||
|  * @param dialog_ex - DialogEx instance |  * @param dialog_ex - DialogEx instance | ||||||
|  * @param context - context pointer, will be passed to result callback |  * @param context - context pointer, will be passed to result callback | ||||||
|  */ |  */ | ||||||
| void dialog_ex_set_context(DialogEx* dialog_ex, void* context); | 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 |  * If text is null, dialog header will not be rendered | ||||||
|  * @param dialog - DialogEx instance |  * @param dialog - DialogEx instance | ||||||
|  * @param text - text to be shown, can be multiline |  * @param text - text to be shown, can be multiline | ||||||
| @ -63,7 +64,7 @@ void dialog_ex_set_header( | |||||||
|     Align horizontal, |     Align horizontal, | ||||||
|     Align vertical); |     Align vertical); | ||||||
| 
 | 
 | ||||||
| /* Set dialog text
 | /** Set dialog text
 | ||||||
|  * If text is null, dialog text will not be rendered |  * If text is null, dialog text will not be rendered | ||||||
|  * @param dialog - DialogEx instance |  * @param dialog - DialogEx instance | ||||||
|  * @param text - text to be shown, can be multiline |  * @param text - text to be shown, can be multiline | ||||||
| @ -78,7 +79,7 @@ void dialog_ex_set_text( | |||||||
|     Align horizontal, |     Align horizontal, | ||||||
|     Align vertical); |     Align vertical); | ||||||
| 
 | 
 | ||||||
| /* Set dialog icon
 | /** Set dialog icon
 | ||||||
|  * If x or y is negative, dialog icon will not be rendered |  * If x or y is negative, dialog icon will not be rendered | ||||||
|  * @param dialog - DialogEx instance |  * @param dialog - DialogEx instance | ||||||
|  * @param x, y - icon position |  * @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); | 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 |  * If text is null, left button will not be rendered and processed | ||||||
|  * @param dialog - DialogEx instance |  * @param dialog - DialogEx instance | ||||||
|  * @param text - text to be shown |  * @param text - text to be shown | ||||||
|  */ |  */ | ||||||
| void dialog_ex_set_left_button_text(DialogEx* dialog_ex, const char* text); | 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 |  * If text is null, center button will not be rendered and processed | ||||||
|  * @param dialog - DialogEx instance |  * @param dialog - DialogEx instance | ||||||
|  * @param text - text to be shown |  * @param text - text to be shown | ||||||
|  */ |  */ | ||||||
| void dialog_ex_set_center_button_text(DialogEx* dialog_ex, const char* text); | 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 |  * If text is null, right button will not be rendered and processed | ||||||
|  * @param dialog - DialogEx instance |  * @param dialog - DialogEx instance | ||||||
|  * @param text - text to be shown |  * @param text - text to be shown | ||||||
|  */ |  */ | ||||||
| void dialog_ex_set_right_button_text(DialogEx* dialog_ex, const char* text); | 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 | #ifdef __cplusplus | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
| @ -238,7 +238,7 @@ static void loader_build_menu() { | |||||||
|     with_value_mutex( |     with_value_mutex( | ||||||
|         loader_instance->menu_vm, (Menu * menu) { |         loader_instance->menu_vm, (Menu * menu) { | ||||||
|             MenuItem* menu_debug = |             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++) { |             for(size_t i = 0; i < FLIPPER_DEBUG_APPS_COUNT; i++) { | ||||||
|                 // Add menu item
 |                 // Add menu item
 | ||||||
|  | |||||||
| @ -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_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_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_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}; | 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_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_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_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_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,}; | 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_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_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_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}; | 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_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_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_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_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_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}; | 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 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_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_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_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_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}; | 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_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_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_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_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_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}; | 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_DolphinFirstStart7_61x51; | ||||||
| extern const Icon I_Flipper_young_80x60; | extern const Icon I_Flipper_young_80x60; | ||||||
| extern const Icon I_DolphinFirstStart3_57x48; | 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_PassportBottom_128x17; | ||||||
| extern const Icon I_DoorLeft_8x56; | extern const Icon I_DoorLeft_8x56; | ||||||
| extern const Icon I_DoorLocked_10x56; | 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 I_KeyBackspace_16x9; | ||||||
| extern const Icon A_125khz_14; | extern const Icon A_125khz_14; | ||||||
| extern const Icon A_Bluetooth_14; | extern const Icon A_Bluetooth_14; | ||||||
|  | extern const Icon A_Debug_14; | ||||||
| extern const Icon A_FileManager_14; | extern const Icon A_FileManager_14; | ||||||
| extern const Icon A_GPIO_14; | extern const Icon A_GPIO_14; | ||||||
| extern const Icon A_Games_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_USBConnected_15x8; | ||||||
| extern const Icon I_Bluetooth_5x8; | extern const Icon I_Bluetooth_5x8; | ||||||
| extern const Icon I_Background_128x11; | 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_DolphinMafia_115x62; | ||||||
| extern const Icon I_DolphinExcited_64x63; | extern const Icon I_DolphinExcited_64x63; | ||||||
| extern const Icon I_iButtonDolphinSuccess_109x60; | 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 | 
| @ -43,7 +43,7 @@ bool furi_hal_bt_is_alive() { | |||||||
|     return APPE_Status() == BleGlueStatusStarted; |     return APPE_Status() == BleGlueStatusStarted; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool furi_hal_bt_wait_transition() { | bool furi_hal_bt_wait_startup() { | ||||||
|     uint8_t counter = 0; |     uint8_t counter = 0; | ||||||
|     while (APPE_Status() == BleGlueStatusStartup) { |     while (APPE_Status() == BleGlueStatusStartup) { | ||||||
|         osDelay(10); |         osDelay(10); | ||||||
| @ -56,7 +56,7 @@ bool furi_hal_bt_wait_transition() { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool furi_hal_bt_lock_flash() { | bool furi_hal_bt_lock_flash() { | ||||||
|     if (!furi_hal_bt_wait_transition()) { |     if (!furi_hal_bt_wait_startup()) { | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|     if (APPE_Status() == BleGlueStatusUninitialized) { |     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 furi_hal_bt_stop_packet_test() { | ||||||
|     uint16_t num_of_packets; |     uint16_t num_of_packets = 0; | ||||||
|     hci_le_test_end(&num_of_packets); |     hci_le_test_end(&num_of_packets); | ||||||
|     return 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(); |     __disable_irq(); | ||||||
|     uint8_t pin_num = hal_gpio_get_pin_num(gpio); |     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].callback = cb; | ||||||
|     gpio_interrupt[pin_num].context = ctx; |     gpio_interrupt[pin_num].context = ctx; | ||||||
|     gpio_interrupt[pin_num].ready = true; |     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 */ | /** Get BT/BLE system component state */ | ||||||
| bool furi_hal_bt_is_alive(); | bool furi_hal_bt_is_alive(); | ||||||
| 
 | 
 | ||||||
|  | /** Wait for Core2 startup */ | ||||||
|  | bool furi_hal_bt_wait_startup(); | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * Lock shared access to flash controller |  * Lock shared access to flash controller | ||||||
|  * @return true if lock was successful, false if not |  * @return true if lock was successful, false if not | ||||||
|  | |||||||
 gornekich
						gornekich