Merge remote-tracking branch 'origin/release-candidate' into release

This commit is contained in:
Aleksandr Kutuzov 2023-01-09 02:02:31 +09:00
commit 8ee66c3e9b
350 changed files with 4599 additions and 2194 deletions

View File

@ -14,7 +14,7 @@ body:
description: | description: |
Please describe your feature request in as many details as possible. Please describe your feature request in as many details as possible.
- Describe what it should do. - 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: validations:
required: true required: true
- type: textarea - type: textarea

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

View File

@ -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

View File

@ -30,11 +30,6 @@ jobs:
fetch-depth: 0 fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }} ref: ${{ github.event.pull_request.head.sha }}
- name: 'Make artifacts directory'
run: |
rm -rf artifacts
mkdir artifacts
- name: 'Get commit details' - name: 'Get commit details'
id: names id: names
run: | run: |
@ -46,6 +41,15 @@ jobs:
TYPE="other" TYPE="other"
fi fi
python3 scripts/get_env.py "--event_file=${{ github.event_path }}" "--type=$TYPE" 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' - name: 'Bundle scripts'
if: ${{ !github.event.pull_request.head.repo.fork }} if: ${{ !github.event.pull_request.head.repo.fork }}
@ -82,9 +86,33 @@ jobs:
run: | run: |
cp build/core2_firmware.tgz "artifacts/flipper-z-any-core2_firmware-${SUFFIX}.tgz" 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: | 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' - name: 'Upload artifacts to update server'
if: ${{ !github.event.pull_request.head.repo.fork }} if: ${{ !github.event.pull_request.head.repo.fork }}

View File

@ -50,7 +50,7 @@ jobs:
- name: 'Generate compile_comands.json' - name: 'Generate compile_comands.json'
run: | 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' - name: 'Static code analysis'
run: | run: |
@ -58,15 +58,25 @@ jobs:
pvs-studio-analyzer credentials ${{ secrets.PVS_STUDIO_CREDENTIALS }} pvs-studio-analyzer credentials ${{ secrets.PVS_STUDIO_CREDENTIALS }}
pvs-studio-analyzer analyze \ pvs-studio-analyzer analyze \
@.pvsoptions \ @.pvsoptions \
-C gccarm \
-j$(grep -c processor /proc/cpuinfo) \ -j$(grep -c processor /proc/cpuinfo) \
-f build/f7-firmware-DC/compile_commands.json \ -f build/f7-firmware-DC/compile_commands.json \
-o PVS-Studio.log -o PVS-Studio.log
- name: 'Convert PVS-Studio output to html page' - name: 'Convert PVS-Studio output to html and detect warnings'
run: plog-converter -a GA:1,2,3 -t fullhtml PVS-Studio.log -o reports/${DEFAULT_TARGET}-${SUFFIX} 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' - 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: | run: |
mkdir -p ~/.ssh mkdir -p ~/.ssh
ssh-keyscan -p ${{ secrets.RSYNC_DEPLOY_PORT }} -H ${{ secrets.RSYNC_DEPLOY_HOST }} > ~/.ssh/known_hosts ssh-keyscan -p ${{ secrets.RSYNC_DEPLOY_PORT }} -H ${{ secrets.RSYNC_DEPLOY_HOST }} > ~/.ssh/known_hosts
@ -78,8 +88,8 @@ jobs:
rm ./deploy_key; rm ./deploy_key;
- name: 'Find Previous Comment' - name: 'Find Previous 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/find-comment@v1 uses: peter-evans/find-comment@v2
id: fc id: fc
with: with:
issue-number: ${{ github.event.pull_request.number }} issue-number: ${{ github.event.pull_request.number }}
@ -87,7 +97,7 @@ jobs:
body-includes: 'PVS-Studio report for commit' body-includes: 'PVS-Studio report for commit'
- name: 'Create or update comment' - 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 uses: peter-evans/create-or-update-comment@v1
with: with:
comment-id: ${{ steps.fc.outputs.comment-id }} comment-id: ${{ steps.fc.outputs.comment-id }}
@ -96,3 +106,10 @@ jobs:
**PVS-Studio report for commit `${{steps.names.outputs.commit_sha}}`:** **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) - [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 edit-mode: replace
- name: 'Raise exception'
if: ${{ steps.pvs-warn.outputs.warnings != 0 }}
run: |
echo "Please fix all PVS varnings before merge"
exit 1

View File

@ -9,7 +9,7 @@ env:
FBT_TOOLCHAIN_PATH: /opt FBT_TOOLCHAIN_PATH: /opt
jobs: jobs:
run_units_on_test_bench: run_units_on_bench:
runs-on: [self-hosted, FlipperZeroTest] runs-on: [self-hosted, FlipperZeroTest]
steps: steps:
- name: 'Decontaminate previous build leftovers' - name: 'Decontaminate previous build leftovers'
@ -29,81 +29,38 @@ jobs:
run: | run: |
echo "flipper=/dev/ttyACM0" >> $GITHUB_OUTPUT 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' - name: 'Flash unit tests firmware'
id: flashing id: flashing
if: success() if: success()
run: | run: |
./fbt flash OPENOCD_ADAPTER_SERIAL=2A0906016415303030303032 FIRMWARE_APP_SET=unit_tests FORCE=1 ./fbt flash OPENOCD_ADAPTER_SERIAL=2A0906016415303030303032 FIRMWARE_APP_SET=unit_tests FORCE=1
- name: 'Wait for flipper to finish updating' - name: 'Wait for flipper and format ext'
id: connect id: format_ext
if: steps.flashing.outcome == 'success' if: steps.flashing.outcome == 'success'
run: | run: |
source scripts/toolchain/fbtenv.sh source scripts/toolchain/fbtenv.sh
python3 scripts/testing/await_flipper.py ${{steps.device.outputs.flipper}} 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 id: copy
if: steps.connect.outcome == 'success' if: steps.format_ext.outcome == 'success'
run: | run: |
source scripts/toolchain/fbtenv.sh 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/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' - name: 'Run units and validate results'
id: run_units
if: steps.copy.outcome == 'success' if: steps.copy.outcome == 'success'
run: | run: |
source scripts/toolchain/fbtenv.sh source scripts/toolchain/fbtenv.sh
python3 scripts/testing/units.py ${{steps.device.outputs.flipper}} python3 scripts/testing/units.py ${{steps.device.outputs.flipper}}
- name: 'Get last release tag' - name: 'Check GDB output'
id: release_tag if: failure()
if: always()
run: | run: |
echo "tag=$(git tag -l --sort=-version:refname | grep -v "rc\|RC" | head -1)" >> $GITHUB_OUTPUT ./fbt gdb_trace_all OPENOCD_ADAPTER_SERIAL=2A0906016415303030303032 FIRMWARE_APP_SET=unit_tests FORCE=1
- 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

77
.github/workflows/updater_test.yml vendored Normal file
View 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
View File

@ -30,6 +30,10 @@ Brewfile.lock.json
# Visual Studio Code # Visual Studio Code
.vscode/ .vscode/
# Kate
.kateproject
.kateconfig
# legendary cmake's # legendary cmake's
build build
CMakeLists.txt CMakeLists.txt

View File

@ -1,4 +1,5 @@
# MLib macros we can't do much about. # MLib macros we can't do much about.
//-V:M_LET:1048,1044
//-V:M_EACH:1048,1044 //-V:M_EACH:1048,1044
//-V:ARRAY_DEF:760,747,568,776,729,712,654 //-V:ARRAY_DEF:760,747,568,776,729,712,654
//-V:LIST_DEF:760,747,568,712,729,654,776 //-V:LIST_DEF:760,747,568,712,729,654,776
@ -16,8 +17,30 @@
# Potentially null argument warnings # Potentially null argument warnings
//-V:memset:575 //-V:memset:575
//-V:memcpy:575 //-V:memcpy:575
//-V:memcmp:575
//-V:strlen:575
//-V:strcpy:575 //-V:strcpy:575
//-V:strncpy:575
//-V:strchr:575 //-V:strchr:575
# For loop warning on M_FOREACH # For loop warning on M_FOREACH
//-V:for:1044 //-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

View File

@ -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

View File

@ -1,6 +0,0 @@
cask "gcc-arm-embedded"
brew "protobuf"
brew "gdb"
brew "open-ocd"
brew "clang-format"
brew "dfu-util"

View File

@ -3,15 +3,15 @@
Nice to see you reading this document, we really appreciate it. Nice to see you reading this document, we really appreciate it.
As all documents of this kind it's unable to cover everything. 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, Also, we already have automatic rules checking and formatting,
but it got it's limitations and this guide is still mandatory. 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. 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. 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. 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. Code we write is intended to be public.
Avoid one-liners from hell and keep code complexity under control. 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. Leave references to standards that you are implementing.
Use project wiki to document new/reverse engineered standards. Use project wiki to document new/reverse engineered standards.
@ -89,7 +89,7 @@ Enforced by linter.
Suffixes: Suffixes:
- `alloc` - allocate and init instance. C style constructor. Returns pointer to instance. - `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 # C++ coding style

View File

@ -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. - 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 comply with our [Coding Style](CODING_STYLE.md)
- Your PR must contain code compatible with project [LICENSE](LICENSE). - 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 passes CI/CD.
- PR will only be merged if it pass review by code owner. - PR will only be merged if it passes review by code owner.
Feel free to ask questions in issues if you're not sure. 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 ### Pull Request
When you're done making the changes, open a pull request, often referred to as a PR. 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. - 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. - 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. Once you submit your PR, a Docs team member will review your proposal. We may ask questions or request for additional information.

View File

@ -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
View File

@ -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 # Flipper Zero Firmware
[![Discord](https://img.shields.io/discord/740930220399525928.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](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.
![Show me the code](https://habrastorage.org/webt/eo/m0/e4/eom0e4btudte7nrhnyic-laiog0.png) # Contributing
Welcome to [Flipper Zero](https://flipperzero.one/)'s Firmware repo! 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.
Our goal is to create nice and clean code with good documentation, to make it a pleasure for everyone to work with.
# 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 ```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 ```shell
[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
./fbt ./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 ```shell
./fbt flash
Connect your device via ST-Link and run:
```sh
./fbt firmware_flash
``` ```
# Links ## Flashing firmware using USB
* Discord: [flipp.dev/discord](https://flipp.dev/discord) 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:
* Website: [flipperzero.one](https://flipperzero.one)
* Kickstarter page: [kickstarter.com](https://www.kickstarter.com/projects/flipper-devices/flipper-zero-tamagochi-for-hackers) ```shell
* Forum: [forum.flipperzero.one](https://forum.flipperzero.one/) ./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 # Project structure
- `applications` - Applications and services used in firmware - `applications` - applications and services used in firmware
- `assets` - Assets used by applications and services - `assets` - assets used by applications and services
- `furi` - Furi Core: os level primitives and helpers - `furi` - Furi Core: OS-level primitives and helpers
- `debug` - Debug tool: GDB-plugins, SVD-file and etc - `debug` - debug tool: GDB plugins, an SVD file, etc.
- `documentation` - Documentation generation system configs and input files - `documentation` - documentation generation system configs and input files
- `firmware` - Firmware source code - `firmware` - firmware source code
- `lib` - Our and 3rd party libraries, drivers, etc. - `lib` - our and 3rd party libraries, drivers, etc.
- `scripts` - Supplementary scripts and python libraries home - `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)

View File

@ -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

View File

@ -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 # Debugging firmware
firmware_debug = distenv.PhonyTarget( firmware_debug = distenv.PhonyTarget(
"debug", "debug",

View 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",
)

View 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;
}

View 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;
}

View File

@ -3,98 +3,37 @@
#include <string.h> #include <string.h>
#include <stdbool.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() { void test_furi_memmgr() {
size_t heap_size = 0; void* ptr;
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
// allocate memory case // allocate memory case
heap_size_old = memmgr_get_free_heap(); ptr = malloc(100);
ptr = malloc(alloc_size); mu_check(ptr != NULL);
heap_size = memmgr_get_free_heap(); // test that memory is zero-initialized after allocation
mu_assert_pointers_not_eq(ptr, NULL); for(int i = 0; i < 100; i++) {
mu_assert(heap_equal(heap_size, heap_size_old - alloc_size), "allocate failed"); mu_assert_int_eq(0, ((uint8_t*)ptr)[i]);
}
// free memory case
heap_size_old = memmgr_get_free_heap();
free(ptr); 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 // reallocate memory case
ptr = malloc(100);
memset(ptr, 66, 100);
ptr = realloc(ptr, 200);
mu_check(ptr != NULL);
// get filled array with some data // test that memory is really reallocated
original_ptr = malloc(alloc_size); for(int i = 0; i < 100; i++) {
mu_assert_pointers_not_eq(original_ptr, NULL); mu_assert_int_eq(66, ((uint8_t*)ptr)[i]);
for(int i = 0; i < alloc_size; i++) {
*(unsigned char*)(original_ptr + i) = i;
} }
// malloc array and copy data // TODO: fix realloc to copy only old size, and write testcase that leftover of reallocated memory is zero-initialized
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);
free(ptr); free(ptr);
// allocate and zero-initialize array (calloc) // allocate and zero-initialize array (calloc)
original_ptr = malloc(alloc_size); ptr = calloc(100, 2);
mu_assert_pointers_not_eq(original_ptr, NULL); mu_check(ptr != NULL);
for(int i = 0; i < 100 * 2; i++) {
for(int i = 0; i < alloc_size; i++) { mu_assert_int_eq(0, ((uint8_t*)ptr)[i]);
*(unsigned char*)(original_ptr + i) = 0;
} }
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); free(ptr);
} }

View 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;
}

View File

@ -72,8 +72,32 @@ MU_TEST_1(stream_composite_subtest, Stream* stream) {
mu_check(stream_seek(stream, -3, StreamOffsetFromEnd)); mu_check(stream_seek(stream, -3, StreamOffsetFromEnd));
mu_check(stream_tell(stream) == 4); 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" // "1337_69" -> "1337lee"
mu_check(stream_seek(stream, 4, StreamOffsetFromStart));
mu_check(stream_write_string(stream, string_lee) == 3); mu_check(stream_write_string(stream, string_lee) == 3);
mu_check(stream_size(stream) == 7); mu_check(stream_size(stream) == 7);
mu_check(stream_tell(stream) == 7); mu_check(stream_tell(stream) == 7);

View File

@ -13,7 +13,7 @@
#define CAME_ATOMO_DIR_NAME EXT_PATH("subghz/assets/came_atomo") #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 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_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 #define TEST_TIMEOUT 10000
static SubGhzEnvironment* environment_handler; 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_load_preset(FuriHalSubGhzPresetOok650Async);
furi_hal_subghz_set_frequency_and_path(433920000); 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()) { while(!furi_hal_subghz_is_async_tx_complete()) {
furi_delay_ms(10); furi_delay_ms(10);
} }
@ -594,6 +597,13 @@ MU_TEST(subghz_decoder_smc5326_test) {
"Test decoder " SUBGHZ_PROTOCOL_SMC5326_NAME " error\r\n"); "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 //test encoders
MU_TEST(subghz_encoder_princeton_test) { MU_TEST(subghz_encoder_princeton_test) {
mu_assert( mu_assert(
@ -727,6 +737,12 @@ MU_TEST(subghz_encoder_smc5326_test) {
"Test encoder " SUBGHZ_PROTOCOL_SMC5326_NAME " error\r\n"); "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_TEST(subghz_random_test) {
mu_assert(subghz_decode_random_test(TEST_RANDOM_DIR_NAME), "Random test error\r\n"); 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_clemsa_test);
MU_RUN_TEST(subghz_decoder_ansonic_test); MU_RUN_TEST(subghz_decoder_ansonic_test);
MU_RUN_TEST(subghz_decoder_smc5326_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_princeton_test);
MU_RUN_TEST(subghz_encoder_came_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_clemsa_test);
MU_RUN_TEST(subghz_encoder_ansonic_test); MU_RUN_TEST(subghz_encoder_ansonic_test);
MU_RUN_TEST(subghz_encoder_smc5326_test); MU_RUN_TEST(subghz_encoder_smc5326_test);
MU_RUN_TEST(subghz_encoder_holtek_ht12x_test);
MU_RUN_TEST(subghz_random_test); MU_RUN_TEST(subghz_random_test);
subghz_test_deinit(); subghz_test_deinit();

View File

@ -13,6 +13,7 @@ int run_minunit_test_furi_hal();
int run_minunit_test_furi_string(); int run_minunit_test_furi_string();
int run_minunit_test_infrared(); int run_minunit_test_infrared();
int run_minunit_test_rpc(); int run_minunit_test_rpc();
int run_minunit_test_manifest();
int run_minunit_test_flipper_format(); int run_minunit_test_flipper_format();
int run_minunit_test_flipper_format_string(); int run_minunit_test_flipper_format_string();
int run_minunit_test_stream(); 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_lfrfid_protocols();
int run_minunit_test_nfc(); int run_minunit_test_nfc();
int run_minunit_test_bit_lib(); int run_minunit_test_bit_lib();
int run_minunit_test_float_tools();
int run_minunit_test_bt(); int run_minunit_test_bt();
typedef int (*UnitTestEntry)(); typedef int (*UnitTestEntry)();
@ -40,6 +42,7 @@ const UnitTest unit_tests[] = {
{.name = "storage", .entry = run_minunit_test_storage}, {.name = "storage", .entry = run_minunit_test_storage},
{.name = "stream", .entry = run_minunit_test_stream}, {.name = "stream", .entry = run_minunit_test_stream},
{.name = "dirwalk", .entry = run_minunit_test_dirwalk}, {.name = "dirwalk", .entry = run_minunit_test_dirwalk},
{.name = "manifest", .entry = run_minunit_test_manifest},
{.name = "flipper_format", .entry = run_minunit_test_flipper_format}, {.name = "flipper_format", .entry = run_minunit_test_flipper_format},
{.name = "flipper_format_string", .entry = run_minunit_test_flipper_format_string}, {.name = "flipper_format_string", .entry = run_minunit_test_flipper_format_string},
{.name = "rpc", .entry = run_minunit_test_rpc}, {.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 = "protocol_dict", .entry = run_minunit_test_protocol_dict},
{.name = "lfrfid", .entry = run_minunit_test_lfrfid_protocols}, {.name = "lfrfid", .entry = run_minunit_test_lfrfid_protocols},
{.name = "bit_lib", .entry = run_minunit_test_bit_lib}, {.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}, {.name = "bt", .entry = run_minunit_test_bt},
}; };
@ -73,7 +77,6 @@ void unit_tests_cli(Cli* cli, FuriString* args, void* context) {
UNUSED(cli); UNUSED(cli);
UNUSED(args); UNUSED(args);
UNUSED(context); UNUSED(context);
uint32_t failed_tests = 0;
minunit_run = 0; minunit_run = 0;
minunit_assert = 0; minunit_assert = 0;
minunit_fail = 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_size(args)) {
if(furi_string_cmp_str(args, unit_tests[i].name) == 0) { if(furi_string_cmp_str(args, unit_tests[i].name) == 0) {
failed_tests += unit_tests[i].entry(); unit_tests[i].entry();
} else { } else {
printf("Skipping %s\r\n", unit_tests[i].name); printf("Skipping %s\r\n", unit_tests[i].name);
} }
} else { } 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 // Time report
cycle_counter = (furi_get_tick() - cycle_counter); 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); printf("Leaked: %ld\r\n", heap_before - heap_after);
// Final Report // Final Report
if(failed_tests == 0) { if(minunit_fail == 0) {
notification_message(notification, &sequence_success); notification_message(notification, &sequence_success);
printf("Status: PASSED\r\n"); printf("Status: PASSED\r\n");
} else { } else {
@ -127,6 +132,7 @@ void unit_tests_cli(Cli* cli, FuriString* args, void* context) {
printf("Status: FAILED\r\n"); printf("Status: FAILED\r\n");
} }
} }
}
furi_record_close(RECORD_NOTIFICATION); furi_record_close(RECORD_NOTIFICATION);
furi_record_close(RECORD_LOADER); furi_record_close(RECORD_LOADER);

View File

@ -13,7 +13,7 @@ ArchiveAppTypeEnum archive_get_app_type(const char* path) {
} }
app_name++; 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) { if(strncmp(app_name, known_apps[i], strlen(known_apps[i])) == 0) {
return i; return i;
} }

View File

@ -177,7 +177,7 @@ bool archive_favorites_read(void* context) {
archive_set_item_count(browser, file_count); archive_set_item_count(browser, file_count);
if(need_refresh) { if(need_refresh) { //-V547
archive_favourites_rescan(); archive_favourites_rescan();
} }

View File

@ -116,7 +116,7 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) {
case ArchiveBrowserEventFileMenuPin: { case ArchiveBrowserEventFileMenuPin: {
const char* name = archive_get_name(browser); const char* name = archive_get_name(browser);
if(favorites) { if(favorites) {
archive_favorites_delete(name); archive_favorites_delete("%s", name);
archive_file_array_rm_selected(browser); archive_file_array_rm_selected(browser);
archive_show_file_menu(browser, false); archive_show_file_menu(browser, false);
} else if(archive_is_known_app(selected->type)) { } else if(archive_is_known_app(selected->type)) {

View File

@ -218,8 +218,8 @@ static bool ducky_string(const char* param) {
} }
static uint16_t ducky_get_keycode(const char* param, bool accept_chars) { 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++) { for(size_t i = 0; i < (sizeof(ducky_keys) / sizeof(ducky_keys[0])); i++) {
uint8_t key_cmd_len = strlen(ducky_keys[i].name); size_t key_cmd_len = strlen(ducky_keys[i].name);
if((strncmp(param, ducky_keys[i].name, key_cmd_len) == 0) && if((strncmp(param, ducky_keys[i].name, key_cmd_len) == 0) &&
(ducky_is_line_end(param[key_cmd_len]))) { (ducky_is_line_end(param[key_cmd_len]))) {
return ducky_keys[i].keycode; return ducky_keys[i].keycode;
@ -417,7 +417,7 @@ static int32_t ducky_script_execute_next(BadUsbScript* bad_usb, File* script_fil
return 0; return 0;
} else if(delay_val < 0) { // Script error } else if(delay_val < 0) { // Script error
bad_usb->st.error_line = bad_usb->st.line_cur - 1; bad_usb->st.error_line = bad_usb->st.line_cur - 1;
FURI_LOG_E(WORKER_TAG, "Unknown command at line %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; return SCRIPT_STATE_ERROR;
} else { } else {
return (delay_val + bad_usb->defdelay); return (delay_val + bad_usb->defdelay);
@ -596,7 +596,9 @@ static int32_t bad_usb_worker(void* context) {
} }
bad_usb->st.state = worker_state; bad_usb->st.state = worker_state;
continue; continue;
} else if((flags == FuriFlagErrorTimeout) || (flags == FuriFlagErrorResource)) { } else if(
(flags == (unsigned)FuriFlagErrorTimeout) ||
(flags == (unsigned)FuriFlagErrorResource)) {
if(delay_val > 0) { if(delay_val > 0) {
bad_usb->st.delay_remain--; bad_usb->st.delay_remain--;
continue; continue;
@ -650,7 +652,7 @@ static int32_t bad_usb_worker(void* context) {
BadUsbScript* bad_usb_script_open(FuriString* file_path) { BadUsbScript* bad_usb_script_open(FuriString* file_path) {
furi_assert(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(); bad_usb->file_path = furi_string_alloc();
furi_string_set(bad_usb->file_path, file_path); 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); bad_usb->thread = furi_thread_alloc_ex("BadUsbWorker", 2048, bad_usb_worker, bad_usb);
furi_thread_start(bad_usb->thread); furi_thread_start(bad_usb->thread);
return bad_usb; return bad_usb;
} } //-V773
void bad_usb_script_close(BadUsbScript* bad_usb) { void bad_usb_script_close(BadUsbScript* bad_usb) {
furi_assert(bad_usb); furi_assert(bad_usb);

View File

@ -156,7 +156,7 @@ static bool fap_loader_select_app(FapLoader* loader) {
} }
static FapLoader* fap_loader_alloc(const char* path) { 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->fap_path = furi_string_alloc_set(path);
loader->storage = furi_record_open(RECORD_STORAGE); loader->storage = furi_record_open(RECORD_STORAGE);
loader->dialogs = furi_record_open(RECORD_DIALOGS); loader->dialogs = furi_record_open(RECORD_DIALOGS);
@ -167,7 +167,7 @@ static FapLoader* fap_loader_alloc(const char* path) {
loader->view_dispatcher, loader->gui, ViewDispatcherTypeFullscreen); loader->view_dispatcher, loader->gui, ViewDispatcherTypeFullscreen);
view_dispatcher_add_view(loader->view_dispatcher, 0, loading_get_view(loader->loading)); view_dispatcher_add_view(loader->view_dispatcher, 0, loading_get_view(loader->loading));
return loader; return loader;
} } //-V773
static void fap_loader_free(FapLoader* loader) { static void fap_loader_free(FapLoader* loader) {
view_dispatcher_remove_view(loader->view_dispatcher, 0); view_dispatcher_remove_view(loader->view_dispatcher, 0);

View File

@ -278,7 +278,7 @@ bool ibutton_save_key(iButton* ibutton, const char* key_name) {
flipper_format_free(file); flipper_format_free(file);
if(!result) { if(!result) { //-V547
dialog_message_show_storage_error(ibutton->dialogs, "Cannot save\nkey file"); 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) { 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) { void ibutton_notification_message(iButton* ibutton, uint32_t message) {
@ -343,7 +343,7 @@ int32_t ibutton_app(void* p) {
} else { } else {
view_dispatcher_attach_to_gui( view_dispatcher_attach_to_gui(
ibutton->view_dispatcher, ibutton->gui, ViewDispatcherTypeFullscreen); ibutton->view_dispatcher, ibutton->gui, ViewDispatcherTypeFullscreen);
if(key_loaded) { if(key_loaded) { //-V547
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneEmulate); scene_manager_next_scene(ibutton->scene_manager, iButtonSceneEmulate);
DOLPHIN_DEED(DolphinDeedIbuttonEmulate); DOLPHIN_DEED(DolphinDeedIbuttonEmulate);
} else { } else {

View File

@ -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) { 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) { void infrared_play_notification_message(Infrared* infrared, uint32_t message) {
@ -455,7 +455,7 @@ int32_t infrared_app(void* p) {
} else { } else {
view_dispatcher_attach_to_gui( view_dispatcher_attach_to_gui(
infrared->view_dispatcher, infrared->gui, ViewDispatcherTypeFullscreen); infrared->view_dispatcher, infrared->gui, ViewDispatcherTypeFullscreen);
if(is_remote_loaded) { if(is_remote_loaded) { //-V547
scene_manager_next_scene(infrared->scene_manager, InfraredSceneRemote); scene_manager_next_scene(infrared->scene_manager, InfraredSceneRemote);
} else { } else {
scene_manager_next_scene(infrared->scene_manager, InfraredSceneStart); scene_manager_next_scene(infrared->scene_manager, InfraredSceneStart);

View File

@ -65,7 +65,7 @@ bool infrared_brute_force_calculate_messages(InfraredBruteForce* brute_force) {
while(flipper_format_read_string(ff, "name", signal_name)) { while(flipper_format_read_string(ff, "name", signal_name)) {
InfraredBruteForceRecord* record = InfraredBruteForceRecord* record =
InfraredBruteForceRecordDict_get(brute_force->records, signal_name); InfraredBruteForceRecordDict_get(brute_force->records, signal_name);
if(record) { if(record) { //-V547
++(record->count); ++(record->count);
} }
} }

View File

@ -55,7 +55,7 @@ static void signal_received_callback(void* context, InfraredWorkerSignal* receiv
size_t timings_cnt; size_t timings_cnt;
infrared_worker_get_raw_signal(received_signal, &timings, &timings_cnt); infrared_worker_get_raw_signal(received_signal, &timings, &timings_cnt);
buf_cnt = 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); cli_write(cli, (uint8_t*)buf, buf_cnt);
for(size_t i = 0; i < timings_cnt; ++i) { for(size_t i = 0; i < timings_cnt; ++i) {
buf_cnt = snprintf(buf, sizeof(buf), "%lu ", timings[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); InfraredRawSignal* raw_signal = infrared_signal_get_raw_signal(signal);
printf( 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( if(!infrared_cli_decode_raw_signal(
raw_signal, decoder, output_file, furi_string_get_cstr(tmp))) raw_signal, decoder, output_file, furi_string_get_cstr(tmp)))
break; break;
@ -382,7 +384,7 @@ static void infrared_cli_list_remote_signals(FuriString* remote_name) {
while(flipper_format_read_string(ff, "name", signal_name)) { while(flipper_format_read_string(ff, "name", signal_name)) {
furi_string_set_str(key, furi_string_get_cstr(signal_name)); furi_string_set_str(key, furi_string_get_cstr(signal_name));
int* v = dict_signals_get(signals_dict, key); int* v = dict_signals_get(signals_dict, key);
if(v != NULL) { if(v != NULL) { //-V547
(*v)++; (*v)++;
max = M_MAX(*v, max); max = M_MAX(*v, max);
} else { } else {
@ -436,7 +438,7 @@ static void
break; 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"); printf("Press Ctrl-C to stop.\r\n");
int records_sent = 0; int records_sent = 0;

View File

@ -145,15 +145,14 @@ bool infrared_remote_load(InfraredRemote* remote, FuriString* path) {
buf = furi_string_alloc(); buf = furi_string_alloc();
FURI_LOG_I(TAG, "load file: \'%s\'", furi_string_get_cstr(path)); FURI_LOG_I(TAG, "load file: \'%s\'", furi_string_get_cstr(path));
bool success = flipper_format_buffered_file_open_existing(ff, furi_string_get_cstr(path)); bool success = false;
if(success) { do {
if(!flipper_format_buffered_file_open_existing(ff, furi_string_get_cstr(path))) break;
uint32_t version; uint32_t version;
success = flipper_format_read_header(ff, buf, &version) && if(!flipper_format_read_header(ff, buf, &version)) break;
!furi_string_cmp(buf, "IR signals file") && (version == 1); if(!furi_string_equal(buf, "IR signals file") || (version != 1)) break;
}
if(success) {
path_extract_filename(path, buf, true); path_extract_filename(path, buf, true);
infrared_remote_clear_buttons(remote); infrared_remote_clear_buttons(remote);
infrared_remote_set_name(remote, furi_string_get_cstr(buf)); 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); infrared_remote_button_free(button);
} }
} }
} success = true;
} while(false);
furi_string_free(buf); furi_string_free(buf);
flipper_format_free(ff); flipper_format_free(ff);

View File

@ -74,7 +74,7 @@ static bool infrared_signal_is_raw_valid(InfraredRawSignal* raw) {
} else if((raw->timings_size <= 0) || (raw->timings_size > MAX_TIMINGS_AMOUNT)) { } else if((raw->timings_size <= 0) || (raw->timings_size > MAX_TIMINGS_AMOUNT)) {
FURI_LOG_E( FURI_LOG_E(
TAG, TAG,
"Timings amount is out of range (0 - %X): %X", "Timings amount is out of range (0 - %X): %zX",
MAX_TIMINGS_AMOUNT, MAX_TIMINGS_AMOUNT,
raw->timings_size); raw->timings_size);
return false; return false;
@ -275,8 +275,8 @@ bool infrared_signal_search_and_read(
is_name_found = furi_string_equal(name, tmp); is_name_found = furi_string_equal(name, tmp);
if(is_name_found) break; if(is_name_found) break;
} }
if(!is_name_found) break; if(!is_name_found) break; //-V547
if(!infrared_signal_read_body(signal, ff)) break; if(!infrared_signal_read_body(signal, ff)) break; //-V779
success = true; success = true;
} while(false); } while(false);

View File

@ -26,7 +26,7 @@ bool infrared_scene_debug_on_event(void* context, SceneManagerEvent event) {
InfraredRawSignal* raw = infrared_signal_get_raw_signal(signal); InfraredRawSignal* raw = infrared_signal_get_raw_signal(signal);
infrared_debug_view_set_text(debug_view, "RAW\n%d samples\n", raw->timings_size); 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) { for(size_t i = 0; i < raw->timings_size; ++i) {
printf("%lu ", raw->timings[i]); printf("%lu ", raw->timings[i]);
} }

View File

@ -32,7 +32,7 @@ static void rpc_command_callback(RpcAppSystemEvent rpc_event, void* context) {
} }
static LfRfid* lfrfid_alloc() { static LfRfid* lfrfid_alloc() {
LfRfid* lfrfid = malloc(sizeof(LfRfid)); //-V773 LfRfid* lfrfid = malloc(sizeof(LfRfid));
lfrfid->storage = furi_record_open(RECORD_STORAGE); lfrfid->storage = furi_record_open(RECORD_STORAGE);
lfrfid->dialogs = furi_record_open(RECORD_DIALOGS); lfrfid->dialogs = furi_record_open(RECORD_DIALOGS);
@ -100,7 +100,7 @@ static LfRfid* lfrfid_alloc() {
lfrfid->view_dispatcher, LfRfidViewRead, lfrfid_view_read_get_view(lfrfid->read_view)); lfrfid->view_dispatcher, LfRfidViewRead, lfrfid_view_read_get_view(lfrfid->read_view));
return lfrfid; return lfrfid;
} } //-V773
static void lfrfid_free(LfRfid* lfrfid) { static void lfrfid_free(LfRfid* lfrfid) {
furi_assert(lfrfid); furi_assert(lfrfid);

View File

@ -87,7 +87,7 @@ static void lfrfid_cli_read(Cli* cli, FuriString* args) {
uint32_t flags = uint32_t flags =
furi_event_flag_wait(context.event, available_flags, FuriFlagWaitAny, 100); furi_event_flag_wait(context.event, available_flags, FuriFlagWaitAny, 100);
if(flags != FuriFlagErrorTimeout) { if(flags != (unsigned)FuriFlagErrorTimeout) {
if(FURI_BIT(flags, LFRFIDWorkerReadDone)) { if(FURI_BIT(flags, LFRFIDWorkerReadDone)) {
break; break;
} }
@ -153,7 +153,7 @@ static bool lfrfid_cli_parse_args(FuriString* args, ProtocolDict* dict, Protocol
for(ProtocolId i = 0; i < LFRFIDProtocolMax; i++) { for(ProtocolId i = 0; i < LFRFIDProtocolMax; i++) {
printf( printf(
"\t%s, %d bytes long\r\n", "\t%s, %zu bytes long\r\n",
protocol_dict_get_name(dict, i), protocol_dict_get_name(dict, i),
protocol_dict_get_data_size(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 // check data arg
if(!args_read_hex_bytes(data_text, data, data_size)) { if(!args_read_hex_bytes(data_text, data, data_size)) {
printf( 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), protocol_dict_get_name(dict, *protocol),
data_size); data_size);
break; break;
@ -211,7 +211,7 @@ static void lfrfid_cli_write(Cli* cli, FuriString* args) {
while(!cli_cmd_interrupt_received(cli)) { while(!cli_cmd_interrupt_received(cli)) {
uint32_t flags = furi_event_flag_wait(event, available_flags, FuriFlagWaitAny, 100); uint32_t flags = furi_event_flag_wait(event, available_flags, FuriFlagWaitAny, 100);
if(flags != FuriFlagErrorTimeout) { if(flags != (unsigned)FuriFlagErrorTimeout) {
if(FURI_BIT(flags, LFRFIDWorkerWriteOK)) { if(FURI_BIT(flags, LFRFIDWorkerWriteOK)) {
printf("Written!\r\n"); printf("Written!\r\n");
break; break;
@ -309,9 +309,9 @@ static void lfrfid_cli_raw_analyze(Cli* cli, FuriString* args) {
warn = true; 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)); 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)); printf("%-16s", furi_string_get_cstr(info_string));
if(warn) { if(warn) {
@ -335,7 +335,7 @@ static void lfrfid_cli_raw_analyze(Cli* cli, FuriString* args) {
total_pulse += pulse; total_pulse += pulse;
total_duration += duration; total_duration += duration;
if(total_protocol != PROTOCOL_NO) { if(total_protocol != PROTOCOL_NO) { //-V1051
break; break;
} }
} else { } else {
@ -346,9 +346,9 @@ static void lfrfid_cli_raw_analyze(Cli* cli, FuriString* args) {
printf(" Frequency: %f\r\n", (double)frequency); printf(" Frequency: %f\r\n", (double)frequency);
printf(" Duty Cycle: %f\r\n", (double)duty_cycle); printf(" Duty Cycle: %f\r\n", (double)duty_cycle);
printf(" Warns: %ld\r\n", total_warns); printf(" Warns: %lu\r\n", total_warns);
printf(" Pulse sum: %ld\r\n", total_pulse); printf(" Pulse sum: %lu\r\n", total_pulse);
printf("Duration sum: %ld\r\n", total_duration); printf("Duration sum: %lu\r\n", total_duration);
printf(" Average: %f\r\n", (double)((float)total_pulse / (float)total_duration)); printf(" Average: %f\r\n", (double)((float)total_pulse / (float)total_duration));
printf(" Protocol: "); printf(" Protocol: ");
@ -435,7 +435,7 @@ static void lfrfid_cli_raw_read(Cli* cli, FuriString* args) {
while(true) { while(true) {
uint32_t flags = furi_event_flag_wait(event, available_flags, FuriFlagWaitAny, 100); uint32_t flags = furi_event_flag_wait(event, available_flags, FuriFlagWaitAny, 100);
if(flags != FuriFlagErrorTimeout) { if(flags != (unsigned)FuriFlagErrorTimeout) {
if(FURI_BIT(flags, LFRFIDWorkerReadRawFileError)) { if(FURI_BIT(flags, LFRFIDWorkerReadRawFileError)) {
printf("File is not RFID raw file\r\n"); printf("File is not RFID raw file\r\n");
break; break;
@ -510,7 +510,7 @@ static void lfrfid_cli_raw_emulate(Cli* cli, FuriString* args) {
while(true) { while(true) {
uint32_t flags = furi_event_flag_wait(event, available_flags, FuriFlagWaitAny, 100); uint32_t flags = furi_event_flag_wait(event, available_flags, FuriFlagWaitAny, 100);
if(flags != FuriFlagErrorTimeout) { if(flags != (unsigned)FuriFlagErrorTimeout) {
if(FURI_BIT(flags, LFRFIDWorkerEmulateRawFileError)) { if(FURI_BIT(flags, LFRFIDWorkerEmulateRawFileError)) {
printf("File is not RFID raw file\r\n"); printf("File is not RFID raw file\r\n");
break; break;

View File

@ -1,7 +1,6 @@
#include "../lfrfid_i.h" #include "../lfrfid_i.h"
typedef struct { typedef struct {
FuriString* menu_item_name[LFRFIDProtocolMax];
uint32_t line_sel; uint32_t line_sel;
} SaveTypeCtx; } SaveTypeCtx;
@ -16,25 +15,27 @@ void lfrfid_scene_save_type_on_enter(void* context) {
Submenu* submenu = app->submenu; Submenu* submenu = app->submenu;
SaveTypeCtx* state = malloc(sizeof(SaveTypeCtx)); SaveTypeCtx* state = malloc(sizeof(SaveTypeCtx));
FuriString* protocol_string = furi_string_alloc();
for(uint8_t i = 0; i < LFRFIDProtocolMax; i++) { for(uint8_t i = 0; i < LFRFIDProtocolMax; i++) {
if(strcmp( if(strcmp(
protocol_dict_get_manufacturer(app->dict, i), protocol_dict_get_manufacturer(app->dict, i),
protocol_dict_get_name(app->dict, i)) != 0) { protocol_dict_get_name(app->dict, i)) != 0) {
state->menu_item_name[i] = furi_string_alloc_printf( furi_string_printf(
protocol_string,
"%s %s", "%s %s",
protocol_dict_get_manufacturer(app->dict, i), protocol_dict_get_manufacturer(app->dict, i),
protocol_dict_get_name(app->dict, i)); protocol_dict_get_name(app->dict, i));
} else { } else {
state->menu_item_name[i] = furi_string_printf(protocol_string, "%s", protocol_dict_get_name(app->dict, i));
furi_string_alloc_printf("%s", protocol_dict_get_name(app->dict, i));
} }
submenu_add_item( submenu_add_item(
submenu, submenu,
furi_string_get_cstr(state->menu_item_name[i]), furi_string_get_cstr(protocol_string),
i, i,
lfrfid_scene_save_type_submenu_callback, lfrfid_scene_save_type_submenu_callback,
app); app);
} }
furi_string_free(protocol_string);
submenu_set_selected_item( submenu_set_selected_item(
submenu, scene_manager_get_scene_state(app->scene_manager, LfRfidSceneSaveType)); 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); 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; uint32_t line_sel = state->line_sel;
free(state); free(state);
scene_manager_set_scene_state(app->scene_manager, LfRfidSceneSaveType, line_sel); scene_manager_set_scene_state(app->scene_manager, LfRfidSceneSaveType, line_sel);
} }

View File

@ -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_icon_element(widget, 0, 3, &I_NFC_dolphin_emulation_47x61);
widget_add_string_element(widget, 57, 13, AlignLeft, AlignTop, FontPrimary, "Emulating UID"); 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); furi_string_printf(info_str, "%s", nfc->dev->dev_name);
} else { } else {
for(uint8_t i = 0; i < data->uid_len; i++) { for(uint8_t i = 0; i < data->uid_len; i++) {

View File

@ -43,7 +43,7 @@ bool nfc_scene_extra_actions_on_event(void* context, SceneManagerEvent event) {
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubmenuIndexMfClassicKeys) { 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); scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicKeys);
} else { } else {
scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound); scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound);

View File

@ -53,10 +53,10 @@ static void nfc_scene_mf_classic_dict_attack_prepare_view(Nfc* nfc, DictAttackSt
// Setup view // Setup view
if(state == DictAttackStateUserDictInProgress) { if(state == DictAttackStateUserDictInProgress) {
worker_state = NfcWorkerStateMfClassicDictAttack; 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); 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) { if(!dict) {
FURI_LOG_E(TAG, "User dictionary not found"); FURI_LOG_E(TAG, "User dictionary not found");
state = DictAttackStateFlipperDictInProgress; state = DictAttackStateFlipperDictInProgress;
@ -64,11 +64,11 @@ static void nfc_scene_mf_classic_dict_attack_prepare_view(Nfc* nfc, DictAttackSt
} }
if(state == DictAttackStateFlipperDictInProgress) { if(state == DictAttackStateFlipperDictInProgress) {
worker_state = NfcWorkerStateMfClassicDictAttack; worker_state = NfcWorkerStateMfClassicDictAttack;
dict_attack_set_header(nfc->dict_attack, "Mf Classic Flipper Dict."); dict_attack_set_header(nfc->dict_attack, "MF Classic System Dictionary");
dict = mf_classic_dict_alloc(MfClassicDictTypeFlipper); dict = mf_classic_dict_alloc(MfClassicDictTypeSystem);
if(!dict) { if(!dict) {
FURI_LOG_E(TAG, "Flipper dictionary not found"); 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 // Free previous dictionary
@ -153,6 +153,15 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent
nfc_worker_stop(nfc->worker); nfc_worker_stop(nfc->worker);
consumed = true; 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) { } else if(event.type == SceneManagerEventTypeBack) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm);

View File

@ -18,7 +18,7 @@ void nfc_scene_mf_classic_emulate_on_enter(void* context) {
// Setup view // Setup view
Popup* popup = nfc->popup; Popup* popup = nfc->popup;
popup_set_header(popup, "Emulating", 67, 13, AlignLeft, AlignTop); 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); nfc_text_store_set(nfc, "%s", nfc->dev->dev_name);
} else { } else {
nfc_text_store_set(nfc, "MIFARE\nClassic"); nfc_text_store_set(nfc, "MIFARE\nClassic");

View File

@ -12,7 +12,7 @@ void nfc_scene_mf_classic_keys_on_enter(void* context) {
// Load flipper dict keys total // Load flipper dict keys total
uint32_t flipper_dict_keys_total = 0; uint32_t flipper_dict_keys_total = 0;
MfClassicDict* dict = mf_classic_dict_alloc(MfClassicDictTypeFlipper); MfClassicDict* dict = mf_classic_dict_alloc(MfClassicDictTypeSystem);
if(dict) { if(dict) {
flipper_dict_keys_total = mf_classic_dict_get_total_keys(dict); flipper_dict_keys_total = mf_classic_dict_get_total_keys(dict);
mf_classic_dict_free(dict); mf_classic_dict_free(dict);
@ -26,11 +26,11 @@ void nfc_scene_mf_classic_keys_on_enter(void* context) {
} }
widget_add_string_element( 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]; 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); 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_string_element(nfc->widget, 0, 32, AlignLeft, AlignTop, FontSecondary, temp_str);
widget_add_button_element( widget_add_button_element(
nfc->widget, GuiButtonTypeCenter, "Add", nfc_scene_mf_classic_keys_widget_callback, nfc); nfc->widget, GuiButtonTypeCenter, "Add", nfc_scene_mf_classic_keys_widget_callback, nfc);

View File

@ -27,7 +27,7 @@ void nfc_scene_mf_classic_keys_list_prepare(Nfc* nfc, MfClassicDict* dict) {
char* current_key = (char*)malloc(sizeof(char) * 13); char* current_key = (char*)malloc(sizeof(char) * 13);
strncpy(current_key, furi_string_get_cstr(temp_key), 12); strncpy(current_key, furi_string_get_cstr(temp_key), 12);
MfClassicUserKeys_push_back(nfc->mfc_key_strs, current_key); 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_add_item(
submenu, current_key, index++, nfc_scene_mf_classic_keys_list_submenu_callback, nfc); submenu, current_key, index++, nfc_scene_mf_classic_keys_list_submenu_callback, nfc);
} }

View File

@ -51,23 +51,18 @@ void nfc_scene_mf_desfire_app_on_enter(void* context) {
nfc_scene_mf_desfire_app_submenu_callback, nfc_scene_mf_desfire_app_submenu_callback,
nfc); nfc);
uint16_t cap = NFC_TEXT_STORE_SIZE; FuriString* label = furi_string_alloc();
char* buf = nfc->text_store;
int idx = SubmenuIndexDynamic; int idx = SubmenuIndexDynamic;
for(MifareDesfireFile* file = app->file_head; file; file = file->next) { for(MifareDesfireFile* file = app->file_head; file; file = file->next) {
int size = snprintf(buf, cap, "File %d", file->id); furi_string_printf(label, "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;
submenu_add_item( 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); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
} }

View File

@ -33,21 +33,18 @@ void nfc_scene_mf_desfire_data_on_enter(void* context) {
nfc_scene_mf_desfire_data_submenu_callback, nfc_scene_mf_desfire_data_submenu_callback,
nfc); nfc);
uint16_t cap = NFC_TEXT_STORE_SIZE; FuriString* label = furi_string_alloc();
char* buf = nfc->text_store;
int idx = SubmenuIndexDynamic; int idx = SubmenuIndexDynamic;
for(MifareDesfireApplication* app = data->app_head; app; app = app->next) { 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]); furi_string_printf(label, "App %02x%02x%02x", app->id[0], app->id[1], app->id[2]);
if(size < 0 || size >= cap) { submenu_add_item(
FURI_LOG_W( submenu,
TAG, "Exceeded NFC_TEXT_STORE_SIZE when preparing app id strings; menu truncated"); furi_string_get_cstr(label),
break; idx++,
} nfc_scene_mf_desfire_data_submenu_callback,
char* label = buf; nfc);
cap -= size + 1;
buf += size + 1;
submenu_add_item(submenu, label, idx++, nfc_scene_mf_desfire_data_submenu_callback, nfc);
} }
furi_string_free(label);
if(state >= MifareDesfireDataStateItem) { if(state >= MifareDesfireDataStateItem) {
submenu_set_selected_item( submenu_set_selected_item(

View File

@ -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]); 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; 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) { if(data->version.sw_storage & 1) {
furi_string_push_back(temp_str, '+'); 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_apps = 0;
uint16_t n_files = 0; uint16_t n_files = 0;

View File

@ -21,7 +21,7 @@ void nfc_scene_mf_ultralight_emulate_on_enter(void* context) {
(type == MfUltralightTypeUnknown); (type == MfUltralightTypeUnknown);
Popup* popup = nfc->popup; Popup* popup = nfc->popup;
popup_set_header(popup, "Emulating", 67, 13, AlignLeft, AlignTop); 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); nfc_text_store_set(nfc, "%s", nfc->dev->dev_name);
} else if(is_ultralight) { } else if(is_ultralight) {
nfc_text_store_set(nfc, "MIFARE\nUltralight"); nfc_text_store_set(nfc, "MIFARE\nUltralight");

View File

@ -57,13 +57,13 @@ void nfc_scene_nfc_data_info_on_enter(void* context) {
// Set application specific data // Set application specific data
if(protocol == NfcDeviceProtocolMifareDesfire) { if(protocol == NfcDeviceProtocolMifareDesfire) {
MifareDesfireData* data = &dev_data->mf_df_data; 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; 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) { if(data->version.sw_storage & 1) {
furi_string_push_back(temp_str, '+'); 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_apps = 0;
uint16_t n_files = 0; uint16_t n_files = 0;

View File

@ -71,7 +71,7 @@ bool nfc_scene_read_on_event(void* context, SceneManagerEvent event) {
} else if(event.event == NfcWorkerEventReadMfUltralight) { } else if(event.event == NfcWorkerEventReadMfUltralight) {
notification_message(nfc->notifications, &sequence_success); notification_message(nfc->notifications, &sequence_success);
// Set unlock password input to 0xFFFFFFFF only on fresh read // 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); scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadSuccess);
DOLPHIN_DEED(DolphinDeedNfcReadSuccess); DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
consumed = true; consumed = true;
@ -91,7 +91,7 @@ bool nfc_scene_read_on_event(void* context, SceneManagerEvent event) {
DOLPHIN_DEED(DolphinDeedNfcReadSuccess); DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
consumed = true; consumed = true;
} else if(event.event == NfcWorkerEventReadMfClassicDictAttackRequired) { } 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); scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicDictAttack);
} else { } else {
scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound); scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound);

View File

@ -55,7 +55,7 @@ bool nfc_scene_save_name_on_event(void* context, SceneManagerEvent event) {
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
if(event.event == NfcCustomEventTextInputDone) { if(event.event == NfcCustomEventTextInputDone) {
if(strcmp(nfc->dev->dev_name, "")) { if(strcmp(nfc->dev->dev_name, "") != 0) {
nfc_device_delete(nfc->dev, true); nfc_device_delete(nfc->dev, true);
} }
if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetUid)) { if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetUid)) {

View File

@ -7,7 +7,7 @@ enum SubmenuIndex {
SubmenuIndexDetectReader, SubmenuIndexDetectReader,
SubmenuIndexSaved, SubmenuIndexSaved,
SubmenuIndexExtraAction, SubmenuIndexExtraAction,
SubmenuIndexAddManualy, SubmenuIndexAddManually,
SubmenuIndexDebug, SubmenuIndexDebug,
}; };
@ -28,7 +28,7 @@ void nfc_scene_start_on_enter(void* context) {
submenu_add_item( submenu_add_item(
submenu, "Extra Actions", SubmenuIndexExtraAction, nfc_scene_start_submenu_callback, nfc); submenu, "Extra Actions", SubmenuIndexExtraAction, nfc_scene_start_submenu_callback, nfc);
submenu_add_item( 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)) { if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
submenu_add_item( submenu_add_item(
@ -68,7 +68,7 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) {
} else if(event.event == SubmenuIndexExtraAction) { } else if(event.event == SubmenuIndexExtraAction) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneExtraActions); scene_manager_next_scene(nfc->scene_manager, NfcSceneExtraActions);
consumed = true; consumed = true;
} else if(event.event == SubmenuIndexAddManualy) { } else if(event.event == SubmenuIndexAddManually) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneSetType); scene_manager_next_scene(nfc->scene_manager, NfcSceneSetType);
consumed = true; consumed = true;
} else if(event.event == SubmenuIndexDebug) { } else if(event.event == SubmenuIndexDebug) {

View File

@ -24,6 +24,8 @@ typedef struct {
uint8_t keys_found; uint8_t keys_found;
uint16_t dict_keys_total; uint16_t dict_keys_total;
uint16_t dict_keys_current; uint16_t dict_keys_current;
bool is_key_attack;
uint8_t key_attack_current_sector;
} DictAttackViewModel; } DictAttackViewModel;
static void dict_attack_draw_callback(Canvas* canvas, void* model) { 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."); canvas, 64, 23, AlignCenter, AlignTop, "Make sure the tag is\npositioned correctly.");
} else if(m->state == DictAttackStateRead) { } else if(m->state == DictAttackStateRead) {
char draw_str[32] = {}; 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_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 ? float dict_progress = m->dict_keys_total == 0 ?
0 : 0 :
(float)(m->dict_keys_current) / (float)(m->dict_keys_total); (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) { if(progress > 1.0) {
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); canvas_set_font(canvas, FontSecondary);
snprintf(draw_str, sizeof(draw_str), "Keys found: %d/%d", m->keys_found, m->keys_total); snprintf(draw_str, sizeof(draw_str), "Keys found: %d/%d", m->keys_found, m->keys_total);
canvas_draw_str_aligned(canvas, 1, 28, AlignLeft, AlignTop, draw_str); canvas_draw_str_aligned(canvas, 0, 33, AlignLeft, AlignTop, draw_str);
snprintf( snprintf(
draw_str, sizeof(draw_str), "Sectors Read: %d/%d", m->sectors_read, m->sectors_total); 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"); elements_button_center(canvas, "Skip");
} }
@ -113,6 +131,7 @@ void dict_attack_reset(DictAttack* dict_attack) {
model->keys_found = 0; model->keys_found = 0;
model->dict_keys_total = 0; model->dict_keys_total = 0;
model->dict_keys_current = 0; model->dict_keys_current = 0;
model->is_key_attack = false;
furi_string_reset(model->header); furi_string_reset(model->header);
}, },
false); false);
@ -235,3 +254,28 @@ void dict_attack_inc_current_dict_key(DictAttack* dict_attack, uint16_t keys_tri
}, },
true); 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);
}

View File

@ -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_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_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);

View File

@ -2,6 +2,7 @@
#include <lib/drivers/cc1101.h> #include <lib/drivers/cc1101.h>
#include <furi.h> #include <furi.h>
#include <float_tools.h>
#define TAG "SubghzFrequencyAnalyzerWorker" #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; rssi_temp = (rssi_temp + frequency_rssi.rssi_fine) / 2;
frequency_temp = frequency_rssi.frequency_fine; frequency_temp = frequency_rssi.frequency_fine;
if(instance->filVal) { if(!float_is_equal(instance->filVal, 0.f)) {
frequency_rssi.frequency_fine = frequency_rssi.frequency_fine =
subghz_frequency_analyzer_worker_expRunningAverageAdaptive( subghz_frequency_analyzer_worker_expRunningAverageAdaptive(
instance, frequency_rssi.frequency_fine); instance, frequency_rssi.frequency_fine);
@ -219,7 +220,7 @@ static int32_t subghz_frequency_analyzer_worker_thread(void* context) {
instance->sample_hold_counter = 20; instance->sample_hold_counter = 20;
rssi_temp = (rssi_temp + frequency_rssi.rssi_coarse) / 2; rssi_temp = (rssi_temp + frequency_rssi.rssi_coarse) / 2;
frequency_temp = frequency_rssi.frequency_coarse; frequency_temp = frequency_rssi.frequency_coarse;
if(instance->filVal) { if(!float_is_equal(instance->filVal, 0.f)) {
frequency_rssi.frequency_coarse = frequency_rssi.frequency_coarse =
subghz_frequency_analyzer_worker_expRunningAverageAdaptive( subghz_frequency_analyzer_worker_expRunningAverageAdaptive(
instance, frequency_rssi.frequency_coarse); instance, frequency_rssi.frequency_coarse);

View File

@ -23,3 +23,4 @@ ADD_SCENE(subghz, more_raw, MoreRAW)
ADD_SCENE(subghz, delete_raw, DeleteRAW) ADD_SCENE(subghz, delete_raw, DeleteRAW)
ADD_SCENE(subghz, need_saving, NeedSaving) ADD_SCENE(subghz, need_saving, NeedSaving)
ADD_SCENE(subghz, rpc, Rpc) ADD_SCENE(subghz, rpc, Rpc)
ADD_SCENE(subghz, region_info, RegionInfo)

View File

@ -3,6 +3,7 @@
#include <dolphin/dolphin.h> #include <dolphin/dolphin.h>
#include <lib/subghz/protocols/raw.h> #include <lib/subghz/protocols/raw.h>
#include <lib/toolbox/path.h> #include <lib/toolbox/path.h>
#include <float_tools.h>
#define RAW_FILE_NAME "Raw_signal_" #define RAW_FILE_NAME "Raw_signal_"
#define TAG "SubGhzSceneReadRAW" #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(); 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_read_raw_add_data_rssi(subghz->subghz_read_raw, rssi, true);
subghz_protocol_raw_save_to_file_pause( subghz_protocol_raw_save_to_file_pause(
(SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result, false); (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result, false);

View 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);
}

View File

@ -94,7 +94,7 @@ bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) {
return true; return true;
} else if(event.type == SceneManagerEventTypeCustom) { } else if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubGhzCustomEventSceneSaveName) { if(event.event == SubGhzCustomEventSceneSaveName) {
if(strcmp(subghz->file_name_tmp, "")) { if(strcmp(subghz->file_name_tmp, "") != 0) {
furi_string_cat_printf( furi_string_cat_printf(
subghz->file_path, "/%s%s", subghz->file_name_tmp, SUBGHZ_APP_EXTENSION); subghz->file_path, "/%s%s", subghz->file_name_tmp, SUBGHZ_APP_EXTENSION);
if(subghz_path_is_file(subghz->file_path_tmp)) { if(subghz_path_is_file(subghz->file_path_tmp)) {

View File

@ -46,7 +46,7 @@ bool subghz_scene_set_type_submenu_gen_data_protocol(
uint8_t key_data[sizeof(uint64_t)] = {0}; uint8_t key_data[sizeof(uint64_t)] = {0};
for(size_t i = 0; i < sizeof(uint64_t); i++) { 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))) { if(!flipper_format_update_hex(subghz->txrx->fff_data, "Key", key_data, sizeof(uint64_t))) {
FURI_LOG_E(TAG, "Unable to update Key"); FURI_LOG_E(TAG, "Unable to update Key");

View File

@ -5,9 +5,10 @@ enum SubmenuIndex {
SubmenuIndexRead = 10, SubmenuIndexRead = 10,
SubmenuIndexSaved, SubmenuIndexSaved,
SubmenuIndexTest, SubmenuIndexTest,
SubmenuIndexAddManualy, SubmenuIndexAddManually,
SubmenuIndexFrequencyAnalyzer, SubmenuIndexFrequencyAnalyzer,
SubmenuIndexReadRAW, SubmenuIndexReadRAW,
SubmenuIndexShowRegionInfo
}; };
void subghz_scene_start_submenu_callback(void* context, uint32_t index) { 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( submenu_add_item(
subghz->submenu, subghz->submenu,
"Add Manually", "Add Manually",
SubmenuIndexAddManualy, SubmenuIndexAddManually,
subghz_scene_start_submenu_callback, subghz_scene_start_submenu_callback,
subghz); subghz);
submenu_add_item( submenu_add_item(
@ -42,6 +43,12 @@ void subghz_scene_start_on_enter(void* context) {
SubmenuIndexFrequencyAnalyzer, SubmenuIndexFrequencyAnalyzer,
subghz_scene_start_submenu_callback, subghz_scene_start_submenu_callback,
subghz); subghz);
submenu_add_item(
subghz->submenu,
"Region Information",
SubmenuIndexShowRegionInfo,
subghz_scene_start_submenu_callback,
subghz);
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
submenu_add_item( submenu_add_item(
subghz->submenu, "Test", SubmenuIndexTest, subghz_scene_start_submenu_callback, subghz); 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); subghz->scene_manager, SubGhzSceneStart, SubmenuIndexSaved);
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaved); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaved);
return true; return true;
} else if(event.event == SubmenuIndexAddManualy) { } else if(event.event == SubmenuIndexAddManually) {
scene_manager_set_scene_state( scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneStart, SubmenuIndexAddManualy); subghz->scene_manager, SubGhzSceneStart, SubmenuIndexAddManually);
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetType); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetType);
return true; return true;
} else if(event.event == SubmenuIndexFrequencyAnalyzer) { } else if(event.event == SubmenuIndexFrequencyAnalyzer) {
@ -92,6 +99,11 @@ bool subghz_scene_start_on_event(void* context, SceneManagerEvent event) {
subghz->scene_manager, SubGhzSceneStart, SubmenuIndexTest); subghz->scene_manager, SubGhzSceneStart, SubmenuIndexTest);
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneTest); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneTest);
return true; 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; return false;

View File

@ -152,11 +152,11 @@ void subghz_cli_command_tx(Cli* cli, FuriString* args, void* context) {
"Protocol: Princeton\n" "Protocol: Princeton\n"
"Bit: 24\n" "Bit: 24\n"
"Key: 00 00 00 00 00 %02X %02X %02X\n" "Key: 00 00 00 00 00 %02X %02X %02X\n"
"TE: %ld\n" "TE: %lu\n"
"Repeat: %ld\n", "Repeat: %lu\n",
(uint8_t)((key >> 16) & 0xFF), (uint8_t)((key >> 16) & 0xFFU),
(uint8_t)((key >> 8) & 0xFF), (uint8_t)((key >> 8) & 0xFFU),
(uint8_t)(key & 0xFF), (uint8_t)(key & 0xFFU),
te, te,
repeat); repeat);
FlipperFormat* flipper_format = flipper_format_string_alloc(); 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(); 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 // Cleanup
subghz_receiver_free(receiver); subghz_receiver_free(receiver);
@ -787,8 +787,9 @@ static bool subghz_on_system_start_istream_decode_band(
} }
region->bands_count += 1; region->bands_count += 1;
region = region = realloc( //-V701
realloc(region, sizeof(FuriHalRegion) + sizeof(FuriHalRegionBand) * region->bands_count); region,
sizeof(FuriHalRegion) + sizeof(FuriHalRegionBand) * region->bands_count);
size_t pos = region->bands_count - 1; size_t pos = region->bands_count - 1;
region->bands[pos].start = band.start; region->bands[pos].start = band.start;
region->bands[pos].end = band.end; region->bands[pos].end = band.end;
@ -798,7 +799,7 @@ static bool subghz_on_system_start_istream_decode_band(
FURI_LOG_I( FURI_LOG_I(
"SubGhzOnStart", "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.start,
band.end, band.end,
band.power_limit, band.power_limit,

View File

@ -164,7 +164,7 @@ bool subghz_tx_start(SubGhz* subghz, FlipperFormat* flipper_format) {
if(subghz->txrx->transmitter) { if(subghz->txrx->transmitter) {
if(subghz_transmitter_deserialize(subghz->txrx->transmitter, flipper_format)) { 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_begin(
subghz, subghz,
subghz_setting_get_preset_data_by_name( subghz_setting_get_preset_data_by_name(
@ -544,11 +544,8 @@ void subghz_hopper_update(SubGhz* subghz) {
switch(subghz->txrx->hopper_state) { switch(subghz->txrx->hopper_state) {
case SubGhzHopperStateOFF: case SubGhzHopperStateOFF:
return;
break;
case SubGhzHopperStatePause: case SubGhzHopperStatePause:
return; return;
break;
case SubGhzHopperStateRSSITimeOut: case SubGhzHopperStateRSSITimeOut:
if(subghz->txrx->hopper_timeout != 0) { if(subghz->txrx->hopper_timeout != 0) {
subghz->txrx->hopper_timeout--; subghz->txrx->hopper_timeout--;

View File

@ -11,6 +11,7 @@
#include "../helpers/subghz_frequency_analyzer_log_item_array.h" #include "../helpers/subghz_frequency_analyzer_log_item_array.h"
#include <assets_icons.h> #include <assets_icons.h>
#include <float_tools.h>
#define LOG_FREQUENCY_MAX_ITEMS 60 // uint8_t (limited by 'seq' of SubGhzFrequencyAnalyzerLogItem) #define LOG_FREQUENCY_MAX_ITEMS 60 // uint8_t (limited by 'seq' of SubGhzFrequencyAnalyzerLogItem)
@ -47,7 +48,8 @@ typedef struct {
} SubGhzFrequencyAnalyzerModel; } SubGhzFrequencyAnalyzerModel;
static inline uint8_t rssi_sanitize(float rssi) { 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( 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) { if(items_count < LOG_FREQUENCY_MAX_ITEMS) {
SubGhzFrequencyAnalyzerLogItem_t* item = SubGhzFrequencyAnalyzerLogItem_t* item =
SubGhzFrequencyAnalyzerLogItemArray_push_new(model->log_frequency); SubGhzFrequencyAnalyzerLogItemArray_push_new(model->log_frequency);
if(item == NULL) {
return false;
}
(*item)->frequency = model->frequency; (*item)->frequency = model->frequency;
(*item)->count = 1; (*item)->count = 1;
(*item)->rssi_max = model->rssi; (*item)->rssi_max = model->rssi;
@ -340,7 +339,7 @@ void subghz_frequency_analyzer_pair_callback(
float rssi, float rssi,
bool signal) { bool signal) {
SubGhzFrequencyAnalyzer* instance = context; SubGhzFrequencyAnalyzer* instance = context;
if((rssi == 0.f) && (instance->locked)) { if(float_is_equal(rssi, 0.f) && instance->locked) {
if(instance->callback) { if(instance->callback) {
instance->callback(SubGhzCustomEventSceneAnalyzerUnlock, instance->context); instance->callback(SubGhzCustomEventSceneAnalyzerUnlock, instance->context);
} }
@ -355,13 +354,13 @@ void subghz_frequency_analyzer_pair_callback(
model->history_frequency[0] = model->frequency; model->history_frequency[0] = model->frequency;
}, },
false); false);
} else if((rssi != 0.f) && (!instance->locked)) { } else if(!float_is_equal(rssi, 0.f) && !instance->locked) {
if(instance->callback) { if(instance->callback) {
instance->callback(SubGhzCustomEventSceneAnalyzerLock, instance->context); instance->callback(SubGhzCustomEventSceneAnalyzerLock, instance->context);
} }
} }
instance->locked = (rssi != 0.f); instance->locked = !float_is_equal(rssi, 0.f);
with_view_model( with_view_model(
instance->view, instance->view,
SubGhzFrequencyAnalyzerModel * model, SubGhzFrequencyAnalyzerModel * model,

View File

@ -91,7 +91,7 @@ void subghz_read_raw_update_sample_write(SubGhzReadRAW* instance, size_t sample)
with_view_model( with_view_model(
instance->view, instance->view,
SubGhzReadRAWModel * model, SubGhzReadRAWModel * model,
{ furi_string_printf(model->sample_write, "%d spl.", sample); }, { furi_string_printf(model->sample_write, "%zu spl.", sample); },
false); false);
} }
@ -161,7 +161,7 @@ void subghz_read_raw_draw_sin(Canvas* canvas, SubGhzReadRAWModel* model) {
canvas_draw_line( canvas_draw_line(
canvas, canvas,
i + 1, 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, i + 2,
32 + subghz_read_raw_tab_sin((i + model->ind_sin * 16 + 1) * 2) / 32 + subghz_read_raw_tab_sin((i + model->ind_sin * 16 + 1) * 2) /
SUBGHZ_RAW_SIN_AMPLITUDE); SUBGHZ_RAW_SIN_AMPLITUDE);

View File

@ -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); snprintf(buffer, sizeof(buffer), "Path: %d - %s", model->path, path_name);
canvas_draw_str(canvas, 0, 31, buffer); 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); canvas_draw_str(canvas, 0, 42, buffer);
if(model->status == SubGhzTestPacketModelStatusRx) { if(model->status == SubGhzTestPacketModelStatusRx) {

View File

@ -58,7 +58,7 @@ bool u2f_scene_main_on_event(void* context, SceneManagerEvent event) {
app->event_cur = event.event; app->event_cur = event.event;
if(event.event == U2fCustomEventRegister) if(event.event == U2fCustomEventRegister)
u2f_view_set_state(app->u2f_view, U2fMsgRegister); 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); u2f_view_set_state(app->u2f_view, U2fMsgAuth);
notification_message(app->notifications, &sequence_display_backlight_on); notification_message(app->notifications, &sequence_display_backlight_on);
notification_message(app->notifications, &sequence_single_vibro); notification_message(app->notifications, &sequence_single_vibro);

View File

@ -402,9 +402,9 @@ bool u2f_data_cnt_read(uint32_t* cnt_val) {
FURI_LOG_E(TAG, "Unable to load encryption key"); FURI_LOG_E(TAG, "Unable to load encryption key");
break; break;
} }
memset(&cnt, 0, 32); memset(&cnt, 0, sizeof(U2fCounterData));
if(!furi_hal_crypto_decrypt(cnt_encr, (uint8_t*)&cnt, 32)) { if(!furi_hal_crypto_decrypt(cnt_encr, (uint8_t*)&cnt, sizeof(U2fCounterData))) {
memset(&cnt, 0, 32); memset(&cnt, 0, sizeof(U2fCounterData));
FURI_LOG_E(TAG, "Decryption failed"); FURI_LOG_E(TAG, "Decryption failed");
break; break;
} }

View File

@ -94,7 +94,7 @@ static void u2f_hid_send_response(U2fHid* u2f_hid) {
uint16_t data_ptr = 0; uint16_t data_ptr = 0;
memset(packet_buf, 0, HID_U2F_PACKET_LEN); 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 // Init packet
packet_buf[4] = u2f_hid->packet.cmd; packet_buf[4] = u2f_hid->packet.cmd;
@ -166,7 +166,7 @@ static bool u2f_hid_parse_request(U2fHid* u2f_hid) {
return false; return false;
u2f_hid->packet.len = 17; u2f_hid->packet.len = 17;
uint32_t random_cid = furi_hal_random_get(); 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[12] = 2; // Protocol version
u2f_hid->packet.payload[13] = 1; // Device version major u2f_hid->packet.payload[13] = 1; // Device version major
u2f_hid->packet.payload[14] = 0; // Device version minor 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 } else if(u2f_hid->packet.cmd == U2F_HID_WINK) { // WINK - notify user
if(u2f_hid->packet.len != 0) return false; if(u2f_hid->packet.len != 0) return false;
u2f_wink(u2f_hid->u2f_instance); u2f_wink(u2f_hid->u2f_instance);
u2f_hid->packet.len = 0; u2f_hid->packet.len = 0; //-V1048
u2f_hid_send_response(u2f_hid); u2f_hid_send_response(u2f_hid);
} else } else
return false; return false;

View File

@ -568,12 +568,12 @@ void dap_common_usb_set_state_callback(DapStateCallback callback) {
static void* dap_usb_alloc_string_descr(const char* str) { static void* dap_usb_alloc_string_descr(const char* str) {
furi_assert(str); furi_assert(str);
uint8_t len = strlen(str); size_t len = strlen(str);
uint8_t wlen = (len + 1) * sizeof(uint16_t); size_t wlen = (len + 1) * sizeof(uint16_t);
struct usb_string_descriptor* dev_str_desc = malloc(wlen); struct usb_string_descriptor* dev_str_desc = malloc(wlen);
dev_str_desc->bLength = wlen; dev_str_desc->bLength = wlen;
dev_str_desc->bDescriptorType = USB_DTYPE_STRING; 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]; dev_str_desc->wString[i] = str[i];
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 657 B

View File

@ -42,11 +42,13 @@ static void bt_hid_connection_status_changed_callback(BtStatus status, void* con
furi_assert(context); furi_assert(context);
Hid* hid = context; Hid* hid = context;
bool connected = (status == BtStatusConnected); bool connected = (status == BtStatusConnected);
if(hid->transport == HidTransportBle) {
if(connected) { if(connected) {
notification_internal_message(hid->notifications, &sequence_set_blue_255); notification_internal_message(hid->notifications, &sequence_set_blue_255);
} else { } else {
notification_internal_message(hid->notifications, &sequence_reset_blue); notification_internal_message(hid->notifications, &sequence_reset_blue);
} }
}
hid_keynote_set_connected_status(hid->hid_keynote, connected); hid_keynote_set_connected_status(hid->hid_keynote, connected);
hid_keyboard_set_connected_status(hid->hid_keyboard, connected); hid_keyboard_set_connected_status(hid->hid_keyboard, connected);
hid_media_set_connected_status(hid->hid_media, connected); hid_media_set_connected_status(hid->hid_media, connected);
@ -186,7 +188,9 @@ void hid_free(Hid* app) {
furi_assert(app); furi_assert(app);
// Reset notification // Reset notification
if(app->transport == HidTransportBle) {
notification_internal_message(app->notifications, &sequence_reset_blue); notification_internal_message(app->notifications, &sequence_reset_blue);
}
// Free views // Free views
view_dispatcher_remove_view(app->view_dispatcher, HidViewSubmenu); view_dispatcher_remove_view(app->view_dispatcher, HidViewSubmenu);

View File

@ -25,6 +25,7 @@ typedef struct {
bool back_pressed; bool back_pressed;
bool connected; bool connected;
char key_string[5]; char key_string[5];
HidTransport transport;
} HidKeyboardModel; } HidKeyboardModel;
typedef struct { typedef struct {
@ -207,7 +208,7 @@ static void hid_keyboard_draw_callback(Canvas* canvas, void* context) {
HidKeyboardModel* model = context; HidKeyboardModel* model = context;
// Header // Header
if(!model->connected) { if((!model->connected) && (model->transport == HidTransportBle)) {
canvas_draw_icon(canvas, 0, 0, &I_Ble_disconnected_15x15); canvas_draw_icon(canvas, 0, 0, &I_Ble_disconnected_15x15);
canvas_set_font(canvas, FontPrimary); canvas_set_font(canvas, FontPrimary);
elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "Keyboard"); 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) { static uint8_t hid_keyboard_get_selected_key(HidKeyboardModel* model) {
HidKeyboardKey key = hid_keyboard_keyset[model->y][model->x]; 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; return key.value;
} }
static void hid_keyboard_get_select_key(HidKeyboardModel* model, HidKeyboardPoint delta) { 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 // Keep going until a valid spot is found, this allows for nulls and zero width keys in the map
do { do {
if(((int8_t)model->y) + delta.y < 0) const int delta_sum = model->y + delta.y;
model->y = ROW_COUNT - 1; model->y = delta_sum < 0 ? ROW_COUNT - 1 : delta_sum % ROW_COUNT;
else
model->y = (model->y + delta.y) % ROW_COUNT;
} while(delta.y != 0 && hid_keyboard_keyset[model->y][model->x].value == 0); } while(delta.y != 0 && hid_keyboard_keyset[model->y][model->x].value == 0);
do { do {
if(((int8_t)model->x) + delta.x < 0) const int delta_sum = model->x + delta.x;
model->x = COLUMN_COUNT - 1; model->x = delta_sum < 0 ? COLUMN_COUNT - 1 : delta_sum % COLUMN_COUNT;
else
model->x = (model->x + delta.x) % COLUMN_COUNT;
} while(delta.x != 0 && hid_keyboard_keyset[model->y][model->x].width == } while(delta.x != 0 && hid_keyboard_keyset[model->y][model->x].width ==
0); // Skip zero width keys, pretend they are one key 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_draw_callback(hid_keyboard->view, hid_keyboard_draw_callback);
view_set_input_callback(hid_keyboard->view, hid_keyboard_input_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; return hid_keyboard;
} }

View File

@ -19,6 +19,7 @@ typedef struct {
bool ok_pressed; bool ok_pressed;
bool back_pressed; bool back_pressed;
bool connected; bool connected;
HidTransport transport;
} HidKeynoteModel; } HidKeynoteModel;
static void hid_keynote_draw_arrow(Canvas* canvas, uint8_t x, uint8_t y, CanvasDirection dir) { 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; HidKeynoteModel* model = context;
// Header // Header
if(model->transport == HidTransportBle) {
if(model->connected) { if(model->connected) {
canvas_draw_icon(canvas, 0, 0, &I_Ble_connected_15x15); canvas_draw_icon(canvas, 0, 0, &I_Ble_connected_15x15);
} else { } else {
canvas_draw_icon(canvas, 0, 0, &I_Ble_disconnected_15x15); canvas_draw_icon(canvas, 0, 0, &I_Ble_disconnected_15x15);
} }
}
canvas_set_font(canvas, FontPrimary); canvas_set_font(canvas, FontPrimary);
elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "Keynote"); 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_draw_callback(hid_keynote->view, hid_keynote_draw_callback);
view_set_input_callback(hid_keynote->view, hid_keynote_input_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; return hid_keynote;
} }

View File

@ -21,6 +21,7 @@ typedef struct {
bool down_pressed; bool down_pressed;
bool ok_pressed; bool ok_pressed;
bool connected; bool connected;
HidTransport transport;
} HidMediaModel; } HidMediaModel;
static void hid_media_draw_arrow(Canvas* canvas, uint8_t x, uint8_t y, CanvasDirection dir) { 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; HidMediaModel* model = context;
// Header // Header
if(model->transport == HidTransportBle) {
if(model->connected) { if(model->connected) {
canvas_draw_icon(canvas, 0, 0, &I_Ble_connected_15x15); canvas_draw_icon(canvas, 0, 0, &I_Ble_connected_15x15);
} else { } else {
canvas_draw_icon(canvas, 0, 0, &I_Ble_disconnected_15x15); canvas_draw_icon(canvas, 0, 0, &I_Ble_disconnected_15x15);
} }
}
canvas_set_font(canvas, FontPrimary); canvas_set_font(canvas, FontPrimary);
elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "Media"); elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "Media");
canvas_set_font(canvas, FontSecondary); 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_draw_callback(hid_media->view, hid_media_draw_callback);
view_set_input_callback(hid_media->view, hid_media_input_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; return hid_media;
} }

View File

@ -20,6 +20,7 @@ typedef struct {
bool left_mouse_held; bool left_mouse_held;
bool right_mouse_pressed; bool right_mouse_pressed;
bool connected; bool connected;
HidTransport transport;
} HidMouseModel; } HidMouseModel;
static void hid_mouse_draw_callback(Canvas* canvas, void* context) { 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; HidMouseModel* model = context;
// Header // Header
if(model->transport == HidTransportBle) {
if(model->connected) { if(model->connected) {
canvas_draw_icon(canvas, 0, 0, &I_Ble_connected_15x15); canvas_draw_icon(canvas, 0, 0, &I_Ble_connected_15x15);
} else { } else {
canvas_draw_icon(canvas, 0, 0, &I_Ble_disconnected_15x15); canvas_draw_icon(canvas, 0, 0, &I_Ble_disconnected_15x15);
} }
}
canvas_set_font(canvas, FontPrimary); canvas_set_font(canvas, FontPrimary);
elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "Mouse"); elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "Mouse");
canvas_set_font(canvas, FontSecondary); 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_draw_callback(hid_mouse->view, hid_mouse_draw_callback);
view_set_input_callback(hid_mouse->view, hid_mouse_input_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; return hid_mouse;
} }

View File

@ -16,6 +16,7 @@ typedef struct {
bool connected; bool connected;
bool running; bool running;
uint8_t counter; uint8_t counter;
HidTransport transport;
} HidMouseJigglerModel; } HidMouseJigglerModel;
static void hid_mouse_jiggler_draw_callback(Canvas* canvas, void* context) { 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; HidMouseJigglerModel* model = context;
// Header // Header
if(model->transport == HidTransportBle) {
if(model->connected) { if(model->connected) {
canvas_draw_icon(canvas, 0, 0, &I_Ble_connected_15x15); canvas_draw_icon(canvas, 0, 0, &I_Ble_connected_15x15);
} else { } else {
canvas_draw_icon(canvas, 0, 0, &I_Ble_disconnected_15x15); canvas_draw_icon(canvas, 0, 0, &I_Ble_disconnected_15x15);
} }
}
canvas_set_font(canvas, FontPrimary); canvas_set_font(canvas, FontPrimary);
elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "Mouse Jiggler"); 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 = furi_timer_alloc(
hid_mouse_jiggler_timer_callback, FuriTimerTypePeriodic, hid_mouse_jiggler); 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; return hid_mouse_jiggler;
} }

View File

@ -19,6 +19,7 @@ typedef struct {
bool ok_pressed; bool ok_pressed;
bool connected; bool connected;
bool is_cursor_set; bool is_cursor_set;
HidTransport transport;
} HidTikTokModel; } HidTikTokModel;
static void hid_tiktok_draw_callback(Canvas* canvas, void* context) { 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; HidTikTokModel* model = context;
// Header // Header
if(model->transport == HidTransportBle) {
if(model->connected) { if(model->connected) {
canvas_draw_icon(canvas, 0, 0, &I_Ble_connected_15x15); canvas_draw_icon(canvas, 0, 0, &I_Ble_connected_15x15);
} else { } else {
canvas_draw_icon(canvas, 0, 0, &I_Ble_disconnected_15x15); canvas_draw_icon(canvas, 0, 0, &I_Ble_disconnected_15x15);
} }
}
canvas_set_font(canvas, FontPrimary); canvas_set_font(canvas, FontPrimary);
elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "TikTok"); elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "TikTok");
canvas_set_font(canvas, FontSecondary); 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_draw_callback(hid_tiktok->view, hid_tiktok_draw_callback);
view_set_input_callback(hid_tiktok->view, hid_tiktok_input_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; return hid_tiktok;
} }

View File

@ -180,7 +180,7 @@ static void render_callback(Canvas* canvas, void* ctx) {
// note stack view_port // note stack view_port
x_pos = 73; x_pos = 73;
y_pos = 0; y_pos = 0; //-V1048
canvas_set_color(canvas, ColorBlack); canvas_set_color(canvas, ColorBlack);
canvas_set_font(canvas, FontPrimary); canvas_set_font(canvas, FontPrimary);
canvas_draw_frame(canvas, x_pos, y_pos, 49, 64); canvas_draw_frame(canvas, x_pos, y_pos, 49, 64);

View File

@ -111,9 +111,9 @@ static void init_opt_select_LUT(void) {
***********************************************************************************/ ***********************************************************************************/
#define loclass_opt__select(x, y, r) \ #define loclass_opt__select(x, y, r) \
(4 & (((r & (r << 2)) >> 5) ^ ((r & ~(r << 2)) >> 4) ^ ((r | r << 2) >> 3))) | \ (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))) | \ (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)) (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) { static void loclass_opt_successor(const uint8_t* k, LoclassState_t* s, uint8_t y) {
uint16_t Tt = s->t & 0xc533; uint16_t Tt = s->t & 0xc533;
@ -149,30 +149,11 @@ static void loclass_opt_suc(
uint8_t length, uint8_t length,
bool add32Zeroes) { bool add32Zeroes) {
for(int i = 0; i < length; i++) { for(int i = 0; i < length; i++) {
uint8_t head; uint8_t head = in[i];
head = in[i]; for(int j = 0; j < 8; j++) {
loclass_opt_successor(k, s, head); loclass_opt_successor(k, s, head);
head >>= 1; 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 //For tag MAC, an additional 32 zeroes
if(add32Zeroes) { if(add32Zeroes) {

View File

@ -18,6 +18,9 @@
#define PICOPASS_CSN_BLOCK_INDEX 0 #define PICOPASS_CSN_BLOCK_INDEX 0
#define PICOPASS_CONFIG_BLOCK_INDEX 1 #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_AIA_BLOCK_INDEX 5
#define PICOPASS_APP_FOLDER ANY_PATH("picopass") #define PICOPASS_APP_FOLDER ANY_PATH("picopass")

View File

@ -143,7 +143,7 @@ ReturnCode picopass_read_preauth(PicopassBlock* AA1) {
AA1[PICOPASS_CSN_BLOCK_INDEX].data[7]); AA1[PICOPASS_CSN_BLOCK_INDEX].data[7]);
rfalPicoPassReadBlockRes cfg = {0}; 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)); memcpy(AA1[PICOPASS_CONFIG_BLOCK_INDEX].data, cfg.data, sizeof(cfg.data));
FURI_LOG_D( FURI_LOG_D(
TAG, TAG,
@ -158,7 +158,7 @@ ReturnCode picopass_read_preauth(PicopassBlock* AA1) {
AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[7]); AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[7]);
rfalPicoPassReadBlockRes aia; 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)); memcpy(AA1[PICOPASS_AIA_BLOCK_INDEX].data, aia.data, sizeof(aia.data));
FURI_LOG_D( FURI_LOG_D(
TAG, TAG,
@ -175,13 +175,12 @@ ReturnCode picopass_read_preauth(PicopassBlock* AA1) {
return ERR_NONE; return ERR_NONE;
} }
ReturnCode picopass_auth(PicopassBlock* AA1, PicopassPacs* pacs) { static ReturnCode picopass_auth_standard(uint8_t* csn, uint8_t* div_key) {
rfalPicoPassReadCheckRes rcRes; rfalPicoPassReadCheckRes rcRes;
rfalPicoPassCheckRes chkRes; rfalPicoPassCheckRes chkRes;
ReturnCode err; ReturnCode err;
uint8_t div_key[8] = {0};
uint8_t mac[4] = {0}; uint8_t mac[4] = {0};
uint8_t ccnr[12] = {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 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); loclass_opt_doReaderMAC(ccnr, div_key, mac);
err = rfalPicoPassPollerCheck(mac, &chkRes); return rfalPicoPassPollerCheck(mac, &chkRes);
if(err == ERR_NONE) {
return ERR_NONE;
} }
FURI_LOG_E(TAG, "rfalPicoPassPollerCheck error %d", err);
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; size_t index = 0;
uint8_t key[PICOPASS_BLOCK_LEN] = {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"); FURI_LOG_E(TAG, "Dictionary not found");
return ERR_PARAM; return ERR_PARAM;
} }
IclassEliteDict* dict = iclass_elite_dict_alloc(IclassEliteDictTypeFlipper); IclassEliteDict* dict = iclass_elite_dict_alloc(dict_type);
if(!dict) { if(!dict) {
FURI_LOG_E(TAG, "Dictionary not allocated"); FURI_LOG_E(TAG, "Dictionary not allocated");
return ERR_PARAM; return ERR_PARAM;
@ -221,7 +228,7 @@ ReturnCode picopass_auth(PicopassBlock* AA1, PicopassPacs* pacs) {
while(iclass_elite_dict_get_next_key(dict, key)) { while(iclass_elite_dict_get_next_key(dict, key)) {
FURI_LOG_D( FURI_LOG_D(
TAG, 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++, index++,
key[0], key[0],
key[1], key[1],
@ -235,11 +242,11 @@ ReturnCode picopass_auth(PicopassBlock* AA1, PicopassPacs* pacs) {
err = rfalPicoPassPollerReadCheck(&rcRes); err = rfalPicoPassPollerReadCheck(&rcRes);
if(err != ERR_NONE) { if(err != ERR_NONE) {
FURI_LOG_E(TAG, "rfalPicoPassPollerReadCheck error %d", err); FURI_LOG_E(TAG, "rfalPicoPassPollerReadCheck error %d", err);
return err; break;
} }
memcpy(ccnr, rcRes.CCNR, sizeof(rcRes.CCNR)); // last 4 bytes left 0 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); loclass_opt_doReaderMAC(ccnr, div_key, mac);
err = rfalPicoPassPollerCheck(mac, &chkRes); err = rfalPicoPassPollerCheck(mac, &chkRes);
@ -249,8 +256,39 @@ ReturnCode picopass_auth(PicopassBlock* AA1, PicopassPacs* pacs) {
} }
} }
if(dict) {
iclass_elite_dict_free(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; return err;
@ -264,6 +302,11 @@ ReturnCode picopass_read_card(PicopassBlock* AA1) {
PICOPASS_MAX_APP_LIMIT; PICOPASS_MAX_APP_LIMIT;
for(size_t i = 2; i < app_limit; i++) { 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; rfalPicoPassReadBlockRes block;
err = rfalPicoPassPollerReadBlock(i, &block); err = rfalPicoPassPollerReadBlock(i, &block);
if(err != ERR_NONE) { if(err != ERR_NONE) {

View File

@ -54,7 +54,7 @@ bool picopass_scene_save_name_on_event(void* context, SceneManagerEvent event) {
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
if(event.event == PicopassCustomEventTextInputDone) { if(event.event == PicopassCustomEventTextInputDone) {
if(strcmp(picopass->dev->dev_name, "")) { if(strcmp(picopass->dev->dev_name, "") != 0) {
// picopass_device_delete(picopass->dev, true); // picopass_device_delete(picopass->dev, true);
} }
strlcpy( strlcpy(

View File

@ -3,7 +3,7 @@ enum SubmenuIndex {
SubmenuIndexRead, SubmenuIndexRead,
SubmenuIndexRunScript, SubmenuIndexRunScript,
SubmenuIndexSaved, SubmenuIndexSaved,
SubmenuIndexAddManualy, SubmenuIndexAddManually,
SubmenuIndexDebug, SubmenuIndexDebug,
}; };

View File

@ -15,12 +15,12 @@ static void
app->pwm_freq = freq; app->pwm_freq = freq;
app->pwm_duty = duty; 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_prev = app->pwm_ch;
app->pwm_ch = pwm_ch_id[channel_id]; app->pwm_ch = pwm_ch_id[channel_id];
view_dispatcher_send_custom_event(app->view_dispatcher, SignalGenPwmEventChannelChange); view_dispatcher_send_custom_event(app->view_dispatcher, SignalGenPwmEventChannelChange);
} else { } 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); view_dispatcher_send_custom_event(app->view_dispatcher, SignalGenPwmEventUpdate);
} }
} }

View File

@ -127,12 +127,12 @@ static void signal_gen_pwm_draw_callback(Canvas* canvas, void* _model) {
char* line_label = NULL; char* line_label = NULL;
char val_text[16]; char val_text[16];
for(uint8_t line = 0; line < LineIndexTotalCount; line++) { for(size_t line = 0; line < LineIndexTotalCount; line++) {
if(line == LineIndexChannel) { if(line == LineIndexChannel) {
line_label = "GPIO Pin"; line_label = "GPIO Pin";
} else if(line == LineIndexFrequency) { } else if(line == LineIndexFrequency) {
line_label = "Frequency"; line_label = "Frequency";
} else if(line == LineIndexDuty) { } else if(line == LineIndexDuty) { //-V547
line_label = "Pulse width"; 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 - 9, &I_SmallArrowUp_3x5);
canvas_draw_icon(canvas, icon_x, text_y + 5, &I_SmallArrowDown_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); snprintf(val_text, sizeof(val_text), "%d%%", model->duty);
canvas_draw_str_aligned(canvas, VALUE_X, text_y, AlignCenter, AlignCenter, val_text); canvas_draw_str_aligned(canvas, VALUE_X, text_y, AlignCenter, AlignCenter, val_text);
if(model->duty != 0) { if(model->duty != 0) {

View File

@ -130,7 +130,7 @@ static void snake_game_render_callback(Canvas* const canvas, void* ctx) {
canvas_set_font(canvas, FontSecondary); canvas_set_font(canvas, FontSecondary);
char buffer[12]; 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); 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) { 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}}; 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; snake_state->len = 7;

View File

@ -343,7 +343,7 @@ bool ws_protocol_decoder_oregon2_deserialize(void* context, FlipperFormat* flipp
flipper_format, flipper_format,
"VarData", "VarData",
(uint8_t*)&instance->var_data, (uint8_t*)&instance->var_data,
sizeof(instance->var_data))) { sizeof(instance->var_data))) { //-V1051
FURI_LOG_E(TAG, "Missing VarData"); FURI_LOG_E(TAG, "Missing VarData");
break; break;
} }

View File

@ -147,7 +147,7 @@ static void ws_protocol_oregon_v1_remote_controller(WSBlockGeneric* instance) {
instance->temp = -temp_raw; instance->temp = -temp_raw;
} }
instance->battery_low = !(instance->data >> 23) & 1; instance->battery_low = !((instance->data >> 23) & 1ULL);
instance->btn = WS_NO_BTN; instance->btn = WS_NO_BTN;
instance->humidity = WS_NO_HUMIDITY; instance->humidity = WS_NO_HUMIDITY;

View File

@ -79,7 +79,7 @@ bool ws_block_generic_serialize(
uint8_t key_data[sizeof(uint64_t)] = {0}; uint8_t key_data[sizeof(uint64_t)] = {0};
for(size_t i = 0; i < sizeof(uint64_t); i++) { 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))) { if(!flipper_format_write_hex(flipper_format, "Data", key_data, sizeof(uint64_t))) {

View File

@ -4,8 +4,7 @@
#include "../protocols/ws_generic.h" #include "../protocols/ws_generic.h"
#include <input/input.h> #include <input/input.h>
#include <gui/elements.h> #include <gui/elements.h>
#include <float_tools.h>
#define abs(x) ((x) > 0 ? (x) : -(x))
struct WSReceiverInfo { struct WSReceiverInfo {
View* view; 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); elements_bold_rounded_frame(canvas, 0, 38, 127, 25);
canvas_set_font(canvas, FontPrimary); 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); canvas_draw_icon(canvas, 6, 43, &I_Therm_7x16);
uint8_t temp_x1 = 0; uint8_t temp_x1 = 0;

View File

@ -111,11 +111,8 @@ void ws_hopper_update(WeatherStationApp* app) {
switch(app->txrx->hopper_state) { switch(app->txrx->hopper_state) {
case WSHopperStateOFF: case WSHopperStateOFF:
return;
break;
case WSHopperStatePause: case WSHopperStatePause:
return; return;
break;
case WSHopperStateRSSITimeOut: case WSHopperStateRSSITimeOut:
if(app->txrx->hopper_timeout != 0) { if(app->txrx->hopper_timeout != 0) {
app->txrx->hopper_timeout--; app->txrx->hopper_timeout--;

View File

@ -186,7 +186,7 @@ WSHistoryStateAddKey
} }
// or add new record // or add new record
if(!sensor_found) { if(!sensor_found) { //-V547
WSHistoryItem* item = WSHistoryItemArray_push_raw(instance->history->data); WSHistoryItem* item = WSHistoryItemArray_push_raw(instance->history->data);
item->preset = malloc(sizeof(SubGhzRadioPreset)); item->preset = malloc(sizeof(SubGhzRadioPreset));
item->type = decoder_base->protocol->type; item->type = decoder_base->protocol->type;

View File

@ -36,7 +36,7 @@ static void bt_pin_code_view_port_draw_callback(Canvas* canvas, void* context) {
Bt* bt = context; Bt* bt = context;
char pin_code_info[24]; char pin_code_info[24];
canvas_draw_icon(canvas, 0, 0, &I_BLE_Pairing_128x64); 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_multiline_text_aligned(canvas, 64, 4, AlignCenter, AlignTop, pin_code_info);
elements_button_left(canvas, "Quit"); 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); notification_message(bt->notification, &sequence_display_backlight_on);
FuriString* pin_str; FuriString* pin_str;
dialog_message_set_icon(bt->dialog_message, &I_BLE_Pairing_128x64, 0, 0); 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( dialog_message_set_text(
bt->dialog_message, furi_string_get_cstr(pin_str), 64, 4, AlignCenter, AlignTop); bt->dialog_message, furi_string_get_cstr(pin_str), 64, 4, AlignCenter, AlignTop);
dialog_message_set_buttons(bt->dialog_message, "Cancel", "OK", NULL); 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); rpc_session_feed(bt->rpc_session, event.data.buffer, event.data.size, 1000);
if(bytes_processed != event.data.size) { if(bytes_processed != event.data.size) {
FURI_LOG_E( 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); ret = rpc_session_get_available_size(bt->rpc_session);
} else if(event.event == SerialServiceEventTypeDataSent) { } else if(event.event == SerialServiceEventTypeDataSent) {

View File

@ -115,7 +115,7 @@ bool bt_keys_storage_update(BtKeysStorage* instance, uint8_t* start_addr, uint32
FURI_LOG_I( FURI_LOG_I(
TAG, 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, (void*)instance->nvm_sram_buff,
start_addr, start_addr,
size); size);

View File

@ -225,7 +225,7 @@ static void cli_handle_enter(Cli* cli) {
furi_check(furi_mutex_acquire(cli->mutex, FuriWaitForever) == FuriStatusOk); furi_check(furi_mutex_acquire(cli->mutex, FuriWaitForever) == FuriStatusOk);
CliCommand* cli_command_ptr = CliCommandTree_get(cli->commands, command); CliCommand* cli_command_ptr = CliCommandTree_get(cli->commands, command);
if(cli_command_ptr) { if(cli_command_ptr) { //-V547
CliCommand cli_command; CliCommand cli_command;
memcpy(&cli_command, cli_command_ptr, sizeof(CliCommand)); memcpy(&cli_command, cli_command_ptr, sizeof(CliCommand));
furi_check(furi_mutex_release(cli->mutex) == FuriStatusOk); furi_check(furi_mutex_release(cli->mutex) == FuriStatusOk);
@ -353,7 +353,7 @@ void cli_process_input(Cli* cli) {
cli_handle_backspace(cli); cli_handle_backspace(cli);
} else if(in_chr == CliSymbolAsciiCR) { } else if(in_chr == CliSymbolAsciiCR) {
cli_handle_enter(cli); 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)) { if(cli->cursor_position == furi_string_size(cli->line)) {
furi_string_push_back(cli->line, in_chr); furi_string_push_back(cli->line, in_chr);
cli_putc(cli, in_chr); cli_putc(cli, in_chr);

View File

@ -1,5 +1,6 @@
#include "cli_command_gpio.h" #include "cli_command_gpio.h"
#include "core/string.h"
#include <furi.h> #include <furi.h>
#include <furi_hal.h> #include <furi_hal.h>
#include <lib/toolbox/args.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) { static bool pin_name_to_int(FuriString* pin_name, size_t* result) {
bool found = false; bool is_debug_mode = furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug);
bool debug = furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug);
for(size_t i = 0; i < COUNT_OF(cli_command_gpio_pins); i++) { 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(furi_string_equal(pin_name, cli_command_gpio_pins[i].name)) {
if(!cli_command_gpio_pins[i].debug || debug) { if(!cli_command_gpio_pins[i].debug || is_debug_mode) {
*result = i; *result = i;
found = true; return true;
break;
} }
} }
} }
return found; return false;
} }
static void gpio_print_pins(void) { static void gpio_print_pins(void) {
printf("Wrong pin name. Available pins: "); 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++) { 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); printf("%s ", cli_command_gpio_pins[i].name);
} }
} }
@ -69,34 +68,29 @@ typedef enum {
} GpioParseReturn; } GpioParseReturn;
static GpioParseReturn gpio_command_parse(FuriString* args, size_t* pin_num, uint8_t* value) { static GpioParseReturn gpio_command_parse(FuriString* args, size_t* pin_num, uint8_t* value) {
FuriString* pin_name; GpioParseReturn ret = GpioParseReturnOk;
pin_name = furi_string_alloc(); FuriString* pin_name = furi_string_alloc();
size_t ws = furi_string_search_char(args, ' '); do {
if(ws == FURI_STRING_FAILURE) { if(!args_read_string_and_trim(args, pin_name)) {
return GpioParseReturnCmdSyntaxError; 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); int pin_mode; //-V779
furi_string_right(args, ws); if(!args_read_int_and_trim(args, &pin_mode) || pin_mode < 0 || pin_mode > 1) {
furi_string_trim(args); ret = GpioParseReturnValueError;
break;
if(!pin_name_to_int(pin_name, pin_num)) {
furi_string_free(pin_name);
return GpioParseReturnPinError;
} }
*value = pin_mode;
} while(false);
furi_string_free(pin_name); furi_string_free(pin_name);
return ret;
if(!furi_string_cmp(args, "0")) {
*value = 0;
} else if(!furi_string_cmp(args, "1")) {
*value = 1;
} else {
return GpioParseReturnValueError;
}
return GpioParseReturnOk;
} }
void cli_command_gpio_mode(Cli* cli, FuriString* args, void* context) { 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) { if(err == GpioParseReturnCmdSyntaxError) {
cli_print_usage("gpio mode", "<pin_name> <0|1>", furi_string_get_cstr(args)); cli_print_usage("gpio mode", "<pin_name> <0|1>", furi_string_get_cstr(args));
return; return;
} else if(err == GpioParseReturnPinError) { } else if(err == GpioParseReturnPinError) { //-V547
gpio_print_pins(); gpio_print_pins();
return; return;
} else if(err == GpioParseReturnValueError) { } else if(err == GpioParseReturnValueError) {
@ -119,7 +113,7 @@ void cli_command_gpio_mode(Cli* cli, FuriString* args, void* context) {
return; return;
} }
if(cli_command_gpio_pins[num].debug) { if(cli_command_gpio_pins[num].debug) { //-V779
printf( printf(
"Changing this pin mode may damage hardware. Are you sure you want to continue? (y/n)?\r\n"); "Changing this pin mode may damage hardware. Are you sure you want to continue? (y/n)?\r\n");
char c = cli_getc(cli); char c = cli_getc(cli);
@ -149,7 +143,7 @@ void cli_command_gpio_read(Cli* cli, FuriString* args, void* context) {
return; return;
} }
if(LL_GPIO_MODE_INPUT != if(LL_GPIO_MODE_INPUT != //-V779
LL_GPIO_GetPinMode( LL_GPIO_GetPinMode(
cli_command_gpio_pins[num].pin->port, cli_command_gpio_pins[num].pin->pin)) { 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); 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) { if(err == GpioParseReturnCmdSyntaxError) {
cli_print_usage("gpio set", "<pin_name> <0|1>", furi_string_get_cstr(args)); cli_print_usage("gpio set", "<pin_name> <0|1>", furi_string_get_cstr(args));
return; return;
} else if(err == GpioParseReturnPinError) { } else if(err == GpioParseReturnPinError) { //-V547
gpio_print_pins(); gpio_print_pins();
return; return;
} else if(err == GpioParseReturnValueError) { } else if(err == GpioParseReturnValueError) {
@ -179,7 +173,7 @@ void cli_command_gpio_set(Cli* cli, FuriString* args, void* context) {
return; return;
} }
if(LL_GPIO_MODE_OUTPUT != if(LL_GPIO_MODE_OUTPUT != //-V779
LL_GPIO_GetPinMode( LL_GPIO_GetPinMode(
cli_command_gpio_pins[num].pin->port, cli_command_gpio_pins[num].pin->pin)) { 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); 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