From e7965c6d95ceb465296f53b3a49f146b719d11e5 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 19 May 2023 06:33:15 +0300 Subject: [PATCH 1/9] De-libify name changer --- applications/services/application.fam | 2 +- .../services/namechanger/application.fam | 4 +- .../services/namechanger/namechange.c | 46 ------------------- .../services/namechanger}/namechanger.c | 46 ++++++++++++++++++- .../services/namechanger/namechanger.h | 5 ++ .../desktop_settings/desktop_settings_app.c | 2 +- lib/toolbox/namechanger.h | 18 -------- 7 files changed, 54 insertions(+), 69 deletions(-) delete mode 100644 applications/services/namechanger/namechange.c rename {lib/toolbox => applications/services/namechanger}/namechanger.c (60%) create mode 100644 applications/services/namechanger/namechanger.h delete mode 100644 lib/toolbox/namechanger.h diff --git a/applications/services/application.fam b/applications/services/application.fam index afa69301d..0b5009096 100644 --- a/applications/services/application.fam +++ b/applications/services/application.fam @@ -9,6 +9,6 @@ App( "desktop", "loader", "power", - "namechange_srv", + "namechanger_srv", ], ) diff --git a/applications/services/namechanger/application.fam b/applications/services/namechanger/application.fam index a4bc23938..0eaeab987 100644 --- a/applications/services/namechanger/application.fam +++ b/applications/services/namechanger/application.fam @@ -1,7 +1,7 @@ App( - appid="namechange_srv", + appid="namechanger_srv", apptype=FlipperAppType.STARTUP, - entry_point="namechange_on_system_start", + entry_point="namechanger_on_system_start", requires=["storage", "cli", "bt"], conflicts=["updater"], order=600, diff --git a/applications/services/namechanger/namechange.c b/applications/services/namechanger/namechange.c deleted file mode 100644 index 22cb0d9de..000000000 --- a/applications/services/namechanger/namechange.c +++ /dev/null @@ -1,46 +0,0 @@ -#include -#include -#include -#include - -#include -#include - -int32_t namechange_on_system_start(void* p) { - UNUSED(p); - if(furi_hal_rtc_get_boot_mode() != FuriHalRtcBootModeNormal) { - return 0; - } - - // Wait for all required services to start and create their records - uint8_t timeout = 0; - while(!furi_record_exists(RECORD_CLI) || !furi_record_exists(RECORD_BT) || - !furi_record_exists(RECORD_STORAGE)) { - timeout++; - if(timeout > 250) { - return 0; - } - furi_delay_ms(5); - } - - // Hehe bad code now here, bad bad bad, very bad, bad example, dont take it, make it better - - if(NameChanger_Init()) { - Cli* cli = furi_record_open(RECORD_CLI); - cli_session_close(cli); - furi_delay_ms(2); // why i added delays here - cli_session_open(cli, &cli_vcp); - furi_record_close(RECORD_CLI); - - furi_delay_ms(3); - Bt* bt = furi_record_open(RECORD_BT); - if(!bt_set_profile(bt, BtProfileSerial)) { - //FURI_LOG_D(TAG, "Failed to touch bluetooth to name change"); - } - furi_record_close(RECORD_BT); - bt = NULL; - furi_delay_ms(3); - } - - return 0; -} \ No newline at end of file diff --git a/lib/toolbox/namechanger.c b/applications/services/namechanger/namechanger.c similarity index 60% rename from lib/toolbox/namechanger.c rename to applications/services/namechanger/namechanger.c index 94e08ac13..796dd2d3b 100644 --- a/lib/toolbox/namechanger.c +++ b/applications/services/namechanger/namechanger.c @@ -1,10 +1,15 @@ #include "namechanger.h" +#include #include +#include +#include +#include +#include #include #define TAG "NameChanger" -bool NameChanger_Init() { +static bool namechanger_init() { Storage* storage = furi_record_open(RECORD_STORAGE); // Kostil + velosiped = top ficha @@ -64,4 +69,43 @@ bool NameChanger_Init() { furi_string_free(str); return res; +} + +int32_t namechanger_on_system_start(void* p) { + UNUSED(p); + if(furi_hal_rtc_get_boot_mode() != FuriHalRtcBootModeNormal) { + return 0; + } + + // Wait for all required services to start and create their records + uint8_t timeout = 0; + while(!furi_record_exists(RECORD_CLI) || !furi_record_exists(RECORD_BT) || + !furi_record_exists(RECORD_STORAGE)) { + timeout++; + if(timeout > 250) { + return 0; + } + furi_delay_ms(5); + } + + // Hehe bad code now here, bad bad bad, very bad, bad example, dont take it, make it better + + if(namechanger_init()) { + Cli* cli = furi_record_open(RECORD_CLI); + cli_session_close(cli); + furi_delay_ms(2); // why i added delays here + cli_session_open(cli, &cli_vcp); + furi_record_close(RECORD_CLI); + + furi_delay_ms(3); + Bt* bt = furi_record_open(RECORD_BT); + if(!bt_set_profile(bt, BtProfileSerial)) { + //FURI_LOG_D(TAG, "Failed to touch bluetooth to name change"); + } + furi_record_close(RECORD_BT); + bt = NULL; + furi_delay_ms(3); + } + + return 0; } \ No newline at end of file diff --git a/applications/services/namechanger/namechanger.h b/applications/services/namechanger/namechanger.h new file mode 100644 index 000000000..dac1b7952 --- /dev/null +++ b/applications/services/namechanger/namechanger.h @@ -0,0 +1,5 @@ +#pragma once + +#define NAMECHANGER_HEADER "Flipper Name File" +#define NAMECHANGER_VERSION 1 +#define NAMECHANGER_PATH EXT_PATH("dolphin/name.settings") diff --git a/applications/settings/desktop_settings/desktop_settings_app.c b/applications/settings/desktop_settings/desktop_settings_app.c index 317d57654..7e04271f2 100644 --- a/applications/settings/desktop_settings/desktop_settings_app.c +++ b/applications/settings/desktop_settings/desktop_settings_app.c @@ -1,7 +1,7 @@ #include #include #include -#include +#include #include #include diff --git a/lib/toolbox/namechanger.h b/lib/toolbox/namechanger.h deleted file mode 100644 index bfaadec15..000000000 --- a/lib/toolbox/namechanger.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#define NAMECHANGER_HEADER "Flipper Name File" -#define NAMECHANGER_VERSION 1 -#define NAMECHANGER_PATH EXT_PATH("dolphin/name.settings") - -#include "stdbool.h" - -#ifdef __cplusplus -extern "C" { -#endif - -// Initializes the name changer. (Load name file, apply changes) -bool NameChanger_Init(); - -#ifdef __cplusplus -} -#endif \ No newline at end of file From a4d72e0fee973638c393a23c2819926ded35c3f0 Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Fri, 19 May 2023 12:32:35 +0300 Subject: [PATCH 2/9] subrem fix repeat --- .../main/subghz_remote/subghz_remote_app_i.c | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/applications/main/subghz_remote/subghz_remote_app_i.c b/applications/main/subghz_remote/subghz_remote_app_i.c index 9b0f77d17..171618a5f 100644 --- a/applications/main/subghz_remote/subghz_remote_app_i.c +++ b/applications/main/subghz_remote/subghz_remote_app_i.c @@ -129,23 +129,31 @@ bool subrem_save_protocol_to_file(FlipperFormat* flipper_format, const char* dev Stream* flipper_format_stream = flipper_format_get_raw_stream(flipper_format); bool saved = false; + uint32_t repeat = 200; FuriString* file_dir = furi_string_alloc(); path_extract_dirname(dev_file_name, file_dir); do { - //removing additional fields + // removing additional fields flipper_format_delete_key(flipper_format, "Repeat"); - //flipper_format_delete_key(flipper_format, "Manufacture"); + // flipper_format_delete_key(flipper_format, "Manufacture"); if(!storage_simply_remove(storage, dev_file_name)) { break; } + //ToDo check Write stream_seek(flipper_format_stream, 0, StreamOffsetFromStart); stream_save_to_file(flipper_format_stream, storage, dev_file_name, FSOM_CREATE_ALWAYS); + if(!flipper_format_insert_or_update_uint32(flipper_format, "Repeat", &repeat, 1)) { + FURI_LOG_E(TAG, "Unable Repeat"); + break; + } + saved = true; } while(0); + furi_string_free(file_dir); furi_record_close(RECORD_STORAGE); return saved; @@ -267,7 +275,7 @@ static bool subrem_map_preset_check(SubGhzRemoteApp* app, FlipperFormat* fff_dat bool ret = false; bool sub_preset_loaded = false; SubRemSubFilePreset* sub_preset; - + uint32_t repeat = 200; for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { sub_preset = app->subs_preset[i]; sub_preset_loaded = false; @@ -275,6 +283,7 @@ static bool subrem_map_preset_check(SubGhzRemoteApp* app, FlipperFormat* fff_dat // FURI_LOG_I(TAG, "Empty file path"); continue; } + repeat = 200; do { if(!flipper_format_file_open_existing( fff_data_file, furi_string_get_cstr(sub_preset->file_path))) { @@ -361,6 +370,11 @@ static bool subrem_map_preset_check(SubGhzRemoteApp* app, FlipperFormat* fff_dat FURI_LOG_E(TAG, "Protocol does not support transmission"); } + if(!flipper_format_insert_or_update_uint32(fff_data, "Repeat", &repeat, 1)) { + FURI_LOG_E(TAG, "Unable Repeat"); + break; + } + sub_preset_loaded = true; ret |= true; #if FURI_DEBUG From 87ebbc990142a729a04b4baaa6f3b2f0454d0ae5 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sat, 20 May 2023 09:52:00 +0300 Subject: [PATCH 3/9] Update wifi marauder --- .../scenes/wifi_marauder_scene_config.h | 1 + .../wifi_marauder_scene_sniffpmkid_options.c | 117 ++++++++++++++++++ .../scenes/wifi_marauder_scene_start.c | 19 +-- .../wifi_marauder_app.h | 2 +- .../wifi_marauder_app_i.h | 2 +- .../wifi_marauder_custom_event.h | 3 +- 6 files changed, 134 insertions(+), 10 deletions(-) create mode 100644 applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_sniffpmkid_options.c diff --git a/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_config.h b/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_config.h index ae976c6bf..d223af79a 100644 --- a/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_config.h +++ b/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_config.h @@ -12,3 +12,4 @@ ADD_SCENE(wifi_marauder, script_confirm_delete, ScriptConfirmDelete) ADD_SCENE(wifi_marauder, script_stage_edit, ScriptStageEdit) ADD_SCENE(wifi_marauder, script_stage_add, ScriptStageAdd) ADD_SCENE(wifi_marauder, script_stage_edit_list, ScriptStageEditList) +ADD_SCENE(wifi_marauder, sniffpmkid_options, SniffPmkidOptions) diff --git a/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_sniffpmkid_options.c b/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_sniffpmkid_options.c new file mode 100644 index 000000000..02869030e --- /dev/null +++ b/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_sniffpmkid_options.c @@ -0,0 +1,117 @@ +#include "../wifi_marauder_app_i.h" + +enum SubmenuIndex { + SubmenuIndexPassive, + SubmenuIndexActive, + SubmenuIndexTargetedPassive, + SubmenuIndexTargetedActive, + SubmenuIndexChannelPassive, + SubmenuIndexChannelActive, +}; + +static void wifi_marauder_scene_sniffpmkid_options_callback(void* context, uint32_t index) { + WifiMarauderApp* app = context; + + app->is_custom_tx_string = false; // this will be set if needed by text input + switch(index) { + case SubmenuIndexPassive: + app->selected_tx_string = "sniffpmkid"; + scene_manager_set_scene_state( + app->scene_manager, WifiMarauderSceneSniffPmkidOptions, index); + scene_manager_next_scene(app->scene_manager, WifiMarauderSceneConsoleOutput); + break; + case SubmenuIndexActive: + app->selected_tx_string = "sniffpmkid -d"; + scene_manager_set_scene_state( + app->scene_manager, WifiMarauderSceneSniffPmkidOptions, index); + scene_manager_next_scene(app->scene_manager, WifiMarauderSceneConsoleOutput); + break; + case SubmenuIndexTargetedPassive: + app->selected_tx_string = "sniffpmkid -l"; + scene_manager_set_scene_state( + app->scene_manager, WifiMarauderSceneSniffPmkidOptions, index); + scene_manager_next_scene(app->scene_manager, WifiMarauderSceneConsoleOutput); + break; + case SubmenuIndexTargetedActive: + app->selected_tx_string = "sniffpmkid -d -l"; + scene_manager_set_scene_state( + app->scene_manager, WifiMarauderSceneSniffPmkidOptions, index); + scene_manager_next_scene(app->scene_manager, WifiMarauderSceneConsoleOutput); + break; + case SubmenuIndexChannelPassive: + app->selected_tx_string = "sniffpmkid -c"; + scene_manager_set_scene_state( + app->scene_manager, WifiMarauderSceneSniffPmkidOptions, index); + scene_manager_next_scene(app->scene_manager, WifiMarauderSceneTextInput); + break; + case SubmenuIndexChannelActive: + app->selected_tx_string = "sniffpmkid -d -c"; + scene_manager_set_scene_state( + app->scene_manager, WifiMarauderSceneSniffPmkidOptions, index); + scene_manager_next_scene(app->scene_manager, WifiMarauderSceneTextInput); + break; + } +} + +void wifi_marauder_scene_sniffpmkid_options_on_enter(void* context) { + WifiMarauderApp* app = context; + + Submenu* submenu = app->submenu; + + submenu_set_header(submenu, "Sniff PMKID"); + submenu_add_item( + submenu, + "Passive", + SubmenuIndexPassive, + wifi_marauder_scene_sniffpmkid_options_callback, + app); + submenu_add_item( + submenu, + "Active (Force Deauth)", + SubmenuIndexActive, + wifi_marauder_scene_sniffpmkid_options_callback, + app); + submenu_add_item( + submenu, + "Targeted Passive (List)", + SubmenuIndexTargetedPassive, + wifi_marauder_scene_sniffpmkid_options_callback, + app); + submenu_add_item( + submenu, + "Targeted Active (List)", + SubmenuIndexTargetedActive, + wifi_marauder_scene_sniffpmkid_options_callback, + app); + submenu_add_item( + submenu, + "On Channel # - Passive", + SubmenuIndexChannelPassive, + wifi_marauder_scene_sniffpmkid_options_callback, + app); + submenu_add_item( + submenu, + "On Channel # - Active", + SubmenuIndexChannelActive, + wifi_marauder_scene_sniffpmkid_options_callback, + app); + + submenu_set_selected_item( + submenu, + scene_manager_get_scene_state(app->scene_manager, WifiMarauderSceneSniffPmkidOptions)); + view_dispatcher_switch_to_view(app->view_dispatcher, WifiMarauderAppViewSubmenu); +} + +bool wifi_marauder_scene_sniffpmkid_options_on_event(void* context, SceneManagerEvent event) { + //WifiMarauderApp* app = context; + UNUSED(context); + UNUSED(event); + bool consumed = false; + + return consumed; +} + +void wifi_marauder_scene_sniffpmkid_options_on_exit(void* context) { + WifiMarauderApp* app = context; + submenu_reset(app->submenu); +} diff --git a/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_start.c b/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_start.c index 6f22d0adb..28a3ed2a9 100644 --- a/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_start.c +++ b/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_start.c @@ -97,13 +97,6 @@ const WifiMarauderItem items[NUM_MENU_ITEMS] = { NO_ARGS, FOCUS_CONSOLE_END, SHOW_STOPSCAN_TIP}, - {"Sniff PMKID", - {"ap", "channel"}, - 2, - {"sniffpmkid -d -l", "sniffpmkid -c"}, - TOGGLE_ARGS, - FOCUS_CONSOLE_END, - SHOW_STOPSCAN_TIP}, {"Channel", {"get", "set"}, 2, @@ -161,6 +154,14 @@ static void wifi_marauder_scene_start_var_list_enter_callback(void* context, uin return; } + if(app->selected_tx_string && + strncmp("sniffpmkid", app->selected_tx_string, strlen("sniffpmkid")) == 0) { + // sniffpmkid submenu + view_dispatcher_send_custom_event( + app->view_dispatcher, WifiMarauderEventStartSniffPmkidOptions); + return; + } + // Select automation script if(index == NUM_MENU_ITEMS - 2) { view_dispatcher_send_custom_event( @@ -254,6 +255,10 @@ bool wifi_marauder_scene_start_on_event(void* context, SceneManagerEvent event) scene_manager_set_scene_state( app->scene_manager, WifiMarauderSceneStart, app->selected_menu_index); scene_manager_next_scene(app->scene_manager, WifiMarauderSceneScriptSelect); + } else if(event.event == WifiMarauderEventStartSniffPmkidOptions) { + scene_manager_set_scene_state( + app->scene_manager, WifiMarauderSceneStart, app->selected_menu_index); + scene_manager_next_scene(app->scene_manager, WifiMarauderSceneSniffPmkidOptions); } consumed = true; } else if(event.type == SceneManagerEventTypeTick) { diff --git a/applications/external/wifi_marauder_companion/wifi_marauder_app.h b/applications/external/wifi_marauder_companion/wifi_marauder_app.h index 303fb59b4..7e3856059 100644 --- a/applications/external/wifi_marauder_companion/wifi_marauder_app.h +++ b/applications/external/wifi_marauder_companion/wifi_marauder_app.h @@ -4,7 +4,7 @@ extern "C" { #endif -#define WIFI_MARAUDER_APP_VERSION "v0.3.5" +#define WIFI_MARAUDER_APP_VERSION "v0.3.6" typedef struct WifiMarauderApp WifiMarauderApp; diff --git a/applications/external/wifi_marauder_companion/wifi_marauder_app_i.h b/applications/external/wifi_marauder_companion/wifi_marauder_app_i.h index 2a16522bb..45e1e5920 100644 --- a/applications/external/wifi_marauder_companion/wifi_marauder_app_i.h +++ b/applications/external/wifi_marauder_companion/wifi_marauder_app_i.h @@ -26,7 +26,7 @@ #include #include -#define NUM_MENU_ITEMS (18) +#define NUM_MENU_ITEMS (17) #define WIFI_MARAUDER_TEXT_BOX_STORE_SIZE (4096) #define WIFI_MARAUDER_TEXT_INPUT_STORE_SIZE (512) diff --git a/applications/external/wifi_marauder_companion/wifi_marauder_custom_event.h b/applications/external/wifi_marauder_companion/wifi_marauder_custom_event.h index 5acdfa38e..b6d9f8274 100644 --- a/applications/external/wifi_marauder_companion/wifi_marauder_custom_event.h +++ b/applications/external/wifi_marauder_companion/wifi_marauder_custom_event.h @@ -8,5 +8,6 @@ typedef enum { WifiMarauderEventSaveDestinationMac, WifiMarauderEventStartSettingsInit, WifiMarauderEventStartLogViewer, - WifiMarauderEventStartScriptSelect + WifiMarauderEventStartScriptSelect, + WifiMarauderEventStartSniffPmkidOptions } WifiMarauderCustomEvent; From 1ea138f7952ac9bce054ade7add4868694a24ce2 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sat, 20 May 2023 10:01:05 +0300 Subject: [PATCH 4/9] Port XFW keyboard to marauder instead of UART Term keyboard This implementation has not only extra symbols but a cursor feature thanks to @Willy-JL --- .../assets/KeyKeyboardSelected_10x11.png | Bin 0 -> 7210 bytes .../assets/KeyKeyboard_10x11.png | Bin 0 -> 7763 bytes .../wifi_marauder_text_input.c | 559 +++++++++++------- .../wifi_marauder_text_input.h | 31 +- 4 files changed, 358 insertions(+), 232 deletions(-) create mode 100644 applications/external/wifi_marauder_companion/assets/KeyKeyboardSelected_10x11.png create mode 100644 applications/external/wifi_marauder_companion/assets/KeyKeyboard_10x11.png diff --git a/applications/external/wifi_marauder_companion/assets/KeyKeyboardSelected_10x11.png b/applications/external/wifi_marauder_companion/assets/KeyKeyboardSelected_10x11.png new file mode 100644 index 0000000000000000000000000000000000000000..231880386a9d9e83911088c9fcd083f84a7f75bb GIT binary patch literal 7210 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 literal 0 HcmV?d00001 diff --git a/applications/external/wifi_marauder_companion/assets/KeyKeyboard_10x11.png b/applications/external/wifi_marauder_companion/assets/KeyKeyboard_10x11.png new file mode 100644 index 0000000000000000000000000000000000000000..1f4c03478f68cb15c74ef99888ce4faf50e0a140 GIT binary patch literal 7763 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 = (model->selected_keyboard + 1) % keyboard_count; +} + +static uint8_t get_row_size(const Keyboard* keyboard, uint8_t row_index) { uint8_t row_size = 0; - - switch(row_index + 1) { - case 1: - row_size = sizeof(keyboard_keys_row_1) / sizeof(WIFI_TextInputKey); - break; - case 2: - row_size = sizeof(keyboard_keys_row_2) / sizeof(WIFI_TextInputKey); - break; - case 3: - row_size = sizeof(keyboard_keys_row_3) / sizeof(WIFI_TextInputKey); - break; - case 4: - row_size = sizeof(keyboard_keys_row_4) / sizeof(WIFI_TextInputKey); - break; + if(keyboard == &symbol_keyboard) { + switch(row_index + 1) { + case 1: + row_size = COUNT_OF(symbol_keyboard_keys_row_1); + break; + case 2: + row_size = COUNT_OF(symbol_keyboard_keys_row_2); + break; + case 3: + row_size = COUNT_OF(symbol_keyboard_keys_row_3); + break; + default: + furi_crash(NULL); + } + } else { + switch(row_index + 1) { + case 1: + row_size = COUNT_OF(keyboard_keys_row_1); + break; + case 2: + row_size = COUNT_OF(keyboard_keys_row_2); + break; + case 3: + row_size = COUNT_OF(keyboard_keys_row_3); + break; + default: + furi_crash(NULL); + } } return row_size; } -static const WIFI_TextInputKey* get_row(uint8_t row_index) { +static const WIFI_TextInputKey* get_row(const Keyboard* keyboard, uint8_t row_index) { const WIFI_TextInputKey* row = NULL; - - switch(row_index + 1) { - case 1: - row = keyboard_keys_row_1; - break; - case 2: - row = keyboard_keys_row_2; - break; - case 3: - row = keyboard_keys_row_3; - break; - case 4: - row = keyboard_keys_row_4; - break; + if(row_index < 3) { + row = keyboard->rows[row_index]; + } else { + furi_crash(NULL); } return row; } static char get_selected_char(WIFI_TextInputModel* model) { - return get_row(model->selected_row)[model->selected_column].text; + return get_row( + keyboards[model->selected_keyboard], model->selected_row)[model->selected_column] + .text; } static bool char_is_lowercase(char letter) { @@ -165,36 +231,9 @@ static bool char_is_lowercase(char letter) { } static char char_to_uppercase(const char letter) { - switch(letter) { - case '_': + if(letter == '_') { return 0x20; - break; - case '(': - return 0x29; - break; - case '{': - return 0x7d; - break; - case '[': - return 0x5d; - break; - case '/': - return 0x5c; - break; - case ';': - return 0x3a; - break; - case '.': - return 0x2c; - break; - case '!': - return 0x3f; - break; - case '<': - return 0x3e; - break; - } - if(char_is_lowercase(letter)) { + } else if(char_is_lowercase(letter)) { return (letter - 0x20); } else { return letter; @@ -202,86 +241,96 @@ static char char_to_uppercase(const char letter) { } static void wifi_text_input_backspace_cb(WIFI_TextInputModel* model) { - uint8_t text_length = model->clear_default_text ? 1 : strlen(model->text_buffer); - if(text_length > 0) { - model->text_buffer[text_length - 1] = 0; + if(model->clear_default_text) { + model->text_buffer[0] = 0; + model->cursor_pos = 0; + } else if(model->cursor_pos > 0) { + char* move = model->text_buffer + model->cursor_pos; + memmove(move - 1, move, strlen(move) + 1); + model->cursor_pos--; } } static void wifi_text_input_view_draw_callback(Canvas* canvas, void* _model) { WIFI_TextInputModel* model = _model; - //uint8_t text_length = model->text_buffer ? strlen(model->text_buffer) : 0; + uint8_t text_length = model->text_buffer ? strlen(model->text_buffer) : 0; uint8_t needed_string_width = canvas_width(canvas) - 8; uint8_t start_pos = 4; - const char* text = model->text_buffer; + model->cursor_pos = model->cursor_pos > text_length ? text_length : model->cursor_pos; + size_t cursor_pos = model->cursor_pos; canvas_clear(canvas); canvas_set_color(canvas, ColorBlack); - canvas_draw_str(canvas, 2, 7, model->header); - elements_slightly_rounded_frame(canvas, 1, 8, 126, 12); + canvas_draw_str(canvas, 2, 8, model->header); + elements_slightly_rounded_frame(canvas, 1, 12, 126, 15); - if(canvas_string_width(canvas, text) > needed_string_width) { - canvas_draw_str(canvas, start_pos, 17, "..."); - start_pos += 6; - needed_string_width -= 8; - } - - while(text != 0 && canvas_string_width(canvas, text) > needed_string_width) { - text++; + char buf[model->text_buffer_size + 1]; + if(model->text_buffer) { + strlcpy(buf, model->text_buffer, sizeof(buf)); } + char* str = buf; if(model->clear_default_text) { elements_slightly_rounded_box( - canvas, start_pos - 1, 14, canvas_string_width(canvas, text) + 2, 10); + canvas, start_pos - 1, 14, canvas_string_width(canvas, str) + 2, 10); canvas_set_color(canvas, ColorWhite); } else { - canvas_draw_str(canvas, start_pos + canvas_string_width(canvas, text) + 1, 18, "|"); - canvas_draw_str(canvas, start_pos + canvas_string_width(canvas, text) + 2, 18, "|"); + char* move = str + cursor_pos; + memmove(move + 1, move, strlen(move) + 1); + str[cursor_pos] = '|'; } - canvas_draw_str(canvas, start_pos, 17, text); + + if(cursor_pos > 0 && canvas_string_width(canvas, str) > needed_string_width) { + canvas_draw_str(canvas, start_pos, 22, "..."); + start_pos += 6; + needed_string_width -= 8; + for(uint32_t off = 0; + strlen(str) && canvas_string_width(canvas, str) > needed_string_width && + off < cursor_pos; + off++) { + str++; + } + } + + if(canvas_string_width(canvas, str) > needed_string_width) { + needed_string_width -= 4; + size_t len = strlen(str); + while(len && canvas_string_width(canvas, str) > needed_string_width) { + str[len--] = '\0'; + } + strcat(str, "..."); + } + + canvas_draw_str(canvas, start_pos, 22, str); canvas_set_font(canvas, FontKeyboard); - for(uint8_t row = 0; row <= keyboard_row_count; row++) { - const uint8_t column_count = get_row_size(row); - const WIFI_TextInputKey* keys = get_row(row); + for(uint8_t row = 0; row < keyboard_row_count; row++) { + const uint8_t column_count = get_row_size(keyboards[model->selected_keyboard], row); + const WIFI_TextInputKey* keys = get_row(keyboards[model->selected_keyboard], row); for(size_t column = 0; column < column_count; column++) { + bool selected = !model->cursor_select && model->selected_row == row && + model->selected_column == column; + const Icon* icon = NULL; if(keys[column].text == ENTER_KEY) { - canvas_set_color(canvas, ColorBlack); - if(model->selected_row == row && model->selected_column == column) { - canvas_draw_icon( - canvas, - keyboard_origin_x + keys[column].x, - keyboard_origin_y + keys[column].y, - &I_KeySaveSelected_24x11); - } else { - canvas_draw_icon( - canvas, - keyboard_origin_x + keys[column].x, - keyboard_origin_y + keys[column].y, - &I_KeySave_24x11); - } + icon = selected ? &I_KeySaveSelected_24x11 : &I_KeySave_24x11; + } else if(keys[column].text == SWITCH_KEYBOARD_KEY) { + icon = selected ? &I_KeyKeyboardSelected_10x11 : &I_KeyKeyboard_10x11; } else if(keys[column].text == BACKSPACE_KEY) { - canvas_set_color(canvas, ColorBlack); - if(model->selected_row == row && model->selected_column == column) { - canvas_draw_icon( - canvas, - keyboard_origin_x + keys[column].x, - keyboard_origin_y + keys[column].y, - &I_KeyBackspaceSelected_16x9); - } else { - canvas_draw_icon( - canvas, - keyboard_origin_x + keys[column].x, - keyboard_origin_y + keys[column].y, - &I_KeyBackspace_16x9); - } + icon = selected ? &I_KeyBackspaceSelected_16x9 : &I_KeyBackspace_16x9; + } + canvas_set_color(canvas, ColorBlack); + if(icon != NULL) { + canvas_draw_icon( + canvas, + keyboard_origin_x + keys[column].x, + keyboard_origin_y + keys[column].y, + icon); } else { - if(model->selected_row == row && model->selected_column == column) { - canvas_set_color(canvas, ColorBlack); + if(selected) { canvas_draw_box( canvas, keyboard_origin_x + keys[column].x - 1, @@ -289,19 +338,25 @@ static void wifi_text_input_view_draw_callback(Canvas* canvas, void* _model) { 7, 10); canvas_set_color(canvas, ColorWhite); - } else { - canvas_set_color(canvas, ColorBlack); } - canvas_draw_glyph( - canvas, - keyboard_origin_x + keys[column].x, - keyboard_origin_y + keys[column].y, - keys[column].text); + if(model->clear_default_text || text_length == 0) { + canvas_draw_glyph( + canvas, + keyboard_origin_x + keys[column].x, + keyboard_origin_y + keys[column].y, + char_to_uppercase(keys[column].text)); + } else { + canvas_draw_glyph( + canvas, + keyboard_origin_x + keys[column].x, + keyboard_origin_y + keys[column].y, + keys[column].text); + } } } } - if(model->valadator_message_visible) { + if(model->validator_message_visible) { canvas_set_font(canvas, FontSecondary); canvas_set_color(canvas, ColorWhite); canvas_draw_box(canvas, 8, 10, 110, 48); @@ -319,37 +374,69 @@ static void UNUSED(wifi_text_input); if(model->selected_row > 0) { model->selected_row--; - if(model->selected_column > get_row_size(model->selected_row) - 6) { + if(model->selected_row == 0 && + model->selected_column > + get_row_size(keyboards[model->selected_keyboard], model->selected_row) - 6) { model->selected_column = model->selected_column + 1; } + if(model->selected_row == 1 && + model->selected_keyboard == symbol_keyboard.keyboard_index) { + if(model->selected_column > 5) + model->selected_column += 2; + else if(model->selected_column > 1) + model->selected_column += 1; + } + } else { + model->cursor_select = true; + model->clear_default_text = false; } } static void wifi_text_input_handle_down(WIFI_TextInput* wifi_text_input, WIFI_TextInputModel* model) { UNUSED(wifi_text_input); - if(model->selected_row < keyboard_row_count - 1) { + if(model->cursor_select) { + model->cursor_select = false; + } else if(model->selected_row < keyboard_row_count - 1) { model->selected_row++; - if(model->selected_column > get_row_size(model->selected_row) - 4) { + if(model->selected_row == 1 && + model->selected_column > + get_row_size(keyboards[model->selected_keyboard], model->selected_row) - 4) { model->selected_column = model->selected_column - 1; } + if(model->selected_row == 2 && + model->selected_keyboard == symbol_keyboard.keyboard_index) { + if(model->selected_column > 7) + model->selected_column -= 2; + else if(model->selected_column > 1) + model->selected_column -= 1; + } } } static void wifi_text_input_handle_left(WIFI_TextInput* wifi_text_input, WIFI_TextInputModel* model) { UNUSED(wifi_text_input); - if(model->selected_column > 0) { + if(model->cursor_select) { + if(model->cursor_pos > 0) { + model->cursor_pos = CLAMP(model->cursor_pos - 1, strlen(model->text_buffer), 0u); + } + } else if(model->selected_column > 0) { model->selected_column--; } else { - model->selected_column = get_row_size(model->selected_row) - 1; + model->selected_column = + get_row_size(keyboards[model->selected_keyboard], model->selected_row) - 1; } } static void wifi_text_input_handle_right(WIFI_TextInput* wifi_text_input, WIFI_TextInputModel* model) { UNUSED(wifi_text_input); - if(model->selected_column < get_row_size(model->selected_row) - 1) { + if(model->cursor_select) { + model->cursor_pos = CLAMP(model->cursor_pos + 1, strlen(model->text_buffer), 0u); + } else if( + model->selected_column < + get_row_size(keyboards[model->selected_keyboard], model->selected_row) - 1) { model->selected_column++; } else { model->selected_column = 0; @@ -359,35 +446,49 @@ static void static void wifi_text_input_handle_ok( WIFI_TextInput* wifi_text_input, WIFI_TextInputModel* model, - bool shift) { + InputType type) { + if(model->cursor_select) return; + bool shift = type == InputTypeLong; + bool repeat = type == InputTypeRepeat; char selected = get_selected_char(model); - uint8_t text_length = strlen(model->text_buffer); - - if(shift) { - selected = char_to_uppercase(selected); - } + size_t text_length = strlen(model->text_buffer); if(selected == ENTER_KEY) { if(model->validator_callback && (!model->validator_callback( model->text_buffer, model->validator_text, model->validator_callback_context))) { - model->valadator_message_visible = true; + model->validator_message_visible = true; furi_timer_start(wifi_text_input->timer, furi_kernel_get_tick_frequency() * 4); - } else if(model->callback != 0 && text_length > 0) { + } else if(model->callback != 0 && text_length >= model->minimum_length) { model->callback(model->callback_context); } - } else if(selected == BACKSPACE_KEY) { - wifi_text_input_backspace_cb(model); + } else if(selected == SWITCH_KEYBOARD_KEY) { + switch_keyboard(model); } else { - if(model->clear_default_text) { - text_length = 0; - } - if(text_length < (model->text_buffer_size - 1)) { - model->text_buffer[text_length] = selected; - model->text_buffer[text_length + 1] = 0; + if(selected == BACKSPACE_KEY) { + wifi_text_input_backspace_cb(model); + } else if(!repeat) { + if(model->clear_default_text) { + text_length = 0; + } + if(text_length < (model->text_buffer_size - 1)) { + if(shift != (text_length == 0)) { + selected = char_to_uppercase(selected); + } + if(model->clear_default_text) { + model->text_buffer[0] = selected; + model->text_buffer[1] = '\0'; + model->cursor_pos = 1; + } else { + char* move = model->text_buffer + model->cursor_pos; + memmove(move + 1, move, strlen(move) + 1); + model->text_buffer[model->cursor_pos] = selected; + model->cursor_pos++; + } + } } + model->clear_default_text = false; } - model->clear_default_text = false; } static bool wifi_text_input_view_input_callback(InputEvent* event, void* context) { @@ -400,8 +501,8 @@ static bool wifi_text_input_view_input_callback(InputEvent* event, void* context WIFI_TextInputModel* model = view_get_model(wifi_text_input->view); if((!(event->type == InputTypePress) && !(event->type == InputTypeRelease)) && - model->valadator_message_visible) { - model->valadator_message_visible = false; + model->validator_message_visible) { + model->validator_message_visible = false; consumed = true; } else if(event->type == InputTypeShort) { consumed = true; @@ -419,7 +520,7 @@ static bool wifi_text_input_view_input_callback(InputEvent* event, void* context wifi_text_input_handle_right(wifi_text_input, model); break; case InputKeyOk: - wifi_text_input_handle_ok(wifi_text_input, model, false); + wifi_text_input_handle_ok(wifi_text_input, model, event->type); break; default: consumed = false; @@ -441,7 +542,7 @@ static bool wifi_text_input_view_input_callback(InputEvent* event, void* context wifi_text_input_handle_right(wifi_text_input, model); break; case InputKeyOk: - wifi_text_input_handle_ok(wifi_text_input, model, true); + wifi_text_input_handle_ok(wifi_text_input, model, event->type); break; case InputKeyBack: wifi_text_input_backspace_cb(model); @@ -465,6 +566,9 @@ static bool wifi_text_input_view_input_callback(InputEvent* event, void* context case InputKeyRight: wifi_text_input_handle_right(wifi_text_input, model); break; + case InputKeyOk: + wifi_text_input_handle_ok(wifi_text_input, model, event->type); + break; case InputKeyBack: wifi_text_input_backspace_cb(model); break; @@ -487,7 +591,7 @@ void wifi_text_input_timer_callback(void* context) { with_view_model( wifi_text_input->view, WIFI_TextInputModel * model, - { model->valadator_message_visible = false; }, + { model->validator_message_visible = false; }, true); } @@ -505,7 +609,12 @@ WIFI_TextInput* wifi_text_input_alloc() { with_view_model( wifi_text_input->view, WIFI_TextInputModel * model, - { model->validator_text = furi_string_alloc(); }, + { + model->validator_text = furi_string_alloc(); + model->minimum_length = 1; + model->cursor_pos = 0; + model->cursor_select = false; + }, false); wifi_text_input_reset(wifi_text_input); @@ -537,11 +646,14 @@ void wifi_text_input_reset(WIFI_TextInput* wifi_text_input) { wifi_text_input->view, WIFI_TextInputModel * model, { - model->text_buffer_size = 0; model->header = ""; model->selected_row = 0; model->selected_column = 0; + model->selected_keyboard = 0; + model->minimum_length = 1; model->clear_default_text = false; + model->cursor_pos = 0; + model->cursor_select = false; model->text_buffer = NULL; model->text_buffer_size = 0; model->callback = NULL; @@ -549,7 +661,7 @@ void wifi_text_input_reset(WIFI_TextInput* wifi_text_input) { model->validator_callback = NULL; model->validator_callback_context = NULL; furi_string_reset(model->validator_text); - model->valadator_message_visible = false; + model->validator_message_visible = false; }, true); } @@ -575,15 +687,28 @@ void wifi_text_input_set_result_callback( model->text_buffer = text_buffer; model->text_buffer_size = text_buffer_size; model->clear_default_text = clear_default_text; + model->cursor_select = false; if(text_buffer && text_buffer[0] != '\0') { + model->cursor_pos = strlen(text_buffer); // Set focus on Save model->selected_row = 2; - model->selected_column = 8; + model->selected_column = 9; + model->selected_keyboard = 0; + } else { + model->cursor_pos = 0; } }, true); } +void wifi_text_input_set_minimum_length(WIFI_TextInput* wifi_text_input, size_t minimum_length) { + with_view_model( + wifi_text_input->view, + WIFI_TextInputModel * model, + { model->minimum_length = minimum_length; }, + true); +} + void wifi_text_input_set_validator( WIFI_TextInput* wifi_text_input, WIFI_TextInputValidatorCallback callback, diff --git a/applications/external/wifi_marauder_companion/wifi_marauder_text_input.h b/applications/external/wifi_marauder_companion/wifi_marauder_text_input.h index b6b1f7bdf..f5efe9234 100644 --- a/applications/external/wifi_marauder_companion/wifi_marauder_text_input.h +++ b/applications/external/wifi_marauder_companion/wifi_marauder_text_input.h @@ -22,27 +22,27 @@ WIFI_TextInput* wifi_text_input_alloc(); /** Deinitialize and free text input * - * @param wifi_text_input WIFI_TextInput instance + * @param text_input WIFI_TextInput instance */ -void wifi_text_input_free(WIFI_TextInput* wifi_text_input); +void wifi_text_input_free(WIFI_TextInput* text_input); /** Clean text input view Note: this function does not free memory * - * @param wifi_text_input Text input instance + * @param text_input Text input instance */ -void wifi_text_input_reset(WIFI_TextInput* wifi_text_input); +void wifi_text_input_reset(WIFI_TextInput* text_input); /** Get text input view * - * @param wifi_text_input WIFI_TextInput instance + * @param text_input WIFI_TextInput instance * * @return View instance that can be used for embedding */ -View* wifi_text_input_get_view(WIFI_TextInput* wifi_text_input); +View* wifi_text_input_get_view(WIFI_TextInput* text_input); /** Set text input result callback * - * @param wifi_text_input WIFI_TextInput instance + * @param text_input WIFI_TextInput instance * @param callback callback fn * @param callback_context callback context * @param text_buffer pointer to YOUR text buffer, that we going @@ -53,7 +53,7 @@ View* wifi_text_input_get_view(WIFI_TextInput* wifi_text_input); * event */ void wifi_text_input_set_result_callback( - WIFI_TextInput* wifi_text_input, + WIFI_TextInput* text_input, WIFI_TextInputCallback callback, void* callback_context, char* text_buffer, @@ -61,22 +61,23 @@ void wifi_text_input_set_result_callback( bool clear_default_text); void wifi_text_input_set_validator( - WIFI_TextInput* wifi_text_input, + WIFI_TextInput* text_input, WIFI_TextInputValidatorCallback callback, void* callback_context); -WIFI_TextInputValidatorCallback - wifi_text_input_get_validator_callback(WIFI_TextInput* wifi_text_input); +void wifi_text_input_set_minimum_length(WIFI_TextInput* text_input, size_t minimum_length); -void* wifi_text_input_get_validator_callback_context(WIFI_TextInput* wifi_text_input); +WIFI_TextInputValidatorCallback wifi_text_input_get_validator_callback(WIFI_TextInput* text_input); + +void* wifi_text_input_get_validator_callback_context(WIFI_TextInput* text_input); /** Set text input header text * - * @param wifi_text_input WIFI_TextInput instance + * @param text_input WIFI_TextInput instance * @param text text to be shown */ -void wifi_text_input_set_header_text(WIFI_TextInput* wifi_text_input, const char* text); +void wifi_text_input_set_header_text(WIFI_TextInput* text_input, const char* text); #ifdef __cplusplus } -#endif +#endif \ No newline at end of file From 8ee959e1afc2e08b1f729cc4799a6f341ff61062 Mon Sep 17 00:00:00 2001 From: nminaylov Date: Fri, 19 May 2023 18:14:22 +0300 Subject: [PATCH 5/9] USB HID report timeout --- firmware/targets/f7/furi_hal/furi_hal_usb_hid.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/firmware/targets/f7/furi_hal/furi_hal_usb_hid.c b/firmware/targets/f7/furi_hal/furi_hal_usb_hid.c index d27613410..334aa0102 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_usb_hid.c +++ b/firmware/targets/f7/furi_hal/furi_hal_usb_hid.c @@ -436,7 +436,11 @@ static bool hid_send_report(uint8_t report_id) { if((hid_semaphore == NULL) || (hid_connected == false)) return false; if((boot_protocol == true) && (report_id != ReportIdKeyboard)) return false; - furi_check(furi_semaphore_acquire(hid_semaphore, FuriWaitForever) == FuriStatusOk); + FuriStatus status = furi_semaphore_acquire(hid_semaphore, HID_INTERVAL * 2); + if(status == FuriStatusErrorTimeout) { + return false; + } + furi_check(status == FuriStatusOk); if(hid_connected == false) { return false; } From 2bda0820bfb16c4397b4a7e99f0481ef30614936 Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Sat, 20 May 2023 09:38:44 +0300 Subject: [PATCH 6/9] SubGHz App: alloc balance --- applications/main/subghz/scenes/subghz_scene_decode_raw.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/applications/main/subghz/scenes/subghz_scene_decode_raw.c b/applications/main/subghz/scenes/subghz_scene_decode_raw.c index e88da3749..102965df5 100644 --- a/applications/main/subghz/scenes/subghz_scene_decode_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_decode_raw.c @@ -179,11 +179,12 @@ void subghz_scene_decode_raw_on_enter(void* context) { furi_string_get_cstr(item_time), subghz_history_get_type_protocol(subghz->history, i)); } - furi_string_free(item_name); - furi_string_free(item_time); subghz_view_receiver_set_idx_menu(subghz->subghz_receiver, subghz->idx_menu_chosen); } + furi_string_free(item_name); + furi_string_free(item_time); + subghz_scene_receiver_update_statusbar(subghz); view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdReceiver); From d949b010d863c25f8c81f5b1b956e263b61a93e1 Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Fri, 19 May 2023 23:21:18 +0300 Subject: [PATCH 7/9] Loading States & fix label length --- .../main/subghz_remote/helpers/subrem_types.h | 15 +++++ .../scenes/subrem_scene_openmapfile.c | 2 +- .../subghz_remote/scenes/subrem_scene_start.c | 6 +- .../main/subghz_remote/subghz_remote_app_i.c | 58 ++++++++++++------- .../main/subghz_remote/subghz_remote_app_i.h | 3 +- .../main/subghz_remote/views/remote.c | 2 +- 6 files changed, 60 insertions(+), 26 deletions(-) diff --git a/applications/main/subghz_remote/helpers/subrem_types.h b/applications/main/subghz_remote/helpers/subrem_types.h index 1b99aac6d..13b42897f 100644 --- a/applications/main/subghz_remote/helpers/subrem_types.h +++ b/applications/main/subghz_remote/helpers/subrem_types.h @@ -25,8 +25,23 @@ typedef enum { SubRemViewIDRemote, } SubRemViewID; +typedef enum { + SubRemLoadSubStateNotSet, + SubRemLoadSubStatePreloaded, + SubRemLoadSubStateError, + SubRemLoadSubStateErrorNoFile, + SubRemLoadSubStateErrorFreq, + SubRemLoadSubStateErrorMod, + SubRemLoadSubStateErrorProtocol, + SubRemLoadSubStateOK, +} SubRemLoadSubState; + typedef enum { SubRemLoadMapStateBack = 0, SubRemLoadMapStateError, + SubRemLoadMapStateErrorOpenError, + SubRemLoadMapStateErrorStorage, + SubRemLoadMapStateErrorBrokenFile, + SubRemLoadMapStateNotAllOK, SubRemLoadMapStateOK, } SubRemLoadMapState; \ No newline at end of file diff --git a/applications/main/subghz_remote/scenes/subrem_scene_openmapfile.c b/applications/main/subghz_remote/scenes/subrem_scene_openmapfile.c index 3391845e1..ea5c14a0a 100644 --- a/applications/main/subghz_remote/scenes/subrem_scene_openmapfile.c +++ b/applications/main/subghz_remote/scenes/subrem_scene_openmapfile.c @@ -18,7 +18,7 @@ void subrem_scene_openmapfile_on_enter(void* context) { dialog_message_free(message); #endif } - if(load_state == SubRemLoadMapStateOK) { + if(load_state == SubRemLoadMapStateOK || load_state == SubRemLoadMapStateNotAllOK) { scene_manager_next_scene(app->scene_manager, SubRemSceneRemote); } else { // TODO: Map Preset Reset diff --git a/applications/main/subghz_remote/scenes/subrem_scene_start.c b/applications/main/subghz_remote/scenes/subrem_scene_start.c index 962eda54c..a4bfa5047 100644 --- a/applications/main/subghz_remote/scenes/subrem_scene_start.c +++ b/applications/main/subghz_remote/scenes/subrem_scene_start.c @@ -34,8 +34,10 @@ void subrem_scene_start_on_enter(void* context) { // subrem_scene_start_submenu_callback, // app); - submenu_set_selected_item( - submenu, scene_manager_get_scene_state(app->scene_manager, SubRemSceneStart)); + // TODO: set scene state in subrem alloc + // submenu_set_selected_item( + // submenu, scene_manager_get_scene_state(app->scene_manager, SubRemSceneStart)); + submenu_set_selected_item(submenu, SubmenuIndexSubRemOpenMapFile); view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewSubmenu); } diff --git a/applications/main/subghz_remote/subghz_remote_app_i.c b/applications/main/subghz_remote/subghz_remote_app_i.c index 171618a5f..349fb87cd 100644 --- a/applications/main/subghz_remote/subghz_remote_app_i.c +++ b/applications/main/subghz_remote/subghz_remote_app_i.c @@ -51,6 +51,7 @@ SubRemSubFilePreset* subrem_sub_file_preset_alloc() { sub_preset->label = furi_string_alloc_set_str("N/A"); sub_preset->type = SubGhzProtocolTypeUnknown; + sub_preset->load_state = SubRemLoadSubStateNotSet; return sub_preset; } @@ -77,6 +78,7 @@ static void subrem_sub_file_preset_reset(SubRemSubFilePreset* sub_preset) { stream_clean(fff_data_stream); sub_preset->type = SubGhzProtocolTypeUnknown; + sub_preset->load_state = SubRemLoadSubStateNotSet; } void subrem_map_preset_reset(SubGhzRemoteApp* app) { @@ -108,6 +110,7 @@ static bool subrem_map_preset_load(SubGhzRemoteApp* app, FlipperFormat* fff_data #endif path_extract_filename(sub_preset->file_path, sub_preset->label, true); } else { + // Preload seccesful FURI_LOG_I( TAG, "%-5s: %s %s", @@ -115,6 +118,7 @@ static bool subrem_map_preset_load(SubGhzRemoteApp* app, FlipperFormat* fff_data furi_string_get_cstr(sub_preset->label), furi_string_get_cstr(sub_preset->file_path)); ret = true; + sub_preset->load_state = SubRemLoadSubStatePreloaded; } flipper_format_rewind(fff_data_file); } @@ -268,21 +272,25 @@ bool subrem_tx_stop_sub(SubGhzRemoteApp* app, bool forced) { return false; } -static bool subrem_map_preset_check(SubGhzRemoteApp* app, FlipperFormat* fff_data_file) { +static SubRemLoadMapState + subrem_map_preset_check(SubGhzRemoteApp* app, FlipperFormat* fff_data_file) { furi_assert(app); FuriString* temp_str = furi_string_alloc(); uint32_t temp_data32; - bool ret = false; - bool sub_preset_loaded = false; + bool all_loaded = true; + SubRemLoadMapState ret = SubRemLoadMapStateErrorBrokenFile; + SubRemLoadSubState sub_preset_loaded; SubRemSubFilePreset* sub_preset; uint32_t repeat = 200; for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { sub_preset = app->subs_preset[i]; - sub_preset_loaded = false; if(furi_string_empty(sub_preset->file_path)) { // FURI_LOG_I(TAG, "Empty file path"); continue; } + + sub_preset_loaded = SubRemLoadSubStateErrorNoFile; + repeat = 200; do { if(!flipper_format_file_open_existing( @@ -305,6 +313,7 @@ static bool subrem_map_preset_check(SubGhzRemoteApp* app, FlipperFormat* fff_dat } //Load frequency + sub_preset_loaded = SubRemLoadSubStateErrorFreq; if(!flipper_format_read_uint32(fff_data_file, "Frequency", &temp_data32, 1)) { FURI_LOG_W(TAG, "Cannot read frequency. Set default frequency"); sub_preset->freq_preset.frequency = @@ -317,6 +326,7 @@ static bool subrem_map_preset_check(SubGhzRemoteApp* app, FlipperFormat* fff_dat } //Load preset + sub_preset_loaded = SubRemLoadSubStateErrorMod; if(!flipper_format_read_string(fff_data_file, "Preset", temp_str)) { FURI_LOG_E(TAG, "Missing Preset"); break; @@ -329,6 +339,7 @@ static bool subrem_map_preset_check(SubGhzRemoteApp* app, FlipperFormat* fff_dat } //Load protocol + sub_preset_loaded = SubRemLoadSubStateErrorProtocol; if(!flipper_format_read_string(fff_data_file, "Protocol", temp_str)) { FURI_LOG_E(TAG, "Missing Protocol"); break; @@ -375,8 +386,9 @@ static bool subrem_map_preset_check(SubGhzRemoteApp* app, FlipperFormat* fff_dat break; } - sub_preset_loaded = true; - ret |= true; + sub_preset_loaded = SubRemLoadSubStateOK; + ret = SubRemLoadMapStateNotAllOK; + #if FURI_DEBUG FURI_LOG_I(TAG, "%-16s - protocol Loaded", furi_string_get_cstr(sub_preset->label)); #endif @@ -385,9 +397,15 @@ static bool subrem_map_preset_check(SubGhzRemoteApp* app, FlipperFormat* fff_dat // TODO: // Load file state logic // Label depending on the state + // Move to remote scene - if(!sub_preset_loaded) { + if(sub_preset_loaded != SubRemLoadSubStateOK) { furi_string_set_str(sub_preset->label, "N/A"); + all_loaded = false; + } + + if(ret != SubRemLoadMapStateErrorBrokenFile && all_loaded) { + ret = SubRemLoadMapStateOK; } flipper_format_file_close(fff_data_file); @@ -397,7 +415,7 @@ static bool subrem_map_preset_check(SubGhzRemoteApp* app, FlipperFormat* fff_dat return ret; } -bool subrem_map_file_load(SubGhzRemoteApp* app, const char* file_path) { +SubRemLoadMapState subrem_map_file_load(SubGhzRemoteApp* app, const char* file_path) { furi_assert(app); furi_assert(file_path); #if FURI_DEBUG @@ -405,7 +423,7 @@ bool subrem_map_file_load(SubGhzRemoteApp* app, const char* file_path) { #endif Storage* storage = furi_record_open(RECORD_STORAGE); FlipperFormat* fff_data_file = flipper_format_file_alloc(storage); - bool ret = false; + SubRemLoadMapState ret = SubRemLoadMapStateErrorOpenError; #if FURI_DEBUG FURI_LOG_I(TAG, "Open Map File.."); #endif @@ -413,20 +431,23 @@ bool subrem_map_file_load(SubGhzRemoteApp* app, const char* file_path) { if(!flipper_format_file_open_existing(fff_data_file, file_path)) { FURI_LOG_E(TAG, "Could not open MAP file %s", file_path); + ret = SubRemLoadMapStateErrorOpenError; } else { if(!subrem_map_preset_load(app, fff_data_file)) { FURI_LOG_E(TAG, "Could no Sub file path in MAP file"); // ret = // error for popup - } else if( - (flipper_format_file_close(fff_data_file)) && - (subrem_map_preset_check(app, fff_data_file))) { - FURI_LOG_I(TAG, "Load Map File Seccesful"); - ret = true; + } else if(!flipper_format_file_close(fff_data_file)) { + ret = SubRemLoadMapStateErrorOpenError; + } else { + ret = subrem_map_preset_check(app, fff_data_file); } } - // TODO: Popup for error or return error type - if(!ret) { + if(ret == SubRemLoadMapStateOK) { + FURI_LOG_I(TAG, "Load Map File Seccesful"); + } else if(ret == SubRemLoadMapStateNotAllOK) { + FURI_LOG_I(TAG, "Load Map File Seccesful [Not all files]"); + } else { FURI_LOG_E(TAG, "Broken Map File"); } @@ -434,7 +455,6 @@ bool subrem_map_file_load(SubGhzRemoteApp* app, const char* file_path) { flipper_format_free(fff_data_file); furi_record_close(RECORD_STORAGE); - return ret; } @@ -450,10 +470,8 @@ SubRemLoadMapState subrem_load_from_file(SubGhzRemoteApp* app) { // Input events and views are managed by file_select if(!dialog_file_browser_show(app->dialogs, app->file_path, app->file_path, &browser_options)) { - } else if(subrem_map_file_load(app, furi_string_get_cstr(app->file_path))) { - ret = SubRemLoadMapStateOK; } else { - ret = SubRemLoadMapStateError; + ret = subrem_map_file_load(app, furi_string_get_cstr(app->file_path)); } furi_string_free(file_path); diff --git a/applications/main/subghz_remote/subghz_remote_app_i.h b/applications/main/subghz_remote/subghz_remote_app_i.h index 1cbdbd5cd..40d70411a 100644 --- a/applications/main/subghz_remote/subghz_remote_app_i.h +++ b/applications/main/subghz_remote/subghz_remote_app_i.h @@ -42,6 +42,7 @@ typedef struct { FuriString* protocaol_name; FuriString* label; SubGhzProtocolType type; + SubRemLoadSubState load_state; } SubRemSubFilePreset; SubRemSubFilePreset* subrem_sub_file_preset_alloc(); @@ -70,8 +71,6 @@ typedef struct { bool tx_running; uint8_t chusen_sub; - - // TODO: LoadFileError } SubGhzRemoteApp; SubRemLoadMapState subrem_load_from_file(SubGhzRemoteApp* app); diff --git a/applications/main/subghz_remote/views/remote.c b/applications/main/subghz_remote/views/remote.c index 85c63568e..1f867cd0b 100644 --- a/applications/main/subghz_remote/views/remote.c +++ b/applications/main/subghz_remote/views/remote.c @@ -4,7 +4,7 @@ #include #include -#define SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH 16 +#define SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH 12 struct SubRemViewRemote { View* view; From d7db7b8b6729a486d9db1239edcb78c9c7f72531 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sun, 21 May 2023 20:18:09 +0300 Subject: [PATCH 8/9] fix builds for old pythons --- scripts/fbt/appmanifest.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/fbt/appmanifest.py b/scripts/fbt/appmanifest.py index ed1654e36..eb265cee8 100644 --- a/scripts/fbt/appmanifest.py +++ b/scripts/fbt/appmanifest.py @@ -1,7 +1,7 @@ import os from dataclasses import dataclass, field from enum import Enum -from typing import Callable, List, Optional, Tuple +from typing import Callable, List, Optional, Tuple, Union class FlipperManifestException(Exception): @@ -56,7 +56,7 @@ class FlipperApplication: # .fap-specific sources: List[str] = field(default_factory=lambda: ["*.c*"]) - fap_version: str | Tuple[int] = "0.1" + fap_version: Union[str, Tuple[int]] = "0.1" fap_icon: Optional[str] = None fap_libs: List[str] = field(default_factory=list) fap_category: str = "" From ef19fa9b51c3c6047a865ae8ba0db4f0c32df30f Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sun, 21 May 2023 20:37:55 +0300 Subject: [PATCH 9/9] SubRemote: Migrate old files and make folder if not exist --- applications/main/subghz_remote/subghz_remote_app.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/applications/main/subghz_remote/subghz_remote_app.c b/applications/main/subghz_remote/subghz_remote_app.c index 0b3f645ab..75f9fe3dc 100644 --- a/applications/main/subghz_remote/subghz_remote_app.c +++ b/applications/main/subghz_remote/subghz_remote_app.c @@ -23,6 +23,14 @@ static void subghz_remote_app_tick_event_callback(void* context) { SubGhzRemoteApp* subghz_remote_app_alloc() { SubGhzRemoteApp* app = malloc(sizeof(SubGhzRemoteApp)); + Storage* storage = furi_record_open(RECORD_STORAGE); + storage_common_migrate(storage, EXT_PATH("unirf"), SUBREM_APP_FOLDER); + + if(!storage_simply_mkdir(storage, SUBREM_APP_FOLDER)) { + //FURI_LOG_E(TAG, "Could not create folder %s", SUBREM_APP_FOLDER); + } + furi_record_close(RECORD_STORAGE); + // Enable power for External CC1101 if it is connected furi_hal_subghz_enable_ext_power(); // Auto switch to internal radio if external radio is not available