Merge remote-tracking branch 'origin/dev' into release-candidate
This commit is contained in:
		
						commit
						cfde6350a6
					
				
							
								
								
									
										3
									
								
								.github/workflows/amap_analyse.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.github/workflows/amap_analyse.yml
									
									
									
									
										vendored
									
									
								
							| @ -62,6 +62,8 @@ jobs: | |||||||
| 
 | 
 | ||||||
|       - name: 'Download build artifacts' |       - name: 'Download build artifacts' | ||||||
|         run: | |         run: | | ||||||
|  |           mkdir -p ~/.ssh | ||||||
|  |           ssh-keyscan -p ${{ secrets.RSYNC_DEPLOY_PORT }} -H ${{ secrets.RSYNC_DEPLOY_HOST }} > ~/.ssh/known_hosts | ||||||
|           echo "${{ secrets.RSYNC_DEPLOY_KEY }}" > deploy_key; |           echo "${{ secrets.RSYNC_DEPLOY_KEY }}" > deploy_key; | ||||||
|           chmod 600 ./deploy_key; |           chmod 600 ./deploy_key; | ||||||
|           rsync -avzP \ |           rsync -avzP \ | ||||||
| @ -97,3 +99,4 @@ jobs: | |||||||
|             ${{ secrets.AMAP_MARIADB_PORT }} \ |             ${{ secrets.AMAP_MARIADB_PORT }} \ | ||||||
|             ${{ secrets.AMAP_MARIADB_DATABASE }} \ |             ${{ secrets.AMAP_MARIADB_DATABASE }} \ | ||||||
|             artifacts/flipper-z-f7-firmware-$SUFFIX.elf.map.all |             artifacts/flipper-z-f7-firmware-$SUFFIX.elf.map.all | ||||||
|  | 
 | ||||||
|  | |||||||
							
								
								
									
										26
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										26
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
								
							| @ -56,14 +56,14 @@ jobs: | |||||||
|       - name: 'Bundle scripts' |       - name: 'Bundle scripts' | ||||||
|         if: ${{ !github.event.pull_request.head.repo.fork }} |         if: ${{ !github.event.pull_request.head.repo.fork }} | ||||||
|         run: | |         run: | | ||||||
|           tar czpf artifacts/flipper-z-any-scripts-${SUFFIX}.tgz scripts |           tar czpf artifacts/flipper-z-any-scripts-${SUFFIX}.tgz scripts debug | ||||||
| 
 | 
 | ||||||
|       - name: 'Build the firmware' |       - name: 'Build the firmware' | ||||||
|         run: | |         run: | | ||||||
|           set -e |           set -e | ||||||
|           for TARGET in ${TARGETS}; do |           for TARGET in ${TARGETS}; do | ||||||
|             FBT_TOOLCHAIN_PATH=/opt ./fbt TARGET_HW="$(echo "${TARGET}" | sed 's/f//')" \ |             FBT_TOOLCHAIN_PATH=/runner/_work ./fbt TARGET_HW="$(echo "${TARGET}" | sed 's/f//')" \ | ||||||
|                 updater_package ${{ startsWith(github.ref, 'refs/tags') && 'DEBUG=0 COMPACT=1' || '' }} |                 copro_dist updater_package ${{ startsWith(github.ref, 'refs/tags') && 'DEBUG=0 COMPACT=1' || '' }} | ||||||
|           done |           done | ||||||
| 
 | 
 | ||||||
|       - name: 'Move upload files' |       - name: 'Move upload files' | ||||||
| @ -74,17 +74,6 @@ jobs: | |||||||
|             mv dist/${TARGET}-*/* artifacts/ |             mv dist/${TARGET}-*/* artifacts/ | ||||||
|           done |           done | ||||||
| 
 | 
 | ||||||
|       - name: 'Bundle self-update package' |  | ||||||
|         if: ${{ !github.event.pull_request.head.repo.fork }} |  | ||||||
|         run: | |  | ||||||
|           set -e |  | ||||||
|           for UPDATEBUNDLE in artifacts/*/; do |  | ||||||
|             BUNDLE_NAME="$(echo "$UPDATEBUNDLE" | cut -d'/' -f2)" |  | ||||||
|             echo Packaging "${BUNDLE_NAME}" |  | ||||||
|             tar czpf "artifacts/flipper-z-${BUNDLE_NAME}.tgz" -C artifacts "${BUNDLE_NAME}" |  | ||||||
|             rm -rf "artifacts/${BUNDLE_NAME}" |  | ||||||
|           done |  | ||||||
| 
 |  | ||||||
|       - name: "Check for uncommitted changes" |       - name: "Check for uncommitted changes" | ||||||
|         run: | |         run: | | ||||||
|           git diff --exit-code |           git diff --exit-code | ||||||
| @ -97,8 +86,7 @@ jobs: | |||||||
|       - name: 'Bundle core2 firmware' |       - name: 'Bundle core2 firmware' | ||||||
|         if: ${{ !github.event.pull_request.head.repo.fork }} |         if: ${{ !github.event.pull_request.head.repo.fork }} | ||||||
|         run: | |         run: | | ||||||
|           FBT_TOOLCHAIN_PATH=/opt ./fbt copro_dist |           cp build/core2_firmware.tgz "artifacts/flipper-z-any-core2_firmware-${SUFFIX}.tgz" | ||||||
|           tar czpf "artifacts/flipper-z-any-core2_firmware-${SUFFIX}.tgz" -C assets core2_firmware |  | ||||||
| 
 | 
 | ||||||
|       - name: 'Copy .map file' |       - name: 'Copy .map file' | ||||||
|         run: | |         run: | | ||||||
| @ -107,6 +95,8 @@ jobs: | |||||||
|       - name: 'Upload artifacts to update server' |       - name: 'Upload artifacts to update server' | ||||||
|         if: ${{ !github.event.pull_request.head.repo.fork }} |         if: ${{ !github.event.pull_request.head.repo.fork }} | ||||||
|         run: | |         run: | | ||||||
|  |           mkdir -p ~/.ssh | ||||||
|  |           ssh-keyscan -p ${{ secrets.RSYNC_DEPLOY_PORT }} -H ${{ secrets.RSYNC_DEPLOY_HOST }} > ~/.ssh/known_hosts | ||||||
|           echo "${{ secrets.RSYNC_DEPLOY_KEY }}" > deploy_key; |           echo "${{ secrets.RSYNC_DEPLOY_KEY }}" > deploy_key; | ||||||
|           chmod 600 ./deploy_key; |           chmod 600 ./deploy_key; | ||||||
|           rsync -avzP --delete --mkpath \ |           rsync -avzP --delete --mkpath \ | ||||||
| @ -137,7 +127,7 @@ jobs: | |||||||
|             **Compiled firmware for commit `${{steps.names.outputs.commit_sha}}`:** |             **Compiled firmware for commit `${{steps.names.outputs.commit_sha}}`:** | ||||||
|             - [📦 Update package](https://update.flipperzero.one/builds/firmware/${{steps.names.outputs.branch_name}}/flipper-z-${{steps.names.outputs.default_target}}-update-${{steps.names.outputs.suffix}}.tgz) |             - [📦 Update package](https://update.flipperzero.one/builds/firmware/${{steps.names.outputs.branch_name}}/flipper-z-${{steps.names.outputs.default_target}}-update-${{steps.names.outputs.suffix}}.tgz) | ||||||
|             - [📥 DFU file](https://update.flipperzero.one/builds/firmware/${{steps.names.outputs.branch_name}}/flipper-z-${{steps.names.outputs.default_target}}-full-${{steps.names.outputs.suffix}}.dfu) |             - [📥 DFU file](https://update.flipperzero.one/builds/firmware/${{steps.names.outputs.branch_name}}/flipper-z-${{steps.names.outputs.default_target}}-full-${{steps.names.outputs.suffix}}.dfu) | ||||||
|             - [☁️ Web updater](https://my.flipp.dev/?url=https://update.flipperzero.one/builds/firmware/${{steps.names.outputs.branch_name}}/flipper-z-${{steps.names.outputs.default_target}}-update-${{steps.names.outputs.suffix}}.tgz&channel=${{steps.names.outputs.branch_name}}&version=${{steps.names.outputs.commit_sha}}) |             - [☁️ Web/App updater](https://my.flipp.dev/?url=https://update.flipperzero.one/builds/firmware/${{steps.names.outputs.branch_name}}/flipper-z-${{steps.names.outputs.default_target}}-update-${{steps.names.outputs.suffix}}.tgz&channel=${{steps.names.outputs.branch_name}}&version=${{steps.names.outputs.commit_sha}}) | ||||||
|           edit-mode: replace |           edit-mode: replace | ||||||
| 
 | 
 | ||||||
|   compact: |   compact: | ||||||
| @ -174,6 +164,6 @@ jobs: | |||||||
|         run: | |         run: | | ||||||
|           set -e |           set -e | ||||||
|           for TARGET in ${TARGETS}; do |           for TARGET in ${TARGETS}; do | ||||||
|             FBT_TOOLCHAIN_PATH=/opt ./fbt TARGET_HW="$(echo "${TARGET}" | sed 's/f//')" \ |             FBT_TOOLCHAIN_PATH=/runner/_work ./fbt TARGET_HW="$(echo "${TARGET}" | sed 's/f//')" \ | ||||||
|                 updater_package DEBUG=0 COMPACT=1 |                 updater_package DEBUG=0 COMPACT=1 | ||||||
|           done |           done | ||||||
|  | |||||||
							
								
								
									
										1
									
								
								.github/workflows/check_submodules.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.github/workflows/check_submodules.yml
									
									
									
									
										vendored
									
									
								
							| @ -27,6 +27,7 @@ jobs: | |||||||
| 
 | 
 | ||||||
|       - name: 'Check protobuf branch' |       - name: 'Check protobuf branch' | ||||||
|         run: | |         run: | | ||||||
|  |           git submodule update --init | ||||||
|           SUB_PATH="assets/protobuf"; |           SUB_PATH="assets/protobuf"; | ||||||
|           SUB_BRANCH="dev"; |           SUB_BRANCH="dev"; | ||||||
|           SUB_COMMITS_MIN=40; |           SUB_COMMITS_MIN=40; | ||||||
|  | |||||||
							
								
								
									
										2
									
								
								.github/workflows/lint_c.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/lint_c.yml
									
									
									
									
										vendored
									
									
								
							| @ -30,7 +30,7 @@ jobs: | |||||||
| 
 | 
 | ||||||
|       - name: 'Check code formatting' |       - name: 'Check code formatting' | ||||||
|         id: syntax_check |         id: syntax_check | ||||||
|         run: SET_GH_OUTPUT=1 FBT_TOOLCHAIN_PATH=/opt ./fbt lint |         run: SET_GH_OUTPUT=1 FBT_TOOLCHAIN_PATH=/runner/_work ./fbt lint | ||||||
| 
 | 
 | ||||||
|       - name: Report code formatting errors |       - name: Report code formatting errors | ||||||
|         if: failure() && steps.syntax_check.outputs.errors && github.event.pull_request |         if: failure() && steps.syntax_check.outputs.errors && github.event.pull_request | ||||||
|  | |||||||
							
								
								
									
										2
									
								
								.github/workflows/lint_python.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/lint_python.yml
									
									
									
									
										vendored
									
									
								
							| @ -26,4 +26,4 @@ jobs: | |||||||
|           ref: ${{ github.event.pull_request.head.sha }} |           ref: ${{ github.event.pull_request.head.sha }} | ||||||
| 
 | 
 | ||||||
|       - name: 'Check code formatting' |       - name: 'Check code formatting' | ||||||
|         run: SET_GH_OUTPUT=1 FBT_TOOLCHAIN_PATH=/opt ./fbt lint_py |         run: SET_GH_OUTPUT=1 FBT_TOOLCHAIN_PATH=/runner/_work ./fbt lint_py | ||||||
|  | |||||||
							
								
								
									
										7
									
								
								.github/workflows/pvs_studio.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								.github/workflows/pvs_studio.yml
									
									
									
									
										vendored
									
									
								
							| @ -57,14 +57,15 @@ jobs: | |||||||
| 
 | 
 | ||||||
|       - name: 'Generate compile_comands.json' |       - name: 'Generate compile_comands.json' | ||||||
|         run: | |         run: | | ||||||
|           FBT_TOOLCHAIN_PATH=/opt ./fbt COMPACT=1 version_json proto_ver icons firmware_cdb dolphin_internal dolphin_blocking |           FBT_TOOLCHAIN_PATH=/runner/_work ./fbt COMPACT=1 version_json proto_ver icons firmware_cdb dolphin_internal dolphin_blocking | ||||||
| 
 | 
 | ||||||
|       - name: 'Static code analysis' |       - name: 'Static code analysis' | ||||||
|         run: | |         run: | | ||||||
|           FBT_TOOLCHAIN_PATH=/opt source scripts/toolchain/fbtenv.sh |           FBT_TOOLCHAIN_PATH=/runner/_work source scripts/toolchain/fbtenv.sh | ||||||
|           pvs-studio-analyzer credentials ${{ secrets.PVS_STUDIO_CREDENTIALS }} |           pvs-studio-analyzer credentials ${{ secrets.PVS_STUDIO_CREDENTIALS }} | ||||||
|           pvs-studio-analyzer analyze \ |           pvs-studio-analyzer analyze \ | ||||||
|               @.pvsoptions \ |               @.pvsoptions \ | ||||||
|  |               --disableLicenseExpirationCheck \ | ||||||
|               -j$(grep -c processor /proc/cpuinfo) \ |               -j$(grep -c processor /proc/cpuinfo) \ | ||||||
|               -f build/f7-firmware-DC/compile_commands.json \ |               -f build/f7-firmware-DC/compile_commands.json \ | ||||||
|               -o PVS-Studio.log |               -o PVS-Studio.log | ||||||
| @ -75,6 +76,8 @@ jobs: | |||||||
|       - name: 'Upload artifacts to update server' |       - name: 'Upload artifacts to update server' | ||||||
|         if: ${{ !github.event.pull_request.head.repo.fork }} |         if: ${{ !github.event.pull_request.head.repo.fork }} | ||||||
|         run: | |         run: | | ||||||
|  |           mkdir -p ~/.ssh | ||||||
|  |           ssh-keyscan -p ${{ secrets.RSYNC_DEPLOY_PORT }} -H ${{ secrets.RSYNC_DEPLOY_HOST }} > ~/.ssh/known_hosts | ||||||
|           echo "${{ secrets.RSYNC_DEPLOY_KEY }}" > deploy_key; |           echo "${{ secrets.RSYNC_DEPLOY_KEY }}" > deploy_key; | ||||||
|           chmod 600 ./deploy_key; |           chmod 600 ./deploy_key; | ||||||
|           rsync -avrzP --mkpath \ |           rsync -avrzP --mkpath \ | ||||||
|  | |||||||
							
								
								
									
										63
									
								
								SConstruct
									
									
									
									
									
								
							
							
						
						
									
										63
									
								
								SConstruct
									
									
									
									
									
								
							| @ -7,7 +7,6 @@ | |||||||
| # construction of certain targets behind command-line options. | # construction of certain targets behind command-line options. | ||||||
| 
 | 
 | ||||||
| import os | import os | ||||||
| import subprocess |  | ||||||
| 
 | 
 | ||||||
| DefaultEnvironment(tools=[]) | DefaultEnvironment(tools=[]) | ||||||
| 
 | 
 | ||||||
| @ -15,17 +14,22 @@ EnsurePythonVersion(3, 8) | |||||||
| 
 | 
 | ||||||
| # Progress(["OwO\r", "owo\r", "uwu\r", "owo\r"], interval=15) | # Progress(["OwO\r", "owo\r", "uwu\r", "owo\r"], interval=15) | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| # This environment is created only for loading options & validating file/dir existence | # This environment is created only for loading options & validating file/dir existence | ||||||
| fbt_variables = SConscript("site_scons/commandline.scons") | fbt_variables = SConscript("site_scons/commandline.scons") | ||||||
| cmd_environment = Environment(tools=[], variables=fbt_variables) | cmd_environment = Environment( | ||||||
| Help(fbt_variables.GenerateHelpText(cmd_environment)) |     toolpath=["#/scripts/fbt_tools"], | ||||||
|  |     tools=[ | ||||||
|  |         ("fbt_help", {"vars": fbt_variables}), | ||||||
|  |     ], | ||||||
|  |     variables=fbt_variables, | ||||||
|  | ) | ||||||
| 
 | 
 | ||||||
| # Building basic environment - tools, utility methods, cross-compilation | # Building basic environment - tools, utility methods, cross-compilation | ||||||
| # settings, gcc flags for Cortex-M4, basic builders and more | # settings, gcc flags for Cortex-M4, basic builders and more | ||||||
| coreenv = SConscript( | coreenv = SConscript( | ||||||
|     "site_scons/environ.scons", |     "site_scons/environ.scons", | ||||||
|     exports={"VAR_ENV": cmd_environment}, |     exports={"VAR_ENV": cmd_environment}, | ||||||
|  |     toolpath=["#/scripts/fbt_tools"], | ||||||
| ) | ) | ||||||
| SConscript("site_scons/cc.scons", exports={"ENV": coreenv}) | SConscript("site_scons/cc.scons", exports={"ENV": coreenv}) | ||||||
| 
 | 
 | ||||||
| @ -35,41 +39,13 @@ coreenv["ROOT_DIR"] = Dir(".") | |||||||
| 
 | 
 | ||||||
| # Create a separate "dist" environment and add construction envs to it | # Create a separate "dist" environment and add construction envs to it | ||||||
| distenv = coreenv.Clone( | distenv = coreenv.Clone( | ||||||
|     tools=["fbt_dist", "openocd", "blackmagic", "jflash"], |     tools=[ | ||||||
|     OPENOCD_GDB_PIPE=[ |         "fbt_dist", | ||||||
|         "|openocd -c 'gdb_port pipe; log_output debug/openocd.log' ${[SINGLEQUOTEFUNC(OPENOCD_OPTS)]}" |         "fbt_debugopts", | ||||||
|  |         "openocd", | ||||||
|  |         "blackmagic", | ||||||
|  |         "jflash", | ||||||
|     ], |     ], | ||||||
|     GDBOPTS_BASE=[ |  | ||||||
|         "-ex", |  | ||||||
|         "target extended-remote ${GDBREMOTE}", |  | ||||||
|         "-ex", |  | ||||||
|         "set confirm off", |  | ||||||
|         "-ex", |  | ||||||
|         "set pagination off", |  | ||||||
|     ], |  | ||||||
|     GDBOPTS_BLACKMAGIC=[ |  | ||||||
|         "-ex", |  | ||||||
|         "monitor swdp_scan", |  | ||||||
|         "-ex", |  | ||||||
|         "monitor debug_bmp enable", |  | ||||||
|         "-ex", |  | ||||||
|         "attach 1", |  | ||||||
|         "-ex", |  | ||||||
|         "set mem inaccessible-by-default off", |  | ||||||
|     ], |  | ||||||
|     GDBPYOPTS=[ |  | ||||||
|         "-ex", |  | ||||||
|         "source debug/FreeRTOS/FreeRTOS.py", |  | ||||||
|         "-ex", |  | ||||||
|         "source debug/flipperapps.py", |  | ||||||
|         "-ex", |  | ||||||
|         "source debug/PyCortexMDebug/PyCortexMDebug.py", |  | ||||||
|         "-ex", |  | ||||||
|         "svd_load ${SVD_FILE}", |  | ||||||
|         "-ex", |  | ||||||
|         "compare-sections", |  | ||||||
|     ], |  | ||||||
|     JFLASHPROJECT="${ROOT_DIR.abspath}/debug/fw.jflash", |  | ||||||
|     ENV=os.environ, |     ENV=os.environ, | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| @ -166,7 +142,7 @@ basic_dist = distenv.DistCommand("fw_dist", distenv["DIST_DEPENDS"]) | |||||||
| distenv.Default(basic_dist) | distenv.Default(basic_dist) | ||||||
| 
 | 
 | ||||||
| dist_dir = distenv.GetProjetDirName() | dist_dir = distenv.GetProjetDirName() | ||||||
| plugin_dist = [ | fap_dist = [ | ||||||
|     distenv.Install( |     distenv.Install( | ||||||
|         f"#/dist/{dist_dir}/apps/debug_elf", |         f"#/dist/{dist_dir}/apps/debug_elf", | ||||||
|         firmware_env["FW_EXTAPPS"]["debug"].values(), |         firmware_env["FW_EXTAPPS"]["debug"].values(), | ||||||
| @ -176,9 +152,9 @@ plugin_dist = [ | |||||||
|         for dist_entry in firmware_env["FW_EXTAPPS"]["dist"].values() |         for dist_entry in firmware_env["FW_EXTAPPS"]["dist"].values() | ||||||
|     ), |     ), | ||||||
| ] | ] | ||||||
| Depends(plugin_dist, firmware_env["FW_EXTAPPS"]["validators"].values()) | Depends(fap_dist, firmware_env["FW_EXTAPPS"]["validators"].values()) | ||||||
| Alias("plugin_dist", plugin_dist) | Alias("fap_dist", fap_dist) | ||||||
| # distenv.Default(plugin_dist) | # distenv.Default(fap_dist) | ||||||
| 
 | 
 | ||||||
| plugin_resources_dist = list( | plugin_resources_dist = list( | ||||||
|     distenv.Install(f"#/assets/resources/apps/{dist_entry[0]}", dist_entry[1]) |     distenv.Install(f"#/assets/resources/apps/{dist_entry[0]}", dist_entry[1]) | ||||||
| @ -189,9 +165,10 @@ distenv.Depends(firmware_env["FW_RESOURCES"], plugin_resources_dist) | |||||||
| 
 | 
 | ||||||
| # Target for bundling core2 package for qFlipper | # Target for bundling core2 package for qFlipper | ||||||
| copro_dist = distenv.CoproBuilder( | copro_dist = distenv.CoproBuilder( | ||||||
|     distenv.Dir("assets/core2_firmware"), |     "#/build/core2_firmware.tgz", | ||||||
|     [], |     [], | ||||||
| ) | ) | ||||||
|  | distenv.AlwaysBuild(copro_dist) | ||||||
| distenv.Alias("copro_dist", copro_dist) | distenv.Alias("copro_dist", copro_dist) | ||||||
| 
 | 
 | ||||||
| firmware_flash = distenv.AddOpenOCDFlashTarget(firmware_env) | firmware_flash = distenv.AddOpenOCDFlashTarget(firmware_env) | ||||||
|  | |||||||
| @ -3,14 +3,13 @@ | |||||||
| #include <gui/canvas.h> | #include <gui/canvas.h> | ||||||
| #include <gui/elements.h> | #include <gui/elements.h> | ||||||
| #include <m-array.h> | #include <m-array.h> | ||||||
| #include <m-string.h> |  | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
| 
 | 
 | ||||||
| struct BtTestParam { | struct BtTestParam { | ||||||
|     const char* label; |     const char* label; | ||||||
|     uint8_t current_value_index; |     uint8_t current_value_index; | ||||||
|     string_t current_value_text; |     FuriString* current_value_text; | ||||||
|     uint8_t values_count; |     uint8_t values_count; | ||||||
|     BtTestParamChangeCallback change_callback; |     BtTestParamChangeCallback change_callback; | ||||||
|     void* context; |     void* context; | ||||||
| @ -85,7 +84,8 @@ static void bt_test_draw_callback(Canvas* canvas, void* _model) { | |||||||
|                 canvas_draw_str(canvas, 50, param_text_y, "<"); |                 canvas_draw_str(canvas, 50, param_text_y, "<"); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             canvas_draw_str(canvas, 61, param_text_y, string_get_cstr(param->current_value_text)); |             canvas_draw_str( | ||||||
|  |                 canvas, 61, param_text_y, furi_string_get_cstr(param->current_value_text)); | ||||||
| 
 | 
 | ||||||
|             if(param->current_value_index < (param->values_count - 1)) { |             if(param->current_value_index < (param->values_count - 1)) { | ||||||
|                 canvas_draw_str(canvas, 113, param_text_y, ">"); |                 canvas_draw_str(canvas, 113, param_text_y, ">"); | ||||||
| @ -154,7 +154,9 @@ static bool bt_test_input_callback(InputEvent* event, void* context) { | |||||||
| 
 | 
 | ||||||
| void bt_test_process_up(BtTest* bt_test) { | void bt_test_process_up(BtTest* bt_test) { | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         bt_test->view, (BtTestModel * model) { |         bt_test->view, | ||||||
|  |         BtTestModel * model, | ||||||
|  |         { | ||||||
|             uint8_t params_on_screen = 3; |             uint8_t params_on_screen = 3; | ||||||
|             if(model->position > 0) { |             if(model->position > 0) { | ||||||
|                 model->position--; |                 model->position--; | ||||||
| @ -168,13 +170,15 @@ void bt_test_process_up(BtTest* bt_test) { | |||||||
|                     model->window_position = model->position - (params_on_screen - 1); |                     model->window_position = model->position - (params_on_screen - 1); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             return true; |         }, | ||||||
|         }); |         true); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void bt_test_process_down(BtTest* bt_test) { | void bt_test_process_down(BtTest* bt_test) { | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         bt_test->view, (BtTestModel * model) { |         bt_test->view, | ||||||
|  |         BtTestModel * model, | ||||||
|  |         { | ||||||
|             uint8_t params_on_screen = 3; |             uint8_t params_on_screen = 3; | ||||||
|             if(model->position < (BtTestParamArray_size(model->params) - 1)) { |             if(model->position < (BtTestParamArray_size(model->params) - 1)) { | ||||||
|                 model->position++; |                 model->position++; | ||||||
| @ -187,8 +191,8 @@ void bt_test_process_down(BtTest* bt_test) { | |||||||
|                 model->position = 0; |                 model->position = 0; | ||||||
|                 model->window_position = 0; |                 model->window_position = 0; | ||||||
|             } |             } | ||||||
|             return true; |         }, | ||||||
|         }); |         true); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| BtTestParam* bt_test_get_selected_param(BtTestModel* model) { | BtTestParam* bt_test_get_selected_param(BtTestModel* model) { | ||||||
| @ -213,7 +217,9 @@ BtTestParam* bt_test_get_selected_param(BtTestModel* model) { | |||||||
| void bt_test_process_left(BtTest* bt_test) { | void bt_test_process_left(BtTest* bt_test) { | ||||||
|     BtTestParam* param; |     BtTestParam* param; | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         bt_test->view, (BtTestModel * model) { |         bt_test->view, | ||||||
|  |         BtTestModel * model, | ||||||
|  |         { | ||||||
|             param = bt_test_get_selected_param(model); |             param = bt_test_get_selected_param(model); | ||||||
|             if(param->current_value_index > 0) { |             if(param->current_value_index > 0) { | ||||||
|                 param->current_value_index--; |                 param->current_value_index--; | ||||||
| @ -225,8 +231,8 @@ void bt_test_process_left(BtTest* bt_test) { | |||||||
|                     model->packets_num_tx = 0; |                     model->packets_num_tx = 0; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             return true; |         }, | ||||||
|         }); |         true); | ||||||
|     if(param->change_callback) { |     if(param->change_callback) { | ||||||
|         param->change_callback(param); |         param->change_callback(param); | ||||||
|     } |     } | ||||||
| @ -235,7 +241,9 @@ void bt_test_process_left(BtTest* bt_test) { | |||||||
| void bt_test_process_right(BtTest* bt_test) { | void bt_test_process_right(BtTest* bt_test) { | ||||||
|     BtTestParam* param; |     BtTestParam* param; | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         bt_test->view, (BtTestModel * model) { |         bt_test->view, | ||||||
|  |         BtTestModel * model, | ||||||
|  |         { | ||||||
|             param = bt_test_get_selected_param(model); |             param = bt_test_get_selected_param(model); | ||||||
|             if(param->current_value_index < (param->values_count - 1)) { |             if(param->current_value_index < (param->values_count - 1)) { | ||||||
|                 param->current_value_index++; |                 param->current_value_index++; | ||||||
| @ -247,8 +255,8 @@ void bt_test_process_right(BtTest* bt_test) { | |||||||
|                     model->packets_num_tx = 0; |                     model->packets_num_tx = 0; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             return true; |         }, | ||||||
|         }); |         true); | ||||||
|     if(param->change_callback) { |     if(param->change_callback) { | ||||||
|         param->change_callback(param); |         param->change_callback(param); | ||||||
|     } |     } | ||||||
| @ -257,7 +265,9 @@ void bt_test_process_right(BtTest* bt_test) { | |||||||
| void bt_test_process_ok(BtTest* bt_test) { | void bt_test_process_ok(BtTest* bt_test) { | ||||||
|     BtTestState state; |     BtTestState state; | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         bt_test->view, (BtTestModel * model) { |         bt_test->view, | ||||||
|  |         BtTestModel * model, | ||||||
|  |         { | ||||||
|             if(model->state == BtTestStateStarted) { |             if(model->state == BtTestStateStarted) { | ||||||
|                 model->state = BtTestStateStopped; |                 model->state = BtTestStateStopped; | ||||||
|                 model->message = BT_TEST_START_MESSAGE; |                 model->message = BT_TEST_START_MESSAGE; | ||||||
| @ -269,8 +279,8 @@ void bt_test_process_ok(BtTest* bt_test) { | |||||||
|                 model->message = BT_TEST_STOP_MESSAGE; |                 model->message = BT_TEST_STOP_MESSAGE; | ||||||
|             } |             } | ||||||
|             state = model->state; |             state = model->state; | ||||||
|             return true; |         }, | ||||||
|         }); |         true); | ||||||
|     if(bt_test->change_state_callback) { |     if(bt_test->change_state_callback) { | ||||||
|         bt_test->change_state_callback(state, bt_test->context); |         bt_test->change_state_callback(state, bt_test->context); | ||||||
|     } |     } | ||||||
| @ -278,13 +288,15 @@ void bt_test_process_ok(BtTest* bt_test) { | |||||||
| 
 | 
 | ||||||
| void bt_test_process_back(BtTest* bt_test) { | void bt_test_process_back(BtTest* bt_test) { | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         bt_test->view, (BtTestModel * model) { |         bt_test->view, | ||||||
|  |         BtTestModel * model, | ||||||
|  |         { | ||||||
|             model->state = BtTestStateStopped; |             model->state = BtTestStateStopped; | ||||||
|             model->rssi = 0.0f; |             model->rssi = 0.0f; | ||||||
|             model->packets_num_rx = 0; |             model->packets_num_rx = 0; | ||||||
|             model->packets_num_tx = 0; |             model->packets_num_tx = 0; | ||||||
|             return false; |         }, | ||||||
|         }); |         false); | ||||||
|     if(bt_test->back_callback) { |     if(bt_test->back_callback) { | ||||||
|         bt_test->back_callback(bt_test->context); |         bt_test->back_callback(bt_test->context); | ||||||
|     } |     } | ||||||
| @ -299,7 +311,9 @@ BtTest* bt_test_alloc() { | |||||||
|     view_set_input_callback(bt_test->view, bt_test_input_callback); |     view_set_input_callback(bt_test->view, bt_test_input_callback); | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         bt_test->view, (BtTestModel * model) { |         bt_test->view, | ||||||
|  |         BtTestModel * model, | ||||||
|  |         { | ||||||
|             model->state = BtTestStateStopped; |             model->state = BtTestStateStopped; | ||||||
|             model->message = "Ok - Start"; |             model->message = "Ok - Start"; | ||||||
|             BtTestParamArray_init(model->params); |             BtTestParamArray_init(model->params); | ||||||
| @ -308,8 +322,8 @@ BtTest* bt_test_alloc() { | |||||||
|             model->rssi = 0.0f; |             model->rssi = 0.0f; | ||||||
|             model->packets_num_tx = 0; |             model->packets_num_tx = 0; | ||||||
|             model->packets_num_rx = 0; |             model->packets_num_rx = 0; | ||||||
|             return true; |         }, | ||||||
|         }); |         true); | ||||||
| 
 | 
 | ||||||
|     return bt_test; |     return bt_test; | ||||||
| } | } | ||||||
| @ -318,15 +332,17 @@ void bt_test_free(BtTest* bt_test) { | |||||||
|     furi_assert(bt_test); |     furi_assert(bt_test); | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         bt_test->view, (BtTestModel * model) { |         bt_test->view, | ||||||
|  |         BtTestModel * model, | ||||||
|  |         { | ||||||
|             BtTestParamArray_it_t it; |             BtTestParamArray_it_t it; | ||||||
|             for(BtTestParamArray_it(it, model->params); !BtTestParamArray_end_p(it); |             for(BtTestParamArray_it(it, model->params); !BtTestParamArray_end_p(it); | ||||||
|                 BtTestParamArray_next(it)) { |                 BtTestParamArray_next(it)) { | ||||||
|                 string_clear(BtTestParamArray_ref(it)->current_value_text); |                 furi_string_free(BtTestParamArray_ref(it)->current_value_text); | ||||||
|             } |             } | ||||||
|             BtTestParamArray_clear(model->params); |             BtTestParamArray_clear(model->params); | ||||||
|             return false; |         }, | ||||||
|         }); |         false); | ||||||
|     view_free(bt_test->view); |     view_free(bt_test->view); | ||||||
|     free(bt_test); |     free(bt_test); | ||||||
| } | } | ||||||
| @ -347,16 +363,18 @@ BtTestParam* bt_test_param_add( | |||||||
|     furi_assert(bt_test); |     furi_assert(bt_test); | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         bt_test->view, (BtTestModel * model) { |         bt_test->view, | ||||||
|  |         BtTestModel * model, | ||||||
|  |         { | ||||||
|             param = BtTestParamArray_push_new(model->params); |             param = BtTestParamArray_push_new(model->params); | ||||||
|             param->label = label; |             param->label = label; | ||||||
|             param->values_count = values_count; |             param->values_count = values_count; | ||||||
|             param->change_callback = change_callback; |             param->change_callback = change_callback; | ||||||
|             param->context = context; |             param->context = context; | ||||||
|             param->current_value_index = 0; |             param->current_value_index = 0; | ||||||
|             string_init(param->current_value_text); |             param->current_value_text = furi_string_alloc(); | ||||||
|             return true; |         }, | ||||||
|         }); |         true); | ||||||
| 
 | 
 | ||||||
|     return param; |     return param; | ||||||
| } | } | ||||||
| @ -364,28 +382,19 @@ BtTestParam* bt_test_param_add( | |||||||
| void bt_test_set_rssi(BtTest* bt_test, float rssi) { | void bt_test_set_rssi(BtTest* bt_test, float rssi) { | ||||||
|     furi_assert(bt_test); |     furi_assert(bt_test); | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         bt_test->view, (BtTestModel * model) { |         bt_test->view, BtTestModel * model, { model->rssi = rssi; }, true); | ||||||
|             model->rssi = rssi; |  | ||||||
|             return true; |  | ||||||
|         }); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void bt_test_set_packets_tx(BtTest* bt_test, uint32_t packets_num) { | void bt_test_set_packets_tx(BtTest* bt_test, uint32_t packets_num) { | ||||||
|     furi_assert(bt_test); |     furi_assert(bt_test); | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         bt_test->view, (BtTestModel * model) { |         bt_test->view, BtTestModel * model, { model->packets_num_tx = packets_num; }, true); | ||||||
|             model->packets_num_tx = packets_num; |  | ||||||
|             return true; |  | ||||||
|         }); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void bt_test_set_packets_rx(BtTest* bt_test, uint32_t packets_num) { | void bt_test_set_packets_rx(BtTest* bt_test, uint32_t packets_num) { | ||||||
|     furi_assert(bt_test); |     furi_assert(bt_test); | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         bt_test->view, (BtTestModel * model) { |         bt_test->view, BtTestModel * model, { model->packets_num_rx = packets_num; }, true); | ||||||
|             model->packets_num_rx = packets_num; |  | ||||||
|             return true; |  | ||||||
|         }); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void bt_test_set_change_state_callback(BtTest* bt_test, BtTestChangeStateCallback callback) { | void bt_test_set_change_state_callback(BtTest* bt_test, BtTestChangeStateCallback callback) { | ||||||
| @ -410,7 +419,7 @@ void bt_test_set_current_value_index(BtTestParam* param, uint8_t current_value_i | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void bt_test_set_current_value_text(BtTestParam* param, const char* current_value_text) { | void bt_test_set_current_value_text(BtTestParam* param, const char* current_value_text) { | ||||||
|     string_set_str(param->current_value_text, current_value_text); |     furi_string_set(param->current_value_text, current_value_text); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| uint8_t bt_test_get_current_value_index(BtTestParam* param) { | uint8_t bt_test_get_current_value_index(BtTestParam* param) { | ||||||
|  | |||||||
| @ -113,11 +113,11 @@ static void display_config_set_regulation_ratio(VariableItem* item) { | |||||||
| static void display_config_set_contrast(VariableItem* item) { | static void display_config_set_contrast(VariableItem* item) { | ||||||
|     DisplayTest* instance = variable_item_get_context(item); |     DisplayTest* instance = variable_item_get_context(item); | ||||||
|     uint8_t index = variable_item_get_current_value_index(item); |     uint8_t index = variable_item_get_current_value_index(item); | ||||||
|     string_t temp; |     FuriString* temp; | ||||||
|     string_init(temp); |     temp = furi_string_alloc(); | ||||||
|     string_cat_printf(temp, "%d", index); |     furi_string_cat_printf(temp, "%d", index); | ||||||
|     variable_item_set_current_value_text(item, string_get_cstr(temp)); |     variable_item_set_current_value_text(item, furi_string_get_cstr(temp)); | ||||||
|     string_clear(temp); |     furi_string_free(temp); | ||||||
|     instance->config_contrast = index; |     instance->config_contrast = index; | ||||||
|     display_test_reload_config(instance); |     display_test_reload_config(instance); | ||||||
| } | } | ||||||
|  | |||||||
| @ -110,7 +110,9 @@ static bool view_display_test_input_callback(InputEvent* event, void* context) { | |||||||
|     bool consumed = false; |     bool consumed = false; | ||||||
|     if(event->type == InputTypeShort || event->type == InputTypeRepeat) { |     if(event->type == InputTypeShort || event->type == InputTypeRepeat) { | ||||||
|         with_view_model( |         with_view_model( | ||||||
|             instance->view, (ViewDisplayTestModel * model) { |             instance->view, | ||||||
|  |             ViewDisplayTestModel * model, | ||||||
|  |             { | ||||||
|                 if(event->key == InputKeyLeft && model->test > 0) { |                 if(event->key == InputKeyLeft && model->test > 0) { | ||||||
|                     model->test--; |                     model->test--; | ||||||
|                     consumed = true; |                     consumed = true; | ||||||
| @ -129,8 +131,8 @@ static bool view_display_test_input_callback(InputEvent* event, void* context) { | |||||||
|                     model->flip_flop = !model->flip_flop; |                     model->flip_flop = !model->flip_flop; | ||||||
|                     consumed = true; |                     consumed = true; | ||||||
|                 } |                 } | ||||||
|                 return consumed; |             }, | ||||||
|             }); |             consumed); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return consumed; |     return consumed; | ||||||
| @ -149,10 +151,7 @@ static void view_display_test_exit(void* context) { | |||||||
| static void view_display_test_timer_callback(void* context) { | static void view_display_test_timer_callback(void* context) { | ||||||
|     ViewDisplayTest* instance = context; |     ViewDisplayTest* instance = context; | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         instance->view, (ViewDisplayTestModel * model) { |         instance->view, ViewDisplayTestModel * model, { model->counter++; }, true); | ||||||
|             model->counter++; |  | ||||||
|             return true; |  | ||||||
|         }); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ViewDisplayTest* view_display_test_alloc() { | ViewDisplayTest* view_display_test_alloc() { | ||||||
|  | |||||||
| @ -1,7 +1,6 @@ | |||||||
| #include "assets_icons.h" | #include "assets_icons.h" | ||||||
| #include "file_browser_app_i.h" | #include "file_browser_app_i.h" | ||||||
| #include "gui/modules/file_browser.h" | #include "gui/modules/file_browser.h" | ||||||
| #include "m-string.h" |  | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| #include <furi_hal.h> | #include <furi_hal.h> | ||||||
| #include <storage/storage.h> | #include <storage/storage.h> | ||||||
| @ -47,7 +46,7 @@ FileBrowserApp* file_browser_app_alloc(char* arg) { | |||||||
| 
 | 
 | ||||||
|     app->widget = widget_alloc(); |     app->widget = widget_alloc(); | ||||||
| 
 | 
 | ||||||
|     string_init(app->file_path); |     app->file_path = furi_string_alloc(); | ||||||
|     app->file_browser = file_browser_alloc(app->file_path); |     app->file_browser = file_browser_alloc(app->file_path); | ||||||
|     file_browser_configure(app->file_browser, "*", true, &I_badusb_10px, true); |     file_browser_configure(app->file_browser, "*", true, &I_badusb_10px, true); | ||||||
| 
 | 
 | ||||||
| @ -84,7 +83,7 @@ void file_browser_app_free(FileBrowserApp* app) { | |||||||
|     furi_record_close(RECORD_NOTIFICATION); |     furi_record_close(RECORD_NOTIFICATION); | ||||||
|     furi_record_close(RECORD_DIALOGS); |     furi_record_close(RECORD_DIALOGS); | ||||||
| 
 | 
 | ||||||
|     string_clear(app->file_path); |     furi_string_free(app->file_path); | ||||||
| 
 | 
 | ||||||
|     free(app); |     free(app); | ||||||
| } | } | ||||||
|  | |||||||
| @ -22,7 +22,7 @@ struct FileBrowserApp { | |||||||
|     Widget* widget; |     Widget* widget; | ||||||
|     FileBrowser* file_browser; |     FileBrowser* file_browser; | ||||||
| 
 | 
 | ||||||
|     string_t file_path; |     FuriString* file_path; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|  | |||||||
| @ -1,8 +1,5 @@ | |||||||
| #include "../file_browser_app_i.h" | #include "../file_browser_app_i.h" | ||||||
| #include <core/check.h> | #include <furi.h> | ||||||
| #include <core/log.h> |  | ||||||
| #include "furi_hal.h" |  | ||||||
| #include "m-string.h" |  | ||||||
| 
 | 
 | ||||||
| #define DEFAULT_PATH "/" | #define DEFAULT_PATH "/" | ||||||
| #define EXTENSION "*" | #define EXTENSION "*" | ||||||
|  | |||||||
| @ -1,6 +1,5 @@ | |||||||
| #include "../file_browser_app_i.h" | #include "../file_browser_app_i.h" | ||||||
| #include "furi_hal.h" | #include <furi.h> | ||||||
| #include "m-string.h" |  | ||||||
| 
 | 
 | ||||||
| void file_browser_scene_result_ok_callback(InputType type, void* context) { | void file_browser_scene_result_ok_callback(InputType type, void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
| @ -24,7 +23,13 @@ void file_browser_scene_result_on_enter(void* context) { | |||||||
|     FileBrowserApp* app = context; |     FileBrowserApp* app = context; | ||||||
| 
 | 
 | ||||||
|     widget_add_string_multiline_element( |     widget_add_string_multiline_element( | ||||||
|         app->widget, 64, 10, AlignCenter, AlignTop, FontSecondary, string_get_cstr(app->file_path)); |         app->widget, | ||||||
|  |         64, | ||||||
|  |         10, | ||||||
|  |         AlignCenter, | ||||||
|  |         AlignTop, | ||||||
|  |         FontSecondary, | ||||||
|  |         furi_string_get_cstr(app->file_path)); | ||||||
| 
 | 
 | ||||||
|     view_dispatcher_switch_to_view(app->view_dispatcher, FileBrowserAppViewResult); |     view_dispatcher_switch_to_view(app->view_dispatcher, FileBrowserAppViewResult); | ||||||
| } | } | ||||||
|  | |||||||
| @ -19,7 +19,7 @@ bool file_browser_scene_start_on_event(void* context, SceneManagerEvent event) { | |||||||
|     bool consumed = false; |     bool consumed = false; | ||||||
| 
 | 
 | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         string_set_str(app->file_path, ANY_PATH("badusb/demo_windows.txt")); |         furi_string_set(app->file_path, ANY_PATH("badusb/demo_windows.txt")); | ||||||
|         scene_manager_next_scene(app->scene_manager, FileBrowserSceneBrowser); |         scene_manager_next_scene(app->scene_manager, FileBrowserSceneBrowser); | ||||||
|         consumed = true; |         consumed = true; | ||||||
|     } else if(event.type == SceneManagerEventTypeTick) { |     } else if(event.type == SceneManagerEventTypeTick) { | ||||||
|  | |||||||
| @ -52,23 +52,29 @@ static void lfrfid_debug_view_tune_draw_callback(Canvas* canvas, void* _model) { | |||||||
| 
 | 
 | ||||||
| static void lfrfid_debug_view_tune_button_up(LfRfidTuneView* tune_view) { | static void lfrfid_debug_view_tune_button_up(LfRfidTuneView* tune_view) { | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         tune_view->view, (LfRfidTuneViewModel * model) { |         tune_view->view, | ||||||
|  |         LfRfidTuneViewModel * model, | ||||||
|  |         { | ||||||
|             if(model->pos > 0) model->pos--; |             if(model->pos > 0) model->pos--; | ||||||
|             return true; |         }, | ||||||
|         }); |         true); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void lfrfid_debug_view_tune_button_down(LfRfidTuneView* tune_view) { | static void lfrfid_debug_view_tune_button_down(LfRfidTuneView* tune_view) { | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         tune_view->view, (LfRfidTuneViewModel * model) { |         tune_view->view, | ||||||
|  |         LfRfidTuneViewModel * model, | ||||||
|  |         { | ||||||
|             if(model->pos < 1) model->pos++; |             if(model->pos < 1) model->pos++; | ||||||
|             return true; |         }, | ||||||
|         }); |         true); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void lfrfid_debug_view_tune_button_left(LfRfidTuneView* tune_view) { | static void lfrfid_debug_view_tune_button_left(LfRfidTuneView* tune_view) { | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         tune_view->view, (LfRfidTuneViewModel * model) { |         tune_view->view, | ||||||
|  |         LfRfidTuneViewModel * model, | ||||||
|  |         { | ||||||
|             if(model->pos == 0) { |             if(model->pos == 0) { | ||||||
|                 if(model->fine) { |                 if(model->fine) { | ||||||
|                     model->ARR -= 1; |                     model->ARR -= 1; | ||||||
| @ -84,13 +90,15 @@ static void lfrfid_debug_view_tune_button_left(LfRfidTuneView* tune_view) { | |||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             model->dirty = true; |             model->dirty = true; | ||||||
|             return true; |         }, | ||||||
|         }); |         true); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void lfrfid_debug_view_tune_button_right(LfRfidTuneView* tune_view) { | static void lfrfid_debug_view_tune_button_right(LfRfidTuneView* tune_view) { | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         tune_view->view, (LfRfidTuneViewModel * model) { |         tune_view->view, | ||||||
|  |         LfRfidTuneViewModel * model, | ||||||
|  |         { | ||||||
|             if(model->pos == 0) { |             if(model->pos == 0) { | ||||||
|                 if(model->fine) { |                 if(model->fine) { | ||||||
|                     model->ARR += 1; |                     model->ARR += 1; | ||||||
| @ -106,16 +114,13 @@ static void lfrfid_debug_view_tune_button_right(LfRfidTuneView* tune_view) { | |||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             model->dirty = true; |             model->dirty = true; | ||||||
|             return true; |         }, | ||||||
|         }); |         true); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void lfrfid_debug_view_tune_button_ok(LfRfidTuneView* tune_view) { | static void lfrfid_debug_view_tune_button_ok(LfRfidTuneView* tune_view) { | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         tune_view->view, (LfRfidTuneViewModel * model) { |         tune_view->view, LfRfidTuneViewModel * model, { model->fine = !model->fine; }, true); | ||||||
|             model->fine = !model->fine; |  | ||||||
|             return true; |  | ||||||
|         }); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static bool lfrfid_debug_view_tune_input_callback(InputEvent* event, void* context) { | static bool lfrfid_debug_view_tune_input_callback(InputEvent* event, void* context) { | ||||||
| @ -158,14 +163,16 @@ LfRfidTuneView* lfrfid_debug_view_tune_alloc() { | |||||||
|     view_allocate_model(tune_view->view, ViewModelTypeLocking, sizeof(LfRfidTuneViewModel)); |     view_allocate_model(tune_view->view, ViewModelTypeLocking, sizeof(LfRfidTuneViewModel)); | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         tune_view->view, (LfRfidTuneViewModel * model) { |         tune_view->view, | ||||||
|  |         LfRfidTuneViewModel * model, | ||||||
|  |         { | ||||||
|             model->dirty = true; |             model->dirty = true; | ||||||
|             model->fine = false; |             model->fine = false; | ||||||
|             model->ARR = 511; |             model->ARR = 511; | ||||||
|             model->CCR = 255; |             model->CCR = 255; | ||||||
|             model->pos = 0; |             model->pos = 0; | ||||||
|             return true; |         }, | ||||||
|         }); |         true); | ||||||
| 
 | 
 | ||||||
|     view_set_draw_callback(tune_view->view, lfrfid_debug_view_tune_draw_callback); |     view_set_draw_callback(tune_view->view, lfrfid_debug_view_tune_draw_callback); | ||||||
|     view_set_input_callback(tune_view->view, lfrfid_debug_view_tune_input_callback); |     view_set_input_callback(tune_view->view, lfrfid_debug_view_tune_input_callback); | ||||||
| @ -184,24 +191,28 @@ View* lfrfid_debug_view_tune_get_view(LfRfidTuneView* tune_view) { | |||||||
| 
 | 
 | ||||||
| void lfrfid_debug_view_tune_clean(LfRfidTuneView* tune_view) { | void lfrfid_debug_view_tune_clean(LfRfidTuneView* tune_view) { | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         tune_view->view, (LfRfidTuneViewModel * model) { |         tune_view->view, | ||||||
|  |         LfRfidTuneViewModel * model, | ||||||
|  |         { | ||||||
|             model->dirty = true; |             model->dirty = true; | ||||||
|             model->fine = false; |             model->fine = false; | ||||||
|             model->ARR = 511; |             model->ARR = 511; | ||||||
|             model->CCR = 255; |             model->CCR = 255; | ||||||
|             model->pos = 0; |             model->pos = 0; | ||||||
|             return true; |         }, | ||||||
|         }); |         true); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool lfrfid_debug_view_tune_is_dirty(LfRfidTuneView* tune_view) { | bool lfrfid_debug_view_tune_is_dirty(LfRfidTuneView* tune_view) { | ||||||
|     bool result = false; |     bool result = false; | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         tune_view->view, (LfRfidTuneViewModel * model) { |         tune_view->view, | ||||||
|  |         LfRfidTuneViewModel * model, | ||||||
|  |         { | ||||||
|             result = model->dirty; |             result = model->dirty; | ||||||
|             model->dirty = false; |             model->dirty = false; | ||||||
|             return false; |         }, | ||||||
|         }); |         false); | ||||||
| 
 | 
 | ||||||
|     return result; |     return result; | ||||||
| } | } | ||||||
| @ -209,10 +220,7 @@ bool lfrfid_debug_view_tune_is_dirty(LfRfidTuneView* tune_view) { | |||||||
| uint32_t lfrfid_debug_view_tune_get_arr(LfRfidTuneView* tune_view) { | uint32_t lfrfid_debug_view_tune_get_arr(LfRfidTuneView* tune_view) { | ||||||
|     uint32_t result = false; |     uint32_t result = false; | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         tune_view->view, (LfRfidTuneViewModel * model) { |         tune_view->view, LfRfidTuneViewModel * model, { result = model->ARR; }, false); | ||||||
|             result = model->ARR; |  | ||||||
|             return false; |  | ||||||
|         }); |  | ||||||
| 
 | 
 | ||||||
|     return result; |     return result; | ||||||
| } | } | ||||||
| @ -220,10 +228,7 @@ uint32_t lfrfid_debug_view_tune_get_arr(LfRfidTuneView* tune_view) { | |||||||
| uint32_t lfrfid_debug_view_tune_get_ccr(LfRfidTuneView* tune_view) { | uint32_t lfrfid_debug_view_tune_get_ccr(LfRfidTuneView* tune_view) { | ||||||
|     uint32_t result = false; |     uint32_t result = false; | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         tune_view->view, (LfRfidTuneViewModel * model) { |         tune_view->view, LfRfidTuneViewModel * model, { result = model->CCR; }, false); | ||||||
|             result = model->CCR; |  | ||||||
|             return false; |  | ||||||
|         }); |  | ||||||
| 
 | 
 | ||||||
|     return result; |     return result; | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,10 +1,8 @@ | |||||||
| #include <furi.h> | #include <furi.h> | ||||||
| #include <m-string.h> |  | ||||||
| #include <gui/gui.h> | #include <gui/gui.h> | ||||||
| #include <notification/notification.h> | #include <notification/notification.h> | ||||||
| #include <notification/notification_messages.h> | #include <notification/notification_messages.h> | ||||||
| #include <gui/elements.h> | #include <gui/elements.h> | ||||||
| #include <stream_buffer.h> |  | ||||||
| #include <furi_hal_uart.h> | #include <furi_hal_uart.h> | ||||||
| #include <furi_hal_console.h> | #include <furi_hal_console.h> | ||||||
| #include <gui/view_dispatcher.h> | #include <gui/view_dispatcher.h> | ||||||
| @ -21,11 +19,11 @@ typedef struct { | |||||||
|     ViewDispatcher* view_dispatcher; |     ViewDispatcher* view_dispatcher; | ||||||
|     View* view; |     View* view; | ||||||
|     FuriThread* worker_thread; |     FuriThread* worker_thread; | ||||||
|     StreamBufferHandle_t rx_stream; |     FuriStreamBuffer* rx_stream; | ||||||
| } UartEchoApp; | } UartEchoApp; | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     string_t text; |     FuriString* text; | ||||||
| } ListElement; | } ListElement; | ||||||
| 
 | 
 | ||||||
| struct UartDumpModel { | struct UartDumpModel { | ||||||
| @ -64,10 +62,11 @@ static void uart_echo_view_draw_callback(Canvas* canvas, void* _model) { | |||||||
|             canvas, |             canvas, | ||||||
|             0, |             0, | ||||||
|             (i + 1) * (canvas_current_font_height(canvas) - 1), |             (i + 1) * (canvas_current_font_height(canvas) - 1), | ||||||
|             string_get_cstr(model->list[i]->text)); |             furi_string_get_cstr(model->list[i]->text)); | ||||||
| 
 | 
 | ||||||
|         if(i == model->line) { |         if(i == model->line) { | ||||||
|             uint8_t width = canvas_string_width(canvas, string_get_cstr(model->list[i]->text)); |             uint8_t width = | ||||||
|  |                 canvas_string_width(canvas, furi_string_get_cstr(model->list[i]->text)); | ||||||
| 
 | 
 | ||||||
|             canvas_draw_box( |             canvas_draw_box( | ||||||
|                 canvas, |                 canvas, | ||||||
| @ -92,13 +91,11 @@ static uint32_t uart_echo_exit(void* context) { | |||||||
| 
 | 
 | ||||||
| static void uart_echo_on_irq_cb(UartIrqEvent ev, uint8_t data, void* context) { | static void uart_echo_on_irq_cb(UartIrqEvent ev, uint8_t data, void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     BaseType_t xHigherPriorityTaskWoken = pdFALSE; |  | ||||||
|     UartEchoApp* app = context; |     UartEchoApp* app = context; | ||||||
| 
 | 
 | ||||||
|     if(ev == UartIrqEventRXNE) { |     if(ev == UartIrqEventRXNE) { | ||||||
|         xStreamBufferSendFromISR(app->rx_stream, &data, 1, &xHigherPriorityTaskWoken); |         furi_stream_buffer_send(app->rx_stream, &data, 1, 0); | ||||||
|         furi_thread_flags_set(furi_thread_get_id(app->worker_thread), WorkerEventRx); |         furi_thread_flags_set(furi_thread_get_id(app->worker_thread), WorkerEventRx); | ||||||
|         portYIELD_FROM_ISR(xHigherPriorityTaskWoken); |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -113,7 +110,7 @@ static void uart_echo_push_to_list(UartDumpModel* model, const char data) { | |||||||
|         model->escape = true; |         model->escape = true; | ||||||
|     } else if((data >= ' ' && data <= '~') || (data == '\n' || data == '\r')) { |     } else if((data >= ' ' && data <= '~') || (data == '\n' || data == '\r')) { | ||||||
|         bool new_string_needed = false; |         bool new_string_needed = false; | ||||||
|         if(string_size(model->list[model->line]->text) >= COLUMNS_ON_SCREEN) { |         if(furi_string_size(model->list[model->line]->text) >= COLUMNS_ON_SCREEN) { | ||||||
|             new_string_needed = true; |             new_string_needed = true; | ||||||
|         } else if((data == '\n' || data == '\r')) { |         } else if((data == '\n' || data == '\r')) { | ||||||
|             // pack line breaks
 |             // pack line breaks
 | ||||||
| @ -132,13 +129,13 @@ static void uart_echo_push_to_list(UartDumpModel* model, const char data) { | |||||||
|                     model->list[i - 1] = model->list[i]; |                     model->list[i - 1] = model->list[i]; | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 string_reset(first->text); |                 furi_string_reset(first->text); | ||||||
|                 model->list[model->line] = first; |                 model->list[model->line] = first; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if(data != '\n' && data != '\r') { |         if(data != '\n' && data != '\r') { | ||||||
|             string_push_back(model->list[model->line]->text, data); |             furi_string_push_back(model->list[model->line]->text, data); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     model->last_char = data; |     model->last_char = data; | ||||||
| @ -158,25 +155,24 @@ static int32_t uart_echo_worker(void* context) { | |||||||
|             size_t length = 0; |             size_t length = 0; | ||||||
|             do { |             do { | ||||||
|                 uint8_t data[64]; |                 uint8_t data[64]; | ||||||
|                 length = xStreamBufferReceive(app->rx_stream, data, 64, 0); |                 length = furi_stream_buffer_receive(app->rx_stream, data, 64, 0); | ||||||
|                 if(length > 0) { |                 if(length > 0) { | ||||||
|                     furi_hal_uart_tx(FuriHalUartIdUSART1, data, length); |                     furi_hal_uart_tx(FuriHalUartIdUSART1, data, length); | ||||||
|                     with_view_model( |                     with_view_model( | ||||||
|                         app->view, (UartDumpModel * model) { |                         app->view, | ||||||
|  |                         UartDumpModel * model, | ||||||
|  |                         { | ||||||
|                             for(size_t i = 0; i < length; i++) { |                             for(size_t i = 0; i < length; i++) { | ||||||
|                                 uart_echo_push_to_list(model, data[i]); |                                 uart_echo_push_to_list(model, data[i]); | ||||||
|                             } |                             } | ||||||
|                             return false; |                         }, | ||||||
|                         }); |                         false); | ||||||
|                 } |                 } | ||||||
|             } while(length > 0); |             } while(length > 0); | ||||||
| 
 | 
 | ||||||
|             notification_message(app->notification, &sequence_notification); |             notification_message(app->notification, &sequence_notification); | ||||||
|             with_view_model( |             with_view_model( | ||||||
|                 app->view, (UartDumpModel * model) { |                 app->view, UartDumpModel * model, { UNUSED(model); }, true); | ||||||
|                     UNUSED(model); |  | ||||||
|                     return true; |  | ||||||
|                 }); |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -186,7 +182,7 @@ static int32_t uart_echo_worker(void* context) { | |||||||
| static UartEchoApp* uart_echo_app_alloc() { | static UartEchoApp* uart_echo_app_alloc() { | ||||||
|     UartEchoApp* app = malloc(sizeof(UartEchoApp)); |     UartEchoApp* app = malloc(sizeof(UartEchoApp)); | ||||||
| 
 | 
 | ||||||
|     app->rx_stream = xStreamBufferCreate(2048, 1); |     app->rx_stream = furi_stream_buffer_alloc(2048, 1); | ||||||
| 
 | 
 | ||||||
|     // Gui
 |     // Gui
 | ||||||
|     app->gui = furi_record_open(RECORD_GUI); |     app->gui = furi_record_open(RECORD_GUI); | ||||||
| @ -203,15 +199,17 @@ static UartEchoApp* uart_echo_app_alloc() { | |||||||
|     view_set_input_callback(app->view, uart_echo_view_input_callback); |     view_set_input_callback(app->view, uart_echo_view_input_callback); | ||||||
|     view_allocate_model(app->view, ViewModelTypeLocking, sizeof(UartDumpModel)); |     view_allocate_model(app->view, ViewModelTypeLocking, sizeof(UartDumpModel)); | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         app->view, (UartDumpModel * model) { |         app->view, | ||||||
|  |         UartDumpModel * model, | ||||||
|  |         { | ||||||
|             for(size_t i = 0; i < LINES_ON_SCREEN; i++) { |             for(size_t i = 0; i < LINES_ON_SCREEN; i++) { | ||||||
|                 model->line = 0; |                 model->line = 0; | ||||||
|                 model->escape = false; |                 model->escape = false; | ||||||
|                 model->list[i] = malloc(sizeof(ListElement)); |                 model->list[i] = malloc(sizeof(ListElement)); | ||||||
|                 string_init(model->list[i]->text); |                 model->list[i]->text = furi_string_alloc(); | ||||||
|             } |             } | ||||||
|             return true; |         }, | ||||||
|         }); |         true); | ||||||
| 
 | 
 | ||||||
|     view_set_previous_callback(app->view, uart_echo_exit); |     view_set_previous_callback(app->view, uart_echo_exit); | ||||||
|     view_dispatcher_add_view(app->view_dispatcher, 0, app->view); |     view_dispatcher_add_view(app->view_dispatcher, 0, app->view); | ||||||
| @ -245,13 +243,15 @@ static void uart_echo_app_free(UartEchoApp* app) { | |||||||
|     view_dispatcher_remove_view(app->view_dispatcher, 0); |     view_dispatcher_remove_view(app->view_dispatcher, 0); | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         app->view, (UartDumpModel * model) { |         app->view, | ||||||
|  |         UartDumpModel * model, | ||||||
|  |         { | ||||||
|             for(size_t i = 0; i < LINES_ON_SCREEN; i++) { |             for(size_t i = 0; i < LINES_ON_SCREEN; i++) { | ||||||
|                 string_clear(model->list[i]->text); |                 furi_string_free(model->list[i]->text); | ||||||
|                 free(model->list[i]); |                 free(model->list[i]); | ||||||
|             } |             } | ||||||
|             return true; |         }, | ||||||
|         }); |         true); | ||||||
|     view_free(app->view); |     view_free(app->view); | ||||||
|     view_dispatcher_free(app->view_dispatcher); |     view_dispatcher_free(app->view_dispatcher); | ||||||
| 
 | 
 | ||||||
| @ -260,7 +260,7 @@ static void uart_echo_app_free(UartEchoApp* app) { | |||||||
|     furi_record_close(RECORD_NOTIFICATION); |     furi_record_close(RECORD_NOTIFICATION); | ||||||
|     app->gui = NULL; |     app->gui = NULL; | ||||||
| 
 | 
 | ||||||
|     vStreamBufferDelete(app->rx_stream); |     furi_stream_buffer_free(app->rx_stream); | ||||||
| 
 | 
 | ||||||
|     // Free rest
 |     // Free rest
 | ||||||
|     free(app); |     free(app); | ||||||
|  | |||||||
| @ -58,7 +58,7 @@ static const char* test_data_win = "Filetype: Flipper Format test\r\n" | |||||||
| #define ARRAY_W_BSIZE(x) (x), (sizeof(x)) | #define ARRAY_W_BSIZE(x) (x), (sizeof(x)) | ||||||
| 
 | 
 | ||||||
| MU_TEST_1(flipper_format_read_and_update_test, FlipperFormat* flipper_format) { | MU_TEST_1(flipper_format_read_and_update_test, FlipperFormat* flipper_format) { | ||||||
|     string_t tmpstr; |     FuriString* tmpstr; | ||||||
|     uint32_t version; |     uint32_t version; | ||||||
|     uint32_t uint32_data[COUNT_OF(test_uint_data)]; |     uint32_t uint32_data[COUNT_OF(test_uint_data)]; | ||||||
|     int32_t int32_data[COUNT_OF(test_int_data)]; |     int32_t int32_data[COUNT_OF(test_int_data)]; | ||||||
| @ -101,14 +101,14 @@ MU_TEST_1(flipper_format_read_and_update_test, FlipperFormat* flipper_format) { | |||||||
|     mu_assert_int_eq(position_before, stream_tell(flipper_format_get_raw_stream(flipper_format))); |     mu_assert_int_eq(position_before, stream_tell(flipper_format_get_raw_stream(flipper_format))); | ||||||
| 
 | 
 | ||||||
|     // read test
 |     // read test
 | ||||||
|     string_init(tmpstr); |     tmpstr = furi_string_alloc(); | ||||||
| 
 | 
 | ||||||
|     mu_check(flipper_format_read_header(flipper_format, tmpstr, &version)); |     mu_check(flipper_format_read_header(flipper_format, tmpstr, &version)); | ||||||
|     mu_assert_string_eq(test_filetype, string_get_cstr(tmpstr)); |     mu_assert_string_eq(test_filetype, furi_string_get_cstr(tmpstr)); | ||||||
|     mu_assert_int_eq(test_version, version); |     mu_assert_int_eq(test_version, version); | ||||||
| 
 | 
 | ||||||
|     mu_check(flipper_format_read_string(flipper_format, test_string_key, tmpstr)); |     mu_check(flipper_format_read_string(flipper_format, test_string_key, tmpstr)); | ||||||
|     mu_assert_string_eq(test_string_data, string_get_cstr(tmpstr)); |     mu_assert_string_eq(test_string_data, furi_string_get_cstr(tmpstr)); | ||||||
| 
 | 
 | ||||||
|     mu_check(flipper_format_get_value_count(flipper_format, test_int_key, &count)); |     mu_check(flipper_format_get_value_count(flipper_format, test_int_key, &count)); | ||||||
|     mu_assert_int_eq(COUNT_OF(test_int_data), count); |     mu_assert_int_eq(COUNT_OF(test_int_data), count); | ||||||
| @ -133,7 +133,7 @@ MU_TEST_1(flipper_format_read_and_update_test, FlipperFormat* flipper_format) { | |||||||
| 
 | 
 | ||||||
|     mu_check(!flipper_format_read_string(flipper_format, "Key that doesn't exist", tmpstr)); |     mu_check(!flipper_format_read_string(flipper_format, "Key that doesn't exist", tmpstr)); | ||||||
| 
 | 
 | ||||||
|     string_clear(tmpstr); |     furi_string_free(tmpstr); | ||||||
| 
 | 
 | ||||||
|     // update data
 |     // update data
 | ||||||
|     mu_check(flipper_format_rewind(flipper_format)); |     mu_check(flipper_format_rewind(flipper_format)); | ||||||
| @ -155,14 +155,14 @@ MU_TEST_1(flipper_format_read_and_update_test, FlipperFormat* flipper_format) { | |||||||
|     uint8_t hex_updated_data[COUNT_OF(test_hex_updated_data)]; |     uint8_t hex_updated_data[COUNT_OF(test_hex_updated_data)]; | ||||||
| 
 | 
 | ||||||
|     mu_check(flipper_format_rewind(flipper_format)); |     mu_check(flipper_format_rewind(flipper_format)); | ||||||
|     string_init(tmpstr); |     tmpstr = furi_string_alloc(); | ||||||
| 
 | 
 | ||||||
|     mu_check(flipper_format_read_header(flipper_format, tmpstr, &version)); |     mu_check(flipper_format_read_header(flipper_format, tmpstr, &version)); | ||||||
|     mu_assert_string_eq(test_filetype, string_get_cstr(tmpstr)); |     mu_assert_string_eq(test_filetype, furi_string_get_cstr(tmpstr)); | ||||||
|     mu_assert_int_eq(test_version, version); |     mu_assert_int_eq(test_version, version); | ||||||
| 
 | 
 | ||||||
|     mu_check(flipper_format_read_string(flipper_format, test_string_key, tmpstr)); |     mu_check(flipper_format_read_string(flipper_format, test_string_key, tmpstr)); | ||||||
|     mu_assert_string_eq(test_string_updated_data, string_get_cstr(tmpstr)); |     mu_assert_string_eq(test_string_updated_data, furi_string_get_cstr(tmpstr)); | ||||||
| 
 | 
 | ||||||
|     mu_check(flipper_format_get_value_count(flipper_format, test_int_key, &count)); |     mu_check(flipper_format_get_value_count(flipper_format, test_int_key, &count)); | ||||||
|     mu_assert_int_eq(COUNT_OF(test_int_updated_data), count); |     mu_assert_int_eq(COUNT_OF(test_int_updated_data), count); | ||||||
| @ -190,7 +190,7 @@ MU_TEST_1(flipper_format_read_and_update_test, FlipperFormat* flipper_format) { | |||||||
| 
 | 
 | ||||||
|     mu_check(!flipper_format_read_string(flipper_format, "Key that doesn't exist", tmpstr)); |     mu_check(!flipper_format_read_string(flipper_format, "Key that doesn't exist", tmpstr)); | ||||||
| 
 | 
 | ||||||
|     string_clear(tmpstr); |     furi_string_free(tmpstr); | ||||||
| 
 | 
 | ||||||
|     // update data
 |     // update data
 | ||||||
|     mu_check(flipper_format_rewind(flipper_format)); |     mu_check(flipper_format_rewind(flipper_format)); | ||||||
| @ -214,14 +214,14 @@ MU_TEST_1(flipper_format_read_and_update_test, FlipperFormat* flipper_format) { | |||||||
|     uint8_t hex_new_data[COUNT_OF(test_hex_new_data)]; |     uint8_t hex_new_data[COUNT_OF(test_hex_new_data)]; | ||||||
| 
 | 
 | ||||||
|     mu_check(flipper_format_rewind(flipper_format)); |     mu_check(flipper_format_rewind(flipper_format)); | ||||||
|     string_init(tmpstr); |     tmpstr = furi_string_alloc(); | ||||||
| 
 | 
 | ||||||
|     mu_check(flipper_format_read_header(flipper_format, tmpstr, &version)); |     mu_check(flipper_format_read_header(flipper_format, tmpstr, &version)); | ||||||
|     mu_assert_string_eq(test_filetype, string_get_cstr(tmpstr)); |     mu_assert_string_eq(test_filetype, furi_string_get_cstr(tmpstr)); | ||||||
|     mu_assert_int_eq(test_version, version); |     mu_assert_int_eq(test_version, version); | ||||||
| 
 | 
 | ||||||
|     mu_check(flipper_format_read_string(flipper_format, test_string_key, tmpstr)); |     mu_check(flipper_format_read_string(flipper_format, test_string_key, tmpstr)); | ||||||
|     mu_assert_string_eq(test_string_updated_2_data, string_get_cstr(tmpstr)); |     mu_assert_string_eq(test_string_updated_2_data, furi_string_get_cstr(tmpstr)); | ||||||
| 
 | 
 | ||||||
|     mu_check(flipper_format_get_value_count(flipper_format, test_int_key, &count)); |     mu_check(flipper_format_get_value_count(flipper_format, test_int_key, &count)); | ||||||
|     mu_assert_int_eq(COUNT_OF(test_int_updated_2_data), count); |     mu_assert_int_eq(COUNT_OF(test_int_updated_2_data), count); | ||||||
| @ -255,7 +255,7 @@ MU_TEST_1(flipper_format_read_and_update_test, FlipperFormat* flipper_format) { | |||||||
| 
 | 
 | ||||||
|     mu_check(!flipper_format_read_string(flipper_format, "Key that doesn't exist", tmpstr)); |     mu_check(!flipper_format_read_string(flipper_format, "Key that doesn't exist", tmpstr)); | ||||||
| 
 | 
 | ||||||
|     string_clear(tmpstr); |     furi_string_free(tmpstr); | ||||||
| 
 | 
 | ||||||
|     // delete key test
 |     // delete key test
 | ||||||
|     mu_check(flipper_format_rewind(flipper_format)); |     mu_check(flipper_format_rewind(flipper_format)); | ||||||
|  | |||||||
| @ -57,6 +57,23 @@ static const char* test_data_win = "Filetype: Flipper File test\r\n" | |||||||
|                                    "Hex data: DE AD BE"; |                                    "Hex data: DE AD BE"; | ||||||
| 
 | 
 | ||||||
| #define READ_TEST_FLP "ff_flp.test" | #define READ_TEST_FLP "ff_flp.test" | ||||||
|  | #define READ_TEST_ODD "ff_oddities.test" | ||||||
|  | static const char* test_data_odd = "Filetype: Flipper File test\n" | ||||||
|  |                                    // Tabs before newline
 | ||||||
|  |                                    "Version: 666\t\t\n" | ||||||
|  |                                    "# This is comment\n" | ||||||
|  |                                    // Windows newline in a UNIX file
 | ||||||
|  |                                    "String data: String\r\n" | ||||||
|  |                                    // Trailing whitespace
 | ||||||
|  |                                    "Int32 data: 1234 -6345 7813 0 \n" | ||||||
|  |                                    // Extra whitespace
 | ||||||
|  |                                    "Uint32 data:   1234  0   5678   9098  7654321  \n" | ||||||
|  |                                    // Mixed whitespace
 | ||||||
|  |                                    "Float data: 1.5\t \t1000.0\n" | ||||||
|  |                                    // Leading tabs after key
 | ||||||
|  |                                    "Bool data:\t\ttrue   false\n" | ||||||
|  |                                    // Mixed trailing whitespace
 | ||||||
|  |                                    "Hex data: DE AD BE\t    "; | ||||||
| 
 | 
 | ||||||
| // data created by user on linux machine
 | // data created by user on linux machine
 | ||||||
| static const char* test_file_linux = TEST_DIR READ_TEST_NIX; | static const char* test_file_linux = TEST_DIR READ_TEST_NIX; | ||||||
| @ -64,6 +81,8 @@ static const char* test_file_linux = TEST_DIR READ_TEST_NIX; | |||||||
| static const char* test_file_windows = TEST_DIR READ_TEST_WIN; | static const char* test_file_windows = TEST_DIR READ_TEST_WIN; | ||||||
| // data created by flipper itself
 | // data created by flipper itself
 | ||||||
| static const char* test_file_flipper = TEST_DIR READ_TEST_FLP; | static const char* test_file_flipper = TEST_DIR READ_TEST_FLP; | ||||||
|  | // data containing odd user input
 | ||||||
|  | static const char* test_file_oddities = TEST_DIR READ_TEST_ODD; | ||||||
| 
 | 
 | ||||||
| static bool storage_write_string(const char* path, const char* data) { | static bool storage_write_string(const char* path, const char* data) { | ||||||
|     Storage* storage = furi_record_open(RECORD_STORAGE); |     Storage* storage = furi_record_open(RECORD_STORAGE); | ||||||
| @ -102,8 +121,8 @@ static bool test_read(const char* file_name) { | |||||||
|     bool result = false; |     bool result = false; | ||||||
| 
 | 
 | ||||||
|     FlipperFormat* file = flipper_format_file_alloc(storage); |     FlipperFormat* file = flipper_format_file_alloc(storage); | ||||||
|     string_t string_value; |     FuriString* string_value; | ||||||
|     string_init(string_value); |     string_value = furi_string_alloc(); | ||||||
|     uint32_t uint32_value; |     uint32_t uint32_value; | ||||||
|     void* scratchpad = malloc(512); |     void* scratchpad = malloc(512); | ||||||
| 
 | 
 | ||||||
| @ -111,11 +130,11 @@ static bool test_read(const char* file_name) { | |||||||
|         if(!flipper_format_file_open_existing(file, file_name)) break; |         if(!flipper_format_file_open_existing(file, file_name)) break; | ||||||
| 
 | 
 | ||||||
|         if(!flipper_format_read_header(file, string_value, &uint32_value)) break; |         if(!flipper_format_read_header(file, string_value, &uint32_value)) break; | ||||||
|         if(string_cmp_str(string_value, test_filetype) != 0) break; |         if(furi_string_cmp_str(string_value, test_filetype) != 0) break; | ||||||
|         if(uint32_value != test_version) break; |         if(uint32_value != test_version) break; | ||||||
| 
 | 
 | ||||||
|         if(!flipper_format_read_string(file, test_string_key, string_value)) break; |         if(!flipper_format_read_string(file, test_string_key, string_value)) break; | ||||||
|         if(string_cmp_str(string_value, test_string_data) != 0) break; |         if(furi_string_cmp_str(string_value, test_string_data) != 0) break; | ||||||
| 
 | 
 | ||||||
|         if(!flipper_format_get_value_count(file, test_int_key, &uint32_value)) break; |         if(!flipper_format_get_value_count(file, test_int_key, &uint32_value)) break; | ||||||
|         if(uint32_value != COUNT_OF(test_int_data)) break; |         if(uint32_value != COUNT_OF(test_int_data)) break; | ||||||
| @ -150,7 +169,7 @@ static bool test_read(const char* file_name) { | |||||||
|     } while(false); |     } while(false); | ||||||
| 
 | 
 | ||||||
|     free(scratchpad); |     free(scratchpad); | ||||||
|     string_clear(string_value); |     furi_string_free(string_value); | ||||||
| 
 | 
 | ||||||
|     flipper_format_free(file); |     flipper_format_free(file); | ||||||
| 
 | 
 | ||||||
| @ -164,8 +183,8 @@ static bool test_read_updated(const char* file_name) { | |||||||
|     bool result = false; |     bool result = false; | ||||||
| 
 | 
 | ||||||
|     FlipperFormat* file = flipper_format_file_alloc(storage); |     FlipperFormat* file = flipper_format_file_alloc(storage); | ||||||
|     string_t string_value; |     FuriString* string_value; | ||||||
|     string_init(string_value); |     string_value = furi_string_alloc(); | ||||||
|     uint32_t uint32_value; |     uint32_t uint32_value; | ||||||
|     void* scratchpad = malloc(512); |     void* scratchpad = malloc(512); | ||||||
| 
 | 
 | ||||||
| @ -173,11 +192,11 @@ static bool test_read_updated(const char* file_name) { | |||||||
|         if(!flipper_format_file_open_existing(file, file_name)) break; |         if(!flipper_format_file_open_existing(file, file_name)) break; | ||||||
| 
 | 
 | ||||||
|         if(!flipper_format_read_header(file, string_value, &uint32_value)) break; |         if(!flipper_format_read_header(file, string_value, &uint32_value)) break; | ||||||
|         if(string_cmp_str(string_value, test_filetype) != 0) break; |         if(furi_string_cmp_str(string_value, test_filetype) != 0) break; | ||||||
|         if(uint32_value != test_version) break; |         if(uint32_value != test_version) break; | ||||||
| 
 | 
 | ||||||
|         if(!flipper_format_read_string(file, test_string_key, string_value)) break; |         if(!flipper_format_read_string(file, test_string_key, string_value)) break; | ||||||
|         if(string_cmp_str(string_value, test_string_updated_data) != 0) break; |         if(furi_string_cmp_str(string_value, test_string_updated_data) != 0) break; | ||||||
| 
 | 
 | ||||||
|         if(!flipper_format_get_value_count(file, test_int_key, &uint32_value)) break; |         if(!flipper_format_get_value_count(file, test_int_key, &uint32_value)) break; | ||||||
|         if(uint32_value != COUNT_OF(test_int_updated_data)) break; |         if(uint32_value != COUNT_OF(test_int_updated_data)) break; | ||||||
| @ -228,7 +247,7 @@ static bool test_read_updated(const char* file_name) { | |||||||
|     } while(false); |     } while(false); | ||||||
| 
 | 
 | ||||||
|     free(scratchpad); |     free(scratchpad); | ||||||
|     string_clear(string_value); |     furi_string_free(string_value); | ||||||
| 
 | 
 | ||||||
|     flipper_format_free(file); |     flipper_format_free(file); | ||||||
| 
 | 
 | ||||||
| @ -401,14 +420,14 @@ static bool test_read_multikey(const char* file_name) { | |||||||
|     bool result = false; |     bool result = false; | ||||||
|     FlipperFormat* file = flipper_format_file_alloc(storage); |     FlipperFormat* file = flipper_format_file_alloc(storage); | ||||||
| 
 | 
 | ||||||
|     string_t string_value; |     FuriString* string_value; | ||||||
|     string_init(string_value); |     string_value = furi_string_alloc(); | ||||||
|     uint32_t uint32_value; |     uint32_t uint32_value; | ||||||
| 
 | 
 | ||||||
|     do { |     do { | ||||||
|         if(!flipper_format_file_open_existing(file, file_name)) break; |         if(!flipper_format_file_open_existing(file, file_name)) break; | ||||||
|         if(!flipper_format_read_header(file, string_value, &uint32_value)) break; |         if(!flipper_format_read_header(file, string_value, &uint32_value)) break; | ||||||
|         if(string_cmp_str(string_value, test_filetype) != 0) break; |         if(furi_string_cmp_str(string_value, test_filetype) != 0) break; | ||||||
|         if(uint32_value != test_version) break; |         if(uint32_value != test_version) break; | ||||||
| 
 | 
 | ||||||
|         bool error = false; |         bool error = false; | ||||||
| @ -429,7 +448,7 @@ static bool test_read_multikey(const char* file_name) { | |||||||
|         result = true; |         result = true; | ||||||
|     } while(false); |     } while(false); | ||||||
| 
 | 
 | ||||||
|     string_clear(string_value); |     furi_string_free(string_value); | ||||||
| 
 | 
 | ||||||
|     flipper_format_free(file); |     flipper_format_free(file); | ||||||
|     furi_record_close(RECORD_STORAGE); |     furi_record_close(RECORD_STORAGE); | ||||||
| @ -503,6 +522,12 @@ MU_TEST(flipper_format_multikey_test) { | |||||||
|     mu_assert(test_read_multikey(TEST_DIR "ff_multiline.test"), "Multikey read test error"); |     mu_assert(test_read_multikey(TEST_DIR "ff_multiline.test"), "Multikey read test error"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | MU_TEST(flipper_format_oddities_test) { | ||||||
|  |     mu_assert( | ||||||
|  |         storage_write_string(test_file_oddities, test_data_odd), "Write test error [Oddities]"); | ||||||
|  |     mu_assert(test_read(test_file_linux), "Read test error [Oddities]"); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| MU_TEST_SUITE(flipper_format) { | MU_TEST_SUITE(flipper_format) { | ||||||
|     tests_setup(); |     tests_setup(); | ||||||
|     MU_RUN_TEST(flipper_format_write_test); |     MU_RUN_TEST(flipper_format_write_test); | ||||||
| @ -516,6 +541,7 @@ MU_TEST_SUITE(flipper_format) { | |||||||
|     MU_RUN_TEST(flipper_format_update_2_test); |     MU_RUN_TEST(flipper_format_update_2_test); | ||||||
|     MU_RUN_TEST(flipper_format_update_2_result_test); |     MU_RUN_TEST(flipper_format_update_2_result_test); | ||||||
|     MU_RUN_TEST(flipper_format_multikey_test); |     MU_RUN_TEST(flipper_format_multikey_test); | ||||||
|  |     MU_RUN_TEST(flipper_format_oddities_test); | ||||||
|     tests_teardown(); |     tests_teardown(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										469
									
								
								applications/debug/unit_tests/furi/furi_string_test.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										469
									
								
								applications/debug/unit_tests/furi/furi_string_test.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,469 @@ | |||||||
|  | #include <furi.h> | ||||||
|  | #include "../minunit.h" | ||||||
|  | 
 | ||||||
|  | static void test_setup(void) { | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void test_teardown(void) { | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static FuriString* furi_string_alloc_vprintf_test(const char format[], ...) { | ||||||
|  |     va_list args; | ||||||
|  |     va_start(args, format); | ||||||
|  |     FuriString* string = furi_string_alloc_vprintf(format, args); | ||||||
|  |     va_end(args); | ||||||
|  |     return string; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST(mu_test_furi_string_alloc_free) { | ||||||
|  |     FuriString* tmp; | ||||||
|  |     FuriString* string; | ||||||
|  | 
 | ||||||
|  |     // test alloc and free
 | ||||||
|  |     string = furi_string_alloc(); | ||||||
|  |     mu_check(string != NULL); | ||||||
|  |     mu_check(furi_string_empty(string)); | ||||||
|  |     furi_string_free(string); | ||||||
|  | 
 | ||||||
|  |     // test furi_string_alloc_set_str and free
 | ||||||
|  |     string = furi_string_alloc_set_str("test"); | ||||||
|  |     mu_check(string != NULL); | ||||||
|  |     mu_check(!furi_string_empty(string)); | ||||||
|  |     mu_check(furi_string_cmp(string, "test") == 0); | ||||||
|  |     furi_string_free(string); | ||||||
|  | 
 | ||||||
|  |     // test furi_string_alloc_set and free
 | ||||||
|  |     tmp = furi_string_alloc_set("more"); | ||||||
|  |     string = furi_string_alloc_set(tmp); | ||||||
|  |     furi_string_free(tmp); | ||||||
|  |     mu_check(string != NULL); | ||||||
|  |     mu_check(!furi_string_empty(string)); | ||||||
|  |     mu_check(furi_string_cmp(string, "more") == 0); | ||||||
|  |     furi_string_free(string); | ||||||
|  | 
 | ||||||
|  |     // test alloc_printf and free
 | ||||||
|  |     string = furi_string_alloc_printf("test %d %s %c 0x%02x", 1, "two", '3', 0x04); | ||||||
|  |     mu_check(string != NULL); | ||||||
|  |     mu_check(!furi_string_empty(string)); | ||||||
|  |     mu_check(furi_string_cmp(string, "test 1 two 3 0x04") == 0); | ||||||
|  |     furi_string_free(string); | ||||||
|  | 
 | ||||||
|  |     // test alloc_vprintf and free
 | ||||||
|  |     string = furi_string_alloc_vprintf_test("test %d %s %c 0x%02x", 4, "five", '6', 0x07); | ||||||
|  |     mu_check(string != NULL); | ||||||
|  |     mu_check(!furi_string_empty(string)); | ||||||
|  |     mu_check(furi_string_cmp(string, "test 4 five 6 0x07") == 0); | ||||||
|  |     furi_string_free(string); | ||||||
|  | 
 | ||||||
|  |     // test alloc_move and free
 | ||||||
|  |     tmp = furi_string_alloc_set("move"); | ||||||
|  |     string = furi_string_alloc_move(tmp); | ||||||
|  |     mu_check(string != NULL); | ||||||
|  |     mu_check(!furi_string_empty(string)); | ||||||
|  |     mu_check(furi_string_cmp(string, "move") == 0); | ||||||
|  |     furi_string_free(string); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST(mu_test_furi_string_mem) { | ||||||
|  |     FuriString* string = furi_string_alloc_set("test"); | ||||||
|  |     mu_check(string != NULL); | ||||||
|  |     mu_check(!furi_string_empty(string)); | ||||||
|  | 
 | ||||||
|  |     // TODO: how to test furi_string_reserve?
 | ||||||
|  | 
 | ||||||
|  |     // test furi_string_reset
 | ||||||
|  |     furi_string_reset(string); | ||||||
|  |     mu_check(furi_string_empty(string)); | ||||||
|  | 
 | ||||||
|  |     // test furi_string_swap
 | ||||||
|  |     furi_string_set(string, "test"); | ||||||
|  |     FuriString* swap_string = furi_string_alloc_set("swap"); | ||||||
|  |     furi_string_swap(string, swap_string); | ||||||
|  |     mu_check(furi_string_cmp(string, "swap") == 0); | ||||||
|  |     mu_check(furi_string_cmp(swap_string, "test") == 0); | ||||||
|  |     furi_string_free(swap_string); | ||||||
|  | 
 | ||||||
|  |     // test furi_string_move
 | ||||||
|  |     FuriString* move_string = furi_string_alloc_set("move"); | ||||||
|  |     furi_string_move(string, move_string); | ||||||
|  |     mu_check(furi_string_cmp(string, "move") == 0); | ||||||
|  |     // move_string is now empty
 | ||||||
|  |     // and tested by leaked memory check at the end of the tests
 | ||||||
|  | 
 | ||||||
|  |     furi_string_set(string, "abracadabra"); | ||||||
|  | 
 | ||||||
|  |     // test furi_string_hash
 | ||||||
|  |     mu_assert_int_eq(0xc3bc16d7, furi_string_hash(string)); | ||||||
|  | 
 | ||||||
|  |     // test furi_string_size
 | ||||||
|  |     mu_assert_int_eq(11, furi_string_size(string)); | ||||||
|  | 
 | ||||||
|  |     // test furi_string_empty
 | ||||||
|  |     mu_check(!furi_string_empty(string)); | ||||||
|  |     furi_string_reset(string); | ||||||
|  |     mu_check(furi_string_empty(string)); | ||||||
|  | 
 | ||||||
|  |     furi_string_free(string); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST(mu_test_furi_string_getters) { | ||||||
|  |     FuriString* string = furi_string_alloc_set("test"); | ||||||
|  | 
 | ||||||
|  |     // test furi_string_get_char
 | ||||||
|  |     mu_check(furi_string_get_char(string, 0) == 't'); | ||||||
|  |     mu_check(furi_string_get_char(string, 1) == 'e'); | ||||||
|  |     mu_check(furi_string_get_char(string, 2) == 's'); | ||||||
|  |     mu_check(furi_string_get_char(string, 3) == 't'); | ||||||
|  | 
 | ||||||
|  |     // test furi_string_get_cstr
 | ||||||
|  |     mu_assert_string_eq("test", furi_string_get_cstr(string)); | ||||||
|  |     furi_string_free(string); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static FuriString* furi_string_vprintf_test(FuriString* string, const char format[], ...) { | ||||||
|  |     va_list args; | ||||||
|  |     va_start(args, format); | ||||||
|  |     furi_string_vprintf(string, format, args); | ||||||
|  |     va_end(args); | ||||||
|  |     return string; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST(mu_test_furi_string_setters) { | ||||||
|  |     FuriString* tmp; | ||||||
|  |     FuriString* string = furi_string_alloc(); | ||||||
|  | 
 | ||||||
|  |     // test furi_string_set_str
 | ||||||
|  |     furi_string_set_str(string, "test"); | ||||||
|  |     mu_assert_string_eq("test", furi_string_get_cstr(string)); | ||||||
|  | 
 | ||||||
|  |     // test furi_string_set
 | ||||||
|  |     tmp = furi_string_alloc_set("more"); | ||||||
|  |     furi_string_set(string, tmp); | ||||||
|  |     furi_string_free(tmp); | ||||||
|  |     mu_assert_string_eq("more", furi_string_get_cstr(string)); | ||||||
|  | 
 | ||||||
|  |     // test furi_string_set_strn
 | ||||||
|  |     furi_string_set_strn(string, "test", 2); | ||||||
|  |     mu_assert_string_eq("te", furi_string_get_cstr(string)); | ||||||
|  | 
 | ||||||
|  |     // test furi_string_set_char
 | ||||||
|  |     furi_string_set_char(string, 0, 'a'); | ||||||
|  |     furi_string_set_char(string, 1, 'b'); | ||||||
|  |     mu_assert_string_eq("ab", furi_string_get_cstr(string)); | ||||||
|  | 
 | ||||||
|  |     // test furi_string_set_n
 | ||||||
|  |     tmp = furi_string_alloc_set("dodecahedron"); | ||||||
|  |     furi_string_set_n(string, tmp, 4, 5); | ||||||
|  |     furi_string_free(tmp); | ||||||
|  |     mu_assert_string_eq("cahed", furi_string_get_cstr(string)); | ||||||
|  | 
 | ||||||
|  |     // test furi_string_printf
 | ||||||
|  |     furi_string_printf(string, "test %d %s %c 0x%02x", 1, "two", '3', 0x04); | ||||||
|  |     mu_assert_string_eq("test 1 two 3 0x04", furi_string_get_cstr(string)); | ||||||
|  | 
 | ||||||
|  |     // test furi_string_vprintf
 | ||||||
|  |     furi_string_vprintf_test(string, "test %d %s %c 0x%02x", 4, "five", '6', 0x07); | ||||||
|  |     mu_assert_string_eq("test 4 five 6 0x07", furi_string_get_cstr(string)); | ||||||
|  | 
 | ||||||
|  |     furi_string_free(string); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static FuriString* furi_string_cat_vprintf_test(FuriString* string, const char format[], ...) { | ||||||
|  |     va_list args; | ||||||
|  |     va_start(args, format); | ||||||
|  |     furi_string_cat_vprintf(string, format, args); | ||||||
|  |     va_end(args); | ||||||
|  |     return string; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST(mu_test_furi_string_appends) { | ||||||
|  |     FuriString* tmp; | ||||||
|  |     FuriString* string = furi_string_alloc(); | ||||||
|  | 
 | ||||||
|  |     // test furi_string_push_back
 | ||||||
|  |     furi_string_push_back(string, 't'); | ||||||
|  |     furi_string_push_back(string, 'e'); | ||||||
|  |     furi_string_push_back(string, 's'); | ||||||
|  |     furi_string_push_back(string, 't'); | ||||||
|  |     mu_assert_string_eq("test", furi_string_get_cstr(string)); | ||||||
|  |     furi_string_push_back(string, '!'); | ||||||
|  |     mu_assert_string_eq("test!", furi_string_get_cstr(string)); | ||||||
|  | 
 | ||||||
|  |     // test furi_string_cat_str
 | ||||||
|  |     furi_string_cat_str(string, "test"); | ||||||
|  |     mu_assert_string_eq("test!test", furi_string_get_cstr(string)); | ||||||
|  | 
 | ||||||
|  |     // test furi_string_cat
 | ||||||
|  |     tmp = furi_string_alloc_set("more"); | ||||||
|  |     furi_string_cat(string, tmp); | ||||||
|  |     furi_string_free(tmp); | ||||||
|  |     mu_assert_string_eq("test!testmore", furi_string_get_cstr(string)); | ||||||
|  | 
 | ||||||
|  |     // test furi_string_cat_printf
 | ||||||
|  |     furi_string_cat_printf(string, "test %d %s %c 0x%02x", 1, "two", '3', 0x04); | ||||||
|  |     mu_assert_string_eq("test!testmoretest 1 two 3 0x04", furi_string_get_cstr(string)); | ||||||
|  | 
 | ||||||
|  |     // test furi_string_cat_vprintf
 | ||||||
|  |     furi_string_cat_vprintf_test(string, "test %d %s %c 0x%02x", 4, "five", '6', 0x07); | ||||||
|  |     mu_assert_string_eq( | ||||||
|  |         "test!testmoretest 1 two 3 0x04test 4 five 6 0x07", furi_string_get_cstr(string)); | ||||||
|  | 
 | ||||||
|  |     furi_string_free(string); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST(mu_test_furi_string_compare) { | ||||||
|  |     FuriString* string_1 = furi_string_alloc_set("string_1"); | ||||||
|  |     FuriString* string_2 = furi_string_alloc_set("string_2"); | ||||||
|  | 
 | ||||||
|  |     // test furi_string_cmp
 | ||||||
|  |     mu_assert_int_eq(0, furi_string_cmp(string_1, string_1)); | ||||||
|  |     mu_assert_int_eq(0, furi_string_cmp(string_2, string_2)); | ||||||
|  |     mu_assert_int_eq(-1, furi_string_cmp(string_1, string_2)); | ||||||
|  |     mu_assert_int_eq(1, furi_string_cmp(string_2, string_1)); | ||||||
|  | 
 | ||||||
|  |     // test furi_string_cmp_str
 | ||||||
|  |     mu_assert_int_eq(0, furi_string_cmp_str(string_1, "string_1")); | ||||||
|  |     mu_assert_int_eq(0, furi_string_cmp_str(string_2, "string_2")); | ||||||
|  |     mu_assert_int_eq(-1, furi_string_cmp_str(string_1, "string_2")); | ||||||
|  |     mu_assert_int_eq(1, furi_string_cmp_str(string_2, "string_1")); | ||||||
|  | 
 | ||||||
|  |     // test furi_string_cmpi
 | ||||||
|  |     furi_string_set(string_1, "string"); | ||||||
|  |     furi_string_set(string_2, "StrIng"); | ||||||
|  |     mu_assert_int_eq(0, furi_string_cmpi(string_1, string_1)); | ||||||
|  |     mu_assert_int_eq(0, furi_string_cmpi(string_2, string_2)); | ||||||
|  |     mu_assert_int_eq(0, furi_string_cmpi(string_1, string_2)); | ||||||
|  |     mu_assert_int_eq(0, furi_string_cmpi(string_2, string_1)); | ||||||
|  |     furi_string_set(string_1, "string_1"); | ||||||
|  |     furi_string_set(string_2, "StrIng_2"); | ||||||
|  |     mu_assert_int_eq(32, furi_string_cmp(string_1, string_2)); | ||||||
|  |     mu_assert_int_eq(-32, furi_string_cmp(string_2, string_1)); | ||||||
|  |     mu_assert_int_eq(-1, furi_string_cmpi(string_1, string_2)); | ||||||
|  |     mu_assert_int_eq(1, furi_string_cmpi(string_2, string_1)); | ||||||
|  | 
 | ||||||
|  |     // test furi_string_cmpi_str
 | ||||||
|  |     furi_string_set(string_1, "string"); | ||||||
|  |     mu_assert_int_eq(0, furi_string_cmp_str(string_1, "string")); | ||||||
|  |     mu_assert_int_eq(32, furi_string_cmp_str(string_1, "String")); | ||||||
|  |     mu_assert_int_eq(32, furi_string_cmp_str(string_1, "STring")); | ||||||
|  |     mu_assert_int_eq(32, furi_string_cmp_str(string_1, "STRing")); | ||||||
|  |     mu_assert_int_eq(32, furi_string_cmp_str(string_1, "STRIng")); | ||||||
|  |     mu_assert_int_eq(32, furi_string_cmp_str(string_1, "STRINg")); | ||||||
|  |     mu_assert_int_eq(32, furi_string_cmp_str(string_1, "STRING")); | ||||||
|  |     mu_assert_int_eq(0, furi_string_cmpi_str(string_1, "string")); | ||||||
|  |     mu_assert_int_eq(0, furi_string_cmpi_str(string_1, "String")); | ||||||
|  |     mu_assert_int_eq(0, furi_string_cmpi_str(string_1, "STring")); | ||||||
|  |     mu_assert_int_eq(0, furi_string_cmpi_str(string_1, "STRing")); | ||||||
|  |     mu_assert_int_eq(0, furi_string_cmpi_str(string_1, "STRIng")); | ||||||
|  |     mu_assert_int_eq(0, furi_string_cmpi_str(string_1, "STRINg")); | ||||||
|  |     mu_assert_int_eq(0, furi_string_cmpi_str(string_1, "STRING")); | ||||||
|  | 
 | ||||||
|  |     furi_string_free(string_1); | ||||||
|  |     furi_string_free(string_2); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST(mu_test_furi_string_search) { | ||||||
|  |     //                                            012345678901234567
 | ||||||
|  |     FuriString* haystack = furi_string_alloc_set("test321test123test"); | ||||||
|  |     FuriString* needle = furi_string_alloc_set("test"); | ||||||
|  | 
 | ||||||
|  |     // test furi_string_search
 | ||||||
|  |     mu_assert_int_eq(0, furi_string_search(haystack, needle)); | ||||||
|  |     mu_assert_int_eq(7, furi_string_search(haystack, needle, 1)); | ||||||
|  |     mu_assert_int_eq(14, furi_string_search(haystack, needle, 8)); | ||||||
|  |     mu_assert_int_eq(FURI_STRING_FAILURE, furi_string_search(haystack, needle, 15)); | ||||||
|  | 
 | ||||||
|  |     FuriString* tmp = furi_string_alloc_set("testnone"); | ||||||
|  |     mu_assert_int_eq(FURI_STRING_FAILURE, furi_string_search(haystack, tmp)); | ||||||
|  |     furi_string_free(tmp); | ||||||
|  | 
 | ||||||
|  |     // test furi_string_search_str
 | ||||||
|  |     mu_assert_int_eq(0, furi_string_search_str(haystack, "test")); | ||||||
|  |     mu_assert_int_eq(7, furi_string_search_str(haystack, "test", 1)); | ||||||
|  |     mu_assert_int_eq(14, furi_string_search_str(haystack, "test", 8)); | ||||||
|  |     mu_assert_int_eq(4, furi_string_search_str(haystack, "321")); | ||||||
|  |     mu_assert_int_eq(11, furi_string_search_str(haystack, "123")); | ||||||
|  |     mu_assert_int_eq(FURI_STRING_FAILURE, furi_string_search_str(haystack, "testnone")); | ||||||
|  |     mu_assert_int_eq(FURI_STRING_FAILURE, furi_string_search_str(haystack, "test", 15)); | ||||||
|  | 
 | ||||||
|  |     // test furi_string_search_char
 | ||||||
|  |     mu_assert_int_eq(0, furi_string_search_char(haystack, 't')); | ||||||
|  |     mu_assert_int_eq(1, furi_string_search_char(haystack, 'e')); | ||||||
|  |     mu_assert_int_eq(2, furi_string_search_char(haystack, 's')); | ||||||
|  |     mu_assert_int_eq(3, furi_string_search_char(haystack, 't', 1)); | ||||||
|  |     mu_assert_int_eq(7, furi_string_search_char(haystack, 't', 4)); | ||||||
|  |     mu_assert_int_eq(FURI_STRING_FAILURE, furi_string_search_char(haystack, 'x')); | ||||||
|  | 
 | ||||||
|  |     // test furi_string_search_rchar
 | ||||||
|  |     mu_assert_int_eq(17, furi_string_search_rchar(haystack, 't')); | ||||||
|  |     mu_assert_int_eq(15, furi_string_search_rchar(haystack, 'e')); | ||||||
|  |     mu_assert_int_eq(16, furi_string_search_rchar(haystack, 's')); | ||||||
|  |     mu_assert_int_eq(13, furi_string_search_rchar(haystack, '3')); | ||||||
|  |     mu_assert_int_eq(FURI_STRING_FAILURE, furi_string_search_rchar(haystack, '3', 14)); | ||||||
|  |     mu_assert_int_eq(FURI_STRING_FAILURE, furi_string_search_rchar(haystack, 'x')); | ||||||
|  | 
 | ||||||
|  |     furi_string_free(haystack); | ||||||
|  |     furi_string_free(needle); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST(mu_test_furi_string_equality) { | ||||||
|  |     FuriString* string = furi_string_alloc_set("test"); | ||||||
|  |     FuriString* string_eq = furi_string_alloc_set("test"); | ||||||
|  |     FuriString* string_neq = furi_string_alloc_set("test2"); | ||||||
|  | 
 | ||||||
|  |     // test furi_string_equal
 | ||||||
|  |     mu_check(furi_string_equal(string, string_eq)); | ||||||
|  |     mu_check(!furi_string_equal(string, string_neq)); | ||||||
|  | 
 | ||||||
|  |     // test furi_string_equal_str
 | ||||||
|  |     mu_check(furi_string_equal_str(string, "test")); | ||||||
|  |     mu_check(!furi_string_equal_str(string, "test2")); | ||||||
|  |     mu_check(furi_string_equal_str(string_neq, "test2")); | ||||||
|  |     mu_check(!furi_string_equal_str(string_neq, "test")); | ||||||
|  | 
 | ||||||
|  |     furi_string_free(string); | ||||||
|  |     furi_string_free(string_eq); | ||||||
|  |     furi_string_free(string_neq); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST(mu_test_furi_string_replace) { | ||||||
|  |     FuriString* needle = furi_string_alloc_set("test"); | ||||||
|  |     FuriString* replace = furi_string_alloc_set("replace"); | ||||||
|  |     FuriString* string = furi_string_alloc_set("test123test"); | ||||||
|  | 
 | ||||||
|  |     // test furi_string_replace_at
 | ||||||
|  |     furi_string_replace_at(string, 4, 3, "!biglongword!"); | ||||||
|  |     mu_assert_string_eq("test!biglongword!test", furi_string_get_cstr(string)); | ||||||
|  | 
 | ||||||
|  |     // test furi_string_replace
 | ||||||
|  |     mu_assert_int_eq(17, furi_string_replace(string, needle, replace, 1)); | ||||||
|  |     mu_assert_string_eq("test!biglongword!replace", furi_string_get_cstr(string)); | ||||||
|  |     mu_assert_int_eq(0, furi_string_replace(string, needle, replace)); | ||||||
|  |     mu_assert_string_eq("replace!biglongword!replace", furi_string_get_cstr(string)); | ||||||
|  |     mu_assert_int_eq(FURI_STRING_FAILURE, furi_string_replace(string, needle, replace)); | ||||||
|  |     mu_assert_string_eq("replace!biglongword!replace", furi_string_get_cstr(string)); | ||||||
|  | 
 | ||||||
|  |     // test furi_string_replace_str
 | ||||||
|  |     mu_assert_int_eq(20, furi_string_replace_str(string, "replace", "test", 1)); | ||||||
|  |     mu_assert_string_eq("replace!biglongword!test", furi_string_get_cstr(string)); | ||||||
|  |     mu_assert_int_eq(0, furi_string_replace_str(string, "replace", "test")); | ||||||
|  |     mu_assert_string_eq("test!biglongword!test", furi_string_get_cstr(string)); | ||||||
|  |     mu_assert_int_eq(FURI_STRING_FAILURE, furi_string_replace_str(string, "replace", "test")); | ||||||
|  |     mu_assert_string_eq("test!biglongword!test", furi_string_get_cstr(string)); | ||||||
|  | 
 | ||||||
|  |     // test furi_string_replace_all
 | ||||||
|  |     furi_string_replace_all(string, needle, replace); | ||||||
|  |     mu_assert_string_eq("replace!biglongword!replace", furi_string_get_cstr(string)); | ||||||
|  | 
 | ||||||
|  |     // test furi_string_replace_all_str
 | ||||||
|  |     furi_string_replace_all_str(string, "replace", "test"); | ||||||
|  |     mu_assert_string_eq("test!biglongword!test", furi_string_get_cstr(string)); | ||||||
|  | 
 | ||||||
|  |     furi_string_free(string); | ||||||
|  |     furi_string_free(needle); | ||||||
|  |     furi_string_free(replace); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST(mu_test_furi_string_start_end) { | ||||||
|  |     FuriString* string = furi_string_alloc_set("start_end"); | ||||||
|  |     FuriString* start = furi_string_alloc_set("start"); | ||||||
|  |     FuriString* end = furi_string_alloc_set("end"); | ||||||
|  | 
 | ||||||
|  |     // test furi_string_start_with
 | ||||||
|  |     mu_check(furi_string_start_with(string, start)); | ||||||
|  |     mu_check(!furi_string_start_with(string, end)); | ||||||
|  | 
 | ||||||
|  |     // test furi_string_start_with_str
 | ||||||
|  |     mu_check(furi_string_start_with_str(string, "start")); | ||||||
|  |     mu_check(!furi_string_start_with_str(string, "end")); | ||||||
|  | 
 | ||||||
|  |     // test furi_string_end_with
 | ||||||
|  |     mu_check(furi_string_end_with(string, end)); | ||||||
|  |     mu_check(!furi_string_end_with(string, start)); | ||||||
|  | 
 | ||||||
|  |     // test furi_string_end_with_str
 | ||||||
|  |     mu_check(furi_string_end_with_str(string, "end")); | ||||||
|  |     mu_check(!furi_string_end_with_str(string, "start")); | ||||||
|  | 
 | ||||||
|  |     furi_string_free(string); | ||||||
|  |     furi_string_free(start); | ||||||
|  |     furi_string_free(end); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST(mu_test_furi_string_trim) { | ||||||
|  |     FuriString* string = furi_string_alloc_set("biglongstring"); | ||||||
|  | 
 | ||||||
|  |     // test furi_string_left
 | ||||||
|  |     furi_string_left(string, 7); | ||||||
|  |     mu_assert_string_eq("biglong", furi_string_get_cstr(string)); | ||||||
|  | 
 | ||||||
|  |     // test furi_string_right
 | ||||||
|  |     furi_string_right(string, 3); | ||||||
|  |     mu_assert_string_eq("long", furi_string_get_cstr(string)); | ||||||
|  | 
 | ||||||
|  |     // test furi_string_mid
 | ||||||
|  |     furi_string_mid(string, 1, 2); | ||||||
|  |     mu_assert_string_eq("on", furi_string_get_cstr(string)); | ||||||
|  | 
 | ||||||
|  |     // test furi_string_trim
 | ||||||
|  |     furi_string_set(string, "   \n\r\tbiglongstring \n\r\t  "); | ||||||
|  |     furi_string_trim(string); | ||||||
|  |     mu_assert_string_eq("biglongstring", furi_string_get_cstr(string)); | ||||||
|  |     furi_string_set(string, "aaaabaaaabbaaabaaaabbtestaaaaaabbaaabaababaa"); | ||||||
|  |     furi_string_trim(string, "ab"); | ||||||
|  |     mu_assert_string_eq("test", furi_string_get_cstr(string)); | ||||||
|  | 
 | ||||||
|  |     furi_string_free(string); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST(mu_test_furi_string_utf8) { | ||||||
|  |     FuriString* utf8_string = furi_string_alloc_set("イルカ"); | ||||||
|  | 
 | ||||||
|  |     // test furi_string_utf8_length
 | ||||||
|  |     mu_assert_int_eq(9, furi_string_size(utf8_string)); | ||||||
|  |     mu_assert_int_eq(3, furi_string_utf8_length(utf8_string)); | ||||||
|  | 
 | ||||||
|  |     // test furi_string_utf8_decode
 | ||||||
|  |     const uint8_t dolphin_emoji_array[4] = {0xF0, 0x9F, 0x90, 0xAC}; | ||||||
|  |     FuriStringUTF8State state = FuriStringUTF8StateStarting; | ||||||
|  |     FuriStringUnicodeValue value = 0; | ||||||
|  |     furi_string_utf8_decode(dolphin_emoji_array[0], &state, &value); | ||||||
|  |     mu_assert_int_eq(FuriStringUTF8StateDecoding3, state); | ||||||
|  |     furi_string_utf8_decode(dolphin_emoji_array[1], &state, &value); | ||||||
|  |     mu_assert_int_eq(FuriStringUTF8StateDecoding2, state); | ||||||
|  |     furi_string_utf8_decode(dolphin_emoji_array[2], &state, &value); | ||||||
|  |     mu_assert_int_eq(FuriStringUTF8StateDecoding1, state); | ||||||
|  |     furi_string_utf8_decode(dolphin_emoji_array[3], &state, &value); | ||||||
|  |     mu_assert_int_eq(FuriStringUTF8StateStarting, state); | ||||||
|  |     mu_assert_int_eq(0x1F42C, value); | ||||||
|  | 
 | ||||||
|  |     // test furi_string_utf8_push
 | ||||||
|  |     furi_string_set(utf8_string, ""); | ||||||
|  |     furi_string_utf8_push(utf8_string, value); | ||||||
|  |     mu_assert_string_eq("🐬", furi_string_get_cstr(utf8_string)); | ||||||
|  | 
 | ||||||
|  |     furi_string_free(utf8_string); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST_SUITE(test_suite) { | ||||||
|  |     MU_SUITE_CONFIGURE(&test_setup, &test_teardown); | ||||||
|  | 
 | ||||||
|  |     MU_RUN_TEST(mu_test_furi_string_alloc_free); | ||||||
|  |     MU_RUN_TEST(mu_test_furi_string_mem); | ||||||
|  |     MU_RUN_TEST(mu_test_furi_string_getters); | ||||||
|  |     MU_RUN_TEST(mu_test_furi_string_setters); | ||||||
|  |     MU_RUN_TEST(mu_test_furi_string_appends); | ||||||
|  |     MU_RUN_TEST(mu_test_furi_string_compare); | ||||||
|  |     MU_RUN_TEST(mu_test_furi_string_search); | ||||||
|  |     MU_RUN_TEST(mu_test_furi_string_equality); | ||||||
|  |     MU_RUN_TEST(mu_test_furi_string_replace); | ||||||
|  |     MU_RUN_TEST(mu_test_furi_string_start_end); | ||||||
|  |     MU_RUN_TEST(mu_test_furi_string_trim); | ||||||
|  |     MU_RUN_TEST(mu_test_furi_string_utf8); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int run_minunit_test_furi_string() { | ||||||
|  |     MU_RUN_SUITE(test_suite); | ||||||
|  | 
 | ||||||
|  |     return MU_EXIT_CODE; | ||||||
|  | } | ||||||
| @ -11,7 +11,7 @@ | |||||||
| typedef struct { | typedef struct { | ||||||
|     InfraredDecoderHandler* decoder_handler; |     InfraredDecoderHandler* decoder_handler; | ||||||
|     InfraredEncoderHandler* encoder_handler; |     InfraredEncoderHandler* encoder_handler; | ||||||
|     string_t file_path; |     FuriString* file_path; | ||||||
|     FlipperFormat* ff; |     FlipperFormat* ff; | ||||||
| } InfraredTest; | } InfraredTest; | ||||||
| 
 | 
 | ||||||
| @ -23,7 +23,7 @@ static void infrared_test_alloc() { | |||||||
|     test->decoder_handler = infrared_alloc_decoder(); |     test->decoder_handler = infrared_alloc_decoder(); | ||||||
|     test->encoder_handler = infrared_alloc_encoder(); |     test->encoder_handler = infrared_alloc_encoder(); | ||||||
|     test->ff = flipper_format_buffered_file_alloc(storage); |     test->ff = flipper_format_buffered_file_alloc(storage); | ||||||
|     string_init(test->file_path); |     test->file_path = furi_string_alloc(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void infrared_test_free() { | static void infrared_test_free() { | ||||||
| @ -31,18 +31,18 @@ static void infrared_test_free() { | |||||||
|     infrared_free_decoder(test->decoder_handler); |     infrared_free_decoder(test->decoder_handler); | ||||||
|     infrared_free_encoder(test->encoder_handler); |     infrared_free_encoder(test->encoder_handler); | ||||||
|     flipper_format_free(test->ff); |     flipper_format_free(test->ff); | ||||||
|     string_clear(test->file_path); |     furi_string_free(test->file_path); | ||||||
|     furi_record_close(RECORD_STORAGE); |     furi_record_close(RECORD_STORAGE); | ||||||
|     free(test); |     free(test); | ||||||
|     test = NULL; |     test = NULL; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static bool infrared_test_prepare_file(const char* protocol_name) { | static bool infrared_test_prepare_file(const char* protocol_name) { | ||||||
|     string_t file_type; |     FuriString* file_type; | ||||||
|     string_init(file_type); |     file_type = furi_string_alloc(); | ||||||
|     bool success = false; |     bool success = false; | ||||||
| 
 | 
 | ||||||
|     string_printf( |     furi_string_printf( | ||||||
|         test->file_path, |         test->file_path, | ||||||
|         "%s%s%s%s", |         "%s%s%s%s", | ||||||
|         IR_TEST_FILES_DIR, |         IR_TEST_FILES_DIR, | ||||||
| @ -52,14 +52,15 @@ static bool infrared_test_prepare_file(const char* protocol_name) { | |||||||
| 
 | 
 | ||||||
|     do { |     do { | ||||||
|         uint32_t format_version; |         uint32_t format_version; | ||||||
|         if(!flipper_format_buffered_file_open_existing(test->ff, string_get_cstr(test->file_path))) |         if(!flipper_format_buffered_file_open_existing( | ||||||
|  |                test->ff, furi_string_get_cstr(test->file_path))) | ||||||
|             break; |             break; | ||||||
|         if(!flipper_format_read_header(test->ff, file_type, &format_version)) break; |         if(!flipper_format_read_header(test->ff, file_type, &format_version)) break; | ||||||
|         if(string_cmp_str(file_type, "IR tests file") || format_version != 1) break; |         if(furi_string_cmp_str(file_type, "IR tests file") || format_version != 1) break; | ||||||
|         success = true; |         success = true; | ||||||
|     } while(false); |     } while(false); | ||||||
| 
 | 
 | ||||||
|     string_clear(file_type); |     furi_string_free(file_type); | ||||||
|     return success; |     return success; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -68,18 +69,18 @@ static bool infrared_test_load_raw_signal( | |||||||
|     const char* signal_name, |     const char* signal_name, | ||||||
|     uint32_t** timings, |     uint32_t** timings, | ||||||
|     uint32_t* timings_count) { |     uint32_t* timings_count) { | ||||||
|     string_t buf; |     FuriString* buf; | ||||||
|     string_init(buf); |     buf = furi_string_alloc(); | ||||||
|     bool success = false; |     bool success = false; | ||||||
| 
 | 
 | ||||||
|     do { |     do { | ||||||
|         bool is_name_found = false; |         bool is_name_found = false; | ||||||
|         for(; !is_name_found && flipper_format_read_string(ff, "name", buf); |         for(; !is_name_found && flipper_format_read_string(ff, "name", buf); | ||||||
|             is_name_found = !string_cmp_str(buf, signal_name)) |             is_name_found = !furi_string_cmp(buf, signal_name)) | ||||||
|             ; |             ; | ||||||
| 
 | 
 | ||||||
|         if(!is_name_found) break; |         if(!is_name_found) break; | ||||||
|         if(!flipper_format_read_string(ff, "type", buf) || string_cmp_str(buf, "raw")) break; |         if(!flipper_format_read_string(ff, "type", buf) || furi_string_cmp_str(buf, "raw")) break; | ||||||
|         if(!flipper_format_get_value_count(ff, "data", timings_count)) break; |         if(!flipper_format_get_value_count(ff, "data", timings_count)) break; | ||||||
|         if(!*timings_count) break; |         if(!*timings_count) break; | ||||||
| 
 | 
 | ||||||
| @ -91,18 +92,18 @@ static bool infrared_test_load_raw_signal( | |||||||
|         success = true; |         success = true; | ||||||
|     } while(false); |     } while(false); | ||||||
| 
 | 
 | ||||||
|     string_clear(buf); |     furi_string_free(buf); | ||||||
|     return success; |     return success; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static bool infrared_test_read_message(FlipperFormat* ff, InfraredMessage* message) { | static bool infrared_test_read_message(FlipperFormat* ff, InfraredMessage* message) { | ||||||
|     string_t buf; |     FuriString* buf; | ||||||
|     string_init(buf); |     buf = furi_string_alloc(); | ||||||
|     bool success = false; |     bool success = false; | ||||||
| 
 | 
 | ||||||
|     do { |     do { | ||||||
|         if(!flipper_format_read_string(ff, "protocol", buf)) break; |         if(!flipper_format_read_string(ff, "protocol", buf)) break; | ||||||
|         message->protocol = infrared_get_protocol_by_name(string_get_cstr(buf)); |         message->protocol = infrared_get_protocol_by_name(furi_string_get_cstr(buf)); | ||||||
|         if(!infrared_is_protocol_valid(message->protocol)) break; |         if(!infrared_is_protocol_valid(message->protocol)) break; | ||||||
|         if(!flipper_format_read_hex(ff, "address", (uint8_t*)&message->address, sizeof(uint32_t))) |         if(!flipper_format_read_hex(ff, "address", (uint8_t*)&message->address, sizeof(uint32_t))) | ||||||
|             break; |             break; | ||||||
| @ -112,7 +113,7 @@ static bool infrared_test_read_message(FlipperFormat* ff, InfraredMessage* messa | |||||||
|         success = true; |         success = true; | ||||||
|     } while(false); |     } while(false); | ||||||
| 
 | 
 | ||||||
|     string_clear(buf); |     furi_string_free(buf); | ||||||
|     return success; |     return success; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -121,18 +122,19 @@ static bool infrared_test_load_messages( | |||||||
|     const char* signal_name, |     const char* signal_name, | ||||||
|     InfraredMessage** messages, |     InfraredMessage** messages, | ||||||
|     uint32_t* messages_count) { |     uint32_t* messages_count) { | ||||||
|     string_t buf; |     FuriString* buf; | ||||||
|     string_init(buf); |     buf = furi_string_alloc(); | ||||||
|     bool success = false; |     bool success = false; | ||||||
| 
 | 
 | ||||||
|     do { |     do { | ||||||
|         bool is_name_found = false; |         bool is_name_found = false; | ||||||
|         for(; !is_name_found && flipper_format_read_string(ff, "name", buf); |         for(; !is_name_found && flipper_format_read_string(ff, "name", buf); | ||||||
|             is_name_found = !string_cmp_str(buf, signal_name)) |             is_name_found = !furi_string_cmp(buf, signal_name)) | ||||||
|             ; |             ; | ||||||
| 
 | 
 | ||||||
|         if(!is_name_found) break; |         if(!is_name_found) break; | ||||||
|         if(!flipper_format_read_string(ff, "type", buf) || string_cmp_str(buf, "parsed_array")) |         if(!flipper_format_read_string(ff, "type", buf) || | ||||||
|  |            furi_string_cmp_str(buf, "parsed_array")) | ||||||
|             break; |             break; | ||||||
|         if(!flipper_format_read_uint32(ff, "count", messages_count, 1)) break; |         if(!flipper_format_read_uint32(ff, "count", messages_count, 1)) break; | ||||||
|         if(!*messages_count) break; |         if(!*messages_count) break; | ||||||
| @ -151,7 +153,7 @@ static bool infrared_test_load_messages( | |||||||
|         success = true; |         success = true; | ||||||
|     } while(false); |     } while(false); | ||||||
| 
 | 
 | ||||||
|     string_clear(buf); |     furi_string_free(buf); | ||||||
|     return success; |     return success; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -213,26 +215,26 @@ static void infrared_test_run_encoder(InfraredProtocol protocol, uint32_t test_i | |||||||
|     InfraredMessage* input_messages; |     InfraredMessage* input_messages; | ||||||
|     uint32_t input_messages_count; |     uint32_t input_messages_count; | ||||||
| 
 | 
 | ||||||
|     string_t buf; |     FuriString* buf; | ||||||
|     string_init(buf); |     buf = furi_string_alloc(); | ||||||
| 
 | 
 | ||||||
|     const char* protocol_name = infrared_get_protocol_name(protocol); |     const char* protocol_name = infrared_get_protocol_name(protocol); | ||||||
|     mu_assert(infrared_test_prepare_file(protocol_name), "Failed to prepare test file"); |     mu_assert(infrared_test_prepare_file(protocol_name), "Failed to prepare test file"); | ||||||
| 
 | 
 | ||||||
|     string_printf(buf, "encoder_input%d", test_index); |     furi_string_printf(buf, "encoder_input%ld", test_index); | ||||||
|     mu_assert( |     mu_assert( | ||||||
|         infrared_test_load_messages( |         infrared_test_load_messages( | ||||||
|             test->ff, string_get_cstr(buf), &input_messages, &input_messages_count), |             test->ff, furi_string_get_cstr(buf), &input_messages, &input_messages_count), | ||||||
|         "Failed to load messages from file"); |         "Failed to load messages from file"); | ||||||
| 
 | 
 | ||||||
|     string_printf(buf, "encoder_expected%d", test_index); |     furi_string_printf(buf, "encoder_expected%ld", test_index); | ||||||
|     mu_assert( |     mu_assert( | ||||||
|         infrared_test_load_raw_signal( |         infrared_test_load_raw_signal( | ||||||
|             test->ff, string_get_cstr(buf), &expected_timings, &expected_timings_count), |             test->ff, furi_string_get_cstr(buf), &expected_timings, &expected_timings_count), | ||||||
|         "Failed to load raw signal from file"); |         "Failed to load raw signal from file"); | ||||||
| 
 | 
 | ||||||
|     flipper_format_buffered_file_close(test->ff); |     flipper_format_buffered_file_close(test->ff); | ||||||
|     string_clear(buf); |     furi_string_free(buf); | ||||||
| 
 | 
 | ||||||
|     uint32_t j = 0; |     uint32_t j = 0; | ||||||
|     timings = malloc(sizeof(uint32_t) * timings_count); |     timings = malloc(sizeof(uint32_t) * timings_count); | ||||||
| @ -267,22 +269,22 @@ static void infrared_test_run_encoder_decoder(InfraredProtocol protocol, uint32_ | |||||||
|     uint32_t input_messages_count; |     uint32_t input_messages_count; | ||||||
|     bool level = false; |     bool level = false; | ||||||
| 
 | 
 | ||||||
|     string_t buf; |     FuriString* buf; | ||||||
|     string_init(buf); |     buf = furi_string_alloc(); | ||||||
| 
 | 
 | ||||||
|     timings = malloc(sizeof(uint32_t) * timings_count); |     timings = malloc(sizeof(uint32_t) * timings_count); | ||||||
| 
 | 
 | ||||||
|     const char* protocol_name = infrared_get_protocol_name(protocol); |     const char* protocol_name = infrared_get_protocol_name(protocol); | ||||||
|     mu_assert(infrared_test_prepare_file(protocol_name), "Failed to prepare test file"); |     mu_assert(infrared_test_prepare_file(protocol_name), "Failed to prepare test file"); | ||||||
| 
 | 
 | ||||||
|     string_printf(buf, "encoder_decoder_input%d", test_index); |     furi_string_printf(buf, "encoder_decoder_input%ld", test_index); | ||||||
|     mu_assert( |     mu_assert( | ||||||
|         infrared_test_load_messages( |         infrared_test_load_messages( | ||||||
|             test->ff, string_get_cstr(buf), &input_messages, &input_messages_count), |             test->ff, furi_string_get_cstr(buf), &input_messages, &input_messages_count), | ||||||
|         "Failed to load messages from file"); |         "Failed to load messages from file"); | ||||||
| 
 | 
 | ||||||
|     flipper_format_buffered_file_close(test->ff); |     flipper_format_buffered_file_close(test->ff); | ||||||
|     string_clear(buf); |     furi_string_free(buf); | ||||||
| 
 | 
 | ||||||
|     for(uint32_t message_counter = 0; message_counter < input_messages_count; ++message_counter) { |     for(uint32_t message_counter = 0; message_counter < input_messages_count; ++message_counter) { | ||||||
|         const InfraredMessage* message_encoded = &input_messages[message_counter]; |         const InfraredMessage* message_encoded = &input_messages[message_counter]; | ||||||
| @ -327,25 +329,27 @@ static void infrared_test_run_decoder(InfraredProtocol protocol, uint32_t test_i | |||||||
|     InfraredMessage* messages; |     InfraredMessage* messages; | ||||||
|     uint32_t messages_count; |     uint32_t messages_count; | ||||||
| 
 | 
 | ||||||
|     string_t buf; |     FuriString* buf; | ||||||
|     string_init(buf); |     buf = furi_string_alloc(); | ||||||
| 
 | 
 | ||||||
|     mu_assert( |     mu_assert( | ||||||
|         infrared_test_prepare_file(infrared_get_protocol_name(protocol)), |         infrared_test_prepare_file(infrared_get_protocol_name(protocol)), | ||||||
|         "Failed to prepare test file"); |         "Failed to prepare test file"); | ||||||
| 
 | 
 | ||||||
|     string_printf(buf, "decoder_input%d", test_index); |     furi_string_printf(buf, "decoder_input%ld", test_index); | ||||||
|     mu_assert( |     mu_assert( | ||||||
|         infrared_test_load_raw_signal(test->ff, string_get_cstr(buf), &timings, &timings_count), |         infrared_test_load_raw_signal( | ||||||
|  |             test->ff, furi_string_get_cstr(buf), &timings, &timings_count), | ||||||
|         "Failed to load raw signal from file"); |         "Failed to load raw signal from file"); | ||||||
| 
 | 
 | ||||||
|     string_printf(buf, "decoder_expected%d", test_index); |     furi_string_printf(buf, "decoder_expected%ld", test_index); | ||||||
|     mu_assert( |     mu_assert( | ||||||
|         infrared_test_load_messages(test->ff, string_get_cstr(buf), &messages, &messages_count), |         infrared_test_load_messages( | ||||||
|  |             test->ff, furi_string_get_cstr(buf), &messages, &messages_count), | ||||||
|         "Failed to load messages from file"); |         "Failed to load messages from file"); | ||||||
| 
 | 
 | ||||||
|     flipper_format_buffered_file_close(test->ff); |     flipper_format_buffered_file_close(test->ff); | ||||||
|     string_clear(buf); |     furi_string_free(buf); | ||||||
| 
 | 
 | ||||||
|     InfraredMessage message_decoded_check_local; |     InfraredMessage message_decoded_check_local; | ||||||
|     bool level = 0; |     bool level = 0; | ||||||
|  | |||||||
| @ -53,14 +53,15 @@ static bool nfc_test_read_signal_from_file(const char* file_name) { | |||||||
|     bool success = false; |     bool success = false; | ||||||
| 
 | 
 | ||||||
|     FlipperFormat* file = flipper_format_file_alloc(nfc_test->storage); |     FlipperFormat* file = flipper_format_file_alloc(nfc_test->storage); | ||||||
|     string_t file_type; |     FuriString* file_type; | ||||||
|     string_init(file_type); |     file_type = furi_string_alloc(); | ||||||
|     uint32_t file_version = 0; |     uint32_t file_version = 0; | ||||||
| 
 | 
 | ||||||
|     do { |     do { | ||||||
|         if(!flipper_format_file_open_existing(file, file_name)) break; |         if(!flipper_format_file_open_existing(file, file_name)) break; | ||||||
|         if(!flipper_format_read_header(file, file_type, &file_version)) break; |         if(!flipper_format_read_header(file, file_type, &file_version)) break; | ||||||
|         if(string_cmp_str(file_type, nfc_test_file_type) || file_version != nfc_test_file_version) |         if(furi_string_cmp_str(file_type, nfc_test_file_type) || | ||||||
|  |            file_version != nfc_test_file_version) | ||||||
|             break; |             break; | ||||||
|         if(!flipper_format_read_uint32(file, "Data length", &nfc_test->test_data_len, 1)) break; |         if(!flipper_format_read_uint32(file, "Data length", &nfc_test->test_data_len, 1)) break; | ||||||
|         if(nfc_test->test_data_len > NFC_TEST_DATA_MAX_LEN) break; |         if(nfc_test->test_data_len > NFC_TEST_DATA_MAX_LEN) break; | ||||||
| @ -76,7 +77,7 @@ static bool nfc_test_read_signal_from_file(const char* file_name) { | |||||||
|         success = true; |         success = true; | ||||||
|     } while(false); |     } while(false); | ||||||
| 
 | 
 | ||||||
|     string_clear(file_type); |     furi_string_free(file_type); | ||||||
|     flipper_format_free(file); |     flipper_format_free(file); | ||||||
| 
 | 
 | ||||||
|     return success; |     return success; | ||||||
| @ -111,7 +112,7 @@ static bool nfc_test_digital_signal_test_encode( | |||||||
|         // Check timings
 |         // Check timings
 | ||||||
|         if(time > encode_max_time) { |         if(time > encode_max_time) { | ||||||
|             FURI_LOG_E( |             FURI_LOG_E( | ||||||
|                 TAG, "Encoding time: %d us while accepted value: %d us", time, encode_max_time); |                 TAG, "Encoding time: %ld us while accepted value: %ld us", time, encode_max_time); | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| @ -131,7 +132,7 @@ static bool nfc_test_digital_signal_test_encode( | |||||||
|             ref_timings_sum += ref[i]; |             ref_timings_sum += ref[i]; | ||||||
|             if(timings_diff > timing_tolerance) { |             if(timings_diff > timing_tolerance) { | ||||||
|                 FURI_LOG_E( |                 FURI_LOG_E( | ||||||
|                     TAG, "Too big differece in %d timings. Ref: %d, DUT: %d", i, ref[i], dut[i]); |                     TAG, "Too big differece in %d timings. Ref: %ld, DUT: %ld", i, ref[i], dut[i]); | ||||||
|                 timing_check_success = false; |                 timing_check_success = false; | ||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
| @ -142,16 +143,16 @@ static bool nfc_test_digital_signal_test_encode( | |||||||
|         if(sum_diff > timings_sum_tolerance) { |         if(sum_diff > timings_sum_tolerance) { | ||||||
|             FURI_LOG_E( |             FURI_LOG_E( | ||||||
|                 TAG, |                 TAG, | ||||||
|                 "Too big difference in timings sum. Ref: %d, DUT: %d", |                 "Too big difference in timings sum. Ref: %ld, DUT: %ld", | ||||||
|                 ref_timings_sum, |                 ref_timings_sum, | ||||||
|                 dut_timings_sum); |                 dut_timings_sum); | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         FURI_LOG_I(TAG, "Encoding time: %d us. Acceptable time: %d us", time, encode_max_time); |         FURI_LOG_I(TAG, "Encoding time: %ld us. Acceptable time: %ld us", time, encode_max_time); | ||||||
|         FURI_LOG_I( |         FURI_LOG_I( | ||||||
|             TAG, |             TAG, | ||||||
|             "Timings sum difference: %d [1/64MHZ]. Acceptable difference: %d [1/64MHz]", |             "Timings sum difference: %ld [1/64MHZ]. Acceptable difference: %ld [1/64MHz]", | ||||||
|             sum_diff, |             sum_diff, | ||||||
|             timings_sum_tolerance); |             timings_sum_tolerance); | ||||||
|         success = true; |         success = true; | ||||||
| @ -174,8 +175,8 @@ MU_TEST(nfc_digital_signal_test) { | |||||||
| MU_TEST(mf_classic_dict_test) { | MU_TEST(mf_classic_dict_test) { | ||||||
|     MfClassicDict* instance = NULL; |     MfClassicDict* instance = NULL; | ||||||
|     uint64_t key = 0; |     uint64_t key = 0; | ||||||
|     string_t temp_str; |     FuriString* temp_str; | ||||||
|     string_init(temp_str); |     temp_str = furi_string_alloc(); | ||||||
| 
 | 
 | ||||||
|     instance = mf_classic_dict_alloc(MfClassicDictTypeUnitTest); |     instance = mf_classic_dict_alloc(MfClassicDictTypeUnitTest); | ||||||
|     mu_assert(instance != NULL, "mf_classic_dict_alloc\r\n"); |     mu_assert(instance != NULL, "mf_classic_dict_alloc\r\n"); | ||||||
| @ -184,7 +185,7 @@ MU_TEST(mf_classic_dict_test) { | |||||||
|         mf_classic_dict_get_total_keys(instance) == 0, |         mf_classic_dict_get_total_keys(instance) == 0, | ||||||
|         "mf_classic_dict_get_total_keys == 0 assert failed\r\n"); |         "mf_classic_dict_get_total_keys == 0 assert failed\r\n"); | ||||||
| 
 | 
 | ||||||
|     string_set(temp_str, "2196FAD8115B"); |     furi_string_set(temp_str, "2196FAD8115B"); | ||||||
|     mu_assert( |     mu_assert( | ||||||
|         mf_classic_dict_add_key_str(instance, temp_str), |         mf_classic_dict_add_key_str(instance, temp_str), | ||||||
|         "mf_classic_dict_add_key == true assert failed\r\n"); |         "mf_classic_dict_add_key == true assert failed\r\n"); | ||||||
| @ -199,7 +200,7 @@ MU_TEST(mf_classic_dict_test) { | |||||||
|         mf_classic_dict_get_key_at_index_str(instance, temp_str, 0), |         mf_classic_dict_get_key_at_index_str(instance, temp_str, 0), | ||||||
|         "mf_classic_dict_get_key_at_index_str == true assert failed\r\n"); |         "mf_classic_dict_get_key_at_index_str == true assert failed\r\n"); | ||||||
|     mu_assert( |     mu_assert( | ||||||
|         string_cmp(temp_str, "2196FAD8115B") == 0, |         furi_string_cmp(temp_str, "2196FAD8115B") == 0, | ||||||
|         "string_cmp(temp_str, \"2196FAD8115B\") == 0 assert failed\r\n"); |         "string_cmp(temp_str, \"2196FAD8115B\") == 0 assert failed\r\n"); | ||||||
| 
 | 
 | ||||||
|     mu_assert(mf_classic_dict_rewind(instance), "mf_classic_dict_rewind == 1 assert failed\r\n"); |     mu_assert(mf_classic_dict_rewind(instance), "mf_classic_dict_rewind == 1 assert failed\r\n"); | ||||||
| @ -216,7 +217,7 @@ MU_TEST(mf_classic_dict_test) { | |||||||
|         "mf_classic_dict_delete_index == true assert failed\r\n"); |         "mf_classic_dict_delete_index == true assert failed\r\n"); | ||||||
| 
 | 
 | ||||||
|     mf_classic_dict_free(instance); |     mf_classic_dict_free(instance); | ||||||
|     string_clear(temp_str); |     furi_string_free(temp_str); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| MU_TEST_SUITE(nfc) { | MU_TEST_SUITE(nfc) { | ||||||
|  | |||||||
| @ -10,7 +10,6 @@ | |||||||
| #include <furi.h> | #include <furi.h> | ||||||
| #include "../minunit.h" | #include "../minunit.h" | ||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
| #include <stream_buffer.h> |  | ||||||
| #include <pb.h> | #include <pb.h> | ||||||
| #include <pb_encode.h> | #include <pb_encode.h> | ||||||
| #include <m-list.h> | #include <m-list.h> | ||||||
| @ -34,7 +33,7 @@ static uint32_t command_id = 0; | |||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     RpcSession* session; |     RpcSession* session; | ||||||
|     StreamBufferHandle_t output_stream; |     FuriStreamBuffer* output_stream; | ||||||
|     SemaphoreHandle_t close_session_semaphore; |     SemaphoreHandle_t close_session_semaphore; | ||||||
|     SemaphoreHandle_t terminate_semaphore; |     SemaphoreHandle_t terminate_semaphore; | ||||||
|     TickType_t timeout; |     TickType_t timeout; | ||||||
| @ -90,7 +89,7 @@ static void test_rpc_setup(void) { | |||||||
|     } |     } | ||||||
|     furi_check(rpc_session[0].session); |     furi_check(rpc_session[0].session); | ||||||
| 
 | 
 | ||||||
|     rpc_session[0].output_stream = xStreamBufferCreate(1000, 1); |     rpc_session[0].output_stream = furi_stream_buffer_alloc(1000, 1); | ||||||
|     rpc_session_set_send_bytes_callback(rpc_session[0].session, output_bytes_callback); |     rpc_session_set_send_bytes_callback(rpc_session[0].session, output_bytes_callback); | ||||||
|     rpc_session[0].close_session_semaphore = xSemaphoreCreateBinary(); |     rpc_session[0].close_session_semaphore = xSemaphoreCreateBinary(); | ||||||
|     rpc_session[0].terminate_semaphore = xSemaphoreCreateBinary(); |     rpc_session[0].terminate_semaphore = xSemaphoreCreateBinary(); | ||||||
| @ -110,7 +109,7 @@ static void test_rpc_setup_second_session(void) { | |||||||
|     } |     } | ||||||
|     furi_check(rpc_session[1].session); |     furi_check(rpc_session[1].session); | ||||||
| 
 | 
 | ||||||
|     rpc_session[1].output_stream = xStreamBufferCreate(1000, 1); |     rpc_session[1].output_stream = furi_stream_buffer_alloc(1000, 1); | ||||||
|     rpc_session_set_send_bytes_callback(rpc_session[1].session, output_bytes_callback); |     rpc_session_set_send_bytes_callback(rpc_session[1].session, output_bytes_callback); | ||||||
|     rpc_session[1].close_session_semaphore = xSemaphoreCreateBinary(); |     rpc_session[1].close_session_semaphore = xSemaphoreCreateBinary(); | ||||||
|     rpc_session[1].terminate_semaphore = xSemaphoreCreateBinary(); |     rpc_session[1].terminate_semaphore = xSemaphoreCreateBinary(); | ||||||
| @ -126,7 +125,7 @@ static void test_rpc_teardown(void) { | |||||||
|     rpc_session_close(rpc_session[0].session); |     rpc_session_close(rpc_session[0].session); | ||||||
|     furi_check(xSemaphoreTake(rpc_session[0].terminate_semaphore, portMAX_DELAY)); |     furi_check(xSemaphoreTake(rpc_session[0].terminate_semaphore, portMAX_DELAY)); | ||||||
|     furi_record_close(RECORD_RPC); |     furi_record_close(RECORD_RPC); | ||||||
|     vStreamBufferDelete(rpc_session[0].output_stream); |     furi_stream_buffer_free(rpc_session[0].output_stream); | ||||||
|     vSemaphoreDelete(rpc_session[0].close_session_semaphore); |     vSemaphoreDelete(rpc_session[0].close_session_semaphore); | ||||||
|     vSemaphoreDelete(rpc_session[0].terminate_semaphore); |     vSemaphoreDelete(rpc_session[0].terminate_semaphore); | ||||||
|     ++command_id; |     ++command_id; | ||||||
| @ -141,7 +140,7 @@ static void test_rpc_teardown_second_session(void) { | |||||||
|     xSemaphoreTake(rpc_session[1].terminate_semaphore, 0); |     xSemaphoreTake(rpc_session[1].terminate_semaphore, 0); | ||||||
|     rpc_session_close(rpc_session[1].session); |     rpc_session_close(rpc_session[1].session); | ||||||
|     furi_check(xSemaphoreTake(rpc_session[1].terminate_semaphore, portMAX_DELAY)); |     furi_check(xSemaphoreTake(rpc_session[1].terminate_semaphore, portMAX_DELAY)); | ||||||
|     vStreamBufferDelete(rpc_session[1].output_stream); |     furi_stream_buffer_free(rpc_session[1].output_stream); | ||||||
|     vSemaphoreDelete(rpc_session[1].close_session_semaphore); |     vSemaphoreDelete(rpc_session[1].close_session_semaphore); | ||||||
|     vSemaphoreDelete(rpc_session[1].terminate_semaphore); |     vSemaphoreDelete(rpc_session[1].terminate_semaphore); | ||||||
|     ++command_id; |     ++command_id; | ||||||
| @ -268,8 +267,8 @@ static PB_CommandStatus test_rpc_storage_get_file_error(File* file) { | |||||||
| static void output_bytes_callback(void* ctx, uint8_t* got_bytes, size_t got_size) { | static void output_bytes_callback(void* ctx, uint8_t* got_bytes, size_t got_size) { | ||||||
|     RpcSessionContext* callbacks_context = ctx; |     RpcSessionContext* callbacks_context = ctx; | ||||||
| 
 | 
 | ||||||
|     size_t bytes_sent = |     size_t bytes_sent = furi_stream_buffer_send( | ||||||
|         xStreamBufferSend(callbacks_context->output_stream, got_bytes, got_size, FuriWaitForever); |         callbacks_context->output_stream, got_bytes, got_size, FuriWaitForever); | ||||||
|     (void)bytes_sent; |     (void)bytes_sent; | ||||||
|     furi_check(bytes_sent == got_size); |     furi_check(bytes_sent == got_size); | ||||||
| } | } | ||||||
| @ -534,7 +533,8 @@ static bool test_rpc_pb_stream_read(pb_istream_t* istream, pb_byte_t* buf, size_ | |||||||
|     TickType_t now = xTaskGetTickCount(); |     TickType_t now = xTaskGetTickCount(); | ||||||
|     int32_t time_left = session_context->timeout - now; |     int32_t time_left = session_context->timeout - now; | ||||||
|     time_left = MAX(time_left, 0); |     time_left = MAX(time_left, 0); | ||||||
|     bytes_received = xStreamBufferReceive(session_context->output_stream, buf, count, time_left); |     bytes_received = | ||||||
|  |         furi_stream_buffer_receive(session_context->output_stream, buf, count, time_left); | ||||||
|     return (count == bytes_received); |     return (count == bytes_received); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -75,7 +75,7 @@ typedef struct { | |||||||
|     bool visited; |     bool visited; | ||||||
| } StorageTestPath; | } StorageTestPath; | ||||||
| 
 | 
 | ||||||
| DICT_DEF2(StorageTestPathDict, string_t, STRING_OPLIST, StorageTestPath, M_POD_OPLIST) | DICT_DEF2(StorageTestPathDict, FuriString*, FURI_STRING_OPLIST, StorageTestPath, M_POD_OPLIST) | ||||||
| 
 | 
 | ||||||
| static StorageTestPathDict_t* | static StorageTestPathDict_t* | ||||||
|     storage_test_paths_alloc(const StorageTestPathDesc paths[], size_t paths_count) { |     storage_test_paths_alloc(const StorageTestPathDesc paths[], size_t paths_count) { | ||||||
| @ -83,15 +83,15 @@ static StorageTestPathDict_t* | |||||||
|     StorageTestPathDict_init(*data); |     StorageTestPathDict_init(*data); | ||||||
| 
 | 
 | ||||||
|     for(size_t i = 0; i < paths_count; i++) { |     for(size_t i = 0; i < paths_count; i++) { | ||||||
|         string_t key; |         FuriString* key; | ||||||
|         string_init_set(key, paths[i].path); |         key = furi_string_alloc_set(paths[i].path); | ||||||
|         StorageTestPath value = { |         StorageTestPath value = { | ||||||
|             .is_dir = paths[i].is_dir, |             .is_dir = paths[i].is_dir, | ||||||
|             .visited = false, |             .visited = false, | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         StorageTestPathDict_set_at(*data, key, value); |         StorageTestPathDict_set_at(*data, key, value); | ||||||
|         string_clear(key); |         furi_string_free(key); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return data; |     return data; | ||||||
| @ -102,7 +102,7 @@ static void storage_test_paths_free(StorageTestPathDict_t* data) { | |||||||
|     free(data); |     free(data); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static bool storage_test_paths_mark(StorageTestPathDict_t* data, string_t path, bool is_dir) { | static bool storage_test_paths_mark(StorageTestPathDict_t* data, FuriString* path, bool is_dir) { | ||||||
|     bool found = false; |     bool found = false; | ||||||
| 
 | 
 | ||||||
|     StorageTestPath* record = StorageTestPathDict_get(*data, path); |     StorageTestPath* record = StorageTestPathDict_get(*data, path); | ||||||
| @ -148,27 +148,27 @@ static bool write_file_13DA(Storage* storage, const char* path) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void storage_dirs_create(Storage* storage, const char* base) { | static void storage_dirs_create(Storage* storage, const char* base) { | ||||||
|     string_t path; |     FuriString* path; | ||||||
|     string_init(path); |     path = furi_string_alloc(); | ||||||
| 
 | 
 | ||||||
|     storage_common_mkdir(storage, base); |     storage_common_mkdir(storage, base); | ||||||
| 
 | 
 | ||||||
|     for(size_t i = 0; i < COUNT_OF(storage_test_dirwalk_paths); i++) { |     for(size_t i = 0; i < COUNT_OF(storage_test_dirwalk_paths); i++) { | ||||||
|         string_printf(path, "%s/%s", base, storage_test_dirwalk_paths[i]); |         furi_string_printf(path, "%s/%s", base, storage_test_dirwalk_paths[i]); | ||||||
|         storage_common_mkdir(storage, string_get_cstr(path)); |         storage_common_mkdir(storage, furi_string_get_cstr(path)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     for(size_t i = 0; i < COUNT_OF(storage_test_dirwalk_files); i++) { |     for(size_t i = 0; i < COUNT_OF(storage_test_dirwalk_files); i++) { | ||||||
|         string_printf(path, "%s/%s", base, storage_test_dirwalk_files[i]); |         furi_string_printf(path, "%s/%s", base, storage_test_dirwalk_files[i]); | ||||||
|         write_file_13DA(storage, string_get_cstr(path)); |         write_file_13DA(storage, furi_string_get_cstr(path)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     string_clear(path); |     furi_string_free(path); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| MU_TEST_1(test_dirwalk_full, Storage* storage) { | MU_TEST_1(test_dirwalk_full, Storage* storage) { | ||||||
|     string_t path; |     FuriString* path; | ||||||
|     string_init(path); |     path = furi_string_alloc(); | ||||||
|     FileInfo fileinfo; |     FileInfo fileinfo; | ||||||
| 
 | 
 | ||||||
|     StorageTestPathDict_t* paths = |     StorageTestPathDict_t* paths = | ||||||
| @ -178,12 +178,12 @@ MU_TEST_1(test_dirwalk_full, Storage* storage) { | |||||||
|     mu_check(dir_walk_open(dir_walk, EXT_PATH("dirwalk"))); |     mu_check(dir_walk_open(dir_walk, EXT_PATH("dirwalk"))); | ||||||
| 
 | 
 | ||||||
|     while(dir_walk_read(dir_walk, path, &fileinfo) == DirWalkOK) { |     while(dir_walk_read(dir_walk, path, &fileinfo) == DirWalkOK) { | ||||||
|         string_right(path, strlen(EXT_PATH("dirwalk/"))); |         furi_string_right(path, strlen(EXT_PATH("dirwalk/"))); | ||||||
|         mu_check(storage_test_paths_mark(paths, path, (fileinfo.flags & FSF_DIRECTORY))); |         mu_check(storage_test_paths_mark(paths, path, (fileinfo.flags & FSF_DIRECTORY))); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     dir_walk_free(dir_walk); |     dir_walk_free(dir_walk); | ||||||
|     string_clear(path); |     furi_string_free(path); | ||||||
| 
 | 
 | ||||||
|     mu_check(storage_test_paths_check(paths) == false); |     mu_check(storage_test_paths_check(paths) == false); | ||||||
| 
 | 
 | ||||||
| @ -191,8 +191,8 @@ MU_TEST_1(test_dirwalk_full, Storage* storage) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| MU_TEST_1(test_dirwalk_no_recursive, Storage* storage) { | MU_TEST_1(test_dirwalk_no_recursive, Storage* storage) { | ||||||
|     string_t path; |     FuriString* path; | ||||||
|     string_init(path); |     path = furi_string_alloc(); | ||||||
|     FileInfo fileinfo; |     FileInfo fileinfo; | ||||||
| 
 | 
 | ||||||
|     StorageTestPathDict_t* paths = storage_test_paths_alloc( |     StorageTestPathDict_t* paths = storage_test_paths_alloc( | ||||||
| @ -203,12 +203,12 @@ MU_TEST_1(test_dirwalk_no_recursive, Storage* storage) { | |||||||
|     mu_check(dir_walk_open(dir_walk, EXT_PATH("dirwalk"))); |     mu_check(dir_walk_open(dir_walk, EXT_PATH("dirwalk"))); | ||||||
| 
 | 
 | ||||||
|     while(dir_walk_read(dir_walk, path, &fileinfo) == DirWalkOK) { |     while(dir_walk_read(dir_walk, path, &fileinfo) == DirWalkOK) { | ||||||
|         string_right(path, strlen(EXT_PATH("dirwalk/"))); |         furi_string_right(path, strlen(EXT_PATH("dirwalk/"))); | ||||||
|         mu_check(storage_test_paths_mark(paths, path, (fileinfo.flags & FSF_DIRECTORY))); |         mu_check(storage_test_paths_mark(paths, path, (fileinfo.flags & FSF_DIRECTORY))); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     dir_walk_free(dir_walk); |     dir_walk_free(dir_walk); | ||||||
|     string_clear(path); |     furi_string_free(path); | ||||||
| 
 | 
 | ||||||
|     mu_check(storage_test_paths_check(paths) == false); |     mu_check(storage_test_paths_check(paths) == false); | ||||||
| 
 | 
 | ||||||
| @ -230,8 +230,8 @@ static bool test_dirwalk_filter_no_folder_ext(const char* name, FileInfo* filein | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| MU_TEST_1(test_dirwalk_filter, Storage* storage) { | MU_TEST_1(test_dirwalk_filter, Storage* storage) { | ||||||
|     string_t path; |     FuriString* path; | ||||||
|     string_init(path); |     path = furi_string_alloc(); | ||||||
|     FileInfo fileinfo; |     FileInfo fileinfo; | ||||||
| 
 | 
 | ||||||
|     StorageTestPathDict_t* paths = storage_test_paths_alloc( |     StorageTestPathDict_t* paths = storage_test_paths_alloc( | ||||||
| @ -242,12 +242,12 @@ MU_TEST_1(test_dirwalk_filter, Storage* storage) { | |||||||
|     mu_check(dir_walk_open(dir_walk, EXT_PATH("dirwalk"))); |     mu_check(dir_walk_open(dir_walk, EXT_PATH("dirwalk"))); | ||||||
| 
 | 
 | ||||||
|     while(dir_walk_read(dir_walk, path, &fileinfo) == DirWalkOK) { |     while(dir_walk_read(dir_walk, path, &fileinfo) == DirWalkOK) { | ||||||
|         string_right(path, strlen(EXT_PATH("dirwalk/"))); |         furi_string_right(path, strlen(EXT_PATH("dirwalk/"))); | ||||||
|         mu_check(storage_test_paths_mark(paths, path, (fileinfo.flags & FSF_DIRECTORY))); |         mu_check(storage_test_paths_mark(paths, path, (fileinfo.flags & FSF_DIRECTORY))); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     dir_walk_free(dir_walk); |     dir_walk_free(dir_walk); | ||||||
|     string_clear(path); |     furi_string_free(path); | ||||||
| 
 | 
 | ||||||
|     mu_check(storage_test_paths_check(paths) == false); |     mu_check(storage_test_paths_check(paths) == false); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -211,22 +211,22 @@ static bool check_file_13DA(Storage* storage, const char* path) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void storage_dir_create(Storage* storage, const char* base) { | static void storage_dir_create(Storage* storage, const char* base) { | ||||||
|     string_t path; |     FuriString* path; | ||||||
|     string_init(path); |     path = furi_string_alloc(); | ||||||
| 
 | 
 | ||||||
|     storage_common_mkdir(storage, base); |     storage_common_mkdir(storage, base); | ||||||
| 
 | 
 | ||||||
|     for(size_t i = 0; i < COUNT_OF(storage_copy_test_paths); i++) { |     for(size_t i = 0; i < COUNT_OF(storage_copy_test_paths); i++) { | ||||||
|         string_printf(path, "%s/%s", base, storage_copy_test_paths[i]); |         furi_string_printf(path, "%s/%s", base, storage_copy_test_paths[i]); | ||||||
|         storage_common_mkdir(storage, string_get_cstr(path)); |         storage_common_mkdir(storage, furi_string_get_cstr(path)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     for(size_t i = 0; i < COUNT_OF(storage_copy_test_files); i++) { |     for(size_t i = 0; i < COUNT_OF(storage_copy_test_files); i++) { | ||||||
|         string_printf(path, "%s/%s", base, storage_copy_test_files[i]); |         furi_string_printf(path, "%s/%s", base, storage_copy_test_files[i]); | ||||||
|         write_file_13DA(storage, string_get_cstr(path)); |         write_file_13DA(storage, furi_string_get_cstr(path)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     string_clear(path); |     furi_string_free(path); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void storage_dir_remove(Storage* storage, const char* base) { | static void storage_dir_remove(Storage* storage, const char* base) { | ||||||
| @ -235,15 +235,15 @@ static void storage_dir_remove(Storage* storage, const char* base) { | |||||||
| 
 | 
 | ||||||
| static bool storage_dir_rename_check(Storage* storage, const char* base) { | static bool storage_dir_rename_check(Storage* storage, const char* base) { | ||||||
|     bool result = false; |     bool result = false; | ||||||
|     string_t path; |     FuriString* path; | ||||||
|     string_init(path); |     path = furi_string_alloc(); | ||||||
| 
 | 
 | ||||||
|     result = (storage_common_stat(storage, base, NULL) == FSE_OK); |     result = (storage_common_stat(storage, base, NULL) == FSE_OK); | ||||||
| 
 | 
 | ||||||
|     if(result) { |     if(result) { | ||||||
|         for(size_t i = 0; i < COUNT_OF(storage_copy_test_paths); i++) { |         for(size_t i = 0; i < COUNT_OF(storage_copy_test_paths); i++) { | ||||||
|             string_printf(path, "%s/%s", base, storage_copy_test_paths[i]); |             furi_string_printf(path, "%s/%s", base, storage_copy_test_paths[i]); | ||||||
|             result = (storage_common_stat(storage, string_get_cstr(path), NULL) == FSE_OK); |             result = (storage_common_stat(storage, furi_string_get_cstr(path), NULL) == FSE_OK); | ||||||
|             if(!result) { |             if(!result) { | ||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
| @ -252,15 +252,15 @@ static bool storage_dir_rename_check(Storage* storage, const char* base) { | |||||||
| 
 | 
 | ||||||
|     if(result) { |     if(result) { | ||||||
|         for(size_t i = 0; i < COUNT_OF(storage_copy_test_files); i++) { |         for(size_t i = 0; i < COUNT_OF(storage_copy_test_files); i++) { | ||||||
|             string_printf(path, "%s/%s", base, storage_copy_test_files[i]); |             furi_string_printf(path, "%s/%s", base, storage_copy_test_files[i]); | ||||||
|             result = check_file_13DA(storage, string_get_cstr(path)); |             result = check_file_13DA(storage, furi_string_get_cstr(path)); | ||||||
|             if(!result) { |             if(!result) { | ||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     string_clear(path); |     furi_string_free(path); | ||||||
|     return result; |     return result; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -18,8 +18,8 @@ static const char* stream_test_right_data = | |||||||
| MU_TEST_1(stream_composite_subtest, Stream* stream) { | MU_TEST_1(stream_composite_subtest, Stream* stream) { | ||||||
|     const size_t data_size = 128; |     const size_t data_size = 128; | ||||||
|     uint8_t data[data_size]; |     uint8_t data[data_size]; | ||||||
|     string_t string_lee; |     FuriString* string_lee; | ||||||
|     string_init_set(string_lee, "lee"); |     string_lee = furi_string_alloc_set("lee"); | ||||||
| 
 | 
 | ||||||
|     // test that stream is empty
 |     // test that stream is empty
 | ||||||
|     // "" -> ""
 |     // "" -> ""
 | ||||||
| @ -267,7 +267,7 @@ MU_TEST_1(stream_composite_subtest, Stream* stream) { | |||||||
|     mu_assert_int_eq(9, stream_tell(stream)); |     mu_assert_int_eq(9, stream_tell(stream)); | ||||||
|     mu_check(stream_eof(stream)); |     mu_check(stream_eof(stream)); | ||||||
| 
 | 
 | ||||||
|     string_clear(string_lee); |     furi_string_free(string_lee); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| MU_TEST(stream_composite_test) { | MU_TEST(stream_composite_test) { | ||||||
| @ -416,10 +416,10 @@ MU_TEST(stream_buffered_write_after_read_test) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| MU_TEST(stream_buffered_large_file_test) { | MU_TEST(stream_buffered_large_file_test) { | ||||||
|     string_t input_data; |     FuriString* input_data; | ||||||
|     string_t output_data; |     FuriString* output_data; | ||||||
|     string_init(input_data); |     input_data = furi_string_alloc(); | ||||||
|     string_init(output_data); |     output_data = furi_string_alloc(); | ||||||
| 
 | 
 | ||||||
|     Storage* storage = furi_record_open(RECORD_STORAGE); |     Storage* storage = furi_record_open(RECORD_STORAGE); | ||||||
| 
 | 
 | ||||||
| @ -429,7 +429,7 @@ MU_TEST(stream_buffered_large_file_test) { | |||||||
|     const size_t rep_count = data_size / line_size + 1; |     const size_t rep_count = data_size / line_size + 1; | ||||||
| 
 | 
 | ||||||
|     for(size_t i = 0; i < rep_count; ++i) { |     for(size_t i = 0; i < rep_count; ++i) { | ||||||
|         string_cat_printf(input_data, "%s\n", stream_test_data); |         furi_string_cat_printf(input_data, "%s\n", stream_test_data); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // write test data to file
 |     // write test data to file
 | ||||||
| @ -437,8 +437,8 @@ MU_TEST(stream_buffered_large_file_test) { | |||||||
|     mu_check(buffered_file_stream_open( |     mu_check(buffered_file_stream_open( | ||||||
|         stream, EXT_PATH("filestream.str"), FSAM_READ_WRITE, FSOM_CREATE_ALWAYS)); |         stream, EXT_PATH("filestream.str"), FSAM_READ_WRITE, FSOM_CREATE_ALWAYS)); | ||||||
|     mu_assert_int_eq(0, stream_size(stream)); |     mu_assert_int_eq(0, stream_size(stream)); | ||||||
|     mu_assert_int_eq(string_size(input_data), stream_write_string(stream, input_data)); |     mu_assert_int_eq(furi_string_size(input_data), stream_write_string(stream, input_data)); | ||||||
|     mu_assert_int_eq(string_size(input_data), stream_size(stream)); |     mu_assert_int_eq(furi_string_size(input_data), stream_size(stream)); | ||||||
| 
 | 
 | ||||||
|     const size_t substr_start = 8; |     const size_t substr_start = 8; | ||||||
|     const size_t substr_len = 11; |     const size_t substr_len = 11; | ||||||
| @ -475,23 +475,23 @@ MU_TEST(stream_buffered_large_file_test) { | |||||||
| 
 | 
 | ||||||
|     // read the whole file
 |     // read the whole file
 | ||||||
|     mu_check(stream_rewind(stream)); |     mu_check(stream_rewind(stream)); | ||||||
|     string_t tmp; |     FuriString* tmp; | ||||||
|     string_init(tmp); |     tmp = furi_string_alloc(); | ||||||
|     while(stream_read_line(stream, tmp)) { |     while(stream_read_line(stream, tmp)) { | ||||||
|         string_cat(output_data, tmp); |         furi_string_cat(output_data, tmp); | ||||||
|     } |     } | ||||||
|     string_clear(tmp); |     furi_string_free(tmp); | ||||||
| 
 | 
 | ||||||
|     // check against generated data
 |     // check against generated data
 | ||||||
|     mu_assert_int_eq(string_size(input_data), string_size(output_data)); |     mu_assert_int_eq(furi_string_size(input_data), furi_string_size(output_data)); | ||||||
|     mu_check(string_equal_p(input_data, output_data)); |     mu_check(furi_string_equal(input_data, output_data)); | ||||||
|     mu_check(stream_eof(stream)); |     mu_check(stream_eof(stream)); | ||||||
| 
 | 
 | ||||||
|     stream_free(stream); |     stream_free(stream); | ||||||
| 
 | 
 | ||||||
|     furi_record_close(RECORD_STORAGE); |     furi_record_close(RECORD_STORAGE); | ||||||
|     string_clear(input_data); |     furi_string_free(input_data); | ||||||
|     string_clear(output_data); |     furi_string_free(output_data); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| MU_TEST_SUITE(stream_suite) { | MU_TEST_SUITE(stream_suite) { | ||||||
|  | |||||||
| @ -28,12 +28,12 @@ static void subghz_test_rx_callback( | |||||||
|     void* context) { |     void* context) { | ||||||
|     UNUSED(receiver); |     UNUSED(receiver); | ||||||
|     UNUSED(context); |     UNUSED(context); | ||||||
|     string_t text; |     FuriString* text; | ||||||
|     string_init(text); |     text = furi_string_alloc(); | ||||||
|     subghz_protocol_decoder_base_get_string(decoder_base, text); |     subghz_protocol_decoder_base_get_string(decoder_base, text); | ||||||
|     subghz_receiver_reset(receiver_handler); |     subghz_receiver_reset(receiver_handler); | ||||||
|     FURI_LOG_T(TAG, "\r\n%s", string_get_cstr(text)); |     FURI_LOG_T(TAG, "\r\n%s", furi_string_get_cstr(text)); | ||||||
|     string_clear(text); |     furi_string_free(text); | ||||||
|     subghz_test_decoder_count++; |     subghz_test_decoder_count++; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -141,8 +141,8 @@ static bool subghz_decode_random_test(const char* path) { | |||||||
| static bool subghz_encoder_test(const char* path) { | static bool subghz_encoder_test(const char* path) { | ||||||
|     subghz_test_decoder_count = 0; |     subghz_test_decoder_count = 0; | ||||||
|     uint32_t test_start = furi_get_tick(); |     uint32_t test_start = furi_get_tick(); | ||||||
|     string_t temp_str; |     FuriString* temp_str; | ||||||
|     string_init(temp_str); |     temp_str = furi_string_alloc(); | ||||||
|     bool file_load = false; |     bool file_load = false; | ||||||
| 
 | 
 | ||||||
|     Storage* storage = furi_record_open(RECORD_STORAGE); |     Storage* storage = furi_record_open(RECORD_STORAGE); | ||||||
| @ -167,11 +167,11 @@ static bool subghz_encoder_test(const char* path) { | |||||||
|     } while(false); |     } while(false); | ||||||
|     if(file_load) { |     if(file_load) { | ||||||
|         SubGhzTransmitter* transmitter = |         SubGhzTransmitter* transmitter = | ||||||
|             subghz_transmitter_alloc_init(environment_handler, string_get_cstr(temp_str)); |             subghz_transmitter_alloc_init(environment_handler, furi_string_get_cstr(temp_str)); | ||||||
|         subghz_transmitter_deserialize(transmitter, fff_data_file); |         subghz_transmitter_deserialize(transmitter, fff_data_file); | ||||||
| 
 | 
 | ||||||
|         SubGhzProtocolDecoderBase* decoder = subghz_receiver_search_decoder_base_by_name( |         SubGhzProtocolDecoderBase* decoder = subghz_receiver_search_decoder_base_by_name( | ||||||
|             receiver_handler, string_get_cstr(temp_str)); |             receiver_handler, furi_string_get_cstr(temp_str)); | ||||||
| 
 | 
 | ||||||
|         if(decoder) { |         if(decoder) { | ||||||
|             LevelDuration level_duration; |             LevelDuration level_duration; | ||||||
| @ -192,10 +192,11 @@ static bool subghz_encoder_test(const char* path) { | |||||||
|     flipper_format_free(fff_data_file); |     flipper_format_free(fff_data_file); | ||||||
|     FURI_LOG_T(TAG, "\r\n Decoder count parse \033[0;33m%d\033[0m ", subghz_test_decoder_count); |     FURI_LOG_T(TAG, "\r\n Decoder count parse \033[0;33m%d\033[0m ", subghz_test_decoder_count); | ||||||
|     if(furi_get_tick() - test_start > TEST_TIMEOUT) { |     if(furi_get_tick() - test_start > TEST_TIMEOUT) { | ||||||
|         printf("\033[0;31mTest encoder %s ERROR TimeOut\033[0m\r\n", string_get_cstr(temp_str)); |         printf( | ||||||
|  |             "\033[0;31mTest encoder %s ERROR TimeOut\033[0m\r\n", furi_string_get_cstr(temp_str)); | ||||||
|         subghz_test_decoder_count = 0; |         subghz_test_decoder_count = 0; | ||||||
|     } |     } | ||||||
|     string_clear(temp_str); |     furi_string_free(temp_str); | ||||||
| 
 | 
 | ||||||
|     return subghz_test_decoder_count ? true : false; |     return subghz_test_decoder_count ? true : false; | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,5 +1,3 @@ | |||||||
| #include "m-string.h" |  | ||||||
| 
 |  | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| #include <furi_hal.h> | #include <furi_hal.h> | ||||||
| @ -11,6 +9,7 @@ | |||||||
| #define TAG "UnitTests" | #define TAG "UnitTests" | ||||||
| 
 | 
 | ||||||
| int run_minunit_test_furi(); | int run_minunit_test_furi(); | ||||||
|  | int run_minunit_test_furi_string(); | ||||||
| int run_minunit_test_infrared(); | int run_minunit_test_infrared(); | ||||||
| int run_minunit_test_rpc(); | int run_minunit_test_rpc(); | ||||||
| int run_minunit_test_flipper_format(); | int run_minunit_test_flipper_format(); | ||||||
| @ -33,6 +32,7 @@ typedef struct { | |||||||
| 
 | 
 | ||||||
| const UnitTest unit_tests[] = { | const UnitTest unit_tests[] = { | ||||||
|     {.name = "furi", .entry = run_minunit_test_furi}, |     {.name = "furi", .entry = run_minunit_test_furi}, | ||||||
|  |     {.name = "furi_string", .entry = run_minunit_test_furi_string}, | ||||||
|     {.name = "storage", .entry = run_minunit_test_storage}, |     {.name = "storage", .entry = run_minunit_test_storage}, | ||||||
|     {.name = "stream", .entry = run_minunit_test_stream}, |     {.name = "stream", .entry = run_minunit_test_stream}, | ||||||
|     {.name = "dirwalk", .entry = run_minunit_test_dirwalk}, |     {.name = "dirwalk", .entry = run_minunit_test_dirwalk}, | ||||||
| @ -63,7 +63,7 @@ void minunit_print_fail(const char* str) { | |||||||
|     printf(FURI_LOG_CLR_E "%s\r\n" FURI_LOG_CLR_RESET, str); |     printf(FURI_LOG_CLR_E "%s\r\n" FURI_LOG_CLR_RESET, str); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void unit_tests_cli(Cli* cli, string_t args, void* context) { | void unit_tests_cli(Cli* cli, FuriString* args, void* context) { | ||||||
|     UNUSED(cli); |     UNUSED(cli); | ||||||
|     UNUSED(args); |     UNUSED(args); | ||||||
|     UNUSED(context); |     UNUSED(context); | ||||||
| @ -91,8 +91,8 @@ void unit_tests_cli(Cli* cli, string_t args, void* context) { | |||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             if(string_size(args)) { |             if(furi_string_size(args)) { | ||||||
|                 if(string_cmp_str(args, unit_tests[i].name) == 0) { |                 if(furi_string_cmp_str(args, unit_tests[i].name) == 0) { | ||||||
|                     failed_tests += unit_tests[i].entry(); |                     failed_tests += unit_tests[i].entry(); | ||||||
|                 } else { |                 } else { | ||||||
|                     printf("Skipping %s\r\n", unit_tests[i].name); |                     printf("Skipping %s\r\n", unit_tests[i].name); | ||||||
|  | |||||||
							
								
								
									
										5
									
								
								applications/examples/application.fam
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								applications/examples/application.fam
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | |||||||
|  | App( | ||||||
|  |     appid="sample_apps", | ||||||
|  |     name="Sample apps bundle", | ||||||
|  |     apptype=FlipperAppType.METAPACKAGE, | ||||||
|  | ) | ||||||
							
								
								
									
										10
									
								
								applications/examples/example_images/application.fam
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								applications/examples/example_images/application.fam
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | |||||||
|  | App( | ||||||
|  |     appid="example_images", | ||||||
|  |     name="Example: Images", | ||||||
|  |     apptype=FlipperAppType.EXTERNAL, | ||||||
|  |     entry_point="example_images_main", | ||||||
|  |     requires=["gui"], | ||||||
|  |     stack_size=1 * 1024, | ||||||
|  |     fap_category="Examples", | ||||||
|  |     fap_icon_assets="images", | ||||||
|  | ) | ||||||
							
								
								
									
										81
									
								
								applications/examples/example_images/example_images.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								applications/examples/example_images/example_images.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,81 @@ | |||||||
|  | #include <furi.h> | ||||||
|  | #include <furi_hal.h> | ||||||
|  | 
 | ||||||
|  | #include <gui/gui.h> | ||||||
|  | #include <input/input.h> | ||||||
|  | 
 | ||||||
|  | /* Magic happens here -- this file is generated by fbt.
 | ||||||
|  |  * Just set fap_icon_assets in application.fam and #include {APPID}_icons.h */ | ||||||
|  | #include "example_images_icons.h" | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     uint8_t x, y; | ||||||
|  | } ImagePosition; | ||||||
|  | 
 | ||||||
|  | static ImagePosition image_position = {.x = 0, .y = 0}; | ||||||
|  | 
 | ||||||
|  | // Screen is 128x64 px
 | ||||||
|  | static void app_draw_callback(Canvas* canvas, void* ctx) { | ||||||
|  |     UNUSED(ctx); | ||||||
|  | 
 | ||||||
|  |     canvas_clear(canvas); | ||||||
|  |     canvas_draw_icon(canvas, image_position.x % 128, image_position.y % 64, &I_dolphin_71x25); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void app_input_callback(InputEvent* input_event, void* ctx) { | ||||||
|  |     furi_assert(ctx); | ||||||
|  | 
 | ||||||
|  |     FuriMessageQueue* event_queue = ctx; | ||||||
|  |     furi_message_queue_put(event_queue, input_event, FuriWaitForever); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int32_t example_images_main(void* p) { | ||||||
|  |     UNUSED(p); | ||||||
|  |     FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(InputEvent)); | ||||||
|  | 
 | ||||||
|  |     // Configure view port
 | ||||||
|  |     ViewPort* view_port = view_port_alloc(); | ||||||
|  |     view_port_draw_callback_set(view_port, app_draw_callback, view_port); | ||||||
|  |     view_port_input_callback_set(view_port, app_input_callback, event_queue); | ||||||
|  | 
 | ||||||
|  |     // Register view port in GUI
 | ||||||
|  |     Gui* gui = furi_record_open(RECORD_GUI); | ||||||
|  |     gui_add_view_port(gui, view_port, GuiLayerFullscreen); | ||||||
|  | 
 | ||||||
|  |     InputEvent event; | ||||||
|  | 
 | ||||||
|  |     bool running = true; | ||||||
|  |     while(running) { | ||||||
|  |         if(furi_message_queue_get(event_queue, &event, 100) == FuriStatusOk) { | ||||||
|  |             if((event.type == InputTypePress) || (event.type == InputTypeRepeat)) { | ||||||
|  |                 switch(event.key) { | ||||||
|  |                 case InputKeyLeft: | ||||||
|  |                     image_position.x -= 2; | ||||||
|  |                     break; | ||||||
|  |                 case InputKeyRight: | ||||||
|  |                     image_position.x += 2; | ||||||
|  |                     break; | ||||||
|  |                 case InputKeyUp: | ||||||
|  |                     image_position.y -= 2; | ||||||
|  |                     break; | ||||||
|  |                 case InputKeyDown: | ||||||
|  |                     image_position.y += 2; | ||||||
|  |                     break; | ||||||
|  |                 default: | ||||||
|  |                     running = false; | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         view_port_update(view_port); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     view_port_enabled_set(view_port, false); | ||||||
|  |     gui_remove_view_port(gui, view_port); | ||||||
|  |     view_port_free(view_port); | ||||||
|  |     furi_message_queue_free(event_queue); | ||||||
|  | 
 | ||||||
|  |     furi_record_close(RECORD_GUI); | ||||||
|  | 
 | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
							
								
								
									
										
											BIN
										
									
								
								applications/examples/example_images/images/dolphin_71x25.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								applications/examples/example_images/images/dolphin_71x25.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 1.2 KiB | 
| @ -1,5 +1,4 @@ | |||||||
| #include "archive_i.h" | #include "archive_i.h" | ||||||
| #include "m-string.h" |  | ||||||
| 
 | 
 | ||||||
| bool archive_custom_event_callback(void* context, uint32_t event) { | bool archive_custom_event_callback(void* context, uint32_t event) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
| @ -18,7 +17,7 @@ ArchiveApp* archive_alloc() { | |||||||
| 
 | 
 | ||||||
|     archive->gui = furi_record_open(RECORD_GUI); |     archive->gui = furi_record_open(RECORD_GUI); | ||||||
|     archive->text_input = text_input_alloc(); |     archive->text_input = text_input_alloc(); | ||||||
|     string_init(archive->fav_move_str); |     archive->fav_move_str = furi_string_alloc(); | ||||||
| 
 | 
 | ||||||
|     archive->view_dispatcher = view_dispatcher_alloc(); |     archive->view_dispatcher = view_dispatcher_alloc(); | ||||||
|     archive->scene_manager = scene_manager_alloc(&archive_scene_handlers, archive); |     archive->scene_manager = scene_manager_alloc(&archive_scene_handlers, archive); | ||||||
| @ -58,7 +57,7 @@ void archive_free(ArchiveApp* archive) { | |||||||
|     view_dispatcher_free(archive->view_dispatcher); |     view_dispatcher_free(archive->view_dispatcher); | ||||||
|     scene_manager_free(archive->scene_manager); |     scene_manager_free(archive->scene_manager); | ||||||
|     browser_free(archive->browser); |     browser_free(archive->browser); | ||||||
|     string_clear(archive->fav_move_str); |     furi_string_free(archive->fav_move_str); | ||||||
| 
 | 
 | ||||||
|     text_input_free(archive->text_input); |     text_input_free(archive->text_input); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -28,7 +28,7 @@ struct ArchiveApp { | |||||||
|     TextInput* text_input; |     TextInput* text_input; | ||||||
|     Widget* widget; |     Widget* widget; | ||||||
|     FuriPubSubSubscription* loader_stop_subscription; |     FuriPubSubSubscription* loader_stop_subscription; | ||||||
|     string_t fav_move_str; |     FuriString* fav_move_str; | ||||||
|     char text_store[MAX_NAME_LEN]; |     char text_store[MAX_NAME_LEN]; | ||||||
|     char file_extension[MAX_EXT_LEN + 1]; |     char file_extension[MAX_EXT_LEN + 1]; | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -5,7 +5,7 @@ | |||||||
| #include <core/common_defines.h> | #include <core/common_defines.h> | ||||||
| #include <core/log.h> | #include <core/log.h> | ||||||
| #include "gui/modules/file_browser_worker.h" | #include "gui/modules/file_browser_worker.h" | ||||||
| #include "m-string.h" | #include <fap_loader/fap_loader_app.h> | ||||||
| #include <math.h> | #include <math.h> | ||||||
| 
 | 
 | ||||||
| static void | static void | ||||||
| @ -19,9 +19,11 @@ static void | |||||||
| 
 | 
 | ||||||
|     if((item_cnt == 0) && (archive_is_home(browser)) && (tab != ArchiveTabBrowser)) { |     if((item_cnt == 0) && (archive_is_home(browser)) && (tab != ArchiveTabBrowser)) { | ||||||
|         archive_switch_tab(browser, browser->last_tab_switch_dir); |         archive_switch_tab(browser, browser->last_tab_switch_dir); | ||||||
|     } else if(!string_start_with_str_p(browser->path, "/app:")) { |     } else if(!furi_string_start_with_str(browser->path, "/app:")) { | ||||||
|         with_view_model( |         with_view_model( | ||||||
|             browser->view, (ArchiveBrowserViewModel * model) { |             browser->view, | ||||||
|  |             ArchiveBrowserViewModel * model, | ||||||
|  |             { | ||||||
|                 files_array_reset(model->files); |                 files_array_reset(model->files); | ||||||
|                 model->item_cnt = item_cnt; |                 model->item_cnt = item_cnt; | ||||||
|                 model->item_idx = (file_idx > 0) ? file_idx : 0; |                 model->item_idx = (file_idx > 0) ? file_idx : 0; | ||||||
| @ -31,8 +33,8 @@ static void | |||||||
|                 model->list_offset = 0; |                 model->list_offset = 0; | ||||||
|                 model->list_loading = true; |                 model->list_loading = true; | ||||||
|                 model->folder_loading = false; |                 model->folder_loading = false; | ||||||
|                 return false; |             }, | ||||||
|             }); |             false); | ||||||
|         archive_update_offset(browser); |         archive_update_offset(browser); | ||||||
| 
 | 
 | ||||||
|         file_browser_worker_load(browser->worker, load_offset, FILE_LIST_BUF_LEN); |         file_browser_worker_load(browser->worker, load_offset, FILE_LIST_BUF_LEN); | ||||||
| @ -44,25 +46,25 @@ static void archive_list_load_cb(void* context, uint32_t list_load_offset) { | |||||||
|     ArchiveBrowserView* browser = (ArchiveBrowserView*)context; |     ArchiveBrowserView* browser = (ArchiveBrowserView*)context; | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         browser->view, (ArchiveBrowserViewModel * model) { |         browser->view, | ||||||
|  |         ArchiveBrowserViewModel * model, | ||||||
|  |         { | ||||||
|             files_array_reset(model->files); |             files_array_reset(model->files); | ||||||
|             model->array_offset = list_load_offset; |             model->array_offset = list_load_offset; | ||||||
|             return false; |         }, | ||||||
|         }); |         false); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void archive_list_item_cb(void* context, string_t item_path, bool is_folder, bool is_last) { | static void | ||||||
|  |     archive_list_item_cb(void* context, FuriString* item_path, bool is_folder, bool is_last) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     ArchiveBrowserView* browser = (ArchiveBrowserView*)context; |     ArchiveBrowserView* browser = (ArchiveBrowserView*)context; | ||||||
| 
 | 
 | ||||||
|     if(!is_last) { |     if(!is_last) { | ||||||
|         archive_add_file_item(browser, is_folder, string_get_cstr(item_path)); |         archive_add_file_item(browser, is_folder, furi_string_get_cstr(item_path)); | ||||||
|     } else { |     } else { | ||||||
|         with_view_model( |         with_view_model( | ||||||
|             browser->view, (ArchiveBrowserViewModel * model) { |             browser->view, ArchiveBrowserViewModel * model, { model->list_loading = false; }, true); | ||||||
|                 model->list_loading = false; |  | ||||||
|                 return true; |  | ||||||
|             }); |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -71,15 +73,12 @@ static void archive_long_load_cb(void* context) { | |||||||
|     ArchiveBrowserView* browser = (ArchiveBrowserView*)context; |     ArchiveBrowserView* browser = (ArchiveBrowserView*)context; | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         browser->view, (ArchiveBrowserViewModel * model) { |         browser->view, ArchiveBrowserViewModel * model, { model->folder_loading = true; }, true); | ||||||
|             model->folder_loading = true; |  | ||||||
|             return true; |  | ||||||
|         }); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void archive_file_browser_set_path( | static void archive_file_browser_set_path( | ||||||
|     ArchiveBrowserView* browser, |     ArchiveBrowserView* browser, | ||||||
|     string_t path, |     FuriString* path, | ||||||
|     const char* filter_ext, |     const char* filter_ext, | ||||||
|     bool skip_assets) { |     bool skip_assets) { | ||||||
|     furi_assert(browser); |     furi_assert(browser); | ||||||
| @ -112,7 +111,9 @@ void archive_update_offset(ArchiveBrowserView* browser) { | |||||||
|     furi_assert(browser); |     furi_assert(browser); | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         browser->view, (ArchiveBrowserViewModel * model) { |         browser->view, | ||||||
|  |         ArchiveBrowserViewModel * model, | ||||||
|  |         { | ||||||
|             uint16_t bounds = model->item_cnt > 3 ? 2 : model->item_cnt; |             uint16_t bounds = model->item_cnt > 3 ? 2 : model->item_cnt; | ||||||
| 
 | 
 | ||||||
|             if((model->item_cnt > 3u) && (model->item_idx >= ((int32_t)model->item_cnt - 1))) { |             if((model->item_cnt > 3u) && (model->item_idx >= ((int32_t)model->item_cnt - 1))) { | ||||||
| @ -124,33 +125,34 @@ void archive_update_offset(ArchiveBrowserView* browser) { | |||||||
|                 model->list_offset = |                 model->list_offset = | ||||||
|                     CLAMP(model->item_idx - 1, (int32_t)model->item_cnt - bounds, 0); |                     CLAMP(model->item_idx - 1, (int32_t)model->item_cnt - bounds, 0); | ||||||
|             } |             } | ||||||
| 
 |         }, | ||||||
|             return true; |         true); | ||||||
|         }); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void archive_update_focus(ArchiveBrowserView* browser, const char* target) { | void archive_update_focus(ArchiveBrowserView* browser, const char* target) { | ||||||
|     furi_assert(browser); |     furi_assert(browser); | ||||||
|     furi_assert(target); |     furi_assert(target); | ||||||
| 
 | 
 | ||||||
|     archive_get_items(browser, string_get_cstr(browser->path)); |     archive_get_items(browser, furi_string_get_cstr(browser->path)); | ||||||
| 
 | 
 | ||||||
|     if(!archive_file_get_array_size(browser) && archive_is_home(browser)) { |     if(!archive_file_get_array_size(browser) && archive_is_home(browser)) { | ||||||
|         archive_switch_tab(browser, TAB_RIGHT); |         archive_switch_tab(browser, TAB_RIGHT); | ||||||
|     } else { |     } else { | ||||||
|         with_view_model( |         with_view_model( | ||||||
|             browser->view, (ArchiveBrowserViewModel * model) { |             browser->view, | ||||||
|  |             ArchiveBrowserViewModel * model, | ||||||
|  |             { | ||||||
|                 uint16_t idx = 0; |                 uint16_t idx = 0; | ||||||
|                 while(idx < files_array_size(model->files)) { |                 while(idx < files_array_size(model->files)) { | ||||||
|                     ArchiveFile_t* current = files_array_get(model->files, idx); |                     ArchiveFile_t* current = files_array_get(model->files, idx); | ||||||
|                     if(!string_search(current->path, target)) { |                     if(!furi_string_search(current->path, target)) { | ||||||
|                         model->item_idx = idx + model->array_offset; |                         model->item_idx = idx + model->array_offset; | ||||||
|                         break; |                         break; | ||||||
|                     } |                     } | ||||||
|                     ++idx; |                     ++idx; | ||||||
|                 } |                 } | ||||||
|                 return false; |             }, | ||||||
|             }); |             false); | ||||||
| 
 | 
 | ||||||
|         archive_update_offset(browser); |         archive_update_offset(browser); | ||||||
|     } |     } | ||||||
| @ -161,10 +163,10 @@ size_t archive_file_get_array_size(ArchiveBrowserView* browser) { | |||||||
| 
 | 
 | ||||||
|     uint16_t size = 0; |     uint16_t size = 0; | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         browser->view, (ArchiveBrowserViewModel * model) { |         browser->view, | ||||||
|             size = files_array_size(model->files); |         ArchiveBrowserViewModel * model, | ||||||
|             return false; |         { size = files_array_size(model->files); }, | ||||||
|         }); |         false); | ||||||
|     return size; |     return size; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -172,11 +174,13 @@ void archive_set_item_count(ArchiveBrowserView* browser, uint32_t count) { | |||||||
|     furi_assert(browser); |     furi_assert(browser); | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         browser->view, (ArchiveBrowserViewModel * model) { |         browser->view, | ||||||
|  |         ArchiveBrowserViewModel * model, | ||||||
|  |         { | ||||||
|             model->item_cnt = count; |             model->item_cnt = count; | ||||||
|             model->item_idx = CLAMP(model->item_idx, (int32_t)model->item_cnt - 1, 0); |             model->item_idx = CLAMP(model->item_idx, (int32_t)model->item_cnt - 1, 0); | ||||||
|             return false; |         }, | ||||||
|         }); |         false); | ||||||
|     archive_update_offset(browser); |     archive_update_offset(browser); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -185,7 +189,9 @@ void archive_file_array_rm_selected(ArchiveBrowserView* browser) { | |||||||
|     uint32_t items_cnt = 0; |     uint32_t items_cnt = 0; | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         browser->view, (ArchiveBrowserViewModel * model) { |         browser->view, | ||||||
|  |         ArchiveBrowserViewModel * model, | ||||||
|  |         { | ||||||
|             files_array_remove_v( |             files_array_remove_v( | ||||||
|                 model->files, |                 model->files, | ||||||
|                 model->item_idx - model->array_offset, |                 model->item_idx - model->array_offset, | ||||||
| @ -193,8 +199,8 @@ void archive_file_array_rm_selected(ArchiveBrowserView* browser) { | |||||||
|             model->item_cnt--; |             model->item_cnt--; | ||||||
|             model->item_idx = CLAMP(model->item_idx, (int32_t)model->item_cnt - 1, 0); |             model->item_idx = CLAMP(model->item_idx, (int32_t)model->item_cnt - 1, 0); | ||||||
|             items_cnt = model->item_cnt; |             items_cnt = model->item_cnt; | ||||||
|             return false; |         }, | ||||||
|         }); |         false); | ||||||
| 
 | 
 | ||||||
|     if((items_cnt == 0) && (archive_is_home(browser))) { |     if((items_cnt == 0) && (archive_is_home(browser))) { | ||||||
|         archive_switch_tab(browser, TAB_RIGHT); |         archive_switch_tab(browser, TAB_RIGHT); | ||||||
| @ -207,7 +213,9 @@ void archive_file_array_swap(ArchiveBrowserView* browser, int8_t dir) { | |||||||
|     furi_assert(browser); |     furi_assert(browser); | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         browser->view, (ArchiveBrowserViewModel * model) { |         browser->view, | ||||||
|  |         ArchiveBrowserViewModel * model, | ||||||
|  |         { | ||||||
|             ArchiveFile_t temp; |             ArchiveFile_t temp; | ||||||
|             size_t array_size = files_array_size(model->files) - 1; |             size_t array_size = files_array_size(model->files) - 1; | ||||||
|             uint8_t swap_idx = CLAMP((size_t)(model->item_idx + dir), array_size, 0u); |             uint8_t swap_idx = CLAMP((size_t)(model->item_idx + dir), array_size, 0u); | ||||||
| @ -225,18 +233,18 @@ void archive_file_array_swap(ArchiveBrowserView* browser, int8_t dir) { | |||||||
|             } else { |             } else { | ||||||
|                 files_array_swap_at(model->files, model->item_idx, swap_idx); |                 files_array_swap_at(model->files, model->item_idx, swap_idx); | ||||||
|             } |             } | ||||||
|             return false; |         }, | ||||||
|         }); |         false); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void archive_file_array_rm_all(ArchiveBrowserView* browser) { | void archive_file_array_rm_all(ArchiveBrowserView* browser) { | ||||||
|     furi_assert(browser); |     furi_assert(browser); | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         browser->view, (ArchiveBrowserViewModel * model) { |         browser->view, | ||||||
|             files_array_reset(model->files); |         ArchiveBrowserViewModel * model, | ||||||
|             return false; |         { files_array_reset(model->files); }, | ||||||
|         }); |         false); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void archive_file_array_load(ArchiveBrowserView* browser, int8_t dir) { | void archive_file_array_load(ArchiveBrowserView* browser, int8_t dir) { | ||||||
| @ -245,7 +253,9 @@ void archive_file_array_load(ArchiveBrowserView* browser, int8_t dir) { | |||||||
|     int32_t offset_new = 0; |     int32_t offset_new = 0; | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         browser->view, (ArchiveBrowserViewModel * model) { |         browser->view, | ||||||
|  |         ArchiveBrowserViewModel * model, | ||||||
|  |         { | ||||||
|             if(model->item_cnt > FILE_LIST_BUF_LEN) { |             if(model->item_cnt > FILE_LIST_BUF_LEN) { | ||||||
|                 if(dir < 0) { |                 if(dir < 0) { | ||||||
|                     offset_new = model->item_idx - FILE_LIST_BUF_LEN / 4 * 3; |                     offset_new = model->item_idx - FILE_LIST_BUF_LEN / 4 * 3; | ||||||
| @ -261,8 +271,8 @@ void archive_file_array_load(ArchiveBrowserView* browser, int8_t dir) { | |||||||
|                     offset_new = 0; |                     offset_new = 0; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             return false; |         }, | ||||||
|         }); |         false); | ||||||
| 
 | 
 | ||||||
|     file_browser_worker_load(browser->worker, offset_new, FILE_LIST_BUF_LEN); |     file_browser_worker_load(browser->worker, offset_new, FILE_LIST_BUF_LEN); | ||||||
| } | } | ||||||
| @ -272,12 +282,14 @@ ArchiveFile_t* archive_get_current_file(ArchiveBrowserView* browser) { | |||||||
| 
 | 
 | ||||||
|     ArchiveFile_t* selected = NULL; |     ArchiveFile_t* selected = NULL; | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         browser->view, (ArchiveBrowserViewModel * model) { |         browser->view, | ||||||
|  |         ArchiveBrowserViewModel * model, | ||||||
|  |         { | ||||||
|             selected = files_array_size(model->files) ? |             selected = files_array_size(model->files) ? | ||||||
|                            files_array_get(model->files, model->item_idx - model->array_offset) : |                            files_array_get(model->files, model->item_idx - model->array_offset) : | ||||||
|                            NULL; |                            NULL; | ||||||
|             return false; |         }, | ||||||
|         }); |         false); | ||||||
|     return selected; |     return selected; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -287,11 +299,13 @@ ArchiveFile_t* archive_get_file_at(ArchiveBrowserView* browser, size_t idx) { | |||||||
|     ArchiveFile_t* selected = NULL; |     ArchiveFile_t* selected = NULL; | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         browser->view, (ArchiveBrowserViewModel * model) { |         browser->view, | ||||||
|  |         ArchiveBrowserViewModel * model, | ||||||
|  |         { | ||||||
|             idx = CLAMP(idx - model->array_offset, files_array_size(model->files), 0u); |             idx = CLAMP(idx - model->array_offset, files_array_size(model->files), 0u); | ||||||
|             selected = files_array_size(model->files) ? files_array_get(model->files, idx) : NULL; |             selected = files_array_size(model->files) ? files_array_get(model->files, idx) : NULL; | ||||||
|             return false; |         }, | ||||||
|         }); |         false); | ||||||
|     return selected; |     return selected; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -300,10 +314,7 @@ ArchiveTabEnum archive_get_tab(ArchiveBrowserView* browser) { | |||||||
| 
 | 
 | ||||||
|     ArchiveTabEnum tab_id = 0; |     ArchiveTabEnum tab_id = 0; | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         browser->view, (ArchiveBrowserViewModel * model) { |         browser->view, ArchiveBrowserViewModel * model, { tab_id = model->tab_idx; }, false); | ||||||
|             tab_id = model->tab_idx; |  | ||||||
|             return false; |  | ||||||
|         }); |  | ||||||
|     return tab_id; |     return tab_id; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -315,22 +326,19 @@ bool archive_is_home(ArchiveBrowserView* browser) { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     const char* default_path = archive_get_default_path(archive_get_tab(browser)); |     const char* default_path = archive_get_default_path(archive_get_tab(browser)); | ||||||
|     return (string_cmp_str(browser->path, default_path) == 0); |     return (furi_string_cmp_str(browser->path, default_path) == 0); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const char* archive_get_name(ArchiveBrowserView* browser) { | const char* archive_get_name(ArchiveBrowserView* browser) { | ||||||
|     ArchiveFile_t* selected = archive_get_current_file(browser); |     ArchiveFile_t* selected = archive_get_current_file(browser); | ||||||
|     return string_get_cstr(selected->path); |     return furi_string_get_cstr(selected->path); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void archive_set_tab(ArchiveBrowserView* browser, ArchiveTabEnum tab) { | void archive_set_tab(ArchiveBrowserView* browser, ArchiveTabEnum tab) { | ||||||
|     furi_assert(browser); |     furi_assert(browser); | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         browser->view, (ArchiveBrowserViewModel * model) { |         browser->view, ArchiveBrowserViewModel * model, { model->tab_idx = tab; }, false); | ||||||
|             model->tab_idx = tab; |  | ||||||
|             return false; |  | ||||||
|         }); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void archive_add_app_item(ArchiveBrowserView* browser, const char* name) { | void archive_add_app_item(ArchiveBrowserView* browser, const char* name) { | ||||||
| @ -339,75 +347,92 @@ void archive_add_app_item(ArchiveBrowserView* browser, const char* name) { | |||||||
| 
 | 
 | ||||||
|     ArchiveFile_t item; |     ArchiveFile_t item; | ||||||
|     ArchiveFile_t_init(&item); |     ArchiveFile_t_init(&item); | ||||||
|     string_set_str(item.path, name); |     furi_string_set(item.path, name); | ||||||
|     archive_set_file_type(&item, name, false, true); |     archive_set_file_type(&item, name, false, true); | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         browser->view, (ArchiveBrowserViewModel * model) { |         browser->view, | ||||||
|  |         ArchiveBrowserViewModel * model, | ||||||
|  |         { | ||||||
|             files_array_push_back(model->files, item); |             files_array_push_back(model->files, item); | ||||||
|             model->item_cnt = files_array_size(model->files); |             model->item_cnt = files_array_size(model->files); | ||||||
|             return false; |         }, | ||||||
|         }); |         false); | ||||||
|     ArchiveFile_t_clear(&item); |     ArchiveFile_t_clear(&item); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static bool archive_get_fap_meta(FuriString* file_path, FuriString* fap_name, uint8_t** icon_ptr) { | ||||||
|  |     Storage* storage = furi_record_open(RECORD_STORAGE); | ||||||
|  |     bool success = false; | ||||||
|  |     if(fap_loader_load_name_and_icon(file_path, storage, icon_ptr, fap_name)) { | ||||||
|  |         success = true; | ||||||
|  |     } | ||||||
|  |     furi_record_close(RECORD_STORAGE); | ||||||
|  |     return success; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void archive_add_file_item(ArchiveBrowserView* browser, bool is_folder, const char* name) { | void archive_add_file_item(ArchiveBrowserView* browser, bool is_folder, const char* name) { | ||||||
|     furi_assert(browser); |     furi_assert(browser); | ||||||
|     furi_assert(name); |     furi_assert(name); | ||||||
| 
 | 
 | ||||||
|     ArchiveFile_t item; |     ArchiveFile_t item; | ||||||
| 
 |  | ||||||
|     ArchiveFile_t_init(&item); |     ArchiveFile_t_init(&item); | ||||||
|     string_init_set_str(item.path, name); |  | ||||||
|     archive_set_file_type(&item, string_get_cstr(browser->path), is_folder, false); |  | ||||||
| 
 | 
 | ||||||
|  |     furi_string_set(item.path, name); | ||||||
|  |     archive_set_file_type(&item, furi_string_get_cstr(browser->path), is_folder, false); | ||||||
|  |     if(item.type == ArchiveFileTypeApplication) { | ||||||
|  |         item.custom_icon_data = malloc(FAP_MANIFEST_MAX_ICON_SIZE); | ||||||
|  |         if(!archive_get_fap_meta(item.path, item.custom_name, &item.custom_icon_data)) { | ||||||
|  |             free(item.custom_icon_data); | ||||||
|  |             item.custom_icon_data = NULL; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         browser->view, (ArchiveBrowserViewModel * model) { |         browser->view, | ||||||
|             files_array_push_back(model->files, item); |         ArchiveBrowserViewModel * model, | ||||||
|             return false; |         { files_array_push_back(model->files, item); }, | ||||||
|         }); |         false); | ||||||
|     ArchiveFile_t_clear(&item); |     ArchiveFile_t_clear(&item); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void archive_show_file_menu(ArchiveBrowserView* browser, bool show) { | void archive_show_file_menu(ArchiveBrowserView* browser, bool show) { | ||||||
|     furi_assert(browser); |     furi_assert(browser); | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         browser->view, (ArchiveBrowserViewModel * model) { |         browser->view, | ||||||
|  |         ArchiveBrowserViewModel * model, | ||||||
|  |         { | ||||||
|             if(show) { |             if(show) { | ||||||
|                 if(archive_is_item_in_array(model, model->item_idx)) { |                 if(archive_is_item_in_array(model, model->item_idx)) { | ||||||
|                     model->menu = true; |                     model->menu = true; | ||||||
|                     model->menu_idx = 0; |                     model->menu_idx = 0; | ||||||
|                     ArchiveFile_t* selected = |                     ArchiveFile_t* selected = | ||||||
|                         files_array_get(model->files, model->item_idx - model->array_offset); |                         files_array_get(model->files, model->item_idx - model->array_offset); | ||||||
|                     selected->fav = archive_is_favorite("%s", string_get_cstr(selected->path)); |                     selected->fav = | ||||||
|  |                         archive_is_favorite("%s", furi_string_get_cstr(selected->path)); | ||||||
|                 } |                 } | ||||||
|             } else { |             } else { | ||||||
|                 model->menu = false; |                 model->menu = false; | ||||||
|                 model->menu_idx = 0; |                 model->menu_idx = 0; | ||||||
|             } |             } | ||||||
| 
 |         }, | ||||||
|             return true; |         true); | ||||||
|         }); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void archive_favorites_move_mode(ArchiveBrowserView* browser, bool active) { | void archive_favorites_move_mode(ArchiveBrowserView* browser, bool active) { | ||||||
|     furi_assert(browser); |     furi_assert(browser); | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         browser->view, (ArchiveBrowserViewModel * model) { |         browser->view, ArchiveBrowserViewModel * model, { model->move_fav = active; }, true); | ||||||
|             model->move_fav = active; |  | ||||||
|             return true; |  | ||||||
|         }); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static bool archive_is_dir_exists(string_t path) { | static bool archive_is_dir_exists(FuriString* path) { | ||||||
|     if(string_equal_str_p(path, STORAGE_ANY_PATH_PREFIX)) { |     if(furi_string_equal(path, STORAGE_ANY_PATH_PREFIX)) { | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
|     bool state = false; |     bool state = false; | ||||||
|     FileInfo file_info; |     FileInfo file_info; | ||||||
|     Storage* storage = furi_record_open(RECORD_STORAGE); |     Storage* storage = furi_record_open(RECORD_STORAGE); | ||||||
|     if(storage_common_stat(storage, string_get_cstr(path), &file_info) == FSE_OK) { |     if(storage_common_stat(storage, furi_string_get_cstr(path), &file_info) == FSE_OK) { | ||||||
|         if(file_info.flags & FSF_DIRECTORY) { |         if(file_info.flags & FSF_DIRECTORY) { | ||||||
|             state = true; |             state = true; | ||||||
|         } |         } | ||||||
| @ -431,16 +456,16 @@ void archive_switch_tab(ArchiveBrowserView* browser, InputKey key) { | |||||||
|     browser->is_root = true; |     browser->is_root = true; | ||||||
|     archive_set_tab(browser, tab); |     archive_set_tab(browser, tab); | ||||||
| 
 | 
 | ||||||
|     string_set_str(browser->path, archive_get_default_path(tab)); |     furi_string_set(browser->path, archive_get_default_path(tab)); | ||||||
|     bool tab_empty = true; |     bool tab_empty = true; | ||||||
|     if(tab == ArchiveTabFavorites) { |     if(tab == ArchiveTabFavorites) { | ||||||
|         if(archive_favorites_count(browser) > 0) { |         if(archive_favorites_count(browser) > 0) { | ||||||
|             tab_empty = false; |             tab_empty = false; | ||||||
|         } |         } | ||||||
|     } else if(string_start_with_str_p(browser->path, "/app:")) { |     } else if(furi_string_start_with_str(browser->path, "/app:")) { | ||||||
|         char* app_name = strchr(string_get_cstr(browser->path), ':'); |         char* app_name = strchr(furi_string_get_cstr(browser->path), ':'); | ||||||
|         if(app_name != NULL) { |         if(app_name != NULL) { | ||||||
|             if(archive_app_is_available(browser, string_get_cstr(browser->path))) { |             if(archive_app_is_available(browser, furi_string_get_cstr(browser->path))) { | ||||||
|                 tab_empty = false; |                 tab_empty = false; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| @ -458,29 +483,28 @@ void archive_switch_tab(ArchiveBrowserView* browser, InputKey key) { | |||||||
|         archive_switch_tab(browser, key); |         archive_switch_tab(browser, key); | ||||||
|     } else { |     } else { | ||||||
|         with_view_model( |         with_view_model( | ||||||
|             browser->view, (ArchiveBrowserViewModel * model) { |             browser->view, | ||||||
|  |             ArchiveBrowserViewModel * model, | ||||||
|  |             { | ||||||
|                 model->item_idx = 0; |                 model->item_idx = 0; | ||||||
|                 model->array_offset = 0; |                 model->array_offset = 0; | ||||||
|                 return false; |             }, | ||||||
|             }); |             false); | ||||||
|         archive_get_items(browser, string_get_cstr(browser->path)); |         archive_get_items(browser, furi_string_get_cstr(browser->path)); | ||||||
|         archive_update_offset(browser); |         archive_update_offset(browser); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void archive_enter_dir(ArchiveBrowserView* browser, string_t path) { | void archive_enter_dir(ArchiveBrowserView* browser, FuriString* path) { | ||||||
|     furi_assert(browser); |     furi_assert(browser); | ||||||
|     furi_assert(path); |     furi_assert(path); | ||||||
| 
 | 
 | ||||||
|     int32_t idx_temp = 0; |     int32_t idx_temp = 0; | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         browser->view, (ArchiveBrowserViewModel * model) { |         browser->view, ArchiveBrowserViewModel * model, { idx_temp = model->item_idx; }, false); | ||||||
|             idx_temp = model->item_idx; |  | ||||||
|             return false; |  | ||||||
|         }); |  | ||||||
| 
 | 
 | ||||||
|     string_set(browser->path, path); |     furi_string_set(browser->path, path); | ||||||
|     file_browser_worker_folder_enter(browser->worker, path, idx_temp); |     file_browser_worker_folder_enter(browser->worker, path, idx_temp); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -496,9 +520,6 @@ void archive_refresh_dir(ArchiveBrowserView* browser) { | |||||||
|     int32_t idx_temp = 0; |     int32_t idx_temp = 0; | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         browser->view, (ArchiveBrowserViewModel * model) { |         browser->view, ArchiveBrowserViewModel * model, { idx_temp = model->item_idx; }, false); | ||||||
|             idx_temp = model->item_idx; |  | ||||||
|             return false; |  | ||||||
|         }); |  | ||||||
|     file_browser_worker_folder_refresh(browser->worker, idx_temp); |     file_browser_worker_folder_refresh(browser->worker, idx_temp); | ||||||
| } | } | ||||||
|  | |||||||
| @ -16,6 +16,7 @@ static const char* tab_default_paths[] = { | |||||||
|     [ArchiveTabInfrared] = ANY_PATH("infrared"), |     [ArchiveTabInfrared] = ANY_PATH("infrared"), | ||||||
|     [ArchiveTabBadUsb] = ANY_PATH("badusb"), |     [ArchiveTabBadUsb] = ANY_PATH("badusb"), | ||||||
|     [ArchiveTabU2f] = "/app:u2f", |     [ArchiveTabU2f] = "/app:u2f", | ||||||
|  |     [ArchiveTabApplications] = ANY_PATH("apps"), | ||||||
|     [ArchiveTabBrowser] = STORAGE_ANY_PATH_PREFIX, |     [ArchiveTabBrowser] = STORAGE_ANY_PATH_PREFIX, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| @ -27,6 +28,7 @@ static const char* known_ext[] = { | |||||||
|     [ArchiveFileTypeInfrared] = ".ir", |     [ArchiveFileTypeInfrared] = ".ir", | ||||||
|     [ArchiveFileTypeBadUsb] = ".txt", |     [ArchiveFileTypeBadUsb] = ".txt", | ||||||
|     [ArchiveFileTypeU2f] = "?", |     [ArchiveFileTypeU2f] = "?", | ||||||
|  |     [ArchiveFileTypeApplication] = ".fap", | ||||||
|     [ArchiveFileTypeUpdateManifest] = ".fuf", |     [ArchiveFileTypeUpdateManifest] = ".fuf", | ||||||
|     [ArchiveFileTypeFolder] = "?", |     [ArchiveFileTypeFolder] = "?", | ||||||
|     [ArchiveFileTypeUnknown] = "*", |     [ArchiveFileTypeUnknown] = "*", | ||||||
| @ -41,6 +43,7 @@ static const ArchiveFileTypeEnum known_type[] = { | |||||||
|     [ArchiveTabInfrared] = ArchiveFileTypeInfrared, |     [ArchiveTabInfrared] = ArchiveFileTypeInfrared, | ||||||
|     [ArchiveTabBadUsb] = ArchiveFileTypeBadUsb, |     [ArchiveTabBadUsb] = ArchiveFileTypeBadUsb, | ||||||
|     [ArchiveTabU2f] = ArchiveFileTypeU2f, |     [ArchiveTabU2f] = ArchiveFileTypeU2f, | ||||||
|  |     [ArchiveTabApplications] = ArchiveFileTypeApplication, | ||||||
|     [ArchiveTabBrowser] = ArchiveFileTypeUnknown, |     [ArchiveTabBrowser] = ArchiveFileTypeUnknown, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| @ -84,6 +87,6 @@ void archive_show_file_menu(ArchiveBrowserView* browser, bool show); | |||||||
| void archive_favorites_move_mode(ArchiveBrowserView* browser, bool active); | void archive_favorites_move_mode(ArchiveBrowserView* browser, bool active); | ||||||
| 
 | 
 | ||||||
| void archive_switch_tab(ArchiveBrowserView* browser, InputKey key); | void archive_switch_tab(ArchiveBrowserView* browser, InputKey key); | ||||||
| void archive_enter_dir(ArchiveBrowserView* browser, string_t name); | void archive_enter_dir(ArchiveBrowserView* browser, FuriString* name); | ||||||
| void archive_leave_dir(ArchiveBrowserView* browser); | void archive_leave_dir(ArchiveBrowserView* browser); | ||||||
| void archive_refresh_dir(ArchiveBrowserView* browser); | void archive_refresh_dir(ArchiveBrowserView* browser); | ||||||
|  | |||||||
| @ -6,8 +6,8 @@ | |||||||
| 
 | 
 | ||||||
| #define ARCHIVE_FAV_FILE_BUF_LEN 32 | #define ARCHIVE_FAV_FILE_BUF_LEN 32 | ||||||
| 
 | 
 | ||||||
| static bool archive_favorites_read_line(File* file, string_t str_result) { | static bool archive_favorites_read_line(File* file, FuriString* str_result) { | ||||||
|     string_reset(str_result); |     furi_string_reset(str_result); | ||||||
|     uint8_t buffer[ARCHIVE_FAV_FILE_BUF_LEN]; |     uint8_t buffer[ARCHIVE_FAV_FILE_BUF_LEN]; | ||||||
|     bool result = false; |     bool result = false; | ||||||
| 
 | 
 | ||||||
| @ -34,7 +34,7 @@ static bool archive_favorites_read_line(File* file, string_t str_result) { | |||||||
|                 result = true; |                 result = true; | ||||||
|                 break; |                 break; | ||||||
|             } else { |             } else { | ||||||
|                 string_push_back(str_result, buffer[i]); |                 furi_string_push_back(str_result, buffer[i]); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| @ -52,8 +52,8 @@ uint16_t archive_favorites_count(void* context) { | |||||||
|     Storage* fs_api = furi_record_open(RECORD_STORAGE); |     Storage* fs_api = furi_record_open(RECORD_STORAGE); | ||||||
|     File* file = storage_file_alloc(fs_api); |     File* file = storage_file_alloc(fs_api); | ||||||
| 
 | 
 | ||||||
|     string_t buffer; |     FuriString* buffer; | ||||||
|     string_init(buffer); |     buffer = furi_string_alloc(); | ||||||
| 
 | 
 | ||||||
|     bool result = storage_file_open(file, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING); |     bool result = storage_file_open(file, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING); | ||||||
|     uint16_t lines = 0; |     uint16_t lines = 0; | ||||||
| @ -63,7 +63,7 @@ uint16_t archive_favorites_count(void* context) { | |||||||
|             if(!archive_favorites_read_line(file, buffer)) { |             if(!archive_favorites_read_line(file, buffer)) { | ||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
|             if(!string_size(buffer)) { |             if(!furi_string_size(buffer)) { | ||||||
|                 continue; // Skip empty lines
 |                 continue; // Skip empty lines
 | ||||||
|             } |             } | ||||||
|             ++lines; |             ++lines; | ||||||
| @ -72,7 +72,7 @@ uint16_t archive_favorites_count(void* context) { | |||||||
| 
 | 
 | ||||||
|     storage_file_close(file); |     storage_file_close(file); | ||||||
| 
 | 
 | ||||||
|     string_clear(buffer); |     furi_string_free(buffer); | ||||||
|     storage_file_free(file); |     storage_file_free(file); | ||||||
|     furi_record_close(RECORD_STORAGE); |     furi_record_close(RECORD_STORAGE); | ||||||
| 
 | 
 | ||||||
| @ -80,8 +80,8 @@ uint16_t archive_favorites_count(void* context) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static bool archive_favourites_rescan() { | static bool archive_favourites_rescan() { | ||||||
|     string_t buffer; |     FuriString* buffer; | ||||||
|     string_init(buffer); |     buffer = furi_string_alloc(); | ||||||
|     Storage* storage = furi_record_open(RECORD_STORAGE); |     Storage* storage = furi_record_open(RECORD_STORAGE); | ||||||
|     File* file = storage_file_alloc(storage); |     File* file = storage_file_alloc(storage); | ||||||
| 
 | 
 | ||||||
| @ -91,23 +91,25 @@ static bool archive_favourites_rescan() { | |||||||
|             if(!archive_favorites_read_line(file, buffer)) { |             if(!archive_favorites_read_line(file, buffer)) { | ||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
|             if(!string_size(buffer)) { |             if(!furi_string_size(buffer)) { | ||||||
|                 continue; |                 continue; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             if(string_search(buffer, "/app:") == 0) { |             if(furi_string_search(buffer, "/app:") == 0) { | ||||||
|                 if(archive_app_is_available(NULL, string_get_cstr(buffer))) { |                 if(archive_app_is_available(NULL, furi_string_get_cstr(buffer))) { | ||||||
|                     archive_file_append(ARCHIVE_FAV_TEMP_PATH, "%s\n", string_get_cstr(buffer)); |                     archive_file_append( | ||||||
|  |                         ARCHIVE_FAV_TEMP_PATH, "%s\n", furi_string_get_cstr(buffer)); | ||||||
|                 } |                 } | ||||||
|             } else { |             } else { | ||||||
|                 if(storage_file_exists(storage, string_get_cstr(buffer))) { |                 if(storage_file_exists(storage, furi_string_get_cstr(buffer))) { | ||||||
|                     archive_file_append(ARCHIVE_FAV_TEMP_PATH, "%s\n", string_get_cstr(buffer)); |                     archive_file_append( | ||||||
|  |                         ARCHIVE_FAV_TEMP_PATH, "%s\n", furi_string_get_cstr(buffer)); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     string_clear(buffer); |     furi_string_free(buffer); | ||||||
| 
 | 
 | ||||||
|     storage_file_close(file); |     storage_file_close(file); | ||||||
|     storage_common_remove(storage, ARCHIVE_FAV_PATH); |     storage_common_remove(storage, ARCHIVE_FAV_PATH); | ||||||
| @ -127,9 +129,9 @@ bool archive_favorites_read(void* context) { | |||||||
|     Storage* storage = furi_record_open(RECORD_STORAGE); |     Storage* storage = furi_record_open(RECORD_STORAGE); | ||||||
|     File* file = storage_file_alloc(storage); |     File* file = storage_file_alloc(storage); | ||||||
| 
 | 
 | ||||||
|     string_t buffer; |     FuriString* buffer; | ||||||
|     FileInfo file_info; |     FileInfo file_info; | ||||||
|     string_init(buffer); |     buffer = furi_string_alloc(); | ||||||
| 
 | 
 | ||||||
|     bool need_refresh = false; |     bool need_refresh = false; | ||||||
|     uint16_t file_count = 0; |     uint16_t file_count = 0; | ||||||
| @ -143,33 +145,33 @@ bool archive_favorites_read(void* context) { | |||||||
|             if(!archive_favorites_read_line(file, buffer)) { |             if(!archive_favorites_read_line(file, buffer)) { | ||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
|             if(!string_size(buffer)) { |             if(!furi_string_size(buffer)) { | ||||||
|                 continue; |                 continue; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             if(string_search(buffer, "/app:") == 0) { |             if(furi_string_search(buffer, "/app:") == 0) { | ||||||
|                 if(archive_app_is_available(browser, string_get_cstr(buffer))) { |                 if(archive_app_is_available(browser, furi_string_get_cstr(buffer))) { | ||||||
|                     archive_add_app_item(browser, string_get_cstr(buffer)); |                     archive_add_app_item(browser, furi_string_get_cstr(buffer)); | ||||||
|                     file_count++; |                     file_count++; | ||||||
|                 } else { |                 } else { | ||||||
|                     need_refresh = true; |                     need_refresh = true; | ||||||
|                 } |                 } | ||||||
|             } else { |             } else { | ||||||
|                 if(storage_file_exists(storage, string_get_cstr(buffer))) { |                 if(storage_file_exists(storage, furi_string_get_cstr(buffer))) { | ||||||
|                     storage_common_stat(storage, string_get_cstr(buffer), &file_info); |                     storage_common_stat(storage, furi_string_get_cstr(buffer), &file_info); | ||||||
|                     archive_add_file_item( |                     archive_add_file_item( | ||||||
|                         browser, (file_info.flags & FSF_DIRECTORY), string_get_cstr(buffer)); |                         browser, (file_info.flags & FSF_DIRECTORY), furi_string_get_cstr(buffer)); | ||||||
|                     file_count++; |                     file_count++; | ||||||
|                 } else { |                 } else { | ||||||
|                     need_refresh = true; |                     need_refresh = true; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             string_reset(buffer); |             furi_string_reset(buffer); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     storage_file_close(file); |     storage_file_close(file); | ||||||
|     string_clear(buffer); |     furi_string_free(buffer); | ||||||
|     storage_file_free(file); |     storage_file_free(file); | ||||||
|     furi_record_close(RECORD_STORAGE); |     furi_record_close(RECORD_STORAGE); | ||||||
| 
 | 
 | ||||||
| @ -183,14 +185,14 @@ bool archive_favorites_read(void* context) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool archive_favorites_delete(const char* format, ...) { | bool archive_favorites_delete(const char* format, ...) { | ||||||
|     string_t buffer; |     FuriString* buffer; | ||||||
|     string_t filename; |     FuriString* filename; | ||||||
|     va_list args; |     va_list args; | ||||||
|     va_start(args, format); |     va_start(args, format); | ||||||
|     string_init_vprintf(filename, format, args); |     filename = furi_string_alloc_vprintf(format, args); | ||||||
|     va_end(args); |     va_end(args); | ||||||
| 
 | 
 | ||||||
|     string_init(buffer); |     buffer = furi_string_alloc(); | ||||||
|     Storage* fs_api = furi_record_open(RECORD_STORAGE); |     Storage* fs_api = furi_record_open(RECORD_STORAGE); | ||||||
|     File* file = storage_file_alloc(fs_api); |     File* file = storage_file_alloc(fs_api); | ||||||
| 
 | 
 | ||||||
| @ -201,18 +203,18 @@ bool archive_favorites_delete(const char* format, ...) { | |||||||
|             if(!archive_favorites_read_line(file, buffer)) { |             if(!archive_favorites_read_line(file, buffer)) { | ||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
|             if(!string_size(buffer)) { |             if(!furi_string_size(buffer)) { | ||||||
|                 continue; |                 continue; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             if(string_search(buffer, filename)) { |             if(furi_string_search(buffer, filename)) { | ||||||
|                 archive_file_append(ARCHIVE_FAV_TEMP_PATH, "%s\n", string_get_cstr(buffer)); |                 archive_file_append(ARCHIVE_FAV_TEMP_PATH, "%s\n", furi_string_get_cstr(buffer)); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     string_clear(buffer); |     furi_string_free(buffer); | ||||||
|     string_clear(filename); |     furi_string_free(filename); | ||||||
| 
 | 
 | ||||||
|     storage_file_close(file); |     storage_file_close(file); | ||||||
|     storage_common_remove(fs_api, ARCHIVE_FAV_PATH); |     storage_common_remove(fs_api, ARCHIVE_FAV_PATH); | ||||||
| @ -226,14 +228,14 @@ bool archive_favorites_delete(const char* format, ...) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool archive_is_favorite(const char* format, ...) { | bool archive_is_favorite(const char* format, ...) { | ||||||
|     string_t buffer; |     FuriString* buffer; | ||||||
|     string_t filename; |     FuriString* filename; | ||||||
|     va_list args; |     va_list args; | ||||||
|     va_start(args, format); |     va_start(args, format); | ||||||
|     string_init_vprintf(filename, format, args); |     filename = furi_string_alloc_vprintf(format, args); | ||||||
|     va_end(args); |     va_end(args); | ||||||
| 
 | 
 | ||||||
|     string_init(buffer); |     buffer = furi_string_alloc(); | ||||||
|     Storage* fs_api = furi_record_open(RECORD_STORAGE); |     Storage* fs_api = furi_record_open(RECORD_STORAGE); | ||||||
|     File* file = storage_file_alloc(fs_api); |     File* file = storage_file_alloc(fs_api); | ||||||
| 
 | 
 | ||||||
| @ -245,10 +247,10 @@ bool archive_is_favorite(const char* format, ...) { | |||||||
|             if(!archive_favorites_read_line(file, buffer)) { |             if(!archive_favorites_read_line(file, buffer)) { | ||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
|             if(!string_size(buffer)) { |             if(!furi_string_size(buffer)) { | ||||||
|                 continue; |                 continue; | ||||||
|             } |             } | ||||||
|             if(!string_search(buffer, filename)) { |             if(!furi_string_search(buffer, filename)) { | ||||||
|                 found = true; |                 found = true; | ||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
| @ -256,8 +258,8 @@ bool archive_is_favorite(const char* format, ...) { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     storage_file_close(file); |     storage_file_close(file); | ||||||
|     string_clear(buffer); |     furi_string_free(buffer); | ||||||
|     string_clear(filename); |     furi_string_free(filename); | ||||||
|     storage_file_free(file); |     storage_file_free(file); | ||||||
|     furi_record_close(RECORD_STORAGE); |     furi_record_close(RECORD_STORAGE); | ||||||
| 
 | 
 | ||||||
| @ -271,13 +273,13 @@ bool archive_favorites_rename(const char* src, const char* dst) { | |||||||
|     Storage* fs_api = furi_record_open(RECORD_STORAGE); |     Storage* fs_api = furi_record_open(RECORD_STORAGE); | ||||||
|     File* file = storage_file_alloc(fs_api); |     File* file = storage_file_alloc(fs_api); | ||||||
| 
 | 
 | ||||||
|     string_t path; |     FuriString* path; | ||||||
|     string_t buffer; |     FuriString* buffer; | ||||||
| 
 | 
 | ||||||
|     string_init(buffer); |     buffer = furi_string_alloc(); | ||||||
|     string_init(path); |     path = furi_string_alloc(); | ||||||
| 
 | 
 | ||||||
|     string_printf(path, "%s", src); |     furi_string_printf(path, "%s", src); | ||||||
|     bool result = storage_file_open(file, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING); |     bool result = storage_file_open(file, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING); | ||||||
| 
 | 
 | ||||||
|     if(result) { |     if(result) { | ||||||
| @ -285,19 +287,19 @@ bool archive_favorites_rename(const char* src, const char* dst) { | |||||||
|             if(!archive_favorites_read_line(file, buffer)) { |             if(!archive_favorites_read_line(file, buffer)) { | ||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
|             if(!string_size(buffer)) { |             if(!furi_string_size(buffer)) { | ||||||
|                 continue; |                 continue; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             archive_file_append( |             archive_file_append( | ||||||
|                 ARCHIVE_FAV_TEMP_PATH, |                 ARCHIVE_FAV_TEMP_PATH, | ||||||
|                 "%s\n", |                 "%s\n", | ||||||
|                 string_search(buffer, path) ? string_get_cstr(buffer) : dst); |                 furi_string_search(buffer, path) ? furi_string_get_cstr(buffer) : dst); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     string_clear(buffer); |     furi_string_free(buffer); | ||||||
|     string_clear(path); |     furi_string_free(path); | ||||||
| 
 | 
 | ||||||
|     storage_file_close(file); |     storage_file_close(file); | ||||||
|     storage_common_remove(fs_api, ARCHIVE_FAV_PATH); |     storage_common_remove(fs_api, ARCHIVE_FAV_PATH); | ||||||
| @ -325,7 +327,7 @@ void archive_favorites_save(void* context) { | |||||||
| 
 | 
 | ||||||
|     for(size_t i = 0; i < archive_file_get_array_size(browser); i++) { |     for(size_t i = 0; i < archive_file_get_array_size(browser); i++) { | ||||||
|         ArchiveFile_t* item = archive_get_file_at(browser, i); |         ArchiveFile_t* item = archive_get_file_at(browser, i); | ||||||
|         archive_file_append(ARCHIVE_FAV_TEMP_PATH, "%s\n", string_get_cstr(item->path)); |         archive_file_append(ARCHIVE_FAV_TEMP_PATH, "%s\n", furi_string_get_cstr(item->path)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     storage_common_remove(fs_api, ARCHIVE_FAV_PATH); |     storage_common_remove(fs_api, ARCHIVE_FAV_PATH); | ||||||
|  | |||||||
| @ -7,8 +7,8 @@ | |||||||
| 
 | 
 | ||||||
| uint16_t archive_favorites_count(void* context); | uint16_t archive_favorites_count(void* context); | ||||||
| bool archive_favorites_read(void* context); | bool archive_favorites_read(void* context); | ||||||
| bool archive_favorites_delete(const char* format, ...); | bool archive_favorites_delete(const char* format, ...) _ATTRIBUTE((__format__(__printf__, 1, 2))); | ||||||
| bool archive_is_favorite(const char* format, ...); | bool archive_is_favorite(const char* format, ...) _ATTRIBUTE((__format__(__printf__, 1, 2))); | ||||||
| bool archive_favorites_rename(const char* src, const char* dst); | bool archive_favorites_rename(const char* src, const char* dst); | ||||||
| void archive_add_to_favorites(const char* file_path); | void archive_add_to_favorites(const char* file_path); | ||||||
| void archive_favorites_save(void* context); | void archive_favorites_save(void* context); | ||||||
|  | |||||||
| @ -15,10 +15,10 @@ void archive_set_file_type(ArchiveFile_t* file, const char* path, bool is_folder | |||||||
|     } else { |     } else { | ||||||
|         for(size_t i = 0; i < COUNT_OF(known_ext); i++) { |         for(size_t i = 0; i < COUNT_OF(known_ext); i++) { | ||||||
|             if((known_ext[i][0] == '?') || (known_ext[i][0] == '*')) continue; |             if((known_ext[i][0] == '?') || (known_ext[i][0] == '*')) continue; | ||||||
|             if(string_search_str(file->path, known_ext[i], 0) != STRING_FAILURE) { |             if(furi_string_search(file->path, known_ext[i], 0) != FURI_STRING_FAILURE) { | ||||||
|                 if(i == ArchiveFileTypeBadUsb) { |                 if(i == ArchiveFileTypeBadUsb) { | ||||||
|                     if(string_search_str(file->path, archive_get_default_path(ArchiveTabBadUsb)) == |                     if(furi_string_search( | ||||||
|                        0) { |                            file->path, archive_get_default_path(ArchiveTabBadUsb)) == 0) { | ||||||
|                         file->type = i; |                         file->type = i; | ||||||
|                         return; // *.txt file is a BadUSB script only if it is in BadUSB folder
 |                         return; // *.txt file is a BadUSB script only if it is in BadUSB folder
 | ||||||
|                     } |                     } | ||||||
| @ -54,10 +54,10 @@ bool archive_get_items(void* context, const char* path) { | |||||||
| void archive_file_append(const char* path, const char* format, ...) { | void archive_file_append(const char* path, const char* format, ...) { | ||||||
|     furi_assert(path); |     furi_assert(path); | ||||||
| 
 | 
 | ||||||
|     string_t string; |     FuriString* string; | ||||||
|     va_list args; |     va_list args; | ||||||
|     va_start(args, format); |     va_start(args, format); | ||||||
|     string_init_vprintf(string, format, args); |     string = furi_string_alloc_vprintf(format, args); | ||||||
|     va_end(args); |     va_end(args); | ||||||
| 
 | 
 | ||||||
|     Storage* fs_api = furi_record_open(RECORD_STORAGE); |     Storage* fs_api = furi_record_open(RECORD_STORAGE); | ||||||
| @ -66,7 +66,7 @@ void archive_file_append(const char* path, const char* format, ...) { | |||||||
|     bool res = storage_file_open(file, path, FSAM_WRITE, FSOM_OPEN_APPEND); |     bool res = storage_file_open(file, path, FSAM_WRITE, FSOM_OPEN_APPEND); | ||||||
| 
 | 
 | ||||||
|     if(res) { |     if(res) { | ||||||
|         storage_file_write(file, string_get_cstr(string), string_size(string)); |         storage_file_write(file, furi_string_get_cstr(string), furi_string_size(string)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     storage_file_close(file); |     storage_file_close(file); | ||||||
| @ -77,35 +77,35 @@ void archive_file_append(const char* path, const char* format, ...) { | |||||||
| void archive_delete_file(void* context, const char* format, ...) { | void archive_delete_file(void* context, const char* format, ...) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
| 
 | 
 | ||||||
|     string_t filename; |     FuriString* filename; | ||||||
|     va_list args; |     va_list args; | ||||||
|     va_start(args, format); |     va_start(args, format); | ||||||
|     string_init_vprintf(filename, format, args); |     filename = furi_string_alloc_vprintf(format, args); | ||||||
|     va_end(args); |     va_end(args); | ||||||
| 
 | 
 | ||||||
|     ArchiveBrowserView* browser = context; |     ArchiveBrowserView* browser = context; | ||||||
|     Storage* fs_api = furi_record_open(RECORD_STORAGE); |     Storage* fs_api = furi_record_open(RECORD_STORAGE); | ||||||
| 
 | 
 | ||||||
|     FileInfo fileinfo; |     FileInfo fileinfo; | ||||||
|     storage_common_stat(fs_api, string_get_cstr(filename), &fileinfo); |     storage_common_stat(fs_api, furi_string_get_cstr(filename), &fileinfo); | ||||||
| 
 | 
 | ||||||
|     bool res = false; |     bool res = false; | ||||||
| 
 | 
 | ||||||
|     if(fileinfo.flags & FSF_DIRECTORY) { |     if(fileinfo.flags & FSF_DIRECTORY) { | ||||||
|         res = storage_simply_remove_recursive(fs_api, string_get_cstr(filename)); |         res = storage_simply_remove_recursive(fs_api, furi_string_get_cstr(filename)); | ||||||
|     } else { |     } else { | ||||||
|         res = (storage_common_remove(fs_api, string_get_cstr(filename)) == FSE_OK); |         res = (storage_common_remove(fs_api, furi_string_get_cstr(filename)) == FSE_OK); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     furi_record_close(RECORD_STORAGE); |     furi_record_close(RECORD_STORAGE); | ||||||
| 
 | 
 | ||||||
|     if(archive_is_favorite("%s", string_get_cstr(filename))) { |     if(archive_is_favorite("%s", furi_string_get_cstr(filename))) { | ||||||
|         archive_favorites_delete("%s", string_get_cstr(filename)); |         archive_favorites_delete("%s", furi_string_get_cstr(filename)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if(res) { |     if(res) { | ||||||
|         archive_file_array_rm_selected(browser); |         archive_file_array_rm_selected(browser); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     string_clear(filename); |     furi_string_free(filename); | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,9 +1,11 @@ | |||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #include <m-array.h> | #include <m-array.h> | ||||||
| #include <m-string.h> | #include <furi.h> | ||||||
| #include <storage/storage.h> | #include <storage/storage.h> | ||||||
| 
 | 
 | ||||||
|  | #define FAP_MANIFEST_MAX_ICON_SIZE 32 | ||||||
|  | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     ArchiveFileTypeIButton, |     ArchiveFileTypeIButton, | ||||||
|     ArchiveFileTypeNFC, |     ArchiveFileTypeNFC, | ||||||
| @ -13,41 +15,65 @@ typedef enum { | |||||||
|     ArchiveFileTypeBadUsb, |     ArchiveFileTypeBadUsb, | ||||||
|     ArchiveFileTypeU2f, |     ArchiveFileTypeU2f, | ||||||
|     ArchiveFileTypeUpdateManifest, |     ArchiveFileTypeUpdateManifest, | ||||||
|  |     ArchiveFileTypeApplication, | ||||||
|     ArchiveFileTypeFolder, |     ArchiveFileTypeFolder, | ||||||
|     ArchiveFileTypeUnknown, |     ArchiveFileTypeUnknown, | ||||||
|     ArchiveFileTypeLoading, |     ArchiveFileTypeLoading, | ||||||
| } ArchiveFileTypeEnum; | } ArchiveFileTypeEnum; | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     string_t path; |     FuriString* path; | ||||||
|     ArchiveFileTypeEnum type; |     ArchiveFileTypeEnum type; | ||||||
|  |     uint8_t* custom_icon_data; | ||||||
|  |     FuriString* custom_name; | ||||||
|     bool fav; |     bool fav; | ||||||
|     bool is_app; |     bool is_app; | ||||||
| } ArchiveFile_t; | } ArchiveFile_t; | ||||||
| 
 | 
 | ||||||
| static void ArchiveFile_t_init(ArchiveFile_t* obj) { | static void ArchiveFile_t_init(ArchiveFile_t* obj) { | ||||||
|  |     obj->path = furi_string_alloc(); | ||||||
|     obj->type = ArchiveFileTypeUnknown; |     obj->type = ArchiveFileTypeUnknown; | ||||||
|     obj->is_app = false; |     obj->custom_icon_data = NULL; | ||||||
|  |     obj->custom_name = furi_string_alloc(); | ||||||
|     obj->fav = false; |     obj->fav = false; | ||||||
|     string_init(obj->path); |     obj->is_app = false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void ArchiveFile_t_init_set(ArchiveFile_t* obj, const ArchiveFile_t* src) { | static void ArchiveFile_t_init_set(ArchiveFile_t* obj, const ArchiveFile_t* src) { | ||||||
|  |     obj->path = furi_string_alloc_set(src->path); | ||||||
|     obj->type = src->type; |     obj->type = src->type; | ||||||
|     obj->is_app = src->is_app; |     if(src->custom_icon_data) { | ||||||
|  |         obj->custom_icon_data = malloc(FAP_MANIFEST_MAX_ICON_SIZE); | ||||||
|  |         memcpy(obj->custom_icon_data, src->custom_icon_data, FAP_MANIFEST_MAX_ICON_SIZE); | ||||||
|  |     } else { | ||||||
|  |         obj->custom_icon_data = NULL; | ||||||
|  |     } | ||||||
|  |     obj->custom_name = furi_string_alloc_set(src->custom_name); | ||||||
|     obj->fav = src->fav; |     obj->fav = src->fav; | ||||||
|     string_init_set(obj->path, src->path); |     obj->is_app = src->is_app; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void ArchiveFile_t_set(ArchiveFile_t* obj, const ArchiveFile_t* src) { | static void ArchiveFile_t_set(ArchiveFile_t* obj, const ArchiveFile_t* src) { | ||||||
|  |     furi_string_set(obj->path, src->path); | ||||||
|     obj->type = src->type; |     obj->type = src->type; | ||||||
|     obj->is_app = src->is_app; |     if(src->custom_icon_data) { | ||||||
|  |         obj->custom_icon_data = malloc(FAP_MANIFEST_MAX_ICON_SIZE); | ||||||
|  |         memcpy(obj->custom_icon_data, src->custom_icon_data, FAP_MANIFEST_MAX_ICON_SIZE); | ||||||
|  |     } else { | ||||||
|  |         obj->custom_icon_data = NULL; | ||||||
|  |     } | ||||||
|  |     furi_string_set(obj->custom_name, src->custom_name); | ||||||
|     obj->fav = src->fav; |     obj->fav = src->fav; | ||||||
|     string_set(obj->path, src->path); |     obj->is_app = src->is_app; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void ArchiveFile_t_clear(ArchiveFile_t* obj) { | static void ArchiveFile_t_clear(ArchiveFile_t* obj) { | ||||||
|     string_clear(obj->path); |     furi_string_free(obj->path); | ||||||
|  |     if(obj->custom_icon_data) { | ||||||
|  |         free(obj->custom_icon_data); | ||||||
|  |         obj->custom_icon_data = NULL; | ||||||
|  |     } | ||||||
|  |     furi_string_free(obj->custom_name); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ARRAY_DEF( | ARRAY_DEF( | ||||||
| @ -60,5 +86,7 @@ ARRAY_DEF( | |||||||
| 
 | 
 | ||||||
| void archive_set_file_type(ArchiveFile_t* file, const char* path, bool is_folder, bool is_app); | void archive_set_file_type(ArchiveFile_t* file, const char* path, bool is_folder, bool is_app); | ||||||
| bool archive_get_items(void* context, const char* path); | bool archive_get_items(void* context, const char* path); | ||||||
| void archive_file_append(const char* path, const char* format, ...); | void archive_file_append(const char* path, const char* format, ...) | ||||||
| void archive_delete_file(void* context, const char* format, ...); |     _ATTRIBUTE((__format__(__printf__, 2, 3))); | ||||||
|  | void archive_delete_file(void* context, const char* format, ...) | ||||||
|  |     _ATTRIBUTE((__format__(__printf__, 2, 3))); | ||||||
|  | |||||||
| @ -20,6 +20,7 @@ static const char* flipper_app_name[] = { | |||||||
|     [ArchiveFileTypeBadUsb] = "Bad USB", |     [ArchiveFileTypeBadUsb] = "Bad USB", | ||||||
|     [ArchiveFileTypeU2f] = "U2F", |     [ArchiveFileTypeU2f] = "U2F", | ||||||
|     [ArchiveFileTypeUpdateManifest] = "UpdaterApp", |     [ArchiveFileTypeUpdateManifest] = "UpdaterApp", | ||||||
|  |     [ArchiveFileTypeApplication] = "Applications", | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static void archive_loader_callback(const void* message, void* context) { | static void archive_loader_callback(const void* message, void* context) { | ||||||
| @ -40,14 +41,14 @@ static void archive_run_in_app(ArchiveBrowserView* browser, ArchiveFile_t* selec | |||||||
| 
 | 
 | ||||||
|     LoaderStatus status; |     LoaderStatus status; | ||||||
|     if(selected->is_app) { |     if(selected->is_app) { | ||||||
|         char* param = strrchr(string_get_cstr(selected->path), '/'); |         char* param = strrchr(furi_string_get_cstr(selected->path), '/'); | ||||||
|         if(param != NULL) { |         if(param != NULL) { | ||||||
|             param++; |             param++; | ||||||
|         } |         } | ||||||
|         status = loader_start(loader, flipper_app_name[selected->type], param); |         status = loader_start(loader, flipper_app_name[selected->type], param); | ||||||
|     } else { |     } else { | ||||||
|         status = loader_start( |         status = loader_start( | ||||||
|             loader, flipper_app_name[selected->type], string_get_cstr(selected->path)); |             loader, flipper_app_name[selected->type], furi_string_get_cstr(selected->path)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if(status != LoaderStatusOk) { |     if(status != LoaderStatusOk) { | ||||||
| @ -159,13 +160,13 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) { | |||||||
|             consumed = true; |             consumed = true; | ||||||
|             break; |             break; | ||||||
|         case ArchiveBrowserEventEnterFavMove: |         case ArchiveBrowserEventEnterFavMove: | ||||||
|             string_set(archive->fav_move_str, selected->path); |             furi_string_set(archive->fav_move_str, selected->path); | ||||||
|             archive_show_file_menu(browser, false); |             archive_show_file_menu(browser, false); | ||||||
|             archive_favorites_move_mode(archive->browser, true); |             archive_favorites_move_mode(archive->browser, true); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|             break; |             break; | ||||||
|         case ArchiveBrowserEventExitFavMove: |         case ArchiveBrowserEventExitFavMove: | ||||||
|             archive_update_focus(browser, string_get_cstr(archive->fav_move_str)); |             archive_update_focus(browser, furi_string_get_cstr(archive->fav_move_str)); | ||||||
|             archive_favorites_move_mode(archive->browser, false); |             archive_favorites_move_mode(archive->browser, false); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|             break; |             break; | ||||||
|  | |||||||
| @ -4,7 +4,6 @@ | |||||||
| #include "../helpers/archive_apps.h" | #include "../helpers/archive_apps.h" | ||||||
| #include "../helpers/archive_browser.h" | #include "../helpers/archive_browser.h" | ||||||
| #include "toolbox/path.h" | #include "toolbox/path.h" | ||||||
| #include "m-string.h" |  | ||||||
| 
 | 
 | ||||||
| #define SCENE_DELETE_CUSTOM_EVENT (0UL) | #define SCENE_DELETE_CUSTOM_EVENT (0UL) | ||||||
| #define MAX_TEXT_INPUT_LEN 22 | #define MAX_TEXT_INPUT_LEN 22 | ||||||
| @ -26,18 +25,18 @@ void archive_scene_delete_on_enter(void* context) { | |||||||
|     widget_add_button_element( |     widget_add_button_element( | ||||||
|         app->widget, GuiButtonTypeRight, "Delete", archive_scene_delete_widget_callback, app); |         app->widget, GuiButtonTypeRight, "Delete", archive_scene_delete_widget_callback, app); | ||||||
| 
 | 
 | ||||||
|     string_t filename; |     FuriString* filename; | ||||||
|     string_init(filename); |     filename = furi_string_alloc(); | ||||||
| 
 | 
 | ||||||
|     ArchiveFile_t* current = archive_get_current_file(app->browser); |     ArchiveFile_t* current = archive_get_current_file(app->browser); | ||||||
|     path_extract_filename(current->path, filename, false); |     path_extract_filename(current->path, filename, false); | ||||||
| 
 | 
 | ||||||
|     char delete_str[64]; |     char delete_str[64]; | ||||||
|     snprintf(delete_str, sizeof(delete_str), "\e#Delete %s?\e#", string_get_cstr(filename)); |     snprintf(delete_str, sizeof(delete_str), "\e#Delete %s?\e#", furi_string_get_cstr(filename)); | ||||||
|     widget_add_text_box_element( |     widget_add_text_box_element( | ||||||
|         app->widget, 0, 0, 128, 23, AlignCenter, AlignCenter, delete_str, false); |         app->widget, 0, 0, 128, 23, AlignCenter, AlignCenter, delete_str, false); | ||||||
| 
 | 
 | ||||||
|     string_clear(filename); |     furi_string_free(filename); | ||||||
| 
 | 
 | ||||||
|     view_dispatcher_switch_to_view(app->view_dispatcher, ArchiveViewWidget); |     view_dispatcher_switch_to_view(app->view_dispatcher, ArchiveViewWidget); | ||||||
| } | } | ||||||
|  | |||||||
| @ -19,10 +19,10 @@ void archive_scene_rename_on_enter(void* context) { | |||||||
|     TextInput* text_input = archive->text_input; |     TextInput* text_input = archive->text_input; | ||||||
|     ArchiveFile_t* current = archive_get_current_file(archive->browser); |     ArchiveFile_t* current = archive_get_current_file(archive->browser); | ||||||
| 
 | 
 | ||||||
|     string_t filename; |     FuriString* filename; | ||||||
|     string_init(filename); |     filename = furi_string_alloc(); | ||||||
|     path_extract_filename(current->path, filename, true); |     path_extract_filename(current->path, filename, true); | ||||||
|     strlcpy(archive->text_store, string_get_cstr(filename), MAX_NAME_LEN); |     strlcpy(archive->text_store, furi_string_get_cstr(filename), MAX_NAME_LEN); | ||||||
| 
 | 
 | ||||||
|     path_extract_extension(current->path, archive->file_extension, MAX_EXT_LEN); |     path_extract_extension(current->path, archive->file_extension, MAX_EXT_LEN); | ||||||
| 
 | 
 | ||||||
| @ -37,10 +37,10 @@ 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, ""); |         furi_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); |     furi_string_free(filename); | ||||||
| 
 | 
 | ||||||
|     view_dispatcher_switch_to_view(archive->view_dispatcher, ArchiveViewTextInput); |     view_dispatcher_switch_to_view(archive->view_dispatcher, ArchiveViewTextInput); | ||||||
| } | } | ||||||
| @ -56,19 +56,19 @@ bool archive_scene_rename_on_event(void* context, SceneManagerEvent event) { | |||||||
|             const char* path_src = archive_get_name(archive->browser); |             const char* path_src = archive_get_name(archive->browser); | ||||||
|             ArchiveFile_t* file = archive_get_current_file(archive->browser); |             ArchiveFile_t* file = archive_get_current_file(archive->browser); | ||||||
| 
 | 
 | ||||||
|             string_t path_dst; |             FuriString* path_dst; | ||||||
|             string_init(path_dst); |             path_dst = furi_string_alloc(); | ||||||
|             path_extract_dirname(path_src, path_dst); |             path_extract_dirname(path_src, path_dst); | ||||||
|             string_cat_printf(path_dst, "/%s%s", archive->text_store, known_ext[file->type]); |             furi_string_cat_printf(path_dst, "/%s%s", archive->text_store, known_ext[file->type]); | ||||||
| 
 | 
 | ||||||
|             storage_common_rename(fs_api, path_src, string_get_cstr(path_dst)); |             storage_common_rename(fs_api, path_src, furi_string_get_cstr(path_dst)); | ||||||
|             furi_record_close(RECORD_STORAGE); |             furi_record_close(RECORD_STORAGE); | ||||||
| 
 | 
 | ||||||
|             if(file->fav) { |             if(file->fav) { | ||||||
|                 archive_favorites_rename(path_src, string_get_cstr(path_dst)); |                 archive_favorites_rename(path_src, furi_string_get_cstr(path_dst)); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             string_clear(path_dst); |             furi_string_free(path_dst); | ||||||
| 
 | 
 | ||||||
|             scene_manager_next_scene(archive->scene_manager, ArchiveAppSceneBrowser); |             scene_manager_next_scene(archive->scene_manager, ArchiveAppSceneBrowser); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|  | |||||||
| @ -14,6 +14,7 @@ static const char* ArchiveTabNames[] = { | |||||||
|     [ArchiveTabInfrared] = "Infrared", |     [ArchiveTabInfrared] = "Infrared", | ||||||
|     [ArchiveTabBadUsb] = "Bad USB", |     [ArchiveTabBadUsb] = "Bad USB", | ||||||
|     [ArchiveTabU2f] = "U2F", |     [ArchiveTabU2f] = "U2F", | ||||||
|  |     [ArchiveTabApplications] = "Apps", | ||||||
|     [ArchiveTabBrowser] = "Browser", |     [ArchiveTabBrowser] = "Browser", | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| @ -29,6 +30,7 @@ static const Icon* ArchiveItemIcons[] = { | |||||||
|     [ArchiveFileTypeFolder] = &I_dir_10px, |     [ArchiveFileTypeFolder] = &I_dir_10px, | ||||||
|     [ArchiveFileTypeUnknown] = &I_unknown_10px, |     [ArchiveFileTypeUnknown] = &I_unknown_10px, | ||||||
|     [ArchiveFileTypeLoading] = &I_loading_10px, |     [ArchiveFileTypeLoading] = &I_loading_10px, | ||||||
|  |     [ArchiveFileTypeApplication] = &I_unknown_10px, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| void archive_browser_set_callback( | void archive_browser_set_callback( | ||||||
| @ -47,35 +49,35 @@ static void render_item_menu(Canvas* canvas, ArchiveBrowserViewModel* model) { | |||||||
|     canvas_set_color(canvas, ColorBlack); |     canvas_set_color(canvas, ColorBlack); | ||||||
|     elements_slightly_rounded_frame(canvas, 70, 16, 58, 48); |     elements_slightly_rounded_frame(canvas, 70, 16, 58, 48); | ||||||
| 
 | 
 | ||||||
|     string_t menu[MENU_ITEMS]; |     FuriString* menu[MENU_ITEMS]; | ||||||
| 
 | 
 | ||||||
|     string_init_set_str(menu[0], "Run in app"); |     menu[0] = furi_string_alloc_set("Run in app"); | ||||||
|     string_init_set_str(menu[1], "Pin"); |     menu[1] = furi_string_alloc_set("Pin"); | ||||||
|     string_init_set_str(menu[2], "Rename"); |     menu[2] = furi_string_alloc_set("Rename"); | ||||||
|     string_init_set_str(menu[3], "Delete"); |     menu[3] = furi_string_alloc_set("Delete"); | ||||||
| 
 | 
 | ||||||
|     ArchiveFile_t* selected = files_array_get(model->files, model->item_idx - model->array_offset); |     ArchiveFile_t* selected = files_array_get(model->files, model->item_idx - model->array_offset); | ||||||
| 
 | 
 | ||||||
|     if((selected->fav) || (model->tab_idx == ArchiveTabFavorites)) { |     if((selected->fav) || (model->tab_idx == ArchiveTabFavorites)) { | ||||||
|         string_set_str(menu[1], "Unpin"); |         furi_string_set(menu[1], "Unpin"); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if(!archive_is_known_app(selected->type)) { |     if(!archive_is_known_app(selected->type)) { | ||||||
|         string_set_str(menu[0], "---"); |         furi_string_set(menu[0], "---"); | ||||||
|         string_set_str(menu[1], "---"); |         furi_string_set(menu[1], "---"); | ||||||
|         string_set_str(menu[2], "---"); |         furi_string_set(menu[2], "---"); | ||||||
|     } else { |     } else { | ||||||
|         if(model->tab_idx == ArchiveTabFavorites) { |         if(model->tab_idx == ArchiveTabFavorites) { | ||||||
|             string_set_str(menu[2], "Move"); |             furi_string_set(menu[2], "Move"); | ||||||
|             string_set_str(menu[3], "---"); |             furi_string_set(menu[3], "---"); | ||||||
|         } else if(selected->is_app) { |         } else if(selected->is_app) { | ||||||
|             string_set_str(menu[2], "---"); |             furi_string_set(menu[2], "---"); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     for(size_t i = 0; i < MENU_ITEMS; i++) { |     for(size_t i = 0; i < MENU_ITEMS; i++) { | ||||||
|         canvas_draw_str(canvas, 82, 27 + i * 11, string_get_cstr(menu[i])); |         canvas_draw_str(canvas, 82, 27 + i * 11, furi_string_get_cstr(menu[i])); | ||||||
|         string_clear(menu[i]); |         furi_string_free(menu[i]); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     canvas_draw_icon(canvas, 74, 20 + model->menu_idx * 11, &I_ButtonRight_4x7); |     canvas_draw_icon(canvas, 74, 20 + model->menu_idx * 11, &I_ButtonRight_4x7); | ||||||
| @ -118,20 +120,31 @@ static void draw_list(Canvas* canvas, ArchiveBrowserViewModel* model) { | |||||||
|     bool scrollbar = model->item_cnt > 4; |     bool scrollbar = model->item_cnt > 4; | ||||||
| 
 | 
 | ||||||
|     for(uint32_t i = 0; i < MIN(model->item_cnt, MENU_ITEMS); ++i) { |     for(uint32_t i = 0; i < MIN(model->item_cnt, MENU_ITEMS); ++i) { | ||||||
|         string_t str_buf; |         FuriString* str_buf; | ||||||
|         string_init(str_buf); |         str_buf = furi_string_alloc(); | ||||||
|         int32_t idx = CLAMP((uint32_t)(i + model->list_offset), model->item_cnt, 0u); |         int32_t idx = CLAMP((uint32_t)(i + model->list_offset), model->item_cnt, 0u); | ||||||
|         uint8_t x_offset = (model->move_fav && model->item_idx == idx) ? MOVE_OFFSET : 0; |         uint8_t x_offset = (model->move_fav && model->item_idx == idx) ? MOVE_OFFSET : 0; | ||||||
| 
 | 
 | ||||||
|         ArchiveFileTypeEnum file_type = ArchiveFileTypeLoading; |         ArchiveFileTypeEnum file_type = ArchiveFileTypeLoading; | ||||||
|  |         uint8_t* custom_icon_data = NULL; | ||||||
| 
 | 
 | ||||||
|         if(archive_is_item_in_array(model, idx)) { |         if(archive_is_item_in_array(model, idx)) { | ||||||
|             ArchiveFile_t* file = files_array_get( |             ArchiveFile_t* file = files_array_get( | ||||||
|                 model->files, CLAMP(idx - model->array_offset, (int32_t)(array_size - 1), 0)); |                 model->files, CLAMP(idx - model->array_offset, (int32_t)(array_size - 1), 0)); | ||||||
|             path_extract_filename(file->path, str_buf, archive_is_known_app(file->type)); |  | ||||||
|             file_type = file->type; |             file_type = file->type; | ||||||
|  |             if(file_type == ArchiveFileTypeApplication) { | ||||||
|  |                 if(file->custom_icon_data) { | ||||||
|  |                     custom_icon_data = file->custom_icon_data; | ||||||
|  |                     furi_string_set(str_buf, file->custom_name); | ||||||
|  |                 } else { | ||||||
|  |                     file_type = ArchiveFileTypeUnknown; | ||||||
|  |                     path_extract_filename(file->path, str_buf, archive_is_known_app(file->type)); | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 path_extract_filename(file->path, str_buf, archive_is_known_app(file->type)); | ||||||
|  |             } | ||||||
|         } else { |         } else { | ||||||
|             string_set_str(str_buf, "---"); |             furi_string_set(str_buf, "---"); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         elements_string_fit_width( |         elements_string_fit_width( | ||||||
| @ -143,10 +156,17 @@ static void draw_list(Canvas* canvas, ArchiveBrowserViewModel* model) { | |||||||
|             canvas_set_color(canvas, ColorBlack); |             canvas_set_color(canvas, ColorBlack); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         canvas_draw_icon(canvas, 2 + x_offset, 16 + i * FRAME_HEIGHT, ArchiveItemIcons[file_type]); |         if(custom_icon_data) { | ||||||
|         canvas_draw_str(canvas, 15 + x_offset, 24 + i * FRAME_HEIGHT, string_get_cstr(str_buf)); |             canvas_draw_bitmap( | ||||||
|  |                 canvas, 2 + x_offset, 16 + i * FRAME_HEIGHT, 11, 10, custom_icon_data); | ||||||
|  |         } else { | ||||||
|  |             canvas_draw_icon( | ||||||
|  |                 canvas, 2 + x_offset, 16 + i * FRAME_HEIGHT, ArchiveItemIcons[file_type]); | ||||||
|  |         } | ||||||
|  |         canvas_draw_str( | ||||||
|  |             canvas, 15 + x_offset, 24 + i * FRAME_HEIGHT, furi_string_get_cstr(str_buf)); | ||||||
| 
 | 
 | ||||||
|         string_clear(str_buf); |         furi_string_free(str_buf); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if(scrollbar) { |     if(scrollbar) { | ||||||
| @ -243,33 +263,37 @@ static bool archive_view_input(InputEvent* event, void* context) { | |||||||
|     bool in_menu; |     bool in_menu; | ||||||
|     bool move_fav_mode; |     bool move_fav_mode; | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         browser->view, (ArchiveBrowserViewModel * model) { |         browser->view, | ||||||
|  |         ArchiveBrowserViewModel * model, | ||||||
|  |         { | ||||||
|             in_menu = model->menu; |             in_menu = model->menu; | ||||||
|             move_fav_mode = model->move_fav; |             move_fav_mode = model->move_fav; | ||||||
|             return false; |         }, | ||||||
|         }); |         false); | ||||||
| 
 | 
 | ||||||
|     if(in_menu) { |     if(in_menu) { | ||||||
|         if(event->type == InputTypeShort) { |         if(event->type == InputTypeShort) { | ||||||
|             if(event->key == InputKeyUp || event->key == InputKeyDown) { |             if(event->key == InputKeyUp || event->key == InputKeyDown) { | ||||||
|                 with_view_model( |                 with_view_model( | ||||||
|                     browser->view, (ArchiveBrowserViewModel * model) { |                     browser->view, | ||||||
|  |                     ArchiveBrowserViewModel * model, | ||||||
|  |                     { | ||||||
|                         if(event->key == InputKeyUp) { |                         if(event->key == InputKeyUp) { | ||||||
|                             model->menu_idx = ((model->menu_idx - 1) + MENU_ITEMS) % MENU_ITEMS; |                             model->menu_idx = ((model->menu_idx - 1) + MENU_ITEMS) % MENU_ITEMS; | ||||||
|                         } else if(event->key == InputKeyDown) { |                         } else if(event->key == InputKeyDown) { | ||||||
|                             model->menu_idx = (model->menu_idx + 1) % MENU_ITEMS; |                             model->menu_idx = (model->menu_idx + 1) % MENU_ITEMS; | ||||||
|                         } |                         } | ||||||
|                         return true; |                     }, | ||||||
|                     }); |                     true); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             if(event->key == InputKeyOk) { |             if(event->key == InputKeyOk) { | ||||||
|                 uint8_t idx; |                 uint8_t idx; | ||||||
|                 with_view_model( |                 with_view_model( | ||||||
|                     browser->view, (ArchiveBrowserViewModel * model) { |                     browser->view, | ||||||
|                         idx = model->menu_idx; |                     ArchiveBrowserViewModel * model, | ||||||
|                         return false; |                     { idx = model->menu_idx; }, | ||||||
|                     }); |                     false); | ||||||
|                 browser->callback(file_menu_actions[idx], browser->context); |                 browser->callback(file_menu_actions[idx], browser->context); | ||||||
|             } else if(event->key == InputKeyBack) { |             } else if(event->key == InputKeyBack) { | ||||||
|                 browser->callback(ArchiveBrowserEventFileMenuClose, browser->context); |                 browser->callback(ArchiveBrowserEventFileMenuClose, browser->context); | ||||||
| @ -293,7 +317,9 @@ static bool archive_view_input(InputEvent* event, void* context) { | |||||||
|         if((event->key == InputKeyUp || event->key == InputKeyDown) && |         if((event->key == InputKeyUp || event->key == InputKeyDown) && | ||||||
|            (event->type == InputTypeShort || event->type == InputTypeRepeat)) { |            (event->type == InputTypeShort || event->type == InputTypeRepeat)) { | ||||||
|             with_view_model( |             with_view_model( | ||||||
|                 browser->view, (ArchiveBrowserViewModel * model) { |                 browser->view, | ||||||
|  |                 ArchiveBrowserViewModel * model, | ||||||
|  |                 { | ||||||
|                     if(event->key == InputKeyUp) { |                     if(event->key == InputKeyUp) { | ||||||
|                         model->item_idx = |                         model->item_idx = | ||||||
|                             ((model->item_idx - 1) + model->item_cnt) % model->item_cnt; |                             ((model->item_idx - 1) + model->item_cnt) % model->item_cnt; | ||||||
| @ -314,9 +340,8 @@ static bool archive_view_input(InputEvent* event, void* context) { | |||||||
|                             browser->callback(ArchiveBrowserEventFavMoveDown, browser->context); |                             browser->callback(ArchiveBrowserEventFavMoveDown, browser->context); | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
| 
 |                 }, | ||||||
|                     return true; |                 true); | ||||||
|                 }); |  | ||||||
|             archive_update_offset(browser); |             archive_update_offset(browser); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| @ -361,14 +386,16 @@ ArchiveBrowserView* browser_alloc() { | |||||||
|     view_set_draw_callback(browser->view, archive_view_render); |     view_set_draw_callback(browser->view, archive_view_render); | ||||||
|     view_set_input_callback(browser->view, archive_view_input); |     view_set_input_callback(browser->view, archive_view_input); | ||||||
| 
 | 
 | ||||||
|     string_init_set_str(browser->path, archive_get_default_path(TAB_DEFAULT)); |     browser->path = furi_string_alloc_set(archive_get_default_path(TAB_DEFAULT)); | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         browser->view, (ArchiveBrowserViewModel * model) { |         browser->view, | ||||||
|  |         ArchiveBrowserViewModel * model, | ||||||
|  |         { | ||||||
|             files_array_init(model->files); |             files_array_init(model->files); | ||||||
|             model->tab_idx = TAB_DEFAULT; |             model->tab_idx = TAB_DEFAULT; | ||||||
|             return true; |         }, | ||||||
|         }); |         true); | ||||||
| 
 | 
 | ||||||
|     return browser; |     return browser; | ||||||
| } | } | ||||||
| @ -381,12 +408,12 @@ void browser_free(ArchiveBrowserView* browser) { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         browser->view, (ArchiveBrowserViewModel * model) { |         browser->view, | ||||||
|             files_array_clear(model->files); |         ArchiveBrowserViewModel * model, | ||||||
|             return false; |         { files_array_clear(model->files); }, | ||||||
|         }); |         false); | ||||||
| 
 | 
 | ||||||
|     string_clear(browser->path); |     furi_string_free(browser->path); | ||||||
| 
 | 
 | ||||||
|     view_free(browser->view); |     view_free(browser->view); | ||||||
|     free(browser); |     free(browser); | ||||||
|  | |||||||
| @ -26,6 +26,7 @@ typedef enum { | |||||||
|     ArchiveTabIButton, |     ArchiveTabIButton, | ||||||
|     ArchiveTabBadUsb, |     ArchiveTabBadUsb, | ||||||
|     ArchiveTabU2f, |     ArchiveTabU2f, | ||||||
|  |     ArchiveTabApplications, | ||||||
|     ArchiveTabBrowser, |     ArchiveTabBrowser, | ||||||
|     ArchiveTabTotal, |     ArchiveTabTotal, | ||||||
| } ArchiveTabEnum; | } ArchiveTabEnum; | ||||||
| @ -77,7 +78,7 @@ struct ArchiveBrowserView { | |||||||
|     bool worker_running; |     bool worker_running; | ||||||
|     ArchiveBrowserViewCallback callback; |     ArchiveBrowserViewCallback callback; | ||||||
|     void* context; |     void* context; | ||||||
|     string_t path; |     FuriString* path; | ||||||
|     InputKey last_tab_switch_dir; |     InputKey last_tab_switch_dir; | ||||||
|     bool is_root; |     bool is_root; | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -1,5 +1,4 @@ | |||||||
| #include "bad_usb_app_i.h" | #include "bad_usb_app_i.h" | ||||||
| #include "m-string.h" |  | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| #include <furi_hal.h> | #include <furi_hal.h> | ||||||
| #include <storage/storage.h> | #include <storage/storage.h> | ||||||
| @ -26,10 +25,10 @@ static void bad_usb_app_tick_event_callback(void* context) { | |||||||
| BadUsbApp* bad_usb_app_alloc(char* arg) { | BadUsbApp* bad_usb_app_alloc(char* arg) { | ||||||
|     BadUsbApp* app = malloc(sizeof(BadUsbApp)); |     BadUsbApp* app = malloc(sizeof(BadUsbApp)); | ||||||
| 
 | 
 | ||||||
|     string_init(app->file_path); |     app->file_path = furi_string_alloc(); | ||||||
| 
 | 
 | ||||||
|     if(arg && strlen(arg)) { |     if(arg && strlen(arg)) { | ||||||
|         string_set_str(app->file_path, arg); |         furi_string_set(app->file_path, arg); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     app->gui = furi_record_open(RECORD_GUI); |     app->gui = furi_record_open(RECORD_GUI); | ||||||
| @ -64,10 +63,10 @@ BadUsbApp* bad_usb_app_alloc(char* arg) { | |||||||
|         app->error = BadUsbAppErrorCloseRpc; |         app->error = BadUsbAppErrorCloseRpc; | ||||||
|         scene_manager_next_scene(app->scene_manager, BadUsbSceneError); |         scene_manager_next_scene(app->scene_manager, BadUsbSceneError); | ||||||
|     } else { |     } else { | ||||||
|         if(!string_empty_p(app->file_path)) { |         if(!furi_string_empty(app->file_path)) { | ||||||
|             scene_manager_next_scene(app->scene_manager, BadUsbSceneWork); |             scene_manager_next_scene(app->scene_manager, BadUsbSceneWork); | ||||||
|         } else { |         } else { | ||||||
|             string_set_str(app->file_path, BAD_USB_APP_PATH_FOLDER); |             furi_string_set(app->file_path, BAD_USB_APP_PATH_FOLDER); | ||||||
|             scene_manager_next_scene(app->scene_manager, BadUsbSceneFileSelect); |             scene_manager_next_scene(app->scene_manager, BadUsbSceneFileSelect); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -95,7 +94,7 @@ void bad_usb_app_free(BadUsbApp* app) { | |||||||
|     furi_record_close(RECORD_NOTIFICATION); |     furi_record_close(RECORD_NOTIFICATION); | ||||||
|     furi_record_close(RECORD_DIALOGS); |     furi_record_close(RECORD_DIALOGS); | ||||||
| 
 | 
 | ||||||
|     string_clear(app->file_path); |     furi_string_free(app->file_path); | ||||||
| 
 | 
 | ||||||
|     free(app); |     free(app); | ||||||
| } | } | ||||||
|  | |||||||
| @ -31,7 +31,7 @@ struct BadUsbApp { | |||||||
|     Widget* widget; |     Widget* widget; | ||||||
| 
 | 
 | ||||||
|     BadUsbAppError error; |     BadUsbAppError error; | ||||||
|     string_t file_path; |     FuriString* file_path; | ||||||
|     BadUsb* bad_usb_view; |     BadUsb* bad_usb_view; | ||||||
|     BadUsbScript* bad_usb_script; |     BadUsbScript* bad_usb_script; | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -26,16 +26,16 @@ typedef enum { | |||||||
| struct BadUsbScript { | struct BadUsbScript { | ||||||
|     FuriHalUsbHidConfig hid_cfg; |     FuriHalUsbHidConfig hid_cfg; | ||||||
|     BadUsbState st; |     BadUsbState st; | ||||||
|     string_t file_path; |     FuriString* file_path; | ||||||
|     uint32_t defdelay; |     uint32_t defdelay; | ||||||
|     FuriThread* thread; |     FuriThread* thread; | ||||||
|     uint8_t file_buf[FILE_BUFFER_LEN + 1]; |     uint8_t file_buf[FILE_BUFFER_LEN + 1]; | ||||||
|     uint8_t buf_start; |     uint8_t buf_start; | ||||||
|     uint8_t buf_len; |     uint8_t buf_len; | ||||||
|     bool file_end; |     bool file_end; | ||||||
|     string_t line; |     FuriString* line; | ||||||
| 
 | 
 | ||||||
|     string_t line_prev; |     FuriString* line_prev; | ||||||
|     uint32_t repeat_cnt; |     uint32_t repeat_cnt; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| @ -109,6 +109,7 @@ static const char ducky_cmd_string[] = {"STRING "}; | |||||||
| static const char ducky_cmd_defdelay_1[] = {"DEFAULT_DELAY "}; | static const char ducky_cmd_defdelay_1[] = {"DEFAULT_DELAY "}; | ||||||
| static const char ducky_cmd_defdelay_2[] = {"DEFAULTDELAY "}; | static const char ducky_cmd_defdelay_2[] = {"DEFAULTDELAY "}; | ||||||
| static const char ducky_cmd_repeat[] = {"REPEAT "}; | static const char ducky_cmd_repeat[] = {"REPEAT "}; | ||||||
|  | static const char ducky_cmd_sysrq[] = {"SYSRQ "}; | ||||||
| 
 | 
 | ||||||
| static const char ducky_cmd_altchar[] = {"ALTCHAR "}; | static const char ducky_cmd_altchar[] = {"ALTCHAR "}; | ||||||
| static const char ducky_cmd_altstr_1[] = {"ALTSTRING "}; | static const char ducky_cmd_altstr_1[] = {"ALTSTRING "}; | ||||||
| @ -230,9 +231,10 @@ static uint16_t ducky_get_keycode(const char* param, bool accept_chars) { | |||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int32_t ducky_parse_line(BadUsbScript* bad_usb, string_t line) { | static int32_t | ||||||
|     uint32_t line_len = string_size(line); |     ducky_parse_line(BadUsbScript* bad_usb, FuriString* line, char* error, size_t error_len) { | ||||||
|     const char* line_tmp = string_get_cstr(line); |     uint32_t line_len = furi_string_size(line); | ||||||
|  |     const char* line_tmp = furi_string_get_cstr(line); | ||||||
|     bool state = false; |     bool state = false; | ||||||
| 
 | 
 | ||||||
|     for(uint32_t i = 0; i < line_len; i++) { |     for(uint32_t i = 0; i < line_len; i++) { | ||||||
| @ -260,6 +262,9 @@ static int32_t ducky_parse_line(BadUsbScript* bad_usb, string_t line) { | |||||||
|         if((state) && (delay_val > 0)) { |         if((state) && (delay_val > 0)) { | ||||||
|             return (int32_t)delay_val; |             return (int32_t)delay_val; | ||||||
|         } |         } | ||||||
|  |         if(error != NULL) { | ||||||
|  |             snprintf(error, error_len, "Invalid number %s", line_tmp); | ||||||
|  |         } | ||||||
|         return SCRIPT_STATE_ERROR; |         return SCRIPT_STATE_ERROR; | ||||||
|     } else if( |     } else if( | ||||||
|         (strncmp(line_tmp, ducky_cmd_defdelay_1, strlen(ducky_cmd_defdelay_1)) == 0) || |         (strncmp(line_tmp, ducky_cmd_defdelay_1, strlen(ducky_cmd_defdelay_1)) == 0) || | ||||||
| @ -267,17 +272,26 @@ static int32_t ducky_parse_line(BadUsbScript* bad_usb, string_t line) { | |||||||
|         // DEFAULT_DELAY
 |         // DEFAULT_DELAY
 | ||||||
|         line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; |         line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; | ||||||
|         state = ducky_get_number(line_tmp, &bad_usb->defdelay); |         state = ducky_get_number(line_tmp, &bad_usb->defdelay); | ||||||
|  |         if(!state && error != NULL) { | ||||||
|  |             snprintf(error, error_len, "Invalid number %s", line_tmp); | ||||||
|  |         } | ||||||
|         return (state) ? (0) : SCRIPT_STATE_ERROR; |         return (state) ? (0) : SCRIPT_STATE_ERROR; | ||||||
|     } else if(strncmp(line_tmp, ducky_cmd_string, strlen(ducky_cmd_string)) == 0) { |     } else if(strncmp(line_tmp, ducky_cmd_string, strlen(ducky_cmd_string)) == 0) { | ||||||
|         // STRING
 |         // STRING
 | ||||||
|         line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; |         line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; | ||||||
|         state = ducky_string(line_tmp); |         state = ducky_string(line_tmp); | ||||||
|  |         if(!state && error != NULL) { | ||||||
|  |             snprintf(error, error_len, "Invalid string %s", line_tmp); | ||||||
|  |         } | ||||||
|         return (state) ? (0) : SCRIPT_STATE_ERROR; |         return (state) ? (0) : SCRIPT_STATE_ERROR; | ||||||
|     } else if(strncmp(line_tmp, ducky_cmd_altchar, strlen(ducky_cmd_altchar)) == 0) { |     } else if(strncmp(line_tmp, ducky_cmd_altchar, strlen(ducky_cmd_altchar)) == 0) { | ||||||
|         // ALTCHAR
 |         // ALTCHAR
 | ||||||
|         line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; |         line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; | ||||||
|         ducky_numlock_on(); |         ducky_numlock_on(); | ||||||
|         state = ducky_altchar(line_tmp); |         state = ducky_altchar(line_tmp); | ||||||
|  |         if(!state && error != NULL) { | ||||||
|  |             snprintf(error, error_len, "Invalid altchar %s", line_tmp); | ||||||
|  |         } | ||||||
|         return (state) ? (0) : SCRIPT_STATE_ERROR; |         return (state) ? (0) : SCRIPT_STATE_ERROR; | ||||||
|     } else if( |     } else if( | ||||||
|         (strncmp(line_tmp, ducky_cmd_altstr_1, strlen(ducky_cmd_altstr_1)) == 0) || |         (strncmp(line_tmp, ducky_cmd_altstr_1, strlen(ducky_cmd_altstr_1)) == 0) || | ||||||
| @ -286,16 +300,35 @@ static int32_t ducky_parse_line(BadUsbScript* bad_usb, string_t line) { | |||||||
|         line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; |         line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; | ||||||
|         ducky_numlock_on(); |         ducky_numlock_on(); | ||||||
|         state = ducky_altstring(line_tmp); |         state = ducky_altstring(line_tmp); | ||||||
|  |         if(!state && error != NULL) { | ||||||
|  |             snprintf(error, error_len, "Invalid altstring %s", line_tmp); | ||||||
|  |         } | ||||||
|         return (state) ? (0) : SCRIPT_STATE_ERROR; |         return (state) ? (0) : SCRIPT_STATE_ERROR; | ||||||
|     } else if(strncmp(line_tmp, ducky_cmd_repeat, strlen(ducky_cmd_repeat)) == 0) { |     } else if(strncmp(line_tmp, ducky_cmd_repeat, strlen(ducky_cmd_repeat)) == 0) { | ||||||
|         // REPEAT
 |         // REPEAT
 | ||||||
|         line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; |         line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; | ||||||
|         state = ducky_get_number(line_tmp, &bad_usb->repeat_cnt); |         state = ducky_get_number(line_tmp, &bad_usb->repeat_cnt); | ||||||
|  |         if(!state && error != NULL) { | ||||||
|  |             snprintf(error, error_len, "Invalid number %s", line_tmp); | ||||||
|  |         } | ||||||
|         return (state) ? (0) : SCRIPT_STATE_ERROR; |         return (state) ? (0) : SCRIPT_STATE_ERROR; | ||||||
|  |     } else if(strncmp(line_tmp, ducky_cmd_sysrq, strlen(ducky_cmd_sysrq)) == 0) { | ||||||
|  |         // SYSRQ
 | ||||||
|  |         line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; | ||||||
|  |         uint16_t key = ducky_get_keycode(line_tmp, true); | ||||||
|  |         furi_hal_hid_kb_press(KEY_MOD_LEFT_ALT | HID_KEYBOARD_PRINT_SCREEN); | ||||||
|  |         furi_hal_hid_kb_press(key); | ||||||
|  |         furi_hal_hid_kb_release_all(); | ||||||
|  |         return (0); | ||||||
|     } else { |     } else { | ||||||
|         // Special keys + modifiers
 |         // Special keys + modifiers
 | ||||||
|         uint16_t key = ducky_get_keycode(line_tmp, false); |         uint16_t key = ducky_get_keycode(line_tmp, false); | ||||||
|         if(key == HID_KEYBOARD_NONE) return SCRIPT_STATE_ERROR; |         if(key == HID_KEYBOARD_NONE) { | ||||||
|  |             if(error != NULL) { | ||||||
|  |                 snprintf(error, error_len, "No keycode defined for %s", line_tmp); | ||||||
|  |             } | ||||||
|  |             return SCRIPT_STATE_ERROR; | ||||||
|  |         } | ||||||
|         if((key & 0xFF00) != 0) { |         if((key & 0xFF00) != 0) { | ||||||
|             // It's a modifier key
 |             // It's a modifier key
 | ||||||
|             line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; |             line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; | ||||||
| @ -305,6 +338,9 @@ static int32_t ducky_parse_line(BadUsbScript* bad_usb, string_t line) { | |||||||
|         furi_hal_hid_kb_release(key); |         furi_hal_hid_kb_release(key); | ||||||
|         return (0); |         return (0); | ||||||
|     } |     } | ||||||
|  |     if(error != NULL) { | ||||||
|  |         strncpy(error, "Unknown error", error_len); | ||||||
|  |     } | ||||||
|     return SCRIPT_STATE_ERROR; |     return SCRIPT_STATE_ERROR; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -323,7 +359,7 @@ static bool ducky_set_usb_id(BadUsbScript* bad_usb, const char* line) { | |||||||
|         } |         } | ||||||
|         FURI_LOG_D( |         FURI_LOG_D( | ||||||
|             WORKER_TAG, |             WORKER_TAG, | ||||||
|             "set id: %04X:%04X mfr:%s product:%s", |             "set id: %04lX:%04lX mfr:%s product:%s", | ||||||
|             bad_usb->hid_cfg.vid, |             bad_usb->hid_cfg.vid, | ||||||
|             bad_usb->hid_cfg.pid, |             bad_usb->hid_cfg.pid, | ||||||
|             bad_usb->hid_cfg.manuf, |             bad_usb->hid_cfg.manuf, | ||||||
| @ -337,7 +373,7 @@ static bool ducky_script_preload(BadUsbScript* bad_usb, File* script_file) { | |||||||
|     uint8_t ret = 0; |     uint8_t ret = 0; | ||||||
|     uint32_t line_len = 0; |     uint32_t line_len = 0; | ||||||
| 
 | 
 | ||||||
|     string_reset(bad_usb->line); |     furi_string_reset(bad_usb->line); | ||||||
| 
 | 
 | ||||||
|     do { |     do { | ||||||
|         ret = storage_file_read(script_file, bad_usb->file_buf, FILE_BUFFER_LEN); |         ret = storage_file_read(script_file, bad_usb->file_buf, FILE_BUFFER_LEN); | ||||||
| @ -347,7 +383,7 @@ static bool ducky_script_preload(BadUsbScript* bad_usb, File* script_file) { | |||||||
|                 line_len = 0; |                 line_len = 0; | ||||||
|             } else { |             } else { | ||||||
|                 if(bad_usb->st.line_nb == 0) { // Save first line
 |                 if(bad_usb->st.line_nb == 0) { // Save first line
 | ||||||
|                     string_push_back(bad_usb->line, bad_usb->file_buf[i]); |                     furi_string_push_back(bad_usb->line, bad_usb->file_buf[i]); | ||||||
|                 } |                 } | ||||||
|                 line_len++; |                 line_len++; | ||||||
|             } |             } | ||||||
| @ -360,7 +396,7 @@ static bool ducky_script_preload(BadUsbScript* bad_usb, File* script_file) { | |||||||
|         } |         } | ||||||
|     } while(ret > 0); |     } while(ret > 0); | ||||||
| 
 | 
 | ||||||
|     const char* line_tmp = string_get_cstr(bad_usb->line); |     const char* line_tmp = furi_string_get_cstr(bad_usb->line); | ||||||
|     bool id_set = false; // Looking for ID command at first line
 |     bool id_set = false; // Looking for ID command at first line
 | ||||||
|     if(strncmp(line_tmp, ducky_cmd_id, strlen(ducky_cmd_id)) == 0) { |     if(strncmp(line_tmp, ducky_cmd_id, strlen(ducky_cmd_id)) == 0) { | ||||||
|         id_set = ducky_set_usb_id(bad_usb, &line_tmp[strlen(ducky_cmd_id) + 1]); |         id_set = ducky_set_usb_id(bad_usb, &line_tmp[strlen(ducky_cmd_id) + 1]); | ||||||
| @ -373,7 +409,7 @@ static bool ducky_script_preload(BadUsbScript* bad_usb, File* script_file) { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     storage_file_seek(script_file, 0, true); |     storage_file_seek(script_file, 0, true); | ||||||
|     string_reset(bad_usb->line); |     furi_string_reset(bad_usb->line); | ||||||
| 
 | 
 | ||||||
|     return true; |     return true; | ||||||
| } | } | ||||||
| @ -383,20 +419,21 @@ static int32_t ducky_script_execute_next(BadUsbScript* bad_usb, File* script_fil | |||||||
| 
 | 
 | ||||||
|     if(bad_usb->repeat_cnt > 0) { |     if(bad_usb->repeat_cnt > 0) { | ||||||
|         bad_usb->repeat_cnt--; |         bad_usb->repeat_cnt--; | ||||||
|         delay_val = ducky_parse_line(bad_usb, bad_usb->line_prev); |         delay_val = ducky_parse_line( | ||||||
|  |             bad_usb, bad_usb->line_prev, bad_usb->st.error, sizeof(bad_usb->st.error)); | ||||||
|         if(delay_val == SCRIPT_STATE_NEXT_LINE) { // Empty line
 |         if(delay_val == SCRIPT_STATE_NEXT_LINE) { // Empty line
 | ||||||
|             return 0; |             return 0; | ||||||
|         } else if(delay_val < 0) { // Script error
 |         } else if(delay_val < 0) { // Script error
 | ||||||
|             bad_usb->st.error_line = bad_usb->st.line_cur - 1; |             bad_usb->st.error_line = bad_usb->st.line_cur - 1; | ||||||
|             FURI_LOG_E(WORKER_TAG, "Unknown command at line %lu", bad_usb->st.line_cur - 1); |             FURI_LOG_E(WORKER_TAG, "Unknown command at line %u", bad_usb->st.line_cur - 1); | ||||||
|             return SCRIPT_STATE_ERROR; |             return SCRIPT_STATE_ERROR; | ||||||
|         } else { |         } else { | ||||||
|             return (delay_val + bad_usb->defdelay); |             return (delay_val + bad_usb->defdelay); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     string_set(bad_usb->line_prev, bad_usb->line); |     furi_string_set(bad_usb->line_prev, bad_usb->line); | ||||||
|     string_reset(bad_usb->line); |     furi_string_reset(bad_usb->line); | ||||||
| 
 | 
 | ||||||
|     while(1) { |     while(1) { | ||||||
|         if(bad_usb->buf_len == 0) { |         if(bad_usb->buf_len == 0) { | ||||||
| @ -413,20 +450,22 @@ static int32_t ducky_script_execute_next(BadUsbScript* bad_usb, File* script_fil | |||||||
|             if(bad_usb->buf_len == 0) return SCRIPT_STATE_END; |             if(bad_usb->buf_len == 0) return SCRIPT_STATE_END; | ||||||
|         } |         } | ||||||
|         for(uint8_t i = bad_usb->buf_start; i < (bad_usb->buf_start + bad_usb->buf_len); i++) { |         for(uint8_t i = bad_usb->buf_start; i < (bad_usb->buf_start + bad_usb->buf_len); i++) { | ||||||
|             if(bad_usb->file_buf[i] == '\n' && string_size(bad_usb->line) > 0) { |             if(bad_usb->file_buf[i] == '\n' && furi_string_size(bad_usb->line) > 0) { | ||||||
|                 bad_usb->st.line_cur++; |                 bad_usb->st.line_cur++; | ||||||
|                 bad_usb->buf_len = bad_usb->buf_len + bad_usb->buf_start - (i + 1); |                 bad_usb->buf_len = bad_usb->buf_len + bad_usb->buf_start - (i + 1); | ||||||
|                 bad_usb->buf_start = i + 1; |                 bad_usb->buf_start = i + 1; | ||||||
|                 delay_val = ducky_parse_line(bad_usb, bad_usb->line); |                 delay_val = ducky_parse_line( | ||||||
|  |                     bad_usb, bad_usb->line, bad_usb->st.error, sizeof(bad_usb->st.error)); | ||||||
|  | 
 | ||||||
|                 if(delay_val < 0) { |                 if(delay_val < 0) { | ||||||
|                     bad_usb->st.error_line = bad_usb->st.line_cur; |                     bad_usb->st.error_line = bad_usb->st.line_cur; | ||||||
|                     FURI_LOG_E(WORKER_TAG, "Unknown command at line %lu", bad_usb->st.line_cur); |                     FURI_LOG_E(WORKER_TAG, "Unknown command at line %u", bad_usb->st.line_cur); | ||||||
|                     return SCRIPT_STATE_ERROR; |                     return SCRIPT_STATE_ERROR; | ||||||
|                 } else { |                 } else { | ||||||
|                     return (delay_val + bad_usb->defdelay); |                     return (delay_val + bad_usb->defdelay); | ||||||
|                 } |                 } | ||||||
|             } else { |             } else { | ||||||
|                 string_push_back(bad_usb->line, bad_usb->file_buf[i]); |                 furi_string_push_back(bad_usb->line, bad_usb->file_buf[i]); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         bad_usb->buf_len = 0; |         bad_usb->buf_len = 0; | ||||||
| @ -456,8 +495,8 @@ static int32_t bad_usb_worker(void* context) { | |||||||
| 
 | 
 | ||||||
|     FURI_LOG_I(WORKER_TAG, "Init"); |     FURI_LOG_I(WORKER_TAG, "Init"); | ||||||
|     File* script_file = storage_file_alloc(furi_record_open(RECORD_STORAGE)); |     File* script_file = storage_file_alloc(furi_record_open(RECORD_STORAGE)); | ||||||
|     string_init(bad_usb->line); |     bad_usb->line = furi_string_alloc(); | ||||||
|     string_init(bad_usb->line_prev); |     bad_usb->line_prev = furi_string_alloc(); | ||||||
| 
 | 
 | ||||||
|     furi_hal_hid_set_state_callback(bad_usb_hid_state_callback, bad_usb); |     furi_hal_hid_set_state_callback(bad_usb_hid_state_callback, bad_usb); | ||||||
| 
 | 
 | ||||||
| @ -465,7 +504,7 @@ static int32_t bad_usb_worker(void* context) { | |||||||
|         if(worker_state == BadUsbStateInit) { // State: initialization
 |         if(worker_state == BadUsbStateInit) { // State: initialization
 | ||||||
|             if(storage_file_open( |             if(storage_file_open( | ||||||
|                    script_file, |                    script_file, | ||||||
|                    string_get_cstr(bad_usb->file_path), |                    furi_string_get_cstr(bad_usb->file_path), | ||||||
|                    FSAM_READ, |                    FSAM_READ, | ||||||
|                    FSOM_OPEN_EXISTING)) { |                    FSOM_OPEN_EXISTING)) { | ||||||
|                 if((ducky_script_preload(bad_usb, script_file)) && (bad_usb->st.line_nb > 0)) { |                 if((ducky_script_preload(bad_usb, script_file)) && (bad_usb->st.line_nb > 0)) { | ||||||
| @ -577,22 +616,23 @@ static int32_t bad_usb_worker(void* context) { | |||||||
| 
 | 
 | ||||||
|     storage_file_close(script_file); |     storage_file_close(script_file); | ||||||
|     storage_file_free(script_file); |     storage_file_free(script_file); | ||||||
|     string_clear(bad_usb->line); |     furi_string_free(bad_usb->line); | ||||||
|     string_clear(bad_usb->line_prev); |     furi_string_free(bad_usb->line_prev); | ||||||
| 
 | 
 | ||||||
|     FURI_LOG_I(WORKER_TAG, "End"); |     FURI_LOG_I(WORKER_TAG, "End"); | ||||||
| 
 | 
 | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| BadUsbScript* bad_usb_script_open(string_t file_path) { | BadUsbScript* bad_usb_script_open(FuriString* file_path) { | ||||||
|     furi_assert(file_path); |     furi_assert(file_path); | ||||||
| 
 | 
 | ||||||
|     BadUsbScript* bad_usb = malloc(sizeof(BadUsbScript)); |     BadUsbScript* bad_usb = malloc(sizeof(BadUsbScript)); | ||||||
|     string_init(bad_usb->file_path); |     bad_usb->file_path = furi_string_alloc(); | ||||||
|     string_set(bad_usb->file_path, file_path); |     furi_string_set(bad_usb->file_path, file_path); | ||||||
| 
 | 
 | ||||||
|     bad_usb->st.state = BadUsbStateInit; |     bad_usb->st.state = BadUsbStateInit; | ||||||
|  |     bad_usb->st.error[0] = '\0'; | ||||||
| 
 | 
 | ||||||
|     bad_usb->thread = furi_thread_alloc(); |     bad_usb->thread = furi_thread_alloc(); | ||||||
|     furi_thread_set_name(bad_usb->thread, "BadUsbWorker"); |     furi_thread_set_name(bad_usb->thread, "BadUsbWorker"); | ||||||
| @ -609,7 +649,7 @@ void bad_usb_script_close(BadUsbScript* bad_usb) { | |||||||
|     furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtEnd); |     furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtEnd); | ||||||
|     furi_thread_join(bad_usb->thread); |     furi_thread_join(bad_usb->thread); | ||||||
|     furi_thread_free(bad_usb->thread); |     furi_thread_free(bad_usb->thread); | ||||||
|     string_clear(bad_usb->file_path); |     furi_string_free(bad_usb->file_path); | ||||||
|     free(bad_usb); |     free(bad_usb); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -5,7 +5,6 @@ extern "C" { | |||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| #include <m-string.h> |  | ||||||
| 
 | 
 | ||||||
| typedef struct BadUsbScript BadUsbScript; | typedef struct BadUsbScript BadUsbScript; | ||||||
| 
 | 
 | ||||||
| @ -26,9 +25,10 @@ typedef struct { | |||||||
|     uint16_t line_nb; |     uint16_t line_nb; | ||||||
|     uint32_t delay_remain; |     uint32_t delay_remain; | ||||||
|     uint16_t error_line; |     uint16_t error_line; | ||||||
|  |     char error[64]; | ||||||
| } BadUsbState; | } BadUsbState; | ||||||
| 
 | 
 | ||||||
| BadUsbScript* bad_usb_script_open(string_t file_path); | BadUsbScript* bad_usb_script_open(FuriString* file_path); | ||||||
| 
 | 
 | ||||||
| void bad_usb_script_close(BadUsbScript* bad_usb); | void bad_usb_script_close(BadUsbScript* bad_usb); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -2,7 +2,6 @@ | |||||||
| #include "../bad_usb_app_i.h" | #include "../bad_usb_app_i.h" | ||||||
| #include "../views/bad_usb_view.h" | #include "../views/bad_usb_view.h" | ||||||
| #include "furi_hal.h" | #include "furi_hal.h" | ||||||
| #include "m-string.h" |  | ||||||
| #include "toolbox/path.h" | #include "toolbox/path.h" | ||||||
| 
 | 
 | ||||||
| void bad_usb_scene_work_ok_callback(InputType type, void* context) { | void bad_usb_scene_work_ok_callback(InputType type, void* context) { | ||||||
| @ -27,14 +26,14 @@ bool bad_usb_scene_work_on_event(void* context, SceneManagerEvent event) { | |||||||
| void bad_usb_scene_work_on_enter(void* context) { | void bad_usb_scene_work_on_enter(void* context) { | ||||||
|     BadUsbApp* app = context; |     BadUsbApp* app = context; | ||||||
| 
 | 
 | ||||||
|     string_t file_name; |     FuriString* file_name; | ||||||
|     string_init(file_name); |     file_name = furi_string_alloc(); | ||||||
| 
 | 
 | ||||||
|     path_extract_filename(app->file_path, file_name, true); |     path_extract_filename(app->file_path, file_name, true); | ||||||
|     bad_usb_set_file_name(app->bad_usb_view, string_get_cstr(file_name)); |     bad_usb_set_file_name(app->bad_usb_view, furi_string_get_cstr(file_name)); | ||||||
|     app->bad_usb_script = bad_usb_script_open(app->file_path); |     app->bad_usb_script = bad_usb_script_open(app->file_path); | ||||||
| 
 | 
 | ||||||
|     string_clear(file_name); |     furi_string_free(file_name); | ||||||
| 
 | 
 | ||||||
|     bad_usb_set_state(app->bad_usb_view, bad_usb_script_get_state(app->bad_usb_script)); |     bad_usb_set_state(app->bad_usb_view, bad_usb_script_get_state(app->bad_usb_script)); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -19,12 +19,12 @@ typedef struct { | |||||||
| static void bad_usb_draw_callback(Canvas* canvas, void* _model) { | static void bad_usb_draw_callback(Canvas* canvas, void* _model) { | ||||||
|     BadUsbModel* model = _model; |     BadUsbModel* model = _model; | ||||||
| 
 | 
 | ||||||
|     string_t disp_str; |     FuriString* disp_str; | ||||||
|     string_init_set_str(disp_str, model->file_name); |     disp_str = furi_string_alloc_set(model->file_name); | ||||||
|     elements_string_fit_width(canvas, disp_str, 128 - 2); |     elements_string_fit_width(canvas, disp_str, 128 - 2); | ||||||
|     canvas_set_font(canvas, FontSecondary); |     canvas_set_font(canvas, FontSecondary); | ||||||
|     canvas_draw_str(canvas, 2, 8, string_get_cstr(disp_str)); |     canvas_draw_str(canvas, 2, 8, furi_string_get_cstr(disp_str)); | ||||||
|     string_reset(disp_str); |     furi_string_reset(disp_str); | ||||||
| 
 | 
 | ||||||
|     canvas_draw_icon(canvas, 22, 20, &I_UsbTree_48x22); |     canvas_draw_icon(canvas, 22, 20, &I_UsbTree_48x22); | ||||||
| 
 | 
 | ||||||
| @ -49,10 +49,11 @@ static void bad_usb_draw_callback(Canvas* canvas, void* _model) { | |||||||
|         canvas_set_font(canvas, FontPrimary); |         canvas_set_font(canvas, FontPrimary); | ||||||
|         canvas_draw_str_aligned(canvas, 127, 33, AlignRight, AlignBottom, "ERROR:"); |         canvas_draw_str_aligned(canvas, 127, 33, AlignRight, AlignBottom, "ERROR:"); | ||||||
|         canvas_set_font(canvas, FontSecondary); |         canvas_set_font(canvas, FontSecondary); | ||||||
|         string_printf(disp_str, "line %u", model->state.error_line); |         furi_string_printf(disp_str, "line %u", model->state.error_line); | ||||||
|         canvas_draw_str_aligned( |         canvas_draw_str_aligned( | ||||||
|             canvas, 127, 46, AlignRight, AlignBottom, string_get_cstr(disp_str)); |             canvas, 127, 46, AlignRight, AlignBottom, furi_string_get_cstr(disp_str)); | ||||||
|         string_reset(disp_str); |         furi_string_reset(disp_str); | ||||||
|  |         canvas_draw_str_aligned(canvas, 127, 56, AlignRight, AlignBottom, model->state.error); | ||||||
|     } else if(model->state.state == BadUsbStateIdle) { |     } else if(model->state.state == BadUsbStateIdle) { | ||||||
|         canvas_draw_icon(canvas, 4, 22, &I_Smile_18x18); |         canvas_draw_icon(canvas, 4, 22, &I_Smile_18x18); | ||||||
|         canvas_set_font(canvas, FontBigNumbers); |         canvas_set_font(canvas, FontBigNumbers); | ||||||
| @ -65,16 +66,17 @@ static void bad_usb_draw_callback(Canvas* canvas, void* _model) { | |||||||
|             canvas_draw_icon(canvas, 4, 19, &I_EviSmile2_18x21); |             canvas_draw_icon(canvas, 4, 19, &I_EviSmile2_18x21); | ||||||
|         } |         } | ||||||
|         canvas_set_font(canvas, FontBigNumbers); |         canvas_set_font(canvas, FontBigNumbers); | ||||||
|         string_printf(disp_str, "%u", ((model->state.line_cur - 1) * 100) / model->state.line_nb); |         furi_string_printf( | ||||||
|  |             disp_str, "%u", ((model->state.line_cur - 1) * 100) / model->state.line_nb); | ||||||
|         canvas_draw_str_aligned( |         canvas_draw_str_aligned( | ||||||
|             canvas, 114, 36, AlignRight, AlignBottom, string_get_cstr(disp_str)); |             canvas, 114, 36, AlignRight, AlignBottom, furi_string_get_cstr(disp_str)); | ||||||
|         string_reset(disp_str); |         furi_string_reset(disp_str); | ||||||
|         canvas_draw_icon(canvas, 117, 22, &I_Percent_10x14); |         canvas_draw_icon(canvas, 117, 22, &I_Percent_10x14); | ||||||
|     } else if(model->state.state == BadUsbStateDone) { |     } else if(model->state.state == BadUsbStateDone) { | ||||||
|         canvas_draw_icon(canvas, 4, 19, &I_EviSmile1_18x21); |         canvas_draw_icon(canvas, 4, 19, &I_EviSmile1_18x21); | ||||||
|         canvas_set_font(canvas, FontBigNumbers); |         canvas_set_font(canvas, FontBigNumbers); | ||||||
|         canvas_draw_str_aligned(canvas, 114, 36, AlignRight, AlignBottom, "100"); |         canvas_draw_str_aligned(canvas, 114, 36, AlignRight, AlignBottom, "100"); | ||||||
|         string_reset(disp_str); |         furi_string_reset(disp_str); | ||||||
|         canvas_draw_icon(canvas, 117, 22, &I_Percent_10x14); |         canvas_draw_icon(canvas, 117, 22, &I_Percent_10x14); | ||||||
|     } else if(model->state.state == BadUsbStateDelay) { |     } else if(model->state.state == BadUsbStateDelay) { | ||||||
|         if(model->anim_frame == 0) { |         if(model->anim_frame == 0) { | ||||||
| @ -83,21 +85,22 @@ static void bad_usb_draw_callback(Canvas* canvas, void* _model) { | |||||||
|             canvas_draw_icon(canvas, 4, 19, &I_EviWaiting2_18x21); |             canvas_draw_icon(canvas, 4, 19, &I_EviWaiting2_18x21); | ||||||
|         } |         } | ||||||
|         canvas_set_font(canvas, FontBigNumbers); |         canvas_set_font(canvas, FontBigNumbers); | ||||||
|         string_printf(disp_str, "%u", ((model->state.line_cur - 1) * 100) / model->state.line_nb); |         furi_string_printf( | ||||||
|  |             disp_str, "%u", ((model->state.line_cur - 1) * 100) / model->state.line_nb); | ||||||
|         canvas_draw_str_aligned( |         canvas_draw_str_aligned( | ||||||
|             canvas, 114, 36, AlignRight, AlignBottom, string_get_cstr(disp_str)); |             canvas, 114, 36, AlignRight, AlignBottom, furi_string_get_cstr(disp_str)); | ||||||
|         string_reset(disp_str); |         furi_string_reset(disp_str); | ||||||
|         canvas_draw_icon(canvas, 117, 22, &I_Percent_10x14); |         canvas_draw_icon(canvas, 117, 22, &I_Percent_10x14); | ||||||
|         canvas_set_font(canvas, FontSecondary); |         canvas_set_font(canvas, FontSecondary); | ||||||
|         string_printf(disp_str, "delay %us", model->state.delay_remain); |         furi_string_printf(disp_str, "delay %lus", model->state.delay_remain); | ||||||
|         canvas_draw_str_aligned( |         canvas_draw_str_aligned( | ||||||
|             canvas, 127, 46, AlignRight, AlignBottom, string_get_cstr(disp_str)); |             canvas, 127, 46, AlignRight, AlignBottom, furi_string_get_cstr(disp_str)); | ||||||
|         string_reset(disp_str); |         furi_string_reset(disp_str); | ||||||
|     } else { |     } else { | ||||||
|         canvas_draw_icon(canvas, 4, 22, &I_Clock_18x18); |         canvas_draw_icon(canvas, 4, 22, &I_Clock_18x18); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     string_clear(disp_str); |     furi_string_free(disp_str); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static bool bad_usb_input_callback(InputEvent* event, void* context) { | static bool bad_usb_input_callback(InputEvent* event, void* context) { | ||||||
| @ -143,29 +146,33 @@ void bad_usb_set_ok_callback(BadUsb* bad_usb, BadUsbOkCallback callback, void* c | |||||||
|     furi_assert(bad_usb); |     furi_assert(bad_usb); | ||||||
|     furi_assert(callback); |     furi_assert(callback); | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         bad_usb->view, (BadUsbModel * model) { |         bad_usb->view, | ||||||
|  |         BadUsbModel * model, | ||||||
|  |         { | ||||||
|             UNUSED(model); |             UNUSED(model); | ||||||
|             bad_usb->callback = callback; |             bad_usb->callback = callback; | ||||||
|             bad_usb->context = context; |             bad_usb->context = context; | ||||||
|             return true; |         }, | ||||||
|         }); |         true); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void bad_usb_set_file_name(BadUsb* bad_usb, const char* name) { | void bad_usb_set_file_name(BadUsb* bad_usb, const char* name) { | ||||||
|     furi_assert(name); |     furi_assert(name); | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         bad_usb->view, (BadUsbModel * model) { |         bad_usb->view, | ||||||
|             strlcpy(model->file_name, name, MAX_NAME_LEN); |         BadUsbModel * model, | ||||||
|             return true; |         { strlcpy(model->file_name, name, MAX_NAME_LEN); }, | ||||||
|         }); |         true); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void bad_usb_set_state(BadUsb* bad_usb, BadUsbState* st) { | void bad_usb_set_state(BadUsb* bad_usb, BadUsbState* st) { | ||||||
|     furi_assert(st); |     furi_assert(st); | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         bad_usb->view, (BadUsbModel * model) { |         bad_usb->view, | ||||||
|  |         BadUsbModel * model, | ||||||
|  |         { | ||||||
|             memcpy(&(model->state), st, sizeof(BadUsbState)); |             memcpy(&(model->state), st, sizeof(BadUsbState)); | ||||||
|             model->anim_frame ^= 1; |             model->anim_frame ^= 1; | ||||||
|             return true; |         }, | ||||||
|         }); |         true); | ||||||
| } | } | ||||||
|  | |||||||
| @ -3,6 +3,7 @@ App( | |||||||
|     name="Applications", |     name="Applications", | ||||||
|     apptype=FlipperAppType.APP, |     apptype=FlipperAppType.APP, | ||||||
|     entry_point="fap_loader_app", |     entry_point="fap_loader_app", | ||||||
|  |     cdefines=["APP_FAP_LOADER"], | ||||||
|     requires=[ |     requires=[ | ||||||
|         "gui", |         "gui", | ||||||
|         "storage", |         "storage", | ||||||
|  | |||||||
| @ -31,7 +31,7 @@ bool elf_resolve_from_hashtable(const char* name, Elf32_Addr* address) { | |||||||
| 
 | 
 | ||||||
|     auto find_res = std::lower_bound(elf_api_table.cbegin(), elf_api_table.cend(), key); |     auto find_res = std::lower_bound(elf_api_table.cbegin(), elf_api_table.cend(), key); | ||||||
|     if((find_res == elf_api_table.cend() || (find_res->hash != gnu_sym_hash))) { |     if((find_res == elf_api_table.cend() || (find_res->hash != gnu_sym_hash))) { | ||||||
|         FURI_LOG_W(TAG, "Cant find symbol '%s' (hash %x)!", name, gnu_sym_hash); |         FURI_LOG_W(TAG, "Cant find symbol '%s' (hash %lx)!", name, gnu_sym_hash); | ||||||
|         result = false; |         result = false; | ||||||
|     } else { |     } else { | ||||||
|         result = true; |         result = true; | ||||||
|  | |||||||
| @ -1,34 +1,34 @@ | |||||||
| #include <furi.h> | #include <furi.h> | ||||||
| #include <gui/gui.h> | #include <gui/gui.h> | ||||||
| #include <gui/view_dispatcher.h> | #include <gui/view_dispatcher.h> | ||||||
| #include <gui/modules/loading.h> |  | ||||||
| #include <storage/storage.h> | #include <storage/storage.h> | ||||||
|  | #include <gui/modules/loading.h> | ||||||
| #include <dialogs/dialogs.h> | #include <dialogs/dialogs.h> | ||||||
| #include "elf_cpp/elf_hashtable.h" |  | ||||||
| #include <flipper_application/flipper_application.h> | #include <flipper_application/flipper_application.h> | ||||||
|  | #include "elf_cpp/elf_hashtable.h" | ||||||
|  | #include "fap_loader_app.h" | ||||||
| 
 | 
 | ||||||
| #define TAG "fap_loader_app" | #define TAG "fap_loader_app" | ||||||
| 
 | 
 | ||||||
| typedef struct { | struct FapLoader { | ||||||
|     FlipperApplication* app; |     FlipperApplication* app; | ||||||
|     Storage* storage; |     Storage* storage; | ||||||
|     DialogsApp* dialogs; |     DialogsApp* dialogs; | ||||||
|     Gui* gui; |     Gui* gui; | ||||||
|     string_t fap_path; |     FuriString* fap_path; | ||||||
| 
 |  | ||||||
|     ViewDispatcher* view_dispatcher; |     ViewDispatcher* view_dispatcher; | ||||||
|     Loading* loading; |     Loading* loading; | ||||||
| } FapLoader; | }; | ||||||
| 
 | 
 | ||||||
| static bool | bool fap_loader_load_name_and_icon( | ||||||
|     fap_loader_item_callback(string_t path, void* context, uint8_t** icon_ptr, string_t item_name) { |     FuriString* path, | ||||||
|     FapLoader* loader = context; |     Storage* storage, | ||||||
|     furi_assert(loader); |     uint8_t** icon_ptr, | ||||||
| 
 |     FuriString* item_name) { | ||||||
|     FlipperApplication* app = flipper_application_alloc(loader->storage, &hashtable_api_interface); |     FlipperApplication* app = flipper_application_alloc(storage, &hashtable_api_interface); | ||||||
| 
 | 
 | ||||||
|     FlipperApplicationPreloadStatus preload_res = |     FlipperApplicationPreloadStatus preload_res = | ||||||
|         flipper_application_preload_manifest(app, string_get_cstr(path)); |         flipper_application_preload_manifest(app, furi_string_get_cstr(path)); | ||||||
| 
 | 
 | ||||||
|     bool load_success = false; |     bool load_success = false; | ||||||
| 
 | 
 | ||||||
| @ -37,10 +37,10 @@ static bool | |||||||
|         if(manifest->has_icon) { |         if(manifest->has_icon) { | ||||||
|             memcpy(*icon_ptr, manifest->icon, FAP_MANIFEST_MAX_ICON_SIZE); |             memcpy(*icon_ptr, manifest->icon, FAP_MANIFEST_MAX_ICON_SIZE); | ||||||
|         } |         } | ||||||
|         string_set_str(item_name, manifest->name); |         furi_string_set(item_name, manifest->name); | ||||||
|         load_success = true; |         load_success = true; | ||||||
|     } else { |     } else { | ||||||
|         FURI_LOG_E(TAG, "FAP Loader failed to preload %s", string_get_cstr(path)); |         FURI_LOG_E(TAG, "FAP Loader failed to preload %s", furi_string_get_cstr(path)); | ||||||
|         load_success = false; |         load_success = false; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -48,30 +48,41 @@ static bool | |||||||
|     return load_success; |     return load_success; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static bool fap_loader_item_callback( | ||||||
|  |     FuriString* path, | ||||||
|  |     void* context, | ||||||
|  |     uint8_t** icon_ptr, | ||||||
|  |     FuriString* item_name) { | ||||||
|  |     FapLoader* fap_loader = context; | ||||||
|  |     furi_assert(fap_loader); | ||||||
|  |     return fap_loader_load_name_and_icon(path, fap_loader->storage, icon_ptr, item_name); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static bool fap_loader_run_selected_app(FapLoader* loader) { | static bool fap_loader_run_selected_app(FapLoader* loader) { | ||||||
|     furi_assert(loader); |     furi_assert(loader); | ||||||
| 
 | 
 | ||||||
|     string_t error_message; |     FuriString* error_message; | ||||||
| 
 | 
 | ||||||
|     string_init_set(error_message, "unknown error"); |     error_message = furi_string_alloc_set("unknown error"); | ||||||
| 
 | 
 | ||||||
|     bool file_selected = false; |     bool file_selected = false; | ||||||
|     bool show_error = true; |     bool show_error = true; | ||||||
|     do { |     do { | ||||||
|         file_selected = true; |         file_selected = true; | ||||||
|         loader->app = flipper_application_alloc(loader->storage, &hashtable_api_interface); |         loader->app = flipper_application_alloc(loader->storage, &hashtable_api_interface); | ||||||
|  |         size_t start = furi_get_tick(); | ||||||
| 
 | 
 | ||||||
|         FURI_LOG_I(TAG, "FAP Loader is loading %s", string_get_cstr(loader->fap_path)); |         FURI_LOG_I(TAG, "FAP Loader is loading %s", furi_string_get_cstr(loader->fap_path)); | ||||||
| 
 | 
 | ||||||
|         FlipperApplicationPreloadStatus preload_res = |         FlipperApplicationPreloadStatus preload_res = | ||||||
|             flipper_application_preload(loader->app, string_get_cstr(loader->fap_path)); |             flipper_application_preload(loader->app, furi_string_get_cstr(loader->fap_path)); | ||||||
|         if(preload_res != FlipperApplicationPreloadStatusSuccess) { |         if(preload_res != FlipperApplicationPreloadStatusSuccess) { | ||||||
|             const char* err_msg = flipper_application_preload_status_to_string(preload_res); |             const char* err_msg = flipper_application_preload_status_to_string(preload_res); | ||||||
|             string_printf(error_message, "Preload failed: %s", err_msg); |             furi_string_printf(error_message, "Preload failed: %s", err_msg); | ||||||
|             FURI_LOG_E( |             FURI_LOG_E( | ||||||
|                 TAG, |                 TAG, | ||||||
|                 "FAP Loader failed to preload %s: %s", |                 "FAP Loader failed to preload %s: %s", | ||||||
|                 string_get_cstr(loader->fap_path), |                 furi_string_get_cstr(loader->fap_path), | ||||||
|                 err_msg); |                 err_msg); | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
| @ -80,16 +91,17 @@ static bool fap_loader_run_selected_app(FapLoader* loader) { | |||||||
|         FlipperApplicationLoadStatus load_status = flipper_application_map_to_memory(loader->app); |         FlipperApplicationLoadStatus load_status = flipper_application_map_to_memory(loader->app); | ||||||
|         if(load_status != FlipperApplicationLoadStatusSuccess) { |         if(load_status != FlipperApplicationLoadStatusSuccess) { | ||||||
|             const char* err_msg = flipper_application_load_status_to_string(load_status); |             const char* err_msg = flipper_application_load_status_to_string(load_status); | ||||||
|             string_printf(error_message, "Load failed: %s", err_msg); |             furi_string_printf(error_message, "Load failed: %s", err_msg); | ||||||
|             FURI_LOG_E( |             FURI_LOG_E( | ||||||
|                 TAG, |                 TAG, | ||||||
|                 "FAP Loader failed to map to memory %s: %s", |                 "FAP Loader failed to map to memory %s: %s", | ||||||
|                 string_get_cstr(loader->fap_path), |                 furi_string_get_cstr(loader->fap_path), | ||||||
|                 err_msg); |                 err_msg); | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         FURI_LOG_I(TAG, "FAP Loader is staring app"); |         FURI_LOG_I(TAG, "Loaded in %ums", (size_t)(furi_get_tick() - start)); | ||||||
|  |         FURI_LOG_I(TAG, "FAP Loader is starting app"); | ||||||
| 
 | 
 | ||||||
|         FuriThread* thread = flipper_application_spawn(loader->app, NULL); |         FuriThread* thread = flipper_application_spawn(loader->app, NULL); | ||||||
|         furi_thread_start(thread); |         furi_thread_start(thread); | ||||||
| @ -106,19 +118,19 @@ static bool fap_loader_run_selected_app(FapLoader* loader) { | |||||||
|         dialog_message_set_header(message, "Error", 64, 0, AlignCenter, AlignTop); |         dialog_message_set_header(message, "Error", 64, 0, AlignCenter, AlignTop); | ||||||
|         dialog_message_set_buttons(message, NULL, NULL, NULL); |         dialog_message_set_buttons(message, NULL, NULL, NULL); | ||||||
| 
 | 
 | ||||||
|         string_t buffer; |         FuriString* buffer; | ||||||
|         string_init(buffer); |         buffer = furi_string_alloc(); | ||||||
|         string_printf(buffer, "%s", string_get_cstr(error_message)); |         furi_string_printf(buffer, "%s", furi_string_get_cstr(error_message)); | ||||||
|         string_replace_str(buffer, ":", "\n"); |         furi_string_replace(buffer, ":", "\n"); | ||||||
|         dialog_message_set_text( |         dialog_message_set_text( | ||||||
|             message, string_get_cstr(buffer), 64, 32, AlignCenter, AlignCenter); |             message, furi_string_get_cstr(buffer), 64, 32, AlignCenter, AlignCenter); | ||||||
| 
 | 
 | ||||||
|         dialog_message_show(loader->dialogs, message); |         dialog_message_show(loader->dialogs, message); | ||||||
|         dialog_message_free(message); |         dialog_message_free(message); | ||||||
|         string_clear(buffer); |         furi_string_free(buffer); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     string_clear(error_message); |     furi_string_free(error_message); | ||||||
| 
 | 
 | ||||||
|     if(file_selected) { |     if(file_selected) { | ||||||
|         flipper_application_free(loader->app); |         flipper_application_free(loader->app); | ||||||
| @ -131,7 +143,7 @@ static bool fap_loader_select_app(FapLoader* loader) { | |||||||
|     const DialogsFileBrowserOptions browser_options = { |     const DialogsFileBrowserOptions browser_options = { | ||||||
|         .extension = ".fap", |         .extension = ".fap", | ||||||
|         .skip_assets = true, |         .skip_assets = true, | ||||||
|         .icon = &I_badusb_10px, |         .icon = &I_unknown_10px, | ||||||
|         .hide_ext = true, |         .hide_ext = true, | ||||||
|         .item_loader_callback = fap_loader_item_callback, |         .item_loader_callback = fap_loader_item_callback, | ||||||
|         .item_loader_context = loader, |         .item_loader_context = loader, | ||||||
| @ -141,39 +153,45 @@ static bool fap_loader_select_app(FapLoader* loader) { | |||||||
|         loader->dialogs, loader->fap_path, loader->fap_path, &browser_options); |         loader->dialogs, loader->fap_path, loader->fap_path, &browser_options); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int32_t fap_loader_app(void* p) { | static FapLoader* fap_loader_alloc(const char* path) { | ||||||
|     FapLoader* loader = malloc(sizeof(FapLoader)); |     FapLoader* loader = malloc(sizeof(FapLoader)); | ||||||
|  |     loader->fap_path = furi_string_alloc_set(path); | ||||||
|     loader->storage = furi_record_open(RECORD_STORAGE); |     loader->storage = furi_record_open(RECORD_STORAGE); | ||||||
|     loader->dialogs = furi_record_open(RECORD_DIALOGS); |     loader->dialogs = furi_record_open(RECORD_DIALOGS); | ||||||
|     loader->gui = furi_record_open(RECORD_GUI); |     loader->gui = furi_record_open(RECORD_GUI); | ||||||
| 
 |  | ||||||
|     loader->view_dispatcher = view_dispatcher_alloc(); |     loader->view_dispatcher = view_dispatcher_alloc(); | ||||||
|     loader->loading = loading_alloc(); |     loader->loading = loading_alloc(); | ||||||
| 
 |  | ||||||
|     view_dispatcher_attach_to_gui( |     view_dispatcher_attach_to_gui( | ||||||
|         loader->view_dispatcher, loader->gui, ViewDispatcherTypeFullscreen); |         loader->view_dispatcher, loader->gui, ViewDispatcherTypeFullscreen); | ||||||
|     view_dispatcher_add_view(loader->view_dispatcher, 0, loading_get_view(loader->loading)); |     view_dispatcher_add_view(loader->view_dispatcher, 0, loading_get_view(loader->loading)); | ||||||
|  |     return loader; | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
|  | static void fap_loader_free(FapLoader* loader) { | ||||||
|  |     view_dispatcher_remove_view(loader->view_dispatcher, 0); | ||||||
|  |     loading_free(loader->loading); | ||||||
|  |     view_dispatcher_free(loader->view_dispatcher); | ||||||
|  |     furi_string_free(loader->fap_path); | ||||||
|  |     furi_record_close(RECORD_GUI); | ||||||
|  |     furi_record_close(RECORD_DIALOGS); | ||||||
|  |     furi_record_close(RECORD_STORAGE); | ||||||
|  |     free(loader); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int32_t fap_loader_app(void* p) { | ||||||
|  |     FapLoader* loader; | ||||||
|     if(p) { |     if(p) { | ||||||
|         string_init_set(loader->fap_path, (const char*)p); |         loader = fap_loader_alloc((const char*)p); | ||||||
|  |         view_dispatcher_switch_to_view(loader->view_dispatcher, 0); | ||||||
|         fap_loader_run_selected_app(loader); |         fap_loader_run_selected_app(loader); | ||||||
|     } else { |     } else { | ||||||
|         string_init_set(loader->fap_path, EXT_PATH("apps")); |         loader = fap_loader_alloc(EXT_PATH("apps")); | ||||||
| 
 |  | ||||||
|         while(fap_loader_select_app(loader)) { |         while(fap_loader_select_app(loader)) { | ||||||
|             view_dispatcher_switch_to_view(loader->view_dispatcher, 0); |             view_dispatcher_switch_to_view(loader->view_dispatcher, 0); | ||||||
|             fap_loader_run_selected_app(loader); |             fap_loader_run_selected_app(loader); | ||||||
|         }; |         }; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     view_dispatcher_remove_view(loader->view_dispatcher, 0); |     fap_loader_free(loader); | ||||||
|     loading_free(loader->loading); |  | ||||||
|     view_dispatcher_free(loader->view_dispatcher); |  | ||||||
| 
 |  | ||||||
|     string_clear(loader->fap_path); |  | ||||||
|     furi_record_close(RECORD_GUI); |  | ||||||
|     furi_record_close(RECORD_DIALOGS); |  | ||||||
|     furi_record_close(RECORD_STORAGE); |  | ||||||
|     free(loader); |  | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										27
									
								
								applications/main/fap_loader/fap_loader_app.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								applications/main/fap_loader/fap_loader_app.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,27 @@ | |||||||
|  | #pragma once | ||||||
|  | #include <storage/storage.h> | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | typedef struct FapLoader FapLoader; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * @brief Load name and icon from FAP file. | ||||||
|  |  *  | ||||||
|  |  * @param path Path to FAP file. | ||||||
|  |  * @param storage Storage instance. | ||||||
|  |  * @param icon_ptr Icon pointer. | ||||||
|  |  * @param item_name Application name. | ||||||
|  |  * @return true if icon and name were loaded successfully. | ||||||
|  |  */ | ||||||
|  | bool fap_loader_load_name_and_icon( | ||||||
|  |     FuriString* path, | ||||||
|  |     Storage* storage, | ||||||
|  |     uint8_t** icon_ptr, | ||||||
|  |     FuriString* item_name); | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } | ||||||
|  | #endif | ||||||
| @ -1,6 +1,7 @@ | |||||||
| #include "../gpio_app_i.h" | #include "../gpio_app_i.h" | ||||||
| #include "furi_hal_power.h" | #include "furi_hal_power.h" | ||||||
| #include "furi_hal_usb.h" | #include "furi_hal_usb.h" | ||||||
|  | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| enum GpioItem { | enum GpioItem { | ||||||
|     GpioItemUsbUart, |     GpioItemUsbUart, | ||||||
| @ -88,6 +89,7 @@ bool gpio_scene_start_on_event(void* context, SceneManagerEvent event) { | |||||||
|         } else if(event.event == GpioStartEventUsbUart) { |         } else if(event.event == GpioStartEventUsbUart) { | ||||||
|             scene_manager_set_scene_state(app->scene_manager, GpioSceneStart, GpioItemUsbUart); |             scene_manager_set_scene_state(app->scene_manager, GpioSceneStart, GpioItemUsbUart); | ||||||
|             if(!furi_hal_usb_is_locked()) { |             if(!furi_hal_usb_is_locked()) { | ||||||
|  |                 DOLPHIN_DEED(DolphinDeedGpioUartBridge); | ||||||
|                 scene_manager_next_scene(app->scene_manager, GpioSceneUsbUart); |                 scene_manager_next_scene(app->scene_manager, GpioSceneUsbUart); | ||||||
|             } else { |             } else { | ||||||
|                 scene_manager_next_scene(app->scene_manager, GpioSceneUsbUartCloseRpc); |                 scene_manager_next_scene(app->scene_manager, GpioSceneUsbUartCloseRpc); | ||||||
|  | |||||||
| @ -1,6 +1,5 @@ | |||||||
| #include "usb_uart_bridge.h" | #include "usb_uart_bridge.h" | ||||||
| #include "furi_hal.h" | #include "furi_hal.h" | ||||||
| #include <stream_buffer.h> |  | ||||||
| #include <furi_hal_usb_cdc.h> | #include <furi_hal_usb_cdc.h> | ||||||
| #include "usb_cdc.h" | #include "usb_cdc.h" | ||||||
| #include "cli/cli_vcp.h" | #include "cli/cli_vcp.h" | ||||||
| @ -43,7 +42,7 @@ struct UsbUartBridge { | |||||||
|     FuriThread* thread; |     FuriThread* thread; | ||||||
|     FuriThread* tx_thread; |     FuriThread* tx_thread; | ||||||
| 
 | 
 | ||||||
|     StreamBufferHandle_t rx_stream; |     FuriStreamBuffer* rx_stream; | ||||||
| 
 | 
 | ||||||
|     FuriMutex* usb_mutex; |     FuriMutex* usb_mutex; | ||||||
| 
 | 
 | ||||||
| @ -74,12 +73,10 @@ static int32_t usb_uart_tx_thread(void* context); | |||||||
| 
 | 
 | ||||||
| static void usb_uart_on_irq_cb(UartIrqEvent ev, uint8_t data, void* context) { | static void usb_uart_on_irq_cb(UartIrqEvent ev, uint8_t data, void* context) { | ||||||
|     UsbUartBridge* usb_uart = (UsbUartBridge*)context; |     UsbUartBridge* usb_uart = (UsbUartBridge*)context; | ||||||
|     BaseType_t xHigherPriorityTaskWoken = pdFALSE; |  | ||||||
| 
 | 
 | ||||||
|     if(ev == UartIrqEventRXNE) { |     if(ev == UartIrqEventRXNE) { | ||||||
|         xStreamBufferSendFromISR(usb_uart->rx_stream, &data, 1, &xHigherPriorityTaskWoken); |         furi_stream_buffer_send(usb_uart->rx_stream, &data, 1, 0); | ||||||
|         furi_thread_flags_set(furi_thread_get_id(usb_uart->thread), WorkerEvtRxDone); |         furi_thread_flags_set(furi_thread_get_id(usb_uart->thread), WorkerEvtRxDone); | ||||||
|         portYIELD_FROM_ISR(xHigherPriorityTaskWoken); |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -156,7 +153,7 @@ static int32_t usb_uart_worker(void* context) { | |||||||
| 
 | 
 | ||||||
|     memcpy(&usb_uart->cfg, &usb_uart->cfg_new, sizeof(UsbUartConfig)); |     memcpy(&usb_uart->cfg, &usb_uart->cfg_new, sizeof(UsbUartConfig)); | ||||||
| 
 | 
 | ||||||
|     usb_uart->rx_stream = xStreamBufferCreate(USB_UART_RX_BUF_SIZE, 1); |     usb_uart->rx_stream = furi_stream_buffer_alloc(USB_UART_RX_BUF_SIZE, 1); | ||||||
| 
 | 
 | ||||||
|     usb_uart->tx_sem = furi_semaphore_alloc(1, 1); |     usb_uart->tx_sem = furi_semaphore_alloc(1, 1); | ||||||
|     usb_uart->usb_mutex = furi_mutex_alloc(FuriMutexTypeNormal); |     usb_uart->usb_mutex = furi_mutex_alloc(FuriMutexTypeNormal); | ||||||
| @ -189,8 +186,8 @@ static int32_t usb_uart_worker(void* context) { | |||||||
|         furi_check((events & FuriFlagError) == 0); |         furi_check((events & FuriFlagError) == 0); | ||||||
|         if(events & WorkerEvtStop) break; |         if(events & WorkerEvtStop) break; | ||||||
|         if(events & WorkerEvtRxDone) { |         if(events & WorkerEvtRxDone) { | ||||||
|             size_t len = |             size_t len = furi_stream_buffer_receive( | ||||||
|                 xStreamBufferReceive(usb_uart->rx_stream, usb_uart->rx_buf, USB_CDC_PKT_LEN, 0); |                 usb_uart->rx_stream, usb_uart->rx_buf, USB_CDC_PKT_LEN, 0); | ||||||
|             if(len > 0) { |             if(len > 0) { | ||||||
|                 if(furi_semaphore_acquire(usb_uart->tx_sem, 100) == FuriStatusOk) { |                 if(furi_semaphore_acquire(usb_uart->tx_sem, 100) == FuriStatusOk) { | ||||||
|                     usb_uart->st.rx_cnt += len; |                     usb_uart->st.rx_cnt += len; | ||||||
| @ -199,7 +196,7 @@ static int32_t usb_uart_worker(void* context) { | |||||||
|                     furi_hal_cdc_send(usb_uart->cfg.vcp_ch, usb_uart->rx_buf, len); |                     furi_hal_cdc_send(usb_uart->cfg.vcp_ch, usb_uart->rx_buf, len); | ||||||
|                     furi_check(furi_mutex_release(usb_uart->usb_mutex) == FuriStatusOk); |                     furi_check(furi_mutex_release(usb_uart->usb_mutex) == FuriStatusOk); | ||||||
|                 } else { |                 } else { | ||||||
|                     xStreamBufferReset(usb_uart->rx_stream); |                     furi_stream_buffer_reset(usb_uart->rx_stream); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| @ -270,7 +267,7 @@ static int32_t usb_uart_worker(void* context) { | |||||||
|     furi_thread_join(usb_uart->tx_thread); |     furi_thread_join(usb_uart->tx_thread); | ||||||
|     furi_thread_free(usb_uart->tx_thread); |     furi_thread_free(usb_uart->tx_thread); | ||||||
| 
 | 
 | ||||||
|     vStreamBufferDelete(usb_uart->rx_stream); |     furi_stream_buffer_free(usb_uart->rx_stream); | ||||||
|     furi_mutex_free(usb_uart->usb_mutex); |     furi_mutex_free(usb_uart->usb_mutex); | ||||||
|     furi_semaphore_free(usb_uart->tx_sem); |     furi_semaphore_free(usb_uart->tx_sem); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -48,23 +48,27 @@ static bool gpio_test_input_callback(InputEvent* event, void* context) { | |||||||
| 
 | 
 | ||||||
| static bool gpio_test_process_left(GpioTest* gpio_test) { | static bool gpio_test_process_left(GpioTest* gpio_test) { | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         gpio_test->view, (GpioTestModel * model) { |         gpio_test->view, | ||||||
|  |         GpioTestModel * model, | ||||||
|  |         { | ||||||
|             if(model->pin_idx) { |             if(model->pin_idx) { | ||||||
|                 model->pin_idx--; |                 model->pin_idx--; | ||||||
|             } |             } | ||||||
|             return true; |         }, | ||||||
|         }); |         true); | ||||||
|     return true; |     return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static bool gpio_test_process_right(GpioTest* gpio_test) { | static bool gpio_test_process_right(GpioTest* gpio_test) { | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         gpio_test->view, (GpioTestModel * model) { |         gpio_test->view, | ||||||
|  |         GpioTestModel * model, | ||||||
|  |         { | ||||||
|             if(model->pin_idx < GPIO_ITEM_COUNT) { |             if(model->pin_idx < GPIO_ITEM_COUNT) { | ||||||
|                 model->pin_idx++; |                 model->pin_idx++; | ||||||
|             } |             } | ||||||
|             return true; |         }, | ||||||
|         }); |         true); | ||||||
|     return true; |     return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -72,7 +76,9 @@ static bool gpio_test_process_ok(GpioTest* gpio_test, InputEvent* event) { | |||||||
|     bool consumed = false; |     bool consumed = false; | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         gpio_test->view, (GpioTestModel * model) { |         gpio_test->view, | ||||||
|  |         GpioTestModel * model, | ||||||
|  |         { | ||||||
|             if(event->type == InputTypePress) { |             if(event->type == InputTypePress) { | ||||||
|                 if(model->pin_idx < GPIO_ITEM_COUNT) { |                 if(model->pin_idx < GPIO_ITEM_COUNT) { | ||||||
|                     gpio_item_set_pin(model->pin_idx, true); |                     gpio_item_set_pin(model->pin_idx, true); | ||||||
| @ -89,8 +95,8 @@ static bool gpio_test_process_ok(GpioTest* gpio_test, InputEvent* event) { | |||||||
|                 consumed = true; |                 consumed = true; | ||||||
|             } |             } | ||||||
|             gpio_test->callback(event->type, gpio_test->context); |             gpio_test->callback(event->type, gpio_test->context); | ||||||
|             return true; |         }, | ||||||
|         }); |         true); | ||||||
| 
 | 
 | ||||||
|     return consumed; |     return consumed; | ||||||
| } | } | ||||||
| @ -122,10 +128,12 @@ void gpio_test_set_ok_callback(GpioTest* gpio_test, GpioTestOkCallback callback, | |||||||
|     furi_assert(gpio_test); |     furi_assert(gpio_test); | ||||||
|     furi_assert(callback); |     furi_assert(callback); | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         gpio_test->view, (GpioTestModel * model) { |         gpio_test->view, | ||||||
|  |         GpioTestModel * model, | ||||||
|  |         { | ||||||
|             UNUSED(model); |             UNUSED(model); | ||||||
|             gpio_test->callback = callback; |             gpio_test->callback = callback; | ||||||
|             gpio_test->context = context; |             gpio_test->context = context; | ||||||
|             return false; |         }, | ||||||
|         }); |         false); | ||||||
| } | } | ||||||
|  | |||||||
| @ -54,7 +54,7 @@ static void gpio_usb_uart_draw_callback(Canvas* canvas, void* _model) { | |||||||
|         canvas_draw_str_aligned(canvas, 116, 24, AlignRight, AlignBottom, temp_str); |         canvas_draw_str_aligned(canvas, 116, 24, AlignRight, AlignBottom, temp_str); | ||||||
|     } else { |     } else { | ||||||
|         canvas_set_font(canvas, FontSecondary); |         canvas_set_font(canvas, FontSecondary); | ||||||
|         canvas_draw_str_aligned(canvas, 127, 24, AlignRight, AlignBottom, "KB."); |         canvas_draw_str_aligned(canvas, 127, 24, AlignRight, AlignBottom, "KiB."); | ||||||
|         canvas_set_font(canvas, FontKeyboard); |         canvas_set_font(canvas, FontKeyboard); | ||||||
|         snprintf(temp_str, 18, "%lu", model->tx_cnt / 1024); |         snprintf(temp_str, 18, "%lu", model->tx_cnt / 1024); | ||||||
|         canvas_draw_str_aligned(canvas, 111, 24, AlignRight, AlignBottom, temp_str); |         canvas_draw_str_aligned(canvas, 111, 24, AlignRight, AlignBottom, temp_str); | ||||||
| @ -68,7 +68,7 @@ static void gpio_usb_uart_draw_callback(Canvas* canvas, void* _model) { | |||||||
|         canvas_draw_str_aligned(canvas, 116, 41, AlignRight, AlignBottom, temp_str); |         canvas_draw_str_aligned(canvas, 116, 41, AlignRight, AlignBottom, temp_str); | ||||||
|     } else { |     } else { | ||||||
|         canvas_set_font(canvas, FontSecondary); |         canvas_set_font(canvas, FontSecondary); | ||||||
|         canvas_draw_str_aligned(canvas, 127, 41, AlignRight, AlignBottom, "KB."); |         canvas_draw_str_aligned(canvas, 127, 41, AlignRight, AlignBottom, "KiB."); | ||||||
|         canvas_set_font(canvas, FontKeyboard); |         canvas_set_font(canvas, FontKeyboard); | ||||||
|         snprintf(temp_str, 18, "%lu", model->rx_cnt / 1024); |         snprintf(temp_str, 18, "%lu", model->rx_cnt / 1024); | ||||||
|         canvas_draw_str_aligned(canvas, 111, 41, AlignRight, AlignBottom, temp_str); |         canvas_draw_str_aligned(canvas, 111, 41, AlignRight, AlignBottom, temp_str); | ||||||
| @ -129,12 +129,14 @@ void gpio_usb_uart_set_callback(GpioUsbUart* usb_uart, GpioUsbUartCallback callb | |||||||
|     furi_assert(callback); |     furi_assert(callback); | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         usb_uart->view, (GpioUsbUartModel * model) { |         usb_uart->view, | ||||||
|  |         GpioUsbUartModel * model, | ||||||
|  |         { | ||||||
|             UNUSED(model); |             UNUSED(model); | ||||||
|             usb_uart->callback = callback; |             usb_uart->callback = callback; | ||||||
|             usb_uart->context = context; |             usb_uart->context = context; | ||||||
|             return false; |         }, | ||||||
|         }); |         false); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void gpio_usb_uart_update_state(GpioUsbUart* instance, UsbUartConfig* cfg, UsbUartState* st) { | void gpio_usb_uart_update_state(GpioUsbUart* instance, UsbUartConfig* cfg, UsbUartState* st) { | ||||||
| @ -143,7 +145,9 @@ void gpio_usb_uart_update_state(GpioUsbUart* instance, UsbUartConfig* cfg, UsbUa | |||||||
|     furi_assert(st); |     furi_assert(st); | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         instance->view, (GpioUsbUartModel * model) { |         instance->view, | ||||||
|  |         GpioUsbUartModel * model, | ||||||
|  |         { | ||||||
|             model->baudrate = st->baudrate_cur; |             model->baudrate = st->baudrate_cur; | ||||||
|             model->vcp_port = cfg->vcp_ch; |             model->vcp_port = cfg->vcp_ch; | ||||||
|             model->tx_pin = (cfg->uart_ch == 0) ? (13) : (15); |             model->tx_pin = (cfg->uart_ch == 0) ? (13) : (15); | ||||||
| @ -152,6 +156,6 @@ void gpio_usb_uart_update_state(GpioUsbUart* instance, UsbUartConfig* cfg, UsbUa | |||||||
|             model->rx_active = (model->rx_cnt != st->rx_cnt); |             model->rx_active = (model->rx_cnt != st->rx_cnt); | ||||||
|             model->tx_cnt = st->tx_cnt; |             model->tx_cnt = st->tx_cnt; | ||||||
|             model->rx_cnt = st->rx_cnt; |             model->rx_cnt = st->rx_cnt; | ||||||
|             return true; |         }, | ||||||
|         }); |         true); | ||||||
| } | } | ||||||
|  | |||||||
| @ -2,7 +2,6 @@ | |||||||
| #include "assets_icons.h" | #include "assets_icons.h" | ||||||
| #include "ibutton_i.h" | #include "ibutton_i.h" | ||||||
| #include "ibutton/scenes/ibutton_scene.h" | #include "ibutton/scenes/ibutton_scene.h" | ||||||
| #include "m-string.h" |  | ||||||
| #include <toolbox/path.h> | #include <toolbox/path.h> | ||||||
| #include <flipper_format/flipper_format.h> | #include <flipper_format/flipper_format.h> | ||||||
| #include <rpc/rpc_app.h> | #include <rpc/rpc_app.h> | ||||||
| @ -39,25 +38,25 @@ static void ibutton_make_app_folder(iButton* ibutton) { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool ibutton_load_key_data(iButton* ibutton, string_t key_path, bool show_dialog) { | bool ibutton_load_key_data(iButton* ibutton, FuriString* key_path, bool show_dialog) { | ||||||
|     FlipperFormat* file = flipper_format_file_alloc(ibutton->storage); |     FlipperFormat* file = flipper_format_file_alloc(ibutton->storage); | ||||||
|     bool result = false; |     bool result = false; | ||||||
|     string_t data; |     FuriString* data; | ||||||
|     string_init(data); |     data = furi_string_alloc(); | ||||||
| 
 | 
 | ||||||
|     do { |     do { | ||||||
|         if(!flipper_format_file_open_existing(file, string_get_cstr(key_path))) break; |         if(!flipper_format_file_open_existing(file, furi_string_get_cstr(key_path))) break; | ||||||
| 
 | 
 | ||||||
|         // header
 |         // header
 | ||||||
|         uint32_t version; |         uint32_t version; | ||||||
|         if(!flipper_format_read_header(file, data, &version)) break; |         if(!flipper_format_read_header(file, data, &version)) break; | ||||||
|         if(string_cmp_str(data, IBUTTON_APP_FILE_TYPE) != 0) break; |         if(furi_string_cmp_str(data, IBUTTON_APP_FILE_TYPE) != 0) break; | ||||||
|         if(version != 1) break; |         if(version != 1) break; | ||||||
| 
 | 
 | ||||||
|         // key type
 |         // key type
 | ||||||
|         iButtonKeyType type; |         iButtonKeyType type; | ||||||
|         if(!flipper_format_read_string(file, "Key type", data)) break; |         if(!flipper_format_read_string(file, "Key type", data)) break; | ||||||
|         if(!ibutton_key_get_type_by_string(string_get_cstr(data), &type)) break; |         if(!ibutton_key_get_type_by_string(furi_string_get_cstr(data), &type)) break; | ||||||
| 
 | 
 | ||||||
|         // key data
 |         // key data
 | ||||||
|         uint8_t key_data[IBUTTON_KEY_DATA_SIZE] = {0}; |         uint8_t key_data[IBUTTON_KEY_DATA_SIZE] = {0}; | ||||||
| @ -71,7 +70,7 @@ bool ibutton_load_key_data(iButton* ibutton, string_t key_path, bool show_dialog | |||||||
|     } while(false); |     } while(false); | ||||||
| 
 | 
 | ||||||
|     flipper_format_free(file); |     flipper_format_free(file); | ||||||
|     string_clear(data); |     furi_string_free(data); | ||||||
| 
 | 
 | ||||||
|     if((!result) && (show_dialog)) { |     if((!result) && (show_dialog)) { | ||||||
|         dialog_message_show_storage_error(ibutton->dialogs, "Cannot load\nkey file"); |         dialog_message_show_storage_error(ibutton->dialogs, "Cannot load\nkey file"); | ||||||
| @ -119,7 +118,7 @@ void ibutton_tick_event_callback(void* context) { | |||||||
| iButton* ibutton_alloc() { | iButton* ibutton_alloc() { | ||||||
|     iButton* ibutton = malloc(sizeof(iButton)); |     iButton* ibutton = malloc(sizeof(iButton)); | ||||||
| 
 | 
 | ||||||
|     string_init(ibutton->file_path); |     ibutton->file_path = furi_string_alloc(); | ||||||
| 
 | 
 | ||||||
|     ibutton->scene_manager = scene_manager_alloc(&ibutton_scene_handlers, ibutton); |     ibutton->scene_manager = scene_manager_alloc(&ibutton_scene_handlers, ibutton); | ||||||
| 
 | 
 | ||||||
| @ -210,7 +209,7 @@ void ibutton_free(iButton* ibutton) { | |||||||
|     ibutton_worker_free(ibutton->key_worker); |     ibutton_worker_free(ibutton->key_worker); | ||||||
|     ibutton_key_free(ibutton->key); |     ibutton_key_free(ibutton->key); | ||||||
| 
 | 
 | ||||||
|     string_clear(ibutton->file_path); |     furi_string_free(ibutton->file_path); | ||||||
| 
 | 
 | ||||||
|     free(ibutton); |     free(ibutton); | ||||||
| } | } | ||||||
| @ -240,19 +239,19 @@ bool ibutton_save_key(iButton* ibutton, const char* key_name) { | |||||||
| 
 | 
 | ||||||
|     do { |     do { | ||||||
|         // Check if we has old key
 |         // Check if we has old key
 | ||||||
|         if(string_end_with_str_p(ibutton->file_path, IBUTTON_APP_EXTENSION)) { |         if(furi_string_end_with(ibutton->file_path, IBUTTON_APP_EXTENSION)) { | ||||||
|             // First remove old key
 |             // First remove old key
 | ||||||
|             ibutton_delete_key(ibutton); |             ibutton_delete_key(ibutton); | ||||||
| 
 | 
 | ||||||
|             // Remove old key name from path
 |             // Remove old key name from path
 | ||||||
|             size_t filename_start = string_search_rchar(ibutton->file_path, '/'); |             size_t filename_start = furi_string_search_rchar(ibutton->file_path, '/'); | ||||||
|             string_left(ibutton->file_path, filename_start); |             furi_string_left(ibutton->file_path, filename_start); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         string_cat_printf(ibutton->file_path, "/%s%s", key_name, IBUTTON_APP_EXTENSION); |         furi_string_cat_printf(ibutton->file_path, "/%s%s", key_name, IBUTTON_APP_EXTENSION); | ||||||
| 
 | 
 | ||||||
|         // Open file for write
 |         // Open file for write
 | ||||||
|         if(!flipper_format_file_open_always(file, string_get_cstr(ibutton->file_path))) break; |         if(!flipper_format_file_open_always(file, furi_string_get_cstr(ibutton->file_path))) break; | ||||||
| 
 | 
 | ||||||
|         // Write header
 |         // Write header
 | ||||||
|         if(!flipper_format_write_header_cstr(file, IBUTTON_APP_FILE_TYPE, 1)) break; |         if(!flipper_format_write_header_cstr(file, IBUTTON_APP_FILE_TYPE, 1)) break; | ||||||
| @ -286,7 +285,7 @@ bool ibutton_save_key(iButton* ibutton, const char* key_name) { | |||||||
| 
 | 
 | ||||||
| bool ibutton_delete_key(iButton* ibutton) { | bool ibutton_delete_key(iButton* ibutton) { | ||||||
|     bool result = false; |     bool result = false; | ||||||
|     result = storage_simply_remove(ibutton->storage, string_get_cstr(ibutton->file_path)); |     result = storage_simply_remove(ibutton->storage, furi_string_get_cstr(ibutton->file_path)); | ||||||
| 
 | 
 | ||||||
|     return result; |     return result; | ||||||
| } | } | ||||||
| @ -326,7 +325,7 @@ int32_t ibutton_app(void* p) { | |||||||
|             rpc_system_app_set_callback(ibutton->rpc_ctx, ibutton_rpc_command_callback, ibutton); |             rpc_system_app_set_callback(ibutton->rpc_ctx, ibutton_rpc_command_callback, ibutton); | ||||||
|             rpc_system_app_send_started(ibutton->rpc_ctx); |             rpc_system_app_send_started(ibutton->rpc_ctx); | ||||||
|         } else { |         } else { | ||||||
|             string_set_str(ibutton->file_path, (const char*)p); |             furi_string_set(ibutton->file_path, (const char*)p); | ||||||
|             if(ibutton_load_key_data(ibutton, ibutton->file_path, true)) { |             if(ibutton_load_key_data(ibutton, ibutton->file_path, true)) { | ||||||
|                 key_loaded = true; |                 key_loaded = true; | ||||||
|                 // TODO: Display an error if the key from p could not be loaded
 |                 // TODO: Display an error if the key from p could not be loaded
 | ||||||
|  | |||||||
| @ -6,8 +6,8 @@ | |||||||
| #include <one_wire/ibutton/ibutton_worker.h> | #include <one_wire/ibutton/ibutton_worker.h> | ||||||
| #include <one_wire/one_wire_host.h> | #include <one_wire/one_wire_host.h> | ||||||
| 
 | 
 | ||||||
| static void ibutton_cli(Cli* cli, string_t args, void* context); | static void ibutton_cli(Cli* cli, FuriString* args, void* context); | ||||||
| static void onewire_cli(Cli* cli, string_t args, void* context); | static void onewire_cli(Cli* cli, FuriString* args, void* context); | ||||||
| 
 | 
 | ||||||
| // app cli function
 | // app cli function
 | ||||||
| void ibutton_on_system_start() { | void ibutton_on_system_start() { | ||||||
| @ -34,16 +34,16 @@ void ibutton_cli_print_usage() { | |||||||
|     printf("\t<key_data> are hex-formatted\r\n"); |     printf("\t<key_data> are hex-formatted\r\n"); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| bool ibutton_cli_get_key_type(string_t data, iButtonKeyType* type) { | bool ibutton_cli_get_key_type(FuriString* data, iButtonKeyType* type) { | ||||||
|     bool result = false; |     bool result = false; | ||||||
| 
 | 
 | ||||||
|     if(string_cmp_str(data, "Dallas") == 0 || string_cmp_str(data, "dallas") == 0) { |     if(furi_string_cmp_str(data, "Dallas") == 0 || furi_string_cmp_str(data, "dallas") == 0) { | ||||||
|         result = true; |         result = true; | ||||||
|         *type = iButtonKeyDS1990; |         *type = iButtonKeyDS1990; | ||||||
|     } else if(string_cmp_str(data, "Cyfral") == 0 || string_cmp_str(data, "cyfral") == 0) { |     } else if(furi_string_cmp_str(data, "Cyfral") == 0 || furi_string_cmp_str(data, "cyfral") == 0) { | ||||||
|         result = true; |         result = true; | ||||||
|         *type = iButtonKeyCyfral; |         *type = iButtonKeyCyfral; | ||||||
|     } else if(string_cmp_str(data, "Metakom") == 0 || string_cmp_str(data, "metakom") == 0) { |     } else if(furi_string_cmp_str(data, "Metakom") == 0 || furi_string_cmp_str(data, "metakom") == 0) { | ||||||
|         result = true; |         result = true; | ||||||
|         *type = iButtonKeyMetakom; |         *type = iButtonKeyMetakom; | ||||||
|     } |     } | ||||||
| @ -123,17 +123,17 @@ static void ibutton_cli_worker_write_cb(void* context, iButtonWorkerWriteResult | |||||||
|     furi_event_flag_set(write_context->event, EVENT_FLAG_IBUTTON_COMPLETE); |     furi_event_flag_set(write_context->event, EVENT_FLAG_IBUTTON_COMPLETE); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ibutton_cli_write(Cli* cli, string_t args) { | void ibutton_cli_write(Cli* cli, FuriString* args) { | ||||||
|     iButtonKey* key = ibutton_key_alloc(); |     iButtonKey* key = ibutton_key_alloc(); | ||||||
|     iButtonWorker* worker = ibutton_worker_alloc(); |     iButtonWorker* worker = ibutton_worker_alloc(); | ||||||
|     iButtonKeyType type; |     iButtonKeyType type; | ||||||
|     iButtonWriteContext write_context; |     iButtonWriteContext write_context; | ||||||
|     uint8_t key_data[IBUTTON_KEY_DATA_SIZE]; |     uint8_t key_data[IBUTTON_KEY_DATA_SIZE]; | ||||||
|     string_t data; |     FuriString* data; | ||||||
| 
 | 
 | ||||||
|     write_context.event = furi_event_flag_alloc(); |     write_context.event = furi_event_flag_alloc(); | ||||||
| 
 | 
 | ||||||
|     string_init(data); |     data = furi_string_alloc(); | ||||||
|     ibutton_worker_start_thread(worker); |     ibutton_worker_start_thread(worker); | ||||||
|     ibutton_worker_write_set_callback(worker, ibutton_cli_worker_write_cb, &write_context); |     ibutton_worker_write_set_callback(worker, ibutton_cli_worker_write_cb, &write_context); | ||||||
| 
 | 
 | ||||||
| @ -186,7 +186,7 @@ void ibutton_cli_write(Cli* cli, string_t args) { | |||||||
|         ibutton_worker_stop(worker); |         ibutton_worker_stop(worker); | ||||||
|     } while(false); |     } while(false); | ||||||
| 
 | 
 | ||||||
|     string_clear(data); |     furi_string_free(data); | ||||||
|     ibutton_worker_stop_thread(worker); |     ibutton_worker_stop_thread(worker); | ||||||
|     ibutton_worker_free(worker); |     ibutton_worker_free(worker); | ||||||
|     ibutton_key_free(key); |     ibutton_key_free(key); | ||||||
| @ -194,14 +194,14 @@ void ibutton_cli_write(Cli* cli, string_t args) { | |||||||
|     furi_event_flag_free(write_context.event); |     furi_event_flag_free(write_context.event); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| void ibutton_cli_emulate(Cli* cli, string_t args) { | void ibutton_cli_emulate(Cli* cli, FuriString* args) { | ||||||
|     iButtonKey* key = ibutton_key_alloc(); |     iButtonKey* key = ibutton_key_alloc(); | ||||||
|     iButtonWorker* worker = ibutton_worker_alloc(); |     iButtonWorker* worker = ibutton_worker_alloc(); | ||||||
|     iButtonKeyType type; |     iButtonKeyType type; | ||||||
|     uint8_t key_data[IBUTTON_KEY_DATA_SIZE]; |     uint8_t key_data[IBUTTON_KEY_DATA_SIZE]; | ||||||
|     string_t data; |     FuriString* data; | ||||||
| 
 | 
 | ||||||
|     string_init(data); |     data = furi_string_alloc(); | ||||||
|     ibutton_worker_start_thread(worker); |     ibutton_worker_start_thread(worker); | ||||||
| 
 | 
 | ||||||
|     do { |     do { | ||||||
| @ -234,34 +234,34 @@ void ibutton_cli_emulate(Cli* cli, string_t args) { | |||||||
|         ibutton_worker_stop(worker); |         ibutton_worker_stop(worker); | ||||||
|     } while(false); |     } while(false); | ||||||
| 
 | 
 | ||||||
|     string_clear(data); |     furi_string_free(data); | ||||||
|     ibutton_worker_stop_thread(worker); |     ibutton_worker_stop_thread(worker); | ||||||
|     ibutton_worker_free(worker); |     ibutton_worker_free(worker); | ||||||
|     ibutton_key_free(key); |     ibutton_key_free(key); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static void ibutton_cli(Cli* cli, string_t args, void* context) { | static void ibutton_cli(Cli* cli, FuriString* args, void* context) { | ||||||
|     UNUSED(context); |     UNUSED(context); | ||||||
|     string_t cmd; |     FuriString* cmd; | ||||||
|     string_init(cmd); |     cmd = furi_string_alloc(); | ||||||
| 
 | 
 | ||||||
|     if(!args_read_string_and_trim(args, cmd)) { |     if(!args_read_string_and_trim(args, cmd)) { | ||||||
|         string_clear(cmd); |         furi_string_free(cmd); | ||||||
|         ibutton_cli_print_usage(); |         ibutton_cli_print_usage(); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if(string_cmp_str(cmd, "read") == 0) { |     if(furi_string_cmp_str(cmd, "read") == 0) { | ||||||
|         ibutton_cli_read(cli); |         ibutton_cli_read(cli); | ||||||
|     } else if(string_cmp_str(cmd, "write") == 0) { |     } else if(furi_string_cmp_str(cmd, "write") == 0) { | ||||||
|         ibutton_cli_write(cli, args); |         ibutton_cli_write(cli, args); | ||||||
|     } else if(string_cmp_str(cmd, "emulate") == 0) { |     } else if(furi_string_cmp_str(cmd, "emulate") == 0) { | ||||||
|         ibutton_cli_emulate(cli, args); |         ibutton_cli_emulate(cli, args); | ||||||
|     } else { |     } else { | ||||||
|         ibutton_cli_print_usage(); |         ibutton_cli_print_usage(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     string_clear(cmd); |     furi_string_free(cmd); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void onewire_cli_print_usage() { | void onewire_cli_print_usage() { | ||||||
| @ -299,20 +299,20 @@ static void onewire_cli_search(Cli* cli) { | |||||||
|     onewire_host_free(onewire); |     onewire_host_free(onewire); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void onewire_cli(Cli* cli, string_t args, void* context) { | void onewire_cli(Cli* cli, FuriString* args, void* context) { | ||||||
|     UNUSED(context); |     UNUSED(context); | ||||||
|     string_t cmd; |     FuriString* cmd; | ||||||
|     string_init(cmd); |     cmd = furi_string_alloc(); | ||||||
| 
 | 
 | ||||||
|     if(!args_read_string_and_trim(args, cmd)) { |     if(!args_read_string_and_trim(args, cmd)) { | ||||||
|         string_clear(cmd); |         furi_string_free(cmd); | ||||||
|         onewire_cli_print_usage(); |         onewire_cli_print_usage(); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if(string_cmp_str(cmd, "search") == 0) { |     if(furi_string_cmp_str(cmd, "search") == 0) { | ||||||
|         onewire_cli_search(cli); |         onewire_cli_search(cli); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     string_clear(cmd); |     furi_string_free(cmd); | ||||||
| } | } | ||||||
|  | |||||||
| @ -41,7 +41,7 @@ struct iButton { | |||||||
|     iButtonWorker* key_worker; |     iButtonWorker* key_worker; | ||||||
|     iButtonKey* key; |     iButtonKey* key; | ||||||
| 
 | 
 | ||||||
|     string_t file_path; |     FuriString* file_path; | ||||||
|     char text_store[IBUTTON_TEXT_STORE_SIZE + 1]; |     char text_store[IBUTTON_TEXT_STORE_SIZE + 1]; | ||||||
| 
 | 
 | ||||||
|     Submenu* submenu; |     Submenu* submenu; | ||||||
| @ -78,7 +78,7 @@ typedef enum { | |||||||
| } iButtonNotificationMessage; | } iButtonNotificationMessage; | ||||||
| 
 | 
 | ||||||
| bool ibutton_file_select(iButton* ibutton); | bool ibutton_file_select(iButton* ibutton); | ||||||
| bool ibutton_load_key_data(iButton* ibutton, string_t key_path, bool show_dialog); | bool ibutton_load_key_data(iButton* ibutton, FuriString* key_path, bool show_dialog); | ||||||
| bool ibutton_save_key(iButton* ibutton, const char* key_name); | 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, ...); | ||||||
|  | |||||||
| @ -1,5 +1,4 @@ | |||||||
| #include "../ibutton_i.h" | #include "../ibutton_i.h" | ||||||
| #include "m-string.h" |  | ||||||
| 
 | 
 | ||||||
| enum SubmenuIndex { | enum SubmenuIndex { | ||||||
|     SubmenuIndexCyfral, |     SubmenuIndexCyfral, | ||||||
| @ -47,7 +46,7 @@ bool ibutton_scene_add_type_on_event(void* context, SceneManagerEvent event) { | |||||||
|             furi_crash("Unknown key type"); |             furi_crash("Unknown key type"); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         string_set_str(ibutton->file_path, IBUTTON_APP_FOLDER); |         furi_string_set(ibutton->file_path, IBUTTON_APP_FOLDER); | ||||||
|         ibutton_key_clear_data(key); |         ibutton_key_clear_data(key); | ||||||
|         scene_manager_next_scene(ibutton->scene_manager, iButtonSceneAddValue); |         scene_manager_next_scene(ibutton->scene_manager, iButtonSceneAddValue); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -17,11 +17,11 @@ void ibutton_scene_delete_confirm_on_enter(void* context) { | |||||||
|     iButtonKey* key = ibutton->key; |     iButtonKey* key = ibutton->key; | ||||||
|     const uint8_t* key_data = ibutton_key_get_data_p(key); |     const uint8_t* key_data = ibutton_key_get_data_p(key); | ||||||
| 
 | 
 | ||||||
|     string_t key_name; |     FuriString* key_name; | ||||||
|     string_init(key_name); |     key_name = furi_string_alloc(); | ||||||
|     path_extract_filename(ibutton->file_path, key_name, true); |     path_extract_filename(ibutton->file_path, key_name, true); | ||||||
| 
 | 
 | ||||||
|     ibutton_text_store_set(ibutton, "\e#Delete %s?\e#", string_get_cstr(key_name)); |     ibutton_text_store_set(ibutton, "\e#Delete %s?\e#", furi_string_get_cstr(key_name)); | ||||||
|     widget_add_text_box_element( |     widget_add_text_box_element( | ||||||
|         widget, 0, 0, 128, 27, AlignCenter, AlignCenter, ibutton->text_store, true); |         widget, 0, 0, 128, 27, AlignCenter, AlignCenter, ibutton->text_store, true); | ||||||
|     widget_add_button_element( |     widget_add_button_element( | ||||||
| @ -68,7 +68,7 @@ void ibutton_scene_delete_confirm_on_enter(void* context) { | |||||||
| 
 | 
 | ||||||
|     view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewWidget); |     view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewWidget); | ||||||
| 
 | 
 | ||||||
|     string_clear(key_name); |     furi_string_free(key_name); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool ibutton_scene_delete_confirm_on_event(void* context, SceneManagerEvent event) { | bool ibutton_scene_delete_confirm_on_event(void* context, SceneManagerEvent event) { | ||||||
|  | |||||||
| @ -20,17 +20,17 @@ void ibutton_scene_emulate_on_enter(void* context) { | |||||||
| 
 | 
 | ||||||
|     const uint8_t* key_data = ibutton_key_get_data_p(key); |     const uint8_t* key_data = ibutton_key_get_data_p(key); | ||||||
| 
 | 
 | ||||||
|     string_t key_name; |     FuriString* key_name; | ||||||
|     string_init(key_name); |     key_name = furi_string_alloc(); | ||||||
|     if(string_end_with_str_p(ibutton->file_path, IBUTTON_APP_EXTENSION)) { |     if(furi_string_end_with(ibutton->file_path, IBUTTON_APP_EXTENSION)) { | ||||||
|         path_extract_filename(ibutton->file_path, key_name, true); |         path_extract_filename(ibutton->file_path, key_name, true); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     DOLPHIN_DEED(DolphinDeedIbuttonEmulate); |     DOLPHIN_DEED(DolphinDeedIbuttonEmulate); | ||||||
| 
 | 
 | ||||||
|     // check that stored key has name
 |     // check that stored key has name
 | ||||||
|     if(!string_empty_p(key_name)) { |     if(!furi_string_empty(key_name)) { | ||||||
|         ibutton_text_store_set(ibutton, "%s", string_get_cstr(key_name)); |         ibutton_text_store_set(ibutton, "%s", furi_string_get_cstr(key_name)); | ||||||
|     } else { |     } else { | ||||||
|         // if not, show key data
 |         // if not, show key data
 | ||||||
|         switch(ibutton_key_get_type(key)) { |         switch(ibutton_key_get_type(key)) { | ||||||
| @ -69,7 +69,7 @@ void ibutton_scene_emulate_on_enter(void* context) { | |||||||
|         ibutton->key_worker, ibutton_scene_emulate_callback, ibutton); |         ibutton->key_worker, ibutton_scene_emulate_callback, ibutton); | ||||||
|     ibutton_worker_emulate_start(ibutton->key_worker, key); |     ibutton_worker_emulate_start(ibutton->key_worker, key); | ||||||
| 
 | 
 | ||||||
|     string_clear(key_name); |     furi_string_free(key_name); | ||||||
| 
 | 
 | ||||||
|     ibutton_notification_message(ibutton, iButtonNotificationMessageEmulateStart); |     ibutton_notification_message(ibutton, iButtonNotificationMessageEmulateStart); | ||||||
| } | } | ||||||
|  | |||||||
| @ -8,11 +8,11 @@ void ibutton_scene_info_on_enter(void* context) { | |||||||
| 
 | 
 | ||||||
|     const uint8_t* key_data = ibutton_key_get_data_p(key); |     const uint8_t* key_data = ibutton_key_get_data_p(key); | ||||||
| 
 | 
 | ||||||
|     string_t key_name; |     FuriString* key_name; | ||||||
|     string_init(key_name); |     key_name = furi_string_alloc(); | ||||||
|     path_extract_filename(ibutton->file_path, key_name, true); |     path_extract_filename(ibutton->file_path, key_name, true); | ||||||
| 
 | 
 | ||||||
|     ibutton_text_store_set(ibutton, "%s", string_get_cstr(key_name)); |     ibutton_text_store_set(ibutton, "%s", furi_string_get_cstr(key_name)); | ||||||
|     widget_add_text_box_element( |     widget_add_text_box_element( | ||||||
|         widget, 0, 0, 128, 23, AlignCenter, AlignCenter, ibutton->text_store, true); |         widget, 0, 0, 128, 23, AlignCenter, AlignCenter, ibutton->text_store, true); | ||||||
| 
 | 
 | ||||||
| @ -50,7 +50,7 @@ void ibutton_scene_info_on_enter(void* context) { | |||||||
| 
 | 
 | ||||||
|     view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewWidget); |     view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewWidget); | ||||||
| 
 | 
 | ||||||
|     string_clear(key_name); |     furi_string_free(key_name); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool ibutton_scene_info_on_event(void* context, SceneManagerEvent event) { | bool ibutton_scene_info_on_event(void* context, SceneManagerEvent event) { | ||||||
|  | |||||||
| @ -18,7 +18,7 @@ void ibutton_scene_read_on_enter(void* context) { | |||||||
|     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); | ||||||
|     string_set_str(ibutton->file_path, IBUTTON_APP_FOLDER); |     furi_string_set(ibutton->file_path, IBUTTON_APP_FOLDER); | ||||||
| 
 | 
 | ||||||
|     ibutton_worker_read_set_callback(worker, ibutton_scene_read_callback, ibutton); |     ibutton_worker_read_set_callback(worker, ibutton_scene_read_callback, ibutton); | ||||||
|     ibutton_worker_read_start(worker, key); |     ibutton_worker_read_start(worker, key); | ||||||
|  | |||||||
| @ -29,19 +29,19 @@ 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 && (string_empty_p(ibutton->file_path))) { |             if(arg && (furi_string_empty(ibutton->file_path))) { | ||||||
|                 string_set_str(ibutton->file_path, arg); |                 furi_string_set(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); | ||||||
|                     string_t key_name; |                     FuriString* key_name; | ||||||
|                     string_init(key_name); |                     key_name = furi_string_alloc(); | ||||||
|                     if(string_end_with_str_p(ibutton->file_path, IBUTTON_APP_EXTENSION)) { |                     if(furi_string_end_with(ibutton->file_path, IBUTTON_APP_EXTENSION)) { | ||||||
|                         path_extract_filename(ibutton->file_path, key_name, true); |                         path_extract_filename(ibutton->file_path, key_name, true); | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                     if(!string_empty_p(key_name)) { |                     if(!furi_string_empty(key_name)) { | ||||||
|                         ibutton_text_store_set( |                         ibutton_text_store_set( | ||||||
|                             ibutton, "emulating\n%s", string_get_cstr(key_name)); |                             ibutton, "emulating\n%s", furi_string_get_cstr(key_name)); | ||||||
|                     } else { |                     } else { | ||||||
|                         ibutton_text_store_set(ibutton, "emulating"); |                         ibutton_text_store_set(ibutton, "emulating"); | ||||||
|                     } |                     } | ||||||
| @ -49,10 +49,10 @@ bool ibutton_scene_rpc_on_event(void* context, SceneManagerEvent event) { | |||||||
| 
 | 
 | ||||||
|                     ibutton_notification_message(ibutton, iButtonNotificationMessageEmulateStart); |                     ibutton_notification_message(ibutton, iButtonNotificationMessageEmulateStart); | ||||||
| 
 | 
 | ||||||
|                     string_clear(key_name); |                     furi_string_free(key_name); | ||||||
|                     result = true; |                     result = true; | ||||||
|                 } else { |                 } else { | ||||||
|                     string_reset(ibutton->file_path); |                     furi_string_reset(ibutton->file_path); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             rpc_system_app_confirm(ibutton->rpc_ctx, RpcAppEventLoadFile, result); |             rpc_system_app_confirm(ibutton->rpc_ctx, RpcAppEventLoadFile, result); | ||||||
|  | |||||||
| @ -1,5 +1,4 @@ | |||||||
| #include "../ibutton_i.h" | #include "../ibutton_i.h" | ||||||
| #include "m-string.h" |  | ||||||
| #include <lib/toolbox/random_name.h> | #include <lib/toolbox/random_name.h> | ||||||
| #include <toolbox/path.h> | #include <toolbox/path.h> | ||||||
| 
 | 
 | ||||||
| @ -12,17 +11,17 @@ void ibutton_scene_save_name_on_enter(void* context) { | |||||||
|     iButton* ibutton = context; |     iButton* ibutton = context; | ||||||
|     TextInput* text_input = ibutton->text_input; |     TextInput* text_input = ibutton->text_input; | ||||||
| 
 | 
 | ||||||
|     string_t key_name; |     FuriString* key_name; | ||||||
|     string_init(key_name); |     key_name = furi_string_alloc(); | ||||||
|     if(string_end_with_str_p(ibutton->file_path, IBUTTON_APP_EXTENSION)) { |     if(furi_string_end_with(ibutton->file_path, IBUTTON_APP_EXTENSION)) { | ||||||
|         path_extract_filename(ibutton->file_path, key_name, true); |         path_extract_filename(ibutton->file_path, key_name, true); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     const bool key_name_is_empty = string_empty_p(key_name); |     const bool key_name_is_empty = furi_string_empty(key_name); | ||||||
|     if(key_name_is_empty) { |     if(key_name_is_empty) { | ||||||
|         set_random_name(ibutton->text_store, IBUTTON_TEXT_STORE_SIZE); |         set_random_name(ibutton->text_store, IBUTTON_TEXT_STORE_SIZE); | ||||||
|     } else { |     } else { | ||||||
|         ibutton_text_store_set(ibutton, "%s", string_get_cstr(key_name)); |         ibutton_text_store_set(ibutton, "%s", furi_string_get_cstr(key_name)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     text_input_set_header_text(text_input, "Name the key"); |     text_input_set_header_text(text_input, "Name the key"); | ||||||
| @ -34,19 +33,19 @@ void ibutton_scene_save_name_on_enter(void* context) { | |||||||
|         IBUTTON_KEY_NAME_SIZE, |         IBUTTON_KEY_NAME_SIZE, | ||||||
|         key_name_is_empty); |         key_name_is_empty); | ||||||
| 
 | 
 | ||||||
|     string_t folder_path; |     FuriString* folder_path; | ||||||
|     string_init(folder_path); |     folder_path = furi_string_alloc(); | ||||||
| 
 | 
 | ||||||
|     path_extract_dirname(string_get_cstr(ibutton->file_path), folder_path); |     path_extract_dirname(furi_string_get_cstr(ibutton->file_path), folder_path); | ||||||
| 
 | 
 | ||||||
|     ValidatorIsFile* validator_is_file = validator_is_file_alloc_init( |     ValidatorIsFile* validator_is_file = validator_is_file_alloc_init( | ||||||
|         string_get_cstr(folder_path), IBUTTON_APP_EXTENSION, string_get_cstr(key_name)); |         furi_string_get_cstr(folder_path), IBUTTON_APP_EXTENSION, furi_string_get_cstr(key_name)); | ||||||
|     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); | ||||||
| 
 | 
 | ||||||
|     view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewTextInput); |     view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewTextInput); | ||||||
| 
 | 
 | ||||||
|     string_clear(key_name); |     furi_string_free(key_name); | ||||||
|     string_clear(folder_path); |     furi_string_free(folder_path); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool ibutton_scene_save_name_on_event(void* context, SceneManagerEvent event) { | bool ibutton_scene_save_name_on_event(void* context, SceneManagerEvent event) { | ||||||
|  | |||||||
| @ -39,7 +39,7 @@ bool ibutton_scene_start_on_event(void* context, SceneManagerEvent event) { | |||||||
|         if(event.event == SubmenuIndexRead) { |         if(event.event == SubmenuIndexRead) { | ||||||
|             scene_manager_next_scene(ibutton->scene_manager, iButtonSceneRead); |             scene_manager_next_scene(ibutton->scene_manager, iButtonSceneRead); | ||||||
|         } else if(event.event == SubmenuIndexSaved) { |         } else if(event.event == SubmenuIndexSaved) { | ||||||
|             string_set_str(ibutton->file_path, IBUTTON_APP_FOLDER); |             furi_string_set(ibutton->file_path, IBUTTON_APP_FOLDER); | ||||||
|             scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSelectKey); |             scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSelectKey); | ||||||
|         } else if(event.event == SubmenuIndexAdd) { |         } else if(event.event == SubmenuIndexAdd) { | ||||||
|             scene_manager_next_scene(ibutton->scene_manager, iButtonSceneAddType); |             scene_manager_next_scene(ibutton->scene_manager, iButtonSceneAddType); | ||||||
|  | |||||||
| @ -1,5 +1,4 @@ | |||||||
| #include "../ibutton_i.h" | #include "../ibutton_i.h" | ||||||
| #include "m-string.h" |  | ||||||
| #include "toolbox/path.h" | #include "toolbox/path.h" | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
| @ -20,15 +19,15 @@ void ibutton_scene_write_on_enter(void* context) { | |||||||
| 
 | 
 | ||||||
|     const uint8_t* key_data = ibutton_key_get_data_p(key); |     const uint8_t* key_data = ibutton_key_get_data_p(key); | ||||||
| 
 | 
 | ||||||
|     string_t key_name; |     FuriString* key_name; | ||||||
|     string_init(key_name); |     key_name = furi_string_alloc(); | ||||||
|     if(string_end_with_str_p(ibutton->file_path, IBUTTON_APP_EXTENSION)) { |     if(furi_string_end_with(ibutton->file_path, IBUTTON_APP_EXTENSION)) { | ||||||
|         path_extract_filename(ibutton->file_path, key_name, true); |         path_extract_filename(ibutton->file_path, key_name, true); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // check that stored key has name
 |     // check that stored key has name
 | ||||||
|     if(!string_empty_p(key_name)) { |     if(!furi_string_empty(key_name)) { | ||||||
|         ibutton_text_store_set(ibutton, "%s", string_get_cstr(key_name)); |         ibutton_text_store_set(ibutton, "%s", furi_string_get_cstr(key_name)); | ||||||
|     } else { |     } else { | ||||||
|         // if not, show key data
 |         // if not, show key data
 | ||||||
|         switch(ibutton_key_get_type(key)) { |         switch(ibutton_key_get_type(key)) { | ||||||
| @ -66,7 +65,7 @@ void ibutton_scene_write_on_enter(void* context) { | |||||||
|     ibutton_worker_write_set_callback(worker, ibutton_scene_write_callback, ibutton); |     ibutton_worker_write_set_callback(worker, ibutton_scene_write_callback, ibutton); | ||||||
|     ibutton_worker_write_start(worker, key); |     ibutton_worker_write_start(worker, key); | ||||||
| 
 | 
 | ||||||
|     string_clear(key_name); |     furi_string_free(key_name); | ||||||
| 
 | 
 | ||||||
|     ibutton_notification_message(ibutton, iButtonNotificationMessageEmulateStart); |     ibutton_notification_message(ibutton, iButtonNotificationMessageEmulateStart); | ||||||
| } | } | ||||||
|  | |||||||
| @ -65,51 +65,52 @@ static void infrared_rpc_command_callback(RpcAppSystemEvent event, void* context | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void infrared_find_vacant_remote_name(string_t name, const char* path) { | static void infrared_find_vacant_remote_name(FuriString* name, const char* path) { | ||||||
|     Storage* storage = furi_record_open(RECORD_STORAGE); |     Storage* storage = furi_record_open(RECORD_STORAGE); | ||||||
| 
 | 
 | ||||||
|     string_t base_path; |     FuriString* base_path; | ||||||
|     string_init_set_str(base_path, path); |     base_path = furi_string_alloc_set(path); | ||||||
| 
 | 
 | ||||||
|     if(string_end_with_str_p(base_path, INFRARED_APP_EXTENSION)) { |     if(furi_string_end_with(base_path, INFRARED_APP_EXTENSION)) { | ||||||
|         size_t filename_start = string_search_rchar(base_path, '/'); |         size_t filename_start = furi_string_search_rchar(base_path, '/'); | ||||||
|         string_left(base_path, filename_start); |         furi_string_left(base_path, filename_start); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     string_printf(base_path, "%s/%s%s", path, string_get_cstr(name), INFRARED_APP_EXTENSION); |     furi_string_printf( | ||||||
|  |         base_path, "%s/%s%s", path, furi_string_get_cstr(name), INFRARED_APP_EXTENSION); | ||||||
| 
 | 
 | ||||||
|     FS_Error status = storage_common_stat(storage, string_get_cstr(base_path), NULL); |     FS_Error status = storage_common_stat(storage, furi_string_get_cstr(base_path), NULL); | ||||||
| 
 | 
 | ||||||
|     if(status == FSE_OK) { |     if(status == FSE_OK) { | ||||||
|         /* If the suggested name is occupied, try another one (name2, name3, etc) */ |         /* If the suggested name is occupied, try another one (name2, name3, etc) */ | ||||||
|         size_t dot = string_search_rchar(base_path, '.'); |         size_t dot = furi_string_search_rchar(base_path, '.'); | ||||||
|         string_left(base_path, dot); |         furi_string_left(base_path, dot); | ||||||
| 
 | 
 | ||||||
|         string_t path_temp; |         FuriString* path_temp; | ||||||
|         string_init(path_temp); |         path_temp = furi_string_alloc(); | ||||||
| 
 | 
 | ||||||
|         uint32_t i = 1; |         uint32_t i = 1; | ||||||
|         do { |         do { | ||||||
|             string_printf( |             furi_string_printf( | ||||||
|                 path_temp, "%s%u%s", string_get_cstr(base_path), ++i, INFRARED_APP_EXTENSION); |                 path_temp, "%s%lu%s", furi_string_get_cstr(base_path), ++i, INFRARED_APP_EXTENSION); | ||||||
|             status = storage_common_stat(storage, string_get_cstr(path_temp), NULL); |             status = storage_common_stat(storage, furi_string_get_cstr(path_temp), NULL); | ||||||
|         } while(status == FSE_OK); |         } while(status == FSE_OK); | ||||||
| 
 | 
 | ||||||
|         string_clear(path_temp); |         furi_string_free(path_temp); | ||||||
| 
 | 
 | ||||||
|         if(status == FSE_NOT_EXIST) { |         if(status == FSE_NOT_EXIST) { | ||||||
|             string_cat_printf(name, "%u", i); |             furi_string_cat_printf(name, "%lu", i); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     string_clear(base_path); |     furi_string_free(base_path); | ||||||
|     furi_record_close(RECORD_STORAGE); |     furi_record_close(RECORD_STORAGE); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static Infrared* infrared_alloc() { | static Infrared* infrared_alloc() { | ||||||
|     Infrared* infrared = malloc(sizeof(Infrared)); |     Infrared* infrared = malloc(sizeof(Infrared)); | ||||||
| 
 | 
 | ||||||
|     string_init(infrared->file_path); |     infrared->file_path = furi_string_alloc(); | ||||||
| 
 | 
 | ||||||
|     InfraredAppState* app_state = &infrared->app_state; |     InfraredAppState* app_state = &infrared->app_state; | ||||||
|     app_state->is_learning_new_remote = false; |     app_state->is_learning_new_remote = false; | ||||||
| @ -232,7 +233,7 @@ static void infrared_free(Infrared* infrared) { | |||||||
|     furi_record_close(RECORD_GUI); |     furi_record_close(RECORD_GUI); | ||||||
|     infrared->gui = NULL; |     infrared->gui = NULL; | ||||||
| 
 | 
 | ||||||
|     string_clear(infrared->file_path); |     furi_string_free(infrared->file_path); | ||||||
| 
 | 
 | ||||||
|     free(infrared); |     free(infrared); | ||||||
| } | } | ||||||
| @ -243,19 +244,20 @@ bool infrared_add_remote_with_button( | |||||||
|     InfraredSignal* signal) { |     InfraredSignal* signal) { | ||||||
|     InfraredRemote* remote = infrared->remote; |     InfraredRemote* remote = infrared->remote; | ||||||
| 
 | 
 | ||||||
|     string_t new_name, new_path; |     FuriString *new_name, *new_path; | ||||||
|     string_init_set_str(new_name, INFRARED_DEFAULT_REMOTE_NAME); |     new_name = furi_string_alloc_set(INFRARED_DEFAULT_REMOTE_NAME); | ||||||
|     string_init_set_str(new_path, INFRARED_APP_FOLDER); |     new_path = furi_string_alloc_set(INFRARED_APP_FOLDER); | ||||||
| 
 | 
 | ||||||
|     infrared_find_vacant_remote_name(new_name, string_get_cstr(new_path)); |     infrared_find_vacant_remote_name(new_name, furi_string_get_cstr(new_path)); | ||||||
|     string_cat_printf(new_path, "/%s%s", string_get_cstr(new_name), INFRARED_APP_EXTENSION); |     furi_string_cat_printf( | ||||||
|  |         new_path, "/%s%s", furi_string_get_cstr(new_name), INFRARED_APP_EXTENSION); | ||||||
| 
 | 
 | ||||||
|     infrared_remote_reset(remote); |     infrared_remote_reset(remote); | ||||||
|     infrared_remote_set_name(remote, string_get_cstr(new_name)); |     infrared_remote_set_name(remote, furi_string_get_cstr(new_name)); | ||||||
|     infrared_remote_set_path(remote, string_get_cstr(new_path)); |     infrared_remote_set_path(remote, furi_string_get_cstr(new_path)); | ||||||
| 
 | 
 | ||||||
|     string_clear(new_name); |     furi_string_free(new_name); | ||||||
|     string_clear(new_path); |     furi_string_free(new_path); | ||||||
|     return infrared_remote_add_button(remote, button_name, signal); |     return infrared_remote_add_button(remote, button_name, signal); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -267,28 +269,29 @@ bool infrared_rename_current_remote(Infrared* infrared, const char* name) { | |||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     string_t new_name; |     FuriString* new_name; | ||||||
|     string_init_set_str(new_name, name); |     new_name = furi_string_alloc_set(name); | ||||||
| 
 | 
 | ||||||
|     infrared_find_vacant_remote_name(new_name, remote_path); |     infrared_find_vacant_remote_name(new_name, remote_path); | ||||||
| 
 | 
 | ||||||
|     string_t new_path; |     FuriString* new_path; | ||||||
|     string_init_set(new_path, infrared_remote_get_path(remote)); |     new_path = furi_string_alloc_set(infrared_remote_get_path(remote)); | ||||||
|     if(string_end_with_str_p(new_path, INFRARED_APP_EXTENSION)) { |     if(furi_string_end_with(new_path, INFRARED_APP_EXTENSION)) { | ||||||
|         size_t filename_start = string_search_rchar(new_path, '/'); |         size_t filename_start = furi_string_search_rchar(new_path, '/'); | ||||||
|         string_left(new_path, filename_start); |         furi_string_left(new_path, filename_start); | ||||||
|     } |     } | ||||||
|     string_cat_printf(new_path, "/%s%s", string_get_cstr(new_name), INFRARED_APP_EXTENSION); |     furi_string_cat_printf( | ||||||
|  |         new_path, "/%s%s", furi_string_get_cstr(new_name), INFRARED_APP_EXTENSION); | ||||||
| 
 | 
 | ||||||
|     Storage* storage = furi_record_open(RECORD_STORAGE); |     Storage* storage = furi_record_open(RECORD_STORAGE); | ||||||
| 
 | 
 | ||||||
|     FS_Error status = storage_common_rename( |     FS_Error status = storage_common_rename( | ||||||
|         storage, infrared_remote_get_path(remote), string_get_cstr(new_path)); |         storage, infrared_remote_get_path(remote), furi_string_get_cstr(new_path)); | ||||||
|     infrared_remote_set_name(remote, string_get_cstr(new_name)); |     infrared_remote_set_name(remote, furi_string_get_cstr(new_name)); | ||||||
|     infrared_remote_set_path(remote, string_get_cstr(new_path)); |     infrared_remote_set_path(remote, furi_string_get_cstr(new_path)); | ||||||
| 
 | 
 | ||||||
|     string_clear(new_name); |     furi_string_free(new_name); | ||||||
|     string_clear(new_path); |     furi_string_free(new_path); | ||||||
| 
 | 
 | ||||||
|     furi_record_close(RECORD_STORAGE); |     furi_record_close(RECORD_STORAGE); | ||||||
|     return (status == FSE_OK || status == FSE_EXIST); |     return (status == FSE_OK || status == FSE_EXIST); | ||||||
| @ -435,7 +438,7 @@ int32_t infrared_app(void* p) { | |||||||
|             rpc_system_app_send_started(infrared->rpc_ctx); |             rpc_system_app_send_started(infrared->rpc_ctx); | ||||||
|             is_rpc_mode = true; |             is_rpc_mode = true; | ||||||
|         } else { |         } else { | ||||||
|             string_set_str(infrared->file_path, (const char*)p); |             furi_string_set(infrared->file_path, (const char*)p); | ||||||
|             is_remote_loaded = infrared_remote_load(infrared->remote, infrared->file_path); |             is_remote_loaded = infrared_remote_load(infrared->remote, infrared->file_path); | ||||||
|             if(!is_remote_loaded) { |             if(!is_remote_loaded) { | ||||||
|                 dialog_message_show_storage_error( |                 dialog_message_show_storage_error( | ||||||
|  | |||||||
| @ -2,7 +2,6 @@ | |||||||
| 
 | 
 | ||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
| #include <m-dict.h> | #include <m-dict.h> | ||||||
| #include <m-string.h> |  | ||||||
| #include <flipper_format/flipper_format.h> | #include <flipper_format/flipper_format.h> | ||||||
| 
 | 
 | ||||||
| #include "infrared_signal.h" | #include "infrared_signal.h" | ||||||
| @ -14,15 +13,15 @@ typedef struct { | |||||||
| 
 | 
 | ||||||
| DICT_DEF2( | DICT_DEF2( | ||||||
|     InfraredBruteForceRecordDict, |     InfraredBruteForceRecordDict, | ||||||
|     string_t, |     FuriString*, | ||||||
|     STRING_OPLIST, |     FURI_STRING_OPLIST, | ||||||
|     InfraredBruteForceRecord, |     InfraredBruteForceRecord, | ||||||
|     M_POD_OPLIST); |     M_POD_OPLIST); | ||||||
| 
 | 
 | ||||||
| struct InfraredBruteForce { | struct InfraredBruteForce { | ||||||
|     FlipperFormat* ff; |     FlipperFormat* ff; | ||||||
|     const char* db_filename; |     const char* db_filename; | ||||||
|     string_t current_record_name; |     FuriString* current_record_name; | ||||||
|     InfraredSignal* current_signal; |     InfraredSignal* current_signal; | ||||||
|     InfraredBruteForceRecordDict_t records; |     InfraredBruteForceRecordDict_t records; | ||||||
|     bool is_started; |     bool is_started; | ||||||
| @ -34,7 +33,7 @@ InfraredBruteForce* infrared_brute_force_alloc() { | |||||||
|     brute_force->db_filename = NULL; |     brute_force->db_filename = NULL; | ||||||
|     brute_force->current_signal = NULL; |     brute_force->current_signal = NULL; | ||||||
|     brute_force->is_started = false; |     brute_force->is_started = false; | ||||||
|     string_init(brute_force->current_record_name); |     brute_force->current_record_name = furi_string_alloc(); | ||||||
|     InfraredBruteForceRecordDict_init(brute_force->records); |     InfraredBruteForceRecordDict_init(brute_force->records); | ||||||
|     return brute_force; |     return brute_force; | ||||||
| } | } | ||||||
| @ -42,7 +41,7 @@ InfraredBruteForce* infrared_brute_force_alloc() { | |||||||
| void infrared_brute_force_free(InfraredBruteForce* brute_force) { | void infrared_brute_force_free(InfraredBruteForce* brute_force) { | ||||||
|     furi_assert(!brute_force->is_started); |     furi_assert(!brute_force->is_started); | ||||||
|     InfraredBruteForceRecordDict_clear(brute_force->records); |     InfraredBruteForceRecordDict_clear(brute_force->records); | ||||||
|     string_clear(brute_force->current_record_name); |     furi_string_free(brute_force->current_record_name); | ||||||
|     free(brute_force); |     free(brute_force); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -61,8 +60,8 @@ bool infrared_brute_force_calculate_messages(InfraredBruteForce* brute_force) { | |||||||
| 
 | 
 | ||||||
|     success = flipper_format_buffered_file_open_existing(ff, brute_force->db_filename); |     success = flipper_format_buffered_file_open_existing(ff, brute_force->db_filename); | ||||||
|     if(success) { |     if(success) { | ||||||
|         string_t signal_name; |         FuriString* signal_name; | ||||||
|         string_init(signal_name); |         signal_name = furi_string_alloc(); | ||||||
|         while(flipper_format_read_string(ff, "name", signal_name)) { |         while(flipper_format_read_string(ff, "name", signal_name)) { | ||||||
|             InfraredBruteForceRecord* record = |             InfraredBruteForceRecord* record = | ||||||
|                 InfraredBruteForceRecordDict_get(brute_force->records, signal_name); |                 InfraredBruteForceRecordDict_get(brute_force->records, signal_name); | ||||||
| @ -70,7 +69,7 @@ bool infrared_brute_force_calculate_messages(InfraredBruteForce* brute_force) { | |||||||
|                 ++(record->count); |                 ++(record->count); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         string_clear(signal_name); |         furi_string_free(signal_name); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     flipper_format_free(ff); |     flipper_format_free(ff); | ||||||
| @ -94,7 +93,7 @@ bool infrared_brute_force_start( | |||||||
|         if(record->value.index == index) { |         if(record->value.index == index) { | ||||||
|             *record_count = record->value.count; |             *record_count = record->value.count; | ||||||
|             if(*record_count) { |             if(*record_count) { | ||||||
|                 string_set(brute_force->current_record_name, record->key); |                 furi_string_set(brute_force->current_record_name, record->key); | ||||||
|             } |             } | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
| @ -118,7 +117,7 @@ bool infrared_brute_force_is_started(InfraredBruteForce* brute_force) { | |||||||
| 
 | 
 | ||||||
| void infrared_brute_force_stop(InfraredBruteForce* brute_force) { | void infrared_brute_force_stop(InfraredBruteForce* brute_force) { | ||||||
|     furi_assert(brute_force->is_started); |     furi_assert(brute_force->is_started); | ||||||
|     string_reset(brute_force->current_record_name); |     furi_string_reset(brute_force->current_record_name); | ||||||
|     infrared_signal_free(brute_force->current_signal); |     infrared_signal_free(brute_force->current_signal); | ||||||
|     flipper_format_free(brute_force->ff); |     flipper_format_free(brute_force->ff); | ||||||
|     brute_force->current_signal = NULL; |     brute_force->current_signal = NULL; | ||||||
| @ -142,10 +141,10 @@ void infrared_brute_force_add_record( | |||||||
|     uint32_t index, |     uint32_t index, | ||||||
|     const char* name) { |     const char* name) { | ||||||
|     InfraredBruteForceRecord value = {.index = index, .count = 0}; |     InfraredBruteForceRecord value = {.index = index, .count = 0}; | ||||||
|     string_t key; |     FuriString* key; | ||||||
|     string_init_set_str(key, name); |     key = furi_string_alloc_set(name); | ||||||
|     InfraredBruteForceRecordDict_set_at(brute_force->records, key, value); |     InfraredBruteForceRecordDict_set_at(brute_force->records, key, value); | ||||||
|     string_clear(key); |     furi_string_free(key); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void infrared_brute_force_reset(InfraredBruteForce* brute_force) { | void infrared_brute_force_reset(InfraredBruteForce* brute_force) { | ||||||
|  | |||||||
| @ -1,4 +1,3 @@ | |||||||
| #include <m-string.h> |  | ||||||
| #include <cli/cli.h> | #include <cli/cli.h> | ||||||
| #include <infrared.h> | #include <infrared.h> | ||||||
| #include <infrared_worker.h> | #include <infrared_worker.h> | ||||||
| @ -10,13 +9,13 @@ | |||||||
| 
 | 
 | ||||||
| #define INFRARED_CLI_BUF_SIZE 10 | #define INFRARED_CLI_BUF_SIZE 10 | ||||||
| 
 | 
 | ||||||
| static void infrared_cli_start_ir_rx(Cli* cli, string_t args); | static void infrared_cli_start_ir_rx(Cli* cli, FuriString* args); | ||||||
| static void infrared_cli_start_ir_tx(Cli* cli, string_t args); | static void infrared_cli_start_ir_tx(Cli* cli, FuriString* args); | ||||||
| static void infrared_cli_process_decode(Cli* cli, string_t args); | static void infrared_cli_process_decode(Cli* cli, FuriString* args); | ||||||
| 
 | 
 | ||||||
| static const struct { | static const struct { | ||||||
|     const char* cmd; |     const char* cmd; | ||||||
|     void (*process_function)(Cli* cli, string_t args); |     void (*process_function)(Cli* cli, FuriString* args); | ||||||
| } infrared_cli_commands[] = { | } infrared_cli_commands[] = { | ||||||
|     {.cmd = "rx", .process_function = infrared_cli_start_ir_rx}, |     {.cmd = "rx", .process_function = infrared_cli_start_ir_rx}, | ||||||
|     {.cmd = "tx", .process_function = infrared_cli_start_ir_tx}, |     {.cmd = "tx", .process_function = infrared_cli_start_ir_tx}, | ||||||
| @ -58,7 +57,7 @@ static void signal_received_callback(void* context, InfraredWorkerSignal* receiv | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void infrared_cli_start_ir_rx(Cli* cli, string_t args) { | static void infrared_cli_start_ir_rx(Cli* cli, FuriString* args) { | ||||||
|     UNUSED(cli); |     UNUSED(cli); | ||||||
|     UNUSED(args); |     UNUSED(args); | ||||||
|     InfraredWorker* worker = infrared_worker_alloc(); |     InfraredWorker* worker = infrared_worker_alloc(); | ||||||
| @ -151,9 +150,9 @@ static bool infrared_cli_parse_raw(const char* str, InfraredSignal* signal) { | |||||||
|     return infrared_signal_is_valid(signal); |     return infrared_signal_is_valid(signal); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void infrared_cli_start_ir_tx(Cli* cli, string_t args) { | static void infrared_cli_start_ir_tx(Cli* cli, FuriString* args) { | ||||||
|     UNUSED(cli); |     UNUSED(cli); | ||||||
|     const char* str = string_get_cstr(args); |     const char* str = furi_string_get_cstr(args); | ||||||
|     InfraredSignal* signal = infrared_signal_alloc(); |     InfraredSignal* signal = infrared_signal_alloc(); | ||||||
| 
 | 
 | ||||||
|     bool success = infrared_cli_parse_message(str, signal) || infrared_cli_parse_raw(str, signal); |     bool success = infrared_cli_parse_message(str, signal) || infrared_cli_parse_raw(str, signal); | ||||||
| @ -231,8 +230,8 @@ static bool infrared_cli_decode_file(FlipperFormat* input_file, FlipperFormat* o | |||||||
|     InfraredSignal* signal = infrared_signal_alloc(); |     InfraredSignal* signal = infrared_signal_alloc(); | ||||||
|     InfraredDecoderHandler* decoder = infrared_alloc_decoder(); |     InfraredDecoderHandler* decoder = infrared_alloc_decoder(); | ||||||
| 
 | 
 | ||||||
|     string_t tmp; |     FuriString* tmp; | ||||||
|     string_init(tmp); |     tmp = furi_string_alloc(); | ||||||
| 
 | 
 | ||||||
|     while(infrared_signal_read(signal, input_file, tmp)) { |     while(infrared_signal_read(signal, input_file, tmp)) { | ||||||
|         ret = false; |         ret = false; | ||||||
| @ -242,7 +241,7 @@ static bool infrared_cli_decode_file(FlipperFormat* input_file, FlipperFormat* o | |||||||
|         } |         } | ||||||
|         if(!infrared_signal_is_raw(signal)) { |         if(!infrared_signal_is_raw(signal)) { | ||||||
|             if(output_file && |             if(output_file && | ||||||
|                !infrared_cli_save_signal(signal, output_file, string_get_cstr(tmp))) { |                !infrared_cli_save_signal(signal, output_file, furi_string_get_cstr(tmp))) { | ||||||
|                 break; |                 break; | ||||||
|             } else { |             } else { | ||||||
|                 printf("Skipping decoded signal\r\n"); |                 printf("Skipping decoded signal\r\n"); | ||||||
| @ -250,31 +249,33 @@ static bool infrared_cli_decode_file(FlipperFormat* input_file, FlipperFormat* o | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         InfraredRawSignal* raw_signal = infrared_signal_get_raw_signal(signal); |         InfraredRawSignal* raw_signal = infrared_signal_get_raw_signal(signal); | ||||||
|         printf("Raw signal: %s, %u samples\r\n", string_get_cstr(tmp), raw_signal->timings_size); |         printf( | ||||||
|         if(!infrared_cli_decode_raw_signal(raw_signal, decoder, output_file, string_get_cstr(tmp))) |             "Raw signal: %s, %u samples\r\n", furi_string_get_cstr(tmp), raw_signal->timings_size); | ||||||
|  |         if(!infrared_cli_decode_raw_signal( | ||||||
|  |                raw_signal, decoder, output_file, furi_string_get_cstr(tmp))) | ||||||
|             break; |             break; | ||||||
|         ret = true; |         ret = true; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     infrared_free_decoder(decoder); |     infrared_free_decoder(decoder); | ||||||
|     infrared_signal_free(signal); |     infrared_signal_free(signal); | ||||||
|     string_clear(tmp); |     furi_string_free(tmp); | ||||||
| 
 | 
 | ||||||
|     return ret; |     return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void infrared_cli_process_decode(Cli* cli, string_t args) { | static void infrared_cli_process_decode(Cli* cli, FuriString* args) { | ||||||
|     UNUSED(cli); |     UNUSED(cli); | ||||||
|     Storage* storage = furi_record_open(RECORD_STORAGE); |     Storage* storage = furi_record_open(RECORD_STORAGE); | ||||||
|     FlipperFormat* input_file = flipper_format_buffered_file_alloc(storage); |     FlipperFormat* input_file = flipper_format_buffered_file_alloc(storage); | ||||||
|     FlipperFormat* output_file = NULL; |     FlipperFormat* output_file = NULL; | ||||||
| 
 | 
 | ||||||
|     uint32_t version; |     uint32_t version; | ||||||
|     string_t tmp, header, input_path, output_path; |     FuriString *tmp, *header, *input_path, *output_path; | ||||||
|     string_init(tmp); |     tmp = furi_string_alloc(); | ||||||
|     string_init(header); |     header = furi_string_alloc(); | ||||||
|     string_init(input_path); |     input_path = furi_string_alloc(); | ||||||
|     string_init(output_path); |     output_path = furi_string_alloc(); | ||||||
| 
 | 
 | ||||||
|     do { |     do { | ||||||
|         if(!args_read_probably_quoted_string_and_trim(args, input_path)) { |         if(!args_read_probably_quoted_string_and_trim(args, input_path)) { | ||||||
| @ -283,26 +284,32 @@ static void infrared_cli_process_decode(Cli* cli, string_t args) { | |||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         args_read_probably_quoted_string_and_trim(args, output_path); |         args_read_probably_quoted_string_and_trim(args, output_path); | ||||||
|         if(!flipper_format_buffered_file_open_existing(input_file, string_get_cstr(input_path))) { |         if(!flipper_format_buffered_file_open_existing( | ||||||
|             printf("Failed to open file for reading: \"%s\"\r\n", string_get_cstr(input_path)); |                input_file, furi_string_get_cstr(input_path))) { | ||||||
|  |             printf( | ||||||
|  |                 "Failed to open file for reading: \"%s\"\r\n", furi_string_get_cstr(input_path)); | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         if(!flipper_format_read_header(input_file, header, &version) || |         if(!flipper_format_read_header(input_file, header, &version) || | ||||||
|            (!string_start_with_str_p(header, "IR")) || version != 1) { |            (!furi_string_start_with_str(header, "IR")) || version != 1) { | ||||||
|             printf("Invalid or corrupted input file: \"%s\"\r\n", string_get_cstr(input_path)); |             printf( | ||||||
|  |                 "Invalid or corrupted input file: \"%s\"\r\n", furi_string_get_cstr(input_path)); | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         if(!string_empty_p(output_path)) { |         if(!furi_string_empty(output_path)) { | ||||||
|             printf("Writing output to file: \"%s\"\r\n", string_get_cstr(output_path)); |             printf("Writing output to file: \"%s\"\r\n", furi_string_get_cstr(output_path)); | ||||||
|             output_file = flipper_format_file_alloc(storage); |             output_file = flipper_format_file_alloc(storage); | ||||||
|         } |         } | ||||||
|         if(output_file && |         if(output_file && | ||||||
|            !flipper_format_file_open_always(output_file, string_get_cstr(output_path))) { |            !flipper_format_file_open_always(output_file, furi_string_get_cstr(output_path))) { | ||||||
|             printf("Failed to open file for writing: \"%s\"\r\n", string_get_cstr(output_path)); |             printf( | ||||||
|  |                 "Failed to open file for writing: \"%s\"\r\n", furi_string_get_cstr(output_path)); | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         if(output_file && !flipper_format_write_header(output_file, header, version)) { |         if(output_file && !flipper_format_write_header(output_file, header, version)) { | ||||||
|             printf("Failed to write to the output file: \"%s\"\r\n", string_get_cstr(output_path)); |             printf( | ||||||
|  |                 "Failed to write to the output file: \"%s\"\r\n", | ||||||
|  |                 furi_string_get_cstr(output_path)); | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         if(!infrared_cli_decode_file(input_file, output_file)) { |         if(!infrared_cli_decode_file(input_file, output_file)) { | ||||||
| @ -311,31 +318,31 @@ static void infrared_cli_process_decode(Cli* cli, string_t args) { | |||||||
|         printf("File successfully decoded.\r\n"); |         printf("File successfully decoded.\r\n"); | ||||||
|     } while(false); |     } while(false); | ||||||
| 
 | 
 | ||||||
|     string_clear(tmp); |     furi_string_free(tmp); | ||||||
|     string_clear(header); |     furi_string_free(header); | ||||||
|     string_clear(input_path); |     furi_string_free(input_path); | ||||||
|     string_clear(output_path); |     furi_string_free(output_path); | ||||||
| 
 | 
 | ||||||
|     flipper_format_free(input_file); |     flipper_format_free(input_file); | ||||||
|     if(output_file) flipper_format_free(output_file); |     if(output_file) flipper_format_free(output_file); | ||||||
|     furi_record_close(RECORD_STORAGE); |     furi_record_close(RECORD_STORAGE); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void infrared_cli_start_ir(Cli* cli, string_t args, void* context) { | static void infrared_cli_start_ir(Cli* cli, FuriString* args, void* context) { | ||||||
|     UNUSED(context); |     UNUSED(context); | ||||||
|     if(furi_hal_infrared_is_busy()) { |     if(furi_hal_infrared_is_busy()) { | ||||||
|         printf("INFRARED is busy. Exiting."); |         printf("INFRARED is busy. Exiting."); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     string_t command; |     FuriString* command; | ||||||
|     string_init(command); |     command = furi_string_alloc(); | ||||||
|     args_read_string_and_trim(args, command); |     args_read_string_and_trim(args, command); | ||||||
| 
 | 
 | ||||||
|     size_t i = 0; |     size_t i = 0; | ||||||
|     for(; i < COUNT_OF(infrared_cli_commands); ++i) { |     for(; i < COUNT_OF(infrared_cli_commands); ++i) { | ||||||
|         size_t cmd_len = strlen(infrared_cli_commands[i].cmd); |         size_t cmd_len = strlen(infrared_cli_commands[i].cmd); | ||||||
|         if(!strncmp(string_get_cstr(command), infrared_cli_commands[i].cmd, cmd_len)) { |         if(!strncmp(furi_string_get_cstr(command), infrared_cli_commands[i].cmd, cmd_len)) { | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -346,7 +353,7 @@ static void infrared_cli_start_ir(Cli* cli, string_t args, void* context) { | |||||||
|         infrared_cli_print_usage(); |         infrared_cli_print_usage(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     string_clear(command); |     furi_string_free(command); | ||||||
| } | } | ||||||
| void infrared_on_system_start() { | void infrared_on_system_start() { | ||||||
| #ifdef SRV_CLI | #ifdef SRV_CLI | ||||||
|  | |||||||
| @ -96,7 +96,7 @@ struct Infrared { | |||||||
|     Loading* loading; |     Loading* loading; | ||||||
|     InfraredProgressView* progress; |     InfraredProgressView* progress; | ||||||
| 
 | 
 | ||||||
|     string_t file_path; |     FuriString* file_path; | ||||||
|     char text_store[INFRARED_TEXT_STORE_NUM][INFRARED_TEXT_STORE_SIZE + 1]; |     char text_store[INFRARED_TEXT_STORE_NUM][INFRARED_TEXT_STORE_SIZE + 1]; | ||||||
|     InfraredAppState app_state; |     InfraredAppState app_state; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -3,7 +3,6 @@ | |||||||
| #include <stdbool.h> | #include <stdbool.h> | ||||||
| #include <stddef.h> | #include <stddef.h> | ||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
| #include <m-string.h> |  | ||||||
| #include <m-array.h> | #include <m-array.h> | ||||||
| #include <toolbox/path.h> | #include <toolbox/path.h> | ||||||
| #include <storage/storage.h> | #include <storage/storage.h> | ||||||
| @ -15,8 +14,8 @@ ARRAY_DEF(InfraredButtonArray, InfraredRemoteButton*, M_PTR_OPLIST); | |||||||
| 
 | 
 | ||||||
| struct InfraredRemote { | struct InfraredRemote { | ||||||
|     InfraredButtonArray_t buttons; |     InfraredButtonArray_t buttons; | ||||||
|     string_t name; |     FuriString* name; | ||||||
|     string_t path; |     FuriString* path; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static void infrared_remote_clear_buttons(InfraredRemote* remote) { | static void infrared_remote_clear_buttons(InfraredRemote* remote) { | ||||||
| @ -31,39 +30,39 @@ static void infrared_remote_clear_buttons(InfraredRemote* remote) { | |||||||
| InfraredRemote* infrared_remote_alloc() { | InfraredRemote* infrared_remote_alloc() { | ||||||
|     InfraredRemote* remote = malloc(sizeof(InfraredRemote)); |     InfraredRemote* remote = malloc(sizeof(InfraredRemote)); | ||||||
|     InfraredButtonArray_init(remote->buttons); |     InfraredButtonArray_init(remote->buttons); | ||||||
|     string_init(remote->name); |     remote->name = furi_string_alloc(); | ||||||
|     string_init(remote->path); |     remote->path = furi_string_alloc(); | ||||||
|     return remote; |     return remote; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void infrared_remote_free(InfraredRemote* remote) { | void infrared_remote_free(InfraredRemote* remote) { | ||||||
|     infrared_remote_clear_buttons(remote); |     infrared_remote_clear_buttons(remote); | ||||||
|     InfraredButtonArray_clear(remote->buttons); |     InfraredButtonArray_clear(remote->buttons); | ||||||
|     string_clear(remote->path); |     furi_string_free(remote->path); | ||||||
|     string_clear(remote->name); |     furi_string_free(remote->name); | ||||||
|     free(remote); |     free(remote); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void infrared_remote_reset(InfraredRemote* remote) { | void infrared_remote_reset(InfraredRemote* remote) { | ||||||
|     infrared_remote_clear_buttons(remote); |     infrared_remote_clear_buttons(remote); | ||||||
|     string_reset(remote->name); |     furi_string_reset(remote->name); | ||||||
|     string_reset(remote->path); |     furi_string_reset(remote->path); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void infrared_remote_set_name(InfraredRemote* remote, const char* name) { | void infrared_remote_set_name(InfraredRemote* remote, const char* name) { | ||||||
|     string_set_str(remote->name, name); |     furi_string_set(remote->name, name); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const char* infrared_remote_get_name(InfraredRemote* remote) { | const char* infrared_remote_get_name(InfraredRemote* remote) { | ||||||
|     return string_get_cstr(remote->name); |     return furi_string_get_cstr(remote->name); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void infrared_remote_set_path(InfraredRemote* remote, const char* path) { | void infrared_remote_set_path(InfraredRemote* remote, const char* path) { | ||||||
|     string_set_str(remote->path, path); |     furi_string_set(remote->path, path); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const char* infrared_remote_get_path(InfraredRemote* remote) { | const char* infrared_remote_get_path(InfraredRemote* remote) { | ||||||
|     return string_get_cstr(remote->path); |     return furi_string_get_cstr(remote->path); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| size_t infrared_remote_get_button_count(InfraredRemote* remote) { | size_t infrared_remote_get_button_count(InfraredRemote* remote) { | ||||||
| @ -112,7 +111,7 @@ bool infrared_remote_delete_button(InfraredRemote* remote, size_t index) { | |||||||
| bool infrared_remote_store(InfraredRemote* remote) { | bool infrared_remote_store(InfraredRemote* remote) { | ||||||
|     Storage* storage = furi_record_open(RECORD_STORAGE); |     Storage* storage = furi_record_open(RECORD_STORAGE); | ||||||
|     FlipperFormat* ff = flipper_format_file_alloc(storage); |     FlipperFormat* ff = flipper_format_file_alloc(storage); | ||||||
|     const char* path = string_get_cstr(remote->path); |     const char* path = furi_string_get_cstr(remote->path); | ||||||
| 
 | 
 | ||||||
|     FURI_LOG_I(TAG, "store file: \'%s\'", path); |     FURI_LOG_I(TAG, "store file: \'%s\'", path); | ||||||
| 
 | 
 | ||||||
| @ -138,33 +137,33 @@ bool infrared_remote_store(InfraredRemote* remote) { | |||||||
|     return success; |     return success; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool infrared_remote_load(InfraredRemote* remote, string_t path) { | bool infrared_remote_load(InfraredRemote* remote, FuriString* path) { | ||||||
|     Storage* storage = furi_record_open(RECORD_STORAGE); |     Storage* storage = furi_record_open(RECORD_STORAGE); | ||||||
|     FlipperFormat* ff = flipper_format_buffered_file_alloc(storage); |     FlipperFormat* ff = flipper_format_buffered_file_alloc(storage); | ||||||
| 
 | 
 | ||||||
|     string_t buf; |     FuriString* buf; | ||||||
|     string_init(buf); |     buf = furi_string_alloc(); | ||||||
| 
 | 
 | ||||||
|     FURI_LOG_I(TAG, "load file: \'%s\'", string_get_cstr(path)); |     FURI_LOG_I(TAG, "load file: \'%s\'", furi_string_get_cstr(path)); | ||||||
|     bool success = flipper_format_buffered_file_open_existing(ff, string_get_cstr(path)); |     bool success = flipper_format_buffered_file_open_existing(ff, furi_string_get_cstr(path)); | ||||||
| 
 | 
 | ||||||
|     if(success) { |     if(success) { | ||||||
|         uint32_t version; |         uint32_t version; | ||||||
|         success = flipper_format_read_header(ff, buf, &version) && |         success = flipper_format_read_header(ff, buf, &version) && | ||||||
|                   !string_cmp_str(buf, "IR signals file") && (version == 1); |                   !furi_string_cmp(buf, "IR signals file") && (version == 1); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if(success) { |     if(success) { | ||||||
|         path_extract_filename(path, buf, true); |         path_extract_filename(path, buf, true); | ||||||
|         infrared_remote_clear_buttons(remote); |         infrared_remote_clear_buttons(remote); | ||||||
|         infrared_remote_set_name(remote, string_get_cstr(buf)); |         infrared_remote_set_name(remote, furi_string_get_cstr(buf)); | ||||||
|         infrared_remote_set_path(remote, string_get_cstr(path)); |         infrared_remote_set_path(remote, furi_string_get_cstr(path)); | ||||||
| 
 | 
 | ||||||
|         for(bool can_read = true; can_read;) { |         for(bool can_read = true; can_read;) { | ||||||
|             InfraredRemoteButton* button = infrared_remote_button_alloc(); |             InfraredRemoteButton* button = infrared_remote_button_alloc(); | ||||||
|             can_read = infrared_signal_read(infrared_remote_button_get_signal(button), ff, buf); |             can_read = infrared_signal_read(infrared_remote_button_get_signal(button), ff, buf); | ||||||
|             if(can_read) { |             if(can_read) { | ||||||
|                 infrared_remote_button_set_name(button, string_get_cstr(buf)); |                 infrared_remote_button_set_name(button, furi_string_get_cstr(buf)); | ||||||
|                 InfraredButtonArray_push_back(remote->buttons, button); |                 InfraredButtonArray_push_back(remote->buttons, button); | ||||||
|             } else { |             } else { | ||||||
|                 infrared_remote_button_free(button); |                 infrared_remote_button_free(button); | ||||||
| @ -172,7 +171,7 @@ bool infrared_remote_load(InfraredRemote* remote, string_t path) { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     string_clear(buf); |     furi_string_free(buf); | ||||||
|     flipper_format_free(ff); |     flipper_format_free(ff); | ||||||
|     furi_record_close(RECORD_STORAGE); |     furi_record_close(RECORD_STORAGE); | ||||||
|     return success; |     return success; | ||||||
| @ -181,7 +180,7 @@ bool infrared_remote_load(InfraredRemote* remote, string_t path) { | |||||||
| bool infrared_remote_remove(InfraredRemote* remote) { | bool infrared_remote_remove(InfraredRemote* remote) { | ||||||
|     Storage* storage = furi_record_open(RECORD_STORAGE); |     Storage* storage = furi_record_open(RECORD_STORAGE); | ||||||
| 
 | 
 | ||||||
|     FS_Error status = storage_common_remove(storage, string_get_cstr(remote->path)); |     FS_Error status = storage_common_remove(storage, furi_string_get_cstr(remote->path)); | ||||||
|     infrared_remote_reset(remote); |     infrared_remote_reset(remote); | ||||||
| 
 | 
 | ||||||
|     furi_record_close(RECORD_STORAGE); |     furi_record_close(RECORD_STORAGE); | ||||||
|  | |||||||
| @ -25,5 +25,5 @@ bool infrared_remote_rename_button(InfraredRemote* remote, const char* new_name, | |||||||
| bool infrared_remote_delete_button(InfraredRemote* remote, size_t index); | bool infrared_remote_delete_button(InfraredRemote* remote, size_t index); | ||||||
| 
 | 
 | ||||||
| bool infrared_remote_store(InfraredRemote* remote); | bool infrared_remote_store(InfraredRemote* remote); | ||||||
| bool infrared_remote_load(InfraredRemote* remote, string_t path); | bool infrared_remote_load(InfraredRemote* remote, FuriString* path); | ||||||
| bool infrared_remote_remove(InfraredRemote* remote); | bool infrared_remote_remove(InfraredRemote* remote); | ||||||
|  | |||||||
| @ -1,32 +1,31 @@ | |||||||
| #include "infrared_remote_button.h" | #include "infrared_remote_button.h" | ||||||
| 
 | 
 | ||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
| #include <m-string.h> |  | ||||||
| 
 | 
 | ||||||
| struct InfraredRemoteButton { | struct InfraredRemoteButton { | ||||||
|     string_t name; |     FuriString* name; | ||||||
|     InfraredSignal* signal; |     InfraredSignal* signal; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| InfraredRemoteButton* infrared_remote_button_alloc() { | InfraredRemoteButton* infrared_remote_button_alloc() { | ||||||
|     InfraredRemoteButton* button = malloc(sizeof(InfraredRemoteButton)); |     InfraredRemoteButton* button = malloc(sizeof(InfraredRemoteButton)); | ||||||
|     string_init(button->name); |     button->name = furi_string_alloc(); | ||||||
|     button->signal = infrared_signal_alloc(); |     button->signal = infrared_signal_alloc(); | ||||||
|     return button; |     return button; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void infrared_remote_button_free(InfraredRemoteButton* button) { | void infrared_remote_button_free(InfraredRemoteButton* button) { | ||||||
|     string_clear(button->name); |     furi_string_free(button->name); | ||||||
|     infrared_signal_free(button->signal); |     infrared_signal_free(button->signal); | ||||||
|     free(button); |     free(button); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void infrared_remote_button_set_name(InfraredRemoteButton* button, const char* name) { | void infrared_remote_button_set_name(InfraredRemoteButton* button, const char* name) { | ||||||
|     string_set_str(button->name, name); |     furi_string_set(button->name, name); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const char* infrared_remote_button_get_name(InfraredRemoteButton* button) { | const char* infrared_remote_button_get_name(InfraredRemoteButton* button) { | ||||||
|     return string_get_cstr(button->name); |     return furi_string_get_cstr(button->name); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void infrared_remote_button_set_signal(InfraredRemoteButton* button, InfraredSignal* signal) { | void infrared_remote_button_set_signal(InfraredRemoteButton* button, InfraredSignal* signal) { | ||||||
|  | |||||||
| @ -61,7 +61,7 @@ static bool infrared_signal_is_raw_valid(InfraredRawSignal* raw) { | |||||||
|     if((raw->frequency > INFRARED_MAX_FREQUENCY) || (raw->frequency < INFRARED_MIN_FREQUENCY)) { |     if((raw->frequency > INFRARED_MAX_FREQUENCY) || (raw->frequency < INFRARED_MIN_FREQUENCY)) { | ||||||
|         FURI_LOG_E( |         FURI_LOG_E( | ||||||
|             TAG, |             TAG, | ||||||
|             "Frequency is out of range (%lX - %lX): %lX", |             "Frequency is out of range (%X - %X): %lX", | ||||||
|             INFRARED_MIN_FREQUENCY, |             INFRARED_MIN_FREQUENCY, | ||||||
|             INFRARED_MAX_FREQUENCY, |             INFRARED_MAX_FREQUENCY, | ||||||
|             raw->frequency); |             raw->frequency); | ||||||
| @ -74,7 +74,7 @@ static bool infrared_signal_is_raw_valid(InfraredRawSignal* raw) { | |||||||
|     } else if((raw->timings_size <= 0) || (raw->timings_size > MAX_TIMINGS_AMOUNT)) { |     } else if((raw->timings_size <= 0) || (raw->timings_size > MAX_TIMINGS_AMOUNT)) { | ||||||
|         FURI_LOG_E( |         FURI_LOG_E( | ||||||
|             TAG, |             TAG, | ||||||
|             "Timings amount is out of range (0 - %lX): %lX", |             "Timings amount is out of range (0 - %X): %X", | ||||||
|             MAX_TIMINGS_AMOUNT, |             MAX_TIMINGS_AMOUNT, | ||||||
|             raw->timings_size); |             raw->timings_size); | ||||||
|         return false; |         return false; | ||||||
| @ -100,15 +100,15 @@ static inline bool infrared_signal_save_raw(InfraredRawSignal* raw, FlipperForma | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static inline bool infrared_signal_read_message(InfraredSignal* signal, FlipperFormat* ff) { | static inline bool infrared_signal_read_message(InfraredSignal* signal, FlipperFormat* ff) { | ||||||
|     string_t buf; |     FuriString* buf; | ||||||
|     string_init(buf); |     buf = furi_string_alloc(); | ||||||
|     bool success = false; |     bool success = false; | ||||||
| 
 | 
 | ||||||
|     do { |     do { | ||||||
|         if(!flipper_format_read_string(ff, "protocol", buf)) break; |         if(!flipper_format_read_string(ff, "protocol", buf)) break; | ||||||
| 
 | 
 | ||||||
|         InfraredMessage message; |         InfraredMessage message; | ||||||
|         message.protocol = infrared_get_protocol_by_name(string_get_cstr(buf)); |         message.protocol = infrared_get_protocol_by_name(furi_string_get_cstr(buf)); | ||||||
| 
 | 
 | ||||||
|         success = flipper_format_read_hex(ff, "address", (uint8_t*)&message.address, 4) && |         success = flipper_format_read_hex(ff, "address", (uint8_t*)&message.address, 4) && | ||||||
|                   flipper_format_read_hex(ff, "command", (uint8_t*)&message.command, 4) && |                   flipper_format_read_hex(ff, "command", (uint8_t*)&message.command, 4) && | ||||||
| @ -119,7 +119,7 @@ static inline bool infrared_signal_read_message(InfraredSignal* signal, FlipperF | |||||||
|         infrared_signal_set_message(signal, &message); |         infrared_signal_set_message(signal, &message); | ||||||
|     } while(0); |     } while(0); | ||||||
| 
 | 
 | ||||||
|     string_clear(buf); |     furi_string_free(buf); | ||||||
|     return success; |     return success; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -147,22 +147,22 @@ static inline bool infrared_signal_read_raw(InfraredSignal* signal, FlipperForma | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static bool infrared_signal_read_body(InfraredSignal* signal, FlipperFormat* ff) { | static bool infrared_signal_read_body(InfraredSignal* signal, FlipperFormat* ff) { | ||||||
|     string_t tmp; |     FuriString* tmp = furi_string_alloc(); | ||||||
|     string_init(tmp); | 
 | ||||||
|     bool success = false; |     bool success = false; | ||||||
| 
 | 
 | ||||||
|     do { |     do { | ||||||
|         if(!flipper_format_read_string(ff, "type", tmp)) break; |         if(!flipper_format_read_string(ff, "type", tmp)) break; | ||||||
|         if(string_equal_p(tmp, "raw")) { |         if(furi_string_equal(tmp, "raw")) { | ||||||
|             success = infrared_signal_read_raw(signal, ff); |             success = infrared_signal_read_raw(signal, ff); | ||||||
|         } else if(string_equal_p(tmp, "parsed")) { |         } else if(furi_string_equal(tmp, "parsed")) { | ||||||
|             success = infrared_signal_read_message(signal, ff); |             success = infrared_signal_read_message(signal, ff); | ||||||
|         } else { |         } else { | ||||||
|             FURI_LOG_E(TAG, "Unknown signal type"); |             FURI_LOG_E(TAG, "Unknown signal type"); | ||||||
|         } |         } | ||||||
|     } while(false); |     } while(false); | ||||||
| 
 | 
 | ||||||
|     string_clear(tmp); |     furi_string_free(tmp); | ||||||
|     return success; |     return success; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -246,34 +246,33 @@ bool infrared_signal_save(InfraredSignal* signal, FlipperFormat* ff, const char* | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool infrared_signal_read(InfraredSignal* signal, FlipperFormat* ff, string_t name) { | bool infrared_signal_read(InfraredSignal* signal, FlipperFormat* ff, FuriString* name) { | ||||||
|     string_t tmp; |     FuriString* tmp = furi_string_alloc(); | ||||||
|     string_init(tmp); | 
 | ||||||
|     bool success = false; |     bool success = false; | ||||||
| 
 | 
 | ||||||
|     do { |     do { | ||||||
|         if(!flipper_format_read_string(ff, "name", tmp)) break; |         if(!flipper_format_read_string(ff, "name", tmp)) break; | ||||||
|         string_set(name, tmp); |         furi_string_set(name, tmp); | ||||||
|         if(!infrared_signal_read_body(signal, ff)) break; |         if(!infrared_signal_read_body(signal, ff)) break; | ||||||
|         success = true; |         success = true; | ||||||
|     } while(0); |     } while(0); | ||||||
| 
 | 
 | ||||||
|     string_clear(tmp); |     furi_string_free(tmp); | ||||||
|     return success; |     return success; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool infrared_signal_search_and_read( | bool infrared_signal_search_and_read( | ||||||
|     InfraredSignal* signal, |     InfraredSignal* signal, | ||||||
|     FlipperFormat* ff, |     FlipperFormat* ff, | ||||||
|     const string_t name) { |     const FuriString* name) { | ||||||
|     bool success = false; |     bool success = false; | ||||||
|     string_t tmp; |     FuriString* tmp = furi_string_alloc(); | ||||||
|     string_init(tmp); |  | ||||||
| 
 | 
 | ||||||
|     do { |     do { | ||||||
|         bool is_name_found = false; |         bool is_name_found = false; | ||||||
|         while(flipper_format_read_string(ff, "name", tmp)) { |         while(flipper_format_read_string(ff, "name", tmp)) { | ||||||
|             is_name_found = string_equal_p(name, tmp); |             is_name_found = furi_string_equal(name, tmp); | ||||||
|             if(is_name_found) break; |             if(is_name_found) break; | ||||||
|         } |         } | ||||||
|         if(!is_name_found) break; |         if(!is_name_found) break; | ||||||
| @ -281,7 +280,7 @@ bool infrared_signal_search_and_read( | |||||||
|         success = true; |         success = true; | ||||||
|     } while(false); |     } while(false); | ||||||
| 
 | 
 | ||||||
|     string_clear(tmp); |     furi_string_free(tmp); | ||||||
|     return success; |     return success; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -36,10 +36,10 @@ void infrared_signal_set_message(InfraredSignal* signal, const InfraredMessage* | |||||||
| InfraredMessage* infrared_signal_get_message(InfraredSignal* signal); | InfraredMessage* infrared_signal_get_message(InfraredSignal* signal); | ||||||
| 
 | 
 | ||||||
| bool infrared_signal_save(InfraredSignal* signal, FlipperFormat* ff, const char* name); | bool infrared_signal_save(InfraredSignal* signal, FlipperFormat* ff, const char* name); | ||||||
| bool infrared_signal_read(InfraredSignal* signal, FlipperFormat* ff, string_t name); | bool infrared_signal_read(InfraredSignal* signal, FlipperFormat* ff, FuriString* name); | ||||||
| bool infrared_signal_search_and_read( | bool infrared_signal_search_and_read( | ||||||
|     InfraredSignal* signal, |     InfraredSignal* signal, | ||||||
|     FlipperFormat* ff, |     FlipperFormat* ff, | ||||||
|     const string_t name); |     const FuriString* name); | ||||||
| 
 | 
 | ||||||
| void infrared_signal_transmit(InfraredSignal* signal); | void infrared_signal_transmit(InfraredSignal* signal); | ||||||
|  | |||||||
| @ -70,7 +70,7 @@ bool infrared_scene_universal_common_on_event(void* context, SceneManagerEvent e | |||||||
|                 uint32_t record_count; |                 uint32_t record_count; | ||||||
|                 if(infrared_brute_force_start( |                 if(infrared_brute_force_start( | ||||||
|                        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(DolphinDeedIrSend); | ||||||
|                     infrared_scene_universal_common_show_popup(infrared, record_count); |                     infrared_scene_universal_common_show_popup(infrared, record_count); | ||||||
|                 } else { |                 } else { | ||||||
|                     scene_manager_next_scene(scene_manager, InfraredSceneErrorDatabases); |                     scene_manager_next_scene(scene_manager, InfraredSceneErrorDatabases); | ||||||
|  | |||||||
| @ -29,20 +29,20 @@ void infrared_scene_edit_rename_on_enter(void* context) { | |||||||
|         enter_name_length = INFRARED_MAX_REMOTE_NAME_LENGTH; |         enter_name_length = INFRARED_MAX_REMOTE_NAME_LENGTH; | ||||||
|         strncpy(infrared->text_store[0], infrared_remote_get_name(remote), enter_name_length); |         strncpy(infrared->text_store[0], infrared_remote_get_name(remote), enter_name_length); | ||||||
| 
 | 
 | ||||||
|         string_t folder_path; |         FuriString* folder_path; | ||||||
|         string_init(folder_path); |         folder_path = furi_string_alloc(); | ||||||
| 
 | 
 | ||||||
|         if(string_end_with_str_p(infrared->file_path, INFRARED_APP_EXTENSION)) { |         if(furi_string_end_with(infrared->file_path, INFRARED_APP_EXTENSION)) { | ||||||
|             path_extract_dirname(string_get_cstr(infrared->file_path), folder_path); |             path_extract_dirname(furi_string_get_cstr(infrared->file_path), folder_path); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         ValidatorIsFile* validator_is_file = validator_is_file_alloc_init( |         ValidatorIsFile* validator_is_file = validator_is_file_alloc_init( | ||||||
|             string_get_cstr(folder_path), |             furi_string_get_cstr(folder_path), | ||||||
|             INFRARED_APP_EXTENSION, |             INFRARED_APP_EXTENSION, | ||||||
|             infrared_remote_get_name(remote)); |             infrared_remote_get_name(remote)); | ||||||
|         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(folder_path); |         furi_string_free(folder_path); | ||||||
|     } else { |     } else { | ||||||
|         furi_assert(0); |         furi_assert(0); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -50,8 +50,10 @@ bool infrared_scene_learn_enter_name_on_event(void* context, SceneManagerEvent e | |||||||
|             if(success) { |             if(success) { | ||||||
|                 scene_manager_next_scene(scene_manager, InfraredSceneLearnDone); |                 scene_manager_next_scene(scene_manager, InfraredSceneLearnDone); | ||||||
|             } else { |             } else { | ||||||
|                 scene_manager_search_and_switch_to_previous_scene( |                 dialog_message_show_storage_error(infrared->dialogs, "Failed to save file"); | ||||||
|                     scene_manager, InfraredSceneRemoteList); |                 const uint32_t possible_scenes[] = {InfraredSceneRemoteList, InfraredSceneStart}; | ||||||
|  |                 scene_manager_search_and_switch_to_previous_scene_one_of( | ||||||
|  |                     scene_manager, possible_scenes, COUNT_OF(possible_scenes)); | ||||||
|             } |             } | ||||||
|             consumed = true; |             consumed = true; | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -42,7 +42,7 @@ bool infrared_scene_rpc_on_event(void* context, SceneManagerEvent event) { | |||||||
|             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 && (state == InfraredRpcStateIdle)) { |             if(arg && (state == InfraredRpcStateIdle)) { | ||||||
|                 string_set_str(infrared->file_path, arg); |                 furi_string_set(infrared->file_path, arg); | ||||||
|                 result = infrared_remote_load(infrared->remote, infrared->file_path); |                 result = infrared_remote_load(infrared->remote, infrared->file_path); | ||||||
|                 if(result) { |                 if(result) { | ||||||
|                     scene_manager_set_scene_state( |                     scene_manager_set_scene_state( | ||||||
|  | |||||||
| @ -66,7 +66,7 @@ bool infrared_scene_start_on_event(void* context, SceneManagerEvent event) { | |||||||
|             scene_manager_next_scene(scene_manager, InfraredSceneLearn); |             scene_manager_next_scene(scene_manager, InfraredSceneLearn); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|         } else if(submenu_index == SubmenuIndexSavedRemotes) { |         } else if(submenu_index == SubmenuIndexSavedRemotes) { | ||||||
|             string_set_str(infrared->file_path, INFRARED_APP_FOLDER); |             furi_string_set(infrared->file_path, INFRARED_APP_FOLDER); | ||||||
|             scene_manager_next_scene(scene_manager, InfraredSceneRemoteList); |             scene_manager_next_scene(scene_manager, InfraredSceneRemoteList); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|         } else if(submenu_index == SubmenuIndexDebug) { |         } else if(submenu_index == SubmenuIndexDebug) { | ||||||
|  | |||||||
| @ -4,7 +4,6 @@ | |||||||
| #include "gui/canvas.h" | #include "gui/canvas.h" | ||||||
| #include "gui/view.h" | #include "gui/view.h" | ||||||
| #include "input/input.h" | #include "input/input.h" | ||||||
| #include "m-string.h" |  | ||||||
| #include <gui/elements.h> | #include <gui/elements.h> | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| #include "infrared_progress_view.h" | #include "infrared_progress_view.h" | ||||||
|  | |||||||
| @ -36,9 +36,9 @@ static LfRfid* lfrfid_alloc() { | |||||||
|     lfrfid->storage = furi_record_open(RECORD_STORAGE); |     lfrfid->storage = furi_record_open(RECORD_STORAGE); | ||||||
|     lfrfid->dialogs = furi_record_open(RECORD_DIALOGS); |     lfrfid->dialogs = furi_record_open(RECORD_DIALOGS); | ||||||
| 
 | 
 | ||||||
|     string_init(lfrfid->file_name); |     lfrfid->file_name = furi_string_alloc(); | ||||||
|     string_init(lfrfid->raw_file_name); |     lfrfid->raw_file_name = furi_string_alloc(); | ||||||
|     string_init_set_str(lfrfid->file_path, LFRFID_APP_FOLDER); |     lfrfid->file_path = furi_string_alloc_set(LFRFID_APP_FOLDER); | ||||||
| 
 | 
 | ||||||
|     lfrfid->dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax); |     lfrfid->dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax); | ||||||
| 
 | 
 | ||||||
| @ -104,9 +104,9 @@ static LfRfid* lfrfid_alloc() { | |||||||
| static void lfrfid_free(LfRfid* lfrfid) { | static void lfrfid_free(LfRfid* lfrfid) { | ||||||
|     furi_assert(lfrfid); |     furi_assert(lfrfid); | ||||||
| 
 | 
 | ||||||
|     string_clear(lfrfid->raw_file_name); |     furi_string_free(lfrfid->raw_file_name); | ||||||
|     string_clear(lfrfid->file_name); |     furi_string_free(lfrfid->file_name); | ||||||
|     string_clear(lfrfid->file_path); |     furi_string_free(lfrfid->file_path); | ||||||
|     protocol_dict_free(lfrfid->dict); |     protocol_dict_free(lfrfid->dict); | ||||||
| 
 | 
 | ||||||
|     lfrfid_worker_free(lfrfid->lfworker); |     lfrfid_worker_free(lfrfid->lfworker); | ||||||
| @ -183,7 +183,7 @@ int32_t lfrfid_app(void* p) { | |||||||
|                 app->view_dispatcher, app->gui, ViewDispatcherTypeDesktop); |                 app->view_dispatcher, app->gui, ViewDispatcherTypeDesktop); | ||||||
|             scene_manager_next_scene(app->scene_manager, LfRfidSceneRpc); |             scene_manager_next_scene(app->scene_manager, LfRfidSceneRpc); | ||||||
|         } else { |         } else { | ||||||
|             string_set_str(app->file_path, args); |             furi_string_set(app->file_path, args); | ||||||
|             lfrfid_load_key_data(app, app->file_path, true); |             lfrfid_load_key_data(app, app->file_path, true); | ||||||
|             view_dispatcher_attach_to_gui( |             view_dispatcher_attach_to_gui( | ||||||
|                 app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); |                 app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); | ||||||
| @ -210,13 +210,13 @@ bool lfrfid_save_key(LfRfid* app) { | |||||||
| 
 | 
 | ||||||
|     lfrfid_make_app_folder(app); |     lfrfid_make_app_folder(app); | ||||||
| 
 | 
 | ||||||
|     if(string_end_with_str_p(app->file_path, LFRFID_APP_EXTENSION)) { |     if(furi_string_end_with(app->file_path, LFRFID_APP_EXTENSION)) { | ||||||
|         size_t filename_start = string_search_rchar(app->file_path, '/'); |         size_t filename_start = furi_string_search_rchar(app->file_path, '/'); | ||||||
|         string_left(app->file_path, filename_start); |         furi_string_left(app->file_path, filename_start); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     string_cat_printf( |     furi_string_cat_printf( | ||||||
|         app->file_path, "/%s%s", string_get_cstr(app->file_name), LFRFID_APP_EXTENSION); |         app->file_path, "/%s%s", furi_string_get_cstr(app->file_name), LFRFID_APP_EXTENSION); | ||||||
| 
 | 
 | ||||||
|     result = lfrfid_save_key_data(app, app->file_path); |     result = lfrfid_save_key_data(app, app->file_path); | ||||||
|     return result; |     return result; | ||||||
| @ -242,14 +242,14 @@ bool lfrfid_load_key_from_file_select(LfRfid* app) { | |||||||
| bool lfrfid_delete_key(LfRfid* app) { | bool lfrfid_delete_key(LfRfid* app) { | ||||||
|     furi_assert(app); |     furi_assert(app); | ||||||
| 
 | 
 | ||||||
|     return storage_simply_remove(app->storage, string_get_cstr(app->file_path)); |     return storage_simply_remove(app->storage, furi_string_get_cstr(app->file_path)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool lfrfid_load_key_data(LfRfid* app, string_t path, bool show_dialog) { | bool lfrfid_load_key_data(LfRfid* app, FuriString* path, bool show_dialog) { | ||||||
|     bool result = false; |     bool result = false; | ||||||
| 
 | 
 | ||||||
|     do { |     do { | ||||||
|         app->protocol_id = lfrfid_dict_file_load(app->dict, string_get_cstr(path)); |         app->protocol_id = lfrfid_dict_file_load(app->dict, furi_string_get_cstr(path)); | ||||||
|         if(app->protocol_id == PROTOCOL_NO) break; |         if(app->protocol_id == PROTOCOL_NO) break; | ||||||
| 
 | 
 | ||||||
|         path_extract_filename(path, app->file_name, true); |         path_extract_filename(path, app->file_name, true); | ||||||
| @ -263,8 +263,8 @@ bool lfrfid_load_key_data(LfRfid* app, string_t path, bool show_dialog) { | |||||||
|     return result; |     return result; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool lfrfid_save_key_data(LfRfid* app, string_t path) { | bool lfrfid_save_key_data(LfRfid* app, FuriString* path) { | ||||||
|     bool result = lfrfid_dict_file_save(app->dict, app->protocol_id, string_get_cstr(path)); |     bool result = lfrfid_dict_file_save(app->dict, app->protocol_id, furi_string_get_cstr(path)); | ||||||
| 
 | 
 | ||||||
|     if(!result) { |     if(!result) { | ||||||
|         dialog_message_show_storage_error(app->dialogs, "Cannot save\nkey file"); |         dialog_message_show_storage_error(app->dialogs, "Cannot save\nkey file"); | ||||||
|  | |||||||
| @ -14,7 +14,7 @@ | |||||||
| #include <lfrfid/lfrfid_raw_file.h> | #include <lfrfid/lfrfid_raw_file.h> | ||||||
| #include <toolbox/pulse_protocols/pulse_glue.h> | #include <toolbox/pulse_protocols/pulse_glue.h> | ||||||
| 
 | 
 | ||||||
| static void lfrfid_cli(Cli* cli, string_t args, void* context); | static void lfrfid_cli(Cli* cli, FuriString* args, void* context); | ||||||
| 
 | 
 | ||||||
| // app cli function
 | // app cli function
 | ||||||
| void lfrfid_on_system_start() { | void lfrfid_on_system_start() { | ||||||
| @ -46,27 +46,28 @@ static void lfrfid_cli_read_callback(LFRFIDWorkerReadResult result, ProtocolId p | |||||||
|     furi_event_flag_set(context->event, 1 << result); |     furi_event_flag_set(context->event, 1 << result); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void lfrfid_cli_read(Cli* cli, string_t args) { | static void lfrfid_cli_read(Cli* cli, FuriString* args) { | ||||||
|     string_t type_string; |     FuriString* type_string; | ||||||
|     string_init(type_string); |     type_string = furi_string_alloc(); | ||||||
|     LFRFIDWorkerReadType type = LFRFIDWorkerReadTypeAuto; |     LFRFIDWorkerReadType type = LFRFIDWorkerReadTypeAuto; | ||||||
| 
 | 
 | ||||||
|     if(args_read_string_and_trim(args, type_string)) { |     if(args_read_string_and_trim(args, type_string)) { | ||||||
|         if(string_cmp_str(type_string, "normal") == 0 || string_cmp_str(type_string, "ask") == 0) { |         if(furi_string_cmp_str(type_string, "normal") == 0 || | ||||||
|  |            furi_string_cmp_str(type_string, "ask") == 0) { | ||||||
|             // ask
 |             // ask
 | ||||||
|             type = LFRFIDWorkerReadTypeASKOnly; |             type = LFRFIDWorkerReadTypeASKOnly; | ||||||
|         } else if( |         } else if( | ||||||
|             string_cmp_str(type_string, "indala") == 0 || |             furi_string_cmp_str(type_string, "indala") == 0 || | ||||||
|             string_cmp_str(type_string, "psk") == 0) { |             furi_string_cmp_str(type_string, "psk") == 0) { | ||||||
|             // psk
 |             // psk
 | ||||||
|             type = LFRFIDWorkerReadTypePSKOnly; |             type = LFRFIDWorkerReadTypePSKOnly; | ||||||
|         } else { |         } else { | ||||||
|             lfrfid_cli_print_usage(); |             lfrfid_cli_print_usage(); | ||||||
|             string_clear(type_string); |             furi_string_free(type_string); | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     string_clear(type_string); |     furi_string_free(type_string); | ||||||
| 
 | 
 | ||||||
|     ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax); |     ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax); | ||||||
|     LFRFIDWorker* worker = lfrfid_worker_alloc(dict); |     LFRFIDWorker* worker = lfrfid_worker_alloc(dict); | ||||||
| @ -111,13 +112,13 @@ static void lfrfid_cli_read(Cli* cli, string_t args) { | |||||||
|         printf("\r\n"); |         printf("\r\n"); | ||||||
|         free(data); |         free(data); | ||||||
| 
 | 
 | ||||||
|         string_t info; |         FuriString* info; | ||||||
|         string_init(info); |         info = furi_string_alloc(); | ||||||
|         protocol_dict_render_data(dict, info, context.protocol); |         protocol_dict_render_data(dict, info, context.protocol); | ||||||
|         if(!string_empty_p(info)) { |         if(!furi_string_empty(info)) { | ||||||
|             printf("%s\r\n", string_get_cstr(info)); |             printf("%s\r\n", furi_string_get_cstr(info)); | ||||||
|         } |         } | ||||||
|         string_clear(info); |         furi_string_free(info); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     printf("Reading stopped\r\n"); |     printf("Reading stopped\r\n"); | ||||||
| @ -126,11 +127,11 @@ static void lfrfid_cli_read(Cli* cli, string_t args) { | |||||||
|     furi_event_flag_free(context.event); |     furi_event_flag_free(context.event); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static bool lfrfid_cli_parse_args(string_t args, ProtocolDict* dict, ProtocolId* protocol) { | static bool lfrfid_cli_parse_args(FuriString* args, ProtocolDict* dict, ProtocolId* protocol) { | ||||||
|     bool result = false; |     bool result = false; | ||||||
|     string_t protocol_name, data_text; |     FuriString *protocol_name, *data_text; | ||||||
|     string_init(protocol_name); |     protocol_name = furi_string_alloc(); | ||||||
|     string_init(data_text); |     data_text = furi_string_alloc(); | ||||||
|     size_t data_size = protocol_dict_get_max_data_size(dict); |     size_t data_size = protocol_dict_get_max_data_size(dict); | ||||||
|     uint8_t* data = malloc(data_size); |     uint8_t* data = malloc(data_size); | ||||||
| 
 | 
 | ||||||
| @ -143,12 +144,12 @@ static bool lfrfid_cli_parse_args(string_t args, ProtocolDict* dict, ProtocolId* | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         // check protocol arg
 |         // check protocol arg
 | ||||||
|         *protocol = protocol_dict_get_protocol_by_name(dict, string_get_cstr(protocol_name)); |         *protocol = protocol_dict_get_protocol_by_name(dict, furi_string_get_cstr(protocol_name)); | ||||||
|         if(*protocol == PROTOCOL_NO) { |         if(*protocol == PROTOCOL_NO) { | ||||||
|             printf( |             printf( | ||||||
|                 "Unknown protocol: %s\r\n" |                 "Unknown protocol: %s\r\n" | ||||||
|                 "Available protocols:\r\n", |                 "Available protocols:\r\n", | ||||||
|                 string_get_cstr(protocol_name)); |                 furi_string_get_cstr(protocol_name)); | ||||||
| 
 | 
 | ||||||
|             for(ProtocolId i = 0; i < LFRFIDProtocolMax; i++) { |             for(ProtocolId i = 0; i < LFRFIDProtocolMax; i++) { | ||||||
|                 printf( |                 printf( | ||||||
| @ -177,8 +178,8 @@ static bool lfrfid_cli_parse_args(string_t args, ProtocolDict* dict, ProtocolId* | |||||||
|     } while(false); |     } while(false); | ||||||
| 
 | 
 | ||||||
|     free(data); |     free(data); | ||||||
|     string_clear(protocol_name); |     furi_string_free(protocol_name); | ||||||
|     string_clear(data_text); |     furi_string_free(data_text); | ||||||
|     return result; |     return result; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -188,7 +189,7 @@ static void lfrfid_cli_write_callback(LFRFIDWorkerWriteResult result, void* ctx) | |||||||
|     furi_event_flag_set(events, 1 << result); |     furi_event_flag_set(events, 1 << result); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void lfrfid_cli_write(Cli* cli, string_t args) { | static void lfrfid_cli_write(Cli* cli, FuriString* args) { | ||||||
|     ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax); |     ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax); | ||||||
|     ProtocolId protocol; |     ProtocolId protocol; | ||||||
| 
 | 
 | ||||||
| @ -235,7 +236,7 @@ static void lfrfid_cli_write(Cli* cli, string_t args) { | |||||||
|     furi_event_flag_free(event); |     furi_event_flag_free(event); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void lfrfid_cli_emulate(Cli* cli, string_t args) { | static void lfrfid_cli_emulate(Cli* cli, FuriString* args) { | ||||||
|     ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax); |     ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax); | ||||||
|     ProtocolId protocol; |     ProtocolId protocol; | ||||||
| 
 | 
 | ||||||
| @ -261,11 +262,11 @@ static void lfrfid_cli_emulate(Cli* cli, string_t args) { | |||||||
|     protocol_dict_free(dict); |     protocol_dict_free(dict); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void lfrfid_cli_raw_analyze(Cli* cli, string_t args) { | static void lfrfid_cli_raw_analyze(Cli* cli, FuriString* args) { | ||||||
|     UNUSED(cli); |     UNUSED(cli); | ||||||
|     string_t filepath, info_string; |     FuriString *filepath, *info_string; | ||||||
|     string_init(filepath); |     filepath = furi_string_alloc(); | ||||||
|     string_init(info_string); |     info_string = furi_string_alloc(); | ||||||
|     Storage* storage = furi_record_open(RECORD_STORAGE); |     Storage* storage = furi_record_open(RECORD_STORAGE); | ||||||
|     LFRFIDRawFile* file = lfrfid_raw_file_alloc(storage); |     LFRFIDRawFile* file = lfrfid_raw_file_alloc(storage); | ||||||
| 
 | 
 | ||||||
| @ -278,7 +279,7 @@ static void lfrfid_cli_raw_analyze(Cli* cli, string_t args) { | |||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if(!lfrfid_raw_file_open_read(file, string_get_cstr(filepath))) { |         if(!lfrfid_raw_file_open_read(file, furi_string_get_cstr(filepath))) { | ||||||
|             printf("Failed to open file\r\n"); |             printf("Failed to open file\r\n"); | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
| @ -308,10 +309,10 @@ static void lfrfid_cli_raw_analyze(Cli* cli, string_t args) { | |||||||
|                     warn = true; |                     warn = true; | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 string_printf(info_string, "[%ld %ld]", pulse, duration); |                 furi_string_printf(info_string, "[%ld %ld]", pulse, duration); | ||||||
|                 printf("%-16s", string_get_cstr(info_string)); |                 printf("%-16s", furi_string_get_cstr(info_string)); | ||||||
|                 string_printf(info_string, "[%ld %ld]", pulse, duration - pulse); |                 furi_string_printf(info_string, "[%ld %ld]", pulse, duration - pulse); | ||||||
|                 printf("%-16s", string_get_cstr(info_string)); |                 printf("%-16s", furi_string_get_cstr(info_string)); | ||||||
| 
 | 
 | ||||||
|                 if(warn) { |                 if(warn) { | ||||||
|                     printf(" <<----"); |                     printf(" <<----"); | ||||||
| @ -366,7 +367,7 @@ static void lfrfid_cli_raw_analyze(Cli* cli, string_t args) { | |||||||
|             printf("]\r\n"); |             printf("]\r\n"); | ||||||
| 
 | 
 | ||||||
|             protocol_dict_render_data(dict, info_string, total_protocol); |             protocol_dict_render_data(dict, info_string, total_protocol); | ||||||
|             printf("%s\r\n", string_get_cstr(info_string)); |             printf("%s\r\n", furi_string_get_cstr(info_string)); | ||||||
| 
 | 
 | ||||||
|             free(data); |             free(data); | ||||||
|         } else { |         } else { | ||||||
| @ -376,8 +377,8 @@ static void lfrfid_cli_raw_analyze(Cli* cli, string_t args) { | |||||||
|         protocol_dict_free(dict); |         protocol_dict_free(dict); | ||||||
|     } while(false); |     } while(false); | ||||||
| 
 | 
 | ||||||
|     string_clear(filepath); |     furi_string_free(filepath); | ||||||
|     string_clear(info_string); |     furi_string_free(info_string); | ||||||
|     lfrfid_raw_file_free(file); |     lfrfid_raw_file_free(file); | ||||||
|     furi_record_close(RECORD_STORAGE); |     furi_record_close(RECORD_STORAGE); | ||||||
| } | } | ||||||
| @ -388,23 +389,23 @@ static void lfrfid_cli_raw_read_callback(LFRFIDWorkerReadRawResult result, void* | |||||||
|     furi_event_flag_set(event, 1 << result); |     furi_event_flag_set(event, 1 << result); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void lfrfid_cli_raw_read(Cli* cli, string_t args) { | static void lfrfid_cli_raw_read(Cli* cli, FuriString* args) { | ||||||
|     UNUSED(cli); |     UNUSED(cli); | ||||||
| 
 | 
 | ||||||
|     string_t filepath, type_string; |     FuriString *filepath, *type_string; | ||||||
|     string_init(filepath); |     filepath = furi_string_alloc(); | ||||||
|     string_init(type_string); |     type_string = furi_string_alloc(); | ||||||
|     LFRFIDWorkerReadType type = LFRFIDWorkerReadTypeAuto; |     LFRFIDWorkerReadType type = LFRFIDWorkerReadTypeAuto; | ||||||
| 
 | 
 | ||||||
|     do { |     do { | ||||||
|         if(args_read_string_and_trim(args, type_string)) { |         if(args_read_string_and_trim(args, type_string)) { | ||||||
|             if(string_cmp_str(type_string, "normal") == 0 || |             if(furi_string_cmp_str(type_string, "normal") == 0 || | ||||||
|                string_cmp_str(type_string, "ask") == 0) { |                furi_string_cmp_str(type_string, "ask") == 0) { | ||||||
|                 // ask
 |                 // ask
 | ||||||
|                 type = LFRFIDWorkerReadTypeASKOnly; |                 type = LFRFIDWorkerReadTypeASKOnly; | ||||||
|             } else if( |             } else if( | ||||||
|                 string_cmp_str(type_string, "indala") == 0 || |                 furi_string_cmp_str(type_string, "indala") == 0 || | ||||||
|                 string_cmp_str(type_string, "psk") == 0) { |                 furi_string_cmp_str(type_string, "psk") == 0) { | ||||||
|                 // psk
 |                 // psk
 | ||||||
|                 type = LFRFIDWorkerReadTypePSKOnly; |                 type = LFRFIDWorkerReadTypePSKOnly; | ||||||
|             } else { |             } else { | ||||||
| @ -430,7 +431,7 @@ static void lfrfid_cli_raw_read(Cli* cli, string_t args) { | |||||||
|                                          (1 << LFRFIDWorkerReadRawOverrun); |                                          (1 << LFRFIDWorkerReadRawOverrun); | ||||||
| 
 | 
 | ||||||
|         lfrfid_worker_read_raw_start( |         lfrfid_worker_read_raw_start( | ||||||
|             worker, string_get_cstr(filepath), type, lfrfid_cli_raw_read_callback, event); |             worker, furi_string_get_cstr(filepath), type, lfrfid_cli_raw_read_callback, event); | ||||||
|         while(true) { |         while(true) { | ||||||
|             uint32_t flags = furi_event_flag_wait(event, available_flags, FuriFlagWaitAny, 100); |             uint32_t flags = furi_event_flag_wait(event, available_flags, FuriFlagWaitAny, 100); | ||||||
| 
 | 
 | ||||||
| @ -465,8 +466,8 @@ static void lfrfid_cli_raw_read(Cli* cli, string_t args) { | |||||||
| 
 | 
 | ||||||
|     } while(false); |     } while(false); | ||||||
| 
 | 
 | ||||||
|     string_clear(filepath); |     furi_string_free(filepath); | ||||||
|     string_clear(type_string); |     furi_string_free(type_string); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void lfrfid_cli_raw_emulate_callback(LFRFIDWorkerEmulateRawResult result, void* context) { | static void lfrfid_cli_raw_emulate_callback(LFRFIDWorkerEmulateRawResult result, void* context) { | ||||||
| @ -475,11 +476,11 @@ static void lfrfid_cli_raw_emulate_callback(LFRFIDWorkerEmulateRawResult result, | |||||||
|     furi_event_flag_set(event, 1 << result); |     furi_event_flag_set(event, 1 << result); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void lfrfid_cli_raw_emulate(Cli* cli, string_t args) { | static void lfrfid_cli_raw_emulate(Cli* cli, FuriString* args) { | ||||||
|     UNUSED(cli); |     UNUSED(cli); | ||||||
| 
 | 
 | ||||||
|     string_t filepath; |     FuriString* filepath; | ||||||
|     string_init(filepath); |     filepath = furi_string_alloc(); | ||||||
|     Storage* storage = furi_record_open(RECORD_STORAGE); |     Storage* storage = furi_record_open(RECORD_STORAGE); | ||||||
| 
 | 
 | ||||||
|     do { |     do { | ||||||
| @ -488,8 +489,8 @@ static void lfrfid_cli_raw_emulate(Cli* cli, string_t args) { | |||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if(!storage_file_exists(storage, string_get_cstr(filepath))) { |         if(!storage_file_exists(storage, furi_string_get_cstr(filepath))) { | ||||||
|             printf("File not found: \"%s\"\r\n", string_get_cstr(filepath)); |             printf("File not found: \"%s\"\r\n", furi_string_get_cstr(filepath)); | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| @ -505,7 +506,7 @@ static void lfrfid_cli_raw_emulate(Cli* cli, string_t args) { | |||||||
|                                          (1 << LFRFIDWorkerEmulateRawOverrun); |                                          (1 << LFRFIDWorkerEmulateRawOverrun); | ||||||
| 
 | 
 | ||||||
|         lfrfid_worker_emulate_raw_start( |         lfrfid_worker_emulate_raw_start( | ||||||
|             worker, string_get_cstr(filepath), lfrfid_cli_raw_emulate_callback, event); |             worker, furi_string_get_cstr(filepath), lfrfid_cli_raw_emulate_callback, event); | ||||||
|         while(true) { |         while(true) { | ||||||
|             uint32_t flags = furi_event_flag_wait(event, available_flags, FuriFlagWaitAny, 100); |             uint32_t flags = furi_event_flag_wait(event, available_flags, FuriFlagWaitAny, 100); | ||||||
| 
 | 
 | ||||||
| @ -541,35 +542,35 @@ static void lfrfid_cli_raw_emulate(Cli* cli, string_t args) { | |||||||
|     } while(false); |     } while(false); | ||||||
| 
 | 
 | ||||||
|     furi_record_close(RECORD_STORAGE); |     furi_record_close(RECORD_STORAGE); | ||||||
|     string_clear(filepath); |     furi_string_free(filepath); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void lfrfid_cli(Cli* cli, string_t args, void* context) { | static void lfrfid_cli(Cli* cli, FuriString* args, void* context) { | ||||||
|     UNUSED(context); |     UNUSED(context); | ||||||
|     string_t cmd; |     FuriString* cmd; | ||||||
|     string_init(cmd); |     cmd = furi_string_alloc(); | ||||||
| 
 | 
 | ||||||
|     if(!args_read_string_and_trim(args, cmd)) { |     if(!args_read_string_and_trim(args, cmd)) { | ||||||
|         string_clear(cmd); |         furi_string_free(cmd); | ||||||
|         lfrfid_cli_print_usage(); |         lfrfid_cli_print_usage(); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if(string_cmp_str(cmd, "read") == 0) { |     if(furi_string_cmp_str(cmd, "read") == 0) { | ||||||
|         lfrfid_cli_read(cli, args); |         lfrfid_cli_read(cli, args); | ||||||
|     } else if(string_cmp_str(cmd, "write") == 0) { |     } else if(furi_string_cmp_str(cmd, "write") == 0) { | ||||||
|         lfrfid_cli_write(cli, args); |         lfrfid_cli_write(cli, args); | ||||||
|     } else if(string_cmp_str(cmd, "emulate") == 0) { |     } else if(furi_string_cmp_str(cmd, "emulate") == 0) { | ||||||
|         lfrfid_cli_emulate(cli, args); |         lfrfid_cli_emulate(cli, args); | ||||||
|     } else if(string_cmp_str(cmd, "raw_read") == 0) { |     } else if(furi_string_cmp_str(cmd, "raw_read") == 0) { | ||||||
|         lfrfid_cli_raw_read(cli, args); |         lfrfid_cli_raw_read(cli, args); | ||||||
|     } else if(string_cmp_str(cmd, "raw_emulate") == 0) { |     } else if(furi_string_cmp_str(cmd, "raw_emulate") == 0) { | ||||||
|         lfrfid_cli_raw_emulate(cli, args); |         lfrfid_cli_raw_emulate(cli, args); | ||||||
|     } else if(string_cmp_str(cmd, "raw_analyze") == 0) { |     } else if(furi_string_cmp_str(cmd, "raw_analyze") == 0) { | ||||||
|         lfrfid_cli_raw_analyze(cli, args); |         lfrfid_cli_raw_analyze(cli, args); | ||||||
|     } else { |     } else { | ||||||
|         lfrfid_cli_print_usage(); |         lfrfid_cli_print_usage(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     string_clear(cmd); |     furi_string_free(cmd); | ||||||
| } | } | ||||||
| @ -1,7 +1,5 @@ | |||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #include "m-string.h" |  | ||||||
| 
 |  | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| #include <furi_hal.h> | #include <furi_hal.h> | ||||||
| 
 | 
 | ||||||
| @ -86,9 +84,9 @@ struct LfRfid { | |||||||
|     Widget* widget; |     Widget* widget; | ||||||
| 
 | 
 | ||||||
|     char text_store[LFRFID_TEXT_STORE_SIZE + 1]; |     char text_store[LFRFID_TEXT_STORE_SIZE + 1]; | ||||||
|     string_t file_path; |     FuriString* file_path; | ||||||
|     string_t file_name; |     FuriString* file_name; | ||||||
|     string_t raw_file_name; |     FuriString* raw_file_name; | ||||||
| 
 | 
 | ||||||
|     ProtocolDict* dict; |     ProtocolDict* dict; | ||||||
|     ProtocolId protocol_id; |     ProtocolId protocol_id; | ||||||
| @ -128,9 +126,9 @@ bool lfrfid_load_key_from_file_select(LfRfid* app); | |||||||
| 
 | 
 | ||||||
| bool lfrfid_delete_key(LfRfid* app); | bool lfrfid_delete_key(LfRfid* app); | ||||||
| 
 | 
 | ||||||
| bool lfrfid_load_key_data(LfRfid* app, string_t path, bool show_dialog); | bool lfrfid_load_key_data(LfRfid* app, FuriString* path, bool show_dialog); | ||||||
| 
 | 
 | ||||||
| bool lfrfid_save_key_data(LfRfid* app, string_t path); | bool lfrfid_save_key_data(LfRfid* app, FuriString* path); | ||||||
| 
 | 
 | ||||||
| void lfrfid_make_app_folder(LfRfid* app); | void lfrfid_make_app_folder(LfRfid* app); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -4,31 +4,31 @@ void lfrfid_scene_delete_confirm_on_enter(void* context) { | |||||||
|     LfRfid* app = context; |     LfRfid* app = context; | ||||||
|     Widget* widget = app->widget; |     Widget* widget = app->widget; | ||||||
| 
 | 
 | ||||||
|     string_t tmp_string; |     FuriString* tmp_string; | ||||||
|     string_init(tmp_string); |     tmp_string = furi_string_alloc(); | ||||||
| 
 | 
 | ||||||
|     widget_add_button_element(widget, GuiButtonTypeLeft, "Back", lfrfid_widget_callback, app); |     widget_add_button_element(widget, GuiButtonTypeLeft, "Back", lfrfid_widget_callback, app); | ||||||
|     widget_add_button_element(widget, GuiButtonTypeRight, "Delete", lfrfid_widget_callback, app); |     widget_add_button_element(widget, GuiButtonTypeRight, "Delete", lfrfid_widget_callback, app); | ||||||
| 
 | 
 | ||||||
|     string_printf(tmp_string, "Delete %s?", string_get_cstr(app->file_name)); |     furi_string_printf(tmp_string, "Delete %s?", furi_string_get_cstr(app->file_name)); | ||||||
|     widget_add_string_element( |     widget_add_string_element( | ||||||
|         widget, 64, 0, AlignCenter, AlignTop, FontPrimary, string_get_cstr(tmp_string)); |         widget, 64, 0, AlignCenter, AlignTop, FontPrimary, furi_string_get_cstr(tmp_string)); | ||||||
| 
 | 
 | ||||||
|     string_reset(tmp_string); |     furi_string_reset(tmp_string); | ||||||
|     size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id); |     size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id); | ||||||
|     uint8_t* data = (uint8_t*)malloc(size); |     uint8_t* data = (uint8_t*)malloc(size); | ||||||
|     protocol_dict_get_data(app->dict, app->protocol_id, data, size); |     protocol_dict_get_data(app->dict, app->protocol_id, data, size); | ||||||
|     for(uint8_t i = 0; i < MIN(size, (size_t)8); i++) { |     for(uint8_t i = 0; i < MIN(size, (size_t)8); i++) { | ||||||
|         if(i != 0) { |         if(i != 0) { | ||||||
|             string_cat_printf(tmp_string, " "); |             furi_string_cat_printf(tmp_string, " "); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         string_cat_printf(tmp_string, "%02X", data[i]); |         furi_string_cat_printf(tmp_string, "%02X", data[i]); | ||||||
|     } |     } | ||||||
|     free(data); |     free(data); | ||||||
| 
 | 
 | ||||||
|     widget_add_string_element( |     widget_add_string_element( | ||||||
|         widget, 64, 19, AlignCenter, AlignTop, FontSecondary, string_get_cstr(tmp_string)); |         widget, 64, 19, AlignCenter, AlignTop, FontSecondary, furi_string_get_cstr(tmp_string)); | ||||||
|     widget_add_string_element( |     widget_add_string_element( | ||||||
|         widget, |         widget, | ||||||
|         64, |         64, | ||||||
| @ -39,7 +39,7 @@ void lfrfid_scene_delete_confirm_on_enter(void* context) { | |||||||
|         protocol_dict_get_name(app->dict, app->protocol_id)); |         protocol_dict_get_name(app->dict, app->protocol_id)); | ||||||
| 
 | 
 | ||||||
|     view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewWidget); |     view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewWidget); | ||||||
|     string_clear(tmp_string); |     furi_string_free(tmp_string); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool lfrfid_scene_delete_confirm_on_event(void* context, SceneManagerEvent event) { | bool lfrfid_scene_delete_confirm_on_event(void* context, SceneManagerEvent event) { | ||||||
|  | |||||||
| @ -8,8 +8,8 @@ void lfrfid_scene_emulate_on_enter(void* context) { | |||||||
|     DOLPHIN_DEED(DolphinDeedRfidEmulate); |     DOLPHIN_DEED(DolphinDeedRfidEmulate); | ||||||
| 
 | 
 | ||||||
|     popup_set_header(popup, "Emulating", 89, 30, AlignCenter, AlignTop); |     popup_set_header(popup, "Emulating", 89, 30, AlignCenter, AlignTop); | ||||||
|     if(!string_empty_p(app->file_name)) { |     if(!furi_string_empty(app->file_name)) { | ||||||
|         popup_set_text(popup, string_get_cstr(app->file_name), 89, 43, AlignCenter, AlignTop); |         popup_set_text(popup, furi_string_get_cstr(app->file_name), 89, 43, AlignCenter, AlignTop); | ||||||
|     } else { |     } else { | ||||||
|         popup_set_text( |         popup_set_text( | ||||||
|             popup, |             popup, | ||||||
|  | |||||||
| @ -42,7 +42,7 @@ void lfrfid_scene_extra_actions_on_enter(void* context) { | |||||||
|         submenu, scene_manager_get_scene_state(app->scene_manager, LfRfidSceneExtraActions)); |         submenu, scene_manager_get_scene_state(app->scene_manager, LfRfidSceneExtraActions)); | ||||||
| 
 | 
 | ||||||
|     // clear key
 |     // clear key
 | ||||||
|     string_reset(app->file_name); |     furi_string_reset(app->file_name); | ||||||
|     app->protocol_id = PROTOCOL_NO; |     app->protocol_id = PROTOCOL_NO; | ||||||
|     app->read_type = LFRFIDWorkerReadTypeAuto; |     app->read_type = LFRFIDWorkerReadTypeAuto; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -4,8 +4,8 @@ void lfrfid_scene_raw_info_on_enter(void* context) { | |||||||
|     LfRfid* app = context; |     LfRfid* app = context; | ||||||
|     Widget* widget = app->widget; |     Widget* widget = app->widget; | ||||||
| 
 | 
 | ||||||
|     // string_t tmp_string;
 |     // FuriString* tmp_string;
 | ||||||
|     // string_init(tmp_string);
 |     // tmp_string = furi_string_alloc();
 | ||||||
| 
 | 
 | ||||||
|     bool sd_exist = storage_sd_status(app->storage) == FSE_OK; |     bool sd_exist = storage_sd_status(app->storage) == FSE_OK; | ||||||
|     if(!sd_exist) { |     if(!sd_exist) { | ||||||
|  | |||||||
| @ -4,9 +4,9 @@ void lfrfid_scene_raw_name_on_enter(void* context) { | |||||||
|     LfRfid* app = context; |     LfRfid* app = context; | ||||||
|     TextInput* text_input = app->text_input; |     TextInput* text_input = app->text_input; | ||||||
| 
 | 
 | ||||||
|     const char* key_name = string_get_cstr(app->raw_file_name); |     const char* key_name = furi_string_get_cstr(app->raw_file_name); | ||||||
| 
 | 
 | ||||||
|     bool key_name_is_empty = string_empty_p(app->file_name); |     bool key_name_is_empty = furi_string_empty(app->file_name); | ||||||
|     if(key_name_is_empty) { |     if(key_name_is_empty) { | ||||||
|         lfrfid_text_store_set(app, "RfidRecord"); |         lfrfid_text_store_set(app, "RfidRecord"); | ||||||
|     } else { |     } else { | ||||||
| @ -38,7 +38,7 @@ bool lfrfid_scene_raw_name_on_event(void* context, SceneManagerEvent event) { | |||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == LfRfidEventNext) { |         if(event.event == LfRfidEventNext) { | ||||||
|             consumed = true; |             consumed = true; | ||||||
|             string_set_str(app->raw_file_name, app->text_store); |             furi_string_set(app->raw_file_name, app->text_store); | ||||||
|             scene_manager_next_scene(scene_manager, LfRfidSceneRawInfo); |             scene_manager_next_scene(scene_manager, LfRfidSceneRawInfo); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -3,7 +3,7 @@ | |||||||
| #define RAW_READ_TIME 5000 | #define RAW_READ_TIME 5000 | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     string_t string_file_name; |     FuriString* string_file_name; | ||||||
|     FuriTimer* timer; |     FuriTimer* timer; | ||||||
|     bool is_psk; |     bool is_psk; | ||||||
|     bool error; |     bool error; | ||||||
| @ -31,7 +31,7 @@ void lfrfid_scene_raw_read_on_enter(void* context) { | |||||||
| 
 | 
 | ||||||
|     LfRfidReadRawState* state = malloc(sizeof(LfRfidReadRawState)); |     LfRfidReadRawState* state = malloc(sizeof(LfRfidReadRawState)); | ||||||
|     scene_manager_set_scene_state(app->scene_manager, LfRfidSceneRawRead, (uint32_t)state); |     scene_manager_set_scene_state(app->scene_manager, LfRfidSceneRawRead, (uint32_t)state); | ||||||
|     string_init(state->string_file_name); |     state->string_file_name = furi_string_alloc(); | ||||||
| 
 | 
 | ||||||
|     popup_set_icon(popup, 0, 3, &I_RFIDDolphinReceive_97x61); |     popup_set_icon(popup, 0, 3, &I_RFIDDolphinReceive_97x61); | ||||||
|     view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewPopup); |     view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewPopup); | ||||||
| @ -40,16 +40,16 @@ void lfrfid_scene_raw_read_on_enter(void* context) { | |||||||
| 
 | 
 | ||||||
|     state->timer = furi_timer_alloc(timer_callback, FuriTimerTypeOnce, app); |     state->timer = furi_timer_alloc(timer_callback, FuriTimerTypeOnce, app); | ||||||
|     furi_timer_start(state->timer, RAW_READ_TIME); |     furi_timer_start(state->timer, RAW_READ_TIME); | ||||||
|     string_printf( |     furi_string_printf( | ||||||
|         state->string_file_name, |         state->string_file_name, | ||||||
|         "%s/%s%s", |         "%s/%s%s", | ||||||
|         LFRFID_SD_FOLDER, |         LFRFID_SD_FOLDER, | ||||||
|         string_get_cstr(app->raw_file_name), |         furi_string_get_cstr(app->raw_file_name), | ||||||
|         LFRFID_APP_RAW_ASK_EXTENSION); |         LFRFID_APP_RAW_ASK_EXTENSION); | ||||||
|     popup_set_header(popup, "Reading\nRAW RFID\nASK", 89, 30, AlignCenter, AlignTop); |     popup_set_header(popup, "Reading\nRAW RFID\nASK", 89, 30, AlignCenter, AlignTop); | ||||||
|     lfrfid_worker_read_raw_start( |     lfrfid_worker_read_raw_start( | ||||||
|         app->lfworker, |         app->lfworker, | ||||||
|         string_get_cstr(state->string_file_name), |         furi_string_get_cstr(state->string_file_name), | ||||||
|         LFRFIDWorkerReadTypeASKOnly, |         LFRFIDWorkerReadTypeASKOnly, | ||||||
|         lfrfid_read_callback, |         lfrfid_read_callback, | ||||||
|         app); |         app); | ||||||
| @ -88,15 +88,15 @@ bool lfrfid_scene_raw_read_on_event(void* context, SceneManagerEvent event) { | |||||||
|                         popup, "Reading\nRAW RFID\nPSK", 89, 30, AlignCenter, AlignTop); |                         popup, "Reading\nRAW RFID\nPSK", 89, 30, AlignCenter, AlignTop); | ||||||
|                     notification_message(app->notifications, &sequence_blink_start_yellow); |                     notification_message(app->notifications, &sequence_blink_start_yellow); | ||||||
|                     lfrfid_worker_stop(app->lfworker); |                     lfrfid_worker_stop(app->lfworker); | ||||||
|                     string_printf( |                     furi_string_printf( | ||||||
|                         state->string_file_name, |                         state->string_file_name, | ||||||
|                         "%s/%s%s", |                         "%s/%s%s", | ||||||
|                         LFRFID_SD_FOLDER, |                         LFRFID_SD_FOLDER, | ||||||
|                         string_get_cstr(app->raw_file_name), |                         furi_string_get_cstr(app->raw_file_name), | ||||||
|                         LFRFID_APP_RAW_PSK_EXTENSION); |                         LFRFID_APP_RAW_PSK_EXTENSION); | ||||||
|                     lfrfid_worker_read_raw_start( |                     lfrfid_worker_read_raw_start( | ||||||
|                         app->lfworker, |                         app->lfworker, | ||||||
|                         string_get_cstr(state->string_file_name), |                         furi_string_get_cstr(state->string_file_name), | ||||||
|                         LFRFIDWorkerReadTypePSKOnly, |                         LFRFIDWorkerReadTypePSKOnly, | ||||||
|                         lfrfid_read_callback, |                         lfrfid_read_callback, | ||||||
|                         app); |                         app); | ||||||
| @ -121,6 +121,6 @@ void lfrfid_scene_raw_read_on_exit(void* context) { | |||||||
|     lfrfid_worker_stop_thread(app->lfworker); |     lfrfid_worker_stop_thread(app->lfworker); | ||||||
|     furi_timer_free(state->timer); |     furi_timer_free(state->timer); | ||||||
| 
 | 
 | ||||||
|     string_clear(state->string_file_name); |     furi_string_free(state->string_file_name); | ||||||
|     free(state); |     free(state); | ||||||
| } | } | ||||||
|  | |||||||
| @ -81,7 +81,7 @@ bool lfrfid_scene_read_on_event(void* context, SceneManagerEvent event) { | |||||||
|             app->protocol_id = app->protocol_id_next; |             app->protocol_id = app->protocol_id_next; | ||||||
|             DOLPHIN_DEED(DolphinDeedRfidReadSuccess); |             DOLPHIN_DEED(DolphinDeedRfidReadSuccess); | ||||||
|             notification_message(app->notifications, &sequence_success); |             notification_message(app->notifications, &sequence_success); | ||||||
|             string_reset(app->file_name); |             furi_string_reset(app->file_name); | ||||||
|             scene_manager_next_scene(app->scene_manager, LfRfidSceneReadSuccess); |             scene_manager_next_scene(app->scene_manager, LfRfidSceneReadSuccess); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|         } else if(event.event == LfRfidEventReadStartPSK) { |         } else if(event.event == LfRfidEventReadStartPSK) { | ||||||
|  | |||||||
| @ -38,7 +38,7 @@ bool lfrfid_scene_read_key_menu_on_event(void* context, SceneManagerEvent event) | |||||||
|             scene_manager_next_scene(app->scene_manager, LfRfidSceneWrite); |             scene_manager_next_scene(app->scene_manager, LfRfidSceneWrite); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|         } else if(event.event == SubmenuIndexSave) { |         } else if(event.event == SubmenuIndexSave) { | ||||||
|             string_reset(app->file_name); |             furi_string_reset(app->file_name); | ||||||
|             scene_manager_next_scene(app->scene_manager, LfRfidSceneSaveName); |             scene_manager_next_scene(app->scene_manager, LfRfidSceneSaveName); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|         } else if(event.event == SubmenuIndexEmulate) { |         } else if(event.event == SubmenuIndexEmulate) { | ||||||
|  | |||||||
| @ -4,51 +4,51 @@ void lfrfid_scene_read_success_on_enter(void* context) { | |||||||
|     LfRfid* app = context; |     LfRfid* app = context; | ||||||
|     Widget* widget = app->widget; |     Widget* widget = app->widget; | ||||||
| 
 | 
 | ||||||
|     string_t tmp_string; |     FuriString* tmp_string; | ||||||
|     string_init(tmp_string); |     tmp_string = furi_string_alloc(); | ||||||
| 
 | 
 | ||||||
|     widget_add_button_element(widget, GuiButtonTypeLeft, "Retry", lfrfid_widget_callback, app); |     widget_add_button_element(widget, GuiButtonTypeLeft, "Retry", lfrfid_widget_callback, app); | ||||||
|     widget_add_button_element(widget, GuiButtonTypeRight, "More", lfrfid_widget_callback, app); |     widget_add_button_element(widget, GuiButtonTypeRight, "More", lfrfid_widget_callback, app); | ||||||
| 
 | 
 | ||||||
|     string_printf( |     furi_string_printf( | ||||||
|         tmp_string, |         tmp_string, | ||||||
|         "%s[%s]", |         "%s[%s]", | ||||||
|         protocol_dict_get_name(app->dict, app->protocol_id), |         protocol_dict_get_name(app->dict, app->protocol_id), | ||||||
|         protocol_dict_get_manufacturer(app->dict, app->protocol_id)); |         protocol_dict_get_manufacturer(app->dict, app->protocol_id)); | ||||||
| 
 | 
 | ||||||
|     widget_add_string_element( |     widget_add_string_element( | ||||||
|         widget, 0, 2, AlignLeft, AlignTop, FontPrimary, string_get_cstr(tmp_string)); |         widget, 0, 2, AlignLeft, AlignTop, FontPrimary, furi_string_get_cstr(tmp_string)); | ||||||
| 
 | 
 | ||||||
|     string_reset(tmp_string); |     furi_string_reset(tmp_string); | ||||||
|     size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id); |     size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id); | ||||||
|     uint8_t* data = (uint8_t*)malloc(size); |     uint8_t* data = (uint8_t*)malloc(size); | ||||||
|     protocol_dict_get_data(app->dict, app->protocol_id, data, size); |     protocol_dict_get_data(app->dict, app->protocol_id, data, size); | ||||||
|     for(uint8_t i = 0; i < size; i++) { |     for(uint8_t i = 0; i < size; i++) { | ||||||
|         if(i >= 9) { |         if(i >= 9) { | ||||||
|             string_cat_printf(tmp_string, ".."); |             furi_string_cat_printf(tmp_string, ".."); | ||||||
|             break; |             break; | ||||||
|         } else { |         } else { | ||||||
|             if(i != 0) { |             if(i != 0) { | ||||||
|                 string_cat_printf(tmp_string, " "); |                 furi_string_cat_printf(tmp_string, " "); | ||||||
|             } |             } | ||||||
|             string_cat_printf(tmp_string, "%02X", data[i]); |             furi_string_cat_printf(tmp_string, "%02X", data[i]); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     free(data); |     free(data); | ||||||
| 
 | 
 | ||||||
|     string_t render_data; |     FuriString* render_data; | ||||||
|     string_init(render_data); |     render_data = furi_string_alloc(); | ||||||
|     protocol_dict_render_brief_data(app->dict, render_data, app->protocol_id); |     protocol_dict_render_brief_data(app->dict, render_data, app->protocol_id); | ||||||
|     string_cat_printf(tmp_string, "\r\n%s", string_get_cstr(render_data)); |     furi_string_cat_printf(tmp_string, "\r\n%s", furi_string_get_cstr(render_data)); | ||||||
|     string_clear(render_data); |     furi_string_free(render_data); | ||||||
| 
 | 
 | ||||||
|     widget_add_string_multiline_element( |     widget_add_string_multiline_element( | ||||||
|         widget, 0, 16, AlignLeft, AlignTop, FontSecondary, string_get_cstr(tmp_string)); |         widget, 0, 16, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(tmp_string)); | ||||||
| 
 | 
 | ||||||
|     notification_message_block(app->notifications, &sequence_set_green_255); |     notification_message_block(app->notifications, &sequence_set_green_255); | ||||||
| 
 | 
 | ||||||
|     view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewWidget); |     view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewWidget); | ||||||
|     string_clear(tmp_string); |     furi_string_free(tmp_string); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool lfrfid_scene_read_success_on_event(void* context, SceneManagerEvent event) { | bool lfrfid_scene_read_success_on_event(void* context, SceneManagerEvent event) { | ||||||
|  | |||||||
| @ -34,13 +34,14 @@ bool lfrfid_scene_rpc_on_event(void* context, SceneManagerEvent event) { | |||||||
|             const char* arg = rpc_system_app_get_data(app->rpc_ctx); |             const char* arg = rpc_system_app_get_data(app->rpc_ctx); | ||||||
|             bool result = false; |             bool result = false; | ||||||
|             if(arg && (app->rpc_state == LfRfidRpcStateIdle)) { |             if(arg && (app->rpc_state == LfRfidRpcStateIdle)) { | ||||||
|                 string_set_str(app->file_path, arg); |                 furi_string_set(app->file_path, arg); | ||||||
|                 if(lfrfid_load_key_data(app, app->file_path, false)) { |                 if(lfrfid_load_key_data(app, app->file_path, false)) { | ||||||
|                     lfrfid_worker_start_thread(app->lfworker); |                     lfrfid_worker_start_thread(app->lfworker); | ||||||
|                     lfrfid_worker_emulate_start(app->lfworker, (LFRFIDProtocol)app->protocol_id); |                     lfrfid_worker_emulate_start(app->lfworker, (LFRFIDProtocol)app->protocol_id); | ||||||
|                     app->rpc_state = LfRfidRpcStateEmulating; |                     app->rpc_state = LfRfidRpcStateEmulating; | ||||||
| 
 | 
 | ||||||
|                     lfrfid_text_store_set(app, "emulating\n%s", string_get_cstr(app->file_name)); |                     lfrfid_text_store_set( | ||||||
|  |                         app, "emulating\n%s", furi_string_get_cstr(app->file_name)); | ||||||
|                     popup_set_text(popup, app->text_store, 89, 44, AlignCenter, AlignTop); |                     popup_set_text(popup, app->text_store, 89, 44, AlignCenter, AlignTop); | ||||||
| 
 | 
 | ||||||
|                     notification_message(app->notifications, &sequence_blink_start_magenta); |                     notification_message(app->notifications, &sequence_blink_start_magenta); | ||||||
|  | |||||||
| @ -9,14 +9,11 @@ void lfrfid_scene_save_data_on_enter(void* context) { | |||||||
| 
 | 
 | ||||||
|     bool need_restore = scene_manager_get_scene_state(app->scene_manager, LfRfidSceneSaveData); |     bool need_restore = scene_manager_get_scene_state(app->scene_manager, LfRfidSceneSaveData); | ||||||
| 
 | 
 | ||||||
|     if(need_restore) { |     if(!need_restore) { | ||||||
|         protocol_dict_set_data(app->dict, app->protocol_id, app->old_key_data, size); |  | ||||||
|     } else { |  | ||||||
|         protocol_dict_get_data(app->dict, app->protocol_id, app->old_key_data, size); |         protocol_dict_get_data(app->dict, app->protocol_id, app->old_key_data, size); | ||||||
|  |         protocol_dict_get_data(app->dict, app->protocol_id, app->new_key_data, size); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     protocol_dict_get_data(app->dict, app->protocol_id, app->new_key_data, size); |  | ||||||
| 
 |  | ||||||
|     byte_input_set_header_text(byte_input, "Enter the data in hex"); |     byte_input_set_header_text(byte_input, "Enter the data in hex"); | ||||||
| 
 | 
 | ||||||
|     byte_input_set_result_callback( |     byte_input_set_result_callback( | ||||||
| @ -41,6 +38,8 @@ bool lfrfid_scene_save_data_on_event(void* context, SceneManagerEvent event) { | |||||||
|         } |         } | ||||||
|     } else if(event.type == SceneManagerEventTypeBack) { |     } else if(event.type == SceneManagerEventTypeBack) { | ||||||
|         scene_manager_set_scene_state(scene_manager, LfRfidSceneSaveData, 0); |         scene_manager_set_scene_state(scene_manager, LfRfidSceneSaveData, 0); | ||||||
|  |         size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id); | ||||||
|  |         protocol_dict_set_data(app->dict, app->protocol_id, app->old_key_data, size); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return consumed; |     return consumed; | ||||||
|  | |||||||
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