Merge remote-tracking branch 'origin/release-candidate' into release
This commit is contained in:
		
						commit
						8d0faae820
					
				
							
								
								
									
										2
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
								
							| @ -127,7 +127,7 @@ jobs: | |||||||
|             **Compiled firmware for commit `${{steps.names.outputs.commit_sha}}`:** |             **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) |             - [📦 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) |             - [📥 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 |           edit-mode: replace | ||||||
| 
 | 
 | ||||||
|   compact: |   compact: | ||||||
|  | |||||||
							
								
								
									
										1
									
								
								.github/workflows/pvs_studio.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.github/workflows/pvs_studio.yml
									
									
									
									
										vendored
									
									
								
							| @ -65,7 +65,6 @@ jobs: | |||||||
|           pvs-studio-analyzer credentials ${{ secrets.PVS_STUDIO_CREDENTIALS }} |           pvs-studio-analyzer credentials ${{ secrets.PVS_STUDIO_CREDENTIALS }} | ||||||
|           pvs-studio-analyzer analyze \ |           pvs-studio-analyzer analyze \ | ||||||
|               @.pvsoptions \ |               @.pvsoptions \ | ||||||
|               --disableLicenseExpirationCheck \ |  | ||||||
|               -j$(grep -c processor /proc/cpuinfo) \ |               -j$(grep -c processor /proc/cpuinfo) \ | ||||||
|               -f build/f7-firmware-DC/compile_commands.json \ |               -f build/f7-firmware-DC/compile_commands.json \ | ||||||
|               -o PVS-Studio.log |               -o PVS-Studio.log | ||||||
|  | |||||||
							
								
								
									
										52
									
								
								.github/workflows/unit_tests.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								.github/workflows/unit_tests.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -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}} | ||||||
							
								
								
									
										6
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							| @ -22,12 +22,12 @@ | |||||||
| [submodule "lib/microtar"] | [submodule "lib/microtar"] | ||||||
| 	path = lib/microtar | 	path = lib/microtar | ||||||
| 	url = https://github.com/amachronic/microtar.git | 	url = https://github.com/amachronic/microtar.git | ||||||
| [submodule "lib/scons"] |  | ||||||
| 	path = lib/scons |  | ||||||
| 	url = https://github.com/SCons/scons.git |  | ||||||
| [submodule "lib/mbedtls"] | [submodule "lib/mbedtls"] | ||||||
| 	path = lib/mbedtls | 	path = lib/mbedtls | ||||||
| 	url = https://github.com/Mbed-TLS/mbedtls.git | 	url = https://github.com/Mbed-TLS/mbedtls.git | ||||||
| [submodule "lib/cxxheaderparser"] | [submodule "lib/cxxheaderparser"] | ||||||
| 	path = lib/cxxheaderparser | 	path = lib/cxxheaderparser | ||||||
| 	url = https://github.com/robotpy/cxxheaderparser.git | 	url = https://github.com/robotpy/cxxheaderparser.git | ||||||
|  | [submodule "applications/plugins/dap_link/lib/free-dap"] | ||||||
|  | 	path = applications/plugins/dap_link/lib/free-dap | ||||||
|  | 	url = https://github.com/ataradov/free-dap.git | ||||||
|  | |||||||
							
								
								
									
										2
									
								
								.vscode/example/c_cpp_properties.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.vscode/example/c_cpp_properties.json
									
									
									
									
										vendored
									
									
								
							| @ -2,7 +2,7 @@ | |||||||
|     "configurations": [ |     "configurations": [ | ||||||
|         { |         { | ||||||
|             "name": "Win32", |             "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", |             "intelliSenseMode": "gcc-arm", | ||||||
|             "compileCommands": "${workspaceFolder}/build/latest/compile_commands.json", |             "compileCommands": "${workspaceFolder}/build/latest/compile_commands.json", | ||||||
|             "configurationProvider": "ms-vscode.cpptools", |             "configurationProvider": "ms-vscode.cpptools", | ||||||
|  | |||||||
							
								
								
									
										19
									
								
								.vscode/example/launch.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										19
									
								
								.vscode/example/launch.json
									
									
									
									
										vendored
									
									
								
							| @ -79,6 +79,25 @@ | |||||||
|             ] |             ] | ||||||
|             // "showDevDebugOutput": "raw", |             // "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", |             "name": "fbt debug", | ||||||
|             "type": "python", |             "type": "python", | ||||||
|  | |||||||
							
								
								
									
										6
									
								
								.vscode/example/settings.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								.vscode/example/settings.json
									
									
									
									
										vendored
									
									
								
							| @ -6,13 +6,13 @@ | |||||||
|     "cortex-debug.enableTelemetry": false, |     "cortex-debug.enableTelemetry": false, | ||||||
|     "cortex-debug.variableUseNaturalFormat": true, |     "cortex-debug.variableUseNaturalFormat": true, | ||||||
|     "cortex-debug.showRTOS": 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.linux": "${workspaceFolder}/toolchain/x86_64-linux/bin", | ||||||
|     "cortex-debug.armToolchainPath.osx": "${workspaceFolder}/toolchain/x86_64-darwin/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.linux": "${workspaceFolder}/toolchain/x86_64-linux/openocd/bin/openocd", | ||||||
|     "cortex-debug.openocdPath.osx": "${workspaceFolder}/toolchain/x86_64-darwin/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.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", |     "cortex-debug.gdbPath.osx": "${workspaceFolder}/toolchain/x86_64-darwin/bin/arm-none-eabi-gdb-py", | ||||||
|     "editor.formatOnSave": true, |     "editor.formatOnSave": true, | ||||||
|  | |||||||
							
								
								
									
										4
									
								
								.vscode/example/tasks.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.vscode/example/tasks.json
									
									
									
									
										vendored
									
									
								
							| @ -109,13 +109,13 @@ | |||||||
|             "label": "[Debug] Build FAPs", |             "label": "[Debug] Build FAPs", | ||||||
|             "group": "build", |             "group": "build", | ||||||
|             "type": "shell", |             "type": "shell", | ||||||
|             "command": "./fbt plugin_dist" |             "command": "./fbt fap_dist" | ||||||
|         }, |         }, | ||||||
|         { |         { | ||||||
|             "label": "[Release] Build FAPs", |             "label": "[Release] Build FAPs", | ||||||
|             "group": "build", |             "group": "build", | ||||||
|             "type": "shell", |             "type": "shell", | ||||||
|             "command": "./fbt COMPACT=1 DEBUG=0 plugin_dist" |             "command": "./fbt COMPACT=1 DEBUG=0 fap_dist" | ||||||
|         }, |         }, | ||||||
|         { |         { | ||||||
|             "label": "[Debug] Launch App on Flipper", |             "label": "[Debug] Launch App on Flipper", | ||||||
|  | |||||||
							
								
								
									
										16
									
								
								SConstruct
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								SConstruct
									
									
									
									
									
								
							| @ -156,11 +156,9 @@ Depends(fap_dist, firmware_env["FW_EXTAPPS"]["validators"].values()) | |||||||
| Alias("fap_dist", fap_dist) | Alias("fap_dist", fap_dist) | ||||||
| # distenv.Default(fap_dist) | # distenv.Default(fap_dist) | ||||||
| 
 | 
 | ||||||
| plugin_resources_dist = list( | distenv.Depends( | ||||||
|     distenv.Install(f"#/assets/resources/apps/{dist_entry[0]}", dist_entry[1]) |     firmware_env["FW_RESOURCES"], firmware_env["FW_EXTAPPS"]["resources_dist"] | ||||||
|     for dist_entry in firmware_env["FW_EXTAPPS"]["dist"].values() |  | ||||||
| ) | ) | ||||||
| distenv.Depends(firmware_env["FW_RESOURCES"], plugin_resources_dist) |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # Target for bundling core2 package for qFlipper | # Target for bundling core2 package for qFlipper | ||||||
| @ -291,6 +289,16 @@ distenv.PhonyTarget( | |||||||
|     "@echo $( ${BLACKMAGIC_ADDR} $)", |     "@echo $( ${BLACKMAGIC_ADDR} $)", | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | # Find STLink probe ids | ||||||
|  | distenv.PhonyTarget( | ||||||
|  |     "get_stlink", | ||||||
|  |     distenv.Action( | ||||||
|  |         lambda **kw: distenv.GetDevices(), | ||||||
|  |         None, | ||||||
|  |     ), | ||||||
|  | ) | ||||||
|  | 
 | ||||||
| # Prepare vscode environment | # Prepare vscode environment | ||||||
| vscode_dist = distenv.Install("#.vscode", distenv.Glob("#.vscode/example/*")) | vscode_dist = distenv.Install("#.vscode", distenv.Glob("#.vscode/example/*")) | ||||||
| distenv.Precious(vscode_dist) | distenv.Precious(vscode_dist) | ||||||
|  | |||||||
| @ -8,4 +8,5 @@ App( | |||||||
|     stack_size=2 * 1024, |     stack_size=2 * 1024, | ||||||
|     order=150, |     order=150, | ||||||
|     fap_category="Debug", |     fap_category="Debug", | ||||||
|  |     fap_icon_assets="icons", | ||||||
| ) | ) | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| #include "assets_icons.h" | #include <file_browser_test_icons.h> | ||||||
| #include "file_browser_app_i.h" | #include "file_browser_app_i.h" | ||||||
| #include "gui/modules/file_browser.h" | #include "gui/modules/file_browser.h" | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
|  | |||||||
							
								
								
									
										
											BIN
										
									
								
								applications/debug/file_browser_test/icons/badusb_10px.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								applications/debug/file_browser_test/icons/badusb_10px.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 576 B | 
| @ -16,6 +16,7 @@ | |||||||
| #define NFC_TEST_RESOURCES_DIR EXT_PATH("unit_tests/nfc/") | #define NFC_TEST_RESOURCES_DIR EXT_PATH("unit_tests/nfc/") | ||||||
| #define NFC_TEST_SIGNAL_SHORT_FILE "nfc_nfca_signal_short.nfc" | #define NFC_TEST_SIGNAL_SHORT_FILE "nfc_nfca_signal_short.nfc" | ||||||
| #define NFC_TEST_SIGNAL_LONG_FILE "nfc_nfca_signal_long.nfc" | #define NFC_TEST_SIGNAL_LONG_FILE "nfc_nfca_signal_long.nfc" | ||||||
|  | #define NFC_TEST_DICT_PATH EXT_PATH("unit_tests/mf_classic_dict.nfc") | ||||||
| 
 | 
 | ||||||
| static const char* nfc_test_file_type = "Flipper NFC test"; | static const char* nfc_test_file_type = "Flipper NFC test"; | ||||||
| static const uint32_t nfc_test_file_version = 1; | static const uint32_t nfc_test_file_version = 1; | ||||||
| @ -220,11 +221,78 @@ MU_TEST(mf_classic_dict_test) { | |||||||
|     furi_string_free(temp_str); |     furi_string_free(temp_str); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | MU_TEST(mf_classic_dict_load_test) { | ||||||
|  |     Storage* storage = furi_record_open(RECORD_STORAGE); | ||||||
|  |     mu_assert(storage != NULL, "storage != NULL assert failed\r\n"); | ||||||
|  | 
 | ||||||
|  |     // Delete unit test dict file if exists
 | ||||||
|  |     if(storage_file_exists(storage, NFC_TEST_DICT_PATH)) { | ||||||
|  |         mu_assert( | ||||||
|  |             storage_simply_remove(storage, NFC_TEST_DICT_PATH), | ||||||
|  |             "remove == true assert failed\r\n"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Create unit test dict file
 | ||||||
|  |     Stream* file_stream = file_stream_alloc(storage); | ||||||
|  |     mu_assert(file_stream != NULL, "file_stream != NULL assert failed\r\n"); | ||||||
|  |     mu_assert( | ||||||
|  |         file_stream_open(file_stream, NFC_TEST_DICT_PATH, FSAM_WRITE, FSOM_OPEN_ALWAYS), | ||||||
|  |         "file_stream_open == true assert failed\r\n"); | ||||||
|  | 
 | ||||||
|  |     // Write unit test dict file
 | ||||||
|  |     char key_str[] = "a0a1a2a3a4a5"; | ||||||
|  |     mu_assert( | ||||||
|  |         stream_write_cstring(file_stream, key_str) == strlen(key_str), | ||||||
|  |         "write == true assert failed\r\n"); | ||||||
|  |     // Close unit test dict file
 | ||||||
|  |     mu_assert(file_stream_close(file_stream), "file_stream_close == true assert failed\r\n"); | ||||||
|  | 
 | ||||||
|  |     // Load unit test dict file
 | ||||||
|  |     MfClassicDict* instance = NULL; | ||||||
|  |     instance = mf_classic_dict_alloc(MfClassicDictTypeUnitTest); | ||||||
|  |     mu_assert(instance != NULL, "mf_classic_dict_alloc\r\n"); | ||||||
|  |     uint32_t total_keys = mf_classic_dict_get_total_keys(instance); | ||||||
|  |     mu_assert(total_keys == 1, "total_keys == 1 assert failed\r\n"); | ||||||
|  | 
 | ||||||
|  |     // Read key
 | ||||||
|  |     uint64_t key_ref = 0xa0a1a2a3a4a5; | ||||||
|  |     uint64_t key_dut = 0; | ||||||
|  |     FuriString* temp_str = furi_string_alloc(); | ||||||
|  |     mu_assert( | ||||||
|  |         mf_classic_dict_get_next_key_str(instance, temp_str), | ||||||
|  |         "get_next_key_str == true assert failed\r\n"); | ||||||
|  |     mu_assert(furi_string_cmp_str(temp_str, key_str) == 0, "invalid key loaded\r\n"); | ||||||
|  |     mu_assert(mf_classic_dict_rewind(instance), "mf_classic_dict_rewind == 1 assert failed\r\n"); | ||||||
|  |     mu_assert( | ||||||
|  |         mf_classic_dict_get_next_key(instance, &key_dut), | ||||||
|  |         "get_next_key == true assert failed\r\n"); | ||||||
|  |     mu_assert(key_dut == key_ref, "invalid key loaded\r\n"); | ||||||
|  |     furi_string_free(temp_str); | ||||||
|  |     mf_classic_dict_free(instance); | ||||||
|  | 
 | ||||||
|  |     // Check that MfClassicDict added new line to the end of the file
 | ||||||
|  |     mu_assert( | ||||||
|  |         file_stream_open(file_stream, NFC_TEST_DICT_PATH, FSAM_READ, FSOM_OPEN_EXISTING), | ||||||
|  |         "file_stream_open == true assert failed\r\n"); | ||||||
|  |     mu_assert(stream_seek(file_stream, -1, StreamOffsetFromEnd), "seek == true assert failed\r\n"); | ||||||
|  |     uint8_t last_char = 0; | ||||||
|  |     mu_assert(stream_read(file_stream, &last_char, 1) == 1, "read == true assert failed\r\n"); | ||||||
|  |     mu_assert(last_char == '\n', "last_char == '\\n' assert failed\r\n"); | ||||||
|  |     mu_assert(file_stream_close(file_stream), "file_stream_close == true assert failed\r\n"); | ||||||
|  | 
 | ||||||
|  |     // Delete unit test dict file
 | ||||||
|  |     mu_assert( | ||||||
|  |         storage_simply_remove(storage, NFC_TEST_DICT_PATH), "remove == true assert failed\r\n"); | ||||||
|  |     stream_free(file_stream); | ||||||
|  |     furi_record_close(RECORD_STORAGE); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| MU_TEST_SUITE(nfc) { | MU_TEST_SUITE(nfc) { | ||||||
|     nfc_test_alloc(); |     nfc_test_alloc(); | ||||||
| 
 | 
 | ||||||
|     MU_RUN_TEST(nfc_digital_signal_test); |     MU_RUN_TEST(nfc_digital_signal_test); | ||||||
|     MU_RUN_TEST(mf_classic_dict_test); |     MU_RUN_TEST(mf_classic_dict_test); | ||||||
|  |     MU_RUN_TEST(mf_classic_dict_load_test); | ||||||
| 
 | 
 | ||||||
|     nfc_test_free(); |     nfc_test_free(); | ||||||
| } | } | ||||||
|  | |||||||
| @ -5,7 +5,7 @@ | |||||||
| #include <lib/subghz/transmitter.h> | #include <lib/subghz/transmitter.h> | ||||||
| #include <lib/subghz/subghz_keystore.h> | #include <lib/subghz/subghz_keystore.h> | ||||||
| #include <lib/subghz/subghz_file_encoder_worker.h> | #include <lib/subghz/subghz_file_encoder_worker.h> | ||||||
| #include <lib/subghz/protocols/registry.h> | #include <lib/subghz/protocols/protocol_items.h> | ||||||
| #include <flipper_format/flipper_format_i.h> | #include <flipper_format/flipper_format_i.h> | ||||||
| 
 | 
 | ||||||
| #define TAG "SubGhz TEST" | #define TAG "SubGhz TEST" | ||||||
| @ -13,7 +13,7 @@ | |||||||
| #define CAME_ATOMO_DIR_NAME EXT_PATH("subghz/assets/came_atomo") | #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 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_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 | #define TEST_TIMEOUT 10000 | ||||||
| 
 | 
 | ||||||
| static SubGhzEnvironment* environment_handler; | static SubGhzEnvironment* environment_handler; | ||||||
| @ -43,6 +43,8 @@ static void subghz_test_init(void) { | |||||||
|         environment_handler, CAME_ATOMO_DIR_NAME); |         environment_handler, CAME_ATOMO_DIR_NAME); | ||||||
|     subghz_environment_set_nice_flor_s_rainbow_table_file_name( |     subghz_environment_set_nice_flor_s_rainbow_table_file_name( | ||||||
|         environment_handler, NICE_FLOR_S_DIR_NAME); |         environment_handler, NICE_FLOR_S_DIR_NAME); | ||||||
|  |     subghz_environment_set_protocol_registry( | ||||||
|  |         environment_handler, (void*)&subghz_protocol_registry); | ||||||
| 
 | 
 | ||||||
|     receiver_handler = subghz_receiver_alloc_init(environment_handler); |     receiver_handler = subghz_receiver_alloc_init(environment_handler); | ||||||
|     subghz_receiver_set_filter(receiver_handler, SubGhzProtocolFlag_Decodable); |     subghz_receiver_set_filter(receiver_handler, SubGhzProtocolFlag_Decodable); | ||||||
| @ -413,11 +415,11 @@ MU_TEST(subghz_decoder_honeywell_wdb_test) { | |||||||
|         "Test decoder " SUBGHZ_PROTOCOL_HONEYWELL_WDB_NAME " error\r\n"); |         "Test decoder " SUBGHZ_PROTOCOL_HONEYWELL_WDB_NAME " error\r\n"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| MU_TEST(subghz_decoder_magellen_test) { | MU_TEST(subghz_decoder_magellan_test) { | ||||||
|     mu_assert( |     mu_assert( | ||||||
|         subghz_decoder_test( |         subghz_decoder_test( | ||||||
|             EXT_PATH("unit_tests/subghz/magellen_raw.sub"), SUBGHZ_PROTOCOL_MAGELLEN_NAME), |             EXT_PATH("unit_tests/subghz/magellan_raw.sub"), SUBGHZ_PROTOCOL_MAGELLAN_NAME), | ||||||
|         "Test decoder " SUBGHZ_PROTOCOL_MAGELLEN_NAME " error\r\n"); |         "Test decoder " SUBGHZ_PROTOCOL_MAGELLAN_NAME " error\r\n"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| MU_TEST(subghz_decoder_intertechno_v3_test) { | MU_TEST(subghz_decoder_intertechno_v3_test) { | ||||||
| @ -435,13 +437,6 @@ MU_TEST(subghz_decoder_clemsa_test) { | |||||||
|         "Test decoder " SUBGHZ_PROTOCOL_CLEMSA_NAME " error\r\n"); |         "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
 | //test encoders
 | ||||||
| MU_TEST(subghz_encoder_princeton_test) { | MU_TEST(subghz_encoder_princeton_test) { | ||||||
|     mu_assert( |     mu_assert( | ||||||
| @ -545,10 +540,10 @@ MU_TEST(subghz_encoder_honeywell_wdb_test) { | |||||||
|         "Test encoder " SUBGHZ_PROTOCOL_HONEYWELL_WDB_NAME " error\r\n"); |         "Test encoder " SUBGHZ_PROTOCOL_HONEYWELL_WDB_NAME " error\r\n"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| MU_TEST(subghz_encoder_magellen_test) { | MU_TEST(subghz_encoder_magellan_test) { | ||||||
|     mu_assert( |     mu_assert( | ||||||
|         subghz_encoder_test(EXT_PATH("unit_tests/subghz/magellen.sub")), |         subghz_encoder_test(EXT_PATH("unit_tests/subghz/magellan.sub")), | ||||||
|         "Test encoder " SUBGHZ_PROTOCOL_MAGELLEN_NAME " error\r\n"); |         "Test encoder " SUBGHZ_PROTOCOL_MAGELLAN_NAME " error\r\n"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| MU_TEST(subghz_encoder_intertechno_v3_test) { | MU_TEST(subghz_encoder_intertechno_v3_test) { | ||||||
| @ -600,10 +595,9 @@ MU_TEST_SUITE(subghz) { | |||||||
|     MU_RUN_TEST(subghz_decoder_doitrand_test); |     MU_RUN_TEST(subghz_decoder_doitrand_test); | ||||||
|     MU_RUN_TEST(subghz_decoder_phoenix_v2_test); |     MU_RUN_TEST(subghz_decoder_phoenix_v2_test); | ||||||
|     MU_RUN_TEST(subghz_decoder_honeywell_wdb_test); |     MU_RUN_TEST(subghz_decoder_honeywell_wdb_test); | ||||||
|     MU_RUN_TEST(subghz_decoder_magellen_test); |     MU_RUN_TEST(subghz_decoder_magellan_test); | ||||||
|     MU_RUN_TEST(subghz_decoder_intertechno_v3_test); |     MU_RUN_TEST(subghz_decoder_intertechno_v3_test); | ||||||
|     MU_RUN_TEST(subghz_decoder_clemsa_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_princeton_test); | ||||||
|     MU_RUN_TEST(subghz_encoder_came_test); |     MU_RUN_TEST(subghz_encoder_came_test); | ||||||
| @ -622,7 +616,7 @@ MU_TEST_SUITE(subghz) { | |||||||
|     MU_RUN_TEST(subghz_encoder_doitrand_test); |     MU_RUN_TEST(subghz_encoder_doitrand_test); | ||||||
|     MU_RUN_TEST(subghz_encoder_phoenix_v2_test); |     MU_RUN_TEST(subghz_encoder_phoenix_v2_test); | ||||||
|     MU_RUN_TEST(subghz_encoder_honeywell_wdb_test); |     MU_RUN_TEST(subghz_encoder_honeywell_wdb_test); | ||||||
|     MU_RUN_TEST(subghz_encoder_magellen_test); |     MU_RUN_TEST(subghz_encoder_magellan_test); | ||||||
|     MU_RUN_TEST(subghz_encoder_intertechno_v3_test); |     MU_RUN_TEST(subghz_encoder_intertechno_v3_test); | ||||||
|     MU_RUN_TEST(subghz_encoder_clemsa_test); |     MU_RUN_TEST(subghz_encoder_clemsa_test); | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										24
									
								
								applications/examples/example_images/ReadMe.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								applications/examples/example_images/ReadMe.md
									
									
									
									
									
										Normal file
									
								
							| @ -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`. | ||||||
| @ -5,6 +5,7 @@ | |||||||
| #include "bad_usb_script.h" | #include "bad_usb_script.h" | ||||||
| 
 | 
 | ||||||
| #include <gui/gui.h> | #include <gui/gui.h> | ||||||
|  | #include <assets_icons.h> | ||||||
| #include <gui/view_dispatcher.h> | #include <gui/view_dispatcher.h> | ||||||
| #include <gui/scene_manager.h> | #include <gui/scene_manager.h> | ||||||
| #include <gui/modules/submenu.h> | #include <gui/modules/submenu.h> | ||||||
|  | |||||||
| @ -1,6 +1,7 @@ | |||||||
| #include "bad_usb_view.h" | #include "bad_usb_view.h" | ||||||
| #include "../bad_usb_script.h" | #include "../bad_usb_script.h" | ||||||
| #include <gui/elements.h> | #include <gui/elements.h> | ||||||
|  | #include <assets_icons.h> | ||||||
| 
 | 
 | ||||||
| #define MAX_NAME_LEN 64 | #define MAX_NAME_LEN 64 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,5 +1,6 @@ | |||||||
| #include <furi.h> | #include <furi.h> | ||||||
| #include <gui/gui.h> | #include <gui/gui.h> | ||||||
|  | #include <assets_icons.h> | ||||||
| #include <gui/view_dispatcher.h> | #include <gui/view_dispatcher.h> | ||||||
| #include <storage/storage.h> | #include <storage/storage.h> | ||||||
| #include <gui/modules/loading.h> | #include <gui/modules/loading.h> | ||||||
|  | |||||||
| @ -15,6 +15,7 @@ | |||||||
| #include <gui/modules/widget.h> | #include <gui/modules/widget.h> | ||||||
| #include "views/gpio_test.h" | #include "views/gpio_test.h" | ||||||
| #include "views/gpio_usb_uart.h" | #include "views/gpio_usb_uart.h" | ||||||
|  | #include <assets_icons.h> | ||||||
| 
 | 
 | ||||||
| struct GpioApp { | struct GpioApp { | ||||||
|     Gui* gui; |     Gui* gui; | ||||||
| @ -24,6 +25,7 @@ struct GpioApp { | |||||||
|     Widget* widget; |     Widget* widget; | ||||||
| 
 | 
 | ||||||
|     VariableItemList* var_item_list; |     VariableItemList* var_item_list; | ||||||
|  |     VariableItem* var_item_flow; | ||||||
|     GpioTest* gpio_test; |     GpioTest* gpio_test; | ||||||
|     GpioUsbUart* gpio_usb_uart; |     GpioUsbUart* gpio_usb_uart; | ||||||
|     UsbUartBridge* usb_uart_bridge; |     UsbUartBridge* usb_uart_bridge; | ||||||
|  | |||||||
| @ -13,7 +13,7 @@ static UsbUartConfig* cfg_set; | |||||||
| 
 | 
 | ||||||
| static const char* vcp_ch[] = {"0 (CLI)", "1"}; | static const char* vcp_ch[] = {"0 (CLI)", "1"}; | ||||||
| static const char* uart_ch[] = {"13,14", "15,16"}; | static const char* uart_ch[] = {"13,14", "15,16"}; | ||||||
| static const char* flow_pins[] = {"None", "2,3", "6,7"}; | static const char* flow_pins[] = {"None", "2,3", "6,7", "16,15"}; | ||||||
| static const char* baudrate_mode[] = {"Host"}; | static const char* baudrate_mode[] = {"Host"}; | ||||||
| static const uint32_t baudrate_list[] = { | static const uint32_t baudrate_list[] = { | ||||||
|     2400, |     2400, | ||||||
| @ -33,6 +33,24 @@ bool gpio_scene_usb_uart_cfg_on_event(void* context, SceneManagerEvent event) { | |||||||
|     return false; |     return false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void line_ensure_flow_invariant(GpioApp* app) { | ||||||
|  |     // GPIO pins PC0, PC1 (16,15) are unavailable for RTS/DTR when LPUART is
 | ||||||
|  |     // selected. This function enforces that invariant by resetting flow_pins
 | ||||||
|  |     // to None if it is configured to 16,15 when LPUART is selected.
 | ||||||
|  | 
 | ||||||
|  |     uint8_t available_flow_pins = cfg_set->uart_ch == FuriHalUartIdLPUART1 ? 3 : 4; | ||||||
|  |     VariableItem* item = app->var_item_flow; | ||||||
|  |     variable_item_set_values_count(item, available_flow_pins); | ||||||
|  | 
 | ||||||
|  |     if(cfg_set->flow_pins >= available_flow_pins) { | ||||||
|  |         cfg_set->flow_pins = 0; | ||||||
|  |         usb_uart_set_config(app->usb_uart_bridge, cfg_set); | ||||||
|  | 
 | ||||||
|  |         variable_item_set_current_value_index(item, cfg_set->flow_pins); | ||||||
|  |         variable_item_set_current_value_text(item, flow_pins[cfg_set->flow_pins]); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static void line_vcp_cb(VariableItem* item) { | static void line_vcp_cb(VariableItem* item) { | ||||||
|     GpioApp* app = variable_item_get_context(item); |     GpioApp* app = variable_item_get_context(item); | ||||||
|     uint8_t index = variable_item_get_current_value_index(item); |     uint8_t index = variable_item_get_current_value_index(item); | ||||||
| @ -54,6 +72,7 @@ static void line_port_cb(VariableItem* item) { | |||||||
|     else if(index == 1) |     else if(index == 1) | ||||||
|         cfg_set->uart_ch = FuriHalUartIdLPUART1; |         cfg_set->uart_ch = FuriHalUartIdLPUART1; | ||||||
|     usb_uart_set_config(app->usb_uart_bridge, cfg_set); |     usb_uart_set_config(app->usb_uart_bridge, cfg_set); | ||||||
|  |     line_ensure_flow_invariant(app); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void line_flow_cb(VariableItem* item) { | static void line_flow_cb(VariableItem* item) { | ||||||
| @ -116,9 +135,12 @@ void gpio_scene_usb_uart_cfg_on_enter(void* context) { | |||||||
|     variable_item_set_current_value_index(item, cfg_set->uart_ch); |     variable_item_set_current_value_index(item, cfg_set->uart_ch); | ||||||
|     variable_item_set_current_value_text(item, uart_ch[cfg_set->uart_ch]); |     variable_item_set_current_value_text(item, uart_ch[cfg_set->uart_ch]); | ||||||
| 
 | 
 | ||||||
|     item = variable_item_list_add(var_item_list, "RTS/DTR Pins", 3, line_flow_cb, app); |     item = variable_item_list_add( | ||||||
|  |         var_item_list, "RTS/DTR Pins", COUNT_OF(flow_pins), line_flow_cb, app); | ||||||
|     variable_item_set_current_value_index(item, cfg_set->flow_pins); |     variable_item_set_current_value_index(item, cfg_set->flow_pins); | ||||||
|     variable_item_set_current_value_text(item, flow_pins[cfg_set->flow_pins]); |     variable_item_set_current_value_text(item, flow_pins[cfg_set->flow_pins]); | ||||||
|  |     app->var_item_flow = item; | ||||||
|  |     line_ensure_flow_invariant(app); | ||||||
| 
 | 
 | ||||||
|     variable_item_list_set_selected_item( |     variable_item_list_set_selected_item( | ||||||
|         var_item_list, scene_manager_get_scene_state(app->scene_manager, GpioAppViewUsbUartCfg)); |         var_item_list, scene_manager_get_scene_state(app->scene_manager, GpioAppViewUsbUartCfg)); | ||||||
|  | |||||||
| @ -14,6 +14,7 @@ | |||||||
| static const GpioPin* flow_pins[][2] = { | static const GpioPin* flow_pins[][2] = { | ||||||
|     {&gpio_ext_pa7, &gpio_ext_pa6}, // 2, 3
 |     {&gpio_ext_pa7, &gpio_ext_pa6}, // 2, 3
 | ||||||
|     {&gpio_ext_pb2, &gpio_ext_pc3}, // 6, 7
 |     {&gpio_ext_pb2, &gpio_ext_pc3}, // 6, 7
 | ||||||
|  |     {&gpio_ext_pc0, &gpio_ext_pc1}, // 16, 15
 | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|  | |||||||
| @ -5,6 +5,7 @@ | |||||||
| #include <toolbox/path.h> | #include <toolbox/path.h> | ||||||
| #include <flipper_format/flipper_format.h> | #include <flipper_format/flipper_format.h> | ||||||
| #include <rpc/rpc_app.h> | #include <rpc/rpc_app.h> | ||||||
|  | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| #define TAG "iButtonApp" | #define TAG "iButtonApp" | ||||||
| 
 | 
 | ||||||
| @ -337,11 +338,13 @@ int32_t ibutton_app(void* p) { | |||||||
|         view_dispatcher_attach_to_gui( |         view_dispatcher_attach_to_gui( | ||||||
|             ibutton->view_dispatcher, ibutton->gui, ViewDispatcherTypeDesktop); |             ibutton->view_dispatcher, ibutton->gui, ViewDispatcherTypeDesktop); | ||||||
|         scene_manager_next_scene(ibutton->scene_manager, iButtonSceneRpc); |         scene_manager_next_scene(ibutton->scene_manager, iButtonSceneRpc); | ||||||
|  |         DOLPHIN_DEED(DolphinDeedIbuttonEmulate); | ||||||
|     } else { |     } else { | ||||||
|         view_dispatcher_attach_to_gui( |         view_dispatcher_attach_to_gui( | ||||||
|             ibutton->view_dispatcher, ibutton->gui, ViewDispatcherTypeFullscreen); |             ibutton->view_dispatcher, ibutton->gui, ViewDispatcherTypeFullscreen); | ||||||
|         if(key_loaded) { |         if(key_loaded) { | ||||||
|             scene_manager_next_scene(ibutton->scene_manager, iButtonSceneEmulate); |             scene_manager_next_scene(ibutton->scene_manager, iButtonSceneEmulate); | ||||||
|  |             DOLPHIN_DEED(DolphinDeedIbuttonEmulate); | ||||||
|         } else { |         } else { | ||||||
|             scene_manager_next_scene(ibutton->scene_manager, iButtonSceneStart); |             scene_manager_next_scene(ibutton->scene_manager, iButtonSceneStart); | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -4,6 +4,7 @@ | |||||||
| 
 | 
 | ||||||
| #include <gui/gui.h> | #include <gui/gui.h> | ||||||
| #include <gui/view.h> | #include <gui/view.h> | ||||||
|  | #include <assets_icons.h> | ||||||
| #include <gui/view_dispatcher.h> | #include <gui/view_dispatcher.h> | ||||||
| #include <gui/scene_manager.h> | #include <gui/scene_manager.h> | ||||||
| #include <notification/notification_messages.h> | #include <notification/notification_messages.h> | ||||||
|  | |||||||
| @ -1,7 +1,5 @@ | |||||||
| #include "../ibutton_i.h" | #include "../ibutton_i.h" | ||||||
| 
 | 
 | ||||||
| #include <dolphin/dolphin.h> |  | ||||||
| 
 |  | ||||||
| void ibutton_scene_add_type_byte_input_callback(void* context) { | void ibutton_scene_add_type_byte_input_callback(void* context) { | ||||||
|     iButton* ibutton = context; |     iButton* ibutton = context; | ||||||
|     view_dispatcher_send_custom_event(ibutton->view_dispatcher, iButtonCustomEventByteEditResult); |     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; |         consumed = true; | ||||||
|         if(event.event == iButtonCustomEventByteEditResult) { |         if(event.event == iButtonCustomEventByteEditResult) { | ||||||
|             ibutton_key_set_data(ibutton->key, new_key_data, IBUTTON_KEY_DATA_SIZE); |             ibutton_key_set_data(ibutton->key, new_key_data, IBUTTON_KEY_DATA_SIZE); | ||||||
|             DOLPHIN_DEED(DolphinDeedIbuttonAdd); |  | ||||||
|             scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSaveName); |             scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSaveName); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -1,6 +1,5 @@ | |||||||
| #include "../ibutton_i.h" | #include "../ibutton_i.h" | ||||||
| #include <core/log.h> | #include <core/log.h> | ||||||
| #include <dolphin/dolphin.h> |  | ||||||
| #include <toolbox/path.h> | #include <toolbox/path.h> | ||||||
| 
 | 
 | ||||||
| #define EMULATE_TIMEOUT_TICKS 10 | #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); |         path_extract_filename(ibutton->file_path, key_name, true); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     DOLPHIN_DEED(DolphinDeedIbuttonEmulate); |  | ||||||
| 
 |  | ||||||
|     // check that stored key has name
 |     // check that stored key has name
 | ||||||
|     if(!furi_string_empty(key_name)) { |     if(!furi_string_empty(key_name)) { | ||||||
|         ibutton_text_store_set(ibutton, "%s", furi_string_get_cstr(key_name)); |         ibutton_text_store_set(ibutton, "%s", furi_string_get_cstr(key_name)); | ||||||
|  | |||||||
| @ -11,7 +11,6 @@ void ibutton_scene_read_on_enter(void* context) { | |||||||
|     Popup* popup = ibutton->popup; |     Popup* popup = ibutton->popup; | ||||||
|     iButtonKey* key = ibutton->key; |     iButtonKey* key = ibutton->key; | ||||||
|     iButtonWorker* worker = ibutton->key_worker; |     iButtonWorker* worker = ibutton->key_worker; | ||||||
|     DOLPHIN_DEED(DolphinDeedIbuttonRead); |  | ||||||
| 
 | 
 | ||||||
|     popup_set_header(popup, "iButton", 95, 26, AlignCenter, AlignBottom); |     popup_set_header(popup, "iButton", 95, 26, AlignCenter, AlignBottom); | ||||||
|     popup_set_text(popup, "Waiting\nfor key ...", 95, 30, AlignCenter, AlignTop); |     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) { |             if(success) { | ||||||
|                 ibutton_notification_message(ibutton, iButtonNotificationMessageSuccess); |                 ibutton_notification_message(ibutton, iButtonNotificationMessageSuccess); | ||||||
|                 ibutton_notification_message(ibutton, iButtonNotificationMessageGreenOn); |                 ibutton_notification_message(ibutton, iButtonNotificationMessageGreenOn); | ||||||
|                 DOLPHIN_DEED(DolphinDeedIbuttonReadSuccess); |  | ||||||
|                 scene_manager_next_scene(scene_manager, iButtonSceneReadSuccess); |                 scene_manager_next_scene(scene_manager, iButtonSceneReadSuccess); | ||||||
|  |                 DOLPHIN_DEED(DolphinDeedIbuttonReadSuccess); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -1,4 +1,5 @@ | |||||||
| #include "../ibutton_i.h" | #include "../ibutton_i.h" | ||||||
|  | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     SubmenuIndexSave, |     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); |             scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSaveName); | ||||||
|         } else if(event.event == SubmenuIndexEmulate) { |         } else if(event.event == SubmenuIndexEmulate) { | ||||||
|             scene_manager_next_scene(ibutton->scene_manager, iButtonSceneEmulate); |             scene_manager_next_scene(ibutton->scene_manager, iButtonSceneEmulate); | ||||||
|  |             DOLPHIN_DEED(DolphinDeedIbuttonEmulate); | ||||||
|         } else if(event.event == SubmenuIndexWrite) { |         } else if(event.event == SubmenuIndexWrite) { | ||||||
|             scene_manager_next_scene(ibutton->scene_manager, iButtonSceneWrite); |             scene_manager_next_scene(ibutton->scene_manager, iButtonSceneWrite); | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -1,6 +1,7 @@ | |||||||
| #include "../ibutton_i.h" | #include "../ibutton_i.h" | ||||||
| #include <lib/toolbox/random_name.h> | #include <lib/toolbox/random_name.h> | ||||||
| #include <toolbox/path.h> | #include <toolbox/path.h> | ||||||
|  | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| static void ibutton_scene_save_name_text_input_callback(void* context) { | static void ibutton_scene_save_name_text_input_callback(void* context) { | ||||||
|     iButton* ibutton = context; |     iButton* ibutton = context; | ||||||
| @ -57,6 +58,15 @@ bool ibutton_scene_save_name_on_event(void* context, SceneManagerEvent event) { | |||||||
|         if(event.event == iButtonCustomEventTextEditResult) { |         if(event.event == iButtonCustomEventTextEditResult) { | ||||||
|             if(ibutton_save_key(ibutton, ibutton->text_store)) { |             if(ibutton_save_key(ibutton, ibutton->text_store)) { | ||||||
|                 scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSaveSuccess); |                 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 { |             } else { | ||||||
|                 const uint32_t possible_scenes[] = { |                 const uint32_t possible_scenes[] = { | ||||||
|                     iButtonSceneReadKeyMenu, iButtonSceneSavedKeyMenu, iButtonSceneAddType}; |                     iButtonSceneReadKeyMenu, iButtonSceneSavedKeyMenu, iButtonSceneAddType}; | ||||||
|  | |||||||
| @ -1,5 +1,4 @@ | |||||||
| #include "../ibutton_i.h" | #include "../ibutton_i.h" | ||||||
| #include <dolphin/dolphin.h> |  | ||||||
| 
 | 
 | ||||||
| static void ibutton_scene_save_success_popup_callback(void* context) { | static void ibutton_scene_save_success_popup_callback(void* context) { | ||||||
|     iButton* ibutton = 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) { | void ibutton_scene_save_success_on_enter(void* context) { | ||||||
|     iButton* ibutton = context; |     iButton* ibutton = context; | ||||||
|     Popup* popup = ibutton->popup; |     Popup* popup = ibutton->popup; | ||||||
|     DOLPHIN_DEED(DolphinDeedIbuttonSave); |  | ||||||
| 
 | 
 | ||||||
|     popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); |     popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); | ||||||
|     popup_set_header(popup, "Saved!", 5, 7, AlignLeft, AlignTop); |     popup_set_header(popup, "Saved!", 5, 7, AlignLeft, AlignTop); | ||||||
|  | |||||||
| @ -1,4 +1,5 @@ | |||||||
| #include "../ibutton_i.h" | #include "../ibutton_i.h" | ||||||
|  | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| enum SubmenuIndex { | enum SubmenuIndex { | ||||||
|     SubmenuIndexEmulate, |     SubmenuIndexEmulate, | ||||||
| @ -58,6 +59,7 @@ bool ibutton_scene_saved_key_menu_on_event(void* context, SceneManagerEvent even | |||||||
|         consumed = true; |         consumed = true; | ||||||
|         if(event.event == SubmenuIndexEmulate) { |         if(event.event == SubmenuIndexEmulate) { | ||||||
|             scene_manager_next_scene(ibutton->scene_manager, iButtonSceneEmulate); |             scene_manager_next_scene(ibutton->scene_manager, iButtonSceneEmulate); | ||||||
|  |             DOLPHIN_DEED(DolphinDeedIbuttonEmulate); | ||||||
|         } else if(event.event == SubmenuIndexWrite) { |         } else if(event.event == SubmenuIndexWrite) { | ||||||
|             scene_manager_next_scene(ibutton->scene_manager, iButtonSceneWrite); |             scene_manager_next_scene(ibutton->scene_manager, iButtonSceneWrite); | ||||||
|         } else if(event.event == SubmenuIndexEdit) { |         } else if(event.event == SubmenuIndexEdit) { | ||||||
|  | |||||||
| @ -1,5 +1,6 @@ | |||||||
| #include "../ibutton_i.h" | #include "../ibutton_i.h" | ||||||
| #include "ibutton/scenes/ibutton_scene.h" | #include "ibutton/scenes/ibutton_scene.h" | ||||||
|  | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| enum SubmenuIndex { | enum SubmenuIndex { | ||||||
|     SubmenuIndexRead, |     SubmenuIndexRead, | ||||||
| @ -38,6 +39,7 @@ bool ibutton_scene_start_on_event(void* context, SceneManagerEvent event) { | |||||||
|         consumed = true; |         consumed = true; | ||||||
|         if(event.event == SubmenuIndexRead) { |         if(event.event == SubmenuIndexRead) { | ||||||
|             scene_manager_next_scene(ibutton->scene_manager, iButtonSceneRead); |             scene_manager_next_scene(ibutton->scene_manager, iButtonSceneRead); | ||||||
|  |             DOLPHIN_DEED(DolphinDeedIbuttonRead); | ||||||
|         } else if(event.event == SubmenuIndexSaved) { |         } else if(event.event == SubmenuIndexSaved) { | ||||||
|             furi_string_set(ibutton->file_path, IBUTTON_APP_FOLDER); |             furi_string_set(ibutton->file_path, IBUTTON_APP_FOLDER); | ||||||
|             scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSelectKey); |             scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSelectKey); | ||||||
|  | |||||||
| @ -1,17 +1,25 @@ | |||||||
| #include <cli/cli.h> | #include <cli/cli.h> | ||||||
|  | #include <cli/cli_i.h> | ||||||
| #include <infrared.h> | #include <infrared.h> | ||||||
| #include <infrared_worker.h> | #include <infrared_worker.h> | ||||||
| #include <furi_hal_infrared.h> | #include <furi_hal_infrared.h> | ||||||
| #include <flipper_format.h> | #include <flipper_format.h> | ||||||
| #include <toolbox/args.h> | #include <toolbox/args.h> | ||||||
|  | #include <m-dict.h> | ||||||
| 
 | 
 | ||||||
| #include "infrared_signal.h" | #include "infrared_signal.h" | ||||||
|  | #include "infrared_brute_force.h" | ||||||
| 
 | 
 | ||||||
| #define INFRARED_CLI_BUF_SIZE 10 | #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) | ||||||
| 
 | 
 | ||||||
| static void infrared_cli_start_ir_rx(Cli* cli, FuriString* args); | 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_start_ir_tx(Cli* cli, FuriString* args); | ||||||
| static void infrared_cli_process_decode(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 const struct { | static const struct { | ||||||
|     const char* cmd; |     const char* cmd; | ||||||
| @ -20,6 +28,7 @@ static const struct { | |||||||
|     {.cmd = "rx", .process_function = infrared_cli_start_ir_rx}, |     {.cmd = "rx", .process_function = infrared_cli_start_ir_rx}, | ||||||
|     {.cmd = "tx", .process_function = infrared_cli_start_ir_tx}, |     {.cmd = "tx", .process_function = infrared_cli_start_ir_tx}, | ||||||
|     {.cmd = "decode", .process_function = infrared_cli_process_decode}, |     {.cmd = "decode", .process_function = infrared_cli_process_decode}, | ||||||
|  |     {.cmd = "universal", .process_function = infrared_cli_process_universal}, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static void signal_received_callback(void* context, InfraredWorkerSignal* received_signal) { | static void signal_received_callback(void* context, InfraredWorkerSignal* received_signal) { | ||||||
| @ -57,25 +66,9 @@ static void signal_received_callback(void* context, InfraredWorkerSignal* receiv | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void infrared_cli_start_ir_rx(Cli* cli, FuriString* args) { |  | ||||||
|     UNUSED(cli); |  | ||||||
|     UNUSED(args); |  | ||||||
|     InfraredWorker* worker = infrared_worker_alloc(); |  | ||||||
|     infrared_worker_rx_start(worker); |  | ||||||
|     infrared_worker_rx_set_received_signal_callback(worker, signal_received_callback, cli); |  | ||||||
| 
 |  | ||||||
|     printf("Receiving INFRARED...\r\nPress Ctrl+C to abort\r\n"); |  | ||||||
|     while(!cli_cmd_interrupt_received(cli)) { |  | ||||||
|         furi_delay_ms(50); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     infrared_worker_rx_stop(worker); |  | ||||||
|     infrared_worker_free(worker); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void infrared_cli_print_usage(void) { | static void infrared_cli_print_usage(void) { | ||||||
|     printf("Usage:\r\n"); |     printf("Usage:\r\n"); | ||||||
|     printf("\tir rx\r\n"); |     printf("\tir rx [raw]\r\n"); | ||||||
|     printf("\tir tx <protocol> <address> <command>\r\n"); |     printf("\tir tx <protocol> <address> <command>\r\n"); | ||||||
|     printf("\t<command> and <address> are hex-formatted\r\n"); |     printf("\t<command> and <address> are hex-formatted\r\n"); | ||||||
|     printf("\tAvailable protocols:"); |     printf("\tAvailable protocols:"); | ||||||
| @ -90,6 +83,39 @@ static void infrared_cli_print_usage(void) { | |||||||
|         INFRARED_MIN_FREQUENCY, |         INFRARED_MIN_FREQUENCY, | ||||||
|         INFRARED_MAX_FREQUENCY); |         INFRARED_MAX_FREQUENCY); | ||||||
|     printf("\tir decode <input_file> [<output_file>]\r\n"); |     printf("\tir decode <input_file> [<output_file>]\r\n"); | ||||||
|  |     printf("\tir universal <remote_name> <signal_name>\r\n"); | ||||||
|  |     printf("\tir universal list <remote_name>\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) { | ||||||
|  |     UNUSED(cli); | ||||||
|  | 
 | ||||||
|  |     bool enable_decoding = true; | ||||||
|  | 
 | ||||||
|  |     if(!furi_string_empty(args)) { | ||||||
|  |         if(!furi_string_cmp_str(args, "raw")) { | ||||||
|  |             enable_decoding = false; | ||||||
|  |         } else { | ||||||
|  |             printf("Wrong arguments.\r\n"); | ||||||
|  |             infrared_cli_print_usage(); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     InfraredWorker* worker = infrared_worker_alloc(); | ||||||
|  |     infrared_worker_rx_enable_signal_decoding(worker, enable_decoding); | ||||||
|  |     infrared_worker_rx_start(worker); | ||||||
|  |     infrared_worker_rx_set_received_signal_callback(worker, signal_received_callback, cli); | ||||||
|  | 
 | ||||||
|  |     printf("Receiving %s INFRARED...\r\nPress Ctrl+C to abort\r\n", enable_decoding ? "" : "RAW"); | ||||||
|  |     while(!cli_cmd_interrupt_received(cli)) { | ||||||
|  |         furi_delay_ms(50); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     infrared_worker_rx_stop(worker); | ||||||
|  |     infrared_worker_free(worker); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static bool infrared_cli_parse_message(const char* str, InfraredSignal* signal) { | static bool infrared_cli_parse_message(const char* str, InfraredSignal* signal) { | ||||||
| @ -328,6 +354,131 @@ static void infrared_cli_process_decode(Cli* cli, FuriString* args) { | |||||||
|     furi_record_close(RECORD_STORAGE); |     furi_record_close(RECORD_STORAGE); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void infrared_cli_list_remote_signals(FuriString* remote_name) { | ||||||
|  |     if(furi_string_empty(remote_name)) { | ||||||
|  |         printf("Missing remote name.\r\n"); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     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(); | ||||||
|  | 
 | ||||||
|  |         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); | ||||||
|  |             if(v != NULL) { | ||||||
|  |                 (*v)++; | ||||||
|  |                 max = M_MAX(*v, max); | ||||||
|  |             } else { | ||||||
|  |                 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(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, FuriString* remote_name, FuriString* signal_name) { | ||||||
|  |     InfraredBruteForce* brute_force = infrared_brute_force_alloc(); | ||||||
|  |     FuriString* remote_path = furi_string_alloc_printf( | ||||||
|  |         "%s/%s.ir", EXT_PATH(INFRARED_ASSETS_FOLDER), furi_string_get_cstr(remote_name)); | ||||||
|  | 
 | ||||||
|  |     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)); | ||||||
|  | 
 | ||||||
|  |     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; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         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); | ||||||
|  | 
 | ||||||
|  |             if(cli_cmd_interrupt_received(cli)) break; | ||||||
|  | 
 | ||||||
|  |             printf("\r%d%% complete.", (int)((float)records_sent++ / (float)record_count * 100)); | ||||||
|  |             fflush(stdout); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         infrared_brute_force_stop(brute_force); | ||||||
|  |     } 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) { | static void infrared_cli_start_ir(Cli* cli, FuriString* args, void* context) { | ||||||
|     UNUSED(context); |     UNUSED(context); | ||||||
|     if(furi_hal_infrared_is_busy()) { |     if(furi_hal_infrared_is_busy()) { | ||||||
|  | |||||||
| @ -2,6 +2,7 @@ | |||||||
| 
 | 
 | ||||||
| #include <gui/gui.h> | #include <gui/gui.h> | ||||||
| #include <gui/view.h> | #include <gui/view.h> | ||||||
|  | #include <assets_icons.h> | ||||||
| #include <gui/view_stack.h> | #include <gui/view_stack.h> | ||||||
| #include <gui/view_dispatcher.h> | #include <gui/view_dispatcher.h> | ||||||
| #include <gui/scene_manager.h> | #include <gui/scene_manager.h> | ||||||
|  | |||||||
| @ -16,6 +16,7 @@ ADD_SCENE(infrared, remote_list, RemoteList) | |||||||
| ADD_SCENE(infrared, universal, Universal) | ADD_SCENE(infrared, universal, Universal) | ||||||
| ADD_SCENE(infrared, universal_tv, UniversalTV) | ADD_SCENE(infrared, universal_tv, UniversalTV) | ||||||
| ADD_SCENE(infrared, universal_ac, UniversalAC) | ADD_SCENE(infrared, universal_ac, UniversalAC) | ||||||
|  | ADD_SCENE(infrared, universal_audio, UniversalAudio) | ||||||
| ADD_SCENE(infrared, debug, Debug) | ADD_SCENE(infrared, debug, Debug) | ||||||
| ADD_SCENE(infrared, error_databases, ErrorDatabases) | ADD_SCENE(infrared, error_databases, ErrorDatabases) | ||||||
| ADD_SCENE(infrared, rpc, Rpc) | ADD_SCENE(infrared, rpc, Rpc) | ||||||
|  | |||||||
| @ -1,4 +1,5 @@ | |||||||
| #include "../infrared_i.h" | #include "../infrared_i.h" | ||||||
|  | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| void infrared_scene_learn_on_enter(void* context) { | void infrared_scene_learn_on_enter(void* context) { | ||||||
|     Infrared* infrared = context; |     Infrared* infrared = context; | ||||||
| @ -27,6 +28,7 @@ bool infrared_scene_learn_on_event(void* context, SceneManagerEvent event) { | |||||||
|         if(event.event == InfraredCustomEventTypeSignalReceived) { |         if(event.event == InfraredCustomEventTypeSignalReceived) { | ||||||
|             infrared_play_notification_message(infrared, InfraredNotificationMessageSuccess); |             infrared_play_notification_message(infrared, InfraredNotificationMessageSuccess); | ||||||
|             scene_manager_next_scene(infrared->scene_manager, InfraredSceneLearnSuccess); |             scene_manager_next_scene(infrared->scene_manager, InfraredSceneLearnSuccess); | ||||||
|  |             DOLPHIN_DEED(DolphinDeedIrLearnSuccess); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -1,13 +1,10 @@ | |||||||
| #include "../infrared_i.h" | #include "../infrared_i.h" | ||||||
| 
 | 
 | ||||||
| #include <dolphin/dolphin.h> |  | ||||||
| 
 |  | ||||||
| void infrared_scene_learn_done_on_enter(void* context) { | void infrared_scene_learn_done_on_enter(void* context) { | ||||||
|     Infrared* infrared = context; |     Infrared* infrared = context; | ||||||
|     Popup* popup = infrared->popup; |     Popup* popup = infrared->popup; | ||||||
| 
 | 
 | ||||||
|     popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); |     popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); | ||||||
|     DOLPHIN_DEED(DolphinDeedIrSave); |  | ||||||
| 
 | 
 | ||||||
|     if(infrared->app_state.is_learning_new_remote) { |     if(infrared->app_state.is_learning_new_remote) { | ||||||
|         popup_set_header(popup, "New remote\ncreated!", 0, 0, AlignLeft, AlignTop); |         popup_set_header(popup, "New remote\ncreated!", 0, 0, AlignLeft, AlignTop); | ||||||
|  | |||||||
| @ -1,4 +1,5 @@ | |||||||
| #include "../infrared_i.h" | #include "../infrared_i.h" | ||||||
|  | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| void infrared_scene_learn_enter_name_on_enter(void* context) { | void infrared_scene_learn_enter_name_on_enter(void* context) { | ||||||
|     Infrared* infrared = context; |     Infrared* infrared = context; | ||||||
| @ -49,6 +50,7 @@ bool infrared_scene_learn_enter_name_on_event(void* context, SceneManagerEvent e | |||||||
| 
 | 
 | ||||||
|             if(success) { |             if(success) { | ||||||
|                 scene_manager_next_scene(scene_manager, InfraredSceneLearnDone); |                 scene_manager_next_scene(scene_manager, InfraredSceneLearnDone); | ||||||
|  |                 DOLPHIN_DEED(DolphinDeedIrSave); | ||||||
|             } else { |             } else { | ||||||
|                 dialog_message_show_storage_error(infrared->dialogs, "Failed to save file"); |                 dialog_message_show_storage_error(infrared->dialogs, "Failed to save file"); | ||||||
|                 const uint32_t possible_scenes[] = {InfraredSceneRemoteList, InfraredSceneStart}; |                 const uint32_t possible_scenes[] = {InfraredSceneRemoteList, InfraredSceneStart}; | ||||||
|  | |||||||
| @ -1,7 +1,5 @@ | |||||||
| #include "../infrared_i.h" | #include "../infrared_i.h" | ||||||
| 
 | 
 | ||||||
| #include <dolphin/dolphin.h> |  | ||||||
| 
 |  | ||||||
| static void | static void | ||||||
|     infrared_scene_learn_success_dialog_result_callback(DialogExResult result, void* context) { |     infrared_scene_learn_success_dialog_result_callback(DialogExResult result, void* context) { | ||||||
|     Infrared* infrared = context; |     Infrared* infrared = context; | ||||||
| @ -13,7 +11,6 @@ void infrared_scene_learn_success_on_enter(void* context) { | |||||||
|     DialogEx* dialog_ex = infrared->dialog_ex; |     DialogEx* dialog_ex = infrared->dialog_ex; | ||||||
|     InfraredSignal* signal = infrared->received_signal; |     InfraredSignal* signal = infrared->received_signal; | ||||||
| 
 | 
 | ||||||
|     DOLPHIN_DEED(DolphinDeedIrLearnSuccess); |  | ||||||
|     infrared_play_notification_message(infrared, InfraredNotificationMessageGreenOn); |     infrared_play_notification_message(infrared, InfraredNotificationMessageGreenOn); | ||||||
| 
 | 
 | ||||||
|     if(infrared_signal_is_raw(signal)) { |     if(infrared_signal_is_raw(signal)) { | ||||||
|  | |||||||
| @ -21,6 +21,12 @@ void infrared_scene_universal_on_enter(void* context) { | |||||||
|         SubmenuIndexUniversalTV, |         SubmenuIndexUniversalTV, | ||||||
|         infrared_scene_universal_submenu_callback, |         infrared_scene_universal_submenu_callback, | ||||||
|         context); |         context); | ||||||
|  |     submenu_add_item( | ||||||
|  |         submenu, | ||||||
|  |         "Audio Players", | ||||||
|  |         SubmenuIndexUniversalAudio, | ||||||
|  |         infrared_scene_universal_submenu_callback, | ||||||
|  |         context); | ||||||
|     submenu_add_item( |     submenu_add_item( | ||||||
|         submenu, |         submenu, | ||||||
|         "Air Conditioners", |         "Air Conditioners", | ||||||
| @ -45,7 +51,7 @@ bool infrared_scene_universal_on_event(void* context, SceneManagerEvent event) { | |||||||
|             scene_manager_next_scene(scene_manager, InfraredSceneUniversalAC); |             scene_manager_next_scene(scene_manager, InfraredSceneUniversalAC); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|         } else if(event.event == SubmenuIndexUniversalAudio) { |         } else if(event.event == SubmenuIndexUniversalAudio) { | ||||||
|             //TODO Implement Audio universal remote
 |             scene_manager_next_scene(scene_manager, InfraredSceneUniversalAudio); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -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); | ||||||
|  | } | ||||||
| @ -1,4 +1,5 @@ | |||||||
| #include "lfrfid_i.h" | #include "lfrfid_i.h" | ||||||
|  | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| static bool lfrfid_debug_custom_event_callback(void* context, uint32_t event) { | static bool lfrfid_debug_custom_event_callback(void* context, uint32_t event) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
| @ -182,12 +183,14 @@ int32_t lfrfid_app(void* p) { | |||||||
|             view_dispatcher_attach_to_gui( |             view_dispatcher_attach_to_gui( | ||||||
|                 app->view_dispatcher, app->gui, ViewDispatcherTypeDesktop); |                 app->view_dispatcher, app->gui, ViewDispatcherTypeDesktop); | ||||||
|             scene_manager_next_scene(app->scene_manager, LfRfidSceneRpc); |             scene_manager_next_scene(app->scene_manager, LfRfidSceneRpc); | ||||||
|  |             DOLPHIN_DEED(DolphinDeedRfidEmulate); | ||||||
|         } else { |         } else { | ||||||
|             furi_string_set(app->file_path, args); |             furi_string_set(app->file_path, args); | ||||||
|             lfrfid_load_key_data(app, app->file_path, true); |             lfrfid_load_key_data(app, app->file_path, true); | ||||||
|             view_dispatcher_attach_to_gui( |             view_dispatcher_attach_to_gui( | ||||||
|                 app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); |                 app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); | ||||||
|             scene_manager_next_scene(app->scene_manager, LfRfidSceneEmulate); |             scene_manager_next_scene(app->scene_manager, LfRfidSceneEmulate); | ||||||
|  |             DOLPHIN_DEED(DolphinDeedRfidEmulate); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|     } else { |     } else { | ||||||
|  | |||||||
| @ -5,6 +5,7 @@ | |||||||
| 
 | 
 | ||||||
| #include <gui/gui.h> | #include <gui/gui.h> | ||||||
| #include <gui/view.h> | #include <gui/view.h> | ||||||
|  | #include <assets_icons.h> | ||||||
| #include <gui/view_dispatcher.h> | #include <gui/view_dispatcher.h> | ||||||
| #include <gui/scene_manager.h> | #include <gui/scene_manager.h> | ||||||
| #include <cli/cli.h> | #include <cli/cli.h> | ||||||
|  | |||||||
| @ -1,12 +1,9 @@ | |||||||
| #include "../lfrfid_i.h" | #include "../lfrfid_i.h" | ||||||
| #include <dolphin/dolphin.h> |  | ||||||
| 
 | 
 | ||||||
| void lfrfid_scene_emulate_on_enter(void* context) { | void lfrfid_scene_emulate_on_enter(void* context) { | ||||||
|     LfRfid* app = context; |     LfRfid* app = context; | ||||||
|     Popup* popup = app->popup; |     Popup* popup = app->popup; | ||||||
| 
 | 
 | ||||||
|     DOLPHIN_DEED(DolphinDeedRfidEmulate); |  | ||||||
| 
 |  | ||||||
|     popup_set_header(popup, "Emulating", 89, 30, AlignCenter, AlignTop); |     popup_set_header(popup, "Emulating", 89, 30, AlignCenter, AlignTop); | ||||||
|     if(!furi_string_empty(app->file_name)) { |     if(!furi_string_empty(app->file_name)) { | ||||||
|         popup_set_text(popup, furi_string_get_cstr(app->file_name), 89, 43, AlignCenter, AlignTop); |         popup_set_text(popup, furi_string_get_cstr(app->file_name), 89, 43, AlignCenter, AlignTop); | ||||||
|  | |||||||
| @ -1,4 +1,5 @@ | |||||||
| #include "../lfrfid_i.h" | #include "../lfrfid_i.h" | ||||||
|  | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     SubmenuIndexASK, |     SubmenuIndexASK, | ||||||
| @ -57,10 +58,12 @@ bool lfrfid_scene_extra_actions_on_event(void* context, SceneManagerEvent event) | |||||||
|         if(event.event == SubmenuIndexASK) { |         if(event.event == SubmenuIndexASK) { | ||||||
|             app->read_type = LFRFIDWorkerReadTypeASKOnly; |             app->read_type = LFRFIDWorkerReadTypeASKOnly; | ||||||
|             scene_manager_next_scene(app->scene_manager, LfRfidSceneRead); |             scene_manager_next_scene(app->scene_manager, LfRfidSceneRead); | ||||||
|  |             DOLPHIN_DEED(DolphinDeedRfidRead); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|         } else if(event.event == SubmenuIndexPSK) { |         } else if(event.event == SubmenuIndexPSK) { | ||||||
|             app->read_type = LFRFIDWorkerReadTypePSKOnly; |             app->read_type = LFRFIDWorkerReadTypePSKOnly; | ||||||
|             scene_manager_next_scene(app->scene_manager, LfRfidSceneRead); |             scene_manager_next_scene(app->scene_manager, LfRfidSceneRead); | ||||||
|  |             DOLPHIN_DEED(DolphinDeedRfidRead); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|         } else if(event.event == SubmenuIndexRAW) { |         } else if(event.event == SubmenuIndexRAW) { | ||||||
|             scene_manager_next_scene(app->scene_manager, LfRfidSceneRawName); |             scene_manager_next_scene(app->scene_manager, LfRfidSceneRawName); | ||||||
|  | |||||||
| @ -34,7 +34,7 @@ void lfrfid_scene_raw_info_on_enter(void* context) { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewWidget); |     view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewWidget); | ||||||
|     //string_clear(tmp_string);
 |     //furi_string_free(tmp_string);
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool lfrfid_scene_raw_info_on_event(void* context, SceneManagerEvent event) { | bool lfrfid_scene_raw_info_on_event(void* context, SceneManagerEvent event) { | ||||||
|  | |||||||
| @ -46,7 +46,6 @@ static void | |||||||
| void lfrfid_scene_read_on_enter(void* context) { | void lfrfid_scene_read_on_enter(void* context) { | ||||||
|     LfRfid* app = context; |     LfRfid* app = context; | ||||||
| 
 | 
 | ||||||
|     DOLPHIN_DEED(DolphinDeedRfidRead); |  | ||||||
|     if(app->read_type == LFRFIDWorkerReadTypePSKOnly) { |     if(app->read_type == LFRFIDWorkerReadTypePSKOnly) { | ||||||
|         lfrfid_view_read_set_read_mode(app->read_view, LfRfidReadPskOnly); |         lfrfid_view_read_set_read_mode(app->read_view, LfRfidReadPskOnly); | ||||||
|     } else if(app->read_type == LFRFIDWorkerReadTypeASKOnly) { |     } else if(app->read_type == LFRFIDWorkerReadTypeASKOnly) { | ||||||
| @ -79,10 +78,10 @@ bool lfrfid_scene_read_on_event(void* context, SceneManagerEvent event) { | |||||||
|             consumed = true; |             consumed = true; | ||||||
|         } else if(event.event == LfRfidEventReadDone) { |         } else if(event.event == LfRfidEventReadDone) { | ||||||
|             app->protocol_id = app->protocol_id_next; |             app->protocol_id = app->protocol_id_next; | ||||||
|             DOLPHIN_DEED(DolphinDeedRfidReadSuccess); |  | ||||||
|             notification_message(app->notifications, &sequence_success); |             notification_message(app->notifications, &sequence_success); | ||||||
|             furi_string_reset(app->file_name); |             furi_string_reset(app->file_name); | ||||||
|             scene_manager_next_scene(app->scene_manager, LfRfidSceneReadSuccess); |             scene_manager_next_scene(app->scene_manager, LfRfidSceneReadSuccess); | ||||||
|  |             DOLPHIN_DEED(DolphinDeedRfidReadSuccess); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|         } else if(event.event == LfRfidEventReadStartPSK) { |         } else if(event.event == LfRfidEventReadStartPSK) { | ||||||
|             if(app->read_type == LFRFIDWorkerReadTypeAuto) { |             if(app->read_type == LFRFIDWorkerReadTypeAuto) { | ||||||
|  | |||||||
| @ -1,4 +1,5 @@ | |||||||
| #include "../lfrfid_i.h" | #include "../lfrfid_i.h" | ||||||
|  | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     SubmenuIndexSave, |     SubmenuIndexSave, | ||||||
| @ -43,6 +44,7 @@ bool lfrfid_scene_read_key_menu_on_event(void* context, SceneManagerEvent event) | |||||||
|             consumed = true; |             consumed = true; | ||||||
|         } else if(event.event == SubmenuIndexEmulate) { |         } else if(event.event == SubmenuIndexEmulate) { | ||||||
|             scene_manager_next_scene(app->scene_manager, LfRfidSceneEmulate); |             scene_manager_next_scene(app->scene_manager, LfRfidSceneEmulate); | ||||||
|  |             DOLPHIN_DEED(DolphinDeedRfidEmulate); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|         } |         } | ||||||
|         scene_manager_set_scene_state(app->scene_manager, LfRfidSceneReadKeyMenu, event.event); |         scene_manager_set_scene_state(app->scene_manager, LfRfidSceneReadKeyMenu, event.event); | ||||||
|  | |||||||
| @ -1,5 +1,4 @@ | |||||||
| #include "../lfrfid_i.h" | #include "../lfrfid_i.h" | ||||||
| #include <dolphin/dolphin.h> |  | ||||||
| 
 | 
 | ||||||
| void lfrfid_scene_save_data_on_enter(void* context) { | void lfrfid_scene_save_data_on_enter(void* context) { | ||||||
|     LfRfid* app = context; |     LfRfid* app = context; | ||||||
| @ -32,7 +31,6 @@ bool lfrfid_scene_save_data_on_event(void* context, SceneManagerEvent event) { | |||||||
|             consumed = true; |             consumed = true; | ||||||
|             size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id); |             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); |             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_next_scene(scene_manager, LfRfidSceneSaveName); | ||||||
|             scene_manager_set_scene_state(scene_manager, LfRfidSceneSaveData, 1); |             scene_manager_set_scene_state(scene_manager, LfRfidSceneSaveData, 1); | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -1,5 +1,6 @@ | |||||||
| #include <lib/toolbox/random_name.h> | #include <lib/toolbox/random_name.h> | ||||||
| #include "../lfrfid_i.h" | #include "../lfrfid_i.h" | ||||||
|  | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| void lfrfid_scene_save_name_on_enter(void* context) { | void lfrfid_scene_save_name_on_enter(void* context) { | ||||||
|     LfRfid* app = context; |     LfRfid* app = context; | ||||||
| @ -55,6 +56,13 @@ bool lfrfid_scene_save_name_on_event(void* context, SceneManagerEvent event) { | |||||||
| 
 | 
 | ||||||
|             if(lfrfid_save_key(app)) { |             if(lfrfid_save_key(app)) { | ||||||
|                 scene_manager_next_scene(scene_manager, LfRfidSceneSaveSuccess); |                 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 { |             } else { | ||||||
|                 scene_manager_search_and_switch_to_previous_scene( |                 scene_manager_search_and_switch_to_previous_scene( | ||||||
|                     scene_manager, LfRfidSceneReadKeyMenu); |                     scene_manager, LfRfidSceneReadKeyMenu); | ||||||
|  | |||||||
| @ -1,5 +1,4 @@ | |||||||
| #include "../lfrfid_i.h" | #include "../lfrfid_i.h" | ||||||
| #include <dolphin/dolphin.h> |  | ||||||
| 
 | 
 | ||||||
| void lfrfid_scene_save_success_on_enter(void* context) { | void lfrfid_scene_save_success_on_enter(void* context) { | ||||||
|     LfRfid* app = context; |     LfRfid* app = context; | ||||||
| @ -8,7 +7,6 @@ void lfrfid_scene_save_success_on_enter(void* context) { | |||||||
|     // Clear state of data enter scene
 |     // Clear state of data enter scene
 | ||||||
|     scene_manager_set_scene_state(app->scene_manager, LfRfidSceneSaveData, 0); |     scene_manager_set_scene_state(app->scene_manager, LfRfidSceneSaveData, 0); | ||||||
| 
 | 
 | ||||||
|     DOLPHIN_DEED(DolphinDeedRfidSave); |  | ||||||
|     popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); |     popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); | ||||||
|     popup_set_header(popup, "Saved!", 5, 7, AlignLeft, AlignTop); |     popup_set_header(popup, "Saved!", 5, 7, AlignLeft, AlignTop); | ||||||
|     popup_set_context(popup, app); |     popup_set_context(popup, app); | ||||||
|  | |||||||
| @ -1,4 +1,5 @@ | |||||||
| #include "../lfrfid_i.h" | #include "../lfrfid_i.h" | ||||||
|  | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     SubmenuIndexEmulate, |     SubmenuIndexEmulate, | ||||||
| @ -42,6 +43,7 @@ bool lfrfid_scene_saved_key_menu_on_event(void* context, SceneManagerEvent event | |||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == SubmenuIndexEmulate) { |         if(event.event == SubmenuIndexEmulate) { | ||||||
|             scene_manager_next_scene(app->scene_manager, LfRfidSceneEmulate); |             scene_manager_next_scene(app->scene_manager, LfRfidSceneEmulate); | ||||||
|  |             DOLPHIN_DEED(DolphinDeedRfidEmulate); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|         } else if(event.event == SubmenuIndexWrite) { |         } else if(event.event == SubmenuIndexWrite) { | ||||||
|             scene_manager_next_scene(app->scene_manager, LfRfidSceneWrite); |             scene_manager_next_scene(app->scene_manager, LfRfidSceneWrite); | ||||||
|  | |||||||
| @ -1,4 +1,5 @@ | |||||||
| #include "../lfrfid_i.h" | #include "../lfrfid_i.h" | ||||||
|  | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     SubmenuIndexRead, |     SubmenuIndexRead, | ||||||
| @ -47,6 +48,7 @@ bool lfrfid_scene_start_on_event(void* context, SceneManagerEvent event) { | |||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == SubmenuIndexRead) { |         if(event.event == SubmenuIndexRead) { | ||||||
|             scene_manager_next_scene(app->scene_manager, LfRfidSceneRead); |             scene_manager_next_scene(app->scene_manager, LfRfidSceneRead); | ||||||
|  |             DOLPHIN_DEED(DolphinDeedRfidRead); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|         } else if(event.event == SubmenuIndexSaved) { |         } else if(event.event == SubmenuIndexSaved) { | ||||||
|             furi_string_set(app->file_path, LFRFID_APP_FOLDER); |             furi_string_set(app->file_path, LFRFID_APP_FOLDER); | ||||||
|  | |||||||
| @ -1,5 +1,6 @@ | |||||||
| #include "lfrfid_view_read.h" | #include "lfrfid_view_read.h" | ||||||
| #include <gui/elements.h> | #include <gui/elements.h> | ||||||
|  | #include <assets_icons.h> | ||||||
| 
 | 
 | ||||||
| #define TEMP_STR_LEN 128 | #define TEMP_STR_LEN 128 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,5 +1,6 @@ | |||||||
| #include "nfc_i.h" | #include "nfc_i.h" | ||||||
| #include "furi_hal_nfc.h" | #include "furi_hal_nfc.h" | ||||||
|  | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| bool nfc_custom_event_callback(void* context, uint32_t event) { | bool nfc_custom_event_callback(void* context, uint32_t event) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
| @ -275,12 +276,15 @@ int32_t nfc_app(void* p) { | |||||||
|             if(nfc_device_load(nfc->dev, p, true)) { |             if(nfc_device_load(nfc->dev, p, true)) { | ||||||
|                 if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { |                 if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { | ||||||
|                     scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate); |                     scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate); | ||||||
|  |                     DOLPHIN_DEED(DolphinDeedNfcEmulate); | ||||||
|                 } else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) { |                 } else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) { | ||||||
|                     scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate); |                     scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate); | ||||||
|  |                     DOLPHIN_DEED(DolphinDeedNfcEmulate); | ||||||
|                 } else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) { |                 } else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) { | ||||||
|                     scene_manager_next_scene(nfc->scene_manager, NfcSceneDeviceInfo); |                     scene_manager_next_scene(nfc->scene_manager, NfcSceneDeviceInfo); | ||||||
|                 } else { |                 } else { | ||||||
|                     scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); |                     scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); | ||||||
|  |                     DOLPHIN_DEED(DolphinDeedNfcEmulate); | ||||||
|                 } |                 } | ||||||
|             } else { |             } else { | ||||||
|                 // Exit app
 |                 // Exit app
 | ||||||
|  | |||||||
| @ -7,6 +7,7 @@ | |||||||
| 
 | 
 | ||||||
| #include <gui/gui.h> | #include <gui/gui.h> | ||||||
| #include <gui/view.h> | #include <gui/view.h> | ||||||
|  | #include <assets_icons.h> | ||||||
| #include <gui/view_dispatcher.h> | #include <gui/view_dispatcher.h> | ||||||
| #include <gui/scene_manager.h> | #include <gui/scene_manager.h> | ||||||
| #include <cli/cli.h> | #include <cli/cli.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_delete, MfClassicKeysDelete) | ||||||
| ADD_SCENE(nfc, mf_classic_keys_warn_duplicate, MfClassicKeysWarnDuplicate) | ADD_SCENE(nfc, mf_classic_keys_warn_duplicate, MfClassicKeysWarnDuplicate) | ||||||
| ADD_SCENE(nfc, mf_classic_dict_attack, MfClassicDictAttack) | 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_read_success, EmvReadSuccess) | ||||||
| ADD_SCENE(nfc, emv_menu, EmvMenu) | ADD_SCENE(nfc, emv_menu, EmvMenu) | ||||||
| ADD_SCENE(nfc, emulate_apdu_sequence, EmulateApduSequence) | ADD_SCENE(nfc, emulate_apdu_sequence, EmulateApduSequence) | ||||||
|  | |||||||
| @ -1,5 +1,4 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
| #include <dolphin/dolphin.h> |  | ||||||
| 
 | 
 | ||||||
| #define NFC_SCENE_DETECT_READER_PAIR_NONCES_MAX (10U) | #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) { | void nfc_scene_detect_reader_on_enter(void* context) { | ||||||
|     Nfc* nfc = context; |     Nfc* nfc = context; | ||||||
|     DOLPHIN_DEED(DolphinDeedNfcDetectReader); |  | ||||||
| 
 | 
 | ||||||
|     detect_reader_set_callback(nfc->detect_reader, nfc_scene_detect_reader_callback, nfc); |     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); |     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
 |     // Store number of collected nonces in scene state
 | ||||||
|     scene_manager_set_scene_state(nfc->scene_manager, NfcSceneDetectReader, 0); |     scene_manager_set_scene_state(nfc->scene_manager, NfcSceneDetectReader, 0); | ||||||
|  | |||||||
| @ -1,5 +1,4 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
| #include <dolphin/dolphin.h> |  | ||||||
| 
 | 
 | ||||||
| #define NFC_SCENE_EMULATE_UID_LOG_SIZE_MAX (200) | #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) { | void nfc_scene_emulate_uid_on_enter(void* context) { | ||||||
|     Nfc* nfc = context; |     Nfc* nfc = context; | ||||||
|     DOLPHIN_DEED(DolphinDeedNfcEmulate); |  | ||||||
| 
 | 
 | ||||||
|     // Setup Widget
 |     // Setup Widget
 | ||||||
|     nfc_scene_emulate_uid_widget_config(nfc, false); |     nfc_scene_emulate_uid_widget_config(nfc, false); | ||||||
|  | |||||||
| @ -1,6 +1,5 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
| #include "../helpers/nfc_emv_parser.h" | #include "../helpers/nfc_emv_parser.h" | ||||||
| #include <dolphin/dolphin.h> |  | ||||||
| 
 | 
 | ||||||
| void nfc_scene_emv_read_success_widget_callback( | void nfc_scene_emv_read_success_widget_callback( | ||||||
|     GuiButtonType result, |     GuiButtonType result, | ||||||
| @ -15,7 +14,6 @@ void nfc_scene_emv_read_success_widget_callback( | |||||||
| void nfc_scene_emv_read_success_on_enter(void* context) { | void nfc_scene_emv_read_success_on_enter(void* context) { | ||||||
|     Nfc* nfc = context; |     Nfc* nfc = context; | ||||||
|     EmvData* emv_data = &nfc->dev->dev_data.emv_data; |     EmvData* emv_data = &nfc->dev->dev_data.emv_data; | ||||||
|     DOLPHIN_DEED(DolphinDeedNfcReadSuccess); |  | ||||||
| 
 | 
 | ||||||
|     // Setup Custom Widget view
 |     // Setup Custom Widget view
 | ||||||
|     widget_add_button_element( |     widget_add_button_element( | ||||||
|  | |||||||
| @ -1,4 +1,5 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
|  | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| #define TAG "NfcMfClassicDictAttack" | #define TAG "NfcMfClassicDictAttack" | ||||||
| 
 | 
 | ||||||
| @ -110,6 +111,7 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent | |||||||
|             } else { |             } else { | ||||||
|                 notification_message(nfc->notifications, &sequence_success); |                 notification_message(nfc->notifications, &sequence_success); | ||||||
|                 scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSuccess); |                 scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSuccess); | ||||||
|  |                 DOLPHIN_DEED(DolphinDeedNfcReadSuccess); | ||||||
|                 consumed = true; |                 consumed = true; | ||||||
|             } |             } | ||||||
|         } else if(event.event == NfcWorkerEventAborted) { |         } else if(event.event == NfcWorkerEventAborted) { | ||||||
| @ -119,6 +121,8 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent | |||||||
|             } else { |             } else { | ||||||
|                 notification_message(nfc->notifications, &sequence_success); |                 notification_message(nfc->notifications, &sequence_success); | ||||||
|                 scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSuccess); |                 scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSuccess); | ||||||
|  |                 // Counting failed attempts too
 | ||||||
|  |                 DOLPHIN_DEED(DolphinDeedNfcReadSuccess); | ||||||
|                 consumed = true; |                 consumed = true; | ||||||
|             } |             } | ||||||
|         } else if(event.event == NfcWorkerEventCardDetected) { |         } else if(event.event == NfcWorkerEventCardDetected) { | ||||||
|  | |||||||
| @ -1,5 +1,4 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
| #include <dolphin/dolphin.h> |  | ||||||
| 
 | 
 | ||||||
| #define NFC_MF_CLASSIC_DATA_NOT_CHANGED (0UL) | #define NFC_MF_CLASSIC_DATA_NOT_CHANGED (0UL) | ||||||
| #define NFC_MF_CLASSIC_DATA_CHANGED (1UL) | #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) { | void nfc_scene_mf_classic_emulate_on_enter(void* context) { | ||||||
|     Nfc* nfc = context; |     Nfc* nfc = context; | ||||||
|     DOLPHIN_DEED(DolphinDeedNfcEmulate); |  | ||||||
| 
 | 
 | ||||||
|     // Setup view
 |     // Setup view
 | ||||||
|     Popup* popup = nfc->popup; |     Popup* popup = nfc->popup; | ||||||
|  | |||||||
| @ -34,8 +34,6 @@ void nfc_scene_mf_classic_keys_on_enter(void* context) { | |||||||
|     widget_add_string_element(nfc->widget, 0, 32, AlignLeft, AlignTop, FontSecondary, temp_str); |     widget_add_string_element(nfc->widget, 0, 32, AlignLeft, AlignTop, FontSecondary, temp_str); | ||||||
|     widget_add_button_element( |     widget_add_button_element( | ||||||
|         nfc->widget, GuiButtonTypeCenter, "Add", nfc_scene_mf_classic_keys_widget_callback, nfc); |         nfc->widget, GuiButtonTypeCenter, "Add", nfc_scene_mf_classic_keys_widget_callback, nfc); | ||||||
|     widget_add_button_element( |  | ||||||
|         nfc->widget, GuiButtonTypeLeft, "Back", nfc_scene_mf_classic_keys_widget_callback, nfc); |  | ||||||
|     widget_add_icon_element(nfc->widget, 87, 13, &I_Keychain_39x36); |     widget_add_icon_element(nfc->widget, 87, 13, &I_Keychain_39x36); | ||||||
|     if(user_dict_keys_total > 0) { |     if(user_dict_keys_total > 0) { | ||||||
|         widget_add_button_element( |         widget_add_button_element( | ||||||
| @ -57,9 +55,6 @@ bool nfc_scene_mf_classic_keys_on_event(void* context, SceneManagerEvent event) | |||||||
|         if(event.event == GuiButtonTypeCenter) { |         if(event.event == GuiButtonTypeCenter) { | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicKeysAdd); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicKeysAdd); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|         } else if(event.event == GuiButtonTypeLeft) { |  | ||||||
|             scene_manager_previous_scene(nfc->scene_manager); |  | ||||||
|             consumed = true; |  | ||||||
|         } else if(event.event == GuiButtonTypeRight) { |         } else if(event.event == GuiButtonTypeRight) { | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicKeysList); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicKeysList); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|  | |||||||
| @ -1,4 +1,5 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
|  | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| void nfc_scene_mf_classic_keys_add_byte_input_callback(void* context) { | void nfc_scene_mf_classic_keys_add_byte_input_callback(void* context) { | ||||||
|     Nfc* nfc = 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); |                         nfc->scene_manager, NfcSceneMfClassicKeysWarnDuplicate); | ||||||
|                 } else if(mf_classic_dict_add_key(dict, nfc->byte_input_store)) { |                 } else if(mf_classic_dict_add_key(dict, nfc->byte_input_store)) { | ||||||
|                     scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess); |                     scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess); | ||||||
|  |                     DOLPHIN_DEED(DolphinDeedNfcMfcAdd); | ||||||
|                 } else { |                 } else { | ||||||
|                     scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound); |                     scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound); | ||||||
|                 } |                 } | ||||||
|  | |||||||
| @ -36,8 +36,6 @@ bool nfc_scene_mf_classic_menu_on_event(void* context, SceneManagerEvent event) | |||||||
| 
 | 
 | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == SubmenuIndexSave) { |         if(event.event == SubmenuIndexSave) { | ||||||
|             DOLPHIN_DEED(DolphinDeedNfcMfcAdd); |  | ||||||
| 
 |  | ||||||
|             scene_manager_set_scene_state( |             scene_manager_set_scene_state( | ||||||
|                 nfc->scene_manager, NfcSceneMfClassicMenu, SubmenuIndexSave); |                 nfc->scene_manager, NfcSceneMfClassicMenu, SubmenuIndexSave); | ||||||
|             nfc->dev->format = NfcDeviceSaveFormatMifareClassic; |             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( |             scene_manager_set_scene_state( | ||||||
|                 nfc->scene_manager, NfcSceneMfClassicMenu, SubmenuIndexEmulate); |                 nfc->scene_manager, NfcSceneMfClassicMenu, SubmenuIndexEmulate); | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate); |             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; |             consumed = true; | ||||||
|         } else if(event.event == SubmenuIndexInfo) { |         } else if(event.event == SubmenuIndexInfo) { | ||||||
|             scene_manager_set_scene_state( |             scene_manager_set_scene_state( | ||||||
|  | |||||||
| @ -1,5 +1,4 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
| #include <dolphin/dolphin.h> |  | ||||||
| 
 | 
 | ||||||
| void nfc_scene_mf_classic_read_success_widget_callback( | void nfc_scene_mf_classic_read_success_widget_callback( | ||||||
|     GuiButtonType result, |     GuiButtonType result, | ||||||
| @ -18,8 +17,6 @@ void nfc_scene_mf_classic_read_success_on_enter(void* context) { | |||||||
|     NfcDeviceData* dev_data = &nfc->dev->dev_data; |     NfcDeviceData* dev_data = &nfc->dev->dev_data; | ||||||
|     MfClassicData* mf_data = &dev_data->mf_classic_data; |     MfClassicData* mf_data = &dev_data->mf_classic_data; | ||||||
| 
 | 
 | ||||||
|     DOLPHIN_DEED(DolphinDeedNfcReadSuccess); |  | ||||||
| 
 |  | ||||||
|     // Setup view
 |     // Setup view
 | ||||||
|     Widget* widget = nfc->widget; |     Widget* widget = nfc->widget; | ||||||
|     widget_add_button_element( |     widget_add_button_element( | ||||||
|  | |||||||
							
								
								
									
										98
									
								
								applications/main/nfc/scenes/nfc_scene_mf_classic_update.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								applications/main/nfc/scenes/nfc_scene_mf_classic_update.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,98 @@ | |||||||
|  | #include "../nfc_i.h" | ||||||
|  | #include <dolphin/dolphin.h> | ||||||
|  | 
 | ||||||
|  | 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); | ||||||
|  | } | ||||||
| @ -0,0 +1,44 @@ | |||||||
|  | #include "../nfc_i.h" | ||||||
|  | #include <dolphin/dolphin.h> | ||||||
|  | 
 | ||||||
|  | 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); | ||||||
|  | } | ||||||
							
								
								
									
										92
									
								
								applications/main/nfc/scenes/nfc_scene_mf_classic_write.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								applications/main/nfc/scenes/nfc_scene_mf_classic_write.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,92 @@ | |||||||
|  | #include "../nfc_i.h" | ||||||
|  | #include <dolphin/dolphin.h> | ||||||
|  | 
 | ||||||
|  | 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); | ||||||
|  | } | ||||||
| @ -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); | ||||||
|  | } | ||||||
| @ -0,0 +1,44 @@ | |||||||
|  | #include "../nfc_i.h" | ||||||
|  | #include <dolphin/dolphin.h> | ||||||
|  | 
 | ||||||
|  | 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); | ||||||
|  | } | ||||||
| @ -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); | ||||||
|  | } | ||||||
| @ -1,4 +1,5 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
|  | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| enum SubmenuIndex { | enum SubmenuIndex { | ||||||
|     SubmenuIndexSave, |     SubmenuIndexSave, | ||||||
| @ -48,6 +49,11 @@ bool nfc_scene_mf_desfire_menu_on_event(void* context, SceneManagerEvent event) | |||||||
|             consumed = true; |             consumed = true; | ||||||
|         } else if(event.event == SubmenuIndexEmulateUid) { |         } else if(event.event == SubmenuIndexEmulateUid) { | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); |             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; |             consumed = true; | ||||||
|         } else if(event.event == SubmenuIndexInfo) { |         } else if(event.event == SubmenuIndexInfo) { | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); | ||||||
|  | |||||||
| @ -1,5 +1,4 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
| #include <dolphin/dolphin.h> |  | ||||||
| 
 | 
 | ||||||
| #define NFC_MF_UL_DATA_NOT_CHANGED (0UL) | #define NFC_MF_UL_DATA_NOT_CHANGED (0UL) | ||||||
| #define NFC_MF_UL_DATA_CHANGED (1UL) | #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) { | void nfc_scene_mf_ultralight_emulate_on_enter(void* context) { | ||||||
|     Nfc* nfc = context; |     Nfc* nfc = context; | ||||||
|     DOLPHIN_DEED(DolphinDeedNfcEmulate); |  | ||||||
| 
 | 
 | ||||||
|     // Setup view
 |     // Setup view
 | ||||||
|     Popup* popup = nfc->popup; |     Popup* popup = nfc->popup; | ||||||
|  | |||||||
| @ -1,4 +1,5 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
|  | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| enum SubmenuIndex { | enum SubmenuIndex { | ||||||
|     SubmenuIndexUnlock, |     SubmenuIndexUnlock, | ||||||
| @ -56,6 +57,11 @@ bool nfc_scene_mf_ultralight_menu_on_event(void* context, SceneManagerEvent even | |||||||
|             consumed = true; |             consumed = true; | ||||||
|         } else if(event.event == SubmenuIndexEmulate) { |         } else if(event.event == SubmenuIndexEmulate) { | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate); |             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; |             consumed = true; | ||||||
|         } else if(event.event == SubmenuIndexUnlock) { |         } else if(event.event == SubmenuIndexUnlock) { | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockMenu); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockMenu); | ||||||
|  | |||||||
| @ -1,5 +1,4 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
| #include <dolphin/dolphin.h> |  | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     NfcSceneMfUlReadStateIdle, |     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) { | void nfc_scene_mf_ultralight_read_auth_on_enter(void* context) { | ||||||
|     Nfc* nfc = context; |     Nfc* nfc = context; | ||||||
|     DOLPHIN_DEED(DolphinDeedNfcRead); |  | ||||||
| 
 | 
 | ||||||
|     nfc_device_clear(nfc->dev); |     nfc_device_clear(nfc->dev); | ||||||
|     // Setup view
 |     // Setup view
 | ||||||
|  | |||||||
| @ -1,5 +1,4 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
| #include <dolphin/dolphin.h> |  | ||||||
| 
 | 
 | ||||||
| void nfc_scene_mf_ultralight_read_auth_result_widget_callback( | void nfc_scene_mf_ultralight_read_auth_result_widget_callback( | ||||||
|     GuiButtonType result, |     GuiButtonType result, | ||||||
| @ -37,7 +36,6 @@ void nfc_scene_mf_ultralight_read_auth_result_on_enter(void* context) { | |||||||
|     widget_add_string_element( |     widget_add_string_element( | ||||||
|         widget, 0, 17, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(temp_str)); |         widget, 0, 17, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(temp_str)); | ||||||
|     if(mf_ul_data->auth_success) { |     if(mf_ul_data->auth_success) { | ||||||
|         DOLPHIN_DEED(DolphinDeedNfcReadSuccess); |  | ||||||
|         furi_string_printf( |         furi_string_printf( | ||||||
|             temp_str, |             temp_str, | ||||||
|             "Password: %02X %02X %02X %02X", |             "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]); |             config_pages->auth_data.pack.raw[1]); | ||||||
|         widget_add_string_element( |         widget_add_string_element( | ||||||
|             widget, 0, 39, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(temp_str)); |             widget, 0, 39, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(temp_str)); | ||||||
|     } else { |  | ||||||
|         DOLPHIN_DEED(DolphinDeedNfcMfulError); |  | ||||||
|     } |     } | ||||||
|     furi_string_printf( |     furi_string_printf( | ||||||
|         temp_str, "Pages Read: %d/%d", mf_ul_data->data_read / 4, mf_ul_data->data_size / 4); |         temp_str, "Pages Read: %d/%d", mf_ul_data->data_read / 4, mf_ul_data->data_size / 4); | ||||||
|  | |||||||
| @ -1,5 +1,4 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
| #include <dolphin/dolphin.h> |  | ||||||
| 
 | 
 | ||||||
| void nfc_scene_mf_ultralight_read_success_widget_callback( | void nfc_scene_mf_ultralight_read_success_widget_callback( | ||||||
|     GuiButtonType result, |     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) { | void nfc_scene_mf_ultralight_read_success_on_enter(void* context) { | ||||||
|     Nfc* nfc = context; |     Nfc* nfc = context; | ||||||
|     DOLPHIN_DEED(DolphinDeedNfcReadSuccess); |  | ||||||
| 
 | 
 | ||||||
|     // Setup widget view
 |     // Setup widget view
 | ||||||
|     FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; |     FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; | ||||||
|  | |||||||
| @ -1,4 +1,5 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
|  | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| void nfc_scene_mf_ultralight_unlock_warn_dialog_callback(DialogExResult result, void* context) { | void nfc_scene_mf_ultralight_unlock_warn_dialog_callback(DialogExResult result, void* context) { | ||||||
|     Nfc* nfc = 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.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == DialogExResultCenter) { |         if(event.event == DialogExResultCenter) { | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadAuth); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadAuth); | ||||||
|  |             DOLPHIN_DEED(DolphinDeedNfcRead); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -1,4 +1,5 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
|  | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| enum SubmenuIndex { | enum SubmenuIndex { | ||||||
|     SubmenuIndexSaveUid, |     SubmenuIndexSaveUid, | ||||||
| @ -41,6 +42,11 @@ bool nfc_scene_nfca_menu_on_event(void* context, SceneManagerEvent event) { | |||||||
|             consumed = true; |             consumed = true; | ||||||
|         } else if(event.event == SubmenuIndexEmulateUid) { |         } else if(event.event == SubmenuIndexEmulateUid) { | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); |             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; |             consumed = true; | ||||||
|         } else if(event.event == SubmenuIndexInfo) { |         } else if(event.event == SubmenuIndexInfo) { | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); | ||||||
|  | |||||||
| @ -1,5 +1,4 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
| #include <dolphin/dolphin.h> |  | ||||||
| 
 | 
 | ||||||
| void nfc_scene_nfca_read_success_widget_callback( | void nfc_scene_nfca_read_success_widget_callback( | ||||||
|     GuiButtonType result, |     GuiButtonType result, | ||||||
| @ -16,8 +15,6 @@ void nfc_scene_nfca_read_success_widget_callback( | |||||||
| void nfc_scene_nfca_read_success_on_enter(void* context) { | void nfc_scene_nfca_read_success_on_enter(void* context) { | ||||||
|     Nfc* nfc = context; |     Nfc* nfc = context; | ||||||
| 
 | 
 | ||||||
|     DOLPHIN_DEED(DolphinDeedNfcReadSuccess); |  | ||||||
| 
 |  | ||||||
|     // Setup view
 |     // Setup view
 | ||||||
|     FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; |     FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; | ||||||
|     Widget* widget = nfc->widget; |     Widget* widget = nfc->widget; | ||||||
|  | |||||||
| @ -39,7 +39,6 @@ void nfc_scene_read_set_state(Nfc* nfc, NfcSceneReadState state) { | |||||||
| 
 | 
 | ||||||
| void nfc_scene_read_on_enter(void* context) { | void nfc_scene_read_on_enter(void* context) { | ||||||
|     Nfc* nfc = context; |     Nfc* nfc = context; | ||||||
|     DOLPHIN_DEED(DolphinDeedNfcRead); |  | ||||||
| 
 | 
 | ||||||
|     nfc_device_clear(nfc->dev); |     nfc_device_clear(nfc->dev); | ||||||
|     // Setup view
 |     // Setup view
 | ||||||
| @ -62,26 +61,32 @@ bool nfc_scene_read_on_event(void* context, SceneManagerEvent event) { | |||||||
|            (event.event == NfcWorkerEventReadUidNfcV)) { |            (event.event == NfcWorkerEventReadUidNfcV)) { | ||||||
|             notification_message(nfc->notifications, &sequence_success); |             notification_message(nfc->notifications, &sequence_success); | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardSuccess); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardSuccess); | ||||||
|  |             DOLPHIN_DEED(DolphinDeedNfcReadSuccess); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|         } else if(event.event == NfcWorkerEventReadUidNfcA) { |         } else if(event.event == NfcWorkerEventReadUidNfcA) { | ||||||
|             notification_message(nfc->notifications, &sequence_success); |             notification_message(nfc->notifications, &sequence_success); | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcaReadSuccess); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcaReadSuccess); | ||||||
|  |             DOLPHIN_DEED(DolphinDeedNfcReadSuccess); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|         } else if(event.event == NfcWorkerEventReadMfUltralight) { |         } else if(event.event == NfcWorkerEventReadMfUltralight) { | ||||||
|             notification_message(nfc->notifications, &sequence_success); |             notification_message(nfc->notifications, &sequence_success); | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadSuccess); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadSuccess); | ||||||
|  |             DOLPHIN_DEED(DolphinDeedNfcReadSuccess); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|         } else if(event.event == NfcWorkerEventReadMfClassicDone) { |         } else if(event.event == NfcWorkerEventReadMfClassicDone) { | ||||||
|             notification_message(nfc->notifications, &sequence_success); |             notification_message(nfc->notifications, &sequence_success); | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSuccess); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSuccess); | ||||||
|  |             DOLPHIN_DEED(DolphinDeedNfcReadSuccess); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|         } else if(event.event == NfcWorkerEventReadMfDesfire) { |         } else if(event.event == NfcWorkerEventReadMfDesfire) { | ||||||
|             notification_message(nfc->notifications, &sequence_success); |             notification_message(nfc->notifications, &sequence_success); | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireReadSuccess); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireReadSuccess); | ||||||
|  |             DOLPHIN_DEED(DolphinDeedNfcReadSuccess); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|         } else if(event.event == NfcWorkerEventReadBankCard) { |         } else if(event.event == NfcWorkerEventReadBankCard) { | ||||||
|             notification_message(nfc->notifications, &sequence_success); |             notification_message(nfc->notifications, &sequence_success); | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneEmvReadSuccess); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneEmvReadSuccess); | ||||||
|  |             DOLPHIN_DEED(DolphinDeedNfcReadSuccess); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|         } else if(event.event == NfcWorkerEventReadMfClassicDictAttackRequired) { |         } else if(event.event == NfcWorkerEventReadMfClassicDictAttackRequired) { | ||||||
|             if(mf_classic_dict_check_presence(MfClassicDictTypeFlipper)) { |             if(mf_classic_dict_check_presence(MfClassicDictTypeFlipper)) { | ||||||
|  | |||||||
| @ -1,5 +1,4 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
| #include <dolphin/dolphin.h> |  | ||||||
| 
 | 
 | ||||||
| void nfc_scene_read_card_success_widget_callback( | void nfc_scene_read_card_success_widget_callback( | ||||||
|     GuiButtonType result, |     GuiButtonType result, | ||||||
| @ -18,7 +17,6 @@ void nfc_scene_read_card_success_on_enter(void* context) { | |||||||
| 
 | 
 | ||||||
|     FuriString* temp_str; |     FuriString* temp_str; | ||||||
|     temp_str = furi_string_alloc(); |     temp_str = furi_string_alloc(); | ||||||
|     DOLPHIN_DEED(DolphinDeedNfcReadSuccess); |  | ||||||
| 
 | 
 | ||||||
|     // Setup view
 |     // Setup view
 | ||||||
|     FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; |     FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; | ||||||
|  | |||||||
| @ -2,6 +2,7 @@ | |||||||
| #include <lib/toolbox/random_name.h> | #include <lib/toolbox/random_name.h> | ||||||
| #include <gui/modules/validators.h> | #include <gui/modules/validators.h> | ||||||
| #include <toolbox/path.h> | #include <toolbox/path.h> | ||||||
|  | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| void nfc_scene_save_name_text_input_callback(void* context) { | void nfc_scene_save_name_text_input_callback(void* context) { | ||||||
|     Nfc* nfc = 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); |             strlcpy(nfc->dev->dev_name, nfc->text_store, strlen(nfc->text_store) + 1); | ||||||
|             if(nfc_device_save(nfc->dev, nfc->text_store)) { |             if(nfc_device_save(nfc->dev, nfc->text_store)) { | ||||||
|                 scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess); |                 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; |                 consumed = true; | ||||||
|             } else { |             } else { | ||||||
|                 consumed = scene_manager_search_and_switch_to_previous_scene( |                 consumed = scene_manager_search_and_switch_to_previous_scene( | ||||||
|  | |||||||
| @ -1,5 +1,4 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
| #include <dolphin/dolphin.h> |  | ||||||
| 
 | 
 | ||||||
| void nfc_scene_save_success_popup_callback(void* context) { | void nfc_scene_save_success_popup_callback(void* context) { | ||||||
|     Nfc* nfc = 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) { | void nfc_scene_save_success_on_enter(void* context) { | ||||||
|     Nfc* nfc = context; |     Nfc* nfc = context; | ||||||
|     DOLPHIN_DEED(DolphinDeedNfcSave); |  | ||||||
| 
 | 
 | ||||||
|     // Setup view
 |     // Setup view
 | ||||||
|     Popup* popup = nfc->popup; |     Popup* popup = nfc->popup; | ||||||
|  | |||||||
| @ -1,8 +1,12 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
|  | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| enum SubmenuIndex { | enum SubmenuIndex { | ||||||
|     SubmenuIndexEmulate, |     SubmenuIndexEmulate, | ||||||
|     SubmenuIndexEditUid, |     SubmenuIndexEditUid, | ||||||
|  |     SubmenuIndexDetectReader, | ||||||
|  |     SubmenuIndexWrite, | ||||||
|  |     SubmenuIndexUpdate, | ||||||
|     SubmenuIndexRename, |     SubmenuIndexRename, | ||||||
|     SubmenuIndexDelete, |     SubmenuIndexDelete, | ||||||
|     SubmenuIndexInfo, |     SubmenuIndexInfo, | ||||||
| @ -41,6 +45,28 @@ void nfc_scene_saved_menu_on_enter(void* context) { | |||||||
|         submenu_add_item( |         submenu_add_item( | ||||||
|             submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_saved_menu_submenu_callback, nfc); |             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_add_item( | ||||||
|         submenu, "Info", SubmenuIndexInfo, nfc_scene_saved_menu_submenu_callback, nfc); |         submenu, "Info", SubmenuIndexInfo, nfc_scene_saved_menu_submenu_callback, nfc); | ||||||
|     if(nfc->dev->shadow_file_exist) { |     if(nfc->dev->shadow_file_exist) { | ||||||
| @ -76,6 +102,16 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { | |||||||
|             } else { |             } else { | ||||||
|                 scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); |                 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; |             consumed = true; | ||||||
|         } else if(event.event == SubmenuIndexRename) { |         } else if(event.event == SubmenuIndexRename) { | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); | ||||||
|  | |||||||
| @ -1,5 +1,4 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
| #include <dolphin/dolphin.h> |  | ||||||
| 
 | 
 | ||||||
| void nfc_scene_set_uid_byte_input_callback(void* context) { | void nfc_scene_set_uid_byte_input_callback(void* context) { | ||||||
|     Nfc* nfc = 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.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == NfcCustomEventByteInputDone) { |         if(event.event == NfcCustomEventByteInputDone) { | ||||||
|             DOLPHIN_DEED(DolphinDeedNfcAddSave); |  | ||||||
|             if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSavedMenu)) { |             if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSavedMenu)) { | ||||||
|                 nfc->dev->dev_data.nfc_data = nfc->dev_edit_data; |                 nfc->dev->dev_data.nfc_data = nfc->dev_edit_data; | ||||||
|                 if(nfc_device_save(nfc->dev, nfc->dev->dev_name)) { |                 if(nfc_device_save(nfc->dev, nfc->dev->dev_name)) { | ||||||
|  | |||||||
| @ -1,4 +1,5 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
|  | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| enum SubmenuIndex { | enum SubmenuIndex { | ||||||
|     SubmenuIndexRead, |     SubmenuIndexRead, | ||||||
| @ -47,11 +48,14 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) { | |||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == SubmenuIndexRead) { |         if(event.event == SubmenuIndexRead) { | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); | ||||||
|  |             DOLPHIN_DEED(DolphinDeedNfcRead); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|         } else if(event.event == SubmenuIndexDetectReader) { |         } else if(event.event == SubmenuIndexDetectReader) { | ||||||
|             bool sd_exist = storage_sd_status(nfc->dev->storage) == FSE_OK; |             bool sd_exist = storage_sd_status(nfc->dev->storage) == FSE_OK; | ||||||
|             if(sd_exist) { |             if(sd_exist) { | ||||||
|  |                 nfc_device_data_clear(&nfc->dev->dev_data); | ||||||
|                 scene_manager_next_scene(nfc->scene_manager, NfcSceneDetectReader); |                 scene_manager_next_scene(nfc->scene_manager, NfcSceneDetectReader); | ||||||
|  |                 DOLPHIN_DEED(DolphinDeedNfcDetectReader); | ||||||
|             } else { |             } else { | ||||||
|                 scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound); |                 scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound); | ||||||
|             } |             } | ||||||
|  | |||||||
| @ -1,7 +1,9 @@ | |||||||
| #include "detect_reader.h" | #include "detect_reader.h" | ||||||
| 
 | #include <assets_icons.h> | ||||||
| #include <gui/elements.h> | #include <gui/elements.h> | ||||||
| 
 | 
 | ||||||
|  | #define DETECT_READER_UID_MAX_LEN (10) | ||||||
|  | 
 | ||||||
| struct DetectReader { | struct DetectReader { | ||||||
|     View* view; |     View* view; | ||||||
|     DetectReaderDoneCallback callback; |     DetectReaderDoneCallback callback; | ||||||
| @ -12,6 +14,7 @@ typedef struct { | |||||||
|     uint16_t nonces; |     uint16_t nonces; | ||||||
|     uint16_t nonces_max; |     uint16_t nonces_max; | ||||||
|     DetectReaderState state; |     DetectReaderState state; | ||||||
|  |     FuriString* uid_str; | ||||||
| } DetectReaderViewModel; | } DetectReaderViewModel; | ||||||
| 
 | 
 | ||||||
| static void detect_reader_draw_callback(Canvas* canvas, void* model) { | 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) { |     if(m->state == DetectReaderStateStart) { | ||||||
|         snprintf(text, sizeof(text), "Touch the reader"); |         snprintf(text, sizeof(text), "Touch the reader"); | ||||||
|         canvas_draw_icon(canvas, 21, 13, &I_Move_flipper_26x39); |         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) { |     } else if(m->state == DetectReaderStateReaderDetected) { | ||||||
|         snprintf(text, sizeof(text), "Move the Flipper away"); |         snprintf(text, sizeof(text), "Move the Flipper away"); | ||||||
|         canvas_draw_icon(canvas, 24, 25, &I_Release_arrow_18x15); |         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_input_callback(detect_reader->view, detect_reader_input_callback); | ||||||
|     view_set_context(detect_reader->view, detect_reader); |     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; |     return detect_reader; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void detect_reader_free(DetectReader* detect_reader) { | void detect_reader_free(DetectReader* detect_reader) { | ||||||
|     furi_assert(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); |     view_free(detect_reader->view); | ||||||
|     free(detect_reader); |     free(detect_reader); | ||||||
| } | } | ||||||
| @ -106,6 +125,7 @@ void detect_reader_reset(DetectReader* detect_reader) { | |||||||
|             model->nonces = 0; |             model->nonces = 0; | ||||||
|             model->nonces_max = 0; |             model->nonces_max = 0; | ||||||
|             model->state = DetectReaderStateStart; |             model->state = DetectReaderStateStart; | ||||||
|  |             furi_string_reset(model->uid_str); | ||||||
|         }, |         }, | ||||||
|         false); |         false); | ||||||
| } | } | ||||||
| @ -152,3 +172,19 @@ void detect_reader_set_state(DetectReader* detect_reader, DetectReaderState stat | |||||||
|     with_view_model( |     with_view_model( | ||||||
|         detect_reader->view, DetectReaderViewModel * model, { model->state = state; }, true); |         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); | ||||||
|  | } | ||||||
|  | |||||||
| @ -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_nonces_collected(DetectReader* detect_reader, uint16_t nonces_collected); | ||||||
| 
 | 
 | ||||||
| void detect_reader_set_state(DetectReader* detect_reader, DetectReaderState state); | 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); | ||||||
|  | |||||||
| @ -69,12 +69,3 @@ typedef enum { | |||||||
|     SubGhzViewIdTestCarrier, |     SubGhzViewIdTestCarrier, | ||||||
|     SubGhzViewIdTestPacket, |     SubGhzViewIdTestPacket, | ||||||
| } SubGhzViewId; | } SubGhzViewId; | ||||||
| 
 |  | ||||||
| struct SubGhzPresetDefinition { |  | ||||||
|     FuriString* name; |  | ||||||
|     uint32_t frequency; |  | ||||||
|     uint8_t* data; |  | ||||||
|     size_t data_size; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| typedef struct SubGhzPresetDefinition SubGhzPresetDefinition; |  | ||||||
|  | |||||||
| @ -1,6 +1,5 @@ | |||||||
| #include "../subghz_i.h" | #include "../subghz_i.h" | ||||||
| #include "../views/subghz_frequency_analyzer.h" | #include "../views/subghz_frequency_analyzer.h" | ||||||
| #include <dolphin/dolphin.h> |  | ||||||
| 
 | 
 | ||||||
| void subghz_scene_frequency_analyzer_callback(SubGhzCustomEvent event, void* context) { | void subghz_scene_frequency_analyzer_callback(SubGhzCustomEvent event, void* context) { | ||||||
|     furi_assert(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) { | void subghz_scene_frequency_analyzer_on_enter(void* context) { | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     DOLPHIN_DEED(DolphinDeedSubGhzFrequencyAnalyzer); |  | ||||||
|     subghz_frequency_analyzer_set_callback( |     subghz_frequency_analyzer_set_callback( | ||||||
|         subghz->subghz_frequency_analyzer, subghz_scene_frequency_analyzer_callback, subghz); |         subghz->subghz_frequency_analyzer, subghz_scene_frequency_analyzer_callback, subghz); | ||||||
|     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdFrequencyAnalyzer); |     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdFrequencyAnalyzer); | ||||||
|  | |||||||
| @ -6,6 +6,7 @@ | |||||||
| 
 | 
 | ||||||
| #define RAW_FILE_NAME "Raw_signal_" | #define RAW_FILE_NAME "Raw_signal_" | ||||||
| #define TAG "SubGhzSceneReadRAW" | #define TAG "SubGhzSceneReadRAW" | ||||||
|  | #define RAW_THRESHOLD_RSSI_LOW_COUNT 10 | ||||||
| 
 | 
 | ||||||
| bool subghz_scene_read_raw_update_filename(SubGhz* subghz) { | bool subghz_scene_read_raw_update_filename(SubGhz* subghz) { | ||||||
|     bool ret = false; |     bool ret = false; | ||||||
| @ -72,24 +73,33 @@ void subghz_scene_read_raw_on_enter(void* context) { | |||||||
| 
 | 
 | ||||||
|     switch(subghz->txrx->rx_key_state) { |     switch(subghz->txrx->rx_key_state) { | ||||||
|     case SubGhzRxKeyStateBack: |     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; |         break; | ||||||
|     case SubGhzRxKeyStateRAWLoad: |     case SubGhzRxKeyStateRAWLoad: | ||||||
|         path_extract_filename(subghz->file_path, file_name, true); |         path_extract_filename(subghz->file_path, file_name, true); | ||||||
|         subghz_read_raw_set_status( |         subghz_read_raw_set_status( | ||||||
|             subghz->subghz_read_raw, |             subghz->subghz_read_raw, | ||||||
|             SubGhzReadRAWStatusLoadKeyTX, |             SubGhzReadRAWStatusLoadKeyTX, | ||||||
|             furi_string_get_cstr(file_name)); |             furi_string_get_cstr(file_name), | ||||||
|  |             subghz->txrx->raw_threshold_rssi); | ||||||
|         subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; |         subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; | ||||||
|         break; |         break; | ||||||
|     case SubGhzRxKeyStateRAWSave: |     case SubGhzRxKeyStateRAWSave: | ||||||
|         path_extract_filename(subghz->file_path, file_name, true); |         path_extract_filename(subghz->file_path, file_name, true); | ||||||
|         subghz_read_raw_set_status( |         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; |         subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; | ||||||
|         break; |         break; | ||||||
|     default: |     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; |         subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
| @ -213,7 +223,12 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { | |||||||
|                         subghz->txrx->rx_key_state = SubGhzRxKeyStateBack; |                         subghz->txrx->rx_key_state = SubGhzRxKeyStateBack; | ||||||
|                         scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx); |                         scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx); | ||||||
|                     } else { |                     } 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
 |                         // set callback end tx
 | ||||||
|                         subghz_protocol_raw_file_encoder_worker_set_callback_end( |                         subghz_protocol_raw_file_encoder_worker_set_callback_end( | ||||||
|                             (SubGhzProtocolEncoderRAW*)subghz_transmitter_get_protocol_instance( |                             (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) { |             if(subghz->txrx->rx_key_state != SubGhzRxKeyStateIDLE) { | ||||||
|                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving); |                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving); | ||||||
|             } else { |             } 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( |                 if(subghz_protocol_raw_save_to_file_init( | ||||||
|                        (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result, |                        (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result, | ||||||
|                        RAW_FILE_NAME, |                        RAW_FILE_NAME, | ||||||
| @ -319,7 +334,35 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { | |||||||
|                 subghz->subghz_read_raw, |                 subghz->subghz_read_raw, | ||||||
|                 subghz_protocol_raw_get_sample_write( |                 subghz_protocol_raw_get_sample_write( | ||||||
|                     (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result)); |                     (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; |             break; | ||||||
|         case SubGhzNotificationStateTx: |         case SubGhzNotificationStateTx: | ||||||
|             notification_message(subghz->notifications, &sequence_blink_magenta_10); |             notification_message(subghz->notifications, &sequence_blink_magenta_10); | ||||||
|  | |||||||
| @ -1,5 +1,6 @@ | |||||||
| #include "../subghz_i.h" | #include "../subghz_i.h" | ||||||
| #include "../views/receiver.h" | #include "../views/receiver.h" | ||||||
|  | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| static const NotificationSequence subghs_sequence_rx = { | static const NotificationSequence subghs_sequence_rx = { | ||||||
|     &message_green_255, |     &message_green_255, | ||||||
| @ -181,6 +182,7 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { | |||||||
|             subghz->txrx->idx_menu_chosen = |             subghz->txrx->idx_menu_chosen = | ||||||
|                 subghz_view_receiver_get_idx_menu(subghz->subghz_receiver); |                 subghz_view_receiver_get_idx_menu(subghz->subghz_receiver); | ||||||
|             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverInfo); |             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverInfo); | ||||||
|  |             DOLPHIN_DEED(DolphinDeedSubGhzReceiverInfo); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|             break; |             break; | ||||||
|         case SubGhzCustomEventViewReceiverConfig: |         case SubGhzCustomEventViewReceiverConfig: | ||||||
|  | |||||||
| @ -1,10 +1,41 @@ | |||||||
| #include "../subghz_i.h" | #include "../subghz_i.h" | ||||||
|  | #include <lib/toolbox/value_index.h> | ||||||
| 
 | 
 | ||||||
| enum SubGhzSettingIndex { | enum SubGhzSettingIndex { | ||||||
|     SubGhzSettingIndexFrequency, |     SubGhzSettingIndexFrequency, | ||||||
|     SubGhzSettingIndexHopping, |     SubGhzSettingIndexHopping, | ||||||
|     SubGhzSettingIndexModulation, |     SubGhzSettingIndexModulation, | ||||||
|     SubGhzSettingIndexLock, |     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 | #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]; |     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) { | static void subghz_scene_receiver_config_var_list_enter_callback(void* context, uint32_t index) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     SubGhz* subghz = 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_scene_receiver_config_var_list_enter_callback, | ||||||
|             subghz); |             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); |     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdVariableItemList); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,6 +1,5 @@ | |||||||
| #include "../subghz_i.h" | #include "../subghz_i.h" | ||||||
| #include "../helpers/subghz_custom_event.h" | #include "../helpers/subghz_custom_event.h" | ||||||
| #include <dolphin/dolphin.h> |  | ||||||
| 
 | 
 | ||||||
| void subghz_scene_receiver_info_callback(GuiButtonType result, InputType type, void* context) { | void subghz_scene_receiver_info_callback(GuiButtonType result, InputType type, void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
| @ -28,8 +27,8 @@ static bool subghz_scene_receiver_info_update_parser(void* context) { | |||||||
|             subghz->txrx->decoder_result, |             subghz->txrx->decoder_result, | ||||||
|             subghz_history_get_raw_data(subghz->txrx->history, subghz->txrx->idx_menu_chosen)); |             subghz_history_get_raw_data(subghz->txrx->history, subghz->txrx->idx_menu_chosen)); | ||||||
| 
 | 
 | ||||||
|         SubGhzPresetDefinition* preset = |         SubGhzRadioPreset* preset = | ||||||
|             subghz_history_get_preset_def(subghz->txrx->history, subghz->txrx->idx_menu_chosen); |             subghz_history_get_radio_preset(subghz->txrx->history, subghz->txrx->idx_menu_chosen); | ||||||
|         subghz_preset_init( |         subghz_preset_init( | ||||||
|             subghz, |             subghz, | ||||||
|             furi_string_get_cstr(preset->name), |             furi_string_get_cstr(preset->name), | ||||||
| @ -45,7 +44,6 @@ static bool subghz_scene_receiver_info_update_parser(void* context) { | |||||||
| void subghz_scene_receiver_info_on_enter(void* context) { | void subghz_scene_receiver_info_on_enter(void* context) { | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
| 
 | 
 | ||||||
|     DOLPHIN_DEED(DolphinDeedSubGhzReceiverInfo); |  | ||||||
|     if(subghz_scene_receiver_info_update_parser(subghz)) { |     if(subghz_scene_receiver_info_update_parser(subghz)) { | ||||||
|         FuriString* frequency_str; |         FuriString* frequency_str; | ||||||
|         FuriString* modulation_str; |         FuriString* modulation_str; | ||||||
|  | |||||||
| @ -4,6 +4,7 @@ | |||||||
| #include "../helpers/subghz_custom_event.h" | #include "../helpers/subghz_custom_event.h" | ||||||
| #include <lib/subghz/protocols/raw.h> | #include <lib/subghz/protocols/raw.h> | ||||||
| #include <gui/modules/validators.h> | #include <gui/modules/validators.h> | ||||||
|  | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| #define MAX_TEXT_INPUT_LEN 22 | #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); |                 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; |                 return true; | ||||||
|             } else { |             } else { | ||||||
|                 furi_string_set(subghz->error_str, "No name file"); |                 furi_string_set(subghz->error_str, "No name file"); | ||||||
|  | |||||||
| @ -1,7 +1,5 @@ | |||||||
| #include "../subghz_i.h" | #include "../subghz_i.h" | ||||||
| #include "../helpers/subghz_custom_event.h" | #include "../helpers/subghz_custom_event.h" | ||||||
| #include <dolphin/helpers/dolphin_deed.h> |  | ||||||
| #include <dolphin/dolphin.h> |  | ||||||
| 
 | 
 | ||||||
| void subghz_scene_save_success_popup_callback(void* context) { | void subghz_scene_save_success_popup_callback(void* context) { | ||||||
|     SubGhz* subghz = 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) { | void subghz_scene_save_success_on_enter(void* context) { | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     DOLPHIN_DEED(DolphinDeedSubGhzSave); |  | ||||||
| 
 | 
 | ||||||
|     // Setup view
 |     // Setup view
 | ||||||
|     Popup* popup = subghz->popup; |     Popup* popup = subghz->popup; | ||||||
|  | |||||||
| @ -3,10 +3,9 @@ | |||||||
| #include <lib/subghz/protocols/secplus_v1.h> | #include <lib/subghz/protocols/secplus_v1.h> | ||||||
| #include <lib/subghz/protocols/secplus_v2.h> | #include <lib/subghz/protocols/secplus_v2.h> | ||||||
| #include <lib/subghz/blocks/math.h> | #include <lib/subghz/blocks/math.h> | ||||||
| #include <dolphin/dolphin.h> |  | ||||||
| #include <flipper_format/flipper_format_i.h> | #include <flipper_format/flipper_format_i.h> | ||||||
| #include <lib/toolbox/stream/stream.h> | #include <lib/toolbox/stream/stream.h> | ||||||
| #include <lib/subghz/protocols/registry.h> | #include <lib/subghz/protocols/protocol_items.h> | ||||||
| 
 | 
 | ||||||
| #define TAG "SubGhzSetType" | #define TAG "SubGhzSetType" | ||||||
| 
 | 
 | ||||||
| @ -381,7 +380,6 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { | |||||||
| 
 | 
 | ||||||
|         if(generated_protocol) { |         if(generated_protocol) { | ||||||
|             subghz_file_name_clear(subghz); |             subghz_file_name_clear(subghz); | ||||||
|             DOLPHIN_DEED(DolphinDeedSubGhzAddManually); |  | ||||||
|             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); |             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); | ||||||
|             return true; |             return true; | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -1,4 +1,5 @@ | |||||||
| #include "../subghz_i.h" | #include "../subghz_i.h" | ||||||
|  | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| enum SubmenuIndex { | enum SubmenuIndex { | ||||||
|     SubmenuIndexRead = 10, |     SubmenuIndexRead = 10, | ||||||
| @ -84,6 +85,7 @@ bool subghz_scene_start_on_event(void* context, SceneManagerEvent event) { | |||||||
|             scene_manager_set_scene_state( |             scene_manager_set_scene_state( | ||||||
|                 subghz->scene_manager, SubGhzSceneStart, SubmenuIndexFrequencyAnalyzer); |                 subghz->scene_manager, SubGhzSceneStart, SubmenuIndexFrequencyAnalyzer); | ||||||
|             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneFrequencyAnalyzer); |             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneFrequencyAnalyzer); | ||||||
|  |             DOLPHIN_DEED(DolphinDeedSubGhzFrequencyAnalyzer); | ||||||
|             return true; |             return true; | ||||||
|         } else if(event.event == SubmenuIndexTest) { |         } else if(event.event == SubmenuIndexTest) { | ||||||
|             scene_manager_set_scene_state( |             scene_manager_set_scene_state( | ||||||
|  | |||||||
| @ -50,7 +50,6 @@ bool subghz_scene_transmitter_update_data_show(void* context) { | |||||||
| 
 | 
 | ||||||
| void subghz_scene_transmitter_on_enter(void* context) { | void subghz_scene_transmitter_on_enter(void* context) { | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     DOLPHIN_DEED(DolphinDeedSubGhzSend); |  | ||||||
|     if(!subghz_scene_transmitter_update_data_show(subghz)) { |     if(!subghz_scene_transmitter_update_data_show(subghz)) { | ||||||
|         view_dispatcher_send_custom_event( |         view_dispatcher_send_custom_event( | ||||||
|             subghz->view_dispatcher, SubGhzCustomEventViewTransmitterError); |             subghz->view_dispatcher, SubGhzCustomEventViewTransmitterError); | ||||||
| @ -78,6 +77,7 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { | |||||||
|                 } else { |                 } else { | ||||||
|                     subghz->state_notifications = SubGhzNotificationStateTx; |                     subghz->state_notifications = SubGhzNotificationStateTx; | ||||||
|                     subghz_scene_transmitter_update_data_show(subghz); |                     subghz_scene_transmitter_update_data_show(subghz); | ||||||
|  |                     DOLPHIN_DEED(DolphinDeedSubGhzSend); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             return true; |             return true; | ||||||
|  | |||||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Aleksandr Kutuzov
						Aleksandr Kutuzov