Merge remote-tracking branch 'origin/release-candidate' into release
This commit is contained in:
		
						commit
						8ee66c3e9b
					
				| @ -14,7 +14,7 @@ body: | ||||
|     description: | | ||||
|       Please describe your feature request in as many details as possible. | ||||
|         - Describe what it should do. | ||||
|         - Note whetever it is to extend existing functionality or introduce new functionality. | ||||
|         - Note whether it is to extend existing functionality or introduce new functionality. | ||||
|   validations: | ||||
|     required: true | ||||
| - type: textarea | ||||
|  | ||||
							
								
								
									
										
											BIN
										
									
								
								.github/assets/dark_theme_banner.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								.github/assets/dark_theme_banner.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 48 KiB | 
							
								
								
									
										
											BIN
										
									
								
								.github/assets/light_theme_banner.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								.github/assets/light_theme_banner.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 44 KiB | 
							
								
								
									
										103
									
								
								.github/workflows/amap_analyse.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										103
									
								
								.github/workflows/amap_analyse.yml
									
									
									
									
										vendored
									
									
								
							| @ -1,103 +0,0 @@ | ||||
| name: 'Analyze .map file with Amap' | ||||
| 
 | ||||
| on: | ||||
|   push: | ||||
|     branches: | ||||
|       - dev | ||||
|       - "release*" | ||||
|     tags: | ||||
|       - '*' | ||||
|   pull_request: | ||||
| 
 | ||||
| env: | ||||
|   TARGETS: f7 | ||||
|   FBT_TOOLCHAIN_PATH: /opt | ||||
| 
 | ||||
| jobs: | ||||
|   amap_analyse: | ||||
|     if: ${{ !github.event.pull_request.head.repo.fork }} | ||||
|     runs-on: [self-hosted,FlipperZeroMacShell] | ||||
|     timeout-minutes: 15 | ||||
|     steps: | ||||
|       - name: 'Wait Build workflow' | ||||
|         uses: fountainhead/action-wait-for-check@v1.0.0 | ||||
|         id: wait-for-build | ||||
|         with: | ||||
|           token: ${{ secrets.GITHUB_TOKEN }} | ||||
|           checkName: 'main' | ||||
|           ref: ${{ github.event.pull_request.head.sha || github.sha }} | ||||
|           intervalSeconds: 20 | ||||
| 
 | ||||
|       - name: 'Check Build workflow status' | ||||
|         if: steps.wait-for-build.outputs.conclusion == 'failure' | ||||
|         run: | | ||||
|           exit 1 | ||||
| 
 | ||||
|       - name: 'Decontaminate previous build leftovers' | ||||
|         run: | | ||||
|           if [ -d .git ]; then | ||||
|             git submodule status || git checkout "$(git rev-list --max-parents=0 HEAD | tail -n 1)" | ||||
|           fi | ||||
| 
 | ||||
|       - name: 'Checkout code' | ||||
|         uses: actions/checkout@v3 | ||||
|         with: | ||||
|           fetch-depth: 0 | ||||
|           ref: ${{ github.event.pull_request.head.sha }} | ||||
| 
 | ||||
|       - name: 'Get commit details' | ||||
|         run: | | ||||
|           if [[ ${{ github.event_name }} == 'pull_request' ]]; then | ||||
|             TYPE="pull" | ||||
|           elif [[ "${{ github.ref }}" == "refs/tags/"* ]]; then | ||||
|             TYPE="tag" | ||||
|           else | ||||
|             TYPE="other" | ||||
|           fi | ||||
|           python3 scripts/get_env.py "--event_file=${{ github.event_path }}" "--type=$TYPE" | ||||
| 
 | ||||
|       - name: 'Make artifacts directory' | ||||
|         run: | | ||||
|           rm -rf artifacts | ||||
|           mkdir artifacts | ||||
| 
 | ||||
|       - 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 \ | ||||
|               -e 'ssh -p ${{ secrets.RSYNC_DEPLOY_PORT }} -i ./deploy_key' \ | ||||
|               ${{ secrets.RSYNC_DEPLOY_USER }}@${{ secrets.RSYNC_DEPLOY_HOST }}:"${{ secrets.RSYNC_DEPLOY_BASE_PATH }}${BRANCH_NAME}/" artifacts/; | ||||
|           rm ./deploy_key; | ||||
| 
 | ||||
|       - name: 'Make .map file analyze' | ||||
|         run: | | ||||
|           cd artifacts/ | ||||
|           /Applications/amap/Contents/MacOS/amap -f "flipper-z-f7-firmware-${SUFFIX}.elf.map" | ||||
| 
 | ||||
|       - name: 'Upload report to DB' | ||||
|         run: | | ||||
|           source scripts/toolchain/fbtenv.sh | ||||
|           get_size() | ||||
|           { | ||||
|             SECTION="$1"; | ||||
|             arm-none-eabi-size \ | ||||
|               -A artifacts/flipper-z-f7-firmware-$SUFFIX.elf \ | ||||
|               | grep "^$SECTION" | awk '{print $2}' | ||||
|           } | ||||
|           export BSS_SIZE="$(get_size ".bss")" | ||||
|           export TEXT_SIZE="$(get_size ".text")" | ||||
|           export RODATA_SIZE="$(get_size ".rodata")" | ||||
|           export DATA_SIZE="$(get_size ".data")" | ||||
|           export FREE_FLASH_SIZE="$(get_size ".free_flash")" | ||||
|           python3 -m pip install mariadb==1.1.4 | ||||
|           python3 scripts/amap_mariadb_insert.py \ | ||||
|             ${{ secrets.AMAP_MARIADB_USER }} \ | ||||
|             ${{ secrets.AMAP_MARIADB_PASSWORD }} \ | ||||
|             ${{ secrets.AMAP_MARIADB_HOST }} \ | ||||
|             ${{ secrets.AMAP_MARIADB_PORT }} \ | ||||
|             ${{ secrets.AMAP_MARIADB_DATABASE }} \ | ||||
|             artifacts/flipper-z-f7-firmware-$SUFFIX.elf.map.all | ||||
| 
 | ||||
							
								
								
									
										42
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										42
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
								
							| @ -30,11 +30,6 @@ jobs: | ||||
|           fetch-depth: 0 | ||||
|           ref: ${{ github.event.pull_request.head.sha }} | ||||
| 
 | ||||
|       - name: 'Make artifacts directory' | ||||
|         run: | | ||||
|           rm -rf artifacts | ||||
|           mkdir artifacts | ||||
| 
 | ||||
|       - name: 'Get commit details' | ||||
|         id: names | ||||
|         run: | | ||||
| @ -46,6 +41,15 @@ jobs: | ||||
|             TYPE="other" | ||||
|           fi | ||||
|           python3 scripts/get_env.py "--event_file=${{ github.event_path }}" "--type=$TYPE" | ||||
|           echo random_hash=$(openssl rand -base64 40 | shasum -a 256 | awk '{print $1}') >> $GITHUB_OUTPUT | ||||
|           echo "event_type=$TYPE" >> $GITHUB_OUTPUT | ||||
| 
 | ||||
|       - name: 'Make artifacts directory' | ||||
|         run: | | ||||
|           rm -rf artifacts | ||||
|           rm -rf map_analyser_files | ||||
|           mkdir artifacts | ||||
|           mkdir map_analyser_files | ||||
| 
 | ||||
|       - name: 'Bundle scripts' | ||||
|         if: ${{ !github.event.pull_request.head.repo.fork }} | ||||
| @ -82,9 +86,33 @@ jobs: | ||||
|         run: | | ||||
|           cp build/core2_firmware.tgz "artifacts/flipper-z-any-core2_firmware-${SUFFIX}.tgz" | ||||
| 
 | ||||
|       - name: 'Copy .map file' | ||||
|       - name: 'Copy map analyser files' | ||||
|         if: ${{ !github.event.pull_request.head.repo.fork }} | ||||
|         run: | | ||||
|           cp build/f7-firmware-*/firmware.elf.map "artifacts/flipper-z-f7-firmware-${SUFFIX}.elf.map" | ||||
|           cp build/f7-firmware-*/firmware.elf.map map_analyser_files/firmware.elf.map | ||||
|           cp build/f7-firmware-*/firmware.elf map_analyser_files/firmware.elf | ||||
|           cp ${{ github.event_path }} map_analyser_files/event.json | ||||
| 
 | ||||
|       - name: 'Upload map analyser files to storage' | ||||
|         if: ${{ !github.event.pull_request.head.repo.fork }} | ||||
|         uses: keithweaver/aws-s3-github-action@v1.0.0 | ||||
|         with: | ||||
|           source: map_analyser_files/ | ||||
|           destination: "s3://${{ secrets.MAP_REPORT_AWS_BUCKET }}/${{steps.names.outputs.random_hash}}" | ||||
|           aws_access_key_id: "${{ secrets.MAP_REPORT_AWS_ACCESS_KEY }}" | ||||
|           aws_secret_access_key: "${{ secrets.MAP_REPORT_AWS_SECRET_KEY }}" | ||||
|           aws_region: "${{ secrets.MAP_REPORT_AWS_REGION }}" | ||||
|           flags: --recursive | ||||
| 
 | ||||
|       - name: 'Trigger map file reporter' | ||||
|         if: ${{ !github.event.pull_request.head.repo.fork }} | ||||
|         uses: peter-evans/repository-dispatch@v2 | ||||
|         with: | ||||
|           repository: flipperdevices/flipper-map-reporter | ||||
|           token: ${{ secrets.REPOSITORY_DISPATCH_TOKEN }} | ||||
|           event-type: map-file-analyse | ||||
|           client-payload: '{"random_hash": "${{steps.names.outputs.random_hash}}", "event_type": "${{steps.names.outputs.event_type}}"}' | ||||
| 
 | ||||
| 
 | ||||
|       - name: 'Upload artifacts to update server' | ||||
|         if: ${{ !github.event.pull_request.head.repo.fork }} | ||||
|  | ||||
							
								
								
									
										31
									
								
								.github/workflows/pvs_studio.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										31
									
								
								.github/workflows/pvs_studio.yml
									
									
									
									
										vendored
									
									
								
							| @ -50,7 +50,7 @@ jobs: | ||||
| 
 | ||||
|       - name: 'Generate compile_comands.json' | ||||
|         run: | | ||||
|           ./fbt COMPACT=1 version_json proto_ver icons firmware_cdb dolphin_internal dolphin_blocking _fap_icons | ||||
|           ./fbt COMPACT=1 version_json proto_ver icons firmware_cdb dolphin_internal dolphin_blocking _fap_icons api_syms | ||||
| 
 | ||||
|       - name: 'Static code analysis' | ||||
|         run: | | ||||
| @ -58,15 +58,25 @@ jobs: | ||||
|           pvs-studio-analyzer credentials ${{ secrets.PVS_STUDIO_CREDENTIALS }} | ||||
|           pvs-studio-analyzer analyze \ | ||||
|               @.pvsoptions \ | ||||
|               -C gccarm \ | ||||
|               -j$(grep -c processor /proc/cpuinfo) \ | ||||
|               -f build/f7-firmware-DC/compile_commands.json \ | ||||
|               -o PVS-Studio.log | ||||
| 
 | ||||
|       - name: 'Convert PVS-Studio output to html page' | ||||
|         run: plog-converter -a GA:1,2,3 -t fullhtml PVS-Studio.log -o reports/${DEFAULT_TARGET}-${SUFFIX} | ||||
|       - name: 'Convert PVS-Studio output to html and detect warnings' | ||||
|         id: pvs-warn | ||||
|         run: | | ||||
|           WARNINGS=0 | ||||
|           plog-converter \ | ||||
|               -a GA:1,2,3 \ | ||||
|               -t fullhtml \ | ||||
|               --indicate-warnings \ | ||||
|               PVS-Studio.log \ | ||||
|               -o reports/${DEFAULT_TARGET}-${SUFFIX} || WARNINGS=1 | ||||
|           echo "warnings=${WARNINGS}" >> $GITHUB_OUTPUT | ||||
| 
 | ||||
|       - name: 'Upload artifacts to update server' | ||||
|         if: ${{ !github.event.pull_request.head.repo.fork }} | ||||
|         if: ${{ !github.event.pull_request.head.repo.fork && (steps.pvs-warn.outputs.warnings != 0) }} | ||||
|         run: | | ||||
|           mkdir -p ~/.ssh | ||||
|           ssh-keyscan -p ${{ secrets.RSYNC_DEPLOY_PORT }} -H ${{ secrets.RSYNC_DEPLOY_HOST }} > ~/.ssh/known_hosts | ||||
| @ -78,8 +88,8 @@ jobs: | ||||
|           rm ./deploy_key; | ||||
| 
 | ||||
|       - name: 'Find Previous Comment' | ||||
|         if: ${{ !github.event.pull_request.head.repo.fork && github.event.pull_request }} | ||||
|         uses: peter-evans/find-comment@v1 | ||||
|         if: ${{ !github.event.pull_request.head.repo.fork && github.event.pull_request && (steps.pvs-warn.outputs.warnings != 0) }} | ||||
|         uses: peter-evans/find-comment@v2 | ||||
|         id: fc | ||||
|         with: | ||||
|           issue-number: ${{ github.event.pull_request.number }} | ||||
| @ -87,7 +97,7 @@ jobs: | ||||
|           body-includes: 'PVS-Studio report for commit' | ||||
| 
 | ||||
|       - name: 'Create or update comment' | ||||
|         if: ${{ !github.event.pull_request.head.repo.fork && github.event.pull_request}} | ||||
|         if: ${{ !github.event.pull_request.head.repo.fork && github.event.pull_request && (steps.pvs-warn.outputs.warnings != 0) }} | ||||
|         uses: peter-evans/create-or-update-comment@v1 | ||||
|         with: | ||||
|           comment-id: ${{ steps.fc.outputs.comment-id }} | ||||
| @ -96,3 +106,10 @@ jobs: | ||||
|             **PVS-Studio report for commit `${{steps.names.outputs.commit_sha}}`:** | ||||
|             - [Report](https://update.flipperzero.one/builds/firmware-pvs-studio-report/${{steps.names.outputs.branch_name}}/${{steps.names.outputs.default_target}}-${{steps.names.outputs.suffix}}/index.html) | ||||
|           edit-mode: replace | ||||
| 
 | ||||
|       - name: 'Raise exception' | ||||
|         if: ${{ steps.pvs-warn.outputs.warnings != 0 }} | ||||
|         run: | | ||||
|           echo "Please fix all PVS varnings before merge" | ||||
|           exit 1 | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										69
									
								
								.github/workflows/unit_tests.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										69
									
								
								.github/workflows/unit_tests.yml
									
									
									
									
										vendored
									
									
								
							| @ -9,7 +9,7 @@ env: | ||||
|   FBT_TOOLCHAIN_PATH: /opt | ||||
| 
 | ||||
| jobs: | ||||
|   run_units_on_test_bench: | ||||
|   run_units_on_bench: | ||||
|     runs-on: [self-hosted, FlipperZeroTest] | ||||
|     steps: | ||||
|       - name: 'Decontaminate previous build leftovers' | ||||
| @ -29,81 +29,38 @@ jobs: | ||||
|         run: | | ||||
|           echo "flipper=/dev/ttyACM0" >> $GITHUB_OUTPUT | ||||
| 
 | ||||
|       - name: 'Flashing target firmware' | ||||
|         id: first_full_flash | ||||
|         run: | | ||||
|           ./fbt flash_usb_full PORT=${{steps.device.outputs.flipper}} FORCE=1 | ||||
|           source scripts/toolchain/fbtenv.sh | ||||
|           python3 scripts/testing/await_flipper.py ${{steps.device.outputs.flipper}} | ||||
| 
 | ||||
|       - name: 'Validating updater' | ||||
|         id: second_full_flash | ||||
|         if: success() | ||||
|         run: | | ||||
|           ./fbt flash_usb_full PORT=${{steps.device.outputs.flipper}} FORCE=1 | ||||
|           source scripts/toolchain/fbtenv.sh | ||||
|           python3 scripts/testing/await_flipper.py ${{steps.device.outputs.flipper}} | ||||
| 
 | ||||
|       - name: 'Flash unit tests firmware' | ||||
|         id: flashing | ||||
|         if: success() | ||||
|         run: |                                | ||||
|           ./fbt flash OPENOCD_ADAPTER_SERIAL=2A0906016415303030303032 FIRMWARE_APP_SET=unit_tests FORCE=1 | ||||
| 
 | ||||
|       - name: 'Wait for flipper to finish updating' | ||||
|         id: connect | ||||
|       - name: 'Wait for flipper and format ext' | ||||
|         id: format_ext | ||||
|         if: steps.flashing.outcome == 'success' | ||||
|         run: | | ||||
|           source scripts/toolchain/fbtenv.sh | ||||
|           python3 scripts/testing/await_flipper.py ${{steps.device.outputs.flipper}} | ||||
|           python3 scripts/storage.py -p ${{steps.device.outputs.flipper}} format_ext | ||||
| 
 | ||||
|       - name: 'Copy assets and unit tests data to flipper' | ||||
|       - name: 'Copy assets and unit data, reboot and wait for flipper' | ||||
|         id: copy | ||||
|         if: steps.connect.outcome == 'success' | ||||
|         if: steps.format_ext.outcome == 'success' | ||||
|         run: | | ||||
|           source scripts/toolchain/fbtenv.sh | ||||
|           python3 scripts/storage.py -p ${{steps.device.outputs.flipper}} -f send assets/resources /ext | ||||
|           python3 scripts/storage.py -p ${{steps.device.outputs.flipper}} -f send assets/unit_tests /ext/unit_tests | ||||
|           python3 scripts/power.py -p ${{steps.device.outputs.flipper}} reboot | ||||
|           python3 scripts/testing/await_flipper.py ${{steps.device.outputs.flipper}} | ||||
| 
 | ||||
|       - name: 'Run units and validate results' | ||||
|         id: run_units | ||||
|         if: steps.copy.outcome == 'success' | ||||
|         run: | | ||||
|           source scripts/toolchain/fbtenv.sh | ||||
|           python3 scripts/testing/units.py ${{steps.device.outputs.flipper}} | ||||
| 
 | ||||
|       - name: 'Get last release tag' | ||||
|         id: release_tag | ||||
|         if: always() | ||||
|       - name: 'Check GDB output' | ||||
|         if: failure() | ||||
|         run: | | ||||
|           echo "tag=$(git tag -l --sort=-version:refname | grep -v "rc\|RC" | head -1)" >> $GITHUB_OUTPUT | ||||
| 
 | ||||
|       - name: 'Decontaminate previous build leftovers' | ||||
|         if: always() | ||||
|         run: | | ||||
|           if [ -d .git ]; then | ||||
|             git submodule status || git checkout "$(git rev-list --max-parents=0 HEAD | tail -n 1)" | ||||
|           fi | ||||
| 
 | ||||
|       - name: 'Checkout latest release' | ||||
|         uses: actions/checkout@v3 | ||||
|         if: always() | ||||
|         with: | ||||
|           fetch-depth: 0 | ||||
|           ref: ${{ steps.release_tag.outputs.tag }} | ||||
| 
 | ||||
|       - name: 'Flash last release' | ||||
|         if: always() | ||||
|         run: | | ||||
|           ./fbt flash OPENOCD_ADAPTER_SERIAL=2A0906016415303030303032 FIRMWARE_APP_SET=unit_tests FORCE=1 | ||||
| 
 | ||||
|       - name: 'Wait for flipper to finish updating' | ||||
|         if: always() | ||||
|         run: | | ||||
|           source scripts/toolchain/fbtenv.sh | ||||
|           python3 scripts/testing/await_flipper.py ${{steps.device.outputs.flipper}} | ||||
| 
 | ||||
|       - name: 'Format flipper SD card' | ||||
|         id: format | ||||
|         if: always() | ||||
|         run: | | ||||
|           source scripts/toolchain/fbtenv.sh | ||||
|           python3 scripts/storage.py -p ${{steps.device.outputs.flipper}} format_ext | ||||
|           ./fbt gdb_trace_all OPENOCD_ADAPTER_SERIAL=2A0906016415303030303032 FIRMWARE_APP_SET=unit_tests FORCE=1 | ||||
|  | ||||
							
								
								
									
										77
									
								
								.github/workflows/updater_test.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								.github/workflows/updater_test.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,77 @@ | ||||
| name: 'Updater test' | ||||
| 
 | ||||
| on: | ||||
|   pull_request: | ||||
| 
 | ||||
| env: | ||||
|   TARGETS: f7 | ||||
|   DEFAULT_TARGET: f7 | ||||
|   FBT_TOOLCHAIN_PATH: /opt | ||||
| 
 | ||||
| jobs: | ||||
|   test_updater_on_bench: | ||||
|     runs-on: [self-hosted, FlipperZeroTest] # currently on same bench as units, needs different bench | ||||
|     steps: | ||||
|       - name: 'Decontaminate previous build leftovers' | ||||
|         run: | | ||||
|           if [ -d .git ]; then | ||||
|             git submodule status || git checkout "$(git rev-list --max-parents=0 HEAD | tail -n 1)" | ||||
|           fi | ||||
| 
 | ||||
|       - name: Checkout code | ||||
|         uses: actions/checkout@v3 | ||||
|         with: | ||||
|           fetch-depth: 0 | ||||
|           ref: ${{ github.event.pull_request.head.sha }} | ||||
| 
 | ||||
|       - name: 'Get flipper from device manager (mock)' | ||||
|         id: device | ||||
|         run: | | ||||
|           echo "flipper=/dev/ttyACM0" >> $GITHUB_OUTPUT | ||||
| 
 | ||||
|       - name: 'Flashing target firmware' | ||||
|         id: first_full_flash | ||||
|         run: | | ||||
|           source scripts/toolchain/fbtenv.sh | ||||
|           ./fbt flash_usb_full PORT=${{steps.device.outputs.flipper}} FORCE=1 | ||||
|           python3 scripts/testing/await_flipper.py ${{steps.device.outputs.flipper}} | ||||
| 
 | ||||
|       - name: 'Validating updater' | ||||
|         id: second_full_flash | ||||
|         if: success() | ||||
|         run: | | ||||
|           source scripts/toolchain/fbtenv.sh | ||||
|           ./fbt flash_usb PORT=${{steps.device.outputs.flipper}} FORCE=1 | ||||
|           python3 scripts/testing/await_flipper.py ${{steps.device.outputs.flipper}} | ||||
| 
 | ||||
|       - name: 'Get last release tag' | ||||
|         id: release_tag | ||||
|         if: failure() | ||||
|         run: | | ||||
|           echo "tag=$(git tag -l --sort=-version:refname | grep -v "rc\|RC" | head -1)" >> $GITHUB_OUTPUT | ||||
| 
 | ||||
|       - name: 'Decontaminate previous build leftovers' | ||||
|         if: failure() | ||||
|         run: | | ||||
|           if [ -d .git ]; then | ||||
|             git submodule status || git checkout "$(git rev-list --max-parents=0 HEAD | tail -n 1)" | ||||
|           fi | ||||
| 
 | ||||
|       - name: 'Checkout latest release' | ||||
|         uses: actions/checkout@v3 | ||||
|         if: failure() | ||||
|         with: | ||||
|           fetch-depth: 0 | ||||
|           ref: ${{ steps.release_tag.outputs.tag }} | ||||
| 
 | ||||
|       - name: 'Flash last release' | ||||
|         if: failure() | ||||
|         run: | | ||||
|           ./fbt flash OPENOCD_ADAPTER_SERIAL=2A0906016415303030303032 FORCE=1 | ||||
| 
 | ||||
|       - name: 'Wait for flipper and format ext' | ||||
|         if: failure() | ||||
|         run: | | ||||
|           source scripts/toolchain/fbtenv.sh | ||||
|           python3 scripts/testing/await_flipper.py ${{steps.device.outputs.flipper}} | ||||
|           python3 scripts/storage.py -p ${{steps.device.outputs.flipper}} format_ext | ||||
							
								
								
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -30,6 +30,10 @@ Brewfile.lock.json | ||||
| # Visual Studio Code | ||||
| .vscode/ | ||||
| 
 | ||||
| # Kate | ||||
| .kateproject | ||||
| .kateconfig | ||||
| 
 | ||||
| # legendary cmake's | ||||
| build | ||||
| CMakeLists.txt | ||||
|  | ||||
							
								
								
									
										23
									
								
								.pvsconfig
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								.pvsconfig
									
									
									
									
									
								
							| @ -1,4 +1,5 @@ | ||||
| # MLib macros we can't do much about. | ||||
| //-V:M_LET:1048,1044 | ||||
| //-V:M_EACH:1048,1044 | ||||
| //-V:ARRAY_DEF:760,747,568,776,729,712,654 | ||||
| //-V:LIST_DEF:760,747,568,712,729,654,776 | ||||
| @ -16,8 +17,30 @@ | ||||
| # Potentially null argument warnings | ||||
| //-V:memset:575 | ||||
| //-V:memcpy:575 | ||||
| //-V:memcmp:575 | ||||
| //-V:strlen:575 | ||||
| //-V:strcpy:575 | ||||
| //-V:strncpy:575 | ||||
| //-V:strchr:575 | ||||
| 
 | ||||
| # For loop warning on M_FOREACH | ||||
| //-V:for:1044 | ||||
| 
 | ||||
| # Bitwise OR | ||||
| //-V:bit:792 | ||||
| 
 | ||||
| # Do not complain about similar code | ||||
| //-V::525 | ||||
| 
 | ||||
| # Common embedded development pointer operations | ||||
| //-V::566 | ||||
| //-V::1032 | ||||
| 
 | ||||
| # Warnings about length mismatch | ||||
| //-V:property_value_out:666 | ||||
| 
 | ||||
| # Model-related warnings | ||||
| //-V:with_view_model:1044,1048 | ||||
| 
 | ||||
| # Functions that always return the same error code | ||||
| //-V:picopass_device_decrypt:1048 | ||||
|  | ||||
| @ -1 +1 @@ | ||||
| --rules-config .pvsconfig -e lib/fatfs -e lib/fnv1a-hash -e lib/FreeRTOS-Kernel -e lib/heatshrink -e lib/libusb_stm32 -e lib/littlefs -e lib/mbedtls -e lib/micro-ecc -e lib/microtar -e lib/mlib -e lib/qrcode -e lib/ST25RFAL002 -e lib/STM32CubeWB -e lib/u8g2 -e */arm-none-eabi/* | ||||
| --rules-config .pvsconfig -e lib/fatfs -e lib/fnv1a-hash -e lib/FreeRTOS-Kernel -e lib/heatshrink -e lib/libusb_stm32 -e lib/littlefs -e lib/mbedtls -e lib/micro-ecc -e lib/microtar -e lib/mlib -e lib/qrcode -e lib/ST25RFAL002 -e lib/STM32CubeWB -e lib/u8g2 -e lib/nanopb -e */arm-none-eabi/* -e applications/plugins/dap_link/lib/free-dap | ||||
|  | ||||
							
								
								
									
										6
									
								
								Brewfile
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								Brewfile
									
									
									
									
									
								
							| @ -1,6 +0,0 @@ | ||||
| cask "gcc-arm-embedded" | ||||
| brew "protobuf" | ||||
| brew "gdb" | ||||
| brew "open-ocd" | ||||
| brew "clang-format" | ||||
| brew "dfu-util" | ||||
| @ -3,15 +3,15 @@ | ||||
| Nice to see you reading this document, we really appreciate it. | ||||
| 
 | ||||
| As all documents of this kind it's unable to cover everything. | ||||
| But it will cover general rules that we enforcing on PR review. | ||||
| But it will cover general rules that we are enforcing on PR review. | ||||
| 
 | ||||
| Also we already have automatic rules checking and formatting, | ||||
| but it got it's limitations and this guide is still mandatory. | ||||
| Also, we already have automatic rules checking and formatting, | ||||
| but it got its limitations and this guide is still mandatory. | ||||
| 
 | ||||
| Some part of this project do have it's own naming and coding guides. | ||||
| Some part of this project do have its own naming and coding guides. | ||||
| For example: assets. Take a look into `ReadMe.md` in assets folder for more details. | ||||
| 
 | ||||
| Also 3rd party libraries are none of our concern. | ||||
| Also, 3rd party libraries are none of our concern. | ||||
| 
 | ||||
| And yes, this set is not final and we are open to discussion. | ||||
| If you want to add/remove/change something here please feel free to open new ticket. | ||||
| @ -30,7 +30,7 @@ Our guide is inspired by, but not claiming to be compatible with: | ||||
| 
 | ||||
| Code we write is intended to be public. | ||||
| Avoid one-liners from hell and keep code complexity under control. | ||||
| Try to make code self explanatory and add comments if needed. | ||||
| Try to make code self-explanatory and add comments if needed. | ||||
| Leave references to standards that you are implementing. | ||||
| Use project wiki to document new/reverse engineered standards. | ||||
| 
 | ||||
| @ -89,7 +89,7 @@ Enforced by linter. | ||||
| Suffixes: | ||||
| 
 | ||||
| - `alloc` - allocate and init instance. C style constructor. Returns pointer to instance. | ||||
| - `free` - deinit and release instance. C style destructor. Takes pointer to instance. | ||||
| - `free` - de-init and release instance. C style destructor. Takes pointer to instance. | ||||
| 
 | ||||
| # C++ coding style | ||||
| 
 | ||||
|  | ||||
| @ -23,8 +23,8 @@ Before writing code and creating PR make sure that it aligns with our mission an | ||||
| - PR that contains code intended to commit crimes is not going to be accepted. | ||||
| - Your PR must comply with our [Coding Style](CODING_STYLE.md) | ||||
| - Your PR must contain code compatible with project [LICENSE](LICENSE). | ||||
| - PR will only be merged if it pass CI/CD. | ||||
| - PR will only be merged if it pass review by code owner. | ||||
| - PR will only be merged if it passes CI/CD. | ||||
| - PR will only be merged if it passes review by code owner. | ||||
| 
 | ||||
| Feel free to ask questions in issues if you're not sure. | ||||
| 
 | ||||
| @ -59,7 +59,7 @@ Commit the changes once you are happy with them. Make sure that code compilation | ||||
| ### Pull Request | ||||
| 
 | ||||
| When you're done making the changes, open a pull request, often referred to as a PR.  | ||||
| - Fill out the "Ready for review" template so we can review your PR. This template helps reviewers understand your changes and the purpose of your pull request.  | ||||
| - Fill out the "Ready for review" template, so we can review your PR. This template helps reviewers understand your changes and the purpose of your pull request.  | ||||
| - Don't forget to [link PR to issue](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue) if you are solving one. | ||||
| - Enable the checkbox to [allow maintainer edits](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/allowing-changes-to-a-pull-request-branch-created-from-a-fork) so the branch can be updated for a merge. | ||||
| Once you submit your PR, a Docs team member will review your proposal. We may ask questions or request for additional information. | ||||
|  | ||||
							
								
								
									
										21
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								Makefile
									
									
									
									
									
								
							| @ -1,21 +0,0 @@ | ||||
| $(info +-------------------------------------------------+) | ||||
| $(info |                                                 |) | ||||
| $(info |      Hello, this is Flipper team speaking!      |) | ||||
| $(info |                                                 |) | ||||
| $(info |       We've migrated to new build system        |) | ||||
| $(info |          It's nice and based on scons           |) | ||||
| $(info |                                                 |) | ||||
| $(info |      Crash course:                              |) | ||||
| $(info |                                                 |) | ||||
| $(info |        `./fbt`                                  |) | ||||
| $(info |        `./fbt flash`                            |) | ||||
| $(info |        `./fbt debug`                            |) | ||||
| $(info |                                                 |) | ||||
| $(info |      More details in documentation/fbt.md       |) | ||||
| $(info |                                                 |) | ||||
| $(info |      Also Please leave your feedback here:      |) | ||||
| $(info |           https://flipp.dev/4RDu                |) | ||||
| $(info |                      or                         |) | ||||
| $(info |           https://flipp.dev/2XM8                |) | ||||
| $(info |                                                 |) | ||||
| $(info +-------------------------------------------------+) | ||||
							
								
								
									
										203
									
								
								ReadMe.md
									
									
									
									
									
								
							
							
						
						
									
										203
									
								
								ReadMe.md
									
									
									
									
									
								
							| @ -1,134 +1,115 @@ | ||||
| <picture> | ||||
|     <source media="(prefers-color-scheme: dark)" srcset="/.github/assets/dark_theme_banner.png"> | ||||
|     <source media="(prefers-color-scheme: light)" srcset="/.github/assets/light_theme_banner.png"> | ||||
|     <img | ||||
|         alt="A pixel art of a Dophin with text: Flipper Zero Official Repo" | ||||
|         src="/.github/assets/light_theme_banner.png"> | ||||
| </picture> | ||||
| 
 | ||||
| # Flipper Zero Firmware | ||||
| 
 | ||||
| [](http://flipperzero.one/discord) | ||||
| - [Flipper Zero Official Website](https://flipperzero.one). A simple way to explain to your friends what Flipper Zero can do. | ||||
| - [Flipper Zero Firmware Update](https://update.flipperzero.one). Improvements for your dolphin: latest firmware releases, upgrade tools for PC and mobile devices. | ||||
| - [User Documentation](https://docs.flipperzero.one). Learn more about your dolphin: specs, usage guides, and anything you want to ask. | ||||
| 
 | ||||
|  | ||||
| # Contributing | ||||
| 
 | ||||
| Welcome to [Flipper Zero](https://flipperzero.one/)'s Firmware repo! | ||||
| Our goal is to create nice and clean code with good documentation, to make it a pleasure for everyone to work with. | ||||
| Our main goal is to build a healthy and sustainable community around Flipper, so we're open to any new ideas and contributions. We also have some rules and taboos here, so please read this page and our [Code of Conduct](/CODE_OF_CONDUCT.md) carefully. | ||||
| 
 | ||||
| # Clone the Repository | ||||
| ## I need help | ||||
| 
 | ||||
| The best place to search for answers is our [User Documentation](https://docs.flipperzero.one). If you can't find the answer there, check our [Discord Server](https://flipp.dev/discord) or our [Forum](https://forum.flipperzero.one/). | ||||
| 
 | ||||
| ## I want to report an issue | ||||
| 
 | ||||
| If you've found an issue and want to report it, please check our [Issues](https://github.com/flipperdevices/flipperzero-firmware/issues) page. Make sure the description contains information about the firmware version you're using, your platform, and a clear explanation of the steps to reproduce the issue. | ||||
| 
 | ||||
| ## I want to contribute code | ||||
| 
 | ||||
| Before opening a PR, please confirm that your changes must be contained in the firmware. Many ideas can easily be implemented as external applications and published in the Flipper Application Catalog (coming soon). If you are unsure, reach out to us on the [Discord Server](https://flipp.dev/discord) or the [Issues](https://github.com/flipperdevices/flipperzero-firmware/issues) page, and we'll help you find the right place for your code. | ||||
| 
 | ||||
| Also, please read our [Contribution Guide](/CONTRIBUTING.md) and our [Coding Style](/CODING_STYLE.md), and make sure your code is compatible with our [Project License](/LICENSE). | ||||
| 
 | ||||
| Finally, open a [Pull Request](https://github.com/flipperdevices/flipperzero-firmware/pulls) and make sure that CI/CD statuses are all green. | ||||
| 
 | ||||
| # Development | ||||
| 
 | ||||
| Flipper Zero Firmware is written in C, with some bits and pieces written in C++ and armv7m assembly languages. An intermediate level of C knowledge is recommended for comfortable programming. C, C++, and armv7m assembly languages are supported for Flipper applications. | ||||
| 
 | ||||
| ## Requirements | ||||
| 
 | ||||
| Supported development platforms: | ||||
| 
 | ||||
| - Windows 10+ with PowerShell and Git (x86_64) | ||||
| - macOS 12+ with Command Line tools (x86_64, arm64) | ||||
| - Ubuntu 20.04+ with build-essential and Git (x86_64) | ||||
| 
 | ||||
| Supported in-circuit debuggers (optional but highly recommended): | ||||
| 
 | ||||
| - [Flipper Zero Wi-Fi Development Board](https://shop.flipperzero.one/products/wifi-devboard) | ||||
| - ST-Link | ||||
| - J-Link | ||||
| 
 | ||||
| Flipper Build System will take care of all the other dependencies. | ||||
| 
 | ||||
| ## Cloning source code | ||||
| 
 | ||||
| Make sure you have enough space and clone the source code: | ||||
| 
 | ||||
| You should clone with  | ||||
| ```shell | ||||
| $ git clone --recursive https://github.com/flipperdevices/flipperzero-firmware.git | ||||
| git clone --recursive https://github.com/flipperdevices/flipperzero-firmware.git | ||||
| ``` | ||||
| 
 | ||||
| # Read the Docs | ||||
| ## Building | ||||
| 
 | ||||
| Check out details on [how to build firmware](documentation/fbt.md), [write applications](documentation/AppsOnSDCard.md), [un-brick your device](documentation/KeyCombo.md) and more in `documentation` folder.  | ||||
| Build firmware using Flipper Build Tool: | ||||
| 
 | ||||
| # Update firmware | ||||
| 
 | ||||
| [Get Latest Firmware from Update Server](https://update.flipperzero.one/) | ||||
| 
 | ||||
| Flipper Zero's firmware consists of two components: | ||||
| 
 | ||||
| - Core2 firmware set - proprietary components by ST: FUS + radio stack. FUS is flashed at factory, and you should never update it. | ||||
| - Core1 Firmware - HAL + OS + Drivers + Applications. | ||||
| 
 | ||||
| They both must be flashed in the order described. | ||||
| 
 | ||||
| ## With offline update package | ||||
| 
 | ||||
| With Flipper attached over USB: | ||||
| 
 | ||||
| `./fbt flash_usb` | ||||
| 
 | ||||
| Just building the package: | ||||
| 
 | ||||
| `./fbt updater_package` | ||||
| 
 | ||||
| To update, copy the resulting directory to Flipper's SD card and navigate to `update.fuf` file in Archive app.  | ||||
| 
 | ||||
| ## With STLink | ||||
| 
 | ||||
| ### Core1 Firmware | ||||
| 
 | ||||
| Prerequisites: | ||||
| 
 | ||||
| - Linux / macOS | ||||
| - Terminal | ||||
| - [arm-gcc-none-eabi](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads) | ||||
| - openocd | ||||
| 
 | ||||
| One-liner: `./fbt firmware_flash` | ||||
| 
 | ||||
| ## With USB DFU  | ||||
| 
 | ||||
| 1. Download latest [Firmware](https://update.flipperzero.one) | ||||
| 
 | ||||
| 2. Reboot Flipper to Bootloader | ||||
|  - Press and hold `← Left` + `↩ Back` for reset  | ||||
|  - Release `↩ Back` and keep holding `← Left` until blue LED lights up | ||||
|  - Release `← Left` | ||||
| 
 | ||||
| 3. Run `dfu-util -D full.dfu -a 0` | ||||
| 
 | ||||
| # Build on Linux/macOS | ||||
| 
 | ||||
| Check out `documentation/fbt.md` for details on building and flashing firmware.  | ||||
| 
 | ||||
| ## macOS Prerequisites | ||||
| 
 | ||||
| Make sure you have [brew](https://brew.sh) and install all the dependencies: | ||||
| ```sh | ||||
| brew bundle --verbose | ||||
| ``` | ||||
| 
 | ||||
| ## Linux Prerequisites | ||||
| 
 | ||||
| The FBT tool handles everything, only `git` is required. | ||||
| 
 | ||||
| ### Optional dependencies | ||||
| 
 | ||||
| - openocd (debugging/flashing over SWD) | ||||
| - heatshrink (compiling image assets) | ||||
| - clang-format (code formatting) | ||||
| - dfu-util (flashing over USB DFU) | ||||
| - protobuf (compiling proto sources) | ||||
| 
 | ||||
| For example, to install them on Debian, use: | ||||
| ```sh | ||||
| apt update | ||||
| apt install openocd clang-format-13 dfu-util protobuf-compiler | ||||
| ``` | ||||
| 
 | ||||
| heatshrink has to be compiled [from sources](https://github.com/atomicobject/heatshrink). | ||||
| 
 | ||||
| ## Compile everything | ||||
| 
 | ||||
| ```sh | ||||
| ```shell | ||||
| ./fbt | ||||
| ``` | ||||
| 
 | ||||
| Check `dist/` for build outputs. | ||||
| ## Flashing firmware using an in-circuit debugger | ||||
| 
 | ||||
| Use **`flipper-z-{target}-full-{suffix}.dfu`** to flash your device. | ||||
| Connect your in-circuit debugger to your Flipper and flash firmware using Flipper Build Tool: | ||||
| 
 | ||||
| ## Flash everything | ||||
| 
 | ||||
| Connect your device via ST-Link and run: | ||||
| ```sh | ||||
| ./fbt firmware_flash | ||||
| ```shell | ||||
| ./fbt flash | ||||
| ``` | ||||
| 
 | ||||
| # Links | ||||
| ## Flashing firmware using USB | ||||
| 
 | ||||
| * Discord: [flipp.dev/discord](https://flipp.dev/discord) | ||||
| * Website: [flipperzero.one](https://flipperzero.one) | ||||
| * Kickstarter page: [kickstarter.com](https://www.kickstarter.com/projects/flipper-devices/flipper-zero-tamagochi-for-hackers) | ||||
| * Forum: [forum.flipperzero.one](https://forum.flipperzero.one/) | ||||
| Make sure your Flipper is on, and your firmware is functioning. Connect your Flipper with a USB cable and flash firmware using Flipper Build Tool: | ||||
| 
 | ||||
| ```shell | ||||
| ./fbt flash_usb | ||||
| ``` | ||||
| 
 | ||||
| ## Documentation | ||||
| 
 | ||||
| - [Flipper Build Tool](/documentation/fbt.md) - building, flashing, and debugging Flipper software | ||||
| - [Applications](/documentation/AppsOnSDCard.md), [Application Manifest](/documentation/AppManifests.md) - developing, building, deploying, and debugging Flipper applications | ||||
| - [Hardware combos and Un-bricking](/documentation/KeyCombo.md) - recovering your Flipper from the most nasty situations | ||||
| - [Flipper File Formats](/documentation/file_formats) - everything about how Flipper stores your data and how you can work with it | ||||
| - [Universal Remotes](/documentation/UniversalRemotes.md) - contributing your infrared remote to the universal remote database | ||||
| - [Firmware Roadmap](/documentation/RoadMap.md) | ||||
| - And much more in the [documentation](/documentation) folder | ||||
| 
 | ||||
| # Project structure | ||||
| 
 | ||||
| - `applications`    - Applications and services used in firmware | ||||
| - `assets`          - Assets used by applications and services | ||||
| - `furi`            - Furi Core: os level primitives and helpers | ||||
| - `debug`           - Debug tool: GDB-plugins, SVD-file and etc | ||||
| - `documentation`   - Documentation generation system configs and input files | ||||
| - `firmware`        - Firmware source code | ||||
| - `lib`             - Our and 3rd party libraries, drivers, etc. | ||||
| - `scripts`         - Supplementary scripts and python libraries home | ||||
| - `applications`    - applications and services used in firmware | ||||
| - `assets`          - assets used by applications and services | ||||
| - `furi`            - Furi Core: OS-level primitives and helpers | ||||
| - `debug`           - debug tool: GDB plugins, an SVD file, etc. | ||||
| - `documentation`   - documentation generation system configs and input files | ||||
| - `firmware`        - firmware source code | ||||
| - `lib`             - our and 3rd party libraries, drivers, etc. | ||||
| - `scripts`         - supplementary scripts and python libraries home | ||||
| 
 | ||||
| Also pay attention to `ReadMe.md` files inside those directories. | ||||
| Also, see `ReadMe.md` files inside those directories for further details. | ||||
| 
 | ||||
| # Links | ||||
| 
 | ||||
| - Discord: [flipp.dev/discord](https://flipp.dev/discord) | ||||
| - Website: [flipperzero.one](https://flipperzero.one) | ||||
| - Forum: [forum.flipperzero.one](https://forum.flipperzero.one/) | ||||
| - Kickstarter: [kickstarter.com](https://www.kickstarter.com/projects/flipper-devices/flipper-zero-tamagochi-for-hackers) | ||||
|  | ||||
							
								
								
									
										51
									
								
								RoadMap.md
									
									
									
									
									
								
							
							
						
						
									
										51
									
								
								RoadMap.md
									
									
									
									
									
								
							| @ -1,51 +0,0 @@ | ||||
| # RoadMap | ||||
| 
 | ||||
| # Where we are (0.x.x branch) | ||||
| 
 | ||||
| Our goal for 0.x.x branch is to build stable usable apps and API. | ||||
| First public release that we support in this branch is 0.43.1. Your device most likely came with this version. | ||||
| You can develop applications but keep in mind that API is not final yet. | ||||
| 
 | ||||
| ## What's already implemented | ||||
| 
 | ||||
| **Applications** | ||||
| 
 | ||||
| - SubGhz: all most common protocols, reading RAW for everything else | ||||
| - 125kHz RFID: all most common protocols | ||||
| - NFC: reading/emulating Mifare Ultralight, reading MiFare Classic and DESFire, basic EMV, basic NFC-B,F,V | ||||
| - Infrared: all most common RC protocols, RAW format for everything else | ||||
| - GPIO: UART bridge, basic GPIO controls | ||||
| - iButton: DS1990, Cyfral, Metacom | ||||
| - Bad USB: Full USB Rubber Ducky support, some extras for windows alt codes | ||||
| - U2F: Full U2F specification support | ||||
| 
 | ||||
| **Extras** | ||||
| 
 | ||||
| - BLE Keyboard | ||||
| - Snake game | ||||
| 
 | ||||
| **System and HAL** | ||||
| 
 | ||||
| - Furi Core | ||||
| - Furi HAL  | ||||
| 
 | ||||
| # Where we're going (Version 1) | ||||
| 
 | ||||
| Main goal for 1.0.0 is to provide first stable version for both Users and Developers. | ||||
| 
 | ||||
| ## What we're planning to implement in 1.0.0 | ||||
| 
 | ||||
| - Loading applications from SD (tested as PoC, work scheduled for Q2) | ||||
| - More protocols (gathering feedback) | ||||
| - User documentation (work in progress) | ||||
| - FuriCore: get rid of CMSIS API, replace hard real time timers, improve stability and performance (work in progress) | ||||
| - FuriHal: deep sleep mode, stable API, examples, documentation (work in progress) | ||||
| - Application improvements (a ton of things that we want to add and improve that are too numerous to list here) | ||||
| 
 | ||||
| ## When will it happen and where I can see the progress? | ||||
| 
 | ||||
| Release 1.0.0 will most likely happen around the end of Q3 | ||||
| 
 | ||||
| Development progress can be tracked in our public Miro board: | ||||
| 
 | ||||
| https://miro.com/app/board/uXjVO_3D6xU=/?moveToWidget=3458764522498020058&cot=14 | ||||
							
								
								
									
										14
									
								
								SConstruct
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								SConstruct
									
									
									
									
									
								
							| @ -194,6 +194,20 @@ firmware_bm_flash = distenv.PhonyTarget( | ||||
|     ], | ||||
| ) | ||||
| 
 | ||||
| gdb_backtrace_all_threads = distenv.PhonyTarget( | ||||
|     "gdb_trace_all", | ||||
|     "$GDB $GDBOPTS $SOURCES $GDBFLASH", | ||||
|     source=firmware_env["FW_ELF"], | ||||
|     GDBOPTS="${GDBOPTS_BASE}", | ||||
|     GDBREMOTE="${OPENOCD_GDB_PIPE}", | ||||
|     GDBFLASH=[ | ||||
|         "-ex", | ||||
|         "thread apply all bt", | ||||
|         "-ex", | ||||
|         "quit", | ||||
|     ], | ||||
| ) | ||||
| 
 | ||||
| # Debugging firmware | ||||
| firmware_debug = distenv.PhonyTarget( | ||||
|     "debug", | ||||
|  | ||||
							
								
								
									
										10
									
								
								applications/debug/direct_draw/application.fam
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								applications/debug/direct_draw/application.fam
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | ||||
| App( | ||||
|     appid="direct_draw", | ||||
|     name="Direct Draw", | ||||
|     apptype=FlipperAppType.DEBUG, | ||||
|     entry_point="direct_draw_app", | ||||
|     requires=["gui", "input"], | ||||
|     stack_size=2 * 1024, | ||||
|     order=70, | ||||
|     fap_category="Debug", | ||||
| ) | ||||
							
								
								
									
										112
									
								
								applications/debug/direct_draw/direct_draw.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								applications/debug/direct_draw/direct_draw.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,112 @@ | ||||
| #include <furi.h> | ||||
| #include <gui/gui.h> | ||||
| #include <gui/canvas_i.h> | ||||
| #include <input/input.h> | ||||
| 
 | ||||
| #define BUFFER_SIZE (32U) | ||||
| 
 | ||||
| typedef struct { | ||||
|     FuriPubSub* input; | ||||
|     FuriPubSubSubscription* input_subscription; | ||||
|     Gui* gui; | ||||
|     Canvas* canvas; | ||||
|     bool stop; | ||||
|     uint32_t counter; | ||||
| } DirectDraw; | ||||
| 
 | ||||
| static void gui_input_events_callback(const void* value, void* ctx) { | ||||
|     furi_assert(value); | ||||
|     furi_assert(ctx); | ||||
| 
 | ||||
|     DirectDraw* instance = ctx; | ||||
|     const InputEvent* event = value; | ||||
| 
 | ||||
|     if(event->key == InputKeyBack && event->type == InputTypeShort) { | ||||
|         instance->stop = true; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static DirectDraw* direct_draw_alloc() { | ||||
|     DirectDraw* instance = malloc(sizeof(DirectDraw)); | ||||
| 
 | ||||
|     instance->input = furi_record_open(RECORD_INPUT_EVENTS); | ||||
|     instance->gui = furi_record_open(RECORD_GUI); | ||||
|     instance->canvas = gui_direct_draw_acquire(instance->gui); | ||||
| 
 | ||||
|     instance->input_subscription = | ||||
|         furi_pubsub_subscribe(instance->input, gui_input_events_callback, instance); | ||||
| 
 | ||||
|     return instance; | ||||
| } | ||||
| 
 | ||||
| static void direct_draw_free(DirectDraw* instance) { | ||||
|     furi_pubsub_unsubscribe(instance->input, instance->input_subscription); | ||||
| 
 | ||||
|     instance->canvas = NULL; | ||||
|     gui_direct_draw_release(instance->gui); | ||||
|     furi_record_close(RECORD_GUI); | ||||
|     furi_record_close(RECORD_INPUT_EVENTS); | ||||
| } | ||||
| 
 | ||||
| static void direct_draw_block(Canvas* canvas, uint32_t size, uint32_t counter) { | ||||
|     size += 16; | ||||
|     uint8_t width = canvas_width(canvas) - size; | ||||
|     uint8_t height = canvas_height(canvas) - size; | ||||
| 
 | ||||
|     uint8_t x = counter % width; | ||||
|     if((counter / width) % 2) { | ||||
|         x = width - x; | ||||
|     } | ||||
| 
 | ||||
|     uint8_t y = counter % height; | ||||
|     if((counter / height) % 2) { | ||||
|         y = height - y; | ||||
|     } | ||||
| 
 | ||||
|     canvas_draw_box(canvas, x, y, size, size); | ||||
| } | ||||
| 
 | ||||
| static void direct_draw_run(DirectDraw* instance) { | ||||
|     size_t start = DWT->CYCCNT; | ||||
|     size_t counter = 0; | ||||
|     float fps = 0; | ||||
| 
 | ||||
|     vTaskPrioritySet(furi_thread_get_current_id(), FuriThreadPriorityIdle); | ||||
| 
 | ||||
|     do { | ||||
|         size_t elapsed = DWT->CYCCNT - start; | ||||
|         char buffer[BUFFER_SIZE] = {0}; | ||||
| 
 | ||||
|         if(elapsed >= 64000000) { | ||||
|             fps = (float)counter / ((float)elapsed / 64000000.0f); | ||||
| 
 | ||||
|             start = DWT->CYCCNT; | ||||
|             counter = 0; | ||||
|         } | ||||
|         snprintf(buffer, BUFFER_SIZE, "FPS: %.1f", (double)fps); | ||||
| 
 | ||||
|         canvas_reset(instance->canvas); | ||||
|         canvas_set_color(instance->canvas, ColorXOR); | ||||
|         direct_draw_block(instance->canvas, instance->counter % 16, instance->counter); | ||||
|         direct_draw_block(instance->canvas, instance->counter * 2 % 16, instance->counter * 2); | ||||
|         direct_draw_block(instance->canvas, instance->counter * 3 % 16, instance->counter * 3); | ||||
|         direct_draw_block(instance->canvas, instance->counter * 4 % 16, instance->counter * 4); | ||||
|         direct_draw_block(instance->canvas, instance->counter * 5 % 16, instance->counter * 5); | ||||
|         canvas_draw_str(instance->canvas, 10, 10, buffer); | ||||
|         canvas_commit(instance->canvas); | ||||
| 
 | ||||
|         counter++; | ||||
|         instance->counter++; | ||||
|         furi_thread_yield(); | ||||
|     } while(!instance->stop); | ||||
| } | ||||
| 
 | ||||
| int32_t direct_draw_app(void* p) { | ||||
|     UNUSED(p); | ||||
| 
 | ||||
|     DirectDraw* instance = direct_draw_alloc(); | ||||
|     direct_draw_run(instance); | ||||
|     direct_draw_free(instance); | ||||
| 
 | ||||
|     return 0; | ||||
| } | ||||
							
								
								
									
										60
									
								
								applications/debug/unit_tests/float_tools/float_tools_test.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								applications/debug/unit_tests/float_tools/float_tools_test.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,60 @@ | ||||
| #include <float.h> | ||||
| #include <float_tools.h> | ||||
| 
 | ||||
| #include "../minunit.h" | ||||
| 
 | ||||
| MU_TEST(float_tools_equal_test) { | ||||
|     mu_check(float_is_equal(FLT_MAX, FLT_MAX)); | ||||
|     mu_check(float_is_equal(FLT_MIN, FLT_MIN)); | ||||
|     mu_check(float_is_equal(-FLT_MAX, -FLT_MAX)); | ||||
|     mu_check(float_is_equal(-FLT_MIN, -FLT_MIN)); | ||||
| 
 | ||||
|     mu_check(!float_is_equal(FLT_MIN, FLT_MAX)); | ||||
|     mu_check(!float_is_equal(-FLT_MIN, FLT_MAX)); | ||||
|     mu_check(!float_is_equal(FLT_MIN, -FLT_MAX)); | ||||
|     mu_check(!float_is_equal(-FLT_MIN, -FLT_MAX)); | ||||
| 
 | ||||
|     const float pi = 3.14159f; | ||||
|     mu_check(float_is_equal(pi, pi)); | ||||
|     mu_check(float_is_equal(-pi, -pi)); | ||||
|     mu_check(!float_is_equal(pi, -pi)); | ||||
|     mu_check(!float_is_equal(-pi, pi)); | ||||
| 
 | ||||
|     const float one_third = 1.f / 3.f; | ||||
|     const float one_third_dec = 0.3333333f; | ||||
|     mu_check(one_third != one_third_dec); | ||||
|     mu_check(float_is_equal(one_third, one_third_dec)); | ||||
| 
 | ||||
|     const float big_num = 1.e12f; | ||||
|     const float med_num = 95.389f; | ||||
|     const float smol_num = 1.e-12f; | ||||
|     mu_check(float_is_equal(big_num, big_num)); | ||||
|     mu_check(float_is_equal(med_num, med_num)); | ||||
|     mu_check(float_is_equal(smol_num, smol_num)); | ||||
|     mu_check(!float_is_equal(smol_num, big_num)); | ||||
|     mu_check(!float_is_equal(med_num, smol_num)); | ||||
|     mu_check(!float_is_equal(big_num, med_num)); | ||||
| 
 | ||||
|     const float more_than_one = 1.f + FLT_EPSILON; | ||||
|     const float less_than_one = 1.f - FLT_EPSILON; | ||||
|     mu_check(!float_is_equal(more_than_one, less_than_one)); | ||||
|     mu_check(!float_is_equal(more_than_one, -less_than_one)); | ||||
|     mu_check(!float_is_equal(-more_than_one, less_than_one)); | ||||
|     mu_check(!float_is_equal(-more_than_one, -less_than_one)); | ||||
| 
 | ||||
|     const float slightly_more_than_one = 1.f + FLT_EPSILON / 2.f; | ||||
|     const float slightly_less_than_one = 1.f - FLT_EPSILON / 2.f; | ||||
|     mu_check(float_is_equal(slightly_more_than_one, slightly_less_than_one)); | ||||
|     mu_check(float_is_equal(-slightly_more_than_one, -slightly_less_than_one)); | ||||
|     mu_check(!float_is_equal(slightly_more_than_one, -slightly_less_than_one)); | ||||
|     mu_check(!float_is_equal(-slightly_more_than_one, slightly_less_than_one)); | ||||
| } | ||||
| 
 | ||||
| MU_TEST_SUITE(float_tools_suite) { | ||||
|     MU_RUN_TEST(float_tools_equal_test); | ||||
| } | ||||
| 
 | ||||
| int run_minunit_test_float_tools() { | ||||
|     MU_RUN_SUITE(float_tools_suite); | ||||
|     return MU_EXIT_CODE; | ||||
| } | ||||
| @ -3,98 +3,37 @@ | ||||
| #include <string.h> | ||||
| #include <stdbool.h> | ||||
| 
 | ||||
| // this test is not accurate, but gives a basic understanding
 | ||||
| // that memory management is working fine
 | ||||
| 
 | ||||
| // do not include memmgr.h here
 | ||||
| // we also test that we are linking against stdlib
 | ||||
| extern size_t memmgr_get_free_heap(void); | ||||
| extern size_t memmgr_get_minimum_free_heap(void); | ||||
| 
 | ||||
| // current heap management realization consume:
 | ||||
| // X bytes after allocate and 0 bytes after allocate and free,
 | ||||
| // where X = sizeof(void*) + sizeof(size_t), look to BlockLink_t
 | ||||
| const size_t heap_overhead_max_size = sizeof(void*) + sizeof(size_t); | ||||
| 
 | ||||
| bool heap_equal(size_t heap_size, size_t heap_size_old) { | ||||
|     // heap borders with overhead
 | ||||
|     const size_t heap_low = heap_size_old - heap_overhead_max_size; | ||||
|     const size_t heap_high = heap_size_old + heap_overhead_max_size; | ||||
| 
 | ||||
|     // not exact, so we must test it against bigger numbers than "overhead size"
 | ||||
|     const bool result = ((heap_size >= heap_low) && (heap_size <= heap_high)); | ||||
| 
 | ||||
|     // debug allocation info
 | ||||
|     if(!result) { | ||||
|         printf("\n(hl: %zu) <= (p: %zu) <= (hh: %zu)\n", heap_low, heap_size, heap_high); | ||||
|     } | ||||
| 
 | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| void test_furi_memmgr() { | ||||
|     size_t heap_size = 0; | ||||
|     size_t heap_size_old = 0; | ||||
|     const int alloc_size = 128; | ||||
| 
 | ||||
|     void* ptr = NULL; | ||||
|     void* original_ptr = NULL; | ||||
| 
 | ||||
|     // do not include furi memmgr.h case
 | ||||
| #ifdef FURI_MEMMGR_GUARD | ||||
|     mu_fail("do not link against furi memmgr.h"); | ||||
| #endif | ||||
|     void* ptr; | ||||
| 
 | ||||
|     // allocate memory case
 | ||||
|     heap_size_old = memmgr_get_free_heap(); | ||||
|     ptr = malloc(alloc_size); | ||||
|     heap_size = memmgr_get_free_heap(); | ||||
|     mu_assert_pointers_not_eq(ptr, NULL); | ||||
|     mu_assert(heap_equal(heap_size, heap_size_old - alloc_size), "allocate failed"); | ||||
| 
 | ||||
|     // free memory case
 | ||||
|     heap_size_old = memmgr_get_free_heap(); | ||||
|     ptr = malloc(100); | ||||
|     mu_check(ptr != NULL); | ||||
|     // test that memory is zero-initialized after allocation
 | ||||
|     for(int i = 0; i < 100; i++) { | ||||
|         mu_assert_int_eq(0, ((uint8_t*)ptr)[i]); | ||||
|     } | ||||
|     free(ptr); | ||||
|     ptr = NULL; | ||||
|     heap_size = memmgr_get_free_heap(); | ||||
|     mu_assert(heap_equal(heap_size, heap_size_old + alloc_size), "free failed"); | ||||
| 
 | ||||
|     // reallocate memory case
 | ||||
|     ptr = malloc(100); | ||||
|     memset(ptr, 66, 100); | ||||
|     ptr = realloc(ptr, 200); | ||||
|     mu_check(ptr != NULL); | ||||
| 
 | ||||
|     // get filled array with some data
 | ||||
|     original_ptr = malloc(alloc_size); | ||||
|     mu_assert_pointers_not_eq(original_ptr, NULL); | ||||
|     for(int i = 0; i < alloc_size; i++) { | ||||
|         *(unsigned char*)(original_ptr + i) = i; | ||||
|     // test that memory is really reallocated
 | ||||
|     for(int i = 0; i < 100; i++) { | ||||
|         mu_assert_int_eq(66, ((uint8_t*)ptr)[i]); | ||||
|     } | ||||
| 
 | ||||
|     // malloc array and copy data
 | ||||
|     ptr = malloc(alloc_size); | ||||
|     mu_assert_pointers_not_eq(ptr, NULL); | ||||
|     memcpy(ptr, original_ptr, alloc_size); | ||||
| 
 | ||||
|     // reallocate array
 | ||||
|     heap_size_old = memmgr_get_free_heap(); | ||||
|     ptr = realloc(ptr, alloc_size * 2); | ||||
|     heap_size = memmgr_get_free_heap(); | ||||
|     mu_assert(heap_equal(heap_size, heap_size_old - alloc_size), "reallocate failed"); | ||||
|     mu_assert_int_eq(memcmp(original_ptr, ptr, alloc_size), 0); | ||||
|     free(original_ptr); | ||||
|     // TODO: fix realloc to copy only old size, and write testcase that leftover of reallocated memory is zero-initialized
 | ||||
|     free(ptr); | ||||
| 
 | ||||
|     // allocate and zero-initialize array (calloc)
 | ||||
|     original_ptr = malloc(alloc_size); | ||||
|     mu_assert_pointers_not_eq(original_ptr, NULL); | ||||
| 
 | ||||
|     for(int i = 0; i < alloc_size; i++) { | ||||
|         *(unsigned char*)(original_ptr + i) = 0; | ||||
|     ptr = calloc(100, 2); | ||||
|     mu_check(ptr != NULL); | ||||
|     for(int i = 0; i < 100 * 2; i++) { | ||||
|         mu_assert_int_eq(0, ((uint8_t*)ptr)[i]); | ||||
|     } | ||||
|     heap_size_old = memmgr_get_free_heap(); | ||||
|     ptr = calloc(1, alloc_size); | ||||
|     heap_size = memmgr_get_free_heap(); | ||||
|     mu_assert(heap_equal(heap_size, heap_size_old - alloc_size), "callocate failed"); | ||||
|     mu_assert_int_eq(memcmp(original_ptr, ptr, alloc_size), 0); | ||||
| 
 | ||||
|     free(original_ptr); | ||||
|     free(ptr); | ||||
| } | ||||
|  | ||||
							
								
								
									
										75
									
								
								applications/debug/unit_tests/manifest/manifest.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								applications/debug/unit_tests/manifest/manifest.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,75 @@ | ||||
| #include <furi.c> | ||||
| #include "../minunit.h" | ||||
| #include <update_util/resources/manifest.h> | ||||
| 
 | ||||
| #define TAG "Manifest" | ||||
| 
 | ||||
| MU_TEST(manifest_type_test) { | ||||
|     mu_assert(ResourceManifestEntryTypeUnknown == 0, "ResourceManifestEntryTypeUnknown != 0\r\n"); | ||||
|     mu_assert(ResourceManifestEntryTypeVersion == 1, "ResourceManifestEntryTypeVersion != 1\r\n"); | ||||
|     mu_assert( | ||||
|         ResourceManifestEntryTypeTimestamp == 2, "ResourceManifestEntryTypeTimestamp != 2\r\n"); | ||||
|     mu_assert( | ||||
|         ResourceManifestEntryTypeDirectory == 3, "ResourceManifestEntryTypeDirectory != 3\r\n"); | ||||
|     mu_assert(ResourceManifestEntryTypeFile == 4, "ResourceManifestEntryTypeFile != 4\r\n"); | ||||
| } | ||||
| 
 | ||||
| MU_TEST(manifest_iteration_test) { | ||||
|     bool result = true; | ||||
|     size_t counters[5] = {0}; | ||||
| 
 | ||||
|     Storage* storage = furi_record_open(RECORD_STORAGE); | ||||
|     ResourceManifestReader* manifest_reader = resource_manifest_reader_alloc(storage); | ||||
|     do { | ||||
|         // Open manifest file
 | ||||
|         if(!resource_manifest_reader_open(manifest_reader, EXT_PATH("unit_tests/Manifest"))) { | ||||
|             result = false; | ||||
|             break; | ||||
|         } | ||||
| 
 | ||||
|         // Iterate forward
 | ||||
|         ResourceManifestEntry* entry_ptr = NULL; | ||||
|         while((entry_ptr = resource_manifest_reader_next(manifest_reader))) { | ||||
|             FURI_LOG_D(TAG, "F:%u:%s", entry_ptr->type, furi_string_get_cstr(entry_ptr->name)); | ||||
|             if(entry_ptr->type > 4) { | ||||
|                 mu_fail("entry_ptr->type > 4\r\n"); | ||||
|                 result = false; | ||||
|                 break; | ||||
|             } | ||||
|             counters[entry_ptr->type]++; | ||||
|         } | ||||
|         if(!result) break; | ||||
| 
 | ||||
|         // Iterate backward
 | ||||
|         while((entry_ptr = resource_manifest_reader_previous(manifest_reader))) { | ||||
|             FURI_LOG_D(TAG, "B:%u:%s", entry_ptr->type, furi_string_get_cstr(entry_ptr->name)); | ||||
|             if(entry_ptr->type > 4) { | ||||
|                 mu_fail("entry_ptr->type > 4\r\n"); | ||||
|                 result = false; | ||||
|                 break; | ||||
|             } | ||||
|             counters[entry_ptr->type]--; | ||||
|         } | ||||
|     } while(false); | ||||
| 
 | ||||
|     resource_manifest_reader_free(manifest_reader); | ||||
|     furi_record_close(RECORD_STORAGE); | ||||
| 
 | ||||
|     mu_assert(counters[ResourceManifestEntryTypeUnknown] == 0, "Unknown counter != 0\r\n"); | ||||
|     mu_assert(counters[ResourceManifestEntryTypeVersion] == 0, "Version counter != 0\r\n"); | ||||
|     mu_assert(counters[ResourceManifestEntryTypeTimestamp] == 0, "Timestamp counter != 0\r\n"); | ||||
|     mu_assert(counters[ResourceManifestEntryTypeDirectory] == 0, "Directory counter != 0\r\n"); | ||||
|     mu_assert(counters[ResourceManifestEntryTypeFile] == 0, "File counter != 0\r\n"); | ||||
| 
 | ||||
|     mu_assert(result, "Manifest forward iterate failed\r\n"); | ||||
| } | ||||
| 
 | ||||
| MU_TEST_SUITE(manifest_suite) { | ||||
|     MU_RUN_TEST(manifest_type_test); | ||||
|     MU_RUN_TEST(manifest_iteration_test); | ||||
| } | ||||
| 
 | ||||
| int run_minunit_test_manifest() { | ||||
|     MU_RUN_SUITE(manifest_suite); | ||||
|     return MU_EXIT_CODE; | ||||
| } | ||||
| @ -72,8 +72,32 @@ MU_TEST_1(stream_composite_subtest, Stream* stream) { | ||||
|     mu_check(stream_seek(stream, -3, StreamOffsetFromEnd)); | ||||
|     mu_check(stream_tell(stream) == 4); | ||||
| 
 | ||||
|     // write string with replacemet
 | ||||
|     // test seeks to char. content: '1337_69'
 | ||||
|     stream_rewind(stream); | ||||
|     mu_check(stream_seek_to_char(stream, '3', StreamDirectionForward)); | ||||
|     mu_check(stream_tell(stream) == 1); | ||||
|     mu_check(stream_seek_to_char(stream, '3', StreamDirectionForward)); | ||||
|     mu_check(stream_tell(stream) == 2); | ||||
|     mu_check(stream_seek_to_char(stream, '_', StreamDirectionForward)); | ||||
|     mu_check(stream_tell(stream) == 4); | ||||
|     mu_check(stream_seek_to_char(stream, '9', StreamDirectionForward)); | ||||
|     mu_check(stream_tell(stream) == 6); | ||||
|     mu_check(!stream_seek_to_char(stream, '9', StreamDirectionForward)); | ||||
|     mu_check(stream_tell(stream) == 6); | ||||
|     mu_check(stream_seek_to_char(stream, '_', StreamDirectionBackward)); | ||||
|     mu_check(stream_tell(stream) == 4); | ||||
|     mu_check(stream_seek_to_char(stream, '3', StreamDirectionBackward)); | ||||
|     mu_check(stream_tell(stream) == 2); | ||||
|     mu_check(stream_seek_to_char(stream, '3', StreamDirectionBackward)); | ||||
|     mu_check(stream_tell(stream) == 1); | ||||
|     mu_check(!stream_seek_to_char(stream, '3', StreamDirectionBackward)); | ||||
|     mu_check(stream_tell(stream) == 1); | ||||
|     mu_check(stream_seek_to_char(stream, '1', StreamDirectionBackward)); | ||||
|     mu_check(stream_tell(stream) == 0); | ||||
| 
 | ||||
|     // write string with replacement
 | ||||
|     // "1337_69" -> "1337lee"
 | ||||
|     mu_check(stream_seek(stream, 4, StreamOffsetFromStart)); | ||||
|     mu_check(stream_write_string(stream, string_lee) == 3); | ||||
|     mu_check(stream_size(stream) == 7); | ||||
|     mu_check(stream_tell(stream) == 7); | ||||
|  | ||||
| @ -13,7 +13,7 @@ | ||||
| #define CAME_ATOMO_DIR_NAME EXT_PATH("subghz/assets/came_atomo") | ||||
| #define NICE_FLOR_S_DIR_NAME EXT_PATH("subghz/assets/nice_flor_s") | ||||
| #define TEST_RANDOM_DIR_NAME EXT_PATH("unit_tests/subghz/test_random_raw.sub") | ||||
| #define TEST_RANDOM_COUNT_PARSE 253 | ||||
| #define TEST_RANDOM_COUNT_PARSE 273 | ||||
| #define TEST_TIMEOUT 10000 | ||||
| 
 | ||||
| static SubGhzEnvironment* environment_handler; | ||||
| @ -318,7 +318,10 @@ bool subghz_hal_async_tx_test_run(SubGhzHalAsyncTxTestType type) { | ||||
|     furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async); | ||||
|     furi_hal_subghz_set_frequency_and_path(433920000); | ||||
| 
 | ||||
|     furi_hal_subghz_start_async_tx(subghz_hal_async_tx_test_yield, &test); | ||||
|     if(!furi_hal_subghz_start_async_tx(subghz_hal_async_tx_test_yield, &test)) { | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     while(!furi_hal_subghz_is_async_tx_complete()) { | ||||
|         furi_delay_ms(10); | ||||
|     } | ||||
| @ -594,6 +597,13 @@ MU_TEST(subghz_decoder_smc5326_test) { | ||||
|         "Test decoder " SUBGHZ_PROTOCOL_SMC5326_NAME " error\r\n"); | ||||
| } | ||||
| 
 | ||||
| MU_TEST(subghz_decoder_holtek_ht12x_test) { | ||||
|     mu_assert( | ||||
|         subghz_decoder_test( | ||||
|             EXT_PATH("unit_tests/subghz/holtek_ht12x_raw.sub"), SUBGHZ_PROTOCOL_HOLTEK_HT12X_NAME), | ||||
|         "Test decoder " SUBGHZ_PROTOCOL_HOLTEK_HT12X_NAME " error\r\n"); | ||||
| } | ||||
| 
 | ||||
| //test encoders
 | ||||
| MU_TEST(subghz_encoder_princeton_test) { | ||||
|     mu_assert( | ||||
| @ -727,6 +737,12 @@ MU_TEST(subghz_encoder_smc5326_test) { | ||||
|         "Test encoder " SUBGHZ_PROTOCOL_SMC5326_NAME " error\r\n"); | ||||
| } | ||||
| 
 | ||||
| MU_TEST(subghz_encoder_holtek_ht12x_test) { | ||||
|     mu_assert( | ||||
|         subghz_encoder_test(EXT_PATH("unit_tests/subghz/holtek_ht12x.sub")), | ||||
|         "Test encoder " SUBGHZ_PROTOCOL_HOLTEK_HT12X_NAME " error\r\n"); | ||||
| } | ||||
| 
 | ||||
| MU_TEST(subghz_random_test) { | ||||
|     mu_assert(subghz_decode_random_test(TEST_RANDOM_DIR_NAME), "Random test error\r\n"); | ||||
| } | ||||
| @ -771,6 +787,7 @@ MU_TEST_SUITE(subghz) { | ||||
|     MU_RUN_TEST(subghz_decoder_clemsa_test); | ||||
|     MU_RUN_TEST(subghz_decoder_ansonic_test); | ||||
|     MU_RUN_TEST(subghz_decoder_smc5326_test); | ||||
|     MU_RUN_TEST(subghz_decoder_holtek_ht12x_test); | ||||
| 
 | ||||
|     MU_RUN_TEST(subghz_encoder_princeton_test); | ||||
|     MU_RUN_TEST(subghz_encoder_came_test); | ||||
| @ -794,6 +811,7 @@ MU_TEST_SUITE(subghz) { | ||||
|     MU_RUN_TEST(subghz_encoder_clemsa_test); | ||||
|     MU_RUN_TEST(subghz_encoder_ansonic_test); | ||||
|     MU_RUN_TEST(subghz_encoder_smc5326_test); | ||||
|     MU_RUN_TEST(subghz_encoder_holtek_ht12x_test); | ||||
| 
 | ||||
|     MU_RUN_TEST(subghz_random_test); | ||||
|     subghz_test_deinit(); | ||||
|  | ||||
| @ -13,6 +13,7 @@ int run_minunit_test_furi_hal(); | ||||
| int run_minunit_test_furi_string(); | ||||
| int run_minunit_test_infrared(); | ||||
| int run_minunit_test_rpc(); | ||||
| int run_minunit_test_manifest(); | ||||
| int run_minunit_test_flipper_format(); | ||||
| int run_minunit_test_flipper_format_string(); | ||||
| int run_minunit_test_stream(); | ||||
| @ -24,6 +25,7 @@ int run_minunit_test_protocol_dict(); | ||||
| int run_minunit_test_lfrfid_protocols(); | ||||
| int run_minunit_test_nfc(); | ||||
| int run_minunit_test_bit_lib(); | ||||
| int run_minunit_test_float_tools(); | ||||
| int run_minunit_test_bt(); | ||||
| 
 | ||||
| typedef int (*UnitTestEntry)(); | ||||
| @ -40,6 +42,7 @@ const UnitTest unit_tests[] = { | ||||
|     {.name = "storage", .entry = run_minunit_test_storage}, | ||||
|     {.name = "stream", .entry = run_minunit_test_stream}, | ||||
|     {.name = "dirwalk", .entry = run_minunit_test_dirwalk}, | ||||
|     {.name = "manifest", .entry = run_minunit_test_manifest}, | ||||
|     {.name = "flipper_format", .entry = run_minunit_test_flipper_format}, | ||||
|     {.name = "flipper_format_string", .entry = run_minunit_test_flipper_format_string}, | ||||
|     {.name = "rpc", .entry = run_minunit_test_rpc}, | ||||
| @ -50,6 +53,7 @@ const UnitTest unit_tests[] = { | ||||
|     {.name = "protocol_dict", .entry = run_minunit_test_protocol_dict}, | ||||
|     {.name = "lfrfid", .entry = run_minunit_test_lfrfid_protocols}, | ||||
|     {.name = "bit_lib", .entry = run_minunit_test_bit_lib}, | ||||
|     {.name = "float_tools", .entry = run_minunit_test_float_tools}, | ||||
|     {.name = "bt", .entry = run_minunit_test_bt}, | ||||
| }; | ||||
| 
 | ||||
| @ -73,7 +77,6 @@ void unit_tests_cli(Cli* cli, FuriString* args, void* context) { | ||||
|     UNUSED(cli); | ||||
|     UNUSED(args); | ||||
|     UNUSED(context); | ||||
|     uint32_t failed_tests = 0; | ||||
|     minunit_run = 0; | ||||
|     minunit_assert = 0; | ||||
|     minunit_fail = 0; | ||||
| @ -99,15 +102,17 @@ void unit_tests_cli(Cli* cli, FuriString* args, void* context) { | ||||
| 
 | ||||
|             if(furi_string_size(args)) { | ||||
|                 if(furi_string_cmp_str(args, unit_tests[i].name) == 0) { | ||||
|                     failed_tests += unit_tests[i].entry(); | ||||
|                     unit_tests[i].entry(); | ||||
|                 } else { | ||||
|                     printf("Skipping %s\r\n", unit_tests[i].name); | ||||
|                 } | ||||
|             } else { | ||||
|                 failed_tests += unit_tests[i].entry(); | ||||
|                 unit_tests[i].entry(); | ||||
|             } | ||||
|         } | ||||
|         printf("\r\nFailed tests: %lu\r\n", failed_tests); | ||||
| 
 | ||||
|         if(minunit_run != 0) { | ||||
|             printf("\r\nFailed tests: %u\r\n", minunit_fail); | ||||
| 
 | ||||
|             // Time report
 | ||||
|             cycle_counter = (furi_get_tick() - cycle_counter); | ||||
| @ -119,7 +124,7 @@ void unit_tests_cli(Cli* cli, FuriString* args, void* context) { | ||||
|             printf("Leaked: %ld\r\n", heap_before - heap_after); | ||||
| 
 | ||||
|             // Final Report
 | ||||
|         if(failed_tests == 0) { | ||||
|             if(minunit_fail == 0) { | ||||
|                 notification_message(notification, &sequence_success); | ||||
|                 printf("Status: PASSED\r\n"); | ||||
|             } else { | ||||
| @ -127,6 +132,7 @@ void unit_tests_cli(Cli* cli, FuriString* args, void* context) { | ||||
|                 printf("Status: FAILED\r\n"); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     furi_record_close(RECORD_NOTIFICATION); | ||||
|     furi_record_close(RECORD_LOADER); | ||||
|  | ||||
| @ -13,7 +13,7 @@ ArchiveAppTypeEnum archive_get_app_type(const char* path) { | ||||
|     } | ||||
|     app_name++; | ||||
| 
 | ||||
|     for(size_t i = 0; i < COUNT_OF(known_apps); i++) { | ||||
|     for(size_t i = 0; i < COUNT_OF(known_apps); i++) { //-V1008
 | ||||
|         if(strncmp(app_name, known_apps[i], strlen(known_apps[i])) == 0) { | ||||
|             return i; | ||||
|         } | ||||
|  | ||||
| @ -177,7 +177,7 @@ bool archive_favorites_read(void* context) { | ||||
| 
 | ||||
|     archive_set_item_count(browser, file_count); | ||||
| 
 | ||||
|     if(need_refresh) { | ||||
|     if(need_refresh) { //-V547
 | ||||
|         archive_favourites_rescan(); | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -116,7 +116,7 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) { | ||||
|         case ArchiveBrowserEventFileMenuPin: { | ||||
|             const char* name = archive_get_name(browser); | ||||
|             if(favorites) { | ||||
|                 archive_favorites_delete(name); | ||||
|                 archive_favorites_delete("%s", name); | ||||
|                 archive_file_array_rm_selected(browser); | ||||
|                 archive_show_file_menu(browser, false); | ||||
|             } else if(archive_is_known_app(selected->type)) { | ||||
|  | ||||
| @ -218,8 +218,8 @@ static bool ducky_string(const char* param) { | ||||
| } | ||||
| 
 | ||||
| static uint16_t ducky_get_keycode(const char* param, bool accept_chars) { | ||||
|     for(uint8_t i = 0; i < (sizeof(ducky_keys) / sizeof(ducky_keys[0])); i++) { | ||||
|         uint8_t key_cmd_len = strlen(ducky_keys[i].name); | ||||
|     for(size_t i = 0; i < (sizeof(ducky_keys) / sizeof(ducky_keys[0])); i++) { | ||||
|         size_t key_cmd_len = strlen(ducky_keys[i].name); | ||||
|         if((strncmp(param, ducky_keys[i].name, key_cmd_len) == 0) && | ||||
|            (ducky_is_line_end(param[key_cmd_len]))) { | ||||
|             return ducky_keys[i].keycode; | ||||
| @ -417,7 +417,7 @@ static int32_t ducky_script_execute_next(BadUsbScript* bad_usb, File* script_fil | ||||
|             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 %u", bad_usb->st.line_cur - 1); | ||||
|             FURI_LOG_E(WORKER_TAG, "Unknown command at line %u", bad_usb->st.line_cur - 1U); | ||||
|             return SCRIPT_STATE_ERROR; | ||||
|         } else { | ||||
|             return (delay_val + bad_usb->defdelay); | ||||
| @ -596,7 +596,9 @@ static int32_t bad_usb_worker(void* context) { | ||||
|                 } | ||||
|                 bad_usb->st.state = worker_state; | ||||
|                 continue; | ||||
|             } else if((flags == FuriFlagErrorTimeout) || (flags == FuriFlagErrorResource)) { | ||||
|             } else if( | ||||
|                 (flags == (unsigned)FuriFlagErrorTimeout) || | ||||
|                 (flags == (unsigned)FuriFlagErrorResource)) { | ||||
|                 if(delay_val > 0) { | ||||
|                     bad_usb->st.delay_remain--; | ||||
|                     continue; | ||||
| @ -650,7 +652,7 @@ static int32_t bad_usb_worker(void* context) { | ||||
| BadUsbScript* bad_usb_script_open(FuriString* file_path) { | ||||
|     furi_assert(file_path); | ||||
| 
 | ||||
|     BadUsbScript* bad_usb = malloc(sizeof(BadUsbScript)); //-V773
 | ||||
|     BadUsbScript* bad_usb = malloc(sizeof(BadUsbScript)); | ||||
|     bad_usb->file_path = furi_string_alloc(); | ||||
|     furi_string_set(bad_usb->file_path, file_path); | ||||
| 
 | ||||
| @ -660,7 +662,7 @@ BadUsbScript* bad_usb_script_open(FuriString* file_path) { | ||||
|     bad_usb->thread = furi_thread_alloc_ex("BadUsbWorker", 2048, bad_usb_worker, bad_usb); | ||||
|     furi_thread_start(bad_usb->thread); | ||||
|     return bad_usb; | ||||
| } | ||||
| } //-V773
 | ||||
| 
 | ||||
| void bad_usb_script_close(BadUsbScript* bad_usb) { | ||||
|     furi_assert(bad_usb); | ||||
|  | ||||
| @ -156,7 +156,7 @@ static bool fap_loader_select_app(FapLoader* loader) { | ||||
| } | ||||
| 
 | ||||
| static FapLoader* fap_loader_alloc(const char* path) { | ||||
|     FapLoader* loader = malloc(sizeof(FapLoader)); //-V773
 | ||||
|     FapLoader* loader = malloc(sizeof(FapLoader)); //-V799
 | ||||
|     loader->fap_path = furi_string_alloc_set(path); | ||||
|     loader->storage = furi_record_open(RECORD_STORAGE); | ||||
|     loader->dialogs = furi_record_open(RECORD_DIALOGS); | ||||
| @ -167,7 +167,7 @@ static FapLoader* fap_loader_alloc(const char* path) { | ||||
|         loader->view_dispatcher, loader->gui, ViewDispatcherTypeFullscreen); | ||||
|     view_dispatcher_add_view(loader->view_dispatcher, 0, loading_get_view(loader->loading)); | ||||
|     return loader; | ||||
| } | ||||
| } //-V773
 | ||||
| 
 | ||||
| static void fap_loader_free(FapLoader* loader) { | ||||
|     view_dispatcher_remove_view(loader->view_dispatcher, 0); | ||||
|  | ||||
| @ -278,7 +278,7 @@ bool ibutton_save_key(iButton* ibutton, const char* key_name) { | ||||
| 
 | ||||
|     flipper_format_free(file); | ||||
| 
 | ||||
|     if(!result) { | ||||
|     if(!result) { //-V547
 | ||||
|         dialog_message_show_storage_error(ibutton->dialogs, "Cannot save\nkey file"); | ||||
|     } | ||||
| 
 | ||||
| @ -302,7 +302,7 @@ void ibutton_text_store_set(iButton* ibutton, const char* text, ...) { | ||||
| } | ||||
| 
 | ||||
| void ibutton_text_store_clear(iButton* ibutton) { | ||||
|     memset(ibutton->text_store, 0, IBUTTON_TEXT_STORE_SIZE); | ||||
|     memset(ibutton->text_store, 0, IBUTTON_TEXT_STORE_SIZE + 1); | ||||
| } | ||||
| 
 | ||||
| void ibutton_notification_message(iButton* ibutton, uint32_t message) { | ||||
| @ -343,7 +343,7 @@ int32_t ibutton_app(void* p) { | ||||
|     } else { | ||||
|         view_dispatcher_attach_to_gui( | ||||
|             ibutton->view_dispatcher, ibutton->gui, ViewDispatcherTypeFullscreen); | ||||
|         if(key_loaded) { | ||||
|         if(key_loaded) { //-V547
 | ||||
|             scene_manager_next_scene(ibutton->scene_manager, iButtonSceneEmulate); | ||||
|             DOLPHIN_DEED(DolphinDeedIbuttonEmulate); | ||||
|         } else { | ||||
|  | ||||
| @ -360,7 +360,7 @@ void infrared_text_store_set(Infrared* infrared, uint32_t bank, const char* text | ||||
| } | ||||
| 
 | ||||
| void infrared_text_store_clear(Infrared* infrared, uint32_t bank) { | ||||
|     memset(infrared->text_store[bank], 0, INFRARED_TEXT_STORE_SIZE); | ||||
|     memset(infrared->text_store[bank], 0, INFRARED_TEXT_STORE_SIZE + 1); | ||||
| } | ||||
| 
 | ||||
| void infrared_play_notification_message(Infrared* infrared, uint32_t message) { | ||||
| @ -455,7 +455,7 @@ int32_t infrared_app(void* p) { | ||||
|     } else { | ||||
|         view_dispatcher_attach_to_gui( | ||||
|             infrared->view_dispatcher, infrared->gui, ViewDispatcherTypeFullscreen); | ||||
|         if(is_remote_loaded) { | ||||
|         if(is_remote_loaded) { //-V547
 | ||||
|             scene_manager_next_scene(infrared->scene_manager, InfraredSceneRemote); | ||||
|         } else { | ||||
|             scene_manager_next_scene(infrared->scene_manager, InfraredSceneStart); | ||||
|  | ||||
| @ -65,7 +65,7 @@ bool infrared_brute_force_calculate_messages(InfraredBruteForce* brute_force) { | ||||
|         while(flipper_format_read_string(ff, "name", signal_name)) { | ||||
|             InfraredBruteForceRecord* record = | ||||
|                 InfraredBruteForceRecordDict_get(brute_force->records, signal_name); | ||||
|             if(record) { | ||||
|             if(record) { //-V547
 | ||||
|                 ++(record->count); | ||||
|             } | ||||
|         } | ||||
|  | ||||
| @ -55,7 +55,7 @@ static void signal_received_callback(void* context, InfraredWorkerSignal* receiv | ||||
|         size_t timings_cnt; | ||||
|         infrared_worker_get_raw_signal(received_signal, &timings, &timings_cnt); | ||||
| 
 | ||||
|         buf_cnt = snprintf(buf, sizeof(buf), "RAW, %d samples:\r\n", timings_cnt); | ||||
|         buf_cnt = snprintf(buf, sizeof(buf), "RAW, %zu samples:\r\n", timings_cnt); | ||||
|         cli_write(cli, (uint8_t*)buf, buf_cnt); | ||||
|         for(size_t i = 0; i < timings_cnt; ++i) { | ||||
|             buf_cnt = snprintf(buf, sizeof(buf), "%lu ", timings[i]); | ||||
| @ -276,7 +276,9 @@ 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", furi_string_get_cstr(tmp), raw_signal->timings_size); | ||||
|             "Raw signal: %s, %zu 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; | ||||
| @ -382,7 +384,7 @@ static void infrared_cli_list_remote_signals(FuriString* remote_name) { | ||||
|         while(flipper_format_read_string(ff, "name", signal_name)) { | ||||
|             furi_string_set_str(key, furi_string_get_cstr(signal_name)); | ||||
|             int* v = dict_signals_get(signals_dict, key); | ||||
|             if(v != NULL) { | ||||
|             if(v != NULL) { //-V547
 | ||||
|                 (*v)++; | ||||
|                 max = M_MAX(*v, max); | ||||
|             } else { | ||||
| @ -436,7 +438,7 @@ static void | ||||
|             break; | ||||
|         } | ||||
| 
 | ||||
|         printf("Sending %ld signal(s)...\r\n", record_count); | ||||
|         printf("Sending %lu signal(s)...\r\n", record_count); | ||||
|         printf("Press Ctrl-C to stop.\r\n"); | ||||
| 
 | ||||
|         int records_sent = 0; | ||||
|  | ||||
| @ -145,15 +145,14 @@ bool infrared_remote_load(InfraredRemote* remote, FuriString* path) { | ||||
|     buf = furi_string_alloc(); | ||||
| 
 | ||||
|     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)); | ||||
|     bool success = false; | ||||
| 
 | ||||
|     if(success) { | ||||
|     do { | ||||
|         if(!flipper_format_buffered_file_open_existing(ff, furi_string_get_cstr(path))) break; | ||||
|         uint32_t version; | ||||
|         success = flipper_format_read_header(ff, buf, &version) && | ||||
|                   !furi_string_cmp(buf, "IR signals file") && (version == 1); | ||||
|     } | ||||
|         if(!flipper_format_read_header(ff, buf, &version)) break; | ||||
|         if(!furi_string_equal(buf, "IR signals file") || (version != 1)) break; | ||||
| 
 | ||||
|     if(success) { | ||||
|         path_extract_filename(path, buf, true); | ||||
|         infrared_remote_clear_buttons(remote); | ||||
|         infrared_remote_set_name(remote, furi_string_get_cstr(buf)); | ||||
| @ -169,7 +168,8 @@ bool infrared_remote_load(InfraredRemote* remote, FuriString* path) { | ||||
|                 infrared_remote_button_free(button); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|         success = true; | ||||
|     } while(false); | ||||
| 
 | ||||
|     furi_string_free(buf); | ||||
|     flipper_format_free(ff); | ||||
|  | ||||
| @ -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 - %X): %X", | ||||
|             "Timings amount is out of range (0 - %X): %zX", | ||||
|             MAX_TIMINGS_AMOUNT, | ||||
|             raw->timings_size); | ||||
|         return false; | ||||
| @ -275,8 +275,8 @@ bool infrared_signal_search_and_read( | ||||
|             is_name_found = furi_string_equal(name, tmp); | ||||
|             if(is_name_found) break; | ||||
|         } | ||||
|         if(!is_name_found) break; | ||||
|         if(!infrared_signal_read_body(signal, ff)) break; | ||||
|         if(!is_name_found) break; //-V547
 | ||||
|         if(!infrared_signal_read_body(signal, ff)) break; //-V779
 | ||||
|         success = true; | ||||
|     } while(false); | ||||
| 
 | ||||
|  | ||||
| @ -26,7 +26,7 @@ bool infrared_scene_debug_on_event(void* context, SceneManagerEvent event) { | ||||
|                 InfraredRawSignal* raw = infrared_signal_get_raw_signal(signal); | ||||
|                 infrared_debug_view_set_text(debug_view, "RAW\n%d samples\n", raw->timings_size); | ||||
| 
 | ||||
|                 printf("RAW, %d samples:\r\n", raw->timings_size); | ||||
|                 printf("RAW, %zu samples:\r\n", raw->timings_size); | ||||
|                 for(size_t i = 0; i < raw->timings_size; ++i) { | ||||
|                     printf("%lu ", raw->timings[i]); | ||||
|                 } | ||||
|  | ||||
| @ -32,7 +32,7 @@ static void rpc_command_callback(RpcAppSystemEvent rpc_event, void* context) { | ||||
| } | ||||
| 
 | ||||
| static LfRfid* lfrfid_alloc() { | ||||
|     LfRfid* lfrfid = malloc(sizeof(LfRfid)); //-V773
 | ||||
|     LfRfid* lfrfid = malloc(sizeof(LfRfid)); | ||||
| 
 | ||||
|     lfrfid->storage = furi_record_open(RECORD_STORAGE); | ||||
|     lfrfid->dialogs = furi_record_open(RECORD_DIALOGS); | ||||
| @ -100,7 +100,7 @@ static LfRfid* lfrfid_alloc() { | ||||
|         lfrfid->view_dispatcher, LfRfidViewRead, lfrfid_view_read_get_view(lfrfid->read_view)); | ||||
| 
 | ||||
|     return lfrfid; | ||||
| } | ||||
| } //-V773
 | ||||
| 
 | ||||
| static void lfrfid_free(LfRfid* lfrfid) { | ||||
|     furi_assert(lfrfid); | ||||
|  | ||||
| @ -87,7 +87,7 @@ static void lfrfid_cli_read(Cli* cli, FuriString* args) { | ||||
|         uint32_t flags = | ||||
|             furi_event_flag_wait(context.event, available_flags, FuriFlagWaitAny, 100); | ||||
| 
 | ||||
|         if(flags != FuriFlagErrorTimeout) { | ||||
|         if(flags != (unsigned)FuriFlagErrorTimeout) { | ||||
|             if(FURI_BIT(flags, LFRFIDWorkerReadDone)) { | ||||
|                 break; | ||||
|             } | ||||
| @ -153,7 +153,7 @@ static bool lfrfid_cli_parse_args(FuriString* args, ProtocolDict* dict, Protocol | ||||
| 
 | ||||
|             for(ProtocolId i = 0; i < LFRFIDProtocolMax; i++) { | ||||
|                 printf( | ||||
|                     "\t%s, %d bytes long\r\n", | ||||
|                     "\t%s, %zu bytes long\r\n", | ||||
|                     protocol_dict_get_name(dict, i), | ||||
|                     protocol_dict_get_data_size(dict, i)); | ||||
|             } | ||||
| @ -165,7 +165,7 @@ static bool lfrfid_cli_parse_args(FuriString* args, ProtocolDict* dict, Protocol | ||||
|         // check data arg
 | ||||
|         if(!args_read_hex_bytes(data_text, data, data_size)) { | ||||
|             printf( | ||||
|                 "%s data needs to be %d bytes long\r\n", | ||||
|                 "%s data needs to be %zu bytes long\r\n", | ||||
|                 protocol_dict_get_name(dict, *protocol), | ||||
|                 data_size); | ||||
|             break; | ||||
| @ -211,7 +211,7 @@ static void lfrfid_cli_write(Cli* cli, FuriString* args) { | ||||
| 
 | ||||
|     while(!cli_cmd_interrupt_received(cli)) { | ||||
|         uint32_t flags = furi_event_flag_wait(event, available_flags, FuriFlagWaitAny, 100); | ||||
|         if(flags != FuriFlagErrorTimeout) { | ||||
|         if(flags != (unsigned)FuriFlagErrorTimeout) { | ||||
|             if(FURI_BIT(flags, LFRFIDWorkerWriteOK)) { | ||||
|                 printf("Written!\r\n"); | ||||
|                 break; | ||||
| @ -309,9 +309,9 @@ static void lfrfid_cli_raw_analyze(Cli* cli, FuriString* args) { | ||||
|                     warn = true; | ||||
|                 } | ||||
| 
 | ||||
|                 furi_string_printf(info_string, "[%ld %ld]", pulse, duration); | ||||
|                 furi_string_printf(info_string, "[%lu %lu]", pulse, duration); | ||||
|                 printf("%-16s", furi_string_get_cstr(info_string)); | ||||
|                 furi_string_printf(info_string, "[%ld %ld]", pulse, duration - pulse); | ||||
|                 furi_string_printf(info_string, "[%lu %lu]", pulse, duration - pulse); | ||||
|                 printf("%-16s", furi_string_get_cstr(info_string)); | ||||
| 
 | ||||
|                 if(warn) { | ||||
| @ -335,7 +335,7 @@ static void lfrfid_cli_raw_analyze(Cli* cli, FuriString* args) { | ||||
|                 total_pulse += pulse; | ||||
|                 total_duration += duration; | ||||
| 
 | ||||
|                 if(total_protocol != PROTOCOL_NO) { | ||||
|                 if(total_protocol != PROTOCOL_NO) { //-V1051
 | ||||
|                     break; | ||||
|                 } | ||||
|             } else { | ||||
| @ -346,9 +346,9 @@ static void lfrfid_cli_raw_analyze(Cli* cli, FuriString* args) { | ||||
| 
 | ||||
|         printf("   Frequency: %f\r\n", (double)frequency); | ||||
|         printf("  Duty Cycle: %f\r\n", (double)duty_cycle); | ||||
|         printf("       Warns: %ld\r\n", total_warns); | ||||
|         printf("   Pulse sum: %ld\r\n", total_pulse); | ||||
|         printf("Duration sum: %ld\r\n", total_duration); | ||||
|         printf("       Warns: %lu\r\n", total_warns); | ||||
|         printf("   Pulse sum: %lu\r\n", total_pulse); | ||||
|         printf("Duration sum: %lu\r\n", total_duration); | ||||
|         printf("     Average: %f\r\n", (double)((float)total_pulse / (float)total_duration)); | ||||
|         printf("    Protocol: "); | ||||
| 
 | ||||
| @ -435,7 +435,7 @@ static void lfrfid_cli_raw_read(Cli* cli, FuriString* args) { | ||||
|         while(true) { | ||||
|             uint32_t flags = furi_event_flag_wait(event, available_flags, FuriFlagWaitAny, 100); | ||||
| 
 | ||||
|             if(flags != FuriFlagErrorTimeout) { | ||||
|             if(flags != (unsigned)FuriFlagErrorTimeout) { | ||||
|                 if(FURI_BIT(flags, LFRFIDWorkerReadRawFileError)) { | ||||
|                     printf("File is not RFID raw file\r\n"); | ||||
|                     break; | ||||
| @ -510,7 +510,7 @@ static void lfrfid_cli_raw_emulate(Cli* cli, FuriString* args) { | ||||
|         while(true) { | ||||
|             uint32_t flags = furi_event_flag_wait(event, available_flags, FuriFlagWaitAny, 100); | ||||
| 
 | ||||
|             if(flags != FuriFlagErrorTimeout) { | ||||
|             if(flags != (unsigned)FuriFlagErrorTimeout) { | ||||
|                 if(FURI_BIT(flags, LFRFIDWorkerEmulateRawFileError)) { | ||||
|                     printf("File is not RFID raw file\r\n"); | ||||
|                     break; | ||||
|  | ||||
| @ -1,7 +1,6 @@ | ||||
| #include "../lfrfid_i.h" | ||||
| 
 | ||||
| typedef struct { | ||||
|     FuriString* menu_item_name[LFRFIDProtocolMax]; | ||||
|     uint32_t line_sel; | ||||
| } SaveTypeCtx; | ||||
| 
 | ||||
| @ -16,25 +15,27 @@ void lfrfid_scene_save_type_on_enter(void* context) { | ||||
|     Submenu* submenu = app->submenu; | ||||
| 
 | ||||
|     SaveTypeCtx* state = malloc(sizeof(SaveTypeCtx)); | ||||
|     FuriString* protocol_string = furi_string_alloc(); | ||||
|     for(uint8_t i = 0; i < LFRFIDProtocolMax; i++) { | ||||
|         if(strcmp( | ||||
|                protocol_dict_get_manufacturer(app->dict, i), | ||||
|                protocol_dict_get_name(app->dict, i)) != 0) { | ||||
|             state->menu_item_name[i] = furi_string_alloc_printf( | ||||
|             furi_string_printf( | ||||
|                 protocol_string, | ||||
|                 "%s %s", | ||||
|                 protocol_dict_get_manufacturer(app->dict, i), | ||||
|                 protocol_dict_get_name(app->dict, i)); | ||||
|         } else { | ||||
|             state->menu_item_name[i] = | ||||
|                 furi_string_alloc_printf("%s", protocol_dict_get_name(app->dict, i)); | ||||
|             furi_string_printf(protocol_string, "%s", protocol_dict_get_name(app->dict, i)); | ||||
|         } | ||||
|         submenu_add_item( | ||||
|             submenu, | ||||
|             furi_string_get_cstr(state->menu_item_name[i]), | ||||
|             furi_string_get_cstr(protocol_string), | ||||
|             i, | ||||
|             lfrfid_scene_save_type_submenu_callback, | ||||
|             app); | ||||
|     } | ||||
|     furi_string_free(protocol_string); | ||||
| 
 | ||||
|     submenu_set_selected_item( | ||||
|         submenu, scene_manager_get_scene_state(app->scene_manager, LfRfidSceneSaveType)); | ||||
| @ -73,13 +74,7 @@ void lfrfid_scene_save_type_on_exit(void* context) { | ||||
| 
 | ||||
|     submenu_reset(app->submenu); | ||||
| 
 | ||||
|     for(uint8_t i = 0; i < LFRFIDProtocolMax; i++) { | ||||
|         furi_string_free(state->menu_item_name[i]); | ||||
|     } | ||||
| 
 | ||||
|     uint32_t line_sel = state->line_sel; | ||||
| 
 | ||||
|     free(state); | ||||
| 
 | ||||
|     scene_manager_set_scene_state(app->scene_manager, LfRfidSceneSaveType, line_sel); | ||||
| } | ||||
|  | ||||
| @ -39,7 +39,7 @@ static void nfc_scene_emulate_uid_widget_config(Nfc* nfc, bool data_received) { | ||||
| 
 | ||||
|     widget_add_icon_element(widget, 0, 3, &I_NFC_dolphin_emulation_47x61); | ||||
|     widget_add_string_element(widget, 57, 13, AlignLeft, AlignTop, FontPrimary, "Emulating UID"); | ||||
|     if(strcmp(nfc->dev->dev_name, "")) { | ||||
|     if(strcmp(nfc->dev->dev_name, "") != 0) { | ||||
|         furi_string_printf(info_str, "%s", nfc->dev->dev_name); | ||||
|     } else { | ||||
|         for(uint8_t i = 0; i < data->uid_len; i++) { | ||||
|  | ||||
| @ -43,7 +43,7 @@ bool nfc_scene_extra_actions_on_event(void* context, SceneManagerEvent event) { | ||||
| 
 | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         if(event.event == SubmenuIndexMfClassicKeys) { | ||||
|             if(mf_classic_dict_check_presence(MfClassicDictTypeFlipper)) { | ||||
|             if(mf_classic_dict_check_presence(MfClassicDictTypeSystem)) { | ||||
|                 scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicKeys); | ||||
|             } else { | ||||
|                 scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound); | ||||
|  | ||||
| @ -53,10 +53,10 @@ static void nfc_scene_mf_classic_dict_attack_prepare_view(Nfc* nfc, DictAttackSt | ||||
|     // Setup view
 | ||||
|     if(state == DictAttackStateUserDictInProgress) { | ||||
|         worker_state = NfcWorkerStateMfClassicDictAttack; | ||||
|         dict_attack_set_header(nfc->dict_attack, "Mf Classic User Dict."); | ||||
|         dict_attack_set_header(nfc->dict_attack, "MF Classic User Dictionary"); | ||||
|         dict = mf_classic_dict_alloc(MfClassicDictTypeUser); | ||||
| 
 | ||||
|         // If failed to load user dictionary - try flipper dictionary
 | ||||
|         // If failed to load user dictionary - try the system dictionary
 | ||||
|         if(!dict) { | ||||
|             FURI_LOG_E(TAG, "User dictionary not found"); | ||||
|             state = DictAttackStateFlipperDictInProgress; | ||||
| @ -64,11 +64,11 @@ static void nfc_scene_mf_classic_dict_attack_prepare_view(Nfc* nfc, DictAttackSt | ||||
|     } | ||||
|     if(state == DictAttackStateFlipperDictInProgress) { | ||||
|         worker_state = NfcWorkerStateMfClassicDictAttack; | ||||
|         dict_attack_set_header(nfc->dict_attack, "Mf Classic Flipper Dict."); | ||||
|         dict = mf_classic_dict_alloc(MfClassicDictTypeFlipper); | ||||
|         dict_attack_set_header(nfc->dict_attack, "MF Classic System Dictionary"); | ||||
|         dict = mf_classic_dict_alloc(MfClassicDictTypeSystem); | ||||
|         if(!dict) { | ||||
|             FURI_LOG_E(TAG, "Flipper dictionary not found"); | ||||
|             // Pass through to let worker handle the failure
 | ||||
|             // Pass through to let the worker handle the failure
 | ||||
|         } | ||||
|     } | ||||
|     // Free previous dictionary
 | ||||
| @ -153,6 +153,15 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent | ||||
|                 nfc_worker_stop(nfc->worker); | ||||
|                 consumed = true; | ||||
|             } | ||||
|         } else if(event.event == NfcWorkerEventKeyAttackStart) { | ||||
|             dict_attack_set_key_attack( | ||||
|                 nfc->dict_attack, | ||||
|                 true, | ||||
|                 nfc->dev->dev_data.mf_classic_dict_attack_data.current_sector); | ||||
|         } else if(event.event == NfcWorkerEventKeyAttackStop) { | ||||
|             dict_attack_set_key_attack(nfc->dict_attack, false, 0); | ||||
|         } else if(event.event == NfcWorkerEventKeyAttackNextSector) { | ||||
|             dict_attack_inc_key_attack_current_sector(nfc->dict_attack); | ||||
|         } | ||||
|     } else if(event.type == SceneManagerEventTypeBack) { | ||||
|         scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); | ||||
|  | ||||
| @ -18,7 +18,7 @@ void nfc_scene_mf_classic_emulate_on_enter(void* context) { | ||||
|     // Setup view
 | ||||
|     Popup* popup = nfc->popup; | ||||
|     popup_set_header(popup, "Emulating", 67, 13, AlignLeft, AlignTop); | ||||
|     if(strcmp(nfc->dev->dev_name, "")) { | ||||
|     if(strcmp(nfc->dev->dev_name, "") != 0) { | ||||
|         nfc_text_store_set(nfc, "%s", nfc->dev->dev_name); | ||||
|     } else { | ||||
|         nfc_text_store_set(nfc, "MIFARE\nClassic"); | ||||
|  | ||||
| @ -12,7 +12,7 @@ void nfc_scene_mf_classic_keys_on_enter(void* context) { | ||||
| 
 | ||||
|     // Load flipper dict keys total
 | ||||
|     uint32_t flipper_dict_keys_total = 0; | ||||
|     MfClassicDict* dict = mf_classic_dict_alloc(MfClassicDictTypeFlipper); | ||||
|     MfClassicDict* dict = mf_classic_dict_alloc(MfClassicDictTypeSystem); | ||||
|     if(dict) { | ||||
|         flipper_dict_keys_total = mf_classic_dict_get_total_keys(dict); | ||||
|         mf_classic_dict_free(dict); | ||||
| @ -26,11 +26,11 @@ void nfc_scene_mf_classic_keys_on_enter(void* context) { | ||||
|     } | ||||
| 
 | ||||
|     widget_add_string_element( | ||||
|         nfc->widget, 0, 0, AlignLeft, AlignTop, FontPrimary, "Mifare Classic Keys"); | ||||
|         nfc->widget, 0, 0, AlignLeft, AlignTop, FontPrimary, "MIFARE Classic Keys"); | ||||
|     char temp_str[32]; | ||||
|     snprintf(temp_str, sizeof(temp_str), "Flipper list: %ld", flipper_dict_keys_total); | ||||
|     snprintf(temp_str, sizeof(temp_str), "System dict: %lu", flipper_dict_keys_total); | ||||
|     widget_add_string_element(nfc->widget, 0, 20, AlignLeft, AlignTop, FontSecondary, temp_str); | ||||
|     snprintf(temp_str, sizeof(temp_str), "User list: %ld", user_dict_keys_total); | ||||
|     snprintf(temp_str, sizeof(temp_str), "User dict: %lu", user_dict_keys_total); | ||||
|     widget_add_string_element(nfc->widget, 0, 32, AlignLeft, AlignTop, FontSecondary, temp_str); | ||||
|     widget_add_button_element( | ||||
|         nfc->widget, GuiButtonTypeCenter, "Add", nfc_scene_mf_classic_keys_widget_callback, nfc); | ||||
|  | ||||
| @ -27,7 +27,7 @@ void nfc_scene_mf_classic_keys_list_prepare(Nfc* nfc, MfClassicDict* dict) { | ||||
|         char* current_key = (char*)malloc(sizeof(char) * 13); | ||||
|         strncpy(current_key, furi_string_get_cstr(temp_key), 12); | ||||
|         MfClassicUserKeys_push_back(nfc->mfc_key_strs, current_key); | ||||
|         FURI_LOG_D("ListKeys", "Key %ld: %s", index, current_key); | ||||
|         FURI_LOG_D("ListKeys", "Key %lu: %s", index, current_key); | ||||
|         submenu_add_item( | ||||
|             submenu, current_key, index++, nfc_scene_mf_classic_keys_list_submenu_callback, nfc); | ||||
|     } | ||||
|  | ||||
| @ -51,23 +51,18 @@ void nfc_scene_mf_desfire_app_on_enter(void* context) { | ||||
|             nfc_scene_mf_desfire_app_submenu_callback, | ||||
|             nfc); | ||||
| 
 | ||||
|         uint16_t cap = NFC_TEXT_STORE_SIZE; | ||||
|         char* buf = nfc->text_store; | ||||
|         FuriString* label = furi_string_alloc(); | ||||
|         int idx = SubmenuIndexDynamic; | ||||
|         for(MifareDesfireFile* file = app->file_head; file; file = file->next) { | ||||
|             int size = snprintf(buf, cap, "File %d", file->id); | ||||
|             if(size < 0 || size >= cap) { | ||||
|                 FURI_LOG_W( | ||||
|                     TAG, | ||||
|                     "Exceeded NFC_TEXT_STORE_SIZE when preparing file id strings; menu truncated"); | ||||
|                 break; | ||||
|             } | ||||
|             char* label = buf; | ||||
|             cap -= size + 1; | ||||
|             buf += size + 1; | ||||
|             furi_string_printf(label, "File %d", file->id); | ||||
|             submenu_add_item( | ||||
|                 nfc->submenu, label, idx++, nfc_scene_mf_desfire_app_submenu_callback, nfc); | ||||
|                 nfc->submenu, | ||||
|                 furi_string_get_cstr(label), | ||||
|                 idx++, | ||||
|                 nfc_scene_mf_desfire_app_submenu_callback, | ||||
|                 nfc); | ||||
|         } | ||||
|         furi_string_free(label); | ||||
| 
 | ||||
|         view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); | ||||
|     } | ||||
|  | ||||
| @ -33,21 +33,18 @@ void nfc_scene_mf_desfire_data_on_enter(void* context) { | ||||
|         nfc_scene_mf_desfire_data_submenu_callback, | ||||
|         nfc); | ||||
| 
 | ||||
|     uint16_t cap = NFC_TEXT_STORE_SIZE; | ||||
|     char* buf = nfc->text_store; | ||||
|     FuriString* label = furi_string_alloc(); | ||||
|     int idx = SubmenuIndexDynamic; | ||||
|     for(MifareDesfireApplication* app = data->app_head; app; app = app->next) { | ||||
|         int size = snprintf(buf, cap, "App %02x%02x%02x", app->id[0], app->id[1], app->id[2]); | ||||
|         if(size < 0 || size >= cap) { | ||||
|             FURI_LOG_W( | ||||
|                 TAG, "Exceeded NFC_TEXT_STORE_SIZE when preparing app id strings; menu truncated"); | ||||
|             break; | ||||
|         } | ||||
|         char* label = buf; | ||||
|         cap -= size + 1; | ||||
|         buf += size + 1; | ||||
|         submenu_add_item(submenu, label, idx++, nfc_scene_mf_desfire_data_submenu_callback, nfc); | ||||
|         furi_string_printf(label, "App %02x%02x%02x", app->id[0], app->id[1], app->id[2]); | ||||
|         submenu_add_item( | ||||
|             submenu, | ||||
|             furi_string_get_cstr(label), | ||||
|             idx++, | ||||
|             nfc_scene_mf_desfire_data_submenu_callback, | ||||
|             nfc); | ||||
|     } | ||||
|     furi_string_free(label); | ||||
| 
 | ||||
|     if(state >= MifareDesfireDataStateItem) { | ||||
|         submenu_set_selected_item( | ||||
|  | ||||
| @ -26,13 +26,13 @@ void nfc_scene_mf_desfire_read_success_on_enter(void* context) { | ||||
|         furi_string_cat_printf(temp_str, " %02X", nfc_data->uid[i]); | ||||
|     } | ||||
| 
 | ||||
|     uint32_t bytes_total = 1 << (data->version.sw_storage >> 1); | ||||
|     uint32_t bytes_total = 1UL << (data->version.sw_storage >> 1); | ||||
|     uint32_t bytes_free = data->free_memory ? data->free_memory->bytes : 0; | ||||
|     furi_string_cat_printf(temp_str, "\n%ld", bytes_total); | ||||
|     furi_string_cat_printf(temp_str, "\n%lu", bytes_total); | ||||
|     if(data->version.sw_storage & 1) { | ||||
|         furi_string_push_back(temp_str, '+'); | ||||
|     } | ||||
|     furi_string_cat_printf(temp_str, " bytes, %ld bytes free\n", bytes_free); | ||||
|     furi_string_cat_printf(temp_str, " bytes, %lu bytes free\n", bytes_free); | ||||
| 
 | ||||
|     uint16_t n_apps = 0; | ||||
|     uint16_t n_files = 0; | ||||
|  | ||||
| @ -21,7 +21,7 @@ void nfc_scene_mf_ultralight_emulate_on_enter(void* context) { | ||||
|                          (type == MfUltralightTypeUnknown); | ||||
|     Popup* popup = nfc->popup; | ||||
|     popup_set_header(popup, "Emulating", 67, 13, AlignLeft, AlignTop); | ||||
|     if(strcmp(nfc->dev->dev_name, "")) { | ||||
|     if(strcmp(nfc->dev->dev_name, "") != 0) { | ||||
|         nfc_text_store_set(nfc, "%s", nfc->dev->dev_name); | ||||
|     } else if(is_ultralight) { | ||||
|         nfc_text_store_set(nfc, "MIFARE\nUltralight"); | ||||
|  | ||||
| @ -57,13 +57,13 @@ void nfc_scene_nfc_data_info_on_enter(void* context) { | ||||
|     // Set application specific data
 | ||||
|     if(protocol == NfcDeviceProtocolMifareDesfire) { | ||||
|         MifareDesfireData* data = &dev_data->mf_df_data; | ||||
|         uint32_t bytes_total = 1 << (data->version.sw_storage >> 1); | ||||
|         uint32_t bytes_total = 1UL << (data->version.sw_storage >> 1); | ||||
|         uint32_t bytes_free = data->free_memory ? data->free_memory->bytes : 0; | ||||
|         furi_string_cat_printf(temp_str, "\n%ld", bytes_total); | ||||
|         furi_string_cat_printf(temp_str, "\n%lu", bytes_total); | ||||
|         if(data->version.sw_storage & 1) { | ||||
|             furi_string_push_back(temp_str, '+'); | ||||
|         } | ||||
|         furi_string_cat_printf(temp_str, " bytes, %ld bytes free\n", bytes_free); | ||||
|         furi_string_cat_printf(temp_str, " bytes, %lu bytes free\n", bytes_free); | ||||
| 
 | ||||
|         uint16_t n_apps = 0; | ||||
|         uint16_t n_files = 0; | ||||
|  | ||||
| @ -71,7 +71,7 @@ bool nfc_scene_read_on_event(void* context, SceneManagerEvent event) { | ||||
|         } else if(event.event == NfcWorkerEventReadMfUltralight) { | ||||
|             notification_message(nfc->notifications, &sequence_success); | ||||
|             // Set unlock password input to 0xFFFFFFFF only on fresh read
 | ||||
|             memset(nfc->byte_input_store, 0xFF, 4); | ||||
|             memset(nfc->byte_input_store, 0xFF, sizeof(nfc->byte_input_store)); | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadSuccess); | ||||
|             DOLPHIN_DEED(DolphinDeedNfcReadSuccess); | ||||
|             consumed = true; | ||||
| @ -91,7 +91,7 @@ bool nfc_scene_read_on_event(void* context, SceneManagerEvent event) { | ||||
|             DOLPHIN_DEED(DolphinDeedNfcReadSuccess); | ||||
|             consumed = true; | ||||
|         } else if(event.event == NfcWorkerEventReadMfClassicDictAttackRequired) { | ||||
|             if(mf_classic_dict_check_presence(MfClassicDictTypeFlipper)) { | ||||
|             if(mf_classic_dict_check_presence(MfClassicDictTypeSystem)) { | ||||
|                 scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicDictAttack); | ||||
|             } else { | ||||
|                 scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound); | ||||
|  | ||||
| @ -55,7 +55,7 @@ bool nfc_scene_save_name_on_event(void* context, SceneManagerEvent event) { | ||||
| 
 | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         if(event.event == NfcCustomEventTextInputDone) { | ||||
|             if(strcmp(nfc->dev->dev_name, "")) { | ||||
|             if(strcmp(nfc->dev->dev_name, "") != 0) { | ||||
|                 nfc_device_delete(nfc->dev, true); | ||||
|             } | ||||
|             if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetUid)) { | ||||
|  | ||||
| @ -7,7 +7,7 @@ enum SubmenuIndex { | ||||
|     SubmenuIndexDetectReader, | ||||
|     SubmenuIndexSaved, | ||||
|     SubmenuIndexExtraAction, | ||||
|     SubmenuIndexAddManualy, | ||||
|     SubmenuIndexAddManually, | ||||
|     SubmenuIndexDebug, | ||||
| }; | ||||
| 
 | ||||
| @ -28,7 +28,7 @@ void nfc_scene_start_on_enter(void* context) { | ||||
|     submenu_add_item( | ||||
|         submenu, "Extra Actions", SubmenuIndexExtraAction, nfc_scene_start_submenu_callback, nfc); | ||||
|     submenu_add_item( | ||||
|         submenu, "Add Manually", SubmenuIndexAddManualy, nfc_scene_start_submenu_callback, nfc); | ||||
|         submenu, "Add Manually", SubmenuIndexAddManually, nfc_scene_start_submenu_callback, nfc); | ||||
| 
 | ||||
|     if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { | ||||
|         submenu_add_item( | ||||
| @ -68,7 +68,7 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) { | ||||
|         } else if(event.event == SubmenuIndexExtraAction) { | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneExtraActions); | ||||
|             consumed = true; | ||||
|         } else if(event.event == SubmenuIndexAddManualy) { | ||||
|         } else if(event.event == SubmenuIndexAddManually) { | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneSetType); | ||||
|             consumed = true; | ||||
|         } else if(event.event == SubmenuIndexDebug) { | ||||
|  | ||||
| @ -24,6 +24,8 @@ typedef struct { | ||||
|     uint8_t keys_found; | ||||
|     uint16_t dict_keys_total; | ||||
|     uint16_t dict_keys_current; | ||||
|     bool is_key_attack; | ||||
|     uint8_t key_attack_current_sector; | ||||
| } DictAttackViewModel; | ||||
| 
 | ||||
| static void dict_attack_draw_callback(Canvas* canvas, void* model) { | ||||
| @ -36,10 +38,19 @@ static void dict_attack_draw_callback(Canvas* canvas, void* model) { | ||||
|             canvas, 64, 23, AlignCenter, AlignTop, "Make sure the tag is\npositioned correctly."); | ||||
|     } else if(m->state == DictAttackStateRead) { | ||||
|         char draw_str[32] = {}; | ||||
|         canvas_set_font(canvas, FontPrimary); | ||||
|         canvas_draw_str_aligned( | ||||
|             canvas, 64, 2, AlignCenter, AlignTop, furi_string_get_cstr(m->header)); | ||||
|         canvas_set_font(canvas, FontSecondary); | ||||
|         canvas_draw_str_aligned( | ||||
|             canvas, 64, 0, AlignCenter, AlignTop, furi_string_get_cstr(m->header)); | ||||
|         if(m->is_key_attack) { | ||||
|             snprintf( | ||||
|                 draw_str, | ||||
|                 sizeof(draw_str), | ||||
|                 "Reuse key check for sector: %d", | ||||
|                 m->key_attack_current_sector); | ||||
|         } else { | ||||
|             snprintf(draw_str, sizeof(draw_str), "Unlocking sector: %d", m->sector_current); | ||||
|         } | ||||
|         canvas_draw_str_aligned(canvas, 0, 10, AlignLeft, AlignTop, draw_str); | ||||
|         float dict_progress = m->dict_keys_total == 0 ? | ||||
|                                   0 : | ||||
|                                   (float)(m->dict_keys_current) / (float)(m->dict_keys_total); | ||||
| @ -49,13 +60,20 @@ static void dict_attack_draw_callback(Canvas* canvas, void* model) { | ||||
|         if(progress > 1.0) { | ||||
|             progress = 1.0; | ||||
|         } | ||||
|         elements_progress_bar(canvas, 5, 15, 120, progress); | ||||
|         if(m->dict_keys_current == 0) { | ||||
|             // Cause when people see 0 they think it's broken
 | ||||
|             snprintf(draw_str, sizeof(draw_str), "%d/%d", 1, m->dict_keys_total); | ||||
|         } else { | ||||
|             snprintf( | ||||
|                 draw_str, sizeof(draw_str), "%d/%d", m->dict_keys_current, m->dict_keys_total); | ||||
|         } | ||||
|         elements_progress_bar_with_text(canvas, 0, 20, 128, dict_progress, draw_str); | ||||
|         canvas_set_font(canvas, FontSecondary); | ||||
|         snprintf(draw_str, sizeof(draw_str), "Keys found: %d/%d", m->keys_found, m->keys_total); | ||||
|         canvas_draw_str_aligned(canvas, 1, 28, AlignLeft, AlignTop, draw_str); | ||||
|         canvas_draw_str_aligned(canvas, 0, 33, AlignLeft, AlignTop, draw_str); | ||||
|         snprintf( | ||||
|             draw_str, sizeof(draw_str), "Sectors Read: %d/%d", m->sectors_read, m->sectors_total); | ||||
|         canvas_draw_str_aligned(canvas, 1, 40, AlignLeft, AlignTop, draw_str); | ||||
|         canvas_draw_str_aligned(canvas, 0, 43, AlignLeft, AlignTop, draw_str); | ||||
|     } | ||||
|     elements_button_center(canvas, "Skip"); | ||||
| } | ||||
| @ -113,6 +131,7 @@ void dict_attack_reset(DictAttack* dict_attack) { | ||||
|             model->keys_found = 0; | ||||
|             model->dict_keys_total = 0; | ||||
|             model->dict_keys_current = 0; | ||||
|             model->is_key_attack = false; | ||||
|             furi_string_reset(model->header); | ||||
|         }, | ||||
|         false); | ||||
| @ -235,3 +254,28 @@ void dict_attack_inc_current_dict_key(DictAttack* dict_attack, uint16_t keys_tri | ||||
|         }, | ||||
|         true); | ||||
| } | ||||
| 
 | ||||
| void dict_attack_set_key_attack(DictAttack* dict_attack, bool is_key_attack, uint8_t sector) { | ||||
|     furi_assert(dict_attack); | ||||
|     with_view_model( | ||||
|         dict_attack->view, | ||||
|         DictAttackViewModel * model, | ||||
|         { | ||||
|             model->is_key_attack = is_key_attack; | ||||
|             model->key_attack_current_sector = sector; | ||||
|         }, | ||||
|         true); | ||||
| } | ||||
| 
 | ||||
| void dict_attack_inc_key_attack_current_sector(DictAttack* dict_attack) { | ||||
|     furi_assert(dict_attack); | ||||
|     with_view_model( | ||||
|         dict_attack->view, | ||||
|         DictAttackViewModel * model, | ||||
|         { | ||||
|             if(model->key_attack_current_sector < model->sectors_total) { | ||||
|                 model->key_attack_current_sector++; | ||||
|             } | ||||
|         }, | ||||
|         true); | ||||
| } | ||||
|  | ||||
| @ -38,3 +38,7 @@ void dict_attack_inc_keys_found(DictAttack* dict_attack); | ||||
| void dict_attack_set_total_dict_keys(DictAttack* dict_attack, uint16_t dict_keys_total); | ||||
| 
 | ||||
| void dict_attack_inc_current_dict_key(DictAttack* dict_attack, uint16_t keys_tried); | ||||
| 
 | ||||
| void dict_attack_set_key_attack(DictAttack* dict_attack, bool is_key_attack, uint8_t sector); | ||||
| 
 | ||||
| void dict_attack_inc_key_attack_current_sector(DictAttack* dict_attack); | ||||
| @ -2,6 +2,7 @@ | ||||
| #include <lib/drivers/cc1101.h> | ||||
| 
 | ||||
| #include <furi.h> | ||||
| #include <float_tools.h> | ||||
| 
 | ||||
| #define TAG "SubghzFrequencyAnalyzerWorker" | ||||
| 
 | ||||
| @ -197,7 +198,7 @@ static int32_t subghz_frequency_analyzer_worker_thread(void* context) { | ||||
|             rssi_temp = (rssi_temp + frequency_rssi.rssi_fine) / 2; | ||||
|             frequency_temp = frequency_rssi.frequency_fine; | ||||
| 
 | ||||
|             if(instance->filVal) { | ||||
|             if(!float_is_equal(instance->filVal, 0.f)) { | ||||
|                 frequency_rssi.frequency_fine = | ||||
|                     subghz_frequency_analyzer_worker_expRunningAverageAdaptive( | ||||
|                         instance, frequency_rssi.frequency_fine); | ||||
| @ -219,7 +220,7 @@ static int32_t subghz_frequency_analyzer_worker_thread(void* context) { | ||||
|             instance->sample_hold_counter = 20; | ||||
|             rssi_temp = (rssi_temp + frequency_rssi.rssi_coarse) / 2; | ||||
|             frequency_temp = frequency_rssi.frequency_coarse; | ||||
|             if(instance->filVal) { | ||||
|             if(!float_is_equal(instance->filVal, 0.f)) { | ||||
|                 frequency_rssi.frequency_coarse = | ||||
|                     subghz_frequency_analyzer_worker_expRunningAverageAdaptive( | ||||
|                         instance, frequency_rssi.frequency_coarse); | ||||
|  | ||||
| @ -23,3 +23,4 @@ ADD_SCENE(subghz, more_raw, MoreRAW) | ||||
| ADD_SCENE(subghz, delete_raw, DeleteRAW) | ||||
| ADD_SCENE(subghz, need_saving, NeedSaving) | ||||
| ADD_SCENE(subghz, rpc, Rpc) | ||||
| ADD_SCENE(subghz, region_info, RegionInfo) | ||||
|  | ||||
| @ -3,6 +3,7 @@ | ||||
| #include <dolphin/dolphin.h> | ||||
| #include <lib/subghz/protocols/raw.h> | ||||
| #include <lib/toolbox/path.h> | ||||
| #include <float_tools.h> | ||||
| 
 | ||||
| #define RAW_FILE_NAME "Raw_signal_" | ||||
| #define TAG "SubGhzSceneReadRAW" | ||||
| @ -358,7 +359,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { | ||||
| 
 | ||||
|             float rssi = furi_hal_subghz_get_rssi(); | ||||
| 
 | ||||
|             if(subghz->txrx->raw_threshold_rssi == SUBGHZ_RAW_TRESHOLD_MIN) { | ||||
|             if(float_is_equal(subghz->txrx->raw_threshold_rssi, SUBGHZ_RAW_TRESHOLD_MIN)) { | ||||
|                 subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, rssi, true); | ||||
|                 subghz_protocol_raw_save_to_file_pause( | ||||
|                     (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result, false); | ||||
|  | ||||
							
								
								
									
										39
									
								
								applications/main/subghz/scenes/subghz_scene_region_info.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								applications/main/subghz/scenes/subghz_scene_region_info.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,39 @@ | ||||
| #include "../subghz_i.h" | ||||
| 
 | ||||
| #include <furi_hal_region.h> | ||||
| 
 | ||||
| void subghz_scene_region_info_on_enter(void* context) { | ||||
|     SubGhz* subghz = context; | ||||
|     const FuriHalRegion* const region = furi_hal_region_get(); | ||||
|     FuriString* buffer; | ||||
|     buffer = furi_string_alloc(); | ||||
|     if(region) { | ||||
|         furi_string_cat_printf(buffer, "Region: %s,  bands:\n", region->country_code); | ||||
|         for(uint16_t i = 0; i < region->bands_count; ++i) { | ||||
|             furi_string_cat_printf( | ||||
|                 buffer, | ||||
|                 "   %lu-%lu kHz\n", | ||||
|                 region->bands[i].start / 1000, | ||||
|                 region->bands[i].end / 1000); | ||||
|         } | ||||
|     } else { | ||||
|         furi_string_cat_printf(buffer, "Region: N/A\n"); | ||||
|     } | ||||
| 
 | ||||
|     widget_add_string_multiline_element( | ||||
|         subghz->widget, 0, 0, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(buffer)); | ||||
| 
 | ||||
|     furi_string_free(buffer); | ||||
|     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdWidget); | ||||
| } | ||||
| 
 | ||||
| bool subghz_scene_region_info_on_event(void* context, SceneManagerEvent event) { | ||||
|     UNUSED(context); | ||||
|     UNUSED(event); | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| void subghz_scene_region_info_on_exit(void* context) { | ||||
|     SubGhz* subghz = context; | ||||
|     widget_reset(subghz->widget); | ||||
| } | ||||
| @ -94,7 +94,7 @@ bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) { | ||||
|         return true; | ||||
|     } else if(event.type == SceneManagerEventTypeCustom) { | ||||
|         if(event.event == SubGhzCustomEventSceneSaveName) { | ||||
|             if(strcmp(subghz->file_name_tmp, "")) { | ||||
|             if(strcmp(subghz->file_name_tmp, "") != 0) { | ||||
|                 furi_string_cat_printf( | ||||
|                     subghz->file_path, "/%s%s", subghz->file_name_tmp, SUBGHZ_APP_EXTENSION); | ||||
|                 if(subghz_path_is_file(subghz->file_path_tmp)) { | ||||
|  | ||||
| @ -46,7 +46,7 @@ bool subghz_scene_set_type_submenu_gen_data_protocol( | ||||
| 
 | ||||
|         uint8_t key_data[sizeof(uint64_t)] = {0}; | ||||
|         for(size_t i = 0; i < sizeof(uint64_t); i++) { | ||||
|             key_data[sizeof(uint64_t) - i - 1] = (key >> i * 8) & 0xFF; | ||||
|             key_data[sizeof(uint64_t) - i - 1] = (key >> (i * 8)) & 0xFF; | ||||
|         } | ||||
|         if(!flipper_format_update_hex(subghz->txrx->fff_data, "Key", key_data, sizeof(uint64_t))) { | ||||
|             FURI_LOG_E(TAG, "Unable to update Key"); | ||||
|  | ||||
| @ -5,9 +5,10 @@ enum SubmenuIndex { | ||||
|     SubmenuIndexRead = 10, | ||||
|     SubmenuIndexSaved, | ||||
|     SubmenuIndexTest, | ||||
|     SubmenuIndexAddManualy, | ||||
|     SubmenuIndexAddManually, | ||||
|     SubmenuIndexFrequencyAnalyzer, | ||||
|     SubmenuIndexReadRAW, | ||||
|     SubmenuIndexShowRegionInfo | ||||
| }; | ||||
| 
 | ||||
| void subghz_scene_start_submenu_callback(void* context, uint32_t index) { | ||||
| @ -33,7 +34,7 @@ void subghz_scene_start_on_enter(void* context) { | ||||
|     submenu_add_item( | ||||
|         subghz->submenu, | ||||
|         "Add Manually", | ||||
|         SubmenuIndexAddManualy, | ||||
|         SubmenuIndexAddManually, | ||||
|         subghz_scene_start_submenu_callback, | ||||
|         subghz); | ||||
|     submenu_add_item( | ||||
| @ -42,6 +43,12 @@ void subghz_scene_start_on_enter(void* context) { | ||||
|         SubmenuIndexFrequencyAnalyzer, | ||||
|         subghz_scene_start_submenu_callback, | ||||
|         subghz); | ||||
|     submenu_add_item( | ||||
|         subghz->submenu, | ||||
|         "Region Information", | ||||
|         SubmenuIndexShowRegionInfo, | ||||
|         subghz_scene_start_submenu_callback, | ||||
|         subghz); | ||||
|     if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { | ||||
|         submenu_add_item( | ||||
|             subghz->submenu, "Test", SubmenuIndexTest, subghz_scene_start_submenu_callback, subghz); | ||||
| @ -76,9 +83,9 @@ bool subghz_scene_start_on_event(void* context, SceneManagerEvent event) { | ||||
|                 subghz->scene_manager, SubGhzSceneStart, SubmenuIndexSaved); | ||||
|             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaved); | ||||
|             return true; | ||||
|         } else if(event.event == SubmenuIndexAddManualy) { | ||||
|         } else if(event.event == SubmenuIndexAddManually) { | ||||
|             scene_manager_set_scene_state( | ||||
|                 subghz->scene_manager, SubGhzSceneStart, SubmenuIndexAddManualy); | ||||
|                 subghz->scene_manager, SubGhzSceneStart, SubmenuIndexAddManually); | ||||
|             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetType); | ||||
|             return true; | ||||
|         } else if(event.event == SubmenuIndexFrequencyAnalyzer) { | ||||
| @ -92,6 +99,11 @@ bool subghz_scene_start_on_event(void* context, SceneManagerEvent event) { | ||||
|                 subghz->scene_manager, SubGhzSceneStart, SubmenuIndexTest); | ||||
|             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneTest); | ||||
|             return true; | ||||
|         } else if(event.event == SubmenuIndexShowRegionInfo) { | ||||
|             scene_manager_set_scene_state( | ||||
|                 subghz->scene_manager, SubGhzSceneStart, SubmenuIndexShowRegionInfo); | ||||
|             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneRegionInfo); | ||||
|             return true; | ||||
|         } | ||||
|     } | ||||
|     return false; | ||||
|  | ||||
| @ -152,11 +152,11 @@ void subghz_cli_command_tx(Cli* cli, FuriString* args, void* context) { | ||||
|         "Protocol: Princeton\n" | ||||
|         "Bit: 24\n" | ||||
|         "Key: 00 00 00 00 00 %02X %02X %02X\n" | ||||
|         "TE: %ld\n" | ||||
|         "Repeat: %ld\n", | ||||
|         (uint8_t)((key >> 16) & 0xFF), | ||||
|         (uint8_t)((key >> 8) & 0xFF), | ||||
|         (uint8_t)(key & 0xFF), | ||||
|         "TE: %lu\n" | ||||
|         "Repeat: %lu\n", | ||||
|         (uint8_t)((key >> 16) & 0xFFU), | ||||
|         (uint8_t)((key >> 8) & 0xFFU), | ||||
|         (uint8_t)(key & 0xFFU), | ||||
|         te, | ||||
|         repeat); | ||||
|     FlipperFormat* flipper_format = flipper_format_string_alloc(); | ||||
| @ -300,7 +300,7 @@ void subghz_cli_command_rx(Cli* cli, FuriString* args, void* context) { | ||||
| 
 | ||||
|     furi_hal_power_suppress_charge_exit(); | ||||
| 
 | ||||
|     printf("\r\nPackets received %u\r\n", instance->packet_count); | ||||
|     printf("\r\nPackets received %zu\r\n", instance->packet_count); | ||||
| 
 | ||||
|     // Cleanup
 | ||||
|     subghz_receiver_free(receiver); | ||||
| @ -787,8 +787,9 @@ static bool subghz_on_system_start_istream_decode_band( | ||||
|     } | ||||
| 
 | ||||
|     region->bands_count += 1; | ||||
|     region = | ||||
|         realloc(region, sizeof(FuriHalRegion) + sizeof(FuriHalRegionBand) * region->bands_count); | ||||
|     region = realloc( //-V701
 | ||||
|         region, | ||||
|         sizeof(FuriHalRegion) + sizeof(FuriHalRegionBand) * region->bands_count); | ||||
|     size_t pos = region->bands_count - 1; | ||||
|     region->bands[pos].start = band.start; | ||||
|     region->bands[pos].end = band.end; | ||||
| @ -798,7 +799,7 @@ static bool subghz_on_system_start_istream_decode_band( | ||||
| 
 | ||||
|     FURI_LOG_I( | ||||
|         "SubGhzOnStart", | ||||
|         "Add allowed band: start %ldHz, stop %ldHz, power_limit %ddBm, duty_cycle %d%%", | ||||
|         "Add allowed band: start %luHz, stop %luHz, power_limit %ddBm, duty_cycle %u%%", | ||||
|         band.start, | ||||
|         band.end, | ||||
|         band.power_limit, | ||||
|  | ||||
| @ -164,7 +164,7 @@ bool subghz_tx_start(SubGhz* subghz, FlipperFormat* flipper_format) { | ||||
| 
 | ||||
|         if(subghz->txrx->transmitter) { | ||||
|             if(subghz_transmitter_deserialize(subghz->txrx->transmitter, flipper_format)) { | ||||
|                 if(strcmp(furi_string_get_cstr(subghz->txrx->preset->name), "")) { | ||||
|                 if(strcmp(furi_string_get_cstr(subghz->txrx->preset->name), "") != 0) { | ||||
|                     subghz_begin( | ||||
|                         subghz, | ||||
|                         subghz_setting_get_preset_data_by_name( | ||||
| @ -544,11 +544,8 @@ void subghz_hopper_update(SubGhz* subghz) { | ||||
| 
 | ||||
|     switch(subghz->txrx->hopper_state) { | ||||
|     case SubGhzHopperStateOFF: | ||||
|         return; | ||||
|         break; | ||||
|     case SubGhzHopperStatePause: | ||||
|         return; | ||||
|         break; | ||||
|     case SubGhzHopperStateRSSITimeOut: | ||||
|         if(subghz->txrx->hopper_timeout != 0) { | ||||
|             subghz->txrx->hopper_timeout--; | ||||
|  | ||||
| @ -11,6 +11,7 @@ | ||||
| #include "../helpers/subghz_frequency_analyzer_log_item_array.h" | ||||
| 
 | ||||
| #include <assets_icons.h> | ||||
| #include <float_tools.h> | ||||
| 
 | ||||
| #define LOG_FREQUENCY_MAX_ITEMS 60 // uint8_t (limited by 'seq' of SubGhzFrequencyAnalyzerLogItem)
 | ||||
| 
 | ||||
| @ -47,7 +48,8 @@ typedef struct { | ||||
| } SubGhzFrequencyAnalyzerModel; | ||||
| 
 | ||||
| static inline uint8_t rssi_sanitize(float rssi) { | ||||
|     return (rssi ? (uint8_t)(rssi - SUBGHZ_FREQUENCY_ANALYZER_THRESHOLD) : 0); | ||||
|     return ( | ||||
|         !float_is_equal(rssi, 0.f) ? (uint8_t)(rssi - SUBGHZ_FREQUENCY_ANALYZER_THRESHOLD) : 0); | ||||
| } | ||||
| 
 | ||||
| void subghz_frequency_analyzer_set_callback( | ||||
| @ -294,9 +296,6 @@ static bool subghz_frequency_analyzer_log_frequency_insert(SubGhzFrequencyAnalyz | ||||
|     if(items_count < LOG_FREQUENCY_MAX_ITEMS) { | ||||
|         SubGhzFrequencyAnalyzerLogItem_t* item = | ||||
|             SubGhzFrequencyAnalyzerLogItemArray_push_new(model->log_frequency); | ||||
|         if(item == NULL) { | ||||
|             return false; | ||||
|         } | ||||
|         (*item)->frequency = model->frequency; | ||||
|         (*item)->count = 1; | ||||
|         (*item)->rssi_max = model->rssi; | ||||
| @ -340,7 +339,7 @@ void subghz_frequency_analyzer_pair_callback( | ||||
|     float rssi, | ||||
|     bool signal) { | ||||
|     SubGhzFrequencyAnalyzer* instance = context; | ||||
|     if((rssi == 0.f) && (instance->locked)) { | ||||
|     if(float_is_equal(rssi, 0.f) && instance->locked) { | ||||
|         if(instance->callback) { | ||||
|             instance->callback(SubGhzCustomEventSceneAnalyzerUnlock, instance->context); | ||||
|         } | ||||
| @ -355,13 +354,13 @@ void subghz_frequency_analyzer_pair_callback( | ||||
|                 model->history_frequency[0] = model->frequency; | ||||
|             }, | ||||
|             false); | ||||
|     } else if((rssi != 0.f) && (!instance->locked)) { | ||||
|     } else if(!float_is_equal(rssi, 0.f) && !instance->locked) { | ||||
|         if(instance->callback) { | ||||
|             instance->callback(SubGhzCustomEventSceneAnalyzerLock, instance->context); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     instance->locked = (rssi != 0.f); | ||||
|     instance->locked = !float_is_equal(rssi, 0.f); | ||||
|     with_view_model( | ||||
|         instance->view, | ||||
|         SubGhzFrequencyAnalyzerModel * model, | ||||
|  | ||||
| @ -91,7 +91,7 @@ void subghz_read_raw_update_sample_write(SubGhzReadRAW* instance, size_t sample) | ||||
|     with_view_model( | ||||
|         instance->view, | ||||
|         SubGhzReadRAWModel * model, | ||||
|         { furi_string_printf(model->sample_write, "%d spl.", sample); }, | ||||
|         { furi_string_printf(model->sample_write, "%zu spl.", sample); }, | ||||
|         false); | ||||
| } | ||||
| 
 | ||||
| @ -161,7 +161,7 @@ void subghz_read_raw_draw_sin(Canvas* canvas, SubGhzReadRAWModel* model) { | ||||
|         canvas_draw_line( | ||||
|             canvas, | ||||
|             i + 1, | ||||
|             32 - subghz_read_raw_tab_sin((i + model->ind_sin * 16)) / SUBGHZ_RAW_SIN_AMPLITUDE, | ||||
|             32 - subghz_read_raw_tab_sin(i + model->ind_sin * 16) / SUBGHZ_RAW_SIN_AMPLITUDE, | ||||
|             i + 2, | ||||
|             32 + subghz_read_raw_tab_sin((i + model->ind_sin * 16 + 1) * 2) / | ||||
|                      SUBGHZ_RAW_SIN_AMPLITUDE); | ||||
|  | ||||
| @ -114,7 +114,7 @@ static void subghz_test_packet_draw(Canvas* canvas, SubGhzTestPacketModel* model | ||||
|     snprintf(buffer, sizeof(buffer), "Path: %d - %s", model->path, path_name); | ||||
|     canvas_draw_str(canvas, 0, 31, buffer); | ||||
| 
 | ||||
|     snprintf(buffer, sizeof(buffer), "Packets: %d", model->packets); | ||||
|     snprintf(buffer, sizeof(buffer), "Packets: %zu", model->packets); | ||||
|     canvas_draw_str(canvas, 0, 42, buffer); | ||||
| 
 | ||||
|     if(model->status == SubGhzTestPacketModelStatusRx) { | ||||
|  | ||||
| @ -58,7 +58,7 @@ bool u2f_scene_main_on_event(void* context, SceneManagerEvent event) { | ||||
|                 app->event_cur = event.event; | ||||
|                 if(event.event == U2fCustomEventRegister) | ||||
|                     u2f_view_set_state(app->u2f_view, U2fMsgRegister); | ||||
|                 else if(event.event == U2fCustomEventAuth) | ||||
|                 else if(event.event == U2fCustomEventAuth) //-V547
 | ||||
|                     u2f_view_set_state(app->u2f_view, U2fMsgAuth); | ||||
|                 notification_message(app->notifications, &sequence_display_backlight_on); | ||||
|                 notification_message(app->notifications, &sequence_single_vibro); | ||||
|  | ||||
| @ -402,9 +402,9 @@ bool u2f_data_cnt_read(uint32_t* cnt_val) { | ||||
|                 FURI_LOG_E(TAG, "Unable to load encryption key"); | ||||
|                 break; | ||||
|             } | ||||
|             memset(&cnt, 0, 32); | ||||
|             if(!furi_hal_crypto_decrypt(cnt_encr, (uint8_t*)&cnt, 32)) { | ||||
|                 memset(&cnt, 0, 32); | ||||
|             memset(&cnt, 0, sizeof(U2fCounterData)); | ||||
|             if(!furi_hal_crypto_decrypt(cnt_encr, (uint8_t*)&cnt, sizeof(U2fCounterData))) { | ||||
|                 memset(&cnt, 0, sizeof(U2fCounterData)); | ||||
|                 FURI_LOG_E(TAG, "Decryption failed"); | ||||
|                 break; | ||||
|             } | ||||
|  | ||||
| @ -94,7 +94,7 @@ static void u2f_hid_send_response(U2fHid* u2f_hid) { | ||||
|     uint16_t data_ptr = 0; | ||||
| 
 | ||||
|     memset(packet_buf, 0, HID_U2F_PACKET_LEN); | ||||
|     memcpy(packet_buf, &(u2f_hid->packet.cid), 4); | ||||
|     memcpy(packet_buf, &(u2f_hid->packet.cid), sizeof(uint32_t)); //-V1086
 | ||||
| 
 | ||||
|     // Init packet
 | ||||
|     packet_buf[4] = u2f_hid->packet.cmd; | ||||
| @ -166,7 +166,7 @@ static bool u2f_hid_parse_request(U2fHid* u2f_hid) { | ||||
|             return false; | ||||
|         u2f_hid->packet.len = 17; | ||||
|         uint32_t random_cid = furi_hal_random_get(); | ||||
|         memcpy(&(u2f_hid->packet.payload[8]), &random_cid, 4); | ||||
|         memcpy(&(u2f_hid->packet.payload[8]), &random_cid, sizeof(uint32_t)); //-V1086
 | ||||
|         u2f_hid->packet.payload[12] = 2; // Protocol version
 | ||||
|         u2f_hid->packet.payload[13] = 1; // Device version major
 | ||||
|         u2f_hid->packet.payload[14] = 0; // Device version minor
 | ||||
| @ -177,7 +177,7 @@ static bool u2f_hid_parse_request(U2fHid* u2f_hid) { | ||||
|     } else if(u2f_hid->packet.cmd == U2F_HID_WINK) { // WINK - notify user
 | ||||
|         if(u2f_hid->packet.len != 0) return false; | ||||
|         u2f_wink(u2f_hid->u2f_instance); | ||||
|         u2f_hid->packet.len = 0; | ||||
|         u2f_hid->packet.len = 0; //-V1048
 | ||||
|         u2f_hid_send_response(u2f_hid); | ||||
|     } else | ||||
|         return false; | ||||
|  | ||||
| @ -568,12 +568,12 @@ void dap_common_usb_set_state_callback(DapStateCallback callback) { | ||||
| static void* dap_usb_alloc_string_descr(const char* str) { | ||||
|     furi_assert(str); | ||||
| 
 | ||||
|     uint8_t len = strlen(str); | ||||
|     uint8_t wlen = (len + 1) * sizeof(uint16_t); | ||||
|     size_t len = strlen(str); | ||||
|     size_t wlen = (len + 1) * sizeof(uint16_t); | ||||
|     struct usb_string_descriptor* dev_str_desc = malloc(wlen); | ||||
|     dev_str_desc->bLength = wlen; | ||||
|     dev_str_desc->bDescriptorType = USB_DTYPE_STRING; | ||||
|     for(uint8_t i = 0; i < len; i++) { | ||||
|     for(size_t i = 0; i < len; i++) { | ||||
|         dev_str_desc->wString[i] = str[i]; | ||||
|     } | ||||
| 
 | ||||
|  | ||||
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 657 B | 
| @ -42,11 +42,13 @@ static void bt_hid_connection_status_changed_callback(BtStatus status, void* con | ||||
|     furi_assert(context); | ||||
|     Hid* hid = context; | ||||
|     bool connected = (status == BtStatusConnected); | ||||
|     if(hid->transport == HidTransportBle) { | ||||
|         if(connected) { | ||||
|             notification_internal_message(hid->notifications, &sequence_set_blue_255); | ||||
|         } else { | ||||
|             notification_internal_message(hid->notifications, &sequence_reset_blue); | ||||
|         } | ||||
|     } | ||||
|     hid_keynote_set_connected_status(hid->hid_keynote, connected); | ||||
|     hid_keyboard_set_connected_status(hid->hid_keyboard, connected); | ||||
|     hid_media_set_connected_status(hid->hid_media, connected); | ||||
| @ -186,7 +188,9 @@ void hid_free(Hid* app) { | ||||
|     furi_assert(app); | ||||
| 
 | ||||
|     // Reset notification
 | ||||
|     if(app->transport == HidTransportBle) { | ||||
|         notification_internal_message(app->notifications, &sequence_reset_blue); | ||||
|     } | ||||
| 
 | ||||
|     // Free views
 | ||||
|     view_dispatcher_remove_view(app->view_dispatcher, HidViewSubmenu); | ||||
|  | ||||
| @ -25,6 +25,7 @@ typedef struct { | ||||
|     bool back_pressed; | ||||
|     bool connected; | ||||
|     char key_string[5]; | ||||
|     HidTransport transport; | ||||
| } HidKeyboardModel; | ||||
| 
 | ||||
| typedef struct { | ||||
| @ -207,7 +208,7 @@ static void hid_keyboard_draw_callback(Canvas* canvas, void* context) { | ||||
|     HidKeyboardModel* model = context; | ||||
| 
 | ||||
|     // Header
 | ||||
|     if(!model->connected) { | ||||
|     if((!model->connected) && (model->transport == HidTransportBle)) { | ||||
|         canvas_draw_icon(canvas, 0, 0, &I_Ble_disconnected_15x15); | ||||
|         canvas_set_font(canvas, FontPrimary); | ||||
|         elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "Keyboard"); | ||||
| @ -249,30 +250,19 @@ static void hid_keyboard_draw_callback(Canvas* canvas, void* context) { | ||||
| 
 | ||||
| static uint8_t hid_keyboard_get_selected_key(HidKeyboardModel* model) { | ||||
|     HidKeyboardKey key = hid_keyboard_keyset[model->y][model->x]; | ||||
|     // Use upper case if shift is toggled
 | ||||
|     bool useUppercase = model->shift; | ||||
|     // Check if the key has an upper case version
 | ||||
|     bool hasUppercase = key.shift_key != 0; | ||||
|     if(useUppercase && hasUppercase) | ||||
|         return key.value; | ||||
|     else | ||||
|     return key.value; | ||||
| } | ||||
| 
 | ||||
| static void hid_keyboard_get_select_key(HidKeyboardModel* model, HidKeyboardPoint delta) { | ||||
|     // Keep going until a valid spot is found, this allows for nulls and zero width keys in the map
 | ||||
|     do { | ||||
|         if(((int8_t)model->y) + delta.y < 0) | ||||
|             model->y = ROW_COUNT - 1; | ||||
|         else | ||||
|             model->y = (model->y + delta.y) % ROW_COUNT; | ||||
|         const int delta_sum = model->y + delta.y; | ||||
|         model->y = delta_sum < 0 ? ROW_COUNT - 1 : delta_sum % ROW_COUNT; | ||||
|     } while(delta.y != 0 && hid_keyboard_keyset[model->y][model->x].value == 0); | ||||
| 
 | ||||
|     do { | ||||
|         if(((int8_t)model->x) + delta.x < 0) | ||||
|             model->x = COLUMN_COUNT - 1; | ||||
|         else | ||||
|             model->x = (model->x + delta.x) % COLUMN_COUNT; | ||||
|         const int delta_sum = model->x + delta.x; | ||||
|         model->x = delta_sum < 0 ? COLUMN_COUNT - 1 : delta_sum % COLUMN_COUNT; | ||||
|     } while(delta.x != 0 && hid_keyboard_keyset[model->y][model->x].width == | ||||
|                                 0); // Skip zero width keys, pretend they are one key
 | ||||
| } | ||||
| @ -372,6 +362,12 @@ HidKeyboard* hid_keyboard_alloc(Hid* bt_hid) { | ||||
|     view_set_draw_callback(hid_keyboard->view, hid_keyboard_draw_callback); | ||||
|     view_set_input_callback(hid_keyboard->view, hid_keyboard_input_callback); | ||||
| 
 | ||||
|     with_view_model( | ||||
|         hid_keyboard->view, | ||||
|         HidKeyboardModel * model, | ||||
|         { model->transport = bt_hid->transport; }, | ||||
|         true); | ||||
| 
 | ||||
|     return hid_keyboard; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -19,6 +19,7 @@ typedef struct { | ||||
|     bool ok_pressed; | ||||
|     bool back_pressed; | ||||
|     bool connected; | ||||
|     HidTransport transport; | ||||
| } HidKeynoteModel; | ||||
| 
 | ||||
| static void hid_keynote_draw_arrow(Canvas* canvas, uint8_t x, uint8_t y, CanvasDirection dir) { | ||||
| @ -39,11 +40,14 @@ static void hid_keynote_draw_callback(Canvas* canvas, void* context) { | ||||
|     HidKeynoteModel* model = context; | ||||
| 
 | ||||
|     // Header
 | ||||
|     if(model->transport == HidTransportBle) { | ||||
|         if(model->connected) { | ||||
|             canvas_draw_icon(canvas, 0, 0, &I_Ble_connected_15x15); | ||||
|         } else { | ||||
|             canvas_draw_icon(canvas, 0, 0, &I_Ble_disconnected_15x15); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     canvas_set_font(canvas, FontPrimary); | ||||
|     elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "Keynote"); | ||||
| 
 | ||||
| @ -186,6 +190,9 @@ HidKeynote* hid_keynote_alloc(Hid* hid) { | ||||
|     view_set_draw_callback(hid_keynote->view, hid_keynote_draw_callback); | ||||
|     view_set_input_callback(hid_keynote->view, hid_keynote_input_callback); | ||||
| 
 | ||||
|     with_view_model( | ||||
|         hid_keynote->view, HidKeynoteModel * model, { model->transport = hid->transport; }, true); | ||||
| 
 | ||||
|     return hid_keynote; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -21,6 +21,7 @@ typedef struct { | ||||
|     bool down_pressed; | ||||
|     bool ok_pressed; | ||||
|     bool connected; | ||||
|     HidTransport transport; | ||||
| } HidMediaModel; | ||||
| 
 | ||||
| static void hid_media_draw_arrow(Canvas* canvas, uint8_t x, uint8_t y, CanvasDirection dir) { | ||||
| @ -41,11 +42,14 @@ static void hid_media_draw_callback(Canvas* canvas, void* context) { | ||||
|     HidMediaModel* model = context; | ||||
| 
 | ||||
|     // Header
 | ||||
|     if(model->transport == HidTransportBle) { | ||||
|         if(model->connected) { | ||||
|             canvas_draw_icon(canvas, 0, 0, &I_Ble_connected_15x15); | ||||
|         } else { | ||||
|             canvas_draw_icon(canvas, 0, 0, &I_Ble_disconnected_15x15); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     canvas_set_font(canvas, FontPrimary); | ||||
|     elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "Media"); | ||||
|     canvas_set_font(canvas, FontSecondary); | ||||
| @ -190,6 +194,9 @@ HidMedia* hid_media_alloc(Hid* hid) { | ||||
|     view_set_draw_callback(hid_media->view, hid_media_draw_callback); | ||||
|     view_set_input_callback(hid_media->view, hid_media_input_callback); | ||||
| 
 | ||||
|     with_view_model( | ||||
|         hid_media->view, HidMediaModel * model, { model->transport = hid->transport; }, true); | ||||
| 
 | ||||
|     return hid_media; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -20,6 +20,7 @@ typedef struct { | ||||
|     bool left_mouse_held; | ||||
|     bool right_mouse_pressed; | ||||
|     bool connected; | ||||
|     HidTransport transport; | ||||
| } HidMouseModel; | ||||
| 
 | ||||
| static void hid_mouse_draw_callback(Canvas* canvas, void* context) { | ||||
| @ -27,11 +28,14 @@ static void hid_mouse_draw_callback(Canvas* canvas, void* context) { | ||||
|     HidMouseModel* model = context; | ||||
| 
 | ||||
|     // Header
 | ||||
|     if(model->transport == HidTransportBle) { | ||||
|         if(model->connected) { | ||||
|             canvas_draw_icon(canvas, 0, 0, &I_Ble_connected_15x15); | ||||
|         } else { | ||||
|             canvas_draw_icon(canvas, 0, 0, &I_Ble_disconnected_15x15); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     canvas_set_font(canvas, FontPrimary); | ||||
|     elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "Mouse"); | ||||
|     canvas_set_font(canvas, FontSecondary); | ||||
| @ -198,6 +202,9 @@ HidMouse* hid_mouse_alloc(Hid* hid) { | ||||
|     view_set_draw_callback(hid_mouse->view, hid_mouse_draw_callback); | ||||
|     view_set_input_callback(hid_mouse->view, hid_mouse_input_callback); | ||||
| 
 | ||||
|     with_view_model( | ||||
|         hid_mouse->view, HidMouseModel * model, { model->transport = hid->transport; }, true); | ||||
| 
 | ||||
|     return hid_mouse; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -16,6 +16,7 @@ typedef struct { | ||||
|     bool connected; | ||||
|     bool running; | ||||
|     uint8_t counter; | ||||
|     HidTransport transport; | ||||
| } HidMouseJigglerModel; | ||||
| 
 | ||||
| static void hid_mouse_jiggler_draw_callback(Canvas* canvas, void* context) { | ||||
| @ -23,11 +24,14 @@ static void hid_mouse_jiggler_draw_callback(Canvas* canvas, void* context) { | ||||
|     HidMouseJigglerModel* model = context; | ||||
| 
 | ||||
|     // Header
 | ||||
|     if(model->transport == HidTransportBle) { | ||||
|         if(model->connected) { | ||||
|             canvas_draw_icon(canvas, 0, 0, &I_Ble_connected_15x15); | ||||
|         } else { | ||||
|             canvas_draw_icon(canvas, 0, 0, &I_Ble_disconnected_15x15); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     canvas_set_font(canvas, FontPrimary); | ||||
|     elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "Mouse Jiggler"); | ||||
| 
 | ||||
| @ -120,6 +124,12 @@ HidMouseJiggler* hid_mouse_jiggler_alloc(Hid* hid) { | ||||
|     hid_mouse_jiggler->timer = furi_timer_alloc( | ||||
|         hid_mouse_jiggler_timer_callback, FuriTimerTypePeriodic, hid_mouse_jiggler); | ||||
| 
 | ||||
|     with_view_model( | ||||
|         hid_mouse_jiggler->view, | ||||
|         HidMouseJigglerModel * model, | ||||
|         { model->transport = hid->transport; }, | ||||
|         true); | ||||
| 
 | ||||
|     return hid_mouse_jiggler; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -19,6 +19,7 @@ typedef struct { | ||||
|     bool ok_pressed; | ||||
|     bool connected; | ||||
|     bool is_cursor_set; | ||||
|     HidTransport transport; | ||||
| } HidTikTokModel; | ||||
| 
 | ||||
| static void hid_tiktok_draw_callback(Canvas* canvas, void* context) { | ||||
| @ -26,11 +27,14 @@ static void hid_tiktok_draw_callback(Canvas* canvas, void* context) { | ||||
|     HidTikTokModel* model = context; | ||||
| 
 | ||||
|     // Header
 | ||||
|     if(model->transport == HidTransportBle) { | ||||
|         if(model->connected) { | ||||
|             canvas_draw_icon(canvas, 0, 0, &I_Ble_connected_15x15); | ||||
|         } else { | ||||
|             canvas_draw_icon(canvas, 0, 0, &I_Ble_disconnected_15x15); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     canvas_set_font(canvas, FontPrimary); | ||||
|     elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "TikTok"); | ||||
|     canvas_set_font(canvas, FontSecondary); | ||||
| @ -207,6 +211,9 @@ HidTikTok* hid_tiktok_alloc(Hid* bt_hid) { | ||||
|     view_set_draw_callback(hid_tiktok->view, hid_tiktok_draw_callback); | ||||
|     view_set_input_callback(hid_tiktok->view, hid_tiktok_input_callback); | ||||
| 
 | ||||
|     with_view_model( | ||||
|         hid_tiktok->view, HidTikTokModel * model, { model->transport = bt_hid->transport; }, true); | ||||
| 
 | ||||
|     return hid_tiktok; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -180,7 +180,7 @@ static void render_callback(Canvas* canvas, void* ctx) { | ||||
| 
 | ||||
|     // note stack view_port
 | ||||
|     x_pos = 73; | ||||
|     y_pos = 0; | ||||
|     y_pos = 0; //-V1048
 | ||||
|     canvas_set_color(canvas, ColorBlack); | ||||
|     canvas_set_font(canvas, FontPrimary); | ||||
|     canvas_draw_frame(canvas, x_pos, y_pos, 49, 64); | ||||
|  | ||||
| @ -111,9 +111,9 @@ static void init_opt_select_LUT(void) { | ||||
| ***********************************************************************************/ | ||||
| 
 | ||||
| #define loclass_opt__select(x, y, r)                                                        \ | ||||
|     (4 & (((r & (r << 2)) >> 5) ^ ((r & ~(r << 2)) >> 4) ^ ((r | r << 2) >> 3))) |          \ | ||||
|         (2 & (((r | r << 2) >> 6) ^ ((r | r << 2) >> 1) ^ (r >> 5) ^ r ^ ((x ^ y) << 1))) | \ | ||||
|         (1 & (((r & ~(r << 2)) >> 4) ^ ((r & (r << 2)) >> 3) ^ r ^ x)) | ||||
|     (4 & ((((r) & ((r) << 2)) >> 5) ^ (((r) & ~((r) << 2)) >> 4) ^ (((r) | (r) << 2) >> 3))) |          \ | ||||
|         (2 & ((((r) | (r) << 2) >> 6) ^ (((r) | (r) << 2) >> 1) ^ ((r) >> 5) ^ (r) ^ (((x) ^ (y)) << 1))) | \ | ||||
|         (1 & ((((r) & ~((r) << 2)) >> 4) ^ (((r) & ((r) << 2)) >> 3) ^ (r) ^ (x))) | ||||
| 
 | ||||
| static void loclass_opt_successor(const uint8_t* k, LoclassState_t* s, uint8_t y) { | ||||
|     uint16_t Tt = s->t & 0xc533; | ||||
| @ -149,30 +149,11 @@ static void loclass_opt_suc( | ||||
|     uint8_t length, | ||||
|     bool add32Zeroes) { | ||||
|     for(int i = 0; i < length; i++) { | ||||
|         uint8_t head; | ||||
|         head = in[i]; | ||||
|         uint8_t head = in[i]; | ||||
|         for(int j = 0; j < 8; j++) { | ||||
|             loclass_opt_successor(k, s, head); | ||||
| 
 | ||||
|             head >>= 1; | ||||
|         loclass_opt_successor(k, s, head); | ||||
| 
 | ||||
|         head >>= 1; | ||||
|         loclass_opt_successor(k, s, head); | ||||
| 
 | ||||
|         head >>= 1; | ||||
|         loclass_opt_successor(k, s, head); | ||||
| 
 | ||||
|         head >>= 1; | ||||
|         loclass_opt_successor(k, s, head); | ||||
| 
 | ||||
|         head >>= 1; | ||||
|         loclass_opt_successor(k, s, head); | ||||
| 
 | ||||
|         head >>= 1; | ||||
|         loclass_opt_successor(k, s, head); | ||||
| 
 | ||||
|         head >>= 1; | ||||
|         loclass_opt_successor(k, s, head); | ||||
|         } | ||||
|     } | ||||
|     //For tag MAC, an additional 32 zeroes
 | ||||
|     if(add32Zeroes) { | ||||
|  | ||||
| @ -18,6 +18,9 @@ | ||||
| 
 | ||||
| #define PICOPASS_CSN_BLOCK_INDEX 0 | ||||
| #define PICOPASS_CONFIG_BLOCK_INDEX 1 | ||||
| #define PICOPASS_EPURSE_BLOCK_INDEX 2 | ||||
| #define PICOPASS_KD_BLOCK_INDEX 3 | ||||
| #define PICOPASS_KC_BLOCK_INDEX 4 | ||||
| #define PICOPASS_AIA_BLOCK_INDEX 5 | ||||
| 
 | ||||
| #define PICOPASS_APP_FOLDER ANY_PATH("picopass") | ||||
|  | ||||
| @ -143,7 +143,7 @@ ReturnCode picopass_read_preauth(PicopassBlock* AA1) { | ||||
|         AA1[PICOPASS_CSN_BLOCK_INDEX].data[7]); | ||||
| 
 | ||||
|     rfalPicoPassReadBlockRes cfg = {0}; | ||||
|     err = rfalPicoPassPollerReadBlock(PICOPASS_CONFIG_BLOCK_INDEX, &cfg); | ||||
|     rfalPicoPassPollerReadBlock(PICOPASS_CONFIG_BLOCK_INDEX, &cfg); | ||||
|     memcpy(AA1[PICOPASS_CONFIG_BLOCK_INDEX].data, cfg.data, sizeof(cfg.data)); | ||||
|     FURI_LOG_D( | ||||
|         TAG, | ||||
| @ -158,7 +158,7 @@ ReturnCode picopass_read_preauth(PicopassBlock* AA1) { | ||||
|         AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[7]); | ||||
| 
 | ||||
|     rfalPicoPassReadBlockRes aia; | ||||
|     err = rfalPicoPassPollerReadBlock(PICOPASS_AIA_BLOCK_INDEX, &aia); | ||||
|     rfalPicoPassPollerReadBlock(PICOPASS_AIA_BLOCK_INDEX, &aia); | ||||
|     memcpy(AA1[PICOPASS_AIA_BLOCK_INDEX].data, aia.data, sizeof(aia.data)); | ||||
|     FURI_LOG_D( | ||||
|         TAG, | ||||
| @ -175,13 +175,12 @@ ReturnCode picopass_read_preauth(PicopassBlock* AA1) { | ||||
|     return ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| ReturnCode picopass_auth(PicopassBlock* AA1, PicopassPacs* pacs) { | ||||
| static ReturnCode picopass_auth_standard(uint8_t* csn, uint8_t* div_key) { | ||||
|     rfalPicoPassReadCheckRes rcRes; | ||||
|     rfalPicoPassCheckRes chkRes; | ||||
| 
 | ||||
|     ReturnCode err; | ||||
| 
 | ||||
|     uint8_t div_key[8] = {0}; | ||||
|     uint8_t mac[4] = {0}; | ||||
|     uint8_t ccnr[12] = {0}; | ||||
| 
 | ||||
| @ -192,26 +191,34 @@ ReturnCode picopass_auth(PicopassBlock* AA1, PicopassPacs* pacs) { | ||||
|     } | ||||
|     memcpy(ccnr, rcRes.CCNR, sizeof(rcRes.CCNR)); // last 4 bytes left 0
 | ||||
| 
 | ||||
|     loclass_diversifyKey(AA1[PICOPASS_CSN_BLOCK_INDEX].data, picopass_iclass_key, div_key); | ||||
|     loclass_diversifyKey(csn, picopass_iclass_key, div_key); | ||||
|     loclass_opt_doReaderMAC(ccnr, div_key, mac); | ||||
| 
 | ||||
|     err = rfalPicoPassPollerCheck(mac, &chkRes); | ||||
|     if(err == ERR_NONE) { | ||||
|         return ERR_NONE; | ||||
|     } | ||||
|     FURI_LOG_E(TAG, "rfalPicoPassPollerCheck error %d", err); | ||||
|     return rfalPicoPassPollerCheck(mac, &chkRes); | ||||
| } | ||||
| 
 | ||||
|     FURI_LOG_E(TAG, "Starting dictionary attack"); | ||||
| static ReturnCode picopass_auth_dict( | ||||
|     uint8_t* csn, | ||||
|     PicopassPacs* pacs, | ||||
|     uint8_t* div_key, | ||||
|     IclassEliteDictType dict_type) { | ||||
|     rfalPicoPassReadCheckRes rcRes; | ||||
|     rfalPicoPassCheckRes chkRes; | ||||
| 
 | ||||
|     ReturnCode err = ERR_PARAM; | ||||
| 
 | ||||
|     uint8_t mac[4] = {0}; | ||||
|     uint8_t ccnr[12] = {0}; | ||||
| 
 | ||||
|     size_t index = 0; | ||||
|     uint8_t key[PICOPASS_BLOCK_LEN] = {0}; | ||||
| 
 | ||||
|     if(!iclass_elite_dict_check_presence(IclassEliteDictTypeFlipper)) { | ||||
|     if(!iclass_elite_dict_check_presence(dict_type)) { | ||||
|         FURI_LOG_E(TAG, "Dictionary not found"); | ||||
|         return ERR_PARAM; | ||||
|     } | ||||
| 
 | ||||
|     IclassEliteDict* dict = iclass_elite_dict_alloc(IclassEliteDictTypeFlipper); | ||||
|     IclassEliteDict* dict = iclass_elite_dict_alloc(dict_type); | ||||
|     if(!dict) { | ||||
|         FURI_LOG_E(TAG, "Dictionary not allocated"); | ||||
|         return ERR_PARAM; | ||||
| @ -221,7 +228,7 @@ ReturnCode picopass_auth(PicopassBlock* AA1, PicopassPacs* pacs) { | ||||
|     while(iclass_elite_dict_get_next_key(dict, key)) { | ||||
|         FURI_LOG_D( | ||||
|             TAG, | ||||
|             "Try to auth with key %d %02x%02x%02x%02x%02x%02x%02x%02x", | ||||
|             "Try to auth with key %zu %02x%02x%02x%02x%02x%02x%02x%02x", | ||||
|             index++, | ||||
|             key[0], | ||||
|             key[1], | ||||
| @ -235,11 +242,11 @@ ReturnCode picopass_auth(PicopassBlock* AA1, PicopassPacs* pacs) { | ||||
|         err = rfalPicoPassPollerReadCheck(&rcRes); | ||||
|         if(err != ERR_NONE) { | ||||
|             FURI_LOG_E(TAG, "rfalPicoPassPollerReadCheck error %d", err); | ||||
|             return err; | ||||
|             break; | ||||
|         } | ||||
|         memcpy(ccnr, rcRes.CCNR, sizeof(rcRes.CCNR)); // last 4 bytes left 0
 | ||||
| 
 | ||||
|         loclass_iclass_calc_div_key(AA1[PICOPASS_CSN_BLOCK_INDEX].data, key, div_key, true); | ||||
|         loclass_iclass_calc_div_key(csn, key, div_key, true); | ||||
|         loclass_opt_doReaderMAC(ccnr, div_key, mac); | ||||
| 
 | ||||
|         err = rfalPicoPassPollerCheck(mac, &chkRes); | ||||
| @ -249,8 +256,39 @@ ReturnCode picopass_auth(PicopassBlock* AA1, PicopassPacs* pacs) { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if(dict) { | ||||
|     iclass_elite_dict_free(dict); | ||||
| 
 | ||||
|     return err; | ||||
| } | ||||
| 
 | ||||
| ReturnCode picopass_auth(PicopassBlock* AA1, PicopassPacs* pacs) { | ||||
|     ReturnCode err; | ||||
| 
 | ||||
|     FURI_LOG_E(TAG, "Trying standard legacy key"); | ||||
|     err = picopass_auth_standard( | ||||
|         AA1[PICOPASS_CSN_BLOCK_INDEX].data, AA1[PICOPASS_KD_BLOCK_INDEX].data); | ||||
|     if(err == ERR_NONE) { | ||||
|         return ERR_NONE; | ||||
|     } | ||||
| 
 | ||||
|     FURI_LOG_E(TAG, "Starting user dictionary attack"); | ||||
|     err = picopass_auth_dict( | ||||
|         AA1[PICOPASS_CSN_BLOCK_INDEX].data, | ||||
|         pacs, | ||||
|         AA1[PICOPASS_KD_BLOCK_INDEX].data, | ||||
|         IclassEliteDictTypeUser); | ||||
|     if(err == ERR_NONE) { | ||||
|         return ERR_NONE; | ||||
|     } | ||||
| 
 | ||||
|     FURI_LOG_E(TAG, "Starting in-built dictionary attack"); | ||||
|     err = picopass_auth_dict( | ||||
|         AA1[PICOPASS_CSN_BLOCK_INDEX].data, | ||||
|         pacs, | ||||
|         AA1[PICOPASS_KD_BLOCK_INDEX].data, | ||||
|         IclassEliteDictTypeFlipper); | ||||
|     if(err == ERR_NONE) { | ||||
|         return ERR_NONE; | ||||
|     } | ||||
| 
 | ||||
|     return err; | ||||
| @ -264,6 +302,11 @@ ReturnCode picopass_read_card(PicopassBlock* AA1) { | ||||
|                            PICOPASS_MAX_APP_LIMIT; | ||||
| 
 | ||||
|     for(size_t i = 2; i < app_limit; i++) { | ||||
|         if(i == PICOPASS_KD_BLOCK_INDEX) { | ||||
|             // Skip over Kd block which is populated earlier (READ of Kd returns all FF's)
 | ||||
|             continue; | ||||
|         } | ||||
| 
 | ||||
|         rfalPicoPassReadBlockRes block; | ||||
|         err = rfalPicoPassPollerReadBlock(i, &block); | ||||
|         if(err != ERR_NONE) { | ||||
|  | ||||
| @ -54,7 +54,7 @@ bool picopass_scene_save_name_on_event(void* context, SceneManagerEvent event) { | ||||
| 
 | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         if(event.event == PicopassCustomEventTextInputDone) { | ||||
|             if(strcmp(picopass->dev->dev_name, "")) { | ||||
|             if(strcmp(picopass->dev->dev_name, "") != 0) { | ||||
|                 // picopass_device_delete(picopass->dev, true);
 | ||||
|             } | ||||
|             strlcpy( | ||||
|  | ||||
| @ -3,7 +3,7 @@ enum SubmenuIndex { | ||||
|     SubmenuIndexRead, | ||||
|     SubmenuIndexRunScript, | ||||
|     SubmenuIndexSaved, | ||||
|     SubmenuIndexAddManualy, | ||||
|     SubmenuIndexAddManually, | ||||
|     SubmenuIndexDebug, | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -15,12 +15,12 @@ static void | ||||
|     app->pwm_freq = freq; | ||||
|     app->pwm_duty = duty; | ||||
| 
 | ||||
|     if(app->pwm_ch != pwm_ch_id[channel_id]) { | ||||
|     if(app->pwm_ch != pwm_ch_id[channel_id]) { //-V1051
 | ||||
|         app->pwm_ch_prev = app->pwm_ch; | ||||
|         app->pwm_ch = pwm_ch_id[channel_id]; | ||||
|         view_dispatcher_send_custom_event(app->view_dispatcher, SignalGenPwmEventChannelChange); | ||||
|     } else { | ||||
|         app->pwm_ch = pwm_ch_id[channel_id]; | ||||
|         app->pwm_ch = pwm_ch_id[channel_id]; //-V1048
 | ||||
|         view_dispatcher_send_custom_event(app->view_dispatcher, SignalGenPwmEventUpdate); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -127,12 +127,12 @@ static void signal_gen_pwm_draw_callback(Canvas* canvas, void* _model) { | ||||
|     char* line_label = NULL; | ||||
|     char val_text[16]; | ||||
| 
 | ||||
|     for(uint8_t line = 0; line < LineIndexTotalCount; line++) { | ||||
|     for(size_t line = 0; line < LineIndexTotalCount; line++) { | ||||
|         if(line == LineIndexChannel) { | ||||
|             line_label = "GPIO Pin"; | ||||
|         } else if(line == LineIndexFrequency) { | ||||
|             line_label = "Frequency"; | ||||
|         } else if(line == LineIndexDuty) { | ||||
|         } else if(line == LineIndexDuty) { //-V547
 | ||||
|             line_label = "Pulse width"; | ||||
|         } | ||||
| 
 | ||||
| @ -169,7 +169,7 @@ static void signal_gen_pwm_draw_callback(Canvas* canvas, void* _model) { | ||||
|                 canvas_draw_icon(canvas, icon_x, text_y - 9, &I_SmallArrowUp_3x5); | ||||
|                 canvas_draw_icon(canvas, icon_x, text_y + 5, &I_SmallArrowDown_3x5); | ||||
|             } | ||||
|         } else if(line == LineIndexDuty) { | ||||
|         } else if(line == LineIndexDuty) { //-V547
 | ||||
|             snprintf(val_text, sizeof(val_text), "%d%%", model->duty); | ||||
|             canvas_draw_str_aligned(canvas, VALUE_X, text_y, AlignCenter, AlignCenter, val_text); | ||||
|             if(model->duty != 0) { | ||||
|  | ||||
| @ -130,7 +130,7 @@ static void snake_game_render_callback(Canvas* const canvas, void* ctx) { | ||||
| 
 | ||||
|         canvas_set_font(canvas, FontSecondary); | ||||
|         char buffer[12]; | ||||
|         snprintf(buffer, sizeof(buffer), "Score: %u", snake_state->len - 7); | ||||
|         snprintf(buffer, sizeof(buffer), "Score: %u", snake_state->len - 7U); | ||||
|         canvas_draw_str_aligned(canvas, 64, 41, AlignCenter, AlignBottom, buffer); | ||||
|     } | ||||
| 
 | ||||
| @ -153,7 +153,7 @@ static void snake_game_update_timer_callback(FuriMessageQueue* event_queue) { | ||||
| 
 | ||||
| static void snake_game_init_game(SnakeState* const snake_state) { | ||||
|     Point p[] = {{8, 6}, {7, 6}, {6, 6}, {5, 6}, {4, 6}, {3, 6}, {2, 6}}; | ||||
|     memcpy(snake_state->points, p, sizeof(p)); | ||||
|     memcpy(snake_state->points, p, sizeof(p)); //-V1086
 | ||||
| 
 | ||||
|     snake_state->len = 7; | ||||
| 
 | ||||
|  | ||||
| @ -343,7 +343,7 @@ bool ws_protocol_decoder_oregon2_deserialize(void* context, FlipperFormat* flipp | ||||
|                flipper_format, | ||||
|                "VarData", | ||||
|                (uint8_t*)&instance->var_data, | ||||
|                sizeof(instance->var_data))) { | ||||
|                sizeof(instance->var_data))) { //-V1051
 | ||||
|             FURI_LOG_E(TAG, "Missing VarData"); | ||||
|             break; | ||||
|         } | ||||
|  | ||||
| @ -147,7 +147,7 @@ static void ws_protocol_oregon_v1_remote_controller(WSBlockGeneric* instance) { | ||||
|         instance->temp = -temp_raw; | ||||
|     } | ||||
| 
 | ||||
|     instance->battery_low = !(instance->data >> 23) & 1; | ||||
|     instance->battery_low = !((instance->data >> 23) & 1ULL); | ||||
| 
 | ||||
|     instance->btn = WS_NO_BTN; | ||||
|     instance->humidity = WS_NO_HUMIDITY; | ||||
|  | ||||
| @ -79,7 +79,7 @@ bool ws_block_generic_serialize( | ||||
| 
 | ||||
|         uint8_t key_data[sizeof(uint64_t)] = {0}; | ||||
|         for(size_t i = 0; i < sizeof(uint64_t); i++) { | ||||
|             key_data[sizeof(uint64_t) - i - 1] = (instance->data >> i * 8) & 0xFF; | ||||
|             key_data[sizeof(uint64_t) - i - 1] = (instance->data >> (i * 8)) & 0xFF; | ||||
|         } | ||||
| 
 | ||||
|         if(!flipper_format_write_hex(flipper_format, "Data", key_data, sizeof(uint64_t))) { | ||||
|  | ||||
| @ -4,8 +4,7 @@ | ||||
| #include "../protocols/ws_generic.h" | ||||
| #include <input/input.h> | ||||
| #include <gui/elements.h> | ||||
| 
 | ||||
| #define abs(x) ((x) > 0 ? (x) : -(x)) | ||||
| #include <float_tools.h> | ||||
| 
 | ||||
| struct WSReceiverInfo { | ||||
|     View* view; | ||||
| @ -79,7 +78,7 @@ void ws_view_receiver_info_draw(Canvas* canvas, WSReceiverInfoModel* model) { | ||||
|     elements_bold_rounded_frame(canvas, 0, 38, 127, 25); | ||||
|     canvas_set_font(canvas, FontPrimary); | ||||
| 
 | ||||
|     if(model->generic->temp != WS_NO_TEMPERATURE) { | ||||
|     if(!float_is_equal(model->generic->temp, WS_NO_TEMPERATURE)) { | ||||
|         canvas_draw_icon(canvas, 6, 43, &I_Therm_7x16); | ||||
| 
 | ||||
|         uint8_t temp_x1 = 0; | ||||
|  | ||||
| @ -111,11 +111,8 @@ void ws_hopper_update(WeatherStationApp* app) { | ||||
| 
 | ||||
|     switch(app->txrx->hopper_state) { | ||||
|     case WSHopperStateOFF: | ||||
|         return; | ||||
|         break; | ||||
|     case WSHopperStatePause: | ||||
|         return; | ||||
|         break; | ||||
|     case WSHopperStateRSSITimeOut: | ||||
|         if(app->txrx->hopper_timeout != 0) { | ||||
|             app->txrx->hopper_timeout--; | ||||
|  | ||||
| @ -186,7 +186,7 @@ WSHistoryStateAddKey | ||||
|     } | ||||
| 
 | ||||
|     // or add new record
 | ||||
|     if(!sensor_found) { | ||||
|     if(!sensor_found) { //-V547
 | ||||
|         WSHistoryItem* item = WSHistoryItemArray_push_raw(instance->history->data); | ||||
|         item->preset = malloc(sizeof(SubGhzRadioPreset)); | ||||
|         item->type = decoder_base->protocol->type; | ||||
|  | ||||
| @ -36,7 +36,7 @@ static void bt_pin_code_view_port_draw_callback(Canvas* canvas, void* context) { | ||||
|     Bt* bt = context; | ||||
|     char pin_code_info[24]; | ||||
|     canvas_draw_icon(canvas, 0, 0, &I_BLE_Pairing_128x64); | ||||
|     snprintf(pin_code_info, sizeof(pin_code_info), "Pairing code\n%06ld", bt->pin_code); | ||||
|     snprintf(pin_code_info, sizeof(pin_code_info), "Pairing code\n%06lu", bt->pin_code); | ||||
|     elements_multiline_text_aligned(canvas, 64, 4, AlignCenter, AlignTop, pin_code_info); | ||||
|     elements_button_left(canvas, "Quit"); | ||||
| } | ||||
| @ -78,7 +78,7 @@ static bool bt_pin_code_verify_event_handler(Bt* bt, uint32_t pin) { | ||||
|     notification_message(bt->notification, &sequence_display_backlight_on); | ||||
|     FuriString* pin_str; | ||||
|     dialog_message_set_icon(bt->dialog_message, &I_BLE_Pairing_128x64, 0, 0); | ||||
|     pin_str = furi_string_alloc_printf("Verify code\n%06ld", pin); | ||||
|     pin_str = furi_string_alloc_printf("Verify code\n%06lu", pin); | ||||
|     dialog_message_set_text( | ||||
|         bt->dialog_message, furi_string_get_cstr(pin_str), 64, 4, AlignCenter, AlignTop); | ||||
|     dialog_message_set_buttons(bt->dialog_message, "Cancel", "OK", NULL); | ||||
| @ -163,7 +163,7 @@ static uint16_t bt_serial_event_callback(SerialServiceEvent event, void* context | ||||
|             rpc_session_feed(bt->rpc_session, event.data.buffer, event.data.size, 1000); | ||||
|         if(bytes_processed != event.data.size) { | ||||
|             FURI_LOG_E( | ||||
|                 TAG, "Only %d of %d bytes processed by RPC", bytes_processed, event.data.size); | ||||
|                 TAG, "Only %zu of %u bytes processed by RPC", bytes_processed, event.data.size); | ||||
|         } | ||||
|         ret = rpc_session_get_available_size(bt->rpc_session); | ||||
|     } else if(event.event == SerialServiceEventTypeDataSent) { | ||||
|  | ||||
| @ -115,7 +115,7 @@ bool bt_keys_storage_update(BtKeysStorage* instance, uint8_t* start_addr, uint32 | ||||
| 
 | ||||
|     FURI_LOG_I( | ||||
|         TAG, | ||||
|         "Base address: %p. Start update address: %p. Size changed: %ld", | ||||
|         "Base address: %p. Start update address: %p. Size changed: %lu", | ||||
|         (void*)instance->nvm_sram_buff, | ||||
|         start_addr, | ||||
|         size); | ||||
|  | ||||
| @ -225,7 +225,7 @@ static void cli_handle_enter(Cli* cli) { | ||||
|     furi_check(furi_mutex_acquire(cli->mutex, FuriWaitForever) == FuriStatusOk); | ||||
|     CliCommand* cli_command_ptr = CliCommandTree_get(cli->commands, command); | ||||
| 
 | ||||
|     if(cli_command_ptr) { | ||||
|     if(cli_command_ptr) { //-V547
 | ||||
|         CliCommand cli_command; | ||||
|         memcpy(&cli_command, cli_command_ptr, sizeof(CliCommand)); | ||||
|         furi_check(furi_mutex_release(cli->mutex) == FuriStatusOk); | ||||
| @ -353,7 +353,7 @@ void cli_process_input(Cli* cli) { | ||||
|         cli_handle_backspace(cli); | ||||
|     } else if(in_chr == CliSymbolAsciiCR) { | ||||
|         cli_handle_enter(cli); | ||||
|     } else if(in_chr >= 0x20 && in_chr < 0x7F) { | ||||
|     } else if(in_chr >= 0x20 && in_chr < 0x7F) { //-V560
 | ||||
|         if(cli->cursor_position == furi_string_size(cli->line)) { | ||||
|             furi_string_push_back(cli->line, in_chr); | ||||
|             cli_putc(cli, in_chr); | ||||
|  | ||||
| @ -1,5 +1,6 @@ | ||||
| #include "cli_command_gpio.h" | ||||
| 
 | ||||
| #include "core/string.h" | ||||
| #include <furi.h> | ||||
| #include <furi_hal.h> | ||||
| #include <lib/toolbox/args.h> | ||||
| @ -36,26 +37,24 @@ void cli_command_gpio_print_usage() { | ||||
| } | ||||
| 
 | ||||
| static bool pin_name_to_int(FuriString* pin_name, size_t* result) { | ||||
|     bool found = false; | ||||
|     bool debug = furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug); | ||||
|     bool is_debug_mode = furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug); | ||||
|     for(size_t i = 0; i < COUNT_OF(cli_command_gpio_pins); i++) { | ||||
|         if(!furi_string_cmp(pin_name, cli_command_gpio_pins[i].name)) { | ||||
|             if(!cli_command_gpio_pins[i].debug || debug) { | ||||
|         if(furi_string_equal(pin_name, cli_command_gpio_pins[i].name)) { | ||||
|             if(!cli_command_gpio_pins[i].debug || is_debug_mode) { | ||||
|                 *result = i; | ||||
|                 found = true; | ||||
|                 break; | ||||
|                 return true; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return found; | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| static void gpio_print_pins(void) { | ||||
|     printf("Wrong pin name. Available pins: "); | ||||
|     bool debug = furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug); | ||||
|     bool is_debug_mode = furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug); | ||||
|     for(size_t i = 0; i < COUNT_OF(cli_command_gpio_pins); i++) { | ||||
|         if(!cli_command_gpio_pins[i].debug || debug) { | ||||
|         if(!cli_command_gpio_pins[i].debug || is_debug_mode) { | ||||
|             printf("%s ", cli_command_gpio_pins[i].name); | ||||
|         } | ||||
|     } | ||||
| @ -69,34 +68,29 @@ typedef enum { | ||||
| } GpioParseReturn; | ||||
| 
 | ||||
| static GpioParseReturn gpio_command_parse(FuriString* args, size_t* pin_num, uint8_t* value) { | ||||
|     FuriString* pin_name; | ||||
|     pin_name = furi_string_alloc(); | ||||
|     GpioParseReturn ret = GpioParseReturnOk; | ||||
|     FuriString* pin_name = furi_string_alloc(); | ||||
| 
 | ||||
|     size_t ws = furi_string_search_char(args, ' '); | ||||
|     if(ws == FURI_STRING_FAILURE) { | ||||
|         return GpioParseReturnCmdSyntaxError; | ||||
|     do { | ||||
|         if(!args_read_string_and_trim(args, pin_name)) { | ||||
|             ret = GpioParseReturnCmdSyntaxError; | ||||
|             break; | ||||
|         } else if(!pin_name_to_int(pin_name, pin_num)) { | ||||
|             ret = GpioParseReturnPinError; | ||||
|             break; | ||||
|         } | ||||
| 
 | ||||
|     furi_string_set_n(pin_name, args, 0, ws); | ||||
|     furi_string_right(args, ws); | ||||
|     furi_string_trim(args); | ||||
| 
 | ||||
|     if(!pin_name_to_int(pin_name, pin_num)) { | ||||
|         furi_string_free(pin_name); | ||||
|         return GpioParseReturnPinError; | ||||
|         int pin_mode; //-V779
 | ||||
|         if(!args_read_int_and_trim(args, &pin_mode) || pin_mode < 0 || pin_mode > 1) { | ||||
|             ret = GpioParseReturnValueError; | ||||
|             break; | ||||
|         } | ||||
| 
 | ||||
|         *value = pin_mode; | ||||
|     } while(false); | ||||
| 
 | ||||
|     furi_string_free(pin_name); | ||||
| 
 | ||||
|     if(!furi_string_cmp(args, "0")) { | ||||
|         *value = 0; | ||||
|     } else if(!furi_string_cmp(args, "1")) { | ||||
|         *value = 1; | ||||
|     } else { | ||||
|         return GpioParseReturnValueError; | ||||
|     } | ||||
| 
 | ||||
|     return GpioParseReturnOk; | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| void cli_command_gpio_mode(Cli* cli, FuriString* args, void* context) { | ||||
| @ -111,7 +105,7 @@ void cli_command_gpio_mode(Cli* cli, FuriString* args, void* context) { | ||||
|     if(err == GpioParseReturnCmdSyntaxError) { | ||||
|         cli_print_usage("gpio mode", "<pin_name> <0|1>", furi_string_get_cstr(args)); | ||||
|         return; | ||||
|     } else if(err == GpioParseReturnPinError) { | ||||
|     } else if(err == GpioParseReturnPinError) { //-V547
 | ||||
|         gpio_print_pins(); | ||||
|         return; | ||||
|     } else if(err == GpioParseReturnValueError) { | ||||
| @ -119,7 +113,7 @@ void cli_command_gpio_mode(Cli* cli, FuriString* args, void* context) { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     if(cli_command_gpio_pins[num].debug) { | ||||
|     if(cli_command_gpio_pins[num].debug) { //-V779
 | ||||
|         printf( | ||||
|             "Changing this pin mode may damage hardware. Are you sure you want to continue? (y/n)?\r\n"); | ||||
|         char c = cli_getc(cli); | ||||
| @ -149,7 +143,7 @@ void cli_command_gpio_read(Cli* cli, FuriString* args, void* context) { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     if(LL_GPIO_MODE_INPUT != | ||||
|     if(LL_GPIO_MODE_INPUT != //-V779
 | ||||
|        LL_GPIO_GetPinMode( | ||||
|            cli_command_gpio_pins[num].pin->port, cli_command_gpio_pins[num].pin->pin)) { | ||||
|         printf("Err: pin %s is not set as an input.", cli_command_gpio_pins[num].name); | ||||
| @ -171,7 +165,7 @@ void cli_command_gpio_set(Cli* cli, FuriString* args, void* context) { | ||||
|     if(err == GpioParseReturnCmdSyntaxError) { | ||||
|         cli_print_usage("gpio set", "<pin_name> <0|1>", furi_string_get_cstr(args)); | ||||
|         return; | ||||
|     } else if(err == GpioParseReturnPinError) { | ||||
|     } else if(err == GpioParseReturnPinError) { //-V547
 | ||||
|         gpio_print_pins(); | ||||
|         return; | ||||
|     } else if(err == GpioParseReturnValueError) { | ||||
| @ -179,7 +173,7 @@ void cli_command_gpio_set(Cli* cli, FuriString* args, void* context) { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     if(LL_GPIO_MODE_OUTPUT != | ||||
|     if(LL_GPIO_MODE_OUTPUT != //-V779
 | ||||
|        LL_GPIO_GetPinMode( | ||||
|            cli_command_gpio_pins[num].pin->port, cli_command_gpio_pins[num].pin->pin)) { | ||||
|         printf("Err: pin %s is not set as an output.", cli_command_gpio_pins[num].name); | ||||
|  | ||||
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