Merge remote-tracking branch 'origin/release-candidate' into release
This commit is contained in:
		
						commit
						747e81fe1e
					
				
							
								
								
									
										3
									
								
								.github/workflows/amap_analyse.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.github/workflows/amap_analyse.yml
									
									
									
									
										vendored
									
									
								
							| @ -62,6 +62,8 @@ jobs: | ||||
| 
 | ||||
|       - name: 'Download build artifacts' | ||||
|         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; | ||||
|           chmod 600 ./deploy_key; | ||||
|           rsync -avzP \ | ||||
| @ -97,3 +99,4 @@ jobs: | ||||
|             ${{ secrets.AMAP_MARIADB_PORT }} \ | ||||
|             ${{ secrets.AMAP_MARIADB_DATABASE }} \ | ||||
|             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' | ||||
|         if: ${{ !github.event.pull_request.head.repo.fork }} | ||||
|         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' | ||||
|         run: | | ||||
|           set -e | ||||
|           for TARGET in ${TARGETS}; do | ||||
|             FBT_TOOLCHAIN_PATH=/opt ./fbt TARGET_HW="$(echo "${TARGET}" | sed 's/f//')" \ | ||||
|                 updater_package ${{ startsWith(github.ref, 'refs/tags') && 'DEBUG=0 COMPACT=1' || '' }} | ||||
|             FBT_TOOLCHAIN_PATH=/runner/_work ./fbt TARGET_HW="$(echo "${TARGET}" | sed 's/f//')" \ | ||||
|                 copro_dist updater_package ${{ startsWith(github.ref, 'refs/tags') && 'DEBUG=0 COMPACT=1' || '' }} | ||||
|           done | ||||
| 
 | ||||
|       - name: 'Move upload files' | ||||
| @ -74,17 +74,6 @@ jobs: | ||||
|             mv dist/${TARGET}-*/* artifacts/ | ||||
|           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" | ||||
|         run: | | ||||
|           git diff --exit-code | ||||
| @ -97,8 +86,7 @@ jobs: | ||||
|       - name: 'Bundle core2 firmware' | ||||
|         if: ${{ !github.event.pull_request.head.repo.fork }} | ||||
|         run: | | ||||
|           FBT_TOOLCHAIN_PATH=/opt ./fbt copro_dist | ||||
|           tar czpf "artifacts/flipper-z-any-core2_firmware-${SUFFIX}.tgz" -C assets core2_firmware | ||||
|           cp build/core2_firmware.tgz "artifacts/flipper-z-any-core2_firmware-${SUFFIX}.tgz" | ||||
| 
 | ||||
|       - name: 'Copy .map file' | ||||
|         run: | | ||||
| @ -107,6 +95,8 @@ jobs: | ||||
|       - name: 'Upload artifacts to update server' | ||||
|         if: ${{ !github.event.pull_request.head.repo.fork }} | ||||
|         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; | ||||
|           chmod 600 ./deploy_key; | ||||
|           rsync -avzP --delete --mkpath \ | ||||
| @ -137,7 +127,7 @@ jobs: | ||||
|             **Compiled firmware for commit `${{steps.names.outputs.commit_sha}}`:** | ||||
|             - [📦 Update package](https://update.flipperzero.one/builds/firmware/${{steps.names.outputs.branch_name}}/flipper-z-${{steps.names.outputs.default_target}}-update-${{steps.names.outputs.suffix}}.tgz) | ||||
|             - [📥 DFU file](https://update.flipperzero.one/builds/firmware/${{steps.names.outputs.branch_name}}/flipper-z-${{steps.names.outputs.default_target}}-full-${{steps.names.outputs.suffix}}.dfu) | ||||
|             - [☁️ Web 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 | ||||
| 
 | ||||
|   compact: | ||||
| @ -174,6 +164,6 @@ jobs: | ||||
|         run: | | ||||
|           set -e | ||||
|           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 | ||||
|           done | ||||
|  | ||||
							
								
								
									
										1
									
								
								.github/workflows/check_submodules.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.github/workflows/check_submodules.yml
									
									
									
									
										vendored
									
									
								
							| @ -27,6 +27,7 @@ jobs: | ||||
| 
 | ||||
|       - name: 'Check protobuf branch' | ||||
|         run: | | ||||
|           git submodule update --init | ||||
|           SUB_PATH="assets/protobuf"; | ||||
|           SUB_BRANCH="dev"; | ||||
|           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' | ||||
|         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 | ||||
|         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 }} | ||||
| 
 | ||||
|       - 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' | ||||
|         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' | ||||
|         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 analyze \ | ||||
|               @.pvsoptions \ | ||||
|               --disableLicenseExpirationCheck \ | ||||
|               -j$(grep -c processor /proc/cpuinfo) \ | ||||
|               -f build/f7-firmware-DC/compile_commands.json \ | ||||
|               -o PVS-Studio.log | ||||
| @ -75,6 +76,8 @@ jobs: | ||||
|       - name: 'Upload artifacts to update server' | ||||
|         if: ${{ !github.event.pull_request.head.repo.fork }} | ||||
|         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; | ||||
|           chmod 600 ./deploy_key; | ||||
|           rsync -avrzP --mkpath \ | ||||
|  | ||||
							
								
								
									
										63
									
								
								SConstruct
									
									
									
									
									
								
							
							
						
						
									
										63
									
								
								SConstruct
									
									
									
									
									
								
							| @ -7,7 +7,6 @@ | ||||
| # construction of certain targets behind command-line options. | ||||
| 
 | ||||
| import os | ||||
| import subprocess | ||||
| 
 | ||||
| DefaultEnvironment(tools=[]) | ||||
| 
 | ||||
| @ -15,17 +14,22 @@ EnsurePythonVersion(3, 8) | ||||
| 
 | ||||
| # Progress(["OwO\r", "owo\r", "uwu\r", "owo\r"], interval=15) | ||||
| 
 | ||||
| 
 | ||||
| # This environment is created only for loading options & validating file/dir existence | ||||
| fbt_variables = SConscript("site_scons/commandline.scons") | ||||
| cmd_environment = Environment(tools=[], variables=fbt_variables) | ||||
| Help(fbt_variables.GenerateHelpText(cmd_environment)) | ||||
| cmd_environment = Environment( | ||||
|     toolpath=["#/scripts/fbt_tools"], | ||||
|     tools=[ | ||||
|         ("fbt_help", {"vars": fbt_variables}), | ||||
|     ], | ||||
|     variables=fbt_variables, | ||||
| ) | ||||
| 
 | ||||
| # Building basic environment - tools, utility methods, cross-compilation | ||||
| # settings, gcc flags for Cortex-M4, basic builders and more | ||||
| coreenv = SConscript( | ||||
|     "site_scons/environ.scons", | ||||
|     exports={"VAR_ENV": cmd_environment}, | ||||
|     toolpath=["#/scripts/fbt_tools"], | ||||
| ) | ||||
| 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 | ||||
| distenv = coreenv.Clone( | ||||
|     tools=["fbt_dist", "openocd", "blackmagic", "jflash"], | ||||
|     OPENOCD_GDB_PIPE=[ | ||||
|         "|openocd -c 'gdb_port pipe; log_output debug/openocd.log' ${[SINGLEQUOTEFUNC(OPENOCD_OPTS)]}" | ||||
|     tools=[ | ||||
|         "fbt_dist", | ||||
|         "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, | ||||
| ) | ||||
| 
 | ||||
| @ -166,7 +142,7 @@ basic_dist = distenv.DistCommand("fw_dist", distenv["DIST_DEPENDS"]) | ||||
| distenv.Default(basic_dist) | ||||
| 
 | ||||
| dist_dir = distenv.GetProjetDirName() | ||||
| plugin_dist = [ | ||||
| fap_dist = [ | ||||
|     distenv.Install( | ||||
|         f"#/dist/{dist_dir}/apps/debug_elf", | ||||
|         firmware_env["FW_EXTAPPS"]["debug"].values(), | ||||
| @ -176,9 +152,9 @@ plugin_dist = [ | ||||
|         for dist_entry in firmware_env["FW_EXTAPPS"]["dist"].values() | ||||
|     ), | ||||
| ] | ||||
| Depends(plugin_dist, firmware_env["FW_EXTAPPS"]["validators"].values()) | ||||
| Alias("plugin_dist", plugin_dist) | ||||
| # distenv.Default(plugin_dist) | ||||
| Depends(fap_dist, firmware_env["FW_EXTAPPS"]["validators"].values()) | ||||
| Alias("fap_dist", fap_dist) | ||||
| # distenv.Default(fap_dist) | ||||
| 
 | ||||
| plugin_resources_dist = list( | ||||
|     distenv.Install(f"#/assets/resources/apps/{dist_entry[0]}", dist_entry[1]) | ||||
| @ -189,9 +165,10 @@ distenv.Depends(firmware_env["FW_RESOURCES"], plugin_resources_dist) | ||||
| 
 | ||||
| # Target for bundling core2 package for qFlipper | ||||
| copro_dist = distenv.CoproBuilder( | ||||
|     distenv.Dir("assets/core2_firmware"), | ||||
|     "#/build/core2_firmware.tgz", | ||||
|     [], | ||||
| ) | ||||
| distenv.AlwaysBuild(copro_dist) | ||||
| distenv.Alias("copro_dist", copro_dist) | ||||
| 
 | ||||
| firmware_flash = distenv.AddOpenOCDFlashTarget(firmware_env) | ||||
|  | ||||
| @ -3,14 +3,13 @@ | ||||
| #include <gui/canvas.h> | ||||
| #include <gui/elements.h> | ||||
| #include <m-array.h> | ||||
| #include <m-string.h> | ||||
| #include <furi.h> | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| struct BtTestParam { | ||||
|     const char* label; | ||||
|     uint8_t current_value_index; | ||||
|     string_t current_value_text; | ||||
|     FuriString* current_value_text; | ||||
|     uint8_t values_count; | ||||
|     BtTestParamChangeCallback change_callback; | ||||
|     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, 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)) { | ||||
|                 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) { | ||||
|     with_view_model( | ||||
|         bt_test->view, (BtTestModel * model) { | ||||
|         bt_test->view, | ||||
|         BtTestModel * model, | ||||
|         { | ||||
|             uint8_t params_on_screen = 3; | ||||
|             if(model->position > 0) { | ||||
|                 model->position--; | ||||
| @ -168,13 +170,15 @@ void bt_test_process_up(BtTest* bt_test) { | ||||
|                     model->window_position = model->position - (params_on_screen - 1); | ||||
|                 } | ||||
|             } | ||||
|             return true; | ||||
|         }); | ||||
|         }, | ||||
|         true); | ||||
| } | ||||
| 
 | ||||
| void bt_test_process_down(BtTest* bt_test) { | ||||
|     with_view_model( | ||||
|         bt_test->view, (BtTestModel * model) { | ||||
|         bt_test->view, | ||||
|         BtTestModel * model, | ||||
|         { | ||||
|             uint8_t params_on_screen = 3; | ||||
|             if(model->position < (BtTestParamArray_size(model->params) - 1)) { | ||||
|                 model->position++; | ||||
| @ -187,8 +191,8 @@ void bt_test_process_down(BtTest* bt_test) { | ||||
|                 model->position = 0; | ||||
|                 model->window_position = 0; | ||||
|             } | ||||
|             return true; | ||||
|         }); | ||||
|         }, | ||||
|         true); | ||||
| } | ||||
| 
 | ||||
| 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) { | ||||
|     BtTestParam* param; | ||||
|     with_view_model( | ||||
|         bt_test->view, (BtTestModel * model) { | ||||
|         bt_test->view, | ||||
|         BtTestModel * model, | ||||
|         { | ||||
|             param = bt_test_get_selected_param(model); | ||||
|             if(param->current_value_index > 0) { | ||||
|                 param->current_value_index--; | ||||
| @ -225,8 +231,8 @@ void bt_test_process_left(BtTest* bt_test) { | ||||
|                     model->packets_num_tx = 0; | ||||
|                 } | ||||
|             } | ||||
|             return true; | ||||
|         }); | ||||
|         }, | ||||
|         true); | ||||
|     if(param->change_callback) { | ||||
|         param->change_callback(param); | ||||
|     } | ||||
| @ -235,7 +241,9 @@ void bt_test_process_left(BtTest* bt_test) { | ||||
| void bt_test_process_right(BtTest* bt_test) { | ||||
|     BtTestParam* param; | ||||
|     with_view_model( | ||||
|         bt_test->view, (BtTestModel * model) { | ||||
|         bt_test->view, | ||||
|         BtTestModel * model, | ||||
|         { | ||||
|             param = bt_test_get_selected_param(model); | ||||
|             if(param->current_value_index < (param->values_count - 1)) { | ||||
|                 param->current_value_index++; | ||||
| @ -247,8 +255,8 @@ void bt_test_process_right(BtTest* bt_test) { | ||||
|                     model->packets_num_tx = 0; | ||||
|                 } | ||||
|             } | ||||
|             return true; | ||||
|         }); | ||||
|         }, | ||||
|         true); | ||||
|     if(param->change_callback) { | ||||
|         param->change_callback(param); | ||||
|     } | ||||
| @ -257,7 +265,9 @@ void bt_test_process_right(BtTest* bt_test) { | ||||
| void bt_test_process_ok(BtTest* bt_test) { | ||||
|     BtTestState state; | ||||
|     with_view_model( | ||||
|         bt_test->view, (BtTestModel * model) { | ||||
|         bt_test->view, | ||||
|         BtTestModel * model, | ||||
|         { | ||||
|             if(model->state == BtTestStateStarted) { | ||||
|                 model->state = BtTestStateStopped; | ||||
|                 model->message = BT_TEST_START_MESSAGE; | ||||
| @ -269,8 +279,8 @@ void bt_test_process_ok(BtTest* bt_test) { | ||||
|                 model->message = BT_TEST_STOP_MESSAGE; | ||||
|             } | ||||
|             state = model->state; | ||||
|             return true; | ||||
|         }); | ||||
|         }, | ||||
|         true); | ||||
|     if(bt_test->change_state_callback) { | ||||
|         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) { | ||||
|     with_view_model( | ||||
|         bt_test->view, (BtTestModel * model) { | ||||
|         bt_test->view, | ||||
|         BtTestModel * model, | ||||
|         { | ||||
|             model->state = BtTestStateStopped; | ||||
|             model->rssi = 0.0f; | ||||
|             model->packets_num_rx = 0; | ||||
|             model->packets_num_tx = 0; | ||||
|             return false; | ||||
|         }); | ||||
|         }, | ||||
|         false); | ||||
|     if(bt_test->back_callback) { | ||||
|         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); | ||||
| 
 | ||||
|     with_view_model( | ||||
|         bt_test->view, (BtTestModel * model) { | ||||
|         bt_test->view, | ||||
|         BtTestModel * model, | ||||
|         { | ||||
|             model->state = BtTestStateStopped; | ||||
|             model->message = "Ok - Start"; | ||||
|             BtTestParamArray_init(model->params); | ||||
| @ -308,8 +322,8 @@ BtTest* bt_test_alloc() { | ||||
|             model->rssi = 0.0f; | ||||
|             model->packets_num_tx = 0; | ||||
|             model->packets_num_rx = 0; | ||||
|             return true; | ||||
|         }); | ||||
|         }, | ||||
|         true); | ||||
| 
 | ||||
|     return bt_test; | ||||
| } | ||||
| @ -318,15 +332,17 @@ void bt_test_free(BtTest* bt_test) { | ||||
|     furi_assert(bt_test); | ||||
| 
 | ||||
|     with_view_model( | ||||
|         bt_test->view, (BtTestModel * model) { | ||||
|         bt_test->view, | ||||
|         BtTestModel * model, | ||||
|         { | ||||
|             BtTestParamArray_it_t it; | ||||
|             for(BtTestParamArray_it(it, model->params); !BtTestParamArray_end_p(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); | ||||
|             return false; | ||||
|         }); | ||||
|         }, | ||||
|         false); | ||||
|     view_free(bt_test->view); | ||||
|     free(bt_test); | ||||
| } | ||||
| @ -347,16 +363,18 @@ BtTestParam* bt_test_param_add( | ||||
|     furi_assert(bt_test); | ||||
| 
 | ||||
|     with_view_model( | ||||
|         bt_test->view, (BtTestModel * model) { | ||||
|         bt_test->view, | ||||
|         BtTestModel * model, | ||||
|         { | ||||
|             param = BtTestParamArray_push_new(model->params); | ||||
|             param->label = label; | ||||
|             param->values_count = values_count; | ||||
|             param->change_callback = change_callback; | ||||
|             param->context = context; | ||||
|             param->current_value_index = 0; | ||||
|             string_init(param->current_value_text); | ||||
|             return true; | ||||
|         }); | ||||
|             param->current_value_text = furi_string_alloc(); | ||||
|         }, | ||||
|         true); | ||||
| 
 | ||||
|     return param; | ||||
| } | ||||
| @ -364,28 +382,19 @@ BtTestParam* bt_test_param_add( | ||||
| void bt_test_set_rssi(BtTest* bt_test, float rssi) { | ||||
|     furi_assert(bt_test); | ||||
|     with_view_model( | ||||
|         bt_test->view, (BtTestModel * model) { | ||||
|             model->rssi = rssi; | ||||
|             return true; | ||||
|         }); | ||||
|         bt_test->view, BtTestModel * model, { model->rssi = rssi; }, true); | ||||
| } | ||||
| 
 | ||||
| void bt_test_set_packets_tx(BtTest* bt_test, uint32_t packets_num) { | ||||
|     furi_assert(bt_test); | ||||
|     with_view_model( | ||||
|         bt_test->view, (BtTestModel * model) { | ||||
|             model->packets_num_tx = packets_num; | ||||
|             return true; | ||||
|         }); | ||||
|         bt_test->view, BtTestModel * model, { model->packets_num_tx = packets_num; }, true); | ||||
| } | ||||
| 
 | ||||
| void bt_test_set_packets_rx(BtTest* bt_test, uint32_t packets_num) { | ||||
|     furi_assert(bt_test); | ||||
|     with_view_model( | ||||
|         bt_test->view, (BtTestModel * model) { | ||||
|             model->packets_num_rx = packets_num; | ||||
|             return true; | ||||
|         }); | ||||
|         bt_test->view, BtTestModel * model, { model->packets_num_rx = packets_num; }, true); | ||||
| } | ||||
| 
 | ||||
| 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) { | ||||
|     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) { | ||||
|  | ||||
| @ -113,11 +113,11 @@ static void display_config_set_regulation_ratio(VariableItem* item) { | ||||
| static void display_config_set_contrast(VariableItem* item) { | ||||
|     DisplayTest* instance = variable_item_get_context(item); | ||||
|     uint8_t index = variable_item_get_current_value_index(item); | ||||
|     string_t temp; | ||||
|     string_init(temp); | ||||
|     string_cat_printf(temp, "%d", index); | ||||
|     variable_item_set_current_value_text(item, string_get_cstr(temp)); | ||||
|     string_clear(temp); | ||||
|     FuriString* temp; | ||||
|     temp = furi_string_alloc(); | ||||
|     furi_string_cat_printf(temp, "%d", index); | ||||
|     variable_item_set_current_value_text(item, furi_string_get_cstr(temp)); | ||||
|     furi_string_free(temp); | ||||
|     instance->config_contrast = index; | ||||
|     display_test_reload_config(instance); | ||||
| } | ||||
|  | ||||
| @ -110,7 +110,9 @@ static bool view_display_test_input_callback(InputEvent* event, void* context) { | ||||
|     bool consumed = false; | ||||
|     if(event->type == InputTypeShort || event->type == InputTypeRepeat) { | ||||
|         with_view_model( | ||||
|             instance->view, (ViewDisplayTestModel * model) { | ||||
|             instance->view, | ||||
|             ViewDisplayTestModel * model, | ||||
|             { | ||||
|                 if(event->key == InputKeyLeft && model->test > 0) { | ||||
|                     model->test--; | ||||
|                     consumed = true; | ||||
| @ -129,8 +131,8 @@ static bool view_display_test_input_callback(InputEvent* event, void* context) { | ||||
|                     model->flip_flop = !model->flip_flop; | ||||
|                     consumed = true; | ||||
|                 } | ||||
|                 return consumed; | ||||
|             }); | ||||
|             }, | ||||
|             consumed); | ||||
|     } | ||||
| 
 | ||||
|     return consumed; | ||||
| @ -149,10 +151,7 @@ static void view_display_test_exit(void* context) { | ||||
| static void view_display_test_timer_callback(void* context) { | ||||
|     ViewDisplayTest* instance = context; | ||||
|     with_view_model( | ||||
|         instance->view, (ViewDisplayTestModel * model) { | ||||
|             model->counter++; | ||||
|             return true; | ||||
|         }); | ||||
|         instance->view, ViewDisplayTestModel * model, { model->counter++; }, true); | ||||
| } | ||||
| 
 | ||||
| ViewDisplayTest* view_display_test_alloc() { | ||||
|  | ||||
| @ -1,7 +1,6 @@ | ||||
| #include "assets_icons.h" | ||||
| #include "file_browser_app_i.h" | ||||
| #include "gui/modules/file_browser.h" | ||||
| #include "m-string.h" | ||||
| #include <furi.h> | ||||
| #include <furi_hal.h> | ||||
| #include <storage/storage.h> | ||||
| @ -47,7 +46,7 @@ FileBrowserApp* file_browser_app_alloc(char* arg) { | ||||
| 
 | ||||
|     app->widget = widget_alloc(); | ||||
| 
 | ||||
|     string_init(app->file_path); | ||||
|     app->file_path = furi_string_alloc(); | ||||
|     app->file_browser = file_browser_alloc(app->file_path); | ||||
|     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_DIALOGS); | ||||
| 
 | ||||
|     string_clear(app->file_path); | ||||
|     furi_string_free(app->file_path); | ||||
| 
 | ||||
|     free(app); | ||||
| } | ||||
|  | ||||
| @ -22,7 +22,7 @@ struct FileBrowserApp { | ||||
|     Widget* widget; | ||||
|     FileBrowser* file_browser; | ||||
| 
 | ||||
|     string_t file_path; | ||||
|     FuriString* file_path; | ||||
| }; | ||||
| 
 | ||||
| typedef enum { | ||||
|  | ||||
| @ -1,8 +1,5 @@ | ||||
| #include "../file_browser_app_i.h" | ||||
| #include <core/check.h> | ||||
| #include <core/log.h> | ||||
| #include "furi_hal.h" | ||||
| #include "m-string.h" | ||||
| #include <furi.h> | ||||
| 
 | ||||
| #define DEFAULT_PATH "/" | ||||
| #define EXTENSION "*" | ||||
|  | ||||
| @ -1,6 +1,5 @@ | ||||
| #include "../file_browser_app_i.h" | ||||
| #include "furi_hal.h" | ||||
| #include "m-string.h" | ||||
| #include <furi.h> | ||||
| 
 | ||||
| void file_browser_scene_result_ok_callback(InputType type, void* context) { | ||||
|     furi_assert(context); | ||||
| @ -24,7 +23,13 @@ void file_browser_scene_result_on_enter(void* context) { | ||||
|     FileBrowserApp* app = context; | ||||
| 
 | ||||
|     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); | ||||
| } | ||||
|  | ||||
| @ -19,7 +19,7 @@ bool file_browser_scene_start_on_event(void* context, SceneManagerEvent event) { | ||||
|     bool consumed = false; | ||||
| 
 | ||||
|     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); | ||||
|         consumed = true; | ||||
|     } 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) { | ||||
|     with_view_model( | ||||
|         tune_view->view, (LfRfidTuneViewModel * model) { | ||||
|         tune_view->view, | ||||
|         LfRfidTuneViewModel * model, | ||||
|         { | ||||
|             if(model->pos > 0) model->pos--; | ||||
|             return true; | ||||
|         }); | ||||
|         }, | ||||
|         true); | ||||
| } | ||||
| 
 | ||||
| static void lfrfid_debug_view_tune_button_down(LfRfidTuneView* tune_view) { | ||||
|     with_view_model( | ||||
|         tune_view->view, (LfRfidTuneViewModel * model) { | ||||
|         tune_view->view, | ||||
|         LfRfidTuneViewModel * model, | ||||
|         { | ||||
|             if(model->pos < 1) model->pos++; | ||||
|             return true; | ||||
|         }); | ||||
|         }, | ||||
|         true); | ||||
| } | ||||
| 
 | ||||
| static void lfrfid_debug_view_tune_button_left(LfRfidTuneView* tune_view) { | ||||
|     with_view_model( | ||||
|         tune_view->view, (LfRfidTuneViewModel * model) { | ||||
|         tune_view->view, | ||||
|         LfRfidTuneViewModel * model, | ||||
|         { | ||||
|             if(model->pos == 0) { | ||||
|                 if(model->fine) { | ||||
|                     model->ARR -= 1; | ||||
| @ -84,13 +90,15 @@ static void lfrfid_debug_view_tune_button_left(LfRfidTuneView* tune_view) { | ||||
|             } | ||||
| 
 | ||||
|             model->dirty = true; | ||||
|             return true; | ||||
|         }); | ||||
|         }, | ||||
|         true); | ||||
| } | ||||
| 
 | ||||
| static void lfrfid_debug_view_tune_button_right(LfRfidTuneView* tune_view) { | ||||
|     with_view_model( | ||||
|         tune_view->view, (LfRfidTuneViewModel * model) { | ||||
|         tune_view->view, | ||||
|         LfRfidTuneViewModel * model, | ||||
|         { | ||||
|             if(model->pos == 0) { | ||||
|                 if(model->fine) { | ||||
|                     model->ARR += 1; | ||||
| @ -106,16 +114,13 @@ static void lfrfid_debug_view_tune_button_right(LfRfidTuneView* tune_view) { | ||||
|             } | ||||
| 
 | ||||
|             model->dirty = true; | ||||
|             return true; | ||||
|         }); | ||||
|         }, | ||||
|         true); | ||||
| } | ||||
| 
 | ||||
| static void lfrfid_debug_view_tune_button_ok(LfRfidTuneView* tune_view) { | ||||
|     with_view_model( | ||||
|         tune_view->view, (LfRfidTuneViewModel * model) { | ||||
|             model->fine = !model->fine; | ||||
|             return true; | ||||
|         }); | ||||
|         tune_view->view, LfRfidTuneViewModel * model, { model->fine = !model->fine; }, true); | ||||
| } | ||||
| 
 | ||||
| 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)); | ||||
| 
 | ||||
|     with_view_model( | ||||
|         tune_view->view, (LfRfidTuneViewModel * model) { | ||||
|         tune_view->view, | ||||
|         LfRfidTuneViewModel * model, | ||||
|         { | ||||
|             model->dirty = true; | ||||
|             model->fine = false; | ||||
|             model->ARR = 511; | ||||
|             model->CCR = 255; | ||||
|             model->pos = 0; | ||||
|             return true; | ||||
|         }); | ||||
|         }, | ||||
|         true); | ||||
| 
 | ||||
|     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); | ||||
| @ -184,24 +191,28 @@ View* lfrfid_debug_view_tune_get_view(LfRfidTuneView* tune_view) { | ||||
| 
 | ||||
| void lfrfid_debug_view_tune_clean(LfRfidTuneView* tune_view) { | ||||
|     with_view_model( | ||||
|         tune_view->view, (LfRfidTuneViewModel * model) { | ||||
|         tune_view->view, | ||||
|         LfRfidTuneViewModel * model, | ||||
|         { | ||||
|             model->dirty = true; | ||||
|             model->fine = false; | ||||
|             model->ARR = 511; | ||||
|             model->CCR = 255; | ||||
|             model->pos = 0; | ||||
|             return true; | ||||
|         }); | ||||
|         }, | ||||
|         true); | ||||
| } | ||||
| 
 | ||||
| bool lfrfid_debug_view_tune_is_dirty(LfRfidTuneView* tune_view) { | ||||
|     bool result = false; | ||||
|     with_view_model( | ||||
|         tune_view->view, (LfRfidTuneViewModel * model) { | ||||
|         tune_view->view, | ||||
|         LfRfidTuneViewModel * model, | ||||
|         { | ||||
|             result = model->dirty; | ||||
|             model->dirty = false; | ||||
|             return false; | ||||
|         }); | ||||
|         }, | ||||
|         false); | ||||
| 
 | ||||
|     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 result = false; | ||||
|     with_view_model( | ||||
|         tune_view->view, (LfRfidTuneViewModel * model) { | ||||
|             result = model->ARR; | ||||
|             return false; | ||||
|         }); | ||||
|         tune_view->view, LfRfidTuneViewModel * model, { result = model->ARR; }, false); | ||||
| 
 | ||||
|     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 result = false; | ||||
|     with_view_model( | ||||
|         tune_view->view, (LfRfidTuneViewModel * model) { | ||||
|             result = model->CCR; | ||||
|             return false; | ||||
|         }); | ||||
|         tune_view->view, LfRfidTuneViewModel * model, { result = model->CCR; }, false); | ||||
| 
 | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| @ -1,10 +1,8 @@ | ||||
| #include <furi.h> | ||||
| #include <m-string.h> | ||||
| #include <gui/gui.h> | ||||
| #include <notification/notification.h> | ||||
| #include <notification/notification_messages.h> | ||||
| #include <gui/elements.h> | ||||
| #include <stream_buffer.h> | ||||
| #include <furi_hal_uart.h> | ||||
| #include <furi_hal_console.h> | ||||
| #include <gui/view_dispatcher.h> | ||||
| @ -21,11 +19,11 @@ typedef struct { | ||||
|     ViewDispatcher* view_dispatcher; | ||||
|     View* view; | ||||
|     FuriThread* worker_thread; | ||||
|     StreamBufferHandle_t rx_stream; | ||||
|     FuriStreamBuffer* rx_stream; | ||||
| } UartEchoApp; | ||||
| 
 | ||||
| typedef struct { | ||||
|     string_t text; | ||||
|     FuriString* text; | ||||
| } ListElement; | ||||
| 
 | ||||
| struct UartDumpModel { | ||||
| @ -64,10 +62,11 @@ static void uart_echo_view_draw_callback(Canvas* canvas, void* _model) { | ||||
|             canvas, | ||||
|             0, | ||||
|             (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) { | ||||
|             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, | ||||
| @ -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) { | ||||
|     furi_assert(context); | ||||
|     BaseType_t xHigherPriorityTaskWoken = pdFALSE; | ||||
|     UartEchoApp* app = context; | ||||
| 
 | ||||
|     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); | ||||
|         portYIELD_FROM_ISR(xHigherPriorityTaskWoken); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -113,7 +110,7 @@ static void uart_echo_push_to_list(UartDumpModel* model, const char data) { | ||||
|         model->escape = true; | ||||
|     } else if((data >= ' ' && data <= '~') || (data == '\n' || data == '\r')) { | ||||
|         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; | ||||
|         } else if((data == '\n' || data == '\r')) { | ||||
|             // 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]; | ||||
|                 } | ||||
| 
 | ||||
|                 string_reset(first->text); | ||||
|                 furi_string_reset(first->text); | ||||
|                 model->list[model->line] = first; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         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; | ||||
| @ -158,25 +155,24 @@ static int32_t uart_echo_worker(void* context) { | ||||
|             size_t length = 0; | ||||
|             do { | ||||
|                 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) { | ||||
|                     furi_hal_uart_tx(FuriHalUartIdUSART1, data, length); | ||||
|                     with_view_model( | ||||
|                         app->view, (UartDumpModel * model) { | ||||
|                         app->view, | ||||
|                         UartDumpModel * model, | ||||
|                         { | ||||
|                             for(size_t i = 0; i < length; i++) { | ||||
|                                 uart_echo_push_to_list(model, data[i]); | ||||
|                             } | ||||
|                             return false; | ||||
|                         }); | ||||
|                         }, | ||||
|                         false); | ||||
|                 } | ||||
|             } while(length > 0); | ||||
| 
 | ||||
|             notification_message(app->notification, &sequence_notification); | ||||
|             with_view_model( | ||||
|                 app->view, (UartDumpModel * model) { | ||||
|                     UNUSED(model); | ||||
|                     return true; | ||||
|                 }); | ||||
|                 app->view, UartDumpModel * model, { UNUSED(model); }, true); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| @ -186,7 +182,7 @@ static int32_t uart_echo_worker(void* context) { | ||||
| static UartEchoApp* uart_echo_app_alloc() { | ||||
|     UartEchoApp* app = malloc(sizeof(UartEchoApp)); | ||||
| 
 | ||||
|     app->rx_stream = xStreamBufferCreate(2048, 1); | ||||
|     app->rx_stream = furi_stream_buffer_alloc(2048, 1); | ||||
| 
 | ||||
|     // 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_allocate_model(app->view, ViewModelTypeLocking, sizeof(UartDumpModel)); | ||||
|     with_view_model( | ||||
|         app->view, (UartDumpModel * model) { | ||||
|         app->view, | ||||
|         UartDumpModel * model, | ||||
|         { | ||||
|             for(size_t i = 0; i < LINES_ON_SCREEN; i++) { | ||||
|                 model->line = 0; | ||||
|                 model->escape = false; | ||||
|                 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_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); | ||||
| 
 | ||||
|     with_view_model( | ||||
|         app->view, (UartDumpModel * model) { | ||||
|         app->view, | ||||
|         UartDumpModel * model, | ||||
|         { | ||||
|             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]); | ||||
|             } | ||||
|             return true; | ||||
|         }); | ||||
|         }, | ||||
|         true); | ||||
|     view_free(app->view); | ||||
|     view_dispatcher_free(app->view_dispatcher); | ||||
| 
 | ||||
| @ -260,7 +260,7 @@ static void uart_echo_app_free(UartEchoApp* app) { | ||||
|     furi_record_close(RECORD_NOTIFICATION); | ||||
|     app->gui = NULL; | ||||
| 
 | ||||
|     vStreamBufferDelete(app->rx_stream); | ||||
|     furi_stream_buffer_free(app->rx_stream); | ||||
| 
 | ||||
|     // Free rest
 | ||||
|     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)) | ||||
| 
 | ||||
| MU_TEST_1(flipper_format_read_and_update_test, FlipperFormat* flipper_format) { | ||||
|     string_t tmpstr; | ||||
|     FuriString* tmpstr; | ||||
|     uint32_t version; | ||||
|     uint32_t uint32_data[COUNT_OF(test_uint_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))); | ||||
| 
 | ||||
|     // read test
 | ||||
|     string_init(tmpstr); | ||||
|     tmpstr = furi_string_alloc(); | ||||
| 
 | ||||
|     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_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_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)); | ||||
| 
 | ||||
|     string_clear(tmpstr); | ||||
|     furi_string_free(tmpstr); | ||||
| 
 | ||||
|     // update data
 | ||||
|     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)]; | ||||
| 
 | ||||
|     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_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_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_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)); | ||||
| 
 | ||||
|     string_clear(tmpstr); | ||||
|     furi_string_free(tmpstr); | ||||
| 
 | ||||
|     // update data
 | ||||
|     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)]; | ||||
| 
 | ||||
|     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_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_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_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)); | ||||
| 
 | ||||
|     string_clear(tmpstr); | ||||
|     furi_string_free(tmpstr); | ||||
| 
 | ||||
|     // delete key test
 | ||||
|     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"; | ||||
| 
 | ||||
| #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
 | ||||
| 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; | ||||
| // data created by flipper itself
 | ||||
| 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) { | ||||
|     Storage* storage = furi_record_open(RECORD_STORAGE); | ||||
| @ -102,8 +121,8 @@ static bool test_read(const char* file_name) { | ||||
|     bool result = false; | ||||
| 
 | ||||
|     FlipperFormat* file = flipper_format_file_alloc(storage); | ||||
|     string_t string_value; | ||||
|     string_init(string_value); | ||||
|     FuriString* string_value; | ||||
|     string_value = furi_string_alloc(); | ||||
|     uint32_t uint32_value; | ||||
|     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_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(!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(uint32_value != COUNT_OF(test_int_data)) break; | ||||
| @ -150,7 +169,7 @@ static bool test_read(const char* file_name) { | ||||
|     } while(false); | ||||
| 
 | ||||
|     free(scratchpad); | ||||
|     string_clear(string_value); | ||||
|     furi_string_free(string_value); | ||||
| 
 | ||||
|     flipper_format_free(file); | ||||
| 
 | ||||
| @ -164,8 +183,8 @@ static bool test_read_updated(const char* file_name) { | ||||
|     bool result = false; | ||||
| 
 | ||||
|     FlipperFormat* file = flipper_format_file_alloc(storage); | ||||
|     string_t string_value; | ||||
|     string_init(string_value); | ||||
|     FuriString* string_value; | ||||
|     string_value = furi_string_alloc(); | ||||
|     uint32_t uint32_value; | ||||
|     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_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(!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(uint32_value != COUNT_OF(test_int_updated_data)) break; | ||||
| @ -228,7 +247,7 @@ static bool test_read_updated(const char* file_name) { | ||||
|     } while(false); | ||||
| 
 | ||||
|     free(scratchpad); | ||||
|     string_clear(string_value); | ||||
|     furi_string_free(string_value); | ||||
| 
 | ||||
|     flipper_format_free(file); | ||||
| 
 | ||||
| @ -401,14 +420,14 @@ static bool test_read_multikey(const char* file_name) { | ||||
|     bool result = false; | ||||
|     FlipperFormat* file = flipper_format_file_alloc(storage); | ||||
| 
 | ||||
|     string_t string_value; | ||||
|     string_init(string_value); | ||||
|     FuriString* string_value; | ||||
|     string_value = furi_string_alloc(); | ||||
|     uint32_t uint32_value; | ||||
| 
 | ||||
|     do { | ||||
|         if(!flipper_format_file_open_existing(file, file_name)) 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; | ||||
| 
 | ||||
|         bool error = false; | ||||
| @ -429,7 +448,7 @@ static bool test_read_multikey(const char* file_name) { | ||||
|         result = true; | ||||
|     } while(false); | ||||
| 
 | ||||
|     string_clear(string_value); | ||||
|     furi_string_free(string_value); | ||||
| 
 | ||||
|     flipper_format_free(file); | ||||
|     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_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) { | ||||
|     tests_setup(); | ||||
|     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_result_test); | ||||
|     MU_RUN_TEST(flipper_format_multikey_test); | ||||
|     MU_RUN_TEST(flipper_format_oddities_test); | ||||
|     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 { | ||||
|     InfraredDecoderHandler* decoder_handler; | ||||
|     InfraredEncoderHandler* encoder_handler; | ||||
|     string_t file_path; | ||||
|     FuriString* file_path; | ||||
|     FlipperFormat* ff; | ||||
| } InfraredTest; | ||||
| 
 | ||||
| @ -23,7 +23,7 @@ static void infrared_test_alloc() { | ||||
|     test->decoder_handler = infrared_alloc_decoder(); | ||||
|     test->encoder_handler = infrared_alloc_encoder(); | ||||
|     test->ff = flipper_format_buffered_file_alloc(storage); | ||||
|     string_init(test->file_path); | ||||
|     test->file_path = furi_string_alloc(); | ||||
| } | ||||
| 
 | ||||
| static void infrared_test_free() { | ||||
| @ -31,18 +31,18 @@ static void infrared_test_free() { | ||||
|     infrared_free_decoder(test->decoder_handler); | ||||
|     infrared_free_encoder(test->encoder_handler); | ||||
|     flipper_format_free(test->ff); | ||||
|     string_clear(test->file_path); | ||||
|     furi_string_free(test->file_path); | ||||
|     furi_record_close(RECORD_STORAGE); | ||||
|     free(test); | ||||
|     test = NULL; | ||||
| } | ||||
| 
 | ||||
| static bool infrared_test_prepare_file(const char* protocol_name) { | ||||
|     string_t file_type; | ||||
|     string_init(file_type); | ||||
|     FuriString* file_type; | ||||
|     file_type = furi_string_alloc(); | ||||
|     bool success = false; | ||||
| 
 | ||||
|     string_printf( | ||||
|     furi_string_printf( | ||||
|         test->file_path, | ||||
|         "%s%s%s%s", | ||||
|         IR_TEST_FILES_DIR, | ||||
| @ -52,14 +52,15 @@ static bool infrared_test_prepare_file(const char* protocol_name) { | ||||
| 
 | ||||
|     do { | ||||
|         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; | ||||
|         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; | ||||
|     } while(false); | ||||
| 
 | ||||
|     string_clear(file_type); | ||||
|     furi_string_free(file_type); | ||||
|     return success; | ||||
| } | ||||
| 
 | ||||
| @ -68,18 +69,18 @@ static bool infrared_test_load_raw_signal( | ||||
|     const char* signal_name, | ||||
|     uint32_t** timings, | ||||
|     uint32_t* timings_count) { | ||||
|     string_t buf; | ||||
|     string_init(buf); | ||||
|     FuriString* buf; | ||||
|     buf = furi_string_alloc(); | ||||
|     bool success = false; | ||||
| 
 | ||||
|     do { | ||||
|         bool is_name_found = false; | ||||
|         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(!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(!*timings_count) break; | ||||
| 
 | ||||
| @ -91,18 +92,18 @@ static bool infrared_test_load_raw_signal( | ||||
|         success = true; | ||||
|     } while(false); | ||||
| 
 | ||||
|     string_clear(buf); | ||||
|     furi_string_free(buf); | ||||
|     return success; | ||||
| } | ||||
| 
 | ||||
| static bool infrared_test_read_message(FlipperFormat* ff, InfraredMessage* message) { | ||||
|     string_t buf; | ||||
|     string_init(buf); | ||||
|     FuriString* buf; | ||||
|     buf = furi_string_alloc(); | ||||
|     bool success = false; | ||||
| 
 | ||||
|     do { | ||||
|         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(!flipper_format_read_hex(ff, "address", (uint8_t*)&message->address, sizeof(uint32_t))) | ||||
|             break; | ||||
| @ -112,7 +113,7 @@ static bool infrared_test_read_message(FlipperFormat* ff, InfraredMessage* messa | ||||
|         success = true; | ||||
|     } while(false); | ||||
| 
 | ||||
|     string_clear(buf); | ||||
|     furi_string_free(buf); | ||||
|     return success; | ||||
| } | ||||
| 
 | ||||
| @ -121,18 +122,19 @@ static bool infrared_test_load_messages( | ||||
|     const char* signal_name, | ||||
|     InfraredMessage** messages, | ||||
|     uint32_t* messages_count) { | ||||
|     string_t buf; | ||||
|     string_init(buf); | ||||
|     FuriString* buf; | ||||
|     buf = furi_string_alloc(); | ||||
|     bool success = false; | ||||
| 
 | ||||
|     do { | ||||
|         bool is_name_found = false; | ||||
|         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(!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; | ||||
|         if(!flipper_format_read_uint32(ff, "count", messages_count, 1)) break; | ||||
|         if(!*messages_count) break; | ||||
| @ -151,7 +153,7 @@ static bool infrared_test_load_messages( | ||||
|         success = true; | ||||
|     } while(false); | ||||
| 
 | ||||
|     string_clear(buf); | ||||
|     furi_string_free(buf); | ||||
|     return success; | ||||
| } | ||||
| 
 | ||||
| @ -213,26 +215,26 @@ static void infrared_test_run_encoder(InfraredProtocol protocol, uint32_t test_i | ||||
|     InfraredMessage* input_messages; | ||||
|     uint32_t input_messages_count; | ||||
| 
 | ||||
|     string_t buf; | ||||
|     string_init(buf); | ||||
|     FuriString* buf; | ||||
|     buf = furi_string_alloc(); | ||||
| 
 | ||||
|     const char* protocol_name = infrared_get_protocol_name(protocol); | ||||
|     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( | ||||
|         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"); | ||||
| 
 | ||||
|     string_printf(buf, "encoder_expected%d", test_index); | ||||
|     furi_string_printf(buf, "encoder_expected%ld", test_index); | ||||
|     mu_assert( | ||||
|         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"); | ||||
| 
 | ||||
|     flipper_format_buffered_file_close(test->ff); | ||||
|     string_clear(buf); | ||||
|     furi_string_free(buf); | ||||
| 
 | ||||
|     uint32_t j = 0; | ||||
|     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; | ||||
|     bool level = false; | ||||
| 
 | ||||
|     string_t buf; | ||||
|     string_init(buf); | ||||
|     FuriString* buf; | ||||
|     buf = furi_string_alloc(); | ||||
| 
 | ||||
|     timings = malloc(sizeof(uint32_t) * timings_count); | ||||
| 
 | ||||
|     const char* protocol_name = infrared_get_protocol_name(protocol); | ||||
|     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( | ||||
|         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"); | ||||
| 
 | ||||
|     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) { | ||||
|         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; | ||||
|     uint32_t messages_count; | ||||
| 
 | ||||
|     string_t buf; | ||||
|     string_init(buf); | ||||
|     FuriString* buf; | ||||
|     buf = furi_string_alloc(); | ||||
| 
 | ||||
|     mu_assert( | ||||
|         infrared_test_prepare_file(infrared_get_protocol_name(protocol)), | ||||
|         "Failed to prepare test file"); | ||||
| 
 | ||||
|     string_printf(buf, "decoder_input%d", test_index); | ||||
|     furi_string_printf(buf, "decoder_input%ld", test_index); | ||||
|     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"); | ||||
| 
 | ||||
|     string_printf(buf, "decoder_expected%d", test_index); | ||||
|     furi_string_printf(buf, "decoder_expected%ld", test_index); | ||||
|     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"); | ||||
| 
 | ||||
|     flipper_format_buffered_file_close(test->ff); | ||||
|     string_clear(buf); | ||||
|     furi_string_free(buf); | ||||
| 
 | ||||
|     InfraredMessage message_decoded_check_local; | ||||
|     bool level = 0; | ||||
|  | ||||
| @ -53,14 +53,15 @@ static bool nfc_test_read_signal_from_file(const char* file_name) { | ||||
|     bool success = false; | ||||
| 
 | ||||
|     FlipperFormat* file = flipper_format_file_alloc(nfc_test->storage); | ||||
|     string_t file_type; | ||||
|     string_init(file_type); | ||||
|     FuriString* file_type; | ||||
|     file_type = furi_string_alloc(); | ||||
|     uint32_t file_version = 0; | ||||
| 
 | ||||
|     do { | ||||
|         if(!flipper_format_file_open_existing(file, file_name)) 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; | ||||
|         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; | ||||
| @ -76,7 +77,7 @@ static bool nfc_test_read_signal_from_file(const char* file_name) { | ||||
|         success = true; | ||||
|     } while(false); | ||||
| 
 | ||||
|     string_clear(file_type); | ||||
|     furi_string_free(file_type); | ||||
|     flipper_format_free(file); | ||||
| 
 | ||||
|     return success; | ||||
| @ -111,7 +112,7 @@ static bool nfc_test_digital_signal_test_encode( | ||||
|         // Check timings
 | ||||
|         if(time > encode_max_time) { | ||||
|             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; | ||||
|         } | ||||
| 
 | ||||
| @ -131,7 +132,7 @@ static bool nfc_test_digital_signal_test_encode( | ||||
|             ref_timings_sum += ref[i]; | ||||
|             if(timings_diff > timing_tolerance) { | ||||
|                 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; | ||||
|                 break; | ||||
|             } | ||||
| @ -142,16 +143,16 @@ static bool nfc_test_digital_signal_test_encode( | ||||
|         if(sum_diff > timings_sum_tolerance) { | ||||
|             FURI_LOG_E( | ||||
|                 TAG, | ||||
|                 "Too big difference in timings sum. Ref: %d, DUT: %d", | ||||
|                 "Too big difference in timings sum. Ref: %ld, DUT: %ld", | ||||
|                 ref_timings_sum, | ||||
|                 dut_timings_sum); | ||||
|             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( | ||||
|             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, | ||||
|             timings_sum_tolerance); | ||||
|         success = true; | ||||
| @ -174,8 +175,8 @@ MU_TEST(nfc_digital_signal_test) { | ||||
| MU_TEST(mf_classic_dict_test) { | ||||
|     MfClassicDict* instance = NULL; | ||||
|     uint64_t key = 0; | ||||
|     string_t temp_str; | ||||
|     string_init(temp_str); | ||||
|     FuriString* temp_str; | ||||
|     temp_str = furi_string_alloc(); | ||||
| 
 | ||||
|     instance = mf_classic_dict_alloc(MfClassicDictTypeUnitTest); | ||||
|     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 == 0 assert failed\r\n"); | ||||
| 
 | ||||
|     string_set(temp_str, "2196FAD8115B"); | ||||
|     furi_string_set(temp_str, "2196FAD8115B"); | ||||
|     mu_assert( | ||||
|         mf_classic_dict_add_key_str(instance, temp_str), | ||||
|         "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 == true assert failed\r\n"); | ||||
|     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"); | ||||
| 
 | ||||
|     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_free(instance); | ||||
|     string_clear(temp_str); | ||||
|     furi_string_free(temp_str); | ||||
| } | ||||
| 
 | ||||
| MU_TEST_SUITE(nfc) { | ||||
|  | ||||
| @ -10,7 +10,6 @@ | ||||
| #include <furi.h> | ||||
| #include "../minunit.h" | ||||
| #include <stdint.h> | ||||
| #include <stream_buffer.h> | ||||
| #include <pb.h> | ||||
| #include <pb_encode.h> | ||||
| #include <m-list.h> | ||||
| @ -34,7 +33,7 @@ static uint32_t command_id = 0; | ||||
| 
 | ||||
| typedef struct { | ||||
|     RpcSession* session; | ||||
|     StreamBufferHandle_t output_stream; | ||||
|     FuriStreamBuffer* output_stream; | ||||
|     SemaphoreHandle_t close_session_semaphore; | ||||
|     SemaphoreHandle_t terminate_semaphore; | ||||
|     TickType_t timeout; | ||||
| @ -90,7 +89,7 @@ static void test_rpc_setup(void) { | ||||
|     } | ||||
|     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[0].close_session_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); | ||||
| 
 | ||||
|     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[1].close_session_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); | ||||
|     furi_check(xSemaphoreTake(rpc_session[0].terminate_semaphore, portMAX_DELAY)); | ||||
|     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].terminate_semaphore); | ||||
|     ++command_id; | ||||
| @ -141,7 +140,7 @@ static void test_rpc_teardown_second_session(void) { | ||||
|     xSemaphoreTake(rpc_session[1].terminate_semaphore, 0); | ||||
|     rpc_session_close(rpc_session[1].session); | ||||
|     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].terminate_semaphore); | ||||
|     ++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) { | ||||
|     RpcSessionContext* callbacks_context = ctx; | ||||
| 
 | ||||
|     size_t bytes_sent = | ||||
|         xStreamBufferSend(callbacks_context->output_stream, got_bytes, got_size, FuriWaitForever); | ||||
|     size_t bytes_sent = furi_stream_buffer_send( | ||||
|         callbacks_context->output_stream, got_bytes, got_size, FuriWaitForever); | ||||
|     (void)bytes_sent; | ||||
|     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(); | ||||
|     int32_t time_left = session_context->timeout - now; | ||||
|     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); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -75,7 +75,7 @@ typedef struct { | ||||
|     bool visited; | ||||
| } 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* | ||||
|     storage_test_paths_alloc(const StorageTestPathDesc paths[], size_t paths_count) { | ||||
| @ -83,15 +83,15 @@ static StorageTestPathDict_t* | ||||
|     StorageTestPathDict_init(*data); | ||||
| 
 | ||||
|     for(size_t i = 0; i < paths_count; i++) { | ||||
|         string_t key; | ||||
|         string_init_set(key, paths[i].path); | ||||
|         FuriString* key; | ||||
|         key = furi_string_alloc_set(paths[i].path); | ||||
|         StorageTestPath value = { | ||||
|             .is_dir = paths[i].is_dir, | ||||
|             .visited = false, | ||||
|         }; | ||||
| 
 | ||||
|         StorageTestPathDict_set_at(*data, key, value); | ||||
|         string_clear(key); | ||||
|         furi_string_free(key); | ||||
|     } | ||||
| 
 | ||||
|     return data; | ||||
| @ -102,7 +102,7 @@ static void storage_test_paths_free(StorageTestPathDict_t* 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; | ||||
| 
 | ||||
|     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) { | ||||
|     string_t path; | ||||
|     string_init(path); | ||||
|     FuriString* path; | ||||
|     path = furi_string_alloc(); | ||||
| 
 | ||||
|     storage_common_mkdir(storage, base); | ||||
| 
 | ||||
|     for(size_t i = 0; i < COUNT_OF(storage_test_dirwalk_paths); i++) { | ||||
|         string_printf(path, "%s/%s", base, storage_test_dirwalk_paths[i]); | ||||
|         storage_common_mkdir(storage, string_get_cstr(path)); | ||||
|         furi_string_printf(path, "%s/%s", base, storage_test_dirwalk_paths[i]); | ||||
|         storage_common_mkdir(storage, furi_string_get_cstr(path)); | ||||
|     } | ||||
| 
 | ||||
|     for(size_t i = 0; i < COUNT_OF(storage_test_dirwalk_files); i++) { | ||||
|         string_printf(path, "%s/%s", base, storage_test_dirwalk_files[i]); | ||||
|         write_file_13DA(storage, string_get_cstr(path)); | ||||
|         furi_string_printf(path, "%s/%s", base, storage_test_dirwalk_files[i]); | ||||
|         write_file_13DA(storage, furi_string_get_cstr(path)); | ||||
|     } | ||||
| 
 | ||||
|     string_clear(path); | ||||
|     furi_string_free(path); | ||||
| } | ||||
| 
 | ||||
| MU_TEST_1(test_dirwalk_full, Storage* storage) { | ||||
|     string_t path; | ||||
|     string_init(path); | ||||
|     FuriString* path; | ||||
|     path = furi_string_alloc(); | ||||
|     FileInfo fileinfo; | ||||
| 
 | ||||
|     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"))); | ||||
| 
 | ||||
|     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))); | ||||
|     } | ||||
| 
 | ||||
|     dir_walk_free(dir_walk); | ||||
|     string_clear(path); | ||||
|     furi_string_free(path); | ||||
| 
 | ||||
|     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) { | ||||
|     string_t path; | ||||
|     string_init(path); | ||||
|     FuriString* path; | ||||
|     path = furi_string_alloc(); | ||||
|     FileInfo fileinfo; | ||||
| 
 | ||||
|     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"))); | ||||
| 
 | ||||
|     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))); | ||||
|     } | ||||
| 
 | ||||
|     dir_walk_free(dir_walk); | ||||
|     string_clear(path); | ||||
|     furi_string_free(path); | ||||
| 
 | ||||
|     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) { | ||||
|     string_t path; | ||||
|     string_init(path); | ||||
|     FuriString* path; | ||||
|     path = furi_string_alloc(); | ||||
|     FileInfo fileinfo; | ||||
| 
 | ||||
|     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"))); | ||||
| 
 | ||||
|     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))); | ||||
|     } | ||||
| 
 | ||||
|     dir_walk_free(dir_walk); | ||||
|     string_clear(path); | ||||
|     furi_string_free(path); | ||||
| 
 | ||||
|     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) { | ||||
|     string_t path; | ||||
|     string_init(path); | ||||
|     FuriString* path; | ||||
|     path = furi_string_alloc(); | ||||
| 
 | ||||
|     storage_common_mkdir(storage, base); | ||||
| 
 | ||||
|     for(size_t i = 0; i < COUNT_OF(storage_copy_test_paths); i++) { | ||||
|         string_printf(path, "%s/%s", base, storage_copy_test_paths[i]); | ||||
|         storage_common_mkdir(storage, string_get_cstr(path)); | ||||
|         furi_string_printf(path, "%s/%s", base, storage_copy_test_paths[i]); | ||||
|         storage_common_mkdir(storage, furi_string_get_cstr(path)); | ||||
|     } | ||||
| 
 | ||||
|     for(size_t i = 0; i < COUNT_OF(storage_copy_test_files); i++) { | ||||
|         string_printf(path, "%s/%s", base, storage_copy_test_files[i]); | ||||
|         write_file_13DA(storage, string_get_cstr(path)); | ||||
|         furi_string_printf(path, "%s/%s", base, storage_copy_test_files[i]); | ||||
|         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) { | ||||
| @ -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) { | ||||
|     bool result = false; | ||||
|     string_t path; | ||||
|     string_init(path); | ||||
|     FuriString* path; | ||||
|     path = furi_string_alloc(); | ||||
| 
 | ||||
|     result = (storage_common_stat(storage, base, NULL) == FSE_OK); | ||||
| 
 | ||||
|     if(result) { | ||||
|         for(size_t i = 0; i < COUNT_OF(storage_copy_test_paths); i++) { | ||||
|             string_printf(path, "%s/%s", base, storage_copy_test_paths[i]); | ||||
|             result = (storage_common_stat(storage, string_get_cstr(path), NULL) == FSE_OK); | ||||
|             furi_string_printf(path, "%s/%s", base, storage_copy_test_paths[i]); | ||||
|             result = (storage_common_stat(storage, furi_string_get_cstr(path), NULL) == FSE_OK); | ||||
|             if(!result) { | ||||
|                 break; | ||||
|             } | ||||
| @ -252,15 +252,15 @@ static bool storage_dir_rename_check(Storage* storage, const char* base) { | ||||
| 
 | ||||
|     if(result) { | ||||
|         for(size_t i = 0; i < COUNT_OF(storage_copy_test_files); i++) { | ||||
|             string_printf(path, "%s/%s", base, storage_copy_test_files[i]); | ||||
|             result = check_file_13DA(storage, string_get_cstr(path)); | ||||
|             furi_string_printf(path, "%s/%s", base, storage_copy_test_files[i]); | ||||
|             result = check_file_13DA(storage, furi_string_get_cstr(path)); | ||||
|             if(!result) { | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     string_clear(path); | ||||
|     furi_string_free(path); | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -18,8 +18,8 @@ static const char* stream_test_right_data = | ||||
| MU_TEST_1(stream_composite_subtest, Stream* stream) { | ||||
|     const size_t data_size = 128; | ||||
|     uint8_t data[data_size]; | ||||
|     string_t string_lee; | ||||
|     string_init_set(string_lee, "lee"); | ||||
|     FuriString* string_lee; | ||||
|     string_lee = furi_string_alloc_set("lee"); | ||||
| 
 | ||||
|     // 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_check(stream_eof(stream)); | ||||
| 
 | ||||
|     string_clear(string_lee); | ||||
|     furi_string_free(string_lee); | ||||
| } | ||||
| 
 | ||||
| MU_TEST(stream_composite_test) { | ||||
| @ -416,10 +416,10 @@ MU_TEST(stream_buffered_write_after_read_test) { | ||||
| } | ||||
| 
 | ||||
| MU_TEST(stream_buffered_large_file_test) { | ||||
|     string_t input_data; | ||||
|     string_t output_data; | ||||
|     string_init(input_data); | ||||
|     string_init(output_data); | ||||
|     FuriString* input_data; | ||||
|     FuriString* output_data; | ||||
|     input_data = furi_string_alloc(); | ||||
|     output_data = furi_string_alloc(); | ||||
| 
 | ||||
|     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; | ||||
| 
 | ||||
|     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
 | ||||
| @ -437,8 +437,8 @@ MU_TEST(stream_buffered_large_file_test) { | ||||
|     mu_check(buffered_file_stream_open( | ||||
|         stream, EXT_PATH("filestream.str"), FSAM_READ_WRITE, FSOM_CREATE_ALWAYS)); | ||||
|     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(string_size(input_data), stream_size(stream)); | ||||
|     mu_assert_int_eq(furi_string_size(input_data), stream_write_string(stream, input_data)); | ||||
|     mu_assert_int_eq(furi_string_size(input_data), stream_size(stream)); | ||||
| 
 | ||||
|     const size_t substr_start = 8; | ||||
|     const size_t substr_len = 11; | ||||
| @ -475,23 +475,23 @@ MU_TEST(stream_buffered_large_file_test) { | ||||
| 
 | ||||
|     // read the whole file
 | ||||
|     mu_check(stream_rewind(stream)); | ||||
|     string_t tmp; | ||||
|     string_init(tmp); | ||||
|     FuriString* tmp; | ||||
|     tmp = furi_string_alloc(); | ||||
|     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
 | ||||
|     mu_assert_int_eq(string_size(input_data), string_size(output_data)); | ||||
|     mu_check(string_equal_p(input_data, output_data)); | ||||
|     mu_assert_int_eq(furi_string_size(input_data), furi_string_size(output_data)); | ||||
|     mu_check(furi_string_equal(input_data, output_data)); | ||||
|     mu_check(stream_eof(stream)); | ||||
| 
 | ||||
|     stream_free(stream); | ||||
| 
 | ||||
|     furi_record_close(RECORD_STORAGE); | ||||
|     string_clear(input_data); | ||||
|     string_clear(output_data); | ||||
|     furi_string_free(input_data); | ||||
|     furi_string_free(output_data); | ||||
| } | ||||
| 
 | ||||
| MU_TEST_SUITE(stream_suite) { | ||||
|  | ||||
| @ -28,12 +28,12 @@ static void subghz_test_rx_callback( | ||||
|     void* context) { | ||||
|     UNUSED(receiver); | ||||
|     UNUSED(context); | ||||
|     string_t text; | ||||
|     string_init(text); | ||||
|     FuriString* text; | ||||
|     text = furi_string_alloc(); | ||||
|     subghz_protocol_decoder_base_get_string(decoder_base, text); | ||||
|     subghz_receiver_reset(receiver_handler); | ||||
|     FURI_LOG_T(TAG, "\r\n%s", string_get_cstr(text)); | ||||
|     string_clear(text); | ||||
|     FURI_LOG_T(TAG, "\r\n%s", furi_string_get_cstr(text)); | ||||
|     furi_string_free(text); | ||||
|     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) { | ||||
|     subghz_test_decoder_count = 0; | ||||
|     uint32_t test_start = furi_get_tick(); | ||||
|     string_t temp_str; | ||||
|     string_init(temp_str); | ||||
|     FuriString* temp_str; | ||||
|     temp_str = furi_string_alloc(); | ||||
|     bool file_load = false; | ||||
| 
 | ||||
|     Storage* storage = furi_record_open(RECORD_STORAGE); | ||||
| @ -167,11 +167,11 @@ static bool subghz_encoder_test(const char* path) { | ||||
|     } while(false); | ||||
|     if(file_load) { | ||||
|         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); | ||||
| 
 | ||||
|         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) { | ||||
|             LevelDuration level_duration; | ||||
| @ -192,10 +192,11 @@ static bool subghz_encoder_test(const char* path) { | ||||
|     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); | ||||
|     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; | ||||
|     } | ||||
|     string_clear(temp_str); | ||||
|     furi_string_free(temp_str); | ||||
| 
 | ||||
|     return subghz_test_decoder_count ? true : false; | ||||
| } | ||||
|  | ||||
| @ -1,5 +1,3 @@ | ||||
| #include "m-string.h" | ||||
| 
 | ||||
| #include <stdio.h> | ||||
| #include <furi.h> | ||||
| #include <furi_hal.h> | ||||
| @ -11,6 +9,7 @@ | ||||
| #define TAG "UnitTests" | ||||
| 
 | ||||
| int run_minunit_test_furi(); | ||||
| int run_minunit_test_furi_string(); | ||||
| int run_minunit_test_infrared(); | ||||
| int run_minunit_test_rpc(); | ||||
| int run_minunit_test_flipper_format(); | ||||
| @ -33,6 +32,7 @@ typedef struct { | ||||
| 
 | ||||
| const UnitTest unit_tests[] = { | ||||
|     {.name = "furi", .entry = run_minunit_test_furi}, | ||||
|     {.name = "furi_string", .entry = run_minunit_test_furi_string}, | ||||
|     {.name = "storage", .entry = run_minunit_test_storage}, | ||||
|     {.name = "stream", .entry = run_minunit_test_stream}, | ||||
|     {.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); | ||||
| } | ||||
| 
 | ||||
| void unit_tests_cli(Cli* cli, string_t args, void* context) { | ||||
| void unit_tests_cli(Cli* cli, FuriString* args, void* context) { | ||||
|     UNUSED(cli); | ||||
|     UNUSED(args); | ||||
|     UNUSED(context); | ||||
| @ -91,8 +91,8 @@ void unit_tests_cli(Cli* cli, string_t args, void* context) { | ||||
|                 break; | ||||
|             } | ||||
| 
 | ||||
|             if(string_size(args)) { | ||||
|                 if(string_cmp_str(args, unit_tests[i].name) == 0) { | ||||
|             if(furi_string_size(args)) { | ||||
|                 if(furi_string_cmp_str(args, unit_tests[i].name) == 0) { | ||||
|                     failed_tests += unit_tests[i].entry(); | ||||
|                 } else { | ||||
|                     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 "m-string.h" | ||||
| 
 | ||||
| bool archive_custom_event_callback(void* context, uint32_t event) { | ||||
|     furi_assert(context); | ||||
| @ -18,7 +17,7 @@ ArchiveApp* archive_alloc() { | ||||
| 
 | ||||
|     archive->gui = furi_record_open(RECORD_GUI); | ||||
|     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->scene_manager = scene_manager_alloc(&archive_scene_handlers, archive); | ||||
| @ -58,7 +57,7 @@ void archive_free(ArchiveApp* archive) { | ||||
|     view_dispatcher_free(archive->view_dispatcher); | ||||
|     scene_manager_free(archive->scene_manager); | ||||
|     browser_free(archive->browser); | ||||
|     string_clear(archive->fav_move_str); | ||||
|     furi_string_free(archive->fav_move_str); | ||||
| 
 | ||||
|     text_input_free(archive->text_input); | ||||
| 
 | ||||
|  | ||||
| @ -28,7 +28,7 @@ struct ArchiveApp { | ||||
|     TextInput* text_input; | ||||
|     Widget* widget; | ||||
|     FuriPubSubSubscription* loader_stop_subscription; | ||||
|     string_t fav_move_str; | ||||
|     FuriString* fav_move_str; | ||||
|     char text_store[MAX_NAME_LEN]; | ||||
|     char file_extension[MAX_EXT_LEN + 1]; | ||||
| }; | ||||
|  | ||||
| @ -5,7 +5,7 @@ | ||||
| #include <core/common_defines.h> | ||||
| #include <core/log.h> | ||||
| #include "gui/modules/file_browser_worker.h" | ||||
| #include "m-string.h" | ||||
| #include <fap_loader/fap_loader_app.h> | ||||
| #include <math.h> | ||||
| 
 | ||||
| static void | ||||
| @ -19,9 +19,11 @@ static void | ||||
| 
 | ||||
|     if((item_cnt == 0) && (archive_is_home(browser)) && (tab != ArchiveTabBrowser)) { | ||||
|         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( | ||||
|             browser->view, (ArchiveBrowserViewModel * model) { | ||||
|             browser->view, | ||||
|             ArchiveBrowserViewModel * model, | ||||
|             { | ||||
|                 files_array_reset(model->files); | ||||
|                 model->item_cnt = item_cnt; | ||||
|                 model->item_idx = (file_idx > 0) ? file_idx : 0; | ||||
| @ -31,8 +33,8 @@ static void | ||||
|                 model->list_offset = 0; | ||||
|                 model->list_loading = true; | ||||
|                 model->folder_loading = false; | ||||
|                 return false; | ||||
|             }); | ||||
|             }, | ||||
|             false); | ||||
|         archive_update_offset(browser); | ||||
| 
 | ||||
|         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; | ||||
| 
 | ||||
|     with_view_model( | ||||
|         browser->view, (ArchiveBrowserViewModel * model) { | ||||
|         browser->view, | ||||
|         ArchiveBrowserViewModel * model, | ||||
|         { | ||||
|             files_array_reset(model->files); | ||||
|             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); | ||||
|     ArchiveBrowserView* browser = (ArchiveBrowserView*)context; | ||||
| 
 | ||||
|     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 { | ||||
|         with_view_model( | ||||
|             browser->view, (ArchiveBrowserViewModel * model) { | ||||
|                 model->list_loading = false; | ||||
|                 return true; | ||||
|             }); | ||||
|             browser->view, ArchiveBrowserViewModel * model, { model->list_loading = false; }, true); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -71,15 +73,12 @@ static void archive_long_load_cb(void* context) { | ||||
|     ArchiveBrowserView* browser = (ArchiveBrowserView*)context; | ||||
| 
 | ||||
|     with_view_model( | ||||
|         browser->view, (ArchiveBrowserViewModel * model) { | ||||
|             model->folder_loading = true; | ||||
|             return true; | ||||
|         }); | ||||
|         browser->view, ArchiveBrowserViewModel * model, { model->folder_loading = true; }, true); | ||||
| } | ||||
| 
 | ||||
| static void archive_file_browser_set_path( | ||||
|     ArchiveBrowserView* browser, | ||||
|     string_t path, | ||||
|     FuriString* path, | ||||
|     const char* filter_ext, | ||||
|     bool skip_assets) { | ||||
|     furi_assert(browser); | ||||
| @ -112,7 +111,9 @@ void archive_update_offset(ArchiveBrowserView* browser) { | ||||
|     furi_assert(browser); | ||||
| 
 | ||||
|     with_view_model( | ||||
|         browser->view, (ArchiveBrowserViewModel * model) { | ||||
|         browser->view, | ||||
|         ArchiveBrowserViewModel * model, | ||||
|         { | ||||
|             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))) { | ||||
| @ -124,33 +125,34 @@ void archive_update_offset(ArchiveBrowserView* browser) { | ||||
|                 model->list_offset = | ||||
|                     CLAMP(model->item_idx - 1, (int32_t)model->item_cnt - bounds, 0); | ||||
|             } | ||||
| 
 | ||||
|             return true; | ||||
|         }); | ||||
|         }, | ||||
|         true); | ||||
| } | ||||
| 
 | ||||
| void archive_update_focus(ArchiveBrowserView* browser, const char* target) { | ||||
|     furi_assert(browser); | ||||
|     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)) { | ||||
|         archive_switch_tab(browser, TAB_RIGHT); | ||||
|     } else { | ||||
|         with_view_model( | ||||
|             browser->view, (ArchiveBrowserViewModel * model) { | ||||
|             browser->view, | ||||
|             ArchiveBrowserViewModel * model, | ||||
|             { | ||||
|                 uint16_t idx = 0; | ||||
|                 while(idx < files_array_size(model->files)) { | ||||
|                     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; | ||||
|                         break; | ||||
|                     } | ||||
|                     ++idx; | ||||
|                 } | ||||
|                 return false; | ||||
|             }); | ||||
|             }, | ||||
|             false); | ||||
| 
 | ||||
|         archive_update_offset(browser); | ||||
|     } | ||||
| @ -161,10 +163,10 @@ size_t archive_file_get_array_size(ArchiveBrowserView* browser) { | ||||
| 
 | ||||
|     uint16_t size = 0; | ||||
|     with_view_model( | ||||
|         browser->view, (ArchiveBrowserViewModel * model) { | ||||
|             size = files_array_size(model->files); | ||||
|             return false; | ||||
|         }); | ||||
|         browser->view, | ||||
|         ArchiveBrowserViewModel * model, | ||||
|         { size = files_array_size(model->files); }, | ||||
|         false); | ||||
|     return size; | ||||
| } | ||||
| 
 | ||||
| @ -172,11 +174,13 @@ void archive_set_item_count(ArchiveBrowserView* browser, uint32_t count) { | ||||
|     furi_assert(browser); | ||||
| 
 | ||||
|     with_view_model( | ||||
|         browser->view, (ArchiveBrowserViewModel * model) { | ||||
|         browser->view, | ||||
|         ArchiveBrowserViewModel * model, | ||||
|         { | ||||
|             model->item_cnt = count; | ||||
|             model->item_idx = CLAMP(model->item_idx, (int32_t)model->item_cnt - 1, 0); | ||||
|             return false; | ||||
|         }); | ||||
|         }, | ||||
|         false); | ||||
|     archive_update_offset(browser); | ||||
| } | ||||
| 
 | ||||
| @ -185,7 +189,9 @@ void archive_file_array_rm_selected(ArchiveBrowserView* browser) { | ||||
|     uint32_t items_cnt = 0; | ||||
| 
 | ||||
|     with_view_model( | ||||
|         browser->view, (ArchiveBrowserViewModel * model) { | ||||
|         browser->view, | ||||
|         ArchiveBrowserViewModel * model, | ||||
|         { | ||||
|             files_array_remove_v( | ||||
|                 model->files, | ||||
|                 model->item_idx - model->array_offset, | ||||
| @ -193,8 +199,8 @@ void archive_file_array_rm_selected(ArchiveBrowserView* browser) { | ||||
|             model->item_cnt--; | ||||
|             model->item_idx = CLAMP(model->item_idx, (int32_t)model->item_cnt - 1, 0); | ||||
|             items_cnt = model->item_cnt; | ||||
|             return false; | ||||
|         }); | ||||
|         }, | ||||
|         false); | ||||
| 
 | ||||
|     if((items_cnt == 0) && (archive_is_home(browser))) { | ||||
|         archive_switch_tab(browser, TAB_RIGHT); | ||||
| @ -207,7 +213,9 @@ void archive_file_array_swap(ArchiveBrowserView* browser, int8_t dir) { | ||||
|     furi_assert(browser); | ||||
| 
 | ||||
|     with_view_model( | ||||
|         browser->view, (ArchiveBrowserViewModel * model) { | ||||
|         browser->view, | ||||
|         ArchiveBrowserViewModel * model, | ||||
|         { | ||||
|             ArchiveFile_t temp; | ||||
|             size_t array_size = files_array_size(model->files) - 1; | ||||
|             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 { | ||||
|                 files_array_swap_at(model->files, model->item_idx, swap_idx); | ||||
|             } | ||||
|             return false; | ||||
|         }); | ||||
|         }, | ||||
|         false); | ||||
| } | ||||
| 
 | ||||
| void archive_file_array_rm_all(ArchiveBrowserView* browser) { | ||||
|     furi_assert(browser); | ||||
| 
 | ||||
|     with_view_model( | ||||
|         browser->view, (ArchiveBrowserViewModel * model) { | ||||
|             files_array_reset(model->files); | ||||
|             return false; | ||||
|         }); | ||||
|         browser->view, | ||||
|         ArchiveBrowserViewModel * model, | ||||
|         { files_array_reset(model->files); }, | ||||
|         false); | ||||
| } | ||||
| 
 | ||||
| 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; | ||||
| 
 | ||||
|     with_view_model( | ||||
|         browser->view, (ArchiveBrowserViewModel * model) { | ||||
|         browser->view, | ||||
|         ArchiveBrowserViewModel * model, | ||||
|         { | ||||
|             if(model->item_cnt > FILE_LIST_BUF_LEN) { | ||||
|                 if(dir < 0) { | ||||
|                     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; | ||||
|                 } | ||||
|             } | ||||
|             return false; | ||||
|         }); | ||||
|         }, | ||||
|         false); | ||||
| 
 | ||||
|     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; | ||||
|     with_view_model( | ||||
|         browser->view, (ArchiveBrowserViewModel * model) { | ||||
|         browser->view, | ||||
|         ArchiveBrowserViewModel * model, | ||||
|         { | ||||
|             selected = files_array_size(model->files) ? | ||||
|                            files_array_get(model->files, model->item_idx - model->array_offset) : | ||||
|                            NULL; | ||||
|             return false; | ||||
|         }); | ||||
|         }, | ||||
|         false); | ||||
|     return selected; | ||||
| } | ||||
| 
 | ||||
| @ -287,11 +299,13 @@ ArchiveFile_t* archive_get_file_at(ArchiveBrowserView* browser, size_t idx) { | ||||
|     ArchiveFile_t* selected = NULL; | ||||
| 
 | ||||
|     with_view_model( | ||||
|         browser->view, (ArchiveBrowserViewModel * model) { | ||||
|         browser->view, | ||||
|         ArchiveBrowserViewModel * model, | ||||
|         { | ||||
|             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; | ||||
|             return false; | ||||
|         }); | ||||
|         }, | ||||
|         false); | ||||
|     return selected; | ||||
| } | ||||
| 
 | ||||
| @ -300,10 +314,7 @@ ArchiveTabEnum archive_get_tab(ArchiveBrowserView* browser) { | ||||
| 
 | ||||
|     ArchiveTabEnum tab_id = 0; | ||||
|     with_view_model( | ||||
|         browser->view, (ArchiveBrowserViewModel * model) { | ||||
|             tab_id = model->tab_idx; | ||||
|             return false; | ||||
|         }); | ||||
|         browser->view, ArchiveBrowserViewModel * model, { tab_id = model->tab_idx; }, false); | ||||
|     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)); | ||||
|     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) { | ||||
|     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) { | ||||
|     furi_assert(browser); | ||||
| 
 | ||||
|     with_view_model( | ||||
|         browser->view, (ArchiveBrowserViewModel * model) { | ||||
|             model->tab_idx = tab; | ||||
|             return false; | ||||
|         }); | ||||
|         browser->view, ArchiveBrowserViewModel * model, { model->tab_idx = tab; }, false); | ||||
| } | ||||
| 
 | ||||
| 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_init(&item); | ||||
|     string_set_str(item.path, name); | ||||
|     furi_string_set(item.path, name); | ||||
|     archive_set_file_type(&item, name, false, true); | ||||
| 
 | ||||
|     with_view_model( | ||||
|         browser->view, (ArchiveBrowserViewModel * model) { | ||||
|         browser->view, | ||||
|         ArchiveBrowserViewModel * model, | ||||
|         { | ||||
|             files_array_push_back(model->files, item); | ||||
|             model->item_cnt = files_array_size(model->files); | ||||
|             return false; | ||||
|         }); | ||||
|         }, | ||||
|         false); | ||||
|     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) { | ||||
|     furi_assert(browser); | ||||
|     furi_assert(name); | ||||
| 
 | ||||
|     ArchiveFile_t 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( | ||||
|         browser->view, (ArchiveBrowserViewModel * model) { | ||||
|             files_array_push_back(model->files, item); | ||||
|             return false; | ||||
|         }); | ||||
|         browser->view, | ||||
|         ArchiveBrowserViewModel * model, | ||||
|         { files_array_push_back(model->files, item); }, | ||||
|         false); | ||||
|     ArchiveFile_t_clear(&item); | ||||
| } | ||||
| 
 | ||||
| void archive_show_file_menu(ArchiveBrowserView* browser, bool show) { | ||||
|     furi_assert(browser); | ||||
|     with_view_model( | ||||
|         browser->view, (ArchiveBrowserViewModel * model) { | ||||
|         browser->view, | ||||
|         ArchiveBrowserViewModel * model, | ||||
|         { | ||||
|             if(show) { | ||||
|                 if(archive_is_item_in_array(model, model->item_idx)) { | ||||
|                     model->menu = true; | ||||
|                     model->menu_idx = 0; | ||||
|                     ArchiveFile_t* selected = | ||||
|                         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 { | ||||
|                 model->menu = false; | ||||
|                 model->menu_idx = 0; | ||||
|             } | ||||
| 
 | ||||
|             return true; | ||||
|         }); | ||||
|         }, | ||||
|         true); | ||||
| } | ||||
| 
 | ||||
| void archive_favorites_move_mode(ArchiveBrowserView* browser, bool active) { | ||||
|     furi_assert(browser); | ||||
| 
 | ||||
|     with_view_model( | ||||
|         browser->view, (ArchiveBrowserViewModel * model) { | ||||
|             model->move_fav = active; | ||||
|             return true; | ||||
|         }); | ||||
|         browser->view, ArchiveBrowserViewModel * model, { model->move_fav = active; }, true); | ||||
| } | ||||
| 
 | ||||
| static bool archive_is_dir_exists(string_t path) { | ||||
|     if(string_equal_str_p(path, STORAGE_ANY_PATH_PREFIX)) { | ||||
| static bool archive_is_dir_exists(FuriString* path) { | ||||
|     if(furi_string_equal(path, STORAGE_ANY_PATH_PREFIX)) { | ||||
|         return true; | ||||
|     } | ||||
|     bool state = false; | ||||
|     FileInfo file_info; | ||||
|     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) { | ||||
|             state = true; | ||||
|         } | ||||
| @ -431,16 +456,16 @@ void archive_switch_tab(ArchiveBrowserView* browser, InputKey key) { | ||||
|     browser->is_root = true; | ||||
|     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; | ||||
|     if(tab == ArchiveTabFavorites) { | ||||
|         if(archive_favorites_count(browser) > 0) { | ||||
|             tab_empty = false; | ||||
|         } | ||||
|     } else if(string_start_with_str_p(browser->path, "/app:")) { | ||||
|         char* app_name = strchr(string_get_cstr(browser->path), ':'); | ||||
|     } else if(furi_string_start_with_str(browser->path, "/app:")) { | ||||
|         char* app_name = strchr(furi_string_get_cstr(browser->path), ':'); | ||||
|         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; | ||||
|             } | ||||
|         } | ||||
| @ -458,29 +483,28 @@ void archive_switch_tab(ArchiveBrowserView* browser, InputKey key) { | ||||
|         archive_switch_tab(browser, key); | ||||
|     } else { | ||||
|         with_view_model( | ||||
|             browser->view, (ArchiveBrowserViewModel * model) { | ||||
|             browser->view, | ||||
|             ArchiveBrowserViewModel * model, | ||||
|             { | ||||
|                 model->item_idx = 0; | ||||
|                 model->array_offset = 0; | ||||
|                 return false; | ||||
|             }); | ||||
|         archive_get_items(browser, string_get_cstr(browser->path)); | ||||
|             }, | ||||
|             false); | ||||
|         archive_get_items(browser, furi_string_get_cstr(browser->path)); | ||||
|         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(path); | ||||
| 
 | ||||
|     int32_t idx_temp = 0; | ||||
| 
 | ||||
|     with_view_model( | ||||
|         browser->view, (ArchiveBrowserViewModel * model) { | ||||
|             idx_temp = model->item_idx; | ||||
|             return false; | ||||
|         }); | ||||
|         browser->view, ArchiveBrowserViewModel * model, { idx_temp = model->item_idx; }, false); | ||||
| 
 | ||||
|     string_set(browser->path, path); | ||||
|     furi_string_set(browser->path, path); | ||||
|     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; | ||||
| 
 | ||||
|     with_view_model( | ||||
|         browser->view, (ArchiveBrowserViewModel * model) { | ||||
|             idx_temp = model->item_idx; | ||||
|             return false; | ||||
|         }); | ||||
|         browser->view, ArchiveBrowserViewModel * model, { idx_temp = model->item_idx; }, false); | ||||
|     file_browser_worker_folder_refresh(browser->worker, idx_temp); | ||||
| } | ||||
|  | ||||
| @ -16,6 +16,7 @@ static const char* tab_default_paths[] = { | ||||
|     [ArchiveTabInfrared] = ANY_PATH("infrared"), | ||||
|     [ArchiveTabBadUsb] = ANY_PATH("badusb"), | ||||
|     [ArchiveTabU2f] = "/app:u2f", | ||||
|     [ArchiveTabApplications] = ANY_PATH("apps"), | ||||
|     [ArchiveTabBrowser] = STORAGE_ANY_PATH_PREFIX, | ||||
| }; | ||||
| 
 | ||||
| @ -27,6 +28,7 @@ static const char* known_ext[] = { | ||||
|     [ArchiveFileTypeInfrared] = ".ir", | ||||
|     [ArchiveFileTypeBadUsb] = ".txt", | ||||
|     [ArchiveFileTypeU2f] = "?", | ||||
|     [ArchiveFileTypeApplication] = ".fap", | ||||
|     [ArchiveFileTypeUpdateManifest] = ".fuf", | ||||
|     [ArchiveFileTypeFolder] = "?", | ||||
|     [ArchiveFileTypeUnknown] = "*", | ||||
| @ -41,6 +43,7 @@ static const ArchiveFileTypeEnum known_type[] = { | ||||
|     [ArchiveTabInfrared] = ArchiveFileTypeInfrared, | ||||
|     [ArchiveTabBadUsb] = ArchiveFileTypeBadUsb, | ||||
|     [ArchiveTabU2f] = ArchiveFileTypeU2f, | ||||
|     [ArchiveTabApplications] = ArchiveFileTypeApplication, | ||||
|     [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_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_refresh_dir(ArchiveBrowserView* browser); | ||||
|  | ||||
| @ -6,8 +6,8 @@ | ||||
| 
 | ||||
| #define ARCHIVE_FAV_FILE_BUF_LEN 32 | ||||
| 
 | ||||
| static bool archive_favorites_read_line(File* file, string_t str_result) { | ||||
|     string_reset(str_result); | ||||
| static bool archive_favorites_read_line(File* file, FuriString* str_result) { | ||||
|     furi_string_reset(str_result); | ||||
|     uint8_t buffer[ARCHIVE_FAV_FILE_BUF_LEN]; | ||||
|     bool result = false; | ||||
| 
 | ||||
| @ -34,7 +34,7 @@ static bool archive_favorites_read_line(File* file, string_t str_result) { | ||||
|                 result = true; | ||||
|                 break; | ||||
|             } 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); | ||||
|     File* file = storage_file_alloc(fs_api); | ||||
| 
 | ||||
|     string_t buffer; | ||||
|     string_init(buffer); | ||||
|     FuriString* buffer; | ||||
|     buffer = furi_string_alloc(); | ||||
| 
 | ||||
|     bool result = storage_file_open(file, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING); | ||||
|     uint16_t lines = 0; | ||||
| @ -63,7 +63,7 @@ uint16_t archive_favorites_count(void* context) { | ||||
|             if(!archive_favorites_read_line(file, buffer)) { | ||||
|                 break; | ||||
|             } | ||||
|             if(!string_size(buffer)) { | ||||
|             if(!furi_string_size(buffer)) { | ||||
|                 continue; // Skip empty lines
 | ||||
|             } | ||||
|             ++lines; | ||||
| @ -72,7 +72,7 @@ uint16_t archive_favorites_count(void* context) { | ||||
| 
 | ||||
|     storage_file_close(file); | ||||
| 
 | ||||
|     string_clear(buffer); | ||||
|     furi_string_free(buffer); | ||||
|     storage_file_free(file); | ||||
|     furi_record_close(RECORD_STORAGE); | ||||
| 
 | ||||
| @ -80,8 +80,8 @@ uint16_t archive_favorites_count(void* context) { | ||||
| } | ||||
| 
 | ||||
| static bool archive_favourites_rescan() { | ||||
|     string_t buffer; | ||||
|     string_init(buffer); | ||||
|     FuriString* buffer; | ||||
|     buffer = furi_string_alloc(); | ||||
|     Storage* storage = furi_record_open(RECORD_STORAGE); | ||||
|     File* file = storage_file_alloc(storage); | ||||
| 
 | ||||
| @ -91,23 +91,25 @@ static bool archive_favourites_rescan() { | ||||
|             if(!archive_favorites_read_line(file, buffer)) { | ||||
|                 break; | ||||
|             } | ||||
|             if(!string_size(buffer)) { | ||||
|             if(!furi_string_size(buffer)) { | ||||
|                 continue; | ||||
|             } | ||||
| 
 | ||||
|             if(string_search(buffer, "/app:") == 0) { | ||||
|                 if(archive_app_is_available(NULL, string_get_cstr(buffer))) { | ||||
|                     archive_file_append(ARCHIVE_FAV_TEMP_PATH, "%s\n", string_get_cstr(buffer)); | ||||
|             if(furi_string_search(buffer, "/app:") == 0) { | ||||
|                 if(archive_app_is_available(NULL, furi_string_get_cstr(buffer))) { | ||||
|                     archive_file_append( | ||||
|                         ARCHIVE_FAV_TEMP_PATH, "%s\n", furi_string_get_cstr(buffer)); | ||||
|                 } | ||||
|             } else { | ||||
|                 if(storage_file_exists(storage, string_get_cstr(buffer))) { | ||||
|                     archive_file_append(ARCHIVE_FAV_TEMP_PATH, "%s\n", string_get_cstr(buffer)); | ||||
|                 if(storage_file_exists(storage, furi_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_common_remove(storage, ARCHIVE_FAV_PATH); | ||||
| @ -127,9 +129,9 @@ bool archive_favorites_read(void* context) { | ||||
|     Storage* storage = furi_record_open(RECORD_STORAGE); | ||||
|     File* file = storage_file_alloc(storage); | ||||
| 
 | ||||
|     string_t buffer; | ||||
|     FuriString* buffer; | ||||
|     FileInfo file_info; | ||||
|     string_init(buffer); | ||||
|     buffer = furi_string_alloc(); | ||||
| 
 | ||||
|     bool need_refresh = false; | ||||
|     uint16_t file_count = 0; | ||||
| @ -143,33 +145,33 @@ bool archive_favorites_read(void* context) { | ||||
|             if(!archive_favorites_read_line(file, buffer)) { | ||||
|                 break; | ||||
|             } | ||||
|             if(!string_size(buffer)) { | ||||
|             if(!furi_string_size(buffer)) { | ||||
|                 continue; | ||||
|             } | ||||
| 
 | ||||
|             if(string_search(buffer, "/app:") == 0) { | ||||
|                 if(archive_app_is_available(browser, string_get_cstr(buffer))) { | ||||
|                     archive_add_app_item(browser, string_get_cstr(buffer)); | ||||
|             if(furi_string_search(buffer, "/app:") == 0) { | ||||
|                 if(archive_app_is_available(browser, furi_string_get_cstr(buffer))) { | ||||
|                     archive_add_app_item(browser, furi_string_get_cstr(buffer)); | ||||
|                     file_count++; | ||||
|                 } else { | ||||
|                     need_refresh = true; | ||||
|                 } | ||||
|             } else { | ||||
|                 if(storage_file_exists(storage, string_get_cstr(buffer))) { | ||||
|                     storage_common_stat(storage, string_get_cstr(buffer), &file_info); | ||||
|                 if(storage_file_exists(storage, furi_string_get_cstr(buffer))) { | ||||
|                     storage_common_stat(storage, furi_string_get_cstr(buffer), &file_info); | ||||
|                     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++; | ||||
|                 } else { | ||||
|                     need_refresh = true; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             string_reset(buffer); | ||||
|             furi_string_reset(buffer); | ||||
|         } | ||||
|     } | ||||
|     storage_file_close(file); | ||||
|     string_clear(buffer); | ||||
|     furi_string_free(buffer); | ||||
|     storage_file_free(file); | ||||
|     furi_record_close(RECORD_STORAGE); | ||||
| 
 | ||||
| @ -183,14 +185,14 @@ bool archive_favorites_read(void* context) { | ||||
| } | ||||
| 
 | ||||
| bool archive_favorites_delete(const char* format, ...) { | ||||
|     string_t buffer; | ||||
|     string_t filename; | ||||
|     FuriString* buffer; | ||||
|     FuriString* filename; | ||||
|     va_list args; | ||||
|     va_start(args, format); | ||||
|     string_init_vprintf(filename, format, args); | ||||
|     filename = furi_string_alloc_vprintf(format, args); | ||||
|     va_end(args); | ||||
| 
 | ||||
|     string_init(buffer); | ||||
|     buffer = furi_string_alloc(); | ||||
|     Storage* fs_api = furi_record_open(RECORD_STORAGE); | ||||
|     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)) { | ||||
|                 break; | ||||
|             } | ||||
|             if(!string_size(buffer)) { | ||||
|             if(!furi_string_size(buffer)) { | ||||
|                 continue; | ||||
|             } | ||||
| 
 | ||||
|             if(string_search(buffer, filename)) { | ||||
|                 archive_file_append(ARCHIVE_FAV_TEMP_PATH, "%s\n", string_get_cstr(buffer)); | ||||
|             if(furi_string_search(buffer, filename)) { | ||||
|                 archive_file_append(ARCHIVE_FAV_TEMP_PATH, "%s\n", furi_string_get_cstr(buffer)); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     string_clear(buffer); | ||||
|     string_clear(filename); | ||||
|     furi_string_free(buffer); | ||||
|     furi_string_free(filename); | ||||
| 
 | ||||
|     storage_file_close(file); | ||||
|     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, ...) { | ||||
|     string_t buffer; | ||||
|     string_t filename; | ||||
|     FuriString* buffer; | ||||
|     FuriString* filename; | ||||
|     va_list args; | ||||
|     va_start(args, format); | ||||
|     string_init_vprintf(filename, format, args); | ||||
|     filename = furi_string_alloc_vprintf(format, args); | ||||
|     va_end(args); | ||||
| 
 | ||||
|     string_init(buffer); | ||||
|     buffer = furi_string_alloc(); | ||||
|     Storage* fs_api = furi_record_open(RECORD_STORAGE); | ||||
|     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)) { | ||||
|                 break; | ||||
|             } | ||||
|             if(!string_size(buffer)) { | ||||
|             if(!furi_string_size(buffer)) { | ||||
|                 continue; | ||||
|             } | ||||
|             if(!string_search(buffer, filename)) { | ||||
|             if(!furi_string_search(buffer, filename)) { | ||||
|                 found = true; | ||||
|                 break; | ||||
|             } | ||||
| @ -256,8 +258,8 @@ bool archive_is_favorite(const char* format, ...) { | ||||
|     } | ||||
| 
 | ||||
|     storage_file_close(file); | ||||
|     string_clear(buffer); | ||||
|     string_clear(filename); | ||||
|     furi_string_free(buffer); | ||||
|     furi_string_free(filename); | ||||
|     storage_file_free(file); | ||||
|     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); | ||||
|     File* file = storage_file_alloc(fs_api); | ||||
| 
 | ||||
|     string_t path; | ||||
|     string_t buffer; | ||||
|     FuriString* path; | ||||
|     FuriString* buffer; | ||||
| 
 | ||||
|     string_init(buffer); | ||||
|     string_init(path); | ||||
|     buffer = furi_string_alloc(); | ||||
|     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); | ||||
| 
 | ||||
|     if(result) { | ||||
| @ -285,19 +287,19 @@ bool archive_favorites_rename(const char* src, const char* dst) { | ||||
|             if(!archive_favorites_read_line(file, buffer)) { | ||||
|                 break; | ||||
|             } | ||||
|             if(!string_size(buffer)) { | ||||
|             if(!furi_string_size(buffer)) { | ||||
|                 continue; | ||||
|             } | ||||
| 
 | ||||
|             archive_file_append( | ||||
|                 ARCHIVE_FAV_TEMP_PATH, | ||||
|                 "%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); | ||||
|     string_clear(path); | ||||
|     furi_string_free(buffer); | ||||
|     furi_string_free(path); | ||||
| 
 | ||||
|     storage_file_close(file); | ||||
|     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++) { | ||||
|         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); | ||||
|  | ||||
| @ -7,8 +7,8 @@ | ||||
| 
 | ||||
| uint16_t archive_favorites_count(void* context); | ||||
| bool archive_favorites_read(void* context); | ||||
| bool archive_favorites_delete(const char* format, ...); | ||||
| bool archive_is_favorite(const char* format, ...); | ||||
| bool archive_favorites_delete(const char* format, ...) _ATTRIBUTE((__format__(__printf__, 1, 2))); | ||||
| bool archive_is_favorite(const char* format, ...) _ATTRIBUTE((__format__(__printf__, 1, 2))); | ||||
| bool archive_favorites_rename(const char* src, const char* dst); | ||||
| void archive_add_to_favorites(const char* file_path); | ||||
| 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 { | ||||
|         for(size_t i = 0; i < COUNT_OF(known_ext); i++) { | ||||
|             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(string_search_str(file->path, archive_get_default_path(ArchiveTabBadUsb)) == | ||||
|                        0) { | ||||
|                     if(furi_string_search( | ||||
|                            file->path, archive_get_default_path(ArchiveTabBadUsb)) == 0) { | ||||
|                         file->type = i; | ||||
|                         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, ...) { | ||||
|     furi_assert(path); | ||||
| 
 | ||||
|     string_t string; | ||||
|     FuriString* string; | ||||
|     va_list args; | ||||
|     va_start(args, format); | ||||
|     string_init_vprintf(string, format, args); | ||||
|     string = furi_string_alloc_vprintf(format, args); | ||||
|     va_end(args); | ||||
| 
 | ||||
|     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); | ||||
| 
 | ||||
|     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); | ||||
| @ -77,35 +77,35 @@ void archive_file_append(const char* path, const char* format, ...) { | ||||
| void archive_delete_file(void* context, const char* format, ...) { | ||||
|     furi_assert(context); | ||||
| 
 | ||||
|     string_t filename; | ||||
|     FuriString* filename; | ||||
|     va_list args; | ||||
|     va_start(args, format); | ||||
|     string_init_vprintf(filename, format, args); | ||||
|     filename = furi_string_alloc_vprintf(format, args); | ||||
|     va_end(args); | ||||
| 
 | ||||
|     ArchiveBrowserView* browser = context; | ||||
|     Storage* fs_api = furi_record_open(RECORD_STORAGE); | ||||
| 
 | ||||
|     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; | ||||
| 
 | ||||
|     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 { | ||||
|         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); | ||||
| 
 | ||||
|     if(archive_is_favorite("%s", string_get_cstr(filename))) { | ||||
|         archive_favorites_delete("%s", string_get_cstr(filename)); | ||||
|     if(archive_is_favorite("%s", furi_string_get_cstr(filename))) { | ||||
|         archive_favorites_delete("%s", furi_string_get_cstr(filename)); | ||||
|     } | ||||
| 
 | ||||
|     if(res) { | ||||
|         archive_file_array_rm_selected(browser); | ||||
|     } | ||||
| 
 | ||||
|     string_clear(filename); | ||||
|     furi_string_free(filename); | ||||
| } | ||||
|  | ||||
| @ -1,9 +1,11 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <m-array.h> | ||||
| #include <m-string.h> | ||||
| #include <furi.h> | ||||
| #include <storage/storage.h> | ||||
| 
 | ||||
| #define FAP_MANIFEST_MAX_ICON_SIZE 32 | ||||
| 
 | ||||
| typedef enum { | ||||
|     ArchiveFileTypeIButton, | ||||
|     ArchiveFileTypeNFC, | ||||
| @ -13,41 +15,65 @@ typedef enum { | ||||
|     ArchiveFileTypeBadUsb, | ||||
|     ArchiveFileTypeU2f, | ||||
|     ArchiveFileTypeUpdateManifest, | ||||
|     ArchiveFileTypeApplication, | ||||
|     ArchiveFileTypeFolder, | ||||
|     ArchiveFileTypeUnknown, | ||||
|     ArchiveFileTypeLoading, | ||||
| } ArchiveFileTypeEnum; | ||||
| 
 | ||||
| typedef struct { | ||||
|     string_t path; | ||||
|     FuriString* path; | ||||
|     ArchiveFileTypeEnum type; | ||||
|     uint8_t* custom_icon_data; | ||||
|     FuriString* custom_name; | ||||
|     bool fav; | ||||
|     bool is_app; | ||||
| } ArchiveFile_t; | ||||
| 
 | ||||
| static void ArchiveFile_t_init(ArchiveFile_t* obj) { | ||||
|     obj->path = furi_string_alloc(); | ||||
|     obj->type = ArchiveFileTypeUnknown; | ||||
|     obj->is_app = false; | ||||
|     obj->custom_icon_data = NULL; | ||||
|     obj->custom_name = furi_string_alloc(); | ||||
|     obj->fav = false; | ||||
|     string_init(obj->path); | ||||
|     obj->is_app = false; | ||||
| } | ||||
| 
 | ||||
| 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->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; | ||||
|     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) { | ||||
|     furi_string_set(obj->path, src->path); | ||||
|     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; | ||||
|     string_set(obj->path, src->path); | ||||
|     obj->is_app = src->is_app; | ||||
| } | ||||
| 
 | ||||
| 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( | ||||
| @ -60,5 +86,7 @@ ARRAY_DEF( | ||||
| 
 | ||||
| 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); | ||||
| void archive_file_append(const char* path, const char* format, ...); | ||||
| void archive_delete_file(void* context, const char* format, ...); | ||||
| void archive_file_append(const char* path, 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", | ||||
|     [ArchiveFileTypeU2f] = "U2F", | ||||
|     [ArchiveFileTypeUpdateManifest] = "UpdaterApp", | ||||
|     [ArchiveFileTypeApplication] = "Applications", | ||||
| }; | ||||
| 
 | ||||
| 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; | ||||
|     if(selected->is_app) { | ||||
|         char* param = strrchr(string_get_cstr(selected->path), '/'); | ||||
|         char* param = strrchr(furi_string_get_cstr(selected->path), '/'); | ||||
|         if(param != NULL) { | ||||
|             param++; | ||||
|         } | ||||
|         status = loader_start(loader, flipper_app_name[selected->type], param); | ||||
|     } else { | ||||
|         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) { | ||||
| @ -159,13 +160,13 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) { | ||||
|             consumed = true; | ||||
|             break; | ||||
|         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_favorites_move_mode(archive->browser, true); | ||||
|             consumed = true; | ||||
|             break; | ||||
|         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); | ||||
|             consumed = true; | ||||
|             break; | ||||
|  | ||||
| @ -4,7 +4,6 @@ | ||||
| #include "../helpers/archive_apps.h" | ||||
| #include "../helpers/archive_browser.h" | ||||
| #include "toolbox/path.h" | ||||
| #include "m-string.h" | ||||
| 
 | ||||
| #define SCENE_DELETE_CUSTOM_EVENT (0UL) | ||||
| #define MAX_TEXT_INPUT_LEN 22 | ||||
| @ -26,18 +25,18 @@ void archive_scene_delete_on_enter(void* context) { | ||||
|     widget_add_button_element( | ||||
|         app->widget, GuiButtonTypeRight, "Delete", archive_scene_delete_widget_callback, app); | ||||
| 
 | ||||
|     string_t filename; | ||||
|     string_init(filename); | ||||
|     FuriString* filename; | ||||
|     filename = furi_string_alloc(); | ||||
| 
 | ||||
|     ArchiveFile_t* current = archive_get_current_file(app->browser); | ||||
|     path_extract_filename(current->path, filename, false); | ||||
| 
 | ||||
|     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( | ||||
|         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); | ||||
| } | ||||
|  | ||||
| @ -19,10 +19,10 @@ void archive_scene_rename_on_enter(void* context) { | ||||
|     TextInput* text_input = archive->text_input; | ||||
|     ArchiveFile_t* current = archive_get_current_file(archive->browser); | ||||
| 
 | ||||
|     string_t filename; | ||||
|     string_init(filename); | ||||
|     FuriString* filename; | ||||
|     filename = furi_string_alloc(); | ||||
|     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); | ||||
| 
 | ||||
| @ -37,10 +37,10 @@ void archive_scene_rename_on_enter(void* context) { | ||||
|         false); | ||||
| 
 | ||||
|     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); | ||||
| 
 | ||||
|     string_clear(filename); | ||||
|     furi_string_free(filename); | ||||
| 
 | ||||
|     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); | ||||
|             ArchiveFile_t* file = archive_get_current_file(archive->browser); | ||||
| 
 | ||||
|             string_t path_dst; | ||||
|             string_init(path_dst); | ||||
|             FuriString* path_dst; | ||||
|             path_dst = furi_string_alloc(); | ||||
|             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); | ||||
| 
 | ||||
|             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); | ||||
|             consumed = true; | ||||
|  | ||||
| @ -14,6 +14,7 @@ static const char* ArchiveTabNames[] = { | ||||
|     [ArchiveTabInfrared] = "Infrared", | ||||
|     [ArchiveTabBadUsb] = "Bad USB", | ||||
|     [ArchiveTabU2f] = "U2F", | ||||
|     [ArchiveTabApplications] = "Apps", | ||||
|     [ArchiveTabBrowser] = "Browser", | ||||
| }; | ||||
| 
 | ||||
| @ -29,6 +30,7 @@ static const Icon* ArchiveItemIcons[] = { | ||||
|     [ArchiveFileTypeFolder] = &I_dir_10px, | ||||
|     [ArchiveFileTypeUnknown] = &I_unknown_10px, | ||||
|     [ArchiveFileTypeLoading] = &I_loading_10px, | ||||
|     [ArchiveFileTypeApplication] = &I_unknown_10px, | ||||
| }; | ||||
| 
 | ||||
| void archive_browser_set_callback( | ||||
| @ -47,35 +49,35 @@ static void render_item_menu(Canvas* canvas, ArchiveBrowserViewModel* model) { | ||||
|     canvas_set_color(canvas, ColorBlack); | ||||
|     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"); | ||||
|     string_init_set_str(menu[1], "Pin"); | ||||
|     string_init_set_str(menu[2], "Rename"); | ||||
|     string_init_set_str(menu[3], "Delete"); | ||||
|     menu[0] = furi_string_alloc_set("Run in app"); | ||||
|     menu[1] = furi_string_alloc_set("Pin"); | ||||
|     menu[2] = furi_string_alloc_set("Rename"); | ||||
|     menu[3] = furi_string_alloc_set("Delete"); | ||||
| 
 | ||||
|     ArchiveFile_t* selected = files_array_get(model->files, model->item_idx - model->array_offset); | ||||
| 
 | ||||
|     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)) { | ||||
|         string_set_str(menu[0], "---"); | ||||
|         string_set_str(menu[1], "---"); | ||||
|         string_set_str(menu[2], "---"); | ||||
|         furi_string_set(menu[0], "---"); | ||||
|         furi_string_set(menu[1], "---"); | ||||
|         furi_string_set(menu[2], "---"); | ||||
|     } else { | ||||
|         if(model->tab_idx == ArchiveTabFavorites) { | ||||
|             string_set_str(menu[2], "Move"); | ||||
|             string_set_str(menu[3], "---"); | ||||
|             furi_string_set(menu[2], "Move"); | ||||
|             furi_string_set(menu[3], "---"); | ||||
|         } else if(selected->is_app) { | ||||
|             string_set_str(menu[2], "---"); | ||||
|             furi_string_set(menu[2], "---"); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     for(size_t i = 0; i < MENU_ITEMS; i++) { | ||||
|         canvas_draw_str(canvas, 82, 27 + i * 11, string_get_cstr(menu[i])); | ||||
|         string_clear(menu[i]); | ||||
|         canvas_draw_str(canvas, 82, 27 + i * 11, furi_string_get_cstr(menu[i])); | ||||
|         furi_string_free(menu[i]); | ||||
|     } | ||||
| 
 | ||||
|     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; | ||||
| 
 | ||||
|     for(uint32_t i = 0; i < MIN(model->item_cnt, MENU_ITEMS); ++i) { | ||||
|         string_t str_buf; | ||||
|         string_init(str_buf); | ||||
|         FuriString* str_buf; | ||||
|         str_buf = furi_string_alloc(); | ||||
|         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; | ||||
| 
 | ||||
|         ArchiveFileTypeEnum file_type = ArchiveFileTypeLoading; | ||||
|         uint8_t* custom_icon_data = NULL; | ||||
| 
 | ||||
|         if(archive_is_item_in_array(model, idx)) { | ||||
|             ArchiveFile_t* file = files_array_get( | ||||
|                 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; | ||||
|             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 { | ||||
|             string_set_str(str_buf, "---"); | ||||
|             furi_string_set(str_buf, "---"); | ||||
|         } | ||||
| 
 | ||||
|         elements_string_fit_width( | ||||
| @ -143,10 +156,17 @@ static void draw_list(Canvas* canvas, ArchiveBrowserViewModel* model) { | ||||
|             canvas_set_color(canvas, ColorBlack); | ||||
|         } | ||||
| 
 | ||||
|         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, string_get_cstr(str_buf)); | ||||
|         if(custom_icon_data) { | ||||
|             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) { | ||||
| @ -243,33 +263,37 @@ static bool archive_view_input(InputEvent* event, void* context) { | ||||
|     bool in_menu; | ||||
|     bool move_fav_mode; | ||||
|     with_view_model( | ||||
|         browser->view, (ArchiveBrowserViewModel * model) { | ||||
|         browser->view, | ||||
|         ArchiveBrowserViewModel * model, | ||||
|         { | ||||
|             in_menu = model->menu; | ||||
|             move_fav_mode = model->move_fav; | ||||
|             return false; | ||||
|         }); | ||||
|         }, | ||||
|         false); | ||||
| 
 | ||||
|     if(in_menu) { | ||||
|         if(event->type == InputTypeShort) { | ||||
|             if(event->key == InputKeyUp || event->key == InputKeyDown) { | ||||
|                 with_view_model( | ||||
|                     browser->view, (ArchiveBrowserViewModel * model) { | ||||
|                     browser->view, | ||||
|                     ArchiveBrowserViewModel * model, | ||||
|                     { | ||||
|                         if(event->key == InputKeyUp) { | ||||
|                             model->menu_idx = ((model->menu_idx - 1) + MENU_ITEMS) % MENU_ITEMS; | ||||
|                         } else if(event->key == InputKeyDown) { | ||||
|                             model->menu_idx = (model->menu_idx + 1) % MENU_ITEMS; | ||||
|                         } | ||||
|                         return true; | ||||
|                     }); | ||||
|                     }, | ||||
|                     true); | ||||
|             } | ||||
| 
 | ||||
|             if(event->key == InputKeyOk) { | ||||
|                 uint8_t idx; | ||||
|                 with_view_model( | ||||
|                     browser->view, (ArchiveBrowserViewModel * model) { | ||||
|                         idx = model->menu_idx; | ||||
|                         return false; | ||||
|                     }); | ||||
|                     browser->view, | ||||
|                     ArchiveBrowserViewModel * model, | ||||
|                     { idx = model->menu_idx; }, | ||||
|                     false); | ||||
|                 browser->callback(file_menu_actions[idx], browser->context); | ||||
|             } else if(event->key == InputKeyBack) { | ||||
|                 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) && | ||||
|            (event->type == InputTypeShort || event->type == InputTypeRepeat)) { | ||||
|             with_view_model( | ||||
|                 browser->view, (ArchiveBrowserViewModel * model) { | ||||
|                 browser->view, | ||||
|                 ArchiveBrowserViewModel * model, | ||||
|                 { | ||||
|                     if(event->key == InputKeyUp) { | ||||
|                         model->item_idx = | ||||
|                             ((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); | ||||
|                         } | ||||
|                     } | ||||
| 
 | ||||
|                     return true; | ||||
|                 }); | ||||
|                 }, | ||||
|                 true); | ||||
|             archive_update_offset(browser); | ||||
|         } | ||||
| 
 | ||||
| @ -361,14 +386,16 @@ ArchiveBrowserView* browser_alloc() { | ||||
|     view_set_draw_callback(browser->view, archive_view_render); | ||||
|     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( | ||||
|         browser->view, (ArchiveBrowserViewModel * model) { | ||||
|         browser->view, | ||||
|         ArchiveBrowserViewModel * model, | ||||
|         { | ||||
|             files_array_init(model->files); | ||||
|             model->tab_idx = TAB_DEFAULT; | ||||
|             return true; | ||||
|         }); | ||||
|         }, | ||||
|         true); | ||||
| 
 | ||||
|     return browser; | ||||
| } | ||||
| @ -381,12 +408,12 @@ void browser_free(ArchiveBrowserView* browser) { | ||||
|     } | ||||
| 
 | ||||
|     with_view_model( | ||||
|         browser->view, (ArchiveBrowserViewModel * model) { | ||||
|             files_array_clear(model->files); | ||||
|             return false; | ||||
|         }); | ||||
|         browser->view, | ||||
|         ArchiveBrowserViewModel * model, | ||||
|         { files_array_clear(model->files); }, | ||||
|         false); | ||||
| 
 | ||||
|     string_clear(browser->path); | ||||
|     furi_string_free(browser->path); | ||||
| 
 | ||||
|     view_free(browser->view); | ||||
|     free(browser); | ||||
|  | ||||
| @ -26,6 +26,7 @@ typedef enum { | ||||
|     ArchiveTabIButton, | ||||
|     ArchiveTabBadUsb, | ||||
|     ArchiveTabU2f, | ||||
|     ArchiveTabApplications, | ||||
|     ArchiveTabBrowser, | ||||
|     ArchiveTabTotal, | ||||
| } ArchiveTabEnum; | ||||
| @ -77,7 +78,7 @@ struct ArchiveBrowserView { | ||||
|     bool worker_running; | ||||
|     ArchiveBrowserViewCallback callback; | ||||
|     void* context; | ||||
|     string_t path; | ||||
|     FuriString* path; | ||||
|     InputKey last_tab_switch_dir; | ||||
|     bool is_root; | ||||
| }; | ||||
|  | ||||
| @ -1,5 +1,4 @@ | ||||
| #include "bad_usb_app_i.h" | ||||
| #include "m-string.h" | ||||
| #include <furi.h> | ||||
| #include <furi_hal.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* app = malloc(sizeof(BadUsbApp)); | ||||
| 
 | ||||
|     string_init(app->file_path); | ||||
|     app->file_path = furi_string_alloc(); | ||||
| 
 | ||||
|     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); | ||||
| @ -64,10 +63,10 @@ BadUsbApp* bad_usb_app_alloc(char* arg) { | ||||
|         app->error = BadUsbAppErrorCloseRpc; | ||||
|         scene_manager_next_scene(app->scene_manager, BadUsbSceneError); | ||||
|     } else { | ||||
|         if(!string_empty_p(app->file_path)) { | ||||
|         if(!furi_string_empty(app->file_path)) { | ||||
|             scene_manager_next_scene(app->scene_manager, BadUsbSceneWork); | ||||
|         } 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); | ||||
|         } | ||||
|     } | ||||
| @ -95,7 +94,7 @@ void bad_usb_app_free(BadUsbApp* app) { | ||||
|     furi_record_close(RECORD_NOTIFICATION); | ||||
|     furi_record_close(RECORD_DIALOGS); | ||||
| 
 | ||||
|     string_clear(app->file_path); | ||||
|     furi_string_free(app->file_path); | ||||
| 
 | ||||
|     free(app); | ||||
| } | ||||
|  | ||||
| @ -31,7 +31,7 @@ struct BadUsbApp { | ||||
|     Widget* widget; | ||||
| 
 | ||||
|     BadUsbAppError error; | ||||
|     string_t file_path; | ||||
|     FuriString* file_path; | ||||
|     BadUsb* bad_usb_view; | ||||
|     BadUsbScript* bad_usb_script; | ||||
| }; | ||||
|  | ||||
| @ -26,16 +26,16 @@ typedef enum { | ||||
| struct BadUsbScript { | ||||
|     FuriHalUsbHidConfig hid_cfg; | ||||
|     BadUsbState st; | ||||
|     string_t file_path; | ||||
|     FuriString* file_path; | ||||
|     uint32_t defdelay; | ||||
|     FuriThread* thread; | ||||
|     uint8_t file_buf[FILE_BUFFER_LEN + 1]; | ||||
|     uint8_t buf_start; | ||||
|     uint8_t buf_len; | ||||
|     bool file_end; | ||||
|     string_t line; | ||||
|     FuriString* line; | ||||
| 
 | ||||
|     string_t line_prev; | ||||
|     FuriString* line_prev; | ||||
|     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_2[] = {"DEFAULTDELAY "}; | ||||
| 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_altstr_1[] = {"ALTSTRING "}; | ||||
| @ -230,9 +231,10 @@ static uint16_t ducky_get_keycode(const char* param, bool accept_chars) { | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| static int32_t ducky_parse_line(BadUsbScript* bad_usb, string_t line) { | ||||
|     uint32_t line_len = string_size(line); | ||||
|     const char* line_tmp = string_get_cstr(line); | ||||
| static int32_t | ||||
|     ducky_parse_line(BadUsbScript* bad_usb, FuriString* line, char* error, size_t error_len) { | ||||
|     uint32_t line_len = furi_string_size(line); | ||||
|     const char* line_tmp = furi_string_get_cstr(line); | ||||
|     bool state = false; | ||||
| 
 | ||||
|     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)) { | ||||
|             return (int32_t)delay_val; | ||||
|         } | ||||
|         if(error != NULL) { | ||||
|             snprintf(error, error_len, "Invalid number %s", line_tmp); | ||||
|         } | ||||
|         return SCRIPT_STATE_ERROR; | ||||
|     } else if( | ||||
|         (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
 | ||||
|         line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; | ||||
|         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; | ||||
|     } else if(strncmp(line_tmp, ducky_cmd_string, strlen(ducky_cmd_string)) == 0) { | ||||
|         // STRING
 | ||||
|         line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; | ||||
|         state = ducky_string(line_tmp); | ||||
|         if(!state && error != NULL) { | ||||
|             snprintf(error, error_len, "Invalid string %s", line_tmp); | ||||
|         } | ||||
|         return (state) ? (0) : SCRIPT_STATE_ERROR; | ||||
|     } else if(strncmp(line_tmp, ducky_cmd_altchar, strlen(ducky_cmd_altchar)) == 0) { | ||||
|         // ALTCHAR
 | ||||
|         line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; | ||||
|         ducky_numlock_on(); | ||||
|         state = ducky_altchar(line_tmp); | ||||
|         if(!state && error != NULL) { | ||||
|             snprintf(error, error_len, "Invalid altchar %s", line_tmp); | ||||
|         } | ||||
|         return (state) ? (0) : SCRIPT_STATE_ERROR; | ||||
|     } else if( | ||||
|         (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]; | ||||
|         ducky_numlock_on(); | ||||
|         state = ducky_altstring(line_tmp); | ||||
|         if(!state && error != NULL) { | ||||
|             snprintf(error, error_len, "Invalid altstring %s", line_tmp); | ||||
|         } | ||||
|         return (state) ? (0) : SCRIPT_STATE_ERROR; | ||||
|     } else if(strncmp(line_tmp, ducky_cmd_repeat, strlen(ducky_cmd_repeat)) == 0) { | ||||
|         // REPEAT
 | ||||
|         line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; | ||||
|         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; | ||||
|     } 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 { | ||||
|         // Special keys + modifiers
 | ||||
|         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) { | ||||
|             // It's a modifier key
 | ||||
|             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); | ||||
|         return (0); | ||||
|     } | ||||
|     if(error != NULL) { | ||||
|         strncpy(error, "Unknown error", error_len); | ||||
|     } | ||||
|     return SCRIPT_STATE_ERROR; | ||||
| } | ||||
| 
 | ||||
| @ -323,7 +359,7 @@ static bool ducky_set_usb_id(BadUsbScript* bad_usb, const char* line) { | ||||
|         } | ||||
|         FURI_LOG_D( | ||||
|             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.pid, | ||||
|             bad_usb->hid_cfg.manuf, | ||||
| @ -337,7 +373,7 @@ static bool ducky_script_preload(BadUsbScript* bad_usb, File* script_file) { | ||||
|     uint8_t ret = 0; | ||||
|     uint32_t line_len = 0; | ||||
| 
 | ||||
|     string_reset(bad_usb->line); | ||||
|     furi_string_reset(bad_usb->line); | ||||
| 
 | ||||
|     do { | ||||
|         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; | ||||
|             } else { | ||||
|                 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++; | ||||
|             } | ||||
| @ -360,7 +396,7 @@ static bool ducky_script_preload(BadUsbScript* bad_usb, File* script_file) { | ||||
|         } | ||||
|     } 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
 | ||||
|     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]); | ||||
| @ -373,7 +409,7 @@ static bool ducky_script_preload(BadUsbScript* bad_usb, File* script_file) { | ||||
|     } | ||||
| 
 | ||||
|     storage_file_seek(script_file, 0, true); | ||||
|     string_reset(bad_usb->line); | ||||
|     furi_string_reset(bad_usb->line); | ||||
| 
 | ||||
|     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) { | ||||
|         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
 | ||||
|             return 0; | ||||
|         } else if(delay_val < 0) { // Script error
 | ||||
|             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; | ||||
|         } else { | ||||
|             return (delay_val + bad_usb->defdelay); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     string_set(bad_usb->line_prev, bad_usb->line); | ||||
|     string_reset(bad_usb->line); | ||||
|     furi_string_set(bad_usb->line_prev, bad_usb->line); | ||||
|     furi_string_reset(bad_usb->line); | ||||
| 
 | ||||
|     while(1) { | ||||
|         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; | ||||
|         } | ||||
|         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->buf_len = bad_usb->buf_len + 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) { | ||||
|                     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; | ||||
|                 } else { | ||||
|                     return (delay_val + bad_usb->defdelay); | ||||
|                 } | ||||
|             } 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; | ||||
| @ -456,8 +495,8 @@ static int32_t bad_usb_worker(void* context) { | ||||
| 
 | ||||
|     FURI_LOG_I(WORKER_TAG, "Init"); | ||||
|     File* script_file = storage_file_alloc(furi_record_open(RECORD_STORAGE)); | ||||
|     string_init(bad_usb->line); | ||||
|     string_init(bad_usb->line_prev); | ||||
|     bad_usb->line = furi_string_alloc(); | ||||
|     bad_usb->line_prev = furi_string_alloc(); | ||||
| 
 | ||||
|     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(storage_file_open( | ||||
|                    script_file, | ||||
|                    string_get_cstr(bad_usb->file_path), | ||||
|                    furi_string_get_cstr(bad_usb->file_path), | ||||
|                    FSAM_READ, | ||||
|                    FSOM_OPEN_EXISTING)) { | ||||
|                 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_free(script_file); | ||||
|     string_clear(bad_usb->line); | ||||
|     string_clear(bad_usb->line_prev); | ||||
|     furi_string_free(bad_usb->line); | ||||
|     furi_string_free(bad_usb->line_prev); | ||||
| 
 | ||||
|     FURI_LOG_I(WORKER_TAG, "End"); | ||||
| 
 | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| BadUsbScript* bad_usb_script_open(string_t file_path) { | ||||
| BadUsbScript* bad_usb_script_open(FuriString* file_path) { | ||||
|     furi_assert(file_path); | ||||
| 
 | ||||
|     BadUsbScript* bad_usb = malloc(sizeof(BadUsbScript)); | ||||
|     string_init(bad_usb->file_path); | ||||
|     string_set(bad_usb->file_path, file_path); | ||||
|     bad_usb->file_path = furi_string_alloc(); | ||||
|     furi_string_set(bad_usb->file_path, file_path); | ||||
| 
 | ||||
|     bad_usb->st.state = BadUsbStateInit; | ||||
|     bad_usb->st.error[0] = '\0'; | ||||
| 
 | ||||
|     bad_usb->thread = furi_thread_alloc(); | ||||
|     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_join(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); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -5,7 +5,6 @@ extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| #include <furi.h> | ||||
| #include <m-string.h> | ||||
| 
 | ||||
| typedef struct BadUsbScript BadUsbScript; | ||||
| 
 | ||||
| @ -26,9 +25,10 @@ typedef struct { | ||||
|     uint16_t line_nb; | ||||
|     uint32_t delay_remain; | ||||
|     uint16_t error_line; | ||||
|     char error[64]; | ||||
| } 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); | ||||
| 
 | ||||
|  | ||||
| @ -2,7 +2,6 @@ | ||||
| #include "../bad_usb_app_i.h" | ||||
| #include "../views/bad_usb_view.h" | ||||
| #include "furi_hal.h" | ||||
| #include "m-string.h" | ||||
| #include "toolbox/path.h" | ||||
| 
 | ||||
| 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) { | ||||
|     BadUsbApp* app = context; | ||||
| 
 | ||||
|     string_t file_name; | ||||
|     string_init(file_name); | ||||
|     FuriString* file_name; | ||||
|     file_name = furi_string_alloc(); | ||||
| 
 | ||||
|     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); | ||||
| 
 | ||||
|     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)); | ||||
| 
 | ||||
|  | ||||
| @ -19,12 +19,12 @@ typedef struct { | ||||
| static void bad_usb_draw_callback(Canvas* canvas, void* _model) { | ||||
|     BadUsbModel* model = _model; | ||||
| 
 | ||||
|     string_t disp_str; | ||||
|     string_init_set_str(disp_str, model->file_name); | ||||
|     FuriString* disp_str; | ||||
|     disp_str = furi_string_alloc_set(model->file_name); | ||||
|     elements_string_fit_width(canvas, disp_str, 128 - 2); | ||||
|     canvas_set_font(canvas, FontSecondary); | ||||
|     canvas_draw_str(canvas, 2, 8, string_get_cstr(disp_str)); | ||||
|     string_reset(disp_str); | ||||
|     canvas_draw_str(canvas, 2, 8, furi_string_get_cstr(disp_str)); | ||||
|     furi_string_reset(disp_str); | ||||
| 
 | ||||
|     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_draw_str_aligned(canvas, 127, 33, AlignRight, AlignBottom, "ERROR:"); | ||||
|         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, 127, 46, AlignRight, AlignBottom, string_get_cstr(disp_str)); | ||||
|         string_reset(disp_str); | ||||
|             canvas, 127, 46, AlignRight, AlignBottom, furi_string_get_cstr(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) { | ||||
|         canvas_draw_icon(canvas, 4, 22, &I_Smile_18x18); | ||||
|         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_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, 114, 36, AlignRight, AlignBottom, string_get_cstr(disp_str)); | ||||
|         string_reset(disp_str); | ||||
|             canvas, 114, 36, AlignRight, AlignBottom, furi_string_get_cstr(disp_str)); | ||||
|         furi_string_reset(disp_str); | ||||
|         canvas_draw_icon(canvas, 117, 22, &I_Percent_10x14); | ||||
|     } else if(model->state.state == BadUsbStateDone) { | ||||
|         canvas_draw_icon(canvas, 4, 19, &I_EviSmile1_18x21); | ||||
|         canvas_set_font(canvas, FontBigNumbers); | ||||
|         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); | ||||
|     } else if(model->state.state == BadUsbStateDelay) { | ||||
|         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_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, 114, 36, AlignRight, AlignBottom, string_get_cstr(disp_str)); | ||||
|         string_reset(disp_str); | ||||
|             canvas, 114, 36, AlignRight, AlignBottom, furi_string_get_cstr(disp_str)); | ||||
|         furi_string_reset(disp_str); | ||||
|         canvas_draw_icon(canvas, 117, 22, &I_Percent_10x14); | ||||
|         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, 127, 46, AlignRight, AlignBottom, string_get_cstr(disp_str)); | ||||
|         string_reset(disp_str); | ||||
|             canvas, 127, 46, AlignRight, AlignBottom, furi_string_get_cstr(disp_str)); | ||||
|         furi_string_reset(disp_str); | ||||
|     } else { | ||||
|         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) { | ||||
| @ -143,29 +146,33 @@ void bad_usb_set_ok_callback(BadUsb* bad_usb, BadUsbOkCallback callback, void* c | ||||
|     furi_assert(bad_usb); | ||||
|     furi_assert(callback); | ||||
|     with_view_model( | ||||
|         bad_usb->view, (BadUsbModel * model) { | ||||
|         bad_usb->view, | ||||
|         BadUsbModel * model, | ||||
|         { | ||||
|             UNUSED(model); | ||||
|             bad_usb->callback = callback; | ||||
|             bad_usb->context = context; | ||||
|             return true; | ||||
|         }); | ||||
|         }, | ||||
|         true); | ||||
| } | ||||
| 
 | ||||
| void bad_usb_set_file_name(BadUsb* bad_usb, const char* name) { | ||||
|     furi_assert(name); | ||||
|     with_view_model( | ||||
|         bad_usb->view, (BadUsbModel * model) { | ||||
|             strlcpy(model->file_name, name, MAX_NAME_LEN); | ||||
|             return true; | ||||
|         }); | ||||
|         bad_usb->view, | ||||
|         BadUsbModel * model, | ||||
|         { strlcpy(model->file_name, name, MAX_NAME_LEN); }, | ||||
|         true); | ||||
| } | ||||
| 
 | ||||
| void bad_usb_set_state(BadUsb* bad_usb, BadUsbState* st) { | ||||
|     furi_assert(st); | ||||
|     with_view_model( | ||||
|         bad_usb->view, (BadUsbModel * model) { | ||||
|         bad_usb->view, | ||||
|         BadUsbModel * model, | ||||
|         { | ||||
|             memcpy(&(model->state), st, sizeof(BadUsbState)); | ||||
|             model->anim_frame ^= 1; | ||||
|             return true; | ||||
|         }); | ||||
|         }, | ||||
|         true); | ||||
| } | ||||
|  | ||||
| @ -3,6 +3,7 @@ App( | ||||
|     name="Applications", | ||||
|     apptype=FlipperAppType.APP, | ||||
|     entry_point="fap_loader_app", | ||||
|     cdefines=["APP_FAP_LOADER"], | ||||
|     requires=[ | ||||
|         "gui", | ||||
|         "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); | ||||
|     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; | ||||
|     } else { | ||||
|         result = true; | ||||
|  | ||||
| @ -1,34 +1,34 @@ | ||||
| #include <furi.h> | ||||
| #include <gui/gui.h> | ||||
| #include <gui/view_dispatcher.h> | ||||
| #include <gui/modules/loading.h> | ||||
| #include <storage/storage.h> | ||||
| #include <gui/modules/loading.h> | ||||
| #include <dialogs/dialogs.h> | ||||
| #include "elf_cpp/elf_hashtable.h" | ||||
| #include <flipper_application/flipper_application.h> | ||||
| #include "elf_cpp/elf_hashtable.h" | ||||
| #include "fap_loader_app.h" | ||||
| 
 | ||||
| #define TAG "fap_loader_app" | ||||
| 
 | ||||
| typedef struct { | ||||
| struct FapLoader { | ||||
|     FlipperApplication* app; | ||||
|     Storage* storage; | ||||
|     DialogsApp* dialogs; | ||||
|     Gui* gui; | ||||
|     string_t fap_path; | ||||
| 
 | ||||
|     FuriString* fap_path; | ||||
|     ViewDispatcher* view_dispatcher; | ||||
|     Loading* loading; | ||||
| } FapLoader; | ||||
| }; | ||||
| 
 | ||||
| static bool | ||||
|     fap_loader_item_callback(string_t path, void* context, uint8_t** icon_ptr, string_t item_name) { | ||||
|     FapLoader* loader = context; | ||||
|     furi_assert(loader); | ||||
| 
 | ||||
|     FlipperApplication* app = flipper_application_alloc(loader->storage, &hashtable_api_interface); | ||||
| bool fap_loader_load_name_and_icon( | ||||
|     FuriString* path, | ||||
|     Storage* storage, | ||||
|     uint8_t** icon_ptr, | ||||
|     FuriString* item_name) { | ||||
|     FlipperApplication* app = flipper_application_alloc(storage, &hashtable_api_interface); | ||||
| 
 | ||||
|     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; | ||||
| 
 | ||||
| @ -37,10 +37,10 @@ static bool | ||||
|         if(manifest->has_icon) { | ||||
|             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; | ||||
|     } 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; | ||||
|     } | ||||
| 
 | ||||
| @ -48,30 +48,41 @@ static bool | ||||
|     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) { | ||||
|     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 show_error = true; | ||||
|     do { | ||||
|         file_selected = true; | ||||
|         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 = | ||||
|             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) { | ||||
|             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( | ||||
|                 TAG, | ||||
|                 "FAP Loader failed to preload %s: %s", | ||||
|                 string_get_cstr(loader->fap_path), | ||||
|                 furi_string_get_cstr(loader->fap_path), | ||||
|                 err_msg); | ||||
|             break; | ||||
|         } | ||||
| @ -80,16 +91,17 @@ static bool fap_loader_run_selected_app(FapLoader* loader) { | ||||
|         FlipperApplicationLoadStatus load_status = flipper_application_map_to_memory(loader->app); | ||||
|         if(load_status != FlipperApplicationLoadStatusSuccess) { | ||||
|             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( | ||||
|                 TAG, | ||||
|                 "FAP Loader failed to map to memory %s: %s", | ||||
|                 string_get_cstr(loader->fap_path), | ||||
|                 furi_string_get_cstr(loader->fap_path), | ||||
|                 err_msg); | ||||
|             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); | ||||
|         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_buttons(message, NULL, NULL, NULL); | ||||
| 
 | ||||
|         string_t buffer; | ||||
|         string_init(buffer); | ||||
|         string_printf(buffer, "%s", string_get_cstr(error_message)); | ||||
|         string_replace_str(buffer, ":", "\n"); | ||||
|         FuriString* buffer; | ||||
|         buffer = furi_string_alloc(); | ||||
|         furi_string_printf(buffer, "%s", furi_string_get_cstr(error_message)); | ||||
|         furi_string_replace(buffer, ":", "\n"); | ||||
|         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_free(message); | ||||
|         string_clear(buffer); | ||||
|         furi_string_free(buffer); | ||||
|     } | ||||
| 
 | ||||
|     string_clear(error_message); | ||||
|     furi_string_free(error_message); | ||||
| 
 | ||||
|     if(file_selected) { | ||||
|         flipper_application_free(loader->app); | ||||
| @ -131,7 +143,7 @@ static bool fap_loader_select_app(FapLoader* loader) { | ||||
|     const DialogsFileBrowserOptions browser_options = { | ||||
|         .extension = ".fap", | ||||
|         .skip_assets = true, | ||||
|         .icon = &I_badusb_10px, | ||||
|         .icon = &I_unknown_10px, | ||||
|         .hide_ext = true, | ||||
|         .item_loader_callback = fap_loader_item_callback, | ||||
|         .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); | ||||
| } | ||||
| 
 | ||||
| int32_t fap_loader_app(void* p) { | ||||
| static FapLoader* fap_loader_alloc(const char* path) { | ||||
|     FapLoader* loader = malloc(sizeof(FapLoader)); | ||||
|     loader->fap_path = furi_string_alloc_set(path); | ||||
|     loader->storage = furi_record_open(RECORD_STORAGE); | ||||
|     loader->dialogs = furi_record_open(RECORD_DIALOGS); | ||||
|     loader->gui = furi_record_open(RECORD_GUI); | ||||
| 
 | ||||
|     loader->view_dispatcher = view_dispatcher_alloc(); | ||||
|     loader->loading = loading_alloc(); | ||||
| 
 | ||||
|     view_dispatcher_attach_to_gui( | ||||
|         loader->view_dispatcher, loader->gui, ViewDispatcherTypeFullscreen); | ||||
|     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) { | ||||
|         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); | ||||
|     } else { | ||||
|         string_init_set(loader->fap_path, EXT_PATH("apps")); | ||||
| 
 | ||||
|         loader = fap_loader_alloc(EXT_PATH("apps")); | ||||
|         while(fap_loader_select_app(loader)) { | ||||
|             view_dispatcher_switch_to_view(loader->view_dispatcher, 0); | ||||
|             fap_loader_run_selected_app(loader); | ||||
|         }; | ||||
|     } | ||||
| 
 | ||||
|     view_dispatcher_remove_view(loader->view_dispatcher, 0); | ||||
|     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); | ||||
|     fap_loader_free(loader); | ||||
|     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 "furi_hal_power.h" | ||||
| #include "furi_hal_usb.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| enum GpioItem { | ||||
|     GpioItemUsbUart, | ||||
| @ -88,6 +89,7 @@ bool gpio_scene_start_on_event(void* context, SceneManagerEvent event) { | ||||
|         } else if(event.event == GpioStartEventUsbUart) { | ||||
|             scene_manager_set_scene_state(app->scene_manager, GpioSceneStart, GpioItemUsbUart); | ||||
|             if(!furi_hal_usb_is_locked()) { | ||||
|                 DOLPHIN_DEED(DolphinDeedGpioUartBridge); | ||||
|                 scene_manager_next_scene(app->scene_manager, GpioSceneUsbUart); | ||||
|             } else { | ||||
|                 scene_manager_next_scene(app->scene_manager, GpioSceneUsbUartCloseRpc); | ||||
|  | ||||
| @ -1,6 +1,5 @@ | ||||
| #include "usb_uart_bridge.h" | ||||
| #include "furi_hal.h" | ||||
| #include <stream_buffer.h> | ||||
| #include <furi_hal_usb_cdc.h> | ||||
| #include "usb_cdc.h" | ||||
| #include "cli/cli_vcp.h" | ||||
| @ -43,7 +42,7 @@ struct UsbUartBridge { | ||||
|     FuriThread* thread; | ||||
|     FuriThread* tx_thread; | ||||
| 
 | ||||
|     StreamBufferHandle_t rx_stream; | ||||
|     FuriStreamBuffer* rx_stream; | ||||
| 
 | ||||
|     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) { | ||||
|     UsbUartBridge* usb_uart = (UsbUartBridge*)context; | ||||
|     BaseType_t xHigherPriorityTaskWoken = pdFALSE; | ||||
| 
 | ||||
|     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); | ||||
|         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)); | ||||
| 
 | ||||
|     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->usb_mutex = furi_mutex_alloc(FuriMutexTypeNormal); | ||||
| @ -189,8 +186,8 @@ static int32_t usb_uart_worker(void* context) { | ||||
|         furi_check((events & FuriFlagError) == 0); | ||||
|         if(events & WorkerEvtStop) break; | ||||
|         if(events & WorkerEvtRxDone) { | ||||
|             size_t len = | ||||
|                 xStreamBufferReceive(usb_uart->rx_stream, usb_uart->rx_buf, USB_CDC_PKT_LEN, 0); | ||||
|             size_t len = furi_stream_buffer_receive( | ||||
|                 usb_uart->rx_stream, usb_uart->rx_buf, USB_CDC_PKT_LEN, 0); | ||||
|             if(len > 0) { | ||||
|                 if(furi_semaphore_acquire(usb_uart->tx_sem, 100) == FuriStatusOk) { | ||||
|                     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_check(furi_mutex_release(usb_uart->usb_mutex) == FuriStatusOk); | ||||
|                 } 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_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_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) { | ||||
|     with_view_model( | ||||
|         gpio_test->view, (GpioTestModel * model) { | ||||
|         gpio_test->view, | ||||
|         GpioTestModel * model, | ||||
|         { | ||||
|             if(model->pin_idx) { | ||||
|                 model->pin_idx--; | ||||
|             } | ||||
|             return true; | ||||
|         }); | ||||
|         }, | ||||
|         true); | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| static bool gpio_test_process_right(GpioTest* gpio_test) { | ||||
|     with_view_model( | ||||
|         gpio_test->view, (GpioTestModel * model) { | ||||
|         gpio_test->view, | ||||
|         GpioTestModel * model, | ||||
|         { | ||||
|             if(model->pin_idx < GPIO_ITEM_COUNT) { | ||||
|                 model->pin_idx++; | ||||
|             } | ||||
|             return true; | ||||
|         }); | ||||
|         }, | ||||
|         true); | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| @ -72,7 +76,9 @@ static bool gpio_test_process_ok(GpioTest* gpio_test, InputEvent* event) { | ||||
|     bool consumed = false; | ||||
| 
 | ||||
|     with_view_model( | ||||
|         gpio_test->view, (GpioTestModel * model) { | ||||
|         gpio_test->view, | ||||
|         GpioTestModel * model, | ||||
|         { | ||||
|             if(event->type == InputTypePress) { | ||||
|                 if(model->pin_idx < GPIO_ITEM_COUNT) { | ||||
|                     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; | ||||
|             } | ||||
|             gpio_test->callback(event->type, gpio_test->context); | ||||
|             return true; | ||||
|         }); | ||||
|         }, | ||||
|         true); | ||||
| 
 | ||||
|     return consumed; | ||||
| } | ||||
| @ -122,10 +128,12 @@ void gpio_test_set_ok_callback(GpioTest* gpio_test, GpioTestOkCallback callback, | ||||
|     furi_assert(gpio_test); | ||||
|     furi_assert(callback); | ||||
|     with_view_model( | ||||
|         gpio_test->view, (GpioTestModel * model) { | ||||
|         gpio_test->view, | ||||
|         GpioTestModel * model, | ||||
|         { | ||||
|             UNUSED(model); | ||||
|             gpio_test->callback = callback; | ||||
|             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); | ||||
|     } else { | ||||
|         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); | ||||
|         snprintf(temp_str, 18, "%lu", model->tx_cnt / 1024); | ||||
|         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); | ||||
|     } else { | ||||
|         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); | ||||
|         snprintf(temp_str, 18, "%lu", model->rx_cnt / 1024); | ||||
|         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); | ||||
| 
 | ||||
|     with_view_model( | ||||
|         usb_uart->view, (GpioUsbUartModel * model) { | ||||
|         usb_uart->view, | ||||
|         GpioUsbUartModel * model, | ||||
|         { | ||||
|             UNUSED(model); | ||||
|             usb_uart->callback = callback; | ||||
|             usb_uart->context = context; | ||||
|             return false; | ||||
|         }); | ||||
|         }, | ||||
|         false); | ||||
| } | ||||
| 
 | ||||
| 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); | ||||
| 
 | ||||
|     with_view_model( | ||||
|         instance->view, (GpioUsbUartModel * model) { | ||||
|         instance->view, | ||||
|         GpioUsbUartModel * model, | ||||
|         { | ||||
|             model->baudrate = st->baudrate_cur; | ||||
|             model->vcp_port = cfg->vcp_ch; | ||||
|             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->tx_cnt = st->tx_cnt; | ||||
|             model->rx_cnt = st->rx_cnt; | ||||
|             return true; | ||||
|         }); | ||||
|         }, | ||||
|         true); | ||||
| } | ||||
|  | ||||
| @ -2,7 +2,6 @@ | ||||
| #include "assets_icons.h" | ||||
| #include "ibutton_i.h" | ||||
| #include "ibutton/scenes/ibutton_scene.h" | ||||
| #include "m-string.h" | ||||
| #include <toolbox/path.h> | ||||
| #include <flipper_format/flipper_format.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); | ||||
|     bool result = false; | ||||
|     string_t data; | ||||
|     string_init(data); | ||||
|     FuriString* data; | ||||
|     data = furi_string_alloc(); | ||||
| 
 | ||||
|     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
 | ||||
|         uint32_t version; | ||||
|         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; | ||||
| 
 | ||||
|         // key type
 | ||||
|         iButtonKeyType type; | ||||
|         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
 | ||||
|         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); | ||||
| 
 | ||||
|     flipper_format_free(file); | ||||
|     string_clear(data); | ||||
|     furi_string_free(data); | ||||
| 
 | ||||
|     if((!result) && (show_dialog)) { | ||||
|         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 = malloc(sizeof(iButton)); | ||||
| 
 | ||||
|     string_init(ibutton->file_path); | ||||
|     ibutton->file_path = furi_string_alloc(); | ||||
| 
 | ||||
|     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_key_free(ibutton->key); | ||||
| 
 | ||||
|     string_clear(ibutton->file_path); | ||||
|     furi_string_free(ibutton->file_path); | ||||
| 
 | ||||
|     free(ibutton); | ||||
| } | ||||
| @ -240,19 +239,19 @@ bool ibutton_save_key(iButton* ibutton, const char* key_name) { | ||||
| 
 | ||||
|     do { | ||||
|         // 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
 | ||||
|             ibutton_delete_key(ibutton); | ||||
| 
 | ||||
|             // Remove old key name from path
 | ||||
|             size_t filename_start = string_search_rchar(ibutton->file_path, '/'); | ||||
|             string_left(ibutton->file_path, filename_start); | ||||
|             size_t filename_start = furi_string_search_rchar(ibutton->file_path, '/'); | ||||
|             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
 | ||||
|         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
 | ||||
|         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 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; | ||||
| } | ||||
| @ -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_send_started(ibutton->rpc_ctx); | ||||
|         } 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)) { | ||||
|                 key_loaded = true; | ||||
|                 // 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/one_wire_host.h> | ||||
| 
 | ||||
| static void ibutton_cli(Cli* cli, string_t args, void* context); | ||||
| static void onewire_cli(Cli* cli, string_t args, void* context); | ||||
| static void ibutton_cli(Cli* cli, FuriString* args, void* context); | ||||
| static void onewire_cli(Cli* cli, FuriString* args, void* context); | ||||
| 
 | ||||
| // app cli function
 | ||||
| void ibutton_on_system_start() { | ||||
| @ -34,16 +34,16 @@ void ibutton_cli_print_usage() { | ||||
|     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; | ||||
| 
 | ||||
|     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; | ||||
|         *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; | ||||
|         *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; | ||||
|         *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); | ||||
| } | ||||
| 
 | ||||
| void ibutton_cli_write(Cli* cli, string_t args) { | ||||
| void ibutton_cli_write(Cli* cli, FuriString* args) { | ||||
|     iButtonKey* key = ibutton_key_alloc(); | ||||
|     iButtonWorker* worker = ibutton_worker_alloc(); | ||||
|     iButtonKeyType type; | ||||
|     iButtonWriteContext write_context; | ||||
|     uint8_t key_data[IBUTTON_KEY_DATA_SIZE]; | ||||
|     string_t data; | ||||
|     FuriString* data; | ||||
| 
 | ||||
|     write_context.event = furi_event_flag_alloc(); | ||||
| 
 | ||||
|     string_init(data); | ||||
|     data = furi_string_alloc(); | ||||
|     ibutton_worker_start_thread(worker); | ||||
|     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); | ||||
|     } while(false); | ||||
| 
 | ||||
|     string_clear(data); | ||||
|     furi_string_free(data); | ||||
|     ibutton_worker_stop_thread(worker); | ||||
|     ibutton_worker_free(worker); | ||||
|     ibutton_key_free(key); | ||||
| @ -194,14 +194,14 @@ void ibutton_cli_write(Cli* cli, string_t args) { | ||||
|     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(); | ||||
|     iButtonWorker* worker = ibutton_worker_alloc(); | ||||
|     iButtonKeyType type; | ||||
|     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); | ||||
| 
 | ||||
|     do { | ||||
| @ -234,34 +234,34 @@ void ibutton_cli_emulate(Cli* cli, string_t args) { | ||||
|         ibutton_worker_stop(worker); | ||||
|     } while(false); | ||||
| 
 | ||||
|     string_clear(data); | ||||
|     furi_string_free(data); | ||||
|     ibutton_worker_stop_thread(worker); | ||||
|     ibutton_worker_free(worker); | ||||
|     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); | ||||
|     string_t cmd; | ||||
|     string_init(cmd); | ||||
|     FuriString* cmd; | ||||
|     cmd = furi_string_alloc(); | ||||
| 
 | ||||
|     if(!args_read_string_and_trim(args, cmd)) { | ||||
|         string_clear(cmd); | ||||
|         furi_string_free(cmd); | ||||
|         ibutton_cli_print_usage(); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     if(string_cmp_str(cmd, "read") == 0) { | ||||
|     if(furi_string_cmp_str(cmd, "read") == 0) { | ||||
|         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); | ||||
|     } else if(string_cmp_str(cmd, "emulate") == 0) { | ||||
|     } else if(furi_string_cmp_str(cmd, "emulate") == 0) { | ||||
|         ibutton_cli_emulate(cli, args); | ||||
|     } else { | ||||
|         ibutton_cli_print_usage(); | ||||
|     } | ||||
| 
 | ||||
|     string_clear(cmd); | ||||
|     furi_string_free(cmd); | ||||
| } | ||||
| 
 | ||||
| void onewire_cli_print_usage() { | ||||
| @ -299,20 +299,20 @@ static void onewire_cli_search(Cli* cli) { | ||||
|     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); | ||||
|     string_t cmd; | ||||
|     string_init(cmd); | ||||
|     FuriString* cmd; | ||||
|     cmd = furi_string_alloc(); | ||||
| 
 | ||||
|     if(!args_read_string_and_trim(args, cmd)) { | ||||
|         string_clear(cmd); | ||||
|         furi_string_free(cmd); | ||||
|         onewire_cli_print_usage(); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     if(string_cmp_str(cmd, "search") == 0) { | ||||
|     if(furi_string_cmp_str(cmd, "search") == 0) { | ||||
|         onewire_cli_search(cli); | ||||
|     } | ||||
| 
 | ||||
|     string_clear(cmd); | ||||
|     furi_string_free(cmd); | ||||
| } | ||||
|  | ||||
| @ -41,7 +41,7 @@ struct iButton { | ||||
|     iButtonWorker* key_worker; | ||||
|     iButtonKey* key; | ||||
| 
 | ||||
|     string_t file_path; | ||||
|     FuriString* file_path; | ||||
|     char text_store[IBUTTON_TEXT_STORE_SIZE + 1]; | ||||
| 
 | ||||
|     Submenu* submenu; | ||||
| @ -78,7 +78,7 @@ typedef enum { | ||||
| } iButtonNotificationMessage; | ||||
| 
 | ||||
| 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_delete_key(iButton* ibutton); | ||||
| void ibutton_text_store_set(iButton* ibutton, const char* text, ...); | ||||
|  | ||||
| @ -1,5 +1,4 @@ | ||||
| #include "../ibutton_i.h" | ||||
| #include "m-string.h" | ||||
| 
 | ||||
| enum SubmenuIndex { | ||||
|     SubmenuIndexCyfral, | ||||
| @ -47,7 +46,7 @@ bool ibutton_scene_add_type_on_event(void* context, SceneManagerEvent event) { | ||||
|             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); | ||||
|         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; | ||||
|     const uint8_t* key_data = ibutton_key_get_data_p(key); | ||||
| 
 | ||||
|     string_t key_name; | ||||
|     string_init(key_name); | ||||
|     FuriString* key_name; | ||||
|     key_name = furi_string_alloc(); | ||||
|     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, 0, 0, 128, 27, AlignCenter, AlignCenter, ibutton->text_store, true); | ||||
|     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); | ||||
| 
 | ||||
|     string_clear(key_name); | ||||
|     furi_string_free(key_name); | ||||
| } | ||||
| 
 | ||||
| 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); | ||||
| 
 | ||||
|     string_t key_name; | ||||
|     string_init(key_name); | ||||
|     if(string_end_with_str_p(ibutton->file_path, IBUTTON_APP_EXTENSION)) { | ||||
|     FuriString* key_name; | ||||
|     key_name = furi_string_alloc(); | ||||
|     if(furi_string_end_with(ibutton->file_path, IBUTTON_APP_EXTENSION)) { | ||||
|         path_extract_filename(ibutton->file_path, key_name, true); | ||||
|     } | ||||
| 
 | ||||
|     DOLPHIN_DEED(DolphinDeedIbuttonEmulate); | ||||
| 
 | ||||
|     // check that stored key has name
 | ||||
|     if(!string_empty_p(key_name)) { | ||||
|         ibutton_text_store_set(ibutton, "%s", string_get_cstr(key_name)); | ||||
|     if(!furi_string_empty(key_name)) { | ||||
|         ibutton_text_store_set(ibutton, "%s", furi_string_get_cstr(key_name)); | ||||
|     } else { | ||||
|         // if not, show key data
 | ||||
|         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_worker_emulate_start(ibutton->key_worker, key); | ||||
| 
 | ||||
|     string_clear(key_name); | ||||
|     furi_string_free(key_name); | ||||
| 
 | ||||
|     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); | ||||
| 
 | ||||
|     string_t key_name; | ||||
|     string_init(key_name); | ||||
|     FuriString* key_name; | ||||
|     key_name = furi_string_alloc(); | ||||
|     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, 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); | ||||
| 
 | ||||
|     string_clear(key_name); | ||||
|     furi_string_free(key_name); | ||||
| } | ||||
| 
 | ||||
| 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); | ||||
| 
 | ||||
|     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_start(worker, key); | ||||
|  | ||||
| @ -29,19 +29,19 @@ bool ibutton_scene_rpc_on_event(void* context, SceneManagerEvent event) { | ||||
|         if(event.event == iButtonCustomEventRpcLoad) { | ||||
|             const char* arg = rpc_system_app_get_data(ibutton->rpc_ctx); | ||||
|             bool result = false; | ||||
|             if(arg && (string_empty_p(ibutton->file_path))) { | ||||
|                 string_set_str(ibutton->file_path, arg); | ||||
|             if(arg && (furi_string_empty(ibutton->file_path))) { | ||||
|                 furi_string_set(ibutton->file_path, arg); | ||||
|                 if(ibutton_load_key_data(ibutton, ibutton->file_path, false)) { | ||||
|                     ibutton_worker_emulate_start(ibutton->key_worker, ibutton->key); | ||||
|                     string_t key_name; | ||||
|                     string_init(key_name); | ||||
|                     if(string_end_with_str_p(ibutton->file_path, IBUTTON_APP_EXTENSION)) { | ||||
|                     FuriString* key_name; | ||||
|                     key_name = furi_string_alloc(); | ||||
|                     if(furi_string_end_with(ibutton->file_path, IBUTTON_APP_EXTENSION)) { | ||||
|                         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, "emulating\n%s", string_get_cstr(key_name)); | ||||
|                             ibutton, "emulating\n%s", furi_string_get_cstr(key_name)); | ||||
|                     } else { | ||||
|                         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); | ||||
| 
 | ||||
|                     string_clear(key_name); | ||||
|                     furi_string_free(key_name); | ||||
|                     result = true; | ||||
|                 } else { | ||||
|                     string_reset(ibutton->file_path); | ||||
|                     furi_string_reset(ibutton->file_path); | ||||
|                 } | ||||
|             } | ||||
|             rpc_system_app_confirm(ibutton->rpc_ctx, RpcAppEventLoadFile, result); | ||||
|  | ||||
| @ -1,5 +1,4 @@ | ||||
| #include "../ibutton_i.h" | ||||
| #include "m-string.h" | ||||
| #include <lib/toolbox/random_name.h> | ||||
| #include <toolbox/path.h> | ||||
| 
 | ||||
| @ -12,17 +11,17 @@ void ibutton_scene_save_name_on_enter(void* context) { | ||||
|     iButton* ibutton = context; | ||||
|     TextInput* text_input = ibutton->text_input; | ||||
| 
 | ||||
|     string_t key_name; | ||||
|     string_init(key_name); | ||||
|     if(string_end_with_str_p(ibutton->file_path, IBUTTON_APP_EXTENSION)) { | ||||
|     FuriString* key_name; | ||||
|     key_name = furi_string_alloc(); | ||||
|     if(furi_string_end_with(ibutton->file_path, IBUTTON_APP_EXTENSION)) { | ||||
|         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) { | ||||
|         set_random_name(ibutton->text_store, IBUTTON_TEXT_STORE_SIZE); | ||||
|     } 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"); | ||||
| @ -34,19 +33,19 @@ void ibutton_scene_save_name_on_enter(void* context) { | ||||
|         IBUTTON_KEY_NAME_SIZE, | ||||
|         key_name_is_empty); | ||||
| 
 | ||||
|     string_t folder_path; | ||||
|     string_init(folder_path); | ||||
|     FuriString* 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( | ||||
|         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); | ||||
| 
 | ||||
|     view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewTextInput); | ||||
| 
 | ||||
|     string_clear(key_name); | ||||
|     string_clear(folder_path); | ||||
|     furi_string_free(key_name); | ||||
|     furi_string_free(folder_path); | ||||
| } | ||||
| 
 | ||||
| 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) { | ||||
|             scene_manager_next_scene(ibutton->scene_manager, iButtonSceneRead); | ||||
|         } 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); | ||||
|         } else if(event.event == SubmenuIndexAdd) { | ||||
|             scene_manager_next_scene(ibutton->scene_manager, iButtonSceneAddType); | ||||
|  | ||||
| @ -1,5 +1,4 @@ | ||||
| #include "../ibutton_i.h" | ||||
| #include "m-string.h" | ||||
| #include "toolbox/path.h" | ||||
| 
 | ||||
| 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); | ||||
| 
 | ||||
|     string_t key_name; | ||||
|     string_init(key_name); | ||||
|     if(string_end_with_str_p(ibutton->file_path, IBUTTON_APP_EXTENSION)) { | ||||
|     FuriString* key_name; | ||||
|     key_name = furi_string_alloc(); | ||||
|     if(furi_string_end_with(ibutton->file_path, IBUTTON_APP_EXTENSION)) { | ||||
|         path_extract_filename(ibutton->file_path, key_name, true); | ||||
|     } | ||||
| 
 | ||||
|     // check that stored key has name
 | ||||
|     if(!string_empty_p(key_name)) { | ||||
|         ibutton_text_store_set(ibutton, "%s", string_get_cstr(key_name)); | ||||
|     if(!furi_string_empty(key_name)) { | ||||
|         ibutton_text_store_set(ibutton, "%s", furi_string_get_cstr(key_name)); | ||||
|     } else { | ||||
|         // if not, show key data
 | ||||
|         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_start(worker, key); | ||||
| 
 | ||||
|     string_clear(key_name); | ||||
|     furi_string_free(key_name); | ||||
| 
 | ||||
|     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); | ||||
| 
 | ||||
|     string_t base_path; | ||||
|     string_init_set_str(base_path, path); | ||||
|     FuriString* base_path; | ||||
|     base_path = furi_string_alloc_set(path); | ||||
| 
 | ||||
|     if(string_end_with_str_p(base_path, INFRARED_APP_EXTENSION)) { | ||||
|         size_t filename_start = string_search_rchar(base_path, '/'); | ||||
|         string_left(base_path, filename_start); | ||||
|     if(furi_string_end_with(base_path, INFRARED_APP_EXTENSION)) { | ||||
|         size_t filename_start = furi_string_search_rchar(base_path, '/'); | ||||
|         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 the suggested name is occupied, try another one (name2, name3, etc) */ | ||||
|         size_t dot = string_search_rchar(base_path, '.'); | ||||
|         string_left(base_path, dot); | ||||
|         size_t dot = furi_string_search_rchar(base_path, '.'); | ||||
|         furi_string_left(base_path, dot); | ||||
| 
 | ||||
|         string_t path_temp; | ||||
|         string_init(path_temp); | ||||
|         FuriString* path_temp; | ||||
|         path_temp = furi_string_alloc(); | ||||
| 
 | ||||
|         uint32_t i = 1; | ||||
|         do { | ||||
|             string_printf( | ||||
|                 path_temp, "%s%u%s", string_get_cstr(base_path), ++i, INFRARED_APP_EXTENSION); | ||||
|             status = storage_common_stat(storage, string_get_cstr(path_temp), NULL); | ||||
|             furi_string_printf( | ||||
|                 path_temp, "%s%lu%s", furi_string_get_cstr(base_path), ++i, INFRARED_APP_EXTENSION); | ||||
|             status = storage_common_stat(storage, furi_string_get_cstr(path_temp), NULL); | ||||
|         } while(status == FSE_OK); | ||||
| 
 | ||||
|         string_clear(path_temp); | ||||
|         furi_string_free(path_temp); | ||||
| 
 | ||||
|         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); | ||||
| } | ||||
| 
 | ||||
| static Infrared* infrared_alloc() { | ||||
|     Infrared* infrared = malloc(sizeof(Infrared)); | ||||
| 
 | ||||
|     string_init(infrared->file_path); | ||||
|     infrared->file_path = furi_string_alloc(); | ||||
| 
 | ||||
|     InfraredAppState* app_state = &infrared->app_state; | ||||
|     app_state->is_learning_new_remote = false; | ||||
| @ -232,7 +233,7 @@ static void infrared_free(Infrared* infrared) { | ||||
|     furi_record_close(RECORD_GUI); | ||||
|     infrared->gui = NULL; | ||||
| 
 | ||||
|     string_clear(infrared->file_path); | ||||
|     furi_string_free(infrared->file_path); | ||||
| 
 | ||||
|     free(infrared); | ||||
| } | ||||
| @ -243,19 +244,20 @@ bool infrared_add_remote_with_button( | ||||
|     InfraredSignal* signal) { | ||||
|     InfraredRemote* remote = infrared->remote; | ||||
| 
 | ||||
|     string_t new_name, new_path; | ||||
|     string_init_set_str(new_name, INFRARED_DEFAULT_REMOTE_NAME); | ||||
|     string_init_set_str(new_path, INFRARED_APP_FOLDER); | ||||
|     FuriString *new_name, *new_path; | ||||
|     new_name = furi_string_alloc_set(INFRARED_DEFAULT_REMOTE_NAME); | ||||
|     new_path = furi_string_alloc_set(INFRARED_APP_FOLDER); | ||||
| 
 | ||||
|     infrared_find_vacant_remote_name(new_name, string_get_cstr(new_path)); | ||||
|     string_cat_printf(new_path, "/%s%s", string_get_cstr(new_name), INFRARED_APP_EXTENSION); | ||||
|     infrared_find_vacant_remote_name(new_name, furi_string_get_cstr(new_path)); | ||||
|     furi_string_cat_printf( | ||||
|         new_path, "/%s%s", furi_string_get_cstr(new_name), INFRARED_APP_EXTENSION); | ||||
| 
 | ||||
|     infrared_remote_reset(remote); | ||||
|     infrared_remote_set_name(remote, string_get_cstr(new_name)); | ||||
|     infrared_remote_set_path(remote, string_get_cstr(new_path)); | ||||
|     infrared_remote_set_name(remote, furi_string_get_cstr(new_name)); | ||||
|     infrared_remote_set_path(remote, furi_string_get_cstr(new_path)); | ||||
| 
 | ||||
|     string_clear(new_name); | ||||
|     string_clear(new_path); | ||||
|     furi_string_free(new_name); | ||||
|     furi_string_free(new_path); | ||||
|     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; | ||||
|     } | ||||
| 
 | ||||
|     string_t new_name; | ||||
|     string_init_set_str(new_name, name); | ||||
|     FuriString* new_name; | ||||
|     new_name = furi_string_alloc_set(name); | ||||
| 
 | ||||
|     infrared_find_vacant_remote_name(new_name, remote_path); | ||||
| 
 | ||||
|     string_t new_path; | ||||
|     string_init_set(new_path, infrared_remote_get_path(remote)); | ||||
|     if(string_end_with_str_p(new_path, INFRARED_APP_EXTENSION)) { | ||||
|         size_t filename_start = string_search_rchar(new_path, '/'); | ||||
|         string_left(new_path, filename_start); | ||||
|     FuriString* new_path; | ||||
|     new_path = furi_string_alloc_set(infrared_remote_get_path(remote)); | ||||
|     if(furi_string_end_with(new_path, INFRARED_APP_EXTENSION)) { | ||||
|         size_t filename_start = furi_string_search_rchar(new_path, '/'); | ||||
|         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); | ||||
| 
 | ||||
|     FS_Error status = storage_common_rename( | ||||
|         storage, infrared_remote_get_path(remote), string_get_cstr(new_path)); | ||||
|     infrared_remote_set_name(remote, string_get_cstr(new_name)); | ||||
|     infrared_remote_set_path(remote, string_get_cstr(new_path)); | ||||
|         storage, infrared_remote_get_path(remote), furi_string_get_cstr(new_path)); | ||||
|     infrared_remote_set_name(remote, furi_string_get_cstr(new_name)); | ||||
|     infrared_remote_set_path(remote, furi_string_get_cstr(new_path)); | ||||
| 
 | ||||
|     string_clear(new_name); | ||||
|     string_clear(new_path); | ||||
|     furi_string_free(new_name); | ||||
|     furi_string_free(new_path); | ||||
| 
 | ||||
|     furi_record_close(RECORD_STORAGE); | ||||
|     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); | ||||
|             is_rpc_mode = true; | ||||
|         } 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); | ||||
|             if(!is_remote_loaded) { | ||||
|                 dialog_message_show_storage_error( | ||||
|  | ||||
| @ -2,7 +2,6 @@ | ||||
| 
 | ||||
| #include <stdlib.h> | ||||
| #include <m-dict.h> | ||||
| #include <m-string.h> | ||||
| #include <flipper_format/flipper_format.h> | ||||
| 
 | ||||
| #include "infrared_signal.h" | ||||
| @ -14,15 +13,15 @@ typedef struct { | ||||
| 
 | ||||
| DICT_DEF2( | ||||
|     InfraredBruteForceRecordDict, | ||||
|     string_t, | ||||
|     STRING_OPLIST, | ||||
|     FuriString*, | ||||
|     FURI_STRING_OPLIST, | ||||
|     InfraredBruteForceRecord, | ||||
|     M_POD_OPLIST); | ||||
| 
 | ||||
| struct InfraredBruteForce { | ||||
|     FlipperFormat* ff; | ||||
|     const char* db_filename; | ||||
|     string_t current_record_name; | ||||
|     FuriString* current_record_name; | ||||
|     InfraredSignal* current_signal; | ||||
|     InfraredBruteForceRecordDict_t records; | ||||
|     bool is_started; | ||||
| @ -34,7 +33,7 @@ InfraredBruteForce* infrared_brute_force_alloc() { | ||||
|     brute_force->db_filename = NULL; | ||||
|     brute_force->current_signal = NULL; | ||||
|     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); | ||||
|     return brute_force; | ||||
| } | ||||
| @ -42,7 +41,7 @@ InfraredBruteForce* infrared_brute_force_alloc() { | ||||
| void infrared_brute_force_free(InfraredBruteForce* brute_force) { | ||||
|     furi_assert(!brute_force->is_started); | ||||
|     InfraredBruteForceRecordDict_clear(brute_force->records); | ||||
|     string_clear(brute_force->current_record_name); | ||||
|     furi_string_free(brute_force->current_record_name); | ||||
|     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); | ||||
|     if(success) { | ||||
|         string_t signal_name; | ||||
|         string_init(signal_name); | ||||
|         FuriString* signal_name; | ||||
|         signal_name = furi_string_alloc(); | ||||
|         while(flipper_format_read_string(ff, "name", signal_name)) { | ||||
|             InfraredBruteForceRecord* record = | ||||
|                 InfraredBruteForceRecordDict_get(brute_force->records, signal_name); | ||||
| @ -70,7 +69,7 @@ bool infrared_brute_force_calculate_messages(InfraredBruteForce* brute_force) { | ||||
|                 ++(record->count); | ||||
|             } | ||||
|         } | ||||
|         string_clear(signal_name); | ||||
|         furi_string_free(signal_name); | ||||
|     } | ||||
| 
 | ||||
|     flipper_format_free(ff); | ||||
| @ -94,7 +93,7 @@ bool infrared_brute_force_start( | ||||
|         if(record->value.index == index) { | ||||
|             *record_count = record->value.count; | ||||
|             if(*record_count) { | ||||
|                 string_set(brute_force->current_record_name, record->key); | ||||
|                 furi_string_set(brute_force->current_record_name, record->key); | ||||
|             } | ||||
|             break; | ||||
|         } | ||||
| @ -118,7 +117,7 @@ bool infrared_brute_force_is_started(InfraredBruteForce* brute_force) { | ||||
| 
 | ||||
| void infrared_brute_force_stop(InfraredBruteForce* brute_force) { | ||||
|     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); | ||||
|     flipper_format_free(brute_force->ff); | ||||
|     brute_force->current_signal = NULL; | ||||
| @ -142,10 +141,10 @@ void infrared_brute_force_add_record( | ||||
|     uint32_t index, | ||||
|     const char* name) { | ||||
|     InfraredBruteForceRecord value = {.index = index, .count = 0}; | ||||
|     string_t key; | ||||
|     string_init_set_str(key, name); | ||||
|     FuriString* key; | ||||
|     key = furi_string_alloc_set(name); | ||||
|     InfraredBruteForceRecordDict_set_at(brute_force->records, key, value); | ||||
|     string_clear(key); | ||||
|     furi_string_free(key); | ||||
| } | ||||
| 
 | ||||
| void infrared_brute_force_reset(InfraredBruteForce* brute_force) { | ||||
|  | ||||
| @ -1,4 +1,3 @@ | ||||
| #include <m-string.h> | ||||
| #include <cli/cli.h> | ||||
| #include <infrared.h> | ||||
| #include <infrared_worker.h> | ||||
| @ -10,13 +9,13 @@ | ||||
| 
 | ||||
| #define INFRARED_CLI_BUF_SIZE 10 | ||||
| 
 | ||||
| static void infrared_cli_start_ir_rx(Cli* cli, string_t args); | ||||
| static void infrared_cli_start_ir_tx(Cli* cli, string_t args); | ||||
| static void infrared_cli_process_decode(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, FuriString* args); | ||||
| static void infrared_cli_process_decode(Cli* cli, FuriString* args); | ||||
| 
 | ||||
| static const struct { | ||||
|     const char* cmd; | ||||
|     void (*process_function)(Cli* cli, string_t args); | ||||
|     void (*process_function)(Cli* cli, FuriString* args); | ||||
| } infrared_cli_commands[] = { | ||||
|     {.cmd = "rx", .process_function = infrared_cli_start_ir_rx}, | ||||
|     {.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(args); | ||||
|     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); | ||||
| } | ||||
| 
 | ||||
| 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); | ||||
|     const char* str = string_get_cstr(args); | ||||
|     const char* str = furi_string_get_cstr(args); | ||||
|     InfraredSignal* signal = infrared_signal_alloc(); | ||||
| 
 | ||||
|     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(); | ||||
|     InfraredDecoderHandler* decoder = infrared_alloc_decoder(); | ||||
| 
 | ||||
|     string_t tmp; | ||||
|     string_init(tmp); | ||||
|     FuriString* tmp; | ||||
|     tmp = furi_string_alloc(); | ||||
| 
 | ||||
|     while(infrared_signal_read(signal, input_file, tmp)) { | ||||
|         ret = false; | ||||
| @ -242,7 +241,7 @@ static bool infrared_cli_decode_file(FlipperFormat* input_file, FlipperFormat* o | ||||
|         } | ||||
|         if(!infrared_signal_is_raw(signal)) { | ||||
|             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; | ||||
|             } else { | ||||
|                 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); | ||||
|         printf("Raw signal: %s, %u samples\r\n", string_get_cstr(tmp), raw_signal->timings_size); | ||||
|         if(!infrared_cli_decode_raw_signal(raw_signal, decoder, output_file, string_get_cstr(tmp))) | ||||
|         printf( | ||||
|             "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; | ||||
|         ret = true; | ||||
|     } | ||||
| 
 | ||||
|     infrared_free_decoder(decoder); | ||||
|     infrared_signal_free(signal); | ||||
|     string_clear(tmp); | ||||
|     furi_string_free(tmp); | ||||
| 
 | ||||
|     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); | ||||
|     Storage* storage = furi_record_open(RECORD_STORAGE); | ||||
|     FlipperFormat* input_file = flipper_format_buffered_file_alloc(storage); | ||||
|     FlipperFormat* output_file = NULL; | ||||
| 
 | ||||
|     uint32_t version; | ||||
|     string_t tmp, header, input_path, output_path; | ||||
|     string_init(tmp); | ||||
|     string_init(header); | ||||
|     string_init(input_path); | ||||
|     string_init(output_path); | ||||
|     FuriString *tmp, *header, *input_path, *output_path; | ||||
|     tmp = furi_string_alloc(); | ||||
|     header = furi_string_alloc(); | ||||
|     input_path = furi_string_alloc(); | ||||
|     output_path = furi_string_alloc(); | ||||
| 
 | ||||
|     do { | ||||
|         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; | ||||
|         } | ||||
|         args_read_probably_quoted_string_and_trim(args, output_path); | ||||
|         if(!flipper_format_buffered_file_open_existing(input_file, string_get_cstr(input_path))) { | ||||
|             printf("Failed to open file for reading: \"%s\"\r\n", string_get_cstr(input_path)); | ||||
|         if(!flipper_format_buffered_file_open_existing( | ||||
|                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; | ||||
|         } | ||||
|         if(!flipper_format_read_header(input_file, header, &version) || | ||||
|            (!string_start_with_str_p(header, "IR")) || version != 1) { | ||||
|             printf("Invalid or corrupted input file: \"%s\"\r\n", string_get_cstr(input_path)); | ||||
|            (!furi_string_start_with_str(header, "IR")) || version != 1) { | ||||
|             printf( | ||||
|                 "Invalid or corrupted input file: \"%s\"\r\n", furi_string_get_cstr(input_path)); | ||||
|             break; | ||||
|         } | ||||
|         if(!string_empty_p(output_path)) { | ||||
|             printf("Writing output to file: \"%s\"\r\n", string_get_cstr(output_path)); | ||||
|         if(!furi_string_empty(output_path)) { | ||||
|             printf("Writing output to file: \"%s\"\r\n", furi_string_get_cstr(output_path)); | ||||
|             output_file = flipper_format_file_alloc(storage); | ||||
|         } | ||||
|         if(output_file && | ||||
|            !flipper_format_file_open_always(output_file, string_get_cstr(output_path))) { | ||||
|             printf("Failed to open file for writing: \"%s\"\r\n", 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", furi_string_get_cstr(output_path)); | ||||
|             break; | ||||
|         } | ||||
|         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; | ||||
|         } | ||||
|         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"); | ||||
|     } while(false); | ||||
| 
 | ||||
|     string_clear(tmp); | ||||
|     string_clear(header); | ||||
|     string_clear(input_path); | ||||
|     string_clear(output_path); | ||||
|     furi_string_free(tmp); | ||||
|     furi_string_free(header); | ||||
|     furi_string_free(input_path); | ||||
|     furi_string_free(output_path); | ||||
| 
 | ||||
|     flipper_format_free(input_file); | ||||
|     if(output_file) flipper_format_free(output_file); | ||||
|     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); | ||||
|     if(furi_hal_infrared_is_busy()) { | ||||
|         printf("INFRARED is busy. Exiting."); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     string_t command; | ||||
|     string_init(command); | ||||
|     FuriString* command; | ||||
|     command = furi_string_alloc(); | ||||
|     args_read_string_and_trim(args, command); | ||||
| 
 | ||||
|     size_t i = 0; | ||||
|     for(; i < COUNT_OF(infrared_cli_commands); ++i) { | ||||
|         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; | ||||
|         } | ||||
|     } | ||||
| @ -346,7 +353,7 @@ static void infrared_cli_start_ir(Cli* cli, string_t args, void* context) { | ||||
|         infrared_cli_print_usage(); | ||||
|     } | ||||
| 
 | ||||
|     string_clear(command); | ||||
|     furi_string_free(command); | ||||
| } | ||||
| void infrared_on_system_start() { | ||||
| #ifdef SRV_CLI | ||||
|  | ||||
| @ -96,7 +96,7 @@ struct Infrared { | ||||
|     Loading* loading; | ||||
|     InfraredProgressView* progress; | ||||
| 
 | ||||
|     string_t file_path; | ||||
|     FuriString* file_path; | ||||
|     char text_store[INFRARED_TEXT_STORE_NUM][INFRARED_TEXT_STORE_SIZE + 1]; | ||||
|     InfraredAppState app_state; | ||||
| 
 | ||||
|  | ||||
| @ -3,7 +3,6 @@ | ||||
| #include <stdbool.h> | ||||
| #include <stddef.h> | ||||
| #include <stdlib.h> | ||||
| #include <m-string.h> | ||||
| #include <m-array.h> | ||||
| #include <toolbox/path.h> | ||||
| #include <storage/storage.h> | ||||
| @ -15,8 +14,8 @@ ARRAY_DEF(InfraredButtonArray, InfraredRemoteButton*, M_PTR_OPLIST); | ||||
| 
 | ||||
| struct InfraredRemote { | ||||
|     InfraredButtonArray_t buttons; | ||||
|     string_t name; | ||||
|     string_t path; | ||||
|     FuriString* name; | ||||
|     FuriString* path; | ||||
| }; | ||||
| 
 | ||||
| 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* remote = malloc(sizeof(InfraredRemote)); | ||||
|     InfraredButtonArray_init(remote->buttons); | ||||
|     string_init(remote->name); | ||||
|     string_init(remote->path); | ||||
|     remote->name = furi_string_alloc(); | ||||
|     remote->path = furi_string_alloc(); | ||||
|     return remote; | ||||
| } | ||||
| 
 | ||||
| void infrared_remote_free(InfraredRemote* remote) { | ||||
|     infrared_remote_clear_buttons(remote); | ||||
|     InfraredButtonArray_clear(remote->buttons); | ||||
|     string_clear(remote->path); | ||||
|     string_clear(remote->name); | ||||
|     furi_string_free(remote->path); | ||||
|     furi_string_free(remote->name); | ||||
|     free(remote); | ||||
| } | ||||
| 
 | ||||
| void infrared_remote_reset(InfraredRemote* remote) { | ||||
|     infrared_remote_clear_buttons(remote); | ||||
|     string_reset(remote->name); | ||||
|     string_reset(remote->path); | ||||
|     furi_string_reset(remote->name); | ||||
|     furi_string_reset(remote->path); | ||||
| } | ||||
| 
 | ||||
| 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) { | ||||
|     return string_get_cstr(remote->name); | ||||
|     return furi_string_get_cstr(remote->name); | ||||
| } | ||||
| 
 | ||||
| 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) { | ||||
|     return string_get_cstr(remote->path); | ||||
|     return furi_string_get_cstr(remote->path); | ||||
| } | ||||
| 
 | ||||
| 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) { | ||||
|     Storage* storage = furi_record_open(RECORD_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); | ||||
| 
 | ||||
| @ -138,33 +137,33 @@ bool infrared_remote_store(InfraredRemote* remote) { | ||||
|     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); | ||||
|     FlipperFormat* ff = flipper_format_buffered_file_alloc(storage); | ||||
| 
 | ||||
|     string_t buf; | ||||
|     string_init(buf); | ||||
|     FuriString* buf; | ||||
|     buf = furi_string_alloc(); | ||||
| 
 | ||||
|     FURI_LOG_I(TAG, "load file: \'%s\'", string_get_cstr(path)); | ||||
|     bool success = flipper_format_buffered_file_open_existing(ff, 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, furi_string_get_cstr(path)); | ||||
| 
 | ||||
|     if(success) { | ||||
|         uint32_t 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) { | ||||
|         path_extract_filename(path, buf, true); | ||||
|         infrared_remote_clear_buttons(remote); | ||||
|         infrared_remote_set_name(remote, string_get_cstr(buf)); | ||||
|         infrared_remote_set_path(remote, string_get_cstr(path)); | ||||
|         infrared_remote_set_name(remote, furi_string_get_cstr(buf)); | ||||
|         infrared_remote_set_path(remote, furi_string_get_cstr(path)); | ||||
| 
 | ||||
|         for(bool can_read = true; can_read;) { | ||||
|             InfraredRemoteButton* button = infrared_remote_button_alloc(); | ||||
|             can_read = infrared_signal_read(infrared_remote_button_get_signal(button), ff, buf); | ||||
|             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); | ||||
|             } else { | ||||
|                 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); | ||||
|     furi_record_close(RECORD_STORAGE); | ||||
|     return success; | ||||
| @ -181,7 +180,7 @@ bool infrared_remote_load(InfraredRemote* remote, string_t path) { | ||||
| bool infrared_remote_remove(InfraredRemote* remote) { | ||||
|     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); | ||||
| 
 | ||||
|     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_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); | ||||
|  | ||||
| @ -1,32 +1,31 @@ | ||||
| #include "infrared_remote_button.h" | ||||
| 
 | ||||
| #include <stdlib.h> | ||||
| #include <m-string.h> | ||||
| 
 | ||||
| struct InfraredRemoteButton { | ||||
|     string_t name; | ||||
|     FuriString* name; | ||||
|     InfraredSignal* signal; | ||||
| }; | ||||
| 
 | ||||
| InfraredRemoteButton* infrared_remote_button_alloc() { | ||||
|     InfraredRemoteButton* button = malloc(sizeof(InfraredRemoteButton)); | ||||
|     string_init(button->name); | ||||
|     button->name = furi_string_alloc(); | ||||
|     button->signal = infrared_signal_alloc(); | ||||
|     return button; | ||||
| } | ||||
| 
 | ||||
| void infrared_remote_button_free(InfraredRemoteButton* button) { | ||||
|     string_clear(button->name); | ||||
|     furi_string_free(button->name); | ||||
|     infrared_signal_free(button->signal); | ||||
|     free(button); | ||||
| } | ||||
| 
 | ||||
| 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) { | ||||
|     return string_get_cstr(button->name); | ||||
|     return furi_string_get_cstr(button->name); | ||||
| } | ||||
| 
 | ||||
| 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)) { | ||||
|         FURI_LOG_E( | ||||
|             TAG, | ||||
|             "Frequency is out of range (%lX - %lX): %lX", | ||||
|             "Frequency is out of range (%X - %X): %lX", | ||||
|             INFRARED_MIN_FREQUENCY, | ||||
|             INFRARED_MAX_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)) { | ||||
|         FURI_LOG_E( | ||||
|             TAG, | ||||
|             "Timings amount is out of range (0 - %lX): %lX", | ||||
|             "Timings amount is out of range (0 - %X): %X", | ||||
|             MAX_TIMINGS_AMOUNT, | ||||
|             raw->timings_size); | ||||
|         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) { | ||||
|     string_t buf; | ||||
|     string_init(buf); | ||||
|     FuriString* buf; | ||||
|     buf = furi_string_alloc(); | ||||
|     bool success = false; | ||||
| 
 | ||||
|     do { | ||||
|         if(!flipper_format_read_string(ff, "protocol", buf)) break; | ||||
| 
 | ||||
|         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) && | ||||
|                   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); | ||||
|     } while(0); | ||||
| 
 | ||||
|     string_clear(buf); | ||||
|     furi_string_free(buf); | ||||
|     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) { | ||||
|     string_t tmp; | ||||
|     string_init(tmp); | ||||
|     FuriString* tmp = furi_string_alloc(); | ||||
| 
 | ||||
|     bool success = false; | ||||
| 
 | ||||
|     do { | ||||
|         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); | ||||
|         } else if(string_equal_p(tmp, "parsed")) { | ||||
|         } else if(furi_string_equal(tmp, "parsed")) { | ||||
|             success = infrared_signal_read_message(signal, ff); | ||||
|         } else { | ||||
|             FURI_LOG_E(TAG, "Unknown signal type"); | ||||
|         } | ||||
|     } while(false); | ||||
| 
 | ||||
|     string_clear(tmp); | ||||
|     furi_string_free(tmp); | ||||
|     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) { | ||||
|     string_t tmp; | ||||
|     string_init(tmp); | ||||
| bool infrared_signal_read(InfraredSignal* signal, FlipperFormat* ff, FuriString* name) { | ||||
|     FuriString* tmp = furi_string_alloc(); | ||||
| 
 | ||||
|     bool success = false; | ||||
| 
 | ||||
|     do { | ||||
|         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; | ||||
|         success = true; | ||||
|     } while(0); | ||||
| 
 | ||||
|     string_clear(tmp); | ||||
|     furi_string_free(tmp); | ||||
|     return success; | ||||
| } | ||||
| 
 | ||||
| bool infrared_signal_search_and_read( | ||||
|     InfraredSignal* signal, | ||||
|     FlipperFormat* ff, | ||||
|     const string_t name) { | ||||
|     const FuriString* name) { | ||||
|     bool success = false; | ||||
|     string_t tmp; | ||||
|     string_init(tmp); | ||||
|     FuriString* tmp = furi_string_alloc(); | ||||
| 
 | ||||
|     do { | ||||
|         bool is_name_found = false; | ||||
|         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; | ||||
| @ -281,7 +280,7 @@ bool infrared_signal_search_and_read( | ||||
|         success = true; | ||||
|     } while(false); | ||||
| 
 | ||||
|     string_clear(tmp); | ||||
|     furi_string_free(tmp); | ||||
|     return success; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -36,10 +36,10 @@ void infrared_signal_set_message(InfraredSignal* signal, const InfraredMessage* | ||||
| InfraredMessage* infrared_signal_get_message(InfraredSignal* signal); | ||||
| 
 | ||||
| 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( | ||||
|     InfraredSignal* signal, | ||||
|     FlipperFormat* ff, | ||||
|     const string_t name); | ||||
|     const FuriString* name); | ||||
| 
 | ||||
| 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; | ||||
|                 if(infrared_brute_force_start( | ||||
|                        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); | ||||
|                 } else { | ||||
|                     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; | ||||
|         strncpy(infrared->text_store[0], infrared_remote_get_name(remote), enter_name_length); | ||||
| 
 | ||||
|         string_t folder_path; | ||||
|         string_init(folder_path); | ||||
|         FuriString* folder_path; | ||||
|         folder_path = furi_string_alloc(); | ||||
| 
 | ||||
|         if(string_end_with_str_p(infrared->file_path, INFRARED_APP_EXTENSION)) { | ||||
|             path_extract_dirname(string_get_cstr(infrared->file_path), folder_path); | ||||
|         if(furi_string_end_with(infrared->file_path, INFRARED_APP_EXTENSION)) { | ||||
|             path_extract_dirname(furi_string_get_cstr(infrared->file_path), folder_path); | ||||
|         } | ||||
| 
 | ||||
|         ValidatorIsFile* validator_is_file = validator_is_file_alloc_init( | ||||
|             string_get_cstr(folder_path), | ||||
|             furi_string_get_cstr(folder_path), | ||||
|             INFRARED_APP_EXTENSION, | ||||
|             infrared_remote_get_name(remote)); | ||||
|         text_input_set_validator(text_input, validator_is_file_callback, validator_is_file); | ||||
| 
 | ||||
|         string_clear(folder_path); | ||||
|         furi_string_free(folder_path); | ||||
|     } else { | ||||
|         furi_assert(0); | ||||
|     } | ||||
|  | ||||
| @ -50,8 +50,10 @@ bool infrared_scene_learn_enter_name_on_event(void* context, SceneManagerEvent e | ||||
|             if(success) { | ||||
|                 scene_manager_next_scene(scene_manager, InfraredSceneLearnDone); | ||||
|             } else { | ||||
|                 scene_manager_search_and_switch_to_previous_scene( | ||||
|                     scene_manager, InfraredSceneRemoteList); | ||||
|                 dialog_message_show_storage_error(infrared->dialogs, "Failed to save file"); | ||||
|                 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; | ||||
|         } | ||||
|  | ||||
| @ -42,7 +42,7 @@ bool infrared_scene_rpc_on_event(void* context, SceneManagerEvent event) { | ||||
|             bool result = false; | ||||
|             const char* arg = rpc_system_app_get_data(infrared->rpc_ctx); | ||||
|             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); | ||||
|                 if(result) { | ||||
|                     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); | ||||
|             consumed = true; | ||||
|         } 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); | ||||
|             consumed = true; | ||||
|         } else if(submenu_index == SubmenuIndexDebug) { | ||||
|  | ||||
| @ -4,7 +4,6 @@ | ||||
| #include "gui/canvas.h" | ||||
| #include "gui/view.h" | ||||
| #include "input/input.h" | ||||
| #include "m-string.h" | ||||
| #include <gui/elements.h> | ||||
| #include <furi.h> | ||||
| #include "infrared_progress_view.h" | ||||
|  | ||||
| @ -36,9 +36,9 @@ static LfRfid* lfrfid_alloc() { | ||||
|     lfrfid->storage = furi_record_open(RECORD_STORAGE); | ||||
|     lfrfid->dialogs = furi_record_open(RECORD_DIALOGS); | ||||
| 
 | ||||
|     string_init(lfrfid->file_name); | ||||
|     string_init(lfrfid->raw_file_name); | ||||
|     string_init_set_str(lfrfid->file_path, LFRFID_APP_FOLDER); | ||||
|     lfrfid->file_name = furi_string_alloc(); | ||||
|     lfrfid->raw_file_name = furi_string_alloc(); | ||||
|     lfrfid->file_path = furi_string_alloc_set(LFRFID_APP_FOLDER); | ||||
| 
 | ||||
|     lfrfid->dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax); | ||||
| 
 | ||||
| @ -104,9 +104,9 @@ static LfRfid* lfrfid_alloc() { | ||||
| static void lfrfid_free(LfRfid* lfrfid) { | ||||
|     furi_assert(lfrfid); | ||||
| 
 | ||||
|     string_clear(lfrfid->raw_file_name); | ||||
|     string_clear(lfrfid->file_name); | ||||
|     string_clear(lfrfid->file_path); | ||||
|     furi_string_free(lfrfid->raw_file_name); | ||||
|     furi_string_free(lfrfid->file_name); | ||||
|     furi_string_free(lfrfid->file_path); | ||||
|     protocol_dict_free(lfrfid->dict); | ||||
| 
 | ||||
|     lfrfid_worker_free(lfrfid->lfworker); | ||||
| @ -183,7 +183,7 @@ int32_t lfrfid_app(void* p) { | ||||
|                 app->view_dispatcher, app->gui, ViewDispatcherTypeDesktop); | ||||
|             scene_manager_next_scene(app->scene_manager, LfRfidSceneRpc); | ||||
|         } else { | ||||
|             string_set_str(app->file_path, args); | ||||
|             furi_string_set(app->file_path, args); | ||||
|             lfrfid_load_key_data(app, app->file_path, true); | ||||
|             view_dispatcher_attach_to_gui( | ||||
|                 app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); | ||||
| @ -210,13 +210,13 @@ bool lfrfid_save_key(LfRfid* app) { | ||||
| 
 | ||||
|     lfrfid_make_app_folder(app); | ||||
| 
 | ||||
|     if(string_end_with_str_p(app->file_path, LFRFID_APP_EXTENSION)) { | ||||
|         size_t filename_start = string_search_rchar(app->file_path, '/'); | ||||
|         string_left(app->file_path, filename_start); | ||||
|     if(furi_string_end_with(app->file_path, LFRFID_APP_EXTENSION)) { | ||||
|         size_t filename_start = furi_string_search_rchar(app->file_path, '/'); | ||||
|         furi_string_left(app->file_path, filename_start); | ||||
|     } | ||||
| 
 | ||||
|     string_cat_printf( | ||||
|         app->file_path, "/%s%s", string_get_cstr(app->file_name), LFRFID_APP_EXTENSION); | ||||
|     furi_string_cat_printf( | ||||
|         app->file_path, "/%s%s", furi_string_get_cstr(app->file_name), LFRFID_APP_EXTENSION); | ||||
| 
 | ||||
|     result = lfrfid_save_key_data(app, app->file_path); | ||||
|     return result; | ||||
| @ -242,14 +242,14 @@ bool lfrfid_load_key_from_file_select(LfRfid* app) { | ||||
| bool lfrfid_delete_key(LfRfid* 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; | ||||
| 
 | ||||
|     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; | ||||
| 
 | ||||
|         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; | ||||
| } | ||||
| 
 | ||||
| bool lfrfid_save_key_data(LfRfid* app, string_t path) { | ||||
|     bool result = lfrfid_dict_file_save(app->dict, app->protocol_id, string_get_cstr(path)); | ||||
| bool lfrfid_save_key_data(LfRfid* app, FuriString* path) { | ||||
|     bool result = lfrfid_dict_file_save(app->dict, app->protocol_id, furi_string_get_cstr(path)); | ||||
| 
 | ||||
|     if(!result) { | ||||
|         dialog_message_show_storage_error(app->dialogs, "Cannot save\nkey file"); | ||||
|  | ||||
| @ -14,7 +14,7 @@ | ||||
| #include <lfrfid/lfrfid_raw_file.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
 | ||||
| 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); | ||||
| } | ||||
| 
 | ||||
| static void lfrfid_cli_read(Cli* cli, string_t args) { | ||||
|     string_t type_string; | ||||
|     string_init(type_string); | ||||
| static void lfrfid_cli_read(Cli* cli, FuriString* args) { | ||||
|     FuriString* type_string; | ||||
|     type_string = furi_string_alloc(); | ||||
|     LFRFIDWorkerReadType type = LFRFIDWorkerReadTypeAuto; | ||||
| 
 | ||||
|     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
 | ||||
|             type = LFRFIDWorkerReadTypeASKOnly; | ||||
|         } else if( | ||||
|             string_cmp_str(type_string, "indala") == 0 || | ||||
|             string_cmp_str(type_string, "psk") == 0) { | ||||
|             furi_string_cmp_str(type_string, "indala") == 0 || | ||||
|             furi_string_cmp_str(type_string, "psk") == 0) { | ||||
|             // psk
 | ||||
|             type = LFRFIDWorkerReadTypePSKOnly; | ||||
|         } else { | ||||
|             lfrfid_cli_print_usage(); | ||||
|             string_clear(type_string); | ||||
|             furi_string_free(type_string); | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
|     string_clear(type_string); | ||||
|     furi_string_free(type_string); | ||||
| 
 | ||||
|     ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax); | ||||
|     LFRFIDWorker* worker = lfrfid_worker_alloc(dict); | ||||
| @ -111,13 +112,13 @@ static void lfrfid_cli_read(Cli* cli, string_t args) { | ||||
|         printf("\r\n"); | ||||
|         free(data); | ||||
| 
 | ||||
|         string_t info; | ||||
|         string_init(info); | ||||
|         FuriString* info; | ||||
|         info = furi_string_alloc(); | ||||
|         protocol_dict_render_data(dict, info, context.protocol); | ||||
|         if(!string_empty_p(info)) { | ||||
|             printf("%s\r\n", string_get_cstr(info)); | ||||
|         if(!furi_string_empty(info)) { | ||||
|             printf("%s\r\n", furi_string_get_cstr(info)); | ||||
|         } | ||||
|         string_clear(info); | ||||
|         furi_string_free(info); | ||||
|     } | ||||
| 
 | ||||
|     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); | ||||
| } | ||||
| 
 | ||||
| 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; | ||||
|     string_t protocol_name, data_text; | ||||
|     string_init(protocol_name); | ||||
|     string_init(data_text); | ||||
|     FuriString *protocol_name, *data_text; | ||||
|     protocol_name = furi_string_alloc(); | ||||
|     data_text = furi_string_alloc(); | ||||
|     size_t data_size = protocol_dict_get_max_data_size(dict); | ||||
|     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
 | ||||
|         *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) { | ||||
|             printf( | ||||
|                 "Unknown protocol: %s\r\n" | ||||
|                 "Available protocols:\r\n", | ||||
|                 string_get_cstr(protocol_name)); | ||||
|                 furi_string_get_cstr(protocol_name)); | ||||
| 
 | ||||
|             for(ProtocolId i = 0; i < LFRFIDProtocolMax; i++) { | ||||
|                 printf( | ||||
| @ -177,8 +178,8 @@ static bool lfrfid_cli_parse_args(string_t args, ProtocolDict* dict, ProtocolId* | ||||
|     } while(false); | ||||
| 
 | ||||
|     free(data); | ||||
|     string_clear(protocol_name); | ||||
|     string_clear(data_text); | ||||
|     furi_string_free(protocol_name); | ||||
|     furi_string_free(data_text); | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| @ -188,7 +189,7 @@ static void lfrfid_cli_write_callback(LFRFIDWorkerWriteResult result, void* ctx) | ||||
|     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); | ||||
|     ProtocolId protocol; | ||||
| 
 | ||||
| @ -235,7 +236,7 @@ static void lfrfid_cli_write(Cli* cli, string_t args) { | ||||
|     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); | ||||
|     ProtocolId protocol; | ||||
| 
 | ||||
| @ -261,11 +262,11 @@ static void lfrfid_cli_emulate(Cli* cli, string_t args) { | ||||
|     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); | ||||
|     string_t filepath, info_string; | ||||
|     string_init(filepath); | ||||
|     string_init(info_string); | ||||
|     FuriString *filepath, *info_string; | ||||
|     filepath = furi_string_alloc(); | ||||
|     info_string = furi_string_alloc(); | ||||
|     Storage* storage = furi_record_open(RECORD_STORAGE); | ||||
|     LFRFIDRawFile* file = lfrfid_raw_file_alloc(storage); | ||||
| 
 | ||||
| @ -278,7 +279,7 @@ static void lfrfid_cli_raw_analyze(Cli* cli, string_t args) { | ||||
|             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"); | ||||
|             break; | ||||
|         } | ||||
| @ -308,10 +309,10 @@ static void lfrfid_cli_raw_analyze(Cli* cli, string_t args) { | ||||
|                     warn = true; | ||||
|                 } | ||||
| 
 | ||||
|                 string_printf(info_string, "[%ld %ld]", pulse, duration); | ||||
|                 printf("%-16s", string_get_cstr(info_string)); | ||||
|                 string_printf(info_string, "[%ld %ld]", pulse, duration - pulse); | ||||
|                 printf("%-16s", string_get_cstr(info_string)); | ||||
|                 furi_string_printf(info_string, "[%ld %ld]", pulse, duration); | ||||
|                 printf("%-16s", furi_string_get_cstr(info_string)); | ||||
|                 furi_string_printf(info_string, "[%ld %ld]", pulse, duration - pulse); | ||||
|                 printf("%-16s", furi_string_get_cstr(info_string)); | ||||
| 
 | ||||
|                 if(warn) { | ||||
|                     printf(" <<----"); | ||||
| @ -366,7 +367,7 @@ static void lfrfid_cli_raw_analyze(Cli* cli, string_t args) { | ||||
|             printf("]\r\n"); | ||||
| 
 | ||||
|             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); | ||||
|         } else { | ||||
| @ -376,8 +377,8 @@ static void lfrfid_cli_raw_analyze(Cli* cli, string_t args) { | ||||
|         protocol_dict_free(dict); | ||||
|     } while(false); | ||||
| 
 | ||||
|     string_clear(filepath); | ||||
|     string_clear(info_string); | ||||
|     furi_string_free(filepath); | ||||
|     furi_string_free(info_string); | ||||
|     lfrfid_raw_file_free(file); | ||||
|     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); | ||||
| } | ||||
| 
 | ||||
| static void lfrfid_cli_raw_read(Cli* cli, string_t args) { | ||||
| static void lfrfid_cli_raw_read(Cli* cli, FuriString* args) { | ||||
|     UNUSED(cli); | ||||
| 
 | ||||
|     string_t filepath, type_string; | ||||
|     string_init(filepath); | ||||
|     string_init(type_string); | ||||
|     FuriString *filepath, *type_string; | ||||
|     filepath = furi_string_alloc(); | ||||
|     type_string = furi_string_alloc(); | ||||
|     LFRFIDWorkerReadType type = LFRFIDWorkerReadTypeAuto; | ||||
| 
 | ||||
|     do { | ||||
|         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
 | ||||
|                 type = LFRFIDWorkerReadTypeASKOnly; | ||||
|             } else if( | ||||
|                 string_cmp_str(type_string, "indala") == 0 || | ||||
|                 string_cmp_str(type_string, "psk") == 0) { | ||||
|                 furi_string_cmp_str(type_string, "indala") == 0 || | ||||
|                 furi_string_cmp_str(type_string, "psk") == 0) { | ||||
|                 // psk
 | ||||
|                 type = LFRFIDWorkerReadTypePSKOnly; | ||||
|             } else { | ||||
| @ -430,7 +431,7 @@ static void lfrfid_cli_raw_read(Cli* cli, string_t args) { | ||||
|                                          (1 << LFRFIDWorkerReadRawOverrun); | ||||
| 
 | ||||
|         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) { | ||||
|             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); | ||||
| 
 | ||||
|     string_clear(filepath); | ||||
|     string_clear(type_string); | ||||
|     furi_string_free(filepath); | ||||
|     furi_string_free(type_string); | ||||
| } | ||||
| 
 | ||||
| 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); | ||||
| } | ||||
| 
 | ||||
| static void lfrfid_cli_raw_emulate(Cli* cli, string_t args) { | ||||
| static void lfrfid_cli_raw_emulate(Cli* cli, FuriString* args) { | ||||
|     UNUSED(cli); | ||||
| 
 | ||||
|     string_t filepath; | ||||
|     string_init(filepath); | ||||
|     FuriString* filepath; | ||||
|     filepath = furi_string_alloc(); | ||||
|     Storage* storage = furi_record_open(RECORD_STORAGE); | ||||
| 
 | ||||
|     do { | ||||
| @ -488,8 +489,8 @@ static void lfrfid_cli_raw_emulate(Cli* cli, string_t args) { | ||||
|             break; | ||||
|         } | ||||
| 
 | ||||
|         if(!storage_file_exists(storage, string_get_cstr(filepath))) { | ||||
|             printf("File not found: \"%s\"\r\n", string_get_cstr(filepath)); | ||||
|         if(!storage_file_exists(storage, furi_string_get_cstr(filepath))) { | ||||
|             printf("File not found: \"%s\"\r\n", furi_string_get_cstr(filepath)); | ||||
|             break; | ||||
|         } | ||||
| 
 | ||||
| @ -505,7 +506,7 @@ static void lfrfid_cli_raw_emulate(Cli* cli, string_t args) { | ||||
|                                          (1 << LFRFIDWorkerEmulateRawOverrun); | ||||
| 
 | ||||
|         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) { | ||||
|             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); | ||||
| 
 | ||||
|     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); | ||||
|     string_t cmd; | ||||
|     string_init(cmd); | ||||
|     FuriString* cmd; | ||||
|     cmd = furi_string_alloc(); | ||||
| 
 | ||||
|     if(!args_read_string_and_trim(args, cmd)) { | ||||
|         string_clear(cmd); | ||||
|         furi_string_free(cmd); | ||||
|         lfrfid_cli_print_usage(); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     if(string_cmp_str(cmd, "read") == 0) { | ||||
|     if(furi_string_cmp_str(cmd, "read") == 0) { | ||||
|         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); | ||||
|     } else if(string_cmp_str(cmd, "emulate") == 0) { | ||||
|     } else if(furi_string_cmp_str(cmd, "emulate") == 0) { | ||||
|         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); | ||||
|     } 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); | ||||
|     } 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); | ||||
|     } else { | ||||
|         lfrfid_cli_print_usage(); | ||||
|     } | ||||
| 
 | ||||
|     string_clear(cmd); | ||||
|     furi_string_free(cmd); | ||||
| } | ||||
| @ -1,7 +1,5 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include "m-string.h" | ||||
| 
 | ||||
| #include <furi.h> | ||||
| #include <furi_hal.h> | ||||
| 
 | ||||
| @ -86,9 +84,9 @@ struct LfRfid { | ||||
|     Widget* widget; | ||||
| 
 | ||||
|     char text_store[LFRFID_TEXT_STORE_SIZE + 1]; | ||||
|     string_t file_path; | ||||
|     string_t file_name; | ||||
|     string_t raw_file_name; | ||||
|     FuriString* file_path; | ||||
|     FuriString* file_name; | ||||
|     FuriString* raw_file_name; | ||||
| 
 | ||||
|     ProtocolDict* dict; | ||||
|     ProtocolId protocol_id; | ||||
| @ -128,9 +126,9 @@ bool lfrfid_load_key_from_file_select(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); | ||||
| 
 | ||||
|  | ||||
| @ -4,31 +4,31 @@ void lfrfid_scene_delete_confirm_on_enter(void* context) { | ||||
|     LfRfid* app = context; | ||||
|     Widget* widget = app->widget; | ||||
| 
 | ||||
|     string_t tmp_string; | ||||
|     string_init(tmp_string); | ||||
|     FuriString* tmp_string; | ||||
|     tmp_string = furi_string_alloc(); | ||||
| 
 | ||||
|     widget_add_button_element(widget, GuiButtonTypeLeft, "Back", 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, 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); | ||||
|     uint8_t* data = (uint8_t*)malloc(size); | ||||
|     protocol_dict_get_data(app->dict, app->protocol_id, data, size); | ||||
|     for(uint8_t i = 0; i < MIN(size, (size_t)8); i++) { | ||||
|         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); | ||||
| 
 | ||||
|     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, | ||||
|         64, | ||||
| @ -39,7 +39,7 @@ void lfrfid_scene_delete_confirm_on_enter(void* context) { | ||||
|         protocol_dict_get_name(app->dict, app->protocol_id)); | ||||
| 
 | ||||
|     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) { | ||||
|  | ||||
| @ -8,8 +8,8 @@ void lfrfid_scene_emulate_on_enter(void* context) { | ||||
|     DOLPHIN_DEED(DolphinDeedRfidEmulate); | ||||
| 
 | ||||
|     popup_set_header(popup, "Emulating", 89, 30, AlignCenter, AlignTop); | ||||
|     if(!string_empty_p(app->file_name)) { | ||||
|         popup_set_text(popup, string_get_cstr(app->file_name), 89, 43, AlignCenter, AlignTop); | ||||
|     if(!furi_string_empty(app->file_name)) { | ||||
|         popup_set_text(popup, furi_string_get_cstr(app->file_name), 89, 43, AlignCenter, AlignTop); | ||||
|     } else { | ||||
|         popup_set_text( | ||||
|             popup, | ||||
|  | ||||
| @ -42,7 +42,7 @@ void lfrfid_scene_extra_actions_on_enter(void* context) { | ||||
|         submenu, scene_manager_get_scene_state(app->scene_manager, LfRfidSceneExtraActions)); | ||||
| 
 | ||||
|     // clear key
 | ||||
|     string_reset(app->file_name); | ||||
|     furi_string_reset(app->file_name); | ||||
|     app->protocol_id = PROTOCOL_NO; | ||||
|     app->read_type = LFRFIDWorkerReadTypeAuto; | ||||
| 
 | ||||
|  | ||||
| @ -4,8 +4,8 @@ void lfrfid_scene_raw_info_on_enter(void* context) { | ||||
|     LfRfid* app = context; | ||||
|     Widget* widget = app->widget; | ||||
| 
 | ||||
|     // string_t tmp_string;
 | ||||
|     // string_init(tmp_string);
 | ||||
|     // FuriString* tmp_string;
 | ||||
|     // tmp_string = furi_string_alloc();
 | ||||
| 
 | ||||
|     bool sd_exist = storage_sd_status(app->storage) == FSE_OK; | ||||
|     if(!sd_exist) { | ||||
|  | ||||
| @ -4,9 +4,9 @@ void lfrfid_scene_raw_name_on_enter(void* context) { | ||||
|     LfRfid* app = context; | ||||
|     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) { | ||||
|         lfrfid_text_store_set(app, "RfidRecord"); | ||||
|     } else { | ||||
| @ -38,7 +38,7 @@ bool lfrfid_scene_raw_name_on_event(void* context, SceneManagerEvent event) { | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         if(event.event == LfRfidEventNext) { | ||||
|             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); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @ -3,7 +3,7 @@ | ||||
| #define RAW_READ_TIME 5000 | ||||
| 
 | ||||
| typedef struct { | ||||
|     string_t string_file_name; | ||||
|     FuriString* string_file_name; | ||||
|     FuriTimer* timer; | ||||
|     bool is_psk; | ||||
|     bool error; | ||||
| @ -31,7 +31,7 @@ void lfrfid_scene_raw_read_on_enter(void* context) { | ||||
| 
 | ||||
|     LfRfidReadRawState* state = malloc(sizeof(LfRfidReadRawState)); | ||||
|     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); | ||||
|     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); | ||||
|     furi_timer_start(state->timer, RAW_READ_TIME); | ||||
|     string_printf( | ||||
|     furi_string_printf( | ||||
|         state->string_file_name, | ||||
|         "%s/%s%s", | ||||
|         LFRFID_SD_FOLDER, | ||||
|         string_get_cstr(app->raw_file_name), | ||||
|         furi_string_get_cstr(app->raw_file_name), | ||||
|         LFRFID_APP_RAW_ASK_EXTENSION); | ||||
|     popup_set_header(popup, "Reading\nRAW RFID\nASK", 89, 30, AlignCenter, AlignTop); | ||||
|     lfrfid_worker_read_raw_start( | ||||
|         app->lfworker, | ||||
|         string_get_cstr(state->string_file_name), | ||||
|         furi_string_get_cstr(state->string_file_name), | ||||
|         LFRFIDWorkerReadTypeASKOnly, | ||||
|         lfrfid_read_callback, | ||||
|         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); | ||||
|                     notification_message(app->notifications, &sequence_blink_start_yellow); | ||||
|                     lfrfid_worker_stop(app->lfworker); | ||||
|                     string_printf( | ||||
|                     furi_string_printf( | ||||
|                         state->string_file_name, | ||||
|                         "%s/%s%s", | ||||
|                         LFRFID_SD_FOLDER, | ||||
|                         string_get_cstr(app->raw_file_name), | ||||
|                         furi_string_get_cstr(app->raw_file_name), | ||||
|                         LFRFID_APP_RAW_PSK_EXTENSION); | ||||
|                     lfrfid_worker_read_raw_start( | ||||
|                         app->lfworker, | ||||
|                         string_get_cstr(state->string_file_name), | ||||
|                         furi_string_get_cstr(state->string_file_name), | ||||
|                         LFRFIDWorkerReadTypePSKOnly, | ||||
|                         lfrfid_read_callback, | ||||
|                         app); | ||||
| @ -121,6 +121,6 @@ void lfrfid_scene_raw_read_on_exit(void* context) { | ||||
|     lfrfid_worker_stop_thread(app->lfworker); | ||||
|     furi_timer_free(state->timer); | ||||
| 
 | ||||
|     string_clear(state->string_file_name); | ||||
|     furi_string_free(state->string_file_name); | ||||
|     free(state); | ||||
| } | ||||
|  | ||||
| @ -81,7 +81,7 @@ bool lfrfid_scene_read_on_event(void* context, SceneManagerEvent event) { | ||||
|             app->protocol_id = app->protocol_id_next; | ||||
|             DOLPHIN_DEED(DolphinDeedRfidReadSuccess); | ||||
|             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); | ||||
|             consumed = true; | ||||
|         } 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); | ||||
|             consumed = true; | ||||
|         } else if(event.event == SubmenuIndexSave) { | ||||
|             string_reset(app->file_name); | ||||
|             furi_string_reset(app->file_name); | ||||
|             scene_manager_next_scene(app->scene_manager, LfRfidSceneSaveName); | ||||
|             consumed = true; | ||||
|         } else if(event.event == SubmenuIndexEmulate) { | ||||
|  | ||||
| @ -4,51 +4,51 @@ void lfrfid_scene_read_success_on_enter(void* context) { | ||||
|     LfRfid* app = context; | ||||
|     Widget* widget = app->widget; | ||||
| 
 | ||||
|     string_t tmp_string; | ||||
|     string_init(tmp_string); | ||||
|     FuriString* tmp_string; | ||||
|     tmp_string = furi_string_alloc(); | ||||
| 
 | ||||
|     widget_add_button_element(widget, GuiButtonTypeLeft, "Retry", lfrfid_widget_callback, app); | ||||
|     widget_add_button_element(widget, GuiButtonTypeRight, "More", lfrfid_widget_callback, app); | ||||
| 
 | ||||
|     string_printf( | ||||
|     furi_string_printf( | ||||
|         tmp_string, | ||||
|         "%s[%s]", | ||||
|         protocol_dict_get_name(app->dict, app->protocol_id), | ||||
|         protocol_dict_get_manufacturer(app->dict, app->protocol_id)); | ||||
| 
 | ||||
|     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); | ||||
|     uint8_t* data = (uint8_t*)malloc(size); | ||||
|     protocol_dict_get_data(app->dict, app->protocol_id, data, size); | ||||
|     for(uint8_t i = 0; i < size; i++) { | ||||
|         if(i >= 9) { | ||||
|             string_cat_printf(tmp_string, ".."); | ||||
|             furi_string_cat_printf(tmp_string, ".."); | ||||
|             break; | ||||
|         } else { | ||||
|             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); | ||||
| 
 | ||||
|     string_t render_data; | ||||
|     string_init(render_data); | ||||
|     FuriString* render_data; | ||||
|     render_data = furi_string_alloc(); | ||||
|     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)); | ||||
|     string_clear(render_data); | ||||
|     furi_string_cat_printf(tmp_string, "\r\n%s", furi_string_get_cstr(render_data)); | ||||
|     furi_string_free(render_data); | ||||
| 
 | ||||
|     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); | ||||
| 
 | ||||
|     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) { | ||||
|  | ||||
| @ -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); | ||||
|             bool result = false; | ||||
|             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)) { | ||||
|                     lfrfid_worker_start_thread(app->lfworker); | ||||
|                     lfrfid_worker_emulate_start(app->lfworker, (LFRFIDProtocol)app->protocol_id); | ||||
|                     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); | ||||
| 
 | ||||
|                     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); | ||||
| 
 | ||||
|     if(need_restore) { | ||||
|         protocol_dict_set_data(app->dict, app->protocol_id, app->old_key_data, size); | ||||
|     } else { | ||||
|     if(!need_restore) { | ||||
|         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_result_callback( | ||||
| @ -41,6 +38,8 @@ bool lfrfid_scene_save_data_on_event(void* context, SceneManagerEvent event) { | ||||
|         } | ||||
|     } else if(event.type == SceneManagerEventTypeBack) { | ||||
|         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; | ||||
|  | ||||
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