Merge remote-tracking branch 'OFW/dev' into dev

This commit is contained in:
MX 2024-05-15 18:22:54 +03:00
parent 96db11a0d6
commit 1afa3f7ef3
No known key found for this signature in database
GPG key ID: 7CCC66B7DBDD1C83
83 changed files with 531 additions and 483 deletions

View file

@ -8,7 +8,8 @@
"amiralizadeh9480.cpp-helper", "amiralizadeh9480.cpp-helper",
"marus25.cortex-debug", "marus25.cortex-debug",
"zxh404.vscode-proto3", "zxh404.vscode-proto3",
"augustocdias.tasks-shell-input" "augustocdias.tasks-shell-input",
"rioj7.command-variable"
], ],
// List of extensions recommended by VS Code that should not be recommended for users of this workspace. // List of extensions recommended by VS Code that should not be recommended for users of this workspace.
"unwantedRecommendations": [ "unwantedRecommendations": [

View file

@ -2,7 +2,7 @@
"configurations": [ "configurations": [
{ {
"name": "Win32", "name": "Win32",
"compilerPath": "${workspaceFolder}/toolchain/x86_64-windows/bin/arm-none-eabi-gcc.exe", "compilerPath": "${workspaceFolder}/toolchain/current/bin/arm-none-eabi-gcc.exe",
"intelliSenseMode": "gcc-arm", "intelliSenseMode": "gcc-arm",
"compileCommands": "${workspaceFolder}/build/latest/compile_commands.json", "compileCommands": "${workspaceFolder}/build/latest/compile_commands.json",
"cStandard": "gnu23", "cStandard": "gnu23",
@ -10,7 +10,7 @@
}, },
{ {
"name": "Linux", "name": "Linux",
"compilerPath": "${workspaceFolder}/toolchain/x86_64-linux/bin/arm-none-eabi-gcc", "compilerPath": "${workspaceFolder}/toolchain/current/bin/arm-none-eabi-gcc",
"intelliSenseMode": "gcc-arm", "intelliSenseMode": "gcc-arm",
"compileCommands": "${workspaceFolder}/build/latest/compile_commands.json", "compileCommands": "${workspaceFolder}/build/latest/compile_commands.json",
"cStandard": "gnu23", "cStandard": "gnu23",
@ -18,7 +18,7 @@
}, },
{ {
"name": "Mac", "name": "Mac",
"compilerPath": "${workspaceFolder}/toolchain/x86_64-darwin/bin/arm-none-eabi-gcc", "compilerPath": "${workspaceFolder}/toolchain/current/bin/arm-none-eabi-gcc",
"intelliSenseMode": "gcc-arm", "intelliSenseMode": "gcc-arm",
"compileCommands": "${workspaceFolder}/build/latest/compile_commands.json", "compileCommands": "${workspaceFolder}/build/latest/compile_commands.json",
"cStandard": "gnu23", "cStandard": "gnu23",

View file

@ -1021,3 +1021,35 @@ type: raw
frequency: 38000 frequency: 38000
duty_cycle: 0.330000 duty_cycle: 0.330000
data: 3302 1640 404 423 407 420 410 1212 437 390 440 1234 405 395 435 392 438 415 415 1207 432 1242 407 420 410 391 439 414 405 1243 406 1241 408 392 438 415 415 386 433 393 437 390 440 414 405 396 434 419 411 389 441 412 407 420 410 390 440 387 432 1242 407 393 437 390 440 414 405 395 435 392 438 389 430 396 434 1240 409 417 413 414 405 395 435 419 411 1237 412 389 430 396 434 393 437 416 414 387 432 394 436 1212 437 389 441 1234 405 1217 432 1241 408 1213 436 1212 437 1210 439 data: 3302 1640 404 423 407 420 410 1212 437 390 440 1234 405 395 435 392 438 415 415 1207 432 1242 407 420 410 391 439 414 405 1243 406 1241 408 392 438 415 415 386 433 393 437 390 440 414 405 396 434 419 411 389 441 412 407 420 410 390 440 387 432 1242 407 393 437 390 440 414 405 395 435 392 438 389 430 396 434 1240 409 417 413 414 405 395 435 419 411 1237 412 389 430 396 434 393 437 416 414 387 432 394 436 1212 437 389 441 1234 405 1217 432 1241 408 1213 436 1212 437 1210 439
#
# Model: Toshiba RAS-2518D
#
name: Dh
type: raw
frequency: 38000
duty_cycle: 0.330000
data: 4349 4437 549 1615 551 1614 551 1614 551 1617 549 531 550 530 551 1615 550 531 550 532 549 530 551 531 550 530 551 1615 550 1614 551 531 550 1615 551 529 552 531 550 530 551 533 548 530 551 530 551 1616 549 1615 550 1616 550 1615 550 1614 551 1616 550 1615 551 1615 550 531 550 531 550 530 551 529 552 530 551 530 551 529 552 530 551 531 550 1615 550 532 549 1615 550 1616 550 531 550 531 550 530 551 530 551 529 552 532 549 530 551 530 551 531 550 529 552 531 550 1615 551 530 551 530 551 530 551 531 550 530 551 531 550 530 551 531 550 531 550 531 550 1616 550 1618 547 532 549 529 552 530 551 1615 551 1615 550 5379 4350 4436 550 1616 549 1615 551 1614 552 1615 550 529 552 530 551 1614 552 530 551 529 552 531 550 531 550 531 550 1614 552 1614 551 530 551 1615 550 530 551 530 551 530 551 530 551 531 550 532 549 1616 549 1615 551 1614 552 1615 550 1614 551 1616 550 1614 552 1615 550 529 552 530 551 530 551 530 551 531 550 531 550 530 551 530 551 531 550 1615 550 530 551 1615 550 1615 551 530 551 530 551 530 551 530 551 530 551 530 551 529 552 530 551 531 550 532 549 530 551 1615 551 531 550 530 551 530 551 530 551 530 551 531 550 531 550 531 550 530 551 531 550 1615 551 1615 551 532 549 531 550 531 550 1616 549 1614 552
#
name: Cool_hi
type: raw
frequency: 38000
duty_cycle: 0.330000
data: 4350 4438 549 1615 551 1614 552 1616 549 1616 550 530 551 531 550 1615 551 530 551 529 552 531 550 530 551 531 550 1614 551 1616 550 531 550 1616 549 530 551 531 550 530 551 529 552 530 551 531 550 1616 549 1616 550 1616 549 1616 550 1615 551 1614 551 1614 552 1615 551 530 551 531 550 530 551 531 550 531 550 529 552 532 549 531 550 530 551 1613 552 530 551 531 550 529 552 532 549 530 551 530 551 531 550 531 550 530 551 530 551 530 551 531 550 530 551 531 550 531 550 1615 551 529 552 530 551 530 551 530 551 530 551 530 551 530 551 530 551 532 549 531 550 531 550 532 549 531 550 531 550 530 551 530 551 5132 4351 4435 552 1616 550 1615 550 1615 551 1613 553 531 550 530 551 1615 550 530 551 531 550 531 550 530 551 532 549 1616 550 1616 549 530 551 1615 551 530 551 531 550 530 551 530 551 530 551 531 550 1615 551 1615 551 1614 551 1615 550 1615 551 1615 550 1615 550 1616 550 530 551 530 551 531 550 532 549 530 551 530 551 531 550 531 550 531 550 1615 550 530 551 530 551 530 551 529 552 531 550 530 551 531 550 531 550 530 551 530 551 531 550 530 551 530 551 530 551 531 550 1616 550 530 551 529 552 530 551 531 550 532 549 530 551 530 551 529 552 531 550 529 552 530 551 530 551 531 550 531 550 529 552 531 550
#
name: Cool_lo
type: raw
frequency: 38000
duty_cycle: 0.330000
data: 4350 4436 550 1617 549 1615 550 1615 550 1617 548 530 551 531 550 1615 551 531 550 531 550 530 551 530 551 531 550 1614 552 1615 550 530 551 1614 551 531 550 531 550 531 550 529 552 532 549 530 551 1617 549 1616 549 1615 551 1619 547 1615 550 1615 550 1616 549 1616 550 530 551 531 550 530 551 530 551 531 550 530 551 529 552 529 552 530 551 1617 548 533 548 1615 551 1613 552 530 551 531 550 531 550 530 551 530 551 532 549 531 550 531 550 530 551 531 550 531 550 531 550 1615 551 531 550 531 550 532 549 531 550 530 551 531 550 533 548 531 550 530 551 1617 548 1616 549 530 551 531 550 532 549 532 549 532 549 5200 4349 4436 550 1615 551 1615 551 1615 550 1616 550 531 550 530 551 1615 551 531 550 530 551 530 551 530 551 530 551 1616 549 1615 551 530 551 1615 551 531 550 531 550 530 551 531 550 531 550 531 550 1615 551 1616 550 1616 550 1615 550 1617 548 1616 549 1616 550 1615 550 531 550 530 551 531 550 531 550 532 549 530 551 531 550 531 550 532 549 1616 550 531 550 1616 550 1615 550 531 550 530 551 531 550 531 550 531 550 531 550 531 550 532 549 532 549 531 550 532 549 531 550 1616 550 531 550 530 551 532 549 532 549 530 551 532 549 531 550 532 549 531 550 1616 549 1617 549 531 550 530 551 531 550 532 549 532 549
#
name: Heat_hi
type: raw
frequency: 38000
duty_cycle: 0.330000
data: 4350 4437 547 1618 548 1620 546 1620 546 1619 547 534 547 535 546 1619 547 534 547 536 545 536 545 535 546 535 546 1619 547 1620 545 534 523 1644 546 535 522 559 546 535 546 534 547 535 546 535 545 1620 546 1620 546 1620 546 1619 547 1619 546 1619 547 1620 545 1620 546 535 546 534 547 537 520 558 523 558 547 534 547 536 521 559 522 559 522 1644 546 535 546 535 522 560 545 536 521 559 522 559 522 558 523 559 522 560 521 559 522 559 522 560 521 559 522 561 520 1644 521 1645 520 559 522 559 522 559 522 559 522 559 522 560 521 560 521 560 521 561 520 559 522 560 521 559 522 559 522 559 522 1644 522 559 522 5341 4349 4439 520 1645 521 1645 521 1646 519 1645 521 560 521 561 520 1645 521 560 521 560 521 559 522 560 521 561 520 1646 520 1645 521 561 520 1645 521 561 520 560 521 560 521 560 521 560 521 561 520 1644 522 1644 522 1645 520 1645 521 1645 521 1645 520 1646 520 1644 522 561 520 560 521 560 521 561 520 560 521 561 520 561 520 561 520 560 521 1646 520 562 519 561 520 561 520 562 519 560 521 560 521 561 520 561 520 560 521 560 521 561 520 560 521 560 521 562 519 1646 520 1645 521 561 520 561 520 561 520 560 521 560 521 561 520 560 521 559 522 560 521 561 520 561 520 560 521 562 519 559 522 1645 521 561 520
#
name: Heat_lo
type: raw
frequency: 38000
duty_cycle: 0.330000
data: 4348 4439 520 1646 520 1646 520 1646 519 1646 520 561 520 561 520 1646 519 561 520 561 520 562 519 562 519 561 520 1646 520 1647 518 563 518 1646 519 562 519 561 520 561 520 562 519 562 519 561 520 1648 517 1647 519 1646 519 1647 519 1646 520 1646 520 1645 520 1647 519 561 520 561 520 562 519 562 519 562 519 562 519 561 520 562 519 561 520 1646 520 562 519 1647 518 1646 520 562 519 560 521 561 520 561 520 561 520 562 519 562 519 560 521 562 519 562 519 560 521 1646 520 1646 520 561 520 562 519 561 520 562 519 561 520 561 520 561 520 561 520 561 520 1647 518 1646 520 562 519 562 519 561 520 1646 520 561 520 5409 4348 4440 519 1645 521 1646 519 1645 521 1645 521 561 520 561 520 1644 522 561 520 561 520 561 520 560 521 562 519 1646 520 1646 520 562 519 1644 522 561 520 561 520 561 520 561 520 561 520 561 520 1646 520 1645 520 1646 520 1645 521 1646 520 1646 520 1644 522 1645 521 560 521 560 521 561 520 561 520 560 521 560 521 561 520 561 520 561 520 1645 521 562 519 1645 521 1645 520 561 520 562 519 561 520 561 520 561 520 560 521 560 521 560 521 560 521 561 520 560 521 1646 520 1646 520 561 520 560 521 559 522 560 521 561 520 561 520 560 521 560 521 560 521 1646 520 1645 520 561 520 560 521 560 521 1645 521 561 520

View file

@ -121,7 +121,8 @@ void elements_multiline_text_aligned(
/** Draw multiline text /** Draw multiline text
* *
* @param canvas Canvas instance * @param canvas Canvas instance
* @param x, y top left corner coordinates * @param x top left corner coordinates
* @param y top left corner coordinates
* @param text string (possible multiline) * @param text string (possible multiline)
*/ */
void elements_multiline_text(Canvas* canvas, int32_t x, int32_t y, const char* text); void elements_multiline_text(Canvas* canvas, int32_t x, int32_t y, const char* text);
@ -129,7 +130,8 @@ void elements_multiline_text(Canvas* canvas, int32_t x, int32_t y, const char* t
/** Draw framed multiline text /** Draw framed multiline text
* *
* @param canvas Canvas instance * @param canvas Canvas instance
* @param x, y top left corner coordinates * @param x top left corner coordinates
* @param y top left corner coordinates
* @param text string (possible multiline) * @param text string (possible multiline)
*/ */
void elements_multiline_text_framed(Canvas* canvas, int32_t x, int32_t y, const char* text); void elements_multiline_text_framed(Canvas* canvas, int32_t x, int32_t y, const char* text);
@ -137,8 +139,10 @@ void elements_multiline_text_framed(Canvas* canvas, int32_t x, int32_t y, const
/** Draw slightly rounded frame /** Draw slightly rounded frame
* *
* @param canvas Canvas instance * @param canvas Canvas instance
* @param x, y top left corner coordinates * @param x top left corner coordinates
* @param width, height size of frame * @param y top left corner coordinates
* @param width width of frame
* @param height height of frame
*/ */
void elements_slightly_rounded_frame( void elements_slightly_rounded_frame(
Canvas* canvas, Canvas* canvas,
@ -150,8 +154,10 @@ void elements_slightly_rounded_frame(
/** Draw slightly rounded box /** Draw slightly rounded box
* *
* @param canvas Canvas instance * @param canvas Canvas instance
* @param x, y top left corner coordinates * @param x top left corner coordinates
* @param width, height size of box * @param y top left corner coordinates
* @param width height of box
* @param height height of box
*/ */
void elements_slightly_rounded_box( void elements_slightly_rounded_box(
Canvas* canvas, Canvas* canvas,
@ -163,8 +169,10 @@ void elements_slightly_rounded_box(
/** Draw bold rounded frame /** Draw bold rounded frame
* *
* @param canvas Canvas instance * @param canvas Canvas instance
* @param x, y top left corner coordinates * @param x top left corner coordinates
* @param width, height size of frame * @param y top left corner coordinates
* @param width width of frame
* @param height height of frame
*/ */
void elements_bold_rounded_frame(Canvas* canvas, int32_t x, int32_t y, size_t width, size_t height); void elements_bold_rounded_frame(Canvas* canvas, int32_t x, int32_t y, size_t width, size_t height);

View file

@ -318,6 +318,26 @@ void submenu_add_lockable_item(
true); true);
} }
void submenu_change_item_label(Submenu* submenu, uint32_t index, const char* label) {
furi_check(submenu);
furi_check(label);
with_view_model(
submenu->view,
SubmenuModel * model,
{
SubmenuItemArray_it_t it;
for(SubmenuItemArray_it(it, model->items); !SubmenuItemArray_end_p(it);
SubmenuItemArray_next(it)) {
if(index == SubmenuItemArray_cref(it)->index) {
furi_string_set_str(SubmenuItemArray_cref(it)->label, label);
break;
}
}
},
true);
}
void submenu_reset(Submenu* submenu) { void submenu_reset(Submenu* submenu) {
furi_check(submenu); furi_check(submenu);
view_set_orientation(submenu->view, ViewOrientationHorizontal); view_set_orientation(submenu->view, ViewOrientationHorizontal);
@ -335,6 +355,25 @@ void submenu_reset(Submenu* submenu) {
true); true);
} }
uint32_t submenu_get_selected_item(Submenu* submenu) {
furi_check(submenu);
uint32_t selected_item_index = 0;
with_view_model(
submenu->view,
SubmenuModel * model,
{
if(model->position < SubmenuItemArray_size(model->items)) {
const SubmenuItem* item = SubmenuItemArray_cget(model->items, model->position);
selected_item_index = item->index;
}
},
false);
return selected_item_index;
}
void submenu_set_selected_item(Submenu* submenu, uint32_t index) { void submenu_set_selected_item(Submenu* submenu, uint32_t index) {
furi_check(submenu); furi_check(submenu);
with_view_model( with_view_model(

View file

@ -73,16 +73,32 @@ void submenu_add_lockable_item(
bool locked, bool locked,
const char* locked_message); const char* locked_message);
/** Change label of an existing item
*
* @param submenu Submenu instance
* @param index The index of the item
* @param label The new label
*/
void submenu_change_item_label(Submenu* submenu, uint32_t index, const char* label);
/** Remove all items from submenu /** Remove all items from submenu
* *
* @param submenu Submenu instance * @param submenu Submenu instance
*/ */
void submenu_reset(Submenu* submenu); void submenu_reset(Submenu* submenu);
/** Set submenu item selector /** Get submenu selected item index
* *
* @param submenu Submenu instance * @param submenu Submenu instance
* @param index The index *
* @return Index of the selected item
*/
uint32_t submenu_get_selected_item(Submenu* submenu);
/** Set submenu selected item by index
*
* @param submenu Submenu instance
* @param index The index of the selected item
*/ */
void submenu_set_selected_item(Submenu* submenu, uint32_t index); void submenu_set_selected_item(Submenu* submenu, uint32_t index);

View file

@ -43,7 +43,7 @@ static DialogMessageButton product_screen(DialogsApp* dialogs, DialogMessage* me
static DialogMessageButton address_screen(DialogsApp* dialogs, DialogMessage* message) { static DialogMessageButton address_screen(DialogsApp* dialogs, DialogMessage* message) {
DialogMessageButton result; DialogMessageButton result;
const char* screen_text = "Flipper Devices Inc\n" const char* screen_text = "Flipper Devices Inc.\n"
"Suite B #551, 2803\n" "Suite B #551, 2803\n"
"Philadelphia Pike, Claymont\n" "Philadelphia Pike, Claymont\n"
"DE, USA 19703\n"; "DE, USA 19703\n";
@ -59,7 +59,7 @@ static DialogMessageButton compliance_screen(DialogsApp* dialogs, DialogMessage*
DialogMessageButton result; DialogMessageButton result;
const char* screen_text = "For all compliance\n" const char* screen_text = "For all compliance\n"
"certificates please visit:\n" "certificates, please visit:\n"
"www.flipp.dev/compliance"; "www.flipp.dev/compliance";
dialog_message_set_text(message, screen_text, 0, 0, AlignLeft, AlignTop); dialog_message_set_text(message, screen_text, 0, 0, AlignLeft, AlignTop);
@ -226,9 +226,11 @@ int32_t about_settings_app(void* p) {
while(1) { while(1) {
if(screen_index >= COUNT_OF(about_screens) - 1) { if(screen_index >= COUNT_OF(about_screens) - 1) {
dialog_message_set_buttons(message, "Back", NULL, NULL); dialog_message_set_buttons(message, "Prev.", NULL, NULL);
} else if(screen_index == 0) {
dialog_message_set_buttons(message, NULL, NULL, "Next");
} else { } else {
dialog_message_set_buttons(message, "Back", NULL, "Next"); dialog_message_set_buttons(message, "Prev.", NULL, "Next");
} }
screen_result = about_screens[screen_index](dialogs, message); screen_result = about_screens[screen_index](dialogs, message);

View file

@ -11,10 +11,10 @@ void bt_settings_scene_forget_dev_confirm_dialog_callback(DialogExResult result,
void bt_settings_scene_forget_dev_confirm_on_enter(void* context) { void bt_settings_scene_forget_dev_confirm_on_enter(void* context) {
BtSettingsApp* app = context; BtSettingsApp* app = context;
DialogEx* dialog = app->dialog; DialogEx* dialog = app->dialog;
dialog_ex_set_header(dialog, "Unpair All Devices?", 64, 3, AlignCenter, AlignTop); dialog_ex_set_header(dialog, "Unpair All Devices?", 64, 0, AlignCenter, AlignTop);
dialog_ex_set_text( dialog_ex_set_text(
dialog, "All previous pairings\nwill be lost!", 64, 22, AlignCenter, AlignTop); dialog, "All previous pairings\nwill be lost!", 64, 14, AlignCenter, AlignTop);
dialog_ex_set_left_button_text(dialog, "Back"); dialog_ex_set_left_button_text(dialog, "Cancel");
dialog_ex_set_right_button_text(dialog, "Unpair"); dialog_ex_set_right_button_text(dialog, "Unpair");
dialog_ex_set_context(dialog, app); dialog_ex_set_context(dialog, app);
dialog_ex_set_result_callback(dialog, bt_settings_scene_forget_dev_confirm_dialog_callback); dialog_ex_set_result_callback(dialog, bt_settings_scene_forget_dev_confirm_dialog_callback);

View file

@ -53,7 +53,7 @@ void bt_settings_scene_start_on_enter(void* context) {
variable_item_set_current_value_index(item, BtSettingOff); variable_item_set_current_value_index(item, BtSettingOff);
variable_item_set_current_value_text(item, bt_settings_text[BtSettingOff]); variable_item_set_current_value_text(item, bt_settings_text[BtSettingOff]);
} }
variable_item_list_add(var_item_list, "Forget All Paired Devices", 1, NULL, NULL); variable_item_list_add(var_item_list, "Unpair All Devices", 1, NULL, NULL);
variable_item_list_set_enter_callback( variable_item_list_set_enter_callback(
var_item_list, bt_settings_scene_start_var_list_enter_callback, app); var_item_list, bt_settings_scene_start_var_list_enter_callback, app);
} else { } else {

View file

@ -133,6 +133,7 @@ void desktop_settings_app_free(DesktopSettingsApp* app) {
extern int32_t desktop_settings_app(void* p) { extern int32_t desktop_settings_app(void* p) {
DesktopSettingsApp* app = desktop_settings_app_alloc(); DesktopSettingsApp* app = desktop_settings_app_alloc();
DESKTOP_SETTINGS_LOAD(&app->settings); DESKTOP_SETTINGS_LOAD(&app->settings);
if(p && (strcmp(p, DESKTOP_SETTINGS_RUN_PIN_SETUP_ARG) == 0)) { if(p && (strcmp(p, DESKTOP_SETTINGS_RUN_PIN_SETUP_ARG) == 0)) {
scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinSetupHowto); scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinSetupHowto);
} else { } else {
@ -140,6 +141,9 @@ extern int32_t desktop_settings_app(void* p) {
} }
view_dispatcher_run(app->view_dispatcher); view_dispatcher_run(app->view_dispatcher);
DESKTOP_SETTINGS_SAVE(&app->settings);
desktop_settings_app_free(app); desktop_settings_app_free(app);
return 0; return 0;
} }

View file

@ -47,4 +47,5 @@ typedef struct {
char device_name[FURI_HAL_VERSION_ARRAY_NAME_LENGTH]; char device_name[FURI_HAL_VERSION_ARRAY_NAME_LENGTH];
uint8_t menu_idx; uint8_t menu_idx;
uint32_t pin_menu_idx;
} DesktopSettingsApp; } DesktopSettingsApp;

View file

@ -44,7 +44,7 @@ void desktop_settings_scene_pin_menu_on_enter(void* context) {
} }
submenu_set_header(app->submenu, "PIN Code Settings"); submenu_set_header(app->submenu, "PIN Code Settings");
submenu_set_selected_item(app->submenu, app->menu_idx); submenu_set_selected_item(app->submenu, app->pin_menu_idx);
view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewMenu); view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewMenu);
} }
@ -76,11 +76,16 @@ bool desktop_settings_scene_pin_menu_on_event(void* context, SceneManagerEvent e
consumed = true; consumed = true;
break; break;
} }
} else if(event.type == SceneManagerEventTypeBack) {
submenu_set_selected_item(app->submenu, 0);
} }
return consumed; return consumed;
} }
void desktop_settings_scene_pin_menu_on_exit(void* context) { void desktop_settings_scene_pin_menu_on_exit(void* context) {
DesktopSettingsApp* app = context; DesktopSettingsApp* app = context;
app->pin_menu_idx = submenu_get_selected_item(app->submenu);
submenu_reset(app->submenu); submenu_reset(app->submenu);
} }

View file

@ -97,6 +97,7 @@ bool desktop_settings_scene_pin_setup_on_event(void* context, SceneManagerEvent
break; break;
} }
} }
return consumed; return consumed;
} }

View file

@ -27,6 +27,7 @@ void desktop_settings_scene_pin_setup_done_on_enter(void* context) {
DESKTOP_SETTINGS_SAVE(&app->settings); DESKTOP_SETTINGS_SAVE(&app->settings);
NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION); NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
notification_message(notification, &sequence_single_vibro); notification_message(notification, &sequence_single_vibro);
notification_message(notification, &sequence_blink_green_10);
furi_record_close(RECORD_NOTIFICATION); furi_record_close(RECORD_NOTIFICATION);
desktop_view_pin_input_set_context(app->pin_input_view, app); desktop_view_pin_input_set_context(app->pin_input_view, app);

View file

@ -24,9 +24,9 @@ static void desktop_settings_view_pin_setup_howto2_draw(Canvas* canvas, void* mo
elements_multiline_text_aligned( elements_multiline_text_aligned(
canvas, canvas,
64, 64,
24, 0,
AlignCenter,
AlignCenter, AlignCenter,
AlignTop,
"Forgotten PIN can only be\n" "Forgotten PIN can only be\n"
"reset with entire device.\n" "reset with entire device.\n"
"Read docs How to reset PIN."); "Read docs How to reset PIN.");

View file

@ -30,3 +30,5 @@ typedef enum {
PowerSettingsAppViewSubmenu, PowerSettingsAppViewSubmenu,
PowerSettingsAppViewDialog, PowerSettingsAppViewDialog,
} PowerSettingsAppView; } PowerSettingsAppView;
typedef enum { RebootTypeDFU, RebootTypeNormal } RebootType;

View file

@ -1,4 +1,5 @@
ADD_SCENE(power_settings, start, Start) ADD_SCENE(power_settings, start, Start)
ADD_SCENE(power_settings, battery_info, BatteryInfo) ADD_SCENE(power_settings, battery_info, BatteryInfo)
ADD_SCENE(power_settings, reboot, Reboot) ADD_SCENE(power_settings, reboot, Reboot)
ADD_SCENE(power_settings, reboot_confirm, RebootConfirm)
ADD_SCENE(power_settings, power_off, PowerOff) ADD_SCENE(power_settings, power_off, PowerOff)

View file

@ -10,12 +10,12 @@ void power_settings_scene_power_off_on_enter(void* context) {
PowerSettingsApp* app = context; PowerSettingsApp* app = context;
DialogEx* dialog = app->dialog; DialogEx* dialog = app->dialog;
dialog_ex_set_header(dialog, "Turn OFF Device?", 64, 2, AlignCenter, AlignTop); dialog_ex_set_header(dialog, "Turn Off Device?", 64, 0, AlignCenter, AlignTop);
dialog_ex_set_text( dialog_ex_set_text(
dialog, " I will be\nwaiting for\n you here...", 78, 16, AlignLeft, AlignTop); dialog, " I will be\nwaiting for\n you here...", 78, 14, AlignLeft, AlignTop);
dialog_ex_set_icon(dialog, 21, 13, &I_Cry_dolph_55x52); dialog_ex_set_icon(dialog, 14, 10, &I_dolph_cry_49x54);
dialog_ex_set_left_button_text(dialog, "Back"); dialog_ex_set_left_button_text(dialog, "Cancel");
dialog_ex_set_right_button_text(dialog, "OFF"); dialog_ex_set_right_button_text(dialog, "Power Off");
dialog_ex_set_result_callback(dialog, power_settings_scene_power_off_dialog_callback); dialog_ex_set_result_callback(dialog, power_settings_scene_power_off_dialog_callback);
dialog_ex_set_context(dialog, app); dialog_ex_set_context(dialog, app);

View file

@ -24,7 +24,7 @@ void power_settings_scene_reboot_on_enter(void* context) {
app); app);
submenu_add_item( submenu_add_item(
submenu, submenu,
"Flipper OS", "Reboot Flipper",
PowerSettingsRebootSubmenuIndexOs, PowerSettingsRebootSubmenuIndexOs,
power_settings_scene_reboot_submenu_callback, power_settings_scene_reboot_submenu_callback,
app); app);
@ -33,14 +33,18 @@ void power_settings_scene_reboot_on_enter(void* context) {
} }
bool power_settings_scene_reboot_on_event(void* context, SceneManagerEvent event) { bool power_settings_scene_reboot_on_event(void* context, SceneManagerEvent event) {
UNUSED(context); PowerSettingsApp* app = context;
bool consumed = false; bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
if(event.event == PowerSettingsRebootSubmenuIndexDfu) { if(event.event == PowerSettingsRebootSubmenuIndexDfu) {
power_reboot(PowerBootModeDfu); scene_manager_set_scene_state(
app->scene_manager, PowerSettingsAppSceneRebootConfirm, RebootTypeDFU);
scene_manager_next_scene(app->scene_manager, PowerSettingsAppSceneRebootConfirm);
} else if(event.event == PowerSettingsRebootSubmenuIndexOs) { } else if(event.event == PowerSettingsRebootSubmenuIndexOs) {
power_reboot(PowerBootModeNormal); scene_manager_set_scene_state(
app->scene_manager, PowerSettingsAppSceneRebootConfirm, RebootTypeNormal);
scene_manager_next_scene(app->scene_manager, PowerSettingsAppSceneRebootConfirm);
} }
consumed = true; consumed = true;
} }

View file

@ -0,0 +1,66 @@
#include "../power_settings_app.h"
void power_settings_scene_reboot_confirm_dialog_callback(DialogExResult result, void* context) {
furi_assert(context);
PowerSettingsApp* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, result);
}
void power_settings_scene_reboot_confirm_on_enter(void* context) {
PowerSettingsApp* app = context;
DialogEx* dialog = app->dialog;
RebootType reboot_type =
scene_manager_get_scene_state(app->scene_manager, PowerSettingsAppSceneRebootConfirm);
if(reboot_type == RebootTypeDFU) {
dialog_ex_set_header(dialog, "Reboot to DFU Mode?", 64, 0, AlignCenter, AlignTop);
dialog_ex_set_text(
dialog,
"Needed for device maintenance\nor firmware upgrades",
64,
14,
AlignCenter,
AlignTop);
} else if(reboot_type == RebootTypeNormal) {
dialog_ex_set_header(dialog, "Reboot Flipper?", 64, 0, AlignCenter, AlignTop);
dialog_ex_set_text(
dialog, "May help with some firmware\n issues", 64, 14, AlignCenter, AlignTop);
} else {
furi_crash("Invalid reboot type");
}
dialog_ex_set_left_button_text(dialog, "Cancel");
dialog_ex_set_right_button_text(dialog, "Reboot");
dialog_ex_set_result_callback(dialog, power_settings_scene_reboot_confirm_dialog_callback);
dialog_ex_set_context(dialog, app);
view_dispatcher_switch_to_view(app->view_dispatcher, PowerSettingsAppViewDialog);
}
bool power_settings_scene_reboot_confirm_on_event(void* context, SceneManagerEvent event) {
PowerSettingsApp* app = context;
bool consumed = false;
RebootType reboot_type =
scene_manager_get_scene_state(app->scene_manager, PowerSettingsAppSceneRebootConfirm);
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == DialogExResultLeft) {
scene_manager_previous_scene(app->scene_manager);
} else if(event.event == DialogExResultRight) {
if(reboot_type == RebootTypeDFU) {
power_reboot(PowerBootModeDfu);
} else {
power_reboot(PowerBootModeNormal);
}
}
consumed = true;
}
return consumed;
}
void power_settings_scene_reboot_confirm_on_exit(void* context) {
PowerSettingsApp* app = context;
dialog_ex_reset(app->dialog);
}

View file

@ -1,5 +1,7 @@
#include "../storage_settings.h" #include "../storage_settings.h"
#include <furi_hal.h> #include <furi_hal.h>
#include <notification/notification.h>
#include <notification/notification_messages.h>
#define BENCH_DATA_SIZE 4096 #define BENCH_DATA_SIZE 4096
#define BENCH_COUNT 6 #define BENCH_COUNT 6
@ -86,7 +88,8 @@ static void storage_settings_scene_benchmark(StorageSettings* app) {
uint32_t bench_w_speed[BENCH_COUNT] = {0, 0, 0, 0, 0, 0}; uint32_t bench_w_speed[BENCH_COUNT] = {0, 0, 0, 0, 0, 0};
uint32_t bench_r_speed[BENCH_COUNT] = {0, 0, 0, 0, 0, 0}; uint32_t bench_r_speed[BENCH_COUNT] = {0, 0, 0, 0, 0, 0};
dialog_ex_set_header(dialog_ex, "Benchmarking...", 64, 32, AlignCenter, AlignCenter); dialog_ex_set_header(dialog_ex, "Benchmarking...", 74, 32, AlignCenter, AlignCenter);
dialog_ex_set_icon(dialog_ex, 12, 20, &I_LoadingHourglass_24x24);
for(size_t i = 0; i < BENCH_COUNT; i++) { for(size_t i = 0; i < BENCH_COUNT; i++) {
if(!storage_settings_scene_bench_write( if(!storage_settings_scene_bench_write(
app->fs_api, bench_size[i], bench_data, &bench_w_speed[i])) app->fs_api, bench_size[i], bench_data, &bench_w_speed[i]))
@ -95,6 +98,7 @@ static void storage_settings_scene_benchmark(StorageSettings* app) {
if(i > 0) furi_string_cat_printf(app->text_string, "\n"); if(i > 0) furi_string_cat_printf(app->text_string, "\n");
furi_string_cat_printf(app->text_string, "%ub : W %luK ", bench_size[i], bench_w_speed[i]); furi_string_cat_printf(app->text_string, "%ub : W %luK ", bench_size[i], bench_w_speed[i]);
dialog_ex_set_header(dialog_ex, NULL, 0, 0, AlignCenter, AlignCenter); dialog_ex_set_header(dialog_ex, NULL, 0, 0, AlignCenter, AlignCenter);
dialog_ex_set_icon(dialog_ex, 0, 0, NULL);
dialog_ex_set_text( dialog_ex_set_text(
dialog_ex, furi_string_get_cstr(app->text_string), 0, 32, AlignLeft, AlignCenter); dialog_ex, furi_string_get_cstr(app->text_string), 0, 32, AlignLeft, AlignCenter);
@ -110,6 +114,12 @@ static void storage_settings_scene_benchmark(StorageSettings* app) {
dialog_ex, furi_string_get_cstr(app->text_string), 0, 32, AlignLeft, AlignCenter); dialog_ex, furi_string_get_cstr(app->text_string), 0, 32, AlignLeft, AlignCenter);
} }
NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
notification_message(notification, &sequence_single_vibro);
notification_message(notification, &sequence_set_green_255);
notification_message(notification, &sequence_success);
furi_record_close(RECORD_NOTIFICATION);
free(bench_data); free(bench_data);
} }
@ -146,12 +156,18 @@ bool storage_settings_scene_benchmark_on_event(void* context, SceneManagerEvent
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
switch(event.event) { switch(event.event) {
case DialogExResultCenter: case DialogExResultCenter:
consumed = scene_manager_previous_scene(app->scene_manager); consumed = scene_manager_search_and_switch_to_previous_scene(
app->scene_manager, StorageSettingsStart);
break; break;
} }
} else if(event.type == SceneManagerEventTypeBack && sd_status != FSE_OK) { } else if(event.type == SceneManagerEventTypeBack) {
if(sd_status == FSE_OK) {
consumed = scene_manager_search_and_switch_to_previous_scene(
app->scene_manager, StorageSettingsStart);
} else {
consumed = true; consumed = true;
} }
}
return consumed; return consumed;
} }
@ -160,6 +176,10 @@ void storage_settings_scene_benchmark_on_exit(void* context) {
StorageSettings* app = context; StorageSettings* app = context;
DialogEx* dialog_ex = app->dialog_ex; DialogEx* dialog_ex = app->dialog_ex;
NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
notification_message(notification, &sequence_reset_green);
furi_record_close(RECORD_NOTIFICATION);
dialog_ex_reset(dialog_ex); dialog_ex_reset(dialog_ex);
furi_string_reset(app->text_string); furi_string_reset(app->text_string);

View file

@ -0,0 +1,70 @@
#include "../storage_settings.h"
static void
storage_settings_scene_benchmark_confirm_dialog_callback(DialogExResult result, void* context) {
StorageSettings* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, result);
}
void storage_settings_scene_benchmark_confirm_on_enter(void* context) {
StorageSettings* app = context;
DialogEx* dialog_ex = app->dialog_ex;
FS_Error sd_status = storage_sd_status(app->fs_api);
if(sd_status == FSE_NOT_READY) {
dialog_ex_set_icon(dialog_ex, 83, 22, &I_WarningDolphinFlip_45x42);
dialog_ex_set_header(dialog_ex, "SD Card Not Mounted", 64, 3, AlignCenter, AlignTop);
dialog_ex_set_text(
dialog_ex, "Try to reinsert\nor format SD\ncard.", 3, 19, AlignLeft, AlignTop);
dialog_ex_set_center_button_text(dialog_ex, "Ok");
} else {
dialog_ex_set_header(dialog_ex, "Benchmark SD Card?", 64, 0, AlignCenter, AlignTop);
dialog_ex_set_text(
dialog_ex,
"SD will be tested in SPI\nmode. Learn more:\nr.flipper.net/sd_test",
0,
12,
AlignLeft,
AlignTop);
dialog_ex_set_icon(dialog_ex, 103, 12, &I_qr_benchmark_25x25);
dialog_ex_set_left_button_text(dialog_ex, "Cancel");
dialog_ex_set_right_button_text(dialog_ex, "Benchmark");
}
dialog_ex_set_context(dialog_ex, app);
dialog_ex_set_result_callback(
dialog_ex, storage_settings_scene_benchmark_confirm_dialog_callback);
view_dispatcher_switch_to_view(app->view_dispatcher, StorageSettingsViewDialogEx);
}
bool storage_settings_scene_benchmark_confirm_on_event(void* context, SceneManagerEvent event) {
StorageSettings* app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
switch(event.event) {
case DialogExResultLeft:
case DialogExResultCenter:
consumed = scene_manager_previous_scene(app->scene_manager);
break;
case DialogExResultRight:
scene_manager_next_scene(app->scene_manager, StorageSettingsBenchmark);
consumed = true;
break;
}
} else if(event.type == SceneManagerEventTypeBack) {
consumed = true;
}
return consumed;
}
void storage_settings_scene_benchmark_confirm_on_exit(void* context) {
StorageSettings* app = context;
DialogEx* dialog_ex = app->dialog_ex;
dialog_ex_reset(dialog_ex);
}

View file

@ -5,5 +5,6 @@ ADD_SCENE(storage_settings, format_confirm, FormatConfirm)
ADD_SCENE(storage_settings, formatting, Formatting) ADD_SCENE(storage_settings, formatting, Formatting)
ADD_SCENE(storage_settings, sd_info, SDInfo) ADD_SCENE(storage_settings, sd_info, SDInfo)
ADD_SCENE(storage_settings, internal_info, InternalInfo) ADD_SCENE(storage_settings, internal_info, InternalInfo)
ADD_SCENE(storage_settings, benchmark_confirm, BenchmarkConfirm)
ADD_SCENE(storage_settings, benchmark, Benchmark) ADD_SCENE(storage_settings, benchmark, Benchmark)
ADD_SCENE(storage_settings, factory_reset, FactoryReset) ADD_SCENE(storage_settings, factory_reset, FactoryReset)

View file

@ -21,14 +21,14 @@ void storage_settings_scene_factory_reset_on_enter(void* context) {
dialog_ex_set_left_button_text(dialog_ex, "Cancel"); dialog_ex_set_left_button_text(dialog_ex, "Cancel");
dialog_ex_set_right_button_text(dialog_ex, "Erase"); dialog_ex_set_right_button_text(dialog_ex, "Erase");
dialog_ex_set_header(dialog_ex, "Confirm Factory Reset", 64, 10, AlignCenter, AlignCenter); dialog_ex_set_header(dialog_ex, "Confirm Factory Reset?", 64, 0, AlignCenter, AlignTop);
dialog_ex_set_text( dialog_ex_set_text(
dialog_ex, dialog_ex,
"Internal storage will be erased\r\nData and settings will be lost!", "Internal storage will be erased\ndata and settings will be lost!",
64, 64,
32, 14,
AlignCenter, AlignCenter,
AlignCenter); AlignTop);
view_dispatcher_switch_to_view(app->view_dispatcher, StorageSettingsViewDialogEx); view_dispatcher_switch_to_view(app->view_dispatcher, StorageSettingsViewDialogEx);
} }

View file

@ -20,8 +20,8 @@ void storage_settings_scene_format_confirm_on_enter(void* context) {
dialog_ex, "Try to reinsert\nor format SD\ncard.", 3, 19, AlignLeft, AlignTop); dialog_ex, "Try to reinsert\nor format SD\ncard.", 3, 19, AlignLeft, AlignTop);
dialog_ex_set_center_button_text(dialog_ex, "Ok"); dialog_ex_set_center_button_text(dialog_ex, "Ok");
} else { } else {
dialog_ex_set_header(dialog_ex, "Format SD Card?", 64, 10, AlignCenter, AlignCenter); dialog_ex_set_header(dialog_ex, "Format SD Card?", 64, 0, AlignCenter, AlignTop);
dialog_ex_set_text(dialog_ex, "All data will be lost!", 64, 32, AlignCenter, AlignCenter); dialog_ex_set_text(dialog_ex, "All data will be lost!", 64, 12, AlignCenter, AlignTop);
dialog_ex_set_left_button_text(dialog_ex, "Cancel"); dialog_ex_set_left_button_text(dialog_ex, "Cancel");
dialog_ex_set_right_button_text(dialog_ex, "Format"); dialog_ex_set_right_button_text(dialog_ex, "Format");
} }

View file

@ -1,4 +1,6 @@
#include "../storage_settings.h" #include "../storage_settings.h"
#include <notification/notification.h>
#include <notification/notification_messages.h>
static const NotificationMessage message_green_165 = { static const NotificationMessage message_green_165 = {
.type = NotificationMessageTypeLedGreen, .type = NotificationMessageTypeLedGreen,
@ -31,7 +33,8 @@ void storage_settings_scene_formatting_on_enter(void* context) {
FS_Error error; FS_Error error;
DialogEx* dialog_ex = app->dialog_ex; DialogEx* dialog_ex = app->dialog_ex;
dialog_ex_set_header(dialog_ex, "Formatting...", 64, 32, AlignCenter, AlignCenter); dialog_ex_set_header(dialog_ex, "Formatting...", 70, 32, AlignCenter, AlignCenter);
dialog_ex_set_icon(dialog_ex, 15, 20, &I_LoadingHourglass_24x24);
view_dispatcher_switch_to_view(app->view_dispatcher, StorageSettingsViewDialogEx); view_dispatcher_switch_to_view(app->view_dispatcher, StorageSettingsViewDialogEx);
notification_message_block(app->notification, &sequence_set_formatting_leds); notification_message_block(app->notification, &sequence_set_formatting_leds);
@ -44,11 +47,17 @@ void storage_settings_scene_formatting_on_enter(void* context) {
if(error != FSE_OK) { if(error != FSE_OK) {
dialog_ex_set_header(dialog_ex, "Cannot Format SD Card", 64, 10, AlignCenter, AlignCenter); dialog_ex_set_header(dialog_ex, "Cannot Format SD Card", 64, 10, AlignCenter, AlignCenter);
dialog_ex_set_icon(dialog_ex, 0, 0, NULL);
dialog_ex_set_text( dialog_ex_set_text(
dialog_ex, storage_error_get_desc(error), 64, 32, AlignCenter, AlignCenter); dialog_ex, storage_error_get_desc(error), 64, 32, AlignCenter, AlignCenter);
} else { } else {
dialog_ex_set_icon(dialog_ex, 83, 22, &I_WarningDolphinFlip_45x42); dialog_ex_set_icon(dialog_ex, 83, 22, &I_WarningDolphinFlip_45x42);
dialog_ex_set_header(dialog_ex, "Format\ncomplete!", 14, 15, AlignLeft, AlignTop); dialog_ex_set_header(dialog_ex, "Format\ncomplete!", 14, 15, AlignLeft, AlignTop);
NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
notification_message(notification, &sequence_single_vibro);
notification_message(notification, &sequence_set_green_255);
notification_message(notification, &sequence_success);
furi_record_close(RECORD_NOTIFICATION);
} }
dialog_ex_set_center_button_text(dialog_ex, "OK"); dialog_ex_set_center_button_text(dialog_ex, "OK");
} }
@ -75,5 +84,9 @@ void storage_settings_scene_formatting_on_exit(void* context) {
StorageSettings* app = context; StorageSettings* app = context;
DialogEx* dialog_ex = app->dialog_ex; DialogEx* dialog_ex = app->dialog_ex;
NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
notification_message(notification, &sequence_reset_green);
furi_record_close(RECORD_NOTIFICATION);
dialog_ex_reset(dialog_ex); dialog_ex_reset(dialog_ex);
} }

View file

@ -27,7 +27,7 @@ void storage_settings_scene_internal_info_on_enter(void* context) {
} else { } else {
furi_string_printf( furi_string_printf(
app->text_string, app->text_string,
"Label: %s\nType: LittleFS\n%lu KiB total\n%lu KiB free", "Name: %s\nType: LittleFS\nTotal: %lu KiB\nFree: %lu KiB",
furi_hal_version_get_name_ptr() ? furi_hal_version_get_name_ptr() : "Unknown", furi_hal_version_get_name_ptr() ? furi_hal_version_get_name_ptr() : "Unknown",
(uint32_t)(total_space / 1024), (uint32_t)(total_space / 1024),
(uint32_t)(free_space / 1024)); (uint32_t)(free_space / 1024));

View file

@ -27,12 +27,31 @@ void storage_settings_scene_sd_info_on_enter(void* context) {
} else { } else {
furi_string_printf( furi_string_printf(
app->text_string, app->text_string,
"Label: %s\nType: %s\n%lu KiB total\n%lu KiB free\n" "Label: %s\nType: %s\n",
"%02X%s %s v%i.%i\nSN:%04lX %02i/%i",
sd_info.label, sd_info.label,
sd_api_get_fs_type_text(sd_info.fs_type), sd_api_get_fs_type_text(sd_info.fs_type));
sd_info.kb_total,
sd_info.kb_free, if(sd_info.kb_total < 1024) {
furi_string_cat_printf(app->text_string, "Total: %lu KiB\n", sd_info.kb_total);
} else if(sd_info.kb_total < 1024 * 1024) {
furi_string_cat_printf(app->text_string, "Total: %lu MiB\n", sd_info.kb_total / 1024);
} else {
furi_string_cat_printf(
app->text_string, "Total: %lu GiB\n", sd_info.kb_total / (1024 * 1024));
}
if(sd_info.kb_free < 1024) {
furi_string_cat_printf(app->text_string, "Free: %lu KiB\n", sd_info.kb_free);
} else if(sd_info.kb_free < 1024 * 1024) {
furi_string_cat_printf(app->text_string, "Free: %lu MiB\n", sd_info.kb_free / 1024);
} else {
furi_string_cat_printf(
app->text_string, "Free: %lu GiB\n", sd_info.kb_free / (1024 * 1024));
}
furi_string_cat_printf(
app->text_string,
"%02X%s %s v%i.%i\nSN:%04lX %02i/%i",
sd_info.manufacturer_id, sd_info.manufacturer_id,
sd_info.oem_id, sd_info.oem_id,
sd_info.product_name, sd_info.product_name,
@ -41,6 +60,7 @@ void storage_settings_scene_sd_info_on_enter(void* context) {
sd_info.product_serial_number, sd_info.product_serial_number,
sd_info.manufacturing_month, sd_info.manufacturing_month,
sd_info.manufacturing_year); sd_info.manufacturing_year);
dialog_ex_set_text( dialog_ex_set_text(
dialog_ex, furi_string_get_cstr(app->text_string), 4, 1, AlignLeft, AlignTop); dialog_ex, furi_string_get_cstr(app->text_string), 4, 1, AlignLeft, AlignTop);
} }

View file

@ -109,7 +109,7 @@ bool storage_settings_scene_start_on_event(void* context, SceneManagerEvent even
case StorageSettingsStartSubmenuIndexBenchy: case StorageSettingsStartSubmenuIndexBenchy:
scene_manager_set_scene_state( scene_manager_set_scene_state(
app->scene_manager, StorageSettingsStart, StorageSettingsStartSubmenuIndexBenchy); app->scene_manager, StorageSettingsStart, StorageSettingsStartSubmenuIndexBenchy);
scene_manager_next_scene(app->scene_manager, StorageSettingsBenchmark); scene_manager_next_scene(app->scene_manager, StorageSettingsBenchmarkConfirm);
consumed = true; consumed = true;
break; break;
case StorageSettingsStartSubmenuIndexFactoryReset: case StorageSettingsStartSubmenuIndexFactoryReset:

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View file

@ -0,0 +1,14 @@
Filetype: Flipper Animation
Version: 1
Width: 128
Height: 64
Passive frames: 15
Active frames: 21
Frames order: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
Active cycles: 1
Frame rate: 2
Duration: 3600
Active cooldown: 7
Bubble slots: 0

View file

@ -190,6 +190,13 @@ Min level: 3
Max level: 3 Max level: 3
Weight: 5 Weight: 5
Name: L1_Akira_128x64
Min butthurt: 0
Max butthurt: 8
Min level: 1
Max level: 3
Weight: 5
Name: L3_Fireplace_128x64 Name: L3_Fireplace_128x64
Min butthurt: 0 Min butthurt: 0
Max butthurt: 13 Max butthurt: 13

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 973 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 395 B

View file

@ -381,7 +381,7 @@ static GapConfig template_config = {
.conn_param = .conn_param =
{ {
.conn_int_min = 0x18, // AN5289: 4.7, we need at least 25ms + advertisement, which is 30 ms .conn_int_min = 0x18, // AN5289: 4.7, we need at least 25ms + advertisement, which is 30 ms
.conn_int_max = 0x18, // 30 ms .conn_int_max = 0x24, // 45 ms
.slave_latency = 0, .slave_latency = 0,
.supervisor_timeout = 0, .supervisor_timeout = 0,
}, },

View file

@ -202,6 +202,7 @@ __attribute__((unused)) static const char* elf_reloc_type_to_str(int symt) {
STRCASE(R_ARM_NONE) STRCASE(R_ARM_NONE)
STRCASE(R_ARM_TARGET1) STRCASE(R_ARM_TARGET1)
STRCASE(R_ARM_ABS32) STRCASE(R_ARM_ABS32)
STRCASE(R_ARM_REL32)
STRCASE(R_ARM_THM_PC22) STRCASE(R_ARM_THM_PC22)
STRCASE(R_ARM_THM_JUMP24) STRCASE(R_ARM_THM_JUMP24)
default: default:
@ -329,6 +330,10 @@ static bool elf_relocate_symbol(ELFFile* elf, Elf32_Addr relAddr, int type, Elf3
*((uint32_t*)relAddr) += symAddr; *((uint32_t*)relAddr) += symAddr;
FURI_LOG_D(TAG, " R_ARM_ABS32 relocated is 0x%08X", (unsigned int)*((uint32_t*)relAddr)); FURI_LOG_D(TAG, " R_ARM_ABS32 relocated is 0x%08X", (unsigned int)*((uint32_t*)relAddr));
break; break;
case R_ARM_REL32:
*((uint32_t*)relAddr) += symAddr - relAddr;
FURI_LOG_D(TAG, " R_ARM_REL32 relocated is 0x%08X", (unsigned int)*((uint32_t*)relAddr));
break;
case R_ARM_THM_PC22: case R_ARM_THM_PC22:
case R_ARM_CALL: case R_ARM_CALL:
case R_ARM_THM_JUMP24: case R_ARM_THM_JUMP24:

View file

@ -75,7 +75,7 @@ MfDesfireError mf_desfire_send_chunks(
const size_t rx_capacity_remaining = const size_t rx_capacity_remaining =
bit_buffer_get_capacity_bytes(rx_buffer) - bit_buffer_get_size_bytes(rx_buffer); bit_buffer_get_capacity_bytes(rx_buffer) - bit_buffer_get_size_bytes(rx_buffer);
if(rx_size - 1 <= rx_capacity_remaining) { if(rx_size <= rx_capacity_remaining + 1) {
bit_buffer_append_right(rx_buffer, instance->rx_buffer, sizeof(uint8_t)); bit_buffer_append_right(rx_buffer, instance->rx_buffer, sizeof(uint8_t));
} else { } else {
FURI_LOG_W(TAG, "RX buffer overflow: ignoring %zu bytes", rx_size - 1); FURI_LOG_W(TAG, "RX buffer overflow: ignoring %zu bytes", rx_size - 1);

86
scripts/map_analyse_upload.py Executable file
View file

@ -0,0 +1,86 @@
#!/usr/bin/env python3
import os
import requests
import argparse
import subprocess
# usage:
# COMMIT_HASH, COMMIT_MSG, BRANCH_NAME,
# PULL_ID(optional), PULL_NAME(optional) must be set as envs
# maybe from sctipts/get_env.py
# other args must be set via command line args
class AnalyseRequest:
def __init__(self):
self.commit_hash = os.environ["COMMIT_HASH"]
self.commit_msg = os.environ["COMMIT_MSG"]
self.branch_name = os.environ["BRANCH_NAME"]
self.pull_id = os.getenv("PULL_ID", default=None)
self.pull_name = os.getenv("PULL_NAME", default=None)
def get_payload(self):
return vars(self)
class AnalyseUploader:
def __init__(self):
self.args = self.parse_args()
@staticmethod
def get_sections_size(elf_file) -> dict:
ret = dict()
all_sizes = subprocess.check_output(
["arm-none-eabi-size", "-A", elf_file], shell=False
)
all_sizes = all_sizes.splitlines()
sections_to_keep = (".text", ".rodata", ".data", ".bss", ".free_flash")
for line in all_sizes:
line = line.decode("utf-8")
parts = line.split()
if len(parts) != 3:
continue
section, size, _ = parts
if section not in sections_to_keep:
continue
section_size_payload_name = (
section[1:] if section.startswith(".") else section
)
section_size_payload_name += "_size"
ret[section_size_payload_name] = size
return ret
@staticmethod
def parse_args():
parser = argparse.ArgumentParser()
parser.add_argument("--elf_file", help="Firmware ELF file", required=True)
parser.add_argument("--map_file", help="Firmware MAP file", required=True)
parser.add_argument(
"--analyser_token", help="Analyser auth token", required=True
)
parser.add_argument(
"--analyser_url", help="Analyser analyse url", required=True
)
args = parser.parse_args()
return args
def upload_analyse_request(self):
payload = AnalyseRequest().get_payload() | self.get_sections_size(
self.args.elf_file
)
headers = {"Authorization": f"Bearer {self.args.analyser_token}"}
file = {"map_file": open(self.args.map_file, "rb")}
response = requests.post(
self.args.analyser_url, data=payload, files=file, headers=headers
)
if not response.ok:
raise Exception(
f"Failed to upload map file, code: {response.status_code}, reason: {response.text}"
)
if __name__ == "__main__":
analyzer = AnalyseUploader()
analyzer.upload_analyse_request()

View file

@ -1,139 +0,0 @@
#!/usr/bin/env python3
# Requiremets:
# mariadb==1.1.6
from datetime import datetime
import argparse
import mariadb
import sys
import os
def parseArgs():
parser = argparse.ArgumentParser()
parser.add_argument("db_user", help="MariaDB user")
parser.add_argument("db_pass", help="MariaDB password")
parser.add_argument("db_host", help="MariaDB hostname")
parser.add_argument("db_port", type=int, help="MariaDB port")
parser.add_argument("db_name", help="MariaDB database")
parser.add_argument("report_file", help="Report file(.map.all)")
args = parser.parse_args()
return args
def mariadbConnect(args):
try:
conn = mariadb.connect(
user=args.db_user,
password=args.db_pass,
host=args.db_host,
port=args.db_port,
database=args.db_name,
)
except mariadb.Error as e:
print(f"Error connecting to MariaDB: {e}")
sys.exit(1)
return conn
def parseEnv():
outArr = []
outArr.append(datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
outArr.append(os.getenv("COMMIT_HASH", default=None))
outArr.append(os.getenv("COMMIT_MSG", default=None))
outArr.append(os.getenv("BRANCH_NAME", default=None))
outArr.append(os.getenv("BSS_SIZE", default=None))
outArr.append(os.getenv("TEXT_SIZE", default=None))
outArr.append(os.getenv("RODATA_SIZE", default=None))
outArr.append(os.getenv("DATA_SIZE", default=None))
outArr.append(os.getenv("FREE_FLASH_SIZE", default=None))
outArr.append(os.getenv("PULL_ID", default=None))
outArr.append(os.getenv("PULL_NAME", default=None))
return outArr
def createTables(cur, conn):
headerTable = "CREATE TABLE IF NOT EXISTS `header` ( \
`id` int(10) unsigned NOT NULL AUTO_INCREMENT, \
`datetime` datetime NOT NULL, \
`commit` varchar(40) NOT NULL, \
`commit_msg` text NOT NULL, \
`branch_name` text NOT NULL, \
`bss_size` int(10) unsigned NOT NULL, \
`text_size` int(10) unsigned NOT NULL, \
`rodata_size` int(10) unsigned NOT NULL, \
`data_size` int(10) unsigned NOT NULL, \
`free_flash_size` int(10) unsigned NOT NULL, \
`pullrequest_id` int(10) unsigned DEFAULT NULL, \
`pullrequest_name` text DEFAULT NULL, \
PRIMARY KEY (`id`), \
KEY `header_id_index` (`id`) )"
dataTable = "CREATE TABLE IF NOT EXISTS `data` ( \
`header_id` int(10) unsigned NOT NULL, \
`id` int(10) unsigned NOT NULL AUTO_INCREMENT, \
`section` text NOT NULL, \
`address` text NOT NULL, \
`size` int(10) unsigned NOT NULL, \
`name` text NOT NULL, \
`lib` text NOT NULL, \
`obj_name` text NOT NULL, \
PRIMARY KEY (`id`), \
KEY `data_id_index` (`id`), \
KEY `data_header_id_index` (`header_id`), \
CONSTRAINT `data_header_id_foreign` FOREIGN KEY (`header_id`) REFERENCES `header` (`id`) )"
cur.execute(headerTable)
cur.execute(dataTable)
conn.commit()
def insertHeader(data, cur, conn):
query = "INSERT INTO `header` ( \
datetime, commit, commit_msg, branch_name, bss_size, text_size, \
rodata_size, data_size, free_flash_size, pullrequest_id, pullrequest_name) \
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
cur.execute(query, data)
conn.commit()
return cur.lastrowid
def parseFile(fileObj, headerID):
arr = []
fileLines = fileObj.readlines()
for line in fileLines:
lineArr = []
tempLineArr = line.split("\t")
lineArr.append(headerID)
lineArr.append(tempLineArr[0]) # section
lineArr.append(int(tempLineArr[2], 16)) # address hex
lineArr.append(int(tempLineArr[3])) # size
lineArr.append(tempLineArr[4]) # name
lineArr.append(tempLineArr[5]) # lib
lineArr.append(tempLineArr[6]) # obj_name
arr.append(tuple(lineArr))
return arr
def insertData(data, cur, conn):
query = "INSERT INTO `data` ( \
header_id, section, address, size, \
name, lib, obj_name) \
VALUES (?, ?, ?, ?, ? ,?, ?)"
cur.executemany(query, data)
conn.commit()
def main():
args = parseArgs()
dbConn = mariadbConnect(args)
reportFile = open(args.report_file)
dbCurs = dbConn.cursor()
createTables(dbCurs, dbConn)
headerID = insertHeader(parseEnv(), dbCurs, dbConn)
insertData(parseFile(reportFile, headerID), dbCurs, dbConn)
reportFile.close()
dbCurs.close()
if __name__ == "__main__":
main()

View file

@ -1,274 +0,0 @@
#!/usr/bin/env python3
# Requiremets:
# cxxfilt==0.3.0
# Most part of this code written by Lars-Dominik Braun <lars@6xq.net> https://github.com/PromyLOPh/linkermapviz
# and distributes under MIT licence
# Copyright (c) 2017 Lars-Dominik Braun <lars@6xq.net>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
import sys
import re
import os
from typing import TextIO
from cxxfilt import demangle
class Objectfile:
def __init__(self, section: str, offset: int, size: int, comment: str):
self.section = section.strip()
self.offset = offset
self.size = size
self.path = (None, None)
self.basepath = None
if comment:
self.path = re.match(r"^(.+?)(?:\(([^\)]+)\))?$", comment).groups()
self.basepath = os.path.basename(self.path[0])
self.children = []
def __repr__(self) -> str:
return f"<Objectfile {self.section} {self.offset:x} {self.size:x} {self.path} {repr(self.children)}>"
def update_children_size(children: list[list], subsection_size: int) -> list:
# set subsection size to an only child
if len(children) == 1:
children[0][1] = subsection_size
return children
rest_size = subsection_size
for index in range(1, len(children)):
if rest_size > 0:
# current size = current address - previous child address
child_size = children[index][0] - children[index - 1][0]
rest_size -= child_size
children[index - 1][1] = child_size
# if there is rest size, set it to the last child element
if rest_size > 0:
children[-1][1] = rest_size
return children
def parse_sections(file_name: str) -> list:
"""
Quick&Dirty parsing for GNU lds linker map output, needs LANG=C, because
some messages are localized.
"""
sections = []
with open(file_name, "r") as file:
# skip until memory map is found
found = False
while True:
line = file.readline()
if not line:
break
if line.strip() == "Memory Configuration":
found = True
break
if not found:
raise Exception(f"Memory configuration is not found in the{input_file}")
# long section names result in a linebreak afterwards
sectionre = re.compile(
"(?P<section>.+?|.{14,}\n)[ ]+0x(?P<offset>[0-9a-f]+)[ ]+0x(?P<size>[0-9a-f]+)(?:[ ]+(?P<comment>.+))?\n+",
re.I,
)
subsectionre = re.compile(
"[ ]{16}0x(?P<offset>[0-9a-f]+)[ ]+(?P<function>.+)\n+", re.I
)
s = file.read()
pos = 0
while True:
m = sectionre.match(s, pos)
if not m:
# skip that line
try:
nextpos = s.index("\n", pos) + 1
pos = nextpos
continue
except ValueError:
break
pos = m.end()
section = m.group("section")
v = m.group("offset")
offset = int(v, 16) if v is not None else None
v = m.group("size")
size = int(v, 16) if v is not None else None
comment = m.group("comment")
if section != "*default*" and size > 0:
of = Objectfile(section, offset, size, comment)
if section.startswith(" "):
children = []
sections[-1].children.append(of)
while True:
m = subsectionre.match(s, pos)
if not m:
break
pos = m.end()
offset, function = m.groups()
offset = int(offset, 16)
if sections and sections[-1].children:
children.append([offset, 0, function])
if children:
children = update_children_size(
children=children, subsection_size=of.size
)
sections[-1].children[-1].children.extend(children)
else:
sections.append(of)
return sections
def get_subsection_name(section_name: str, subsection: Objectfile) -> str:
subsection_split_names = subsection.section.split(".")
if subsection.section.startswith("."):
subsection_split_names = subsection_split_names[1:]
return (
f".{subsection_split_names[1]}"
if len(subsection_split_names) > 2
else section_name
)
def write_subsection(
section_name: str,
subsection_name: str,
address: str,
size: int,
demangled_name: str,
module_name: str,
file_name: str,
mangled_name: str,
write_file_object: TextIO,
) -> None:
write_file_object.write(
f"{section_name}\t"
f"{subsection_name}\t"
f"{address}\t"
f"{size}\t"
f"{demangled_name}\t"
f"{module_name}\t"
f"{file_name}\t"
f"{mangled_name}\n"
)
def save_subsection(
section_name: str, subsection: Objectfile, write_file_object: TextIO
) -> None:
subsection_name = get_subsection_name(section_name, subsection)
module_name = subsection.path[0]
file_name = subsection.path[1]
if not file_name:
file_name, module_name = module_name, ""
if not subsection.children:
address = f"{subsection.offset:x}"
size = subsection.size
mangled_name = (
""
if subsection.section == section_name
else subsection.section.split(".")[-1]
)
demangled_name = demangle(mangled_name) if mangled_name else mangled_name
write_subsection(
section_name=section_name,
subsection_name=subsection_name,
address=address,
size=size,
demangled_name=demangled_name,
module_name=module_name,
file_name=file_name,
mangled_name=mangled_name,
write_file_object=write_file_object,
)
return
for subsection_child in subsection.children:
address = f"{subsection_child[0]:x}"
size = subsection_child[1]
mangled_name = subsection_child[2]
demangled_name = demangle(mangled_name)
write_subsection(
section_name=section_name,
subsection_name=subsection_name,
address=address,
size=size,
demangled_name=demangled_name,
module_name=module_name,
file_name=file_name,
mangled_name=mangled_name,
write_file_object=write_file_object,
)
def save_section(section: Objectfile, write_file_object: TextIO) -> None:
section_name = section.section
for subsection in section.children:
save_subsection(
section_name=section_name,
subsection=subsection,
write_file_object=write_file_object,
)
def save_parsed_data(parsed_data: list[Objectfile], output_file_name: str) -> None:
with open(output_file_name, "w") as write_file_object:
for section in parsed_data:
if section.children:
save_section(section=section, write_file_object=write_file_object)
if __name__ == "__main__":
if len(sys.argv) < 3:
raise Exception(f"Usage: {sys.argv[0]} <input file> <output file>")
input_file = sys.argv[1]
output_file = sys.argv[2]
parsed_sections = parse_sections(input_file)
if parsed_sections is None:
raise Exception(f"Memory configuration is not {input_file}")
save_parsed_data(parsed_sections, output_file)

View file

@ -1,5 +1,5 @@
entry,status,name,type,params entry,status,name,type,params
Version,+,61.2,, Version,+,61.3,,
Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt.h,,
Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli.h,,
Header,+,applications/services/cli/cli_vcp.h,, Header,+,applications/services/cli/cli_vcp.h,,
@ -2554,7 +2554,9 @@ Function,-,strxfrm,size_t,"char*, const char*, size_t"
Function,-,strxfrm_l,size_t,"char*, const char*, size_t, locale_t" Function,-,strxfrm_l,size_t,"char*, const char*, size_t, locale_t"
Function,+,submenu_add_item,void,"Submenu*, const char*, uint32_t, SubmenuItemCallback, void*" Function,+,submenu_add_item,void,"Submenu*, const char*, uint32_t, SubmenuItemCallback, void*"
Function,+,submenu_alloc,Submenu*, Function,+,submenu_alloc,Submenu*,
Function,+,submenu_change_item_label,void,"Submenu*, uint32_t, const char*"
Function,+,submenu_free,void,Submenu* Function,+,submenu_free,void,Submenu*
Function,+,submenu_get_selected_item,uint32_t,Submenu*
Function,+,submenu_get_view,View*,Submenu* Function,+,submenu_get_view,View*,Submenu*
Function,+,submenu_reset,void,Submenu* Function,+,submenu_reset,void,Submenu*
Function,+,submenu_set_header,void,"Submenu*, const char*" Function,+,submenu_set_header,void,"Submenu*, const char*"

1 entry status name type params
2 Version + 61.2 61.3
3 Header + applications/services/bt/bt_service/bt.h
4 Header + applications/services/cli/cli.h
5 Header + applications/services/cli/cli_vcp.h
2554 Function - strxfrm_l size_t char*, const char*, size_t, locale_t
2555 Function + submenu_add_item void Submenu*, const char*, uint32_t, SubmenuItemCallback, void*
2556 Function + submenu_alloc Submenu*
2557 Function + submenu_change_item_label void Submenu*, uint32_t, const char*
2558 Function + submenu_free void Submenu*
2559 Function + submenu_get_selected_item uint32_t Submenu*
2560 Function + submenu_get_view View* Submenu*
2561 Function + submenu_reset void Submenu*
2562 Function + submenu_set_header void Submenu*, const char*

View file

@ -17,6 +17,7 @@ void furi_hal_init_early(void) {
furi_hal_i2c_init_early(); furi_hal_i2c_init_early();
furi_hal_light_init(); furi_hal_light_init();
furi_hal_rtc_init_early(); furi_hal_rtc_init_early();
furi_hal_version_init();
} }
void furi_hal_deinit_early(void) { void furi_hal_deinit_early(void) {
@ -39,7 +40,6 @@ void furi_hal_init(void) {
furi_hal_interrupt_init(); furi_hal_interrupt_init();
furi_hal_flash_init(); furi_hal_flash_init();
furi_hal_resources_init(); furi_hal_resources_init();
furi_hal_version_init();
furi_hal_spi_config_init(); furi_hal_spi_config_init();
furi_hal_spi_dma_init(); furi_hal_spi_dma_init();
furi_hal_speaker_init(); furi_hal_speaker_init();

View file

@ -1,5 +1,5 @@
entry,status,name,type,params entry,status,name,type,params
Version,+,61.2,, Version,+,61.3,,
Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,,
Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt.h,,
Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli.h,,
@ -3426,7 +3426,9 @@ Function,+,subghz_worker_stop,void,SubGhzWorker*
Function,+,submenu_add_item,void,"Submenu*, const char*, uint32_t, SubmenuItemCallback, void*" Function,+,submenu_add_item,void,"Submenu*, const char*, uint32_t, SubmenuItemCallback, void*"
Function,+,submenu_add_lockable_item,void,"Submenu*, const char*, uint32_t, SubmenuItemCallback, void*, _Bool, const char*" Function,+,submenu_add_lockable_item,void,"Submenu*, const char*, uint32_t, SubmenuItemCallback, void*, _Bool, const char*"
Function,+,submenu_alloc,Submenu*, Function,+,submenu_alloc,Submenu*,
Function,+,submenu_change_item_label,void,"Submenu*, uint32_t, const char*"
Function,+,submenu_free,void,Submenu* Function,+,submenu_free,void,Submenu*
Function,+,submenu_get_selected_item,uint32_t,Submenu*
Function,+,submenu_get_view,View*,Submenu* Function,+,submenu_get_view,View*,Submenu*
Function,+,submenu_reset,void,Submenu* Function,+,submenu_reset,void,Submenu*
Function,+,submenu_set_header,void,"Submenu*, const char*" Function,+,submenu_set_header,void,"Submenu*, const char*"

1 entry status name type params
2 Version + 61.2 61.3
3 Header + applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h
4 Header + applications/services/bt/bt_service/bt.h
5 Header + applications/services/cli/cli.h
3426 Function + submenu_add_item void Submenu*, const char*, uint32_t, SubmenuItemCallback, void*
3427 Function + submenu_add_lockable_item void Submenu*, const char*, uint32_t, SubmenuItemCallback, void*, _Bool, const char*
3428 Function + submenu_alloc Submenu*
3429 Function + submenu_change_item_label void Submenu*, uint32_t, const char*
3430 Function + submenu_free void Submenu*
3431 Function + submenu_get_selected_item uint32_t Submenu*
3432 Function + submenu_get_view View* Submenu*
3433 Function + submenu_reset void Submenu*
3434 Function + submenu_set_header void Submenu*, const char*

View file

@ -40,6 +40,8 @@ typedef struct {
FuriThread* thread; FuriThread* thread;
FuriMessageQueue* command_queue; FuriMessageQueue* command_queue;
bool enable_adv; bool enable_adv;
bool is_secure;
uint8_t negotiation_round;
} Gap; } Gap;
typedef enum { typedef enum {
@ -87,17 +89,46 @@ static void gap_verify_connection_parameters(Gap* gap) {
// Send connection parameters request update if necessary // Send connection parameters request update if necessary
GapConnectionParamsRequest* params = &gap->config->conn_param; GapConnectionParamsRequest* params = &gap->config->conn_param;
if(params->conn_int_min > gap->connection_params.conn_interval ||
params->conn_int_max < gap->connection_params.conn_interval) { // Desired max connection interval depends on how many negotiation rounds we had in the past
FURI_LOG_W(TAG, "Unsupported connection interval. Request connection parameters update"); // In the first negotiation round we want connection interval to be minimum
// If platform disagree then we request wider range
uint16_t connection_interval_max = gap->negotiation_round ? params->conn_int_max :
params->conn_int_min;
// We do care about lower connection interval bound a lot: if it's lower than 30ms 2nd core will not allow us to use flash controller
bool negotiation_failed = params->conn_int_min > gap->connection_params.conn_interval;
// We don't care about upper bound till connection become secure
if(gap->is_secure) {
negotiation_failed |= connection_interval_max < gap->connection_params.conn_interval;
}
if(negotiation_failed) {
FURI_LOG_W(
TAG,
"Connection interval doesn't suite us. Trying to negotiate, round %u",
gap->negotiation_round + 1);
if(aci_l2cap_connection_parameter_update_req( if(aci_l2cap_connection_parameter_update_req(
gap->service.connection_handle, gap->service.connection_handle,
params->conn_int_min, params->conn_int_min,
params->conn_int_max, connection_interval_max,
gap->connection_params.slave_latency, gap->connection_params.slave_latency,
gap->connection_params.supervisor_timeout)) { gap->connection_params.supervisor_timeout)) {
FURI_LOG_E(TAG, "Failed to request connection parameters update"); FURI_LOG_E(TAG, "Failed to request connection parameters update");
// The other side is not in the mood
// But we are open to try it again
gap->negotiation_round = 0;
} else {
gap->negotiation_round++;
} }
} else {
FURI_LOG_I(
TAG,
"Connection interval suits us. Spent %u rounds to negotiate",
gap->negotiation_round);
// Looks like the other side is open to negotiation
gap->negotiation_round = 0;
} }
} }
@ -112,9 +143,9 @@ BleEventFlowStatus ble_event_app_notification(void* pckt) {
event_pckt = (hci_event_pckt*)((hci_uart_pckt*)pckt)->data; event_pckt = (hci_event_pckt*)((hci_uart_pckt*)pckt)->data;
if(gap) { furi_check(gap);
furi_mutex_acquire(gap->state_mutex, FuriWaitForever); furi_mutex_acquire(gap->state_mutex, FuriWaitForever);
}
switch(event_pckt->evt) { switch(event_pckt->evt) {
case HCI_DISCONNECTION_COMPLETE_EVT_CODE: { case HCI_DISCONNECTION_COMPLETE_EVT_CODE: {
hci_disconnection_complete_event_rp0* disconnection_complete_event = hci_disconnection_complete_event_rp0* disconnection_complete_event =
@ -125,6 +156,8 @@ BleEventFlowStatus ble_event_app_notification(void* pckt) {
FURI_LOG_I( FURI_LOG_I(
TAG, "Disconnect from client. Reason: %02X", disconnection_complete_event->Reason); TAG, "Disconnect from client. Reason: %02X", disconnection_complete_event->Reason);
} }
gap->is_secure = false;
gap->negotiation_round = 0;
// Enterprise sleep // Enterprise sleep
furi_delay_us(666 + 666); furi_delay_us(666 + 666);
if(gap->enable_adv) { if(gap->enable_adv) {
@ -232,6 +265,7 @@ BleEventFlowStatus ble_event_app_notification(void* pckt) {
case ACI_GAP_SLAVE_SECURITY_INITIATED_VSEVT_CODE: case ACI_GAP_SLAVE_SECURITY_INITIATED_VSEVT_CODE:
FURI_LOG_D(TAG, "Slave security initiated"); FURI_LOG_D(TAG, "Slave security initiated");
gap->is_secure = true;
break; break;
case ACI_GAP_BOND_LOST_VSEVT_CODE: case ACI_GAP_BOND_LOST_VSEVT_CODE:
@ -293,9 +327,9 @@ BleEventFlowStatus ble_event_app_notification(void* pckt) {
default: default:
break; break;
} }
if(gap) {
furi_mutex_release(gap->state_mutex); furi_mutex_release(gap->state_mutex);
}
return BleEventFlowEnable; return BleEventFlowEnable;
} }
@ -539,6 +573,10 @@ bool gap_init(GapConfig* config, GapEventCallback on_event_cb, void* context) {
gap->thread = furi_thread_alloc_ex("BleGapDriver", 1024, gap_app, gap); gap->thread = furi_thread_alloc_ex("BleGapDriver", 1024, gap_app, gap);
furi_thread_start(gap->thread); furi_thread_start(gap->thread);
// Set initial state
gap->is_secure = false;
gap->negotiation_round = 0;
uint8_t adv_service_uid[2]; uint8_t adv_service_uid[2];
gap->service.adv_svc_uuid_len = 1; gap->service.adv_svc_uuid_len = 1;
adv_service_uid[0] = gap->config->adv_service_uuid & 0xff; adv_service_uid[0] = gap->config->adv_service_uuid & 0xff;

View file

@ -47,7 +47,7 @@ static GapConfig serial_template_config = {
.pairing_method = GapPairingPinCodeShow, .pairing_method = GapPairingPinCodeShow,
.conn_param = { .conn_param = {
.conn_int_min = 0x18, // AN5289: 4.7, we need at least 25ms + advertisement, which is 30 ms .conn_int_min = 0x18, // AN5289: 4.7, we need at least 25ms + advertisement, which is 30 ms
.conn_int_max = 0x18, // 30 ms .conn_int_max = 0x24, // 45 ms
.slave_latency = 0, .slave_latency = 0,
.supervisor_timeout = 0, .supervisor_timeout = 0,
}}; }};

View file

@ -17,6 +17,7 @@ void furi_hal_init_early(void) {
furi_hal_i2c_init_early(); furi_hal_i2c_init_early();
furi_hal_light_init(); furi_hal_light_init();
furi_hal_rtc_init_early(); furi_hal_rtc_init_early();
furi_hal_version_init();
} }
void furi_hal_deinit_early(void) { void furi_hal_deinit_early(void) {
@ -39,7 +40,6 @@ void furi_hal_init(void) {
furi_hal_interrupt_init(); furi_hal_interrupt_init();
furi_hal_flash_init(); furi_hal_flash_init();
furi_hal_resources_init(); furi_hal_resources_init();
furi_hal_version_init();
furi_hal_spi_config_init(); furi_hal_spi_config_init();
furi_hal_spi_dma_init(); furi_hal_spi_dma_init();
furi_hal_ibutton_init(); furi_hal_ibutton_init();