diff --git a/.gitmodules b/.gitmodules index 52cf4a207..e68c05465 100644 --- a/.gitmodules +++ b/.gitmodules @@ -38,3 +38,7 @@ [submodule "lib/stm32wb_copro"] path = lib/stm32wb_copro url = https://github.com/flipperdevices/stm32wb_copro.git +[submodule "subghz_remote"] + path = applications/main/subghz_remote + url = https://github.com/DarkFlippers/SubGHz_Remote + branch = ufw_main_app diff --git a/applications/main/subghz_remote/.gitignore b/applications/main/subghz_remote/.gitignore new file mode 100644 index 000000000..e2a15a10a --- /dev/null +++ b/applications/main/subghz_remote/.gitignore @@ -0,0 +1,4 @@ +dist/* +.vscode +.clang-format +.editorconfig \ No newline at end of file diff --git a/applications/main/subghz_remote/LICENSE b/applications/main/subghz_remote/LICENSE new file mode 100644 index 000000000..6f55e3b0d --- /dev/null +++ b/applications/main/subghz_remote/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 DarkFlippers @gid9798 @xMasterX + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/applications/main/subghz_remote/application.fam b/applications/main/subghz_remote/application.fam index 7d11e153e..34fb390ab 100644 --- a/applications/main/subghz_remote/application.fam +++ b/applications/main/subghz_remote/application.fam @@ -1,17 +1,43 @@ +# App( +# appid="subghz_remote_ofw", +# name="Sub-GHz Remote", +# apptype=FlipperAppType.EXTERNAL, +# entry_point="subghz_remote_app", +# requires=[ +# "gui", +# "dialogs", +# ], +# stack_size=2 * 1024, +# targets=["f7"], +# fap_icon="icon.png", +# fap_author="gid9798 xMasterX", +# fap_description="SubGhz Remote, uses up to 5 .sub files", +# fap_category="Sub-GHz", +# fap_icon_assets="icons", +# fap_icon_assets_symbol="subghz_remote", +# fap_version="1.2", +# fap_weburl="https://github.com/DarkFlippers/SubGHz_Remote", +# ) + App( appid="subghz_remote", name="Sub-GHz Remote", apptype=FlipperAppType.MENUEXTERNAL, entry_point="subghz_remote_app", icon="A_SubGHzRemote_14", + order=11, requires=[ "gui", "dialogs", ], stack_size=2 * 1024, - order=11, - fap_libs=["assets",], + targets=["f7"], fap_icon="icon.png", + fap_author="gid9798 xMasterX", fap_description="SubGhz Remote, uses up to 5 .sub files", fap_category="Sub-GHz", -) \ No newline at end of file + fap_icon_assets="icons", + fap_icon_assets_symbol="subghz_remote", + fap_version="1.2", + fap_weburl="https://github.com/DarkFlippers/SubGHz_Remote", +) diff --git a/applications/main/subghz_remote/catalog/docs/Changelog.md b/applications/main/subghz_remote/catalog/docs/Changelog.md new file mode 100644 index 000000000..31ed245e8 --- /dev/null +++ b/applications/main/subghz_remote/catalog/docs/Changelog.md @@ -0,0 +1,25 @@ +## v1.2 +- **Official FirmWare Support** +- Add warning screen on CustomFW + - The .sub file format may differ from the official one and may be broken + +## v1.1 +- **Was combined with a configuration plugin** + - Editing/Creating map file +- Support for starting arguments + +## v1.0 + +**Initial implementation:** +- Transmission +- GUI +- All .sub files for which transfer is available are supported +- Signal types: + - Static + - Dynamic + - RAW + - BinRAW + +*Custom modulations are not supported yet* + +**Map File Format** - FlipperFormat .txt file \ No newline at end of file diff --git a/applications/main/subghz_remote/catalog/docs/Readme.md b/applications/main/subghz_remote/catalog/docs/Readme.md new file mode 100644 index 000000000..1da170e19 --- /dev/null +++ b/applications/main/subghz_remote/catalog/docs/Readme.md @@ -0,0 +1,24 @@ +With this application, you can combine up to 5 .sub files into one remote, and use flipper as a remote with multiple buttons. +## What is "Map" Files? +"Map" is short for mapping +A Map Files is a .txt files that the application uses to store information about remotes +# How to use +## First screen +After launching the application, you will see the MAP file selection screen (file browser). +- Select map file or press "back" to go Main menu +## Main menu +- Open map file - switching to remote + - Select map file + - On remote screen, use the navigation buttons(D-pad) to send a signal +- Edit Map File - map file editor + - Select map file + - Up/Down - slot nafigation + - Ok - edit menu + - Left - preview/save +- New Map File - Creating a new map file + - Enter a name + - The rest is similar to map file editor +# About map file +Map file - FlipperFormat .txt file. + +Stores custom names, and paths to used .sub files. \ No newline at end of file diff --git a/applications/main/subghz_remote/catalog/screenshots/Editor_main.png b/applications/main/subghz_remote/catalog/screenshots/Editor_main.png new file mode 100644 index 000000000..9498c9451 Binary files /dev/null and b/applications/main/subghz_remote/catalog/screenshots/Editor_main.png differ diff --git a/applications/main/subghz_remote/catalog/screenshots/Editor_submenu.png b/applications/main/subghz_remote/catalog/screenshots/Editor_submenu.png new file mode 100644 index 000000000..f5f7cd849 Binary files /dev/null and b/applications/main/subghz_remote/catalog/screenshots/Editor_submenu.png differ diff --git a/applications/main/subghz_remote/catalog/screenshots/Remote_idle.png b/applications/main/subghz_remote/catalog/screenshots/Remote_idle.png new file mode 100644 index 000000000..eb91fff58 Binary files /dev/null and b/applications/main/subghz_remote/catalog/screenshots/Remote_idle.png differ diff --git a/applications/main/subghz_remote/catalog/screenshots/Remote_send.png b/applications/main/subghz_remote/catalog/screenshots/Remote_send.png new file mode 100644 index 000000000..000cff3b3 Binary files /dev/null and b/applications/main/subghz_remote/catalog/screenshots/Remote_send.png differ diff --git a/applications/main/subghz_remote/helpers/subrem_custom_event.h b/applications/main/subghz_remote/helpers/subrem_custom_event.h index e6b9e8ac6..810df6a89 100644 --- a/applications/main/subghz_remote/helpers/subrem_custom_event.h +++ b/applications/main/subghz_remote/helpers/subrem_custom_event.h @@ -48,4 +48,11 @@ typedef enum { SubRemCustomEventSceneEditPreviewSaved, SubRemCustomEventSceneNewName, + +#ifdef FW_ORIGIN_Official + SubRemCustomEventSceneFwWarningExit, + SubRemCustomEventSceneFwWarningNext, + SubRemCustomEventSceneFwWarningContinue, +#endif + } SubRemCustomEvent; \ No newline at end of file diff --git a/applications/main/subghz_remote/helpers/subrem_presets.c b/applications/main/subghz_remote/helpers/subrem_presets.c index ca91ccbaf..bca888b96 100644 --- a/applications/main/subghz_remote/helpers/subrem_presets.c +++ b/applications/main/subghz_remote/helpers/subrem_presets.c @@ -149,7 +149,9 @@ SubRemLoadSubState subrem_sub_preset_load( if(protocol->flag & SubGhzProtocolFlag_Send) { if((protocol->type == SubGhzProtocolTypeStatic) || (protocol->type == SubGhzProtocolTypeDynamic) || +#ifndef FW_ORIGIN_Official (protocol->type == SubGhzProtocolTypeBinRAW) || +#endif (protocol->type == SubGhzProtocolTypeRAW)) { sub_preset->type = protocol->type; } else { diff --git a/applications/main/subghz_remote/helpers/txrx/subghz_txrx.c b/applications/main/subghz_remote/helpers/txrx/subghz_txrx.c index aa713c7a8..8c8c3b56d 100644 --- a/applications/main/subghz_remote/helpers/txrx/subghz_txrx.c +++ b/applications/main/subghz_remote/helpers/txrx/subghz_txrx.c @@ -1,10 +1,12 @@ #include "subghz_txrx_i.h" -#include +#include #include #include +#ifndef FW_ORIGIN_Official #include +#endif #define TAG "SubGhz" @@ -657,12 +659,14 @@ bool subghz_txrx_get_debug_pin_state(SubGhzTxRx* instance) { return instance->debug_pin_state; } +#ifndef FW_ORIGIN_Official void subghz_txrx_reset_dynamic_and_custom_btns(SubGhzTxRx* instance) { furi_assert(instance); subghz_environment_reset_keeloq(instance->environment); subghz_custom_btns_reset(); } +#endif SubGhzReceiver* subghz_txrx_get_receiver(SubGhzTxRx* instance) { furi_assert(instance); diff --git a/applications/main/subghz_remote/helpers/txrx/subghz_txrx.h b/applications/main/subghz_remote/helpers/txrx/subghz_txrx.h index 4593ea20c..93c4a2276 100644 --- a/applications/main/subghz_remote/helpers/txrx/subghz_txrx.h +++ b/applications/main/subghz_remote/helpers/txrx/subghz_txrx.h @@ -369,7 +369,7 @@ bool subghz_txrx_radio_device_is_tx_allowed(SubGhzTxRx* instance, uint32_t frequ void subghz_txrx_set_debug_pin_state(SubGhzTxRx* instance, bool state); bool subghz_txrx_get_debug_pin_state(SubGhzTxRx* instance); - +#ifndef FW_ORIGIN_Official void subghz_txrx_reset_dynamic_and_custom_btns(SubGhzTxRx* instance); - +#endif SubGhzReceiver* subghz_txrx_get_receiver(SubGhzTxRx* instance); // TODO use only in DecodeRaw diff --git a/applications/main/subghz_remote/icons/DolphinNice_96x59.png b/applications/main/subghz_remote/icons/DolphinNice_96x59.png new file mode 100644 index 000000000..a299d3630 Binary files /dev/null and b/applications/main/subghz_remote/icons/DolphinNice_96x59.png differ diff --git a/applications/main/subghz_remote/icons/remote_scene/ButtonDown_7x4.png b/applications/main/subghz_remote/icons/remote_scene/ButtonDown_7x4.png new file mode 100644 index 000000000..2954bb6a6 Binary files /dev/null and b/applications/main/subghz_remote/icons/remote_scene/ButtonDown_7x4.png differ diff --git a/applications/main/subghz_remote/icons/remote_scene/ButtonLeft_4x7.png b/applications/main/subghz_remote/icons/remote_scene/ButtonLeft_4x7.png new file mode 100644 index 000000000..0b4655d43 Binary files /dev/null and b/applications/main/subghz_remote/icons/remote_scene/ButtonLeft_4x7.png differ diff --git a/applications/main/subghz_remote/icons/remote_scene/ButtonRight_4x7.png b/applications/main/subghz_remote/icons/remote_scene/ButtonRight_4x7.png new file mode 100644 index 000000000..8e1c74c1c Binary files /dev/null and b/applications/main/subghz_remote/icons/remote_scene/ButtonRight_4x7.png differ diff --git a/applications/main/subghz_remote/icons/remote_scene/ButtonUp_7x4.png b/applications/main/subghz_remote/icons/remote_scene/ButtonUp_7x4.png new file mode 100644 index 000000000..1be79328b Binary files /dev/null and b/applications/main/subghz_remote/icons/remote_scene/ButtonUp_7x4.png differ diff --git a/applications/main/subghz_remote/icons/remote_scene/Ok_btn_9x9.png b/applications/main/subghz_remote/icons/remote_scene/Ok_btn_9x9.png new file mode 100644 index 000000000..9a1539da2 Binary files /dev/null and b/applications/main/subghz_remote/icons/remote_scene/Ok_btn_9x9.png differ diff --git a/applications/main/subghz_remote/icons/remote_scene/Pin_arrow_up_7x9.png b/applications/main/subghz_remote/icons/remote_scene/Pin_arrow_up_7x9.png new file mode 100644 index 000000000..a91a6fd5e Binary files /dev/null and b/applications/main/subghz_remote/icons/remote_scene/Pin_arrow_up_7x9.png differ diff --git a/applications/main/subghz_remote/icons/remote_scene/Pin_cell_13x13.png b/applications/main/subghz_remote/icons/remote_scene/Pin_cell_13x13.png new file mode 100644 index 000000000..1b1ff0c2f Binary files /dev/null and b/applications/main/subghz_remote/icons/remote_scene/Pin_cell_13x13.png differ diff --git a/applications/main/subghz_remote/icons/remote_scene/Pin_star_7x7.png b/applications/main/subghz_remote/icons/remote_scene/Pin_star_7x7.png new file mode 100644 index 000000000..42fdea86e Binary files /dev/null and b/applications/main/subghz_remote/icons/remote_scene/Pin_star_7x7.png differ diff --git a/applications/main/subghz_remote/icons/remote_scene/back_10px.png b/applications/main/subghz_remote/icons/remote_scene/back_10px.png new file mode 100644 index 000000000..f9c615a99 Binary files /dev/null and b/applications/main/subghz_remote/icons/remote_scene/back_10px.png differ diff --git a/applications/main/subghz_remote/icons/sub1_10px.png b/applications/main/subghz_remote/icons/sub1_10px.png new file mode 100644 index 000000000..5a25fdf4e Binary files /dev/null and b/applications/main/subghz_remote/icons/sub1_10px.png differ diff --git a/applications/main/subghz_remote/icons/subrem_10px.png b/applications/main/subghz_remote/icons/subrem_10px.png new file mode 100644 index 000000000..c6b410f4c Binary files /dev/null and b/applications/main/subghz_remote/icons/subrem_10px.png differ diff --git a/applications/main/subghz_remote/scenes/subrem_scene_config.h b/applications/main/subghz_remote/scenes/subrem_scene_config.h index 08486be74..56fe641a6 100644 --- a/applications/main/subghz_remote/scenes/subrem_scene_config.h +++ b/applications/main/subghz_remote/scenes/subrem_scene_config.h @@ -6,4 +6,7 @@ ADD_SCENE(subrem, edit_submenu, EditSubMenu) ADD_SCENE(subrem, edit_label, EditLabel) ADD_SCENE(subrem, open_sub_file, OpenSubFile) ADD_SCENE(subrem, edit_preview, EditPreview) -ADD_SCENE(subrem, enter_new_name, EnterNewName) \ No newline at end of file +ADD_SCENE(subrem, enter_new_name, EnterNewName) +#ifdef FW_ORIGIN_Official +ADD_SCENE(subrem, fw_warning, FwWarning) +#endif \ No newline at end of file diff --git a/applications/main/subghz_remote/scenes/subrem_scene_edit_label.c b/applications/main/subghz_remote/scenes/subrem_scene_edit_label.c index baec60145..af4a33c1a 100644 --- a/applications/main/subghz_remote/scenes/subrem_scene_edit_label.c +++ b/applications/main/subghz_remote/scenes/subrem_scene_edit_label.c @@ -53,9 +53,9 @@ void subrem_scene_edit_label_on_enter(void* context) { app->file_name_tmp, 25, false); - +#ifndef FW_ORIGIN_Official text_input_set_minimum_length(app->text_input, 0); - +#endif widget_add_string_element( app->widget, 63, 12, AlignCenter, AlignCenter, FontPrimary, "Empty Label Name"); widget_add_string_element( diff --git a/applications/main/subghz_remote/scenes/subrem_scene_fw_warning.c b/applications/main/subghz_remote/scenes/subrem_scene_fw_warning.c new file mode 100644 index 000000000..de473b72c --- /dev/null +++ b/applications/main/subghz_remote/scenes/subrem_scene_fw_warning.c @@ -0,0 +1,129 @@ +#include "../subghz_remote_app_i.h" +#include "../helpers/subrem_custom_event.h" +#ifdef FW_ORIGIN_Official +typedef enum { + SceneFwWarningStateAttention, + SceneFwWarningStateAccept, +} SceneFwWarningState; + +static void subrem_scene_fw_warning_widget_render(SubGhzRemoteApp* app, SceneFwWarningState state); + +static void + subrem_scene_fw_warning_widget_callback(GuiButtonType result, InputType type, void* context) { + furi_assert(context); + SubGhzRemoteApp* app = context; + + if(type == InputTypeShort) { + SubRemCustomEvent event = SubRemCustomEventSceneFwWarningExit; + + switch(scene_manager_get_scene_state(app->scene_manager, SubRemSceneFwWarning)) { + case SceneFwWarningStateAttention: + if(result == GuiButtonTypeRight) { + event = SubRemCustomEventSceneFwWarningNext; + } + break; + + case SceneFwWarningStateAccept: + if(result == GuiButtonTypeRight) { + event = SubRemCustomEventSceneFwWarningContinue; + } + + break; + } + + view_dispatcher_send_custom_event(app->view_dispatcher, event); + } +} + +static void + subrem_scene_fw_warning_widget_render(SubGhzRemoteApp* app, SceneFwWarningState state) { + furi_assert(app); + Widget* widget = app->widget; + + widget_reset(widget); + + switch(state) { + case SceneFwWarningStateAttention: + widget_add_button_element( + widget, GuiButtonTypeLeft, "Exit", subrem_scene_fw_warning_widget_callback, app); + widget_add_button_element( + widget, GuiButtonTypeRight, "Continue", subrem_scene_fw_warning_widget_callback, app); + widget_add_string_element( + widget, 64, 12, AlignCenter, AlignBottom, FontPrimary, "Not official FW"); + widget_add_string_multiline_element( + widget, + 64, + 32, + AlignCenter, + AlignCenter, + FontSecondary, + "You are using custom firmware\nPlease download a compatible\nversion of the application"); + break; + + case SceneFwWarningStateAccept: + widget_add_button_element( + widget, GuiButtonTypeLeft, "Exit", subrem_scene_fw_warning_widget_callback, app); + widget_add_button_element( + widget, GuiButtonTypeRight, "Accept", subrem_scene_fw_warning_widget_callback, app); + widget_add_string_element( + widget, 64, 12, AlignCenter, AlignBottom, FontPrimary, "Not official FW"); + widget_add_string_multiline_element( + widget, + 64, + 32, + AlignCenter, + AlignCenter, + FontSecondary, + "Yes, I understand that\nthe application can\nbreak my subghz key file"); + break; + } +} + +void subrem_scene_fw_warning_on_enter(void* context) { + furi_assert(context); + + SubGhzRemoteApp* app = context; + + scene_manager_set_scene_state( + app->scene_manager, SubRemSceneFwWarning, SceneFwWarningStateAttention); + + subrem_scene_fw_warning_widget_render(app, SceneFwWarningStateAttention); + + view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDWidget); +} + +bool subrem_scene_fw_warning_on_event(void* context, SceneManagerEvent event) { + furi_assert(context); + + SubGhzRemoteApp* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeBack) { + consumed = true; + } else if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubRemCustomEventSceneFwWarningExit) { + scene_manager_stop(app->scene_manager); + view_dispatcher_stop(app->view_dispatcher); + consumed = true; + } else if(event.event == SubRemCustomEventSceneFwWarningNext) { + scene_manager_set_scene_state( + app->scene_manager, SubRemSceneFwWarning, SceneFwWarningStateAccept); + subrem_scene_fw_warning_widget_render(app, SceneFwWarningStateAccept); + view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDWidget); + consumed = true; + } else if(event.event == SubRemCustomEventSceneFwWarningContinue) { + scene_manager_previous_scene(app->scene_manager); + consumed = true; + } + } + + return consumed; +} + +void subrem_scene_fw_warning_on_exit(void* context) { + furi_assert(context); + + SubGhzRemoteApp* app = context; + widget_reset(app->widget); +} +#endif \ No newline at end of file diff --git a/applications/main/subghz_remote/subghz_remote_app.c b/applications/main/subghz_remote/subghz_remote_app.c index 1af39f57d..473e3c012 100644 --- a/applications/main/subghz_remote/subghz_remote_app.c +++ b/applications/main/subghz_remote/subghz_remote_app.c @@ -1,4 +1,5 @@ #include "subghz_remote_app_i.h" +#include static bool subghz_remote_app_custom_event_callback(void* context, uint32_t event) { furi_assert(context); @@ -174,7 +175,9 @@ int32_t subghz_remote_app(void* arg) { subghz_remote_make_app_folder(subghz_remote_app); bool map_loaded = false; - +#ifdef FW_ORIGIN_Official + const bool fw_ofw = strcmp(version_get_firmware_origin(version_get()), "Official") == 0; +#endif if((arg != NULL) && (strlen(arg) != 0)) { furi_string_set(subghz_remote_app->file_path, (const char*)arg); SubRemLoadMapState load_state = subrem_map_file_load( @@ -193,8 +196,19 @@ int32_t subghz_remote_app(void* arg) { } else { furi_string_set(subghz_remote_app->file_path, SUBREM_APP_FOLDER); scene_manager_next_scene(subghz_remote_app->scene_manager, SubRemSceneStart); +#ifdef FW_ORIGIN_Official + if(fw_ofw) { + scene_manager_next_scene(subghz_remote_app->scene_manager, SubRemSceneOpenMapFile); + } + } + + if(!fw_ofw) { + scene_manager_next_scene(subghz_remote_app->scene_manager, SubRemSceneFwWarning); + } +#else scene_manager_next_scene(subghz_remote_app->scene_manager, SubRemSceneOpenMapFile); } +#endif view_dispatcher_run(subghz_remote_app->view_dispatcher); diff --git a/applications/main/subghz_remote/subghz_remote_app_i.c b/applications/main/subghz_remote/subghz_remote_app_i.c index 82e762c2a..ca54a997b 100644 --- a/applications/main/subghz_remote/subghz_remote_app_i.c +++ b/applications/main/subghz_remote/subghz_remote_app_i.c @@ -3,12 +3,9 @@ #include #include "helpers/txrx/subghz_txrx.h" - -// #include -// #include - -#include +#ifndef FW_ORIGIN_Official #include +#endif #define TAG "SubGhzRemote" @@ -225,9 +222,9 @@ bool subrem_tx_start_sub(SubGhzRemoteApp* app, SubRemSubFilePreset* sub_preset) sub_preset->freq_preset.frequency, NULL, 0); - +#ifndef FW_ORIGIN_Official subghz_custom_btns_reset(); - +#endif if(subghz_txrx_tx_start(app->txrx, sub_preset->fff_data) == SubGhzTxRxStartTxStateOk) { ret = true; } @@ -242,12 +239,12 @@ bool subrem_tx_stop_sub(SubGhzRemoteApp* app, bool forced) { if(forced || (sub_preset->type != SubGhzProtocolTypeRAW)) { subghz_txrx_stop(app->txrx); - +#ifndef FW_ORIGIN_Official if(sub_preset->type == SubGhzProtocolTypeDynamic) { subghz_txrx_reset_dynamic_and_custom_btns(app->txrx); } subghz_custom_btns_reset(); - +#endif return true; } diff --git a/applications/main/subghz_remote/subghz_remote_app_i.h b/applications/main/subghz_remote/subghz_remote_app_i.h index d200bdf96..2300b3e52 100644 --- a/applications/main/subghz_remote/subghz_remote_app_i.h +++ b/applications/main/subghz_remote/subghz_remote_app_i.h @@ -6,7 +6,7 @@ #include "helpers/txrx/subghz_txrx.h" -#include +#include "subghz_remote_icons.h" #include "views/remote.h" #include "views/edit_menu.h"