Merge branch 'release-candidate' into release
This commit is contained in:
		
						commit
						7a6720384f
					
				
							
								
								
									
										2
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
								
							| @ -113,7 +113,7 @@ jobs: | |||||||
|         run: | |         run: | | ||||||
|           echo "${{ secrets.RSYNC_DEPLOY_KEY }}" > deploy_key; |           echo "${{ secrets.RSYNC_DEPLOY_KEY }}" > deploy_key; | ||||||
|           chmod 600 ./deploy_key; |           chmod 600 ./deploy_key; | ||||||
|           rsync -avzP --mkpath \ |           rsync -avzP --delete --mkpath \ | ||||||
|               -e 'ssh -p ${{ secrets.RSYNC_DEPLOY_PORT }} -i ./deploy_key' \ |               -e 'ssh -p ${{ secrets.RSYNC_DEPLOY_PORT }} -i ./deploy_key' \ | ||||||
|               artifacts/ ${{ secrets.RSYNC_DEPLOY_USER }}@${{ secrets.RSYNC_DEPLOY_HOST }}:"${{ secrets.RSYNC_DEPLOY_BASE_PATH }}${{steps.names.outputs.artifacts-path}}/"; |               artifacts/ ${{ secrets.RSYNC_DEPLOY_USER }}@${{ secrets.RSYNC_DEPLOY_HOST }}:"${{ secrets.RSYNC_DEPLOY_BASE_PATH }}${{steps.names.outputs.artifacts-path}}/"; | ||||||
|           rm ./deploy_key; |           rm ./deploy_key; | ||||||
|  | |||||||
							
								
								
									
										4
									
								
								.vscode/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								.vscode/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,4 @@ | |||||||
|  | ./c_cpp_properties.json | ||||||
|  | ./launch.json | ||||||
|  | ./settings.json | ||||||
|  | ./tasks.json | ||||||
							
								
								
									
										17
									
								
								.vscode/ReadMe.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								.vscode/ReadMe.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | |||||||
|  | # Visual Studio Code workspace for Flipper Zero | ||||||
|  | 
 | ||||||
|  | ## Setup | ||||||
|  | 
 | ||||||
|  |  * To start developing with VSCode, run `./fbt vscode_dist` in project root. _That should only be done once_ | ||||||
|  |  * After that, open firmware folder in VSCode: "File" > "Open folder" | ||||||
|  | 
 | ||||||
|  |  For more details on fbt, see [fbt docs](../documentation/fbt.md). | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ## Workflow | ||||||
|  | 
 | ||||||
|  | Commands for building firmware are invoked through Build menu: Ctrl+Shift+B. | ||||||
|  | 
 | ||||||
|  | To attach a debugging session, first build and flash firmware, then choose your debug probe in Debug menu (Ctrl+Shift+D). | ||||||
|  | 
 | ||||||
|  | Note that you have to detach debugging session before rebuilding and re-flashing firmware. | ||||||
							
								
								
									
										32
									
								
								.vscode/example/c_cpp_properties.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								.vscode/example/c_cpp_properties.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,32 @@ | |||||||
|  | { | ||||||
|  |     "configurations": [ | ||||||
|  |         { | ||||||
|  |             "name": "Win32", | ||||||
|  |             "compilerPath": "${workspaceFolder}/toolchain/i686-windows/bin/arm-none-eabi-gcc.exe", | ||||||
|  |             "intelliSenseMode": "gcc-arm", | ||||||
|  |             "compileCommands": "${workspaceFolder}/build/latest/compile_commands.json", | ||||||
|  |             "configurationProvider": "ms-vscode.cpptools", | ||||||
|  |             "cStandard": "gnu17", | ||||||
|  |             "cppStandard": "c++17" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "name": "Linux", | ||||||
|  |             "compilerPath": "${workspaceFolder}/toolchain/x86_64-linux/bin/arm-none-eabi-gcc", | ||||||
|  |             "intelliSenseMode": "gcc-arm", | ||||||
|  |             "compileCommands": "${workspaceFolder}/build/latest/compile_commands.json", | ||||||
|  |             "configurationProvider": "ms-vscode.cpptools", | ||||||
|  |             "cStandard": "gnu17", | ||||||
|  |             "cppStandard": "c++17" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "name": "Mac", | ||||||
|  |             "compilerPath": "${workspaceFolder}/toolchain/x86_64-darwin/bin/arm-none-eabi-gcc", | ||||||
|  |             "intelliSenseMode": "gcc-arm", | ||||||
|  |             "compileCommands": "${workspaceFolder}/build/latest/compile_commands.json", | ||||||
|  |             "configurationProvider": "ms-vscode.cpptools", | ||||||
|  |             "cStandard": "gnu17", | ||||||
|  |             "cppStandard": "c++17" | ||||||
|  |         } | ||||||
|  |     ], | ||||||
|  |     "version": 4 | ||||||
|  | } | ||||||
							
								
								
									
										87
									
								
								.vscode/example/launch.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								.vscode/example/launch.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,87 @@ | |||||||
|  | { | ||||||
|  |     // Use IntelliSense to learn about possible attributes. | ||||||
|  |     // Hover to view descriptions of existing attributes. | ||||||
|  |     // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 | ||||||
|  |     "version": "0.2.0", | ||||||
|  |     "inputs": [ | ||||||
|  |         { | ||||||
|  |             "id": "BLACKMAGIC", | ||||||
|  |             "type": "command", | ||||||
|  |             "command": "shellCommand.execute", | ||||||
|  |             "args": { | ||||||
|  |                 "command": "./fbt get_blackmagic", | ||||||
|  |                 "description": "Get Blackmagic device", | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     ], | ||||||
|  |     "configurations": [ | ||||||
|  |         { | ||||||
|  |             "name": "Attach FW (ST-Link)", | ||||||
|  |             "cwd": "${workspaceFolder}", | ||||||
|  |             "executable": "./build/latest/firmware.elf", | ||||||
|  |             "request": "attach", | ||||||
|  |             "type": "cortex-debug", | ||||||
|  |             "servertype": "openocd", | ||||||
|  |             "device": "stlink", | ||||||
|  |             "svdFile": "./debug/STM32WB55_CM4.svd", | ||||||
|  |             "rtos": "FreeRTOS", | ||||||
|  |             "configFiles": [ | ||||||
|  |                 "interface/stlink.cfg", | ||||||
|  |                 "./debug/stm32wbx.cfg", | ||||||
|  |             ], | ||||||
|  |             "postAttachCommands": [ | ||||||
|  |                 // "attach 1", | ||||||
|  |                 "compare-sections", | ||||||
|  |             ] | ||||||
|  |             // "showDevDebugOutput": "raw", | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "name": "Attach FW (blackmagic)", | ||||||
|  |             "cwd": "${workspaceFolder}", | ||||||
|  |             "executable": "./build/latest/firmware.elf", | ||||||
|  |             "request": "attach", | ||||||
|  |             "type": "cortex-debug", | ||||||
|  |             "servertype": "external", | ||||||
|  |             "gdbTarget": "${input:BLACKMAGIC}", | ||||||
|  |             "svdFile": "./debug/STM32WB55_CM4.svd", | ||||||
|  |             "rtos": "FreeRTOS", | ||||||
|  |             "postAttachCommands": [ | ||||||
|  |                 "monitor swdp_scan", | ||||||
|  |                 "attach 1", | ||||||
|  |                 "set confirm off", | ||||||
|  |                 "set mem inaccessible-by-default off", | ||||||
|  |                 "compare-sections", | ||||||
|  |             ] | ||||||
|  |             // "showDevDebugOutput": "raw", | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "name": "Attach FW (JLink)", | ||||||
|  |             "cwd": "${workspaceFolder}", | ||||||
|  |             "executable": "./build/latest/firmware.elf", | ||||||
|  |             "request": "attach", | ||||||
|  |             "type": "cortex-debug", | ||||||
|  |             "servertype": "jlink", | ||||||
|  |             "interface": "swd", | ||||||
|  |             "device": "STM32WB55RG", | ||||||
|  |             "svdFile": "./debug/STM32WB55_CM4.svd", | ||||||
|  |             "rtos": "FreeRTOS", | ||||||
|  |             // "showDevDebugOutput": "raw", | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "name": "fbt debug", | ||||||
|  |             "type": "python", | ||||||
|  |             "request": "launch", | ||||||
|  |             "program": "./lib/scons/scripts/scons.py", | ||||||
|  |             "args": [ | ||||||
|  |                 "sdk" | ||||||
|  |             ] | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "name": "python debug", | ||||||
|  |             "type": "python", | ||||||
|  |             "request": "launch", | ||||||
|  |             "program": "${file}", | ||||||
|  |             "args": [] | ||||||
|  |         } | ||||||
|  |     ] | ||||||
|  | } | ||||||
							
								
								
									
										22
									
								
								.vscode/example/settings.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								.vscode/example/settings.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | |||||||
|  | { | ||||||
|  |     "C_Cpp.default.cStandard": "gnu17", | ||||||
|  |     "C_Cpp.default.cppStandard": "c++17", | ||||||
|  |     "python.formatting.provider": "black", | ||||||
|  |     "workbench.tree.indent": 12, | ||||||
|  |     "cortex-debug.enableTelemetry": false, | ||||||
|  |     "cortex-debug.variableUseNaturalFormat": true, | ||||||
|  |     "cortex-debug.showRTOS": true, | ||||||
|  |     "cortex-debug.armToolchainPath.windows": "${workspaceFolder}/toolchain/i686-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.linux": "${workspaceFolder}/toolchain/x86_64-linux/openocd/bin/openocd", | ||||||
|  |     "cortex-debug.openocdPath.osx": "${workspaceFolder}/toolchain/x86_64-darwin/openocd/bin/openocd", | ||||||
|  |     "editor.formatOnSave": true, | ||||||
|  |     "files.associations": { | ||||||
|  |         "*.scons": "python", | ||||||
|  |         "SConscript": "python", | ||||||
|  |         "SConstruct": "python", | ||||||
|  |         "*.fam": "python", | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										103
									
								
								.vscode/example/tasks.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								.vscode/example/tasks.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,103 @@ | |||||||
|  | { | ||||||
|  |     // See https://go.microsoft.com/fwlink/?LinkId=733558 | ||||||
|  |     // for the documentation about the tasks.json format | ||||||
|  |     "version": "2.0.0", | ||||||
|  |     "tasks": [ | ||||||
|  |         { | ||||||
|  |             "label": "[Release] Build", | ||||||
|  |             "group": "build", | ||||||
|  |             "type": "shell", | ||||||
|  |             "command": "./fbt COMPACT=1 DEBUG=0" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "[Debug] Build", | ||||||
|  |             "group": "build", | ||||||
|  |             "type": "shell", | ||||||
|  |             "command": "./fbt" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "[Release] Flash (ST-Link)", | ||||||
|  |             "group": "build", | ||||||
|  |             "type": "shell", | ||||||
|  |             "command": "./fbt COMPACT=1 DEBUG=0 FORCE=1 flash" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "[Debug] Flash (ST-Link)", | ||||||
|  |             "group": "build", | ||||||
|  |             "type": "shell", | ||||||
|  |             "command": "./fbt FORCE=1 flash" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "[Release] Flash (blackmagic)", | ||||||
|  |             "group": "build", | ||||||
|  |             "type": "shell", | ||||||
|  |             "command": "./fbt COMPACT=1 DEBUG=0 FORCE=1 flash_blackmagic" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "[Debug] Flash (blackmagic)", | ||||||
|  |             "group": "build", | ||||||
|  |             "type": "shell", | ||||||
|  |             "command": "./fbt FORCE=1 flash_blackmagic" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "[Release] Flash (JLink)", | ||||||
|  |             "group": "build", | ||||||
|  |             "type": "shell", | ||||||
|  |             "command": "./fbt COMPACT=1 DEBUG=0 FORCE=1 jflash" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "[Debug] Flash (JLink)", | ||||||
|  |             "group": "build", | ||||||
|  |             "type": "shell", | ||||||
|  |             "command": "./fbt FORCE=1 jflash" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "[Release] Build update bundle", | ||||||
|  |             "group": "build", | ||||||
|  |             "type": "shell", | ||||||
|  |             "command": "./fbt updater_package COMPACT=1 DEBUG=0" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "[Debug] Build update bundle", | ||||||
|  |             "group": "build", | ||||||
|  |             "type": "shell", | ||||||
|  |             "command": "./fbt updater_package" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "[Release] Build updater", | ||||||
|  |             "group": "build", | ||||||
|  |             "type": "shell", | ||||||
|  |             "command": "./fbt updater_all COMPACT=1 DEBUG=0" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "[Debug] Build updater", | ||||||
|  |             "group": "build", | ||||||
|  |             "type": "shell", | ||||||
|  |             "command": "./fbt updater_all" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "[Debug] Flash (USB, w/o resources)", | ||||||
|  |             "group": "build", | ||||||
|  |             "type": "shell", | ||||||
|  |             "command": "./fbt FORCE=1 flash_usb" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "[Release] Flash (USB, w/o resources)", | ||||||
|  |             "group": "build", | ||||||
|  |             "type": "shell", | ||||||
|  |             "command": "./fbt COMPACT=1 DEBUG=0 FORCE=1 flash_usb" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "[Debug:unit_tests] Flash (USB)", | ||||||
|  |             "group": "build", | ||||||
|  |             "type": "shell", | ||||||
|  |             "command": "./fbt FIRMWARE_APP_SET=unit_tests FORCE=1 flash_usb" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "[Release] Flash (USB, with resources)", | ||||||
|  |             "group": "build", | ||||||
|  |             "type": "shell", | ||||||
|  |             "command": "./fbt COMPACT=1 DEBUG=0 FORCE=1 flash_usb_full" | ||||||
|  |         }, | ||||||
|  |     ] | ||||||
|  | } | ||||||
							
								
								
									
										15
									
								
								.vscode/extensions.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								.vscode/extensions.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | |||||||
|  | { | ||||||
|  | 	// See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. | ||||||
|  | 	// Extension identifier format: ${publisher}.${name}. Example: vscode.csharp | ||||||
|  | 	// List of extensions which should be recommended for users of this workspace. | ||||||
|  | 	"recommendations": [ | ||||||
|  | 		"ms-python.black-formatter", | ||||||
|  | 		"ms-vscode.cpptools", | ||||||
|  | 		"amiralizadeh9480.cpp-helper", | ||||||
|  | 		"marus25.cortex-debug", | ||||||
|  | 		"zxh404.vscode-proto3", | ||||||
|  | 		"augustocdias.tasks-shell-input" | ||||||
|  | 	], | ||||||
|  | 	// List of extensions recommended by VS Code that should not be recommended for users of this workspace. | ||||||
|  | 	"unwantedRecommendations": [] | ||||||
|  | } | ||||||
| @ -274,8 +274,13 @@ distenv.PhonyTarget("cli", "${PYTHON3} scripts/serial_cli.py") | |||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # Find blackmagic probe | # Find blackmagic probe | ||||||
| 
 |  | ||||||
| distenv.PhonyTarget( | distenv.PhonyTarget( | ||||||
|     "get_blackmagic", |     "get_blackmagic", | ||||||
|     "@echo $( ${BLACKMAGIC_ADDR} $)", |     "@echo $( ${BLACKMAGIC_ADDR} $)", | ||||||
| ) | ) | ||||||
|  | 
 | ||||||
|  | # Prepare vscode environment | ||||||
|  | vscode_dist = distenv.Install("#.vscode", distenv.Glob("#.vscode/example/*")) | ||||||
|  | distenv.Precious(vscode_dist) | ||||||
|  | distenv.NoClean(vscode_dist) | ||||||
|  | distenv.Alias("vscode_dist", vscode_dist) | ||||||
|  | |||||||
| @ -5,6 +5,7 @@ | |||||||
| #include <gui/modules/empty_screen.h> | #include <gui/modules/empty_screen.h> | ||||||
| #include <m-string.h> | #include <m-string.h> | ||||||
| #include <furi_hal_version.h> | #include <furi_hal_version.h> | ||||||
|  | #include <furi_hal_region.h> | ||||||
| #include <furi_hal_bt.h> | #include <furi_hal_bt.h> | ||||||
| 
 | 
 | ||||||
| typedef DialogMessageButton (*AboutDialogScreen)(DialogsApp* dialogs, DialogMessage* message); | typedef DialogMessageButton (*AboutDialogScreen)(DialogsApp* dialogs, DialogMessage* message); | ||||||
| @ -45,7 +46,7 @@ static DialogMessageButton compliance_screen(DialogsApp* dialogs, DialogMessage* | |||||||
|     DialogMessageButton result; |     DialogMessageButton result; | ||||||
| 
 | 
 | ||||||
|     const char* screen_text = "For all compliance\n" |     const char* screen_text = "For all compliance\n" | ||||||
|                               "certificates please visit\n" |                               "certificates please visit:\n" | ||||||
|                               "www.flipp.dev/compliance"; |                               "www.flipp.dev/compliance"; | ||||||
| 
 | 
 | ||||||
|     dialog_message_set_text(message, screen_text, 0, 0, AlignLeft, AlignTop); |     dialog_message_set_text(message, screen_text, 0, 0, AlignLeft, AlignTop); | ||||||
| @ -83,21 +84,22 @@ static DialogMessageButton hw_version_screen(DialogsApp* dialogs, DialogMessage* | |||||||
| 
 | 
 | ||||||
|     string_cat_printf( |     string_cat_printf( | ||||||
|         buffer, |         buffer, | ||||||
|         "%d.F%dB%dC%d %s %s\n", |         "%d.F%dB%dC%d %s:%s %s\n", | ||||||
|         furi_hal_version_get_hw_version(), |         furi_hal_version_get_hw_version(), | ||||||
|         furi_hal_version_get_hw_target(), |         furi_hal_version_get_hw_target(), | ||||||
|         furi_hal_version_get_hw_body(), |         furi_hal_version_get_hw_body(), | ||||||
|         furi_hal_version_get_hw_connect(), |         furi_hal_version_get_hw_connect(), | ||||||
|         furi_hal_version_get_hw_region_name(), |         furi_hal_version_get_hw_region_name(), | ||||||
|  |         furi_hal_region_get_name(), | ||||||
|         my_name ? my_name : "Unknown"); |         my_name ? my_name : "Unknown"); | ||||||
| 
 | 
 | ||||||
|     string_cat_printf(buffer, "Serial number:\n"); |     string_cat_printf(buffer, "Serial Number:\n"); | ||||||
|     const uint8_t* uid = furi_hal_version_uid(); |     const uint8_t* uid = furi_hal_version_uid(); | ||||||
|     for(size_t i = 0; i < furi_hal_version_uid_size(); i++) { |     for(size_t i = 0; i < furi_hal_version_uid_size(); i++) { | ||||||
|         string_cat_printf(buffer, "%02X", uid[i]); |         string_cat_printf(buffer, "%02X", uid[i]); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     dialog_message_set_header(message, "HW Version info:", 0, 0, AlignLeft, AlignTop); |     dialog_message_set_header(message, "HW Version Info:", 0, 0, AlignLeft, AlignTop); | ||||||
|     dialog_message_set_text(message, string_get_cstr(buffer), 0, 13, AlignLeft, AlignTop); |     dialog_message_set_text(message, string_get_cstr(buffer), 0, 13, AlignLeft, AlignTop); | ||||||
|     result = dialog_message_show(dialogs, message); |     result = dialog_message_show(dialogs, message); | ||||||
|     dialog_message_set_text(message, NULL, 0, 0, AlignLeft, AlignTop); |     dialog_message_set_text(message, NULL, 0, 0, AlignLeft, AlignTop); | ||||||
| @ -133,7 +135,7 @@ static DialogMessageButton fw_version_screen(DialogsApp* dialogs, DialogMessage* | |||||||
|             version_get_gitbranch(ver)); |             version_get_gitbranch(ver)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     dialog_message_set_header(message, "FW Version info:", 0, 0, AlignLeft, AlignTop); |     dialog_message_set_header(message, "FW Version Info:", 0, 0, AlignLeft, AlignTop); | ||||||
|     dialog_message_set_text(message, string_get_cstr(buffer), 0, 13, AlignLeft, AlignTop); |     dialog_message_set_text(message, string_get_cstr(buffer), 0, 13, AlignLeft, AlignTop); | ||||||
|     result = dialog_message_show(dialogs, message); |     result = dialog_message_show(dialogs, message); | ||||||
|     dialog_message_set_text(message, NULL, 0, 0, AlignLeft, AlignTop); |     dialog_message_set_text(message, NULL, 0, 0, AlignLeft, AlignTop); | ||||||
|  | |||||||
| @ -32,14 +32,14 @@ void AccessorApp::run(void) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| AccessorApp::AccessorApp() { | AccessorApp::AccessorApp() { | ||||||
|     notification = static_cast<NotificationApp*>(furi_record_open("notification")); |     notification = static_cast<NotificationApp*>(furi_record_open(RECORD_NOTIFICATION)); | ||||||
|     onewire_host = onewire_host_alloc(); |     onewire_host = onewire_host_alloc(); | ||||||
|     furi_hal_power_enable_otg(); |     furi_hal_power_enable_otg(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| AccessorApp::~AccessorApp() { | AccessorApp::~AccessorApp() { | ||||||
|     furi_hal_power_disable_otg(); |     furi_hal_power_disable_otg(); | ||||||
|     furi_record_close("notification"); |     furi_record_close(RECORD_NOTIFICATION); | ||||||
|     onewire_host_free(onewire_host); |     onewire_host_free(onewire_host); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -15,7 +15,7 @@ AccessorAppViewManager::AccessorAppViewManager() { | |||||||
|     popup = popup_alloc(); |     popup = popup_alloc(); | ||||||
|     add_view(ViewType::Popup, popup_get_view(popup)); |     add_view(ViewType::Popup, popup_get_view(popup)); | ||||||
| 
 | 
 | ||||||
|     gui = static_cast<Gui*>(furi_record_open("gui")); |     gui = static_cast<Gui*>(furi_record_open(RECORD_GUI)); | ||||||
|     view_dispatcher_attach_to_gui(view_dispatcher, gui, ViewDispatcherTypeFullscreen); |     view_dispatcher_attach_to_gui(view_dispatcher, gui, ViewDispatcherTypeFullscreen); | ||||||
| 
 | 
 | ||||||
|     // set previous view callback for all views
 |     // set previous view callback for all views
 | ||||||
| @ -31,6 +31,7 @@ AccessorAppViewManager::~AccessorAppViewManager() { | |||||||
|         view_dispatcher, static_cast<uint32_t>(AccessorAppViewManager::ViewType::Popup)); |         view_dispatcher, static_cast<uint32_t>(AccessorAppViewManager::ViewType::Popup)); | ||||||
| 
 | 
 | ||||||
|     // free view modules
 |     // free view modules
 | ||||||
|  |     furi_record_close(RECORD_GUI); | ||||||
|     submenu_free(submenu); |     submenu_free(submenu); | ||||||
|     popup_free(popup); |     popup_free(popup); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -18,6 +18,8 @@ typedef struct { | |||||||
| 
 | 
 | ||||||
| typedef void (*FlipperOnStartHook)(void); | typedef void (*FlipperOnStartHook)(void); | ||||||
| 
 | 
 | ||||||
|  | extern const char* FLIPPER_AUTORUN_APP_NAME; | ||||||
|  | 
 | ||||||
| /* Services list
 | /* Services list
 | ||||||
|  * Spawned on startup |  * Spawned on startup | ||||||
|  */ |  */ | ||||||
|  | |||||||
| @ -64,7 +64,7 @@ uint16_t archive_favorites_count(void* context) { | |||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
|             if(!string_size(buffer)) { |             if(!string_size(buffer)) { | ||||||
|                 break; |                 continue; // Skip empty lines
 | ||||||
|             } |             } | ||||||
|             ++lines; |             ++lines; | ||||||
|         } |         } | ||||||
| @ -93,7 +93,7 @@ static bool archive_favourites_rescan() { | |||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
|             if(!string_size(buffer)) { |             if(!string_size(buffer)) { | ||||||
|                 break; |                 continue; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             if(string_search(buffer, "/app:") == 0) { |             if(string_search(buffer, "/app:") == 0) { | ||||||
| @ -152,7 +152,7 @@ bool archive_favorites_read(void* context) { | |||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
|             if(!string_size(buffer)) { |             if(!string_size(buffer)) { | ||||||
|                 break; |                 continue; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             if(string_search(buffer, "/app:") == 0) { |             if(string_search(buffer, "/app:") == 0) { | ||||||
| @ -215,7 +215,7 @@ bool archive_favorites_delete(const char* format, ...) { | |||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
|             if(!string_size(buffer)) { |             if(!string_size(buffer)) { | ||||||
|                 break; |                 continue; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             if(string_search(buffer, filename)) { |             if(string_search(buffer, filename)) { | ||||||
| @ -259,7 +259,7 @@ bool archive_is_favorite(const char* format, ...) { | |||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
|             if(!string_size(buffer)) { |             if(!string_size(buffer)) { | ||||||
|                 break; |                 continue; | ||||||
|             } |             } | ||||||
|             if(!string_search(buffer, filename)) { |             if(!string_search(buffer, filename)) { | ||||||
|                 found = true; |                 found = true; | ||||||
| @ -299,7 +299,7 @@ bool archive_favorites_rename(const char* src, const char* dst) { | |||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
|             if(!string_size(buffer)) { |             if(!string_size(buffer)) { | ||||||
|                 break; |                 continue; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             archive_file_append( |             archive_file_append( | ||||||
|  | |||||||
| @ -92,8 +92,6 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) { | |||||||
|     ArchiveBrowserView* browser = archive->browser; |     ArchiveBrowserView* browser = archive->browser; | ||||||
|     ArchiveFile_t* selected = archive_get_current_file(browser); |     ArchiveFile_t* selected = archive_get_current_file(browser); | ||||||
| 
 | 
 | ||||||
|     const char* name = archive_get_name(browser); |  | ||||||
|     bool known_app = archive_is_known_app(selected->type); |  | ||||||
|     bool favorites = archive_get_tab(browser) == ArchiveTabFavorites; |     bool favorites = archive_get_tab(browser) == ArchiveTabFavorites; | ||||||
|     bool consumed = false; |     bool consumed = false; | ||||||
| 
 | 
 | ||||||
| @ -108,18 +106,19 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) { | |||||||
|             consumed = true; |             consumed = true; | ||||||
|             break; |             break; | ||||||
|         case ArchiveBrowserEventFileMenuRun: |         case ArchiveBrowserEventFileMenuRun: | ||||||
|             if(known_app) { |             if(archive_is_known_app(selected->type)) { | ||||||
|                 archive_run_in_app(browser, selected); |                 archive_run_in_app(browser, selected); | ||||||
|                 archive_show_file_menu(browser, false); |                 archive_show_file_menu(browser, false); | ||||||
|             } |             } | ||||||
|             consumed = true; |             consumed = true; | ||||||
|             break; |             break; | ||||||
|         case ArchiveBrowserEventFileMenuPin: |         case ArchiveBrowserEventFileMenuPin: { | ||||||
|  |             const char* name = archive_get_name(browser); | ||||||
|             if(favorites) { |             if(favorites) { | ||||||
|                 archive_favorites_delete(name); |                 archive_favorites_delete(name); | ||||||
|                 archive_file_array_rm_selected(browser); |                 archive_file_array_rm_selected(browser); | ||||||
|                 archive_show_file_menu(browser, false); |                 archive_show_file_menu(browser, false); | ||||||
|             } else if(known_app) { |             } else if(archive_is_known_app(selected->type)) { | ||||||
|                 if(archive_is_favorite("%s", name)) { |                 if(archive_is_favorite("%s", name)) { | ||||||
|                     archive_favorites_delete("%s", name); |                     archive_favorites_delete("%s", name); | ||||||
|                 } else { |                 } else { | ||||||
| @ -128,12 +127,12 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) { | |||||||
|                 archive_show_file_menu(browser, false); |                 archive_show_file_menu(browser, false); | ||||||
|             } |             } | ||||||
|             consumed = true; |             consumed = true; | ||||||
|             break; |         } break; | ||||||
| 
 | 
 | ||||||
|         case ArchiveBrowserEventFileMenuRename: |         case ArchiveBrowserEventFileMenuRename: | ||||||
|             if(favorites) { |             if(favorites) { | ||||||
|                 browser->callback(ArchiveBrowserEventEnterFavMove, browser->context); |                 browser->callback(ArchiveBrowserEventEnterFavMove, browser->context); | ||||||
|             } else if((known_app) && (selected->is_app == false)) { |             } else if((archive_is_known_app(selected->type)) && (selected->is_app == false)) { | ||||||
|                 archive_show_file_menu(browser, false); |                 archive_show_file_menu(browser, false); | ||||||
|                 scene_manager_set_scene_state( |                 scene_manager_set_scene_state( | ||||||
|                     archive->scene_manager, ArchiveAppSceneBrowser, SCENE_STATE_NEED_REFRESH); |                     archive->scene_manager, ArchiveAppSceneBrowser, SCENE_STATE_NEED_REFRESH); | ||||||
|  | |||||||
| @ -37,7 +37,7 @@ void archive_scene_rename_on_enter(void* context) { | |||||||
|         false); |         false); | ||||||
| 
 | 
 | ||||||
|     ValidatorIsFile* validator_is_file = validator_is_file_alloc_init( |     ValidatorIsFile* validator_is_file = validator_is_file_alloc_init( | ||||||
|         string_get_cstr(archive->browser->path), archive->file_extension, NULL); |         string_get_cstr(archive->browser->path), archive->file_extension, ""); | ||||||
|     text_input_set_validator(text_input, validator_is_file_callback, validator_is_file); |     text_input_set_validator(text_input, validator_is_file_callback, validator_is_file); | ||||||
| 
 | 
 | ||||||
|     string_clear(filename); |     string_clear(filename); | ||||||
|  | |||||||
| @ -28,7 +28,7 @@ BadUsbApp* bad_usb_app_alloc(char* arg) { | |||||||
| 
 | 
 | ||||||
|     string_init(app->file_path); |     string_init(app->file_path); | ||||||
| 
 | 
 | ||||||
|     if(arg != NULL) { |     if(arg && strlen(arg)) { | ||||||
|         string_set_str(app->file_path, arg); |         string_set_str(app->file_path, arg); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -79,7 +79,6 @@ void bad_usb_app_free(BadUsbApp* app) { | |||||||
|     furi_assert(app); |     furi_assert(app); | ||||||
| 
 | 
 | ||||||
|     // Views
 |     // Views
 | ||||||
|     view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewFileSelect); |  | ||||||
|     view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewWork); |     view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewWork); | ||||||
|     bad_usb_free(app->bad_usb_view); |     bad_usb_free(app->bad_usb_view); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -38,6 +38,5 @@ struct BadUsbApp { | |||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     BadUsbAppViewError, |     BadUsbAppViewError, | ||||||
|     BadUsbAppViewFileSelect, |  | ||||||
|     BadUsbAppViewWork, |     BadUsbAppViewWork, | ||||||
| } BadUsbAppView; | } BadUsbAppView; | ||||||
|  | |||||||
| @ -90,7 +90,7 @@ BtHid* bt_hid_app_alloc() { | |||||||
|     submenu_add_item( |     submenu_add_item( | ||||||
|         app->submenu, "Keyboard", BtHidSubmenuIndexKeyboard, bt_hid_submenu_callback, app); |         app->submenu, "Keyboard", BtHidSubmenuIndexKeyboard, bt_hid_submenu_callback, app); | ||||||
|     submenu_add_item( |     submenu_add_item( | ||||||
|         app->submenu, "Media player", BtHidSubmenuIndexMedia, bt_hid_submenu_callback, app); |         app->submenu, "Media Player", BtHidSubmenuIndexMedia, bt_hid_submenu_callback, app); | ||||||
|     submenu_add_item(app->submenu, "Mouse", BtHidSubmenuIndexMouse, bt_hid_submenu_callback, app); |     submenu_add_item(app->submenu, "Mouse", BtHidSubmenuIndexMouse, bt_hid_submenu_callback, app); | ||||||
|     view_set_previous_callback(submenu_get_view(app->submenu), bt_hid_exit); |     view_set_previous_callback(submenu_get_view(app->submenu), bt_hid_exit); | ||||||
|     view_dispatcher_add_view( |     view_dispatcher_add_view( | ||||||
| @ -103,7 +103,7 @@ BtHid* bt_hid_app_alloc() { | |||||||
|     dialog_ex_set_left_button_text(app->dialog, "Exit"); |     dialog_ex_set_left_button_text(app->dialog, "Exit"); | ||||||
|     dialog_ex_set_right_button_text(app->dialog, "Stay"); |     dialog_ex_set_right_button_text(app->dialog, "Stay"); | ||||||
|     dialog_ex_set_center_button_text(app->dialog, "Menu"); |     dialog_ex_set_center_button_text(app->dialog, "Menu"); | ||||||
|     dialog_ex_set_header(app->dialog, "Close current app?", 16, 12, AlignLeft, AlignTop); |     dialog_ex_set_header(app->dialog, "Close Current App?", 16, 12, AlignLeft, AlignTop); | ||||||
|     view_dispatcher_add_view( |     view_dispatcher_add_view( | ||||||
|         app->view_dispatcher, BtHidViewExitConfirm, dialog_ex_get_view(app->dialog)); |         app->view_dispatcher, BtHidViewExitConfirm, dialog_ex_get_view(app->dialog)); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -347,7 +347,8 @@ static void bt_close_connection(Bt* bt) { | |||||||
|     furi_event_flag_set(bt->api_event, BT_API_UNLOCK_EVENT); |     furi_event_flag_set(bt->api_event, BT_API_UNLOCK_EVENT); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int32_t bt_srv() { | int32_t bt_srv(void* p) { | ||||||
|  |     UNUSED(p); | ||||||
|     Bt* bt = bt_alloc(); |     Bt* bt = bt_alloc(); | ||||||
| 
 | 
 | ||||||
|     if(furi_hal_rtc_get_boot_mode() != FuriHalRtcBootModeNormal) { |     if(furi_hal_rtc_get_boot_mode() != FuriHalRtcBootModeNormal) { | ||||||
|  | |||||||
| @ -10,9 +10,9 @@ void bt_settings_scene_forget_dev_confirm_dialog_callback(DialogExResult result, | |||||||
| void bt_settings_scene_forget_dev_confirm_on_enter(void* context) { | void bt_settings_scene_forget_dev_confirm_on_enter(void* context) { | ||||||
|     BtSettingsApp* app = context; |     BtSettingsApp* app = context; | ||||||
|     DialogEx* dialog = app->dialog; |     DialogEx* dialog = app->dialog; | ||||||
|     dialog_ex_set_header(dialog, "Unpair all devices?", 64, 3, AlignCenter, AlignTop); |     dialog_ex_set_header(dialog, "Unpair All Devices?", 64, 3, AlignCenter, AlignTop); | ||||||
|     dialog_ex_set_text( |     dialog_ex_set_text( | ||||||
|         dialog, "All previous pairings\nwill be lost.", 64, 22, AlignCenter, AlignTop); |         dialog, "All previous pairings\nwill be lost!", 64, 22, AlignCenter, AlignTop); | ||||||
|     dialog_ex_set_left_button_text(dialog, "Back"); |     dialog_ex_set_left_button_text(dialog, "Back"); | ||||||
|     dialog_ex_set_right_button_text(dialog, "Unpair"); |     dialog_ex_set_right_button_text(dialog, "Unpair"); | ||||||
|     dialog_ex_set_context(dialog, app); |     dialog_ex_set_context(dialog, app); | ||||||
|  | |||||||
| @ -439,9 +439,9 @@ void cli_session_open(Cli* cli, void* session) { | |||||||
|     cli->session = session; |     cli->session = session; | ||||||
|     if(cli->session != NULL) { |     if(cli->session != NULL) { | ||||||
|         cli->session->init(); |         cli->session->init(); | ||||||
|         furi_stdglue_set_thread_stdout_callback(cli->session->tx_stdout); |         furi_thread_set_stdout_callback(cli->session->tx_stdout); | ||||||
|     } else { |     } else { | ||||||
|         furi_stdglue_set_thread_stdout_callback(NULL); |         furi_thread_set_stdout_callback(NULL); | ||||||
|     } |     } | ||||||
|     furi_semaphore_release(cli->idle_sem); |     furi_semaphore_release(cli->idle_sem); | ||||||
|     furi_check(furi_mutex_release(cli->mutex) == FuriStatusOk); |     furi_check(furi_mutex_release(cli->mutex) == FuriStatusOk); | ||||||
| @ -455,7 +455,7 @@ void cli_session_close(Cli* cli) { | |||||||
|         cli->session->deinit(); |         cli->session->deinit(); | ||||||
|     } |     } | ||||||
|     cli->session = NULL; |     cli->session = NULL; | ||||||
|     furi_stdglue_set_thread_stdout_callback(NULL); |     furi_thread_set_stdout_callback(NULL); | ||||||
|     furi_check(furi_mutex_release(cli->mutex) == FuriStatusOk); |     furi_check(furi_mutex_release(cli->mutex) == FuriStatusOk); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -469,9 +469,9 @@ int32_t cli_srv(void* p) { | |||||||
|     furi_record_create(RECORD_CLI, cli); |     furi_record_create(RECORD_CLI, cli); | ||||||
| 
 | 
 | ||||||
|     if(cli->session != NULL) { |     if(cli->session != NULL) { | ||||||
|         furi_stdglue_set_thread_stdout_callback(cli->session->tx_stdout); |         furi_thread_set_stdout_callback(cli->session->tx_stdout); | ||||||
|     } else { |     } else { | ||||||
|         furi_stdglue_set_thread_stdout_callback(NULL); |         furi_thread_set_stdout_callback(NULL); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if(furi_hal_rtc_get_boot_mode() == FuriHalRtcBootModeNormal) { |     if(furi_hal_rtc_get_boot_mode() == FuriHalRtcBootModeNormal) { | ||||||
|  | |||||||
| @ -15,7 +15,7 @@ | |||||||
| void cli_command_device_info_callback(const char* key, const char* value, bool last, void* context) { | void cli_command_device_info_callback(const char* key, const char* value, bool last, void* context) { | ||||||
|     UNUSED(context); |     UNUSED(context); | ||||||
|     UNUSED(last); |     UNUSED(last); | ||||||
|     printf("%-24s: %s\r\n", key, value); |     printf("%-30s: %s\r\n", key, value); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* 
 | /* 
 | ||||||
|  | |||||||
| @ -25,7 +25,7 @@ struct CliSession { | |||||||
|     void (*deinit)(void); |     void (*deinit)(void); | ||||||
|     size_t (*rx)(uint8_t* buffer, size_t size, uint32_t timeout); |     size_t (*rx)(uint8_t* buffer, size_t size, uint32_t timeout); | ||||||
|     void (*tx)(const uint8_t* buffer, size_t size); |     void (*tx)(const uint8_t* buffer, size_t size); | ||||||
|     void (*tx_stdout)(void* _cookie, const char* data, size_t size); |     void (*tx_stdout)(const char* data, size_t size); | ||||||
|     bool (*is_connected)(void); |     bool (*is_connected)(void); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -277,8 +277,7 @@ static void cli_vcp_tx(const uint8_t* buffer, size_t size) { | |||||||
| #endif | #endif | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void cli_vcp_tx_stdout(void* _cookie, const char* data, size_t size) { | static void cli_vcp_tx_stdout(const char* data, size_t size) { | ||||||
|     UNUSED(_cookie); |  | ||||||
|     cli_vcp_tx((const uint8_t*)data, size); |     cli_vcp_tx((const uint8_t*)data, size); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -26,11 +26,11 @@ static void keypad_test_render_callback(Canvas* canvas, void* ctx) { | |||||||
|     canvas_clear(canvas); |     canvas_clear(canvas); | ||||||
|     char strings[5][20]; |     char strings[5][20]; | ||||||
| 
 | 
 | ||||||
|     sprintf(strings[0], "Ok: %d", state->ok); |     snprintf(strings[0], 20, "Ok: %d", state->ok); | ||||||
|     sprintf(strings[1], "L: %d", state->left); |     snprintf(strings[1], 20, "L: %d", state->left); | ||||||
|     sprintf(strings[2], "R: %d", state->right); |     snprintf(strings[2], 20, "R: %d", state->right); | ||||||
|     sprintf(strings[3], "U: %d", state->up); |     snprintf(strings[3], 20, "U: %d", state->up); | ||||||
|     sprintf(strings[4], "D: %d", state->down); |     snprintf(strings[4], 20, "D: %d", state->down); | ||||||
| 
 | 
 | ||||||
|     canvas_set_font(canvas, FontPrimary); |     canvas_set_font(canvas, FontPrimary); | ||||||
|     canvas_draw_str(canvas, 0, 10, "Keypad test"); |     canvas_draw_str(canvas, 0, 10, "Keypad test"); | ||||||
|  | |||||||
| @ -143,7 +143,7 @@ static void bubble_animation_activate(BubbleAnimationView* view, bool force) { | |||||||
|     furi_assert(view); |     furi_assert(view); | ||||||
|     bool activate = true; |     bool activate = true; | ||||||
|     BubbleAnimationViewModel* model = view_get_model(view->view); |     BubbleAnimationViewModel* model = view_get_model(view->view); | ||||||
|     if(!model->current) { |     if(model->current == NULL) { | ||||||
|         activate = false; |         activate = false; | ||||||
|     } else if(model->freeze_frame) { |     } else if(model->freeze_frame) { | ||||||
|         activate = false; |         activate = false; | ||||||
| @ -151,6 +151,7 @@ static void bubble_animation_activate(BubbleAnimationView* view, bool force) { | |||||||
|         activate = false; |         activate = false; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     if(model->current != NULL) { | ||||||
|         if(!force) { |         if(!force) { | ||||||
|             if((model->active_ended_at + model->current->active_cooldown * 1000) > |             if((model->active_ended_at + model->current->active_cooldown * 1000) > | ||||||
|                xTaskGetTickCount()) { |                xTaskGetTickCount()) { | ||||||
| @ -161,6 +162,7 @@ static void bubble_animation_activate(BubbleAnimationView* view, bool force) { | |||||||
|                 activate = false; |                 activate = false; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |     } | ||||||
|     view_commit_model(view->view, false); |     view_commit_model(view->view, false); | ||||||
| 
 | 
 | ||||||
|     if(!activate && !force) { |     if(!activate && !force) { | ||||||
| @ -288,7 +290,10 @@ static void bubble_animation_enter(void* context) { | |||||||
|     bubble_animation_activate(view, false); |     bubble_animation_activate(view, false); | ||||||
| 
 | 
 | ||||||
|     BubbleAnimationViewModel* model = view_get_model(view->view); |     BubbleAnimationViewModel* model = view_get_model(view->view); | ||||||
|     uint8_t frame_rate = model->current->icon_animation.frame_rate; |     uint8_t frame_rate = 0; | ||||||
|  |     if(model->current != NULL) { | ||||||
|  |         frame_rate = model->current->icon_animation.frame_rate; | ||||||
|  |     } | ||||||
|     view_commit_model(view->view, false); |     view_commit_model(view->view, false); | ||||||
| 
 | 
 | ||||||
|     if(frame_rate) { |     if(frame_rate) { | ||||||
|  | |||||||
| @ -90,7 +90,7 @@ void desktop_settings_app_free(DesktopSettingsApp* app) { | |||||||
| extern int32_t desktop_settings_app(void* p) { | extern int32_t desktop_settings_app(void* p) { | ||||||
|     DesktopSettingsApp* app = desktop_settings_app_alloc(); |     DesktopSettingsApp* app = desktop_settings_app_alloc(); | ||||||
|     LOAD_DESKTOP_SETTINGS(&app->settings); |     LOAD_DESKTOP_SETTINGS(&app->settings); | ||||||
|     if(!strcmp(p, DESKTOP_SETTINGS_RUN_PIN_SETUP_ARG)) { |     if(p && (strcmp(p, DESKTOP_SETTINGS_RUN_PIN_SETUP_ARG) == 0)) { | ||||||
|         scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinSetupHowto); |         scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinSetupHowto); | ||||||
|     } else { |     } else { | ||||||
|         scene_manager_next_scene(app->scene_manager, DesktopSettingsAppSceneStart); |         scene_manager_next_scene(app->scene_manager, DesktopSettingsAppSceneStart); | ||||||
|  | |||||||
| @ -23,7 +23,7 @@ void desktop_debug_render(Canvas* canvas, void* model) { | |||||||
|     const Version* ver; |     const Version* ver; | ||||||
|     char buffer[64]; |     char buffer[64]; | ||||||
| 
 | 
 | ||||||
|     static const char* headers[] = {"FW Version info:", "Dolphin info:"}; |     static const char* headers[] = {"FW Version Info:", "Dolphin Info:"}; | ||||||
| 
 | 
 | ||||||
|     canvas_set_color(canvas, ColorBlack); |     canvas_set_color(canvas, ColorBlack); | ||||||
|     canvas_set_font(canvas, FontPrimary); |     canvas_set_font(canvas, FontPrimary); | ||||||
| @ -36,12 +36,13 @@ void desktop_debug_render(Canvas* canvas, void* model) { | |||||||
|         snprintf( |         snprintf( | ||||||
|             buffer, |             buffer, | ||||||
|             sizeof(buffer), |             sizeof(buffer), | ||||||
|             "%d.F%dB%dC%d %s %s", |             "%d.F%dB%dC%d %s:%s %s", | ||||||
|             furi_hal_version_get_hw_version(), |             furi_hal_version_get_hw_version(), | ||||||
|             furi_hal_version_get_hw_target(), |             furi_hal_version_get_hw_target(), | ||||||
|             furi_hal_version_get_hw_body(), |             furi_hal_version_get_hw_body(), | ||||||
|             furi_hal_version_get_hw_connect(), |             furi_hal_version_get_hw_connect(), | ||||||
|             furi_hal_version_get_hw_region_name(), |             furi_hal_version_get_hw_region_name(), | ||||||
|  |             furi_hal_region_get_name(), | ||||||
|             my_name ? my_name : "Unknown"); |             my_name ? my_name : "Unknown"); | ||||||
|         canvas_draw_str(canvas, 5, 19 + STATUS_BAR_Y_SHIFT, buffer); |         canvas_draw_str(canvas, 5, 19 + STATUS_BAR_Y_SHIFT, buffer); | ||||||
| 
 | 
 | ||||||
| @ -78,7 +79,6 @@ void desktop_debug_render(Canvas* canvas, void* model) { | |||||||
|         canvas_draw_str(canvas, 5, 50 + STATUS_BAR_Y_SHIFT, buffer); |         canvas_draw_str(canvas, 5, 50 + STATUS_BAR_Y_SHIFT, buffer); | ||||||
| 
 | 
 | ||||||
|     } else { |     } else { | ||||||
|         char buffer[64]; |  | ||||||
|         Dolphin* dolphin = furi_record_open(RECORD_DOLPHIN); |         Dolphin* dolphin = furi_record_open(RECORD_DOLPHIN); | ||||||
|         DolphinStats stats = dolphin_stats(dolphin); |         DolphinStats stats = dolphin_stats(dolphin); | ||||||
|         furi_record_close(RECORD_DOLPHIN); |         furi_record_close(RECORD_DOLPHIN); | ||||||
| @ -87,18 +87,20 @@ void desktop_debug_render(Canvas* canvas, void* model) { | |||||||
|         uint32_t remaining = dolphin_state_xp_to_levelup(m->icounter); |         uint32_t remaining = dolphin_state_xp_to_levelup(m->icounter); | ||||||
| 
 | 
 | ||||||
|         canvas_set_font(canvas, FontSecondary); |         canvas_set_font(canvas, FontSecondary); | ||||||
|         snprintf(buffer, 64, "Icounter: %ld  Butthurt %ld", m->icounter, m->butthurt); |         snprintf(buffer, sizeof(buffer), "Icounter: %ld  Butthurt %ld", m->icounter, m->butthurt); | ||||||
|         canvas_draw_str(canvas, 5, 19 + STATUS_BAR_Y_SHIFT, buffer); |         canvas_draw_str(canvas, 5, 19 + STATUS_BAR_Y_SHIFT, buffer); | ||||||
| 
 | 
 | ||||||
|         snprintf( |         snprintf( | ||||||
|             buffer, |             buffer, | ||||||
|             64, |             sizeof(buffer), | ||||||
|             "Level: %ld  To level up: %ld", |             "Level: %ld  To level up: %ld", | ||||||
|             current_lvl, |             current_lvl, | ||||||
|             (remaining == (uint32_t)(-1) ? remaining : 0)); |             (remaining == (uint32_t)(-1) ? remaining : 0)); | ||||||
|         canvas_draw_str(canvas, 5, 29 + STATUS_BAR_Y_SHIFT, buffer); |         canvas_draw_str(canvas, 5, 29 + STATUS_BAR_Y_SHIFT, buffer); | ||||||
| 
 | 
 | ||||||
|         snprintf(buffer, 64, "%s", asctime(localtime((const time_t*)&m->timestamp))); |         // even if timestamp is uint64_t, it's safe to cast it to uint32_t, because furi_hal_rtc_datetime_to_timestamp only returns uint32_t
 | ||||||
|  |         snprintf(buffer, sizeof(buffer), "%ld", (uint32_t)m->timestamp); | ||||||
|  | 
 | ||||||
|         canvas_draw_str(canvas, 5, 39 + STATUS_BAR_Y_SHIFT, buffer); |         canvas_draw_str(canvas, 5, 39 + STATUS_BAR_Y_SHIFT, buffer); | ||||||
|         canvas_draw_str(canvas, 0, 49 + STATUS_BAR_Y_SHIFT, "[< >] icounter value   [ok] save"); |         canvas_draw_str(canvas, 0, 49 + STATUS_BAR_Y_SHIFT, "[< >] icounter value   [ok] save"); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -67,7 +67,7 @@ void desktop_lock_menu_render(Canvas* canvas, void* model) { | |||||||
|         const char* str = Lockmenu_Items[i]; |         const char* str = Lockmenu_Items[i]; | ||||||
| 
 | 
 | ||||||
|         if(i == 1 && !m->pin_set) str = "Set PIN"; |         if(i == 1 && !m->pin_set) str = "Set PIN"; | ||||||
|         if(m->hint_timeout && m->idx == 2 && m->idx == i) str = "Not implemented"; |         if(m->hint_timeout && m->idx == 2 && m->idx == i) str = "Not Implemented"; | ||||||
| 
 | 
 | ||||||
|         if(str != NULL) |         if(str != NULL) | ||||||
|             canvas_draw_str_aligned( |             canvas_draw_str_aligned( | ||||||
|  | |||||||
| @ -20,7 +20,7 @@ static bool gpio_test_process_ok(GpioTest* gpio_test, InputEvent* event); | |||||||
| static void gpio_test_draw_callback(Canvas* canvas, void* _model) { | static void gpio_test_draw_callback(Canvas* canvas, void* _model) { | ||||||
|     GpioTestModel* model = _model; |     GpioTestModel* model = _model; | ||||||
|     canvas_set_font(canvas, FontPrimary); |     canvas_set_font(canvas, FontPrimary); | ||||||
|     elements_multiline_text_aligned(canvas, 64, 2, AlignCenter, AlignTop, "Gpio Output mode test"); |     elements_multiline_text_aligned(canvas, 64, 2, AlignCenter, AlignTop, "GPIO Output Mode Test"); | ||||||
|     canvas_set_font(canvas, FontSecondary); |     canvas_set_font(canvas, FontSecondary); | ||||||
|     elements_multiline_text_aligned( |     elements_multiline_text_aligned( | ||||||
|         canvas, 64, 16, AlignCenter, AlignTop, "Press < or > to change pin"); |         canvas, 64, 16, AlignCenter, AlignTop, "Press < or > to change pin"); | ||||||
|  | |||||||
| @ -185,6 +185,7 @@ static void button_menu_process_ok(ButtonMenu* button_menu, InputType type) { | |||||||
|             return false; |             return false; | ||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
|  |     if(item) { | ||||||
|         if(item->type == ButtonMenuItemTypeControl) { |         if(item->type == ButtonMenuItemTypeControl) { | ||||||
|             if(type == InputTypeShort) { |             if(type == InputTypeShort) { | ||||||
|                 if(item && item->callback) { |                 if(item && item->callback) { | ||||||
| @ -199,6 +200,7 @@ static void button_menu_process_ok(ButtonMenu* button_menu, InputType type) { | |||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static bool button_menu_view_input_callback(InputEvent* event, void* context) { | static bool button_menu_view_input_callback(InputEvent* event, void* context) { | ||||||
|  | |||||||
| @ -131,7 +131,9 @@ static bool char_is_lowercase(char letter) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static char char_to_uppercase(const char letter) { | static char char_to_uppercase(const char letter) { | ||||||
|     if(isalpha(letter)) { |     if(letter == '_') { | ||||||
|  |         return 0x20; | ||||||
|  |     } else if(isalpha(letter)) { | ||||||
|         return (letter - 0x20); |         return (letter - 0x20); | ||||||
|     } else { |     } else { | ||||||
|         return letter; |         return letter; | ||||||
| @ -147,7 +149,7 @@ static void text_input_backspace_cb(TextInputModel* model) { | |||||||
| 
 | 
 | ||||||
| static void text_input_view_draw_callback(Canvas* canvas, void* _model) { | static void text_input_view_draw_callback(Canvas* canvas, void* _model) { | ||||||
|     TextInputModel* model = _model; |     TextInputModel* model = _model; | ||||||
|     uint8_t text_length = strlen(model->text_buffer); |     uint8_t text_length = model->text_buffer ? strlen(model->text_buffer) : 0; | ||||||
|     uint8_t needed_string_width = canvas_width(canvas) - 8; |     uint8_t needed_string_width = canvas_width(canvas) - 8; | ||||||
|     uint8_t start_pos = 4; |     uint8_t start_pos = 4; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| // #include <gui/view.h>
 |  | ||||||
| #include <m-string.h> | #include <m-string.h> | ||||||
|  | #include <core/common_defines.h> | ||||||
| 
 | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| extern "C" { | extern "C" { | ||||||
|  | |||||||
| @ -9,20 +9,6 @@ | |||||||
| 
 | 
 | ||||||
| #define TAG "iButtonApp" | #define TAG "iButtonApp" | ||||||
| 
 | 
 | ||||||
| static const NotificationSequence sequence_blink_start_cyan = { |  | ||||||
|     &message_blink_start_10, |  | ||||||
|     &message_blink_set_color_cyan, |  | ||||||
|     &message_do_not_reset, |  | ||||||
|     NULL, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| static const NotificationSequence sequence_blink_start_magenta = { |  | ||||||
|     &message_blink_start_10, |  | ||||||
|     &message_blink_set_color_magenta, |  | ||||||
|     &message_do_not_reset, |  | ||||||
|     NULL, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| static const NotificationSequence sequence_blink_set_yellow = { | static const NotificationSequence sequence_blink_set_yellow = { | ||||||
|     &message_blink_set_color_yellow, |     &message_blink_set_color_yellow, | ||||||
|     NULL, |     NULL, | ||||||
| @ -33,11 +19,6 @@ static const NotificationSequence sequence_blink_set_magenta = { | |||||||
|     NULL, |     NULL, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static const NotificationSequence sequence_blink_stop = { |  | ||||||
|     &message_blink_stop, |  | ||||||
|     NULL, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| static const NotificationSequence* ibutton_notification_sequences[] = { | static const NotificationSequence* ibutton_notification_sequences[] = { | ||||||
|     &sequence_error, |     &sequence_error, | ||||||
|     &sequence_success, |     &sequence_success, | ||||||
| @ -106,6 +87,8 @@ static void ibutton_rpc_command_callback(RpcAppSystemEvent event, void* context) | |||||||
|     if(event == RpcAppEventSessionClose) { |     if(event == RpcAppEventSessionClose) { | ||||||
|         view_dispatcher_send_custom_event( |         view_dispatcher_send_custom_event( | ||||||
|             ibutton->view_dispatcher, iButtonCustomEventRpcSessionClose); |             ibutton->view_dispatcher, iButtonCustomEventRpcSessionClose); | ||||||
|  |         rpc_system_app_set_callback(ibutton->rpc_ctx, NULL, NULL); | ||||||
|  |         ibutton->rpc_ctx = NULL; | ||||||
|     } else if(event == RpcAppEventAppExit) { |     } else if(event == RpcAppEventAppExit) { | ||||||
|         view_dispatcher_send_custom_event(ibutton->view_dispatcher, iButtonCustomEventRpcExit); |         view_dispatcher_send_custom_event(ibutton->view_dispatcher, iButtonCustomEventRpcExit); | ||||||
|     } else if(event == RpcAppEventLoadFile) { |     } else if(event == RpcAppEventLoadFile) { | ||||||
| @ -324,22 +307,6 @@ void ibutton_text_store_clear(iButton* ibutton) { | |||||||
|     memset(ibutton->text_store, 0, IBUTTON_TEXT_STORE_SIZE); |     memset(ibutton->text_store, 0, IBUTTON_TEXT_STORE_SIZE); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ibutton_switch_to_previous_scene_one_of( |  | ||||||
|     iButton* ibutton, |  | ||||||
|     const uint32_t* scene_ids, |  | ||||||
|     size_t scene_ids_size) { |  | ||||||
|     furi_assert(scene_ids_size); |  | ||||||
|     SceneManager* scene_manager = ibutton->scene_manager; |  | ||||||
| 
 |  | ||||||
|     for(size_t i = 0; i < scene_ids_size; ++i) { |  | ||||||
|         const uint32_t scene_id = scene_ids[i]; |  | ||||||
|         if(scene_manager_has_previous_scene(scene_manager, scene_id)) { |  | ||||||
|             scene_manager_search_and_switch_to_previous_scene(scene_manager, scene_id); |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void ibutton_notification_message(iButton* ibutton, uint32_t message) { | void ibutton_notification_message(iButton* ibutton, uint32_t message) { | ||||||
|     furi_assert(message < sizeof(ibutton_notification_sequences) / sizeof(NotificationSequence*)); |     furi_assert(message < sizeof(ibutton_notification_sequences) / sizeof(NotificationSequence*)); | ||||||
|     notification_message(ibutton->notifications, ibutton_notification_sequences[message]); |     notification_message(ibutton->notifications, ibutton_notification_sequences[message]); | ||||||
| @ -353,7 +320,7 @@ int32_t ibutton_app(void* p) { | |||||||
|     bool key_loaded = false; |     bool key_loaded = false; | ||||||
|     bool rpc_mode = false; |     bool rpc_mode = false; | ||||||
| 
 | 
 | ||||||
|     if(p) { |     if(p && strlen(p)) { | ||||||
|         uint32_t rpc_ctx = 0; |         uint32_t rpc_ctx = 0; | ||||||
|         if(sscanf(p, "RPC %lX", &rpc_ctx) == 1) { |         if(sscanf(p, "RPC %lX", &rpc_ctx) == 1) { | ||||||
|             FURI_LOG_D(TAG, "Running in RPC mode"); |             FURI_LOG_D(TAG, "Running in RPC mode"); | ||||||
|  | |||||||
| @ -83,8 +83,4 @@ bool ibutton_save_key(iButton* ibutton, const char* key_name); | |||||||
| bool ibutton_delete_key(iButton* ibutton); | bool ibutton_delete_key(iButton* ibutton); | ||||||
| void ibutton_text_store_set(iButton* ibutton, const char* text, ...); | void ibutton_text_store_set(iButton* ibutton, const char* text, ...); | ||||||
| void ibutton_text_store_clear(iButton* ibutton); | void ibutton_text_store_clear(iButton* ibutton); | ||||||
| void ibutton_switch_to_previous_scene_one_of( |  | ||||||
|     iButton* ibutton, |  | ||||||
|     const uint32_t* scene_ids, |  | ||||||
|     size_t scene_ids_size); |  | ||||||
| void ibutton_notification_message(iButton* ibutton, uint32_t message); | void ibutton_notification_message(iButton* ibutton, uint32_t message); | ||||||
|  | |||||||
| @ -21,7 +21,7 @@ void ibutton_scene_exit_confirm_on_enter(void* context) { | |||||||
|     widget_add_string_element( |     widget_add_string_element( | ||||||
|         widget, 64, 19, AlignCenter, AlignBottom, FontPrimary, "Exit to iButton menu?"); |         widget, 64, 19, AlignCenter, AlignBottom, FontPrimary, "Exit to iButton menu?"); | ||||||
|     widget_add_string_element( |     widget_add_string_element( | ||||||
|         widget, 64, 31, AlignCenter, AlignBottom, FontSecondary, "All unsaved data will be lost."); |         widget, 64, 31, AlignCenter, AlignBottom, FontSecondary, "All unsaved data will be lost!"); | ||||||
| 
 | 
 | ||||||
|     view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewWidget); |     view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewWidget); | ||||||
| } | } | ||||||
|  | |||||||
| @ -14,7 +14,7 @@ void ibutton_scene_read_on_enter(void* context) { | |||||||
|     DOLPHIN_DEED(DolphinDeedIbuttonRead); |     DOLPHIN_DEED(DolphinDeedIbuttonRead); | ||||||
| 
 | 
 | ||||||
|     popup_set_header(popup, "iButton", 95, 26, AlignCenter, AlignBottom); |     popup_set_header(popup, "iButton", 95, 26, AlignCenter, AlignBottom); | ||||||
|     popup_set_text(popup, "waiting\nfor key ...", 95, 30, AlignCenter, AlignTop); |     popup_set_text(popup, "Waiting\nfor key ...", 95, 30, AlignCenter, AlignTop); | ||||||
|     popup_set_icon(popup, 0, 5, &I_DolphinWait_61x59); |     popup_set_icon(popup, 0, 5, &I_DolphinWait_61x59); | ||||||
| 
 | 
 | ||||||
|     view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewPopup); |     view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewPopup); | ||||||
|  | |||||||
| @ -21,7 +21,7 @@ void ibutton_scene_retry_confirm_on_enter(void* context) { | |||||||
|     widget_add_string_element( |     widget_add_string_element( | ||||||
|         widget, 64, 19, AlignCenter, AlignBottom, FontPrimary, "Return to reading?"); |         widget, 64, 19, AlignCenter, AlignBottom, FontPrimary, "Return to reading?"); | ||||||
|     widget_add_string_element( |     widget_add_string_element( | ||||||
|         widget, 64, 29, AlignCenter, AlignBottom, FontSecondary, "All unsaved data will be lost."); |         widget, 64, 29, AlignCenter, AlignBottom, FontSecondary, "All unsaved data will be lost!"); | ||||||
| 
 | 
 | ||||||
|     view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewWidget); |     view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewWidget); | ||||||
| } | } | ||||||
|  | |||||||
| @ -29,7 +29,7 @@ bool ibutton_scene_rpc_on_event(void* context, SceneManagerEvent event) { | |||||||
|         if(event.event == iButtonCustomEventRpcLoad) { |         if(event.event == iButtonCustomEventRpcLoad) { | ||||||
|             const char* arg = rpc_system_app_get_data(ibutton->rpc_ctx); |             const char* arg = rpc_system_app_get_data(ibutton->rpc_ctx); | ||||||
|             bool result = false; |             bool result = false; | ||||||
|             if(arg) { |             if(arg && (string_empty_p(ibutton->file_path))) { | ||||||
|                 string_set_str(ibutton->file_path, arg); |                 string_set_str(ibutton->file_path, arg); | ||||||
|                 if(ibutton_load_key_data(ibutton, ibutton->file_path, false)) { |                 if(ibutton_load_key_data(ibutton, ibutton->file_path, false)) { | ||||||
|                     ibutton_worker_emulate_start(ibutton->key_worker, ibutton->key); |                     ibutton_worker_emulate_start(ibutton->key_worker, ibutton->key); | ||||||
| @ -51,17 +51,17 @@ bool ibutton_scene_rpc_on_event(void* context, SceneManagerEvent event) { | |||||||
| 
 | 
 | ||||||
|                     string_clear(key_name); |                     string_clear(key_name); | ||||||
|                     result = true; |                     result = true; | ||||||
|  |                 } else { | ||||||
|  |                     string_reset(ibutton->file_path); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             rpc_system_app_confirm(ibutton->rpc_ctx, RpcAppEventLoadFile, result); |             rpc_system_app_confirm(ibutton->rpc_ctx, RpcAppEventLoadFile, result); | ||||||
|         } else if(event.event == iButtonCustomEventRpcExit) { |         } else if(event.event == iButtonCustomEventRpcExit) { | ||||||
|             rpc_system_app_confirm(ibutton->rpc_ctx, RpcAppEventAppExit, true); |             rpc_system_app_confirm(ibutton->rpc_ctx, RpcAppEventAppExit, true); | ||||||
|             ibutton_notification_message(ibutton, iButtonNotificationMessageBlinkStop); |             scene_manager_stop(ibutton->scene_manager); | ||||||
|             view_dispatcher_stop(ibutton->view_dispatcher); |             view_dispatcher_stop(ibutton->view_dispatcher); | ||||||
|         } else if(event.event == iButtonCustomEventRpcSessionClose) { |         } else if(event.event == iButtonCustomEventRpcSessionClose) { | ||||||
|             rpc_system_app_set_callback(ibutton->rpc_ctx, NULL, NULL); |             scene_manager_stop(ibutton->scene_manager); | ||||||
|             ibutton->rpc_ctx = NULL; |  | ||||||
|             ibutton_notification_message(ibutton, iButtonNotificationMessageBlinkStop); |  | ||||||
|             view_dispatcher_stop(ibutton->view_dispatcher); |             view_dispatcher_stop(ibutton->view_dispatcher); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -61,8 +61,8 @@ bool ibutton_scene_save_name_on_event(void* context, SceneManagerEvent event) { | |||||||
|             } else { |             } else { | ||||||
|                 const uint32_t possible_scenes[] = { |                 const uint32_t possible_scenes[] = { | ||||||
|                     iButtonSceneReadKeyMenu, iButtonSceneSavedKeyMenu, iButtonSceneAddType}; |                     iButtonSceneReadKeyMenu, iButtonSceneSavedKeyMenu, iButtonSceneAddType}; | ||||||
|                 ibutton_switch_to_previous_scene_one_of( |                 scene_manager_search_and_switch_to_previous_scene_one_of( | ||||||
|                     ibutton, possible_scenes, sizeof(possible_scenes) / sizeof(uint32_t)); |                     ibutton->scene_manager, possible_scenes, COUNT_OF(possible_scenes)); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -31,8 +31,8 @@ bool ibutton_scene_save_success_on_event(void* context, SceneManagerEvent event) | |||||||
|         if(event.event == iButtonCustomEventBack) { |         if(event.event == iButtonCustomEventBack) { | ||||||
|             const uint32_t possible_scenes[] = { |             const uint32_t possible_scenes[] = { | ||||||
|                 iButtonSceneReadKeyMenu, iButtonSceneSavedKeyMenu, iButtonSceneAddType}; |                 iButtonSceneReadKeyMenu, iButtonSceneSavedKeyMenu, iButtonSceneAddType}; | ||||||
|             ibutton_switch_to_previous_scene_one_of( |             scene_manager_search_and_switch_to_previous_scene_one_of( | ||||||
|                 ibutton, possible_scenes, sizeof(possible_scenes) / sizeof(uint32_t)); |                 ibutton->scene_manager, possible_scenes, COUNT_OF(possible_scenes)); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -31,8 +31,8 @@ bool ibutton_scene_write_success_on_event(void* context, SceneManagerEvent event | |||||||
|         consumed = true; |         consumed = true; | ||||||
|         if(event.event == iButtonCustomEventBack) { |         if(event.event == iButtonCustomEventBack) { | ||||||
|             const uint32_t possible_scenes[] = {iButtonSceneReadKeyMenu, iButtonSceneStart}; |             const uint32_t possible_scenes[] = {iButtonSceneReadKeyMenu, iButtonSceneStart}; | ||||||
|             ibutton_switch_to_previous_scene_one_of( |             scene_manager_search_and_switch_to_previous_scene_one_of( | ||||||
|                 ibutton, possible_scenes, sizeof(possible_scenes) / sizeof(uint32_t)); |                 ibutton->scene_manager, possible_scenes, COUNT_OF(possible_scenes)); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -7,10 +7,12 @@ static const NotificationSequence* infrared_notification_sequences[] = { | |||||||
|     &sequence_success, |     &sequence_success, | ||||||
|     &sequence_set_only_green_255, |     &sequence_set_only_green_255, | ||||||
|     &sequence_reset_green, |     &sequence_reset_green, | ||||||
|     &sequence_blink_cyan_10, |  | ||||||
|     &sequence_blink_magenta_10, |  | ||||||
|     &sequence_solid_yellow, |     &sequence_solid_yellow, | ||||||
|     &sequence_reset_rgb}; |     &sequence_reset_rgb, | ||||||
|  |     &sequence_blink_start_cyan, | ||||||
|  |     &sequence_blink_start_magenta, | ||||||
|  |     &sequence_blink_stop, | ||||||
|  | }; | ||||||
| 
 | 
 | ||||||
| static void infrared_make_app_folder(Infrared* infrared) { | static void infrared_make_app_folder(Infrared* infrared) { | ||||||
|     if(!storage_simply_mkdir(infrared->storage, INFRARED_APP_FOLDER)) { |     if(!storage_simply_mkdir(infrared->storage, INFRARED_APP_FOLDER)) { | ||||||
| @ -44,6 +46,8 @@ static void infrared_rpc_command_callback(RpcAppSystemEvent event, void* context | |||||||
|     if(event == RpcAppEventSessionClose) { |     if(event == RpcAppEventSessionClose) { | ||||||
|         view_dispatcher_send_custom_event( |         view_dispatcher_send_custom_event( | ||||||
|             infrared->view_dispatcher, InfraredCustomEventTypeRpcSessionClose); |             infrared->view_dispatcher, InfraredCustomEventTypeRpcSessionClose); | ||||||
|  |         rpc_system_app_set_callback(infrared->rpc_ctx, NULL, NULL); | ||||||
|  |         infrared->rpc_ctx = NULL; | ||||||
|     } else if(event == RpcAppEventAppExit) { |     } else if(event == RpcAppEventAppExit) { | ||||||
|         view_dispatcher_send_custom_event( |         view_dispatcher_send_custom_event( | ||||||
|             infrared->view_dispatcher, InfraredCustomEventTypeRpcExit); |             infrared->view_dispatcher, InfraredCustomEventTypeRpcExit); | ||||||
| @ -291,6 +295,13 @@ bool infrared_rename_current_remote(Infrared* infrared, const char* name) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void infrared_tx_start_signal(Infrared* infrared, InfraredSignal* signal) { | void infrared_tx_start_signal(Infrared* infrared, InfraredSignal* signal) { | ||||||
|  |     if(infrared->app_state.is_transmitting) { | ||||||
|  |         FURI_LOG_D(INFRARED_LOG_TAG, "Transmitter is already active"); | ||||||
|  |         return; | ||||||
|  |     } else { | ||||||
|  |         infrared->app_state.is_transmitting = true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     if(infrared_signal_is_raw(signal)) { |     if(infrared_signal_is_raw(signal)) { | ||||||
|         InfraredRawSignal* raw = infrared_signal_get_raw_signal(signal); |         InfraredRawSignal* raw = infrared_signal_get_raw_signal(signal); | ||||||
|         infrared_worker_set_raw_signal(infrared->worker, raw->timings, raw->timings_size); |         infrared_worker_set_raw_signal(infrared->worker, raw->timings, raw->timings_size); | ||||||
| @ -300,6 +311,10 @@ void infrared_tx_start_signal(Infrared* infrared, InfraredSignal* signal) { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     DOLPHIN_DEED(DolphinDeedIrSend); |     DOLPHIN_DEED(DolphinDeedIrSend); | ||||||
|  |     infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStartSend); | ||||||
|  | 
 | ||||||
|  |     infrared_worker_tx_set_get_signal_callback( | ||||||
|  |         infrared->worker, infrared_worker_tx_get_signal_steady_callback, infrared); | ||||||
|     infrared_worker_tx_start(infrared->worker); |     infrared_worker_tx_start(infrared->worker); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -310,14 +325,26 @@ void infrared_tx_start_button_index(Infrared* infrared, size_t button_index) { | |||||||
|     InfraredSignal* signal = infrared_remote_button_get_signal(button); |     InfraredSignal* signal = infrared_remote_button_get_signal(button); | ||||||
| 
 | 
 | ||||||
|     infrared_tx_start_signal(infrared, signal); |     infrared_tx_start_signal(infrared, signal); | ||||||
|  |     infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStartSend); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void infrared_tx_start_received(Infrared* infrared) { | void infrared_tx_start_received(Infrared* infrared) { | ||||||
|     infrared_tx_start_signal(infrared, infrared->received_signal); |     infrared_tx_start_signal(infrared, infrared->received_signal); | ||||||
|  |     infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStartSend); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void infrared_tx_stop(Infrared* infrared) { | void infrared_tx_stop(Infrared* infrared) { | ||||||
|  |     if(!infrared->app_state.is_transmitting) { | ||||||
|  |         FURI_LOG_D(INFRARED_LOG_TAG, "Transmitter is already stopped"); | ||||||
|  |         return; | ||||||
|  |     } else { | ||||||
|  |         infrared->app_state.is_transmitting = false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     infrared_worker_tx_stop(infrared->worker); |     infrared_worker_tx_stop(infrared->worker); | ||||||
|  |     infrared_worker_tx_set_get_signal_callback(infrared->worker, NULL, NULL); | ||||||
|  | 
 | ||||||
|  |     infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStop); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void infrared_text_store_set(Infrared* infrared, uint32_t bank, const char* text, ...) { | void infrared_text_store_set(Infrared* infrared, uint32_t bank, const char* text, ...) { | ||||||
| @ -354,12 +381,6 @@ void infrared_show_loading_popup(Infrared* infrared, bool show) { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void infrared_signal_sent_callback(void* context) { |  | ||||||
|     furi_assert(context); |  | ||||||
|     Infrared* infrared = context; |  | ||||||
|     infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkSend); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void infrared_signal_received_callback(void* context, InfraredWorkerSignal* received_signal) { | void infrared_signal_received_callback(void* context, InfraredWorkerSignal* received_signal) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     Infrared* infrared = context; |     Infrared* infrared = context; | ||||||
| @ -405,7 +426,7 @@ int32_t infrared_app(void* p) { | |||||||
|     bool is_remote_loaded = false; |     bool is_remote_loaded = false; | ||||||
|     bool is_rpc_mode = false; |     bool is_rpc_mode = false; | ||||||
| 
 | 
 | ||||||
|     if(p) { |     if(p && strlen(p)) { | ||||||
|         uint32_t rpc_ctx = 0; |         uint32_t rpc_ctx = 0; | ||||||
|         if(sscanf(p, "RPC %lX", &rpc_ctx) == 1) { |         if(sscanf(p, "RPC %lX", &rpc_ctx) == 1) { | ||||||
|             infrared->rpc_ctx = (void*)rpc_ctx; |             infrared->rpc_ctx = (void*)rpc_ctx; | ||||||
|  | |||||||
| @ -27,7 +27,7 @@ static void signal_received_callback(void* context, InfraredWorkerSignal* receiv | |||||||
| 
 | 
 | ||||||
|     if(infrared_worker_signal_is_decoded(received_signal)) { |     if(infrared_worker_signal_is_decoded(received_signal)) { | ||||||
|         const InfraredMessage* message = infrared_worker_get_decoded_signal(received_signal); |         const InfraredMessage* message = infrared_worker_get_decoded_signal(received_signal); | ||||||
|         buf_cnt = sniprintf( |         buf_cnt = snprintf( | ||||||
|             buf, |             buf, | ||||||
|             sizeof(buf), |             sizeof(buf), | ||||||
|             "%s, A:0x%0*lX, C:0x%0*lX%s\r\n", |             "%s, A:0x%0*lX, C:0x%0*lX%s\r\n", | ||||||
| @ -43,13 +43,13 @@ static void signal_received_callback(void* context, InfraredWorkerSignal* receiv | |||||||
|         size_t timings_cnt; |         size_t timings_cnt; | ||||||
|         infrared_worker_get_raw_signal(received_signal, &timings, &timings_cnt); |         infrared_worker_get_raw_signal(received_signal, &timings, &timings_cnt); | ||||||
| 
 | 
 | ||||||
|         buf_cnt = sniprintf(buf, sizeof(buf), "RAW, %d samples:\r\n", timings_cnt); |         buf_cnt = snprintf(buf, sizeof(buf), "RAW, %d samples:\r\n", timings_cnt); | ||||||
|         cli_write(cli, (uint8_t*)buf, buf_cnt); |         cli_write(cli, (uint8_t*)buf, buf_cnt); | ||||||
|         for(size_t i = 0; i < timings_cnt; ++i) { |         for(size_t i = 0; i < timings_cnt; ++i) { | ||||||
|             buf_cnt = sniprintf(buf, sizeof(buf), "%lu ", timings[i]); |             buf_cnt = snprintf(buf, sizeof(buf), "%lu ", timings[i]); | ||||||
|             cli_write(cli, (uint8_t*)buf, buf_cnt); |             cli_write(cli, (uint8_t*)buf, buf_cnt); | ||||||
|         } |         } | ||||||
|         buf_cnt = sniprintf(buf, sizeof(buf), "\r\n"); |         buf_cnt = snprintf(buf, sizeof(buf), "\r\n"); | ||||||
|         cli_write(cli, (uint8_t*)buf, buf_cnt); |         cli_write(cli, (uint8_t*)buf, buf_cnt); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -43,6 +43,7 @@ | |||||||
| #define INFRARED_APP_EXTENSION ".ir" | #define INFRARED_APP_EXTENSION ".ir" | ||||||
| 
 | 
 | ||||||
| #define INFRARED_DEFAULT_REMOTE_NAME "Remote" | #define INFRARED_DEFAULT_REMOTE_NAME "Remote" | ||||||
|  | #define INFRARED_LOG_TAG "InfraredApp" | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     InfraredButtonIndexNone = -1, |     InfraredButtonIndexNone = -1, | ||||||
| @ -63,6 +64,7 @@ typedef enum { | |||||||
| typedef struct { | typedef struct { | ||||||
|     bool is_learning_new_remote; |     bool is_learning_new_remote; | ||||||
|     bool is_debug_enabled; |     bool is_debug_enabled; | ||||||
|  |     bool is_transmitting; | ||||||
|     InfraredEditTarget edit_target : 8; |     InfraredEditTarget edit_target : 8; | ||||||
|     InfraredEditMode edit_mode : 8; |     InfraredEditMode edit_mode : 8; | ||||||
|     int32_t current_button_index; |     int32_t current_button_index; | ||||||
| @ -115,10 +117,11 @@ typedef enum { | |||||||
|     InfraredNotificationMessageSuccess, |     InfraredNotificationMessageSuccess, | ||||||
|     InfraredNotificationMessageGreenOn, |     InfraredNotificationMessageGreenOn, | ||||||
|     InfraredNotificationMessageGreenOff, |     InfraredNotificationMessageGreenOff, | ||||||
|     InfraredNotificationMessageBlinkRead, |  | ||||||
|     InfraredNotificationMessageBlinkSend, |  | ||||||
|     InfraredNotificationMessageYellowOn, |     InfraredNotificationMessageYellowOn, | ||||||
|     InfraredNotificationMessageYellowOff, |     InfraredNotificationMessageYellowOff, | ||||||
|  |     InfraredNotificationMessageBlinkStartRead, | ||||||
|  |     InfraredNotificationMessageBlinkStartSend, | ||||||
|  |     InfraredNotificationMessageBlinkStop, | ||||||
| } InfraredNotificationMessage; | } InfraredNotificationMessage; | ||||||
| 
 | 
 | ||||||
| bool infrared_add_remote_with_button(Infrared* infrared, const char* name, InfraredSignal* signal); | bool infrared_add_remote_with_button(Infrared* infrared, const char* name, InfraredSignal* signal); | ||||||
| @ -132,7 +135,6 @@ void infrared_text_store_clear(Infrared* infrared, uint32_t bank); | |||||||
| void infrared_play_notification_message(Infrared* infrared, uint32_t message); | void infrared_play_notification_message(Infrared* infrared, uint32_t message); | ||||||
| void infrared_show_loading_popup(Infrared* infrared, bool show); | void infrared_show_loading_popup(Infrared* infrared, bool show); | ||||||
| 
 | 
 | ||||||
| void infrared_signal_sent_callback(void* context); |  | ||||||
| void infrared_signal_received_callback(void* context, InfraredWorkerSignal* received_signal); | void infrared_signal_received_callback(void* context, InfraredWorkerSignal* received_signal); | ||||||
| void infrared_text_input_callback(void* context); | void infrared_text_input_callback(void* context); | ||||||
| void infrared_popup_closed_callback(void* context); | void infrared_popup_closed_callback(void* context); | ||||||
|  | |||||||
| @ -21,12 +21,14 @@ static void infrared_scene_universal_common_show_popup(Infrared* infrared, uint3 | |||||||
|     infrared_progress_view_set_back_callback( |     infrared_progress_view_set_back_callback( | ||||||
|         progress, infrared_scene_universal_common_progress_back_callback, infrared); |         progress, infrared_scene_universal_common_progress_back_callback, infrared); | ||||||
|     view_stack_add_view(view_stack, infrared_progress_view_get_view(progress)); |     view_stack_add_view(view_stack, infrared_progress_view_get_view(progress)); | ||||||
|  |     infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStartSend); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void infrared_scene_universal_common_hide_popup(Infrared* infrared) { | static void infrared_scene_universal_common_hide_popup(Infrared* infrared) { | ||||||
|     ViewStack* view_stack = infrared->view_stack; |     ViewStack* view_stack = infrared->view_stack; | ||||||
|     InfraredProgressView* progress = infrared->progress; |     InfraredProgressView* progress = infrared->progress; | ||||||
|     view_stack_remove_view(view_stack, infrared_progress_view_get_view(progress)); |     view_stack_remove_view(view_stack, infrared_progress_view_get_view(progress)); | ||||||
|  |     infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStop); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void infrared_scene_universal_common_on_enter(void* context) { | void infrared_scene_universal_common_on_enter(void* context) { | ||||||
| @ -42,7 +44,6 @@ bool infrared_scene_universal_common_on_event(void* context, SceneManagerEvent e | |||||||
| 
 | 
 | ||||||
|     if(infrared_brute_force_is_started(brute_force)) { |     if(infrared_brute_force_is_started(brute_force)) { | ||||||
|         if(event.type == SceneManagerEventTypeTick) { |         if(event.type == SceneManagerEventTypeTick) { | ||||||
|             infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkSend); |  | ||||||
|             bool success = infrared_brute_force_send_next(brute_force); |             bool success = infrared_brute_force_send_next(brute_force); | ||||||
|             if(success) { |             if(success) { | ||||||
|                 success = infrared_progress_view_increase_progress(infrared->progress); |                 success = infrared_progress_view_increase_progress(infrared->progress); | ||||||
| @ -71,8 +72,6 @@ bool infrared_scene_universal_common_on_event(void* context, SceneManagerEvent e | |||||||
|                        brute_force, infrared_custom_event_get_value(event.event), &record_count)) { |                        brute_force, infrared_custom_event_get_value(event.event), &record_count)) { | ||||||
|                     DOLPHIN_DEED(DolphinDeedIrBruteForce); |                     DOLPHIN_DEED(DolphinDeedIrBruteForce); | ||||||
|                     infrared_scene_universal_common_show_popup(infrared, record_count); |                     infrared_scene_universal_common_show_popup(infrared, record_count); | ||||||
|                     infrared_play_notification_message( |  | ||||||
|                         infrared, InfraredNotificationMessageBlinkSend); |  | ||||||
|                 } else { |                 } else { | ||||||
|                     scene_manager_next_scene(scene_manager, InfraredSceneErrorDatabases); |                     scene_manager_next_scene(scene_manager, InfraredSceneErrorDatabases); | ||||||
|                 } |                 } | ||||||
|  | |||||||
| @ -10,13 +10,13 @@ void infrared_scene_ask_back_on_enter(void* context) { | |||||||
|     DialogEx* dialog_ex = infrared->dialog_ex; |     DialogEx* dialog_ex = infrared->dialog_ex; | ||||||
| 
 | 
 | ||||||
|     if(infrared->app_state.is_learning_new_remote) { |     if(infrared->app_state.is_learning_new_remote) { | ||||||
|         dialog_ex_set_header(dialog_ex, "Exit to Infrared menu?", 64, 0, AlignCenter, AlignTop); |         dialog_ex_set_header(dialog_ex, "Exit to Infrared Menu?", 64, 0, AlignCenter, AlignTop); | ||||||
|     } else { |     } else { | ||||||
|         dialog_ex_set_header(dialog_ex, "Exit to remote menu?", 64, 0, AlignCenter, AlignTop); |         dialog_ex_set_header(dialog_ex, "Exit to Remote Menu?", 64, 0, AlignCenter, AlignTop); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     dialog_ex_set_text( |     dialog_ex_set_text( | ||||||
|         dialog_ex, "All unsaved data\nwill be lost.", 64, 31, AlignCenter, AlignCenter); |         dialog_ex, "All unsaved data\nwill be lost!", 64, 31, AlignCenter, AlignCenter); | ||||||
|     dialog_ex_set_icon(dialog_ex, 0, 0, NULL); |     dialog_ex_set_icon(dialog_ex, 0, 0, NULL); | ||||||
|     dialog_ex_set_left_button_text(dialog_ex, "Exit"); |     dialog_ex_set_left_button_text(dialog_ex, "Exit"); | ||||||
|     dialog_ex_set_center_button_text(dialog_ex, NULL); |     dialog_ex_set_center_button_text(dialog_ex, NULL); | ||||||
|  | |||||||
| @ -9,9 +9,9 @@ void infrared_scene_ask_retry_on_enter(void* context) { | |||||||
|     Infrared* infrared = context; |     Infrared* infrared = context; | ||||||
|     DialogEx* dialog_ex = infrared->dialog_ex; |     DialogEx* dialog_ex = infrared->dialog_ex; | ||||||
| 
 | 
 | ||||||
|     dialog_ex_set_header(dialog_ex, "Return to reading?", 64, 0, AlignCenter, AlignTop); |     dialog_ex_set_header(dialog_ex, "Return to Reading?", 64, 0, AlignCenter, AlignTop); | ||||||
|     dialog_ex_set_text( |     dialog_ex_set_text( | ||||||
|         dialog_ex, "All unsaved data\nwill be lost.", 64, 31, AlignCenter, AlignCenter); |         dialog_ex, "All unsaved data\nwill be lost!", 64, 31, AlignCenter, AlignCenter); | ||||||
|     dialog_ex_set_icon(dialog_ex, 0, 0, NULL); |     dialog_ex_set_icon(dialog_ex, 0, 0, NULL); | ||||||
|     dialog_ex_set_left_button_text(dialog_ex, "Exit"); |     dialog_ex_set_left_button_text(dialog_ex, "Exit"); | ||||||
|     dialog_ex_set_center_button_text(dialog_ex, NULL); |     dialog_ex_set_center_button_text(dialog_ex, NULL); | ||||||
|  | |||||||
| @ -65,4 +65,5 @@ void infrared_scene_debug_on_exit(void* context) { | |||||||
|     InfraredWorker* worker = infrared->worker; |     InfraredWorker* worker = infrared->worker; | ||||||
|     infrared_worker_rx_stop(worker); |     infrared_worker_rx_stop(worker); | ||||||
|     infrared_worker_rx_enable_blink_on_receiving(worker, false); |     infrared_worker_rx_enable_blink_on_receiving(worker, false); | ||||||
|  |     infrared_worker_rx_set_received_signal_callback(worker, NULL, NULL); | ||||||
| } | } | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ void infrared_scene_edit_delete_on_enter(void* context) { | |||||||
|         int32_t current_button_index = infrared->app_state.current_button_index; |         int32_t current_button_index = infrared->app_state.current_button_index; | ||||||
|         furi_assert(current_button_index != InfraredButtonIndexNone); |         furi_assert(current_button_index != InfraredButtonIndexNone); | ||||||
| 
 | 
 | ||||||
|         dialog_ex_set_header(dialog_ex, "Delete button?", 64, 0, AlignCenter, AlignTop); |         dialog_ex_set_header(dialog_ex, "Delete Button?", 64, 0, AlignCenter, AlignTop); | ||||||
|         InfraredRemoteButton* current_button = |         InfraredRemoteButton* current_button = | ||||||
|             infrared_remote_get_button(remote, current_button_index); |             infrared_remote_get_button(remote, current_button_index); | ||||||
|         InfraredSignal* signal = infrared_remote_button_get_signal(current_button); |         InfraredSignal* signal = infrared_remote_button_get_signal(current_button); | ||||||
| @ -45,7 +45,7 @@ void infrared_scene_edit_delete_on_enter(void* context) { | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|     } else if(edit_target == InfraredEditTargetRemote) { |     } else if(edit_target == InfraredEditTargetRemote) { | ||||||
|         dialog_ex_set_header(dialog_ex, "Delete remote?", 64, 0, AlignCenter, AlignTop); |         dialog_ex_set_header(dialog_ex, "Delete Remote?", 64, 0, AlignCenter, AlignTop); | ||||||
|         infrared_text_store_set( |         infrared_text_store_set( | ||||||
|             infrared, |             infrared, | ||||||
|             0, |             0, | ||||||
| @ -97,7 +97,7 @@ bool infrared_scene_edit_delete_on_event(void* context, SceneManagerEvent event) | |||||||
|             } else { |             } else { | ||||||
|                 const uint32_t possible_scenes[] = {InfraredSceneRemoteList, InfraredSceneStart}; |                 const uint32_t possible_scenes[] = {InfraredSceneRemoteList, InfraredSceneStart}; | ||||||
|                 scene_manager_search_and_switch_to_previous_scene_one_of( |                 scene_manager_search_and_switch_to_previous_scene_one_of( | ||||||
|                     scene_manager, possible_scenes, sizeof(possible_scenes) / sizeof(uint32_t)); |                     scene_manager, possible_scenes, COUNT_OF(possible_scenes)); | ||||||
|             } |             } | ||||||
|             consumed = true; |             consumed = true; | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -28,8 +28,10 @@ bool infrared_scene_edit_delete_done_on_event(void* context, SceneManagerEvent e | |||||||
|                     scene_manager, InfraredSceneRemote); |                     scene_manager, InfraredSceneRemote); | ||||||
|             } else if(edit_target == InfraredEditTargetRemote) { |             } else if(edit_target == InfraredEditTargetRemote) { | ||||||
|                 const uint32_t possible_scenes[] = {InfraredSceneStart, InfraredSceneRemoteList}; |                 const uint32_t possible_scenes[] = {InfraredSceneStart, InfraredSceneRemoteList}; | ||||||
|                 scene_manager_search_and_switch_to_previous_scene_one_of( |                 if(!scene_manager_search_and_switch_to_previous_scene_one_of( | ||||||
|                     scene_manager, possible_scenes, sizeof(possible_scenes) / sizeof(uint32_t)); |                        scene_manager, possible_scenes, COUNT_OF(possible_scenes))) { | ||||||
|  |                     view_dispatcher_stop(infrared->view_dispatcher); | ||||||
|  |                 } | ||||||
|             } else { |             } else { | ||||||
|                 furi_assert(0); |                 furi_assert(0); | ||||||
|             } |             } | ||||||
|  | |||||||
| @ -21,7 +21,10 @@ bool infrared_scene_edit_rename_done_on_event(void* context, SceneManagerEvent e | |||||||
| 
 | 
 | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == InfraredCustomEventTypePopupClosed) { |         if(event.event == InfraredCustomEventTypePopupClosed) { | ||||||
|  |             if(!scene_manager_search_and_switch_to_previous_scene( | ||||||
|  |                    infrared->scene_manager, InfraredSceneRemote)) { | ||||||
|                 scene_manager_next_scene(infrared->scene_manager, InfraredSceneRemote); |                 scene_manager_next_scene(infrared->scene_manager, InfraredSceneRemote); | ||||||
|  |             } | ||||||
|             consumed = true; |             consumed = true; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -8,6 +8,7 @@ void infrared_scene_learn_on_enter(void* context) { | |||||||
|     infrared_worker_rx_set_received_signal_callback( |     infrared_worker_rx_set_received_signal_callback( | ||||||
|         worker, infrared_signal_received_callback, context); |         worker, infrared_signal_received_callback, context); | ||||||
|     infrared_worker_rx_start(worker); |     infrared_worker_rx_start(worker); | ||||||
|  |     infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStartRead); | ||||||
| 
 | 
 | ||||||
|     popup_set_icon(popup, 0, 32, &I_InfraredLearnShort_128x31); |     popup_set_icon(popup, 0, 32, &I_InfraredLearnShort_128x31); | ||||||
|     popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignCenter); |     popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignCenter); | ||||||
| @ -22,10 +23,7 @@ bool infrared_scene_learn_on_event(void* context, SceneManagerEvent event) { | |||||||
|     Infrared* infrared = context; |     Infrared* infrared = context; | ||||||
|     bool consumed = false; |     bool consumed = false; | ||||||
| 
 | 
 | ||||||
|     if(event.type == SceneManagerEventTypeTick) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkRead); |  | ||||||
|         consumed = true; |  | ||||||
|     } else if(event.type == SceneManagerEventTypeCustom) { |  | ||||||
|         if(event.event == InfraredCustomEventTypeSignalReceived) { |         if(event.event == InfraredCustomEventTypeSignalReceived) { | ||||||
|             infrared_worker_rx_set_received_signal_callback(infrared->worker, NULL, NULL); |             infrared_worker_rx_set_received_signal_callback(infrared->worker, NULL, NULL); | ||||||
|             infrared_play_notification_message(infrared, InfraredNotificationMessageSuccess); |             infrared_play_notification_message(infrared, InfraredNotificationMessageSuccess); | ||||||
| @ -41,6 +39,7 @@ void infrared_scene_learn_on_exit(void* context) { | |||||||
|     Infrared* infrared = context; |     Infrared* infrared = context; | ||||||
|     Popup* popup = infrared->popup; |     Popup* popup = infrared->popup; | ||||||
|     infrared_worker_rx_stop(infrared->worker); |     infrared_worker_rx_stop(infrared->worker); | ||||||
|  |     infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStop); | ||||||
|     popup_set_icon(popup, 0, 0, NULL); |     popup_set_icon(popup, 0, 0, NULL); | ||||||
|     popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignCenter); |     popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignCenter); | ||||||
| } | } | ||||||
|  | |||||||
| @ -29,7 +29,10 @@ bool infrared_scene_learn_done_on_event(void* context, SceneManagerEvent event) | |||||||
| 
 | 
 | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == InfraredCustomEventTypePopupClosed) { |         if(event.event == InfraredCustomEventTypePopupClosed) { | ||||||
|  |             if(!scene_manager_search_and_switch_to_previous_scene( | ||||||
|  |                    infrared->scene_manager, InfraredSceneRemote)) { | ||||||
|                 scene_manager_next_scene(infrared->scene_manager, InfraredSceneRemote); |                 scene_manager_next_scene(infrared->scene_manager, InfraredSceneRemote); | ||||||
|  |             } | ||||||
|             consumed = true; |             consumed = true; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -2,11 +2,6 @@ | |||||||
| 
 | 
 | ||||||
| #include <dolphin/dolphin.h> | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| typedef enum { |  | ||||||
|     InfraredSceneLearnSuccessStateIdle = 0, |  | ||||||
|     InfraredSceneLearnSuccessStateSending = 1, |  | ||||||
| } InfraredSceneLearnSuccessState; |  | ||||||
| 
 |  | ||||||
| static void | static void | ||||||
|     infrared_scene_learn_success_dialog_result_callback(DialogExResult result, void* context) { |     infrared_scene_learn_success_dialog_result_callback(DialogExResult result, void* context) { | ||||||
|     Infrared* infrared = context; |     Infrared* infrared = context; | ||||||
| @ -21,11 +16,6 @@ void infrared_scene_learn_success_on_enter(void* context) { | |||||||
|     DOLPHIN_DEED(DolphinDeedIrLearnSuccess); |     DOLPHIN_DEED(DolphinDeedIrLearnSuccess); | ||||||
|     infrared_play_notification_message(infrared, InfraredNotificationMessageGreenOn); |     infrared_play_notification_message(infrared, InfraredNotificationMessageGreenOn); | ||||||
| 
 | 
 | ||||||
|     infrared_worker_tx_set_get_signal_callback( |  | ||||||
|         infrared->worker, infrared_worker_tx_get_signal_steady_callback, context); |  | ||||||
|     infrared_worker_tx_set_signal_sent_callback( |  | ||||||
|         infrared->worker, infrared_signal_sent_callback, context); |  | ||||||
| 
 |  | ||||||
|     if(infrared_signal_is_raw(signal)) { |     if(infrared_signal_is_raw(signal)) { | ||||||
|         InfraredRawSignal* raw = infrared_signal_get_raw_signal(signal); |         InfraredRawSignal* raw = infrared_signal_get_raw_signal(signal); | ||||||
|         dialog_ex_set_header(dialog_ex, "Unknown", 95, 10, AlignCenter, AlignCenter); |         dialog_ex_set_header(dialog_ex, "Unknown", 95, 10, AlignCenter, AlignCenter); | ||||||
| @ -65,54 +55,42 @@ void infrared_scene_learn_success_on_enter(void* context) { | |||||||
|     dialog_ex_set_context(dialog_ex, context); |     dialog_ex_set_context(dialog_ex, context); | ||||||
|     dialog_ex_enable_extended_events(dialog_ex); |     dialog_ex_enable_extended_events(dialog_ex); | ||||||
| 
 | 
 | ||||||
|     scene_manager_set_scene_state( |  | ||||||
|         infrared->scene_manager, InfraredSceneLearnSuccess, InfraredSceneLearnSuccessStateIdle); |  | ||||||
|     view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewDialogEx); |     view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewDialogEx); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool infrared_scene_learn_success_on_event(void* context, SceneManagerEvent event) { | bool infrared_scene_learn_success_on_event(void* context, SceneManagerEvent event) { | ||||||
|     Infrared* infrared = context; |     Infrared* infrared = context; | ||||||
|     SceneManager* scene_manager = infrared->scene_manager; |     SceneManager* scene_manager = infrared->scene_manager; | ||||||
|     uint32_t scene_state = scene_manager_get_scene_state(scene_manager, InfraredSceneLearnSuccess); |     const bool is_transmitter_idle = !infrared->app_state.is_transmitting; | ||||||
|     bool consumed = false; |     bool consumed = false; | ||||||
| 
 | 
 | ||||||
|     if(event.type == SceneManagerEventTypeTick) { |     if(event.type == SceneManagerEventTypeTick) { | ||||||
|         if(scene_state == InfraredSceneLearnSuccessStateIdle) { |         if(is_transmitter_idle) { | ||||||
|             infrared_play_notification_message(infrared, InfraredNotificationMessageGreenOn); |             infrared_play_notification_message(infrared, InfraredNotificationMessageGreenOn); | ||||||
|         } |         } | ||||||
|         consumed = true; |         consumed = true; | ||||||
|     } else if(event.type == SceneManagerEventTypeBack) { |     } else if(event.type == SceneManagerEventTypeBack) { | ||||||
|         if(scene_state == InfraredSceneLearnSuccessStateIdle) { |         if(is_transmitter_idle) { | ||||||
|             scene_manager_next_scene(scene_manager, InfraredSceneAskBack); |             scene_manager_next_scene(scene_manager, InfraredSceneAskBack); | ||||||
|         } |         } | ||||||
|         consumed = true; |         consumed = true; | ||||||
|     } else if(event.type == SceneManagerEventTypeCustom) { |     } else if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == DialogExResultLeft) { |         if(event.event == DialogExResultLeft) { | ||||||
|             if(scene_state == InfraredSceneLearnSuccessStateIdle) { |             if(is_transmitter_idle) { | ||||||
|                 scene_manager_next_scene(scene_manager, InfraredSceneAskRetry); |                 scene_manager_next_scene(scene_manager, InfraredSceneAskRetry); | ||||||
|             } |             } | ||||||
|             consumed = true; |             consumed = true; | ||||||
|         } else if(event.event == DialogExResultRight) { |         } else if(event.event == DialogExResultRight) { | ||||||
|             if(scene_state == InfraredSceneLearnSuccessStateIdle) { |             if(is_transmitter_idle) { | ||||||
|                 scene_manager_next_scene(scene_manager, InfraredSceneLearnEnterName); |                 scene_manager_next_scene(scene_manager, InfraredSceneLearnEnterName); | ||||||
|             } |             } | ||||||
|             consumed = true; |             consumed = true; | ||||||
|         } else if(event.event == DialogExPressCenter) { |         } else if(event.event == DialogExPressCenter) { | ||||||
|             if(scene_state == InfraredSceneLearnSuccessStateIdle) { |             infrared_play_notification_message(infrared, InfraredNotificationMessageGreenOff); | ||||||
|                 scene_manager_set_scene_state( |  | ||||||
|                     scene_manager, |  | ||||||
|                     InfraredSceneLearnSuccess, |  | ||||||
|                     InfraredSceneLearnSuccessStateSending); |  | ||||||
|             infrared_tx_start_received(infrared); |             infrared_tx_start_received(infrared); | ||||||
|             } |  | ||||||
|             consumed = true; |             consumed = true; | ||||||
|         } else if(event.event == DialogExReleaseCenter) { |         } else if(event.event == DialogExReleaseCenter) { | ||||||
|             if(scene_state == InfraredSceneLearnSuccessStateSending) { |  | ||||||
|                 scene_manager_set_scene_state( |  | ||||||
|                     scene_manager, InfraredSceneLearnSuccess, InfraredSceneLearnSuccessStateIdle); |  | ||||||
|             infrared_tx_stop(infrared); |             infrared_tx_stop(infrared); | ||||||
|                 infrared_play_notification_message(infrared, InfraredNotificationMessageGreenOff); |  | ||||||
|             } |  | ||||||
|             consumed = true; |             consumed = true; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -122,9 +100,6 @@ bool infrared_scene_learn_success_on_event(void* context, SceneManagerEvent even | |||||||
| 
 | 
 | ||||||
| void infrared_scene_learn_success_on_exit(void* context) { | void infrared_scene_learn_success_on_exit(void* context) { | ||||||
|     Infrared* infrared = context; |     Infrared* infrared = context; | ||||||
|     InfraredWorker* worker = infrared->worker; |  | ||||||
|     dialog_ex_reset(infrared->dialog_ex); |     dialog_ex_reset(infrared->dialog_ex); | ||||||
|     infrared_play_notification_message(infrared, InfraredNotificationMessageGreenOff); |     infrared_play_notification_message(infrared, InfraredNotificationMessageGreenOff); | ||||||
|     infrared_worker_tx_set_get_signal_callback(worker, NULL, NULL); |  | ||||||
|     infrared_worker_tx_set_signal_sent_callback(worker, NULL, NULL); |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -31,11 +31,6 @@ void infrared_scene_remote_on_enter(void* context) { | |||||||
|     ButtonMenu* button_menu = infrared->button_menu; |     ButtonMenu* button_menu = infrared->button_menu; | ||||||
|     SceneManager* scene_manager = infrared->scene_manager; |     SceneManager* scene_manager = infrared->scene_manager; | ||||||
| 
 | 
 | ||||||
|     infrared_worker_tx_set_get_signal_callback( |  | ||||||
|         infrared->worker, infrared_worker_tx_get_signal_steady_callback, infrared); |  | ||||||
|     infrared_worker_tx_set_signal_sent_callback( |  | ||||||
|         infrared->worker, infrared_signal_sent_callback, infrared); |  | ||||||
| 
 |  | ||||||
|     size_t button_count = infrared_remote_get_button_count(remote); |     size_t button_count = infrared_remote_get_button_count(remote); | ||||||
|     for(size_t i = 0; i < button_count; ++i) { |     for(size_t i = 0; i < button_count; ++i) { | ||||||
|         InfraredRemoteButton* button = infrared_remote_get_button(remote, i); |         InfraredRemoteButton* button = infrared_remote_get_button(remote, i); | ||||||
| @ -75,12 +70,17 @@ void infrared_scene_remote_on_enter(void* context) { | |||||||
| bool infrared_scene_remote_on_event(void* context, SceneManagerEvent event) { | bool infrared_scene_remote_on_event(void* context, SceneManagerEvent event) { | ||||||
|     Infrared* infrared = context; |     Infrared* infrared = context; | ||||||
|     SceneManager* scene_manager = infrared->scene_manager; |     SceneManager* scene_manager = infrared->scene_manager; | ||||||
|  |     const bool is_transmitter_idle = !infrared->app_state.is_transmitting; | ||||||
|     bool consumed = false; |     bool consumed = false; | ||||||
| 
 | 
 | ||||||
|     if(event.type == SceneManagerEventTypeBack) { |     if(event.type == SceneManagerEventTypeBack) { | ||||||
|  |         if(is_transmitter_idle) { | ||||||
|             const uint32_t possible_scenes[] = {InfraredSceneRemoteList, InfraredSceneStart}; |             const uint32_t possible_scenes[] = {InfraredSceneRemoteList, InfraredSceneStart}; | ||||||
|             consumed = scene_manager_search_and_switch_to_previous_scene_one_of( |             consumed = scene_manager_search_and_switch_to_previous_scene_one_of( | ||||||
|             scene_manager, possible_scenes, sizeof(possible_scenes) / sizeof(uint32_t)); |                 scene_manager, possible_scenes, COUNT_OF(possible_scenes)); | ||||||
|  |         } else { | ||||||
|  |             consumed = true; | ||||||
|  |         } | ||||||
|     } else if(event.type == SceneManagerEventTypeCustom) { |     } else if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         const uint16_t custom_type = infrared_custom_event_get_type(event.event); |         const uint16_t custom_type = infrared_custom_event_get_type(event.event); | ||||||
|         const int16_t button_index = infrared_custom_event_get_value(event.event); |         const int16_t button_index = infrared_custom_event_get_value(event.event); | ||||||
| @ -94,6 +94,7 @@ bool infrared_scene_remote_on_event(void* context, SceneManagerEvent event) { | |||||||
|             consumed = true; |             consumed = true; | ||||||
|         } else if(custom_type == InfraredCustomEventTypeMenuSelected) { |         } else if(custom_type == InfraredCustomEventTypeMenuSelected) { | ||||||
|             furi_assert(button_index < 0); |             furi_assert(button_index < 0); | ||||||
|  |             if(is_transmitter_idle) { | ||||||
|                 scene_manager_set_scene_state( |                 scene_manager_set_scene_state( | ||||||
|                     scene_manager, InfraredSceneRemote, (unsigned)button_index); |                     scene_manager, InfraredSceneRemote, (unsigned)button_index); | ||||||
|                 if(button_index == ButtonIndexPlus) { |                 if(button_index == ButtonIndexPlus) { | ||||||
| @ -104,6 +105,10 @@ bool infrared_scene_remote_on_event(void* context, SceneManagerEvent event) { | |||||||
|                     scene_manager_next_scene(scene_manager, InfraredSceneEdit); |                     scene_manager_next_scene(scene_manager, InfraredSceneEdit); | ||||||
|                     consumed = true; |                     consumed = true; | ||||||
|                 } |                 } | ||||||
|  | 
 | ||||||
|  |             } else { | ||||||
|  |                 consumed = true; | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -112,7 +117,5 @@ bool infrared_scene_remote_on_event(void* context, SceneManagerEvent event) { | |||||||
| 
 | 
 | ||||||
| void infrared_scene_remote_on_exit(void* context) { | void infrared_scene_remote_on_exit(void* context) { | ||||||
|     Infrared* infrared = context; |     Infrared* infrared = context; | ||||||
|     infrared_worker_tx_set_get_signal_callback(infrared->worker, NULL, NULL); |  | ||||||
|     infrared_worker_tx_set_signal_sent_callback(infrared->worker, NULL, NULL); |  | ||||||
|     button_menu_reset(infrared->button_menu); |     button_menu_reset(infrared->button_menu); | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,20 +1,28 @@ | |||||||
| #include "../infrared_i.h" | #include "../infrared_i.h" | ||||||
| #include "gui/canvas.h" | #include "gui/canvas.h" | ||||||
| 
 | 
 | ||||||
|  | typedef enum { | ||||||
|  |     InfraredRpcStateIdle, | ||||||
|  |     InfraredRpcStateLoaded, | ||||||
|  |     InfraredRpcStateSending, | ||||||
|  | } InfraredRpcState; | ||||||
|  | 
 | ||||||
| void infrared_scene_rpc_on_enter(void* context) { | void infrared_scene_rpc_on_enter(void* context) { | ||||||
|     Infrared* infrared = context; |     Infrared* infrared = context; | ||||||
|     Popup* popup = infrared->popup; |     Popup* popup = infrared->popup; | ||||||
| 
 | 
 | ||||||
|     popup_set_header(popup, "Infrared", 82, 28, AlignCenter, AlignBottom); |     popup_set_header(popup, "Infrared", 89, 42, AlignCenter, AlignBottom); | ||||||
|     popup_set_text(popup, "RPC mode", 82, 32, AlignCenter, AlignTop); |     popup_set_text(popup, "RPC mode", 89, 44, AlignCenter, AlignTop); | ||||||
| 
 | 
 | ||||||
|     popup_set_icon(popup, 2, 14, &I_Warning_30x23); // TODO: icon
 |     popup_set_icon(popup, 0, 12, &I_RFIDDolphinSend_97x61); | ||||||
| 
 | 
 | ||||||
|     popup_set_context(popup, context); |     popup_set_context(popup, context); | ||||||
|     popup_set_callback(popup, infrared_popup_closed_callback); |     popup_set_callback(popup, infrared_popup_closed_callback); | ||||||
| 
 | 
 | ||||||
|     view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewPopup); |     view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewPopup); | ||||||
| 
 | 
 | ||||||
|  |     scene_manager_set_scene_state(infrared->scene_manager, InfraredSceneRpc, InfraredRpcStateIdle); | ||||||
|  | 
 | ||||||
|     notification_message(infrared->notifications, &sequence_display_backlight_on); |     notification_message(infrared->notifications, &sequence_display_backlight_on); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -24,6 +32,8 @@ bool infrared_scene_rpc_on_event(void* context, SceneManagerEvent event) { | |||||||
| 
 | 
 | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         consumed = true; |         consumed = true; | ||||||
|  |         InfraredRpcState state = | ||||||
|  |             scene_manager_get_scene_state(infrared->scene_manager, InfraredSceneRpc); | ||||||
|         if(event.event == InfraredCustomEventTypeBackPressed) { |         if(event.event == InfraredCustomEventTypeBackPressed) { | ||||||
|             view_dispatcher_stop(infrared->view_dispatcher); |             view_dispatcher_stop(infrared->view_dispatcher); | ||||||
|         } else if(event.event == InfraredCustomEventTypePopupClosed) { |         } else if(event.event == InfraredCustomEventTypePopupClosed) { | ||||||
| @ -31,41 +41,49 @@ bool infrared_scene_rpc_on_event(void* context, SceneManagerEvent event) { | |||||||
|         } else if(event.event == InfraredCustomEventTypeRpcLoad) { |         } else if(event.event == InfraredCustomEventTypeRpcLoad) { | ||||||
|             bool result = false; |             bool result = false; | ||||||
|             const char* arg = rpc_system_app_get_data(infrared->rpc_ctx); |             const char* arg = rpc_system_app_get_data(infrared->rpc_ctx); | ||||||
|             if(arg) { |             if(arg && (state == InfraredRpcStateIdle)) { | ||||||
|                 string_set_str(infrared->file_path, arg); |                 string_set_str(infrared->file_path, arg); | ||||||
|                 result = infrared_remote_load(infrared->remote, infrared->file_path); |                 result = infrared_remote_load(infrared->remote, infrared->file_path); | ||||||
|                 infrared_worker_tx_set_get_signal_callback( |                 if(result) { | ||||||
|                     infrared->worker, infrared_worker_tx_get_signal_steady_callback, infrared); |                     scene_manager_set_scene_state( | ||||||
|                 infrared_worker_tx_set_signal_sent_callback( |                         infrared->scene_manager, InfraredSceneRpc, InfraredRpcStateLoaded); | ||||||
|                     infrared->worker, infrared_signal_sent_callback, infrared); |                 } | ||||||
|             } |             } | ||||||
|             const char* remote_name = infrared_remote_get_name(infrared->remote); |             const char* remote_name = infrared_remote_get_name(infrared->remote); | ||||||
| 
 | 
 | ||||||
|             infrared_text_store_set(infrared, 0, "loaded\n%s", remote_name); |             infrared_text_store_set(infrared, 0, "loaded\n%s", remote_name); | ||||||
|             popup_set_text( |             popup_set_text( | ||||||
|                 infrared->popup, infrared->text_store[0], 82, 32, AlignCenter, AlignTop); |                 infrared->popup, infrared->text_store[0], 89, 44, AlignCenter, AlignTop); | ||||||
| 
 | 
 | ||||||
|             rpc_system_app_confirm(infrared->rpc_ctx, RpcAppEventLoadFile, result); |             rpc_system_app_confirm(infrared->rpc_ctx, RpcAppEventLoadFile, result); | ||||||
|         } else if(event.event == InfraredCustomEventTypeRpcButtonPress) { |         } else if(event.event == InfraredCustomEventTypeRpcButtonPress) { | ||||||
|             bool result = false; |             bool result = false; | ||||||
|             const char* arg = rpc_system_app_get_data(infrared->rpc_ctx); |             const char* arg = rpc_system_app_get_data(infrared->rpc_ctx); | ||||||
|             if(arg) { |             if(arg && (state == InfraredRpcStateLoaded)) { | ||||||
|                 size_t button_index = 0; |                 size_t button_index = 0; | ||||||
|                 if(infrared_remote_find_button_by_name(infrared->remote, arg, &button_index)) { |                 if(infrared_remote_find_button_by_name(infrared->remote, arg, &button_index)) { | ||||||
|                     infrared_tx_start_button_index(infrared, button_index); |                     infrared_tx_start_button_index(infrared, button_index); | ||||||
|                     result = true; |                     result = true; | ||||||
|  |                     scene_manager_set_scene_state( | ||||||
|  |                         infrared->scene_manager, InfraredSceneRpc, InfraredRpcStateSending); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             rpc_system_app_confirm(infrared->rpc_ctx, RpcAppEventButtonRelease, result); |             rpc_system_app_confirm(infrared->rpc_ctx, RpcAppEventButtonRelease, result); | ||||||
|         } else if(event.event == InfraredCustomEventTypeRpcButtonRelease) { |         } else if(event.event == InfraredCustomEventTypeRpcButtonRelease) { | ||||||
|  |             bool result = false; | ||||||
|  |             if(state == InfraredRpcStateSending) { | ||||||
|                 infrared_tx_stop(infrared); |                 infrared_tx_stop(infrared); | ||||||
|             rpc_system_app_confirm(infrared->rpc_ctx, RpcAppEventButtonRelease, true); |                 result = true; | ||||||
|  |                 scene_manager_set_scene_state( | ||||||
|  |                     infrared->scene_manager, InfraredSceneRpc, InfraredRpcStateLoaded); | ||||||
|  |             } | ||||||
|  |             rpc_system_app_confirm(infrared->rpc_ctx, RpcAppEventButtonRelease, result); | ||||||
|         } else if(event.event == InfraredCustomEventTypeRpcExit) { |         } else if(event.event == InfraredCustomEventTypeRpcExit) { | ||||||
|  |             scene_manager_stop(infrared->scene_manager); | ||||||
|             view_dispatcher_stop(infrared->view_dispatcher); |             view_dispatcher_stop(infrared->view_dispatcher); | ||||||
|             rpc_system_app_confirm(infrared->rpc_ctx, RpcAppEventAppExit, true); |             rpc_system_app_confirm(infrared->rpc_ctx, RpcAppEventAppExit, true); | ||||||
|         } else if(event.event == InfraredCustomEventTypeRpcSessionClose) { |         } else if(event.event == InfraredCustomEventTypeRpcSessionClose) { | ||||||
|             rpc_system_app_set_callback(infrared->rpc_ctx, NULL, NULL); |             scene_manager_stop(infrared->scene_manager); | ||||||
|             infrared->rpc_ctx = NULL; |  | ||||||
|             view_dispatcher_stop(infrared->view_dispatcher); |             view_dispatcher_stop(infrared->view_dispatcher); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -74,5 +92,9 @@ bool infrared_scene_rpc_on_event(void* context, SceneManagerEvent event) { | |||||||
| 
 | 
 | ||||||
| void infrared_scene_rpc_on_exit(void* context) { | void infrared_scene_rpc_on_exit(void* context) { | ||||||
|     Infrared* infrared = context; |     Infrared* infrared = context; | ||||||
|  |     if(scene_manager_get_scene_state(infrared->scene_manager, InfraredSceneRpc) == | ||||||
|  |        InfraredRpcStateSending) { | ||||||
|  |         infrared_tx_stop(infrared); | ||||||
|  |     } | ||||||
|     popup_reset(infrared->popup); |     popup_reset(infrared->popup); | ||||||
| } | } | ||||||
|  | |||||||
| @ -64,7 +64,8 @@ const char* input_get_type_name(InputType type) { | |||||||
|     return "Unknown"; |     return "Unknown"; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int32_t input_srv() { | int32_t input_srv(void* p) { | ||||||
|  |     UNUSED(p); | ||||||
|     input = malloc(sizeof(Input)); |     input = malloc(sizeof(Input)); | ||||||
|     input->thread_id = furi_thread_get_current_id(); |     input->thread_id = furi_thread_get_current_id(); | ||||||
|     input->event_pubsub = furi_pubsub_alloc(); |     input->event_pubsub = furi_pubsub_alloc(); | ||||||
|  | |||||||
| @ -56,6 +56,9 @@ static void rpc_command_callback(RpcAppSystemEvent rpc_event, void* context) { | |||||||
|         LfRfidApp::Event event; |         LfRfidApp::Event event; | ||||||
|         event.type = LfRfidApp::EventType::RpcSessionClose; |         event.type = LfRfidApp::EventType::RpcSessionClose; | ||||||
|         app->view_controller.send_event(&event); |         app->view_controller.send_event(&event); | ||||||
|  |         // Detach RPC
 | ||||||
|  |         rpc_system_app_set_callback(app->rpc_ctx, NULL, NULL); | ||||||
|  |         app->rpc_ctx = NULL; | ||||||
|     } else if(rpc_event == RpcAppEventAppExit) { |     } else if(rpc_event == RpcAppEventAppExit) { | ||||||
|         LfRfidApp::Event event; |         LfRfidApp::Event event; | ||||||
|         event.type = LfRfidApp::EventType::Exit; |         event.type = LfRfidApp::EventType::Exit; | ||||||
| @ -74,22 +77,25 @@ void LfRfidApp::run(void* _args) { | |||||||
| 
 | 
 | ||||||
|     make_app_folder(); |     make_app_folder(); | ||||||
| 
 | 
 | ||||||
|     if(strlen(args)) { |     if(args && strlen(args)) { | ||||||
|         uint32_t rpc_ctx_ptr = 0; |         uint32_t rpc_ctx_ptr = 0; | ||||||
|         if(sscanf(args, "RPC %lX", &rpc_ctx_ptr) == 1) { |         if(sscanf(args, "RPC %lX", &rpc_ctx_ptr) == 1) { | ||||||
|             rpc_ctx = (RpcAppSystem*)rpc_ctx_ptr; |             rpc_ctx = (RpcAppSystem*)rpc_ctx_ptr; | ||||||
|             rpc_system_app_set_callback(rpc_ctx, rpc_command_callback, this); |             rpc_system_app_set_callback(rpc_ctx, rpc_command_callback, this); | ||||||
|             rpc_system_app_send_started(rpc_ctx); |             rpc_system_app_send_started(rpc_ctx); | ||||||
|  |             view_controller.attach_to_gui(ViewDispatcherTypeDesktop); | ||||||
|             scene_controller.add_scene(SceneType::Rpc, new LfRfidAppSceneRpc()); |             scene_controller.add_scene(SceneType::Rpc, new LfRfidAppSceneRpc()); | ||||||
|             scene_controller.process(100, SceneType::Rpc); |             scene_controller.process(100, SceneType::Rpc); | ||||||
|         } else { |         } else { | ||||||
|             string_set_str(file_path, args); |             string_set_str(file_path, args); | ||||||
|             load_key_data(file_path, &worker.key, true); |             load_key_data(file_path, &worker.key, true); | ||||||
|  |             view_controller.attach_to_gui(ViewDispatcherTypeFullscreen); | ||||||
|             scene_controller.add_scene(SceneType::Emulate, new LfRfidAppSceneEmulate()); |             scene_controller.add_scene(SceneType::Emulate, new LfRfidAppSceneEmulate()); | ||||||
|             scene_controller.process(100, SceneType::Emulate); |             scene_controller.process(100, SceneType::Emulate); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|     } else { |     } else { | ||||||
|  |         view_controller.attach_to_gui(ViewDispatcherTypeFullscreen); | ||||||
|         scene_controller.add_scene(SceneType::Start, new LfRfidAppSceneStart()); |         scene_controller.add_scene(SceneType::Start, new LfRfidAppSceneStart()); | ||||||
|         scene_controller.add_scene(SceneType::Read, new LfRfidAppSceneRead()); |         scene_controller.add_scene(SceneType::Read, new LfRfidAppSceneRead()); | ||||||
|         scene_controller.add_scene(SceneType::RetryConfirm, new LfRfidAppSceneRetryConfirm()); |         scene_controller.add_scene(SceneType::RetryConfirm, new LfRfidAppSceneRetryConfirm()); | ||||||
|  | |||||||
| @ -101,5 +101,4 @@ public: | |||||||
|     bool save_key_data(string_t path, RfidKey* key); |     bool save_key_data(string_t path, RfidKey* key); | ||||||
| 
 | 
 | ||||||
|     void make_app_folder(); |     void make_app_folder(); | ||||||
|     //bool rpc_command_callback(RpcAppSystemEvent event, const char* arg, void* context);
 |  | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -107,7 +107,7 @@ static void lfrfid_cli_write(Cli* cli, string_t args) { | |||||||
|     UNUSED(cli); |     UNUSED(cli); | ||||||
|     UNUSED(args); |     UNUSED(args); | ||||||
|     // TODO implement rfid write
 |     // TODO implement rfid write
 | ||||||
|     printf("Not implemented :(\r\n"); |     printf("Not Implemented :(\r\n"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void lfrfid_cli_emulate(Cli* cli, string_t args) { | static void lfrfid_cli_emulate(Cli* cli, string_t args) { | ||||||
|  | |||||||
| @ -2,18 +2,6 @@ | |||||||
| #include <core/common_defines.h> | #include <core/common_defines.h> | ||||||
| #include <dolphin/dolphin.h> | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| static const NotificationSequence sequence_blink_start_magenta = { |  | ||||||
|     &message_blink_start_10, |  | ||||||
|     &message_blink_set_color_magenta, |  | ||||||
|     &message_do_not_reset, |  | ||||||
|     NULL, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| static const NotificationSequence sequence_blink_stop = { |  | ||||||
|     &message_blink_stop, |  | ||||||
|     NULL, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| void LfRfidAppSceneEmulate::on_enter(LfRfidApp* app, bool /* need_restore */) { | void LfRfidAppSceneEmulate::on_enter(LfRfidApp* app, bool /* need_restore */) { | ||||||
|     string_init(data_string); |     string_init(data_string); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -17,9 +17,9 @@ void LfRfidAppSceneExitConfirm::on_enter(LfRfidApp* app, bool /* need_restore */ | |||||||
|     auto line_1 = container->add<StringElement>(); |     auto line_1 = container->add<StringElement>(); | ||||||
|     auto line_2 = container->add<StringElement>(); |     auto line_2 = container->add<StringElement>(); | ||||||
| 
 | 
 | ||||||
|     line_1->set_text("Exit to RFID menu?", 64, 19, 128 - 2, AlignCenter, AlignBottom, FontPrimary); |     line_1->set_text("Exit to RFID Menu?", 64, 19, 128 - 2, AlignCenter, AlignBottom, FontPrimary); | ||||||
|     line_2->set_text( |     line_2->set_text( | ||||||
|         "All unsaved data will be lost.", 64, 31, 0, AlignCenter, AlignBottom, FontSecondary); |         "All unsaved data will be lost!", 64, 31, 0, AlignCenter, AlignBottom, FontSecondary); | ||||||
| 
 | 
 | ||||||
|     app->view_controller.switch_to<ContainerVM>(); |     app->view_controller.switch_to<ContainerVM>(); | ||||||
| } | } | ||||||
|  | |||||||
| @ -17,9 +17,9 @@ void LfRfidAppSceneRetryConfirm::on_enter(LfRfidApp* app, bool /* need_restore * | |||||||
|     auto line_1 = container->add<StringElement>(); |     auto line_1 = container->add<StringElement>(); | ||||||
|     auto line_2 = container->add<StringElement>(); |     auto line_2 = container->add<StringElement>(); | ||||||
| 
 | 
 | ||||||
|     line_1->set_text("Return to reading?", 64, 19, 128 - 2, AlignCenter, AlignBottom, FontPrimary); |     line_1->set_text("Return to Reading?", 64, 19, 128 - 2, AlignCenter, AlignBottom, FontPrimary); | ||||||
|     line_2->set_text( |     line_2->set_text( | ||||||
|         "All unsaved data will be lost.", 64, 29, 0, AlignCenter, AlignBottom, FontSecondary); |         "All unsaved data will be lost!", 64, 29, 0, AlignCenter, AlignBottom, FontSecondary); | ||||||
| 
 | 
 | ||||||
|     app->view_controller.switch_to<ContainerVM>(); |     app->view_controller.switch_to<ContainerVM>(); | ||||||
| } | } | ||||||
|  | |||||||
| @ -3,24 +3,12 @@ | |||||||
| #include <dolphin/dolphin.h> | #include <dolphin/dolphin.h> | ||||||
| #include <rpc/rpc_app.h> | #include <rpc/rpc_app.h> | ||||||
| 
 | 
 | ||||||
| static const NotificationSequence sequence_blink_start_magenta = { |  | ||||||
|     &message_blink_start_10, |  | ||||||
|     &message_blink_set_color_magenta, |  | ||||||
|     &message_do_not_reset, |  | ||||||
|     NULL, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| static const NotificationSequence sequence_blink_stop = { |  | ||||||
|     &message_blink_stop, |  | ||||||
|     NULL, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| void LfRfidAppSceneRpc::on_enter(LfRfidApp* app, bool /* need_restore */) { | void LfRfidAppSceneRpc::on_enter(LfRfidApp* app, bool /* need_restore */) { | ||||||
|     auto popup = app->view_controller.get<PopupVM>(); |     auto popup = app->view_controller.get<PopupVM>(); | ||||||
| 
 | 
 | ||||||
|     popup->set_header("LF RFID", 89, 30, AlignCenter, AlignTop); |     popup->set_header("LF RFID", 89, 42, AlignCenter, AlignBottom); | ||||||
|     popup->set_text("RPC mode", 89, 43, AlignCenter, AlignTop); |     popup->set_text("RPC mode", 89, 44, AlignCenter, AlignTop); | ||||||
|     popup->set_icon(0, 3, &I_RFIDDolphinSend_97x61); |     popup->set_icon(0, 12, &I_RFIDDolphinSend_97x61); | ||||||
| 
 | 
 | ||||||
|     app->view_controller.switch_to<PopupVM>(); |     app->view_controller.switch_to<PopupVM>(); | ||||||
| 
 | 
 | ||||||
| @ -39,33 +27,25 @@ bool LfRfidAppSceneRpc::on_event(LfRfidApp* app, LfRfidApp::Event* event) { | |||||||
|         app->view_controller.send_event(&view_event); |         app->view_controller.send_event(&view_event); | ||||||
|         rpc_system_app_confirm(app->rpc_ctx, RpcAppEventAppExit, true); |         rpc_system_app_confirm(app->rpc_ctx, RpcAppEventAppExit, true); | ||||||
|     } else if(event->type == LfRfidApp::EventType::RpcSessionClose) { |     } else if(event->type == LfRfidApp::EventType::RpcSessionClose) { | ||||||
|         // Detach RPC
 |  | ||||||
|         rpc_system_app_set_callback(app->rpc_ctx, NULL, NULL); |  | ||||||
|         app->rpc_ctx = NULL; |  | ||||||
| 
 |  | ||||||
|         consumed = true; |         consumed = true; | ||||||
|         LfRfidApp::Event view_event; |         LfRfidApp::Event view_event; | ||||||
|         view_event.type = LfRfidApp::EventType::Back; |         view_event.type = LfRfidApp::EventType::Back; | ||||||
|         app->view_controller.send_event(&view_event); |         app->view_controller.send_event(&view_event); | ||||||
|     } else if(event->type == LfRfidApp::EventType::EmulateStart) { |  | ||||||
|         auto popup = app->view_controller.get<PopupVM>(); |  | ||||||
|         consumed = true; |  | ||||||
|         emulating = true; |  | ||||||
| 
 |  | ||||||
|         app->text_store.set("emulating\n%s", app->worker.key.get_name()); |  | ||||||
|         popup->set_text(app->text_store.text, 89, 43, AlignCenter, AlignTop); |  | ||||||
| 
 |  | ||||||
|         notification_message(app->notification, &sequence_blink_start_magenta); |  | ||||||
|     } else if(event->type == LfRfidApp::EventType::RpcLoadFile) { |     } else if(event->type == LfRfidApp::EventType::RpcLoadFile) { | ||||||
|         const char* arg = rpc_system_app_get_data(app->rpc_ctx); |         const char* arg = rpc_system_app_get_data(app->rpc_ctx); | ||||||
|  |         consumed = true; | ||||||
|         bool result = false; |         bool result = false; | ||||||
|         if(arg) { |         if(arg && !emulating) { | ||||||
|             string_set_str(app->file_path, arg); |             string_set_str(app->file_path, arg); | ||||||
|             if(app->load_key_data(app->file_path, &(app->worker.key), false)) { |             if(app->load_key_data(app->file_path, &(app->worker.key), false)) { | ||||||
|                 LfRfidApp::Event event; |  | ||||||
|                 event.type = LfRfidApp::EventType::EmulateStart; |  | ||||||
|                 app->view_controller.send_event(&event); |  | ||||||
|                 app->worker.start_emulate(); |                 app->worker.start_emulate(); | ||||||
|  |                 emulating = true; | ||||||
|  | 
 | ||||||
|  |                 auto popup = app->view_controller.get<PopupVM>(); | ||||||
|  |                 app->text_store.set("emulating\n%s", app->worker.key.get_name()); | ||||||
|  |                 popup->set_text(app->text_store.text, 89, 44, AlignCenter, AlignTop); | ||||||
|  | 
 | ||||||
|  |                 notification_message(app->notification, &sequence_blink_start_magenta); | ||||||
|                 result = true; |                 result = true; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -10,6 +10,7 @@ LfRfidDebugApp::~LfRfidDebugApp() { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void LfRfidDebugApp::run() { | void LfRfidDebugApp::run() { | ||||||
|  |     view_controller.attach_to_gui(ViewDispatcherTypeFullscreen); | ||||||
|     scene_controller.add_scene(SceneType::Start, new LfRfidDebugAppSceneStart()); |     scene_controller.add_scene(SceneType::Start, new LfRfidDebugAppSceneStart()); | ||||||
|     scene_controller.add_scene(SceneType::TuneScene, new LfRfidDebugAppSceneTune()); |     scene_controller.add_scene(SceneType::TuneScene, new LfRfidDebugAppSceneTune()); | ||||||
|     scene_controller.process(100); |     scene_controller.process(100); | ||||||
|  | |||||||
| @ -5,6 +5,6 @@ App( | |||||||
|     entry_point="loader_srv", |     entry_point="loader_srv", | ||||||
|     cdefines=["SRV_LOADER"], |     cdefines=["SRV_LOADER"], | ||||||
|     requires=["gui"], |     requires=["gui"], | ||||||
|     stack_size=1 * 1024, |     stack_size=2 * 1024, | ||||||
|     order=90, |     order=90, | ||||||
| ) | ) | ||||||
|  | |||||||
| @ -466,9 +466,9 @@ int32_t loader_srv(void* p) { | |||||||
| 
 | 
 | ||||||
|     furi_record_create(RECORD_LOADER, loader_instance); |     furi_record_create(RECORD_LOADER, loader_instance); | ||||||
| 
 | 
 | ||||||
| #ifdef LOADER_AUTOSTART |     if(FLIPPER_AUTORUN_APP_NAME && strlen(FLIPPER_AUTORUN_APP_NAME)) { | ||||||
|     loader_start(loader_instance, LOADER_AUTOSTART, NULL); |         loader_start(loader_instance, FLIPPER_AUTORUN_APP_NAME, NULL); | ||||||
| #endif |     } | ||||||
| 
 | 
 | ||||||
|     while(1) { |     while(1) { | ||||||
|         uint32_t flags = |         uint32_t flags = | ||||||
|  | |||||||
| @ -300,7 +300,7 @@ int32_t music_player_app(void* p) { | |||||||
|     string_init(file_path); |     string_init(file_path); | ||||||
| 
 | 
 | ||||||
|     do { |     do { | ||||||
|         if(p) { |         if(p && strlen(p)) { | ||||||
|             string_cat_str(file_path, p); |             string_cat_str(file_path, p); | ||||||
|         } else { |         } else { | ||||||
|             string_set_str(file_path, MUSIC_PLAYER_APP_PATH_FOLDER); |             string_set_str(file_path, MUSIC_PLAYER_APP_PATH_FOLDER); | ||||||
|  | |||||||
| @ -10,7 +10,7 @@ App( | |||||||
|     ], |     ], | ||||||
|     provides=["nfc_start"], |     provides=["nfc_start"], | ||||||
|     icon="A_NFC_14", |     icon="A_NFC_14", | ||||||
|     stack_size=4 * 1024, |     stack_size=5 * 1024, | ||||||
|     order=30, |     order=30, | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -55,6 +55,7 @@ static void nfc_generate_mf_ul_orig(NfcDeviceData* data) { | |||||||
|     MfUltralightData* mful = &data->mf_ul_data; |     MfUltralightData* mful = &data->mf_ul_data; | ||||||
|     mful->type = MfUltralightTypeUnknown; |     mful->type = MfUltralightTypeUnknown; | ||||||
|     mful->data_size = 16 * 4; |     mful->data_size = 16 * 4; | ||||||
|  |     mful->data_read = mful->data_size; | ||||||
|     nfc_generate_mf_ul_copy_uid_with_bcc(data); |     nfc_generate_mf_ul_copy_uid_with_bcc(data); | ||||||
|     // TODO: what's internal byte on page 2?
 |     // TODO: what's internal byte on page 2?
 | ||||||
|     memset(&mful->data[4 * 4], 0xFF, 4); |     memset(&mful->data[4 * 4], 0xFF, 4); | ||||||
| @ -67,6 +68,7 @@ static void nfc_generate_mf_ul_ntag203(NfcDeviceData* data) { | |||||||
|     MfUltralightData* mful = &data->mf_ul_data; |     MfUltralightData* mful = &data->mf_ul_data; | ||||||
|     mful->type = MfUltralightTypeNTAG203; |     mful->type = MfUltralightTypeNTAG203; | ||||||
|     mful->data_size = 42 * 4; |     mful->data_size = 42 * 4; | ||||||
|  |     mful->data_read = mful->data_size; | ||||||
|     nfc_generate_mf_ul_copy_uid_with_bcc(data); |     nfc_generate_mf_ul_copy_uid_with_bcc(data); | ||||||
|     mful->data[9] = 0x48; // Internal byte
 |     mful->data[9] = 0x48; // Internal byte
 | ||||||
|     memcpy(&mful->data[3 * 4], default_data_ntag203, sizeof(default_data_ntag203)); |     memcpy(&mful->data[3 * 4], default_data_ntag203, sizeof(default_data_ntag203)); | ||||||
| @ -78,6 +80,7 @@ static void nfc_generate_mf_ul_with_config_common(NfcDeviceData* data, uint8_t n | |||||||
| 
 | 
 | ||||||
|     MfUltralightData* mful = &data->mf_ul_data; |     MfUltralightData* mful = &data->mf_ul_data; | ||||||
|     mful->data_size = num_pages * 4; |     mful->data_size = num_pages * 4; | ||||||
|  |     mful->data_read = mful->data_size; | ||||||
|     nfc_generate_mf_ul_copy_uid_with_bcc(data); |     nfc_generate_mf_ul_copy_uid_with_bcc(data); | ||||||
|     uint16_t config_index = (num_pages - 4) * 4; |     uint16_t config_index = (num_pages - 4) * 4; | ||||||
|     mful->data[config_index] = 0x04; // STRG_MOD_EN
 |     mful->data[config_index] = 0x04; // STRG_MOD_EN
 | ||||||
| @ -180,6 +183,7 @@ static void | |||||||
|     mful->type = type; |     mful->type = type; | ||||||
|     memcpy(&mful->version, version_bytes_ntag_i2c, sizeof(version_bytes_ntag_i2c)); |     memcpy(&mful->version, version_bytes_ntag_i2c, sizeof(version_bytes_ntag_i2c)); | ||||||
|     mful->data_size = num_pages * 4; |     mful->data_size = num_pages * 4; | ||||||
|  |     mful->data_read = mful->data_size; | ||||||
|     memcpy(mful->data, data->nfc_data.uid, data->nfc_data.uid_len); |     memcpy(mful->data, data->nfc_data.uid, data->nfc_data.uid_len); | ||||||
|     mful->data[7] = data->nfc_data.sak; |     mful->data[7] = data->nfc_data.sak; | ||||||
|     mful->data[8] = data->nfc_data.atqa[0]; |     mful->data[8] = data->nfc_data.atqa[0]; | ||||||
|  | |||||||
| @ -21,6 +21,8 @@ static void nfc_rpc_command_callback(RpcAppSystemEvent event, void* context) { | |||||||
| 
 | 
 | ||||||
|     if(event == RpcAppEventSessionClose) { |     if(event == RpcAppEventSessionClose) { | ||||||
|         view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventRpcSessionClose); |         view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventRpcSessionClose); | ||||||
|  |         rpc_system_app_set_callback(nfc->rpc_ctx, NULL, NULL); | ||||||
|  |         nfc->rpc_ctx = NULL; | ||||||
|     } else if(event == RpcAppEventAppExit) { |     } else if(event == RpcAppEventAppExit) { | ||||||
|         view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); |         view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); | ||||||
|     } else if(event == RpcAppEventLoadFile) { |     } else if(event == RpcAppEventLoadFile) { | ||||||
| @ -199,18 +201,6 @@ void nfc_text_store_clear(Nfc* nfc) { | |||||||
|     memset(nfc->text_store, 0, sizeof(nfc->text_store)); |     memset(nfc->text_store, 0, sizeof(nfc->text_store)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static const NotificationSequence sequence_blink_start_blue = { |  | ||||||
|     &message_blink_start_10, |  | ||||||
|     &message_blink_set_color_blue, |  | ||||||
|     &message_do_not_reset, |  | ||||||
|     NULL, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| static const NotificationSequence sequence_blink_stop = { |  | ||||||
|     &message_blink_stop, |  | ||||||
|     NULL, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| void nfc_blink_start(Nfc* nfc) { | void nfc_blink_start(Nfc* nfc) { | ||||||
|     notification_message(nfc->notifications, &sequence_blink_start_blue); |     notification_message(nfc->notifications, &sequence_blink_start_blue); | ||||||
| } | } | ||||||
| @ -238,7 +228,7 @@ int32_t nfc_app(void* p) { | |||||||
|     char* args = p; |     char* args = p; | ||||||
| 
 | 
 | ||||||
|     // Check argument and run corresponding scene
 |     // Check argument and run corresponding scene
 | ||||||
|     if((*args != '\0')) { |     if(args && strlen(args)) { | ||||||
|         nfc_device_set_loading_callback(nfc->dev, nfc_show_loading_popup, nfc); |         nfc_device_set_loading_callback(nfc->dev, nfc_show_loading_popup, nfc); | ||||||
|         uint32_t rpc_ctx = 0; |         uint32_t rpc_ctx = 0; | ||||||
|         if(sscanf(p, "RPC %lX", &rpc_ctx) == 1) { |         if(sscanf(p, "RPC %lX", &rpc_ctx) == 1) { | ||||||
|  | |||||||
							
								
								
									
										0
									
								
								applications/nfc/nfc_i.h
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										0
									
								
								applications/nfc/nfc_i.h
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							| @ -15,11 +15,17 @@ ADD_SCENE(nfc, emulate_uid, EmulateUid) | |||||||
| ADD_SCENE(nfc, mf_ultralight_read_success, MfUltralightReadSuccess) | ADD_SCENE(nfc, mf_ultralight_read_success, MfUltralightReadSuccess) | ||||||
| ADD_SCENE(nfc, mf_ultralight_menu, MfUltralightMenu) | ADD_SCENE(nfc, mf_ultralight_menu, MfUltralightMenu) | ||||||
| ADD_SCENE(nfc, mf_ultralight_emulate, MfUltralightEmulate) | ADD_SCENE(nfc, mf_ultralight_emulate, MfUltralightEmulate) | ||||||
|  | ADD_SCENE(nfc, mf_ultralight_read_auth, MfUltralightReadAuth) | ||||||
|  | ADD_SCENE(nfc, mf_ultralight_read_auth_result, MfUltralightReadAuthResult) | ||||||
|  | ADD_SCENE(nfc, mf_ultralight_key_input, MfUltralightKeyInput) | ||||||
|  | ADD_SCENE(nfc, mf_ultralight_unlock_menu, MfUltralightUnlockMenu) | ||||||
|  | ADD_SCENE(nfc, mf_ultralight_unlock_warn, MfUltralightUnlockWarn) | ||||||
| ADD_SCENE(nfc, mf_desfire_read_success, MfDesfireReadSuccess) | ADD_SCENE(nfc, mf_desfire_read_success, MfDesfireReadSuccess) | ||||||
| ADD_SCENE(nfc, mf_desfire_menu, MfDesfireMenu) | ADD_SCENE(nfc, mf_desfire_menu, MfDesfireMenu) | ||||||
| ADD_SCENE(nfc, mf_desfire_data, MfDesfireData) | ADD_SCENE(nfc, mf_desfire_data, MfDesfireData) | ||||||
| ADD_SCENE(nfc, mf_desfire_app, MfDesfireApp) | ADD_SCENE(nfc, mf_desfire_app, MfDesfireApp) | ||||||
| ADD_SCENE(nfc, mf_classic_read_success, MfClassicReadSuccess) | ADD_SCENE(nfc, mf_classic_read_success, MfClassicReadSuccess) | ||||||
|  | ADD_SCENE(nfc, mf_classic_info, MfClassicInfo) | ||||||
| ADD_SCENE(nfc, mf_classic_menu, MfClassicMenu) | ADD_SCENE(nfc, mf_classic_menu, MfClassicMenu) | ||||||
| ADD_SCENE(nfc, mf_classic_emulate, MfClassicEmulate) | ADD_SCENE(nfc, mf_classic_emulate, MfClassicEmulate) | ||||||
| ADD_SCENE(nfc, mf_classic_keys, MfClassicKeys) | ADD_SCENE(nfc, mf_classic_keys, MfClassicKeys) | ||||||
|  | |||||||
| @ -37,7 +37,7 @@ static void nfc_scene_detect_reader_widget_config(Nfc* nfc, bool data_received) | |||||||
| 
 | 
 | ||||||
|     widget_add_icon_element(widget, 0, 14, &I_Reader_detect); |     widget_add_icon_element(widget, 0, 14, &I_Reader_detect); | ||||||
|     widget_add_string_element( |     widget_add_string_element( | ||||||
|         widget, 64, 3, AlignCenter, AlignTop, FontSecondary, "Hold near reader"); |         widget, 64, 3, AlignCenter, AlignTop, FontSecondary, "Hold Near Reader"); | ||||||
|     widget_add_string_element(widget, 55, 22, AlignLeft, AlignTop, FontPrimary, "Emulating..."); |     widget_add_string_element(widget, 55, 22, AlignLeft, AlignTop, FontPrimary, "Emulating..."); | ||||||
| 
 | 
 | ||||||
|     if(data_received) { |     if(data_received) { | ||||||
|  | |||||||
| @ -12,9 +12,9 @@ void nfc_scene_exit_confirm_on_enter(void* context) { | |||||||
| 
 | 
 | ||||||
|     dialog_ex_set_left_button_text(dialog_ex, "Exit"); |     dialog_ex_set_left_button_text(dialog_ex, "Exit"); | ||||||
|     dialog_ex_set_right_button_text(dialog_ex, "Stay"); |     dialog_ex_set_right_button_text(dialog_ex, "Stay"); | ||||||
|     dialog_ex_set_header(dialog_ex, "Exit to NFC menu?", 64, 11, AlignCenter, AlignTop); |     dialog_ex_set_header(dialog_ex, "Exit to NFC Menu?", 64, 11, AlignCenter, AlignTop); | ||||||
|     dialog_ex_set_text( |     dialog_ex_set_text( | ||||||
|         dialog_ex, "All unsaved data\nwill be lost.", 64, 25, AlignCenter, AlignTop); |         dialog_ex, "All unsaved data\nwill be lost!", 64, 25, AlignCenter, AlignTop); | ||||||
|     dialog_ex_set_context(dialog_ex, nfc); |     dialog_ex_set_context(dialog_ex, nfc); | ||||||
|     dialog_ex_set_result_callback(dialog_ex, nfc_scene_exit_confirm_dialog_callback); |     dialog_ex_set_result_callback(dialog_ex, nfc_scene_exit_confirm_dialog_callback); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -2,6 +2,7 @@ | |||||||
| 
 | 
 | ||||||
| enum SubmenuIndex { | enum SubmenuIndex { | ||||||
|     SubmenuIndexMfClassicKeys, |     SubmenuIndexMfClassicKeys, | ||||||
|  |     SubmenuIndexMfUltralightUnlock, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| void nfc_scene_extra_actions_submenu_callback(void* context, uint32_t index) { | void nfc_scene_extra_actions_submenu_callback(void* context, uint32_t index) { | ||||||
| @ -20,6 +21,12 @@ void nfc_scene_extra_actions_on_enter(void* context) { | |||||||
|         SubmenuIndexMfClassicKeys, |         SubmenuIndexMfClassicKeys, | ||||||
|         nfc_scene_extra_actions_submenu_callback, |         nfc_scene_extra_actions_submenu_callback, | ||||||
|         nfc); |         nfc); | ||||||
|  |     submenu_add_item( | ||||||
|  |         submenu, | ||||||
|  |         "Unlock NTAG/Ultralight", | ||||||
|  |         SubmenuIndexMfUltralightUnlock, | ||||||
|  |         nfc_scene_extra_actions_submenu_callback, | ||||||
|  |         nfc); | ||||||
|     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); |     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -35,6 +42,8 @@ bool nfc_scene_extra_actions_on_event(void* context, SceneManagerEvent event) { | |||||||
|                 scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound); |                 scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound); | ||||||
|             } |             } | ||||||
|             consumed = true; |             consumed = true; | ||||||
|  |         } else if(event.event == SubmenuIndexMfUltralightUnlock) { | ||||||
|  |             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockMenu); | ||||||
|         } |         } | ||||||
|         scene_manager_set_scene_state(nfc->scene_manager, NfcSceneExtraActions, event.event); |         scene_manager_set_scene_state(nfc->scene_manager, NfcSceneExtraActions, event.event); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -1,5 +1,7 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
| 
 | 
 | ||||||
|  | #define TAG "NfcMfClassicDictAttack" | ||||||
|  | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     DictAttackStateIdle, |     DictAttackStateIdle, | ||||||
|     DictAttackStateUserDictInProgress, |     DictAttackStateUserDictInProgress, | ||||||
| @ -32,7 +34,9 @@ static void nfc_scene_mf_classic_dict_attack_update_view(Nfc* nfc) { | |||||||
| 
 | 
 | ||||||
| static void nfc_scene_mf_classic_dict_attack_prepare_view(Nfc* nfc, DictAttackState state) { | static void nfc_scene_mf_classic_dict_attack_prepare_view(Nfc* nfc, DictAttackState state) { | ||||||
|     MfClassicData* data = &nfc->dev->dev_data.mf_classic_data; |     MfClassicData* data = &nfc->dev->dev_data.mf_classic_data; | ||||||
|  |     NfcMfClassicDictAttackData* dict_attack_data = &nfc->dev->dev_data.mf_classic_dict_attack_data; | ||||||
|     NfcWorkerState worker_state = NfcWorkerStateReady; |     NfcWorkerState worker_state = NfcWorkerStateReady; | ||||||
|  |     MfClassicDict* dict = NULL; | ||||||
| 
 | 
 | ||||||
|     // Identify scene state
 |     // Identify scene state
 | ||||||
|     if(state == DictAttackStateIdle) { |     if(state == DictAttackStateIdle) { | ||||||
| @ -47,16 +51,36 @@ static void nfc_scene_mf_classic_dict_attack_prepare_view(Nfc* nfc, DictAttackSt | |||||||
| 
 | 
 | ||||||
|     // Setup view
 |     // Setup view
 | ||||||
|     if(state == DictAttackStateUserDictInProgress) { |     if(state == DictAttackStateUserDictInProgress) { | ||||||
|         worker_state = NfcWorkerStateMfClassicUserDictAttack; |         worker_state = NfcWorkerStateMfClassicDictAttack; | ||||||
|         dict_attack_set_header(nfc->dict_attack, "Mf Classic User Dict."); |         dict_attack_set_header(nfc->dict_attack, "Mf Classic User Dict."); | ||||||
|     } else if(state == DictAttackStateFlipperDictInProgress) { |         dict = mf_classic_dict_alloc(MfClassicDictTypeUser); | ||||||
|         worker_state = NfcWorkerStateMfClassicFlipperDictAttack; | 
 | ||||||
|         dict_attack_set_header(nfc->dict_attack, "Mf Classic Flipper Dict."); |         // If failed to load user dictionary - try flipper dictionary
 | ||||||
|  |         if(!dict) { | ||||||
|  |             FURI_LOG_E(TAG, "User dictionary not found"); | ||||||
|  |             state = DictAttackStateFlipperDictInProgress; | ||||||
|         } |         } | ||||||
|  |     } | ||||||
|  |     if(state == DictAttackStateFlipperDictInProgress) { | ||||||
|  |         worker_state = NfcWorkerStateMfClassicDictAttack; | ||||||
|  |         dict_attack_set_header(nfc->dict_attack, "Mf Classic Flipper Dict."); | ||||||
|  |         dict = mf_classic_dict_alloc(MfClassicDictTypeFlipper); | ||||||
|  |         if(!dict) { | ||||||
|  |             FURI_LOG_E(TAG, "Flipper dictionary not found"); | ||||||
|  |             // Pass through to let worker handle the failure
 | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     // Free previous dictionary
 | ||||||
|  |     if(dict_attack_data->dict) { | ||||||
|  |         mf_classic_dict_free(dict_attack_data->dict); | ||||||
|  |     } | ||||||
|  |     dict_attack_data->dict = dict; | ||||||
|     scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfClassicDictAttack, state); |     scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfClassicDictAttack, state); | ||||||
|     dict_attack_set_callback(nfc->dict_attack, nfc_dict_attack_dict_attack_result_callback, nfc); |     dict_attack_set_callback(nfc->dict_attack, nfc_dict_attack_dict_attack_result_callback, nfc); | ||||||
|     dict_attack_set_current_sector(nfc->dict_attack, 0); |     dict_attack_set_current_sector(nfc->dict_attack, 0); | ||||||
|     dict_attack_set_card_detected(nfc->dict_attack, data->type); |     dict_attack_set_card_detected(nfc->dict_attack, data->type); | ||||||
|  |     dict_attack_set_total_dict_keys( | ||||||
|  |         nfc->dict_attack, dict ? mf_classic_dict_get_total_keys(dict) : 0); | ||||||
|     nfc_scene_mf_classic_dict_attack_update_view(nfc); |     nfc_scene_mf_classic_dict_attack_update_view(nfc); | ||||||
|     nfc_worker_start( |     nfc_worker_start( | ||||||
|         nfc->worker, worker_state, &nfc->dev->dev_data, nfc_dict_attack_worker_callback, nfc); |         nfc->worker, worker_state, &nfc->dev->dev_data, nfc_dict_attack_worker_callback, nfc); | ||||||
| @ -112,6 +136,10 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent | |||||||
|             nfc_scene_mf_classic_dict_attack_update_view(nfc); |             nfc_scene_mf_classic_dict_attack_update_view(nfc); | ||||||
|             dict_attack_inc_current_sector(nfc->dict_attack); |             dict_attack_inc_current_sector(nfc->dict_attack); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|  |         } else if(event.event == NfcWorkerEventNewDictKeyBatch) { | ||||||
|  |             nfc_scene_mf_classic_dict_attack_update_view(nfc); | ||||||
|  |             dict_attack_inc_current_dict_key(nfc->dict_attack, NFC_DICT_KEY_BATCH_SIZE); | ||||||
|  |             consumed = true; | ||||||
|         } else if(event.event == NfcCustomEventDictAttackSkip) { |         } else if(event.event == NfcCustomEventDictAttackSkip) { | ||||||
|             if(state == DictAttackStateUserDictInProgress) { |             if(state == DictAttackStateUserDictInProgress) { | ||||||
|                 nfc_worker_stop(nfc->worker); |                 nfc_worker_stop(nfc->worker); | ||||||
| @ -130,8 +158,13 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent | |||||||
| 
 | 
 | ||||||
| void nfc_scene_mf_classic_dict_attack_on_exit(void* context) { | void nfc_scene_mf_classic_dict_attack_on_exit(void* context) { | ||||||
|     Nfc* nfc = context; |     Nfc* nfc = context; | ||||||
|  |     NfcMfClassicDictAttackData* dict_attack_data = &nfc->dev->dev_data.mf_classic_dict_attack_data; | ||||||
|     // Stop worker
 |     // Stop worker
 | ||||||
|     nfc_worker_stop(nfc->worker); |     nfc_worker_stop(nfc->worker); | ||||||
|  |     if(dict_attack_data->dict) { | ||||||
|  |         mf_classic_dict_free(dict_attack_data->dict); | ||||||
|  |         dict_attack_data->dict = NULL; | ||||||
|  |     } | ||||||
|     dict_attack_reset(nfc->dict_attack); |     dict_attack_reset(nfc->dict_attack); | ||||||
|     nfc_blink_stop(nfc); |     nfc_blink_stop(nfc); | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										72
									
								
								applications/nfc/scenes/nfc_scene_mf_classic_info.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								applications/nfc/scenes/nfc_scene_mf_classic_info.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,72 @@ | |||||||
|  | #include "../nfc_i.h" | ||||||
|  | 
 | ||||||
|  | void nfc_scene_mf_classic_info_widget_callback(GuiButtonType result, InputType type, void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     Nfc* nfc = context; | ||||||
|  | 
 | ||||||
|  |     if(type == InputTypeShort) { | ||||||
|  |         view_dispatcher_send_custom_event(nfc->view_dispatcher, result); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void nfc_scene_mf_classic_info_on_enter(void* context) { | ||||||
|  |     Nfc* nfc = context; | ||||||
|  |     NfcDeviceData* dev_data = &nfc->dev->dev_data; | ||||||
|  |     MfClassicData* mf_data = &dev_data->mf_classic_data; | ||||||
|  |     string_t str_tmp; | ||||||
|  |     string_init(str_tmp); | ||||||
|  | 
 | ||||||
|  |     // Setup view
 | ||||||
|  |     Widget* widget = nfc->widget; | ||||||
|  | 
 | ||||||
|  |     widget_add_string_element( | ||||||
|  |         widget, 0, 0, AlignLeft, AlignTop, FontSecondary, mf_classic_get_type_str(mf_data->type)); | ||||||
|  |     widget_add_string_element( | ||||||
|  |         widget, 0, 11, AlignLeft, AlignTop, FontSecondary, "ISO 14443-3 (Type A)"); | ||||||
|  |     string_printf(str_tmp, "UID:"); | ||||||
|  |     for(size_t i = 0; i < dev_data->nfc_data.uid_len; i++) { | ||||||
|  |         string_cat_printf(str_tmp, " %02X", dev_data->nfc_data.uid[i]); | ||||||
|  |     } | ||||||
|  |     widget_add_string_element( | ||||||
|  |         widget, 0, 22, AlignLeft, AlignTop, FontSecondary, string_get_cstr(str_tmp)); | ||||||
|  |     string_printf( | ||||||
|  |         str_tmp, | ||||||
|  |         "ATQA: %02X %02X   SAK: %02X", | ||||||
|  |         dev_data->nfc_data.atqa[0], | ||||||
|  |         dev_data->nfc_data.atqa[1], | ||||||
|  |         dev_data->nfc_data.sak); | ||||||
|  |     widget_add_string_element( | ||||||
|  |         widget, 0, 33, AlignLeft, AlignTop, FontSecondary, string_get_cstr(str_tmp)); | ||||||
|  |     uint8_t sectors_total = mf_classic_get_total_sectors_num(mf_data->type); | ||||||
|  |     uint8_t keys_total = sectors_total * 2; | ||||||
|  |     uint8_t keys_found = 0; | ||||||
|  |     uint8_t sectors_read = 0; | ||||||
|  |     mf_classic_get_read_sectors_and_keys(mf_data, §ors_read, &keys_found); | ||||||
|  |     string_printf(str_tmp, "Keys Found: %d/%d", keys_found, keys_total); | ||||||
|  |     widget_add_string_element( | ||||||
|  |         widget, 0, 44, AlignLeft, AlignTop, FontSecondary, string_get_cstr(str_tmp)); | ||||||
|  |     string_printf(str_tmp, "Sectors Read: %d/%d", sectors_read, sectors_total); | ||||||
|  |     widget_add_string_element( | ||||||
|  |         widget, 0, 55, AlignLeft, AlignTop, FontSecondary, string_get_cstr(str_tmp)); | ||||||
|  | 
 | ||||||
|  |     string_clear(str_tmp); | ||||||
|  |     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool nfc_scene_mf_classic_info_on_event(void* context, SceneManagerEvent event) { | ||||||
|  |     Nfc* nfc = context; | ||||||
|  |     bool consumed = false; | ||||||
|  | 
 | ||||||
|  |     if(event.type == SceneManagerEventTypeBack) { | ||||||
|  |         consumed = scene_manager_previous_scene(nfc->scene_manager); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return consumed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void nfc_scene_mf_classic_info_on_exit(void* context) { | ||||||
|  |     Nfc* nfc = context; | ||||||
|  | 
 | ||||||
|  |     // Clear view
 | ||||||
|  |     widget_reset(nfc->widget); | ||||||
|  | } | ||||||
| @ -3,6 +3,7 @@ | |||||||
| enum SubmenuIndex { | enum SubmenuIndex { | ||||||
|     SubmenuIndexSave, |     SubmenuIndexSave, | ||||||
|     SubmenuIndexEmulate, |     SubmenuIndexEmulate, | ||||||
|  |     SubmenuIndexInfo, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| void nfc_scene_mf_classic_menu_submenu_callback(void* context, uint32_t index) { | void nfc_scene_mf_classic_menu_submenu_callback(void* context, uint32_t index) { | ||||||
| @ -19,6 +20,9 @@ void nfc_scene_mf_classic_menu_on_enter(void* context) { | |||||||
|         submenu, "Save", SubmenuIndexSave, nfc_scene_mf_classic_menu_submenu_callback, nfc); |         submenu, "Save", SubmenuIndexSave, nfc_scene_mf_classic_menu_submenu_callback, nfc); | ||||||
|     submenu_add_item( |     submenu_add_item( | ||||||
|         submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_mf_classic_menu_submenu_callback, nfc); |         submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_mf_classic_menu_submenu_callback, nfc); | ||||||
|  |     submenu_add_item( | ||||||
|  |         submenu, "Info", SubmenuIndexInfo, nfc_scene_mf_classic_menu_submenu_callback, nfc); | ||||||
|  | 
 | ||||||
|     submenu_set_selected_item( |     submenu_set_selected_item( | ||||||
|         nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicMenu)); |         nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicMenu)); | ||||||
| 
 | 
 | ||||||
| @ -43,6 +47,11 @@ bool nfc_scene_mf_classic_menu_on_event(void* context, SceneManagerEvent event) | |||||||
|                 nfc->scene_manager, NfcSceneMfClassicMenu, SubmenuIndexEmulate); |                 nfc->scene_manager, NfcSceneMfClassicMenu, SubmenuIndexEmulate); | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|  |         } else if(event.event == SubmenuIndexInfo) { | ||||||
|  |             scene_manager_set_scene_state( | ||||||
|  |                 nfc->scene_manager, NfcSceneMfClassicMenu, SubmenuIndexInfo); | ||||||
|  |             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicInfo); | ||||||
|  |             consumed = true; | ||||||
|         } |         } | ||||||
|     } else if(event.type == SceneManagerEventTypeBack) { |     } else if(event.type == SceneManagerEventTypeBack) { | ||||||
|         consumed = scene_manager_previous_scene(nfc->scene_manager); |         consumed = scene_manager_previous_scene(nfc->scene_manager); | ||||||
|  | |||||||
							
								
								
									
										44
									
								
								applications/nfc/scenes/nfc_scene_mf_ultralight_key_input.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								applications/nfc/scenes/nfc_scene_mf_ultralight_key_input.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,44 @@ | |||||||
|  | #include "../nfc_i.h" | ||||||
|  | 
 | ||||||
|  | void nfc_scene_mf_ultralight_key_input_byte_input_callback(void* context) { | ||||||
|  |     Nfc* nfc = context; | ||||||
|  | 
 | ||||||
|  |     view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void nfc_scene_mf_ultralight_key_input_on_enter(void* context) { | ||||||
|  |     Nfc* nfc = context; | ||||||
|  | 
 | ||||||
|  |     // Setup view
 | ||||||
|  |     ByteInput* byte_input = nfc->byte_input; | ||||||
|  |     byte_input_set_header_text(byte_input, "Enter the password in hex"); | ||||||
|  |     byte_input_set_result_callback( | ||||||
|  |         byte_input, | ||||||
|  |         nfc_scene_mf_ultralight_key_input_byte_input_callback, | ||||||
|  |         NULL, | ||||||
|  |         nfc, | ||||||
|  |         nfc->byte_input_store, | ||||||
|  |         4); | ||||||
|  |     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewByteInput); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool nfc_scene_mf_ultralight_key_input_on_event(void* context, SceneManagerEvent event) { | ||||||
|  |     Nfc* nfc = context; | ||||||
|  |     bool consumed = false; | ||||||
|  | 
 | ||||||
|  |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|  |         if(event.event == NfcCustomEventByteInputDone) { | ||||||
|  |             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockWarn); | ||||||
|  |             consumed = true; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return consumed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void nfc_scene_mf_ultralight_key_input_on_exit(void* context) { | ||||||
|  |     Nfc* nfc = context; | ||||||
|  | 
 | ||||||
|  |     // Clear view
 | ||||||
|  |     byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0); | ||||||
|  |     byte_input_set_header_text(nfc->byte_input, ""); | ||||||
|  | } | ||||||
| @ -1,6 +1,7 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
| 
 | 
 | ||||||
| enum SubmenuIndex { | enum SubmenuIndex { | ||||||
|  |     SubmenuIndexUnlock, | ||||||
|     SubmenuIndexSave, |     SubmenuIndexSave, | ||||||
|     SubmenuIndexEmulate, |     SubmenuIndexEmulate, | ||||||
| }; | }; | ||||||
| @ -14,7 +15,16 @@ void nfc_scene_mf_ultralight_menu_submenu_callback(void* context, uint32_t index | |||||||
| void nfc_scene_mf_ultralight_menu_on_enter(void* context) { | void nfc_scene_mf_ultralight_menu_on_enter(void* context) { | ||||||
|     Nfc* nfc = context; |     Nfc* nfc = context; | ||||||
|     Submenu* submenu = nfc->submenu; |     Submenu* submenu = nfc->submenu; | ||||||
|  |     MfUltralightData* data = &nfc->dev->dev_data.mf_ul_data; | ||||||
| 
 | 
 | ||||||
|  |     if(data->data_read != data->data_size) { | ||||||
|  |         submenu_add_item( | ||||||
|  |             submenu, | ||||||
|  |             "Unlock With Password", | ||||||
|  |             SubmenuIndexUnlock, | ||||||
|  |             nfc_scene_mf_ultralight_menu_submenu_callback, | ||||||
|  |             nfc); | ||||||
|  |     } | ||||||
|     submenu_add_item( |     submenu_add_item( | ||||||
|         submenu, "Save", SubmenuIndexSave, nfc_scene_mf_ultralight_menu_submenu_callback, nfc); |         submenu, "Save", SubmenuIndexSave, nfc_scene_mf_ultralight_menu_submenu_callback, nfc); | ||||||
|     submenu_add_item( |     submenu_add_item( | ||||||
| @ -35,19 +45,20 @@ bool nfc_scene_mf_ultralight_menu_on_event(void* context, SceneManagerEvent even | |||||||
| 
 | 
 | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == SubmenuIndexSave) { |         if(event.event == SubmenuIndexSave) { | ||||||
|             scene_manager_set_scene_state( |  | ||||||
|                 nfc->scene_manager, NfcSceneMfUltralightMenu, SubmenuIndexSave); |  | ||||||
|             nfc->dev->format = NfcDeviceSaveFormatMifareUl; |             nfc->dev->format = NfcDeviceSaveFormatMifareUl; | ||||||
|             // Clear device name
 |             // Clear device name
 | ||||||
|             nfc_device_set_name(nfc->dev, ""); |             nfc_device_set_name(nfc->dev, ""); | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|         } else if(event.event == SubmenuIndexEmulate) { |         } else if(event.event == SubmenuIndexEmulate) { | ||||||
|             scene_manager_set_scene_state( |  | ||||||
|                 nfc->scene_manager, NfcSceneMfUltralightMenu, SubmenuIndexEmulate); |  | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|  |         } else if(event.event == SubmenuIndexUnlock) { | ||||||
|  |             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockMenu); | ||||||
|  |             consumed = true; | ||||||
|         } |         } | ||||||
|  |         scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfUltralightMenu, event.event); | ||||||
|  | 
 | ||||||
|     } else if(event.type == SceneManagerEventTypeBack) { |     } else if(event.type == SceneManagerEventTypeBack) { | ||||||
|         consumed = scene_manager_previous_scene(nfc->scene_manager); |         consumed = scene_manager_previous_scene(nfc->scene_manager); | ||||||
|     } |     } | ||||||
|  | |||||||
							
								
								
									
										107
									
								
								applications/nfc/scenes/nfc_scene_mf_ultralight_read_auth.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								applications/nfc/scenes/nfc_scene_mf_ultralight_read_auth.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,107 @@ | |||||||
|  | #include "../nfc_i.h" | ||||||
|  | #include <dolphin/dolphin.h> | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     NfcSceneMfUlReadStateIdle, | ||||||
|  |     NfcSceneMfUlReadStateDetecting, | ||||||
|  |     NfcSceneMfUlReadStateReading, | ||||||
|  |     NfcSceneMfUlReadStateNotSupportedCard, | ||||||
|  | } NfcSceneMfUlReadState; | ||||||
|  | 
 | ||||||
|  | bool nfc_scene_mf_ultralight_read_auth_worker_callback(NfcWorkerEvent event, void* context) { | ||||||
|  |     Nfc* nfc = context; | ||||||
|  | 
 | ||||||
|  |     if(event == NfcWorkerEventMfUltralightPassKey) { | ||||||
|  |         memcpy(nfc->dev->dev_data.mf_ul_data.auth_key, nfc->byte_input_store, 4); | ||||||
|  |     } else { | ||||||
|  |         view_dispatcher_send_custom_event(nfc->view_dispatcher, event); | ||||||
|  |     } | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void nfc_scene_mf_ultralight_read_auth_set_state(Nfc* nfc, NfcSceneMfUlReadState state) { | ||||||
|  |     uint32_t curr_state = | ||||||
|  |         scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightReadAuth); | ||||||
|  |     if(curr_state != state) { | ||||||
|  |         if(state == NfcSceneMfUlReadStateDetecting) { | ||||||
|  |             popup_reset(nfc->popup); | ||||||
|  |             popup_set_text( | ||||||
|  |                 nfc->popup, "Apply card to\nFlipper's back", 97, 24, AlignCenter, AlignTop); | ||||||
|  |             popup_set_icon(nfc->popup, 0, 8, &I_NFC_manual); | ||||||
|  |         } else if(state == NfcSceneMfUlReadStateReading) { | ||||||
|  |             popup_reset(nfc->popup); | ||||||
|  |             popup_set_header( | ||||||
|  |                 nfc->popup, "Reading card\nDon't move...", 85, 24, AlignCenter, AlignTop); | ||||||
|  |             popup_set_icon(nfc->popup, 12, 23, &A_Loading_24); | ||||||
|  |         } else if(state == NfcSceneMfUlReadStateNotSupportedCard) { | ||||||
|  |             popup_reset(nfc->popup); | ||||||
|  |             popup_set_header(nfc->popup, "Wrong type of card!", 64, 3, AlignCenter, AlignTop); | ||||||
|  |             popup_set_text( | ||||||
|  |                 nfc->popup, | ||||||
|  |                 "Only MIFARE\nUltralight & NTAG\n are supported", | ||||||
|  |                 4, | ||||||
|  |                 22, | ||||||
|  |                 AlignLeft, | ||||||
|  |                 AlignTop); | ||||||
|  |             popup_set_icon(nfc->popup, 73, 17, &I_DolphinFirstStart8_56x51); | ||||||
|  |         } | ||||||
|  |         scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfUltralightReadAuth, state); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void nfc_scene_mf_ultralight_read_auth_on_enter(void* context) { | ||||||
|  |     Nfc* nfc = context; | ||||||
|  |     DOLPHIN_DEED(DolphinDeedNfcRead); | ||||||
|  | 
 | ||||||
|  |     nfc_device_clear(nfc->dev); | ||||||
|  |     // Setup view
 | ||||||
|  |     nfc_scene_mf_ultralight_read_auth_set_state(nfc, NfcSceneMfUlReadStateDetecting); | ||||||
|  |     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); | ||||||
|  |     // Start worker
 | ||||||
|  |     nfc_worker_start( | ||||||
|  |         nfc->worker, | ||||||
|  |         NfcWorkerStateReadMfUltralightReadAuth, | ||||||
|  |         &nfc->dev->dev_data, | ||||||
|  |         nfc_scene_mf_ultralight_read_auth_worker_callback, | ||||||
|  |         nfc); | ||||||
|  | 
 | ||||||
|  |     nfc_blink_start(nfc); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool nfc_scene_mf_ultralight_read_auth_on_event(void* context, SceneManagerEvent event) { | ||||||
|  |     Nfc* nfc = context; | ||||||
|  |     bool consumed = false; | ||||||
|  | 
 | ||||||
|  |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|  |         if((event.event == NfcWorkerEventSuccess) || (event.event == NfcWorkerEventFail)) { | ||||||
|  |             notification_message(nfc->notifications, &sequence_success); | ||||||
|  |             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadAuthResult); | ||||||
|  |             consumed = true; | ||||||
|  |         } else if(event.event == NfcWorkerEventCardDetected) { | ||||||
|  |             nfc_scene_mf_ultralight_read_auth_set_state(nfc, NfcSceneMfUlReadStateReading); | ||||||
|  |             consumed = true; | ||||||
|  |         } else if(event.event == NfcWorkerEventNoCardDetected) { | ||||||
|  |             nfc_scene_mf_ultralight_read_auth_set_state(nfc, NfcSceneMfUlReadStateDetecting); | ||||||
|  |             consumed = true; | ||||||
|  |         } else if(event.event == NfcWorkerEventWrongCardDetected) { | ||||||
|  |             nfc_scene_mf_ultralight_read_auth_set_state( | ||||||
|  |                 nfc, NfcSceneMfUlReadStateNotSupportedCard); | ||||||
|  |         } | ||||||
|  |     } else if(event.type == SceneManagerEventTypeBack) { | ||||||
|  |         consumed = scene_manager_search_and_switch_to_previous_scene( | ||||||
|  |             nfc->scene_manager, NfcSceneMfUltralightUnlockMenu); | ||||||
|  |     } | ||||||
|  |     return consumed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void nfc_scene_mf_ultralight_read_auth_on_exit(void* context) { | ||||||
|  |     Nfc* nfc = context; | ||||||
|  | 
 | ||||||
|  |     // Stop worker
 | ||||||
|  |     nfc_worker_stop(nfc->worker); | ||||||
|  |     // Clear view
 | ||||||
|  |     popup_reset(nfc->popup); | ||||||
|  |     nfc_blink_stop(nfc); | ||||||
|  |     scene_manager_set_scene_state( | ||||||
|  |         nfc->scene_manager, NfcSceneMfUltralightReadAuth, NfcSceneMfUlReadStateIdle); | ||||||
|  | } | ||||||
| @ -0,0 +1,98 @@ | |||||||
|  | #include "../nfc_i.h" | ||||||
|  | #include <dolphin/dolphin.h> | ||||||
|  | 
 | ||||||
|  | void nfc_scene_mf_ultralight_read_auth_result_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_ultralight_read_auth_result_on_enter(void* context) { | ||||||
|  |     Nfc* nfc = context; | ||||||
|  |     DOLPHIN_DEED(DolphinDeedNfcReadSuccess); | ||||||
|  | 
 | ||||||
|  |     // Setup dialog view
 | ||||||
|  |     FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data; | ||||||
|  |     MfUltralightData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data; | ||||||
|  |     MfUltralightConfigPages* config_pages = mf_ultralight_get_config_pages(mf_ul_data); | ||||||
|  |     Widget* widget = nfc->widget; | ||||||
|  |     string_t temp_str; | ||||||
|  |     string_init(temp_str); | ||||||
|  | 
 | ||||||
|  |     if((mf_ul_data->data_read == mf_ul_data->data_size) && (mf_ul_data->data_read > 0)) { | ||||||
|  |         widget_add_string_element( | ||||||
|  |             widget, 64, 0, AlignCenter, AlignTop, FontPrimary, "All pages are unlocked!"); | ||||||
|  |     } else { | ||||||
|  |         widget_add_string_element( | ||||||
|  |             widget, 64, 0, AlignCenter, AlignTop, FontPrimary, "Not all pages unlocked!"); | ||||||
|  |     } | ||||||
|  |     string_set_str(temp_str, "UID:"); | ||||||
|  |     for(size_t i = 0; i < nfc_data->uid_len; i++) { | ||||||
|  |         string_cat_printf(temp_str, " %02X", nfc_data->uid[i]); | ||||||
|  |     } | ||||||
|  |     widget_add_string_element( | ||||||
|  |         widget, 0, 17, AlignLeft, AlignTop, FontSecondary, string_get_cstr(temp_str)); | ||||||
|  |     if(mf_ul_data->auth_success) { | ||||||
|  |         string_printf( | ||||||
|  |             temp_str, | ||||||
|  |             "Password: %02X %02X %02X %02X", | ||||||
|  |             config_pages->auth_data.pwd.raw[0], | ||||||
|  |             config_pages->auth_data.pwd.raw[1], | ||||||
|  |             config_pages->auth_data.pwd.raw[2], | ||||||
|  |             config_pages->auth_data.pwd.raw[3]); | ||||||
|  |         widget_add_string_element( | ||||||
|  |             widget, 0, 28, AlignLeft, AlignTop, FontSecondary, string_get_cstr(temp_str)); | ||||||
|  |         string_printf( | ||||||
|  |             temp_str, | ||||||
|  |             "PACK: %02X %02X", | ||||||
|  |             config_pages->auth_data.pack.raw[0], | ||||||
|  |             config_pages->auth_data.pack.raw[1]); | ||||||
|  |         widget_add_string_element( | ||||||
|  |             widget, 0, 39, AlignLeft, AlignTop, FontSecondary, string_get_cstr(temp_str)); | ||||||
|  |     } | ||||||
|  |     string_printf( | ||||||
|  |         temp_str, "Pages Read: %d/%d", mf_ul_data->data_read / 4, mf_ul_data->data_size / 4); | ||||||
|  |     widget_add_string_element( | ||||||
|  |         widget, 0, 50, AlignLeft, AlignTop, FontSecondary, string_get_cstr(temp_str)); | ||||||
|  |     widget_add_button_element( | ||||||
|  |         widget, | ||||||
|  |         GuiButtonTypeRight, | ||||||
|  |         "Save", | ||||||
|  |         nfc_scene_mf_ultralight_read_auth_result_widget_callback, | ||||||
|  |         nfc); | ||||||
|  | 
 | ||||||
|  |     string_clear(temp_str); | ||||||
|  |     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool nfc_scene_mf_ultralight_read_auth_result_on_event(void* context, SceneManagerEvent event) { | ||||||
|  |     Nfc* nfc = context; | ||||||
|  |     bool consumed = false; | ||||||
|  | 
 | ||||||
|  |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|  |         if(event.event == GuiButtonTypeRight) { | ||||||
|  |             nfc->dev->format = NfcDeviceSaveFormatMifareUl; | ||||||
|  |             // Clear device name
 | ||||||
|  |             nfc_device_set_name(nfc->dev, ""); | ||||||
|  |             scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); | ||||||
|  |             consumed = true; | ||||||
|  |         } | ||||||
|  |     } else if(event.type == SceneManagerEventTypeBack) { | ||||||
|  |         consumed = scene_manager_search_and_switch_to_previous_scene( | ||||||
|  |             nfc->scene_manager, NfcSceneMfUltralightUnlockMenu); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return consumed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void nfc_scene_mf_ultralight_read_auth_result_on_exit(void* context) { | ||||||
|  |     Nfc* nfc = context; | ||||||
|  | 
 | ||||||
|  |     // Clean views
 | ||||||
|  |     widget_reset(nfc->widget); | ||||||
|  | } | ||||||
							
								
								
									
										92
									
								
								applications/nfc/scenes/nfc_scene_mf_ultralight_read_success.c
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										92
									
								
								applications/nfc/scenes/nfc_scene_mf_ultralight_read_success.c
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							| @ -1,51 +1,67 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
| #include <dolphin/dolphin.h> | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| #define NFC_SCENE_READ_SUCCESS_SHIFT "              " |  | ||||||
| 
 |  | ||||||
| enum { | enum { | ||||||
|     ReadMifareUlStateShowUID, |     ReadMifareUlStateShowInfo, | ||||||
|     ReadMifareUlStateShowData, |     ReadMifareUlStateShowData, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| void nfc_scene_mf_ultralight_read_success_dialog_callback(DialogExResult result, void* context) { | void nfc_scene_mf_ultralight_read_success_widget_callback( | ||||||
|  |     GuiButtonType result, | ||||||
|  |     InputType type, | ||||||
|  |     void* context) { | ||||||
|     Nfc* nfc = context; |     Nfc* nfc = context; | ||||||
| 
 | 
 | ||||||
|  |     if(type == InputTypeShort) { | ||||||
|         view_dispatcher_send_custom_event(nfc->view_dispatcher, result); |         view_dispatcher_send_custom_event(nfc->view_dispatcher, result); | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void nfc_scene_mf_ultralight_read_success_on_enter(void* context) { | void nfc_scene_mf_ultralight_read_success_on_enter(void* context) { | ||||||
|     Nfc* nfc = context; |     Nfc* nfc = context; | ||||||
|     DOLPHIN_DEED(DolphinDeedNfcReadSuccess); |     DOLPHIN_DEED(DolphinDeedNfcReadSuccess); | ||||||
| 
 | 
 | ||||||
|     // Setup dialog view
 |     // Setup widget view
 | ||||||
|     FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; |     FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; | ||||||
|     MfUltralightData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data; |     MfUltralightData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data; | ||||||
|     DialogEx* dialog_ex = nfc->dialog_ex; |     Widget* widget = nfc->widget; | ||||||
|     dialog_ex_set_left_button_text(dialog_ex, "Retry"); |     widget_add_button_element( | ||||||
|     dialog_ex_set_right_button_text(dialog_ex, "More"); |         widget, | ||||||
|     dialog_ex_set_center_button_text(dialog_ex, "Data"); |         GuiButtonTypeLeft, | ||||||
|     dialog_ex_set_header( |         "Retry", | ||||||
|         dialog_ex, nfc_mf_ul_type(mf_ul_data->type, true), 64, 8, AlignCenter, AlignCenter); |         nfc_scene_mf_ultralight_read_success_widget_callback, | ||||||
|     dialog_ex_set_icon(dialog_ex, 8, 13, &I_Medium_chip_22x21); |         nfc); | ||||||
|     // Display UID
 |     widget_add_button_element( | ||||||
|     nfc_text_store_set( |         widget, | ||||||
|         nfc, |         GuiButtonTypeCenter, | ||||||
|         NFC_SCENE_READ_SUCCESS_SHIFT "ATQA: %02X%02X\n" NFC_SCENE_READ_SUCCESS_SHIFT |         "Data", | ||||||
|                                      "SAK: %02X\nUID: %02X %02X %02X %02X %02X %02X %02X", |         nfc_scene_mf_ultralight_read_success_widget_callback, | ||||||
|         data->atqa[0], |         nfc); | ||||||
|         data->atqa[1], |     widget_add_button_element( | ||||||
|         data->sak, |         widget, | ||||||
|         data->uid[0], |         GuiButtonTypeRight, | ||||||
|         data->uid[1], |         "More", | ||||||
|         data->uid[2], |         nfc_scene_mf_ultralight_read_success_widget_callback, | ||||||
|         data->uid[3], |         nfc); | ||||||
|         data->uid[4], | 
 | ||||||
|         data->uid[5], |     widget_add_string_element( | ||||||
|         data->uid[6]); |         widget, 0, 0, AlignLeft, AlignTop, FontSecondary, nfc_mf_ul_type(mf_ul_data->type, true)); | ||||||
|     dialog_ex_set_text(dialog_ex, nfc->text_store, 8, 16, AlignLeft, AlignTop); |     string_t data_str; | ||||||
|     dialog_ex_set_context(dialog_ex, nfc); |     string_init_printf(data_str, "UID:"); | ||||||
|     dialog_ex_set_result_callback(dialog_ex, nfc_scene_mf_ultralight_read_success_dialog_callback); |     for(size_t i = 0; i < data->uid_len; i++) { | ||||||
|  |         string_cat_printf(data_str, " %02X", data->uid[i]); | ||||||
|  |     } | ||||||
|  |     widget_add_string_element( | ||||||
|  |         widget, 0, 13, AlignLeft, AlignTop, FontSecondary, string_get_cstr(data_str)); | ||||||
|  |     string_printf( | ||||||
|  |         data_str, "Pages Read: %d/%d", mf_ul_data->data_read / 4, mf_ul_data->data_size / 4); | ||||||
|  |     widget_add_string_element( | ||||||
|  |         widget, 0, 24, AlignLeft, AlignTop, FontSecondary, string_get_cstr(data_str)); | ||||||
|  |     if(mf_ul_data->data_read != mf_ul_data->data_size) { | ||||||
|  |         widget_add_string_element( | ||||||
|  |             widget, 0, 35, AlignLeft, AlignTop, FontSecondary, "Password-protected pages!"); | ||||||
|  |     } | ||||||
|  |     string_clear(data_str); | ||||||
| 
 | 
 | ||||||
|     // Setup TextBox view
 |     // Setup TextBox view
 | ||||||
|     TextBox* text_box = nfc->text_box; |     TextBox* text_box = nfc->text_box; | ||||||
| @ -60,8 +76,8 @@ void nfc_scene_mf_ultralight_read_success_on_enter(void* context) { | |||||||
|     text_box_set_text(text_box, string_get_cstr(nfc->text_box_store)); |     text_box_set_text(text_box, string_get_cstr(nfc->text_box_store)); | ||||||
| 
 | 
 | ||||||
|     scene_manager_set_scene_state( |     scene_manager_set_scene_state( | ||||||
|         nfc->scene_manager, NfcSceneMfUltralightReadSuccess, ReadMifareUlStateShowUID); |         nfc->scene_manager, NfcSceneMfUltralightReadSuccess, ReadMifareUlStateShowInfo); | ||||||
|     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); |     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool nfc_scene_mf_ultralight_read_success_on_event(void* context, SceneManagerEvent event) { | bool nfc_scene_mf_ultralight_read_success_on_event(void* context, SceneManagerEvent event) { | ||||||
| @ -71,13 +87,13 @@ bool nfc_scene_mf_ultralight_read_success_on_event(void* context, SceneManagerEv | |||||||
|         scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightReadSuccess); |         scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightReadSuccess); | ||||||
| 
 | 
 | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(state == ReadMifareUlStateShowUID && event.event == DialogExResultLeft) { |         if(state == ReadMifareUlStateShowInfo && event.event == GuiButtonTypeLeft) { | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneRetryConfirm); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneRetryConfirm); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|         } else if(state == ReadMifareUlStateShowUID && event.event == DialogExResultRight) { |         } else if(state == ReadMifareUlStateShowInfo && event.event == GuiButtonTypeRight) { | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightMenu); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightMenu); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|         } else if(state == ReadMifareUlStateShowUID && event.event == DialogExResultCenter) { |         } else if(state == ReadMifareUlStateShowInfo && event.event == GuiButtonTypeCenter) { | ||||||
|             view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); |             view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); | ||||||
|             scene_manager_set_scene_state( |             scene_manager_set_scene_state( | ||||||
|                 nfc->scene_manager, NfcSceneMfUltralightReadSuccess, ReadMifareUlStateShowData); |                 nfc->scene_manager, NfcSceneMfUltralightReadSuccess, ReadMifareUlStateShowData); | ||||||
| @ -85,9 +101,9 @@ bool nfc_scene_mf_ultralight_read_success_on_event(void* context, SceneManagerEv | |||||||
|         } |         } | ||||||
|     } else if(event.type == SceneManagerEventTypeBack) { |     } else if(event.type == SceneManagerEventTypeBack) { | ||||||
|         if(state == ReadMifareUlStateShowData) { |         if(state == ReadMifareUlStateShowData) { | ||||||
|             view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); |             view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); | ||||||
|             scene_manager_set_scene_state( |             scene_manager_set_scene_state( | ||||||
|                 nfc->scene_manager, NfcSceneMfUltralightReadSuccess, ReadMifareUlStateShowUID); |                 nfc->scene_manager, NfcSceneMfUltralightReadSuccess, ReadMifareUlStateShowInfo); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|         } else { |         } else { | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); | ||||||
| @ -102,7 +118,7 @@ void nfc_scene_mf_ultralight_read_success_on_exit(void* context) { | |||||||
|     Nfc* nfc = context; |     Nfc* nfc = context; | ||||||
| 
 | 
 | ||||||
|     // Clean views
 |     // Clean views
 | ||||||
|     dialog_ex_reset(nfc->dialog_ex); |     widget_reset(nfc->widget); | ||||||
|     text_box_reset(nfc->text_box); |     text_box_reset(nfc->text_box); | ||||||
|     string_reset(nfc->text_box_store); |     string_reset(nfc->text_box_store); | ||||||
| } | } | ||||||
|  | |||||||
| @ -0,0 +1,70 @@ | |||||||
|  | #include "../nfc_i.h" | ||||||
|  | 
 | ||||||
|  | enum SubmenuIndex { | ||||||
|  |     SubmenuIndexMfUlUnlockMenuManual, | ||||||
|  |     SubmenuIndexMfUlUnlockMenuAmeebo, | ||||||
|  |     SubmenuIndexMfUlUnlockMenuXiaomi, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | void nfc_scene_mf_ultralight_unlock_menu_submenu_callback(void* context, uint32_t index) { | ||||||
|  |     Nfc* nfc = context; | ||||||
|  | 
 | ||||||
|  |     view_dispatcher_send_custom_event(nfc->view_dispatcher, index); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void nfc_scene_mf_ultralight_unlock_menu_on_enter(void* context) { | ||||||
|  |     Nfc* nfc = context; | ||||||
|  |     Submenu* submenu = nfc->submenu; | ||||||
|  | 
 | ||||||
|  |     uint32_t state = | ||||||
|  |         scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightUnlockMenu); | ||||||
|  |     submenu_add_item( | ||||||
|  |         submenu, | ||||||
|  |         "Enter Password Manually", | ||||||
|  |         SubmenuIndexMfUlUnlockMenuManual, | ||||||
|  |         nfc_scene_mf_ultralight_unlock_menu_submenu_callback, | ||||||
|  |         nfc); | ||||||
|  |     submenu_add_item( | ||||||
|  |         submenu, | ||||||
|  |         "Auth As Ameebo", | ||||||
|  |         SubmenuIndexMfUlUnlockMenuAmeebo, | ||||||
|  |         nfc_scene_mf_ultralight_unlock_menu_submenu_callback, | ||||||
|  |         nfc); | ||||||
|  |     submenu_add_item( | ||||||
|  |         submenu, | ||||||
|  |         "Auth As Xiaomi", | ||||||
|  |         SubmenuIndexMfUlUnlockMenuXiaomi, | ||||||
|  |         nfc_scene_mf_ultralight_unlock_menu_submenu_callback, | ||||||
|  |         nfc); | ||||||
|  |     submenu_set_selected_item(submenu, state); | ||||||
|  |     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool nfc_scene_mf_ultralight_unlock_menu_on_event(void* context, SceneManagerEvent event) { | ||||||
|  |     Nfc* nfc = context; | ||||||
|  |     bool consumed = false; | ||||||
|  | 
 | ||||||
|  |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|  |         if(event.event == SubmenuIndexMfUlUnlockMenuManual) { | ||||||
|  |             nfc->dev->dev_data.mf_ul_data.auth_method = MfUltralightAuthMethodManual; | ||||||
|  |             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightKeyInput); | ||||||
|  |             consumed = true; | ||||||
|  |         } else if(event.event == SubmenuIndexMfUlUnlockMenuAmeebo) { | ||||||
|  |             nfc->dev->dev_data.mf_ul_data.auth_method = MfUltralightAuthMethodAmeebo; | ||||||
|  |             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockWarn); | ||||||
|  |             consumed = true; | ||||||
|  |         } else if(event.event == SubmenuIndexMfUlUnlockMenuXiaomi) { | ||||||
|  |             nfc->dev->dev_data.mf_ul_data.auth_method = MfUltralightAuthMethodXiaomi; | ||||||
|  |             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockWarn); | ||||||
|  |             consumed = true; | ||||||
|  |         } | ||||||
|  |         scene_manager_set_scene_state(nfc->scene_manager, NfcSceneExtraActions, event.event); | ||||||
|  |     } | ||||||
|  |     return consumed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void nfc_scene_mf_ultralight_unlock_menu_on_exit(void* context) { | ||||||
|  |     Nfc* nfc = context; | ||||||
|  | 
 | ||||||
|  |     submenu_reset(nfc->submenu); | ||||||
|  | } | ||||||
| @ -0,0 +1,45 @@ | |||||||
|  | #include "../nfc_i.h" | ||||||
|  | 
 | ||||||
|  | void nfc_scene_mf_ultralight_unlock_warn_dialog_callback(DialogExResult result, void* context) { | ||||||
|  |     Nfc* nfc = context; | ||||||
|  | 
 | ||||||
|  |     view_dispatcher_send_custom_event(nfc->view_dispatcher, result); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void nfc_scene_mf_ultralight_unlock_warn_on_enter(void* context) { | ||||||
|  |     Nfc* nfc = context; | ||||||
|  |     DialogEx* dialog_ex = nfc->dialog_ex; | ||||||
|  | 
 | ||||||
|  |     dialog_ex_set_context(dialog_ex, nfc); | ||||||
|  |     dialog_ex_set_result_callback(dialog_ex, nfc_scene_mf_ultralight_unlock_warn_dialog_callback); | ||||||
|  | 
 | ||||||
|  |     dialog_ex_set_header(dialog_ex, "Risky function!", 64, 4, AlignCenter, AlignTop); | ||||||
|  |     dialog_ex_set_text( | ||||||
|  |         dialog_ex, "Wrong password\ncan block your\ncard.", 4, 18, AlignLeft, AlignTop); | ||||||
|  |     dialog_ex_set_icon(dialog_ex, 73, 17, &I_DolphinFirstStart8_56x51); | ||||||
|  |     dialog_ex_set_center_button_text(dialog_ex, "OK"); | ||||||
|  | 
 | ||||||
|  |     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool nfc_scene_mf_ultralight_unlock_warn_on_event(void* context, SceneManagerEvent event) { | ||||||
|  |     Nfc* nfc = context; | ||||||
|  | 
 | ||||||
|  |     bool consumed = false; | ||||||
|  | 
 | ||||||
|  |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|  |         if(event.event == DialogExResultCenter) { | ||||||
|  |             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadAuth); | ||||||
|  |             consumed = true; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return consumed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void nfc_scene_mf_ultralight_unlock_warn_on_exit(void* context) { | ||||||
|  |     Nfc* nfc = context; | ||||||
|  | 
 | ||||||
|  |     dialog_ex_reset(nfc->dialog_ex); | ||||||
|  |     submenu_reset(nfc->submenu); | ||||||
|  | } | ||||||
| @ -10,7 +10,7 @@ void nfc_scene_restore_original_confirm_on_enter(void* context) { | |||||||
|     Nfc* nfc = context; |     Nfc* nfc = context; | ||||||
|     DialogEx* dialog_ex = nfc->dialog_ex; |     DialogEx* dialog_ex = nfc->dialog_ex; | ||||||
| 
 | 
 | ||||||
|     dialog_ex_set_header(dialog_ex, "Restore card data?", 64, 0, AlignCenter, AlignTop); |     dialog_ex_set_header(dialog_ex, "Restore Card Data?", 64, 0, AlignCenter, AlignTop); | ||||||
|     dialog_ex_set_icon(dialog_ex, 5, 15, &I_Restoring); |     dialog_ex_set_icon(dialog_ex, 5, 15, &I_Restoring); | ||||||
|     dialog_ex_set_text( |     dialog_ex_set_text( | ||||||
|         dialog_ex, "It will be returned\nto its original state.", 47, 21, AlignLeft, AlignTop); |         dialog_ex, "It will be returned\nto its original state.", 47, 21, AlignLeft, AlignTop); | ||||||
|  | |||||||
| @ -12,9 +12,9 @@ void nfc_scene_retry_confirm_on_enter(void* context) { | |||||||
| 
 | 
 | ||||||
|     dialog_ex_set_left_button_text(dialog_ex, "Retry"); |     dialog_ex_set_left_button_text(dialog_ex, "Retry"); | ||||||
|     dialog_ex_set_right_button_text(dialog_ex, "Stay"); |     dialog_ex_set_right_button_text(dialog_ex, "Stay"); | ||||||
|     dialog_ex_set_header(dialog_ex, "Retry reading?", 64, 11, AlignCenter, AlignTop); |     dialog_ex_set_header(dialog_ex, "Retry Reading?", 64, 11, AlignCenter, AlignTop); | ||||||
|     dialog_ex_set_text( |     dialog_ex_set_text( | ||||||
|         dialog_ex, "All unsaved data will be\nlost.", 64, 25, AlignCenter, AlignTop); |         dialog_ex, "All unsaved data will be\nlost!", 64, 25, AlignCenter, AlignTop); | ||||||
|     dialog_ex_set_context(dialog_ex, nfc); |     dialog_ex_set_context(dialog_ex, nfc); | ||||||
|     dialog_ex_set_result_callback(dialog_ex, nfc_scene_retry_confirm_dialog_callback); |     dialog_ex_set_result_callback(dialog_ex, nfc_scene_retry_confirm_dialog_callback); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -4,10 +4,10 @@ void nfc_scene_rpc_on_enter(void* context) { | |||||||
|     Nfc* nfc = context; |     Nfc* nfc = context; | ||||||
|     Popup* popup = nfc->popup; |     Popup* popup = nfc->popup; | ||||||
| 
 | 
 | ||||||
|     popup_set_header(popup, "NFC", 82, 28, AlignCenter, AlignBottom); |     popup_set_header(popup, "NFC", 89, 42, AlignCenter, AlignBottom); | ||||||
|     popup_set_text(popup, "RPC mode", 82, 32, AlignCenter, AlignTop); |     popup_set_text(popup, "RPC mode", 89, 44, AlignCenter, AlignTop); | ||||||
| 
 | 
 | ||||||
|     popup_set_icon(popup, 2, 14, &I_Warning_30x23); // TODO: icon
 |     popup_set_icon(popup, 0, 12, &I_RFIDDolphinSend_97x61); | ||||||
| 
 | 
 | ||||||
|     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); |     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); | ||||||
| 
 | 
 | ||||||
| @ -31,13 +31,11 @@ bool nfc_scene_rpc_on_event(void* context, SceneManagerEvent event) { | |||||||
|         consumed = true; |         consumed = true; | ||||||
|         if(event.event == NfcCustomEventViewExit) { |         if(event.event == NfcCustomEventViewExit) { | ||||||
|             rpc_system_app_confirm(nfc->rpc_ctx, RpcAppEventAppExit, true); |             rpc_system_app_confirm(nfc->rpc_ctx, RpcAppEventAppExit, true); | ||||||
|  |             scene_manager_stop(nfc->scene_manager); | ||||||
|             view_dispatcher_stop(nfc->view_dispatcher); |             view_dispatcher_stop(nfc->view_dispatcher); | ||||||
|             nfc_blink_stop(nfc); |  | ||||||
|         } else if(event.event == NfcCustomEventRpcSessionClose) { |         } else if(event.event == NfcCustomEventRpcSessionClose) { | ||||||
|             rpc_system_app_set_callback(nfc->rpc_ctx, NULL, NULL); |             scene_manager_stop(nfc->scene_manager); | ||||||
|             nfc->rpc_ctx = NULL; |  | ||||||
|             view_dispatcher_stop(nfc->view_dispatcher); |             view_dispatcher_stop(nfc->view_dispatcher); | ||||||
|             nfc_blink_stop(nfc); |  | ||||||
|         } else if(event.event == NfcCustomEventRpcLoad) { |         } else if(event.event == NfcCustomEventRpcLoad) { | ||||||
|             bool result = false; |             bool result = false; | ||||||
|             const char* arg = rpc_system_app_get_data(nfc->rpc_ctx); |             const char* arg = rpc_system_app_get_data(nfc->rpc_ctx); | ||||||
| @ -66,7 +64,7 @@ bool nfc_scene_rpc_on_event(void* context, SceneManagerEvent event) { | |||||||
| 
 | 
 | ||||||
|                     nfc_blink_start(nfc); |                     nfc_blink_start(nfc); | ||||||
|                     nfc_text_store_set(nfc, "emulating\n%s", nfc->dev->dev_name); |                     nfc_text_store_set(nfc, "emulating\n%s", nfc->dev->dev_name); | ||||||
|                     popup_set_text(popup, nfc->text_store, 82, 32, AlignCenter, AlignTop); |                     popup_set_text(popup, nfc->text_store, 89, 44, AlignCenter, AlignTop); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -2,6 +2,7 @@ | |||||||
| 
 | 
 | ||||||
| enum SubmenuIndex { | enum SubmenuIndex { | ||||||
|     SubmenuIndexEmulate, |     SubmenuIndexEmulate, | ||||||
|  |     SubmenuIndexEditUid, | ||||||
|     SubmenuIndexRename, |     SubmenuIndexRename, | ||||||
|     SubmenuIndexDelete, |     SubmenuIndexDelete, | ||||||
|     SubmenuIndexInfo, |     SubmenuIndexInfo, | ||||||
| @ -27,6 +28,14 @@ void nfc_scene_saved_menu_on_enter(void* context) { | |||||||
|             SubmenuIndexEmulate, |             SubmenuIndexEmulate, | ||||||
|             nfc_scene_saved_menu_submenu_callback, |             nfc_scene_saved_menu_submenu_callback, | ||||||
|             nfc); |             nfc); | ||||||
|  |         if(nfc->dev->dev_data.protocol == NfcDeviceProtocolUnknown) { | ||||||
|  |             submenu_add_item( | ||||||
|  |                 submenu, | ||||||
|  |                 "Edit UID", | ||||||
|  |                 SubmenuIndexEditUid, | ||||||
|  |                 nfc_scene_saved_menu_submenu_callback, | ||||||
|  |                 nfc); | ||||||
|  |         } | ||||||
|     } else if( |     } else if( | ||||||
|         nfc->dev->format == NfcDeviceSaveFormatMifareUl || |         nfc->dev->format == NfcDeviceSaveFormatMifareUl || | ||||||
|         nfc->dev->format == NfcDeviceSaveFormatMifareClassic) { |         nfc->dev->format == NfcDeviceSaveFormatMifareClassic) { | ||||||
| @ -71,6 +80,9 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { | |||||||
|         } else if(event.event == SubmenuIndexRename) { |         } else if(event.event == SubmenuIndexRename) { | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|  |         } else if(event.event == SubmenuIndexEditUid) { | ||||||
|  |             scene_manager_next_scene(nfc->scene_manager, NfcSceneSetUid); | ||||||
|  |             consumed = true; | ||||||
|         } else if(event.event == SubmenuIndexDelete) { |         } else if(event.event == SubmenuIndexDelete) { | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneDelete); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneDelete); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|  | |||||||
| @ -31,10 +31,18 @@ bool nfc_scene_set_uid_on_event(void* context, SceneManagerEvent event) { | |||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == NfcCustomEventByteInputDone) { |         if(event.event == NfcCustomEventByteInputDone) { | ||||||
|             DOLPHIN_DEED(DolphinDeedNfcAdd); |             DOLPHIN_DEED(DolphinDeedNfcAdd); | ||||||
|  |             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)) { | ||||||
|  |                     scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess); | ||||||
|  |                     consumed = true; | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|                 scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); |                 scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); | ||||||
|                 consumed = true; |                 consumed = true; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |     } | ||||||
|     return consumed; |     return consumed; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -23,6 +23,8 @@ typedef struct { | |||||||
|     uint8_t sector_current; |     uint8_t sector_current; | ||||||
|     uint8_t keys_total; |     uint8_t keys_total; | ||||||
|     uint8_t keys_found; |     uint8_t keys_found; | ||||||
|  |     uint16_t dict_keys_total; | ||||||
|  |     uint16_t dict_keys_current; | ||||||
| } DictAttackViewModel; | } DictAttackViewModel; | ||||||
| 
 | 
 | ||||||
| static void dict_attack_draw_callback(Canvas* canvas, void* model) { | static void dict_attack_draw_callback(Canvas* canvas, void* model) { | ||||||
| @ -38,8 +40,15 @@ static void dict_attack_draw_callback(Canvas* canvas, void* model) { | |||||||
|         canvas_set_font(canvas, FontPrimary); |         canvas_set_font(canvas, FontPrimary); | ||||||
|         canvas_draw_str_aligned(canvas, 64, 2, AlignCenter, AlignTop, string_get_cstr(m->header)); |         canvas_draw_str_aligned(canvas, 64, 2, AlignCenter, AlignTop, string_get_cstr(m->header)); | ||||||
|         canvas_set_font(canvas, FontSecondary); |         canvas_set_font(canvas, FontSecondary); | ||||||
|         float progress = |         float dict_progress = m->dict_keys_total == 0 ? | ||||||
|             m->sectors_total == 0 ? 0 : (float)(m->sector_current) / (float)(m->sectors_total); |                                   0 : | ||||||
|  |                                   (float)(m->dict_keys_current) / (float)(m->dict_keys_total); | ||||||
|  |         float progress = m->sectors_total == 0 ? 0 : | ||||||
|  |                                                  ((float)(m->sector_current) + dict_progress) / | ||||||
|  |                                                      (float)(m->sectors_total); | ||||||
|  |         if(progress > 1.0) { | ||||||
|  |             progress = 1.0; | ||||||
|  |         } | ||||||
|         elements_progress_bar(canvas, 5, 15, 120, progress); |         elements_progress_bar(canvas, 5, 15, 120, progress); | ||||||
|         canvas_set_font(canvas, FontSecondary); |         canvas_set_font(canvas, FontSecondary); | ||||||
|         snprintf(draw_str, sizeof(draw_str), "Keys found: %d/%d", m->keys_found, m->keys_total); |         snprintf(draw_str, sizeof(draw_str), "Keys found: %d/%d", m->keys_found, m->keys_total); | ||||||
| @ -100,6 +109,8 @@ void dict_attack_reset(DictAttack* dict_attack) { | |||||||
|             model->sector_current = 0; |             model->sector_current = 0; | ||||||
|             model->keys_total = 0; |             model->keys_total = 0; | ||||||
|             model->keys_found = 0; |             model->keys_found = 0; | ||||||
|  |             model->dict_keys_total = 0; | ||||||
|  |             model->dict_keys_current = 0; | ||||||
|             string_reset(model->header); |             string_reset(model->header); | ||||||
|             return false; |             return false; | ||||||
|         }); |         }); | ||||||
| @ -171,6 +182,7 @@ void dict_attack_set_current_sector(DictAttack* dict_attack, uint8_t curr_sec) { | |||||||
|     with_view_model( |     with_view_model( | ||||||
|         dict_attack->view, (DictAttackViewModel * model) { |         dict_attack->view, (DictAttackViewModel * model) { | ||||||
|             model->sector_current = curr_sec; |             model->sector_current = curr_sec; | ||||||
|  |             model->dict_keys_current = 0; | ||||||
|             return true; |             return true; | ||||||
|         }); |         }); | ||||||
| } | } | ||||||
| @ -181,6 +193,7 @@ void dict_attack_inc_current_sector(DictAttack* dict_attack) { | |||||||
|         dict_attack->view, (DictAttackViewModel * model) { |         dict_attack->view, (DictAttackViewModel * model) { | ||||||
|             if(model->sector_current < model->sectors_total) { |             if(model->sector_current < model->sectors_total) { | ||||||
|                 model->sector_current++; |                 model->sector_current++; | ||||||
|  |                 model->dict_keys_current = 0; | ||||||
|             } |             } | ||||||
|             return true; |             return true; | ||||||
|         }); |         }); | ||||||
| @ -196,3 +209,23 @@ void dict_attack_inc_keys_found(DictAttack* dict_attack) { | |||||||
|             return true; |             return true; | ||||||
|         }); |         }); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | void dict_attack_set_total_dict_keys(DictAttack* dict_attack, uint16_t dict_keys_total) { | ||||||
|  |     furi_assert(dict_attack); | ||||||
|  |     with_view_model( | ||||||
|  |         dict_attack->view, (DictAttackViewModel * model) { | ||||||
|  |             model->dict_keys_total = dict_keys_total; | ||||||
|  |             return true; | ||||||
|  |         }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void dict_attack_inc_current_dict_key(DictAttack* dict_attack, uint16_t keys_tried) { | ||||||
|  |     furi_assert(dict_attack); | ||||||
|  |     with_view_model( | ||||||
|  |         dict_attack->view, (DictAttackViewModel * model) { | ||||||
|  |             if(model->dict_keys_current + keys_tried < model->dict_keys_total) { | ||||||
|  |                 model->dict_keys_current += keys_tried; | ||||||
|  |             } | ||||||
|  |             return true; | ||||||
|  |         }); | ||||||
|  | } | ||||||
|  | |||||||
| @ -34,3 +34,7 @@ void dict_attack_set_current_sector(DictAttack* dict_attack, uint8_t curr_sec); | |||||||
| void dict_attack_inc_current_sector(DictAttack* dict_attack); | void dict_attack_inc_current_sector(DictAttack* dict_attack); | ||||||
| 
 | 
 | ||||||
| void dict_attack_inc_keys_found(DictAttack* dict_attack); | void dict_attack_inc_keys_found(DictAttack* dict_attack); | ||||||
|  | 
 | ||||||
|  | void dict_attack_set_total_dict_keys(DictAttack* dict_attack, uint16_t dict_keys_total); | ||||||
|  | 
 | ||||||
|  | void dict_attack_inc_current_dict_key(DictAttack* dict_attack, uint16_t keys_tried); | ||||||
|  | |||||||
| @ -431,6 +431,54 @@ const NotificationSequence sequence_blink_white_100 = { | |||||||
|     NULL, |     NULL, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | // Hardware blink
 | ||||||
|  | const NotificationSequence sequence_blink_start_blue = { | ||||||
|  |     &message_blink_start_10, | ||||||
|  |     &message_blink_set_color_blue, | ||||||
|  |     &message_do_not_reset, | ||||||
|  |     NULL, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const NotificationSequence sequence_blink_start_red = { | ||||||
|  |     &message_blink_start_10, | ||||||
|  |     &message_blink_set_color_red, | ||||||
|  |     &message_do_not_reset, | ||||||
|  |     NULL, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const NotificationSequence sequence_blink_start_green = { | ||||||
|  |     &message_blink_start_10, | ||||||
|  |     &message_blink_set_color_green, | ||||||
|  |     &message_do_not_reset, | ||||||
|  |     NULL, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const NotificationSequence sequence_blink_start_yellow = { | ||||||
|  |     &message_blink_start_10, | ||||||
|  |     &message_blink_set_color_yellow, | ||||||
|  |     &message_do_not_reset, | ||||||
|  |     NULL, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const NotificationSequence sequence_blink_start_cyan = { | ||||||
|  |     &message_blink_start_10, | ||||||
|  |     &message_blink_set_color_cyan, | ||||||
|  |     &message_do_not_reset, | ||||||
|  |     NULL, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const NotificationSequence sequence_blink_start_magenta = { | ||||||
|  |     &message_blink_start_10, | ||||||
|  |     &message_blink_set_color_magenta, | ||||||
|  |     &message_do_not_reset, | ||||||
|  |     NULL, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const NotificationSequence sequence_blink_stop = { | ||||||
|  |     &message_blink_stop, | ||||||
|  |     NULL, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| //General
 | //General
 | ||||||
| const NotificationSequence sequence_single_vibro = { | const NotificationSequence sequence_single_vibro = { | ||||||
|     &message_vibro_on, |     &message_vibro_on, | ||||||
|  | |||||||
| @ -122,6 +122,15 @@ extern const NotificationSequence sequence_blink_cyan_100; | |||||||
| extern const NotificationSequence sequence_blink_magenta_100; | extern const NotificationSequence sequence_blink_magenta_100; | ||||||
| extern const NotificationSequence sequence_blink_white_100; | extern const NotificationSequence sequence_blink_white_100; | ||||||
| 
 | 
 | ||||||
|  | // Hardware blink
 | ||||||
|  | extern const NotificationSequence sequence_blink_start_blue; | ||||||
|  | extern const NotificationSequence sequence_blink_start_red; | ||||||
|  | extern const NotificationSequence sequence_blink_start_green; | ||||||
|  | extern const NotificationSequence sequence_blink_start_yellow; | ||||||
|  | extern const NotificationSequence sequence_blink_start_cyan; | ||||||
|  | extern const NotificationSequence sequence_blink_start_magenta; | ||||||
|  | extern const NotificationSequence sequence_blink_stop; | ||||||
|  | 
 | ||||||
| // General
 | // General
 | ||||||
| extern const NotificationSequence sequence_single_vibro; | extern const NotificationSequence sequence_single_vibro; | ||||||
| extern const NotificationSequence sequence_double_vibro; | extern const NotificationSequence sequence_double_vibro; | ||||||
|  | |||||||
| @ -13,7 +13,7 @@ void picopass_scene_read_card_on_enter(void* context) { | |||||||
| 
 | 
 | ||||||
|     // Setup view
 |     // Setup view
 | ||||||
|     Popup* popup = picopass->popup; |     Popup* popup = picopass->popup; | ||||||
|     popup_set_header(popup, "Detecting\npicopass card", 70, 34, AlignLeft, AlignTop); |     popup_set_header(popup, "Detecting\npicopass\ncard", 68, 30, AlignLeft, AlignTop); | ||||||
|     popup_set_icon(popup, 0, 3, &I_RFIDDolphinReceive_97x61); |     popup_set_icon(popup, 0, 3, &I_RFIDDolphinReceive_97x61); | ||||||
| 
 | 
 | ||||||
|     // Start worker
 |     // Start worker
 | ||||||
|  | |||||||
| @ -57,7 +57,7 @@ BatteryTestApp* battery_test_alloc() { | |||||||
|         battery_info_get_view(app->batery_info)); |         battery_info_get_view(app->batery_info)); | ||||||
| 
 | 
 | ||||||
|     app->dialog = dialog_ex_alloc(); |     app->dialog = dialog_ex_alloc(); | ||||||
|     dialog_ex_set_header(app->dialog, "Close battery test?", 64, 12, AlignCenter, AlignTop); |     dialog_ex_set_header(app->dialog, "Close Battery Test?", 64, 12, AlignCenter, AlignTop); | ||||||
|     dialog_ex_set_left_button_text(app->dialog, "Exit"); |     dialog_ex_set_left_button_text(app->dialog, "Exit"); | ||||||
|     dialog_ex_set_right_button_text(app->dialog, "Stay"); |     dialog_ex_set_right_button_text(app->dialog, "Stay"); | ||||||
|     dialog_ex_set_result_callback(app->dialog, battery_test_dialog_callback); |     dialog_ex_set_result_callback(app->dialog, battery_test_dialog_callback); | ||||||
|  | |||||||
| @ -200,7 +200,7 @@ static void power_check_battery_level_change(Power* power) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int32_t power_srv(void* p) { | int32_t power_srv(void* p) { | ||||||
|     (void)p; |     UNUSED(p); | ||||||
|     Power* power = power_alloc(); |     Power* power = power_alloc(); | ||||||
|     power_update_info(power); |     power_update_info(power); | ||||||
|     furi_record_create(RECORD_POWER, power); |     furi_record_create(RECORD_POWER, power); | ||||||
|  | |||||||
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