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}}`:** | ||||
|             - [📦 Update package](https://update.flipperzero.one/builds/firmware/${{steps.names.outputs.branch_name}}/flipper-z-${{steps.names.outputs.default_target}}-update-${{steps.names.outputs.suffix}}.tgz) | ||||
|             - [📥 DFU file](https://update.flipperzero.one/builds/firmware/${{steps.names.outputs.branch_name}}/flipper-z-${{steps.names.outputs.default_target}}-full-${{steps.names.outputs.suffix}}.dfu) | ||||
|             - [☁️ Web/App updater](https://my.flipp.dev/?url=https://update.flipperzero.one/builds/firmware/${{steps.names.outputs.branch_name}}/flipper-z-${{steps.names.outputs.default_target}}-update-${{steps.names.outputs.suffix}}.tgz&channel=${{steps.names.outputs.branch_name}}&version=${{steps.names.outputs.commit_sha}}) | ||||
|             - [☁️ Web/App updater](https://lab.flipper.net/?url=https://update.flipperzero.one/builds/firmware/${{steps.names.outputs.branch_name}}/flipper-z-${{steps.names.outputs.default_target}}-update-${{steps.names.outputs.suffix}}.tgz&channel=${{steps.names.outputs.branch_name}}&version=${{steps.names.outputs.commit_sha}}) | ||||
|           edit-mode: replace | ||||
| 
 | ||||
|   compact: | ||||
|  | ||||
							
								
								
									
										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 analyze \ | ||||
|               @.pvsoptions \ | ||||
|               --disableLicenseExpirationCheck \ | ||||
|               -j$(grep -c processor /proc/cpuinfo) \ | ||||
|               -f build/f7-firmware-DC/compile_commands.json \ | ||||
|               -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"] | ||||
| 	path = lib/microtar | ||||
| 	url = https://github.com/amachronic/microtar.git | ||||
| [submodule "lib/scons"] | ||||
| 	path = lib/scons | ||||
| 	url = https://github.com/SCons/scons.git | ||||
| [submodule "lib/mbedtls"] | ||||
| 	path = lib/mbedtls | ||||
| 	url = https://github.com/Mbed-TLS/mbedtls.git | ||||
| [submodule "lib/cxxheaderparser"] | ||||
| 	path = lib/cxxheaderparser | ||||
| 	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": [ | ||||
|         { | ||||
|             "name": "Win32", | ||||
|             "compilerPath": "${workspaceFolder}/toolchain/i686-windows/bin/arm-none-eabi-gcc.exe", | ||||
|             "compilerPath": "${workspaceFolder}/toolchain/x86_64-windows/bin/arm-none-eabi-gcc.exe", | ||||
|             "intelliSenseMode": "gcc-arm", | ||||
|             "compileCommands": "${workspaceFolder}/build/latest/compile_commands.json", | ||||
|             "configurationProvider": "ms-vscode.cpptools", | ||||
|  | ||||
							
								
								
									
										19
									
								
								.vscode/example/launch.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										19
									
								
								.vscode/example/launch.json
									
									
									
									
										vendored
									
									
								
							| @ -79,6 +79,25 @@ | ||||
|             ] | ||||
|             // "showDevDebugOutput": "raw", | ||||
|         }, | ||||
|         { | ||||
|             "name": "Attach FW (DAP)", | ||||
|             "cwd": "${workspaceFolder}", | ||||
|             "executable": "./build/latest/firmware.elf", | ||||
|             "request": "attach", | ||||
|             "type": "cortex-debug", | ||||
|             "servertype": "openocd", | ||||
|             "device": "cmsis-dap", | ||||
|             "svdFile": "./debug/STM32WB55_CM4.svd", | ||||
|             "rtos": "FreeRTOS", | ||||
|             "configFiles": [ | ||||
|                 "interface/cmsis-dap.cfg", | ||||
|                 "./debug/stm32wbx.cfg", | ||||
|             ], | ||||
|             "postAttachCommands": [ | ||||
|                 "source debug/flipperapps.py", | ||||
|             ], | ||||
|             // "showDevDebugOutput": "raw", | ||||
|         }, | ||||
|         { | ||||
|             "name": "fbt debug", | ||||
|             "type": "python", | ||||
|  | ||||
							
								
								
									
										6
									
								
								.vscode/example/settings.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								.vscode/example/settings.json
									
									
									
									
										vendored
									
									
								
							| @ -6,13 +6,13 @@ | ||||
|     "cortex-debug.enableTelemetry": false, | ||||
|     "cortex-debug.variableUseNaturalFormat": true, | ||||
|     "cortex-debug.showRTOS": true, | ||||
|     "cortex-debug.armToolchainPath.windows": "${workspaceFolder}/toolchain/i686-windows/bin", | ||||
|     "cortex-debug.armToolchainPath.windows": "${workspaceFolder}/toolchain/x86_64-windows/bin", | ||||
|     "cortex-debug.armToolchainPath.linux": "${workspaceFolder}/toolchain/x86_64-linux/bin", | ||||
|     "cortex-debug.armToolchainPath.osx": "${workspaceFolder}/toolchain/x86_64-darwin/bin", | ||||
|     "cortex-debug.openocdPath.windows": "${workspaceFolder}/toolchain/i686-windows/openocd/bin/openocd.exe", | ||||
|     "cortex-debug.openocdPath.windows": "${workspaceFolder}/toolchain/x86_64-windows/openocd/bin/openocd.exe", | ||||
|     "cortex-debug.openocdPath.linux": "${workspaceFolder}/toolchain/x86_64-linux/openocd/bin/openocd", | ||||
|     "cortex-debug.openocdPath.osx": "${workspaceFolder}/toolchain/x86_64-darwin/openocd/bin/openocd", | ||||
|     "cortex-debug.gdbPath.windows": "${workspaceFolder}/toolchain/i686-windows/bin/arm-none-eabi-gdb-py.bat", | ||||
|     "cortex-debug.gdbPath.windows": "${workspaceFolder}/toolchain/x86_64-windows/bin/arm-none-eabi-gdb-py.bat", | ||||
|     "cortex-debug.gdbPath.linux": "${workspaceFolder}/toolchain/x86_64-linux/bin/arm-none-eabi-gdb-py", | ||||
|     "cortex-debug.gdbPath.osx": "${workspaceFolder}/toolchain/x86_64-darwin/bin/arm-none-eabi-gdb-py", | ||||
|     "editor.formatOnSave": true, | ||||
|  | ||||
							
								
								
									
										4
									
								
								.vscode/example/tasks.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.vscode/example/tasks.json
									
									
									
									
										vendored
									
									
								
							| @ -109,13 +109,13 @@ | ||||
|             "label": "[Debug] Build FAPs", | ||||
|             "group": "build", | ||||
|             "type": "shell", | ||||
|             "command": "./fbt plugin_dist" | ||||
|             "command": "./fbt fap_dist" | ||||
|         }, | ||||
|         { | ||||
|             "label": "[Release] Build FAPs", | ||||
|             "group": "build", | ||||
|             "type": "shell", | ||||
|             "command": "./fbt COMPACT=1 DEBUG=0 plugin_dist" | ||||
|             "command": "./fbt COMPACT=1 DEBUG=0 fap_dist" | ||||
|         }, | ||||
|         { | ||||
|             "label": "[Debug] Launch App on Flipper", | ||||
|  | ||||
							
								
								
									
										16
									
								
								SConstruct
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								SConstruct
									
									
									
									
									
								
							| @ -156,11 +156,9 @@ Depends(fap_dist, firmware_env["FW_EXTAPPS"]["validators"].values()) | ||||
| Alias("fap_dist", fap_dist) | ||||
| # distenv.Default(fap_dist) | ||||
| 
 | ||||
| plugin_resources_dist = list( | ||||
|     distenv.Install(f"#/assets/resources/apps/{dist_entry[0]}", dist_entry[1]) | ||||
|     for dist_entry in firmware_env["FW_EXTAPPS"]["dist"].values() | ||||
| distenv.Depends( | ||||
|     firmware_env["FW_RESOURCES"], firmware_env["FW_EXTAPPS"]["resources_dist"] | ||||
| ) | ||||
| distenv.Depends(firmware_env["FW_RESOURCES"], plugin_resources_dist) | ||||
| 
 | ||||
| 
 | ||||
| # Target for bundling core2 package for qFlipper | ||||
| @ -291,6 +289,16 @@ distenv.PhonyTarget( | ||||
|     "@echo $( ${BLACKMAGIC_ADDR} $)", | ||||
| ) | ||||
| 
 | ||||
| 
 | ||||
| # Find STLink probe ids | ||||
| distenv.PhonyTarget( | ||||
|     "get_stlink", | ||||
|     distenv.Action( | ||||
|         lambda **kw: distenv.GetDevices(), | ||||
|         None, | ||||
|     ), | ||||
| ) | ||||
| 
 | ||||
| # Prepare vscode environment | ||||
| vscode_dist = distenv.Install("#.vscode", distenv.Glob("#.vscode/example/*")) | ||||
| distenv.Precious(vscode_dist) | ||||
|  | ||||
| @ -8,4 +8,5 @@ App( | ||||
|     stack_size=2 * 1024, | ||||
|     order=150, | ||||
|     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 "gui/modules/file_browser.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_SIGNAL_SHORT_FILE "nfc_nfca_signal_short.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 uint32_t nfc_test_file_version = 1; | ||||
| @ -220,11 +221,78 @@ MU_TEST(mf_classic_dict_test) { | ||||
|     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) { | ||||
|     nfc_test_alloc(); | ||||
| 
 | ||||
|     MU_RUN_TEST(nfc_digital_signal_test); | ||||
|     MU_RUN_TEST(mf_classic_dict_test); | ||||
|     MU_RUN_TEST(mf_classic_dict_load_test); | ||||
| 
 | ||||
|     nfc_test_free(); | ||||
| } | ||||
|  | ||||
| @ -5,7 +5,7 @@ | ||||
| #include <lib/subghz/transmitter.h> | ||||
| #include <lib/subghz/subghz_keystore.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> | ||||
| 
 | ||||
| #define TAG "SubGhz TEST" | ||||
| @ -13,7 +13,7 @@ | ||||
| #define CAME_ATOMO_DIR_NAME EXT_PATH("subghz/assets/came_atomo") | ||||
| #define NICE_FLOR_S_DIR_NAME EXT_PATH("subghz/assets/nice_flor_s") | ||||
| #define TEST_RANDOM_DIR_NAME EXT_PATH("unit_tests/subghz/test_random_raw.sub") | ||||
| #define TEST_RANDOM_COUNT_PARSE 233 | ||||
| #define TEST_RANDOM_COUNT_PARSE 232 | ||||
| #define TEST_TIMEOUT 10000 | ||||
| 
 | ||||
| static SubGhzEnvironment* environment_handler; | ||||
| @ -43,6 +43,8 @@ static void subghz_test_init(void) { | ||||
|         environment_handler, CAME_ATOMO_DIR_NAME); | ||||
|     subghz_environment_set_nice_flor_s_rainbow_table_file_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); | ||||
|     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"); | ||||
| } | ||||
| 
 | ||||
| MU_TEST(subghz_decoder_magellen_test) { | ||||
| MU_TEST(subghz_decoder_magellan_test) { | ||||
|     mu_assert( | ||||
|         subghz_decoder_test( | ||||
|             EXT_PATH("unit_tests/subghz/magellen_raw.sub"), SUBGHZ_PROTOCOL_MAGELLEN_NAME), | ||||
|         "Test decoder " SUBGHZ_PROTOCOL_MAGELLEN_NAME " error\r\n"); | ||||
|             EXT_PATH("unit_tests/subghz/magellan_raw.sub"), SUBGHZ_PROTOCOL_MAGELLAN_NAME), | ||||
|         "Test decoder " SUBGHZ_PROTOCOL_MAGELLAN_NAME " error\r\n"); | ||||
| } | ||||
| 
 | ||||
| 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"); | ||||
| } | ||||
| 
 | ||||
| MU_TEST(subghz_decoder_oregon2_test) { | ||||
|     mu_assert( | ||||
|         subghz_decoder_test( | ||||
|             EXT_PATH("unit_tests/subghz/oregon2_raw.sub"), SUBGHZ_PROTOCOL_OREGON2_NAME), | ||||
|         "Test decoder " SUBGHZ_PROTOCOL_OREGON2_NAME " error\r\n"); | ||||
| } | ||||
| 
 | ||||
| //test encoders
 | ||||
| MU_TEST(subghz_encoder_princeton_test) { | ||||
|     mu_assert( | ||||
| @ -545,10 +540,10 @@ MU_TEST(subghz_encoder_honeywell_wdb_test) { | ||||
|         "Test encoder " SUBGHZ_PROTOCOL_HONEYWELL_WDB_NAME " error\r\n"); | ||||
| } | ||||
| 
 | ||||
| MU_TEST(subghz_encoder_magellen_test) { | ||||
| MU_TEST(subghz_encoder_magellan_test) { | ||||
|     mu_assert( | ||||
|         subghz_encoder_test(EXT_PATH("unit_tests/subghz/magellen.sub")), | ||||
|         "Test encoder " SUBGHZ_PROTOCOL_MAGELLEN_NAME " error\r\n"); | ||||
|         subghz_encoder_test(EXT_PATH("unit_tests/subghz/magellan.sub")), | ||||
|         "Test encoder " SUBGHZ_PROTOCOL_MAGELLAN_NAME " error\r\n"); | ||||
| } | ||||
| 
 | ||||
| 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_phoenix_v2_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_clemsa_test); | ||||
|     MU_RUN_TEST(subghz_decoder_oregon2_test); | ||||
| 
 | ||||
|     MU_RUN_TEST(subghz_encoder_princeton_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_phoenix_v2_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_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 <gui/gui.h> | ||||
| #include <assets_icons.h> | ||||
| #include <gui/view_dispatcher.h> | ||||
| #include <gui/scene_manager.h> | ||||
| #include <gui/modules/submenu.h> | ||||
|  | ||||
| @ -1,6 +1,7 @@ | ||||
| #include "bad_usb_view.h" | ||||
| #include "../bad_usb_script.h" | ||||
| #include <gui/elements.h> | ||||
| #include <assets_icons.h> | ||||
| 
 | ||||
| #define MAX_NAME_LEN 64 | ||||
| 
 | ||||
|  | ||||
| @ -1,5 +1,6 @@ | ||||
| #include <furi.h> | ||||
| #include <gui/gui.h> | ||||
| #include <assets_icons.h> | ||||
| #include <gui/view_dispatcher.h> | ||||
| #include <storage/storage.h> | ||||
| #include <gui/modules/loading.h> | ||||
|  | ||||
| @ -15,6 +15,7 @@ | ||||
| #include <gui/modules/widget.h> | ||||
| #include "views/gpio_test.h" | ||||
| #include "views/gpio_usb_uart.h" | ||||
| #include <assets_icons.h> | ||||
| 
 | ||||
| struct GpioApp { | ||||
|     Gui* gui; | ||||
| @ -24,6 +25,7 @@ struct GpioApp { | ||||
|     Widget* widget; | ||||
| 
 | ||||
|     VariableItemList* var_item_list; | ||||
|     VariableItem* var_item_flow; | ||||
|     GpioTest* gpio_test; | ||||
|     GpioUsbUart* gpio_usb_uart; | ||||
|     UsbUartBridge* usb_uart_bridge; | ||||
|  | ||||
| @ -13,7 +13,7 @@ static UsbUartConfig* cfg_set; | ||||
| 
 | ||||
| static const char* vcp_ch[] = {"0 (CLI)", "1"}; | ||||
| 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 uint32_t baudrate_list[] = { | ||||
|     2400, | ||||
| @ -33,6 +33,24 @@ bool gpio_scene_usb_uart_cfg_on_event(void* context, SceneManagerEvent event) { | ||||
|     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) { | ||||
|     GpioApp* app = variable_item_get_context(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) | ||||
|         cfg_set->uart_ch = FuriHalUartIdLPUART1; | ||||
|     usb_uart_set_config(app->usb_uart_bridge, cfg_set); | ||||
|     line_ensure_flow_invariant(app); | ||||
| } | ||||
| 
 | ||||
| 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_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_text(item, flow_pins[cfg_set->flow_pins]); | ||||
|     app->var_item_flow = item; | ||||
|     line_ensure_flow_invariant(app); | ||||
| 
 | ||||
|     variable_item_list_set_selected_item( | ||||
|         var_item_list, scene_manager_get_scene_state(app->scene_manager, GpioAppViewUsbUartCfg)); | ||||
|  | ||||
| @ -14,6 +14,7 @@ | ||||
| static const GpioPin* flow_pins[][2] = { | ||||
|     {&gpio_ext_pa7, &gpio_ext_pa6}, // 2, 3
 | ||||
|     {&gpio_ext_pb2, &gpio_ext_pc3}, // 6, 7
 | ||||
|     {&gpio_ext_pc0, &gpio_ext_pc1}, // 16, 15
 | ||||
| }; | ||||
| 
 | ||||
| typedef enum { | ||||
|  | ||||
| @ -5,6 +5,7 @@ | ||||
| #include <toolbox/path.h> | ||||
| #include <flipper_format/flipper_format.h> | ||||
| #include <rpc/rpc_app.h> | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| #define TAG "iButtonApp" | ||||
| 
 | ||||
| @ -337,11 +338,13 @@ int32_t ibutton_app(void* p) { | ||||
|         view_dispatcher_attach_to_gui( | ||||
|             ibutton->view_dispatcher, ibutton->gui, ViewDispatcherTypeDesktop); | ||||
|         scene_manager_next_scene(ibutton->scene_manager, iButtonSceneRpc); | ||||
|         DOLPHIN_DEED(DolphinDeedIbuttonEmulate); | ||||
|     } else { | ||||
|         view_dispatcher_attach_to_gui( | ||||
|             ibutton->view_dispatcher, ibutton->gui, ViewDispatcherTypeFullscreen); | ||||
|         if(key_loaded) { | ||||
|             scene_manager_next_scene(ibutton->scene_manager, iButtonSceneEmulate); | ||||
|             DOLPHIN_DEED(DolphinDeedIbuttonEmulate); | ||||
|         } else { | ||||
|             scene_manager_next_scene(ibutton->scene_manager, iButtonSceneStart); | ||||
|         } | ||||
|  | ||||
| @ -4,6 +4,7 @@ | ||||
| 
 | ||||
| #include <gui/gui.h> | ||||
| #include <gui/view.h> | ||||
| #include <assets_icons.h> | ||||
| #include <gui/view_dispatcher.h> | ||||
| #include <gui/scene_manager.h> | ||||
| #include <notification/notification_messages.h> | ||||
|  | ||||
| @ -1,7 +1,5 @@ | ||||
| #include "../ibutton_i.h" | ||||
| 
 | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| void ibutton_scene_add_type_byte_input_callback(void* context) { | ||||
|     iButton* ibutton = context; | ||||
|     view_dispatcher_send_custom_event(ibutton->view_dispatcher, iButtonCustomEventByteEditResult); | ||||
| @ -38,7 +36,6 @@ bool ibutton_scene_add_value_on_event(void* context, SceneManagerEvent event) { | ||||
|         consumed = true; | ||||
|         if(event.event == iButtonCustomEventByteEditResult) { | ||||
|             ibutton_key_set_data(ibutton->key, new_key_data, IBUTTON_KEY_DATA_SIZE); | ||||
|             DOLPHIN_DEED(DolphinDeedIbuttonAdd); | ||||
|             scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSaveName); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @ -1,6 +1,5 @@ | ||||
| #include "../ibutton_i.h" | ||||
| #include <core/log.h> | ||||
| #include <dolphin/dolphin.h> | ||||
| #include <toolbox/path.h> | ||||
| 
 | ||||
| #define EMULATE_TIMEOUT_TICKS 10 | ||||
| @ -26,8 +25,6 @@ void ibutton_scene_emulate_on_enter(void* context) { | ||||
|         path_extract_filename(ibutton->file_path, key_name, true); | ||||
|     } | ||||
| 
 | ||||
|     DOLPHIN_DEED(DolphinDeedIbuttonEmulate); | ||||
| 
 | ||||
|     // check that stored key has name
 | ||||
|     if(!furi_string_empty(key_name)) { | ||||
|         ibutton_text_store_set(ibutton, "%s", furi_string_get_cstr(key_name)); | ||||
|  | ||||
| @ -11,7 +11,6 @@ void ibutton_scene_read_on_enter(void* context) { | ||||
|     Popup* popup = ibutton->popup; | ||||
|     iButtonKey* key = ibutton->key; | ||||
|     iButtonWorker* worker = ibutton->key_worker; | ||||
|     DOLPHIN_DEED(DolphinDeedIbuttonRead); | ||||
| 
 | ||||
|     popup_set_header(popup, "iButton", 95, 26, AlignCenter, AlignBottom); | ||||
|     popup_set_text(popup, "Waiting\nfor key ...", 95, 30, AlignCenter, AlignTop); | ||||
| @ -54,8 +53,8 @@ bool ibutton_scene_read_on_event(void* context, SceneManagerEvent event) { | ||||
|             if(success) { | ||||
|                 ibutton_notification_message(ibutton, iButtonNotificationMessageSuccess); | ||||
|                 ibutton_notification_message(ibutton, iButtonNotificationMessageGreenOn); | ||||
|                 DOLPHIN_DEED(DolphinDeedIbuttonReadSuccess); | ||||
|                 scene_manager_next_scene(scene_manager, iButtonSceneReadSuccess); | ||||
|                 DOLPHIN_DEED(DolphinDeedIbuttonReadSuccess); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @ -1,4 +1,5 @@ | ||||
| #include "../ibutton_i.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| typedef enum { | ||||
|     SubmenuIndexSave, | ||||
| @ -49,6 +50,7 @@ bool ibutton_scene_read_key_menu_on_event(void* context, SceneManagerEvent event | ||||
|             scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSaveName); | ||||
|         } else if(event.event == SubmenuIndexEmulate) { | ||||
|             scene_manager_next_scene(ibutton->scene_manager, iButtonSceneEmulate); | ||||
|             DOLPHIN_DEED(DolphinDeedIbuttonEmulate); | ||||
|         } else if(event.event == SubmenuIndexWrite) { | ||||
|             scene_manager_next_scene(ibutton->scene_manager, iButtonSceneWrite); | ||||
|         } | ||||
|  | ||||
| @ -1,6 +1,7 @@ | ||||
| #include "../ibutton_i.h" | ||||
| #include <lib/toolbox/random_name.h> | ||||
| #include <toolbox/path.h> | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| static void ibutton_scene_save_name_text_input_callback(void* context) { | ||||
|     iButton* ibutton = context; | ||||
| @ -57,6 +58,15 @@ bool ibutton_scene_save_name_on_event(void* context, SceneManagerEvent event) { | ||||
|         if(event.event == iButtonCustomEventTextEditResult) { | ||||
|             if(ibutton_save_key(ibutton, ibutton->text_store)) { | ||||
|                 scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSaveSuccess); | ||||
|                 if(scene_manager_has_previous_scene( | ||||
|                        ibutton->scene_manager, iButtonSceneSavedKeyMenu)) { | ||||
|                     // Nothing, do not count editing as saving
 | ||||
|                 } else if(scene_manager_has_previous_scene( | ||||
|                               ibutton->scene_manager, iButtonSceneAddType)) { | ||||
|                     DOLPHIN_DEED(DolphinDeedIbuttonAdd); | ||||
|                 } else { | ||||
|                     DOLPHIN_DEED(DolphinDeedIbuttonSave); | ||||
|                 } | ||||
|             } else { | ||||
|                 const uint32_t possible_scenes[] = { | ||||
|                     iButtonSceneReadKeyMenu, iButtonSceneSavedKeyMenu, iButtonSceneAddType}; | ||||
|  | ||||
| @ -1,5 +1,4 @@ | ||||
| #include "../ibutton_i.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| static void ibutton_scene_save_success_popup_callback(void* context) { | ||||
|     iButton* ibutton = context; | ||||
| @ -9,7 +8,6 @@ static void ibutton_scene_save_success_popup_callback(void* context) { | ||||
| void ibutton_scene_save_success_on_enter(void* context) { | ||||
|     iButton* ibutton = context; | ||||
|     Popup* popup = ibutton->popup; | ||||
|     DOLPHIN_DEED(DolphinDeedIbuttonSave); | ||||
| 
 | ||||
|     popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); | ||||
|     popup_set_header(popup, "Saved!", 5, 7, AlignLeft, AlignTop); | ||||
|  | ||||
| @ -1,4 +1,5 @@ | ||||
| #include "../ibutton_i.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| enum SubmenuIndex { | ||||
|     SubmenuIndexEmulate, | ||||
| @ -58,6 +59,7 @@ bool ibutton_scene_saved_key_menu_on_event(void* context, SceneManagerEvent even | ||||
|         consumed = true; | ||||
|         if(event.event == SubmenuIndexEmulate) { | ||||
|             scene_manager_next_scene(ibutton->scene_manager, iButtonSceneEmulate); | ||||
|             DOLPHIN_DEED(DolphinDeedIbuttonEmulate); | ||||
|         } else if(event.event == SubmenuIndexWrite) { | ||||
|             scene_manager_next_scene(ibutton->scene_manager, iButtonSceneWrite); | ||||
|         } else if(event.event == SubmenuIndexEdit) { | ||||
|  | ||||
| @ -1,5 +1,6 @@ | ||||
| #include "../ibutton_i.h" | ||||
| #include "ibutton/scenes/ibutton_scene.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| enum SubmenuIndex { | ||||
|     SubmenuIndexRead, | ||||
| @ -38,6 +39,7 @@ bool ibutton_scene_start_on_event(void* context, SceneManagerEvent event) { | ||||
|         consumed = true; | ||||
|         if(event.event == SubmenuIndexRead) { | ||||
|             scene_manager_next_scene(ibutton->scene_manager, iButtonSceneRead); | ||||
|             DOLPHIN_DEED(DolphinDeedIbuttonRead); | ||||
|         } else if(event.event == SubmenuIndexSaved) { | ||||
|             furi_string_set(ibutton->file_path, IBUTTON_APP_FOLDER); | ||||
|             scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSelectKey); | ||||
|  | ||||
| @ -1,17 +1,25 @@ | ||||
| #include <cli/cli.h> | ||||
| #include <cli/cli_i.h> | ||||
| #include <infrared.h> | ||||
| #include <infrared_worker.h> | ||||
| #include <furi_hal_infrared.h> | ||||
| #include <flipper_format.h> | ||||
| #include <toolbox/args.h> | ||||
| #include <m-dict.h> | ||||
| 
 | ||||
| #include "infrared_signal.h" | ||||
| #include "infrared_brute_force.h" | ||||
| 
 | ||||
| #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_tx(Cli* cli, FuriString* args); | ||||
| static void infrared_cli_process_decode(Cli* cli, FuriString* args); | ||||
| static void infrared_cli_process_universal(Cli* cli, FuriString* args); | ||||
| 
 | ||||
| static const struct { | ||||
|     const char* cmd; | ||||
| @ -20,6 +28,7 @@ static const struct { | ||||
|     {.cmd = "rx", .process_function = infrared_cli_start_ir_rx}, | ||||
|     {.cmd = "tx", .process_function = infrared_cli_start_ir_tx}, | ||||
|     {.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) { | ||||
| @ -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) { | ||||
|     printf("Usage:\r\n"); | ||||
|     printf("\tir rx\r\n"); | ||||
|     printf("\tir rx [raw]\r\n"); | ||||
|     printf("\tir tx <protocol> <address> <command>\r\n"); | ||||
|     printf("\t<command> and <address> are hex-formatted\r\n"); | ||||
|     printf("\tAvailable protocols:"); | ||||
| @ -90,6 +83,39 @@ static void infrared_cli_print_usage(void) { | ||||
|         INFRARED_MIN_FREQUENCY, | ||||
|         INFRARED_MAX_FREQUENCY); | ||||
|     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) { | ||||
| @ -328,6 +354,131 @@ static void infrared_cli_process_decode(Cli* cli, FuriString* args) { | ||||
|     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) { | ||||
|     UNUSED(context); | ||||
|     if(furi_hal_infrared_is_busy()) { | ||||
|  | ||||
| @ -2,6 +2,7 @@ | ||||
| 
 | ||||
| #include <gui/gui.h> | ||||
| #include <gui/view.h> | ||||
| #include <assets_icons.h> | ||||
| #include <gui/view_stack.h> | ||||
| #include <gui/view_dispatcher.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_tv, UniversalTV) | ||||
| ADD_SCENE(infrared, universal_ac, UniversalAC) | ||||
| ADD_SCENE(infrared, universal_audio, UniversalAudio) | ||||
| ADD_SCENE(infrared, debug, Debug) | ||||
| ADD_SCENE(infrared, error_databases, ErrorDatabases) | ||||
| ADD_SCENE(infrared, rpc, Rpc) | ||||
|  | ||||
| @ -1,4 +1,5 @@ | ||||
| #include "../infrared_i.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| void infrared_scene_learn_on_enter(void* context) { | ||||
|     Infrared* infrared = context; | ||||
| @ -27,6 +28,7 @@ bool infrared_scene_learn_on_event(void* context, SceneManagerEvent event) { | ||||
|         if(event.event == InfraredCustomEventTypeSignalReceived) { | ||||
|             infrared_play_notification_message(infrared, InfraredNotificationMessageSuccess); | ||||
|             scene_manager_next_scene(infrared->scene_manager, InfraredSceneLearnSuccess); | ||||
|             DOLPHIN_DEED(DolphinDeedIrLearnSuccess); | ||||
|             consumed = true; | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @ -1,13 +1,10 @@ | ||||
| #include "../infrared_i.h" | ||||
| 
 | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| void infrared_scene_learn_done_on_enter(void* context) { | ||||
|     Infrared* infrared = context; | ||||
|     Popup* popup = infrared->popup; | ||||
| 
 | ||||
|     popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); | ||||
|     DOLPHIN_DEED(DolphinDeedIrSave); | ||||
| 
 | ||||
|     if(infrared->app_state.is_learning_new_remote) { | ||||
|         popup_set_header(popup, "New remote\ncreated!", 0, 0, AlignLeft, AlignTop); | ||||
|  | ||||
| @ -1,4 +1,5 @@ | ||||
| #include "../infrared_i.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| void infrared_scene_learn_enter_name_on_enter(void* context) { | ||||
|     Infrared* infrared = context; | ||||
| @ -49,6 +50,7 @@ bool infrared_scene_learn_enter_name_on_event(void* context, SceneManagerEvent e | ||||
| 
 | ||||
|             if(success) { | ||||
|                 scene_manager_next_scene(scene_manager, InfraredSceneLearnDone); | ||||
|                 DOLPHIN_DEED(DolphinDeedIrSave); | ||||
|             } else { | ||||
|                 dialog_message_show_storage_error(infrared->dialogs, "Failed to save file"); | ||||
|                 const uint32_t possible_scenes[] = {InfraredSceneRemoteList, InfraredSceneStart}; | ||||
|  | ||||
| @ -1,7 +1,5 @@ | ||||
| #include "../infrared_i.h" | ||||
| 
 | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| static void | ||||
|     infrared_scene_learn_success_dialog_result_callback(DialogExResult result, void* context) { | ||||
|     Infrared* infrared = context; | ||||
| @ -13,7 +11,6 @@ void infrared_scene_learn_success_on_enter(void* context) { | ||||
|     DialogEx* dialog_ex = infrared->dialog_ex; | ||||
|     InfraredSignal* signal = infrared->received_signal; | ||||
| 
 | ||||
|     DOLPHIN_DEED(DolphinDeedIrLearnSuccess); | ||||
|     infrared_play_notification_message(infrared, InfraredNotificationMessageGreenOn); | ||||
| 
 | ||||
|     if(infrared_signal_is_raw(signal)) { | ||||
|  | ||||
| @ -21,6 +21,12 @@ void infrared_scene_universal_on_enter(void* context) { | ||||
|         SubmenuIndexUniversalTV, | ||||
|         infrared_scene_universal_submenu_callback, | ||||
|         context); | ||||
|     submenu_add_item( | ||||
|         submenu, | ||||
|         "Audio Players", | ||||
|         SubmenuIndexUniversalAudio, | ||||
|         infrared_scene_universal_submenu_callback, | ||||
|         context); | ||||
|     submenu_add_item( | ||||
|         submenu, | ||||
|         "Air Conditioners", | ||||
| @ -45,7 +51,7 @@ bool infrared_scene_universal_on_event(void* context, SceneManagerEvent event) { | ||||
|             scene_manager_next_scene(scene_manager, InfraredSceneUniversalAC); | ||||
|             consumed = true; | ||||
|         } else if(event.event == SubmenuIndexUniversalAudio) { | ||||
|             //TODO Implement Audio universal remote
 | ||||
|             scene_manager_next_scene(scene_manager, InfraredSceneUniversalAudio); | ||||
|             consumed = true; | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @ -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 <dolphin/dolphin.h> | ||||
| 
 | ||||
| static bool lfrfid_debug_custom_event_callback(void* context, uint32_t event) { | ||||
|     furi_assert(context); | ||||
| @ -182,12 +183,14 @@ int32_t lfrfid_app(void* p) { | ||||
|             view_dispatcher_attach_to_gui( | ||||
|                 app->view_dispatcher, app->gui, ViewDispatcherTypeDesktop); | ||||
|             scene_manager_next_scene(app->scene_manager, LfRfidSceneRpc); | ||||
|             DOLPHIN_DEED(DolphinDeedRfidEmulate); | ||||
|         } else { | ||||
|             furi_string_set(app->file_path, args); | ||||
|             lfrfid_load_key_data(app, app->file_path, true); | ||||
|             view_dispatcher_attach_to_gui( | ||||
|                 app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); | ||||
|             scene_manager_next_scene(app->scene_manager, LfRfidSceneEmulate); | ||||
|             DOLPHIN_DEED(DolphinDeedRfidEmulate); | ||||
|         } | ||||
| 
 | ||||
|     } else { | ||||
|  | ||||
| @ -5,6 +5,7 @@ | ||||
| 
 | ||||
| #include <gui/gui.h> | ||||
| #include <gui/view.h> | ||||
| #include <assets_icons.h> | ||||
| #include <gui/view_dispatcher.h> | ||||
| #include <gui/scene_manager.h> | ||||
| #include <cli/cli.h> | ||||
|  | ||||
| @ -1,12 +1,9 @@ | ||||
| #include "../lfrfid_i.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| void lfrfid_scene_emulate_on_enter(void* context) { | ||||
|     LfRfid* app = context; | ||||
|     Popup* popup = app->popup; | ||||
| 
 | ||||
|     DOLPHIN_DEED(DolphinDeedRfidEmulate); | ||||
| 
 | ||||
|     popup_set_header(popup, "Emulating", 89, 30, AlignCenter, AlignTop); | ||||
|     if(!furi_string_empty(app->file_name)) { | ||||
|         popup_set_text(popup, furi_string_get_cstr(app->file_name), 89, 43, AlignCenter, AlignTop); | ||||
|  | ||||
| @ -1,4 +1,5 @@ | ||||
| #include "../lfrfid_i.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| typedef enum { | ||||
|     SubmenuIndexASK, | ||||
| @ -57,10 +58,12 @@ bool lfrfid_scene_extra_actions_on_event(void* context, SceneManagerEvent event) | ||||
|         if(event.event == SubmenuIndexASK) { | ||||
|             app->read_type = LFRFIDWorkerReadTypeASKOnly; | ||||
|             scene_manager_next_scene(app->scene_manager, LfRfidSceneRead); | ||||
|             DOLPHIN_DEED(DolphinDeedRfidRead); | ||||
|             consumed = true; | ||||
|         } else if(event.event == SubmenuIndexPSK) { | ||||
|             app->read_type = LFRFIDWorkerReadTypePSKOnly; | ||||
|             scene_manager_next_scene(app->scene_manager, LfRfidSceneRead); | ||||
|             DOLPHIN_DEED(DolphinDeedRfidRead); | ||||
|             consumed = true; | ||||
|         } else if(event.event == SubmenuIndexRAW) { | ||||
|             scene_manager_next_scene(app->scene_manager, LfRfidSceneRawName); | ||||
|  | ||||
| @ -34,7 +34,7 @@ void lfrfid_scene_raw_info_on_enter(void* context) { | ||||
|     } | ||||
| 
 | ||||
|     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) { | ||||
|  | ||||
| @ -46,7 +46,6 @@ static void | ||||
| void lfrfid_scene_read_on_enter(void* context) { | ||||
|     LfRfid* app = context; | ||||
| 
 | ||||
|     DOLPHIN_DEED(DolphinDeedRfidRead); | ||||
|     if(app->read_type == LFRFIDWorkerReadTypePSKOnly) { | ||||
|         lfrfid_view_read_set_read_mode(app->read_view, LfRfidReadPskOnly); | ||||
|     } else if(app->read_type == LFRFIDWorkerReadTypeASKOnly) { | ||||
| @ -79,10 +78,10 @@ bool lfrfid_scene_read_on_event(void* context, SceneManagerEvent event) { | ||||
|             consumed = true; | ||||
|         } else if(event.event == LfRfidEventReadDone) { | ||||
|             app->protocol_id = app->protocol_id_next; | ||||
|             DOLPHIN_DEED(DolphinDeedRfidReadSuccess); | ||||
|             notification_message(app->notifications, &sequence_success); | ||||
|             furi_string_reset(app->file_name); | ||||
|             scene_manager_next_scene(app->scene_manager, LfRfidSceneReadSuccess); | ||||
|             DOLPHIN_DEED(DolphinDeedRfidReadSuccess); | ||||
|             consumed = true; | ||||
|         } else if(event.event == LfRfidEventReadStartPSK) { | ||||
|             if(app->read_type == LFRFIDWorkerReadTypeAuto) { | ||||
|  | ||||
| @ -1,4 +1,5 @@ | ||||
| #include "../lfrfid_i.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| typedef enum { | ||||
|     SubmenuIndexSave, | ||||
| @ -43,6 +44,7 @@ bool lfrfid_scene_read_key_menu_on_event(void* context, SceneManagerEvent event) | ||||
|             consumed = true; | ||||
|         } else if(event.event == SubmenuIndexEmulate) { | ||||
|             scene_manager_next_scene(app->scene_manager, LfRfidSceneEmulate); | ||||
|             DOLPHIN_DEED(DolphinDeedRfidEmulate); | ||||
|             consumed = true; | ||||
|         } | ||||
|         scene_manager_set_scene_state(app->scene_manager, LfRfidSceneReadKeyMenu, event.event); | ||||
|  | ||||
| @ -1,5 +1,4 @@ | ||||
| #include "../lfrfid_i.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| void lfrfid_scene_save_data_on_enter(void* context) { | ||||
|     LfRfid* app = context; | ||||
| @ -32,7 +31,6 @@ bool lfrfid_scene_save_data_on_event(void* context, SceneManagerEvent event) { | ||||
|             consumed = true; | ||||
|             size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id); | ||||
|             protocol_dict_set_data(app->dict, app->protocol_id, app->new_key_data, size); | ||||
|             DOLPHIN_DEED(DolphinDeedRfidAdd); | ||||
|             scene_manager_next_scene(scene_manager, LfRfidSceneSaveName); | ||||
|             scene_manager_set_scene_state(scene_manager, LfRfidSceneSaveData, 1); | ||||
|         } | ||||
|  | ||||
| @ -1,5 +1,6 @@ | ||||
| #include <lib/toolbox/random_name.h> | ||||
| #include "../lfrfid_i.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| void lfrfid_scene_save_name_on_enter(void* context) { | ||||
|     LfRfid* app = context; | ||||
| @ -55,6 +56,13 @@ bool lfrfid_scene_save_name_on_event(void* context, SceneManagerEvent event) { | ||||
| 
 | ||||
|             if(lfrfid_save_key(app)) { | ||||
|                 scene_manager_next_scene(scene_manager, LfRfidSceneSaveSuccess); | ||||
|                 if(scene_manager_has_previous_scene(scene_manager, LfRfidSceneSavedKeyMenu)) { | ||||
|                     // Nothing, do not count editing as saving
 | ||||
|                 } else if(scene_manager_has_previous_scene(scene_manager, LfRfidSceneSaveType)) { | ||||
|                     DOLPHIN_DEED(DolphinDeedRfidAdd); | ||||
|                 } else { | ||||
|                     DOLPHIN_DEED(DolphinDeedRfidSave); | ||||
|                 } | ||||
|             } else { | ||||
|                 scene_manager_search_and_switch_to_previous_scene( | ||||
|                     scene_manager, LfRfidSceneReadKeyMenu); | ||||
|  | ||||
| @ -1,5 +1,4 @@ | ||||
| #include "../lfrfid_i.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| void lfrfid_scene_save_success_on_enter(void* context) { | ||||
|     LfRfid* app = context; | ||||
| @ -8,7 +7,6 @@ void lfrfid_scene_save_success_on_enter(void* context) { | ||||
|     // Clear state of data enter scene
 | ||||
|     scene_manager_set_scene_state(app->scene_manager, LfRfidSceneSaveData, 0); | ||||
| 
 | ||||
|     DOLPHIN_DEED(DolphinDeedRfidSave); | ||||
|     popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); | ||||
|     popup_set_header(popup, "Saved!", 5, 7, AlignLeft, AlignTop); | ||||
|     popup_set_context(popup, app); | ||||
|  | ||||
| @ -1,4 +1,5 @@ | ||||
| #include "../lfrfid_i.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| typedef enum { | ||||
|     SubmenuIndexEmulate, | ||||
| @ -42,6 +43,7 @@ bool lfrfid_scene_saved_key_menu_on_event(void* context, SceneManagerEvent event | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         if(event.event == SubmenuIndexEmulate) { | ||||
|             scene_manager_next_scene(app->scene_manager, LfRfidSceneEmulate); | ||||
|             DOLPHIN_DEED(DolphinDeedRfidEmulate); | ||||
|             consumed = true; | ||||
|         } else if(event.event == SubmenuIndexWrite) { | ||||
|             scene_manager_next_scene(app->scene_manager, LfRfidSceneWrite); | ||||
|  | ||||
| @ -1,4 +1,5 @@ | ||||
| #include "../lfrfid_i.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| typedef enum { | ||||
|     SubmenuIndexRead, | ||||
| @ -47,6 +48,7 @@ bool lfrfid_scene_start_on_event(void* context, SceneManagerEvent event) { | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         if(event.event == SubmenuIndexRead) { | ||||
|             scene_manager_next_scene(app->scene_manager, LfRfidSceneRead); | ||||
|             DOLPHIN_DEED(DolphinDeedRfidRead); | ||||
|             consumed = true; | ||||
|         } else if(event.event == SubmenuIndexSaved) { | ||||
|             furi_string_set(app->file_path, LFRFID_APP_FOLDER); | ||||
|  | ||||
| @ -1,5 +1,6 @@ | ||||
| #include "lfrfid_view_read.h" | ||||
| #include <gui/elements.h> | ||||
| #include <assets_icons.h> | ||||
| 
 | ||||
| #define TEMP_STR_LEN 128 | ||||
| 
 | ||||
|  | ||||
| @ -1,5 +1,6 @@ | ||||
| #include "nfc_i.h" | ||||
| #include "furi_hal_nfc.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| bool nfc_custom_event_callback(void* context, uint32_t event) { | ||||
|     furi_assert(context); | ||||
| @ -275,12 +276,15 @@ int32_t nfc_app(void* p) { | ||||
|             if(nfc_device_load(nfc->dev, p, true)) { | ||||
|                 if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { | ||||
|                     scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate); | ||||
|                     DOLPHIN_DEED(DolphinDeedNfcEmulate); | ||||
|                 } else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) { | ||||
|                     scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate); | ||||
|                     DOLPHIN_DEED(DolphinDeedNfcEmulate); | ||||
|                 } else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) { | ||||
|                     scene_manager_next_scene(nfc->scene_manager, NfcSceneDeviceInfo); | ||||
|                 } else { | ||||
|                     scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); | ||||
|                     DOLPHIN_DEED(DolphinDeedNfcEmulate); | ||||
|                 } | ||||
|             } else { | ||||
|                 // Exit app
 | ||||
|  | ||||
| @ -7,6 +7,7 @@ | ||||
| 
 | ||||
| #include <gui/gui.h> | ||||
| #include <gui/view.h> | ||||
| #include <assets_icons.h> | ||||
| #include <gui/view_dispatcher.h> | ||||
| #include <gui/scene_manager.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_warn_duplicate, MfClassicKeysWarnDuplicate) | ||||
| ADD_SCENE(nfc, mf_classic_dict_attack, MfClassicDictAttack) | ||||
| ADD_SCENE(nfc, mf_classic_write, MfClassicWrite) | ||||
| ADD_SCENE(nfc, mf_classic_write_success, MfClassicWriteSuccess) | ||||
| ADD_SCENE(nfc, mf_classic_write_fail, MfClassicWriteFail) | ||||
| ADD_SCENE(nfc, mf_classic_update, MfClassicUpdate) | ||||
| ADD_SCENE(nfc, mf_classic_update_success, MfClassicUpdateSuccess) | ||||
| ADD_SCENE(nfc, mf_classic_wrong_card, MfClassicWrongCard) | ||||
| ADD_SCENE(nfc, emv_read_success, EmvReadSuccess) | ||||
| ADD_SCENE(nfc, emv_menu, EmvMenu) | ||||
| ADD_SCENE(nfc, emulate_apdu_sequence, EmulateApduSequence) | ||||
|  | ||||
| @ -1,5 +1,4 @@ | ||||
| #include "../nfc_i.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| #define NFC_SCENE_DETECT_READER_PAIR_NONCES_MAX (10U) | ||||
| 
 | ||||
| @ -26,10 +25,14 @@ void nfc_scene_detect_reader_callback(void* context) { | ||||
| 
 | ||||
| void nfc_scene_detect_reader_on_enter(void* context) { | ||||
|     Nfc* nfc = context; | ||||
|     DOLPHIN_DEED(DolphinDeedNfcDetectReader); | ||||
| 
 | ||||
|     detect_reader_set_callback(nfc->detect_reader, nfc_scene_detect_reader_callback, nfc); | ||||
|     detect_reader_set_nonces_max(nfc->detect_reader, NFC_SCENE_DETECT_READER_PAIR_NONCES_MAX); | ||||
|     NfcDeviceData* dev_data = &nfc->dev->dev_data; | ||||
|     if(dev_data->nfc_data.uid_len) { | ||||
|         detect_reader_set_uid( | ||||
|             nfc->detect_reader, dev_data->nfc_data.uid, dev_data->nfc_data.uid_len); | ||||
|     } | ||||
| 
 | ||||
|     // Store number of collected nonces in scene state
 | ||||
|     scene_manager_set_scene_state(nfc->scene_manager, NfcSceneDetectReader, 0); | ||||
|  | ||||
| @ -1,5 +1,4 @@ | ||||
| #include "../nfc_i.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| #define NFC_SCENE_EMULATE_UID_LOG_SIZE_MAX (200) | ||||
| 
 | ||||
| @ -59,7 +58,6 @@ static void nfc_scene_emulate_uid_widget_config(Nfc* nfc, bool data_received) { | ||||
| 
 | ||||
| void nfc_scene_emulate_uid_on_enter(void* context) { | ||||
|     Nfc* nfc = context; | ||||
|     DOLPHIN_DEED(DolphinDeedNfcEmulate); | ||||
| 
 | ||||
|     // Setup Widget
 | ||||
|     nfc_scene_emulate_uid_widget_config(nfc, false); | ||||
|  | ||||
| @ -1,6 +1,5 @@ | ||||
| #include "../nfc_i.h" | ||||
| #include "../helpers/nfc_emv_parser.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| void nfc_scene_emv_read_success_widget_callback( | ||||
|     GuiButtonType result, | ||||
| @ -15,7 +14,6 @@ void nfc_scene_emv_read_success_widget_callback( | ||||
| void nfc_scene_emv_read_success_on_enter(void* context) { | ||||
|     Nfc* nfc = context; | ||||
|     EmvData* emv_data = &nfc->dev->dev_data.emv_data; | ||||
|     DOLPHIN_DEED(DolphinDeedNfcReadSuccess); | ||||
| 
 | ||||
|     // Setup Custom Widget view
 | ||||
|     widget_add_button_element( | ||||
|  | ||||
| @ -1,4 +1,5 @@ | ||||
| #include "../nfc_i.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| #define TAG "NfcMfClassicDictAttack" | ||||
| 
 | ||||
| @ -110,6 +111,7 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent | ||||
|             } else { | ||||
|                 notification_message(nfc->notifications, &sequence_success); | ||||
|                 scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSuccess); | ||||
|                 DOLPHIN_DEED(DolphinDeedNfcReadSuccess); | ||||
|                 consumed = true; | ||||
|             } | ||||
|         } else if(event.event == NfcWorkerEventAborted) { | ||||
| @ -119,6 +121,8 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent | ||||
|             } else { | ||||
|                 notification_message(nfc->notifications, &sequence_success); | ||||
|                 scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSuccess); | ||||
|                 // Counting failed attempts too
 | ||||
|                 DOLPHIN_DEED(DolphinDeedNfcReadSuccess); | ||||
|                 consumed = true; | ||||
|             } | ||||
|         } else if(event.event == NfcWorkerEventCardDetected) { | ||||
|  | ||||
| @ -1,5 +1,4 @@ | ||||
| #include "../nfc_i.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| #define NFC_MF_CLASSIC_DATA_NOT_CHANGED (0UL) | ||||
| #define NFC_MF_CLASSIC_DATA_CHANGED (1UL) | ||||
| @ -15,7 +14,6 @@ bool nfc_mf_classic_emulate_worker_callback(NfcWorkerEvent event, void* context) | ||||
| 
 | ||||
| void nfc_scene_mf_classic_emulate_on_enter(void* context) { | ||||
|     Nfc* nfc = context; | ||||
|     DOLPHIN_DEED(DolphinDeedNfcEmulate); | ||||
| 
 | ||||
|     // Setup view
 | ||||
|     Popup* popup = nfc->popup; | ||||
|  | ||||
| @ -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_button_element( | ||||
|         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); | ||||
|     if(user_dict_keys_total > 0) { | ||||
|         widget_add_button_element( | ||||
| @ -57,9 +55,6 @@ bool nfc_scene_mf_classic_keys_on_event(void* context, SceneManagerEvent event) | ||||
|         if(event.event == GuiButtonTypeCenter) { | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicKeysAdd); | ||||
|             consumed = true; | ||||
|         } else if(event.event == GuiButtonTypeLeft) { | ||||
|             scene_manager_previous_scene(nfc->scene_manager); | ||||
|             consumed = true; | ||||
|         } else if(event.event == GuiButtonTypeRight) { | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicKeysList); | ||||
|             consumed = true; | ||||
|  | ||||
| @ -1,4 +1,5 @@ | ||||
| #include "../nfc_i.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| void nfc_scene_mf_classic_keys_add_byte_input_callback(void* context) { | ||||
|     Nfc* nfc = context; | ||||
| @ -36,6 +37,7 @@ bool nfc_scene_mf_classic_keys_add_on_event(void* context, SceneManagerEvent eve | ||||
|                         nfc->scene_manager, NfcSceneMfClassicKeysWarnDuplicate); | ||||
|                 } else if(mf_classic_dict_add_key(dict, nfc->byte_input_store)) { | ||||
|                     scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess); | ||||
|                     DOLPHIN_DEED(DolphinDeedNfcMfcAdd); | ||||
|                 } else { | ||||
|                     scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound); | ||||
|                 } | ||||
|  | ||||
| @ -36,8 +36,6 @@ bool nfc_scene_mf_classic_menu_on_event(void* context, SceneManagerEvent event) | ||||
| 
 | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         if(event.event == SubmenuIndexSave) { | ||||
|             DOLPHIN_DEED(DolphinDeedNfcMfcAdd); | ||||
| 
 | ||||
|             scene_manager_set_scene_state( | ||||
|                 nfc->scene_manager, NfcSceneMfClassicMenu, SubmenuIndexSave); | ||||
|             nfc->dev->format = NfcDeviceSaveFormatMifareClassic; | ||||
| @ -49,6 +47,11 @@ bool nfc_scene_mf_classic_menu_on_event(void* context, SceneManagerEvent event) | ||||
|             scene_manager_set_scene_state( | ||||
|                 nfc->scene_manager, NfcSceneMfClassicMenu, SubmenuIndexEmulate); | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate); | ||||
|             if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) { | ||||
|                 DOLPHIN_DEED(DolphinDeedNfcAddEmulate); | ||||
|             } else { | ||||
|                 DOLPHIN_DEED(DolphinDeedNfcEmulate); | ||||
|             } | ||||
|             consumed = true; | ||||
|         } else if(event.event == SubmenuIndexInfo) { | ||||
|             scene_manager_set_scene_state( | ||||
|  | ||||
| @ -1,5 +1,4 @@ | ||||
| #include "../nfc_i.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| void nfc_scene_mf_classic_read_success_widget_callback( | ||||
|     GuiButtonType result, | ||||
| @ -18,8 +17,6 @@ void nfc_scene_mf_classic_read_success_on_enter(void* context) { | ||||
|     NfcDeviceData* dev_data = &nfc->dev->dev_data; | ||||
|     MfClassicData* mf_data = &dev_data->mf_classic_data; | ||||
| 
 | ||||
|     DOLPHIN_DEED(DolphinDeedNfcReadSuccess); | ||||
| 
 | ||||
|     // Setup view
 | ||||
|     Widget* widget = nfc->widget; | ||||
|     widget_add_button_element( | ||||
|  | ||||
							
								
								
									
										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 <dolphin/dolphin.h> | ||||
| 
 | ||||
| enum SubmenuIndex { | ||||
|     SubmenuIndexSave, | ||||
| @ -48,6 +49,11 @@ bool nfc_scene_mf_desfire_menu_on_event(void* context, SceneManagerEvent event) | ||||
|             consumed = true; | ||||
|         } else if(event.event == SubmenuIndexEmulateUid) { | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); | ||||
|             if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) { | ||||
|                 DOLPHIN_DEED(DolphinDeedNfcAddEmulate); | ||||
|             } else { | ||||
|                 DOLPHIN_DEED(DolphinDeedNfcEmulate); | ||||
|             } | ||||
|             consumed = true; | ||||
|         } else if(event.event == SubmenuIndexInfo) { | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); | ||||
|  | ||||
| @ -1,5 +1,4 @@ | ||||
| #include "../nfc_i.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| #define NFC_MF_UL_DATA_NOT_CHANGED (0UL) | ||||
| #define NFC_MF_UL_DATA_CHANGED (1UL) | ||||
| @ -15,7 +14,6 @@ bool nfc_mf_ultralight_emulate_worker_callback(NfcWorkerEvent event, void* conte | ||||
| 
 | ||||
| void nfc_scene_mf_ultralight_emulate_on_enter(void* context) { | ||||
|     Nfc* nfc = context; | ||||
|     DOLPHIN_DEED(DolphinDeedNfcEmulate); | ||||
| 
 | ||||
|     // Setup view
 | ||||
|     Popup* popup = nfc->popup; | ||||
|  | ||||
| @ -1,4 +1,5 @@ | ||||
| #include "../nfc_i.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| enum SubmenuIndex { | ||||
|     SubmenuIndexUnlock, | ||||
| @ -56,6 +57,11 @@ bool nfc_scene_mf_ultralight_menu_on_event(void* context, SceneManagerEvent even | ||||
|             consumed = true; | ||||
|         } else if(event.event == SubmenuIndexEmulate) { | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate); | ||||
|             if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) { | ||||
|                 DOLPHIN_DEED(DolphinDeedNfcAddEmulate); | ||||
|             } else { | ||||
|                 DOLPHIN_DEED(DolphinDeedNfcEmulate); | ||||
|             } | ||||
|             consumed = true; | ||||
|         } else if(event.event == SubmenuIndexUnlock) { | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockMenu); | ||||
|  | ||||
| @ -1,5 +1,4 @@ | ||||
| #include "../nfc_i.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| typedef enum { | ||||
|     NfcSceneMfUlReadStateIdle, | ||||
| @ -51,7 +50,6 @@ void nfc_scene_mf_ultralight_read_auth_set_state(Nfc* nfc, NfcSceneMfUlReadState | ||||
| 
 | ||||
| void nfc_scene_mf_ultralight_read_auth_on_enter(void* context) { | ||||
|     Nfc* nfc = context; | ||||
|     DOLPHIN_DEED(DolphinDeedNfcRead); | ||||
| 
 | ||||
|     nfc_device_clear(nfc->dev); | ||||
|     // Setup view
 | ||||
|  | ||||
| @ -1,5 +1,4 @@ | ||||
| #include "../nfc_i.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| void nfc_scene_mf_ultralight_read_auth_result_widget_callback( | ||||
|     GuiButtonType result, | ||||
| @ -37,7 +36,6 @@ void nfc_scene_mf_ultralight_read_auth_result_on_enter(void* context) { | ||||
|     widget_add_string_element( | ||||
|         widget, 0, 17, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(temp_str)); | ||||
|     if(mf_ul_data->auth_success) { | ||||
|         DOLPHIN_DEED(DolphinDeedNfcReadSuccess); | ||||
|         furi_string_printf( | ||||
|             temp_str, | ||||
|             "Password: %02X %02X %02X %02X", | ||||
| @ -54,8 +52,6 @@ void nfc_scene_mf_ultralight_read_auth_result_on_enter(void* context) { | ||||
|             config_pages->auth_data.pack.raw[1]); | ||||
|         widget_add_string_element( | ||||
|             widget, 0, 39, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(temp_str)); | ||||
|     } else { | ||||
|         DOLPHIN_DEED(DolphinDeedNfcMfulError); | ||||
|     } | ||||
|     furi_string_printf( | ||||
|         temp_str, "Pages Read: %d/%d", mf_ul_data->data_read / 4, mf_ul_data->data_size / 4); | ||||
|  | ||||
| @ -1,5 +1,4 @@ | ||||
| #include "../nfc_i.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| void nfc_scene_mf_ultralight_read_success_widget_callback( | ||||
|     GuiButtonType result, | ||||
| @ -14,7 +13,6 @@ void nfc_scene_mf_ultralight_read_success_widget_callback( | ||||
| 
 | ||||
| void nfc_scene_mf_ultralight_read_success_on_enter(void* context) { | ||||
|     Nfc* nfc = context; | ||||
|     DOLPHIN_DEED(DolphinDeedNfcReadSuccess); | ||||
| 
 | ||||
|     // Setup widget view
 | ||||
|     FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; | ||||
|  | ||||
| @ -1,4 +1,5 @@ | ||||
| #include "../nfc_i.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| void nfc_scene_mf_ultralight_unlock_warn_dialog_callback(DialogExResult result, void* context) { | ||||
|     Nfc* nfc = context; | ||||
| @ -30,6 +31,7 @@ bool nfc_scene_mf_ultralight_unlock_warn_on_event(void* context, SceneManagerEve | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         if(event.event == DialogExResultCenter) { | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadAuth); | ||||
|             DOLPHIN_DEED(DolphinDeedNfcRead); | ||||
|             consumed = true; | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @ -1,4 +1,5 @@ | ||||
| #include "../nfc_i.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| enum SubmenuIndex { | ||||
|     SubmenuIndexSaveUid, | ||||
| @ -41,6 +42,11 @@ bool nfc_scene_nfca_menu_on_event(void* context, SceneManagerEvent event) { | ||||
|             consumed = true; | ||||
|         } else if(event.event == SubmenuIndexEmulateUid) { | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); | ||||
|             if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) { | ||||
|                 DOLPHIN_DEED(DolphinDeedNfcAddEmulate); | ||||
|             } else { | ||||
|                 DOLPHIN_DEED(DolphinDeedNfcEmulate); | ||||
|             } | ||||
|             consumed = true; | ||||
|         } else if(event.event == SubmenuIndexInfo) { | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); | ||||
|  | ||||
| @ -1,5 +1,4 @@ | ||||
| #include "../nfc_i.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| void nfc_scene_nfca_read_success_widget_callback( | ||||
|     GuiButtonType result, | ||||
| @ -16,8 +15,6 @@ void nfc_scene_nfca_read_success_widget_callback( | ||||
| void nfc_scene_nfca_read_success_on_enter(void* context) { | ||||
|     Nfc* nfc = context; | ||||
| 
 | ||||
|     DOLPHIN_DEED(DolphinDeedNfcReadSuccess); | ||||
| 
 | ||||
|     // Setup view
 | ||||
|     FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; | ||||
|     Widget* widget = nfc->widget; | ||||
|  | ||||
| @ -39,7 +39,6 @@ void nfc_scene_read_set_state(Nfc* nfc, NfcSceneReadState state) { | ||||
| 
 | ||||
| void nfc_scene_read_on_enter(void* context) { | ||||
|     Nfc* nfc = context; | ||||
|     DOLPHIN_DEED(DolphinDeedNfcRead); | ||||
| 
 | ||||
|     nfc_device_clear(nfc->dev); | ||||
|     // Setup view
 | ||||
| @ -62,26 +61,32 @@ bool nfc_scene_read_on_event(void* context, SceneManagerEvent event) { | ||||
|            (event.event == NfcWorkerEventReadUidNfcV)) { | ||||
|             notification_message(nfc->notifications, &sequence_success); | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardSuccess); | ||||
|             DOLPHIN_DEED(DolphinDeedNfcReadSuccess); | ||||
|             consumed = true; | ||||
|         } else if(event.event == NfcWorkerEventReadUidNfcA) { | ||||
|             notification_message(nfc->notifications, &sequence_success); | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcaReadSuccess); | ||||
|             DOLPHIN_DEED(DolphinDeedNfcReadSuccess); | ||||
|             consumed = true; | ||||
|         } else if(event.event == NfcWorkerEventReadMfUltralight) { | ||||
|             notification_message(nfc->notifications, &sequence_success); | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadSuccess); | ||||
|             DOLPHIN_DEED(DolphinDeedNfcReadSuccess); | ||||
|             consumed = true; | ||||
|         } else if(event.event == NfcWorkerEventReadMfClassicDone) { | ||||
|             notification_message(nfc->notifications, &sequence_success); | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSuccess); | ||||
|             DOLPHIN_DEED(DolphinDeedNfcReadSuccess); | ||||
|             consumed = true; | ||||
|         } else if(event.event == NfcWorkerEventReadMfDesfire) { | ||||
|             notification_message(nfc->notifications, &sequence_success); | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireReadSuccess); | ||||
|             DOLPHIN_DEED(DolphinDeedNfcReadSuccess); | ||||
|             consumed = true; | ||||
|         } else if(event.event == NfcWorkerEventReadBankCard) { | ||||
|             notification_message(nfc->notifications, &sequence_success); | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneEmvReadSuccess); | ||||
|             DOLPHIN_DEED(DolphinDeedNfcReadSuccess); | ||||
|             consumed = true; | ||||
|         } else if(event.event == NfcWorkerEventReadMfClassicDictAttackRequired) { | ||||
|             if(mf_classic_dict_check_presence(MfClassicDictTypeFlipper)) { | ||||
|  | ||||
| @ -1,5 +1,4 @@ | ||||
| #include "../nfc_i.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| void nfc_scene_read_card_success_widget_callback( | ||||
|     GuiButtonType result, | ||||
| @ -18,7 +17,6 @@ void nfc_scene_read_card_success_on_enter(void* context) { | ||||
| 
 | ||||
|     FuriString* temp_str; | ||||
|     temp_str = furi_string_alloc(); | ||||
|     DOLPHIN_DEED(DolphinDeedNfcReadSuccess); | ||||
| 
 | ||||
|     // Setup view
 | ||||
|     FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; | ||||
|  | ||||
| @ -2,6 +2,7 @@ | ||||
| #include <lib/toolbox/random_name.h> | ||||
| #include <gui/modules/validators.h> | ||||
| #include <toolbox/path.h> | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| void nfc_scene_save_name_text_input_callback(void* context) { | ||||
|     Nfc* nfc = context; | ||||
| @ -63,6 +64,13 @@ bool nfc_scene_save_name_on_event(void* context, SceneManagerEvent event) { | ||||
|             strlcpy(nfc->dev->dev_name, nfc->text_store, strlen(nfc->text_store) + 1); | ||||
|             if(nfc_device_save(nfc->dev, nfc->text_store)) { | ||||
|                 scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess); | ||||
|                 if(!scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSavedMenu)) { | ||||
|                     // Nothing, do not count editing as saving
 | ||||
|                 } else if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) { | ||||
|                     DOLPHIN_DEED(DolphinDeedNfcAddSave); | ||||
|                 } else { | ||||
|                     DOLPHIN_DEED(DolphinDeedNfcSave); | ||||
|                 } | ||||
|                 consumed = true; | ||||
|             } else { | ||||
|                 consumed = scene_manager_search_and_switch_to_previous_scene( | ||||
|  | ||||
| @ -1,5 +1,4 @@ | ||||
| #include "../nfc_i.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| void nfc_scene_save_success_popup_callback(void* context) { | ||||
|     Nfc* nfc = context; | ||||
| @ -8,7 +7,6 @@ void nfc_scene_save_success_popup_callback(void* context) { | ||||
| 
 | ||||
| void nfc_scene_save_success_on_enter(void* context) { | ||||
|     Nfc* nfc = context; | ||||
|     DOLPHIN_DEED(DolphinDeedNfcSave); | ||||
| 
 | ||||
|     // Setup view
 | ||||
|     Popup* popup = nfc->popup; | ||||
|  | ||||
| @ -1,8 +1,12 @@ | ||||
| #include "../nfc_i.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| enum SubmenuIndex { | ||||
|     SubmenuIndexEmulate, | ||||
|     SubmenuIndexEditUid, | ||||
|     SubmenuIndexDetectReader, | ||||
|     SubmenuIndexWrite, | ||||
|     SubmenuIndexUpdate, | ||||
|     SubmenuIndexRename, | ||||
|     SubmenuIndexDelete, | ||||
|     SubmenuIndexInfo, | ||||
| @ -41,6 +45,28 @@ void nfc_scene_saved_menu_on_enter(void* context) { | ||||
|         submenu_add_item( | ||||
|             submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_saved_menu_submenu_callback, nfc); | ||||
|     } | ||||
|     if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) { | ||||
|         if(!mf_classic_is_card_read(&nfc->dev->dev_data.mf_classic_data)) { | ||||
|             submenu_add_item( | ||||
|                 submenu, | ||||
|                 "Detect reader", | ||||
|                 SubmenuIndexDetectReader, | ||||
|                 nfc_scene_saved_menu_submenu_callback, | ||||
|                 nfc); | ||||
|         } | ||||
|         submenu_add_item( | ||||
|             submenu, | ||||
|             "Write To Initial Card", | ||||
|             SubmenuIndexWrite, | ||||
|             nfc_scene_saved_menu_submenu_callback, | ||||
|             nfc); | ||||
|         submenu_add_item( | ||||
|             submenu, | ||||
|             "Update From Initial Card", | ||||
|             SubmenuIndexUpdate, | ||||
|             nfc_scene_saved_menu_submenu_callback, | ||||
|             nfc); | ||||
|     } | ||||
|     submenu_add_item( | ||||
|         submenu, "Info", SubmenuIndexInfo, nfc_scene_saved_menu_submenu_callback, nfc); | ||||
|     if(nfc->dev->shadow_file_exist) { | ||||
| @ -76,6 +102,16 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { | ||||
|             } else { | ||||
|                 scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); | ||||
|             } | ||||
|             DOLPHIN_DEED(DolphinDeedNfcEmulate); | ||||
|             consumed = true; | ||||
|         } else if(event.event == SubmenuIndexDetectReader) { | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneDetectReader); | ||||
|             consumed = true; | ||||
|         } else if(event.event == SubmenuIndexWrite) { | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicWrite); | ||||
|             consumed = true; | ||||
|         } else if(event.event == SubmenuIndexUpdate) { | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicUpdate); | ||||
|             consumed = true; | ||||
|         } else if(event.event == SubmenuIndexRename) { | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); | ||||
|  | ||||
| @ -1,5 +1,4 @@ | ||||
| #include "../nfc_i.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| void nfc_scene_set_uid_byte_input_callback(void* context) { | ||||
|     Nfc* nfc = context; | ||||
| @ -30,7 +29,6 @@ bool nfc_scene_set_uid_on_event(void* context, SceneManagerEvent event) { | ||||
| 
 | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         if(event.event == NfcCustomEventByteInputDone) { | ||||
|             DOLPHIN_DEED(DolphinDeedNfcAddSave); | ||||
|             if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSavedMenu)) { | ||||
|                 nfc->dev->dev_data.nfc_data = nfc->dev_edit_data; | ||||
|                 if(nfc_device_save(nfc->dev, nfc->dev->dev_name)) { | ||||
|  | ||||
| @ -1,4 +1,5 @@ | ||||
| #include "../nfc_i.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| enum SubmenuIndex { | ||||
|     SubmenuIndexRead, | ||||
| @ -47,11 +48,14 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) { | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         if(event.event == SubmenuIndexRead) { | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); | ||||
|             DOLPHIN_DEED(DolphinDeedNfcRead); | ||||
|             consumed = true; | ||||
|         } else if(event.event == SubmenuIndexDetectReader) { | ||||
|             bool sd_exist = storage_sd_status(nfc->dev->storage) == FSE_OK; | ||||
|             if(sd_exist) { | ||||
|                 nfc_device_data_clear(&nfc->dev->dev_data); | ||||
|                 scene_manager_next_scene(nfc->scene_manager, NfcSceneDetectReader); | ||||
|                 DOLPHIN_DEED(DolphinDeedNfcDetectReader); | ||||
|             } else { | ||||
|                 scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound); | ||||
|             } | ||||
|  | ||||
| @ -1,7 +1,9 @@ | ||||
| #include "detect_reader.h" | ||||
| 
 | ||||
| #include <assets_icons.h> | ||||
| #include <gui/elements.h> | ||||
| 
 | ||||
| #define DETECT_READER_UID_MAX_LEN (10) | ||||
| 
 | ||||
| struct DetectReader { | ||||
|     View* view; | ||||
|     DetectReaderDoneCallback callback; | ||||
| @ -12,6 +14,7 @@ typedef struct { | ||||
|     uint16_t nonces; | ||||
|     uint16_t nonces_max; | ||||
|     DetectReaderState state; | ||||
|     FuriString* uid_str; | ||||
| } DetectReaderViewModel; | ||||
| 
 | ||||
| static void detect_reader_draw_callback(Canvas* canvas, void* model) { | ||||
| @ -23,6 +26,10 @@ static void detect_reader_draw_callback(Canvas* canvas, void* model) { | ||||
|     if(m->state == DetectReaderStateStart) { | ||||
|         snprintf(text, sizeof(text), "Touch the reader"); | ||||
|         canvas_draw_icon(canvas, 21, 13, &I_Move_flipper_26x39); | ||||
|         if(furi_string_size(m->uid_str)) { | ||||
|             elements_multiline_text_aligned( | ||||
|                 canvas, 64, 64, AlignCenter, AlignBottom, furi_string_get_cstr(m->uid_str)); | ||||
|         } | ||||
|     } else if(m->state == DetectReaderStateReaderDetected) { | ||||
|         snprintf(text, sizeof(text), "Move the Flipper away"); | ||||
|         canvas_draw_icon(canvas, 24, 25, &I_Release_arrow_18x15); | ||||
| @ -86,12 +93,24 @@ DetectReader* detect_reader_alloc() { | ||||
|     view_set_input_callback(detect_reader->view, detect_reader_input_callback); | ||||
|     view_set_context(detect_reader->view, detect_reader); | ||||
| 
 | ||||
|     with_view_model( | ||||
|         detect_reader->view, | ||||
|         DetectReaderViewModel * model, | ||||
|         { model->uid_str = furi_string_alloc(); }, | ||||
|         false); | ||||
| 
 | ||||
|     return detect_reader; | ||||
| } | ||||
| 
 | ||||
| void detect_reader_free(DetectReader* detect_reader) { | ||||
|     furi_assert(detect_reader); | ||||
| 
 | ||||
|     with_view_model( | ||||
|         detect_reader->view, | ||||
|         DetectReaderViewModel * model, | ||||
|         { furi_string_free(model->uid_str); }, | ||||
|         false); | ||||
| 
 | ||||
|     view_free(detect_reader->view); | ||||
|     free(detect_reader); | ||||
| } | ||||
| @ -106,6 +125,7 @@ void detect_reader_reset(DetectReader* detect_reader) { | ||||
|             model->nonces = 0; | ||||
|             model->nonces_max = 0; | ||||
|             model->state = DetectReaderStateStart; | ||||
|             furi_string_reset(model->uid_str); | ||||
|         }, | ||||
|         false); | ||||
| } | ||||
| @ -152,3 +172,19 @@ void detect_reader_set_state(DetectReader* detect_reader, DetectReaderState stat | ||||
|     with_view_model( | ||||
|         detect_reader->view, DetectReaderViewModel * model, { model->state = state; }, true); | ||||
| } | ||||
| 
 | ||||
| void detect_reader_set_uid(DetectReader* detect_reader, uint8_t* uid, uint8_t uid_len) { | ||||
|     furi_assert(detect_reader); | ||||
|     furi_assert(uid); | ||||
|     furi_assert(uid_len < DETECT_READER_UID_MAX_LEN); | ||||
|     with_view_model( | ||||
|         detect_reader->view, | ||||
|         DetectReaderViewModel * model, | ||||
|         { | ||||
|             furi_string_set_str(model->uid_str, "UID:"); | ||||
|             for(size_t i = 0; i < uid_len; i++) { | ||||
|                 furi_string_cat_printf(model->uid_str, " %02X", uid[i]); | ||||
|             } | ||||
|         }, | ||||
|         true); | ||||
| } | ||||
|  | ||||
| @ -32,3 +32,5 @@ void detect_reader_set_nonces_max(DetectReader* detect_reader, uint16_t nonces_m | ||||
| void detect_reader_set_nonces_collected(DetectReader* detect_reader, uint16_t nonces_collected); | ||||
| 
 | ||||
| void detect_reader_set_state(DetectReader* detect_reader, DetectReaderState state); | ||||
| 
 | ||||
| void detect_reader_set_uid(DetectReader* detect_reader, uint8_t* uid, uint8_t uid_len); | ||||
|  | ||||
| @ -69,12 +69,3 @@ typedef enum { | ||||
|     SubGhzViewIdTestCarrier, | ||||
|     SubGhzViewIdTestPacket, | ||||
| } 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 "../views/subghz_frequency_analyzer.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| void subghz_scene_frequency_analyzer_callback(SubGhzCustomEvent event, void* context) { | ||||
|     furi_assert(context); | ||||
| @ -10,7 +9,6 @@ void subghz_scene_frequency_analyzer_callback(SubGhzCustomEvent event, void* con | ||||
| 
 | ||||
| void subghz_scene_frequency_analyzer_on_enter(void* context) { | ||||
|     SubGhz* subghz = context; | ||||
|     DOLPHIN_DEED(DolphinDeedSubGhzFrequencyAnalyzer); | ||||
|     subghz_frequency_analyzer_set_callback( | ||||
|         subghz->subghz_frequency_analyzer, subghz_scene_frequency_analyzer_callback, subghz); | ||||
|     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdFrequencyAnalyzer); | ||||
|  | ||||
| @ -6,6 +6,7 @@ | ||||
| 
 | ||||
| #define RAW_FILE_NAME "Raw_signal_" | ||||
| #define TAG "SubGhzSceneReadRAW" | ||||
| #define RAW_THRESHOLD_RSSI_LOW_COUNT 10 | ||||
| 
 | ||||
| bool subghz_scene_read_raw_update_filename(SubGhz* subghz) { | ||||
|     bool ret = false; | ||||
| @ -72,24 +73,33 @@ void subghz_scene_read_raw_on_enter(void* context) { | ||||
| 
 | ||||
|     switch(subghz->txrx->rx_key_state) { | ||||
|     case SubGhzRxKeyStateBack: | ||||
|         subghz_read_raw_set_status(subghz->subghz_read_raw, SubGhzReadRAWStatusIDLE, ""); | ||||
|         subghz_read_raw_set_status( | ||||
|             subghz->subghz_read_raw, SubGhzReadRAWStatusIDLE, "", subghz->txrx->raw_threshold_rssi); | ||||
|         break; | ||||
|     case SubGhzRxKeyStateRAWLoad: | ||||
|         path_extract_filename(subghz->file_path, file_name, true); | ||||
|         subghz_read_raw_set_status( | ||||
|             subghz->subghz_read_raw, | ||||
|             SubGhzReadRAWStatusLoadKeyTX, | ||||
|             furi_string_get_cstr(file_name)); | ||||
|             furi_string_get_cstr(file_name), | ||||
|             subghz->txrx->raw_threshold_rssi); | ||||
|         subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; | ||||
|         break; | ||||
|     case SubGhzRxKeyStateRAWSave: | ||||
|         path_extract_filename(subghz->file_path, file_name, true); | ||||
|         subghz_read_raw_set_status( | ||||
|             subghz->subghz_read_raw, SubGhzReadRAWStatusSaveKey, furi_string_get_cstr(file_name)); | ||||
|             subghz->subghz_read_raw, | ||||
|             SubGhzReadRAWStatusSaveKey, | ||||
|             furi_string_get_cstr(file_name), | ||||
|             subghz->txrx->raw_threshold_rssi); | ||||
|         subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; | ||||
|         break; | ||||
|     default: | ||||
|         subghz_read_raw_set_status(subghz->subghz_read_raw, SubGhzReadRAWStatusStart, ""); | ||||
|         subghz_read_raw_set_status( | ||||
|             subghz->subghz_read_raw, | ||||
|             SubGhzReadRAWStatusStart, | ||||
|             "", | ||||
|             subghz->txrx->raw_threshold_rssi); | ||||
|         subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; | ||||
|         break; | ||||
|     } | ||||
| @ -213,7 +223,12 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { | ||||
|                         subghz->txrx->rx_key_state = SubGhzRxKeyStateBack; | ||||
|                         scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx); | ||||
|                     } else { | ||||
|                         if(scene_manager_has_previous_scene( | ||||
|                                subghz->scene_manager, SubGhzSceneSaved) || | ||||
|                            !scene_manager_has_previous_scene( | ||||
|                                subghz->scene_manager, SubGhzSceneStart)) { | ||||
|                             DOLPHIN_DEED(DolphinDeedSubGhzSend); | ||||
|                         } | ||||
|                         // set callback end tx
 | ||||
|                         subghz_protocol_raw_file_encoder_worker_set_callback_end( | ||||
|                             (SubGhzProtocolEncoderRAW*)subghz_transmitter_get_protocol_instance( | ||||
| @ -273,7 +288,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { | ||||
|             if(subghz->txrx->rx_key_state != SubGhzRxKeyStateIDLE) { | ||||
|                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving); | ||||
|             } else { | ||||
|                 //subghz_get_preset_name(subghz, subghz->error_str);
 | ||||
|                 subghz->txrx->raw_threshold_rssi_low_count = RAW_THRESHOLD_RSSI_LOW_COUNT; | ||||
|                 if(subghz_protocol_raw_save_to_file_init( | ||||
|                        (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result, | ||||
|                        RAW_FILE_NAME, | ||||
| @ -319,7 +334,35 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { | ||||
|                 subghz->subghz_read_raw, | ||||
|                 subghz_protocol_raw_get_sample_write( | ||||
|                     (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result)); | ||||
|             subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, furi_hal_subghz_get_rssi()); | ||||
| 
 | ||||
|             float rssi = furi_hal_subghz_get_rssi(); | ||||
| 
 | ||||
|             if(subghz->txrx->raw_threshold_rssi == SUBGHZ_RAW_TRESHOLD_MIN) { | ||||
|                 subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, rssi, true); | ||||
|                 subghz_protocol_raw_save_to_file_pause( | ||||
|                     (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result, false); | ||||
|             } else { | ||||
|                 if(rssi < subghz->txrx->raw_threshold_rssi) { | ||||
|                     subghz->txrx->raw_threshold_rssi_low_count++; | ||||
|                     if(subghz->txrx->raw_threshold_rssi_low_count > RAW_THRESHOLD_RSSI_LOW_COUNT) { | ||||
|                         subghz->txrx->raw_threshold_rssi_low_count = RAW_THRESHOLD_RSSI_LOW_COUNT; | ||||
|                     } | ||||
|                     subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, rssi, false); | ||||
|                 } else { | ||||
|                     subghz->txrx->raw_threshold_rssi_low_count = 0; | ||||
|                 } | ||||
| 
 | ||||
|                 if(subghz->txrx->raw_threshold_rssi_low_count == RAW_THRESHOLD_RSSI_LOW_COUNT) { | ||||
|                     subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, rssi, false); | ||||
|                     subghz_protocol_raw_save_to_file_pause( | ||||
|                         (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result, true); | ||||
|                 } else { | ||||
|                     subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, rssi, true); | ||||
|                     subghz_protocol_raw_save_to_file_pause( | ||||
|                         (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result, false); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             break; | ||||
|         case SubGhzNotificationStateTx: | ||||
|             notification_message(subghz->notifications, &sequence_blink_magenta_10); | ||||
|  | ||||
| @ -1,5 +1,6 @@ | ||||
| #include "../subghz_i.h" | ||||
| #include "../views/receiver.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| static const NotificationSequence subghs_sequence_rx = { | ||||
|     &message_green_255, | ||||
| @ -181,6 +182,7 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { | ||||
|             subghz->txrx->idx_menu_chosen = | ||||
|                 subghz_view_receiver_get_idx_menu(subghz->subghz_receiver); | ||||
|             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverInfo); | ||||
|             DOLPHIN_DEED(DolphinDeedSubGhzReceiverInfo); | ||||
|             consumed = true; | ||||
|             break; | ||||
|         case SubGhzCustomEventViewReceiverConfig: | ||||
|  | ||||
| @ -1,10 +1,41 @@ | ||||
| #include "../subghz_i.h" | ||||
| #include <lib/toolbox/value_index.h> | ||||
| 
 | ||||
| enum SubGhzSettingIndex { | ||||
|     SubGhzSettingIndexFrequency, | ||||
|     SubGhzSettingIndexHopping, | ||||
|     SubGhzSettingIndexModulation, | ||||
|     SubGhzSettingIndexLock, | ||||
|     SubGhzSettingIndexRAWThesholdRSSI, | ||||
| }; | ||||
| 
 | ||||
| #define RAW_THRESHOLD_RSSI_COUNT 11 | ||||
| const char* const raw_theshold_rssi_text[RAW_THRESHOLD_RSSI_COUNT] = { | ||||
|     "-----", | ||||
|     "-85.0", | ||||
|     "-80.0", | ||||
|     "-75.0", | ||||
|     "-70.0", | ||||
|     "-65.0", | ||||
|     "-60.0", | ||||
|     "-55.0", | ||||
|     "-50.0", | ||||
|     "-45.0", | ||||
|     "-40.0", | ||||
| 
 | ||||
| }; | ||||
| const float raw_theshold_rssi_value[RAW_THRESHOLD_RSSI_COUNT] = { | ||||
|     -90.0f, | ||||
|     -85.0f, | ||||
|     -80.0f, | ||||
|     -75.0f, | ||||
|     -70.0f, | ||||
|     -65.0f, | ||||
|     -60.0f, | ||||
|     -55.0f, | ||||
|     -50.0f, | ||||
|     -45.0f, | ||||
|     -40.0f, | ||||
| }; | ||||
| 
 | ||||
| #define HOPPING_COUNT 2 | ||||
| @ -136,6 +167,14 @@ static void subghz_scene_receiver_config_set_hopping_running(VariableItem* item) | ||||
|     subghz->txrx->hopper_state = hopping_value[index]; | ||||
| } | ||||
| 
 | ||||
| static void subghz_scene_receiver_config_set_raw_threshold_rssi(VariableItem* item) { | ||||
|     SubGhz* subghz = variable_item_get_context(item); | ||||
|     uint8_t index = variable_item_get_current_value_index(item); | ||||
| 
 | ||||
|     variable_item_set_current_value_text(item, raw_theshold_rssi_text[index]); | ||||
|     subghz->txrx->raw_threshold_rssi = raw_theshold_rssi_value[index]; | ||||
| } | ||||
| 
 | ||||
| static void subghz_scene_receiver_config_var_list_enter_callback(void* context, uint32_t index) { | ||||
|     furi_assert(context); | ||||
|     SubGhz* subghz = context; | ||||
| @ -204,6 +243,19 @@ void subghz_scene_receiver_config_on_enter(void* context) { | ||||
|             subghz_scene_receiver_config_var_list_enter_callback, | ||||
|             subghz); | ||||
|     } | ||||
|     if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) == | ||||
|        SubGhzCustomEventManagerSet) { | ||||
|         item = variable_item_list_add( | ||||
|             subghz->variable_item_list, | ||||
|             "RSSI Threshold:", | ||||
|             RAW_THRESHOLD_RSSI_COUNT, | ||||
|             subghz_scene_receiver_config_set_raw_threshold_rssi, | ||||
|             subghz); | ||||
|         value_index = value_index_float( | ||||
|             subghz->txrx->raw_threshold_rssi, raw_theshold_rssi_value, RAW_THRESHOLD_RSSI_COUNT); | ||||
|         variable_item_set_current_value_index(item, value_index); | ||||
|         variable_item_set_current_value_text(item, raw_theshold_rssi_text[value_index]); | ||||
|     } | ||||
|     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdVariableItemList); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -1,6 +1,5 @@ | ||||
| #include "../subghz_i.h" | ||||
| #include "../helpers/subghz_custom_event.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| void subghz_scene_receiver_info_callback(GuiButtonType result, InputType type, void* context) { | ||||
|     furi_assert(context); | ||||
| @ -28,8 +27,8 @@ static bool subghz_scene_receiver_info_update_parser(void* context) { | ||||
|             subghz->txrx->decoder_result, | ||||
|             subghz_history_get_raw_data(subghz->txrx->history, subghz->txrx->idx_menu_chosen)); | ||||
| 
 | ||||
|         SubGhzPresetDefinition* preset = | ||||
|             subghz_history_get_preset_def(subghz->txrx->history, subghz->txrx->idx_menu_chosen); | ||||
|         SubGhzRadioPreset* preset = | ||||
|             subghz_history_get_radio_preset(subghz->txrx->history, subghz->txrx->idx_menu_chosen); | ||||
|         subghz_preset_init( | ||||
|             subghz, | ||||
|             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) { | ||||
|     SubGhz* subghz = context; | ||||
| 
 | ||||
|     DOLPHIN_DEED(DolphinDeedSubGhzReceiverInfo); | ||||
|     if(subghz_scene_receiver_info_update_parser(subghz)) { | ||||
|         FuriString* frequency_str; | ||||
|         FuriString* modulation_str; | ||||
|  | ||||
| @ -4,6 +4,7 @@ | ||||
| #include "../helpers/subghz_custom_event.h" | ||||
| #include <lib/subghz/protocols/raw.h> | ||||
| #include <gui/modules/validators.h> | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| #define MAX_TEXT_INPUT_LEN 22 | ||||
| 
 | ||||
| @ -131,6 +132,17 @@ bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) { | ||||
|                 } | ||||
| 
 | ||||
|                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveSuccess); | ||||
|                 if(scene_manager_has_previous_scene(subghz->scene_manager, SubGhzSceneSavedMenu)) { | ||||
|                     // Nothing, do not count editing as saving
 | ||||
|                 } else if(scene_manager_has_previous_scene( | ||||
|                               subghz->scene_manager, SubGhzSceneMoreRAW)) { | ||||
|                     // Ditto, for RAW signals
 | ||||
|                 } else if(scene_manager_has_previous_scene( | ||||
|                               subghz->scene_manager, SubGhzSceneSetType)) { | ||||
|                     DOLPHIN_DEED(DolphinDeedSubGhzAddManually); | ||||
|                 } else { | ||||
|                     DOLPHIN_DEED(DolphinDeedSubGhzSave); | ||||
|                 } | ||||
|                 return true; | ||||
|             } else { | ||||
|                 furi_string_set(subghz->error_str, "No name file"); | ||||
|  | ||||
| @ -1,7 +1,5 @@ | ||||
| #include "../subghz_i.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) { | ||||
|     SubGhz* subghz = context; | ||||
| @ -10,7 +8,6 @@ void subghz_scene_save_success_popup_callback(void* context) { | ||||
| 
 | ||||
| void subghz_scene_save_success_on_enter(void* context) { | ||||
|     SubGhz* subghz = context; | ||||
|     DOLPHIN_DEED(DolphinDeedSubGhzSave); | ||||
| 
 | ||||
|     // Setup view
 | ||||
|     Popup* popup = subghz->popup; | ||||
|  | ||||
| @ -3,10 +3,9 @@ | ||||
| #include <lib/subghz/protocols/secplus_v1.h> | ||||
| #include <lib/subghz/protocols/secplus_v2.h> | ||||
| #include <lib/subghz/blocks/math.h> | ||||
| #include <dolphin/dolphin.h> | ||||
| #include <flipper_format/flipper_format_i.h> | ||||
| #include <lib/toolbox/stream/stream.h> | ||||
| #include <lib/subghz/protocols/registry.h> | ||||
| #include <lib/subghz/protocols/protocol_items.h> | ||||
| 
 | ||||
| #define TAG "SubGhzSetType" | ||||
| 
 | ||||
| @ -381,7 +380,6 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { | ||||
| 
 | ||||
|         if(generated_protocol) { | ||||
|             subghz_file_name_clear(subghz); | ||||
|             DOLPHIN_DEED(DolphinDeedSubGhzAddManually); | ||||
|             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); | ||||
|             return true; | ||||
|         } | ||||
|  | ||||
| @ -1,4 +1,5 @@ | ||||
| #include "../subghz_i.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| enum SubmenuIndex { | ||||
|     SubmenuIndexRead = 10, | ||||
| @ -84,6 +85,7 @@ bool subghz_scene_start_on_event(void* context, SceneManagerEvent event) { | ||||
|             scene_manager_set_scene_state( | ||||
|                 subghz->scene_manager, SubGhzSceneStart, SubmenuIndexFrequencyAnalyzer); | ||||
|             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneFrequencyAnalyzer); | ||||
|             DOLPHIN_DEED(DolphinDeedSubGhzFrequencyAnalyzer); | ||||
|             return true; | ||||
|         } else if(event.event == SubmenuIndexTest) { | ||||
|             scene_manager_set_scene_state( | ||||
|  | ||||
| @ -50,7 +50,6 @@ bool subghz_scene_transmitter_update_data_show(void* context) { | ||||
| 
 | ||||
| void subghz_scene_transmitter_on_enter(void* context) { | ||||
|     SubGhz* subghz = context; | ||||
|     DOLPHIN_DEED(DolphinDeedSubGhzSend); | ||||
|     if(!subghz_scene_transmitter_update_data_show(subghz)) { | ||||
|         view_dispatcher_send_custom_event( | ||||
|             subghz->view_dispatcher, SubGhzCustomEventViewTransmitterError); | ||||
| @ -78,6 +77,7 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { | ||||
|                 } else { | ||||
|                     subghz->state_notifications = SubGhzNotificationStateTx; | ||||
|                     subghz_scene_transmitter_update_data_show(subghz); | ||||
|                     DOLPHIN_DEED(DolphinDeedSubGhzSend); | ||||
|                 } | ||||
|             } | ||||
|             return true; | ||||
|  | ||||
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