[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>
This commit is contained in:
gornekich 2021-09-02 02:22:40 +03:00 committed by GitHub
parent e17336498d
commit 420c03bb58
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
46 changed files with 1497 additions and 744 deletions

View file

@ -109,16 +109,6 @@ void AccessorApp::notify_green_blink() {
void AccessorApp::notify_success() {
notification_message(notification, &sequence_success);
hal_pwm_set(0.5, 1760 / 2, &htim2, TIM_CHANNEL_2);
delay(100);
hal_pwm_stop(&htim2, TIM_CHANNEL_2);
delay(100);
hal_pwm_set(0.5, 1760, &htim2, TIM_CHANNEL_2);
delay(100);
hal_pwm_stop(&htim2, TIM_CHANNEL_2);
}
/*************************** TEXT STORE *****************************/

View file

@ -11,6 +11,8 @@ volatile int WIEGAND::_bitCount = 0;
int WIEGAND::_wiegandType = 0;
constexpr uint32_t clocks_in_ms = 64 * 1000;
const GpioPin* pinD0 = &gpio_ext_pa4;
const GpioPin* pinD1 = &gpio_ext_pa7;
WIEGAND::WIEGAND() {
}
@ -53,9 +55,6 @@ void WIEGAND::begin() {
_wiegandType = 0;
_bitCount = 0;
const GpioPin* pinD0 = &gpio_ext_pa6;
const GpioPin* pinD1 = &gpio_ext_pa7;
hal_gpio_init_simple(pinD0, GpioModeInterruptFall); // Set D0 pin as input
hal_gpio_init_simple(pinD1, GpioModeInterruptFall); // Set D1 pin as input
@ -64,11 +63,11 @@ void WIEGAND::begin() {
}
void WIEGAND::end() {
hal_gpio_remove_int_callback(&gpio_ext_pa6);
hal_gpio_remove_int_callback(&gpio_ext_pa7);
hal_gpio_remove_int_callback(pinD0);
hal_gpio_remove_int_callback(pinD1);
hal_gpio_init_simple(&gpio_ext_pa6, GpioModeAnalog);
hal_gpio_init_simple(&gpio_ext_pa7, GpioModeAnalog);
hal_gpio_init_simple(pinD0, GpioModeAnalog);
hal_gpio_init_simple(pinD1, GpioModeAnalog);
}
void WIEGAND::ReadD0() {

View file

@ -32,6 +32,7 @@ extern int32_t scened_app(void* p);
extern int32_t storage_test_app(void* p);
extern int32_t subghz_app(void* p);
extern int32_t vibro_test_app(void* p);
extern int32_t bt_debug_app(void* p);
// Plugins
extern int32_t music_player_app(void* p);
@ -48,6 +49,7 @@ extern void subghz_cli_init();
// Settings
extern int32_t notification_settings_app(void* p);
extern int32_t storage_settings_app(void* p);
extern int32_t bt_settings_app(void* p);
const FlipperApplication FLIPPER_SERVICES[] = {
/* Services */
@ -236,6 +238,10 @@ const FlipperApplication FLIPPER_DEBUG_APPS[] = {
#ifdef APP_LF_RFID
{.app = lfrfid_debug_app, .name = "LF-RFID Debug", .stack_size = 1024, .icon = &A_125khz_14},
#endif
#ifdef SRV_BT
{.app = bt_debug_app, .name = "Bluetooth Debug", .stack_size = 1024, .icon = NULL},
#endif
};
const size_t FLIPPER_DEBUG_APPS_COUNT = sizeof(FLIPPER_DEBUG_APPS) / sizeof(FlipperApplication);
@ -254,6 +260,10 @@ const FlipperApplication FLIPPER_SETTINGS_APPS[] = {
#ifdef SRV_STORAGE
{.app = storage_settings_app, .name = "Storage", .stack_size = 2048, .icon = NULL},
#endif
#ifdef SRV_BT
{.app = bt_settings_app, .name = "Bluetooth", .stack_size = 1024, .icon = NULL},
#endif
};
const size_t FLIPPER_SETTINGS_APPS_COUNT =

View file

@ -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;
}

View 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;
}

View 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;

View 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);
}

View 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);

View 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);
}

View 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);

View 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;
}

View 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);

View 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;

View file

@ -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);

View 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;
}

View 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;
};

View 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;
}

View 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);

View 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;
}

View 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;

View 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,
};

View 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

View file

@ -0,0 +1,2 @@
ADD_SCENE(bt_settings, start, Start)
ADD_SCENE(bt_settings, disable_dialog, DisableDialog)

View 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);
}

View 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);
}

View file

@ -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;

View file

@ -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;
}

View file

@ -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
View file

@ -243,3 +243,22 @@ void dialog_ex_set_right_button_text(DialogEx* dialog_ex, const char* text) {
return true;
});
}
void dialog_ex_clean(DialogEx* dialog_ex) {
furi_assert(dialog_ex);
TextElement clean_text_el = {
.text = NULL, .x = 0, .y = 0, .horizontal = AlignLeft, .vertical = AlignLeft};
IconElement clean_icon_el = {.icon = NULL, .x = 0, .y = 0};
with_view_model(
dialog_ex->view, (DialogExModel * model) {
model->header = clean_text_el;
model->text = clean_text_el;
model->icon = clean_icon_el;
model->left_text = NULL;
model->center_text = NULL;
model->right_text = NULL;
return true;
});
dialog_ex->context = NULL;
dialog_ex->callback = NULL;
}

View file

@ -5,50 +5,51 @@
extern "C" {
#endif
/* Dialog anonymous structure */
/** Dialog anonymous structure */
typedef struct DialogEx DialogEx;
/* DialogEx result */
/** DialogEx result */
typedef enum {
DialogExResultLeft,
DialogExResultCenter,
DialogExResultRight,
} DialogExResult;
/* DialogEx result callback type
/** DialogEx result callback type
* @warning comes from GUI thread
*/
typedef void (*DialogExResultCallback)(DialogExResult result, void* context);
/* Allocate and initialize dialog
* This dialog used to ask simple questions like Yes/
/** Allocate and initialize dialog
* This dialog used to ask simple questions
* @return DialogEx instance
*/
DialogEx* dialog_ex_alloc();
/* Deinitialize and free dialog
/** Deinitialize and free dialog
* @param dialog - DialogEx instance
*/
void dialog_ex_free(DialogEx* dialog_ex);
/* Get dialog view
/** Get dialog view
* @param dialog - DialogEx instance
* @return View instance that can be used for embedding
*/
View* dialog_ex_get_view(DialogEx* dialog_ex);
/* Set dialog result callback
/** Set dialog result callback
* @param dialog_ex - DialogEx instance
* @param callback - result callback function
*/
void dialog_ex_set_result_callback(DialogEx* dialog_ex, DialogExResultCallback callback);
/* Set dialog context
/** Set dialog context
* @param dialog_ex - DialogEx instance
* @param context - context pointer, will be passed to result callback
*/
void dialog_ex_set_context(DialogEx* dialog_ex, void* context);
/* Set dialog header text
/** Set dialog header text
* If text is null, dialog header will not be rendered
* @param dialog - DialogEx instance
* @param text - text to be shown, can be multiline
@ -63,7 +64,7 @@ void dialog_ex_set_header(
Align horizontal,
Align vertical);
/* Set dialog text
/** Set dialog text
* If text is null, dialog text will not be rendered
* @param dialog - DialogEx instance
* @param text - text to be shown, can be multiline
@ -78,7 +79,7 @@ void dialog_ex_set_text(
Align horizontal,
Align vertical);
/* Set dialog icon
/** Set dialog icon
* If x or y is negative, dialog icon will not be rendered
* @param dialog - DialogEx instance
* @param x, y - icon position
@ -86,27 +87,32 @@ void dialog_ex_set_text(
*/
void dialog_ex_set_icon(DialogEx* dialog_ex, uint8_t x, uint8_t y, const Icon* icon);
/* Set left button text
/** Set left button text
* If text is null, left button will not be rendered and processed
* @param dialog - DialogEx instance
* @param text - text to be shown
*/
void dialog_ex_set_left_button_text(DialogEx* dialog_ex, const char* text);
/* Set center button text
/** Set center button text
* If text is null, center button will not be rendered and processed
* @param dialog - DialogEx instance
* @param text - text to be shown
*/
void dialog_ex_set_center_button_text(DialogEx* dialog_ex, const char* text);
/* Set right button text
/** Set right button text
* If text is null, right button will not be rendered and processed
* @param dialog - DialogEx instance
* @param text - text to be shown
*/
void dialog_ex_set_right_button_text(DialogEx* dialog_ex, const char* text);
/** Clean dialog
* @param dialog_ex DialogEx instance
*/
void dialog_ex_clean(DialogEx* dialog_ex);
#ifdef __cplusplus
}
#endif

View file

@ -238,7 +238,7 @@ static void loader_build_menu() {
with_value_mutex(
loader_instance->menu_vm, (Menu * menu) {
MenuItem* menu_debug =
menu_item_alloc_menu("Debug tools", icon_animation_alloc(&A_Settings_14));
menu_item_alloc_menu("Debug tools", icon_animation_alloc(&A_Debug_14));
for(size_t i = 0; i < FLIPPER_DEBUG_APPS_COUNT; i++) {
// Add menu item

View file

@ -98,18 +98,6 @@ const uint8_t *_I_Flipper_young_80x60[] = {_I_Flipper_young_80x60_0};
const uint8_t _I_DolphinFirstStart3_57x48_0[] = {0x00,0x00,0x00,0x80,0xFF,0x07,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x04,0x00,0x00,0xF8,0x03,0x01,0x00,0x00,0x08,0x00,0x00,0x04,0xBC,0x00,0x00,0x00,0x10,0x00,0x00,0x02,0xC0,0x00,0x00,0x00,0x20,0x00,0x00,0x02,0x00,0x01,0x00,0x00,0x20,0x00,0x00,0x02,0x00,0x02,0x00,0x38,0x40,0x00,0x00,0x02,0x00,0x04,0x00,0x3E,0x40,0x00,0x00,0xF4,0x03,0x08,0x80,0x07,0x80,0x00,0x00,0x5C,0x0D,0x10,0xE0,0x01,0x80,0x00,0x00,0xA8,0x3A,0x20,0xE0,0x00,0x00,0x01,0x00,0x58,0x55,0x00,0xC0,0x01,0x00,0x01,0x00,0xB0,0xAA,0x00,0x80,0x07,0x00,0x01,0x00,0x60,0x55,0x01,0x00,0x1E,0x00,0x01,0x0E,0xC0,0xAA,0x02,0xE0,0x5C,0x00,0x01,0x11,0x80,0x55,0x05,0x00,0xA9,0x00,0x01,0x21,0x00,0xAB,0x0A,0x00,0x56,0x07,0x01,0x41,0x00,0x56,0x15,0x00,0xEC,0x08,0x01,0x81,0x00,0xBF,0x2A,0x00,0x34,0x08,0x01,0x01,0xF1,0xC0,0x57,0x00,0x0C,0x08,0x01,0x02,0x0A,0x00,0xBE,0x00,0x04,0x08,0x01,0x02,0x06,0x00,0x78,0x83,0x02,0x04,0x01,0x02,0x0C,0x00,0xF0,0x7F,0x01,0x04,0x01,0x02,0xF4,0x01,0xFE,0x81,0x00,0x04,0x01,0x04,0x08,0xFF,0x6B,0x40,0x00,0x02,0x01,0x04,0x88,0x55,0x1D,0x40,0x00,0x02,0x01,0x04,0x50,0xAA,0x06,0x20,0x00,0x02,0x01,0x04,0x30,0xD4,0x01,0x20,0x00,0x01,0x01,0x04,0x10,0x68,0x00,0x10,0x00,0x01,0x01,0x04,0x18,0x18,0x00,0x10,0x00,0x01,0x01,0x08,0x18,0x06,0x80,0x10,0x00,0x01,0x01,0x08,0xE8,0x01,0x60,0x08,0x80,0x00,0x01,0x08,0x08,0x00,0x18,0x08,0x80,0x00,0x00,0x08,0x10,0x00,0x06,0x08,0x80,0x00,0x00,0x08,0x60,0xE0,0x01,0x08,0x80,0x00,0x00,0x08,0x80,0x1F,0x00,0x08,0x80,0x00,0x00,0x08,0x80,0x04,0x00,0x04,0x00,0x01,0x00,0x08,0x80,0x04,0x00,0x04,0x00,0x01,0x00,0x10,0x00,0x03,0x00,0x04,0x00,0x01,0x00,0x10,0x00,0x03,0x00,0x04,0x00,0x01,0x00,0x10,0x00,0x01,0x00,0x04,0x00,0x02,0x00,0x10,0x00,0x01,0x00,0x04,0x00,0x02,0x00,0x10,0x80,0x00,0x00,0x04,0x00,0x02,0x00,0x10,0x80,0x00,0x00,0x04,0x00,0x06,0x00,};
const uint8_t *_I_DolphinFirstStart3_57x48[] = {_I_DolphinFirstStart3_57x48_0};
const uint8_t _I_Scanning_123x52_0[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x07,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xAC,0x03,0x18,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x56,0x05,0x60,0x00,0x00,0x00,0x80,0x02,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x81,0x0A,0x80,0x00,0x00,0x00,0x80,0x02,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x80,0x00,0x15,0x00,0x01,0x00,0x00,0x40,0x02,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x40,0x00,0x38,0x00,0x02,0x00,0x00,0x40,0x02,0x00,0x00,0x00,0x00,0x82,0x00,0x00,0x20,0x00,0x74,0x00,0x04,0x00,0x00,0x40,0x82,0x01,0x00,0x00,0x00,0x41,0x00,0x00,0x20,0x00,0x68,0x00,0x04,0x00,0x00,0x20,0x82,0x02,0x06,0x00,0x00,0x21,0x00,0x00,0x10,0x00,0xD0,0xE0,0x0F,0x00,0x00,0x20,0x82,0x02,0x0A,0x0C,0x80,0x20,0x08,0x00,0x10,0x00,0xA0,0x1C,0x10,0x00,0x00,0x20,0x82,0x02,0x0A,0x14,0x80,0x10,0x04,0x00,0x08,0xE0,0xD3,0x03,0x10,0x00,0x00,0x10,0x82,0x02,0x0A,0x14,0x80,0x10,0x02,0x00,0x08,0x90,0xA7,0x40,0x24,0x00,0x00,0x10,0x82,0x02,0x0A,0x14,0x80,0x10,0x02,0x00,0x08,0xC8,0x7F,0x84,0x28,0x00,0x00,0x10,0x84,0x02,0x0A,0xFF,0x80,0x10,0x02,0x00,0x88,0x67,0x3E,0x88,0x28,0x00,0x00,0x10,0x84,0xFA,0xFF,0xFF,0x80,0x10,0x02,0x00,0x44,0x64,0x2E,0x88,0x28,0x00,0x00,0x10,0xFC,0xAF,0xFF,0x15,0x80,0x10,0x04,0x00,0x44,0xE4,0x2F,0x88,0x2A,0x00,0x00,0x18,0xD4,0xDF,0x1F,0x14,0x80,0x20,0x08,0x00,0x44,0xE4,0x2F,0x50,0xFF,0x00,0xFE,0x1F,0xEC,0x3F,0x0A,0x14,0x00,0x21,0x00,0x00,0x44,0xC4,0x2F,0xEA,0x00,0x01,0x01,0x1A,0xFC,0x02,0x0A,0x14,0x00,0x41,0x00,0x00,0x84,0x88,0x2F,0x1D,0x00,0x82,0x7D,0x1E,0x84,0x02,0x0A,0x18,0x00,0x82,0x00,0x00,0x86,0x1F,0xC6,0x06,0x00,0x84,0x7D,0x16,0x84,0x02,0x0A,0x00,0x00,0x02,0x00,0x00,0x46,0xF5,0xC3,0x01,0x00,0x44,0x01,0x22,0x84,0x02,0x0C,0x00,0x00,0x04,0x00,0x00,0x87,0x0A,0x7C,0x00,0x00,0x44,0x03,0x22,0x88,0x02,0x00,0x00,0x00,0x08,0x00,0x00,0x45,0x05,0x08,0x00,0x7E,0xA4,0x03,0x42,0x88,0x02,0x00,0x00,0x00,0x10,0x00,0x00,0x86,0x06,0x00,0xC0,0x81,0xA5,0x07,0x42,0x08,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x30,0x00,0xD2,0xFF,0x81,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x0C,0x00,0xD2,0x1F,0x80,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x80,0x00,0x03,0x00,0xD1,0x1F,0x00,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0xE1,0x00,0x80,0xE9,0x0F,0x00,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x1E,0x00,0xC0,0xE8,0x0F,0x00,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x70,0xEE,0x0F,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x3C,0xF9,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0xAA,0x9F,0xF0,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x40,0x55,0xFD,0x5F,0xF0,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x80,0xEA,0xFF,0x3F,0xE0,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x40,0xD5,0xFF,0x1F,0xE0,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x80,0xAA,0xFF,0x0F,0xE0,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x55,0x55,0x03,0xF0,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0xAA,0xAA,0x00,0xB0,0x0A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x54,0x75,0x00,0x58,0x0D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0xA8,0x0F,0x00,0xA8,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x7C,0x00,0x00,0x5C,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0xAE,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x00,0xD7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0A,0x00,0x00,0x00,0x80,0x7B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0xC0,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0xF0,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x55,0x00,0x00,0x00,0xFC,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xAA,0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,};
const uint8_t *_I_Scanning_123x52[] = {_I_Scanning_123x52_0};
const uint8_t _I_Quest_7x8_0[] = {0x1E,0x33,0x33,0x30,0x18,0x0C,0x00,0x0C,};
const uint8_t *_I_Quest_7x8[] = {_I_Quest_7x8_0};
const uint8_t _I_Unlock_7x8_0[] = {0x1C,0x22,0x02,0x4F,0x67,0x73,0x79,0x3C,};
const uint8_t *_I_Unlock_7x8[] = {_I_Unlock_7x8_0};
const uint8_t _I_Lock_7x8_0[] = {0x1C,0x22,0x22,0x7F,0x7F,0x77,0x7F,0x3E,};
const uint8_t *_I_Lock_7x8[] = {_I_Lock_7x8_0};
const uint8_t _I_PassportBottom_128x17_0[] = {0x2C,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x8F,0x34,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x95,0x2C,0x00,0x00,0x00,0x00,0x00,0x00,0xA8,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0x9A,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x95,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0xA8,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0x9A,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x95,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0xA8,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0x9A,0xF2,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x8F,0xF9,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x0D,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x05,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x05,0xF2,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x3F,0x05,0xFA,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x1F,0x09,0x79,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0xD5,0x80,0x55,0xD5,0x00,0xF3,0xCC,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0x6A,0x00,0xAB,0x6A,0x00,0x06,0x86,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x3F,0x00,0xFE,0x3F,0x00,0xFC,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,};
const uint8_t *_I_PassportBottom_128x17[] = {_I_PassportBottom_128x17_0};
@ -220,6 +208,12 @@ const uint8_t _A_Bluetooth_14_4[] = {0x10,0x00,0x30,0x00,0x51,0x00,0x92,0x00,0x9
const uint8_t _A_Bluetooth_14_5[] = {0x10,0x00,0x30,0x00,0x51,0x00,0x92,0x00,0x94,0x04,0x58,0x08,0x30,0x09,0x30,0x09,0x58,0x08,0x94,0x04,0x92,0x00,0x51,0x00,0x30,0x00,0x10,0x00,};
const uint8_t *_A_Bluetooth_14[] = {_A_Bluetooth_14_0,_A_Bluetooth_14_1,_A_Bluetooth_14_2,_A_Bluetooth_14_3,_A_Bluetooth_14_4,_A_Bluetooth_14_5};
const uint8_t _A_Debug_14_0[] = {0x20,0x01,0xC1,0x20,0x22,0x11,0x24,0x09,0xD9,0x26,0x16,0x1A,0xD8,0x06,0xD8,0x06,0xD6,0x1A,0x19,0x26,0xE4,0x09,0xC2,0x10,0x01,0x20,0x00,0x00,};
const uint8_t _A_Debug_14_1[] = {0x20,0x01,0xC0,0x00,0x22,0x11,0x25,0x29,0xD8,0x06,0x16,0x1A,0xD9,0x26,0xD8,0x06,0xD4,0x0A,0x12,0x12,0xEA,0x15,0xC5,0x28,0x02,0x10,0x02,0x10,};
const uint8_t _A_Debug_14_2[] = {0x20,0x01,0xC0,0x00,0x20,0x01,0x24,0x09,0xDA,0x16,0x11,0x22,0xDC,0x0E,0xDA,0x16,0xD9,0x26,0x14,0x0A,0xF2,0x13,0xD1,0x22,0x08,0x04,0x06,0x18,};
const uint8_t _A_Debug_14_3[] = {0x22,0x11,0xC4,0x08,0x24,0x09,0x25,0x29,0xD9,0x26,0x12,0x12,0xDC,0x0E,0xD8,0x06,0xD8,0x06,0x14,0x0A,0xF4,0x0B,0xD2,0x12,0x19,0x26,0x06,0x18,};
const uint8_t *_A_Debug_14[] = {_A_Debug_14_0,_A_Debug_14_1,_A_Debug_14_2,_A_Debug_14_3};
const uint8_t _A_FileManager_14_0[] = {0xFC,0x07,0x04,0x04,0xF4,0x05,0x04,0x04,0xF7,0x05,0x05,0x04,0xF5,0x3F,0x15,0x20,0x0D,0x20,0x0D,0x10,0x05,0x10,0x05,0x08,0x03,0x08,0xFE,0x07,};
const uint8_t _A_FileManager_14_1[] = {0x00,0x00,0x00,0x00,0xFC,0x07,0x04,0x04,0xF7,0x05,0x05,0x04,0xF5,0x3F,0x15,0x20,0x0D,0x20,0x0D,0x10,0x05,0x10,0x05,0x08,0x03,0x08,0xFE,0x07,};
const uint8_t _A_FileManager_14_2[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x07,0x05,0x04,0xF5,0x3F,0x15,0x20,0x0D,0x20,0x0D,0x10,0x05,0x10,0x05,0x08,0x03,0x08,0xFE,0x07,};
@ -423,6 +417,18 @@ const uint8_t *_I_Bluetooth_5x8[] = {_I_Bluetooth_5x8_0};
const uint8_t _I_Background_128x11_0[] = {0xFE,0x01,0x00,0x00,0x00,0x00,0x00,0xE0,0xFF,0xFF,0xFF,0x0F,0x00,0x00,0x00,0x00,0x01,0x03,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x7D,0x06,0x00,0x00,0x00,0x00,0x00,0x18,0xFF,0xB7,0x55,0x31,0x00,0x00,0x00,0x00,0x81,0xFC,0xFF,0xFF,0xFF,0xFF,0xFF,0x8F,0x00,0x00,0x00,0xE2,0xFF,0xFF,0xFF,0x7F,0x3D,0x01,0x00,0x00,0x00,0x00,0x00,0x40,0xB6,0xEA,0xFF,0x04,0x00,0x00,0x00,0x80,0x41,0xFE,0xFF,0xFF,0xAA,0xFE,0xFF,0x3F,0x01,0x00,0x00,0xF9,0xFF,0xFF,0xFF,0xAB,0x9F,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xF8,0xFF,0x7F,0x02,0x00,0x00,0x00,0x80,0x3E,0xFF,0xFF,0xFF,0xFF,0x55,0xFD,0x7F,0xFC,0xFF,0xFF,0x6C,0xFF,0xFF,0xFF,0xB5,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x80,0x01,0x00,0x00,0x00,0x80,0xC0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x03,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x80,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x00,0xFE,0xFF,0xFF,0xFF,0x7F,};
const uint8_t *_I_Background_128x11[] = {_I_Background_128x11_0};
const uint8_t _I_Scanning_123x52_0[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x07,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xAC,0x03,0x18,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x56,0x05,0x60,0x00,0x00,0x00,0x80,0x02,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x81,0x0A,0x80,0x00,0x00,0x00,0x80,0x02,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x80,0x00,0x15,0x00,0x01,0x00,0x00,0x40,0x02,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x40,0x00,0x38,0x00,0x02,0x00,0x00,0x40,0x02,0x00,0x00,0x00,0x00,0x82,0x00,0x00,0x20,0x00,0x74,0x00,0x04,0x00,0x00,0x40,0x82,0x01,0x00,0x00,0x00,0x41,0x00,0x00,0x20,0x00,0x68,0x00,0x04,0x00,0x00,0x20,0x82,0x02,0x06,0x00,0x00,0x21,0x00,0x00,0x10,0x00,0xD0,0xE0,0x0F,0x00,0x00,0x20,0x82,0x02,0x0A,0x0C,0x80,0x20,0x08,0x00,0x10,0x00,0xA0,0x1C,0x10,0x00,0x00,0x20,0x82,0x02,0x0A,0x14,0x80,0x10,0x04,0x00,0x08,0xE0,0xD3,0x03,0x10,0x00,0x00,0x10,0x82,0x02,0x0A,0x14,0x80,0x10,0x02,0x00,0x08,0x90,0xA7,0x40,0x24,0x00,0x00,0x10,0x82,0x02,0x0A,0x14,0x80,0x10,0x02,0x00,0x08,0xC8,0x7F,0x84,0x28,0x00,0x00,0x10,0x84,0x02,0x0A,0xFF,0x80,0x10,0x02,0x00,0x88,0x67,0x3E,0x88,0x28,0x00,0x00,0x10,0x84,0xFA,0xFF,0xFF,0x80,0x10,0x02,0x00,0x44,0x64,0x2E,0x88,0x28,0x00,0x00,0x10,0xFC,0xAF,0xFF,0x15,0x80,0x10,0x04,0x00,0x44,0xE4,0x2F,0x88,0x2A,0x00,0x00,0x18,0xD4,0xDF,0x1F,0x14,0x80,0x20,0x08,0x00,0x44,0xE4,0x2F,0x50,0xFF,0x00,0xFE,0x1F,0xEC,0x3F,0x0A,0x14,0x00,0x21,0x00,0x00,0x44,0xC4,0x2F,0xEA,0x00,0x01,0x01,0x1A,0xFC,0x02,0x0A,0x14,0x00,0x41,0x00,0x00,0x84,0x88,0x2F,0x1D,0x00,0x82,0x7D,0x1E,0x84,0x02,0x0A,0x18,0x00,0x82,0x00,0x00,0x86,0x1F,0xC6,0x06,0x00,0x84,0x7D,0x16,0x84,0x02,0x0A,0x00,0x00,0x02,0x00,0x00,0x46,0xF5,0xC3,0x01,0x00,0x44,0x01,0x22,0x84,0x02,0x0C,0x00,0x00,0x04,0x00,0x00,0x87,0x0A,0x7C,0x00,0x00,0x44,0x03,0x22,0x88,0x02,0x00,0x00,0x00,0x08,0x00,0x00,0x45,0x05,0x08,0x00,0x7E,0xA4,0x03,0x42,0x88,0x02,0x00,0x00,0x00,0x10,0x00,0x00,0x86,0x06,0x00,0xC0,0x81,0xA5,0x07,0x42,0x08,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x30,0x00,0xD2,0xFF,0x81,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x0C,0x00,0xD2,0x1F,0x80,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x80,0x00,0x03,0x00,0xD1,0x1F,0x00,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0xE1,0x00,0x80,0xE9,0x0F,0x00,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x1E,0x00,0xC0,0xE8,0x0F,0x00,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x70,0xEE,0x0F,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x3C,0xF9,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0xAA,0x9F,0xF0,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x40,0x55,0xFD,0x5F,0xF0,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x80,0xEA,0xFF,0x3F,0xE0,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x40,0xD5,0xFF,0x1F,0xE0,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x80,0xAA,0xFF,0x0F,0xE0,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x55,0x55,0x03,0xF0,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0xAA,0xAA,0x00,0xB0,0x0A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x54,0x75,0x00,0x58,0x0D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0xA8,0x0F,0x00,0xA8,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x7C,0x00,0x00,0x5C,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0xAE,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x00,0xD7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0A,0x00,0x00,0x00,0x80,0x7B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0xC0,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0xF0,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x55,0x00,0x00,0x00,0xFC,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xAA,0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,};
const uint8_t *_I_Scanning_123x52[] = {_I_Scanning_123x52_0};
const uint8_t _I_Quest_7x8_0[] = {0x1E,0x33,0x33,0x30,0x18,0x0C,0x00,0x0C,};
const uint8_t *_I_Quest_7x8[] = {_I_Quest_7x8_0};
const uint8_t _I_Unlock_7x8_0[] = {0x1C,0x22,0x02,0x4F,0x67,0x73,0x79,0x3C,};
const uint8_t *_I_Unlock_7x8[] = {_I_Unlock_7x8_0};
const uint8_t _I_Lock_7x8_0[] = {0x1C,0x22,0x22,0x7F,0x7F,0x77,0x7F,0x3E,};
const uint8_t *_I_Lock_7x8[] = {_I_Lock_7x8_0};
const uint8_t _I_DolphinMafia_115x62_0[] = {0x00,0x00,0x00,0x00,0x80,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x01,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2F,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x15,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xAF,0x0A,0x00,0x40,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x55,0x15,0x00,0x80,0xF0,0xFF,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xAA,0x0A,0x00,0x80,0xFF,0xFF,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x55,0x15,0x00,0xFF,0xFF,0xFF,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xAA,0x2A,0xE0,0xFF,0xFF,0xFF,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x55,0x55,0xFC,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xAA,0xAA,0xFF,0xFF,0xFF,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x55,0xD5,0xFF,0x7F,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xAA,0xFA,0xFF,0x2B,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x55,0xFD,0x7F,0x05,0xE8,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xAB,0xFE,0xAF,0x00,0xF1,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x55,0xFF,0x15,0xE0,0x37,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xEB,0xFF,0x0A,0xFC,0x7F,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF6,0x7F,0x81,0xFF,0xEF,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0xFA,0xAF,0xE0,0x3F,0xEE,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0xFE,0x57,0xF8,0x0F,0xCE,0xFF,0x0F,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0xFF,0x2B,0xFC,0x1F,0x07,0x00,0x30,0x00,0x00,0x00,0x00,0x80,0x02,0x00,0xC0,0xFF,0x15,0xFC,0xFF,0x07,0x00,0xC0,0x00,0x00,0x00,0x00,0x20,0x02,0x00,0xE0,0xBF,0x0A,0xFC,0xFF,0x03,0x00,0x00,0x01,0x00,0x00,0x00,0x18,0x01,0x00,0xF8,0x5F,0x05,0xF8,0xFF,0x03,0x00,0x00,0x02,0x00,0x00,0x60,0x86,0x00,0x00,0xFC,0xAF,0x02,0xFA,0xFF,0x01,0x00,0x00,0x02,0x00,0x30,0x1D,0x40,0x00,0x00,0xFF,0x57,0x01,0xF5,0x7F,0x00,0x00,0xC0,0x02,0x00,0x08,0x00,0x30,0x00,0x80,0xFF,0xAB,0x80,0xEA,0x1F,0x00,0x00,0xE0,0xFB,0x03,0x04,0x00,0x0E,0x00,0xC0,0xFF,0x57,0x00,0xF5,0x03,0x00,0x00,0xF8,0x02,0x00,0x04,0x60,0x01,0x00,0xE0,0xFF,0x2B,0x80,0x0A,0x04,0x00,0x00,0xC6,0xC2,0x0F,0x04,0x03,0x00,0x00,0xF0,0xFF,0x16,0x00,0x05,0x08,0x00,0x80,0x01,0x02,0x00,0xF0,0x00,0x00,0x00,0xF0,0x3F,0x0A,0x80,0x02,0x00,0x00,0x60,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0xE0,0x03,0x06,0x00,0x03,0x00,0x00,0x1C,0x00,0x01,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x0A,0x00,0x82,0x00,0x00,0x03,0x80,0x00,0x00,0x24,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x82,0x00,0xE0,0x00,0x40,0x00,0x00,0x22,0x00,0x00,0x00,0x00,0x00,0x0A,0x00,0x00,0x03,0x1E,0x00,0x30,0x00,0x00,0x22,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0xFC,0x01,0x00,0x0E,0x00,0x00,0x22,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0xC0,0x01,0x00,0x00,0x21,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0xE1,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0xF8,0x10,0x03,0x00,0x00,0x00,0x80,0x01,0x00,0x00,0x00,0xF0,0x04,0x00,0x00,0x04,0x10,0x04,0x00,0x00,0x00,0xE0,0x03,0x00,0x00,0x00,0x0F,0x04,0x00,0x00,0x04,0x10,0x08,0x00,0x00,0x00,0xB0,0x01,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x04,0x10,0x08,0x00,0x00,0x00,0xD8,0xFF,0xFF,0xFF,0x3F,0x00,0x28,0x00,0x00,0x08,0x10,0x08,0x00,0x00,0x00,0xEC,0x01,0x00,0x00,0xE0,0x1F,0x28,0x00,0x00,0x10,0x10,0x08,0x00,0x00,0x00,0xD6,0x02,0x00,0x00,0x00,0x30,0x50,0x00,0x00,0x10,0x10,0x04,0x00,0x00,0x00,0xEB,0x05,0x00,0x00,0x00,0x50,0x50,0x00,0x00,0x10,0x20,0x02,0x00,0x00,0x80,0xD4,0x0A,0x00,0x00,0x00,0x90,0x50,0x00,0x00,0x08,0xC0,0x01,0x00,0x00,0x40,0xEA,0x15,0x00,0x00,0x00,0x08,0x61,0x00,0x00,0x0C,0x00,0x01,0x00,0x00,0x20,0xF4,0xFF,0xFF,0x01,0x00,0x08,0x62,0x00,0x00,0x12,0x80,0x00,0x00,0x00,0x10,0xEA,0x15,0x00,0xFE,0x00,0x08,0xE4,0x01,0x00,0x21,0x80,0x00,0x00,0x00,0x10,0xF4,0x0A,0x00,0x00,0x0F,0x04,0xA8,0x06,0xC0,0xC0,0x40,0x00,0x00,0x00,0x08,0xE8,0x05,0x00,0x00,0x30,0x04,0x50,0x19,0x38,0x01,0x47,0x00,0x00,0x00,0x04,0xF4,0x02,0x00,0x00,0xC0,0x04,0xC0,0xE2,0x07,0x06,0x38,0x00,0x00,0x00,0x04,0xF8,0x05,0x00,0x00,0x00,0x03,0x40,0x01,0x00,0x18,0x20,0x00,0x00,0x00,0x02,0xF0,0x02,0x00,0x00,0x00,0x00,0x80,0x02,0x00,0x60,0x10,0x00,0x00,0x00,0x02,0xF8,0x01,0x00,0x00,0x00,0x00,0x80,0x05,0x00,0x80,0x11,0x00,0x00,0x00,0x01,0xF0,0x02,0x00,0x00,0x00,0x00,0x80,0x0A,0x00,0x00,0x0E,0x00,0x00,0x00,};
const uint8_t *_I_DolphinMafia_115x62[] = {_I_DolphinMafia_115x62_0};
@ -472,10 +478,6 @@ const Icon I_DolphinFirstStart8_56x51 = {.width=56,.height=51,.frame_count=1,.fr
const Icon I_DolphinFirstStart7_61x51 = {.width=61,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_DolphinFirstStart7_61x51};
const Icon I_Flipper_young_80x60 = {.width=80,.height=60,.frame_count=1,.frame_rate=0,.frames=_I_Flipper_young_80x60};
const Icon I_DolphinFirstStart3_57x48 = {.width=57,.height=48,.frame_count=1,.frame_rate=0,.frames=_I_DolphinFirstStart3_57x48};
const Icon I_Scanning_123x52 = {.width=123,.height=52,.frame_count=1,.frame_rate=0,.frames=_I_Scanning_123x52};
const Icon I_Quest_7x8 = {.width=7,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Quest_7x8};
const Icon I_Unlock_7x8 = {.width=7,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Unlock_7x8};
const Icon I_Lock_7x8 = {.width=7,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Lock_7x8};
const Icon I_PassportBottom_128x17 = {.width=128,.height=17,.frame_count=1,.frame_rate=0,.frames=_I_PassportBottom_128x17};
const Icon I_DoorLeft_8x56 = {.width=8,.height=56,.frame_count=1,.frame_rate=0,.frames=_I_DoorLeft_8x56};
const Icon I_DoorLocked_10x56 = {.width=10,.height=56,.frame_count=1,.frame_rate=0,.frames=_I_DoorLocked_10x56};
@ -510,6 +512,7 @@ const Icon I_KeySaveSelected_24x11 = {.width=24,.height=11,.frame_count=1,.frame
const Icon I_KeyBackspace_16x9 = {.width=16,.height=9,.frame_count=1,.frame_rate=0,.frames=_I_KeyBackspace_16x9};
const Icon A_125khz_14 = {.width=14,.height=14,.frame_count=4,.frame_rate=3,.frames=_A_125khz_14};
const Icon A_Bluetooth_14 = {.width=14,.height=14,.frame_count=6,.frame_rate=3,.frames=_A_Bluetooth_14};
const Icon A_Debug_14 = {.width=14,.height=14,.frame_count=4,.frame_rate=3,.frames=_A_Debug_14};
const Icon A_FileManager_14 = {.width=14,.height=14,.frame_count=10,.frame_rate=3,.frames=_A_FileManager_14};
const Icon A_GPIO_14 = {.width=14,.height=14,.frame_count=8,.frame_rate=3,.frames=_A_GPIO_14};
const Icon A_Games_14 = {.width=14,.height=14,.frame_count=9,.frame_rate=3,.frames=_A_Games_14};
@ -552,6 +555,10 @@ const Icon I_SDcardFail_11x8 = {.width=11,.height=8,.frame_count=1,.frame_rate=0
const Icon I_USBConnected_15x8 = {.width=15,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_USBConnected_15x8};
const Icon I_Bluetooth_5x8 = {.width=5,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Bluetooth_5x8};
const Icon I_Background_128x11 = {.width=128,.height=11,.frame_count=1,.frame_rate=0,.frames=_I_Background_128x11};
const Icon I_Scanning_123x52 = {.width=123,.height=52,.frame_count=1,.frame_rate=0,.frames=_I_Scanning_123x52};
const Icon I_Quest_7x8 = {.width=7,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Quest_7x8};
const Icon I_Unlock_7x8 = {.width=7,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Unlock_7x8};
const Icon I_Lock_7x8 = {.width=7,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Lock_7x8};
const Icon I_DolphinMafia_115x62 = {.width=115,.height=62,.frame_count=1,.frame_rate=0,.frames=_I_DolphinMafia_115x62};
const Icon I_DolphinExcited_64x63 = {.width=64,.height=63,.frame_count=1,.frame_rate=0,.frames=_I_DolphinExcited_64x63};
const Icon I_iButtonDolphinSuccess_109x60 = {.width=109,.height=60,.frame_count=1,.frame_rate=0,.frames=_I_iButtonDolphinSuccess_109x60};

View file

@ -29,10 +29,6 @@ extern const Icon I_DolphinFirstStart8_56x51;
extern const Icon I_DolphinFirstStart7_61x51;
extern const Icon I_Flipper_young_80x60;
extern const Icon I_DolphinFirstStart3_57x48;
extern const Icon I_Scanning_123x52;
extern const Icon I_Quest_7x8;
extern const Icon I_Unlock_7x8;
extern const Icon I_Lock_7x8;
extern const Icon I_PassportBottom_128x17;
extern const Icon I_DoorLeft_8x56;
extern const Icon I_DoorLocked_10x56;
@ -67,6 +63,7 @@ extern const Icon I_KeySaveSelected_24x11;
extern const Icon I_KeyBackspace_16x9;
extern const Icon A_125khz_14;
extern const Icon A_Bluetooth_14;
extern const Icon A_Debug_14;
extern const Icon A_FileManager_14;
extern const Icon A_GPIO_14;
extern const Icon A_Games_14;
@ -109,6 +106,10 @@ extern const Icon I_SDcardFail_11x8;
extern const Icon I_USBConnected_15x8;
extern const Icon I_Bluetooth_5x8;
extern const Icon I_Background_128x11;
extern const Icon I_Scanning_123x52;
extern const Icon I_Quest_7x8;
extern const Icon I_Unlock_7x8;
extern const Icon I_Lock_7x8;
extern const Icon I_DolphinMafia_115x62;
extern const Icon I_DolphinExcited_64x63;
extern const Icon I_iButtonDolphinSuccess_109x60;

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

View file

@ -0,0 +1 @@
3

View file

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View file

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

View file

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

View file

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

View file

@ -43,7 +43,7 @@ bool furi_hal_bt_is_alive() {
return APPE_Status() == BleGlueStatusStarted;
}
bool furi_hal_bt_wait_transition() {
bool furi_hal_bt_wait_startup() {
uint8_t counter = 0;
while (APPE_Status() == BleGlueStatusStartup) {
osDelay(10);
@ -56,7 +56,7 @@ bool furi_hal_bt_wait_transition() {
}
bool furi_hal_bt_lock_flash() {
if (!furi_hal_bt_wait_transition()) {
if (!furi_hal_bt_wait_startup()) {
return false;
}
if (APPE_Status() == BleGlueStatusUninitialized) {
@ -100,7 +100,7 @@ void furi_hal_bt_start_packet_rx(uint8_t channel, uint8_t datarate) {
}
uint16_t furi_hal_bt_stop_packet_test() {
uint16_t num_of_packets;
uint16_t num_of_packets = 0;
hci_le_test_end(&num_of_packets);
return num_of_packets;
}

View file

@ -151,6 +151,7 @@ void hal_gpio_add_int_callback(const GpioPin* gpio, GpioExtiCallback cb, void* c
__disable_irq();
uint8_t pin_num = hal_gpio_get_pin_num(gpio);
furi_assert(gpio_interrupt[pin_num].callback == NULL);
gpio_interrupt[pin_num].callback = cb;
gpio_interrupt[pin_num].context = ctx;
gpio_interrupt[pin_num].ready = true;

View file

@ -19,6 +19,9 @@ void furi_hal_bt_dump_state(string_t buffer);
/** Get BT/BLE system component state */
bool furi_hal_bt_is_alive();
/** Wait for Core2 startup */
bool furi_hal_bt_wait_startup();
/**
* Lock shared access to flash controller
* @return true if lock was successful, false if not