diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7d6162954..ed5ee6bd7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -127,7 +127,7 @@ jobs: **Compiled firmware for commit `${{steps.names.outputs.commit_sha}}`:** - [📦 Update package](https://update.flipperzero.one/builds/firmware/${{steps.names.outputs.branch_name}}/flipper-z-${{steps.names.outputs.default_target}}-update-${{steps.names.outputs.suffix}}.tgz) - [📥 DFU file](https://update.flipperzero.one/builds/firmware/${{steps.names.outputs.branch_name}}/flipper-z-${{steps.names.outputs.default_target}}-full-${{steps.names.outputs.suffix}}.dfu) - - [☁️ Web/App updater](https://my.flipp.dev/?url=https://update.flipperzero.one/builds/firmware/${{steps.names.outputs.branch_name}}/flipper-z-${{steps.names.outputs.default_target}}-update-${{steps.names.outputs.suffix}}.tgz&channel=${{steps.names.outputs.branch_name}}&version=${{steps.names.outputs.commit_sha}}) + - [☁️ Web/App updater](https://lab.flipper.net/?url=https://update.flipperzero.one/builds/firmware/${{steps.names.outputs.branch_name}}/flipper-z-${{steps.names.outputs.default_target}}-update-${{steps.names.outputs.suffix}}.tgz&channel=${{steps.names.outputs.branch_name}}&version=${{steps.names.outputs.commit_sha}}) edit-mode: replace compact: diff --git a/.github/workflows/pvs_studio.yml b/.github/workflows/pvs_studio.yml index e3d5fc132..f28fad20d 100644 --- a/.github/workflows/pvs_studio.yml +++ b/.github/workflows/pvs_studio.yml @@ -65,7 +65,6 @@ jobs: pvs-studio-analyzer credentials ${{ secrets.PVS_STUDIO_CREDENTIALS }} pvs-studio-analyzer analyze \ @.pvsoptions \ - --disableLicenseExpirationCheck \ -j$(grep -c processor /proc/cpuinfo) \ -f build/f7-firmware-DC/compile_commands.json \ -o PVS-Studio.log diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml new file mode 100644 index 000000000..b5bf10004 --- /dev/null +++ b/.github/workflows/unit_tests.yml @@ -0,0 +1,52 @@ +name: 'Unit tests' + +on: + pull_request: + +env: + TARGETS: f7 + DEFAULT_TARGET: f7 + +jobs: + main: + runs-on: [self-hosted, FlipperZeroTest] + steps: + - name: Checkout code + uses: actions/checkout@v2 + with: + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha }} + + - name: 'Get flipper from device manager (mock)' + id: device + run: | + echo "flipper=/dev/ttyACM0" >> $GITHUB_OUTPUT + + - name: 'Compile unit tests firmware' + id: compile + run: | + FBT_TOOLCHAIN_PATH=/opt ./fbt flash OPENOCD_ADAPTER_SERIAL=2A0906016415303030303032 FIRMWARE_APP_SET=unit_tests FORCE=1 + + - name: 'Wait for flipper to finish updating' + id: connect + if: steps.compile.outcome == 'success' + run: | + python3 ./scripts/testing/await_flipper.py ${{steps.device.outputs.flipper}} + + - name: 'Format flipper SD card' + id: format + if: steps.connect.outcome == 'success' + run: | + ./scripts/storage.py -p ${{steps.device.outputs.flipper}} format_ext + + - name: 'Copy assets and unit tests data to flipper' + id: copy + if: steps.format.outcome == 'success' + run: | + ./scripts/storage.py -p ${{steps.device.outputs.flipper}} send assets/resources /ext + ./scripts/storage.py -p ${{steps.device.outputs.flipper}} send assets/unit_tests /ext/unit_tests + + - name: 'Run units and validate results' + if: steps.copy.outcome == 'success' + run: | + python3 ./scripts/testing/units.py ${{steps.device.outputs.flipper}} diff --git a/.gitmodules b/.gitmodules index 308d60fdc..a97e0933a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -22,9 +22,6 @@ [submodule "lib/microtar"] path = lib/microtar url = https://github.com/amachronic/microtar.git -[submodule "lib/scons"] - path = lib/scons - url = https://github.com/SCons/scons.git [submodule "lib/mbedtls"] path = lib/mbedtls url = https://github.com/Mbed-TLS/mbedtls.git diff --git a/.vscode/example/c_cpp_properties.json b/.vscode/example/c_cpp_properties.json index db08320c9..d1cac63e9 100644 --- a/.vscode/example/c_cpp_properties.json +++ b/.vscode/example/c_cpp_properties.json @@ -2,7 +2,7 @@ "configurations": [ { "name": "Win32", - "compilerPath": "${workspaceFolder}/toolchain/i686-windows/bin/arm-none-eabi-gcc.exe", + "compilerPath": "${workspaceFolder}/toolchain/x86_64-windows/bin/arm-none-eabi-gcc.exe", "intelliSenseMode": "gcc-arm", "compileCommands": "${workspaceFolder}/build/latest/compile_commands.json", "configurationProvider": "ms-vscode.cpptools", diff --git a/.vscode/example/launch.json b/.vscode/example/launch.json index f4df96592..c8b0c601d 100644 --- a/.vscode/example/launch.json +++ b/.vscode/example/launch.json @@ -79,6 +79,25 @@ ] // "showDevDebugOutput": "raw", }, + { + "name": "Attach FW (DAP)", + "cwd": "${workspaceFolder}", + "executable": "./build/latest/firmware.elf", + "request": "attach", + "type": "cortex-debug", + "servertype": "openocd", + "device": "cmsis-dap", + "svdFile": "./debug/STM32WB55_CM4.svd", + "rtos": "FreeRTOS", + "configFiles": [ + "interface/cmsis-dap.cfg", + "./debug/stm32wbx.cfg", + ], + "postAttachCommands": [ + "source debug/flipperapps.py", + ], + // "showDevDebugOutput": "raw", + }, { "name": "fbt debug", "type": "python", diff --git a/.vscode/example/settings.json b/.vscode/example/settings.json index d84707e07..19a03b69d 100644 --- a/.vscode/example/settings.json +++ b/.vscode/example/settings.json @@ -6,13 +6,13 @@ "cortex-debug.enableTelemetry": false, "cortex-debug.variableUseNaturalFormat": true, "cortex-debug.showRTOS": true, - "cortex-debug.armToolchainPath.windows": "${workspaceFolder}/toolchain/i686-windows/bin", + "cortex-debug.armToolchainPath.windows": "${workspaceFolder}/toolchain/x86_64-windows/bin", "cortex-debug.armToolchainPath.linux": "${workspaceFolder}/toolchain/x86_64-linux/bin", "cortex-debug.armToolchainPath.osx": "${workspaceFolder}/toolchain/x86_64-darwin/bin", - "cortex-debug.openocdPath.windows": "${workspaceFolder}/toolchain/i686-windows/openocd/bin/openocd.exe", + "cortex-debug.openocdPath.windows": "${workspaceFolder}/toolchain/x86_64-windows/openocd/bin/openocd.exe", "cortex-debug.openocdPath.linux": "${workspaceFolder}/toolchain/x86_64-linux/openocd/bin/openocd", "cortex-debug.openocdPath.osx": "${workspaceFolder}/toolchain/x86_64-darwin/openocd/bin/openocd", - "cortex-debug.gdbPath.windows": "${workspaceFolder}/toolchain/i686-windows/bin/arm-none-eabi-gdb-py.bat", + "cortex-debug.gdbPath.windows": "${workspaceFolder}/toolchain/x86_64-windows/bin/arm-none-eabi-gdb-py.bat", "cortex-debug.gdbPath.linux": "${workspaceFolder}/toolchain/x86_64-linux/bin/arm-none-eabi-gdb-py", "cortex-debug.gdbPath.osx": "${workspaceFolder}/toolchain/x86_64-darwin/bin/arm-none-eabi-gdb-py", "editor.formatOnSave": true, diff --git a/.vscode/example/tasks.json b/.vscode/example/tasks.json index 3946d05cc..9baaf97b4 100644 --- a/.vscode/example/tasks.json +++ b/.vscode/example/tasks.json @@ -109,13 +109,13 @@ "label": "[Debug] Build FAPs", "group": "build", "type": "shell", - "command": "./fbt plugin_dist" + "command": "./fbt fap_dist" }, { "label": "[Release] Build FAPs", "group": "build", "type": "shell", - "command": "./fbt COMPACT=1 DEBUG=0 plugin_dist" + "command": "./fbt COMPACT=1 DEBUG=0 fap_dist" }, { "label": "[Debug] Launch App on Flipper", diff --git a/SConstruct b/SConstruct index 74fa5667b..448df9715 100644 --- a/SConstruct +++ b/SConstruct @@ -156,11 +156,9 @@ Depends(fap_dist, firmware_env["FW_EXTAPPS"]["validators"].values()) Alias("fap_dist", fap_dist) # distenv.Default(fap_dist) -plugin_resources_dist = list( - distenv.Install(f"#/assets/resources/apps/{dist_entry[0]}", dist_entry[1]) - for dist_entry in firmware_env["FW_EXTAPPS"]["dist"].values() +distenv.Depends( + firmware_env["FW_RESOURCES"], firmware_env["FW_EXTAPPS"]["resources_dist"] ) -distenv.Depends(firmware_env["FW_RESOURCES"], plugin_resources_dist) # Target for bundling core2 package for qFlipper @@ -291,6 +289,16 @@ distenv.PhonyTarget( "@echo $( ${BLACKMAGIC_ADDR} $)", ) + +# Find STLink probe ids +distenv.PhonyTarget( + "get_stlink", + distenv.Action( + lambda **kw: distenv.GetDevices(), + None, + ), +) + # Prepare vscode environment vscode_dist = distenv.Install("#.vscode", distenv.Glob("#.vscode/example/*")) distenv.Precious(vscode_dist) diff --git a/applications/debug/file_browser_test/application.fam b/applications/debug/file_browser_test/application.fam index 5e4c7f467..4a401a649 100644 --- a/applications/debug/file_browser_test/application.fam +++ b/applications/debug/file_browser_test/application.fam @@ -8,4 +8,5 @@ App( stack_size=2 * 1024, order=150, fap_category="Debug", + fap_icon_assets="icons", ) diff --git a/applications/debug/file_browser_test/file_browser_app.c b/applications/debug/file_browser_test/file_browser_app.c index 5c7b93bcb..6cb50d385 100644 --- a/applications/debug/file_browser_test/file_browser_app.c +++ b/applications/debug/file_browser_test/file_browser_app.c @@ -1,4 +1,4 @@ -#include "assets_icons.h" +#include #include "file_browser_app_i.h" #include "gui/modules/file_browser.h" #include diff --git a/applications/debug/file_browser_test/icons/badusb_10px.png b/applications/debug/file_browser_test/icons/badusb_10px.png new file mode 100644 index 000000000..037474aa3 Binary files /dev/null and b/applications/debug/file_browser_test/icons/badusb_10px.png differ diff --git a/applications/debug/unit_tests/subghz/subghz_test.c b/applications/debug/unit_tests/subghz/subghz_test.c index 2dbf2eeda..dbe03d88c 100644 --- a/applications/debug/unit_tests/subghz/subghz_test.c +++ b/applications/debug/unit_tests/subghz/subghz_test.c @@ -13,7 +13,7 @@ #define CAME_ATOMO_DIR_NAME EXT_PATH("subghz/assets/came_atomo") #define NICE_FLOR_S_DIR_NAME EXT_PATH("subghz/assets/nice_flor_s") #define TEST_RANDOM_DIR_NAME EXT_PATH("unit_tests/subghz/test_random_raw.sub") -#define TEST_RANDOM_COUNT_PARSE 233 +#define TEST_RANDOM_COUNT_PARSE 232 #define TEST_TIMEOUT 10000 static SubGhzEnvironment* environment_handler; @@ -437,13 +437,6 @@ MU_TEST(subghz_decoder_clemsa_test) { "Test decoder " SUBGHZ_PROTOCOL_CLEMSA_NAME " error\r\n"); } -MU_TEST(subghz_decoder_oregon2_test) { - mu_assert( - subghz_decoder_test( - EXT_PATH("unit_tests/subghz/oregon2_raw.sub"), SUBGHZ_PROTOCOL_OREGON2_NAME), - "Test decoder " SUBGHZ_PROTOCOL_OREGON2_NAME " error\r\n"); -} - //test encoders MU_TEST(subghz_encoder_princeton_test) { mu_assert( @@ -605,7 +598,6 @@ MU_TEST_SUITE(subghz) { MU_RUN_TEST(subghz_decoder_magellan_test); MU_RUN_TEST(subghz_decoder_intertechno_v3_test); MU_RUN_TEST(subghz_decoder_clemsa_test); - MU_RUN_TEST(subghz_decoder_oregon2_test); MU_RUN_TEST(subghz_encoder_princeton_test); MU_RUN_TEST(subghz_encoder_came_test); diff --git a/applications/examples/example_images/ReadMe.md b/applications/examples/example_images/ReadMe.md new file mode 100644 index 000000000..d884a0a97 --- /dev/null +++ b/applications/examples/example_images/ReadMe.md @@ -0,0 +1,24 @@ +# Application icons +To use icons, do the following: +* add a line to the application manifest: `fap_icon_assets="folder"`, where `folder` points to the folder where your icons are located +* add `#include "application_id_icons.h"` to the application code, where `application_id` is the appid from the manifest +* every icon in the folder will be available as a `I_icon_name` variable, where `icon_name` is the name of the icon file without the extension + +## Example +We have an application with the following manifest: +``` +App( + appid="example_images", + ... + fap_icon_assets="images", +) +``` + +So the icons are in the `images` folder and will be available in the generated `example_images_icons.h` file. + +The example code is located in `example_images_main.c` and contains the following line: +``` +#include "example_images_icons.h" +``` + +Image `dolphin_71x25.png` is available as `I_dolphin_71x25`. diff --git a/applications/main/bad_usb/bad_usb_app_i.h b/applications/main/bad_usb/bad_usb_app_i.h index 85fd56ff0..f333c36d8 100644 --- a/applications/main/bad_usb/bad_usb_app_i.h +++ b/applications/main/bad_usb/bad_usb_app_i.h @@ -5,6 +5,7 @@ #include "bad_usb_script.h" #include +#include #include #include #include diff --git a/applications/main/bad_usb/views/bad_usb_view.c b/applications/main/bad_usb/views/bad_usb_view.c index 6c6a15847..e5c5d92a3 100644 --- a/applications/main/bad_usb/views/bad_usb_view.c +++ b/applications/main/bad_usb/views/bad_usb_view.c @@ -1,6 +1,7 @@ #include "bad_usb_view.h" #include "../bad_usb_script.h" #include +#include #define MAX_NAME_LEN 64 diff --git a/applications/main/fap_loader/fap_loader_app.c b/applications/main/fap_loader/fap_loader_app.c index faf8eefc8..9b4c92335 100644 --- a/applications/main/fap_loader/fap_loader_app.c +++ b/applications/main/fap_loader/fap_loader_app.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include diff --git a/applications/main/gpio/gpio_app_i.h b/applications/main/gpio/gpio_app_i.h index fff35c95a..85c5c332e 100644 --- a/applications/main/gpio/gpio_app_i.h +++ b/applications/main/gpio/gpio_app_i.h @@ -15,6 +15,7 @@ #include #include "views/gpio_test.h" #include "views/gpio_usb_uart.h" +#include struct GpioApp { Gui* gui; diff --git a/applications/main/ibutton/ibutton.c b/applications/main/ibutton/ibutton.c index 887fb3e75..b6d8361b3 100644 --- a/applications/main/ibutton/ibutton.c +++ b/applications/main/ibutton/ibutton.c @@ -5,6 +5,7 @@ #include #include #include +#include #define TAG "iButtonApp" @@ -337,11 +338,13 @@ int32_t ibutton_app(void* p) { view_dispatcher_attach_to_gui( ibutton->view_dispatcher, ibutton->gui, ViewDispatcherTypeDesktop); scene_manager_next_scene(ibutton->scene_manager, iButtonSceneRpc); + DOLPHIN_DEED(DolphinDeedIbuttonEmulate); } else { view_dispatcher_attach_to_gui( ibutton->view_dispatcher, ibutton->gui, ViewDispatcherTypeFullscreen); if(key_loaded) { scene_manager_next_scene(ibutton->scene_manager, iButtonSceneEmulate); + DOLPHIN_DEED(DolphinDeedIbuttonEmulate); } else { scene_manager_next_scene(ibutton->scene_manager, iButtonSceneStart); } diff --git a/applications/main/ibutton/ibutton_i.h b/applications/main/ibutton/ibutton_i.h index a9515195e..0a8099351 100644 --- a/applications/main/ibutton/ibutton_i.h +++ b/applications/main/ibutton/ibutton_i.h @@ -4,6 +4,7 @@ #include #include +#include #include #include #include diff --git a/applications/main/ibutton/scenes/ibutton_scene_add_value.c b/applications/main/ibutton/scenes/ibutton_scene_add_value.c index b3ec11a50..ccac76121 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_add_value.c +++ b/applications/main/ibutton/scenes/ibutton_scene_add_value.c @@ -1,7 +1,5 @@ #include "../ibutton_i.h" -#include - void ibutton_scene_add_type_byte_input_callback(void* context) { iButton* ibutton = context; view_dispatcher_send_custom_event(ibutton->view_dispatcher, iButtonCustomEventByteEditResult); @@ -38,7 +36,6 @@ bool ibutton_scene_add_value_on_event(void* context, SceneManagerEvent event) { consumed = true; if(event.event == iButtonCustomEventByteEditResult) { ibutton_key_set_data(ibutton->key, new_key_data, IBUTTON_KEY_DATA_SIZE); - DOLPHIN_DEED(DolphinDeedIbuttonAdd); scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSaveName); } } diff --git a/applications/main/ibutton/scenes/ibutton_scene_emulate.c b/applications/main/ibutton/scenes/ibutton_scene_emulate.c index b3bc38ead..6f6ffcf57 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_emulate.c +++ b/applications/main/ibutton/scenes/ibutton_scene_emulate.c @@ -1,6 +1,5 @@ #include "../ibutton_i.h" #include -#include #include #define EMULATE_TIMEOUT_TICKS 10 @@ -26,8 +25,6 @@ void ibutton_scene_emulate_on_enter(void* context) { path_extract_filename(ibutton->file_path, key_name, true); } - DOLPHIN_DEED(DolphinDeedIbuttonEmulate); - // check that stored key has name if(!furi_string_empty(key_name)) { ibutton_text_store_set(ibutton, "%s", furi_string_get_cstr(key_name)); diff --git a/applications/main/ibutton/scenes/ibutton_scene_read.c b/applications/main/ibutton/scenes/ibutton_scene_read.c index 05920a0ad..1fe75e45a 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_read.c +++ b/applications/main/ibutton/scenes/ibutton_scene_read.c @@ -11,7 +11,6 @@ void ibutton_scene_read_on_enter(void* context) { Popup* popup = ibutton->popup; iButtonKey* key = ibutton->key; iButtonWorker* worker = ibutton->key_worker; - DOLPHIN_DEED(DolphinDeedIbuttonRead); popup_set_header(popup, "iButton", 95, 26, AlignCenter, AlignBottom); popup_set_text(popup, "Waiting\nfor key ...", 95, 30, AlignCenter, AlignTop); @@ -54,8 +53,8 @@ bool ibutton_scene_read_on_event(void* context, SceneManagerEvent event) { if(success) { ibutton_notification_message(ibutton, iButtonNotificationMessageSuccess); ibutton_notification_message(ibutton, iButtonNotificationMessageGreenOn); - DOLPHIN_DEED(DolphinDeedIbuttonReadSuccess); scene_manager_next_scene(scene_manager, iButtonSceneReadSuccess); + DOLPHIN_DEED(DolphinDeedIbuttonReadSuccess); } } } diff --git a/applications/main/ibutton/scenes/ibutton_scene_read_key_menu.c b/applications/main/ibutton/scenes/ibutton_scene_read_key_menu.c index 921b24fc1..0a8ecfa55 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_read_key_menu.c +++ b/applications/main/ibutton/scenes/ibutton_scene_read_key_menu.c @@ -1,4 +1,5 @@ #include "../ibutton_i.h" +#include typedef enum { SubmenuIndexSave, @@ -49,6 +50,7 @@ bool ibutton_scene_read_key_menu_on_event(void* context, SceneManagerEvent event scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSaveName); } else if(event.event == SubmenuIndexEmulate) { scene_manager_next_scene(ibutton->scene_manager, iButtonSceneEmulate); + DOLPHIN_DEED(DolphinDeedIbuttonEmulate); } else if(event.event == SubmenuIndexWrite) { scene_manager_next_scene(ibutton->scene_manager, iButtonSceneWrite); } diff --git a/applications/main/ibutton/scenes/ibutton_scene_save_name.c b/applications/main/ibutton/scenes/ibutton_scene_save_name.c index 773b93e0c..5f25a0002 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_save_name.c +++ b/applications/main/ibutton/scenes/ibutton_scene_save_name.c @@ -1,6 +1,7 @@ #include "../ibutton_i.h" #include #include +#include static void ibutton_scene_save_name_text_input_callback(void* context) { iButton* ibutton = context; @@ -57,6 +58,15 @@ bool ibutton_scene_save_name_on_event(void* context, SceneManagerEvent event) { if(event.event == iButtonCustomEventTextEditResult) { if(ibutton_save_key(ibutton, ibutton->text_store)) { scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSaveSuccess); + if(scene_manager_has_previous_scene( + ibutton->scene_manager, iButtonSceneSavedKeyMenu)) { + // Nothing, do not count editing as saving + } else if(scene_manager_has_previous_scene( + ibutton->scene_manager, iButtonSceneAddType)) { + DOLPHIN_DEED(DolphinDeedIbuttonAdd); + } else { + DOLPHIN_DEED(DolphinDeedIbuttonSave); + } } else { const uint32_t possible_scenes[] = { iButtonSceneReadKeyMenu, iButtonSceneSavedKeyMenu, iButtonSceneAddType}; diff --git a/applications/main/ibutton/scenes/ibutton_scene_save_success.c b/applications/main/ibutton/scenes/ibutton_scene_save_success.c index 43237f429..e0b9b3c47 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_save_success.c +++ b/applications/main/ibutton/scenes/ibutton_scene_save_success.c @@ -1,5 +1,4 @@ #include "../ibutton_i.h" -#include static void ibutton_scene_save_success_popup_callback(void* context) { iButton* ibutton = context; @@ -9,7 +8,6 @@ static void ibutton_scene_save_success_popup_callback(void* context) { void ibutton_scene_save_success_on_enter(void* context) { iButton* ibutton = context; Popup* popup = ibutton->popup; - DOLPHIN_DEED(DolphinDeedIbuttonSave); popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); popup_set_header(popup, "Saved!", 5, 7, AlignLeft, AlignTop); diff --git a/applications/main/ibutton/scenes/ibutton_scene_saved_key_menu.c b/applications/main/ibutton/scenes/ibutton_scene_saved_key_menu.c index 3d588dd02..e4c9c350a 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_saved_key_menu.c +++ b/applications/main/ibutton/scenes/ibutton_scene_saved_key_menu.c @@ -1,4 +1,5 @@ #include "../ibutton_i.h" +#include enum SubmenuIndex { SubmenuIndexEmulate, @@ -58,6 +59,7 @@ bool ibutton_scene_saved_key_menu_on_event(void* context, SceneManagerEvent even consumed = true; if(event.event == SubmenuIndexEmulate) { scene_manager_next_scene(ibutton->scene_manager, iButtonSceneEmulate); + DOLPHIN_DEED(DolphinDeedIbuttonEmulate); } else if(event.event == SubmenuIndexWrite) { scene_manager_next_scene(ibutton->scene_manager, iButtonSceneWrite); } else if(event.event == SubmenuIndexEdit) { diff --git a/applications/main/ibutton/scenes/ibutton_scene_start.c b/applications/main/ibutton/scenes/ibutton_scene_start.c index dde224e15..b8f6b07d6 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_start.c +++ b/applications/main/ibutton/scenes/ibutton_scene_start.c @@ -1,5 +1,6 @@ #include "../ibutton_i.h" #include "ibutton/scenes/ibutton_scene.h" +#include enum SubmenuIndex { SubmenuIndexRead, @@ -38,6 +39,7 @@ bool ibutton_scene_start_on_event(void* context, SceneManagerEvent event) { consumed = true; if(event.event == SubmenuIndexRead) { scene_manager_next_scene(ibutton->scene_manager, iButtonSceneRead); + DOLPHIN_DEED(DolphinDeedIbuttonRead); } else if(event.event == SubmenuIndexSaved) { furi_string_set(ibutton->file_path, IBUTTON_APP_FOLDER); scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSelectKey); diff --git a/applications/main/infrared/infrared_cli.c b/applications/main/infrared/infrared_cli.c index 5a04f7495..8f35a8fd1 100644 --- a/applications/main/infrared/infrared_cli.c +++ b/applications/main/infrared/infrared_cli.c @@ -5,25 +5,21 @@ #include #include #include +#include #include "infrared_signal.h" #include "infrared_brute_force.h" -#include - #define INFRARED_CLI_BUF_SIZE 10 +#define INFRARED_ASSETS_FOLDER "infrared/assets" +#define INFRARED_BRUTE_FORCE_DUMMY_INDEX 0 DICT_DEF2(dict_signals, FuriString*, FURI_STRING_OPLIST, int, M_DEFAULT_OPLIST) -enum RemoteTypes { TV = 0, AC = 1 }; - static void infrared_cli_start_ir_rx(Cli* cli, FuriString* args); static void infrared_cli_start_ir_tx(Cli* cli, FuriString* args); static void infrared_cli_process_decode(Cli* cli, FuriString* args); static void infrared_cli_process_universal(Cli* cli, FuriString* args); -static void infrared_cli_list_remote_signals(enum RemoteTypes remote_type); -static void - infrared_cli_brute_force_signals(Cli* cli, enum RemoteTypes remote_type, FuriString* signal); static const struct { const char* cmd; @@ -87,8 +83,10 @@ static void infrared_cli_print_usage(void) { INFRARED_MIN_FREQUENCY, INFRARED_MAX_FREQUENCY); printf("\tir decode []\r\n"); - printf("\tir universal \r\n"); - printf("\tir universal list \r\n"); + printf("\tir universal \r\n"); + printf("\tir universal list \r\n"); + // TODO: Do not hardcode universal remote names + printf("\tAvailable universal remotes: tv audio ac\r\n"); } static void infrared_cli_start_ir_rx(Cli* cli, FuriString* args) { @@ -356,89 +354,31 @@ static void infrared_cli_process_decode(Cli* cli, FuriString* args) { furi_record_close(RECORD_STORAGE); } -static void infrared_cli_process_universal(Cli* cli, FuriString* args) { - enum RemoteTypes Remote; - - FuriString* command; - FuriString* remote; - FuriString* signal; - command = furi_string_alloc(); - remote = furi_string_alloc(); - signal = furi_string_alloc(); - - do { - if(!args_read_string_and_trim(args, command)) { - infrared_cli_print_usage(); - break; - } - - if(furi_string_cmp_str(command, "list") == 0) { - args_read_string_and_trim(args, remote); - if(furi_string_cmp_str(remote, "tv") == 0) { - Remote = TV; - } else if(furi_string_cmp_str(remote, "ac") == 0) { - Remote = AC; - } else { - printf("Invalid remote type.\r\n"); - break; - } - infrared_cli_list_remote_signals(Remote); - break; - } - - if(furi_string_cmp_str(command, "tv") == 0) { - Remote = TV; - } else if(furi_string_cmp_str(command, "ac") == 0) { - Remote = AC; - } else { - printf("Invalid remote type.\r\n"); - break; - } - - args_read_string_and_trim(args, signal); - if(furi_string_empty(signal)) { - printf("Must supply a valid signal for type of remote selected.\r\n"); - break; - } - - infrared_cli_brute_force_signals(cli, Remote, signal); - break; - - } while(false); - - furi_string_free(command); - furi_string_free(remote); - furi_string_free(signal); -} - -static void infrared_cli_list_remote_signals(enum RemoteTypes remote_type) { - Storage* storage = furi_record_open(RECORD_STORAGE); - FlipperFormat* ff = flipper_format_buffered_file_alloc(storage); - dict_signals_t signals_dict; - FuriString* key; - const char* remote_file = NULL; - bool success = false; - int max = 1; - - switch(remote_type) { - case TV: - remote_file = EXT_PATH("infrared/assets/tv.ir"); - break; - case AC: - remote_file = EXT_PATH("infrared/assets/ac.ir"); - break; - default: - break; +static void infrared_cli_list_remote_signals(FuriString* remote_name) { + if(furi_string_empty(remote_name)) { + printf("Missing remote name.\r\n"); + return; } - dict_signals_init(signals_dict); - key = furi_string_alloc(); + Storage* storage = furi_record_open(RECORD_STORAGE); + FlipperFormat* ff = flipper_format_buffered_file_alloc(storage); + FuriString* remote_path = furi_string_alloc_printf( + "%s/%s.ir", EXT_PATH(INFRARED_ASSETS_FOLDER), furi_string_get_cstr(remote_name)); + + do { + if(!flipper_format_buffered_file_open_existing(ff, furi_string_get_cstr(remote_path))) { + printf("Invalid remote name.\r\n"); + break; + } + + dict_signals_t signals_dict; + dict_signals_init(signals_dict); + + FuriString* key = furi_string_alloc(); + FuriString* signal_name = furi_string_alloc(); - success = flipper_format_buffered_file_open_existing(ff, remote_file); - if(success) { - FuriString* signal_name; - signal_name = furi_string_alloc(); printf("Valid signals:\r\n"); + int max = 1; while(flipper_format_read_string(ff, "name", signal_name)) { furi_string_set_str(key, furi_string_get_cstr(signal_name)); int* v = dict_signals_get(signals_dict, key); @@ -449,57 +389,57 @@ static void infrared_cli_list_remote_signals(enum RemoteTypes remote_type) { dict_signals_set_at(signals_dict, key, 1); } } + dict_signals_it_t it; for(dict_signals_it(it, signals_dict); !dict_signals_end_p(it); dict_signals_next(it)) { const struct dict_signals_pair_s* pair = dict_signals_cref(it); printf("\t%s\r\n", furi_string_get_cstr(pair->key)); } - furi_string_free(signal_name); - } - furi_string_free(key); - dict_signals_clear(signals_dict); + furi_string_free(key); + furi_string_free(signal_name); + dict_signals_clear(signals_dict); + + } while(false); + flipper_format_free(ff); + furi_string_free(remote_path); furi_record_close(RECORD_STORAGE); } static void - infrared_cli_brute_force_signals(Cli* cli, enum RemoteTypes remote_type, FuriString* signal) { + infrared_cli_brute_force_signals(Cli* cli, FuriString* remote_name, FuriString* signal_name) { InfraredBruteForce* brute_force = infrared_brute_force_alloc(); - const char* remote_file = NULL; - uint32_t i = 0; - bool success = false; + FuriString* remote_path = furi_string_alloc_printf( + "%s/%s.ir", EXT_PATH(INFRARED_ASSETS_FOLDER), furi_string_get_cstr(remote_name)); - switch(remote_type) { - case TV: - remote_file = EXT_PATH("infrared/assets/tv.ir"); - break; - case AC: - remote_file = EXT_PATH("infrared/assets/ac.ir"); - break; - default: - break; - } + infrared_brute_force_set_db_filename(brute_force, furi_string_get_cstr(remote_path)); + infrared_brute_force_add_record( + brute_force, INFRARED_BRUTE_FORCE_DUMMY_INDEX, furi_string_get_cstr(signal_name)); - infrared_brute_force_set_db_filename(brute_force, remote_file); - infrared_brute_force_add_record(brute_force, i++, furi_string_get_cstr(signal)); - - success = infrared_brute_force_calculate_messages(brute_force); - if(success) { - uint32_t record_count; - uint32_t index = 0; - int records_sent = 0; - bool running = false; - - running = infrared_brute_force_start(brute_force, index, &record_count); - if(record_count <= 0) { - printf("Invalid signal.\n"); - infrared_brute_force_reset(brute_force); - return; + do { + if(furi_string_empty(signal_name)) { + printf("Missing signal name.\r\n"); + break; + } + if(!infrared_brute_force_calculate_messages(brute_force)) { + printf("Invalid remote name.\r\n"); + break; } - printf("Sending %ld codes to the tv.\r\n", record_count); + uint32_t record_count; + bool running = infrared_brute_force_start( + brute_force, INFRARED_BRUTE_FORCE_DUMMY_INDEX, &record_count); + + if(record_count <= 0) { + printf("Invalid signal name.\r\n"); + break; + } + + printf("Sending %ld signal(s)...\r\n", record_count); printf("Press Ctrl-C to stop.\r\n"); + + int records_sent = 0; while(running) { running = infrared_brute_force_send_next(brute_force); @@ -510,14 +450,35 @@ static void } infrared_brute_force_stop(brute_force); - } else { - printf("Invalid signal.\r\n"); - } + } while(false); + furi_string_free(remote_path); infrared_brute_force_reset(brute_force); infrared_brute_force_free(brute_force); } +static void infrared_cli_process_universal(Cli* cli, FuriString* args) { + FuriString* arg1 = furi_string_alloc(); + FuriString* arg2 = furi_string_alloc(); + + do { + if(!args_read_string_and_trim(args, arg1)) break; + if(!args_read_string_and_trim(args, arg2)) break; + } while(false); + + if(furi_string_empty(arg1)) { + printf("Wrong arguments.\r\n"); + infrared_cli_print_usage(); + } else if(furi_string_equal_str(arg1, "list")) { + infrared_cli_list_remote_signals(arg2); + } else { + infrared_cli_brute_force_signals(cli, arg1, arg2); + } + + furi_string_free(arg1); + furi_string_free(arg2); +} + static void infrared_cli_start_ir(Cli* cli, FuriString* args, void* context) { UNUSED(context); if(furi_hal_infrared_is_busy()) { diff --git a/applications/main/infrared/infrared_i.h b/applications/main/infrared/infrared_i.h index 6d25d1609..5b555e4bb 100644 --- a/applications/main/infrared/infrared_i.h +++ b/applications/main/infrared/infrared_i.h @@ -2,6 +2,7 @@ #include #include +#include #include #include #include diff --git a/applications/main/infrared/scenes/infrared_scene_config.h b/applications/main/infrared/scenes/infrared_scene_config.h index 22125fb79..111fd2d31 100644 --- a/applications/main/infrared/scenes/infrared_scene_config.h +++ b/applications/main/infrared/scenes/infrared_scene_config.h @@ -16,6 +16,7 @@ ADD_SCENE(infrared, remote_list, RemoteList) ADD_SCENE(infrared, universal, Universal) ADD_SCENE(infrared, universal_tv, UniversalTV) ADD_SCENE(infrared, universal_ac, UniversalAC) +ADD_SCENE(infrared, universal_audio, UniversalAudio) ADD_SCENE(infrared, debug, Debug) ADD_SCENE(infrared, error_databases, ErrorDatabases) ADD_SCENE(infrared, rpc, Rpc) diff --git a/applications/main/infrared/scenes/infrared_scene_learn.c b/applications/main/infrared/scenes/infrared_scene_learn.c index 37f9b3e05..48699a71f 100644 --- a/applications/main/infrared/scenes/infrared_scene_learn.c +++ b/applications/main/infrared/scenes/infrared_scene_learn.c @@ -1,4 +1,5 @@ #include "../infrared_i.h" +#include void infrared_scene_learn_on_enter(void* context) { Infrared* infrared = context; @@ -27,6 +28,7 @@ bool infrared_scene_learn_on_event(void* context, SceneManagerEvent event) { if(event.event == InfraredCustomEventTypeSignalReceived) { infrared_play_notification_message(infrared, InfraredNotificationMessageSuccess); scene_manager_next_scene(infrared->scene_manager, InfraredSceneLearnSuccess); + DOLPHIN_DEED(DolphinDeedIrLearnSuccess); consumed = true; } } diff --git a/applications/main/infrared/scenes/infrared_scene_learn_done.c b/applications/main/infrared/scenes/infrared_scene_learn_done.c index 7d3571715..54b7da724 100644 --- a/applications/main/infrared/scenes/infrared_scene_learn_done.c +++ b/applications/main/infrared/scenes/infrared_scene_learn_done.c @@ -1,13 +1,10 @@ #include "../infrared_i.h" -#include - void infrared_scene_learn_done_on_enter(void* context) { Infrared* infrared = context; Popup* popup = infrared->popup; popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); - DOLPHIN_DEED(DolphinDeedIrSave); if(infrared->app_state.is_learning_new_remote) { popup_set_header(popup, "New remote\ncreated!", 0, 0, AlignLeft, AlignTop); diff --git a/applications/main/infrared/scenes/infrared_scene_learn_enter_name.c b/applications/main/infrared/scenes/infrared_scene_learn_enter_name.c index b6a7eac0d..a8772a985 100644 --- a/applications/main/infrared/scenes/infrared_scene_learn_enter_name.c +++ b/applications/main/infrared/scenes/infrared_scene_learn_enter_name.c @@ -1,4 +1,5 @@ #include "../infrared_i.h" +#include void infrared_scene_learn_enter_name_on_enter(void* context) { Infrared* infrared = context; @@ -49,6 +50,7 @@ bool infrared_scene_learn_enter_name_on_event(void* context, SceneManagerEvent e if(success) { scene_manager_next_scene(scene_manager, InfraredSceneLearnDone); + DOLPHIN_DEED(DolphinDeedIrSave); } else { dialog_message_show_storage_error(infrared->dialogs, "Failed to save file"); const uint32_t possible_scenes[] = {InfraredSceneRemoteList, InfraredSceneStart}; diff --git a/applications/main/infrared/scenes/infrared_scene_learn_success.c b/applications/main/infrared/scenes/infrared_scene_learn_success.c index 466627144..469d4de9e 100644 --- a/applications/main/infrared/scenes/infrared_scene_learn_success.c +++ b/applications/main/infrared/scenes/infrared_scene_learn_success.c @@ -1,7 +1,5 @@ #include "../infrared_i.h" -#include - static void infrared_scene_learn_success_dialog_result_callback(DialogExResult result, void* context) { Infrared* infrared = context; @@ -13,7 +11,6 @@ void infrared_scene_learn_success_on_enter(void* context) { DialogEx* dialog_ex = infrared->dialog_ex; InfraredSignal* signal = infrared->received_signal; - DOLPHIN_DEED(DolphinDeedIrLearnSuccess); infrared_play_notification_message(infrared, InfraredNotificationMessageGreenOn); if(infrared_signal_is_raw(signal)) { diff --git a/applications/main/infrared/scenes/infrared_scene_universal.c b/applications/main/infrared/scenes/infrared_scene_universal.c index 2bd7082c4..914360d78 100644 --- a/applications/main/infrared/scenes/infrared_scene_universal.c +++ b/applications/main/infrared/scenes/infrared_scene_universal.c @@ -21,6 +21,12 @@ void infrared_scene_universal_on_enter(void* context) { SubmenuIndexUniversalTV, infrared_scene_universal_submenu_callback, context); + submenu_add_item( + submenu, + "Audio Players", + SubmenuIndexUniversalAudio, + infrared_scene_universal_submenu_callback, + context); submenu_add_item( submenu, "Air Conditioners", @@ -45,7 +51,7 @@ bool infrared_scene_universal_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(scene_manager, InfraredSceneUniversalAC); consumed = true; } else if(event.event == SubmenuIndexUniversalAudio) { - //TODO Implement Audio universal remote + scene_manager_next_scene(scene_manager, InfraredSceneUniversalAudio); consumed = true; } } diff --git a/applications/main/infrared/scenes/infrared_scene_universal_audio.c b/applications/main/infrared/scenes/infrared_scene_universal_audio.c new file mode 100644 index 000000000..00c86fff4 --- /dev/null +++ b/applications/main/infrared/scenes/infrared_scene_universal_audio.c @@ -0,0 +1,133 @@ +#include "../infrared_i.h" + +#include "common/infrared_scene_universal_common.h" + +void infrared_scene_universal_audio_on_enter(void* context) { + infrared_scene_universal_common_on_enter(context); + + Infrared* infrared = context; + ButtonPanel* button_panel = infrared->button_panel; + InfraredBruteForce* brute_force = infrared->brute_force; + + infrared_brute_force_set_db_filename(brute_force, EXT_PATH("infrared/assets/audio.ir")); + + button_panel_reserve(button_panel, 2, 4); + uint32_t i = 0; + button_panel_add_item( + button_panel, + i, + 0, + 0, + 3, + 11, + &I_Power_25x27, + &I_Power_hvr_25x27, + infrared_scene_universal_common_item_callback, + context); + infrared_brute_force_add_record(brute_force, i++, "Power"); + button_panel_add_item( + button_panel, + i, + 1, + 0, + 36, + 11, + &I_Mute_25x27, + &I_Mute_hvr_25x27, + infrared_scene_universal_common_item_callback, + context); + infrared_brute_force_add_record(brute_force, i++, "Mute"); + button_panel_add_item( + button_panel, + i, + 0, + 1, + 3, + 41, + &I_Play_25x27, + &I_Play_hvr_25x27, + infrared_scene_universal_common_item_callback, + context); + infrared_brute_force_add_record(brute_force, i++, "Play"); + button_panel_add_item( + button_panel, + i, + 1, + 1, + 36, + 41, + &I_Pause_25x27, + &I_Pause_hvr_25x27, + infrared_scene_universal_common_item_callback, + context); + infrared_brute_force_add_record(brute_force, i++, "Pause"); + button_panel_add_item( + button_panel, + i, + 0, + 2, + 3, + 71, + &I_TrackPrev_25x27, + &I_TrackPrev_hvr_25x27, + infrared_scene_universal_common_item_callback, + context); + infrared_brute_force_add_record(brute_force, i++, "Prev"); + button_panel_add_item( + button_panel, + i, + 1, + 2, + 36, + 71, + &I_TrackNext_25x27, + &I_TrackNext_hvr_25x27, + infrared_scene_universal_common_item_callback, + context); + infrared_brute_force_add_record(brute_force, i++, "Next"); + button_panel_add_item( + button_panel, + i, + 0, + 3, + 3, + 101, + &I_Vol_down_25x27, + &I_Vol_down_hvr_25x27, + infrared_scene_universal_common_item_callback, + context); + infrared_brute_force_add_record(brute_force, i++, "Vol_dn"); + button_panel_add_item( + button_panel, + i, + 1, + 3, + 36, + 101, + &I_Vol_up_25x27, + &I_Vol_up_hvr_25x27, + infrared_scene_universal_common_item_callback, + context); + infrared_brute_force_add_record(brute_force, i++, "Vol_up"); + + button_panel_add_label(button_panel, 1, 8, FontPrimary, "Mus. remote"); + + view_set_orientation(view_stack_get_view(infrared->view_stack), ViewOrientationVertical); + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewStack); + + infrared_show_loading_popup(infrared, true); + bool success = infrared_brute_force_calculate_messages(brute_force); + infrared_show_loading_popup(infrared, false); + + if(!success) { + scene_manager_next_scene(infrared->scene_manager, InfraredSceneErrorDatabases); + } +} + +bool infrared_scene_universal_audio_on_event(void* context, SceneManagerEvent event) { + return infrared_scene_universal_common_on_event(context, event); +} + +void infrared_scene_universal_audio_on_exit(void* context) { + infrared_scene_universal_common_on_exit(context); +} diff --git a/applications/main/lfrfid/lfrfid.c b/applications/main/lfrfid/lfrfid.c index b0f989374..513227306 100644 --- a/applications/main/lfrfid/lfrfid.c +++ b/applications/main/lfrfid/lfrfid.c @@ -1,4 +1,5 @@ #include "lfrfid_i.h" +#include static bool lfrfid_debug_custom_event_callback(void* context, uint32_t event) { furi_assert(context); @@ -182,12 +183,14 @@ int32_t lfrfid_app(void* p) { view_dispatcher_attach_to_gui( app->view_dispatcher, app->gui, ViewDispatcherTypeDesktop); scene_manager_next_scene(app->scene_manager, LfRfidSceneRpc); + DOLPHIN_DEED(DolphinDeedRfidEmulate); } else { furi_string_set(app->file_path, args); lfrfid_load_key_data(app, app->file_path, true); view_dispatcher_attach_to_gui( app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); scene_manager_next_scene(app->scene_manager, LfRfidSceneEmulate); + DOLPHIN_DEED(DolphinDeedRfidEmulate); } } else { @@ -311,4 +314,4 @@ void lfrfid_widget_callback(GuiButtonType result, InputType type, void* context) void lfrfid_text_input_callback(void* context) { LfRfid* app = context; view_dispatcher_send_custom_event(app->view_dispatcher, LfRfidEventNext); -} \ No newline at end of file +} diff --git a/applications/main/lfrfid/lfrfid_i.h b/applications/main/lfrfid/lfrfid_i.h index 71917c0c2..72b061930 100644 --- a/applications/main/lfrfid/lfrfid_i.h +++ b/applications/main/lfrfid/lfrfid_i.h @@ -5,6 +5,7 @@ #include #include +#include #include #include #include diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_emulate.c b/applications/main/lfrfid/scenes/lfrfid_scene_emulate.c index 2725982f0..dc3918994 100644 --- a/applications/main/lfrfid/scenes/lfrfid_scene_emulate.c +++ b/applications/main/lfrfid/scenes/lfrfid_scene_emulate.c @@ -1,12 +1,9 @@ #include "../lfrfid_i.h" -#include void lfrfid_scene_emulate_on_enter(void* context) { LfRfid* app = context; Popup* popup = app->popup; - DOLPHIN_DEED(DolphinDeedRfidEmulate); - popup_set_header(popup, "Emulating", 89, 30, AlignCenter, AlignTop); if(!furi_string_empty(app->file_name)) { popup_set_text(popup, furi_string_get_cstr(app->file_name), 89, 43, AlignCenter, AlignTop); diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_extra_actions.c b/applications/main/lfrfid/scenes/lfrfid_scene_extra_actions.c index d7fd93e19..fac2ebcec 100644 --- a/applications/main/lfrfid/scenes/lfrfid_scene_extra_actions.c +++ b/applications/main/lfrfid/scenes/lfrfid_scene_extra_actions.c @@ -1,4 +1,5 @@ #include "../lfrfid_i.h" +#include typedef enum { SubmenuIndexASK, @@ -57,10 +58,12 @@ bool lfrfid_scene_extra_actions_on_event(void* context, SceneManagerEvent event) if(event.event == SubmenuIndexASK) { app->read_type = LFRFIDWorkerReadTypeASKOnly; scene_manager_next_scene(app->scene_manager, LfRfidSceneRead); + DOLPHIN_DEED(DolphinDeedRfidRead); consumed = true; } else if(event.event == SubmenuIndexPSK) { app->read_type = LFRFIDWorkerReadTypePSKOnly; scene_manager_next_scene(app->scene_manager, LfRfidSceneRead); + DOLPHIN_DEED(DolphinDeedRfidRead); consumed = true; } else if(event.event == SubmenuIndexRAW) { scene_manager_next_scene(app->scene_manager, LfRfidSceneRawName); diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_read.c b/applications/main/lfrfid/scenes/lfrfid_scene_read.c index 4bdb215d1..5f1959728 100644 --- a/applications/main/lfrfid/scenes/lfrfid_scene_read.c +++ b/applications/main/lfrfid/scenes/lfrfid_scene_read.c @@ -46,7 +46,6 @@ static void void lfrfid_scene_read_on_enter(void* context) { LfRfid* app = context; - DOLPHIN_DEED(DolphinDeedRfidRead); if(app->read_type == LFRFIDWorkerReadTypePSKOnly) { lfrfid_view_read_set_read_mode(app->read_view, LfRfidReadPskOnly); } else if(app->read_type == LFRFIDWorkerReadTypeASKOnly) { @@ -79,10 +78,10 @@ bool lfrfid_scene_read_on_event(void* context, SceneManagerEvent event) { consumed = true; } else if(event.event == LfRfidEventReadDone) { app->protocol_id = app->protocol_id_next; - DOLPHIN_DEED(DolphinDeedRfidReadSuccess); notification_message(app->notifications, &sequence_success); furi_string_reset(app->file_name); scene_manager_next_scene(app->scene_manager, LfRfidSceneReadSuccess); + DOLPHIN_DEED(DolphinDeedRfidReadSuccess); consumed = true; } else if(event.event == LfRfidEventReadStartPSK) { if(app->read_type == LFRFIDWorkerReadTypeAuto) { diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_read_key_menu.c b/applications/main/lfrfid/scenes/lfrfid_scene_read_key_menu.c index 7480304b6..081c47912 100644 --- a/applications/main/lfrfid/scenes/lfrfid_scene_read_key_menu.c +++ b/applications/main/lfrfid/scenes/lfrfid_scene_read_key_menu.c @@ -1,4 +1,5 @@ #include "../lfrfid_i.h" +#include typedef enum { SubmenuIndexSave, @@ -43,6 +44,7 @@ bool lfrfid_scene_read_key_menu_on_event(void* context, SceneManagerEvent event) consumed = true; } else if(event.event == SubmenuIndexEmulate) { scene_manager_next_scene(app->scene_manager, LfRfidSceneEmulate); + DOLPHIN_DEED(DolphinDeedRfidEmulate); consumed = true; } scene_manager_set_scene_state(app->scene_manager, LfRfidSceneReadKeyMenu, event.event); diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_save_data.c b/applications/main/lfrfid/scenes/lfrfid_scene_save_data.c index 6c5ea2f2d..11a687bdd 100644 --- a/applications/main/lfrfid/scenes/lfrfid_scene_save_data.c +++ b/applications/main/lfrfid/scenes/lfrfid_scene_save_data.c @@ -1,5 +1,4 @@ #include "../lfrfid_i.h" -#include void lfrfid_scene_save_data_on_enter(void* context) { LfRfid* app = context; @@ -32,7 +31,6 @@ bool lfrfid_scene_save_data_on_event(void* context, SceneManagerEvent event) { consumed = true; size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id); protocol_dict_set_data(app->dict, app->protocol_id, app->new_key_data, size); - DOLPHIN_DEED(DolphinDeedRfidAdd); scene_manager_next_scene(scene_manager, LfRfidSceneSaveName); scene_manager_set_scene_state(scene_manager, LfRfidSceneSaveData, 1); } diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_save_name.c b/applications/main/lfrfid/scenes/lfrfid_scene_save_name.c index ca9a52de0..87e110f18 100644 --- a/applications/main/lfrfid/scenes/lfrfid_scene_save_name.c +++ b/applications/main/lfrfid/scenes/lfrfid_scene_save_name.c @@ -1,5 +1,6 @@ #include #include "../lfrfid_i.h" +#include void lfrfid_scene_save_name_on_enter(void* context) { LfRfid* app = context; @@ -55,6 +56,13 @@ bool lfrfid_scene_save_name_on_event(void* context, SceneManagerEvent event) { if(lfrfid_save_key(app)) { scene_manager_next_scene(scene_manager, LfRfidSceneSaveSuccess); + if(scene_manager_has_previous_scene(scene_manager, LfRfidSceneSavedKeyMenu)) { + // Nothing, do not count editing as saving + } else if(scene_manager_has_previous_scene(scene_manager, LfRfidSceneSaveType)) { + DOLPHIN_DEED(DolphinDeedRfidAdd); + } else { + DOLPHIN_DEED(DolphinDeedRfidSave); + } } else { scene_manager_search_and_switch_to_previous_scene( scene_manager, LfRfidSceneReadKeyMenu); diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_save_success.c b/applications/main/lfrfid/scenes/lfrfid_scene_save_success.c index e91ad04e3..52aefa848 100644 --- a/applications/main/lfrfid/scenes/lfrfid_scene_save_success.c +++ b/applications/main/lfrfid/scenes/lfrfid_scene_save_success.c @@ -1,5 +1,4 @@ #include "../lfrfid_i.h" -#include void lfrfid_scene_save_success_on_enter(void* context) { LfRfid* app = context; @@ -8,7 +7,6 @@ void lfrfid_scene_save_success_on_enter(void* context) { // Clear state of data enter scene scene_manager_set_scene_state(app->scene_manager, LfRfidSceneSaveData, 0); - DOLPHIN_DEED(DolphinDeedRfidSave); popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); popup_set_header(popup, "Saved!", 5, 7, AlignLeft, AlignTop); popup_set_context(popup, app); diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_saved_key_menu.c b/applications/main/lfrfid/scenes/lfrfid_scene_saved_key_menu.c index 040b31f10..d3c3d389a 100644 --- a/applications/main/lfrfid/scenes/lfrfid_scene_saved_key_menu.c +++ b/applications/main/lfrfid/scenes/lfrfid_scene_saved_key_menu.c @@ -1,4 +1,5 @@ #include "../lfrfid_i.h" +#include typedef enum { SubmenuIndexEmulate, @@ -42,6 +43,7 @@ bool lfrfid_scene_saved_key_menu_on_event(void* context, SceneManagerEvent event if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubmenuIndexEmulate) { scene_manager_next_scene(app->scene_manager, LfRfidSceneEmulate); + DOLPHIN_DEED(DolphinDeedRfidEmulate); consumed = true; } else if(event.event == SubmenuIndexWrite) { scene_manager_next_scene(app->scene_manager, LfRfidSceneWrite); diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_start.c b/applications/main/lfrfid/scenes/lfrfid_scene_start.c index d6d87f441..8e1c92dbb 100644 --- a/applications/main/lfrfid/scenes/lfrfid_scene_start.c +++ b/applications/main/lfrfid/scenes/lfrfid_scene_start.c @@ -1,4 +1,5 @@ #include "../lfrfid_i.h" +#include typedef enum { SubmenuIndexRead, @@ -47,6 +48,7 @@ bool lfrfid_scene_start_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubmenuIndexRead) { scene_manager_next_scene(app->scene_manager, LfRfidSceneRead); + DOLPHIN_DEED(DolphinDeedRfidRead); consumed = true; } else if(event.event == SubmenuIndexSaved) { furi_string_set(app->file_path, LFRFID_APP_FOLDER); diff --git a/applications/main/lfrfid/views/lfrfid_view_read.c b/applications/main/lfrfid/views/lfrfid_view_read.c index 0d4db6178..094afb617 100644 --- a/applications/main/lfrfid/views/lfrfid_view_read.c +++ b/applications/main/lfrfid/views/lfrfid_view_read.c @@ -1,5 +1,6 @@ #include "lfrfid_view_read.h" #include +#include #define TEMP_STR_LEN 128 diff --git a/applications/main/nfc/nfc.c b/applications/main/nfc/nfc.c index 0b685f545..55c68a450 100644 --- a/applications/main/nfc/nfc.c +++ b/applications/main/nfc/nfc.c @@ -1,5 +1,6 @@ #include "nfc_i.h" #include "furi_hal_nfc.h" +#include bool nfc_custom_event_callback(void* context, uint32_t event) { furi_assert(context); @@ -275,12 +276,15 @@ int32_t nfc_app(void* p) { if(nfc_device_load(nfc->dev, p, true)) { if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate); + DOLPHIN_DEED(DolphinDeedNfcEmulate); } else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate); + DOLPHIN_DEED(DolphinDeedNfcEmulate); } else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) { scene_manager_next_scene(nfc->scene_manager, NfcSceneDeviceInfo); } else { scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); + DOLPHIN_DEED(DolphinDeedNfcEmulate); } } else { // Exit app diff --git a/applications/main/nfc/nfc_i.h b/applications/main/nfc/nfc_i.h index fa5b54edc..e9b36a3e9 100644 --- a/applications/main/nfc/nfc_i.h +++ b/applications/main/nfc/nfc_i.h @@ -7,6 +7,7 @@ #include #include +#include #include #include #include diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index a25850c84..9b922add2 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -36,6 +36,12 @@ ADD_SCENE(nfc, mf_classic_keys_list, MfClassicKeysList) ADD_SCENE(nfc, mf_classic_keys_delete, MfClassicKeysDelete) ADD_SCENE(nfc, mf_classic_keys_warn_duplicate, MfClassicKeysWarnDuplicate) ADD_SCENE(nfc, mf_classic_dict_attack, MfClassicDictAttack) +ADD_SCENE(nfc, mf_classic_write, MfClassicWrite) +ADD_SCENE(nfc, mf_classic_write_success, MfClassicWriteSuccess) +ADD_SCENE(nfc, mf_classic_write_fail, MfClassicWriteFail) +ADD_SCENE(nfc, mf_classic_update, MfClassicUpdate) +ADD_SCENE(nfc, mf_classic_update_success, MfClassicUpdateSuccess) +ADD_SCENE(nfc, mf_classic_wrong_card, MfClassicWrongCard) ADD_SCENE(nfc, emv_read_success, EmvReadSuccess) ADD_SCENE(nfc, emv_menu, EmvMenu) ADD_SCENE(nfc, emulate_apdu_sequence, EmulateApduSequence) diff --git a/applications/main/nfc/scenes/nfc_scene_detect_reader.c b/applications/main/nfc/scenes/nfc_scene_detect_reader.c index f0177f9c1..745946157 100644 --- a/applications/main/nfc/scenes/nfc_scene_detect_reader.c +++ b/applications/main/nfc/scenes/nfc_scene_detect_reader.c @@ -1,5 +1,4 @@ #include "../nfc_i.h" -#include #define NFC_SCENE_DETECT_READER_PAIR_NONCES_MAX (10U) @@ -26,10 +25,14 @@ void nfc_scene_detect_reader_callback(void* context) { void nfc_scene_detect_reader_on_enter(void* context) { Nfc* nfc = context; - DOLPHIN_DEED(DolphinDeedNfcDetectReader); detect_reader_set_callback(nfc->detect_reader, nfc_scene_detect_reader_callback, nfc); detect_reader_set_nonces_max(nfc->detect_reader, NFC_SCENE_DETECT_READER_PAIR_NONCES_MAX); + NfcDeviceData* dev_data = &nfc->dev->dev_data; + if(dev_data->nfc_data.uid_len) { + detect_reader_set_uid( + nfc->detect_reader, dev_data->nfc_data.uid, dev_data->nfc_data.uid_len); + } // Store number of collected nonces in scene state scene_manager_set_scene_state(nfc->scene_manager, NfcSceneDetectReader, 0); diff --git a/applications/main/nfc/scenes/nfc_scene_emulate_uid.c b/applications/main/nfc/scenes/nfc_scene_emulate_uid.c index 8bb207960..5ddb60992 100644 --- a/applications/main/nfc/scenes/nfc_scene_emulate_uid.c +++ b/applications/main/nfc/scenes/nfc_scene_emulate_uid.c @@ -1,5 +1,4 @@ #include "../nfc_i.h" -#include #define NFC_SCENE_EMULATE_UID_LOG_SIZE_MAX (200) @@ -59,7 +58,6 @@ static void nfc_scene_emulate_uid_widget_config(Nfc* nfc, bool data_received) { void nfc_scene_emulate_uid_on_enter(void* context) { Nfc* nfc = context; - DOLPHIN_DEED(DolphinDeedNfcEmulate); // Setup Widget nfc_scene_emulate_uid_widget_config(nfc, false); diff --git a/applications/main/nfc/scenes/nfc_scene_emv_read_success.c b/applications/main/nfc/scenes/nfc_scene_emv_read_success.c index 6a0b32fad..005b76cb2 100644 --- a/applications/main/nfc/scenes/nfc_scene_emv_read_success.c +++ b/applications/main/nfc/scenes/nfc_scene_emv_read_success.c @@ -1,6 +1,5 @@ #include "../nfc_i.h" #include "../helpers/nfc_emv_parser.h" -#include void nfc_scene_emv_read_success_widget_callback( GuiButtonType result, @@ -15,7 +14,6 @@ void nfc_scene_emv_read_success_widget_callback( void nfc_scene_emv_read_success_on_enter(void* context) { Nfc* nfc = context; EmvData* emv_data = &nfc->dev->dev_data.emv_data; - DOLPHIN_DEED(DolphinDeedNfcReadSuccess); // Setup Custom Widget view widget_add_button_element( diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c index 813546905..acb5b783c 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c @@ -1,4 +1,5 @@ #include "../nfc_i.h" +#include #define TAG "NfcMfClassicDictAttack" @@ -110,6 +111,7 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent } else { notification_message(nfc->notifications, &sequence_success); scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSuccess); + DOLPHIN_DEED(DolphinDeedNfcReadSuccess); consumed = true; } } else if(event.event == NfcWorkerEventAborted) { @@ -119,6 +121,8 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent } else { notification_message(nfc->notifications, &sequence_success); scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSuccess); + // Counting failed attempts too + DOLPHIN_DEED(DolphinDeedNfcReadSuccess); consumed = true; } } else if(event.event == NfcWorkerEventCardDetected) { diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_emulate.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_emulate.c index 65639b2b4..e514fa728 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_emulate.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_emulate.c @@ -1,5 +1,4 @@ #include "../nfc_i.h" -#include #define NFC_MF_CLASSIC_DATA_NOT_CHANGED (0UL) #define NFC_MF_CLASSIC_DATA_CHANGED (1UL) @@ -15,7 +14,6 @@ bool nfc_mf_classic_emulate_worker_callback(NfcWorkerEvent event, void* context) void nfc_scene_mf_classic_emulate_on_enter(void* context) { Nfc* nfc = context; - DOLPHIN_DEED(DolphinDeedNfcEmulate); // Setup view Popup* popup = nfc->popup; diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_add.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_add.c index 2921d21c9..b122aa225 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_add.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_add.c @@ -1,4 +1,5 @@ #include "../nfc_i.h" +#include void nfc_scene_mf_classic_keys_add_byte_input_callback(void* context) { Nfc* nfc = context; @@ -36,6 +37,7 @@ bool nfc_scene_mf_classic_keys_add_on_event(void* context, SceneManagerEvent eve nfc->scene_manager, NfcSceneMfClassicKeysWarnDuplicate); } else if(mf_classic_dict_add_key(dict, nfc->byte_input_store)) { scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess); + DOLPHIN_DEED(DolphinDeedNfcMfcAdd); } else { scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound); } diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_menu.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_menu.c index 2cba04337..a5bb10ddf 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_menu.c @@ -36,8 +36,6 @@ bool nfc_scene_mf_classic_menu_on_event(void* context, SceneManagerEvent event) if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubmenuIndexSave) { - DOLPHIN_DEED(DolphinDeedNfcMfcAdd); - scene_manager_set_scene_state( nfc->scene_manager, NfcSceneMfClassicMenu, SubmenuIndexSave); nfc->dev->format = NfcDeviceSaveFormatMifareClassic; @@ -49,6 +47,11 @@ bool nfc_scene_mf_classic_menu_on_event(void* context, SceneManagerEvent event) scene_manager_set_scene_state( nfc->scene_manager, NfcSceneMfClassicMenu, SubmenuIndexEmulate); scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate); + if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) { + DOLPHIN_DEED(DolphinDeedNfcAddEmulate); + } else { + DOLPHIN_DEED(DolphinDeedNfcEmulate); + } consumed = true; } else if(event.event == SubmenuIndexInfo) { scene_manager_set_scene_state( diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_read_success.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_read_success.c index 0cdb86464..ae31e92cc 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_read_success.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_read_success.c @@ -1,5 +1,4 @@ #include "../nfc_i.h" -#include void nfc_scene_mf_classic_read_success_widget_callback( GuiButtonType result, @@ -18,8 +17,6 @@ void nfc_scene_mf_classic_read_success_on_enter(void* context) { NfcDeviceData* dev_data = &nfc->dev->dev_data; MfClassicData* mf_data = &dev_data->mf_classic_data; - DOLPHIN_DEED(DolphinDeedNfcReadSuccess); - // Setup view Widget* widget = nfc->widget; widget_add_button_element( diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_update.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_update.c new file mode 100644 index 000000000..dd3a6f7d5 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_update.c @@ -0,0 +1,98 @@ +#include "../nfc_i.h" +#include + +enum { + NfcSceneMfClassicUpdateStateCardSearch, + NfcSceneMfClassicUpdateStateCardFound, +}; + +bool nfc_mf_classic_update_worker_callback(NfcWorkerEvent event, void* context) { + furi_assert(context); + + Nfc* nfc = context; + view_dispatcher_send_custom_event(nfc->view_dispatcher, event); + + return true; +} + +static void nfc_scene_mf_classic_update_setup_view(Nfc* nfc) { + Popup* popup = nfc->popup; + popup_reset(popup); + uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicUpdate); + + if(state == NfcSceneMfClassicUpdateStateCardSearch) { + popup_set_text( + nfc->popup, "Apply the initial\ncard only", 128, 32, AlignRight, AlignCenter); + popup_set_icon(nfc->popup, 0, 8, &I_NFC_manual_60x50); + } else { + popup_set_header(popup, "Updating\nDon't move...", 52, 32, AlignLeft, AlignCenter); + popup_set_icon(popup, 12, 23, &A_Loading_24); + } + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); +} + +void nfc_scene_mf_classic_update_on_enter(void* context) { + Nfc* nfc = context; + DOLPHIN_DEED(DolphinDeedNfcEmulate); + + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneMfClassicUpdate, NfcSceneMfClassicUpdateStateCardSearch); + nfc_scene_mf_classic_update_setup_view(nfc); + + // Setup and start worker + nfc_worker_start( + nfc->worker, + NfcWorkerStateMfClassicUpdate, + &nfc->dev->dev_data, + nfc_mf_classic_update_worker_callback, + nfc); + nfc_blink_emulate_start(nfc); +} + +bool nfc_scene_mf_classic_update_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcWorkerEventSuccess) { + nfc_worker_stop(nfc->worker); + if(nfc_device_save_shadow(nfc->dev, nfc->dev->dev_name)) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicUpdateSuccess); + } else { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicWrongCard); + } + consumed = true; + } else if(event.event == NfcWorkerEventWrongCard) { + nfc_worker_stop(nfc->worker); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicWrongCard); + consumed = true; + } else if(event.event == NfcWorkerEventCardDetected) { + scene_manager_set_scene_state( + nfc->scene_manager, + NfcSceneMfClassicUpdate, + NfcSceneMfClassicUpdateStateCardFound); + nfc_scene_mf_classic_update_setup_view(nfc); + consumed = true; + } else if(event.event == NfcWorkerEventNoCardDetected) { + scene_manager_set_scene_state( + nfc->scene_manager, + NfcSceneMfClassicUpdate, + NfcSceneMfClassicUpdateStateCardSearch); + nfc_scene_mf_classic_update_setup_view(nfc); + consumed = true; + } + } + return consumed; +} + +void nfc_scene_mf_classic_update_on_exit(void* context) { + Nfc* nfc = context; + nfc_worker_stop(nfc->worker); + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneMfClassicUpdate, NfcSceneMfClassicUpdateStateCardSearch); + // Clear view + popup_reset(nfc->popup); + + nfc_blink_stop(nfc); +} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_update_success.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_update_success.c new file mode 100644 index 000000000..fef8fd5e9 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_update_success.c @@ -0,0 +1,44 @@ +#include "../nfc_i.h" +#include + +void nfc_scene_mf_classic_update_success_popup_callback(void* context) { + Nfc* nfc = context; + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); +} + +void nfc_scene_mf_classic_update_success_on_enter(void* context) { + Nfc* nfc = context; + DOLPHIN_DEED(DolphinDeedNfcSave); + + notification_message(nfc->notifications, &sequence_success); + + Popup* popup = nfc->popup; + popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); + popup_set_header(popup, "Updated!", 11, 20, AlignLeft, AlignBottom); + popup_set_timeout(popup, 1500); + popup_set_context(popup, nfc); + popup_set_callback(popup, nfc_scene_mf_classic_update_success_popup_callback); + popup_enable_timeout(popup); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); +} + +bool nfc_scene_mf_classic_update_success_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventViewExit) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneFileSelect); + } + } + return consumed; +} + +void nfc_scene_mf_classic_update_success_on_exit(void* context) { + Nfc* nfc = context; + + // Clear view + popup_reset(nfc->popup); +} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_write.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_write.c new file mode 100644 index 000000000..3543cbc58 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_write.c @@ -0,0 +1,92 @@ +#include "../nfc_i.h" +#include + +enum { + NfcSceneMfClassicWriteStateCardSearch, + NfcSceneMfClassicWriteStateCardFound, +}; + +bool nfc_mf_classic_write_worker_callback(NfcWorkerEvent event, void* context) { + furi_assert(context); + + Nfc* nfc = context; + view_dispatcher_send_custom_event(nfc->view_dispatcher, event); + + return true; +} + +static void nfc_scene_mf_classic_write_setup_view(Nfc* nfc) { + Popup* popup = nfc->popup; + popup_reset(popup); + uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicWrite); + + if(state == NfcSceneMfClassicWriteStateCardSearch) { + popup_set_text( + nfc->popup, "Apply the initial\ncard only", 128, 32, AlignRight, AlignCenter); + popup_set_icon(nfc->popup, 0, 8, &I_NFC_manual_60x50); + } else { + popup_set_header(popup, "Writing\nDon't move...", 52, 32, AlignLeft, AlignCenter); + popup_set_icon(popup, 12, 23, &A_Loading_24); + } + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); +} + +void nfc_scene_mf_classic_write_on_enter(void* context) { + Nfc* nfc = context; + DOLPHIN_DEED(DolphinDeedNfcEmulate); + + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneMfClassicWrite, NfcSceneMfClassicWriteStateCardSearch); + nfc_scene_mf_classic_write_setup_view(nfc); + + // Setup and start worker + nfc_worker_start( + nfc->worker, + NfcWorkerStateMfClassicWrite, + &nfc->dev->dev_data, + nfc_mf_classic_write_worker_callback, + nfc); + nfc_blink_emulate_start(nfc); +} + +bool nfc_scene_mf_classic_write_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcWorkerEventSuccess) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicWriteSuccess); + consumed = true; + } else if(event.event == NfcWorkerEventFail) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicWriteFail); + consumed = true; + } else if(event.event == NfcWorkerEventWrongCard) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicWrongCard); + consumed = true; + } else if(event.event == NfcWorkerEventCardDetected) { + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneMfClassicWrite, NfcSceneMfClassicWriteStateCardFound); + nfc_scene_mf_classic_write_setup_view(nfc); + consumed = true; + } else if(event.event == NfcWorkerEventNoCardDetected) { + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneMfClassicWrite, NfcSceneMfClassicWriteStateCardSearch); + nfc_scene_mf_classic_write_setup_view(nfc); + consumed = true; + } + } + return consumed; +} + +void nfc_scene_mf_classic_write_on_exit(void* context) { + Nfc* nfc = context; + + nfc_worker_stop(nfc->worker); + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneMfClassicWrite, NfcSceneMfClassicWriteStateCardSearch); + // Clear view + popup_reset(nfc->popup); + + nfc_blink_stop(nfc); +} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_write_fail.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_write_fail.c new file mode 100644 index 000000000..aeea6eef0 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_write_fail.c @@ -0,0 +1,58 @@ +#include "../nfc_i.h" + +void nfc_scene_mf_classic_write_fail_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + Nfc* nfc = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); + } +} + +void nfc_scene_mf_classic_write_fail_on_enter(void* context) { + Nfc* nfc = context; + Widget* widget = nfc->widget; + + notification_message(nfc->notifications, &sequence_error); + + widget_add_icon_element(widget, 72, 17, &I_DolphinCommon_56x48); + widget_add_string_element( + widget, 7, 4, AlignLeft, AlignTop, FontPrimary, "Writing gone wrong!"); + widget_add_string_multiline_element( + widget, + 7, + 17, + AlignLeft, + AlignTop, + FontSecondary, + "Not all sectors\nwere written\ncorrectly."); + + widget_add_button_element( + widget, GuiButtonTypeLeft, "Finish", nfc_scene_mf_classic_write_fail_widget_callback, nfc); + + // Setup and start worker + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); +} + +bool nfc_scene_mf_classic_write_fail_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeLeft) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneFileSelect); + } + } else if(event.type == SceneManagerEventTypeBack) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneSavedMenu); + } + return consumed; +} + +void nfc_scene_mf_classic_write_fail_on_exit(void* context) { + Nfc* nfc = context; + + widget_reset(nfc->widget); +} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_write_success.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_write_success.c new file mode 100644 index 000000000..2f2a3beb1 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_write_success.c @@ -0,0 +1,44 @@ +#include "../nfc_i.h" +#include + +void nfc_scene_mf_classic_write_success_popup_callback(void* context) { + Nfc* nfc = context; + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); +} + +void nfc_scene_mf_classic_write_success_on_enter(void* context) { + Nfc* nfc = context; + DOLPHIN_DEED(DolphinDeedNfcSave); + + notification_message(nfc->notifications, &sequence_success); + + Popup* popup = nfc->popup; + popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); + popup_set_header(popup, "Successfully\nwritten", 13, 22, AlignLeft, AlignBottom); + popup_set_timeout(popup, 1500); + popup_set_context(popup, nfc); + popup_set_callback(popup, nfc_scene_mf_classic_write_success_popup_callback); + popup_enable_timeout(popup); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); +} + +bool nfc_scene_mf_classic_write_success_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventViewExit) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneFileSelect); + } + } + return consumed; +} + +void nfc_scene_mf_classic_write_success_on_exit(void* context) { + Nfc* nfc = context; + + // Clear view + popup_reset(nfc->popup); +} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_wrong_card.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_wrong_card.c new file mode 100644 index 000000000..2c56270e3 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_wrong_card.c @@ -0,0 +1,53 @@ +#include "../nfc_i.h" + +void nfc_scene_mf_classic_wrong_card_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + Nfc* nfc = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); + } +} + +void nfc_scene_mf_classic_wrong_card_on_enter(void* context) { + Nfc* nfc = context; + Widget* widget = nfc->widget; + + notification_message(nfc->notifications, &sequence_error); + + widget_add_icon_element(widget, 73, 17, &I_DolphinCommon_56x48); + widget_add_string_element( + widget, 3, 4, AlignLeft, AlignTop, FontPrimary, "This is wrong card"); + widget_add_string_multiline_element( + widget, + 4, + 17, + AlignLeft, + AlignTop, + FontSecondary, + "Data management\nis only possible\nwith initial card"); + widget_add_button_element( + widget, GuiButtonTypeLeft, "Retry", nfc_scene_mf_classic_wrong_card_widget_callback, nfc); + + // Setup and start worker + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); +} + +bool nfc_scene_mf_classic_wrong_card_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeLeft) { + consumed = scene_manager_previous_scene(nfc->scene_manager); + } + } + return consumed; +} + +void nfc_scene_mf_classic_wrong_card_on_exit(void* context) { + Nfc* nfc = context; + + widget_reset(nfc->widget); +} \ No newline at end of file diff --git a/applications/main/nfc/scenes/nfc_scene_mf_desfire_menu.c b/applications/main/nfc/scenes/nfc_scene_mf_desfire_menu.c index 1e2f2d2f2..bee63d775 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_desfire_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_desfire_menu.c @@ -1,4 +1,5 @@ #include "../nfc_i.h" +#include enum SubmenuIndex { SubmenuIndexSave, @@ -48,6 +49,11 @@ bool nfc_scene_mf_desfire_menu_on_event(void* context, SceneManagerEvent event) consumed = true; } else if(event.event == SubmenuIndexEmulateUid) { scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); + if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) { + DOLPHIN_DEED(DolphinDeedNfcAddEmulate); + } else { + DOLPHIN_DEED(DolphinDeedNfcEmulate); + } consumed = true; } else if(event.event == SubmenuIndexInfo) { scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_emulate.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_emulate.c index 712ddc077..e84fb3927 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_emulate.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_emulate.c @@ -1,5 +1,4 @@ #include "../nfc_i.h" -#include #define NFC_MF_UL_DATA_NOT_CHANGED (0UL) #define NFC_MF_UL_DATA_CHANGED (1UL) @@ -15,7 +14,6 @@ bool nfc_mf_ultralight_emulate_worker_callback(NfcWorkerEvent event, void* conte void nfc_scene_mf_ultralight_emulate_on_enter(void* context) { Nfc* nfc = context; - DOLPHIN_DEED(DolphinDeedNfcEmulate); // Setup view Popup* popup = nfc->popup; diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c index ba9f22338..ab4d37b09 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c @@ -1,4 +1,5 @@ #include "../nfc_i.h" +#include enum SubmenuIndex { SubmenuIndexUnlock, @@ -56,6 +57,11 @@ bool nfc_scene_mf_ultralight_menu_on_event(void* context, SceneManagerEvent even consumed = true; } else if(event.event == SubmenuIndexEmulate) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate); + if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) { + DOLPHIN_DEED(DolphinDeedNfcAddEmulate); + } else { + DOLPHIN_DEED(DolphinDeedNfcEmulate); + } consumed = true; } else if(event.event == SubmenuIndexUnlock) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockMenu); diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_auth.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_auth.c index 25008004b..5dbb0c18a 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_auth.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_auth.c @@ -1,5 +1,4 @@ #include "../nfc_i.h" -#include typedef enum { NfcSceneMfUlReadStateIdle, @@ -51,7 +50,6 @@ void nfc_scene_mf_ultralight_read_auth_set_state(Nfc* nfc, NfcSceneMfUlReadState void nfc_scene_mf_ultralight_read_auth_on_enter(void* context) { Nfc* nfc = context; - DOLPHIN_DEED(DolphinDeedNfcRead); nfc_device_clear(nfc->dev); // Setup view diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_auth_result.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_auth_result.c index 5a690a213..178d03351 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_auth_result.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_auth_result.c @@ -1,5 +1,4 @@ #include "../nfc_i.h" -#include void nfc_scene_mf_ultralight_read_auth_result_widget_callback( GuiButtonType result, @@ -37,7 +36,6 @@ void nfc_scene_mf_ultralight_read_auth_result_on_enter(void* context) { widget_add_string_element( widget, 0, 17, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(temp_str)); if(mf_ul_data->auth_success) { - DOLPHIN_DEED(DolphinDeedNfcReadSuccess); furi_string_printf( temp_str, "Password: %02X %02X %02X %02X", @@ -54,8 +52,6 @@ void nfc_scene_mf_ultralight_read_auth_result_on_enter(void* context) { config_pages->auth_data.pack.raw[1]); widget_add_string_element( widget, 0, 39, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(temp_str)); - } else { - DOLPHIN_DEED(DolphinDeedNfcMfulError); } furi_string_printf( temp_str, "Pages Read: %d/%d", mf_ul_data->data_read / 4, mf_ul_data->data_size / 4); diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_success.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_success.c index 77034ea80..63bffbf36 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_success.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_success.c @@ -1,5 +1,4 @@ #include "../nfc_i.h" -#include void nfc_scene_mf_ultralight_read_success_widget_callback( GuiButtonType result, @@ -14,7 +13,6 @@ void nfc_scene_mf_ultralight_read_success_widget_callback( void nfc_scene_mf_ultralight_read_success_on_enter(void* context) { Nfc* nfc = context; - DOLPHIN_DEED(DolphinDeedNfcReadSuccess); // Setup widget view FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c index 58e081db9..514cd4e98 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c @@ -1,4 +1,5 @@ #include "../nfc_i.h" +#include void nfc_scene_mf_ultralight_unlock_warn_dialog_callback(DialogExResult result, void* context) { Nfc* nfc = context; @@ -30,6 +31,7 @@ bool nfc_scene_mf_ultralight_unlock_warn_on_event(void* context, SceneManagerEve if(event.type == SceneManagerEventTypeCustom) { if(event.event == DialogExResultCenter) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadAuth); + DOLPHIN_DEED(DolphinDeedNfcRead); consumed = true; } } diff --git a/applications/main/nfc/scenes/nfc_scene_nfca_menu.c b/applications/main/nfc/scenes/nfc_scene_nfca_menu.c index 00d0d943d..30f63945c 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfca_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_nfca_menu.c @@ -1,4 +1,5 @@ #include "../nfc_i.h" +#include enum SubmenuIndex { SubmenuIndexSaveUid, @@ -41,6 +42,11 @@ bool nfc_scene_nfca_menu_on_event(void* context, SceneManagerEvent event) { consumed = true; } else if(event.event == SubmenuIndexEmulateUid) { scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); + if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) { + DOLPHIN_DEED(DolphinDeedNfcAddEmulate); + } else { + DOLPHIN_DEED(DolphinDeedNfcEmulate); + } consumed = true; } else if(event.event == SubmenuIndexInfo) { scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); diff --git a/applications/main/nfc/scenes/nfc_scene_nfca_read_success.c b/applications/main/nfc/scenes/nfc_scene_nfca_read_success.c index 2ea7c9921..a38f31a98 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfca_read_success.c +++ b/applications/main/nfc/scenes/nfc_scene_nfca_read_success.c @@ -1,5 +1,4 @@ #include "../nfc_i.h" -#include void nfc_scene_nfca_read_success_widget_callback( GuiButtonType result, @@ -16,8 +15,6 @@ void nfc_scene_nfca_read_success_widget_callback( void nfc_scene_nfca_read_success_on_enter(void* context) { Nfc* nfc = context; - DOLPHIN_DEED(DolphinDeedNfcReadSuccess); - // Setup view FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; Widget* widget = nfc->widget; diff --git a/applications/main/nfc/scenes/nfc_scene_read.c b/applications/main/nfc/scenes/nfc_scene_read.c index e6df476f0..1f82aef08 100644 --- a/applications/main/nfc/scenes/nfc_scene_read.c +++ b/applications/main/nfc/scenes/nfc_scene_read.c @@ -39,7 +39,6 @@ void nfc_scene_read_set_state(Nfc* nfc, NfcSceneReadState state) { void nfc_scene_read_on_enter(void* context) { Nfc* nfc = context; - DOLPHIN_DEED(DolphinDeedNfcRead); nfc_device_clear(nfc->dev); // Setup view @@ -62,26 +61,32 @@ bool nfc_scene_read_on_event(void* context, SceneManagerEvent event) { (event.event == NfcWorkerEventReadUidNfcV)) { notification_message(nfc->notifications, &sequence_success); scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardSuccess); + DOLPHIN_DEED(DolphinDeedNfcReadSuccess); consumed = true; } else if(event.event == NfcWorkerEventReadUidNfcA) { notification_message(nfc->notifications, &sequence_success); scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcaReadSuccess); + DOLPHIN_DEED(DolphinDeedNfcReadSuccess); consumed = true; } else if(event.event == NfcWorkerEventReadMfUltralight) { notification_message(nfc->notifications, &sequence_success); scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadSuccess); + DOLPHIN_DEED(DolphinDeedNfcReadSuccess); consumed = true; } else if(event.event == NfcWorkerEventReadMfClassicDone) { notification_message(nfc->notifications, &sequence_success); scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSuccess); + DOLPHIN_DEED(DolphinDeedNfcReadSuccess); consumed = true; } else if(event.event == NfcWorkerEventReadMfDesfire) { notification_message(nfc->notifications, &sequence_success); scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireReadSuccess); + DOLPHIN_DEED(DolphinDeedNfcReadSuccess); consumed = true; } else if(event.event == NfcWorkerEventReadBankCard) { notification_message(nfc->notifications, &sequence_success); scene_manager_next_scene(nfc->scene_manager, NfcSceneEmvReadSuccess); + DOLPHIN_DEED(DolphinDeedNfcReadSuccess); consumed = true; } else if(event.event == NfcWorkerEventReadMfClassicDictAttackRequired) { if(mf_classic_dict_check_presence(MfClassicDictTypeFlipper)) { diff --git a/applications/main/nfc/scenes/nfc_scene_read_card_success.c b/applications/main/nfc/scenes/nfc_scene_read_card_success.c index 352cb4a7e..9b2a2188e 100644 --- a/applications/main/nfc/scenes/nfc_scene_read_card_success.c +++ b/applications/main/nfc/scenes/nfc_scene_read_card_success.c @@ -1,5 +1,4 @@ #include "../nfc_i.h" -#include void nfc_scene_read_card_success_widget_callback( GuiButtonType result, @@ -18,7 +17,6 @@ void nfc_scene_read_card_success_on_enter(void* context) { FuriString* temp_str; temp_str = furi_string_alloc(); - DOLPHIN_DEED(DolphinDeedNfcReadSuccess); // Setup view FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; diff --git a/applications/main/nfc/scenes/nfc_scene_save_name.c b/applications/main/nfc/scenes/nfc_scene_save_name.c index 736eab7de..791f8d99b 100644 --- a/applications/main/nfc/scenes/nfc_scene_save_name.c +++ b/applications/main/nfc/scenes/nfc_scene_save_name.c @@ -2,6 +2,7 @@ #include #include #include +#include void nfc_scene_save_name_text_input_callback(void* context) { Nfc* nfc = context; @@ -63,6 +64,13 @@ bool nfc_scene_save_name_on_event(void* context, SceneManagerEvent event) { strlcpy(nfc->dev->dev_name, nfc->text_store, strlen(nfc->text_store) + 1); if(nfc_device_save(nfc->dev, nfc->text_store)) { scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess); + if(!scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSavedMenu)) { + // Nothing, do not count editing as saving + } else if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) { + DOLPHIN_DEED(DolphinDeedNfcAddSave); + } else { + DOLPHIN_DEED(DolphinDeedNfcSave); + } consumed = true; } else { consumed = scene_manager_search_and_switch_to_previous_scene( diff --git a/applications/main/nfc/scenes/nfc_scene_save_success.c b/applications/main/nfc/scenes/nfc_scene_save_success.c index dcd2519f1..34919cbd8 100644 --- a/applications/main/nfc/scenes/nfc_scene_save_success.c +++ b/applications/main/nfc/scenes/nfc_scene_save_success.c @@ -1,5 +1,4 @@ #include "../nfc_i.h" -#include void nfc_scene_save_success_popup_callback(void* context) { Nfc* nfc = context; @@ -8,7 +7,6 @@ void nfc_scene_save_success_popup_callback(void* context) { void nfc_scene_save_success_on_enter(void* context) { Nfc* nfc = context; - DOLPHIN_DEED(DolphinDeedNfcSave); // Setup view Popup* popup = nfc->popup; diff --git a/applications/main/nfc/scenes/nfc_scene_saved_menu.c b/applications/main/nfc/scenes/nfc_scene_saved_menu.c index fe65b5b8a..231f12089 100644 --- a/applications/main/nfc/scenes/nfc_scene_saved_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_saved_menu.c @@ -1,8 +1,12 @@ #include "../nfc_i.h" +#include enum SubmenuIndex { SubmenuIndexEmulate, SubmenuIndexEditUid, + SubmenuIndexDetectReader, + SubmenuIndexWrite, + SubmenuIndexUpdate, SubmenuIndexRename, SubmenuIndexDelete, SubmenuIndexInfo, @@ -41,6 +45,28 @@ void nfc_scene_saved_menu_on_enter(void* context) { submenu_add_item( submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_saved_menu_submenu_callback, nfc); } + if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) { + if(!mf_classic_is_card_read(&nfc->dev->dev_data.mf_classic_data)) { + submenu_add_item( + submenu, + "Detect reader", + SubmenuIndexDetectReader, + nfc_scene_saved_menu_submenu_callback, + nfc); + } + submenu_add_item( + submenu, + "Write To Initial Card", + SubmenuIndexWrite, + nfc_scene_saved_menu_submenu_callback, + nfc); + submenu_add_item( + submenu, + "Update From Initial Card", + SubmenuIndexUpdate, + nfc_scene_saved_menu_submenu_callback, + nfc); + } submenu_add_item( submenu, "Info", SubmenuIndexInfo, nfc_scene_saved_menu_submenu_callback, nfc); if(nfc->dev->shadow_file_exist) { @@ -76,6 +102,16 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { } else { scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); } + DOLPHIN_DEED(DolphinDeedNfcEmulate); + consumed = true; + } else if(event.event == SubmenuIndexDetectReader) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneDetectReader); + consumed = true; + } else if(event.event == SubmenuIndexWrite) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicWrite); + consumed = true; + } else if(event.event == SubmenuIndexUpdate) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicUpdate); consumed = true; } else if(event.event == SubmenuIndexRename) { scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); diff --git a/applications/main/nfc/scenes/nfc_scene_set_uid.c b/applications/main/nfc/scenes/nfc_scene_set_uid.c index 9622ba213..1d3fb5eb9 100644 --- a/applications/main/nfc/scenes/nfc_scene_set_uid.c +++ b/applications/main/nfc/scenes/nfc_scene_set_uid.c @@ -1,5 +1,4 @@ #include "../nfc_i.h" -#include void nfc_scene_set_uid_byte_input_callback(void* context) { Nfc* nfc = context; @@ -30,7 +29,6 @@ bool nfc_scene_set_uid_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == NfcCustomEventByteInputDone) { - DOLPHIN_DEED(DolphinDeedNfcAddSave); if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSavedMenu)) { nfc->dev->dev_data.nfc_data = nfc->dev_edit_data; if(nfc_device_save(nfc->dev, nfc->dev->dev_name)) { diff --git a/applications/main/nfc/scenes/nfc_scene_start.c b/applications/main/nfc/scenes/nfc_scene_start.c index 1a9051dfd..028f85ae0 100644 --- a/applications/main/nfc/scenes/nfc_scene_start.c +++ b/applications/main/nfc/scenes/nfc_scene_start.c @@ -1,4 +1,5 @@ #include "../nfc_i.h" +#include enum SubmenuIndex { SubmenuIndexRead, @@ -47,11 +48,14 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubmenuIndexRead) { scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); + DOLPHIN_DEED(DolphinDeedNfcRead); consumed = true; } else if(event.event == SubmenuIndexDetectReader) { bool sd_exist = storage_sd_status(nfc->dev->storage) == FSE_OK; if(sd_exist) { + nfc_device_data_clear(&nfc->dev->dev_data); scene_manager_next_scene(nfc->scene_manager, NfcSceneDetectReader); + DOLPHIN_DEED(DolphinDeedNfcDetectReader); } else { scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound); } diff --git a/applications/main/nfc/views/detect_reader.c b/applications/main/nfc/views/detect_reader.c index 2dbb4338b..e5951beb2 100644 --- a/applications/main/nfc/views/detect_reader.c +++ b/applications/main/nfc/views/detect_reader.c @@ -1,7 +1,9 @@ #include "detect_reader.h" - +#include #include +#define DETECT_READER_UID_MAX_LEN (10) + struct DetectReader { View* view; DetectReaderDoneCallback callback; @@ -12,6 +14,7 @@ typedef struct { uint16_t nonces; uint16_t nonces_max; DetectReaderState state; + FuriString* uid_str; } DetectReaderViewModel; static void detect_reader_draw_callback(Canvas* canvas, void* model) { @@ -23,6 +26,10 @@ static void detect_reader_draw_callback(Canvas* canvas, void* model) { if(m->state == DetectReaderStateStart) { snprintf(text, sizeof(text), "Touch the reader"); canvas_draw_icon(canvas, 21, 13, &I_Move_flipper_26x39); + if(furi_string_size(m->uid_str)) { + elements_multiline_text_aligned( + canvas, 64, 64, AlignCenter, AlignBottom, furi_string_get_cstr(m->uid_str)); + } } else if(m->state == DetectReaderStateReaderDetected) { snprintf(text, sizeof(text), "Move the Flipper away"); canvas_draw_icon(canvas, 24, 25, &I_Release_arrow_18x15); @@ -86,12 +93,24 @@ DetectReader* detect_reader_alloc() { view_set_input_callback(detect_reader->view, detect_reader_input_callback); view_set_context(detect_reader->view, detect_reader); + with_view_model( + detect_reader->view, + DetectReaderViewModel * model, + { model->uid_str = furi_string_alloc(); }, + false); + return detect_reader; } void detect_reader_free(DetectReader* detect_reader) { furi_assert(detect_reader); + with_view_model( + detect_reader->view, + DetectReaderViewModel * model, + { furi_string_free(model->uid_str); }, + false); + view_free(detect_reader->view); free(detect_reader); } @@ -106,6 +125,7 @@ void detect_reader_reset(DetectReader* detect_reader) { model->nonces = 0; model->nonces_max = 0; model->state = DetectReaderStateStart; + furi_string_reset(model->uid_str); }, false); } @@ -152,3 +172,19 @@ void detect_reader_set_state(DetectReader* detect_reader, DetectReaderState stat with_view_model( detect_reader->view, DetectReaderViewModel * model, { model->state = state; }, true); } + +void detect_reader_set_uid(DetectReader* detect_reader, uint8_t* uid, uint8_t uid_len) { + furi_assert(detect_reader); + furi_assert(uid); + furi_assert(uid_len < DETECT_READER_UID_MAX_LEN); + with_view_model( + detect_reader->view, + DetectReaderViewModel * model, + { + furi_string_set_str(model->uid_str, "UID:"); + for(size_t i = 0; i < uid_len; i++) { + furi_string_cat_printf(model->uid_str, " %02X", uid[i]); + } + }, + true); +} diff --git a/applications/main/nfc/views/detect_reader.h b/applications/main/nfc/views/detect_reader.h index aabdd7c87..6481216b4 100644 --- a/applications/main/nfc/views/detect_reader.h +++ b/applications/main/nfc/views/detect_reader.h @@ -32,3 +32,5 @@ void detect_reader_set_nonces_max(DetectReader* detect_reader, uint16_t nonces_m void detect_reader_set_nonces_collected(DetectReader* detect_reader, uint16_t nonces_collected); void detect_reader_set_state(DetectReader* detect_reader, DetectReaderState state); + +void detect_reader_set_uid(DetectReader* detect_reader, uint8_t* uid, uint8_t uid_len); diff --git a/applications/main/subghz/scenes/subghz_scene_frequency_analyzer.c b/applications/main/subghz/scenes/subghz_scene_frequency_analyzer.c index 9595c61be..b48a821da 100644 --- a/applications/main/subghz/scenes/subghz_scene_frequency_analyzer.c +++ b/applications/main/subghz/scenes/subghz_scene_frequency_analyzer.c @@ -1,6 +1,5 @@ #include "../subghz_i.h" #include "../views/subghz_frequency_analyzer.h" -#include void subghz_scene_frequency_analyzer_callback(SubGhzCustomEvent event, void* context) { furi_assert(context); @@ -10,7 +9,6 @@ void subghz_scene_frequency_analyzer_callback(SubGhzCustomEvent event, void* con void subghz_scene_frequency_analyzer_on_enter(void* context) { SubGhz* subghz = context; - DOLPHIN_DEED(DolphinDeedSubGhzFrequencyAnalyzer); subghz_frequency_analyzer_set_callback( subghz->subghz_frequency_analyzer, subghz_scene_frequency_analyzer_callback, subghz); view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdFrequencyAnalyzer); diff --git a/applications/main/subghz/scenes/subghz_scene_read_raw.c b/applications/main/subghz/scenes/subghz_scene_read_raw.c index 5dacefd66..ba9ce803b 100644 --- a/applications/main/subghz/scenes/subghz_scene_read_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_read_raw.c @@ -6,6 +6,7 @@ #define RAW_FILE_NAME "Raw_signal_" #define TAG "SubGhzSceneReadRAW" +#define RAW_THRESHOLD_RSSI_LOW_COUNT 10 bool subghz_scene_read_raw_update_filename(SubGhz* subghz) { bool ret = false; @@ -72,24 +73,33 @@ void subghz_scene_read_raw_on_enter(void* context) { switch(subghz->txrx->rx_key_state) { case SubGhzRxKeyStateBack: - subghz_read_raw_set_status(subghz->subghz_read_raw, SubGhzReadRAWStatusIDLE, ""); + subghz_read_raw_set_status( + subghz->subghz_read_raw, SubGhzReadRAWStatusIDLE, "", subghz->txrx->raw_threshold_rssi); break; case SubGhzRxKeyStateRAWLoad: path_extract_filename(subghz->file_path, file_name, true); subghz_read_raw_set_status( subghz->subghz_read_raw, SubGhzReadRAWStatusLoadKeyTX, - furi_string_get_cstr(file_name)); + furi_string_get_cstr(file_name), + subghz->txrx->raw_threshold_rssi); subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; break; case SubGhzRxKeyStateRAWSave: path_extract_filename(subghz->file_path, file_name, true); subghz_read_raw_set_status( - subghz->subghz_read_raw, SubGhzReadRAWStatusSaveKey, furi_string_get_cstr(file_name)); + subghz->subghz_read_raw, + SubGhzReadRAWStatusSaveKey, + furi_string_get_cstr(file_name), + subghz->txrx->raw_threshold_rssi); subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; break; default: - subghz_read_raw_set_status(subghz->subghz_read_raw, SubGhzReadRAWStatusStart, ""); + subghz_read_raw_set_status( + subghz->subghz_read_raw, + SubGhzReadRAWStatusStart, + "", + subghz->txrx->raw_threshold_rssi); subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; break; } @@ -213,7 +223,12 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { subghz->txrx->rx_key_state = SubGhzRxKeyStateBack; scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx); } else { - DOLPHIN_DEED(DolphinDeedSubGhzSend); + if(scene_manager_has_previous_scene( + subghz->scene_manager, SubGhzSceneSaved) || + !scene_manager_has_previous_scene( + subghz->scene_manager, SubGhzSceneStart)) { + DOLPHIN_DEED(DolphinDeedSubGhzSend); + } // set callback end tx subghz_protocol_raw_file_encoder_worker_set_callback_end( (SubGhzProtocolEncoderRAW*)subghz_transmitter_get_protocol_instance( @@ -273,7 +288,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { if(subghz->txrx->rx_key_state != SubGhzRxKeyStateIDLE) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving); } else { - //subghz_get_preset_name(subghz, subghz->error_str); + subghz->txrx->raw_threshold_rssi_low_count = RAW_THRESHOLD_RSSI_LOW_COUNT; if(subghz_protocol_raw_save_to_file_init( (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result, RAW_FILE_NAME, @@ -319,7 +334,35 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { subghz->subghz_read_raw, subghz_protocol_raw_get_sample_write( (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result)); - subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, furi_hal_subghz_get_rssi()); + + float rssi = furi_hal_subghz_get_rssi(); + + if(subghz->txrx->raw_threshold_rssi == SUBGHZ_RAW_TRESHOLD_MIN) { + subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, rssi, true); + subghz_protocol_raw_save_to_file_pause( + (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result, false); + } else { + if(rssi < subghz->txrx->raw_threshold_rssi) { + subghz->txrx->raw_threshold_rssi_low_count++; + if(subghz->txrx->raw_threshold_rssi_low_count > RAW_THRESHOLD_RSSI_LOW_COUNT) { + subghz->txrx->raw_threshold_rssi_low_count = RAW_THRESHOLD_RSSI_LOW_COUNT; + } + subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, rssi, false); + } else { + subghz->txrx->raw_threshold_rssi_low_count = 0; + } + + if(subghz->txrx->raw_threshold_rssi_low_count == RAW_THRESHOLD_RSSI_LOW_COUNT) { + subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, rssi, false); + subghz_protocol_raw_save_to_file_pause( + (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result, true); + } else { + subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, rssi, true); + subghz_protocol_raw_save_to_file_pause( + (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result, false); + } + } + break; case SubGhzNotificationStateTx: notification_message(subghz->notifications, &sequence_blink_magenta_10); diff --git a/applications/main/subghz/scenes/subghz_scene_receiver.c b/applications/main/subghz/scenes/subghz_scene_receiver.c index 77a921457..2b01e2975 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver.c @@ -1,5 +1,6 @@ #include "../subghz_i.h" #include "../views/receiver.h" +#include static const NotificationSequence subghs_sequence_rx = { &message_green_255, @@ -181,6 +182,7 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { subghz->txrx->idx_menu_chosen = subghz_view_receiver_get_idx_menu(subghz->subghz_receiver); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverInfo); + DOLPHIN_DEED(DolphinDeedSubGhzReceiverInfo); consumed = true; break; case SubGhzCustomEventViewReceiverConfig: diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_config.c b/applications/main/subghz/scenes/subghz_scene_receiver_config.c index 5f022d6e1..fd42829b5 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_config.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_config.c @@ -1,10 +1,41 @@ #include "../subghz_i.h" +#include enum SubGhzSettingIndex { SubGhzSettingIndexFrequency, SubGhzSettingIndexHopping, SubGhzSettingIndexModulation, SubGhzSettingIndexLock, + SubGhzSettingIndexRAWThesholdRSSI, +}; + +#define RAW_THRESHOLD_RSSI_COUNT 11 +const char* const raw_theshold_rssi_text[RAW_THRESHOLD_RSSI_COUNT] = { + "-----", + "-85.0", + "-80.0", + "-75.0", + "-70.0", + "-65.0", + "-60.0", + "-55.0", + "-50.0", + "-45.0", + "-40.0", + +}; +const float raw_theshold_rssi_value[RAW_THRESHOLD_RSSI_COUNT] = { + -90.0f, + -85.0f, + -80.0f, + -75.0f, + -70.0f, + -65.0f, + -60.0f, + -55.0f, + -50.0f, + -45.0f, + -40.0f, }; #define HOPPING_COUNT 2 @@ -136,6 +167,14 @@ static void subghz_scene_receiver_config_set_hopping_running(VariableItem* item) subghz->txrx->hopper_state = hopping_value[index]; } +static void subghz_scene_receiver_config_set_raw_threshold_rssi(VariableItem* item) { + SubGhz* subghz = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + + variable_item_set_current_value_text(item, raw_theshold_rssi_text[index]); + subghz->txrx->raw_threshold_rssi = raw_theshold_rssi_value[index]; +} + static void subghz_scene_receiver_config_var_list_enter_callback(void* context, uint32_t index) { furi_assert(context); SubGhz* subghz = context; @@ -204,6 +243,19 @@ void subghz_scene_receiver_config_on_enter(void* context) { subghz_scene_receiver_config_var_list_enter_callback, subghz); } + if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) == + SubGhzCustomEventManagerSet) { + item = variable_item_list_add( + subghz->variable_item_list, + "RSSI Threshold:", + RAW_THRESHOLD_RSSI_COUNT, + subghz_scene_receiver_config_set_raw_threshold_rssi, + subghz); + value_index = value_index_float( + subghz->txrx->raw_threshold_rssi, raw_theshold_rssi_value, RAW_THRESHOLD_RSSI_COUNT); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, raw_theshold_rssi_text[value_index]); + } view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdVariableItemList); } diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_info.c b/applications/main/subghz/scenes/subghz_scene_receiver_info.c index 03a8ebbcb..bc6c8f112 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_info.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_info.c @@ -1,6 +1,5 @@ #include "../subghz_i.h" #include "../helpers/subghz_custom_event.h" -#include void subghz_scene_receiver_info_callback(GuiButtonType result, InputType type, void* context) { furi_assert(context); @@ -45,7 +44,6 @@ static bool subghz_scene_receiver_info_update_parser(void* context) { void subghz_scene_receiver_info_on_enter(void* context) { SubGhz* subghz = context; - DOLPHIN_DEED(DolphinDeedSubGhzReceiverInfo); if(subghz_scene_receiver_info_update_parser(subghz)) { FuriString* frequency_str; FuriString* modulation_str; diff --git a/applications/main/subghz/scenes/subghz_scene_save_name.c b/applications/main/subghz/scenes/subghz_scene_save_name.c index dfcb65865..33846c283 100644 --- a/applications/main/subghz/scenes/subghz_scene_save_name.c +++ b/applications/main/subghz/scenes/subghz_scene_save_name.c @@ -4,6 +4,7 @@ #include "../helpers/subghz_custom_event.h" #include #include +#include #define MAX_TEXT_INPUT_LEN 22 @@ -131,6 +132,17 @@ bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) { } scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveSuccess); + if(scene_manager_has_previous_scene(subghz->scene_manager, SubGhzSceneSavedMenu)) { + // Nothing, do not count editing as saving + } else if(scene_manager_has_previous_scene( + subghz->scene_manager, SubGhzSceneMoreRAW)) { + // Ditto, for RAW signals + } else if(scene_manager_has_previous_scene( + subghz->scene_manager, SubGhzSceneSetType)) { + DOLPHIN_DEED(DolphinDeedSubGhzAddManually); + } else { + DOLPHIN_DEED(DolphinDeedSubGhzSave); + } return true; } else { furi_string_set(subghz->error_str, "No name file"); diff --git a/applications/main/subghz/scenes/subghz_scene_save_success.c b/applications/main/subghz/scenes/subghz_scene_save_success.c index 3d5c16ca3..d32c9271a 100644 --- a/applications/main/subghz/scenes/subghz_scene_save_success.c +++ b/applications/main/subghz/scenes/subghz_scene_save_success.c @@ -1,7 +1,5 @@ #include "../subghz_i.h" #include "../helpers/subghz_custom_event.h" -#include -#include void subghz_scene_save_success_popup_callback(void* context) { SubGhz* subghz = context; @@ -10,7 +8,6 @@ void subghz_scene_save_success_popup_callback(void* context) { void subghz_scene_save_success_on_enter(void* context) { SubGhz* subghz = context; - DOLPHIN_DEED(DolphinDeedSubGhzSave); // Setup view Popup* popup = subghz->popup; diff --git a/applications/main/subghz/scenes/subghz_scene_set_type.c b/applications/main/subghz/scenes/subghz_scene_set_type.c index 44fe2fc76..2ed537193 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_type.c +++ b/applications/main/subghz/scenes/subghz_scene_set_type.c @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include @@ -381,7 +380,6 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { if(generated_protocol) { subghz_file_name_clear(subghz); - DOLPHIN_DEED(DolphinDeedSubGhzAddManually); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); return true; } diff --git a/applications/main/subghz/scenes/subghz_scene_start.c b/applications/main/subghz/scenes/subghz_scene_start.c index f37ccae9e..0b1c3c159 100644 --- a/applications/main/subghz/scenes/subghz_scene_start.c +++ b/applications/main/subghz/scenes/subghz_scene_start.c @@ -1,4 +1,5 @@ #include "../subghz_i.h" +#include enum SubmenuIndex { SubmenuIndexRead = 10, @@ -84,6 +85,7 @@ bool subghz_scene_start_on_event(void* context, SceneManagerEvent event) { scene_manager_set_scene_state( subghz->scene_manager, SubGhzSceneStart, SubmenuIndexFrequencyAnalyzer); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneFrequencyAnalyzer); + DOLPHIN_DEED(DolphinDeedSubGhzFrequencyAnalyzer); return true; } else if(event.event == SubmenuIndexTest) { scene_manager_set_scene_state( diff --git a/applications/main/subghz/scenes/subghz_scene_transmitter.c b/applications/main/subghz/scenes/subghz_scene_transmitter.c index 5da6f4300..fbe954f0c 100644 --- a/applications/main/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/main/subghz/scenes/subghz_scene_transmitter.c @@ -50,7 +50,6 @@ bool subghz_scene_transmitter_update_data_show(void* context) { void subghz_scene_transmitter_on_enter(void* context) { SubGhz* subghz = context; - DOLPHIN_DEED(DolphinDeedSubGhzSend); if(!subghz_scene_transmitter_update_data_show(subghz)) { view_dispatcher_send_custom_event( subghz->view_dispatcher, SubGhzCustomEventViewTransmitterError); @@ -78,6 +77,7 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { } else { subghz->state_notifications = SubGhzNotificationStateTx; subghz_scene_transmitter_update_data_show(subghz); + DOLPHIN_DEED(DolphinDeedSubGhzSend); } } return true; diff --git a/applications/main/subghz/subghz.c b/applications/main/subghz/subghz.c index ba70f36d1..df5a76525 100644 --- a/applications/main/subghz/subghz.c +++ b/applications/main/subghz/subghz.c @@ -178,6 +178,7 @@ SubGhz* subghz_alloc() { subghz->txrx->txrx_state = SubGhzTxRxStateSleep; subghz->txrx->hopper_state = SubGhzHopperStateOFF; subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; + subghz->txrx->raw_threshold_rssi = SUBGHZ_RAW_TRESHOLD_MIN; subghz->txrx->history = subghz_history_alloc(); subghz->txrx->worker = subghz_worker_alloc(); subghz->txrx->fff_data = flipper_format_string_alloc(); diff --git a/applications/main/subghz/subghz_i.c b/applications/main/subghz/subghz_i.c index ac1036d05..beefd8024 100644 --- a/applications/main/subghz/subghz_i.c +++ b/applications/main/subghz/subghz_i.c @@ -102,8 +102,8 @@ static bool subghz_tx(SubGhz* subghz, uint32_t frequency) { furi_assert(subghz->txrx->txrx_state != SubGhzTxRxStateSleep); furi_hal_subghz_idle(); furi_hal_subghz_set_frequency_and_path(frequency); + furi_hal_gpio_write(&gpio_cc1101_g0, false); furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); - furi_hal_gpio_write(&gpio_cc1101_g0, true); bool ret = furi_hal_subghz_tx(); subghz->txrx->txrx_state = SubGhzTxRxStateTx; return ret; diff --git a/applications/main/subghz/subghz_i.h b/applications/main/subghz/subghz_i.h index 284f7ccf5..46768cf02 100644 --- a/applications/main/subghz/subghz_i.h +++ b/applications/main/subghz/subghz_i.h @@ -13,6 +13,7 @@ #include "views/subghz_test_packet.h" #include +#include #include #include #include @@ -54,6 +55,9 @@ struct SubGhzTxRx { uint8_t hopper_timeout; uint8_t hopper_idx_frequency; SubGhzRxKeyState rx_key_state; + + float raw_threshold_rssi; + uint8_t raw_threshold_rssi_low_count; }; typedef struct SubGhzTxRx SubGhzTxRx; diff --git a/applications/main/subghz/views/subghz_read_raw.c b/applications/main/subghz/views/subghz_read_raw.c index 2d951b11a..6120a210b 100644 --- a/applications/main/subghz/views/subghz_read_raw.c +++ b/applications/main/subghz/views/subghz_read_raw.c @@ -23,10 +23,12 @@ typedef struct { FuriString* sample_write; FuriString* file_name; uint8_t* rssi_history; + uint8_t rssi_curret; bool rssi_history_end; uint8_t ind_write; uint8_t ind_sin; SubGhzReadRAWStatus status; + float raw_threshold_rssi; } SubGhzReadRAWModel; void subghz_read_raw_set_callback( @@ -54,21 +56,27 @@ void subghz_read_raw_add_data_statusbar( true); } -void subghz_read_raw_add_data_rssi(SubGhzReadRAW* instance, float rssi) { +void subghz_read_raw_add_data_rssi(SubGhzReadRAW* instance, float rssi, bool trace) { furi_assert(instance); uint8_t u_rssi = 0; - if(rssi < -90) { + if(rssi < SUBGHZ_RAW_TRESHOLD_MIN) { u_rssi = 0; } else { - u_rssi = (uint8_t)((rssi + 90) / 2.7); + u_rssi = (uint8_t)((rssi - SUBGHZ_RAW_TRESHOLD_MIN) / 2.7); } with_view_model( instance->view, SubGhzReadRAWModel * model, { - model->rssi_history[model->ind_write++] = u_rssi; + model->rssi_curret = u_rssi; + if(trace) { + model->rssi_history[model->ind_write++] = u_rssi; + } else { + model->rssi_history[model->ind_write] = u_rssi; + } + if(model->ind_write > SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE) { model->rssi_history_end = true; model->ind_write = 0; @@ -187,24 +195,53 @@ void subghz_read_raw_draw_scale(Canvas* canvas, SubGhzReadRAWModel* model) { void subghz_read_raw_draw_rssi(Canvas* canvas, SubGhzReadRAWModel* model) { int ind = 0; int base = 0; + uint8_t width = 2; if(model->rssi_history_end == false) { for(int i = model->ind_write; i >= 0; i--) { canvas_draw_line(canvas, i, 47, i, 47 - model->rssi_history[i]); } + canvas_draw_line( + canvas, model->ind_write + 1, 47, model->ind_write + 1, 47 - model->rssi_curret); if(model->ind_write > 3) { - canvas_draw_line(canvas, model->ind_write, 47, model->ind_write, 13); + canvas_draw_line( + canvas, model->ind_write - 1, 47, model->ind_write - 1, 47 - model->rssi_curret); + + for(uint8_t i = 13; i < 47; i += width * 2) { + canvas_draw_line(canvas, model->ind_write, i, model->ind_write, i + width); + } canvas_draw_line(canvas, model->ind_write - 2, 12, model->ind_write + 2, 12); canvas_draw_line(canvas, model->ind_write - 1, 13, model->ind_write + 1, 13); } } else { + int i = 0; base = SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE - model->ind_write; - for(int i = SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE; i >= 0; i--) { + for(i = SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE; i > 0; i--) { ind = i - base; if(ind < 0) ind += SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE; canvas_draw_line(canvas, i, 47, i, 47 - model->rssi_history[ind]); } + canvas_draw_line( - canvas, SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE, 47, SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE, 13); + canvas, + SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE - 1, + 47, + SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE - 1, + 47 - model->rssi_curret); + canvas_draw_line( + canvas, + SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE + 1, + 47, + SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE + 1, + 47 - model->rssi_curret); + + for(uint8_t i = 13; i < 47; i += width * 2) { + canvas_draw_line( + canvas, + SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE, + i, + SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE, + i + width); + } canvas_draw_line( canvas, SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE - 2, @@ -220,6 +257,24 @@ void subghz_read_raw_draw_rssi(Canvas* canvas, SubGhzReadRAWModel* model) { } } +void subghz_read_raw_draw_threshold_rssi(Canvas* canvas, SubGhzReadRAWModel* model) { + uint8_t x = 118; + uint8_t y = 48; + + if(model->raw_threshold_rssi > SUBGHZ_RAW_TRESHOLD_MIN) { + uint8_t x = 118; + y -= (uint8_t)((model->raw_threshold_rssi - SUBGHZ_RAW_TRESHOLD_MIN) / 2.7); + + uint8_t width = 3; + for(uint8_t i = 0; i < x; i += width * 2) { + canvas_draw_line(canvas, i, y, i + width, y); + } + } + canvas_draw_line(canvas, x, y - 2, x, y + 2); + canvas_draw_line(canvas, x - 1, y - 1, x - 1, y + 1); + canvas_draw_dot(canvas, x - 2, y); +} + void subghz_read_raw_draw(Canvas* canvas, SubGhzReadRAWModel* model) { uint8_t graphics_mode = 1; canvas_set_color(canvas, ColorBlack); @@ -278,8 +333,9 @@ void subghz_read_raw_draw(Canvas* canvas, SubGhzReadRAWModel* model) { } else { subghz_read_raw_draw_rssi(canvas, model); subghz_read_raw_draw_scale(canvas, model); + subghz_read_raw_draw_threshold_rssi(canvas, model); canvas_set_font_direction(canvas, CanvasDirectionBottomToTop); - canvas_draw_str(canvas, 126, 40, "RSSI"); + canvas_draw_str(canvas, 128, 40, "RSSI"); canvas_set_font_direction(canvas, CanvasDirectionLeftToRight); } } @@ -433,7 +489,8 @@ bool subghz_read_raw_input(InputEvent* event, void* context) { void subghz_read_raw_set_status( SubGhzReadRAW* instance, SubGhzReadRAWStatus status, - const char* file_name) { + const char* file_name, + float raw_threshold_rssi) { furi_assert(instance); switch(status) { @@ -447,6 +504,7 @@ void subghz_read_raw_set_status( model->ind_write = 0; furi_string_reset(model->file_name); furi_string_set(model->sample_write, "0 spl."); + model->raw_threshold_rssi = raw_threshold_rssi; }, true); break; @@ -536,6 +594,7 @@ SubGhzReadRAW* subghz_read_raw_alloc() { model->sample_write = furi_string_alloc(); model->file_name = furi_string_alloc(); model->rssi_history = malloc(SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE * sizeof(uint8_t)); + model->raw_threshold_rssi = -127.0f; }, true); diff --git a/applications/main/subghz/views/subghz_read_raw.h b/applications/main/subghz/views/subghz_read_raw.h index 1d4bb7dc0..bc8711923 100644 --- a/applications/main/subghz/views/subghz_read_raw.h +++ b/applications/main/subghz/views/subghz_read_raw.h @@ -3,6 +3,8 @@ #include #include "../helpers/subghz_custom_event.h" +#define SUBGHZ_RAW_TRESHOLD_MIN -90.0f + typedef struct SubGhzReadRAW SubGhzReadRAW; typedef void (*SubGhzReadRAWCallback)(SubGhzCustomEvent event, void* context); @@ -40,11 +42,12 @@ void subghz_read_raw_stop_send(SubGhzReadRAW* instance); void subghz_read_raw_update_sin(SubGhzReadRAW* instance); -void subghz_read_raw_add_data_rssi(SubGhzReadRAW* instance, float rssi); +void subghz_read_raw_add_data_rssi(SubGhzReadRAW* instance, float rssi, bool trace); void subghz_read_raw_set_status( SubGhzReadRAW* instance, SubGhzReadRAWStatus status, - const char* file_name); + const char* file_name, + float raw_threshold_rssi); View* subghz_read_raw_get_view(SubGhzReadRAW* subghz_static); diff --git a/applications/main/u2f/u2f_app_i.h b/applications/main/u2f/u2f_app_i.h index 53647859a..2896684c3 100644 --- a/applications/main/u2f/u2f_app_i.h +++ b/applications/main/u2f/u2f_app_i.h @@ -4,6 +4,7 @@ #include "scenes/u2f_scene.h" #include +#include #include #include #include diff --git a/applications/main/u2f/views/u2f_view.c b/applications/main/u2f/views/u2f_view.c index fa3d6cc24..181c495d0 100644 --- a/applications/main/u2f/views/u2f_view.c +++ b/applications/main/u2f/views/u2f_view.c @@ -1,5 +1,6 @@ #include "u2f_view.h" #include +#include struct U2fView { View* view; diff --git a/applications/plugins/bt_hid_app/assets/ButtonDown_7x4.png b/applications/plugins/bt_hid_app/assets/ButtonDown_7x4.png new file mode 100644 index 000000000..2954bb6a6 Binary files /dev/null and b/applications/plugins/bt_hid_app/assets/ButtonDown_7x4.png differ diff --git a/applications/plugins/bt_hid_app/assets/ButtonLeft_4x7.png b/applications/plugins/bt_hid_app/assets/ButtonLeft_4x7.png new file mode 100644 index 000000000..0b4655d43 Binary files /dev/null and b/applications/plugins/bt_hid_app/assets/ButtonLeft_4x7.png differ diff --git a/applications/plugins/bt_hid_app/assets/ButtonRight_4x7.png b/applications/plugins/bt_hid_app/assets/ButtonRight_4x7.png new file mode 100644 index 000000000..8e1c74c1c Binary files /dev/null and b/applications/plugins/bt_hid_app/assets/ButtonRight_4x7.png differ diff --git a/applications/plugins/bt_hid_app/assets/ButtonUp_7x4.png b/applications/plugins/bt_hid_app/assets/ButtonUp_7x4.png new file mode 100644 index 000000000..1be79328b Binary files /dev/null and b/applications/plugins/bt_hid_app/assets/ButtonUp_7x4.png differ diff --git a/applications/plugins/bt_hid_app/assets/Ok_btn_9x9.png b/applications/plugins/bt_hid_app/assets/Ok_btn_9x9.png new file mode 100644 index 000000000..9a1539da2 Binary files /dev/null and b/applications/plugins/bt_hid_app/assets/Ok_btn_9x9.png differ diff --git a/applications/plugins/bt_hid_app/assets/Pin_arrow_down_7x9.png b/applications/plugins/bt_hid_app/assets/Pin_arrow_down_7x9.png new file mode 100644 index 000000000..9687397af Binary files /dev/null and b/applications/plugins/bt_hid_app/assets/Pin_arrow_down_7x9.png differ diff --git a/applications/plugins/bt_hid_app/assets/Pin_arrow_left_9x7.png b/applications/plugins/bt_hid_app/assets/Pin_arrow_left_9x7.png new file mode 100644 index 000000000..fb4ded78f Binary files /dev/null and b/applications/plugins/bt_hid_app/assets/Pin_arrow_left_9x7.png differ diff --git a/applications/plugins/bt_hid_app/assets/Pin_arrow_right_9x7.png b/applications/plugins/bt_hid_app/assets/Pin_arrow_right_9x7.png new file mode 100644 index 000000000..97648d176 Binary files /dev/null and b/applications/plugins/bt_hid_app/assets/Pin_arrow_right_9x7.png differ diff --git a/applications/plugins/bt_hid_app/assets/Pin_arrow_up_7x9.png b/applications/plugins/bt_hid_app/assets/Pin_arrow_up_7x9.png new file mode 100644 index 000000000..a91a6fd5e Binary files /dev/null and b/applications/plugins/bt_hid_app/assets/Pin_arrow_up_7x9.png differ diff --git a/applications/plugins/bt_hid_app/assets/Pin_back_arrow_10x8.png b/applications/plugins/bt_hid_app/assets/Pin_back_arrow_10x8.png new file mode 100644 index 000000000..3bafabd14 Binary files /dev/null and b/applications/plugins/bt_hid_app/assets/Pin_back_arrow_10x8.png differ diff --git a/applications/plugins/bt_hid_app/views/bt_hid_tiktok.c b/applications/plugins/bt_hid_app/views/bt_hid_tiktok.c index 9af00157d..fe1005b2d 100644 --- a/applications/plugins/bt_hid_app/views/bt_hid_tiktok.c +++ b/applications/plugins/bt_hid_app/views/bt_hid_tiktok.c @@ -17,6 +17,7 @@ typedef struct { bool down_pressed; bool ok_pressed; bool connected; + bool is_cursor_set; } BtHidTikTokModel; static void bt_hid_tiktok_draw_callback(Canvas* canvas, void* context) { @@ -88,48 +89,48 @@ static void bt_hid_tiktok_draw_callback(Canvas* canvas, void* context) { elements_multiline_text_aligned(canvas, 13, 62, AlignLeft, AlignBottom, "Hold to exit"); } -static void bt_hid_tiktok_process_press(BtHidTikTok* bt_hid_tiktok, InputEvent* event) { - with_view_model( - bt_hid_tiktok->view, - BtHidTikTokModel * model, - { - if(event->key == InputKeyUp) { - model->up_pressed = true; - } else if(event->key == InputKeyDown) { - model->down_pressed = true; - } else if(event->key == InputKeyLeft) { - model->left_pressed = true; - furi_hal_bt_hid_consumer_key_press(HID_CONSUMER_VOLUME_DECREMENT); - } else if(event->key == InputKeyRight) { - model->right_pressed = true; - furi_hal_bt_hid_consumer_key_press(HID_CONSUMER_VOLUME_INCREMENT); - } else if(event->key == InputKeyOk) { - model->ok_pressed = true; - } - }, - true); +static void bt_hid_tiktok_reset_cursor() { + // Set cursor to the phone's left up corner + // Delays to guarantee one packet per connection interval + for(size_t i = 0; i < 8; i++) { + furi_hal_bt_hid_mouse_move(-127, -127); + furi_delay_ms(50); + } + // Move cursor from the corner + furi_hal_bt_hid_mouse_move(20, 120); + furi_delay_ms(50); } -static void bt_hid_tiktok_process_release(BtHidTikTok* bt_hid_tiktok, InputEvent* event) { - with_view_model( - bt_hid_tiktok->view, - BtHidTikTokModel * model, - { - if(event->key == InputKeyUp) { - model->up_pressed = false; - } else if(event->key == InputKeyDown) { - model->down_pressed = false; - } else if(event->key == InputKeyLeft) { - model->left_pressed = false; - furi_hal_bt_hid_consumer_key_release(HID_CONSUMER_VOLUME_DECREMENT); - } else if(event->key == InputKeyRight) { - model->right_pressed = false; - furi_hal_bt_hid_consumer_key_release(HID_CONSUMER_VOLUME_INCREMENT); - } else if(event->key == InputKeyOk) { - model->ok_pressed = false; - } - }, - true); +static void bt_hid_tiktok_process_press(BtHidTikTokModel* model, InputEvent* event) { + if(event->key == InputKeyUp) { + model->up_pressed = true; + } else if(event->key == InputKeyDown) { + model->down_pressed = true; + } else if(event->key == InputKeyLeft) { + model->left_pressed = true; + furi_hal_bt_hid_consumer_key_press(HID_CONSUMER_VOLUME_DECREMENT); + } else if(event->key == InputKeyRight) { + model->right_pressed = true; + furi_hal_bt_hid_consumer_key_press(HID_CONSUMER_VOLUME_INCREMENT); + } else if(event->key == InputKeyOk) { + model->ok_pressed = true; + } +} + +static void bt_hid_tiktok_process_release(BtHidTikTokModel* model, InputEvent* event) { + if(event->key == InputKeyUp) { + model->up_pressed = false; + } else if(event->key == InputKeyDown) { + model->down_pressed = false; + } else if(event->key == InputKeyLeft) { + model->left_pressed = false; + furi_hal_bt_hid_consumer_key_release(HID_CONSUMER_VOLUME_DECREMENT); + } else if(event->key == InputKeyRight) { + model->right_pressed = false; + furi_hal_bt_hid_consumer_key_release(HID_CONSUMER_VOLUME_INCREMENT); + } else if(event->key == InputKeyOk) { + model->ok_pressed = false; + } } static bool bt_hid_tiktok_input_callback(InputEvent* event, void* context) { @@ -137,43 +138,59 @@ static bool bt_hid_tiktok_input_callback(InputEvent* event, void* context) { BtHidTikTok* bt_hid_tiktok = context; bool consumed = false; - if(event->type == InputTypePress) { - bt_hid_tiktok_process_press(bt_hid_tiktok, event); - consumed = true; - } else if(event->type == InputTypeRelease) { - bt_hid_tiktok_process_release(bt_hid_tiktok, event); - consumed = true; - } else if(event->type == InputTypeShort) { - if(event->key == InputKeyOk) { - furi_hal_bt_hid_mouse_press(HID_MOUSE_BTN_LEFT); - furi_delay_ms(50); - furi_hal_bt_hid_mouse_release(HID_MOUSE_BTN_LEFT); - furi_delay_ms(50); - furi_hal_bt_hid_mouse_press(HID_MOUSE_BTN_LEFT); - furi_delay_ms(50); - furi_hal_bt_hid_mouse_release(HID_MOUSE_BTN_LEFT); - consumed = true; - } else if(event->key == InputKeyUp) { - // Emulate up swipe - furi_hal_bt_hid_mouse_scroll(-6); - furi_hal_bt_hid_mouse_scroll(-12); - furi_hal_bt_hid_mouse_scroll(-19); - furi_hal_bt_hid_mouse_scroll(-12); - furi_hal_bt_hid_mouse_scroll(-6); - consumed = true; - } else if(event->key == InputKeyDown) { - // Emulate down swipe - furi_hal_bt_hid_mouse_scroll(6); - furi_hal_bt_hid_mouse_scroll(12); - furi_hal_bt_hid_mouse_scroll(19); - furi_hal_bt_hid_mouse_scroll(12); - furi_hal_bt_hid_mouse_scroll(6); - consumed = true; - } else if(event->key == InputKeyBack) { - furi_hal_bt_hid_consumer_key_release_all(); - consumed = true; - } - } + with_view_model( + bt_hid_tiktok->view, + BtHidTikTokModel * model, + { + if(event->type == InputTypePress) { + bt_hid_tiktok_process_press(model, event); + if(model->connected && !model->is_cursor_set) { + bt_hid_tiktok_reset_cursor(); + model->is_cursor_set = true; + } + consumed = true; + } else if(event->type == InputTypeRelease) { + bt_hid_tiktok_process_release(model, event); + consumed = true; + } else if(event->type == InputTypeShort) { + if(event->key == InputKeyOk) { + furi_hal_bt_hid_mouse_press(HID_MOUSE_BTN_LEFT); + furi_delay_ms(50); + furi_hal_bt_hid_mouse_release(HID_MOUSE_BTN_LEFT); + furi_delay_ms(50); + furi_hal_bt_hid_mouse_press(HID_MOUSE_BTN_LEFT); + furi_delay_ms(50); + furi_hal_bt_hid_mouse_release(HID_MOUSE_BTN_LEFT); + consumed = true; + } else if(event->key == InputKeyUp) { + // Emulate up swipe + furi_hal_bt_hid_mouse_scroll(-6); + furi_hal_bt_hid_mouse_scroll(-12); + furi_hal_bt_hid_mouse_scroll(-19); + furi_hal_bt_hid_mouse_scroll(-12); + furi_hal_bt_hid_mouse_scroll(-6); + consumed = true; + } else if(event->key == InputKeyDown) { + // Emulate down swipe + furi_hal_bt_hid_mouse_scroll(6); + furi_hal_bt_hid_mouse_scroll(12); + furi_hal_bt_hid_mouse_scroll(19); + furi_hal_bt_hid_mouse_scroll(12); + furi_hal_bt_hid_mouse_scroll(6); + consumed = true; + } else if(event->key == InputKeyBack) { + furi_hal_bt_hid_consumer_key_release_all(); + consumed = true; + } + } else if(event->type == InputTypeLong) { + if(event->key == InputKeyBack) { + furi_hal_bt_hid_consumer_key_release_all(); + model->is_cursor_set = false; + consumed = false; + } + } + }, + true); return consumed; } @@ -203,5 +220,11 @@ View* bt_hid_tiktok_get_view(BtHidTikTok* bt_hid_tiktok) { void bt_hid_tiktok_set_connected_status(BtHidTikTok* bt_hid_tiktok, bool connected) { furi_assert(bt_hid_tiktok); with_view_model( - bt_hid_tiktok->view, BtHidTikTokModel * model, { model->connected = connected; }, true); + bt_hid_tiktok->view, + BtHidTikTokModel * model, + { + model->connected = connected; + model->is_cursor_set = false; + }, + true); } diff --git a/applications/plugins/dap_link/gui/scenes/dap_scene_help.c b/applications/plugins/dap_link/gui/scenes/dap_scene_help.c index 7193f4f4b..d8d70e7ff 100644 --- a/applications/plugins/dap_link/gui/scenes/dap_scene_help.c +++ b/applications/plugins/dap_link/gui/scenes/dap_scene_help.c @@ -72,13 +72,13 @@ void dap_scene_help_on_enter(void* context) { if(config->uart_swap == DapUartTXRXNormal) { furi_string_cat( string, - " TX: 15 [С1]\r\n" - " RX: 16 [С0]\r\n"); + " TX: 15 [C1]\r\n" + " RX: 16 [C0]\r\n"); } else { furi_string_cat( string, - " RX: 15 [С1]\r\n" - " TX: 16 [С0]\r\n"); + " RX: 15 [C1]\r\n" + " TX: 16 [C0]\r\n"); } break; default: diff --git a/applications/plugins/music_player/application.fam b/applications/plugins/music_player/application.fam index 76787e097..a36988983 100644 --- a/applications/plugins/music_player/application.fam +++ b/applications/plugins/music_player/application.fam @@ -11,8 +11,9 @@ App( provides=["music_player_start"], stack_size=2 * 1024, order=20, - fap_icon="../../../assets/icons/Archive/music_10px.png", + fap_icon="icons/music_10px.png", fap_category="Misc", + fap_icon_assets="icons", ) App( diff --git a/applications/plugins/music_player/icons/music_10px.png b/applications/plugins/music_player/icons/music_10px.png new file mode 100644 index 000000000..d41eb0db8 Binary files /dev/null and b/applications/plugins/music_player/icons/music_10px.png differ diff --git a/applications/plugins/music_player/music_player.c b/applications/plugins/music_player/music_player.c index 192500c2e..28872284b 100644 --- a/applications/plugins/music_player/music_player.c +++ b/applications/plugins/music_player/music_player.c @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include #include diff --git a/applications/plugins/picopass/application.fam b/applications/plugins/picopass/application.fam index bbe37e064..88460b4ff 100644 --- a/applications/plugins/picopass/application.fam +++ b/applications/plugins/picopass/application.fam @@ -17,4 +17,5 @@ App( name="loclass", ), ], + fap_icon_assets="icons", ) diff --git a/applications/plugins/picopass/icons/DolphinMafia_115x62.png b/applications/plugins/picopass/icons/DolphinMafia_115x62.png new file mode 100644 index 000000000..66fdb40ff Binary files /dev/null and b/applications/plugins/picopass/icons/DolphinMafia_115x62.png differ diff --git a/applications/plugins/picopass/icons/DolphinNice_96x59.png b/applications/plugins/picopass/icons/DolphinNice_96x59.png new file mode 100644 index 000000000..a299d3630 Binary files /dev/null and b/applications/plugins/picopass/icons/DolphinNice_96x59.png differ diff --git a/applications/plugins/picopass/icons/Nfc_10px.png b/applications/plugins/picopass/icons/Nfc_10px.png new file mode 100644 index 000000000..6bc027111 Binary files /dev/null and b/applications/plugins/picopass/icons/Nfc_10px.png differ diff --git a/applications/plugins/picopass/icons/RFIDDolphinReceive_97x61.png b/applications/plugins/picopass/icons/RFIDDolphinReceive_97x61.png new file mode 100644 index 000000000..e1f5f9f80 Binary files /dev/null and b/applications/plugins/picopass/icons/RFIDDolphinReceive_97x61.png differ diff --git a/applications/plugins/picopass/icons/RFIDDolphinSend_97x61.png b/applications/plugins/picopass/icons/RFIDDolphinSend_97x61.png new file mode 100644 index 000000000..380a970d9 Binary files /dev/null and b/applications/plugins/picopass/icons/RFIDDolphinSend_97x61.png differ diff --git a/applications/plugins/picopass/picopass_device.c b/applications/plugins/picopass/picopass_device.c index b6e69cc21..199b79e97 100644 --- a/applications/plugins/picopass/picopass_device.c +++ b/applications/plugins/picopass/picopass_device.c @@ -2,6 +2,7 @@ #include #include +#include #define TAG "PicopassDevice" diff --git a/applications/plugins/picopass/picopass_i.h b/applications/plugins/picopass/picopass_i.h index 8e011f222..469a672b7 100644 --- a/applications/plugins/picopass/picopass_i.h +++ b/applications/plugins/picopass/picopass_i.h @@ -24,6 +24,7 @@ #include #include +#include #define PICOPASS_TEXT_STORE_SIZE 128 diff --git a/applications/plugins/signal_generator/application.fam b/applications/plugins/signal_generator/application.fam index 7794ee492..de915733c 100644 --- a/applications/plugins/signal_generator/application.fam +++ b/applications/plugins/signal_generator/application.fam @@ -9,4 +9,5 @@ App( order=50, fap_icon="signal_gen_10px.png", fap_category="Tools", + fap_icon_assets="icons", ) diff --git a/applications/plugins/signal_generator/icons/SmallArrowDown_3x5.png b/applications/plugins/signal_generator/icons/SmallArrowDown_3x5.png new file mode 100644 index 000000000..1912e5d24 Binary files /dev/null and b/applications/plugins/signal_generator/icons/SmallArrowDown_3x5.png differ diff --git a/applications/plugins/signal_generator/icons/SmallArrowUp_3x5.png b/applications/plugins/signal_generator/icons/SmallArrowUp_3x5.png new file mode 100644 index 000000000..9c6242078 Binary files /dev/null and b/applications/plugins/signal_generator/icons/SmallArrowUp_3x5.png differ diff --git a/applications/plugins/signal_generator/views/signal_gen_pwm.c b/applications/plugins/signal_generator/views/signal_gen_pwm.c index 6d1a3c1ba..8e618f8a9 100644 --- a/applications/plugins/signal_generator/views/signal_gen_pwm.c +++ b/applications/plugins/signal_generator/views/signal_gen_pwm.c @@ -1,6 +1,7 @@ #include "../signal_gen_app_i.h" #include "furi_hal.h" #include +#include typedef enum { LineIndexChannel, diff --git a/applications/plugins/weather_station/helpers/weather_station_types.h b/applications/plugins/weather_station/helpers/weather_station_types.h index 275d23329..2976cbce8 100644 --- a/applications/plugins/weather_station/helpers/weather_station_types.h +++ b/applications/plugins/weather_station/helpers/weather_station_types.h @@ -3,7 +3,7 @@ #include #include -#define WS_VERSION_APP "0.2" +#define WS_VERSION_APP "0.3.1" #define WS_DEVELOPED "SkorP" #define WS_GITHUB "https://github.com/flipperdevices/flipperzero-firmware" diff --git a/applications/plugins/weather_station/images/Lock_7x8.png b/applications/plugins/weather_station/images/Lock_7x8.png new file mode 100644 index 000000000..f7c9ca2c7 Binary files /dev/null and b/applications/plugins/weather_station/images/Lock_7x8.png differ diff --git a/applications/plugins/weather_station/images/Pin_back_arrow_10x8.png b/applications/plugins/weather_station/images/Pin_back_arrow_10x8.png new file mode 100644 index 000000000..3bafabd14 Binary files /dev/null and b/applications/plugins/weather_station/images/Pin_back_arrow_10x8.png differ diff --git a/applications/plugins/weather_station/images/Quest_7x8.png b/applications/plugins/weather_station/images/Quest_7x8.png new file mode 100644 index 000000000..6825247fb Binary files /dev/null and b/applications/plugins/weather_station/images/Quest_7x8.png differ diff --git a/applications/plugins/weather_station/images/Scanning_123x52.png b/applications/plugins/weather_station/images/Scanning_123x52.png new file mode 100644 index 000000000..ec785948d Binary files /dev/null and b/applications/plugins/weather_station/images/Scanning_123x52.png differ diff --git a/applications/plugins/weather_station/images/Unlock_7x8.png b/applications/plugins/weather_station/images/Unlock_7x8.png new file mode 100644 index 000000000..9d82b4daf Binary files /dev/null and b/applications/plugins/weather_station/images/Unlock_7x8.png differ diff --git a/applications/plugins/weather_station/images/WarningDolphin_45x42.png b/applications/plugins/weather_station/images/WarningDolphin_45x42.png new file mode 100644 index 000000000..d766ffbb4 Binary files /dev/null and b/applications/plugins/weather_station/images/WarningDolphin_45x42.png differ diff --git a/applications/plugins/weather_station/protocols/acurite_592txr.c b/applications/plugins/weather_station/protocols/acurite_592txr.c new file mode 100644 index 000000000..db05af095 --- /dev/null +++ b/applications/plugins/weather_station/protocols/acurite_592txr.c @@ -0,0 +1,307 @@ +#include "acurite_592txr.h" + +#define TAG "WSProtocolAcurite_592TXR" + +/* + * Help + * https://github.com/merbanan/rtl_433/blob/5bef4e43133ac4c0e2d18d36f87c52b4f9458453/src/devices/acurite.c + * + * Acurite 592TXR Temperature Humidity sensor decoder + * Message Type 0x04, 7 bytes + * | Byte 0 | Byte 1 | Byte 2 | Byte 3 | Byte 4 | Byte 5 | Byte 6 | + * | --------- | --------- | --------- | --------- | --------- | --------- | --------- | + * | CCII IIII | IIII IIII | pB00 0100 | pHHH HHHH | p??T TTTT | pTTT TTTT | KKKK KKKK | + * - C: Channel 00: C, 10: B, 11: A, (01 is invalid) + * - I: Device ID (14 bits) + * - B: Battery, 1 is battery OK, 0 is battery low + * - M: Message type (6 bits), 0x04 + * - T: Temperature Celsius (11 - 14 bits?), + 1000 * 10 + * - H: Relative Humidity (%) (7 bits) + * - K: Checksum (8 bits) + * - p: Parity bit + * Notes: + * - Temperature + * - Encoded as Celsius + 1000 * 10 + * - only 11 bits needed for specified range -40 C to 70 C (-40 F - 158 F) + * - However 14 bits available for temperature, giving possible range of -100 C to 1538.4 C + * - @todo - check if high 3 bits ever used for anything else + * + */ + +static const SubGhzBlockConst ws_protocol_acurite_592txr_const = { + .te_short = 200, + .te_long = 400, + .te_delta = 90, + .min_count_bit_for_found = 56, +}; + +struct WSProtocolDecoderAcurite_592TXR { + SubGhzProtocolDecoderBase base; + + SubGhzBlockDecoder decoder; + WSBlockGeneric generic; + + uint16_t header_count; +}; + +struct WSProtocolEncoderAcurite_592TXR { + SubGhzProtocolEncoderBase base; + + SubGhzProtocolBlockEncoder encoder; + WSBlockGeneric generic; +}; + +typedef enum { + Acurite_592TXRDecoderStepReset = 0, + Acurite_592TXRDecoderStepCheckPreambule, + Acurite_592TXRDecoderStepSaveDuration, + Acurite_592TXRDecoderStepCheckDuration, +} Acurite_592TXRDecoderStep; + +const SubGhzProtocolDecoder ws_protocol_acurite_592txr_decoder = { + .alloc = ws_protocol_decoder_acurite_592txr_alloc, + .free = ws_protocol_decoder_acurite_592txr_free, + + .feed = ws_protocol_decoder_acurite_592txr_feed, + .reset = ws_protocol_decoder_acurite_592txr_reset, + + .get_hash_data = ws_protocol_decoder_acurite_592txr_get_hash_data, + .serialize = ws_protocol_decoder_acurite_592txr_serialize, + .deserialize = ws_protocol_decoder_acurite_592txr_deserialize, + .get_string = ws_protocol_decoder_acurite_592txr_get_string, +}; + +const SubGhzProtocolEncoder ws_protocol_acurite_592txr_encoder = { + .alloc = NULL, + .free = NULL, + + .deserialize = NULL, + .stop = NULL, + .yield = NULL, +}; + +const SubGhzProtocol ws_protocol_acurite_592txr = { + .name = WS_PROTOCOL_ACURITE_592TXR_NAME, + .type = SubGhzProtocolWeatherStation, + .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_868 | + SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable, + + .decoder = &ws_protocol_acurite_592txr_decoder, + .encoder = &ws_protocol_acurite_592txr_encoder, +}; + +void* ws_protocol_decoder_acurite_592txr_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + WSProtocolDecoderAcurite_592TXR* instance = malloc(sizeof(WSProtocolDecoderAcurite_592TXR)); + instance->base.protocol = &ws_protocol_acurite_592txr; + instance->generic.protocol_name = instance->base.protocol->name; + return instance; +} + +void ws_protocol_decoder_acurite_592txr_free(void* context) { + furi_assert(context); + WSProtocolDecoderAcurite_592TXR* instance = context; + free(instance); +} + +void ws_protocol_decoder_acurite_592txr_reset(void* context) { + furi_assert(context); + WSProtocolDecoderAcurite_592TXR* instance = context; + instance->decoder.parser_step = Acurite_592TXRDecoderStepReset; +} + +static bool ws_protocol_acurite_592txr_check_crc(WSProtocolDecoderAcurite_592TXR* instance) { + uint8_t msg[] = { + instance->decoder.decode_data >> 48, + instance->decoder.decode_data >> 40, + instance->decoder.decode_data >> 32, + instance->decoder.decode_data >> 24, + instance->decoder.decode_data >> 16, + instance->decoder.decode_data >> 8}; + + if((subghz_protocol_blocks_add_bytes(msg, 6) == + (uint8_t)(instance->decoder.decode_data & 0xFF)) && + (!subghz_protocol_blocks_parity_bytes(&msg[2], 4))) { + return true; + } else { + return false; + } +} + +/** + * Analysis of received data + * @param instance Pointer to a WSBlockGeneric* instance + */ +static void ws_protocol_acurite_592txr_remote_controller(WSBlockGeneric* instance) { + uint8_t channel[] = {3, 0, 2, 1}; + uint8_t channel_raw = ((instance->data >> 54) & 0x03); + instance->channel = channel[channel_raw]; + instance->id = (instance->data >> 40) & 0x3FFF; + instance->battery_low = !((instance->data >> 38) & 1); + instance->humidity = (instance->data >> 24) & 0x7F; + + uint16_t temp_raw = ((instance->data >> 9) & 0xF80) | ((instance->data >> 8) & 0x7F); + instance->temp = ((float)(temp_raw)-1000) / 10.0f; + + instance->btn = WS_NO_BTN; +} + +void ws_protocol_decoder_acurite_592txr_feed(void* context, bool level, uint32_t duration) { + furi_assert(context); + WSProtocolDecoderAcurite_592TXR* instance = context; + + switch(instance->decoder.parser_step) { + case Acurite_592TXRDecoderStepReset: + if((level) && (DURATION_DIFF(duration, ws_protocol_acurite_592txr_const.te_short * 3) < + ws_protocol_acurite_592txr_const.te_delta * 2)) { + instance->decoder.parser_step = Acurite_592TXRDecoderStepCheckPreambule; + instance->decoder.te_last = duration; + instance->header_count = 0; + } + break; + + case Acurite_592TXRDecoderStepCheckPreambule: + if(level) { + instance->decoder.te_last = duration; + } else { + if((DURATION_DIFF( + instance->decoder.te_last, ws_protocol_acurite_592txr_const.te_short * 3) < + ws_protocol_acurite_592txr_const.te_delta * 2) && + (DURATION_DIFF(duration, ws_protocol_acurite_592txr_const.te_short * 3) < + ws_protocol_acurite_592txr_const.te_delta * 2)) { + //Found preambule + instance->header_count++; + } else if((instance->header_count > 2) && (instance->header_count < 5)) { + if((DURATION_DIFF( + instance->decoder.te_last, ws_protocol_acurite_592txr_const.te_short) < + ws_protocol_acurite_592txr_const.te_delta) && + (DURATION_DIFF(duration, ws_protocol_acurite_592txr_const.te_long) < + ws_protocol_acurite_592txr_const.te_delta)) { + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + instance->decoder.parser_step = Acurite_592TXRDecoderStepSaveDuration; + } else if( + (DURATION_DIFF( + instance->decoder.te_last, ws_protocol_acurite_592txr_const.te_long) < + ws_protocol_acurite_592txr_const.te_delta) && + (DURATION_DIFF(duration, ws_protocol_acurite_592txr_const.te_short) < + ws_protocol_acurite_592txr_const.te_delta)) { + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + instance->decoder.parser_step = Acurite_592TXRDecoderStepSaveDuration; + } else { + instance->decoder.parser_step = Acurite_592TXRDecoderStepReset; + } + } else { + instance->decoder.parser_step = Acurite_592TXRDecoderStepReset; + } + } + break; + + case Acurite_592TXRDecoderStepSaveDuration: + if(level) { + instance->decoder.te_last = duration; + instance->decoder.parser_step = Acurite_592TXRDecoderStepCheckDuration; + } else { + instance->decoder.parser_step = Acurite_592TXRDecoderStepReset; + } + break; + + case Acurite_592TXRDecoderStepCheckDuration: + if(!level) { + if(duration >= ((uint32_t)ws_protocol_acurite_592txr_const.te_short * 5)) { + if((instance->decoder.decode_count_bit == + ws_protocol_acurite_592txr_const.min_count_bit_for_found) && + ws_protocol_acurite_592txr_check_crc(instance)) { + instance->generic.data = instance->decoder.decode_data; + instance->generic.data_count_bit = instance->decoder.decode_count_bit; + ws_protocol_acurite_592txr_remote_controller(&instance->generic); + if(instance->base.callback) + instance->base.callback(&instance->base, instance->base.context); + } + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + instance->decoder.parser_step = Acurite_592TXRDecoderStepReset; + break; + } else if( + (DURATION_DIFF( + instance->decoder.te_last, ws_protocol_acurite_592txr_const.te_short) < + ws_protocol_acurite_592txr_const.te_delta) && + (DURATION_DIFF(duration, ws_protocol_acurite_592txr_const.te_long) < + ws_protocol_acurite_592txr_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + instance->decoder.parser_step = Acurite_592TXRDecoderStepSaveDuration; + } else if( + (DURATION_DIFF( + instance->decoder.te_last, ws_protocol_acurite_592txr_const.te_long) < + ws_protocol_acurite_592txr_const.te_delta) && + (DURATION_DIFF(duration, ws_protocol_acurite_592txr_const.te_short) < + ws_protocol_acurite_592txr_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + instance->decoder.parser_step = Acurite_592TXRDecoderStepSaveDuration; + } else { + instance->decoder.parser_step = Acurite_592TXRDecoderStepReset; + } + } else { + instance->decoder.parser_step = Acurite_592TXRDecoderStepReset; + } + break; + } +} + +uint8_t ws_protocol_decoder_acurite_592txr_get_hash_data(void* context) { + furi_assert(context); + WSProtocolDecoderAcurite_592TXR* instance = context; + return subghz_protocol_blocks_get_hash_data( + &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); +} + +bool ws_protocol_decoder_acurite_592txr_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzRadioPreset* preset) { + furi_assert(context); + WSProtocolDecoderAcurite_592TXR* instance = context; + return ws_block_generic_serialize(&instance->generic, flipper_format, preset); +} + +bool ws_protocol_decoder_acurite_592txr_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + WSProtocolDecoderAcurite_592TXR* instance = context; + bool ret = false; + do { + if(!ws_block_generic_deserialize(&instance->generic, flipper_format)) { + break; + } + if(instance->generic.data_count_bit != + ws_protocol_acurite_592txr_const.min_count_bit_for_found) { + FURI_LOG_E(TAG, "Wrong number of bits in key"); + break; + } + ret = true; + } while(false); + return ret; +} + +void ws_protocol_decoder_acurite_592txr_get_string(void* context, FuriString* output) { + furi_assert(context); + WSProtocolDecoderAcurite_592TXR* instance = context; + furi_string_printf( + output, + "%s %dbit\r\n" + "Key:0x%lX%08lX\r\n" + "Sn:0x%lX Ch:%d Bat:%d\r\n" + "Temp:%d.%d C Hum:%d%%", + instance->generic.protocol_name, + instance->generic.data_count_bit, + (uint32_t)(instance->generic.data >> 32), + (uint32_t)(instance->generic.data), + instance->generic.id, + instance->generic.channel, + instance->generic.battery_low, + (int16_t)instance->generic.temp, + abs(((int16_t)(instance->generic.temp * 10) - (((int16_t)instance->generic.temp) * 10))), + instance->generic.humidity); +} diff --git a/applications/plugins/weather_station/protocols/acurite_592txr.h b/applications/plugins/weather_station/protocols/acurite_592txr.h new file mode 100644 index 000000000..ac0371d89 --- /dev/null +++ b/applications/plugins/weather_station/protocols/acurite_592txr.h @@ -0,0 +1,79 @@ +#pragma once + +#include + +#include +#include +#include +#include "ws_generic.h" +#include + +#define WS_PROTOCOL_ACURITE_592TXR_NAME "Acurite 592TXR" + +typedef struct WSProtocolDecoderAcurite_592TXR WSProtocolDecoderAcurite_592TXR; +typedef struct WSProtocolEncoderAcurite_592TXR WSProtocolEncoderAcurite_592TXR; + +extern const SubGhzProtocolDecoder ws_protocol_acurite_592txr_decoder; +extern const SubGhzProtocolEncoder ws_protocol_acurite_592txr_encoder; +extern const SubGhzProtocol ws_protocol_acurite_592txr; + +/** + * Allocate WSProtocolDecoderAcurite_592TXR. + * @param environment Pointer to a SubGhzEnvironment instance + * @return WSProtocolDecoderAcurite_592TXR* pointer to a WSProtocolDecoderAcurite_592TXR instance + */ +void* ws_protocol_decoder_acurite_592txr_alloc(SubGhzEnvironment* environment); + +/** + * Free WSProtocolDecoderAcurite_592TXR. + * @param context Pointer to a WSProtocolDecoderAcurite_592TXR instance + */ +void ws_protocol_decoder_acurite_592txr_free(void* context); + +/** + * Reset decoder WSProtocolDecoderAcurite_592TXR. + * @param context Pointer to a WSProtocolDecoderAcurite_592TXR instance + */ +void ws_protocol_decoder_acurite_592txr_reset(void* context); + +/** + * Parse a raw sequence of levels and durations received from the air. + * @param context Pointer to a WSProtocolDecoderAcurite_592TXR instance + * @param level Signal level true-high false-low + * @param duration Duration of this level in, us + */ +void ws_protocol_decoder_acurite_592txr_feed(void* context, bool level, uint32_t duration); + +/** + * Getting the hash sum of the last randomly received parcel. + * @param context Pointer to a WSProtocolDecoderAcurite_592TXR instance + * @return hash Hash sum + */ +uint8_t ws_protocol_decoder_acurite_592txr_get_hash_data(void* context); + +/** + * Serialize data WSProtocolDecoderAcurite_592TXR. + * @param context Pointer to a WSProtocolDecoderAcurite_592TXR instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param preset The modulation on which the signal was received, SubGhzRadioPreset + * @return true On success + */ +bool ws_protocol_decoder_acurite_592txr_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzRadioPreset* preset); + +/** + * Deserialize data WSProtocolDecoderAcurite_592TXR. + * @param context Pointer to a WSProtocolDecoderAcurite_592TXR instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool ws_protocol_decoder_acurite_592txr_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Getting a textual representation of the received data. + * @param context Pointer to a WSProtocolDecoderAcurite_592TXR instance + * @param output Resulting text + */ +void ws_protocol_decoder_acurite_592txr_get_string(void* context, FuriString* output); diff --git a/applications/plugins/weather_station/protocols/acurite_606tx.c b/applications/plugins/weather_station/protocols/acurite_606tx.c index a92ec243c..3c9144057 100644 --- a/applications/plugins/weather_station/protocols/acurite_606tx.c +++ b/applications/plugins/weather_station/protocols/acurite_606tx.c @@ -151,41 +151,37 @@ void ws_protocol_decoder_acurite_606tx_feed(void* context, bool level, uint32_t case Acurite_606TXDecoderStepCheckDuration: if(!level) { - if((DURATION_DIFF(instance->decoder.te_last, ws_protocol_acurite_606tx_const.te_short) < - ws_protocol_acurite_606tx_const.te_delta) && - (DURATION_DIFF(duration, ws_protocol_acurite_606tx_const.te_short) < - ws_protocol_acurite_606tx_const.te_delta)) { - //Found syncPostfix - instance->decoder.parser_step = Acurite_606TXDecoderStepReset; - if((instance->decoder.decode_count_bit == - ws_protocol_acurite_606tx_const.min_count_bit_for_found) && - ws_protocol_acurite_606tx_check(instance)) { - instance->generic.data = instance->decoder.decode_data; - instance->generic.data_count_bit = instance->decoder.decode_count_bit; - ws_protocol_acurite_606tx_remote_controller(&instance->generic); - if(instance->base.callback) - instance->base.callback(&instance->base, instance->base.context); + if(DURATION_DIFF(instance->decoder.te_last, ws_protocol_acurite_606tx_const.te_short) < + ws_protocol_acurite_606tx_const.te_delta) { + if((DURATION_DIFF(duration, ws_protocol_acurite_606tx_const.te_short) < + ws_protocol_acurite_606tx_const.te_delta) || + (duration > ws_protocol_acurite_606tx_const.te_long * 3)) { + //Found syncPostfix + instance->decoder.parser_step = Acurite_606TXDecoderStepReset; + if((instance->decoder.decode_count_bit == + ws_protocol_acurite_606tx_const.min_count_bit_for_found) && + ws_protocol_acurite_606tx_check(instance)) { + instance->generic.data = instance->decoder.decode_data; + instance->generic.data_count_bit = instance->decoder.decode_count_bit; + ws_protocol_acurite_606tx_remote_controller(&instance->generic); + if(instance->base.callback) + instance->base.callback(&instance->base, instance->base.context); + } + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + } else if( + DURATION_DIFF(duration, ws_protocol_acurite_606tx_const.te_long) < + ws_protocol_acurite_606tx_const.te_delta * 2) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + instance->decoder.parser_step = Acurite_606TXDecoderStepSaveDuration; + } else if( + DURATION_DIFF(duration, ws_protocol_acurite_606tx_const.te_long * 2) < + ws_protocol_acurite_606tx_const.te_delta * 4) { + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + instance->decoder.parser_step = Acurite_606TXDecoderStepSaveDuration; + } else { + instance->decoder.parser_step = Acurite_606TXDecoderStepReset; } - instance->decoder.decode_data = 0; - instance->decoder.decode_count_bit = 0; - - break; - } else if( - (DURATION_DIFF( - instance->decoder.te_last, ws_protocol_acurite_606tx_const.te_short) < - ws_protocol_acurite_606tx_const.te_delta) && - (DURATION_DIFF(duration, ws_protocol_acurite_606tx_const.te_long) < - ws_protocol_acurite_606tx_const.te_delta * 2)) { - subghz_protocol_blocks_add_bit(&instance->decoder, 0); - instance->decoder.parser_step = Acurite_606TXDecoderStepSaveDuration; - } else if( - (DURATION_DIFF( - instance->decoder.te_last, ws_protocol_acurite_606tx_const.te_short) < - ws_protocol_acurite_606tx_const.te_delta) && - (DURATION_DIFF(duration, ws_protocol_acurite_606tx_const.te_long * 2) < - ws_protocol_acurite_606tx_const.te_delta * 4)) { - subghz_protocol_blocks_add_bit(&instance->decoder, 1); - instance->decoder.parser_step = Acurite_606TXDecoderStepSaveDuration; } else { instance->decoder.parser_step = Acurite_606TXDecoderStepReset; } diff --git a/lib/subghz/protocols/oregon2.c b/applications/plugins/weather_station/protocols/oregon2.c similarity index 55% rename from lib/subghz/protocols/oregon2.c rename to applications/plugins/weather_station/protocols/oregon2.c index 244ac58d8..d294548e6 100644 --- a/lib/subghz/protocols/oregon2.c +++ b/applications/plugins/weather_station/protocols/oregon2.c @@ -1,14 +1,17 @@ #include "oregon2.h" -#include "../blocks/const.h" -#include "../blocks/decoder.h" -#include "../blocks/generic.h" -#include "../blocks/math.h" + +#include +#include +#include +#include +#include "ws_generic.h" + #include #include -#define TAG "SubGhzProtocolOregon2" +#define TAG "WSProtocolOregon2" -static const SubGhzBlockConst oregon2_const = { +static const SubGhzBlockConst ws_oregon2_const = { .te_long = 1000, .te_short = 500, .te_delta = 200, @@ -16,7 +19,7 @@ static const SubGhzBlockConst oregon2_const = { }; #define OREGON2_PREAMBLE_BITS 19 -#define OREGON2_PREAMBLE_MASK ((1 << (OREGON2_PREAMBLE_BITS + 1)) - 1) +#define OREGON2_PREAMBLE_MASK 0b1111111111111111111 #define OREGON2_SENSOR_ID(d) (((d) >> 16) & 0xFFFF) #define OREGON2_CHECKSUM_BITS 8 @@ -26,11 +29,45 @@ static const SubGhzBlockConst oregon2_const = { // bit indicating the low battery #define OREGON2_FLAG_BAT_LOW 0x4 -struct SubGhzProtocolDecoderOregon2 { +/// Documentation for Oregon Scientific protocols can be found here: +/// http://wmrx00.sourceforge.net/Arduino/OregonScientific-RF-Protocols.pdf +// Sensors ID +#define ID_THGR122N 0x1d20 +#define ID_THGR968 0x1d30 +#define ID_BTHR918 0x5d50 +#define ID_BHTR968 0x5d60 +#define ID_RGR968 0x2d10 +#define ID_THR228N 0xec40 +#define ID_THN132N 0xec40 // same as THR228N but different packet size +#define ID_RTGN318 0x0cc3 // warning: id is from 0x0cc3 and 0xfcc3 +#define ID_RTGN129 0x0cc3 // same as RTGN318 but different packet size +#define ID_THGR810 0xf824 // This might be ID_THGR81, but what's true is lost in (git) history +#define ID_THGR810a 0xf8b4 // unconfirmed version +#define ID_THN802 0xc844 +#define ID_PCR800 0x2914 +#define ID_PCR800a 0x2d14 // Different PCR800 ID - AU version I think +#define ID_WGR800 0x1984 +#define ID_WGR800a 0x1994 // unconfirmed version +#define ID_WGR968 0x3d00 +#define ID_UV800 0xd874 +#define ID_THN129 0xcc43 // THN129 Temp only +#define ID_RTHN129 0x0cd3 // RTHN129 Temp, clock sensors +#define ID_BTHGN129 0x5d53 // Baro, Temp, Hygro sensor +#define ID_UVR128 0xec70 +#define ID_THGR328N 0xcc23 // Temp & Hygro sensor similar to THR228N with 5 channel instead of 3 +#define ID_RTGR328N_1 0xdcc3 // RTGR328N_[1-5] RFclock(date &time)&Temp&Hygro sensor +#define ID_RTGR328N_2 0xccc3 +#define ID_RTGR328N_3 0xbcc3 +#define ID_RTGR328N_4 0xacc3 +#define ID_RTGR328N_5 0x9cc3 +#define ID_RTGR328N_6 0x8ce3 // RTGR328N_6&7 RFclock(date &time)&Temp&Hygro sensor like THGR328N +#define ID_RTGR328N_7 0x8ae3 + +struct WSProtocolDecoderOregon2 { SubGhzProtocolDecoderBase base; SubGhzBlockDecoder decoder; - SubGhzBlockGeneric generic; + WSBlockGeneric generic; ManchesterState manchester_state; bool prev_bit; bool have_bit; @@ -39,7 +76,7 @@ struct SubGhzProtocolDecoderOregon2 { uint32_t var_data; }; -typedef struct SubGhzProtocolDecoderOregon2 SubGhzProtocolDecoderOregon2; +typedef struct WSProtocolDecoderOregon2 WSProtocolDecoderOregon2; typedef enum { Oregon2DecoderStepReset = 0, @@ -47,23 +84,29 @@ typedef enum { Oregon2DecoderStepVarData, } Oregon2DecoderStep; -void* subghz_protocol_decoder_oregon2_alloc(SubGhzEnvironment* environment) { +void* ws_protocol_decoder_oregon2_alloc(SubGhzEnvironment* environment) { UNUSED(environment); - SubGhzProtocolDecoderOregon2* instance = malloc(sizeof(SubGhzProtocolDecoderOregon2)); - instance->base.protocol = &subghz_protocol_oregon2; + WSProtocolDecoderOregon2* instance = malloc(sizeof(WSProtocolDecoderOregon2)); + instance->base.protocol = &ws_protocol_oregon2; instance->generic.protocol_name = instance->base.protocol->name; + instance->generic.humidity = WS_NO_HUMIDITY; + instance->generic.temp = WS_NO_TEMPERATURE; + instance->generic.btn = WS_NO_BTN; + instance->generic.channel = WS_NO_CHANNEL; + instance->generic.battery_low = WS_NO_BATT; + instance->generic.id = WS_NO_ID; return instance; } -void subghz_protocol_decoder_oregon2_free(void* context) { +void ws_protocol_decoder_oregon2_free(void* context) { furi_assert(context); - SubGhzProtocolDecoderOregon2* instance = context; + WSProtocolDecoderOregon2* instance = context; free(instance); } -void subghz_protocol_decoder_oregon2_reset(void* context) { +void ws_protocol_decoder_oregon2_reset(void* context) { furi_assert(context); - SubGhzProtocolDecoderOregon2* instance = context; + WSProtocolDecoderOregon2* instance = context; instance->decoder.parser_step = Oregon2DecoderStepReset; instance->decoder.decode_data = 0UL; instance->decoder.decode_count_bit = 0; @@ -77,9 +120,9 @@ void subghz_protocol_decoder_oregon2_reset(void* context) { static ManchesterEvent level_and_duration_to_event(bool level, uint32_t duration) { bool is_long = false; - if(DURATION_DIFF(duration, oregon2_const.te_long) < oregon2_const.te_delta) { + if(DURATION_DIFF(duration, ws_oregon2_const.te_long) < ws_oregon2_const.te_delta) { is_long = true; - } else if(DURATION_DIFF(duration, oregon2_const.te_short) < oregon2_const.te_delta) { + } else if(DURATION_DIFF(duration, ws_oregon2_const.te_short) < ws_oregon2_const.te_delta) { is_long = false; } else { return ManchesterEventReset; @@ -92,14 +135,58 @@ static ManchesterEvent level_and_duration_to_event(bool level, uint32_t duration } // From sensor id code return amount of bits in variable section +// https://temofeev.ru/info/articles/o-dekodirovanii-protokola-pogodnykh-datchikov-oregon-scientific static uint8_t oregon2_sensor_id_var_bits(uint16_t sensor_id) { - if(sensor_id == 0xEC40) return 16; + if(sensor_id == ID_THR228N) return 16; + + if(sensor_id == ID_THGR122N) return 24; + return 0; } -void subghz_protocol_decoder_oregon2_feed(void* context, bool level, uint32_t duration) { +static void ws_oregon2_decode_const_data(WSBlockGeneric* ws_block) { + ws_block->id = OREGON2_SENSOR_ID(ws_block->data); + + uint8_t ch_bits = (ws_block->data >> 12) & 0xF; + ws_block->channel = 1; + while(ch_bits > 1) { + ws_block->channel++; + ch_bits >>= 1; + } + + ws_block->battery_low = (ws_block->data & OREGON2_FLAG_BAT_LOW) ? 1 : 0; +} + +uint16_t bcd_decode_short(uint32_t data) { + return (data & 0xF) * 10 + ((data >> 4) & 0xF); +} + +static float ws_oregon2_decode_temp(uint32_t data) { + int32_t temp_val; + temp_val = bcd_decode_short(data >> 4); + temp_val *= 10; + temp_val += (data >> 12) & 0xF; + if(data & 0xF) temp_val = -temp_val; + return (float)temp_val / 10.0; +} + +static void ws_oregon2_decode_var_data(WSBlockGeneric* ws_b, uint16_t sensor_id, uint32_t data) { + if(sensor_id == ID_THR228N) { + ws_b->temp = ws_oregon2_decode_temp(data); + ws_b->humidity = WS_NO_HUMIDITY; + return; + } + + if(sensor_id == ID_THGR122N) { + ws_b->humidity = bcd_decode_short(data); + ws_b->temp = ws_oregon2_decode_temp(data >> 8); + return; + } +} + +void ws_protocol_decoder_oregon2_feed(void* context, bool level, uint32_t duration) { furi_assert(context); - SubGhzProtocolDecoderOregon2* instance = context; + WSProtocolDecoderOregon2* instance = context; // oregon v2.1 signal is inverted ManchesterEvent event = level_and_duration_to_event(!level, duration); bool data; @@ -118,7 +205,7 @@ void subghz_protocol_decoder_oregon2_feed(void* context, bool level, uint32_t du } else if(instance->prev_bit && !data) { subghz_protocol_blocks_add_bit(&instance->decoder, 0); } else { - subghz_protocol_decoder_oregon2_reset(context); + ws_protocol_decoder_oregon2_reset(context); } instance->have_bit = false; } else { @@ -151,6 +238,7 @@ void subghz_protocol_decoder_oregon2_feed(void* context, bool level, uint32_t du instance->generic.data = (instance->generic.data & 0x33333333) << 2 | (instance->generic.data & 0xCCCCCCCC) >> 2; + ws_oregon2_decode_const_data(&instance->generic); instance->var_bits = oregon2_sensor_id_var_bits(OREGON2_SENSOR_ID(instance->generic.data)); @@ -175,6 +263,11 @@ void subghz_protocol_decoder_oregon2_feed(void* context, bool level, uint32_t du instance->var_data = (instance->var_data & 0x33333333) << 2 | (instance->var_data & 0xCCCCCCCC) >> 2; + ws_oregon2_decode_var_data( + &instance->generic, + OREGON2_SENSOR_ID(instance->generic.data), + instance->var_data >> OREGON2_CHECKSUM_BITS); + instance->decoder.parser_step = Oregon2DecoderStepReset; if(instance->base.callback) instance->base.callback(&instance->base, instance->base.context); @@ -183,20 +276,20 @@ void subghz_protocol_decoder_oregon2_feed(void* context, bool level, uint32_t du } } -uint8_t subghz_protocol_decoder_oregon2_get_hash_data(void* context) { +uint8_t ws_protocol_decoder_oregon2_get_hash_data(void* context) { furi_assert(context); - SubGhzProtocolDecoderOregon2* instance = context; + WSProtocolDecoderOregon2* instance = context; return subghz_protocol_blocks_get_hash_data( &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); } -bool subghz_protocol_decoder_oregon2_serialize( +bool ws_protocol_decoder_oregon2_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { furi_assert(context); - SubGhzProtocolDecoderOregon2* instance = context; - if(!subghz_block_generic_serialize(&instance->generic, flipper_format, preset)) return false; + WSProtocolDecoderOregon2* instance = context; + if(!ws_block_generic_serialize(&instance->generic, flipper_format, preset)) return false; uint32_t temp = instance->var_bits; if(!flipper_format_write_uint32(flipper_format, "VarBits", &temp, 1)) { FURI_LOG_E(TAG, "Error adding VarBits"); @@ -213,13 +306,13 @@ bool subghz_protocol_decoder_oregon2_serialize( return true; } -bool subghz_protocol_decoder_oregon2_deserialize(void* context, FlipperFormat* flipper_format) { +bool ws_protocol_decoder_oregon2_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); - SubGhzProtocolDecoderOregon2* instance = context; + WSProtocolDecoderOregon2* instance = context; bool ret = false; uint32_t temp_data; do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + if(!ws_block_generic_deserialize(&instance->generic, flipper_format)) { break; } if(!flipper_format_read_uint32(flipper_format, "VarBits", &temp_data, 1)) { @@ -235,7 +328,7 @@ bool subghz_protocol_decoder_oregon2_deserialize(void* context, FlipperFormat* f FURI_LOG_E(TAG, "Missing VarData"); break; } - if(instance->generic.data_count_bit != oregon2_const.min_count_bit_for_found) { + if(instance->generic.data_count_bit != ws_oregon2_const.min_count_bit_for_found) { FURI_LOG_E(TAG, "Wrong number of bits in key: %d", instance->generic.data_count_bit); break; } @@ -244,22 +337,6 @@ bool subghz_protocol_decoder_oregon2_deserialize(void* context, FlipperFormat* f return ret; } -// append string of the variable data -static void - oregon2_var_data_append_string(uint16_t sensor_id, uint32_t var_data, FuriString* output) { - uint32_t val; - - if(sensor_id == 0xEC40) { - val = ((var_data >> 4) & 0xF) * 10 + ((var_data >> 8) & 0xF); - furi_string_cat_printf( - output, - "Temp: %s%ld.%ld C\r\n", - (var_data & 0xF) ? "-" : "+", - val, - (uint32_t)(var_data >> 12) & 0xF); - } -} - static void oregon2_append_check_sum(uint32_t fix_data, uint32_t var_data, FuriString* output) { uint8_t sum = fix_data & 0xF; uint8_t ref_sum = var_data & 0xFF; @@ -279,45 +356,49 @@ static void oregon2_append_check_sum(uint32_t fix_data, uint32_t var_data, FuriS furi_string_cat_printf(output, "Sum err: 0x%hhX vs 0x%hhX", ref_sum, sum); } -void subghz_protocol_decoder_oregon2_get_string(void* context, FuriString* output) { +void ws_protocol_decoder_oregon2_get_string(void* context, FuriString* output) { furi_assert(context); - SubGhzProtocolDecoderOregon2* instance = context; - uint16_t sensor_id = OREGON2_SENSOR_ID(instance->generic.data); + WSProtocolDecoderOregon2* instance = context; furi_string_cat_printf( output, "%s\r\n" - "ID: 0x%04lX, ch: %ld%s, rc: 0x%02lX\r\n", + "ID: 0x%04lX, ch: %d, bat: %d, rc: 0x%02lX\r\n", instance->generic.protocol_name, - (uint32_t)sensor_id, - (uint32_t)(instance->generic.data >> 12) & 0xF, - ((instance->generic.data & OREGON2_FLAG_BAT_LOW) ? ", low bat" : ""), + instance->generic.id, + instance->generic.channel, + instance->generic.battery_low, (uint32_t)(instance->generic.data >> 4) & 0xFF); if(instance->var_bits > 0) { - oregon2_var_data_append_string( - sensor_id, instance->var_data >> OREGON2_CHECKSUM_BITS, output); + furi_string_cat_printf( + output, + "Temp:%d.%d C Hum:%d%%", + (int16_t)instance->generic.temp, + abs( + ((int16_t)(instance->generic.temp * 10) - + (((int16_t)instance->generic.temp) * 10))), + instance->generic.humidity); oregon2_append_check_sum((uint32_t)instance->generic.data, instance->var_data, output); } } -const SubGhzProtocolDecoder subghz_protocol_oregon2_decoder = { - .alloc = subghz_protocol_decoder_oregon2_alloc, - .free = subghz_protocol_decoder_oregon2_free, +const SubGhzProtocolDecoder ws_protocol_oregon2_decoder = { + .alloc = ws_protocol_decoder_oregon2_alloc, + .free = ws_protocol_decoder_oregon2_free, - .feed = subghz_protocol_decoder_oregon2_feed, - .reset = subghz_protocol_decoder_oregon2_reset, + .feed = ws_protocol_decoder_oregon2_feed, + .reset = ws_protocol_decoder_oregon2_reset, - .get_hash_data = subghz_protocol_decoder_oregon2_get_hash_data, - .serialize = subghz_protocol_decoder_oregon2_serialize, - .deserialize = subghz_protocol_decoder_oregon2_deserialize, - .get_string = subghz_protocol_decoder_oregon2_get_string, + .get_hash_data = ws_protocol_decoder_oregon2_get_hash_data, + .serialize = ws_protocol_decoder_oregon2_serialize, + .deserialize = ws_protocol_decoder_oregon2_deserialize, + .get_string = ws_protocol_decoder_oregon2_get_string, }; -const SubGhzProtocol subghz_protocol_oregon2 = { - .name = SUBGHZ_PROTOCOL_OREGON2_NAME, - .type = SubGhzProtocolTypeStatic, - .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | - SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save, +const SubGhzProtocol ws_protocol_oregon2 = { + .name = WS_PROTOCOL_OREGON2_NAME, + .type = SubGhzProtocolWeatherStation, + .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable, - .decoder = &subghz_protocol_oregon2_decoder, + .decoder = &ws_protocol_oregon2_decoder, }; diff --git a/applications/plugins/weather_station/protocols/oregon2.h b/applications/plugins/weather_station/protocols/oregon2.h new file mode 100644 index 000000000..cfe938e6d --- /dev/null +++ b/applications/plugins/weather_station/protocols/oregon2.h @@ -0,0 +1,6 @@ +#pragma once + +#include + +#define WS_PROTOCOL_OREGON2_NAME "Oregon2" +extern const SubGhzProtocol ws_protocol_oregon2; diff --git a/applications/plugins/weather_station/protocols/protocol_items.c b/applications/plugins/weather_station/protocols/protocol_items.c index 5b753994e..3ec9e995a 100644 --- a/applications/plugins/weather_station/protocols/protocol_items.c +++ b/applications/plugins/weather_station/protocols/protocol_items.c @@ -7,6 +7,8 @@ const SubGhzProtocol* weather_station_protocol_registry_items[] = { &ws_protocol_gt_wt_03, &ws_protocol_acurite_606tx, &ws_protocol_lacrosse_tx141thbv2, + &ws_protocol_oregon2, + &ws_protocol_acurite_592txr, }; const SubGhzProtocolRegistry weather_station_protocol_registry = { diff --git a/applications/plugins/weather_station/protocols/protocol_items.h b/applications/plugins/weather_station/protocols/protocol_items.h index c4f4ecd9a..8f3eb53d7 100644 --- a/applications/plugins/weather_station/protocols/protocol_items.h +++ b/applications/plugins/weather_station/protocols/protocol_items.h @@ -7,5 +7,7 @@ #include "gt_wt_03.h" #include "acurite_606tx.h" #include "lacrosse_tx141thbv2.h" +#include "oregon2.h" +#include "acurite_592txr.h" extern const SubGhzProtocolRegistry weather_station_protocol_registry; diff --git a/applications/plugins/weather_station/views/weather_station_receiver.c b/applications/plugins/weather_station/views/weather_station_receiver.c index d30b7926b..61b152602 100644 --- a/applications/plugins/weather_station/views/weather_station_receiver.c +++ b/applications/plugins/weather_station/views/weather_station_receiver.c @@ -1,11 +1,10 @@ #include "weather_station_receiver.h" #include "../weather_station_app_i.h" -#include "weather_station_icons.h" +#include #include #include #include -#include #include #define FRAME_HEIGHT 12 diff --git a/applications/services/bt/bt_service/bt.c b/applications/services/bt/bt_service/bt.c index c003013e4..62b5ab109 100644 --- a/applications/services/bt/bt_service/bt.c +++ b/applications/services/bt/bt_service/bt.c @@ -4,6 +4,7 @@ #include #include +#include #define TAG "BtSrv" diff --git a/applications/services/desktop/views/desktop_view_lock_menu.c b/applications/services/desktop/views/desktop_view_lock_menu.c index 8cb8a7a12..486be23b5 100644 --- a/applications/services/desktop/views/desktop_view_lock_menu.c +++ b/applications/services/desktop/views/desktop_view_lock_menu.c @@ -1,5 +1,6 @@ #include #include +#include #include "../desktop_i.h" #include "desktop_view_lock_menu.h" diff --git a/applications/services/desktop/views/desktop_view_locked.c b/applications/services/desktop/views/desktop_view_locked.c index 915b26103..d18ed6c98 100644 --- a/applications/services/desktop/views/desktop_view_locked.c +++ b/applications/services/desktop/views/desktop_view_locked.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include diff --git a/applications/services/desktop/views/desktop_view_pin_input.c b/applications/services/desktop/views/desktop_view_pin_input.c index bf05f06b9..b86bf2929 100644 --- a/applications/services/desktop/views/desktop_view_pin_input.c +++ b/applications/services/desktop/views/desktop_view_pin_input.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include diff --git a/applications/services/dialogs/dialogs_api.c b/applications/services/dialogs/dialogs_api.c index 6fd51782d..ee959a33c 100644 --- a/applications/services/dialogs/dialogs_api.c +++ b/applications/services/dialogs/dialogs_api.c @@ -1,6 +1,7 @@ #include "dialogs/dialogs_message.h" #include "dialogs_i.h" #include "dialogs_api_lock.h" +#include /****************** File browser ******************/ diff --git a/applications/services/dolphin/helpers/dolphin_deed.c b/applications/services/dolphin/helpers/dolphin_deed.c index ce3e058b5..51db56fdf 100644 --- a/applications/services/dolphin/helpers/dolphin_deed.c +++ b/applications/services/dolphin/helpers/dolphin_deed.c @@ -21,8 +21,8 @@ static const DolphinDeedWeight dolphin_deed_weights[] = { {1, DolphinAppNfc}, // DolphinDeedNfcDetectReader {2, DolphinAppNfc}, // DolphinDeedNfcEmulate {2, DolphinAppNfc}, // DolphinDeedNfcMfcAdd - {1, DolphinAppNfc}, // DolphinDeedNfcMfulError {1, DolphinAppNfc}, // DolphinDeedNfcAddSave + {1, DolphinAppNfc}, // DolphinDeedNfcAddEmulate {1, DolphinAppIr}, // DolphinDeedIrSend {3, DolphinAppIr}, // DolphinDeedIrLearnSuccess diff --git a/applications/services/dolphin/helpers/dolphin_deed.h b/applications/services/dolphin/helpers/dolphin_deed.h index abe027d79..c9cd18f31 100644 --- a/applications/services/dolphin/helpers/dolphin_deed.h +++ b/applications/services/dolphin/helpers/dolphin_deed.h @@ -37,8 +37,8 @@ typedef enum { DolphinDeedNfcDetectReader, DolphinDeedNfcEmulate, DolphinDeedNfcMfcAdd, - DolphinDeedNfcMfulError, DolphinDeedNfcAddSave, + DolphinDeedNfcAddEmulate, DolphinDeedIrSend, DolphinDeedIrLearnSuccess, diff --git a/applications/services/gui/canvas.c b/applications/services/gui/canvas.c index 1e275aafb..a2979d56b 100644 --- a/applications/services/gui/canvas.c +++ b/applications/services/gui/canvas.c @@ -371,16 +371,39 @@ void canvas_set_bitmap_mode(Canvas* canvas, bool alpha) { void canvas_set_orientation(Canvas* canvas, CanvasOrientation orientation) { furi_assert(canvas); if(canvas->orientation != orientation) { - canvas->orientation = orientation; - if(canvas->orientation == CanvasOrientationHorizontal) { - FURI_SWAP(canvas->width, canvas->height); + switch(orientation) { + case CanvasOrientationHorizontal: + if(canvas->orientation == CanvasOrientationVertical || + canvas->orientation == CanvasOrientationVerticalFlip) { + FURI_SWAP(canvas->width, canvas->height); + } u8g2_SetDisplayRotation(&canvas->fb, U8G2_R0); - } else if(canvas->orientation == CanvasOrientationVertical) { - FURI_SWAP(canvas->width, canvas->height); + break; + case CanvasOrientationHorizontalFlip: + if(canvas->orientation == CanvasOrientationVertical || + canvas->orientation == CanvasOrientationVerticalFlip) { + FURI_SWAP(canvas->width, canvas->height); + } + u8g2_SetDisplayRotation(&canvas->fb, U8G2_R2); + break; + case CanvasOrientationVertical: + if(canvas->orientation == CanvasOrientationHorizontal || + canvas->orientation == CanvasOrientationHorizontalFlip) { + FURI_SWAP(canvas->width, canvas->height); + }; u8g2_SetDisplayRotation(&canvas->fb, U8G2_R3); - } else { + break; + case CanvasOrientationVerticalFlip: + if(canvas->orientation == CanvasOrientationHorizontal || + canvas->orientation == CanvasOrientationHorizontalFlip) { + FURI_SWAP(canvas->width, canvas->height); + } + u8g2_SetDisplayRotation(&canvas->fb, U8G2_R1); + break; + default: furi_assert(0); } + canvas->orientation = orientation; } } diff --git a/applications/services/gui/canvas.h b/applications/services/gui/canvas.h index 49bbd7d68..a3df5adc7 100644 --- a/applications/services/gui/canvas.h +++ b/applications/services/gui/canvas.h @@ -7,7 +7,7 @@ #include #include -#include +#include #ifdef __cplusplus extern "C" { @@ -42,7 +42,9 @@ typedef enum { /** Canvas Orientation */ typedef enum { CanvasOrientationHorizontal, + CanvasOrientationHorizontalFlip, CanvasOrientationVertical, + CanvasOrientationVerticalFlip, } CanvasOrientation; /** Font Direction */ diff --git a/applications/services/gui/gui.c b/applications/services/gui/gui.c index 0535b32b8..2d06d70c7 100644 --- a/applications/services/gui/gui.c +++ b/applications/services/gui/gui.c @@ -1,5 +1,6 @@ #include "gui/canvas.h" #include "gui_i.h" +#include #define TAG "GuiSrv" @@ -152,7 +153,7 @@ static void gui_redraw_status_bar(Gui* gui, bool need_attention) { } // Extra notification if(need_attention) { - width = icon_get_width(&I_Attention_5x8); + width = icon_get_width(&I_Hidden_window_9x8); // Prepare work area background canvas_frame_set( gui->canvas, @@ -166,7 +167,7 @@ static void gui_redraw_status_bar(Gui* gui, bool need_attention) { // Draw Icon canvas_frame_set( gui->canvas, x, GUI_STATUS_BAR_Y + 2, width, GUI_STATUS_BAR_WORKAREA_HEIGHT); - canvas_draw_icon(gui->canvas, 0, 0, &I_Attention_5x8); + canvas_draw_icon(gui->canvas, 0, 0, &I_Hidden_window_9x8); // Recalculate next position left_used += (width + 2); x += (width + 2); @@ -322,7 +323,9 @@ void gui_add_view_port(Gui* gui, ViewPort* view_port, GuiLayer layer) { furi_check(layer < GuiLayerMAX); // Only fullscreen supports Vertical orientation for now furi_assert( - (layer == GuiLayerFullscreen) || (view_port->orientation != ViewPortOrientationVertical)); + (layer == GuiLayerFullscreen) || + ((view_port->orientation != ViewPortOrientationVertical) && + (view_port->orientation != ViewPortOrientationVerticalFlip))); gui_lock(gui); // Verify that view port is not yet added diff --git a/applications/services/gui/icon_animation.h b/applications/services/gui/icon_animation.h index dab9d996d..684790353 100644 --- a/applications/services/gui/icon_animation.h +++ b/applications/services/gui/icon_animation.h @@ -7,7 +7,7 @@ #include #include -#include +#include #ifdef __cplusplus extern "C" { diff --git a/applications/services/gui/modules/button_menu.c b/applications/services/gui/modules/button_menu.c index 37a04326a..ff12a9311 100644 --- a/applications/services/gui/modules/button_menu.c +++ b/applications/services/gui/modules/button_menu.c @@ -5,6 +5,7 @@ #include #include #include +#include #define ITEM_FIRST_OFFSET 17 #define ITEM_NEXT_OFFSET 4 diff --git a/applications/services/gui/modules/byte_input.c b/applications/services/gui/modules/byte_input.c index 8d7e7fd4f..bc19f0eee 100644 --- a/applications/services/gui/modules/byte_input.c +++ b/applications/services/gui/modules/byte_input.c @@ -1,6 +1,7 @@ -#include "byte_input.h" -#include #include +#include +#include +#include "byte_input.h" struct ByteInput { View* view; diff --git a/applications/services/gui/modules/menu.c b/applications/services/gui/modules/menu.c index db0717f77..6983e0108 100644 --- a/applications/services/gui/modules/menu.c +++ b/applications/services/gui/modules/menu.c @@ -2,6 +2,7 @@ #include #include +#include #include struct Menu { diff --git a/applications/services/gui/modules/text_input.c b/applications/services/gui/modules/text_input.c index 79fa87728..540e4b7c4 100644 --- a/applications/services/gui/modules/text_input.c +++ b/applications/services/gui/modules/text_input.c @@ -1,5 +1,6 @@ #include "text_input.h" #include +#include #include struct TextInput { diff --git a/applications/services/gui/view.h b/applications/services/gui/view.h index b40f8ded5..7a2003a63 100644 --- a/applications/services/gui/view.h +++ b/applications/services/gui/view.h @@ -25,7 +25,9 @@ extern "C" { typedef enum { ViewOrientationHorizontal, + ViewOrientationHorizontalFlip, ViewOrientationVertical, + ViewOrientationVerticalFlip, } ViewOrientation; /** View, anonymous type */ diff --git a/applications/services/gui/view_dispatcher.c b/applications/services/gui/view_dispatcher.c index 6e4ce8360..1736558cb 100644 --- a/applications/services/gui/view_dispatcher.c +++ b/applications/services/gui/view_dispatcher.c @@ -331,10 +331,16 @@ void view_dispatcher_set_current_view(ViewDispatcher* view_dispatcher, View* vie view_dispatcher->current_view = view; // Dispatch view enter event if(view_dispatcher->current_view) { - if(view->orientation == ViewOrientationVertical) + if(view->orientation == ViewOrientationVertical) { view_port_set_orientation(view_dispatcher->view_port, ViewPortOrientationVertical); - else if(view->orientation == ViewOrientationHorizontal) + } else if(view->orientation == ViewOrientationVerticalFlip) { + view_port_set_orientation(view_dispatcher->view_port, ViewPortOrientationVerticalFlip); + } else if(view->orientation == ViewOrientationHorizontal) { view_port_set_orientation(view_dispatcher->view_port, ViewPortOrientationHorizontal); + } else if(view->orientation == ViewOrientationHorizontalFlip) { + view_port_set_orientation( + view_dispatcher->view_port, ViewPortOrientationHorizontalFlip); + } view_enter(view_dispatcher->current_view); view_port_enabled_set(view_dispatcher->view_port, true); view_port_update(view_dispatcher->view_port); diff --git a/applications/services/gui/view_port.c b/applications/services/gui/view_port.c index 8069a02e5..baa8f7bd2 100644 --- a/applications/services/gui/view_port.c +++ b/applications/services/gui/view_port.c @@ -7,7 +7,7 @@ // TODO add mutex to view_port ops -static void view_port_rotate_buttons(InputEvent* event) { +static void view_port_remap_buttons_vertical(InputEvent* event) { switch(event->key) { case InputKeyUp: event->key = InputKeyRight; @@ -26,14 +26,61 @@ static void view_port_rotate_buttons(InputEvent* event) { } } -static void view_port_setup_canvas_orientation(const ViewPort* view_port, Canvas* canvas) { - if(view_port->orientation == ViewPortOrientationHorizontal) { - canvas_set_orientation(canvas, CanvasOrientationHorizontal); - } else if(view_port->orientation == ViewPortOrientationVertical) { - canvas_set_orientation(canvas, CanvasOrientationVertical); +static void view_port_remap_buttons_vertical_flip(InputEvent* event) { + switch(event->key) { + case InputKeyUp: + event->key = InputKeyLeft; + break; + case InputKeyDown: + event->key = InputKeyRight; + break; + case InputKeyRight: + event->key = InputKeyUp; + break; + case InputKeyLeft: + event->key = InputKeyDown; + break; + default: + break; } } +static void view_port_remap_buttons_horizontal_flip(InputEvent* event) { + switch(event->key) { + case InputKeyUp: + event->key = InputKeyDown; + break; + case InputKeyDown: + event->key = InputKeyUp; + break; + case InputKeyRight: + event->key = InputKeyLeft; + break; + case InputKeyLeft: + event->key = InputKeyRight; + break; + default: + break; + } +} + +static void view_port_setup_canvas_orientation(const ViewPort* view_port, Canvas* canvas) { + switch(view_port->orientation) { + case ViewPortOrientationHorizontalFlip: + canvas_set_orientation(canvas, CanvasOrientationHorizontalFlip); + break; + case ViewPortOrientationVertical: + canvas_set_orientation(canvas, CanvasOrientationVertical); + break; + case ViewPortOrientationVerticalFlip: + canvas_set_orientation(canvas, CanvasOrientationVerticalFlip); + break; + default: + canvas_set_orientation(canvas, CanvasOrientationHorizontal); + break; + }; +} + ViewPort* view_port_alloc() { ViewPort* view_port = malloc(sizeof(ViewPort)); view_port->orientation = ViewPortOrientationHorizontal; @@ -122,8 +169,19 @@ void view_port_input(ViewPort* view_port, InputEvent* event) { furi_check(view_port->gui); if(view_port->input_callback) { - if(view_port_get_orientation(view_port) == ViewPortOrientationVertical) { - view_port_rotate_buttons(event); + ViewPortOrientation orientation = view_port_get_orientation(view_port); + switch(orientation) { + case ViewPortOrientationHorizontalFlip: + view_port_remap_buttons_horizontal_flip(event); + break; + case ViewPortOrientationVertical: + view_port_remap_buttons_vertical(event); + break; + case ViewPortOrientationVerticalFlip: + view_port_remap_buttons_vertical_flip(event); + break; + default: + break; } view_port->input_callback(event, view_port->input_callback_context); } diff --git a/applications/services/gui/view_port.h b/applications/services/gui/view_port.h index 96f2798e2..169681ac0 100644 --- a/applications/services/gui/view_port.h +++ b/applications/services/gui/view_port.h @@ -16,7 +16,9 @@ typedef struct ViewPort ViewPort; typedef enum { ViewPortOrientationHorizontal, + ViewPortOrientationHorizontalFlip, ViewPortOrientationVertical, + ViewPortOrientationVerticalFlip, } ViewPortOrientation; /** ViewPort Draw callback diff --git a/applications/services/power/power_service/power_i.h b/applications/services/power/power_service/power_i.h index 38dc59224..25a5b6ac2 100644 --- a/applications/services/power/power_service/power_i.h +++ b/applications/services/power/power_service/power_i.h @@ -5,6 +5,7 @@ #include #include #include +#include #include #include "views/power_off.h" diff --git a/applications/services/power/power_service/views/power_off.c b/applications/services/power/power_service/views/power_off.c index b0046325c..f14a18d7e 100644 --- a/applications/services/power/power_service/views/power_off.c +++ b/applications/services/power/power_service/views/power_off.c @@ -1,6 +1,7 @@ #include "power_off.h" #include #include +#include struct PowerOff { View* view; diff --git a/applications/services/power/power_service/views/power_unplug_usb.c b/applications/services/power/power_service/views/power_unplug_usb.c index 5632cd8b0..c2d61139e 100644 --- a/applications/services/power/power_service/views/power_unplug_usb.c +++ b/applications/services/power/power_service/views/power_unplug_usb.c @@ -1,6 +1,7 @@ #include "power_unplug_usb.h" #include #include +#include struct PowerUnplugUsb { View* view; diff --git a/applications/services/rpc/rpc.c b/applications/services/rpc/rpc.c index 06c05173c..73eaadfb1 100644 --- a/applications/services/rpc/rpc.c +++ b/applications/services/rpc/rpc.c @@ -148,7 +148,8 @@ size_t rpc_session_feed(RpcSession* session, uint8_t* encoded_bytes, size_t size, TickType_t timeout) { furi_assert(session); furi_assert(encoded_bytes); - furi_assert(size > 0); + + if(!size) return 0; size_t bytes_sent = furi_stream_buffer_send(session->stream, encoded_bytes, size, timeout); diff --git a/applications/services/storage/storage.c b/applications/services/storage/storage.c index 9079a95ed..700408c9d 100644 --- a/applications/services/storage/storage.c +++ b/applications/services/storage/storage.c @@ -5,6 +5,7 @@ #include "storage/storage_glue.h" #include "storages/storage_int.h" #include "storages/storage_ext.h" +#include #define STORAGE_TICK 1000 diff --git a/applications/settings/about/about.c b/applications/settings/about/about.c index a42969b2b..1719e188d 100644 --- a/applications/settings/about/about.c +++ b/applications/settings/about/about.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include diff --git a/applications/settings/bt_settings_app/bt_settings_app.h b/applications/settings/bt_settings_app/bt_settings_app.h index c45ff3db0..b79e36951 100644 --- a/applications/settings/bt_settings_app/bt_settings_app.h +++ b/applications/settings/bt_settings_app/bt_settings_app.h @@ -6,6 +6,7 @@ #include #include #include +#include #include #include diff --git a/applications/settings/desktop_settings/desktop_settings_app.h b/applications/settings/desktop_settings/desktop_settings_app.h index fc56c3253..6f97564c9 100644 --- a/applications/settings/desktop_settings/desktop_settings_app.h +++ b/applications/settings/desktop_settings/desktop_settings_app.h @@ -7,6 +7,7 @@ #include #include #include +#include #include #include diff --git a/applications/settings/power_settings_app/power_settings_app.h b/applications/settings/power_settings_app/power_settings_app.h index c128215d0..d30cbaf43 100644 --- a/applications/settings/power_settings_app/power_settings_app.h +++ b/applications/settings/power_settings_app/power_settings_app.h @@ -6,6 +6,7 @@ #include #include #include +#include #include "views/battery_info.h" #include diff --git a/applications/settings/power_settings_app/views/battery_info.c b/applications/settings/power_settings_app/views/battery_info.c index 1a8bc71ec..e1b7adb4b 100644 --- a/applications/settings/power_settings_app/views/battery_info.c +++ b/applications/settings/power_settings_app/views/battery_info.c @@ -1,6 +1,7 @@ #include "battery_info.h" #include #include +#include struct BatteryInfo { View* view; diff --git a/applications/settings/storage_settings/scenes/storage_settings_scene_factory_reset.c b/applications/settings/storage_settings/scenes/storage_settings_scene_factory_reset.c index 64d2b96b1..865ee48d4 100644 --- a/applications/settings/storage_settings/scenes/storage_settings_scene_factory_reset.c +++ b/applications/settings/storage_settings/scenes/storage_settings_scene_factory_reset.c @@ -24,7 +24,7 @@ void storage_settings_scene_factory_reset_on_enter(void* context) { dialog_ex_set_header(dialog_ex, "Confirm Factory Reset", 64, 10, AlignCenter, AlignCenter); dialog_ex_set_text( dialog_ex, - "Internal storage will be erased\r\nData and setting will be lost!", + "Internal storage will be erased\r\nData and settings will be lost!", 64, 32, AlignCenter, diff --git a/applications/settings/storage_settings/storage_settings.h b/applications/settings/storage_settings/storage_settings.h index 4cf185e0c..664e74c84 100644 --- a/applications/settings/storage_settings/storage_settings.h +++ b/applications/settings/storage_settings/storage_settings.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include diff --git a/applications/system/updater/views/updater_main.c b/applications/system/updater/views/updater_main.c index 5ed3c70aa..1199cc882 100644 --- a/applications/system/updater/views/updater_main.c +++ b/applications/system/updater/views/updater_main.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include diff --git a/assets/.gitignore b/assets/.gitignore index 9bc0bdc0c..269577047 100644 --- a/assets/.gitignore +++ b/assets/.gitignore @@ -1,3 +1,4 @@ /core2_firmware /resources/Manifest -/resources/apps/* \ No newline at end of file +/resources/apps/* +/resources/dolphin/* diff --git a/assets/SConscript b/assets/SConscript index e1bf546cc..63141829e 100644 --- a/assets/SConscript +++ b/assets/SConscript @@ -68,15 +68,17 @@ if assetsenv["IS_BASE_FIRMWARE"]: assetsenv.Dir("#/assets/dolphin"), DOLPHIN_RES_TYPE="external", ) - assetsenv.NoClean(dolphin_external) if assetsenv["FORCE"]: assetsenv.AlwaysBuild(dolphin_external) assetsenv.Alias("dolphin_ext", dolphin_external) + assetsenv.Clean(dolphin_external, assetsenv.Dir("#/assets/resources/dolphin")) # Resources manifest resources = assetsenv.Command( "#/assets/resources/Manifest", - assetsenv.GlobRecursive("*", "resources", exclude="Manifest"), + assetsenv.GlobRecursive( + "*", assetsenv.Dir("resources").srcnode(), exclude="Manifest" + ), action=Action( '${PYTHON3} "${ASSETS_COMPILER}" manifest "${TARGET.dir.posix}" --timestamp=${GIT_UNIX_TIMESTAMP}', "${RESMANIFESTCOMSTR}", diff --git a/assets/icons/Infrared/Pause_25x27.png b/assets/icons/Infrared/Pause_25x27.png new file mode 100644 index 000000000..a371ba817 Binary files /dev/null and b/assets/icons/Infrared/Pause_25x27.png differ diff --git a/assets/icons/Infrared/Pause_hvr_25x27.png b/assets/icons/Infrared/Pause_hvr_25x27.png new file mode 100644 index 000000000..472d583db Binary files /dev/null and b/assets/icons/Infrared/Pause_hvr_25x27.png differ diff --git a/assets/icons/Infrared/Play_25x27.png b/assets/icons/Infrared/Play_25x27.png new file mode 100644 index 000000000..fb793c5a9 Binary files /dev/null and b/assets/icons/Infrared/Play_25x27.png differ diff --git a/assets/icons/Infrared/Play_hvr_25x27.png b/assets/icons/Infrared/Play_hvr_25x27.png new file mode 100644 index 000000000..6708dcdbf Binary files /dev/null and b/assets/icons/Infrared/Play_hvr_25x27.png differ diff --git a/assets/icons/Infrared/TrackNext_25x27.png b/assets/icons/Infrared/TrackNext_25x27.png new file mode 100644 index 000000000..7b8f28391 Binary files /dev/null and b/assets/icons/Infrared/TrackNext_25x27.png differ diff --git a/assets/icons/Infrared/TrackNext_hvr_25x27.png b/assets/icons/Infrared/TrackNext_hvr_25x27.png new file mode 100644 index 000000000..a4de4fc3c Binary files /dev/null and b/assets/icons/Infrared/TrackNext_hvr_25x27.png differ diff --git a/assets/icons/Infrared/TrackPrev_25x27.png b/assets/icons/Infrared/TrackPrev_25x27.png new file mode 100644 index 000000000..3cd2a8da6 Binary files /dev/null and b/assets/icons/Infrared/TrackPrev_25x27.png differ diff --git a/assets/icons/Infrared/TrackPrev_hvr_25x27.png b/assets/icons/Infrared/TrackPrev_hvr_25x27.png new file mode 100644 index 000000000..838055341 Binary files /dev/null and b/assets/icons/Infrared/TrackPrev_hvr_25x27.png differ diff --git a/assets/icons/StatusBar/Alert_9x8.png b/assets/icons/StatusBar/Alert_9x8.png new file mode 100644 index 000000000..d03f107ef Binary files /dev/null and b/assets/icons/StatusBar/Alert_9x8.png differ diff --git a/assets/icons/StatusBar/Hidden_window_9x8.png b/assets/icons/StatusBar/Hidden_window_9x8.png new file mode 100644 index 000000000..d6fc2b326 Binary files /dev/null and b/assets/icons/StatusBar/Hidden_window_9x8.png differ diff --git a/assets/resources/dolphin/L1_Boxing_128x64/frame_0.bm b/assets/resources/dolphin/L1_Boxing_128x64/frame_0.bm deleted file mode 100644 index 46079c372..000000000 Binary files a/assets/resources/dolphin/L1_Boxing_128x64/frame_0.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Boxing_128x64/frame_1.bm b/assets/resources/dolphin/L1_Boxing_128x64/frame_1.bm deleted file mode 100644 index e12d70796..000000000 Binary files a/assets/resources/dolphin/L1_Boxing_128x64/frame_1.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Boxing_128x64/frame_2.bm b/assets/resources/dolphin/L1_Boxing_128x64/frame_2.bm deleted file mode 100644 index b416740f2..000000000 Binary files a/assets/resources/dolphin/L1_Boxing_128x64/frame_2.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Boxing_128x64/frame_3.bm b/assets/resources/dolphin/L1_Boxing_128x64/frame_3.bm deleted file mode 100644 index b7e15ddee..000000000 Binary files a/assets/resources/dolphin/L1_Boxing_128x64/frame_3.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Boxing_128x64/frame_4.bm b/assets/resources/dolphin/L1_Boxing_128x64/frame_4.bm deleted file mode 100644 index 202ad6e37..000000000 Binary files a/assets/resources/dolphin/L1_Boxing_128x64/frame_4.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Boxing_128x64/frame_5.bm b/assets/resources/dolphin/L1_Boxing_128x64/frame_5.bm deleted file mode 100644 index cdc0a2a34..000000000 Binary files a/assets/resources/dolphin/L1_Boxing_128x64/frame_5.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Boxing_128x64/frame_6.bm b/assets/resources/dolphin/L1_Boxing_128x64/frame_6.bm deleted file mode 100644 index e8ea3aa68..000000000 Binary files a/assets/resources/dolphin/L1_Boxing_128x64/frame_6.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Boxing_128x64/meta.txt b/assets/resources/dolphin/L1_Boxing_128x64/meta.txt deleted file mode 100644 index c66998e7d..000000000 --- a/assets/resources/dolphin/L1_Boxing_128x64/meta.txt +++ /dev/null @@ -1,32 +0,0 @@ -Filetype: Flipper Animation -Version: 1 - -Width: 128 -Height: 64 -Passive frames: 9 -Active frames: 7 -Frames order: 0 1 2 1 3 1 2 3 1 4 5 6 5 6 5 4 -Active cycles: 1 -Frame rate: 2 -Duration: 3600 -Active cooldown: 7 - -Bubble slots: 2 - -Slot: 0 -X: 78 -Y: 16 -Text: F*&K!!! -AlignH: Left -AlignV: Bottom -StartFrame: 2 -EndFrame: 4 - -Slot: 1 -X: 78 -Y: 16 -Text: What ya\nlookin at?! -AlignH: Left -AlignV: Center -StartFrame: 10 -EndFrame: 15 diff --git a/assets/resources/dolphin/L1_Cry_128x64/frame_0.bm b/assets/resources/dolphin/L1_Cry_128x64/frame_0.bm deleted file mode 100644 index 9147714c1..000000000 Binary files a/assets/resources/dolphin/L1_Cry_128x64/frame_0.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Cry_128x64/frame_1.bm b/assets/resources/dolphin/L1_Cry_128x64/frame_1.bm deleted file mode 100644 index 789273d9d..000000000 Binary files a/assets/resources/dolphin/L1_Cry_128x64/frame_1.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Cry_128x64/frame_2.bm b/assets/resources/dolphin/L1_Cry_128x64/frame_2.bm deleted file mode 100644 index a3c87e0a6..000000000 Binary files a/assets/resources/dolphin/L1_Cry_128x64/frame_2.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Cry_128x64/frame_3.bm b/assets/resources/dolphin/L1_Cry_128x64/frame_3.bm deleted file mode 100644 index ba3012b7e..000000000 Binary files a/assets/resources/dolphin/L1_Cry_128x64/frame_3.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Cry_128x64/frame_4.bm b/assets/resources/dolphin/L1_Cry_128x64/frame_4.bm deleted file mode 100644 index 1ce28c7ad..000000000 Binary files a/assets/resources/dolphin/L1_Cry_128x64/frame_4.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Cry_128x64/frame_5.bm b/assets/resources/dolphin/L1_Cry_128x64/frame_5.bm deleted file mode 100644 index 4cbc49689..000000000 Binary files a/assets/resources/dolphin/L1_Cry_128x64/frame_5.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Cry_128x64/frame_6.bm b/assets/resources/dolphin/L1_Cry_128x64/frame_6.bm deleted file mode 100644 index cba81ef35..000000000 Binary files a/assets/resources/dolphin/L1_Cry_128x64/frame_6.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Cry_128x64/frame_7.bm b/assets/resources/dolphin/L1_Cry_128x64/frame_7.bm deleted file mode 100644 index da28419fd..000000000 Binary files a/assets/resources/dolphin/L1_Cry_128x64/frame_7.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Cry_128x64/meta.txt b/assets/resources/dolphin/L1_Cry_128x64/meta.txt deleted file mode 100644 index 1b7d13dd8..000000000 --- a/assets/resources/dolphin/L1_Cry_128x64/meta.txt +++ /dev/null @@ -1,41 +0,0 @@ -Filetype: Flipper Animation -Version: 1 - -Width: 128 -Height: 64 -Passive frames: 8 -Active frames: 4 -Frames order: 0 1 2 3 4 2 3 4 5 6 7 6 -Active cycles: 2 -Frame rate: 2 -Duration: 3600 -Active cooldown: 7 - -Bubble slots: 2 - -Slot: 0 -X: 22 -Y: 40 -Text: I miss you -AlignH: Right -AlignV: Bottom -StartFrame: 9 -EndFrame: 11 - -Slot: 0 -X: 17 -Y: 40 -Text: my friend... -AlignH: Right -AlignV: Bottom -StartFrame: 12 -EndFrame: 15 - -Slot: 1 -X: 2 -Y: 29 -Text: Why are you\nalways away? -AlignH: Right -AlignV: Bottom -StartFrame: 9 -EndFrame: 15 diff --git a/assets/resources/dolphin/L1_Furippa1_128x64/frame_0.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_0.bm deleted file mode 100644 index 8558f0f5b..000000000 Binary files a/assets/resources/dolphin/L1_Furippa1_128x64/frame_0.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Furippa1_128x64/frame_1.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_1.bm deleted file mode 100644 index ac7a126ea..000000000 Binary files a/assets/resources/dolphin/L1_Furippa1_128x64/frame_1.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Furippa1_128x64/frame_10.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_10.bm deleted file mode 100644 index c5312e5e5..000000000 Binary files a/assets/resources/dolphin/L1_Furippa1_128x64/frame_10.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Furippa1_128x64/frame_11.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_11.bm deleted file mode 100644 index c91ed2fd2..000000000 Binary files a/assets/resources/dolphin/L1_Furippa1_128x64/frame_11.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Furippa1_128x64/frame_12.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_12.bm deleted file mode 100644 index 392905a55..000000000 Binary files a/assets/resources/dolphin/L1_Furippa1_128x64/frame_12.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Furippa1_128x64/frame_13.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_13.bm deleted file mode 100644 index aa5353e98..000000000 Binary files a/assets/resources/dolphin/L1_Furippa1_128x64/frame_13.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Furippa1_128x64/frame_14.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_14.bm deleted file mode 100644 index 837c6c71d..000000000 Binary files a/assets/resources/dolphin/L1_Furippa1_128x64/frame_14.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Furippa1_128x64/frame_15.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_15.bm deleted file mode 100644 index 4cb6e5332..000000000 Binary files a/assets/resources/dolphin/L1_Furippa1_128x64/frame_15.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Furippa1_128x64/frame_16.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_16.bm deleted file mode 100644 index ce3ccdece..000000000 Binary files a/assets/resources/dolphin/L1_Furippa1_128x64/frame_16.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Furippa1_128x64/frame_17.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_17.bm deleted file mode 100644 index 02af0bcf3..000000000 Binary files a/assets/resources/dolphin/L1_Furippa1_128x64/frame_17.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Furippa1_128x64/frame_18.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_18.bm deleted file mode 100644 index 72620a7c9..000000000 Binary files a/assets/resources/dolphin/L1_Furippa1_128x64/frame_18.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Furippa1_128x64/frame_2.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_2.bm deleted file mode 100644 index 94357802f..000000000 Binary files a/assets/resources/dolphin/L1_Furippa1_128x64/frame_2.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Furippa1_128x64/frame_3.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_3.bm deleted file mode 100644 index b0d0e6914..000000000 Binary files a/assets/resources/dolphin/L1_Furippa1_128x64/frame_3.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Furippa1_128x64/frame_4.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_4.bm deleted file mode 100644 index 3413e5072..000000000 Binary files a/assets/resources/dolphin/L1_Furippa1_128x64/frame_4.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Furippa1_128x64/frame_5.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_5.bm deleted file mode 100644 index fd83dd1c6..000000000 Binary files a/assets/resources/dolphin/L1_Furippa1_128x64/frame_5.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Furippa1_128x64/frame_6.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_6.bm deleted file mode 100644 index 8c946d184..000000000 Binary files a/assets/resources/dolphin/L1_Furippa1_128x64/frame_6.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Furippa1_128x64/frame_7.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_7.bm deleted file mode 100644 index 8558f0f5b..000000000 Binary files a/assets/resources/dolphin/L1_Furippa1_128x64/frame_7.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Furippa1_128x64/frame_8.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_8.bm deleted file mode 100644 index a57e4bac7..000000000 Binary files a/assets/resources/dolphin/L1_Furippa1_128x64/frame_8.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Furippa1_128x64/frame_9.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_9.bm deleted file mode 100644 index 114b26391..000000000 Binary files a/assets/resources/dolphin/L1_Furippa1_128x64/frame_9.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Furippa1_128x64/meta.txt b/assets/resources/dolphin/L1_Furippa1_128x64/meta.txt deleted file mode 100644 index c21027e49..000000000 --- a/assets/resources/dolphin/L1_Furippa1_128x64/meta.txt +++ /dev/null @@ -1,14 +0,0 @@ -Filetype: Flipper Animation -Version: 1 - -Width: 128 -Height: 64 -Passive frames: 8 -Active frames: 11 -Frames order: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 -Active cycles: 1 -Frame rate: 2 -Duration: 3600 -Active cooldown: 7 - -Bubble slots: 0 diff --git a/assets/resources/dolphin/L1_Laptop_128x51/frame_0.bm b/assets/resources/dolphin/L1_Laptop_128x51/frame_0.bm deleted file mode 100644 index 5eb2bdd05..000000000 Binary files a/assets/resources/dolphin/L1_Laptop_128x51/frame_0.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Laptop_128x51/frame_1.bm b/assets/resources/dolphin/L1_Laptop_128x51/frame_1.bm deleted file mode 100644 index 210f0c918..000000000 Binary files a/assets/resources/dolphin/L1_Laptop_128x51/frame_1.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Laptop_128x51/frame_2.bm b/assets/resources/dolphin/L1_Laptop_128x51/frame_2.bm deleted file mode 100644 index ff2851c28..000000000 Binary files a/assets/resources/dolphin/L1_Laptop_128x51/frame_2.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Laptop_128x51/frame_3.bm b/assets/resources/dolphin/L1_Laptop_128x51/frame_3.bm deleted file mode 100644 index 360d405ab..000000000 Binary files a/assets/resources/dolphin/L1_Laptop_128x51/frame_3.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Laptop_128x51/frame_4.bm b/assets/resources/dolphin/L1_Laptop_128x51/frame_4.bm deleted file mode 100644 index 9dd5111f8..000000000 Binary files a/assets/resources/dolphin/L1_Laptop_128x51/frame_4.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Laptop_128x51/frame_5.bm b/assets/resources/dolphin/L1_Laptop_128x51/frame_5.bm deleted file mode 100644 index e56c3f1a8..000000000 Binary files a/assets/resources/dolphin/L1_Laptop_128x51/frame_5.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Laptop_128x51/frame_6.bm b/assets/resources/dolphin/L1_Laptop_128x51/frame_6.bm deleted file mode 100644 index e9b0c0dff..000000000 Binary files a/assets/resources/dolphin/L1_Laptop_128x51/frame_6.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Laptop_128x51/frame_7.bm b/assets/resources/dolphin/L1_Laptop_128x51/frame_7.bm deleted file mode 100644 index 4663c6b03..000000000 Binary files a/assets/resources/dolphin/L1_Laptop_128x51/frame_7.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Laptop_128x51/meta.txt b/assets/resources/dolphin/L1_Laptop_128x51/meta.txt deleted file mode 100644 index 90cdc5ce9..000000000 --- a/assets/resources/dolphin/L1_Laptop_128x51/meta.txt +++ /dev/null @@ -1,32 +0,0 @@ -Filetype: Flipper Animation -Version: 1 - -Width: 128 -Height: 51 -Passive frames: 6 -Active frames: 2 -Frames order: 0 1 2 3 4 5 6 7 -Active cycles: 4 -Frame rate: 2 -Duration: 3600 -Active cooldown: 7 - -Bubble slots: 1 - -Slot: 0 -X: 60 -Y: 23 -Text: I have to rest -AlignH: Left -AlignV: Bottom -StartFrame: 7 -EndFrame: 10 - -Slot: 0 -X: 60 -Y: 23 -Text: but not today -AlignH: Left -AlignV: Bottom -StartFrame: 11 -EndFrame: 13 diff --git a/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_0.bm b/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_0.bm deleted file mode 100644 index d4cf85bad..000000000 Binary files a/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_0.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_1.bm b/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_1.bm deleted file mode 100644 index f1f0e89f0..000000000 Binary files a/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_1.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_10.bm b/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_10.bm deleted file mode 100644 index b91030b12..000000000 Binary files a/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_10.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_11.bm b/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_11.bm deleted file mode 100644 index fe93787f2..000000000 Binary files a/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_11.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_12.bm b/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_12.bm deleted file mode 100644 index 13fb8e985..000000000 Binary files a/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_12.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_2.bm b/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_2.bm deleted file mode 100644 index 3050ba38f..000000000 Binary files a/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_2.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_3.bm b/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_3.bm deleted file mode 100644 index 0c0c83238..000000000 Binary files a/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_3.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_4.bm b/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_4.bm deleted file mode 100644 index 5e74ea12a..000000000 Binary files a/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_4.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_5.bm b/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_5.bm deleted file mode 100644 index 5c556cfdf..000000000 Binary files a/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_5.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_6.bm b/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_6.bm deleted file mode 100644 index 1dc156764..000000000 Binary files a/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_6.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_7.bm b/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_7.bm deleted file mode 100644 index e992d75c7..000000000 Binary files a/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_7.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_8.bm b/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_8.bm deleted file mode 100644 index 49266d7c2..000000000 Binary files a/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_8.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_9.bm b/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_9.bm deleted file mode 100644 index 6ebc55c16..000000000 Binary files a/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_9.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Leaving_sad_128x64/meta.txt b/assets/resources/dolphin/L1_Leaving_sad_128x64/meta.txt deleted file mode 100644 index 876003079..000000000 --- a/assets/resources/dolphin/L1_Leaving_sad_128x64/meta.txt +++ /dev/null @@ -1,32 +0,0 @@ -Filetype: Flipper Animation -Version: 1 - -Width: 128 -Height: 64 -Passive frames: 4 -Active frames: 42 -Frames order: 0 1 2 1 3 4 5 6 7 8 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 10 11 12 4 3 -Active cycles: 1 -Frame rate: 2 -Duration: 3600 -Active cooldown: 7 - -Bubble slots: 1 - -Slot: 0 -X: 51 -Y: 49 -Text: Adios. -AlignH: Center -AlignV: Top -StartFrame: 6 -EndFrame: 9 - -Slot: 0 -X: 1 -Y: 49 -Text: Forgot something... -AlignH: Center -AlignV: Top -StartFrame: 42 -EndFrame: 45 diff --git a/assets/resources/dolphin/L1_Mad_fist_128x64/frame_0.bm b/assets/resources/dolphin/L1_Mad_fist_128x64/frame_0.bm deleted file mode 100644 index d200bb2af..000000000 Binary files a/assets/resources/dolphin/L1_Mad_fist_128x64/frame_0.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Mad_fist_128x64/frame_1.bm b/assets/resources/dolphin/L1_Mad_fist_128x64/frame_1.bm deleted file mode 100644 index 0ec761cbf..000000000 Binary files a/assets/resources/dolphin/L1_Mad_fist_128x64/frame_1.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Mad_fist_128x64/frame_10.bm b/assets/resources/dolphin/L1_Mad_fist_128x64/frame_10.bm deleted file mode 100644 index d4207c95d..000000000 Binary files a/assets/resources/dolphin/L1_Mad_fist_128x64/frame_10.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Mad_fist_128x64/frame_11.bm b/assets/resources/dolphin/L1_Mad_fist_128x64/frame_11.bm deleted file mode 100644 index 35955bc20..000000000 Binary files a/assets/resources/dolphin/L1_Mad_fist_128x64/frame_11.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Mad_fist_128x64/frame_12.bm b/assets/resources/dolphin/L1_Mad_fist_128x64/frame_12.bm deleted file mode 100644 index 80adf8671..000000000 Binary files a/assets/resources/dolphin/L1_Mad_fist_128x64/frame_12.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Mad_fist_128x64/frame_13.bm b/assets/resources/dolphin/L1_Mad_fist_128x64/frame_13.bm deleted file mode 100644 index 1994c0966..000000000 Binary files a/assets/resources/dolphin/L1_Mad_fist_128x64/frame_13.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Mad_fist_128x64/frame_2.bm b/assets/resources/dolphin/L1_Mad_fist_128x64/frame_2.bm deleted file mode 100644 index d3f19290d..000000000 Binary files a/assets/resources/dolphin/L1_Mad_fist_128x64/frame_2.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Mad_fist_128x64/frame_3.bm b/assets/resources/dolphin/L1_Mad_fist_128x64/frame_3.bm deleted file mode 100644 index 1fc2e2b26..000000000 Binary files a/assets/resources/dolphin/L1_Mad_fist_128x64/frame_3.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Mad_fist_128x64/frame_4.bm b/assets/resources/dolphin/L1_Mad_fist_128x64/frame_4.bm deleted file mode 100644 index 6152a83f8..000000000 Binary files a/assets/resources/dolphin/L1_Mad_fist_128x64/frame_4.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Mad_fist_128x64/frame_5.bm b/assets/resources/dolphin/L1_Mad_fist_128x64/frame_5.bm deleted file mode 100644 index 842600e6d..000000000 Binary files a/assets/resources/dolphin/L1_Mad_fist_128x64/frame_5.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Mad_fist_128x64/frame_6.bm b/assets/resources/dolphin/L1_Mad_fist_128x64/frame_6.bm deleted file mode 100644 index 887a4b866..000000000 Binary files a/assets/resources/dolphin/L1_Mad_fist_128x64/frame_6.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Mad_fist_128x64/frame_7.bm b/assets/resources/dolphin/L1_Mad_fist_128x64/frame_7.bm deleted file mode 100644 index 8e9a34e97..000000000 Binary files a/assets/resources/dolphin/L1_Mad_fist_128x64/frame_7.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Mad_fist_128x64/frame_8.bm b/assets/resources/dolphin/L1_Mad_fist_128x64/frame_8.bm deleted file mode 100644 index a430e480a..000000000 Binary files a/assets/resources/dolphin/L1_Mad_fist_128x64/frame_8.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Mad_fist_128x64/frame_9.bm b/assets/resources/dolphin/L1_Mad_fist_128x64/frame_9.bm deleted file mode 100644 index 487f50b35..000000000 Binary files a/assets/resources/dolphin/L1_Mad_fist_128x64/frame_9.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Mad_fist_128x64/meta.txt b/assets/resources/dolphin/L1_Mad_fist_128x64/meta.txt deleted file mode 100644 index 93e59e49b..000000000 --- a/assets/resources/dolphin/L1_Mad_fist_128x64/meta.txt +++ /dev/null @@ -1,23 +0,0 @@ -Filetype: Flipper Animation -Version: 1 - -Width: 128 -Height: 64 -Passive frames: 7 -Active frames: 13 -Frames order: 0 1 0 1 2 3 4 5 6 7 8 9 10 11 12 13 12 13 12 13 -Active cycles: 1 -Frame rate: 2 -Duration: 3600 -Active cooldown: 7 - -Bubble slots: 1 - -Slot: 0 -X: 67 -Y: 24 -Text: Am I a joke\nto you?!?! -AlignH: Left -AlignV: Center -StartFrame: 15 -EndFrame: 19 diff --git a/assets/resources/dolphin/L1_Painting_128x64/frame_0.bm b/assets/resources/dolphin/L1_Painting_128x64/frame_0.bm deleted file mode 100644 index 2694219ef..000000000 Binary files a/assets/resources/dolphin/L1_Painting_128x64/frame_0.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Painting_128x64/frame_1.bm b/assets/resources/dolphin/L1_Painting_128x64/frame_1.bm deleted file mode 100644 index 3c9623d4c..000000000 Binary files a/assets/resources/dolphin/L1_Painting_128x64/frame_1.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Painting_128x64/frame_10.bm b/assets/resources/dolphin/L1_Painting_128x64/frame_10.bm deleted file mode 100644 index 64a750e95..000000000 Binary files a/assets/resources/dolphin/L1_Painting_128x64/frame_10.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Painting_128x64/frame_11.bm b/assets/resources/dolphin/L1_Painting_128x64/frame_11.bm deleted file mode 100644 index af1503fef..000000000 Binary files a/assets/resources/dolphin/L1_Painting_128x64/frame_11.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Painting_128x64/frame_2.bm b/assets/resources/dolphin/L1_Painting_128x64/frame_2.bm deleted file mode 100644 index 13916806f..000000000 Binary files a/assets/resources/dolphin/L1_Painting_128x64/frame_2.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Painting_128x64/frame_3.bm b/assets/resources/dolphin/L1_Painting_128x64/frame_3.bm deleted file mode 100644 index 751fbc3ef..000000000 Binary files a/assets/resources/dolphin/L1_Painting_128x64/frame_3.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Painting_128x64/frame_4.bm b/assets/resources/dolphin/L1_Painting_128x64/frame_4.bm deleted file mode 100644 index c1135b467..000000000 Binary files a/assets/resources/dolphin/L1_Painting_128x64/frame_4.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Painting_128x64/frame_5.bm b/assets/resources/dolphin/L1_Painting_128x64/frame_5.bm deleted file mode 100644 index a4681af98..000000000 Binary files a/assets/resources/dolphin/L1_Painting_128x64/frame_5.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Painting_128x64/frame_6.bm b/assets/resources/dolphin/L1_Painting_128x64/frame_6.bm deleted file mode 100644 index 36f2d084f..000000000 Binary files a/assets/resources/dolphin/L1_Painting_128x64/frame_6.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Painting_128x64/frame_7.bm b/assets/resources/dolphin/L1_Painting_128x64/frame_7.bm deleted file mode 100644 index 9759e787d..000000000 Binary files a/assets/resources/dolphin/L1_Painting_128x64/frame_7.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Painting_128x64/frame_8.bm b/assets/resources/dolphin/L1_Painting_128x64/frame_8.bm deleted file mode 100644 index 244adf310..000000000 Binary files a/assets/resources/dolphin/L1_Painting_128x64/frame_8.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Painting_128x64/frame_9.bm b/assets/resources/dolphin/L1_Painting_128x64/frame_9.bm deleted file mode 100644 index 99ed50717..000000000 Binary files a/assets/resources/dolphin/L1_Painting_128x64/frame_9.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Painting_128x64/meta.txt b/assets/resources/dolphin/L1_Painting_128x64/meta.txt deleted file mode 100644 index e5f5fc0a6..000000000 --- a/assets/resources/dolphin/L1_Painting_128x64/meta.txt +++ /dev/null @@ -1,32 +0,0 @@ -Filetype: Flipper Animation -Version: 1 - -Width: 128 -Height: 64 -Passive frames: 9 -Active frames: 13 -Frames order: 0 1 2 3 4 5 2 3 4 10 6 7 8 7 8 7 8 7 8 9 10 11 -Active cycles: 1 -Frame rate: 2 -Duration: 3600 -Active cooldown: 7 - -Bubble slots: 1 - -Slot: 0 -X: 57 -Y: 24 -Text: No mistakes, -AlignH: Left -AlignV: Center -StartFrame: 11 -EndFrame: 14 - -Slot: 0 -X: 57 -Y: 21 -Text: only happy\n accidents -AlignH: Left -AlignV: Center -StartFrame: 15 -EndFrame: 18 diff --git a/assets/resources/dolphin/L1_Read_books_128x64/frame_0.bm b/assets/resources/dolphin/L1_Read_books_128x64/frame_0.bm deleted file mode 100644 index 1169e42d6..000000000 Binary files a/assets/resources/dolphin/L1_Read_books_128x64/frame_0.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Read_books_128x64/frame_1.bm b/assets/resources/dolphin/L1_Read_books_128x64/frame_1.bm deleted file mode 100644 index 80e2f39bb..000000000 Binary files a/assets/resources/dolphin/L1_Read_books_128x64/frame_1.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Read_books_128x64/frame_2.bm b/assets/resources/dolphin/L1_Read_books_128x64/frame_2.bm deleted file mode 100644 index 959b02556..000000000 Binary files a/assets/resources/dolphin/L1_Read_books_128x64/frame_2.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Read_books_128x64/frame_3.bm b/assets/resources/dolphin/L1_Read_books_128x64/frame_3.bm deleted file mode 100644 index 8c106d906..000000000 Binary files a/assets/resources/dolphin/L1_Read_books_128x64/frame_3.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Read_books_128x64/frame_4.bm b/assets/resources/dolphin/L1_Read_books_128x64/frame_4.bm deleted file mode 100644 index 389d2a8ef..000000000 Binary files a/assets/resources/dolphin/L1_Read_books_128x64/frame_4.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Read_books_128x64/frame_5.bm b/assets/resources/dolphin/L1_Read_books_128x64/frame_5.bm deleted file mode 100644 index 4b65b6d9b..000000000 Binary files a/assets/resources/dolphin/L1_Read_books_128x64/frame_5.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Read_books_128x64/frame_6.bm b/assets/resources/dolphin/L1_Read_books_128x64/frame_6.bm deleted file mode 100644 index 451c80a26..000000000 Binary files a/assets/resources/dolphin/L1_Read_books_128x64/frame_6.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Read_books_128x64/frame_7.bm b/assets/resources/dolphin/L1_Read_books_128x64/frame_7.bm deleted file mode 100644 index 417809078..000000000 Binary files a/assets/resources/dolphin/L1_Read_books_128x64/frame_7.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Read_books_128x64/frame_8.bm b/assets/resources/dolphin/L1_Read_books_128x64/frame_8.bm deleted file mode 100644 index 4370393dc..000000000 Binary files a/assets/resources/dolphin/L1_Read_books_128x64/frame_8.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Read_books_128x64/meta.txt b/assets/resources/dolphin/L1_Read_books_128x64/meta.txt deleted file mode 100644 index 7432507ce..000000000 --- a/assets/resources/dolphin/L1_Read_books_128x64/meta.txt +++ /dev/null @@ -1,23 +0,0 @@ -Filetype: Flipper Animation -Version: 1 - -Width: 128 -Height: 64 -Passive frames: 13 -Active frames: 2 -Frames order: 0 1 0 2 3 3 4 0 1 5 6 1 1 7 8 -Active cycles: 2 -Frame rate: 2 -Duration: 3600 -Active cooldown: 5 - -Bubble slots: 1 - -Slot: 0 -X: 5 -Y: 28 -Text: Predictable twist -AlignH: Right -AlignV: Bottom -StartFrame: 14 -EndFrame: 16 diff --git a/assets/resources/dolphin/L1_Recording_128x51/frame_0.bm b/assets/resources/dolphin/L1_Recording_128x51/frame_0.bm deleted file mode 100644 index a278e3a9d..000000000 Binary files a/assets/resources/dolphin/L1_Recording_128x51/frame_0.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Recording_128x51/frame_1.bm b/assets/resources/dolphin/L1_Recording_128x51/frame_1.bm deleted file mode 100644 index 403a3ccd7..000000000 Binary files a/assets/resources/dolphin/L1_Recording_128x51/frame_1.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Recording_128x51/frame_10.bm b/assets/resources/dolphin/L1_Recording_128x51/frame_10.bm deleted file mode 100644 index 7684384fd..000000000 Binary files a/assets/resources/dolphin/L1_Recording_128x51/frame_10.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Recording_128x51/frame_11.bm b/assets/resources/dolphin/L1_Recording_128x51/frame_11.bm deleted file mode 100644 index 478c1e8b5..000000000 Binary files a/assets/resources/dolphin/L1_Recording_128x51/frame_11.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Recording_128x51/frame_2.bm b/assets/resources/dolphin/L1_Recording_128x51/frame_2.bm deleted file mode 100644 index f5dbbc71c..000000000 Binary files a/assets/resources/dolphin/L1_Recording_128x51/frame_2.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Recording_128x51/frame_3.bm b/assets/resources/dolphin/L1_Recording_128x51/frame_3.bm deleted file mode 100644 index eb4b3644b..000000000 Binary files a/assets/resources/dolphin/L1_Recording_128x51/frame_3.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Recording_128x51/frame_4.bm b/assets/resources/dolphin/L1_Recording_128x51/frame_4.bm deleted file mode 100644 index e0db66ffe..000000000 Binary files a/assets/resources/dolphin/L1_Recording_128x51/frame_4.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Recording_128x51/frame_5.bm b/assets/resources/dolphin/L1_Recording_128x51/frame_5.bm deleted file mode 100644 index 9265ef6d6..000000000 Binary files a/assets/resources/dolphin/L1_Recording_128x51/frame_5.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Recording_128x51/frame_6.bm b/assets/resources/dolphin/L1_Recording_128x51/frame_6.bm deleted file mode 100644 index b2676b7ce..000000000 Binary files a/assets/resources/dolphin/L1_Recording_128x51/frame_6.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Recording_128x51/frame_7.bm b/assets/resources/dolphin/L1_Recording_128x51/frame_7.bm deleted file mode 100644 index 70a1f2d13..000000000 Binary files a/assets/resources/dolphin/L1_Recording_128x51/frame_7.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Recording_128x51/frame_8.bm b/assets/resources/dolphin/L1_Recording_128x51/frame_8.bm deleted file mode 100644 index 05f98d639..000000000 Binary files a/assets/resources/dolphin/L1_Recording_128x51/frame_8.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Recording_128x51/frame_9.bm b/assets/resources/dolphin/L1_Recording_128x51/frame_9.bm deleted file mode 100644 index 65b723203..000000000 Binary files a/assets/resources/dolphin/L1_Recording_128x51/frame_9.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Recording_128x51/meta.txt b/assets/resources/dolphin/L1_Recording_128x51/meta.txt deleted file mode 100644 index de37d5b2e..000000000 --- a/assets/resources/dolphin/L1_Recording_128x51/meta.txt +++ /dev/null @@ -1,14 +0,0 @@ -Filetype: Flipper Animation -Version: 1 - -Width: 128 -Height: 51 -Passive frames: 6 -Active frames: 6 -Frames order: 0 1 2 3 4 5 6 7 8 9 10 11 -Active cycles: 1 -Frame rate: 2 -Duration: 3600 -Active cooldown: 5 - -Bubble slots: 0 diff --git a/assets/resources/dolphin/L1_Sleep_128x64/frame_0.bm b/assets/resources/dolphin/L1_Sleep_128x64/frame_0.bm deleted file mode 100644 index 9560e1f41..000000000 Binary files a/assets/resources/dolphin/L1_Sleep_128x64/frame_0.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Sleep_128x64/frame_1.bm b/assets/resources/dolphin/L1_Sleep_128x64/frame_1.bm deleted file mode 100644 index 238b50a2e..000000000 Binary files a/assets/resources/dolphin/L1_Sleep_128x64/frame_1.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Sleep_128x64/frame_2.bm b/assets/resources/dolphin/L1_Sleep_128x64/frame_2.bm deleted file mode 100644 index b18e615fe..000000000 Binary files a/assets/resources/dolphin/L1_Sleep_128x64/frame_2.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Sleep_128x64/frame_3.bm b/assets/resources/dolphin/L1_Sleep_128x64/frame_3.bm deleted file mode 100644 index 72fedc5e1..000000000 Binary files a/assets/resources/dolphin/L1_Sleep_128x64/frame_3.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Sleep_128x64/meta.txt b/assets/resources/dolphin/L1_Sleep_128x64/meta.txt deleted file mode 100644 index ffd845e8c..000000000 --- a/assets/resources/dolphin/L1_Sleep_128x64/meta.txt +++ /dev/null @@ -1,41 +0,0 @@ -Filetype: Flipper Animation -Version: 1 - -Width: 128 -Height: 64 -Passive frames: 2 -Active frames: 4 -Frames order: 0 1 2 3 2 3 -Active cycles: 2 -Frame rate: 2 -Duration: 3600 -Active cooldown: 5 - -Bubble slots: 2 - -Slot: 0 -X: 53 -Y: 20 -Text: In a lucid dream,\nI could walk... -AlignH: Left -AlignV: Bottom -StartFrame: 3 -EndFrame: 9 - -Slot: 1 -X: 53 -Y: 20 -Text: OH MY GOD! -AlignH: Left -AlignV: Bottom -StartFrame: 3 -EndFrame: 5 - -Slot: 1 -X: 53 -Y: 31 -Text: Just a dream... -AlignH: Left -AlignV: Bottom -StartFrame: 6 -EndFrame: 9 diff --git a/assets/resources/dolphin/L1_Waves_128x50/frame_0.bm b/assets/resources/dolphin/L1_Waves_128x50/frame_0.bm deleted file mode 100644 index aa7454666..000000000 Binary files a/assets/resources/dolphin/L1_Waves_128x50/frame_0.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Waves_128x50/frame_1.bm b/assets/resources/dolphin/L1_Waves_128x50/frame_1.bm deleted file mode 100644 index a23d250b9..000000000 Binary files a/assets/resources/dolphin/L1_Waves_128x50/frame_1.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Waves_128x50/frame_2.bm b/assets/resources/dolphin/L1_Waves_128x50/frame_2.bm deleted file mode 100644 index cd39b17ec..000000000 Binary files a/assets/resources/dolphin/L1_Waves_128x50/frame_2.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Waves_128x50/frame_3.bm b/assets/resources/dolphin/L1_Waves_128x50/frame_3.bm deleted file mode 100644 index 2d5452d7c..000000000 Binary files a/assets/resources/dolphin/L1_Waves_128x50/frame_3.bm and /dev/null differ diff --git a/assets/resources/dolphin/L1_Waves_128x50/meta.txt b/assets/resources/dolphin/L1_Waves_128x50/meta.txt deleted file mode 100644 index 376447af7..000000000 --- a/assets/resources/dolphin/L1_Waves_128x50/meta.txt +++ /dev/null @@ -1,50 +0,0 @@ -Filetype: Flipper Animation -Version: 1 - -Width: 128 -Height: 50 -Passive frames: 2 -Active frames: 4 -Frames order: 0 1 2 3 2 3 -Active cycles: 2 -Frame rate: 2 -Duration: 3600 -Active cooldown: 5 - -Bubble slots: 3 - -Slot: 0 -X: 1 -Y: 17 -Text: I am happy,\nmy friend! -AlignH: Right -AlignV: Bottom -StartFrame: 3 -EndFrame: 9 - -Slot: 1 -X: 1 -Y: 17 -Text: So long and\nthanks for\nall the fish! -AlignH: Right -AlignV: Center -StartFrame: 3 -EndFrame: 9 - -Slot: 2 -X: 1 -Y: 25 -Text: I wish I could -AlignH: Right -AlignV: Bottom -StartFrame: 3 -EndFrame: 5 - -Slot: 2 -X: 1 -Y: 25 -Text: swim all day -AlignH: Right -AlignV: Bottom -StartFrame: 6 -EndFrame: 9 diff --git a/assets/resources/dolphin/L2_Furippa2_128x64/frame_0.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_0.bm deleted file mode 100644 index 7e83e14a5..000000000 Binary files a/assets/resources/dolphin/L2_Furippa2_128x64/frame_0.bm and /dev/null differ diff --git a/assets/resources/dolphin/L2_Furippa2_128x64/frame_1.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_1.bm deleted file mode 100644 index f149f01e9..000000000 Binary files a/assets/resources/dolphin/L2_Furippa2_128x64/frame_1.bm and /dev/null differ diff --git a/assets/resources/dolphin/L2_Furippa2_128x64/frame_10.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_10.bm deleted file mode 100644 index c5312e5e5..000000000 Binary files a/assets/resources/dolphin/L2_Furippa2_128x64/frame_10.bm and /dev/null differ diff --git a/assets/resources/dolphin/L2_Furippa2_128x64/frame_11.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_11.bm deleted file mode 100644 index c91ed2fd2..000000000 Binary files a/assets/resources/dolphin/L2_Furippa2_128x64/frame_11.bm and /dev/null differ diff --git a/assets/resources/dolphin/L2_Furippa2_128x64/frame_12.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_12.bm deleted file mode 100644 index 392905a55..000000000 Binary files a/assets/resources/dolphin/L2_Furippa2_128x64/frame_12.bm and /dev/null differ diff --git a/assets/resources/dolphin/L2_Furippa2_128x64/frame_13.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_13.bm deleted file mode 100644 index aa5353e98..000000000 Binary files a/assets/resources/dolphin/L2_Furippa2_128x64/frame_13.bm and /dev/null differ diff --git a/assets/resources/dolphin/L2_Furippa2_128x64/frame_14.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_14.bm deleted file mode 100644 index 837c6c71d..000000000 Binary files a/assets/resources/dolphin/L2_Furippa2_128x64/frame_14.bm and /dev/null differ diff --git a/assets/resources/dolphin/L2_Furippa2_128x64/frame_15.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_15.bm deleted file mode 100644 index 0000a8863..000000000 Binary files a/assets/resources/dolphin/L2_Furippa2_128x64/frame_15.bm and /dev/null differ diff --git a/assets/resources/dolphin/L2_Furippa2_128x64/frame_16.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_16.bm deleted file mode 100644 index 46a96ff46..000000000 Binary files a/assets/resources/dolphin/L2_Furippa2_128x64/frame_16.bm and /dev/null differ diff --git a/assets/resources/dolphin/L2_Furippa2_128x64/frame_17.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_17.bm deleted file mode 100644 index edccc7396..000000000 Binary files a/assets/resources/dolphin/L2_Furippa2_128x64/frame_17.bm and /dev/null differ diff --git a/assets/resources/dolphin/L2_Furippa2_128x64/frame_18.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_18.bm deleted file mode 100644 index 84f60c81e..000000000 Binary files a/assets/resources/dolphin/L2_Furippa2_128x64/frame_18.bm and /dev/null differ diff --git a/assets/resources/dolphin/L2_Furippa2_128x64/frame_2.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_2.bm deleted file mode 100644 index ade67d101..000000000 Binary files a/assets/resources/dolphin/L2_Furippa2_128x64/frame_2.bm and /dev/null differ diff --git a/assets/resources/dolphin/L2_Furippa2_128x64/frame_3.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_3.bm deleted file mode 100644 index d05e8ae2b..000000000 Binary files a/assets/resources/dolphin/L2_Furippa2_128x64/frame_3.bm and /dev/null differ diff --git a/assets/resources/dolphin/L2_Furippa2_128x64/frame_4.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_4.bm deleted file mode 100644 index 5aef12762..000000000 Binary files a/assets/resources/dolphin/L2_Furippa2_128x64/frame_4.bm and /dev/null differ diff --git a/assets/resources/dolphin/L2_Furippa2_128x64/frame_5.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_5.bm deleted file mode 100644 index 3be1790d7..000000000 Binary files a/assets/resources/dolphin/L2_Furippa2_128x64/frame_5.bm and /dev/null differ diff --git a/assets/resources/dolphin/L2_Furippa2_128x64/frame_6.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_6.bm deleted file mode 100644 index c457e7877..000000000 Binary files a/assets/resources/dolphin/L2_Furippa2_128x64/frame_6.bm and /dev/null differ diff --git a/assets/resources/dolphin/L2_Furippa2_128x64/frame_7.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_7.bm deleted file mode 100644 index 7e83e14a5..000000000 Binary files a/assets/resources/dolphin/L2_Furippa2_128x64/frame_7.bm and /dev/null differ diff --git a/assets/resources/dolphin/L2_Furippa2_128x64/frame_8.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_8.bm deleted file mode 100644 index b7b871d13..000000000 Binary files a/assets/resources/dolphin/L2_Furippa2_128x64/frame_8.bm and /dev/null differ diff --git a/assets/resources/dolphin/L2_Furippa2_128x64/frame_9.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_9.bm deleted file mode 100644 index 269e5b1d8..000000000 Binary files a/assets/resources/dolphin/L2_Furippa2_128x64/frame_9.bm and /dev/null differ diff --git a/assets/resources/dolphin/L2_Furippa2_128x64/meta.txt b/assets/resources/dolphin/L2_Furippa2_128x64/meta.txt deleted file mode 100644 index c21027e49..000000000 --- a/assets/resources/dolphin/L2_Furippa2_128x64/meta.txt +++ /dev/null @@ -1,14 +0,0 @@ -Filetype: Flipper Animation -Version: 1 - -Width: 128 -Height: 64 -Passive frames: 8 -Active frames: 11 -Frames order: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 -Active cycles: 1 -Frame rate: 2 -Duration: 3600 -Active cooldown: 7 - -Bubble slots: 0 diff --git a/assets/resources/dolphin/L2_Hacking_pc_128x64/frame_0.bm b/assets/resources/dolphin/L2_Hacking_pc_128x64/frame_0.bm deleted file mode 100644 index 3ff70a916..000000000 Binary files a/assets/resources/dolphin/L2_Hacking_pc_128x64/frame_0.bm and /dev/null differ diff --git a/assets/resources/dolphin/L2_Hacking_pc_128x64/frame_1.bm b/assets/resources/dolphin/L2_Hacking_pc_128x64/frame_1.bm deleted file mode 100644 index ed11583f8..000000000 Binary files a/assets/resources/dolphin/L2_Hacking_pc_128x64/frame_1.bm and /dev/null differ diff --git a/assets/resources/dolphin/L2_Hacking_pc_128x64/frame_2.bm b/assets/resources/dolphin/L2_Hacking_pc_128x64/frame_2.bm deleted file mode 100644 index 41850505b..000000000 Binary files a/assets/resources/dolphin/L2_Hacking_pc_128x64/frame_2.bm and /dev/null differ diff --git a/assets/resources/dolphin/L2_Hacking_pc_128x64/frame_3.bm b/assets/resources/dolphin/L2_Hacking_pc_128x64/frame_3.bm deleted file mode 100644 index d4b47960a..000000000 Binary files a/assets/resources/dolphin/L2_Hacking_pc_128x64/frame_3.bm and /dev/null differ diff --git a/assets/resources/dolphin/L2_Hacking_pc_128x64/frame_4.bm b/assets/resources/dolphin/L2_Hacking_pc_128x64/frame_4.bm deleted file mode 100644 index ee3a5f188..000000000 Binary files a/assets/resources/dolphin/L2_Hacking_pc_128x64/frame_4.bm and /dev/null differ diff --git a/assets/resources/dolphin/L2_Hacking_pc_128x64/meta.txt b/assets/resources/dolphin/L2_Hacking_pc_128x64/meta.txt deleted file mode 100644 index 8ad8d42a3..000000000 --- a/assets/resources/dolphin/L2_Hacking_pc_128x64/meta.txt +++ /dev/null @@ -1,32 +0,0 @@ -Filetype: Flipper Animation -Version: 1 - -Width: 128 -Height: 64 -Passive frames: 3 -Active frames: 2 -Frames order: 0 1 2 3 4 -Active cycles: 4 -Frame rate: 2 -Duration: 3600 -Active cooldown: 7 - -Bubble slots: 1 - -Slot: 0 -X: 22 -Y: 25 -Text: Mess with\nthe best, -AlignH: Right -AlignV: Center -StartFrame: 4 -EndFrame: 7 - -Slot: 0 -X: 31 -Y: 25 -Text: die like\nthe rest. -AlignH: Right -AlignV: Center -StartFrame: 8 -EndFrame: 10 diff --git a/assets/resources/dolphin/L2_Soldering_128x64/frame_0.bm b/assets/resources/dolphin/L2_Soldering_128x64/frame_0.bm deleted file mode 100644 index 3fc364406..000000000 Binary files a/assets/resources/dolphin/L2_Soldering_128x64/frame_0.bm and /dev/null differ diff --git a/assets/resources/dolphin/L2_Soldering_128x64/frame_1.bm b/assets/resources/dolphin/L2_Soldering_128x64/frame_1.bm deleted file mode 100644 index 60a2e700a..000000000 Binary files a/assets/resources/dolphin/L2_Soldering_128x64/frame_1.bm and /dev/null differ diff --git a/assets/resources/dolphin/L2_Soldering_128x64/frame_10.bm b/assets/resources/dolphin/L2_Soldering_128x64/frame_10.bm deleted file mode 100644 index f80819358..000000000 Binary files a/assets/resources/dolphin/L2_Soldering_128x64/frame_10.bm and /dev/null differ diff --git a/assets/resources/dolphin/L2_Soldering_128x64/frame_2.bm b/assets/resources/dolphin/L2_Soldering_128x64/frame_2.bm deleted file mode 100644 index 1d981e7d5..000000000 Binary files a/assets/resources/dolphin/L2_Soldering_128x64/frame_2.bm and /dev/null differ diff --git a/assets/resources/dolphin/L2_Soldering_128x64/frame_3.bm b/assets/resources/dolphin/L2_Soldering_128x64/frame_3.bm deleted file mode 100644 index 48d0aa85d..000000000 Binary files a/assets/resources/dolphin/L2_Soldering_128x64/frame_3.bm and /dev/null differ diff --git a/assets/resources/dolphin/L2_Soldering_128x64/frame_4.bm b/assets/resources/dolphin/L2_Soldering_128x64/frame_4.bm deleted file mode 100644 index a961f4c0a..000000000 Binary files a/assets/resources/dolphin/L2_Soldering_128x64/frame_4.bm and /dev/null differ diff --git a/assets/resources/dolphin/L2_Soldering_128x64/frame_5.bm b/assets/resources/dolphin/L2_Soldering_128x64/frame_5.bm deleted file mode 100644 index 81b569339..000000000 Binary files a/assets/resources/dolphin/L2_Soldering_128x64/frame_5.bm and /dev/null differ diff --git a/assets/resources/dolphin/L2_Soldering_128x64/frame_6.bm b/assets/resources/dolphin/L2_Soldering_128x64/frame_6.bm deleted file mode 100644 index 2f030833a..000000000 Binary files a/assets/resources/dolphin/L2_Soldering_128x64/frame_6.bm and /dev/null differ diff --git a/assets/resources/dolphin/L2_Soldering_128x64/frame_7.bm b/assets/resources/dolphin/L2_Soldering_128x64/frame_7.bm deleted file mode 100644 index 4519819ea..000000000 Binary files a/assets/resources/dolphin/L2_Soldering_128x64/frame_7.bm and /dev/null differ diff --git a/assets/resources/dolphin/L2_Soldering_128x64/frame_8.bm b/assets/resources/dolphin/L2_Soldering_128x64/frame_8.bm deleted file mode 100644 index 4bb3b7983..000000000 Binary files a/assets/resources/dolphin/L2_Soldering_128x64/frame_8.bm and /dev/null differ diff --git a/assets/resources/dolphin/L2_Soldering_128x64/frame_9.bm b/assets/resources/dolphin/L2_Soldering_128x64/frame_9.bm deleted file mode 100644 index 1339c607e..000000000 Binary files a/assets/resources/dolphin/L2_Soldering_128x64/frame_9.bm and /dev/null differ diff --git a/assets/resources/dolphin/L2_Soldering_128x64/meta.txt b/assets/resources/dolphin/L2_Soldering_128x64/meta.txt deleted file mode 100644 index b705bf623..000000000 --- a/assets/resources/dolphin/L2_Soldering_128x64/meta.txt +++ /dev/null @@ -1,23 +0,0 @@ -Filetype: Flipper Animation -Version: 1 - -Width: 128 -Height: 64 -Passive frames: 9 -Active frames: 5 -Frames order: 0 1 2 3 4 5 6 7 8 9 10 9 10 9 -Active cycles: 1 -Frame rate: 2 -Duration: 3600 -Active cooldown: 7 - -Bubble slots: 1 - -Slot: 0 -X: 71 -Y: 28 -Text: I am busy rn -AlignH: Left -AlignV: Center -StartFrame: 10 -EndFrame: 13 diff --git a/assets/resources/dolphin/L3_Furippa3_128x64/frame_0.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_0.bm deleted file mode 100644 index 07a63d642..000000000 Binary files a/assets/resources/dolphin/L3_Furippa3_128x64/frame_0.bm and /dev/null differ diff --git a/assets/resources/dolphin/L3_Furippa3_128x64/frame_1.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_1.bm deleted file mode 100644 index 6d118f28a..000000000 Binary files a/assets/resources/dolphin/L3_Furippa3_128x64/frame_1.bm and /dev/null differ diff --git a/assets/resources/dolphin/L3_Furippa3_128x64/frame_10.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_10.bm deleted file mode 100644 index 8010501d0..000000000 Binary files a/assets/resources/dolphin/L3_Furippa3_128x64/frame_10.bm and /dev/null differ diff --git a/assets/resources/dolphin/L3_Furippa3_128x64/frame_11.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_11.bm deleted file mode 100644 index 4d650bff0..000000000 Binary files a/assets/resources/dolphin/L3_Furippa3_128x64/frame_11.bm and /dev/null differ diff --git a/assets/resources/dolphin/L3_Furippa3_128x64/frame_12.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_12.bm deleted file mode 100644 index 392905a55..000000000 Binary files a/assets/resources/dolphin/L3_Furippa3_128x64/frame_12.bm and /dev/null differ diff --git a/assets/resources/dolphin/L3_Furippa3_128x64/frame_13.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_13.bm deleted file mode 100644 index aa5353e98..000000000 Binary files a/assets/resources/dolphin/L3_Furippa3_128x64/frame_13.bm and /dev/null differ diff --git a/assets/resources/dolphin/L3_Furippa3_128x64/frame_14.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_14.bm deleted file mode 100644 index 837c6c71d..000000000 Binary files a/assets/resources/dolphin/L3_Furippa3_128x64/frame_14.bm and /dev/null differ diff --git a/assets/resources/dolphin/L3_Furippa3_128x64/frame_15.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_15.bm deleted file mode 100644 index 9ff56a5b6..000000000 Binary files a/assets/resources/dolphin/L3_Furippa3_128x64/frame_15.bm and /dev/null differ diff --git a/assets/resources/dolphin/L3_Furippa3_128x64/frame_16.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_16.bm deleted file mode 100644 index 34cc0b512..000000000 Binary files a/assets/resources/dolphin/L3_Furippa3_128x64/frame_16.bm and /dev/null differ diff --git a/assets/resources/dolphin/L3_Furippa3_128x64/frame_17.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_17.bm deleted file mode 100644 index 80cb06fd3..000000000 Binary files a/assets/resources/dolphin/L3_Furippa3_128x64/frame_17.bm and /dev/null differ diff --git a/assets/resources/dolphin/L3_Furippa3_128x64/frame_18.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_18.bm deleted file mode 100644 index 719a80f0e..000000000 Binary files a/assets/resources/dolphin/L3_Furippa3_128x64/frame_18.bm and /dev/null differ diff --git a/assets/resources/dolphin/L3_Furippa3_128x64/frame_2.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_2.bm deleted file mode 100644 index c01485850..000000000 Binary files a/assets/resources/dolphin/L3_Furippa3_128x64/frame_2.bm and /dev/null differ diff --git a/assets/resources/dolphin/L3_Furippa3_128x64/frame_3.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_3.bm deleted file mode 100644 index f70c33cad..000000000 Binary files a/assets/resources/dolphin/L3_Furippa3_128x64/frame_3.bm and /dev/null differ diff --git a/assets/resources/dolphin/L3_Furippa3_128x64/frame_4.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_4.bm deleted file mode 100644 index 3fee74b77..000000000 Binary files a/assets/resources/dolphin/L3_Furippa3_128x64/frame_4.bm and /dev/null differ diff --git a/assets/resources/dolphin/L3_Furippa3_128x64/frame_5.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_5.bm deleted file mode 100644 index e363bf7d5..000000000 Binary files a/assets/resources/dolphin/L3_Furippa3_128x64/frame_5.bm and /dev/null differ diff --git a/assets/resources/dolphin/L3_Furippa3_128x64/frame_6.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_6.bm deleted file mode 100644 index f46aabadf..000000000 Binary files a/assets/resources/dolphin/L3_Furippa3_128x64/frame_6.bm and /dev/null differ diff --git a/assets/resources/dolphin/L3_Furippa3_128x64/frame_7.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_7.bm deleted file mode 100644 index 07a63d642..000000000 Binary files a/assets/resources/dolphin/L3_Furippa3_128x64/frame_7.bm and /dev/null differ diff --git a/assets/resources/dolphin/L3_Furippa3_128x64/frame_8.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_8.bm deleted file mode 100644 index f8bae3a62..000000000 Binary files a/assets/resources/dolphin/L3_Furippa3_128x64/frame_8.bm and /dev/null differ diff --git a/assets/resources/dolphin/L3_Furippa3_128x64/frame_9.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_9.bm deleted file mode 100644 index 6b5810dc9..000000000 Binary files a/assets/resources/dolphin/L3_Furippa3_128x64/frame_9.bm and /dev/null differ diff --git a/assets/resources/dolphin/L3_Furippa3_128x64/meta.txt b/assets/resources/dolphin/L3_Furippa3_128x64/meta.txt deleted file mode 100644 index c21027e49..000000000 --- a/assets/resources/dolphin/L3_Furippa3_128x64/meta.txt +++ /dev/null @@ -1,14 +0,0 @@ -Filetype: Flipper Animation -Version: 1 - -Width: 128 -Height: 64 -Passive frames: 8 -Active frames: 11 -Frames order: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 -Active cycles: 1 -Frame rate: 2 -Duration: 3600 -Active cooldown: 7 - -Bubble slots: 0 diff --git a/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_0.bm b/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_0.bm deleted file mode 100644 index cf2120ff4..000000000 Binary files a/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_0.bm and /dev/null differ diff --git a/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_1.bm b/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_1.bm deleted file mode 100644 index 24a492132..000000000 Binary files a/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_1.bm and /dev/null differ diff --git a/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_10.bm b/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_10.bm deleted file mode 100644 index 1354c78f2..000000000 Binary files a/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_10.bm and /dev/null differ diff --git a/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_11.bm b/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_11.bm deleted file mode 100644 index c15289b5e..000000000 Binary files a/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_11.bm and /dev/null differ diff --git a/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_12.bm b/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_12.bm deleted file mode 100644 index ac9f08334..000000000 Binary files a/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_12.bm and /dev/null differ diff --git a/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_13.bm b/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_13.bm deleted file mode 100644 index 9ad7b9cf3..000000000 Binary files a/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_13.bm and /dev/null differ diff --git a/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_2.bm b/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_2.bm deleted file mode 100644 index 30c4bedcd..000000000 Binary files a/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_2.bm and /dev/null differ diff --git a/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_3.bm b/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_3.bm deleted file mode 100644 index dc0fb9b79..000000000 Binary files a/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_3.bm and /dev/null differ diff --git a/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_4.bm b/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_4.bm deleted file mode 100644 index 025477a7a..000000000 Binary files a/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_4.bm and /dev/null differ diff --git a/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_5.bm b/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_5.bm deleted file mode 100644 index 89a4cd6ac..000000000 Binary files a/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_5.bm and /dev/null differ diff --git a/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_6.bm b/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_6.bm deleted file mode 100644 index c93ff6acd..000000000 Binary files a/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_6.bm and /dev/null differ diff --git a/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_7.bm b/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_7.bm deleted file mode 100644 index fb6d9bd29..000000000 Binary files a/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_7.bm and /dev/null differ diff --git a/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_8.bm b/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_8.bm deleted file mode 100644 index a0377f635..000000000 Binary files a/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_8.bm and /dev/null differ diff --git a/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_9.bm b/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_9.bm deleted file mode 100644 index 06f66ab3a..000000000 Binary files a/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_9.bm and /dev/null differ diff --git a/assets/resources/dolphin/L3_Hijack_radio_128x64/meta.txt b/assets/resources/dolphin/L3_Hijack_radio_128x64/meta.txt deleted file mode 100644 index 1d415b4b8..000000000 --- a/assets/resources/dolphin/L3_Hijack_radio_128x64/meta.txt +++ /dev/null @@ -1,14 +0,0 @@ -Filetype: Flipper Animation -Version: 1 - -Width: 128 -Height: 64 -Passive frames: 8 -Active frames: 8 -Frames order: 0 1 2 3 4 5 4 6 7 8 9 10 11 12 11 13 -Active cycles: 1 -Frame rate: 2 -Duration: 3600 -Active cooldown: 7 - -Bubble slots: 0 diff --git a/assets/resources/dolphin/L3_Lab_research_128x54/frame_0.bm b/assets/resources/dolphin/L3_Lab_research_128x54/frame_0.bm deleted file mode 100644 index db283e81f..000000000 Binary files a/assets/resources/dolphin/L3_Lab_research_128x54/frame_0.bm and /dev/null differ diff --git a/assets/resources/dolphin/L3_Lab_research_128x54/frame_1.bm b/assets/resources/dolphin/L3_Lab_research_128x54/frame_1.bm deleted file mode 100644 index c60074370..000000000 Binary files a/assets/resources/dolphin/L3_Lab_research_128x54/frame_1.bm and /dev/null differ diff --git a/assets/resources/dolphin/L3_Lab_research_128x54/frame_10.bm b/assets/resources/dolphin/L3_Lab_research_128x54/frame_10.bm deleted file mode 100644 index 694302a9d..000000000 Binary files a/assets/resources/dolphin/L3_Lab_research_128x54/frame_10.bm and /dev/null differ diff --git a/assets/resources/dolphin/L3_Lab_research_128x54/frame_11.bm b/assets/resources/dolphin/L3_Lab_research_128x54/frame_11.bm deleted file mode 100644 index 246b955cf..000000000 Binary files a/assets/resources/dolphin/L3_Lab_research_128x54/frame_11.bm and /dev/null differ diff --git a/assets/resources/dolphin/L3_Lab_research_128x54/frame_12.bm b/assets/resources/dolphin/L3_Lab_research_128x54/frame_12.bm deleted file mode 100644 index b6fb1130b..000000000 Binary files a/assets/resources/dolphin/L3_Lab_research_128x54/frame_12.bm and /dev/null differ diff --git a/assets/resources/dolphin/L3_Lab_research_128x54/frame_13.bm b/assets/resources/dolphin/L3_Lab_research_128x54/frame_13.bm deleted file mode 100644 index 561335413..000000000 Binary files a/assets/resources/dolphin/L3_Lab_research_128x54/frame_13.bm and /dev/null differ diff --git a/assets/resources/dolphin/L3_Lab_research_128x54/frame_2.bm b/assets/resources/dolphin/L3_Lab_research_128x54/frame_2.bm deleted file mode 100644 index 1025137e4..000000000 Binary files a/assets/resources/dolphin/L3_Lab_research_128x54/frame_2.bm and /dev/null differ diff --git a/assets/resources/dolphin/L3_Lab_research_128x54/frame_3.bm b/assets/resources/dolphin/L3_Lab_research_128x54/frame_3.bm deleted file mode 100644 index e623a1c0f..000000000 Binary files a/assets/resources/dolphin/L3_Lab_research_128x54/frame_3.bm and /dev/null differ diff --git a/assets/resources/dolphin/L3_Lab_research_128x54/frame_4.bm b/assets/resources/dolphin/L3_Lab_research_128x54/frame_4.bm deleted file mode 100644 index 654a68e87..000000000 Binary files a/assets/resources/dolphin/L3_Lab_research_128x54/frame_4.bm and /dev/null differ diff --git a/assets/resources/dolphin/L3_Lab_research_128x54/frame_5.bm b/assets/resources/dolphin/L3_Lab_research_128x54/frame_5.bm deleted file mode 100644 index 14eae4c1c..000000000 Binary files a/assets/resources/dolphin/L3_Lab_research_128x54/frame_5.bm and /dev/null differ diff --git a/assets/resources/dolphin/L3_Lab_research_128x54/frame_6.bm b/assets/resources/dolphin/L3_Lab_research_128x54/frame_6.bm deleted file mode 100644 index 561335413..000000000 Binary files a/assets/resources/dolphin/L3_Lab_research_128x54/frame_6.bm and /dev/null differ diff --git a/assets/resources/dolphin/L3_Lab_research_128x54/frame_7.bm b/assets/resources/dolphin/L3_Lab_research_128x54/frame_7.bm deleted file mode 100644 index c9b99a014..000000000 Binary files a/assets/resources/dolphin/L3_Lab_research_128x54/frame_7.bm and /dev/null differ diff --git a/assets/resources/dolphin/L3_Lab_research_128x54/frame_8.bm b/assets/resources/dolphin/L3_Lab_research_128x54/frame_8.bm deleted file mode 100644 index 812db0d46..000000000 Binary files a/assets/resources/dolphin/L3_Lab_research_128x54/frame_8.bm and /dev/null differ diff --git a/assets/resources/dolphin/L3_Lab_research_128x54/frame_9.bm b/assets/resources/dolphin/L3_Lab_research_128x54/frame_9.bm deleted file mode 100644 index 0cad9cc26..000000000 Binary files a/assets/resources/dolphin/L3_Lab_research_128x54/frame_9.bm and /dev/null differ diff --git a/assets/resources/dolphin/L3_Lab_research_128x54/meta.txt b/assets/resources/dolphin/L3_Lab_research_128x54/meta.txt deleted file mode 100644 index e83a8b436..000000000 --- a/assets/resources/dolphin/L3_Lab_research_128x54/meta.txt +++ /dev/null @@ -1,59 +0,0 @@ -Filetype: Flipper Animation -Version: 1 - -Width: 128 -Height: 54 -Passive frames: 6 -Active frames: 8 -Frames order: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 -Active cycles: 1 -Frame rate: 2 -Duration: 3600 -Active cooldown: 7 - -Bubble slots: 1 - -Slot: 0 -X: 71 -Y: 23 -Text: 7em!g!7j!\nVyP5?T- -AlignH: Left -AlignV: Center -StartFrame: 8 -EndFrame: 8 - -Slot: 0 -X: 71 -Y: 23 -Text: aUqF7sz!\n%9.mP5H -AlignH: Left -AlignV: Center -StartFrame: 9 -EndFrame: 9 - -Slot: 0 -X: 71 -Y: 23 -Text: 2%Kx2mV\nL8EyA84 -AlignH: Left -AlignV: Center -StartFrame: 10 -EndFrame: 10 - -Slot: 0 -X: 71 -Y: 23 -Text: U7%cRXr\nvbBa!_W1 -AlignH: Left -AlignV: Center -StartFrame: 11 -EndFrame: 11 - -Slot: 0 -X: 71 -Y: 23 -Text: 5rm_[K%\n!!(U9d$tE -AlignH: Left -AlignV: Center -StartFrame: 12 -EndFrame: 12 diff --git a/assets/resources/dolphin/manifest.txt b/assets/resources/dolphin/manifest.txt deleted file mode 100644 index 6bf6957c3..000000000 --- a/assets/resources/dolphin/manifest.txt +++ /dev/null @@ -1,121 +0,0 @@ -Filetype: Flipper Animation Manifest -Version: 1 - -Name: L1_Waves_128x50 -Min butthurt: 0 -Max butthurt: 5 -Min level: 1 -Max level: 3 -Weight: 3 - -Name: L1_Laptop_128x51 -Min butthurt: 0 -Max butthurt: 7 -Min level: 1 -Max level: 1 -Weight: 3 - -Name: L1_Sleep_128x64 -Min butthurt: 0 -Max butthurt: 10 -Min level: 1 -Max level: 3 -Weight: 3 - -Name: L1_Recording_128x51 -Min butthurt: 0 -Max butthurt: 8 -Min level: 1 -Max level: 1 -Weight: 3 - -Name: L1_Furippa1_128x64 -Min butthurt: 0 -Max butthurt: 6 -Min level: 1 -Max level: 1 -Weight: 3 - -Name: L2_Furippa2_128x64 -Min butthurt: 0 -Max butthurt: 6 -Min level: 2 -Max level: 2 -Weight: 3 - -Name: L3_Furippa3_128x64 -Min butthurt: 0 -Max butthurt: 6 -Min level: 3 -Max level: 3 -Weight: 3 - -Name: L1_Read_books_128x64 -Min butthurt: 0 -Max butthurt: 8 -Min level: 1 -Max level: 1 -Weight: 3 - -Name: L2_Hacking_pc_128x64 -Min butthurt: 0 -Max butthurt: 8 -Min level: 2 -Max level: 2 -Weight: 3 - -Name: L1_Cry_128x64 -Min butthurt: 8 -Max butthurt: 13 -Min level: 1 -Max level: 3 -Weight: 3 - -Name: L1_Boxing_128x64 -Min butthurt: 10 -Max butthurt: 13 -Min level: 1 -Max level: 3 -Weight: 3 - -Name: L1_Mad_fist_128x64 -Min butthurt: 9 -Max butthurt: 13 -Min level: 1 -Max level: 3 -Weight: 3 - -Name: L1_Painting_128x64 -Min butthurt: 0 -Max butthurt: 7 -Min level: 1 -Max level: 3 -Weight: 6 - -Name: L3_Hijack_radio_128x64 -Min butthurt: 0 -Max butthurt: 8 -Min level: 3 -Max level: 3 -Weight: 3 - -Name: L3_Lab_research_128x54 -Min butthurt: 0 -Max butthurt: 10 -Min level: 3 -Max level: 3 -Weight: 3 - -Name: L2_Soldering_128x64 -Min butthurt: 0 -Max butthurt: 10 -Min level: 2 -Max level: 2 -Weight: 3 - -Name: L1_Leaving_sad_128x64 -Min butthurt: 14 -Max butthurt: 14 -Min level: 1 -Max level: 3 -Weight: 3 diff --git a/assets/resources/infrared/assets/ac.ir b/assets/resources/infrared/assets/ac.ir index 97c384591..7ef953059 100644 --- a/assets/resources/infrared/assets/ac.ir +++ b/assets/resources/infrared/assets/ac.ir @@ -111,4 +111,41 @@ type: raw frequency: 38000 duty_cycle: 0.330000 data: 9106 4398 731 499 706 500 705 502 702 504 701 505 701 505 701 1606 701 505 701 1607 701 505 701 506 700 1607 700 506 700 506 700 505 700 505 701 506 700 506 700 506 699 506 700 506 700 1607 700 506 700 506 700 506 700 505 701 506 700 506 700 1608 699 506 700 1608 699 506 700 506 700 1608 700 506 700 19941 701 1606 700 505 701 505 701 506 700 505 700 506 700 506 700 506 700 506 700 506 700 506 700 506 700 506 701 506 700 506 700 506 700 506 700 506 700 506 700 506 700 506 700 506 700 506 700 506 700 506 700 506 699 506 700 506 700 1608 700 1607 700 506 700 506 700 +# +# Model: Saturn CS-TL09CHR +name: Dh +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3014 1708 488 1059 464 1085 461 362 461 363 460 387 436 1085 462 362 461 402 436 1084 463 1083 463 364 459 1083 463 363 460 386 437 1082 518 1044 464 386 437 1108 439 1108 438 386 464 360 463 1082 464 360 490 352 459 1084 462 362 460 363 460 363 460 364 459 364 459 364 459 380 459 364 459 364 459 364 460 364 459 364 459 364 459 364 459 380 459 364 459 365 458 1088 459 364 459 365 458 1088 458 365 458 380 459 365 458 1088 459 365 458 364 459 365 459 365 458 365 458 380 458 1088 459 1088 459 1088 458 365 458 365 458 365 458 365 458 381 458 365 458 365 458 365 458 365 458 365 459 365 458 365 458 381 458 366 457 366 457 366 457 366 457 366 458 365 458 366 458 381 457 366 457 366 457 366 457 366 457 366 457 366 457 366 458 382 457 366 457 366 457 367 456 367 457 367 456 367 456 390 433 406 433 367 456 367 456 390 433 391 433 390 433 390 433 390 433 406 433 391 432 1114 432 391 432 391 432 391 432 391 432 1114 433 396 433 +# +name: Cool_hi +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3011 1710 462 1084 462 1085 486 356 467 356 444 364 484 1060 462 364 483 357 458 1085 461 1085 461 388 435 1085 461 388 435 388 435 1084 462 1099 463 387 436 1084 462 1085 461 388 461 362 461 1084 462 362 461 378 460 1087 459 365 458 365 458 366 457 366 457 366 457 366 457 382 457 366 457 366 457 366 457 367 456 367 456 367 456 367 456 382 457 367 456 367 456 1090 457 367 456 367 456 1090 457 367 456 382 457 1090 456 1090 457 367 456 367 456 367 456 367 456 367 456 382 457 1091 456 1091 456 1091 456 1090 456 367 456 367 456 367 457 382 457 367 456 367 456 367 456 367 456 368 456 367 456 368 455 383 456 367 456 367 456 368 455 368 455 368 455 368 456 368 455 383 456 368 455 368 455 368 455 368 455 368 455 368 455 368 455 383 456 368 455 368 455 368 455 368 455 368 455 368 455 368 455 384 455 368 455 368 455 368 455 368 455 368 455 368 455 368 455 383 456 1091 456 1091 456 368 456 1091 455 368 455 368 455 1091 456 373 456 +# +name: Cool_lo +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3012 1709 462 1083 463 1084 463 361 462 362 484 355 469 1059 463 387 436 402 437 1083 464 1083 464 362 462 1080 520 354 469 354 469 1026 521 1068 518 354 390 1108 439 1108 438 386 463 360 464 1081 465 359 464 375 463 1083 463 361 462 362 461 363 460 363 460 364 459 364 459 380 459 364 459 364 459 365 458 365 458 365 458 365 458 365 458 380 459 365 458 365 458 1089 458 365 459 365 458 1089 458 366 457 382 456 1090 457 1113 433 390 433 390 433 390 433 390 433 390 433 405 434 390 433 390 433 390 433 1113 434 390 433 390 433 390 433 405 434 390 433 390 433 390 434 390 433 390 433 390 433 390 433 405 434 390 433 390 433 390 433 390 433 390 433 390 433 390 434 405 433 390 433 390 433 390 433 390 433 390 433 390 433 390 433 406 433 390 433 390 433 390 433 390 433 390 433 391 432 391 432 406 433 390 433 391 432 391 432 391 433 390 433 390 433 391 432 406 433 391 432 391 432 1114 433 391 432 391 432 391 432 1114 433 396 433 +# +name: Heat_hi +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3011 1712 461 1087 459 1088 459 364 459 389 434 366 458 1086 461 388 435 404 435 1086 460 1085 461 388 435 1085 461 365 458 388 435 1084 462 1098 464 387 436 1084 462 1084 462 388 461 362 461 1084 462 362 461 378 460 1086 460 364 459 365 458 365 458 365 458 366 457 365 458 381 458 366 457 366 458 366 457 366 457 366 457 366 457 365 458 381 458 366 458 366 457 1089 458 366 457 366 457 1089 458 366 457 381 458 1089 458 366 457 366 457 366 457 366 458 366 457 366 457 381 458 366 457 366 457 366 457 366 457 366 457 366 457 366 457 381 458 366 457 366 457 366 458 366 457 366 457 366 457 366 457 382 457 366 457 366 457 366 457 366 457 366 457 366 457 366 457 382 457 366 457 366 457 367 456 367 456 367 457 366 457 366 457 382 457 367 457 366 457 367 457 366 457 367 457 366 457 366 457 382 457 367 456 367 456 367 456 367 456 367 456 367 456 367 456 382 457 367 456 1090 457 367 456 1091 456 1090 457 1090 456 367 456 373 456 +# +name: Heat_lo +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3045 1677 493 1023 524 1024 522 354 469 354 469 354 469 1026 576 353 470 350 487 1001 492 1054 492 354 469 1054 492 355 468 354 469 1054 492 1070 491 354 468 1056 438 1109 438 386 437 385 438 1107 439 385 438 400 464 1081 465 359 464 360 463 361 462 362 461 388 435 388 435 404 434 389 434 389 434 389 434 389 434 389 434 389 434 389 434 405 434 389 434 389 434 1112 434 389 434 389 434 1113 434 389 434 405 434 1112 435 389 434 366 458 365 458 365 458 365 458 365 458 381 458 365 458 366 457 365 458 1089 457 366 457 366 457 366 457 382 456 367 433 390 433 391 432 391 432 391 432 391 432 391 432 406 433 391 432 391 432 390 433 391 432 391 432 391 432 391 432 406 433 391 432 391 433 391 432 391 432 391 432 391 432 391 432 407 432 391 432 391 432 391 432 392 431 391 433 391 432 391 432 430 409 393 430 392 431 392 431 392 432 391 457 367 432 392 431 408 431 392 431 1138 433 391 408 392 431 392 456 367 456 1113 408 421 433 +# +name: Off +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3013 1709 463 1085 462 1084 463 387 461 355 469 355 444 1084 463 387 461 378 436 1084 462 1084 487 355 469 1059 463 387 460 355 444 1083 463 1098 464 386 437 1083 463 1083 489 361 463 360 463 1082 464 361 462 376 462 1085 461 363 460 364 459 364 459 365 458 365 459 364 459 380 459 365 458 365 458 365 458 365 458 365 458 365 458 365 459 380 458 365 459 365 458 365 459 365 458 365 458 1089 458 365 458 380 459 1088 459 365 458 365 458 365 458 365 459 365 458 365 458 381 458 365 458 365 458 365 458 1089 458 365 458 365 458 365 458 381 458 365 458 365 458 365 458 365 458 365 458 365 458 365 458 381 457 366 457 366 457 366 457 366 457 366 458 365 458 366 457 381 458 366 458 366 457 366 457 366 457 366 457 366 457 366 457 381 458 366 457 366 457 366 457 366 457 366 457 366 457 366 457 382 457 366 457 366 457 366 457 366 457 366 457 367 457 366 457 382 457 367 456 1090 457 1090 456 1090 457 1090 457 1090 456 367 457 372 457 diff --git a/assets/resources/infrared/assets/audio.ir b/assets/resources/infrared/assets/audio.ir new file mode 100644 index 000000000..dec6c05a9 --- /dev/null +++ b/assets/resources/infrared/assets/audio.ir @@ -0,0 +1,244 @@ +Filetype: IR library file +Version: 1 +# +# Model: NoName Unknown Audio remote +name: Play +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 43 00 00 00 +# +name: Vol_up +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 15 00 00 00 +# +name: Vol_dn +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 07 00 00 00 +# +name: Next +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 40 00 00 00 +# +name: Prev +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 44 00 00 00 +# +# Model: Western Digital Unknown +name: Power +type: parsed +protocol: NECext +address: 84 79 00 00 +command: 12 ED 00 00 +# +name: Play +type: parsed +protocol: NECext +address: 84 79 00 00 +command: 0A F5 00 00 +# +name: Vol_up +type: parsed +protocol: NECext +address: 84 79 00 00 +command: 05 FA 00 00 +# +name: Vol_dn +type: parsed +protocol: NECext +address: 84 79 00 00 +command: 00 FF 00 00 +# +name: Next +type: parsed +protocol: NECext +address: 84 79 00 00 +command: 01 FE 00 00 +# +name: Prev +type: parsed +protocol: NECext +address: 84 79 00 00 +command: 02 FD 00 00 +# +# Model: Yamaha RAV15 +name: Play +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 43 00 00 00 +# +name: Vol_up +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 15 00 00 00 +# +name: Vol_dn +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 07 00 00 00 +# +name: Next +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 40 00 00 00 +# +name: Prev +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 44 00 00 00 +# +# Model: Yamaha RX-V375 +name: Power +type: parsed +protocol: NEC +address: 7E 00 00 00 +command: 2A 00 00 00 +# +name: Vol_up +type: parsed +protocol: NEC +address: 7A 00 00 00 +command: 1A 00 00 00 +# +name: Mute +type: parsed +protocol: NEC +address: 7A 00 00 00 +command: 1C 00 00 00 +# +name: Vol_dn +type: parsed +protocol: NEC +address: 7A 00 00 00 +command: 1B 00 00 00 +# +# Model: SVEN HT-415 +name: Power +type: parsed +protocol: NEC +address: 41 00 00 00 +command: 42 00 00 00 +# +name: Vol_up +type: parsed +protocol: NEC +address: 41 00 00 00 +command: 0B 00 00 00 +# +name: Vol_dn +type: parsed +protocol: NEC +address: 41 00 00 00 +command: 1B 00 00 00 +# +name: Mute +type: parsed +protocol: NEC +address: 41 00 00 00 +command: 56 00 00 00 +# +# Model: HUAYU AKB74475490 +name: Power +type: parsed +protocol: NEC +address: 04 00 00 00 +command: 08 00 00 00 +# +name: Play +type: parsed +protocol: NEC +address: 04 00 00 00 +command: B0 00 00 00 +# +name: Pause +type: parsed +protocol: NEC +address: 04 00 00 00 +command: BA 00 00 00 +# +name: Vol_up +type: parsed +protocol: NEC +address: 04 00 00 00 +command: 02 00 00 00 +# +name: Vol_dn +type: parsed +protocol: NEC +address: 04 00 00 00 +command: 03 00 00 00 +# +name: Prev +type: parsed +protocol: NEC +address: 04 00 00 00 +command: 8F 00 00 00 +# +name: Next +type: parsed +protocol: NEC +address: 04 00 00 00 +command: 8E 00 00 00 +# +name: Mute +type: parsed +protocol: NEC +address: 04 00 00 00 +command: 09 00 00 00 +# +# Model: Samsung HW-K450 Soundbar +# +name: Power +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4637 4376 612 419 584 420 584 420 583 421 582 1427 531 1477 531 472 532 472 557 1452 556 1451 557 1451 557 1452 556 447 557 448 556 449 555 449 555 4453 554 450 554 450 554 451 553 450 554 451 553 451 553 451 553 450 554 1455 553 1454 554 1454 554 451 553 1454 554 1454 554 1455 553 1454 554 451 553 450 554 450 554 1455 553 55439 4554 4458 555 449 555 449 555 450 554 450 554 1455 553 1454 554 451 553 450 554 1454 554 1454 554 1454 554 1455 553 450 554 451 553 451 553 451 553 4453 554 451 553 451 552 451 553 451 553 451 553 451 553 451 553 451 553 1455 553 1455 553 1455 553 451 553 1455 553 1455 553 1455 553 1455 553 451 553 451 552 451 553 1455 553 +# +name: Play +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4636 4380 612 392 612 394 610 394 610 419 583 1399 557 1452 556 473 556 448 556 1428 581 1453 555 1453 555 1453 555 449 555 450 554 451 553 452 552 4457 551 452 552 452 552 452 552 452 552 452 552 1457 551 452 552 1457 551 452 552 452 552 453 551 1457 552 1457 551 452 552 1457 551 452 552 1457 551 1457 551 1457 552 452 552 55450 4551 4461 553 451 553 452 552 452 552 452 552 1456 552 1456 552 452 552 452 552 1456 552 1456 552 1456 552 1456 552 452 552 452 552 453 551 453 551 4456 551 453 551 453 551 453 551 453 551 453 551 1457 551 453 551 1457 552 453 551 454 550 454 550 1457 552 1457 551 454 550 1457 551 454 550 1458 551 1457 551 1458 550 454 550 +# +name: Vol_up +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4640 4405 583 420 583 421 582 421 583 422 581 1427 531 1478 530 473 531 472 557 1452 557 1452 556 1452 556 1452 556 448 556 448 556 449 555 450 554 4454 554 451 553 451 553 451 553 451 553 1455 554 1455 553 1455 553 451 553 1455 553 1456 553 1456 553 451 553 451 553 451 553 451 554 1455 554 451 553 452 553 451 553 1456 553 55447 4556 4458 555 449 555 450 554 450 554 450 554 1455 553 1455 553 451 553 451 553 1455 553 1455 553 1455 553 1455 553 451 553 451 553 451 553 451 553 4454 553 451 553 450 554 451 553 450 554 1455 553 1455 553 1455 553 451 553 1455 553 1455 553 1455 553 451 553 451 553 451 553 450 554 1455 553 451 553 451 553 451 553 1455 553 +# +name: Vol_dn +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4636 4378 613 393 611 392 612 393 611 393 557 1451 558 1450 610 420 583 421 557 1427 581 1452 556 1452 556 1452 556 448 555 449 555 450 554 450 554 4455 553 451 553 451 553 451 553 451 553 451 553 451 553 452 552 1456 553 1456 552 1456 553 1456 552 451 553 1456 553 1456 552 1456 553 451 553 451 553 452 552 451 553 1456 552 55452 4553 4461 553 450 554 451 553 451 553 451 553 1456 553 1456 552 451 553 451 553 1456 552 1455 553 1455 553 1455 553 451 553 451 553 451 553 451 553 4456 552 451 553 451 553 451 553 451 553 451 553 451 553 451 553 1456 552 1455 553 1455 553 1455 553 451 553 1455 553 1456 552 1456 552 451 553 451 553 451 553 451 553 1456 552 +# +name: Prev +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 255 113623 4638 4378 613 391 612 392 559 446 558 446 558 1477 531 1477 532 472 532 472 532 1476 532 1476 532 1476 532 1477 531 473 555 449 555 449 555 450 554 4455 554 450 554 450 554 450 554 450 554 1455 554 1455 554 450 554 1455 554 450 555 450 554 450 554 1455 554 451 553 451 553 1455 554 450 554 1455 554 1456 553 1455 554 450 554 +# +name: Next +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4557 4430 611 392 610 394 559 445 559 446 558 1451 558 1477 531 448 556 472 532 1476 532 1477 532 1477 531 1477 531 473 556 449 555 449 555 450 554 4454 554 450 554 450 554 450 554 450 555 450 554 450 554 1455 554 1455 554 450 554 450 554 450 554 1455 554 1455 554 1455 553 451 553 450 554 1455 554 1455 554 1455 554 450 554 55458 4555 4459 554 450 554 450 554 450 554 450 554 1455 553 1455 553 450 554 450 554 1455 553 1455 553 1455 553 1455 553 450 554 450 554 450 554 450 554 4454 554 450 554 450 554 450 554 451 553 450 554 450 554 1455 553 1455 553 451 553 450 554 450 554 1455 553 1455 553 1455 553 450 554 451 553 1455 554 1455 553 1455 553 450 554 +# +name: Mute +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4639 4406 586 418 585 393 559 447 557 447 557 1477 532 1477 532 472 532 472 532 1476 533 1476 532 1476 532 1476 532 473 555 449 555 449 555 449 555 4455 554 450 554 450 554 450 554 450 554 1455 554 450 554 450 554 450 554 1455 554 1455 553 1455 553 450 554 450 554 1455 554 1455 554 1455 554 450 554 450 554 450 554 1455 554 55454 4557 4458 555 449 555 449 555 450 554 450 554 1455 554 1455 553 450 554 450 554 1455 554 1455 554 1454 554 1455 554 450 554 450 554 450 555 450 554 4455 553 450 554 450 554 450 554 450 554 1455 554 450 554 450 554 450 554 1455 554 1455 554 1455 553 450 554 450 554 1455 554 1455 553 1455 554 450 554 450 554 450 554 1455 554 diff --git a/assets/resources/subghz/assets/keeloq_mfcodes b/assets/resources/subghz/assets/keeloq_mfcodes index b8fc36903..1b27bfb01 100644 --- a/assets/resources/subghz/assets/keeloq_mfcodes +++ b/assets/resources/subghz/assets/keeloq_mfcodes @@ -1,50 +1,55 @@ Filetype: Flipper SubGhz Keystore File Version: 0 Encryption: 1 -IV: 2A 34 F1 5A AF 6F F5 1A 83 A6 1E DA DE B7 3D F1 -06B63DF24AE073A2F2B19C55CA9E8364FBECD26E49C551990153F6513BDE5267 -6139C78C74C341EB7474085CF1D047BD6FB005F80A72AF3EF3F89D58EF5DF500 -D85F11689020ECA47FBE9C2B67EE41A81E1F06DE2A35AF958965E3ECE29EA701 -1AE9073A42FE0E439544FE6945F6B33CF15A7A4A279020B5E0B3BE33FD189A7E -E161F007854BB33E0056FA09A2E2DEE66789B5C87C8D6D3DE2C8C1BD2B48983EB9D1C5697CA6E95996918F7C47B761B0 -59AE4644DCB3D720C38B5115F230DA58E7BE0A697907F6174BB05AB7886ACDB1 -634DF0BCC185C4C1F7E1B1594B4438D051ABAE092433078963063B51D961D08C -1EBEBCB49E498B9BE977D53EC21B9A546155B627737BD0AA832D496035729346 -4DFA93E639197772D57E8ACE04512CEFC045B8CC965C175A25ED525B630CBB63 -C2D5235D1014A319B249EAE8A5EE350F18D5AB8A498EF222704BD4EB1435F388 -F66D1937160E1392197F463A52E87FCE938A92070892113443C348D7553327A5715CF615CE2F2C96284F47759E043419 -841D29E7CBE040188E2283BFBA9F26EF2F65CCB085B56C3515E8C46C3F20BD75BAA963550869435FDAF509CEEE66A2C4 -7D87E24487D307635E7A17B989B8547EE11F3BF3468D055F0B44633B631BA42C -B4916043973501B95A82B329196D6EBA69FBBC3AF8FD914583104E0E18CE82F6 -E4649F9C2A5465D2EA6F3E9724DD06CD6962FE2BAEB14F1453C14D1559232AE1 -96E15D890DF7FD348441F5E429A875754C6BF0520A787F8E9D8C5415674783CC -CB52005EDED47B57F795BC92FB0522EAB18D23EE028B8D10ED57828C250EB285BFEC6E4A4BE8DABCE0D57ECAA20D90C3 -8E5A50C7D5C374445E88752301D20F0B3D6E4988B61D90FD63779B0EDEF9C60D -49D6CB276A0E5FF134A38062503F01351F44CD6455708B50B5F07D03FC477C33 -CB45B56613DF208E79E4E10A6510F07DC1AA49210C7B94E8BBAECD2C35EC6ABC99FB10FD7C96DD6BB6A6685E9FAD93FB -0743F3CC51200F763C242F1956B4D775C092ADF1A5C19ACAE96EB60C2990CF214F8FEA8FC6749286F6BDAB67657C479A -E5608B28A058787D64A145F0362DEFD98CAE0B5A0F22C6DA7C6D278C7B5F95E3 -D4C113D43E7FB6D2EFA9E87471AA76A61B26872607B4AF5B87F9D72113835CE6 -2DC502800BFD21B76126390CA64A08C5432A2254E822F214CDE1EA11430084C5 -CA22C73010B0F1CB8009601BE2AF0B3674D83D5880E4A26C2A3FF0EA0A098CEA -E53B2B102FDB000E9BB747F957156976E5A0C0E3898AA844C13AE8A9CEE7013B -95CF1A46FFC252BE92919531C92BF6A3AA1B16C170DF4461EC54BE07A55C2387 -2EC7E24090F6DFFF6F2F2D8874D2F36AA769995F31F29FBE3B0EA6A16C3EE833 -C1145B1D9AC70761EA902B86455C1BE1BB1153552A1F7327411DECABE538827B -18D596CADD2EE544200A58716C7A4690B658E58CC2B97334740F70894A6C90FA -6A2F8859DFF01E13AC6C5300AD4A2218810FC91A6FB64A560E99FE6C99226AD2 -48D2EB5A08E35AF89A3B7A1CFDEE829FC0C2DDD2E965F4E3D043B0B14CB7825E -91039325D53CDD0236D1CD13047973A013C14B45A32DE0784A73BFABCEAFBCD1 -51B4EAC87C4DC49B007F40D38B8166C388A1AF25E8D2FF6598E8EDE8726E6E14AD88443114D2A0F5E7721E304F3870DA -3A179DDF65B9868CD84C7C04931F40D5D204C97B20DCBF1A70C241E59BFD7F14 -AF538FD16104DCAF03F4DDF05026D6741898DFC247E48A8F72E652DDF2DFD289 -E67F16AEC9D84B6C06F77B806CA6FBC7618BFBECD0D7A04EC3AE1D1DD06BEC5B -FA4D9F8920EBF2F4293C6D4E99083AA4A71A9DDFFDB07EEBDC552DACEC4DA24A -5BF23E630AC81E2CD533803E225BCB3C481B8D650A9858CF2B5219BAE1CDA01A -17B57E8C1032481E69247EA9A0C9EA41F6C0EA9B3F11170CA69C0842423F0455 -96EA848B8527A647DC9DACDB16C5D92B0081EB1CD77B99B47F56C2E249190BD3BE4306333F37487133DD3AD8E57F3092 -B0E9411274D799BE5989D52E74E00DE310CCA2BD47D7A8FA554D66BB04CD787A -D0D28476E3D8832975653D93F545C35278EC1F0B7AD70CA2F36EB476CC207937 -933195E37014619F997B73F5CF4C0110865A822CA8CB0ED1D977D49A1B06A37F -E790CAC2A26452BF941A9E1BABF0A85598EA1CC8F8CFED637C9B40D5E027B518 -49C1F179ABA5BD4F2C45257A33701730E9CC4728677EFF07808ABE31D3CE6FD5C805F43EA5ABB7261B220C82F0794092 +IV: AA FF DE 54 A1 BB F1 21 83 46 FE 2A 1E B7 3D 33 +95B8CD65BBAC95EACE67CA94F679B82877A921396D461ECB479722F8A369454A +61065C41297B9FF8F8168814F49A03D1FE7B4CB79DFFCBBF0402AAA6A2211E84 +A1557AC139188FF105D1081A4B688C5CA440FB5DA7F40901B541120AD08A544F +AF0A6056D7F0D97DAD6C16C4E63204E4B3B1C5A20AC82B983B516F4F718EE29F +6861BFAE46A1AADB1DB2D6DFAA7E39D21D5B3E46A41BD50F4F2828879EB328EF0A406F2B9C79A031AB361257E6D69756 +0DDB3DAC53678541981CC46C22CED245CBA314C9BBE1BA9383B8505B75AC5E40 +99AB5D9404934F2D257ED04D9F8CCEE06D00F38157B121AFD63101E4E5C08268 +5114A6C42B342C7D933A76F9052FF963C2047E85EA524497C21B4C35C38EF6E7 +88CA2A1907D94B972FF93DBB9B88CB576F3E1BB0FE8F85A5B2CCA7D44B00374D +349C4153FE7CA8AE044E9F75F77D9694304474CE3F127CF968662B5F78A7F421 +62AA02E20CA7E691EFC0B55CA41C9BDF889FB23868289284241CD31AA1A0E499AE2A770B6B5AB3170CDCCDB8A246D36C +97901B5EB76228ADF8E5073F1BAB1502878DEFF1C4EBF12A43D105556CB7E80F947A8BD7831666BD838C57CDF64A6F3F +B05959D210B500943A93BDFAF783D9DB215FC84503B152EAFBCFB5B6237E3888 +B393DE4489BCAFD5DB80592A12E329E18913E185D2042580048029A8C4C3A257 +B4B30492A5F0C3C763E2F43C02D1451A5B9CFB468CFE62BE85B1F56FF49DAB9A +CE5D57C0EE3D717FC717EB725970A9F25D211546EE7AC5C237950CEA323D85D4 +4E9028944813FD40A17AF6DF5A97E76179B48EE79265BBD38B07E3A270587A813DADB51B3367479AC5644F754B5613F8 +3B3C3000B9D1361711ECE3DB77C90A059576F738CB167679DA36DD3D128B27A1 +997023148148DE7B9CBA47D3FD48DEF73AA1715FF4BC1E7A1DBA6D52A0DCB2C0 +C8428D18E69FB92486434FCE470F1FF37D40507F27D824679C132A70D516530367277F02DDB5C464D03450FF6B425A24 +3701200DF5DA7235971FD95844056E74C7D61A8EB12A8772E04F52037C63D50B6229A7F905F3E6F84C565FCC7632870C +BB392A464CDC0D5D923AA9EF8ECC3C6F020D0AD82165462DF0DE7C5025AAAAAC +999C82209B30638506E5D708471676D2CBB4A432E5AF86ABD61179111EDAE636 +FDE2A452A6B47261338117EC20FC57731DA492562ECD21BBC61F098A5442CF20 +D923BABB5C4DFB48E3F763898B2796C7830D3EE9A91DF904AC2223A0F4736507 +0987DDAC695DD5E4607048DF1D4EF96599E17ED52F41785E676AA048AB7213FE +26CB3E6CFA10338A8DDD99BFF6957C53DEF435CB0FF977B71B5164ADFE11292A +097908FD07A0A093CA80E6FF59524707C1A11169D0CB6F8E4967D8DAA725FE7A +8C629E70A5CC6FCB039DFA1A6AC58CB7B7E92C85BDA66266AB49E6B1285FC7A6 +39A2052350CD446EDC1B9AD0C2DD51C78B2E5F3A76AAD0EC200F74B40ACD4AC5 +A1685CF8C4A5401F2CA0C8172CB5B4B5726C61CE68A72AE834B0A472CEB2F3DE +1F5ED5793DB381D1B501BA8A4DF3E74FB11FC1A922DDC8AE62E5BA8934C37EA8 +D80EF661BF36E2F6C179E253CE5BC3732684ACBC7C65E526A628442A2EBF8FAA +7785BF721F21E19A8CFBFBBB56BD76B96A4E8EF9F8A2344009B14AB385909598F834A5533B648DA7D62BD6D4314A43A5 +C8F6F943DE615B5827569B283577344C0455B3279C73634FC4E0E9A8088DF633 +FB4F4C786FC51BBDA679A212B4A05EF120AC62F7EBFFE8263BD50A4D9BC9C6E0 +16EEC35CF69BA86DB3BE999CDF9B39F5736F3727B2AA2C5AB9141A48F176D831 +AD1AD6DE813E7710DA3AF546D4F9EA085831E6B3FA17B64F1B8765F48134EA54 +345D743BC35B4A8614632ADD11E809C0D1E6C78F9469256B9A738DA0B648B2B8 +7C876CECAC839EBB4609C3996966C3EC454F51C8ABCC51097E405370C4B6F086 +0F857C031FD3047607647148C534F969567F207FF1691D8D06DCDF4C2514695D +EC0630EDC82241C1952F49B6B1B0C1A954A7DDD6BDB1326ACC54AD449D1BF985 +286EF9F7FD0D09F2604CCE867C52144CD0C4773A3D8183066C61B8BF9860AE7C +EA55424097A08722A66966E3177E09DE91AC65175E5C68CB47B6153E6585DF85 +D54FCDF9EA4BD1FE4F316DB6D5CE4A2675F2D0144772865EDC781FBA7DFD23E4 +7A2F5C5CA9F97FE9527BAA760E64B930C407A27DE036476737E6BDD9422F4056A5F1F414F12F0982109FD7C30E8CC1CB +06BAD9B4EEEEB1BCF8C97672D271534FE84D772282EE9642698788D3842D7641 +101C1B2DBD963E23777294C22E553D145D5B40838F91355CA86D571A0CEFF68F +1B148C2B502B3E0A5BD40858E019C513DD4CCAF2A114CBB29C59BFB018079285 +8DF4D07EC20FF873EA989ACEF4AF96E9787FE6E0F71965858B4186C3AF302A31 +2317DC8C098CD60F3467B3644A19CCE887339708820CD37F6F5277D6648F837512F70CE90E23D7339CDDE002BD8D83DB diff --git a/assets/unit_tests/subghz/oregon2_raw.sub b/assets/unit_tests/subghz/oregon2_raw.sub deleted file mode 100644 index 549a60db3..000000000 --- a/assets/unit_tests/subghz/oregon2_raw.sub +++ /dev/null @@ -1,20 +0,0 @@ -Filetype: Flipper SubGhz RAW File -Version: 1 -Frequency: 433920000 -Preset: FuriHalSubGhzPresetOok270Async -Protocol: RAW -RAW_Data: 889 -130 325 -64 457 -560 165 -68 199 -170 67 -66 265 -132 133 -666 67 -166 431 -66 201 -98 297 -100 595 -66 199 -134 65 -100 795 -132 99 -168 501 -200 331 -132 265 -102 265 -134 423 -98 521 -226 65 -166 431 -134 99 -100 133 -464 195 -326 623 -100 673 -98 321 -200 65 -136 369 -166 65 -68 97 -166 165 -334 265 -102 231 -166 101 -170 65 -170 265 -136 931 -100 133 -134 563 -66 333 -100 427 -66 163 -390 231 -66 193 -130 461 -166 557 -100 99 -198 263 -100 197 -294 231 -232 299 -134 199 -170 267 -134 631 -98 235 -100 499 -68 463 -100 65 -134 335 -170 273 -134 297 -100 67 -66 197 -166 67 -134 301 -168 537 -470 99 -134 433 -132 199 -192 261 -100 523 -164 459 -132 259 -332 359 -64 227 -96 131 -132 687 -132 363 -136 329 -434 99 -334 133 -100 401 -132 233 -700 233 -170 337 -66 371 -68 233 -202 531 -266 731 -66 465 -100 167 -100 133 -232 335 -166 239 -102 367 -232 231 -100 167 -134 201 -136 301 -168 199 -300 231 -98 237 -134 233 -102 329 -132 261 -134 199 -66 265 -136 99 -170 167 -134 199 -166 167 -136 367 -298 197 -200 99 -166 469 -136 439 -66 303 -134 295 -100 433 -134 899 -266 363 -132 197 -160 555 -324 129 -96 97 -128 257 -132 97 -394 257 -98 195 -166 459 -332 395 -132 633 -134 301 -100 131 -332 169 -168 395 -166 263 -540 783 -100 287 -130 295 -96 225 -296 133 -98 99 -100 461 -164 545 -130 99 -66 301 -68 265 -100 235 -134 235 -70 333 -102 497 -66 233 -364 301 -170 103 -66 165 -336 733 -200 133 -100 263 -102 65 -136 465 -200 1035 -198 165 -170 67 -302 631 -100 429 -332 65 -128 129 -130 159 -128 159 -66 161 -96 325 -164 261 -100 197 -162 65 -96 99 -130 65 -102 333 -100 199 -98 389 -330 129 -128 229 -66 425 -366 229 -64 261 -100 227 -96 227 -526 301 -200 97 -66 699 -334 67 -100 399 -198 787 -98 297 -134 429 -100 3245 -64 527 -98 131 -526 633 -68 133 -302 1459 -164 971 -102 237 -136 1439 -266 1131 -66 599 -200 303 -332 325 -130 389 -166 371 -66 333 -102 65 -100 233 -234 327 -266 233 -166 297 -100 225 -130 163 -336 99 -596 199 -330 131 -66 331 -338 263 -358 197 -168 877 -66 227 -96 63 -130 263 -162 225 -290 197 -198 357 -132 297 -262 165 -456 227 -98 399 -296 95 -132 99 -98 457 -200 199 -168 535 -100 567 -134 327 -130 193 -130 683 -102 101 -132 233 -170 943 -166 827 -66 267 -102 503 -68 1325 -164 -RAW_Data: 1607 -68 233 -166 1167 -70 531 -134 335 -168 131 -66 299 -402 899 -66 461 -66 457 -98 953 -98 165 -66 293 -230 881 -64 393 -166 589 -66 289 -66 1093 -204 333 -98 2745 -132 2019 -170 925 -68 269 -102 1469 -136 2301 -68 1355 -100 527 -66 975 -68 1445 -98 2397 -100 1733 -66 703 -100 995 -100 135 -136 235 -202 167 -134 2071 -166 339 -170 201 -268 129 -66 465 -66 365 -100 197 -164 129 -98 161 -96 423 -66 675 -66 1543 -136 567 -200 767 -202 65 -100 1401 -66 623 -136 567 -234 67 -236 197 -194 97 -66 263 -66 1827 -392 1893 -98 165 -268 133 -132 231 -162 225 -98 695 -198 563 -100 301 -332 267 -102 341 -66 99 -132 1299 -130 525 -68 161 -96 357 -98 353 -100 131 -100 131 -98 163 -132 323 -100 535 -66 1323 -130 133 -66 235 -134 1497 -132 387 -98 129 -162 2623 -134 163 -68 167 -66 959 -232 495 -68 131 -134 867 -134 865 -66 333 -98 305 -134 231 -98 765 -198 397 -432 165 -66 165 -366 265 -102 541 -100 261 -162 331 -134 457 -66 491 -196 97 -266 193 -262 65 -166 231 -266 497 -360 263 -98 587 -164 259 -98 231 -66 359 -100 267 -102 271 -168 97 -262 63 -66 261 -130 227 -130 295 -164 65 -66 265 -200 597 -134 267 -170 603 -100 97 -466 231 -264 97 -168 99 -66 65 -200 199 -100 267 -404 303 -102 201 -204 235 -134 131 -198 335 -298 327 -130 291 -164 63 -162 295 -262 197 -130 95 -130 195 -96 159 -130 161 -66 231 -100 165 -66 199 -134 363 -66 267 -168 165 -168 167 -100 165 -530 363 -432 99 -232 65 -132 395 -328 229 -98 197 -132 161 -96 191 -292 197 -204 133 -100 399 -166 531 -332 235 -168 99 -66 325 -158 553 -132 129 -226 231 -134 99 -462 129 -64 289 -100 193 -66 355 -164 291 -198 131 -298 197 -198 373 -268 335 -234 427 -68 199 -132 267 -232 131 -66 783 -326 63 -162 161 -130 227 -66 259 -562 233 -464 303 -102 201 -334 301 -134 297 -198 229 -66 127 -166 99 -100 197 -198 571 -66 457 -134 361 -424 131 -328 163 -98 63 -100 505 -102 201 -1094 229 -164 65 -230 789 -236 2505 -166 201 -170 163 -64 1139 -66 927 -100 295 -198 723 -100 365 -66 459 -196 3033 -272 199 -66 499 -202 1319 -232 295 -298 131 -362 97 -164 129 -132 65 -98 197 -130 129 -98 261 -130 97 -98 229 -96 425 -66 227 -166 483 -66 163 -326 567 -68 235 -68 67 -66 167 -66 235 -330 425 -164 63 -66 427 -102 167 -66 669 -132 429 -200 65 -102 133 -100 197 -368 -RAW_Data: 65 -134 2481 -228 65 -130 229 -228 763 -136 603 -166 1619 -98 1763 -102 837 -166 321 -66 951 -130 2067 -66 259 -132 1835 -66 437 -102 701 -66 565 -68 363 -70 1113 -66 1989 -164 257 -128 351 -162 1055 -232 265 -170 309 -200 435 -166 833 -102 2467 -132 595 -66 773 -166 1615 -98 131 -96 485 -64 517 -166 197 -68 1231 -68 403 -100 263 -134 233 -100 503 -100 333 -266 729 -66 199 -100 369 -68 1239 -100 197 -68 299 -170 337 -100 825 -132 163 -66 4205 -64 161 -100 635 -66 907 -66 1017 -166 1709 -100 201 -266 657 -68 463 -166 331 -164 293 -64 259 -162 129 -262 597 -134 701 -136 67 -168 235 -136 303 -170 1417 -66 263 -98 857 -100 659 -166 97 -100 2497 -64 2495 -98 719 -128 227 -130 2217 -164 623 -264 719 -134 329 -98 1371 -100 553 -294 165 -66 1163 -100 329 -196 649 -200 1123 -68 263 -100 593 -266 333 -102 1133 -136 131 -132 603 -200 1819 -66 489 -66 563 -266 1113 -230 165 -66 423 -68 335 -100 101 -100 1073 -132 897 -100 101 -100 499 -134 173 -138 763 -238 371 -130 403 -166 203 -102 271 -136 269 -166 99 -168 263 -96 425 -66 331 -234 133 -400 231 -132 453 -66 459 -164 199 -68 237 -132 163 -198 161 -196 265 -132 65 -64 195 -130 357 -164 663 -68 167 -600 131 -98 133 -304 203 -134 433 -98 261 -130 199 -100 237 -100 229 -326 99 -98 331 -132 99 -294 165 -66 303 -134 99 -232 133 -136 99 -68 267 -198 233 -138 67 -166 367 -100 333 -168 267 -200 369 -266 135 -404 1939 -132 231 -160 161 -64 293 -98 331 -132 339 -104 135 -100 197 -430 263 -202 233 -64 195 -162 129 -64 227 -298 265 -68 697 -66 301 -68 231 -300 131 -368 769 -234 265 -98 195 -324 97 -752 229 -126 355 -98 257 -98 287 -64 427 -132 295 -262 197 -170 369 -102 267 -100 169 -68 201 -102 2551 -136 635 -134 639 -134 99 -132 197 -200 371 -66 731 -132 199 -138 733 -304 433 -68 729 -440 197 -68 99 -102 165 -266 261 -164 491 -296 489 -194 257 -164 133 -134 237 -68 335 -98 227 -130 229 -98 295 -98 231 -202 267 -236 233 -136 331 -130 195 -128 261 -430 261 -162 97 -224 99 -130 193 -96 197 -162 229 -396 97 -98 227 -364 267 -100 99 -100 233 -236 697 -164 227 -196 63 -98 327 -230 325 -66 129 -196 95 -98 195 -130 325 -430 131 -194 129 -454 161 -196 235 -68 433 -134 667 -164 355 -236 101 -98 2143 -134 1827 -198 63 -198 65 -64 2859 -64 619 -66 97 -130 3157 -66 679 -194 1491 -98 -RAW_Data: 951 -64 393 -100 955 -132 4715 -100 131 -66 199 -204 1541 -66 929 -130 1347 -166 665 -132 233 -132 67 -102 433 -100 595 -228 997 -66 505 -68 133 -98 231 -68 571 -134 1371 -232 231 -270 135 -102 97 -66 867 -100 269 -68 967 -100 1649 -66 65 -66 951 -68 65 -202 363 -200 779 -102 1449 -294 419 -130 361 -230 1079 -164 163 -260 893 -102 333 -100 533 -166 467 -100 135 -66 135 -202 369 -100 199 -100 269 -134 301 -166 229 -66 101 -134 199 -134 1293 -64 779 -62 831 -66 1243 -68 267 -102 197 -100 395 -98 455 -64 621 -132 877 -98 199 -100 2101 -134 503 -100 2035 -134 735 -236 475 -136 237 -132 133 -134 1229 -100 133 -66 167 -68 2655 -100 1807 -100 1095 -264 825 -98 163 -66 491 -98 161 -128 953 -100 773 -100 131 -66 67 -134 457 -130 63 -64 389 -98 715 -66 425 -300 97 -100 1515 -66 303 -68 99 -98 721 -64 887 -132 65 -132 165 -66 635 -68 2801 -66 1561 -100 751 -98 129 -64 725 -136 201 -100 333 -204 573 -104 1745 -134 99 -66 129 -64 595 -134 167 -102 337 -134 567 -134 1131 -138 1207 -100 269 -68 135 -100 1143 -134 2139 -68 1701 -162 991 -596 431 -66 99 -132 657 -66 391 -320 357 -260 259 -98 429 -66 163 -228 65 -130 227 -66 261 -166 99 -98 131 -366 199 -134 463 -102 201 -98 231 -102 639 -238 301 -568 169 -610 265 -102 841 -198 297 -100 335 -132 263 -266 265 -68 469 -134 267 -68 933 -298 333 -298 729 -168 135 -136 437 -132 1137 -134 199 -68 265 -132 463 -166 129 -130 227 -98 297 -98 65 -132 97 -202 199 -232 305 -66 165 -198 365 -66 99 -98 299 -170 65 -136 301 -232 99 -564 133 -132 233 -170 99 -102 131 -134 65 -204 101 -98 297 -98 167 -762 233 -298 99 -326 395 -66 299 -132 369 -504 333 -98 483 -200 457 -164 63 -164 329 -162 65 -622 231 -268 131 -132 133 -134 131 -134 131 -66 99 -100 231 -66 167 -336 165 -98 197 -100 97 -264 321 -98 521 -132 163 -130 129 -294 297 -134 101 -102 265 -168 497 -68 197 -68 499 -134 269 -398 267 -130 203 -302 65 -498 271 -136 465 -292 131 -294 163 -198 329 -96 129 -98 193 -130 391 -330 165 -134 167 -170 297 -102 133 -136 135 -366 199 -132 423 -132 395 -168 65 -166 401 -98 229 -98 329 -98 99 -130 129 -228 261 -160 127 -426 389 -162 193 -132 131 -100 231 -168 67 -304 201 -68 765 -132 161 -162 193 -64 195 -64 295 -130 787 -98 419 -528 429 -66 363 -134 131 -100 133 -200 331 -98 -RAW_Data: 431 -66 1167 -68 937 -68 1003 -66 99 -132 941 -134 65 -66 365 -274 165 -236 367 -96 557 -134 675 -66 261 -164 127 -96 391 -164 161 -98 391 -292 163 -98 519 -196 165 -98 523 -66 195 -160 3343 -66 661 -100 2589 -136 307 -100 629 -136 639 -100 133 -168 405 -100 267 -66 465 -132 1171 -64 749 -64 165 -98 983 -100 163 -202 537 -66 327 -100 669 -100 401 -236 2885 -164 439 -134 97 -426 1931 -66 1385 -98 715 -98 519 -66 289 -162 97 -360 297 -166 163 -66 289 -66 555 -334 167 -230 429 -102 267 -132 943 -136 401 -68 929 -130 193 -68 467 -198 335 -66 963 -100 597 -132 197 -260 523 -232 1115 -102 1935 -66 1395 -134 305 -100 99 -66 199 -66 1071 -66 2357 -66 367 -498 769 -234 163 -130 191 -64 1211 -200 133 -102 201 -100 561 -366 361 -98 195 -100 537 -64 165 -196 1041 -332 133 -102 441 -230 4217 -66 1033 -66 167 -66 933 -100 565 -66 331 -164 673 -104 441 -66 533 -66 2095 -164 525 -66 297 -170 965 -198 421 -100 663 -832 65 -100 331 -164 231 -166 135 -168 237 -466 761 -134 891 -196 791 -198 257 -160 161 -98 293 -66 1081 -98 229 -130 327 -66 1301 -200 331 -166 101 -66 461 -100 2619 -132 1663 -98 1609 -134 499 -332 165 -370 67 -264 97 -96 259 -98 701 -402 197 -128 527 -236 233 -102 167 -134 303 -134 99 -166 299 -132 165 -200 467 -68 305 -168 207 -102 465 -102 729 -136 101 -374 327 -96 259 -98 467 -202 65 -66 673 -98 335 -404 135 -66 339 -204 99 -366 233 -68 365 -166 133 -102 867 -198 163 -162 163 -294 463 -332 165 -68 269 -268 331 -100 131 -166 299 -132 231 -400 263 -164 131 -266 267 -264 367 -66 371 -134 229 -104 267 -232 67 -466 265 -100 101 -100 165 -200 65 -200 301 -66 199 -168 233 -98 267 -66 67 -134 261 -196 261 -234 427 -294 65 -194 193 -66 259 -132 849 -96 63 -198 167 -294 95 -98 361 -164 261 -196 131 -132 437 -100 597 -262 327 -162 295 -98 295 -164 259 -196 425 -230 321 -66 195 -66 261 -496 99 -200 529 -132 133 -966 133 -132 165 -66 63 -128 491 -402 65 -262 299 -66 299 -202 265 -100 99 -668 97 -134 65 -100 101 -66 65 -266 691 -66 431 -166 167 -134 199 -370 899 -134 99 -100 1093 -166 163 -166 399 -98 327 -100 99 -168 135 -200 133 -202 429 -98 65 -98 197 -556 65 -66 97 -326 331 -166 333 -200 135 -100 235 -234 265 -98 65 -68 135 -66 335 -66 133 -298 99 -66 233 -164 435 -232 97 -132 97 -392 -RAW_Data: 99 -198 819 -66 1235 -98 321 -132 1091 -66 1307 -98 3059 -164 3305 -64 227 -98 591 -98 129 -66 229 -98 2143 -98 939 -68 563 -100 361 -232 945 -164 257 -96 229 -230 387 -64 195 -130 981 -294 587 -162 193 -98 1337 -66 293 -98 2665 -66 297 -98 647 -66 459 -132 491 -164 489 -96 595 -66 899 -66 837 -64 1151 -196 259 -98 357 -164 891 -132 1359 -134 197 -98 97 -98 261 -64 229 -96 461 -136 693 -100 201 -98 865 -66 599 -100 517 -132 709 -66 293 -298 655 -66 197 -130 129 -66 197 -98 4291 -66 673 -66 667 -132 1473 -132 133 -104 99 -66 163 -168 333 -134 1743 -132 1097 -132 99 -68 167 -602 1323 -352 99 -166 753 -98 423 -98 97 -66 1317 -228 1309 -98 1849 -66 1939 -132 601 -100 665 -100 1875 -66 695 -132 425 -66 425 -66 263 -134 165 -134 99 -98 829 -66 601 -166 131 -102 565 -66 301 -100 1099 -100 601 -138 533 -66 667 -234 561 -66 99 -68 2741 -98 199 -100 531 -168 101 -434 1027 -68 431 -66 403 -132 99 -98 565 -132 135 -100 399 -166 271 -236 233 -166 197 -366 99 -66 99 -168 503 -66 199 -170 207 -100 673 -368 99 -66 263 -168 133 -98 397 -268 337 -66 131 -132 231 -132 501 -134 99 -168 567 -138 103 -136 267 -298 231 -134 197 -160 321 -332 231 -98 131 -164 257 -64 163 -328 395 -66 331 -202 65 -168 133 -68 167 -100 233 -102 335 -66 197 -326 1101 -132 589 -100 811 -132 399 -136 269 -102 497 -66 559 -100 129 -98 855 -68 637 -102 65 -200 875 -68 233 -166 167 -66 529 -202 235 -102 231 -66 1237 -66 733 -98 1723 -132 101 -100 297 -66 829 -232 197 -100 367 -134 169 -166 167 -434 633 -100 235 -200 131 -134 233 -100 131 -100 331 -134 495 -432 65 -528 161 -130 295 -132 337 -136 133 -166 165 -100 269 -240 201 -336 133 -166 165 -238 199 -202 431 -434 99 -134 501 -166 231 -96 559 -202 167 -66 717 -98 987 -198 65 -64 163 -64 227 -98 555 -164 199 -64 361 -66 163 -98 129 -162 97 -130 161 -460 197 -230 681 -98 197 -98 329 -100 267 -266 291 -264 65 -100 329 -100 459 -200 363 -98 165 -134 231 -134 301 -134 231 -302 99 -132 101 -134 267 -136 233 -68 393 -422 163 -166 361 -166 99 -134 365 -134 133 -336 401 -66 495 -132 401 -168 133 -402 501 -136 1093 -862 165 -132 293 -300 289 -66 131 -164 391 -134 99 -360 359 -130 323 -200 423 -98 195 -162 295 -132 161 -98 129 -782 131 -426 227 -64 259 -166 63 -160 323 -98 261 -230 -RAW_Data: 231 -66 921 -66 355 -64 1019 -98 227 -258 163 -66 597 -232 1313 -132 163 -404 467 -236 901 -164 483 -98 195 -96 489 -134 103 -238 169 -66 67 -68 299 -100 497 -68 65 -134 1635 -304 1153 -100 539 -168 265 -200 499 -166 535 -100 397 -168 931 -100 131 -66 631 -134 897 -270 1233 -100 65 -132 131 -334 663 -66 163 -66 131 -132 705 -98 571 -200 433 -100 237 -234 229 -132 1627 -66 569 -100 715 -66 1863 -272 265 -68 301 -98 465 -68 97 -134 99 -66 395 -136 1405 -66 529 -132 63 -196 579 -132 413 -260 129 -136 101 -166 1201 -134 833 -134 393 -66 335 -172 201 -68 1027 -96 753 -64 815 -66 97 -64 1341 -132 289 -160 127 -66 99 -228 1083 -96 163 -66 259 -64 159 -98 2409 -168 767 -200 367 -66 1675 -66 1067 -98 3407 -200 99 -66 1403 -166 99 -134 439 -200 329 -136 599 -66 637 -66 835 -66 1099 -98 99 -66 463 -166 165 -100 461 -164 3037 -66 655 -66 97 -98 229 -130 355 -132 1443 -66 527 -98 881 -98 229 -162 127 -96 583 -64 65 -162 489 -166 885 -194 257 -98 1539 -66 293 -166 229 -132 655 -98 757 -49522 271 -758 689 -1264 737 -670 293 -1152 811 -1144 341 -664 773 -678 327 -1118 807 -1144 835 -1146 781 -1126 873 -1096 347 -622 877 -624 321 -1106 843 -1098 871 -1098 843 -1106 379 -610 841 -584 381 -1122 365 -602 845 -1116 837 -610 381 -1056 889 -1078 383 -614 827 -1110 877 -592 353 -1108 845 -1120 839 -1120 347 -602 849 -1110 865 -612 361 -1072 869 -1114 351 -618 861 -618 343 -1090 853 -1106 387 -618 797 -674 347 -1084 389 -574 867 -584 381 -1114 841 -1102 845 -1116 839 -1112 843 -1098 875 -1086 383 -584 865 -588 375 -1100 861 -1112 851 -1084 853 -1108 847 -1106 381 -584 857 -610 383 -1080 357 -602 871 -602 385 -1084 383 -616 823 -610 373 -1086 381 -590 871 -1084 839 -628 353 -1102 875 -1100 349 -9404 875 -1060 871 -1086 887 -1088 879 -1058 863 -1086 855 -1132 845 -1078 871 -1076 857 -1098 881 -1082 861 -1088 843 -1120 853 -1074 879 -1074 879 -1068 889 -614 341 -1090 387 -616 863 -624 345 -1088 391 -590 857 -612 385 -1058 393 -596 843 -1088 889 -1078 879 -578 387 -1082 875 -1076 415 -550 881 -1070 877 -592 391 -1114 821 -1104 373 -620 821 -624 361 -1072 903 -1086 855 -1092 843 -1086 905 -1054 387 -614 863 -618 347 -1088 853 -1114 845 -1090 867 -1070 381 -610 885 -584 385 -1052 407 -578 877 -1052 899 -600 389 -1048 907 -1074 383 -586 877 -1072 877 -594 359 -1076 875 -1082 891 -1088 363 -616 855 -1084 857 -592 381 -1088 883 -1086 385 -572 -RAW_Data: 889 -624 353 -1082 853 -1096 379 -594 853 -624 353 -1092 417 -582 847 -612 385 -1076 847 -1080 883 -1052 913 -1044 907 -1076 849 -1088 383 -602 867 -616 361 -1068 901 -1072 865 -1104 831 -1080 879 -1098 397 -586 855 -626 355 -1084 381 -592 873 -616 351 -1084 385 -624 821 -620 359 -1086 387 -584 883 -1086 877 -592 355 -1106 853 -1086 387 -69570 97 -100 99 -2620 131 -636 333 -102 235 -236 67 -68 363 -66 201 -100 567 -102 267 -164 101 -134 65 -68 197 -68 297 -166 671 -100 469 -336 165 -100 201 -66 169 -230 169 -204 329 -624 67 -98 265 -232 193 -168 299 -100 235 -138 101 -370 165 -294 333 -622 231 -130 129 -130 353 -132 195 -162 359 -164 67 -68 333 -100 133 -688 235 -236 497 -198 293 -98 129 -296 293 -164 229 -128 229 -132 193 -400 165 -66 163 -98 361 -164 355 -196 587 -164 131 -98 263 -554 99 -130 129 -130 191 -464 99 -132 67 -100 167 -604 329 -66 199 -68 133 -102 163 -66 2971 -132 785 -66 329 -96 323 -100 201 -136 301 -66 1959 -166 867 -134 467 -66 297 -100 835 -100 753 -166 165 -64 67 -370 335 -66 559 -232 165 -334 65 -162 129 -354 163 -64 131 -134 265 -300 263 -132 267 -296 327 -198 99 -132 535 -132 469 -866 231 -860 99 -232 503 -134 99 -198 233 -134 267 -200 97 -358 297 -164 259 -98 227 -166 135 -66 323 -100 97 -294 131 -164 129 -98 295 -96 129 -426 299 -100 67 -102 623 -100 163 -194 127 -360 563 -134 199 -428 493 -98 229 -130 257 -64 165 -100 131 -98 163 -692 357 -64 161 -98 321 -64 389 -230 65 -692 227 -130 261 -132 231 -162 287 -298 97 -460 393 -130 301 -168 331 -100 269 -202 101 -134 201 -102 99 -132 199 -204 235 -664 65 -562 133 -328 463 -100 291 -194 159 -162 227 -98 293 -328 165 -128 227 -574 535 -332 197 -168 65 -300 131 -66 389 -1078 131 -64 259 -64 223 -98 257 -164 63 -328 433 -134 65 -602 131 -68 333 -136 369 -66 297 -264 427 -66 97 -130 429 -102 133 -136 203 -240 167 -236 329 -526 67 -132 133 -168 331 -360 65 -66 331 -296 267 -134 469 -132 595 -230 661 -662 299 -100 265 -200 203 -168 801 -100 133 -68 399 -132 99 -100 161 -390 65 -298 65 -98 261 -130 161 -128 257 -66 67 -134 621 -98 227 -328 99 -230 129 -294 193 -96 195 -318 425 -526 129 -196 163 -162 65 -132 293 -130 63 -66 325 -128 63 -130 293 -66 199 -200 269 -206 133 -198 325 -98 163 -100 97 -98 261 -164 67 -98 167 -430 131 -494 131 -164 -RAW_Data: 97 -98 861 -66 1199 -166 231 -100 651 -166 197 -104 439 -98 131 -64 493 -98 883 -96 99 -98 3327 -66 131 -264 733 -134 2133 -166 131 -102 303 -136 535 -134 701 -98 355 -228 131 -202 99 -134 99 -100 791 -166 169 -202 671 -100 741 -100 263 -66 165 -68 935 -132 197 -198 673 -100 605 -66 1457 -98 1195 -166 2347 -134 505 -100 1469 -66 391 -100 229 -100 1171 -98 939 -100 459 -170 369 -134 231 -162 127 -98 95 -66 195 -98 195 -66 299 -100 331 -98 65 -232 369 -132 201 -68 167 -166 1481 -102 501 -160 1257 -66 2307 -64 623 -164 2079 -66 1101 -98 423 -64 659 -68 431 -136 99 -100 435 -130 167 -168 835 -200 135 -104 133 -100 503 -68 1437 -232 821 -132 357 -96 463 -66 263 -64 683 -132 165 -96 655 -166 3939 -100 1169 -132 2443 -98 197 -132 425 -234 233 -162 1043 -66 197 -100 2793 -134 167 -104 675 -100 197 -134 1367 -102 763 -132 265 -230 133 -102 365 -100 167 -66 1069 -66 837 -100 295 -160 97 -64 129 -132 617 -164 197 -100 133 -136 337 -172 133 -66 557 -98 951 -66 263 -130 587 -66 729 -196 335 -166 933 -432 369 -100 199 -296 225 -98 355 -66 129 -64 557 -98 289 -66 355 -128 193 -162 267 -134 299 -98 165 -170 303 -640 1031 -134 99 -66 135 -68 771 -166 171 -104 201 -134 131 -68 635 -428 661 -292 749 -430 1161 -100 905 -98 65 -98 657 -262 2837 -132 67 -66 265 -132 631 -66 1037 -296 97 -98 1703 -302 367 -100 505 -232 497 -362 333 -134 591 -100 755 -232 67 -130 587 -66 231 -168 65 -332 99 -66 267 -232 393 -134 65 -132 131 -428 133 -200 165 -202 199 -168 165 -102 269 -100 333 -852 201 -134 233 -202 65 -200 563 -768 265 -136 169 -102 169 -598 333 -202 267 -134 267 -328 163 -130 625 -500 199 -200 99 -270 65 -134 65 -198 65 -100 99 -596 493 -66 99 -66 331 -232 103 -136 373 -168 831 -170 65 -672 163 -102 133 -136 331 -100 333 -234 101 -100 99 -200 99 -100 201 -302 199 -600 301 -202 135 -134 705 -166 435 -530 97 -198 131 -198 195 -66 163 -392 293 -66 295 -370 229 -198 65 -100 405 -134 165 -134 133 -170 337 -236 205 -274 267 -134 329 -132 195 -132 503 -132 133 -136 133 -334 197 -196 299 -168 101 -100 233 -100 439 -134 301 -332 331 -298 433 -406 433 -68 167 -100 203 -100 101 -102 99 -328 397 -234 205 -168 133 -364 63 -202 397 -198 95 -394 267 -134 569 -66 201 -102 133 -136 101 -102 99 -132 99 -196 197 -498 197 -102 135 -170 -RAW_Data: 331 -164 63 -162 1267 -66 163 -130 129 -66 725 -164 231 -64 853 -66 101 -134 199 -102 99 -68 365 -66 357 -130 815 -64 357 -98 97 -98 97 -66 65 -466 231 -172 3749 -66 849 -130 917 -64 327 -64 1013 -98 555 -332 795 -100 571 -132 769 -132 401 -134 1297 -134 377 -138 435 -100 401 -100 667 -100 1761 -66 667 -66 1533 -236 233 -98 885 -130 457 -66 999 -66 165 -66 833 -134 695 -166 501 -66 499 -200 329 -64 197 -134 441 -100 2099 -98 491 -134 197 -130 2225 -132 65 -100 689 -64 193 -160 159 -96 195 -98 323 -164 259 -98 535 -472 771 -66 665 -270 665 -66 595 -266 2191 -64 643 -98 1287 -98 741 -100 233 -200 569 -194 261 -68 637 -100 97 -66 491 -158 395 -138 1017 -66 627 -262 559 -64 327 -98 263 -134 99 -102 201 -102 337 -66 167 -68 679 -100 471 -134 195 -66 133 -202 693 -96 197 -98 391 -164 99 -98 3883 -194 461 -100 237 -168 1891 -68 301 -68 969 -166 1439 -294 551 -130 389 -98 99 -196 167 -102 505 -66 569 -234 901 -98 407 -136 469 -66 769 -98 769 -166 1263 -266 297 -98 1701 -200 203 -168 329 -232 65 -100 329 -164 803 -100 135 -200 233 -166 135 -272 265 -134 197 -100 133 -134 539 -232 197 -396 165 -366 263 -68 233 -102 365 -132 233 -100 135 -266 199 -234 167 -232 97 -524 127 -128 389 -98 305 -364 261 -130 257 -162 589 -464 361 -66 229 -134 161 -100 203 -432 265 -66 199 -66 199 -366 229 -236 99 -134 99 -100 131 -168 133 -100 131 -236 267 -132 297 -264 291 -132 167 -234 65 -100 199 -66 333 -730 237 -440 365 -102 99 -100 99 -132 99 -100 1429 -134 427 -100 97 -100 131 -164 799 -170 1077 -100 431 -66 133 -168 737 -134 197 -230 65 -102 803 -132 491 -98 429 -198 471 -134 365 -66 299 -236 65 -66 2837 -102 399 -64 585 -64 523 -196 97 -98 295 -196 555 -160 261 -500 299 -396 333 -236 133 -68 327 -100 199 -204 699 -66 701 -100 65 -164 65 -370 195 -196 97 -66 193 -130 129 -360 195 -130 231 -96 291 -64 455 -228 293 -196 291 -162 97 -194 621 -130 847 -66 395 -66 161 -128 193 -130 293 -98 231 -170 67 -134 297 -360 167 -266 263 -526 263 -132 229 -98 191 -160 159 -100 721 -234 101 -100 99 -130 259 -258 265 -632 687 -164 133 -134 631 -100 199 -102 165 -560 299 -200 265 -332 431 -870 99 -266 503 -364 135 -66 269 -68 499 -100 265 -102 263 -102 569 -234 719 -132 99 -196 419 -262 163 -688 95 -66 165 -128 95 -66 -RAW_Data: 295 -98 987 -196 517 -100 489 -66 355 -132 563 -198 867 -134 1413 -134 541 -134 767 -100 193 -98 1799 -102 467 -134 299 -96 323 -66 261 -100 259 -66 229 -96 851 -66 369 -266 469 -66 101 -98 163 -136 267 -432 859 -130 523 -66 197 -134 1027 -132 227 -194 393 -98 807 -166 235 -100 133 -66 165 -102 133 -136 371 -162 1411 -132 865 -200 471 -100 133 -68 299 -66 633 -98 329 -234 401 -98 1505 -132 133 -134 331 -262 163 -66 261 -98 289 -64 201 -68 1055 -96 391 -66 951 -298 265 -202 297 -66 401 -68 131 -100 1733 -98 941 -66 803 -98 847 -64 3701 -100 721 -160 357 -166 1799 -66 329 -100 99 -102 363 -198 167 -136 197 -66 567 -66 199 -236 1247 -166 2455 -68 1107 -200 235 -100 2355 -130 913 -98 877 -98 163 -196 97 -66 427 -100 801 -134 867 -98 263 -68 441 -134 561 -98 1671 -134 865 -68 935 -132 163 -102 975 -66 1343 -132 1339 -134 369 -100 1107 -66 1167 -168 631 -232 835 -66 1027 -132 333 -166 265 -98 1207 -98 223 -98 455 -64 2095 -134 933 -136 233 -68 335 -136 305 -100 1737 -66 427 -100 263 -130 323 -66 227 -66 717 -100 265 -100 65 -128 355 -66 367 -132 95 -230 229 -100 131 -64 493 -132 291 -396 393 -130 259 -196 227 -288 397 -68 229 -430 99 -302 237 -700 65 -66 65 -100 133 -200 101 -336 133 -166 237 -202 67 -302 67 -68 333 -132 263 -102 267 -296 163 -166 233 -168 363 -64 295 -298 537 -166 431 -200 431 -166 63 -258 363 -164 563 -234 199 -68 299 -100 325 -754 295 -196 65 -98 165 -132 301 -134 131 -134 97 -68 405 -68 233 -134 271 -134 67 -168 101 -136 133 -366 99 -132 67 -132 265 -200 233 -100 201 -136 101 -66 263 -132 129 -66 293 -582 263 -132 1103 -134 203 -168 97 -66 197 -264 131 -168 133 -132 65 -134 199 -134 101 -100 131 -436 99 -232 97 -398 231 -362 65 -202 301 -396 297 -98 199 -134 265 -164 101 -168 267 -102 405 -170 99 -102 397 -132 97 -98 295 -98 1179 -100 135 -136 131 -134 765 -134 465 -168 439 -232 403 -100 65 -134 931 -100 169 -136 237 -68 231 -234 199 -68 401 -134 541 -166 429 -166 1607 -368 533 -66 363 -66 133 -134 433 -166 297 -238 201 -100 201 -170 199 -134 273 -136 99 -134 167 -238 133 -66 265 -134 165 -132 165 -132 97 -228 723 -198 415 -64 491 -298 257 -66 231 -192 225 -96 227 -98 193 -96 521 -198 65 -66 231 -166 163 -98 465 -66 133 -132 195 -130 225 -162 521 -130 63 -66 199 -228 -RAW_Data: 817 -162 449 -160 719 -198 469 -68 133 -68 1101 -132 593 -230 1105 -100 131 -134 231 -66 329 -196 685 -96 557 -68 1263 -68 101 -68 397 -100 65 -66 625 -66 97 -132 1099 -66 493 -66 757 -98 1151 -66 303 -134 1901 -66 99 -100 665 -262 991 -98 791 -66 1925 -168 865 -232 835 -98 505 -102 99 -100 535 -100 169 -134 427 -132 863 -68 167 -134 975 -100 133 -268 1339 -100 1453 -66 1445 -162 195 -64 3623 -66 237 -68 1063 -308 1449 -98 1111 -132 167 -102 855 -270 199 -134 297 -134 267 -168 863 -234 637 -66 567 -230 99 -200 3325 -198 845 -66 289 -66 131 -66 815 -130 1093 -100 167 -100 429 -98 1703 -166 195 -64 971 -98 163 -192 195 -168 439 -132 329 -132 67 -134 67 -134 1591 -168 407 -100 867 -68 399 -134 661 -100 663 -66 237 -136 395 -232 131 -66 695 -100 627 -264 913 -66 1083 -98 287 -66 199 -132 335 -100 1031 -68 99 -100 3815 -98 165 -66 129 -98 163 -128 563 -98 779 -96 223 -64 161 -164 2025 -66 1741 -172 101 -136 203 -102 665 -100 475 -64 167 -100 637 -98 997 -170 1207 -136 233 -166 233 -168 635 -132 199 -100 235 -270 199 -98 131 -102 169 -170 293 -98 323 -164 427 -334 233 -168 267 -68 369 -100 263 -368 101 -66 665 -98 265 -100 133 -100 99 -168 133 -66 133 -132 133 -66 269 -134 435 -68 267 -136 271 -500 163 -100 163 -166 355 -132 97 -98 323 -194 63 -688 463 -130 97 -396 65 -100 357 -194 461 -98 161 -130 223 -162 165 -352 461 -300 267 -166 233 -464 329 -100 293 -362 163 -228 289 -66 229 -66 195 -162 325 -66 261 -98 127 -424 299 -302 367 -68 265 -272 429 -98 161 -98 393 -296 65 -130 161 -196 261 -66 473 -234 97 -98 263 -160 323 -98 67 -132 697 -298 99 -134 233 -202 97 -134 301 -200 307 -100 101 -134 865 -166 231 -202 233 -100 301 -170 169 -102 169 -200 65 -98 595 -166 231 -234 661 -66 473 -334 165 -304 365 -266 97 -502 363 -134 133 -236 65 -100 99 -134 99 -170 235 -66 333 -100 195 -100 133 -300 133 -102 301 -304 65 -100 99 -100 131 -202 135 -134 65 -200 363 -66 263 -498 67 -68 295 -194 321 -368 435 -100 97 -664 99 -100 569 -66 133 -66 67 -134 199 -136 101 -68 301 -68 405 -198 133 -132 581 -132 165 -98 159 -98 197 -66 229 -130 131 -294 133 -96 423 -100 427 -300 357 -132 291 -64 95 -194 455 -98 263 -100 359 -196 65 -162 227 -162 157 -96 157 -230 589 -132 325 -134 535 -66 267 -100 135 -302 -RAW_Data: 131 -134 599 -166 393 -98 369 -236 197 -100 401 -232 569 -134 135 -70 337 -134 101 -136 135 -100 1895 -66 401 -170 503 -66 1633 -66 601 -66 355 -96 683 -100 729 -68 133 -132 433 -68 569 -100 133 -68 201 -132 835 -100 465 -68 527 -98 193 -200 1129 -166 535 -100 199 -98 259 -132 227 -64 1597 -98 261 -192 753 -100 911 -66 667 -298 131 -100 263 -66 1051 -230 787 -66 935 -66 233 -98 885 -236 431 -66 197 -162 521 -68 167 -196 263 -96 589 -98 517 -66 1439 -64 777 -66 3219 -132 679 -134 205 -68 507 -198 749 -200 199 -168 167 -100 133 -134 201 -68 731 -66 495 -198 737 -66 237 -68 135 -100 167 -234 1535 -68 873 -66 373 -66 67 -232 297 -68 65 -66 1095 -68 327 -130 63 -132 1715 -66 2261 -100 321 -132 197 -164 457 -232 1291 -132 405 -68 1001 -68 1133 -272 471 -66 99 -134 1403 -68 167 -68 1091 -336 933 -134 1207 -132 265 -68 267 -66 99 -366 265 -66 1469 -258 367 -168 429 -132 129 -66 491 -132 343 -100 65 -100 263 -136 199 -164 273 -204 791 -100 901 -66 167 -98 165 -64 559 -132 619 -132 1087 -128 2283 -398 1467 -164 259 -130 1927 -130 421 -98 1085 -66 705 -68 1843 -168 875 -170 203 -136 341 -640 199 -66 133 -554 161 -196 63 -66 521 -292 163 -160 95 -158 127 -192 197 -100 587 -130 397 -662 261 -66 193 -130 259 -66 361 -64 459 -98 197 -560 655 -130 389 -66 1135 -100 133 -130 131 -98 1011 -100 561 -66 685 -164 457 -132 2469 -200 609 -66 665 -66 67 -132 327 -200 1657 -134 919 -132 651 -100 327 -230 191 -130 263 -358 95 -130 549 -98 99 -68 299 -100 461 -132 99 -472 165 -134 99 -66 99 -132 399 -102 169 -102 697 -166 233 -132 333 -632 197 -164 865 -266 101 -68 533 -166 299 -100 163 -228 259 -66 327 -200 65 -66 229 -100 363 -230 197 -336 165 -102 893 -300 65 -132 231 -370 265 -230 99 -98 229 -518 199 -100 401 -724 225 -98 63 -96 231 -64 291 -292 65 -98 131 -98 159 -158 127 -194 161 -292 65 -98 133 -66 297 -66 303 -168 97 -168 231 -234 269 -532 135 -168 99 -168 301 -528 99 -506 199 -368 399 -132 329 -372 99 -68 133 -264 197 -100 201 -200 67 -134 131 -270 133 -134 133 -198 327 -200 65 -100 331 -262 161 -166 469 -534 167 -738 131 -100 367 -232 101 -100 265 -604 65 -170 99 -166 299 -102 169 -132 99 -398 229 -330 197 -166 335 -366 97 -98 131 -200 269 -100 199 -168 131 -134 537 -98 265 -100 335 -236 99 -366 -RAW_Data: 459 -100 453 -130 419 -130 519 -96 63 -130 2077 -66 767 -64 127 -134 1961 -296 529 -202 637 -134 527 -100 201 -68 633 -66 163 -360 1029 -68 765 -100 867 -66 503 -100 131 -66 841 -98 165 -68 237 -66 509 -100 501 -302 235 -66 99 -164 227 -130 551 -196 327 -66 1571 -132 99 -68 867 -66 163 -96 161 -130 129 -130 549 -130 487 -166 1801 -66 229 -66 197 -232 325 -66 425 -198 131 -64 295 -166 735 -66 533 -98 227 -130 129 -262 425 -100 263 -66 129 -132 97 -168 971 -170 405 -68 199 -134 475 -202 297 -98 1445 -98 395 -196 161 -66 225 -134 1803 -100 473 -102 1499 -66 199 -100 701 -132 165 -68 133 -102 303 -98 735 -102 805 -100 827 -100 235 -100 65 -266 637 -68 693 -66 1383 -228 819 -66 233 -304 435 -198 203 -136 1135 -270 1709 -64 227 -64 581 -134 505 -66 2203 -64 293 -64 753 -66 551 -132 747 -64 1303 -64 463 -66 229 -102 1877 -266 871 -166 1357 -64 819 -66 465 -198 693 -68 165 -64 95 -128 3785 -132 1465 -100 299 -102 329 -164 595 -134 1029 -66 299 -168 1263 -166 331 -68 967 -100 101 -102 603 -260 165 -132 467 -66 233 -66 235 -102 475 -100 135 -68 301 -134 297 -98 131 -102 269 -466 99 -134 237 -166 135 -168 203 -102 265 -68 503 -66 233 -66 637 -134 101 -200 199 -166 293 -554 361 -328 367 -264 533 -238 167 -68 135 -170 99 -300 591 -298 133 -236 299 -66 231 -368 263 -232 435 -136 133 -102 133 -200 133 -134 163 -134 167 -168 299 -66 265 -100 133 -240 135 -132 263 -170 269 -200 501 -396 263 -98 227 -132 129 -292 427 -66 165 -102 627 -602 99 -66 301 -168 199 -100 563 -330 165 -134 233 -136 65 -332 499 -100 131 -232 325 -96 65 -132 195 -98 393 -624 323 -68 133 -98 195 -162 231 -100 263 -132 231 -102 133 -236 99 -236 231 -166 65 -102 133 -268 101 -102 299 -136 267 -164 493 -64 229 -258 291 -326 263 -198 391 -134 167 -202 365 -594 133 -102 201 -134 503 -396 429 -204 169 -400 197 -170 267 -132 403 -466 297 -98 469 -234 395 -132 233 -100 165 -100 165 -66 197 -68 297 -166 501 -134 133 -100 65 -166 631 -68 297 -134 199 -100 165 -68 299 -266 133 -66 165 -100 231 -490 557 -134 371 -164 299 -170 733 -164 239 -334 335 -66 299 -300 199 -170 103 -100 233 -102 641 -168 65 -100 995 -66 265 -160 259 -130 129 -226 425 -100 355 -726 97 -688 99 -66 233 -266 299 -942 167 -102 167 -166 65 -100 367 -136 99 -134 199 -134 267 -164 -RAW_Data: 67 -68 233 -66 899 -66 163 -96 485 -98 355 -130 943 -100 235 -168 499 -104 1367 -98 297 -100 635 -68 1169 -100 67 -134 835 -264 959 -164 129 -98 419 -196 589 -66 421 -66 1717 -100 133 -100 265 -134 227 -356 455 -166 163 -66 1055 -100 1455 -134 463 -98 2191 -132 295 -132 335 -66 709 -64 619 -98 959 -68 835 -170 603 -134 1033 -134 635 -168 759 -232 397 -198 397 -164 1267 -166 257 -198 1295 -100 239 -104 563 -204 335 -198 203 -68 901 -68 1255 -134 1697 -66 793 -66 1691 -68 201 -100 765 -66 165 -132 131 -230 131 -66 917 -66 335 -338 231 -170 827 -98 199 -136 301 -196 65 -98 199 -200 765 -134 403 -98 333 -68 1691 -132 2565 -64 569 -170 1255 -264 65 -132 1243 -132 2527 -66 259 -66 1739 -100 1309 -198 167 -238 337 -66 131 -68 1973 -362 299 -100 1387 -96 129 -164 423 -230 3875 -96 4283 -98 165 -98 515 -134 469 -68 171 -102 1163 -100 65 -298 461 -66 367 -136 205 -168 371 -98 491 -164 161 -262 1093 -100 299 -100 269 -334 1205 -98 63 -98 261 -64 457 -98 diff --git a/assets/unit_tests/subghz/test_random_raw.sub b/assets/unit_tests/subghz/test_random_raw.sub index 7d342bb93..928838d3c 100644 --- a/assets/unit_tests/subghz/test_random_raw.sub +++ b/assets/unit_tests/subghz/test_random_raw.sub @@ -145,18 +145,3 @@ RAW_Data: -66 133 -66 97 -166 561 -100 895 -132 1323 -66 10873 -3752 99 -722 229 RAW_Data: -5434 65 -298 133 -132 131 -68 231 -200 661 -132 9517 -424 97 -1456 99 -1694 393 -100 131 -560 131 -196 197 -298 65 -428 229 -196 297 -266 131 -166 2435 -66 10161 -11230 65 -1320 131 -298 265 -532 231 -200 1291 -68 631 -66 12645 -4048 133 -66 67 -132 167 -266 163 -66 397 -132 197 -132 299 -98 197 -198 2903 -66 2361 -66 9627 -3588 197 -332 165 -68 331 -68 197 -132 99 -100 663 -66 363 -230 231 -166 131 -100 201 -298 163 -132 133 -202 363 -300 397 -102 263 -100 165 -66 1221 -66 1479 -132 165 -98 229 -12976 263 -66 363 -134 231 -66 629 -132 327 -100 97 -130 99 -164 227 -64 297 -132 397 -164 425 -198 97 -198 99 -66 365 -164 199 -102 97 -66 1817 -13524 231 -134 16907 -4086 233 -630 65 -396 201 -66 165 -198 67 -198 99 -664 2117 -166 12473 -446 2649 -440 2661 -420 2651 -422 2681 -418 2703 -400 365 -2724 387 -2696 2695 -414 357 -2704 2707 -386 389 -2700 2687 -392 405 -2706 2695 -402 363 -21268 2707 -388 377 -2706 2691 -404 2699 -382 2717 -382 2707 -378 2693 -416 2687 -396 363 -2736 355 -2748 2659 -416 365 -2708 2715 -388 377 -2708 2697 -404 363 -2730 2673 -420 355 -21268 2655 -460 319 -2766 2663 -448 2631 -436 2665 -418 2683 -410 2681 -416 2701 -386 383 -2700 375 -2744 2669 -416 353 -2730 2685 -416 357 -2708 2721 -380 369 -2724 2697 -382 385 -21260 2701 -418 353 -2720 2673 -418 2675 -408 2693 -384 2715 -386 2717 -386 2691 -404 363 -2732 387 -2702 2669 -412 359 -2736 2699 -380 381 -2728 2675 -416 381 -2720 2675 -414 347 -21280 2685 -390 377 -2724 2689 -416 2673 -408 2705 -382 2695 -410 2689 -414 2661 -418 385 -2704 369 -2704 2693 -416 375 -2726 2661 -420 355 -2728 2711 -388 375 -2702 2691 -410 363 -21252 2659 -488 287 -2794 2651 -448 2629 -436 2671 -416 2695 -416 2663 -406 2699 -384 383 -2730 367 -2702 2695 -418 385 -2702 2685 -412 349 -2744 2693 -366 389 -2714 2693 -394 381 -21266 2685 -418 363 -2730 2683 -382 2693 -418 2675 -410 2699 -384 2719 -382 2707 -380 359 -2734 387 -2704 2709 -380 361 -2732 2699 -418 357 -2728 2667 -416 383 -2696 2709 -380 391 -21228 2685 -458 307 -2800 2647 -412 2659 -432 2667 -416 2695 -416 2675 -406 2675 -416 383 -2700 361 -2730 2687 -414 375 -2696 2701 -420 353 -2720 2711 -382 367 -2728 2675 -416 385 -21222 2735 -386 355 -2744 2687 -396 2679 -418 2701 -386 2705 -382 2681 -410 2697 -384 385 -2736 365 -2704 2715 -384 377 -2696 2697 -416 349 -2722 2707 -386 379 -2732 2671 -410 361 -21258 2681 -464 297 -2796 2629 -456 2655 -420 2661 -448 2663 -404 2695 -382 2715 -380 371 -2740 355 -2744 2679 -384 391 -2728 2675 -388 379 RAW_Data: -2728 2695 -414 357 -2704 2705 -418 357 -21262 2673 -416 383 -2696 2709 -380 2703 -384 2699 -418 2671 -408 2695 -382 2713 -386 379 -2730 357 -2732 2695 -384 383 -2730 2679 -416 357 -2708 2701 -410 349 -2736 2697 -382 385 -21252 2669 -478 289 -2790 2647 -426 2651 -444 2653 -430 2659 -418 2695 -414 2681 -402 349 -2738 383 -2722 2677 -414 347 -2744 2691 -382 369 -2730 2691 -384 383 -2734 2679 -414 347 -21264 2705 -386 379 -2736 2667 -410 2695 -382 2715 -380 2709 -420 2665 -392 2713 -382 383 -2730 365 -2728 2665 -418 383 -2696 2693 -418 357 -2710 2711 -380 375 -2718 2701 -416 357 -21238 2677 -484 311 -2766 2635 -444 2657 -420 2663 -422 2695 -416 2667 -428 2675 -396 363 -73890 133 -98 131 -132 129 -658 99 -66 853 -100 63 -100 361 -98 1589 -66 1231 -132 65 -100 297 -198 65 -132 265 -66 9857 -4672 165 -1030 97 -1394 65 -200 2687 -68 6873 -8336 99 -1156 97 -66 163 -232 163 -262 197 -132 295 -132 263 -166 953 -100 263 -130 393 -164 295 -64 329 -66 393 -164 823 -130 165 -66 6133 -8436 165 -164 265 -266 65 -362 197 -696 3181 -132 363 -98 65 -166 131 -66 399 -132 663 -396 329 -66 7335 -7578 497 -230 627 -264 99 -366 99 -132 131 -134 265 -498 163 -100 1323 -66 265 -66 1129 -100 399 -132 365 -100 795 -68 397 -98 597 -364 297 -132 361 -132 265 -132 8591 -4740 65 -100 131 -166 199 -1088 97 -296 99 -528 131 -98 661 -66 401 -198 1157 -166 361 -164 495 -100 165 -66 297 -100 1423 -66 3067 -5658 67 -6406 197 -1092 65 -530 659 -68 265 -100 991 -68 231 -230 297 -66 327 -66 131 -132 659 -134 131 -100 1183 -132 263 -98 621 -66 2075 -6976 65 -5138 67 -132 129 -664 67 -132 165 -100 331 -466 231 -68 467 -98 563 -66 231 -100 531 -66 465 -66 1023 -166 297 -134 3409 -12290 67 -164 99 -532 133 -166 263 -66 231 -66 721 -64 131 -68 959 -134 495 -100 299 -98 497 -98 365 -100 397 -232 297 -98 531 -66 3029 -12216 265 -132 99 -364 199 -234 131 -66 431 -166 333 -166 397 -132 327 -100 395 -66 197 -132 395 -66 527 -98 295 -100 97 -98 789 -132 363 -132 297 -200 2815 -4914 65 -6620 65 -462 65 -134 297 -66 497 -264 231 -198 2773 -134 365 -100 831 -166 131 -100 297 -132 861 -132 299 -100 561 -66 1381 -6946 65 -5516 231 -266 97 -1362 1093 -68 1621 -134 165 -332 297 -98 361 -228 97 -132 797 -98 3487 -13224 229 -164 65 -132 913 -66 1123 -98 527 -134 929 -98 723 -100 12259 -270 165 -132 67 -132 165 -1326 99 -98 65 -1194 431 -66 695 -66 733 -134 197 RAW_Data: -134 10801 -166 67 -6130 133 -198 231 -334 365 -98 229 -132 165 -68 231 -166 14501 -524 65 -328 131 -498 129 -1288 65 -494 163 -64 165 -66 527 -132 131 -132 1019 -198 129 -166 393 -198 65 -164 6411 -66 3255 -10642 65 -1320 165 -164 493 -492 559 -264 2555 -66 695 -66 1657 -164 855 -66 4001 -10526 97 -596 133 -298 67 -264 65 -300 65 -100 263 -166 231 -134 99 -100 2703 -68 13643 -4922 297 -100 65 -232 133 -198 331 -300 231 -66 331 -100 12047 -3872 97 -196 65 -494 329 -66 65 -890 97 -98 229 -164 195 -596 797 -66 861 -132 65 -66 231 -100 565 -66 65 -66 1297 -132 265 -66 363 -134 265 -364 297 -164 299 -134 297 -134 495 -98 11309 -3790 131 -1380 65 -758 65 -164 129 -460 65 -360 199 -100 563 -68 497 -198 363 -266 263 -100 165 -66 697 -66 1933 -13594 65 -762 1223 -132 1119 -196 361 -134 131 -100 793 -166 695 -68 231 -68 463 -66 11727 -4204 363 -264 131 -132 133 -1124 97 -100 163 -100 327 -100 331 -198 397 -66 397 -100 395 -100 163 -66 197 -564 1059 -7962 65 -100 65 -198 129 -362 99 -394 197 -296 495 -100 1357 -68 459 -66 593 -66 265 -68 301 -132 465 -66 231 -200 397 -66 397 -232 199 -298 12077 -4350 231 -796 363 -198 133 -264 65 -1132 597 -332 3295 -100 755 -98 231 -164 97 -264 459 -166 759 -164 3265 -12138 99 -232 99 -1228 1025 -100 393 -66 531 -132 693 -132 1063 -66 427 -64 297 -294 229 -98 9723 -5404 67 -466 99 -796 267 -98 201 -100 167 -264 461 -98 1415 -66 861 -66 267 -66 331 -134 1663 -66 2089 -7012 65 -100 101 -4804 431 -728 99 -100 65 -100 995 -134 165 -66 929 -100 65 -66 927 -100 1093 -168 99 -100 497 -66 665 -200 6517 -8312 165 -66 129 -66 559 -166 99 -430 65 -398 67 -66 593 -198 459 -132 261 -132 263 -130 723 -66 459 -100 325 -166 67 -198 559 -66 493 -66 11475 -3896 99 -266 99 -66 197 -1092 129 -198 361 -166 163 -98 263 -196 759 -100 265 -100 365 -630 4635 -12748 65 -1712 461 -100 497 -66 395 -98 265 -98 229 -164 529 -132 297 -66 565 -132 987 -132 8665 -2820 2265 -450 313 -2774 2643 -442 325 -2772 2665 -416 359 -2734 2667 -386 379 -21274 2657 -474 293 -2810 2619 -466 2613 -476 2629 -452 2663 -388 2683 -418 2705 -400 365 -2722 387 -2700 2697 -380 361 -2732 2691 -418 361 -2732 2667 -416 383 -2698 2697 -416 357 -21238 2715 -384 383 -2732 2685 -416 2667 -416 2695 -398 2671 -418 2687 -390 2713 -382 383 -2730 365 -2728 2661 -416 379 -2716 2685 -384 379 -2720 2703 -378 401 -2718 2671 -RAW_Data: 889 -130 325 -64 457 -560 165 -68 199 -170 67 -66 265 -132 133 -666 67 -166 431 -66 201 -98 297 -100 595 -66 199 -134 65 -100 795 -132 99 -168 501 -200 331 -132 265 -102 265 -134 423 -98 521 -226 65 -166 431 -134 99 -100 133 -464 195 -326 623 -100 673 -98 321 -200 65 -136 369 -166 65 -68 97 -166 165 -334 265 -102 231 -166 101 -170 65 -170 265 -136 931 -100 133 -134 563 -66 333 -100 427 -66 163 -390 231 -66 193 -130 461 -166 557 -100 99 -198 263 -100 197 -294 231 -232 299 -134 199 -170 267 -134 631 -98 235 -100 499 -68 463 -100 65 -134 335 -170 273 -134 297 -100 67 -66 197 -166 67 -134 301 -168 537 -470 99 -134 433 -132 199 -192 261 -100 523 -164 459 -132 259 -332 359 -64 227 -96 131 -132 687 -132 363 -136 329 -434 99 -334 133 -100 401 -132 233 -700 233 -170 337 -66 371 -68 233 -202 531 -266 731 -66 465 -100 167 -100 133 -232 335 -166 239 -102 367 -232 231 -100 167 -134 201 -136 301 -168 199 -300 231 -98 237 -134 233 -102 329 -132 261 -134 199 -66 265 -136 99 -170 167 -134 199 -166 167 -136 367 -298 197 -200 99 -166 469 -136 439 -66 303 -134 295 -100 433 -134 899 -266 363 -132 197 -160 555 -324 129 -96 97 -128 257 -132 97 -394 257 -98 195 -166 459 -332 395 -132 633 -134 301 -100 131 -332 169 -168 395 -166 263 -540 783 -100 287 -130 295 -96 225 -296 133 -98 99 -100 461 -164 545 -130 99 -66 301 -68 265 -100 235 -134 235 -70 333 -102 497 -66 233 -364 301 -170 103 -66 165 -336 733 -200 133 -100 263 -102 65 -136 465 -200 1035 -198 165 -170 67 -302 631 -100 429 -332 65 -128 129 -130 159 -128 159 -66 161 -96 325 -164 261 -100 197 -162 65 -96 99 -130 65 -102 333 -100 199 -98 389 -330 129 -128 229 -66 425 -366 229 -64 261 -100 227 -96 227 -526 301 -200 97 -66 699 -334 67 -100 399 -198 787 -98 297 -134 429 -100 3245 -64 527 -98 131 -526 633 -68 133 -302 1459 -164 971 -102 237 -136 1439 -266 1131 -66 599 -200 303 -332 325 -130 389 -166 371 -66 333 -102 65 -100 233 -234 327 -266 233 -166 297 -100 225 -130 163 -336 99 -596 199 -330 131 -66 331 -338 263 -358 197 -168 877 -66 227 -96 63 -130 263 -162 225 -290 197 -198 357 -132 297 -262 165 -456 227 -98 399 -296 95 -132 99 -98 457 -200 199 -168 535 -100 567 -134 327 -130 193 -130 683 -102 101 -132 233 -170 943 -166 827 -66 267 -102 503 -68 1325 -164 -RAW_Data: 1607 -68 233 -166 1167 -70 531 -134 335 -168 131 -66 299 -402 899 -66 461 -66 457 -98 953 -98 165 -66 293 -230 881 -64 393 -166 589 -66 289 -66 1093 -204 333 -98 2745 -132 2019 -170 925 -68 269 -102 1469 -136 2301 -68 1355 -100 527 -66 975 -68 1445 -98 2397 -100 1733 -66 703 -100 995 -100 135 -136 235 -202 167 -134 2071 -166 339 -170 201 -268 129 -66 465 -66 365 -100 197 -164 129 -98 161 -96 423 -66 675 -66 1543 -136 567 -200 767 -202 65 -100 1401 -66 623 -136 567 -234 67 -236 197 -194 97 -66 263 -66 1827 -392 1893 -98 165 -268 133 -132 231 -162 225 -98 695 -198 563 -100 301 -332 267 -102 341 -66 99 -132 1299 -130 525 -68 161 -96 357 -98 353 -100 131 -100 131 -98 163 -132 323 -100 535 -66 1323 -130 133 -66 235 -134 1497 -132 387 -98 129 -162 2623 -134 163 -68 167 -66 959 -232 495 -68 131 -134 867 -134 865 -66 333 -98 305 -134 231 -98 765 -198 397 -432 165 -66 165 -366 265 -102 541 -100 261 -162 331 -134 457 -66 491 -196 97 -266 193 -262 65 -166 231 -266 497 -360 263 -98 587 -164 259 -98 231 -66 359 -100 267 -102 271 -168 97 -262 63 -66 261 -130 227 -130 295 -164 65 -66 265 -200 597 -134 267 -170 603 -100 97 -466 231 -264 97 -168 99 -66 65 -200 199 -100 267 -404 303 -102 201 -204 235 -134 131 -198 335 -298 327 -130 291 -164 63 -162 295 -262 197 -130 95 -130 195 -96 159 -130 161 -66 231 -100 165 -66 199 -134 363 -66 267 -168 165 -168 167 -100 165 -530 363 -432 99 -232 65 -132 395 -328 229 -98 197 -132 161 -96 191 -292 197 -204 133 -100 399 -166 531 -332 235 -168 99 -66 325 -158 553 -132 129 -226 231 -134 99 -462 129 -64 289 -100 193 -66 355 -164 291 -198 131 -298 197 -198 373 -268 335 -234 427 -68 199 -132 267 -232 131 -66 783 -326 63 -162 161 -130 227 -66 259 -562 233 -464 303 -102 201 -334 301 -134 297 -198 229 -66 127 -166 99 -100 197 -198 571 -66 457 -134 361 -424 131 -328 163 -98 63 -100 505 -102 201 -1094 229 -164 65 -230 789 -236 2505 -166 201 -170 163 -64 1139 -66 927 -100 295 -198 723 -100 365 -66 459 -196 3033 -272 199 -66 499 -202 1319 -232 295 -298 131 -362 97 -164 129 -132 65 -98 197 -130 129 -98 261 -130 97 -98 229 -96 425 -66 227 -166 483 -66 163 -326 567 -68 235 -68 67 -66 167 -66 235 -330 425 -164 63 -66 427 -102 167 -66 669 -132 429 -200 65 -102 133 -100 197 -368 -RAW_Data: 65 -134 2481 -228 65 -130 229 -228 763 -136 603 -166 1619 -98 1763 -102 837 -166 321 -66 951 -130 2067 -66 259 -132 1835 -66 437 -102 701 -66 565 -68 363 -70 1113 -66 1989 -164 257 -128 351 -162 1055 -232 265 -170 309 -200 435 -166 833 -102 2467 -132 595 -66 773 -166 1615 -98 131 -96 485 -64 517 -166 197 -68 1231 -68 403 -100 263 -134 233 -100 503 -100 333 -266 729 -66 199 -100 369 -68 1239 -100 197 -68 299 -170 337 -100 825 -132 163 -66 4205 -64 161 -100 635 -66 907 -66 1017 -166 1709 -100 201 -266 657 -68 463 -166 331 -164 293 -64 259 -162 129 -262 597 -134 701 -136 67 -168 235 -136 303 -170 1417 -66 263 -98 857 -100 659 -166 97 -100 2497 -64 2495 -98 719 -128 227 -130 2217 -164 623 -264 719 -134 329 -98 1371 -100 553 -294 165 -66 1163 -100 329 -196 649 -200 1123 -68 263 -100 593 -266 333 -102 1133 -136 131 -132 603 -200 1819 -66 489 -66 563 -266 1113 -230 165 -66 423 -68 335 -100 101 -100 1073 -132 897 -100 101 -100 499 -134 173 -138 763 -238 371 -130 403 -166 203 -102 271 -136 269 -166 99 -168 263 -96 425 -66 331 -234 133 -400 231 -132 453 -66 459 -164 199 -68 237 -132 163 -198 161 -196 265 -132 65 -64 195 -130 357 -164 663 -68 167 -600 131 -98 133 -304 203 -134 433 -98 261 -130 199 -100 237 -100 229 -326 99 -98 331 -132 99 -294 165 -66 303 -134 99 -232 133 -136 99 -68 267 -198 233 -138 67 -166 367 -100 333 -168 267 -200 369 -266 135 -404 1939 -132 231 -160 161 -64 293 -98 331 -132 339 -104 135 -100 197 -430 263 -202 233 -64 195 -162 129 -64 227 -298 265 -68 697 -66 301 -68 231 -300 131 -368 769 -234 265 -98 195 -324 97 -752 229 -126 355 -98 257 -98 287 -64 427 -132 295 -262 197 -170 369 -102 267 -100 169 -68 201 -102 2551 -136 635 -134 639 -134 99 -132 197 -200 371 -66 731 -132 199 -138 733 -304 433 -68 729 -440 197 -68 99 -102 165 -266 261 -164 491 -296 489 -194 257 -164 133 -134 237 -68 335 -98 227 -130 229 -98 295 -98 231 -202 267 -236 233 -136 331 -130 195 -128 261 -430 261 -162 97 -224 99 -130 193 -96 197 -162 229 -396 97 -98 227 -364 267 -100 99 -100 233 -236 697 -164 227 -196 63 -98 327 -230 325 -66 129 -196 95 -98 195 -130 325 -430 131 -194 129 -454 161 -196 235 -68 433 -134 667 -164 355 -236 101 -98 2143 -134 1827 -198 63 -198 65 -64 2859 -64 619 -66 97 -130 3157 -66 679 -194 1491 -98 -RAW_Data: 951 -64 393 -100 955 -132 4715 -100 131 -66 199 -204 1541 -66 929 -130 1347 -166 665 -132 233 -132 67 -102 433 -100 595 -228 997 -66 505 -68 133 -98 231 -68 571 -134 1371 -232 231 -270 135 -102 97 -66 867 -100 269 -68 967 -100 1649 -66 65 -66 951 -68 65 -202 363 -200 779 -102 1449 -294 419 -130 361 -230 1079 -164 163 -260 893 -102 333 -100 533 -166 467 -100 135 -66 135 -202 369 -100 199 -100 269 -134 301 -166 229 -66 101 -134 199 -134 1293 -64 779 -62 831 -66 1243 -68 267 -102 197 -100 395 -98 455 -64 621 -132 877 -98 199 -100 2101 -134 503 -100 2035 -134 735 -236 475 -136 237 -132 133 -134 1229 -100 133 -66 167 -68 2655 -100 1807 -100 1095 -264 825 -98 163 -66 491 -98 161 -128 953 -100 773 -100 131 -66 67 -134 457 -130 63 -64 389 -98 715 -66 425 -300 97 -100 1515 -66 303 -68 99 -98 721 -64 887 -132 65 -132 165 -66 635 -68 2801 -66 1561 -100 751 -98 129 -64 725 -136 201 -100 333 -204 573 -104 1745 -134 99 -66 129 -64 595 -134 167 -102 337 -134 567 -134 1131 -138 1207 -100 269 -68 135 -100 1143 -134 2139 -68 1701 -162 991 -596 431 -66 99 -132 657 -66 391 -320 357 -260 259 -98 429 -66 163 -228 65 -130 227 -66 261 -166 99 -98 131 -366 199 -134 463 -102 201 -98 231 -102 639 -238 301 -568 169 -610 265 -102 841 -198 297 -100 335 -132 263 -266 265 -68 469 -134 267 -68 933 -298 333 -298 729 -168 135 -136 437 -132 1137 -134 199 -68 265 -132 463 -166 129 -130 227 -98 297 -98 65 -132 97 -202 199 -232 305 -66 165 -198 365 -66 99 -98 299 -170 65 -136 301 -232 99 -564 133 -132 233 -170 99 -102 131 -134 65 -204 101 -98 297 -98 167 -762 233 -298 99 -326 395 -66 299 -132 369 -504 333 -98 483 -200 457 -164 63 -164 329 -162 65 -622 231 -268 131 -132 133 -134 131 -134 131 -66 99 -100 231 -66 167 -336 165 -98 197 -100 97 -264 321 -98 521 -132 163 -130 129 -294 297 -134 101 -102 265 -168 497 -68 197 -68 499 -134 269 -398 267 -130 203 -302 65 -498 271 -136 465 -292 131 -294 163 -198 329 -96 129 -98 193 -130 391 -330 165 -134 167 -170 297 -102 133 -136 135 -366 199 -132 423 -132 395 -168 65 -166 401 -98 229 -98 329 -98 99 -130 129 -228 261 -160 127 -426 389 -162 193 -132 131 -100 231 -168 67 -304 201 -68 765 -132 161 -162 193 -64 195 -64 295 -130 787 -98 419 -528 429 -66 363 -134 131 -100 133 -200 331 -98 -RAW_Data: 431 -66 1167 -68 937 -68 1003 -66 99 -132 941 -134 65 -66 365 -274 165 -236 367 -96 557 -134 675 -66 261 -164 127 -96 391 -164 161 -98 391 -292 163 -98 519 -196 165 -98 523 -66 195 -160 3343 -66 661 -100 2589 -136 307 -100 629 -136 639 -100 133 -168 405 -100 267 -66 465 -132 1171 -64 749 -64 165 -98 983 -100 163 -202 537 -66 327 -100 669 -100 401 -236 2885 -164 439 -134 97 -426 1931 -66 1385 -98 715 -98 519 -66 289 -162 97 -360 297 -166 163 -66 289 -66 555 -334 167 -230 429 -102 267 -132 943 -136 401 -68 929 -130 193 -68 467 -198 335 -66 963 -100 597 -132 197 -260 523 -232 1115 -102 1935 -66 1395 -134 305 -100 99 -66 199 -66 1071 -66 2357 -66 367 -498 769 -234 163 -130 191 -64 1211 -200 133 -102 201 -100 561 -366 361 -98 195 -100 537 -64 165 -196 1041 -332 133 -102 441 -230 4217 -66 1033 -66 167 -66 933 -100 565 -66 331 -164 673 -104 441 -66 533 -66 2095 -164 525 -66 297 -170 965 -198 421 -100 663 -832 65 -100 331 -164 231 -166 135 -168 237 -466 761 -134 891 -196 791 -198 257 -160 161 -98 293 -66 1081 -98 229 -130 327 -66 1301 -200 331 -166 101 -66 461 -100 2619 -132 1663 -98 1609 -134 499 -332 165 -370 67 -264 97 -96 259 -98 701 -402 197 -128 527 -236 233 -102 167 -134 303 -134 99 -166 299 -132 165 -200 467 -68 305 -168 207 -102 465 -102 729 -136 101 -374 327 -96 259 -98 467 -202 65 -66 673 -98 335 -404 135 -66 339 -204 99 -366 233 -68 365 -166 133 -102 867 -198 163 -162 163 -294 463 -332 165 -68 269 -268 331 -100 131 -166 299 -132 231 -400 263 -164 131 -266 267 -264 367 -66 371 -134 229 -104 267 -232 67 -466 265 -100 101 -100 165 -200 65 -200 301 -66 199 -168 233 -98 267 -66 67 -134 261 -196 261 -234 427 -294 65 -194 193 -66 259 -132 849 -96 63 -198 167 -294 95 -98 361 -164 261 -196 131 -132 437 -100 597 -262 327 -162 295 -98 295 -164 259 -196 425 -230 321 -66 195 -66 261 -496 99 -200 529 -132 133 -966 133 -132 165 -66 63 -128 491 -402 65 -262 299 -66 299 -202 265 -100 99 -668 97 -134 65 -100 101 -66 65 -266 691 -66 431 -166 167 -134 199 -370 899 -134 99 -100 1093 -166 163 -166 399 -98 327 -100 99 -168 135 -200 133 -202 429 -98 65 -98 197 -556 65 -66 97 -326 331 -166 333 -200 135 -100 235 -234 265 -98 65 -68 135 -66 335 -66 133 -298 99 -66 233 -164 435 -232 97 -132 97 -392 -RAW_Data: 99 -198 819 -66 1235 -98 321 -132 1091 -66 1307 -98 3059 -164 3305 -64 227 -98 591 -98 129 -66 229 -98 2143 -98 939 -68 563 -100 361 -232 945 -164 257 -96 229 -230 387 -64 195 -130 981 -294 587 -162 193 -98 1337 -66 293 -98 2665 -66 297 -98 647 -66 459 -132 491 -164 489 -96 595 -66 899 -66 837 -64 1151 -196 259 -98 357 -164 891 -132 1359 -134 197 -98 97 -98 261 -64 229 -96 461 -136 693 -100 201 -98 865 -66 599 -100 517 -132 709 -66 293 -298 655 -66 197 -130 129 -66 197 -98 4291 -66 673 -66 667 -132 1473 -132 133 -104 99 -66 163 -168 333 -134 1743 -132 1097 -132 99 -68 167 -602 1323 -352 99 -166 753 -98 423 -98 97 -66 1317 -228 1309 -98 1849 -66 1939 -132 601 -100 665 -100 1875 -66 695 -132 425 -66 425 -66 263 -134 165 -134 99 -98 829 -66 601 -166 131 -102 565 -66 301 -100 1099 -100 601 -138 533 -66 667 -234 561 -66 99 -68 2741 -98 199 -100 531 -168 101 -434 1027 -68 431 -66 403 -132 99 -98 565 -132 135 -100 399 -166 271 -236 233 -166 197 -366 99 -66 99 -168 503 -66 199 -170 207 -100 673 -368 99 -66 263 -168 133 -98 397 -268 337 -66 131 -132 231 -132 501 -134 99 -168 567 -138 103 -136 267 -298 231 -134 197 -160 321 -332 231 -98 131 -164 257 -64 163 -328 395 -66 331 -202 65 -168 133 -68 167 -100 233 -102 335 -66 197 -326 1101 -132 589 -100 811 -132 399 -136 269 -102 497 -66 559 -100 129 -98 855 -68 637 -102 65 -200 875 -68 233 -166 167 -66 529 -202 235 -102 231 -66 1237 -66 733 -98 1723 -132 101 -100 297 -66 829 -232 197 -100 367 -134 169 -166 167 -434 633 -100 235 -200 131 -134 233 -100 131 -100 331 -134 495 -432 65 -528 161 -130 295 -132 337 -136 133 -166 165 -100 269 -240 201 -336 133 -166 165 -238 199 -202 431 -434 99 -134 501 -166 231 -96 559 -202 167 -66 717 -98 987 -198 65 -64 163 -64 227 -98 555 -164 199 -64 361 -66 163 -98 129 -162 97 -130 161 -460 197 -230 681 -98 197 -98 329 -100 267 -266 291 -264 65 -100 329 -100 459 -200 363 -98 165 -134 231 -134 301 -134 231 -302 99 -132 101 -134 267 -136 233 -68 393 -422 163 -166 361 -166 99 -134 365 -134 133 -336 401 -66 495 -132 401 -168 133 -402 501 -136 1093 -862 165 -132 293 -300 289 -66 131 -164 391 -134 99 -360 359 -130 323 -200 423 -98 195 -162 295 -132 161 -98 129 -782 131 -426 227 -64 259 -166 63 -160 323 -98 261 -230 -RAW_Data: 231 -66 921 -66 355 -64 1019 -98 227 -258 163 -66 597 -232 1313 -132 163 -404 467 -236 901 -164 483 -98 195 -96 489 -134 103 -238 169 -66 67 -68 299 -100 497 -68 65 -134 1635 -304 1153 -100 539 -168 265 -200 499 -166 535 -100 397 -168 931 -100 131 -66 631 -134 897 -270 1233 -100 65 -132 131 -334 663 -66 163 -66 131 -132 705 -98 571 -200 433 -100 237 -234 229 -132 1627 -66 569 -100 715 -66 1863 -272 265 -68 301 -98 465 -68 97 -134 99 -66 395 -136 1405 -66 529 -132 63 -196 579 -132 413 -260 129 -136 101 -166 1201 -134 833 -134 393 -66 335 -172 201 -68 1027 -96 753 -64 815 -66 97 -64 1341 -132 289 -160 127 -66 99 -228 1083 -96 163 -66 259 -64 159 -98 2409 -168 767 -200 367 -66 1675 -66 1067 -98 3407 -200 99 -66 1403 -166 99 -134 439 -200 329 -136 599 -66 637 -66 835 -66 1099 -98 99 -66 463 -166 165 -100 461 -164 3037 -66 655 -66 97 -98 229 -130 355 -132 1443 -66 527 -98 881 -98 229 -162 127 -96 583 -64 65 -162 489 -166 885 -194 257 -98 1539 -66 293 -166 229 -132 655 -98 757 -49522 271 -758 689 -1264 737 -670 293 -1152 811 -1144 341 -664 773 -678 327 -1118 807 -1144 835 -1146 781 -1126 873 -1096 347 -622 877 -624 321 -1106 843 -1098 871 -1098 843 -1106 379 -610 841 -584 381 -1122 365 -602 845 -1116 837 -610 381 -1056 889 -1078 383 -614 827 -1110 877 -592 353 -1108 845 -1120 839 -1120 347 -602 849 -1110 865 -612 361 -1072 869 -1114 351 -618 861 -618 343 -1090 853 -1106 387 -618 797 -674 347 -1084 389 -574 867 -584 381 -1114 841 -1102 845 -1116 839 -1112 843 -1098 875 -1086 383 -584 865 -588 375 -1100 861 -1112 851 -1084 853 -1108 847 -1106 381 -584 857 -610 383 -1080 357 -602 871 -602 385 -1084 383 -616 823 -610 373 -1086 381 -590 871 -1084 839 -628 353 -1102 875 -1100 349 -9404 875 -1060 871 -1086 887 -1088 879 -1058 863 -1086 855 -1132 845 -1078 871 -1076 857 -1098 881 -1082 861 -1088 843 -1120 853 -1074 879 -1074 879 -1068 889 -614 341 -1090 387 -616 863 -624 345 -1088 391 -590 857 -612 385 -1058 393 -596 843 -1088 889 -1078 879 -578 387 -1082 875 -1076 415 -550 881 -1070 877 -592 391 -1114 821 -1104 373 -620 821 -624 361 -1072 903 -1086 855 -1092 843 -1086 905 -1054 387 -614 863 -618 347 -1088 853 -1114 845 -1090 867 -1070 381 -610 885 -584 385 -1052 407 -578 877 -1052 899 -600 389 -1048 907 -1074 383 -586 877 -1072 877 -594 359 -1076 875 -1082 891 -1088 363 -616 855 -1084 857 -592 381 -1088 883 -1086 385 -572 -RAW_Data: 889 -624 353 -1082 853 -1096 379 -594 853 -624 353 -1092 417 -582 847 -612 385 -1076 847 -1080 883 -1052 913 -1044 907 -1076 849 -1088 383 -602 867 -616 361 -1068 901 -1072 865 -1104 831 -1080 879 -1098 397 -586 855 -626 355 -1084 381 -592 873 -616 351 -1084 385 -624 821 -620 359 -1086 387 -584 883 -1086 877 -592 355 -1106 853 -1086 387 -69570 97 -100 99 -2620 131 -636 333 -102 235 -236 67 -68 363 -66 201 -100 567 -102 267 -164 101 -134 65 -68 197 -68 297 -166 671 -100 469 -336 165 -100 201 -66 169 -230 169 -204 329 -624 67 -98 265 -232 193 -168 299 -100 235 -138 101 -370 165 -294 333 -622 231 -130 129 -130 353 -132 195 -162 359 -164 67 -68 333 -100 133 -688 235 -236 497 -198 293 -98 129 -296 293 -164 229 -128 229 -132 193 -400 165 -66 163 -98 361 -164 355 -196 587 -164 131 -98 263 -554 99 -130 129 -130 191 -464 99 -132 67 -100 167 -604 329 -66 199 -68 133 -102 163 -66 2971 -132 785 -66 329 -96 323 -100 201 -136 301 -66 1959 -166 867 -134 467 -66 297 -100 835 -100 753 -166 165 -64 67 -370 335 -66 559 -232 165 -334 65 -162 129 -354 163 -64 131 -134 265 -300 263 -132 267 -296 327 -198 99 -132 535 -132 469 -866 231 -860 99 -232 503 -134 99 -198 233 -134 267 -200 97 -358 297 -164 259 -98 227 -166 135 -66 323 -100 97 -294 131 -164 129 -98 295 -96 129 -426 299 -100 67 -102 623 -100 163 -194 127 -360 563 -134 199 -428 493 -98 229 -130 257 -64 165 -100 131 -98 163 -692 357 -64 161 -98 321 -64 389 -230 65 -692 227 -130 261 -132 231 -162 287 -298 97 -460 393 -130 301 -168 331 -100 269 -202 101 -134 201 -102 99 -132 199 -204 235 -664 65 -562 133 -328 463 -100 291 -194 159 -162 227 -98 293 -328 165 -128 227 -574 535 -332 197 -168 65 -300 131 -66 389 -1078 131 -64 259 -64 223 -98 257 -164 63 -328 433 -134 65 -602 131 -68 333 -136 369 -66 297 -264 427 -66 97 -130 429 -102 133 -136 203 -240 167 -236 329 -526 67 -132 133 -168 331 -360 65 -66 331 -296 267 -134 469 -132 595 -230 661 -662 299 -100 265 -200 203 -168 801 -100 133 -68 399 -132 99 -100 161 -390 65 -298 65 -98 261 -130 161 -128 257 -66 67 -134 621 -98 227 -328 99 -230 129 -294 193 -96 195 -318 425 -526 129 -196 163 -162 65 -132 293 -130 63 -66 325 -128 63 -130 293 -66 199 -200 269 -206 133 -198 325 -98 163 -100 97 -98 261 -164 67 -98 167 -430 131 -494 131 -164 -RAW_Data: 97 -98 861 -66 1199 -166 231 -100 651 -166 197 -104 439 -98 131 -64 493 -98 883 -96 99 -98 3327 -66 131 -264 733 -134 2133 -166 131 -102 303 -136 535 -134 701 -98 355 -228 131 -202 99 -134 99 -100 791 -166 169 -202 671 -100 741 -100 263 -66 165 -68 935 -132 197 -198 673 -100 605 -66 1457 -98 1195 -166 2347 -134 505 -100 1469 -66 391 -100 229 -100 1171 -98 939 -100 459 -170 369 -134 231 -162 127 -98 95 -66 195 -98 195 -66 299 -100 331 -98 65 -232 369 -132 201 -68 167 -166 1481 -102 501 -160 1257 -66 2307 -64 623 -164 2079 -66 1101 -98 423 -64 659 -68 431 -136 99 -100 435 -130 167 -168 835 -200 135 -104 133 -100 503 -68 1437 -232 821 -132 357 -96 463 -66 263 -64 683 -132 165 -96 655 -166 3939 -100 1169 -132 2443 -98 197 -132 425 -234 233 -162 1043 -66 197 -100 2793 -134 167 -104 675 -100 197 -134 1367 -102 763 -132 265 -230 133 -102 365 -100 167 -66 1069 -66 837 -100 295 -160 97 -64 129 -132 617 -164 197 -100 133 -136 337 -172 133 -66 557 -98 951 -66 263 -130 587 -66 729 -196 335 -166 933 -432 369 -100 199 -296 225 -98 355 -66 129 -64 557 -98 289 -66 355 -128 193 -162 267 -134 299 -98 165 -170 303 -640 1031 -134 99 -66 135 -68 771 -166 171 -104 201 -134 131 -68 635 -428 661 -292 749 -430 1161 -100 905 -98 65 -98 657 -262 2837 -132 67 -66 265 -132 631 -66 1037 -296 97 -98 1703 -302 367 -100 505 -232 497 -362 333 -134 591 -100 755 -232 67 -130 587 -66 231 -168 65 -332 99 -66 267 -232 393 -134 65 -132 131 -428 133 -200 165 -202 199 -168 165 -102 269 -100 333 -852 201 -134 233 -202 65 -200 563 -768 265 -136 169 -102 169 -598 333 -202 267 -134 267 -328 163 -130 625 -500 199 -200 99 -270 65 -134 65 -198 65 -100 99 -596 493 -66 99 -66 331 -232 103 -136 373 -168 831 -170 65 -672 163 -102 133 -136 331 -100 333 -234 101 -100 99 -200 99 -100 201 -302 199 -600 301 -202 135 -134 705 -166 435 -530 97 -198 131 -198 195 -66 163 -392 293 -66 295 -370 229 -198 65 -100 405 -134 165 -134 133 -170 337 -236 205 -274 267 -134 329 -132 195 -132 503 -132 133 -136 133 -334 197 -196 299 -168 101 -100 233 -100 439 -134 301 -332 331 -298 433 -406 433 -68 167 -100 203 -100 101 -102 99 -328 397 -234 205 -168 133 -364 63 -202 397 -198 95 -394 267 -134 569 -66 201 -102 133 -136 101 -102 99 -132 99 -196 197 -498 197 -102 135 -170 -RAW_Data: 331 -164 63 -162 1267 -66 163 -130 129 -66 725 -164 231 -64 853 -66 101 -134 199 -102 99 -68 365 -66 357 -130 815 -64 357 -98 97 -98 97 -66 65 -466 231 -172 3749 -66 849 -130 917 -64 327 -64 1013 -98 555 -332 795 -100 571 -132 769 -132 401 -134 1297 -134 377 -138 435 -100 401 -100 667 -100 1761 -66 667 -66 1533 -236 233 -98 885 -130 457 -66 999 -66 165 -66 833 -134 695 -166 501 -66 499 -200 329 -64 197 -134 441 -100 2099 -98 491 -134 197 -130 2225 -132 65 -100 689 -64 193 -160 159 -96 195 -98 323 -164 259 -98 535 -472 771 -66 665 -270 665 -66 595 -266 2191 -64 643 -98 1287 -98 741 -100 233 -200 569 -194 261 -68 637 -100 97 -66 491 -158 395 -138 1017 -66 627 -262 559 -64 327 -98 263 -134 99 -102 201 -102 337 -66 167 -68 679 -100 471 -134 195 -66 133 -202 693 -96 197 -98 391 -164 99 -98 3883 -194 461 -100 237 -168 1891 -68 301 -68 969 -166 1439 -294 551 -130 389 -98 99 -196 167 -102 505 -66 569 -234 901 -98 407 -136 469 -66 769 -98 769 -166 1263 -266 297 -98 1701 -200 203 -168 329 -232 65 -100 329 -164 803 -100 135 -200 233 -166 135 -272 265 -134 197 -100 133 -134 539 -232 197 -396 165 -366 263 -68 233 -102 365 -132 233 -100 135 -266 199 -234 167 -232 97 -524 127 -128 389 -98 305 -364 261 -130 257 -162 589 -464 361 -66 229 -134 161 -100 203 -432 265 -66 199 -66 199 -366 229 -236 99 -134 99 -100 131 -168 133 -100 131 -236 267 -132 297 -264 291 -132 167 -234 65 -100 199 -66 333 -730 237 -440 365 -102 99 -100 99 -132 99 -100 1429 -134 427 -100 97 -100 131 -164 799 -170 1077 -100 431 -66 133 -168 737 -134 197 -230 65 -102 803 -132 491 -98 429 -198 471 -134 365 -66 299 -236 65 -66 2837 -102 399 -64 585 -64 523 -196 97 -98 295 -196 555 -160 261 -500 299 -396 333 -236 133 -68 327 -100 199 -204 699 -66 701 -100 65 -164 65 -370 195 -196 97 -66 193 -130 129 -360 195 -130 231 -96 291 -64 455 -228 293 -196 291 -162 97 -194 621 -130 847 -66 395 -66 161 -128 193 -130 293 -98 231 -170 67 -134 297 -360 167 -266 263 -526 263 -132 229 -98 191 -160 159 -100 721 -234 101 -100 99 -130 259 -258 265 -632 687 -164 133 -134 631 -100 199 -102 165 -560 299 -200 265 -332 431 -870 99 -266 503 -364 135 -66 269 -68 499 -100 265 -102 263 -102 569 -234 719 -132 99 -196 419 -262 163 -688 95 -66 165 -128 95 -66 -RAW_Data: 295 -98 987 -196 517 -100 489 -66 355 -132 563 -198 867 -134 1413 -134 541 -134 767 -100 193 -98 1799 -102 467 -134 299 -96 323 -66 261 -100 259 -66 229 -96 851 -66 369 -266 469 -66 101 -98 163 -136 267 -432 859 -130 523 -66 197 -134 1027 -132 227 -194 393 -98 807 -166 235 -100 133 -66 165 -102 133 -136 371 -162 1411 -132 865 -200 471 -100 133 -68 299 -66 633 -98 329 -234 401 -98 1505 -132 133 -134 331 -262 163 -66 261 -98 289 -64 201 -68 1055 -96 391 -66 951 -298 265 -202 297 -66 401 -68 131 -100 1733 -98 941 -66 803 -98 847 -64 3701 -100 721 -160 357 -166 1799 -66 329 -100 99 -102 363 -198 167 -136 197 -66 567 -66 199 -236 1247 -166 2455 -68 1107 -200 235 -100 2355 -130 913 -98 877 -98 163 -196 97 -66 427 -100 801 -134 867 -98 263 -68 441 -134 561 -98 1671 -134 865 -68 935 -132 163 -102 975 -66 1343 -132 1339 -134 369 -100 1107 -66 1167 -168 631 -232 835 -66 1027 -132 333 -166 265 -98 1207 -98 223 -98 455 -64 2095 -134 933 -136 233 -68 335 -136 305 -100 1737 -66 427 -100 263 -130 323 -66 227 -66 717 -100 265 -100 65 -128 355 -66 367 -132 95 -230 229 -100 131 -64 493 -132 291 -396 393 -130 259 -196 227 -288 397 -68 229 -430 99 -302 237 -700 65 -66 65 -100 133 -200 101 -336 133 -166 237 -202 67 -302 67 -68 333 -132 263 -102 267 -296 163 -166 233 -168 363 -64 295 -298 537 -166 431 -200 431 -166 63 -258 363 -164 563 -234 199 -68 299 -100 325 -754 295 -196 65 -98 165 -132 301 -134 131 -134 97 -68 405 -68 233 -134 271 -134 67 -168 101 -136 133 -366 99 -132 67 -132 265 -200 233 -100 201 -136 101 -66 263 -132 129 -66 293 -582 263 -132 1103 -134 203 -168 97 -66 197 -264 131 -168 133 -132 65 -134 199 -134 101 -100 131 -436 99 -232 97 -398 231 -362 65 -202 301 -396 297 -98 199 -134 265 -164 101 -168 267 -102 405 -170 99 -102 397 -132 97 -98 295 -98 1179 -100 135 -136 131 -134 765 -134 465 -168 439 -232 403 -100 65 -134 931 -100 169 -136 237 -68 231 -234 199 -68 401 -134 541 -166 429 -166 1607 -368 533 -66 363 -66 133 -134 433 -166 297 -238 201 -100 201 -170 199 -134 273 -136 99 -134 167 -238 133 -66 265 -134 165 -132 165 -132 97 -228 723 -198 415 -64 491 -298 257 -66 231 -192 225 -96 227 -98 193 -96 521 -198 65 -66 231 -166 163 -98 465 -66 133 -132 195 -130 225 -162 521 -130 63 -66 199 -228 -RAW_Data: 817 -162 449 -160 719 -198 469 -68 133 -68 1101 -132 593 -230 1105 -100 131 -134 231 -66 329 -196 685 -96 557 -68 1263 -68 101 -68 397 -100 65 -66 625 -66 97 -132 1099 -66 493 -66 757 -98 1151 -66 303 -134 1901 -66 99 -100 665 -262 991 -98 791 -66 1925 -168 865 -232 835 -98 505 -102 99 -100 535 -100 169 -134 427 -132 863 -68 167 -134 975 -100 133 -268 1339 -100 1453 -66 1445 -162 195 -64 3623 -66 237 -68 1063 -308 1449 -98 1111 -132 167 -102 855 -270 199 -134 297 -134 267 -168 863 -234 637 -66 567 -230 99 -200 3325 -198 845 -66 289 -66 131 -66 815 -130 1093 -100 167 -100 429 -98 1703 -166 195 -64 971 -98 163 -192 195 -168 439 -132 329 -132 67 -134 67 -134 1591 -168 407 -100 867 -68 399 -134 661 -100 663 -66 237 -136 395 -232 131 -66 695 -100 627 -264 913 -66 1083 -98 287 -66 199 -132 335 -100 1031 -68 99 -100 3815 -98 165 -66 129 -98 163 -128 563 -98 779 -96 223 -64 161 -164 2025 -66 1741 -172 101 -136 203 -102 665 -100 475 -64 167 -100 637 -98 997 -170 1207 -136 233 -166 233 -168 635 -132 199 -100 235 -270 199 -98 131 -102 169 -170 293 -98 323 -164 427 -334 233 -168 267 -68 369 -100 263 -368 101 -66 665 -98 265 -100 133 -100 99 -168 133 -66 133 -132 133 -66 269 -134 435 -68 267 -136 271 -500 163 -100 163 -166 355 -132 97 -98 323 -194 63 -688 463 -130 97 -396 65 -100 357 -194 461 -98 161 -130 223 -162 165 -352 461 -300 267 -166 233 -464 329 -100 293 -362 163 -228 289 -66 229 -66 195 -162 325 -66 261 -98 127 -424 299 -302 367 -68 265 -272 429 -98 161 -98 393 -296 65 -130 161 -196 261 -66 473 -234 97 -98 263 -160 323 -98 67 -132 697 -298 99 -134 233 -202 97 -134 301 -200 307 -100 101 -134 865 -166 231 -202 233 -100 301 -170 169 -102 169 -200 65 -98 595 -166 231 -234 661 -66 473 -334 165 -304 365 -266 97 -502 363 -134 133 -236 65 -100 99 -134 99 -170 235 -66 333 -100 195 -100 133 -300 133 -102 301 -304 65 -100 99 -100 131 -202 135 -134 65 -200 363 -66 263 -498 67 -68 295 -194 321 -368 435 -100 97 -664 99 -100 569 -66 133 -66 67 -134 199 -136 101 -68 301 -68 405 -198 133 -132 581 -132 165 -98 159 -98 197 -66 229 -130 131 -294 133 -96 423 -100 427 -300 357 -132 291 -64 95 -194 455 -98 263 -100 359 -196 65 -162 227 -162 157 -96 157 -230 589 -132 325 -134 535 -66 267 -100 135 -302 -RAW_Data: 131 -134 599 -166 393 -98 369 -236 197 -100 401 -232 569 -134 135 -70 337 -134 101 -136 135 -100 1895 -66 401 -170 503 -66 1633 -66 601 -66 355 -96 683 -100 729 -68 133 -132 433 -68 569 -100 133 -68 201 -132 835 -100 465 -68 527 -98 193 -200 1129 -166 535 -100 199 -98 259 -132 227 -64 1597 -98 261 -192 753 -100 911 -66 667 -298 131 -100 263 -66 1051 -230 787 -66 935 -66 233 -98 885 -236 431 -66 197 -162 521 -68 167 -196 263 -96 589 -98 517 -66 1439 -64 777 -66 3219 -132 679 -134 205 -68 507 -198 749 -200 199 -168 167 -100 133 -134 201 -68 731 -66 495 -198 737 -66 237 -68 135 -100 167 -234 1535 -68 873 -66 373 -66 67 -232 297 -68 65 -66 1095 -68 327 -130 63 -132 1715 -66 2261 -100 321 -132 197 -164 457 -232 1291 -132 405 -68 1001 -68 1133 -272 471 -66 99 -134 1403 -68 167 -68 1091 -336 933 -134 1207 -132 265 -68 267 -66 99 -366 265 -66 1469 -258 367 -168 429 -132 129 -66 491 -132 343 -100 65 -100 263 -136 199 -164 273 -204 791 -100 901 -66 167 -98 165 -64 559 -132 619 -132 1087 -128 2283 -398 1467 -164 259 -130 1927 -130 421 -98 1085 -66 705 -68 1843 -168 875 -170 203 -136 341 -640 199 -66 133 -554 161 -196 63 -66 521 -292 163 -160 95 -158 127 -192 197 -100 587 -130 397 -662 261 -66 193 -130 259 -66 361 -64 459 -98 197 -560 655 -130 389 -66 1135 -100 133 -130 131 -98 1011 -100 561 -66 685 -164 457 -132 2469 -200 609 -66 665 -66 67 -132 327 -200 1657 -134 919 -132 651 -100 327 -230 191 -130 263 -358 95 -130 549 -98 99 -68 299 -100 461 -132 99 -472 165 -134 99 -66 99 -132 399 -102 169 -102 697 -166 233 -132 333 -632 197 -164 865 -266 101 -68 533 -166 299 -100 163 -228 259 -66 327 -200 65 -66 229 -100 363 -230 197 -336 165 -102 893 -300 65 -132 231 -370 265 -230 99 -98 229 -518 199 -100 401 -724 225 -98 63 -96 231 -64 291 -292 65 -98 131 -98 159 -158 127 -194 161 -292 65 -98 133 -66 297 -66 303 -168 97 -168 231 -234 269 -532 135 -168 99 -168 301 -528 99 -506 199 -368 399 -132 329 -372 99 -68 133 -264 197 -100 201 -200 67 -134 131 -270 133 -134 133 -198 327 -200 65 -100 331 -262 161 -166 469 -534 167 -738 131 -100 367 -232 101 -100 265 -604 65 -170 99 -166 299 -102 169 -132 99 -398 229 -330 197 -166 335 -366 97 -98 131 -200 269 -100 199 -168 131 -134 537 -98 265 -100 335 -236 99 -366 -RAW_Data: 459 -100 453 -130 419 -130 519 -96 63 -130 2077 -66 767 -64 127 -134 1961 -296 529 -202 637 -134 527 -100 201 -68 633 -66 163 -360 1029 -68 765 -100 867 -66 503 -100 131 -66 841 -98 165 -68 237 -66 509 -100 501 -302 235 -66 99 -164 227 -130 551 -196 327 -66 1571 -132 99 -68 867 -66 163 -96 161 -130 129 -130 549 -130 487 -166 1801 -66 229 -66 197 -232 325 -66 425 -198 131 -64 295 -166 735 -66 533 -98 227 -130 129 -262 425 -100 263 -66 129 -132 97 -168 971 -170 405 -68 199 -134 475 -202 297 -98 1445 -98 395 -196 161 -66 225 -134 1803 -100 473 -102 1499 -66 199 -100 701 -132 165 -68 133 -102 303 -98 735 -102 805 -100 827 -100 235 -100 65 -266 637 -68 693 -66 1383 -228 819 -66 233 -304 435 -198 203 -136 1135 -270 1709 -64 227 -64 581 -134 505 -66 2203 -64 293 -64 753 -66 551 -132 747 -64 1303 -64 463 -66 229 -102 1877 -266 871 -166 1357 -64 819 -66 465 -198 693 -68 165 -64 95 -128 3785 -132 1465 -100 299 -102 329 -164 595 -134 1029 -66 299 -168 1263 -166 331 -68 967 -100 101 -102 603 -260 165 -132 467 -66 233 -66 235 -102 475 -100 135 -68 301 -134 297 -98 131 -102 269 -466 99 -134 237 -166 135 -168 203 -102 265 -68 503 -66 233 -66 637 -134 101 -200 199 -166 293 -554 361 -328 367 -264 533 -238 167 -68 135 -170 99 -300 591 -298 133 -236 299 -66 231 -368 263 -232 435 -136 133 -102 133 -200 133 -134 163 -134 167 -168 299 -66 265 -100 133 -240 135 -132 263 -170 269 -200 501 -396 263 -98 227 -132 129 -292 427 -66 165 -102 627 -602 99 -66 301 -168 199 -100 563 -330 165 -134 233 -136 65 -332 499 -100 131 -232 325 -96 65 -132 195 -98 393 -624 323 -68 133 -98 195 -162 231 -100 263 -132 231 -102 133 -236 99 -236 231 -166 65 -102 133 -268 101 -102 299 -136 267 -164 493 -64 229 -258 291 -326 263 -198 391 -134 167 -202 365 -594 133 -102 201 -134 503 -396 429 -204 169 -400 197 -170 267 -132 403 -466 297 -98 469 -234 395 -132 233 -100 165 -100 165 -66 197 -68 297 -166 501 -134 133 -100 65 -166 631 -68 297 -134 199 -100 165 -68 299 -266 133 -66 165 -100 231 -490 557 -134 371 -164 299 -170 733 -164 239 -334 335 -66 299 -300 199 -170 103 -100 233 -102 641 -168 65 -100 995 -66 265 -160 259 -130 129 -226 425 -100 355 -726 97 -688 99 -66 233 -266 299 -942 167 -102 167 -166 65 -100 367 -136 99 -134 199 -134 267 -164 -RAW_Data: 67 -68 233 -66 899 -66 163 -96 485 -98 355 -130 943 -100 235 -168 499 -104 1367 -98 297 -100 635 -68 1169 -100 67 -134 835 -264 959 -164 129 -98 419 -196 589 -66 421 -66 1717 -100 133 -100 265 -134 227 -356 455 -166 163 -66 1055 -100 1455 -134 463 -98 2191 -132 295 -132 335 -66 709 -64 619 -98 959 -68 835 -170 603 -134 1033 -134 635 -168 759 -232 397 -198 397 -164 1267 -166 257 -198 1295 -100 239 -104 563 -204 335 -198 203 -68 901 -68 1255 -134 1697 -66 793 -66 1691 -68 201 -100 765 -66 165 -132 131 -230 131 -66 917 -66 335 -338 231 -170 827 -98 199 -136 301 -196 65 -98 199 -200 765 -134 403 -98 333 -68 1691 -132 2565 -64 569 -170 1255 -264 65 -132 1243 -132 2527 -66 259 -66 1739 -100 1309 -198 167 -238 337 -66 131 -68 1973 -362 299 -100 1387 -96 129 -164 423 -230 3875 -96 4283 -98 165 -98 515 -134 469 -68 171 -102 1163 -100 65 -298 461 -66 367 -136 205 -168 371 -98 491 -164 161 -262 1093 -100 299 -100 269 -334 1205 -98 63 -98 261 -64 457 -98 diff --git a/documentation/AppManifests.md b/documentation/AppManifests.md index c7c73110b..f4814ee5d 100644 --- a/documentation/AppManifests.md +++ b/documentation/AppManifests.md @@ -76,10 +76,10 @@ Each library is defined as a call to `Lib()` function, accepting the following p - **name**: name of library's folder. Required. - **fap_include_paths**: list of library's relative paths to add to parent fap's include path list. Default value is `["."]` meaning library's source root. - - **sources**: list of filename masks to be used for gathering include files for this library. Default value is `["*.c*"]`. + - **sources**: list of filename masks to be used for gathering include files for this library. Paths are relative to library's source root. Default value is `["*.c*"]`. - **cflags**: list of additional compiler flags to be used for building this library. Default value is `[]`. - **cdefines**: list of additional preprocessor definitions to be used for building this library. Default value is `[]`. - - **cincludes**: list of additional include paths to be used for building this library. Can be used for providing external search paths for this library's code - for configuration headers. Default value is `[]`. + - **cincludes**: list of additional include paths to be used for building this library. Paths are relative to application's root. Can be used for providing external search paths for this library's code - for configuration headers. Default value is `[]`. Example for building an app with a private library: diff --git a/documentation/UniversalRemotes.md b/documentation/UniversalRemotes.md index 3dd82c615..0a833727e 100644 --- a/documentation/UniversalRemotes.md +++ b/documentation/UniversalRemotes.md @@ -1,4 +1,18 @@ # Universal Remotes +## Audio Players +### Recording signals +Adding your audio player to the universal remote is quite straightforward. 8 signals can be recorded: `Power`, `Play`, `Pause`, `Vol_up`, `Vol_dn`, `Next`, `Prev`, `Mute`. Any of them can be omitted if it is not supported by the device. + +The signal names are self-explanatory. +On many remotes, the `Play` button doubles as `Pause`. In this case record it as `Play` omitting the `Pause`. +Make sure that every signal does what it's supposed to. + +If everything checks out, append these signals **to the end** of the [Audio players universal remote file](/assets/resources/infrared/assets/audio.ir). + +The order of signals is not important, but they must be preceded by a following comment: `# Model: ` in order to keep the library organised. + +When done, open a pull request containing the changed file. + ## Air Conditioners ### Recording signals Air conditioners differ from most other infrared-controlled devices because their state is tracked by the remote. @@ -31,7 +45,7 @@ Finally, record the `Off` signal: 4. Save the resulting signal under the name `Off`. The resulting remote file should now contain 6 signals. Any of them can be omitted, but that will mean that this functionality will not be used. -Test the file against the actual device. Every signal must do what it's supposed to. +Test the file against the actual device. Make sure that every signal does what it's supposed to. If everything checks out, append these signals **to the end** of the [A/C universal remote file](/assets/resources/infrared/assets/ac.ir). diff --git a/documentation/fbt.md b/documentation/fbt.md index 3fac7ce75..2bf9ea28e 100644 --- a/documentation/fbt.md +++ b/documentation/fbt.md @@ -54,6 +54,7 @@ To run cleanup (think of `make clean`) for specified targets, add `-c` option. - `blackmagic` - debug firmware with Blackmagic probe (WiFi dev board) - `openocd` - just start OpenOCD - `get_blackmagic` - output blackmagic address in gdb remote format. Useful for IDE integration +- `get_stlink` - output serial numbers for attached STLink probes. Used for specifying an adapter with `OPENOCD_ADAPTER_SERIAL=...`. - `lint`, `format` - run clang-format on C source code to check and reformat it according to `.clang-format` specs - `lint_py`, `format_py` - run [black](https://black.readthedocs.io/en/stable/index.html) on Python source code, build system files & application manifests - `cli` - start Flipper CLI session over USB diff --git a/fbt b/fbt index 981489dd1..e576f37ac 100755 --- a/fbt +++ b/fbt @@ -7,6 +7,7 @@ set -eu; # private variables SCRIPT_PATH="$(cd "$(dirname "$0")" && pwd -P)"; SCONS_DEFAULT_FLAGS="-Q --warn=target-not-built"; +SCONS_EP="python3 -m SCons" # public variables FBT_NOENV="${FBT_NOENV:-""}"; @@ -25,4 +26,4 @@ if [ -z "$FBT_NO_SYNC" ]; then git submodule update --init; fi -python3 "$SCRIPT_PATH/lib/scons/scripts/scons.py" $SCONS_DEFAULT_FLAGS "$@" +$SCONS_EP $SCONS_DEFAULT_FLAGS "$@" diff --git a/fbt.cmd b/fbt.cmd index f09b98382..197f2359c 100644 --- a/fbt.cmd +++ b/fbt.cmd @@ -1,7 +1,7 @@ @echo off call "%~dp0scripts\toolchain\fbtenv.cmd" env -set SCONS_EP=%~dp0\lib\scons\scripts\scons.py +set SCONS_EP=python -m SCons if [%FBT_NO_SYNC%] == [] ( if exist ".git" ( @@ -13,4 +13,4 @@ if [%FBT_NO_SYNC%] == [] ( ) set "SCONS_DEFAULT_FLAGS=-Q --warn=target-not-built" -python lib\scons\scripts\scons.py %SCONS_DEFAULT_FLAGS% %* +%SCONS_EP% %SCONS_DEFAULT_FLAGS% %* diff --git a/fbt_options.py b/fbt_options.py index 716f99fdf..6ef9759e3 100644 --- a/fbt_options.py +++ b/fbt_options.py @@ -52,8 +52,6 @@ OPENOCD_OPTS = [ "debug/stm32wbx.cfg", "-c", "stm32wbx.cpu configure -rtos auto", - "-c", - "init", ] SVD_FILE = "debug/STM32WB55_CM4.svd" diff --git a/firmware.scons b/firmware.scons index 5219a2f3b..63a1aa3f7 100644 --- a/firmware.scons +++ b/firmware.scons @@ -86,21 +86,6 @@ env.AddMethod(ApplyLibFlags) Export("env") -if not env["VERBOSE"]: - env.SetDefault( - HEXCOMSTR="\tHEX\t${TARGET}", - BINCOMSTR="\tBIN\t${TARGET}", - DFUCOMSTR="\tDFU\t${TARGET}", - SDK_PREGEN_COMSTR="\tPREGEN\t${TARGET}", - SDK_COMSTR="\tSDKSRC\t${TARGET}", - SDKSYM_UPDATER_COMSTR="\tSDKCHK\t${TARGET}", - SDKSYM_GENERATOR_COMSTR="\tSDKSYM\t${TARGET}", - APPMETA_COMSTR="\tAPPMETA\t${TARGET}", - APPMETAEMBED_COMSTR="\tFAP\t${TARGET}", - APPCHECK_COMSTR="\tAPPCHK\t${SOURCE}", - ) - - if env["IS_BASE_FIRMWARE"]: env.Append( FIRMWARE_BUILD_CFG="firmware", @@ -149,9 +134,10 @@ fwenv.LoadApplicationManifests() fwenv.PrepareApplicationsBuild() # Build external apps -extapps = fwenv["FW_EXTAPPS"] = SConscript( - "site_scons/extapps.scons", exports={"ENV": fwenv} -) +if env["IS_BASE_FIRMWARE"]: + extapps = fwenv["FW_EXTAPPS"] = SConscript( + "site_scons/extapps.scons", exports={"ENV": fwenv} + ) # Add preprocessor definitions for current set of apps @@ -192,23 +178,6 @@ sources.extend( ) ) - -fwenv.AppendUnique( - LINKFLAGS=[ - "-specs=nano.specs", - "-specs=nosys.specs", - "-Wl,--gc-sections", - "-Wl,--undefined=uxTopUsedPriority", - "-Wl,--wrap,_malloc_r", - "-Wl,--wrap,_free_r", - "-Wl,--wrap,_calloc_r", - "-Wl,--wrap,_realloc_r", - "-n", - "-Xlinker", - "-Map=${TARGET}.map", - ], -) - # Debug # print(fwenv.Dump()) @@ -306,21 +275,10 @@ Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_all", fw_artifacts) if fwenv["IS_BASE_FIRMWARE"]: sdk_source = fwenv.SDKPrebuilder( "sdk_origin", - [], - # Filtering out things cxxheaderparser cannot handle - SDK_PP_FLAGS=[ - '-D"_Static_assert(x,y)="', - '-D"__asm__(x)="', - '-D"__attribute__(x)="', - "-Drestrict=", - "-D_Noreturn=", - "-D__restrict=", - "-D__extension__=", - "-D__inline=inline", - "-D__inline__=inline", - ], + # Deps on root SDK headers and generated files + (fwenv["SDK_HEADERS"], fwenv["FW_ASSETS_HEADERS"]), ) - # Depends(sdk_source, (fwenv["SDK_HEADERS"], fwenv["FW_ASSETS_HEADERS"])) + # Extra deps on headers included in deeper levels Depends(sdk_source, fwenv.ProcessSdkDepends("sdk_origin.d")) fwenv["SDK_DIR"] = fwenv.Dir("sdk") diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 55671641c..2e7cc07cf 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,3.6,, +Version,+,7.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -260,6 +260,8 @@ Function,-,__eprintf,void,"const char*, const char*, unsigned int, const char*" Function,+,__errno,int*, Function,-,__fpclassifyd,int,double Function,-,__fpclassifyf,int,float +Function,+,__furi_crash,void, +Function,+,__furi_halt,void, Function,-,__getdelim,ssize_t,"char**, size_t*, int, FILE*" Function,-,__getline,ssize_t,"char**, size_t*, FILE*" Function,-,__isinfd,int,double @@ -891,7 +893,6 @@ Function,-,ftello,off_t,FILE* Function,-,ftrylockfile,int,FILE* Function,-,funlockfile,void,FILE* Function,-,funopen,FILE*,"const void*, int (*)(void*, char*, int), int (*)(void*, const char*, int), fpos_t (*)(void*, fpos_t, int), int (*)(void*)" -Function,+,furi_crash,void,const char* Function,+,furi_delay_ms,void,uint32_t Function,+,furi_delay_tick,void,uint32_t Function,+,furi_delay_until_tick,FuriStatus,uint32_t @@ -1308,7 +1309,6 @@ Function,+,furi_hal_version_uid,const uint8_t*, Function,+,furi_hal_version_uid_size,size_t, Function,-,furi_hal_vibro_init,void, Function,+,furi_hal_vibro_on,void,_Bool -Function,+,furi_halt,void,const char* Function,-,furi_init,void, Function,+,furi_kernel_get_tick_frequency,uint32_t, Function,+,furi_kernel_lock,int32_t, @@ -2272,21 +2272,26 @@ Function,-,subghz_keystore_raw_encrypted_save,_Bool,"const char*, const char*, u Function,-,subghz_keystore_raw_get_data,_Bool,"const char*, size_t, uint8_t*, size_t" Function,-,subghz_keystore_save,_Bool,"SubGhzKeystore*, const char*, uint8_t*" Function,+,subghz_protocol_blocks_add_bit,void,"SubGhzBlockDecoder*, uint8_t" -Function,+,subghz_protocol_blocks_crc16,uint16_t,"const uint8_t[], unsigned, uint16_t, uint16_t" -Function,+,subghz_protocol_blocks_crc16lsb,uint16_t,"const uint8_t[], unsigned, uint16_t, uint16_t" -Function,+,subghz_protocol_blocks_crc4,uint8_t,"const uint8_t[], unsigned, uint8_t, uint8_t" -Function,+,subghz_protocol_blocks_crc7,uint8_t,"const uint8_t[], unsigned, uint8_t, uint8_t" -Function,+,subghz_protocol_blocks_crc8,uint8_t,"const uint8_t[], unsigned, uint8_t, uint8_t" -Function,+,subghz_protocol_blocks_crc8le,uint8_t,"const uint8_t[], unsigned, uint8_t, uint8_t" +Function,+,subghz_protocol_blocks_add_bytes,uint8_t,"const uint8_t[], size_t" +Function,+,subghz_protocol_blocks_add_to_128_bit,void,"SubGhzBlockDecoder*, uint8_t, uint64_t*" +Function,+,subghz_protocol_blocks_crc16,uint16_t,"const uint8_t[], size_t, uint16_t, uint16_t" +Function,+,subghz_protocol_blocks_crc16lsb,uint16_t,"const uint8_t[], size_t, uint16_t, uint16_t" +Function,+,subghz_protocol_blocks_crc4,uint8_t,"const uint8_t[], size_t, uint8_t, uint8_t" +Function,+,subghz_protocol_blocks_crc7,uint8_t,"const uint8_t[], size_t, uint8_t, uint8_t" +Function,+,subghz_protocol_blocks_crc8,uint8_t,"const uint8_t[], size_t, uint8_t, uint8_t" +Function,+,subghz_protocol_blocks_crc8le,uint8_t,"const uint8_t[], size_t, uint8_t, uint8_t" Function,+,subghz_protocol_blocks_get_bit_array,_Bool,"uint8_t[], size_t" Function,+,subghz_protocol_blocks_get_hash_data,uint8_t,"SubGhzBlockDecoder*, size_t" Function,+,subghz_protocol_blocks_get_parity,uint8_t,"uint64_t, uint8_t" Function,+,subghz_protocol_blocks_get_upload,size_t,"uint8_t[], size_t, LevelDuration*, size_t, uint32_t" -Function,+,subghz_protocol_blocks_lfsr_digest16,uint16_t,"const uint8_t[], unsigned, uint16_t, uint16_t" -Function,+,subghz_protocol_blocks_lfsr_digest8,uint8_t,"const uint8_t[], unsigned, uint8_t, uint8_t" -Function,+,subghz_protocol_blocks_lfsr_digest8_reflect,uint8_t,"const uint8_t[], int, uint8_t, uint8_t" +Function,+,subghz_protocol_blocks_lfsr_digest16,uint16_t,"const uint8_t[], size_t, uint16_t, uint16_t" +Function,+,subghz_protocol_blocks_lfsr_digest8,uint8_t,"const uint8_t[], size_t, uint8_t, uint8_t" +Function,+,subghz_protocol_blocks_lfsr_digest8_reflect,uint8_t,"const uint8_t[], size_t, uint8_t, uint8_t" +Function,+,subghz_protocol_blocks_parity8,uint8_t,uint8_t +Function,+,subghz_protocol_blocks_parity_bytes,uint8_t,"const uint8_t[], size_t" Function,+,subghz_protocol_blocks_reverse_key,uint64_t,"uint64_t, uint8_t" Function,+,subghz_protocol_blocks_set_bit_array,void,"_Bool, uint8_t[], size_t, size_t" +Function,+,subghz_protocol_blocks_xor_bytes,uint8_t,"const uint8_t[], size_t" Function,-,subghz_protocol_decoder_base_deserialize,_Bool,"SubGhzProtocolDecoderBase*, FlipperFormat*" Function,+,subghz_protocol_decoder_base_get_hash_data,uint8_t,SubGhzProtocolDecoderBase* Function,+,subghz_protocol_decoder_base_get_string,_Bool,"SubGhzProtocolDecoderBase*, FuriString*" @@ -2307,6 +2312,7 @@ Function,+,subghz_protocol_raw_file_encoder_worker_set_callback_end,void,"SubGhz Function,+,subghz_protocol_raw_gen_fff_data,void,"FlipperFormat*, const char*" Function,+,subghz_protocol_raw_get_sample_write,size_t,SubGhzProtocolDecoderRAW* Function,+,subghz_protocol_raw_save_to_file_init,_Bool,"SubGhzProtocolDecoderRAW*, const char*, SubGhzRadioPreset*" +Function,+,subghz_protocol_raw_save_to_file_pause,void,"SubGhzProtocolDecoderRAW*, _Bool" Function,+,subghz_protocol_raw_save_to_file_stop,void,SubGhzProtocolDecoderRAW* Function,+,subghz_receiver_alloc_init,SubGhzReceiver*,SubGhzEnvironment* Function,+,subghz_receiver_decode,void,"SubGhzReceiver*, _Bool, uint32_t" @@ -2656,189 +2662,7 @@ Function,-,yn,double,"int, double" Function,-,ynf,float,"int, float" Variable,-,AHBPrescTable,const uint32_t[16], Variable,-,APBPrescTable,const uint32_t[8], -Variable,+,A_125khz_14,const Icon, -Variable,+,A_BadUsb_14,const Icon, -Variable,+,A_Debug_14,const Icon, -Variable,+,A_FileManager_14,const Icon, -Variable,+,A_GPIO_14,const Icon, -Variable,+,A_Infrared_14,const Icon, -Variable,+,A_Levelup1_128x64,const Icon, -Variable,+,A_Levelup2_128x64,const Icon, -Variable,+,A_Loading_24,const Icon, -Variable,+,A_NFC_14,const Icon, -Variable,+,A_Plugins_14,const Icon, -Variable,+,A_Round_loader_8x8,const Icon, -Variable,+,A_Settings_14,const Icon, -Variable,+,A_Sub1ghz_14,const Icon, -Variable,+,A_U2F_14,const Icon, -Variable,+,A_iButton_14,const Icon, Variable,-,ITM_RxBuffer,volatile int32_t, -Variable,+,I_125_10px,const Icon, -Variable,+,I_ActiveConnection_50x64,const Icon, -Variable,+,I_ArrowC_1_36x36,const Icon, -Variable,+,I_ArrowDownEmpty_14x15,const Icon, -Variable,+,I_ArrowDownFilled_14x15,const Icon, -Variable,+,I_ArrowUpEmpty_14x15,const Icon, -Variable,+,I_ArrowUpFilled_14x15,const Icon, -Variable,+,I_Attention_5x8,const Icon, -Variable,+,I_Auth_62x31,const Icon, -Variable,+,I_BLE_Pairing_128x64,const Icon, -Variable,+,I_Background_128x11,const Icon, -Variable,+,I_BatteryBody_52x28,const Icon, -Variable,+,I_Battery_16x16,const Icon, -Variable,+,I_Battery_26x8,const Icon, -Variable,+,I_Ble_connected_15x15,const Icon, -Variable,+,I_Ble_disconnected_15x15,const Icon, -Variable,+,I_Bluetooth_Connected_16x8,const Icon, -Variable,+,I_Bluetooth_Idle_5x8,const Icon, -Variable,+,I_ButtonCenter_7x7,const Icon, -Variable,+,I_ButtonDown_7x4,const Icon, -Variable,+,I_ButtonLeftSmall_3x5,const Icon, -Variable,+,I_ButtonLeft_4x7,const Icon, -Variable,+,I_ButtonRightSmall_3x5,const Icon, -Variable,+,I_ButtonRight_4x7,const Icon, -Variable,+,I_ButtonUp_7x4,const Icon, -Variable,+,I_Button_18x18,const Icon, -Variable,+,I_Certification1_103x56,const Icon, -Variable,+,I_Certification2_98x33,const Icon, -Variable,+,I_Charging_lightning_9x10,const Icon, -Variable,+,I_Charging_lightning_mask_9x10,const Icon, -Variable,+,I_Circles_47x47,const Icon, -Variable,+,I_Clock_18x18,const Icon, -Variable,+,I_Connect_me_62x31,const Icon, -Variable,+,I_Connected_62x31,const Icon, -Variable,+,I_CoolHi_25x27,const Icon, -Variable,+,I_CoolHi_hvr_25x27,const Icon, -Variable,+,I_CoolLo_25x27,const Icon, -Variable,+,I_CoolLo_hvr_25x27,const Icon, -Variable,+,I_Cry_dolph_55x52,const Icon, -Variable,+,I_DFU_128x50,const Icon, -Variable,+,I_Dehumidify_25x27,const Icon, -Variable,+,I_Dehumidify_hvr_25x27,const Icon, -Variable,+,I_Detailed_chip_17x13,const Icon, -Variable,+,I_DolphinCommon_56x48,const Icon, -Variable,+,I_DolphinMafia_115x62,const Icon, -Variable,+,I_DolphinNice_96x59,const Icon, -Variable,+,I_DolphinReadingSuccess_59x63,const Icon, -Variable,+,I_DolphinWait_61x59,const Icon, -Variable,+,I_DoorLeft_70x55,const Icon, -Variable,+,I_DoorRight_70x55,const Icon, -Variable,+,I_Down_25x27,const Icon, -Variable,+,I_Down_hvr_25x27,const Icon, -Variable,+,I_Drive_112x35,const Icon, -Variable,+,I_Error_18x18,const Icon, -Variable,+,I_Error_62x31,const Icon, -Variable,+,I_EviSmile1_18x21,const Icon, -Variable,+,I_EviSmile2_18x21,const Icon, -Variable,+,I_EviWaiting1_18x21,const Icon, -Variable,+,I_EviWaiting2_18x21,const Icon, -Variable,+,I_FaceCharging_29x14,const Icon, -Variable,+,I_FaceConfused_29x14,const Icon, -Variable,+,I_FaceNopower_29x14,const Icon, -Variable,+,I_FaceNormal_29x14,const Icon, -Variable,+,I_GameMode_11x8,const Icon, -Variable,+,I_Health_16x16,const Icon, -Variable,+,I_HeatHi_25x27,const Icon, -Variable,+,I_HeatHi_hvr_25x27,const Icon, -Variable,+,I_HeatLo_25x27,const Icon, -Variable,+,I_HeatLo_hvr_25x27,const Icon, -Variable,+,I_InfraredArrowDown_4x8,const Icon, -Variable,+,I_InfraredArrowUp_4x8,const Icon, -Variable,+,I_InfraredLearnShort_128x31,const Icon, -Variable,+,I_KeyBackspaceSelected_16x9,const Icon, -Variable,+,I_KeyBackspace_16x9,const Icon, -Variable,+,I_KeySaveSelected_24x11,const Icon, -Variable,+,I_KeySave_24x11,const Icon, -Variable,+,I_Keychain_39x36,const Icon, -Variable,+,I_Left_mouse_icon_9x9,const Icon, -Variable,+,I_Lock_7x8,const Icon, -Variable,+,I_Lock_8x8,const Icon, -Variable,+,I_MHz_25x11,const Icon, -Variable,+,I_Medium_chip_22x21,const Icon, -Variable,+,I_Modern_reader_18x34,const Icon, -Variable,+,I_Move_flipper_26x39,const Icon, -Variable,+,I_Mute_25x27,const Icon, -Variable,+,I_Mute_hvr_25x27,const Icon, -Variable,+,I_NFC_manual_60x50,const Icon, -Variable,+,I_Nfc_10px,const Icon, -Variable,+,I_Off_25x27,const Icon, -Variable,+,I_Off_hvr_25x27,const Icon, -Variable,+,I_Ok_btn_9x9,const Icon, -Variable,+,I_Ok_btn_pressed_13x13,const Icon, -Variable,+,I_Percent_10x14,const Icon, -Variable,+,I_Pin_arrow_down_7x9,const Icon, -Variable,+,I_Pin_arrow_left_9x7,const Icon, -Variable,+,I_Pin_arrow_right_9x7,const Icon, -Variable,+,I_Pin_arrow_up_7x9,const Icon, -Variable,+,I_Pin_attention_dpad_29x29,const Icon, -Variable,+,I_Pin_back_arrow_10x8,const Icon, -Variable,+,I_Pin_back_full_40x8,const Icon, -Variable,+,I_Pin_pointer_5x3,const Icon, -Variable,+,I_Pin_star_7x7,const Icon, -Variable,+,I_Power_25x27,const Icon, -Variable,+,I_Power_hvr_25x27,const Icon, -Variable,+,I_Pressed_Button_13x13,const Icon, -Variable,+,I_Quest_7x8,const Icon, -Variable,+,I_RFIDBigChip_37x36,const Icon, -Variable,+,I_RFIDDolphinReceive_97x61,const Icon, -Variable,+,I_RFIDDolphinSend_97x61,const Icon, -Variable,+,I_RFIDDolphinSuccess_108x57,const Icon, -Variable,+,I_Reader_detect_43x40,const Icon, -Variable,+,I_Release_arrow_18x15,const Icon, -Variable,+,I_Restoring_38x32,const Icon, -Variable,+,I_Right_mouse_icon_9x9,const Icon, -Variable,+,I_SDQuestion_35x43,const Icon, -Variable,+,I_SDcardFail_11x8,const Icon, -Variable,+,I_SDcardMounted_11x8,const Icon, -Variable,+,I_Scanning_123x52,const Icon, -Variable,+,I_SmallArrowDown_3x5,const Icon, -Variable,+,I_SmallArrowDown_4x7,const Icon, -Variable,+,I_SmallArrowUp_3x5,const Icon, -Variable,+,I_SmallArrowUp_4x7,const Icon, -Variable,+,I_Smile_18x18,const Icon, -Variable,+,I_Space_65x18,const Icon, -Variable,+,I_Tap_reader_36x38,const Icon, -Variable,+,I_Temperature_16x16,const Icon, -Variable,+,I_Unlock_7x8,const Icon, -Variable,+,I_Unplug_bg_bottom_128x10,const Icon, -Variable,+,I_Unplug_bg_top_128x14,const Icon, -Variable,+,I_Up_25x27,const Icon, -Variable,+,I_Up_hvr_25x27,const Icon, -Variable,+,I_Updating_32x40,const Icon, -Variable,+,I_UsbTree_48x22,const Icon, -Variable,+,I_Vol_down_25x27,const Icon, -Variable,+,I_Vol_down_hvr_25x27,const Icon, -Variable,+,I_Vol_up_25x27,const Icon, -Variable,+,I_Vol_up_hvr_25x27,const Icon, -Variable,+,I_Voldwn_6x6,const Icon, -Variable,+,I_Voltage_16x16,const Icon, -Variable,+,I_Volup_8x6,const Icon, -Variable,+,I_WarningDolphin_45x42,const Icon, -Variable,+,I_Warning_30x23,const Icon, -Variable,+,I_back_10px,const Icon, -Variable,+,I_badusb_10px,const Icon, -Variable,+,I_dir_10px,const Icon, -Variable,+,I_iButtonDolphinVerySuccess_108x52,const Icon, -Variable,+,I_iButtonKey_49x44,const Icon, -Variable,+,I_ibutt_10px,const Icon, -Variable,+,I_ir_10px,const Icon, -Variable,+,I_loading_10px,const Icon, -Variable,+,I_music_10px,const Icon, -Variable,+,I_passport_bad1_46x49,const Icon, -Variable,+,I_passport_bad2_46x49,const Icon, -Variable,+,I_passport_bad3_46x49,const Icon, -Variable,+,I_passport_bottom_128x18,const Icon, -Variable,+,I_passport_happy1_46x49,const Icon, -Variable,+,I_passport_happy2_46x49,const Icon, -Variable,+,I_passport_happy3_46x49,const Icon, -Variable,+,I_passport_left_6x46,const Icon, -Variable,+,I_passport_okay1_46x49,const Icon, -Variable,+,I_passport_okay2_46x49,const Icon, -Variable,+,I_passport_okay3_46x49,const Icon, -Variable,+,I_sub1_10px,const Icon, -Variable,+,I_u2f_10px,const Icon, -Variable,+,I_unknown_10px,const Icon, -Variable,+,I_update_10px,const Icon, Variable,-,MSIRangeTable,const uint32_t[16], Variable,-,SmpsPrescalerTable,const uint32_t[4][6], Variable,+,SystemCoreClock,uint32_t, diff --git a/firmware/targets/f7/ble_glue/dev_info_service.c b/firmware/targets/f7/ble_glue/dev_info_service.c old mode 100755 new mode 100644 diff --git a/firmware/targets/f7/furi_hal/furi_hal_cortex.c b/firmware/targets/f7/furi_hal/furi_hal_cortex.c index c2abd1b85..192b83ee4 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_cortex.c +++ b/firmware/targets/f7/furi_hal/furi_hal_cortex.c @@ -36,5 +36,6 @@ bool furi_hal_cortex_timer_is_expired(FuriHalCortexTimer cortex_timer) { } void furi_hal_cortex_timer_wait(FuriHalCortexTimer cortex_timer) { - while(!furi_hal_cortex_timer_is_expired(cortex_timer)); + while(!furi_hal_cortex_timer_is_expired(cortex_timer)) + ; } \ No newline at end of file diff --git a/firmware/targets/f7/furi_hal/furi_hal_nfc.c b/firmware/targets/f7/furi_hal/furi_hal_nfc.c index 069ac4ea4..3ebf4f82b 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_nfc.c +++ b/firmware/targets/f7/furi_hal/furi_hal_nfc.c @@ -620,6 +620,10 @@ uint16_t furi_hal_nfc_bitstream_to_data_and_parity( uint16_t in_buff_bits, uint8_t* out_data, uint8_t* out_parity) { + if(in_buff_bits < 8) { + out_data[0] = in_buff[0]; + return in_buff_bits; + } if(in_buff_bits % 9 != 0) { return 0; } @@ -635,7 +639,7 @@ uint16_t furi_hal_nfc_bitstream_to_data_and_parity( bit_processed += 9; curr_byte++; } - return curr_byte; + return curr_byte * 8; } bool furi_hal_nfc_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_t timeout_ms) { @@ -692,8 +696,8 @@ bool furi_hal_nfc_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_t timeout_ms) { if(tx_rx->tx_rx_type == FuriHalNfcTxRxTypeRaw || tx_rx->tx_rx_type == FuriHalNfcTxRxTypeRxRaw) { - tx_rx->rx_bits = 8 * furi_hal_nfc_bitstream_to_data_and_parity( - temp_rx_buff, *temp_rx_bits, tx_rx->rx_data, tx_rx->rx_parity); + tx_rx->rx_bits = furi_hal_nfc_bitstream_to_data_and_parity( + temp_rx_buff, *temp_rx_bits, tx_rx->rx_data, tx_rx->rx_parity); } else { memcpy(tx_rx->rx_data, temp_rx_buff, MIN(*temp_rx_bits / 8, FURI_HAL_NFC_DATA_BUFF_SIZE)); tx_rx->rx_bits = *temp_rx_bits; diff --git a/firmware/targets/furi_hal_include/furi_hal_nfc.h b/firmware/targets/furi_hal_include/furi_hal_nfc.h index 537e0abf0..90d968fea 100644 --- a/firmware/targets/furi_hal_include/furi_hal_nfc.h +++ b/firmware/targets/furi_hal_include/furi_hal_nfc.h @@ -111,7 +111,7 @@ bool furi_hal_nfc_is_busy(); * * @return true if initialized */ - bool furi_hal_nfc_is_init(); +bool furi_hal_nfc_is_init(); /** NFC field on */ @@ -234,7 +234,6 @@ void furi_hal_nfc_sleep(); void furi_hal_nfc_stop(); - /* Low level transport API, use it to implement your own transport layers */ #define furi_hal_nfc_ll_ms2fc rfalConvMsTo1fc @@ -250,7 +249,8 @@ typedef enum { FuriHalNfcReturnBusy = 2, /*!< device or resource busy */ FuriHalNfcReturnIo = 3, /*!< generic IO error */ FuriHalNfcReturnTimeout = 4, /*!< error due to timeout */ - FuriHalNfcReturnRequest = 5, /*!< invalid request or requested function can't be executed at the moment */ + FuriHalNfcReturnRequest = + 5, /*!< invalid request or requested function can't be executed at the moment */ FuriHalNfcReturnNomsg = 6, /*!< No message of desired type */ FuriHalNfcReturnParam = 7, /*!< Parameter error */ FuriHalNfcReturnSystem = 8, /*!< System error */ @@ -261,20 +261,23 @@ typedef enum { FuriHalNfcReturnAgain = 13, /*!< Call again */ FuriHalNfcReturnMemCorrupt = 14, /*!< memory corruption */ FuriHalNfcReturnNotImplemented = 15, /*!< not implemented */ - FuriHalNfcReturnPcCorrupt = 16, /*!< Program Counter has been manipulated or spike/noise trigger illegal operation */ + FuriHalNfcReturnPcCorrupt = + 16, /*!< Program Counter has been manipulated or spike/noise trigger illegal operation */ FuriHalNfcReturnSend = 17, /*!< error sending*/ FuriHalNfcReturnIgnore = 18, /*!< indicates error detected but to be ignored */ FuriHalNfcReturnSemantic = 19, /*!< indicates error in state machine (unexpected cmd) */ FuriHalNfcReturnSyntax = 20, /*!< indicates error in state machine (unknown cmd) */ FuriHalNfcReturnCrc = 21, /*!< crc error */ FuriHalNfcReturnNotfound = 22, /*!< transponder not found */ - FuriHalNfcReturnNotunique = 23, /*!< transponder not unique - more than one transponder in field */ + FuriHalNfcReturnNotunique = + 23, /*!< transponder not unique - more than one transponder in field */ FuriHalNfcReturnNotsupp = 24, /*!< requested operation not supported */ FuriHalNfcReturnWrite = 25, /*!< write error */ FuriHalNfcReturnFifo = 26, /*!< fifo over or underflow error */ FuriHalNfcReturnPar = 27, /*!< parity error */ FuriHalNfcReturnDone = 28, /*!< transfer has already finished */ - FuriHalNfcReturnRfCollision = 29, /*!< collision error (Bit Collision or during RF Collision avoidance ) */ + FuriHalNfcReturnRfCollision = + 29, /*!< collision error (Bit Collision or during RF Collision avoidance ) */ FuriHalNfcReturnHwOverrun = 30, /*!< lost one or more received bytes */ FuriHalNfcReturnReleaseReq = 31, /*!< device requested release */ FuriHalNfcReturnSleepReq = 32, /*!< device requested sleep */ @@ -282,7 +285,8 @@ typedef enum { FuriHalNfcReturnMaxReruns = 34, /*!< blocking procedure reached maximum runs */ FuriHalNfcReturnDisabled = 35, /*!< operation aborted due to disabled configuration */ FuriHalNfcReturnHwMismatch = 36, /*!< expected hw do not match */ - FuriHalNfcReturnLinkLoss = 37, /*!< Other device's field didn't behave as expected: turned off by Initiator in Passive mode, or AP2P did not turn on field */ + FuriHalNfcReturnLinkLoss = + 37, /*!< Other device's field didn't behave as expected: turned off by Initiator in Passive mode, or AP2P did not turn on field */ FuriHalNfcReturnInvalidHandle = 38, /*!< invalid or not initalized device handle */ FuriHalNfcReturnIncompleteByte = 40, /*!< Incomplete byte rcvd */ FuriHalNfcReturnIncompleteByte01 = 41, /*!< Incomplete byte rcvd - 1 bit */ @@ -295,38 +299,40 @@ typedef enum { } FuriHalNfcReturn; typedef enum { - FuriHalNfcModeNone = 0, /*!< No mode selected/defined */ - FuriHalNfcModePollNfca = 1, /*!< Mode to perform as NFCA (ISO14443A) Poller (PCD) */ - FuriHalNfcModePollNfcaT1t = 2, /*!< Mode to perform as NFCA T1T (Topaz) Poller (PCD) */ - FuriHalNfcModePollNfcb = 3, /*!< Mode to perform as NFCB (ISO14443B) Poller (PCD) */ - FuriHalNfcModePollBPrime = 4, /*!< Mode to perform as B' Calypso (Innovatron) (PCD) */ - FuriHalNfcModePollBCts = 5, /*!< Mode to perform as CTS Poller (PCD) */ - FuriHalNfcModePollNfcf = 6, /*!< Mode to perform as NFCF (FeliCa) Poller (PCD) */ - FuriHalNfcModePollNfcv = 7, /*!< Mode to perform as NFCV (ISO15963) Poller (PCD) */ - FuriHalNfcModePollPicopass = 8, /*!< Mode to perform as PicoPass / iClass Poller (PCD) */ - FuriHalNfcModePollActiveP2p = 9, /*!< Mode to perform as Active P2P (ISO18092) Initiator */ - FuriHalNfcModeListenNfca = 10, /*!< Mode to perform as NFCA (ISO14443A) Listener (PICC) */ - FuriHalNfcModeListenNfcb = 11, /*!< Mode to perform as NFCA (ISO14443B) Listener (PICC) */ - FuriHalNfcModeListenNfcf = 12, /*!< Mode to perform as NFCA (ISO15963) Listener (PICC) */ - FuriHalNfcModeListenActiveP2p = 13 /*!< Mode to perform as Active P2P (ISO18092) Target */ + FuriHalNfcModeNone = 0, /*!< No mode selected/defined */ + FuriHalNfcModePollNfca = 1, /*!< Mode to perform as NFCA (ISO14443A) Poller (PCD) */ + FuriHalNfcModePollNfcaT1t = 2, /*!< Mode to perform as NFCA T1T (Topaz) Poller (PCD) */ + FuriHalNfcModePollNfcb = 3, /*!< Mode to perform as NFCB (ISO14443B) Poller (PCD) */ + FuriHalNfcModePollBPrime = 4, /*!< Mode to perform as B' Calypso (Innovatron) (PCD) */ + FuriHalNfcModePollBCts = 5, /*!< Mode to perform as CTS Poller (PCD) */ + FuriHalNfcModePollNfcf = 6, /*!< Mode to perform as NFCF (FeliCa) Poller (PCD) */ + FuriHalNfcModePollNfcv = 7, /*!< Mode to perform as NFCV (ISO15963) Poller (PCD) */ + FuriHalNfcModePollPicopass = 8, /*!< Mode to perform as PicoPass / iClass Poller (PCD) */ + FuriHalNfcModePollActiveP2p = 9, /*!< Mode to perform as Active P2P (ISO18092) Initiator */ + FuriHalNfcModeListenNfca = 10, /*!< Mode to perform as NFCA (ISO14443A) Listener (PICC) */ + FuriHalNfcModeListenNfcb = 11, /*!< Mode to perform as NFCA (ISO14443B) Listener (PICC) */ + FuriHalNfcModeListenNfcf = 12, /*!< Mode to perform as NFCA (ISO15963) Listener (PICC) */ + FuriHalNfcModeListenActiveP2p = 13 /*!< Mode to perform as Active P2P (ISO18092) Target */ } FuriHalNfcMode; typedef enum { - FuriHalNfcBitrate106 = 0, /*!< Bit Rate 106 kbit/s (fc/128) */ - FuriHalNfcBitrate212 = 1, /*!< Bit Rate 212 kbit/s (fc/64) */ - FuriHalNfcBitrate424 = 2, /*!< Bit Rate 424 kbit/s (fc/32) */ - FuriHalNfcBitrate848 = 3, /*!< Bit Rate 848 kbit/s (fc/16) */ - FuriHalNfcBitrate1695 = 4, /*!< Bit Rate 1695 kbit/s (fc/8) */ - FuriHalNfcBitrate3390 = 5, /*!< Bit Rate 3390 kbit/s (fc/4) */ - FuriHalNfcBitrate6780 = 6, /*!< Bit Rate 6780 kbit/s (fc/2) */ - FuriHalNfcBitrate13560 = 7, /*!< Bit Rate 13560 kbit/s (fc) */ - FuriHalNfcBitrate52p97 = 0xEB, /*!< Bit Rate 52.97 kbit/s (fc/256) Fast Mode VICC->VCD */ - FuriHalNfcBitrate26p48 = 0xEC, /*!< Bit Rate 26,48 kbit/s (fc/512) NFCV VICC->VCD & VCD->VICC 1of4 */ - FuriHalNfcBitrate1p66 = 0xED, /*!< Bit Rate 1,66 kbit/s (fc/8192) NFCV VCD->VICC 1of256 */ - FuriHalNfcBitrateKeep = 0xFF /*!< Value indicating to keep the same previous bit rate */ + FuriHalNfcBitrate106 = 0, /*!< Bit Rate 106 kbit/s (fc/128) */ + FuriHalNfcBitrate212 = 1, /*!< Bit Rate 212 kbit/s (fc/64) */ + FuriHalNfcBitrate424 = 2, /*!< Bit Rate 424 kbit/s (fc/32) */ + FuriHalNfcBitrate848 = 3, /*!< Bit Rate 848 kbit/s (fc/16) */ + FuriHalNfcBitrate1695 = 4, /*!< Bit Rate 1695 kbit/s (fc/8) */ + FuriHalNfcBitrate3390 = 5, /*!< Bit Rate 3390 kbit/s (fc/4) */ + FuriHalNfcBitrate6780 = 6, /*!< Bit Rate 6780 kbit/s (fc/2) */ + FuriHalNfcBitrate13560 = 7, /*!< Bit Rate 13560 kbit/s (fc) */ + FuriHalNfcBitrate52p97 = 0xEB, /*!< Bit Rate 52.97 kbit/s (fc/256) Fast Mode VICC->VCD */ + FuriHalNfcBitrate26p48 = + 0xEC, /*!< Bit Rate 26,48 kbit/s (fc/512) NFCV VICC->VCD & VCD->VICC 1of4 */ + FuriHalNfcBitrate1p66 = 0xED, /*!< Bit Rate 1,66 kbit/s (fc/8192) NFCV VCD->VICC 1of256 */ + FuriHalNfcBitrateKeep = 0xFF /*!< Value indicating to keep the same previous bit rate */ } FuriHalNfcBitrate; -FuriHalNfcReturn furi_hal_nfc_ll_set_mode(FuriHalNfcMode mode, FuriHalNfcBitrate txBR, FuriHalNfcBitrate rxBR); +FuriHalNfcReturn + furi_hal_nfc_ll_set_mode(FuriHalNfcMode mode, FuriHalNfcBitrate txBR, FuriHalNfcBitrate rxBR); #define FURI_HAL_NFC_LL_GT_NFCA furi_hal_nfc_ll_ms2fc(5U) /*!< GTA Digital 2.0 6.10.4.1 & B.2 */ #define FURI_HAL_NFC_LL_GT_NFCB furi_hal_nfc_ll_ms2fc(5U) /*!< GTB Digital 2.0 7.9.4.1 & B.3 */ @@ -334,40 +340,57 @@ FuriHalNfcReturn furi_hal_nfc_ll_set_mode(FuriHalNfcMode mode, FuriHalNfcBitrate #define FURI_HAL_NFC_LL_GT_NFCV furi_hal_nfc_ll_ms2fc(5U) /*!< GTV Digital 2.0 9.7.5.1 & B.5 */ #define FURI_HAL_NFC_LL_GT_PICOPASS furi_hal_nfc_ll_ms2fc(1U) /*!< GT Picopass */ #define FURI_HAL_NFC_LL_GT_AP2P furi_hal_nfc_ll_ms2fc(5U) /*!< TIRFG Ecma 340 11.1.1 */ -#define FURI_HAL_NFC_LL_GT_AP2P_ADJUSTED furi_hal_nfc_ll_ms2fc(5U + 25U) /*!< Adjusted GT for greater interoperability (Sony XPERIA P, Nokia N9, Huawei P2) */ +#define FURI_HAL_NFC_LL_GT_AP2P_ADJUSTED \ + furi_hal_nfc_ll_ms2fc( \ + 5U + \ + 25U) /*!< Adjusted GT for greater interoperability (Sony XPERIA P, Nokia N9, Huawei P2) */ void furi_hal_nfc_ll_set_guard_time(uint32_t cycles); typedef enum { - FuriHalNfcErrorHandlingNone = 0, /*!< No special error handling will be performed */ - FuriHalNfcErrorHandlingNfc = 1, /*!< Error handling set to perform as NFC compliant device */ - FuriHalNfcErrorHandlingEmvco = 2 /*!< Error handling set to perform as EMVCo compliant device */ + FuriHalNfcErrorHandlingNone = 0, /*!< No special error handling will be performed */ + FuriHalNfcErrorHandlingNfc = 1, /*!< Error handling set to perform as NFC compliant device */ + FuriHalNfcErrorHandlingEmvco = + 2 /*!< Error handling set to perform as EMVCo compliant device */ } FuriHalNfcErrorHandling; void furi_hal_nfc_ll_set_error_handling(FuriHalNfcErrorHandling eHandling); /* RFAL Frame Delay Time (FDT) Listen default values */ -#define FURI_HAL_NFC_LL_FDT_LISTEN_NFCA_POLLER 1172U /*!< FDTA,LISTEN,MIN (n=9) Last bit: Logic "1" - tnn,min/2 Digital 1.1 6.10 ; EMV CCP Spec Book D v2.01 4.8.1.3 */ -#define FURI_HAL_NFC_LL_FDT_LISTEN_NFCB_POLLER 1008U /*!< TR0B,MIN Digital 1.1 7.1.3 & A.3 ; EMV CCP Spec Book D v2.01 4.8.1.3 & Table A.5 */ -#define FURI_HAL_NFC_LL_FDT_LISTEN_NFCF_POLLER 2672U /*!< TR0F,LISTEN,MIN Digital 1.1 8.7.1.1 & A.4 */ -#define FURI_HAL_NFC_LL_FDT_LISTEN_NFCV_POLLER 4310U /*!< FDTV,LISTEN,MIN t1 min Digital 2.1 B.5 ; ISO15693-3 2009 9.1 */ -#define FURI_HAL_NFC_LL_FDT_LISTEN_PICOPASS_POLLER 3400U /*!< ISO15693 t1 min - observed adjustment */ -#define FURI_HAL_NFC_LL_FDT_LISTEN_AP2P_POLLER 64U /*!< FDT AP2P No actual FDTListen is required as fields switch and collision avoidance */ +#define FURI_HAL_NFC_LL_FDT_LISTEN_NFCA_POLLER \ + 1172U /*!< FDTA,LISTEN,MIN (n=9) Last bit: Logic "1" - tnn,min/2 Digital 1.1 6.10 ; EMV CCP Spec Book D v2.01 4.8.1.3 */ +#define FURI_HAL_NFC_LL_FDT_LISTEN_NFCB_POLLER \ + 1008U /*!< TR0B,MIN Digital 1.1 7.1.3 & A.3 ; EMV CCP Spec Book D v2.01 4.8.1.3 & Table A.5 */ +#define FURI_HAL_NFC_LL_FDT_LISTEN_NFCF_POLLER \ + 2672U /*!< TR0F,LISTEN,MIN Digital 1.1 8.7.1.1 & A.4 */ +#define FURI_HAL_NFC_LL_FDT_LISTEN_NFCV_POLLER \ + 4310U /*!< FDTV,LISTEN,MIN t1 min Digital 2.1 B.5 ; ISO15693-3 2009 9.1 */ +#define FURI_HAL_NFC_LL_FDT_LISTEN_PICOPASS_POLLER \ + 3400U /*!< ISO15693 t1 min - observed adjustment */ +#define FURI_HAL_NFC_LL_FDT_LISTEN_AP2P_POLLER \ + 64U /*!< FDT AP2P No actual FDTListen is required as fields switch and collision avoidance */ #define FURI_HAL_NFC_LL_FDT_LISTEN_NFCA_LISTENER 1172U /*!< FDTA,LISTEN,MIN Digital 1.1 6.10 */ -#define FURI_HAL_NFC_LL_FDT_LISTEN_NFCB_LISTENER 1024U /*!< TR0B,MIN Digital 1.1 7.1.3 & A.3 ; EMV CCP Spec Book D v2.01 4.8.1.3 & Table A.5 */ -#define FURI_HAL_NFC_LL_FDT_LISTEN_NFCF_LISTENER 2688U /*!< TR0F,LISTEN,MIN Digital 2.1 8.7.1.1 & B.4 */ -#define FURI_HAL_NFC_LL_FDT_LISTEN_AP2P_LISTENER 64U /*!< FDT AP2P No actual FDTListen exists as fields switch and collision avoidance */ +#define FURI_HAL_NFC_LL_FDT_LISTEN_NFCB_LISTENER \ + 1024U /*!< TR0B,MIN Digital 1.1 7.1.3 & A.3 ; EMV CCP Spec Book D v2.01 4.8.1.3 & Table A.5 */ +#define FURI_HAL_NFC_LL_FDT_LISTEN_NFCF_LISTENER \ + 2688U /*!< TR0F,LISTEN,MIN Digital 2.1 8.7.1.1 & B.4 */ +#define FURI_HAL_NFC_LL_FDT_LISTEN_AP2P_LISTENER \ + 64U /*!< FDT AP2P No actual FDTListen exists as fields switch and collision avoidance */ void furi_hal_nfc_ll_set_fdt_listen(uint32_t cycles); /* RFAL Frame Delay Time (FDT) Poll default values */ -#define FURI_HAL_NFC_LL_FDT_POLL_NFCA_POLLER 6780U /*!< FDTA,POLL,MIN Digital 1.1 6.10.3.1 & A.2 */ -#define FURI_HAL_NFC_LL_FDT_POLL_NFCA_T1T_POLLER 384U /*!< RRDDT1T,MIN,B1 Digital 1.1 10.7.1 & A.5 */ -#define FURI_HAL_NFC_LL_FDT_POLL_NFCB_POLLER 6780U /*!< FDTB,POLL,MIN = TR2B,MIN,DEFAULT Digital 1.1 7.9.3 & A.3 ; EMVCo 3.0 FDTB,PCD,MIN Table A.5 */ +#define FURI_HAL_NFC_LL_FDT_POLL_NFCA_POLLER \ + 6780U /*!< FDTA,POLL,MIN Digital 1.1 6.10.3.1 & A.2 */ +#define FURI_HAL_NFC_LL_FDT_POLL_NFCA_T1T_POLLER \ + 384U /*!< RRDDT1T,MIN,B1 Digital 1.1 10.7.1 & A.5 */ +#define FURI_HAL_NFC_LL_FDT_POLL_NFCB_POLLER \ + 6780U /*!< FDTB,POLL,MIN = TR2B,MIN,DEFAULT Digital 1.1 7.9.3 & A.3 ; EMVCo 3.0 FDTB,PCD,MIN Table A.5 */ #define FURI_HAL_NFC_LL_FDT_POLL_NFCF_POLLER 6800U /*!< FDTF,POLL,MIN Digital 2.1 8.7.3 & B.4 */ #define FURI_HAL_NFC_LL_FDT_POLL_NFCV_POLLER 4192U /*!< FDTV,POLL Digital 2.1 9.7.3.1 & B.5 */ #define FURI_HAL_NFC_LL_FDT_POLL_PICOPASS_POLLER 1790U /*!< FDT Max */ -#define FURI_HAL_NFC_LL_FDT_POLL_AP2P_POLLER 0U /*!< FDT AP2P No actual FDTPoll exists as fields switch and collision avoidance */ +#define FURI_HAL_NFC_LL_FDT_POLL_AP2P_POLLER \ + 0U /*!< FDT AP2P No actual FDTPoll exists as fields switch and collision avoidance */ void furi_hal_nfc_ll_set_fdt_poll(uint32_t FDTPoll); diff --git a/furi/SConscript b/furi/SConscript index a751eb6e1..f95ef13f9 100644 --- a/furi/SConscript +++ b/furi/SConscript @@ -1,6 +1,11 @@ Import("env") -env.Append(LINT_SOURCES=["furi"]) +env.Append( + LINT_SOURCES=[ + "furi", + "furi/core", + ] +) libenv = env.Clone(FW_LIB_NAME="furi") diff --git a/furi/core/check.c b/furi/core/check.c index 613b52f46..00c20575a 100644 --- a/furi/core/check.c +++ b/furi/core/check.c @@ -11,6 +11,31 @@ #include #include +PLACE_IN_SECTION("MB_MEM2") const char* __furi_check_message = NULL; +PLACE_IN_SECTION("MB_MEM2") uint32_t __furi_check_registers[12] = {0}; + +/** Load r12 value to __furi_check_message and store registers to __furi_check_registers */ +#define GET_MESSAGE_AND_STORE_REGISTERS() \ + asm volatile("ldr r11, =__furi_check_message \n" \ + "str r12, [r11] \n" \ + "ldr r12, =__furi_check_registers \n" \ + "stm r12, {r0-r11} \n" \ + : \ + : \ + : "memory"); + +// Restore registers and halt MCU +#define RESTORE_REGISTERS_AND_HALT_MCU() \ + asm volatile("ldr r12, =__furi_check_registers \n" \ + "ldm r12, {r0-r11} \n" \ + "loop%=: \n" \ + "bkpt 0x00 \n" \ + "wfi \n" \ + "b loop%= \n" \ + : \ + : \ + : "memory"); + extern size_t xPortGetTotalHeapSize(void); extern size_t xPortGetFreeHeapSize(void); extern size_t xPortGetMinimumEverFreeHeapSize(void); @@ -52,31 +77,19 @@ static void __furi_print_name(bool isr) { } } -static FURI_NORETURN void __furi_halt() { - asm volatile( -#ifdef FURI_DEBUG - "bkpt 0x00 \n" -#endif - "loop%=: \n" - "wfi \n" - "b loop%= \n" - : - : - : "memory"); - __builtin_unreachable(); -} - -FURI_NORETURN void furi_crash(const char* message) { - bool isr = FURI_IS_ISR(); +FURI_NORETURN void __furi_crash() { __disable_irq(); + GET_MESSAGE_AND_STORE_REGISTERS(); - if(message == NULL) { - message = "Fatal Error"; + bool isr = FURI_IS_IRQ_MODE(); + + if(__furi_check_message == NULL) { + __furi_check_message = "Fatal Error"; } furi_hal_console_puts("\r\n\033[0;31m[CRASH]"); __furi_print_name(isr); - furi_hal_console_puts(message); + furi_hal_console_puts(__furi_check_message); if(!isr) { __furi_print_stack_info(); @@ -86,9 +99,9 @@ FURI_NORETURN void furi_crash(const char* message) { #ifdef FURI_DEBUG furi_hal_console_puts("\r\nSystem halted. Connect debugger for more info\r\n"); furi_hal_console_puts("\033[0m\r\n"); - __furi_halt(); + RESTORE_REGISTERS_AND_HALT_MCU(); #else - furi_hal_rtc_set_fault_data((uint32_t)message); + furi_hal_rtc_set_fault_data((uint32_t)__furi_check_message); furi_hal_console_puts("\r\nRebooting system.\r\n"); furi_hal_console_puts("\033[0m\r\n"); furi_hal_power_reset(); @@ -96,18 +109,21 @@ FURI_NORETURN void furi_crash(const char* message) { __builtin_unreachable(); } -FURI_NORETURN void furi_halt(const char* message) { - bool isr = FURI_IS_ISR(); +FURI_NORETURN void __furi_halt() { __disable_irq(); + GET_MESSAGE_AND_STORE_REGISTERS(); - if(message == NULL) { - message = "System halt requested."; + bool isr = FURI_IS_IRQ_MODE(); + + if(__furi_check_message == NULL) { + __furi_check_message = "System halt requested."; } furi_hal_console_puts("\r\n\033[0;31m[HALT]"); __furi_print_name(isr); - furi_hal_console_puts(message); + furi_hal_console_puts(__furi_check_message); furi_hal_console_puts("\r\nSystem halted. Bye-bye!\r\n"); furi_hal_console_puts("\033[0m\r\n"); - __furi_halt(); + RESTORE_REGISTERS_AND_HALT_MCU(); + __builtin_unreachable(); } diff --git a/furi/core/check.h b/furi/core/check.h index 30efdf010..78efc1451 100644 --- a/furi/core/check.h +++ b/furi/core/check.h @@ -1,3 +1,16 @@ +/** + * @file check.h + * + * Furi crash and assert functions. + * + * The main problem with crashing is that you can't do anything without disturbing registers, + * and if you disturb registers, you won't be able to see the correct register values in the debugger. + * + * Current solution works around it by passing the message through r12 and doing some magic with registers in crash function. + * r0-r10 are stored in the ram2 on crash routine start and restored at the end. + * The only register that is going to be lost is r11. + * + */ #pragma once #ifdef __cplusplus @@ -8,12 +21,44 @@ extern "C" { #define FURI_NORETURN noreturn #endif +/** Crash system */ +FURI_NORETURN void __furi_crash(); + +/** Halt system */ +FURI_NORETURN void __furi_halt(); + +/** Crash system with message. Show message after reboot. */ +#define furi_crash(message) \ + do { \ + register const void* r12 asm("r12") = (void*)message; \ + asm volatile("sukima%=:" : : "r"(r12)); \ + __furi_crash(); \ + } while(0) + +/** Halt system with message. */ +#define furi_halt(message) \ + do { \ + register const void* r12 asm("r12") = (void*)message; \ + asm volatile("sukima%=:" : : "r"(r12)); \ + __furi_halt(); \ + } while(0) + /** Check condition and crash if check failed */ -#define furi_check(__e) ((__e) ? (void)0 : furi_crash("furi_check failed\r\n")) +#define furi_check(__e) \ + do { \ + if((__e) == 0) { \ + furi_crash("furi_check failed\r\n"); \ + } \ + } while(0) /** Only in debug build: Assert condition and crash if assert failed */ #ifdef FURI_DEBUG -#define furi_assert(__e) ((__e) ? (void)0 : furi_crash("furi_assert failed\r\n")) +#define furi_assert(__e) \ + do { \ + if((__e) == 0) { \ + furi_crash("furi_assert failed\r\n"); \ + } \ + } while(0) #else #define furi_assert(__e) \ do { \ @@ -21,12 +66,6 @@ extern "C" { } while(0) #endif -/** Crash system */ -FURI_NORETURN void furi_crash(const char* message); - -/** Halt system */ -FURI_NORETURN void furi_halt(const char* message); - #ifdef __cplusplus } #endif diff --git a/furi/core/timer.c b/furi/core/timer.c index 462a2e89e..c42b0c2ac 100644 --- a/furi/core/timer.c +++ b/furi/core/timer.c @@ -86,7 +86,7 @@ void furi_timer_free(FuriTimer* instance) { furi_check(xTimerDelete(hTimer, portMAX_DELAY) == pdPASS); - while (furi_timer_is_running(instance)) furi_delay_tick(2); + while(furi_timer_is_running(instance)) furi_delay_tick(2); if((uint32_t)callb & 1U) { /* Callback memory was allocated from dynamic pool, clear flag */ diff --git a/furi/flipper.c b/furi/flipper.c old mode 100755 new mode 100644 diff --git a/lib/lfrfid/SConscript b/lib/lfrfid/SConscript index fd29ca2ef..6177a9a50 100644 --- a/lib/lfrfid/SConscript +++ b/lib/lfrfid/SConscript @@ -2,7 +2,7 @@ Import("env") env.Append( LINT_SOURCES=[ - "#/lib/lfrfid", + "lib/lfrfid", ], CPPPATH=[ "#/lib/lfrfid", diff --git a/lib/lfrfid/protocols/protocol_awid.c b/lib/lfrfid/protocols/protocol_awid.c index 38c7793b8..939627723 100644 --- a/lib/lfrfid/protocols/protocol_awid.c +++ b/lib/lfrfid/protocols/protocol_awid.c @@ -207,7 +207,7 @@ bool protocol_awid_write_data(ProtocolAwid* protocol, void* data) { // Fix incorrect length byte if(protocol->data[0] != 26 && protocol->data[0] != 50 && protocol->data[0] != 37 && - protocol->data[0] != 34 && protocol->data[0] != 36 ) { + protocol->data[0] != 34 && protocol->data[0] != 36) { protocol->data[0] = 26; } diff --git a/lib/nfc/helpers/reader_analyzer.c b/lib/nfc/helpers/reader_analyzer.c index 0ba657a2e..7fed9c6f6 100644 --- a/lib/nfc/helpers/reader_analyzer.c +++ b/lib/nfc/helpers/reader_analyzer.c @@ -201,10 +201,17 @@ NfcProtocol FuriHalNfcDevData* reader_analyzer_get_nfc_data(ReaderAnalyzer* instance) { furi_assert(instance); - + instance->nfc_data = reader_analyzer_nfc_data[ReaderAnalyzerNfcDataMfClassic]; return &instance->nfc_data; } +void reader_analyzer_set_nfc_data(ReaderAnalyzer* instance, FuriHalNfcDevData* nfc_data) { + furi_assert(instance); + furi_assert(nfc_data); + + memcpy(&instance->nfc_data, nfc_data, sizeof(FuriHalNfcDevData)); +} + static void reader_analyzer_write( ReaderAnalyzer* instance, uint8_t* data, diff --git a/lib/nfc/helpers/reader_analyzer.h b/lib/nfc/helpers/reader_analyzer.h index cc501f5a6..13bf4d77c 100644 --- a/lib/nfc/helpers/reader_analyzer.h +++ b/lib/nfc/helpers/reader_analyzer.h @@ -35,6 +35,8 @@ NfcProtocol FuriHalNfcDevData* reader_analyzer_get_nfc_data(ReaderAnalyzer* instance); +void reader_analyzer_set_nfc_data(ReaderAnalyzer* instance, FuriHalNfcDevData* nfc_data); + void reader_analyzer_prepare_tx_rx( ReaderAnalyzer* instance, FuriHalNfcTxRxContext* tx_rx, diff --git a/lib/nfc/nfc_device.c b/lib/nfc/nfc_device.c index 740cfae5e..a5e3fc14f 100644 --- a/lib/nfc/nfc_device.c +++ b/lib/nfc/nfc_device.c @@ -1122,6 +1122,13 @@ static bool nfc_device_load_data(NfcDevice* dev, FuriString* path, bool show_dia if(!flipper_format_read_hex(file, "UID", data->uid, data->uid_len)) break; if(!flipper_format_read_hex(file, "ATQA", data->atqa, 2)) break; if(!flipper_format_read_hex(file, "SAK", &data->sak, 1)) break; + // Load CUID + uint8_t* cuid_start = data->uid; + if(data->uid_len == 7) { + cuid_start = &data->uid[3]; + } + data->cuid = (cuid_start[0] << 24) | (cuid_start[1] << 16) | (cuid_start[2] << 8) | + (cuid_start[3]); // Parse other data if(dev->format == NfcDeviceSaveFormatMifareUl) { if(!nfc_device_load_mifare_ul_data(file, dev)) break; diff --git a/lib/nfc/nfc_worker.c b/lib/nfc/nfc_worker.c index ebe203905..e1e379a06 100644 --- a/lib/nfc/nfc_worker.c +++ b/lib/nfc/nfc_worker.c @@ -99,6 +99,10 @@ int32_t nfc_worker_task(void* context) { nfc_worker_emulate_mf_ultralight(nfc_worker); } else if(nfc_worker->state == NfcWorkerStateMfClassicEmulate) { nfc_worker_emulate_mf_classic(nfc_worker); + } else if(nfc_worker->state == NfcWorkerStateMfClassicWrite) { + nfc_worker_write_mf_classic(nfc_worker); + } else if(nfc_worker->state == NfcWorkerStateMfClassicUpdate) { + nfc_worker_update_mf_classic(nfc_worker); } else if(nfc_worker->state == NfcWorkerStateReadMfUltralightReadAuth) { nfc_worker_mf_ultralight_read_auth(nfc_worker); } else if(nfc_worker->state == NfcWorkerStateMfClassicDictAttack) { @@ -666,6 +670,144 @@ void nfc_worker_emulate_mf_classic(NfcWorker* nfc_worker) { rfal_platform_spi_release(); } +void nfc_worker_write_mf_classic(NfcWorker* nfc_worker) { + FuriHalNfcTxRxContext tx_rx = {}; + bool card_found_notified = false; + FuriHalNfcDevData nfc_data = {}; + MfClassicData* src_data = &nfc_worker->dev_data->mf_classic_data; + MfClassicData dest_data = *src_data; + + while(nfc_worker->state == NfcWorkerStateMfClassicWrite) { + if(furi_hal_nfc_detect(&nfc_data, 200)) { + if(!card_found_notified) { + nfc_worker->callback(NfcWorkerEventCardDetected, nfc_worker->context); + card_found_notified = true; + } + furi_hal_nfc_sleep(); + + FURI_LOG_I(TAG, "Check low level nfc data"); + if(memcmp(&nfc_data, &nfc_worker->dev_data->nfc_data, sizeof(FuriHalNfcDevData))) { + FURI_LOG_E(TAG, "Wrong card"); + nfc_worker->callback(NfcWorkerEventWrongCard, nfc_worker->context); + break; + } + + FURI_LOG_I(TAG, "Check mf classic type"); + MfClassicType type = + mf_classic_get_classic_type(nfc_data.atqa[0], nfc_data.atqa[1], nfc_data.sak); + if(type != nfc_worker->dev_data->mf_classic_data.type) { + FURI_LOG_E(TAG, "Wrong mf classic type"); + nfc_worker->callback(NfcWorkerEventWrongCard, nfc_worker->context); + break; + } + + // Set blocks not read + mf_classic_set_sector_data_not_read(&dest_data); + FURI_LOG_I(TAG, "Updating card sectors"); + uint8_t total_sectors = mf_classic_get_total_sectors_num(type); + bool write_success = true; + for(uint8_t i = 0; i < total_sectors; i++) { + FURI_LOG_I(TAG, "Reading sector %d", i); + mf_classic_read_sector(&tx_rx, &dest_data, i); + bool old_data_read = mf_classic_is_sector_data_read(src_data, i); + bool new_data_read = mf_classic_is_sector_data_read(&dest_data, i); + if(old_data_read != new_data_read) { + FURI_LOG_E(TAG, "Failed to update sector %d", i); + write_success = false; + break; + } + if(nfc_worker->state != NfcWorkerStateMfClassicWrite) break; + if(!mf_classic_write_sector(&tx_rx, &dest_data, src_data, i)) { + FURI_LOG_E(TAG, "Failed to write %d sector", i); + write_success = false; + break; + } + } + if(nfc_worker->state != NfcWorkerStateMfClassicWrite) break; + if(write_success) { + nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); + break; + } else { + nfc_worker->callback(NfcWorkerEventFail, nfc_worker->context); + break; + } + + } else { + if(card_found_notified) { + nfc_worker->callback(NfcWorkerEventNoCardDetected, nfc_worker->context); + card_found_notified = false; + } + } + furi_delay_ms(300); + } +} + +void nfc_worker_update_mf_classic(NfcWorker* nfc_worker) { + FuriHalNfcTxRxContext tx_rx = {}; + bool card_found_notified = false; + FuriHalNfcDevData nfc_data = {}; + MfClassicData* old_data = &nfc_worker->dev_data->mf_classic_data; + MfClassicData new_data = *old_data; + + while(nfc_worker->state == NfcWorkerStateMfClassicUpdate) { + if(furi_hal_nfc_detect(&nfc_data, 200)) { + if(!card_found_notified) { + nfc_worker->callback(NfcWorkerEventCardDetected, nfc_worker->context); + card_found_notified = true; + } + furi_hal_nfc_sleep(); + + FURI_LOG_I(TAG, "Check low level nfc data"); + if(memcmp(&nfc_data, &nfc_worker->dev_data->nfc_data, sizeof(FuriHalNfcDevData))) { + FURI_LOG_E(TAG, "Low level nfc data mismatch"); + nfc_worker->callback(NfcWorkerEventWrongCard, nfc_worker->context); + break; + } + + FURI_LOG_I(TAG, "Check MF classic type"); + MfClassicType type = + mf_classic_get_classic_type(nfc_data.atqa[0], nfc_data.atqa[1], nfc_data.sak); + if(type != nfc_worker->dev_data->mf_classic_data.type) { + FURI_LOG_E(TAG, "MF classic type mismatch"); + nfc_worker->callback(NfcWorkerEventWrongCard, nfc_worker->context); + break; + } + + // Set blocks not read + mf_classic_set_sector_data_not_read(&new_data); + FURI_LOG_I(TAG, "Updating card sectors"); + uint8_t total_sectors = mf_classic_get_total_sectors_num(type); + bool update_success = true; + for(uint8_t i = 0; i < total_sectors; i++) { + FURI_LOG_I(TAG, "Reading sector %d", i); + mf_classic_read_sector(&tx_rx, &new_data, i); + bool old_data_read = mf_classic_is_sector_data_read(old_data, i); + bool new_data_read = mf_classic_is_sector_data_read(&new_data, i); + if(old_data_read != new_data_read) { + FURI_LOG_E(TAG, "Failed to update sector %d", i); + update_success = false; + break; + } + if(nfc_worker->state != NfcWorkerStateMfClassicUpdate) break; + } + if(nfc_worker->state != NfcWorkerStateMfClassicUpdate) break; + + // Check updated data + if(update_success) { + *old_data = new_data; + nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); + break; + } + } else { + if(card_found_notified) { + nfc_worker->callback(NfcWorkerEventNoCardDetected, nfc_worker->context); + card_found_notified = false; + } + } + furi_delay_ms(300); + } +} + void nfc_worker_mf_ultralight_read_auth(NfcWorker* nfc_worker) { furi_assert(nfc_worker); furi_assert(nfc_worker->callback); @@ -758,7 +900,13 @@ void nfc_worker_analyze_reader(NfcWorker* nfc_worker) { FuriHalNfcTxRxContext tx_rx = {}; ReaderAnalyzer* reader_analyzer = nfc_worker->reader_analyzer; - FuriHalNfcDevData* nfc_data = reader_analyzer_get_nfc_data(reader_analyzer); + FuriHalNfcDevData* nfc_data = NULL; + if(nfc_worker->dev_data->protocol == NfcDeviceProtocolMifareClassic) { + nfc_data = &nfc_worker->dev_data->nfc_data; + reader_analyzer_set_nfc_data(reader_analyzer, nfc_data); + } else { + nfc_data = reader_analyzer_get_nfc_data(reader_analyzer); + } MfClassicEmulator emulator = { .cuid = nfc_util_bytes2num(&nfc_data->uid[nfc_data->uid_len - 4], 4), .data = nfc_worker->dev_data->mf_classic_data, diff --git a/lib/nfc/nfc_worker.h b/lib/nfc/nfc_worker.h index 84615f5d8..ce3a18241 100644 --- a/lib/nfc/nfc_worker.h +++ b/lib/nfc/nfc_worker.h @@ -14,6 +14,8 @@ typedef enum { NfcWorkerStateUidEmulate, NfcWorkerStateMfUltralightEmulate, NfcWorkerStateMfClassicEmulate, + NfcWorkerStateMfClassicWrite, + NfcWorkerStateMfClassicUpdate, NfcWorkerStateReadMfUltralightReadAuth, NfcWorkerStateMfClassicDictAttack, NfcWorkerStateAnalyzeReader, @@ -48,13 +50,16 @@ typedef enum { NfcWorkerEventNoCardDetected, NfcWorkerEventWrongCardDetected, - // Mifare Classic events + // Read Mifare Classic events NfcWorkerEventNoDictFound, NfcWorkerEventNewSector, NfcWorkerEventNewDictKeyBatch, NfcWorkerEventFoundKeyA, NfcWorkerEventFoundKeyB, + // Write Mifare Classic events + NfcWorkerEventWrongCard, + // Detect Reader events NfcWorkerEventDetectReaderDetected, NfcWorkerEventDetectReaderLost, diff --git a/lib/nfc/nfc_worker_i.h b/lib/nfc/nfc_worker_i.h index 526182f9a..b9f69e620 100644 --- a/lib/nfc/nfc_worker_i.h +++ b/lib/nfc/nfc_worker_i.h @@ -41,6 +41,10 @@ void nfc_worker_emulate_mf_ultralight(NfcWorker* nfc_worker); void nfc_worker_emulate_mf_classic(NfcWorker* nfc_worker); +void nfc_worker_write_mf_classic(NfcWorker* nfc_worker); + +void nfc_worker_update_mf_classic(NfcWorker* nfc_worker); + void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker); void nfc_worker_mf_ultralight_read_auth(NfcWorker* nfc_worker); diff --git a/lib/nfc/protocols/crypto1.c b/lib/nfc/protocols/crypto1.c index f08164ba9..2ac0ff081 100644 --- a/lib/nfc/protocols/crypto1.c +++ b/lib/nfc/protocols/crypto1.c @@ -73,3 +73,55 @@ uint32_t prng_successor(uint32_t x, uint32_t n) { return SWAPENDIAN(x); } + +void crypto1_decrypt( + Crypto1* crypto, + uint8_t* encrypted_data, + uint16_t encrypted_data_bits, + uint8_t* decrypted_data) { + furi_assert(crypto); + furi_assert(encrypted_data); + furi_assert(decrypted_data); + + if(encrypted_data_bits < 8) { + uint8_t decrypted_byte = 0; + decrypted_byte |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(encrypted_data[0], 0)) << 0; + decrypted_byte |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(encrypted_data[0], 1)) << 1; + decrypted_byte |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(encrypted_data[0], 2)) << 2; + decrypted_byte |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(encrypted_data[0], 3)) << 3; + decrypted_data[0] = decrypted_byte; + } else { + for(size_t i = 0; i < encrypted_data_bits / 8; i++) { + decrypted_data[i] = crypto1_byte(crypto, 0, 0) ^ encrypted_data[i]; + } + } +} + +void crypto1_encrypt( + Crypto1* crypto, + uint8_t* keystream, + uint8_t* plain_data, + uint16_t plain_data_bits, + uint8_t* encrypted_data, + uint8_t* encrypted_parity) { + furi_assert(crypto); + furi_assert(plain_data); + furi_assert(encrypted_data); + furi_assert(encrypted_parity); + + if(plain_data_bits < 8) { + encrypted_data[0] = 0; + for(size_t i = 0; i < plain_data_bits; i++) { + encrypted_data[0] |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(plain_data[0], i)) << i; + } + } else { + memset(encrypted_parity, 0, plain_data_bits / 8 + 1); + for(uint8_t i = 0; i < plain_data_bits / 8; i++) { + encrypted_data[i] = crypto1_byte(crypto, keystream ? keystream[i] : 0, 0) ^ + plain_data[i]; + encrypted_parity[i / 8] |= + (((crypto1_filter(crypto->odd) ^ nfc_util_odd_parity8(plain_data[i])) & 0x01) + << (7 - (i & 0x0007))); + } + } +} diff --git a/lib/nfc/protocols/crypto1.h b/lib/nfc/protocols/crypto1.h index 07b39c22c..450d1534e 100644 --- a/lib/nfc/protocols/crypto1.h +++ b/lib/nfc/protocols/crypto1.h @@ -21,3 +21,17 @@ uint32_t crypto1_word(Crypto1* crypto1, uint32_t in, int is_encrypted); uint32_t crypto1_filter(uint32_t in); uint32_t prng_successor(uint32_t x, uint32_t n); + +void crypto1_decrypt( + Crypto1* crypto, + uint8_t* encrypted_data, + uint16_t encrypted_data_bits, + uint8_t* decrypted_data); + +void crypto1_encrypt( + Crypto1* crypto, + uint8_t* keystream, + uint8_t* plain_data, + uint16_t plain_data_bits, + uint8_t* encrypted_data, + uint8_t* encrypted_parity); diff --git a/lib/nfc/protocols/mifare_classic.c b/lib/nfc/protocols/mifare_classic.c index e879ff4ef..7b0e17975 100644 --- a/lib/nfc/protocols/mifare_classic.c +++ b/lib/nfc/protocols/mifare_classic.c @@ -9,21 +9,8 @@ #define MF_CLASSIC_AUTH_KEY_A_CMD (0x60U) #define MF_CLASSIC_AUTH_KEY_B_CMD (0x61U) -#define MF_CLASSIC_READ_SECT_CMD (0x30) - -typedef enum { - MfClassicActionDataRead, - MfClassicActionDataWrite, - MfClassicActionDataInc, - MfClassicActionDataDec, - - MfClassicActionKeyARead, - MfClassicActionKeyAWrite, - MfClassicActionKeyBRead, - MfClassicActionKeyBWrite, - MfClassicActionACRead, - MfClassicActionACWrite, -} MfClassicAction; +#define MF_CLASSIC_READ_BLOCK_CMD (0x30) +#define MF_CLASSIC_WRITE_BLOCK_CMD (0xA0) const char* mf_classic_get_type_str(MfClassicType type) { if(type == MfClassicType1k) { @@ -122,6 +109,24 @@ void mf_classic_set_block_read(MfClassicData* data, uint8_t block_num, MfClassic FURI_BIT_SET(data->block_read_mask[block_num / 32], block_num % 32); } +bool mf_classic_is_sector_data_read(MfClassicData* data, uint8_t sector_num) { + furi_assert(data); + + uint8_t first_block = mf_classic_get_first_block_num_of_sector(sector_num); + uint8_t total_blocks = mf_classic_get_blocks_num_in_sector(sector_num); + bool data_read = true; + for(size_t i = first_block; i < first_block + total_blocks; i++) { + data_read &= mf_classic_is_block_read(data, i); + } + + return data_read; +} + +void mf_classic_set_sector_data_not_read(MfClassicData* data) { + furi_assert(data); + memset(data->block_read_mask, 0, sizeof(data->block_read_mask)); +} + bool mf_classic_is_key_found(MfClassicData* data, uint8_t sector_num, MfClassicKey key_type) { furi_assert(data); @@ -190,6 +195,9 @@ void mf_classic_get_read_sectors_and_keys( uint8_t* sectors_read, uint8_t* keys_found) { furi_assert(data); + furi_assert(sectors_read); + furi_assert(keys_found); + *sectors_read = 0; *keys_found = 0; uint8_t sectors_total = mf_classic_get_total_sectors_num(data->type); @@ -225,12 +233,12 @@ bool mf_classic_is_card_read(MfClassicData* data) { return card_read; } -static bool mf_classic_is_allowed_access_sector_trailer( - MfClassicEmulator* emulator, +bool mf_classic_is_allowed_access_sector_trailer( + MfClassicData* data, uint8_t block_num, MfClassicKey key, MfClassicAction action) { - uint8_t* sector_trailer = emulator->data.block[block_num].value; + uint8_t* sector_trailer = data->block[block_num].value; uint8_t AC = ((sector_trailer[7] >> 5) & 0x04) | ((sector_trailer[8] >> 2) & 0x02) | ((sector_trailer[8] >> 7) & 0x01); switch(action) { @@ -266,13 +274,13 @@ static bool mf_classic_is_allowed_access_sector_trailer( return true; } -static bool mf_classic_is_allowed_access_data_block( - MfClassicEmulator* emulator, +bool mf_classic_is_allowed_access_data_block( + MfClassicData* data, uint8_t block_num, MfClassicKey key, MfClassicAction action) { uint8_t* sector_trailer = - emulator->data.block[mf_classic_get_sector_trailer_num_by_block(block_num)].value; + data->block[mf_classic_get_sector_trailer_num_by_block(block_num)].value; uint8_t sector_block; if(block_num <= 128) { @@ -336,9 +344,10 @@ static bool mf_classic_is_allowed_access( MfClassicKey key, MfClassicAction action) { if(mf_classic_is_sector_trailer(block_num)) { - return mf_classic_is_allowed_access_sector_trailer(emulator, block_num, key, action); + return mf_classic_is_allowed_access_sector_trailer( + &emulator->data, block_num, key, action); } else { - return mf_classic_is_allowed_access_data_block(emulator, block_num, key, action); + return mf_classic_is_allowed_access_data_block(&emulator->data, block_num, key, action); } } @@ -514,25 +523,17 @@ bool mf_classic_read_block( furi_assert(block); bool read_block_success = false; - uint8_t plain_cmd[4] = {MF_CLASSIC_READ_SECT_CMD, block_num, 0x00, 0x00}; + uint8_t plain_cmd[4] = {MF_CLASSIC_READ_BLOCK_CMD, block_num, 0x00, 0x00}; nfca_append_crc16(plain_cmd, 2); - memset(tx_rx->tx_data, 0, sizeof(tx_rx->tx_data)); - memset(tx_rx->tx_parity, 0, sizeof(tx_rx->tx_parity)); - for(uint8_t i = 0; i < 4; i++) { - tx_rx->tx_data[i] = crypto1_byte(crypto, 0x00, 0) ^ plain_cmd[i]; - tx_rx->tx_parity[0] |= - ((crypto1_filter(crypto->odd) ^ nfc_util_odd_parity8(plain_cmd[i])) & 0x01) << (7 - i); - } + crypto1_encrypt(crypto, NULL, plain_cmd, 4 * 8, tx_rx->tx_data, tx_rx->tx_parity); tx_rx->tx_bits = 4 * 9; tx_rx->tx_rx_type = FuriHalNfcTxRxTypeRaw; if(furi_hal_nfc_tx_rx(tx_rx, 50)) { if(tx_rx->rx_bits == 8 * (MF_CLASSIC_BLOCK_SIZE + 2)) { uint8_t block_received[MF_CLASSIC_BLOCK_SIZE + 2]; - for(uint8_t i = 0; i < MF_CLASSIC_BLOCK_SIZE + 2; i++) { - block_received[i] = crypto1_byte(crypto, 0, 0) ^ tx_rx->rx_data[i]; - } + crypto1_decrypt(crypto, tx_rx->rx_data, tx_rx->rx_bits, block_received); uint16_t crc_calc = nfca_get_crc16(block_received, MF_CLASSIC_BLOCK_SIZE); uint16_t crc_received = (block_received[MF_CLASSIC_BLOCK_SIZE + 1] << 8) | block_received[MF_CLASSIC_BLOCK_SIZE]; @@ -754,49 +755,6 @@ uint8_t mf_classic_update_card(FuriHalNfcTxRxContext* tx_rx, MfClassicData* data return sectors_read; } -void mf_crypto1_decrypt( - Crypto1* crypto, - uint8_t* encrypted_data, - uint16_t encrypted_data_bits, - uint8_t* decrypted_data) { - if(encrypted_data_bits < 8) { - uint8_t decrypted_byte = 0; - decrypted_byte |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(encrypted_data[0], 0)) << 0; - decrypted_byte |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(encrypted_data[0], 1)) << 1; - decrypted_byte |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(encrypted_data[0], 2)) << 2; - decrypted_byte |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(encrypted_data[0], 3)) << 3; - decrypted_data[0] = decrypted_byte; - } else { - for(size_t i = 0; i < encrypted_data_bits / 8; i++) { - decrypted_data[i] = crypto1_byte(crypto, 0, 0) ^ encrypted_data[i]; - } - } -} - -void mf_crypto1_encrypt( - Crypto1* crypto, - uint8_t* keystream, - uint8_t* plain_data, - uint16_t plain_data_bits, - uint8_t* encrypted_data, - uint8_t* encrypted_parity) { - if(plain_data_bits < 8) { - encrypted_data[0] = 0; - for(size_t i = 0; i < plain_data_bits; i++) { - encrypted_data[0] |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(plain_data[0], i)) << i; - } - } else { - memset(encrypted_parity, 0, plain_data_bits / 8 + 1); - for(uint8_t i = 0; i < plain_data_bits / 8; i++) { - encrypted_data[i] = crypto1_byte(crypto, keystream ? keystream[i] : 0, 0) ^ - plain_data[i]; - encrypted_parity[i / 8] |= - (((crypto1_filter(crypto->odd) ^ nfc_util_odd_parity8(plain_data[i])) & 0x01) - << (7 - (i & 0x0007))); - } - } -} - bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_rx) { furi_assert(emulator); furi_assert(tx_rx); @@ -819,7 +777,7 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_ tx_rx->rx_bits); break; } - mf_crypto1_decrypt(&emulator->crypto, tx_rx->rx_data, tx_rx->rx_bits, plain_data); + crypto1_decrypt(&emulator->crypto, tx_rx->rx_data, tx_rx->rx_bits, plain_data); } if(plain_data[0] == 0x50 && plain_data[1] == 0x00) { @@ -857,7 +815,7 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_ tx_rx->tx_bits = sizeof(nt) * 8; tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent; } else { - mf_crypto1_encrypt( + crypto1_encrypt( &emulator->crypto, nt_keystream, nt, @@ -904,7 +862,7 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_ uint32_t ans = prng_successor(nonce, 96); uint8_t responce[4] = {}; nfc_util_num2bytes(ans, 4, responce); - mf_crypto1_encrypt( + crypto1_encrypt( &emulator->crypto, NULL, responce, @@ -938,7 +896,7 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_ // Send NACK uint8_t nack = 0x04; if(is_encrypted) { - mf_crypto1_encrypt( + crypto1_encrypt( &emulator->crypto, NULL, &nack, 4, tx_rx->tx_data, tx_rx->tx_parity); } else { tx_rx->tx_data[0] = nack; @@ -951,7 +909,7 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_ } nfca_append_crc16(block_data, 16); - mf_crypto1_encrypt( + crypto1_encrypt( &emulator->crypto, NULL, block_data, @@ -967,14 +925,14 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_ } // Send ACK uint8_t ack = 0x0A; - mf_crypto1_encrypt(&emulator->crypto, NULL, &ack, 4, tx_rx->tx_data, tx_rx->tx_parity); + crypto1_encrypt(&emulator->crypto, NULL, &ack, 4, tx_rx->tx_data, tx_rx->tx_parity); tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent; tx_rx->tx_bits = 4; if(!furi_hal_nfc_tx_rx(tx_rx, 300)) break; if(tx_rx->rx_bits != 18 * 8) break; - mf_crypto1_decrypt(&emulator->crypto, tx_rx->rx_data, tx_rx->rx_bits, plain_data); + crypto1_decrypt(&emulator->crypto, tx_rx->rx_data, tx_rx->rx_bits, plain_data); uint8_t block_data[16] = {}; memcpy(block_data, emulator->data.block[block].value, MF_CLASSIC_BLOCK_SIZE); if(mf_classic_is_sector_trailer(block)) { @@ -1002,7 +960,7 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_ } // Send ACK ack = 0x0A; - mf_crypto1_encrypt(&emulator->crypto, NULL, &ack, 4, tx_rx->tx_data, tx_rx->tx_parity); + crypto1_encrypt(&emulator->crypto, NULL, &ack, 4, tx_rx->tx_data, tx_rx->tx_parity); tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent; tx_rx->tx_bits = 4; } else { @@ -1015,8 +973,7 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_ // Send NACK uint8_t nack = 0x04; if(is_encrypted) { - mf_crypto1_encrypt( - &emulator->crypto, NULL, &nack, 4, tx_rx->tx_data, tx_rx->tx_parity); + crypto1_encrypt(&emulator->crypto, NULL, &nack, 4, tx_rx->tx_data, tx_rx->tx_parity); } else { tx_rx->tx_data[0] = nack; } @@ -1027,3 +984,143 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_ return true; } + +bool mf_classic_write_block( + FuriHalNfcTxRxContext* tx_rx, + MfClassicBlock* src_block, + uint8_t block_num, + MfClassicKey key_type, + uint64_t key) { + furi_assert(tx_rx); + furi_assert(src_block); + + Crypto1 crypto = {}; + uint8_t plain_data[18] = {}; + uint8_t resp = 0; + bool write_success = false; + + do { + furi_hal_nfc_sleep(); + if(!mf_classic_auth(tx_rx, block_num, key, key_type, &crypto)) { + FURI_LOG_D(TAG, "Auth fail"); + break; + } + // Send write command + plain_data[0] = MF_CLASSIC_WRITE_BLOCK_CMD; + plain_data[1] = block_num; + nfca_append_crc16(plain_data, 2); + crypto1_encrypt(&crypto, NULL, plain_data, 4 * 8, tx_rx->tx_data, tx_rx->tx_parity); + tx_rx->tx_bits = 4 * 8; + tx_rx->tx_rx_type = FuriHalNfcTxRxTypeRaw; + + if(furi_hal_nfc_tx_rx(tx_rx, 50)) { + if(tx_rx->rx_bits == 4) { + crypto1_decrypt(&crypto, tx_rx->rx_data, 4, &resp); + if(resp != 0x0A) { + FURI_LOG_D(TAG, "NACK received on write cmd: %02X", resp); + break; + } + } else { + FURI_LOG_D(TAG, "Not ACK received"); + break; + } + } else { + FURI_LOG_D(TAG, "Failed to send write cmd"); + break; + } + + // Send data + memcpy(plain_data, src_block->value, MF_CLASSIC_BLOCK_SIZE); + nfca_append_crc16(plain_data, MF_CLASSIC_BLOCK_SIZE); + crypto1_encrypt( + &crypto, + NULL, + plain_data, + (MF_CLASSIC_BLOCK_SIZE + 2) * 8, + tx_rx->tx_data, + tx_rx->tx_parity); + tx_rx->tx_bits = (MF_CLASSIC_BLOCK_SIZE + 2) * 8; + tx_rx->tx_rx_type = FuriHalNfcTxRxTypeRaw; + if(furi_hal_nfc_tx_rx(tx_rx, 50)) { + if(tx_rx->rx_bits == 4) { + crypto1_decrypt(&crypto, tx_rx->rx_data, 4, &resp); + if(resp != 0x0A) { + FURI_LOG_D(TAG, "NACK received on sending data"); + break; + } + } else { + FURI_LOG_D(TAG, "Not ACK received"); + break; + } + } else { + FURI_LOG_D(TAG, "Failed to send data"); + break; + } + write_success = true; + + // Send Halt + plain_data[0] = 0x50; + plain_data[1] = 0x00; + nfca_append_crc16(plain_data, 2); + crypto1_encrypt(&crypto, NULL, plain_data, 2 * 8, tx_rx->tx_data, tx_rx->tx_parity); + tx_rx->tx_bits = 2 * 8; + tx_rx->tx_rx_type = FuriHalNfcTxRxTypeRaw; + // No response is expected + furi_hal_nfc_tx_rx(tx_rx, 50); + } while(false); + + return write_success; +} + +bool mf_classic_write_sector( + FuriHalNfcTxRxContext* tx_rx, + MfClassicData* dest_data, + MfClassicData* src_data, + uint8_t sec_num) { + furi_assert(tx_rx); + furi_assert(dest_data); + furi_assert(src_data); + + uint8_t first_block = mf_classic_get_first_block_num_of_sector(sec_num); + uint8_t total_blocks = mf_classic_get_blocks_num_in_sector(sec_num); + MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(dest_data, sec_num); + bool key_a_found = mf_classic_is_key_found(dest_data, sec_num, MfClassicKeyA); + bool key_b_found = mf_classic_is_key_found(dest_data, sec_num, MfClassicKeyB); + + bool write_success = true; + for(size_t i = first_block; i < first_block + total_blocks; i++) { + // Compare blocks + if(memcmp(dest_data->block[i].value, src_data->block[i].value, MF_CLASSIC_BLOCK_SIZE)) { + bool key_a_write_allowed = mf_classic_is_allowed_access_data_block( + dest_data, i, MfClassicKeyA, MfClassicActionDataWrite); + bool key_b_write_allowed = mf_classic_is_allowed_access_data_block( + dest_data, i, MfClassicKeyB, MfClassicActionDataWrite); + + if(key_a_found && key_a_write_allowed) { + FURI_LOG_I(TAG, "Writing block %d with key A", i); + uint64_t key = nfc_util_bytes2num(sec_tr->key_a, 6); + if(!mf_classic_write_block(tx_rx, &src_data->block[i], i, MfClassicKeyA, key)) { + FURI_LOG_E(TAG, "Failed to write block %d", i); + write_success = false; + break; + } + } else if(key_b_found && key_b_write_allowed) { + FURI_LOG_I(TAG, "Writing block %d with key A", i); + uint64_t key = nfc_util_bytes2num(sec_tr->key_b, 6); + if(!mf_classic_write_block(tx_rx, &src_data->block[i], i, MfClassicKeyB, key)) { + FURI_LOG_E(TAG, "Failed to write block %d", i); + write_success = false; + break; + } + } else { + FURI_LOG_E(TAG, "Failed to find key with write access"); + write_success = false; + break; + } + } else { + FURI_LOG_D(TAG, "Blocks %d are equal", i); + } + } + + return write_success; +} diff --git a/lib/nfc/protocols/mifare_classic.h b/lib/nfc/protocols/mifare_classic.h index ead846e42..d5467b100 100644 --- a/lib/nfc/protocols/mifare_classic.h +++ b/lib/nfc/protocols/mifare_classic.h @@ -27,6 +27,20 @@ typedef enum { MfClassicKeyB, } MfClassicKey; +typedef enum { + MfClassicActionDataRead, + MfClassicActionDataWrite, + MfClassicActionDataInc, + MfClassicActionDataDec, + + MfClassicActionKeyARead, + MfClassicActionKeyAWrite, + MfClassicActionKeyBRead, + MfClassicActionKeyBWrite, + MfClassicActionACRead, + MfClassicActionACWrite, +} MfClassicAction; + typedef struct { uint8_t value[MF_CLASSIC_BLOCK_SIZE]; } MfClassicBlock; @@ -90,6 +104,18 @@ bool mf_classic_is_sector_trailer(uint8_t block); uint8_t mf_classic_get_sector_by_block(uint8_t block); +bool mf_classic_is_allowed_access_sector_trailer( + MfClassicData* data, + uint8_t block_num, + MfClassicKey key, + MfClassicAction action); + +bool mf_classic_is_allowed_access_data_block( + MfClassicData* data, + uint8_t block_num, + MfClassicKey key, + MfClassicAction action); + bool mf_classic_is_key_found(MfClassicData* data, uint8_t sector_num, MfClassicKey key_type); void mf_classic_set_key_found( @@ -104,6 +130,10 @@ bool mf_classic_is_block_read(MfClassicData* data, uint8_t block_num); void mf_classic_set_block_read(MfClassicData* data, uint8_t block_num, MfClassicBlock* block_data); +bool mf_classic_is_sector_data_read(MfClassicData* data, uint8_t sector_num); + +void mf_classic_set_sector_data_not_read(MfClassicData* data); + bool mf_classic_is_sector_read(MfClassicData* data, uint8_t sector_num); bool mf_classic_is_card_read(MfClassicData* data); @@ -145,3 +175,16 @@ uint8_t mf_classic_read_card( uint8_t mf_classic_update_card(FuriHalNfcTxRxContext* tx_rx, MfClassicData* data); bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_rx); + +bool mf_classic_write_block( + FuriHalNfcTxRxContext* tx_rx, + MfClassicBlock* src_block, + uint8_t block_num, + MfClassicKey key_type, + uint64_t key); + +bool mf_classic_write_sector( + FuriHalNfcTxRxContext* tx_rx, + MfClassicData* dest_data, + MfClassicData* src_data, + uint8_t sec_num); diff --git a/lib/scons b/lib/scons deleted file mode 160000 index c2d1f09f6..000000000 --- a/lib/scons +++ /dev/null @@ -1 +0,0 @@ -Subproject commit c2d1f09f615a9ef3fb5497a7e8e5ee2c900d21a7 diff --git a/lib/subghz/blocks/decoder.c b/lib/subghz/blocks/decoder.c index d2237f6c4..f491c87bf 100644 --- a/lib/subghz/blocks/decoder.c +++ b/lib/subghz/blocks/decoder.c @@ -7,6 +7,16 @@ void subghz_protocol_blocks_add_bit(SubGhzBlockDecoder* decoder, uint8_t bit) { decoder->decode_count_bit++; } +void subghz_protocol_blocks_add_to_128_bit( + SubGhzBlockDecoder* decoder, + uint8_t bit, + uint64_t* head_64_bit) { + if(++decoder->decode_count_bit > 64) { + (*head_64_bit) = ((*head_64_bit) << 1) | (decoder->decode_data >> 63); + } + decoder->decode_data = decoder->decode_data << 1 | bit; +} + uint8_t subghz_protocol_blocks_get_hash_data(SubGhzBlockDecoder* decoder, size_t len) { uint8_t hash = 0; uint8_t* p = (uint8_t*)&decoder->decode_data; diff --git a/lib/subghz/blocks/decoder.h b/lib/subghz/blocks/decoder.h index 25549fab3..a5e561e35 100644 --- a/lib/subghz/blocks/decoder.h +++ b/lib/subghz/blocks/decoder.h @@ -24,6 +24,17 @@ struct SubGhzBlockDecoder { */ void subghz_protocol_blocks_add_bit(SubGhzBlockDecoder* decoder, uint8_t bit); +/** + * Add data to_128 bit when decoding. + * @param decoder Pointer to a SubGhzBlockDecoder instance + * @param head_64_bit Pointer to a head_64_bit + * @param bit data, 1bit + */ +void subghz_protocol_blocks_add_to_128_bit( + SubGhzBlockDecoder* decoder, + uint8_t bit, + uint64_t* head_64_bit); + /** * Getting the hash sum of the last randomly received parcel. * @param decoder Pointer to a SubGhzBlockDecoder instance diff --git a/lib/subghz/blocks/math.c b/lib/subghz/blocks/math.c index 588d4effc..24202ad1c 100644 --- a/lib/subghz/blocks/math.c +++ b/lib/subghz/blocks/math.c @@ -1,16 +1,16 @@ #include "math.h" -uint64_t subghz_protocol_blocks_reverse_key(uint64_t key, uint8_t count_bit) { - uint64_t key_reverse = 0; - for(uint8_t i = 0; i < count_bit; i++) { - key_reverse = key_reverse << 1 | bit_read(key, i); +uint64_t subghz_protocol_blocks_reverse_key(uint64_t key, uint8_t bit_count) { + uint64_t reverse_key = 0; + for(uint8_t i = 0; i < bit_count; i++) { + reverse_key = reverse_key << 1 | bit_read(key, i); } - return key_reverse; + return reverse_key; } -uint8_t subghz_protocol_blocks_get_parity(uint64_t key, uint8_t count_bit) { +uint8_t subghz_protocol_blocks_get_parity(uint64_t key, uint8_t bit_count) { uint8_t parity = 0; - for(uint8_t i = 0; i < count_bit; i++) { + for(uint8_t i = 0; i < bit_count; i++) { parity += bit_read(key, i); } return parity & 0x01; @@ -18,14 +18,14 @@ uint8_t subghz_protocol_blocks_get_parity(uint64_t key, uint8_t count_bit) { uint8_t subghz_protocol_blocks_crc4( uint8_t const message[], - unsigned nBytes, + size_t size, uint8_t polynomial, uint8_t init) { - unsigned remainder = init << 4; // LSBs are unused - unsigned poly = polynomial << 4; - unsigned bit; + uint8_t remainder = init << 4; // LSBs are unused + uint8_t poly = polynomial << 4; + uint8_t bit; - while(nBytes--) { + while(size--) { remainder ^= *message++; for(bit = 0; bit < 8; bit++) { if(remainder & 0x80) { @@ -40,16 +40,15 @@ uint8_t subghz_protocol_blocks_crc4( uint8_t subghz_protocol_blocks_crc7( uint8_t const message[], - unsigned nBytes, + size_t size, uint8_t polynomial, uint8_t init) { - unsigned remainder = init << 1; // LSB is unused - unsigned poly = polynomial << 1; - unsigned byte, bit; + uint8_t remainder = init << 1; // LSB is unused + uint8_t poly = polynomial << 1; - for(byte = 0; byte < nBytes; ++byte) { + for(size_t byte = 0; byte < size; ++byte) { remainder ^= message[byte]; - for(bit = 0; bit < 8; ++bit) { + for(uint8_t bit = 0; bit < 8; ++bit) { if(remainder & 0x80) { remainder = (remainder << 1) ^ poly; } else { @@ -62,15 +61,14 @@ uint8_t subghz_protocol_blocks_crc7( uint8_t subghz_protocol_blocks_crc8( uint8_t const message[], - unsigned nBytes, + size_t size, uint8_t polynomial, uint8_t init) { uint8_t remainder = init; - unsigned byte, bit; - for(byte = 0; byte < nBytes; ++byte) { + for(size_t byte = 0; byte < size; ++byte) { remainder ^= message[byte]; - for(bit = 0; bit < 8; ++bit) { + for(uint8_t bit = 0; bit < 8; ++bit) { if(remainder & 0x80) { remainder = (remainder << 1) ^ polynomial; } else { @@ -83,16 +81,15 @@ uint8_t subghz_protocol_blocks_crc8( uint8_t subghz_protocol_blocks_crc8le( uint8_t const message[], - unsigned nBytes, + size_t size, uint8_t polynomial, uint8_t init) { uint8_t remainder = subghz_protocol_blocks_reverse_key(init, 8); - unsigned byte, bit; polynomial = subghz_protocol_blocks_reverse_key(polynomial, 8); - for(byte = 0; byte < nBytes; ++byte) { + for(size_t byte = 0; byte < size; ++byte) { remainder ^= message[byte]; - for(bit = 0; bit < 8; ++bit) { + for(uint8_t bit = 0; bit < 8; ++bit) { if(remainder & 1) { remainder = (remainder >> 1) ^ polynomial; } else { @@ -105,15 +102,14 @@ uint8_t subghz_protocol_blocks_crc8le( uint16_t subghz_protocol_blocks_crc16lsb( uint8_t const message[], - unsigned nBytes, + size_t size, uint16_t polynomial, uint16_t init) { uint16_t remainder = init; - unsigned byte, bit; - for(byte = 0; byte < nBytes; ++byte) { + for(size_t byte = 0; byte < size; ++byte) { remainder ^= message[byte]; - for(bit = 0; bit < 8; ++bit) { + for(uint8_t bit = 0; bit < 8; ++bit) { if(remainder & 1) { remainder = (remainder >> 1) ^ polynomial; } else { @@ -126,15 +122,14 @@ uint16_t subghz_protocol_blocks_crc16lsb( uint16_t subghz_protocol_blocks_crc16( uint8_t const message[], - unsigned nBytes, + size_t size, uint16_t polynomial, uint16_t init) { uint16_t remainder = init; - unsigned byte, bit; - for(byte = 0; byte < nBytes; ++byte) { + for(size_t byte = 0; byte < size; ++byte) { remainder ^= message[byte] << 8; - for(bit = 0; bit < 8; ++bit) { + for(uint8_t bit = 0; bit < 8; ++bit) { if(remainder & 0x8000) { remainder = (remainder << 1) ^ polynomial; } else { @@ -147,18 +142,18 @@ uint16_t subghz_protocol_blocks_crc16( uint8_t subghz_protocol_blocks_lfsr_digest8( uint8_t const message[], - unsigned bytes, + size_t size, uint8_t gen, uint8_t key) { uint8_t sum = 0; - for(unsigned k = 0; k < bytes; ++k) { - uint8_t data = message[k]; + for(size_t byte = 0; byte < size; ++byte) { + uint8_t data = message[byte]; for(int i = 7; i >= 0; --i) { // XOR key into sum if data bit is set if((data >> i) & 1) sum ^= key; - // roll the key right (actually the lsb is dropped here) - // and apply the gen (needs to include the dropped lsb as msb) + // roll the key right (actually the LSB is dropped here) + // and apply the gen (needs to include the dropped LSB as MSB) if(key & 1) key = (key >> 1) ^ gen; else @@ -170,22 +165,22 @@ uint8_t subghz_protocol_blocks_lfsr_digest8( uint8_t subghz_protocol_blocks_lfsr_digest8_reflect( uint8_t const message[], - int bytes, + size_t size, uint8_t gen, uint8_t key) { uint8_t sum = 0; // Process message from last byte to first byte (reflected) - for(int k = bytes - 1; k >= 0; --k) { - uint8_t data = message[k]; + for(int byte = size - 1; byte >= 0; --byte) { + uint8_t data = message[byte]; // Process individual bits of each byte (reflected) - for(int i = 0; i < 8; ++i) { + for(uint8_t i = 0; i < 8; ++i) { // XOR key into sum if data bit is set if((data >> i) & 1) { sum ^= key; } - // roll the key left (actually the lsb is dropped here) - // and apply the gen (needs to include the dropped lsb as msb) + // roll the key left (actually the LSB is dropped here) + // and apply the gen (needs to include the dropped lsb as MSB) if(key & 0x80) key = (key << 1) ^ gen; else @@ -197,18 +192,18 @@ uint8_t subghz_protocol_blocks_lfsr_digest8_reflect( uint16_t subghz_protocol_blocks_lfsr_digest16( uint8_t const message[], - unsigned bytes, + size_t size, uint16_t gen, uint16_t key) { uint16_t sum = 0; - for(unsigned k = 0; k < bytes; ++k) { - uint8_t data = message[k]; - for(int i = 7; i >= 0; --i) { + for(size_t byte = 0; byte < size; ++byte) { + uint8_t data = message[byte]; + for(int8_t i = 7; i >= 0; --i) { // if data bit is set then xor with key if((data >> i) & 1) sum ^= key; - // roll the key right (actually the lsb is dropped here) - // and apply the gen (needs to include the dropped lsb as msb) + // roll the key right (actually the LSB is dropped here) + // and apply the gen (needs to include the dropped LSB as MSB) if(key & 1) key = (key >> 1) ^ gen; else @@ -216,4 +211,34 @@ uint16_t subghz_protocol_blocks_lfsr_digest16( } } return sum; +} + +uint8_t subghz_protocol_blocks_add_bytes(uint8_t const message[], size_t size) { + uint32_t result = 0; + for(size_t i = 0; i < size; ++i) { + result += message[i]; + } + return (uint8_t)result; +} + +uint8_t subghz_protocol_blocks_parity8(uint8_t byte) { + byte ^= byte >> 4; + byte &= 0xf; + return (0x6996 >> byte) & 1; +} + +uint8_t subghz_protocol_blocks_parity_bytes(uint8_t const message[], size_t size) { + uint8_t result = 0; + for(size_t i = 0; i < size; ++i) { + result ^= subghz_protocol_blocks_parity8(message[i]); + } + return result; +} + +uint8_t subghz_protocol_blocks_xor_bytes(uint8_t const message[], size_t size) { + uint8_t result = 0; + for(size_t i = 0; i < size; ++i) { + result ^= message[i]; + } + return result; } \ No newline at end of file diff --git a/lib/subghz/blocks/math.h b/lib/subghz/blocks/math.h index 275889484..a4f04271a 100644 --- a/lib/subghz/blocks/math.h +++ b/lib/subghz/blocks/math.h @@ -14,153 +14,202 @@ #ifdef __cplusplus extern "C" { #endif -/** - * Flip the data bitwise. - * @param key In data - * @param count_bit number of data bits - * @return Reverse data - **/ -uint64_t subghz_protocol_blocks_reverse_key(uint64_t key, uint8_t count_bit); -/** - * Get parity the data bitwise. - * @param key In data - * @param count_bit number of data bits - * @return parity - **/ -uint8_t subghz_protocol_blocks_get_parity(uint64_t key, uint8_t count_bit); +/** Flip the data bitwise + * + * @param key In data + * @param bit_count number of data bits + * + * @return Reverse data + */ +uint64_t subghz_protocol_blocks_reverse_key(uint64_t key, uint8_t bit_count); -/** - * CRC-4. - * @param message array of bytes to check - * @param nBytes number of bytes in message - * @param polynomial CRC polynomial - * @param init starting crc value - * @return CRC value - **/ +/** Get parity the data bitwise + * + * @param key In data + * @param bit_count number of data bits + * + * @return parity + */ +uint8_t subghz_protocol_blocks_get_parity(uint64_t key, uint8_t bit_count); + +/** CRC-4 + * + * @param message array of bytes to check + * @param size number of bytes in message + * @param polynomial CRC polynomial + * @param init starting crc value + * + * @return CRC value + */ uint8_t subghz_protocol_blocks_crc4( uint8_t const message[], - unsigned nBytes, + size_t size, uint8_t polynomial, uint8_t init); -/** - * CRC-7. - * @param message array of bytes to check - * @param nBytes number of bytes in message - * @param polynomial CRC polynomial - * @param init starting crc value - * @return CRC value - **/ +/** CRC-7 + * + * @param message array of bytes to check + * @param size number of bytes in message + * @param polynomial CRC polynomial + * @param init starting crc value + * + * @return CRC value + */ uint8_t subghz_protocol_blocks_crc7( uint8_t const message[], - unsigned nBytes, + size_t size, uint8_t polynomial, uint8_t init); -/** - * Generic Cyclic Redundancy Check CRC-8. - * Example polynomial: 0x31 = x8 + x5 + x4 + 1 (x8 is implicit) - * Example polynomial: 0x80 = x8 + x7 (a normal bit-by-bit parity XOR) - * @param message array of bytes to check - * @param nBytes number of bytes in message - * @param polynomial byte is from x^7 to x^0 (x^8 is implicitly one) - * @param init starting crc value - * @return CRC value - **/ +/** Generic Cyclic Redundancy Check CRC-8. Example polynomial: 0x31 = x8 + x5 + + * x4 + 1 (x8 is implicit) Example polynomial: 0x80 = x8 + x7 (a normal + * bit-by-bit parity XOR) + * + * @param message array of bytes to check + * @param size number of bytes in message + * @param polynomial byte is from x^7 to x^0 (x^8 is implicitly one) + * @param init starting crc value + * + * @return CRC value + */ uint8_t subghz_protocol_blocks_crc8( uint8_t const message[], - unsigned nBytes, + size_t size, uint8_t polynomial, uint8_t init); -/** - * "Little-endian" Cyclic Redundancy Check CRC-8 LE - * Input and output are reflected, i.e. least significant bit is shifted in first. - * @param message array of bytes to check - * @param nBytes number of bytes in message - * @param polynomial CRC polynomial - * @param init starting crc value - * @return CRC value - **/ +/** "Little-endian" Cyclic Redundancy Check CRC-8 LE Input and output are + * reflected, i.e. least significant bit is shifted in first + * + * @param message array of bytes to check + * @param size number of bytes in message + * @param polynomial CRC polynomial + * @param init starting crc value + * + * @return CRC value + */ uint8_t subghz_protocol_blocks_crc8le( uint8_t const message[], - unsigned nBytes, + size_t size, uint8_t polynomial, uint8_t init); -/** - * CRC-16 LSB. - * Input and output are reflected, i.e. least significant bit is shifted in first. - * Note that poly and init already need to be reflected. - * @param message array of bytes to check - * @param nBytes number of bytes in message - * @param polynomial CRC polynomial - * @param init starting crc value - * @return CRC value - **/ +/** CRC-16 LSB. Input and output are reflected, i.e. least significant bit is + * shifted in first. Note that poly and init already need to be reflected + * + * @param message array of bytes to check + * @param size number of bytes in message + * @param polynomial CRC polynomial + * @param init starting crc value + * + * @return CRC value + */ uint16_t subghz_protocol_blocks_crc16lsb( uint8_t const message[], - unsigned nBytes, + size_t size, uint16_t polynomial, uint16_t init); -/** - * CRC-16. - * @param message array of bytes to check - * @param nBytes number of bytes in message - * @param polynomial CRC polynomial - * @param init starting crc value - * @return CRC value - **/ +/** CRC-16 + * + * @param message array of bytes to check + * @param size number of bytes in message + * @param polynomial CRC polynomial + * @param init starting crc value + * + * @return CRC value + */ uint16_t subghz_protocol_blocks_crc16( uint8_t const message[], - unsigned nBytes, + size_t size, uint16_t polynomial, uint16_t init); -/** - * Digest-8 by "LFSR-based Toeplitz hash". - * @param message bytes of message data - * @param bytes number of bytes to digest - * @param gen key stream generator, needs to includes the MSB if the LFSR is rolling - * @param key initial key - * @return digest value - **/ +/** Digest-8 by "LFSR-based Toeplitz hash" + * + * @param message bytes of message data + * @param size number of bytes to digest + * @param gen key stream generator, needs to includes the MSB if the + * LFSR is rolling + * @param key initial key + * + * @return digest value + */ uint8_t subghz_protocol_blocks_lfsr_digest8( uint8_t const message[], - unsigned bytes, + size_t size, uint8_t gen, uint8_t key); -/** - * Digest-8 by "LFSR-based Toeplitz hash", byte reflect, bit reflect. - * @param message bytes of message data - * @param bytes number of bytes to digest - * @param gen key stream generator, needs to includes the MSB if the LFSR is rolling - * @param key initial key - * @return digest value - **/ +/** Digest-8 by "LFSR-based Toeplitz hash", byte reflect, bit reflect + * + * @param message bytes of message data + * @param size number of bytes to digest + * @param gen key stream generator, needs to includes the MSB if the + * LFSR is rolling + * @param key initial key + * + * @return digest value + */ uint8_t subghz_protocol_blocks_lfsr_digest8_reflect( uint8_t const message[], - int bytes, + size_t size, uint8_t gen, uint8_t key); -/** - * Digest-16 by "LFSR-based Toeplitz hash". - * @param message bytes of message data - * @param bytes number of bytes to digest - * @param gen key stream generator, needs to includes the MSB if the LFSR is rolling - * @param key initial key - * @return digest value - **/ +/** Digest-16 by "LFSR-based Toeplitz hash" + * + * @param message bytes of message data + * @param size number of bytes to digest + * @param gen key stream generator, needs to includes the MSB if the + * LFSR is rolling + * @param key initial key + * + * @return digest value + */ uint16_t subghz_protocol_blocks_lfsr_digest16( uint8_t const message[], - unsigned bytes, + size_t size, uint16_t gen, uint16_t key); +/** Compute Addition of a number of bytes + * + * @param message bytes of message data + * @param size number of bytes to sum + * + * @return summation value + */ +uint8_t subghz_protocol_blocks_add_bytes(uint8_t const message[], size_t size); + +/** Compute bit parity of a single byte (8 bits) + * + * @param byte single byte to check + * + * @return 1 odd parity, 0 even parity + */ +uint8_t subghz_protocol_blocks_parity8(uint8_t byte); + +/** Compute bit parity of a number of bytes + * + * @param message bytes of message data + * @param size number of bytes to sum + * + * @return 1 odd parity, 0 even parity + */ +uint8_t subghz_protocol_blocks_parity_bytes(uint8_t const message[], size_t size); + +/** Compute XOR (byte-wide parity) of a number of bytes + * + * @param message bytes of message data + * @param size number of bytes to sum + * + * @return summation value, per bit-position 1 odd parity, 0 even parity + */ +uint8_t subghz_protocol_blocks_xor_bytes(uint8_t const message[], size_t size); + #ifdef __cplusplus } #endif diff --git a/lib/subghz/protocols/keeloq.c b/lib/subghz/protocols/keeloq.c index ae6588e7a..eef1d0937 100644 --- a/lib/subghz/protocols/keeloq.c +++ b/lib/subghz/protocols/keeloq.c @@ -529,6 +529,24 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector( return 1; } break; + case KEELOQ_LEARNING_MAGIC_SERIAL_TYPE_2: + man = subghz_protocol_keeloq_common_magic_serial_type2_learning( + fix, manufacture_code->key); + decrypt = subghz_protocol_keeloq_common_decrypt(hop, man); + if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { + *manufacture_name = furi_string_get_cstr(manufacture_code->name); + return 1; + } + break; + case KEELOQ_LEARNING_MAGIC_SERIAL_TYPE_3: + man = subghz_protocol_keeloq_common_magic_serial_type3_learning( + fix, manufacture_code->key); + decrypt = subghz_protocol_keeloq_common_decrypt(hop, man); + if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { + *manufacture_name = furi_string_get_cstr(manufacture_code->name); + return 1; + } + break; case KEELOQ_LEARNING_UNKNOWN: // Simple Learning decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key); diff --git a/lib/subghz/protocols/keeloq_common.c b/lib/subghz/protocols/keeloq_common.c index 6c9bc461e..ddbf1c917 100644 --- a/lib/subghz/protocols/keeloq_common.c +++ b/lib/subghz/protocols/keeloq_common.c @@ -94,6 +94,34 @@ inline uint64_t inline uint64_t subghz_protocol_keeloq_common_magic_serial_type1_learning(uint32_t data, uint64_t man) { - return man | ((uint64_t)data << 40) | + return (man & 0xFFFFFFFF) | ((uint64_t)data << 40) | ((uint64_t)(((data & 0xff) + ((data >> 8) & 0xFF)) & 0xFF) << 32); } + +/** Magic_serial_type2 Learning + * @param data - btn+serial number (32bit) + * @param man - magic man (64bit) + * @return manufacture for this serial number (64bit) + */ + +inline uint64_t + subghz_protocol_keeloq_common_magic_serial_type2_learning(uint32_t data, uint64_t man) { + uint8_t* p = (uint8_t*)&data; + uint8_t* m = (uint8_t*)&man; + m[7] = p[0]; + m[6] = p[1]; + m[5] = p[2]; + m[4] = p[3]; + return man; +} + +/** Magic_serial_type3 Learning + * @param data - serial number (24bit) + * @param man - magic man (64bit) + * @return manufacture for this serial number (64bit) + */ + +inline uint64_t + subghz_protocol_keeloq_common_magic_serial_type3_learning(uint32_t data, uint64_t man) { + return (man & 0xFFFFFFFFFF000000) | (data & 0xFFFFFF); +} diff --git a/lib/subghz/protocols/keeloq_common.h b/lib/subghz/protocols/keeloq_common.h index 448388f0a..df3d0dbf3 100644 --- a/lib/subghz/protocols/keeloq_common.h +++ b/lib/subghz/protocols/keeloq_common.h @@ -22,6 +22,8 @@ #define KEELOQ_LEARNING_SECURE 3u #define KEELOQ_LEARNING_MAGIC_XOR_TYPE_1 4u #define KEELOQ_LEARNING_MAGIC_SERIAL_TYPE_1 5u +#define KEELOQ_LEARNING_MAGIC_SERIAL_TYPE_2 6u +#define KEELOQ_LEARNING_MAGIC_SERIAL_TYPE_3 7u /** * Simple Learning Encrypt @@ -72,3 +74,19 @@ uint64_t subghz_protocol_keeloq_common_magic_xor_type1_learning(uint32_t data, u */ uint64_t subghz_protocol_keeloq_common_magic_serial_type1_learning(uint32_t data, uint64_t man); + +/** Magic_serial_type2 Learning + * @param data - btn+serial number (32bit) + * @param man - magic man (64bit) + * @return manufacture for this serial number (64bit) + */ + +uint64_t subghz_protocol_keeloq_common_magic_serial_type2_learning(uint32_t data, uint64_t man); + +/** Magic_serial_type3 Learning + * @param data - btn+serial number (32bit) + * @param man - magic man (64bit) + * @return manufacture for this serial number (64bit) + */ + +uint64_t subghz_protocol_keeloq_common_magic_serial_type3_learning(uint32_t data, uint64_t man); diff --git a/lib/subghz/protocols/oregon2.h b/lib/subghz/protocols/oregon2.h deleted file mode 100644 index 981b25999..000000000 --- a/lib/subghz/protocols/oregon2.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -#include "base.h" -#define SUBGHZ_PROTOCOL_OREGON2_NAME "Oregon2" -extern const SubGhzProtocol subghz_protocol_oregon2; diff --git a/lib/subghz/protocols/protocol_items.c b/lib/subghz/protocols/protocol_items.c index 65ba03280..ebf9b93e4 100644 --- a/lib/subghz/protocols/protocol_items.c +++ b/lib/subghz/protocols/protocol_items.c @@ -12,7 +12,8 @@ const SubGhzProtocol* subghz_protocol_registry_items[] = { &subghz_protocol_chamb_code, &subghz_protocol_power_smart, &subghz_protocol_marantec, &subghz_protocol_bett, &subghz_protocol_doitrand, &subghz_protocol_phoenix_v2, &subghz_protocol_honeywell_wdb, &subghz_protocol_magellan, &subghz_protocol_intertechno_v3, - &subghz_protocol_clemsa, &subghz_protocol_oregon2}; + &subghz_protocol_clemsa, +}; const SubGhzProtocolRegistry subghz_protocol_registry = { .items = subghz_protocol_registry_items, diff --git a/lib/subghz/protocols/protocol_items.h b/lib/subghz/protocols/protocol_items.h index 9c187e795..23aa71be0 100644 --- a/lib/subghz/protocols/protocol_items.h +++ b/lib/subghz/protocols/protocol_items.h @@ -35,6 +35,5 @@ #include "magellan.h" #include "intertechno_v3.h" #include "clemsa.h" -#include "oregon2.h" extern const SubGhzProtocolRegistry subghz_protocol_registry; diff --git a/lib/subghz/protocols/raw.c b/lib/subghz/protocols/raw.c index b8e93c3d5..b639c93b9 100644 --- a/lib/subghz/protocols/raw.c +++ b/lib/subghz/protocols/raw.c @@ -32,6 +32,7 @@ struct SubGhzProtocolDecoderRAW { FuriString* file_name; size_t sample_write; bool last_level; + bool pause; }; struct SubGhzProtocolEncoderRAW { @@ -158,6 +159,7 @@ bool subghz_protocol_raw_save_to_file_init( instance->upload_raw = malloc(SUBGHZ_DOWNLOAD_MAX_SIZE * sizeof(int32_t)); instance->file_is_open = RAWFileIsOpenWrite; instance->sample_write = 0; + instance->pause = false; init = true; } while(0); @@ -199,6 +201,14 @@ void subghz_protocol_raw_save_to_file_stop(SubGhzProtocolDecoderRAW* instance) { instance->file_is_open = RAWFileIsOpenClose; } +void subghz_protocol_raw_save_to_file_pause(SubGhzProtocolDecoderRAW* instance, bool pause) { + furi_assert(instance); + + if(instance->pause != pause) { + instance->pause = pause; + } +} + size_t subghz_protocol_raw_get_sample_write(SubGhzProtocolDecoderRAW* instance) { return instance->sample_write + instance->ind_write; } @@ -234,7 +244,7 @@ void subghz_protocol_decoder_raw_feed(void* context, bool level, uint32_t durati furi_assert(context); SubGhzProtocolDecoderRAW* instance = context; - if(instance->upload_raw != NULL) { + if(!instance->pause && (instance->upload_raw != NULL)) { if(duration > subghz_protocol_raw_const.te_short) { if(instance->last_level != level) { instance->last_level = (level ? true : false); diff --git a/lib/subghz/protocols/raw.h b/lib/subghz/protocols/raw.h index 96c77553a..44c7faec5 100644 --- a/lib/subghz/protocols/raw.h +++ b/lib/subghz/protocols/raw.h @@ -103,6 +103,13 @@ void subghz_protocol_encoder_raw_free(void* context); */ void subghz_protocol_encoder_raw_stop(void* context); +/** + * pause writing to flash. + * @param context Pointer to a SubGhzProtocolEncoderRAW instance + * @param pause pause writing + */ +void subghz_protocol_raw_save_to_file_pause(SubGhzProtocolDecoderRAW* instance, bool pause); + /** * Set callback on completion of file transfer. * @param instance Pointer to a SubGhzProtocolEncoderRAW instance diff --git a/scripts/fbt/sdk.py b/scripts/fbt/sdk.py deleted file mode 100644 index 3d4a17b2f..000000000 --- a/scripts/fbt/sdk.py +++ /dev/null @@ -1,519 +0,0 @@ -import operator -import os -import csv -import operator - -from enum import Enum, auto -from typing import List, Set, ClassVar, Any -from dataclasses import dataclass, field - -from cxxheaderparser.parser import CxxParser - - -# 'Fixing' complaints about typedefs -CxxParser._fundamentals.discard("wchar_t") - -from cxxheaderparser.types import ( - EnumDecl, - Field, - ForwardDecl, - FriendDecl, - Function, - Method, - Typedef, - UsingAlias, - UsingDecl, - Variable, - Pointer, - Type, - PQName, - NameSpecifier, - FundamentalSpecifier, - Parameter, - Array, - Value, - Token, - FunctionType, -) - -from cxxheaderparser.parserstate import ( - State, - EmptyBlockState, - ClassBlockState, - ExternBlockState, - NamespaceBlockState, -) - - -@dataclass(frozen=True) -class ApiEntryFunction: - name: str - returns: str - params: str - - csv_type: ClassVar[str] = "Function" - - def dictify(self): - return dict(name=self.name, type=self.returns, params=self.params) - - -@dataclass(frozen=True) -class ApiEntryVariable: - name: str - var_type: str - - csv_type: ClassVar[str] = "Variable" - - def dictify(self): - return dict(name=self.name, type=self.var_type, params=None) - - -@dataclass(frozen=True) -class ApiHeader: - name: str - - csv_type: ClassVar[str] = "Header" - - def dictify(self): - return dict(name=self.name, type=None, params=None) - - -@dataclass -class ApiEntries: - # These are sets, to avoid creating duplicates when we have multiple - # declarations with same signature - functions: Set[ApiEntryFunction] = field(default_factory=set) - variables: Set[ApiEntryVariable] = field(default_factory=set) - headers: Set[ApiHeader] = field(default_factory=set) - - -class SymbolManager: - def __init__(self): - self.api = ApiEntries() - self.name_hashes = set() - - # Calculate hash of name and raise exception if it already is in the set - def _name_check(self, name: str): - name_hash = gnu_sym_hash(name) - if name_hash in self.name_hashes: - raise Exception(f"Hash collision on {name}") - self.name_hashes.add(name_hash) - - def add_function(self, function_def: ApiEntryFunction): - if function_def in self.api.functions: - return - self._name_check(function_def.name) - self.api.functions.add(function_def) - - def add_variable(self, variable_def: ApiEntryVariable): - if variable_def in self.api.variables: - return - self._name_check(variable_def.name) - self.api.variables.add(variable_def) - - def add_header(self, header: str): - self.api.headers.add(ApiHeader(header)) - - -def gnu_sym_hash(name: str): - h = 0x1505 - for c in name: - h = (h << 5) + h + ord(c) - return str(hex(h))[-8:] - - -class SdkCollector: - def __init__(self): - self.symbol_manager = SymbolManager() - - def add_header_to_sdk(self, header: str): - self.symbol_manager.add_header(header) - - def process_source_file_for_sdk(self, file_path: str): - visitor = SdkCxxVisitor(self.symbol_manager) - with open(file_path, "rt") as f: - content = f.read() - parser = CxxParser(file_path, content, visitor, None) - parser.parse() - - def get_api(self): - return self.symbol_manager.api - - -def stringify_array_dimension(size_descr): - if not size_descr: - return "" - return stringify_descr(size_descr) - - -def stringify_array_descr(type_descr): - assert isinstance(type_descr, Array) - return ( - stringify_descr(type_descr.array_of), - stringify_array_dimension(type_descr.size), - ) - - -def stringify_descr(type_descr): - if isinstance(type_descr, (NameSpecifier, FundamentalSpecifier)): - return type_descr.name - elif isinstance(type_descr, PQName): - return "::".join(map(stringify_descr, type_descr.segments)) - elif isinstance(type_descr, Pointer): - # Hack - if isinstance(type_descr.ptr_to, FunctionType): - return stringify_descr(type_descr.ptr_to) - return f"{stringify_descr(type_descr.ptr_to)}*" - elif isinstance(type_descr, Type): - return ( - f"{'const ' if type_descr.const else ''}" - f"{'volatile ' if type_descr.volatile else ''}" - f"{stringify_descr(type_descr.typename)}" - ) - elif isinstance(type_descr, Parameter): - return stringify_descr(type_descr.type) - elif isinstance(type_descr, Array): - # Hack for 2d arrays - if isinstance(type_descr.array_of, Array): - argtype, dimension = stringify_array_descr(type_descr.array_of) - return ( - f"{argtype}[{stringify_array_dimension(type_descr.size)}][{dimension}]" - ) - return f"{stringify_descr(type_descr.array_of)}[{stringify_array_dimension(type_descr.size)}]" - elif isinstance(type_descr, Value): - return " ".join(map(stringify_descr, type_descr.tokens)) - elif isinstance(type_descr, FunctionType): - return f"{stringify_descr(type_descr.return_type)} (*)({', '.join(map(stringify_descr, type_descr.parameters))})" - elif isinstance(type_descr, Token): - return type_descr.value - elif type_descr is None: - return "" - else: - raise Exception("unsupported type_descr: %s" % type_descr) - - -class SdkCxxVisitor: - def __init__(self, symbol_manager: SymbolManager): - self.api = symbol_manager - - def on_variable(self, state: State, v: Variable) -> None: - if not v.extern: - return - - self.api.add_variable( - ApiEntryVariable( - stringify_descr(v.name), - stringify_descr(v.type), - ) - ) - - def on_function(self, state: State, fn: Function) -> None: - if fn.inline or fn.has_body: - return - - self.api.add_function( - ApiEntryFunction( - stringify_descr(fn.name), - stringify_descr(fn.return_type), - ", ".join(map(stringify_descr, fn.parameters)) - + (", ..." if fn.vararg else ""), - ) - ) - - def on_define(self, state: State, content: str) -> None: - pass - - def on_pragma(self, state: State, content: str) -> None: - pass - - def on_include(self, state: State, filename: str) -> None: - pass - - def on_empty_block_start(self, state: EmptyBlockState) -> None: - pass - - def on_empty_block_end(self, state: EmptyBlockState) -> None: - pass - - def on_extern_block_start(self, state: ExternBlockState) -> None: - pass - - def on_extern_block_end(self, state: ExternBlockState) -> None: - pass - - def on_namespace_start(self, state: NamespaceBlockState) -> None: - pass - - def on_namespace_end(self, state: NamespaceBlockState) -> None: - pass - - def on_forward_decl(self, state: State, fdecl: ForwardDecl) -> None: - pass - - def on_typedef(self, state: State, typedef: Typedef) -> None: - pass - - def on_using_namespace(self, state: State, namespace: List[str]) -> None: - pass - - def on_using_alias(self, state: State, using: UsingAlias) -> None: - pass - - def on_using_declaration(self, state: State, using: UsingDecl) -> None: - pass - - def on_enum(self, state: State, enum: EnumDecl) -> None: - pass - - def on_class_start(self, state: ClassBlockState) -> None: - pass - - def on_class_field(self, state: State, f: Field) -> None: - pass - - def on_class_method(self, state: ClassBlockState, method: Method) -> None: - pass - - def on_class_friend(self, state: ClassBlockState, friend: FriendDecl) -> None: - pass - - def on_class_end(self, state: ClassBlockState) -> None: - pass - - -@dataclass(frozen=True) -class SdkVersion: - major: int = 0 - minor: int = 0 - - csv_type: ClassVar[str] = "Version" - - def __str__(self) -> str: - return f"{self.major}.{self.minor}" - - def as_int(self) -> int: - return ((self.major & 0xFFFF) << 16) | (self.minor & 0xFFFF) - - @staticmethod - def from_str(s: str) -> "SdkVersion": - major, minor = s.split(".") - return SdkVersion(int(major), int(minor)) - - def dictify(self) -> dict: - return dict(name=str(self), type=None, params=None) - - -class VersionBump(Enum): - NONE = auto() - MAJOR = auto() - MINOR = auto() - - -class ApiEntryState(Enum): - PENDING = "?" - APPROVED = "+" - DISABLED = "-" - # Special value for API version entry so users have less incentive to edit it - VERSION_PENDING = "v" - - -# Class that stores all known API entries, both enabled and disabled. -# Also keeps track of API versioning -# Allows comparison and update from newly-generated API -class SdkCache: - CSV_FIELD_NAMES = ("entry", "status", "name", "type", "params") - - def __init__(self, cache_file: str, load_version_only=False): - self.cache_file_name = cache_file - self.version = SdkVersion(0, 0) - self.sdk = ApiEntries() - self.disabled_entries = set() - self.new_entries = set() - self.loaded_dirty_version = False - - self.version_action = VersionBump.NONE - self._load_version_only = load_version_only - self.load_cache() - - def is_buildable(self) -> bool: - return ( - self.version != SdkVersion(0, 0) - and self.version_action == VersionBump.NONE - and not self._have_pending_entries() - ) - - def _filter_enabled(self, sdk_entries): - return sorted( - filter(lambda e: e not in self.disabled_entries, sdk_entries), - key=operator.attrgetter("name"), - ) - - def get_valid_names(self): - syms = set(map(lambda e: e.name, self.get_functions())) - syms.update(map(lambda e: e.name, self.get_variables())) - return syms - - def get_functions(self): - return self._filter_enabled(self.sdk.functions) - - def get_variables(self): - return self._filter_enabled(self.sdk.variables) - - def get_headers(self): - return self._filter_enabled(self.sdk.headers) - - def _get_entry_status(self, entry) -> str: - if entry in self.disabled_entries: - return ApiEntryState.DISABLED - elif entry in self.new_entries: - if isinstance(entry, SdkVersion): - return ApiEntryState.VERSION_PENDING - return ApiEntryState.PENDING - else: - return ApiEntryState.APPROVED - - def _format_entry(self, obj): - obj_dict = obj.dictify() - obj_dict.update( - dict( - entry=obj.csv_type, - status=self._get_entry_status(obj).value, - ) - ) - return obj_dict - - def save(self) -> None: - if self._load_version_only: - raise Exception("Only SDK version was loaded, cannot save") - - if self.version_action == VersionBump.MINOR: - self.version = SdkVersion(self.version.major, self.version.minor + 1) - elif self.version_action == VersionBump.MAJOR: - self.version = SdkVersion(self.version.major + 1, 0) - - if self._have_pending_entries(): - self.new_entries.add(self.version) - print( - f"API version is still WIP: {self.version}. Review the changes and re-run command." - ) - print(f"Entries to review:") - print( - "\n".join( - map( - str, - filter( - lambda e: not isinstance(e, SdkVersion), self.new_entries - ), - ) - ) - ) - else: - print(f"API version {self.version} is up to date") - - regenerate_csv = ( - self.loaded_dirty_version - or self._have_pending_entries() - or self.version_action != VersionBump.NONE - ) - - if regenerate_csv: - str_cache_entries = [self.version] - name_getter = operator.attrgetter("name") - str_cache_entries.extend(sorted(self.sdk.headers, key=name_getter)) - str_cache_entries.extend(sorted(self.sdk.functions, key=name_getter)) - str_cache_entries.extend(sorted(self.sdk.variables, key=name_getter)) - - with open(self.cache_file_name, "wt", newline="") as f: - writer = csv.DictWriter(f, fieldnames=SdkCache.CSV_FIELD_NAMES) - writer.writeheader() - - for entry in str_cache_entries: - writer.writerow(self._format_entry(entry)) - - def _process_entry(self, entry_dict: dict) -> None: - entry_class = entry_dict["entry"] - entry_status = entry_dict["status"] - entry_name = entry_dict["name"] - - entry = None - if entry_class == SdkVersion.csv_type: - self.version = SdkVersion.from_str(entry_name) - if entry_status == ApiEntryState.VERSION_PENDING.value: - self.loaded_dirty_version = True - elif entry_class == ApiHeader.csv_type: - self.sdk.headers.add(entry := ApiHeader(entry_name)) - elif entry_class == ApiEntryFunction.csv_type: - self.sdk.functions.add( - entry := ApiEntryFunction( - entry_name, - entry_dict["type"], - entry_dict["params"], - ) - ) - elif entry_class == ApiEntryVariable.csv_type: - self.sdk.variables.add( - entry := ApiEntryVariable(entry_name, entry_dict["type"]) - ) - else: - print(entry_dict) - raise Exception("Unknown entry type: %s" % entry_class) - - if entry is None: - return - - if entry_status == ApiEntryState.DISABLED.value: - self.disabled_entries.add(entry) - elif entry_status == ApiEntryState.PENDING.value: - self.new_entries.add(entry) - - def load_cache(self) -> None: - if not os.path.exists(self.cache_file_name): - raise Exception( - f"Cannot load symbol cache '{self.cache_file_name}'! File does not exist" - ) - - with open(self.cache_file_name, "rt") as f: - reader = csv.DictReader(f) - for row in reader: - self._process_entry(row) - if self._load_version_only and row.get("entry") == SdkVersion.csv_type: - break - - def _have_pending_entries(self) -> bool: - return any( - filter( - lambda e: not isinstance(e, SdkVersion), - self.new_entries, - ) - ) - - def sync_sets( - self, known_set: Set[Any], new_set: Set[Any], update_version: bool = True - ): - new_entries = new_set - known_set - if new_entries: - print(f"New: {new_entries}") - known_set |= new_entries - self.new_entries |= new_entries - if update_version and self.version_action == VersionBump.NONE: - self.version_action = VersionBump.MINOR - removed_entries = known_set - new_set - if removed_entries: - print(f"Removed: {removed_entries}") - known_set -= removed_entries - # If any of removed entries was a part of active API, that's a major bump - if update_version and any( - filter( - lambda e: e not in self.disabled_entries - and e not in self.new_entries, - removed_entries, - ) - ): - self.version_action = VersionBump.MAJOR - self.disabled_entries -= removed_entries - self.new_entries -= removed_entries - - def validate_api(self, api: ApiEntries) -> None: - self.sync_sets(self.sdk.headers, api.headers, False) - self.sync_sets(self.sdk.functions, api.functions) - self.sync_sets(self.sdk.variables, api.variables) diff --git a/scripts/fbt/sdk/__init__.py b/scripts/fbt/sdk/__init__.py new file mode 100644 index 000000000..27da5f7c8 --- /dev/null +++ b/scripts/fbt/sdk/__init__.py @@ -0,0 +1,44 @@ +from typing import Set, ClassVar +from dataclasses import dataclass, field + + +@dataclass(frozen=True) +class ApiEntryFunction: + name: str + returns: str + params: str + + csv_type: ClassVar[str] = "Function" + + def dictify(self): + return dict(name=self.name, type=self.returns, params=self.params) + + +@dataclass(frozen=True) +class ApiEntryVariable: + name: str + var_type: str + + csv_type: ClassVar[str] = "Variable" + + def dictify(self): + return dict(name=self.name, type=self.var_type, params=None) + + +@dataclass(frozen=True) +class ApiHeader: + name: str + + csv_type: ClassVar[str] = "Header" + + def dictify(self): + return dict(name=self.name, type=None, params=None) + + +@dataclass +class ApiEntries: + # These are sets, to avoid creating duplicates when we have multiple + # declarations with same signature + functions: Set[ApiEntryFunction] = field(default_factory=set) + variables: Set[ApiEntryVariable] = field(default_factory=set) + headers: Set[ApiHeader] = field(default_factory=set) diff --git a/scripts/fbt/sdk/cache.py b/scripts/fbt/sdk/cache.py new file mode 100644 index 000000000..62d42798c --- /dev/null +++ b/scripts/fbt/sdk/cache.py @@ -0,0 +1,260 @@ +import operator +import os +import csv +import operator + +from enum import Enum, auto +from typing import Set, ClassVar, Any +from dataclasses import dataclass + +from ansi.color import fg + +from . import ( + ApiEntries, + ApiEntryFunction, + ApiEntryVariable, + ApiHeader, +) + + +@dataclass(frozen=True) +class SdkVersion: + major: int = 0 + minor: int = 0 + + csv_type: ClassVar[str] = "Version" + + def __str__(self) -> str: + return f"{self.major}.{self.minor}" + + def as_int(self) -> int: + return ((self.major & 0xFFFF) << 16) | (self.minor & 0xFFFF) + + @staticmethod + def from_str(s: str) -> "SdkVersion": + major, minor = s.split(".") + return SdkVersion(int(major), int(minor)) + + def dictify(self) -> dict: + return dict(name=str(self), type=None, params=None) + + +class VersionBump(Enum): + NONE = auto() + MAJOR = auto() + MINOR = auto() + + +class ApiEntryState(Enum): + PENDING = "?" + APPROVED = "+" + DISABLED = "-" + # Special value for API version entry so users have less incentive to edit it + VERSION_PENDING = "v" + + +# Class that stores all known API entries, both enabled and disabled. +# Also keeps track of API versioning +# Allows comparison and update from newly-generated API +class SdkCache: + CSV_FIELD_NAMES = ("entry", "status", "name", "type", "params") + + def __init__(self, cache_file: str, load_version_only=False): + self.cache_file_name = cache_file + self.version = SdkVersion(0, 0) + self.sdk = ApiEntries() + self.disabled_entries = set() + self.new_entries = set() + self.loaded_dirty_version = False + + self.version_action = VersionBump.NONE + self._load_version_only = load_version_only + self.load_cache() + + def is_buildable(self) -> bool: + return ( + self.version != SdkVersion(0, 0) + and self.version_action == VersionBump.NONE + and not self._have_pending_entries() + ) + + def _filter_enabled(self, sdk_entries): + return sorted( + filter(lambda e: e not in self.disabled_entries, sdk_entries), + key=operator.attrgetter("name"), + ) + + def get_valid_names(self): + syms = set(map(lambda e: e.name, self.get_functions())) + syms.update(map(lambda e: e.name, self.get_variables())) + return syms + + def get_functions(self): + return self._filter_enabled(self.sdk.functions) + + def get_variables(self): + return self._filter_enabled(self.sdk.variables) + + def get_headers(self): + return self._filter_enabled(self.sdk.headers) + + def _get_entry_status(self, entry) -> str: + if entry in self.disabled_entries: + return ApiEntryState.DISABLED + elif entry in self.new_entries: + if isinstance(entry, SdkVersion): + return ApiEntryState.VERSION_PENDING + return ApiEntryState.PENDING + else: + return ApiEntryState.APPROVED + + def _format_entry(self, obj): + obj_dict = obj.dictify() + obj_dict.update( + dict( + entry=obj.csv_type, + status=self._get_entry_status(obj).value, + ) + ) + return obj_dict + + def save(self) -> None: + if self._load_version_only: + raise Exception("Only SDK version was loaded, cannot save") + + if self.version_action == VersionBump.MINOR: + self.version = SdkVersion(self.version.major, self.version.minor + 1) + elif self.version_action == VersionBump.MAJOR: + self.version = SdkVersion(self.version.major + 1, 0) + + if self._have_pending_entries(): + self.new_entries.add(self.version) + print( + fg.red( + f"API version is still WIP: {self.version}. Review the changes and re-run command." + ) + ) + print(f"CSV file entries to mark up:") + print( + fg.yellow( + "\n".join( + map( + str, + filter( + lambda e: not isinstance(e, SdkVersion), + self.new_entries, + ), + ) + ) + ) + ) + else: + print(fg.green(f"API version {self.version} is up to date")) + + regenerate_csv = ( + self.loaded_dirty_version + or self._have_pending_entries() + or self.version_action != VersionBump.NONE + ) + + if regenerate_csv: + str_cache_entries = [self.version] + name_getter = operator.attrgetter("name") + str_cache_entries.extend(sorted(self.sdk.headers, key=name_getter)) + str_cache_entries.extend(sorted(self.sdk.functions, key=name_getter)) + str_cache_entries.extend(sorted(self.sdk.variables, key=name_getter)) + + with open(self.cache_file_name, "wt", newline="") as f: + writer = csv.DictWriter(f, fieldnames=SdkCache.CSV_FIELD_NAMES) + writer.writeheader() + + for entry in str_cache_entries: + writer.writerow(self._format_entry(entry)) + + def _process_entry(self, entry_dict: dict) -> None: + entry_class = entry_dict["entry"] + entry_status = entry_dict["status"] + entry_name = entry_dict["name"] + + entry = None + if entry_class == SdkVersion.csv_type: + self.version = SdkVersion.from_str(entry_name) + if entry_status == ApiEntryState.VERSION_PENDING.value: + self.loaded_dirty_version = True + elif entry_class == ApiHeader.csv_type: + self.sdk.headers.add(entry := ApiHeader(entry_name)) + elif entry_class == ApiEntryFunction.csv_type: + self.sdk.functions.add( + entry := ApiEntryFunction( + entry_name, + entry_dict["type"], + entry_dict["params"], + ) + ) + elif entry_class == ApiEntryVariable.csv_type: + self.sdk.variables.add( + entry := ApiEntryVariable(entry_name, entry_dict["type"]) + ) + else: + print(entry_dict) + raise Exception("Unknown entry type: %s" % entry_class) + + if entry is None: + return + + if entry_status == ApiEntryState.DISABLED.value: + self.disabled_entries.add(entry) + elif entry_status == ApiEntryState.PENDING.value: + self.new_entries.add(entry) + + def load_cache(self) -> None: + if not os.path.exists(self.cache_file_name): + raise Exception( + f"Cannot load symbol cache '{self.cache_file_name}'! File does not exist" + ) + + with open(self.cache_file_name, "rt") as f: + reader = csv.DictReader(f) + for row in reader: + self._process_entry(row) + if self._load_version_only and row.get("entry") == SdkVersion.csv_type: + break + + def _have_pending_entries(self) -> bool: + return any( + filter( + lambda e: not isinstance(e, SdkVersion), + self.new_entries, + ) + ) + + def sync_sets( + self, known_set: Set[Any], new_set: Set[Any], update_version: bool = True + ): + new_entries = new_set - known_set + if new_entries: + print(f"New: {new_entries}") + known_set |= new_entries + self.new_entries |= new_entries + if update_version and self.version_action == VersionBump.NONE: + self.version_action = VersionBump.MINOR + removed_entries = known_set - new_set + if removed_entries: + print(f"Removed: {removed_entries}") + known_set -= removed_entries + # If any of removed entries was a part of active API, that's a major bump + if update_version and any( + filter( + lambda e: e not in self.disabled_entries + and e not in self.new_entries, + removed_entries, + ) + ): + self.version_action = VersionBump.MAJOR + self.disabled_entries -= removed_entries + self.new_entries -= removed_entries + + def validate_api(self, api: ApiEntries) -> None: + self.sync_sets(self.sdk.headers, api.headers, False) + self.sync_sets(self.sdk.functions, api.functions) + self.sync_sets(self.sdk.variables, api.variables) diff --git a/scripts/fbt/sdk/collector.py b/scripts/fbt/sdk/collector.py new file mode 100644 index 000000000..578a8c7a6 --- /dev/null +++ b/scripts/fbt/sdk/collector.py @@ -0,0 +1,238 @@ +from typing import List + +from cxxheaderparser.parser import CxxParser +from . import ( + ApiEntries, + ApiEntryFunction, + ApiEntryVariable, + ApiHeader, +) + + +# 'Fixing' complaints about typedefs +CxxParser._fundamentals.discard("wchar_t") + +from cxxheaderparser.types import ( + EnumDecl, + Field, + ForwardDecl, + FriendDecl, + Function, + Method, + Typedef, + UsingAlias, + UsingDecl, + Variable, + Pointer, + Type, + PQName, + NameSpecifier, + FundamentalSpecifier, + Parameter, + Array, + Value, + Token, + FunctionType, +) + +from cxxheaderparser.parserstate import ( + State, + EmptyBlockState, + ClassBlockState, + ExternBlockState, + NamespaceBlockState, +) + + +class SymbolManager: + def __init__(self): + self.api = ApiEntries() + self.name_hashes = set() + + # Calculate hash of name and raise exception if it already is in the set + def _name_check(self, name: str): + name_hash = gnu_sym_hash(name) + if name_hash in self.name_hashes: + raise Exception(f"Hash collision on {name}") + self.name_hashes.add(name_hash) + + def add_function(self, function_def: ApiEntryFunction): + if function_def in self.api.functions: + return + self._name_check(function_def.name) + self.api.functions.add(function_def) + + def add_variable(self, variable_def: ApiEntryVariable): + if variable_def in self.api.variables: + return + self._name_check(variable_def.name) + self.api.variables.add(variable_def) + + def add_header(self, header: str): + self.api.headers.add(ApiHeader(header)) + + +def gnu_sym_hash(name: str): + h = 0x1505 + for c in name: + h = (h << 5) + h + ord(c) + return str(hex(h))[-8:] + + +class SdkCollector: + def __init__(self): + self.symbol_manager = SymbolManager() + + def add_header_to_sdk(self, header: str): + self.symbol_manager.add_header(header) + + def process_source_file_for_sdk(self, file_path: str): + visitor = SdkCxxVisitor(self.symbol_manager) + with open(file_path, "rt") as f: + content = f.read() + parser = CxxParser(file_path, content, visitor, None) + parser.parse() + + def get_api(self): + return self.symbol_manager.api + + +def stringify_array_dimension(size_descr): + if not size_descr: + return "" + return stringify_descr(size_descr) + + +def stringify_array_descr(type_descr): + assert isinstance(type_descr, Array) + return ( + stringify_descr(type_descr.array_of), + stringify_array_dimension(type_descr.size), + ) + + +def stringify_descr(type_descr): + if isinstance(type_descr, (NameSpecifier, FundamentalSpecifier)): + return type_descr.name + elif isinstance(type_descr, PQName): + return "::".join(map(stringify_descr, type_descr.segments)) + elif isinstance(type_descr, Pointer): + # Hack + if isinstance(type_descr.ptr_to, FunctionType): + return stringify_descr(type_descr.ptr_to) + return f"{stringify_descr(type_descr.ptr_to)}*" + elif isinstance(type_descr, Type): + return ( + f"{'const ' if type_descr.const else ''}" + f"{'volatile ' if type_descr.volatile else ''}" + f"{stringify_descr(type_descr.typename)}" + ) + elif isinstance(type_descr, Parameter): + return stringify_descr(type_descr.type) + elif isinstance(type_descr, Array): + # Hack for 2d arrays + if isinstance(type_descr.array_of, Array): + argtype, dimension = stringify_array_descr(type_descr.array_of) + return ( + f"{argtype}[{stringify_array_dimension(type_descr.size)}][{dimension}]" + ) + return f"{stringify_descr(type_descr.array_of)}[{stringify_array_dimension(type_descr.size)}]" + elif isinstance(type_descr, Value): + return " ".join(map(stringify_descr, type_descr.tokens)) + elif isinstance(type_descr, FunctionType): + return f"{stringify_descr(type_descr.return_type)} (*)({', '.join(map(stringify_descr, type_descr.parameters))})" + elif isinstance(type_descr, Token): + return type_descr.value + elif type_descr is None: + return "" + else: + raise Exception("unsupported type_descr: %s" % type_descr) + + +class SdkCxxVisitor: + def __init__(self, symbol_manager: SymbolManager): + self.api = symbol_manager + + def on_variable(self, state: State, v: Variable) -> None: + if not v.extern: + return + + self.api.add_variable( + ApiEntryVariable( + stringify_descr(v.name), + stringify_descr(v.type), + ) + ) + + def on_function(self, state: State, fn: Function) -> None: + if fn.inline or fn.has_body: + return + + self.api.add_function( + ApiEntryFunction( + stringify_descr(fn.name), + stringify_descr(fn.return_type), + ", ".join(map(stringify_descr, fn.parameters)) + + (", ..." if fn.vararg else ""), + ) + ) + + def on_define(self, state: State, content: str) -> None: + pass + + def on_pragma(self, state: State, content: str) -> None: + pass + + def on_include(self, state: State, filename: str) -> None: + pass + + def on_empty_block_start(self, state: EmptyBlockState) -> None: + pass + + def on_empty_block_end(self, state: EmptyBlockState) -> None: + pass + + def on_extern_block_start(self, state: ExternBlockState) -> None: + pass + + def on_extern_block_end(self, state: ExternBlockState) -> None: + pass + + def on_namespace_start(self, state: NamespaceBlockState) -> None: + pass + + def on_namespace_end(self, state: NamespaceBlockState) -> None: + pass + + def on_forward_decl(self, state: State, fdecl: ForwardDecl) -> None: + pass + + def on_typedef(self, state: State, typedef: Typedef) -> None: + pass + + def on_using_namespace(self, state: State, namespace: List[str]) -> None: + pass + + def on_using_alias(self, state: State, using: UsingAlias) -> None: + pass + + def on_using_declaration(self, state: State, using: UsingDecl) -> None: + pass + + def on_enum(self, state: State, enum: EnumDecl) -> None: + pass + + def on_class_start(self, state: ClassBlockState) -> None: + pass + + def on_class_field(self, state: State, f: Field) -> None: + pass + + def on_class_method(self, state: ClassBlockState, method: Method) -> None: + pass + + def on_class_friend(self, state: ClassBlockState, friend: FriendDecl) -> None: + pass + + def on_class_end(self, state: ClassBlockState) -> None: + pass diff --git a/scripts/fbt_tools/fbt_assets.py b/scripts/fbt_tools/fbt_assets.py index f058d15f9..4fa5353d0 100644 --- a/scripts/fbt_tools/fbt_assets.py +++ b/scripts/fbt_tools/fbt_assets.py @@ -30,22 +30,25 @@ def dolphin_emitter(target, source, env): res_root_dir = source[0].Dir(env["DOLPHIN_RES_TYPE"]) source = [res_root_dir] source.extend( - env.GlobRecursive("*.*", res_root_dir), + env.GlobRecursive("*.*", res_root_dir.srcnode()), ) target_base_dir = target[0] env.Replace(_DOLPHIN_OUT_DIR=target[0]) if env["DOLPHIN_RES_TYPE"] == "external": - target = [] - target.extend( - map( - lambda node: target_base_dir.File( - res_root_dir.rel_path(node).replace(".png", ".bm") - ), - filter(lambda node: isinstance(node, SCons.Node.FS.File), source), - ) - ) + target = [target_base_dir.File("manifest.txt")] + ## A detailed list of files to be generated + ## works better if we just leave target the folder + # target = [] + # target.extend( + # map( + # lambda node: target_base_dir.File( + # res_root_dir.rel_path(node).replace(".png", ".bm") + # ), + # filter(lambda node: isinstance(node, SCons.Node.FS.File), source), + # ) + # ) else: asset_basename = f"assets_dolphin_{env['DOLPHIN_RES_TYPE']}" target = [ @@ -53,6 +56,13 @@ def dolphin_emitter(target, source, env): target_base_dir.File(asset_basename + ".h"), ] + # Debug output + # print( + # f"Dolphin res type: {env['DOLPHIN_RES_TYPE']},\ntarget files:", + # list(f.path for f in target), + # f"\nsource files:", + # list(f.path for f in source), + # ) return target, source diff --git a/scripts/fbt_tools/fbt_debugopts.py b/scripts/fbt_tools/fbt_debugopts.py index 3e7b07010..0c0ce3d32 100644 --- a/scripts/fbt_tools/fbt_debugopts.py +++ b/scripts/fbt_tools/fbt_debugopts.py @@ -1,4 +1,39 @@ +from re import search + +from SCons.Errors import UserError +from fbt_options import OPENOCD_OPTS + + +def _get_device_serials(search_str="STLink"): + import serial.tools.list_ports as list_ports + + return set([device.serial_number for device in list_ports.grep(search_str)]) + + +def GetDevices(env): + serials = _get_device_serials() + if len(serials) == 0: + raise UserError("No devices found") + + print("\n".join(serials)) + + def generate(env, **kw): + env.AddMethod(GetDevices) + + if (adapter_serial := env.subst("$OPENOCD_ADAPTER_SERIAL")) != "auto": + env.Append( + OPENOCD_OPTS=[ + "-c", + f"adapter serial {adapter_serial}", + ] + ) + + # Final command is "init", always explicitly added + env.Append( + OPENOCD_OPTS=["-c", "init"], + ) + env.SetDefault( OPENOCD_GDB_PIPE=[ "|openocd -c 'gdb_port pipe; log_output debug/openocd.log' ${[SINGLEQUOTEFUNC(OPENOCD_OPTS)]}" diff --git a/scripts/fbt_tools/fbt_extapps.py b/scripts/fbt_tools/fbt_extapps.py index e40a4efc2..38c943cc5 100644 --- a/scripts/fbt_tools/fbt_extapps.py +++ b/scripts/fbt_tools/fbt_extapps.py @@ -1,3 +1,4 @@ +import shutil from SCons.Builder import Builder from SCons.Action import Action from SCons.Errors import UserError @@ -7,8 +8,9 @@ import os import pathlib from fbt.elfmanifest import assemble_manifest_data from fbt.appmanifest import FlipperApplication, FlipperManifestException -from fbt.sdk import SdkCache +from fbt.sdk.cache import SdkCache import itertools +from ansi.color import fg def BuildAppElf(env, app): @@ -175,7 +177,8 @@ def validate_app_imports(target, source, env): if unresolved_syms: SCons.Warnings.warn( SCons.Warnings.LinkWarning, - f"\033[93m{source[0].path}: app won't run. Unresolved symbols: \033[95m{unresolved_syms}\033[0m", + fg.brightyellow(f"{source[0].path}: app won't run. Unresolved symbols: ") + + fg.brightmagenta(f"{unresolved_syms}"), ) @@ -209,14 +212,51 @@ def GetExtAppFromPath(env, app_dir): return (app, app_elf[0], app_validator[0]) +def fap_dist_emitter(target, source, env): + target_dir = target[0] + + target = [] + for dist_entry in env["_extapps"]["dist"].values(): + target.append(target_dir.Dir(dist_entry[0]).File(dist_entry[1][0].name)) + + for compact_entry in env["_extapps"]["compact"].values(): + source.extend(compact_entry) + + return (target, source) + + +def fap_dist_action(target, source, env): + # FIXME + target_dir = env.Dir("#/assets/resources/apps") + + shutil.rmtree(target_dir.path, ignore_errors=True) + for src, target in zip(source, target): + os.makedirs(os.path.dirname(target.path), exist_ok=True) + shutil.copy(src.path, target.path) + + def generate(env, **kw): env.SetDefault(EXT_APPS_WORK_DIR=kw.get("EXT_APPS_WORK_DIR")) - # env.VariantDir(env.subst("$EXT_APPS_WORK_DIR"), env.Dir("#"), duplicate=False) + + if not env["VERBOSE"]: + env.SetDefault( + FAPDISTCOMSTR="\tFAPDIST\t${TARGET}", + APPMETA_COMSTR="\tAPPMETA\t${TARGET}", + APPMETAEMBED_COMSTR="\tFAP\t${TARGET}", + APPCHECK_COMSTR="\tAPPCHK\t${SOURCE}", + ) env.AddMethod(BuildAppElf) env.AddMethod(GetExtAppFromPath) env.Append( BUILDERS={ + "FapDist": Builder( + action=Action( + fap_dist_action, + "$FAPDISTCOMSTR", + ), + emitter=fap_dist_emitter, + ), "EmbedAppMetadata": Builder( action=[ Action(prepare_app_metadata, "$APPMETA_COMSTR"), diff --git a/scripts/fbt_tools/fbt_sdk.py b/scripts/fbt_tools/fbt_sdk.py index ed0abdff6..f1f55bdb8 100644 --- a/scripts/fbt_tools/fbt_sdk.py +++ b/scripts/fbt_tools/fbt_sdk.py @@ -1,9 +1,10 @@ +import shutil from SCons.Builder import Builder from SCons.Action import Action from SCons.Errors import UserError # from SCons.Scanner import C -from SCons.Script import Mkdir, Copy, Delete, Entry +from SCons.Script import Entry from SCons.Util import LogicalLines import os.path @@ -11,7 +12,8 @@ import posixpath import pathlib import json -from fbt.sdk import SdkCollector, SdkCache +from fbt.sdk.collector import SdkCollector +from fbt.sdk.cache import SdkCache def ProcessSdkDepends(env, filename): @@ -48,15 +50,19 @@ def prebuild_sdk_create_origin_file(target, source, env): class SdkMeta: - def __init__(self, env): + def __init__(self, env, tree_builder: "SdkTreeBuilder"): self.env = env + self.treebuilder = tree_builder def save_to(self, json_manifest_path: str): meta_contents = { - "sdk_symbols": self.env["SDK_DEFINITION"].name, + "sdk_symbols": self.treebuilder.build_sdk_file_path( + self.env["SDK_DEFINITION"].path + ), "cc_args": self._wrap_scons_vars("$CCFLAGS $_CCCOMCOM"), "cpp_args": self._wrap_scons_vars("$CXXFLAGS $CCFLAGS $_CCCOMCOM"), "linker_args": self._wrap_scons_vars("$LINKFLAGS"), + "linker_script": self.env.subst("${LINKER_SCRIPT_PATH}"), } with open(json_manifest_path, "wt") as f: json.dump(meta_contents, f, indent=4) @@ -67,6 +73,8 @@ class SdkMeta: class SdkTreeBuilder: + SDK_DIR_SUBST = "SDK_ROOT_DIR" + def __init__(self, env, target, source) -> None: self.env = env self.target = target @@ -87,6 +95,8 @@ class SdkTreeBuilder: self.header_depends = list( filter(lambda fname: fname.endswith(".h"), depends.split()), ) + self.header_depends.append(self.env.subst("${LINKER_SCRIPT_PATH}")) + self.header_depends.append(self.env.subst("${SDK_DEFINITION}")) self.header_dirs = sorted( set(map(os.path.normpath, map(os.path.dirname, self.header_depends))) ) @@ -101,58 +111,60 @@ class SdkTreeBuilder: ) sdk_dirs = ", ".join(f"'{dir}'" for dir in self.header_dirs) - for dir in full_fw_paths: - if dir in sdk_dirs: - filtered_paths.append( - posixpath.normpath(posixpath.join(self.target_sdk_dir_name, dir)) - ) + filtered_paths.extend( + map( + self.build_sdk_file_path, + filter(lambda path: path in sdk_dirs, full_fw_paths), + ) + ) sdk_env = self.env.Clone() - sdk_env.Replace(CPPPATH=filtered_paths) - meta = SdkMeta(sdk_env) + sdk_env.Replace( + CPPPATH=filtered_paths, + LINKER_SCRIPT=self.env.subst("${APP_LINKER_SCRIPT}"), + ORIG_LINKER_SCRIPT_PATH=self.env["LINKER_SCRIPT_PATH"], + LINKER_SCRIPT_PATH=self.build_sdk_file_path("${ORIG_LINKER_SCRIPT_PATH}"), + ) + + meta = SdkMeta(sdk_env, self) meta.save_to(self.target[0].path) + def build_sdk_file_path(self, orig_path: str) -> str: + return posixpath.normpath( + posixpath.join( + self.SDK_DIR_SUBST, + self.target_sdk_dir_name, + orig_path, + ) + ).replace("\\", "/") + def emitter(self, target, source, env): target_folder = target[0] target = [target_folder.File("sdk.opts")] return target, source - def _create_deploy_commands(self): + def _run_deploy_commands(self): dirs_to_create = set( - self.sdk_deploy_dir.Dir(dirpath) for dirpath in self.header_dirs + self.sdk_deploy_dir.Dir(dirpath).path for dirpath in self.header_dirs ) - actions = [ - Delete(self.sdk_deploy_dir), - Mkdir(self.sdk_deploy_dir), - Copy( - self.sdk_root_dir, - self.env["SDK_DEFINITION"], - ), - ] - actions += [Mkdir(d) for d in dirs_to_create] - actions += [ - Action( - Copy(self.sdk_deploy_dir.File(h).path, h), - # f"Copy {h} to {self.sdk_deploy_dir}", - ) - for h in self.header_depends - ] - return actions + shutil.rmtree(self.sdk_root_dir.path, ignore_errors=False) - def generate_actions(self): + for sdkdir in dirs_to_create: + os.makedirs(sdkdir, exist_ok=True) + + for header in self.header_depends: + shutil.copy2(header, self.sdk_deploy_dir.File(header).path) + + def deploy_action(self): self._parse_sdk_depends() + self._run_deploy_commands() self._generate_sdk_meta() - return self._create_deploy_commands() - - -def deploy_sdk_tree(target, source, env, for_signature): - if for_signature: - return [] +def deploy_sdk_tree_action(target, source, env): sdk_tree = SdkTreeBuilder(env, target, source) - return sdk_tree.generate_actions() + return sdk_tree.deploy_action() def deploy_sdk_tree_emitter(target, source, env): @@ -217,6 +229,30 @@ def generate_sdk_symbols(source, target, env): def generate(env, **kw): + if not env["VERBOSE"]: + env.SetDefault( + SDK_PREGEN_COMSTR="\tPREGEN\t${TARGET}", + SDK_COMSTR="\tSDKSRC\t${TARGET}", + SDKSYM_UPDATER_COMSTR="\tSDKCHK\t${TARGET}", + SDKSYM_GENERATOR_COMSTR="\tSDKSYM\t${TARGET}", + SDKDEPLOY_COMSTR="\tSDKTREE\t${TARGET}", + ) + + # Filtering out things cxxheaderparser cannot handle + env.SetDefault( + SDK_PP_FLAGS=[ + '-D"_Static_assert(x,y)="', + '-D"__asm__(x)="', + '-D"__attribute__(x)="', + "-Drestrict=", + "-D_Noreturn=", + "-D__restrict=", + "-D__extension__=", + "-D__inline=inline", + "-D__inline__=inline", + ] + ) + env.AddMethod(ProcessSdkDepends) env.Append( BUILDERS={ @@ -235,7 +271,10 @@ def generate(env, **kw): suffix=".i", ), "SDKTree": Builder( - generator=deploy_sdk_tree, + action=Action( + deploy_sdk_tree_action, + "$SDKDEPLOY_COMSTR", + ), emitter=deploy_sdk_tree_emitter, src_suffix=".d", ), diff --git a/scripts/fbt_tools/fbt_tweaks.py b/scripts/fbt_tools/fbt_tweaks.py new file mode 100644 index 000000000..a903d4033 --- /dev/null +++ b/scripts/fbt_tools/fbt_tweaks.py @@ -0,0 +1,43 @@ +import SCons.Warnings as Warnings + +# from SCons.Script.Main import find_deepest_user_frame + +from ansi.color import fg, bg, fx + +import traceback +import sys +import os + + +def find_deepest_user_frame(tb): + tb.reverse() + + # find the deepest traceback frame that is not part + # of SCons: + for frame in tb: + filename = frame[0] + if filename.find("fbt_tweaks") != -1: + continue + if filename.find(os.sep + "SCons" + os.sep) == -1: + return frame + return tb[0] + + +def fbt_warning(e): + filename, lineno, routine, dummy = find_deepest_user_frame( + traceback.extract_stack() + ) + fbt_line = "\nfbt: warning: %s\n" % e.args[0] + sys.stderr.write(fg.boldmagenta(fbt_line)) + fbt_line = ( + fg.yellow("%s, line %d, " % (routine, lineno)) + 'in file "%s"\n' % filename + ) + sys.stderr.write(fg.yellow(fbt_line)) + + +def generate(env): + Warnings._warningOut = fbt_warning + + +def exists(): + return True diff --git a/scripts/fbt_tools/fwbin.py b/scripts/fbt_tools/fwbin.py index 678b04998..67e0d6450 100644 --- a/scripts/fbt_tools/fwbin.py +++ b/scripts/fbt_tools/fwbin.py @@ -12,6 +12,14 @@ def generate(env): OBJCOPY=__OBJCOPY_ARM_BIN, # FIXME NM=__NM_ARM_BIN, # FIXME ) + + if not env["VERBOSE"]: + env.SetDefault( + HEXCOMSTR="\tHEX\t${TARGET}", + BINCOMSTR="\tBIN\t${TARGET}", + DFUCOMSTR="\tDFU\t${TARGET}", + ) + env.Append( BUILDERS={ "HEXBuilder": Builder( diff --git a/scripts/fbt_tools/gdb.py b/scripts/fbt_tools/gdb.py index 94ea9fbe9..38256a0f8 100644 --- a/scripts/fbt_tools/gdb.py +++ b/scripts/fbt_tools/gdb.py @@ -6,8 +6,6 @@ def generate(env): env.SetDefault( GDB="gdb", GDBPY="gdb-py", - GDBOPTS="", - GDBPYOPTS="", GDBCOM="$GDB $GDBOPTS $SOURCES", # no $TARGET GDBPYCOM="$GDBPY $GDBOPTS $GDBPYOPTS $SOURCES", # no $TARGET ) diff --git a/scripts/flipper/storage.py b/scripts/flipper/storage.py index 5fa8a2c81..6b53f7477 100644 --- a/scripts/flipper/storage.py +++ b/scripts/flipper/storage.py @@ -340,6 +340,19 @@ class FlipperStorage: else: return True + def format_ext(self): + """Create a directory on Flipper""" + self.send_and_wait_eol("storage format /ext\r") + self.send_and_wait_eol("y\r") + answer = self.read.until(self.CLI_EOL) + self.read.until(self.CLI_PROMPT) + + if self.has_error(answer): + self.last_error = self.get_error(answer) + return False + else: + return True + def remove(self, path): """Remove file or directory on Flipper""" self.send_and_wait_eol('storage remove "' + path + '"\r') diff --git a/scripts/fwsize.py b/scripts/fwsize.py index b381f6e9a..445c29049 100644 --- a/scripts/fwsize.py +++ b/scripts/fwsize.py @@ -4,6 +4,7 @@ from flipper.app import App import subprocess import os import math +from ansi.color import fg class Main(App): @@ -43,7 +44,9 @@ class Main(App): pages = math.ceil(binsize / PAGE_SIZE) last_page_state = (binsize % PAGE_SIZE) * 100 / PAGE_SIZE print( - f"{os.path.basename(self.args.binname):<11}: {pages:>4} flash pages (last page {last_page_state:.02f}% full)" + fg.yellow( + f"{os.path.basename(self.args.binname):<11}: {pages:>4} flash pages (last page {last_page_state:.02f}% full)" + ) ) return 0 diff --git a/scripts/sconsdist.py b/scripts/sconsdist.py index cb4f8f5a5..7636c87bb 100644 --- a/scripts/sconsdist.py +++ b/scripts/sconsdist.py @@ -7,6 +7,7 @@ from update import Main as UpdateMain import shutil import zipfile import tarfile +from ansi.color import fg class ProjectDir: @@ -47,48 +48,52 @@ class Main(App): ) self.parser_copy.set_defaults(func=self.copy) - def get_project_filename(self, project, filetype): + def get_project_file_name(self, project: ProjectDir, filetype: str) -> str: # Temporary fix project_name = project.project - if project_name == "firmware": - if filetype == "zip": - project_name = "sdk" - elif filetype != "elf": - project_name = "full" + if project_name == "firmware" and filetype != "elf": + project_name = "full" - return f"{self.DIST_FILE_PREFIX}{self.target}-{project_name}-{self.args.suffix}.{filetype}" + return self.get_dist_file_name(project_name, filetype) - def get_dist_filepath(self, filename): + def get_dist_file_name(self, dist_artifact_type: str, filetype: str) -> str: + return f"{self.DIST_FILE_PREFIX}{self.target}-{dist_artifact_type}-{self.args.suffix}.{filetype}" + + def get_dist_file_path(self, filename: str) -> str: return join(self.output_dir_path, filename) - def copy_single_project(self, project): + def copy_single_project(self, project: ProjectDir) -> None: obj_directory = join("build", project.dir) for filetype in ("elf", "bin", "dfu", "json"): if exists(src_file := join(obj_directory, f"{project.project}.{filetype}")): shutil.copyfile( src_file, - self.get_dist_filepath( - self.get_project_filename(project, filetype) + self.get_dist_file_path( + self.get_project_file_name(project, filetype) ), ) - if exists(sdk_folder := join(obj_directory, "sdk")): - with zipfile.ZipFile( - self.get_dist_filepath(self.get_project_filename(project, "zip")), - "w", - zipfile.ZIP_DEFLATED, - ) as zf: - for root, dirs, files in walk(sdk_folder): - for file in files: - zf.write( - join(root, file), - relpath( - join(root, file), - sdk_folder, - ), - ) + for foldertype in ("sdk", "lib"): + if exists(sdk_folder := join(obj_directory, foldertype)): + self.package_zip(foldertype, sdk_folder) - def copy(self): + def package_zip(self, foldertype, sdk_folder): + with zipfile.ZipFile( + self.get_dist_file_path(self.get_dist_file_name(foldertype, "zip")), + "w", + zipfile.ZIP_DEFLATED, + ) as zf: + for root, _, files in walk(sdk_folder): + for file in files: + zf.write( + join(root, file), + relpath( + join(root, file), + sdk_folder, + ), + ) + + def copy(self) -> int: self.projects = dict( map( lambda pd: (pd.project, pd), @@ -126,7 +131,7 @@ class Main(App): self.copy_single_project(project) self.logger.info( - f"Firmware binaries can be found at:\n\t{self.output_dir_path}" + fg.green(f"Firmware binaries can be found at:\n\t{self.output_dir_path}") ) if self.args.version: @@ -143,12 +148,12 @@ class Main(App): "-t", self.target, "--dfu", - self.get_dist_filepath( - self.get_project_filename(self.projects["firmware"], "dfu") + self.get_dist_file_path( + self.get_project_file_name(self.projects["firmware"], "dfu") ), "--stage", - self.get_dist_filepath( - self.get_project_filename(self.projects["updater"], "bin") + self.get_dist_file_path( + self.get_project_file_name(self.projects["updater"], "bin") ), ] if self.args.resources: @@ -162,7 +167,9 @@ class Main(App): if (bundle_result := UpdateMain(no_exit=True)(bundle_args)) == 0: self.logger.info( - f"Use this directory to self-update your Flipper:\n\t{bundle_dir}" + fg.green( + f"Use this directory to self-update your Flipper:\n\t{bundle_dir}" + ) ) # Create tgz archive diff --git a/scripts/storage.py b/scripts/storage.py index 167ba88eb..ee5dabd43 100755 --- a/scripts/storage.py +++ b/scripts/storage.py @@ -21,6 +21,11 @@ class Main(App): self.parser_mkdir.add_argument("flipper_path", help="Flipper path") self.parser_mkdir.set_defaults(func=self.mkdir) + self.parser_format = self.subparsers.add_parser( + "format_ext", help="Format flash card" + ) + self.parser_format.set_defaults(func=self.format_ext) + self.parser_remove = self.subparsers.add_parser( "remove", help="Remove file/directory" ) @@ -275,6 +280,17 @@ class Main(App): storage.stop() return 0 + def format_ext(self): + if not (storage := self._get_storage()): + return 1 + + self.logger.debug("Formatting /ext SD card") + + if not storage.format_ext(): + self.logger.error(f"Error: {storage.last_error}") + storage.stop() + return 0 + def stress(self): self.logger.error("This test is wearing out flash memory.") self.logger.error("Never use it with internal storage(/int)") diff --git a/scripts/testing/await_flipper.py b/scripts/testing/await_flipper.py new file mode 100644 index 000000000..1f0d16194 --- /dev/null +++ b/scripts/testing/await_flipper.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python3 + +import sys, os, time + + +def flp_serial_by_name(flp_name): + if sys.platform == "darwin": # MacOS + flp_serial = "/dev/cu.usbmodemflip_" + flp_name + "1" + elif sys.platform == "linux": # Linux + flp_serial = ( + "/dev/serial/by-id/usb-Flipper_Devices_Inc._Flipper_" + + flp_name + + "_flip_" + + flp_name + + "-if00" + ) + + if os.path.exists(flp_serial): + return flp_serial + else: + if os.path.exists(flp_name): + return flp_name + else: + return "" + + +UPDATE_TIMEOUT = 30 + + +def main(): + flipper_name = sys.argv[1] + elapsed = 0 + flipper = flp_serial_by_name(flipper_name) + + while flipper == "" and elapsed < UPDATE_TIMEOUT: + elapsed += 1 + time.sleep(1) + flipper = flp_serial_by_name(flipper_name) + + if flipper == "": + print(f"Cannot find {flipper_name} flipper. Guess your flipper swam away") + sys.exit(1) + + sys.exit(0) + + +if __name__ == "__main__": + main() diff --git a/scripts/testing/units.py b/scripts/testing/units.py new file mode 100644 index 000000000..83b07899a --- /dev/null +++ b/scripts/testing/units.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python3 + +import sys, os +import serial +import re + +from await_flipper import flp_serial_by_name + + +LEAK_THRESHOLD = 3000 # added until units are fixed + + +def main(): + flp_serial = flp_serial_by_name(sys.argv[1]) + + if flp_serial == "": + print("Name or serial port is invalid") + sys.exit(1) + + with serial.Serial(flp_serial, timeout=1) as flipper: + flipper.baudrate = 230400 + flipper.flushOutput() + flipper.flushInput() + + flipper.timeout = 300 + + flipper.read_until(b">: ").decode("utf-8") + flipper.write(b"unit_tests\r") + data = flipper.read_until(b">: ").decode("utf-8") + + lines = data.split("\r\n") + + tests_re = r"Failed tests: \d{0,}" + time_re = r"Consumed: \d{0,}" + leak_re = r"Leaked: \d{0,}" + status_re = r"Status: \w{3,}" + + tests_pattern = re.compile(tests_re) + time_pattern = re.compile(time_re) + leak_pattern = re.compile(leak_re) + status_pattern = re.compile(status_re) + + tests, time, leak, status = None, None, None, None + + for line in lines: + print(line) + if not tests: + tests = re.match(tests_pattern, line) + if not time: + time = re.match(time_pattern, line) + if not leak: + leak = re.match(leak_pattern, line) + if not status: + status = re.match(status_pattern, line) + + if leak is None or time is None or leak is None or status is None: + print("Failed to get data. Or output is corrupt") + sys.exit(1) + + leak = int(re.findall(r"[- ]\d+", leak.group(0))[0]) + status = re.findall(r"\w+", status.group(0))[1] + tests = int(re.findall(r"\d+", tests.group(0))[0]) + time = int(re.findall(r"\d+", time.group(0))[0]) + + if tests > 0 or leak > LEAK_THRESHOLD or status != "PASSED": + print(f"Got {tests} failed tests.") + print(f"Leaked {leak} bytes.") + print(f"Status by flipper: {status}") + print(f"Time elapsed {time/1000} seconds.") + sys.exit(1) + + print( + f"Tests ran successfully! Time elapsed {time/1000} seconds. Passed {tests} tests." + ) + sys.exit(0) + + +if __name__ == "__main__": + main() diff --git a/scripts/toolchain/fbtenv.cmd b/scripts/toolchain/fbtenv.cmd index 5eaf16f94..a11a3ccd5 100644 --- a/scripts/toolchain/fbtenv.cmd +++ b/scripts/toolchain/fbtenv.cmd @@ -13,8 +13,8 @@ if not [%FBT_NOENV%] == [] ( exit /b 0 ) -set "FLIPPER_TOOLCHAIN_VERSION=15" -set "FBT_TOOLCHAIN_ROOT=%FBT_ROOT%\toolchain\i686-windows" +set "FLIPPER_TOOLCHAIN_VERSION=16" +set "FBT_TOOLCHAIN_ROOT=%FBT_ROOT%\toolchain\x86_64-windows" if not exist "%FBT_TOOLCHAIN_ROOT%" ( diff --git a/scripts/toolchain/fbtenv.sh b/scripts/toolchain/fbtenv.sh index 7c501803f..15f29e4dc 100755 --- a/scripts/toolchain/fbtenv.sh +++ b/scripts/toolchain/fbtenv.sh @@ -5,7 +5,7 @@ # public variables DEFAULT_SCRIPT_PATH="$(pwd -P)"; SCRIPT_PATH="${SCRIPT_PATH:-$DEFAULT_SCRIPT_PATH}"; -FBT_TOOLCHAIN_VERSION="${FBT_TOOLCHAIN_VERSION:-"15"}"; +FBT_TOOLCHAIN_VERSION="${FBT_TOOLCHAIN_VERSION:-"16"}"; FBT_TOOLCHAIN_PATH="${FBT_TOOLCHAIN_PATH:-$SCRIPT_PATH}"; fbtenv_show_usage() diff --git a/scripts/toolchain/windows-toolchain-download.ps1 b/scripts/toolchain/windows-toolchain-download.ps1 index bcb8f998f..aaed89856 100644 --- a/scripts/toolchain/windows-toolchain-download.ps1 +++ b/scripts/toolchain/windows-toolchain-download.ps1 @@ -3,13 +3,13 @@ $ErrorActionPreference = "Stop" [Net.ServicePointManager]::SecurityProtocol = "tls12, tls11, tls" $repo_root = (Get-Item "$PSScriptRoot\..\..").FullName $toolchain_version = $args[0] -$toolchain_url = "https://update.flipperzero.one/builds/toolchain/gcc-arm-none-eabi-10.3-i686-windows-flipper-$toolchain_version.zip" -$toolchain_zip = "gcc-arm-none-eabi-10.3-i686-windows-flipper-$toolchain_version.zip" -$toolchain_dir = "gcc-arm-none-eabi-10.3-i686-windows-flipper" +$toolchain_url = "https://update.flipperzero.one/builds/toolchain/gcc-arm-none-eabi-10.3-x86_64-windows-flipper-$toolchain_version.zip" +$toolchain_zip = "gcc-arm-none-eabi-10.3-x86_64-windows-flipper-$toolchain_version.zip" +$toolchain_dir = "gcc-arm-none-eabi-10.3-x86_64-windows-flipper" -if (Test-Path -LiteralPath "$repo_root\toolchain\i686-windows") { +if (Test-Path -LiteralPath "$repo_root\toolchain\x86_64-windows") { Write-Host -NoNewline "Removing old Windows toolchain.." - Remove-Item -LiteralPath "$repo_root\toolchain\i686-windows" -Force -Recurse + Remove-Item -LiteralPath "$repo_root\toolchain\x86_64-windows" -Force -Recurse Write-Host "done!" } if (!(Test-Path -Path "$repo_root\$toolchain_zip" -PathType Leaf)) { @@ -23,12 +23,12 @@ if (!(Test-Path -LiteralPath "$repo_root\toolchain")) { New-Item "$repo_root\toolchain" -ItemType Directory } -Write-Host -NoNewline "Unziping Windows toolchain.." +Write-Host -NoNewline "Extracting Windows toolchain.." Add-Type -Assembly "System.IO.Compression.Filesystem" -[System.IO.Compression.ZipFile]::ExtractToDirectory("$toolchain_zip", "$repo_root\") -Move-Item -Path "$repo_root\$toolchain_dir" -Destination "$repo_root\toolchain\i686-windows" +[System.IO.Compression.ZipFile]::ExtractToDirectory("$repo_root\$toolchain_zip", "$repo_root\") +Move-Item -Path "$repo_root\$toolchain_dir" -Destination "$repo_root\toolchain\x86_64-windows" Write-Host "done!" -Write-Host -NoNewline "Clearing temporary files.." +Write-Host -NoNewline "Cleaning up temporary files.." Remove-Item -LiteralPath "$repo_root\$toolchain_zip" -Force Write-Host "done!" diff --git a/site_scons/commandline.scons b/site_scons/commandline.scons index 324dfe332..cadb417f8 100644 --- a/site_scons/commandline.scons +++ b/site_scons/commandline.scons @@ -171,6 +171,11 @@ vars.AddVariables( "Blackmagic probe location", "auto", ), + ( + "OPENOCD_ADAPTER_SERIAL", + "OpenOCD adapter serial number", + "auto", + ), ( "UPDATE_SPLASH", "Directory name with slideshow frames to render after installing update package", diff --git a/site_scons/environ.scons b/site_scons/environ.scons index 2d082838a..94705dada 100644 --- a/site_scons/environ.scons +++ b/site_scons/environ.scons @@ -35,6 +35,7 @@ for env_value_name in variables_to_forward: coreenv = VAR_ENV.Clone( tools=[ + "fbt_tweaks", ( "crosscc", { @@ -80,8 +81,9 @@ if not coreenv["VERBOSE"]: # Default value for commandline options SetOption("num_jobs", multiprocessing.cpu_count()) +## NB - disabled both caches since they seem to do more harm then good in our case # Avoiding re-scan of all sources on every startup -SetOption("implicit_cache", True) +# SetOption("implicit_cache", True) # SetOption("implicit_deps_unchanged", True) # More aggressive caching SetOption("max_drift", 1) diff --git a/site_scons/extapps.scons b/site_scons/extapps.scons index 9edc6b5c1..90d228e58 100644 --- a/site_scons/extapps.scons +++ b/site_scons/extapps.scons @@ -21,7 +21,7 @@ appenv = ENV.Clone( ) appenv.Replace( - LINKER_SCRIPT="application_ext", + LINKER_SCRIPT=appenv.subst("$APP_LINKER_SCRIPT"), ) appenv.AppendUnique( @@ -65,6 +65,7 @@ extapps = appenv["_extapps"] = { "debug": {}, "validators": {}, "dist": {}, + "resources_dist": None, } @@ -108,6 +109,8 @@ appenv.PhonyTarget("firmware_extapps", appenv.Action(legacy_app_build_stub, None Alias("faps", extapps["compact"].values()) Alias("faps", extapps["validators"].values()) +extapps["resources_dist"] = appenv.FapDist(appenv.Dir("#/assets/resources/apps"), []) + if appsrc := appenv.subst("$APPSRC"): app_manifest, fap_file, app_validator = appenv.GetExtAppFromPath(appsrc) appenv.PhonyTarget( diff --git a/site_scons/fbt_extra/util.py b/site_scons/fbt_extra/util.py index aa3d50b64..c670c01d4 100644 --- a/site_scons/fbt_extra/util.py +++ b/site_scons/fbt_extra/util.py @@ -1,10 +1,11 @@ from fbt.util import link_dir +from ansi.color import fg def link_elf_dir_as_latest(env, elf_node): elf_dir = elf_node.Dir(".") latest_dir = env.Dir("#build/latest") - print(f"Setting {elf_dir} as latest built dir (./build/latest/)") + print(fg.green(f"Linking {elf_dir} as latest built dir (./build/latest/)")) return link_dir(latest_dir.abspath, elf_dir.abspath, env["PLATFORM"] == "win32") @@ -12,7 +13,7 @@ def should_gen_cdb_and_link_dir(env, requested_targets): explicitly_building_updater = False # Hacky way to check if updater-related targets were requested for build_target in requested_targets: - if "updater" in str(build_target): + if "updater" in str(build_target) and "package" not in str(build_target): explicitly_building_updater = True is_updater = not env["IS_BASE_FIRMWARE"] diff --git a/site_scons/firmwareopts.scons b/site_scons/firmwareopts.scons index f04b55cdd..9f707b4d8 100644 --- a/site_scons/firmwareopts.scons +++ b/site_scons/firmwareopts.scons @@ -32,12 +32,27 @@ else: ], ) -ENV.Append( +ENV.AppendUnique( LINKFLAGS=[ - "-Tfirmware/targets/f${TARGET_HW}/${LINKER_SCRIPT}.ld", + "-specs=nano.specs", + "-specs=nosys.specs", + "-Wl,--gc-sections", + "-Wl,--undefined=uxTopUsedPriority", + "-Wl,--wrap,_malloc_r", + "-Wl,--wrap,_free_r", + "-Wl,--wrap,_calloc_r", + "-Wl,--wrap,_realloc_r", + "-n", + "-Xlinker", + "-Map=${TARGET}.map", + "-T${LINKER_SCRIPT_PATH}", ], ) +ENV.SetDefault( + LINKER_SCRIPT_PATH="firmware/targets/f${TARGET_HW}/${LINKER_SCRIPT}.ld", +) + if ENV["FIRMWARE_BUILD_CFG"] == "updater": ENV.Append( IMAGE_BASE_ADDRESS="0x20000000", @@ -47,4 +62,5 @@ else: ENV.Append( IMAGE_BASE_ADDRESS="0x8000000", LINKER_SCRIPT="stm32wb55xx_flash", + APP_LINKER_SCRIPT="application_ext", ) diff --git a/site_scons/site_init.py b/site_scons/site_init.py index 2d83d8816..b763a3a7c 100644 --- a/site_scons/site_init.py +++ b/site_scons/site_init.py @@ -3,6 +3,7 @@ from SCons.Script import GetBuildFailures import sys import os import atexit +from ansi.color import fg, fx sys.path.insert(0, os.path.join(os.getcwd(), "scripts")) sys.path.insert(0, os.path.join(os.getcwd(), "lib/cxxheaderparser")) @@ -16,12 +17,12 @@ def bf_to_str(bf): if bf is None: # unknown targets product None in list return "(unknown tgt)" elif isinstance(bf, SCons.Errors.StopError): - return str(bf) + return fg.yellow(str(bf)) elif bf.node: - return str(bf.node) + ": " + bf.errstr + return fg.yellow(str(bf.node)) + ": " + bf.errstr elif bf.filename: - return bf.filename + ": " + bf.errstr - return "unknown failure: " + bf.errstr + return fg.yellow(bf.filename) + ": " + bf.errstr + return fg.yellow("unknown failure: ") + bf.errstr def display_build_status(): @@ -31,10 +32,9 @@ def display_build_status(): if bf: # bf is normally a list of build failures; if an element is None, # it's because of a target that scons doesn't know anything about. - failures_message = "\n".join( - ["Failed building %s" % bf_to_str(x) for x in bf if x is not None] - ) - print("*" * 10, "ERRORS", "*" * 10) + failures_message = "\n".join([bf_to_str(x) for x in bf if x is not None]) + print() + print(fg.brightred(fx.bold("*" * 10 + " FBT ERRORS " + "*" * 10))) print(failures_message)