diff --git a/.github/assets/dark_theme_banner.png b/.github/assets/dark_theme_banner.png deleted file mode 100644 index 10a4e8c30..000000000 Binary files a/.github/assets/dark_theme_banner.png and /dev/null differ diff --git a/.github/assets/light_theme_banner.png b/.github/assets/light_theme_banner.png deleted file mode 100644 index 6c6b3b708..000000000 Binary files a/.github/assets/light_theme_banner.png and /dev/null differ diff --git a/.gitmodules b/.gitmodules index a97e0933a..de580c3c0 100644 --- a/.gitmodules +++ b/.gitmodules @@ -28,6 +28,9 @@ [submodule "lib/cxxheaderparser"] path = lib/cxxheaderparser url = https://github.com/robotpy/cxxheaderparser.git +[submodule "applications/plugins/subbrute"] + path = applications/plugins/subbrute + url = https://github.com/derskythe/flipperzero-subbrute.git [submodule "applications/plugins/dap_link/lib/free-dap"] path = applications/plugins/dap_link/lib/free-dap url = https://github.com/ataradov/free-dap.git diff --git a/applications/debug/uart_echo/application.fam b/applications/debug/uart_echo/application.fam index a16c611bd..b9766254c 100644 --- a/applications/debug/uart_echo/application.fam +++ b/applications/debug/uart_echo/application.fam @@ -1,6 +1,6 @@ App( appid="UART_Echo", - name="UART Echo", + name="[GPIO] UART Echo", apptype=FlipperAppType.PLUGIN, entry_point="uart_echo_app", cdefines=["APP_UART_ECHO"], @@ -8,5 +8,5 @@ App( stack_size=2 * 1024, order=70, fap_icon="uart_10px.png", - fap_category="Misc", + fap_category="GPIO", ) diff --git a/applications/main/bad_kb/bad_kb_app.c b/applications/main/bad_kb/bad_kb_app.c index dfce5acbf..e1219ffc4 100644 --- a/applications/main/bad_kb/bad_kb_app.c +++ b/applications/main/bad_kb/bad_kb_app.c @@ -37,9 +37,26 @@ static void bad_kb_load_settings(BadKbApp* app) { !storage_file_eof(settings_file) && !isspace(chr)) { furi_string_push_back(app->keyboard_layout, chr); } + } else { + furi_string_reset(app->keyboard_layout); } storage_file_close(settings_file); storage_file_free(settings_file); + + if(!furi_string_empty(app->keyboard_layout)) { + Storage* fs_api = furi_record_open(RECORD_STORAGE); + FileInfo layout_file_info; + FS_Error file_check_err = storage_common_stat( + fs_api, furi_string_get_cstr(app->keyboard_layout), &layout_file_info); + furi_record_close(RECORD_STORAGE); + if(file_check_err != FSE_OK) { + furi_string_reset(app->keyboard_layout); + return; + } + if(layout_file_info.size != 256) { + furi_string_reset(app->keyboard_layout); + } + } } static void bad_kb_save_settings(BadKbApp* app) { diff --git a/applications/main/bad_kb/bad_kb_app_i.h b/applications/main/bad_kb/bad_kb_app_i.h index 913830e72..38cae44c5 100644 --- a/applications/main/bad_kb/bad_kb_app_i.h +++ b/applications/main/bad_kb/bad_kb_app_i.h @@ -17,7 +17,7 @@ #include "views/bad_kb_view.h" #define BAD_KB_APP_BASE_FOLDER ANY_PATH("badkb") -#define BAD_KB_APP_PATH_LAYOUT_FOLDER BAD_KB_APP_BASE_FOLDER "/layouts" +#define BAD_KB_APP_PATH_LAYOUT_FOLDER BAD_KB_APP_BASE_FOLDER "/assets/layouts" #define BAD_KB_APP_SCRIPT_EXTENSION ".txt" #define BAD_KB_APP_LAYOUT_EXTENSION ".kl" diff --git a/applications/main/bad_kb/bad_kb_script.c b/applications/main/bad_kb/bad_kb_script.c index e2fd464ff..99622ff7c 100644 --- a/applications/main/bad_kb/bad_kb_script.c +++ b/applications/main/bad_kb/bad_kb_script.c @@ -949,7 +949,7 @@ void bad_kb_script_set_keyboard_layout(BadKbScript* bad_kb, FuriString* layout_p } File* layout_file = storage_file_alloc(furi_record_open(RECORD_STORAGE)); - if(!furi_string_empty(layout_path)) { + if(!furi_string_empty(layout_path)) { //-V1051 furi_string_set(bad_kb->keyboard_layout, layout_path); if(storage_file_open( layout_file, furi_string_get_cstr(layout_path), FSAM_READ, FSOM_OPEN_EXISTING)) { diff --git a/applications/main/bad_kb/scenes/bad_kb_scene_config_layout.c b/applications/main/bad_kb/scenes/bad_kb_scene_config_layout.c index 3842c59fa..a73822fcc 100644 --- a/applications/main/bad_kb/scenes/bad_kb_scene_config_layout.c +++ b/applications/main/bad_kb/scenes/bad_kb_scene_config_layout.c @@ -3,8 +3,6 @@ #include "furi_hal_usb.h" #include -#define KEYBOARD_FOLDER "/ext/badkb/layouts" - static bool bad_kb_layout_select(BadKbApp* bad_kb) { furi_assert(bad_kb); @@ -19,7 +17,8 @@ static bool bad_kb_layout_select(BadKbApp* bad_kb) { DialogsFileBrowserOptions browser_options; dialog_file_browser_set_basic_options( &browser_options, BAD_KB_APP_LAYOUT_EXTENSION, &I_keyboard_10px); - browser_options.base_path = KEYBOARD_FOLDER; + browser_options.base_path = BAD_KB_APP_PATH_LAYOUT_FOLDER; + browser_options.skip_assets = false; // Input events and views are managed by file_browser bool res = dialog_file_browser_show( diff --git a/applications/main/infrared/scenes/infrared_scene_universal.c b/applications/main/infrared/scenes/infrared_scene_universal.c index 09b77b1f7..1d6021171 100644 --- a/applications/main/infrared/scenes/infrared_scene_universal.c +++ b/applications/main/infrared/scenes/infrared_scene_universal.c @@ -52,7 +52,8 @@ void infrared_scene_universal_on_enter(void* context) { infrared_scene_universal_submenu_callback, context); - submenu_set_selected_item(submenu, 0); + submenu_set_selected_item( + submenu, scene_manager_get_scene_state(infrared->scene_manager, InfraredSceneUniversal)); view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewSubmenu); } diff --git a/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c b/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c index 6452792a6..fc9603744 100644 --- a/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c +++ b/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c @@ -117,16 +117,15 @@ static int32_t subghz_frequency_analyzer_worker_thread(void* context) { // First stage: coarse scan for(size_t i = 0; i < subghz_setting_get_frequency_count(instance->setting); i++) { - if(furi_hal_subghz_is_frequency_valid( - subghz_setting_get_frequency(instance->setting, i)) && + uint32_t current_frequnecy = subghz_setting_get_frequency(instance->setting, i); + if(furi_hal_subghz_is_frequency_valid(current_frequnecy) && + (current_frequnecy != 467750000) && !((furi_hal_subghz.radio_type == SubGhzRadioExternal) && - (subghz_setting_get_frequency(instance->setting, i) >= 311900000 && - subghz_setting_get_frequency(instance->setting, i) <= 312200000))) { + (current_frequnecy >= 311900000 && current_frequnecy <= 312200000))) { furi_hal_spi_acquire(furi_hal_subghz.spi_bus_handle); cc1101_switch_to_idle(furi_hal_subghz.spi_bus_handle); - frequency = cc1101_set_frequency( - furi_hal_subghz.spi_bus_handle, - subghz_setting_get_frequency(instance->setting, i)); + frequency = + cc1101_set_frequency(furi_hal_subghz.spi_bus_handle, current_frequnecy); cc1101_calibrate(furi_hal_subghz.spi_bus_handle); do { @@ -331,4 +330,4 @@ void subghz_frequency_analyzer_worker_set_trigger_level( float subghz_frequency_analyzer_worker_get_trigger_level(SubGhzFrequencyAnalyzerWorker* instance) { return instance->trigger_level; -} \ No newline at end of file +} diff --git a/applications/main/subghz/scenes/subghz_scene_ext_module_settings.c b/applications/main/subghz/scenes/subghz_scene_ext_module_settings.c index 7d7a505cb..4627c57be 100644 --- a/applications/main/subghz/scenes/subghz_scene_ext_module_settings.c +++ b/applications/main/subghz/scenes/subghz_scene_ext_module_settings.c @@ -13,7 +13,7 @@ const char* const radio_modules_variables_text[] = { #define DEBUG_P_COUNT 2 const char* const debug_pin_text[DEBUG_P_COUNT] = { "OFF", - "A7", + "17(1W)", }; static void subghz_scene_ext_module_changed(VariableItem* item) { diff --git a/applications/main/subghz/subghz_i.c b/applications/main/subghz/subghz_i.c index 1fbe662ed..9f9a4be8f 100644 --- a/applications/main/subghz/subghz_i.c +++ b/applications/main/subghz/subghz_i.c @@ -598,7 +598,7 @@ void subghz_hopper_update(SubGhz* subghz) { void subghz_speaker_on(SubGhz* subghz) { if(subghz->txrx->debug_pin_state) { - furi_hal_subghz_set_async_mirror_pin(&gpio_ext_pa7); + furi_hal_subghz_set_async_mirror_pin(&ibutton_gpio); } if(subghz->txrx->speaker_state == SubGhzSpeakerStateEnable) { @@ -643,7 +643,7 @@ void subghz_speaker_mute(SubGhz* subghz) { void subghz_speaker_unmute(SubGhz* subghz) { if(subghz->txrx->debug_pin_state) { - furi_hal_subghz_set_async_mirror_pin(&gpio_ext_pa7); + furi_hal_subghz_set_async_mirror_pin(&ibutton_gpio); } if(subghz->txrx->speaker_state == SubGhzSpeakerStateEnable) { if(furi_hal_speaker_is_mine()) { diff --git a/applications/main/subghz/views/receiver.c b/applications/main/subghz/views/receiver.c index fa3569245..48630eafb 100644 --- a/applications/main/subghz/views/receiver.c +++ b/applications/main/subghz/views/receiver.c @@ -261,13 +261,21 @@ void subghz_view_receiver_draw(Canvas* canvas, SubGhzViewReceiverModel* model) { if(model->history_item == 0) { if(model->mode == SubGhzViewReceiverModeLive) { - canvas_draw_icon(canvas, 0, 0, XTREME_ASSETS()->I_Scanning_123x52); + canvas_draw_icon( + canvas, + 0, + 0, + furi_hal_subghz_get_radio_type() ? &I_Fishing_123x52 : XTREME_ASSETS()->I_Scanning_123x52); canvas_set_font(canvas, FontPrimary); canvas_draw_str(canvas, 63, 46, "Scanning..."); //canvas_draw_line(canvas, 46, 51, 125, 51); canvas_set_font(canvas, FontSecondary); } else { - canvas_draw_icon(canvas, 0, 0, XTREME_ASSETS()->I_Scanning_123x52); + canvas_draw_icon( + canvas, + 0, + 0, + furi_hal_subghz_get_radio_type() ? &I_Fishing_123x52 : XTREME_ASSETS()->I_Scanning_123x52); canvas_set_font(canvas, FontPrimary); canvas_draw_str(canvas, 63, 46, "Decoding..."); canvas_set_font(canvas, FontSecondary); diff --git a/applications/main/subghz/views/subghz_frequency_analyzer.c b/applications/main/subghz/views/subghz_frequency_analyzer.c index ce2e34297..3b8c37d73 100644 --- a/applications/main/subghz/views/subghz_frequency_analyzer.c +++ b/applications/main/subghz/views/subghz_frequency_analyzer.c @@ -21,13 +21,12 @@ #define MAX_HISTORY 4 static const uint32_t subghz_frequency_list[] = { - 300000000, 302757000, 303875000, 304250000, 307000000, 307500000, 307800000, - 309000000, 310000000, 312000000, 312100000, 313000000, 313850000, 314000000, - 314350000, 314980000, 315000000, 318000000, 330000000, 345000000, 348000000, - 350000000, 387000000, 390000000, 418000000, 433075000, 433220000, 433420000, - 433657070, 433889000, 433920000, 434075000, 434176948, 434390000, 434420000, - 434775000, 438900000, 440175000, 464000000, 467750000, 779000000, 868350000, - 868400000, 868800000, 868950000, 906400000, 915000000, 925000000, 928000000}; + 300000000, 302757000, 303875000, 304250000, 307000000, 307500000, 307800000, 309000000, + 310000000, 312000000, 312100000, 313000000, 313850000, 314000000, 314350000, 314980000, + 315000000, 318000000, 330000000, 345000000, 348000000, 350000000, 387000000, 390000000, + 418000000, 433075000, 433220000, 433420000, 433657070, 433889000, 433920000, 434075000, + 434176948, 434390000, 434420000, 434775000, 438900000, 440175000, 464000000, 779000000, + 868350000, 868400000, 868800000, 868950000, 906400000, 915000000, 925000000, 928000000}; typedef enum { SubGhzFrequencyAnalyzerStatusIDLE, diff --git a/applications/main/unirfremix/unirfremix_app.c b/applications/main/unirfremix/unirfremix_app.c index 2b12a12b2..a0e131882 100644 --- a/applications/main/unirfremix/unirfremix_app.c +++ b/applications/main/unirfremix/unirfremix_app.c @@ -522,13 +522,14 @@ static bool unirfremix_send_sub(UniRFRemix* app, FlipperFormat* fff_data) { furi_hal_subghz_reset(); furi_hal_subghz_idle(); furi_hal_subghz_load_custom_preset(app->txpreset->data); - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_init(furi_hal_subghz.cc1101_g0_pin, GpioModeInput, GpioPullNo, GpioSpeedLow); furi_hal_subghz_idle(); furi_hal_subghz_set_frequency_and_path(app->txpreset->frequency); - furi_hal_gpio_write(&gpio_cc1101_g0, false); - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_write(furi_hal_subghz.cc1101_g0_pin, false); + furi_hal_gpio_init( + furi_hal_subghz.cc1101_g0_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); if(!furi_hal_subghz_tx()) { FURI_LOG_E(TAG, "Sending not allowed"); diff --git a/applications/plugins/arkanoid/arkanoid_game.c b/applications/plugins/arkanoid/arkanoid_game.c index af9976c98..0b9bb91e9 100644 --- a/applications/plugins/arkanoid/arkanoid_game.c +++ b/applications/plugins/arkanoid/arkanoid_game.c @@ -5,6 +5,7 @@ #include #include #include +#include #define TAG "Arkanoid" @@ -397,6 +398,9 @@ int32_t arkanoid_game_app(void* p) { Gui* gui = furi_record_open(RECORD_GUI); gui_add_view_port(gui, view_port, GuiLayerFullscreen); + // Call dolphin deed on game start + DOLPHIN_DEED(DolphinDeedPluginGameStart); + GameEvent event; for(bool processing = true; processing;) { FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100); diff --git a/applications/plugins/barcode_generator/application.fam b/applications/plugins/barcode_generator/application.fam index 97dc9acef..d2d7c4b96 100644 --- a/applications/plugins/barcode_generator/application.fam +++ b/applications/plugins/barcode_generator/application.fam @@ -9,7 +9,7 @@ App( "dialogs", ], stack_size=1 * 1024, - order=250, + order=50, fap_icon="barcode_10px.png", fap_category="Misc", -) +) \ No newline at end of file diff --git a/applications/plugins/barcode_generator/barcode_generator.c b/applications/plugins/barcode_generator/barcode_generator.c index 4aa54e7d4..cbbb41671 100644 --- a/applications/plugins/barcode_generator/barcode_generator.c +++ b/applications/plugins/barcode_generator/barcode_generator.c @@ -1,8 +1,3 @@ -#include -#include -#include -#include - #include "barcode_generator.h" static BarcodeType* barcodeTypes[NUMBER_OF_BARCODE_TYPES]; @@ -103,9 +98,9 @@ int get_menu_text_location(int index) { } int get_barcode_max_index(PluginState* plugin_state) { - return plugin_state->doParityCalculation ? - barcodeTypes[plugin_state->barcodeTypeIndex]->numberOfDigits - 1 : - barcodeTypes[plugin_state->barcodeTypeIndex]->numberOfDigits; + return plugin_state->barcode_state.doParityCalculation ? + barcodeTypes[plugin_state->barcode_state.barcodeTypeIndex]->numberOfDigits - 1 : + barcodeTypes[plugin_state->barcode_state.barcodeTypeIndex]->numberOfDigits; } int calculate_check_digit(PluginState* plugin_state, BarcodeType* type) { @@ -114,12 +109,12 @@ int calculate_check_digit(PluginState* plugin_state, BarcodeType* type) { int checkDigitEven = 0; //add all odd positions. Confusing because 0index for(int i = 0; i < type->numberOfDigits - 1; i += 2) { - checkDigitOdd += plugin_state->barcodeNumeral[i]; + checkDigitOdd += plugin_state->barcode_state.barcodeNumeral[i]; } //add all even positions to above. Confusing because 0index for(int i = 1; i < type->numberOfDigits - 1; i += 2) { - checkDigitEven += plugin_state->barcodeNumeral[i]; + checkDigitEven += plugin_state->barcode_state.barcodeNumeral[i]; } if(type->bartype == BarTypeEAN13) { @@ -152,7 +147,7 @@ static void render_callback(Canvas* const canvas, void* ctx) { canvas, 64, get_menu_text_location(2), AlignCenter, AlignCenter, "Parity?"); canvas_draw_frame(canvas, 83, get_menu_text_location(2) - 3, 6, 6); - if(plugin_state->doParityCalculation == true) { + if(plugin_state->barcode_state.doParityCalculation == true) { canvas_draw_box(canvas, 85, get_menu_text_location(2) - 1, 2, 2); } canvas_draw_str_aligned( @@ -161,14 +156,14 @@ static void render_callback(Canvas* const canvas, void* ctx) { get_menu_text_location(3), AlignCenter, AlignCenter, - (barcodeTypes[plugin_state->barcodeTypeIndex])->name); + (barcodeTypes[plugin_state->barcode_state.barcodeTypeIndex])->name); canvas_draw_disc( canvas, 40, get_menu_text_location(plugin_state->menuIndex) - 1, 2); //draw menu cursor } else { - BarcodeType* type = barcodeTypes[plugin_state->barcodeTypeIndex]; + BarcodeType* type = barcodeTypes[plugin_state->barcode_state.barcodeTypeIndex]; //start saftey canvas_set_color(canvas, ColorBlack); @@ -181,13 +176,13 @@ static void render_callback(Canvas* const canvas, void* ctx) { startpos++; draw_digit( canvas, - plugin_state->barcodeNumeral[0], + plugin_state->barcode_state.barcodeNumeral[0], BarEncodingTypeRight, - get_digit_position(0, barcodeTypes[plugin_state->barcodeTypeIndex]), + get_digit_position(0, barcodeTypes[plugin_state->barcode_state.barcodeTypeIndex]), false); } - if(plugin_state->doParityCalculation) { //calculate the check digit - plugin_state->barcodeNumeral[type->numberOfDigits - 1] = + if(plugin_state->barcode_state.doParityCalculation) { //calculate the check digit + plugin_state->barcode_state.barcodeNumeral[type->numberOfDigits - 1] = calculate_check_digit(plugin_state, type); } for(int index = startpos; index < endpos; index++) { @@ -197,7 +192,9 @@ static void render_callback(Canvas* const canvas, void* ctx) { barEncodingType = BarEncodingTypeRight; } else { barEncodingType = - (FURI_BIT(EAN13ENCODE[plugin_state->barcodeNumeral[0]], index - 1)) ? + (FURI_BIT( + EAN13ENCODE[plugin_state->barcode_state.barcodeNumeral[0]], + index - 1)) ? BarEncodingTypeG : BarEncodingTypeLeft; } @@ -207,10 +204,14 @@ static void render_callback(Canvas* const canvas, void* ctx) { } } - int digitPosition = - get_digit_position(index, barcodeTypes[plugin_state->barcodeTypeIndex]); + int digitPosition = get_digit_position( + index, barcodeTypes[plugin_state->barcode_state.barcodeTypeIndex]); draw_digit( - canvas, plugin_state->barcodeNumeral[index], barEncodingType, digitPosition, true); + canvas, + plugin_state->barcode_state.barcodeNumeral[index], + barEncodingType, + digitPosition, + true); } //central separator @@ -223,7 +224,8 @@ static void render_callback(Canvas* const canvas, void* ctx) { canvas_draw_box( canvas, get_digit_position( - plugin_state->editingIndex, barcodeTypes[plugin_state->barcodeTypeIndex]) - + plugin_state->editingIndex, + barcodeTypes[plugin_state->barcode_state.barcodeTypeIndex]) - 1, 63, 7, @@ -247,15 +249,17 @@ static void input_callback(InputEvent* input_event, FuriMessageQueue* event_queu furi_message_queue_put(event_queue, &event, FuriWaitForever); } -static void barcode_generator_state_init(PluginState* const plugin_state) { - for(int i = 0; i < BARCODE_MAX_LENS; ++i) { - plugin_state->barcodeNumeral[i] = i % 10; - } +static void barcode_generator_state_init(PluginState* plugin_state) { plugin_state->editingIndex = 0; plugin_state->mode = ViewMode; - plugin_state->doParityCalculation = true; plugin_state->menuIndex = MENU_INDEX_VIEW; - plugin_state->barcodeTypeIndex = 0; + if(!LOAD_BARCODE_SETTINGS(&plugin_state->barcode_state)) { + for(int i = 0; i < BARCODE_MAX_LENS; ++i) { + plugin_state->barcode_state.barcodeNumeral[i] = i % 10; + } + plugin_state->barcode_state.doParityCalculation = true; + plugin_state->barcode_state.barcodeTypeIndex = 0; + } } static bool handle_key_press_view(InputKey key, PluginState* plugin_state) { @@ -277,15 +281,15 @@ static bool handle_key_press_edit(InputKey key, PluginState* plugin_state) { switch(key) { case InputKeyUp: - plugin_state->barcodeNumeral[plugin_state->editingIndex] = - (plugin_state->barcodeNumeral[plugin_state->editingIndex] + 1) % 10; + plugin_state->barcode_state.barcodeNumeral[plugin_state->editingIndex] = + (plugin_state->barcode_state.barcodeNumeral[plugin_state->editingIndex] + 1) % 10; break; case InputKeyDown: - plugin_state->barcodeNumeral[plugin_state->editingIndex] = - (plugin_state->barcodeNumeral[plugin_state->editingIndex] == 0) ? + plugin_state->barcode_state.barcodeNumeral[plugin_state->editingIndex] = + (plugin_state->barcode_state.barcodeNumeral[plugin_state->editingIndex] == 0) ? 9 : - plugin_state->barcodeNumeral[plugin_state->editingIndex] - 1; + plugin_state->barcode_state.barcodeNumeral[plugin_state->editingIndex] - 1; break; case InputKeyRight: @@ -324,21 +328,24 @@ static bool handle_key_press_menu(InputKey key, PluginState* plugin_state) { case InputKeyRight: if(plugin_state->menuIndex == MENU_INDEX_TYPE) { - plugin_state->barcodeTypeIndex = - (plugin_state->barcodeTypeIndex == NUMBER_OF_BARCODE_TYPES - 1) ? + plugin_state->barcode_state.barcodeTypeIndex = + (plugin_state->barcode_state.barcodeTypeIndex == NUMBER_OF_BARCODE_TYPES - 1) ? 0 : - plugin_state->barcodeTypeIndex + 1; + plugin_state->barcode_state.barcodeTypeIndex + 1; } else if(plugin_state->menuIndex == MENU_INDEX_PARITY) { - plugin_state->doParityCalculation = !plugin_state->doParityCalculation; + plugin_state->barcode_state.doParityCalculation = + !plugin_state->barcode_state.doParityCalculation; } break; case InputKeyLeft: if(plugin_state->menuIndex == MENU_INDEX_TYPE) { - plugin_state->barcodeTypeIndex = (plugin_state->barcodeTypeIndex == 0) ? - NUMBER_OF_BARCODE_TYPES - 1 : - plugin_state->barcodeTypeIndex - 1; + plugin_state->barcode_state.barcodeTypeIndex = + (plugin_state->barcode_state.barcodeTypeIndex == 0) ? + NUMBER_OF_BARCODE_TYPES - 1 : + plugin_state->barcode_state.barcodeTypeIndex - 1; } else if(plugin_state->menuIndex == MENU_INDEX_PARITY) { - plugin_state->doParityCalculation = !plugin_state->doParityCalculation; + plugin_state->barcode_state.doParityCalculation = + !plugin_state->barcode_state.doParityCalculation; } break; @@ -348,12 +355,13 @@ static bool handle_key_press_menu(InputKey key, PluginState* plugin_state) { } else if(plugin_state->menuIndex == MENU_INDEX_EDIT) { plugin_state->mode = EditMode; } else if(plugin_state->menuIndex == MENU_INDEX_PARITY) { - plugin_state->doParityCalculation = !plugin_state->doParityCalculation; + plugin_state->barcode_state.doParityCalculation = + !plugin_state->barcode_state.doParityCalculation; } else if(plugin_state->menuIndex == MENU_INDEX_TYPE) { - plugin_state->barcodeTypeIndex = - (plugin_state->barcodeTypeIndex == NUMBER_OF_BARCODE_TYPES - 1) ? + plugin_state->barcode_state.barcodeTypeIndex = + (plugin_state->barcode_state.barcodeTypeIndex == NUMBER_OF_BARCODE_TYPES - 1) ? 0 : - plugin_state->barcodeTypeIndex + 1; + plugin_state->barcode_state.barcodeTypeIndex + 1; } break; @@ -430,6 +438,9 @@ int32_t barcode_generator_app(void* p) { furi_record_close(RECORD_GUI); view_port_free(view_port); furi_message_queue_free(event_queue); + // save settings + SAVE_BARCODE_SETTINGS(&plugin_state->barcode_state); + free(plugin_state); return 0; -} \ No newline at end of file +} diff --git a/applications/plugins/barcode_generator/barcode_generator.h b/applications/plugins/barcode_generator/barcode_generator.h index 1b5ff9e15..b39e43320 100644 --- a/applications/plugins/barcode_generator/barcode_generator.h +++ b/applications/plugins/barcode_generator/barcode_generator.h @@ -1,3 +1,34 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#define BARCODE_SETTINGS_FILE_NAME "apps/Misc/barcodegen.save" + +#define BARCODE_SETTINGS_VER (1) +#define BARCODE_SETTINGS_PATH EXT_PATH(BARCODE_SETTINGS_FILE_NAME) +#define BARCODE_SETTINGS_MAGIC (0xC2) + +#define SAVE_BARCODE_SETTINGS(x) \ + saved_struct_save( \ + BARCODE_SETTINGS_PATH, \ + (x), \ + sizeof(BarcodeState), \ + BARCODE_SETTINGS_MAGIC, \ + BARCODE_SETTINGS_VER) + +#define LOAD_BARCODE_SETTINGS(x) \ + saved_struct_load( \ + BARCODE_SETTINGS_PATH, \ + (x), \ + sizeof(BarcodeState), \ + BARCODE_SETTINGS_MAGIC, \ + BARCODE_SETTINGS_VER) + #define BARCODE_HEIGHT 50 #define BARCODE_Y_START 3 #define BARCODE_TEXT_OFFSET 9 @@ -45,11 +76,15 @@ typedef struct { typedef struct { int barcodeNumeral[BARCODE_MAX_LENS]; //The current barcode number + bool doParityCalculation; //Should do parity check? + int barcodeTypeIndex; +} BarcodeState; + +typedef struct { + BarcodeState barcode_state; int editingIndex; //The index of the editing symbol int menuIndex; //The index of the menu cursor Mode mode; //View, edit or menu - bool doParityCalculation; //Should do parity check? - int barcodeTypeIndex; } PluginState; static const int DIGITS[10][4] = { diff --git a/applications/plugins/blackjack/blackjack.c b/applications/plugins/blackjack/blackjack.c index 73d393f8b..9314e21dd 100644 --- a/applications/plugins/blackjack/blackjack.c +++ b/applications/plugins/blackjack/blackjack.c @@ -278,6 +278,7 @@ void dealer_tick(GameState* game_state) { if(dealer_score >= DEALER_MAX) { if(dealer_score > 21 || dealer_score < player_score) { + DOLPHIN_DEED(DolphinDeedPluginGameWin); enqueue( &(game_state->queue_state), game_state, @@ -571,6 +572,9 @@ int32_t blackjack_app(void* p) { AppEvent event; + // Call dolphin deed on game start + DOLPHIN_DEED(DolphinDeedPluginGameStart); + for(bool processing = true; processing;) { FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100); GameState* localstate = (GameState*)acquire_mutex_block(&state_mutex); diff --git a/applications/plugins/doom/doom.c b/applications/plugins/doom/doom.c index 78a06055c..65b63c75b 100644 --- a/applications/plugins/doom/doom.c +++ b/applications/plugins/doom/doom.c @@ -13,6 +13,7 @@ #include "level.h" #include #include +#include #define SOUND @@ -995,6 +996,9 @@ int32_t doom_app() { music_player_worker_load_rtttl_from_string(plugin_state->music_instance->worker, dsintro); music_player_worker_start(plugin_state->music_instance->worker); #endif + // Call dolphin deed on game start + DOLPHIN_DEED(DolphinDeedPluginGameStart); + for(bool processing = true; processing;) { FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100); PluginState* plugin_state = (PluginState*)acquire_mutex_block(&state_mutex); diff --git a/applications/plugins/flappy_bird/flappy_bird.c b/applications/plugins/flappy_bird/flappy_bird.c index a86ddb2bb..2a885f985 100644 --- a/applications/plugins/flappy_bird/flappy_bird.c +++ b/applications/plugins/flappy_bird/flappy_bird.c @@ -6,6 +6,7 @@ #include #include #include +#include #define TAG "Flappy" #define DEBUG false @@ -312,6 +313,9 @@ int32_t flappy_game_app(void* p) { Gui* gui = furi_record_open(RECORD_GUI); gui_add_view_port(gui, view_port, GuiLayerFullscreen); + // Call dolphin deed on game start + DOLPHIN_DEED(DolphinDeedPluginGameStart); + GameEvent event; for(bool processing = true; processing;) { FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100); diff --git a/applications/plugins/game15/game15.c b/applications/plugins/game15/game15.c index d9b059466..43d2e12f4 100644 --- a/applications/plugins/game15/game15.c +++ b/applications/plugins/game15/game15.c @@ -3,6 +3,7 @@ #include #include #include +#include #include "sandbox.h" @@ -461,6 +462,10 @@ int32_t game15_app() { sandbox_init( FPS, (SandboxRenderCallback)render_callback, (SandboxEventHandler)game_event_handler); + + // Call dolphin deed on game start + DOLPHIN_DEED(DolphinDeedPluginGameStart); + sandbox_loop(); sandbox_free(); game_free(); diff --git a/applications/plugins/game_2048/game_2048.c b/applications/plugins/game_2048/game_2048.c index e0c4a4cec..1a2f4a4d3 100644 --- a/applications/plugins/game_2048/game_2048.c +++ b/applications/plugins/game_2048/game_2048.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "digits.h" #include "array_utils.h" @@ -382,7 +383,7 @@ int32_t game_2048_app() { ValueMutex state_mutex; if(!init_mutex(&state_mutex, game_state, sizeof(GameState))) { - FURI_LOG_E("SnakeGame", "cannot create mutex\r\n"); + FURI_LOG_E("2048Game", "cannot create mutex\r\n"); free(game_state); return 255; } @@ -397,6 +398,9 @@ int32_t game_2048_app() { Gui* gui = furi_record_open(RECORD_GUI); gui_add_view_port(gui, view_port, GuiLayerFullscreen); + // Call dolphin deed on game start + DOLPHIN_DEED(DolphinDeedPluginGameStart); + bool is_finished = false; while(!is_finished) { FuriStatus event_status = furi_message_queue_get(event_queue, &input, FuriWaitForever); diff --git a/applications/plugins/heap_defence_game/heap_defence.c b/applications/plugins/heap_defence_game/heap_defence.c index a22a8db22..e40a97803 100644 --- a/applications/plugins/heap_defence_game/heap_defence.c +++ b/applications/plugins/heap_defence_game/heap_defence.c @@ -15,6 +15,7 @@ #include #include #include +#include #define Y_FIELD_SIZE 6 #define Y_LAST (Y_FIELD_SIZE - 1) @@ -530,6 +531,9 @@ int32_t heap_defence_app(void* p) { game->game_status = 0; game->animation = AnimationPause; + // Call dolphin deed on game start + DOLPHIN_DEED(DolphinDeedPluginGameStart); + GameEvent event = {0}; while(event.input.key != InputKeyBack) { if(furi_message_queue_get(event_queue, &event, 100) != FuriStatusOk) { diff --git a/applications/plugins/hex_viewer/README.md b/applications/plugins/hex_viewer/README.md deleted file mode 100644 index e830eef8e..000000000 --- a/applications/plugins/hex_viewer/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# flipper-zero-hex-viewer - -Hex Viewer application for Flipper Zero! - -![Hex Viewer app!](https://habrastorage.org/r/w1560/getpro/habr/upload_files/46e/28a/d97/46e28ad973d144b123a4ce513c895d18.png) - -[Link to FAP](https://nightly.link/QtRoS/flipper-zero-hex-viewer/actions/artifacts/448677581.zip) (firmware version 0.72) diff --git a/applications/plugins/hex_viewer/application.fam b/applications/plugins/hex_viewer/application.fam index cfddabb0d..7204e07c8 100644 --- a/applications/plugins/hex_viewer/application.fam +++ b/applications/plugins/hex_viewer/application.fam @@ -1,5 +1,5 @@ App( - appid="HEX_Viewer", + appid="hex_viewer", name="HEX Viewer", apptype=FlipperAppType.EXTERNAL, entry_point="hex_viewer_app", @@ -13,5 +13,4 @@ App( fap_icon="icons/hex_10px.png", fap_category="Misc", fap_icon_assets="icons", - fap_icon_assets_symbol="hex_viewer", ) diff --git a/applications/plugins/hid_app/application.fam b/applications/plugins/hid_app/application.fam index 86c65c2dd..7e04f0780 100644 --- a/applications/plugins/hid_app/application.fam +++ b/applications/plugins/hid_app/application.fam @@ -10,6 +10,7 @@ App( fap_icon_assets_symbol="hid", ) + App( appid="Bluetooth_Remote", name="Bluetooth Remote", diff --git a/applications/plugins/hid_app/hid_usb_10px.png b/applications/plugins/hid_app/hid_usb_10px.png index 415de7d23..7649138eb 100644 Binary files a/applications/plugins/hid_app/hid_usb_10px.png and b/applications/plugins/hid_app/hid_usb_10px.png differ diff --git a/applications/plugins/hid_app/views/hid_keyboard.c b/applications/plugins/hid_app/views/hid_keyboard.c index 82e772b15..9d29ccf5e 100644 --- a/applications/plugins/hid_app/views/hid_keyboard.c +++ b/applications/plugins/hid_app/views/hid_keyboard.c @@ -140,18 +140,18 @@ const HidKeyboardKey hid_keyboard_keyset[ROW_COUNT][COLUMN_COUNT] = { {.width = 1, .icon = &I_ButtonRight_4x7, .value = HID_KEYBOARD_RIGHT_ARROW}, }, { - {.width = 3, .icon = NULL, .key = "Ctrl", .value = HID_KEYBOARD_L_CTRL}, + {.width = 2, .icon = NULL, .key = "Ctl", .value = HID_KEYBOARD_L_CTRL}, {.width = 0, .icon = NULL, .value = HID_KEYBOARD_L_CTRL}, - {.width = 0, .icon = NULL, .value = HID_KEYBOARD_L_CTRL}, - {.width = 3, .icon = NULL, .key = "Alt", .value = HID_KEYBOARD_L_ALT}, + {.width = 2, .icon = NULL, .key = "Alt", .value = HID_KEYBOARD_L_ALT}, {.width = 0, .icon = NULL, .value = HID_KEYBOARD_L_ALT}, - {.width = 0, .icon = NULL, .value = HID_KEYBOARD_L_ALT}, - {.width = 3, .icon = NULL, .key = "Cmd", .value = HID_KEYBOARD_L_GUI}, + {.width = 2, .icon = NULL, .key = "Cmd", .value = HID_KEYBOARD_L_GUI}, {.width = 0, .icon = NULL, .value = HID_KEYBOARD_L_GUI}, - {.width = 0, .icon = NULL, .value = HID_KEYBOARD_L_GUI}, - {.width = 3, .icon = NULL, .key = "Tab", .value = HID_KEYBOARD_TAB}, - {.width = 0, .icon = NULL, .value = HID_KEYBOARD_TAB}, + {.width = 2, .icon = NULL, .key = "Tab", .value = HID_KEYBOARD_TAB}, {.width = 0, .icon = NULL, .value = HID_KEYBOARD_TAB}, + {.width = 2, .icon = NULL, .key = "Esc", .value = HID_KEYBOARD_ESCAPE}, + {.width = 0, .icon = NULL, .value = HID_KEYBOARD_ESCAPE}, + {.width = 2, .icon = NULL, .key = "Del", .value = HID_KEYBOARD_DELETE_FORWARD}, + {.width = 0, .icon = NULL, .value = HID_KEYBOARD_DELETE_FORWARD}, }, }; diff --git a/applications/plugins/hid_app/views/hid_mouse_jiggler.c b/applications/plugins/hid_app/views/hid_mouse_jiggler.c index d8f1f8928..120d5bc34 100644 --- a/applications/plugins/hid_app/views/hid_mouse_jiggler.c +++ b/applications/plugins/hid_app/views/hid_mouse_jiggler.c @@ -6,6 +6,8 @@ #define TAG "HidMouseJiggler" +#define LENGTH(x) (int)(sizeof(x) / sizeof((x)[0])) + struct HidMouseJiggler { View* view; Hid* hid; @@ -15,10 +17,13 @@ struct HidMouseJiggler { typedef struct { bool connected; bool running; + int interval_idx; uint8_t counter; HidTransport transport; } HidMouseJigglerModel; +const int intervals[6] = {500, 2000, 5000, 10000, 30000, 60000}; + static void hid_mouse_jiggler_draw_callback(Canvas* canvas, void* context) { furi_assert(context); HidMouseJigglerModel* model = context; @@ -33,29 +38,39 @@ static void hid_mouse_jiggler_draw_callback(Canvas* canvas, void* context) { } canvas_set_font(canvas, FontPrimary); - elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "Mouse Jiggler"); + elements_multiline_text_aligned(canvas, 17, 2, AlignLeft, AlignTop, "Mouse Jiggler"); + + // Timeout + elements_multiline_text(canvas, AlignLeft, 26, "Interval (ms):"); + canvas_set_font(canvas, FontSecondary); + if(model->interval_idx != 0) canvas_draw_icon(canvas, 74, 19, &I_ButtonLeft_4x7); + if(model->interval_idx != LENGTH(intervals) - 1) + canvas_draw_icon(canvas, 80, 19, &I_ButtonRight_4x7); + FuriString* interval_str = furi_string_alloc_printf("%d", intervals[model->interval_idx]); + elements_multiline_text(canvas, 91, 26, furi_string_get_cstr(interval_str)); + furi_string_free(interval_str); canvas_set_font(canvas, FontPrimary); - elements_multiline_text(canvas, AlignLeft, 35, "Press Start\nto jiggle"); + elements_multiline_text(canvas, AlignLeft, 40, "Press Start\nto jiggle"); canvas_set_font(canvas, FontSecondary); // Ok - canvas_draw_icon(canvas, 63, 25, &I_Space_65x18); + canvas_draw_icon(canvas, 63, 30, &I_Space_65x18); if(model->running) { - elements_slightly_rounded_box(canvas, 66, 27, 60, 13); + elements_slightly_rounded_box(canvas, 66, 32, 60, 13); canvas_set_color(canvas, ColorWhite); } - canvas_draw_icon(canvas, 74, 29, &I_Ok_btn_9x9); + canvas_draw_icon(canvas, 74, 34, &I_Ok_btn_9x9); if(model->running) { - elements_multiline_text_aligned(canvas, 91, 36, AlignLeft, AlignBottom, "Stop"); + elements_multiline_text_aligned(canvas, 91, 41, AlignLeft, AlignBottom, "Stop"); } else { - elements_multiline_text_aligned(canvas, 91, 36, AlignLeft, AlignBottom, "Start"); + elements_multiline_text_aligned(canvas, 91, 41, AlignLeft, AlignBottom, "Start"); } canvas_set_color(canvas, ColorBlack); // Back - canvas_draw_icon(canvas, 74, 49, &I_Pin_back_arrow_10x8); - elements_multiline_text_aligned(canvas, 91, 57, AlignLeft, AlignBottom, "Quit"); + canvas_draw_icon(canvas, 74, 54, &I_Pin_back_arrow_10x8); + elements_multiline_text_aligned(canvas, 91, 62, AlignLeft, AlignBottom, "Quit"); } static void hid_mouse_jiggler_timer_callback(void* context) { @@ -76,13 +91,6 @@ static void hid_mouse_jiggler_timer_callback(void* context) { false); } -static void hid_mouse_jiggler_enter_callback(void* context) { - furi_assert(context); - HidMouseJiggler* hid_mouse_jiggler = context; - - furi_timer_start(hid_mouse_jiggler->timer, 500); -} - static void hid_mouse_jiggler_exit_callback(void* context) { furi_assert(context); HidMouseJiggler* hid_mouse_jiggler = context; @@ -95,14 +103,30 @@ static bool hid_mouse_jiggler_input_callback(InputEvent* event, void* context) { bool consumed = false; - if(event->key == InputKeyOk) { - with_view_model( - hid_mouse_jiggler->view, - HidMouseJigglerModel * model, - { model->running = !model->running; }, - true); - consumed = true; - } + with_view_model( + hid_mouse_jiggler->view, + HidMouseJigglerModel * model, + { + if(event->type == InputTypePress && event->key == InputKeyOk) { + model->running = !model->running; + if(model->running) { + furi_timer_stop(hid_mouse_jiggler->timer); + furi_timer_start(hid_mouse_jiggler->timer, intervals[model->interval_idx]); + }; + consumed = true; + } + if(event->type == InputTypePress && event->key == InputKeyRight && !model->running && + model->interval_idx < LENGTH(intervals) - 1) { + model->interval_idx++; + consumed = true; + } + if(event->type == InputTypePress && event->key == InputKeyLeft && !model->running && + model->interval_idx > 0) { + model->interval_idx--; + consumed = true; + } + }, + true); return consumed; } @@ -116,7 +140,6 @@ HidMouseJiggler* hid_mouse_jiggler_alloc(Hid* hid) { hid_mouse_jiggler->view, ViewModelTypeLocking, sizeof(HidMouseJigglerModel)); view_set_draw_callback(hid_mouse_jiggler->view, hid_mouse_jiggler_draw_callback); view_set_input_callback(hid_mouse_jiggler->view, hid_mouse_jiggler_input_callback); - view_set_enter_callback(hid_mouse_jiggler->view, hid_mouse_jiggler_enter_callback); view_set_exit_callback(hid_mouse_jiggler->view, hid_mouse_jiggler_exit_callback); hid_mouse_jiggler->hid = hid; @@ -127,7 +150,10 @@ HidMouseJiggler* hid_mouse_jiggler_alloc(Hid* hid) { with_view_model( hid_mouse_jiggler->view, HidMouseJigglerModel * model, - { model->transport = hid->transport; }, + { + model->transport = hid->transport; + model->interval_idx = 2; + }, true); return hid_mouse_jiggler; diff --git a/applications/plugins/htu21d_temp_sensor/Readme.md b/applications/plugins/htu21d_temp_sensor/Readme.md deleted file mode 100644 index 45c332306..000000000 --- a/applications/plugins/htu21d_temp_sensor/Readme.md +++ /dev/null @@ -1,65 +0,0 @@ -[Original link](https://github.com/Mywk/FlipperTemperatureSensor) - -# Flipper Temperature Sensor - -## Supported sensors - -> HTU2xD, SHT2x, SI702x, SI700x, SI701x, AM2320 - -## What is this? - -A small app for the [Flipper Zero](https://flipperzero.one) that reads the [I2C](https://en.wikipedia.org/wiki/I%C2%B2C) signal from a few temperature sensors and displays the current temperature and humidity. - -I'm using a [Sparkfun HTU21D sensor](https://learn.sparkfun.com/tutorials/htu21d-humidity-sensor-hookup-guide), also tested with a clone and with the Si7021 variant. - -![Flipper Temperature Sensor](images/Flipper.png) - -![App](images/App.png) - -
- -# How to Connect the HTU21D sensor -![Connection](images/Connection.png) - - -# How to install - -If you have the FAP loader, just copy the fap file from the Releases into your Flipper apps folder and you should be able to launch it from the menu. - -If you don't have the FAP loader you will have to bake this application together with your firmware (aka compile it all together). - -# FAQ - -## The app says the sensor is not found! - -1- Are the four connectors correctly soldered? - -2- Are the SCL and SDA connections correct? Re-check the "How to Connect the sensor" above. - -3- For the HTU21D, on the sensor board, there should be three contacts in the center, for it to work correctly they must be soldered together (basically drop a blob of solder to connect the three of them). Without the solder it looks like this: - -![Sensor](images/Sensor.png) - -## Which Flipper versions was this app tested on? - -Version 1.2 -- RM11221439-0.71.2 -- unlshd-015 -- 0.71.1 - -Version 1.1 -- RM10302252-0.70.1 -- unlshd-012 -- 0.68.2-1007-RM -- 0.68.1 -- 0.67.2 - -## I can't build the app together with the firmware? - -In the *application.fam*, don't forget to change the apptype, it should not be EXTERNAL but APP. - -# How to compile - -Place the temperature_sensor folder in the applications_user folder and compile using FBT. - -Please refer to the [Flipper Build Tool documentation](https://github.com/flipperdevices/flipperzero-firmware/blob/dev/documentation/fbt.md). \ No newline at end of file diff --git a/applications/plugins/htu21d_temp_sensor/application.fam b/applications/plugins/htu21d_temp_sensor/application.fam deleted file mode 100644 index 724f55cd5..000000000 --- a/applications/plugins/htu21d_temp_sensor/application.fam +++ /dev/null @@ -1,14 +0,0 @@ -App( - appid="HTU_Temperature_Sensor", - name="[HTU/+] Temperature Sensor", - apptype=FlipperAppType.EXTERNAL, - entry_point="temperature_sensor_app", - cdefines=["APP_TEMPERATURE_SENSOR"], - requires=[ - "gui", - ], - stack_size=2 * 1024, - order=90, - fap_icon="temperature_sensor.png", - fap_category="GPIO", -) diff --git a/applications/plugins/htu21d_temp_sensor/docs/App.png b/applications/plugins/htu21d_temp_sensor/docs/App.png deleted file mode 100644 index a0373bdbd..000000000 Binary files a/applications/plugins/htu21d_temp_sensor/docs/App.png and /dev/null differ diff --git a/applications/plugins/htu21d_temp_sensor/docs/Connection.png b/applications/plugins/htu21d_temp_sensor/docs/Connection.png deleted file mode 100644 index b38f5c250..000000000 Binary files a/applications/plugins/htu21d_temp_sensor/docs/Connection.png and /dev/null differ diff --git a/applications/plugins/htu21d_temp_sensor/docs/Flipper.png b/applications/plugins/htu21d_temp_sensor/docs/Flipper.png deleted file mode 100644 index c85319593..000000000 Binary files a/applications/plugins/htu21d_temp_sensor/docs/Flipper.png and /dev/null differ diff --git a/applications/plugins/htu21d_temp_sensor/temperature_sensor.c b/applications/plugins/htu21d_temp_sensor/temperature_sensor.c deleted file mode 100644 index b04e40a7d..000000000 --- a/applications/plugins/htu21d_temp_sensor/temperature_sensor.c +++ /dev/null @@ -1,387 +0,0 @@ -/* Flipper App to read the values from a HTU2XD, SHT2X, SI702X, SI700X, SI701X or AM2320 Sensor */ -/* Created by Mywk - https://github.com/Mywk - https://mywk.net */ -#include -#include -#include -#include - -#include -#include - -#include - -#include - -#define TS_DEFAULT_VALUE 0xFFFF - -#define TS_AVAILABLE_SENSORS 2 - -// HTU2XD, SHT2X, SI702X, SI700X address -#define HTU2XD_SHT2X_SI702X_SI700X_ADDRESS (0x40 << 1) -// SI701X ADDRESS -#define SI701X_ADDRESS (0x41 << 1) - -// HTU2XD, SHT2X, SI702X, SI700X commands -#define HTU21D_CMD_TEMPERATURE 0xE3 -#define HTU21D_CMD_HUMIDITY 0xE5 - -// AM2320 address -#define AM2320_ADDRESS (0x5C << 1) - -// Used for the temperature and humidity buffers -#define DATA_BUFFER_SIZE 8 - -// External I2C BUS -#define I2C_BUS &furi_hal_i2c_handle_external - -// Typedef enums to make everything easier to read - -typedef enum { TSSCmdNone, TSSCmdTemperature, TSSCmdHumidity } TSSCmdType; - -typedef enum { - TSSInitializing, - TSSNoSensor, - TSSPendingUpdate, -} TSStatus; - -typedef enum { - TSEventTypeTick, - TSEventTypeInput, -} TSEventType; - -typedef struct { - TSEventType type; - InputEvent input; -} TSEvent; - -// Possible return values for sensor_cmd -typedef enum { - TSCmdRet_Error, - TSCmdRet_HTU2XD_SHT2X_SI702X_SI700X, - TSCmdRet_SI701X, - TSCmdRet_AM2320, -} TSCmdRet; - -// External NotificationSequence RGB -extern const NotificationSequence sequence_blink_red_100; -extern const NotificationSequence sequence_blink_green_100; -extern const NotificationSequence sequence_blink_blue_100; - -// Current status of the temperature sensor app -static TSStatus temperature_sensor_current_status = TSSInitializing; - -// We keep track of the last cmd return -static TSCmdRet temperature_sensor_last_cmd_ret = TSCmdRet_Error; - -// Temperature and Humidity data buffers, ready to print -char ts_data_buffer_temperature_c[DATA_BUFFER_SIZE]; -char ts_data_buffer_temperature_f[DATA_BUFFER_SIZE]; -char ts_data_buffer_relative_humidity[DATA_BUFFER_SIZE]; -char ts_data_buffer_absolute_humidity[DATA_BUFFER_SIZE]; - -// -// Executes an I2C cmd (trx) -// -// -// CRC -// -// -// true if fetch was successful, false otherwise -// -static TSCmdRet temperature_sensor_cmd(TSSCmdType cmd, uint8_t* buffer) { - uint32_t timeout = furi_ms_to_ticks(100); - TSCmdRet ret = TSCmdRet_Error; - - // Aquire I2C and check if device is ready, then release - furi_hal_i2c_acquire(I2C_BUS); - - // Check if HTU2XD, SHT2X, SI702X, SI700X sensor is available - uint8_t isAddress40 = - furi_hal_i2c_is_device_ready(I2C_BUS, HTU2XD_SHT2X_SI702X_SI700X_ADDRESS, timeout); - uint8_t isAddress41 = 0; - - // Check if SI701X sensor is available if necessary - if(!isAddress40) isAddress41 = furi_hal_i2c_is_device_ready(I2C_BUS, SI701X_ADDRESS, timeout); - - if(isAddress40 || isAddress41) { - uint8_t address = isAddress40 ? HTU2XD_SHT2X_SI702X_SI700X_ADDRESS : SI701X_ADDRESS; - - // Better safe than sorry delay - furi_delay_ms(15); - - // Extra delay for the SI70XX - if(isAddress41) furi_delay_ms(50); - - // Transmit either the temperature or the humidity command depending on TSSCmdType - uint8_t c = (cmd == TSSCmdTemperature) ? HTU21D_CMD_TEMPERATURE : HTU21D_CMD_HUMIDITY; - if(furi_hal_i2c_tx(I2C_BUS, address, &c, 1, timeout)) { - // Receive data (2 bytes) - if(furi_hal_i2c_rx(I2C_BUS, address, buffer, 2, timeout + 50)) - ret = isAddress40 ? TSCmdRet_HTU2XD_SHT2X_SI702X_SI700X : TSCmdRet_SI701X; - } - } else { - // The AM2320 goes to sleep after a period of inactivity, wake it up (check AM2320 datasheet for more info) - furi_hal_i2c_is_device_ready(I2C_BUS, AM2320_ADDRESS, timeout); - furi_delay_ms(30); - - // Check if it's really available - if(furi_hal_i2c_is_device_ready(I2C_BUS, AM2320_ADDRESS, timeout)) { - // {Address, Register, Len} - const uint8_t request[3] = {0x03, 0x00, 0x04}; - - if(furi_hal_i2c_tx(I2C_BUS, AM2320_ADDRESS, request, 3, timeout)) { - // 6 bytes - usually 8 but we currently don't check the CRC - if(furi_hal_i2c_rx(I2C_BUS, (uint8_t)AM2320_ADDRESS, buffer, 6, timeout)) - ret = TSCmdRet_AM2320; - } - } - } - - furi_hal_i2c_release(I2C_BUS); - - temperature_sensor_last_cmd_ret = ret; - return ret; -} - -// -// Fetches temperature and humidity from sensor -// -// -// temperature in C -// humidity in relative humidity -// -// -// Temperature and humidity must be preallocated -// -// -// CRC -// -// -// true if fetch was successful, false otherwise -// -static bool temperature_sensor_fetch_data(double* temperature, double* humidity) { - bool ret = false; - - uint16_t adc_raw; - - uint8_t buffer[DATA_BUFFER_SIZE] = {0x00}; - - // Check if the sensor is the HTU21D by attempting to fetch the temperature - TSCmdRet cmdRet = temperature_sensor_cmd(TSSCmdTemperature, buffer); - if(cmdRet == TSCmdRet_HTU2XD_SHT2X_SI702X_SI700X || cmdRet == TSCmdRet_SI701X) { - // Calculate temperature - adc_raw = ((uint16_t)(buffer[0] << 8) | (buffer[1])); - *temperature = (float)(adc_raw * 175.72 / 65536.00) - 46.85; - - // Fetch humidity - if(temperature_sensor_cmd(TSSCmdHumidity, buffer)) { - // Calculate humidity - adc_raw = ((uint16_t)(buffer[0] << 8) | (buffer[1])); - *humidity = (float)(adc_raw * 125.0 / 65536.00) - 6.0; - - ret = true; - } - } else if(cmdRet == TSCmdRet_AM2320) { - // The AM2320 returns all the data immediately so we just process it all - // Note: CRC isn't currently present in the buffer - - // Temperature - float temp = (((buffer[4] & 0x7F) << 8) + buffer[5]) / 10; - *temperature = ((buffer[4] & 0x80) >> 7) == 1 ? temp * (-1) : temp; - - // Humidity - temp = ((buffer[2] << 8) + buffer[3]) / 10; - *humidity = temp; - - ret = true; - } - - return ret; -} - -// -// Draw callback -// -static void temperature_sensor_draw_callback(Canvas* canvas, void* ctx) { - UNUSED(ctx); - - canvas_clear(canvas); - canvas_set_font(canvas, FontPrimary); - - // Update title accordingly (this could be improved by checking the hardware id) - switch(temperature_sensor_last_cmd_ret) { - case TSCmdRet_Error: - canvas_draw_str(canvas, 2, 10, "Temperature Sensor"); - break; - - case TSCmdRet_HTU2XD_SHT2X_SI702X_SI700X: - canvas_draw_str(canvas, 2, 10, "HTU/SHT/SI70 Sensor"); - break; - - case TSCmdRet_SI701X: - canvas_draw_str(canvas, 2, 10, "SI701X Sensor"); - break; - - case TSCmdRet_AM2320: - canvas_draw_str(canvas, 2, 10, "AM2320 Sensor"); - break; - - default: - break; - } - - canvas_set_font(canvas, FontSecondary); - canvas_draw_str(canvas, 2, 62, "Press back to exit."); - - switch(temperature_sensor_current_status) { - case TSSInitializing: - canvas_draw_str(canvas, 2, 30, "Initializing.."); - break; - case TSSNoSensor: - canvas_draw_str(canvas, 2, 30, "No sensor found!"); - break; - case TSSPendingUpdate: { - canvas_draw_str(canvas, 3, 24, "Temperature"); - canvas_draw_str(canvas, 68, 24, "Humidity"); - - // Draw vertical lines - canvas_draw_line(canvas, 61, 16, 61, 50); - canvas_draw_line(canvas, 62, 16, 62, 50); - - // Draw horizontal line - canvas_draw_line(canvas, 2, 27, 122, 27); - - // Draw temperature and humidity values - canvas_draw_str(canvas, 8, 38, ts_data_buffer_temperature_c); - canvas_draw_str(canvas, 42, 38, "C"); - canvas_draw_str(canvas, 8, 48, ts_data_buffer_temperature_f); - canvas_draw_str(canvas, 42, 48, "F"); - canvas_draw_str(canvas, 68, 38, ts_data_buffer_relative_humidity); - canvas_draw_str(canvas, 100, 38, "%"); - canvas_draw_str(canvas, 68, 48, ts_data_buffer_absolute_humidity); - canvas_draw_str(canvas, 100, 48, "g/m3"); - } break; - default: - break; - } -} - -// -// Input callback -// -static void temperature_sensor_input_callback(InputEvent* input_event, void* ctx) { - furi_assert(ctx); - FuriMessageQueue* event_queue = ctx; - - TSEvent event = {.type = TSEventTypeInput, .input = *input_event}; - furi_message_queue_put(event_queue, &event, FuriWaitForever); -} - -// -// Timer callback -// -static void temperature_sensor_timer_callback(FuriMessageQueue* event_queue) { - furi_assert(event_queue); - - TSEvent event = {.type = TSEventTypeTick}; - furi_message_queue_put(event_queue, &event, 0); -} - -// -// App entry point -// -int32_t temperature_sensor_app(void* p) { - UNUSED(p); - - // Declare our variables and assign variables a default value - TSEvent tsEvent; - bool sensorFound = false; - double celsius, fahrenheit, rel_humidity, abs_humidity = TS_DEFAULT_VALUE; - - // Used for absolute humidity calculation - double vapour_pressure = 0; - - FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(TSEvent)); - - // Register callbacks - ViewPort* view_port = view_port_alloc(); - view_port_draw_callback_set(view_port, temperature_sensor_draw_callback, NULL); - view_port_input_callback_set(view_port, temperature_sensor_input_callback, event_queue); - - // Create timer and register its callback - FuriTimer* timer = - furi_timer_alloc(temperature_sensor_timer_callback, FuriTimerTypePeriodic, event_queue); - furi_timer_start(timer, furi_kernel_get_tick_frequency()); - - // Register viewport - Gui* gui = furi_record_open(RECORD_GUI); - gui_add_view_port(gui, view_port, GuiLayerFullscreen); - - // Used to notify the user by blinking red (error) or blue (fetch successful) - NotificationApp* notifications = furi_record_open(RECORD_NOTIFICATION); - - while(1) { - furi_check(furi_message_queue_get(event_queue, &tsEvent, FuriWaitForever) == FuriStatusOk); - - // Handle events - if(tsEvent.type == TSEventTypeInput) { - // Exit on back key - if(tsEvent.input.key == - InputKeyBack) // We dont check for type here, we can check the type of keypress like: (event.input.type == InputTypeShort) - break; - } else if(tsEvent.type == TSEventTypeTick) { - // Update sensor data - // Fetch data and set the sensor current status accordingly - sensorFound = temperature_sensor_fetch_data(&celsius, &rel_humidity); - temperature_sensor_current_status = (sensorFound ? TSSPendingUpdate : TSSNoSensor); - - if(sensorFound) { - // Blink blue - notification_message(notifications, &sequence_blink_blue_100); - - if(celsius != TS_DEFAULT_VALUE && rel_humidity != TS_DEFAULT_VALUE) { - // Convert celsius to fahrenheit - fahrenheit = (celsius * 9 / 5) + 32; - - // Calculate absolute humidity - For more info refer to https://github.com/Mywk/FlipperTemperatureSensor/issues/1 - // Calculate saturation vapour pressure first - vapour_pressure = - (double)6.11 * - pow(10, (double)(((double)7.5 * celsius) / ((double)237.3 + celsius))); - // Then the vapour pressure in Pa - vapour_pressure = vapour_pressure * rel_humidity; - // Calculate absolute humidity - abs_humidity = - (double)2.16679 * (double)(vapour_pressure / ((double)273.15 + celsius)); - - // Fill our buffers here, not on the canvas draw callback - snprintf(ts_data_buffer_temperature_c, DATA_BUFFER_SIZE, "%.2f", celsius); - snprintf(ts_data_buffer_temperature_f, DATA_BUFFER_SIZE, "%.2f", fahrenheit); - snprintf( - ts_data_buffer_relative_humidity, DATA_BUFFER_SIZE, "%.2f", rel_humidity); - snprintf( - ts_data_buffer_absolute_humidity, DATA_BUFFER_SIZE, "%.2f", abs_humidity); - } - } else { - // Reset our variables to their default values - celsius = fahrenheit = rel_humidity = abs_humidity = TS_DEFAULT_VALUE; - - // Blink red - notification_message(notifications, &sequence_blink_red_100); - } - } - - furi_delay_ms(!sensorFound ? 100 : 500); - } - - // Dobby is freee (free our variables, Flipper will crash if we don't do this!) - furi_timer_free(timer); - gui_remove_view_port(gui, view_port); - view_port_free(view_port); - furi_message_queue_free(event_queue); - - furi_record_close(RECORD_NOTIFICATION); - furi_record_close(RECORD_GUI); - - return 0; -} \ No newline at end of file diff --git a/applications/plugins/htu21d_temp_sensor/temperature_sensor.png b/applications/plugins/htu21d_temp_sensor/temperature_sensor.png deleted file mode 100644 index b6fe6d7fe..000000000 Binary files a/applications/plugins/htu21d_temp_sensor/temperature_sensor.png and /dev/null differ diff --git a/applications/plugins/minesweeper/minesweeper.c b/applications/plugins/minesweeper/minesweeper.c index 75fb32e56..cbc1329bc 100644 --- a/applications/plugins/minesweeper/minesweeper.c +++ b/applications/plugins/minesweeper/minesweeper.c @@ -8,6 +8,8 @@ #include #include +#include + #include "assets.h" #define PLAYFIELD_WIDTH 16 @@ -251,6 +253,9 @@ static bool game_won(Minesweeper* minesweeper_state) { dialog_message_set_buttons(message, NULL, "Play again", NULL); dialog_message_set_icon(message, NULL, 72, 17); + // Call dolphin deed when we win the game + DOLPHIN_DEED(DolphinDeedPluginGameWin); + DialogMessageButton choice = dialog_message_show(dialogs, message); dialog_message_free(message); furi_string_free(tempStr); @@ -405,6 +410,9 @@ int32_t minesweeper_app(void* p) { Gui* gui = furi_record_open("gui"); gui_add_view_port(gui, view_port, GuiLayerFullscreen); + // Call dolphin deed on game start + DOLPHIN_DEED(DolphinDeedPluginGameStart); + PluginEvent event; for(bool processing = true; processing;) { FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100); diff --git a/applications/plugins/morse_code/morse_code.c b/applications/plugins/morse_code/morse_code.c index beb661222..3f96969e7 100644 --- a/applications/plugins/morse_code/morse_code.c +++ b/applications/plugins/morse_code/morse_code.c @@ -44,15 +44,10 @@ static void render_callback(Canvas* const canvas, void* ctx) { canvas_draw_frame(canvas, vol_bar_x_pos, vol_bar_y_pos, 4, 64); canvas_draw_box(canvas, vol_bar_x_pos, vol_bar_y_pos + (64 - volume_h), 4, volume_h); - //dit bpm - canvas_draw_str_aligned( - canvas, - 0, - 10, - AlignLeft, - AlignCenter, - furi_string_get_cstr( - furi_string_alloc_printf("Dit: %ld ms", morse_code->model->dit_delta))); + //dit bpms + FuriString* ditbpm = furi_string_alloc_printf("Dit: %ld ms", morse_code->model->dit_delta); + canvas_draw_str_aligned(canvas, 0, 10, AlignLeft, AlignCenter, furi_string_get_cstr(ditbpm)); + furi_string_free(ditbpm); //button info elements_button_center(canvas, "Press/Hold"); @@ -67,7 +62,7 @@ static void input_callback(InputEvent* input_event, void* ctx) { static void morse_code_worker_callback(FuriString* words, void* context) { MorseCode* morse_code = context; furi_check(furi_mutex_acquire(morse_code->model_mutex, FuriWaitForever) == FuriStatusOk); - morse_code->model->words = words; + furi_string_set(morse_code->model->words, words); furi_mutex_release(morse_code->model_mutex); view_port_update(morse_code->view_port); } @@ -109,6 +104,7 @@ void morse_code_free(MorseCode* instance) { furi_mutex_free(instance->model_mutex); + furi_string_free(instance->model->words); free(instance->model); free(instance); } @@ -116,10 +112,12 @@ void morse_code_free(MorseCode* instance) { int32_t morse_code_app() { MorseCode* morse_code = morse_code_alloc(); InputEvent input; + morse_code_worker_start(morse_code->worker); morse_code_worker_set_volume( morse_code->worker, MORSE_CODE_VOLUMES[morse_code->model->volume]); morse_code_worker_set_dit_delta(morse_code->worker, morse_code->model->dit_delta); + while(furi_message_queue_get(morse_code->input_queue, &input, FuriWaitForever) == FuriStatusOk) { furi_check(furi_mutex_acquire(morse_code->model_mutex, FuriWaitForever) == FuriStatusOk); @@ -128,6 +126,7 @@ int32_t morse_code_app() { break; } else if(input.key == InputKeyBack && input.type == InputTypeShort) { morse_code_worker_reset_text(morse_code->worker); + furi_string_reset(morse_code->model->words); } else if(input.key == InputKeyOk) { if(input.type == InputTypePress) morse_code_worker_play(morse_code->worker, true); @@ -160,6 +159,7 @@ int32_t morse_code_app() { furi_mutex_release(morse_code->model_mutex); view_port_update(morse_code->view_port); } + morse_code_worker_stop(morse_code->worker); morse_code_free(morse_code); return 0; diff --git a/applications/plugins/morse_code/morse_code_worker.c b/applications/plugins/morse_code/morse_code_worker.c index 142b427b6..47896b91a 100644 --- a/applications/plugins/morse_code/morse_code_worker.c +++ b/applications/plugins/morse_code/morse_code_worker.c @@ -35,6 +35,8 @@ void morse_code_worker_fill_buffer(MorseCodeWorker* instance, uint32_t duration) furi_string_push_back(instance->buffer, *DOT); else if(duration <= (instance->dit_delta * 3)) furi_string_push_back(instance->buffer, *LINE); + else + furi_string_reset(instance->buffer); if(furi_string_size(instance->buffer) > 5) furi_string_reset(instance->buffer); FURI_LOG_D("MorseCode: Buffer", "%s", furi_string_get_cstr(instance->buffer)); } @@ -87,9 +89,13 @@ static int32_t morse_code_worker_thread_callback(void* context) { if(!pushed) { if(end_tick + (instance->dit_delta * 3) < furi_get_tick()) { //NEW LETTER - morse_code_worker_fill_letter(instance); - if(instance->callback) - instance->callback(instance->words, instance->callback_context); + if(!furi_string_empty(instance->buffer)) { + morse_code_worker_fill_letter(instance); + if(instance->callback) + instance->callback(instance->words, instance->callback_context); + } else { + spaced = true; + } pushed = true; } } @@ -170,6 +176,7 @@ void morse_code_worker_start(MorseCodeWorker* instance) { void morse_code_worker_stop(MorseCodeWorker* instance) { furi_assert(instance); furi_assert(instance->is_running == true); + instance->play = false; instance->is_running = false; furi_thread_join(instance->thread); FURI_LOG_D("MorseCode: Stop", "Stop"); diff --git a/applications/plugins/pocsag_pager/pocsag_pager_app_i.c b/applications/plugins/pocsag_pager/pocsag_pager_app_i.c index ba6e87c28..ff73ab50e 100644 --- a/applications/plugins/pocsag_pager/pocsag_pager_app_i.c +++ b/applications/plugins/pocsag_pager/pocsag_pager_app_i.c @@ -40,7 +40,7 @@ void pcsg_begin(POCSAGPagerApp* app, uint8_t* preset_data) { furi_hal_subghz_reset(); furi_hal_subghz_idle(); furi_hal_subghz_load_custom_preset(preset_data); - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_init(furi_hal_subghz.cc1101_g0_pin, GpioModeInput, GpioPullNo, GpioSpeedLow); app->txrx->txrx_state = PCSGTxRxStateIDLE; } @@ -54,7 +54,7 @@ uint32_t pcsg_rx(POCSAGPagerApp* app, uint32_t frequency) { furi_hal_subghz_idle(); uint32_t value = furi_hal_subghz_set_frequency_and_path(frequency); - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_init(furi_hal_subghz.cc1101_g0_pin, GpioModeInput, GpioPullNo, GpioSpeedLow); furi_hal_subghz_flush_rx(); furi_hal_subghz_rx(); diff --git a/applications/plugins/pocsag_pager/scenes/pocsag_pager_receiver.c b/applications/plugins/pocsag_pager/scenes/pocsag_pager_receiver.c index 3f41b9b5d..658b70fea 100644 --- a/applications/plugins/pocsag_pager/scenes/pocsag_pager_receiver.c +++ b/applications/plugins/pocsag_pager/scenes/pocsag_pager_receiver.c @@ -195,6 +195,10 @@ bool pocsag_pager_scene_receiver_on_event(void* context, SceneManagerEvent event pcsg_hopper_update(app); pocsag_pager_scene_receiver_update_statusbar(app); } + // Get current RSSI + float rssi = furi_hal_subghz_get_rssi(); + pcsg_receiver_rssi(app->pcsg_receiver, rssi); + if(app->txrx->txrx_state == PCSGTxRxStateRx) { notification_message(app->notifications, &sequence_blink_cyan_10); } diff --git a/applications/plugins/pocsag_pager/views/pocsag_pager_receiver.c b/applications/plugins/pocsag_pager/views/pocsag_pager_receiver.c index 972c8dafb..3ab5898a0 100644 --- a/applications/plugins/pocsag_pager/views/pocsag_pager_receiver.c +++ b/applications/plugins/pocsag_pager/views/pocsag_pager_receiver.c @@ -12,6 +12,8 @@ #define MENU_ITEMS 4u #define UNLOCK_CNT 3 +#define SUBGHZ_RAW_TRESHOLD_MIN -90.0f + typedef struct { FuriString* item_str; uint8_t type; @@ -58,8 +60,24 @@ typedef struct { uint16_t list_offset; uint16_t history_item; PCSGReceiverBarShow bar_show; + uint8_t u_rssi; } PCSGReceiverModel; +void pcsg_receiver_rssi(PCSGReceiver* instance, float rssi) { + furi_assert(instance); + with_view_model( + instance->view, + PCSGReceiverModel * model, + { + if(rssi < SUBGHZ_RAW_TRESHOLD_MIN) { + model->u_rssi = 0; + } else { + model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_TRESHOLD_MIN); + } + }, + true); +} + void pcsg_view_receiver_set_lock(PCSGReceiver* pcsg_receiver, PCSGLock lock) { furi_assert(pcsg_receiver); pcsg_receiver->lock_count = 0; @@ -167,13 +185,23 @@ static void pcsg_view_receiver_draw_frame(Canvas* canvas, uint16_t idx, bool scr canvas_draw_dot(canvas, scrollbar ? 121 : 126, (0 + idx * FRAME_HEIGHT) + 11); } +static void pcsg_view_rssi_draw(Canvas* canvas, PCSGReceiverModel* model) { + for(uint8_t i = 1; i < model->u_rssi; i++) { + if(i % 5) { + canvas_draw_dot(canvas, 46 + i, 50); + canvas_draw_dot(canvas, 47 + i, 51); + canvas_draw_dot(canvas, 46 + i, 52); + } + } +} + void pcsg_view_receiver_draw(Canvas* canvas, PCSGReceiverModel* model) { canvas_clear(canvas); canvas_set_color(canvas, ColorBlack); canvas_set_font(canvas, FontSecondary); elements_button_left(canvas, "Config"); - canvas_draw_line(canvas, 46, 51, 125, 51); + //canvas_draw_line(canvas, 46, 51, 125, 51); bool scrollbar = model->history_item > 4; FuriString* str_buff; @@ -207,10 +235,13 @@ void pcsg_view_receiver_draw(Canvas* canvas, PCSGReceiverModel* model) { canvas_draw_icon(canvas, 0, 0, &I_Scanning_123x52); canvas_set_font(canvas, FontPrimary); canvas_draw_str(canvas, 63, 46, "Scanning..."); - canvas_draw_line(canvas, 46, 51, 125, 51); + //canvas_draw_line(canvas, 46, 51, 125, 51); canvas_set_font(canvas, FontSecondary); } + // Draw RSSI + pcsg_view_rssi_draw(canvas, model); + switch(model->bar_show) { case PCSGReceiverBarShowLock: canvas_draw_icon(canvas, 64, 55, &I_Lock_7x8); diff --git a/applications/plugins/pocsag_pager/views/pocsag_pager_receiver.h b/applications/plugins/pocsag_pager/views/pocsag_pager_receiver.h index 5ea2d4859..a13f5cdc7 100644 --- a/applications/plugins/pocsag_pager/views/pocsag_pager_receiver.h +++ b/applications/plugins/pocsag_pager/views/pocsag_pager_receiver.h @@ -8,6 +8,8 @@ typedef struct PCSGReceiver PCSGReceiver; typedef void (*PCSGReceiverCallback)(PCSGCustomEvent event, void* context); +void pcsg_receiver_rssi(PCSGReceiver* instance, float rssi); + void pcsg_view_receiver_set_lock(PCSGReceiver* pcsg_receiver, PCSGLock keyboard); void pcsg_view_receiver_set_callback( diff --git a/applications/plugins/protoview/README.md b/applications/plugins/protoview/README.md index 71083cdef..7523913ca 100644 --- a/applications/plugins/protoview/README.md +++ b/applications/plugins/protoview/README.md @@ -285,3 +285,5 @@ A big thank you to the RTL433 author, [Benjamin Larsson](https://github.com/merb * As a sourve of documentation for protocols. * As an awesome way to visualize and understand protocols, via [these great web tools](https://triq.org/). * To have tons of fun with RTLSDR in general, now and in the past. + +The application icon was designed by Stefano Liuzzo. diff --git a/applications/plugins/protoview/app.c b/applications/plugins/protoview/app.c index 4765da9e3..d27b3a54a 100644 --- a/applications/plugins/protoview/app.c +++ b/applications/plugins/protoview/app.c @@ -3,32 +3,6 @@ #include "app.h" -/* If this define is enabled, ProtoView is going to mess with the - * otherwise opaque SubGhzWorker structure in order to disable - * its filter for samples shorter than a given amount (30us at the - * time I'm writing this comment). - * - * This structure must be taken in sync with the one of the firmware. */ -#define PROTOVIEW_DISABLE_SUBGHZ_FILTER 0 - -#ifdef PROTOVIEW_DISABLE_SUBGHZ_FILTER -struct SubGhzWorker { - FuriThread* thread; - FuriStreamBuffer* stream; - - volatile bool running; - volatile bool overrun; - - LevelDuration filter_level_duration; - bool filter_running; - uint16_t filter_duration; - - SubGhzWorkerOverrunCallback overrun_callback; - SubGhzWorkerPairCallback pair_callback; - void* context; -}; -#endif - RawSamplesBuffer *RawSamples, *DetectedSamples; extern const SubGhzProtocolRegistry protoview_protocol_registry; @@ -42,6 +16,7 @@ extern const SubGhzProtocolRegistry protoview_protocol_registry; * and setting color to black. */ static void render_callback(Canvas* const canvas, void* ctx) { ProtoViewApp* app = ctx; + furi_mutex_acquire(app->view_updating_mutex, FuriWaitForever); /* Clear screen. */ canvas_set_color(canvas, ColorWhite); @@ -74,6 +49,7 @@ static void render_callback(Canvas* const canvas, void* ctx) { /* Draw the alert box if set. */ ui_draw_alert_if_needed(canvas, app); + furi_mutex_release(app->view_updating_mutex); } /* Here all we do is putting the events into the queue that will be handled @@ -91,6 +67,8 @@ static void input_callback(InputEvent* input_event, void* ctx) { * special views ViewGoNext and ViewGoPrev in order to move to * the logical next/prev view. */ static void app_switch_view(ProtoViewApp* app, ProtoViewCurrentView switchto) { + furi_mutex_acquire(app->view_updating_mutex, FuriWaitForever); + /* Switch to the specified view. */ ProtoViewCurrentView old = app->current_view; if(switchto == ViewGoNext) { @@ -106,22 +84,10 @@ static void app_switch_view(ProtoViewApp* app, ProtoViewCurrentView switchto) { } ProtoViewCurrentView new = app->current_view; - /* Set the current subview of the view we just left to zero. This is - * the main subview of the old view. When re re-enter the view we are - * lefting, we want to see the main thing again. */ - app->current_subview[old] = 0; - - /* Reset the view private data each time, before calling the enter/exit - * callbacks that may want to setup some state. */ - memset(app->view_privdata, 0, PROTOVIEW_VIEW_PRIVDATA_LEN); - - /* Call the enter/exit view callbacks if needed. */ + /* Call the exit view callbacks. */ if(old == ViewDirectSampling) view_exit_direct_sampling(app); - if(new == ViewDirectSampling) view_enter_direct_sampling(app); if(old == ViewBuildMessage) view_exit_build_message(app); - if(new == ViewBuildMessage) view_enter_build_message(app); if(old == ViewInfo) view_exit_info(app); - /* The frequency/modulation settings are actually a single view: * as long as the user stays between the two modes of this view we * don't need to call the exit-view callback. */ @@ -129,7 +95,24 @@ static void app_switch_view(ProtoViewApp* app, ProtoViewCurrentView switchto) { (old == ViewModulationSettings && new != ViewFrequencySettings)) view_exit_settings(app); + /* Reset the view private data each time, before calling the enter + * callbacks that may want to setup some state. */ + memset(app->view_privdata, 0, PROTOVIEW_VIEW_PRIVDATA_LEN); + + /* Call the enter view callbacks after all the exit callback + * of the old view was already executed. */ + if(new == ViewDirectSampling) view_enter_direct_sampling(app); + if(new == ViewBuildMessage) view_enter_build_message(app); + + /* Set the current subview of the view we just left to zero. This is + * the main subview of the old view. When we re-enter the view we are + * lefting, we want to see the main thing again. */ + app->current_subview[old] = 0; + + /* If there is an alert on screen, dismiss it: if the user is + * switching view she already read it. */ ui_dismiss_alert(app); + furi_mutex_release(app->view_updating_mutex); } /* Allocate the application state and initialize a number of stuff. @@ -143,7 +126,7 @@ ProtoViewApp* protoview_app_alloc() { //init setting app->setting = subghz_setting_alloc(); - subghz_setting_load(app->setting, EXT_PATH("subghz/assets/setting_user.txt")); + subghz_setting_load(app->setting, EXT_PATH("subghz/assets/setting_user")); // GUI app->gui = furi_record_open(RECORD_GUI); @@ -158,6 +141,7 @@ ProtoViewApp* protoview_app_alloc() { app->show_text_input = false; app->alert_dismiss_time = 0; app->current_view = ViewRawPulses; + app->view_updating_mutex = furi_mutex_alloc(FuriMutexTypeNormal); for(int j = 0; j < ViewLast; j++) app->current_subview[j] = 0; app->direct_sampling_enabled = false; app->view_privdata = malloc(PROTOVIEW_VIEW_PRIVDATA_LEN); @@ -174,25 +158,11 @@ ProtoViewApp* protoview_app_alloc() { // Init Worker & Protocol app->txrx = malloc(sizeof(ProtoViewTxRx)); - /* Setup rx worker and environment. */ + /* Setup rx state. */ app->txrx->freq_mod_changed = false; app->txrx->debug_timer_sampling = false; app->txrx->last_g0_change_time = DWT->CYCCNT; app->txrx->last_g0_value = false; - app->txrx->worker = subghz_worker_alloc(); -#ifdef PROTOVIEW_DISABLE_SUBGHZ_FILTER - app->txrx->worker->filter_running = 0; -#endif - app->txrx->environment = subghz_environment_alloc(); - subghz_environment_set_protocol_registry( - app->txrx->environment, (void*)&protoview_protocol_registry); - app->txrx->receiver = subghz_receiver_alloc_init(app->txrx->environment); - subghz_receiver_set_filter(app->txrx->receiver, SubGhzProtocolFlag_Decodable); - subghz_worker_set_overrun_callback( - app->txrx->worker, (SubGhzWorkerOverrunCallback)subghz_receiver_reset); - subghz_worker_set_pair_callback( - app->txrx->worker, (SubGhzWorkerPairCallback)subghz_receiver_decode); - subghz_worker_set_context(app->txrx->worker, app->txrx->receiver); app->frequency = subghz_setting_get_default_frequency(app->setting); app->modulation = 0; /* Defaults to ProtoViewModulations[0]. */ @@ -219,17 +189,13 @@ void protoview_app_free(ProtoViewApp* app) { furi_record_close(RECORD_GUI); furi_record_close(RECORD_NOTIFICATION); furi_message_queue_free(app->event_queue); + furi_mutex_free(app->view_updating_mutex); app->gui = NULL; // Frequency setting. subghz_setting_free(app->setting); // Worker stuff. - if(!app->txrx->debug_timer_sampling) { - subghz_receiver_free(app->txrx->receiver); - subghz_environment_free(app->txrx->environment); - subghz_worker_free(app->txrx->worker); - } free(app->txrx); // Raw samples buffers. @@ -259,7 +225,7 @@ static void timer_callback(void* ctx) { } if(delta < RawSamples->total / 2) return; app->signal_last_scan_idx = RawSamples->idx; - scan_for_signal(app, RawSamples); + scan_for_signal(app, RawSamples, ProtoViewModulations[app->modulation].duration_filter); } /* This is the navigation callback we use in the view dispatcher used diff --git a/applications/plugins/protoview/app.h b/applications/plugins/protoview/app.h index 85007e345..624c118e2 100644 --- a/applications/plugins/protoview/app.h +++ b/applications/plugins/protoview/app.h @@ -17,9 +17,6 @@ #include #include #include -#include -#include -#include #include #include "raw_samples.h" @@ -28,7 +25,7 @@ #define BITMAP_SEEK_NOT_FOUND UINT32_MAX // Returned by function as sentinel #define PROTOVIEW_VIEW_PRIVDATA_LEN 64 // View specific private data len -#define DEBUG_MSG 1 +#define DEBUG_MSG 0 /* Forward declarations. */ @@ -69,8 +66,11 @@ typedef struct { const char* name; // Name to show to the user. const char* id; // Identifier in the Flipper API/file. FuriHalSubGhzPreset preset; // The preset ID. - uint8_t* custom; // If not null, a set of registers for - // the CC1101, specifying a custom preset. + uint8_t* custom; /* If not null, a set of registers for + the CC1101, specifying a custom preset.*/ + uint32_t duration_filter; /* Ignore pulses and gaps that are less + than the specified microseconds. This + depends on the data rate. */ } ProtoViewModulation; extern ProtoViewModulation ProtoViewModulations[]; /* In app_subghz.c */ @@ -82,9 +82,6 @@ struct ProtoViewTxRx { bool freq_mod_changed; /* The user changed frequency and/or modulation from the interface. There is to restart the radio with the right parameters. */ - SubGhzWorker* worker; /* Our background worker. */ - SubGhzEnvironment* environment; - SubGhzReceiver* receiver; TxRxState txrx_state; /* Receiving, idle or sleeping? */ /* Timer sampling mode state. */ @@ -108,6 +105,10 @@ struct ProtoViewApp { ViewPort* view_port; /* We just use a raw viewport and we render everything into the low level canvas. */ ProtoViewCurrentView current_view; /* Active left-right view ID. */ + FuriMutex* view_updating_mutex; /* The Flipper GUI calls the screen redraw + callback in a different thread. We + use this mutex to protect the redraw + from changes in app->view_privdata. */ int current_subview[ViewLast]; /* Active up-down subview ID. */ FuriMessageQueue* event_queue; /* Keypress events go here. */ @@ -238,7 +239,7 @@ typedef struct ProtoViewDecoder { extern RawSamplesBuffer *RawSamples, *DetectedSamples; -/* app_radio.c */ +/* app_subghz.c */ void radio_begin(ProtoViewApp* app); uint32_t radio_rx(ProtoViewApp* app); void radio_idle(ProtoViewApp* app); @@ -247,11 +248,12 @@ void radio_sleep(ProtoViewApp* app); void raw_sampling_worker_start(ProtoViewApp* app); void raw_sampling_worker_stop(ProtoViewApp* app); void radio_tx_signal(ProtoViewApp* app, FuriHalSubGhzAsyncTxCallback data_feeder, void* ctx); +void protoview_rx_callback(bool level, uint32_t duration, void* context); /* signal.c */ uint32_t duration_delta(uint32_t a, uint32_t b); void reset_current_signal(ProtoViewApp* app); -void scan_for_signal(ProtoViewApp* app, RawSamplesBuffer* source); +void scan_for_signal(ProtoViewApp* app, RawSamplesBuffer* source, uint32_t min_duration); bool bitmap_get(uint8_t* b, uint32_t blen, uint32_t bitpos); void bitmap_set(uint8_t* b, uint32_t blen, uint32_t bitpos, bool val); void bitmap_copy( @@ -271,6 +273,15 @@ uint32_t bitmap_seek_bits( uint32_t startpos, uint32_t maxbits, const char* bits); +bool bitmap_match_bitmap( + uint8_t* b1, + uint32_t b1len, + uint32_t b1off, + uint8_t* b2, + uint32_t b2len, + uint32_t b2off, + uint32_t cmplen); +void bitmap_to_string(char* dst, uint8_t* b, uint32_t blen, uint32_t off, uint32_t len); uint32_t convert_from_line_code( uint8_t* buf, uint64_t buflen, @@ -339,7 +350,7 @@ void fieldset_add_int(ProtoViewFieldSet* fs, const char* name, int64_t val, uint void fieldset_add_uint(ProtoViewFieldSet* fs, const char* name, uint64_t uval, uint8_t bits); void fieldset_add_hex(ProtoViewFieldSet* fs, const char* name, uint64_t uval, uint8_t bits); void fieldset_add_bin(ProtoViewFieldSet* fs, const char* name, uint64_t uval, uint8_t bits); -void fieldset_add_str(ProtoViewFieldSet* fs, const char* name, const char* s); +void fieldset_add_str(ProtoViewFieldSet* fs, const char* name, const char* s, size_t len); void fieldset_add_bytes( ProtoViewFieldSet* fs, const char* name, @@ -359,3 +370,5 @@ void field_set_from_field(ProtoViewField* dst, ProtoViewField* src); /* crc.c */ uint8_t crc8(const uint8_t* data, size_t len, uint8_t init, uint8_t poly); +uint8_t sum_bytes(const uint8_t* data, size_t len, uint8_t init); +uint8_t xor_bytes(const uint8_t* data, size_t len, uint8_t init); diff --git a/applications/plugins/protoview/app_subghz.c b/applications/plugins/protoview/app_subghz.c index 73e0e16ae..69197df5c 100644 --- a/applications/plugins/protoview/app_subghz.c +++ b/applications/plugins/protoview/app_subghz.c @@ -9,31 +9,32 @@ #include #include -void raw_sampling_worker_start(ProtoViewApp* app); -void raw_sampling_worker_stop(ProtoViewApp* app); +void raw_sampling_timer_start(ProtoViewApp* app); +void raw_sampling_timer_stop(ProtoViewApp* app); ProtoViewModulation ProtoViewModulations[] = { - {"OOK 650Khz", "FuriHalSubGhzPresetOok650Async", FuriHalSubGhzPresetOok650Async, NULL}, - {"OOK 270Khz", "FuriHalSubGhzPresetOok270Async", FuriHalSubGhzPresetOok270Async, NULL}, + {"OOK 650Khz", "FuriHalSubGhzPresetOok650Async", FuriHalSubGhzPresetOok650Async, NULL, 30}, + {"OOK 270Khz", "FuriHalSubGhzPresetOok270Async", FuriHalSubGhzPresetOok270Async, NULL, 30}, {"2FSK 2.38Khz", "FuriHalSubGhzPreset2FSKDev238Async", FuriHalSubGhzPreset2FSKDev238Async, - NULL}, + NULL, + 30}, {"2FSK 47.6Khz", "FuriHalSubGhzPreset2FSKDev476Async", FuriHalSubGhzPreset2FSKDev476Async, - NULL}, - {"TPMS 1 (FSK)", NULL, 0, (uint8_t*)protoview_subghz_tpms1_fsk_async_regs}, - {"TPMS 2 (OOK)", NULL, 0, (uint8_t*)protoview_subghz_tpms2_ook_async_regs}, - {"TPMS 3 (FSK)", NULL, 0, (uint8_t*)protoview_subghz_tpms3_fsk_async_regs}, - {"TPMS 4 (FSK)", NULL, 0, (uint8_t*)protoview_subghz_tpms4_fsk_async_regs}, - {NULL, NULL, 0, NULL} /* End of list sentinel. */ + NULL, + 30}, + {"TPMS 1 (FSK)", NULL, 0, (uint8_t*)protoview_subghz_tpms1_fsk_async_regs, 30}, + {"TPMS 2 (OOK)", NULL, 0, (uint8_t*)protoview_subghz_tpms2_ook_async_regs, 30}, + {"TPMS 3 (GFSK)", NULL, 0, (uint8_t*)protoview_subghz_tpms3_gfsk_async_regs, 30}, + {"OOK 40kBaud", NULL, 0, (uint8_t*)protoview_subghz_40k_ook_async_regs, 15}, + {"FSK 40kBaud", NULL, 0, (uint8_t*)protoview_subghz_40k_fsk_async_regs, 15}, + {NULL, NULL, 0, NULL, 0} /* End of list sentinel. */ }; /* Called after the application initialization in order to setup the - * subghz system and put it into idle state. If the user wants to start - * receiving we will call radio_rx() to start a receiving worker and - * associated thread. */ + * subghz system and put it into idle state. */ void radio_begin(ProtoViewApp* app) { furi_assert(app); furi_hal_subghz_reset(); @@ -51,13 +52,23 @@ void radio_begin(ProtoViewApp* app) { } else { furi_hal_subghz_load_custom_preset(ProtoViewModulations[app->modulation].custom); } - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_init(furi_hal_subghz.cc1101_g0_pin, GpioModeInput, GpioPullNo, GpioSpeedLow); app->txrx->txrx_state = TxRxStateIDLE; } /* ================================= Reception ============================== */ -/* Setup subghz to start receiving using a background worker. */ +/* We avoid the subghz provided abstractions and put the data in our + * simple abstraction: the RawSamples circular buffer. */ +void protoview_rx_callback(bool level, uint32_t duration, void* context) { + UNUSED(context); + /* Add data to the circular buffer. */ + raw_samples_add(RawSamples, level, duration); + // FURI_LOG_E(TAG, "FEED: %d %d", (int)level, (int)duration); + return; +} + +/* Setup the CC1101 to start receiving using a background worker. */ uint32_t radio_rx(ProtoViewApp* app) { furi_assert(app); if(!furi_hal_subghz_is_frequency_valid(app->frequency)) { @@ -69,12 +80,11 @@ uint32_t radio_rx(ProtoViewApp* app) { furi_hal_subghz_idle(); /* Put it into idle state in case it is sleeping. */ uint32_t value = furi_hal_subghz_set_frequency_and_path(app->frequency); FURI_LOG_E(TAG, "Switched to frequency: %lu", value); - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_init(furi_hal_subghz.cc1101_g0_pin, GpioModeInput, GpioPullNo, GpioSpeedLow); furi_hal_subghz_flush_rx(); furi_hal_subghz_rx(); if(!app->txrx->debug_timer_sampling) { - furi_hal_subghz_start_async_rx(subghz_worker_rx_callback, app->txrx->worker); - subghz_worker_start(app->txrx->worker); + furi_hal_subghz_start_async_rx(protoview_rx_callback, NULL); } else { raw_sampling_worker_start(app); } @@ -82,16 +92,13 @@ uint32_t radio_rx(ProtoViewApp* app) { return value; } -/* Stop subghz worker (if active), put radio on idle state. */ +/* Stop receiving (if active) and put the radio on idle state. */ void radio_rx_end(ProtoViewApp* app) { furi_assert(app); if(app->txrx->txrx_state == TxRxStateRx) { if(!app->txrx->debug_timer_sampling) { - if(subghz_worker_is_running(app->txrx->worker)) { - subghz_worker_stop(app->txrx->worker); - furi_hal_subghz_stop_async_rx(); - } + furi_hal_subghz_stop_async_rx(); } else { raw_sampling_worker_stop(app); } @@ -104,8 +111,8 @@ void radio_rx_end(ProtoViewApp* app) { void radio_sleep(ProtoViewApp* app) { furi_assert(app); if(app->txrx->txrx_state == TxRxStateRx) { - /* We can't go from having an active RX worker to sleeping. - * Stop the RX subsystems first. */ + /* Stop the asynchronous receiving system before putting the + * chip into sleep. */ radio_rx_end(app); } furi_hal_subghz_sleep(); @@ -127,8 +134,9 @@ void radio_tx_signal(ProtoViewApp* app, FuriHalSubGhzAsyncTxCallback data_feeder furi_hal_subghz_idle(); uint32_t value = furi_hal_subghz_set_frequency_and_path(app->frequency); FURI_LOG_E(TAG, "Switched to frequency: %lu", value); - furi_hal_gpio_write(&gpio_cc1101_g0, false); - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_write(furi_hal_subghz.cc1101_g0_pin, false); + furi_hal_gpio_init( + furi_hal_subghz.cc1101_g0_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); furi_hal_subghz_start_async_tx(data_feeder, ctx); while(!furi_hal_subghz_is_async_tx_complete()) furi_delay_ms(10); @@ -149,7 +157,7 @@ void radio_tx_signal(ProtoViewApp* app, FuriHalSubGhzAsyncTxCallback data_feeder void protoview_timer_isr(void* ctx) { ProtoViewApp* app = ctx; - bool level = furi_hal_gpio_read(&gpio_cc1101_g0); + bool level = furi_hal_gpio_read(furi_hal_subghz.cc1101_g0_pin); if(app->txrx->last_g0_value != level) { uint32_t now = DWT->CYCCNT; uint32_t dur = now - app->txrx->last_g0_change_time; diff --git a/applications/plugins/protoview/appicon.png b/applications/plugins/protoview/appicon.png index 7ce5c4eff..fa7122515 100644 Binary files a/applications/plugins/protoview/appicon.png and b/applications/plugins/protoview/appicon.png differ diff --git a/applications/plugins/protoview/application.fam b/applications/plugins/protoview/application.fam index d3614524c..6cd31372e 100644 --- a/applications/plugins/protoview/application.fam +++ b/applications/plugins/protoview/application.fam @@ -5,7 +5,7 @@ App( entry_point="protoview_app_entry", cdefines=["APP_PROTOVIEW"], requires=["gui"], - stack_size=8 * 1024, + stack_size=8*1024, order=50, fap_icon="appicon.png", fap_category="Tools", diff --git a/applications/plugins/protoview/crc.c b/applications/plugins/protoview/crc.c index 94d482972..e99786952 100644 --- a/applications/plugins/protoview/crc.c +++ b/applications/plugins/protoview/crc.c @@ -1,3 +1,6 @@ +/* Copyright (C) 2022-2023 Salvatore Sanfilippo -- All Rights Reserved + * See the LICENSE file for information about the license. */ + #include #include @@ -17,3 +20,17 @@ uint8_t crc8(const uint8_t* data, size_t len, uint8_t init, uint8_t poly) { } return crc; } + +/* Sum all the specified bytes modulo 256. + * Initialize the sum with 'init' (usually 0). */ +uint8_t sum_bytes(const uint8_t* data, size_t len, uint8_t init) { + for(size_t i = 0; i < len; i++) init += data[i]; + return init; +} + +/* Perform the bitwise xor of all the specified bytes. + * Initialize xor value with 'init' (usually 0). */ +uint8_t xor_bytes(const uint8_t* data, size_t len, uint8_t init) { + for(size_t i = 0; i < len; i++) init ^= data[i]; + return init; +} diff --git a/applications/plugins/protoview/custom_presets.h b/applications/plugins/protoview/custom_presets.h index 00aa49945..ef1c56a94 100644 --- a/applications/plugins/protoview/custom_presets.h +++ b/applications/plugins/protoview/custom_presets.h @@ -1,5 +1,4 @@ #include - /* ========================== DATA RATE SETTINGS =============================== * * This is how to configure registers MDMCFG3 and MDMCFG4. @@ -131,8 +130,8 @@ static const uint8_t protoview_subghz_tpms2_ook_async_regs[][2] = { {CC1101_MDMCFG0, 0x00}, // Channel spacing is 25kHz {CC1101_MDMCFG1, 0x00}, // Channel spacing is 25kHz {CC1101_MDMCFG2, 0x30}, // Format ASK/OOK, No preamble/sync - {CC1101_MDMCFG3, /*0x93*/ 0x32}, // Data rate is 10kBaud - {CC1101_MDMCFG4, /*0x18*/ 0x17}, // Rx BW filter is 650.000kHz + {CC1101_MDMCFG3, 0x93}, // Data rate is 10kBaud + {CC1101_MDMCFG4, 0x18}, // Rx BW filter is 650.000kHz /* Main Radio Control State Machine */ {CC1101_MCSM0, 0x18}, // Autocalibrate on idle-to-rx/tx, PO_TIMEOUT is 64 cycles(149-155us) @@ -164,8 +163,57 @@ static const uint8_t protoview_subghz_tpms2_ook_async_regs[][2] = { {0, 0}, {0, 0}}; +/* GFSK 19k dev, 325 Khz filter, 20kBaud. Different AGI settings. + * Works well with Toyota. */ +static uint8_t protoview_subghz_tpms3_gfsk_async_regs[][2] = { + /* GPIO GD0 */ + {CC1101_IOCFG0, 0x0D}, // GD0 as async serial data output/input + + /* Frequency Synthesizer Control */ + {CC1101_FSCTRL1, 0x06}, // IF = (26*10^6) / (2^10) * 0x06 = 152343.75Hz + + /* Packet engine */ + {CC1101_PKTCTRL0, 0x32}, // Async, continious, no whitening + {CC1101_PKTCTRL1, 0x04}, + + // // Modem Configuration + {CC1101_MDMCFG0, 0x00}, + {CC1101_MDMCFG1, 0x02}, // 2 is the channel spacing exponet: not used + {CC1101_MDMCFG2, 0x10}, // GFSK without any other check + {CC1101_MDMCFG3, 0x93}, // Data rate is 20kBaud + {CC1101_MDMCFG4, 0x59}, // Rx bandwidth filter is 325 kHz + {CC1101_DEVIATN, 0x34}, // Deviation 19.04 Khz. + + /* Main Radio Control State Machine */ + {CC1101_MCSM0, 0x18}, // Autocalibrate on idle-to-rx/tx, PO_TIMEOUT is 64 cycles(149-155us) + + /* Frequency Offset Compensation Configuration */ + {CC1101_FOCCFG, + 0x16}, // no frequency offset compensation, POST_K same as PRE_K, PRE_K is 4K, GATE is off + + /* Automatic Gain Control */ + {CC1101_AGCCTRL0, 0x80}, + {CC1101_AGCCTRL1, 0x58}, + {CC1101_AGCCTRL2, 0x87}, + + /* Wake on radio and timeouts control */ + {CC1101_WORCTRL, 0xFB}, // WOR_RES is 2^15 periods (0.91 - 0.94 s) 16.5 - 17.2 hours + + /* Frontend configuration */ + {CC1101_FREND0, 0x10}, // Adjusts current TX LO buffer + {CC1101_FREND1, 0x56}, + + /* End */ + {0, 0}, + + /* CC1101 2FSK PATABLE. */ + {0xC0, 0}, + {0, 0}, + {0, 0}, + {0, 0}}; + /* 40 KBaud, 2FSK, 28 kHz deviation, 270 Khz bandwidth filter. */ -static uint8_t protoview_subghz_tpms3_fsk_async_regs[][2] = { +static uint8_t protoview_subghz_40k_fsk_async_regs[][2] = { /* GPIO GD0 */ {CC1101_IOCFG0, 0x0D}, // GD0 as async serial data output/input @@ -215,50 +263,55 @@ static uint8_t protoview_subghz_tpms3_fsk_async_regs[][2] = { {0, 0}, {0, 0}}; -/* FSK 19k dev, 325 Khz filter, 20kBaud. Works well with Toyota. */ -static uint8_t protoview_subghz_tpms4_fsk_async_regs[][2] = { +/* This is like the default Flipper OOK 640Khz bandwidth preset, but + * the bandwidth is changed to 40kBaud, in order to receive signals + * with a pulse width ~25us/30us. */ +static const uint8_t protoview_subghz_40k_ook_async_regs[][2] = { /* GPIO GD0 */ {CC1101_IOCFG0, 0x0D}, // GD0 as async serial data output/input + /* FIFO and internals */ + {CC1101_FIFOTHR, 0x07}, // The only important bit is ADC_RETENTION + + /* Packet engine */ + {CC1101_PKTCTRL0, 0x32}, // Async, continious, no whitening + /* Frequency Synthesizer Control */ {CC1101_FSCTRL1, 0x06}, // IF = (26*10^6) / (2^10) * 0x06 = 152343.75Hz - /* Packet engine */ - {CC1101_PKTCTRL0, 0x32}, // Async, continious, no whitening - {CC1101_PKTCTRL1, 0x04}, - - // // Modem Configuration - {CC1101_MDMCFG0, 0x00}, - {CC1101_MDMCFG1, 0x02}, // 2 is the channel spacing exponet: not used - {CC1101_MDMCFG2, 0x10}, // GFSK without any other check - {CC1101_MDMCFG3, 0x93}, // Data rate is 20kBaud - {CC1101_MDMCFG4, 0x59}, // Rx bandwidth filter is 325 kHz - {CC1101_DEVIATN, 0x34}, // Deviation 19.04 Khz. + // Modem Configuration + {CC1101_MDMCFG0, 0x00}, // Channel spacing is 25kHz + {CC1101_MDMCFG1, 0x00}, // Channel spacing is 25kHz + {CC1101_MDMCFG2, 0x30}, // Format ASK/OOK, No preamble/sync + {CC1101_MDMCFG3, 0x93}, // Data rate is 40kBaud + {CC1101_MDMCFG4, 0x1A}, // Rx BW filter is 650.000kHz /* Main Radio Control State Machine */ {CC1101_MCSM0, 0x18}, // Autocalibrate on idle-to-rx/tx, PO_TIMEOUT is 64 cycles(149-155us) /* Frequency Offset Compensation Configuration */ {CC1101_FOCCFG, - 0x16}, // no frequency offset compensation, POST_K same as PRE_K, PRE_K is 4K, GATE is off + 0x18}, // no frequency offset compensation, POST_K same as PRE_K, PRE_K is 4K, GATE is off /* Automatic Gain Control */ - {CC1101_AGCCTRL0, 0x80}, - {CC1101_AGCCTRL1, 0x58}, - {CC1101_AGCCTRL2, 0x87}, + {CC1101_AGCCTRL0, + 0x91}, // 10 - Medium hysteresis, medium asymmetric dead zone, medium gain ; 01 - 16 samples agc; 00 - Normal AGC, 01 - 8dB boundary + {CC1101_AGCCTRL1, + 0x0}, // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 0000 - RSSI to MAIN_TARGET + {CC1101_AGCCTRL2, 0x07}, // 00 - DVGA all; 000 - MAX LNA+LNA2; 111 - MAIN_TARGET 42 dB /* Wake on radio and timeouts control */ {CC1101_WORCTRL, 0xFB}, // WOR_RES is 2^15 periods (0.91 - 0.94 s) 16.5 - 17.2 hours /* Frontend configuration */ - {CC1101_FREND0, 0x10}, // Adjusts current TX LO buffer - {CC1101_FREND1, 0x56}, + {CC1101_FREND0, 0x11}, // Adjusts current TX LO buffer + high is PATABLE[1] + {CC1101_FREND1, 0xB6}, // /* End */ {0, 0}, - /* CC1101 2FSK PATABLE. */ - {0xC0, 0}, + /* CC1101 OOK PATABLE. */ + {0, 0xC0}, {0, 0}, {0, 0}, {0, 0}}; diff --git a/applications/plugins/protoview/data_feed.c b/applications/plugins/protoview/data_feed.c deleted file mode 100644 index 81d1a8020..000000000 --- a/applications/plugins/protoview/data_feed.c +++ /dev/null @@ -1,115 +0,0 @@ -/* Copyright (C) 2022-2023 Salvatore Sanfilippo -- All Rights Reserved - * See the LICENSE file for information about the license. */ - -#include -#include -#include -#include -#include -#include "raw_samples.h" - -#define TAG "PROTOVIEW-protocol" - -const SubGhzProtocol subghz_protocol_protoview; - -/* The feed() method puts data in the RawSamples global (protected by - * a mutex). */ -extern RawSamplesBuffer* RawSamples; - -/* This is totally dummy: we just define the decoder base for the async - * system to work but we don't really use it if not to collect raw - * data via the feed() method. */ -typedef struct SubGhzProtocolDecoderprotoview { - SubGhzProtocolDecoderBase base; -} SubGhzProtocolDecoderprotoview; - -void* subghz_protocol_decoder_protoview_alloc(SubGhzEnvironment* environment) { - UNUSED(environment); - - SubGhzProtocolDecoderprotoview* instance = malloc(sizeof(SubGhzProtocolDecoderprotoview)); - instance->base.protocol = &subghz_protocol_protoview; - return instance; -} - -void subghz_protocol_decoder_protoview_free(void* context) { - furi_assert(context); - SubGhzProtocolDecoderprotoview* instance = context; - free(instance); -} - -void subghz_protocol_decoder_protoview_reset(void* context) { - furi_assert(context); -} - -/* That's the only thig we really use of the protocol decoder - * implementation. We avoid the subghz provided abstractions and put - * the data in our simple abstraction: the RawSamples circular buffer. */ -void subghz_protocol_decoder_protoview_feed(void* context, bool level, uint32_t duration) { - furi_assert(context); - UNUSED(context); - - /* Add data to the circular buffer. */ - raw_samples_add(RawSamples, level, duration); - // FURI_LOG_E(TAG, "FEED: %d %d", (int)level, (int)duration); - return; -} - -/* The only scope of this method is to avoid duplicated messages in the - * Subghz history, which we don't use. */ -uint8_t subghz_protocol_decoder_protoview_get_hash_data(void* context) { - furi_assert(context); - return 123; -} - -/* Not used. */ -bool subghz_protocol_decoder_protoview_serialize( - void* context, - FlipperFormat* flipper_format, - SubGhzRadioPreset* preset) { - UNUSED(context); - UNUSED(flipper_format); - UNUSED(preset); - return false; -} - -/* Not used. */ -bool subghz_protocol_decoder_protoview_deserialize(void* context, FlipperFormat* flipper_format) { - UNUSED(context); - UNUSED(flipper_format); - return false; -} - -void subhz_protocol_decoder_protoview_get_string(void* context, FuriString* output) { - furi_assert(context); - furi_string_cat_printf(output, "Protoview"); -} - -const SubGhzProtocolDecoder subghz_protocol_protoview_decoder = { - .alloc = subghz_protocol_decoder_protoview_alloc, - .free = subghz_protocol_decoder_protoview_free, - .reset = subghz_protocol_decoder_protoview_reset, - .feed = subghz_protocol_decoder_protoview_feed, - .get_hash_data = subghz_protocol_decoder_protoview_get_hash_data, - .serialize = subghz_protocol_decoder_protoview_serialize, - .deserialize = subghz_protocol_decoder_protoview_deserialize, - .get_string = subhz_protocol_decoder_protoview_get_string, -}; - -/* Well, we don't really target a specific protocol. So let's put flags - * that make sense. */ -const SubGhzProtocol subghz_protocol_protoview = { - .name = "Protoview", - .type = SubGhzProtocolTypeStatic, - .flag = SubGhzProtocolFlag_AM | SubGhzProtocolFlag_FM | SubGhzProtocolFlag_Decodable, - .decoder = &subghz_protocol_protoview_decoder, -}; - -/* Our table has just the single dummy protocol we defined for the - * sake of data collection. */ -const SubGhzProtocol* protoview_protocol_registry_items[] = { - &subghz_protocol_protoview, -}; - -const SubGhzProtocolRegistry protoview_protocol_registry = { - .items = protoview_protocol_registry_items, - .size = COUNT_OF(protoview_protocol_registry_items)}; diff --git a/applications/plugins/protoview/fields.c b/applications/plugins/protoview/fields.c index 47d573f4f..18dee6502 100644 --- a/applications/plugins/protoview/fields.c +++ b/applications/plugins/protoview/fields.c @@ -314,11 +314,16 @@ void fieldset_add_bin(ProtoViewFieldSet* fs, const char* name, uint64_t uval, ui fieldset_add_field(fs, f); } -/* Allocate and append a string field. */ -void fieldset_add_str(ProtoViewFieldSet* fs, const char* name, const char* s) { +/* Allocate and append a string field. The string 's' does not need to point + * to a null terminated string, but must have at least 'len' valid bytes + * starting from the pointer. The field object will be correctly null + * terminated. */ +void fieldset_add_str(ProtoViewFieldSet* fs, const char* name, const char* s, size_t len) { ProtoViewField* f = field_new(FieldTypeStr, name); - f->str = strdup(s); - f->len = strlen(s); + f->len = len; + f->str = malloc(len + 1); + memcpy(f->str, s, len); + f->str[len] = 0; fieldset_add_field(fs, f); } diff --git a/applications/plugins/protoview/protocols/b4b1.c b/applications/plugins/protoview/protocols/b4b1.c index 52c59d24b..6d0b8237a 100644 --- a/applications/plugins/protoview/protocols/b4b1.c +++ b/applications/plugins/protoview/protocols/b4b1.c @@ -1,4 +1,7 @@ -/* PT/SC remotes. Usually 443.92 Mhz OOK. +/* Copyright (C) 2022-2023 Salvatore Sanfilippo -- All Rights Reserved + * See the LICENSE file for information about the license. + * + * PT/SC remotes. Usually 443.92 Mhz OOK. * * This line code is used in many remotes such as Princeton chips * named PT2262, Silian Microelectronics SC5262 and others. @@ -11,10 +14,15 @@ static bool decode(uint8_t* bits, uint32_t numbytes, uint32_t numbits, ProtoViewMsgInfo* info) { if(numbits < 30) return false; - const char* sync_patterns[3] = { - "10000000000000000000000000000001", /* 30 zero bits. */ - "100000000000000000000000000000001", /* 31 zero bits. */ - "1000000000000000000000000000000001", /* 32 zero bits. */ + + /* Test different pulse + gap + first byte possibilities. */ + const char* sync_patterns[6] = { + "100000000000000000000000000000011101", /* 30 times gap + one. */ + "100000000000000000000000000000010001", /* 30 times gap + zero. */ + "1000000000000000000000000000000011101", /* 31 times gap + one. */ + "1000000000000000000000000000000010001", /* 31 times gap + zero. */ + "10000000000000000000000000000000011101", /* 32 times gap + one. */ + "10000000000000000000000000000000010001", /* 32 times gap + zero. */ }; uint32_t off; @@ -24,11 +32,11 @@ static bool decode(uint8_t* bits, uint32_t numbytes, uint32_t numbits, ProtoView if(off != BITMAP_SEEK_NOT_FOUND) break; } if(off == BITMAP_SEEK_NOT_FOUND) return false; - if(DEBUG_MSG) FURI_LOG_E(TAG, "B4B1 preamble at: %lu", off); + if(DEBUG_MSG) FURI_LOG_E(TAG, "B4B1 preamble id:%d at: %lu", j, off); info->start_off = off; - // Seek data setction. Why -1? Last bit is data. - off += strlen(sync_patterns[j]) - 1; + // Seek data setction. Why -5? Last 5 half-bit-times are data. + off += strlen(sync_patterns[j]) - 5; uint8_t d[3]; /* 24 bits of data. */ uint32_t decoded = convert_from_line_code(d, sizeof(d), bits, numbytes, off, "1000", "1110"); diff --git a/applications/plugins/protoview/protocols/keeloq.c b/applications/plugins/protoview/protocols/keeloq.c index 298c690d4..c09cc35fc 100644 --- a/applications/plugins/protoview/protocols/keeloq.c +++ b/applications/plugins/protoview/protocols/keeloq.c @@ -1,4 +1,7 @@ -/* Microchip HCS200/HCS300/HSC301 KeeLoq, rolling code remotes. +/* Copyright (C) 2022-2023 Salvatore Sanfilippo -- All Rights Reserved + * See the LICENSE file for information about the license. + * + * Microchip HCS200/HCS300/HSC301 KeeLoq, rolling code remotes. * * Usually 443.92 Mhz OOK, ~200us or ~400us pulse len, depending * on the configuration. diff --git a/applications/plugins/protoview/protocols/oregon2.c b/applications/plugins/protoview/protocols/oregon2.c index f67e85a2d..f7b123deb 100644 --- a/applications/plugins/protoview/protocols/oregon2.c +++ b/applications/plugins/protoview/protocols/oregon2.c @@ -1,4 +1,7 @@ -/* Oregon remote termometers. Usually 443.92 Mhz OOK. +/* Copyright (C) 2022-2023 Salvatore Sanfilippo -- All Rights Reserved + * See the LICENSE file for information about the license. + * + * Oregon remote termometers. Usually 443.92 Mhz OOK. * * The protocol is described here: * https://wmrx00.sourceforge.net/Arduino/OregonScientific-RF-Protocols.pdf diff --git a/applications/plugins/protoview/protocols/pvchat.c b/applications/plugins/protoview/protocols/pvchat.c new file mode 100644 index 000000000..779248c5b --- /dev/null +++ b/applications/plugins/protoview/protocols/pvchat.c @@ -0,0 +1,205 @@ +#include "../app.h" + +/* Copyright (C) 2022-2023 Salvatore Sanfilippo -- All Rights Reserved + * See the LICENSE file for information about the license. + * + * ---------------------------------------------------------- + * ProtoView chat protocol. This is just a fun test protocol + * that can be used between two Flippers in order to send + * and receive text messages. + * ---------------------------------------------------------- + * + * Protocol description + * ==================== + * + * The protocol works with different data rates. However here is defined + * to use a short pulse/gap duration of 300us and a long pulse/gap + * duration of 600us. Even with the Flipper hardware, the protocol works + * with 100/200us, but becomes less reliable and standard presets can't + * be used because of the higher data rate. + * + * In the following description we have that: + * + * "1" represents a pulse of one-third bit time (300us) + * "0" represents a gap of one-third bit time (300us) + * + * The message starts with a preamble + a sync pattern: + * + * preamble = 1010101010101010 x 3 + * sync = 1100110011001010 + * + * The a variable amount of bytes follow, where each bit + * is encoded in the following way: + * + * zero 100 (300 us pulse, 600 us gap) + * one 110 (600 us pulse, 300 us gap) + * + * Bytes are sent MSB first, so receiving, in sequence, bits + * 11100001, means byte E1. + * + * This is the data format: + * + * +--+------+-------+--+--+--+ + * |SL|Sender|Message|FF|AA|CS| + * +--+------+-------+--+--+--+ + * | | | + * | | \_ N bytes of message terminated by FF AA + 1 byte of checksum + * | | + * | \_ SL bytes of sender name + * \ + * \_ 1 byte of sender len, 8 bit unsigned integer. + * + * + * Checksum = sum of bytes modulo 256, with checksum set + * to 0 for the computation. + * + * Design notes + * ============ + * + * The protocol is designed in order to have certain properties: + * + * 1. Pulses and gaps can only be 100 or 200 microseconds, so the + * message can be described, encoded and decoded with only two + * fixed durations. + * + * 2. The preamble + sync is designed to have a well recognizable + * pattern that can't be reproduced just for accident inside + * the encoded pattern. There is no combinatio of encoded bits + * leading to the preamble+sync. Also the sync pattern final + * part can't be mistaken for actual bits of data, since it + * contains alternating short pulses/gaps at 100us. + * + * 3. Data encoding wastes some bandwidth in order to be more + * robust. Even so, with a 300us clock period, a single bit + * bit takes 900us, reaching a data transfer of 138 characters per + * second. More than enough for the simple chat we have here. + */ + +static bool decode(uint8_t* bits, uint32_t numbytes, uint32_t numbits, ProtoViewMsgInfo* info) { + const char* sync_pattern = "1010101010101010" // Preamble + "1100110011001010"; // Sync + uint8_t sync_len = 32; + + /* This is a variable length message, however the minimum length + * requires a sender len byte (of value zero) and the terminator + * FF 00 plus checksum: a total of 4 bytes. */ + if(numbits - sync_len < 8 * 4) return false; + + uint64_t off = bitmap_seek_bits(bits, numbytes, 0, numbits, sync_pattern); + if(off == BITMAP_SEEK_NOT_FOUND) return false; + FURI_LOG_E(TAG, "Chat preamble+sync found"); + + /* If there is room on the left, let's mark the start of the message + * a bit before: we don't try to detect all the preamble, but only + * the first part, however it is likely present. */ + if(off >= 16) { + off -= 16; + sync_len += 16; + } + + info->start_off = off; + off += sync_len; /* Skip preamble and sync. */ + + uint8_t raw[64] = {(uint8_t)'.'}; + uint32_t decoded = + convert_from_line_code(raw, sizeof(raw), bits, numbytes, off, "100", "110"); /* PWM */ + FURI_LOG_E(TAG, "Chat decoded bits: %lu", decoded); + + if(decoded < 8 * 4) return false; /* Min message len. */ + + // The message needs to have a two bytes terminator before + // the checksum. + uint32_t j; + for(j = 0; j < sizeof(raw) - 1; j++) + if(raw[j] == 0xff && raw[j + 1] == 0xaa) break; + + if(j == sizeof(raw) - 1) { + FURI_LOG_E(TAG, "Chat: terminator not found"); + return false; // No terminator found. + } + + uint32_t datalen = j + 3; // If the terminator was found at j, then + // we need to sum three more bytes to have + // the len: FF itself, AA, checksum. + info->pulses_count = sync_len + 8 * 3 * datalen; + + // Check if the control sum matches. + if(sum_bytes(raw, datalen - 1, 0) != raw[datalen - 1]) { + FURI_LOG_E(TAG, "Chat: checksum mismatch"); + return false; + } + + // Check if the length of the sender looks sane + uint8_t senderlen = raw[0]; + if(senderlen >= sizeof(raw)) { + FURI_LOG_E(TAG, "Chat: invalid sender length"); + return false; // Overflow + } + + fieldset_add_str(info->fieldset, "sender", (char*)raw + 1, senderlen); + fieldset_add_str( + info->fieldset, "message", (char*)raw + 1 + senderlen, datalen - senderlen - 4); + return true; +} + +/* Give fields and defaults for the signal creator. */ +static void get_fields(ProtoViewFieldSet* fieldset) { + fieldset_add_str(fieldset, "sender", "Carol", 5); + fieldset_add_str(fieldset, "message", "Anyone hearing?", 15); +} + +/* Create a signal. */ +static void build_message(RawSamplesBuffer* samples, ProtoViewFieldSet* fs) { + uint32_t te = 300; /* Short pulse duration in microseconds. + Our protocol needs three symbol times to send + a bit, so 300 us per bit = 3.33 kBaud. */ + + // Preamble: 24 alternating 300us pulse/gap pairs. + for(int j = 0; j < 24; j++) { + raw_samples_add(samples, true, te); + raw_samples_add(samples, false, te); + } + + // Sync: 3 alternating 600 us pulse/gap pairs. + for(int j = 0; j < 3; j++) { + raw_samples_add(samples, true, te * 2); + raw_samples_add(samples, false, te * 2); + } + + // Sync: plus 2 alternating 300 us pluse/gap pairs. + for(int j = 0; j < 2; j++) { + raw_samples_add(samples, true, te); + raw_samples_add(samples, false, te); + } + + // Data: build the array. + uint32_t datalen = 1 + fs->fields[0]->len + // Userlen + Username + fs->fields[1]->len + 3; // Message + FF + 00 + CRC + uint8_t *data = malloc(datalen), *p = data; + *p++ = fs->fields[0]->len; + memcpy(p, fs->fields[0]->str, fs->fields[0]->len); + p += fs->fields[0]->len; + memcpy(p, fs->fields[1]->str, fs->fields[1]->len); + p += fs->fields[1]->len; + *p++ = 0xff; + *p++ = 0xaa; + *p = sum_bytes(data, datalen - 1, 0); + + // Emit bits + for(uint32_t j = 0; j < datalen * 8; j++) { + if(bitmap_get(data, datalen, j)) { + raw_samples_add(samples, true, te * 2); + raw_samples_add(samples, false, te); + } else { + raw_samples_add(samples, true, te); + raw_samples_add(samples, false, te * 2); + } + } + free(data); +} + +ProtoViewDecoder ProtoViewChatDecoder = { + .name = "ProtoView chat", + .decode = decode, + .get_fields = get_fields, + .build_message = build_message}; diff --git a/applications/plugins/protoview/protocols/tpms/citroen.c b/applications/plugins/protoview/protocols/tpms/citroen.c index ecd8fb983..a86e5f7d6 100644 --- a/applications/plugins/protoview/protocols/tpms/citroen.c +++ b/applications/plugins/protoview/protocols/tpms/citroen.c @@ -1,4 +1,7 @@ -/* Citroen TPMS. Usually 443.92 Mhz FSK. +/* Copyright (C) 2022-2023 Salvatore Sanfilippo -- All Rights Reserved + * See the LICENSE file for information about the license. + * + * Citroen TPMS. Usually 443.92 Mhz FSK. * * Preamble of ~14 high/low 52 us pulses * Sync of high 100us pulse then 50us low diff --git a/applications/plugins/protoview/protocols/tpms/ford.c b/applications/plugins/protoview/protocols/tpms/ford.c index 3816e72f9..066332590 100644 --- a/applications/plugins/protoview/protocols/tpms/ford.c +++ b/applications/plugins/protoview/protocols/tpms/ford.c @@ -1,4 +1,7 @@ -/* Ford tires TPMS. Usually 443.92 Mhz FSK (in Europe). +/* Copyright (C) 2022-2023 Salvatore Sanfilippo -- All Rights Reserved + * See the LICENSE file for information about the license. + * + * Ford tires TPMS. Usually 443.92 Mhz FSK (in Europe). * * 52 us short pules * Preamble: 0101010101010101010101010101 diff --git a/applications/plugins/protoview/protocols/tpms/renault.c b/applications/plugins/protoview/protocols/tpms/renault.c index 3d8fc43d5..0755a515f 100644 --- a/applications/plugins/protoview/protocols/tpms/renault.c +++ b/applications/plugins/protoview/protocols/tpms/renault.c @@ -1,4 +1,7 @@ -/* Renault tires TPMS. Usually 443.92 Mhz FSK. +/* Copyright (C) 2022-2023 Salvatore Sanfilippo -- All Rights Reserved + * See the LICENSE file for information about the license. + * + * Renault tires TPMS. Usually 443.92 Mhz FSK. * * Preamble + sync + Manchester bits. ~48us short pulse. * 9 Bytes in total not counting the preamble. */ diff --git a/applications/plugins/protoview/protocols/tpms/schrader.c b/applications/plugins/protoview/protocols/tpms/schrader.c index 7dc85a2cb..2b53d313c 100644 --- a/applications/plugins/protoview/protocols/tpms/schrader.c +++ b/applications/plugins/protoview/protocols/tpms/schrader.c @@ -1,4 +1,7 @@ -/* Schrader TPMS. Usually 443.92 Mhz OOK, 120us pulse len. +/* Copyright (C) 2022-2023 Salvatore Sanfilippo -- All Rights Reserved + * See the LICENSE file for information about the license. + * + * Schrader TPMS. Usually 443.92 Mhz OOK, 120us pulse len. * * 500us high pulse + Preamble + Manchester coded bits where: * 1 = 10 diff --git a/applications/plugins/protoview/protocols/tpms/schrader_eg53ma4.c b/applications/plugins/protoview/protocols/tpms/schrader_eg53ma4.c index 45accf1a1..b186f57b1 100644 --- a/applications/plugins/protoview/protocols/tpms/schrader_eg53ma4.c +++ b/applications/plugins/protoview/protocols/tpms/schrader_eg53ma4.c @@ -1,4 +1,7 @@ -/* Schrader variant EG53MA4 TPMS. +/* Copyright (C) 2022-2023 Salvatore Sanfilippo -- All Rights Reserved + * See the LICENSE file for information about the license. + * + * Schrader variant EG53MA4 TPMS. * Usually 443.92 Mhz OOK, 100us pulse len. * * Preamble: alternating pulse/gap, 100us. diff --git a/applications/plugins/protoview/protocols/tpms/toyota.c b/applications/plugins/protoview/protocols/tpms/toyota.c index b80af7647..3a02447b7 100644 --- a/applications/plugins/protoview/protocols/tpms/toyota.c +++ b/applications/plugins/protoview/protocols/tpms/toyota.c @@ -1,4 +1,7 @@ -/* Toyota tires TPMS. Usually 443.92 Mhz FSK (In Europe). +/* Copyright (C) 2022-2023 Salvatore Sanfilippo -- All Rights Reserved + * See the LICENSE file for information about the license. + * + * Toyota tires TPMS. Usually 443.92 Mhz FSK (In Europe). * * Preamble + sync + 64 bits of data. ~48us short pulse length. * diff --git a/applications/plugins/protoview/protocols/unknown.c b/applications/plugins/protoview/protocols/unknown.c new file mode 100644 index 000000000..9e2f4a893 --- /dev/null +++ b/applications/plugins/protoview/protocols/unknown.c @@ -0,0 +1,326 @@ +#include "../app.h" + +/* Copyright (C) 2023 Salvatore Sanfilippo -- All Rights Reserved + * See the LICENSE file for information about the license. + * + * ---------------------------------------------------------------------------- + * The "unknown" decoder fires as the last one, once we are sure no other + * decoder was able to identify the signal. The goal is to detect the + * preamble and line code used in the received signal, then turn the + * decoded bits into bytes. + * + * The techniques used for the detection are described in the comments + * below. + * ---------------------------------------------------------------------------- + */ + +/* Scan the signal bitmap looking for a PWM modulation. In this case + * for PWM we are referring to two exact patterns of high and low + * signal (each bit in the bitmap is worth the smallest gap/pulse duration + * we detected) that repeat each other in a given segment of the message. + * + * This modulation is quite common, for instance sometimes zero and + * one are rappresented by a 700us pulse followed by 350 gap, + * and 350us pulse followed by a 700us gap. So the signal bitmap received + * by the decoder would contain 110 and 100 symbols. + * + * The way this function work is commented inline. + * + * The function returns the number of consecutive symbols found, having + * a symbol length of 'symlen' (3 in the above example), and stores + * in *s1i the offset of the first symbol found, and in *s2i the offset + * of the second symbol. The function can't tell which is one and which + * zero. */ +static uint32_t find_pwm( + uint8_t* bits, + uint32_t numbytes, + uint32_t numbits, + uint32_t symlen, + uint32_t* s1i, + uint32_t* s2i) { + uint32_t best_count = 0; /* Max number of symbols found in this try. */ + uint32_t best_idx1 = 0; /* First symbol offset of longest sequence found. + * This is also the start sequence offset. */ + uint32_t best_idx2 = 0; /* Second symbol offset. */ + + /* Try all the possible symbol offsets that are less of our + * symbol len. This is likely not really useful but we take + * a conservative approach. Because if have have, for instance, + * repeating symbols "100" and "110", they will form a sequence + * that is choerent at different offsets, but out-of-sync. + * + * Anyway at the end of the function we try to fix the sync. */ + for(uint32_t off = 0; off < symlen; off++) { + uint32_t c = 0; // Number of contiguous symbols found. + uint32_t c1 = 0, c2 = 0; // Occurrences of first/second symbol. + *s1i = off; // Assume we start at one symbol boundaty. + *s2i = UINT32_MAX; // Second symbol first index still unknown. + uint32_t next = off; + + /* We scan the whole bitmap in one pass, resetting the state + * each time we find a pattern that is not one of the two + * symbols we found so far. */ + while(next < numbits - symlen) { + bool match1 = bitmap_match_bitmap(bits, numbytes, next, bits, numbytes, *s1i, symlen); + if(!match1 && *s2i == UINT32_MAX) { + /* It's not the first sybol. We don't know how the + * second look like. Assume we found an occurrence of + * the second symbol. */ + *s2i = next; + } + + bool match2 = bitmap_match_bitmap(bits, numbytes, next, bits, numbytes, *s2i, symlen); + + /* One or the other should match. */ + if(match1 || match2) { + c++; + if(match1) c1++; + if(match2) c2++; + if(c > best_count && c1 >= best_count / 5 && // Require enough presence of both + c2 >= best_count / 5) // zero and one. + { + best_count = c; + best_idx1 = *s1i; + best_idx2 = *s2i; + } + next += symlen; + } else { + /* No match. Continue resetting the signal info. */ + c = 0; // Start again to count contiguous symbols. + c1 = 0; + c2 = 0; + *s1i = next; // First symbol always at start. + *s2i = UINT32_MAX; // Second symbol unknown. + } + } + } + + /* We don't know if we are really synchronized with the bits at this point. + * For example if zero bit is 100 and one bit is 110 in a specific + * line code, our detector could randomly believe it's 001 and 101. + * However PWD line codes normally start with a pulse in both symbols. + * If that is the case, let's align. */ + uint32_t shift; + for(shift = 0; shift < symlen; shift++) { + if(bitmap_get(bits, numbytes, best_idx1 + shift) && + bitmap_get(bits, numbytes, best_idx2 + shift)) + break; + } + if(shift != symlen) { + best_idx1 += shift; + best_idx2 += shift; + } + + *s1i = best_idx1; + *s2i = best_idx2; + return best_count; +} + +/* Find the longest sequence that looks like Manchester coding. + * + * Manchester coding requires each pairs of bits to be either + * 01 or 10. We'll have to try odd and even offsets to be + * sure to find it. + * + * Note that this will also detect differential Manchester, but + * will report it as Manchester. I can't think of any way to + * distinguish between the two line codes, because shifting them + * one symbol will make one to look like the other. + * + * Only option could be to decode the message with both line + * codes and use statistical properties (common byte values) + * to determine what's more likely, but this looks very fragile. + * + * Fortunately differential Manchester is more rarely used, + * so we can assume Manchester most of the times. Yet we are left + * with the indetermination about zero being pulse-gap or gap-pulse + * or the other way around. + * + * If the 'only_raising' parameter is true, the function detects + * only sequences going from gap to pulse: this is useful in order + * to locate preambles of alternating gaps and pulses. */ +static uint32_t find_alternating_bits( + uint8_t* bits, + uint32_t numbytes, + uint32_t numbits, + uint32_t* start, + bool only_raising) { + uint32_t best_count = 0; // Max number of symbols found + uint32_t best_off = 0; // Max symbols start offset. + for(int odd = 0; odd < 2; odd++) { + uint32_t count = 0; // Symbols found so far + uint32_t start_off = odd; + uint32_t j = odd; + while(j < numbits - 1) { + bool bit1 = bitmap_get(bits, numbytes, j); + bool bit2 = bitmap_get(bits, numbytes, j + 1); + if((!only_raising && bit1 != bit2) || (only_raising && !bit1 && bit2)) { + count++; + if(count > best_count) { + best_count = count; + best_off = start_off; + } + } else { + /* End of sequence. Continue with the next + * part of the signal. */ + count = 0; + start_off = j + 2; + } + j += 2; + } + } + *start = best_off; + return best_count; +} + +/* Wrapper to find Manchester code. */ +static uint32_t + find_manchester(uint8_t* bits, uint32_t numbytes, uint32_t numbits, uint32_t* start) { + return find_alternating_bits(bits, numbytes, numbits, start, false); +} + +/* Wrapper to find preamble sections. */ +static uint32_t + find_preamble(uint8_t* bits, uint32_t numbytes, uint32_t numbits, uint32_t* start) { + return find_alternating_bits(bits, numbytes, numbits, start, true); +} + +typedef enum { + LineCodeNone, + LineCodeManchester, + LineCodePWM3, + LineCodePWM4, +} LineCodeGuess; + +static char* get_linecode_name(LineCodeGuess lc) { + switch(lc) { + case LineCodeNone: + return "none"; + case LineCodeManchester: + return "Manchester"; + case LineCodePWM3: + return "PWM3"; + case LineCodePWM4: + return "PWM4"; + } + return "unknown"; +} + +static bool decode(uint8_t* bits, uint32_t numbytes, uint32_t numbits, ProtoViewMsgInfo* info) { + /* No decoder was able to detect this message. Let's try if we can + * find some structure. To start, we'll see if it looks like is + * manchester coded, or PWM with symbol len of 3 or 4. */ + + /* For PWM, start1 and start2 are the offsets at which the two + * sequences composing the message appear the first time. + * So start1 is also the message start offset. Start2 is not used + * for Manchester, that does not have two separated symbols like + * PWM. */ + uint32_t start1 = 0, start2 = 0; + uint32_t msgbits; // Number of message bits in the bitmap, so + // this will be the number of symbols, not actual + // bits after the message is decoded. + uint32_t tmp1, tmp2; // Temp vars to store the start. + uint32_t minbits = 16; // Less than that gets undetected. + uint32_t pwm_len; // Bits per symbol, in the case of PWM. + LineCodeGuess linecode = LineCodeNone; + + // Try PWM3 + uint32_t pwm3_bits = find_pwm(bits, numbytes, numbits, 3, &tmp1, &tmp2); + if(pwm3_bits >= minbits) { + linecode = LineCodePWM3; + start1 = tmp1; + start2 = tmp2; + pwm_len = 3; + msgbits = pwm3_bits * pwm_len; + } + + // Try PWM4 + uint32_t pwm4_bits = find_pwm(bits, numbytes, numbits, 4, &tmp1, &tmp2); + if(pwm4_bits >= minbits && pwm4_bits > pwm3_bits) { + linecode = LineCodePWM4; + start1 = tmp1; + start2 = tmp2; + pwm_len = 4; + msgbits = pwm3_bits * pwm_len; + } + + // Try Manchester + uint32_t manchester_bits = find_manchester(bits, numbytes, numbits, &tmp1); + if(manchester_bits > minbits && manchester_bits > pwm3_bits && manchester_bits > pwm4_bits) { + linecode = LineCodeManchester; + start1 = tmp1; + msgbits = manchester_bits * 2; + FURI_LOG_E(TAG, "MANCHESTER START: %lu", tmp1); + } + + if(linecode == LineCodeNone) return false; + + /* Often there is a preamble before the signal. We'll try to find + * it, and if it is not too far away from our signal, we'll claim + * our signal starts at the preamble. */ + uint32_t preamble_len = find_preamble(bits, numbytes, numbits, &tmp1); + uint32_t min_preamble_len = 10; + uint32_t max_preamble_distance = 32; + uint32_t preamble_start = 0; + bool preamble_found = false; + + /* Note that because of the following checks, if the Manchester detector + * detected the preamble bits as data, we are ok with that, since it + * means that the synchronization is not designed to "break" the bits + * flow. In this case we ignore the preamble and return all as data. */ + if(preamble_len >= min_preamble_len && // Not too short. + tmp1 < start1 && // Should be before the data. + start1 - tmp1 <= max_preamble_distance) // Not too far. + { + preamble_start = tmp1; + preamble_found = true; + } + + info->start_off = preamble_found ? preamble_start : start1; + info->pulses_count = (start1 + msgbits) - info->start_off; + info->pulses_count += 20; /* Add a few more, so that if the user resends + * the message, it is more likely we will + * transfer all that is needed, like a message + * terminator (that we don't detect). */ + + if(preamble_found) FURI_LOG_E(TAG, "PREAMBLE AT: %lu", preamble_start); + FURI_LOG_E(TAG, "START: %lu", info->start_off); + FURI_LOG_E(TAG, "MSGBITS: %lu", msgbits); + FURI_LOG_E(TAG, "DATASTART: %lu", start1); + FURI_LOG_E(TAG, "PULSES: %lu", info->pulses_count); + + /* We think there is a message and we know where it starts and the + * line code used. We can turn it into bits and bytes. */ + uint32_t decoded; + uint8_t data[32]; + uint32_t datalen; + + char symbol1[5], symbol2[5]; + if(linecode == LineCodePWM3 || linecode == LineCodePWM4) { + bitmap_to_string(symbol1, bits, numbytes, start1, pwm_len); + bitmap_to_string(symbol2, bits, numbytes, start2, pwm_len); + } else if(linecode == LineCodeManchester) { + memcpy(symbol1, "01", 3); + memcpy(symbol2, "10", 3); + } + + decoded = convert_from_line_code(data, sizeof(data), bits, numbytes, start1, symbol1, symbol2); + datalen = (decoded + 7) / 8; + + char* linecode_name = get_linecode_name(linecode); + fieldset_add_str(info->fieldset, "line code", linecode_name, strlen(linecode_name)); + fieldset_add_uint(info->fieldset, "data bits", decoded, 8); + if(preamble_found) fieldset_add_uint(info->fieldset, "preamble len", preamble_len, 8); + fieldset_add_str(info->fieldset, "first symbol", symbol1, strlen(symbol1)); + fieldset_add_str(info->fieldset, "second symbol", symbol2, strlen(symbol2)); + for(uint32_t j = 0; j < datalen; j++) { + char label[16]; + snprintf(label, sizeof(label), "data[%lu]", j); + fieldset_add_bytes(info->fieldset, label, data + j, 2); + } + return true; +} + +ProtoViewDecoder UnknownDecoder = + {.name = "Unknown", .decode = decode, .get_fields = NULL, .build_message = NULL}; diff --git a/applications/plugins/protoview/signal.c b/applications/plugins/protoview/signal.c index a1c4b2b8f..71fbe823f 100644 --- a/applications/plugins/protoview/signal.c +++ b/applications/plugins/protoview/signal.c @@ -5,6 +5,43 @@ bool decode_signal(RawSamplesBuffer* s, uint64_t len, ProtoViewMsgInfo* info); +/* ============================================================================= + * Protocols table. + * + * Supported protocols go here, with the relevant implementation inside + * protocols/.c + * ===========================================================================*/ + +extern ProtoViewDecoder Oregon2Decoder; +extern ProtoViewDecoder B4B1Decoder; +extern ProtoViewDecoder RenaultTPMSDecoder; +extern ProtoViewDecoder ToyotaTPMSDecoder; +extern ProtoViewDecoder SchraderTPMSDecoder; +extern ProtoViewDecoder SchraderEG53MA4TPMSDecoder; +extern ProtoViewDecoder CitroenTPMSDecoder; +extern ProtoViewDecoder FordTPMSDecoder; +extern ProtoViewDecoder KeeloqDecoder; +extern ProtoViewDecoder ProtoViewChatDecoder; +extern ProtoViewDecoder UnknownDecoder; + +ProtoViewDecoder* Decoders[] = { + &Oregon2Decoder, /* Oregon sensors v2.1 protocol. */ + &B4B1Decoder, /* PT, SC, ... 24 bits remotes. */ + &RenaultTPMSDecoder, /* Renault TPMS. */ + &ToyotaTPMSDecoder, /* Toyota TPMS. */ + &SchraderTPMSDecoder, /* Schrader TPMS. */ + &SchraderEG53MA4TPMSDecoder, /* Schrader EG53MA4 TPMS. */ + &CitroenTPMSDecoder, /* Citroen TPMS. */ + &FordTPMSDecoder, /* Ford TPMS. */ + &KeeloqDecoder, /* Keeloq remote. */ + &ProtoViewChatDecoder, /* Protoview simple text messages. */ + + /* Warning: the following decoder must stay at the end of the + * list. Otherwise would detect most signals and prevent the actaul + * decoders from handling them. */ + &UnknownDecoder, /* General protocol detector. */ + NULL}; + /* ============================================================================= * Raw signal detection * ===========================================================================*/ @@ -39,23 +76,28 @@ void reset_current_signal(ProtoViewApp* app) { * For instance Oregon2 sensors, in the case of protocol 2.1 will send * pulses of ~400us (RF on) VS ~580us (RF off). */ #define SEARCH_CLASSES 3 -uint32_t search_coherent_signal(RawSamplesBuffer* s, uint32_t idx) { +uint32_t search_coherent_signal(RawSamplesBuffer* s, uint32_t idx, uint32_t min_duration) { struct { uint32_t dur[2]; /* dur[0] = low, dur[1] = high */ uint32_t count[2]; /* Associated observed frequency. */ } classes[SEARCH_CLASSES]; memset(classes, 0, sizeof(classes)); - uint32_t minlen = 30, maxlen = 4000; /* Depends on data rate, here we - allow for high and low. */ + + // Set a min/max duration limit for samples to be considered part of a + // coherent signal. The maximum length is fixed while the minimum + // is passed as argument, as depends on the data rate and in general + // on the signal to analyze. + uint32_t max_duration = 4000; + uint32_t len = 0; /* Observed len of coherent samples. */ s->short_pulse_dur = 0; - for(uint32_t j = idx; j < idx + 500; j++) { + for(uint32_t j = idx; j < idx + s->total; j++) { bool level; uint32_t dur; raw_samples_get(s, j, &level, &dur); - if(dur < minlen || dur > maxlen) break; /* return. */ + if(dur < min_duration || dur > max_duration) break; /* return. */ /* Let's see if it matches a class we already have or if we * can populate a new (yet empty) class. */ @@ -142,7 +184,7 @@ void notify_signal_detected(ProtoViewApp* app, bool decoded) { * in order to find a coherent signal. If a signal that does not appear to * be just noise is found, it is set in DetectedSamples global signal * buffer, that is what is rendered on the screen. */ -void scan_for_signal(ProtoViewApp* app, RawSamplesBuffer* source) { +void scan_for_signal(ProtoViewApp* app, RawSamplesBuffer* source, uint32_t min_duration) { /* We need to work on a copy: the source buffer may be populated * by the background thread receiving data. */ RawSamplesBuffer* copy = raw_samples_alloc(); @@ -157,7 +199,7 @@ void scan_for_signal(ProtoViewApp* app, RawSamplesBuffer* source) { uint32_t i = 0; while(i < copy->total - 1) { - uint32_t thislen = search_coherent_signal(copy, i); + uint32_t thislen = search_coherent_signal(copy, i, min_duration); /* For messages that are long enough, attempt decoding. */ if(thislen > minlen) { @@ -179,8 +221,11 @@ void scan_for_signal(ProtoViewApp* app, RawSamplesBuffer* source) { /* Accept this signal as the new signal if either it's longer * than the previous undecoded one, or the previous one was * unknown and this is decoded. */ - if((thislen > app->signal_bestlen && app->signal_decoded == false) || - (app->signal_decoded == false && decoded)) { + bool oldsignal_not_decoded = app->signal_decoded == false || + app->msg_info->decoder == &UnknownDecoder; + + if(oldsignal_not_decoded && + (thislen > app->signal_bestlen || (decoded && info->decoder != &UnknownDecoder))) { free_msg_info(app->msg_info); app->msg_info = info; app->signal_bestlen = thislen; @@ -194,7 +239,7 @@ void scan_for_signal(ProtoViewApp* app, RawSamplesBuffer* source) { DetectedSamples->short_pulse_dur); adjust_raw_view_scale(app, DetectedSamples->short_pulse_dur); - notify_signal_detected(app, decoded); + if(app->msg_info->decoder != &UnknownDecoder) notify_signal_detected(app, decoded); } else { /* If the structure was not filled, discard it. Otherwise * now the owner is app->msg_info. */ @@ -387,6 +432,33 @@ uint32_t bitmap_seek_bits( return BITMAP_SEEK_NOT_FOUND; } +/* Compare bitmaps b1 and b2 (possibly overlapping or the same bitmap), + * at the specified offsets, for cmplen bits. Returns true if the + * exact same bits are found, otherwise false. */ +bool bitmap_match_bitmap( + uint8_t* b1, + uint32_t b1len, + uint32_t b1off, + uint8_t* b2, + uint32_t b2len, + uint32_t b2off, + uint32_t cmplen) { + for(uint32_t j = 0; j < cmplen; j++) { + bool bit1 = bitmap_get(b1, b1len, b1off + j); + bool bit2 = bitmap_get(b2, b2len, b2off + j); + if(bit1 != bit2) return false; + } + return true; +} + +/* Convert 'len' bitmap bits of the bitmap 'bitmap' into a null terminated + * string, stored at 'dst', that must have space at least for len+1 bytes. + * The bits are extracted from the specified offset. */ +void bitmap_to_string(char* dst, uint8_t* b, uint32_t blen, uint32_t off, uint32_t len) { + for(uint32_t j = 0; j < len; j++) dst[j] = bitmap_get(b, blen, off + j) ? '1' : '0'; + dst[len] = 0; +} + /* Set the pattern 'pat' into the bitmap 'b' of max length 'blen' bytes, * starting from the specified offset. * @@ -503,7 +575,7 @@ uint32_t convert_from_line_code( } /* Convert the differential Manchester code to bits. This is similar to - * convert_from_line_code() but specific for Manchester. The user must + * convert_from_line_code() but specific for diff-Manchester. The user must * supply the value of the previous symbol before this stream, since * in differential codings the next bits depend on the previous one. * @@ -528,31 +600,6 @@ uint32_t convert_from_diff_manchester( return decoded; } -/* Supported protocols go here, with the relevant implementation inside - * protocols/.c */ - -extern ProtoViewDecoder Oregon2Decoder; -extern ProtoViewDecoder B4B1Decoder; -extern ProtoViewDecoder RenaultTPMSDecoder; -extern ProtoViewDecoder ToyotaTPMSDecoder; -extern ProtoViewDecoder SchraderTPMSDecoder; -extern ProtoViewDecoder SchraderEG53MA4TPMSDecoder; -extern ProtoViewDecoder CitroenTPMSDecoder; -extern ProtoViewDecoder FordTPMSDecoder; -extern ProtoViewDecoder KeeloqDecoder; - -ProtoViewDecoder* Decoders[] = { - &Oregon2Decoder, /* Oregon sensors v2.1 protocol. */ - &B4B1Decoder, /* PT, SC, ... 24 bits remotes. */ - &RenaultTPMSDecoder, /* Renault TPMS. */ - &ToyotaTPMSDecoder, /* Toyota TPMS. */ - &SchraderTPMSDecoder, /* Schrader TPMS. */ - &SchraderEG53MA4TPMSDecoder, /* Schrader EG53MA4 TPMS. */ - &CitroenTPMSDecoder, /* Citroen TPMS. */ - &FordTPMSDecoder, /* Ford TPMS. */ - &KeeloqDecoder, /* Keeloq remote. */ - NULL}; - /* Free the message info and allocated data. */ void free_msg_info(ProtoViewMsgInfo* i) { if(i == NULL) return; diff --git a/applications/plugins/protoview/view_build.c b/applications/plugins/protoview/view_build.c index 955855902..57e6e4fbc 100644 --- a/applications/plugins/protoview/view_build.c +++ b/applications/plugins/protoview/view_build.c @@ -205,7 +205,7 @@ static void process_input_set_fields(ProtoViewApp* app, InputEvent input) { privdata->decoder->build_message(rs, privdata->fieldset); app->signal_decoded = false; // So that the new signal will be // accepted as the current signal. - scan_for_signal(app, rs); + scan_for_signal(app, rs, 5); raw_samples_free(rs); ui_show_alert(app, "Done: press back key", 3000); } diff --git a/applications/plugins/protoview/view_direct_sampling.c b/applications/plugins/protoview/view_direct_sampling.c index 1ab90f096..0268e5297 100644 --- a/applications/plugins/protoview/view_direct_sampling.c +++ b/applications/plugins/protoview/view_direct_sampling.c @@ -2,63 +2,161 @@ * See the LICENSE file for information about the license. */ #include "app.h" - #include +static void direct_sampling_timer_start(ProtoViewApp* app); +static void direct_sampling_timer_stop(ProtoViewApp* app); + +#define CAPTURED_BITMAP_BITS (128 * 64) +#define CAPTURED_BITMAP_BYTES (CAPTURED_BITMAP_BITS / 8) +#define DEFAULT_USEC_PER_PIXEL 50 +#define USEC_PER_PIXEL_SMALL_CHANGE 5 +#define USEC_PER_PIXEL_LARGE_CHANGE 25 +#define USEC_PER_PIXEL_MIN 5 +#define USEC_PER_PIXEL_MAX 300 +typedef struct { + uint8_t* captured; // Bitmap with the last captured screen. + uint32_t captured_idx; // Current index to write into the bitmap + uint32_t usec_per_pixel; // Number of useconds a pixel should represent + bool show_usage_info; +} DirectSamplingViewPrivData; + /* Read directly from the G0 CC1101 pin, and draw a black or white * dot depending on the level. */ void render_view_direct_sampling(Canvas* const canvas, ProtoViewApp* app) { - if(!app->direct_sampling_enabled) { + DirectSamplingViewPrivData* privdata = app->view_privdata; + + if(!app->direct_sampling_enabled && privdata->show_usage_info) { canvas_set_font(canvas, FontSecondary); - canvas_draw_str(canvas, 2, 9, "Direct sampling is a special"); - canvas_draw_str(canvas, 2, 18, "mode that displays the signal"); - canvas_draw_str(canvas, 2, 27, "captured in real time. Like in"); - canvas_draw_str(canvas, 2, 36, "a old CRT TV. It's very slow."); - canvas_draw_str(canvas, 2, 45, "Can crash your Flipper."); + canvas_draw_str(canvas, 2, 9, "Direct sampling displays the"); + canvas_draw_str(canvas, 2, 18, "the captured signal in real"); + canvas_draw_str(canvas, 2, 27, "time, like in a CRT TV set."); + canvas_draw_str(canvas, 2, 36, "Use UP/DOWN to change the"); + canvas_draw_str(canvas, 2, 45, "resolution (usec/pixel)."); canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas, 14, 60, "To enable press OK"); + canvas_draw_str(canvas, 5, 60, "To start/stop, press OK"); return; } + privdata->show_usage_info = false; + /* Draw on screen. */ + int idx = 0; for(int y = 0; y < 64; y++) { for(int x = 0; x < 128; x++) { - bool level = furi_hal_gpio_read(&gpio_cc1101_g0); + bool level = bitmap_get(privdata->captured, CAPTURED_BITMAP_BYTES, idx++); if(level) canvas_draw_dot(canvas, x, y); - /* Busy loop: this is a terrible approach as it blocks - * everything else, but for now it's the best we can do - * to obtain direct data with some spacing. */ - uint32_t x = 250; - while(x--) - ; } } + + char buf[32]; + snprintf(buf, sizeof(buf), "%lu usec/px", privdata->usec_per_pixel); canvas_set_font(canvas, FontSecondary); - canvas_draw_str_with_border(canvas, 36, 60, "Direct sampling", ColorWhite, ColorBlack); + canvas_draw_str_with_border(canvas, 1, 60, buf, ColorWhite, ColorBlack); } /* Handle input */ void process_input_direct_sampling(ProtoViewApp* app, InputEvent input) { + DirectSamplingViewPrivData* privdata = app->view_privdata; + if(input.type == InputTypePress && input.key == InputKeyOk) { app->direct_sampling_enabled = !app->direct_sampling_enabled; } + + if((input.key == InputKeyUp || input.key == InputKeyDown) && + (input.type == InputTypePress || input.type == InputTypeRepeat)) { + uint32_t change = input.type == InputTypePress ? USEC_PER_PIXEL_SMALL_CHANGE : + USEC_PER_PIXEL_LARGE_CHANGE; + if(input.key == InputKeyUp) change = -change; + privdata->usec_per_pixel += change; + if(privdata->usec_per_pixel < USEC_PER_PIXEL_MIN) + privdata->usec_per_pixel = USEC_PER_PIXEL_MIN; + else if(privdata->usec_per_pixel > USEC_PER_PIXEL_MAX) + privdata->usec_per_pixel = USEC_PER_PIXEL_MAX; + /* Update the timer frequency. */ + direct_sampling_timer_stop(app); + direct_sampling_timer_start(app); + } } /* Enter view. Stop the subghz thread to prevent access as we read * the CC1101 data directly. */ void view_enter_direct_sampling(ProtoViewApp* app) { + /* Set view defaults. */ + DirectSamplingViewPrivData* privdata = app->view_privdata; + privdata->usec_per_pixel = DEFAULT_USEC_PER_PIXEL; + privdata->captured = malloc(CAPTURED_BITMAP_BYTES); + privdata->show_usage_info = true; + if(app->txrx->txrx_state == TxRxStateRx && !app->txrx->debug_timer_sampling) { - subghz_worker_stop(app->txrx->worker); + furi_hal_subghz_stop_async_rx(); + + /* To read data asynchronously directly from the view, we need + * to put the CC1101 back into reception mode (the previous call + * to stop the async RX will put it into idle) and configure the + * G0 pin for reading. */ + furi_hal_subghz_rx(); + furi_hal_gpio_init(furi_hal_subghz.cc1101_g0_pin, GpioModeInput, GpioPullNo, GpioSpeedLow); } else { raw_sampling_worker_stop(app); } + + // Start the timer to capture raw data + direct_sampling_timer_start(app); } /* Exit view. Restore the subghz thread. */ void view_exit_direct_sampling(ProtoViewApp* app) { + DirectSamplingViewPrivData* privdata = app->view_privdata; + if(privdata->captured) free(privdata->captured); + app->direct_sampling_enabled = false; + + direct_sampling_timer_stop(app); + + /* Restart normal data feeding. */ if(app->txrx->txrx_state == TxRxStateRx && !app->txrx->debug_timer_sampling) { - subghz_worker_start(app->txrx->worker); + furi_hal_subghz_start_async_rx(protoview_rx_callback, NULL); } else { raw_sampling_worker_start(app); } - app->direct_sampling_enabled = false; +} + +/* =========================== Timer implementation ========================= */ + +static void ds_timer_isr(void* ctx) { + ProtoViewApp* app = ctx; + DirectSamplingViewPrivData* privdata = app->view_privdata; + + if(app->direct_sampling_enabled) { + bool level = furi_hal_gpio_read(furi_hal_subghz.cc1101_g0_pin); + bitmap_set(privdata->captured, CAPTURED_BITMAP_BYTES, privdata->captured_idx, level); + privdata->captured_idx = (privdata->captured_idx + 1) % CAPTURED_BITMAP_BITS; + } + LL_TIM_ClearFlag_UPDATE(TIM2); +} + +static void direct_sampling_timer_start(ProtoViewApp* app) { + DirectSamplingViewPrivData* privdata = app->view_privdata; + + LL_TIM_InitTypeDef tim_init = { + .Prescaler = 63, /* CPU frequency is ~64Mhz. */ + .CounterMode = LL_TIM_COUNTERMODE_UP, + .Autoreload = privdata->usec_per_pixel}; + + LL_TIM_Init(TIM2, &tim_init); + LL_TIM_SetClockSource(TIM2, LL_TIM_CLOCKSOURCE_INTERNAL); + LL_TIM_DisableCounter(TIM2); + LL_TIM_SetCounter(TIM2, 0); + furi_hal_interrupt_set_isr(FuriHalInterruptIdTIM2, ds_timer_isr, app); + LL_TIM_EnableIT_UPDATE(TIM2); + LL_TIM_EnableCounter(TIM2); +} + +static void direct_sampling_timer_stop(ProtoViewApp* app) { + UNUSED(app); + FURI_CRITICAL_ENTER(); + LL_TIM_DisableCounter(TIM2); + LL_TIM_DisableIT_UPDATE(TIM2); + furi_hal_interrupt_set_isr(FuriHalInterruptIdTIM2, NULL, NULL); + LL_TIM_DeInit(TIM2); + FURI_CRITICAL_EXIT(); } diff --git a/applications/plugins/protoview/view_settings.c b/applications/plugins/protoview/view_settings.c index 94d80cfb5..09abf5a2a 100644 --- a/applications/plugins/protoview/view_settings.c +++ b/applications/plugins/protoview/view_settings.c @@ -88,7 +88,7 @@ void process_input_settings(ProtoViewApp* app, InputEvent input) { if(input.key == InputKeyUp) { modid = modid == 0 ? count - 1 : modid - 1; } else if(input.key == InputKeyDown) { - modid = (modid + 1) % (count ? count : 1); + modid = (modid + 1) % count; } else { return; } diff --git a/applications/plugins/solitaire/solitaire.c b/applications/plugins/solitaire/solitaire.c index 8893b3986..bfb533d82 100644 --- a/applications/plugins/solitaire/solitaire.c +++ b/applications/plugins/solitaire/solitaire.c @@ -255,7 +255,9 @@ bool place_on_top(Card* where, Card what) { int8_t b_letter = (int8_t)what.character; if(a_letter == 12) a_letter = -1; if(b_letter == 12) b_letter = -1; + if(where->disabled && b_letter != -1) return false; + if((a_letter + 1) == b_letter) { where->disabled = what.disabled; where->pip = what.pip; @@ -275,6 +277,7 @@ void tick(GameState* game_state, NotificationApp* notification) { if(game_state->state == GameStatePlay) { if(game_state->top_cards[0].character == 11 && game_state->top_cards[1].character == 11 && game_state->top_cards[2].character == 11 && game_state->top_cards[3].character == 11) { + DOLPHIN_DEED(DolphinDeedPluginGameWin); game_state->state = GameStateAnimate; return; } @@ -488,6 +491,10 @@ int32_t solitaire_app(void* p) { gui_add_view_port(gui, view_port, GuiLayerFullscreen); AppEvent event; + + // Call Dolphin deed on game start + DOLPHIN_DEED(DolphinDeedPluginGameStart); + for(bool processing = true; processing;) { FuriStatus event_status = furi_message_queue_get(event_queue, &event, 150); GameState* localstate = (GameState*)acquire_mutex_block(&state_mutex); @@ -566,4 +573,4 @@ free_and_exit: free(game_state); furi_message_queue_free(event_queue); return return_code; -} \ No newline at end of file +} diff --git a/applications/plugins/subbrute b/applications/plugins/subbrute new file mode 160000 index 000000000..819b53293 --- /dev/null +++ b/applications/plugins/subbrute @@ -0,0 +1 @@ +Subproject commit 819b532937b8920504cd54385e25389c199285f9 diff --git a/applications/plugins/subbrute/README.md b/applications/plugins/subbrute/README.md deleted file mode 100644 index 98c1503d0..000000000 --- a/applications/plugins/subbrute/README.md +++ /dev/null @@ -1,72 +0,0 @@ -# SubGHz Bruteforcer Plugin for Flipper Zero - -SubGhz Bruteforcer from [Unleashed Firmware](https://github.com/DarkFlippers/unleashed-firmware) - -### Disclaimer - -This software is for experimental purposes only and is not meant for any illegal activity/purposes. -We do not condone illegal activity and strongly encourage keeping transmissions to legal/valid uses allowed by law. - -### Supported Protocols: - -#### CAME - -- CAME 12bit 303MHz -- CAME 12bit 307MHz -- CAME 12bit 315MHz -- CAME 12bit 433MHz -- CAME 12bit 868MHz - -#### NICE - -- NICE 12bit 433MHz -- NICE 12bit 868MHz - -#### Ansonic - -- Ansonic 12bit 433.075MHz -- Ansonic 12bit 433.920MHz -- Ansonic 12bit 434.075MHz - -#### Holtek - -- Holtek HT12X 12bit 433.920MHz - -#### Chamberlain - -- Chamberlain 9bit 300MHz -- Chamberlain 9bit 315MHz -- Chamberlain 9bit 390MHz -- Chamberlain 9bit 433MHz -- Chamberlain 8bit 300MHz -- Chamberlain 8bit 315MHz -- Chamberlain 8bit 390MHz -- Chamberlain 7bit 300MHz -- Chamberlain 7bit 315MHz -- Chamberlain 7bit 390MHz - -#### Linear - -- Linear 10bit 300MHz -- Linear 10bit 310MHz - -#### UNILARM - -- UNILARM 25bit 330MHz -- UNILARM 25bit 433MHz - -#### SMC5326 - -- SMC5326 25bit 330MHz -- SMC5326 25bit 433MHz - -#### PT2260 - -- PT2260 24bit 315MHz -- PT2260 24bit 330MHz -- PT2260 24bit 390MHz -- PT2260 24bit 433MHz - -#### Additional - -- BF Existing dump works for most other static protocols supported by Flipper Zero diff --git a/applications/plugins/subbrute/application.fam b/applications/plugins/subbrute/application.fam deleted file mode 100644 index 20a5f5367..000000000 --- a/applications/plugins/subbrute/application.fam +++ /dev/null @@ -1,13 +0,0 @@ -App( - appid="SubGHz_Bruteforcer", - name="Sub-GHz Bruteforcer", - apptype=FlipperAppType.EXTERNAL, - entry_point="subbrute_app", - cdefines=["APP_SUB_BRUTE"], - requires=["gui", "dialogs"], - stack_size=2 * 1024, - order=11, - fap_icon="images/subbrute_10px.png", - fap_category="Tools", - fap_icon_assets="images", -) diff --git a/applications/plugins/subbrute/helpers/gui_top_buttons.c b/applications/plugins/subbrute/helpers/gui_top_buttons.c deleted file mode 100644 index 0415c5ae7..000000000 --- a/applications/plugins/subbrute/helpers/gui_top_buttons.c +++ /dev/null @@ -1,59 +0,0 @@ -#include "gui_top_buttons.h" - -void elements_button_top_left(Canvas* canvas, const char* str) { - const Icon* icon = &I_ButtonUp_7x4; - - const uint8_t button_height = 12; - const uint8_t vertical_offset = 3; - const uint8_t horizontal_offset = 3; - const uint8_t string_width = canvas_string_width(canvas, str); - const uint8_t icon_h_offset = 3; - const uint8_t icon_width_with_offset = icon_get_width(icon) + icon_h_offset; - const uint8_t icon_v_offset = icon_get_height(icon) + vertical_offset; - const uint8_t button_width = string_width + horizontal_offset * 2 + icon_width_with_offset; - - const uint8_t x = 0; - const uint8_t y = 0 + button_height; - - uint8_t line_x = x + button_width; - uint8_t line_y = y - button_height; - canvas_draw_box(canvas, x, line_y, button_width, button_height); - canvas_draw_line(canvas, line_x + 0, line_y, line_x + 0, y - 1); - canvas_draw_line(canvas, line_x + 1, line_y, line_x + 1, y - 2); - canvas_draw_line(canvas, line_x + 2, line_y, line_x + 2, y - 3); - - canvas_invert_color(canvas); - canvas_draw_icon(canvas, x + horizontal_offset, y - icon_v_offset, icon); - canvas_draw_str( - canvas, x + horizontal_offset + icon_width_with_offset, y - vertical_offset, str); - canvas_invert_color(canvas); -} - -void elements_button_top_right(Canvas* canvas, const char* str) { - const Icon* icon = &I_ButtonDown_7x4; - - const uint8_t button_height = 12; - const uint8_t vertical_offset = 3; - const uint8_t horizontal_offset = 3; - const uint8_t string_width = canvas_string_width(canvas, str); - const uint8_t icon_h_offset = 3; - const uint8_t icon_width_with_offset = icon_get_width(icon) + icon_h_offset; - const uint8_t icon_v_offset = icon_get_height(icon) + vertical_offset + 1; - const uint8_t button_width = string_width + horizontal_offset * 2 + icon_width_with_offset; - - const uint8_t x = canvas_width(canvas); - const uint8_t y = 0 + button_height; - - uint8_t line_x = x - button_width; - uint8_t line_y = y - button_height; - canvas_draw_box(canvas, line_x, line_y, button_width, button_height); - canvas_draw_line(canvas, line_x - 1, line_y, line_x - 1, y - 1); - canvas_draw_line(canvas, line_x - 2, line_y, line_x - 2, y - 2); - canvas_draw_line(canvas, line_x - 3, line_y, line_x - 3, y - 3); - - canvas_invert_color(canvas); - canvas_draw_str(canvas, x - button_width + horizontal_offset, y - vertical_offset, str); - canvas_draw_icon( - canvas, x - horizontal_offset - icon_get_width(icon), y - icon_v_offset, icon); - canvas_invert_color(canvas); -} \ No newline at end of file diff --git a/applications/plugins/subbrute/helpers/gui_top_buttons.h b/applications/plugins/subbrute/helpers/gui_top_buttons.h deleted file mode 100644 index b5ca507b7..000000000 --- a/applications/plugins/subbrute/helpers/gui_top_buttons.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -/** - * Thanks to the author of metronome - * @param canvas - * @param str - */ -void elements_button_top_left(Canvas* canvas, const char* str); - -/** - * Thanks to the author of metronome - * @param canvas - * @param str - */ -void elements_button_top_right(Canvas* canvas, const char* str); \ No newline at end of file diff --git a/applications/plugins/subbrute/helpers/subbrute_worker.c b/applications/plugins/subbrute/helpers/subbrute_worker.c deleted file mode 100644 index 118e63c65..000000000 --- a/applications/plugins/subbrute/helpers/subbrute_worker.c +++ /dev/null @@ -1,437 +0,0 @@ -#include "subbrute_worker_private.h" -#include -#include -#include -#include -#include - -#define TAG "SubBruteWorker" -#define SUBBRUTE_TX_TIMEOUT 5 -#define SUBBRUTE_MANUAL_TRANSMIT_INTERVAL 400 - -SubBruteWorker* subbrute_worker_alloc() { - SubBruteWorker* instance = malloc(sizeof(SubBruteWorker)); - - instance->state = SubBruteWorkerStateIDLE; - instance->step = 0; - instance->worker_running = false; - instance->initiated = false; - instance->last_time_tx_data = 0; - instance->load_index = 0; - - instance->thread = furi_thread_alloc(); - furi_thread_set_name(instance->thread, "SubBruteAttackWorker"); - furi_thread_set_stack_size(instance->thread, 2048); - furi_thread_set_context(instance->thread, instance); - furi_thread_set_callback(instance->thread, subbrute_worker_thread); - - instance->context = NULL; - instance->callback = NULL; - - instance->decoder_result = NULL; - instance->transmitter = NULL; - instance->environment = subghz_environment_alloc(); - subghz_environment_set_protocol_registry( - instance->environment, (void*)&subghz_protocol_registry); - - instance->transmit_mode = false; - - return instance; -} - -void subbrute_worker_free(SubBruteWorker* instance) { - furi_assert(instance); - - // I don't know how to free this - instance->decoder_result = NULL; - - if(instance->transmitter != NULL) { - subghz_transmitter_free(instance->transmitter); - instance->transmitter = NULL; - } - - subghz_environment_free(instance->environment); - instance->environment = NULL; - - furi_thread_free(instance->thread); - - free(instance); -} - -uint64_t subbrute_worker_get_step(SubBruteWorker* instance) { - return instance->step; -} - -bool subbrute_worker_set_step(SubBruteWorker* instance, uint64_t step) { - furi_assert(instance); - if(!subbrute_worker_can_manual_transmit(instance)) { - FURI_LOG_W(TAG, "Cannot set step during running mode"); - return false; - } - - instance->step = step; - - return true; -} - -bool subbrute_worker_init_default_attack( - SubBruteWorker* instance, - SubBruteAttacks attack_type, - uint64_t step, - const SubBruteProtocol* protocol, - uint8_t extra_repeats) { - furi_assert(instance); - - if(instance->worker_running) { - FURI_LOG_W(TAG, "Init Worker when it's running"); - subbrute_worker_stop(instance); - } - - instance->attack = attack_type; - instance->frequency = protocol->frequency; - instance->preset = protocol->preset; - instance->file = protocol->file; - instance->step = step; - instance->bits = protocol->bits; - instance->te = protocol->te; - instance->repeat = protocol->repeat + extra_repeats; - instance->load_index = 0; - instance->file_key = 0; - instance->two_bytes = false; - - instance->max_value = - subbrute_protocol_calc_max_value(instance->attack, instance->bits, instance->two_bytes); - - instance->initiated = true; - instance->state = SubBruteWorkerStateReady; - subbrute_worker_send_callback(instance); -#ifdef FURI_DEBUG - FURI_LOG_I( - TAG, - "subbrute_worker_init_default_attack: %s, bits: %d, preset: %s, file: %s, te: %ld, repeat: %d, max_value: %lld", - subbrute_protocol_name(instance->attack), - instance->bits, - subbrute_protocol_preset(instance->preset), - subbrute_protocol_file(instance->file), - instance->te, - instance->repeat, - instance->max_value); -#endif - - return true; -} - -bool subbrute_worker_init_file_attack( - SubBruteWorker* instance, - uint64_t step, - uint8_t load_index, - uint64_t file_key, - SubBruteProtocol* protocol, - uint8_t extra_repeats, - bool two_bytes) { - furi_assert(instance); - - if(instance->worker_running) { - FURI_LOG_W(TAG, "Init Worker when it's running"); - subbrute_worker_stop(instance); - } - - instance->attack = SubBruteAttackLoadFile; - instance->frequency = protocol->frequency; - instance->preset = protocol->preset; - instance->file = protocol->file; - instance->step = step; - instance->bits = protocol->bits; - instance->te = protocol->te; - instance->load_index = load_index; - instance->repeat = protocol->repeat + extra_repeats; - instance->file_key = file_key; - instance->two_bytes = two_bytes; - - instance->max_value = - subbrute_protocol_calc_max_value(instance->attack, instance->bits, instance->two_bytes); - - instance->initiated = true; - instance->state = SubBruteWorkerStateReady; - subbrute_worker_send_callback(instance); -#ifdef FURI_DEBUG - FURI_LOG_I( - TAG, - "subbrute_worker_init_file_attack: %s, bits: %d, preset: %s, file: %s, te: %ld, repeat: %d, max_value: %lld, key: %llX", - subbrute_protocol_name(instance->attack), - instance->bits, - subbrute_protocol_preset(instance->preset), - subbrute_protocol_file(instance->file), - instance->te, - instance->repeat, - instance->max_value, - instance->file_key); -#endif - - return true; -} - -bool subbrute_worker_start(SubBruteWorker* instance) { - furi_assert(instance); - - if(!instance->initiated) { - FURI_LOG_W(TAG, "Worker not init!"); - return false; - } - - if(instance->worker_running) { - FURI_LOG_W(TAG, "Worker is already running!"); - return false; - } - if(instance->state != SubBruteWorkerStateReady && - instance->state != SubBruteWorkerStateFinished) { - FURI_LOG_W(TAG, "Worker cannot start, invalid device state: %d", instance->state); - return false; - } - - instance->worker_running = true; - furi_thread_start(instance->thread); - - return true; -} - -void subbrute_worker_stop(SubBruteWorker* instance) { - furi_assert(instance); - - if(!instance->worker_running) { - return; - } - - instance->worker_running = false; - furi_thread_join(instance->thread); - - furi_hal_subghz_set_path(FuriHalSubGhzPathIsolate); - furi_hal_subghz_sleep(); -} - -bool subbrute_worker_transmit_current_key(SubBruteWorker* instance, uint64_t step) { - furi_assert(instance); - - if(!instance->initiated) { - FURI_LOG_W(TAG, "Worker not init!"); - return false; - } - if(instance->worker_running) { - FURI_LOG_W(TAG, "Worker in running state!"); - return false; - } - if(instance->state != SubBruteWorkerStateReady && - instance->state != SubBruteWorkerStateFinished) { - FURI_LOG_W(TAG, "Invalid state for running worker! State: %d", instance->state); - return false; - } - - uint32_t ticks = furi_get_tick(); - if((ticks - instance->last_time_tx_data) < SUBBRUTE_MANUAL_TRANSMIT_INTERVAL) { -#if FURI_DEBUG - FURI_LOG_D(TAG, "Need to wait, current: %ld", ticks - instance->last_time_tx_data); -#endif - return false; - } - - instance->last_time_tx_data = ticks; - instance->step = step; - - bool result; - instance->protocol_name = subbrute_protocol_file(instance->file); - FlipperFormat* flipper_format = flipper_format_string_alloc(); - Stream* stream = flipper_format_get_raw_stream(flipper_format); - - stream_clean(stream); - - if(instance->attack == SubBruteAttackLoadFile) { - subbrute_protocol_file_payload( - stream, - step, - instance->bits, - instance->te, - instance->repeat, - instance->load_index, - instance->file_key, - instance->two_bytes); - } else { - subbrute_protocol_default_payload( - stream, instance->file, step, instance->bits, instance->te, instance->repeat); - } - - // size_t written = stream_write_string(stream, payload); - // if(written <= 0) { - // FURI_LOG_W(TAG, "Error creating packet! EXIT"); - // result = false; - // } else { - subbrute_worker_subghz_transmit(instance, flipper_format); - - result = true; -#if FURI_DEBUG - FURI_LOG_D(TAG, "Manual transmit done"); -#endif - // } - - flipper_format_free(flipper_format); - // furi_string_free(payload); - - return result; -} - -bool subbrute_worker_is_running(SubBruteWorker* instance) { - return instance->worker_running; -} - -bool subbrute_worker_can_manual_transmit(SubBruteWorker* instance) { - furi_assert(instance); - - if(!instance->initiated) { - FURI_LOG_W(TAG, "Worker not init!"); - return false; - } - - return !instance->worker_running && instance->state != SubBruteWorkerStateIDLE && - instance->state != SubBruteWorkerStateTx && - ((furi_get_tick() - instance->last_time_tx_data) > SUBBRUTE_MANUAL_TRANSMIT_INTERVAL); -} - -void subbrute_worker_set_callback( - SubBruteWorker* instance, - SubBruteWorkerCallback callback, - void* context) { - furi_assert(instance); - - instance->callback = callback; - instance->context = context; -} - -void subbrute_worker_subghz_transmit(SubBruteWorker* instance, FlipperFormat* flipper_format) { - while(instance->transmit_mode) { - furi_delay_ms(SUBBRUTE_TX_TIMEOUT); - } - instance->transmit_mode = true; - if(instance->transmitter != NULL) { - subghz_transmitter_free(instance->transmitter); - instance->transmitter = NULL; - } - instance->transmitter = - subghz_transmitter_alloc_init(instance->environment, instance->protocol_name); - subghz_transmitter_deserialize(instance->transmitter, flipper_format); - furi_hal_subghz_reset(); - furi_hal_subghz_load_preset(instance->preset); - furi_hal_subghz_set_frequency_and_path(instance->frequency); - furi_hal_subghz_start_async_tx(subghz_transmitter_yield, instance->transmitter); - - while(!furi_hal_subghz_is_async_tx_complete()) { - furi_delay_ms(SUBBRUTE_TX_TIMEOUT); - } - furi_hal_subghz_stop_async_tx(); - - furi_hal_subghz_set_path(FuriHalSubGhzPathIsolate); - furi_hal_subghz_sleep(); - subghz_transmitter_free(instance->transmitter); - instance->transmitter = NULL; - - instance->transmit_mode = false; -} - -void subbrute_worker_send_callback(SubBruteWorker* instance) { - if(instance->callback != NULL) { - instance->callback(instance->context, instance->state); - } -} - -/** - * Entrypoint for worker - * - * @param context SubBruteWorker* - * @return 0 if ok - */ -int32_t subbrute_worker_thread(void* context) { - furi_assert(context); - SubBruteWorker* instance = (SubBruteWorker*)context; - - if(!instance->worker_running) { - FURI_LOG_W(TAG, "Worker is not set to running state!"); - return -1; - } - if(instance->state != SubBruteWorkerStateReady && - instance->state != SubBruteWorkerStateFinished) { - FURI_LOG_W(TAG, "Invalid state for running worker! State: %d", instance->state); - return -2; - } -#ifdef FURI_DEBUG - FURI_LOG_I(TAG, "Worker start"); -#endif - - SubBruteWorkerState local_state = instance->state = SubBruteWorkerStateTx; - subbrute_worker_send_callback(instance); - - instance->protocol_name = subbrute_protocol_file(instance->file); - - FlipperFormat* flipper_format = flipper_format_string_alloc(); - Stream* stream = flipper_format_get_raw_stream(flipper_format); - - while(instance->worker_running) { - stream_clean(stream); - if(instance->attack == SubBruteAttackLoadFile) { - subbrute_protocol_file_payload( - stream, - instance->step, - instance->bits, - instance->te, - instance->repeat, - instance->load_index, - instance->file_key, - instance->two_bytes); - } else { - subbrute_protocol_default_payload( - stream, - instance->file, - instance->step, - instance->bits, - instance->te, - instance->repeat); - } -#ifdef FURI_DEBUG - //FURI_LOG_I(TAG, "Payload: %s", furi_string_get_cstr(payload)); - //furi_delay_ms(SUBBRUTE_MANUAL_TRANSMIT_INTERVAL / 4); -#endif - - // size_t written = stream_write_stream_write_string(stream, payload); - // if(written <= 0) { - // FURI_LOG_W(TAG, "Error creating packet! BREAK"); - // instance->worker_running = false; - // local_state = SubBruteWorkerStateIDLE; - // furi_string_free(payload); - // break; - // } - - subbrute_worker_subghz_transmit(instance, flipper_format); - - if(instance->step + 1 > instance->max_value) { -#ifdef FURI_DEBUG - FURI_LOG_I(TAG, "Worker finished to end"); -#endif - local_state = SubBruteWorkerStateFinished; - // furi_string_free(payload); - break; - } - instance->step++; - - // furi_string_free(payload); - furi_delay_ms(SUBBRUTE_TX_TIMEOUT); - } - - flipper_format_free(flipper_format); - - instance->worker_running = false; // Because we have error states - instance->state = local_state == SubBruteWorkerStateTx ? SubBruteWorkerStateReady : - local_state; - subbrute_worker_send_callback(instance); - -#ifdef FURI_DEBUG - FURI_LOG_I(TAG, "Worker stop"); -#endif - return 0; -} diff --git a/applications/plugins/subbrute/helpers/subbrute_worker.h b/applications/plugins/subbrute/helpers/subbrute_worker.h deleted file mode 100644 index 4046f997c..000000000 --- a/applications/plugins/subbrute/helpers/subbrute_worker.h +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once - -#include "../subbrute_protocols.h" - -typedef enum { - SubBruteWorkerStateIDLE, - SubBruteWorkerStateReady, - SubBruteWorkerStateTx, - SubBruteWorkerStateFinished -} SubBruteWorkerState; - -typedef void (*SubBruteWorkerCallback)(void* context, SubBruteWorkerState state); - -typedef struct SubBruteWorker SubBruteWorker; - -SubBruteWorker* subbrute_worker_alloc(); -void subbrute_worker_free(SubBruteWorker* instance); -uint64_t subbrute_worker_get_step(SubBruteWorker* instance); -bool subbrute_worker_set_step(SubBruteWorker* instance, uint64_t step); -bool subbrute_worker_is_running(SubBruteWorker* instance); -bool subbrute_worker_init_default_attack( - SubBruteWorker* instance, - SubBruteAttacks attack_type, - uint64_t step, - const SubBruteProtocol* protocol, - uint8_t extra_repeats); -bool subbrute_worker_init_file_attack( - SubBruteWorker* instance, - uint64_t step, - uint8_t load_index, - uint64_t file_key, - SubBruteProtocol* protocol, - uint8_t extra_repeats, - bool two_bytes); -bool subbrute_worker_start(SubBruteWorker* instance); -void subbrute_worker_stop(SubBruteWorker* instance); -bool subbrute_worker_transmit_current_key(SubBruteWorker* instance, uint64_t step); -bool subbrute_worker_can_manual_transmit(SubBruteWorker* instance); -void subbrute_worker_set_callback( - SubBruteWorker* instance, - SubBruteWorkerCallback callback, - void* context); \ No newline at end of file diff --git a/applications/plugins/subbrute/helpers/subbrute_worker_private.h b/applications/plugins/subbrute/helpers/subbrute_worker_private.h deleted file mode 100644 index e38e77dc4..000000000 --- a/applications/plugins/subbrute/helpers/subbrute_worker_private.h +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -#include "subbrute_worker.h" -#include -#include -#include -#include - -struct SubBruteWorker { - SubBruteWorkerState state; - volatile bool worker_running; - volatile bool initiated; - volatile bool transmit_mode; - - // Current step - uint64_t step; - - // SubGhz - FuriThread* thread; - SubGhzProtocolDecoderBase* decoder_result; - SubGhzEnvironment* environment; - SubGhzTransmitter* transmitter; - const char* protocol_name; - - // Initiated values - SubBruteAttacks attack; // Attack state - uint32_t frequency; - FuriHalSubGhzPreset preset; - SubBruteFileProtocol file; - uint8_t bits; - uint32_t te; - uint8_t repeat; - uint8_t load_index; // Index of group to bruteforce in loaded file - uint64_t file_key; - uint64_t max_value; // Max step - bool two_bytes; - - // Manual transmit - uint32_t last_time_tx_data; - - // Callback for changed states - SubBruteWorkerCallback callback; - void* context; -}; - -int32_t subbrute_worker_thread(void* context); -void subbrute_worker_subghz_transmit(SubBruteWorker* instance, FlipperFormat* flipper_format); -void subbrute_worker_send_callback(SubBruteWorker* instance); \ No newline at end of file diff --git a/applications/plugins/subbrute/images/ButtonDown_7x4.png b/applications/plugins/subbrute/images/ButtonDown_7x4.png deleted file mode 100644 index 2954bb6a6..000000000 Binary files a/applications/plugins/subbrute/images/ButtonDown_7x4.png and /dev/null differ diff --git a/applications/plugins/subbrute/images/ButtonUp_7x4.png b/applications/plugins/subbrute/images/ButtonUp_7x4.png deleted file mode 100644 index 1be79328b..000000000 Binary files a/applications/plugins/subbrute/images/ButtonUp_7x4.png and /dev/null differ diff --git a/applications/plugins/subbrute/images/DolphinNice_96x59.png b/applications/plugins/subbrute/images/DolphinNice_96x59.png deleted file mode 100644 index a299d3630..000000000 Binary files a/applications/plugins/subbrute/images/DolphinNice_96x59.png and /dev/null differ diff --git a/applications/plugins/subbrute/images/Sub1ghz_14/frame_01.png b/applications/plugins/subbrute/images/Sub1ghz_14/frame_01.png deleted file mode 100644 index 52dc4ad21..000000000 Binary files a/applications/plugins/subbrute/images/Sub1ghz_14/frame_01.png and /dev/null differ diff --git a/applications/plugins/subbrute/images/Sub1ghz_14/frame_02.png b/applications/plugins/subbrute/images/Sub1ghz_14/frame_02.png deleted file mode 100644 index 2dff1c031..000000000 Binary files a/applications/plugins/subbrute/images/Sub1ghz_14/frame_02.png and /dev/null differ diff --git a/applications/plugins/subbrute/images/Sub1ghz_14/frame_03.png b/applications/plugins/subbrute/images/Sub1ghz_14/frame_03.png deleted file mode 100644 index c1e438b01..000000000 Binary files a/applications/plugins/subbrute/images/Sub1ghz_14/frame_03.png and /dev/null differ diff --git a/applications/plugins/subbrute/images/Sub1ghz_14/frame_04.png b/applications/plugins/subbrute/images/Sub1ghz_14/frame_04.png deleted file mode 100644 index 169fb6147..000000000 Binary files a/applications/plugins/subbrute/images/Sub1ghz_14/frame_04.png and /dev/null differ diff --git a/applications/plugins/subbrute/images/Sub1ghz_14/frame_05.png b/applications/plugins/subbrute/images/Sub1ghz_14/frame_05.png deleted file mode 100644 index 79b2bc972..000000000 Binary files a/applications/plugins/subbrute/images/Sub1ghz_14/frame_05.png and /dev/null differ diff --git a/applications/plugins/subbrute/images/Sub1ghz_14/frame_06.png b/applications/plugins/subbrute/images/Sub1ghz_14/frame_06.png deleted file mode 100644 index 8fce0c44d..000000000 Binary files a/applications/plugins/subbrute/images/Sub1ghz_14/frame_06.png and /dev/null differ diff --git a/applications/plugins/subbrute/images/Sub1ghz_14/frame_rate b/applications/plugins/subbrute/images/Sub1ghz_14/frame_rate deleted file mode 100644 index e440e5c84..000000000 --- a/applications/plugins/subbrute/images/Sub1ghz_14/frame_rate +++ /dev/null @@ -1 +0,0 @@ -3 \ No newline at end of file diff --git a/applications/plugins/subbrute/images/sub1_10px.png b/applications/plugins/subbrute/images/sub1_10px.png deleted file mode 100644 index 5a25fdf4e..000000000 Binary files a/applications/plugins/subbrute/images/sub1_10px.png and /dev/null differ diff --git a/applications/plugins/subbrute/images/subbrute_10px.png b/applications/plugins/subbrute/images/subbrute_10px.png deleted file mode 100644 index 57d6f6a45..000000000 Binary files a/applications/plugins/subbrute/images/subbrute_10px.png and /dev/null differ diff --git a/applications/plugins/subbrute/scenes/subbrute_scene_config.h b/applications/plugins/subbrute/scenes/subbrute_scene_config.h deleted file mode 100644 index 3541df9ac..000000000 --- a/applications/plugins/subbrute/scenes/subbrute_scene_config.h +++ /dev/null @@ -1,7 +0,0 @@ -ADD_SCENE(subbrute, load_file, LoadFile) -ADD_SCENE(subbrute, load_select, LoadSelect) -ADD_SCENE(subbrute, run_attack, RunAttack) -ADD_SCENE(subbrute, save_name, SaveName) -ADD_SCENE(subbrute, save_success, SaveSuccess) -ADD_SCENE(subbrute, setup_attack, SetupAttack) -ADD_SCENE(subbrute, start, Start) \ No newline at end of file diff --git a/applications/plugins/subbrute/scenes/subbrute_scene_load_file.c b/applications/plugins/subbrute/scenes/subbrute_scene_load_file.c deleted file mode 100644 index 8aae1bcad..000000000 --- a/applications/plugins/subbrute/scenes/subbrute_scene_load_file.c +++ /dev/null @@ -1,91 +0,0 @@ -#include "../subbrute_i.h" -#include "subbrute_scene.h" - -#define TAG "SubBruteSceneLoadFile" - -void subbrute_scene_load_file_on_enter(void* context) { - furi_assert(context); - SubBruteState* instance = (SubBruteState*)context; - - // Input events and views are managed by file_browser - FuriString* app_folder; - FuriString* load_path; - load_path = furi_string_alloc(); - app_folder = furi_string_alloc_set(SUBBRUTE_PATH); - - DialogsFileBrowserOptions browser_options; - dialog_file_browser_set_basic_options(&browser_options, SUBBRUTE_FILE_EXT, &I_sub1_10px); - - SubBruteFileResult load_result = SubBruteFileResultUnknown; - // TODO: DELETE IT -#ifdef SUBBRUTE_FAST_TRACK - bool res = true; - furi_string_printf(load_path, "%s", "/ext/subghz/princeton.sub"); -#else - bool res = - dialog_file_browser_show(instance->dialogs, load_path, app_folder, &browser_options); -#endif -#ifdef FURI_DEBUG - FURI_LOG_D( - TAG, - "load_path: %s, app_folder: %s", - furi_string_get_cstr(load_path), - furi_string_get_cstr(app_folder)); -#endif - if(res) { - load_result = - subbrute_device_load_from_file(instance->device, furi_string_get_cstr(load_path)); - if(load_result == SubBruteFileResultOk) { - uint8_t extra_repeats = subbrute_main_view_get_extra_repeats(instance->view_main); - - load_result = subbrute_device_attack_set( - instance->device, SubBruteAttackLoadFile, extra_repeats); - if(load_result == SubBruteFileResultOk) { - if(!subbrute_worker_init_file_attack( - instance->worker, - instance->device->current_step, - instance->device->bit_index, - instance->device->key_from_file, - instance->device->file_protocol_info, - extra_repeats, - instance->device->two_bytes)) { - furi_crash("Invalid attack set!"); - } - // Ready to run! - FURI_LOG_I(TAG, "Ready to run"); - res = true; - } - } - - if(load_result == SubBruteFileResultOk) { - scene_manager_next_scene(instance->scene_manager, SubBruteSceneLoadSelect); - } else { - FURI_LOG_E(TAG, "Returned error: %d", load_result); - - FuriString* dialog_msg; - dialog_msg = furi_string_alloc(); - furi_string_cat_printf( - dialog_msg, "Cannot parse\nfile: %s", subbrute_device_error_get_desc(load_result)); - dialog_message_show_storage_error(instance->dialogs, furi_string_get_cstr(dialog_msg)); - furi_string_free(dialog_msg); - scene_manager_search_and_switch_to_previous_scene( - instance->scene_manager, SubBruteSceneStart); - } - } else { - scene_manager_search_and_switch_to_previous_scene( - instance->scene_manager, SubBruteSceneStart); - } - - furi_string_free(app_folder); - furi_string_free(load_path); -} - -void subbrute_scene_load_file_on_exit(void* context) { - UNUSED(context); -} - -bool subbrute_scene_load_file_on_event(void* context, SceneManagerEvent event) { - UNUSED(context); - UNUSED(event); - return false; -} \ No newline at end of file diff --git a/applications/plugins/subbrute/scenes/subbrute_scene_load_select.c b/applications/plugins/subbrute/scenes/subbrute_scene_load_select.c deleted file mode 100644 index d018e8b4d..000000000 --- a/applications/plugins/subbrute/scenes/subbrute_scene_load_select.c +++ /dev/null @@ -1,82 +0,0 @@ -#include "../subbrute_i.h" -#include "subbrute_scene.h" - -#define TAG "SubBruteSceneStart" - -void subbrute_scene_load_select_callback(SubBruteCustomEvent event, void* context) { - furi_assert(context); - - SubBruteState* instance = (SubBruteState*)context; - view_dispatcher_send_custom_event(instance->view_dispatcher, event); -} - -void subbrute_scene_load_select_on_enter(void* context) { - furi_assert(context); -#ifdef FURI_DEBUG - FURI_LOG_I(TAG, "subbrute_scene_load_select_on_enter"); -#endif - SubBruteState* instance = (SubBruteState*)context; - SubBruteMainView* view = instance->view_main; - - instance->current_view = SubBruteViewMain; - subbrute_main_view_set_callback(view, subbrute_scene_load_select_callback, instance); - subbrute_main_view_set_index( - view, 7, true, instance->device->two_bytes, instance->device->key_from_file); - - view_dispatcher_switch_to_view(instance->view_dispatcher, instance->current_view); -} - -void subbrute_scene_load_select_on_exit(void* context) { - UNUSED(context); -#ifdef FURI_DEBUG - FURI_LOG_I(TAG, "subbrute_scene_load_select_on_exit"); -#endif -} - -bool subbrute_scene_load_select_on_event(void* context, SceneManagerEvent event) { - SubBruteState* instance = (SubBruteState*)context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == SubBruteCustomEventTypeIndexSelected) { - /*#ifdef FURI_DEBUG && !SUBBRUTE_FAST_TRACK - view_dispatcher_stop(instance->view_dispatcher); - consumed = true; -#else*/ - instance->device->current_step = 0; - instance->device->bit_index = subbrute_main_view_get_index(instance->view_main); - instance->device->two_bytes = subbrute_main_view_get_two_bytes(instance->view_main); - uint8_t extra_repeats = subbrute_main_view_get_extra_repeats(instance->view_main); - instance->device->max_value = subbrute_protocol_calc_max_value( - instance->device->attack, - instance->device->bit_index, - instance->device->two_bytes); - - if(!subbrute_worker_init_file_attack( - instance->worker, - instance->device->current_step, - instance->device->bit_index, - instance->device->key_from_file, - instance->device->file_protocol_info, - extra_repeats, - instance->device->two_bytes)) { - furi_crash("Invalid attack set!"); - } - scene_manager_next_scene(instance->scene_manager, SubBruteSceneSetupAttack); - /*#endif*/ - consumed = true; - } /* else if(event.event == SubBruteCustomEventTypeChangeStepUp) { - instance->device->two_bytes = true; - } else if(event.event == SubBruteCustomEventTypeChangeStepDown) { - instance->device->two_bytes = false; - }*/ - } else if(event.type == SceneManagerEventTypeBack) { - if(!scene_manager_search_and_switch_to_previous_scene( - instance->scene_manager, SubBruteSceneStart)) { - scene_manager_next_scene(instance->scene_manager, SubBruteSceneStart); - } - consumed = true; - } - - return consumed; -} \ No newline at end of file diff --git a/applications/plugins/subbrute/scenes/subbrute_scene_run_attack.c b/applications/plugins/subbrute/scenes/subbrute_scene_run_attack.c deleted file mode 100644 index 2f22c25d4..000000000 --- a/applications/plugins/subbrute/scenes/subbrute_scene_run_attack.c +++ /dev/null @@ -1,104 +0,0 @@ -#include "../subbrute_i.h" -#include "subbrute_scene.h" - -#define TAG "SubBruteSceneRunAttack" - -static void subbrute_scene_run_attack_callback(SubBruteCustomEvent event, void* context) { - furi_assert(context); - - SubBruteState* instance = (SubBruteState*)context; - view_dispatcher_send_custom_event(instance->view_dispatcher, event); -} - -static void - subbrute_scene_run_attack_device_state_changed(void* context, SubBruteWorkerState state) { - furi_assert(context); - - SubBruteState* instance = (SubBruteState*)context; - - if(state == SubBruteWorkerStateIDLE) { - // Can't be IDLE on this step! - view_dispatcher_send_custom_event(instance->view_dispatcher, SubBruteCustomEventTypeError); - } else if(state == SubBruteWorkerStateFinished) { - view_dispatcher_send_custom_event( - instance->view_dispatcher, SubBruteCustomEventTypeTransmitFinished); - } -} -void subbrute_scene_run_attack_on_exit(void* context) { - furi_assert(context); - SubBruteState* instance = (SubBruteState*)context; - - notification_message(instance->notifications, &sequence_blink_stop); - subbrute_worker_stop(instance->worker); -} - -void subbrute_scene_run_attack_on_enter(void* context) { - furi_assert(context); - SubBruteState* instance = (SubBruteState*)context; - SubBruteAttackView* view = instance->view_attack; - - instance->current_view = SubBruteViewAttack; - subbrute_attack_view_set_callback(view, subbrute_scene_run_attack_callback, instance); - view_dispatcher_switch_to_view(instance->view_dispatcher, instance->current_view); - - subbrute_worker_set_callback( - instance->worker, subbrute_scene_run_attack_device_state_changed, instance); - - if(!subbrute_worker_is_running(instance->worker)) { - subbrute_worker_set_step(instance->worker, instance->device->current_step); - if(!subbrute_worker_start(instance->worker)) { - view_dispatcher_send_custom_event( - instance->view_dispatcher, SubBruteCustomEventTypeError); - } else { - notification_message(instance->notifications, &sequence_single_vibro); - notification_message(instance->notifications, &sequence_blink_start_yellow); - } - } -} - -bool subbrute_scene_run_attack_on_event(void* context, SceneManagerEvent event) { - SubBruteState* instance = (SubBruteState*)context; - SubBruteAttackView* view = instance->view_attack; - - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - uint64_t step = subbrute_worker_get_step(instance->worker); - instance->device->current_step = step; - subbrute_attack_view_set_current_step(view, step); - - if(event.event == SubBruteCustomEventTypeTransmitFinished) { - notification_message(instance->notifications, &sequence_display_backlight_on); - notification_message(instance->notifications, &sequence_double_vibro); - - scene_manager_next_scene(instance->scene_manager, SubBruteSceneSetupAttack); - } else if( - event.event == SubBruteCustomEventTypeTransmitNotStarted || - event.event == SubBruteCustomEventTypeBackPressed) { - if(subbrute_worker_is_running(instance->worker)) { - // Notify - notification_message(instance->notifications, &sequence_single_vibro); - } - // Stop transmit - scene_manager_search_and_switch_to_previous_scene( - instance->scene_manager, SubBruteSceneSetupAttack); - } else if(event.event == SubBruteCustomEventTypeError) { - notification_message(instance->notifications, &sequence_error); - - // Stop transmit - scene_manager_search_and_switch_to_previous_scene( - instance->scene_manager, SubBruteSceneSetupAttack); - } else if(event.event == SubBruteCustomEventTypeUpdateView) { - //subbrute_attack_view_set_current_step(view, instance->device->current_step); - } - consumed = true; - } else if(event.type == SceneManagerEventTypeTick) { - uint64_t step = subbrute_worker_get_step(instance->worker); - instance->device->current_step = step; - subbrute_attack_view_set_current_step(view, step); - - consumed = true; - } - - return consumed; -} diff --git a/applications/plugins/subbrute/scenes/subbrute_scene_save_name.c b/applications/plugins/subbrute/scenes/subbrute_scene_save_name.c deleted file mode 100644 index bb129e948..000000000 --- a/applications/plugins/subbrute/scenes/subbrute_scene_save_name.c +++ /dev/null @@ -1,84 +0,0 @@ -#include "../subbrute_i.h" -#include "subbrute_scene.h" -#include - -#define TAG "SubBruteSceneSaveFile" - -void subbrute_scene_save_name_on_enter(void* context) { - SubBruteState* instance = (SubBruteState*)context; - - // Setup view - TextInput* text_input = instance->text_input; - set_random_name(instance->text_store, sizeof(instance->text_store)); - - text_input_set_header_text(text_input, "Name of file"); - text_input_set_result_callback( - text_input, - subbrute_text_input_callback, - instance, - instance->text_store, - SUBBRUTE_MAX_LEN_NAME, - true); - - furi_string_reset(instance->file_path); - furi_string_set_str(instance->file_path, SUBBRUTE_PATH); - - ValidatorIsFile* validator_is_file = validator_is_file_alloc_init( - furi_string_get_cstr(instance->file_path), SUBBRUTE_FILE_EXT, ""); - text_input_set_validator(text_input, validator_is_file_callback, validator_is_file); - - view_dispatcher_switch_to_view(instance->view_dispatcher, SubBruteViewTextInput); -} - -bool subbrute_scene_save_name_on_event(void* context, SceneManagerEvent event) { - SubBruteState* instance = (SubBruteState*)context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeBack) { - scene_manager_previous_scene(instance->scene_manager); - return true; - } else if( - event.type == SceneManagerEventTypeCustom && - event.event == SubBruteCustomEventTypeTextEditDone) { -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "Saving: %s", instance->text_store); -#endif - bool success = false; - if(strcmp(instance->text_store, "")) { - furi_string_reset(instance->file_path); - furi_string_cat_printf( - instance->file_path, - "%s/%s%s", - SUBBRUTE_PATH, - instance->text_store, - SUBBRUTE_FILE_EXT); - - if(subbrute_device_save_file( - instance->device, furi_string_get_cstr(instance->file_path))) { - scene_manager_next_scene(instance->scene_manager, SubBruteSceneSaveSuccess); - success = true; - consumed = true; - } - } - - if(!success) { - dialog_message_show_storage_error(instance->dialogs, "Error during saving!"); - consumed = scene_manager_search_and_switch_to_previous_scene( - instance->scene_manager, SubBruteSceneSetupAttack); - } - } - return consumed; -} - -void subbrute_scene_save_name_on_exit(void* context) { - SubBruteState* instance = (SubBruteState*)context; - - // Clear view - void* validator_context = text_input_get_validator_callback_context(instance->text_input); - text_input_set_validator(instance->text_input, NULL, NULL); - validator_is_file_free(validator_context); - - text_input_reset(instance->text_input); - - furi_string_reset(instance->file_path); -} diff --git a/applications/plugins/subbrute/scenes/subbrute_scene_save_success.c b/applications/plugins/subbrute/scenes/subbrute_scene_save_success.c deleted file mode 100644 index 20b1a0de4..000000000 --- a/applications/plugins/subbrute/scenes/subbrute_scene_save_success.c +++ /dev/null @@ -1,51 +0,0 @@ -#include "../subbrute_i.h" -#include "subbrute_scene.h" - -void subbrute_scene_save_success_on_enter(void* context) { - furi_assert(context); - SubBruteState* instance = context; - - // Setup view - Popup* popup = instance->popup; - popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); - popup_set_header(popup, "Saved!", 13, 22, AlignLeft, AlignBottom); - popup_set_timeout(popup, 1500); - popup_set_context(popup, instance); - popup_set_callback(popup, subbrute_popup_closed_callback); - popup_enable_timeout(popup); - view_dispatcher_switch_to_view(instance->view_dispatcher, SubBruteViewPopup); -} - -bool subbrute_scene_save_success_on_event(void* context, SceneManagerEvent event) { - furi_assert(context); - - SubBruteState* instance = (SubBruteState*)context; - //SubBruteMainView* view = instance->view_main; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == SubBruteCustomEventTypePopupClosed) { - if(!scene_manager_search_and_switch_to_previous_scene( - instance->scene_manager, SubBruteSceneSetupAttack)) { - scene_manager_next_scene(instance->scene_manager, SubBruteSceneStart); - } - return true; - } - } - return false; -} - -void subbrute_scene_save_success_on_exit(void* context) { - furi_assert(context); - - SubBruteState* instance = (SubBruteState*)context; - - // Clear view - Popup* popup = instance->popup; - popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom); - popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop); - popup_set_icon(popup, 0, 0, NULL); - popup_set_callback(popup, NULL); - popup_set_context(popup, NULL); - popup_set_timeout(popup, 0); - popup_disable_timeout(popup); -} diff --git a/applications/plugins/subbrute/scenes/subbrute_scene_setup_attack.c b/applications/plugins/subbrute/scenes/subbrute_scene_setup_attack.c deleted file mode 100644 index c2877c7cb..000000000 --- a/applications/plugins/subbrute/scenes/subbrute_scene_setup_attack.c +++ /dev/null @@ -1,138 +0,0 @@ -#include "../subbrute_i.h" -#include "subbrute_scene.h" - -#define TAG "SubBruteSceneSetupAttack" - -static void subbrute_scene_setup_attack_callback(SubBruteCustomEvent event, void* context) { - furi_assert(context); - - SubBruteState* instance = (SubBruteState*)context; - view_dispatcher_send_custom_event(instance->view_dispatcher, event); -} - -static void - subbrute_scene_setup_attack_device_state_changed(void* context, SubBruteWorkerState state) { - furi_assert(context); - - SubBruteState* instance = (SubBruteState*)context; - - if(state == SubBruteWorkerStateIDLE) { - // Can't be IDLE on this step! - view_dispatcher_send_custom_event(instance->view_dispatcher, SubBruteCustomEventTypeError); - } -} - -void subbrute_scene_setup_attack_on_enter(void* context) { - furi_assert(context); - SubBruteState* instance = (SubBruteState*)context; - SubBruteAttackView* view = instance->view_attack; - - notification_message(instance->notifications, &sequence_reset_vibro); - -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "Enter Attack: %s", subbrute_protocol_name(instance->device->attack)); -#endif - - subbrute_worker_set_callback( - instance->worker, subbrute_scene_setup_attack_device_state_changed, context); - if(subbrute_worker_is_running(instance->worker)) { - subbrute_worker_stop(instance->worker); - instance->device->current_step = subbrute_worker_get_step(instance->worker); - } - - subbrute_attack_view_init_values( - view, - instance->device->attack, - instance->device->max_value, - instance->device->current_step, - false, - instance->device->extra_repeats); - - instance->current_view = SubBruteViewAttack; - subbrute_attack_view_set_callback(view, subbrute_scene_setup_attack_callback, instance); - view_dispatcher_switch_to_view(instance->view_dispatcher, instance->current_view); -} - -void subbrute_scene_setup_attack_on_exit(void* context) { - furi_assert(context); -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "subbrute_scene_setup_attack_on_exit"); -#endif - SubBruteState* instance = (SubBruteState*)context; - subbrute_worker_stop(instance->worker); - notification_message(instance->notifications, &sequence_blink_stop); - notification_message(instance->notifications, &sequence_reset_vibro); -} - -bool subbrute_scene_setup_attack_on_event(void* context, SceneManagerEvent event) { - SubBruteState* instance = (SubBruteState*)context; - SubBruteAttackView* view = instance->view_attack; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == SubBruteCustomEventTypeTransmitStarted) { - scene_manager_next_scene(instance->scene_manager, SubBruteSceneRunAttack); - } else if(event.event == SubBruteCustomEventTypeSaveFile) { - subbrute_attack_view_init_values( - view, - instance->device->attack, - instance->device->max_value, - instance->device->current_step, - false, - instance->device->extra_repeats); - scene_manager_next_scene(instance->scene_manager, SubBruteSceneSaveName); - } else if(event.event == SubBruteCustomEventTypeBackPressed) { - subbrute_attack_view_init_values( - view, - instance->device->attack, - instance->device->max_value, - instance->device->current_step, - false, - instance->device->extra_repeats); - scene_manager_next_scene(instance->scene_manager, SubBruteSceneStart); - } else if(event.event == SubBruteCustomEventTypeError) { - notification_message(instance->notifications, &sequence_error); - } else if(event.event == SubBruteCustomEventTypeTransmitCustom) { - // We can transmit only in not working states - if(subbrute_worker_can_manual_transmit(instance->worker)) { - // MANUAL Transmit! - // Blink - notification_message(instance->notifications, &sequence_blink_green_100); - subbrute_worker_transmit_current_key( - instance->worker, instance->device->current_step); - // Stop - notification_message(instance->notifications, &sequence_blink_stop); - } - } else if(event.event == SubBruteCustomEventTypeChangeStepUp) { - // +1 - uint64_t step = subbrute_device_add_step(instance->device, 1); - subbrute_worker_set_step(instance->worker, step); - subbrute_attack_view_set_current_step(view, step); - } else if(event.event == SubBruteCustomEventTypeChangeStepUpMore) { - // +50 - uint64_t step = subbrute_device_add_step(instance->device, 50); - subbrute_worker_set_step(instance->worker, step); - subbrute_attack_view_set_current_step(view, step); - } else if(event.event == SubBruteCustomEventTypeChangeStepDown) { - // -1 - uint64_t step = subbrute_device_add_step(instance->device, -1); - subbrute_worker_set_step(instance->worker, step); - subbrute_attack_view_set_current_step(view, step); - } else if(event.event == SubBruteCustomEventTypeChangeStepDownMore) { - // -50 - uint64_t step = subbrute_device_add_step(instance->device, -50); - subbrute_worker_set_step(instance->worker, step); - subbrute_attack_view_set_current_step(view, step); - } - - consumed = true; - } else if(event.type == SceneManagerEventTypeTick) { - if(subbrute_worker_is_running(instance->worker)) { - instance->device->current_step = subbrute_worker_get_step(instance->worker); - } - subbrute_attack_view_set_current_step(view, instance->device->current_step); - consumed = true; - } - - return consumed; -} diff --git a/applications/plugins/subbrute/scenes/subbrute_scene_start.c b/applications/plugins/subbrute/scenes/subbrute_scene_start.c deleted file mode 100644 index 256762d92..000000000 --- a/applications/plugins/subbrute/scenes/subbrute_scene_start.c +++ /dev/null @@ -1,89 +0,0 @@ -#include "../subbrute_i.h" -#include "subbrute_scene.h" - -#define TAG "SubBruteSceneStart" - -void subbrute_scene_start_callback(SubBruteCustomEvent event, void* context) { - furi_assert(context); - - SubBruteState* instance = (SubBruteState*)context; -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "subbrute_scene_start_callback"); -#endif - view_dispatcher_send_custom_event(instance->view_dispatcher, event); -} - -void subbrute_scene_start_on_enter(void* context) { - furi_assert(context); -#ifdef FURI_DEBUG - FURI_LOG_I(TAG, "subbrute_scene_start_on_enter"); -#endif - SubBruteState* instance = (SubBruteState*)context; - SubBruteMainView* view = instance->view_main; - - instance->current_view = SubBruteViewMain; - subbrute_main_view_set_callback(view, subbrute_scene_start_callback, instance); - subbrute_main_view_set_index( - view, instance->device->attack, false, instance->device->two_bytes, 0); - - view_dispatcher_switch_to_view(instance->view_dispatcher, instance->current_view); - - // TODO: DELETE IT -#ifdef SUBBRUTE_FAST_TRACK - scene_manager_next_scene(instance->scene_manager, SubBruteSceneLoadFile); -#endif -} - -void subbrute_scene_start_on_exit(void* context) { - UNUSED(context); -#ifdef FURI_DEBUG - FURI_LOG_I(TAG, "subbrute_scene_start_on_exit"); -#endif -} - -bool subbrute_scene_start_on_event(void* context, SceneManagerEvent event) { - SubBruteState* instance = (SubBruteState*)context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { -#ifdef FURI_DEBUG - FURI_LOG_D( - TAG, - "Event: %ld, SubBruteCustomEventTypeMenuSelected: %s, SubBruteCustomEventTypeLoadFile: %s", - event.event, - event.event == SubBruteCustomEventTypeMenuSelected ? "true" : "false", - event.event == SubBruteCustomEventTypeLoadFile ? "true" : "false"); -#endif - if(event.event == SubBruteCustomEventTypeMenuSelected) { - SubBruteAttacks attack = subbrute_main_view_get_index(instance->view_main); - uint8_t extra_repeats = subbrute_main_view_get_extra_repeats(instance->view_main); - - if((subbrute_device_attack_set(instance->device, attack, extra_repeats) != - SubBruteFileResultOk) || - (!subbrute_worker_init_default_attack( - instance->worker, - attack, - instance->device->current_step, - instance->device->protocol_info, - instance->device->extra_repeats))) { - furi_crash("Invalid attack set!"); - } - scene_manager_next_scene(instance->scene_manager, SubBruteSceneSetupAttack); - - consumed = true; - } else if(event.event == SubBruteCustomEventTypeLoadFile) { - //uint8_t extra_repeats = subbrute_main_view_get_extra_repeats(instance->view_main); - - //instance->device->extra_repeats = extra_repeats; - scene_manager_next_scene(instance->scene_manager, SubBruteSceneLoadFile); - consumed = true; - } - } else if(event.type == SceneManagerEventTypeBack) { - //exit app - scene_manager_stop(instance->scene_manager); - view_dispatcher_stop(instance->view_dispatcher); - consumed = true; - } - - return consumed; -} \ No newline at end of file diff --git a/applications/plugins/subbrute/scenes/subbute_scene.c b/applications/plugins/subbrute/scenes/subbute_scene.c deleted file mode 100644 index 6d9ba9799..000000000 --- a/applications/plugins/subbrute/scenes/subbute_scene.c +++ /dev/null @@ -1,30 +0,0 @@ -#include "subbrute_scene.h" - -// Generate scene on_enter handlers array -#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter, -void (*const subbrute_on_enter_handlers[])(void*) = { -#include "subbrute_scene_config.h" -}; -#undef ADD_SCENE - -// Generate scene on_event handlers array -#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event, -bool (*const subbrute_on_event_handlers[])(void* context, SceneManagerEvent event) = { -#include "subbrute_scene_config.h" -}; -#undef ADD_SCENE - -// Generate scene on_exit handlers array -#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit, -void (*const subbrute_on_exit_handlers[])(void* context) = { -#include "subbrute_scene_config.h" -}; -#undef ADD_SCENE - -// Initialize scene handlers configuration structure -const SceneManagerHandlers subbrute_scene_handlers = { - .on_enter_handlers = subbrute_on_enter_handlers, - .on_event_handlers = subbrute_on_event_handlers, - .on_exit_handlers = subbrute_on_exit_handlers, - .scene_num = SubBruteSceneNum, -}; diff --git a/applications/plugins/subbrute/subbrute.c b/applications/plugins/subbrute/subbrute.c deleted file mode 100644 index aaab3aeb1..000000000 --- a/applications/plugins/subbrute/subbrute.c +++ /dev/null @@ -1,188 +0,0 @@ -#include "subbrute_i.h" -#include "subbrute_custom_event.h" -#include "scenes/subbrute_scene.h" - -#define TAG "SubBruteApp" - -static bool subbrute_custom_event_callback(void* context, uint32_t event) { - furi_assert(context); - SubBruteState* instance = context; - return scene_manager_handle_custom_event(instance->scene_manager, event); -} - -static bool subbrute_back_event_callback(void* context) { - furi_assert(context); - SubBruteState* instance = context; - return scene_manager_handle_back_event(instance->scene_manager); -} - -static void subbrute_tick_event_callback(void* context) { - furi_assert(context); - SubBruteState* instance = context; - scene_manager_handle_tick_event(instance->scene_manager); -} - -SubBruteState* subbrute_alloc() { - SubBruteState* instance = malloc(sizeof(SubBruteState)); - - memset(instance->text_store, 0, sizeof(instance->text_store)); - instance->file_path = furi_string_alloc(); - - instance->scene_manager = scene_manager_alloc(&subbrute_scene_handlers, instance); - instance->view_dispatcher = view_dispatcher_alloc(); - - instance->gui = furi_record_open(RECORD_GUI); - - view_dispatcher_enable_queue(instance->view_dispatcher); - view_dispatcher_set_event_callback_context(instance->view_dispatcher, instance); - view_dispatcher_set_custom_event_callback( - instance->view_dispatcher, subbrute_custom_event_callback); - view_dispatcher_set_navigation_event_callback( - instance->view_dispatcher, subbrute_back_event_callback); - view_dispatcher_set_tick_event_callback( - instance->view_dispatcher, subbrute_tick_event_callback, 100); - - //Dialog - instance->dialogs = furi_record_open(RECORD_DIALOGS); - - // Notifications - instance->notifications = furi_record_open(RECORD_NOTIFICATION); - - // Devices - instance->device = subbrute_device_alloc(); - - // SubBruteWorker - instance->worker = subbrute_worker_alloc(); - - // TextInput - instance->text_input = text_input_alloc(); - view_dispatcher_add_view( - instance->view_dispatcher, - SubBruteViewTextInput, - text_input_get_view(instance->text_input)); - - // Custom Widget - instance->widget = widget_alloc(); - view_dispatcher_add_view( - instance->view_dispatcher, SubBruteViewWidget, widget_get_view(instance->widget)); - - // Popup - instance->popup = popup_alloc(); - view_dispatcher_add_view( - instance->view_dispatcher, SubBruteViewPopup, popup_get_view(instance->popup)); - - // ViewStack - instance->view_stack = view_stack_alloc(); - view_dispatcher_add_view( - instance->view_dispatcher, SubBruteViewStack, view_stack_get_view(instance->view_stack)); - - // SubBruteMainView - instance->view_main = subbrute_main_view_alloc(); - view_dispatcher_add_view( - instance->view_dispatcher, - SubBruteViewMain, - subbrute_main_view_get_view(instance->view_main)); - - // SubBruteAttackView - instance->view_attack = subbrute_attack_view_alloc(); - view_dispatcher_add_view( - instance->view_dispatcher, - SubBruteViewAttack, - subbrute_attack_view_get_view(instance->view_attack)); - - //instance->flipper_format = flipper_format_string_alloc(); - //instance->environment = subghz_environment_alloc(); - - return instance; -} - -void subbrute_free(SubBruteState* instance) { - furi_assert(instance); - - // SubBruteWorker - subbrute_worker_stop(instance->worker); - subbrute_worker_free(instance->worker); - - // SubBruteDevice - subbrute_device_free(instance->device); - - // Notifications - notification_message(instance->notifications, &sequence_blink_stop); - furi_record_close(RECORD_NOTIFICATION); - instance->notifications = NULL; - - // View Main - view_dispatcher_remove_view(instance->view_dispatcher, SubBruteViewMain); - subbrute_main_view_free(instance->view_main); - - // View Attack - view_dispatcher_remove_view(instance->view_dispatcher, SubBruteViewAttack); - subbrute_attack_view_free(instance->view_attack); - - // TextInput - view_dispatcher_remove_view(instance->view_dispatcher, SubBruteViewTextInput); - text_input_free(instance->text_input); - - // Custom Widget - view_dispatcher_remove_view(instance->view_dispatcher, SubBruteViewWidget); - widget_free(instance->widget); - - // Popup - view_dispatcher_remove_view(instance->view_dispatcher, SubBruteViewPopup); - popup_free(instance->popup); - - // ViewStack - view_dispatcher_remove_view(instance->view_dispatcher, SubBruteViewStack); - view_stack_free(instance->view_stack); - - //Dialog - furi_record_close(RECORD_DIALOGS); - instance->dialogs = NULL; - - // Scene manager - scene_manager_free(instance->scene_manager); - - // View Dispatcher - view_dispatcher_free(instance->view_dispatcher); - - // GUI - furi_record_close(RECORD_GUI); - instance->gui = NULL; - - furi_string_free(instance->file_path); - - // The rest - free(instance); -} - -void subbrute_text_input_callback(void* context) { - furi_assert(context); - SubBruteState* instance = context; - view_dispatcher_send_custom_event( - instance->view_dispatcher, SubBruteCustomEventTypeTextEditDone); -} - -void subbrute_popup_closed_callback(void* context) { - furi_assert(context); - SubBruteState* instance = context; - view_dispatcher_send_custom_event( - instance->view_dispatcher, SubBruteCustomEventTypePopupClosed); -} - -// ENTRYPOINT -int32_t subbrute_app(void* p) { - UNUSED(p); - - SubBruteState* instance = subbrute_alloc(); - view_dispatcher_attach_to_gui( - instance->view_dispatcher, instance->gui, ViewDispatcherTypeFullscreen); - scene_manager_next_scene(instance->scene_manager, SubBruteSceneStart); - - furi_hal_power_suppress_charge_enter(); - notification_message(instance->notifications, &sequence_display_backlight_on); - view_dispatcher_run(instance->view_dispatcher); - furi_hal_power_suppress_charge_exit(); - subbrute_free(instance); - - return 0; -} \ No newline at end of file diff --git a/applications/plugins/subbrute/subbrute.h b/applications/plugins/subbrute/subbrute.h deleted file mode 100644 index 5fedb9158..000000000 --- a/applications/plugins/subbrute/subbrute.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -typedef struct SubBruteState SubBruteState; \ No newline at end of file diff --git a/applications/plugins/subbrute/subbrute_custom_event.h b/applications/plugins/subbrute/subbrute_custom_event.h deleted file mode 100644 index 2864f8934..000000000 --- a/applications/plugins/subbrute/subbrute_custom_event.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -typedef enum { - // Reserve first 100 events for button types and indexes, starting from 0 - SubBruteCustomEventTypeReserved = 100, - - SubBruteCustomEventTypeBackPressed, - SubBruteCustomEventTypeIndexSelected, - SubBruteCustomEventTypeTransmitStarted, - SubBruteCustomEventTypeError, - SubBruteCustomEventTypeTransmitFinished, - SubBruteCustomEventTypeTransmitNotStarted, - SubBruteCustomEventTypeTransmitCustom, - SubBruteCustomEventTypeSaveFile, - SubBruteCustomEventTypeUpdateView, - SubBruteCustomEventTypeChangeStepUp, - SubBruteCustomEventTypeChangeStepDown, - SubBruteCustomEventTypeChangeStepUpMore, - SubBruteCustomEventTypeChangeStepDownMore, - - SubBruteCustomEventTypeMenuSelected, - SubBruteCustomEventTypeTextEditDone, - SubBruteCustomEventTypePopupClosed, - - SubBruteCustomEventTypeLoadFile, -} SubBruteCustomEvent; \ No newline at end of file diff --git a/applications/plugins/subbrute/subbrute_device.c b/applications/plugins/subbrute/subbrute_device.c deleted file mode 100644 index 0971c380e..000000000 --- a/applications/plugins/subbrute/subbrute_device.c +++ /dev/null @@ -1,460 +0,0 @@ -#include "subbrute_device.h" - -#include -#include -#include -#include -#include -#include - -#define TAG "SubBruteDevice" - -SubBruteDevice* subbrute_device_alloc() { - SubBruteDevice* instance = malloc(sizeof(SubBruteDevice)); - - instance->current_step = 0; - - instance->protocol_info = NULL; - instance->file_protocol_info = NULL; - instance->decoder_result = NULL; - instance->receiver = NULL; - instance->environment = subghz_environment_alloc(); - subghz_environment_set_protocol_registry( - instance->environment, (void*)&subghz_protocol_registry); - -#ifdef FURI_DEBUG - subbrute_device_attack_set_default_values(instance, SubBruteAttackLoadFile); -#else - subbrute_device_attack_set_default_values(instance, SubBruteAttackCAME12bit433); -#endif - return instance; -} - -void subbrute_device_free(SubBruteDevice* instance) { - furi_assert(instance); - - // I don't know how to free this - instance->decoder_result = NULL; - - if(instance->receiver != NULL) { - subghz_receiver_free(instance->receiver); - instance->receiver = NULL; - } - - subghz_environment_free(instance->environment); - instance->environment = NULL; - - subbrute_device_free_protocol_info(instance); - - free(instance); -} - -uint64_t subbrute_device_add_step(SubBruteDevice* instance, int8_t step) { - if(step > 0) { - if((instance->current_step + step) - instance->max_value == 1) { - instance->current_step = 0x00; - } else { - uint64_t value = instance->current_step + step; - if(value == instance->max_value) { - instance->current_step = value; - } else { - instance->current_step = value % instance->max_value; - } - } - } else { - if(instance->current_step + step == 0) { - instance->current_step = 0x00; - } else if(instance->current_step == 0) { - instance->current_step = instance->max_value; - } else { - uint64_t value = ((instance->current_step + step) + instance->max_value); - if(value == instance->max_value) { - instance->current_step = value; - } else { - instance->current_step = value % instance->max_value; - } - } - } - - return instance->current_step; -} - -bool subbrute_device_save_file(SubBruteDevice* instance, const char* dev_file_name) { - furi_assert(instance); - -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "subbrute_device_save_file: %s", dev_file_name); -#endif - - Storage* storage = furi_record_open(RECORD_STORAGE); - FlipperFormat* file = flipper_format_file_alloc(storage); - bool result = false; - do { - if(!flipper_format_file_open_always(file, dev_file_name)) { - FURI_LOG_E(TAG, "Failed to open file: %s", dev_file_name); - break; - } - Stream* stream = flipper_format_get_raw_stream(file); - if(instance->attack == SubBruteAttackLoadFile) { - subbrute_protocol_file_generate_file( - stream, - instance->file_protocol_info->frequency, - instance->file_protocol_info->preset, - instance->file_protocol_info->file, - instance->current_step, - instance->file_protocol_info->bits, - instance->file_protocol_info->te, - instance->file_protocol_info->repeat, - instance->bit_index, - instance->key_from_file, - instance->two_bytes); - } else { - subbrute_protocol_default_generate_file( - stream, - instance->protocol_info->frequency, - instance->protocol_info->preset, - instance->protocol_info->file, - instance->current_step, - instance->protocol_info->bits, - instance->protocol_info->te, - instance->protocol_info->repeat); - } - - result = true; - } while(false); - - if(!result) { - FURI_LOG_E(TAG, "subbrute_device_save_file failed!"); - } - - flipper_format_file_close(file); - flipper_format_free(file); - furi_record_close(RECORD_STORAGE); - - return result; -} - -SubBruteFileResult subbrute_device_attack_set( - SubBruteDevice* instance, - SubBruteAttacks type, - uint8_t extra_repeats) { - furi_assert(instance); -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "subbrute_device_attack_set: %d, extra_repeats: %d", type, extra_repeats); -#endif - subbrute_device_attack_set_default_values(instance, type); - - if(type != SubBruteAttackLoadFile) { - subbrute_device_free_protocol_info(instance); - instance->protocol_info = subbrute_protocol(type); - } - - instance->extra_repeats = extra_repeats; - - // For non-file types we didn't set SubGhzProtocolDecoderBase - instance->receiver = subghz_receiver_alloc_init(instance->environment); - subghz_receiver_set_filter(instance->receiver, SubGhzProtocolFlag_Decodable); - furi_hal_subghz_reset(); - - uint8_t protocol_check_result = SubBruteFileResultProtocolNotFound; -#ifdef FURI_DEBUG - uint8_t bits; - uint32_t te; - uint8_t repeat; - FuriHalSubGhzPreset preset; - SubBruteFileProtocol file; -#endif - if(type != SubBruteAttackLoadFile) { - instance->decoder_result = subghz_receiver_search_decoder_base_by_name( - instance->receiver, subbrute_protocol_file(instance->protocol_info->file)); - - if(!instance->decoder_result || - instance->decoder_result->protocol->type == SubGhzProtocolTypeDynamic) { - FURI_LOG_E(TAG, "Can't load SubGhzProtocolDecoderBase in phase non-file decoder set"); - } else { - protocol_check_result = SubBruteFileResultOk; - - // Calc max value - instance->max_value = subbrute_protocol_calc_max_value( - instance->attack, instance->protocol_info->bits, instance->two_bytes); - } -#ifdef FURI_DEBUG - bits = instance->protocol_info->bits; - te = instance->protocol_info->te; - repeat = instance->protocol_info->repeat + instance->extra_repeats; - preset = instance->protocol_info->preset; - file = instance->protocol_info->file; -#endif - } else { - // And here we need to set preset enum - protocol_check_result = SubBruteFileResultOk; - - // Calc max value - instance->max_value = subbrute_protocol_calc_max_value( - instance->attack, instance->file_protocol_info->bits, instance->two_bytes); -#ifdef FURI_DEBUG - bits = instance->file_protocol_info->bits; - te = instance->file_protocol_info->te; - repeat = instance->file_protocol_info->repeat + instance->extra_repeats; - preset = instance->file_protocol_info->preset; - file = instance->file_protocol_info->file; -#endif - } - - subghz_receiver_free(instance->receiver); - instance->receiver = NULL; - - if(protocol_check_result != SubBruteFileResultOk) { - return SubBruteFileResultProtocolNotFound; - } - -#ifdef FURI_DEBUG - FURI_LOG_I( - TAG, - "subbrute_device_attack_set: %s, bits: %d, preset: %s, file: %s, te: %ld, repeat: %d, max_value: %lld", - subbrute_protocol_name(instance->attack), - bits, - subbrute_protocol_preset(preset), - subbrute_protocol_file(file), - te, - repeat, - instance->max_value); -#endif - - return SubBruteFileResultOk; -} - -uint8_t subbrute_device_load_from_file(SubBruteDevice* instance, const char* file_path) { - furi_assert(instance); -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "subbrute_device_load_from_file: %s", file_path); -#endif - SubBruteFileResult result = SubBruteFileResultUnknown; - - Storage* storage = furi_record_open(RECORD_STORAGE); - FlipperFormat* fff_data_file = flipper_format_file_alloc(storage); - - subbrute_device_free_protocol_info(instance); - instance->file_protocol_info = malloc(sizeof(SubBruteProtocol)); - - FuriString* temp_str; - temp_str = furi_string_alloc(); - uint32_t temp_data32; - - instance->receiver = subghz_receiver_alloc_init(instance->environment); - subghz_receiver_set_filter(instance->receiver, SubGhzProtocolFlag_Decodable); - furi_hal_subghz_reset(); - - do { - if(!flipper_format_file_open_existing(fff_data_file, file_path)) { - FURI_LOG_E(TAG, "Error open file %s", file_path); - result = SubBruteFileResultErrorOpenFile; - break; - } - if(!flipper_format_read_header(fff_data_file, temp_str, &temp_data32)) { - FURI_LOG_E(TAG, "Missing or incorrect header"); - result = SubBruteFileResultMissingOrIncorrectHeader; - break; - } - - // Frequency - if(!flipper_format_read_uint32(fff_data_file, "Frequency", &temp_data32, 1)) { - FURI_LOG_E(TAG, "Missing or incorrect Frequency"); - result = SubBruteFileResultMissingOrIncorrectFrequency; - break; - } - instance->file_protocol_info->frequency = temp_data32; - if(!furi_hal_subghz_is_tx_allowed(instance->file_protocol_info->frequency)) { - result = SubBruteFileResultFrequencyNotAllowed; - break; - } - - // Preset - if(!flipper_format_read_string(fff_data_file, "Preset", temp_str)) { - FURI_LOG_E(TAG, "Preset FAIL"); - result = SubBruteFileResultPresetInvalid; - break; - } - instance->file_protocol_info->preset = subbrute_protocol_convert_preset(temp_str); - - const char* protocol_file = NULL; - // Protocol - if(!flipper_format_read_string(fff_data_file, "Protocol", temp_str)) { - FURI_LOG_E(TAG, "Missing Protocol"); - result = SubBruteFileResultMissingProtocol; - break; - } - instance->file_protocol_info->file = subbrute_protocol_file_protocol_name(temp_str); - protocol_file = subbrute_protocol_file(instance->file_protocol_info->file); -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "Protocol: %s", protocol_file); -#endif - - instance->decoder_result = subghz_receiver_search_decoder_base_by_name( - instance->receiver, furi_string_get_cstr(temp_str)); - - if((!instance->decoder_result) || (strcmp(protocol_file, "RAW") == 0) || - (strcmp(protocol_file, "Unknown") == 0)) { - FURI_LOG_E(TAG, "Protocol unsupported"); - result = SubBruteFileResultProtocolNotSupported; - break; - } - - if(instance->decoder_result->protocol->type == SubGhzProtocolTypeDynamic) { - FURI_LOG_E(TAG, "Protocol is dynamic - not supported"); - result = SubBruteFileResultDynamicProtocolNotValid; - break; - } -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "Decoder: %s", instance->decoder_result->protocol->name); -#endif - - // Bit - if(!flipper_format_read_uint32(fff_data_file, "Bit", &temp_data32, 1)) { - FURI_LOG_E(TAG, "Missing or incorrect Bit"); - result = SubBruteFileResultMissingOrIncorrectBit; - break; - } - instance->file_protocol_info->bits = temp_data32; -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "Bit: %d", instance->file_protocol_info->bits); -#endif - - uint8_t key_data[sizeof(uint64_t)] = {0}; - if(!flipper_format_read_hex(fff_data_file, "Key", key_data, sizeof(uint64_t))) { - FURI_LOG_E(TAG, "Missing Key"); - result = SubBruteFileResultMissingOrIncorrectKey; - break; - } - uint64_t data = 0; - for(uint8_t i = 0; i < sizeof(uint64_t); i++) { - data = (data << 8) | key_data[i]; - } -#if FURI_DEBUG - FURI_LOG_D(TAG, "Key: %.16llX", data); -#endif - instance->key_from_file = data; - - // TE - if(!flipper_format_read_uint32(fff_data_file, "TE", &temp_data32, 1)) { - FURI_LOG_E(TAG, "Missing or incorrect TE"); - //result = SubBruteFileResultMissingOrIncorrectTe; - //break; - } else { - instance->file_protocol_info->te = temp_data32 != 0 ? temp_data32 : 0; - } - - // Repeat - if(flipper_format_read_uint32(fff_data_file, "Repeat", &temp_data32, 1)) { -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "Repeat: %ld", temp_data32); -#endif - instance->file_protocol_info->repeat = (uint8_t)temp_data32; - } else { -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "Repeat: 3 (default)"); -#endif - instance->file_protocol_info->repeat = 3; - } - - result = SubBruteFileResultOk; - } while(0); - - furi_string_free(temp_str); - flipper_format_file_close(fff_data_file); - flipper_format_free(fff_data_file); - furi_record_close(RECORD_STORAGE); - - subghz_receiver_free(instance->receiver); - - instance->decoder_result = NULL; - instance->receiver = NULL; - - if(result == SubBruteFileResultOk) { -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "Loaded successfully"); -#endif - } else { - subbrute_device_free_protocol_info(instance); - } - - return result; -} - -void subbrute_device_attack_set_default_values( - SubBruteDevice* instance, - SubBruteAttacks default_attack) { - furi_assert(instance); -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "subbrute_device_attack_set_default_values"); -#endif - instance->attack = default_attack; - instance->current_step = 0x00; - instance->bit_index = 0x00; - instance->extra_repeats = 0; - instance->two_bytes = false; - - if(default_attack != SubBruteAttackLoadFile) { - instance->max_value = subbrute_protocol_calc_max_value( - instance->attack, instance->bit_index, instance->two_bytes); - } -} - -const char* subbrute_device_error_get_desc(SubBruteFileResult error_id) { - const char* result; - switch(error_id) { - case(SubBruteFileResultOk): - result = "OK"; - break; - case(SubBruteFileResultErrorOpenFile): - result = "invalid name/path"; - break; - case(SubBruteFileResultMissingOrIncorrectHeader): - result = "Missing or incorrect header"; - break; - case(SubBruteFileResultFrequencyNotAllowed): - result = "Invalid frequency!"; - break; - case(SubBruteFileResultMissingOrIncorrectFrequency): - result = "Missing or incorrect Frequency"; - break; - case(SubBruteFileResultPresetInvalid): - result = "Preset FAIL"; - break; - case(SubBruteFileResultMissingProtocol): - result = "Missing Protocol"; - break; - case(SubBruteFileResultProtocolNotSupported): - result = "Protocol unsupported"; - break; - case(SubBruteFileResultDynamicProtocolNotValid): - result = "Dynamic protocol unsupported"; - break; - case(SubBruteFileResultProtocolNotFound): - result = "Protocol not found"; - break; - case(SubBruteFileResultMissingOrIncorrectBit): - result = "Missing or incorrect Bit"; - break; - case(SubBruteFileResultMissingOrIncorrectKey): - result = "Missing or incorrect Key"; - break; - case(SubBruteFileResultMissingOrIncorrectTe): - result = "Missing or incorrect TE"; - break; - case SubBruteFileResultUnknown: - default: - result = "Unknown error"; - break; - } - return result; -} - -void subbrute_device_free_protocol_info(SubBruteDevice* instance) { - furi_assert(instance); - instance->protocol_info = NULL; - if(instance->file_protocol_info) { - free(instance->file_protocol_info); - } - instance->file_protocol_info = NULL; -} \ No newline at end of file diff --git a/applications/plugins/subbrute/subbrute_device.h b/applications/plugins/subbrute/subbrute_device.h deleted file mode 100644 index 7ff650e93..000000000 --- a/applications/plugins/subbrute/subbrute_device.h +++ /dev/null @@ -1,75 +0,0 @@ -#pragma once - -#include "subbrute_protocols.h" -#include -#include -#include -#include - -#define SUBBRUTE_TEXT_STORE_SIZE 256 - -#define SUBBRUTE_MAX_LEN_NAME 64 -#define SUBBRUTE_PATH EXT_PATH("subghz") -#define SUBBRUTE_FILE_EXT ".sub" - -#define SUBBRUTE_PAYLOAD_SIZE 16 - -typedef enum { - SubBruteFileResultUnknown, - SubBruteFileResultOk, - SubBruteFileResultErrorOpenFile, - SubBruteFileResultMissingOrIncorrectHeader, - SubBruteFileResultFrequencyNotAllowed, - SubBruteFileResultMissingOrIncorrectFrequency, - SubBruteFileResultPresetInvalid, - SubBruteFileResultMissingProtocol, - SubBruteFileResultProtocolNotSupported, - SubBruteFileResultDynamicProtocolNotValid, - SubBruteFileResultProtocolNotFound, - SubBruteFileResultMissingOrIncorrectBit, - SubBruteFileResultMissingOrIncorrectKey, - SubBruteFileResultMissingOrIncorrectTe, -} SubBruteFileResult; - -typedef struct { - const SubBruteProtocol* protocol_info; - SubBruteProtocol* file_protocol_info; - - // Current step - uint64_t current_step; - - // SubGhz - SubGhzReceiver* receiver; - SubGhzProtocolDecoderBase* decoder_result; - SubGhzEnvironment* environment; - - // Attack state - SubBruteAttacks attack; - uint64_t max_value; - uint8_t extra_repeats; - - // Loaded info for attack type - uint64_t key_from_file; - uint64_t current_key_from_file; - bool two_bytes; - // Index of group to bruteforce in loaded file - uint8_t bit_index; -} SubBruteDevice; - -SubBruteDevice* subbrute_device_alloc(); -void subbrute_device_free(SubBruteDevice* instance); - -bool subbrute_device_save_file(SubBruteDevice* instance, const char* key_name); -const char* subbrute_device_error_get_desc(SubBruteFileResult error_id); -SubBruteFileResult subbrute_device_attack_set( - SubBruteDevice* context, - SubBruteAttacks type, - uint8_t extra_repeats); -uint8_t subbrute_device_load_from_file(SubBruteDevice* context, const char* file_path); - -uint64_t subbrute_device_add_step(SubBruteDevice* instance, int8_t step); - -void subbrute_device_free_protocol_info(SubBruteDevice* instance); -void subbrute_device_attack_set_default_values( - SubBruteDevice* context, - SubBruteAttacks default_attack); \ No newline at end of file diff --git a/applications/plugins/subbrute/subbrute_i.h b/applications/plugins/subbrute/subbrute_i.h deleted file mode 100644 index eff9a9075..000000000 --- a/applications/plugins/subbrute/subbrute_i.h +++ /dev/null @@ -1,80 +0,0 @@ -#pragma once - -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "SubGHz_Bruteforcer_icons.h" - -#include - -#include -#include - -#include "subbrute.h" -#include "subbrute_device.h" -#include "helpers/subbrute_worker.h" -#include "views/subbrute_attack_view.h" -#include "views/subbrute_main_view.h" - -#define SUBBRUTEFORCER_VER "Sub-GHz BruteForcer 3.4" - -#ifdef FURI_DEBUG -//#define SUBBRUTE_FAST_TRACK false -#endif - -typedef enum { - SubBruteViewNone, - SubBruteViewMain, - SubBruteViewAttack, - SubBruteViewTextInput, - SubBruteViewDialogEx, - SubBruteViewPopup, - SubBruteViewWidget, - SubBruteViewStack, -} SubBruteView; - -struct SubBruteState { - // GUI elements - NotificationApp* notifications; - Gui* gui; - ViewDispatcher* view_dispatcher; - ViewStack* view_stack; - TextInput* text_input; - Popup* popup; - Widget* widget; - DialogsApp* dialogs; - - // Text store - char text_store[SUBBRUTE_MAX_LEN_NAME]; - FuriString* file_path; - - // Views - SubBruteMainView* view_main; - SubBruteAttackView* view_attack; - SubBruteView current_view; - - // Scene - SceneManager* scene_manager; - - // SubBruteDevice - SubBruteDevice* device; - // SubBruteWorker - SubBruteWorker* worker; -}; - -void subbrute_show_loading_popup(void* context, bool show); -void subbrute_text_input_callback(void* context); -void subbrute_popup_closed_callback(void* context); \ No newline at end of file diff --git a/applications/plugins/subbrute/subbrute_protocols.c b/applications/plugins/subbrute/subbrute_protocols.c deleted file mode 100644 index d3a4826b8..000000000 --- a/applications/plugins/subbrute/subbrute_protocols.c +++ /dev/null @@ -1,815 +0,0 @@ -#include "subbrute_protocols.h" -#include "math.h" -#include - -#define TAG "SubBruteProtocols" - -/** - * CAME 12bit 303MHz - */ -const SubBruteProtocol subbrute_protocol_came_12bit_303 = { - .frequency = 303875000, - .bits = 12, - .te = 0, - .repeat = 3, - .preset = FuriHalSubGhzPresetOok650Async, - .file = CAMEFileProtocol}; - -/** - * CAME 12bit 307MHz - */ -const SubBruteProtocol subbrute_protocol_came_12bit_307 = { - .frequency = 307800000, - .bits = 12, - .te = 0, - .repeat = 3, - .preset = FuriHalSubGhzPresetOok650Async, - .file = CAMEFileProtocol}; - -/** - * CAME 12bit 315MHz - */ -const SubBruteProtocol subbrute_protocol_came_12bit_315 = { - .frequency = 315000000, - .bits = 12, - .te = 0, - .repeat = 3, - .preset = FuriHalSubGhzPresetOok650Async, - .file = CAMEFileProtocol}; - -/** - * CAME 12bit 433MHz - */ -const SubBruteProtocol subbrute_protocol_came_12bit_433 = { - .frequency = 433920000, - .bits = 12, - .te = 0, - .repeat = 3, - .preset = FuriHalSubGhzPresetOok650Async, - .file = CAMEFileProtocol}; - -/** - * CAME 12bit 868MHz - */ -const SubBruteProtocol subbrute_protocol_came_12bit_868 = { - .frequency = 868350000, - .bits = 12, - .te = 0, - .repeat = 3, - .preset = FuriHalSubGhzPresetOok650Async, - .file = CAMEFileProtocol}; - -/** - * NICE 12bit 433MHz - */ -const SubBruteProtocol subbrute_protocol_nice_12bit_433 = { - .frequency = 433920000, - .bits = 12, - .te = 0, - .repeat = 3, - .preset = FuriHalSubGhzPresetOok650Async, - .file = NICEFileProtocol}; - -/** - * NICE 12bit 868MHz - */ -const SubBruteProtocol subbrute_protocol_nice_12bit_868 = { - .frequency = 868350000, - .bits = 12, - .te = 0, - .repeat = 3, - .preset = FuriHalSubGhzPresetOok650Async, - .file = NICEFileProtocol}; - -/** - * Ansonic 12bit 433.075MHz - */ -const SubBruteProtocol subbrute_protocol_ansonic_12bit_433075 = { - .frequency = 433075000, - .bits = 12, - .te = 0, - .repeat = 3, - .preset = FuriHalSubGhzPreset2FSKDev238Async, - .file = AnsonicFileProtocol}; - -/** - * Ansonic 12bit 433.92MHz - */ -const SubBruteProtocol subbrute_protocol_ansonic_12bit_433 = { - .frequency = 433920000, - .bits = 12, - .te = 0, - .repeat = 3, - .preset = FuriHalSubGhzPreset2FSKDev238Async, - .file = AnsonicFileProtocol}; - -/** - * Ansonic 12bit 434.075MHz - */ -const SubBruteProtocol subbrute_protocol_ansonic_12bit_434 = { - .frequency = 434075000, - .bits = 12, - .te = 0, - .repeat = 3, - .preset = FuriHalSubGhzPreset2FSKDev238Async, - .file = AnsonicFileProtocol}; - -/** - * Chamberlain 9bit 300MHz - */ -const SubBruteProtocol subbrute_protocol_chamberlain_9bit_300 = { - .frequency = 300000000, - .bits = 9, - .te = 0, - .repeat = 3, - .preset = FuriHalSubGhzPresetOok650Async, - .file = ChamberlainFileProtocol}; - -/** - * Chamberlain 9bit 315MHz - */ -const SubBruteProtocol subbrute_protocol_chamberlain_9bit_315 = { - .frequency = 315000000, - .bits = 9, - .te = 0, - .repeat = 3, - .preset = FuriHalSubGhzPresetOok650Async, - .file = ChamberlainFileProtocol}; - -/** - * Chamberlain 9bit 390MHz - */ -const SubBruteProtocol subbrute_protocol_chamberlain_9bit_390 = { - .frequency = 390000000, - .bits = 9, - .te = 0, - .repeat = 3, - .preset = FuriHalSubGhzPresetOok650Async, - .file = ChamberlainFileProtocol}; - -/** - * Chamberlain 9bit 433MHz - */ -const SubBruteProtocol subbrute_protocol_chamberlain_9bit_433 = { - .frequency = 433920000, - .bits = 9, - .te = 0, - .repeat = 3, - .preset = FuriHalSubGhzPresetOok650Async, - .file = ChamberlainFileProtocol}; - -/** - * Chamberlain 8bit 300MHz - */ -const SubBruteProtocol subbrute_protocol_chamberlain_8bit_300 = { - .frequency = 300000000, - .bits = 8, - .te = 0, - .repeat = 3, - .preset = FuriHalSubGhzPresetOok650Async, - .file = ChamberlainFileProtocol}; - -/** - * Chamberlain 8bit 315MHz - */ -const SubBruteProtocol subbrute_protocol_chamberlain_8bit_315 = { - .frequency = 315000000, - .bits = 8, - .te = 0, - .repeat = 3, - .preset = FuriHalSubGhzPresetOok650Async, - .file = ChamberlainFileProtocol}; - -/** - * Chamberlain 8bit 390MHz - */ -const SubBruteProtocol subbrute_protocol_chamberlain_8bit_390 = { - .frequency = 390000000, - .bits = 8, - .te = 0, - .repeat = 3, - .preset = FuriHalSubGhzPresetOok650Async, - .file = ChamberlainFileProtocol}; - -/** - * Chamberlain 7bit 300MHz - */ -const SubBruteProtocol subbrute_protocol_chamberlain_7bit_300 = { - .frequency = 300000000, - .bits = 7, - .te = 0, - .repeat = 3, - .preset = FuriHalSubGhzPresetOok650Async, - .file = ChamberlainFileProtocol}; - -/** - * Chamberlain 7bit 315MHz - */ -const SubBruteProtocol subbrute_protocol_chamberlain_7bit_315 = { - .frequency = 315000000, - .bits = 7, - .te = 0, - .repeat = 3, - .preset = FuriHalSubGhzPresetOok650Async, - .file = ChamberlainFileProtocol}; - -/** - * Chamberlain 7bit 390MHz - */ -const SubBruteProtocol subbrute_protocol_chamberlain_7bit_390 = { - .frequency = 390000000, - .bits = 7, - .te = 0, - .repeat = 3, - .preset = FuriHalSubGhzPresetOok650Async, - .file = ChamberlainFileProtocol}; - -/** - * Linear 10bit 300MHz - */ -const SubBruteProtocol subbrute_protocol_linear_10bit_300 = { - .frequency = 300000000, - .bits = 10, - .te = 0, - .repeat = 5, - .preset = FuriHalSubGhzPresetOok650Async, - .file = LinearFileProtocol}; - -/** - * Linear 10bit 310MHz - */ -const SubBruteProtocol subbrute_protocol_linear_10bit_310 = { - .frequency = 310000000, - .bits = 10, - .te = 0, - .repeat = 5, - .preset = FuriHalSubGhzPresetOok650Async, - .file = LinearFileProtocol}; - -/** - * UNILARM 24bit 330MHz - */ -const SubBruteProtocol subbrute_protocol_unilarm_24bit_330 = { - .frequency = 330000000, - .bits = 25, - .te = 209, - .repeat = 5, - .preset = FuriHalSubGhzPresetOok650Async, - .file = UNILARMFileProtocol}; - -/** - * UNILARM 24bit 433MHz - */ -const SubBruteProtocol subbrute_protocol_unilarm_24bit_433 = { - .frequency = 433920000, - .bits = 25, - .te = 209, - .repeat = 5, - .preset = FuriHalSubGhzPresetOok650Async, - .file = UNILARMFileProtocol}; - -/** - * SMC5326 24bit 330MHz - */ -const SubBruteProtocol subbrute_protocol_smc5326_24bit_330 = { - .frequency = 330000000, - .bits = 25, - .te = 320, - .repeat = 5, - .preset = FuriHalSubGhzPresetOok650Async, - .file = SMC5326FileProtocol}; - -/** - * SMC5326 24bit 433MHz - */ -const SubBruteProtocol subbrute_protocol_smc5326_24bit_433 = { - .frequency = 433920000, - .bits = 25, - .te = 320, - .repeat = 5, - .preset = FuriHalSubGhzPresetOok650Async, - .file = SMC5326FileProtocol}; - -/** - * PT2260 (Princeton) 24bit 315MHz - */ -const SubBruteProtocol subbrute_protocol_pt2260_24bit_315 = { - .frequency = 315000000, - .bits = 24, - .te = 286, - .repeat = 5, - .preset = FuriHalSubGhzPresetOok650Async, - .file = PT2260FileProtocol}; - -/** - * PT2260 (Princeton) 24bit 330MHz - */ -const SubBruteProtocol subbrute_protocol_pt2260_24bit_330 = { - .frequency = 330000000, - .bits = 24, - .te = 286, - .repeat = 5, - .preset = FuriHalSubGhzPresetOok650Async, - .file = PT2260FileProtocol}; - -/** - * PT2260 (Princeton) 24bit 390MHz - */ -const SubBruteProtocol subbrute_protocol_pt2260_24bit_390 = { - .frequency = 390000000, - .bits = 24, - .te = 286, - .repeat = 5, - .preset = FuriHalSubGhzPresetOok650Async, - .file = PT2260FileProtocol}; - -/** - * PT2260 (Princeton) 24bit 433MHz - */ -const SubBruteProtocol subbrute_protocol_pt2260_24bit_433 = { - .frequency = 433920000, - .bits = 24, - .te = 286, - .repeat = 5, - .preset = FuriHalSubGhzPresetOok650Async, - .file = PT2260FileProtocol}; - -/** - * Holtek FM 12bit 433MHz - */ -const SubBruteProtocol subbrute_protocol_holtek_12bit_433 = { - .frequency = 433920000, - .bits = 12, - .te = 204, - .repeat = 4, - .preset = FuriHalSubGhzPreset2FSKDev476Async, - .file = HoltekFileProtocol}; - -/** - * BF existing dump - */ -const SubBruteProtocol subbrute_protocol_load_file = - {0, 0, 0, 3, FuriHalSubGhzPresetOok650Async, UnknownFileProtocol}; - -static const char* subbrute_protocol_names[] = { - [SubBruteAttackCAME12bit303] = "CAME 12bit 303MHz", - [SubBruteAttackCAME12bit307] = "CAME 12bit 307MHz", - [SubBruteAttackCAME12bit315] = "CAME 12bit 315MHz", - [SubBruteAttackCAME12bit433] = "CAME 12bit 433MHz", - [SubBruteAttackCAME12bit868] = "CAME 12bit 868MHz", - [SubBruteAttackNICE12bit433] = "NICE 12bit 433MHz", - [SubBruteAttackNICE12bit868] = "NICE 12bit 868MHz", - [SubBruteAttackAnsonic12bit433075] = "Ansonic 12bit 433.07MHz", - [SubBruteAttackAnsonic12bit433] = "Ansonic 12bit 433.92MHz", - [SubBruteAttackAnsonic12bit434] = "Ansonic 12bit 434.07MHz", - [SubBruteAttackHoltek12bit433] = "Holtek FM 12bit 433MHz", - [SubBruteAttackChamberlain9bit300] = "Chamberlain 9bit 300MHz", - [SubBruteAttackChamberlain9bit315] = "Chamberlain 9bit 315MHz", - [SubBruteAttackChamberlain9bit390] = "Chamberlain 9bit 390MHz", - [SubBruteAttackChamberlain9bit433] = "Chamberlain 9bit 433MHz", - [SubBruteAttackChamberlain8bit300] = "Chamberlain 8bit 300MHz", - [SubBruteAttackChamberlain8bit315] = "Chamberlain 8bit 315MHz", - [SubBruteAttackChamberlain8bit390] = "Chamberlain 8bit 390MHz", - [SubBruteAttackChamberlain7bit300] = "Chamberlain 7bit 300MHz", - [SubBruteAttackChamberlain7bit315] = "Chamberlain 7bit 315MHz", - [SubBruteAttackChamberlain7bit390] = "Chamberlain 7bit 390MHz", - [SubBruteAttackLinear10bit300] = "Linear 10bit 300MHz", - [SubBruteAttackLinear10bit310] = "Linear 10bit 310MHz", - [SubBruteAttackUNILARM24bit330] = "UNILARM 25bit 330MHz", - [SubBruteAttackUNILARM24bit433] = "UNILARM 25bit 433MHz", - [SubBruteAttackSMC532624bit330] = "SMC5326 25bit 330MHz", - [SubBruteAttackSMC532624bit433] = "SMC5326 25bit 433MHz", - [SubBruteAttackPT226024bit315] = "PT2260 24bit 315MHz", - [SubBruteAttackPT226024bit330] = "PT2260 24bit 330MHz", - [SubBruteAttackPT226024bit390] = "PT2260 24bit 390MHz", - [SubBruteAttackPT226024bit433] = "PT2260 24bit 433MHz", - [SubBruteAttackLoadFile] = "BF existing dump", - [SubBruteAttackTotalCount] = "Total Count", -}; - -static const char* subbrute_protocol_presets[] = { - [FuriHalSubGhzPresetIDLE] = "FuriHalSubGhzPresetIDLE", - [FuriHalSubGhzPresetOok270Async] = "FuriHalSubGhzPresetOok270Async", - [FuriHalSubGhzPresetOok650Async] = "FuriHalSubGhzPresetOok650Async", - [FuriHalSubGhzPreset2FSKDev238Async] = "FuriHalSubGhzPreset2FSKDev238Async", - [FuriHalSubGhzPreset2FSKDev476Async] = "FuriHalSubGhzPreset2FSKDev476Async", - [FuriHalSubGhzPresetMSK99_97KbAsync] = "FuriHalSubGhzPresetMSK99_97KbAsync", - [FuriHalSubGhzPresetGFSK9_99KbAsync] = "FuriHalSubGhzPresetGFSK9_99KbAsync", -}; - -const SubBruteProtocol* subbrute_protocol_registry[] = { - [SubBruteAttackCAME12bit303] = &subbrute_protocol_came_12bit_303, - [SubBruteAttackCAME12bit307] = &subbrute_protocol_came_12bit_307, - [SubBruteAttackCAME12bit315] = &subbrute_protocol_came_12bit_315, - [SubBruteAttackCAME12bit433] = &subbrute_protocol_came_12bit_433, - [SubBruteAttackCAME12bit868] = &subbrute_protocol_came_12bit_868, - [SubBruteAttackNICE12bit433] = &subbrute_protocol_nice_12bit_433, - [SubBruteAttackNICE12bit868] = &subbrute_protocol_nice_12bit_868, - [SubBruteAttackAnsonic12bit433075] = &subbrute_protocol_ansonic_12bit_433075, - [SubBruteAttackAnsonic12bit433] = &subbrute_protocol_ansonic_12bit_433, - [SubBruteAttackAnsonic12bit434] = &subbrute_protocol_ansonic_12bit_434, - [SubBruteAttackHoltek12bit433] = &subbrute_protocol_holtek_12bit_433, - [SubBruteAttackChamberlain9bit300] = &subbrute_protocol_chamberlain_9bit_300, - [SubBruteAttackChamberlain9bit315] = &subbrute_protocol_chamberlain_9bit_315, - [SubBruteAttackChamberlain9bit390] = &subbrute_protocol_chamberlain_9bit_390, - [SubBruteAttackChamberlain9bit433] = &subbrute_protocol_chamberlain_9bit_433, - [SubBruteAttackChamberlain8bit300] = &subbrute_protocol_chamberlain_8bit_300, - [SubBruteAttackChamberlain8bit315] = &subbrute_protocol_chamberlain_8bit_315, - [SubBruteAttackChamberlain8bit390] = &subbrute_protocol_chamberlain_8bit_390, - [SubBruteAttackChamberlain7bit300] = &subbrute_protocol_chamberlain_7bit_300, - [SubBruteAttackChamberlain7bit315] = &subbrute_protocol_chamberlain_7bit_315, - [SubBruteAttackChamberlain7bit390] = &subbrute_protocol_chamberlain_7bit_390, - [SubBruteAttackLinear10bit300] = &subbrute_protocol_linear_10bit_300, - [SubBruteAttackLinear10bit310] = &subbrute_protocol_linear_10bit_310, - [SubBruteAttackUNILARM24bit330] = &subbrute_protocol_unilarm_24bit_330, - [SubBruteAttackUNILARM24bit433] = &subbrute_protocol_unilarm_24bit_433, - [SubBruteAttackSMC532624bit330] = &subbrute_protocol_smc5326_24bit_330, - [SubBruteAttackSMC532624bit433] = &subbrute_protocol_smc5326_24bit_433, - [SubBruteAttackPT226024bit315] = &subbrute_protocol_pt2260_24bit_315, - [SubBruteAttackPT226024bit330] = &subbrute_protocol_pt2260_24bit_330, - [SubBruteAttackPT226024bit390] = &subbrute_protocol_pt2260_24bit_390, - [SubBruteAttackPT226024bit433] = &subbrute_protocol_pt2260_24bit_433, - [SubBruteAttackLoadFile] = &subbrute_protocol_load_file}; - -static const char* subbrute_protocol_file_types[] = { - [CAMEFileProtocol] = "CAME", - [NICEFileProtocol] = "Nice FLO", - [ChamberlainFileProtocol] = "Cham_Code", - [LinearFileProtocol] = "Linear", - [PrincetonFileProtocol] = "Princeton", - [RAWFileProtocol] = "RAW", - [BETTFileProtocol] = "BETT", - [ClemsaFileProtocol] = "Clemsa", - [DoitrandFileProtocol] = "Doitrand", - [GateTXFileProtocol] = "GateTX", - [MagellanFileProtocol] = "Magellan", - [IntertechnoV3FileProtocol] = "Intertechno_V3", - [AnsonicFileProtocol] = "Ansonic", - [SMC5326FileProtocol] = "SMC5326", - [UNILARMFileProtocol] = "SMC5326", - [PT2260FileProtocol] = "Princeton", - [HoneywellFileProtocol] = "Honeywell", - [HoltekFileProtocol] = "Holtek_HT12X", - [UnknownFileProtocol] = "Unknown"}; - -/** - * Values to not use less memory for packet parse operations - */ -static const char* subbrute_key_file_start_no_tail = - "Filetype: Flipper SubGhz Key File\nVersion: 1\nFrequency: %u\nPreset: %s\nProtocol: %s\nBit: %d\nKey: %s\nRepeat: %d\n"; -static const char* subbrute_key_file_start_with_tail = - "Filetype: Flipper SubGhz Key File\nVersion: 1\nFrequency: %u\nPreset: %s\nProtocol: %s\nBit: %d\nKey: %s\nTE: %d\nRepeat: %d\n"; -static const char* subbrute_key_small_no_tail = "Bit: %d\nKey: %s\nRepeat: %d\n"; -//static const char* subbrute_key_small_raw = -// "Filetype: Flipper SubGhz Key File\nVersion: 1\nFrequency: %u\nPreset: %s\nProtocol: %s\nBit: %d\n"; -static const char* subbrute_key_small_with_tail = "Bit: %d\nKey: %s\nTE: %d\nRepeat: %d\n"; - -const char* subbrute_protocol_name(SubBruteAttacks index) { - return subbrute_protocol_names[index]; -} - -const SubBruteProtocol* subbrute_protocol(SubBruteAttacks index) { - return subbrute_protocol_registry[index]; -} - -uint8_t subbrute_protocol_repeats_count(SubBruteAttacks index) { - return subbrute_protocol_registry[index]->repeat; -} - -const char* subbrute_protocol_preset(FuriHalSubGhzPreset preset) { - return subbrute_protocol_presets[preset]; -} - -const char* subbrute_protocol_file(SubBruteFileProtocol protocol) { - return subbrute_protocol_file_types[protocol]; -} - -FuriHalSubGhzPreset subbrute_protocol_convert_preset(FuriString* preset_name) { - for(size_t i = FuriHalSubGhzPresetIDLE; i < FuriHalSubGhzPresetCustom; i++) { - if(furi_string_cmp_str(preset_name, subbrute_protocol_presets[i]) == 0) { - return i; - } - } - - return FuriHalSubGhzPresetIDLE; -} - -SubBruteFileProtocol subbrute_protocol_file_protocol_name(FuriString* name) { - for(size_t i = CAMEFileProtocol; i < TotalFileProtocol - 1; i++) { - if(furi_string_cmp_str(name, subbrute_protocol_file_types[i]) == 0) { - return i; - } - } - - return UnknownFileProtocol; -} - -void subbrute_protocol_create_candidate_for_existing_file( - FuriString* candidate, - uint64_t step, - uint8_t bit_index, - uint64_t file_key, - bool two_bytes) { - uint8_t p[8]; - for(int i = 0; i < 8; i++) { - p[i] = (uint8_t)(file_key >> 8 * (7 - i)) & 0xFF; - } - uint8_t low_byte = step & (0xff); - uint8_t high_byte = (step >> 8) & 0xff; - - size_t size = sizeof(uint64_t); - for(uint8_t i = 0; i < size; i++) { - if(i == bit_index - 1 && two_bytes) { - furi_string_cat_printf(candidate, "%02X %02X", high_byte, low_byte); - i++; - } else if(i == bit_index) { - furi_string_cat_printf(candidate, "%02X", low_byte); - } else if(p[i] != 0) { - furi_string_cat_printf(candidate, "%02X", p[i]); - } else { - furi_string_cat_printf(candidate, "%s", "00"); - } - - if(i < size - 1) { - furi_string_push_back(candidate, ' '); - } - } - -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "file candidate: %s, step: %lld", furi_string_get_cstr(candidate), step); -#endif -} - -void subbrute_protocol_create_candidate_for_default( - FuriString* candidate, - SubBruteFileProtocol file, - uint64_t step) { - uint8_t p[8]; - if(file == SMC5326FileProtocol) { - const uint8_t lut[] = {0x00, 0x02, 0x03}; // 00, 10, 11 - const uint64_t gate1 = 0x01D5; // 111010101 - //const uint8_t gate2 = 0x0175; // 101110101 - - uint64_t total = 0; - for(size_t j = 0; j < 8; j++) { - total |= lut[step % 3] << (2 * j); - double sub_step = step / 3; - step = (uint64_t)floor(sub_step); - } - total <<= 9; - total |= gate1; - - for(int i = 0; i < 8; i++) { - p[i] = (uint8_t)(total >> 8 * (7 - i)) & 0xFF; - } - } else if(file == UNILARMFileProtocol) { - const uint8_t lut[] = {0x00, 0x02, 0x03}; // 00, 10, 11 - const uint64_t gate1 = 3 << 7; - //const uint8_t gate2 = 3 << 5; - - uint64_t total = 0; - for(size_t j = 0; j < 8; j++) { - total |= lut[step % 3] << (2 * j); - double sub_step = step / 3; - step = (uint64_t)floor(sub_step); - } - total <<= 9; - total |= gate1; - - for(int i = 0; i < 8; i++) { - p[i] = (uint8_t)(total >> 8 * (7 - i)) & 0xFF; - } - } else if(file == PT2260FileProtocol) { - const uint8_t lut[] = {0x00, 0x01, 0x03}; // 00, 01, 11 - const uint64_t button_open = 0x03; // 11 - //const uint8_t button_lock = 0x0C; // 1100 - //const uint8_t button_stop = 0x30; // 110000 - //const uint8_t button_close = 0xC0; // 11000000 - - uint64_t total = 0; - for(size_t j = 0; j < 8; j++) { - total |= lut[step % 3] << (2 * j); - double sub_step = step / 3; - step = (uint64_t)floor(sub_step); - } - total <<= 8; - total |= button_open; - - for(int i = 0; i < 8; i++) { - p[i] = (uint8_t)(total >> 8 * (7 - i)) & 0xFF; - } - } else { - for(int i = 0; i < 8; i++) { - p[i] = (uint8_t)(step >> 8 * (7 - i)) & 0xFF; - } - } - - size_t size = sizeof(uint64_t); - for(uint8_t i = 0; i < size; i++) { - if(p[i] != 0) { - furi_string_cat_printf(candidate, "%02X", p[i]); - } else { - furi_string_cat_printf(candidate, "%s", "00"); - } - - if(i < size - 1) { - furi_string_push_back(candidate, ' '); - } - } - -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "candidate: %s, step: %lld", furi_string_get_cstr(candidate), step); -#endif -} - -void subbrute_protocol_default_payload( - Stream* stream, - SubBruteFileProtocol file, - uint64_t step, - uint8_t bits, - uint32_t te, - uint8_t repeat) { - FuriString* candidate = furi_string_alloc(); - subbrute_protocol_create_candidate_for_default(candidate, file, step); - -#ifdef FURI_DEBUG - FURI_LOG_D( - TAG, - "candidate: %s, step: %lld, repeat: %d, te: %s", - furi_string_get_cstr(candidate), - step, - repeat, - te ? "true" : "false"); -#endif - stream_clean(stream); - if(te) { - stream_write_format( - stream, - subbrute_key_small_with_tail, - bits, - furi_string_get_cstr(candidate), - te, - repeat); - } else { - stream_write_format( - stream, subbrute_key_small_no_tail, bits, furi_string_get_cstr(candidate), repeat); - } - - furi_string_free(candidate); -} - -void subbrute_protocol_file_payload( - Stream* stream, - uint64_t step, - uint8_t bits, - uint32_t te, - uint8_t repeat, - uint8_t bit_index, - uint64_t file_key, - bool two_bytes) { - FuriString* candidate = furi_string_alloc(); - subbrute_protocol_create_candidate_for_existing_file( - candidate, step, bit_index, file_key, two_bytes); - -#ifdef FURI_DEBUG - FURI_LOG_D( - TAG, - "candidate: %s, step: %lld, repeat: %d, te: %s", - furi_string_get_cstr(candidate), - step, - repeat, - te ? "true" : "false"); -#endif - stream_clean(stream); - - if(te) { - stream_write_format( - stream, - subbrute_key_small_with_tail, - bits, - furi_string_get_cstr(candidate), - te, - repeat); - } else { - stream_write_format( - stream, subbrute_key_small_no_tail, bits, furi_string_get_cstr(candidate), repeat); - } - - furi_string_free(candidate); -} - -void subbrute_protocol_default_generate_file( - Stream* stream, - uint32_t frequency, - FuriHalSubGhzPreset preset, - SubBruteFileProtocol file, - uint64_t step, - uint8_t bits, - uint32_t te, - uint8_t repeat) { - FuriString* candidate = furi_string_alloc(); - subbrute_protocol_create_candidate_for_default(candidate, file, step); - -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "candidate: %s, step: %lld", furi_string_get_cstr(candidate), step); -#endif - stream_clean(stream); - - if(te) { - stream_write_format( - stream, - subbrute_key_file_start_with_tail, - frequency, - subbrute_protocol_preset(preset), - subbrute_protocol_file(file), - bits, - furi_string_get_cstr(candidate), - te, - repeat); - } else { - stream_write_format( - stream, - subbrute_key_file_start_no_tail, - frequency, - subbrute_protocol_preset(preset), - subbrute_protocol_file(file), - bits, - furi_string_get_cstr(candidate), - repeat); - } - - furi_string_free(candidate); -} - -void subbrute_protocol_file_generate_file( - Stream* stream, - uint32_t frequency, - FuriHalSubGhzPreset preset, - SubBruteFileProtocol file, - uint64_t step, - uint8_t bits, - uint32_t te, - uint8_t repeat, - uint8_t bit_index, - uint64_t file_key, - bool two_bytes) { - FuriString* candidate = furi_string_alloc(); - // char subbrute_payload_byte[8]; - //furi_string_set_str(candidate, file_key); - subbrute_protocol_create_candidate_for_existing_file( - candidate, step, bit_index, file_key, two_bytes); - - stream_clean(stream); - if(te) { - stream_write_format( - stream, - subbrute_key_file_start_with_tail, - frequency, - subbrute_protocol_preset(preset), - subbrute_protocol_file(file), - bits, - furi_string_get_cstr(candidate), - te, - repeat); - } else { - stream_write_format( - stream, - subbrute_key_file_start_no_tail, - frequency, - subbrute_protocol_preset(preset), - subbrute_protocol_file(file), - bits, - furi_string_get_cstr(candidate), - repeat); - } - - furi_string_free(candidate); -} - -uint64_t - subbrute_protocol_calc_max_value(SubBruteAttacks attack_type, uint8_t bits, bool two_bytes) { - uint64_t max_value; - if(attack_type == SubBruteAttackLoadFile) { - max_value = two_bytes ? 0xFFFF : 0xFF; - } else if( - attack_type == SubBruteAttackSMC532624bit330 || - attack_type == SubBruteAttackSMC532624bit433 || - attack_type == SubBruteAttackUNILARM24bit330 || - attack_type == SubBruteAttackUNILARM24bit433 || - attack_type == SubBruteAttackPT226024bit315 || - attack_type == SubBruteAttackPT226024bit330 || - attack_type == SubBruteAttackPT226024bit390 || - attack_type == SubBruteAttackPT226024bit433) { - max_value = 6561; - } else { - FuriString* max_value_s; - max_value_s = furi_string_alloc(); - for(uint8_t i = 0; i < bits; i++) { - furi_string_cat_printf(max_value_s, "1"); - } - max_value = (uint64_t)strtol(furi_string_get_cstr(max_value_s), NULL, 2); - furi_string_free(max_value_s); - } - - return max_value; -} \ No newline at end of file diff --git a/applications/plugins/subbrute/subbrute_protocols.h b/applications/plugins/subbrute/subbrute_protocols.h deleted file mode 100644 index 0aba8140f..000000000 --- a/applications/plugins/subbrute/subbrute_protocols.h +++ /dev/null @@ -1,122 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -typedef enum { - CAMEFileProtocol, - NICEFileProtocol, - ChamberlainFileProtocol, - LinearFileProtocol, - PrincetonFileProtocol, - RAWFileProtocol, - BETTFileProtocol, - ClemsaFileProtocol, - DoitrandFileProtocol, - GateTXFileProtocol, - MagellanFileProtocol, - IntertechnoV3FileProtocol, - AnsonicFileProtocol, - SMC5326FileProtocol, - UNILARMFileProtocol, - PT2260FileProtocol, - HoneywellFileProtocol, - HoltekFileProtocol, - UnknownFileProtocol, - TotalFileProtocol, -} SubBruteFileProtocol; - -typedef enum { - SubBruteAttackCAME12bit303, - SubBruteAttackCAME12bit307, - SubBruteAttackCAME12bit315, - SubBruteAttackCAME12bit433, - SubBruteAttackCAME12bit868, - SubBruteAttackNICE12bit433, - SubBruteAttackNICE12bit868, - SubBruteAttackAnsonic12bit433075, - SubBruteAttackAnsonic12bit433, - SubBruteAttackAnsonic12bit434, - SubBruteAttackHoltek12bit433, - SubBruteAttackChamberlain9bit300, - SubBruteAttackChamberlain9bit315, - SubBruteAttackChamberlain9bit390, - SubBruteAttackChamberlain9bit433, - SubBruteAttackChamberlain8bit300, - SubBruteAttackChamberlain8bit315, - SubBruteAttackChamberlain8bit390, - SubBruteAttackChamberlain7bit300, - SubBruteAttackChamberlain7bit315, - SubBruteAttackChamberlain7bit390, - SubBruteAttackLinear10bit300, - SubBruteAttackLinear10bit310, - SubBruteAttackUNILARM24bit330, - SubBruteAttackUNILARM24bit433, - SubBruteAttackSMC532624bit330, - SubBruteAttackSMC532624bit433, - SubBruteAttackPT226024bit315, - SubBruteAttackPT226024bit330, - SubBruteAttackPT226024bit390, - SubBruteAttackPT226024bit433, - SubBruteAttackLoadFile, - SubBruteAttackTotalCount, -} SubBruteAttacks; - -typedef struct { - uint32_t frequency; - uint8_t bits; - uint32_t te; - uint8_t repeat; - FuriHalSubGhzPreset preset; - SubBruteFileProtocol file; -} SubBruteProtocol; - -const SubBruteProtocol* subbrute_protocol(SubBruteAttacks index); -const char* subbrute_protocol_preset(FuriHalSubGhzPreset preset); -const char* subbrute_protocol_file(SubBruteFileProtocol protocol); -FuriHalSubGhzPreset subbrute_protocol_convert_preset(FuriString* preset_name); -SubBruteFileProtocol subbrute_protocol_file_protocol_name(FuriString* name); -uint8_t subbrute_protocol_repeats_count(SubBruteAttacks index); -const char* subbrute_protocol_name(SubBruteAttacks index); - -void subbrute_protocol_default_payload( - Stream* stream, - SubBruteFileProtocol file, - uint64_t step, - uint8_t bits, - uint32_t te, - uint8_t repeat); -void subbrute_protocol_file_payload( - Stream* stream, - uint64_t step, - uint8_t bits, - uint32_t te, - uint8_t repeat, - uint8_t bit_index, - uint64_t file_key, - bool two_bytes); -void subbrute_protocol_default_generate_file( - Stream* stream, - uint32_t frequency, - FuriHalSubGhzPreset preset, - SubBruteFileProtocol file, - uint64_t step, - uint8_t bits, - uint32_t te, - uint8_t repeat); -void subbrute_protocol_file_generate_file( - Stream* stream, - uint32_t frequency, - FuriHalSubGhzPreset preset, - SubBruteFileProtocol file, - uint64_t step, - uint8_t bits, - uint32_t te, - uint8_t repeat, - uint8_t bit_index, - uint64_t file_key, - bool two_bytes); -uint64_t - subbrute_protocol_calc_max_value(SubBruteAttacks attack_type, uint8_t bits, bool two_bytes); \ No newline at end of file diff --git a/applications/plugins/subbrute/views/subbrute_attack_view.c b/applications/plugins/subbrute/views/subbrute_attack_view.c deleted file mode 100644 index d7770bb44..000000000 --- a/applications/plugins/subbrute/views/subbrute_attack_view.c +++ /dev/null @@ -1,341 +0,0 @@ -#include "subbrute_attack_view.h" -#include "../subbrute_i.h" -#include "../subbrute_protocols.h" -#include "../helpers/gui_top_buttons.h" - -#include -#include -#include -#include -#include - -#define TAG "SubBruteAttackView" - -struct SubBruteAttackView { - View* view; - SubBruteAttackViewCallback callback; - void* context; - SubBruteAttacks attack_type; - uint64_t max_value; - uint64_t current_step; - bool is_attacking; - uint8_t extra_repeats; -}; - -typedef struct { - SubBruteAttacks attack_type; - uint64_t max_value; - uint64_t current_step; - uint8_t extra_repeats; - bool is_attacking; - IconAnimation* icon; -} SubBruteAttackViewModel; - -void subbrute_attack_view_set_callback( - SubBruteAttackView* instance, - SubBruteAttackViewCallback callback, - void* context) { - furi_assert(instance); - furi_assert(callback); - - instance->callback = callback; - instance->context = context; -} - -bool subbrute_attack_view_input(InputEvent* event, void* context) { - furi_assert(event); - furi_assert(context); - SubBruteAttackView* instance = context; -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "InputKey: %d", event->key); -#endif - - if(event->key == InputKeyBack && event->type == InputTypeShort) { - instance->is_attacking = false; - with_view_model( - instance->view, - SubBruteAttackViewModel * model, - { model->is_attacking = false; }, - true); - - instance->callback(SubBruteCustomEventTypeBackPressed, instance->context); - return true; - } - - bool update = false; - - if(!instance->is_attacking) { - if(event->type == InputTypeShort && event->key == InputKeyOk) { -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "InputKey: %d OK", event->key); -#endif - instance->is_attacking = true; - instance->callback(SubBruteCustomEventTypeTransmitStarted, instance->context); - update = true; - } else if(event->key == InputKeyUp) { - instance->callback(SubBruteCustomEventTypeSaveFile, instance->context); - update = true; - } else if(event->key == InputKeyDown) { - instance->callback(SubBruteCustomEventTypeTransmitCustom, instance->context); - update = true; - } else if(event->type == InputTypeShort) { - if(event->key == InputKeyLeft) { - instance->callback(SubBruteCustomEventTypeChangeStepDown, instance->context); - } else if(event->key == InputKeyRight) { - instance->callback(SubBruteCustomEventTypeChangeStepUp, instance->context); - } - update = true; - } else if(event->type == InputTypeRepeat) { - if(event->key == InputKeyLeft) { - instance->callback(SubBruteCustomEventTypeChangeStepDownMore, instance->context); - } else if(event->key == InputKeyRight) { - instance->callback(SubBruteCustomEventTypeChangeStepUpMore, instance->context); - } - update = true; - } - } else { - // ATTACK Mode! - if((event->type == InputTypeShort || event->type == InputTypeRepeat) && - (event->key == InputKeyOk || event->key == InputKeyBack)) { - instance->is_attacking = false; - instance->callback(SubBruteCustomEventTypeTransmitNotStarted, instance->context); - - update = true; - } - } - - if(update) { - with_view_model( - instance->view, - SubBruteAttackViewModel * model, - { - if(model->is_attacking != instance->is_attacking) { - if(instance->is_attacking) { - icon_animation_stop(model->icon); - icon_animation_start(model->icon); - } else { - icon_animation_stop(model->icon); - } - } - - model->attack_type = instance->attack_type; - model->max_value = instance->max_value; - model->current_step = instance->current_step; - model->is_attacking = instance->is_attacking; - }, - true); - } - - return true; -} - -SubBruteAttackView* subbrute_attack_view_alloc() { - SubBruteAttackView* instance = malloc(sizeof(SubBruteAttackView)); - - instance->view = view_alloc(); - view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(SubBruteAttackViewModel)); - view_set_context(instance->view, instance); - - with_view_model( - instance->view, - SubBruteAttackViewModel * model, - { - model->icon = icon_animation_alloc(&A_Sub1ghz_14); - view_tie_icon_animation(instance->view, model->icon); - }, - true); - - view_set_draw_callback(instance->view, (ViewDrawCallback)subbrute_attack_view_draw); - view_set_input_callback(instance->view, subbrute_attack_view_input); - view_set_enter_callback(instance->view, subbrute_attack_view_enter); - view_set_exit_callback(instance->view, subbrute_attack_view_exit); - - instance->attack_type = SubBruteAttackTotalCount; - instance->max_value = 0x00; - instance->current_step = 0; - instance->is_attacking = false; - - return instance; -} - -void subbrute_attack_view_enter(void* context) { - furi_assert(context); - -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "subbrute_attack_view_enter"); -#endif -} - -void subbrute_attack_view_free(SubBruteAttackView* instance) { - furi_assert(instance); - -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "subbrute_attack_view_free"); -#endif - - with_view_model( - instance->view, - SubBruteAttackViewModel * model, - { icon_animation_free(model->icon); }, - false); - - view_free(instance->view); - free(instance); -} - -View* subbrute_attack_view_get_view(SubBruteAttackView* instance) { - furi_assert(instance); - return instance->view; -} - -void subbrute_attack_view_set_current_step(SubBruteAttackView* instance, uint64_t current_step) { - furi_assert(instance); -#ifdef FURI_DEBUG - //FURI_LOG_D(TAG, "Set step: %d", current_step); -#endif - instance->current_step = current_step; - with_view_model( - instance->view, - SubBruteAttackViewModel * model, - { model->current_step = current_step; }, - true); -} - -// We need to call init every time, because not every time we calls enter -// normally, call enter only once -void subbrute_attack_view_init_values( - SubBruteAttackView* instance, - uint8_t index, - uint64_t max_value, - uint64_t current_step, - bool is_attacking, - uint8_t extra_repeats) { -#ifdef FURI_DEBUG - FURI_LOG_I( - TAG, - "INIT, attack_type: %d, max_value: %lld, current_step: %lld, extra_repeats: %d", - index, - max_value, - current_step, - extra_repeats); -#endif - instance->attack_type = index; - instance->max_value = max_value; - instance->current_step = current_step; - instance->is_attacking = is_attacking; - instance->extra_repeats = extra_repeats; - - with_view_model( - instance->view, - SubBruteAttackViewModel * model, - { - model->max_value = max_value; - model->attack_type = index; - model->current_step = current_step; - model->is_attacking = is_attacking; - model->extra_repeats = extra_repeats; - if(is_attacking) { - icon_animation_start(model->icon); - } else { - icon_animation_stop(model->icon); - } - }, - true); -} - -void subbrute_attack_view_exit(void* context) { - furi_assert(context); - SubBruteAttackView* instance = context; -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "subbrute_attack_view_exit"); -#endif - with_view_model( - instance->view, - SubBruteAttackViewModel * model, - { icon_animation_stop(model->icon); }, - false); -} - -void subbrute_attack_view_draw(Canvas* canvas, void* context) { - furi_assert(context); - SubBruteAttackViewModel* model = (SubBruteAttackViewModel*)context; - char buffer[64]; - - const char* attack_name = NULL; - attack_name = subbrute_protocol_name(model->attack_type); - - // Title - if(model->is_attacking) { - canvas_set_color(canvas, ColorBlack); - canvas_set_font(canvas, FontSecondary); - canvas_draw_str_aligned(canvas, 64, 2, AlignCenter, AlignTop, attack_name); - } - - // Current Step / Max value - const uint8_t y_frequency = 17; - if(model->max_value > 9999) { - canvas_set_font(canvas, FontBigNumbers); - snprintf(buffer, sizeof(buffer), "%05d/", (int)model->current_step); - canvas_draw_str_aligned(canvas, 5, y_frequency, AlignLeft, AlignTop, buffer); - - // Second part with another font, because BigNumber is out of screen bounds - canvas_set_font(canvas, FontPrimary); - snprintf(buffer, sizeof(buffer), "%05d", (int)model->max_value); - canvas_draw_str_aligned(canvas, 107, y_frequency + 13, AlignRight, AlignBottom, buffer); - } else if(model->max_value <= 0xFF) { - canvas_set_font(canvas, FontBigNumbers); - snprintf( - buffer, sizeof(buffer), "%03d/%03d", (int)model->current_step, (int)model->max_value); - canvas_draw_str_aligned(canvas, 64, y_frequency, AlignCenter, AlignTop, buffer); - } else { - canvas_set_font(canvas, FontBigNumbers); - snprintf( - buffer, sizeof(buffer), "%04d/%04d", (int)model->current_step, (int)model->max_value); - canvas_draw_str_aligned(canvas, 64, y_frequency, AlignCenter, AlignTop, buffer); - } - canvas_set_font(canvas, FontSecondary); - - memset(buffer, 0, sizeof(buffer)); - if(!model->is_attacking) { - canvas_set_color(canvas, ColorBlack); - canvas_set_font(canvas, FontSecondary); - canvas_draw_str_aligned(canvas, 64, 44, AlignCenter, AlignBottom, attack_name); - - snprintf( - buffer, - sizeof(buffer), - "x%d", - model->extra_repeats + subbrute_protocol_repeats_count(model->attack_type)); - canvas_draw_str_aligned(canvas, 60, 6, AlignCenter, AlignCenter, buffer); - - elements_button_left(canvas, "-1"); - elements_button_right(canvas, "+1"); - elements_button_center(canvas, "Start"); - elements_button_top_left(canvas, "Save"); - elements_button_top_right(canvas, "Resend"); - } else { - // canvas_draw_icon_animation - const uint8_t icon_h_offset = 0; - const uint8_t icon_width_with_offset = - icon_animation_get_width(model->icon) + icon_h_offset; - const uint8_t icon_v_offset = icon_animation_get_height(model->icon); // + vertical_offset; - const uint8_t x = canvas_width(canvas); - const uint8_t y = canvas_height(canvas); - canvas_draw_icon_animation( - canvas, x - icon_width_with_offset, y - icon_v_offset, model->icon); - // Progress bar - // Resolution: 128x64 px - float progress_value = (float)model->current_step / model->max_value; - elements_progress_bar(canvas, 8, 37, 110, progress_value > 1 ? 1 : progress_value); - - snprintf( - buffer, - sizeof(buffer), - "x%d", - model->extra_repeats + subbrute_protocol_repeats_count(model->attack_type)); - canvas_draw_str(canvas, 4, y - 8, buffer); - canvas_draw_str(canvas, 4, y - 1, "repeats"); - - elements_button_center(canvas, "Stop"); - } -} diff --git a/applications/plugins/subbrute/views/subbrute_attack_view.h b/applications/plugins/subbrute/views/subbrute_attack_view.h deleted file mode 100644 index 55e3a8222..000000000 --- a/applications/plugins/subbrute/views/subbrute_attack_view.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include "../subbrute_custom_event.h" -#include -#include -#include - -typedef void (*SubBruteAttackViewCallback)(SubBruteCustomEvent event, void* context); -typedef struct SubBruteAttackView SubBruteAttackView; - -void subbrute_attack_view_set_callback( - SubBruteAttackView* instance, - SubBruteAttackViewCallback callback, - void* context); -SubBruteAttackView* subbrute_attack_view_alloc(); -void subbrute_attack_view_free(SubBruteAttackView* instance); -View* subbrute_attack_view_get_view(SubBruteAttackView* instance); -void subbrute_attack_view_set_current_step(SubBruteAttackView* instance, uint64_t current_step); -void subbrute_attack_view_init_values( - SubBruteAttackView* instance, - uint8_t index, - uint64_t max_value, - uint64_t current_step, - bool is_attacking, - uint8_t extra_repeats); \ No newline at end of file diff --git a/applications/plugins/subbrute/views/subbrute_main_view.c b/applications/plugins/subbrute/views/subbrute_main_view.c deleted file mode 100644 index c21f2ea33..000000000 --- a/applications/plugins/subbrute/views/subbrute_main_view.c +++ /dev/null @@ -1,463 +0,0 @@ -#include "subbrute_main_view.h" -#include "../subbrute_i.h" -#include "../subbrute_protocols.h" -#include "../helpers/gui_top_buttons.h" - -#include -#include -#include - -#define STATUS_BAR_Y_SHIFT 14 -#define TAG "SubBruteMainView" - -#define ITEMS_ON_SCREEN 3 -#define ITEMS_INTERVAL 1 -#define ITEM_WIDTH 14 -#define ITEM_Y 27 -#define ITEM_HEIGHT 13 -#define TEXT_X 6 -#define TEXT_Y 37 -#define TEXT_INTERVAL 3 -#define TEXT_WIDTH 12 -#define ITEM_FRAME_RADIUS 2 - -struct SubBruteMainView { - View* view; - SubBruteMainViewCallback callback; - void* context; - uint8_t index; - bool is_select_byte; - bool two_bytes; - uint64_t key_from_file; - uint8_t extra_repeats; - uint8_t window_position; -}; - -typedef struct { - uint8_t index; - uint8_t extra_repeats; - uint8_t window_position; - bool is_select_byte; - bool two_bytes; - uint64_t key_from_file; -} SubBruteMainViewModel; - -void subbrute_main_view_set_callback( - SubBruteMainView* instance, - SubBruteMainViewCallback callback, - void* context) { - furi_assert(instance); - furi_assert(callback); - - instance->callback = callback; - instance->context = context; -} - -void subbrute_main_view_center_displayed_key( - Canvas* canvas, - uint64_t key, - uint8_t index, - bool two_bytes) { - uint8_t text_x = TEXT_X; - uint8_t item_x = TEXT_X - ITEMS_INTERVAL; - canvas_set_font(canvas, FontSecondary); - - for(int i = 0; i < 8; i++) { - char current_value[3] = {0}; - uint8_t byte_value = (uint8_t)(key >> 8 * (7 - i)) & 0xFF; - snprintf(current_value, sizeof(current_value), "%02X", byte_value); - - // For two bytes we need to select prev location - if(!two_bytes && i == index) { - canvas_set_color(canvas, ColorBlack); - canvas_draw_rbox( - canvas, item_x - 1, ITEM_Y, ITEM_WIDTH + 1, ITEM_HEIGHT, ITEM_FRAME_RADIUS); - canvas_set_color(canvas, ColorWhite); - canvas_draw_str(canvas, text_x, TEXT_Y, current_value); - } else if(two_bytes && (i == index || i == index - 1)) { - if(i == index) { - canvas_set_color(canvas, ColorBlack); - canvas_draw_rbox( - canvas, - item_x - ITEMS_INTERVAL - ITEM_WIDTH - 1, - ITEM_Y, - ITEM_WIDTH * 2 + ITEMS_INTERVAL * 2 + 1, - ITEM_HEIGHT, - ITEM_FRAME_RADIUS); - - canvas_set_color(canvas, ColorWhite); - canvas_draw_str(canvas, text_x, TEXT_Y, current_value); - - // Redraw prev element with white - memset(current_value, 0, sizeof(current_value)); - byte_value = (uint8_t)(key >> 8 * (7 - i + 1)) & 0xFF; - snprintf(current_value, sizeof(current_value), "%02X", byte_value); - canvas_draw_str( - canvas, text_x - (TEXT_WIDTH + TEXT_INTERVAL), TEXT_Y, current_value); - } else { - canvas_set_color(canvas, ColorWhite); - canvas_draw_str(canvas, text_x, TEXT_Y, current_value); - } - } else { - canvas_set_color(canvas, ColorBlack); - canvas_draw_str(canvas, text_x, TEXT_Y, current_value); - } - text_x = text_x + TEXT_WIDTH + TEXT_INTERVAL; - item_x = item_x + ITEM_WIDTH + ITEMS_INTERVAL; - } - - // Return normal color - canvas_set_color(canvas, ColorBlack); -} - -void subbrute_main_view_draw(Canvas* canvas, SubBruteMainViewModel* model) { - uint16_t screen_width = canvas_width(canvas); - uint16_t screen_height = canvas_height(canvas); - - if(model->is_select_byte) { -#ifdef FURI_DEBUG - //FURI_LOG_D(TAG, "key_from_file: %s", model->key_from_file); -#endif - //char msg_index[18]; - //snprintf(msg_index, sizeof(msg_index), "Field index: %d", model->index); - canvas_set_font(canvas, FontSecondary); - canvas_draw_str_aligned( - canvas, 64, 17, AlignCenter, AlignTop, "Please select values to calc:"); - - subbrute_main_view_center_displayed_key( - canvas, model->key_from_file, model->index, model->two_bytes); - //const char* line = furi_string_get_cstr(menu_items); - //canvas_set_font(canvas, FontSecondary); - //canvas_draw_str_aligned( - // canvas, 64, 37, AlignCenter, AlignTop, furi_string_get_cstr(menu_items)); - - elements_button_center(canvas, "Select"); - if(model->index > 0) { - elements_button_left(canvas, " "); - } - if(model->index < 7) { - elements_button_right(canvas, " "); - } - // Switch to another mode - if(model->two_bytes) { - elements_button_top_left(canvas, "One byte"); - } else { - elements_button_top_left(canvas, "Two bytes"); - } - } else { - // Title - canvas_set_font(canvas, FontPrimary); - canvas_draw_box(canvas, 0, 0, canvas_width(canvas), STATUS_BAR_Y_SHIFT); - canvas_invert_color(canvas); - canvas_draw_str_aligned(canvas, 64, 3, AlignCenter, AlignTop, SUBBRUTEFORCER_VER); - canvas_invert_color(canvas); - - // Menu - canvas_set_color(canvas, ColorBlack); - canvas_set_font(canvas, FontSecondary); - const uint8_t item_height = 16; - -#ifdef FURI_DEBUG - //FURI_LOG_D(TAG, "window_position: %d, index: %d", model->window_position, model->index); -#endif - for(uint8_t position = 0; position < SubBruteAttackTotalCount; ++position) { - uint8_t item_position = position - model->window_position; - - if(item_position < ITEMS_ON_SCREEN) { - if(model->index == position) { - canvas_draw_str_aligned( - canvas, - 4, - 9 + (item_position * item_height) + STATUS_BAR_Y_SHIFT, - AlignLeft, - AlignCenter, - subbrute_protocol_name(position)); - - if(model->extra_repeats > 0) { - canvas_set_font(canvas, FontBatteryPercent); - char buffer[10]; - snprintf( - buffer, - sizeof(buffer), - "x%d", - model->extra_repeats + subbrute_protocol_repeats_count(model->index)); - canvas_draw_str_aligned( - canvas, - screen_width - 15, - 9 + (item_position * item_height) + STATUS_BAR_Y_SHIFT, - AlignLeft, - AlignCenter, - buffer); - canvas_set_font(canvas, FontSecondary); - } - - elements_frame( - canvas, 1, 1 + (item_position * item_height) + STATUS_BAR_Y_SHIFT, 124, 15); - } else { - canvas_draw_str_aligned( - canvas, - 4, - 9 + (item_position * item_height) + STATUS_BAR_Y_SHIFT, - AlignLeft, - AlignCenter, - subbrute_protocol_name(position)); - } - } - } - - elements_scrollbar_pos( - canvas, - screen_width, - STATUS_BAR_Y_SHIFT + 2, - screen_height - STATUS_BAR_Y_SHIFT, - model->index, - SubBruteAttackTotalCount); - } -} - -bool subbrute_main_view_input(InputEvent* event, void* context) { - furi_assert(event); - furi_assert(context); - - if(event->key == InputKeyBack && event->type == InputTypeShort) { -#ifdef FURI_DEBUG - FURI_LOG_I(TAG, "InputKey: BACK"); -#endif - return false; - } - - SubBruteMainView* instance = context; -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "InputKey: %d, extra_repeats: %d", event->key, instance->extra_repeats); -#endif - const uint8_t min_value = 0; - const uint8_t correct_total = SubBruteAttackTotalCount - 1; - uint8_t max_repeats = 9 - subbrute_protocol_repeats_count(instance->index); - - bool updated = false; - bool consumed = false; - bool is_short = (event->type == InputTypeShort) || (event->type == InputTypeRepeat); - - if(!instance->is_select_byte) { - if(event->key == InputKeyUp && is_short) { - if(instance->index == min_value) { - instance->index = correct_total; - } else { - instance->index = CLAMP(instance->index - 1, correct_total, min_value); - } - instance->extra_repeats = 0; - updated = true; - consumed = true; - } else if(event->key == InputKeyDown && is_short) { - if(instance->index == correct_total) { - instance->index = min_value; - } else { - instance->index = CLAMP(instance->index + 1, correct_total, min_value); - } - instance->extra_repeats = 0; - updated = true; - consumed = true; - } else if(event->key == InputKeyLeft && is_short) { - instance->extra_repeats = CLAMP(instance->extra_repeats - 1, max_repeats, 0); - - updated = true; - consumed = true; - } else if(event->key == InputKeyRight && is_short) { - instance->extra_repeats = CLAMP(instance->extra_repeats + 1, max_repeats, 0); - - updated = true; - consumed = true; - } else if(event->key == InputKeyOk && is_short) { - if(instance->index == SubBruteAttackLoadFile) { - instance->callback(SubBruteCustomEventTypeLoadFile, instance->context); - } else { - instance->callback(SubBruteCustomEventTypeMenuSelected, instance->context); - } - consumed = true; - updated = true; - } - if(updated) { - instance->window_position = instance->index; - if(instance->window_position > 0) { - instance->window_position -= 1; - } - - if(SubBruteAttackTotalCount <= ITEMS_ON_SCREEN) { - instance->window_position = 0; - } else { - if(instance->window_position >= (SubBruteAttackTotalCount - ITEMS_ON_SCREEN)) { - instance->window_position = (SubBruteAttackTotalCount - ITEMS_ON_SCREEN); - } - } - } - } else if(is_short) { - if(event->key == InputKeyLeft) { - if((instance->index > 0 && !instance->two_bytes) || - (instance->two_bytes && instance->index > 1)) { - instance->index--; - } - updated = true; - consumed = true; - } else if(event->key == InputKeyRight) { - if(instance->index < 7) { - instance->index++; - } - updated = true; - consumed = true; - } else if(event->key == InputKeyUp) { - instance->two_bytes = !instance->two_bytes; - // Because index is changing - if(instance->two_bytes && instance->index < 7) { - instance->index++; - } - // instance->callback( - // instance->two_bytes ? SubBruteCustomEventTypeChangeStepUp : - // SubBruteCustomEventTypeChangeStepDown, - // instance->context); - - updated = true; - consumed = true; - } else if(event->key == InputKeyOk) { - instance->callback(SubBruteCustomEventTypeIndexSelected, instance->context); - consumed = true; - updated = true; - } - } - - if(updated) { - with_view_model( - instance->view, - SubBruteMainViewModel * model, - { - model->index = instance->index; - model->window_position = instance->window_position; - model->key_from_file = instance->key_from_file; - model->is_select_byte = instance->is_select_byte; - model->two_bytes = instance->two_bytes; - model->extra_repeats = instance->extra_repeats; - }, - true); - } - - return consumed; -} - -void subbrute_main_view_enter(void* context) { - furi_assert(context); - -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "subbrute_main_view_enter"); -#endif -} - -void subbrute_main_view_exit(void* context) { - furi_assert(context); - -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "subbrute_main_view_exit"); -#endif -} - -SubBruteMainView* subbrute_main_view_alloc() { - SubBruteMainView* instance = malloc(sizeof(SubBruteMainView)); - instance->view = view_alloc(); - view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(SubBruteMainViewModel)); - view_set_context(instance->view, instance); - view_set_draw_callback(instance->view, (ViewDrawCallback)subbrute_main_view_draw); - view_set_input_callback(instance->view, subbrute_main_view_input); - view_set_enter_callback(instance->view, subbrute_main_view_enter); - view_set_exit_callback(instance->view, subbrute_main_view_exit); - - instance->index = 0; - instance->window_position = 0; - instance->key_from_file = 0; - instance->is_select_byte = false; - instance->two_bytes = false; - instance->extra_repeats = 0; - with_view_model( - instance->view, - SubBruteMainViewModel * model, - { - model->index = instance->index; - model->window_position = instance->window_position; - model->key_from_file = instance->key_from_file; - model->is_select_byte = instance->is_select_byte; - model->two_bytes = instance->two_bytes; - model->extra_repeats = instance->extra_repeats; - }, - true); - - return instance; -} - -void subbrute_main_view_free(SubBruteMainView* instance) { - furi_assert(instance); - - view_free(instance->view); - free(instance); -} - -View* subbrute_main_view_get_view(SubBruteMainView* instance) { - furi_assert(instance); - return instance->view; -} - -void subbrute_main_view_set_index( - SubBruteMainView* instance, - uint8_t idx, - bool is_select_byte, - bool two_bytes, - uint64_t key_from_file) { - furi_assert(instance); - furi_assert(idx < SubBruteAttackTotalCount); -#ifdef FURI_DEBUG - FURI_LOG_I(TAG, "Set index: %d, is_select_byte: %d", idx, is_select_byte); -#endif - instance->is_select_byte = is_select_byte; - instance->two_bytes = two_bytes; - instance->key_from_file = key_from_file; - instance->index = idx; - instance->window_position = idx; - - if(!is_select_byte) { - if(instance->window_position > 0) { - instance->window_position -= 1; - } - - if(SubBruteAttackTotalCount <= ITEMS_ON_SCREEN) { - instance->window_position = 0; - } else { - if(instance->window_position >= (SubBruteAttackTotalCount - ITEMS_ON_SCREEN)) { - instance->window_position = (SubBruteAttackTotalCount - ITEMS_ON_SCREEN); - } - } - } - - with_view_model( - instance->view, - SubBruteMainViewModel * model, - { - model->index = instance->index; - model->window_position = instance->window_position; - model->key_from_file = instance->key_from_file; - model->is_select_byte = instance->is_select_byte; - model->two_bytes = instance->two_bytes; - model->extra_repeats = instance->extra_repeats; - }, - true); -} - -SubBruteAttacks subbrute_main_view_get_index(SubBruteMainView* instance) { - furi_assert(instance); - return instance->index; -} - -uint8_t subbrute_main_view_get_extra_repeats(SubBruteMainView* instance) { - furi_assert(instance); - return instance->extra_repeats; -} - -bool subbrute_main_view_get_two_bytes(SubBruteMainView* instance) { - furi_assert(instance); - return instance->two_bytes; -} \ No newline at end of file diff --git a/applications/plugins/subbrute/views/subbrute_main_view.h b/applications/plugins/subbrute/views/subbrute_main_view.h deleted file mode 100644 index 003cd9817..000000000 --- a/applications/plugins/subbrute/views/subbrute_main_view.h +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include "../subbrute_custom_event.h" -#include "../subbrute_protocols.h" -#include -#include -#include - -typedef void (*SubBruteMainViewCallback)(SubBruteCustomEvent event, void* context); -typedef struct SubBruteMainView SubBruteMainView; - -void subbrute_main_view_set_callback( - SubBruteMainView* instance, - SubBruteMainViewCallback callback, - void* context); - -SubBruteMainView* subbrute_main_view_alloc(); -void subbrute_main_view_free(SubBruteMainView* instance); -View* subbrute_main_view_get_view(SubBruteMainView* instance); -void subbrute_main_view_set_index( - SubBruteMainView* instance, - uint8_t idx, - bool is_select_byte, - bool two_bytes, - uint64_t file_key); -SubBruteAttacks subbrute_main_view_get_index(SubBruteMainView* instance); -uint8_t subbrute_main_view_get_extra_repeats(SubBruteMainView* instance); -bool subbrute_main_view_get_two_bytes(SubBruteMainView* instance); -void subbrute_attack_view_enter(void* context); -void subbrute_attack_view_exit(void* context); -bool subbrute_attack_view_input(InputEvent* event, void* context); -void subbrute_attack_view_draw(Canvas* canvas, void* context); \ No newline at end of file diff --git a/applications/plugins/tetris_game/tetris_game.c b/applications/plugins/tetris_game/tetris_game.c index a4a17d348..366f405f3 100644 --- a/applications/plugins/tetris_game/tetris_game.c +++ b/applications/plugins/tetris_game/tetris_game.c @@ -16,6 +16,9 @@ #define FIELD_WIDTH 11 #define FIELD_HEIGHT 24 +#define MAX_FALL_SPEED 500 +#define MIN_FALL_SPEED 100 + typedef struct Point { // Also used for offset data, which is sometimes negative int8_t x, y; @@ -173,7 +176,7 @@ static void tetris_game_input_callback(InputEvent* input_event, FuriMessageQueue static void tetris_game_init_state(TetrisState* tetris_state) { tetris_state->gameState = GameStatePlaying; tetris_state->numLines = 0; - tetris_state->fallSpeed = 500; + tetris_state->fallSpeed = MAX_FALL_SPEED; memset(tetris_state->playField, 0, sizeof(tetris_state->playField)); memcpy(&tetris_state->currPiece, &shapes[rand() % 7], sizeof(tetris_state->currPiece)); @@ -307,6 +310,7 @@ static void tetris_game_render_curr_piece(tetris_state); uint8_t numLines = 0; uint8_t lines[] = {0, 0, 0, 0}; + uint16_t nextFallSpeed; tetris_game_check_for_lines(tetris_state, lines, &numLines); if(numLines > 0) { @@ -327,7 +331,10 @@ static void uint16_t oldNumLines = tetris_state->numLines; tetris_state->numLines += numLines; if((oldNumLines / 10) % 10 != (tetris_state->numLines / 10) % 10) { - tetris_state->fallSpeed -= 50; + nextFallSpeed = tetris_state->fallSpeed - (100 / (tetris_state->numLines / 10)); + if (nextFallSpeed >= MIN_FALL_SPEED){ + tetris_state->fallSpeed = nextFallSpeed; + } } } @@ -388,6 +395,9 @@ int32_t tetris_game_app() { Piece* newPiece = malloc(sizeof(Piece)); uint8_t downRepeatCounter = 0; + // Call dolphin deed on game start + DOLPHIN_DEED(DolphinDeedPluginGameStart); + for(bool processing = true; processing;) { // This 10U implicitly sets the game loop speed. downRepeatCounter relies on this value FuriStatus event_status = furi_message_queue_get(event_queue, &event, 10U); diff --git a/applications/plugins/text_viewer/.gitignore b/applications/plugins/text_viewer/.gitignore deleted file mode 100644 index c6127b38c..000000000 --- a/applications/plugins/text_viewer/.gitignore +++ /dev/null @@ -1,52 +0,0 @@ -# Prerequisites -*.d - -# Object files -*.o -*.ko -*.obj -*.elf - -# Linker output -*.ilk -*.map -*.exp - -# Precompiled Headers -*.gch -*.pch - -# Libraries -*.lib -*.a -*.la -*.lo - -# Shared objects (inc. Windows DLLs) -*.dll -*.so -*.so.* -*.dylib - -# Executables -*.exe -*.out -*.app -*.i*86 -*.x86_64 -*.hex - -# Debug files -*.dSYM/ -*.su -*.idb -*.pdb - -# Kernel Module Compile Results -*.mod* -*.cmd -.tmp_versions/ -modules.order -Module.symvers -Mkfile.old -dkms.conf diff --git a/applications/plugins/text_viewer/application.fam b/applications/plugins/text_viewer/application.fam index 4f5182edf..dcd573c9d 100644 --- a/applications/plugins/text_viewer/application.fam +++ b/applications/plugins/text_viewer/application.fam @@ -2,7 +2,7 @@ App( appid="text_viewer", name="Text Viewer", apptype=FlipperAppType.EXTERNAL, - entry_point="hex_viewer_app", + entry_point="text_viewer_app", cdefines=["APP_TEXT_VIEWER"], requires=[ "gui", @@ -10,7 +10,7 @@ App( ], stack_size=2 * 1024, order=20, - fap_icon="icons/hex_10px.png", + fap_icon="icons/text_10px.png", fap_category="Misc", fap_icon_assets="icons", ) diff --git a/applications/plugins/text_viewer/icons/hex_10px.png b/applications/plugins/text_viewer/icons/hex_10px.png deleted file mode 100644 index 582e288c6..000000000 Binary files a/applications/plugins/text_viewer/icons/hex_10px.png and /dev/null differ diff --git a/applications/plugins/text_viewer/icons/text_10px.png b/applications/plugins/text_viewer/icons/text_10px.png new file mode 100644 index 000000000..8e8a6183d Binary files /dev/null and b/applications/plugins/text_viewer/icons/text_10px.png differ diff --git a/applications/plugins/text_viewer/hex_viewer.c b/applications/plugins/text_viewer/text_viewer.c similarity index 52% rename from applications/plugins/text_viewer/hex_viewer.c rename to applications/plugins/text_viewer/text_viewer.c index 3830a6602..59923adb9 100644 --- a/applications/plugins/text_viewer/hex_viewer.c +++ b/applications/plugins/text_viewer/text_viewer.c @@ -13,24 +13,24 @@ #define TAG "TextViewer" -#define HEX_VIEWER_APP_PATH_FOLDER "/any" -#define HEX_VIEWER_APP_EXTENSION "*" +#define TEXT_VIEWER_APP_PATH_FOLDER ANY_PATH("") +#define TEXT_VIEWER_APP_EXTENSION "*" -#define HEX_VIEWER_BYTES_PER_LINE 20u -#define HEX_VIEWER_LINES_ON_SCREEN 5u -#define HEX_VIEWER_BUF_SIZE (HEX_VIEWER_LINES_ON_SCREEN * HEX_VIEWER_BYTES_PER_LINE) +#define TEXT_VIEWER_BYTES_PER_LINE 20u +#define TEXT_VIEWER_LINES_ON_SCREEN 5u +#define TEXT_VIEWER_BUF_SIZE (TEXT_VIEWER_LINES_ON_SCREEN * TEXT_VIEWER_BYTES_PER_LINE) typedef struct { - uint8_t file_bytes[HEX_VIEWER_LINES_ON_SCREEN][HEX_VIEWER_BYTES_PER_LINE]; + uint8_t file_bytes[TEXT_VIEWER_LINES_ON_SCREEN][TEXT_VIEWER_BYTES_PER_LINE]; uint32_t file_offset; uint32_t file_read_bytes; uint32_t file_size; Stream* stream; bool mode; // Print address or content -} HexViewerModel; +} TextViewerModel; typedef struct { - HexViewerModel* model; + TextViewerModel* model; FuriMutex** mutex; FuriMessageQueue* input_queue; @@ -38,56 +38,56 @@ typedef struct { ViewPort* view_port; Gui* gui; Storage* storage; -} HexViewer; +} TextViewer; static void render_callback(Canvas* canvas, void* ctx) { - HexViewer* hex_viewer = ctx; - furi_check(furi_mutex_acquire(hex_viewer->mutex, FuriWaitForever) == FuriStatusOk); + TextViewer* text_viewer = ctx; + furi_check(furi_mutex_acquire(text_viewer->mutex, FuriWaitForever) == FuriStatusOk); canvas_clear(canvas); canvas_set_color(canvas, ColorBlack); - //elements_button_left(canvas, hex_viewer->model->mode ? "Addr" : "Text"); - hex_viewer->model->mode = 1; //text mode + //elements_button_left(canvas, text_viewer->model->mode ? "Addr" : "Text"); + text_viewer->model->mode = 1; //text mode //elements_button_right(canvas, "Info"); int ROW_HEIGHT = 12; int TOP_OFFSET = 10; int LEFT_OFFSET = 3; - uint32_t line_count = hex_viewer->model->file_size / HEX_VIEWER_BYTES_PER_LINE; - if(hex_viewer->model->file_size % HEX_VIEWER_BYTES_PER_LINE != 0) line_count += 1; - uint32_t first_line_on_screen = hex_viewer->model->file_offset / HEX_VIEWER_BYTES_PER_LINE; - if(line_count > HEX_VIEWER_LINES_ON_SCREEN) { + uint32_t line_count = text_viewer->model->file_size / TEXT_VIEWER_BYTES_PER_LINE; + if(text_viewer->model->file_size % TEXT_VIEWER_BYTES_PER_LINE != 0) line_count += 1; + uint32_t first_line_on_screen = text_viewer->model->file_offset / TEXT_VIEWER_BYTES_PER_LINE; + if(line_count > TEXT_VIEWER_LINES_ON_SCREEN) { uint8_t width = canvas_width(canvas); elements_scrollbar_pos( canvas, width, 0, - ROW_HEIGHT * HEX_VIEWER_LINES_ON_SCREEN, + ROW_HEIGHT * TEXT_VIEWER_LINES_ON_SCREEN, first_line_on_screen, // TODO - line_count - (HEX_VIEWER_LINES_ON_SCREEN - 1)); + line_count - (TEXT_VIEWER_LINES_ON_SCREEN - 1)); } char temp_buf[32]; - uint32_t row_iters = hex_viewer->model->file_read_bytes / HEX_VIEWER_BYTES_PER_LINE; - if(hex_viewer->model->file_read_bytes % HEX_VIEWER_BYTES_PER_LINE != 0) row_iters += 1; + uint32_t row_iters = text_viewer->model->file_read_bytes / TEXT_VIEWER_BYTES_PER_LINE; + if(text_viewer->model->file_read_bytes % TEXT_VIEWER_BYTES_PER_LINE != 0) row_iters += 1; for(uint32_t i = 0; i < row_iters; ++i) { uint32_t bytes_left_per_row = - hex_viewer->model->file_read_bytes - i * HEX_VIEWER_BYTES_PER_LINE; - bytes_left_per_row = MIN(bytes_left_per_row, HEX_VIEWER_BYTES_PER_LINE); + text_viewer->model->file_read_bytes - i * TEXT_VIEWER_BYTES_PER_LINE; + bytes_left_per_row = MIN(bytes_left_per_row, TEXT_VIEWER_BYTES_PER_LINE); - if(hex_viewer->model->mode) { - memcpy(temp_buf, hex_viewer->model->file_bytes[i], bytes_left_per_row); + if(text_viewer->model->mode) { + memcpy(temp_buf, text_viewer->model->file_bytes[i], bytes_left_per_row); temp_buf[bytes_left_per_row] = '\0'; for(uint32_t j = 0; j < bytes_left_per_row; ++j) - if(!isprint((int)temp_buf[j])) temp_buf[j] = '.'; + if(!isprint((int)temp_buf[j])) temp_buf[j] = ' '; canvas_set_font(canvas, FontKeyboard); canvas_draw_str(canvas, LEFT_OFFSET, TOP_OFFSET + i * ROW_HEIGHT, temp_buf); } else { - uint32_t addr = hex_viewer->model->file_offset + i * HEX_VIEWER_BYTES_PER_LINE; + uint32_t addr = text_viewer->model->file_offset + i * TEXT_VIEWER_BYTES_PER_LINE; snprintf(temp_buf, 32, "%04lX", addr); canvas_set_font(canvas, FontKeyboard); @@ -95,21 +95,21 @@ static void render_callback(Canvas* canvas, void* ctx) { } } - furi_mutex_release(hex_viewer->mutex); + furi_mutex_release(text_viewer->mutex); } static void input_callback(InputEvent* input_event, void* ctx) { - HexViewer* hex_viewer = ctx; + TextViewer* text_viewer = ctx; if(input_event->type == InputTypeShort || input_event->type == InputTypeRepeat) { - furi_message_queue_put(hex_viewer->input_queue, input_event, 0); + furi_message_queue_put(text_viewer->input_queue, input_event, 0); } } -static HexViewer* hex_viewer_alloc() { - HexViewer* instance = malloc(sizeof(HexViewer)); +static TextViewer* text_viewer_alloc() { + TextViewer* instance = malloc(sizeof(TextViewer)); - instance->model = malloc(sizeof(HexViewerModel)); - memset(instance->model, 0x0, sizeof(HexViewerModel)); + instance->model = malloc(sizeof(TextViewerModel)); + memset(instance->model, 0x0, sizeof(TextViewerModel)); instance->mutex = furi_mutex_alloc(FuriMutexTypeNormal); @@ -127,7 +127,7 @@ static HexViewer* hex_viewer_alloc() { return instance; } -static void hex_viewer_free(HexViewer* instance) { +static void text_viewer_free(TextViewer* instance) { furi_record_close(RECORD_STORAGE); gui_remove_view_port(instance->gui, instance->view_port); @@ -144,54 +144,54 @@ static void hex_viewer_free(HexViewer* instance) { free(instance); } -static bool hex_viewer_open_file(HexViewer* hex_viewer, const char* file_path) { - furi_assert(hex_viewer); +static bool text_viewer_open_file(TextViewer* text_viewer, const char* file_path) { + furi_assert(text_viewer); furi_assert(file_path); - hex_viewer->model->stream = buffered_file_stream_alloc(hex_viewer->storage); + text_viewer->model->stream = buffered_file_stream_alloc(text_viewer->storage); bool isOk = true; do { if(!buffered_file_stream_open( - hex_viewer->model->stream, file_path, FSAM_READ, FSOM_OPEN_EXISTING)) { + text_viewer->model->stream, file_path, FSAM_READ, FSOM_OPEN_EXISTING)) { FURI_LOG_E(TAG, "Unable to open stream: %s", file_path); isOk = false; break; }; - hex_viewer->model->file_size = stream_size(hex_viewer->model->stream); + text_viewer->model->file_size = stream_size(text_viewer->model->stream); } while(false); return isOk; } -static bool hex_viewer_read_file(HexViewer* hex_viewer) { - furi_assert(hex_viewer); - furi_assert(hex_viewer->model->stream); - furi_assert(hex_viewer->model->file_offset % HEX_VIEWER_BYTES_PER_LINE == 0); +static bool text_viewer_read_file(TextViewer* text_viewer) { + furi_assert(text_viewer); + furi_assert(text_viewer->model->stream); + furi_assert(text_viewer->model->file_offset % TEXT_VIEWER_BYTES_PER_LINE == 0); - memset(hex_viewer->model->file_bytes, 0x0, HEX_VIEWER_BUF_SIZE); + memset(text_viewer->model->file_bytes, 0x0, TEXT_VIEWER_BUF_SIZE); bool isOk = true; do { - uint32_t offset = hex_viewer->model->file_offset; - if(!stream_seek(hex_viewer->model->stream, offset, true)) { + uint32_t offset = text_viewer->model->file_offset; + if(!stream_seek(text_viewer->model->stream, offset, true)) { FURI_LOG_E(TAG, "Unable to seek stream"); isOk = false; break; } - hex_viewer->model->file_read_bytes = stream_read( - hex_viewer->model->stream, - (uint8_t*)hex_viewer->model->file_bytes, - HEX_VIEWER_BUF_SIZE); + text_viewer->model->file_read_bytes = stream_read( + text_viewer->model->stream, + (uint8_t*)text_viewer->model->file_bytes, + TEXT_VIEWER_BUF_SIZE); } while(false); return isOk; } -int32_t hex_viewer_app(void* p) { - HexViewer* hex_viewer = hex_viewer_alloc(); +int32_t text_viewer_app(void* p) { + TextViewer* text_viewer = text_viewer_alloc(); FuriString* file_path; file_path = furi_string_alloc(); @@ -200,11 +200,11 @@ int32_t hex_viewer_app(void* p) { if(p && strlen(p)) { furi_string_set(file_path, (const char*)p); } else { - furi_string_set(file_path, HEX_VIEWER_APP_PATH_FOLDER); + furi_string_set(file_path, TEXT_VIEWER_APP_PATH_FOLDER); DialogsFileBrowserOptions browser_options; dialog_file_browser_set_basic_options( - &browser_options, HEX_VIEWER_APP_EXTENSION, &I_hex_10px); + &browser_options, TEXT_VIEWER_APP_EXTENSION, &I_text_10px); browser_options.hide_ext = false; DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS); @@ -219,35 +219,38 @@ int32_t hex_viewer_app(void* p) { FURI_LOG_I(TAG, "File selected: %s", furi_string_get_cstr(file_path)); - if(!hex_viewer_open_file(hex_viewer, furi_string_get_cstr(file_path))) break; - hex_viewer_read_file(hex_viewer); + if(!text_viewer_open_file(text_viewer, furi_string_get_cstr(file_path))) break; + text_viewer_read_file(text_viewer); InputEvent input; - while(furi_message_queue_get(hex_viewer->input_queue, &input, FuriWaitForever) == + while(furi_message_queue_get(text_viewer->input_queue, &input, FuriWaitForever) == FuriStatusOk) { if(input.key == InputKeyBack) { break; } else if(input.key == InputKeyUp) { - furi_check(furi_mutex_acquire(hex_viewer->mutex, FuriWaitForever) == FuriStatusOk); - if(hex_viewer->model->file_offset > 0) { - hex_viewer->model->file_offset -= HEX_VIEWER_BYTES_PER_LINE; - if(!hex_viewer_read_file(hex_viewer)) break; + furi_check( + furi_mutex_acquire(text_viewer->mutex, FuriWaitForever) == FuriStatusOk); + if(text_viewer->model->file_offset > 0) { + text_viewer->model->file_offset -= TEXT_VIEWER_BYTES_PER_LINE; + if(!text_viewer_read_file(text_viewer)) break; } - furi_mutex_release(hex_viewer->mutex); + furi_mutex_release(text_viewer->mutex); } else if(input.key == InputKeyDown) { - furi_check(furi_mutex_acquire(hex_viewer->mutex, FuriWaitForever) == FuriStatusOk); + furi_check( + furi_mutex_acquire(text_viewer->mutex, FuriWaitForever) == FuriStatusOk); uint32_t last_byte_on_screen = - hex_viewer->model->file_offset + hex_viewer->model->file_read_bytes; + text_viewer->model->file_offset + text_viewer->model->file_read_bytes; - if(hex_viewer->model->file_size > last_byte_on_screen) { - hex_viewer->model->file_offset += HEX_VIEWER_BYTES_PER_LINE; - if(!hex_viewer_read_file(hex_viewer)) break; + if(text_viewer->model->file_size > last_byte_on_screen) { + text_viewer->model->file_offset += TEXT_VIEWER_BYTES_PER_LINE; + if(!text_viewer_read_file(text_viewer)) break; } - furi_mutex_release(hex_viewer->mutex); + furi_mutex_release(text_viewer->mutex); } else if(input.key == InputKeyLeft) { - furi_check(furi_mutex_acquire(hex_viewer->mutex, FuriWaitForever) == FuriStatusOk); - hex_viewer->model->mode = !hex_viewer->model->mode; - furi_mutex_release(hex_viewer->mutex); + furi_check( + furi_mutex_acquire(text_viewer->mutex, FuriWaitForever) == FuriStatusOk); + text_viewer->model->mode = !text_viewer->model->mode; + furi_mutex_release(text_viewer->mutex); } else if(input.key == InputKeyRight) { FuriString* buffer; buffer = furi_string_alloc(); @@ -255,13 +258,13 @@ int32_t hex_viewer_app(void* p) { buffer, "File path: %s\nFile size: %lu (0x%lX)", furi_string_get_cstr(file_path), - hex_viewer->model->file_size, - hex_viewer->model->file_size); + text_viewer->model->file_size, + text_viewer->model->file_size); DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS); DialogMessage* message = dialog_message_alloc(); dialog_message_set_header(message, "Text Viewer v1.1", 16, 2, AlignLeft, AlignTop); - dialog_message_set_icon(message, &I_hex_10px, 3, 2); + dialog_message_set_icon(message, &I_text_10px, 3, 2); dialog_message_set_text( message, furi_string_get_cstr(buffer), 3, 16, AlignLeft, AlignTop); dialog_message_set_buttons(message, NULL, NULL, "Back"); @@ -271,12 +274,12 @@ int32_t hex_viewer_app(void* p) { dialog_message_free(message); furi_record_close(RECORD_DIALOGS); } - view_port_update(hex_viewer->view_port); + view_port_update(text_viewer->view_port); } } while(false); furi_string_free(file_path); - hex_viewer_free(hex_viewer); + text_viewer_free(text_viewer); return 0; } \ No newline at end of file diff --git a/applications/plugins/tictactoe_game/tictactoe_game.c b/applications/plugins/tictactoe_game/tictactoe_game.c index fe57d7c62..ec82192a8 100644 --- a/applications/plugins/tictactoe_game/tictactoe_game.c +++ b/applications/plugins/tictactoe_game/tictactoe_game.c @@ -3,6 +3,7 @@ #include #include #include +#include #define TAG "TicTacToe" @@ -330,6 +331,9 @@ int32_t tictactoe_game_app(void* p) { Gui* gui = furi_record_open(RECORD_GUI); gui_add_view_port(gui, view_port, GuiLayerFullscreen); + // Call dolphin deed on game start + DOLPHIN_DEED(DolphinDeedPluginGameStart); + GameEvent event; for(bool processing = true; processing;) { FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100); diff --git a/applications/plugins/totp/cli/commands/move/move.c b/applications/plugins/totp/cli/commands/move/move.c index 9d47134e5..e2929f153 100644 --- a/applications/plugins/totp/cli/commands/move/move.c +++ b/applications/plugins/totp/cli/commands/move/move.c @@ -34,10 +34,10 @@ void totp_cli_command_move_docopt_usage() { void totp_cli_command_move_docopt_options() { TOTP_CLI_PRINTF(" " DOCOPT_OPTION( TOTP_CLI_COMMAND_MOVE_ARG_NEW_NAME_PREFIX, - DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_MOVE_ARG_NEW_NAME)) " New token name.\r\n"); + DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_MOVE_ARG_NEW_NAME)) " New token name\r\n"); TOTP_CLI_PRINTF(" " DOCOPT_OPTION( TOTP_CLI_COMMAND_MOVE_ARG_NEW_INDEX_PREFIX, - DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_MOVE_ARG_NEW_INDEX)) " New token index.\r\n"); + DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_MOVE_ARG_NEW_INDEX)) " New token index\r\n"); } void totp_cli_command_move_handle(PluginState* plugin_state, FuriString* args, Cli* cli) { diff --git a/applications/plugins/totp/cli/commands/timezone/timezone.c b/applications/plugins/totp/cli/commands/timezone/timezone.c index 537cf8a4a..4a737f6ef 100644 --- a/applications/plugins/totp/cli/commands/timezone/timezone.c +++ b/applications/plugins/totp/cli/commands/timezone/timezone.c @@ -20,7 +20,7 @@ void totp_cli_command_timezone_docopt_usage() { void totp_cli_command_timezone_docopt_arguments() { TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_TIMEZONE_ARG_TIMEZONE - " Timezone offset in hours to be set.\r\n"); + " Timezone offset in hours to be set\r\n"); } void totp_cli_command_timezone_handle(PluginState* plugin_state, FuriString* args, Cli* cli) { diff --git a/applications/plugins/totp/services/config/config.c b/applications/plugins/totp/services/config/config.c index c5193ac2e..a11f3b116 100644 --- a/applications/plugins/totp/services/config/config.c +++ b/applications/plugins/totp/services/config/config.c @@ -196,7 +196,7 @@ static TotpConfigFileOpenResult totp_open_config_file(Storage* storage, FlipperF return TotpConfigFileOpenSuccess; } -TotpConfigFileUpdateResult +static TotpConfigFileUpdateResult totp_config_file_save_new_token_i(FlipperFormat* file, const TokenInfo* token_info) { TotpConfigFileUpdateResult update_result; do { diff --git a/applications/plugins/totp/totp_app.c b/applications/plugins/totp/totp_app.c index f10837814..f791e99de 100644 --- a/applications/plugins/totp/totp_app.c +++ b/applications/plugins/totp/totp_app.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "services/config/config.h" #include "types/plugin_state.h" #include "types/token_info.h" @@ -151,6 +152,9 @@ int32_t totp_app() { return 253; } + // Affecting dolphin level + DOLPHIN_DEED(DolphinDeedPluginStart); + // Set system callbacks ViewPort* view_port = view_port_alloc(); view_port_draw_callback_set(view_port, render_callback, &state_mutex); diff --git a/applications/plugins/subbrute/LICENSE b/applications/plugins/uart_terminal/LICENSE similarity index 96% rename from applications/plugins/subbrute/LICENSE rename to applications/plugins/uart_terminal/LICENSE index 06dcf7e87..c4613e7ea 100644 --- a/applications/plugins/subbrute/LICENSE +++ b/applications/plugins/uart_terminal/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2022 Der Skythe +Copyright (c) 2023 Malik cool4uma Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -19,3 +19,4 @@ 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. + diff --git a/applications/plugins/uart_terminal/README.md b/applications/plugins/uart_terminal/README.md new file mode 100644 index 000000000..7e2cfd212 --- /dev/null +++ b/applications/plugins/uart_terminal/README.md @@ -0,0 +1,45 @@ +# UART Terminal for Flipper Zero +[Flipper Zero](https://flipperzero.one/) app to control various devices via UART interface. + +## Capabilities +- Read log and command output by uart +- Send commands by uart +- Set baud rate +- Fast commands + +## Connecting +| Flipper Zero pin | UART interface | +| ---------------- | --------------- | +| 13 TX | RX | +| 14 RX | TX | +|8, 18 GND | GND | + +Info: If possible, do not power your devices from 3V3 (pin 9) Flipper Zero. It does not support hot plugging. + +## Keyboard +UART_terminal uses its own special keyboard for work, which has all the symbols necessary for working in the console. + +To accommodate more characters on a small display, some characters are called up by holding. + +![kbf](https://user-images.githubusercontent.com/122148894/212286637-7063f1ee-c6ff-46b9-8dc5-79a5f367fab1.png) + + +## How to install +Copy the contents of the repository to the applications_user/uart_terminal folder Flipper Zero firmware and build app with the command ./fbt fap_uart_terminal. + +Or use the tool [uFBT](https://github.com/flipperdevices/flipperzero-ufbt) for building applications for Flipper Zero. + +## How it works + + +![1f](https://user-images.githubusercontent.com/122148894/211161450-6d177638-3bfa-42a8-9c73-0cf3af5e5ca7.jpg) + + +![2f](https://user-images.githubusercontent.com/122148894/211161456-4d2be15b-4a05-4450-a62e-edcaab3772fd.jpg) + + +![4f](https://user-images.githubusercontent.com/122148894/211161461-4507120b-42df-441f-9e01-e4517aa83537.jpg) + +## INFO: + +~70% of the source code is taken from the [Wifi Marauder](https://github.com/0xchocolate/flipperzero-firmware-with-wifi-marauder-companion) project. Many thanks to the developers of the Wifi Marauder project. diff --git a/applications/plugins/uart_terminal/application.fam b/applications/plugins/uart_terminal/application.fam new file mode 100644 index 000000000..a36960ea4 --- /dev/null +++ b/applications/plugins/uart_terminal/application.fam @@ -0,0 +1,13 @@ +App( + appid="uart_terminal", + name="[GPIO] UART Terminal", + apptype=FlipperAppType.EXTERNAL, + entry_point="uart_terminal_app", + cdefines=["APP_UART_TERMINAL"], + requires=["gui"], + stack_size=1 * 1024, + order=90, + fap_icon="uart_terminal.png", + fap_category="GPIO", + fap_icon_assets="assets", +) diff --git a/applications/plugins/uart_terminal/assets/KeyBackspaceSelected_16x9.png b/applications/plugins/uart_terminal/assets/KeyBackspaceSelected_16x9.png new file mode 100644 index 000000000..7cc0759a8 Binary files /dev/null and b/applications/plugins/uart_terminal/assets/KeyBackspaceSelected_16x9.png differ diff --git a/applications/plugins/uart_terminal/assets/KeyBackspace_16x9.png b/applications/plugins/uart_terminal/assets/KeyBackspace_16x9.png new file mode 100644 index 000000000..9946232d9 Binary files /dev/null and b/applications/plugins/uart_terminal/assets/KeyBackspace_16x9.png differ diff --git a/applications/plugins/uart_terminal/assets/KeySaveSelected_24x11.png b/applications/plugins/uart_terminal/assets/KeySaveSelected_24x11.png new file mode 100644 index 000000000..eeb3569d3 Binary files /dev/null and b/applications/plugins/uart_terminal/assets/KeySaveSelected_24x11.png differ diff --git a/applications/plugins/uart_terminal/assets/KeySave_24x11.png b/applications/plugins/uart_terminal/assets/KeySave_24x11.png new file mode 100644 index 000000000..e7dba987a Binary files /dev/null and b/applications/plugins/uart_terminal/assets/KeySave_24x11.png differ diff --git a/applications/plugins/uart_terminal/assets/WarningDolphin_45x42.png b/applications/plugins/uart_terminal/assets/WarningDolphin_45x42.png new file mode 100644 index 000000000..d766ffbb4 Binary files /dev/null and b/applications/plugins/uart_terminal/assets/WarningDolphin_45x42.png differ diff --git a/applications/plugins/uart_terminal/scenes/uart_terminal_scene.c b/applications/plugins/uart_terminal/scenes/uart_terminal_scene.c new file mode 100644 index 000000000..451c5d98b --- /dev/null +++ b/applications/plugins/uart_terminal/scenes/uart_terminal_scene.c @@ -0,0 +1,30 @@ +#include "uart_terminal_scene.h" + +// Generate scene on_enter handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter, +void (*const uart_terminal_scene_on_enter_handlers[])(void*) = { +#include "uart_terminal_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_event handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event, +bool (*const uart_terminal_scene_on_event_handlers[])(void* context, SceneManagerEvent event) = { +#include "uart_terminal_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_exit handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit, +void (*const uart_terminal_scene_on_exit_handlers[])(void* context) = { +#include "uart_terminal_scene_config.h" +}; +#undef ADD_SCENE + +// Initialize scene handlers configuration structure +const SceneManagerHandlers uart_terminal_scene_handlers = { + .on_enter_handlers = uart_terminal_scene_on_enter_handlers, + .on_event_handlers = uart_terminal_scene_on_event_handlers, + .on_exit_handlers = uart_terminal_scene_on_exit_handlers, + .scene_num = UART_TerminalSceneNum, +}; diff --git a/applications/plugins/subbrute/scenes/subbrute_scene.h b/applications/plugins/uart_terminal/scenes/uart_terminal_scene.h similarity index 64% rename from applications/plugins/subbrute/scenes/subbrute_scene.h rename to applications/plugins/uart_terminal/scenes/uart_terminal_scene.h index c048985e2..c6f4ed4b4 100644 --- a/applications/plugins/subbrute/scenes/subbrute_scene.h +++ b/applications/plugins/uart_terminal/scenes/uart_terminal_scene.h @@ -3,27 +3,27 @@ #include // Generate scene id and total number -#define ADD_SCENE(prefix, name, id) SubBruteScene##id, +#define ADD_SCENE(prefix, name, id) UART_TerminalScene##id, typedef enum { -#include "subbrute_scene_config.h" - SubBruteSceneNum, -} SubBruteScene; +#include "uart_terminal_scene_config.h" + UART_TerminalSceneNum, +} UART_TerminalScene; #undef ADD_SCENE -extern const SceneManagerHandlers subbrute_scene_handlers; +extern const SceneManagerHandlers uart_terminal_scene_handlers; // Generate scene on_enter handlers declaration #define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*); -#include "subbrute_scene_config.h" +#include "uart_terminal_scene_config.h" #undef ADD_SCENE // Generate scene on_event handlers declaration #define ADD_SCENE(prefix, name, id) \ bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event); -#include "subbrute_scene_config.h" +#include "uart_terminal_scene_config.h" #undef ADD_SCENE // Generate scene on_exit handlers declaration #define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context); -#include "subbrute_scene_config.h" +#include "uart_terminal_scene_config.h" #undef ADD_SCENE diff --git a/applications/plugins/uart_terminal/scenes/uart_terminal_scene_config.h b/applications/plugins/uart_terminal/scenes/uart_terminal_scene_config.h new file mode 100644 index 000000000..febdce167 --- /dev/null +++ b/applications/plugins/uart_terminal/scenes/uart_terminal_scene_config.h @@ -0,0 +1,3 @@ +ADD_SCENE(uart_terminal, start, Start) +ADD_SCENE(uart_terminal, console_output, ConsoleOutput) +ADD_SCENE(uart_terminal, text_input, UART_TextInput) diff --git a/applications/plugins/uart_terminal/scenes/uart_terminal_scene_console_output.c b/applications/plugins/uart_terminal/scenes/uart_terminal_scene_console_output.c new file mode 100644 index 000000000..a9f998124 --- /dev/null +++ b/applications/plugins/uart_terminal/scenes/uart_terminal_scene_console_output.c @@ -0,0 +1,147 @@ +#include "../uart_terminal_app_i.h" + +void uart_terminal_console_output_handle_rx_data_cb(uint8_t* buf, size_t len, void* context) { + furi_assert(context); + UART_TerminalApp* app = context; + + // If text box store gets too big, then truncate it + app->text_box_store_strlen += len; + if(app->text_box_store_strlen >= UART_TERMINAL_TEXT_BOX_STORE_SIZE - 1) { + furi_string_right(app->text_box_store, app->text_box_store_strlen / 2); + app->text_box_store_strlen = furi_string_size(app->text_box_store) + len; + } + + // Null-terminate buf and append to text box store + buf[len] = '\0'; + furi_string_cat_printf(app->text_box_store, "%s", buf); + + view_dispatcher_send_custom_event( + app->view_dispatcher, UART_TerminalEventRefreshConsoleOutput); +} + +void uart_terminal_scene_console_output_on_enter(void* context) { + UART_TerminalApp* app = context; + + TextBox* text_box = app->text_box; + text_box_reset(app->text_box); + text_box_set_font(text_box, TextBoxFontText); + if(app->focus_console_start) { + text_box_set_focus(text_box, TextBoxFocusStart); + } else { + text_box_set_focus(text_box, TextBoxFocusEnd); + } + + //Change baudrate /////////////////////////////////////////////////////////////////////////// + if(0 == strncmp("2400", app->selected_tx_string, strlen("2400")) && app->BAUDRATE != 2400) { + uart_terminal_uart_free(app->uart); + app->BAUDRATE = 2400; + app->uart = uart_terminal_uart_init(app); + } + if(0 == strncmp("9600", app->selected_tx_string, strlen("9600")) && app->BAUDRATE != 9600) { + uart_terminal_uart_free(app->uart); + app->BAUDRATE = 9600; + app->uart = uart_terminal_uart_init(app); + } + if(0 == strncmp("19200", app->selected_tx_string, strlen("19200")) && app->BAUDRATE != 19200) { + uart_terminal_uart_free(app->uart); + app->BAUDRATE = 19200; + app->uart = uart_terminal_uart_init(app); + } + if(0 == strncmp("38400", app->selected_tx_string, strlen("38400")) && app->BAUDRATE != 38400) { + uart_terminal_uart_free(app->uart); + app->BAUDRATE = 38400; + app->uart = uart_terminal_uart_init(app); + } + if(0 == strncmp("57600", app->selected_tx_string, strlen("57600")) && app->BAUDRATE != 57600) { + uart_terminal_uart_free(app->uart); + app->BAUDRATE = 57600; + app->uart = uart_terminal_uart_init(app); + } + if(0 == strncmp("115200", app->selected_tx_string, strlen("115200")) && + app->BAUDRATE != 115200) { + uart_terminal_uart_free(app->uart); + app->BAUDRATE = 115200; + app->uart = uart_terminal_uart_init(app); + } + if(0 == strncmp("230400", app->selected_tx_string, strlen("230400")) && + app->BAUDRATE != 230400) { + uart_terminal_uart_free(app->uart); + app->BAUDRATE = 230400; + app->uart = uart_terminal_uart_init(app); + } + if(0 == strncmp("460800", app->selected_tx_string, strlen("460800")) && + app->BAUDRATE != 460800) { + uart_terminal_uart_free(app->uart); + app->BAUDRATE = 460800; + app->uart = uart_terminal_uart_init(app); + } + if(0 == strncmp("921600", app->selected_tx_string, strlen("921600")) && + app->BAUDRATE != 921600) { + uart_terminal_uart_free(app->uart); + app->BAUDRATE = 921600; + app->uart = uart_terminal_uart_init(app); + } + ///////////////////////////////////////////////////////////////////////////////////////////////////// + + if(app->is_command) { + furi_string_reset(app->text_box_store); + app->text_box_store_strlen = 0; + + if(0 == strncmp("help", app->selected_tx_string, strlen("help"))) { + const char* help_msg = + "UART terminal for Flipper\n\nI'm in github: cool4uma\n\nThis app is a modified\nWiFi Marauder companion,\nThanks 0xchocolate(github)\nfor great code and app.\n\n"; + furi_string_cat_str(app->text_box_store, help_msg); + app->text_box_store_strlen += strlen(help_msg); + } + + if(app->show_stopscan_tip) { + const char* help_msg = "Press BACK to return\n"; + furi_string_cat_str(app->text_box_store, help_msg); + app->text_box_store_strlen += strlen(help_msg); + } + } + + // Set starting text - for "View Log", this will just be what was already in the text box store + text_box_set_text(app->text_box, furi_string_get_cstr(app->text_box_store)); + + scene_manager_set_scene_state(app->scene_manager, UART_TerminalSceneConsoleOutput, 0); + view_dispatcher_switch_to_view(app->view_dispatcher, UART_TerminalAppViewConsoleOutput); + + // Register callback to receive data + uart_terminal_uart_set_handle_rx_data_cb( + app->uart, uart_terminal_console_output_handle_rx_data_cb); // setup callback for rx thread + + // Send command with newline '\n' + if(app->is_command && app->selected_tx_string) { + uart_terminal_uart_tx( + (uint8_t*)(app->selected_tx_string), strlen(app->selected_tx_string)); + uart_terminal_uart_tx((uint8_t*)("\n"), 1); + } +} + +bool uart_terminal_scene_console_output_on_event(void* context, SceneManagerEvent event) { + UART_TerminalApp* app = context; + + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + text_box_set_text(app->text_box, furi_string_get_cstr(app->text_box_store)); + consumed = true; + } else if(event.type == SceneManagerEventTypeTick) { + consumed = true; + } + + return consumed; +} + +void uart_terminal_scene_console_output_on_exit(void* context) { + UART_TerminalApp* app = context; + + // Unregister rx callback + uart_terminal_uart_set_handle_rx_data_cb(app->uart, NULL); + + // Automatically logut when exiting view + //if(app->is_command) { + // uart_terminal_uart_tx((uint8_t*)("exit\n"), strlen("exit\n")); + //} +} diff --git a/applications/plugins/uart_terminal/scenes/uart_terminal_scene_start.c b/applications/plugins/uart_terminal/scenes/uart_terminal_scene_start.c new file mode 100644 index 000000000..db783e9b2 --- /dev/null +++ b/applications/plugins/uart_terminal/scenes/uart_terminal_scene_start.c @@ -0,0 +1,137 @@ +#include "../uart_terminal_app_i.h" + +// For each command, define whether additional arguments are needed +// (enabling text input to fill them out), and whether the console +// text box should focus at the start of the output or the end +typedef enum { NO_ARGS = 0, INPUT_ARGS, TOGGLE_ARGS } InputArgs; + +typedef enum { FOCUS_CONSOLE_END = 0, FOCUS_CONSOLE_START, FOCUS_CONSOLE_TOGGLE } FocusConsole; + +#define SHOW_STOPSCAN_TIP (true) +#define NO_TIP (false) + +#define MAX_OPTIONS (9) +typedef struct { + const char* item_string; + const char* options_menu[MAX_OPTIONS]; + int num_options_menu; + const char* actual_commands[MAX_OPTIONS]; + InputArgs needs_keyboard; + FocusConsole focus_console; + bool show_stopscan_tip; +} UART_TerminalItem; + +// NUM_MENU_ITEMS defined in uart_terminal_app_i.h - if you add an entry here, increment it! +const UART_TerminalItem items[NUM_MENU_ITEMS] = { + {"Console", + {"115200", "2400", "9600", "19200", "38400", "57600", "230400", "460800", "921600"}, + 9, + {"115200", "2400", "9600", "19200", "38400", "57600", "230400", "460800", "921600"}, + NO_ARGS, + FOCUS_CONSOLE_TOGGLE, + NO_TIP}, + {"Send command", {""}, 1, {""}, INPUT_ARGS, FOCUS_CONSOLE_END, NO_TIP}, + {"Fast cmd", + {"help", "uptime", "date", "df -h", "ps", "dmesg", "reboot", "poweroff"}, + 8, + {"help", "uptime", "date", "df -h", "ps", "dmesg", "reboot", "poweroff"}, + INPUT_ARGS, + FOCUS_CONSOLE_END, + NO_TIP}, + {"Help", {""}, 1, {"help"}, NO_ARGS, FOCUS_CONSOLE_START, SHOW_STOPSCAN_TIP}, +}; + +static void uart_terminal_scene_start_var_list_enter_callback(void* context, uint32_t index) { + furi_assert(context); + UART_TerminalApp* app = context; + + furi_assert(index < NUM_MENU_ITEMS); + const UART_TerminalItem* item = &items[index]; + + const int selected_option_index = app->selected_option_index[index]; + furi_assert(selected_option_index < item->num_options_menu); + app->selected_tx_string = item->actual_commands[selected_option_index]; + app->is_command = (1 <= index); + app->is_custom_tx_string = false; + app->selected_menu_index = index; + app->focus_console_start = (item->focus_console == FOCUS_CONSOLE_TOGGLE) ? + (selected_option_index == 0) : + item->focus_console; + app->show_stopscan_tip = item->show_stopscan_tip; + + bool needs_keyboard = (item->needs_keyboard == TOGGLE_ARGS) ? (selected_option_index != 0) : + item->needs_keyboard; + if(needs_keyboard) { + view_dispatcher_send_custom_event(app->view_dispatcher, UART_TerminalEventStartKeyboard); + } else { + view_dispatcher_send_custom_event(app->view_dispatcher, UART_TerminalEventStartConsole); + } +} + +static void uart_terminal_scene_start_var_list_change_callback(VariableItem* item) { + furi_assert(item); + + UART_TerminalApp* app = variable_item_get_context(item); + furi_assert(app); + + const UART_TerminalItem* menu_item = &items[app->selected_menu_index]; + uint8_t item_index = variable_item_get_current_value_index(item); + furi_assert(item_index < menu_item->num_options_menu); + variable_item_set_current_value_text(item, menu_item->options_menu[item_index]); + app->selected_option_index[app->selected_menu_index] = item_index; +} + +void uart_terminal_scene_start_on_enter(void* context) { + UART_TerminalApp* app = context; + VariableItemList* var_item_list = app->var_item_list; + + variable_item_list_set_enter_callback( + var_item_list, uart_terminal_scene_start_var_list_enter_callback, app); + + VariableItem* item; + for(int i = 0; i < NUM_MENU_ITEMS; ++i) { + item = variable_item_list_add( + var_item_list, + items[i].item_string, + items[i].num_options_menu, + uart_terminal_scene_start_var_list_change_callback, + app); + variable_item_set_current_value_index(item, app->selected_option_index[i]); + variable_item_set_current_value_text( + item, items[i].options_menu[app->selected_option_index[i]]); + } + + variable_item_list_set_selected_item( + var_item_list, scene_manager_get_scene_state(app->scene_manager, UART_TerminalSceneStart)); + + view_dispatcher_switch_to_view(app->view_dispatcher, UART_TerminalAppViewVarItemList); +} + +bool uart_terminal_scene_start_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + UART_TerminalApp* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == UART_TerminalEventStartKeyboard) { + scene_manager_set_scene_state( + app->scene_manager, UART_TerminalSceneStart, app->selected_menu_index); + scene_manager_next_scene(app->scene_manager, UART_TerminalAppViewTextInput); + } else if(event.event == UART_TerminalEventStartConsole) { + scene_manager_set_scene_state( + app->scene_manager, UART_TerminalSceneStart, app->selected_menu_index); + scene_manager_next_scene(app->scene_manager, UART_TerminalAppViewConsoleOutput); + } + consumed = true; + } else if(event.type == SceneManagerEventTypeTick) { + app->selected_menu_index = variable_item_list_get_selected_item_index(app->var_item_list); + consumed = true; + } + + return consumed; +} + +void uart_terminal_scene_start_on_exit(void* context) { + UART_TerminalApp* app = context; + variable_item_list_reset(app->var_item_list); +} diff --git a/applications/plugins/uart_terminal/scenes/uart_terminal_scene_text_input.c b/applications/plugins/uart_terminal/scenes/uart_terminal_scene_text_input.c new file mode 100644 index 000000000..62c0792d4 --- /dev/null +++ b/applications/plugins/uart_terminal/scenes/uart_terminal_scene_text_input.c @@ -0,0 +1,60 @@ +#include "../uart_terminal_app_i.h" + +void uart_terminal_scene_text_input_callback(void* context) { + UART_TerminalApp* app = context; + + view_dispatcher_send_custom_event(app->view_dispatcher, UART_TerminalEventStartConsole); +} + +void uart_terminal_scene_text_input_on_enter(void* context) { + UART_TerminalApp* app = context; + + if(false == app->is_custom_tx_string) { + // Fill text input with selected string so that user can add to it + size_t length = strlen(app->selected_tx_string); + furi_assert(length < UART_TERMINAL_TEXT_INPUT_STORE_SIZE); + bzero(app->text_input_store, UART_TERMINAL_TEXT_INPUT_STORE_SIZE); + strncpy(app->text_input_store, app->selected_tx_string, length); + + // Add space - because flipper keyboard currently doesn't have a space + //app->text_input_store[length] = ' '; + app->text_input_store[length + 1] = '\0'; + app->is_custom_tx_string = true; + } + + // Setup view + UART_TextInput* text_input = app->text_input; + // Add help message to header + uart_text_input_set_header_text(text_input, "Send command to UART"); + uart_text_input_set_result_callback( + text_input, + uart_terminal_scene_text_input_callback, + app, + app->text_input_store, + UART_TERMINAL_TEXT_INPUT_STORE_SIZE, + false); + + view_dispatcher_switch_to_view(app->view_dispatcher, UART_TerminalAppViewTextInput); +} + +bool uart_terminal_scene_text_input_on_event(void* context, SceneManagerEvent event) { + UART_TerminalApp* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == UART_TerminalEventStartConsole) { + // Point to custom string to send + app->selected_tx_string = app->text_input_store; + scene_manager_next_scene(app->scene_manager, UART_TerminalAppViewConsoleOutput); + consumed = true; + } + } + + return consumed; +} + +void uart_terminal_scene_text_input_on_exit(void* context) { + UART_TerminalApp* app = context; + + uart_text_input_reset(app->text_input); +} diff --git a/applications/plugins/uart_terminal/uart_terminal.png b/applications/plugins/uart_terminal/uart_terminal.png new file mode 100644 index 000000000..8420f5692 Binary files /dev/null and b/applications/plugins/uart_terminal/uart_terminal.png differ diff --git a/applications/plugins/uart_terminal/uart_terminal_app.c b/applications/plugins/uart_terminal/uart_terminal_app.c new file mode 100644 index 000000000..2c18c5bae --- /dev/null +++ b/applications/plugins/uart_terminal/uart_terminal_app.c @@ -0,0 +1,104 @@ +#include "uart_terminal_app_i.h" + +#include +#include + +static bool uart_terminal_app_custom_event_callback(void* context, uint32_t event) { + furi_assert(context); + UART_TerminalApp* app = context; + return scene_manager_handle_custom_event(app->scene_manager, event); +} + +static bool uart_terminal_app_back_event_callback(void* context) { + furi_assert(context); + UART_TerminalApp* app = context; + return scene_manager_handle_back_event(app->scene_manager); +} + +static void uart_terminal_app_tick_event_callback(void* context) { + furi_assert(context); + UART_TerminalApp* app = context; + scene_manager_handle_tick_event(app->scene_manager); +} + +UART_TerminalApp* uart_terminal_app_alloc() { + UART_TerminalApp* app = malloc(sizeof(UART_TerminalApp)); + + app->gui = furi_record_open(RECORD_GUI); + + app->view_dispatcher = view_dispatcher_alloc(); + app->scene_manager = scene_manager_alloc(&uart_terminal_scene_handlers, app); + view_dispatcher_enable_queue(app->view_dispatcher); + view_dispatcher_set_event_callback_context(app->view_dispatcher, app); + + view_dispatcher_set_custom_event_callback( + app->view_dispatcher, uart_terminal_app_custom_event_callback); + view_dispatcher_set_navigation_event_callback( + app->view_dispatcher, uart_terminal_app_back_event_callback); + view_dispatcher_set_tick_event_callback( + app->view_dispatcher, uart_terminal_app_tick_event_callback, 100); + + view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); + + app->var_item_list = variable_item_list_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, + UART_TerminalAppViewVarItemList, + variable_item_list_get_view(app->var_item_list)); + + for(int i = 0; i < NUM_MENU_ITEMS; ++i) { + app->selected_option_index[i] = 0; + } + + app->text_box = text_box_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, UART_TerminalAppViewConsoleOutput, text_box_get_view(app->text_box)); + app->text_box_store = furi_string_alloc(); + furi_string_reserve(app->text_box_store, UART_TERMINAL_TEXT_BOX_STORE_SIZE); + + app->text_input = uart_text_input_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, + UART_TerminalAppViewTextInput, + uart_text_input_get_view(app->text_input)); + + scene_manager_next_scene(app->scene_manager, UART_TerminalSceneStart); + + return app; +} + +void uart_terminal_app_free(UART_TerminalApp* app) { + furi_assert(app); + + // Views + view_dispatcher_remove_view(app->view_dispatcher, UART_TerminalAppViewVarItemList); + view_dispatcher_remove_view(app->view_dispatcher, UART_TerminalAppViewConsoleOutput); + view_dispatcher_remove_view(app->view_dispatcher, UART_TerminalAppViewTextInput); + text_box_free(app->text_box); + furi_string_free(app->text_box_store); + uart_text_input_free(app->text_input); + + // View dispatcher + view_dispatcher_free(app->view_dispatcher); + scene_manager_free(app->scene_manager); + + uart_terminal_uart_free(app->uart); + + // Close records + furi_record_close(RECORD_GUI); + + free(app); +} + +int32_t uart_terminal_app(void* p) { + UNUSED(p); + UART_TerminalApp* uart_terminal_app = uart_terminal_app_alloc(); + + uart_terminal_app->uart = uart_terminal_uart_init(uart_terminal_app); + + view_dispatcher_run(uart_terminal_app->view_dispatcher); + + uart_terminal_app_free(uart_terminal_app); + + return 0; +} diff --git a/applications/plugins/uart_terminal/uart_terminal_app.h b/applications/plugins/uart_terminal/uart_terminal_app.h new file mode 100644 index 000000000..c859d828b --- /dev/null +++ b/applications/plugins/uart_terminal/uart_terminal_app.h @@ -0,0 +1,11 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct UART_TerminalApp UART_TerminalApp; + +#ifdef __cplusplus +} +#endif diff --git a/applications/plugins/uart_terminal/uart_terminal_app_i.h b/applications/plugins/uart_terminal/uart_terminal_app_i.h new file mode 100644 index 000000000..6b1996eb5 --- /dev/null +++ b/applications/plugins/uart_terminal/uart_terminal_app_i.h @@ -0,0 +1,49 @@ +#pragma once + +#include "uart_terminal_app.h" +#include "scenes/uart_terminal_scene.h" +#include "uart_terminal_custom_event.h" +#include "uart_terminal_uart.h" + +#include +#include +#include +#include +#include +#include "uart_text_input.h" + +#define NUM_MENU_ITEMS (4) + +#define UART_TERMINAL_TEXT_BOX_STORE_SIZE (4096) +#define UART_TERMINAL_TEXT_INPUT_STORE_SIZE (512) +#define UART_CH (FuriHalUartIdUSART1) + +struct UART_TerminalApp { + Gui* gui; + ViewDispatcher* view_dispatcher; + SceneManager* scene_manager; + + char text_input_store[UART_TERMINAL_TEXT_INPUT_STORE_SIZE + 1]; + FuriString* text_box_store; + size_t text_box_store_strlen; + TextBox* text_box; + UART_TextInput* text_input; + + VariableItemList* var_item_list; + + UART_TerminalUart* uart; + int selected_menu_index; + int selected_option_index[NUM_MENU_ITEMS]; + const char* selected_tx_string; + bool is_command; + bool is_custom_tx_string; + bool focus_console_start; + bool show_stopscan_tip; + int BAUDRATE; +}; + +typedef enum { + UART_TerminalAppViewVarItemList, + UART_TerminalAppViewConsoleOutput, + UART_TerminalAppViewTextInput, +} UART_TerminalAppView; diff --git a/applications/plugins/uart_terminal/uart_terminal_custom_event.h b/applications/plugins/uart_terminal/uart_terminal_custom_event.h new file mode 100644 index 000000000..d57d822d1 --- /dev/null +++ b/applications/plugins/uart_terminal/uart_terminal_custom_event.h @@ -0,0 +1,7 @@ +#pragma once + +typedef enum { + UART_TerminalEventRefreshConsoleOutput = 0, + UART_TerminalEventStartConsole, + UART_TerminalEventStartKeyboard, +} UART_TerminalCustomEvent; diff --git a/applications/plugins/uart_terminal/uart_terminal_uart.c b/applications/plugins/uart_terminal/uart_terminal_uart.c new file mode 100644 index 000000000..136bd5d38 --- /dev/null +++ b/applications/plugins/uart_terminal/uart_terminal_uart.c @@ -0,0 +1,97 @@ +#include "uart_terminal_app_i.h" +#include "uart_terminal_uart.h" + +//#define UART_CH (FuriHalUartIdUSART1) +//#define BAUDRATE (115200) + +struct UART_TerminalUart { + UART_TerminalApp* app; + FuriThread* rx_thread; + FuriStreamBuffer* rx_stream; + uint8_t rx_buf[RX_BUF_SIZE + 1]; + void (*handle_rx_data_cb)(uint8_t* buf, size_t len, void* context); +}; + +typedef enum { + WorkerEvtStop = (1 << 0), + WorkerEvtRxDone = (1 << 1), +} WorkerEvtFlags; + +void uart_terminal_uart_set_handle_rx_data_cb( + UART_TerminalUart* uart, + void (*handle_rx_data_cb)(uint8_t* buf, size_t len, void* context)) { + furi_assert(uart); + uart->handle_rx_data_cb = handle_rx_data_cb; +} + +#define WORKER_ALL_RX_EVENTS (WorkerEvtStop | WorkerEvtRxDone) + +void uart_terminal_uart_on_irq_cb(UartIrqEvent ev, uint8_t data, void* context) { + UART_TerminalUart* uart = (UART_TerminalUart*)context; + + if(ev == UartIrqEventRXNE) { + furi_stream_buffer_send(uart->rx_stream, &data, 1, 0); + furi_thread_flags_set(furi_thread_get_id(uart->rx_thread), WorkerEvtRxDone); + } +} + +static int32_t uart_worker(void* context) { + UART_TerminalUart* uart = (void*)context; + + uart->rx_stream = furi_stream_buffer_alloc(RX_BUF_SIZE, 1); + + while(1) { + uint32_t events = + furi_thread_flags_wait(WORKER_ALL_RX_EVENTS, FuriFlagWaitAny, FuriWaitForever); + furi_check((events & FuriFlagError) == 0); + if(events & WorkerEvtStop) break; + if(events & WorkerEvtRxDone) { + size_t len = furi_stream_buffer_receive(uart->rx_stream, uart->rx_buf, RX_BUF_SIZE, 0); + if(len > 0) { + if(uart->handle_rx_data_cb) uart->handle_rx_data_cb(uart->rx_buf, len, uart->app); + } + } + } + + furi_stream_buffer_free(uart->rx_stream); + + return 0; +} + +void uart_terminal_uart_tx(uint8_t* data, size_t len) { + furi_hal_uart_tx(UART_CH, data, len); +} + +UART_TerminalUart* uart_terminal_uart_init(UART_TerminalApp* app) { + UART_TerminalUart* uart = malloc(sizeof(UART_TerminalUart)); + + furi_hal_console_disable(); + if(app->BAUDRATE == 0) { + app->BAUDRATE = 115200; + } + furi_hal_uart_set_br(UART_CH, app->BAUDRATE); + furi_hal_uart_set_irq_cb(UART_CH, uart_terminal_uart_on_irq_cb, uart); + + uart->app = app; + uart->rx_thread = furi_thread_alloc(); + furi_thread_set_name(uart->rx_thread, "UART_TerminalUartRxThread"); + furi_thread_set_stack_size(uart->rx_thread, 1024); + furi_thread_set_context(uart->rx_thread, uart); + furi_thread_set_callback(uart->rx_thread, uart_worker); + + furi_thread_start(uart->rx_thread); + return uart; +} + +void uart_terminal_uart_free(UART_TerminalUart* uart) { + furi_assert(uart); + + furi_thread_flags_set(furi_thread_get_id(uart->rx_thread), WorkerEvtStop); + furi_thread_join(uart->rx_thread); + furi_thread_free(uart->rx_thread); + + furi_hal_uart_set_irq_cb(UART_CH, NULL, NULL); + furi_hal_console_enable(); + + free(uart); +} \ No newline at end of file diff --git a/applications/plugins/uart_terminal/uart_terminal_uart.h b/applications/plugins/uart_terminal/uart_terminal_uart.h new file mode 100644 index 000000000..ca95c92fb --- /dev/null +++ b/applications/plugins/uart_terminal/uart_terminal_uart.h @@ -0,0 +1,14 @@ +#pragma once + +#include "furi_hal.h" + +#define RX_BUF_SIZE (320) + +typedef struct UART_TerminalUart UART_TerminalUart; + +void uart_terminal_uart_set_handle_rx_data_cb( + UART_TerminalUart* uart, + void (*handle_rx_data_cb)(uint8_t* buf, size_t len, void* context)); +void uart_terminal_uart_tx(uint8_t* data, size_t len); +UART_TerminalUart* uart_terminal_uart_init(UART_TerminalApp* app); +void uart_terminal_uart_free(UART_TerminalUart* uart); diff --git a/applications/plugins/uart_terminal/uart_text_input.c b/applications/plugins/uart_terminal/uart_text_input.c new file mode 100644 index 000000000..4a571b127 --- /dev/null +++ b/applications/plugins/uart_terminal/uart_text_input.c @@ -0,0 +1,637 @@ +#include "uart_text_input.h" +#include +#include "uart_terminal_icons.h" +#include + +struct UART_TextInput { + View* view; + FuriTimer* timer; +}; + +typedef struct { + const char text; + const uint8_t x; + const uint8_t y; +} UART_TextInputKey; + +typedef struct { + const char* header; + char* text_buffer; + size_t text_buffer_size; + bool clear_default_text; + + UART_TextInputCallback callback; + void* callback_context; + + uint8_t selected_row; + uint8_t selected_column; + + UART_TextInputValidatorCallback validator_callback; + void* validator_callback_context; + FuriString* validator_text; + bool valadator_message_visible; +} UART_TextInputModel; + +static const uint8_t keyboard_origin_x = 1; +static const uint8_t keyboard_origin_y = 29; +static const uint8_t keyboard_row_count = 4; + +#define ENTER_KEY '\r' +#define BACKSPACE_KEY '\b' + +static const UART_TextInputKey keyboard_keys_row_1[] = { + {'{', 1, 0}, + {'(', 9, 0}, + {'[', 17, 0}, + {'|', 25, 0}, + {'@', 33, 0}, + {'&', 41, 0}, + {'#', 49, 0}, + {';', 57, 0}, + {'^', 65, 0}, + {'*', 73, 0}, + {'`', 81, 0}, + {'"', 89, 0}, + {'~', 97, 0}, + {'\'', 105, 0}, + {'.', 113, 0}, + {'/', 120, 0}, +}; + +static const UART_TextInputKey keyboard_keys_row_2[] = { + {'q', 1, 10}, + {'w', 9, 10}, + {'e', 17, 10}, + {'r', 25, 10}, + {'t', 33, 10}, + {'y', 41, 10}, + {'u', 49, 10}, + {'i', 57, 10}, + {'o', 65, 10}, + {'p', 73, 10}, + {'0', 81, 10}, + {'1', 89, 10}, + {'2', 97, 10}, + {'3', 105, 10}, + {'=', 113, 10}, + {'-', 120, 10}, +}; + +static const UART_TextInputKey keyboard_keys_row_3[] = { + {'a', 1, 21}, + {'s', 9, 21}, + {'d', 18, 21}, + {'f', 25, 21}, + {'g', 33, 21}, + {'h', 41, 21}, + {'j', 49, 21}, + {'k', 57, 21}, + {'l', 65, 21}, + {BACKSPACE_KEY, 72, 13}, + {'4', 89, 21}, + {'5', 97, 21}, + {'6', 105, 21}, + {'$', 113, 21}, + {'%', 120, 21}, + +}; + +static const UART_TextInputKey keyboard_keys_row_4[] = { + {'z', 1, 33}, + {'x', 9, 33}, + {'c', 18, 33}, + {'v', 25, 33}, + {'b', 33, 33}, + {'n', 41, 33}, + {'m', 49, 33}, + {'_', 57, 33}, + {ENTER_KEY, 64, 24}, + {'7', 89, 33}, + {'8', 97, 33}, + {'9', 105, 33}, + {'!', 113, 33}, + {'+', 120, 33}, +}; + +static uint8_t get_row_size(uint8_t row_index) { + uint8_t row_size = 0; + + switch(row_index + 1) { + case 1: + row_size = sizeof(keyboard_keys_row_1) / sizeof(UART_TextInputKey); + break; + case 2: + row_size = sizeof(keyboard_keys_row_2) / sizeof(UART_TextInputKey); + break; + case 3: + row_size = sizeof(keyboard_keys_row_3) / sizeof(UART_TextInputKey); + break; + case 4: + row_size = sizeof(keyboard_keys_row_4) / sizeof(UART_TextInputKey); + break; + } + + return row_size; +} + +static const UART_TextInputKey* get_row(uint8_t row_index) { + const UART_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; + } + + return row; +} + +static char get_selected_char(UART_TextInputModel* model) { + return get_row(model->selected_row)[model->selected_column].text; +} + +static bool char_is_lowercase(char letter) { + return (letter >= 0x61 && letter <= 0x7A); +} + +static char char_to_uppercase(const char letter) { + switch(letter) { + case '_': + 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(isalpha(letter)) { + return (letter - 0x20); + } else { + return letter; + } +} + +static void uart_text_input_backspace_cb(UART_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; + } +} + +static void uart_text_input_view_draw_callback(Canvas* canvas, void* _model) { + UART_TextInputModel* model = _model; + 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; + + 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); + + 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++; + } + + if(model->clear_default_text) { + elements_slightly_rounded_box( + canvas, start_pos - 1, 14, canvas_string_width(canvas, text) + 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, "|"); + } + canvas_draw_str(canvas, start_pos, 17, text); + + 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 UART_TextInputKey* keys = get_row(row); + + for(size_t column = 0; column < column_count; column++) { + 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); + } + } 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); + } + } else { + if(model->selected_row == row && model->selected_column == column) { + canvas_set_color(canvas, ColorBlack); + canvas_draw_box( + canvas, + keyboard_origin_x + keys[column].x - 1, + keyboard_origin_y + keys[column].y - 8, + 7, + 10); + canvas_set_color(canvas, ColorWhite); + } else { + canvas_set_color(canvas, ColorBlack); + } + + if(model->clear_default_text || + (text_length == 0 && char_is_lowercase(keys[column].text))) { + canvas_draw_glyph( + canvas, + keyboard_origin_x + keys[column].x, + keyboard_origin_y + keys[column].y, + //char_to_uppercase(keys[column].text)); + 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) { + canvas_set_font(canvas, FontSecondary); + canvas_set_color(canvas, ColorWhite); + canvas_draw_box(canvas, 8, 10, 110, 48); + canvas_set_color(canvas, ColorBlack); + canvas_draw_icon(canvas, 10, 14, &I_WarningDolphin_45x42); + canvas_draw_rframe(canvas, 8, 8, 112, 50, 3); + canvas_draw_rframe(canvas, 9, 9, 110, 48, 2); + elements_multiline_text(canvas, 62, 20, furi_string_get_cstr(model->validator_text)); + canvas_set_font(canvas, FontKeyboard); + } +} + +static void + uart_text_input_handle_up(UART_TextInput* uart_text_input, UART_TextInputModel* model) { + UNUSED(uart_text_input); + if(model->selected_row > 0) { + model->selected_row--; + if(model->selected_column > get_row_size(model->selected_row) - 6) { + model->selected_column = model->selected_column + 1; + } + } +} + +static void + uart_text_input_handle_down(UART_TextInput* uart_text_input, UART_TextInputModel* model) { + UNUSED(uart_text_input); + if(model->selected_row < keyboard_row_count - 1) { + model->selected_row++; + if(model->selected_column > get_row_size(model->selected_row) - 4) { + model->selected_column = model->selected_column - 1; + } + } +} + +static void + uart_text_input_handle_left(UART_TextInput* uart_text_input, UART_TextInputModel* model) { + UNUSED(uart_text_input); + if(model->selected_column > 0) { + model->selected_column--; + } else { + model->selected_column = get_row_size(model->selected_row) - 1; + } +} + +static void + uart_text_input_handle_right(UART_TextInput* uart_text_input, UART_TextInputModel* model) { + UNUSED(uart_text_input); + if(model->selected_column < get_row_size(model->selected_row) - 1) { + model->selected_column++; + } else { + model->selected_column = 0; + } +} + +static void uart_text_input_handle_ok( + UART_TextInput* uart_text_input, + UART_TextInputModel* model, + bool shift) { + char selected = get_selected_char(model); + uint8_t text_length = strlen(model->text_buffer); + + if(shift) { + selected = char_to_uppercase(selected); + } + + 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; + furi_timer_start(uart_text_input->timer, furi_kernel_get_tick_frequency() * 4); + } else if(model->callback != 0 && text_length > 0) { + model->callback(model->callback_context); + } + } else if(selected == BACKSPACE_KEY) { + uart_text_input_backspace_cb(model); + } else { + if(model->clear_default_text) { + text_length = 0; + } + if(text_length < (model->text_buffer_size - 1)) { + if(text_length == 0 && char_is_lowercase(selected)) { + //selected = char_to_uppercase(selected); + } + model->text_buffer[text_length] = selected; + model->text_buffer[text_length + 1] = 0; + } + } + model->clear_default_text = false; +} + +static bool uart_text_input_view_input_callback(InputEvent* event, void* context) { + UART_TextInput* uart_text_input = context; + furi_assert(uart_text_input); + + bool consumed = false; + + // Acquire model + UART_TextInputModel* model = view_get_model(uart_text_input->view); + + if((!(event->type == InputTypePress) && !(event->type == InputTypeRelease)) && + model->valadator_message_visible) { + model->valadator_message_visible = false; + consumed = true; + } else if(event->type == InputTypeShort) { + consumed = true; + switch(event->key) { + case InputKeyUp: + uart_text_input_handle_up(uart_text_input, model); + break; + case InputKeyDown: + uart_text_input_handle_down(uart_text_input, model); + break; + case InputKeyLeft: + uart_text_input_handle_left(uart_text_input, model); + break; + case InputKeyRight: + uart_text_input_handle_right(uart_text_input, model); + break; + case InputKeyOk: + uart_text_input_handle_ok(uart_text_input, model, false); + break; + default: + consumed = false; + break; + } + } else if(event->type == InputTypeLong) { + consumed = true; + switch(event->key) { + case InputKeyUp: + uart_text_input_handle_up(uart_text_input, model); + break; + case InputKeyDown: + uart_text_input_handle_down(uart_text_input, model); + break; + case InputKeyLeft: + uart_text_input_handle_left(uart_text_input, model); + break; + case InputKeyRight: + uart_text_input_handle_right(uart_text_input, model); + break; + case InputKeyOk: + uart_text_input_handle_ok(uart_text_input, model, true); + break; + case InputKeyBack: + uart_text_input_backspace_cb(model); + break; + default: + consumed = false; + break; + } + } else if(event->type == InputTypeRepeat) { + consumed = true; + switch(event->key) { + case InputKeyUp: + uart_text_input_handle_up(uart_text_input, model); + break; + case InputKeyDown: + uart_text_input_handle_down(uart_text_input, model); + break; + case InputKeyLeft: + uart_text_input_handle_left(uart_text_input, model); + break; + case InputKeyRight: + uart_text_input_handle_right(uart_text_input, model); + break; + case InputKeyBack: + uart_text_input_backspace_cb(model); + break; + default: + consumed = false; + break; + } + } + + // Commit model + view_commit_model(uart_text_input->view, consumed); + + return consumed; +} + +void uart_text_input_timer_callback(void* context) { + furi_assert(context); + UART_TextInput* uart_text_input = context; + + with_view_model( + uart_text_input->view, + UART_TextInputModel * model, + { model->valadator_message_visible = false; }, + true); +} + +UART_TextInput* uart_text_input_alloc() { + UART_TextInput* uart_text_input = malloc(sizeof(UART_TextInput)); + uart_text_input->view = view_alloc(); + view_set_context(uart_text_input->view, uart_text_input); + view_allocate_model(uart_text_input->view, ViewModelTypeLocking, sizeof(UART_TextInputModel)); + view_set_draw_callback(uart_text_input->view, uart_text_input_view_draw_callback); + view_set_input_callback(uart_text_input->view, uart_text_input_view_input_callback); + + uart_text_input->timer = + furi_timer_alloc(uart_text_input_timer_callback, FuriTimerTypeOnce, uart_text_input); + + with_view_model( + uart_text_input->view, + UART_TextInputModel * model, + { model->validator_text = furi_string_alloc(); }, + false); + + uart_text_input_reset(uart_text_input); + + return uart_text_input; +} + +void uart_text_input_free(UART_TextInput* uart_text_input) { + furi_assert(uart_text_input); + with_view_model( + uart_text_input->view, + UART_TextInputModel * model, + { furi_string_free(model->validator_text); }, + false); + + // Send stop command + furi_timer_stop(uart_text_input->timer); + // Release allocated memory + furi_timer_free(uart_text_input->timer); + + view_free(uart_text_input->view); + + free(uart_text_input); +} + +void uart_text_input_reset(UART_TextInput* uart_text_input) { + furi_assert(uart_text_input); + with_view_model( + uart_text_input->view, + UART_TextInputModel * model, + { + model->text_buffer_size = 0; + model->header = ""; + model->selected_row = 0; + model->selected_column = 0; + model->clear_default_text = false; + model->text_buffer = NULL; + model->text_buffer_size = 0; + model->callback = NULL; + model->callback_context = NULL; + model->validator_callback = NULL; + model->validator_callback_context = NULL; + furi_string_reset(model->validator_text); + model->valadator_message_visible = false; + }, + true); +} + +View* uart_text_input_get_view(UART_TextInput* uart_text_input) { + furi_assert(uart_text_input); + return uart_text_input->view; +} + +void uart_text_input_set_result_callback( + UART_TextInput* uart_text_input, + UART_TextInputCallback callback, + void* callback_context, + char* text_buffer, + size_t text_buffer_size, + bool clear_default_text) { + with_view_model( + uart_text_input->view, + UART_TextInputModel * model, + { + model->callback = callback; + model->callback_context = callback_context; + model->text_buffer = text_buffer; + model->text_buffer_size = text_buffer_size; + model->clear_default_text = clear_default_text; + if(text_buffer && text_buffer[0] != '\0') { + // Set focus on Save + model->selected_row = 2; + model->selected_column = 8; + } + }, + true); +} + +void uart_text_input_set_validator( + UART_TextInput* uart_text_input, + UART_TextInputValidatorCallback callback, + void* callback_context) { + with_view_model( + uart_text_input->view, + UART_TextInputModel * model, + { + model->validator_callback = callback; + model->validator_callback_context = callback_context; + }, + true); +} + +UART_TextInputValidatorCallback + uart_text_input_get_validator_callback(UART_TextInput* uart_text_input) { + UART_TextInputValidatorCallback validator_callback = NULL; + with_view_model( + uart_text_input->view, + UART_TextInputModel * model, + { validator_callback = model->validator_callback; }, + false); + return validator_callback; +} + +void* uart_text_input_get_validator_callback_context(UART_TextInput* uart_text_input) { + void* validator_callback_context = NULL; + with_view_model( + uart_text_input->view, + UART_TextInputModel * model, + { validator_callback_context = model->validator_callback_context; }, + false); + return validator_callback_context; +} + +void uart_text_input_set_header_text(UART_TextInput* uart_text_input, const char* text) { + with_view_model( + uart_text_input->view, UART_TextInputModel * model, { model->header = text; }, true); +} diff --git a/applications/plugins/uart_terminal/uart_text_input.h b/applications/plugins/uart_terminal/uart_text_input.h new file mode 100644 index 000000000..f3703ed5a --- /dev/null +++ b/applications/plugins/uart_terminal/uart_text_input.h @@ -0,0 +1,82 @@ +#pragma once + +#include +#include "uart_validators.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Text input anonymous structure */ +typedef struct UART_TextInput UART_TextInput; +typedef void (*UART_TextInputCallback)(void* context); +typedef bool (*UART_TextInputValidatorCallback)(const char* text, FuriString* error, void* context); + +/** Allocate and initialize text input + * + * This text input is used to enter string + * + * @return UART_TextInput instance + */ +UART_TextInput* uart_text_input_alloc(); + +/** Deinitialize and free text input + * + * @param uart_text_input UART_TextInput instance + */ +void uart_text_input_free(UART_TextInput* uart_text_input); + +/** Clean text input view Note: this function does not free memory + * + * @param uart_text_input Text input instance + */ +void uart_text_input_reset(UART_TextInput* uart_text_input); + +/** Get text input view + * + * @param uart_text_input UART_TextInput instance + * + * @return View instance that can be used for embedding + */ +View* uart_text_input_get_view(UART_TextInput* uart_text_input); + +/** Set text input result callback + * + * @param uart_text_input UART_TextInput instance + * @param callback callback fn + * @param callback_context callback context + * @param text_buffer pointer to YOUR text buffer, that we going + * to modify + * @param text_buffer_size YOUR text buffer size in bytes. Max string + * length will be text_buffer_size-1. + * @param clear_default_text clear text from text_buffer on first OK + * event + */ +void uart_text_input_set_result_callback( + UART_TextInput* uart_text_input, + UART_TextInputCallback callback, + void* callback_context, + char* text_buffer, + size_t text_buffer_size, + bool clear_default_text); + +void uart_text_input_set_validator( + UART_TextInput* uart_text_input, + UART_TextInputValidatorCallback callback, + void* callback_context); + +UART_TextInputValidatorCallback + uart_text_input_get_validator_callback(UART_TextInput* uart_text_input); + +void* uart_text_input_get_validator_callback_context(UART_TextInput* uart_text_input); + +/** Set text input header text + * + * @param uart_text_input UART_TextInput instance + * @param text text to be shown + */ +void uart_text_input_set_header_text(UART_TextInput* uart_text_input, const char* text); + +#ifdef __cplusplus +} +#endif diff --git a/applications/plugins/uart_terminal/uart_validators.c b/applications/plugins/uart_terminal/uart_validators.c new file mode 100644 index 000000000..c87a6cc6e --- /dev/null +++ b/applications/plugins/uart_terminal/uart_validators.c @@ -0,0 +1,57 @@ +#include +#include "uart_validators.h" +#include + +struct ValidatorIsFile { + char* app_path_folder; + const char* app_extension; + char* current_name; +}; + +bool validator_is_file_callback(const char* text, FuriString* error, void* context) { + furi_assert(context); + ValidatorIsFile* instance = context; + + if(instance->current_name != NULL) { + if(strcmp(instance->current_name, text) == 0) { + return true; + } + } + + bool ret = true; + FuriString* path = furi_string_alloc_printf( + "%s/%s%s", instance->app_path_folder, text, instance->app_extension); + Storage* storage = furi_record_open(RECORD_STORAGE); + if(storage_common_stat(storage, furi_string_get_cstr(path), NULL) == FSE_OK) { + ret = false; + furi_string_printf(error, "This name\nexists!\nChoose\nanother one."); + } else { + ret = true; + } + furi_string_free(path); + furi_record_close(RECORD_STORAGE); + + return ret; +} + +ValidatorIsFile* validator_is_file_alloc_init( + const char* app_path_folder, + const char* app_extension, + const char* current_name) { + ValidatorIsFile* instance = malloc(sizeof(ValidatorIsFile)); + + instance->app_path_folder = strdup(app_path_folder); + instance->app_extension = app_extension; + if(current_name != NULL) { + instance->current_name = strdup(current_name); + } + + return instance; +} + +void validator_is_file_free(ValidatorIsFile* instance) { + furi_assert(instance); + free(instance->app_path_folder); + free(instance->current_name); + free(instance); +} diff --git a/applications/plugins/uart_terminal/uart_validators.h b/applications/plugins/uart_terminal/uart_validators.h new file mode 100644 index 000000000..d9200b6db --- /dev/null +++ b/applications/plugins/uart_terminal/uart_validators.h @@ -0,0 +1,21 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif +typedef struct ValidatorIsFile ValidatorIsFile; + +ValidatorIsFile* validator_is_file_alloc_init( + const char* app_path_folder, + const char* app_extension, + const char* current_name); + +void validator_is_file_free(ValidatorIsFile* instance); + +bool validator_is_file_callback(const char* text, FuriString* error, void* context); + +#ifdef __cplusplus +} +#endif diff --git a/applications/plugins/usbkeyboard/LICENSE.md b/applications/plugins/usbkeyboard/LICENSE.md deleted file mode 100644 index c616efe70..000000000 --- a/applications/plugins/usbkeyboard/LICENSE.md +++ /dev/null @@ -1,24 +0,0 @@ -BSD 2-Clause License - -Copyright (c) 2022, Gabriel Cirlig - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/applications/plugins/usbkeyboard/README.md b/applications/plugins/usbkeyboard/README.md deleted file mode 100644 index b2e31f9f4..000000000 --- a/applications/plugins/usbkeyboard/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# FlipperZeroUSBKeyboard -Turn your Flipper Zero into an USB keyboard. Works with the [latest Unleashed firmware](https://github.com/Eng1n33r/flipperzero-firmware). See the release on how to install the external app on the sdcard. For building instructions please refer the [official FAP guide](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/AppsOnSDCard.md). - -How it works: https://twitter.com/hookgab/status/1572537933210718211 - -Credits: - -All the good people that made the [BT HID remote](https://github.com/flipperdevices/flipperzero-firmware/tree/873e1f114b7ca55a72dc68bf1b1fa6d169e7c17e/applications/plugins/bt_hid_app) and the [USB Mouse](https://github.com/flipperdevices/flipperzero-firmware/tree/873e1f114b7ca55a72dc68bf1b1fa6d169e7c17e/applications/debug/usb_mouse). diff --git a/applications/plugins/usbkeyboard/application.fam b/applications/plugins/usbkeyboard/application.fam deleted file mode 100644 index 1e419f3fe..000000000 --- a/applications/plugins/usbkeyboard/application.fam +++ /dev/null @@ -1,15 +0,0 @@ -App( - appid="USB_Keyboard", - name="USB Keyboard & Mouse", - apptype=FlipperAppType.EXTERNAL, - entry_point="usb_hid_app", - stack_size=1 * 1024, - cdefines=["APP_USB_KEYBOARD"], - requires=[ - "gui", - ], - order=60, - fap_icon="usb_keyboard_10px.png", - fap_category="Misc", - fap_icon_assets="assets", -) diff --git a/applications/plugins/usbkeyboard/assets/Arr_dwn_7x9.png b/applications/plugins/usbkeyboard/assets/Arr_dwn_7x9.png deleted file mode 100644 index d4034efc4..000000000 Binary files a/applications/plugins/usbkeyboard/assets/Arr_dwn_7x9.png and /dev/null differ diff --git a/applications/plugins/usbkeyboard/assets/Arr_up_7x9.png b/applications/plugins/usbkeyboard/assets/Arr_up_7x9.png deleted file mode 100644 index 28b4236a2..000000000 Binary files a/applications/plugins/usbkeyboard/assets/Arr_up_7x9.png and /dev/null differ diff --git a/applications/plugins/usbkeyboard/assets/ButtonDown_7x4.png b/applications/plugins/usbkeyboard/assets/ButtonDown_7x4.png deleted file mode 100644 index 2954bb6a6..000000000 Binary files a/applications/plugins/usbkeyboard/assets/ButtonDown_7x4.png and /dev/null differ diff --git a/applications/plugins/usbkeyboard/assets/ButtonLeft_4x7.png b/applications/plugins/usbkeyboard/assets/ButtonLeft_4x7.png deleted file mode 100644 index 0b4655d43..000000000 Binary files a/applications/plugins/usbkeyboard/assets/ButtonLeft_4x7.png and /dev/null differ diff --git a/applications/plugins/usbkeyboard/assets/ButtonRight_4x7.png b/applications/plugins/usbkeyboard/assets/ButtonRight_4x7.png deleted file mode 100644 index 8e1c74c1c..000000000 Binary files a/applications/plugins/usbkeyboard/assets/ButtonRight_4x7.png and /dev/null differ diff --git a/applications/plugins/usbkeyboard/assets/ButtonUp_7x4.png b/applications/plugins/usbkeyboard/assets/ButtonUp_7x4.png deleted file mode 100644 index 1be79328b..000000000 Binary files a/applications/plugins/usbkeyboard/assets/ButtonUp_7x4.png and /dev/null differ diff --git a/applications/plugins/usbkeyboard/assets/Button_18x18.png b/applications/plugins/usbkeyboard/assets/Button_18x18.png deleted file mode 100644 index 30a5b4fab..000000000 Binary files a/applications/plugins/usbkeyboard/assets/Button_18x18.png and /dev/null differ diff --git a/applications/plugins/usbkeyboard/assets/Circles_47x47.png b/applications/plugins/usbkeyboard/assets/Circles_47x47.png deleted file mode 100644 index 6a16ebf7b..000000000 Binary files a/applications/plugins/usbkeyboard/assets/Circles_47x47.png and /dev/null differ diff --git a/applications/plugins/usbkeyboard/assets/Left_mouse_icon_9x9.png b/applications/plugins/usbkeyboard/assets/Left_mouse_icon_9x9.png deleted file mode 100644 index c533d8572..000000000 Binary files a/applications/plugins/usbkeyboard/assets/Left_mouse_icon_9x9.png and /dev/null differ diff --git a/applications/plugins/usbkeyboard/assets/Like_def_11x9.png b/applications/plugins/usbkeyboard/assets/Like_def_11x9.png deleted file mode 100644 index 555bea3d4..000000000 Binary files a/applications/plugins/usbkeyboard/assets/Like_def_11x9.png and /dev/null differ diff --git a/applications/plugins/usbkeyboard/assets/Like_pressed_17x17.png b/applications/plugins/usbkeyboard/assets/Like_pressed_17x17.png deleted file mode 100644 index f5bf276f3..000000000 Binary files a/applications/plugins/usbkeyboard/assets/Like_pressed_17x17.png and /dev/null differ diff --git a/applications/plugins/usbkeyboard/assets/Ok_btn_9x9.png b/applications/plugins/usbkeyboard/assets/Ok_btn_9x9.png deleted file mode 100644 index 9a1539da2..000000000 Binary files a/applications/plugins/usbkeyboard/assets/Ok_btn_9x9.png and /dev/null differ diff --git a/applications/plugins/usbkeyboard/assets/Ok_btn_pressed_13x13.png b/applications/plugins/usbkeyboard/assets/Ok_btn_pressed_13x13.png deleted file mode 100644 index 6b46ba3a8..000000000 Binary files a/applications/plugins/usbkeyboard/assets/Ok_btn_pressed_13x13.png and /dev/null differ diff --git a/applications/plugins/usbkeyboard/assets/Pin_arrow_down_7x9.png b/applications/plugins/usbkeyboard/assets/Pin_arrow_down_7x9.png deleted file mode 100644 index 9687397af..000000000 Binary files a/applications/plugins/usbkeyboard/assets/Pin_arrow_down_7x9.png and /dev/null differ diff --git a/applications/plugins/usbkeyboard/assets/Pin_arrow_left_9x7.png b/applications/plugins/usbkeyboard/assets/Pin_arrow_left_9x7.png deleted file mode 100644 index fb4ded78f..000000000 Binary files a/applications/plugins/usbkeyboard/assets/Pin_arrow_left_9x7.png and /dev/null differ diff --git a/applications/plugins/usbkeyboard/assets/Pin_arrow_right_9x7.png b/applications/plugins/usbkeyboard/assets/Pin_arrow_right_9x7.png deleted file mode 100644 index 97648d176..000000000 Binary files a/applications/plugins/usbkeyboard/assets/Pin_arrow_right_9x7.png and /dev/null differ diff --git a/applications/plugins/usbkeyboard/assets/Pin_arrow_up_7x9.png b/applications/plugins/usbkeyboard/assets/Pin_arrow_up_7x9.png deleted file mode 100644 index a91a6fd5e..000000000 Binary files a/applications/plugins/usbkeyboard/assets/Pin_arrow_up_7x9.png and /dev/null differ diff --git a/applications/plugins/usbkeyboard/assets/Pin_back_arrow_10x8.png b/applications/plugins/usbkeyboard/assets/Pin_back_arrow_10x8.png deleted file mode 100644 index 3bafabd14..000000000 Binary files a/applications/plugins/usbkeyboard/assets/Pin_back_arrow_10x8.png and /dev/null differ diff --git a/applications/plugins/usbkeyboard/assets/Pressed_Button_13x13.png b/applications/plugins/usbkeyboard/assets/Pressed_Button_13x13.png deleted file mode 100644 index 823926b84..000000000 Binary files a/applications/plugins/usbkeyboard/assets/Pressed_Button_13x13.png and /dev/null differ diff --git a/applications/plugins/usbkeyboard/assets/Right_mouse_icon_9x9.png b/applications/plugins/usbkeyboard/assets/Right_mouse_icon_9x9.png deleted file mode 100644 index 446d7176c..000000000 Binary files a/applications/plugins/usbkeyboard/assets/Right_mouse_icon_9x9.png and /dev/null differ diff --git a/applications/plugins/usbkeyboard/assets/Space_65x18.png b/applications/plugins/usbkeyboard/assets/Space_65x18.png deleted file mode 100644 index b60ae5097..000000000 Binary files a/applications/plugins/usbkeyboard/assets/Space_65x18.png and /dev/null differ diff --git a/applications/plugins/usbkeyboard/assets/Voldwn_6x6.png b/applications/plugins/usbkeyboard/assets/Voldwn_6x6.png deleted file mode 100644 index d7a82a2df..000000000 Binary files a/applications/plugins/usbkeyboard/assets/Voldwn_6x6.png and /dev/null differ diff --git a/applications/plugins/usbkeyboard/assets/Volup_8x6.png b/applications/plugins/usbkeyboard/assets/Volup_8x6.png deleted file mode 100644 index 4b7ec66d6..000000000 Binary files a/applications/plugins/usbkeyboard/assets/Volup_8x6.png and /dev/null differ diff --git a/applications/plugins/usbkeyboard/usb_hid.c b/applications/plugins/usbkeyboard/usb_hid.c deleted file mode 100644 index 744d6463e..000000000 --- a/applications/plugins/usbkeyboard/usb_hid.c +++ /dev/null @@ -1,198 +0,0 @@ -#include "usb_hid.h" -#include -#include -#include - -#define TAG "UsbHidApp" - -enum UsbDebugSubmenuIndex { - UsbHidSubmenuIndexDirpad, - UsbHidSubmenuIndexKeyboard, - UsbHidSubmenuIndexMedia, - UsbHidSubmenuIndexMouse, - UsbHidSubmenuIndexMouseJiggler, -}; - -void usb_hid_submenu_callback(void* context, uint32_t index) { - furi_assert(context); - UsbHid* app = context; - if(index == UsbHidSubmenuIndexDirpad) { - app->view_id = UsbHidViewDirpad; - view_dispatcher_switch_to_view(app->view_dispatcher, UsbHidViewDirpad); - } else if(index == UsbHidSubmenuIndexKeyboard) { - app->view_id = UsbHidViewKeyboard; - view_dispatcher_switch_to_view(app->view_dispatcher, UsbHidViewKeyboard); - } else if(index == UsbHidSubmenuIndexMedia) { - app->view_id = UsbHidViewMedia; - view_dispatcher_switch_to_view(app->view_dispatcher, UsbHidViewMedia); - } else if(index == UsbHidSubmenuIndexMouse) { - app->view_id = UsbHidViewMouse; - view_dispatcher_switch_to_view(app->view_dispatcher, UsbHidViewMouse); - } else if(index == UsbHidSubmenuIndexMouseJiggler) { - app->view_id = UsbHidViewMouseJiggler; - view_dispatcher_switch_to_view(app->view_dispatcher, UsbHidViewMouseJiggler); - } -} - -void usb_hid_dialog_callback(DialogExResult result, void* context) { - furi_assert(context); - UsbHid* app = context; - if(result == DialogExResultLeft) { - view_dispatcher_stop(app->view_dispatcher); - } else if(result == DialogExResultRight) { - view_dispatcher_switch_to_view(app->view_dispatcher, app->view_id); // Show last view - } else if(result == DialogExResultCenter) { - view_dispatcher_switch_to_view(app->view_dispatcher, UsbHidViewSubmenu); - } -} - -uint32_t usb_hid_exit_confirm_view(void* context) { - UNUSED(context); - return UsbHidViewExitConfirm; -} - -uint32_t usb_hid_exit(void* context) { - UNUSED(context); - return VIEW_NONE; -} - -UsbHid* usb_hid_app_alloc() { - UsbHid* app = malloc(sizeof(UsbHid)); - - // Gui - app->gui = furi_record_open(RECORD_GUI); - - // Notifications - app->notifications = furi_record_open(RECORD_NOTIFICATION); - - // View dispatcher - app->view_dispatcher = view_dispatcher_alloc(); - view_dispatcher_enable_queue(app->view_dispatcher); - view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); - - // Submenu view - app->submenu = submenu_alloc(); - submenu_add_item( - app->submenu, "Dirpad", UsbHidSubmenuIndexDirpad, usb_hid_submenu_callback, app); - submenu_add_item( - app->submenu, "Keyboard", UsbHidSubmenuIndexKeyboard, usb_hid_submenu_callback, app); - submenu_add_item( - app->submenu, "Media", UsbHidSubmenuIndexMedia, usb_hid_submenu_callback, app); - submenu_add_item( - app->submenu, "Mouse", UsbHidSubmenuIndexMouse, usb_hid_submenu_callback, app); - submenu_add_item( - app->submenu, - "Mouse Jiggler", - UsbHidSubmenuIndexMouseJiggler, - usb_hid_submenu_callback, - app); - view_set_previous_callback(submenu_get_view(app->submenu), usb_hid_exit); - view_dispatcher_add_view( - app->view_dispatcher, UsbHidViewSubmenu, submenu_get_view(app->submenu)); - - // Dialog view - app->dialog = dialog_ex_alloc(); - dialog_ex_set_result_callback(app->dialog, usb_hid_dialog_callback); - dialog_ex_set_context(app->dialog, app); - dialog_ex_set_left_button_text(app->dialog, "Exit"); - dialog_ex_set_right_button_text(app->dialog, "Stay"); - dialog_ex_set_center_button_text(app->dialog, "Menu"); - dialog_ex_set_header(app->dialog, "Close Current App?", 16, 12, AlignLeft, AlignTop); - view_dispatcher_add_view( - app->view_dispatcher, UsbHidViewExitConfirm, dialog_ex_get_view(app->dialog)); - - // Dirpad view - app->usb_hid_dirpad = usb_hid_dirpad_alloc(); - view_set_previous_callback( - usb_hid_dirpad_get_view(app->usb_hid_dirpad), usb_hid_exit_confirm_view); - view_dispatcher_add_view( - app->view_dispatcher, UsbHidViewDirpad, usb_hid_dirpad_get_view(app->usb_hid_dirpad)); - - // Keyboard view - app->usb_hid_keyboard = usb_hid_keyboard_alloc(); - view_set_previous_callback( - usb_hid_keyboard_get_view(app->usb_hid_keyboard), usb_hid_exit_confirm_view); - view_dispatcher_add_view( - app->view_dispatcher, - UsbHidViewKeyboard, - usb_hid_keyboard_get_view(app->usb_hid_keyboard)); - - // Media view - app->usb_hid_media = usb_hid_media_alloc(); - view_set_previous_callback( - usb_hid_media_get_view(app->usb_hid_media), usb_hid_exit_confirm_view); - view_dispatcher_add_view( - app->view_dispatcher, UsbHidViewMedia, usb_hid_media_get_view(app->usb_hid_media)); - - // Mouse view - app->usb_hid_mouse = usb_hid_mouse_alloc(); - view_set_previous_callback( - usb_hid_mouse_get_view(app->usb_hid_mouse), usb_hid_exit_confirm_view); - view_dispatcher_add_view( - app->view_dispatcher, UsbHidViewMouse, usb_hid_mouse_get_view(app->usb_hid_mouse)); - - // Mouse jiggler view - app->hid_mouse_jiggler = hid_mouse_jiggler_alloc(app); - view_set_previous_callback( - hid_mouse_jiggler_get_view(app->hid_mouse_jiggler), usb_hid_exit_confirm_view); - view_dispatcher_add_view( - app->view_dispatcher, - UsbHidViewMouseJiggler, - hid_mouse_jiggler_get_view(app->hid_mouse_jiggler)); - - // TODO switch to menu after Media is done - app->view_id = UsbHidViewSubmenu; - view_dispatcher_switch_to_view(app->view_dispatcher, app->view_id); - - return app; -} - -void usb_hid_app_free(UsbHid* app) { - furi_assert(app); - - // Reset notification - notification_internal_message(app->notifications, &sequence_reset_blue); - - // Free views - view_dispatcher_remove_view(app->view_dispatcher, UsbHidViewSubmenu); - submenu_free(app->submenu); - view_dispatcher_remove_view(app->view_dispatcher, UsbHidViewExitConfirm); - dialog_ex_free(app->dialog); - view_dispatcher_remove_view(app->view_dispatcher, UsbHidViewDirpad); - usb_hid_dirpad_free(app->usb_hid_dirpad); - view_dispatcher_remove_view(app->view_dispatcher, UsbHidViewKeyboard); - usb_hid_keyboard_free(app->usb_hid_keyboard); - view_dispatcher_remove_view(app->view_dispatcher, UsbHidViewMedia); - usb_hid_media_free(app->usb_hid_media); - view_dispatcher_remove_view(app->view_dispatcher, UsbHidViewMouse); - usb_hid_mouse_free(app->usb_hid_mouse); - view_dispatcher_remove_view(app->view_dispatcher, UsbHidViewMouseJiggler); - hid_mouse_jiggler_free(app->hid_mouse_jiggler); - view_dispatcher_free(app->view_dispatcher); - // Close records - furi_record_close(RECORD_GUI); - app->gui = NULL; - furi_record_close(RECORD_NOTIFICATION); - app->notifications = NULL; - - // Free rest - free(app); -} - -int32_t usb_hid_app(void* p) { - UNUSED(p); - // Switch profile to Hid - UsbHid* app = usb_hid_app_alloc(); - - FuriHalUsbInterface* usb_mode_prev = furi_hal_usb_get_config(); - furi_hal_usb_unlock(); - furi_check(furi_hal_usb_set_config(&usb_hid, NULL) == true); - - view_dispatcher_run(app->view_dispatcher); - - // Change back profile - furi_hal_usb_set_config(usb_mode_prev, NULL); - usb_hid_app_free(app); - - return 0; -} diff --git a/applications/plugins/usbkeyboard/usb_hid.h b/applications/plugins/usbkeyboard/usb_hid.h deleted file mode 100644 index 77b70e59f..000000000 --- a/applications/plugins/usbkeyboard/usb_hid.h +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -#include -#include -#include "views/usb_hid_dirpad.h" -#include "views/usb_hid_keyboard.h" -#include "views/usb_hid_media.h" -#include "views/usb_hid_mouse.h" -#include "views/usb_hid_mouse_jiggler.h" - -typedef struct { - Gui* gui; - NotificationApp* notifications; - ViewDispatcher* view_dispatcher; - Submenu* submenu; - DialogEx* dialog; - UsbHidDirpad* usb_hid_dirpad; - UsbHidKeyboard* usb_hid_keyboard; - UsbHidMedia* usb_hid_media; - UsbHidMouse* usb_hid_mouse; - HidMouseJiggler* hid_mouse_jiggler; - uint32_t view_id; -} UsbHid; - -typedef enum { - UsbHidViewSubmenu, - UsbHidViewDirpad, - UsbHidViewKeyboard, - UsbHidViewMedia, - UsbHidViewMouse, - UsbHidViewMouseJiggler, - UsbHidViewExitConfirm, -} UsbHidView; diff --git a/applications/plugins/usbkeyboard/usb_keyboard_10px.png b/applications/plugins/usbkeyboard/usb_keyboard_10px.png deleted file mode 100644 index 7649138eb..000000000 Binary files a/applications/plugins/usbkeyboard/usb_keyboard_10px.png and /dev/null differ diff --git a/applications/plugins/usbkeyboard/views/usb_hid_dirpad.c b/applications/plugins/usbkeyboard/views/usb_hid_dirpad.c deleted file mode 100644 index d6aec9ef2..000000000 --- a/applications/plugins/usbkeyboard/views/usb_hid_dirpad.c +++ /dev/null @@ -1,197 +0,0 @@ -#include "usb_hid_dirpad.h" -#include -#include -#include -#include - -struct UsbHidDirpad { - View* view; -}; - -typedef struct { - bool left_pressed; - bool up_pressed; - bool right_pressed; - bool down_pressed; - bool ok_pressed; - bool back_pressed; - bool connected; -} UsbHidDirpadModel; - -static void usb_hid_dirpad_draw_arrow(Canvas* canvas, uint8_t x, uint8_t y, CanvasDirection dir) { - canvas_draw_triangle(canvas, x, y, 5, 3, dir); - if(dir == CanvasDirectionBottomToTop) { - canvas_draw_line(canvas, x, y + 6, x, y - 1); - } else if(dir == CanvasDirectionTopToBottom) { - canvas_draw_line(canvas, x, y - 6, x, y + 1); - } else if(dir == CanvasDirectionRightToLeft) { - canvas_draw_line(canvas, x + 6, y, x - 1, y); - } else if(dir == CanvasDirectionLeftToRight) { - canvas_draw_line(canvas, x - 6, y, x + 1, y); - } -} - -static void usb_hid_dirpad_draw_callback(Canvas* canvas, void* context) { - furi_assert(context); - UsbHidDirpadModel* model = context; - - canvas_set_font(canvas, FontPrimary); - elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "Dirpad"); - - canvas_draw_icon(canvas, 68, 2, &I_Pin_back_arrow_10x8); - canvas_set_font(canvas, FontSecondary); - elements_multiline_text_aligned(canvas, 127, 3, AlignRight, AlignTop, "Hold to exit"); - - // Up - canvas_draw_icon(canvas, 21, 24, &I_Button_18x18); - if(model->up_pressed) { - elements_slightly_rounded_box(canvas, 24, 26, 13, 13); - canvas_set_color(canvas, ColorWhite); - } - usb_hid_dirpad_draw_arrow(canvas, 30, 30, CanvasDirectionBottomToTop); - canvas_set_color(canvas, ColorBlack); - - // Down - canvas_draw_icon(canvas, 21, 45, &I_Button_18x18); - if(model->down_pressed) { - elements_slightly_rounded_box(canvas, 24, 47, 13, 13); - canvas_set_color(canvas, ColorWhite); - } - usb_hid_dirpad_draw_arrow(canvas, 30, 55, CanvasDirectionTopToBottom); - canvas_set_color(canvas, ColorBlack); - - // Left - canvas_draw_icon(canvas, 0, 45, &I_Button_18x18); - if(model->left_pressed) { - elements_slightly_rounded_box(canvas, 3, 47, 13, 13); - canvas_set_color(canvas, ColorWhite); - } - usb_hid_dirpad_draw_arrow(canvas, 7, 53, CanvasDirectionRightToLeft); - canvas_set_color(canvas, ColorBlack); - - // Right - canvas_draw_icon(canvas, 42, 45, &I_Button_18x18); - if(model->right_pressed) { - elements_slightly_rounded_box(canvas, 45, 47, 13, 13); - canvas_set_color(canvas, ColorWhite); - } - usb_hid_dirpad_draw_arrow(canvas, 53, 53, CanvasDirectionLeftToRight); - canvas_set_color(canvas, ColorBlack); - - // Ok - canvas_draw_icon(canvas, 63, 25, &I_Space_65x18); - if(model->ok_pressed) { - elements_slightly_rounded_box(canvas, 66, 27, 60, 13); - canvas_set_color(canvas, ColorWhite); - } - canvas_draw_icon(canvas, 74, 29, &I_Ok_btn_9x9); - elements_multiline_text_aligned(canvas, 91, 36, AlignLeft, AlignBottom, "Space"); - canvas_set_color(canvas, ColorBlack); - - // Back - canvas_draw_icon(canvas, 63, 45, &I_Space_65x18); - if(model->back_pressed) { - elements_slightly_rounded_box(canvas, 66, 47, 60, 13); - canvas_set_color(canvas, ColorWhite); - } - canvas_draw_icon(canvas, 74, 49, &I_Pin_back_arrow_10x8); - elements_multiline_text_aligned(canvas, 91, 57, AlignLeft, AlignBottom, "Back"); -} - -static void usb_hid_dirpad_process(UsbHidDirpad* usb_hid_dirpad, InputEvent* event) { - with_view_model( - usb_hid_dirpad->view, - UsbHidDirpadModel * model, - { - if(event->type == InputTypePress) { - if(event->key == InputKeyUp) { - model->up_pressed = true; - furi_hal_hid_kb_press(HID_KEYBOARD_UP_ARROW); - } else if(event->key == InputKeyDown) { - model->down_pressed = true; - furi_hal_hid_kb_press(HID_KEYBOARD_DOWN_ARROW); - } else if(event->key == InputKeyLeft) { - model->left_pressed = true; - furi_hal_hid_kb_press(HID_KEYBOARD_LEFT_ARROW); - } else if(event->key == InputKeyRight) { - model->right_pressed = true; - furi_hal_hid_kb_press(HID_KEYBOARD_RIGHT_ARROW); - } else if(event->key == InputKeyOk) { - model->ok_pressed = true; - furi_hal_hid_kb_press(HID_KEYBOARD_SPACEBAR); - } else if(event->key == InputKeyBack) { - model->back_pressed = true; - } - } else if(event->type == InputTypeRelease) { - if(event->key == InputKeyUp) { - model->up_pressed = false; - furi_hal_hid_kb_release(HID_KEYBOARD_UP_ARROW); - } else if(event->key == InputKeyDown) { - model->down_pressed = false; - furi_hal_hid_kb_release(HID_KEYBOARD_DOWN_ARROW); - } else if(event->key == InputKeyLeft) { - model->left_pressed = false; - furi_hal_hid_kb_release(HID_KEYBOARD_LEFT_ARROW); - } else if(event->key == InputKeyRight) { - model->right_pressed = false; - furi_hal_hid_kb_release(HID_KEYBOARD_RIGHT_ARROW); - } else if(event->key == InputKeyOk) { - model->ok_pressed = false; - furi_hal_hid_kb_release(HID_KEYBOARD_SPACEBAR); - } else if(event->key == InputKeyBack) { - model->back_pressed = false; - } - } else if(event->type == InputTypeShort) { - if(event->key == InputKeyBack) { - furi_hal_hid_kb_press(HID_KEYBOARD_DELETE); - furi_hal_hid_kb_release(HID_KEYBOARD_DELETE); - furi_hal_hid_consumer_key_press(HID_CONSUMER_AC_BACK); - furi_hal_hid_consumer_key_release(HID_CONSUMER_AC_BACK); - } - } - }, - true); -} - -static bool usb_hid_dirpad_input_callback(InputEvent* event, void* context) { - furi_assert(context); - UsbHidDirpad* usb_hid_dirpad = context; - bool consumed = false; - - if(event->type == InputTypeLong && event->key == InputKeyBack) { - furi_hal_hid_kb_release_all(); - } else { - usb_hid_dirpad_process(usb_hid_dirpad, event); - consumed = true; - } - - return consumed; -} - -UsbHidDirpad* usb_hid_dirpad_alloc() { - UsbHidDirpad* usb_hid_dirpad = malloc(sizeof(UsbHidDirpad)); - usb_hid_dirpad->view = view_alloc(); - view_set_context(usb_hid_dirpad->view, usb_hid_dirpad); - view_allocate_model(usb_hid_dirpad->view, ViewModelTypeLocking, sizeof(UsbHidDirpadModel)); - view_set_draw_callback(usb_hid_dirpad->view, usb_hid_dirpad_draw_callback); - view_set_input_callback(usb_hid_dirpad->view, usb_hid_dirpad_input_callback); - - return usb_hid_dirpad; -} - -void usb_hid_dirpad_free(UsbHidDirpad* usb_hid_dirpad) { - furi_assert(usb_hid_dirpad); - view_free(usb_hid_dirpad->view); - free(usb_hid_dirpad); -} - -View* usb_hid_dirpad_get_view(UsbHidDirpad* usb_hid_dirpad) { - furi_assert(usb_hid_dirpad); - return usb_hid_dirpad->view; -} - -void usb_hid_dirpad_set_connected_status(UsbHidDirpad* usb_hid_dirpad, bool connected) { - furi_assert(usb_hid_dirpad); - with_view_model( - usb_hid_dirpad->view, UsbHidDirpadModel * model, { model->connected = connected; }, true); -} diff --git a/applications/plugins/usbkeyboard/views/usb_hid_dirpad.h b/applications/plugins/usbkeyboard/views/usb_hid_dirpad.h deleted file mode 100644 index 305e051b4..000000000 --- a/applications/plugins/usbkeyboard/views/usb_hid_dirpad.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include - -typedef struct UsbHidDirpad UsbHidDirpad; - -UsbHidDirpad* usb_hid_dirpad_alloc(); - -void usb_hid_dirpad_free(UsbHidDirpad* usb_hid_dirpad); - -View* usb_hid_dirpad_get_view(UsbHidDirpad* usb_hid_dirpad); - -void usb_hid_dirpad_set_connected_status(UsbHidDirpad* usb_hid_dirpad, bool connected); diff --git a/applications/plugins/usbkeyboard/views/usb_hid_keyboard.c b/applications/plugins/usbkeyboard/views/usb_hid_keyboard.c deleted file mode 100644 index 61fcaab80..000000000 --- a/applications/plugins/usbkeyboard/views/usb_hid_keyboard.c +++ /dev/null @@ -1,387 +0,0 @@ -#include "usb_hid_keyboard.h" -#include -#include -#include -#include -#include - -struct UsbHidKeyboard { - View* view; -}; - -typedef struct { - bool shift; - bool alt; - bool ctrl; - bool gui; - uint8_t x; - uint8_t y; - uint8_t last_key_code; - uint16_t modifier_code; - bool ok_pressed; - bool back_pressed; - bool connected; - char key_string[5]; -} UsbHidKeyboardModel; - -typedef struct { - uint8_t width; - char* key; - const Icon* icon; - char* shift_key; - uint8_t value; -} UsbHidKeyboardKey; - -typedef struct { - int8_t x; - int8_t y; -} UsbHidKeyboardPoint; - -// 4 BY 12 -#define MARGIN_TOP 0 -#define MARGIN_LEFT 4 -#define KEY_WIDTH 9 -#define KEY_HEIGHT 12 -#define KEY_PADDING 1 -#define ROW_COUNT 7 -#define COLUMN_COUNT 12 - -// 0 width items are not drawn, but there value is used -const UsbHidKeyboardKey usb_hid_keyboard_keyset[ROW_COUNT][COLUMN_COUNT] = { - { - {.width = 1, .icon = NULL, .key = "1", .shift_key = "!", .value = HID_KEYBOARD_1}, - {.width = 1, .icon = NULL, .key = "2", .shift_key = "@", .value = HID_KEYBOARD_2}, - {.width = 1, .icon = NULL, .key = "3", .shift_key = "#", .value = HID_KEYBOARD_3}, - {.width = 1, .icon = NULL, .key = "4", .shift_key = "$", .value = HID_KEYBOARD_4}, - {.width = 1, .icon = NULL, .key = "5", .shift_key = "%", .value = HID_KEYBOARD_5}, - {.width = 1, .icon = NULL, .key = "6", .shift_key = "^", .value = HID_KEYBOARD_6}, - {.width = 1, .icon = NULL, .key = "7", .shift_key = "&", .value = HID_KEYBOARD_7}, - {.width = 1, .icon = NULL, .key = "8", .shift_key = "*", .value = HID_KEYBOARD_8}, - {.width = 1, .icon = NULL, .key = "9", .shift_key = "(", .value = HID_KEYBOARD_9}, - {.width = 1, .icon = NULL, .key = "0", .shift_key = ")", .value = HID_KEYBOARD_0}, - {.width = 2, .icon = &I_Pin_arrow_left_9x7, .value = HID_KEYBOARD_DELETE}, - {.width = 0, .value = HID_KEYBOARD_DELETE}, - }, - { - {.width = 1, .icon = NULL, .key = "q", .shift_key = "Q", .value = HID_KEYBOARD_Q}, - {.width = 1, .icon = NULL, .key = "w", .shift_key = "W", .value = HID_KEYBOARD_W}, - {.width = 1, .icon = NULL, .key = "e", .shift_key = "E", .value = HID_KEYBOARD_E}, - {.width = 1, .icon = NULL, .key = "r", .shift_key = "R", .value = HID_KEYBOARD_R}, - {.width = 1, .icon = NULL, .key = "t", .shift_key = "T", .value = HID_KEYBOARD_T}, - {.width = 1, .icon = NULL, .key = "y", .shift_key = "Y", .value = HID_KEYBOARD_Y}, - {.width = 1, .icon = NULL, .key = "u", .shift_key = "U", .value = HID_KEYBOARD_U}, - {.width = 1, .icon = NULL, .key = "i", .shift_key = "I", .value = HID_KEYBOARD_I}, - {.width = 1, .icon = NULL, .key = "o", .shift_key = "O", .value = HID_KEYBOARD_O}, - {.width = 1, .icon = NULL, .key = "p", .shift_key = "P", .value = HID_KEYBOARD_P}, - {.width = 1, .icon = NULL, .key = "[", .shift_key = "{", .value = HID_KEYBOARD_OPEN_BRACKET}, - {.width = 1, - .icon = NULL, - .key = "]", - .shift_key = "}", - .value = HID_KEYBOARD_CLOSE_BRACKET}, - }, - { - {.width = 1, .icon = NULL, .key = "a", .shift_key = "A", .value = HID_KEYBOARD_A}, - {.width = 1, .icon = NULL, .key = "s", .shift_key = "S", .value = HID_KEYBOARD_S}, - {.width = 1, .icon = NULL, .key = "d", .shift_key = "D", .value = HID_KEYBOARD_D}, - {.width = 1, .icon = NULL, .key = "f", .shift_key = "F", .value = HID_KEYBOARD_F}, - {.width = 1, .icon = NULL, .key = "g", .shift_key = "G", .value = HID_KEYBOARD_G}, - {.width = 1, .icon = NULL, .key = "h", .shift_key = "H", .value = HID_KEYBOARD_H}, - {.width = 1, .icon = NULL, .key = "j", .shift_key = "J", .value = HID_KEYBOARD_J}, - {.width = 1, .icon = NULL, .key = "k", .shift_key = "K", .value = HID_KEYBOARD_K}, - {.width = 1, .icon = NULL, .key = "l", .shift_key = "L", .value = HID_KEYBOARD_L}, - {.width = 1, .icon = NULL, .key = ";", .shift_key = ":", .value = HID_KEYBOARD_SEMICOLON}, - {.width = 2, .icon = &I_Pin_arrow_right_9x7, .value = HID_KEYBOARD_RETURN}, - {.width = 0, .value = HID_KEYBOARD_RETURN}, - }, - { - {.width = 1, .icon = NULL, .key = "z", .shift_key = "Z", .value = HID_KEYBOARD_Z}, - {.width = 1, .icon = NULL, .key = "x", .shift_key = "X", .value = HID_KEYBOARD_X}, - {.width = 1, .icon = NULL, .key = "c", .shift_key = "C", .value = HID_KEYBOARD_C}, - {.width = 1, .icon = NULL, .key = "v", .shift_key = "V", .value = HID_KEYBOARD_V}, - {.width = 1, .icon = NULL, .key = "b", .shift_key = "B", .value = HID_KEYBOARD_B}, - {.width = 1, .icon = NULL, .key = "n", .shift_key = "N", .value = HID_KEYBOARD_N}, - {.width = 1, .icon = NULL, .key = "m", .shift_key = "M", .value = HID_KEYBOARD_M}, - {.width = 1, .icon = NULL, .key = "/", .shift_key = "?", .value = HID_KEYBOARD_SLASH}, - {.width = 1, .icon = NULL, .key = "\\", .shift_key = "|", .value = HID_KEYBOARD_BACKSLASH}, - {.width = 1, .icon = NULL, .key = "`", .shift_key = "~", .value = HID_KEYBOARD_GRAVE_ACCENT}, - {.width = 1, .icon = &I_ButtonUp_7x4, .value = HID_KEYBOARD_UP_ARROW}, - {.width = 1, .icon = NULL, .key = "-", .shift_key = "_", .value = HID_KEYBOARD_MINUS}, - }, - { - {.width = 1, .icon = &I_Pin_arrow_up_7x9, .value = HID_KEYBOARD_L_SHIFT}, - {.width = 1, .icon = NULL, .key = ",", .shift_key = "<", .value = HID_KEYPAD_COMMA}, - {.width = 1, .icon = NULL, .key = ".", .shift_key = ">", .value = HID_KEYBOARD_DOT}, - {.width = 4, .icon = NULL, .key = " ", .value = HID_KEYBOARD_SPACEBAR}, - {.width = 0, .value = HID_KEYBOARD_SPACEBAR}, - {.width = 0, .value = HID_KEYBOARD_SPACEBAR}, - {.width = 0, .value = HID_KEYBOARD_SPACEBAR}, - {.width = 1, .icon = NULL, .key = "'", .shift_key = "\"", .value = HID_KEYBOARD_APOSTROPHE}, - {.width = 1, .icon = NULL, .key = "=", .shift_key = "+", .value = HID_KEYBOARD_EQUAL_SIGN}, - {.width = 1, .icon = &I_ButtonLeft_4x7, .value = HID_KEYBOARD_LEFT_ARROW}, - {.width = 1, .icon = &I_ButtonDown_7x4, .value = HID_KEYBOARD_DOWN_ARROW}, - {.width = 1, .icon = &I_ButtonRight_4x7, .value = HID_KEYBOARD_RIGHT_ARROW}, - }, - { - {.width = 2, .icon = NULL, .key = "Ctl", .value = HID_KEYBOARD_L_CTRL}, - {.width = 0, .icon = NULL, .value = HID_KEYBOARD_L_CTRL}, - {.width = 2, .icon = NULL, .key = "Alt", .value = HID_KEYBOARD_L_ALT}, - {.width = 0, .icon = NULL, .value = HID_KEYBOARD_L_ALT}, - {.width = 2, .icon = NULL, .key = "Cmd", .value = HID_KEYBOARD_L_GUI}, - {.width = 0, .icon = NULL, .value = HID_KEYBOARD_L_GUI}, - {.width = 2, .icon = NULL, .key = "Tab", .value = HID_KEYBOARD_TAB}, - {.width = 0, .icon = NULL, .value = HID_KEYBOARD_TAB}, - {.width = 2, .icon = NULL, .key = "Esc", .value = HID_KEYBOARD_ESCAPE}, - {.width = 0, .icon = NULL, .value = HID_KEYBOARD_ESCAPE}, - {.width = 2, .icon = NULL, .key = "Del", .value = HID_KEYBOARD_DELETE_FORWARD}, - {.width = 0, .icon = NULL, .value = HID_KEYBOARD_DELETE_FORWARD}, - }, - { - {.width = 1, .icon = NULL, .key = "1", .shift_key = "1", .value = HID_KEYBOARD_F1}, - {.width = 1, .icon = NULL, .key = "2", .shift_key = "2", .value = HID_KEYBOARD_F2}, - {.width = 1, .icon = NULL, .key = "3", .shift_key = "3", .value = HID_KEYBOARD_F3}, - {.width = 1, .icon = NULL, .key = "4", .shift_key = "4", .value = HID_KEYBOARD_F4}, - {.width = 1, .icon = NULL, .key = "5", .shift_key = "5", .value = HID_KEYBOARD_F5}, - {.width = 1, .icon = NULL, .key = "6", .shift_key = "6", .value = HID_KEYBOARD_F6}, - {.width = 1, .icon = NULL, .key = "7", .shift_key = "7", .value = HID_KEYBOARD_F7}, - {.width = 1, .icon = NULL, .key = "8", .shift_key = "8", .value = HID_KEYBOARD_F8}, - {.width = 1, .icon = NULL, .key = "9", .shift_key = "9", .value = HID_KEYBOARD_F9}, - {.width = 1, .icon = NULL, .key = "0", .shift_key = "0", .value = HID_KEYBOARD_F10}, - {.width = 1, .icon = NULL, .key = "1", .shift_key = "1", .value = HID_KEYBOARD_F11}, - {.width = 1, .icon = NULL, .key = "2", .shift_key = "2", .value = HID_KEYBOARD_F12}, - }}; - -static void usb_hid_keyboard_to_upper(char* str) { - while(*str) { - *str = toupper((unsigned char)*str); - str++; - } -} - -static void usb_hid_keyboard_draw_key( - Canvas* canvas, - UsbHidKeyboardModel* model, - uint8_t x, - uint8_t y, - UsbHidKeyboardKey key, - bool selected) { - if(!key.width) return; - - canvas_set_color(canvas, ColorBlack); - uint8_t keyWidth = KEY_WIDTH * key.width + KEY_PADDING * (key.width - 1); - if(selected) { - // Draw a filled box - elements_slightly_rounded_box( - canvas, - MARGIN_LEFT + x * (KEY_WIDTH + KEY_PADDING), - MARGIN_TOP + y * (KEY_HEIGHT + KEY_PADDING), - keyWidth, - KEY_HEIGHT); - canvas_set_color(canvas, ColorWhite); - } else { - // Draw a framed box - elements_slightly_rounded_frame( - canvas, - MARGIN_LEFT + x * (KEY_WIDTH + KEY_PADDING), - MARGIN_TOP + y * (KEY_HEIGHT + KEY_PADDING), - keyWidth, - KEY_HEIGHT); - } - if(key.icon != NULL) { - // Draw the icon centered on the button - canvas_draw_icon( - canvas, - MARGIN_LEFT + x * (KEY_WIDTH + KEY_PADDING) + keyWidth / 2 - key.icon->width / 2, - MARGIN_TOP + y * (KEY_HEIGHT + KEY_PADDING) + KEY_HEIGHT / 2 - key.icon->height / 2, - key.icon); - } else { - // If shift is toggled use the shift key when available - strcpy(model->key_string, (model->shift && key.shift_key != 0) ? key.shift_key : key.key); - // Upper case if ctrl or alt was toggled true - if((model->ctrl && key.value == HID_KEYBOARD_L_CTRL) || - (model->alt && key.value == HID_KEYBOARD_L_ALT) || - (model->gui && key.value == HID_KEYBOARD_L_GUI)) { - usb_hid_keyboard_to_upper(model->key_string); - } - canvas_draw_str_aligned( - canvas, - MARGIN_LEFT + x * (KEY_WIDTH + KEY_PADDING) + keyWidth / 2 + 1, - MARGIN_TOP + y * (KEY_HEIGHT + KEY_PADDING) + KEY_HEIGHT / 2, - AlignCenter, - AlignCenter, - model->key_string); - } -} - -static void usb_hid_keyboard_draw_callback(Canvas* canvas, void* context) { - furi_assert(context); - UsbHidKeyboardModel* model = context; - - canvas_set_font(canvas, FontKeyboard); - // Start shifting the all keys up if on the next row (Scrolling) - uint8_t initY = model->y - 4 > 0 ? model->y - 4 : 0; - for(uint8_t y = initY; y < ROW_COUNT; y++) { - const UsbHidKeyboardKey* keyboardKeyRow = usb_hid_keyboard_keyset[y]; - uint8_t x = 0; - for(uint8_t i = 0; i < COLUMN_COUNT; i++) { - UsbHidKeyboardKey key = keyboardKeyRow[i]; - // Select when the button is hovered - // Select if the button is hovered within its width - // Select if back is clicked and its the backspace key - // Deselect when the button clicked or not hovered - bool keySelected = (x <= model->x && model->x < (x + key.width)) && y == model->y; - // Revert selection for function keys - keySelected = y == ROW_COUNT - 1 ? !keySelected : keySelected; - bool backSelected = model->back_pressed && key.value == HID_KEYBOARD_DELETE; - usb_hid_keyboard_draw_key( - canvas, - model, - x, - y - initY, - key, - (!model->ok_pressed && keySelected) || backSelected); - x += key.width; - } - } -} - -static uint8_t usb_hid_keyboard_get_selected_key(UsbHidKeyboardModel* model) { - UsbHidKeyboardKey key = usb_hid_keyboard_keyset[model->y][model->x]; - // Use upper case if shift is toggled - bool useUppercase = model->shift; - // Check if the key has an upper case version - bool hasUppercase = key.shift_key != 0; - if(useUppercase && hasUppercase) - return key.value; - else - return key.value; -} - -static void - usb_hid_keyboard_get_select_key(UsbHidKeyboardModel* model, UsbHidKeyboardPoint delta) { - // Keep going until a valid spot is found, this allows for nulls and zero width keys in the map - do { - if(((int8_t)model->y) + delta.y < 0) - model->y = ROW_COUNT - 1; - else - model->y = (model->y + delta.y) % ROW_COUNT; - } while(delta.y != 0 && usb_hid_keyboard_keyset[model->y][model->x].value == 0); - - do { - if(((int8_t)model->x) + delta.x < 0) - model->x = COLUMN_COUNT - 1; - else - model->x = (model->x + delta.x) % COLUMN_COUNT; - } while(delta.x != 0 && usb_hid_keyboard_keyset[model->y][model->x].width == - 0); // Skip zero width keys, pretend they are one key -} - -static void usb_hid_keyboard_process(UsbHidKeyboard* usb_hid_keyboard, InputEvent* event) { - with_view_model( - usb_hid_keyboard->view, - UsbHidKeyboardModel * model, - { - if(event->key == InputKeyOk) { - if(event->type == InputTypePress) { - model->ok_pressed = true; - } else if(event->type == InputTypeLong || event->type == InputTypeShort) { - model->last_key_code = usb_hid_keyboard_get_selected_key(model); - - // Toggle the modifier key when clicked, and click the key - if(model->last_key_code == HID_KEYBOARD_L_SHIFT) { - model->shift = !model->shift; - if(model->shift) - model->modifier_code |= KEY_MOD_LEFT_SHIFT; - else - model->modifier_code &= ~KEY_MOD_LEFT_SHIFT; - } else if(model->last_key_code == HID_KEYBOARD_L_ALT) { - model->alt = !model->alt; - if(model->alt) - model->modifier_code |= KEY_MOD_LEFT_ALT; - else - model->modifier_code &= ~KEY_MOD_LEFT_ALT; - } else if(model->last_key_code == HID_KEYBOARD_L_CTRL) { - model->ctrl = !model->ctrl; - if(model->ctrl) - model->modifier_code |= KEY_MOD_LEFT_CTRL; - else - model->modifier_code &= ~KEY_MOD_LEFT_CTRL; - } else if(model->last_key_code == HID_KEYBOARD_L_GUI) { - model->gui = !model->gui; - if(model->gui) - model->modifier_code |= KEY_MOD_LEFT_GUI; - else - model->modifier_code &= ~KEY_MOD_LEFT_GUI; - } - furi_hal_hid_kb_press(model->modifier_code | model->last_key_code); - } else if(event->type == InputTypeRelease) { - // Release happens after short and long presses - furi_hal_hid_kb_release(model->modifier_code | model->last_key_code); - model->ok_pressed = false; - } - } else if(event->key == InputKeyBack) { - // If back is pressed for a short time, backspace - if(event->type == InputTypePress) { - model->back_pressed = true; - } else if(event->type == InputTypeShort) { - furi_hal_hid_kb_press(HID_KEYBOARD_DELETE); - furi_hal_hid_kb_release(HID_KEYBOARD_DELETE); - } else if(event->type == InputTypeRelease) { - model->back_pressed = false; - } - } else if(event->type == InputTypePress || event->type == InputTypeRepeat) { - // Cycle the selected keys - if(event->key == InputKeyUp) { - usb_hid_keyboard_get_select_key(model, (UsbHidKeyboardPoint){.x = 0, .y = -1}); - } else if(event->key == InputKeyDown) { - usb_hid_keyboard_get_select_key(model, (UsbHidKeyboardPoint){.x = 0, .y = 1}); - } else if(event->key == InputKeyLeft) { - usb_hid_keyboard_get_select_key(model, (UsbHidKeyboardPoint){.x = -1, .y = 0}); - } else if(event->key == InputKeyRight) { - usb_hid_keyboard_get_select_key(model, (UsbHidKeyboardPoint){.x = 1, .y = 0}); - } - } - }, - true); -} - -static bool usb_hid_keyboard_input_callback(InputEvent* event, void* context) { - furi_assert(context); - UsbHidKeyboard* usb_hid_keyboard = context; - bool consumed = false; - - if(event->type == InputTypeLong && event->key == InputKeyBack) { - furi_hal_hid_kb_release_all(); - } else { - usb_hid_keyboard_process(usb_hid_keyboard, event); - consumed = true; - } - - return consumed; -} - -UsbHidKeyboard* usb_hid_keyboard_alloc() { - UsbHidKeyboard* usb_hid_keyboard = malloc(sizeof(UsbHidKeyboard)); - - usb_hid_keyboard->view = view_alloc(); - view_set_context(usb_hid_keyboard->view, usb_hid_keyboard); - view_allocate_model(usb_hid_keyboard->view, ViewModelTypeLocking, sizeof(UsbHidKeyboardModel)); - view_set_draw_callback(usb_hid_keyboard->view, usb_hid_keyboard_draw_callback); - view_set_input_callback(usb_hid_keyboard->view, usb_hid_keyboard_input_callback); - - with_view_model( - usb_hid_keyboard->view, UsbHidKeyboardModel * model, { model->connected = true; }, true); - - return usb_hid_keyboard; -} - -void usb_hid_keyboard_free(UsbHidKeyboard* usb_hid_keyboard) { - furi_assert(usb_hid_keyboard); - view_free(usb_hid_keyboard->view); - free(usb_hid_keyboard); -} - -View* usb_hid_keyboard_get_view(UsbHidKeyboard* usb_hid_keyboard) { - furi_assert(usb_hid_keyboard); - return usb_hid_keyboard->view; -} \ No newline at end of file diff --git a/applications/plugins/usbkeyboard/views/usb_hid_keyboard.h b/applications/plugins/usbkeyboard/views/usb_hid_keyboard.h deleted file mode 100644 index 4dee5fbee..000000000 --- a/applications/plugins/usbkeyboard/views/usb_hid_keyboard.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include - -typedef struct UsbHidKeyboard UsbHidKeyboard; - -UsbHidKeyboard* usb_hid_keyboard_alloc(); - -void usb_hid_keyboard_free(UsbHidKeyboard* usb_hid_keyboard); - -View* usb_hid_keyboard_get_view(UsbHidKeyboard* usb_hid_keyboard); - -void usb_hid_keyboard_set_connected_status(UsbHidKeyboard* usb_hid_keyboard, bool connected); diff --git a/applications/plugins/usbkeyboard/views/usb_hid_media.c b/applications/plugins/usbkeyboard/views/usb_hid_media.c deleted file mode 100644 index 8d2188434..000000000 --- a/applications/plugins/usbkeyboard/views/usb_hid_media.c +++ /dev/null @@ -1,201 +0,0 @@ -#include "usb_hid_media.h" -#include -#include -#include -#include - -struct UsbHidMedia { - View* view; -}; - -typedef struct { - bool left_pressed; - bool up_pressed; - bool right_pressed; - bool down_pressed; - bool ok_pressed; - bool connected; -} UsbHidMediaModel; - -static void usb_hid_media_draw_arrow(Canvas* canvas, uint8_t x, uint8_t y, CanvasDirection dir) { - canvas_draw_triangle(canvas, x, y, 5, 3, dir); - if(dir == CanvasDirectionBottomToTop) { - canvas_draw_dot(canvas, x, y - 1); - } else if(dir == CanvasDirectionTopToBottom) { - canvas_draw_dot(canvas, x, y + 1); - } else if(dir == CanvasDirectionRightToLeft) { - canvas_draw_dot(canvas, x - 1, y); - } else if(dir == CanvasDirectionLeftToRight) { - canvas_draw_dot(canvas, x + 1, y); - } -} - -static void usb_hid_media_draw_callback(Canvas* canvas, void* context) { - furi_assert(context); - UsbHidMediaModel* model = context; - - canvas_set_font(canvas, FontPrimary); - elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "Media"); - canvas_set_font(canvas, FontSecondary); - - // Keypad circles - canvas_draw_icon(canvas, 76, 8, &I_Circles_47x47); - - // Up - if(model->up_pressed) { - canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 93, 9, &I_Pressed_Button_13x13); - canvas_set_bitmap_mode(canvas, 0); - canvas_set_color(canvas, ColorWhite); - } - canvas_draw_icon(canvas, 96, 12, &I_Volup_8x6); - canvas_set_color(canvas, ColorBlack); - - // Down - if(model->down_pressed) { - canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 93, 41, &I_Pressed_Button_13x13); - canvas_set_bitmap_mode(canvas, 0); - canvas_set_color(canvas, ColorWhite); - } - canvas_draw_icon(canvas, 96, 45, &I_Voldwn_6x6); - canvas_set_color(canvas, ColorBlack); - - // Left - if(model->left_pressed) { - canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 77, 25, &I_Pressed_Button_13x13); - canvas_set_bitmap_mode(canvas, 0); - canvas_set_color(canvas, ColorWhite); - } - usb_hid_media_draw_arrow(canvas, 82, 31, CanvasDirectionRightToLeft); - usb_hid_media_draw_arrow(canvas, 86, 31, CanvasDirectionRightToLeft); - canvas_set_color(canvas, ColorBlack); - - // Right - if(model->right_pressed) { - canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 109, 25, &I_Pressed_Button_13x13); - canvas_set_bitmap_mode(canvas, 0); - canvas_set_color(canvas, ColorWhite); - } - usb_hid_media_draw_arrow(canvas, 112, 31, CanvasDirectionLeftToRight); - usb_hid_media_draw_arrow(canvas, 116, 31, CanvasDirectionLeftToRight); - canvas_set_color(canvas, ColorBlack); - - // Ok - if(model->ok_pressed) { - canvas_draw_icon(canvas, 93, 25, &I_Pressed_Button_13x13); - canvas_set_color(canvas, ColorWhite); - } - usb_hid_media_draw_arrow(canvas, 96, 31, CanvasDirectionLeftToRight); - canvas_draw_line(canvas, 100, 29, 100, 33); - canvas_draw_line(canvas, 102, 29, 102, 33); - canvas_set_color(canvas, ColorBlack); - - // Exit - canvas_draw_icon(canvas, 0, 54, &I_Pin_back_arrow_10x8); - canvas_set_font(canvas, FontSecondary); - elements_multiline_text_aligned(canvas, 13, 62, AlignLeft, AlignBottom, "Hold to exit"); -} - -static void usb_hid_media_process_press(UsbHidMedia* usb_hid_media, InputEvent* event) { - with_view_model( - usb_hid_media->view, - UsbHidMediaModel * model, - { - if(event->key == InputKeyUp) { - model->up_pressed = true; - furi_hal_hid_consumer_key_press(HID_CONSUMER_VOLUME_INCREMENT); - } else if(event->key == InputKeyDown) { - model->down_pressed = true; - furi_hal_hid_consumer_key_press(HID_CONSUMER_VOLUME_DECREMENT); - } else if(event->key == InputKeyLeft) { - model->left_pressed = true; - furi_hal_hid_consumer_key_press(HID_CONSUMER_SCAN_PREVIOUS_TRACK); - } else if(event->key == InputKeyRight) { - model->right_pressed = true; - furi_hal_hid_consumer_key_press(HID_CONSUMER_SCAN_NEXT_TRACK); - } else if(event->key == InputKeyOk) { - model->ok_pressed = true; - furi_hal_hid_consumer_key_press(HID_CONSUMER_PLAY_PAUSE); - } - }, - true); -} - -static void hid_media_process_release(UsbHidMedia* usb_hid_media, InputEvent* event) { - with_view_model( - usb_hid_media->view, - UsbHidMediaModel * model, - { - if(event->key == InputKeyUp) { - model->up_pressed = false; - furi_hal_hid_consumer_key_release(HID_CONSUMER_VOLUME_INCREMENT); - } else if(event->key == InputKeyDown) { - model->down_pressed = false; - furi_hal_hid_consumer_key_release(HID_CONSUMER_VOLUME_DECREMENT); - } else if(event->key == InputKeyLeft) { - model->left_pressed = false; - furi_hal_hid_consumer_key_release(HID_CONSUMER_SCAN_PREVIOUS_TRACK); - } else if(event->key == InputKeyRight) { - model->right_pressed = false; - furi_hal_hid_consumer_key_release(HID_CONSUMER_SCAN_NEXT_TRACK); - } else if(event->key == InputKeyOk) { - model->ok_pressed = false; - furi_hal_hid_consumer_key_release(HID_CONSUMER_PLAY_PAUSE); - } - }, - true); -} - -static bool usb_hid_media_input_callback(InputEvent* event, void* context) { - furi_assert(context); - UsbHidMedia* usb_hid_media = context; - bool consumed = false; - - if(event->type == InputTypePress) { - usb_hid_media_process_press(usb_hid_media, event); - consumed = true; - } else if(event->type == InputTypeRelease) { - hid_media_process_release(usb_hid_media, event); - consumed = true; - } else if(event->type == InputTypeShort) { - if(event->key == InputKeyBack) { - furi_hal_hid_kb_release_all(); - } - } - - return consumed; -} - -UsbHidMedia* usb_hid_media_alloc() { - UsbHidMedia* usb_hid_media = malloc(sizeof(UsbHidMedia)); - usb_hid_media->view = view_alloc(); - view_set_context(usb_hid_media->view, usb_hid_media); - view_allocate_model(usb_hid_media->view, ViewModelTypeLocking, sizeof(UsbHidMediaModel)); - view_set_draw_callback(usb_hid_media->view, usb_hid_media_draw_callback); - view_set_input_callback(usb_hid_media->view, usb_hid_media_input_callback); - - with_view_model( - usb_hid_media->view, UsbHidMediaModel * model, { model->connected = true; }, true); - - return usb_hid_media; -} - -void usb_hid_media_free(UsbHidMedia* usb_hid_media) { - furi_assert(usb_hid_media); - view_free(usb_hid_media->view); - free(usb_hid_media); -} - -View* usb_hid_media_get_view(UsbHidMedia* usb_hid_media) { - furi_assert(usb_hid_media); - return usb_hid_media->view; -} - -void usb_hid_media_set_connected_status(UsbHidMedia* usb_hid_media, bool connected) { - furi_assert(usb_hid_media); - with_view_model( - usb_hid_media->view, UsbHidMediaModel * model, { model->connected = connected; }, true); -} diff --git a/applications/plugins/usbkeyboard/views/usb_hid_media.h b/applications/plugins/usbkeyboard/views/usb_hid_media.h deleted file mode 100644 index 441e2bd6d..000000000 --- a/applications/plugins/usbkeyboard/views/usb_hid_media.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include - -typedef struct UsbHidMedia UsbHidMedia; - -UsbHidMedia* usb_hid_media_alloc(); - -void usb_hid_media_free(UsbHidMedia* usb_hid_media); - -View* usb_hid_media_get_view(UsbHidMedia* usb_hid_media); - -void usb_hid_media_set_connected_status(UsbHidMedia* usb_hid_media, bool connected); diff --git a/applications/plugins/usbkeyboard/views/usb_hid_mouse.c b/applications/plugins/usbkeyboard/views/usb_hid_mouse.c deleted file mode 100644 index 27f2ac105..000000000 --- a/applications/plugins/usbkeyboard/views/usb_hid_mouse.c +++ /dev/null @@ -1,215 +0,0 @@ -#include "usb_hid_mouse.h" -#include -#include -#include -#include - -struct UsbHidMouse { - View* view; -}; -#define MOUSE_MOVE_SHORT 5 -#define MOUSE_MOVE_LONG 20 - -typedef struct { - bool left_pressed; - bool up_pressed; - bool right_pressed; - bool down_pressed; - bool left_mouse_pressed; - bool left_mouse_held; - bool right_mouse_pressed; - bool connected; -} UsbHidMouseModel; - -static void usb_hid_mouse_draw_callback(Canvas* canvas, void* context) { - furi_assert(context); - UsbHidMouseModel* model = context; - - // Header - /*if(model->connected) { - canvas_draw_icon(canvas, 0, 0, &I_Ble_connected_15x15); - } else { - canvas_draw_icon(canvas, 0, 0, &I_Ble_disconnected_15x15); - }*/ - canvas_set_font(canvas, FontPrimary); - elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "Mouse"); - canvas_set_font(canvas, FontSecondary); - - if(model->left_mouse_held == true) { - elements_multiline_text_aligned(canvas, 0, 62, AlignLeft, AlignBottom, "Selecting..."); - } else { - canvas_draw_icon(canvas, 0, 54, &I_Pin_back_arrow_10x8); - canvas_set_font(canvas, FontSecondary); - elements_multiline_text_aligned(canvas, 13, 62, AlignLeft, AlignBottom, "Hold to exit"); - } - - // Keypad circles - canvas_draw_icon(canvas, 64, 8, &I_Circles_47x47); - - // Up - if(model->up_pressed) { - canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 81, 9, &I_Pressed_Button_13x13); - canvas_set_bitmap_mode(canvas, 0); - canvas_set_color(canvas, ColorWhite); - } - canvas_draw_icon(canvas, 84, 10, &I_Pin_arrow_up_7x9); - canvas_set_color(canvas, ColorBlack); - - // Down - if(model->down_pressed) { - canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 81, 41, &I_Pressed_Button_13x13); - canvas_set_bitmap_mode(canvas, 0); - canvas_set_color(canvas, ColorWhite); - } - canvas_draw_icon(canvas, 84, 43, &I_Pin_arrow_down_7x9); - canvas_set_color(canvas, ColorBlack); - - // Left - if(model->left_pressed) { - canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 65, 25, &I_Pressed_Button_13x13); - canvas_set_bitmap_mode(canvas, 0); - canvas_set_color(canvas, ColorWhite); - } - canvas_draw_icon(canvas, 67, 28, &I_Pin_arrow_left_9x7); - canvas_set_color(canvas, ColorBlack); - - // Right - if(model->right_pressed) { - canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 97, 25, &I_Pressed_Button_13x13); - canvas_set_bitmap_mode(canvas, 0); - canvas_set_color(canvas, ColorWhite); - } - canvas_draw_icon(canvas, 99, 28, &I_Pin_arrow_right_9x7); - canvas_set_color(canvas, ColorBlack); - - // Ok - if(model->left_mouse_pressed) { - canvas_draw_icon(canvas, 81, 25, &I_Ok_btn_pressed_13x13); - } else { - canvas_draw_icon(canvas, 83, 27, &I_Left_mouse_icon_9x9); - } - - // Back - if(model->right_mouse_pressed) { - canvas_draw_icon(canvas, 108, 48, &I_Ok_btn_pressed_13x13); - } else { - canvas_draw_icon(canvas, 110, 50, &I_Right_mouse_icon_9x9); - } -} - -static void usb_hid_mouse_process(UsbHidMouse* usb_hid_mouse, InputEvent* event) { - with_view_model( - usb_hid_mouse->view, - UsbHidMouseModel * model, - { - if(event->key == InputKeyBack) { - if(event->type == InputTypeShort) { - furi_hal_hid_mouse_press(HID_MOUSE_BTN_RIGHT); - furi_hal_hid_mouse_release(HID_MOUSE_BTN_RIGHT); - } else if(event->type == InputTypePress) { - model->right_mouse_pressed = true; - } else if(event->type == InputTypeRelease) { - model->right_mouse_pressed = false; - } - } else if(event->key == InputKeyOk) { - if(event->type == InputTypeShort) { - // Just release if it was being held before - if(!model->left_mouse_held) furi_hal_hid_mouse_press(HID_MOUSE_BTN_LEFT); - furi_hal_hid_mouse_release(HID_MOUSE_BTN_LEFT); - model->left_mouse_held = false; - } else if(event->type == InputTypeLong) { - furi_hal_hid_mouse_press(HID_MOUSE_BTN_LEFT); - model->left_mouse_held = true; - model->left_mouse_pressed = true; - } else if(event->type == InputTypePress) { - model->left_mouse_pressed = true; - } else if(event->type == InputTypeRelease) { - // Only release if it wasn't a long press - if(!model->left_mouse_held) model->left_mouse_pressed = false; - } - - } else if(event->key == InputKeyRight) { - if(event->type == InputTypePress) { - model->right_pressed = true; - furi_hal_hid_mouse_move(MOUSE_MOVE_SHORT, 0); - } else if(event->type == InputTypeRepeat) { - furi_hal_hid_mouse_move(MOUSE_MOVE_LONG, 0); - } else if(event->type == InputTypeRelease) { - model->right_pressed = false; - } - } else if(event->key == InputKeyLeft) { - if(event->type == InputTypePress) { - model->left_pressed = true; - furi_hal_hid_mouse_move(-MOUSE_MOVE_SHORT, 0); - } else if(event->type == InputTypeRepeat) { - furi_hal_hid_mouse_move(-MOUSE_MOVE_LONG, 0); - } else if(event->type == InputTypeRelease) { - model->left_pressed = false; - } - } else if(event->key == InputKeyDown) { - if(event->type == InputTypePress) { - model->down_pressed = true; - furi_hal_hid_mouse_move(0, MOUSE_MOVE_SHORT); - } else if(event->type == InputTypeRepeat) { - furi_hal_hid_mouse_move(0, MOUSE_MOVE_LONG); - } else if(event->type == InputTypeRelease) { - model->down_pressed = false; - } - } else if(event->key == InputKeyUp) { - if(event->type == InputTypePress) { - model->up_pressed = true; - furi_hal_hid_mouse_move(0, -MOUSE_MOVE_SHORT); - } else if(event->type == InputTypeRepeat) { - furi_hal_hid_mouse_move(0, -MOUSE_MOVE_LONG); - } else if(event->type == InputTypeRelease) { - model->up_pressed = false; - } - } - }, - true); -} - -static bool usb_hid_mouse_input_callback(InputEvent* event, void* context) { - furi_assert(context); - UsbHidMouse* usb_hid_mouse = context; - bool consumed = false; - - if(event->type == InputTypeLong && event->key == InputKeyBack) { - furi_hal_hid_mouse_release(HID_MOUSE_BTN_LEFT); - furi_hal_hid_mouse_release(HID_MOUSE_BTN_RIGHT); - } else { - usb_hid_mouse_process(usb_hid_mouse, event); - consumed = true; - } - - return consumed; -} - -UsbHidMouse* usb_hid_mouse_alloc() { - UsbHidMouse* usb_hid_mouse = malloc(sizeof(UsbHidMouse)); - usb_hid_mouse->view = view_alloc(); - view_set_context(usb_hid_mouse->view, usb_hid_mouse); - view_allocate_model(usb_hid_mouse->view, ViewModelTypeLocking, sizeof(UsbHidMouseModel)); - view_set_draw_callback(usb_hid_mouse->view, usb_hid_mouse_draw_callback); - view_set_input_callback(usb_hid_mouse->view, usb_hid_mouse_input_callback); - - with_view_model( - usb_hid_mouse->view, UsbHidMouseModel * model, { model->connected = true; }, true); - - return usb_hid_mouse; -} - -void usb_hid_mouse_free(UsbHidMouse* usb_hid_mouse) { - furi_assert(usb_hid_mouse); - view_free(usb_hid_mouse->view); - free(usb_hid_mouse); -} - -View* usb_hid_mouse_get_view(UsbHidMouse* usb_hid_mouse) { - furi_assert(usb_hid_mouse); - return usb_hid_mouse->view; -} diff --git a/applications/plugins/usbkeyboard/views/usb_hid_mouse.h b/applications/plugins/usbkeyboard/views/usb_hid_mouse.h deleted file mode 100644 index e7eec9224..000000000 --- a/applications/plugins/usbkeyboard/views/usb_hid_mouse.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include - -typedef struct UsbHidMouse UsbHidMouse; - -UsbHidMouse* usb_hid_mouse_alloc(); - -void usb_hid_mouse_free(UsbHidMouse* usb_hid_mouse); - -View* usb_hid_mouse_get_view(UsbHidMouse* usb_hid_mouse); - -void usb_hid_mouse_set_connected_status(UsbHidMouse* usb_hid_mouse, bool connected); diff --git a/applications/plugins/usbkeyboard/views/usb_hid_mouse_jiggler.c b/applications/plugins/usbkeyboard/views/usb_hid_mouse_jiggler.c deleted file mode 100644 index fe0c618d2..000000000 --- a/applications/plugins/usbkeyboard/views/usb_hid_mouse_jiggler.c +++ /dev/null @@ -1,130 +0,0 @@ -#include "usb_hid_mouse_jiggler.h" -#include -#include -#include - -#include - -#define TAG "HidMouseJiggler" - -struct HidMouseJiggler { - View* view; - FuriTimer* timer; -}; - -typedef struct { - bool running; - uint8_t counter; -} HidMouseJigglerModel; - -static void hid_mouse_jiggler_draw_callback(Canvas* canvas, void* context) { - furi_assert(context); - HidMouseJigglerModel* model = context; - - // Header - canvas_set_font(canvas, FontPrimary); - elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "Mouse Jiggler"); - - canvas_set_font(canvas, FontPrimary); - elements_multiline_text(canvas, AlignLeft, 35, "Press Start\nto jiggle"); - canvas_set_font(canvas, FontSecondary); - - // Ok - canvas_draw_icon(canvas, 63, 25, &I_Space_65x18); - if(model->running) { - elements_slightly_rounded_box(canvas, 66, 27, 60, 13); - canvas_set_color(canvas, ColorWhite); - } - canvas_draw_icon(canvas, 74, 29, &I_Ok_btn_9x9); - if(model->running) { - elements_multiline_text_aligned(canvas, 91, 36, AlignLeft, AlignBottom, "Stop"); - } else { - elements_multiline_text_aligned(canvas, 91, 36, AlignLeft, AlignBottom, "Start"); - } - canvas_set_color(canvas, ColorBlack); - - // Back - canvas_draw_icon(canvas, 74, 49, &I_Pin_back_arrow_10x8); - elements_multiline_text_aligned(canvas, 91, 57, AlignLeft, AlignBottom, "Quit"); -} - -static void hid_mouse_jiggler_timer_callback(void* context) { - furi_assert(context); - HidMouseJiggler* hid_mouse_jiggler = context; - with_view_model( - hid_mouse_jiggler->view, - HidMouseJigglerModel * model, - { - if(model->running) { - model->counter++; - furi_hal_hid_mouse_move( - (model->counter % 2 == 0) ? MOUSE_MOVE_SHORT : -MOUSE_MOVE_SHORT, 0); - } - }, - false); -} - -static void hid_mouse_jiggler_enter_callback(void* context) { - furi_assert(context); - HidMouseJiggler* hid_mouse_jiggler = context; - - furi_timer_start(hid_mouse_jiggler->timer, 500); -} - -static void hid_mouse_jiggler_exit_callback(void* context) { - furi_assert(context); - HidMouseJiggler* hid_mouse_jiggler = context; - furi_timer_stop(hid_mouse_jiggler->timer); -} - -static bool hid_mouse_jiggler_input_callback(InputEvent* event, void* context) { - furi_assert(context); - HidMouseJiggler* hid_mouse_jiggler = context; - - bool consumed = false; - - if(event->key == InputKeyOk) { - with_view_model( - hid_mouse_jiggler->view, - HidMouseJigglerModel * model, - { model->running = !model->running; }, - true); - consumed = true; - } - - return consumed; -} - -HidMouseJiggler* hid_mouse_jiggler_alloc() { - HidMouseJiggler* hid_mouse_jiggler = malloc(sizeof(HidMouseJiggler)); - - hid_mouse_jiggler->view = view_alloc(); - view_set_context(hid_mouse_jiggler->view, hid_mouse_jiggler); - view_allocate_model( - hid_mouse_jiggler->view, ViewModelTypeLocking, sizeof(HidMouseJigglerModel)); - view_set_draw_callback(hid_mouse_jiggler->view, hid_mouse_jiggler_draw_callback); - view_set_input_callback(hid_mouse_jiggler->view, hid_mouse_jiggler_input_callback); - view_set_enter_callback(hid_mouse_jiggler->view, hid_mouse_jiggler_enter_callback); - view_set_exit_callback(hid_mouse_jiggler->view, hid_mouse_jiggler_exit_callback); - - hid_mouse_jiggler->timer = furi_timer_alloc( - hid_mouse_jiggler_timer_callback, FuriTimerTypePeriodic, hid_mouse_jiggler); - - return hid_mouse_jiggler; -} - -void hid_mouse_jiggler_free(HidMouseJiggler* hid_mouse_jiggler) { - furi_assert(hid_mouse_jiggler); - - furi_timer_stop(hid_mouse_jiggler->timer); - furi_timer_free(hid_mouse_jiggler->timer); - - view_free(hid_mouse_jiggler->view); - - free(hid_mouse_jiggler); -} - -View* hid_mouse_jiggler_get_view(HidMouseJiggler* hid_mouse_jiggler) { - furi_assert(hid_mouse_jiggler); - return hid_mouse_jiggler->view; -} diff --git a/applications/plugins/usbkeyboard/views/usb_hid_mouse_jiggler.h b/applications/plugins/usbkeyboard/views/usb_hid_mouse_jiggler.h deleted file mode 100644 index 24cf877a7..000000000 --- a/applications/plugins/usbkeyboard/views/usb_hid_mouse_jiggler.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include - -#define MOUSE_MOVE_SHORT 5 -#define MOUSE_MOVE_LONG 20 - -typedef struct HidMouseJiggler HidMouseJiggler; - -HidMouseJiggler* hid_mouse_jiggler_alloc(); - -void hid_mouse_jiggler_free(HidMouseJiggler* hid_mouse_jiggler); - -View* hid_mouse_jiggler_get_view(HidMouseJiggler* hid_mouse_jiggler); diff --git a/applications/plugins/wav_player/README.md b/applications/plugins/wav_player/README.md new file mode 100644 index 000000000..ef87e1e77 --- /dev/null +++ b/applications/plugins/wav_player/README.md @@ -0,0 +1,4 @@ +# WAV player + A Flipper Zero application for playing wav files. My fork adds support for correct playback speed (for files with different sample rates) and for mono files (original wav player only plays stereo). You still need to convert your file to unsigned 8-bit PCM format for it to played correctly on flipper. + +Original app by https://github.com/DrZlo13. diff --git a/applications/plugins/wav_player/application.fam b/applications/plugins/wav_player/application.fam index ec0c76291..4040ed159 100644 --- a/applications/plugins/wav_player/application.fam +++ b/applications/plugins/wav_player/application.fam @@ -5,7 +5,7 @@ App( entry_point="wav_player_app", cdefines=["APP_WAV_PLAYER"], stack_size=4 * 1024, - order=60, + order=46, fap_icon="wav_10px.png", fap_category="Music", fap_icon_assets="images", diff --git a/applications/plugins/wav_player/wav_parser.c b/applications/plugins/wav_player/wav_parser.c index c2897706c..1f534bacb 100644 --- a/applications/plugins/wav_player/wav_parser.c +++ b/applications/plugins/wav_player/wav_parser.c @@ -29,7 +29,7 @@ void wav_parser_free(WavParser* parser) { free(parser); } -bool wav_parser_parse(WavParser* parser, Stream* stream) { +bool wav_parser_parse(WavParser* parser, Stream* stream, WavPlayerApp* app) { stream_read(stream, (uint8_t*)&parser->header, sizeof(WavHeaderChunk)); stream_read(stream, (uint8_t*)&parser->format, sizeof(WavFormatChunk)); stream_read(stream, (uint8_t*)&parser->data, sizeof(WavDataChunk)); @@ -63,6 +63,10 @@ bool wav_parser_parse(WavParser* parser, Stream* stream) { parser->format.byte_per_sec, parser->format.bits_per_sample); + app->sample_rate = parser->format.sample_rate; + app->num_channels = parser->format.channels; + app->bits_per_sample = parser->format.bits_per_sample; + parser->wav_data_start = stream_tell(stream); parser->wav_data_end = parser->wav_data_start + parser->data.size; diff --git a/applications/plugins/wav_player/wav_parser.h b/applications/plugins/wav_player/wav_parser.h index f50c48b3f..8d4139865 100644 --- a/applications/plugins/wav_player/wav_parser.h +++ b/applications/plugins/wav_player/wav_parser.h @@ -1,6 +1,18 @@ #pragma once #include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wav_player_view.h" + #ifdef __cplusplus extern "C" { #endif @@ -34,11 +46,37 @@ typedef struct { typedef struct WavParser WavParser; +typedef struct { + Storage* storage; + Stream* stream; + WavParser* parser; + uint16_t* sample_buffer; + uint8_t* tmp_buffer; + + uint32_t sample_rate; + + uint16_t num_channels; + uint16_t bits_per_sample; + + size_t samples_count_half; + size_t samples_count; + + FuriMessageQueue* queue; + + float volume; + bool play; + + WavPlayerView* view; + ViewDispatcher* view_dispatcher; + Gui* gui; + NotificationApp* notification; +} WavPlayerApp; + WavParser* wav_parser_alloc(); void wav_parser_free(WavParser* parser); -bool wav_parser_parse(WavParser* parser, Stream* stream); +bool wav_parser_parse(WavParser* parser, Stream* stream, WavPlayerApp* app); size_t wav_parser_get_data_start(WavParser* parser); @@ -48,4 +86,4 @@ size_t wav_parser_get_data_len(WavParser* parser); #ifdef __cplusplus } -#endif \ No newline at end of file +#endif diff --git a/applications/plugins/wav_player/wav_player.c b/applications/plugins/wav_player/wav_player.c index 0a57162ff..3fb8b1ea5 100644 --- a/applications/plugins/wav_player/wav_player.c +++ b/applications/plugins/wav_player/wav_player.c @@ -11,7 +11,6 @@ #include "wav_parser.h" #include "wav_player_view.h" #include -#include #include @@ -80,27 +79,6 @@ static void wav_player_dma_isr(void* ctx) { } } -typedef struct { - Storage* storage; - Stream* stream; - WavParser* parser; - uint16_t* sample_buffer; - uint8_t* tmp_buffer; - - size_t samples_count_half; - size_t samples_count; - - FuriMessageQueue* queue; - - float volume; - bool play; - - WavPlayerView* view; - ViewDispatcher* view_dispatcher; - Gui* gui; - NotificationApp* notification; -} WavPlayerApp; - static WavPlayerApp* app_alloc() { WavPlayerApp* app = malloc(sizeof(WavPlayerApp)); app->samples_count_half = 1024 * 4; @@ -149,38 +127,83 @@ static void app_free(WavPlayerApp* app) { // TODO: that works only with 8-bit 2ch audio static bool fill_data(WavPlayerApp* app, size_t index) { - uint16_t* sample_buffer_start = &app->sample_buffer[index]; - size_t count = stream_read(app->stream, app->tmp_buffer, app->samples_count); + if(app->num_channels == 1) { + uint16_t* sample_buffer_start = &app->sample_buffer[index]; + size_t count = stream_read(app->stream, app->tmp_buffer, app->samples_count_half); - for(size_t i = count; i < app->samples_count; i++) { - app->tmp_buffer[i] = 0; - } - - for(size_t i = 0; i < app->samples_count; i += 2) { - float data = app->tmp_buffer[i]; - data -= UINT8_MAX / 2; // to signed - data /= UINT8_MAX / 2; // scale -1..1 - - data *= app->volume; // volume - data = tanhf(data); // hyperbolic tangent limiter - - data *= UINT8_MAX / 2; // scale -128..127 - data += UINT8_MAX / 2; // to unsigned - - if(data < 0) { - data = 0; + for(size_t i = count; i < app->samples_count_half; i++) { + app->tmp_buffer[i] = 0; } - if(data > 255) { - data = 255; + //for(size_t i = 0; i < app->samples_count; i += 2) + for(size_t i = 0; i < app->samples_count_half; i++) //now works with mono! + { + float data = app->tmp_buffer[i]; + data -= UINT8_MAX / 2; // to signed + data /= UINT8_MAX / 2; // scale -1..1 + + data *= app->volume; // volume + data = tanhf(data); // hyperbolic tangent limiter + + data *= UINT8_MAX / 2; // scale -128..127 + data += UINT8_MAX / 2; // to unsigned + + if(data < 0) { + data = 0; + } + + if(data > 255) { + data = 255; + } + + //uint8_t data = app->tmp_buffer[i]; + + sample_buffer_start[i] = data; } - sample_buffer_start[i / 2] = data; + wav_player_view_set_data(app->view, sample_buffer_start, app->samples_count_half); + + return count != app->samples_count_half; } - wav_player_view_set_data(app->view, sample_buffer_start, app->samples_count_half); + if(app->num_channels == 2) { + uint16_t* sample_buffer_start = &app->sample_buffer[index]; + size_t count = stream_read(app->stream, app->tmp_buffer, app->samples_count); - return count != app->samples_count; + for(size_t i = count; i < app->samples_count; i++) { + app->tmp_buffer[i] = 0; + } + + for(size_t i = 0; i < app->samples_count; i += 2) { + float data = (app->tmp_buffer[i] + app->tmp_buffer[i + 1]) / 2; // (L + R) / 2 + data -= UINT8_MAX / 2; // to signed + data /= UINT8_MAX / 2; // scale -1..1 + + data *= app->volume; // volume + data = tanhf(data); // hyperbolic tangent limiter + + data *= UINT8_MAX / 2; // scale -128..127 + data += UINT8_MAX / 2; // to unsigned + + if(data < 0) { + data = 0; + } + + if(data > 255) { + data = 255; + } + + //uint8_t data = app->tmp_buffer[i]; + + sample_buffer_start[i / 2] = data; + } + + wav_player_view_set_data(app->view, sample_buffer_start, app->samples_count_half); + + return count != app->samples_count; + } + + return true; } static void ctrl_callback(WavPlayerCtrl ctrl, void* ctx) { @@ -219,7 +242,7 @@ static void ctrl_callback(WavPlayerCtrl ctrl, void* ctx) { static void app_run(WavPlayerApp* app) { if(!open_wav_stream(app->stream)) return; - if(!wav_parser_parse(app->parser, app->stream)) return; + if(!wav_parser_parse(app->parser, app->stream, app)) return; wav_player_view_set_volume(app->view, app->volume); wav_player_view_set_start(app->view, wav_parser_get_data_start(app->parser)); @@ -233,7 +256,7 @@ static void app_run(WavPlayerApp* app) { bool eof = fill_data(app, 0); eof = fill_data(app, app->samples_count_half); - wav_player_speaker_init(); + wav_player_speaker_init(app->sample_rate); wav_player_dma_init((uint32_t)app->sample_buffer, app->samples_count); furi_hal_interrupt_set_isr(FuriHalInterruptIdDma1Ch1, wav_player_dma_isr, app->queue); diff --git a/applications/plugins/wav_player/wav_player_hal.c b/applications/plugins/wav_player/wav_player_hal.c index ad0c019be..e711eccb4 100644 --- a/applications/plugins/wav_player/wav_player_hal.c +++ b/applications/plugins/wav_player/wav_player_hal.c @@ -2,14 +2,26 @@ #include #include +#include +#include +#include +#include + +//#define FURI_HAL_SPEAKER_TIMER TIM16 + #define FURI_HAL_SPEAKER_TIMER TIM16 + +#define SAMPLE_RATE_TIMER TIM2 + #define FURI_HAL_SPEAKER_CHANNEL LL_TIM_CHANNEL_CH1 #define DMA_INSTANCE DMA1, LL_DMA_CHANNEL_1 -void wav_player_speaker_init() { +void wav_player_speaker_init(uint32_t sample_rate) { LL_TIM_InitTypeDef TIM_InitStruct = {0}; - TIM_InitStruct.Prescaler = 4; - TIM_InitStruct.Autoreload = 255; + //TIM_InitStruct.Prescaler = 4; + TIM_InitStruct.Prescaler = 1; + TIM_InitStruct.Autoreload = + 255; //in this fork used purely as PWM timer, the DMA now is triggered by SAMPLE_RATE_TIMER LL_TIM_Init(FURI_HAL_SPEAKER_TIMER, &TIM_InitStruct); LL_TIM_OC_InitTypeDef TIM_OC_InitStruct = {0}; @@ -17,16 +29,51 @@ void wav_player_speaker_init() { TIM_OC_InitStruct.OCState = LL_TIM_OCSTATE_ENABLE; TIM_OC_InitStruct.CompareValue = 127; LL_TIM_OC_Init(FURI_HAL_SPEAKER_TIMER, FURI_HAL_SPEAKER_CHANNEL, &TIM_OC_InitStruct); + + //====================================================== + + TIM_InitStruct.Prescaler = 0; + //TIM_InitStruct.Autoreload = 1451; //64 000 000 / 1451 ~= 44100 Hz + + TIM_InitStruct.Autoreload = 64000000 / sample_rate; //to support various sample rates + + LL_TIM_Init(SAMPLE_RATE_TIMER, &TIM_InitStruct); + + //LL_TIM_OC_InitTypeDef TIM_OC_InitStruct = {0}; + TIM_OC_InitStruct.OCMode = LL_TIM_OCMODE_PWM1; + TIM_OC_InitStruct.OCState = LL_TIM_OCSTATE_ENABLE; + TIM_OC_InitStruct.CompareValue = 127; + LL_TIM_OC_Init(SAMPLE_RATE_TIMER, FURI_HAL_SPEAKER_CHANNEL, &TIM_OC_InitStruct); + + //========================================================= + //configuring PA6 pin as TIM16 output + + //furi_hal_gpio_init_ex(&gpio_ext_pa6, (GpioMode)GpioPullNo, (GpioPull)GpioModeAltFunctionPushPull, GpioSpeedVeryHigh, GpioAltFn14TIM16); + //furi_hal_gpio_init_ex(&gpio_ext_pa6, (GpioMode)GpioPullNo, (GpioPull)GpioModeAltFunctionPushPull, GpioSpeedLow, GpioAltFn14TIM16); + furi_hal_gpio_init_ex( + &gpio_ext_pa6, + GpioModeAltFunctionPushPull, + GpioPullNo, + GpioSpeedVeryHigh, + GpioAltFn14TIM16); + //furi_hal_gpio_init_simple(&gpio_ext_pa6, GpioModeOutputPushPull); + //furi_hal_gpio_write(&gpio_ext_pa6, false); } void wav_player_speaker_start() { LL_TIM_EnableAllOutputs(FURI_HAL_SPEAKER_TIMER); LL_TIM_EnableCounter(FURI_HAL_SPEAKER_TIMER); + + LL_TIM_EnableAllOutputs(SAMPLE_RATE_TIMER); + LL_TIM_EnableCounter(SAMPLE_RATE_TIMER); } void wav_player_speaker_stop() { LL_TIM_DisableAllOutputs(FURI_HAL_SPEAKER_TIMER); LL_TIM_DisableCounter(FURI_HAL_SPEAKER_TIMER); + + LL_TIM_DisableAllOutputs(SAMPLE_RATE_TIMER); + LL_TIM_DisableCounter(SAMPLE_RATE_TIMER); } void wav_player_dma_init(uint32_t address, size_t size) { @@ -35,7 +82,7 @@ void wav_player_dma_init(uint32_t address, size_t size) { LL_DMA_ConfigAddresses(DMA_INSTANCE, address, dma_dst, LL_DMA_DIRECTION_MEMORY_TO_PERIPH); LL_DMA_SetDataLength(DMA_INSTANCE, size); - LL_DMA_SetPeriphRequest(DMA_INSTANCE, LL_DMAMUX_REQ_TIM16_UP); + LL_DMA_SetPeriphRequest(DMA_INSTANCE, LL_DMAMUX_REQ_TIM2_UP); LL_DMA_SetDataTransferDirection(DMA_INSTANCE, LL_DMA_DIRECTION_MEMORY_TO_PERIPH); LL_DMA_SetChannelPriorityLevel(DMA_INSTANCE, LL_DMA_PRIORITY_VERYHIGH); LL_DMA_SetMode(DMA_INSTANCE, LL_DMA_MODE_CIRCULAR); @@ -50,9 +97,9 @@ void wav_player_dma_init(uint32_t address, size_t size) { void wav_player_dma_start() { LL_DMA_EnableChannel(DMA_INSTANCE); - LL_TIM_EnableDMAReq_UPDATE(FURI_HAL_SPEAKER_TIMER); + LL_TIM_EnableDMAReq_UPDATE(SAMPLE_RATE_TIMER); } void wav_player_dma_stop() { LL_DMA_DisableChannel(DMA_INSTANCE); -} \ No newline at end of file +} diff --git a/applications/plugins/wav_player/wav_player_view.c b/applications/plugins/wav_player/wav_player_view.c index fdf08cb21..eee39c902 100644 --- a/applications/plugins/wav_player/wav_player_view.c +++ b/applications/plugins/wav_player/wav_player_view.c @@ -1,22 +1,5 @@ #include "wav_player_view.h" -#define DATA_COUNT 116 - -struct WavPlayerView { - View* view; - WavPlayerCtrlCallback callback; - void* context; -}; - -typedef struct { - bool play; - float volume; - size_t start; - size_t end; - size_t current; - uint8_t data[DATA_COUNT]; -} WavPlayerViewModel; - float map(float x, float in_min, float in_max, float out_min, float out_max) { return (x - in_min) * (out_max - out_min + 1) / (in_max - in_min + 1) + out_min; } @@ -30,7 +13,7 @@ static void wav_player_view_draw_callback(Canvas* canvas, void* _model) { uint8_t y_pos = 0; // volume - x_pos = 124; + x_pos = 123; y_pos = 0; const float volume = (64 / 10.0f) * model->volume; canvas_draw_frame(canvas, x_pos, y_pos, 4, 64); @@ -198,4 +181,4 @@ void wav_player_view_set_ctrl_callback(WavPlayerView* wav_view, WavPlayerCtrlCal void wav_player_view_set_context(WavPlayerView* wav_view, void* context) { furi_assert(wav_view); wav_view->context = context; -} \ No newline at end of file +} diff --git a/applications/plugins/wav_player/wav_player_view.h b/applications/plugins/wav_player/wav_player_view.h index 246aeaf3e..d841b04c0 100644 --- a/applications/plugins/wav_player/wav_player_view.h +++ b/applications/plugins/wav_player/wav_player_view.h @@ -1,6 +1,16 @@ #pragma once #include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #ifdef __cplusplus extern "C" { #endif @@ -18,6 +28,23 @@ typedef enum { typedef void (*WavPlayerCtrlCallback)(WavPlayerCtrl ctrl, void* context); +#define DATA_COUNT 116 + +struct WavPlayerView { + View* view; + WavPlayerCtrlCallback callback; + void* context; +}; + +typedef struct { + bool play; + float volume; + size_t start; + size_t end; + size_t current; + uint8_t data[DATA_COUNT]; +} WavPlayerViewModel; + WavPlayerView* wav_player_view_alloc(); void wav_player_view_free(WavPlayerView* wav_view); @@ -42,4 +69,4 @@ void wav_player_view_set_context(WavPlayerView* wav_view, void* context); #ifdef __cplusplus } -#endif \ No newline at end of file +#endif diff --git a/applications/plugins/weather_station/scenes/weather_station_receiver.c b/applications/plugins/weather_station/scenes/weather_station_receiver.c index 670c8c386..3b62a1512 100644 --- a/applications/plugins/weather_station/scenes/weather_station_receiver.c +++ b/applications/plugins/weather_station/scenes/weather_station_receiver.c @@ -195,6 +195,10 @@ bool weather_station_scene_receiver_on_event(void* context, SceneManagerEvent ev ws_hopper_update(app); weather_station_scene_receiver_update_statusbar(app); } + // Get current RSSI + float rssi = furi_hal_subghz_get_rssi(); + ws_receiver_rssi(app->ws_receiver, rssi); + if(app->txrx->txrx_state == WSTxRxStateRx) { notification_message(app->notifications, &sequence_blink_cyan_10); } diff --git a/applications/plugins/weather_station/views/weather_station_receiver.c b/applications/plugins/weather_station/views/weather_station_receiver.c index 42a90b22d..c98b46de5 100644 --- a/applications/plugins/weather_station/views/weather_station_receiver.c +++ b/applications/plugins/weather_station/views/weather_station_receiver.c @@ -12,6 +12,7 @@ #define MENU_ITEMS 4u #define UNLOCK_CNT 3 +#define SUBGHZ_RAW_TRESHOLD_MIN -90.0f typedef struct { FuriString* item_str; uint8_t type; @@ -59,8 +60,24 @@ typedef struct { uint16_t list_offset; uint16_t history_item; WSReceiverBarShow bar_show; + uint8_t u_rssi; } WSReceiverModel; +void ws_receiver_rssi(WSReceiver* instance, float rssi) { + furi_assert(instance); + with_view_model( + instance->view, + WSReceiverModel * model, + { + if(rssi < SUBGHZ_RAW_TRESHOLD_MIN) { + model->u_rssi = 0; + } else { + model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_TRESHOLD_MIN); + } + }, + true); +} + void ws_view_receiver_set_lock(WSReceiver* ws_receiver, WSLock lock) { furi_assert(ws_receiver); ws_receiver->lock_count = 0; @@ -164,13 +181,23 @@ static void ws_view_receiver_draw_frame(Canvas* canvas, uint16_t idx, bool scrol canvas_draw_dot(canvas, scrollbar ? 121 : 126, (0 + idx * FRAME_HEIGHT) + 11); } +static void ws_view_rssi_draw(Canvas* canvas, WSReceiverModel* model) { + for(uint8_t i = 1; i < model->u_rssi; i++) { + if(i % 5) { + canvas_draw_dot(canvas, 46 + i, 50); + canvas_draw_dot(canvas, 47 + i, 51); + canvas_draw_dot(canvas, 46 + i, 52); + } + } +} + void ws_view_receiver_draw(Canvas* canvas, WSReceiverModel* model) { canvas_clear(canvas); canvas_set_color(canvas, ColorBlack); canvas_set_font(canvas, FontSecondary); elements_button_left(canvas, "Config"); - canvas_draw_line(canvas, 46, 51, 125, 51); + //canvas_draw_line(canvas, 46, 51, 125, 51); bool scrollbar = model->history_item > 4; FuriString* str_buff; @@ -203,10 +230,13 @@ void ws_view_receiver_draw(Canvas* canvas, WSReceiverModel* model) { canvas_draw_icon(canvas, 0, 0, &I_Scanning_123x52); canvas_set_font(canvas, FontPrimary); canvas_draw_str(canvas, 63, 46, "Scanning..."); - canvas_draw_line(canvas, 46, 51, 125, 51); + //canvas_draw_line(canvas, 46, 51, 125, 51); canvas_set_font(canvas, FontSecondary); } + // Draw RSSI + ws_view_rssi_draw(canvas, model); + switch(model->bar_show) { case WSReceiverBarShowLock: canvas_draw_icon(canvas, 64, 55, &I_Lock_7x8); diff --git a/applications/plugins/weather_station/views/weather_station_receiver.h b/applications/plugins/weather_station/views/weather_station_receiver.h index 30c6516d5..abe2c6255 100644 --- a/applications/plugins/weather_station/views/weather_station_receiver.h +++ b/applications/plugins/weather_station/views/weather_station_receiver.h @@ -8,6 +8,8 @@ typedef struct WSReceiver WSReceiver; typedef void (*WSReceiverCallback)(WSCustomEvent event, void* context); +void ws_receiver_rssi(WSReceiver* instance, float rssi); + void ws_view_receiver_set_lock(WSReceiver* ws_receiver, WSLock keyboard); void ws_view_receiver_set_callback( diff --git a/applications/plugins/weather_station/weather_station_app_i.c b/applications/plugins/weather_station/weather_station_app_i.c index 712634a2c..7236b6625 100644 --- a/applications/plugins/weather_station/weather_station_app_i.c +++ b/applications/plugins/weather_station/weather_station_app_i.c @@ -58,7 +58,7 @@ void ws_begin(WeatherStationApp* app, uint8_t* preset_data) { furi_hal_subghz_reset(); furi_hal_subghz_idle(); furi_hal_subghz_load_custom_preset(preset_data); - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_init(furi_hal_subghz.cc1101_g0_pin, GpioModeInput, GpioPullNo, GpioSpeedLow); app->txrx->txrx_state = WSTxRxStateIDLE; } @@ -72,7 +72,7 @@ uint32_t ws_rx(WeatherStationApp* app, uint32_t frequency) { furi_hal_subghz_idle(); uint32_t value = furi_hal_subghz_set_frequency_and_path(frequency); - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_init(furi_hal_subghz.cc1101_g0_pin, GpioModeInput, GpioPullNo, GpioSpeedLow); furi_hal_subghz_flush_rx(); furi_hal_subghz_rx(); diff --git a/applications/plugins/zombiez/zombiez.c b/applications/plugins/zombiez/zombiez.c index bd2a5c97d..2677d13e0 100644 --- a/applications/plugins/zombiez/zombiez.c +++ b/applications/plugins/zombiez/zombiez.c @@ -2,6 +2,7 @@ #include #include #include +#include //ORIGINAL REPO: https://github.com/Dooskington/flipperzero-zombiez //AUTHORS: https://github.com/Dooskington | https://github.com/DevMilanIan @@ -313,6 +314,9 @@ int32_t zombiez_game_app(void* p) { Gui* gui = furi_record_open(RECORD_GUI); gui_add_view_port(gui, view_port, GuiLayerFullscreen); + // Call dolphin deed on game start + DOLPHIN_DEED(DolphinDeedPluginGameStart); + PluginEvent event; bool isRunning = true; while(isRunning) { diff --git a/applications/services/desktop/desktop_settings.h b/applications/services/desktop/desktop_settings.h index 93292072f..959059cb0 100644 --- a/applications/services/desktop/desktop_settings.h +++ b/applications/services/desktop/desktop_settings.h @@ -8,7 +8,7 @@ #include #include -#define DESKTOP_SETTINGS_VER (6) +#define DESKTOP_SETTINGS_VER (7) #define DESKTOP_SETTINGS_PATH INT_PATH(DESKTOP_SETTINGS_FILE_NAME) #define DESKTOP_SETTINGS_MAGIC (0x17) diff --git a/applications/services/desktop/scenes/desktop_scene_main.c b/applications/services/desktop/scenes/desktop_scene_main.c index 2465a8d2c..e61c38dd2 100644 --- a/applications/services/desktop/scenes/desktop_scene_main.c +++ b/applications/services/desktop/scenes/desktop_scene_main.c @@ -119,7 +119,6 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) { case DesktopMainEventLock: if(desktop->settings.pin_code.length > 0) { - scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 1); desktop_pin_lock(&desktop->settings); scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 0); } diff --git a/applications/services/desktop/views/desktop_view_debug.c b/applications/services/desktop/views/desktop_view_debug.c index 016188874..abb9d2c26 100644 --- a/applications/services/desktop/views/desktop_view_debug.c +++ b/applications/services/desktop/views/desktop_view_debug.c @@ -42,7 +42,7 @@ void desktop_debug_render(Canvas* canvas, void* model) { furi_hal_version_get_hw_target(), furi_hal_version_get_hw_body(), furi_hal_version_get_hw_connect(), - furi_hal_version_get_hw_region_name(), + furi_hal_version_get_hw_region_name_otp(), furi_hal_region_get_name(), my_name ? my_name : "Unknown"); canvas_draw_str(canvas, 0, 19 + STATUS_BAR_Y_SHIFT, buffer); diff --git a/applications/services/power/power_service/power.c b/applications/services/power/power_service/power.c index aff3d946d..d2ced27de 100644 --- a/applications/services/power/power_service/power.c +++ b/applications/services/power/power_service/power.c @@ -86,10 +86,10 @@ void power_draw_battery_callback(Canvas* canvas, void* context) { } else if(bar_charge >= 62 && bar_charge < 74) { bar_charge = 74; } - canvas_set_color(canvas, ColorBlack); - canvas_draw_box(canvas, 1, 1, (bar_charge * 22) / 100, 6); // drawing digits + canvas_set_color(canvas, ColorBlack); + canvas_draw_box(canvas, 1, 1, (bar_charge * 22) / 100, 6); if(bar_charge < 38) { // both digits are black canvas_set_color(canvas, ColorBlack); canvas_draw_str_aligned( @@ -122,6 +122,7 @@ void power_draw_battery_callback(Canvas* canvas, void* context) { canvas_draw_str_aligned( canvas, 11, 4, AlignCenter, AlignCenter, batteryPercentile); } + } else { //default bar display, added here to serve as fallback/default behaviour. canvas_draw_box(canvas, 2, 2, (power->info.charge + 4) / 5, 4); } @@ -145,7 +146,7 @@ void power_draw_battery_callback(Canvas* canvas, void* context) { if(power->state == PowerStateCharging) { canvas_set_bitmap_mode(canvas, 1); // TODO: replace -1 magic for uint8_t with re-framing - if(battery_icon == BatteryIconPercent || battery_icon == BatteryIconBarPercent) { + if(battery_icon == BatteryIconPercent) { canvas_set_color(canvas, ColorBlack); canvas_draw_box(canvas, 1, 1, 22, 6); canvas_draw_icon(canvas, 2, -1, &I_Charging_lightning_9x10); @@ -163,6 +164,63 @@ void power_draw_battery_callback(Canvas* canvas, void* context) { canvas_set_font(canvas, FontBatteryPercent); canvas_draw_str_aligned( canvas, 16, 4, AlignCenter, AlignCenter, batteryPercentile); + } else if(battery_icon == BatteryIconBarPercent) { + // clean-up default charging bar display + canvas_set_color(canvas, ColorWhite); + canvas_draw_box(canvas, 1, 1, 22, 6); + + // align charge dispaly value with digits to draw + uint8_t bar_charge = power->info.charge; + + if(bar_charge > 48 && bar_charge < 63) { + bar_charge = 48; + } else if(bar_charge >= 63 && bar_charge < 84) { + bar_charge = 75; + } else if(bar_charge >= 84 && bar_charge < 96) { + bar_charge = 96; + } + canvas_set_color(canvas, ColorBlack); + canvas_draw_box(canvas, 1, 1, (bar_charge * 22) / 100, 6); + + // drawing charge icon + canvas_draw_icon(canvas, 2, -1, &I_Charging_lightning_9x10); + canvas_set_color(canvas, ColorWhite); + canvas_draw_icon(canvas, 2, -1, &I_Charging_lightning_mask_9x10); + + // drawing digits + canvas_set_font(canvas, FontBatteryPercent); + if(bar_charge < 64) { // both digits are black + canvas_set_color(canvas, ColorBlack); + canvas_draw_str_aligned( + canvas, 16, 4, AlignCenter, AlignCenter, batteryPercentile); + } else if(bar_charge >= 64 && bar_charge < 84) { // first digit is white + canvas_set_color(canvas, ColorWhite); + + // first + char batteryPercentileFirstDigit[2]; + snprintf( + batteryPercentileFirstDigit, + sizeof(batteryPercentileFirstDigit), + "%c", + batteryPercentile[0]); + canvas_draw_str_aligned( + canvas, 14, 4, AlignCenter, AlignCenter, batteryPercentileFirstDigit); + + // second + char batteryPercentileSecondDigit[2]; + snprintf( + batteryPercentileSecondDigit, + sizeof(batteryPercentileSecondDigit), + "%c", + batteryPercentile[1]); + canvas_set_color(canvas, ColorBlack); + canvas_draw_str_aligned( + canvas, 20, 4, AlignCenter, AlignCenter, batteryPercentileSecondDigit); + } else { // charge >= 84, both digits are white + canvas_set_color(canvas, ColorWhite); + canvas_draw_str_aligned( + canvas, 16, 4, AlignCenter, AlignCenter, batteryPercentile); + } } else { canvas_set_color(canvas, ColorWhite); canvas_draw_icon(canvas, 8, -1, &I_Charging_lightning_mask_9x10); @@ -261,6 +319,7 @@ Power* power_alloc() { // Records power->notification = furi_record_open(RECORD_NOTIFICATION); power->gui = furi_record_open(RECORD_GUI); + // Pubsub power->event_pubsub = furi_pubsub_alloc(); power->settings_events = furi_pubsub_alloc(); diff --git a/applications/settings/about/about.c b/applications/settings/about/about.c index 4172214a9..518c3ff14 100644 --- a/applications/settings/about/about.c +++ b/applications/settings/about/about.c @@ -108,7 +108,7 @@ static DialogMessageButton hw_version_screen(DialogsApp* dialogs, DialogMessage* furi_hal_version_get_hw_target(), furi_hal_version_get_hw_body(), furi_hal_version_get_hw_connect(), - furi_hal_version_get_hw_region_name(), + furi_hal_version_get_hw_region_name_otp(), furi_hal_region_get_name(), my_name ? my_name : "Unknown"); diff --git a/assets/icons/SubGhz/Fishing_123x52.png b/assets/icons/SubGhz/Fishing_123x52.png new file mode 100644 index 000000000..1e365de8f Binary files /dev/null and b/assets/icons/SubGhz/Fishing_123x52.png differ diff --git a/assets/resources/badkb/layouts/ba-BA.kl b/assets/resources/badkb/assets/layouts/ba-BA.kl similarity index 100% rename from assets/resources/badkb/layouts/ba-BA.kl rename to assets/resources/badkb/assets/layouts/ba-BA.kl diff --git a/assets/resources/badkb/layouts/cz_CS.kl b/assets/resources/badkb/assets/layouts/cz_CS.kl similarity index 100% rename from assets/resources/badkb/layouts/cz_CS.kl rename to assets/resources/badkb/assets/layouts/cz_CS.kl diff --git a/assets/resources/badkb/layouts/da-DA.kl b/assets/resources/badkb/assets/layouts/da-DA.kl similarity index 100% rename from assets/resources/badkb/layouts/da-DA.kl rename to assets/resources/badkb/assets/layouts/da-DA.kl diff --git a/assets/resources/badkb/layouts/de-CH.kl b/assets/resources/badkb/assets/layouts/de-CH.kl similarity index 100% rename from assets/resources/badkb/layouts/de-CH.kl rename to assets/resources/badkb/assets/layouts/de-CH.kl diff --git a/assets/resources/badkb/layouts/de-DE.kl b/assets/resources/badkb/assets/layouts/de-DE.kl similarity index 100% rename from assets/resources/badkb/layouts/de-DE.kl rename to assets/resources/badkb/assets/layouts/de-DE.kl diff --git a/assets/resources/badkb/layouts/dvorak.kl b/assets/resources/badkb/assets/layouts/dvorak.kl similarity index 100% rename from assets/resources/badkb/layouts/dvorak.kl rename to assets/resources/badkb/assets/layouts/dvorak.kl diff --git a/assets/resources/badkb/layouts/en-UK.kl b/assets/resources/badkb/assets/layouts/en-UK.kl similarity index 100% rename from assets/resources/badkb/layouts/en-UK.kl rename to assets/resources/badkb/assets/layouts/en-UK.kl diff --git a/assets/resources/badkb/layouts/en-US.kl b/assets/resources/badkb/assets/layouts/en-US.kl similarity index 100% rename from assets/resources/badkb/layouts/en-US.kl rename to assets/resources/badkb/assets/layouts/en-US.kl diff --git a/assets/resources/badkb/layouts/es-ES.kl b/assets/resources/badkb/assets/layouts/es-ES.kl similarity index 100% rename from assets/resources/badkb/layouts/es-ES.kl rename to assets/resources/badkb/assets/layouts/es-ES.kl diff --git a/assets/resources/badkb/layouts/fr-BE.kl b/assets/resources/badkb/assets/layouts/fr-BE.kl similarity index 100% rename from assets/resources/badkb/layouts/fr-BE.kl rename to assets/resources/badkb/assets/layouts/fr-BE.kl diff --git a/assets/resources/badkb/layouts/fr-CH.kl b/assets/resources/badkb/assets/layouts/fr-CH.kl similarity index 100% rename from assets/resources/badkb/layouts/fr-CH.kl rename to assets/resources/badkb/assets/layouts/fr-CH.kl diff --git a/assets/resources/badkb/layouts/fr-FR.kl b/assets/resources/badkb/assets/layouts/fr-FR.kl similarity index 100% rename from assets/resources/badkb/layouts/fr-FR.kl rename to assets/resources/badkb/assets/layouts/fr-FR.kl diff --git a/assets/resources/badkb/layouts/hr-HR.kl b/assets/resources/badkb/assets/layouts/hr-HR.kl similarity index 100% rename from assets/resources/badkb/layouts/hr-HR.kl rename to assets/resources/badkb/assets/layouts/hr-HR.kl diff --git a/assets/resources/badkb/layouts/hu-HU.kl b/assets/resources/badkb/assets/layouts/hu-HU.kl similarity index 100% rename from assets/resources/badkb/layouts/hu-HU.kl rename to assets/resources/badkb/assets/layouts/hu-HU.kl diff --git a/assets/resources/badkb/layouts/it-IT.kl b/assets/resources/badkb/assets/layouts/it-IT.kl similarity index 100% rename from assets/resources/badkb/layouts/it-IT.kl rename to assets/resources/badkb/assets/layouts/it-IT.kl diff --git a/assets/resources/badkb/layouts/nb-NO.kl b/assets/resources/badkb/assets/layouts/nb-NO.kl similarity index 100% rename from assets/resources/badkb/layouts/nb-NO.kl rename to assets/resources/badkb/assets/layouts/nb-NO.kl diff --git a/assets/resources/badkb/layouts/nl-NL.kl b/assets/resources/badkb/assets/layouts/nl-NL.kl similarity index 100% rename from assets/resources/badkb/layouts/nl-NL.kl rename to assets/resources/badkb/assets/layouts/nl-NL.kl diff --git a/assets/resources/badkb/layouts/pt-BR.kl b/assets/resources/badkb/assets/layouts/pt-BR.kl similarity index 100% rename from assets/resources/badkb/layouts/pt-BR.kl rename to assets/resources/badkb/assets/layouts/pt-BR.kl diff --git a/assets/resources/badkb/layouts/pt-PT.kl b/assets/resources/badkb/assets/layouts/pt-PT.kl similarity index 100% rename from assets/resources/badkb/layouts/pt-PT.kl rename to assets/resources/badkb/assets/layouts/pt-PT.kl diff --git a/assets/resources/badkb/layouts/si-SI.kl b/assets/resources/badkb/assets/layouts/si-SI.kl similarity index 100% rename from assets/resources/badkb/layouts/si-SI.kl rename to assets/resources/badkb/assets/layouts/si-SI.kl diff --git a/assets/resources/badkb/layouts/sk-SK.kl b/assets/resources/badkb/assets/layouts/sk-SK.kl similarity index 100% rename from assets/resources/badkb/layouts/sk-SK.kl rename to assets/resources/badkb/assets/layouts/sk-SK.kl diff --git a/assets/resources/badkb/layouts/sv-SE.kl b/assets/resources/badkb/assets/layouts/sv-SE.kl similarity index 100% rename from assets/resources/badkb/layouts/sv-SE.kl rename to assets/resources/badkb/assets/layouts/sv-SE.kl diff --git a/assets/resources/badkb/layouts/tr-TR.kl b/assets/resources/badkb/assets/layouts/tr-TR.kl similarity index 100% rename from assets/resources/badkb/layouts/tr-TR.kl rename to assets/resources/badkb/assets/layouts/tr-TR.kl diff --git a/assets/resources/infrared/assets/ac.ir b/assets/resources/infrared/assets/ac.ir index 4d9a85041..e55c27f30 100644 --- a/assets/resources/infrared/assets/ac.ir +++ b/assets/resources/infrared/assets/ac.ir @@ -1,7 +1,7 @@ Filetype: IR library file Version: 1 -# Last Updated 13th Jan, 2023 -# Last Checked 31th Jan, 2023 +# Last Updated 15th Feb, 2023 +# Last Checked 15th Feb, 2023 # name: POWER type: raw @@ -1541,78 +1541,22 @@ name: TEMP- type: raw frequency: 38000 duty_cycle: 0.330000 -data: 2320 634 837 637 838 637 838 640 835 642 832 1378 836 645 826 670 809 667 808 1406 806 672 803 674 802 1412 802 1412 800 676 801 675 802 1412 802 674 802 1413 801 1412 801 1413 802 1412 802 50937 2285 671 801 1411 802 51225 2280 696 775 1412 801 51212 2283 671 775 1412 802 -# Model: Daikin FTXM20M. +data: 3110 1567 551 1031 550 356 471 1032 550 356 471 356 445 1084 497 355 472 357 497 356 472 1058 523 1058 523 356 471 356 470 357 469 357 470 357 474 357 470 1063 519 357 470 1063 518 1063 519 1063 518 357 470 357 471 # -name: Off +name: POWER type: raw frequency: 38000 duty_cycle: 0.330000 -data: 500 393 473 392 473 368 498 368 497 367 499 25050 3533 1662 502 1230 501 392 472 393 471 395 469 1263 467 400 465 401 465 401 465 401 465 1267 465 401 465 1268 464 1268 464 402 464 1268 464 1269 463 1269 463 1292 440 1269 463 404 462 426 439 1293 439 426 440 426 440 426 440 426 440 426 440 427 439 426 440 427 439 427 438 427 439 1294 438 427 439 1294 438 427 439 427 439 428 438 1294 438 1294 438 428 438 428 437 428 438 428 438 1294 438 428 438 428 438 429 437 429 437 429 436 429 437 429 437 429 437 429 436 429 437 430 436 1296 436 1296 436 1296 436 430 436 430 435 1297 435 1297 435 1298 434 35482 3500 1699 464 1268 464 402 463 402 463 403 463 1269 463 426 440 426 439 426 440 426 439 1293 439 426 440 1293 439 1293 439 427 439 1293 439 1293 439 1293 439 1293 439 1294 438 427 438 427 439 1294 438 427 439 428 438 428 438 428 438 427 438 428 438 428 437 428 438 428 437 428 438 428 438 1295 437 429 437 429 437 429 436 429 437 1296 436 429 437 429 436 429 437 430 436 430 436 430 435 430 436 430 435 431 435 431 435 431 435 455 410 456 409 1322 410 456 409 456 410 456 410 456 410 456 410 1323 409 457 409 457 409 1323 409 1323 409 457 409 35483 3500 1699 464 1268 464 402 464 402 463 403 463 1269 463 426 440 426 440 426 440 426 439 1293 439 426 439 1293 439 1293 439 427 439 1293 439 1293 439 1293 439 1294 438 1293 438 427 439 427 438 1294 438 428 438 427 438 428 438 428 438 428 438 428 437 428 438 428 438 428 438 428 438 428 438 428 438 429 437 429 437 429 437 429 437 429 437 429 437 429 437 429 437 430 436 1296 436 430 436 1297 435 430 436 430 436 431 435 431 435 456 410 456 410 456 410 456 409 1323 409 1322 410 456 410 456 409 457 409 457 409 457 409 457 409 457 408 457 409 1324 408 1324 408 1324 408 1324 408 458 408 1325 406 459 407 1351 356 1376 356 1376 356 1376 356 1377 355 510 355 510 356 511 355 511 354 511 355 537 328 537 329 538 328 538 327 538 328 539 327 565 300 566 300 1432 300 1433 298 593 272 594 271 621 245 621 244 622 243 +data: 3087 1607 488 1064 517 335 492 1087 484 315 512 340 487 1091 490 336 491 338 489 1089 492 333 494 332 485 341 486 340 487 338 489 336 491 339 488 1090 491 334 493 1085 486 340 487 1091 490 1088 493 333 484 343 484 44227 178 # -name: Dh +name: TIMER type: raw frequency: 38000 duty_cycle: 0.330000 -data: 500 368 498 369 497 367 499 366 499 367 499 25050 3533 1662 502 1230 501 392 472 393 471 395 469 1264 467 400 465 401 465 401 465 401 465 1267 465 401 465 1268 464 1268 464 402 464 1269 463 1269 463 1269 463 1292 440 1292 440 426 440 426 440 1293 439 426 440 426 439 426 440 426 440 427 439 427 438 427 439 427 439 427 439 427 439 1293 439 427 439 1294 438 427 439 427 439 428 437 1294 438 1294 438 428 437 428 438 428 437 429 437 1295 437 428 437 429 437 429 437 429 436 429 437 429 437 429 437 429 437 429 437 429 437 430 436 1296 436 1297 435 1297 435 431 435 455 410 1298 434 1322 410 1322 410 35482 3500 1700 464 1269 463 403 463 403 463 403 462 1292 440 426 440 426 440 426 440 426 439 1293 439 426 440 1293 439 1293 439 427 439 1293 439 1293 439 1293 439 1293 439 1293 439 427 439 427 439 1294 438 427 439 427 439 427 439 428 438 427 438 428 438 428 438 428 437 428 438 428 438 428 438 1295 437 429 437 429 436 429 437 429 437 1296 436 429 437 429 437 429 437 430 436 430 436 430 436 431 435 431 435 431 435 455 410 456 410 456 410 456 410 1322 410 456 410 456 410 456 409 457 409 456 409 1323 409 457 409 457 409 1323 409 1324 408 458 408 35483 3500 1700 464 1268 464 402 464 403 463 402 464 1292 440 426 440 426 440 426 439 426 440 1293 439 426 440 1293 439 1293 439 427 439 1293 439 1293 439 1293 438 1293 439 1293 439 427 439 427 438 1294 438 428 438 428 438 427 438 428 438 428 438 428 438 428 438 428 438 428 438 428 437 428 438 429 436 429 437 429 437 429 437 429 437 429 437 429 437 1296 436 430 435 430 436 1297 435 431 435 1297 435 431 435 456 409 456 410 456 409 456 410 456 410 456 410 456 410 1323 409 1323 409 457 409 457 409 457 408 457 409 457 409 458 408 458 407 458 408 1325 407 1326 405 1327 406 1351 381 485 356 1376 356 510 355 1377 355 1377 355 1377 355 1378 354 1378 354 512 354 512 354 538 327 538 328 538 328 539 326 565 300 566 300 566 299 567 299 593 272 621 244 596 270 1488 244 +data: 3092 1602 492 1059 512 341 486 1092 489 337 490 336 491 1087 494 332 485 344 493 1085 486 1093 488 1064 517 1061 520 333 494 332 484 341 486 343 484 1094 487 1091 490 336 491 335 492 334 493 333 484 1094 487 340 487 # -name: Cool_hi +name: POWER type: raw frequency: 38000 duty_cycle: 0.330000 -data: 504 389 477 364 501 364 502 364 501 364 502 25048 3511 1684 505 1228 504 389 475 390 474 392 472 1260 470 396 469 396 470 396 469 397 469 1263 469 397 469 1263 469 1263 469 397 468 1263 469 1263 469 1264 468 1263 469 1264 468 397 468 398 468 1264 468 398 468 398 468 398 468 398 468 398 468 399 467 398 468 399 467 423 443 400 466 1289 443 423 443 1289 443 423 443 423 443 423 443 1289 443 1290 442 424 442 423 442 423 443 424 442 1290 442 424 442 423 443 424 442 424 441 424 442 424 441 424 442 424 442 424 441 424 442 424 442 1291 441 1291 441 1291 441 425 441 425 441 1291 441 1291 441 1291 441 35478 3505 1695 468 1264 468 398 467 398 468 398 468 1265 467 398 467 398 468 398 468 399 467 1265 467 399 467 1266 466 1266 466 423 443 1289 443 1290 442 1290 442 1290 442 1290 442 424 442 423 442 1290 442 423 443 424 442 424 442 424 442 424 441 424 442 424 442 424 441 424 442 424 442 424 442 1291 441 425 441 425 441 424 442 424 441 1291 441 425 441 425 440 425 441 425 441 425 441 425 441 425 441 425 440 425 441 425 441 425 440 426 440 426 440 1292 440 426 440 426 440 426 440 426 439 427 439 1293 439 427 439 427 438 1294 438 1294 438 428 437 35479 3504 1695 468 1264 468 398 468 398 468 398 467 1265 467 399 467 399 467 399 466 399 467 1265 467 399 467 1289 443 1290 442 423 443 1290 442 1290 442 1290 442 1290 442 1290 442 423 443 424 442 1290 442 424 442 424 442 424 441 424 442 424 442 424 442 424 442 424 442 424 442 424 442 424 442 424 442 425 441 425 440 425 441 425 441 425 441 425 441 1291 441 425 441 425 441 1292 440 1292 440 1292 440 426 440 425 441 426 440 426 440 1292 440 426 440 426 440 1292 440 426 440 426 440 426 440 427 439 426 440 426 440 427 438 427 439 427 439 427 439 1294 438 1295 437 1294 438 1319 413 453 413 1319 413 453 412 1320 412 1319 413 1319 413 1319 413 1320 412 453 412 453 413 453 412 454 412 454 411 454 412 454 412 454 412 454 412 454 412 455 411 454 412 455 411 1321 411 1321 411 456 409 456 410 481 384 482 384 482 383 482 359 506 360 507 359 507 359 507 358 1374 358 1374 358 508 357 508 358 509 357 534 332 534 332 534 332 534 332 535 331 535 331 535 331 535 330 536 330 536 330 562 303 563 303 563 302 564 302 1430 302 565 301 564 302 591 274 619 247 619 247 1512 219 1539 190 -# -name: Cool_lo -type: raw -frequency: 38000 -duty_cycle: 0.330000 -data: 502 390 476 365 501 365 500 365 500 365 501 25049 3535 1660 504 1229 502 390 474 391 473 393 471 1261 469 397 468 398 468 398 468 398 468 1264 468 398 468 1265 467 1265 467 399 467 1265 467 1265 467 1265 467 1266 466 1265 467 400 466 401 465 1266 466 401 465 401 465 401 465 424 442 424 441 424 442 424 441 424 442 424 442 424 442 1291 441 424 442 1291 441 424 442 425 440 425 441 1291 441 1291 441 425 441 425 441 425 440 425 441 1292 440 425 441 425 441 425 441 425 441 425 441 425 441 425 441 425 440 426 440 426 440 426 440 1292 440 1293 439 1293 439 426 439 427 439 1293 439 1293 439 1293 439 35480 3503 1696 467 1265 467 399 467 398 468 399 466 1266 466 399 467 399 467 399 467 399 467 1266 466 400 466 1267 465 1290 442 424 442 1290 442 1290 442 1290 442 1290 441 1291 441 424 442 424 442 1291 441 424 442 424 442 425 441 424 442 424 442 425 441 425 440 425 441 425 441 425 441 425 441 1292 440 425 441 425 441 425 440 426 440 1292 440 426 440 426 439 426 440 426 439 426 440 426 440 426 440 426 440 426 440 427 438 427 439 427 439 427 439 1293 439 427 438 427 439 428 438 428 438 428 438 1294 438 428 438 428 438 1295 437 1320 412 453 413 35480 3503 1696 467 1265 467 399 467 399 467 399 467 1266 466 399 467 399 467 400 466 400 466 1290 442 424 442 1289 443 1290 442 424 442 1291 441 1290 442 1290 442 1291 441 1291 441 424 442 424 442 1291 441 425 441 425 441 425 441 425 441 425 441 425 441 425 441 425 441 425 440 425 441 425 441 425 441 425 441 425 441 425 440 426 440 426 440 426 440 1292 440 426 440 426 440 1292 440 1293 439 1293 439 427 439 426 439 427 439 1293 439 1293 439 1293 439 427 438 1294 438 427 439 427 438 428 438 427 438 453 413 429 437 429 437 429 437 453 412 454 412 1320 412 1320 412 1320 412 1320 412 454 412 1321 411 454 412 1320 412 1321 411 1321 411 1321 411 1321 411 455 410 455 411 455 411 455 411 455 411 456 410 456 410 457 409 481 384 457 409 482 383 483 383 483 358 1374 358 1374 358 508 357 508 358 509 357 509 357 509 357 509 357 510 356 535 330 536 330 536 330 1402 330 1403 329 537 329 536 329 563 302 564 302 564 302 565 300 565 300 592 273 619 246 620 246 619 246 620 245 674 188 -# -name: Heat_hi -type: raw -frequency: 38000 -duty_cycle: 0.330000 -data: 504 365 500 365 500 365 500 365 501 365 501 25049 3535 1660 504 1229 502 390 474 391 473 393 471 1261 470 397 468 397 469 398 468 398 468 1264 468 398 467 1265 467 1265 467 398 468 1265 467 1265 467 1265 467 1266 466 1266 466 399 466 399 467 1266 466 400 466 400 466 400 465 400 466 424 442 424 442 424 442 424 441 424 442 424 442 1291 441 424 442 1291 441 424 442 424 442 425 441 1291 441 1291 441 425 440 425 441 425 441 425 440 1292 440 425 441 425 440 425 441 425 441 425 441 425 441 425 441 426 440 426 440 426 440 426 439 1293 439 1293 439 1293 439 426 440 427 439 1293 439 1293 439 1293 439 35480 3503 1696 468 1264 468 398 468 398 468 398 467 1265 467 399 467 399 467 399 467 399 467 1267 465 400 466 1266 466 1267 465 424 441 1290 442 1290 442 1290 442 1290 442 1291 441 424 442 424 442 1291 441 424 442 424 442 424 442 424 442 424 441 425 441 425 441 425 441 425 441 425 441 425 441 1292 440 425 441 425 441 425 441 425 441 1292 440 426 440 426 439 426 440 426 440 426 439 426 440 426 440 426 439 427 439 426 440 427 439 427 439 427 438 1293 439 427 439 427 439 427 439 428 438 428 438 1295 437 428 438 429 436 1296 436 1296 436 453 412 35481 3502 1696 467 1265 467 399 466 399 467 399 467 1265 467 399 467 399 467 399 466 400 466 1266 466 400 466 1290 442 1267 465 424 442 1290 442 1290 442 1290 442 1290 442 1291 441 424 442 424 441 1291 441 424 442 424 442 424 442 424 441 425 441 425 441 425 441 425 441 425 441 425 441 425 441 425 441 425 440 426 440 425 441 425 441 425 441 426 440 1292 440 426 440 426 440 1292 440 426 440 426 439 1293 439 427 439 427 439 427 439 1293 439 1294 438 1294 438 1293 439 427 439 428 438 428 438 428 438 429 436 429 437 429 437 453 412 453 413 453 412 1320 412 1320 412 1320 412 1320 412 454 412 1320 412 454 412 1321 411 1321 411 1321 411 1321 411 1322 410 455 411 455 411 456 410 456 410 455 410 456 410 456 409 481 384 458 408 482 383 482 384 483 358 508 358 1374 358 1374 358 508 357 509 357 509 357 510 355 535 330 536 330 536 330 536 329 536 330 536 330 1403 329 1430 301 564 302 564 302 564 301 591 274 566 301 592 273 619 247 619 247 620 245 647 219 -# -name: Heat_lo -type: raw -frequency: 38000 -duty_cycle: 0.330000 -data: 503 365 500 364 501 366 499 365 500 364 502 25049 3535 1660 504 1228 503 390 474 391 473 393 471 1261 469 397 468 397 469 397 469 397 469 1264 468 398 468 1264 468 1264 468 398 468 1265 467 1265 467 1265 467 1265 467 1265 467 399 467 399 467 1266 466 399 467 400 466 400 466 400 466 423 443 423 443 401 465 423 442 424 442 424 442 1290 442 424 442 1290 442 424 442 424 441 424 442 1290 442 1291 441 425 441 424 442 425 441 425 441 1291 441 425 440 425 441 425 441 425 441 425 441 425 440 425 441 425 441 425 441 425 441 426 440 1292 440 1292 440 1292 440 426 440 426 440 1292 440 1293 439 1293 439 35480 3503 1696 467 1264 468 398 468 398 467 398 468 1265 467 398 467 399 467 399 466 399 467 1265 467 399 467 1266 466 1267 465 400 466 1290 442 1290 442 1290 442 1290 442 1290 442 424 442 424 442 1290 442 424 441 424 442 424 442 424 442 424 442 424 441 424 442 425 441 424 442 425 441 425 441 1291 441 425 441 425 441 425 441 425 440 1292 440 425 441 425 440 426 440 426 440 426 440 426 440 426 440 426 440 426 440 426 439 427 439 426 440 426 440 1293 439 427 439 427 439 427 438 427 439 428 438 1294 438 428 437 428 438 1295 437 1319 413 453 413 35480 3503 1696 468 1265 467 398 468 398 468 398 468 1265 467 398 468 399 466 399 467 399 467 1266 466 399 466 1267 465 1290 442 401 465 1290 442 1290 442 1290 442 1290 442 1290 442 424 442 424 441 1291 441 424 442 424 442 424 442 424 442 424 441 424 442 425 441 424 442 424 441 425 441 425 441 425 440 425 441 425 441 425 441 425 441 425 441 425 441 1292 440 426 440 426 440 1292 440 426 440 426 440 1293 439 426 440 426 440 1293 439 1293 439 1293 439 427 439 1294 438 427 438 427 439 427 438 428 438 428 438 428 438 428 438 453 413 429 437 453 413 1319 413 1320 412 1320 412 1320 412 454 412 1320 412 454 412 1321 411 1321 411 1321 411 1321 411 1321 411 455 410 455 411 455 411 455 410 456 410 456 410 456 410 481 384 481 385 482 383 482 383 483 358 507 359 1374 358 1374 358 508 358 508 358 508 358 509 357 509 357 535 331 535 331 535 330 535 330 536 330 1403 329 1403 329 563 302 564 301 564 302 564 301 565 301 591 274 619 246 593 273 620 245 620 245 621 245 673 189 -# Model: Mitsubishi SRK63HE. -# -name: Off -type: raw -frequency: 38000 -duty_cycle: 0.330000 -data: 3232 1526 463 334 462 1127 464 334 460 334 461 1128 463 336 459 1128 464 359 436 359 436 1133 458 1156 434 1157 434 362 433 1159 432 363 432 1159 432 1159 432 1159 432 363 433 363 432 363 432 363 432 1160 431 1160 432 363 432 1160 431 1160 431 363 432 364 432 1160 431 363 432 363 432 1160 432 363 432 364 431 1160 431 1160 431 364 431 1160 431 1160 431 1160 431 1160 431 1160 431 1160 431 364 431 1160 431 1160 431 1160 431 364 432 364 432 364 431 364 431 1160 432 364 432 364 431 364 431 1160 431 1160 431 1160 431 364 431 1161 430 1161 430 1160 431 1161 430 364 432 364 431 365 431 1161 430 364 431 365 431 364 431 365 430 365 431 1161 430 1161 430 1161 430 365 430 1161 430 365 430 365 430 1161 430 365 430 365 431 365 430 1161 430 365 430 1161 430 1161 430 -# -name: Dh -type: raw -frequency: 38000 -duty_cycle: 0.330000 -data: 3229 1528 461 335 461 1128 463 334 461 335 460 1129 463 337 458 1129 463 359 436 360 434 1156 434 1157 433 1159 432 364 431 1161 430 364 431 1161 430 1161 430 1160 431 364 431 364 431 365 430 365 430 1161 430 1161 430 365 430 1161 430 1161 431 365 430 365 431 1161 430 365 430 365 430 1161 430 365 430 365 431 1161 430 1161 430 365 431 1161 430 1161 430 1161 430 1161 430 1161 431 1161 430 365 430 1161 430 1161 430 1161 431 365 430 365 430 365 430 365 430 1162 430 365 430 365 430 365 431 1162 429 1162 429 1162 430 365 430 1162 429 1162 429 1162 429 1162 429 366 430 366 429 366 430 1162 429 366 429 366 430 366 429 366 429 1162 429 366 429 1163 428 366 429 1162 429 366 429 366 429 1162 429 366 430 1162 429 366 429 1163 429 366 430 1163 428 1163 428 367 428 -# -name: Cool_hi -type: raw -frequency: 38000 -duty_cycle: 0.330000 -data: 3230 1526 463 335 460 1128 464 333 461 335 460 1128 463 337 458 1128 463 359 436 359 436 1155 435 1157 433 1158 432 363 432 1160 431 364 431 1161 430 1160 431 1160 431 364 431 364 431 364 431 364 431 1161 430 1161 430 364 431 1161 430 1160 431 365 430 364 431 1161 431 364 431 364 431 1161 430 365 430 365 431 1161 430 1161 431 364 431 1161 430 1161 430 1161 430 1161 431 1161 430 1161 431 365 430 1161 431 1161 430 1162 430 365 430 365 430 365 431 365 430 1161 430 365 430 365 430 365 431 1161 430 1162 430 1162 429 365 430 1162 429 1162 429 1162 429 1162 429 366 429 366 430 366 430 1162 429 366 430 366 429 366 429 366 430 366 429 1162 429 1163 429 366 429 366 429 1163 428 1163 428 1163 429 1163 428 366 429 366 430 1163 428 1163 428 367 428 367 429 366 429 -# -name: Cool_lo -type: raw -frequency: 38000 -duty_cycle: 0.330000 -data: 3231 1526 463 334 461 1127 465 333 461 334 460 1128 463 336 459 1129 463 359 436 359 436 1133 458 1156 434 1157 433 362 433 1159 432 363 432 1159 432 1160 431 1159 433 363 432 363 432 363 432 363 432 1159 433 1159 432 363 432 1159 432 1160 432 363 432 363 432 1159 432 363 432 363 433 1159 432 364 432 363 432 1160 431 1160 432 363 432 1160 431 1160 431 1160 431 1160 432 1160 431 1160 431 364 432 1160 431 1160 431 1160 431 364 431 364 431 364 432 364 431 1160 432 364 431 364 431 364 432 1160 431 1161 430 1161 430 364 431 1161 431 1161 430 1161 430 1161 430 364 432 364 431 364 431 1161 430 365 430 365 430 365 430 365 431 365 430 1161 430 1161 431 365 430 1161 430 365 430 365 431 1161 430 1161 430 365 431 365 430 1162 430 365 431 1161 430 1162 429 365 430 -# -name: Heat_hi -type: raw -frequency: 38000 -duty_cycle: 0.330000 -data: 3230 1526 463 334 461 1128 464 333 461 334 461 1128 463 336 459 1129 463 359 436 359 436 1155 435 1156 434 1158 433 363 432 1159 432 363 432 1159 432 1160 431 1160 431 363 433 363 432 363 432 363 432 1160 432 1160 431 364 431 1160 431 1160 432 364 431 364 431 1160 431 364 431 364 432 1160 431 364 431 364 431 1160 431 1160 431 364 432 1160 431 1160 431 1160 431 1160 431 1160 431 1160 431 364 431 1160 432 1160 431 1160 431 364 432 364 431 364 431 364 431 1161 430 364 431 364 432 364 431 1161 430 1161 430 1161 430 365 430 1161 431 1161 430 1161 430 1161 430 365 430 365 430 365 430 1161 430 365 431 365 431 365 430 365 431 1161 430 1161 430 365 430 365 430 365 430 1162 430 365 430 365 430 365 431 365 430 1162 429 1162 430 1162 429 366 429 1162 429 1162 429 -# -name: Heat_lo -type: raw -frequency: 38000 -duty_cycle: 0.330000 -data: 3234 1525 463 333 462 1127 465 332 462 333 436 1153 518 307 488 1073 518 307 488 308 434 1131 459 1155 435 1156 434 362 433 1159 432 363 432 1159 432 1159 432 1159 433 363 432 363 432 363 433 363 432 1159 433 1159 432 363 432 1159 433 1159 432 363 432 363 432 1159 432 363 433 363 432 1159 432 363 432 363 432 1159 432 1159 432 363 432 1160 432 1160 431 1160 432 1160 431 1160 431 1160 431 364 431 1160 431 1160 431 1160 431 364 431 364 431 364 431 364 431 1160 431 364 431 364 431 364 431 1160 432 1160 431 1160 432 364 431 1160 431 1160 431 1161 431 1161 430 364 431 364 431 364 431 1160 432 364 431 364 431 364 432 364 431 1161 431 1161 431 364 431 364 431 1161 430 364 432 364 431 1161 430 365 431 365 431 1161 430 1161 430 365 431 1161 430 1161 430 365 430 +data: 8838 3941 624 1427 514 500 515 497 541 473 540 1487 540 474 539 474 538 476 512 1538 514 1516 544 466 514 497 514 501 514 499 514 500 513 499 513 501 487 525 514 499 512 502 487 526 512 1517 542 470 487 1539 513 499 512 503 513 499 512 1513 512 diff --git a/assets/resources/infrared/assets/audio.ir b/assets/resources/infrared/assets/audio.ir index ae29a43f0..1bb3c11e0 100644 --- a/assets/resources/infrared/assets/audio.ir +++ b/assets/resources/infrared/assets/audio.ir @@ -1,7 +1,7 @@ Filetype: IR library file Version: 1 -# Last Updated 30th Jan, 2023 -# Last Checked 31th Jan, 2023 +# Last Updated 15th Feb, 2023 +# Last Checked 15th Feb, 2023 # name: POWER type: parsed @@ -2032,3 +2032,39 @@ type: parsed protocol: NEC address: 80 00 00 00 command: 04 00 00 00 +# +name: MUTE +type: parsed +protocol: NEC42 +address: 6E 00 00 00 +command: 4C 00 00 00 +# +name: VOL+ +type: parsed +protocol: NEC +address: 01 00 00 00 +command: 11 00 00 00 +# +name: VOL- +type: parsed +protocol: NEC +address: 01 00 00 00 +command: 10 00 00 00 +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4555 4463 532 473 532 473 531 474 530 474 530 1478 531 1478 531 475 529 476 528 1482 551 1480 529 1480 528 1481 528 477 527 478 527 478 526 478 527 4498 526 477 527 477 527 478 526 478 526 478 526 478 526 478 527 478 526 1483 527 1483 526 1483 526 478 526 1483 527 1483 527 1483 526 1483 526 478 526 478 527 478 527 1484 526 55527 4527 4492 526 478 526 478 526 478 526 479 526 1483 527 1483 526 478 526 478 526 1483 527 1483 526 1483 526 1483 526 478 527 478 526 479 526 478 526 4497 526 478 526 478 526 478 526 478 526 478 526 478 526 478 526 478 526 1484 525 1483 526 1484 525 478 526 1484 525 1484 525 1484 525 1484 525 478 526 479 526 479 525 1484 525 +# +name: VOL+ +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4552 4463 531 474 530 474 530 474 530 474 530 1478 531 1478 531 475 529 476 553 1455 554 1478 530 1479 529 1481 527 477 527 478 526 478 526 478 526 4497 526 478 526 478 526 478 526 477 527 1483 526 1482 527 1482 527 478 526 1483 526 1483 526 1483 526 478 526 478 526 478 526 478 526 1483 526 478 526 478 526 478 526 1483 526 +# +name: VOL- +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 325 50440 173 137541 4551 4465 530 475 529 475 529 474 530 474 530 1479 530 1479 529 476 528 477 527 1480 554 1457 551 1480 528 1481 527 477 527 478 526 478 526 478 526 4497 525 478 526 478 526 478 526 478 526 479 525 479 525 479 525 1484 525 1483 526 1484 525 1483 526 479 525 1483 526 1483 526 1483 526 479 525 479 525 479 525 479 525 1484 525 diff --git a/assets/resources/infrared/assets/fans.ir b/assets/resources/infrared/assets/fans.ir index 942c2df13..c30f58e5e 100644 --- a/assets/resources/infrared/assets/fans.ir +++ b/assets/resources/infrared/assets/fans.ir @@ -1,7 +1,7 @@ Filetype: IR library file Version: 1 -# Last Updated 31th Jan, 2023 -# Last Checked 31th Jan, 2023 +# Last Updated 15th Feb, 2023 +# Last Checked 15th Feb, 2023 # name: POWER type: raw @@ -1364,4 +1364,58 @@ name: ROTATE type: raw frequency: 38000 duty_cycle: 0.330000 -data: 2256 698 786 695 786 689 787 1348 787 1342 787 673 788 668 787 663 787 722 786 696 784 1353 786 1375 759 706 759 702 783 672 783 1332 782 102265 2310 645 838 668 812 664 811 1323 810 1319 810 651 809 647 808 642 808 701 807 673 807 1332 807 1327 807 658 808 653 807 648 807 1307 807 \ No newline at end of file +data: 2256 698 786 695 786 689 787 1348 787 1342 787 673 788 668 787 663 787 722 786 696 784 1353 786 1375 759 706 759 702 783 672 783 1332 782 102265 2310 645 838 668 812 664 811 1323 810 1319 810 651 809 647 808 642 808 701 807 673 807 1332 807 1327 807 658 808 653 807 648 807 1307 807 +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1356 337 1423 337 516 1157 1298 409 1296 416 448 1274 451 1276 452 1274 450 1274 449 1277 449 1275 1301 7091 1301 407 1300 405 450 1267 1302 407 1301 414 450 1274 451 1275 451 1275 451 1276 450 1275 451 1274 1302 7074 1303 406 1302 406 450 1268 1301 409 1299 416 449 1277 472 1254 473 1253 473 1254 472 1254 473 1252 1323 7069 1325 384 1300 408 470 1247 1324 387 1299 417 471 1253 472 1254 472 1254 472 1254 472 1254 472 1252 1324 7052 1324 384 1300 408 472 1246 1324 387 1299 417 472 1253 472 1254 472 1254 472 1254 473 1254 472 1252 1324 7064 1325 385 1323 385 471 1246 1324 387 1323 394 471 1254 471 1254 472 1254 472 1254 472 1254 472 1252 1324 7053 1324 385 1323 385 471 1247 1323 387 1322 394 471 1254 472 1254 472 1255 471 1255 471 1255 472 1253 1323 7070 1323 385 1323 385 471 1247 1323 388 1322 395 470 1254 472 1255 471 1255 471 1255 471 1255 471 1253 1323 7054 1323 386 1322 386 470 1248 1322 413 1297 396 470 1255 470 1256 470 1256 470 1256 470 1256 471 1254 1322 7071 1322 411 1297 387 469 1249 1321 414 1296 396 470 1280 445 1281 446 1281 445 1282 445 1282 445 1280 1296 7076 1296 412 1296 412 444 1274 1297 413 1297 421 445 1281 445 1282 444 1282 444 1282 445 1282 444 1280 1296 7098 1295 412 1296 412 445 1275 1296 414 1296 421 445 1282 444 1282 445 1282 444 1283 444 1282 445 1280 1296 7082 1296 412 1296 412 445 1275 1295 414 1296 421 444 1282 444 1282 444 1283 444 1283 444 1282 445 1280 1296 7098 1296 413 1295 413 444 1275 1295 415 1295 422 444 1283 443 1282 444 1283 443 1282 445 1282 444 1281 1295 7082 1295 413 1295 413 444 1275 1295 415 1294 423 443 1283 443 1283 443 1283 443 1283 443 1283 443 1281 1294 7093 1295 413 1295 414 443 1276 1294 415 1295 423 443 1283 443 1283 443 1283 443 1283 444 1283 444 1280 1295 7082 1295 414 1294 414 443 1276 1294 416 1294 423 443 1283 443 1283 443 1283 443 1283 444 1283 444 1281 1294 7098 1295 414 1294 414 443 1276 1294 416 1294 424 442 1284 443 1283 443 1283 443 1284 443 1283 443 1281 1294 7083 1294 414 1294 415 442 1277 1293 417 1293 425 441 1284 442 1284 442 1284 442 1284 442 1284 443 1282 1293 7099 1294 415 1293 416 441 1278 1292 418 1292 425 441 1285 441 1285 441 1285 442 1285 441 1285 441 1283 1292 7083 1293 417 1291 441 415 1279 1292 443 1267 451 415 1286 440 1286 441 1286 440 1285 441 1286 440 1284 1291 7096 1292 441 1267 442 415 1304 1266 444 1266 451 415 1311 415 1287 439 1287 440 1311 415 1286 440 1285 1290 7085 1291 442 1241 467 414 1304 1266 445 1241 476 414 1313 414 1312 415 1311 415 1312 415 1312 414 1310 1241 7151 1242 467 1241 467 415 1305 1241 469 1241 477 412 1314 414 1312 414 1312 414 1312 414 1312 414 1310 1241 7135 1241 467 1241 468 389 1330 1241 470 1240 477 389 1337 389 1337 414 1312 414 1313 413 1313 389 1335 1241 7151 1241 469 1239 470 386 1331 1240 496 1214 503 362 1338 388 1338 388 1338 388 1338 388 1338 388 1336 1240 7130 1241 494 1214 495 361 1357 1214 497 1213 504 362 1364 362 1364 362 1364 363 1364 362 1364 362 1362 1214 7153 1239 495 1213 496 360 1358 1213 498 1212 531 334 1365 362 1365 361 1365 361 1365 362 1364 362 1363 1213 7162 1213 496 1212 522 334 1359 1212 524 1186 532 333 1367 359 1366 360 1366 361 1365 361 1365 361 1364 1211 7180 1212 523 1185 550 306 1387 1185 552 1157 586 278 1395 332 1394 332 1394 332 1393 333 1393 334 1391 1184 7190 1185 576 1131 604 250 1415 1158 660 1049 2341 251 1448 278 1422 305 1448 278 1448 278 1447 1130 7229 1157 +# +name: SPEED+ +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1357 353 1327 382 448 1239 1333 409 1301 416 477 1246 452 1274 452 1274 453 1273 479 1246 1330 416 448 7967 1300 409 1299 410 446 1273 1299 412 1298 419 446 1280 446 1281 446 1281 446 1281 446 1279 1298 419 446 7958 1298 411 1297 410 446 1273 1298 412 1298 419 446 1280 446 1281 445 1281 446 1281 445 1279 1298 419 446 7967 1298 410 1298 411 445 1274 1297 413 1297 420 445 1281 445 1281 445 1281 445 1282 445 1279 1298 420 445 7957 1297 411 1297 411 445 1274 1297 413 1297 420 445 1281 445 1281 445 1282 444 1282 444 1280 1296 420 445 7962 1297 411 1297 411 445 1274 1297 413 1297 420 445 1282 444 1282 444 1282 444 1282 444 1280 1297 421 444 7957 1296 412 1297 411 444 1275 1296 414 1296 421 444 1282 444 1283 443 1283 443 1282 444 1281 1296 421 444 7968 1296 412 1296 412 444 1275 1296 414 1296 421 444 1283 443 1283 443 1283 443 1283 443 1281 1296 422 443 7958 1295 413 1295 413 443 1276 1295 415 1295 422 443 1283 443 1284 442 1284 442 1284 442 1282 1294 422 443 7970 1293 414 1294 414 442 1277 1294 416 1294 423 442 1284 442 1309 417 1309 417 1309 417 1307 1269 424 441 7978 1270 416 1292 414 442 1302 1269 440 1270 424 441 1309 417 1309 417 1310 417 1309 417 1307 1270 448 417 7994 1269 439 1269 439 416 1302 1269 441 1269 448 416 1310 416 1310 416 1310 416 1310 416 1308 1269 448 416 7984 1269 439 1268 440 416 1303 1268 442 1267 449 415 1310 416 1310 416 1310 416 1310 416 1309 1268 449 416 7994 1268 440 1268 440 415 1303 1268 442 1268 449 415 1311 415 1311 415 1311 415 1311 415 1309 1267 450 415 7985 1267 441 1267 441 414 1304 1266 444 1267 450 414 1311 415 1312 413 1312 414 1312 414 1310 1265 452 414 7991 1266 442 1242 466 413 1306 1241 468 1242 475 414 1337 388 1338 388 1338 388 1338 388 1336 1217 501 386 8013 1215 492 1216 492 387 1331 1216 494 1216 501 363 1363 362 1363 363 1363 363 1363 387 1338 1215 502 362 8047 1215 493 1215 492 363 1356 1215 495 1215 502 362 1364 361 1364 362 1364 362 1364 362 1363 1214 503 361 8063 1189 494 1214 494 361 1382 1189 496 1214 503 361 1390 335 1391 335 1391 335 1391 335 1389 1188 529 335 8074 1188 520 1188 520 334 1385 1187 522 1187 529 334 1392 333 1417 308 1418 308 1419 307 1417 1161 556 307 8092 1160 547 1161 547 307 1412 1160 550 1160 557 306 1419 306 1446 279 1421 305 1446 279 1445 1133 584 279 8125 1133 575 1133 576 277 1466 1106 603 1107 611 251 1474 251 1501 224 1502 224 1528 186 1511 1079 638 224 8228 1025 735 972 2640 786 +# +name: SPEED+ +type: parsed +protocol: NEC +address: 01 00 00 00 +command: 1A 00 00 00 +# +name: POWER +type: parsed +protocol: NEC +address: 01 00 00 00 +command: 1D 00 00 00 +# +name: ROTATE +type: parsed +protocol: NEC +address: 01 00 00 00 +command: 18 00 00 00 +# +name: TIMER +type: parsed +protocol: NEC +address: 01 00 00 00 +command: 0D 00 00 00 +# +name: POWER +type: parsed +protocol: NECext +address: 80 DE 00 00 +command: 00 FF 00 00 +# +name: SPEED+ +type: parsed +protocol: NECext +address: 80 DE 00 00 +command: 08 F7 00 00 +# +name: SPEED- +type: parsed +protocol: NECext +address: 80 DE 00 00 +command: 10 EF 00 00 diff --git a/assets/resources/infrared/assets/projector.ir b/assets/resources/infrared/assets/projector.ir deleted file mode 100644 index e9861de21..000000000 --- a/assets/resources/infrared/assets/projector.ir +++ /dev/null @@ -1,829 +0,0 @@ -Filetype: IR library file -Version: 1 -# -# Model: Smart -name: Power -type: parsed -protocol: NEC -address: 00 00 00 00 -command: 8A 00 00 00 -# -# Model: Epson -name: Power -type: parsed -protocol: NECext -address: 83 55 00 00 -command: 90 6F 00 00 -# -# Model: Epson -name: Power -type: parsed -protocol: NECext -address: 81 03 00 00 -command: F0 0F 00 00 -# -# Model: Hitatchi -name: Power -type: parsed -protocol: NECext -address: 87 45 00 00 -command: 17 E8 00 00 -# -name: Power -type: raw -frequency: 38000 -duty_cycle: 0.330000 -data: 310 27591 171 27662 241 27731 307 27575 107 27749 306 27551 130 55520 243 27614 217 55584 129 27743 119 27756 115 27747 163 27712 308 27502 243 27650 217 27732 175 27693 167 27698 166 27689 171 27622 215 27712 133 27658 216 27716 129 27732 162 27698 305 27571 131 27753 310 27570 170 27707 162 27707 175 10960 9194 4518 618 542 618 543 725 434 672 1623 671 1647 646 514 592 568 592 568 592 1702 592 568 592 567 593 1702 592 568 618 1676 618 1676 618 1676 618 543 617 543 617 543 617 1677 617 544 616 544 616 544 616 544 616 1678 616 1678 616 1678 616 544 616 1678 616 1679 615 1678 616 1678 616 40239 9196 2250 617 -# -name: Vol_up -type: parsed -protocol: NEC -address: 08 00 00 00 -command: 48 00 00 00 -# -name: Vol_dn -type: parsed -protocol: NEC -address: 08 00 00 00 -command: 49 00 00 00 -# -name: Mute -type: parsed -protocol: NEC -address: 08 00 00 00 -command: 14 00 00 00 -# -name: Power -type: parsed -protocol: NEC -address: 08 00 00 00 -command: 0B 00 00 00 -# -name: Vol_dn -type: parsed -protocol: NEC -address: 01 00 00 00 -command: 40 00 00 00 -# -name: Vol_up -type: parsed -protocol: NEC -address: 01 00 00 00 -command: 48 00 00 00 -# -name: Mute -type: parsed -protocol: NEC -address: 01 00 00 00 -command: 44 00 00 00 -# -name: Vol_dn -type: parsed -protocol: NECext -address: 00 30 00 00 -command: 83 7C 00 00 -# -name: Vol_up -type: parsed -protocol: NECext -address: 00 30 00 00 -command: 82 7D 00 00 -# -name: Power -type: parsed -protocol: NECext -address: 08 13 00 00 -command: 87 78 00 00 -# -name: Power -type: raw -frequency: 38000 -duty_cycle: 0.330000 -data: 9055 4338 672 1551 669 1553 618 1603 619 481 617 482 616 481 617 507 591 1605 645 479 619 1577 645 1578 644 1578 644 479 619 480 618 1581 641 480 617 1605 617 1606 616 1606 615 483 615 1608 614 484 614 484 614 484 614 484 614 484 614 484 614 1609 614 484 614 1609 614 1609 613 1609 613 40058 9000 2068 614 95467 9022 2068 614 -# -name: Mute -type: parsed -protocol: NECext -address: 87 4E 00 00 -command: 29 D6 00 00 -# -name: Vol_up -type: parsed -protocol: NECext -address: 87 4E 00 00 -command: 08 F7 00 00 -# -name: Vol_dn -type: parsed -protocol: NECext -address: 87 4E 00 00 -command: 04 FB 00 00 -# -name: Mute -type: parsed -protocol: NECext -address: 83 55 00 00 -command: 93 6C 00 00 -# -name: Vol_dn -type: parsed -protocol: NEC -address: 02 00 00 00 -command: 15 00 00 00 -# -name: Vol_up -type: raw -frequency: 38000 -duty_cycle: 0.330000 -data: 9032 4462 598 501 627 1604 627 530 598 531 677 423 706 422 706 421 707 451 677 1554 677 451 598 1633 598 1634 597 1634 598 1634 598 1634 625 1606 681 1550 626 502 598 530 599 529 600 1632 600 528 600 528 601 528 601 528 601 1631 600 1631 625 1607 625 504 625 1607 624 1608 624 1608 623 -# -name: Mute -type: parsed -protocol: NEC -address: 02 00 00 00 -command: 02 00 00 00 -# -name: Power -type: parsed -protocol: NEC -address: 02 00 00 00 -command: 1D 00 00 00 -# -# ON -name: Power -type: raw -frequency: 38000 -duty_cycle: 0.330000 -data: 9096 4436 620 505 647 478 648 501 623 1599 647 1624 623 502 623 503 621 504 619 1628 618 507 617 507 617 1630 617 508 616 1630 617 1630 617 1631 616 508 616 508 617 508 616 1631 616 508 617 508 617 508 616 508 616 1630 616 1630 616 1631 616 508 616 1630 617 1630 617 1630 617 1631 617 509 616 508 616 509 616 509 616 509 616 509 615 509 616 508 617 1631 616 1631 615 1631 616 1631 616 1631 616 1631 616 1631 615 1631 616 14435 9093 2186 615 96359 9095 2184 617 -# -name: Vol_up -type: raw -frequency: 38000 -duty_cycle: 0.330000 -data: 9091 4465 594 530 595 530 594 530 594 1651 595 1652 595 529 621 504 620 504 619 1628 618 507 617 508 616 1631 616 509 615 1631 616 1631 616 1632 615 509 616 509 616 509 615 1631 616 509 616 508 616 1631 616 509 616 1631 615 1631 616 1631 617 508 616 1631 616 1631 616 508 616 1631 617 508 617 509 616 509 616 509 616 509 616 509 616 509 616 509 616 1631 616 1631 616 1631 616 1631 616 1631 615 1631 615 1631 615 1631 616 14435 9090 2190 615 -# -name: Vol_dn -type: raw -frequency: 38000 -duty_cycle: 0.330000 -data: 9092 4439 620 506 619 506 618 530 593 1627 620 1630 643 504 620 505 618 506 617 1630 617 508 616 508 616 1632 616 508 617 1631 616 1631 616 1631 616 1631 616 509 616 508 616 1631 616 509 616 509 615 1632 616 509 616 508 616 1631 616 1631 616 508 616 1631 615 1631 616 509 615 1632 615 509 616 509 616 509 616 509 616 509 616 510 615 509 616 509 616 1631 616 1631 615 1631 616 1631 615 1631 615 1631 615 1631 615 1631 615 14434 9088 2191 615 96339 9115 2189 616 96343 9117 2189 616 96343 9114 2189 616 -# AV-Mute -name: Mute -type: raw -frequency: 38000 -duty_cycle: 0.330000 -data: 9092 4439 620 506 618 506 618 530 594 1627 619 1629 643 505 619 505 619 506 617 1629 617 508 616 508 616 1631 616 508 616 1630 616 1630 616 1630 617 1630 616 1630 616 1631 616 508 616 508 616 508 616 1631 616 508 617 508 616 508 616 508 616 1630 616 1631 615 1631 616 508 616 1631 616 508 617 508 616 509 615 509 616 508 616 509 615 509 616 508 616 1631 615 1631 615 1631 616 1631 615 1631 615 1631 615 1631 615 1631 616 14433 9088 2191 615 -# -name: Power -type: raw -frequency: 38000 -duty_cycle: 0.330000 -data: 9014 4332 661 1570 661 471 660 473 658 474 657 476 655 498 633 498 634 502 633 499 633 1599 632 1599 632 1599 632 1599 632 1599 632 1600 631 1603 632 500 632 501 631 501 631 501 631 501 631 501 631 1601 631 504 631 1601 631 1601 631 1601 631 1601 631 1601 630 1601 630 501 631 1601 631 38177 8983 2149 630 -# -name: Vol_up -type: parsed -protocol: NEC -address: 01 00 00 00 -command: 11 00 00 00 -# -name: Vol_dn -type: parsed -protocol: NEC -address: 01 00 00 00 -command: 4C 00 00 00 -# -name: Mute -type: raw -frequency: 38000 -duty_cycle: 0.330000 -data: 9042 4306 690 1541 665 468 664 468 664 469 663 470 662 471 660 495 636 499 636 497 634 1597 634 1598 633 1598 633 1599 633 1599 632 1599 633 1603 632 1599 633 499 633 499 633 500 632 499 633 500 632 1600 632 503 633 500 632 1600 632 1600 632 1600 633 1600 632 1600 632 500 632 1600 632 37912 8986 2145 633 -# ON -name: Power -type: raw -frequency: 38000 -duty_cycle: 0.330000 -data: 3522 1701 472 426 444 1269 472 426 444 426 443 427 443 427 443 426 444 427 443 426 444 427 442 428 441 429 440 431 438 1304 437 433 437 433 438 433 437 433 437 434 436 434 436 434 436 434 436 434 436 1305 436 434 436 434 436 434 436 1305 436 434 436 434 436 1305 436 435 435 435 435 435 435 435 435 435 435 435 435 435 435 459 411 459 411 459 411 1330 411 1330 411 1330 411 1330 411 1330 411 460 410 459 411 459 411 1330 411 1330 411 460 410 1330 411 1330 411 1331 410 1330 411 74392 3516 1736 436 433 437 1304 437 433 437 433 437 433 437 433 437 433 437 434 436 433 437 434 436 434 436 434 436 434 436 1305 436 434 436 434 436 434 436 434 436 434 436 434 436 434 436 434 436 434 436 1305 436 434 436 434 436 435 435 1305 436 435 435 435 435 1306 435 435 435 435 435 435 435 436 434 436 434 436 434 435 435 436 434 436 434 436 434 1330 411 1331 410 1330 411 1330 411 1330 411 459 411 460 410 460 410 1331 410 1331 410 460 410 1331 410 1331 410 1331 410 1331 410 74392 3515 1736 437 433 437 1304 437 433 437 433 437 434 436 433 437 434 436 433 437 434 436 434 436 434 436 434 436 434 436 1305 436 434 436 434 436 434 436 434 436 434 436 434 436 434 436 434 436 434 436 1305 436 434 436 435 436 434 436 1306 435 435 435 435 435 1306 435 435 435 435 435 435 435 435 435 435 435 436 434 436 434 435 435 436 434 435 435 1306 435 1330 411 1307 434 1331 410 1308 433 436 434 436 434 460 410 1331 410 1331 410 460 410 1331 410 1331 410 1331 410 1331 410 74392 3515 1736 437 433 437 1304 437 434 436 433 437 434 436 433 437 434 436 434 436 434 436 434 436 434 436 434 436 434 436 1305 436 434 436 434 436 434 436 435 435 434 436 434 436 434 436 434 436 434 436 1306 435 435 435 435 435 435 435 1306 435 435 435 436 434 1306 435 435 435 436 434 436 434 435 435 436 434 436 434 460 410 460 410 460 410 460 410 1331 410 1331 410 1331 410 1331 410 1331 410 460 410 460 410 460 410 1331 410 1331 410 460 410 1331 410 1331 410 1331 410 1331 410 74392 3515 1736 437 433 437 1304 437 433 437 434 436 434 436 433 437 434 436 434 436 434 436 434 436 434 436 434 436 434 436 1305 436 434 436 434 436 434 436 434 436 434 436 434 436 435 435 435 435 434 436 1306 435 434 436 435 435 435 435 1306 435 436 434 435 435 1306 435 435 435 436 434 436 434 436 434 436 434 460 410 437 433 459 411 460 410 460 410 1331 410 1331 410 1331 410 1331 410 1331 410 460 410 460 410 460 410 1331 410 1331 410 460 410 1331 410 1331 410 1331 410 1331 410 74393 3514 1736 437 434 436 1304 437 433 437 434 436 433 437 434 436 433 437 434 436 434 436 434 436 434 436 434 436 434 436 1305 436 434 436 434 436 434 436 434 436 435 435 434 436 434 436 435 435 434 436 1305 436 435 435 435 435 435 435 1306 435 435 435 435 435 1306 435 435 435 436 434 435 435 459 411 436 434 435 435 459 411 459 411 459 411 459 411 1330 411 1306 435 1330 411 1330 411 1331 410 460 410 460 410 460 410 1331 410 1331 410 460 410 1331 410 1331 410 1331 410 1331 410 -# ON -name: Power -type: raw -frequency: 38000 -duty_cycle: 0.330000 -data: 529 7218 126 6585 219 703 180 5362 427 18618 177 -# -name: Vol_up -type: raw -frequency: 38000 -duty_cycle: 0.330000 -data: 9069 4362 622 486 621 487 621 491 622 1608 623 1603 622 487 621 487 621 491 622 1604 621 487 622 491 622 1604 621 491 622 1608 622 1609 621 1604 622 486 622 487 621 491 621 1605 621 487 621 491 622 1604 622 491 621 1609 621 1609 621 1604 622 491 621 1609 622 1604 621 491 621 1604 622 487 621 487 622 486 622 487 621 488 621 487 621 488 620 491 621 1609 622 1609 620 1609 621 1609 621 1609 621 1609 621 1609 621 1618 621 14330 9047 2137 620 -# -name: Vol_dn -type: raw -frequency: 38000 -duty_cycle: 0.330000 -data: 9047 4362 621 486 622 463 645 490 622 1609 622 1604 622 487 620 487 621 491 622 1604 622 484 625 490 621 1605 649 463 621 1609 620 1611 621 1608 622 1605 621 486 622 491 622 1604 621 487 621 492 620 1604 621 488 621 492 620 1609 622 1604 621 492 622 1609 620 1605 621 491 622 1603 622 488 621 488 620 488 620 488 621 488 620 487 622 485 621 492 596 1635 621 1609 622 1585 643 1611 620 1608 621 1610 619 1611 620 1619 619 14332 9074 2109 647 -# -name: Mute -type: raw -frequency: 38000 -duty_cycle: 0.330000 -data: 9073 4336 648 461 647 484 624 489 623 1607 623 1603 622 486 622 486 622 491 622 1604 621 487 621 491 622 1604 622 491 621 1609 621 1609 621 1609 621 1608 622 1609 621 1604 621 486 622 486 622 491 622 1604 622 486 622 487 621 487 621 491 622 1608 622 1609 621 1604 622 491 621 1604 621 487 621 486 622 487 621 487 621 487 621 487 621 487 621 491 622 1608 622 1608 622 1609 621 1608 622 1608 622 1608 622 1609 621 1617 622 14330 9047 2137 620 -# ON -name: Power -type: parsed -protocol: NECext -address: 83 F4 00 00 -command: 4F B0 00 00 -# -name: Power -type: parsed -protocol: NECext -address: 80 19 00 00 -command: 10 EF 00 00 -# -name: Vol_up -type: parsed -protocol: NECext -address: 80 19 00 00 -command: 1C E3 00 00 -# -name: Vol_dn -type: parsed -protocol: NECext -address: 80 19 00 00 -command: 46 B9 00 00 -# -name: Power -type: parsed -protocol: NEC -address: 80 00 00 00 -command: 51 00 00 00 -# -name: Power -type: parsed -protocol: NECext -address: 40 40 00 00 -command: 0A F5 00 00 -# -name: Power -type: parsed -protocol: NECext -address: 00 30 00 00 -command: 4E B1 00 00 -# -name: Vol_up -type: parsed -protocol: NECext -address: 00 30 00 00 -command: 0E F1 00 00 -# -name: Vol_dn -type: parsed -protocol: NECext -address: 00 30 00 00 -command: 0D F2 00 00 -# -name: Power -type: parsed -protocol: NECext -address: 00 30 00 00 -command: 4F B0 00 00 -# -name: Mute -type: parsed -protocol: NECext -address: 00 30 00 00 -command: 14 EB 00 00 -# -name: Power -type: parsed -protocol: NECext -address: 08 16 00 00 -command: 87 78 00 00 -# -name: Mute -type: parsed -protocol: NECext -address: 08 16 00 00 -command: C8 37 00 00 -# -name: Power -type: parsed -protocol: NEC -address: 01 00 00 00 -command: 01 00 00 00 -# -name: Mute -type: parsed -protocol: NEC -address: 01 00 00 00 -command: 02 00 00 00 -# -name: Vol_up -type: parsed -protocol: NEC -address: 01 00 00 00 -command: 28 00 00 00 -# -name: Vol_dn -type: parsed -protocol: NEC -address: 01 00 00 00 -command: 29 00 00 00 -# -name: Power -type: parsed -protocol: NECext -address: 84 F4 00 00 -command: 0B F4 00 00 -# -name: Power -type: parsed -protocol: NECext -address: 33 00 00 00 -command: 00 FF 00 00 -# -name: Vol_dn -type: parsed -protocol: NECext -address: 33 00 00 00 -command: 1E E1 00 00 -# -name: Vol_up -type: parsed -protocol: NECext -address: 33 00 00 00 -command: 1D E2 00 00 -# -name: Mute -type: parsed -protocol: NECext -address: 33 00 00 00 -command: 0B F4 00 00 -# -name: Power -type: parsed -protocol: NECext -address: 83 55 00 00 -command: 90 6F 00 00 -# -name: Vol_dn -type: parsed -protocol: NECext -address: 83 55 00 00 -command: 99 66 00 00 -# -name: Vol_up -type: parsed -protocol: NECext -address: 83 55 00 00 -command: 98 67 00 00 -# -name: Power -type: parsed -protocol: NECext -address: 00 DF 00 00 -command: 1C E3 00 00 -# -name: Vol_dn -type: parsed -protocol: NECext -address: 00 DF 00 00 -command: 4F B0 00 00 -# -name: Vol_up -type: parsed -protocol: NECext -address: 00 DF 00 00 -command: 4B B4 00 00 -# -name: Power -type: parsed -protocol: NEC -address: 32 00 00 00 -command: 02 00 00 00 -# -name: Power -type: parsed -protocol: NEC -address: 32 00 00 00 -command: 2E 00 00 00 -# -name: Mute -type: parsed -protocol: NEC -address: 32 00 00 00 -command: 52 00 00 00 -# -name: Power -type: parsed -protocol: NEC -address: 20 00 00 00 -command: 41 00 00 00 -# -name: Vol_up -type: parsed -protocol: NEC -address: 20 00 00 00 -command: 51 00 00 00 -# -name: Vol_dn -type: parsed -protocol: NEC -address: 20 00 00 00 -command: 56 00 00 00 -# -name: Mute -type: parsed -protocol: NEC -address: 20 00 00 00 -command: 5A 00 00 00 -# -name: Power -type: parsed -protocol: SIRC15 -address: 54 00 00 00 -command: 15 00 00 00 -# -name: Vol_up -type: parsed -protocol: NECext -address: 83 F4 00 00 -command: 82 7D 00 00 -# -name: Vol_dn -type: parsed -protocol: NECext -address: 83 F4 00 00 -command: 83 7C 00 00 -# -name: Mute -type: parsed -protocol: NECext -address: 83 F4 00 00 -command: 14 EB 00 00 -# -name: Power -type: parsed -protocol: NEC -address: 31 00 00 00 -command: 91 00 00 00 -# -name: Power -type: parsed -protocol: NEC -address: 31 00 00 00 -command: 90 00 00 00 -# -name: Vol_up -type: parsed -protocol: NEC -address: 31 00 00 00 -command: D0 00 00 00 -# -name: Mute -type: parsed -protocol: NEC -address: 31 00 00 00 -command: 89 00 00 00 -# -name: Power -type: parsed -protocol: NECext -address: 86 00 00 00 -command: 00 00 00 00 -# -name: Vol_up -type: parsed -protocol: NECext -address: 86 00 00 00 -command: 30 00 00 00 -# -name: Vol_dn -type: parsed -protocol: NECext -address: 86 00 00 00 -command: 31 00 00 00 -# -name: Mute -type: parsed -protocol: NECext -address: 86 00 00 00 -command: 32 00 00 00 -# -name: Power -type: parsed -protocol: NECext -address: 30 00 00 00 -command: 00 00 00 00 -# -name: Power -type: parsed -protocol: NECext -address: 87 4E 00 00 -command: 0D 00 00 00 -# -name: Power -type: raw -frequency: 38000 -duty_cycle: 0.330000 -data: 9032 4479 597 560 572 558 564 566 566 1666 589 1671 594 562 570 560 562 568 564 1669 596 560 562 568 564 1669 596 560 562 1671 594 1666 588 1671 594 562 570 560 562 568 564 1669 596 560 562 568 564 566 566 563 569 1664 591 1669 596 1664 590 565 567 1667 598 1661 593 1666 588 1671 594 562 570 560 562 568 564 565 567 563 569 560 562 568 564 565 567 1666 588 1671 594 1665 589 1670 595 1665 590 1669 596 1664 590 1668 597 13983 9029 2222 599 96237 9030 2221 589 96244 9034 2217 594 96244 9033 2218 592 96249 9038 2213 597 96239 9037 2214 596 96238 9028 2223 598 96221 9032 2215 595 -# -name: Vol_up -type: raw -frequency: 38000 -duty_cycle: 0.330000 -data: 9034 4482 593 563 569 561 571 559 563 1698 566 1694 570 559 563 568 564 566 566 1695 569 560 572 559 563 1671 593 563 569 1692 562 1671 593 1693 571 558 564 567 565 565 567 1693 571 532 590 567 565 1695 569 560 562 1698 566 1694 570 1663 591 539 593 1693 571 1688 566 564 568 1691 563 567 565 565 567 563 569 561 571 559 563 567 565 565 567 563 569 1690 564 1695 569 1691 563 1696 568 1691 563 1697 567 1692 562 1697 567 13988 9030 2223 597 96250 9035 2219 591 96245 9032 2221 589 96240 9038 2215 595 96235 9033 2220 590 -# -name: Vol_dn -type: raw -frequency: 38000 -duty_cycle: 0.330000 -data: 9028 4482 593 563 569 561 571 558 564 1696 568 1690 564 566 566 563 569 561 571 1688 566 563 569 561 571 1688 566 563 569 1690 564 1695 569 1689 565 1668 596 560 562 568 564 1695 569 560 562 568 564 1695 569 560 562 568 564 1695 569 1690 564 566 566 1692 572 1687 567 563 569 1690 564 566 566 564 568 562 570 559 563 567 565 565 567 562 570 560 562 1696 568 1665 589 1670 594 1665 589 1670 594 1664 590 1669 647 1612 590 13987 9031 2220 590 96223 9033 2217 593 96223 9034 2218 592 96225 9032 2219 591 96221 9087 2164 595 -# -name: Mute -type: raw -frequency: 38000 -duty_cycle: 0.330000 -data: 9031 4479 596 560 572 558 564 566 566 1693 571 1688 566 563 569 561 571 559 563 1696 568 561 571 559 563 1697 567 562 570 1689 565 1694 570 1688 566 1693 571 1661 593 1693 571 558 564 566 566 564 568 1691 563 541 591 564 568 562 570 560 562 1697 567 1692 562 1696 568 562 570 1689 565 564 568 561 571 559 563 567 565 564 568 562 570 560 562 567 565 1694 570 1689 565 1694 570 1688 566 1693 571 1688 566 1693 571 1662 592 13987 9031 2220 590 96231 9034 2217 593 96234 9030 2222 588 96247 9037 2215 595 -# -name: Vol_up -type: parsed -protocol: NEC -address: 32 00 00 00 -command: 11 00 00 00 -# -name: Vol_dn -type: parsed -protocol: NEC -address: 32 00 00 00 -command: 14 00 00 00 -# OFF -name: Power -type: parsed -protocol: NECext -address: 83 F4 00 00 -command: 4E B1 00 00 -# -name: Power -type: parsed -protocol: NEC -address: 03 00 00 00 -command: 1D 00 00 00 -# -name: Vol_up -type: parsed -protocol: NEC -address: 03 00 00 00 -command: 11 00 00 00 -# -name: Vol_dn -type: parsed -protocol: NEC -address: 03 00 00 00 -command: 15 00 00 00 -# OFF -name: Power -type: raw -frequency: 38000 -duty_cycle: 0.330000 -data: 9075 4307 677 433 675 456 651 461 651 1579 650 1576 649 459 649 460 648 465 648 1578 647 461 622 491 622 1604 647 465 647 1583 622 1608 647 1579 647 461 647 466 622 1604 647 465 647 1579 647 461 645 463 648 465 648 1583 646 1580 646 466 647 1579 622 491 647 1583 622 1608 647 1579 647 461 647 461 622 486 622 486 647 461 647 462 646 462 622 491 646 1584 622 1608 647 1584 621 1608 647 1583 646 1584 647 1584 646 1592 622 14330 9047 2137 621 -# -name: Power -type: parsed -protocol: Samsung32 -address: 07 00 00 00 -command: E6 00 00 00 -# -name: Vol_up -type: parsed -protocol: Samsung32 -address: 07 00 00 00 -command: 07 00 00 00 -# -name: Vol_dn -type: parsed -protocol: Samsung32 -address: 07 00 00 00 -command: 0B 00 00 00 -# -name: Mute -type: parsed -protocol: Samsung32 -address: 07 00 00 00 -command: 0F 00 00 00 -# OFF -name: Power -type: raw -frequency: 38000 -duty_cycle: 0.330000 -data: 3523 1701 472 426 444 1269 472 426 444 426 442 429 443 427 443 426 444 426 444 426 443 427 442 429 440 430 439 432 438 1304 437 433 437 432 438 432 438 433 437 433 437 433 437 433 437 433 437 433 437 1304 437 433 437 433 437 433 437 1304 437 433 437 433 437 1304 437 433 437 434 436 433 437 434 436 434 436 434 436 433 437 433 437 434 436 1304 437 1305 436 1305 436 1305 436 1305 436 1305 436 434 436 434 436 1305 436 1305 436 1305 436 434 436 1305 436 1305 436 1306 435 1306 435 74393 3515 1736 437 433 437 1304 437 433 437 433 437 433 437 433 437 433 437 433 437 433 437 434 436 433 437 434 436 434 436 1304 437 434 436 434 436 434 436 434 436 434 436 434 436 434 436 434 436 434 436 1305 436 434 436 434 436 434 436 1305 436 434 436 434 436 1306 435 435 435 435 435 435 435 435 435 435 435 435 435 435 435 436 434 435 435 1307 434 1331 410 1307 434 1307 434 1330 411 1307 434 460 410 460 410 1331 410 1331 410 1331 410 460 410 1331 410 1331 410 1331 410 1331 410 74393 3515 1736 437 433 437 1304 437 433 437 433 437 433 437 433 437 433 437 433 437 433 437 434 436 434 436 433 437 433 437 1304 437 434 436 434 436 434 437 434 436 434 436 434 436 434 436 434 436 434 436 1305 436 434 436 434 436 434 436 1305 436 435 435 434 436 1305 436 434 436 435 435 435 435 435 435 435 435 435 435 435 435 435 435 435 435 1307 434 1306 435 1307 434 1307 434 1307 434 1331 410 460 410 460 410 1331 410 1331 410 1331 410 460 410 1331 410 1331 410 1331 410 1331 410 74393 3515 1736 437 433 437 1304 437 433 437 433 437 433 437 433 437 433 437 433 437 433 437 433 437 433 437 434 436 433 437 1304 437 433 437 434 436 434 436 434 436 434 436 434 436 434 436 434 436 434 437 1305 436 434 436 434 436 434 436 1305 436 434 436 434 436 1306 435 435 435 435 435 435 435 435 435 435 435 435 435 435 435 435 435 435 435 1307 434 1330 411 1330 411 1330 411 1330 411 1330 411 460 410 460 410 1331 410 1331 410 1331 410 460 410 1331 410 1331 410 1331 410 1331 410 -# OFF -name: Power -type: raw -frequency: 38000 -duty_cycle: 0.330000 -data: 9093 4441 620 507 618 530 594 531 593 1652 595 1653 620 505 620 505 619 506 617 1630 616 508 616 508 616 1632 615 509 615 1631 616 1632 615 1632 615 510 615 509 615 1632 615 509 615 1632 615 510 615 510 614 509 615 1632 614 1633 614 509 615 1633 614 509 615 1632 615 1632 614 1633 614 510 614 510 615 510 615 510 614 510 614 510 615 510 615 510 614 1632 615 1632 614 1632 615 1632 615 1632 615 1632 615 1632 615 1633 614 14439 9088 2192 614 96349 9112 2190 616 -# OFF -name: Power -type: raw -frequency: 38000 -duty_cycle: 0.330000 -data: 243 27700 170 27632 246 27694 282 27595 307 27497 241 27696 177 27710 164 27644 245 27629 246 27712 174 27638 211 27736 131 27741 306 27504 214 27727 135 27749 132 27761 126 27744 131 27753 127 27764 121 27767 132 27773 307 27577 131 27706 213 27761 129 27759 128 27770 125 27694 213 27751 307 27578 131 27737 131 27745 304 27575 335 27540 124 27752 132 27749 132 27747 134 27757 134 27758 127 27762 131 27748 131 27750 122 27749 130 27748 125 27772 131 27774 136 27762 135 27686 215 27742 131 27749 132 27756 133 27764 126 24073 9255 4460 672 488 618 541 619 541 619 1675 619 1676 618 542 618 542 618 542 618 1676 618 542 618 543 617 1678 616 568 592 1702 592 1702 592 1703 617 543 617 543 617 1677 617 543 617 1678 615 544 616 544 616 544 616 1678 616 1679 615 544 616 1679 615 545 615 1679 615 1679 615 1679 615 40240 9173 2273 591 -# -name: Vol_up -type: raw -frequency: 38000 -duty_cycle: 0.330000 -data: 219 27658 217 27663 216 27658 216 27634 216 27642 215 27646 217 27662 217 27637 216 27649 216 27649 218 27656 217 27658 215 27640 214 27636 217 27649 216 27644 218 27635 217 27630 215 27645 216 27631 215 27632 216 27650 216 27628 217 27630 214 27627 217 27623 215 27632 215 27641 216 27634 214 27633 215 27648 215 27648 217 27651 215 27635 216 27629 216 27630 216 2021 9254 4461 618 542 618 542 618 542 618 1675 619 1676 618 541 619 541 619 542 618 1677 617 543 617 543 617 1678 616 568 592 1702 592 1702 618 1676 618 542 618 542 618 543 617 1677 617 543 617 544 616 1678 616 544 616 1678 616 1678 616 1678 616 544 616 1678 616 1678 616 544 616 1678 616 40239 9200 2247 617 99930 110 27739 119 27738 123 27750 126 27738 175 27617 214 27716 203 27604 213 27639 217 27631 214 27722 136 27753 119 27736 175 27618 246 27683 177 27619 245 27685 171 55486 244 27693 158 27635 241 27695 170 27693 129 27717 340 27530 113 27757 106 27751 124 27728 172 27707 126 27666 215 27708 123 27733 123 -# -name: Vol_dn -type: parsed -protocol: NECext -address: 18 E9 00 00 -command: 49 B6 00 00 -# -name: Power -type: parsed -protocol: NEC -address: 02 00 00 00 -command: 14 00 00 00 -# -name: Vol_up -type: parsed -protocol: NEC -address: 02 00 00 00 -command: 48 00 00 00 -# -name: Vol_dn -type: parsed -protocol: NEC -address: 02 00 00 00 -command: 40 00 00 00 -# -name: Mute -type: parsed -protocol: NEC -address: 02 00 00 00 -command: 18 00 00 00 -# -name: Power -type: parsed -protocol: NECext -address: B8 57 00 00 -command: 0C F3 00 00 -# -name: Mute -type: parsed -protocol: NECext -address: B8 57 00 00 -command: 0D F2 00 00 -# -name: Vol_dn -type: parsed -protocol: NECext -address: B8 57 00 00 -command: 1E E1 00 00 -# -name: Vol_up -type: parsed -protocol: NECext -address: B8 57 00 00 -command: 1F E0 00 00 -# -name: Power -type: parsed -protocol: NEC -address: 32 00 00 00 -command: 81 00 00 00 -# -name: Vol_dn -type: parsed -protocol: NEC -address: 32 00 00 00 -command: 8F 00 00 00 -# -name: Vol_up -type: parsed -protocol: NEC -address: 32 00 00 00 -command: 8C 00 00 00 -# -name: Mute -type: raw -frequency: 38000 -duty_cycle: 0.330000 -data: 9066 4428 608 507 609 1622 609 507 609 507 609 1623 608 1623 609 507 609 506 610 1623 609 507 609 1622 610 1623 608 507 609 506 610 1622 609 1623 609 506 610 1622 610 506 610 1623 637 478 690 425 638 478 637 1594 637 1594 664 451 636 1594 610 506 610 1621 611 1621 610 1621 610 505 611 40183 9065 2156 637 95953 9037 2185 608 -# -name: Power -type: parsed -protocol: NEC -address: 00 00 00 00 -command: A8 00 00 00 -# -name: Mute -type: parsed -protocol: NEC -address: 00 00 00 00 -command: 88 00 00 00 -# -name: Vol_dn -type: parsed -protocol: NEC -address: 00 00 00 00 -command: 9C 00 00 00 -# -name: Vol_up -type: parsed -protocol: NEC -address: 00 00 00 00 -command: 8C 00 00 00 -# -name: Power -type: parsed -protocol: NECext -address: 87 45 00 00 -command: 17 E8 00 00 -# -name: Vol_up -type: raw -frequency: 38000 -duty_cycle: 0.330000 -data: 9064 4354 666 1559 666 1562 662 1586 638 475 636 477 635 477 635 478 635 1590 635 1591 634 478 635 1591 634 478 634 478 635 478 634 1591 635 478 634 1591 634 478 635 478 634 478 635 1591 634 478 634 1591 635 478 634 478 634 1591 634 1591 635 1591 634 478 635 1591 634 478 634 1591 635 40957 9035 2144 634 95483 9047 2155 632 95484 9048 2153 633 -# -name: Vol_dn -type: parsed -protocol: NECext -address: 87 45 00 00 -command: 50 AF 00 00 -# -name: Mute -type: raw -frequency: 38000 -duty_cycle: 0.330000 -data: 9034 4385 638 1587 664 1562 663 1587 637 476 635 478 634 478 635 478 635 1591 634 1591 634 478 635 1591 635 478 634 478 635 478 635 1591 635 478 634 478 634 1591 634 478 635 479 634 1591 635 478 634 1591 635 478 634 1592 634 478 634 1591 635 1591 635 478 634 1592 634 478 634 1591 634 40958 9033 2144 635 -# -name: Power -type: parsed -protocol: NECext -address: FF FF 00 00 -command: E8 17 00 00 -# -name: Vol_up -type: parsed -protocol: NECext -address: FF FF 00 00 -command: BD 42 00 00 -# -name: Vol_dn -type: parsed -protocol: NECext -address: FF FF 00 00 -command: F2 0D 00 00 -# -name: Power -type: parsed -protocol: Kaseikyo -address: 41 54 32 00 -command: 05 00 00 00 -# -name: Vol_up -type: parsed -protocol: Kaseikyo -address: 41 54 32 00 -command: 70 01 00 00 -# -name: Vol_dn -type: parsed -protocol: Kaseikyo -address: 41 54 32 00 -command: 71 01 00 00 -# -name: Power -type: parsed -protocol: NEC -address: 31 00 00 00 -command: 81 00 00 00 -# -name: Power -type: parsed -protocol: NECext -address: 83 F4 00 00 -command: 17 E8 00 00 -# -name: Vol_up -type: raw -frequency: 38000 -duty_cycle: 0.33 -data: 9010 4413 532 1617 532 1617 533 489 533 489 533 489 558 464 558 465 557 1593 557 465 557 466 556 1594 555 467 555 1595 529 1621 554 1595 581 1569 581 441 581 1569 581 441 581 441 581 441 581 441 581 441 581 1569 581 1569 581 441 581 1569 580 1569 580 1570 580 1595 554 1595 555 468 554 42156 8983 2135 556 -# -name: Vol_dn -type: raw -frequency: 38000 -duty_cycle: 0.33 -data: 9032 4390 556 1592 559 1591 559 463 559 463 558 464 557 465 556 465 557 1593 583 440 581 441 580 1569 581 441 581 1569 580 1569 581 1569 581 1570 580 1596 554 1596 554 468 554 468 554 468 554 442 580 442 580 1596 554 469 553 469 553 1596 554 1596 553 1597 550 1598 553 1598 552 469 551 42155 9008 2107 531 95218 9006 2108 582 -# -name: Mute -type: raw -frequency: 38000 -duty_cycle: 0.33 -data: 9011 4388 557 1617 532 1617 532 489 533 489 558 464 558 440 582 440 582 1593 556 466 556 466 556 1594 556 467 555 1595 555 1595 529 1620 554 1596 554 467 554 468 555 1595 579 443 581 1569 581 441 581 441 580 442 581 1569 581 1569 581 441 581 1569 580 441 581 1569 581 1569 581 1570 579 42152 8957 2159 556 \ No newline at end of file diff --git a/assets/resources/infrared/assets/projectors.ir b/assets/resources/infrared/assets/projectors.ir index 9f1d8a0a0..6378f2d12 100644 --- a/assets/resources/infrared/assets/projectors.ir +++ b/assets/resources/infrared/assets/projectors.ir @@ -1,7 +1,7 @@ Filetype: IR library file Version: 1 -# Last Updated 31th Jan, 2023 -# Last Checked 31th Jan, 2023 +# Last Updated 8th Feb, 2023 +# Last Checked 15th Feb, 2023 # # ON name: POWER @@ -802,3 +802,39 @@ type: raw frequency: 38000 duty_cycle: 0.33 data: 9011 4388 557 1617 532 1617 532 489 533 489 558 464 558 440 582 440 582 1593 556 466 556 466 556 1594 556 467 555 1595 555 1595 529 1620 554 1596 554 467 554 468 555 1595 579 443 581 1569 581 441 581 441 580 442 581 1569 581 1569 581 441 581 1569 580 441 581 1569 581 1569 581 1570 579 42152 8957 2159 556 +# +name: POWER +type: parsed +protocol: NECext +address: 4F 50 00 00 +command: 02 FD 00 00 +# +name: VOL+ +type: parsed +protocol: NECext +address: 4F 50 00 00 +command: 08 F7 00 00 +# +name: VOL- +type: parsed +protocol: NECext +address: 4F 50 00 00 +command: 0B F4 00 00 +# +name: VOL+ +type: parsed +protocol: NECext +address: 81 03 00 00 +command: F0 0F 00 00 +# +name: VOL+ +type: parsed +protocol: NECext +address: 87 45 00 00 +command: 51 AE 00 00 +# +name: MUTE +type: parsed +protocol: NECext +address: 87 45 00 00 +command: 52 AD 00 00 diff --git a/assets/resources/infrared/assets/tv.ir b/assets/resources/infrared/assets/tv.ir old mode 100644 new mode 100755 index a7a8c306a..e3d41b9a7 --- a/assets/resources/infrared/assets/tv.ir +++ b/assets/resources/infrared/assets/tv.ir @@ -1,7 +1,7 @@ Filetype: IR library file Version: 1 -# Last Updated 19th Jan, 2023 -# Last Checked 31th Jan, 2023 +# Last Updated 15th Feb, 2023 +# Last Checked 15th Feb, 2023 # name: POWER type: parsed @@ -1839,3 +1839,27 @@ type: parsed protocol: SIRC20 address: 5A 0E 00 00 command: 11 00 00 00 +# +name: VOL+ +type: parsed +protocol: RC5 +address: 00 00 00 00 +command: 15 00 00 00 +# +name: VOL- +type: parsed +protocol: RC5 +address: 00 00 00 00 +command: 14 00 00 00 +# +name: CH+ +type: parsed +protocol: RC5 +address: 00 00 00 00 +command: 18 00 00 00 +# +name: CH- +type: parsed +protocol: RC5 +address: 00 00 00 00 +command: 17 00 00 00 diff --git a/assets/resources/nfc/assets/mf_classic_dict.nfc b/assets/resources/nfc/assets/mf_classic_dict.nfc index d62d0655b..a85d43403 100644 --- a/assets/resources/nfc/assets/mf_classic_dict.nfc +++ b/assets/resources/nfc/assets/mf_classic_dict.nfc @@ -1,41 +1,31 @@ ########################### # Do not edit, this file will be overwritten after firmware update # Use the user_dict file for user keys -# Last updated 25 January 2023 +# Last update 19th October, 2022 # ------------------------- - # MIFARE DEFAULT KEYS # -- ICEMAN FORK VERSION -- # -- CONTRIBUTE TO THIS LIST, SHARING IS CARING -- # https://github.com/RfidResearchGroup/proxmark3/blob/master/client/dictionaries/mfc_default_keys.dic - # DEFAULTKEY(FIRSTKEYUSEDBYPROGRAMIFNOUSERDEFINEDKEY) FFFFFFFFFFFF - # BLANKKEY 000000000000 - # NFC FORUM MADKEY # MAD ACCESS KEY A (REVERSED) A5A4A3A2A1A0 - # MAD ACCESS KEY B 89ECA97F8C2A - # KEY A WIEN # KEY B WIEN - # ICOPY-X E00000000000 E7D6064C5860 B27CCAB30DBD - # LIB / NAT BIEB D2ECE8B9395E - # NSCP DEFAULT KEY 1494E81663D7 - # KIEV KEYS 569369C5A0E5 632193BE1C3C @@ -44,52 +34,40 @@ D2ECE8B9395E 9DE89E070277 EFF603E1EFE9 F14EE7CAE863 - # KIEV / OV-CHIPKAART B5FF67CBA951 - # RKF # VÄSTTRAFIKEN KEYA, RKF ÖSTGÖTATRAFIKEN KEYA FC00018778F7 0297927C0F77 54726176656C - # VÄSTTRAFIKEN KEYB 00000FFE2488 776974687573 EE0042F88840 - # RKF SLKEYA 26940B21FF5D A64598A77478 - # RKF SLKEYB 5C598C9C58B5 E4D2770A89BE - # RKF REJSKORTDANMARK KEYA 722BFCC5375F F1D83F964314 - # RKF JOJOPRIVAKEYA 505249564141 - # RKF JOJOPRIVAKEYB 505249564142 - # RKF JOJOGROUPKEYA 47524F555041 - # RKF JOJOGROUPKEYB 47524F555042 434F4D4D4F41 434F4D4D4F42 4B0B20107CCB - # TNP3XXX # ACCESS CONTROL SYSTEM 605F5E5D5C5B - # MORE KEYS FROM MFC_DEFAULT_KEYS.LUA 000000000001 000000000002 @@ -104,10 +82,8 @@ F1D83F964314 200000000000 222222222222 27DD91F1FCF1 - # DIRECTORYANDEVENTLOGKEYB 2BA9621E0A36 - # DIRECTORYANDEVENTLOGKEYA 4AF9D7ADEBE4 333333333333 @@ -128,7 +104,6 @@ A00000000000 A053A292A4AF A94133013401 AAAAAAAAAAAA - # KEYFROMLADYADA.NET B00000000000 B127C6F41436 @@ -138,41 +113,31 @@ C934FE34D934 CCCCCCCCCCCC DDDDDDDDDDDD EEEEEEEEEEEE - # ELEVATOR # DATA FROM FORUM FFFFFF545846 F1A97341A9FC - # HOTEL SYSTEM 44AB09010845 85FED980EA5A - # ARD (FR) KEY A 43454952534E - # ARD (FR) KEY B 4A2B29111213 4143414F5250 - # TEHRAN RAILWAY A9B43414F585 1FB235AC1388 - # DATA FROM HTTP://IRQ5.IO/2013/04/13/DECODING-BCARD-CONFERENCE-BADGES/ # BCARD KEYB F4A9EF2AFC6D - # DATA FROM ... # S0 B 89EAC97F8C2A - # S4 A 43C7600DEE6B - # S6 A 0120BF672A64 - # S6 B FB0B20DF1F34 A9F953DEF0A3 @@ -181,7 +146,6 @@ A9F953DEF0A3 21EDF95E7433 C121FF19F681 3D5D9996359A - # HERE BE BIP KEYS... 3A42F33AF429 1FC235AC1309 @@ -215,41 +179,32 @@ D49E2826664F 51284C3686A6 3DF14C8000A1 6A470D54127C - # DATA FROM HTTP://PASTEBIN.COM/AK9BFTPW # LÄNSTRAFIKEN I VÄSTERBOTTEN 48FFE71294A0 E3429281EFC1 16F21A82EC84 460722122510 - # 3DPRINTER # EPI ENVISIONTE 3DPRINTER AAFB06045877 - # GYM # FYSIKEN A 3E65E4FB65B3 - # FYSIKEN B 25094DF6F148 - # CLEVERFIT A05DBD98E0FC - # HOTEL KEYCARD D3B595E9DD63 AFBECD121004 - # SIMONSVOSS 6471A5EF2D1A - # ID06 4E3552426B32 22BDACF5A33F 6E7747394E63 763958704B78 - # 24-7 D21762B2DE3B 0E83A374B513 @@ -263,10 +218,8 @@ F101622750B7 710732200D34 7C335FB121B5 B39AE17435DC - # KEY A 454841585443 - # DATA FROM HTTP://PASTEBIN.COM/GQ6NK38G D39BB83F5297 85675B200017 @@ -292,11 +245,9 @@ FEE470A4CB58 75EDE6A84460 DF27A8F1CB8E B0C9DD55DD4D - # DATA FROM HTTP://BIT.LY/1BDSBJL A0B0C0D0E0F0 A1B1C1D1E1F1 - # DATA FROM MSK SOCIAL A229E68AD9E5 49C2B5296EF4 @@ -323,7 +274,6 @@ C7C0ADB3284F D8A274B2E026 B20B83CB145C 9AFA6CB4FC3D - # DATA FROM HTTP://PASTEBIN.COM/RRJUEDCM 0D258FE90296 E55A3CA71826 @@ -337,19 +287,16 @@ EEB420209D0C 1ACC3189578C C2B7EC7D4EB1 369A4663ACD2 - # DATA FROM HTTPS://GITHUB.COM/ZHANGJINGYE03/ZXCARDUMPER # ZXCARD KEY A/B 668770666644 003003003003 - # DATA FROM HTTP://PHREAKERCLUB.COM/FORUM/SHOWTHREAD.PHP?P=41266 26973EA74321 71F3A315AD26 51044EFB5AAB AC70CA327A04 EB0A8FF88ADE - # TRANSPORT SYSTEM METROMONEY 2803BCB0C7E1 9C616585E26D @@ -358,7 +305,6 @@ EB0A8FF88ADE A160FCD5EC4C 112233445566 361A62F35BC9 - # TRANSPORT SYSTEM SPAIN 83F3CB98C258 070D486BC555 @@ -392,18 +338,14 @@ C52876869800 5145C34DBA19 25352912CD8D 81B20C274C3F - # DATA FROM MALL # PLAYLAND BALIKESIR ABBA1234FCB0 - # A TRIO BOWLING BAHCELIEVLER 314F495254FF 4152414B4E41 - # KARINCA PARK NIGDE 4E474434FFFF - # DATA FROM HTTPS://GITHUB.COM/RADIOWAR/NFCGUI 44DD5A385AAF 21A600056CB0 @@ -441,12 +383,10 @@ CBA6AE869AD5 A7ABBC77CC9E F792C4C76A5C BFB6796A11DB - # DATA FROM SALTO A/B 6A1987C40A21 7F33625BC129 2338B4913111 - # DATA FROM STOYE CB779C50E1BD A27D3804C259 @@ -474,22 +414,16 @@ D9A37831DCE5 C5CFE06D9EA3 C0DECE673829 A56C2DF9A26D - # DATA FROM HTTPS://PASTEBIN.COM/VBWAST74 68D3F7307C89 - # SMART RIDER. WESTERN AUSTRALIAN PUBLIC TRANSPORT CARDS 568C9083F71C - # BANGKOK METRO KEY 97F5DA640B18 - # METRO VALENCIA KEY A8844B0BCA06 - # HTC EINDHOVEN KEY 857464D3AAD1 - # VIGIK KEYS # VARIOUS SOURCES : # * HTTPS://GITHUB.COM/DUMPDOS/VIGIK @@ -498,24 +432,18 @@ A8844B0BCA06 # FRENCH VIGIK # VIGIK1 A 314B49474956 - # VIGIK1 B 564C505F4D41 BA5B895DA162 - # VIGIK MYSTERY KEYS MIFARE 1K EV1 (S50) # 16 A 5C8FF9990DA2 - # 17 A 75CCB59C9BED - # 16 B D01AFEEB890A - # 17 B 4B791BEA7BCC - # BTCINO UNDETERMINED SPREAKD 0X01->0X13 KEY 021209197591 2EF720F2AF76 @@ -524,7 +452,6 @@ D01AFEEB890A 4A6352684677 BF1F4424AF76 536653644C65 - # INTRATONE COGELEC # DATA FROM HTTP://BOUZDECK.COM/RFID/32-CLONING-A-MIFARE-CLASSIC-1K-TAG.HTML 484558414354 @@ -543,7 +470,6 @@ E64A986A5D94 66D2B7DC39EF 6BC1E1AE547D 22729A9BD40F - # DATA FROM HTTPS://DFIR.LU/BLOG/CLONING-A-MIFARE-CLASSIC-1K-TAG.HTML 925B158F796F FAD63ECB5891 @@ -559,10 +485,8 @@ CC6B3B3CD263 703140FD6D86 157C9A513FA5 E2A5DC8E066F - # DATA FROM FORUM, SCHLAGE 9691T FOB EF1232AB18A0 - # DATA FROM A OYSTER CARD 374BF468607F BFC8E353AF63 @@ -593,10 +517,8 @@ A2ABB693CE34 91F93A5564C9 E10623E7A016 B725F9CBF183 - # DATA FROM FDI TAG 8829DA9DAF76 - # DATA FROM GITHUB ISSUE 0A7932DC7E65 11428B5BCE06 @@ -621,18 +543,14 @@ D4FE03CE5B09 D4FE03CE5B0A D4FE03CE5B0F E241E8AFCBAF - # DATA FROM FORUM POST 123F8888F322 050908080008 - # DATA FROM HOIST 4F9F59C9C875 - # DATA FROM PASTEBIN 66F3ED00FED7 F7A39753D018 - # DATA FROM HTTPS://PASTEBIN.COM/Z7PEEZIF 386B4D634A65 666E564F4A44 @@ -664,23 +582,19 @@ F7A39753D018 6F506F493353 31646241686C 77646B633657 - # DATA FROM TRANSPERT 2031D1E57A3B 53C11F90822A 9189449EA24E - # DATA FROM GITHUB 410B9B40B872 2CB1A90071C8 - # DATA FROM 8697389ACA26 1AB23CD45EF6 013889343891 0000000018DE 16DDCB6B3F24 - # DATA FROM HTTPS://PASTEBIN.COM/VWDRZW7D # VINGCARD MIFARE 4K STAFF CARD EC0A9B1A9E06 @@ -694,7 +608,6 @@ B66AC040203A 2E641D99AD5B AD4FB33388BF 69FB7B7CD8EE - # HOTEL 2A6D9205E7CA 2A2C13CC242A @@ -702,34 +615,25 @@ AD4FB33388BF 01FA3FC68349 6D44B5AAF464 1717E34A7A8A - # RFIDEAS 6B6579737472 - # HID MIFARE CLASSIC 1K KEY 484944204953 204752454154 - # HID MIFARE SO 3B7E4FD575AD 11496F97752A - # LUXEO/AZTEK CASHLESS VENDING 415A54454B4D - # BQT 321958042333 - # APERIO KEY_A SECTOR 1, 12, 13, 14, 15 DATA START 0 LENGTH 48 160A91D29A9C - # GALLAGHER B7BF0C13066E - # PIK COMFORT MOSCOW KEYS (ISBC MIFARE PLUS SE 1K) 009FB42D98ED 002E626E2820 - # BOSTON, MA, USA TRANSIT - MBTA CHARLIE CARD # CHARLIE 3060206F5B0A @@ -766,10 +670,8 @@ D80511FC2AB4 BB467463ACD6 E67C8010502D FF58BA1B4478 - # DATA FROM HTTPS://PASTEBIN.COM/KZ8XP4EV FBF225DC5D58 - # DATA HTTPS://PASTEBIN.COM/BEM6BDAE # VINGCARD.TXT 4708111C8604 @@ -786,19 +688,16 @@ FBF225DC5D58 D9BCDE7FC489 0C03A720F208 6018522FAC02 - # DATA FROM HTTPS://PASTEBIN.COM/4T2YFMGT # MIFARE TECHNISCHE UNIVERSITÄT GRAZ TUG D58660D1ACDE 50A11381502C C01FC822C6E5 0854BF31111E - # MORE KEYS: 8A19D40CF2B5 AE8587108640 135B88A94B8B - # RUSSIAN TROIKA CARD 08B386463229 0E8F64340BA4 @@ -854,7 +753,6 @@ EAAC88E5DC99 F8493407799D 6B8BD9860763 D3A297DC2698 - # KEYS FROM MIFARECLASSICTOOL PROJECT 044CE1872BC3 045CECA15535 @@ -910,28 +808,22 @@ FD8705E721B0 00ADA2CD516D 237A4D0D9119 0ED7846C2BC9 - # HOTEL ADINA 9EBC3EB37130 - # MOST LIKELY DIVERSED INDIVIDUAL KEYS. # DATA FROM HTTPS://GITHUB.COM/KORSEHINDI/PROXMARK3/COMMIT/24FDBFA9A1D5C996AAA5C192BC07E4AB28DB4C5C 491CDC863104 A2F63A485632 98631ED2B229 19F1FFE02563 - # ARGENTINA 563A22C01FC8 43CA22C13091 25094DF2C1BD - # OMNITEC.ES HOTEL TIMECARD / MAINTENANCECARD AFBECD120454 - # OMNITEC.ES HOTEL EMERGENCYCARD 842146108088 - # TAPCARD PUBLIC TRANSPORT LA EA1B88DF0A76 D1991E71E2C5 @@ -965,7 +857,6 @@ B81846F06EDF C6A76CB2F3B5 E3AD9E9BA5D4 6C9EC046C1A4 - # ROC HIGHSCHOOL ACCESSCARD B021669B44BB B18CDCDE52B7 @@ -997,7 +888,6 @@ AE43F36C1A9A BE7C4F6C7A9A 5EC7938F140A 82D58AA49CCB - # MELONCARD 323334353637 CEE3632EEFF5 @@ -1014,7 +904,6 @@ A7FB4824ACBF 00F0BD116D70 4CFF128FA3EF 10F3BEBC01DF - # TRANSPORTES INSULAR LA PALMA 0172066B2F03 0000085F0000 @@ -1048,7 +937,6 @@ B1A862985913 3B0172066B2F 3F1A87298691 F3F0172066B2 - # TEHRAN EZPAY 38A88AEC1C43 CBD2568BC7C6 @@ -1065,12 +953,10 @@ D3B1C7EA5C53 604AC8D87C7E 8E7B29460F12 BB3D7B11D224 - # CHACO B210CFA436D2 B8B1CFA646A8 A9F95891F0A4 - # KEYS FROM APK APPLICATION "SCAN BADGE" 4A4C474F524D 444156494442 @@ -1090,7 +976,6 @@ A0004A000036 DFE73BE48AC6 B069D0D03D17 000131B93F28 - # FROM THE DFW AREA, TX, USA A506370E7C0F 26396F2042E7 @@ -1107,7 +992,6 @@ EF4C5A7AC6FC B47058139187 8268046CD154 67CC03B7D577 - # FROM THE HTL MÖDLING, NÖ, AT A5524645CD91 D964406E67B4 @@ -1116,40 +1000,32 @@ D964406E67B4 C27D999912EA 66A163BA82B4 4C60F4B15BA8 - # CAFE + CO, AT 35D850D10A24 4B511F4D28DD E45230E7A9E8 535F47D35E39 FB6C88B7E279 - # METRO CARD, AT 223C3427108A - # UNKNOWN, AT 23D4CDFF8DA3 E6849FCC324B 12FD3A94DF0E 0B83797A9C64 39AD2963D3D1 - # HOTEL BERLIN CLASSIC ROOM A KEY 34B16CD59FF8 - # HOTEL BERLIN CLASSIC ROOM B KEY BB2C0007D022 - # COINMATIC LAUNDRY SMART CARD # DATA FROM: HTTPS://PASTEBIN.COM/XZQILTUF 0734BFB93DAB 85A438F72A8A - # DATA FROM FORUM, CHINESE HOTEL 58AC17BF3629 B62307B62307 A2A3CCA2A3CC - # GRANADA, ES TRANSPORT CARD 000000270000 0F385FFB6529 @@ -1167,7 +1043,6 @@ B385EFA64290 C9739233861F F3864FCCA693 FC9839273862 - # VARIOUS HOTEL KEYS 34D3C568B348 91FF18E63887 @@ -1175,7 +1050,6 @@ FC9839273862 354A787087F1 4A306E62E9B6 B9C874AE63D0 - # DATA FROM OFFICIAL REPO F00DFEEDD0D0 0BB31DC123E5 @@ -1193,23 +1067,18 @@ B8937130B6BA D7744A1A0C44 82908B57EF4F FE04ECFE5577 - # COMFORT INN HOTEL 4D57414C5648 4D48414C5648 - # UNKNOWN HOTEL KEY 6D9B485A4845 - # BOSCH SOLUTION 6000 # FOUND IN TAGINFO APP # RATB KEY C1E51C63B8F5 1DB710648A65 - # E-GO CARD KEY 18F34C92A56E - # LIBRARY CARD MFP - SL1 4A832584637D CA679D6291B0 @@ -1225,7 +1094,6 @@ AADE86B1F9C1 C67BEB41FFBF B84D52971107 52B0D3F6116E - # DATA FROM HTTPS://PASTEBIN.COM/CLSQQ9XN CA3A24669D45 4087C6A75A96 @@ -1234,12 +1102,10 @@ D73438698EEA 5F31F6FCD3A0 A0974382C4C5 A82045A10949 - # DATA FROM HTTPS://PASTEBIN.COM/2IV8H93H # FUNNIVARIUM # FORUM ANKARA 2602FFFFFFFF - # MACERA ADASI # ANKARA KENTPARK # INACTIVE @@ -1247,20 +1113,16 @@ A82045A10949 DFF293979FA7 4D6F62692E45 4118D7EF0902 - # PETROL OFISI # POSITIVE CARD # ODE-GEC 0406080A0C0E - # KONYA ELKART 988ACDECDFB0 120D00FFFFFF - # BOWLINGO # SERDIVAN AVYM 4AE23A562A80 - # KART54 2AFFD6F88B97 A9F3F289B70C @@ -1269,23 +1131,18 @@ DB6819558A25 B16B2E573235 42EF7BF572AB 274E6101FC5E - # CRAZY PARK # KIZILAY AVM 00DD300F4F10 - # KARTSISTEM B FEE2A3FBC5B6 - # TORU ENT # TAURUS AVM 005078565703 - # VING? 0602721E8F06 FC0B50AF8700 F7BA51A9434E - # ESKART # ESKISEHIR TRANSPORT CARD E902395C1744 @@ -1294,7 +1151,6 @@ E902395C1744 D8BA1AA9ABA0 76939DDD9E97 3BF391815A8D - # MUZEKART # MUSEUM CARD FOR TURKEY 7C87013A648A @@ -1326,7 +1182,6 @@ D0DDDF2933EC 240F0BB84681 9E7168064993 2F8A867B06B4 - # BURSAKART # BURSA TRANSPORT CARD 755D49191A78 @@ -1336,22 +1191,18 @@ DAC7E0CBA8FD 0860318A3A89 1927A45A83D3 B2FE3B2875A6 - # PLAYLAND # MALTEPE PARK ABCC1276FCB0 AABAFFCC7612 - # LUNASAN # KOCAELI FAIR 26107E7006A0 - # GAMEFACTORY # OZDILEK 17D071403C20 534F4C415249 534F4C303232 - # NESPRESSO, SMART CARD # KEY-GEN ALGO, THESE KEYS ARE FOR ONE CARD FF9A84635BD2 @@ -1430,20 +1281,15 @@ AE76242931F1 124578ABFEDC ABFEDC124578 4578ABFEDC12 - # PREMIER INN HOTEL CHAIN 5E594208EF02 AF9E38D36582 - # NORWEGIAN BUILDING SITE IDENTICATION CARD. (HMS KORT) 10DF4D1859C8 - # KEY B B5244E79B0C8 - # UKRAINE HOTEL F5C1C4C5DE34 - # DATA FROM MIFARE CLASSIC TOOL REPO # ROTTERDAM UNIVERSITY OF APPLIED SCIENCES CAMPUS CARD BB7923232725 @@ -1468,7 +1314,6 @@ B5ADEFCA46C4 BF3FE47637EC B290401B0CAD AD11006B0601 - # ARMENIAN METRO E4410EF8ED2D 6A68A7D83E11 @@ -1478,7 +1323,6 @@ D3F3B958B8A3 2196FAD8115B 7C469FE86855 CE99FBC8BD26 - # KEYS FROM EUROTHERMES GROUP (SWITZERLAND) D66D91829013 75B691829013 @@ -1494,11 +1338,9 @@ FED791829013 29A791829013 668091829013 00008627C10A - # KEYS FROM NSP MANCHESTER UNIVERSITY UK ACCOMODATION STAFF AND STUDENTS 199404281970 199404281998 - # EASYCARD 310D51E539CA 2CCDA1358323 @@ -1506,7 +1348,6 @@ FED791829013 562E6EF73DB6 F53E9F4114A9 AD38C17DE7D2 - # SOME KEYS OF HTTPS://W3BSIT3-DNS.COM AND HTTPS://IKEY.RU # STRELKA EXTENSION 5C83859F2224 @@ -1517,7 +1358,6 @@ C4D3911AD1B3 CAD7D4A6A996 DA898ACBB854 FEA1295774F9 - # MOSCOW PUBLIC TOILETS CARD 807119F81418 22C8BCD10AAA @@ -1527,7 +1367,6 @@ DBF9F79AB7A2 34EDE51B4C22 C8BCD10AAABA BCD10AAABA42 - # MOSCOW SOCIAL CARD 2F87F74090D1 E53EAEFE478F @@ -1570,12 +1409,10 @@ F750C0095199 82DA4B93DB1C 9CF46DB5FD46 93EB64ACF43D - # KEYS FROM RFIDRESEARCHGROUP PROXMARK3 PROJECT # HTTPS://GITHUB.COM/RFIDRESEARCHGROUP/PROXMARK3/BLOB/MASTER/CLIENT/DICTIONARIES/MFC_DEFAULT_KEYS.DIC 13B91C226E56 5A7A52D5E20D - # IRON LOGIC A3A26EF4C6B0 2C3FEAAE99FC @@ -1594,11 +1431,9 @@ DEC0CEB0CE24 413BED2AE45B D6261A9A4B3F CB9D507CE56D - # MORE KEYS FROM THE PM3 REPO # KEYS OF ARMENIAN UNDERGROUND TICKET A0A1A2A8A4A5 - # https://github.com/RfidResearchGroup/proxmark3/blob/master/client/dictionaries/mfc_keys_bmp_sorted.dic 002DE0301481 004173272D18 @@ -2600,7 +2435,6 @@ EE17C426D25E EE487A4C806E EE5931913A8D EED56840AEBA - # https://github.com/RfidResearchGroup/proxmark3/blob/master/client/dictionaries/mfc_keys_icbmp_sorted.dic 00383D96411D 005307DB7853 @@ -3602,7 +3436,6 @@ EE3029556CEB EE49610E6121 EEB704D69BCA EED69A391464 - # https://github.com/RfidResearchGroup/proxmark3/blob/master/client/dictionaries/mfc_keys_mrzd_sorted.dic 010203040506 013940233313 @@ -3661,7 +3494,6 @@ F83466888612 F89C86B2A961 FFFFAE82366C FFFFD06F83E3 - # Unknown origin 2DEB57A3EA8F 32C1BB023F87 @@ -3745,26 +3577,19 @@ D27058C6E2C7 E19504C39461 FA1FBB3F0F1F FF16014FEFC7 - # Cracked by UberGuidoZ # https://github.com/UberGuidoZ # BadgeMaker Leaked 1A1B1C1D1E1F 1665FE2AE945 158B51947A8E -EL67EC67C7FF -D53732OFF9OE 5E56BFA9E2C9 F81CED821B63 C81584EF5EDF 9551F8F9259D -36EL765CE3E8 509052C8E42E 776C9B03BE71 -C608EL3ADD50 BEE8B345B949 -EDOEC56EEFDD -9716D524LE28 05D1FC14DC31 3321FB75A356 F22A78E29880 @@ -3778,9 +3603,7 @@ DB32A6811327 8AA8544A2207 8C5819E780A4 7549E90353A2 -2E52ABEOCE95 E46210ED98AB -61DO30COD7A8 18E20102821E DA59354DFB88 040047C12B75 @@ -3789,7 +3612,6 @@ D10008074A6F 446176696453 6F6674776172 6520446F7665 - # Apartment keyfobs in USA from Corvette830 E60F8387F0B9 FFD46FF6C5EE @@ -3798,7 +3620,6 @@ FFD46FF6C5EE 1C5179C4A8A1 16CA203B811B 11AC8C8F3AF2 - # The Westin Jakarta Indonesia from D4DB0D # Peppers Hotel Unknown location from D4DB0D 6E0DD4136B0A @@ -3813,19 +3634,15 @@ FC5AC7678BE3 F09BB8DD142D B4B3FFEDBE0A 540E0D2D1D08 - # Schlage 9691T Keyfob 7579B671051A 4F4553746B41 - # FOOD REPUBLIC 30C1DC9DD040 A9B9C1D0E3F1 - # iGuard Simple (and reverse) keys AAAAAAFFFFFF FFFFFFAAAAAA - # Vigik verified by quantum-x # https://github.com/RfidResearchGroup/proxmark3/pull/1742#issuecomment-1206113976 A00027000099 @@ -3843,10 +3660,8 @@ A00000043D79 A00000000064 A00025000030 A00003000057 - # BH USA 2013 conference 012279BAD3E5 - # Vigik ScanBadge App (fr.badgevigik.scanbadge) # Website https://badge-vigik.fr/ - By Alex` 0000A2B3C86F @@ -3875,12 +3690,10 @@ A00003000057 9EB7C8A6D4E3 A22AE12C9013 AFC984A3576E - # Spackular A/B # data from http://www.proxmark.org/forum/viewtopic.php?pid=45100#p45100 7CB033257498 1153AABAFF6C - # iGuard Simple and Reverse Keys D537320FF90E 36E1765CE3E8 @@ -3889,13 +3702,10 @@ ED0EC56EEFDD 9716D5241E28 2E52ABE0CE95 61D030C0D7A8 - # BadgeMaker Leaked from https://github.com/UberGuidoZ E167EC67C7FF - # Schlage 9691T Keyfob from seasnaill Added by VideoMan. 3111A3A303EB - # Transport cards E954024EE754 0CD464CDC100 @@ -3905,18 +3715,13 @@ F7A545095C49 6862FD600F78 72A0C485D3F7 6A530C91F85B - # RENFE MADRID (TRAIN) Extracted with detect reader 701AA491A4A5 12BA20088ED3 - # MISC KEYS FROM MY OLD ACCESS CARDS F18D91EE3033 0E726E11CFCC 1D14130D1A0B -4ADLE273EAFL -3DFL4C8000A1 -E64Q986Q5D94 201106141030 D144BD193063 01E2C14F1B18 @@ -3959,25 +3764,20 @@ E10F0E7A8DD5 F833E24C3F1C FA8CA10C7D59 FE98F38F3EE2 -# -########################################## -# added by colonelborkmundus -# "the more, the marriott" mifare project -# - -# 1k - graduate hotel +#---------------------------------------------------- +# Added by colonelborkmundus, cleaned by scaff.walker +# "the more, the marriott" Mifare project +# 1k GRADUATE HOTEL C49DAE1C6049 209A2B910545 - -# 1k - westin +# 1k WESTIN 8C29F8320617 5697519A8F02 7D0A1C277C05 2058580A941F C40964215509 D44CFC178460 - -# 1k - marriott +# 1k MARRIOT 7B4DFC6D6525 23C9FDD9A366 3119A70628EB @@ -3987,52 +3787,39 @@ D44CFC178460 035C70558D7B 9966588CB9A0 12AB4C37BB8B - -# 1k - AC hotels marriott +# 1k AC HOTELS MARRIOT 8EA8EC3F2320 7B56B2B38725 - -# 1k - the ritz-carlton +# 1k THE RITZ-CARTLON 30FB20D0EFEF D20289CD9E6E 66A3B064CC4B D18296CD9E6E - -# 1k - unknown +# 1k UNKNOWN 722538817225 - -# 1k - aria resort & casino +# 1k ARIA RESORT & CASINO 316B8FAA12EF A18D9F4E75AF - -# 1k - fairfield inn & suites marriott +# 1k FAIRFIELD INN & SUITES MARRIOT 7AEB989A5525 7B3B589A5525 215E9DED9DDF 334E91BE3377 310308EC52EF - -# 1k - residence inn marriott +# 1k RESIDENCE INN MARRIOT F72CD208FDF9 - -# 1k - sheraton +# 1k SHERATON 42FC522DE987 - -# 1k - millenium hotels +# 1k millenium hotels 132F641C948B - -# 1k - moxy hotels +# 1k MOXY HOTELS 20C166C00ADB 9EE3896C4530 - -# 1k - residence inn marriott +# 1k RESIDENCE INN MARRIOT 3122AE5341EB - -# 1k - americinn +# 1k AMERICINN 8AC04C1A4A25 - -# 1k - the industrialist +# 1k THE INDUSTRIALIST 2158E314C3DF - -# 1k - waldorf astoria -011C6CF459E8 \ No newline at end of file +# 1k WALDORF ASTORIA +011C6CF459E8 diff --git a/assets/resources/subghz/assets/keeloq_mfcodes b/assets/resources/subghz/assets/keeloq_mfcodes index 31619d6e7..cb80c2e2e 100644 --- a/assets/resources/subghz/assets/keeloq_mfcodes +++ b/assets/resources/subghz/assets/keeloq_mfcodes @@ -1,57 +1,58 @@ Filetype: Flipper SubGhz Keystore File Version: 0 Encryption: 1 -IV: 5C AD F1 B1 BA B0 BA 11 AB 0B A3 6C F7 E3 6A 21 -AA7C98C6E94AA4062F875AB40BA3CE977D18B89830CCEB30179C5F2788E8941C -5B2D494F1AC8971B5F758D56D72F709E674B92F4B8D5BF9E4BBD48DBEFD11678 -AF3FFC3AB39E07694127DC64DD9BB371461200F4A6ED4622C5BA21F854394BE4 -2D889E3B426032518D20A7B35718FCCDA6769E310021BD41FF87D2A4DC4C1ED8 -7FB119118304533D748BAF06AAF69E838D6B6B20A84B51AEEBE6001FD5307DC8C98B46CF249E3E24FF64A033C470135B -B38B5D82576D4BFB7E5B600711695E409C1E33B539F167BE54572F9721D75566 -CAB78E2DE09DA67C95E0302A9A0010204A715CE61AD0884DEF018A15971D0DA8 -9794862BCFD7F31676245AB8BF369C754CBD6E818E8866CB2C743C3DC7F455BA -77AAE6912434A95B46A6C07B5A59EF287B83CE2620FEECF92CDAE7858F6A8050 -1A55BDD4F0E5F555EA3DF74182CE871343C955FD2349FB37B1B21FAC170511EB -892FAE550B5BF6CE2C6C85B74C8AD45D37E174CFD9EE0767927BCBCC904AA7CB464451E43EF9435E61635DC6EEFAD5E5 -26A7511E2213053BA49868CEE9FB56474CFB5AA422AFBF4C0FB5D5285E6C474DB7EF74A731D259A18AD1EF6EE015A9B2 -F3B14CFE82809DD20A8CE0EF9806CA40E3BA6EF8D62495AF9DEF0F92625F05E7 -BAC0B60E24FE913885FE3FF0A7E9EAB2B224471ABF738507E14060747792783E -070E67988EFF2B31EEE0AD2E8663EE8CEB4DACBB9D8D1159E7C9E84E18F1F7D4 -1755162EEA343C8D9D09852FA5B90E05DDE129145442822F937CE64EA168DE78 -70CF01EB50613461B447C6F54A2E28CAFDD39776B90BD88FDE3A2F5BE8ED5950387819C5F8BCAEEE0DE1A16692F5F07C -8152ECF2A96968C7803803851C70489B19846AB4450B5B5398A86E05D76A5E85 -D9A44B2BC3920622F8ED3EC2A18756612D05C3BF3555F752520AA206128576B3 -AD156C422650D482BFD399926330C849F61C145C6874EAE2826AEDA6BFEFB9892FF615E9CE4005274BF2217733629510 -1735246565057FF7A91DF91CE87A82F1823AC53282377CF188245C4E0A0A12420DFDDA0B70D2498D1C6C5456527FBF66 -E25E66ADCCF628CD21C14D61D47952816EE2265AD7664645A321D45197E1703B -07ACA960A68DAD72B3F7C51AB8573AB0BD08531390226F5404B0098A9FCAC239 -577209D5117506CEF9B6D4EA9F9783CE0EA57415EBBE5318B057D7E0AEFBDFC9 -708B950FCF78EFC2FEE1969A2590EBD8BDF95ACD2B052E96017B39EA667C2AAB -05D7DD808F82F97848B695D5C302FDF20F55D2FD56E386227726691ED581EC9A -08F1AEF4B9F694DF723813613FE0208A4ACF7079773B37CEFCAF7A132EBD4DBA -F607CEBFA3E307F27AC484B9E08FB96A2B678FBA4963AAC479F53D9CAC3530DF -578BBAD7BD2818DC9CC6F711035C267AF005B23A24BA79C66D408474CECEA799 -CA9A8ACCB5BEA6B53C4CE302CC052FC560317410A977425D0E7924AE10D4ED85 -523FE24DD7A7F4E2DF0E09771C863A934662A564152966B67DFECE7D37A53A50 -A606653C13720134F4564DD96FCD1AD44E66D9405BA95CFD0D91FE8828D0B615 -3ED9295F9C5D3C4E949B8E83CF63EBFD0482D224F4015451AD31646FD91F95D2 -7077291A87C15DE4605989467D38283F5416D6AD6D9B2458CE5A75D40A61B3D9 -08A7FECA1D73D605D4E71E69AD2112915A28DBE5A6817C52C2C451A9E1435CF1 -76FBB6AA098D630B5297261090F50011FFEEE6611347A2DF65E0C1C88C4DFFDD879A7C9134D2C51A61C3C7796833ADA6 -2315673B961F8D1C46020AAAB3BC73EE480496F6F5C6B9BF7175DF32A92D1E29 -851620CB407C3CA9A26CF6F6E3350A13FC241A99D7FCAF5EC41A90C40F6518A2 -F97AB6A733F1C288585629CC89A8AFA50B0D7B4CC2E0D41CA0B7118B37EB5170 -E725E6B06E9C8A575609E28DB887508D6CD6623BFD2151BDE0984E1E014A3FAB -138082F590404A5A335601C9872D08F0950EEEB7B28C5D6238F6A4C7FD73CFAC -22687BB4B5044A02C4F86FFA6B8113A3D315325CBAC503498284FA44C3566EE3 -1A5D93DE887B497D3904BD5C29F456EB6D8EA7D6B79962769F1862F21C6CC257 -F3ADA4CA246DC47577A40F7F24213A1E773CE7C9D3F5B0A054EE0807C81CB0B6 -CBA2632796ADB82F57A0B701BF1EF9787C27F4DD14C79D0FD09CD88447A8368B -5CF50ED192649B1F769451EEA7FC9D1F6585990D4D7618FB56A7C41DC3A93904 -62062BFC4F4CA5C7568F042832B27777BDB79522BB7BA3BB4F9644D35416ADC9 -AE7EED026C970F8A8AA2B33C01B7660BFD83B550367CACA4D9B266E2756C3A7E6C3BD0D2EEA3F6ED7C9A4023C575750A -A04D0A134EF9B67BAC02ABDD2E355422C96665D99484DF4E4EFD2CE4AA66F4BB -D7209CB12AFC47261B223C8EC48BDA3131C006FA997396F050FCBEEEFAC7B65A -2E58BF2F918C44F01DD3DFBB49C5FABB33FFFF25B6AC975CA1819A7554093C25 -96C5A04C551604AA8069E213A7FFCE7EA8D8BCF9B61F93BA4E912630AF1BA886 -9219823986AE58A5FD919E809478AF894A73A413F7C12D8B29DF8BD3ADE730652FB7EB3115CF2914F748AE64F996A4B3 +IV: AB 0B A1 23 45 FE E7 06 66 73 21 67 97 12 3D 61 +CA9DC3E30069ED9C257FCA6747136F617F4E390F2B8BDDFDEBEC8A398A6A0C1E +78F18401572E33117850EA83D00C2F92376E88D7CAC0BF7CBA7037BF6755F43C +909055FF43224057BCE5F965174AF46586EB7CA4CAE1B3EB8B66EA569047948A +AB9B7D338457774713147BF666A5996926B90146CB698AC2F4DE63ADE89D84BB +ED796AED9BB3185ACD94779F7CC42665D4A3B04419E4272B77DA8D94B5CF84921889CEB110AB55D7267720A7C5B290EF +88E0CECA92549C73981F95999FA8F03B1B2EB98774134752556D7D7EFA802757 +C42CABAD74010E35726659C8E4AF4888282FBEA9703616B3403DA7C3DCA8A8ED +6F44BC56AC2E9883A2469C1909D171A8C58A0CFE4B506CC562EB2F08A484AE1B +65DEBEBC629FA3CE72B5028E1E385DFFEE0A9FE227FC5F6DD4368C0CB1886A7D +EA9BDC762FCBAAA11A4BE677AE344993990153C9E7A4A89F8271F49765FC72EF +8FAE9AC3033E637703626956F91791DAE4B3BEA9C82C065C91A314DDB647F8FE661750526E58C613000260675C2B520C +3D853DEC62375B3201B1C2269E31794A3C29958B191953A331D39675CCB53C002EF1491B63C49E629AF5D747CC52BD11 +61A02BB85B08AA8047EAD9FB80D489AB15CBE0302C660891C4B29D2621C80DBB +5230A9651D1A0910695593E1A5F6EA6EB21990D6465E52B325CF141C9E0C9172 +C9348D18DC019C3E364F7AD9CD5B6D77EE2D6486CFBDFAFE7042AB917E8FFE7C +DED385BBAC8FAB5918DBDBDC8622850048A540963AF35C3DD772926927B148C2 +E1EC13990BDA8E22F2848F97069462FB46840FEA688C52EDE930CD22C4E6F445BF317A96C4A6C2DC4295B2E3E86053B9 +D5453884C337587A13117F35219C7B4356E8E63EBC4C197CC1633D444D0A6AD0 +72C3E291DA11AD3D195C6A1B65849B0C91B7D18762B515A5728389356C42B62C +0E9EA0D97053752977D83A019A2F0393D326407AE507F5EE6E650082DBC683F81BDD71B79BE81EEB3139815377577346 +A32FF38450B3121CB01CE06AA369DC7B883CD9B1695CBADBC9609F009D6BFF7B7518D9DD690D214A1DB0D1A0C6F9FC3F +98848EFBB09D2A3EA59EE91B1B510BA3775E36B14500DE1238317AFC9872358F +E8B2785366399F84EADF07B0E299603BB885780E6ECA883508FFB7664C6473FE +1F6CEA6696B2E07FEB256506609D7E11D9F09F18B9EE43DE9BC42014ABF5213F +F2FF5045A5E90AAF92C2ECCB9FEFFBDE400A7E3E6B09CF43608896F7BC91736F +73CC30A78808BB2B3F7F398D88C79470AF86B825DE0C2FF31442D351C2826D9C +B68FD5017BA4809AD22DF64805DCE329A81C2CE3F7BE87FADFBD02211AB02321 +57BC2E14A724D6E2F4B0FD9401C3E6E5117D338077958648A558E40C553C787F +882A41BC36393F06C57ED71E66D003E24B5DAE86F90D8AEDD89A2DFED6719BF1 +95EDC3C3EB639AC66656B58D8F71A5B1B329002C4CCF7666C41C717A939C0979 +494A32528A68F5B4DF45385CC7FB470224F25D8AC9C81AB0DBD291AA4764BB17 +9A6D21675317433CE6EE860C9A2713265E1DA5E8F4024690252971EA5C2A566A +2B8379BCDDD0E6F73B1AD2D5A4D69D34D0013E98C87AD2BCE7AEED80F3BF4F69 +6E5D67B8B825943F9B9979D5E1EA9348B1DD40A5DA39B20FA96B78CAD3E03747 +27559A18DD6D52FFED8427376113C1A35840D64A53466071E1B769A28F161A99 +A2F38E38C253947816B5E629AAC02BC77EF7B56CC95FBF291C05466C56E01E47FE92053C900C0F6F98B11D7873BB9AFC +8A7E57E1228F75F78D51C13FE79C269E43F007E55F5B87741BCADDAAA6402DF7 +E088817700DBC7D778427464368D7771E3C20194CE60D08668578CAA527258B8 +3E5AD04DE23578A3BBC5FB91608435EBA1FF1465EDCE3E064F60A2EED35C9015 +647C9BFB61C0509D152A7B6B5C548DC558052F862314B42F4D1D8B98F6BF2412 +3D659FF6999401CAB590681036C3FDABAF157C774928E0D7D76FAC08AA6CFE93 +342362E28923E64DC5047E25E5A2F3FC8A6EB63554793CB8A1C99FFE632A370508CA208CA912470DB343A1636C751B9E +3B71D04AB09DFB44015F5553B4B76C9419C4D615F60184BA0B6A5687E47D66BA +14CF7621A4943DE2156AB8FDE8A9E74D26776D8362D9364387626488CB3DA5DC +2F9205BF8B310C33E38F571FFBDF6FC4BA5135457A2CF6CA9CD319F3EDF4BF6E +785EDF05A2111B8E4A126BE274C9BD8D6C0482F4A2B716FFAE93EDB8D1634F41 +4B26880D1AE8EC1D285296F473EB5A805CF1C1EA47B899A6A3F8E9EFDB2CBCA3 +A002B3ED0D1FCBC02298BFE7F18207CD58AB21D358F20855D067939EF50DCC08 +BE82806DE526A6453C6FA309DAE0B52D67A98A194753DD4CC2C8C196A47B253F60149FAF49D0396E1F24CB1EDF1430DA +031686817FB37936FD0313B9358FD35BAF5DEB924F7A939C4B843DD095F11806 +3A7B7A7AE8723C2A060FF368AB048A48737D4EEAD3C97BF98BC9E8CAE552431B +357C4A1A41F43100208863F2E607AE14CC55235D757CDE5C491BE405BB72BDB4 +0C46E442B9AC3C479C18D4D94AB3E5124D4033AFD05AE00AC6881DD62F11E07F +8705CF1D9B202056CEBD98FF25CB0B6BF40175DBDC2FE86FE2A7D2AC796F818EA71A8C1312E9C7FCE6CC3D11FBBA98E4 diff --git a/documentation/InfraredCaptures.md b/documentation/InfraredCaptures.md new file mode 100644 index 000000000..61097ad6d --- /dev/null +++ b/documentation/InfraredCaptures.md @@ -0,0 +1,83 @@ +# Infrared Captures + +**Credits go to @gsurkov, @skotopes, @knrn-ai, @DrZlo13 and @ahumeniy for making and contributing to the original `UniversalRemotes.md` Documentation located [Here](https://github.com/flipperdevices/flipperzero-firmware/blob/dev/documentation/UniversalRemotes.md).** + +**slightly adapted by @amec0e** + +## Televisions, Fans, Audio and Projectors + +Each signal is recorded using the following process: + +1. Get the remote and point it to Flipper's IR receiver. +2. Start learning a new remote if it's the first button or press `+` to add a new button otherwise. +3. Do a Quick Press of a remote button and save it under a corresponding name. **(NOTE: Don't hold the remote button down, this will result in long captures and long playbacks ultimately slowing down the universal remotes performance)** +4. Repeat steps 2-3 until all required signals are saved. + +The signal names are self-explanatory. Remember to make sure that every recorded signal does what it's supposed to. + +**NOTE:** It's possible some devices around you will cause interference and may force your capture into raw data instead of a parsed code. +If you notice you get a parsed code when capturing it's best to click "Retry" a few times on the flipper when capturing to ensure the device is not suffering from any interference, and that the cleanest capture is possible. + +## Types of data + +**Parsed data** + +This is the cleanest type of data because it means it is a recognised code. + +``` +name: EXAMPLE +type: parsed +protocol: NEC +address: 07 00 00 00 +command: 02 00 00 00 +``` + +**Raw Data** + +With raw data its important not to hold the remotes button down when capturing on your flipper as this increases not only the size of the capture but the repeats and also how long it takes to send the signal back. Below is an ideal button capture. + +``` +# +name: EXAMPLE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 2410 597 1189 599 592 600 1186 602 589 603 1183 606 595 597 593 598 1208 605 596 596 594 597 593 599 592 25604 2403 604 1182 606 595 597 1189 599 591 601 1185 603 618 573 617 575 1211 602 588 603 588 605 596 596 594 25605 2402 604 1192 596 594 597 1189 599 592 601 1185 628 593 598 593 600 1186 602 589 603 588 604 597 595 596 +``` + +**Capturing Raw Data:** + +If you are sure your remote is using raw data the best way to capture it will be to do a quick button press **(don't hold the remotes button down)** and look at how many samples you get, the general idea here is to get the lowest amount of raw data samples captured (around 100 samples is about right) while making sure that the playback on the device is still working. This is usually accomplished by doing a quick button press on the remote when capturing. + +## Air Conditioners + +Air conditioners differ from most other infrared-controlled devices because their state is tracked by the remote. +The majority of A/C remotes have a small display that shows the current mode, temperature, and other settings. +When the user presses a button, a whole set of parameters is transmitted to the device, which must be recorded and used as a whole. + +In order to capture a particular air conditioner, there is a particular process require to capturing and this is done using the following process: + +1. Get the remote and press the **Power Button** so that the display shows that A/C is ON. +2. Set the A/C to the corresponding mode (see table below), leaving other parameters such as fan speed or vane on **AUTO** (if applicable). +3. Press the **POWER** button to switch the A/C off. +4. Start learning a new remote on Flipper if it's the first button or press `+` to add a new button otherwise. +5. Point the remote to Flipper's IR receiver as directed and press **POWER** button once again. +6. Save the resulting signal under the specified name. +7. Repeat steps 2-6 for each signal from the table below. + +| Signal | Mode | Temperature | Note | +| :-----: | :--------: | :---------: | ----------------------------------- | +| Dh | Dehumidify | N/A | | +| Cool_hi | Cooling | See note | Lowest temperature in cooling mode | +| Cool_lo | Cooling | 23°C | | +| Heat_hi | Heating | See note | Highest temperature in heating mode | +| Heat_lo | Heating | 23°C | | + +Finally, record the `Off` signal: + +1. Make sure the display shows that the A/C is ON. +2. Start learning a new signal on Flipper and point the remote towards the IR receiver. +3. Press the **POWER** button so that the remote shows the OFF state. +4. Save the resulting signal under the name `Off`. + +Test the file against the actual device. Make sure that every signal does what it's supposed to. diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index adca3b714..eca5f1cf3 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -205,6 +205,7 @@ Header,+,lib/toolbox/stream/string_stream.h,, Header,+,lib/toolbox/tar/tar_archive.h,, Header,+,lib/toolbox/value_index.h,, Header,+,lib/toolbox/version.h,, +Header,+,lib/u8g2/u8g2.h,, Function,-,LL_ADC_CommonDeInit,ErrorStatus,ADC_Common_TypeDef* Function,-,LL_ADC_CommonInit,ErrorStatus,"ADC_Common_TypeDef*, LL_ADC_CommonInitTypeDef*" Function,-,LL_ADC_CommonStructInit,void,LL_ADC_CommonInitTypeDef* @@ -1443,6 +1444,8 @@ Function,+,furi_hal_version_get_hw_connect,uint8_t, Function,+,furi_hal_version_get_hw_display,FuriHalVersionDisplay, Function,+,furi_hal_version_get_hw_region,FuriHalVersionRegion, Function,+,furi_hal_version_get_hw_region_name,const char*, +Function,+,furi_hal_version_get_hw_region_name_otp,const char*, +Function,+,furi_hal_version_get_hw_region_otp,FuriHalVersionRegion, Function,+,furi_hal_version_get_hw_target,uint8_t, Function,+,furi_hal_version_get_hw_timestamp,uint32_t, Function,+,furi_hal_version_get_hw_version,uint8_t, @@ -4483,7 +4486,7 @@ Function,-,uxStreamBufferGetStreamBufferNumber,UBaseType_t,StreamBufferHandle_t Function,-,uxTaskGetNumberOfTasks,UBaseType_t, Function,-,uxTaskGetStackHighWaterMark,UBaseType_t,TaskHandle_t Function,-,uxTaskGetStackHighWaterMark2,uint16_t,TaskHandle_t -Function,+,uxTaskGetSystemState,UBaseType_t,"TaskStatus_t*, const UBaseType_t, uint32_t*" +Function,-,uxTaskGetSystemState,UBaseType_t,"TaskStatus_t*, const UBaseType_t, uint32_t*" Function,-,uxTaskGetTaskNumber,UBaseType_t,TaskHandle_t Function,+,uxTaskPriorityGet,UBaseType_t,const TaskHandle_t Function,-,uxTaskPriorityGetFromISR,UBaseType_t,const TaskHandle_t diff --git a/firmware/targets/f7/furi_hal/furi_hal_subghz.c b/firmware/targets/f7/furi_hal/furi_hal_subghz.c index 0fe5d1878..415bb325e 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_subghz.c +++ b/firmware/targets/f7/furi_hal/furi_hal_subghz.c @@ -44,13 +44,15 @@ volatile FuriHalSubGhz furi_hal_subghz = { bool furi_hal_subghz_set_radio_type(SubGhzRadioType state) { furi_hal_subghz.radio_type = state; furi_hal_spi_bus_handle_deinit(furi_hal_subghz.spi_bus_handle); - if(state) { - furi_hal_subghz.spi_bus_handle = &furi_hal_spi_bus_handle_subghz_ext; - furi_hal_subghz.cc1101_g0_pin = &gpio_cc1101_g0_ext; - } else { + + if(furi_hal_subghz.radio_type == SubGhzRadioInternal) { furi_hal_subghz.spi_bus_handle = &furi_hal_spi_bus_handle_subghz; furi_hal_subghz.cc1101_g0_pin = &gpio_cc1101_g0; + } else { + furi_hal_subghz.spi_bus_handle = &furi_hal_spi_bus_handle_subghz_ext; + furi_hal_subghz.cc1101_g0_pin = &gpio_cc1101_g0_ext; } + furi_hal_spi_bus_handle_init(furi_hal_subghz.spi_bus_handle); furi_hal_subghz_init_check(); return true; @@ -121,37 +123,26 @@ bool furi_hal_subghz_init_check(void) { // Prepare GD0 for power on self test furi_hal_gpio_init(furi_hal_subghz.cc1101_g0_pin, GpioModeInput, GpioPullNo, GpioSpeedLow); - if(furi_hal_subghz.radio_type == SubGhzRadioExternal) { - // GD0 low - cc1101_write_reg(furi_hal_subghz.spi_bus_handle, CC1101_IOCFG0, CC1101IocfgHW); - uint32_t test_start_time = furi_get_tick(); - while(furi_hal_gpio_read(furi_hal_subghz.cc1101_g0_pin) != false && result) { - if(furi_get_tick() - test_start_time > INIT_TIMEOUT) { - result = false; - } - } - // GD0 high - cc1101_write_reg( - furi_hal_subghz.spi_bus_handle, CC1101_IOCFG0, CC1101IocfgHW | CC1101_IOCFG_INV); - test_start_time = furi_get_tick(); - while(furi_hal_gpio_read(furi_hal_subghz.cc1101_g0_pin) != true && result) { - if(furi_get_tick() - test_start_time > INIT_TIMEOUT) { - result = false; - } + // GD0 low + cc1101_write_reg(furi_hal_subghz.spi_bus_handle, CC1101_IOCFG0, CC1101IocfgHW); + uint32_t test_start_time = furi_get_tick(); + while(furi_hal_gpio_read(furi_hal_subghz.cc1101_g0_pin) != false && result) { + if(furi_get_tick() - test_start_time > INIT_TIMEOUT) { + result = false; } - } else { - // GD0 low - cc1101_write_reg(furi_hal_subghz.spi_bus_handle, CC1101_IOCFG0, CC1101IocfgHW); - while(furi_hal_gpio_read(&gpio_cc1101_g0) != false) - ; - - // GD0 high - cc1101_write_reg( - furi_hal_subghz.spi_bus_handle, CC1101_IOCFG0, CC1101IocfgHW | CC1101_IOCFG_INV); - while(furi_hal_gpio_read(&gpio_cc1101_g0) != true) - ; } + + // GD0 high + cc1101_write_reg( + furi_hal_subghz.spi_bus_handle, CC1101_IOCFG0, CC1101IocfgHW | CC1101_IOCFG_INV); + test_start_time = furi_get_tick(); + while(furi_hal_gpio_read(furi_hal_subghz.cc1101_g0_pin) != true && result) { + if(furi_get_tick() - test_start_time > INIT_TIMEOUT) { + result = false; + } + } + // Reset GD0 to floating state cc1101_write_reg(furi_hal_subghz.spi_bus_handle, CC1101_IOCFG0, CC1101IocfgHighImpedance); furi_hal_gpio_init(furi_hal_subghz.cc1101_g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow); @@ -435,47 +426,47 @@ bool furi_hal_subghz_is_tx_allowed(uint32_t value) { flipper_format_free(fff_data_file); furi_record_close(RECORD_STORAGE); - switch(furi_hal_version_get_hw_region()) { - case FuriHalVersionRegionEuRu: - //433,05..434,79; 868,15..868,55 - if(!(value >= 433050000 && value <= 434790000) && - !(value >= 868150000 && value <= 868550000)) { - } else { - is_allowed = true; - } - break; - case FuriHalVersionRegionUsCaAu: - //304,10..321,95; 433,05..434,79; 915,00..928,00 - if(!(value >= 304100000 && value <= 321950000) && - !(value >= 433050000 && value <= 434790000) && - !(value >= 915000000 && value <= 928000000)) { - } else { - if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { - if(value <= 321950000 && - ((furi_hal_subghz.preset == FuriHalSubGhzPresetOok270Async) || - (furi_hal_subghz.preset == FuriHalSubGhzPresetOok650Async))) { - furi_hal_subghz_load_patable(furi_hal_subghz_preset_ook_async_patable_au); - } + switch(furi_hal_version_get_hw_region_otp()) { + case FuriHalVersionRegionEuRu: + //433,05..434,79; 868,15..868,55 + if(!(value >= 433050000 && value <= 434790000) && + !(value >= 868150000 && value <= 868550000)) { + } else { + is_allowed = true; } - is_allowed = true; - } - break; - case FuriHalVersionRegionJp: - //312,00..315,25; 920,50..923,50 - if(!(value >= 312000000 && value <= 315250000) && - !(value >= 920500000 && value <= 923500000)) { - } else { - is_allowed = true; - } - break; + break; + case FuriHalVersionRegionUsCaAu: + //304,10..321,95; 433,05..434,79; 915,00..928,00 + if(!(value >= 304100000 && value <= 321950000) && + !(value >= 433050000 && value <= 434790000) && + !(value >= 915000000 && value <= 928000000)) { + } else { + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + if(value <= 321950000 && + ((furi_hal_subghz.preset == FuriHalSubGhzPresetOok270Async) || + (furi_hal_subghz.preset == FuriHalSubGhzPresetOok650Async))) { + furi_hal_subghz_load_patable(furi_hal_subghz_preset_ook_async_patable_au); + } + } + is_allowed = true; + } + break; + case FuriHalVersionRegionJp: + //312,00..315,25; 920,50..923,50 + if(!(value >= 312000000 && value <= 315250000) && + !(value >= 920500000 && value <= 923500000)) { + } else { + is_allowed = true; + } + break; - default: - is_allowed = true; - break; + default: + is_allowed = true; + break; } // No flag - test original range, flag set, test extended range - if(!(value >= 299999755 && value <= 348000335) && - !(value >= 386999938 && value <= 464000000) && + if(!(value >= 299999755 && value <= 350000335) && // was increased from 348 to 350 + !(value >= 386999938 && value <= 467750000) && // was increased from 464 to 467.75 !(value >= 778999847 && value <= 928000000) && !(is_extended)) { FURI_LOG_I(TAG, "Frequency blocked - outside regional range"); return false; @@ -491,11 +482,8 @@ bool furi_hal_subghz_is_tx_allowed(uint32_t value) { } uint32_t furi_hal_subghz_set_frequency(uint32_t value) { - if(furi_hal_region_is_frequency_allowed(value)) { - furi_hal_subghz.regulation = SubGhzRegulationTxRx; - } else { - furi_hal_subghz.regulation = SubGhzRegulationTxRx; - } + furi_hal_subghz.regulation = SubGhzRegulationTxRx; + furi_hal_spi_acquire(furi_hal_subghz.spi_bus_handle); uint32_t real_frequency = cc1101_set_frequency(furi_hal_subghz.spi_bus_handle, value); cc1101_calibrate(furi_hal_subghz.spi_bus_handle); @@ -558,56 +546,55 @@ volatile uint32_t furi_hal_subghz_capture_delta_duration = 0; volatile FuriHalSubGhzCaptureCallback furi_hal_subghz_capture_callback = NULL; volatile void* furi_hal_subghz_capture_callback_context = NULL; -static void furi_hal_subghz_capture_ISR() { - if(furi_hal_subghz.radio_type == SubGhzRadioExternal) { - if(!furi_hal_gpio_read(furi_hal_subghz.cc1101_g0_pin)) { - if(furi_hal_subghz_capture_callback) { - if(furi_hal_subghz.async_mirror_pin != NULL) - furi_hal_gpio_write(furi_hal_subghz.async_mirror_pin, false); +static void furi_hal_subghz_capture_int_ISR() { + // Channel 1 + if(LL_TIM_IsActiveFlag_CC1(TIM2)) { + LL_TIM_ClearFlag_CC1(TIM2); + furi_hal_subghz_capture_delta_duration = LL_TIM_IC_GetCaptureCH1(TIM2); + if(furi_hal_subghz_capture_callback) { + if(furi_hal_subghz.async_mirror_pin != NULL) + furi_hal_gpio_write(furi_hal_subghz.async_mirror_pin, false); - furi_hal_subghz_capture_callback( - true, TIM2->CNT, (void*)furi_hal_subghz_capture_callback_context); - } - } else { - if(furi_hal_subghz_capture_callback) { - if(furi_hal_subghz.async_mirror_pin != NULL) - furi_hal_gpio_write(furi_hal_subghz.async_mirror_pin, true); - - furi_hal_subghz_capture_callback( - false, TIM2->CNT, (void*)furi_hal_subghz_capture_callback_context); - } - } - //Forced correction for improved accuracy - TIM2->CNT = 9; - } else { - // Channel 1 - if(LL_TIM_IsActiveFlag_CC1(TIM2)) { - LL_TIM_ClearFlag_CC1(TIM2); - furi_hal_subghz_capture_delta_duration = LL_TIM_IC_GetCaptureCH1(TIM2); - if(furi_hal_subghz_capture_callback) { - if(furi_hal_subghz.async_mirror_pin != NULL) - furi_hal_gpio_write(furi_hal_subghz.async_mirror_pin, false); - - furi_hal_subghz_capture_callback( - true, - furi_hal_subghz_capture_delta_duration, - (void*)furi_hal_subghz_capture_callback_context); - } - } - // Channel 2 - if(LL_TIM_IsActiveFlag_CC2(TIM2)) { - LL_TIM_ClearFlag_CC2(TIM2); - if(furi_hal_subghz_capture_callback) { - if(furi_hal_subghz.async_mirror_pin != NULL) - furi_hal_gpio_write(furi_hal_subghz.async_mirror_pin, true); - - furi_hal_subghz_capture_callback( - false, - LL_TIM_IC_GetCaptureCH2(TIM2) - furi_hal_subghz_capture_delta_duration, - (void*)furi_hal_subghz_capture_callback_context); - } + furi_hal_subghz_capture_callback( + true, + furi_hal_subghz_capture_delta_duration, + (void*)furi_hal_subghz_capture_callback_context); } } + // Channel 2 + if(LL_TIM_IsActiveFlag_CC2(TIM2)) { + LL_TIM_ClearFlag_CC2(TIM2); + if(furi_hal_subghz_capture_callback) { + if(furi_hal_subghz.async_mirror_pin != NULL) + furi_hal_gpio_write(furi_hal_subghz.async_mirror_pin, true); + + furi_hal_subghz_capture_callback( + false, + LL_TIM_IC_GetCaptureCH2(TIM2) - furi_hal_subghz_capture_delta_duration, + (void*)furi_hal_subghz_capture_callback_context); + } + } +} + +static void furi_hal_subghz_capture_ext_ISR() { + if(!furi_hal_gpio_read(furi_hal_subghz.cc1101_g0_pin)) { + if(furi_hal_subghz_capture_callback) { + if(furi_hal_subghz.async_mirror_pin != NULL) + furi_hal_gpio_write(furi_hal_subghz.async_mirror_pin, false); + + furi_hal_subghz_capture_callback( + true, TIM2->CNT, (void*)furi_hal_subghz_capture_callback_context); + } + } else { + if(furi_hal_subghz_capture_callback) { + if(furi_hal_subghz.async_mirror_pin != NULL) + furi_hal_gpio_write(furi_hal_subghz.async_mirror_pin, true); + + furi_hal_subghz_capture_callback( + false, TIM2->CNT, (void*)furi_hal_subghz_capture_callback_context); + } + } + TIM2->CNT = 6; } void furi_hal_subghz_start_async_rx(FuriHalSubGhzCaptureCallback callback, void* context) { @@ -617,43 +604,27 @@ void furi_hal_subghz_start_async_rx(FuriHalSubGhzCaptureCallback callback, void* furi_hal_subghz_capture_callback = callback; furi_hal_subghz_capture_callback_context = context; - if(furi_hal_subghz.radio_type == SubGhzRadioExternal) { - furi_hal_gpio_init( - furi_hal_subghz.cc1101_g0_pin, - GpioModeInterruptRiseFall, - GpioPullUp, - GpioSpeedVeryHigh); - furi_hal_gpio_add_int_callback( - furi_hal_subghz.cc1101_g0_pin, - furi_hal_subghz_capture_ISR, - furi_hal_subghz_capture_callback); - furi_hal_gpio_enable_int_callback(furi_hal_subghz.cc1101_g0_pin); - } else { - furi_hal_gpio_init_ex( - &gpio_cc1101_g0, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedLow, GpioAltFn1TIM2); - } - // Timer: base LL_TIM_InitTypeDef TIM_InitStruct = {0}; TIM_InitStruct.Prescaler = 64 - 1; TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP; TIM_InitStruct.Autoreload = 0x7FFFFFFE; - TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV4; // Clock division for capture filter + // Clock division for capture filter (for internal radio) + TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV4; LL_TIM_Init(TIM2, &TIM_InitStruct); // Timer: advanced LL_TIM_SetClockSource(TIM2, LL_TIM_CLOCKSOURCE_INTERNAL); LL_TIM_DisableARRPreload(TIM2); + LL_TIM_DisableDMAReq_TRIG(TIM2); + LL_TIM_DisableIT_TRIG(TIM2); + if(furi_hal_subghz.radio_type == SubGhzRadioInternal) { LL_TIM_SetTriggerInput(TIM2, LL_TIM_TS_TI2FP2); LL_TIM_SetSlaveMode(TIM2, LL_TIM_SLAVEMODE_RESET); LL_TIM_SetTriggerOutput(TIM2, LL_TIM_TRGO_RESET); LL_TIM_EnableMasterSlaveMode(TIM2); - } - LL_TIM_DisableDMAReq_TRIG(TIM2); - LL_TIM_DisableIT_TRIG(TIM2); - if(furi_hal_subghz.radio_type == SubGhzRadioInternal) { // Timer: channel 1 indirect LL_TIM_IC_SetActiveInput(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_ACTIVEINPUT_INDIRECTTI); LL_TIM_IC_SetPrescaler(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_ICPSC_DIV1); @@ -667,13 +638,31 @@ void furi_hal_subghz_start_async_rx(FuriHalSubGhzCaptureCallback callback, void* LL_TIM_IC_SetFilter(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_IC_FILTER_FDIV32_N8); // ISR setup - furi_hal_interrupt_set_isr(FuriHalInterruptIdTIM2, furi_hal_subghz_capture_ISR, NULL); + furi_hal_interrupt_set_isr(FuriHalInterruptIdTIM2, furi_hal_subghz_capture_int_ISR, NULL); // Interrupts and channels LL_TIM_EnableIT_CC1(TIM2); LL_TIM_EnableIT_CC2(TIM2); LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH1); LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH2); + + furi_hal_gpio_init_ex( + furi_hal_subghz.cc1101_g0_pin, + GpioModeAltFunctionPushPull, + GpioPullNo, + GpioSpeedLow, + GpioAltFn1TIM2); + } else { + furi_hal_gpio_init( + furi_hal_subghz.cc1101_g0_pin, + GpioModeInterruptRiseFall, + GpioPullUp, + GpioSpeedVeryHigh); + furi_hal_gpio_add_int_callback( + furi_hal_subghz.cc1101_g0_pin, + furi_hal_subghz_capture_ext_ISR, + furi_hal_subghz_capture_callback); + furi_hal_gpio_enable_int_callback(furi_hal_subghz.cc1101_g0_pin); } // Start timer @@ -706,6 +695,9 @@ void furi_hal_subghz_stop_async_rx() { FURI_CRITICAL_EXIT(); if(furi_hal_subghz.radio_type == SubGhzRadioInternal) { furi_hal_interrupt_set_isr(FuriHalInterruptIdTIM2, NULL, NULL); + } else { + furi_hal_gpio_disable_int_callback(furi_hal_subghz.cc1101_g0_pin); + furi_hal_gpio_remove_int_callback(furi_hal_subghz.cc1101_g0_pin); } furi_hal_gpio_init(furi_hal_subghz.cc1101_g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow); @@ -840,18 +832,19 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void* furi_hal_subghz_async_tx.buffer = malloc(API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * sizeof(uint32_t)); - if(furi_hal_subghz.radio_type == SubGhzRadioExternal) { - furi_hal_gpio_write(furi_hal_subghz.cc1101_g0_pin, true); - furi_hal_gpio_init( - furi_hal_subghz.cc1101_g0_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); - } else { + if(furi_hal_subghz.radio_type == SubGhzRadioInternal) { // Connect CC1101_GD0 to TIM2 as output furi_hal_gpio_init_ex( - &gpio_cc1101_g0, + furi_hal_subghz.cc1101_g0_pin, GpioModeAltFunctionPushPull, GpioPullDown, GpioSpeedLow, GpioAltFn1TIM2); + } else { + //Signal generation with mem-to-mem DMA + furi_hal_gpio_write(furi_hal_subghz.cc1101_g0_pin, true); + furi_hal_gpio_init( + furi_hal_subghz.cc1101_g0_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); } // Configure DMA @@ -912,22 +905,28 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void* LL_TIM_SetCounter(TIM2, 0); LL_TIM_EnableCounter(TIM2); - //Signal generation for external module + // Start debug + if(furi_hal_subghz_start_debug() || furi_hal_subghz.radio_type == SubGhzRadioExternal) { + const GpioPin* gpio = furi_hal_subghz.cc1101_g0_pin; + //Preparing bit mask + //Debug pin is may be only PORTB! (PB0, PB1, .., PB15) + furi_hal_subghz_debug_gpio_buff[0] = 0; + furi_hal_subghz_debug_gpio_buff[1] = 0; - // Start debug (and speaker) - furi_hal_subghz_start_debug(); + //Mirror pin (for example, speaker) + if(furi_hal_subghz.async_mirror_pin != NULL) { + furi_hal_subghz_debug_gpio_buff[0] |= (uint32_t)furi_hal_subghz.async_mirror_pin->pin + << GPIO_NUMBER; + furi_hal_subghz_debug_gpio_buff[1] |= furi_hal_subghz.async_mirror_pin->pin; + gpio = furi_hal_subghz.async_mirror_pin; + } - const GpioPin* gpio = furi_hal_subghz.cc1101_g0_pin; - - if((furi_hal_subghz.async_mirror_pin != NULL) && - (furi_hal_subghz.radio_type == SubGhzRadioInternal)) { - gpio = furi_hal_subghz.async_mirror_pin; - } - if(((furi_hal_subghz.async_mirror_pin != NULL) && - (furi_hal_subghz.radio_type == SubGhzRadioInternal)) || - (furi_hal_subghz.radio_type == SubGhzRadioExternal)) { - furi_hal_subghz_debug_gpio_buff[0] = (uint32_t)gpio->pin << GPIO_NUMBER; - furi_hal_subghz_debug_gpio_buff[1] = gpio->pin; + //G0 singnal generation for external radio + if(furi_hal_subghz.radio_type == SubGhzRadioExternal) { + furi_hal_subghz_debug_gpio_buff[0] |= (uint32_t)furi_hal_subghz.cc1101_g0_pin->pin + << GPIO_NUMBER; + furi_hal_subghz_debug_gpio_buff[1] |= furi_hal_subghz.cc1101_g0_pin->pin; + } dma_config.MemoryOrM2MDstAddress = (uint32_t)furi_hal_subghz_debug_gpio_buff; dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (gpio->port->BSRR); diff --git a/firmware/targets/f7/furi_hal/furi_hal_version.c b/firmware/targets/f7/furi_hal/furi_hal_version.c index 643a30e6e..607560460 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_version.c +++ b/firmware/targets/f7/furi_hal/furi_hal_version.c @@ -271,8 +271,16 @@ FuriHalVersionRegion furi_hal_version_get_hw_region() { return FuriHalVersionRegionUnknown; } +FuriHalVersionRegion furi_hal_version_get_hw_region_otp() { + return furi_hal_version.board_region; +} + const char* furi_hal_version_get_hw_region_name() { - switch(furi_hal_version_get_hw_region()) { + return "R00"; +} + +const char* furi_hal_version_get_hw_region_name_otp() { + switch(furi_hal_version_get_hw_region_otp()) { case FuriHalVersionRegionUnknown: return "R00"; case FuriHalVersionRegionEuRu: diff --git a/firmware/targets/furi_hal_include/furi_hal_version.h b/firmware/targets/furi_hal_include/furi_hal_version.h index 889b29777..b81602029 100644 --- a/firmware/targets/furi_hal_include/furi_hal_version.h +++ b/firmware/targets/furi_hal_include/furi_hal_version.h @@ -122,17 +122,29 @@ FuriHalVersionColor furi_hal_version_get_hw_color(); */ uint8_t furi_hal_version_get_hw_connect(); -/** Get hardware region +/** Get hardware region (fake) = 0 * - * @return Hardware Region + * @return Hardware Region (fake) */ FuriHalVersionRegion furi_hal_version_get_hw_region(); -/** Get hardware region name +/** Get hardware region name (fake) = R00 + * + * @return Hardware Region name (fake) + */ +const char* furi_hal_version_get_hw_region_name(); + +/** Get hardware region (OTP) + * + * @return Hardware Region + */ +FuriHalVersionRegion furi_hal_version_get_hw_region_otp(); + +/** Get hardware region name (OTP) * * @return Hardware Region name */ -const char* furi_hal_version_get_hw_region_name(); +const char* furi_hal_version_get_hw_region_name_otp(); /** Get hardware display id * diff --git a/lib/SConscript b/lib/SConscript index d72ef7700..2de801597 100644 --- a/lib/SConscript +++ b/lib/SConscript @@ -43,6 +43,7 @@ env.Append( "variant", ) ), + File("u8g2/u8g2.h"), ], CPPDEFINES=[ '"M_MEMORY_FULL(x)=abort()"', diff --git a/lib/subghz/protocols/alutech_at_4n.c b/lib/subghz/protocols/alutech_at_4n.c index 7849f7b21..ab2ff0b31 100644 --- a/lib/subghz/protocols/alutech_at_4n.c +++ b/lib/subghz/protocols/alutech_at_4n.c @@ -670,16 +670,15 @@ void subghz_protocol_decoder_alutech_at_4n_get_string(void* context, FuriString* furi_string_cat_printf( output, - "%s %d\r\n" - "Key:0x%08lX%08lX%02X\r\n" + "%s\r\n" + "Key:0x%08lX%08lX\nCRC:%02X %dbit\r\n" "Sn:0x%08lX Btn:0x%01X\r\n" - "Cnt:0x%03lX\r\n", - + "Cnt:0x%04lX\r\n", instance->generic.protocol_name, - instance->generic.data_count_bit, code_found_hi, code_found_lo, (uint8_t)instance->crc, + instance->generic.data_count_bit, instance->generic.serial, instance->generic.btn, instance->generic.cnt); diff --git a/lib/subghz/protocols/alutech_at_4n.h b/lib/subghz/protocols/alutech_at_4n.h index b6d51439b..185d89b06 100644 --- a/lib/subghz/protocols/alutech_at_4n.h +++ b/lib/subghz/protocols/alutech_at_4n.h @@ -1,7 +1,7 @@ #pragma once #include "base.h" -#define SUBGHZ_PROTOCOL_ALUTECH_AT_4N_NAME "Alutech at-4n" +#define SUBGHZ_PROTOCOL_ALUTECH_AT_4N_NAME "Alutech AT-4N" typedef struct SubGhzProtocolDecoderAlutech_at_4n SubGhzProtocolDecoderAlutech_at_4n; typedef struct SubGhzProtocolEncoderAlutech_at_4n SubGhzProtocolEncoderAlutech_at_4n; diff --git a/lib/toolbox/SConscript b/lib/toolbox/SConscript index 9234f1e80..da6c1115c 100644 --- a/lib/toolbox/SConscript +++ b/lib/toolbox/SConscript @@ -21,7 +21,6 @@ env.Append( File("saved_struct.h"), File("version.h"), File("float_tools.h"), - File("value_index.h"), File("tar/tar_archive.h"), File("stream/stream.h"), File("stream/file_stream.h"),