diff --git a/.clang-format b/.clang-format index 3337a7409..4b76f7fa4 100644 --- a/.clang-format +++ b/.clang-format @@ -1,86 +1,191 @@ +--- +Language: Cpp AccessModifierOffset: -4 AlignAfterOpenBracket: AlwaysBreak -AlignConsecutiveAssignments: false -AlignConsecutiveDeclarations: false +AlignArrayOfStructures: None +AlignConsecutiveMacros: None +AlignConsecutiveAssignments: None +AlignConsecutiveBitFields: None +AlignConsecutiveDeclarations: None AlignEscapedNewlines: Left -AlignOperands: true +AlignOperands: Align AlignTrailingComments: false +AllowAllArgumentsOnNextLine: true AllowAllParametersOfDeclarationOnNextLine: false +AllowShortEnumsOnASingleLine: true AllowShortBlocksOnASingleLine: Never AllowShortCaseLabelsOnASingleLine: false AllowShortFunctionsOnASingleLine: None -AllowShortIfStatementsOnASingleLine: true +AllowShortLambdasOnASingleLine: All +AllowShortIfStatementsOnASingleLine: WithoutElse AllowShortLoopsOnASingleLine: true AlwaysBreakAfterDefinitionReturnType: None AlwaysBreakAfterReturnType: None AlwaysBreakBeforeMultilineStrings: false -AlwaysBreakTemplateDeclarations: false +AlwaysBreakTemplateDeclarations: Yes +AttributeMacros: + - __capability BinPackArguments: false BinPackParameters: false +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true BreakBeforeBinaryOperators: None +BreakBeforeConceptDeclarations: true BreakBeforeBraces: Attach +BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeColon BreakBeforeTernaryOperators: false +BreakConstructorInitializersBeforeComma: false BreakConstructorInitializers: BeforeComma +BreakAfterJavaFieldAnnotations: false BreakStringLiterals: false -ColumnLimit: 99 +ColumnLimit: 99 +CommentPragmas: '^ IWYU pragma:' +QualifierAlignment: Leave CompactNamespaces: false -ConstructorInitializerAllOnOneLineOrOnePerLine: false ConstructorInitializerIndentWidth: 4 ContinuationIndentWidth: 4 Cpp11BracedListStyle: true +DeriveLineEnding: true DerivePointerAlignment: false -DisableFormat: false +DisableFormat: false +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: LogicalBlock ExperimentalAutoDetectBinPacking: false +PackConstructorInitializers: BinPack +BasedOnStyle: '' +ConstructorInitializerAllOnOneLineOrOnePerLine: false +AllowAllConstructorInitializersOnNextLine: true FixNamespaceComments: false - -IncludeBlocks: Preserve +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IfMacros: + - KJ_IF_MAYBE +IncludeBlocks: Preserve IncludeCategories: - - Regex: '.*' - Priority: 1 + - Regex: '.*' + Priority: 1 + SortPriority: 0 + CaseSensitive: false + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + SortPriority: 0 + CaseSensitive: false + - Regex: '.*' + Priority: 1 + SortPriority: 0 + CaseSensitive: false IncludeIsMainRegex: '(Test)?$' +IncludeIsMainSourceRegex: '' +IndentAccessModifiers: false IndentCaseLabels: false +IndentCaseBlocks: false +IndentGotoLabels: true IndentPPDirectives: None -IndentWidth: 4 +IndentExternBlock: AfterExternBlock +IndentRequires: false +IndentWidth: 4 IndentWrappedFunctionNames: true +InsertTrailingCommas: None JavaScriptQuotes: Leave JavaScriptWrapImports: true KeepEmptyLinesAtTheStartOfBlocks: false +LambdaBodyIndentation: Signature MacroBlockBegin: '' -MacroBlockEnd: '' +MacroBlockEnd: '' MaxEmptyLinesToKeep: 1 NamespaceIndentation: None ObjCBinPackProtocolList: Auto ObjCBlockIndentWidth: 4 +ObjCBreakBeforeNestedBlockParam: true ObjCSpaceAfterProperty: true ObjCSpaceBeforeProtocolList: true - -# Taken from git's rules PenaltyBreakAssignment: 10 PenaltyBreakBeforeFirstCallParameter: 30 PenaltyBreakComment: 10 PenaltyBreakFirstLessLess: 0 +PenaltyBreakOpenParenthesis: 0 PenaltyBreakString: 10 +PenaltyBreakTemplateDeclaration: 10 PenaltyExcessCharacter: 100 PenaltyReturnTypeOnItsOwnLine: 60 - +PenaltyIndentedWhitespace: 0 PointerAlignment: Left -ReflowComments: false -SortIncludes: false +PPIndentWidth: -1 +ReferenceAlignment: Pointer +ReflowComments: false +RemoveBracesLLVM: false +SeparateDefinitionBlocks: Leave +ShortNamespaceLines: 1 +SortIncludes: Never +SortJavaStaticImport: Before SortUsingDeclarations: false SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false SpaceAfterTemplateKeyword: true SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false +SpaceBeforeCpp11BracedList: false SpaceBeforeCtorInitializerColon: true SpaceBeforeInheritanceColon: true SpaceBeforeParens: Never +SpaceBeforeParensOptions: + AfterControlStatements: false + AfterForeachMacros: false + AfterFunctionDefinitionName: false + AfterFunctionDeclarationName: false + AfterIfMacros: false + AfterOverloadedOperator: false + BeforeNonEmptyParentheses: false +SpaceAroundPointerQualifiers: Default SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyBlock: false SpaceInEmptyParentheses: false SpacesBeforeTrailingComments: 1 -SpacesInAngles: false +SpacesInAngles: Never +SpacesInConditionalStatement: false SpacesInContainerLiterals: false SpacesInCStyleCastParentheses: false +SpacesInLineCommentPrefix: + Minimum: 1 + Maximum: -1 SpacesInParentheses: false SpacesInSquareBrackets: false -Standard: Cpp03 -TabWidth: 4 -UseTab: Never +SpaceBeforeSquareBrackets: false +BitFieldColonSpacing: Both +Standard: c++03 +StatementAttributeLikeMacros: + - Q_EMIT +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 4 +UseCRLF: false +UseTab: Never +WhitespaceSensitiveMacros: + - STRINGIZE + - PP_STRINGIZE + - BOOST_PP_STRINGIZE + - NS_SWIFT_NAME + - CF_SWIFT_NAME +... + diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 6dac0496a..c9b8ff3f5 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -2,82 +2,58 @@ * @skotopes @DrZlo13 @hedger # Apps -/applications/about/ @skotopes @DrZlo13 @hedger -/applications/accessor/ @skotopes @DrZlo13 @hedger -/applications/archive/ @skotopes @DrZlo13 @hedger @nminaylov -/applications/bad_usb/ @skotopes @DrZlo13 @hedger @nminaylov -/applications/bt/ @skotopes @DrZlo13 @hedger @gornekich -/applications/cli/ @skotopes @DrZlo13 @hedger @nminaylov -/applications/crypto/ @skotopes @DrZlo13 @hedger @nminaylov -/applications/debug_tools/ @skotopes @DrZlo13 @hedger -/applications/desktop/ @skotopes @DrZlo13 @hedger @nminaylov -/applications/dialogs/ @skotopes @DrZlo13 @hedger -/applications/dolphin/ @skotopes @DrZlo13 @hedger -/applications/gpio/ @skotopes @DrZlo13 @hedger @nminaylov -/applications/gui/ @skotopes @DrZlo13 @hedger -/applications/ibutton/ @skotopes @DrZlo13 @hedger @gsurkov -/applications/infrared/ @skotopes @DrZlo13 @hedger @gsurkov -/applications/input/ @skotopes @DrZlo13 @hedger -/applications/lfrfid/ @skotopes @DrZlo13 @hedger -/applications/lfrfid_debug/ @skotopes @DrZlo13 @hedger -/applications/loader/ @skotopes @DrZlo13 @hedger -/applications/music_player/ @skotopes @DrZlo13 @hedger -/applications/nfc/ @skotopes @DrZlo13 @hedger @gornekich -/applications/notification/ @skotopes @DrZlo13 @hedger -/applications/power/ @skotopes @DrZlo13 @hedger -/applications/rpc/ @skotopes @DrZlo13 @hedger @nminaylov -/applications/snake_game/ @skotopes @DrZlo13 @hedger -/applications/storage/ @skotopes @DrZlo13 @hedger -/applications/storage_settings/ @skotopes @DrZlo13 @hedger -/applications/subghz/ @skotopes @DrZlo13 @hedger @Skorpionm -/applications/system/ @skotopes @DrZlo13 @hedger -/applications/u2f/ @skotopes @DrZlo13 @hedger @nminaylov -/applications/unit_tests/ @skotopes @DrZlo13 @hedger -/applications/updater/ @skotopes @DrZlo13 @hedger +/applications/debug/bt_debug_app/ @skotopes @DrZlo13 @hedger @gornekich +/applications/debug/accessor/ @skotopes @DrZlo13 @hedger @nminaylov +/applications/debug/battery_test_app/ @skotopes @DrZlo13 @hedger @gornekich +/applications/debug/bt_debug_app/ @skotopes @DrZlo13 @hedger @gornekich +/applications/debug/file_browser_test/ @skotopes @DrZlo13 @hedger @nminaylov +/applications/debug/lfrfid_debug/ @skotopes @DrZlo13 @hedger @nminaylov +/applications/debug/text_box_test/ @skotopes @DrZlo13 @hedger @nminaylov +/applications/debug/uart_echo/ @skotopes @DrZlo13 @hedger @nminaylov +/applications/debug/usb_mouse/ @skotopes @DrZlo13 @hedger @nminaylov +/applications/debug/usb_test/ @skotopes @DrZlo13 @hedger @nminaylov -# Assets -/assets/ @skotopes @DrZlo13 @hedger +/applications/main/archive/ @skotopes @DrZlo13 @hedger @nminaylov +/applications/main/bad_usb/ @skotopes @DrZlo13 @hedger @nminaylov +/applications/main/gpio/ @skotopes @DrZlo13 @hedger @nminaylov +/applications/main/ibutton/ @skotopes @DrZlo13 @hedger @gsurkov +/applications/main/infrared/ @skotopes @DrZlo13 @hedger @gsurkov +/applications/main/nfc/ @skotopes @DrZlo13 @hedger @gornekich +/applications/main/subghz/ @skotopes @DrZlo13 @hedger @Skorpionm +/applications/main/u2f/ @skotopes @DrZlo13 @hedger @nminaylov -# Furi Core -/furi/ @skotopes @DrZlo13 @hedger +/applications/plugins/bt_hid_app/ @skotopes @DrZlo13 @hedger @gornekich +/applications/plugins/picopass/ @skotopes @DrZlo13 @hedger @gornekich -# Debug tools and plugins -/debug/ @skotopes @DrZlo13 @hedger +/applications/services/bt/ @skotopes @DrZlo13 @hedger @gornekich +/applications/services/cli/ @skotopes @DrZlo13 @hedger @nminaylov +/applications/services/crypto/ @skotopes @DrZlo13 @hedger @nminaylov +/applications/services/desktop/ @skotopes @DrZlo13 @hedger @nminaylov +/applications/services/dolphin/ @skotopes @DrZlo13 @hedger @nminaylov +/applications/services/power/ @skotopes @DrZlo13 @hedger @gornekich +/applications/services/rpc/ @skotopes @DrZlo13 @hedger @nminaylov + +/applications/services/bt_settings_app/ @skotopes @DrZlo13 @hedger @gornekich +/applications/services/desktop_settings/ @skotopes @DrZlo13 @hedger @nminaylov +/applications/services/dolphin_passport/ @skotopes @DrZlo13 @hedger @nminaylov +/applications/services/power_settings_app/ @skotopes @DrZlo13 @hedger @gornekich + +/applications/system/storage_move_to_sd/ @skotopes @DrZlo13 @hedger @nminaylov # Documentation /documentation/ @skotopes @DrZlo13 @hedger @drunkbatya - -# Firmware targets -/firmware/ @skotopes @DrZlo13 @hedger +/scripts/toolchain/ @skotopes @DrZlo13 @hedger @drunkbatya # Lib -/lib/FreeRTOS-Kernel/ @skotopes @DrZlo13 @hedger -/lib/FreeRTOS-glue/ @skotopes @DrZlo13 @hedger /lib/ST25RFAL002/ @skotopes @DrZlo13 @hedger @gornekich /lib/STM32CubeWB/ @skotopes @DrZlo13 @hedger @gornekich -/lib/app-scened-template/ @skotopes @DrZlo13 @hedger -/lib/callback-connector/ @skotopes @DrZlo13 @hedger /lib/digital_signal/ @skotopes @DrZlo13 @hedger @gornekich -/lib/drivers/ @skotopes @DrZlo13 @hedger -/lib/fatfs/ @skotopes @DrZlo13 @hedger -/lib/flipper_format/ @skotopes @DrZlo13 @hedger -/lib/fnv1a-hash/ @skotopes @DrZlo13 @hedger -/lib/heatshrink/ @skotopes @DrZlo13 @hedger /lib/infrared/ @skotopes @DrZlo13 @hedger @gsurkov +/lib/lfrfid/ @skotopes @DrZlo13 @hedger @nminaylov /lib/libusb_stm32/ @skotopes @DrZlo13 @hedger @nminaylov -/lib/littlefs/ @skotopes @DrZlo13 @hedger -/lib/lfs_config.h @skotopes @DrZlo13 @hedger +/lib/mbedtls/ @skotopes @DrZlo13 @hedger @nminaylov /lib/micro-ecc/ @skotopes @DrZlo13 @hedger @nminaylov -/lib/microtar/ @skotopes @DrZlo13 @hedger -/lib/mlib/ @skotopes @DrZlo13 @hedger -/lib/nanopb/ @skotopes @DrZlo13 @hedger +/lib/nanopb/ @skotopes @DrZlo13 @hedger @nminaylov /lib/nfc/ @skotopes @DrZlo13 @hedger @gornekich -/lib/one_wire/ @skotopes @DrZlo13 @hedger -/lib/qrcode/ @skotopes @DrZlo13 @hedger +/lib/one_wire/ @skotopes @DrZlo13 @hedger @gsurkov /lib/subghz/ @skotopes @DrZlo13 @hedger @Skorpionm -/lib/toolbox/ @skotopes @DrZlo13 @hedger -/lib/u8g2/ @skotopes @DrZlo13 @hedger -/lib/update_util/ @skotopes @DrZlo13 @hedger - -# Helper scripts -/scripts/ @skotopes @DrZlo13 @hedger diff --git a/.github/workflows/amap_analyse.yml b/.github/workflows/amap_analyse.yml index 3443771dd..6be99c9d1 100644 --- a/.github/workflows/amap_analyse.yml +++ b/.github/workflows/amap_analyse.yml @@ -14,6 +14,7 @@ env: jobs: amap_analyse: + if: ${{ !github.event.pull_request.head.repo.fork }} runs-on: [self-hosted,FlipperZeroMacShell] timeout-minutes: 15 steps: @@ -34,8 +35,7 @@ jobs: - 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` + git submodule status || git checkout "$(git rev-list --max-parents=0 HEAD | tail -n 1)" fi - name: 'Checkout code' @@ -44,32 +44,16 @@ jobs: fetch-depth: 0 ref: ${{ github.event.pull_request.head.sha }} - - name: 'Generate prefixes by commit' - id: names + - name: 'Get commit details' run: | - REF="${{github.ref}}" - COMMIT_HASH="$(git rev-parse HEAD)" - SHA="$(git rev-parse --short HEAD)" - COMMIT_MSG="${{github.event.head_commit.message}}" if [[ ${{ github.event_name }} == 'pull_request' ]]; then - REF="${{github.head_ref}}" - COMMIT_HASH="$(git log -1 --pretty=oneline | awk '{print $1}')" - SHA="$(cut -c -8 <<< "$COMMIT_HASH")" - COMMIT_MSG="$(git log -1 --pretty=format:"%s")" - PULL_ID="${{github.event.pull_request.number}}" - PULL_NAME="${{github.event.pull_request.title}}" + TYPE="pull" + elif [[ "${{ github.ref }}" == "refs/tags/"* ]]; then + TYPE="tag" + else + TYPE="other" fi - BRANCH_NAME=${REF#refs/*/} - SUFFIX=${BRANCH_NAME//\//_}-$(date +'%d%m%Y')-${SHA} - if [[ "${{ github.ref }}" == "refs/tags/"* ]]; then - SUFFIX=${BRANCH_NAME//\//_} - fi - echo "::set-output name=commit-hash::${COMMIT_HASH}" - echo "::set-output name=commit-msg::${COMMIT_MSG}" - echo "::set-output name=pull-id::${PULL_ID}" - echo "::set-output name=pull-name::${PULL_NAME}" - echo "::set-output name=branch-name::${BRANCH_NAME}" - echo "::set-output name=suffix::${SUFFIX}" + python3 scripts/get_env.py "--event_file=${{ github.event_path }}" "--type=$TYPE" - name: 'Make artifacts directory' run: | @@ -77,19 +61,18 @@ jobs: mkdir artifacts - name: 'Download build artifacts' - if: ${{ !github.event.pull_request.head.repo.fork }} run: | 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 }}${{steps.names.outputs.branch-name}}/" artifacts/; + ${{ secrets.RSYNC_DEPLOY_USER }}@${{ secrets.RSYNC_DEPLOY_HOST }}:"${{ secrets.RSYNC_DEPLOY_BASE_PATH }}${BRANCH_NAME}/" artifacts/; rm ./deploy_key; - - name: 'Make .map file analyse' + - name: 'Make .map file analyze' run: | cd artifacts/ - /Applications/amap/Contents/MacOS/amap -f flipper-z-f7-firmware-${{steps.names.outputs.suffix}}.elf.map + /Applications/amap/Contents/MacOS/amap -f "flipper-z-f7-firmware-${SUFFIX}.elf.map" - name: 'Upload report to DB' run: | @@ -98,21 +81,14 @@ jobs: { SECTION="$1"; arm-none-eabi-size \ - -A artifacts/flipper-z-f7-firmware-${{steps.names.outputs.suffix}}.elf \ + -A artifacts/flipper-z-f7-firmware-$SUFFIX.elf \ | grep "^$SECTION" | awk '{print $2}' } - export COMMIT_HASH="${{steps.names.outputs.commit-hash}}" - export COMMIT_MSG="${{steps.names.outputs.commit-msg}}" - export BRANCH_NAME="${{steps.names.outputs.branch-name}}" 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")" - if [[ ${{ github.event_name }} == 'pull_request' ]]; then - export PULL_ID="${{steps.names.outputs.pull-id}}" - export PULL_NAME="${{steps.names.outputs.pull-name}}" - fi python3 -m pip install mariadb python3 scripts/amap_mariadb_insert.py \ ${{ secrets.AMAP_MARIADB_USER }} \ @@ -120,4 +96,4 @@ jobs: ${{ secrets.AMAP_MARIADB_HOST }} \ ${{ secrets.AMAP_MARIADB_PORT }} \ ${{ secrets.AMAP_MARIADB_DATABASE }} \ - artifacts/flipper-z-f7-firmware-${{steps.names.outputs.suffix}}.elf.map.all + artifacts/flipper-z-f7-firmware-$SUFFIX.elf.map.all diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7eeb5c22b..15b3966a7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,10 +19,8 @@ jobs: 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` + if [ -d .git ]; then + git submodule status || git checkout "$(git rev-list --max-parents=0 HEAD | tail -n 1)" fi - name: 'Checkout code' @@ -33,51 +31,46 @@ jobs: - name: 'Make artifacts directory' run: | - test -d artifacts && rm -rf artifacts || true + rm -rf artifacts mkdir artifacts - - name: 'Generate suffix and folder name' + - 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: 'Generate suffixes for comment' id: names run: | - REF=${{ github.ref }} - if [[ ${{ github.event_name }} == 'pull_request' ]]; then - REF=${{ github.head_ref }} - fi - BRANCH_OR_TAG=${REF#refs/*/} - SHA=$(git rev-parse --short HEAD) - - if [[ "${{ github.ref }}" == "refs/tags/"* ]]; then - SUFFIX=${BRANCH_OR_TAG//\//_} - else - SUFFIX=${BRANCH_OR_TAG//\//_}-$(date +'%d%m%Y')-${SHA} - fi - - echo "WORKFLOW_BRANCH_OR_TAG=${BRANCH_OR_TAG}" >> $GITHUB_ENV - echo "DIST_SUFFIX=${SUFFIX}" >> $GITHUB_ENV - echo "::set-output name=artifacts-path::${BRANCH_OR_TAG}" + echo "::set-output name=branch_name::${BRANCH_NAME}" + echo "::set-output name=commit_sha::${COMMIT_SHA}" + echo "::set-output name=default_target::${DEFAULT_TARGET}" echo "::set-output name=suffix::${SUFFIX}" - echo "::set-output name=short-hash::${SHA}" - echo "::set-output name=default-target::${DEFAULT_TARGET}" - name: 'Bundle scripts' if: ${{ !github.event.pull_request.head.repo.fork }} run: | - tar czpf artifacts/flipper-z-any-scripts-${{steps.names.outputs.suffix}}.tgz scripts + tar czpf artifacts/flipper-z-any-scripts-${SUFFIX}.tgz scripts - name: 'Build the firmware' run: | set -e - for TARGET in ${TARGETS} - do - FBT_TOOLCHAIN_PATH=/opt ./fbt TARGET_HW=`echo ${TARGET} | sed 's/f//'` updater_package ${{ startsWith(github.ref, 'refs/tags') && 'DEBUG=0 COMPACT=1' || '' }} + for TARGET in ${TARGETS}; do + FBT_TOOLCHAIN_PATH=/opt ./fbt TARGET_HW="$(echo "${TARGET}" | sed 's/f//')" \ + updater_package ${{ startsWith(github.ref, 'refs/tags') && 'DEBUG=0 COMPACT=1' || '' }} done - name: 'Move upload files' if: ${{ !github.event.pull_request.head.repo.fork }} run: | set -e - for TARGET in ${TARGETS} - do + for TARGET in ${TARGETS}; do mv dist/${TARGET}-*/* artifacts/ done @@ -85,32 +78,31 @@ jobs: if: ${{ !github.event.pull_request.head.repo.fork }} run: | set -e - for UPDATEBUNDLE in artifacts/*/ - do - BUNDLE_NAME=`echo $UPDATEBUNDLE | cut -d'/' -f2` - echo Packaging ${BUNDLE_NAME} - tar czpf artifacts/flipper-z-${BUNDLE_NAME}.tgz -C artifacts ${BUNDLE_NAME} - rm -rf artifacts/${BUNDLE_NAME} + for UPDATEBUNDLE in artifacts/*/; do + BUNDLE_NAME="$(echo "$UPDATEBUNDLE" | cut -d'/' -f2)" + echo Packaging "${BUNDLE_NAME}" + tar czpf "artifacts/flipper-z-${BUNDLE_NAME}.tgz" -C artifacts "${BUNDLE_NAME}" + rm -rf "artifacts/${BUNDLE_NAME}" done - - name: "Check for uncommited changes" + - name: "Check for uncommitted changes" run: | git diff --exit-code - name: 'Bundle resources' if: ${{ !github.event.pull_request.head.repo.fork }} run: | - tar czpf artifacts/flipper-z-any-resources-${{steps.names.outputs.suffix}}.tgz -C assets resources + tar czpf "artifacts/flipper-z-any-resources-${SUFFIX}.tgz" -C assets resources - name: 'Bundle core2 firmware' if: ${{ !github.event.pull_request.head.repo.fork }} run: | FBT_TOOLCHAIN_PATH=/opt ./fbt copro_dist - tar czpf artifacts/flipper-z-any-core2_firmware-${{steps.names.outputs.suffix}}.tgz -C assets core2_firmware + tar czpf "artifacts/flipper-z-any-core2_firmware-${SUFFIX}.tgz" -C assets core2_firmware - name: 'Copy .map file' run: | - cp build/f7-firmware-*/firmware.elf.map artifacts/flipper-z-f7-firmware-${{steps.names.outputs.suffix}}.elf.map + cp build/f7-firmware-*/firmware.elf.map "artifacts/flipper-z-f7-firmware-${SUFFIX}.elf.map" - name: 'Upload artifacts to update server' if: ${{ !github.event.pull_request.head.repo.fork }} @@ -119,7 +111,7 @@ jobs: chmod 600 ./deploy_key; rsync -avzP --delete --mkpath \ -e 'ssh -p ${{ secrets.RSYNC_DEPLOY_PORT }} -i ./deploy_key' \ - artifacts/ ${{ secrets.RSYNC_DEPLOY_USER }}@${{ secrets.RSYNC_DEPLOY_HOST }}:"${{ secrets.RSYNC_DEPLOY_BASE_PATH }}${{steps.names.outputs.artifacts-path}}/"; + artifacts/ ${{ secrets.RSYNC_DEPLOY_USER }}@${{ secrets.RSYNC_DEPLOY_HOST }}:"${{ secrets.RSYNC_DEPLOY_BASE_PATH }}${BRANCH_NAME}/"; rm ./deploy_key; - name: 'Trigger update server reindex' @@ -142,10 +134,10 @@ jobs: comment-id: ${{ steps.fc.outputs.comment-id }} issue-number: ${{ github.event.pull_request.number }} body: | - **Compiled firmware for commit `${{steps.names.outputs.short-hash}}`:** - - [📦 Update package](https://update.flipperzero.one/builds/firmware/${{steps.names.outputs.artifacts-path}}/flipper-z-${{steps.names.outputs.default-target}}-update-${{steps.names.outputs.suffix}}.tgz) - - [📥 DFU file](https://update.flipperzero.one/builds/firmware/${{steps.names.outputs.artifacts-path}}/flipper-z-${{steps.names.outputs.default-target}}-full-${{steps.names.outputs.suffix}}.dfu) - - [☁️ Web updater](https://my.flipp.dev/?url=https://update.flipperzero.one/builds/firmware/${{steps.names.outputs.artifacts-path}}/flipper-z-${{steps.names.outputs.default-target}}-update-${{steps.names.outputs.suffix}}.tgz&channel=${{steps.names.outputs.artifacts-path}}&version=${{steps.names.outputs.short-hash}}) + **Compiled firmware for commit `${{steps.names.outputs.commit_sha}}`:** + - [📦 Update package](https://update.flipperzero.one/builds/firmware/${{steps.names.outputs.branch_name}}/flipper-z-${{steps.names.outputs.default_target}}-update-${{steps.names.outputs.suffix}}.tgz) + - [📥 DFU file](https://update.flipperzero.one/builds/firmware/${{steps.names.outputs.branch_name}}/flipper-z-${{steps.names.outputs.default_target}}-full-${{steps.names.outputs.suffix}}.dfu) + - [☁️ Web updater](https://my.flipp.dev/?url=https://update.flipperzero.one/builds/firmware/${{steps.names.outputs.branch_name}}/flipper-z-${{steps.names.outputs.default_target}}-update-${{steps.names.outputs.suffix}}.tgz&channel=${{steps.names.outputs.branch_name}}&version=${{steps.names.outputs.commit_sha}}) edit-mode: replace compact: @@ -157,7 +149,7 @@ jobs: if [ -d .git ] then git submodule status \ - || git checkout `git rev-list --max-parents=0 HEAD | tail -n 1` + || git checkout "$(git rev-list --max-parents=0 HEAD | tail -n 1)" fi - name: 'Checkout code' @@ -167,29 +159,21 @@ jobs: submodules: true ref: ${{ github.event.pull_request.head.sha }} - - name: 'Generate suffix and folder name' - id: names + - name: 'Get commit details' run: | - REF=${{ github.ref }} if [[ ${{ github.event_name }} == 'pull_request' ]]; then - REF=${{ github.head_ref }} - fi - BRANCH_OR_TAG=${REF#refs/*/} - SHA=$(git rev-parse --short HEAD) - - if [[ "${{ github.ref }}" == "refs/tags/"* ]]; then - SUFFIX=${BRANCH_OR_TAG//\//_} + TYPE="pull" + elif [[ "${{ github.ref }}" == "refs/tags/"* ]]; then + TYPE="tag" else - SUFFIX=${BRANCH_OR_TAG//\//_}-$(date +'%d%m%Y')-${SHA} + TYPE="other" fi - - echo "WORKFLOW_BRANCH_OR_TAG=${BRANCH_OR_TAG}" >> $GITHUB_ENV - echo "DIST_SUFFIX=${SUFFIX}" >> $GITHUB_ENV + python3 scripts/get_env.py "--event_file=${{ github.event_path }}" "--type=$TYPE" - name: 'Build the firmware' run: | set -e - for TARGET in ${TARGETS} - do - FBT_TOOLCHAIN_PATH=/opt ./fbt TARGET_HW=`echo ${TARGET} | sed 's/f//'` updater_package DEBUG=0 COMPACT=1 + for TARGET in ${TARGETS}; do + FBT_TOOLCHAIN_PATH=/opt ./fbt TARGET_HW="$(echo "${TARGET}" | sed 's/f//')" \ + updater_package DEBUG=0 COMPACT=1 done diff --git a/.github/workflows/check_submodules.yml b/.github/workflows/check_submodules.yml index e021c969a..e4178c3c7 100644 --- a/.github/workflows/check_submodules.yml +++ b/.github/workflows/check_submodules.yml @@ -15,10 +15,8 @@ jobs: 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` + if [ -d .git ]; then + git submodule status || git checkout "$(git rev-list --max-parents=0 HEAD | tail -n 1)" fi - name: 'Checkout code' diff --git a/.github/workflows/lint_c.yml b/.github/workflows/lint_c.yml index 64d14b713..becafcab0 100644 --- a/.github/workflows/lint_c.yml +++ b/.github/workflows/lint_c.yml @@ -18,10 +18,8 @@ jobs: 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` + if [ -d .git ]; then + git submodule status || git checkout "$(git rev-list --max-parents=0 HEAD | tail -n 1)" fi - name: 'Checkout code' diff --git a/.github/workflows/lint_python.yml b/.github/workflows/lint_python.yml index 5051c5691..d5ff834ea 100644 --- a/.github/workflows/lint_python.yml +++ b/.github/workflows/lint_python.yml @@ -15,10 +15,8 @@ jobs: 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` + if [ -d .git ]; then + git submodule status || git checkout "$(git rev-list --max-parents=0 HEAD | tail -n 1)" fi - name: 'Checkout code' diff --git a/.github/workflows/pvs_studio.yml b/.github/workflows/pvs_studio.yml index c238b1c6f..7bd71de49 100644 --- a/.github/workflows/pvs_studio.yml +++ b/.github/workflows/pvs_studio.yml @@ -15,14 +15,13 @@ env: jobs: analyse_c_cpp: + if: ${{ !github.event.pull_request.head.repo.fork }} runs-on: [self-hosted, FlipperZeroShell] 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` + if [ -d .git ]; then + git submodule status || git checkout "$(git rev-list --max-parents=0 HEAD | tail -n 1)" fi - name: 'Checkout code' @@ -31,28 +30,25 @@ jobs: fetch-depth: 0 ref: ${{ github.event.pull_request.head.sha }} - - name: 'Generate suffix and folder name' + - 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: 'Generate suffixes for comment' + if: ${{ !github.event.pull_request.head.repo.fork && github.event.pull_request }} id: names run: | - REF=${{ github.ref }} - if [[ ${{ github.event_name }} == 'pull_request' ]]; then - REF=${{ github.head_ref }} - fi - BRANCH_OR_TAG=${REF#refs/*/} - SHA=$(git rev-parse --short HEAD) - - if [[ "${{ github.ref }}" == "refs/tags/"* ]]; then - SUFFIX=${BRANCH_OR_TAG//\//_} - else - SUFFIX=${BRANCH_OR_TAG//\//_}-$(date +'%d%m%Y')-${SHA} - fi - - echo "WORKFLOW_BRANCH_OR_TAG=${BRANCH_OR_TAG}" >> $GITHUB_ENV - echo "DIST_SUFFIX=${SUFFIX}" >> $GITHUB_ENV - echo "::set-output name=artifacts-path::${BRANCH_OR_TAG}" + echo "::set-output name=branch_name::${BRANCH_NAME}" + echo "::set-output name=commit_sha::${COMMIT_SHA}" + echo "::set-output name=default_target::${DEFAULT_TARGET}" echo "::set-output name=suffix::${SUFFIX}" - echo "::set-output name=short-hash::${SHA}" - echo "::set-output name=default-target::${DEFAULT_TARGET}" - name: 'Make reports directory' run: | @@ -74,7 +70,7 @@ jobs: -o PVS-Studio.log - name: 'Convert PVS-Studio output to html page' - run: plog-converter -a GA:1,2,3 -t fullhtml PVS-Studio.log -o reports/${{steps.names.outputs.default-target}}-${{steps.names.outputs.suffix}} + run: plog-converter -a GA:1,2,3 -t fullhtml PVS-Studio.log -o reports/${DEFAULT_TARGET}-${SUFFIX} - name: 'Upload artifacts to update server' if: ${{ !github.event.pull_request.head.repo.fork }} @@ -83,7 +79,7 @@ jobs: chmod 600 ./deploy_key; rsync -avrzP --mkpath \ -e 'ssh -p ${{ secrets.RSYNC_DEPLOY_PORT }} -i ./deploy_key' \ - reports/ ${{ secrets.RSYNC_DEPLOY_USER }}@${{ secrets.RSYNC_DEPLOY_HOST }}:/home/data/firmware-pvs-studio-report/"${{steps.names.outputs.artifacts-path}}/"; + reports/ ${{ secrets.RSYNC_DEPLOY_USER }}@${{ secrets.RSYNC_DEPLOY_HOST }}:/home/data/firmware-pvs-studio-report/"${BRANCH_NAME}/"; rm ./deploy_key; - name: 'Find Previous Comment' @@ -102,6 +98,6 @@ jobs: comment-id: ${{ steps.fc.outputs.comment-id }} issue-number: ${{ github.event.pull_request.number }} body: | - **PVS-Studio report for commit `${{steps.names.outputs.short-hash}}`:** - - [Report](https://update.flipperzero.one/builds/firmware-pvs-studio-report/${{steps.names.outputs.artifacts-path}}/${{steps.names.outputs.default-target}}-${{steps.names.outputs.suffix}}/index.html) + **PVS-Studio report for commit `${{steps.names.outputs.commit_sha}}`:** + - [Report](https://update.flipperzero.one/builds/firmware-pvs-studio-report/${{steps.names.outputs.branch_name}}/${{steps.names.outputs.default_target}}-${{steps.names.outputs.suffix}}/index.html) edit-mode: replace diff --git a/.gitmodules b/.gitmodules index b580a8c71..ba7644981 100644 --- a/.gitmodules +++ b/.gitmodules @@ -28,3 +28,6 @@ [submodule "lib/mbedtls"] path = lib/mbedtls url = https://github.com/Mbed-TLS/mbedtls.git +[submodule "lib/cxxheaderparser"] + path = lib/cxxheaderparser + url = https://github.com/robotpy/cxxheaderparser.git diff --git a/.vscode/example/launch.json b/.vscode/example/launch.json index bdad04285..f9470a740 100644 --- a/.vscode/example/launch.json +++ b/.vscode/example/launch.json @@ -31,7 +31,10 @@ ], "postAttachCommands": [ // "attach 1", - "compare-sections", + // "compare-sections", + "source debug/flipperapps.py", + // "source debug/FreeRTOS/FreeRTOS.py", + // "svd_load debug/STM32WB55_CM4.svd" ] // "showDevDebugOutput": "raw", }, @@ -50,7 +53,8 @@ "attach 1", "set confirm off", "set mem inaccessible-by-default off", - "compare-sections", + "source debug/flipperapps.py", + // "compare-sections", ] // "showDevDebugOutput": "raw", }, @@ -65,6 +69,9 @@ "device": "STM32WB55RG", "svdFile": "./debug/STM32WB55_CM4.svd", "rtos": "FreeRTOS", + "postAttachCommands": [ + "source debug/flipperapps.py", + ] // "showDevDebugOutput": "raw", }, { @@ -73,7 +80,7 @@ "request": "launch", "program": "./lib/scons/scripts/scons.py", "args": [ - "sdk" + "plugin_dist" ] }, { diff --git a/.vscode/example/settings.json b/.vscode/example/settings.json index 925c2e076..d84707e07 100644 --- a/.vscode/example/settings.json +++ b/.vscode/example/settings.json @@ -12,6 +12,9 @@ "cortex-debug.openocdPath.windows": "${workspaceFolder}/toolchain/i686-windows/openocd/bin/openocd.exe", "cortex-debug.openocdPath.linux": "${workspaceFolder}/toolchain/x86_64-linux/openocd/bin/openocd", "cortex-debug.openocdPath.osx": "${workspaceFolder}/toolchain/x86_64-darwin/openocd/bin/openocd", + "cortex-debug.gdbPath.windows": "${workspaceFolder}/toolchain/i686-windows/bin/arm-none-eabi-gdb-py.bat", + "cortex-debug.gdbPath.linux": "${workspaceFolder}/toolchain/x86_64-linux/bin/arm-none-eabi-gdb-py", + "cortex-debug.gdbPath.osx": "${workspaceFolder}/toolchain/x86_64-darwin/bin/arm-none-eabi-gdb-py", "editor.formatOnSave": true, "files.associations": { "*.scons": "python", @@ -19,4 +22,4 @@ "SConstruct": "python", "*.fam": "python", } -} \ No newline at end of file +} diff --git a/.vscode/example/tasks.json b/.vscode/example/tasks.json index 32efa0068..3946d05cc 100644 --- a/.vscode/example/tasks.json +++ b/.vscode/example/tasks.json @@ -93,11 +93,41 @@ "type": "shell", "command": "./fbt FIRMWARE_APP_SET=unit_tests FORCE=1 flash_usb" }, + { + "label": "[Debug] Flash (USB, with resources)", + "group": "build", + "type": "shell", + "command": "./fbt FORCE=1 flash_usb_full" + }, { "label": "[Release] Flash (USB, with resources)", "group": "build", "type": "shell", "command": "./fbt COMPACT=1 DEBUG=0 FORCE=1 flash_usb_full" }, + { + "label": "[Debug] Build FAPs", + "group": "build", + "type": "shell", + "command": "./fbt plugin_dist" + }, + { + "label": "[Release] Build FAPs", + "group": "build", + "type": "shell", + "command": "./fbt COMPACT=1 DEBUG=0 plugin_dist" + }, + { + "label": "[Debug] Launch App on Flipper", + "group": "build", + "type": "shell", + "command": "./fbt launch_app APPSRC=${relativeFileDirname}" + }, + { + "label": "[Release] Launch App on Flipper", + "group": "build", + "type": "shell", + "command": "./fbt COMPACT=1 DEBUG=0 launch_app APPSRC=${relativeFileDirname}" + } ] } \ No newline at end of file diff --git a/ReadMe.md b/ReadMe.md index 7a9777121..e848e18a4 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -14,6 +14,10 @@ You should clone with $ git clone --recursive https://github.com/flipperdevices/flipperzero-firmware.git ``` +# Read the Docs + +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. + # Update firmware [Get Latest Firmware from Update Server](https://update.flipperzero.one/) @@ -74,19 +78,7 @@ brew bundle --verbose ## Linux Prerequisites -### gcc-arm-none-eabi - -```sh -toolchain="gcc-arm-none-eabi-10.3-2021.10" -toolchain_package="$toolchain-$(uname -m)-linux" - -wget -P /opt "https://developer.arm.com/-/media/Files/downloads/gnu-rm/10.3-2021.10/$toolchain_package.tar.bz2" - -tar xjf /opt/$toolchain_package.tar.bz2 -C /opt -rm /opt/$toolchain_package.tar.bz2 - -for file in /opt/$toolchain/bin/* ; do ln -s "${file}" "/usr/bin/$(basename ${file})" ; done -``` +The FBT tool handles everything, only `git` is required. ### Optional dependencies diff --git a/SConstruct b/SConstruct index 52fe75a6a..f39bba686 100644 --- a/SConstruct +++ b/SConstruct @@ -1,5 +1,5 @@ # -# Main Fipper Build System entry point +# Main Flipper Build System entry point # # This file is evaluated by scons (the build system) every time fbt is invoked. # Scons constructs all referenced environments & their targets' dependency @@ -9,13 +9,14 @@ import os import subprocess +DefaultEnvironment(tools=[]) + EnsurePythonVersion(3, 8) -DefaultEnvironment(tools=[]) # Progress(["OwO\r", "owo\r", "uwu\r", "owo\r"], interval=15) -# This environment is created only for loading options & validating file/dir existance +# This environment is created only for loading options & validating file/dir existence fbt_variables = SConscript("site_scons/commandline.scons") cmd_environment = Environment(tools=[], variables=fbt_variables) Help(fbt_variables.GenerateHelpText(cmd_environment)) @@ -58,6 +59,8 @@ distenv = coreenv.Clone( "-ex", "source debug/FreeRTOS/FreeRTOS.py", "-ex", + "source debug/flipperapps.py", + "-ex", "source debug/PyCortexMDebug/PyCortexMDebug.py", "-ex", "svd_load ${SVD_FILE}", @@ -160,6 +163,28 @@ if GetOption("fullenv") or any( basic_dist = distenv.DistCommand("fw_dist", distenv["DIST_DEPENDS"]) distenv.Default(basic_dist) +dist_dir = distenv.GetProjetDirName() +plugin_dist = [ + distenv.Install( + f"#/dist/{dist_dir}/apps/debug_elf", + firmware_env["FW_EXTAPPS"]["debug"].values(), + ), + *( + distenv.Install(f"#/dist/{dist_dir}/apps/{dist_entry[0]}", dist_entry[1]) + for dist_entry in firmware_env["FW_EXTAPPS"]["dist"].values() + ), +] +Depends(plugin_dist, firmware_env["FW_EXTAPPS"]["validators"].values()) +Alias("plugin_dist", plugin_dist) +# distenv.Default(plugin_dist) + +plugin_resources_dist = list( + distenv.Install(f"#/assets/resources/apps/{dist_entry[0]}", dist_entry[1]) + for dist_entry in firmware_env["FW_EXTAPPS"]["dist"].values() +) +distenv.Depends(firmware_env["FW_RESOURCES"], plugin_resources_dist) + + # Target for bundling core2 package for qFlipper copro_dist = distenv.CoproBuilder( distenv.Dir("assets/core2_firmware"), @@ -240,7 +265,6 @@ firmware_env.Append( "site_scons", "scripts", # Extra files - "applications/extapps.scons", "SConstruct", "firmware.scons", "fbt_options.py", diff --git a/applications/ReadMe.md b/applications/ReadMe.md index cb2f5628d..6224cb45a 100644 --- a/applications/ReadMe.md +++ b/applications/ReadMe.md @@ -1,38 +1,89 @@ # Structure -- `about` - Small About application that shows flipper info -- `accessor` - Wiegand server +## debug + +Applications for factory testing the Flipper. + +- `accessor` - Wiegand server +- `battery_test_app` - Battery debug app +- `blink_test` - LED blinker +- `bt_debug_app` - BT test app. Requires full BT stack installed +- `display_test` - Various display tests & tweaks +- `file_browser_test` - Test UI for file picker +- `keypad_test` - Keypad test +- `lfrfid_debug` - LF RFID debug tool +- `text_box_test` - UI tests +- `uart_echo` - UART mode test +- `unit_tests` - Unit tests +- `usb_mouse` - USB HID test +- `usb_test` - Other USB tests +- `vibro_test` - Vibro test + + +## main + +Applications for main Flipper menu. + - `archive` - Archive and file manager - `bad_usb` - Bad USB application +- `fap_loader` - External applications loader +- `gpio` - GPIO application: includes USART bridge and GPIO control +- `ibutton` - iButton application, onewire keys and more +- `infrared` - Infrared application, controls your IR devices +- `lfrfid` - LF RFID application +- `nfc` - NFC application, HF rfid, EMV and etc +- `subghz` - SubGhz application, 433 fobs and etc +- `u2f` - U2F Application + + +## plugins + +Extra apps for Plugins & App Loader menus. + +- `bt_hid_app` - BT Remote controller +- `music_player` - Music player app (demo) +- `picopass` - Picopass tool +- `snake_game` - Snake game application + + +## services + +Background services providing system APIs to applications. + +- `applications.h` - Firmware application list header + - `bt` - BLE service and application - `cli` - Console service and API - `crypto` - Crypto cli tools -- `debug_tools` - Different tools that we use for debug - `desktop` - Desktop service - `dialogs` - Dialogs service: GUI Dialogs for your app - `dolphin` - Dolphin service and supplementary apps -- `gpio` - GPIO application: includes USART bridge and GPIO control - `gui` - GUI service and API -- `ibutton` - iButton application, onewire keys and more - `input` - Input service -- `infrared` - Infrared application, controls your IR devices -- `lfrfid` - LF RFID application -- `lfrfid_debug` - LF RFID debug tool - `loader` - Application loader service -- `music_player` - Music player app (demo) -- `nfc` - NFC application, HF rfid, EMV and etc - `notification` - Notification service - `power` - Power service -- `power_observer` - Power debug tool - `rpc` - RPC service and API -- `scened_app_example` - C++ application example -- `snake_game` - Snake game application - `storage` - Storage service, internal + sdcard -- `storage_settings` - Storage settings app -- `subghz` - SubGhz application, 433 fobs and etc -- `system` - System settings, tools and API -- `tests` - Unit tests and etc -- `u2f` - U2F Application -- `updater` - Update service & application -- `application.h` - Firmware application list header + +## settings + +Small applications providing configuration for basic firmware and its services. + +- `about` - Small About application that shows flipper info +- `bt_settings_app` - Bluetooth options +- `desktop_settings` - Desktop configuration +- `dolphin_passport` - Dolphin passport app +- `notification_settings` - LCD brightness, sound volume, etc configuration +- `power_settings_app` - Basic power options +- `storage_settings` - Storage settings app +- `system` - System settings + + +## system + +Utility apps not visible in other menus. + +- `storage_move_to_sd` - Data migration tool for internal storage +- `updater` - Update service & application diff --git a/applications/bt/application.fam b/applications/bt/application.fam deleted file mode 100644 index 248386ff3..000000000 --- a/applications/bt/application.fam +++ /dev/null @@ -1,66 +0,0 @@ -App( - appid="bt", - name="BtSrv", - apptype=FlipperAppType.SERVICE, - entry_point="bt_srv", - cdefines=["SRV_BT"], - requires=[ - "cli", - "dialogs", - ], - provides=[ - "bt_start", - "bt_settings", - "bt_debug", - ], - stack_size=1 * 1024, - order=20, -) - -App( - appid="bt_start", - apptype=FlipperAppType.STARTUP, - entry_point="bt_on_system_start", - order=70, -) - -App( - appid="bt_settings", - name="Bluetooth", - apptype=FlipperAppType.SETTINGS, - entry_point="bt_settings_app", - stack_size=1 * 1024, - requires=[ - "bt", - "gui", - ], - order=10, -) - -App( - appid="bt_debug", - name="Bluetooth Debug", - apptype=FlipperAppType.DEBUG, - entry_point="bt_debug_app", - stack_size=1 * 1024, - requires=[ - "bt", - "gui", - "dialogs", - ], - order=110, -) - -App( - appid="bt_hid", - name="Bluetooth Remote", - apptype=FlipperAppType.PLUGIN, - entry_point="bt_hid_app", - stack_size=1 * 1024, - cdefines=["APP_BLE_HID"], - requires=[ - "bt", - "gui", - ], - order=10, -) diff --git a/applications/accessor/accessor.cpp b/applications/debug/accessor/accessor.cpp similarity index 100% rename from applications/accessor/accessor.cpp rename to applications/debug/accessor/accessor.cpp diff --git a/applications/accessor/accessor_app.cpp b/applications/debug/accessor/accessor_app.cpp similarity index 100% rename from applications/accessor/accessor_app.cpp rename to applications/debug/accessor/accessor_app.cpp diff --git a/applications/accessor/accessor_app.h b/applications/debug/accessor/accessor_app.h similarity index 100% rename from applications/accessor/accessor_app.h rename to applications/debug/accessor/accessor_app.h diff --git a/applications/accessor/accessor_event.h b/applications/debug/accessor/accessor_event.h similarity index 100% rename from applications/accessor/accessor_event.h rename to applications/debug/accessor/accessor_event.h diff --git a/applications/accessor/accessor_view_manager.cpp b/applications/debug/accessor/accessor_view_manager.cpp similarity index 100% rename from applications/accessor/accessor_view_manager.cpp rename to applications/debug/accessor/accessor_view_manager.cpp diff --git a/applications/accessor/accessor_view_manager.h b/applications/debug/accessor/accessor_view_manager.h similarity index 100% rename from applications/accessor/accessor_view_manager.h rename to applications/debug/accessor/accessor_view_manager.h diff --git a/applications/accessor/application.fam b/applications/debug/accessor/application.fam similarity index 88% rename from applications/accessor/application.fam rename to applications/debug/accessor/application.fam index 8a94049e1..93fc9bc3f 100644 --- a/applications/accessor/application.fam +++ b/applications/debug/accessor/application.fam @@ -7,4 +7,5 @@ App( requires=["gui"], stack_size=4 * 1024, order=40, + fap_category="Debug", ) diff --git a/applications/accessor/helpers/wiegand.cpp b/applications/debug/accessor/helpers/wiegand.cpp similarity index 100% rename from applications/accessor/helpers/wiegand.cpp rename to applications/debug/accessor/helpers/wiegand.cpp diff --git a/applications/accessor/helpers/wiegand.h b/applications/debug/accessor/helpers/wiegand.h similarity index 100% rename from applications/accessor/helpers/wiegand.h rename to applications/debug/accessor/helpers/wiegand.h diff --git a/applications/accessor/scene/accessor_scene_generic.h b/applications/debug/accessor/scene/accessor_scene_generic.h similarity index 100% rename from applications/accessor/scene/accessor_scene_generic.h rename to applications/debug/accessor/scene/accessor_scene_generic.h diff --git a/applications/accessor/scene/accessor_scene_start.cpp b/applications/debug/accessor/scene/accessor_scene_start.cpp similarity index 100% rename from applications/accessor/scene/accessor_scene_start.cpp rename to applications/debug/accessor/scene/accessor_scene_start.cpp diff --git a/applications/accessor/scene/accessor_scene_start.h b/applications/debug/accessor/scene/accessor_scene_start.h similarity index 100% rename from applications/accessor/scene/accessor_scene_start.h rename to applications/debug/accessor/scene/accessor_scene_start.h diff --git a/applications/debug/application.fam b/applications/debug/application.fam new file mode 100644 index 000000000..a33b3693d --- /dev/null +++ b/applications/debug/application.fam @@ -0,0 +1,16 @@ +App( + appid="debug_apps", + name="Basic debug apps bundle", + apptype=FlipperAppType.METAPACKAGE, + provides=[ + "blink_test", + "vibro_test", + "keypad_test", + "usb_test", + "usb_mouse", + "uart_echo", + "display_test", + "text_box_test", + "file_browser_test", + ], +) diff --git a/applications/debug/battery_test_app/application.fam b/applications/debug/battery_test_app/application.fam new file mode 100644 index 000000000..b388445cc --- /dev/null +++ b/applications/debug/battery_test_app/application.fam @@ -0,0 +1,14 @@ +App( + appid="battery_test", + name="Battery Test", + apptype=FlipperAppType.DEBUG, + entry_point="battery_test_app", + cdefines=["APP_BATTERY_TEST"], + requires=[ + "gui", + "power", + ], + stack_size=1 * 1024, + order=130, + fap_category="Debug", +) diff --git a/applications/power/battery_test_app/battery_test_app.c b/applications/debug/battery_test_app/battery_test_app.c old mode 100755 new mode 100644 similarity index 92% rename from applications/power/battery_test_app/battery_test_app.c rename to applications/debug/battery_test_app/battery_test_app.c index ab6889dc8..eabf3c04b --- a/applications/power/battery_test_app/battery_test_app.c +++ b/applications/debug/battery_test_app/battery_test_app.c @@ -27,7 +27,7 @@ static void battery_test_battery_info_update_model(void* context) { .charge = app->info.charge, .health = app->info.health, }; - battery_info_set_data(app->batery_info, &battery_info_data); + battery_info_set_data(app->battery_info, &battery_info_data); notification_message(app->notifications, &sequence_display_backlight_on); } @@ -48,13 +48,13 @@ BatteryTestApp* battery_test_alloc() { view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); // Views - app->batery_info = battery_info_alloc(); + app->battery_info = battery_info_alloc(); view_set_previous_callback( - battery_info_get_view(app->batery_info), battery_test_exit_confirm_view); + battery_info_get_view(app->battery_info), battery_test_exit_confirm_view); view_dispatcher_add_view( app->view_dispatcher, BatteryTestAppViewBatteryInfo, - battery_info_get_view(app->batery_info)); + battery_info_get_view(app->battery_info)); app->dialog = dialog_ex_alloc(); dialog_ex_set_header(app->dialog, "Close Battery Test?", 64, 12, AlignCenter, AlignTop); @@ -76,7 +76,7 @@ void battery_test_free(BatteryTestApp* app) { // Views view_dispatcher_remove_view(app->view_dispatcher, BatteryTestAppViewBatteryInfo); - battery_info_free(app->batery_info); + battery_info_free(app->battery_info); view_dispatcher_remove_view(app->view_dispatcher, BatteryTestAppViewExitDialog); dialog_ex_free(app->dialog); // View dispatcher diff --git a/applications/power/battery_test_app/battery_test_app.h b/applications/debug/battery_test_app/battery_test_app.h similarity index 82% rename from applications/power/battery_test_app/battery_test_app.h rename to applications/debug/battery_test_app/battery_test_app.h index 9c17626da..497cdde82 100644 --- a/applications/power/battery_test_app/battery_test_app.h +++ b/applications/debug/battery_test_app/battery_test_app.h @@ -6,14 +6,15 @@ #include #include -#include +// FIXME +#include "../settings/power_settings_app/views/battery_info.h" typedef struct { Power* power; Gui* gui; NotificationApp* notifications; ViewDispatcher* view_dispatcher; - BatteryInfo* batery_info; + BatteryInfo* battery_info; DialogEx* dialog; PowerInfo info; } BatteryTestApp; diff --git a/applications/debug/blink_test/application.fam b/applications/debug/blink_test/application.fam new file mode 100644 index 000000000..c6a8a922a --- /dev/null +++ b/applications/debug/blink_test/application.fam @@ -0,0 +1,11 @@ +App( + appid="blink_test", + name="Blink Test", + apptype=FlipperAppType.DEBUG, + entry_point="blink_test_app", + cdefines=["APP_BLINK"], + requires=["gui"], + stack_size=1 * 1024, + order=10, + fap_category="Debug", +) diff --git a/applications/debug_tools/blink_test.c b/applications/debug/blink_test/blink_test.c similarity index 100% rename from applications/debug_tools/blink_test.c rename to applications/debug/blink_test/blink_test.c diff --git a/applications/debug/bt_debug_app/application.fam b/applications/debug/bt_debug_app/application.fam new file mode 100644 index 000000000..8ed1ccc05 --- /dev/null +++ b/applications/debug/bt_debug_app/application.fam @@ -0,0 +1,18 @@ +App( + appid="bt_debug", + name="Bluetooth Debug", + apptype=FlipperAppType.DEBUG, + entry_point="bt_debug_app", + cdefines=["SRV_BT"], + requires=[ + "bt", + "gui", + "dialogs", + ], + provides=[ + "bt_debug", + ], + stack_size=1 * 1024, + order=110, + fap_category="Debug", +) diff --git a/applications/bt/bt_debug_app/bt_debug_app.c b/applications/debug/bt_debug_app/bt_debug_app.c similarity index 100% rename from applications/bt/bt_debug_app/bt_debug_app.c rename to applications/debug/bt_debug_app/bt_debug_app.c diff --git a/applications/bt/bt_debug_app/bt_debug_app.h b/applications/debug/bt_debug_app/bt_debug_app.h similarity index 95% rename from applications/bt/bt_debug_app/bt_debug_app.h rename to applications/debug/bt_debug_app/bt_debug_app.h index c3657626e..cd59e4d00 100644 --- a/applications/bt/bt_debug_app/bt_debug_app.h +++ b/applications/debug/bt_debug_app/bt_debug_app.h @@ -9,7 +9,7 @@ #include #include "views/bt_carrier_test.h" #include "views/bt_packet_test.h" -#include "../bt_settings.h" +#include typedef struct { BtSettings settings; diff --git a/applications/bt/bt_debug_app/views/bt_carrier_test.c b/applications/debug/bt_debug_app/views/bt_carrier_test.c old mode 100755 new mode 100644 similarity index 100% rename from applications/bt/bt_debug_app/views/bt_carrier_test.c rename to applications/debug/bt_debug_app/views/bt_carrier_test.c diff --git a/applications/bt/bt_debug_app/views/bt_carrier_test.h b/applications/debug/bt_debug_app/views/bt_carrier_test.h similarity index 100% rename from applications/bt/bt_debug_app/views/bt_carrier_test.h rename to applications/debug/bt_debug_app/views/bt_carrier_test.h diff --git a/applications/bt/bt_debug_app/views/bt_packet_test.c b/applications/debug/bt_debug_app/views/bt_packet_test.c similarity index 100% rename from applications/bt/bt_debug_app/views/bt_packet_test.c rename to applications/debug/bt_debug_app/views/bt_packet_test.c diff --git a/applications/bt/bt_debug_app/views/bt_packet_test.h b/applications/debug/bt_debug_app/views/bt_packet_test.h similarity index 100% rename from applications/bt/bt_debug_app/views/bt_packet_test.h rename to applications/debug/bt_debug_app/views/bt_packet_test.h diff --git a/applications/bt/bt_debug_app/views/bt_test.c b/applications/debug/bt_debug_app/views/bt_test.c old mode 100755 new mode 100644 similarity index 100% rename from applications/bt/bt_debug_app/views/bt_test.c rename to applications/debug/bt_debug_app/views/bt_test.c diff --git a/applications/bt/bt_debug_app/views/bt_test.h b/applications/debug/bt_debug_app/views/bt_test.h old mode 100755 new mode 100644 similarity index 100% rename from applications/bt/bt_debug_app/views/bt_test.h rename to applications/debug/bt_debug_app/views/bt_test.h diff --git a/applications/bt/bt_debug_app/views/bt_test_types.h b/applications/debug/bt_debug_app/views/bt_test_types.h similarity index 100% rename from applications/bt/bt_debug_app/views/bt_test_types.h rename to applications/debug/bt_debug_app/views/bt_test_types.h diff --git a/applications/debug/display_test/application.fam b/applications/debug/display_test/application.fam new file mode 100644 index 000000000..4b40322fb --- /dev/null +++ b/applications/debug/display_test/application.fam @@ -0,0 +1,11 @@ +App( + appid="display_test", + name="Display Test", + apptype=FlipperAppType.DEBUG, + entry_point="display_test_app", + cdefines=["APP_DISPLAY_TEST"], + requires=["gui"], + stack_size=1 * 1024, + order=120, + fap_category="Debug", +) diff --git a/applications/debug_tools/display_test/display_test.c b/applications/debug/display_test/display_test.c similarity index 100% rename from applications/debug_tools/display_test/display_test.c rename to applications/debug/display_test/display_test.c diff --git a/applications/debug_tools/display_test/display_test.h b/applications/debug/display_test/display_test.h similarity index 100% rename from applications/debug_tools/display_test/display_test.h rename to applications/debug/display_test/display_test.h diff --git a/applications/debug_tools/display_test/view_display_test.c b/applications/debug/display_test/view_display_test.c similarity index 100% rename from applications/debug_tools/display_test/view_display_test.c rename to applications/debug/display_test/view_display_test.c diff --git a/applications/debug_tools/display_test/view_display_test.h b/applications/debug/display_test/view_display_test.h similarity index 100% rename from applications/debug_tools/display_test/view_display_test.h rename to applications/debug/display_test/view_display_test.h diff --git a/applications/debug/file_browser_test/application.fam b/applications/debug/file_browser_test/application.fam new file mode 100644 index 000000000..5e4c7f467 --- /dev/null +++ b/applications/debug/file_browser_test/application.fam @@ -0,0 +1,11 @@ +App( + appid="file_browser_test", + name="File Browser Test", + apptype=FlipperAppType.DEBUG, + entry_point="file_browser_app", + cdefines=["APP_FILE_BROWSER_TEST"], + requires=["gui"], + stack_size=2 * 1024, + order=150, + fap_category="Debug", +) diff --git a/applications/debug_tools/file_browser_test/file_browser_app.c b/applications/debug/file_browser_test/file_browser_app.c similarity index 100% rename from applications/debug_tools/file_browser_test/file_browser_app.c rename to applications/debug/file_browser_test/file_browser_app.c diff --git a/applications/debug_tools/file_browser_test/file_browser_app_i.h b/applications/debug/file_browser_test/file_browser_app_i.h similarity index 100% rename from applications/debug_tools/file_browser_test/file_browser_app_i.h rename to applications/debug/file_browser_test/file_browser_app_i.h diff --git a/applications/debug_tools/file_browser_test/scenes/file_browser_scene.c b/applications/debug/file_browser_test/scenes/file_browser_scene.c similarity index 100% rename from applications/debug_tools/file_browser_test/scenes/file_browser_scene.c rename to applications/debug/file_browser_test/scenes/file_browser_scene.c diff --git a/applications/debug_tools/file_browser_test/scenes/file_browser_scene.h b/applications/debug/file_browser_test/scenes/file_browser_scene.h similarity index 100% rename from applications/debug_tools/file_browser_test/scenes/file_browser_scene.h rename to applications/debug/file_browser_test/scenes/file_browser_scene.h diff --git a/applications/debug_tools/file_browser_test/scenes/file_browser_scene_browser.c b/applications/debug/file_browser_test/scenes/file_browser_scene_browser.c similarity index 100% rename from applications/debug_tools/file_browser_test/scenes/file_browser_scene_browser.c rename to applications/debug/file_browser_test/scenes/file_browser_scene_browser.c diff --git a/applications/debug_tools/file_browser_test/scenes/file_browser_scene_config.h b/applications/debug/file_browser_test/scenes/file_browser_scene_config.h similarity index 100% rename from applications/debug_tools/file_browser_test/scenes/file_browser_scene_config.h rename to applications/debug/file_browser_test/scenes/file_browser_scene_config.h diff --git a/applications/debug_tools/file_browser_test/scenes/file_browser_scene_result.c b/applications/debug/file_browser_test/scenes/file_browser_scene_result.c similarity index 100% rename from applications/debug_tools/file_browser_test/scenes/file_browser_scene_result.c rename to applications/debug/file_browser_test/scenes/file_browser_scene_result.c diff --git a/applications/debug_tools/file_browser_test/scenes/file_browser_scene_start.c b/applications/debug/file_browser_test/scenes/file_browser_scene_start.c similarity index 100% rename from applications/debug_tools/file_browser_test/scenes/file_browser_scene_start.c rename to applications/debug/file_browser_test/scenes/file_browser_scene_start.c diff --git a/applications/debug/keypad_test/application.fam b/applications/debug/keypad_test/application.fam new file mode 100644 index 000000000..6859af26f --- /dev/null +++ b/applications/debug/keypad_test/application.fam @@ -0,0 +1,11 @@ +App( + appid="keypad_test", + name="Keypad Test", + apptype=FlipperAppType.DEBUG, + entry_point="keypad_test_app", + cdefines=["APP_KEYPAD_TEST"], + requires=["gui"], + stack_size=1 * 1024, + order=30, + fap_category="Debug", +) diff --git a/applications/debug_tools/keypad_test.c b/applications/debug/keypad_test/keypad_test.c similarity index 100% rename from applications/debug_tools/keypad_test.c rename to applications/debug/keypad_test/keypad_test.c diff --git a/applications/lfrfid_debug/application.fam b/applications/debug/lfrfid_debug/application.fam similarity index 74% rename from applications/lfrfid_debug/application.fam rename to applications/debug/lfrfid_debug/application.fam index 910f65cf3..6844f9291 100644 --- a/applications/lfrfid_debug/application.fam +++ b/applications/debug/lfrfid_debug/application.fam @@ -5,8 +5,11 @@ App( entry_point="lfrfid_debug_app", requires=[ "gui", - "lfrfid", + ], + provides=[ + "lfrfid_debug", ], stack_size=1 * 1024, order=100, + fap_category="Debug", ) diff --git a/applications/debug/lfrfid_debug/lfrfid_debug.c b/applications/debug/lfrfid_debug/lfrfid_debug.c new file mode 100644 index 000000000..63d66b68b --- /dev/null +++ b/applications/debug/lfrfid_debug/lfrfid_debug.c @@ -0,0 +1,81 @@ +#include "lfrfid_debug_i.h" + +static bool lfrfid_debug_custom_event_callback(void* context, uint32_t event) { + furi_assert(context); + LfRfidDebug* app = context; + return scene_manager_handle_custom_event(app->scene_manager, event); +} + +static bool lfrfid_debug_back_event_callback(void* context) { + furi_assert(context); + LfRfidDebug* app = context; + return scene_manager_handle_back_event(app->scene_manager); +} + +static LfRfidDebug* lfrfid_debug_alloc() { + LfRfidDebug* app = malloc(sizeof(LfRfidDebug)); + + app->view_dispatcher = view_dispatcher_alloc(); + app->scene_manager = scene_manager_alloc(&lfrfid_debug_scene_handlers, app); + view_dispatcher_enable_queue(app->view_dispatcher); + view_dispatcher_set_event_callback_context(app->view_dispatcher, app); + view_dispatcher_set_custom_event_callback( + app->view_dispatcher, lfrfid_debug_custom_event_callback); + view_dispatcher_set_navigation_event_callback( + app->view_dispatcher, lfrfid_debug_back_event_callback); + + // Open GUI record + app->gui = furi_record_open(RECORD_GUI); + view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); + + // Submenu + app->submenu = submenu_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, LfRfidDebugViewSubmenu, submenu_get_view(app->submenu)); + + // Tune view + app->tune_view = lfrfid_debug_view_tune_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, + LfRfidDebugViewTune, + lfrfid_debug_view_tune_get_view(app->tune_view)); + + return app; +} + +static void lfrfid_debug_free(LfRfidDebug* app) { + furi_assert(app); + + // Submenu + view_dispatcher_remove_view(app->view_dispatcher, LfRfidDebugViewSubmenu); + submenu_free(app->submenu); + + // Tune view + view_dispatcher_remove_view(app->view_dispatcher, LfRfidDebugViewTune); + lfrfid_debug_view_tune_free(app->tune_view); + + // View Dispatcher + view_dispatcher_free(app->view_dispatcher); + + // Scene Manager + scene_manager_free(app->scene_manager); + + // GUI + furi_record_close(RECORD_GUI); + app->gui = NULL; + + free(app); +} + +int32_t lfrfid_debug_app(void* p) { + UNUSED(p); + LfRfidDebug* app = lfrfid_debug_alloc(); + + scene_manager_next_scene(app->scene_manager, LfRfidDebugSceneStart); + + view_dispatcher_run(app->view_dispatcher); + + lfrfid_debug_free(app); + + return 0; +} \ No newline at end of file diff --git a/applications/debug/lfrfid_debug/lfrfid_debug_i.h b/applications/debug/lfrfid_debug/lfrfid_debug_i.h new file mode 100644 index 000000000..8e4e72388 --- /dev/null +++ b/applications/debug/lfrfid_debug/lfrfid_debug_i.h @@ -0,0 +1,30 @@ +#pragma once +#include +#include + +#include +#include +#include +#include + +#include + +#include "views/lfrfid_debug_view_tune.h" +#include "scenes/lfrfid_debug_scene.h" + +typedef struct LfRfidDebug LfRfidDebug; + +struct LfRfidDebug { + Gui* gui; + ViewDispatcher* view_dispatcher; + SceneManager* scene_manager; + + // Common Views + Submenu* submenu; + LfRfidTuneView* tune_view; +}; + +typedef enum { + LfRfidDebugViewSubmenu, + LfRfidDebugViewTune, +} LfRfidDebugView; diff --git a/applications/debug/lfrfid_debug/scenes/lfrfid_debug_app_scene_start.c b/applications/debug/lfrfid_debug/scenes/lfrfid_debug_app_scene_start.c new file mode 100644 index 000000000..2fc6706e3 --- /dev/null +++ b/applications/debug/lfrfid_debug/scenes/lfrfid_debug_app_scene_start.c @@ -0,0 +1,44 @@ +#include "../lfrfid_debug_i.h" + +typedef enum { + SubmenuIndexTune, +} SubmenuIndex; + +static void lfrfid_debug_scene_start_submenu_callback(void* context, uint32_t index) { + LfRfidDebug* app = context; + + view_dispatcher_send_custom_event(app->view_dispatcher, index); +} + +void lfrfid_debug_scene_start_on_enter(void* context) { + LfRfidDebug* app = context; + Submenu* submenu = app->submenu; + + submenu_add_item( + submenu, "Tune", SubmenuIndexTune, lfrfid_debug_scene_start_submenu_callback, app); + + submenu_set_selected_item( + submenu, scene_manager_get_scene_state(app->scene_manager, LfRfidDebugSceneStart)); + + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidDebugViewSubmenu); +} + +bool lfrfid_debug_scene_start_on_event(void* context, SceneManagerEvent event) { + LfRfidDebug* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexTune) { + scene_manager_next_scene(app->scene_manager, LfRfidDebugSceneTune); + consumed = true; + } + } + + return consumed; +} + +void lfrfid_debug_scene_start_on_exit(void* context) { + LfRfidDebug* app = context; + + submenu_reset(app->submenu); +} diff --git a/applications/lfrfid_debug/scene/lfrfid_debug_app_scene_tune.cpp b/applications/debug/lfrfid_debug/scenes/lfrfid_debug_app_scene_tune.c similarity index 53% rename from applications/lfrfid_debug/scene/lfrfid_debug_app_scene_tune.cpp rename to applications/debug/lfrfid_debug/scenes/lfrfid_debug_app_scene_tune.c index 4b6276497..c7f3bf24f 100644 --- a/applications/lfrfid_debug/scene/lfrfid_debug_app_scene_tune.cpp +++ b/applications/debug/lfrfid_debug/scenes/lfrfid_debug_app_scene_tune.c @@ -1,4 +1,4 @@ -#include "lfrfid_debug_app_scene_tune.h" +#include "../lfrfid_debug_i.h" #include static void comparator_trigger_callback(bool level, void* comp_ctx) { @@ -6,32 +6,38 @@ static void comparator_trigger_callback(bool level, void* comp_ctx) { furi_hal_gpio_write(&gpio_ext_pa7, !level); } -void LfRfidDebugAppSceneTune::on_enter(LfRfidDebugApp* app, bool /* need_restore */) { - app->view_controller.switch_to(); +void lfrfid_debug_scene_tune_on_enter(void* context) { + LfRfidDebug* app = context; + furi_hal_gpio_init_simple(&gpio_ext_pa7, GpioModeOutputPushPull); - furi_hal_rfid_comp_set_callback(comparator_trigger_callback, this); + furi_hal_rfid_comp_set_callback(comparator_trigger_callback, app); furi_hal_rfid_comp_start(); furi_hal_rfid_pins_read(); furi_hal_rfid_tim_read(125000, 0.5); furi_hal_rfid_tim_read_start(); + + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidDebugViewTune); } -bool LfRfidDebugAppSceneTune::on_event(LfRfidDebugApp* app, LfRfidDebugApp::Event* /* event */) { +bool lfrfid_debug_scene_tune_on_event(void* context, SceneManagerEvent event) { + UNUSED(event); + + LfRfidDebug* app = context; bool consumed = false; - LfRfidViewTuneVM* tune = app->view_controller; - - if(tune->is_dirty()) { - furi_hal_rfid_set_read_period(tune->get_ARR()); - furi_hal_rfid_set_read_pulse(tune->get_CCR()); + if(lfrfid_debug_view_tune_is_dirty(app->tune_view)) { + furi_hal_rfid_set_read_period(lfrfid_debug_view_tune_get_arr(app->tune_view)); + furi_hal_rfid_set_read_pulse(lfrfid_debug_view_tune_get_ccr(app->tune_view)); } return consumed; } -void LfRfidDebugAppSceneTune::on_exit(LfRfidDebugApp* /* app */) { +void lfrfid_debug_scene_tune_on_exit(void* context) { + UNUSED(context); + furi_hal_rfid_comp_stop(); furi_hal_rfid_comp_set_callback(NULL, NULL); diff --git a/applications/debug/lfrfid_debug/scenes/lfrfid_debug_scene.c b/applications/debug/lfrfid_debug/scenes/lfrfid_debug_scene.c new file mode 100644 index 000000000..e6288e923 --- /dev/null +++ b/applications/debug/lfrfid_debug/scenes/lfrfid_debug_scene.c @@ -0,0 +1,30 @@ +#include "lfrfid_debug_scene.h" + +// Generate scene on_enter handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter, +void (*const lfrfid_debug_on_enter_handlers[])(void*) = { +#include "lfrfid_debug_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_event handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event, +bool (*const lfrfid_debug_on_event_handlers[])(void* context, SceneManagerEvent event) = { +#include "lfrfid_debug_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_exit handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit, +void (*const lfrfid_debug_on_exit_handlers[])(void* context) = { +#include "lfrfid_debug_scene_config.h" +}; +#undef ADD_SCENE + +// Initialize scene handlers configuration structure +const SceneManagerHandlers lfrfid_debug_scene_handlers = { + .on_enter_handlers = lfrfid_debug_on_enter_handlers, + .on_event_handlers = lfrfid_debug_on_event_handlers, + .on_exit_handlers = lfrfid_debug_on_exit_handlers, + .scene_num = LfRfidDebugSceneNum, +}; diff --git a/applications/debug/lfrfid_debug/scenes/lfrfid_debug_scene.h b/applications/debug/lfrfid_debug/scenes/lfrfid_debug_scene.h new file mode 100644 index 000000000..8fc74f724 --- /dev/null +++ b/applications/debug/lfrfid_debug/scenes/lfrfid_debug_scene.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +// Generate scene id and total number +#define ADD_SCENE(prefix, name, id) LfRfidDebugScene##id, +typedef enum { +#include "lfrfid_debug_scene_config.h" + LfRfidDebugSceneNum, +} LfRfidDebugScene; +#undef ADD_SCENE + +extern const SceneManagerHandlers lfrfid_debug_scene_handlers; + +// Generate scene on_enter handlers declaration +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*); +#include "lfrfid_debug_scene_config.h" +#undef ADD_SCENE + +// Generate scene on_event handlers declaration +#define ADD_SCENE(prefix, name, id) \ + bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event); +#include "lfrfid_debug_scene_config.h" +#undef ADD_SCENE + +// Generate scene on_exit handlers declaration +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context); +#include "lfrfid_debug_scene_config.h" +#undef ADD_SCENE diff --git a/applications/debug/lfrfid_debug/scenes/lfrfid_debug_scene_config.h b/applications/debug/lfrfid_debug/scenes/lfrfid_debug_scene_config.h new file mode 100644 index 000000000..f3cca47b8 --- /dev/null +++ b/applications/debug/lfrfid_debug/scenes/lfrfid_debug_scene_config.h @@ -0,0 +1,2 @@ +ADD_SCENE(lfrfid_debug, start, Start) +ADD_SCENE(lfrfid_debug, tune, Tune) diff --git a/applications/debug/lfrfid_debug/views/lfrfid_debug_view_tune.c b/applications/debug/lfrfid_debug/views/lfrfid_debug_view_tune.c new file mode 100644 index 000000000..38fe36036 --- /dev/null +++ b/applications/debug/lfrfid_debug/views/lfrfid_debug_view_tune.c @@ -0,0 +1,229 @@ +#include "lfrfid_debug_view_tune.h" +#include + +#define TEMP_STR_LEN 128 + +struct LfRfidTuneView { + View* view; +}; + +typedef struct { + bool dirty; + bool fine; + uint32_t ARR; + uint32_t CCR; + int pos; +} LfRfidTuneViewModel; + +static void lfrfid_debug_view_tune_draw_callback(Canvas* canvas, void* _model) { + LfRfidTuneViewModel* model = _model; + canvas_set_color(canvas, ColorBlack); + + if(model->fine) { + canvas_draw_box( + canvas, + 128 - canvas_string_width(canvas, "Fine") - 4, + 0, + canvas_string_width(canvas, "Fine") + 4, + canvas_current_font_height(canvas) + 1); + canvas_set_color(canvas, ColorWhite); + } + canvas_draw_str_aligned(canvas, 128 - 2, 2, AlignRight, AlignTop, "Fine"); + canvas_set_color(canvas, ColorBlack); + + char buffer[TEMP_STR_LEN + 1]; + double freq = ((float)SystemCoreClock / ((float)model->ARR + 1)); + double duty = ((float)model->CCR + 1) / ((float)model->ARR + 1) * 100.0f; + snprintf( + buffer, + TEMP_STR_LEN, + "%sARR: %lu\n" + "freq = %.4f\n" + "%sCCR: %lu\n" + "duty = %.4f", + model->pos == 0 ? ">" : "", + model->ARR, + freq, + model->pos == 1 ? ">" : "", + model->CCR, + duty); + elements_multiline_text_aligned(canvas, 2, 2, AlignLeft, AlignTop, buffer); +} + +static void lfrfid_debug_view_tune_button_up(LfRfidTuneView* tune_view) { + with_view_model( + tune_view->view, (LfRfidTuneViewModel * model) { + if(model->pos > 0) model->pos--; + return true; + }); +} + +static void lfrfid_debug_view_tune_button_down(LfRfidTuneView* tune_view) { + with_view_model( + tune_view->view, (LfRfidTuneViewModel * model) { + if(model->pos < 1) model->pos++; + return true; + }); +} + +static void lfrfid_debug_view_tune_button_left(LfRfidTuneView* tune_view) { + with_view_model( + tune_view->view, (LfRfidTuneViewModel * model) { + if(model->pos == 0) { + if(model->fine) { + model->ARR -= 1; + } else { + model->ARR -= 10; + } + } else if(model->pos == 1) { + if(model->fine) { + model->CCR -= 1; + } else { + model->CCR -= 10; + } + } + + model->dirty = true; + return true; + }); +} + +static void lfrfid_debug_view_tune_button_right(LfRfidTuneView* tune_view) { + with_view_model( + tune_view->view, (LfRfidTuneViewModel * model) { + if(model->pos == 0) { + if(model->fine) { + model->ARR += 1; + } else { + model->ARR += 10; + } + } else if(model->pos == 1) { + if(model->fine) { + model->CCR += 1; + } else { + model->CCR += 10; + } + } + + model->dirty = true; + return true; + }); +} + +static void lfrfid_debug_view_tune_button_ok(LfRfidTuneView* tune_view) { + with_view_model( + tune_view->view, (LfRfidTuneViewModel * model) { + model->fine = !model->fine; + return true; + }); +} + +static bool lfrfid_debug_view_tune_input_callback(InputEvent* event, void* context) { + LfRfidTuneView* tune_view = context; + bool consumed = false; + + // Process key presses only + if(event->type == InputTypeShort || event->type == InputTypeRepeat) { + consumed = true; + + switch(event->key) { + case InputKeyLeft: + lfrfid_debug_view_tune_button_left(tune_view); + break; + case InputKeyRight: + lfrfid_debug_view_tune_button_right(tune_view); + break; + case InputKeyUp: + lfrfid_debug_view_tune_button_up(tune_view); + break; + case InputKeyDown: + lfrfid_debug_view_tune_button_down(tune_view); + break; + case InputKeyOk: + lfrfid_debug_view_tune_button_ok(tune_view); + break; + default: + consumed = false; + break; + } + } + + return consumed; +} + +LfRfidTuneView* lfrfid_debug_view_tune_alloc() { + LfRfidTuneView* tune_view = malloc(sizeof(LfRfidTuneView)); + tune_view->view = view_alloc(); + view_set_context(tune_view->view, tune_view); + view_allocate_model(tune_view->view, ViewModelTypeLocking, sizeof(LfRfidTuneViewModel)); + + with_view_model( + tune_view->view, (LfRfidTuneViewModel * model) { + model->dirty = true; + model->fine = false; + model->ARR = 511; + model->CCR = 255; + model->pos = 0; + return true; + }); + + view_set_draw_callback(tune_view->view, lfrfid_debug_view_tune_draw_callback); + view_set_input_callback(tune_view->view, lfrfid_debug_view_tune_input_callback); + + return tune_view; +} + +void lfrfid_debug_view_tune_free(LfRfidTuneView* tune_view) { + view_free(tune_view->view); + free(tune_view); +} + +View* lfrfid_debug_view_tune_get_view(LfRfidTuneView* tune_view) { + return tune_view->view; +} + +void lfrfid_debug_view_tune_clean(LfRfidTuneView* tune_view) { + with_view_model( + tune_view->view, (LfRfidTuneViewModel * model) { + model->dirty = true; + model->fine = false; + model->ARR = 511; + model->CCR = 255; + model->pos = 0; + return true; + }); +} + +bool lfrfid_debug_view_tune_is_dirty(LfRfidTuneView* tune_view) { + bool result = false; + with_view_model( + tune_view->view, (LfRfidTuneViewModel * model) { + result = model->dirty; + model->dirty = false; + return false; + }); + + return result; +} + +uint32_t lfrfid_debug_view_tune_get_arr(LfRfidTuneView* tune_view) { + uint32_t result = false; + with_view_model( + tune_view->view, (LfRfidTuneViewModel * model) { + result = model->ARR; + return false; + }); + + return result; +} + +uint32_t lfrfid_debug_view_tune_get_ccr(LfRfidTuneView* tune_view) { + uint32_t result = false; + with_view_model( + tune_view->view, (LfRfidTuneViewModel * model) { + result = model->CCR; + return false; + }); + + return result; +} diff --git a/applications/debug/lfrfid_debug/views/lfrfid_debug_view_tune.h b/applications/debug/lfrfid_debug/views/lfrfid_debug_view_tune.h new file mode 100644 index 000000000..fd6d0b1fe --- /dev/null +++ b/applications/debug/lfrfid_debug/views/lfrfid_debug_view_tune.h @@ -0,0 +1,18 @@ +#pragma once +#include + +typedef struct LfRfidTuneView LfRfidTuneView; + +LfRfidTuneView* lfrfid_debug_view_tune_alloc(); + +void lfrfid_debug_view_tune_free(LfRfidTuneView* tune_view); + +View* lfrfid_debug_view_tune_get_view(LfRfidTuneView* tune_view); + +void lfrfid_debug_view_tune_clean(LfRfidTuneView* tune_view); + +bool lfrfid_debug_view_tune_is_dirty(LfRfidTuneView* tune_view); + +uint32_t lfrfid_debug_view_tune_get_arr(LfRfidTuneView* tune_view); + +uint32_t lfrfid_debug_view_tune_get_ccr(LfRfidTuneView* tune_view); diff --git a/applications/debug/text_box_test/application.fam b/applications/debug/text_box_test/application.fam new file mode 100644 index 000000000..3e54df9cc --- /dev/null +++ b/applications/debug/text_box_test/application.fam @@ -0,0 +1,11 @@ +App( + appid="text_box_test", + name="Text Box Test", + apptype=FlipperAppType.DEBUG, + entry_point="text_box_test_app", + cdefines=["APP_TEXT_BOX_TEST"], + requires=["gui"], + stack_size=1 * 1024, + order=140, + fap_category="Debug", +) diff --git a/applications/debug_tools/text_box_test.c b/applications/debug/text_box_test/text_box_test.c similarity index 100% rename from applications/debug_tools/text_box_test.c rename to applications/debug/text_box_test/text_box_test.c diff --git a/applications/debug/uart_echo/application.fam b/applications/debug/uart_echo/application.fam new file mode 100644 index 000000000..8863a1a94 --- /dev/null +++ b/applications/debug/uart_echo/application.fam @@ -0,0 +1,11 @@ +App( + appid="uart_echo", + name="UART Echo", + apptype=FlipperAppType.DEBUG, + entry_point="uart_echo_app", + cdefines=["APP_UART_ECHO"], + requires=["gui"], + stack_size=2 * 1024, + order=70, + fap_category="Debug", +) diff --git a/applications/debug_tools/uart_echo.c b/applications/debug/uart_echo/uart_echo.c similarity index 100% rename from applications/debug_tools/uart_echo.c rename to applications/debug/uart_echo/uart_echo.c diff --git a/applications/unit_tests/application.fam b/applications/debug/unit_tests/application.fam similarity index 90% rename from applications/unit_tests/application.fam rename to applications/debug/unit_tests/application.fam index 54e6feaee..949bb3fc2 100644 --- a/applications/unit_tests/application.fam +++ b/applications/debug/unit_tests/application.fam @@ -10,7 +10,7 @@ App( App( appid="delay_test", name="Delay Test", - apptype=FlipperAppType.DEBUG, + apptype=FlipperAppType.SYSTEM, entry_point="delay_test_app", stack_size=1 * 1024, requires=["unit_tests"], diff --git a/applications/unit_tests/flipper_format/flipper_format_string_test.c b/applications/debug/unit_tests/flipper_format/flipper_format_string_test.c similarity index 100% rename from applications/unit_tests/flipper_format/flipper_format_string_test.c rename to applications/debug/unit_tests/flipper_format/flipper_format_string_test.c diff --git a/applications/unit_tests/flipper_format/flipper_format_test.c b/applications/debug/unit_tests/flipper_format/flipper_format_test.c similarity index 100% rename from applications/unit_tests/flipper_format/flipper_format_test.c rename to applications/debug/unit_tests/flipper_format/flipper_format_test.c diff --git a/applications/unit_tests/furi/furi_memmgr_test.c b/applications/debug/unit_tests/furi/furi_memmgr_test.c similarity index 100% rename from applications/unit_tests/furi/furi_memmgr_test.c rename to applications/debug/unit_tests/furi/furi_memmgr_test.c diff --git a/applications/unit_tests/furi/furi_pubsub_test.c b/applications/debug/unit_tests/furi/furi_pubsub_test.c similarity index 100% rename from applications/unit_tests/furi/furi_pubsub_test.c rename to applications/debug/unit_tests/furi/furi_pubsub_test.c diff --git a/applications/unit_tests/furi/furi_record_test.c b/applications/debug/unit_tests/furi/furi_record_test.c similarity index 100% rename from applications/unit_tests/furi/furi_record_test.c rename to applications/debug/unit_tests/furi/furi_record_test.c diff --git a/applications/unit_tests/furi/furi_test.c b/applications/debug/unit_tests/furi/furi_test.c similarity index 100% rename from applications/unit_tests/furi/furi_test.c rename to applications/debug/unit_tests/furi/furi_test.c diff --git a/applications/unit_tests/furi/furi_valuemutex_test.c b/applications/debug/unit_tests/furi/furi_valuemutex_test.c similarity index 100% rename from applications/unit_tests/furi/furi_valuemutex_test.c rename to applications/debug/unit_tests/furi/furi_valuemutex_test.c diff --git a/applications/unit_tests/infrared/infrared_test.c b/applications/debug/unit_tests/infrared/infrared_test.c similarity index 100% rename from applications/unit_tests/infrared/infrared_test.c rename to applications/debug/unit_tests/infrared/infrared_test.c diff --git a/applications/unit_tests/lfrfid/bit_lib_test.c b/applications/debug/unit_tests/lfrfid/bit_lib_test.c similarity index 100% rename from applications/unit_tests/lfrfid/bit_lib_test.c rename to applications/debug/unit_tests/lfrfid/bit_lib_test.c diff --git a/applications/unit_tests/lfrfid/lfrfid_protocols.c b/applications/debug/unit_tests/lfrfid/lfrfid_protocols.c similarity index 100% rename from applications/unit_tests/lfrfid/lfrfid_protocols.c rename to applications/debug/unit_tests/lfrfid/lfrfid_protocols.c diff --git a/applications/unit_tests/minunit.h b/applications/debug/unit_tests/minunit.h similarity index 100% rename from applications/unit_tests/minunit.h rename to applications/debug/unit_tests/minunit.h diff --git a/applications/unit_tests/minunit_vars.h b/applications/debug/unit_tests/minunit_vars.h similarity index 100% rename from applications/unit_tests/minunit_vars.h rename to applications/debug/unit_tests/minunit_vars.h diff --git a/applications/unit_tests/minunit_vars_ex.h b/applications/debug/unit_tests/minunit_vars_ex.h similarity index 100% rename from applications/unit_tests/minunit_vars_ex.h rename to applications/debug/unit_tests/minunit_vars_ex.h diff --git a/applications/unit_tests/nfc/nfc_test.c b/applications/debug/unit_tests/nfc/nfc_test.c similarity index 99% rename from applications/unit_tests/nfc/nfc_test.c rename to applications/debug/unit_tests/nfc/nfc_test.c index dcd162d13..e81199920 100644 --- a/applications/unit_tests/nfc/nfc_test.c +++ b/applications/debug/unit_tests/nfc/nfc_test.c @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include #include diff --git a/applications/unit_tests/protocol_dict/protocol_dict_test.c b/applications/debug/unit_tests/protocol_dict/protocol_dict_test.c similarity index 100% rename from applications/unit_tests/protocol_dict/protocol_dict_test.c rename to applications/debug/unit_tests/protocol_dict/protocol_dict_test.c diff --git a/applications/unit_tests/rpc/rpc_test.c b/applications/debug/unit_tests/rpc/rpc_test.c similarity index 100% rename from applications/unit_tests/rpc/rpc_test.c rename to applications/debug/unit_tests/rpc/rpc_test.c diff --git a/applications/unit_tests/storage/dirwalk_test.c b/applications/debug/unit_tests/storage/dirwalk_test.c similarity index 100% rename from applications/unit_tests/storage/dirwalk_test.c rename to applications/debug/unit_tests/storage/dirwalk_test.c diff --git a/applications/unit_tests/storage/storage_test.c b/applications/debug/unit_tests/storage/storage_test.c similarity index 100% rename from applications/unit_tests/storage/storage_test.c rename to applications/debug/unit_tests/storage/storage_test.c diff --git a/applications/unit_tests/stream/stream_test.c b/applications/debug/unit_tests/stream/stream_test.c similarity index 100% rename from applications/unit_tests/stream/stream_test.c rename to applications/debug/unit_tests/stream/stream_test.c diff --git a/applications/unit_tests/subghz/subghz_test.c b/applications/debug/unit_tests/subghz/subghz_test.c similarity index 93% rename from applications/unit_tests/subghz/subghz_test.c rename to applications/debug/unit_tests/subghz/subghz_test.c index 04f442f6c..36f5b94c2 100644 --- a/applications/unit_tests/subghz/subghz_test.c +++ b/applications/debug/unit_tests/subghz/subghz_test.c @@ -13,7 +13,7 @@ #define CAME_ATOMO_DIR_NAME EXT_PATH("subghz/assets/came_atomo") #define NICE_FLOR_S_DIR_NAME EXT_PATH("subghz/assets/nice_flor_s") #define TEST_RANDOM_DIR_NAME EXT_PATH("unit_tests/subghz/test_random_raw.sub") -#define TEST_RANDOM_COUNT_PARSE 196 +#define TEST_RANDOM_COUNT_PARSE 233 #define TEST_TIMEOUT 10000 static SubGhzEnvironment* environment_handler; @@ -127,7 +127,7 @@ static bool subghz_decode_random_test(const char* path) { } subghz_file_encoder_worker_free(file_worker_encoder_handler); } - FURI_LOG_T(TAG, "\r\n Decoder count parse \033[0;33m%d\033[0m ", subghz_test_decoder_count); + FURI_LOG_D(TAG, "\r\n Decoder count parse \033[0;33m%d\033[0m ", subghz_test_decoder_count); if(furi_get_tick() - test_start > TEST_TIMEOUT * 10) { printf("\033[0;31mRandom test ERROR TimeOut\033[0m\r\n"); return false; @@ -419,6 +419,28 @@ MU_TEST(subghz_decoder_magellen_test) { "Test decoder " SUBGHZ_PROTOCOL_MAGELLEN_NAME " error\r\n"); } +MU_TEST(subghz_decoder_intertechno_v3_test) { + mu_assert( + subghz_decoder_test( + EXT_PATH("unit_tests/subghz/intertechno_v3_raw.sub"), + SUBGHZ_PROTOCOL_INTERTECHNO_V3_NAME), + "Test decoder " SUBGHZ_PROTOCOL_INTERTECHNO_V3_NAME " error\r\n"); +} + +MU_TEST(subghz_decoder_clemsa_test) { + mu_assert( + subghz_decoder_test( + EXT_PATH("unit_tests/subghz/clemsa_raw.sub"), SUBGHZ_PROTOCOL_CLEMSA_NAME), + "Test decoder " SUBGHZ_PROTOCOL_CLEMSA_NAME " error\r\n"); +} + +MU_TEST(subghz_decoder_oregon2_test) { + mu_assert( + subghz_decoder_test( + EXT_PATH("unit_tests/subghz/oregon2_raw.sub"), SUBGHZ_PROTOCOL_OREGON2_NAME), + "Test decoder " SUBGHZ_PROTOCOL_OREGON2_NAME " error\r\n"); +} + //test encoders MU_TEST(subghz_encoder_princeton_test) { mu_assert( @@ -528,6 +550,18 @@ MU_TEST(subghz_encoder_magellen_test) { "Test encoder " SUBGHZ_PROTOCOL_MAGELLEN_NAME " error\r\n"); } +MU_TEST(subghz_encoder_intertechno_v3_test) { + mu_assert( + subghz_encoder_test(EXT_PATH("unit_tests/subghz/intertechno_v3.sub")), + "Test encoder " SUBGHZ_PROTOCOL_INTERTECHNO_V3_NAME " error\r\n"); +} + +MU_TEST(subghz_encoder_clemsa_test) { + mu_assert( + subghz_encoder_test(EXT_PATH("unit_tests/subghz/clemsa.sub")), + "Test encoder " SUBGHZ_PROTOCOL_CLEMSA_NAME " error\r\n"); +} + MU_TEST(subghz_random_test) { mu_assert(subghz_decode_random_test(TEST_RANDOM_DIR_NAME), "Random test error\r\n"); } @@ -566,6 +600,9 @@ MU_TEST_SUITE(subghz) { MU_RUN_TEST(subghz_decoder_phoenix_v2_test); MU_RUN_TEST(subghz_decoder_honeywell_wdb_test); MU_RUN_TEST(subghz_decoder_magellen_test); + MU_RUN_TEST(subghz_decoder_intertechno_v3_test); + MU_RUN_TEST(subghz_decoder_clemsa_test); + MU_RUN_TEST(subghz_decoder_oregon2_test); MU_RUN_TEST(subghz_encoder_princeton_test); MU_RUN_TEST(subghz_encoder_came_test); @@ -585,6 +622,8 @@ MU_TEST_SUITE(subghz) { MU_RUN_TEST(subghz_encoder_phoenix_v2_test); MU_RUN_TEST(subghz_encoder_honeywell_wdb_test); MU_RUN_TEST(subghz_encoder_magellen_test); + MU_RUN_TEST(subghz_encoder_intertechno_v3_test); + MU_RUN_TEST(subghz_encoder_clemsa_test); MU_RUN_TEST(subghz_random_test); subghz_test_deinit(); diff --git a/applications/unit_tests/test_index.c b/applications/debug/unit_tests/test_index.c similarity index 100% rename from applications/unit_tests/test_index.c rename to applications/debug/unit_tests/test_index.c diff --git a/applications/unit_tests/varint/varint_test.c b/applications/debug/unit_tests/varint/varint_test.c similarity index 100% rename from applications/unit_tests/varint/varint_test.c rename to applications/debug/unit_tests/varint/varint_test.c diff --git a/applications/debug/usb_mouse/application.fam b/applications/debug/usb_mouse/application.fam new file mode 100644 index 000000000..5c4340045 --- /dev/null +++ b/applications/debug/usb_mouse/application.fam @@ -0,0 +1,11 @@ +App( + appid="usb_mouse", + name="USB Mouse Demo", + apptype=FlipperAppType.DEBUG, + entry_point="usb_mouse_app", + cdefines=["APP_USB_MOUSE"], + requires=["gui"], + stack_size=1 * 1024, + order=60, + fap_category="Debug", +) diff --git a/applications/debug_tools/usb_mouse.c b/applications/debug/usb_mouse/usb_mouse.c similarity index 100% rename from applications/debug_tools/usb_mouse.c rename to applications/debug/usb_mouse/usb_mouse.c diff --git a/applications/debug/usb_test/application.fam b/applications/debug/usb_test/application.fam new file mode 100644 index 000000000..27395c34d --- /dev/null +++ b/applications/debug/usb_test/application.fam @@ -0,0 +1,11 @@ +App( + appid="usb_test", + name="USB Test", + apptype=FlipperAppType.DEBUG, + entry_point="usb_test_app", + cdefines=["APP_USB_TEST"], + requires=["gui"], + stack_size=1 * 1024, + order=50, + fap_category="Debug", +) diff --git a/applications/debug_tools/usb_test.c b/applications/debug/usb_test/usb_test.c similarity index 100% rename from applications/debug_tools/usb_test.c rename to applications/debug/usb_test/usb_test.c diff --git a/applications/debug/vibro_test/application.fam b/applications/debug/vibro_test/application.fam new file mode 100644 index 000000000..f7115cc96 --- /dev/null +++ b/applications/debug/vibro_test/application.fam @@ -0,0 +1,11 @@ +App( + appid="vibro_test", + name="Vibro Test", + apptype=FlipperAppType.DEBUG, + entry_point="vibro_test_app", + cdefines=["APP_VIBRO_TEST"], + requires=["gui"], + stack_size=1 * 1024, + order=20, + fap_category="Debug", +) diff --git a/applications/debug_tools/vibro_test.c b/applications/debug/vibro_test/vibro_test.c similarity index 100% rename from applications/debug_tools/vibro_test.c rename to applications/debug/vibro_test/vibro_test.c diff --git a/applications/debug_tools/application.fam b/applications/debug_tools/application.fam deleted file mode 100644 index 8cb495b0c..000000000 --- a/applications/debug_tools/application.fam +++ /dev/null @@ -1,115 +0,0 @@ -App( - appid="debug_apps", - name="Basic debug apps bundle", - apptype=FlipperAppType.METAPACKAGE, - provides=[ - "blink_test", - "vibro_test", - "keypad_test", - "usb_test", - "usb_mouse", - "uart_echo", - "display_test", - "text_box_test", - "file_browser_test", - ], -) - -App( - appid="blink_test", - name="Blink Test", - apptype=FlipperAppType.DEBUG, - entry_point="blink_test_app", - cdefines=["APP_BLINK"], - requires=["gui"], - stack_size=1 * 1024, - order=10, -) - -App( - appid="vibro_test", - name="Vibro Test", - apptype=FlipperAppType.DEBUG, - entry_point="vibro_test_app", - cdefines=["APP_VIBRO_TEST"], - requires=["gui"], - stack_size=1 * 1024, - order=20, -) - -App( - appid="keypad_test", - name="Keypad Test", - apptype=FlipperAppType.DEBUG, - entry_point="keypad_test_app", - cdefines=["APP_KEYPAD_TEST"], - requires=["gui"], - stack_size=1 * 1024, - order=30, -) - -App( - appid="usb_test", - name="USB Test", - apptype=FlipperAppType.DEBUG, - entry_point="usb_test_app", - cdefines=["APP_USB_TEST"], - requires=["gui"], - stack_size=1 * 1024, - order=50, -) - -App( - appid="usb_mouse", - name="USB Mouse Demo", - apptype=FlipperAppType.DEBUG, - entry_point="usb_mouse_app", - cdefines=["APP_USB_MOUSE"], - requires=["gui"], - stack_size=1 * 1024, - order=60, -) - -App( - appid="uart_echo", - name="UART Echo", - apptype=FlipperAppType.DEBUG, - entry_point="uart_echo_app", - cdefines=["APP_UART_ECHO"], - requires=["gui"], - stack_size=2 * 1024, - order=70, -) - -App( - appid="display_test", - name="Display Test", - apptype=FlipperAppType.DEBUG, - entry_point="display_test_app", - cdefines=["APP_DISPLAY_TEST"], - requires=["gui"], - stack_size=1 * 1024, - order=120, -) - -App( - appid="text_box_test", - name="Text Box Test", - apptype=FlipperAppType.DEBUG, - entry_point="text_box_test_app", - cdefines=["APP_TEXT_BOX_TEST"], - requires=["gui"], - stack_size=1 * 1024, - order=140, -) - -App( - appid="file_browser_test", - name="File Browser Test", - apptype=FlipperAppType.DEBUG, - entry_point="file_browser_app", - cdefines=["APP_FILE_BROWSER_TEST"], - requires=["gui"], - stack_size=2 * 1024, - order=150, -) diff --git a/applications/desktop/views/desktop_view_lock_menu.c b/applications/desktop/views/desktop_view_lock_menu.c deleted file mode 100644 index 97d3c4898..000000000 --- a/applications/desktop/views/desktop_view_lock_menu.c +++ /dev/null @@ -1,130 +0,0 @@ -#include -#include - -#include "../desktop_i.h" -#include "desktop_view_lock_menu.h" - -#define LOCK_MENU_ITEMS_NB 3 - -void desktop_lock_menu_set_callback( - DesktopLockMenuView* lock_menu, - DesktopLockMenuViewCallback callback, - void* context) { - furi_assert(lock_menu); - furi_assert(callback); - lock_menu->callback = callback; - lock_menu->context = context; -} - -void desktop_lock_menu_pin_set(DesktopLockMenuView* lock_menu, bool pin_is_set) { - with_view_model( - lock_menu->view, (DesktopLockMenuViewModel * model) { - model->pin_set = pin_is_set; - return true; - }); -} - -void desktop_lock_menu_set_idx(DesktopLockMenuView* lock_menu, uint8_t idx) { - furi_assert(idx < LOCK_MENU_ITEMS_NB); - with_view_model( - lock_menu->view, (DesktopLockMenuViewModel * model) { - model->idx = idx; - return true; - }); -} - -static void lock_menu_callback(void* context, uint8_t index) { - furi_assert(context); - DesktopLockMenuView* lock_menu = context; - switch(index) { - case 0: // lock - lock_menu->callback(DesktopLockMenuEventLock, lock_menu->context); - break; - case 1: // lock - lock_menu->callback(DesktopLockMenuEventPinLock, lock_menu->context); - break; - default: // wip message - with_view_model( - lock_menu->view, (DesktopLockMenuViewModel * model) { - model->hint_timeout = HINT_TIMEOUT; - return true; - }); - break; - } -} - -void desktop_lock_menu_render(Canvas* canvas, void* model) { - const char* Lockmenu_Items[LOCK_MENU_ITEMS_NB] = {"Lock", "Lock with PIN", "DUMB mode"}; - - DesktopLockMenuViewModel* m = model; - canvas_clear(canvas); - canvas_set_color(canvas, ColorBlack); - canvas_draw_icon(canvas, -57, 0 + STATUS_BAR_Y_SHIFT, &I_DoorLeft_70x55); - canvas_draw_icon(canvas, 116, 0 + STATUS_BAR_Y_SHIFT, &I_DoorRight_70x55); - canvas_set_font(canvas, FontSecondary); - - for(uint8_t i = 0; i < LOCK_MENU_ITEMS_NB; ++i) { - const char* str = Lockmenu_Items[i]; - - if(i == 1 && !m->pin_set) str = "Set PIN"; - if(m->hint_timeout && m->idx == 2 && m->idx == i) str = "Not Implemented"; - - if(str != NULL) - canvas_draw_str_aligned( - canvas, 64, 9 + (i * 17) + STATUS_BAR_Y_SHIFT, AlignCenter, AlignCenter, str); - - if(m->idx == i) elements_frame(canvas, 15, 1 + (i * 17) + STATUS_BAR_Y_SHIFT, 98, 15); - } -} - -View* desktop_lock_menu_get_view(DesktopLockMenuView* lock_menu) { - furi_assert(lock_menu); - return lock_menu->view; -} - -bool desktop_lock_menu_input(InputEvent* event, void* context) { - furi_assert(event); - furi_assert(context); - - DesktopLockMenuView* lock_menu = context; - uint8_t idx; - - if(event->type != InputTypeShort) return false; - with_view_model( - lock_menu->view, (DesktopLockMenuViewModel * model) { - model->hint_timeout = 0; // clear hint timeout - if(event->key == InputKeyUp) { - model->idx = CLAMP(model->idx - 1, LOCK_MENU_ITEMS_NB - 1, 0); - } else if(event->key == InputKeyDown) { - model->idx = CLAMP(model->idx + 1, LOCK_MENU_ITEMS_NB - 1, 0); - } - idx = model->idx; - return true; - }); - - if(event->key == InputKeyBack) { - lock_menu->callback(DesktopLockMenuEventExit, lock_menu->context); - } else if(event->key == InputKeyOk) { - lock_menu_callback(lock_menu, idx); - } - - return true; -} - -DesktopLockMenuView* desktop_lock_menu_alloc() { - DesktopLockMenuView* lock_menu = malloc(sizeof(DesktopLockMenuView)); - lock_menu->view = view_alloc(); - view_allocate_model(lock_menu->view, ViewModelTypeLocking, sizeof(DesktopLockMenuViewModel)); - view_set_context(lock_menu->view, lock_menu); - view_set_draw_callback(lock_menu->view, (ViewDrawCallback)desktop_lock_menu_render); - view_set_input_callback(lock_menu->view, desktop_lock_menu_input); - - return lock_menu; -} - -void desktop_lock_menu_free(DesktopLockMenuView* lock_menu_view) { - furi_assert(lock_menu_view); - - view_free(lock_menu_view->view); - free(lock_menu_view); -} diff --git a/applications/extapps.scons b/applications/extapps.scons deleted file mode 100644 index 11b597576..000000000 --- a/applications/extapps.scons +++ /dev/null @@ -1,58 +0,0 @@ -Import("ENV") - - -from fbt.appmanifest import FlipperAppType - -appenv = ENV.Clone(tools=["fbt_extapps"]) - -appenv.Replace( - LINKER_SCRIPT="application-ext", - STRIPFLAGS=[ - "--strip-debug", - "--strip-unneeded", - "-d", - "-g", - "-S", - ], -) - -appenv.AppendUnique( - CCFLAGS=[ - "-Os", - "-ggdb3", - "-mword-relocations", - "-mlong-calls", - "-fno-common", - "-nostdlib", - "-fvisibility=hidden", - ], - LINKFLAGS=[ - "-r", - "-s", - # "-Bsymbolic", - "-nostartfiles", - "-mlong-calls", - "-fno-common", - "-nostdlib", - "-Wl,--gc-sections", - "-Wl,--no-export-dynamic", - "-fvisibility=hidden", - "-Wl,-e${APP_ENTRY}", - "-Xlinker", - "-Map=${TARGET}.map", - ], -) - - -extapps = [] -for apptype in (FlipperAppType.PLUGIN, FlipperAppType.EXTERNAL): - for app in appenv["APPBUILD"].get_apps_of_type(apptype): - extapps.append(appenv.BuildAppElf(app)) - -# Ugly access to global option -if extra_app_list := GetOption("extra_ext_apps"): - for extra_app in extra_app_list.split(","): - extapps.append(appenv.BuildAppElf(appenv["APPMGR"].get(extra_app))) - -Alias(appenv["FIRMWARE_BUILD_CFG"] + "_extapps", extapps) -Return("extapps") diff --git a/applications/gui/application.fam b/applications/gui/application.fam deleted file mode 100644 index 0116f5b88..000000000 --- a/applications/gui/application.fam +++ /dev/null @@ -1,13 +0,0 @@ -App( - appid="gui", - name="GuiSrv", - apptype=FlipperAppType.SERVICE, - entry_point="gui_srv", - cdefines=["SRV_GUI"], - requires=[ - "input", - "notification", - ], - stack_size=2 * 1024, - order=70, -) diff --git a/applications/gui/modules/dialog.c b/applications/gui/modules/dialog.c deleted file mode 100644 index 5d36f93f7..000000000 --- a/applications/gui/modules/dialog.c +++ /dev/null @@ -1,131 +0,0 @@ -#include "dialog.h" -#include -#include - -struct Dialog { - View* view; - void* context; - DialogResultCallback callback; -}; - -typedef struct { - const char* header_text; - const char* text; - const char* left_text; - const char* right_text; -} DialogModel; - -static void dialog_view_draw_callback(Canvas* canvas, void* _model) { - DialogModel* model = _model; - uint8_t canvas_center = canvas_width(canvas) / 2; - - // Prepare canvas - canvas_clear(canvas); - canvas_set_color(canvas, ColorBlack); - - // Draw header - canvas_set_font(canvas, FontPrimary); - canvas_draw_str_aligned( - canvas, canvas_center, 17, AlignCenter, AlignBottom, model->header_text); - - // Draw text - canvas_set_font(canvas, FontSecondary); - elements_multiline_text_aligned( - canvas, canvas_center, 32, AlignCenter, AlignCenter, model->text); - - // Draw buttons - elements_button_left(canvas, model->left_text); - elements_button_right(canvas, model->right_text); -} - -static bool dialog_view_input_callback(InputEvent* event, void* context) { - Dialog* dialog = context; - bool consumed = false; - - // Process key presses only - if(event->type == InputTypeShort && dialog->callback) { - if(event->key == InputKeyLeft) { - dialog->callback(DialogResultLeft, dialog->context); - consumed = true; - } else if(event->key == InputKeyRight) { - dialog->callback(DialogResultRight, dialog->context); - consumed = true; - } else if(event->key == InputKeyBack) { - dialog->callback(DialogResultBack, dialog->context); - consumed = true; - } - } - - return consumed; -} - -Dialog* dialog_alloc() { - Dialog* dialog = malloc(sizeof(Dialog)); - dialog->view = view_alloc(); - view_set_context(dialog->view, dialog); - view_allocate_model(dialog->view, ViewModelTypeLockFree, sizeof(DialogModel)); - view_set_draw_callback(dialog->view, dialog_view_draw_callback); - view_set_input_callback(dialog->view, dialog_view_input_callback); - return dialog; -} - -void dialog_free(Dialog* dialog) { - furi_assert(dialog); - view_free(dialog->view); - free(dialog); -} - -View* dialog_get_view(Dialog* dialog) { - furi_assert(dialog); - return dialog->view; -} - -void dialog_set_result_callback(Dialog* dialog, DialogResultCallback callback) { - furi_assert(dialog); - dialog->callback = callback; -} - -void dialog_set_context(Dialog* dialog, void* context) { - furi_assert(dialog); - dialog->context = context; -} - -void dialog_set_header_text(Dialog* dialog, const char* text) { - furi_assert(dialog); - furi_assert(text); - with_view_model( - dialog->view, (DialogModel * model) { - model->header_text = text; - return true; - }); -} - -void dialog_set_text(Dialog* dialog, const char* text) { - furi_assert(dialog); - furi_assert(text); - with_view_model( - dialog->view, (DialogModel * model) { - model->text = text; - return true; - }); -} - -void dialog_set_left_button_text(Dialog* dialog, const char* text) { - furi_assert(dialog); - furi_assert(text); - with_view_model( - dialog->view, (DialogModel * model) { - model->left_text = text; - return true; - }); -} - -void dialog_set_right_button_text(Dialog* dialog, const char* text) { - furi_assert(dialog); - furi_assert(text); - with_view_model( - dialog->view, (DialogModel * model) { - model->right_text = text; - return true; - }); -} diff --git a/applications/gui/modules/dialog.h b/applications/gui/modules/dialog.h deleted file mode 100644 index e9160a351..000000000 --- a/applications/gui/modules/dialog.h +++ /dev/null @@ -1,95 +0,0 @@ -/** - * @file dialog.h - * GUI: Dialog view module API - */ - -#pragma once - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** Dialog anonymous structure */ -typedef struct Dialog Dialog; - -/** Dialog result */ -typedef enum { - DialogResultLeft, - DialogResultRight, - DialogResultBack, -} DialogResult; - -/** Dialog result callback type - * @warning comes from GUI thread - */ -typedef void (*DialogResultCallback)(DialogResult result, void* context); - -/** Allocate and initialize dialog - * - * This dialog used to ask simple questions like Yes/ - * - * @return Dialog instance - */ -Dialog* dialog_alloc(); - -/** Deinitialize and free dialog - * - * @param dialog Dialog instance - */ -void dialog_free(Dialog* dialog); - -/** Get dialog view - * - * @param dialog Dialog instance - * - * @return View instance that can be used for embedding - */ -View* dialog_get_view(Dialog* dialog); - -/** Set dialog result callback - * - * @param dialog Dialog instance - * @param callback result callback function - */ -void dialog_set_result_callback(Dialog* dialog, DialogResultCallback callback); - -/** Set dialog context - * - * @param dialog Dialog instance - * @param context context pointer, will be passed to result callback - */ -void dialog_set_context(Dialog* dialog, void* context); - -/** Set dialog header text - * - * @param dialog Dialog instance - * @param text text to be shown - */ -void dialog_set_header_text(Dialog* dialog, const char* text); - -/** Set dialog text - * - * @param dialog Dialog instance - * @param text text to be shown - */ -void dialog_set_text(Dialog* dialog, const char* text); - -/** Set left button text - * - * @param dialog Dialog instance - * @param text text to be shown - */ -void dialog_set_left_button_text(Dialog* dialog, const char* text); - -/** Set right button text - * - * @param dialog Dialog instance - * @param text text to be shown - */ -void dialog_set_right_button_text(Dialog* dialog, const char* text); - -#ifdef __cplusplus -} -#endif diff --git a/applications/lfrfid/lfrfid_app.cpp b/applications/lfrfid/lfrfid_app.cpp deleted file mode 100644 index 9373ca8c7..000000000 --- a/applications/lfrfid/lfrfid_app.cpp +++ /dev/null @@ -1,218 +0,0 @@ -#include "lfrfid_app.h" -#include "assets_icons.h" -#include -#include "m-string.h" -#include "scene/lfrfid_app_scene_start.h" -#include "scene/lfrfid_app_scene_read.h" -#include "scene/lfrfid_app_scene_read_success.h" -#include "scene/lfrfid_app_scene_retry_confirm.h" -#include "scene/lfrfid_app_scene_exit_confirm.h" -#include "scene/lfrfid_app_scene_read_menu.h" -#include "scene/lfrfid_app_scene_write.h" -#include "scene/lfrfid_app_scene_write_success.h" -#include "scene/lfrfid_app_scene_emulate.h" -#include "scene/lfrfid_app_scene_save_name.h" -#include "scene/lfrfid_app_scene_save_success.h" -#include "scene/lfrfid_app_scene_select_key.h" -#include "scene/lfrfid_app_scene_saved_key_menu.h" -#include "scene/lfrfid_app_scene_save_data.h" -#include "scene/lfrfid_app_scene_save_type.h" -#include "scene/lfrfid_app_scene_saved_info.h" -#include "scene/lfrfid_app_scene_delete_confirm.h" -#include "scene/lfrfid_app_scene_delete_success.h" -#include "scene/lfrfid_app_scene_rpc.h" -#include "scene/lfrfid_app_scene_extra_actions.h" -#include "scene/lfrfid_app_scene_raw_info.h" -#include "scene/lfrfid_app_scene_raw_name.h" -#include "scene/lfrfid_app_scene_raw_read.h" -#include "scene/lfrfid_app_scene_raw_success.h" - -#include -#include - -#include - -const char* LfRfidApp::app_folder = ANY_PATH("lfrfid"); -const char* LfRfidApp::app_sd_folder = EXT_PATH("lfrfid"); -const char* LfRfidApp::app_extension = ".rfid"; -const char* LfRfidApp::app_filetype = "Flipper RFID key"; - -LfRfidApp::LfRfidApp() - : scene_controller{this} - , notification{RECORD_NOTIFICATION} - , storage{RECORD_STORAGE} - , dialogs{RECORD_DIALOGS} - , text_store(40) { - string_init(file_name); - string_init(raw_file_name); - string_init_set_str(file_path, app_folder); - - dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax); - - size_t size = protocol_dict_get_max_data_size(dict); - new_key_data = (uint8_t*)malloc(size); - old_key_data = (uint8_t*)malloc(size); - - lfworker = lfrfid_worker_alloc(dict); -} - -LfRfidApp::~LfRfidApp() { - string_clear(raw_file_name); - string_clear(file_name); - string_clear(file_path); - protocol_dict_free(dict); - - lfrfid_worker_free(lfworker); - - if(rpc_ctx) { - rpc_system_app_set_callback(rpc_ctx, NULL, NULL); - rpc_system_app_send_exited(rpc_ctx); - } - - free(new_key_data); - free(old_key_data); -} - -static void rpc_command_callback(RpcAppSystemEvent rpc_event, void* context) { - furi_assert(context); - LfRfidApp* app = static_cast(context); - - if(rpc_event == RpcAppEventSessionClose) { - LfRfidApp::Event event; - event.type = LfRfidApp::EventType::RpcSessionClose; - app->view_controller.send_event(&event); - // Detach RPC - rpc_system_app_set_callback(app->rpc_ctx, NULL, NULL); - app->rpc_ctx = NULL; - } else if(rpc_event == RpcAppEventAppExit) { - LfRfidApp::Event event; - event.type = LfRfidApp::EventType::Exit; - app->view_controller.send_event(&event); - } else if(rpc_event == RpcAppEventLoadFile) { - LfRfidApp::Event event; - event.type = LfRfidApp::EventType::RpcLoadFile; - app->view_controller.send_event(&event); - } else { - rpc_system_app_confirm(app->rpc_ctx, rpc_event, false); - } -} - -void LfRfidApp::run(void* _args) { - const char* args = reinterpret_cast(_args); - - make_app_folder(); - - if(args && strlen(args)) { - uint32_t rpc_ctx_ptr = 0; - if(sscanf(args, "RPC %lX", &rpc_ctx_ptr) == 1) { - rpc_ctx = (RpcAppSystem*)rpc_ctx_ptr; - rpc_system_app_set_callback(rpc_ctx, rpc_command_callback, this); - rpc_system_app_send_started(rpc_ctx); - view_controller.attach_to_gui(ViewDispatcherTypeDesktop); - scene_controller.add_scene(SceneType::Rpc, new LfRfidAppSceneRpc()); - scene_controller.process(100, SceneType::Rpc); - } else { - string_set_str(file_path, args); - load_key_data(file_path, true); - view_controller.attach_to_gui(ViewDispatcherTypeFullscreen); - scene_controller.add_scene(SceneType::Emulate, new LfRfidAppSceneEmulate()); - scene_controller.process(100, SceneType::Emulate); - } - - } else { - view_controller.attach_to_gui(ViewDispatcherTypeFullscreen); - scene_controller.add_scene(SceneType::Start, new LfRfidAppSceneStart()); - scene_controller.add_scene(SceneType::Read, new LfRfidAppSceneRead()); - scene_controller.add_scene(SceneType::RetryConfirm, new LfRfidAppSceneRetryConfirm()); - scene_controller.add_scene(SceneType::ExitConfirm, new LfRfidAppSceneExitConfirm()); - scene_controller.add_scene(SceneType::ReadSuccess, new LfRfidAppSceneReadSuccess()); - scene_controller.add_scene(SceneType::ReadKeyMenu, new LfRfidAppSceneReadKeyMenu()); - scene_controller.add_scene(SceneType::Write, new LfRfidAppSceneWrite()); - scene_controller.add_scene(SceneType::WriteSuccess, new LfRfidAppSceneWriteSuccess()); - scene_controller.add_scene(SceneType::Emulate, new LfRfidAppSceneEmulate()); - scene_controller.add_scene(SceneType::SaveName, new LfRfidAppSceneSaveName()); - scene_controller.add_scene(SceneType::SaveSuccess, new LfRfidAppSceneSaveSuccess()); - scene_controller.add_scene(SceneType::SelectKey, new LfRfidAppSceneSelectKey()); - scene_controller.add_scene(SceneType::SavedKeyMenu, new LfRfidAppSceneSavedKeyMenu()); - scene_controller.add_scene(SceneType::SaveData, new LfRfidAppSceneSaveData()); - scene_controller.add_scene(SceneType::SaveType, new LfRfidAppSceneSaveType()); - scene_controller.add_scene(SceneType::SavedInfo, new LfRfidAppSceneSavedInfo()); - scene_controller.add_scene(SceneType::DeleteConfirm, new LfRfidAppSceneDeleteConfirm()); - scene_controller.add_scene(SceneType::DeleteSuccess, new LfRfidAppSceneDeleteSuccess()); - scene_controller.add_scene(SceneType::ExtraActions, new LfRfidAppSceneExtraActions()); - scene_controller.add_scene(SceneType::RawInfo, new LfRfidAppSceneRawInfo()); - scene_controller.add_scene(SceneType::RawName, new LfRfidAppSceneRawName()); - scene_controller.add_scene(SceneType::RawRead, new LfRfidAppSceneRawRead()); - scene_controller.add_scene(SceneType::RawSuccess, new LfRfidAppSceneRawSuccess()); - scene_controller.process(100); - } -} - -bool LfRfidApp::save_key() { - bool result = false; - - make_app_folder(); - - if(string_end_with_str_p(file_path, app_extension)) { - size_t filename_start = string_search_rchar(file_path, '/'); - string_left(file_path, filename_start); - } - - string_cat_printf(file_path, "/%s%s", string_get_cstr(file_name), app_extension); - - result = save_key_data(file_path); - return result; -} - -bool LfRfidApp::load_key_from_file_select(bool need_restore) { - if(!need_restore) { - string_set_str(file_path, app_folder); - } - - bool result = dialog_file_browser_show( - dialogs, file_path, file_path, app_extension, true, &I_125_10px, true); - - if(result) { - result = load_key_data(file_path, true); - } - - return result; -} - -bool LfRfidApp::delete_key() { - return storage_simply_remove(storage, string_get_cstr(file_path)); -} - -bool LfRfidApp::load_key_data(string_t path, bool show_dialog) { - bool result = false; - - do { - protocol_id = lfrfid_dict_file_load(dict, string_get_cstr(path)); - if(protocol_id == PROTOCOL_NO) break; - - path_extract_filename(path, file_name, true); - result = true; - } while(0); - - if((!result) && (show_dialog)) { - dialog_message_show_storage_error(dialogs, "Cannot load\nkey file"); - } - - return result; -} - -bool LfRfidApp::save_key_data(string_t path) { - bool result = lfrfid_dict_file_save(dict, protocol_id, string_get_cstr(path)); - - if(!result) { - dialog_message_show_storage_error(dialogs, "Cannot save\nkey file"); - } - - return result; -} - -void LfRfidApp::make_app_folder() { - if(!storage_simply_mkdir(storage, app_folder)) { - dialog_message_show_storage_error(dialogs, "Cannot create\napp folder"); - } -} diff --git a/applications/lfrfid/lfrfid_app.h b/applications/lfrfid/lfrfid_app.h deleted file mode 100644 index 153218dbd..000000000 --- a/applications/lfrfid/lfrfid_app.h +++ /dev/null @@ -1,137 +0,0 @@ -#pragma once -#include "m-string.h" -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include "view/container_vm.h" - -#include -#include -#include - -#include "rpc/rpc_app.h" - -#include -#include -#include -#include - -#define LFRFID_KEY_NAME_SIZE 22 - -class LfRfidApp { -public: - enum class EventType : uint8_t { - GENERIC_EVENT_ENUM_VALUES, - Next, - MenuSelected, - Stay, - Retry, - Exit, - ReadEventSenseStart, - ReadEventSenseEnd, - ReadEventSenseCardStart, - ReadEventSenseCardEnd, - ReadEventStartASK, - ReadEventStartPSK, - ReadEventDone, - ReadEventOverrun, - ReadEventError, - WriteEventOK, - WriteEventProtocolCannotBeWritten, - WriteEventFobCannotBeWritten, - WriteEventTooLongToWrite, - RpcLoadFile, - RpcSessionClose, - }; - - enum class SceneType : uint8_t { - GENERIC_SCENE_ENUM_VALUES, - Read, - ReadSuccess, - RetryConfirm, - ExitConfirm, - ReadKeyMenu, - Write, - WriteSuccess, - Emulate, - SaveName, - SaveSuccess, - SelectKey, - SavedKeyMenu, - SaveData, - SaveType, - SavedInfo, - DeleteConfirm, - DeleteSuccess, - Rpc, - ExtraActions, - RawInfo, - RawName, - RawRead, - RawSuccess, - }; - - class Event { - public: - union { - int32_t signed_int; - } payload; - - EventType type; - }; - - SceneController, LfRfidApp> scene_controller; - ViewController - view_controller; - - ~LfRfidApp(); - LfRfidApp(); - - RecordController notification; - RecordController storage; - RecordController dialogs; - - TextStore text_store; - - string_t file_path; - - RpcAppSystem* rpc_ctx; - - void run(void* args); - - static const char* app_folder; - static const char* app_sd_folder; - static const char* app_extension; - static const char* app_filetype; - - bool save_key(); - bool load_key_from_file_select(bool need_restore); - bool delete_key(); - - bool load_key_data(string_t path, bool show_dialog); - bool save_key_data(string_t path); - - void make_app_folder(); - - ProtocolDict* dict; - LFRFIDWorker* lfworker; - string_t file_name; - ProtocolId protocol_id; - LFRFIDWorkerReadType read_type; - - uint8_t* old_key_data; - uint8_t* new_key_data; - - string_t raw_file_name; -}; diff --git a/applications/lfrfid/lfrfid_app_launcher.cpp b/applications/lfrfid/lfrfid_app_launcher.cpp deleted file mode 100644 index 2855850f5..000000000 --- a/applications/lfrfid/lfrfid_app_launcher.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "lfrfid_app.h" - -// app enter function -extern "C" int32_t lfrfid_app(void* args) { - LfRfidApp* app = new LfRfidApp(); - app->run(args); - delete app; - - return 0; -} diff --git a/applications/lfrfid/scene/lfrfid_app_scene_delete_confirm.cpp b/applications/lfrfid/scene/lfrfid_app_scene_delete_confirm.cpp deleted file mode 100644 index 58ff4dcdf..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_delete_confirm.cpp +++ /dev/null @@ -1,88 +0,0 @@ -#include "lfrfid_app_scene_delete_confirm.h" -#include "../view/elements/button_element.h" -#include "../view/elements/icon_element.h" -#include "../view/elements/string_element.h" - -void LfRfidAppSceneDeleteConfirm::on_enter(LfRfidApp* app, bool /* need_restore */) { - string_init(string_data); - string_init(string_header); - - auto container = app->view_controller.get(); - - auto button = container->add(); - button->set_type(ButtonElement::Type::Left, "Back"); - button->set_callback(app, LfRfidAppSceneDeleteConfirm::back_callback); - - button = container->add(); - button->set_type(ButtonElement::Type::Right, "Delete"); - button->set_callback(app, LfRfidAppSceneDeleteConfirm::delete_callback); - - auto line_1 = container->add(); - auto line_2 = container->add(); - auto line_3 = container->add(); - - size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id); - uint8_t* data = (uint8_t*)malloc(size); - protocol_dict_get_data(app->dict, app->protocol_id, data, size); - for(uint8_t i = 0; i < MIN(size, (size_t)8); i++) { - if(i != 0) { - string_cat_printf(string_data, " "); - } - - string_cat_printf(string_data, "%02X", data[i]); - } - free(data); - - string_printf(string_header, "Delete %s?", string_get_cstr(app->file_name)); - line_1->set_text( - string_get_cstr(string_header), 64, 0, 128 - 2, AlignCenter, AlignTop, FontPrimary); - line_2->set_text( - string_get_cstr(string_data), 64, 19, 0, AlignCenter, AlignTop, FontSecondary); - line_3->set_text( - protocol_dict_get_name(app->dict, app->protocol_id), - 64, - 49, - 0, - AlignCenter, - AlignBottom, - FontSecondary); - - app->view_controller.switch_to(); -} - -bool LfRfidAppSceneDeleteConfirm::on_event(LfRfidApp* app, LfRfidApp::Event* event) { - bool consumed = false; - - if(event->type == LfRfidApp::EventType::Next) { - app->delete_key(); - app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::DeleteSuccess); - consumed = true; - } else if(event->type == LfRfidApp::EventType::Stay) { - app->scene_controller.switch_to_previous_scene(); - consumed = true; - } else if(event->type == LfRfidApp::EventType::Back) { - consumed = true; - } - - return consumed; -} - -void LfRfidAppSceneDeleteConfirm::on_exit(LfRfidApp* app) { - app->view_controller.get()->clean(); - string_clear(string_data); - string_clear(string_header); -} - -void LfRfidAppSceneDeleteConfirm::back_callback(void* context) { - LfRfidApp* app = static_cast(context); - LfRfidApp::Event event; - event.type = LfRfidApp::EventType::Stay; - app->view_controller.send_event(&event); -} - -void LfRfidAppSceneDeleteConfirm::delete_callback(void* context) { - LfRfidApp* app = static_cast(context); - LfRfidApp::Event event; - event.type = LfRfidApp::EventType::Next; - app->view_controller.send_event(&event); -} diff --git a/applications/lfrfid/scene/lfrfid_app_scene_delete_confirm.h b/applications/lfrfid/scene/lfrfid_app_scene_delete_confirm.h deleted file mode 100644 index f9daed543..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_delete_confirm.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once -#include "../lfrfid_app.h" - -class LfRfidAppSceneDeleteConfirm : public GenericScene { -public: - void on_enter(LfRfidApp* app, bool need_restore) final; - bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final; - void on_exit(LfRfidApp* app) final; - -private: - static void back_callback(void* context); - static void delete_callback(void* context); - - string_t string_header; - string_t string_data; -}; diff --git a/applications/lfrfid/scene/lfrfid_app_scene_delete_success.cpp b/applications/lfrfid/scene/lfrfid_app_scene_delete_success.cpp deleted file mode 100644 index 9820338d1..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_delete_success.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "lfrfid_app_scene_delete_success.h" - -void LfRfidAppSceneDeleteSuccess::on_enter(LfRfidApp* app, bool /* need_restore */) { - auto popup = app->view_controller.get(); - - popup->set_icon(0, 2, &I_DolphinMafia_115x62); - popup->set_header("Deleted", 83, 19, AlignLeft, AlignBottom); - popup->set_context(app); - popup->set_callback(LfRfidAppSceneDeleteSuccess::timeout_callback); - popup->set_timeout(1500); - popup->enable_timeout(); - - app->view_controller.switch_to(); -} - -bool LfRfidAppSceneDeleteSuccess::on_event(LfRfidApp* app, LfRfidApp::Event* event) { - bool consumed = false; - - if(event->type == LfRfidApp::EventType::Back) { - app->scene_controller.search_and_switch_to_previous_scene( - {LfRfidApp::SceneType::SelectKey}); - - consumed = true; - } - - return consumed; -} - -void LfRfidAppSceneDeleteSuccess::on_exit(LfRfidApp* app) { - app->view_controller.get()->clean(); -} - -void LfRfidAppSceneDeleteSuccess::timeout_callback(void* context) { - LfRfidApp* app = static_cast(context); - LfRfidApp::Event event; - event.type = LfRfidApp::EventType::Back; - app->view_controller.send_event(&event); -} diff --git a/applications/lfrfid/scene/lfrfid_app_scene_delete_success.h b/applications/lfrfid/scene/lfrfid_app_scene_delete_success.h deleted file mode 100644 index 009b9f25d..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_delete_success.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#include "../lfrfid_app.h" - -class LfRfidAppSceneDeleteSuccess : public GenericScene { -public: - void on_enter(LfRfidApp* app, bool need_restore) final; - bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final; - void on_exit(LfRfidApp* app) final; - -private: - static void timeout_callback(void* context); -}; diff --git a/applications/lfrfid/scene/lfrfid_app_scene_emulate.cpp b/applications/lfrfid/scene/lfrfid_app_scene_emulate.cpp deleted file mode 100644 index 02cb011d1..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_emulate.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "lfrfid_app_scene_emulate.h" -#include -#include - -void LfRfidAppSceneEmulate::on_enter(LfRfidApp* app, bool /* need_restore */) { - DOLPHIN_DEED(DolphinDeedRfidEmulate); - auto popup = app->view_controller.get(); - - popup->set_header("Emulating", 89, 30, AlignCenter, AlignTop); - if(string_size(app->file_name)) { - popup->set_text(string_get_cstr(app->file_name), 89, 43, AlignCenter, AlignTop); - } else { - popup->set_text( - protocol_dict_get_name(app->dict, app->protocol_id), 89, 43, AlignCenter, AlignTop); - } - popup->set_icon(0, 3, &I_RFIDDolphinSend_97x61); - - app->view_controller.switch_to(); - lfrfid_worker_start_thread(app->lfworker); - lfrfid_worker_emulate_start(app->lfworker, (LFRFIDProtocol)app->protocol_id); - notification_message(app->notification, &sequence_blink_start_magenta); -} - -bool LfRfidAppSceneEmulate::on_event(LfRfidApp* app, LfRfidApp::Event* event) { - UNUSED(app); - UNUSED(event); - bool consumed = false; - return consumed; -} - -void LfRfidAppSceneEmulate::on_exit(LfRfidApp* app) { - app->view_controller.get()->clean(); - lfrfid_worker_stop(app->lfworker); - lfrfid_worker_stop_thread(app->lfworker); - notification_message(app->notification, &sequence_blink_stop); -} diff --git a/applications/lfrfid/scene/lfrfid_app_scene_emulate.h b/applications/lfrfid/scene/lfrfid_app_scene_emulate.h deleted file mode 100644 index 13d2b857d..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_emulate.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "../lfrfid_app.h" - -class LfRfidAppSceneEmulate : public GenericScene { -public: - void on_enter(LfRfidApp* app, bool need_restore) final; - bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final; - void on_exit(LfRfidApp* app) final; -}; diff --git a/applications/lfrfid/scene/lfrfid_app_scene_exit_confirm.cpp b/applications/lfrfid/scene/lfrfid_app_scene_exit_confirm.cpp deleted file mode 100644 index be070b40e..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_exit_confirm.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include "lfrfid_app_scene_exit_confirm.h" -#include "../view/elements/button_element.h" -#include "../view/elements/icon_element.h" -#include "../view/elements/string_element.h" - -void LfRfidAppSceneExitConfirm::on_enter(LfRfidApp* app, bool /* need_restore */) { - auto container = app->view_controller.get(); - - auto button = container->add(); - button->set_type(ButtonElement::Type::Left, "Exit"); - button->set_callback(app, LfRfidAppSceneExitConfirm::exit_callback); - - button = container->add(); - button->set_type(ButtonElement::Type::Right, "Stay"); - button->set_callback(app, LfRfidAppSceneExitConfirm::stay_callback); - - auto line_1 = container->add(); - auto line_2 = container->add(); - - line_1->set_text("Exit to RFID Menu?", 64, 19, 128 - 2, AlignCenter, AlignBottom, FontPrimary); - line_2->set_text( - "All unsaved data will be lost!", 64, 31, 0, AlignCenter, AlignBottom, FontSecondary); - - app->view_controller.switch_to(); -} - -bool LfRfidAppSceneExitConfirm::on_event(LfRfidApp* app, LfRfidApp::Event* event) { - bool consumed = false; - - if(event->type == LfRfidApp::EventType::Next) { - app->scene_controller.search_and_switch_to_previous_scene({LfRfidApp::SceneType::Start}); - consumed = true; - } else if(event->type == LfRfidApp::EventType::Stay) { - app->scene_controller.switch_to_previous_scene(); - consumed = true; - } else if(event->type == LfRfidApp::EventType::Back) { - consumed = true; - } - - return consumed; -} - -void LfRfidAppSceneExitConfirm::on_exit(LfRfidApp* app) { - app->view_controller.get()->clean(); -} - -void LfRfidAppSceneExitConfirm::exit_callback(void* context) { - LfRfidApp* app = static_cast(context); - LfRfidApp::Event event; - event.type = LfRfidApp::EventType::Next; - app->view_controller.send_event(&event); -} - -void LfRfidAppSceneExitConfirm::stay_callback(void* context) { - LfRfidApp* app = static_cast(context); - LfRfidApp::Event event; - event.type = LfRfidApp::EventType::Stay; - app->view_controller.send_event(&event); -} diff --git a/applications/lfrfid/scene/lfrfid_app_scene_exit_confirm.h b/applications/lfrfid/scene/lfrfid_app_scene_exit_confirm.h deleted file mode 100644 index a0a102325..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_exit_confirm.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#include "../lfrfid_app.h" - -class LfRfidAppSceneExitConfirm : public GenericScene { -public: - void on_enter(LfRfidApp* app, bool need_restore) final; - bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final; - void on_exit(LfRfidApp* app) final; - -private: - static void exit_callback(void* context); - static void stay_callback(void* context); -}; diff --git a/applications/lfrfid/scene/lfrfid_app_scene_extra_actions.cpp b/applications/lfrfid/scene/lfrfid_app_scene_extra_actions.cpp deleted file mode 100644 index ea4f03dbb..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_extra_actions.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include "lfrfid_app_scene_extra_actions.h" - -typedef enum { - SubmenuASK, - SubmenuPSK, - SubmenuRAW, -} SubmenuIndex; - -void LfRfidAppSceneExtraActions::on_enter(LfRfidApp* app, bool need_restore) { - auto submenu = app->view_controller.get(); - - submenu->add_item("Read ASK (Animal, Ordinary Card)", SubmenuASK, submenu_callback, app); - submenu->add_item("Read PSK (Indala)", SubmenuPSK, submenu_callback, app); - - if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { - submenu->add_item("Read RAW RFID data", SubmenuRAW, submenu_callback, app); - } - - if(need_restore) { - submenu->set_selected_item(submenu_item_selected); - } - - app->view_controller.switch_to(); -} - -bool LfRfidAppSceneExtraActions::on_event(LfRfidApp* app, LfRfidApp::Event* event) { - bool consumed = false; - - if(event->type == LfRfidApp::EventType::MenuSelected) { - submenu_item_selected = event->payload.signed_int; - switch(event->payload.signed_int) { - case SubmenuASK: - app->read_type = LFRFIDWorkerReadTypeASKOnly; - app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::Read); - break; - case SubmenuPSK: - app->read_type = LFRFIDWorkerReadTypePSKOnly; - app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::Read); - break; - case SubmenuRAW: - app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::RawName); - break; - } - - consumed = true; - } - - return consumed; -} - -void LfRfidAppSceneExtraActions::on_exit(LfRfidApp* app) { - app->view_controller.get()->clean(); -} - -void LfRfidAppSceneExtraActions::submenu_callback(void* context, uint32_t index) { - LfRfidApp* app = static_cast(context); - LfRfidApp::Event event; - - event.type = LfRfidApp::EventType::MenuSelected; - event.payload.signed_int = index; - - app->view_controller.send_event(&event); -} diff --git a/applications/lfrfid/scene/lfrfid_app_scene_extra_actions.h b/applications/lfrfid/scene/lfrfid_app_scene_extra_actions.h deleted file mode 100644 index dcd746146..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_extra_actions.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#include "../lfrfid_app.h" - -class LfRfidAppSceneExtraActions : public GenericScene { -public: - void on_enter(LfRfidApp* app, bool need_restore) final; - bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final; - void on_exit(LfRfidApp* app) final; - -private: - static void submenu_callback(void* context, uint32_t index); - uint32_t submenu_item_selected = 0; -}; diff --git a/applications/lfrfid/scene/lfrfid_app_scene_raw_info.cpp b/applications/lfrfid/scene/lfrfid_app_scene_raw_info.cpp deleted file mode 100644 index ce3634b2a..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_raw_info.cpp +++ /dev/null @@ -1,77 +0,0 @@ -#include "lfrfid_app_scene_raw_info.h" -#include "../view/elements/button_element.h" -#include "../view/elements/icon_element.h" -#include "../view/elements/string_element.h" - -static void ok_callback(void* context) { - LfRfidApp* app = static_cast(context); - LfRfidApp::Event event; - event.type = LfRfidApp::EventType::Next; - app->view_controller.send_event(&event); -} - -static void back_callback(void* context) { - LfRfidApp* app = static_cast(context); - LfRfidApp::Event event; - event.type = LfRfidApp::EventType::Back; - app->view_controller.send_event(&event); -} - -void LfRfidAppSceneRawInfo::on_enter(LfRfidApp* app, bool /* need_restore */) { - string_init(string_info); - - auto container = app->view_controller.get(); - - bool sd_exist = storage_sd_status(app->storage) == FSE_OK; - if(!sd_exist) { - auto icon = container->add(); - icon->set_icon(0, 0, &I_SDQuestion_35x43); - auto line = container->add(); - line->set_text( - "No SD card found.\nThis function will not\nwork without\nSD card.", - 81, - 4, - 0, - AlignCenter, - AlignTop, - FontSecondary); - - auto button = container->add(); - button->set_type(ButtonElement::Type::Left, "Back"); - button->set_callback(app, back_callback); - } else { - string_printf( - string_info, - "RAW RFID data reader\r\n" - "1) Put the Flipper on your card\r\n" - "2) Press OK\r\n" - "3) Wait until data is read"); - - auto line = container->add(); - line->set_text(string_get_cstr(string_info), 0, 1, 0, AlignLeft, AlignTop, FontSecondary); - - auto button = container->add(); - button->set_type(ButtonElement::Type::Center, "OK"); - button->set_callback(app, ok_callback); - } - - app->view_controller.switch_to(); -} - -bool LfRfidAppSceneRawInfo::on_event(LfRfidApp* app, LfRfidApp::Event* event) { - bool consumed = false; - if(event->type == LfRfidApp::EventType::Next) { - app->scene_controller.switch_to_scene({LfRfidApp::SceneType::RawRead}); - consumed = true; - } else if(event->type == LfRfidApp::EventType::Back) { - app->scene_controller.search_and_switch_to_previous_scene( - {LfRfidApp::SceneType::ExtraActions}); - consumed = true; - } - return consumed; -} - -void LfRfidAppSceneRawInfo::on_exit(LfRfidApp* app) { - app->view_controller.get()->clean(); - string_clear(string_info); -} diff --git a/applications/lfrfid/scene/lfrfid_app_scene_raw_info.h b/applications/lfrfid/scene/lfrfid_app_scene_raw_info.h deleted file mode 100644 index eecca1436..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_raw_info.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#include "../lfrfid_app.h" - -class LfRfidAppSceneRawInfo : public GenericScene { -public: - void on_enter(LfRfidApp* app, bool need_restore) final; - bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final; - void on_exit(LfRfidApp* app) final; - -private: - string_t string_info; -}; diff --git a/applications/lfrfid/scene/lfrfid_app_scene_raw_name.cpp b/applications/lfrfid/scene/lfrfid_app_scene_raw_name.cpp deleted file mode 100644 index 0ad346198..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_raw_name.cpp +++ /dev/null @@ -1,46 +0,0 @@ - -#include "lfrfid_app_scene_raw_name.h" -#include "m-string.h" -#include -#include - -void LfRfidAppSceneRawName::on_enter(LfRfidApp* app, bool /* need_restore */) { - const char* key_name = string_get_cstr(app->raw_file_name); - - bool key_name_empty = (string_size(app->raw_file_name) == 0); - if(key_name_empty) { - app->text_store.set("RfidRecord"); - } else { - app->text_store.set("%s", key_name); - } - - auto text_input = app->view_controller.get(); - text_input->set_header_text("Name the raw file"); - - text_input->set_result_callback( - save_callback, app, app->text_store.text, LFRFID_KEY_NAME_SIZE, key_name_empty); - - app->view_controller.switch_to(); -} - -bool LfRfidAppSceneRawName::on_event(LfRfidApp* app, LfRfidApp::Event* event) { - bool consumed = false; - - if(event->type == LfRfidApp::EventType::Next) { - string_set_str(app->raw_file_name, app->text_store.text); - app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::RawInfo); - } - - return consumed; -} - -void LfRfidAppSceneRawName::on_exit(LfRfidApp* app) { - app->view_controller.get()->clean(); -} - -void LfRfidAppSceneRawName::save_callback(void* context) { - LfRfidApp* app = static_cast(context); - LfRfidApp::Event event; - event.type = LfRfidApp::EventType::Next; - app->view_controller.send_event(&event); -} diff --git a/applications/lfrfid/scene/lfrfid_app_scene_raw_name.h b/applications/lfrfid/scene/lfrfid_app_scene_raw_name.h deleted file mode 100644 index 225d135e5..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_raw_name.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#include "../lfrfid_app.h" - -class LfRfidAppSceneRawName : public GenericScene { -public: - void on_enter(LfRfidApp* app, bool need_restore) final; - bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final; - void on_exit(LfRfidApp* app) final; - -private: - static void save_callback(void* context); -}; diff --git a/applications/lfrfid/scene/lfrfid_app_scene_raw_read.cpp b/applications/lfrfid/scene/lfrfid_app_scene_raw_read.cpp deleted file mode 100644 index 0d04e6bc7..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_raw_read.cpp +++ /dev/null @@ -1,107 +0,0 @@ -#include "lfrfid_app_scene_raw_read.h" -#include - -#define RAW_READ_TIME 5000 - -static void lfrfid_read_callback(LFRFIDWorkerReadRawResult result, void* ctx) { - LfRfidApp* app = static_cast(ctx); - LfRfidApp::Event event; - - switch(result) { - case LFRFIDWorkerReadRawFileError: - event.type = LfRfidApp::EventType::ReadEventError; - break; - case LFRFIDWorkerReadRawOverrun: - event.type = LfRfidApp::EventType::ReadEventOverrun; - break; - } - - app->view_controller.send_event(&event); -} - -static void timer_callback(void* ctx) { - LfRfidApp* app = static_cast(ctx); - LfRfidApp::Event event; - event.type = LfRfidApp::EventType::ReadEventDone; - app->view_controller.send_event(&event); -} - -void LfRfidAppSceneRawRead::on_enter(LfRfidApp* app, bool /* need_restore */) { - string_init(string_file_name); - auto popup = app->view_controller.get(); - popup->set_icon(0, 3, &I_RFIDDolphinReceive_97x61); - app->view_controller.switch_to(); - lfrfid_worker_start_thread(app->lfworker); - app->make_app_folder(); - - timer = furi_timer_alloc(timer_callback, FuriTimerTypeOnce, app); - furi_timer_start(timer, RAW_READ_TIME); - string_printf( - string_file_name, "%s/%s.ask.raw", app->app_sd_folder, string_get_cstr(app->raw_file_name)); - popup->set_header("Reading\nRAW RFID\nASK", 89, 30, AlignCenter, AlignTop); - lfrfid_worker_read_raw_start( - app->lfworker, - string_get_cstr(string_file_name), - LFRFIDWorkerReadTypeASKOnly, - lfrfid_read_callback, - app); - - notification_message(app->notification, &sequence_blink_start_cyan); - - is_psk = false; - error = false; -} - -bool LfRfidAppSceneRawRead::on_event(LfRfidApp* app, LfRfidApp::Event* event) { - UNUSED(app); - bool consumed = true; - auto popup = app->view_controller.get(); - - switch(event->type) { - case LfRfidApp::EventType::ReadEventError: - error = true; - popup->set_header("Reading\nRAW RFID\nFile error", 89, 30, AlignCenter, AlignTop); - notification_message(app->notification, &sequence_blink_start_red); - furi_timer_stop(timer); - break; - case LfRfidApp::EventType::ReadEventDone: - if(!error) { - if(is_psk) { - notification_message(app->notification, &sequence_success); - app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::RawSuccess); - } else { - popup->set_header("Reading\nRAW RFID\nPSK", 89, 30, AlignCenter, AlignTop); - notification_message(app->notification, &sequence_blink_start_yellow); - lfrfid_worker_stop(app->lfworker); - string_printf( - string_file_name, - "%s/%s.psk.raw", - app->app_sd_folder, - string_get_cstr(app->raw_file_name)); - lfrfid_worker_read_raw_start( - app->lfworker, - string_get_cstr(string_file_name), - LFRFIDWorkerReadTypePSKOnly, - lfrfid_read_callback, - app); - furi_timer_start(timer, RAW_READ_TIME); - is_psk = true; - } - } - break; - default: - consumed = false; - break; - } - - return consumed; -} - -void LfRfidAppSceneRawRead::on_exit(LfRfidApp* app) { - notification_message(app->notification, &sequence_blink_stop); - app->view_controller.get()->clean(); - lfrfid_worker_stop(app->lfworker); - lfrfid_worker_stop_thread(app->lfworker); - furi_timer_free(timer); - string_clear(string_file_name); -} diff --git a/applications/lfrfid/scene/lfrfid_app_scene_raw_read.h b/applications/lfrfid/scene/lfrfid_app_scene_raw_read.h deleted file mode 100644 index 09ef74639..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_raw_read.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once -#include "../lfrfid_app.h" - -class LfRfidAppSceneRawRead : public GenericScene { -public: - void on_enter(LfRfidApp* app, bool need_restore) final; - bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final; - void on_exit(LfRfidApp* app) final; - -private: - string_t string_file_name; - FuriTimer* timer; - bool is_psk; - bool error; -}; diff --git a/applications/lfrfid/scene/lfrfid_app_scene_raw_success.cpp b/applications/lfrfid/scene/lfrfid_app_scene_raw_success.cpp deleted file mode 100644 index 227ab580a..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_raw_success.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include "lfrfid_app_scene_raw_success.h" -#include "../view/elements/button_element.h" -#include "../view/elements/icon_element.h" -#include "../view/elements/string_element.h" - -void LfRfidAppSceneRawSuccess::on_enter(LfRfidApp* app, bool /* need_restore */) { - string_init(string_info); - - string_printf(string_info, "RAW RFID read success!\r\n"); - string_cat_printf(string_info, "Now you can analyze files\r\n"); - string_cat_printf(string_info, "Or send them to developers"); - - auto container = app->view_controller.get(); - - auto line = container->add(); - line->set_text(string_get_cstr(string_info), 0, 1, 0, AlignLeft, AlignTop, FontSecondary); - - auto button = container->add(); - button->set_type(ButtonElement::Type::Center, "OK"); - button->set_callback(app, LfRfidAppSceneRawSuccess::ok_callback); - - app->view_controller.switch_to(); -} - -bool LfRfidAppSceneRawSuccess::on_event(LfRfidApp* app, LfRfidApp::Event* event) { - bool consumed = false; - if(event->type == LfRfidApp::EventType::Next) { - app->scene_controller.search_and_switch_to_previous_scene( - {LfRfidApp::SceneType::ExtraActions}); - consumed = true; - } - return consumed; -} - -void LfRfidAppSceneRawSuccess::on_exit(LfRfidApp* app) { - app->view_controller.get()->clean(); - string_clear(string_info); -} - -void LfRfidAppSceneRawSuccess::ok_callback(void* context) { - LfRfidApp* app = static_cast(context); - LfRfidApp::Event event; - event.type = LfRfidApp::EventType::Next; - app->view_controller.send_event(&event); -} diff --git a/applications/lfrfid/scene/lfrfid_app_scene_raw_success.h b/applications/lfrfid/scene/lfrfid_app_scene_raw_success.h deleted file mode 100644 index 0a0b0116b..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_raw_success.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#include "../lfrfid_app.h" - -class LfRfidAppSceneRawSuccess : public GenericScene { -public: - void on_enter(LfRfidApp* app, bool need_restore) final; - bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final; - void on_exit(LfRfidApp* app) final; - -private: - string_t string_info; - static void ok_callback(void* context); -}; diff --git a/applications/lfrfid/scene/lfrfid_app_scene_read.cpp b/applications/lfrfid/scene/lfrfid_app_scene_read.cpp deleted file mode 100644 index 120eb1a07..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_read.cpp +++ /dev/null @@ -1,100 +0,0 @@ -#include "lfrfid_app_scene_read.h" -#include - -static void lfrfid_read_callback(LFRFIDWorkerReadResult result, ProtocolId protocol, void* ctx) { - LfRfidApp* app = static_cast(ctx); - LfRfidApp::Event event; - - switch(result) { - case LFRFIDWorkerReadSenseStart: - event.type = LfRfidApp::EventType::ReadEventSenseStart; - break; - case LFRFIDWorkerReadSenseEnd: - event.type = LfRfidApp::EventType::ReadEventSenseEnd; - break; - case LFRFIDWorkerReadSenseCardStart: - event.type = LfRfidApp::EventType::ReadEventSenseCardStart; - break; - case LFRFIDWorkerReadSenseCardEnd: - event.type = LfRfidApp::EventType::ReadEventSenseCardEnd; - break; - case LFRFIDWorkerReadDone: - event.type = LfRfidApp::EventType::ReadEventDone; - break; - case LFRFIDWorkerReadStartASK: - event.type = LfRfidApp::EventType::ReadEventStartASK; - break; - case LFRFIDWorkerReadStartPSK: - event.type = LfRfidApp::EventType::ReadEventStartPSK; - break; - } - - event.payload.signed_int = protocol; - - app->view_controller.send_event(&event); -} - -void LfRfidAppSceneRead::on_enter(LfRfidApp* app, bool /* need_restore */) { - auto popup = app->view_controller.get(); - - DOLPHIN_DEED(DolphinDeedRfidRead); - if(app->read_type == LFRFIDWorkerReadTypePSKOnly) { - popup->set_header("Reading\nLF RFID\nPSK", 89, 30, AlignCenter, AlignTop); - } else { - popup->set_header("Reading\nLF RFID\nASK", 89, 30, AlignCenter, AlignTop); - } - - popup->set_icon(0, 3, &I_RFIDDolphinReceive_97x61); - - app->view_controller.switch_to(); - lfrfid_worker_start_thread(app->lfworker); - lfrfid_worker_read_start(app->lfworker, app->read_type, lfrfid_read_callback, app); - - notification_message(app->notification, &sequence_blink_start_cyan); -} - -bool LfRfidAppSceneRead::on_event(LfRfidApp* app, LfRfidApp::Event* event) { - bool consumed = true; - auto popup = app->view_controller.get(); - - switch(event->type) { - case LfRfidApp::EventType::ReadEventSenseStart: - notification_message(app->notification, &sequence_blink_stop); - notification_message(app->notification, &sequence_blink_start_yellow); - break; - case LfRfidApp::EventType::ReadEventSenseCardStart: - notification_message(app->notification, &sequence_blink_stop); - notification_message(app->notification, &sequence_blink_start_green); - break; - case LfRfidApp::EventType::ReadEventSenseEnd: - case LfRfidApp::EventType::ReadEventSenseCardEnd: - notification_message(app->notification, &sequence_blink_stop); - notification_message(app->notification, &sequence_blink_start_cyan); - break; - case LfRfidApp::EventType::ReadEventDone: - app->protocol_id = event->payload.signed_int; - DOLPHIN_DEED(DolphinDeedRfidReadSuccess); - notification_message(app->notification, &sequence_success); - string_reset(app->file_name); - app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::ReadSuccess); - break; - case LfRfidApp::EventType::ReadEventStartPSK: - popup->set_header("Reading\nLF RFID\nPSK", 89, 30, AlignCenter, AlignTop); - break; - case LfRfidApp::EventType::ReadEventStartASK: - popup->set_header("Reading\nLF RFID\nASK", 89, 30, AlignCenter, AlignTop); - break; - default: - consumed = false; - break; - } - - return consumed; -} - -void LfRfidAppSceneRead::on_exit(LfRfidApp* app) { - notification_message(app->notification, &sequence_blink_stop); - app->view_controller.get()->clean(); - lfrfid_worker_stop(app->lfworker); - lfrfid_worker_stop_thread(app->lfworker); -} diff --git a/applications/lfrfid/scene/lfrfid_app_scene_read.h b/applications/lfrfid/scene/lfrfid_app_scene_read.h deleted file mode 100644 index b5035b72a..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_read.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "../lfrfid_app.h" - -class LfRfidAppSceneRead : public GenericScene { -public: - void on_enter(LfRfidApp* app, bool need_restore) final; - bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final; - void on_exit(LfRfidApp* app) final; -}; diff --git a/applications/lfrfid/scene/lfrfid_app_scene_read_menu.cpp b/applications/lfrfid/scene/lfrfid_app_scene_read_menu.cpp deleted file mode 100644 index aa3b3f1fb..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_read_menu.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include "lfrfid_app_scene_read_menu.h" - -typedef enum { - SubmenuSave, - SubmenuEmulate, - SubmenuWrite, -} SubmenuIndex; - -void LfRfidAppSceneReadKeyMenu::on_enter(LfRfidApp* app, bool need_restore) { - auto submenu = app->view_controller.get(); - - submenu->add_item("Save", SubmenuSave, submenu_callback, app); - submenu->add_item("Emulate", SubmenuEmulate, submenu_callback, app); - submenu->add_item("Write", SubmenuWrite, submenu_callback, app); - - if(need_restore) { - submenu->set_selected_item(submenu_item_selected); - } - - app->view_controller.switch_to(); -} - -bool LfRfidAppSceneReadKeyMenu::on_event(LfRfidApp* app, LfRfidApp::Event* event) { - bool consumed = false; - - if(event->type == LfRfidApp::EventType::MenuSelected) { - submenu_item_selected = event->payload.signed_int; - switch(event->payload.signed_int) { - case SubmenuWrite: - app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::Write); - break; - case SubmenuSave: - app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SaveName); - break; - case SubmenuEmulate: - app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::Emulate); - break; - } - consumed = true; - } else if(event->type == LfRfidApp::EventType::Back) { - app->scene_controller.switch_to_previous_scene(); - consumed = true; - } - - return consumed; -} - -void LfRfidAppSceneReadKeyMenu::on_exit(LfRfidApp* app) { - app->view_controller.get()->clean(); -} - -void LfRfidAppSceneReadKeyMenu::submenu_callback(void* context, uint32_t index) { - LfRfidApp* app = static_cast(context); - LfRfidApp::Event event; - - event.type = LfRfidApp::EventType::MenuSelected; - event.payload.signed_int = index; - - app->view_controller.send_event(&event); -} diff --git a/applications/lfrfid/scene/lfrfid_app_scene_read_menu.h b/applications/lfrfid/scene/lfrfid_app_scene_read_menu.h deleted file mode 100644 index 2b50b96f9..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_read_menu.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#include "../lfrfid_app.h" - -class LfRfidAppSceneReadKeyMenu : public GenericScene { -public: - void on_enter(LfRfidApp* app, bool need_restore) final; - bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final; - void on_exit(LfRfidApp* app) final; - -private: - static void submenu_callback(void* context, uint32_t index); - uint32_t submenu_item_selected = 0; -}; diff --git a/applications/lfrfid/scene/lfrfid_app_scene_read_success.cpp b/applications/lfrfid/scene/lfrfid_app_scene_read_success.cpp deleted file mode 100644 index 277b43a3e..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_read_success.cpp +++ /dev/null @@ -1,96 +0,0 @@ -#include "lfrfid_app_scene_read_success.h" -#include "../view/elements/button_element.h" -#include "../view/elements/icon_element.h" -#include "../view/elements/string_element.h" - -void LfRfidAppSceneReadSuccess::on_enter(LfRfidApp* app, bool /* need_restore */) { - string_init(string_info); - string_init(string_header); - - string_init_printf( - string_header, - "%s[%s]", - protocol_dict_get_name(app->dict, app->protocol_id), - protocol_dict_get_manufacturer(app->dict, app->protocol_id)); - - size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id); - uint8_t* data = (uint8_t*)malloc(size); - protocol_dict_get_data(app->dict, app->protocol_id, data, size); - for(uint8_t i = 0; i < size; i++) { - if(i != 0) { - string_cat_printf(string_info, " "); - } - - if(i >= 9) { - string_cat_printf(string_info, "..."); - break; - } else { - string_cat_printf(string_info, "%02X", data[i]); - } - } - free(data); - - string_t render_data; - string_init(render_data); - protocol_dict_render_brief_data(app->dict, render_data, app->protocol_id); - string_cat_printf(string_info, "\r\n%s", string_get_cstr(render_data)); - string_clear(render_data); - - auto container = app->view_controller.get(); - - auto button = container->add(); - button->set_type(ButtonElement::Type::Left, "Retry"); - button->set_callback(app, LfRfidAppSceneReadSuccess::back_callback); - - button = container->add(); - button->set_type(ButtonElement::Type::Right, "More"); - button->set_callback(app, LfRfidAppSceneReadSuccess::more_callback); - - auto header = container->add(); - header->set_text(string_get_cstr(string_header), 0, 2, 0, AlignLeft, AlignTop, FontPrimary); - - auto text = container->add(); - text->set_text(string_get_cstr(string_info), 0, 16, 0, AlignLeft, AlignTop, FontSecondary); - - app->view_controller.switch_to(); - - notification_message_block(app->notification, &sequence_set_green_255); -} - -bool LfRfidAppSceneReadSuccess::on_event(LfRfidApp* app, LfRfidApp::Event* event) { - bool consumed = false; - - if(event->type == LfRfidApp::EventType::Next) { - app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::ReadKeyMenu); - consumed = true; - } else if(event->type == LfRfidApp::EventType::Retry) { - app->scene_controller.switch_to_next_scene({LfRfidApp::SceneType::RetryConfirm}); - consumed = true; - } else if(event->type == LfRfidApp::EventType::Back) { - app->scene_controller.switch_to_next_scene({LfRfidApp::SceneType::ExitConfirm}); - consumed = true; - } - - return consumed; -} - -void LfRfidAppSceneReadSuccess::on_exit(LfRfidApp* app) { - notification_message_block(app->notification, &sequence_reset_green); - app->view_controller.get()->clean(); - string_clear(string_info); - string_clear(string_header); -} - -void LfRfidAppSceneReadSuccess::back_callback(void* context) { - LfRfidApp* app = static_cast(context); - LfRfidApp::Event event; - event.type = LfRfidApp::EventType::Retry; - app->view_controller.send_event(&event); -} - -void LfRfidAppSceneReadSuccess::more_callback(void* context) { - LfRfidApp* app = static_cast(context); - LfRfidApp::Event event; - event.type = LfRfidApp::EventType::Next; - app->view_controller.send_event(&event); -} diff --git a/applications/lfrfid/scene/lfrfid_app_scene_read_success.h b/applications/lfrfid/scene/lfrfid_app_scene_read_success.h deleted file mode 100644 index 6d90f6310..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_read_success.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once -#include "../lfrfid_app.h" - -class LfRfidAppSceneReadSuccess : public GenericScene { -public: - void on_enter(LfRfidApp* app, bool need_restore) final; - bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final; - void on_exit(LfRfidApp* app) final; - -private: - static void back_callback(void* context); - static void more_callback(void* context); - - string_t string_header; - string_t string_info; -}; diff --git a/applications/lfrfid/scene/lfrfid_app_scene_retry_confirm.cpp b/applications/lfrfid/scene/lfrfid_app_scene_retry_confirm.cpp deleted file mode 100644 index c18122323..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_retry_confirm.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include "lfrfid_app_scene_retry_confirm.h" -#include "../view/elements/button_element.h" -#include "../view/elements/icon_element.h" -#include "../view/elements/string_element.h" - -void LfRfidAppSceneRetryConfirm::on_enter(LfRfidApp* app, bool /* need_restore */) { - auto container = app->view_controller.get(); - - auto button = container->add(); - button->set_type(ButtonElement::Type::Left, "Exit"); - button->set_callback(app, LfRfidAppSceneRetryConfirm::exit_callback); - - button = container->add(); - button->set_type(ButtonElement::Type::Right, "Stay"); - button->set_callback(app, LfRfidAppSceneRetryConfirm::stay_callback); - - auto line_1 = container->add(); - auto line_2 = container->add(); - - line_1->set_text("Return to Reading?", 64, 19, 128 - 2, AlignCenter, AlignBottom, FontPrimary); - line_2->set_text( - "All unsaved data will be lost!", 64, 29, 0, AlignCenter, AlignBottom, FontSecondary); - - app->view_controller.switch_to(); -} - -bool LfRfidAppSceneRetryConfirm::on_event(LfRfidApp* app, LfRfidApp::Event* event) { - bool consumed = false; - - if(event->type == LfRfidApp::EventType::Next) { - app->scene_controller.search_and_switch_to_previous_scene({LfRfidApp::SceneType::Read}); - consumed = true; - } else if(event->type == LfRfidApp::EventType::Stay) { - app->scene_controller.switch_to_previous_scene(); - consumed = true; - } else if(event->type == LfRfidApp::EventType::Back) { - consumed = true; - } - - return consumed; -} - -void LfRfidAppSceneRetryConfirm::on_exit(LfRfidApp* app) { - app->view_controller.get()->clean(); -} - -void LfRfidAppSceneRetryConfirm::exit_callback(void* context) { - LfRfidApp* app = static_cast(context); - LfRfidApp::Event event; - event.type = LfRfidApp::EventType::Next; - app->view_controller.send_event(&event); -} - -void LfRfidAppSceneRetryConfirm::stay_callback(void* context) { - LfRfidApp* app = static_cast(context); - LfRfidApp::Event event; - event.type = LfRfidApp::EventType::Stay; - app->view_controller.send_event(&event); -} diff --git a/applications/lfrfid/scene/lfrfid_app_scene_retry_confirm.h b/applications/lfrfid/scene/lfrfid_app_scene_retry_confirm.h deleted file mode 100644 index 01b7329c9..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_retry_confirm.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#include "../lfrfid_app.h" - -class LfRfidAppSceneRetryConfirm : public GenericScene { -public: - void on_enter(LfRfidApp* app, bool need_restore) final; - bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final; - void on_exit(LfRfidApp* app) final; - -private: - static void exit_callback(void* context); - static void stay_callback(void* context); -}; diff --git a/applications/lfrfid/scene/lfrfid_app_scene_rpc.cpp b/applications/lfrfid/scene/lfrfid_app_scene_rpc.cpp deleted file mode 100644 index c2e5ec2a6..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_rpc.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include "lfrfid_app_scene_rpc.h" -#include -#include -#include - -void LfRfidAppSceneRpc::on_enter(LfRfidApp* app, bool /* need_restore */) { - auto popup = app->view_controller.get(); - - popup->set_header("LF RFID", 89, 42, AlignCenter, AlignBottom); - popup->set_text("RPC mode", 89, 44, AlignCenter, AlignTop); - popup->set_icon(0, 12, &I_RFIDDolphinSend_97x61); - - app->view_controller.switch_to(); - - notification_message(app->notification, &sequence_display_backlight_on); -} - -bool LfRfidAppSceneRpc::on_event(LfRfidApp* app, LfRfidApp::Event* event) { - UNUSED(app); - UNUSED(event); - bool consumed = false; - - if(event->type == LfRfidApp::EventType::Exit) { - consumed = true; - LfRfidApp::Event view_event; - view_event.type = LfRfidApp::EventType::Back; - app->view_controller.send_event(&view_event); - rpc_system_app_confirm(app->rpc_ctx, RpcAppEventAppExit, true); - } else if(event->type == LfRfidApp::EventType::RpcSessionClose) { - consumed = true; - LfRfidApp::Event view_event; - view_event.type = LfRfidApp::EventType::Back; - app->view_controller.send_event(&view_event); - } else if(event->type == LfRfidApp::EventType::RpcLoadFile) { - const char* arg = rpc_system_app_get_data(app->rpc_ctx); - consumed = true; - bool result = false; - if(arg && !emulating) { - string_set_str(app->file_path, arg); - if(app->load_key_data(app->file_path, false)) { - lfrfid_worker_start_thread(app->lfworker); - lfrfid_worker_emulate_start(app->lfworker, (LFRFIDProtocol)app->protocol_id); - emulating = true; - - auto popup = app->view_controller.get(); - app->text_store.set("emulating\n%s", string_get_cstr(app->file_name)); - popup->set_text(app->text_store.text, 89, 44, AlignCenter, AlignTop); - - notification_message(app->notification, &sequence_blink_start_magenta); - result = true; - } - } - rpc_system_app_confirm(app->rpc_ctx, RpcAppEventLoadFile, result); - } - - return consumed; -} - -void LfRfidAppSceneRpc::on_exit(LfRfidApp* app) { - if(emulating) { - lfrfid_worker_stop(app->lfworker); - lfrfid_worker_stop_thread(app->lfworker); - notification_message(app->notification, &sequence_blink_stop); - } - app->view_controller.get()->clean(); -} diff --git a/applications/lfrfid/scene/lfrfid_app_scene_rpc.h b/applications/lfrfid/scene/lfrfid_app_scene_rpc.h deleted file mode 100644 index f630dfd35..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_rpc.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#include "../lfrfid_app.h" - -class LfRfidAppSceneRpc : public GenericScene { -public: - void on_enter(LfRfidApp* app, bool need_restore) final; - bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final; - void on_exit(LfRfidApp* app) final; - -private: - bool emulating = false; -}; diff --git a/applications/lfrfid/scene/lfrfid_app_scene_save_data.cpp b/applications/lfrfid/scene/lfrfid_app_scene_save_data.cpp deleted file mode 100644 index c506cd729..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_save_data.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include "lfrfid_app_scene_save_data.h" -#include - -void LfRfidAppSceneSaveData::on_enter(LfRfidApp* app, bool need_restore) { - auto byte_input = app->view_controller.get(); - size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id); - - if(need_restore) { - protocol_dict_set_data(app->dict, app->protocol_id, app->old_key_data, size); - } else { - protocol_dict_get_data(app->dict, app->protocol_id, app->old_key_data, size); - } - - protocol_dict_get_data(app->dict, app->protocol_id, app->new_key_data, size); - - byte_input->set_header_text("Enter the data in hex"); - - byte_input->set_result_callback(save_callback, NULL, app, app->new_key_data, size); - - app->view_controller.switch_to(); -} - -bool LfRfidAppSceneSaveData::on_event(LfRfidApp* app, LfRfidApp::Event* event) { - bool consumed = false; - - if(event->type == LfRfidApp::EventType::Next) { - size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id); - protocol_dict_set_data(app->dict, app->protocol_id, app->new_key_data, size); - DOLPHIN_DEED(DolphinDeedRfidAdd); - app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SaveName); - } - - return consumed; -} - -void LfRfidAppSceneSaveData::on_exit(LfRfidApp* app) { - app->view_controller.get()->clean(); -} - -void LfRfidAppSceneSaveData::save_callback(void* context) { - LfRfidApp* app = static_cast(context); - LfRfidApp::Event event; - event.type = LfRfidApp::EventType::Next; - app->view_controller.send_event(&event); -} diff --git a/applications/lfrfid/scene/lfrfid_app_scene_save_data.h b/applications/lfrfid/scene/lfrfid_app_scene_save_data.h deleted file mode 100644 index d03cae125..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_save_data.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#include "../lfrfid_app.h" - -class LfRfidAppSceneSaveData : public GenericScene { -public: - void on_enter(LfRfidApp* app, bool need_restore) final; - bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final; - void on_exit(LfRfidApp* app) final; - -private: - static void save_callback(void* context); -}; diff --git a/applications/lfrfid/scene/lfrfid_app_scene_save_name.cpp b/applications/lfrfid/scene/lfrfid_app_scene_save_name.cpp deleted file mode 100644 index ed58b6453..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_save_name.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include "lfrfid_app_scene_save_name.h" -#include "m-string.h" -#include -#include - -void LfRfidAppSceneSaveName::on_enter(LfRfidApp* app, bool /* need_restore */) { - const char* key_name = string_get_cstr(app->file_name); - - bool key_name_empty = (string_size(app->file_name) == 0); - if(key_name_empty) { - string_set_str(app->file_path, app->app_folder); - set_random_name(app->text_store.text, app->text_store.text_size); - } else { - app->text_store.set("%s", key_name); - } - - auto text_input = app->view_controller.get(); - text_input->set_header_text("Name the card"); - - text_input->set_result_callback( - save_callback, app, app->text_store.text, LFRFID_KEY_NAME_SIZE, key_name_empty); - - string_t folder_path; - string_init(folder_path); - - path_extract_dirname(string_get_cstr(app->file_path), folder_path); - - ValidatorIsFile* validator_is_file = - validator_is_file_alloc_init(string_get_cstr(folder_path), app->app_extension, key_name); - text_input->set_validator(validator_is_file_callback, validator_is_file); - - string_clear(folder_path); - - app->view_controller.switch_to(); -} - -bool LfRfidAppSceneSaveName::on_event(LfRfidApp* app, LfRfidApp::Event* event) { - bool consumed = false; - - if(event->type == LfRfidApp::EventType::Next) { - if(string_size(app->file_name) > 0) { - app->delete_key(); - } - - string_set_str(app->file_name, app->text_store.text); - - if(app->save_key()) { - app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SaveSuccess); - } else { - app->scene_controller.search_and_switch_to_previous_scene( - {LfRfidApp::SceneType::ReadKeyMenu}); - } - } - - return consumed; -} - -void LfRfidAppSceneSaveName::on_exit(LfRfidApp* app) { - void* validator_context = - app->view_controller.get()->get_validator_callback_context(); - app->view_controller.get()->set_validator(NULL, NULL); - validator_is_file_free((ValidatorIsFile*)validator_context); - - app->view_controller.get()->clean(); -} - -void LfRfidAppSceneSaveName::save_callback(void* context) { - LfRfidApp* app = static_cast(context); - LfRfidApp::Event event; - event.type = LfRfidApp::EventType::Next; - app->view_controller.send_event(&event); -} diff --git a/applications/lfrfid/scene/lfrfid_app_scene_save_name.h b/applications/lfrfid/scene/lfrfid_app_scene_save_name.h deleted file mode 100644 index ced42cc0e..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_save_name.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#include "../lfrfid_app.h" - -class LfRfidAppSceneSaveName : public GenericScene { -public: - void on_enter(LfRfidApp* app, bool need_restore) final; - bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final; - void on_exit(LfRfidApp* app) final; - -private: - static void save_callback(void* context); -}; diff --git a/applications/lfrfid/scene/lfrfid_app_scene_save_success.cpp b/applications/lfrfid/scene/lfrfid_app_scene_save_success.cpp deleted file mode 100644 index 64efafa73..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_save_success.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "lfrfid_app_scene_save_success.h" -#include -#include -#include - -void LfRfidAppSceneSaveSuccess::on_enter(LfRfidApp* app, bool /* need_restore */) { - auto popup = app->view_controller.get(); - - DOLPHIN_DEED(DolphinDeedRfidSave); - popup->set_icon(32, 5, &I_DolphinNice_96x59); - popup->set_header("Saved!", 5, 7, AlignLeft, AlignTop); - popup->set_context(app); - popup->set_callback(LfRfidAppSceneSaveSuccess::timeout_callback); - popup->set_timeout(1500); - popup->enable_timeout(); - - app->view_controller.switch_to(); -} - -bool LfRfidAppSceneSaveSuccess::on_event(LfRfidApp* app, LfRfidApp::Event* event) { - bool consumed = false; - - if(event->type == LfRfidApp::EventType::Back) { - bool result = app->scene_controller.has_previous_scene( - {LfRfidApp::SceneType::ReadKeyMenu, LfRfidApp::SceneType::SelectKey}); - - if(result) { - app->scene_controller.search_and_switch_to_previous_scene( - {LfRfidApp::SceneType::ReadKeyMenu, LfRfidApp::SceneType::SelectKey}); - } else { - app->scene_controller.search_and_switch_to_another_scene( - {LfRfidApp::SceneType::SaveType}, LfRfidApp::SceneType::SelectKey); - } - - consumed = true; - } - - return consumed; -} - -void LfRfidAppSceneSaveSuccess::on_exit(LfRfidApp* app) { - app->view_controller.get()->clean(); -} - -void LfRfidAppSceneSaveSuccess::timeout_callback(void* context) { - LfRfidApp* app = static_cast(context); - LfRfidApp::Event event; - event.type = LfRfidApp::EventType::Back; - app->view_controller.send_event(&event); -} diff --git a/applications/lfrfid/scene/lfrfid_app_scene_save_success.h b/applications/lfrfid/scene/lfrfid_app_scene_save_success.h deleted file mode 100644 index 62273a76b..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_save_success.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#include "../lfrfid_app.h" - -class LfRfidAppSceneSaveSuccess : public GenericScene { -public: - void on_enter(LfRfidApp* app, bool need_restore) final; - bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final; - void on_exit(LfRfidApp* app) final; - -private: - static void timeout_callback(void* context); -}; diff --git a/applications/lfrfid/scene/lfrfid_app_scene_save_type.cpp b/applications/lfrfid/scene/lfrfid_app_scene_save_type.cpp deleted file mode 100644 index b017e7b05..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_save_type.cpp +++ /dev/null @@ -1,53 +0,0 @@ -#include "lfrfid_app_scene_save_type.h" - -void LfRfidAppSceneSaveType::on_enter(LfRfidApp* app, bool need_restore) { - auto submenu = app->view_controller.get(); - - for(uint8_t i = 0; i < keys_count; i++) { - string_init_printf( - submenu_name[i], - "%s %s", - protocol_dict_get_manufacturer(app->dict, i), - protocol_dict_get_name(app->dict, i)); - submenu->add_item(string_get_cstr(submenu_name[i]), i, submenu_callback, app); - } - - if(need_restore) { - submenu->set_selected_item(submenu_item_selected); - } - - app->view_controller.switch_to(); - - // clear key name - string_reset(app->file_name); -} - -bool LfRfidAppSceneSaveType::on_event(LfRfidApp* app, LfRfidApp::Event* event) { - bool consumed = false; - - if(event->type == LfRfidApp::EventType::MenuSelected) { - submenu_item_selected = event->payload.signed_int; - app->protocol_id = event->payload.signed_int; - app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SaveData); - consumed = true; - } - - return consumed; -} - -void LfRfidAppSceneSaveType::on_exit(LfRfidApp* app) { - app->view_controller.get()->clean(); - for(uint8_t i = 0; i < keys_count; i++) { - string_clear(submenu_name[i]); - } -} - -void LfRfidAppSceneSaveType::submenu_callback(void* context, uint32_t index) { - LfRfidApp* app = static_cast(context); - LfRfidApp::Event event; - - event.type = LfRfidApp::EventType::MenuSelected; - event.payload.signed_int = index; - - app->view_controller.send_event(&event); -} diff --git a/applications/lfrfid/scene/lfrfid_app_scene_save_type.h b/applications/lfrfid/scene/lfrfid_app_scene_save_type.h deleted file mode 100644 index e4c1be3e6..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_save_type.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once -#include "../lfrfid_app.h" - -class LfRfidAppSceneSaveType : public GenericScene { -public: - void on_enter(LfRfidApp* app, bool need_restore) final; - bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final; - void on_exit(LfRfidApp* app) final; - -private: - static void submenu_callback(void* context, uint32_t index); - uint32_t submenu_item_selected = 0; - static const uint8_t keys_count = static_cast(LFRFIDProtocol::LFRFIDProtocolMax); - string_t submenu_name[keys_count]; -}; diff --git a/applications/lfrfid/scene/lfrfid_app_scene_saved_info.cpp b/applications/lfrfid/scene/lfrfid_app_scene_saved_info.cpp deleted file mode 100644 index 614dd505c..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_saved_info.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include "lfrfid_app_scene_saved_info.h" -#include "../view/elements/button_element.h" -#include "../view/elements/icon_element.h" -#include "../view/elements/string_element.h" - -void LfRfidAppSceneSavedInfo::on_enter(LfRfidApp* app, bool /* need_restore */) { - string_init(string_info); - - string_printf( - string_info, - "%s [%s]\r\n", - string_get_cstr(app->file_name), - protocol_dict_get_name(app->dict, app->protocol_id)); - - size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id); - uint8_t* data = (uint8_t*)malloc(size); - protocol_dict_get_data(app->dict, app->protocol_id, data, size); - for(uint8_t i = 0; i < size; i++) { - if(i != 0) { - string_cat_printf(string_info, " "); - } - - string_cat_printf(string_info, "%02X", data[i]); - } - free(data); - - string_t render_data; - string_init(render_data); - protocol_dict_render_data(app->dict, render_data, app->protocol_id); - string_cat_printf(string_info, "\r\n%s", string_get_cstr(render_data)); - string_clear(render_data); - - auto container = app->view_controller.get(); - - auto line_1 = container->add(); - line_1->set_text(string_get_cstr(string_info), 0, 1, 0, AlignLeft, AlignTop, FontSecondary); - - app->view_controller.switch_to(); -} - -bool LfRfidAppSceneSavedInfo::on_event(LfRfidApp* /* app */, LfRfidApp::Event* /* event */) { - return false; -} - -void LfRfidAppSceneSavedInfo::on_exit(LfRfidApp* app) { - app->view_controller.get()->clean(); - string_clear(string_info); -} diff --git a/applications/lfrfid/scene/lfrfid_app_scene_saved_info.h b/applications/lfrfid/scene/lfrfid_app_scene_saved_info.h deleted file mode 100644 index b0b588bcb..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_saved_info.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#include "../lfrfid_app.h" - -class LfRfidAppSceneSavedInfo : public GenericScene { -public: - void on_enter(LfRfidApp* app, bool need_restore) final; - bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final; - void on_exit(LfRfidApp* app) final; - -private: - string_t string_info; -}; diff --git a/applications/lfrfid/scene/lfrfid_app_scene_saved_key_menu.cpp b/applications/lfrfid/scene/lfrfid_app_scene_saved_key_menu.cpp deleted file mode 100644 index e7a38d8ad..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_saved_key_menu.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#include "lfrfid_app_scene_saved_key_menu.h" - -typedef enum { - SubmenuEmulate, - SubmenuWrite, - SubmenuEdit, - SubmenuDelete, - SubmenuInfo, -} SubmenuIndex; - -void LfRfidAppSceneSavedKeyMenu::on_enter(LfRfidApp* app, bool need_restore) { - auto submenu = app->view_controller.get(); - - submenu->add_item("Emulate", SubmenuEmulate, submenu_callback, app); - submenu->add_item("Write", SubmenuWrite, submenu_callback, app); - submenu->add_item("Edit", SubmenuEdit, submenu_callback, app); - submenu->add_item("Delete", SubmenuDelete, submenu_callback, app); - submenu->add_item("Info", SubmenuInfo, submenu_callback, app); - - if(need_restore) { - submenu->set_selected_item(submenu_item_selected); - } - - app->view_controller.switch_to(); -} - -bool LfRfidAppSceneSavedKeyMenu::on_event(LfRfidApp* app, LfRfidApp::Event* event) { - bool consumed = false; - - if(event->type == LfRfidApp::EventType::MenuSelected) { - submenu_item_selected = event->payload.signed_int; - switch(event->payload.signed_int) { - case SubmenuEmulate: - app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::Emulate); - break; - case SubmenuWrite: - app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::Write); - break; - case SubmenuEdit: - app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SaveData); - break; - case SubmenuDelete: - app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::DeleteConfirm); - break; - case SubmenuInfo: - app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SavedInfo); - break; - } - consumed = true; - } - - return consumed; -} - -void LfRfidAppSceneSavedKeyMenu::on_exit(LfRfidApp* app) { - app->view_controller.get()->clean(); -} - -void LfRfidAppSceneSavedKeyMenu::submenu_callback(void* context, uint32_t index) { - LfRfidApp* app = static_cast(context); - LfRfidApp::Event event; - - event.type = LfRfidApp::EventType::MenuSelected; - event.payload.signed_int = index; - - app->view_controller.send_event(&event); -} diff --git a/applications/lfrfid/scene/lfrfid_app_scene_saved_key_menu.h b/applications/lfrfid/scene/lfrfid_app_scene_saved_key_menu.h deleted file mode 100644 index 69a6e5e58..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_saved_key_menu.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#include "../lfrfid_app.h" - -class LfRfidAppSceneSavedKeyMenu : public GenericScene { -public: - void on_enter(LfRfidApp* app, bool need_restore) final; - bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final; - void on_exit(LfRfidApp* app) final; - -private: - static void submenu_callback(void* context, uint32_t index); - uint32_t submenu_item_selected = 0; -}; diff --git a/applications/lfrfid/scene/lfrfid_app_scene_select_key.cpp b/applications/lfrfid/scene/lfrfid_app_scene_select_key.cpp deleted file mode 100644 index 6d5df73cb..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_select_key.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "lfrfid_app_scene_select_key.h" - -void LfRfidAppSceneSelectKey::on_enter(LfRfidApp* app, bool need_restore) { - if(app->load_key_from_file_select(need_restore)) { - app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SavedKeyMenu); - } else { - app->scene_controller.switch_to_previous_scene(); - } -} - -bool LfRfidAppSceneSelectKey::on_event(LfRfidApp* /* app */, LfRfidApp::Event* /* event */) { - return false; -} - -void LfRfidAppSceneSelectKey::on_exit(LfRfidApp* /* app */) { -} diff --git a/applications/lfrfid/scene/lfrfid_app_scene_select_key.h b/applications/lfrfid/scene/lfrfid_app_scene_select_key.h deleted file mode 100644 index be565a91c..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_select_key.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "../lfrfid_app.h" - -class LfRfidAppSceneSelectKey : public GenericScene { -public: - void on_enter(LfRfidApp* app, bool need_restore) final; - bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final; - void on_exit(LfRfidApp* app) final; -}; diff --git a/applications/lfrfid/scene/lfrfid_app_scene_start.cpp b/applications/lfrfid/scene/lfrfid_app_scene_start.cpp deleted file mode 100644 index 5005c9afb..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_start.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#include "lfrfid_app_scene_start.h" - -typedef enum { - SubmenuRead, - SubmenuSaved, - SubmenuAddManually, - SubmenuExtraActions, -} SubmenuIndex; - -void LfRfidAppSceneStart::on_enter(LfRfidApp* app, bool need_restore) { - auto submenu = app->view_controller.get(); - - submenu->add_item("Read", SubmenuRead, submenu_callback, app); - submenu->add_item("Saved", SubmenuSaved, submenu_callback, app); - submenu->add_item("Add Manually", SubmenuAddManually, submenu_callback, app); - submenu->add_item("Extra Actions", SubmenuExtraActions, submenu_callback, app); - - if(need_restore) { - submenu->set_selected_item(submenu_item_selected); - } - - app->view_controller.switch_to(); - - // clear key - string_reset(app->file_name); - app->protocol_id = PROTOCOL_NO; - app->read_type = LFRFIDWorkerReadTypeAuto; -} - -bool LfRfidAppSceneStart::on_event(LfRfidApp* app, LfRfidApp::Event* event) { - bool consumed = false; - - if(event->type == LfRfidApp::EventType::MenuSelected) { - submenu_item_selected = event->payload.signed_int; - switch(event->payload.signed_int) { - case SubmenuRead: - app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::Read); - break; - case SubmenuSaved: - app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SelectKey); - break; - case SubmenuAddManually: - app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SaveType); - break; - case SubmenuExtraActions: - app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::ExtraActions); - break; - } - consumed = true; - } - - return consumed; -} - -void LfRfidAppSceneStart::on_exit(LfRfidApp* app) { - app->view_controller.get()->clean(); -} - -void LfRfidAppSceneStart::submenu_callback(void* context, uint32_t index) { - LfRfidApp* app = static_cast(context); - LfRfidApp::Event event; - - event.type = LfRfidApp::EventType::MenuSelected; - event.payload.signed_int = index; - - app->view_controller.send_event(&event); -} diff --git a/applications/lfrfid/scene/lfrfid_app_scene_start.h b/applications/lfrfid/scene/lfrfid_app_scene_start.h deleted file mode 100644 index 255590d6a..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_start.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#include "../lfrfid_app.h" - -class LfRfidAppSceneStart : public GenericScene { -public: - void on_enter(LfRfidApp* app, bool need_restore) final; - bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final; - void on_exit(LfRfidApp* app) final; - -private: - static void submenu_callback(void* context, uint32_t index); - uint32_t submenu_item_selected = 0; -}; diff --git a/applications/lfrfid/scene/lfrfid_app_scene_write.cpp b/applications/lfrfid/scene/lfrfid_app_scene_write.cpp deleted file mode 100644 index 8e04d8e8d..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_write.cpp +++ /dev/null @@ -1,79 +0,0 @@ -#include "lfrfid_app_scene_write.h" - -static void lfrfid_write_callback(LFRFIDWorkerWriteResult result, void* ctx) { - LfRfidApp* app = static_cast(ctx); - LfRfidApp::Event event; - - switch(result) { - case LFRFIDWorkerWriteOK: - event.type = LfRfidApp::EventType::WriteEventOK; - break; - case LFRFIDWorkerWriteProtocolCannotBeWritten: - event.type = LfRfidApp::EventType::WriteEventProtocolCannotBeWritten; - break; - case LFRFIDWorkerWriteFobCannotBeWritten: - event.type = LfRfidApp::EventType::WriteEventFobCannotBeWritten; - break; - case LFRFIDWorkerWriteTooLongToWrite: - event.type = LfRfidApp::EventType::WriteEventTooLongToWrite; - break; - } - - app->view_controller.send_event(&event); -} - -void LfRfidAppSceneWrite::on_enter(LfRfidApp* app, bool /* need_restore */) { - auto popup = app->view_controller.get(); - - popup->set_header("Writing", 89, 30, AlignCenter, AlignTop); - if(string_size(app->file_name)) { - popup->set_text(string_get_cstr(app->file_name), 89, 43, AlignCenter, AlignTop); - } else { - popup->set_text( - protocol_dict_get_name(app->dict, app->protocol_id), 89, 43, AlignCenter, AlignTop); - } - popup->set_icon(0, 3, &I_RFIDDolphinSend_97x61); - - app->view_controller.switch_to(); - lfrfid_worker_start_thread(app->lfworker); - lfrfid_worker_write_start( - app->lfworker, (LFRFIDProtocol)app->protocol_id, lfrfid_write_callback, app); - notification_message(app->notification, &sequence_blink_start_magenta); -} - -bool LfRfidAppSceneWrite::on_event(LfRfidApp* app, LfRfidApp::Event* event) { - bool consumed = true; - auto popup = app->view_controller.get(); - - switch(event->type) { - case LfRfidApp::EventType::WriteEventOK: - notification_message(app->notification, &sequence_success); - app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::WriteSuccess); - break; - case LfRfidApp::EventType::WriteEventProtocolCannotBeWritten: - popup->set_icon(72, 17, &I_DolphinCommon_56x48); - popup->set_header("Error", 64, 3, AlignCenter, AlignTop); - popup->set_text("This protocol\ncannot be written", 3, 17, AlignLeft, AlignTop); - notification_message(app->notification, &sequence_blink_start_red); - break; - case LfRfidApp::EventType::WriteEventFobCannotBeWritten: - case LfRfidApp::EventType::WriteEventTooLongToWrite: - popup->set_icon(72, 17, &I_DolphinCommon_56x48); - popup->set_header("Still trying to write...", 64, 3, AlignCenter, AlignTop); - popup->set_text( - "Make sure this\ncard is writable\nand not\nprotected.", 3, 17, AlignLeft, AlignTop); - notification_message(app->notification, &sequence_blink_start_yellow); - break; - default: - consumed = false; - } - - return consumed; -} - -void LfRfidAppSceneWrite::on_exit(LfRfidApp* app) { - notification_message(app->notification, &sequence_blink_stop); - app->view_controller.get()->clean(); - lfrfid_worker_stop(app->lfworker); - lfrfid_worker_stop_thread(app->lfworker); -} diff --git a/applications/lfrfid/scene/lfrfid_app_scene_write.h b/applications/lfrfid/scene/lfrfid_app_scene_write.h deleted file mode 100644 index 7564eff9d..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_write.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "../lfrfid_app.h" - -class LfRfidAppSceneWrite : public GenericScene { -public: - void on_enter(LfRfidApp* app, bool need_restore) final; - bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final; - void on_exit(LfRfidApp* app) final; -}; diff --git a/applications/lfrfid/scene/lfrfid_app_scene_write_success.cpp b/applications/lfrfid/scene/lfrfid_app_scene_write_success.cpp deleted file mode 100644 index 3cf00183d..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_write_success.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "lfrfid_app_scene_write_success.h" - -void LfRfidAppSceneWriteSuccess::on_enter(LfRfidApp* app, bool /* need_restore */) { - auto popup = app->view_controller.get(); - popup->set_header("Successfully\nwritten!", 94, 3, AlignCenter, AlignTop); - popup->set_icon(0, 6, &I_RFIDDolphinSuccess_108x57); - popup->set_context(app); - popup->set_callback(LfRfidAppSceneWriteSuccess::timeout_callback); - popup->set_timeout(1500); - popup->enable_timeout(); - - app->view_controller.switch_to(); - notification_message_block(app->notification, &sequence_set_green_255); -} - -bool LfRfidAppSceneWriteSuccess::on_event(LfRfidApp* app, LfRfidApp::Event* event) { - bool consumed = false; - - if(event->type == LfRfidApp::EventType::Back) { - app->scene_controller.search_and_switch_to_previous_scene( - {LfRfidApp::SceneType::ReadKeyMenu, LfRfidApp::SceneType::SelectKey}); - consumed = true; - } - - return consumed; -} - -void LfRfidAppSceneWriteSuccess::on_exit(LfRfidApp* app) { - notification_message_block(app->notification, &sequence_reset_green); - app->view_controller.get()->clean(); -} - -void LfRfidAppSceneWriteSuccess::timeout_callback(void* context) { - LfRfidApp* app = static_cast(context); - LfRfidApp::Event event; - event.type = LfRfidApp::EventType::Back; - app->view_controller.send_event(&event); -} diff --git a/applications/lfrfid/scene/lfrfid_app_scene_write_success.h b/applications/lfrfid/scene/lfrfid_app_scene_write_success.h deleted file mode 100644 index 4ac9f0892..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_write_success.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#include "../lfrfid_app.h" - -class LfRfidAppSceneWriteSuccess : public GenericScene { -public: - void on_enter(LfRfidApp* app, bool need_restore) final; - bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final; - void on_exit(LfRfidApp* app) final; - -private: - static void timeout_callback(void* context); -}; diff --git a/applications/lfrfid/view/container_vm.cpp b/applications/lfrfid/view/container_vm.cpp deleted file mode 100644 index 3c01ba304..000000000 --- a/applications/lfrfid/view/container_vm.cpp +++ /dev/null @@ -1,115 +0,0 @@ -#include "container_vm.h" -#include "elements/generic_element.h" -#include "elements/string_element.h" -#include "elements/icon_element.h" -#include "elements/button_element.h" -#include - -class ContainerVMData { -public: - ContainerVMData(){}; - - ~ContainerVMData() { - for(auto& it : elements) delete it; - }; - - std::list elements; - - template T add(const T element, View* view) { - elements.push_back(element); - element->set_parent_view(view); - return element; - } - - void clean() { - for(auto& it : elements) delete it; - elements.clear(); - } -}; - -struct ContainerVMModel { - ContainerVMData* data; -}; - -ContainerVM::ContainerVM() { - view = view_alloc(); - view_set_context(view, this); - view_allocate_model(view, ViewModelTypeLocking, sizeof(ContainerVMModel)); - - with_view_model_cpp(view, ContainerVMModel, model, { - model->data = new ContainerVMData(); - return true; - }); - - view_set_draw_callback(view, view_draw_callback); - view_set_input_callback(view, view_input_callback); -} - -ContainerVM::~ContainerVM() { - with_view_model_cpp(view, ContainerVMModel, model, { - delete model->data; - model->data = NULL; - return false; - }); - - view_free(view); -} - -View* ContainerVM::get_view() { - return view; -} - -void ContainerVM::clean() { - with_view_model_cpp(view, ContainerVMModel, model, { - model->data->clean(); - return true; - }); -} - -template T* ContainerVM::add() { - T* element = new T(); - - with_view_model_cpp(view, ContainerVMModel, model, { - model->data->add(element, view); - return true; - }); - - return element; -} - -void ContainerVM::view_draw_callback(Canvas* canvas, void* model) { - ContainerVMData* data = static_cast(model)->data; - - canvas_clear(canvas); - canvas_set_color(canvas, ColorBlack); - canvas_set_font(canvas, FontPrimary); - - for(const auto& element : data->elements) { - element->draw(canvas); - } -} - -bool ContainerVM::view_input_callback(InputEvent* event, void* context) { - bool consumed = false; - View* view = static_cast(context)->view; - - with_view_model_cpp(view, ContainerVMModel, model, { - for(const auto& element : model->data->elements) { - if(element->input(event)) { - consumed = true; - } - - if(consumed) { - break; - } - } - - return consumed; - }); - - return consumed; -} - -template StringElement* ContainerVM::add(); -template IconElement* ContainerVM::add(); -template ButtonElement* ContainerVM::add(); diff --git a/applications/lfrfid/view/container_vm.h b/applications/lfrfid/view/container_vm.h deleted file mode 100644 index 011baa2e9..000000000 --- a/applications/lfrfid/view/container_vm.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once -#include - -class ContainerVM : public GenericViewModule { -public: - ContainerVM(); - ~ContainerVM() final; - View* get_view() final; - void clean() final; - - template T* add(); - -private: - View* view; - static void view_draw_callback(Canvas* canvas, void* model); - static bool view_input_callback(InputEvent* event, void* context); -}; diff --git a/applications/lfrfid/view/elements/button_element.cpp b/applications/lfrfid/view/elements/button_element.cpp deleted file mode 100644 index 58e1ac3e1..000000000 --- a/applications/lfrfid/view/elements/button_element.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include "button_element.h" -#include - -ButtonElement::ButtonElement() { -} - -ButtonElement::~ButtonElement() { -} - -void ButtonElement::draw(Canvas* canvas) { - if(text != nullptr) { - canvas_set_font(canvas, FontSecondary); - switch(type) { - case Type::Left: - elements_button_left(canvas, text); - break; - case Type::Center: - elements_button_center(canvas, text); - break; - case Type::Right: - elements_button_right(canvas, text); - break; - } - } -} - -bool ButtonElement::input(InputEvent* event) { - bool consumed = false; - if(event->type == InputTypeShort && callback != nullptr) { - switch(type) { - case Type::Left: - if(event->key == InputKeyLeft) { - callback(context); - consumed = true; - } - break; - case Type::Center: - if(event->key == InputKeyOk) { - callback(context); - consumed = true; - } - break; - case Type::Right: - if(event->key == InputKeyRight) { - callback(context); - consumed = true; - } - break; - } - } - - return consumed; -} - -void ButtonElement::set_type(Type _type, const char* _text) { - lock_model(); - type = _type; - text = _text; - unlock_model(true); -} - -void ButtonElement::set_callback(void* _context, ButtonElementCallback _callback) { - context = _context; - callback = _callback; -} diff --git a/applications/lfrfid/view/elements/button_element.h b/applications/lfrfid/view/elements/button_element.h deleted file mode 100644 index eb9644277..000000000 --- a/applications/lfrfid/view/elements/button_element.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once -#include "generic_element.h" - -typedef void (*ButtonElementCallback)(void* context); - -class ButtonElement : public GenericElement { -public: - ButtonElement(); - ~ButtonElement() final; - void draw(Canvas* canvas) final; - bool input(InputEvent* event) final; - - enum class Type : uint8_t { - Left, - Center, - Right, - }; - - void set_type(Type type, const char* text); - void set_callback(void* context, ButtonElementCallback callback); - -private: - Type type = Type::Left; - const char* text = nullptr; - - void* context = nullptr; - ButtonElementCallback callback = nullptr; -}; diff --git a/applications/lfrfid/view/elements/generic_element.cpp b/applications/lfrfid/view/elements/generic_element.cpp deleted file mode 100644 index e0f08d15c..000000000 --- a/applications/lfrfid/view/elements/generic_element.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "generic_element.h" - -void GenericElement::lock_model() { - furi_assert(view != nullptr); - view_get_model(view); -} - -void GenericElement::unlock_model(bool need_redraw) { - furi_assert(view != nullptr); - view_commit_model(view, need_redraw); -} - -void GenericElement::set_parent_view(View* _view) { - view = _view; -} diff --git a/applications/lfrfid/view/elements/generic_element.h b/applications/lfrfid/view/elements/generic_element.h deleted file mode 100644 index f5a58b2d9..000000000 --- a/applications/lfrfid/view/elements/generic_element.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once -#include -#include - -class GenericElement { -public: - GenericElement(){}; - virtual ~GenericElement(){}; - virtual void draw(Canvas* canvas) = 0; - virtual bool input(InputEvent* event) = 0; - - // TODO that must be accessible only to ContainerVMData - void set_parent_view(View* view); - - // TODO that must be accessible only to inheritors - void lock_model(); - void unlock_model(bool need_redraw); - -private: - View* view = nullptr; -}; diff --git a/applications/lfrfid/view/elements/icon_element.cpp b/applications/lfrfid/view/elements/icon_element.cpp deleted file mode 100644 index 0b6fba7da..000000000 --- a/applications/lfrfid/view/elements/icon_element.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include "icon_element.h" - -IconElement::IconElement() { -} - -IconElement::~IconElement() { -} - -void IconElement::draw(Canvas* canvas) { - if(icon != NULL) { - canvas_draw_icon(canvas, x, y, icon); - } -} - -bool IconElement::input(InputEvent* /* event */) { - return false; -} - -void IconElement::set_icon(uint8_t _x, uint8_t _y, const Icon* _icon) { - lock_model(); - icon = _icon; - x = _x; - y = _y; - unlock_model(true); -} diff --git a/applications/lfrfid/view/elements/icon_element.h b/applications/lfrfid/view/elements/icon_element.h deleted file mode 100644 index a08202741..000000000 --- a/applications/lfrfid/view/elements/icon_element.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once -#include "generic_element.h" - -class IconElement : public GenericElement { -public: - IconElement(); - ~IconElement() final; - void draw(Canvas* canvas) final; - bool input(InputEvent* event) final; - - void set_icon(uint8_t x = 0, uint8_t y = 0, const Icon* icon = NULL); - -private: - const Icon* icon = NULL; - uint8_t x = 0; - uint8_t y = 0; -}; diff --git a/applications/lfrfid/view/elements/string_element.cpp b/applications/lfrfid/view/elements/string_element.cpp deleted file mode 100644 index 44c11e01a..000000000 --- a/applications/lfrfid/view/elements/string_element.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include "string_element.h" -#include - -StringElement::StringElement() { -} - -StringElement::~StringElement() { -} - -void StringElement::draw(Canvas* canvas) { - if(text) { - string_t line; - string_init(line); - string_set_str(line, text); - - canvas_set_font(canvas, font); - if(fit_width != 0) { - elements_string_fit_width(canvas, line, fit_width); - } - elements_multiline_text_aligned(canvas, x, y, horizontal, vertical, string_get_cstr(line)); - - string_clear(line); - } -} - -bool StringElement::input(InputEvent* /* event */) { - return false; -} - -void StringElement::set_text( - const char* _text, - uint8_t _x, - uint8_t _y, - uint8_t _fit_w, - Align _horizontal, - Align _vertical, - Font _font) { - lock_model(); - text = _text; - x = _x; - y = _y; - fit_width = _fit_w; - horizontal = _horizontal; - vertical = _vertical; - font = _font; - unlock_model(true); -} diff --git a/applications/lfrfid/view/elements/string_element.h b/applications/lfrfid/view/elements/string_element.h deleted file mode 100644 index 173fdd601..000000000 --- a/applications/lfrfid/view/elements/string_element.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once -#include "generic_element.h" - -class StringElement : public GenericElement { -public: - StringElement(); - ~StringElement() final; - void draw(Canvas* canvas) final; - bool input(InputEvent* event) final; - - void set_text( - const char* text = NULL, - uint8_t x = 0, - uint8_t y = 0, - uint8_t fit_width = 0, - Align horizontal = AlignLeft, - Align vertical = AlignTop, - Font font = FontPrimary); - -private: - const char* text = NULL; - uint8_t x = 0; - uint8_t y = 0; - uint8_t fit_width = 0; - Align horizontal = AlignLeft; - Align vertical = AlignTop; - Font font = FontPrimary; -}; diff --git a/applications/lfrfid_debug/lfrfid_debug_app.cpp b/applications/lfrfid_debug/lfrfid_debug_app.cpp deleted file mode 100644 index ef970e361..000000000 --- a/applications/lfrfid_debug/lfrfid_debug_app.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "lfrfid_debug_app.h" -#include "scene/lfrfid_debug_app_scene_start.h" -#include "scene/lfrfid_debug_app_scene_tune.h" - -LfRfidDebugApp::LfRfidDebugApp() - : scene_controller{this} { -} - -LfRfidDebugApp::~LfRfidDebugApp() { -} - -void LfRfidDebugApp::run() { - view_controller.attach_to_gui(ViewDispatcherTypeFullscreen); - scene_controller.add_scene(SceneType::Start, new LfRfidDebugAppSceneStart()); - scene_controller.add_scene(SceneType::TuneScene, new LfRfidDebugAppSceneTune()); - scene_controller.process(100); -} diff --git a/applications/lfrfid_debug/lfrfid_debug_app.h b/applications/lfrfid_debug/lfrfid_debug_app.h deleted file mode 100644 index fee183aec..000000000 --- a/applications/lfrfid_debug/lfrfid_debug_app.h +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once -#include -#include - -#include -#include -#include - -#include -#include "view_modules/lfrfid_view_tune_vm.h" - -class LfRfidDebugApp { -public: - enum class EventType : uint8_t { - GENERIC_EVENT_ENUM_VALUES, - MenuSelected, - }; - - enum class SceneType : uint8_t { - GENERIC_SCENE_ENUM_VALUES, - TuneScene, - }; - - class Event { - public: - union { - int32_t menu_index; - } payload; - - EventType type; - }; - - SceneController, LfRfidDebugApp> scene_controller; - ViewController view_controller; - - ~LfRfidDebugApp(); - LfRfidDebugApp(); - - void run(); -}; diff --git a/applications/lfrfid_debug/lfrfid_debug_app_launcher.cpp b/applications/lfrfid_debug/lfrfid_debug_app_launcher.cpp deleted file mode 100644 index 4551a17cb..000000000 --- a/applications/lfrfid_debug/lfrfid_debug_app_launcher.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "lfrfid_debug_app.h" - -// app enter function -extern "C" int32_t lfrfid_debug_app(void* p) { - UNUSED(p); - LfRfidDebugApp* app = new LfRfidDebugApp(); - app->run(); - delete app; - - return 0; -} diff --git a/applications/lfrfid_debug/scene/lfrfid_debug_app_scene_start.cpp b/applications/lfrfid_debug/scene/lfrfid_debug_app_scene_start.cpp deleted file mode 100644 index 873e152a1..000000000 --- a/applications/lfrfid_debug/scene/lfrfid_debug_app_scene_start.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include "lfrfid_debug_app_scene_start.h" - -typedef enum { - SubmenuTune, -} SubmenuIndex; - -void LfRfidDebugAppSceneStart::on_enter(LfRfidDebugApp* app, bool need_restore) { - auto submenu = app->view_controller.get(); - auto callback = cbc::obtain_connector(this, &LfRfidDebugAppSceneStart::submenu_callback); - - submenu->add_item("Tune", SubmenuTune, callback, app); - - if(need_restore) { - submenu->set_selected_item(submenu_item_selected); - } - app->view_controller.switch_to(); -} - -bool LfRfidDebugAppSceneStart::on_event(LfRfidDebugApp* app, LfRfidDebugApp::Event* event) { - bool consumed = false; - - if(event->type == LfRfidDebugApp::EventType::MenuSelected) { - submenu_item_selected = event->payload.menu_index; - switch(event->payload.menu_index) { - case SubmenuTune: - app->scene_controller.switch_to_next_scene(LfRfidDebugApp::SceneType::TuneScene); - break; - } - consumed = true; - } - - return consumed; -} - -void LfRfidDebugAppSceneStart::on_exit(LfRfidDebugApp* app) { - app->view_controller.get()->clean(); -} - -void LfRfidDebugAppSceneStart::submenu_callback(void* context, uint32_t index) { - LfRfidDebugApp* app = static_cast(context); - LfRfidDebugApp::Event event; - - event.type = LfRfidDebugApp::EventType::MenuSelected; - event.payload.menu_index = index; - - app->view_controller.send_event(&event); -} diff --git a/applications/lfrfid_debug/scene/lfrfid_debug_app_scene_start.h b/applications/lfrfid_debug/scene/lfrfid_debug_app_scene_start.h deleted file mode 100644 index 7fc0b07d9..000000000 --- a/applications/lfrfid_debug/scene/lfrfid_debug_app_scene_start.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#include "../lfrfid_debug_app.h" - -class LfRfidDebugAppSceneStart : public GenericScene { -public: - void on_enter(LfRfidDebugApp* app, bool need_restore) final; - bool on_event(LfRfidDebugApp* app, LfRfidDebugApp::Event* event) final; - void on_exit(LfRfidDebugApp* app) final; - -private: - void submenu_callback(void* context, uint32_t index); - uint32_t submenu_item_selected = 0; -}; diff --git a/applications/lfrfid_debug/scene/lfrfid_debug_app_scene_tune.h b/applications/lfrfid_debug/scene/lfrfid_debug_app_scene_tune.h deleted file mode 100644 index 53399efc9..000000000 --- a/applications/lfrfid_debug/scene/lfrfid_debug_app_scene_tune.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "../lfrfid_debug_app.h" - -class LfRfidDebugAppSceneTune : public GenericScene { -public: - void on_enter(LfRfidDebugApp* app, bool need_restore) final; - bool on_event(LfRfidDebugApp* app, LfRfidDebugApp::Event* event) final; - void on_exit(LfRfidDebugApp* app) final; -}; diff --git a/applications/lfrfid_debug/view_modules/lfrfid_view_tune_vm.cpp b/applications/lfrfid_debug/view_modules/lfrfid_view_tune_vm.cpp deleted file mode 100644 index 5c244b92c..000000000 --- a/applications/lfrfid_debug/view_modules/lfrfid_view_tune_vm.cpp +++ /dev/null @@ -1,214 +0,0 @@ -#include "lfrfid_view_tune_vm.h" -#include -#include - -struct LfRfidViewTuneVMModel { - bool dirty; - bool fine; - uint32_t ARR; - uint32_t CCR; - int pos; -}; - -void LfRfidViewTuneVM::view_draw_callback(Canvas* canvas, void* _model) { - LfRfidViewTuneVMModel* model = reinterpret_cast(_model); - canvas_clear(canvas); - canvas_set_color(canvas, ColorBlack); - - if(model->fine) { - canvas_draw_box( - canvas, - 128 - canvas_string_width(canvas, "Fine") - 4, - 0, - canvas_string_width(canvas, "Fine") + 4, - canvas_current_font_height(canvas) + 1); - canvas_set_color(canvas, ColorWhite); - } - canvas_draw_str_aligned(canvas, 128 - 2, 2, AlignRight, AlignTop, "Fine"); - canvas_set_color(canvas, ColorBlack); - - constexpr uint8_t buffer_size = 128; - char buffer[buffer_size + 1]; - double freq = ((float)SystemCoreClock / ((float)model->ARR + 1)); - double duty = ((float)model->CCR + 1) / ((float)model->ARR + 1) * 100.0f; - snprintf( - buffer, - buffer_size, - "%sARR: %lu\n" - "freq = %.4f\n" - "%sCCR: %lu\n" - "duty = %.4f", - model->pos == 0 ? ">" : "", - model->ARR, - freq, - model->pos == 1 ? ">" : "", - model->CCR, - duty); - elements_multiline_text_aligned(canvas, 2, 2, AlignLeft, AlignTop, buffer); -} - -bool LfRfidViewTuneVM::view_input_callback(InputEvent* event, void* context) { - LfRfidViewTuneVM* _this = reinterpret_cast(context); - bool consumed = false; - - // Process key presses only - if(event->type == InputTypeShort || event->type == InputTypeRepeat) { - consumed = true; - - switch(event->key) { - case InputKeyLeft: - _this->button_left(); - break; - case InputKeyRight: - _this->button_right(); - break; - case InputKeyUp: - _this->button_up(); - break; - case InputKeyDown: - _this->button_down(); - break; - case InputKeyOk: - _this->button_ok(); - break; - default: - consumed = false; - break; - } - } - - return consumed; -} - -void LfRfidViewTuneVM::button_up() { - with_view_model_cpp(view, LfRfidViewTuneVMModel, model, { - if(model->pos > 0) model->pos--; - return true; - }); -} - -void LfRfidViewTuneVM::button_down() { - with_view_model_cpp(view, LfRfidViewTuneVMModel, model, { - if(model->pos < 1) model->pos++; - return true; - }); -} - -void LfRfidViewTuneVM::button_left() { - with_view_model_cpp(view, LfRfidViewTuneVMModel, model, { - if(model->pos == 0) { - if(model->fine) { - model->ARR -= 1; - } else { - model->ARR -= 10; - } - } else if(model->pos == 1) { - if(model->fine) { - model->CCR -= 1; - } else { - model->CCR -= 10; - } - } - - model->dirty = true; - return true; - }); -} - -void LfRfidViewTuneVM::button_right() { - with_view_model_cpp(view, LfRfidViewTuneVMModel, model, { - if(model->pos == 0) { - if(model->fine) { - model->ARR += 1; - } else { - model->ARR += 10; - } - } else if(model->pos == 1) { - if(model->fine) { - model->CCR += 1; - } else { - model->CCR += 10; - } - } - - model->dirty = true; - return true; - }); -} - -void LfRfidViewTuneVM::button_ok() { - with_view_model_cpp(view, LfRfidViewTuneVMModel, model, { - model->fine = !model->fine; - return true; - }); -} - -LfRfidViewTuneVM::LfRfidViewTuneVM() { - view = view_alloc(); - view_set_context(view, this); - view_allocate_model(view, ViewModelTypeLocking, sizeof(LfRfidViewTuneVMModel)); - - with_view_model_cpp(view, LfRfidViewTuneVMModel, model, { - model->dirty = true; - model->fine = false; - model->ARR = 511; - model->CCR = 255; - model->pos = 0; - return true; - }); - - view_set_draw_callback( - view, cbc::obtain_connector(this, &LfRfidViewTuneVM::view_draw_callback)); - view_set_input_callback( - view, cbc::obtain_connector(this, &LfRfidViewTuneVM::view_input_callback)); -} - -LfRfidViewTuneVM::~LfRfidViewTuneVM() { - view_free(view); -} - -View* LfRfidViewTuneVM::get_view() { - return view; -} - -void LfRfidViewTuneVM::clean() { - with_view_model_cpp(view, LfRfidViewTuneVMModel, model, { - model->dirty = true; - model->fine = false; - model->ARR = 511; - model->CCR = 255; - model->pos = 0; - return true; - }); -} - -bool LfRfidViewTuneVM::is_dirty() { - bool result; - with_view_model_cpp(view, LfRfidViewTuneVMModel, model, { - result = model->dirty; - model->dirty = false; - return false; - }); - - return result; -} - -uint32_t LfRfidViewTuneVM::get_ARR() { - uint32_t result; - with_view_model_cpp(view, LfRfidViewTuneVMModel, model, { - result = model->ARR; - return false; - }); - - return result; -} - -uint32_t LfRfidViewTuneVM::get_CCR() { - uint32_t result; - with_view_model_cpp(view, LfRfidViewTuneVMModel, model, { - result = model->CCR; - return false; - }); - - return result; -} diff --git a/applications/lfrfid_debug/view_modules/lfrfid_view_tune_vm.h b/applications/lfrfid_debug/view_modules/lfrfid_view_tune_vm.h deleted file mode 100644 index 7fb185654..000000000 --- a/applications/lfrfid_debug/view_modules/lfrfid_view_tune_vm.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once -#include -#include - -class LfRfidViewTuneVM : public GenericViewModule { -public: - LfRfidViewTuneVM(); - ~LfRfidViewTuneVM() final; - View* get_view() final; - void clean() final; - - bool is_dirty(); - uint32_t get_ARR(); - uint32_t get_CCR(); - -private: - View* view; - void view_draw_callback(Canvas* canvas, void* _model); - bool view_input_callback(InputEvent* event, void* context); - - void button_up(); - void button_down(); - void button_left(); - void button_right(); - void button_ok(); -}; diff --git a/applications/main/application.fam b/applications/main/application.fam new file mode 100644 index 000000000..1fc309905 --- /dev/null +++ b/applications/main/application.fam @@ -0,0 +1,17 @@ +App( + appid="main_apps", + name="Basic applications for main menu", + apptype=FlipperAppType.METAPACKAGE, + provides=[ + "gpio", + "ibutton", + "infrared", + "lfrfid", + "nfc", + "subghz", + "bad_usb", + "u2f", + "fap_loader", + "archive", + ], +) diff --git a/applications/archive/application.fam b/applications/main/archive/application.fam similarity index 100% rename from applications/archive/application.fam rename to applications/main/archive/application.fam diff --git a/applications/archive/archive.c b/applications/main/archive/archive.c similarity index 100% rename from applications/archive/archive.c rename to applications/main/archive/archive.c diff --git a/applications/archive/archive.h b/applications/main/archive/archive.h similarity index 100% rename from applications/archive/archive.h rename to applications/main/archive/archive.h diff --git a/applications/archive/archive_i.h b/applications/main/archive/archive_i.h similarity index 100% rename from applications/archive/archive_i.h rename to applications/main/archive/archive_i.h diff --git a/applications/archive/helpers/archive_apps.c b/applications/main/archive/helpers/archive_apps.c similarity index 100% rename from applications/archive/helpers/archive_apps.c rename to applications/main/archive/helpers/archive_apps.c diff --git a/applications/archive/helpers/archive_apps.h b/applications/main/archive/helpers/archive_apps.h similarity index 100% rename from applications/archive/helpers/archive_apps.h rename to applications/main/archive/helpers/archive_apps.h diff --git a/applications/archive/helpers/archive_browser.c b/applications/main/archive/helpers/archive_browser.c similarity index 98% rename from applications/archive/helpers/archive_browser.c rename to applications/main/archive/helpers/archive_browser.c index 2dfb9484b..00bb6b063 100644 --- a/applications/archive/helpers/archive_browser.c +++ b/applications/main/archive/helpers/archive_browser.c @@ -1,4 +1,4 @@ -#include "archive/views/archive_browser_view.h" +#include #include "archive_files.h" #include "archive_apps.h" #include "archive_browser.h" @@ -270,7 +270,7 @@ void archive_file_array_load(ArchiveBrowserView* browser, int8_t dir) { ArchiveFile_t* archive_get_current_file(ArchiveBrowserView* browser) { furi_assert(browser); - ArchiveFile_t* selected; + ArchiveFile_t* selected = NULL; with_view_model( browser->view, (ArchiveBrowserViewModel * model) { selected = files_array_size(model->files) ? @@ -284,7 +284,7 @@ ArchiveFile_t* archive_get_current_file(ArchiveBrowserView* browser) { ArchiveFile_t* archive_get_file_at(ArchiveBrowserView* browser, size_t idx) { furi_assert(browser); - ArchiveFile_t* selected; + ArchiveFile_t* selected = NULL; with_view_model( browser->view, (ArchiveBrowserViewModel * model) { @@ -298,7 +298,7 @@ ArchiveFile_t* archive_get_file_at(ArchiveBrowserView* browser, size_t idx) { ArchiveTabEnum archive_get_tab(ArchiveBrowserView* browser) { furi_assert(browser); - ArchiveTabEnum tab_id; + ArchiveTabEnum tab_id = 0; with_view_model( browser->view, (ArchiveBrowserViewModel * model) { tab_id = model->tab_idx; @@ -451,8 +451,6 @@ void archive_switch_tab(ArchiveBrowserView* browser, InputKey key) { archive_file_browser_set_path( browser, browser->path, archive_get_tab_ext(tab), skip_assets); tab_empty = false; // Empty check will be performed later - } else { - tab_empty = true; } } diff --git a/applications/archive/helpers/archive_browser.h b/applications/main/archive/helpers/archive_browser.h similarity index 100% rename from applications/archive/helpers/archive_browser.h rename to applications/main/archive/helpers/archive_browser.h diff --git a/applications/archive/helpers/archive_favorites.c b/applications/main/archive/helpers/archive_favorites.c similarity index 100% rename from applications/archive/helpers/archive_favorites.c rename to applications/main/archive/helpers/archive_favorites.c diff --git a/applications/archive/helpers/archive_favorites.h b/applications/main/archive/helpers/archive_favorites.h similarity index 100% rename from applications/archive/helpers/archive_favorites.h rename to applications/main/archive/helpers/archive_favorites.h diff --git a/applications/archive/helpers/archive_files.c b/applications/main/archive/helpers/archive_files.c similarity index 100% rename from applications/archive/helpers/archive_files.c rename to applications/main/archive/helpers/archive_files.c diff --git a/applications/archive/helpers/archive_files.h b/applications/main/archive/helpers/archive_files.h similarity index 100% rename from applications/archive/helpers/archive_files.h rename to applications/main/archive/helpers/archive_files.h diff --git a/applications/archive/scenes/archive_scene.c b/applications/main/archive/scenes/archive_scene.c similarity index 100% rename from applications/archive/scenes/archive_scene.c rename to applications/main/archive/scenes/archive_scene.c diff --git a/applications/archive/scenes/archive_scene.h b/applications/main/archive/scenes/archive_scene.h similarity index 100% rename from applications/archive/scenes/archive_scene.h rename to applications/main/archive/scenes/archive_scene.h diff --git a/applications/archive/scenes/archive_scene_browser.c b/applications/main/archive/scenes/archive_scene_browser.c similarity index 100% rename from applications/archive/scenes/archive_scene_browser.c rename to applications/main/archive/scenes/archive_scene_browser.c diff --git a/applications/archive/scenes/archive_scene_config.h b/applications/main/archive/scenes/archive_scene_config.h similarity index 100% rename from applications/archive/scenes/archive_scene_config.h rename to applications/main/archive/scenes/archive_scene_config.h diff --git a/applications/archive/scenes/archive_scene_delete.c b/applications/main/archive/scenes/archive_scene_delete.c similarity index 100% rename from applications/archive/scenes/archive_scene_delete.c rename to applications/main/archive/scenes/archive_scene_delete.c diff --git a/applications/archive/scenes/archive_scene_rename.c b/applications/main/archive/scenes/archive_scene_rename.c similarity index 100% rename from applications/archive/scenes/archive_scene_rename.c rename to applications/main/archive/scenes/archive_scene_rename.c diff --git a/applications/archive/views/archive_browser_view.c b/applications/main/archive/views/archive_browser_view.c similarity index 99% rename from applications/archive/views/archive_browser_view.c rename to applications/main/archive/views/archive_browser_view.c index 174071ad4..ddd6637db 100644 --- a/applications/archive/views/archive_browser_view.c +++ b/applications/main/archive/views/archive_browser_view.c @@ -194,7 +194,7 @@ static void archive_render_status_bar(Canvas* canvas, ArchiveBrowserViewModel* m canvas_set_color(canvas, ColorBlack); } -void archive_view_render(Canvas* canvas, void* mdl) { +static void archive_view_render(Canvas* canvas, void* mdl) { ArchiveBrowserViewModel* model = mdl; archive_render_status_bar(canvas, mdl); @@ -234,7 +234,7 @@ static bool is_file_list_load_required(ArchiveBrowserViewModel* model) { return false; } -bool archive_view_input(InputEvent* event, void* context) { +static bool archive_view_input(InputEvent* event, void* context) { furi_assert(event); furi_assert(context); diff --git a/applications/archive/views/archive_browser_view.h b/applications/main/archive/views/archive_browser_view.h similarity index 100% rename from applications/archive/views/archive_browser_view.h rename to applications/main/archive/views/archive_browser_view.h diff --git a/applications/bad_usb/application.fam b/applications/main/bad_usb/application.fam similarity index 100% rename from applications/bad_usb/application.fam rename to applications/main/bad_usb/application.fam diff --git a/applications/bad_usb/bad_usb_app.c b/applications/main/bad_usb/bad_usb_app.c similarity index 100% rename from applications/bad_usb/bad_usb_app.c rename to applications/main/bad_usb/bad_usb_app.c diff --git a/applications/bad_usb/bad_usb_app.h b/applications/main/bad_usb/bad_usb_app.h similarity index 100% rename from applications/bad_usb/bad_usb_app.h rename to applications/main/bad_usb/bad_usb_app.h diff --git a/applications/bad_usb/bad_usb_app_i.h b/applications/main/bad_usb/bad_usb_app_i.h similarity index 100% rename from applications/bad_usb/bad_usb_app_i.h rename to applications/main/bad_usb/bad_usb_app_i.h diff --git a/applications/bad_usb/bad_usb_script.c b/applications/main/bad_usb/bad_usb_script.c similarity index 100% rename from applications/bad_usb/bad_usb_script.c rename to applications/main/bad_usb/bad_usb_script.c diff --git a/applications/bad_usb/bad_usb_script.h b/applications/main/bad_usb/bad_usb_script.h similarity index 100% rename from applications/bad_usb/bad_usb_script.h rename to applications/main/bad_usb/bad_usb_script.h diff --git a/applications/bad_usb/scenes/bad_usb_scene.c b/applications/main/bad_usb/scenes/bad_usb_scene.c similarity index 100% rename from applications/bad_usb/scenes/bad_usb_scene.c rename to applications/main/bad_usb/scenes/bad_usb_scene.c diff --git a/applications/bad_usb/scenes/bad_usb_scene.h b/applications/main/bad_usb/scenes/bad_usb_scene.h similarity index 100% rename from applications/bad_usb/scenes/bad_usb_scene.h rename to applications/main/bad_usb/scenes/bad_usb_scene.h diff --git a/applications/bad_usb/scenes/bad_usb_scene_config.h b/applications/main/bad_usb/scenes/bad_usb_scene_config.h similarity index 100% rename from applications/bad_usb/scenes/bad_usb_scene_config.h rename to applications/main/bad_usb/scenes/bad_usb_scene_config.h diff --git a/applications/bad_usb/scenes/bad_usb_scene_error.c b/applications/main/bad_usb/scenes/bad_usb_scene_error.c similarity index 100% rename from applications/bad_usb/scenes/bad_usb_scene_error.c rename to applications/main/bad_usb/scenes/bad_usb_scene_error.c diff --git a/applications/bad_usb/scenes/bad_usb_scene_file_select.c b/applications/main/bad_usb/scenes/bad_usb_scene_file_select.c similarity index 80% rename from applications/bad_usb/scenes/bad_usb_scene_file_select.c rename to applications/main/bad_usb/scenes/bad_usb_scene_file_select.c index 1e6ba895a..c562fc2de 100644 --- a/applications/bad_usb/scenes/bad_usb_scene_file_select.c +++ b/applications/main/bad_usb/scenes/bad_usb_scene_file_select.c @@ -5,15 +5,12 @@ static bool bad_usb_file_select(BadUsbApp* bad_usb) { furi_assert(bad_usb); + DialogsFileBrowserOptions browser_options; + dialog_file_browser_set_basic_options(&browser_options, BAD_USB_APP_EXTENSION, &I_badusb_10px); + // Input events and views are managed by file_browser bool res = dialog_file_browser_show( - bad_usb->dialogs, - bad_usb->file_path, - bad_usb->file_path, - BAD_USB_APP_EXTENSION, - true, - &I_badusb_10px, - true); + bad_usb->dialogs, bad_usb->file_path, bad_usb->file_path, &browser_options); return res; } diff --git a/applications/bad_usb/scenes/bad_usb_scene_work.c b/applications/main/bad_usb/scenes/bad_usb_scene_work.c similarity index 100% rename from applications/bad_usb/scenes/bad_usb_scene_work.c rename to applications/main/bad_usb/scenes/bad_usb_scene_work.c diff --git a/applications/bad_usb/views/bad_usb_view.c b/applications/main/bad_usb/views/bad_usb_view.c similarity index 100% rename from applications/bad_usb/views/bad_usb_view.c rename to applications/main/bad_usb/views/bad_usb_view.c diff --git a/applications/bad_usb/views/bad_usb_view.h b/applications/main/bad_usb/views/bad_usb_view.h old mode 100755 new mode 100644 similarity index 100% rename from applications/bad_usb/views/bad_usb_view.h rename to applications/main/bad_usb/views/bad_usb_view.h diff --git a/applications/main/fap_loader/application.fam b/applications/main/fap_loader/application.fam new file mode 100644 index 000000000..bd0403e0e --- /dev/null +++ b/applications/main/fap_loader/application.fam @@ -0,0 +1,13 @@ +App( + appid="fap_loader", + name="Applications", + apptype=FlipperAppType.APP, + entry_point="fap_loader_app", + requires=[ + "gui", + "storage", + ], + stack_size=int(1.5 * 1024), + icon="A_Plugins_14", + order=90, +) diff --git a/applications/main/fap_loader/elf_cpp/compilesort.hpp b/applications/main/fap_loader/elf_cpp/compilesort.hpp new file mode 100644 index 000000000..746611697 --- /dev/null +++ b/applications/main/fap_loader/elf_cpp/compilesort.hpp @@ -0,0 +1,111 @@ +/** + * Implementation of compile-time sort for symbol table entries. + */ + +#pragma once + +#include +#include + +namespace cstd { + +template +constexpr RAIt next(RAIt it, typename std::iterator_traits::difference_type n = 1) { + return it + n; +} + +template +constexpr auto distance(RAIt first, RAIt last) { + return last - first; +} + +template +constexpr void iter_swap(ForwardIt1 a, ForwardIt2 b) { + auto temp = std::move(*a); + *a = std::move(*b); + *b = std::move(temp); +} + +template +constexpr InputIt find_if_not(InputIt first, InputIt last, UnaryPredicate q) { + for(; first != last; ++first) { + if(!q(*first)) { + return first; + } + } + return last; +} + +template +constexpr ForwardIt partition(ForwardIt first, ForwardIt last, UnaryPredicate p) { + first = cstd::find_if_not(first, last, p); + if(first == last) return first; + + for(ForwardIt i = cstd::next(first); i != last; ++i) { + if(p(*i)) { + cstd::iter_swap(i, first); + ++first; + } + } + return first; +} + +} + +template > +constexpr void quick_sort(RAIt first, RAIt last, Compare cmp = Compare{}) { + auto const N = cstd::distance(first, last); + if(N <= 1) return; + auto const pivot = *cstd::next(first, N / 2); + auto const middle1 = + cstd::partition(first, last, [=](auto const& elem) { return cmp(elem, pivot); }); + auto const middle2 = + cstd::partition(middle1, last, [=](auto const& elem) { return !cmp(pivot, elem); }); + quick_sort(first, middle1, cmp); // assert(std::is_sorted(first, middle1, cmp)); + quick_sort(middle2, last, cmp); // assert(std::is_sorted(middle2, last, cmp)); +} + +template +constexpr auto sort(Range&& range) { + quick_sort(std::begin(range), std::end(range)); + return range; +} + +template +constexpr auto array_of(T&&... t) -> std::array { + return {{std::forward(t)...}}; +} + +template +constexpr auto my_make_array(N&&... args) -> std::array { + return {std::forward(args)...}; +} + +namespace traits { +template +struct array_type { + using type = T; +}; + +template +static constexpr bool are_same_type() { + return std::conjunction_v...>; +} + +} + +template +constexpr auto create_array(const T&&... values) { + using array_type = typename traits::array_type::type; + static_assert(sizeof...(T) > 0, "an array must have at least one element"); + static_assert(traits::are_same_type(), "all elements must have same type"); + return std::array{values...}; +} + +template +constexpr auto create_array_t(const Ts&&... values) { + using array_type = T; + static_assert(sizeof...(Ts) > 0, "an array must have at least one element"); + static_assert(traits::are_same_type(), "all elements must have same type"); + return std::array{static_cast(values)...}; +} diff --git a/applications/main/fap_loader/elf_cpp/elf_hashtable.cpp b/applications/main/fap_loader/elf_cpp/elf_hashtable.cpp new file mode 100644 index 000000000..17e2ba83f --- /dev/null +++ b/applications/main/fap_loader/elf_cpp/elf_hashtable.cpp @@ -0,0 +1,48 @@ +#include "compilesort.hpp" +#include "elf_hashtable.h" +#include "elf_hashtable_entry.h" +#include "elf_hashtable_checks.hpp" + +#include +#include + +/* Generated table */ +#include + +#define TAG "elf_hashtable" + +static_assert(!has_hash_collisions(elf_api_table), "Detected API method hash collision!"); + +/** + * Get function address by function name + * @param name function name + * @param address output for function address + * @return true if the table contains a function + */ + +bool elf_resolve_from_hashtable(const char* name, Elf32_Addr* address) { + bool result = false; + uint32_t gnu_sym_hash = elf_gnu_hash(name); + + sym_entry key = { + .hash = gnu_sym_hash, + .address = 0, + }; + + auto find_res = std::lower_bound(elf_api_table.cbegin(), elf_api_table.cend(), key); + if((find_res == elf_api_table.cend() || (find_res->hash != gnu_sym_hash))) { + FURI_LOG_W(TAG, "Cant find symbol '%s' (hash %x)!", name, gnu_sym_hash); + result = false; + } else { + result = true; + *address = find_res->address; + } + + return result; +} + +const ElfApiInterface hashtable_api_interface = { + .api_version_major = (elf_api_version >> 16), + .api_version_minor = (elf_api_version & 0xFFFF), + .resolver_callback = &elf_resolve_from_hashtable, +}; diff --git a/applications/main/fap_loader/elf_cpp/elf_hashtable.h b/applications/main/fap_loader/elf_cpp/elf_hashtable.h new file mode 100644 index 000000000..e574f1169 --- /dev/null +++ b/applications/main/fap_loader/elf_cpp/elf_hashtable.h @@ -0,0 +1,14 @@ +#pragma once +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern const ElfApiInterface hashtable_api_interface; + +#ifdef __cplusplus +} +#endif diff --git a/applications/main/fap_loader/elf_cpp/elf_hashtable_checks.hpp b/applications/main/fap_loader/elf_cpp/elf_hashtable_checks.hpp new file mode 100644 index 000000000..61ee80e91 --- /dev/null +++ b/applications/main/fap_loader/elf_cpp/elf_hashtable_checks.hpp @@ -0,0 +1,18 @@ +/** + * Check for multiple entries with the same hash value at compilation time. + */ + +#pragma once +#include +#include "elf_hashtable_entry.h" + +template +constexpr bool has_hash_collisions(const std::array api_methods) { + for(std::size_t i = 0; i < (N - 1); ++i) { + if(api_methods[i].hash == api_methods[i + 1].hash) { + return true; + } + } + + return false; +} diff --git a/applications/main/fap_loader/elf_cpp/elf_hashtable_entry.h b/applications/main/fap_loader/elf_cpp/elf_hashtable_entry.h new file mode 100644 index 000000000..7b540fba6 --- /dev/null +++ b/applications/main/fap_loader/elf_cpp/elf_hashtable_entry.h @@ -0,0 +1,41 @@ +#pragma once +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct sym_entry { + uint32_t hash; + uint32_t address; +}; + +#ifdef __cplusplus +} + +#include +#include + +#define API_METHOD(x, ret_type, args_type) \ + sym_entry { \ + .hash = elf_gnu_hash(#x), .address = (uint32_t)(static_cast(x)) \ + } + +#define API_VARIABLE(x, var_type) \ + sym_entry { \ + .hash = elf_gnu_hash(#x), .address = (uint32_t)(&(x)), \ + } + +constexpr bool operator<(const sym_entry& k1, const sym_entry& k2) { + return k1.hash < k2.hash; +} + +constexpr uint32_t elf_gnu_hash(const char* s) { + uint32_t h = 0x1505; + for(unsigned char c = *s; c != '\0'; c = *++s) { + h = (h << 5) + h + c; + } + return h; +} + +#endif diff --git a/applications/main/fap_loader/fap_loader_app.c b/applications/main/fap_loader/fap_loader_app.c new file mode 100644 index 000000000..14da2f320 --- /dev/null +++ b/applications/main/fap_loader/fap_loader_app.c @@ -0,0 +1,176 @@ +#include +#include +#include +#include +#include +#include +#include "elf_cpp/elf_hashtable.h" +#include + +#define TAG "fap_loader_app" + +typedef struct { + FlipperApplication* app; + Storage* storage; + DialogsApp* dialogs; + Gui* gui; + string_t fap_path; +} FapLoader; + +static bool + fap_loader_item_callback(string_t path, void* context, uint8_t** icon_ptr, string_t item_name) { + FapLoader* loader = context; + furi_assert(loader); + + FlipperApplication* app = flipper_application_alloc(loader->storage, &hashtable_api_interface); + + FlipperApplicationPreloadStatus preload_res = + flipper_application_preload(app, string_get_cstr(path)); + + bool load_success = false; + + if(preload_res == FlipperApplicationPreloadStatusSuccess) { + const FlipperApplicationManifest* manifest = flipper_application_get_manifest(app); + if(manifest->has_icon) { + memcpy(*icon_ptr, manifest->icon, FAP_MANIFEST_MAX_ICON_SIZE); + } + string_set_str(item_name, manifest->name); + load_success = true; + } else { + FURI_LOG_E(TAG, "FAP Loader failed to preload %s", string_get_cstr(path)); + load_success = false; + } + + flipper_application_free(app); + return load_success; +} + +static bool fap_loader_run_selected_app(FapLoader* loader) { + furi_assert(loader); + + string_t error_message; + + string_init_set(error_message, "unknown error"); + + bool file_selected = false; + bool show_error = true; + do { + file_selected = true; + loader->app = flipper_application_alloc(loader->storage, &hashtable_api_interface); + + FURI_LOG_I(TAG, "FAP Loader is loading %s", string_get_cstr(loader->fap_path)); + + FlipperApplicationPreloadStatus preload_res = + flipper_application_preload(loader->app, string_get_cstr(loader->fap_path)); + if(preload_res != FlipperApplicationPreloadStatusSuccess) { + const char* err_msg = flipper_application_preload_status_to_string(preload_res); + string_printf(error_message, "Preload failed: %s", err_msg); + FURI_LOG_E( + TAG, + "FAP Loader failed to preload %s: %s", + string_get_cstr(loader->fap_path), + err_msg); + break; + } + + FURI_LOG_I(TAG, "FAP Loader is mapping"); + FlipperApplicationLoadStatus load_status = flipper_application_map_to_memory(loader->app); + if(load_status != FlipperApplicationLoadStatusSuccess) { + const char* err_msg = flipper_application_load_status_to_string(load_status); + string_printf(error_message, "Load failed: %s", err_msg); + FURI_LOG_E( + TAG, + "FAP Loader failed to map to memory %s: %s", + string_get_cstr(loader->fap_path), + err_msg); + break; + } + + FURI_LOG_I(TAG, "FAP Loader is staring app"); + + FuriThread* thread = flipper_application_spawn(loader->app, NULL); + furi_thread_start(thread); + furi_thread_join(thread); + + show_error = false; + int ret = furi_thread_get_return_code(thread); + + FURI_LOG_I(TAG, "FAP app returned: %i", ret); + } while(0); + + if(show_error) { + DialogMessage* message = dialog_message_alloc(); + dialog_message_set_header(message, "Error", 64, 0, AlignCenter, AlignTop); + dialog_message_set_buttons(message, NULL, NULL, NULL); + + string_t buffer; + string_init(buffer); + string_printf(buffer, "%s", string_get_cstr(error_message)); + string_replace_str(buffer, ":", "\n"); + dialog_message_set_text( + message, string_get_cstr(buffer), 64, 32, AlignCenter, AlignCenter); + + dialog_message_show(loader->dialogs, message); + dialog_message_free(message); + string_clear(buffer); + } + + string_clear(error_message); + + if(file_selected) { + flipper_application_free(loader->app); + } + + return file_selected; +} + +static bool fap_loader_select_app(FapLoader* loader) { + const DialogsFileBrowserOptions browser_options = { + .extension = ".fap", + .skip_assets = true, + .icon = &I_badusb_10px, + .hide_ext = true, + .item_loader_callback = fap_loader_item_callback, + .item_loader_context = loader, + }; + + return dialog_file_browser_show( + loader->dialogs, loader->fap_path, loader->fap_path, &browser_options); +} + +int32_t fap_loader_app(void* p) { + FapLoader* loader = malloc(sizeof(FapLoader)); + loader->storage = furi_record_open(RECORD_STORAGE); + loader->dialogs = furi_record_open(RECORD_DIALOGS); + loader->gui = furi_record_open(RECORD_GUI); + + ViewDispatcher* view_dispatcher = view_dispatcher_alloc(); + Loading* loading = loading_alloc(); + + view_dispatcher_enable_queue(view_dispatcher); + view_dispatcher_attach_to_gui(view_dispatcher, loader->gui, ViewDispatcherTypeFullscreen); + view_dispatcher_add_view(view_dispatcher, 0, loading_get_view(loading)); + + if(p) { + string_init_set(loader->fap_path, (const char*)p); + fap_loader_run_selected_app(loader); + } else { + string_init_set(loader->fap_path, EXT_PATH("apps")); + + while(fap_loader_select_app(loader)) { + view_dispatcher_switch_to_view(view_dispatcher, 0); + fap_loader_run_selected_app(loader); + }; + } + + view_dispatcher_remove_view(view_dispatcher, 0); + loading_free(loading); + view_dispatcher_free(view_dispatcher); + + string_clear(loader->fap_path); + furi_record_close(RECORD_GUI); + furi_record_close(RECORD_DIALOGS); + furi_record_close(RECORD_STORAGE); + free(loader); + return 0; +} \ No newline at end of file diff --git a/applications/gpio/application.fam b/applications/main/gpio/application.fam similarity index 100% rename from applications/gpio/application.fam rename to applications/main/gpio/application.fam diff --git a/applications/gpio/gpio_app.c b/applications/main/gpio/gpio_app.c similarity index 100% rename from applications/gpio/gpio_app.c rename to applications/main/gpio/gpio_app.c diff --git a/applications/gpio/gpio_app.h b/applications/main/gpio/gpio_app.h similarity index 100% rename from applications/gpio/gpio_app.h rename to applications/main/gpio/gpio_app.h diff --git a/applications/gpio/gpio_app_i.h b/applications/main/gpio/gpio_app_i.h similarity index 100% rename from applications/gpio/gpio_app_i.h rename to applications/main/gpio/gpio_app_i.h diff --git a/applications/gpio/gpio_custom_event.h b/applications/main/gpio/gpio_custom_event.h similarity index 100% rename from applications/gpio/gpio_custom_event.h rename to applications/main/gpio/gpio_custom_event.h diff --git a/applications/gpio/gpio_item.c b/applications/main/gpio/gpio_item.c similarity index 100% rename from applications/gpio/gpio_item.c rename to applications/main/gpio/gpio_item.c diff --git a/applications/gpio/gpio_item.h b/applications/main/gpio/gpio_item.h similarity index 100% rename from applications/gpio/gpio_item.h rename to applications/main/gpio/gpio_item.h diff --git a/applications/gpio/scenes/gpio_scene.c b/applications/main/gpio/scenes/gpio_scene.c similarity index 100% rename from applications/gpio/scenes/gpio_scene.c rename to applications/main/gpio/scenes/gpio_scene.c diff --git a/applications/gpio/scenes/gpio_scene.h b/applications/main/gpio/scenes/gpio_scene.h similarity index 100% rename from applications/gpio/scenes/gpio_scene.h rename to applications/main/gpio/scenes/gpio_scene.h diff --git a/applications/gpio/scenes/gpio_scene_config.h b/applications/main/gpio/scenes/gpio_scene_config.h similarity index 100% rename from applications/gpio/scenes/gpio_scene_config.h rename to applications/main/gpio/scenes/gpio_scene_config.h diff --git a/applications/gpio/scenes/gpio_scene_start.c b/applications/main/gpio/scenes/gpio_scene_start.c similarity index 100% rename from applications/gpio/scenes/gpio_scene_start.c rename to applications/main/gpio/scenes/gpio_scene_start.c diff --git a/applications/gpio/scenes/gpio_scene_test.c b/applications/main/gpio/scenes/gpio_scene_test.c similarity index 100% rename from applications/gpio/scenes/gpio_scene_test.c rename to applications/main/gpio/scenes/gpio_scene_test.c diff --git a/applications/gpio/scenes/gpio_scene_usb_uart.c b/applications/main/gpio/scenes/gpio_scene_usb_uart.c similarity index 100% rename from applications/gpio/scenes/gpio_scene_usb_uart.c rename to applications/main/gpio/scenes/gpio_scene_usb_uart.c diff --git a/applications/gpio/scenes/gpio_scene_usb_uart_close_rpc.c b/applications/main/gpio/scenes/gpio_scene_usb_uart_close_rpc.c similarity index 100% rename from applications/gpio/scenes/gpio_scene_usb_uart_close_rpc.c rename to applications/main/gpio/scenes/gpio_scene_usb_uart_close_rpc.c diff --git a/applications/gpio/scenes/gpio_scene_usb_uart_config.c b/applications/main/gpio/scenes/gpio_scene_usb_uart_config.c similarity index 100% rename from applications/gpio/scenes/gpio_scene_usb_uart_config.c rename to applications/main/gpio/scenes/gpio_scene_usb_uart_config.c diff --git a/applications/gpio/usb_uart_bridge.c b/applications/main/gpio/usb_uart_bridge.c similarity index 99% rename from applications/gpio/usb_uart_bridge.c rename to applications/main/gpio/usb_uart_bridge.c index 4623c4af1..02f58ed10 100644 --- a/applications/gpio/usb_uart_bridge.c +++ b/applications/main/gpio/usb_uart_bridge.c @@ -1,7 +1,7 @@ #include "usb_uart_bridge.h" #include "furi_hal.h" #include -#include +#include #include "usb_cdc.h" #include "cli/cli_vcp.h" #include "cli/cli.h" diff --git a/applications/gpio/usb_uart_bridge.h b/applications/main/gpio/usb_uart_bridge.h similarity index 100% rename from applications/gpio/usb_uart_bridge.h rename to applications/main/gpio/usb_uart_bridge.h diff --git a/applications/gpio/views/gpio_test.c b/applications/main/gpio/views/gpio_test.c old mode 100755 new mode 100644 similarity index 100% rename from applications/gpio/views/gpio_test.c rename to applications/main/gpio/views/gpio_test.c diff --git a/applications/gpio/views/gpio_test.h b/applications/main/gpio/views/gpio_test.h old mode 100755 new mode 100644 similarity index 100% rename from applications/gpio/views/gpio_test.h rename to applications/main/gpio/views/gpio_test.h diff --git a/applications/gpio/views/gpio_usb_uart.c b/applications/main/gpio/views/gpio_usb_uart.c similarity index 100% rename from applications/gpio/views/gpio_usb_uart.c rename to applications/main/gpio/views/gpio_usb_uart.c diff --git a/applications/gpio/views/gpio_usb_uart.h b/applications/main/gpio/views/gpio_usb_uart.h old mode 100755 new mode 100644 similarity index 100% rename from applications/gpio/views/gpio_usb_uart.h rename to applications/main/gpio/views/gpio_usb_uart.h diff --git a/applications/ibutton/application.fam b/applications/main/ibutton/application.fam similarity index 100% rename from applications/ibutton/application.fam rename to applications/main/ibutton/application.fam diff --git a/applications/ibutton/ibutton.c b/applications/main/ibutton/ibutton.c similarity index 98% rename from applications/ibutton/ibutton.c rename to applications/main/ibutton/ibutton.c index 7ee1110e1..e9ec614ec 100644 --- a/applications/ibutton/ibutton.c +++ b/applications/main/ibutton/ibutton.c @@ -216,14 +216,11 @@ void ibutton_free(iButton* ibutton) { } bool ibutton_file_select(iButton* ibutton) { + DialogsFileBrowserOptions browser_options; + dialog_file_browser_set_basic_options(&browser_options, IBUTTON_APP_EXTENSION, &I_ibutt_10px); + bool success = dialog_file_browser_show( - ibutton->dialogs, - ibutton->file_path, - ibutton->file_path, - IBUTTON_APP_EXTENSION, - true, - &I_ibutt_10px, - true); + ibutton->dialogs, ibutton->file_path, ibutton->file_path, &browser_options); if(success) { success = ibutton_load_key_data(ibutton, ibutton->file_path, true); diff --git a/applications/ibutton/ibutton.h b/applications/main/ibutton/ibutton.h similarity index 100% rename from applications/ibutton/ibutton.h rename to applications/main/ibutton/ibutton.h diff --git a/applications/ibutton/ibutton_cli.c b/applications/main/ibutton/ibutton_cli.c similarity index 100% rename from applications/ibutton/ibutton_cli.c rename to applications/main/ibutton/ibutton_cli.c diff --git a/applications/ibutton/ibutton_custom_event.h b/applications/main/ibutton/ibutton_custom_event.h similarity index 100% rename from applications/ibutton/ibutton_custom_event.h rename to applications/main/ibutton/ibutton_custom_event.h diff --git a/applications/ibutton/ibutton_i.h b/applications/main/ibutton/ibutton_i.h similarity index 100% rename from applications/ibutton/ibutton_i.h rename to applications/main/ibutton/ibutton_i.h diff --git a/applications/ibutton/scenes/ibutton_scene.c b/applications/main/ibutton/scenes/ibutton_scene.c similarity index 100% rename from applications/ibutton/scenes/ibutton_scene.c rename to applications/main/ibutton/scenes/ibutton_scene.c diff --git a/applications/ibutton/scenes/ibutton_scene.h b/applications/main/ibutton/scenes/ibutton_scene.h similarity index 100% rename from applications/ibutton/scenes/ibutton_scene.h rename to applications/main/ibutton/scenes/ibutton_scene.h diff --git a/applications/ibutton/scenes/ibutton_scene_add_type.c b/applications/main/ibutton/scenes/ibutton_scene_add_type.c similarity index 100% rename from applications/ibutton/scenes/ibutton_scene_add_type.c rename to applications/main/ibutton/scenes/ibutton_scene_add_type.c diff --git a/applications/ibutton/scenes/ibutton_scene_add_value.c b/applications/main/ibutton/scenes/ibutton_scene_add_value.c similarity index 100% rename from applications/ibutton/scenes/ibutton_scene_add_value.c rename to applications/main/ibutton/scenes/ibutton_scene_add_value.c diff --git a/applications/ibutton/scenes/ibutton_scene_config.h b/applications/main/ibutton/scenes/ibutton_scene_config.h similarity index 100% rename from applications/ibutton/scenes/ibutton_scene_config.h rename to applications/main/ibutton/scenes/ibutton_scene_config.h diff --git a/applications/ibutton/scenes/ibutton_scene_delete_confirm.c b/applications/main/ibutton/scenes/ibutton_scene_delete_confirm.c similarity index 100% rename from applications/ibutton/scenes/ibutton_scene_delete_confirm.c rename to applications/main/ibutton/scenes/ibutton_scene_delete_confirm.c diff --git a/applications/ibutton/scenes/ibutton_scene_delete_success.c b/applications/main/ibutton/scenes/ibutton_scene_delete_success.c similarity index 100% rename from applications/ibutton/scenes/ibutton_scene_delete_success.c rename to applications/main/ibutton/scenes/ibutton_scene_delete_success.c diff --git a/applications/ibutton/scenes/ibutton_scene_emulate.c b/applications/main/ibutton/scenes/ibutton_scene_emulate.c similarity index 100% rename from applications/ibutton/scenes/ibutton_scene_emulate.c rename to applications/main/ibutton/scenes/ibutton_scene_emulate.c diff --git a/applications/ibutton/scenes/ibutton_scene_exit_confirm.c b/applications/main/ibutton/scenes/ibutton_scene_exit_confirm.c similarity index 100% rename from applications/ibutton/scenes/ibutton_scene_exit_confirm.c rename to applications/main/ibutton/scenes/ibutton_scene_exit_confirm.c diff --git a/applications/ibutton/scenes/ibutton_scene_info.c b/applications/main/ibutton/scenes/ibutton_scene_info.c similarity index 100% rename from applications/ibutton/scenes/ibutton_scene_info.c rename to applications/main/ibutton/scenes/ibutton_scene_info.c diff --git a/applications/ibutton/scenes/ibutton_scene_read.c b/applications/main/ibutton/scenes/ibutton_scene_read.c similarity index 100% rename from applications/ibutton/scenes/ibutton_scene_read.c rename to applications/main/ibutton/scenes/ibutton_scene_read.c diff --git a/applications/ibutton/scenes/ibutton_scene_read_crc_error.c b/applications/main/ibutton/scenes/ibutton_scene_read_crc_error.c similarity index 100% rename from applications/ibutton/scenes/ibutton_scene_read_crc_error.c rename to applications/main/ibutton/scenes/ibutton_scene_read_crc_error.c diff --git a/applications/ibutton/scenes/ibutton_scene_read_key_menu.c b/applications/main/ibutton/scenes/ibutton_scene_read_key_menu.c similarity index 100% rename from applications/ibutton/scenes/ibutton_scene_read_key_menu.c rename to applications/main/ibutton/scenes/ibutton_scene_read_key_menu.c diff --git a/applications/ibutton/scenes/ibutton_scene_read_not_key_error.c b/applications/main/ibutton/scenes/ibutton_scene_read_not_key_error.c similarity index 100% rename from applications/ibutton/scenes/ibutton_scene_read_not_key_error.c rename to applications/main/ibutton/scenes/ibutton_scene_read_not_key_error.c diff --git a/applications/ibutton/scenes/ibutton_scene_read_success.c b/applications/main/ibutton/scenes/ibutton_scene_read_success.c similarity index 100% rename from applications/ibutton/scenes/ibutton_scene_read_success.c rename to applications/main/ibutton/scenes/ibutton_scene_read_success.c diff --git a/applications/ibutton/scenes/ibutton_scene_retry_confirm.c b/applications/main/ibutton/scenes/ibutton_scene_retry_confirm.c similarity index 100% rename from applications/ibutton/scenes/ibutton_scene_retry_confirm.c rename to applications/main/ibutton/scenes/ibutton_scene_retry_confirm.c diff --git a/applications/ibutton/scenes/ibutton_scene_rpc.c b/applications/main/ibutton/scenes/ibutton_scene_rpc.c similarity index 100% rename from applications/ibutton/scenes/ibutton_scene_rpc.c rename to applications/main/ibutton/scenes/ibutton_scene_rpc.c diff --git a/applications/ibutton/scenes/ibutton_scene_save_name.c b/applications/main/ibutton/scenes/ibutton_scene_save_name.c similarity index 100% rename from applications/ibutton/scenes/ibutton_scene_save_name.c rename to applications/main/ibutton/scenes/ibutton_scene_save_name.c diff --git a/applications/ibutton/scenes/ibutton_scene_save_success.c b/applications/main/ibutton/scenes/ibutton_scene_save_success.c similarity index 100% rename from applications/ibutton/scenes/ibutton_scene_save_success.c rename to applications/main/ibutton/scenes/ibutton_scene_save_success.c diff --git a/applications/ibutton/scenes/ibutton_scene_saved_key_menu.c b/applications/main/ibutton/scenes/ibutton_scene_saved_key_menu.c similarity index 100% rename from applications/ibutton/scenes/ibutton_scene_saved_key_menu.c rename to applications/main/ibutton/scenes/ibutton_scene_saved_key_menu.c diff --git a/applications/ibutton/scenes/ibutton_scene_select_key.c b/applications/main/ibutton/scenes/ibutton_scene_select_key.c similarity index 100% rename from applications/ibutton/scenes/ibutton_scene_select_key.c rename to applications/main/ibutton/scenes/ibutton_scene_select_key.c diff --git a/applications/ibutton/scenes/ibutton_scene_start.c b/applications/main/ibutton/scenes/ibutton_scene_start.c similarity index 100% rename from applications/ibutton/scenes/ibutton_scene_start.c rename to applications/main/ibutton/scenes/ibutton_scene_start.c diff --git a/applications/ibutton/scenes/ibutton_scene_write.c b/applications/main/ibutton/scenes/ibutton_scene_write.c similarity index 100% rename from applications/ibutton/scenes/ibutton_scene_write.c rename to applications/main/ibutton/scenes/ibutton_scene_write.c diff --git a/applications/ibutton/scenes/ibutton_scene_write_success.c b/applications/main/ibutton/scenes/ibutton_scene_write_success.c similarity index 100% rename from applications/ibutton/scenes/ibutton_scene_write_success.c rename to applications/main/ibutton/scenes/ibutton_scene_write_success.c diff --git a/applications/infrared/application.fam b/applications/main/infrared/application.fam similarity index 100% rename from applications/infrared/application.fam rename to applications/main/infrared/application.fam diff --git a/applications/infrared/infrared.c b/applications/main/infrared/infrared.c similarity index 100% rename from applications/infrared/infrared.c rename to applications/main/infrared/infrared.c diff --git a/applications/infrared/infrared.h b/applications/main/infrared/infrared.h similarity index 100% rename from applications/infrared/infrared.h rename to applications/main/infrared/infrared.h diff --git a/applications/infrared/infrared_brute_force.c b/applications/main/infrared/infrared_brute_force.c similarity index 100% rename from applications/infrared/infrared_brute_force.c rename to applications/main/infrared/infrared_brute_force.c diff --git a/applications/infrared/infrared_brute_force.h b/applications/main/infrared/infrared_brute_force.h similarity index 100% rename from applications/infrared/infrared_brute_force.h rename to applications/main/infrared/infrared_brute_force.h diff --git a/applications/infrared/infrared_cli.c b/applications/main/infrared/infrared_cli.c similarity index 51% rename from applications/infrared/infrared_cli.c rename to applications/main/infrared/infrared_cli.c index aae02e8fd..693e191ee 100644 --- a/applications/infrared/infrared_cli.c +++ b/applications/main/infrared/infrared_cli.c @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include "infrared_signal.h" @@ -10,6 +12,7 @@ static void infrared_cli_start_ir_rx(Cli* cli, string_t args); static void infrared_cli_start_ir_tx(Cli* cli, string_t args); +static void infrared_cli_process_decode(Cli* cli, string_t args); static const struct { const char* cmd; @@ -17,6 +20,7 @@ static const struct { } infrared_cli_commands[] = { {.cmd = "rx", .process_function = infrared_cli_start_ir_rx}, {.cmd = "tx", .process_function = infrared_cli_start_ir_tx}, + {.cmd = "decode", .process_function = infrared_cli_process_decode}, }; static void signal_received_callback(void* context, InfraredWorkerSignal* received_signal) { @@ -86,6 +90,7 @@ static void infrared_cli_print_usage(void) { "\tFrequency (%d - %d), Duty cycle (0 - 100), max 512 samples\r\n", INFRARED_MIN_FREQUENCY, INFRARED_MAX_FREQUENCY); + printf("\tir decode []\r\n"); } static bool infrared_cli_parse_message(const char* str, InfraredSignal* signal) { @@ -162,6 +167,160 @@ static void infrared_cli_start_ir_tx(Cli* cli, string_t args) { infrared_signal_free(signal); } +static bool + infrared_cli_save_signal(InfraredSignal* signal, FlipperFormat* file, const char* name) { + bool ret = infrared_signal_save(signal, file, name); + if(!ret) { + printf("Failed to save signal: \"%s\"\r\n", name); + } + return ret; +} + +static bool infrared_cli_decode_raw_signal( + InfraredRawSignal* raw_signal, + InfraredDecoderHandler* decoder, + FlipperFormat* output_file, + const char* signal_name) { + InfraredSignal* signal = infrared_signal_alloc(); + bool ret = false, level = true, is_decoded = false; + + size_t i; + for(i = 0; i < raw_signal->timings_size; ++i) { + // TODO: Any infrared_check_decoder_ready() magic? + const InfraredMessage* message = infrared_decode(decoder, level, raw_signal->timings[i]); + + if(message) { + is_decoded = true; + printf( + "Protocol: %s address: 0x%lX command: 0x%lX %s\r\n", + infrared_get_protocol_name(message->protocol), + message->address, + message->command, + (message->repeat ? "R" : "")); + if(output_file && !message->repeat) { + infrared_signal_set_message(signal, message); + if(!infrared_cli_save_signal(signal, output_file, signal_name)) break; + } + } + + level = !level; + } + + if(i == raw_signal->timings_size) { + if(!is_decoded && output_file) { + infrared_signal_set_raw_signal( + signal, + raw_signal->timings, + raw_signal->timings_size, + raw_signal->frequency, + raw_signal->duty_cycle); + ret = infrared_cli_save_signal(signal, output_file, signal_name); + } else { + ret = true; + } + } + + infrared_reset_decoder(decoder); + infrared_signal_free(signal); + return ret; +} + +static bool infrared_cli_decode_file(FlipperFormat* input_file, FlipperFormat* output_file) { + bool ret = false; + + InfraredSignal* signal = infrared_signal_alloc(); + InfraredDecoderHandler* decoder = infrared_alloc_decoder(); + + string_t tmp; + string_init(tmp); + + while(infrared_signal_read(signal, input_file, tmp)) { + ret = false; + if(!infrared_signal_is_valid(signal)) { + printf("Invalid signal\r\n"); + break; + } + if(!infrared_signal_is_raw(signal)) { + if(output_file && + !infrared_cli_save_signal(signal, output_file, string_get_cstr(tmp))) { + break; + } else { + printf("Skipping decoded signal\r\n"); + continue; + } + } + InfraredRawSignal* raw_signal = infrared_signal_get_raw_signal(signal); + printf("Raw signal: %s, %u samples\r\n", string_get_cstr(tmp), raw_signal->timings_size); + if(!infrared_cli_decode_raw_signal(raw_signal, decoder, output_file, string_get_cstr(tmp))) + break; + ret = true; + } + + infrared_free_decoder(decoder); + infrared_signal_free(signal); + string_clear(tmp); + + return ret; +} + +static void infrared_cli_process_decode(Cli* cli, string_t args) { + UNUSED(cli); + Storage* storage = furi_record_open(RECORD_STORAGE); + FlipperFormat* input_file = flipper_format_buffered_file_alloc(storage); + FlipperFormat* output_file = NULL; + + uint32_t version; + string_t tmp, header, input_path, output_path; + string_init(tmp); + string_init(header); + string_init(input_path); + string_init(output_path); + + do { + if(!args_read_probably_quoted_string_and_trim(args, input_path)) { + printf("Wrong arguments.\r\n"); + infrared_cli_print_usage(); + break; + } + args_read_probably_quoted_string_and_trim(args, output_path); + if(!flipper_format_buffered_file_open_existing(input_file, string_get_cstr(input_path))) { + printf("Failed to open file for reading: \"%s\"\r\n", string_get_cstr(input_path)); + break; + } + if(!flipper_format_read_header(input_file, header, &version) || + (!string_start_with_str_p(header, "IR")) || version != 1) { + printf("Invalid or corrupted input file: \"%s\"\r\n", string_get_cstr(input_path)); + break; + } + if(!string_empty_p(output_path)) { + printf("Writing output to file: \"%s\"\r\n", string_get_cstr(output_path)); + output_file = flipper_format_file_alloc(storage); + } + if(output_file && + !flipper_format_file_open_always(output_file, string_get_cstr(output_path))) { + printf("Failed to open file for writing: \"%s\"\r\n", string_get_cstr(output_path)); + break; + } + if(output_file && !flipper_format_write_header(output_file, header, version)) { + printf("Failed to write to the output file: \"%s\"\r\n", string_get_cstr(output_path)); + break; + } + if(!infrared_cli_decode_file(input_file, output_file)) { + break; + } + printf("File successfully decoded.\r\n"); + } while(false); + + string_clear(tmp); + string_clear(header); + string_clear(input_path); + string_clear(output_path); + + flipper_format_free(input_file); + if(output_file) flipper_format_free(output_file); + furi_record_close(RECORD_STORAGE); +} + static void infrared_cli_start_ir(Cli* cli, string_t args, void* context) { UNUSED(context); if(furi_hal_infrared_is_busy()) { @@ -169,18 +328,15 @@ static void infrared_cli_start_ir(Cli* cli, string_t args, void* context) { return; } + string_t command; + string_init(command); + args_read_string_and_trim(args, command); + size_t i = 0; for(; i < COUNT_OF(infrared_cli_commands); ++i) { - size_t size = strlen(infrared_cli_commands[i].cmd); - bool cmd_found = !strncmp(string_get_cstr(args), infrared_cli_commands[i].cmd, size); - if(cmd_found) { - if(string_size(args) == size) { - break; - } - if(string_get_cstr(args)[size] == ' ') { - string_right(args, size + 1); - break; - } + size_t cmd_len = strlen(infrared_cli_commands[i].cmd); + if(!strncmp(string_get_cstr(command), infrared_cli_commands[i].cmd, cmd_len)) { + break; } } @@ -189,6 +345,8 @@ static void infrared_cli_start_ir(Cli* cli, string_t args, void* context) { } else { infrared_cli_print_usage(); } + + string_clear(command); } void infrared_on_system_start() { #ifdef SRV_CLI diff --git a/applications/infrared/infrared_custom_event.h b/applications/main/infrared/infrared_custom_event.h similarity index 100% rename from applications/infrared/infrared_custom_event.h rename to applications/main/infrared/infrared_custom_event.h diff --git a/applications/infrared/infrared_i.h b/applications/main/infrared/infrared_i.h similarity index 100% rename from applications/infrared/infrared_i.h rename to applications/main/infrared/infrared_i.h diff --git a/applications/infrared/infrared_remote.c b/applications/main/infrared/infrared_remote.c similarity index 100% rename from applications/infrared/infrared_remote.c rename to applications/main/infrared/infrared_remote.c diff --git a/applications/infrared/infrared_remote.h b/applications/main/infrared/infrared_remote.h similarity index 100% rename from applications/infrared/infrared_remote.h rename to applications/main/infrared/infrared_remote.h diff --git a/applications/infrared/infrared_remote_button.c b/applications/main/infrared/infrared_remote_button.c similarity index 100% rename from applications/infrared/infrared_remote_button.c rename to applications/main/infrared/infrared_remote_button.c diff --git a/applications/infrared/infrared_remote_button.h b/applications/main/infrared/infrared_remote_button.h similarity index 100% rename from applications/infrared/infrared_remote_button.h rename to applications/main/infrared/infrared_remote_button.h diff --git a/applications/infrared/infrared_signal.c b/applications/main/infrared/infrared_signal.c similarity index 100% rename from applications/infrared/infrared_signal.c rename to applications/main/infrared/infrared_signal.c diff --git a/applications/infrared/infrared_signal.h b/applications/main/infrared/infrared_signal.h similarity index 100% rename from applications/infrared/infrared_signal.h rename to applications/main/infrared/infrared_signal.h diff --git a/applications/infrared/scenes/common/infrared_scene_universal_common.c b/applications/main/infrared/scenes/common/infrared_scene_universal_common.c similarity index 100% rename from applications/infrared/scenes/common/infrared_scene_universal_common.c rename to applications/main/infrared/scenes/common/infrared_scene_universal_common.c diff --git a/applications/infrared/scenes/common/infrared_scene_universal_common.h b/applications/main/infrared/scenes/common/infrared_scene_universal_common.h similarity index 100% rename from applications/infrared/scenes/common/infrared_scene_universal_common.h rename to applications/main/infrared/scenes/common/infrared_scene_universal_common.h diff --git a/applications/infrared/scenes/infrared_scene.c b/applications/main/infrared/scenes/infrared_scene.c similarity index 100% rename from applications/infrared/scenes/infrared_scene.c rename to applications/main/infrared/scenes/infrared_scene.c diff --git a/applications/infrared/scenes/infrared_scene.h b/applications/main/infrared/scenes/infrared_scene.h similarity index 100% rename from applications/infrared/scenes/infrared_scene.h rename to applications/main/infrared/scenes/infrared_scene.h diff --git a/applications/infrared/scenes/infrared_scene_ask_back.c b/applications/main/infrared/scenes/infrared_scene_ask_back.c similarity index 100% rename from applications/infrared/scenes/infrared_scene_ask_back.c rename to applications/main/infrared/scenes/infrared_scene_ask_back.c diff --git a/applications/infrared/scenes/infrared_scene_ask_retry.c b/applications/main/infrared/scenes/infrared_scene_ask_retry.c similarity index 100% rename from applications/infrared/scenes/infrared_scene_ask_retry.c rename to applications/main/infrared/scenes/infrared_scene_ask_retry.c diff --git a/applications/infrared/scenes/infrared_scene_config.h b/applications/main/infrared/scenes/infrared_scene_config.h similarity index 100% rename from applications/infrared/scenes/infrared_scene_config.h rename to applications/main/infrared/scenes/infrared_scene_config.h diff --git a/applications/infrared/scenes/infrared_scene_debug.c b/applications/main/infrared/scenes/infrared_scene_debug.c similarity index 100% rename from applications/infrared/scenes/infrared_scene_debug.c rename to applications/main/infrared/scenes/infrared_scene_debug.c diff --git a/applications/infrared/scenes/infrared_scene_edit.c b/applications/main/infrared/scenes/infrared_scene_edit.c similarity index 100% rename from applications/infrared/scenes/infrared_scene_edit.c rename to applications/main/infrared/scenes/infrared_scene_edit.c diff --git a/applications/infrared/scenes/infrared_scene_edit_button_select.c b/applications/main/infrared/scenes/infrared_scene_edit_button_select.c similarity index 100% rename from applications/infrared/scenes/infrared_scene_edit_button_select.c rename to applications/main/infrared/scenes/infrared_scene_edit_button_select.c diff --git a/applications/infrared/scenes/infrared_scene_edit_delete.c b/applications/main/infrared/scenes/infrared_scene_edit_delete.c similarity index 100% rename from applications/infrared/scenes/infrared_scene_edit_delete.c rename to applications/main/infrared/scenes/infrared_scene_edit_delete.c diff --git a/applications/infrared/scenes/infrared_scene_edit_delete_done.c b/applications/main/infrared/scenes/infrared_scene_edit_delete_done.c similarity index 100% rename from applications/infrared/scenes/infrared_scene_edit_delete_done.c rename to applications/main/infrared/scenes/infrared_scene_edit_delete_done.c diff --git a/applications/infrared/scenes/infrared_scene_edit_rename.c b/applications/main/infrared/scenes/infrared_scene_edit_rename.c similarity index 100% rename from applications/infrared/scenes/infrared_scene_edit_rename.c rename to applications/main/infrared/scenes/infrared_scene_edit_rename.c diff --git a/applications/infrared/scenes/infrared_scene_edit_rename_done.c b/applications/main/infrared/scenes/infrared_scene_edit_rename_done.c similarity index 100% rename from applications/infrared/scenes/infrared_scene_edit_rename_done.c rename to applications/main/infrared/scenes/infrared_scene_edit_rename_done.c diff --git a/applications/infrared/scenes/infrared_scene_error_databases.c b/applications/main/infrared/scenes/infrared_scene_error_databases.c similarity index 100% rename from applications/infrared/scenes/infrared_scene_error_databases.c rename to applications/main/infrared/scenes/infrared_scene_error_databases.c diff --git a/applications/infrared/scenes/infrared_scene_learn.c b/applications/main/infrared/scenes/infrared_scene_learn.c similarity index 94% rename from applications/infrared/scenes/infrared_scene_learn.c rename to applications/main/infrared/scenes/infrared_scene_learn.c index 0edb74ca2..37f9b3e05 100644 --- a/applications/infrared/scenes/infrared_scene_learn.c +++ b/applications/main/infrared/scenes/infrared_scene_learn.c @@ -25,7 +25,6 @@ bool infrared_scene_learn_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == InfraredCustomEventTypeSignalReceived) { - infrared_worker_rx_set_received_signal_callback(infrared->worker, NULL, NULL); infrared_play_notification_message(infrared, InfraredNotificationMessageSuccess); scene_manager_next_scene(infrared->scene_manager, InfraredSceneLearnSuccess); consumed = true; @@ -38,6 +37,7 @@ bool infrared_scene_learn_on_event(void* context, SceneManagerEvent event) { void infrared_scene_learn_on_exit(void* context) { Infrared* infrared = context; Popup* popup = infrared->popup; + infrared_worker_rx_set_received_signal_callback(infrared->worker, NULL, NULL); infrared_worker_rx_stop(infrared->worker); infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStop); popup_set_icon(popup, 0, 0, NULL); diff --git a/applications/infrared/scenes/infrared_scene_learn_done.c b/applications/main/infrared/scenes/infrared_scene_learn_done.c similarity index 100% rename from applications/infrared/scenes/infrared_scene_learn_done.c rename to applications/main/infrared/scenes/infrared_scene_learn_done.c diff --git a/applications/infrared/scenes/infrared_scene_learn_enter_name.c b/applications/main/infrared/scenes/infrared_scene_learn_enter_name.c similarity index 100% rename from applications/infrared/scenes/infrared_scene_learn_enter_name.c rename to applications/main/infrared/scenes/infrared_scene_learn_enter_name.c diff --git a/applications/infrared/scenes/infrared_scene_learn_success.c b/applications/main/infrared/scenes/infrared_scene_learn_success.c similarity index 100% rename from applications/infrared/scenes/infrared_scene_learn_success.c rename to applications/main/infrared/scenes/infrared_scene_learn_success.c diff --git a/applications/infrared/scenes/infrared_scene_remote.c b/applications/main/infrared/scenes/infrared_scene_remote.c similarity index 100% rename from applications/infrared/scenes/infrared_scene_remote.c rename to applications/main/infrared/scenes/infrared_scene_remote.c diff --git a/applications/infrared/scenes/infrared_scene_remote_list.c b/applications/main/infrared/scenes/infrared_scene_remote_list.c similarity index 82% rename from applications/infrared/scenes/infrared_scene_remote_list.c rename to applications/main/infrared/scenes/infrared_scene_remote_list.c index b0038c1a3..1667352d1 100644 --- a/applications/infrared/scenes/infrared_scene_remote_list.c +++ b/applications/main/infrared/scenes/infrared_scene_remote_list.c @@ -5,14 +5,11 @@ void infrared_scene_remote_list_on_enter(void* context) { SceneManager* scene_manager = infrared->scene_manager; ViewDispatcher* view_dispatcher = infrared->view_dispatcher; + DialogsFileBrowserOptions browser_options; + dialog_file_browser_set_basic_options(&browser_options, INFRARED_APP_EXTENSION, &I_ir_10px); + bool success = dialog_file_browser_show( - infrared->dialogs, - infrared->file_path, - infrared->file_path, - INFRARED_APP_EXTENSION, - true, - &I_ir_10px, - true); + infrared->dialogs, infrared->file_path, infrared->file_path, &browser_options); if(success) { view_set_orientation(view_stack_get_view(infrared->view_stack), ViewOrientationVertical); diff --git a/applications/infrared/scenes/infrared_scene_rpc.c b/applications/main/infrared/scenes/infrared_scene_rpc.c similarity index 100% rename from applications/infrared/scenes/infrared_scene_rpc.c rename to applications/main/infrared/scenes/infrared_scene_rpc.c diff --git a/applications/infrared/scenes/infrared_scene_start.c b/applications/main/infrared/scenes/infrared_scene_start.c similarity index 100% rename from applications/infrared/scenes/infrared_scene_start.c rename to applications/main/infrared/scenes/infrared_scene_start.c diff --git a/applications/infrared/scenes/infrared_scene_universal.c b/applications/main/infrared/scenes/infrared_scene_universal.c similarity index 100% rename from applications/infrared/scenes/infrared_scene_universal.c rename to applications/main/infrared/scenes/infrared_scene_universal.c diff --git a/applications/infrared/scenes/infrared_scene_universal_tv.c b/applications/main/infrared/scenes/infrared_scene_universal_tv.c similarity index 100% rename from applications/infrared/scenes/infrared_scene_universal_tv.c rename to applications/main/infrared/scenes/infrared_scene_universal_tv.c diff --git a/applications/infrared/views/infrared_debug_view.c b/applications/main/infrared/views/infrared_debug_view.c similarity index 100% rename from applications/infrared/views/infrared_debug_view.c rename to applications/main/infrared/views/infrared_debug_view.c diff --git a/applications/infrared/views/infrared_debug_view.h b/applications/main/infrared/views/infrared_debug_view.h similarity index 100% rename from applications/infrared/views/infrared_debug_view.h rename to applications/main/infrared/views/infrared_debug_view.h diff --git a/applications/infrared/views/infrared_progress_view.c b/applications/main/infrared/views/infrared_progress_view.c similarity index 100% rename from applications/infrared/views/infrared_progress_view.c rename to applications/main/infrared/views/infrared_progress_view.c diff --git a/applications/infrared/views/infrared_progress_view.h b/applications/main/infrared/views/infrared_progress_view.h similarity index 100% rename from applications/infrared/views/infrared_progress_view.h rename to applications/main/infrared/views/infrared_progress_view.h diff --git a/applications/lfrfid/application.fam b/applications/main/lfrfid/application.fam similarity index 95% rename from applications/lfrfid/application.fam rename to applications/main/lfrfid/application.fam index 8722bb4f8..4a1498181 100644 --- a/applications/lfrfid/application.fam +++ b/applications/main/lfrfid/application.fam @@ -10,7 +10,6 @@ App( ], provides=[ "lfrfid_start", - "lfrfid_debug", ], icon="A_125khz_14", stack_size=2 * 1024, diff --git a/applications/main/lfrfid/lfrfid.c b/applications/main/lfrfid/lfrfid.c new file mode 100644 index 000000000..dbed9f3af --- /dev/null +++ b/applications/main/lfrfid/lfrfid.c @@ -0,0 +1,314 @@ +#include "lfrfid_i.h" + +static bool lfrfid_debug_custom_event_callback(void* context, uint32_t event) { + furi_assert(context); + LfRfid* app = context; + return scene_manager_handle_custom_event(app->scene_manager, event); +} + +static bool lfrfid_debug_back_event_callback(void* context) { + furi_assert(context); + LfRfid* app = context; + return scene_manager_handle_back_event(app->scene_manager); +} + +static void rpc_command_callback(RpcAppSystemEvent rpc_event, void* context) { + furi_assert(context); + LfRfid* app = (LfRfid*)context; + + if(rpc_event == RpcAppEventSessionClose) { + view_dispatcher_send_custom_event(app->view_dispatcher, LfRfidEventRpcSessionClose); + // Detach RPC + rpc_system_app_set_callback(app->rpc_ctx, NULL, NULL); + app->rpc_ctx = NULL; + } else if(rpc_event == RpcAppEventAppExit) { + view_dispatcher_send_custom_event(app->view_dispatcher, LfRfidEventExit); + } else if(rpc_event == RpcAppEventLoadFile) { + view_dispatcher_send_custom_event(app->view_dispatcher, LfRfidEventRpcLoadFile); + } else { + rpc_system_app_confirm(app->rpc_ctx, rpc_event, false); + } +} + +static LfRfid* lfrfid_alloc() { + LfRfid* lfrfid = malloc(sizeof(LfRfid)); + + lfrfid->storage = furi_record_open(RECORD_STORAGE); + lfrfid->dialogs = furi_record_open(RECORD_DIALOGS); + + string_init(lfrfid->file_name); + string_init(lfrfid->raw_file_name); + string_init_set_str(lfrfid->file_path, LFRFID_APP_FOLDER); + + lfrfid->dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax); + + size_t size = protocol_dict_get_max_data_size(lfrfid->dict); + lfrfid->new_key_data = (uint8_t*)malloc(size); + lfrfid->old_key_data = (uint8_t*)malloc(size); + + lfrfid->lfworker = lfrfid_worker_alloc(lfrfid->dict); + + lfrfid->view_dispatcher = view_dispatcher_alloc(); + lfrfid->scene_manager = scene_manager_alloc(&lfrfid_scene_handlers, lfrfid); + view_dispatcher_enable_queue(lfrfid->view_dispatcher); + view_dispatcher_set_event_callback_context(lfrfid->view_dispatcher, lfrfid); + view_dispatcher_set_custom_event_callback( + lfrfid->view_dispatcher, lfrfid_debug_custom_event_callback); + view_dispatcher_set_navigation_event_callback( + lfrfid->view_dispatcher, lfrfid_debug_back_event_callback); + + // Open GUI record + lfrfid->gui = furi_record_open(RECORD_GUI); + + // Open Notification record + lfrfid->notifications = furi_record_open(RECORD_NOTIFICATION); + + // Submenu + lfrfid->submenu = submenu_alloc(); + view_dispatcher_add_view( + lfrfid->view_dispatcher, LfRfidViewSubmenu, submenu_get_view(lfrfid->submenu)); + + // Dialog + lfrfid->dialog_ex = dialog_ex_alloc(); + view_dispatcher_add_view( + lfrfid->view_dispatcher, LfRfidViewDialogEx, dialog_ex_get_view(lfrfid->dialog_ex)); + + // Popup + lfrfid->popup = popup_alloc(); + view_dispatcher_add_view( + lfrfid->view_dispatcher, LfRfidViewPopup, popup_get_view(lfrfid->popup)); + + // Widget + lfrfid->widget = widget_alloc(); + view_dispatcher_add_view( + lfrfid->view_dispatcher, LfRfidViewWidget, widget_get_view(lfrfid->widget)); + + // Text Input + lfrfid->text_input = text_input_alloc(); + view_dispatcher_add_view( + lfrfid->view_dispatcher, LfRfidViewTextInput, text_input_get_view(lfrfid->text_input)); + + // Byte Input + lfrfid->byte_input = byte_input_alloc(); + view_dispatcher_add_view( + lfrfid->view_dispatcher, LfRfidViewByteInput, byte_input_get_view(lfrfid->byte_input)); + + // Read custom view + lfrfid->read_view = lfrfid_view_read_alloc(); + view_dispatcher_add_view( + lfrfid->view_dispatcher, LfRfidViewRead, lfrfid_view_read_get_view(lfrfid->read_view)); + + return lfrfid; +} + +static void lfrfid_free(LfRfid* lfrfid) { + furi_assert(lfrfid); + + string_clear(lfrfid->raw_file_name); + string_clear(lfrfid->file_name); + string_clear(lfrfid->file_path); + protocol_dict_free(lfrfid->dict); + + lfrfid_worker_free(lfrfid->lfworker); + + if(lfrfid->rpc_ctx) { + rpc_system_app_set_callback(lfrfid->rpc_ctx, NULL, NULL); + rpc_system_app_send_exited(lfrfid->rpc_ctx); + } + + free(lfrfid->new_key_data); + free(lfrfid->old_key_data); + + // Submenu + view_dispatcher_remove_view(lfrfid->view_dispatcher, LfRfidViewSubmenu); + submenu_free(lfrfid->submenu); + + // DialogEx + view_dispatcher_remove_view(lfrfid->view_dispatcher, LfRfidViewDialogEx); + dialog_ex_free(lfrfid->dialog_ex); + + // Popup + view_dispatcher_remove_view(lfrfid->view_dispatcher, LfRfidViewPopup); + popup_free(lfrfid->popup); + + // Widget + view_dispatcher_remove_view(lfrfid->view_dispatcher, LfRfidViewWidget); + widget_free(lfrfid->widget); + + // TextInput + view_dispatcher_remove_view(lfrfid->view_dispatcher, LfRfidViewTextInput); + text_input_free(lfrfid->text_input); + + // ByteInput + view_dispatcher_remove_view(lfrfid->view_dispatcher, LfRfidViewByteInput); + byte_input_free(lfrfid->byte_input); + + // Read custom view + view_dispatcher_remove_view(lfrfid->view_dispatcher, LfRfidViewRead); + lfrfid_view_read_free(lfrfid->read_view); + + // View Dispatcher + view_dispatcher_free(lfrfid->view_dispatcher); + + // Scene Manager + scene_manager_free(lfrfid->scene_manager); + + // GUI + furi_record_close(RECORD_GUI); + lfrfid->gui = NULL; + + // Notifications + furi_record_close(RECORD_NOTIFICATION); + lfrfid->notifications = NULL; + + furi_record_close(RECORD_STORAGE); + furi_record_close(RECORD_DIALOGS); + + free(lfrfid); +} + +int32_t lfrfid_app(void* p) { + LfRfid* app = lfrfid_alloc(); + char* args = p; + + lfrfid_make_app_folder(app); + + if(args && strlen(args)) { + uint32_t rpc_ctx_ptr = 0; + if(sscanf(args, "RPC %lX", &rpc_ctx_ptr) == 1) { + app->rpc_ctx = (RpcAppSystem*)rpc_ctx_ptr; + rpc_system_app_set_callback(app->rpc_ctx, rpc_command_callback, app); + rpc_system_app_send_started(app->rpc_ctx); + view_dispatcher_attach_to_gui( + app->view_dispatcher, app->gui, ViewDispatcherTypeDesktop); + scene_manager_next_scene(app->scene_manager, LfRfidSceneRpc); + } else { + string_set_str(app->file_path, args); + lfrfid_load_key_data(app, app->file_path, true); + view_dispatcher_attach_to_gui( + app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); + scene_manager_next_scene(app->scene_manager, LfRfidSceneEmulate); + } + + } else { + view_dispatcher_attach_to_gui( + app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); + scene_manager_next_scene(app->scene_manager, LfRfidSceneStart); + } + + view_dispatcher_run(app->view_dispatcher); + + lfrfid_free(app); + + return 0; +} + +bool lfrfid_save_key(LfRfid* app) { + furi_assert(app); + + bool result = false; + + lfrfid_make_app_folder(app); + + if(string_end_with_str_p(app->file_path, LFRFID_APP_EXTENSION)) { + size_t filename_start = string_search_rchar(app->file_path, '/'); + string_left(app->file_path, filename_start); + } + + string_cat_printf( + app->file_path, "/%s%s", string_get_cstr(app->file_name), LFRFID_APP_EXTENSION); + + result = lfrfid_save_key_data(app, app->file_path); + return result; +} + +bool lfrfid_load_key_from_file_select(LfRfid* app) { + furi_assert(app); + + DialogsFileBrowserOptions browser_options; + dialog_file_browser_set_basic_options(&browser_options, LFRFID_APP_EXTENSION, &I_125_10px); + + // Input events and views are managed by file_browser + bool result = + dialog_file_browser_show(app->dialogs, app->file_path, app->file_path, &browser_options); + + if(result) { + result = lfrfid_load_key_data(app, app->file_path, true); + } + + return result; +} + +bool lfrfid_delete_key(LfRfid* app) { + furi_assert(app); + + return storage_simply_remove(app->storage, string_get_cstr(app->file_path)); +} + +bool lfrfid_load_key_data(LfRfid* app, string_t path, bool show_dialog) { + bool result = false; + + do { + app->protocol_id = lfrfid_dict_file_load(app->dict, string_get_cstr(path)); + if(app->protocol_id == PROTOCOL_NO) break; + + path_extract_filename(path, app->file_name, true); + result = true; + } while(0); + + if((!result) && (show_dialog)) { + dialog_message_show_storage_error(app->dialogs, "Cannot load\nkey file"); + } + + return result; +} + +bool lfrfid_save_key_data(LfRfid* app, string_t path) { + bool result = lfrfid_dict_file_save(app->dict, app->protocol_id, string_get_cstr(path)); + + if(!result) { + dialog_message_show_storage_error(app->dialogs, "Cannot save\nkey file"); + } + + return result; +} + +void lfrfid_make_app_folder(LfRfid* app) { + furi_assert(app); + + if(!storage_simply_mkdir(app->storage, LFRFID_APP_FOLDER)) { + dialog_message_show_storage_error(app->dialogs, "Cannot create\napp folder"); + } +} + +void lfrfid_text_store_set(LfRfid* app, const char* text, ...) { + furi_assert(app); + va_list args; + va_start(args, text); + + vsnprintf(app->text_store, LFRFID_TEXT_STORE_SIZE, text, args); + + va_end(args); +} + +void lfrfid_text_store_clear(LfRfid* app) { + furi_assert(app); + memset(app->text_store, 0, sizeof(app->text_store)); +} + +void lfrfid_popup_timeout_callback(void* context) { + LfRfid* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, LfRfidEventPopupClosed); +} + +void lfrfid_widget_callback(GuiButtonType result, InputType type, void* context) { + LfRfid* app = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(app->view_dispatcher, result); + } +} + +void lfrfid_text_input_callback(void* context) { + LfRfid* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, LfRfidEventNext); +} \ No newline at end of file diff --git a/applications/lfrfid/lfrfid_cli.c b/applications/main/lfrfid/lfrfid_cli.c similarity index 99% rename from applications/lfrfid/lfrfid_cli.c rename to applications/main/lfrfid/lfrfid_cli.c index 9a6930a67..281a0e963 100644 --- a/applications/lfrfid/lfrfid_cli.c +++ b/applications/main/lfrfid/lfrfid_cli.c @@ -114,7 +114,7 @@ static void lfrfid_cli_read(Cli* cli, string_t args) { string_t info; string_init(info); protocol_dict_render_data(dict, info, context.protocol); - if(string_size(info) > 0) { + if(!string_empty_p(info)) { printf("%s\r\n", string_get_cstr(info)); } string_clear(info); diff --git a/applications/main/lfrfid/lfrfid_i.h b/applications/main/lfrfid/lfrfid_i.h new file mode 100644 index 000000000..77e872527 --- /dev/null +++ b/applications/main/lfrfid/lfrfid_i.h @@ -0,0 +1,145 @@ +#pragma once + +#include "m-string.h" + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include + +#define LFRFID_KEY_NAME_SIZE 22 +#define LFRFID_TEXT_STORE_SIZE 40 + +#define LFRFID_APP_FOLDER ANY_PATH("lfrfid") +#define LFRFID_SD_FOLDER EXT_PATH("lfrfid") +#define LFRFID_APP_EXTENSION ".rfid" +#define LFRFID_APP_SHADOW_EXTENSION ".shd" + +#define LFRFID_APP_RAW_ASK_EXTENSION ".ask.raw" +#define LFRFID_APP_RAW_PSK_EXTENSION ".psk.raw" + +enum LfRfidCustomEvent { + LfRfidEventNext = 100, + LfRfidEventExit, + LfRfidEventPopupClosed, + LfRfidEventReadSenseStart, + LfRfidEventReadSenseEnd, + LfRfidEventReadSenseCardStart, + LfRfidEventReadSenseCardEnd, + LfRfidEventReadStartASK, + LfRfidEventReadStartPSK, + LfRfidEventReadDone, + LfRfidEventReadOverrun, + LfRfidEventReadError, + LfRfidEventWriteOK, + LfRfidEventWriteProtocolCannotBeWritten, + LfRfidEventWriteFobCannotBeWritten, + LfRfidEventWriteTooLongToWrite, + LfRfidEventRpcLoadFile, + LfRfidEventRpcSessionClose, +}; + +typedef enum { + LfRfidRpcStateIdle, + LfRfidRpcStateEmulating, +} LfRfidRpcState; + +typedef struct LfRfid LfRfid; + +struct LfRfid { + LFRFIDWorker* lfworker; + ViewDispatcher* view_dispatcher; + Gui* gui; + NotificationApp* notifications; + SceneManager* scene_manager; + Storage* storage; + DialogsApp* dialogs; + Widget* widget; + + char text_store[LFRFID_TEXT_STORE_SIZE + 1]; + string_t file_path; + string_t file_name; + string_t raw_file_name; + + ProtocolDict* dict; + ProtocolId protocol_id; + ProtocolId protocol_id_next; + LFRFIDWorkerReadType read_type; + + uint8_t* old_key_data; + uint8_t* new_key_data; + + RpcAppSystem* rpc_ctx; + LfRfidRpcState rpc_state; + + // Common Views + Submenu* submenu; + DialogEx* dialog_ex; + Popup* popup; + TextInput* text_input; + ByteInput* byte_input; + + // Custom views + LfRfidReadView* read_view; +}; + +typedef enum { + LfRfidViewSubmenu, + LfRfidViewDialogEx, + LfRfidViewPopup, + LfRfidViewWidget, + LfRfidViewTextInput, + LfRfidViewByteInput, + LfRfidViewRead, +} LfRfidView; + +bool lfrfid_save_key(LfRfid* app); + +bool lfrfid_load_key_from_file_select(LfRfid* app); + +bool lfrfid_delete_key(LfRfid* app); + +bool lfrfid_load_key_data(LfRfid* app, string_t path, bool show_dialog); + +bool lfrfid_save_key_data(LfRfid* app, string_t path); + +void lfrfid_make_app_folder(LfRfid* app); + +void lfrfid_text_store_set(LfRfid* app, const char* text, ...); + +void lfrfid_text_store_clear(LfRfid* app); + +void lfrfid_popup_timeout_callback(void* context); + +void lfrfid_widget_callback(GuiButtonType result, InputType type, void* context); + +void lfrfid_text_input_callback(void* context); diff --git a/applications/main/lfrfid/scenes/lfrfid_scene.c b/applications/main/lfrfid/scenes/lfrfid_scene.c new file mode 100644 index 000000000..0de5ec36b --- /dev/null +++ b/applications/main/lfrfid/scenes/lfrfid_scene.c @@ -0,0 +1,30 @@ +#include "lfrfid_scene.h" + +// Generate scene on_enter handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter, +void (*const lfrfid_on_enter_handlers[])(void*) = { +#include "lfrfid_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_event handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event, +bool (*const lfrfid_on_event_handlers[])(void* context, SceneManagerEvent event) = { +#include "lfrfid_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_exit handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit, +void (*const lfrfid_on_exit_handlers[])(void* context) = { +#include "lfrfid_scene_config.h" +}; +#undef ADD_SCENE + +// Initialize scene handlers configuration structure +const SceneManagerHandlers lfrfid_scene_handlers = { + .on_enter_handlers = lfrfid_on_enter_handlers, + .on_event_handlers = lfrfid_on_event_handlers, + .on_exit_handlers = lfrfid_on_exit_handlers, + .scene_num = LfRfidSceneNum, +}; diff --git a/applications/main/lfrfid/scenes/lfrfid_scene.h b/applications/main/lfrfid/scenes/lfrfid_scene.h new file mode 100644 index 000000000..8ce7da09c --- /dev/null +++ b/applications/main/lfrfid/scenes/lfrfid_scene.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +// Generate scene id and total number +#define ADD_SCENE(prefix, name, id) LfRfidScene##id, +typedef enum { +#include "lfrfid_scene_config.h" + LfRfidSceneNum, +} LfRfidScene; +#undef ADD_SCENE + +extern const SceneManagerHandlers lfrfid_scene_handlers; + +// Generate scene on_enter handlers declaration +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*); +#include "lfrfid_scene_config.h" +#undef ADD_SCENE + +// Generate scene on_event handlers declaration +#define ADD_SCENE(prefix, name, id) \ + bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event); +#include "lfrfid_scene_config.h" +#undef ADD_SCENE + +// Generate scene on_exit handlers declaration +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context); +#include "lfrfid_scene_config.h" +#undef ADD_SCENE diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_config.h b/applications/main/lfrfid/scenes/lfrfid_scene_config.h new file mode 100644 index 000000000..b77ade82f --- /dev/null +++ b/applications/main/lfrfid/scenes/lfrfid_scene_config.h @@ -0,0 +1,24 @@ +ADD_SCENE(lfrfid, start, Start) +ADD_SCENE(lfrfid, read, Read) +ADD_SCENE(lfrfid, read_success, ReadSuccess) +ADD_SCENE(lfrfid, retry_confirm, RetryConfirm) +ADD_SCENE(lfrfid, exit_confirm, ExitConfirm) +ADD_SCENE(lfrfid, delete_confirm, DeleteConfirm) +ADD_SCENE(lfrfid, read_key_menu, ReadKeyMenu) +ADD_SCENE(lfrfid, write, Write) +ADD_SCENE(lfrfid, write_success, WriteSuccess) +ADD_SCENE(lfrfid, emulate, Emulate) +ADD_SCENE(lfrfid, save_name, SaveName) +ADD_SCENE(lfrfid, save_success, SaveSuccess) +ADD_SCENE(lfrfid, select_key, SelectKey) +ADD_SCENE(lfrfid, saved_key_menu, SavedKeyMenu) +ADD_SCENE(lfrfid, save_data, SaveData) +ADD_SCENE(lfrfid, save_type, SaveType) +ADD_SCENE(lfrfid, saved_info, SavedInfo) +ADD_SCENE(lfrfid, delete_success, DeleteSuccess) +ADD_SCENE(lfrfid, extra_actions, ExtraActions) +ADD_SCENE(lfrfid, raw_info, RawInfo) +ADD_SCENE(lfrfid, raw_name, RawName) +ADD_SCENE(lfrfid, raw_read, RawRead) +ADD_SCENE(lfrfid, raw_success, RawSuccess) +ADD_SCENE(lfrfid, rpc, Rpc) diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_delete_confirm.c b/applications/main/lfrfid/scenes/lfrfid_scene_delete_confirm.c new file mode 100644 index 000000000..dc1c3df26 --- /dev/null +++ b/applications/main/lfrfid/scenes/lfrfid_scene_delete_confirm.c @@ -0,0 +1,68 @@ +#include "../lfrfid_i.h" + +void lfrfid_scene_delete_confirm_on_enter(void* context) { + LfRfid* app = context; + Widget* widget = app->widget; + + string_t tmp_string; + string_init(tmp_string); + + widget_add_button_element(widget, GuiButtonTypeLeft, "Back", lfrfid_widget_callback, app); + widget_add_button_element(widget, GuiButtonTypeRight, "Delete", lfrfid_widget_callback, app); + + string_printf(tmp_string, "Delete %s?", string_get_cstr(app->file_name)); + widget_add_string_element( + widget, 64, 0, AlignCenter, AlignTop, FontPrimary, string_get_cstr(tmp_string)); + + string_reset(tmp_string); + size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id); + uint8_t* data = (uint8_t*)malloc(size); + protocol_dict_get_data(app->dict, app->protocol_id, data, size); + for(uint8_t i = 0; i < MIN(size, (size_t)8); i++) { + if(i != 0) { + string_cat_printf(tmp_string, " "); + } + + string_cat_printf(tmp_string, "%02X", data[i]); + } + free(data); + + widget_add_string_element( + widget, 64, 19, AlignCenter, AlignTop, FontSecondary, string_get_cstr(tmp_string)); + widget_add_string_element( + widget, + 64, + 49, + AlignCenter, + AlignBottom, + FontSecondary, + protocol_dict_get_name(app->dict, app->protocol_id)); + + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewWidget); + string_clear(tmp_string); +} + +bool lfrfid_scene_delete_confirm_on_event(void* context, SceneManagerEvent event) { + LfRfid* app = context; + SceneManager* scene_manager = app->scene_manager; + bool consumed = false; + + if(event.type == SceneManagerEventTypeBack) { + consumed = true; // Ignore Back button presses + } else if(event.type == SceneManagerEventTypeCustom) { + consumed = true; + if(event.event == GuiButtonTypeLeft) { + scene_manager_previous_scene(scene_manager); + } else if(event.event == GuiButtonTypeRight) { + lfrfid_delete_key(app); + scene_manager_next_scene(scene_manager, LfRfidSceneDeleteSuccess); + } + } + + return consumed; +} + +void lfrfid_scene_delete_confirm_on_exit(void* context) { + LfRfid* app = context; + widget_reset(app->widget); +} diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_delete_success.c b/applications/main/lfrfid/scenes/lfrfid_scene_delete_success.c new file mode 100644 index 000000000..f940b9bd4 --- /dev/null +++ b/applications/main/lfrfid/scenes/lfrfid_scene_delete_success.c @@ -0,0 +1,35 @@ +#include "../lfrfid_i.h" + +void lfrfid_scene_delete_success_on_enter(void* context) { + LfRfid* app = context; + Popup* popup = app->popup; + + popup_set_icon(popup, 0, 2, &I_DolphinMafia_115x62); + popup_set_header(popup, "Deleted", 83, 19, AlignLeft, AlignBottom); + popup_set_context(popup, app); + popup_set_callback(popup, lfrfid_popup_timeout_callback); + popup_set_timeout(popup, 1500); + popup_enable_timeout(popup); + + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewPopup); +} + +bool lfrfid_scene_delete_success_on_event(void* context, SceneManagerEvent event) { + LfRfid* app = context; + bool consumed = false; + + if((event.type == SceneManagerEventTypeBack) || + ((event.type == SceneManagerEventTypeCustom) && (event.event == LfRfidEventPopupClosed))) { + scene_manager_search_and_switch_to_previous_scene( + app->scene_manager, LfRfidSceneSelectKey); + consumed = true; + } + + return consumed; +} + +void lfrfid_scene_delete_success_on_exit(void* context) { + LfRfid* app = context; + + popup_reset(app->popup); +} diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_emulate.c b/applications/main/lfrfid/scenes/lfrfid_scene_emulate.c new file mode 100644 index 000000000..70cc2418c --- /dev/null +++ b/applications/main/lfrfid/scenes/lfrfid_scene_emulate.c @@ -0,0 +1,44 @@ +#include "../lfrfid_i.h" +#include + +void lfrfid_scene_emulate_on_enter(void* context) { + LfRfid* app = context; + Popup* popup = app->popup; + + DOLPHIN_DEED(DolphinDeedRfidEmulate); + + popup_set_header(popup, "Emulating", 89, 30, AlignCenter, AlignTop); + if(!string_empty_p(app->file_name)) { + popup_set_text(popup, string_get_cstr(app->file_name), 89, 43, AlignCenter, AlignTop); + } else { + popup_set_text( + popup, + protocol_dict_get_name(app->dict, app->protocol_id), + 89, + 43, + AlignCenter, + AlignTop); + } + popup_set_icon(popup, 0, 3, &I_RFIDDolphinSend_97x61); + + lfrfid_worker_start_thread(app->lfworker); + lfrfid_worker_emulate_start(app->lfworker, (LFRFIDProtocol)app->protocol_id); + notification_message(app->notifications, &sequence_blink_start_magenta); + + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewPopup); +} + +bool lfrfid_scene_emulate_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + UNUSED(event); + bool consumed = false; + return consumed; +} + +void lfrfid_scene_emulate_on_exit(void* context) { + LfRfid* app = context; + notification_message(app->notifications, &sequence_blink_stop); + popup_reset(app->popup); + lfrfid_worker_stop(app->lfworker); + lfrfid_worker_stop_thread(app->lfworker); +} diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_exit_confirm.c b/applications/main/lfrfid/scenes/lfrfid_scene_exit_confirm.c new file mode 100644 index 000000000..e8ab481c6 --- /dev/null +++ b/applications/main/lfrfid/scenes/lfrfid_scene_exit_confirm.c @@ -0,0 +1,39 @@ +#include "../lfrfid_i.h" + +void lfrfid_scene_exit_confirm_on_enter(void* context) { + LfRfid* app = context; + Widget* widget = app->widget; + + widget_add_button_element(widget, GuiButtonTypeLeft, "Exit", lfrfid_widget_callback, app); + widget_add_button_element(widget, GuiButtonTypeRight, "Stay", lfrfid_widget_callback, app); + widget_add_string_element( + widget, 64, 19, AlignCenter, AlignBottom, FontPrimary, "Exit to RFID Menu?"); + widget_add_string_element( + widget, 64, 31, AlignCenter, AlignBottom, FontSecondary, "All unsaved data will be lost!"); + + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewWidget); +} + +bool lfrfid_scene_exit_confirm_on_event(void* context, SceneManagerEvent event) { + LfRfid* app = context; + SceneManager* scene_manager = app->scene_manager; + bool consumed = false; + + if(event.type == SceneManagerEventTypeBack) { + consumed = true; // Ignore Back button presses + } else if(event.type == SceneManagerEventTypeCustom) { + consumed = true; + if(event.event == GuiButtonTypeLeft) { + scene_manager_search_and_switch_to_previous_scene(scene_manager, LfRfidSceneStart); + } else if(event.event == GuiButtonTypeRight) { + scene_manager_previous_scene(scene_manager); + } + } + + return consumed; +} + +void lfrfid_scene_exit_confirm_on_exit(void* context) { + LfRfid* app = context; + widget_reset(app->widget); +} diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_extra_actions.c b/applications/main/lfrfid/scenes/lfrfid_scene_extra_actions.c new file mode 100644 index 000000000..43e3de99e --- /dev/null +++ b/applications/main/lfrfid/scenes/lfrfid_scene_extra_actions.c @@ -0,0 +1,79 @@ +#include "../lfrfid_i.h" + +typedef enum { + SubmenuIndexASK, + SubmenuIndexPSK, + SubmenuIndexRAW, +} SubmenuIndex; + +static void lfrfid_scene_extra_actions_submenu_callback(void* context, uint32_t index) { + LfRfid* app = context; + + view_dispatcher_send_custom_event(app->view_dispatcher, index); +} + +void lfrfid_scene_extra_actions_on_enter(void* context) { + LfRfid* app = context; + Submenu* submenu = app->submenu; + + submenu_add_item( + submenu, + "Read ASK (Animal, Ordinary Card)", + SubmenuIndexASK, + lfrfid_scene_extra_actions_submenu_callback, + app); + submenu_add_item( + submenu, + "Read PSK (Indala)", + SubmenuIndexPSK, + lfrfid_scene_extra_actions_submenu_callback, + app); + + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + submenu_add_item( + submenu, + "Read RAW RFID data", + SubmenuIndexRAW, + lfrfid_scene_extra_actions_submenu_callback, + app); + } + + submenu_set_selected_item( + submenu, scene_manager_get_scene_state(app->scene_manager, LfRfidSceneExtraActions)); + + // clear key + string_reset(app->file_name); + app->protocol_id = PROTOCOL_NO; + app->read_type = LFRFIDWorkerReadTypeAuto; + + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewSubmenu); +} + +bool lfrfid_scene_extra_actions_on_event(void* context, SceneManagerEvent event) { + LfRfid* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexASK) { + app->read_type = LFRFIDWorkerReadTypeASKOnly; + scene_manager_next_scene(app->scene_manager, LfRfidSceneRead); + consumed = true; + } else if(event.event == SubmenuIndexPSK) { + app->read_type = LFRFIDWorkerReadTypePSKOnly; + scene_manager_next_scene(app->scene_manager, LfRfidSceneRead); + consumed = true; + } else if(event.event == SubmenuIndexRAW) { + scene_manager_next_scene(app->scene_manager, LfRfidSceneRawName); + consumed = true; + } + scene_manager_set_scene_state(app->scene_manager, LfRfidSceneExtraActions, event.event); + } + + return consumed; +} + +void lfrfid_scene_extra_actions_on_exit(void* context) { + LfRfid* app = context; + + submenu_reset(app->submenu); +} diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_raw_info.c b/applications/main/lfrfid/scenes/lfrfid_scene_raw_info.c new file mode 100644 index 000000000..f60dd6243 --- /dev/null +++ b/applications/main/lfrfid/scenes/lfrfid_scene_raw_info.c @@ -0,0 +1,64 @@ +#include "../lfrfid_i.h" + +void lfrfid_scene_raw_info_on_enter(void* context) { + LfRfid* app = context; + Widget* widget = app->widget; + + // string_t tmp_string; + // string_init(tmp_string); + + bool sd_exist = storage_sd_status(app->storage) == FSE_OK; + if(!sd_exist) { + widget_add_icon_element(widget, 0, 0, &I_SDQuestion_35x43); + widget_add_string_multiline_element( + widget, + 81, + 4, + AlignCenter, + AlignTop, + FontSecondary, + "No SD card found.\nThis function will not\nwork without\nSD card."); + + widget_add_button_element(widget, GuiButtonTypeLeft, "Back", lfrfid_widget_callback, app); + } else { + widget_add_string_multiline_element( + widget, + 0, + 1, + AlignLeft, + AlignTop, + FontSecondary, + "RAW RFID data reader\n1) Put the Flipper on your card\n2) Press OK\n3) Wait until data is read"); + + widget_add_button_element(widget, GuiButtonTypeCenter, "OK", lfrfid_widget_callback, app); + } + + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewWidget); + //string_clear(tmp_string); +} + +bool lfrfid_scene_raw_info_on_event(void* context, SceneManagerEvent event) { + LfRfid* app = context; + SceneManager* scene_manager = app->scene_manager; + bool consumed = false; + + if(event.type == SceneManagerEventTypeBack) { + consumed = true; + scene_manager_search_and_switch_to_previous_scene(scene_manager, LfRfidSceneExtraActions); + } else if(event.type == SceneManagerEventTypeCustom) { + consumed = true; + if(event.event == GuiButtonTypeCenter) { + scene_manager_next_scene(scene_manager, LfRfidSceneRawRead); + } else if(event.event == GuiButtonTypeLeft) { + scene_manager_search_and_switch_to_previous_scene( + scene_manager, LfRfidSceneExtraActions); + } + } + + return consumed; +} + +void lfrfid_scene_raw_info_on_exit(void* context) { + LfRfid* app = context; + widget_reset(app->widget); +} diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_raw_name.c b/applications/main/lfrfid/scenes/lfrfid_scene_raw_name.c new file mode 100644 index 000000000..512f9ee4c --- /dev/null +++ b/applications/main/lfrfid/scenes/lfrfid_scene_raw_name.c @@ -0,0 +1,58 @@ +#include "../lfrfid_i.h" + +void lfrfid_scene_raw_name_on_enter(void* context) { + LfRfid* app = context; + TextInput* text_input = app->text_input; + + const char* key_name = string_get_cstr(app->raw_file_name); + + bool key_name_is_empty = string_empty_p(app->file_name); + if(key_name_is_empty) { + lfrfid_text_store_set(app, "RfidRecord"); + } else { + lfrfid_text_store_set(app, "%s", key_name); + } + + text_input_set_header_text(text_input, "Name the raw file"); + + text_input_set_result_callback( + text_input, + lfrfid_text_input_callback, + app, + app->text_store, + LFRFID_KEY_NAME_SIZE, + key_name_is_empty); + + ValidatorIsFile* validator_is_file = + validator_is_file_alloc_init(LFRFID_SD_FOLDER, LFRFID_APP_RAW_ASK_EXTENSION, NULL); + text_input_set_validator(text_input, validator_is_file_callback, validator_is_file); + + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewTextInput); +} + +bool lfrfid_scene_raw_name_on_event(void* context, SceneManagerEvent event) { + LfRfid* app = context; + SceneManager* scene_manager = app->scene_manager; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == LfRfidEventNext) { + consumed = true; + string_set_str(app->raw_file_name, app->text_store); + scene_manager_next_scene(scene_manager, LfRfidSceneRawInfo); + } + } + + return consumed; +} + +void lfrfid_scene_raw_name_on_exit(void* context) { + LfRfid* app = context; + TextInput* text_input = app->text_input; + + void* validator_context = text_input_get_validator_callback_context(text_input); + text_input_set_validator(text_input, NULL, NULL); + validator_is_file_free((ValidatorIsFile*)validator_context); + + text_input_reset(text_input); +} diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_raw_read.c b/applications/main/lfrfid/scenes/lfrfid_scene_raw_read.c new file mode 100644 index 000000000..d0c03ffa9 --- /dev/null +++ b/applications/main/lfrfid/scenes/lfrfid_scene_raw_read.c @@ -0,0 +1,126 @@ +#include "../lfrfid_i.h" + +#define RAW_READ_TIME 5000 + +typedef struct { + string_t string_file_name; + FuriTimer* timer; + bool is_psk; + bool error; +} LfRfidReadRawState; + +static void lfrfid_read_callback(LFRFIDWorkerReadRawResult result, void* context) { + LfRfid* app = context; + + if(result == LFRFIDWorkerReadRawFileError) { + view_dispatcher_send_custom_event(app->view_dispatcher, LfRfidEventReadError); + } else if(result == LFRFIDWorkerReadRawOverrun) { + view_dispatcher_send_custom_event(app->view_dispatcher, LfRfidEventReadOverrun); + } +} + +static void timer_callback(void* context) { + LfRfid* app = context; + + view_dispatcher_send_custom_event(app->view_dispatcher, LfRfidEventReadDone); +} + +void lfrfid_scene_raw_read_on_enter(void* context) { + LfRfid* app = context; + Popup* popup = app->popup; + + LfRfidReadRawState* state = malloc(sizeof(LfRfidReadRawState)); + scene_manager_set_scene_state(app->scene_manager, LfRfidSceneRawRead, (uint32_t)state); + string_init(state->string_file_name); + + popup_set_icon(popup, 0, 3, &I_RFIDDolphinReceive_97x61); + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewPopup); + lfrfid_worker_start_thread(app->lfworker); + lfrfid_make_app_folder(app); + + state->timer = furi_timer_alloc(timer_callback, FuriTimerTypeOnce, app); + furi_timer_start(state->timer, RAW_READ_TIME); + string_printf( + state->string_file_name, + "%s/%s%s", + LFRFID_SD_FOLDER, + string_get_cstr(app->raw_file_name), + LFRFID_APP_RAW_ASK_EXTENSION); + popup_set_header(popup, "Reading\nRAW RFID\nASK", 89, 30, AlignCenter, AlignTop); + lfrfid_worker_read_raw_start( + app->lfworker, + string_get_cstr(state->string_file_name), + LFRFIDWorkerReadTypeASKOnly, + lfrfid_read_callback, + app); + + notification_message(app->notifications, &sequence_blink_start_cyan); + + state->is_psk = false; + state->error = false; +} + +bool lfrfid_scene_raw_read_on_event(void* context, SceneManagerEvent event) { + LfRfid* app = context; + Popup* popup = app->popup; + LfRfidReadRawState* state = + (LfRfidReadRawState*)scene_manager_get_scene_state(app->scene_manager, LfRfidSceneRawRead); + bool consumed = false; + + furi_assert(state); + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == LfRfidEventReadError) { + consumed = true; + state->error = true; + popup_set_header( + popup, "Reading\nRAW RFID\nFile error", 89, 30, AlignCenter, AlignTop); + notification_message(app->notifications, &sequence_blink_start_red); + furi_timer_stop(state->timer); + } else if(event.event == LfRfidEventReadDone) { + consumed = true; + if(!state->error) { + if(state->is_psk) { + notification_message(app->notifications, &sequence_success); + scene_manager_next_scene(app->scene_manager, LfRfidSceneRawSuccess); + } else { + popup_set_header( + popup, "Reading\nRAW RFID\nPSK", 89, 30, AlignCenter, AlignTop); + notification_message(app->notifications, &sequence_blink_start_yellow); + lfrfid_worker_stop(app->lfworker); + string_printf( + state->string_file_name, + "%s/%s%s", + LFRFID_SD_FOLDER, + string_get_cstr(app->raw_file_name), + LFRFID_APP_RAW_PSK_EXTENSION); + lfrfid_worker_read_raw_start( + app->lfworker, + string_get_cstr(state->string_file_name), + LFRFIDWorkerReadTypePSKOnly, + lfrfid_read_callback, + app); + furi_timer_start(state->timer, RAW_READ_TIME); + state->is_psk = true; + } + } + } + } + + return consumed; +} + +void lfrfid_scene_raw_read_on_exit(void* context) { + LfRfid* app = context; + LfRfidReadRawState* state = + (LfRfidReadRawState*)scene_manager_get_scene_state(app->scene_manager, LfRfidSceneRawRead); + + notification_message(app->notifications, &sequence_blink_stop); + popup_reset(app->popup); + lfrfid_worker_stop(app->lfworker); + lfrfid_worker_stop_thread(app->lfworker); + furi_timer_free(state->timer); + + string_clear(state->string_file_name); + free(state); +} diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_raw_success.c b/applications/main/lfrfid/scenes/lfrfid_scene_raw_success.c new file mode 100644 index 000000000..09a005298 --- /dev/null +++ b/applications/main/lfrfid/scenes/lfrfid_scene_raw_success.c @@ -0,0 +1,39 @@ +#include "../lfrfid_i.h" + +void lfrfid_scene_raw_success_on_enter(void* context) { + LfRfid* app = context; + Widget* widget = app->widget; + + widget_add_button_element(widget, GuiButtonTypeCenter, "OK", lfrfid_widget_callback, app); + + widget_add_string_multiline_element( + widget, + 0, + 1, + AlignLeft, + AlignTop, + FontSecondary, + "RAW RFID read success!\nNow you can analyze files\nOr send them to developers"); + + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewWidget); +} + +bool lfrfid_scene_raw_success_on_event(void* context, SceneManagerEvent event) { + LfRfid* app = context; + SceneManager* scene_manager = app->scene_manager; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + consumed = true; + if(event.event == GuiButtonTypeCenter) { + scene_manager_search_and_switch_to_previous_scene( + scene_manager, LfRfidSceneExtraActions); + } + } + return consumed; +} + +void lfrfid_scene_raw_success_on_exit(void* context) { + LfRfid* app = context; + widget_reset(app->widget); +} diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_read.c b/applications/main/lfrfid/scenes/lfrfid_scene_read.c new file mode 100644 index 000000000..661680381 --- /dev/null +++ b/applications/main/lfrfid/scenes/lfrfid_scene_read.c @@ -0,0 +1,109 @@ +#include "../lfrfid_i.h" +#include + +static const NotificationSequence sequence_blink_set_yellow = { + &message_blink_set_color_yellow, + NULL, +}; + +static const NotificationSequence sequence_blink_set_green = { + &message_blink_set_color_green, + NULL, +}; + +static const NotificationSequence sequence_blink_set_cyan = { + &message_blink_set_color_cyan, + NULL, +}; + +static void + lfrfid_read_callback(LFRFIDWorkerReadResult result, ProtocolId protocol, void* context) { + LfRfid* app = context; + uint32_t event = 0; + + if(result == LFRFIDWorkerReadSenseStart) { + event = LfRfidEventReadSenseStart; + } else if(result == LFRFIDWorkerReadSenseEnd) { + event = LfRfidEventReadSenseEnd; + } else if(result == LFRFIDWorkerReadSenseCardStart) { + event = LfRfidEventReadSenseCardStart; + } else if(result == LFRFIDWorkerReadSenseCardEnd) { + event = LfRfidEventReadSenseCardEnd; + } else if(result == LFRFIDWorkerReadDone) { + event = LfRfidEventReadDone; + app->protocol_id_next = protocol; + } else if(result == LFRFIDWorkerReadStartASK) { + event = LfRfidEventReadStartASK; + } else if(result == LFRFIDWorkerReadStartPSK) { + event = LfRfidEventReadStartPSK; + } else { + return; + } + + view_dispatcher_send_custom_event(app->view_dispatcher, event); +} + +void lfrfid_scene_read_on_enter(void* context) { + LfRfid* app = context; + + DOLPHIN_DEED(DolphinDeedRfidRead); + if(app->read_type == LFRFIDWorkerReadTypePSKOnly) { + lfrfid_view_read_set_read_mode(app->read_view, LfRfidReadPskOnly); + } else if(app->read_type == LFRFIDWorkerReadTypeASKOnly) { + lfrfid_view_read_set_read_mode(app->read_view, LfRfidReadAskOnly); + } + + lfrfid_worker_start_thread(app->lfworker); + lfrfid_worker_read_start(app->lfworker, app->read_type, lfrfid_read_callback, app); + + notification_message(app->notifications, &sequence_blink_start_cyan); + + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewRead); +} + +bool lfrfid_scene_read_on_event(void* context, SceneManagerEvent event) { + LfRfid* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == LfRfidEventReadSenseStart) { + notification_message(app->notifications, &sequence_blink_set_yellow); + consumed = true; + } else if(event.event == LfRfidEventReadSenseCardStart) { + notification_message(app->notifications, &sequence_blink_set_green); + consumed = true; + } else if( + (event.event == LfRfidEventReadSenseEnd) || + (event.event == LfRfidEventReadSenseCardEnd)) { + notification_message(app->notifications, &sequence_blink_set_cyan); + consumed = true; + } else if(event.event == LfRfidEventReadDone) { + app->protocol_id = app->protocol_id_next; + DOLPHIN_DEED(DolphinDeedRfidReadSuccess); + notification_message(app->notifications, &sequence_success); + string_reset(app->file_name); + scene_manager_next_scene(app->scene_manager, LfRfidSceneReadSuccess); + consumed = true; + } else if(event.event == LfRfidEventReadStartPSK) { + if(app->read_type == LFRFIDWorkerReadTypeAuto) { + lfrfid_view_read_set_read_mode(app->read_view, LfRfidReadPsk); + } + consumed = true; + } else if(event.event == LfRfidEventReadStartASK) { + if(app->read_type == LFRFIDWorkerReadTypeAuto) { + lfrfid_view_read_set_read_mode(app->read_view, LfRfidReadAsk); + } + consumed = true; + } + } + + return consumed; +} + +void lfrfid_scene_read_on_exit(void* context) { + LfRfid* app = context; + notification_message(app->notifications, &sequence_blink_stop); + popup_reset(app->popup); + lfrfid_worker_stop(app->lfworker); + lfrfid_worker_stop_thread(app->lfworker); +} diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_read_key_menu.c b/applications/main/lfrfid/scenes/lfrfid_scene_read_key_menu.c new file mode 100644 index 000000000..221cc0084 --- /dev/null +++ b/applications/main/lfrfid/scenes/lfrfid_scene_read_key_menu.c @@ -0,0 +1,58 @@ +#include "../lfrfid_i.h" + +typedef enum { + SubmenuIndexSave, + SubmenuIndexEmulate, + SubmenuIndexWrite, +} SubmenuIndex; + +void lfrfid_scene_read_key_menu_submenu_callback(void* context, uint32_t index) { + LfRfid* app = context; + + view_dispatcher_send_custom_event(app->view_dispatcher, index); +} + +void lfrfid_scene_read_key_menu_on_enter(void* context) { + LfRfid* app = context; + Submenu* submenu = app->submenu; + + submenu_add_item( + submenu, "Save", SubmenuIndexSave, lfrfid_scene_read_key_menu_submenu_callback, app); + submenu_add_item( + submenu, "Emulate", SubmenuIndexEmulate, lfrfid_scene_read_key_menu_submenu_callback, app); + submenu_add_item( + submenu, "Write", SubmenuIndexWrite, lfrfid_scene_read_key_menu_submenu_callback, app); + + submenu_set_selected_item( + submenu, scene_manager_get_scene_state(app->scene_manager, LfRfidSceneReadKeyMenu)); + + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewSubmenu); +} + +bool lfrfid_scene_read_key_menu_on_event(void* context, SceneManagerEvent event) { + LfRfid* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexWrite) { + scene_manager_next_scene(app->scene_manager, LfRfidSceneWrite); + consumed = true; + } else if(event.event == SubmenuIndexSave) { + string_reset(app->file_name); + scene_manager_next_scene(app->scene_manager, LfRfidSceneSaveName); + consumed = true; + } else if(event.event == SubmenuIndexEmulate) { + scene_manager_next_scene(app->scene_manager, LfRfidSceneEmulate); + consumed = true; + } + scene_manager_set_scene_state(app->scene_manager, LfRfidSceneReadKeyMenu, event.event); + } + + return consumed; +} + +void lfrfid_scene_read_key_menu_on_exit(void* context) { + LfRfid* app = context; + + submenu_reset(app->submenu); +} diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_read_success.c b/applications/main/lfrfid/scenes/lfrfid_scene_read_success.c new file mode 100644 index 000000000..5ae6f0f1a --- /dev/null +++ b/applications/main/lfrfid/scenes/lfrfid_scene_read_success.c @@ -0,0 +1,78 @@ +#include "../lfrfid_i.h" + +void lfrfid_scene_read_success_on_enter(void* context) { + LfRfid* app = context; + Widget* widget = app->widget; + + string_t tmp_string; + string_init(tmp_string); + + widget_add_button_element(widget, GuiButtonTypeLeft, "Retry", lfrfid_widget_callback, app); + widget_add_button_element(widget, GuiButtonTypeRight, "More", lfrfid_widget_callback, app); + + string_printf( + tmp_string, + "%s[%s]", + protocol_dict_get_name(app->dict, app->protocol_id), + protocol_dict_get_manufacturer(app->dict, app->protocol_id)); + + widget_add_string_element( + widget, 0, 2, AlignLeft, AlignTop, FontPrimary, string_get_cstr(tmp_string)); + + string_reset(tmp_string); + size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id); + uint8_t* data = (uint8_t*)malloc(size); + protocol_dict_get_data(app->dict, app->protocol_id, data, size); + for(uint8_t i = 0; i < size; i++) { + if(i >= 9) { + string_cat_printf(tmp_string, ".."); + break; + } else { + if(i != 0) { + string_cat_printf(tmp_string, " "); + } + string_cat_printf(tmp_string, "%02X", data[i]); + } + } + free(data); + + string_t render_data; + string_init(render_data); + protocol_dict_render_brief_data(app->dict, render_data, app->protocol_id); + string_cat_printf(tmp_string, "\r\n%s", string_get_cstr(render_data)); + string_clear(render_data); + + widget_add_string_multiline_element( + widget, 0, 16, AlignLeft, AlignTop, FontSecondary, string_get_cstr(tmp_string)); + + notification_message_block(app->notifications, &sequence_set_green_255); + + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewWidget); + string_clear(tmp_string); +} + +bool lfrfid_scene_read_success_on_event(void* context, SceneManagerEvent event) { + LfRfid* app = context; + SceneManager* scene_manager = app->scene_manager; + bool consumed = false; + + if(event.type == SceneManagerEventTypeBack) { + scene_manager_next_scene(scene_manager, LfRfidSceneExitConfirm); + consumed = true; + } else if(event.type == SceneManagerEventTypeCustom) { + consumed = true; + if(event.event == GuiButtonTypeLeft) { + scene_manager_next_scene(scene_manager, LfRfidSceneRetryConfirm); + } else if(event.event == GuiButtonTypeRight) { + scene_manager_next_scene(scene_manager, LfRfidSceneReadKeyMenu); + } + } + + return consumed; +} + +void lfrfid_scene_read_success_on_exit(void* context) { + LfRfid* app = context; + notification_message_block(app->notifications, &sequence_reset_green); + widget_reset(app->widget); +} diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_retry_confirm.c b/applications/main/lfrfid/scenes/lfrfid_scene_retry_confirm.c new file mode 100644 index 000000000..f639f0ae1 --- /dev/null +++ b/applications/main/lfrfid/scenes/lfrfid_scene_retry_confirm.c @@ -0,0 +1,39 @@ +#include "../lfrfid_i.h" + +void lfrfid_scene_retry_confirm_on_enter(void* context) { + LfRfid* app = context; + Widget* widget = app->widget; + + widget_add_button_element(widget, GuiButtonTypeLeft, "Exit", lfrfid_widget_callback, app); + widget_add_button_element(widget, GuiButtonTypeRight, "Stay", lfrfid_widget_callback, app); + widget_add_string_element( + widget, 64, 19, AlignCenter, AlignBottom, FontPrimary, "Return to reading?"); + widget_add_string_element( + widget, 64, 29, AlignCenter, AlignBottom, FontSecondary, "All unsaved data will be lost!"); + + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewWidget); +} + +bool lfrfid_scene_retry_confirm_on_event(void* context, SceneManagerEvent event) { + LfRfid* app = context; + SceneManager* scene_manager = app->scene_manager; + bool consumed = false; + + if(event.type == SceneManagerEventTypeBack) { + consumed = true; // Ignore Back button presses + } else if(event.type == SceneManagerEventTypeCustom) { + consumed = true; + if(event.event == GuiButtonTypeLeft) { + scene_manager_search_and_switch_to_previous_scene(scene_manager, LfRfidSceneRead); + } else if(event.event == GuiButtonTypeRight) { + scene_manager_previous_scene(scene_manager); + } + } + + return consumed; +} + +void lfrfid_scene_retry_confirm_on_exit(void* context) { + LfRfid* app = context; + widget_reset(app->widget); +} diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_rpc.c b/applications/main/lfrfid/scenes/lfrfid_scene_rpc.c new file mode 100644 index 000000000..a69d6453a --- /dev/null +++ b/applications/main/lfrfid/scenes/lfrfid_scene_rpc.c @@ -0,0 +1,67 @@ +#include "../lfrfid_i.h" + +void lfrfid_scene_rpc_on_enter(void* context) { + LfRfid* app = context; + Popup* popup = app->popup; + + popup_set_header(popup, "LF RFID", 89, 42, AlignCenter, AlignBottom); + popup_set_text(popup, "RPC mode", 89, 44, AlignCenter, AlignTop); + popup_set_icon(popup, 0, 12, &I_RFIDDolphinSend_97x61); + + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewPopup); + + notification_message(app->notifications, &sequence_display_backlight_on); + + app->rpc_state = LfRfidRpcStateIdle; +} + +bool lfrfid_scene_rpc_on_event(void* context, SceneManagerEvent event) { + LfRfid* app = context; + Popup* popup = app->popup; + UNUSED(event); + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + consumed = true; + if(event.event == LfRfidEventExit) { + rpc_system_app_confirm(app->rpc_ctx, RpcAppEventAppExit, true); + scene_manager_stop(app->scene_manager); + view_dispatcher_stop(app->view_dispatcher); + } else if(event.event == LfRfidEventRpcSessionClose) { + scene_manager_stop(app->scene_manager); + view_dispatcher_stop(app->view_dispatcher); + } else if(event.event == LfRfidEventRpcLoadFile) { + const char* arg = rpc_system_app_get_data(app->rpc_ctx); + bool result = false; + if(arg && (app->rpc_state == LfRfidRpcStateIdle)) { + string_set_str(app->file_path, arg); + if(lfrfid_load_key_data(app, app->file_path, false)) { + lfrfid_worker_start_thread(app->lfworker); + lfrfid_worker_emulate_start(app->lfworker, (LFRFIDProtocol)app->protocol_id); + app->rpc_state = LfRfidRpcStateEmulating; + + lfrfid_text_store_set(app, "emulating\n%s", string_get_cstr(app->file_name)); + popup_set_text(popup, app->text_store, 89, 44, AlignCenter, AlignTop); + + notification_message(app->notifications, &sequence_blink_start_magenta); + result = true; + } + } + rpc_system_app_confirm(app->rpc_ctx, RpcAppEventLoadFile, result); + } + } + return consumed; +} + +void lfrfid_scene_rpc_on_exit(void* context) { + LfRfid* app = context; + Popup* popup = app->popup; + + if(app->rpc_state == LfRfidRpcStateEmulating) { + lfrfid_worker_stop(app->lfworker); + lfrfid_worker_stop_thread(app->lfworker); + notification_message(app->notifications, &sequence_blink_stop); + } + + popup_reset(popup); +} diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_save_data.c b/applications/main/lfrfid/scenes/lfrfid_scene_save_data.c new file mode 100644 index 000000000..2ca1bb433 --- /dev/null +++ b/applications/main/lfrfid/scenes/lfrfid_scene_save_data.c @@ -0,0 +1,51 @@ +#include "../lfrfid_i.h" +#include + +void lfrfid_scene_save_data_on_enter(void* context) { + LfRfid* app = context; + ByteInput* byte_input = app->byte_input; + + size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id); + + bool need_restore = scene_manager_get_scene_state(app->scene_manager, LfRfidSceneSaveData); + + if(need_restore) { + protocol_dict_set_data(app->dict, app->protocol_id, app->old_key_data, size); + } else { + protocol_dict_get_data(app->dict, app->protocol_id, app->old_key_data, size); + } + + protocol_dict_get_data(app->dict, app->protocol_id, app->new_key_data, size); + + byte_input_set_header_text(byte_input, "Enter the data in hex"); + + byte_input_set_result_callback( + byte_input, lfrfid_text_input_callback, NULL, app, app->new_key_data, size); + + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewByteInput); +} + +bool lfrfid_scene_save_data_on_event(void* context, SceneManagerEvent event) { + LfRfid* app = context; + SceneManager* scene_manager = app->scene_manager; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == LfRfidEventNext) { + consumed = true; + size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id); + protocol_dict_set_data(app->dict, app->protocol_id, app->new_key_data, size); + DOLPHIN_DEED(DolphinDeedRfidAdd); + scene_manager_next_scene(scene_manager, LfRfidSceneSaveName); + scene_manager_set_scene_state(scene_manager, LfRfidSceneSaveData, 1); + } + } else if(event.type == SceneManagerEventTypeBack) { + scene_manager_set_scene_state(scene_manager, LfRfidSceneSaveData, 0); + } + + return consumed; +} + +void lfrfid_scene_save_data_on_exit(void* context) { + UNUSED(context); +} diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_save_name.c b/applications/main/lfrfid/scenes/lfrfid_scene_save_name.c new file mode 100644 index 000000000..febf30a41 --- /dev/null +++ b/applications/main/lfrfid/scenes/lfrfid_scene_save_name.c @@ -0,0 +1,76 @@ +#include "m-string.h" +#include +#include "../lfrfid_i.h" + +void lfrfid_scene_save_name_on_enter(void* context) { + LfRfid* app = context; + TextInput* text_input = app->text_input; + string_t folder_path; + string_init(folder_path); + + bool key_name_is_empty = string_empty_p(app->file_name); + if(key_name_is_empty) { + string_set_str(app->file_path, LFRFID_APP_FOLDER); + set_random_name(app->text_store, LFRFID_TEXT_STORE_SIZE); + string_set_str(folder_path, LFRFID_APP_FOLDER); + } else { + lfrfid_text_store_set(app, "%s", string_get_cstr(app->file_name)); + path_extract_dirname(string_get_cstr(app->file_path), folder_path); + } + + text_input_set_header_text(text_input, "Name the card"); + text_input_set_result_callback( + text_input, + lfrfid_text_input_callback, + app, + app->text_store, + LFRFID_KEY_NAME_SIZE, + key_name_is_empty); + + FURI_LOG_I("", "%s %s", string_get_cstr(folder_path), app->text_store); + + ValidatorIsFile* validator_is_file = validator_is_file_alloc_init( + string_get_cstr(folder_path), LFRFID_APP_EXTENSION, string_get_cstr(app->file_name)); + text_input_set_validator(text_input, validator_is_file_callback, validator_is_file); + + string_clear(folder_path); + + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewTextInput); +} + +bool lfrfid_scene_save_name_on_event(void* context, SceneManagerEvent event) { + LfRfid* app = context; + SceneManager* scene_manager = app->scene_manager; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == LfRfidEventNext) { + consumed = true; + if(!string_empty_p(app->file_name)) { + lfrfid_delete_key(app); + } + + string_set_str(app->file_name, app->text_store); + + if(lfrfid_save_key(app)) { + scene_manager_next_scene(scene_manager, LfRfidSceneSaveSuccess); + } else { + scene_manager_search_and_switch_to_previous_scene( + scene_manager, LfRfidSceneReadKeyMenu); + } + } + } + + return consumed; +} + +void lfrfid_scene_save_name_on_exit(void* context) { + LfRfid* app = context; + TextInput* text_input = app->text_input; + + void* validator_context = text_input_get_validator_callback_context(text_input); + text_input_set_validator(text_input, NULL, NULL); + validator_is_file_free((ValidatorIsFile*)validator_context); + + text_input_reset(text_input); +} diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_save_success.c b/applications/main/lfrfid/scenes/lfrfid_scene_save_success.c new file mode 100644 index 000000000..830ef3368 --- /dev/null +++ b/applications/main/lfrfid/scenes/lfrfid_scene_save_success.c @@ -0,0 +1,43 @@ +#include "../lfrfid_i.h" +#include + +void lfrfid_scene_save_success_on_enter(void* context) { + LfRfid* app = context; + Popup* popup = app->popup; + + DOLPHIN_DEED(DolphinDeedRfidSave); + popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); + popup_set_header(popup, "Saved!", 5, 7, AlignLeft, AlignTop); + popup_set_context(popup, app); + popup_set_callback(popup, lfrfid_popup_timeout_callback); + popup_set_timeout(popup, 1500); + popup_enable_timeout(popup); + + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewPopup); +} + +bool lfrfid_scene_save_success_on_event(void* context, SceneManagerEvent event) { + LfRfid* app = context; + bool consumed = false; + + const uint32_t prev_scenes[] = {LfRfidSceneReadKeyMenu, LfRfidSceneSelectKey}; + + if((event.type == SceneManagerEventTypeBack) || + ((event.type == SceneManagerEventTypeCustom) && (event.event == LfRfidEventPopupClosed))) { + bool result = scene_manager_search_and_switch_to_previous_scene_one_of( + app->scene_manager, prev_scenes, COUNT_OF(prev_scenes)); + if(!result) { + scene_manager_search_and_switch_to_another_scene( + app->scene_manager, LfRfidSceneSelectKey); + } + consumed = true; + } + + return consumed; +} + +void lfrfid_scene_save_success_on_exit(void* context) { + LfRfid* app = context; + + popup_reset(app->popup); +} diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_save_type.c b/applications/main/lfrfid/scenes/lfrfid_scene_save_type.c new file mode 100644 index 000000000..4c1116007 --- /dev/null +++ b/applications/main/lfrfid/scenes/lfrfid_scene_save_type.c @@ -0,0 +1,86 @@ +#include "../lfrfid_i.h" + +typedef struct { + string_t menu_item_name[LFRFIDProtocolMax]; + uint32_t line_sel; +} SaveTypeCtx; + +static void lfrfid_scene_save_type_submenu_callback(void* context, uint32_t index) { + LfRfid* app = context; + + view_dispatcher_send_custom_event(app->view_dispatcher, index); +} + +void lfrfid_scene_save_type_on_enter(void* context) { + LfRfid* app = context; + Submenu* submenu = app->submenu; + + SaveTypeCtx* state = malloc(sizeof(SaveTypeCtx)); + for(uint8_t i = 0; i < LFRFIDProtocolMax; i++) { + if(strcmp( + protocol_dict_get_manufacturer(app->dict, i), + protocol_dict_get_name(app->dict, i)) != 0) { + string_init_printf( + state->menu_item_name[i], + "%s %s", + protocol_dict_get_manufacturer(app->dict, i), + protocol_dict_get_name(app->dict, i)); + } else { + string_init_printf( + state->menu_item_name[i], "%s", protocol_dict_get_name(app->dict, i)); + } + submenu_add_item( + submenu, + string_get_cstr(state->menu_item_name[i]), + i, + lfrfid_scene_save_type_submenu_callback, + app); + } + + submenu_set_selected_item( + submenu, scene_manager_get_scene_state(app->scene_manager, LfRfidSceneSaveType)); + + scene_manager_set_scene_state(app->scene_manager, LfRfidSceneSaveType, (uint32_t)state); + + // clear key name + string_reset(app->file_name); + + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewSubmenu); +} + +bool lfrfid_scene_save_type_on_event(void* context, SceneManagerEvent event) { + LfRfid* app = context; + bool consumed = false; + + SaveTypeCtx* state = + (SaveTypeCtx*)scene_manager_get_scene_state(app->scene_manager, LfRfidSceneSaveType); + furi_check(state); + + if(event.type == SceneManagerEventTypeCustom) { + app->protocol_id = event.event; + state->line_sel = event.event; + scene_manager_next_scene(app->scene_manager, LfRfidSceneSaveData); + consumed = true; + } + + return consumed; +} + +void lfrfid_scene_save_type_on_exit(void* context) { + LfRfid* app = context; + SaveTypeCtx* state = + (SaveTypeCtx*)scene_manager_get_scene_state(app->scene_manager, LfRfidSceneSaveType); + furi_check(state); + + submenu_reset(app->submenu); + + for(uint8_t i = 0; i < LFRFIDProtocolMax; i++) { + string_clear(state->menu_item_name[i]); + } + + uint32_t line_sel = state->line_sel; + + free(state); + + scene_manager_set_scene_state(app->scene_manager, LfRfidSceneSaveType, line_sel); +} diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_saved_info.c b/applications/main/lfrfid/scenes/lfrfid_scene_saved_info.c new file mode 100644 index 000000000..1496c6b4b --- /dev/null +++ b/applications/main/lfrfid/scenes/lfrfid_scene_saved_info.c @@ -0,0 +1,51 @@ +#include "../lfrfid_i.h" + +void lfrfid_scene_saved_info_on_enter(void* context) { + LfRfid* app = context; + Widget* widget = app->widget; + + string_t tmp_string; + string_init(tmp_string); + + string_printf( + tmp_string, + "%s [%s]\r\n", + string_get_cstr(app->file_name), + protocol_dict_get_name(app->dict, app->protocol_id)); + + size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id); + uint8_t* data = (uint8_t*)malloc(size); + protocol_dict_get_data(app->dict, app->protocol_id, data, size); + for(uint8_t i = 0; i < size; i++) { + if(i != 0) { + string_cat_printf(tmp_string, " "); + } + + string_cat_printf(tmp_string, "%02X", data[i]); + } + free(data); + + string_t render_data; + string_init(render_data); + protocol_dict_render_data(app->dict, render_data, app->protocol_id); + string_cat_printf(tmp_string, "\r\n%s", string_get_cstr(render_data)); + string_clear(render_data); + + widget_add_string_multiline_element( + widget, 0, 1, AlignLeft, AlignTop, FontSecondary, string_get_cstr(tmp_string)); + + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewWidget); + string_clear(tmp_string); +} + +bool lfrfid_scene_saved_info_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + UNUSED(event); + bool consumed = false; + return consumed; +} + +void lfrfid_scene_saved_info_on_exit(void* context) { + LfRfid* app = context; + widget_reset(app->widget); +} diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_saved_key_menu.c b/applications/main/lfrfid/scenes/lfrfid_scene_saved_key_menu.c new file mode 100644 index 000000000..040b31f10 --- /dev/null +++ b/applications/main/lfrfid/scenes/lfrfid_scene_saved_key_menu.c @@ -0,0 +1,69 @@ +#include "../lfrfid_i.h" + +typedef enum { + SubmenuIndexEmulate, + SubmenuIndexWrite, + SubmenuIndexEdit, + SubmenuIndexDelete, + SubmenuIndexInfo, +} SubmenuIndex; + +static void lfrfid_scene_saved_key_menu_submenu_callback(void* context, uint32_t index) { + LfRfid* app = context; + + view_dispatcher_send_custom_event(app->view_dispatcher, index); +} + +void lfrfid_scene_saved_key_menu_on_enter(void* context) { + LfRfid* app = context; + Submenu* submenu = app->submenu; + + submenu_add_item( + submenu, "Emulate", SubmenuIndexEmulate, lfrfid_scene_saved_key_menu_submenu_callback, app); + submenu_add_item( + submenu, "Write", SubmenuIndexWrite, lfrfid_scene_saved_key_menu_submenu_callback, app); + submenu_add_item( + submenu, "Edit", SubmenuIndexEdit, lfrfid_scene_saved_key_menu_submenu_callback, app); + submenu_add_item( + submenu, "Delete", SubmenuIndexDelete, lfrfid_scene_saved_key_menu_submenu_callback, app); + submenu_add_item( + submenu, "Info", SubmenuIndexInfo, lfrfid_scene_saved_key_menu_submenu_callback, app); + + submenu_set_selected_item( + submenu, scene_manager_get_scene_state(app->scene_manager, LfRfidSceneSavedKeyMenu)); + + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewSubmenu); +} + +bool lfrfid_scene_saved_key_menu_on_event(void* context, SceneManagerEvent event) { + LfRfid* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexEmulate) { + scene_manager_next_scene(app->scene_manager, LfRfidSceneEmulate); + consumed = true; + } else if(event.event == SubmenuIndexWrite) { + scene_manager_next_scene(app->scene_manager, LfRfidSceneWrite); + consumed = true; + } else if(event.event == SubmenuIndexEdit) { + scene_manager_next_scene(app->scene_manager, LfRfidSceneSaveData); + consumed = true; + } else if(event.event == SubmenuIndexDelete) { + scene_manager_next_scene(app->scene_manager, LfRfidSceneDeleteConfirm); + consumed = true; + } else if(event.event == SubmenuIndexInfo) { + scene_manager_next_scene(app->scene_manager, LfRfidSceneSavedInfo); + consumed = true; + } + scene_manager_set_scene_state(app->scene_manager, LfRfidSceneSavedKeyMenu, event.event); + } + + return consumed; +} + +void lfrfid_scene_saved_key_menu_on_exit(void* context) { + LfRfid* app = context; + + submenu_reset(app->submenu); +} diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_select_key.c b/applications/main/lfrfid/scenes/lfrfid_scene_select_key.c new file mode 100644 index 000000000..2a9cc1c63 --- /dev/null +++ b/applications/main/lfrfid/scenes/lfrfid_scene_select_key.c @@ -0,0 +1,22 @@ +#include "../lfrfid_i.h" + +void lfrfid_scene_select_key_on_enter(void* context) { + LfRfid* app = context; + + if(lfrfid_load_key_from_file_select(app)) { + scene_manager_next_scene(app->scene_manager, LfRfidSceneSavedKeyMenu); + } else { + scene_manager_previous_scene(app->scene_manager); + } +} + +bool lfrfid_scene_select_key_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + UNUSED(event); + bool consumed = false; + return consumed; +} + +void lfrfid_scene_select_key_on_exit(void* context) { + UNUSED(context); +} diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_start.c b/applications/main/lfrfid/scenes/lfrfid_scene_start.c new file mode 100644 index 000000000..9074e859b --- /dev/null +++ b/applications/main/lfrfid/scenes/lfrfid_scene_start.c @@ -0,0 +1,72 @@ +#include "../lfrfid_i.h" + +typedef enum { + SubmenuIndexRead, + SubmenuIndexSaved, + SubmenuIndexAddManually, + SubmenuIndexExtraActions, +} SubmenuIndex; + +static void lfrfid_scene_start_submenu_callback(void* context, uint32_t index) { + LfRfid* app = context; + + view_dispatcher_send_custom_event(app->view_dispatcher, index); +} + +void lfrfid_scene_start_on_enter(void* context) { + LfRfid* app = context; + Submenu* submenu = app->submenu; + + submenu_add_item(submenu, "Read", SubmenuIndexRead, lfrfid_scene_start_submenu_callback, app); + submenu_add_item( + submenu, "Saved", SubmenuIndexSaved, lfrfid_scene_start_submenu_callback, app); + submenu_add_item( + submenu, "Add Manually", SubmenuIndexAddManually, lfrfid_scene_start_submenu_callback, app); + submenu_add_item( + submenu, + "Extra Actions", + SubmenuIndexExtraActions, + lfrfid_scene_start_submenu_callback, + app); + + submenu_set_selected_item( + submenu, scene_manager_get_scene_state(app->scene_manager, LfRfidSceneStart)); + + // clear key + string_reset(app->file_name); + app->protocol_id = PROTOCOL_NO; + app->read_type = LFRFIDWorkerReadTypeAuto; + + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewSubmenu); +} + +bool lfrfid_scene_start_on_event(void* context, SceneManagerEvent event) { + LfRfid* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexRead) { + scene_manager_next_scene(app->scene_manager, LfRfidSceneRead); + consumed = true; + } else if(event.event == SubmenuIndexSaved) { + string_set_str(app->file_path, LFRFID_APP_FOLDER); + scene_manager_next_scene(app->scene_manager, LfRfidSceneSelectKey); + consumed = true; + } else if(event.event == SubmenuIndexAddManually) { + scene_manager_next_scene(app->scene_manager, LfRfidSceneSaveType); + consumed = true; + } else if(event.event == SubmenuIndexExtraActions) { + scene_manager_next_scene(app->scene_manager, LfRfidSceneExtraActions); + consumed = true; + } + scene_manager_set_scene_state(app->scene_manager, LfRfidSceneStart, event.event); + } + + return consumed; +} + +void lfrfid_scene_start_on_exit(void* context) { + LfRfid* app = context; + + submenu_reset(app->submenu); +} diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_write.c b/applications/main/lfrfid/scenes/lfrfid_scene_write.c new file mode 100644 index 000000000..4b03bac15 --- /dev/null +++ b/applications/main/lfrfid/scenes/lfrfid_scene_write.c @@ -0,0 +1,96 @@ +#include "../lfrfid_i.h" + +static void lfrfid_write_callback(LFRFIDWorkerWriteResult result, void* context) { + LfRfid* app = context; + uint32_t event = 0; + + if(result == LFRFIDWorkerWriteOK) { + event = LfRfidEventWriteOK; + } else if(result == LFRFIDWorkerWriteProtocolCannotBeWritten) { + event = LfRfidEventWriteProtocolCannotBeWritten; + } else if(result == LFRFIDWorkerWriteFobCannotBeWritten) { + event = LfRfidEventWriteFobCannotBeWritten; + } else if(result == LFRFIDWorkerWriteTooLongToWrite) { + event = LfRfidEventWriteTooLongToWrite; + } + + view_dispatcher_send_custom_event(app->view_dispatcher, event); +} + +void lfrfid_scene_write_on_enter(void* context) { + LfRfid* app = context; + Popup* popup = app->popup; + + popup_set_header(popup, "Writing", 89, 30, AlignCenter, AlignTop); + if(!string_empty_p(app->file_name)) { + popup_set_text(popup, string_get_cstr(app->file_name), 89, 43, AlignCenter, AlignTop); + } else { + popup_set_text( + popup, + protocol_dict_get_name(app->dict, app->protocol_id), + 89, + 43, + AlignCenter, + AlignTop); + } + popup_set_icon(popup, 0, 3, &I_RFIDDolphinSend_97x61); + + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewPopup); + + size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id); + app->old_key_data = (uint8_t*)malloc(size); + protocol_dict_get_data(app->dict, app->protocol_id, app->old_key_data, size); + + lfrfid_worker_start_thread(app->lfworker); + lfrfid_worker_write_start( + app->lfworker, (LFRFIDProtocol)app->protocol_id, lfrfid_write_callback, app); + notification_message(app->notifications, &sequence_blink_start_magenta); +} + +bool lfrfid_scene_write_on_event(void* context, SceneManagerEvent event) { + LfRfid* app = context; + Popup* popup = app->popup; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == LfRfidEventWriteOK) { + notification_message(app->notifications, &sequence_success); + scene_manager_next_scene(app->scene_manager, LfRfidSceneWriteSuccess); + consumed = true; + } else if(event.event == LfRfidEventWriteProtocolCannotBeWritten) { + popup_set_icon(popup, 72, 17, &I_DolphinCommon_56x48); + popup_set_header(popup, "Error", 64, 3, AlignCenter, AlignTop); + popup_set_text(popup, "This protocol\ncannot be written", 3, 17, AlignLeft, AlignTop); + notification_message(app->notifications, &sequence_blink_start_red); + consumed = true; + } else if( + (event.event == LfRfidEventWriteFobCannotBeWritten) || + (event.event == LfRfidEventWriteTooLongToWrite)) { + popup_set_icon(popup, 72, 17, &I_DolphinCommon_56x48); + popup_set_header(popup, "Still trying to write...", 64, 3, AlignCenter, AlignTop); + popup_set_text( + popup, + "Make sure this\ncard is writable\nand not\nprotected.", + 3, + 17, + AlignLeft, + AlignTop); + notification_message(app->notifications, &sequence_blink_start_yellow); + consumed = true; + } + } + + return consumed; +} + +void lfrfid_scene_write_on_exit(void* context) { + LfRfid* app = context; + notification_message(app->notifications, &sequence_blink_stop); + popup_reset(app->popup); + lfrfid_worker_stop(app->lfworker); + lfrfid_worker_stop_thread(app->lfworker); + + size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id); + protocol_dict_set_data(app->dict, app->protocol_id, app->old_key_data, size); + free(app->old_key_data); +} diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_write_success.c b/applications/main/lfrfid/scenes/lfrfid_scene_write_success.c new file mode 100644 index 000000000..52e30d6b6 --- /dev/null +++ b/applications/main/lfrfid/scenes/lfrfid_scene_write_success.c @@ -0,0 +1,38 @@ +#include "../lfrfid_i.h" + +void lfrfid_scene_write_success_on_enter(void* context) { + LfRfid* app = context; + Popup* popup = app->popup; + + popup_set_header(popup, "Successfully\nwritten!", 94, 3, AlignCenter, AlignTop); + popup_set_icon(popup, 0, 6, &I_RFIDDolphinSuccess_108x57); + popup_set_context(popup, app); + popup_set_callback(popup, lfrfid_popup_timeout_callback); + popup_set_timeout(popup, 1500); + popup_enable_timeout(popup); + + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewPopup); + notification_message_block(app->notifications, &sequence_set_green_255); +} + +bool lfrfid_scene_write_success_on_event(void* context, SceneManagerEvent event) { + LfRfid* app = context; + bool consumed = false; + + const uint32_t prev_scenes[] = {LfRfidSceneReadKeyMenu, LfRfidSceneSelectKey}; + + if((event.type == SceneManagerEventTypeBack) || + ((event.type == SceneManagerEventTypeCustom) && (event.event == LfRfidEventPopupClosed))) { + scene_manager_search_and_switch_to_previous_scene_one_of( + app->scene_manager, prev_scenes, COUNT_OF(prev_scenes)); + consumed = true; + } + + return consumed; +} + +void lfrfid_scene_write_success_on_exit(void* context) { + LfRfid* app = context; + notification_message_block(app->notifications, &sequence_reset_green); + popup_reset(app->popup); +} diff --git a/applications/main/lfrfid/views/lfrfid_view_read.c b/applications/main/lfrfid/views/lfrfid_view_read.c new file mode 100644 index 000000000..66caf8df7 --- /dev/null +++ b/applications/main/lfrfid/views/lfrfid_view_read.c @@ -0,0 +1,117 @@ +#include "lfrfid_view_read.h" +#include + +#define TEMP_STR_LEN 128 + +struct LfRfidReadView { + View* view; +}; + +typedef struct { + IconAnimation* icon; + LfRfidReadViewMode read_mode; +} LfRfidReadViewModel; + +static void lfrfid_view_read_draw_callback(Canvas* canvas, void* _model) { + LfRfidReadViewModel* model = _model; + canvas_set_color(canvas, ColorBlack); + + canvas_draw_icon(canvas, 0, 8, &I_NFC_manual_60x50); + + canvas_set_font(canvas, FontPrimary); + + if(model->read_mode == LfRfidReadAsk) { + canvas_draw_str(canvas, 70, 16, "Reading 1/2"); + + canvas_draw_str(canvas, 77, 29, "ASK"); + canvas_draw_icon(canvas, 70, 22, &I_ButtonRight_4x7); + canvas_draw_icon_animation(canvas, 102, 21, model->icon); + + canvas_set_font(canvas, FontSecondary); + canvas_draw_str(canvas, 77, 43, "PSK"); + } else if(model->read_mode == LfRfidReadPsk) { + canvas_draw_str(canvas, 70, 16, "Reading 2/2"); + + canvas_draw_str(canvas, 77, 43, "PSK"); + canvas_draw_icon(canvas, 70, 36, &I_ButtonRight_4x7); + canvas_draw_icon_animation(canvas, 102, 35, model->icon); + + canvas_set_font(canvas, FontSecondary); + canvas_draw_str(canvas, 77, 29, "ASK"); + } else { + canvas_draw_str(canvas, 72, 16, "Reading"); + + if(model->read_mode == LfRfidReadAskOnly) { + canvas_draw_str(canvas, 77, 35, "ASK"); + } else { + canvas_draw_str(canvas, 77, 35, "PSK"); + } + canvas_draw_icon_animation(canvas, 102, 27, model->icon); + } + + canvas_set_font(canvas, FontSecondary); + canvas_draw_str(canvas, 61, 56, "Don't move card"); +} + +void lfrfid_view_read_enter(void* context) { + LfRfidReadView* read_view = context; + with_view_model( + read_view->view, (LfRfidReadViewModel * model) { + icon_animation_start(model->icon); + return true; + }); +} + +void lfrfid_view_read_exit(void* context) { + LfRfidReadView* read_view = context; + with_view_model( + read_view->view, (LfRfidReadViewModel * model) { + icon_animation_stop(model->icon); + return false; + }); +} + +LfRfidReadView* lfrfid_view_read_alloc() { + LfRfidReadView* read_view = malloc(sizeof(LfRfidReadView)); + read_view->view = view_alloc(); + view_set_context(read_view->view, read_view); + view_allocate_model(read_view->view, ViewModelTypeLocking, sizeof(LfRfidReadViewModel)); + + with_view_model( + read_view->view, (LfRfidReadViewModel * model) { + model->icon = icon_animation_alloc(&A_Round_loader_8x8); + view_tie_icon_animation(read_view->view, model->icon); + return false; + }); + + view_set_draw_callback(read_view->view, lfrfid_view_read_draw_callback); + view_set_enter_callback(read_view->view, lfrfid_view_read_enter); + view_set_exit_callback(read_view->view, lfrfid_view_read_exit); + + return read_view; +} + +void lfrfid_view_read_free(LfRfidReadView* read_view) { + with_view_model( + read_view->view, (LfRfidReadViewModel * model) { + icon_animation_free(model->icon); + return false; + }); + + view_free(read_view->view); + free(read_view); +} + +View* lfrfid_view_read_get_view(LfRfidReadView* read_view) { + return read_view->view; +} + +void lfrfid_view_read_set_read_mode(LfRfidReadView* read_view, LfRfidReadViewMode mode) { + with_view_model( + read_view->view, (LfRfidReadViewModel * model) { + icon_animation_stop(model->icon); + icon_animation_start(model->icon); + model->read_mode = mode; + return true; + }); +} diff --git a/applications/main/lfrfid/views/lfrfid_view_read.h b/applications/main/lfrfid/views/lfrfid_view_read.h new file mode 100644 index 000000000..55bb1f230 --- /dev/null +++ b/applications/main/lfrfid/views/lfrfid_view_read.h @@ -0,0 +1,19 @@ +#pragma once +#include + +typedef enum { + LfRfidReadAsk, + LfRfidReadPsk, + LfRfidReadAskOnly, + LfRfidReadPskOnly +} LfRfidReadViewMode; + +typedef struct LfRfidReadView LfRfidReadView; + +LfRfidReadView* lfrfid_view_read_alloc(); + +void lfrfid_view_read_free(LfRfidReadView* read_view); + +View* lfrfid_view_read_get_view(LfRfidReadView* read_view); + +void lfrfid_view_read_set_read_mode(LfRfidReadView* read_view, LfRfidReadViewMode mode); diff --git a/applications/nfc/application.fam b/applications/main/nfc/application.fam similarity index 100% rename from applications/nfc/application.fam rename to applications/main/nfc/application.fam diff --git a/applications/nfc/helpers/nfc_custom_event.h b/applications/main/nfc/helpers/nfc_custom_event.h similarity index 100% rename from applications/nfc/helpers/nfc_custom_event.h rename to applications/main/nfc/helpers/nfc_custom_event.h diff --git a/applications/nfc/helpers/nfc_emv_parser.c b/applications/main/nfc/helpers/nfc_emv_parser.c old mode 100755 new mode 100644 similarity index 100% rename from applications/nfc/helpers/nfc_emv_parser.c rename to applications/main/nfc/helpers/nfc_emv_parser.c diff --git a/applications/nfc/helpers/nfc_emv_parser.h b/applications/main/nfc/helpers/nfc_emv_parser.h old mode 100755 new mode 100644 similarity index 100% rename from applications/nfc/helpers/nfc_emv_parser.h rename to applications/main/nfc/helpers/nfc_emv_parser.h diff --git a/applications/nfc/helpers/nfc_generators.c b/applications/main/nfc/helpers/nfc_generators.c similarity index 99% rename from applications/nfc/helpers/nfc_generators.c rename to applications/main/nfc/helpers/nfc_generators.c index b94adbd7b..11083b9f0 100644 --- a/applications/nfc/helpers/nfc_generators.c +++ b/applications/main/nfc/helpers/nfc_generators.c @@ -254,7 +254,7 @@ static void session_register_page = 234; break; default: - furi_assert(false); + furi_crash("Unknown MFUL"); break; } diff --git a/applications/nfc/helpers/nfc_generators.h b/applications/main/nfc/helpers/nfc_generators.h similarity index 100% rename from applications/nfc/helpers/nfc_generators.h rename to applications/main/nfc/helpers/nfc_generators.h diff --git a/applications/nfc/nfc.c b/applications/main/nfc/nfc.c similarity index 86% rename from applications/nfc/nfc.c rename to applications/main/nfc/nfc.c index 3422e91af..f47a5bac2 100644 --- a/applications/nfc/nfc.c +++ b/applications/main/nfc/nfc.c @@ -94,6 +94,11 @@ Nfc* nfc_alloc() { view_dispatcher_add_view( nfc->view_dispatcher, NfcViewDictAttack, dict_attack_get_view(nfc->dict_attack)); + // Detect Reader + nfc->detect_reader = detect_reader_alloc(); + view_dispatcher_add_view( + nfc->view_dispatcher, NfcViewDetectReader, detect_reader_get_view(nfc->detect_reader)); + // Generator nfc->generator = NULL; @@ -158,6 +163,10 @@ void nfc_free(Nfc* nfc) { view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewDictAttack); dict_attack_free(nfc->dict_attack); + // Detect Reader + view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewDetectReader); + detect_reader_free(nfc->detect_reader); + // Worker nfc_worker_stop(nfc->worker); nfc_worker_free(nfc->worker); @@ -192,8 +201,16 @@ void nfc_text_store_clear(Nfc* nfc) { memset(nfc->text_store, 0, sizeof(nfc->text_store)); } -void nfc_blink_start(Nfc* nfc) { - notification_message(nfc->notifications, &sequence_blink_start_blue); +void nfc_blink_read_start(Nfc* nfc) { + notification_message(nfc->notifications, &sequence_blink_start_cyan); +} + +void nfc_blink_emulate_start(Nfc* nfc) { + notification_message(nfc->notifications, &sequence_blink_start_magenta); +} + +void nfc_blink_detect_start(Nfc* nfc) { + notification_message(nfc->notifications, &sequence_blink_start_yellow); } void nfc_blink_stop(Nfc* nfc) { @@ -214,7 +231,30 @@ void nfc_show_loading_popup(void* context, bool show) { } } +static bool nfc_is_hal_ready() { + if(!furi_hal_nfc_is_init()) { + // No connection to the chip, show an error screen + DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS); + DialogMessage* message = dialog_message_alloc(); + dialog_message_set_text( + message, + "Error!\nNFC chip failed to start\n\n\nSend a photo of this to:\nsupport@flipperzero.one", + 0, + 0, + AlignLeft, + AlignTop); + dialog_message_show(dialogs, message); + dialog_message_free(message); + furi_record_close(RECORD_DIALOGS); + return false; + } else { + return true; + } +} + int32_t nfc_app(void* p) { + if(!nfc_is_hal_ready()) return 0; + Nfc* nfc = nfc_alloc(); char* args = p; diff --git a/applications/nfc/nfc.h b/applications/main/nfc/nfc.h similarity index 100% rename from applications/nfc/nfc.h rename to applications/main/nfc/nfc.h diff --git a/applications/nfc/nfc_cli.c b/applications/main/nfc/nfc_cli.c old mode 100755 new mode 100644 similarity index 100% rename from applications/nfc/nfc_cli.c rename to applications/main/nfc/nfc_cli.c diff --git a/applications/nfc/nfc_i.h b/applications/main/nfc/nfc_i.h similarity index 85% rename from applications/nfc/nfc_i.h rename to applications/main/nfc/nfc_i.h index bcfe4a219..15ea5348f 100644 --- a/applications/nfc/nfc_i.h +++ b/applications/main/nfc/nfc_i.h @@ -28,12 +28,19 @@ #include #include "views/dict_attack.h" +#include "views/detect_reader.h" #include #include +#include + #include "rpc/rpc_app.h" +#include + +ARRAY_DEF(MfClassicUserKeys, char*, M_PTR_OPLIST); + #define NFC_TEXT_STORE_SIZE 128 typedef enum { @@ -57,6 +64,7 @@ struct Nfc { char text_store[NFC_TEXT_STORE_SIZE + 1]; string_t text_box_store; uint8_t byte_input_store[6]; + MfClassicUserKeys_t mfc_key_strs; // Used in MFC key listing void* rpc_ctx; NfcRpcState rpc_state; @@ -71,6 +79,7 @@ struct Nfc { TextBox* text_box; Widget* widget; DictAttack* dict_attack; + DetectReader* detect_reader; const NfcGenerator* generator; }; @@ -85,6 +94,7 @@ typedef enum { NfcViewTextBox, NfcViewWidget, NfcViewDictAttack, + NfcViewDetectReader, } NfcView; Nfc* nfc_alloc(); @@ -95,7 +105,11 @@ void nfc_text_store_set(Nfc* nfc, const char* text, ...); void nfc_text_store_clear(Nfc* nfc); -void nfc_blink_start(Nfc* nfc); +void nfc_blink_read_start(Nfc* nfc); + +void nfc_blink_emulate_start(Nfc* nfc); + +void nfc_blink_detect_start(Nfc* nfc); void nfc_blink_stop(Nfc* nfc); diff --git a/applications/nfc/scenes/nfc_scene.c b/applications/main/nfc/scenes/nfc_scene.c old mode 100755 new mode 100644 similarity index 100% rename from applications/nfc/scenes/nfc_scene.c rename to applications/main/nfc/scenes/nfc_scene.c diff --git a/applications/nfc/scenes/nfc_scene.h b/applications/main/nfc/scenes/nfc_scene.h similarity index 100% rename from applications/nfc/scenes/nfc_scene.h rename to applications/main/nfc/scenes/nfc_scene.h diff --git a/applications/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h old mode 100755 new mode 100644 similarity index 89% rename from applications/nfc/scenes/nfc_scene_config.h rename to applications/main/nfc/scenes/nfc_scene_config.h index ff34a11d8..a25850c84 --- a/applications/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -32,6 +32,9 @@ ADD_SCENE(nfc, mf_classic_menu, MfClassicMenu) ADD_SCENE(nfc, mf_classic_emulate, MfClassicEmulate) ADD_SCENE(nfc, mf_classic_keys, MfClassicKeys) ADD_SCENE(nfc, mf_classic_keys_add, MfClassicKeysAdd) +ADD_SCENE(nfc, mf_classic_keys_list, MfClassicKeysList) +ADD_SCENE(nfc, mf_classic_keys_delete, MfClassicKeysDelete) +ADD_SCENE(nfc, mf_classic_keys_warn_duplicate, MfClassicKeysWarnDuplicate) ADD_SCENE(nfc, mf_classic_dict_attack, MfClassicDictAttack) ADD_SCENE(nfc, emv_read_success, EmvReadSuccess) ADD_SCENE(nfc, emv_menu, EmvMenu) @@ -48,4 +51,6 @@ ADD_SCENE(nfc, rpc, Rpc) ADD_SCENE(nfc, exit_confirm, ExitConfirm) ADD_SCENE(nfc, retry_confirm, RetryConfirm) ADD_SCENE(nfc, detect_reader, DetectReader) +ADD_SCENE(nfc, mfkey_nonces_info, MfkeyNoncesInfo) +ADD_SCENE(nfc, mfkey_complete, MfkeyComplete) ADD_SCENE(nfc, nfc_data_info, NfcDataInfo) diff --git a/applications/nfc/scenes/nfc_scene_debug.c b/applications/main/nfc/scenes/nfc_scene_debug.c similarity index 100% rename from applications/nfc/scenes/nfc_scene_debug.c rename to applications/main/nfc/scenes/nfc_scene_debug.c diff --git a/applications/nfc/scenes/nfc_scene_delete.c b/applications/main/nfc/scenes/nfc_scene_delete.c old mode 100755 new mode 100644 similarity index 100% rename from applications/nfc/scenes/nfc_scene_delete.c rename to applications/main/nfc/scenes/nfc_scene_delete.c diff --git a/applications/nfc/scenes/nfc_scene_delete_success.c b/applications/main/nfc/scenes/nfc_scene_delete_success.c old mode 100755 new mode 100644 similarity index 73% rename from applications/nfc/scenes/nfc_scene_delete_success.c rename to applications/main/nfc/scenes/nfc_scene_delete_success.c index 713b99ebf..1664a9e5b --- a/applications/nfc/scenes/nfc_scene_delete_success.c +++ b/applications/main/nfc/scenes/nfc_scene_delete_success.c @@ -25,8 +25,13 @@ bool nfc_scene_delete_success_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == NfcCustomEventViewExit) { - consumed = scene_manager_search_and_switch_to_previous_scene( - nfc->scene_manager, NfcSceneFileSelect); + if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneMfClassicKeys)) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneMfClassicKeys); + } else { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneStart); + } } } return consumed; diff --git a/applications/main/nfc/scenes/nfc_scene_detect_reader.c b/applications/main/nfc/scenes/nfc_scene_detect_reader.c new file mode 100644 index 000000000..5f4582d8e --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_detect_reader.c @@ -0,0 +1,63 @@ +#include "../nfc_i.h" +#include + +bool nfc_detect_reader_worker_callback(NfcWorkerEvent event, void* context) { + UNUSED(event); + furi_assert(context); + Nfc* nfc = context; + view_dispatcher_send_custom_event(nfc->view_dispatcher, event); + return true; +} + +void nfc_scene_detect_reader_callback(void* context) { + furi_assert(context); + Nfc* nfc = context; + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); +} + +void nfc_scene_detect_reader_on_enter(void* context) { + Nfc* nfc = context; + DOLPHIN_DEED(DolphinDeedNfcEmulate); + + detect_reader_set_callback(nfc->detect_reader, nfc_scene_detect_reader_callback, nfc); + nfc_worker_start( + nfc->worker, + NfcWorkerStateAnalyzeReader, + &nfc->dev->dev_data, + nfc_detect_reader_worker_callback, + nfc); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDetectReader); + + nfc_blink_read_start(nfc); +} + +bool nfc_scene_detect_reader_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventViewExit) { + nfc_worker_stop(nfc->worker); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfkeyNoncesInfo); + consumed = true; + } else if(event.event == NfcWorkerEventDetectReaderMfkeyCollected) { + detect_reader_inc_nonce_cnt(nfc->detect_reader); + consumed = true; + } + } + + return consumed; +} + +void nfc_scene_detect_reader_on_exit(void* context) { + Nfc* nfc = context; + + // Stop worker + nfc_worker_stop(nfc->worker); + + // Clear view + detect_reader_reset(nfc->detect_reader); + + nfc_blink_stop(nfc); +} diff --git a/applications/nfc/scenes/nfc_scene_device_info.c b/applications/main/nfc/scenes/nfc_scene_device_info.c similarity index 95% rename from applications/nfc/scenes/nfc_scene_device_info.c rename to applications/main/nfc/scenes/nfc_scene_device_info.c index 8228c7ea3..245aea5c5 100644 --- a/applications/nfc/scenes/nfc_scene_device_info.c +++ b/applications/main/nfc/scenes/nfc_scene_device_info.c @@ -47,7 +47,9 @@ void nfc_scene_device_info_on_enter(void* context) { } string_clear(country_name); } - } else if(dev_data->protocol == NfcDeviceProtocolMifareClassic) { + } else if( + dev_data->protocol == NfcDeviceProtocolMifareClassic || + dev_data->protocol == NfcDeviceProtocolMifareUl) { string_set(temp_str, nfc->dev->dev_data.parsed_data); } diff --git a/applications/nfc/scenes/nfc_scene_dict_not_found.c b/applications/main/nfc/scenes/nfc_scene_dict_not_found.c similarity index 85% rename from applications/nfc/scenes/nfc_scene_dict_not_found.c rename to applications/main/nfc/scenes/nfc_scene_dict_not_found.c index dc21b08b1..781c5a932 100644 --- a/applications/nfc/scenes/nfc_scene_dict_not_found.c +++ b/applications/main/nfc/scenes/nfc_scene_dict_not_found.c @@ -31,7 +31,10 @@ bool nfc_scene_dict_not_found_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == NfcCustomEventViewExit) { - if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneExtraActions)) { + if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneMfClassicKeys)) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneMfClassicKeys); + } else if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneExtraActions)) { consumed = scene_manager_search_and_switch_to_previous_scene( nfc->scene_manager, NfcSceneExtraActions); } else { diff --git a/applications/nfc/scenes/nfc_scene_emulate_apdu_sequence.c b/applications/main/nfc/scenes/nfc_scene_emulate_apdu_sequence.c similarity index 96% rename from applications/nfc/scenes/nfc_scene_emulate_apdu_sequence.c rename to applications/main/nfc/scenes/nfc_scene_emulate_apdu_sequence.c index e6062ba49..358ad2ab6 100644 --- a/applications/nfc/scenes/nfc_scene_emulate_apdu_sequence.c +++ b/applications/main/nfc/scenes/nfc_scene_emulate_apdu_sequence.c @@ -12,7 +12,7 @@ void nfc_scene_emulate_apdu_sequence_on_enter(void* context) { view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); nfc_worker_start(nfc->worker, NfcWorkerStateEmulateApdu, &nfc->dev->dev_data, NULL, nfc); - nfc_blink_start(nfc); + nfc_blink_emulate_start(nfc); } bool nfc_scene_emulate_apdu_sequence_on_event(void* context, SceneManagerEvent event) { diff --git a/applications/nfc/scenes/nfc_scene_emulate_uid.c b/applications/main/nfc/scenes/nfc_scene_emulate_uid.c old mode 100755 new mode 100644 similarity index 99% rename from applications/nfc/scenes/nfc_scene_emulate_uid.c rename to applications/main/nfc/scenes/nfc_scene_emulate_uid.c index 0d92c9f04..f64023010 --- a/applications/nfc/scenes/nfc_scene_emulate_uid.c +++ b/applications/main/nfc/scenes/nfc_scene_emulate_uid.c @@ -82,7 +82,7 @@ void nfc_scene_emulate_uid_on_enter(void* context) { nfc_emulate_uid_worker_callback, nfc); - nfc_blink_start(nfc); + nfc_blink_emulate_start(nfc); } bool nfc_scene_emulate_uid_on_event(void* context, SceneManagerEvent event) { diff --git a/applications/nfc/scenes/nfc_scene_emv_menu.c b/applications/main/nfc/scenes/nfc_scene_emv_menu.c similarity index 100% rename from applications/nfc/scenes/nfc_scene_emv_menu.c rename to applications/main/nfc/scenes/nfc_scene_emv_menu.c diff --git a/applications/nfc/scenes/nfc_scene_emv_read_success.c b/applications/main/nfc/scenes/nfc_scene_emv_read_success.c similarity index 95% rename from applications/nfc/scenes/nfc_scene_emv_read_success.c rename to applications/main/nfc/scenes/nfc_scene_emv_read_success.c index 9cf7ff9e9..a40b4c1c9 100644 --- a/applications/nfc/scenes/nfc_scene_emv_read_success.c +++ b/applications/main/nfc/scenes/nfc_scene_emv_read_success.c @@ -55,6 +55,8 @@ void nfc_scene_emv_read_success_on_enter(void* context) { string_clear(country_name); } + notification_message_block(nfc->notifications, &sequence_set_green_255); + widget_add_text_scroll_element(nfc->widget, 0, 0, 128, 52, string_get_cstr(temp_str)); string_clear(temp_str); @@ -83,6 +85,8 @@ bool nfc_scene_emv_read_success_on_event(void* context, SceneManagerEvent event) void nfc_scene_emv_read_success_on_exit(void* context) { Nfc* nfc = context; + notification_message_block(nfc->notifications, &sequence_reset_green); + // Clear view widget_reset(nfc->widget); } diff --git a/applications/nfc/scenes/nfc_scene_exit_confirm.c b/applications/main/nfc/scenes/nfc_scene_exit_confirm.c similarity index 100% rename from applications/nfc/scenes/nfc_scene_exit_confirm.c rename to applications/main/nfc/scenes/nfc_scene_exit_confirm.c diff --git a/applications/nfc/scenes/nfc_scene_extra_actions.c b/applications/main/nfc/scenes/nfc_scene_extra_actions.c similarity index 98% rename from applications/nfc/scenes/nfc_scene_extra_actions.c rename to applications/main/nfc/scenes/nfc_scene_extra_actions.c index 43e49e5a0..e888e9d35 100644 --- a/applications/nfc/scenes/nfc_scene_extra_actions.c +++ b/applications/main/nfc/scenes/nfc_scene_extra_actions.c @@ -17,7 +17,7 @@ void nfc_scene_extra_actions_on_enter(void* context) { submenu_add_item( submenu, - "Mf Classic Keys", + "Mifare Classic Keys", SubmenuIndexMfClassicKeys, nfc_scene_extra_actions_submenu_callback, nfc); diff --git a/applications/nfc/scenes/nfc_scene_field.c b/applications/main/nfc/scenes/nfc_scene_field.c similarity index 100% rename from applications/nfc/scenes/nfc_scene_field.c rename to applications/main/nfc/scenes/nfc_scene_field.c diff --git a/applications/nfc/scenes/nfc_scene_file_select.c b/applications/main/nfc/scenes/nfc_scene_file_select.c old mode 100755 new mode 100644 similarity index 100% rename from applications/nfc/scenes/nfc_scene_file_select.c rename to applications/main/nfc/scenes/nfc_scene_file_select.c diff --git a/applications/nfc/scenes/nfc_scene_generate_info.c b/applications/main/nfc/scenes/nfc_scene_generate_info.c similarity index 100% rename from applications/nfc/scenes/nfc_scene_generate_info.c rename to applications/main/nfc/scenes/nfc_scene_generate_info.c diff --git a/applications/nfc/scenes/nfc_scene_mf_classic_dict_attack.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c similarity index 99% rename from applications/nfc/scenes/nfc_scene_mf_classic_dict_attack.c rename to applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c index d821c182d..b23f4b8f1 100644 --- a/applications/nfc/scenes/nfc_scene_mf_classic_dict_attack.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c @@ -90,7 +90,7 @@ void nfc_scene_mf_classic_dict_attack_on_enter(void* context) { Nfc* nfc = context; nfc_scene_mf_classic_dict_attack_prepare_view(nfc, DictAttackStateIdle); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDictAttack); - nfc_blink_start(nfc); + nfc_blink_read_start(nfc); } bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent event) { diff --git a/applications/nfc/scenes/nfc_scene_mf_classic_emulate.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_emulate.c similarity index 98% rename from applications/nfc/scenes/nfc_scene_mf_classic_emulate.c rename to applications/main/nfc/scenes/nfc_scene_mf_classic_emulate.c index 044388b8b..65639b2b4 100644 --- a/applications/nfc/scenes/nfc_scene_mf_classic_emulate.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_emulate.c @@ -35,7 +35,7 @@ void nfc_scene_mf_classic_emulate_on_enter(void* context) { &nfc->dev->dev_data, nfc_mf_classic_emulate_worker_callback, nfc); - nfc_blink_start(nfc); + nfc_blink_emulate_start(nfc); } bool nfc_scene_mf_classic_emulate_on_event(void* context, SceneManagerEvent event) { diff --git a/applications/nfc/scenes/nfc_scene_mf_classic_keys.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys.c similarity index 66% rename from applications/nfc/scenes/nfc_scene_mf_classic_keys.c rename to applications/main/nfc/scenes/nfc_scene_mf_classic_keys.c index fcb8bc189..a2e6ae745 100644 --- a/applications/nfc/scenes/nfc_scene_mf_classic_keys.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys.c @@ -26,15 +26,25 @@ void nfc_scene_mf_classic_keys_on_enter(void* context) { } widget_add_string_element( - nfc->widget, 0, 0, AlignLeft, AlignTop, FontPrimary, "MF Classic Keys"); + nfc->widget, 0, 0, AlignLeft, AlignTop, FontPrimary, "Mifare Classic Keys"); char temp_str[32]; - snprintf(temp_str, sizeof(temp_str), "Flipper dict: %ld", flipper_dict_keys_total); + snprintf(temp_str, sizeof(temp_str), "Flipper list: %ld", flipper_dict_keys_total); widget_add_string_element(nfc->widget, 0, 20, AlignLeft, AlignTop, FontSecondary, temp_str); - snprintf(temp_str, sizeof(temp_str), "User dict: %ld", user_dict_keys_total); + snprintf(temp_str, sizeof(temp_str), "User list: %ld", user_dict_keys_total); widget_add_string_element(nfc->widget, 0, 32, AlignLeft, AlignTop, FontSecondary, temp_str); widget_add_button_element( nfc->widget, GuiButtonTypeCenter, "Add", nfc_scene_mf_classic_keys_widget_callback, nfc); - widget_add_icon_element(nfc->widget, 90, 12, &I_Keychain); + widget_add_button_element( + nfc->widget, GuiButtonTypeLeft, "Back", nfc_scene_mf_classic_keys_widget_callback, nfc); + widget_add_icon_element(nfc->widget, 87, 13, &I_Keychain_39x36); + if(user_dict_keys_total > 0) { + widget_add_button_element( + nfc->widget, + GuiButtonTypeRight, + "List", + nfc_scene_mf_classic_keys_widget_callback, + nfc); + } view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); } @@ -47,6 +57,12 @@ bool nfc_scene_mf_classic_keys_on_event(void* context, SceneManagerEvent event) if(event.event == GuiButtonTypeCenter) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicKeysAdd); consumed = true; + } else if(event.event == GuiButtonTypeLeft) { + scene_manager_previous_scene(nfc->scene_manager); + consumed = true; + } else if(event.event == GuiButtonTypeRight) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicKeysList); + consumed = true; } } diff --git a/applications/nfc/scenes/nfc_scene_mf_classic_keys_add.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_add.c similarity index 76% rename from applications/nfc/scenes/nfc_scene_mf_classic_keys_add.c rename to applications/main/nfc/scenes/nfc_scene_mf_classic_keys_add.c index 9f56b0f45..2921d21c9 100644 --- a/applications/nfc/scenes/nfc_scene_mf_classic_keys_add.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_add.c @@ -29,15 +29,16 @@ bool nfc_scene_mf_classic_keys_add_on_event(void* context, SceneManagerEvent eve if(event.type == SceneManagerEventTypeCustom) { if(event.event == NfcCustomEventByteInputDone) { // Add key to dict - bool key_added = false; MfClassicDict* dict = mf_classic_dict_alloc(MfClassicDictTypeUser); if(dict) { - if(mf_classic_dict_add_key(dict, nfc->byte_input_store)) { - key_added = true; + if(mf_classic_dict_is_key_present(dict, nfc->byte_input_store)) { + scene_manager_next_scene( + nfc->scene_manager, NfcSceneMfClassicKeysWarnDuplicate); + } else if(mf_classic_dict_add_key(dict, nfc->byte_input_store)) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess); + } else { + scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound); } - } - if(key_added) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess); } else { scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound); } diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_delete.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_delete.c new file mode 100644 index 000000000..16a189da6 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_delete.c @@ -0,0 +1,77 @@ +#include "../nfc_i.h" + +void nfc_scene_mf_classic_keys_delete_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + Nfc* nfc = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); + } +} + +void nfc_scene_mf_classic_keys_delete_on_enter(void* context) { + Nfc* nfc = context; + MfClassicDict* dict = mf_classic_dict_alloc(MfClassicDictTypeUser); + uint32_t key_index = + scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicKeysDelete); + // Setup Custom Widget view + string_t key_str; + string_init(key_str); + + widget_add_string_element( + nfc->widget, 64, 0, AlignCenter, AlignTop, FontPrimary, "Delete this key?"); + widget_add_button_element( + nfc->widget, + GuiButtonTypeLeft, + "Cancel", + nfc_scene_mf_classic_keys_delete_widget_callback, + nfc); + widget_add_button_element( + nfc->widget, + GuiButtonTypeRight, + "Delete", + nfc_scene_mf_classic_keys_delete_widget_callback, + nfc); + + mf_classic_dict_get_key_at_index_str(dict, key_str, key_index); + widget_add_string_element( + nfc->widget, 64, 32, AlignCenter, AlignCenter, FontSecondary, string_get_cstr(key_str)); + + string_clear(key_str); + mf_classic_dict_free(dict); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); +} + +bool nfc_scene_mf_classic_keys_delete_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + bool consumed = false; + uint32_t key_index = + scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicKeysDelete); + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeLeft) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneMfClassicKeys); + } else if(event.event == GuiButtonTypeRight) { + MfClassicDict* dict = mf_classic_dict_alloc(MfClassicDictTypeUser); + if(mf_classic_dict_delete_index(dict, key_index)) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneDeleteSuccess); + } else { + scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneMfClassicKeys); + } + mf_classic_dict_free(dict); + consumed = true; + } + } + + return consumed; +} + +void nfc_scene_mf_classic_keys_delete_on_exit(void* context) { + Nfc* nfc = context; + + widget_reset(nfc->widget); +} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_list.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_list.c new file mode 100644 index 000000000..36f01897e --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_list.c @@ -0,0 +1,60 @@ +#include "../nfc_i.h" + +void nfc_scene_mf_classic_keys_list_submenu_callback(void* context, uint32_t index) { + Nfc* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, index); +} + +void nfc_scene_mf_classic_keys_list_on_enter(void* context) { + Nfc* nfc = context; + Submenu* submenu = nfc->submenu; + MfClassicDict* dict = mf_classic_dict_alloc(MfClassicDictTypeUser); + uint32_t index = 0; + string_t temp_key; + MfClassicUserKeys_init(nfc->mfc_key_strs); + string_init(temp_key); + if(dict) { + mf_classic_dict_rewind(dict); + while(mf_classic_dict_get_next_key_str(dict, temp_key)) { + char* current_key = (char*)malloc(sizeof(char) * 13); + strncpy(current_key, string_get_cstr(temp_key), 12); + MfClassicUserKeys_push_back(nfc->mfc_key_strs, current_key); + FURI_LOG_D("ListKeys", "Key %d: %s", index, current_key); + submenu_add_item( + submenu, + current_key, + index++, + nfc_scene_mf_classic_keys_list_submenu_callback, + nfc); + } + } + submenu_set_header(submenu, "Select key to delete:"); + mf_classic_dict_free(dict); + string_clear(temp_key); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); +} + +bool nfc_scene_mf_classic_keys_list_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + bool consumed = false; + if(event.type == SceneManagerEventTypeCustom) { + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneMfClassicKeysDelete, event.event); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicKeysDelete); + consumed = true; + } + return consumed; +} + +void nfc_scene_mf_classic_keys_list_on_exit(void* context) { + Nfc* nfc = context; + + MfClassicUserKeys_it_t it; + for(MfClassicUserKeys_it(it, nfc->mfc_key_strs); !MfClassicUserKeys_end_p(it); + MfClassicUserKeys_next(it)) { + free(*MfClassicUserKeys_ref(it)); + } + MfClassicUserKeys_clear(nfc->mfc_key_strs); + submenu_reset(nfc->submenu); +} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_warn_duplicate.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_warn_duplicate.c new file mode 100644 index 000000000..ab41989b2 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_warn_duplicate.c @@ -0,0 +1,47 @@ +#include "../nfc_i.h" + +void nfc_scene_mf_classic_keys_warn_duplicate_popup_callback(void* context) { + Nfc* nfc = context; + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); +} + +void nfc_scene_mf_classic_keys_warn_duplicate_on_enter(void* context) { + Nfc* nfc = context; + + // Setup view + Popup* popup = nfc->popup; + popup_set_icon(popup, 72, 16, &I_DolphinCommon_56x48); + popup_set_header(popup, "Key already exists!", 64, 3, AlignCenter, AlignTop); + popup_set_text( + popup, + "Please enter a\n" + "different key.", + 4, + 24, + AlignLeft, + AlignTop); + popup_set_timeout(popup, 5000); + popup_set_context(popup, nfc); + popup_set_callback(popup, nfc_scene_mf_classic_keys_warn_duplicate_popup_callback); + popup_enable_timeout(popup); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); +} + +bool nfc_scene_mf_classic_keys_warn_duplicate_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventViewExit) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneMfClassicKeysAdd); + } + } + return consumed; +} + +void nfc_scene_mf_classic_keys_warn_duplicate_on_exit(void* context) { + Nfc* nfc = context; + + popup_reset(nfc->popup); +} diff --git a/applications/nfc/scenes/nfc_scene_mf_classic_menu.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_menu.c similarity index 100% rename from applications/nfc/scenes/nfc_scene_mf_classic_menu.c rename to applications/main/nfc/scenes/nfc_scene_mf_classic_menu.c diff --git a/applications/nfc/scenes/nfc_scene_mf_classic_read_success.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_read_success.c similarity index 94% rename from applications/nfc/scenes/nfc_scene_mf_classic_read_success.c rename to applications/main/nfc/scenes/nfc_scene_mf_classic_read_success.c index efe676706..3ca24416a 100644 --- a/applications/nfc/scenes/nfc_scene_mf_classic_read_success.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_read_success.c @@ -48,6 +48,8 @@ void nfc_scene_mf_classic_read_success_on_enter(void* context) { widget_add_text_scroll_element(widget, 0, 0, 128, 52, string_get_cstr(temp_str)); string_clear(temp_str); + notification_message_block(nfc->notifications, &sequence_set_green_255); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); } @@ -76,6 +78,8 @@ bool nfc_scene_mf_classic_read_success_on_event(void* context, SceneManagerEvent void nfc_scene_mf_classic_read_success_on_exit(void* context) { Nfc* nfc = context; + notification_message_block(nfc->notifications, &sequence_reset_green); + // Clear view widget_reset(nfc->widget); } diff --git a/applications/nfc/scenes/nfc_scene_mf_desfire_app.c b/applications/main/nfc/scenes/nfc_scene_mf_desfire_app.c similarity index 100% rename from applications/nfc/scenes/nfc_scene_mf_desfire_app.c rename to applications/main/nfc/scenes/nfc_scene_mf_desfire_app.c diff --git a/applications/nfc/scenes/nfc_scene_mf_desfire_data.c b/applications/main/nfc/scenes/nfc_scene_mf_desfire_data.c similarity index 100% rename from applications/nfc/scenes/nfc_scene_mf_desfire_data.c rename to applications/main/nfc/scenes/nfc_scene_mf_desfire_data.c diff --git a/applications/nfc/scenes/nfc_scene_mf_desfire_menu.c b/applications/main/nfc/scenes/nfc_scene_mf_desfire_menu.c similarity index 100% rename from applications/nfc/scenes/nfc_scene_mf_desfire_menu.c rename to applications/main/nfc/scenes/nfc_scene_mf_desfire_menu.c diff --git a/applications/nfc/scenes/nfc_scene_mf_desfire_read_success.c b/applications/main/nfc/scenes/nfc_scene_mf_desfire_read_success.c similarity index 95% rename from applications/nfc/scenes/nfc_scene_mf_desfire_read_success.c rename to applications/main/nfc/scenes/nfc_scene_mf_desfire_read_success.c index 4827c2851..12047c15a 100644 --- a/applications/nfc/scenes/nfc_scene_mf_desfire_read_success.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_desfire_read_success.c @@ -52,6 +52,8 @@ void nfc_scene_mf_desfire_read_success_on_enter(void* context) { string_push_back(temp_str, 's'); } + notification_message_block(nfc->notifications, &sequence_set_green_255); + // Add text scroll element widget_add_text_scroll_element(widget, 0, 0, 128, 52, string_get_cstr(temp_str)); string_clear(temp_str); @@ -88,6 +90,8 @@ bool nfc_scene_mf_desfire_read_success_on_event(void* context, SceneManagerEvent void nfc_scene_mf_desfire_read_success_on_exit(void* context) { Nfc* nfc = context; + notification_message_block(nfc->notifications, &sequence_reset_green); + // Clean dialog widget_reset(nfc->widget); } diff --git a/applications/nfc/scenes/nfc_scene_mf_ultralight_data.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_data.c similarity index 100% rename from applications/nfc/scenes/nfc_scene_mf_ultralight_data.c rename to applications/main/nfc/scenes/nfc_scene_mf_ultralight_data.c diff --git a/applications/nfc/scenes/nfc_scene_mf_ultralight_emulate.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_emulate.c old mode 100755 new mode 100644 similarity index 98% rename from applications/nfc/scenes/nfc_scene_mf_ultralight_emulate.c rename to applications/main/nfc/scenes/nfc_scene_mf_ultralight_emulate.c index ce3755541..712ddc077 --- a/applications/nfc/scenes/nfc_scene_mf_ultralight_emulate.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_emulate.c @@ -35,7 +35,7 @@ void nfc_scene_mf_ultralight_emulate_on_enter(void* context) { &nfc->dev->dev_data, nfc_mf_ultralight_emulate_worker_callback, nfc); - nfc_blink_start(nfc); + nfc_blink_emulate_start(nfc); } bool nfc_scene_mf_ultralight_emulate_on_event(void* context, SceneManagerEvent event) { diff --git a/applications/nfc/scenes/nfc_scene_mf_ultralight_key_input.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_key_input.c similarity index 100% rename from applications/nfc/scenes/nfc_scene_mf_ultralight_key_input.c rename to applications/main/nfc/scenes/nfc_scene_mf_ultralight_key_input.c diff --git a/applications/nfc/scenes/nfc_scene_mf_ultralight_menu.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c similarity index 100% rename from applications/nfc/scenes/nfc_scene_mf_ultralight_menu.c rename to applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c diff --git a/applications/nfc/scenes/nfc_scene_mf_ultralight_read_auth.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_auth.c similarity index 97% rename from applications/nfc/scenes/nfc_scene_mf_ultralight_read_auth.c rename to applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_auth.c index 853ccb055..25008004b 100644 --- a/applications/nfc/scenes/nfc_scene_mf_ultralight_read_auth.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_auth.c @@ -27,7 +27,7 @@ void nfc_scene_mf_ultralight_read_auth_set_state(Nfc* nfc, NfcSceneMfUlReadState popup_reset(nfc->popup); popup_set_text( nfc->popup, "Apply card to\nFlipper's back", 97, 24, AlignCenter, AlignTop); - popup_set_icon(nfc->popup, 0, 8, &I_NFC_manual); + popup_set_icon(nfc->popup, 0, 8, &I_NFC_manual_60x50); } else if(state == NfcSceneMfUlReadStateReading) { popup_reset(nfc->popup); popup_set_header( @@ -65,7 +65,7 @@ void nfc_scene_mf_ultralight_read_auth_on_enter(void* context) { nfc_scene_mf_ultralight_read_auth_worker_callback, nfc); - nfc_blink_start(nfc); + nfc_blink_read_start(nfc); } bool nfc_scene_mf_ultralight_read_auth_on_event(void* context, SceneManagerEvent event) { diff --git a/applications/nfc/scenes/nfc_scene_mf_ultralight_read_auth_result.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_auth_result.c similarity index 100% rename from applications/nfc/scenes/nfc_scene_mf_ultralight_read_auth_result.c rename to applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_auth_result.c diff --git a/applications/nfc/scenes/nfc_scene_mf_ultralight_read_success.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_success.c similarity index 71% rename from applications/nfc/scenes/nfc_scene_mf_ultralight_read_success.c rename to applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_success.c index d775bb71d..f6dc5984e 100644 --- a/applications/nfc/scenes/nfc_scene_mf_ultralight_read_success.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_success.c @@ -34,19 +34,25 @@ void nfc_scene_mf_ultralight_read_success_on_enter(void* context) { nfc); string_t temp_str; - string_init_printf(temp_str, "\e#%s\n", nfc_mf_ul_type(mf_ul_data->type, true)); - string_cat_printf(temp_str, "UID:"); - for(size_t i = 0; i < data->uid_len; i++) { - string_cat_printf(temp_str, " %02X", data->uid[i]); - } - string_cat_printf( - temp_str, "\nPages Read: %d/%d", mf_ul_data->data_read / 4, mf_ul_data->data_size / 4); - if(mf_ul_data->data_read != mf_ul_data->data_size) { - string_cat_printf(temp_str, "\nPassword-protected pages!"); + if(string_size(nfc->dev->dev_data.parsed_data)) { + string_init_set(temp_str, nfc->dev->dev_data.parsed_data); + } else { + string_init_printf(temp_str, "\e#%s\n", nfc_mf_ul_type(mf_ul_data->type, true)); + string_cat_printf(temp_str, "UID:"); + for(size_t i = 0; i < data->uid_len; i++) { + string_cat_printf(temp_str, " %02X", data->uid[i]); + } + string_cat_printf( + temp_str, "\nPages Read: %d/%d", mf_ul_data->data_read / 4, mf_ul_data->data_size / 4); + if(mf_ul_data->data_read != mf_ul_data->data_size) { + string_cat_printf(temp_str, "\nPassword-protected pages!"); + } } widget_add_text_scroll_element(widget, 0, 0, 128, 52, string_get_cstr(temp_str)); string_clear(temp_str); + notification_message_block(nfc->notifications, &sequence_set_green_255); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); } @@ -73,6 +79,8 @@ bool nfc_scene_mf_ultralight_read_success_on_event(void* context, SceneManagerEv void nfc_scene_mf_ultralight_read_success_on_exit(void* context) { Nfc* nfc = context; + notification_message_block(nfc->notifications, &sequence_reset_green); + // Clean view widget_reset(nfc->widget); } diff --git a/applications/nfc/scenes/nfc_scene_mf_ultralight_unlock_menu.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_menu.c similarity index 100% rename from applications/nfc/scenes/nfc_scene_mf_ultralight_unlock_menu.c rename to applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_menu.c diff --git a/applications/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c similarity index 100% rename from applications/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c rename to applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c diff --git a/applications/main/nfc/scenes/nfc_scene_mfkey_complete.c b/applications/main/nfc/scenes/nfc_scene_mfkey_complete.c new file mode 100644 index 000000000..3c4f9dba1 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mfkey_complete.c @@ -0,0 +1,49 @@ +#include "../nfc_i.h" + +void nfc_scene_mfkey_complete_callback(GuiButtonType result, InputType type, void* context) { + Nfc* nfc = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); + } +} + +void nfc_scene_mfkey_complete_on_enter(void* context) { + Nfc* nfc = context; + + widget_add_string_element(nfc->widget, 64, 0, AlignCenter, AlignTop, FontPrimary, "Complete!"); + widget_add_string_multiline_element( + nfc->widget, + 64, + 32, + AlignCenter, + AlignCenter, + FontSecondary, + "Now use mfkey32v2\nto extract keys"); + widget_add_button_element( + nfc->widget, GuiButtonTypeCenter, "OK", nfc_scene_mfkey_complete_callback, nfc); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); +} + +bool nfc_scene_mfkey_complete_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeCenter) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneStart); + } + } else if(event.event == SceneManagerEventTypeBack) { + consumed = + scene_manager_search_and_switch_to_previous_scene(nfc->scene_manager, NfcSceneStart); + } + + return consumed; +} + +void nfc_scene_mfkey_complete_on_exit(void* context) { + Nfc* nfc = context; + + widget_reset(nfc->widget); +} \ No newline at end of file diff --git a/applications/main/nfc/scenes/nfc_scene_mfkey_nonces_info.c b/applications/main/nfc/scenes/nfc_scene_mfkey_nonces_info.c new file mode 100644 index 000000000..b45b690d3 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mfkey_nonces_info.c @@ -0,0 +1,55 @@ +#include "../nfc_i.h" +#include + +void nfc_scene_mfkey_nonces_info_callback(GuiButtonType result, InputType type, void* context) { + Nfc* nfc = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); + } +} + +void nfc_scene_mfkey_nonces_info_on_enter(void* context) { + Nfc* nfc = context; + + string_t temp_str; + string_init(temp_str); + + uint16_t nonces_saved = mfkey32_get_auth_sectors(temp_str); + widget_add_text_scroll_element(nfc->widget, 0, 22, 128, 42, string_get_cstr(temp_str)); + string_printf(temp_str, "Nonces saved %d", nonces_saved); + widget_add_string_element( + nfc->widget, 0, 0, AlignLeft, AlignTop, FontPrimary, string_get_cstr(temp_str)); + widget_add_string_element( + nfc->widget, 0, 12, AlignLeft, AlignTop, FontSecondary, "Authenticated sectors:"); + + widget_add_button_element( + nfc->widget, GuiButtonTypeRight, "Next", nfc_scene_mfkey_nonces_info_callback, nfc); + + string_clear(temp_str); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); +} + +bool nfc_scene_mfkey_nonces_info_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeRight) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfkeyComplete); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeBack) { + consumed = + scene_manager_search_and_switch_to_previous_scene(nfc->scene_manager, NfcSceneStart); + } + + return consumed; +} + +void nfc_scene_mfkey_nonces_info_on_exit(void* context) { + Nfc* nfc = context; + + // Clear view + widget_reset(nfc->widget); +} diff --git a/applications/nfc/scenes/nfc_scene_nfc_data_info.c b/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c similarity index 100% rename from applications/nfc/scenes/nfc_scene_nfc_data_info.c rename to applications/main/nfc/scenes/nfc_scene_nfc_data_info.c diff --git a/applications/nfc/scenes/nfc_scene_nfca_menu.c b/applications/main/nfc/scenes/nfc_scene_nfca_menu.c similarity index 100% rename from applications/nfc/scenes/nfc_scene_nfca_menu.c rename to applications/main/nfc/scenes/nfc_scene_nfca_menu.c diff --git a/applications/nfc/scenes/nfc_scene_nfca_read_success.c b/applications/main/nfc/scenes/nfc_scene_nfca_read_success.c similarity index 93% rename from applications/nfc/scenes/nfc_scene_nfca_read_success.c rename to applications/main/nfc/scenes/nfc_scene_nfca_read_success.c index 3467a03b6..c695da247 100644 --- a/applications/nfc/scenes/nfc_scene_nfca_read_success.c +++ b/applications/main/nfc/scenes/nfc_scene_nfca_read_success.c @@ -25,6 +25,8 @@ void nfc_scene_nfca_read_success_on_enter(void* context) { string_t temp_str; string_init_set_str(temp_str, "\e#Unknown ISO tag\n"); + notification_message_block(nfc->notifications, &sequence_set_green_255); + char iso_type = FURI_BIT(data->sak, 5) ? '4' : '3'; string_cat_printf(temp_str, "ISO 14443-%c (NFC-A)\n", iso_type); string_cat_printf(temp_str, "UID:"); @@ -67,6 +69,8 @@ bool nfc_scene_nfca_read_success_on_event(void* context, SceneManagerEvent event void nfc_scene_nfca_read_success_on_exit(void* context) { Nfc* nfc = context; + notification_message_block(nfc->notifications, &sequence_reset_green); + // Clear view widget_reset(nfc->widget); } diff --git a/applications/nfc/scenes/nfc_scene_read.c b/applications/main/nfc/scenes/nfc_scene_read.c similarity index 96% rename from applications/nfc/scenes/nfc_scene_read.c rename to applications/main/nfc/scenes/nfc_scene_read.c index 00b7c8fac..e6df476f0 100644 --- a/applications/nfc/scenes/nfc_scene_read.c +++ b/applications/main/nfc/scenes/nfc_scene_read.c @@ -26,7 +26,7 @@ void nfc_scene_read_set_state(Nfc* nfc, NfcSceneReadState state) { popup_reset(nfc->popup); popup_set_text( nfc->popup, "Apply card to\nFlipper's back", 97, 24, AlignCenter, AlignTop); - popup_set_icon(nfc->popup, 0, 8, &I_NFC_manual); + popup_set_icon(nfc->popup, 0, 8, &I_NFC_manual_60x50); } else if(state == NfcSceneReadStateReading) { popup_reset(nfc->popup); popup_set_header( @@ -49,7 +49,7 @@ void nfc_scene_read_on_enter(void* context) { nfc_worker_start( nfc->worker, NfcWorkerStateRead, &nfc->dev->dev_data, nfc_scene_read_worker_callback, nfc); - nfc_blink_start(nfc); + nfc_blink_read_start(nfc); } bool nfc_scene_read_on_event(void* context, SceneManagerEvent event) { @@ -92,9 +92,11 @@ bool nfc_scene_read_on_event(void* context, SceneManagerEvent event) { consumed = true; } else if(event.event == NfcWorkerEventCardDetected) { nfc_scene_read_set_state(nfc, NfcSceneReadStateReading); + nfc_blink_detect_start(nfc); consumed = true; } else if(event.event == NfcWorkerEventNoCardDetected) { nfc_scene_read_set_state(nfc, NfcSceneReadStateDetecting); + nfc_blink_read_start(nfc); consumed = true; } } diff --git a/applications/nfc/scenes/nfc_scene_read_card_success.c b/applications/main/nfc/scenes/nfc_scene_read_card_success.c old mode 100755 new mode 100644 similarity index 100% rename from applications/nfc/scenes/nfc_scene_read_card_success.c rename to applications/main/nfc/scenes/nfc_scene_read_card_success.c diff --git a/applications/nfc/scenes/nfc_scene_restore_original.c b/applications/main/nfc/scenes/nfc_scene_restore_original.c similarity index 100% rename from applications/nfc/scenes/nfc_scene_restore_original.c rename to applications/main/nfc/scenes/nfc_scene_restore_original.c diff --git a/applications/nfc/scenes/nfc_scene_restore_original_confirm.c b/applications/main/nfc/scenes/nfc_scene_restore_original_confirm.c similarity index 96% rename from applications/nfc/scenes/nfc_scene_restore_original_confirm.c rename to applications/main/nfc/scenes/nfc_scene_restore_original_confirm.c index 2c12749df..730dd41e8 100644 --- a/applications/nfc/scenes/nfc_scene_restore_original_confirm.c +++ b/applications/main/nfc/scenes/nfc_scene_restore_original_confirm.c @@ -11,7 +11,7 @@ void nfc_scene_restore_original_confirm_on_enter(void* context) { DialogEx* dialog_ex = nfc->dialog_ex; dialog_ex_set_header(dialog_ex, "Restore Card Data?", 64, 0, AlignCenter, AlignTop); - dialog_ex_set_icon(dialog_ex, 5, 15, &I_Restoring); + dialog_ex_set_icon(dialog_ex, 5, 15, &I_Restoring_38x32); dialog_ex_set_text( dialog_ex, "It will be returned\nto its original state.", 47, 21, AlignLeft, AlignTop); dialog_ex_set_left_button_text(dialog_ex, "Cancel"); diff --git a/applications/nfc/scenes/nfc_scene_retry_confirm.c b/applications/main/nfc/scenes/nfc_scene_retry_confirm.c similarity index 100% rename from applications/nfc/scenes/nfc_scene_retry_confirm.c rename to applications/main/nfc/scenes/nfc_scene_retry_confirm.c diff --git a/applications/nfc/scenes/nfc_scene_rpc.c b/applications/main/nfc/scenes/nfc_scene_rpc.c similarity index 98% rename from applications/nfc/scenes/nfc_scene_rpc.c rename to applications/main/nfc/scenes/nfc_scene_rpc.c index 7a9eb4503..e5128a52f 100644 --- a/applications/nfc/scenes/nfc_scene_rpc.c +++ b/applications/main/nfc/scenes/nfc_scene_rpc.c @@ -62,7 +62,7 @@ bool nfc_scene_rpc_on_event(void* context, SceneManagerEvent event) { nfc->rpc_state = NfcRpcStateEmulating; result = true; - nfc_blink_start(nfc); + nfc_blink_emulate_start(nfc); nfc_text_store_set(nfc, "emulating\n%s", nfc->dev->dev_name); popup_set_text(popup, nfc->text_store, 89, 44, AlignCenter, AlignTop); } diff --git a/applications/nfc/scenes/nfc_scene_save_name.c b/applications/main/nfc/scenes/nfc_scene_save_name.c similarity index 100% rename from applications/nfc/scenes/nfc_scene_save_name.c rename to applications/main/nfc/scenes/nfc_scene_save_name.c diff --git a/applications/nfc/scenes/nfc_scene_save_success.c b/applications/main/nfc/scenes/nfc_scene_save_success.c similarity index 85% rename from applications/nfc/scenes/nfc_scene_save_success.c rename to applications/main/nfc/scenes/nfc_scene_save_success.c index a3b17451f..dcd2519f1 100644 --- a/applications/nfc/scenes/nfc_scene_save_success.c +++ b/applications/main/nfc/scenes/nfc_scene_save_success.c @@ -27,7 +27,10 @@ bool nfc_scene_save_success_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == NfcCustomEventViewExit) { - if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSavedMenu)) { + if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneMfClassicKeys)) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneMfClassicKeys); + } else if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSavedMenu)) { consumed = scene_manager_search_and_switch_to_previous_scene( nfc->scene_manager, NfcSceneSavedMenu); } else { diff --git a/applications/nfc/scenes/nfc_scene_saved_menu.c b/applications/main/nfc/scenes/nfc_scene_saved_menu.c similarity index 96% rename from applications/nfc/scenes/nfc_scene_saved_menu.c rename to applications/main/nfc/scenes/nfc_scene_saved_menu.c index c7aec5d87..c1043b3a7 100644 --- a/applications/nfc/scenes/nfc_scene_saved_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_saved_menu.c @@ -91,7 +91,9 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { bool application_info_present = false; if(dev_data->protocol == NfcDeviceProtocolEMV) { application_info_present = true; - } else if(dev_data->protocol == NfcDeviceProtocolMifareClassic) { + } else if( + dev_data->protocol == NfcDeviceProtocolMifareClassic || + dev_data->protocol == NfcDeviceProtocolMifareUl) { application_info_present = nfc_supported_card_verify_and_parse(dev_data); } diff --git a/applications/nfc/scenes/nfc_scene_set_atqa.c b/applications/main/nfc/scenes/nfc_scene_set_atqa.c old mode 100755 new mode 100644 similarity index 100% rename from applications/nfc/scenes/nfc_scene_set_atqa.c rename to applications/main/nfc/scenes/nfc_scene_set_atqa.c diff --git a/applications/nfc/scenes/nfc_scene_set_sak.c b/applications/main/nfc/scenes/nfc_scene_set_sak.c old mode 100755 new mode 100644 similarity index 100% rename from applications/nfc/scenes/nfc_scene_set_sak.c rename to applications/main/nfc/scenes/nfc_scene_set_sak.c diff --git a/applications/nfc/scenes/nfc_scene_set_type.c b/applications/main/nfc/scenes/nfc_scene_set_type.c similarity index 100% rename from applications/nfc/scenes/nfc_scene_set_type.c rename to applications/main/nfc/scenes/nfc_scene_set_type.c diff --git a/applications/nfc/scenes/nfc_scene_set_uid.c b/applications/main/nfc/scenes/nfc_scene_set_uid.c old mode 100755 new mode 100644 similarity index 100% rename from applications/nfc/scenes/nfc_scene_set_uid.c rename to applications/main/nfc/scenes/nfc_scene_set_uid.c diff --git a/applications/nfc/scenes/nfc_scene_start.c b/applications/main/nfc/scenes/nfc_scene_start.c similarity index 89% rename from applications/nfc/scenes/nfc_scene_start.c rename to applications/main/nfc/scenes/nfc_scene_start.c index 01ffb46b8..1a9051dfd 100644 --- a/applications/nfc/scenes/nfc_scene_start.c +++ b/applications/main/nfc/scenes/nfc_scene_start.c @@ -49,7 +49,12 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); consumed = true; } else if(event.event == SubmenuIndexDetectReader) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneDetectReader); + bool sd_exist = storage_sd_status(nfc->dev->storage) == FSE_OK; + if(sd_exist) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneDetectReader); + } else { + scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound); + } consumed = true; } else if(event.event == SubmenuIndexSaved) { scene_manager_next_scene(nfc->scene_manager, NfcSceneFileSelect); @@ -61,7 +66,6 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(nfc->scene_manager, NfcSceneSetType); consumed = true; } else if(event.event == SubmenuIndexDebug) { - scene_manager_set_scene_state(nfc->scene_manager, NfcSceneStart, SubmenuIndexDebug); scene_manager_next_scene(nfc->scene_manager, NfcSceneDebug); consumed = true; } diff --git a/applications/main/nfc/views/detect_reader.c b/applications/main/nfc/views/detect_reader.c new file mode 100644 index 000000000..177c13f75 --- /dev/null +++ b/applications/main/nfc/views/detect_reader.c @@ -0,0 +1,115 @@ +#include "detect_reader.h" + +#include + +struct DetectReader { + View* view; + DetectReaderDoneCallback callback; + void* context; +}; + +typedef struct { + uint16_t nonces; +} DetectReaderViewModel; + +static void detect_reader_draw_callback(Canvas* canvas, void* model) { + DetectReaderViewModel* m = model; + char text[32] = {}; + + snprintf(text, sizeof(text), "Tap the reader several times"); + canvas_draw_str_aligned(canvas, 64, 0, AlignCenter, AlignTop, "Tap the reader several times"); + + if(m->nonces == 0) { + canvas_set_font(canvas, FontPrimary); + canvas_draw_str_aligned(canvas, 52, 22, AlignLeft, AlignTop, "Emulating..."); + canvas_set_font(canvas, FontSecondary); + canvas_draw_str_aligned(canvas, 52, 35, AlignLeft, AlignTop, "MIFARE Classic"); + canvas_draw_icon(canvas, 0, 13, &I_Tap_reader_36x38); + } else { + canvas_set_font(canvas, FontPrimary); + canvas_draw_str_aligned(canvas, 54, 22, AlignLeft, AlignTop, "Collecting..."); + canvas_set_font(canvas, FontSecondary); + snprintf(text, sizeof(text), "Nonces: %d", m->nonces); + canvas_draw_str_aligned(canvas, 54, 35, AlignLeft, AlignTop, text); + elements_button_right(canvas, "Next"); + canvas_draw_icon(canvas, 6, 15, &I_ArrowC_1_36x36); + } +} + +static bool detect_reader_input_callback(InputEvent* event, void* context) { + DetectReader* detect_reader = context; + furi_assert(detect_reader->callback); + bool consumed = false; + + uint8_t nonces = 0; + with_view_model( + detect_reader->view, (DetectReaderViewModel * model) { + nonces = model->nonces; + return false; + }); + + if(event->type == InputTypeShort) { + if(event->key == InputKeyRight) { + if(nonces > 0) { + detect_reader->callback(detect_reader->context); + consumed = true; + } + } + } + + return consumed; +} + +DetectReader* detect_reader_alloc() { + DetectReader* detect_reader = malloc(sizeof(DetectReader)); + detect_reader->view = view_alloc(); + view_allocate_model(detect_reader->view, ViewModelTypeLocking, sizeof(DetectReaderViewModel)); + view_set_draw_callback(detect_reader->view, detect_reader_draw_callback); + view_set_input_callback(detect_reader->view, detect_reader_input_callback); + view_set_context(detect_reader->view, detect_reader); + + return detect_reader; +} + +void detect_reader_free(DetectReader* detect_reader) { + furi_assert(detect_reader); + + view_free(detect_reader->view); + free(detect_reader); +} + +void detect_reader_reset(DetectReader* detect_reader) { + furi_assert(detect_reader); + + with_view_model( + detect_reader->view, (DetectReaderViewModel * model) { + model->nonces = 0; + return false; + }); +} + +View* detect_reader_get_view(DetectReader* detect_reader) { + furi_assert(detect_reader); + + return detect_reader->view; +} + +void detect_reader_set_callback( + DetectReader* detect_reader, + DetectReaderDoneCallback callback, + void* context) { + furi_assert(detect_reader); + furi_assert(callback); + + detect_reader->callback = callback; + detect_reader->context = context; +} + +void detect_reader_inc_nonce_cnt(DetectReader* detect_reader) { + furi_assert(detect_reader); + with_view_model( + detect_reader->view, (DetectReaderViewModel * model) { + model->nonces++; + return false; + }); +} diff --git a/applications/main/nfc/views/detect_reader.h b/applications/main/nfc/views/detect_reader.h new file mode 100644 index 000000000..12cd03db4 --- /dev/null +++ b/applications/main/nfc/views/detect_reader.h @@ -0,0 +1,23 @@ +#pragma once +#include +#include +#include + +typedef struct DetectReader DetectReader; + +typedef void (*DetectReaderDoneCallback)(void* context); + +DetectReader* detect_reader_alloc(); + +void detect_reader_free(DetectReader* detect_reader); + +void detect_reader_reset(DetectReader* detect_reader); + +View* detect_reader_get_view(DetectReader* detect_reader); + +void detect_reader_set_callback( + DetectReader* detect_reader, + DetectReaderDoneCallback callback, + void* context); + +void detect_reader_inc_nonce_cnt(DetectReader* detect_reader); diff --git a/applications/nfc/views/dict_attack.c b/applications/main/nfc/views/dict_attack.c similarity index 100% rename from applications/nfc/views/dict_attack.c rename to applications/main/nfc/views/dict_attack.c diff --git a/applications/nfc/views/dict_attack.h b/applications/main/nfc/views/dict_attack.h similarity index 100% rename from applications/nfc/views/dict_attack.h rename to applications/main/nfc/views/dict_attack.h diff --git a/applications/subghz/application.fam b/applications/main/subghz/application.fam similarity index 100% rename from applications/subghz/application.fam rename to applications/main/subghz/application.fam diff --git a/applications/subghz/helpers/subghz_chat.c b/applications/main/subghz/helpers/subghz_chat.c similarity index 100% rename from applications/subghz/helpers/subghz_chat.c rename to applications/main/subghz/helpers/subghz_chat.c diff --git a/applications/subghz/helpers/subghz_chat.h b/applications/main/subghz/helpers/subghz_chat.h similarity index 100% rename from applications/subghz/helpers/subghz_chat.h rename to applications/main/subghz/helpers/subghz_chat.h diff --git a/applications/subghz/helpers/subghz_custom_event.h b/applications/main/subghz/helpers/subghz_custom_event.h similarity index 100% rename from applications/subghz/helpers/subghz_custom_event.h rename to applications/main/subghz/helpers/subghz_custom_event.h diff --git a/applications/subghz/helpers/subghz_frequency_analyzer_worker.c b/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c similarity index 100% rename from applications/subghz/helpers/subghz_frequency_analyzer_worker.c rename to applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c diff --git a/applications/subghz/helpers/subghz_frequency_analyzer_worker.h b/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.h similarity index 100% rename from applications/subghz/helpers/subghz_frequency_analyzer_worker.h rename to applications/main/subghz/helpers/subghz_frequency_analyzer_worker.h diff --git a/applications/subghz/helpers/subghz_testing.c b/applications/main/subghz/helpers/subghz_testing.c similarity index 100% rename from applications/subghz/helpers/subghz_testing.c rename to applications/main/subghz/helpers/subghz_testing.c diff --git a/applications/subghz/helpers/subghz_testing.h b/applications/main/subghz/helpers/subghz_testing.h similarity index 100% rename from applications/subghz/helpers/subghz_testing.h rename to applications/main/subghz/helpers/subghz_testing.h diff --git a/applications/subghz/helpers/subghz_types.h b/applications/main/subghz/helpers/subghz_types.h similarity index 98% rename from applications/subghz/helpers/subghz_types.h rename to applications/main/subghz/helpers/subghz_types.h index 8da4c8f53..7fe1e7ce7 100644 --- a/applications/subghz/helpers/subghz_types.h +++ b/applications/main/subghz/helpers/subghz_types.h @@ -47,7 +47,6 @@ typedef enum { SubGhzLoadKeyStateUnknown, SubGhzLoadKeyStateOK, SubGhzLoadKeyStateParseErr, - SubGhzLoadKeyStateOnlyRx, } SubGhzLoadKeyState; /** SubGhzLock */ diff --git a/applications/subghz/scenes/subghz_scene.c b/applications/main/subghz/scenes/subghz_scene.c similarity index 100% rename from applications/subghz/scenes/subghz_scene.c rename to applications/main/subghz/scenes/subghz_scene.c diff --git a/applications/subghz/scenes/subghz_scene.h b/applications/main/subghz/scenes/subghz_scene.h similarity index 100% rename from applications/subghz/scenes/subghz_scene.h rename to applications/main/subghz/scenes/subghz_scene.h diff --git a/applications/subghz/scenes/subghz_scene_config.h b/applications/main/subghz/scenes/subghz_scene_config.h similarity index 100% rename from applications/subghz/scenes/subghz_scene_config.h rename to applications/main/subghz/scenes/subghz_scene_config.h diff --git a/applications/subghz/scenes/subghz_scene_delete.c b/applications/main/subghz/scenes/subghz_scene_delete.c similarity index 100% rename from applications/subghz/scenes/subghz_scene_delete.c rename to applications/main/subghz/scenes/subghz_scene_delete.c diff --git a/applications/subghz/scenes/subghz_scene_delete_raw.c b/applications/main/subghz/scenes/subghz_scene_delete_raw.c similarity index 100% rename from applications/subghz/scenes/subghz_scene_delete_raw.c rename to applications/main/subghz/scenes/subghz_scene_delete_raw.c diff --git a/applications/subghz/scenes/subghz_scene_delete_success.c b/applications/main/subghz/scenes/subghz_scene_delete_success.c similarity index 100% rename from applications/subghz/scenes/subghz_scene_delete_success.c rename to applications/main/subghz/scenes/subghz_scene_delete_success.c diff --git a/applications/subghz/scenes/subghz_scene_frequency_analyzer.c b/applications/main/subghz/scenes/subghz_scene_frequency_analyzer.c similarity index 100% rename from applications/subghz/scenes/subghz_scene_frequency_analyzer.c rename to applications/main/subghz/scenes/subghz_scene_frequency_analyzer.c diff --git a/applications/subghz/scenes/subghz_scene_more_raw.c b/applications/main/subghz/scenes/subghz_scene_more_raw.c similarity index 100% rename from applications/subghz/scenes/subghz_scene_more_raw.c rename to applications/main/subghz/scenes/subghz_scene_more_raw.c diff --git a/applications/subghz/scenes/subghz_scene_need_saving.c b/applications/main/subghz/scenes/subghz_scene_need_saving.c similarity index 100% rename from applications/subghz/scenes/subghz_scene_need_saving.c rename to applications/main/subghz/scenes/subghz_scene_need_saving.c diff --git a/applications/subghz/scenes/subghz_scene_read_raw.c b/applications/main/subghz/scenes/subghz_scene_read_raw.c similarity index 100% rename from applications/subghz/scenes/subghz_scene_read_raw.c rename to applications/main/subghz/scenes/subghz_scene_read_raw.c diff --git a/applications/subghz/scenes/subghz_scene_receiver.c b/applications/main/subghz/scenes/subghz_scene_receiver.c similarity index 100% rename from applications/subghz/scenes/subghz_scene_receiver.c rename to applications/main/subghz/scenes/subghz_scene_receiver.c diff --git a/applications/subghz/scenes/subghz_scene_receiver_config.c b/applications/main/subghz/scenes/subghz_scene_receiver_config.c similarity index 100% rename from applications/subghz/scenes/subghz_scene_receiver_config.c rename to applications/main/subghz/scenes/subghz_scene_receiver_config.c diff --git a/applications/subghz/scenes/subghz_scene_receiver_info.c b/applications/main/subghz/scenes/subghz_scene_receiver_info.c similarity index 100% rename from applications/subghz/scenes/subghz_scene_receiver_info.c rename to applications/main/subghz/scenes/subghz_scene_receiver_info.c diff --git a/applications/subghz/scenes/subghz_scene_rpc.c b/applications/main/subghz/scenes/subghz_scene_rpc.c similarity index 100% rename from applications/subghz/scenes/subghz_scene_rpc.c rename to applications/main/subghz/scenes/subghz_scene_rpc.c diff --git a/applications/subghz/scenes/subghz_scene_save_name.c b/applications/main/subghz/scenes/subghz_scene_save_name.c similarity index 100% rename from applications/subghz/scenes/subghz_scene_save_name.c rename to applications/main/subghz/scenes/subghz_scene_save_name.c diff --git a/applications/subghz/scenes/subghz_scene_save_success.c b/applications/main/subghz/scenes/subghz_scene_save_success.c similarity index 100% rename from applications/subghz/scenes/subghz_scene_save_success.c rename to applications/main/subghz/scenes/subghz_scene_save_success.c diff --git a/applications/subghz/scenes/subghz_scene_saved.c b/applications/main/subghz/scenes/subghz_scene_saved.c similarity index 100% rename from applications/subghz/scenes/subghz_scene_saved.c rename to applications/main/subghz/scenes/subghz_scene_saved.c diff --git a/applications/subghz/scenes/subghz_scene_saved_menu.c b/applications/main/subghz/scenes/subghz_scene_saved_menu.c similarity index 100% rename from applications/subghz/scenes/subghz_scene_saved_menu.c rename to applications/main/subghz/scenes/subghz_scene_saved_menu.c diff --git a/applications/subghz/scenes/subghz_scene_set_type.c b/applications/main/subghz/scenes/subghz_scene_set_type.c similarity index 100% rename from applications/subghz/scenes/subghz_scene_set_type.c rename to applications/main/subghz/scenes/subghz_scene_set_type.c diff --git a/applications/subghz/scenes/subghz_scene_show_error.c b/applications/main/subghz/scenes/subghz_scene_show_error.c similarity index 100% rename from applications/subghz/scenes/subghz_scene_show_error.c rename to applications/main/subghz/scenes/subghz_scene_show_error.c diff --git a/applications/subghz/scenes/subghz_scene_show_error_sub.c b/applications/main/subghz/scenes/subghz_scene_show_error_sub.c similarity index 100% rename from applications/subghz/scenes/subghz_scene_show_error_sub.c rename to applications/main/subghz/scenes/subghz_scene_show_error_sub.c diff --git a/applications/subghz/scenes/subghz_scene_show_only_rx.c b/applications/main/subghz/scenes/subghz_scene_show_only_rx.c similarity index 100% rename from applications/subghz/scenes/subghz_scene_show_only_rx.c rename to applications/main/subghz/scenes/subghz_scene_show_only_rx.c diff --git a/applications/subghz/scenes/subghz_scene_start.c b/applications/main/subghz/scenes/subghz_scene_start.c similarity index 100% rename from applications/subghz/scenes/subghz_scene_start.c rename to applications/main/subghz/scenes/subghz_scene_start.c diff --git a/applications/subghz/scenes/subghz_scene_test.c b/applications/main/subghz/scenes/subghz_scene_test.c similarity index 100% rename from applications/subghz/scenes/subghz_scene_test.c rename to applications/main/subghz/scenes/subghz_scene_test.c diff --git a/applications/subghz/scenes/subghz_scene_test_carrier.c b/applications/main/subghz/scenes/subghz_scene_test_carrier.c similarity index 100% rename from applications/subghz/scenes/subghz_scene_test_carrier.c rename to applications/main/subghz/scenes/subghz_scene_test_carrier.c diff --git a/applications/subghz/scenes/subghz_scene_test_packet.c b/applications/main/subghz/scenes/subghz_scene_test_packet.c similarity index 100% rename from applications/subghz/scenes/subghz_scene_test_packet.c rename to applications/main/subghz/scenes/subghz_scene_test_packet.c diff --git a/applications/subghz/scenes/subghz_scene_test_static.c b/applications/main/subghz/scenes/subghz_scene_test_static.c similarity index 100% rename from applications/subghz/scenes/subghz_scene_test_static.c rename to applications/main/subghz/scenes/subghz_scene_test_static.c diff --git a/applications/subghz/scenes/subghz_scene_transmitter.c b/applications/main/subghz/scenes/subghz_scene_transmitter.c similarity index 100% rename from applications/subghz/scenes/subghz_scene_transmitter.c rename to applications/main/subghz/scenes/subghz_scene_transmitter.c diff --git a/applications/subghz/subghz.c b/applications/main/subghz/subghz.c similarity index 100% rename from applications/subghz/subghz.c rename to applications/main/subghz/subghz.c diff --git a/applications/subghz/subghz.h b/applications/main/subghz/subghz.h similarity index 100% rename from applications/subghz/subghz.h rename to applications/main/subghz/subghz.h diff --git a/applications/subghz/subghz_cli.c b/applications/main/subghz/subghz_cli.c similarity index 97% rename from applications/subghz/subghz_cli.c rename to applications/main/subghz/subghz_cli.c index 09dae0481..d921979f0 100644 --- a/applications/subghz/subghz_cli.c +++ b/applications/main/subghz/subghz_cli.c @@ -114,19 +114,21 @@ void subghz_cli_command_tx(Cli* cli, string_t args, void* context) { uint32_t frequency = 433920000; uint32_t key = 0x0074BADE; uint32_t repeat = 10; + uint32_t te = 403; if(string_size(args)) { - int ret = sscanf(string_get_cstr(args), "%lx %lu %lu", &key, &frequency, &repeat); - if(ret != 3) { + int ret = sscanf(string_get_cstr(args), "%lx %lu %lu %lu", &key, &frequency, &te, &repeat); + if(ret != 4) { printf( - "sscanf returned %d, key: %lx, frequency: %lu, repeat: %lu\r\n", + "sscanf returned %d, key: %lx, frequency: %lu, te:%lu, repeat: %lu\r\n", ret, key, frequency, + te, repeat); cli_print_usage( "subghz tx", - "<3 Byte Key: in hex> ", + "<3 Byte Key: in hex> ", string_get_cstr(args)); return; } @@ -139,9 +141,10 @@ void subghz_cli_command_tx(Cli* cli, string_t args, void* context) { } printf( - "Transmitting at %lu, key %lx, repeat %lu. Press CTRL+C to stop\r\n", + "Transmitting at %lu, key %lx, te %lu, repeat %lu. Press CTRL+C to stop\r\n", frequency, key, + te, repeat); string_t flipper_format_string; @@ -149,12 +152,13 @@ void subghz_cli_command_tx(Cli* cli, string_t args, void* context) { flipper_format_string, "Protocol: Princeton\n" "Bit: 24\n" - "Key: 00 00 00 00 00 %X %X %X\n" - "TE: 403\n" + "Key: 00 00 00 00 00 %02X %02X %02X\n" + "TE: %d\n" "Repeat: %d\n", (uint8_t)((key >> 16) & 0xFF), (uint8_t)((key >> 8) & 0xFF), (uint8_t)(key & 0xFF), + te, repeat); FlipperFormat* flipper_format = flipper_format_string_alloc(); Stream* stream = flipper_format_get_raw_stream(flipper_format); @@ -425,7 +429,7 @@ static void subghz_cli_command_print_usage() { printf("\tchat \t - Chat with other Flippers\r\n"); printf( - "\ttx <3 byte Key: in hex> \t - Transmitting key\r\n"); + "\ttx <3 byte Key: in hex> \t - Transmitting key\r\n"); printf("\trx \t - Reception key\r\n"); printf("\tdecode_raw \t - Testing\r\n"); @@ -858,5 +862,7 @@ void subghz_on_system_start() { furi_record_close(RECORD_STORAGE); #else UNUSED(subghz_cli_command); + UNUSED(subghz_on_system_start_istream_decode_band); + UNUSED(subghz_on_system_start_istream_read); #endif } diff --git a/applications/subghz/subghz_cli.h b/applications/main/subghz/subghz_cli.h similarity index 100% rename from applications/subghz/subghz_cli.h rename to applications/main/subghz/subghz_cli.h diff --git a/applications/subghz/subghz_history.c b/applications/main/subghz/subghz_history.c similarity index 100% rename from applications/subghz/subghz_history.c rename to applications/main/subghz/subghz_history.c diff --git a/applications/subghz/subghz_history.h b/applications/main/subghz/subghz_history.h similarity index 100% rename from applications/subghz/subghz_history.h rename to applications/main/subghz/subghz_history.h diff --git a/applications/subghz/subghz_i.c b/applications/main/subghz/subghz_i.c similarity index 96% rename from applications/subghz/subghz_i.c rename to applications/main/subghz/subghz_i.c index dc0d71e56..6ed8fd539 100644 --- a/applications/subghz/subghz_i.c +++ b/applications/main/subghz/subghz_i.c @@ -7,9 +7,9 @@ #include #include #include +#include #include #include -#include "../notification/notification.h" #include "views/receiver.h" #include @@ -278,11 +278,6 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) { break; } - if(!furi_hal_region_is_frequency_allowed(temp_data32)) { - FURI_LOG_E(TAG, "This frequency can only be used for RX in your region"); - load_key_state = SubGhzLoadKeyStateOnlyRx; - break; - } subghz->txrx->preset->frequency = temp_data32; if(!flipper_format_read_string(fff_data_file, "Preset", temp_str)) { @@ -354,12 +349,6 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) { } return false; - case SubGhzLoadKeyStateOnlyRx: - if(show_dialog) { - subghz_dialog_message_show_only_rx(subghz); - } - return false; - case SubGhzLoadKeyStateOK: return true; @@ -461,15 +450,12 @@ bool subghz_load_protocol_from_file(SubGhz* subghz) { string_t file_path; string_init(file_path); + DialogsFileBrowserOptions browser_options; + dialog_file_browser_set_basic_options(&browser_options, SUBGHZ_APP_EXTENSION, &I_sub1_10px); + // Input events and views are managed by file_select bool res = dialog_file_browser_show( - subghz->dialogs, - subghz->file_path, - subghz->file_path, - SUBGHZ_APP_EXTENSION, - true, - &I_sub1_10px, - true); + subghz->dialogs, subghz->file_path, subghz->file_path, &browser_options); if(res) { res = subghz_key_load(subghz, string_get_cstr(subghz->file_path), true); diff --git a/applications/subghz/subghz_i.h b/applications/main/subghz/subghz_i.h similarity index 100% rename from applications/subghz/subghz_i.h rename to applications/main/subghz/subghz_i.h diff --git a/applications/subghz/subghz_setting.c b/applications/main/subghz/subghz_setting.c similarity index 100% rename from applications/subghz/subghz_setting.c rename to applications/main/subghz/subghz_setting.c diff --git a/applications/subghz/subghz_setting.h b/applications/main/subghz/subghz_setting.h similarity index 100% rename from applications/subghz/subghz_setting.h rename to applications/main/subghz/subghz_setting.h diff --git a/applications/subghz/views/receiver.c b/applications/main/subghz/views/receiver.c similarity index 100% rename from applications/subghz/views/receiver.c rename to applications/main/subghz/views/receiver.c diff --git a/applications/subghz/views/receiver.h b/applications/main/subghz/views/receiver.h similarity index 100% rename from applications/subghz/views/receiver.h rename to applications/main/subghz/views/receiver.h diff --git a/applications/subghz/views/subghz_frequency_analyzer.c b/applications/main/subghz/views/subghz_frequency_analyzer.c similarity index 100% rename from applications/subghz/views/subghz_frequency_analyzer.c rename to applications/main/subghz/views/subghz_frequency_analyzer.c diff --git a/applications/subghz/views/subghz_frequency_analyzer.h b/applications/main/subghz/views/subghz_frequency_analyzer.h similarity index 100% rename from applications/subghz/views/subghz_frequency_analyzer.h rename to applications/main/subghz/views/subghz_frequency_analyzer.h diff --git a/applications/subghz/views/subghz_read_raw.c b/applications/main/subghz/views/subghz_read_raw.c similarity index 100% rename from applications/subghz/views/subghz_read_raw.c rename to applications/main/subghz/views/subghz_read_raw.c diff --git a/applications/subghz/views/subghz_read_raw.h b/applications/main/subghz/views/subghz_read_raw.h similarity index 100% rename from applications/subghz/views/subghz_read_raw.h rename to applications/main/subghz/views/subghz_read_raw.h diff --git a/applications/subghz/views/subghz_test_carrier.c b/applications/main/subghz/views/subghz_test_carrier.c similarity index 100% rename from applications/subghz/views/subghz_test_carrier.c rename to applications/main/subghz/views/subghz_test_carrier.c diff --git a/applications/subghz/views/subghz_test_carrier.h b/applications/main/subghz/views/subghz_test_carrier.h similarity index 100% rename from applications/subghz/views/subghz_test_carrier.h rename to applications/main/subghz/views/subghz_test_carrier.h diff --git a/applications/subghz/views/subghz_test_packet.c b/applications/main/subghz/views/subghz_test_packet.c similarity index 100% rename from applications/subghz/views/subghz_test_packet.c rename to applications/main/subghz/views/subghz_test_packet.c diff --git a/applications/subghz/views/subghz_test_packet.h b/applications/main/subghz/views/subghz_test_packet.h similarity index 100% rename from applications/subghz/views/subghz_test_packet.h rename to applications/main/subghz/views/subghz_test_packet.h diff --git a/applications/subghz/views/subghz_test_static.c b/applications/main/subghz/views/subghz_test_static.c similarity index 100% rename from applications/subghz/views/subghz_test_static.c rename to applications/main/subghz/views/subghz_test_static.c diff --git a/applications/subghz/views/subghz_test_static.h b/applications/main/subghz/views/subghz_test_static.h similarity index 100% rename from applications/subghz/views/subghz_test_static.h rename to applications/main/subghz/views/subghz_test_static.h diff --git a/applications/subghz/views/transmitter.c b/applications/main/subghz/views/transmitter.c similarity index 100% rename from applications/subghz/views/transmitter.c rename to applications/main/subghz/views/transmitter.c diff --git a/applications/subghz/views/transmitter.h b/applications/main/subghz/views/transmitter.h similarity index 100% rename from applications/subghz/views/transmitter.h rename to applications/main/subghz/views/transmitter.h diff --git a/applications/u2f/application.fam b/applications/main/u2f/application.fam similarity index 100% rename from applications/u2f/application.fam rename to applications/main/u2f/application.fam diff --git a/applications/u2f/scenes/u2f_scene.c b/applications/main/u2f/scenes/u2f_scene.c similarity index 100% rename from applications/u2f/scenes/u2f_scene.c rename to applications/main/u2f/scenes/u2f_scene.c diff --git a/applications/u2f/scenes/u2f_scene.h b/applications/main/u2f/scenes/u2f_scene.h similarity index 100% rename from applications/u2f/scenes/u2f_scene.h rename to applications/main/u2f/scenes/u2f_scene.h diff --git a/applications/u2f/scenes/u2f_scene_config.h b/applications/main/u2f/scenes/u2f_scene_config.h similarity index 100% rename from applications/u2f/scenes/u2f_scene_config.h rename to applications/main/u2f/scenes/u2f_scene_config.h diff --git a/applications/u2f/scenes/u2f_scene_error.c b/applications/main/u2f/scenes/u2f_scene_error.c similarity index 100% rename from applications/u2f/scenes/u2f_scene_error.c rename to applications/main/u2f/scenes/u2f_scene_error.c diff --git a/applications/u2f/scenes/u2f_scene_main.c b/applications/main/u2f/scenes/u2f_scene_main.c similarity index 100% rename from applications/u2f/scenes/u2f_scene_main.c rename to applications/main/u2f/scenes/u2f_scene_main.c diff --git a/applications/u2f/u2f.c b/applications/main/u2f/u2f.c similarity index 100% rename from applications/u2f/u2f.c rename to applications/main/u2f/u2f.c diff --git a/applications/u2f/u2f.h b/applications/main/u2f/u2f.h similarity index 100% rename from applications/u2f/u2f.h rename to applications/main/u2f/u2f.h diff --git a/applications/u2f/u2f_app.c b/applications/main/u2f/u2f_app.c similarity index 100% rename from applications/u2f/u2f_app.c rename to applications/main/u2f/u2f_app.c diff --git a/applications/u2f/u2f_app.h b/applications/main/u2f/u2f_app.h similarity index 100% rename from applications/u2f/u2f_app.h rename to applications/main/u2f/u2f_app.h diff --git a/applications/u2f/u2f_app_i.h b/applications/main/u2f/u2f_app_i.h similarity index 100% rename from applications/u2f/u2f_app_i.h rename to applications/main/u2f/u2f_app_i.h diff --git a/applications/u2f/u2f_data.c b/applications/main/u2f/u2f_data.c similarity index 100% rename from applications/u2f/u2f_data.c rename to applications/main/u2f/u2f_data.c diff --git a/applications/u2f/u2f_data.h b/applications/main/u2f/u2f_data.h similarity index 100% rename from applications/u2f/u2f_data.h rename to applications/main/u2f/u2f_data.h diff --git a/applications/u2f/u2f_hid.c b/applications/main/u2f/u2f_hid.c similarity index 100% rename from applications/u2f/u2f_hid.c rename to applications/main/u2f/u2f_hid.c diff --git a/applications/u2f/u2f_hid.h b/applications/main/u2f/u2f_hid.h similarity index 100% rename from applications/u2f/u2f_hid.h rename to applications/main/u2f/u2f_hid.h diff --git a/applications/u2f/views/u2f_view.c b/applications/main/u2f/views/u2f_view.c similarity index 100% rename from applications/u2f/views/u2f_view.c rename to applications/main/u2f/views/u2f_view.c diff --git a/applications/u2f/views/u2f_view.h b/applications/main/u2f/views/u2f_view.h similarity index 100% rename from applications/u2f/views/u2f_view.h rename to applications/main/u2f/views/u2f_view.h diff --git a/applications/meta/application.fam b/applications/meta/application.fam deleted file mode 100644 index a447b94ae..000000000 --- a/applications/meta/application.fam +++ /dev/null @@ -1,41 +0,0 @@ -App( - appid="basic_services", - name="Basic services", - apptype=FlipperAppType.METAPACKAGE, - provides=[ - "rpc", - "bt", - "desktop", - "loader", - "power", - ], -) - - -App( - appid="basic_apps", - name="Basic applications for main menu", - apptype=FlipperAppType.METAPACKAGE, - provides=[ - "gpio", - "ibutton", - "infrared", - "lfrfid", - "nfc", - "subghz", - "bad_usb", - "u2f", - ], -) - - -App( - appid="basic_plugins", - name="Basic applications for plug-in menu", - apptype=FlipperAppType.METAPACKAGE, - provides=[ - "music_player", - "snake_game", - "bt_hid", - ], -) diff --git a/applications/nfc/scenes/nfc_scene_detect_reader.c b/applications/nfc/scenes/nfc_scene_detect_reader.c deleted file mode 100644 index f734f04cb..000000000 --- a/applications/nfc/scenes/nfc_scene_detect_reader.c +++ /dev/null @@ -1,143 +0,0 @@ -#include "../nfc_i.h" -#include - -#define NFC_SCENE_DETECT_READER_LOG_SIZE_MAX (200) - -enum { - NfcSceneDetectReaderStateWidget, - NfcSceneDetectReaderStateTextBox, -}; - -bool nfc_detect_reader_worker_callback(NfcWorkerEvent event, void* context) { - UNUSED(event); - furi_assert(context); - Nfc* nfc = context; - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit); - return true; -} - -void nfc_scene_detect_reader_widget_callback(GuiButtonType result, InputType type, void* context) { - furi_assert(context); - Nfc* nfc = context; - if(type == InputTypeShort) { - view_dispatcher_send_custom_event(nfc->view_dispatcher, result); - } -} - -void nfc_detect_reader_textbox_callback(void* context) { - furi_assert(context); - Nfc* nfc = context; - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); -} - -// Add widget with device name or inform that data received -static void nfc_scene_detect_reader_widget_config(Nfc* nfc, bool data_received) { - Widget* widget = nfc->widget; - widget_reset(widget); - - widget_add_icon_element(widget, 0, 14, &I_Reader_detect); - widget_add_string_element( - widget, 64, 3, AlignCenter, AlignTop, FontSecondary, "Hold Near Reader"); - widget_add_string_element(widget, 55, 22, AlignLeft, AlignTop, FontPrimary, "Emulating..."); - - if(data_received) { - widget_add_button_element( - widget, GuiButtonTypeCenter, "Log", nfc_scene_detect_reader_widget_callback, nfc); - } -} - -void nfc_scene_detect_reader_on_enter(void* context) { - Nfc* nfc = context; - DOLPHIN_DEED(DolphinDeedNfcEmulate); - FuriHalNfcDevData nfc_params = { - .uid = {0x36, 0x9C, 0xe7, 0xb1, 0x0A, 0xC1, 0x34}, - .uid_len = 7, - .atqa = {0x44, 0x00}, - .sak = 0x08, - .type = FuriHalNfcTypeA, - }; - nfc->dev->dev_data.nfc_data = nfc_params; - - // Setup Widget - nfc_scene_detect_reader_widget_config(nfc, false); - // Setup TextBox - TextBox* text_box = nfc->text_box; - text_box_set_font(text_box, TextBoxFontHex); - text_box_set_focus(text_box, TextBoxFocusEnd); - string_reset(nfc->text_box_store); - - // Set Widget state and view - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneDetectReader, NfcSceneDetectReaderStateWidget); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); - // Start worker - memset(&nfc->dev->dev_data.reader_data, 0, sizeof(NfcReaderRequestData)); - nfc_worker_start( - nfc->worker, - NfcWorkerStateUidEmulate, - &nfc->dev->dev_data, - nfc_detect_reader_worker_callback, - nfc); - - nfc_blink_start(nfc); -} - -bool nfc_scene_detect_reader_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; - NfcReaderRequestData* reader_data = &nfc->dev->dev_data.reader_data; - uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneDetectReader); - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == NfcCustomEventWorkerExit) { - // Add data button to widget if data is received for the first time - if(!string_size(nfc->text_box_store)) { - nfc_scene_detect_reader_widget_config(nfc, true); - } - // Update TextBox data - if(string_size(nfc->text_box_store) < NFC_SCENE_DETECT_READER_LOG_SIZE_MAX) { - string_cat_printf(nfc->text_box_store, "R:"); - for(uint16_t i = 0; i < reader_data->size; i++) { - string_cat_printf(nfc->text_box_store, " %02X", reader_data->data[i]); - } - string_push_back(nfc->text_box_store, '\n'); - text_box_set_text(nfc->text_box, string_get_cstr(nfc->text_box_store)); - } - memset(reader_data, 0, sizeof(NfcReaderRequestData)); - consumed = true; - } else if(event.event == GuiButtonTypeCenter && state == NfcSceneDetectReaderStateWidget) { - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneDetectReader, NfcSceneDetectReaderStateTextBox); - consumed = true; - } else if(event.event == NfcCustomEventViewExit && state == NfcSceneDetectReaderStateTextBox) { - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneDetectReader, NfcSceneDetectReaderStateWidget); - consumed = true; - } - } else if(event.type == SceneManagerEventTypeBack) { - if(state == NfcSceneDetectReaderStateTextBox) { - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneDetectReader, NfcSceneDetectReaderStateWidget); - consumed = true; - } - } - - return consumed; -} - -void nfc_scene_detect_reader_on_exit(void* context) { - Nfc* nfc = context; - - // Stop worker - nfc_worker_stop(nfc->worker); - - // Clear view - widget_reset(nfc->widget); - text_box_reset(nfc->text_box); - string_reset(nfc->text_box_store); - - nfc_blink_stop(nfc); -} diff --git a/applications/picopass/application.fam b/applications/picopass/application.fam deleted file mode 100644 index ffc4b5182..000000000 --- a/applications/picopass/application.fam +++ /dev/null @@ -1,11 +0,0 @@ -App( - appid="picopass", - name="PicoPass Reader", - apptype=FlipperAppType.PLUGIN, - entry_point="picopass_app", - cdefines=["APP_PICOPASS"], - requires=["storage", "gui"], - stack_size=4 * 1024, - icon="A_Plugins_14", - order=30, -) diff --git a/applications/plugins/application.fam b/applications/plugins/application.fam new file mode 100644 index 000000000..c88f6d289 --- /dev/null +++ b/applications/plugins/application.fam @@ -0,0 +1,10 @@ +App( + appid="basic_plugins", + name="Basic applications for plug-in menu", + apptype=FlipperAppType.METAPACKAGE, + provides=[ + "music_player", + "snake_game", + "bt_hid", + ], +) diff --git a/applications/plugins/bt_hid_app/application.fam b/applications/plugins/bt_hid_app/application.fam new file mode 100644 index 000000000..e6a3b1752 --- /dev/null +++ b/applications/plugins/bt_hid_app/application.fam @@ -0,0 +1,15 @@ +App( + appid="bt_hid", + name="Bluetooth Remote", + apptype=FlipperAppType.PLUGIN, + entry_point="bt_hid_app", + stack_size=1 * 1024, + cdefines=["APP_BLE_HID"], + requires=[ + "bt", + "gui", + ], + order=10, + fap_icon="bt_remote_10px.png", + fap_category="Tools", +) diff --git a/applications/bt/bt_hid_app/bt_hid.c b/applications/plugins/bt_hid_app/bt_hid.c similarity index 99% rename from applications/bt/bt_hid_app/bt_hid.c rename to applications/plugins/bt_hid_app/bt_hid.c index 0827bd0ad..b653fb37d 100644 --- a/applications/bt/bt_hid_app/bt_hid.c +++ b/applications/plugins/bt_hid_app/bt_hid.c @@ -1,6 +1,6 @@ #include "bt_hid.h" #include -#include +#include #define TAG "BtHidApp" diff --git a/applications/bt/bt_hid_app/bt_hid.h b/applications/plugins/bt_hid_app/bt_hid.h similarity index 94% rename from applications/bt/bt_hid_app/bt_hid.h rename to applications/plugins/bt_hid_app/bt_hid.h index 81d092db4..0f4c7be9f 100644 --- a/applications/bt/bt_hid_app/bt_hid.h +++ b/applications/plugins/bt_hid_app/bt_hid.h @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include #include diff --git a/applications/plugins/bt_hid_app/bt_remote_10px.png b/applications/plugins/bt_hid_app/bt_remote_10px.png new file mode 100644 index 000000000..d4d30afe0 Binary files /dev/null and b/applications/plugins/bt_hid_app/bt_remote_10px.png differ diff --git a/applications/bt/bt_hid_app/views/bt_hid_keyboard.c b/applications/plugins/bt_hid_app/views/bt_hid_keyboard.c similarity index 99% rename from applications/bt/bt_hid_app/views/bt_hid_keyboard.c rename to applications/plugins/bt_hid_app/views/bt_hid_keyboard.c index 1088e2959..3617dc0f1 100644 --- a/applications/bt/bt_hid_app/views/bt_hid_keyboard.c +++ b/applications/plugins/bt_hid_app/views/bt_hid_keyboard.c @@ -109,7 +109,7 @@ const BtHidKeyboardKey bt_hid_keyboard_keyset[ROW_COUNT][COLUMN_COUNT] = { {.width = 1, .icon = NULL, .key = "-", .shift_key = "_", .value = HID_KEYBOARD_MINUS}, }, { - {.width = 1, .icon = &I_Pin_arrow_up7x9, .value = HID_KEYBOARD_L_SHIFT}, + {.width = 1, .icon = &I_Pin_arrow_up_7x9, .value = HID_KEYBOARD_L_SHIFT}, {.width = 1, .icon = NULL, .key = ",", .shift_key = "<", .value = HID_KEYPAD_COMMA}, {.width = 1, .icon = NULL, .key = ".", .shift_key = ">", .value = HID_KEYBOARD_DOT}, {.width = 4, .icon = NULL, .key = " ", .value = HID_KEYBOARD_SPACEBAR}, diff --git a/applications/bt/bt_hid_app/views/bt_hid_keyboard.h b/applications/plugins/bt_hid_app/views/bt_hid_keyboard.h similarity index 100% rename from applications/bt/bt_hid_app/views/bt_hid_keyboard.h rename to applications/plugins/bt_hid_app/views/bt_hid_keyboard.h diff --git a/applications/bt/bt_hid_app/views/bt_hid_keynote.c b/applications/plugins/bt_hid_app/views/bt_hid_keynote.c old mode 100755 new mode 100644 similarity index 100% rename from applications/bt/bt_hid_app/views/bt_hid_keynote.c rename to applications/plugins/bt_hid_app/views/bt_hid_keynote.c diff --git a/applications/bt/bt_hid_app/views/bt_hid_keynote.h b/applications/plugins/bt_hid_app/views/bt_hid_keynote.h similarity index 100% rename from applications/bt/bt_hid_app/views/bt_hid_keynote.h rename to applications/plugins/bt_hid_app/views/bt_hid_keynote.h diff --git a/applications/bt/bt_hid_app/views/bt_hid_media.c b/applications/plugins/bt_hid_app/views/bt_hid_media.c old mode 100755 new mode 100644 similarity index 100% rename from applications/bt/bt_hid_app/views/bt_hid_media.c rename to applications/plugins/bt_hid_app/views/bt_hid_media.c diff --git a/applications/bt/bt_hid_app/views/bt_hid_media.h b/applications/plugins/bt_hid_app/views/bt_hid_media.h similarity index 100% rename from applications/bt/bt_hid_app/views/bt_hid_media.h rename to applications/plugins/bt_hid_app/views/bt_hid_media.h diff --git a/applications/bt/bt_hid_app/views/bt_hid_mouse.c b/applications/plugins/bt_hid_app/views/bt_hid_mouse.c similarity index 99% rename from applications/bt/bt_hid_app/views/bt_hid_mouse.c rename to applications/plugins/bt_hid_app/views/bt_hid_mouse.c index f9d84f9fb..395cb52c9 100644 --- a/applications/bt/bt_hid_app/views/bt_hid_mouse.c +++ b/applications/plugins/bt_hid_app/views/bt_hid_mouse.c @@ -53,7 +53,7 @@ static void bt_hid_mouse_draw_callback(Canvas* canvas, void* context) { canvas_set_bitmap_mode(canvas, 0); canvas_set_color(canvas, ColorWhite); } - canvas_draw_icon(canvas, 84, 10, &I_Pin_arrow_up7x9); + canvas_draw_icon(canvas, 84, 10, &I_Pin_arrow_up_7x9); canvas_set_color(canvas, ColorBlack); // Down diff --git a/applications/bt/bt_hid_app/views/bt_hid_mouse.h b/applications/plugins/bt_hid_app/views/bt_hid_mouse.h similarity index 100% rename from applications/bt/bt_hid_app/views/bt_hid_mouse.h rename to applications/plugins/bt_hid_app/views/bt_hid_mouse.h diff --git a/applications/music_player/application.fam b/applications/plugins/music_player/application.fam similarity index 84% rename from applications/music_player/application.fam rename to applications/plugins/music_player/application.fam index 70e297432..76787e097 100644 --- a/applications/music_player/application.fam +++ b/applications/plugins/music_player/application.fam @@ -11,6 +11,8 @@ App( provides=["music_player_start"], stack_size=2 * 1024, order=20, + fap_icon="../../../assets/icons/Archive/music_10px.png", + fap_category="Misc", ) App( diff --git a/applications/music_player/music_player.c b/applications/plugins/music_player/music_player.c similarity index 96% rename from applications/music_player/music_player.c rename to applications/plugins/music_player/music_player.c index 121efa0f9..40e9085fb 100644 --- a/applications/music_player/music_player.c +++ b/applications/plugins/music_player/music_player.c @@ -305,15 +305,13 @@ int32_t music_player_app(void* p) { } else { string_set_str(file_path, MUSIC_PLAYER_APP_PATH_FOLDER); + DialogsFileBrowserOptions browser_options; + dialog_file_browser_set_basic_options( + &browser_options, MUSIC_PLAYER_APP_EXTENSION, &I_music_10px); + browser_options.hide_ext = false; + DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS); - bool res = dialog_file_browser_show( - dialogs, - file_path, - file_path, - MUSIC_PLAYER_APP_EXTENSION, - true, - &I_music_10px, - false); + bool res = dialog_file_browser_show(dialogs, file_path, file_path, &browser_options); furi_record_close(RECORD_DIALOGS); if(!res) { diff --git a/applications/music_player/music_player_cli.c b/applications/plugins/music_player/music_player_cli.c similarity index 100% rename from applications/music_player/music_player_cli.c rename to applications/plugins/music_player/music_player_cli.c diff --git a/applications/music_player/music_player_worker.c b/applications/plugins/music_player/music_player_worker.c similarity index 100% rename from applications/music_player/music_player_worker.c rename to applications/plugins/music_player/music_player_worker.c diff --git a/applications/music_player/music_player_worker.h b/applications/plugins/music_player/music_player_worker.h similarity index 100% rename from applications/music_player/music_player_worker.h rename to applications/plugins/music_player/music_player_worker.h diff --git a/applications/plugins/picopass/application.fam b/applications/plugins/picopass/application.fam new file mode 100644 index 000000000..7a81e0804 --- /dev/null +++ b/applications/plugins/picopass/application.fam @@ -0,0 +1,17 @@ +App( + appid="picopass", + name="PicoPass Reader", + apptype=FlipperAppType.EXTERNAL, + entry_point="picopass_app", + requires=[ + "storage", + "gui", + ], + stack_size=4 * 1024, + order=30, + fap_icon="../../../assets/icons/Archive/125_10px.png", + fap_libs=[ + "mbedtls", + ], + fap_category="Tools", +) diff --git a/lib/loclass/optimized_cipher.c b/applications/plugins/picopass/loclass/optimized_cipher.c similarity index 73% rename from lib/loclass/optimized_cipher.c rename to applications/plugins/picopass/loclass/optimized_cipher.c index e4f6a58c3..eba95538f 100644 --- a/lib/loclass/optimized_cipher.c +++ b/applications/plugins/picopass/loclass/optimized_cipher.c @@ -82,23 +82,17 @@ #include "optimized_cipherutils.h" static const uint8_t loclass_opt_select_LUT[256] = { - 00, 03, 02, 01, 02, 03, 00, 01, 04, 07, 07, 04, 06, 07, 05, 04, - 01, 02, 03, 00, 02, 03, 00, 01, 05, 06, 06, 05, 06, 07, 05, 04, - 06, 05, 04, 07, 04, 05, 06, 07, 06, 05, 05, 06, 04, 05, 07, 06, - 07, 04, 05, 06, 04, 05, 06, 07, 07, 04, 04, 07, 04, 05, 07, 06, - 06, 05, 04, 07, 04, 05, 06, 07, 02, 01, 01, 02, 00, 01, 03, 02, - 03, 00, 01, 02, 00, 01, 02, 03, 07, 04, 04, 07, 04, 05, 07, 06, - 00, 03, 02, 01, 02, 03, 00, 01, 00, 03, 03, 00, 02, 03, 01, 00, - 05, 06, 07, 04, 06, 07, 04, 05, 05, 06, 06, 05, 06, 07, 05, 04, - 02, 01, 00, 03, 00, 01, 02, 03, 06, 05, 05, 06, 04, 05, 07, 06, - 03, 00, 01, 02, 00, 01, 02, 03, 07, 04, 04, 07, 04, 05, 07, 06, - 02, 01, 00, 03, 00, 01, 02, 03, 02, 01, 01, 02, 00, 01, 03, 02, - 03, 00, 01, 02, 00, 01, 02, 03, 03, 00, 00, 03, 00, 01, 03, 02, - 04, 07, 06, 05, 06, 07, 04, 05, 00, 03, 03, 00, 02, 03, 01, 00, - 01, 02, 03, 00, 02, 03, 00, 01, 05, 06, 06, 05, 06, 07, 05, 04, - 04, 07, 06, 05, 06, 07, 04, 05, 04, 07, 07, 04, 06, 07, 05, 04, - 01, 02, 03, 00, 02, 03, 00, 01, 01, 02, 02, 01, 02, 03, 01, 00 -}; + 00, 03, 02, 01, 02, 03, 00, 01, 04, 07, 07, 04, 06, 07, 05, 04, 01, 02, 03, 00, 02, 03, 00, 01, + 05, 06, 06, 05, 06, 07, 05, 04, 06, 05, 04, 07, 04, 05, 06, 07, 06, 05, 05, 06, 04, 05, 07, 06, + 07, 04, 05, 06, 04, 05, 06, 07, 07, 04, 04, 07, 04, 05, 07, 06, 06, 05, 04, 07, 04, 05, 06, 07, + 02, 01, 01, 02, 00, 01, 03, 02, 03, 00, 01, 02, 00, 01, 02, 03, 07, 04, 04, 07, 04, 05, 07, 06, + 00, 03, 02, 01, 02, 03, 00, 01, 00, 03, 03, 00, 02, 03, 01, 00, 05, 06, 07, 04, 06, 07, 04, 05, + 05, 06, 06, 05, 06, 07, 05, 04, 02, 01, 00, 03, 00, 01, 02, 03, 06, 05, 05, 06, 04, 05, 07, 06, + 03, 00, 01, 02, 00, 01, 02, 03, 07, 04, 04, 07, 04, 05, 07, 06, 02, 01, 00, 03, 00, 01, 02, 03, + 02, 01, 01, 02, 00, 01, 03, 02, 03, 00, 01, 02, 00, 01, 02, 03, 03, 00, 00, 03, 00, 01, 03, 02, + 04, 07, 06, 05, 06, 07, 04, 05, 00, 03, 03, 00, 02, 03, 01, 00, 01, 02, 03, 00, 02, 03, 00, 01, + 05, 06, 06, 05, 06, 07, 05, 04, 04, 07, 06, 05, 06, 07, 04, 05, 04, 07, 07, 04, 06, 07, 05, 04, + 01, 02, 03, 00, 02, 03, 00, 01, 01, 02, 02, 01, 02, 03, 01, 00}; /********************** the table above has been generated with this code: ******** #include "util.h" @@ -116,12 +110,12 @@ static void init_opt_select_LUT(void) { } ***********************************************************************************/ -#define loclass_opt__select(x,y,r) (4 & (((r & (r << 2)) >> 5) ^ ((r & ~(r << 2)) >> 4) ^ ( (r | r << 2) >> 3)))\ - |(2 & (((r | r << 2) >> 6) ^ ( (r | r << 2) >> 1) ^ (r >> 5) ^ r ^ ((x^y) << 1)))\ - |(1 & (((r & ~(r << 2)) >> 4) ^ ((r & (r << 2)) >> 3) ^ r ^ x)) +#define loclass_opt__select(x, y, r) \ + (4 & (((r & (r << 2)) >> 5) ^ ((r & ~(r << 2)) >> 4) ^ ((r | r << 2) >> 3))) | \ + (2 & (((r | r << 2) >> 6) ^ ((r | r << 2) >> 1) ^ (r >> 5) ^ r ^ ((x ^ y) << 1))) | \ + (1 & (((r & ~(r << 2)) >> 4) ^ ((r & (r << 2)) >> 3) ^ r ^ x)) - -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; Tt = Tt ^ (Tt >> 1); Tt = Tt ^ (Tt >> 4); @@ -144,12 +138,17 @@ static void loclass_opt_successor(const uint8_t *k, LoclassState_t *s, uint8_t y opt_select |= (loclass_opt_select_LUT[s->r] ^ Tt) & 0x01; uint8_t r = s->r; - s->r = (k[opt_select] ^ s->b) + s->l ; + s->r = (k[opt_select] ^ s->b) + s->l; s->l = s->r + r; } -static void loclass_opt_suc(const uint8_t *k, LoclassState_t *s, const uint8_t *in, uint8_t length, bool add32Zeroes) { - for (int i = 0; i < length; i++) { +static void loclass_opt_suc( + const uint8_t* k, + LoclassState_t* s, + const uint8_t* in, + uint8_t length, + bool add32Zeroes) { + for(int i = 0; i < length; i++) { uint8_t head; head = in[i]; loclass_opt_successor(k, s, head); @@ -176,16 +175,16 @@ static void loclass_opt_suc(const uint8_t *k, LoclassState_t *s, const uint8_t * loclass_opt_successor(k, s, head); } //For tag MAC, an additional 32 zeroes - if (add32Zeroes) { - for (int i = 0; i < 16; i++) { + if(add32Zeroes) { + for(int i = 0; i < 16; i++) { loclass_opt_successor(k, s, 0); loclass_opt_successor(k, s, 0); } } } -static void loclass_opt_output(const uint8_t *k, LoclassState_t *s, uint8_t *buffer) { - for (uint8_t times = 0; times < 4; times++) { +static void loclass_opt_output(const uint8_t* k, LoclassState_t* s, uint8_t* buffer) { + for(uint8_t times = 0; times < 4; times++) { uint8_t bout = 0; bout |= (s->r & 0x4) >> 2; loclass_opt_successor(k, s, 0); @@ -207,10 +206,10 @@ static void loclass_opt_output(const uint8_t *k, LoclassState_t *s, uint8_t *bu } } -static void loclass_opt_MAC(uint8_t *k, uint8_t *input, uint8_t *out) { - LoclassState_t _init = { - ((k[0] ^ 0x4c) + 0xEC) & 0xFF,// l - ((k[0] ^ 0x4c) + 0x21) & 0xFF,// r +static void loclass_opt_MAC(uint8_t* k, uint8_t* input, uint8_t* out) { + LoclassState_t _init = { + ((k[0] ^ 0x4c) + 0xEC) & 0xFF, // l + ((k[0] ^ 0x4c) + 0x21) & 0xFF, // r 0x4c, // b 0xE012 // t }; @@ -219,10 +218,10 @@ static void loclass_opt_MAC(uint8_t *k, uint8_t *input, uint8_t *out) { loclass_opt_output(k, &_init, out); } -static void loclass_opt_MAC_N(uint8_t *k, uint8_t *input, uint8_t in_size, uint8_t *out) { - LoclassState_t _init = { - ((k[0] ^ 0x4c) + 0xEC) & 0xFF,// l - ((k[0] ^ 0x4c) + 0x21) & 0xFF,// r +static void loclass_opt_MAC_N(uint8_t* k, uint8_t* input, uint8_t in_size, uint8_t* out) { + LoclassState_t _init = { + ((k[0] ^ 0x4c) + 0xEC) & 0xFF, // l + ((k[0] ^ 0x4c) + 0x21) & 0xFF, // r 0x4c, // b 0xE012 // t }; @@ -231,28 +230,31 @@ static void loclass_opt_MAC_N(uint8_t *k, uint8_t *input, uint8_t in_size, uint8 loclass_opt_output(k, &_init, out); } -void loclass_opt_doReaderMAC(uint8_t *cc_nr_p, uint8_t *div_key_p, uint8_t mac[4]) { - uint8_t dest [] = {0, 0, 0, 0, 0, 0, 0, 0}; +void loclass_opt_doReaderMAC(uint8_t* cc_nr_p, uint8_t* div_key_p, uint8_t mac[4]) { + uint8_t dest[] = {0, 0, 0, 0, 0, 0, 0, 0}; loclass_opt_MAC(div_key_p, cc_nr_p, dest); memcpy(mac, dest, 4); } -void loclass_opt_doReaderMAC_2(LoclassState_t _init, uint8_t *nr, uint8_t mac[4], const uint8_t *div_key_p) { +void loclass_opt_doReaderMAC_2( + LoclassState_t _init, + uint8_t* nr, + uint8_t mac[4], + const uint8_t* div_key_p) { loclass_opt_suc(div_key_p, &_init, nr, 4, false); loclass_opt_output(div_key_p, &_init, mac); } - -void loclass_doMAC_N(uint8_t *in_p, uint8_t in_size, uint8_t *div_key_p, uint8_t mac[4]) { - uint8_t dest [] = {0, 0, 0, 0, 0, 0, 0, 0}; +void loclass_doMAC_N(uint8_t* in_p, uint8_t in_size, uint8_t* div_key_p, uint8_t mac[4]) { + uint8_t dest[] = {0, 0, 0, 0, 0, 0, 0, 0}; loclass_opt_MAC_N(div_key_p, in_p, in_size, dest); memcpy(mac, dest, 4); } -void loclass_opt_doTagMAC(uint8_t *cc_p, const uint8_t *div_key_p, uint8_t mac[4]) { - LoclassState_t _init = { - ((div_key_p[0] ^ 0x4c) + 0xEC) & 0xFF,// l - ((div_key_p[0] ^ 0x4c) + 0x21) & 0xFF,// r +void loclass_opt_doTagMAC(uint8_t* cc_p, const uint8_t* div_key_p, uint8_t mac[4]) { + LoclassState_t _init = { + ((div_key_p[0] ^ 0x4c) + 0xEC) & 0xFF, // l + ((div_key_p[0] ^ 0x4c) + 0x21) & 0xFF, // r 0x4c, // b 0xE012 // t }; @@ -268,10 +270,10 @@ void loclass_opt_doTagMAC(uint8_t *cc_p, const uint8_t *div_key_p, uint8_t mac[4 * @param div_key_p * @return the cipher state */ -LoclassState_t loclass_opt_doTagMAC_1(uint8_t *cc_p, const uint8_t *div_key_p) { - LoclassState_t _init = { - ((div_key_p[0] ^ 0x4c) + 0xEC) & 0xFF,// l - ((div_key_p[0] ^ 0x4c) + 0x21) & 0xFF,// r +LoclassState_t loclass_opt_doTagMAC_1(uint8_t* cc_p, const uint8_t* div_key_p) { + LoclassState_t _init = { + ((div_key_p[0] ^ 0x4c) + 0xEC) & 0xFF, // l + ((div_key_p[0] ^ 0x4c) + 0x21) & 0xFF, // r 0x4c, // b 0xE012 // t }; @@ -288,21 +290,24 @@ LoclassState_t loclass_opt_doTagMAC_1(uint8_t *cc_p, const uint8_t *div_key_p) { * @param mac - where to store the MAC * @param div_key_p - the key to use */ -void loclass_opt_doTagMAC_2(LoclassState_t _init, uint8_t *nr, uint8_t mac[4], const uint8_t *div_key_p) { +void loclass_opt_doTagMAC_2( + LoclassState_t _init, + uint8_t* nr, + uint8_t mac[4], + const uint8_t* div_key_p) { loclass_opt_suc(div_key_p, &_init, nr, 4, true); loclass_opt_output(div_key_p, &_init, mac); } -void loclass_iclass_calc_div_key(uint8_t *csn, uint8_t *key, uint8_t *div_key, bool elite) { - if (elite) { +void loclass_iclass_calc_div_key(uint8_t* csn, uint8_t* key, uint8_t* div_key, bool elite) { + if(elite) { uint8_t keytable[128] = {0}; uint8_t key_index[8] = {0}; - uint8_t key_sel[8] = { 0 }; - uint8_t key_sel_p[8] = { 0 }; + uint8_t key_sel[8] = {0}; + uint8_t key_sel_p[8] = {0}; loclass_hash2(key, keytable); loclass_hash1(csn, key_index); - for (uint8_t i = 0; i < 8 ; i++) - key_sel[i] = keytable[key_index[i]]; + for(uint8_t i = 0; i < 8; i++) key_sel[i] = keytable[key_index[i]]; //Permute from iclass format to standard format loclass_permutekey_rev(key_sel, key_sel_p); diff --git a/lib/loclass/optimized_cipher.h b/applications/plugins/picopass/loclass/optimized_cipher.h similarity index 84% rename from lib/loclass/optimized_cipher.h rename to applications/plugins/picopass/loclass/optimized_cipher.h index e7b8cbd67..2158f0acf 100644 --- a/lib/loclass/optimized_cipher.h +++ b/applications/plugins/picopass/loclass/optimized_cipher.h @@ -56,14 +56,18 @@ typedef struct { /** The reader MAC is MAC(key, CC * NR ) **/ -void loclass_opt_doReaderMAC(uint8_t *cc_nr_p, uint8_t *div_key_p, uint8_t mac[4]); +void loclass_opt_doReaderMAC(uint8_t* cc_nr_p, uint8_t* div_key_p, uint8_t mac[4]); -void loclass_opt_doReaderMAC_2(LoclassState_t _init, uint8_t *nr, uint8_t mac[4], const uint8_t *div_key_p); +void loclass_opt_doReaderMAC_2( + LoclassState_t _init, + uint8_t* nr, + uint8_t mac[4], + const uint8_t* div_key_p); /** * The tag MAC is MAC(key, CC * NR * 32x0)) */ -void loclass_opt_doTagMAC(uint8_t *cc_p, const uint8_t *div_key_p, uint8_t mac[4]); +void loclass_opt_doTagMAC(uint8_t* cc_p, const uint8_t* div_key_p, uint8_t mac[4]); /** * The tag MAC can be divided (both can, but no point in dividing the reader mac) into @@ -73,7 +77,7 @@ void loclass_opt_doTagMAC(uint8_t *cc_p, const uint8_t *div_key_p, uint8_t mac[4 * @param div_key_p * @return the cipher state */ -LoclassState_t loclass_opt_doTagMAC_1(uint8_t *cc_p, const uint8_t *div_key_p); +LoclassState_t loclass_opt_doTagMAC_1(uint8_t* cc_p, const uint8_t* div_key_p); /** * The second part of the tag MAC calculation, since the CC is already calculated into the state, * this function is fed only the NR, and internally feeds the remaining 32 0-bits to generate the tag @@ -83,8 +87,12 @@ LoclassState_t loclass_opt_doTagMAC_1(uint8_t *cc_p, const uint8_t *div_key_p); * @param mac - where to store the MAC * @param div_key_p - the key to use */ -void loclass_opt_doTagMAC_2(LoclassState_t _init, uint8_t *nr, uint8_t mac[4], const uint8_t *div_key_p); +void loclass_opt_doTagMAC_2( + LoclassState_t _init, + uint8_t* nr, + uint8_t mac[4], + const uint8_t* div_key_p); -void loclass_doMAC_N(uint8_t *in_p, uint8_t in_size, uint8_t *div_key_p, uint8_t mac[4]); -void loclass_iclass_calc_div_key(uint8_t *csn, uint8_t *key, uint8_t *div_key, bool elite); +void loclass_doMAC_N(uint8_t* in_p, uint8_t in_size, uint8_t* div_key_p, uint8_t mac[4]); +void loclass_iclass_calc_div_key(uint8_t* csn, uint8_t* key, uint8_t* div_key, bool elite); #endif // OPTIMIZED_CIPHER_H diff --git a/lib/loclass/optimized_cipherutils.c b/applications/plugins/picopass/loclass/optimized_cipherutils.c similarity index 84% rename from lib/loclass/optimized_cipherutils.c rename to applications/plugins/picopass/loclass/optimized_cipherutils.c index c5bcbaccd..e6a87c4a7 100644 --- a/lib/loclass/optimized_cipherutils.c +++ b/applications/plugins/picopass/loclass/optimized_cipherutils.c @@ -40,7 +40,7 @@ * @param stream * @return */ -bool loclass_headBit(LoclassBitstreamIn_t *stream) { +bool loclass_headBit(LoclassBitstreamIn_t* stream) { int bytepos = stream->position >> 3; // divide by 8 int bitpos = (stream->position++) & 7; // mask out 00000111 return (*(stream->buffer + bytepos) >> (7 - bitpos)) & 1; @@ -50,7 +50,7 @@ bool loclass_headBit(LoclassBitstreamIn_t *stream) { * @param stream * @return */ -bool loclass_tailBit(LoclassBitstreamIn_t *stream) { +bool loclass_tailBit(LoclassBitstreamIn_t* stream) { int bitpos = stream->numbits - 1 - (stream->position++); int bytepos = bitpos >> 3; @@ -62,7 +62,7 @@ bool loclass_tailBit(LoclassBitstreamIn_t *stream) { * @param stream * @param bit */ -void loclass_pushBit(LoclassBitstreamOut_t *stream, bool bit) { +void loclass_pushBit(LoclassBitstreamOut_t* stream, bool bit) { int bytepos = stream->position >> 3; // divide by 8 int bitpos = stream->position & 7; *(stream->buffer + bytepos) |= (bit) << (7 - bitpos); @@ -76,7 +76,7 @@ void loclass_pushBit(LoclassBitstreamOut_t *stream, bool bit) { * @param stream * @param bits */ -void loclass_push6bits(LoclassBitstreamOut_t *stream, uint8_t bits) { +void loclass_push6bits(LoclassBitstreamOut_t* stream, uint8_t bits) { loclass_pushBit(stream, bits & 0x20); loclass_pushBit(stream, bits & 0x10); loclass_pushBit(stream, bits & 0x08); @@ -90,7 +90,7 @@ void loclass_push6bits(LoclassBitstreamOut_t *stream, uint8_t bits) { * @param stream * @return number of bits left in stream */ -int loclass_bitsLeft(LoclassBitstreamIn_t *stream) { +int loclass_bitsLeft(LoclassBitstreamIn_t* stream) { return stream->numbits - stream->position; } /** @@ -98,16 +98,16 @@ int loclass_bitsLeft(LoclassBitstreamIn_t *stream) { * @param stream * @return Number of bits stored in stream */ -void loclass_x_num_to_bytes(uint64_t n, size_t len, uint8_t *dest) { - while (len--) { - dest[len] = (uint8_t) n; +void loclass_x_num_to_bytes(uint64_t n, size_t len, uint8_t* dest) { + while(len--) { + dest[len] = (uint8_t)n; n >>= 8; } } -uint64_t loclass_x_bytes_to_num(uint8_t *src, size_t len) { +uint64_t loclass_x_bytes_to_num(uint8_t* src, size_t len) { uint64_t num = 0; - while (len--) { + while(len--) { num = (num << 8) | (*src); src++; } @@ -121,17 +121,16 @@ uint8_t loclass_reversebytes(uint8_t b) { return b; } -void loclass_reverse_arraybytes(uint8_t *arr, size_t len) { +void loclass_reverse_arraybytes(uint8_t* arr, size_t len) { uint8_t i; - for (i = 0; i < len ; i++) { + for(i = 0; i < len; i++) { arr[i] = loclass_reversebytes(arr[i]); } } -void loclass_reverse_arraycopy(uint8_t *arr, uint8_t *dest, size_t len) { +void loclass_reverse_arraycopy(uint8_t* arr, uint8_t* dest, size_t len) { uint8_t i; - for (i = 0; i < len ; i++) { + for(i = 0; i < len; i++) { dest[i] = loclass_reversebytes(arr[i]); } } - diff --git a/lib/loclass/optimized_cipherutils.h b/applications/plugins/picopass/loclass/optimized_cipherutils.h similarity index 78% rename from lib/loclass/optimized_cipherutils.h rename to applications/plugins/picopass/loclass/optimized_cipherutils.h index cb9d2724a..05b682079 100644 --- a/lib/loclass/optimized_cipherutils.h +++ b/applications/plugins/picopass/loclass/optimized_cipherutils.h @@ -39,26 +39,26 @@ #include typedef struct { - uint8_t *buffer; + uint8_t* buffer; uint8_t numbits; uint8_t position; } LoclassBitstreamIn_t; typedef struct { - uint8_t *buffer; + uint8_t* buffer; uint8_t numbits; uint8_t position; } LoclassBitstreamOut_t; -bool loclass_headBit(LoclassBitstreamIn_t *stream); -bool loclass_tailBit(LoclassBitstreamIn_t *stream); -void loclass_pushBit(LoclassBitstreamOut_t *stream, bool bit); -int loclass_bitsLeft(LoclassBitstreamIn_t *stream); +bool loclass_headBit(LoclassBitstreamIn_t* stream); +bool loclass_tailBit(LoclassBitstreamIn_t* stream); +void loclass_pushBit(LoclassBitstreamOut_t* stream, bool bit); +int loclass_bitsLeft(LoclassBitstreamIn_t* stream); -void loclass_push6bits(LoclassBitstreamOut_t *stream, uint8_t bits); -void loclass_x_num_to_bytes(uint64_t n, size_t len, uint8_t *dest); -uint64_t loclass_x_bytes_to_num(uint8_t *src, size_t len); +void loclass_push6bits(LoclassBitstreamOut_t* stream, uint8_t bits); +void loclass_x_num_to_bytes(uint64_t n, size_t len, uint8_t* dest); +uint64_t loclass_x_bytes_to_num(uint8_t* src, size_t len); uint8_t loclass_reversebytes(uint8_t b); -void loclass_reverse_arraybytes(uint8_t *arr, size_t len); -void loclass_reverse_arraycopy(uint8_t *arr, uint8_t *dest, size_t len); +void loclass_reverse_arraybytes(uint8_t* arr, size_t len); +void loclass_reverse_arraycopy(uint8_t* arr, uint8_t* dest, size_t len); #endif // CIPHERUTILS_H diff --git a/lib/loclass/optimized_elite.c b/applications/plugins/picopass/loclass/optimized_elite.c similarity index 92% rename from lib/loclass/optimized_elite.c rename to applications/plugins/picopass/loclass/optimized_elite.c index fc1e5d748..c175f3986 100644 --- a/lib/loclass/optimized_elite.c +++ b/applications/plugins/picopass/loclass/optimized_elite.c @@ -62,7 +62,7 @@ */ void loclass_permutekey(const uint8_t key[8], uint8_t dest[8]) { int i; - for (i = 0 ; i < 8 ; i++) { + for(i = 0; i < 8; i++) { dest[i] = (((key[7] & (0x80 >> i)) >> (7 - i)) << 7) | (((key[6] & (0x80 >> i)) >> (7 - i)) << 6) | (((key[5] & (0x80 >> i)) >> (7 - i)) << 5) | @@ -81,7 +81,7 @@ void loclass_permutekey(const uint8_t key[8], uint8_t dest[8]) { */ void loclass_permutekey_rev(const uint8_t key[8], uint8_t dest[8]) { int i; - for (i = 0 ; i < 8 ; i++) { + for(i = 0; i < 8; i++) { dest[7 - i] = (((key[0] & (0x80 >> i)) >> (7 - i)) << 7) | (((key[1] & (0x80 >> i)) >> (7 - i)) << 6) | (((key[2] & (0x80 >> i)) >> (7 - i)) << 5) | @@ -153,12 +153,11 @@ Definition 14. Define the rotate key function loclass_rk : (F 82 ) 8 × N → (F loclass_rk(x [0] . . . x [7] , 0) = x [0] . . . x [7] loclass_rk(x [0] . . . x [7] , n + 1) = loclass_rk(loclass_rl(x [0] ) . . . loclass_rl(x [7] ), n) **/ -static void loclass_rk(uint8_t *key, uint8_t n, uint8_t *outp_key) { +static void loclass_rk(uint8_t* key, uint8_t n, uint8_t* outp_key) { memcpy(outp_key, key, 8); uint8_t j; - while (n-- > 0) { - for (j = 0; j < 8 ; j++) - outp_key[j] = loclass_rl(outp_key[j]); + while(n-- > 0) { + for(j = 0; j < 8; j++) outp_key[j] = loclass_rl(outp_key[j]); } return; } @@ -166,14 +165,14 @@ static void loclass_rk(uint8_t *key, uint8_t n, uint8_t *outp_key) { static mbedtls_des_context loclass_ctx_enc; static mbedtls_des_context loclass_ctx_dec; -static void loclass_desdecrypt_iclass(uint8_t *iclass_key, uint8_t *input, uint8_t *output) { +static void loclass_desdecrypt_iclass(uint8_t* iclass_key, uint8_t* input, uint8_t* output) { uint8_t key_std_format[8] = {0}; loclass_permutekey_rev(iclass_key, key_std_format); mbedtls_des_setkey_dec(&loclass_ctx_dec, key_std_format); mbedtls_des_crypt_ecb(&loclass_ctx_dec, input, output); } -static void loclass_desencrypt_iclass(uint8_t *iclass_key, uint8_t *input, uint8_t *output) { +static void loclass_desencrypt_iclass(uint8_t* iclass_key, uint8_t* input, uint8_t* output) { uint8_t key_std_format[8] = {0}; loclass_permutekey_rev(iclass_key, key_std_format); mbedtls_des_setkey_enc(&loclass_ctx_enc, key_std_format); @@ -186,7 +185,7 @@ static void loclass_desencrypt_iclass(uint8_t *iclass_key, uint8_t *input, uint8 * @param loclass_hash1 loclass_hash1 * @param key_sel output key_sel=h[loclass_hash1[i]] */ -void hash2(uint8_t *key64, uint8_t *outp_keytable) { +void hash2(uint8_t* key64, uint8_t* outp_keytable) { /** *Expected: * High Security Key Table @@ -207,8 +206,7 @@ void hash2(uint8_t *key64, uint8_t *outp_keytable) { //calculate complement of key int i; - for (i = 0; i < 8; i++) - key64_negated[i] = ~key64[i]; + for(i = 0; i < 8; i++) key64_negated[i] = ~key64[i]; // Once again, key is on iclass-format loclass_desencrypt_iclass(key64, key64_negated, z[0]); @@ -219,14 +217,14 @@ void hash2(uint8_t *key64, uint8_t *outp_keytable) { // Once again, key is on iclass-format loclass_desdecrypt_iclass(z[0], key64_negated, y[0]); - for (i = 1; i < 8; i++) { + for(i = 1; i < 8; i++) { loclass_rk(key64, i, temp_output); loclass_desdecrypt_iclass(temp_output, z[i - 1], z[i]); loclass_desencrypt_iclass(temp_output, y[i - 1], y[i]); } - if (outp_keytable != NULL) { - for (i = 0 ; i < 8 ; i++) { + if(outp_keytable != NULL) { + for(i = 0; i < 8; i++) { memcpy(outp_keytable + i * 16, y[i], 8); memcpy(outp_keytable + 8 + i * 16, z[i], 8); } diff --git a/lib/loclass/optimized_elite.h b/applications/plugins/picopass/loclass/optimized_elite.h similarity index 95% rename from lib/loclass/optimized_elite.h rename to applications/plugins/picopass/loclass/optimized_elite.h index 9bc30e575..5343ebb07 100644 --- a/lib/loclass/optimized_elite.h +++ b/applications/plugins/picopass/loclass/optimized_elite.h @@ -52,7 +52,7 @@ void loclass_permutekey_rev(const uint8_t key[8], uint8_t dest[8]); * @param csn the CSN used * @param k output */ -void loclass_hash1(const uint8_t *csn, uint8_t *k); -void loclass_hash2(uint8_t *key64, uint8_t *outp_keytable); +void loclass_hash1(const uint8_t* csn, uint8_t* k); +void loclass_hash2(uint8_t* key64, uint8_t* outp_keytable); #endif diff --git a/lib/loclass/optimized_ikeys.c b/applications/plugins/picopass/loclass/optimized_ikeys.c similarity index 90% rename from lib/loclass/optimized_ikeys.c rename to applications/plugins/picopass/loclass/optimized_ikeys.c index 9531c16c2..1e6f12c56 100644 --- a/lib/loclass/optimized_ikeys.c +++ b/applications/plugins/picopass/loclass/optimized_ikeys.c @@ -61,13 +61,10 @@ From "Dismantling iclass": #include #include "optimized_cipherutils.h" -static const uint8_t loclass_pi[35] = { - 0x0F, 0x17, 0x1B, 0x1D, 0x1E, 0x27, 0x2B, 0x2D, - 0x2E, 0x33, 0x35, 0x39, 0x36, 0x3A, 0x3C, 0x47, - 0x4B, 0x4D, 0x4E, 0x53, 0x55, 0x56, 0x59, 0x5A, - 0x5C, 0x63, 0x65, 0x66, 0x69, 0x6A, 0x6C, 0x71, - 0x72, 0x74, 0x78 -}; +static const uint8_t loclass_pi[35] = {0x0F, 0x17, 0x1B, 0x1D, 0x1E, 0x27, 0x2B, 0x2D, 0x2E, + 0x33, 0x35, 0x39, 0x36, 0x3A, 0x3C, 0x47, 0x4B, 0x4D, + 0x4E, 0x53, 0x55, 0x56, 0x59, 0x5A, 0x5C, 0x63, 0x65, + 0x66, 0x69, 0x6A, 0x6C, 0x71, 0x72, 0x74, 0x78}; /** * @brief The key diversification algorithm uses 6-bit bytes. @@ -90,7 +87,7 @@ static uint8_t loclass_getSixBitByte(uint64_t c, int n) { * @param z the value to place there * @param n bitnumber. */ -static void loclass_pushbackSixBitByte(uint64_t *c, uint8_t z, int n) { +static void loclass_pushbackSixBitByte(uint64_t* c, uint8_t z, int n) { //0x XXXX YYYY ZZZZ ZZZZ ZZZZ // ^z0 ^z7 //z0: 1111 1100 0000 0000 @@ -106,7 +103,6 @@ static void loclass_pushbackSixBitByte(uint64_t *c, uint8_t z, int n) { eraser = ~eraser; (*c) &= eraser; (*c) |= masked; - } /** * @brief Swaps the z-values. @@ -133,21 +129,21 @@ static uint64_t loclass_swapZvalues(uint64_t c) { * @return 4 six-bit bytes chunked into a uint64_t,as 00..00a0a1a2a3 */ static uint64_t loclass_ck(int i, int j, uint64_t z) { - if (i == 1 && j == -1) { + if(i == 1 && j == -1) { // loclass_ck(1, −1, z [0] . . . z [3] ) = z [0] . . . z [3] return z; - } else if (j == -1) { + } else if(j == -1) { // loclass_ck(i, −1, z [0] . . . z [3] ) = loclass_ck(i − 1, i − 2, z [0] . . . z [3] ) return loclass_ck(i - 1, i - 2, z); } - if (loclass_getSixBitByte(z, i) == loclass_getSixBitByte(z, j)) { + if(loclass_getSixBitByte(z, i) == loclass_getSixBitByte(z, j)) { //loclass_ck(i, j − 1, z [0] . . . z [i] ← j . . . z [3] ) uint64_t newz = 0; int c; - for (c = 0; c < 4; c++) { + for(c = 0; c < 4; c++) { uint8_t val = loclass_getSixBitByte(z, c); - if (c == i) + if(c == i) loclass_pushbackSixBitByte(&newz, j, c); else loclass_pushbackSixBitByte(&newz, val, c); @@ -191,12 +187,16 @@ static uint64_t loclass_check(uint64_t z) { return ck1 | ck2 >> 24; } -static void loclass_permute(LoclassBitstreamIn_t *p_in, uint64_t z, int l, int r, LoclassBitstreamOut_t *out) { - if (loclass_bitsLeft(p_in) == 0) - return; +static void loclass_permute( + LoclassBitstreamIn_t* p_in, + uint64_t z, + int l, + int r, + LoclassBitstreamOut_t* out) { + if(loclass_bitsLeft(p_in) == 0) return; bool pn = loclass_tailBit(p_in); - if (pn) { // pn = 1 + if(pn) { // pn = 1 uint8_t zl = loclass_getSixBitByte(z, l); loclass_push6bits(out, zl + 1); @@ -231,7 +231,7 @@ void loclass_hash0(uint64_t c, uint8_t k[8]) { uint8_t y = (c & 0x00FF000000000000) >> 48; uint64_t zP = 0; - for (int n = 0; n < 4 ; n++) { + for(int n = 0; n < 4; n++) { uint8_t zn = loclass_getSixBitByte(c, n); uint8_t zn4 = loclass_getSixBitByte(c, n + 4); uint8_t _zn = (zn % (63 - n)) + n; @@ -243,10 +243,10 @@ void loclass_hash0(uint64_t c, uint8_t k[8]) { uint64_t zCaret = loclass_check(zP); uint8_t p = loclass_pi[x % 35]; - if (x & 1) //Check if x7 is 1 + if(x & 1) //Check if x7 is 1 p = ~p; - LoclassBitstreamIn_t p_in = { &p, 8, 0 }; + LoclassBitstreamIn_t p_in = {&p, 8, 0}; uint8_t outbuffer[] = {0, 0, 0, 0, 0, 0, 0, 0}; LoclassBitstreamOut_t out = {outbuffer, 0, 0}; loclass_permute(&p_in, zCaret, 0, 4, &out); //returns 48 bits? or 6 8-bytes @@ -259,7 +259,7 @@ void loclass_hash0(uint64_t c, uint8_t k[8]) { zTilde >>= 16; - for (int i = 0; i < 8; i++) { + for(int i = 0; i < 8; i++) { // the key on index i is first a bit from y // then six bits from z, // then a bit from p @@ -270,7 +270,7 @@ void loclass_hash0(uint64_t c, uint8_t k[8]) { //k[i] |= (y << i) & 0x80 ; // First, place y(7-i) leftmost in k - k[i] |= (y << (7 - i)) & 0x80 ; + k[i] |= (y << (7 - i)) & 0x80; uint8_t zTilde_i = loclass_getSixBitByte(zTilde, i); // zTildeI is now on the form 00XXXXXX @@ -285,7 +285,7 @@ void loclass_hash0(uint64_t c, uint8_t k[8]) { //Shift bit i into rightmost location (mask only after complement) uint8_t p_i = p >> i & 0x1; - if (k[i]) { // yi = 1 + if(k[i]) { // yi = 1 k[i] |= ~zTilde_i & 0x7E; k[i] |= p_i & 1; k[i] += 1; @@ -302,7 +302,7 @@ void loclass_hash0(uint64_t c, uint8_t k[8]) { * @param key * @param div_key */ -void loclass_diversifyKey(uint8_t *csn, const uint8_t *key, uint8_t *div_key) { +void loclass_diversifyKey(uint8_t* csn, const uint8_t* key, uint8_t* div_key) { mbedtls_des_context loclass_ctx_enc; // Prepare the DES key @@ -318,4 +318,3 @@ void loclass_diversifyKey(uint8_t *csn, const uint8_t *key, uint8_t *div_key) { loclass_hash0(c_csn, div_key); } - diff --git a/lib/loclass/optimized_ikeys.h b/applications/plugins/picopass/loclass/optimized_ikeys.h similarity index 96% rename from lib/loclass/optimized_ikeys.h rename to applications/plugins/picopass/loclass/optimized_ikeys.h index e960b8be2..f2711d31e 100644 --- a/lib/loclass/optimized_ikeys.h +++ b/applications/plugins/picopass/loclass/optimized_ikeys.h @@ -56,7 +56,7 @@ void loclass_hash0(uint64_t c, uint8_t k[8]); * @param div_key */ -void loclass_diversifyKey(uint8_t *csn, const uint8_t *key, uint8_t *div_key); +void loclass_diversifyKey(uint8_t* csn, const uint8_t* key, uint8_t* div_key); /** * @brief Permutes a key from standard NIST format to Iclass specific format * @param key diff --git a/applications/picopass/picopass.c b/applications/plugins/picopass/picopass.c similarity index 100% rename from applications/picopass/picopass.c rename to applications/plugins/picopass/picopass.c diff --git a/applications/picopass/picopass.h b/applications/plugins/picopass/picopass.h similarity index 100% rename from applications/picopass/picopass.h rename to applications/plugins/picopass/picopass.h diff --git a/applications/picopass/picopass_device.c b/applications/plugins/picopass/picopass_device.c similarity index 97% rename from applications/picopass/picopass_device.c rename to applications/plugins/picopass/picopass_device.c index 4cd6faaab..e7f3e0bed 100644 --- a/applications/picopass/picopass_device.c +++ b/applications/plugins/picopass/picopass_device.c @@ -226,14 +226,13 @@ bool picopass_file_select(PicopassDevice* dev) { // Input events and views are managed by file_browser string_t picopass_app_folder; string_init_set_str(picopass_app_folder, PICOPASS_APP_FOLDER); + + DialogsFileBrowserOptions browser_options; + dialog_file_browser_set_basic_options(&browser_options, PICOPASS_APP_EXTENSION, &I_Nfc_10px); + bool res = dialog_file_browser_show( - dev->dialogs, - dev->load_path, - picopass_app_folder, - PICOPASS_APP_EXTENSION, - true, - &I_Nfc_10px, - true); + dev->dialogs, dev->load_path, picopass_app_folder, &browser_options); + string_clear(picopass_app_folder); if(res) { string_t filename; @@ -310,10 +309,6 @@ ReturnCode picopass_device_decrypt(uint8_t* enc_data, uint8_t* dec_data) { ReturnCode picopass_device_parse_credential(PicopassBlock* AA1, PicopassPacs* pacs) { ReturnCode err; - // Thank you proxmark! - pacs->legacy = (memcmp(AA1[5].data, "\xff\xff\xff\xff\xff\xff\xff\xff", 8) == 0); - pacs->se_enabled = (memcmp(AA1[5].data, "\xff\xff\xff\x00\x06\xff\xff\xff", 8) == 0); - pacs->biometrics = AA1[6].data[4]; pacs->pin_length = AA1[6].data[6] & 0x0F; pacs->encryption = AA1[6].data[7]; @@ -348,6 +343,8 @@ ReturnCode picopass_device_parse_credential(PicopassBlock* AA1, PicopassPacs* pa FURI_LOG_D(TAG, "Unknown encryption"); } + pacs->sio = (AA1[10].data[0] == 0x30); // rough check + return ERR_NONE; } diff --git a/applications/picopass/picopass_device.h b/applications/plugins/picopass/picopass_device.h similarity index 95% rename from applications/picopass/picopass_device.h rename to applications/plugins/picopass/picopass_device.h index 0415b8794..745b64bd5 100644 --- a/applications/picopass/picopass_device.h +++ b/applications/plugins/picopass/picopass_device.h @@ -4,12 +4,11 @@ #include #include #include - -#include - #include -#include -#include + +#include "rfal_picopass.h" +#include "loclass/optimized_ikeys.h" +#include "loclass/optimized_cipher.h" #define PICOPASS_DEV_NAME_MAX_LEN 22 #define PICOPASS_READER_DATA_MAX_SIZE 64 @@ -48,6 +47,7 @@ typedef struct { typedef struct { bool legacy; bool se_enabled; + bool sio; bool biometrics; uint8_t pin_length; PicopassEncryption encryption; diff --git a/applications/picopass/picopass_i.h b/applications/plugins/picopass/picopass_i.h similarity index 96% rename from applications/picopass/picopass_i.h rename to applications/plugins/picopass/picopass_i.h index d295f53ac..dec5a865f 100644 --- a/applications/picopass/picopass_i.h +++ b/applications/plugins/picopass/picopass_i.h @@ -4,7 +4,7 @@ #include "picopass_worker.h" #include "picopass_device.h" -#include +#include "rfal_picopass.h" #include #include @@ -20,7 +20,7 @@ #include -#include +#include "scenes/picopass_scene.h" #include #include diff --git a/applications/picopass/picopass_worker.c b/applications/plugins/picopass/picopass_worker.c similarity index 50% rename from applications/picopass/picopass_worker.c rename to applications/plugins/picopass/picopass_worker.c index 88df8d45b..532effd9a 100644 --- a/applications/picopass/picopass_worker.c +++ b/applications/plugins/picopass/picopass_worker.c @@ -6,14 +6,14 @@ const uint8_t picopass_iclass_key[] = {0xaf, 0xa7, 0x85, 0xa7, 0xda, 0xb3, 0x33, const uint8_t picopass_factory_key[] = {0x76, 0x65, 0x54, 0x43, 0x32, 0x21, 0x10, 0x00}; static void picopass_worker_enable_field() { - st25r3916TxRxOn(); - rfalLowPowerModeStop(); - rfalWorker(); + furi_hal_nfc_ll_txrx_on(); + furi_hal_nfc_exit_sleep(); + furi_hal_nfc_ll_poll(); } static ReturnCode picopass_worker_disable_field(ReturnCode rc) { - st25r3916TxRxOff(); - rfalLowPowerModeStart(); + furi_hal_nfc_ll_txrx_off(); + furi_hal_nfc_start_sleep(); return rc; } @@ -112,7 +112,128 @@ ReturnCode picopass_detect_card(int timeout) { return ERR_NONE; } +ReturnCode picopass_read_preauth(PicopassBlock* AA1) { + rfalPicoPassIdentifyRes idRes; + rfalPicoPassSelectRes selRes; + + ReturnCode err; + + err = rfalPicoPassPollerIdentify(&idRes); + if(err != ERR_NONE) { + FURI_LOG_E(TAG, "rfalPicoPassPollerIdentify error %d", err); + return err; + } + + err = rfalPicoPassPollerSelect(idRes.CSN, &selRes); + if(err != ERR_NONE) { + FURI_LOG_E(TAG, "rfalPicoPassPollerSelect error %d", err); + return err; + } + + memcpy(AA1[PICOPASS_CSN_BLOCK_INDEX].data, selRes.CSN, sizeof(selRes.CSN)); + FURI_LOG_D( + TAG, + "csn %02x%02x%02x%02x%02x%02x%02x%02x", + AA1[PICOPASS_CSN_BLOCK_INDEX].data[0], + AA1[PICOPASS_CSN_BLOCK_INDEX].data[1], + AA1[PICOPASS_CSN_BLOCK_INDEX].data[2], + AA1[PICOPASS_CSN_BLOCK_INDEX].data[3], + AA1[PICOPASS_CSN_BLOCK_INDEX].data[4], + AA1[PICOPASS_CSN_BLOCK_INDEX].data[5], + AA1[PICOPASS_CSN_BLOCK_INDEX].data[6], + AA1[PICOPASS_CSN_BLOCK_INDEX].data[7]); + + rfalPicoPassReadBlockRes cfg = {0}; + err = rfalPicoPassPollerReadBlock(PICOPASS_CONFIG_BLOCK_INDEX, &cfg); + memcpy(AA1[PICOPASS_CONFIG_BLOCK_INDEX].data, cfg.data, sizeof(cfg.data)); + FURI_LOG_D( + TAG, + "config %02x%02x%02x%02x%02x%02x%02x%02x", + AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[0], + AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[1], + AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[2], + AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[3], + AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[4], + AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[5], + AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[6], + AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[7]); + + rfalPicoPassReadBlockRes aia; + err = rfalPicoPassPollerReadBlock(PICOPASS_AIA_BLOCK_INDEX, &aia); + memcpy(AA1[PICOPASS_AIA_BLOCK_INDEX].data, aia.data, sizeof(aia.data)); + FURI_LOG_D( + TAG, + "aia %02x%02x%02x%02x%02x%02x%02x%02x", + AA1[PICOPASS_AIA_BLOCK_INDEX].data[0], + AA1[PICOPASS_AIA_BLOCK_INDEX].data[1], + AA1[PICOPASS_AIA_BLOCK_INDEX].data[2], + AA1[PICOPASS_AIA_BLOCK_INDEX].data[3], + AA1[PICOPASS_AIA_BLOCK_INDEX].data[4], + AA1[PICOPASS_AIA_BLOCK_INDEX].data[5], + AA1[PICOPASS_AIA_BLOCK_INDEX].data[6], + AA1[PICOPASS_AIA_BLOCK_INDEX].data[7]); + + return ERR_NONE; +} + ReturnCode picopass_read_card(PicopassBlock* AA1) { + rfalPicoPassReadCheckRes rcRes; + rfalPicoPassCheckRes chkRes; + + ReturnCode err; + + uint8_t div_key[8] = {0}; + uint8_t mac[4] = {0}; + uint8_t ccnr[12] = {0}; + + err = rfalPicoPassPollerReadCheck(&rcRes); + if(err != ERR_NONE) { + FURI_LOG_E(TAG, "rfalPicoPassPollerReadCheck error %d", err); + return err; + } + 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_opt_doReaderMAC(ccnr, div_key, mac); + + err = rfalPicoPassPollerCheck(mac, &chkRes); + if(err != ERR_NONE) { + FURI_LOG_E(TAG, "rfalPicoPassPollerCheck error %d", err); + return err; + } + + size_t app_limit = AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[0] < PICOPASS_MAX_APP_LIMIT ? + AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[0] : + PICOPASS_MAX_APP_LIMIT; + + for(size_t i = 2; i < app_limit; i++) { + rfalPicoPassReadBlockRes block; + err = rfalPicoPassPollerReadBlock(i, &block); + if(err != ERR_NONE) { + FURI_LOG_E(TAG, "rfalPicoPassPollerReadBlock error %d", err); + return err; + } + + FURI_LOG_D( + TAG, + "rfalPicoPassPollerReadBlock %d %02x%02x%02x%02x%02x%02x%02x%02x", + i, + block.data[0], + block.data[1], + block.data[2], + block.data[3], + block.data[4], + block.data[5], + block.data[6], + block.data[7]); + + memcpy(AA1[i].data, block.data, sizeof(block.data)); + } + + return ERR_NONE; +} + +ReturnCode picopass_write_card(PicopassBlock* AA1) { rfalPicoPassIdentifyRes idRes; rfalPicoPassSelectRes selRes; rfalPicoPassReadCheckRes rcRes; @@ -152,39 +273,34 @@ ReturnCode picopass_read_card(PicopassBlock* AA1) { return err; } - rfalPicoPassReadBlockRes csn; - err = rfalPicoPassPollerReadBlock(PICOPASS_CSN_BLOCK_INDEX, &csn); - memcpy(AA1[PICOPASS_CSN_BLOCK_INDEX].data, csn.data, sizeof(csn.data)); - - rfalPicoPassReadBlockRes cfg; - err = rfalPicoPassPollerReadBlock(PICOPASS_CONFIG_BLOCK_INDEX, &cfg); - memcpy(AA1[PICOPASS_CONFIG_BLOCK_INDEX].data, cfg.data, sizeof(cfg.data)); - - size_t app_limit = cfg.data[0] < PICOPASS_MAX_APP_LIMIT ? cfg.data[0] : PICOPASS_MAX_APP_LIMIT; - - for(size_t i = 2; i < app_limit; i++) { - FURI_LOG_D(TAG, "rfalPicoPassPollerReadBlock block %d", i); - rfalPicoPassReadBlockRes block; - err = rfalPicoPassPollerReadBlock(i, &block); - if(err != ERR_NONE) { - FURI_LOG_E(TAG, "rfalPicoPassPollerReadBlock error %d", err); - return err; - } - + for(size_t i = 6; i < 10; i++) { + FURI_LOG_D(TAG, "rfalPicoPassPollerWriteBlock %d", i); + uint8_t data[9] = {0}; + data[0] = i; + memcpy(data + 1, AA1[i].data, RFAL_PICOPASS_MAX_BLOCK_LEN); + loclass_doMAC_N(data, sizeof(data), div_key, mac); FURI_LOG_D( TAG, - "rfalPicoPassPollerReadBlock %d %02x%02x%02x%02x%02x%02x%02x%02x", + "loclass_doMAC_N %d %02x%02x%02x%02x%02x%02x%02x%02x %02x%02x%02x%02x", i, - block.data[0], - block.data[1], - block.data[2], - block.data[3], - block.data[4], - block.data[5], - block.data[6], - block.data[7]); + data[1], + data[2], + data[3], + data[4], + data[5], + data[6], + data[7], + data[8], + mac[0], + mac[1], + mac[2], + mac[3]); - memcpy(AA1[i].data, block.data, sizeof(block.data)); + err = rfalPicoPassPollerWriteBlock(i, AA1[i].data, mac); + if(err != ERR_NONE) { + FURI_LOG_E(TAG, "rfalPicoPassPollerWriteBlock error %d", err); + return err; + } } return ERR_NONE; @@ -196,6 +312,8 @@ int32_t picopass_worker_task(void* context) { picopass_worker_enable_field(); if(picopass_worker->state == PicopassWorkerStateDetect) { picopass_worker_detect(picopass_worker); + } else if(picopass_worker->state == PicopassWorkerStateWrite) { + picopass_worker_write(picopass_worker); } picopass_worker_disable_field(ERR_NONE); @@ -212,27 +330,79 @@ void picopass_worker_detect(PicopassWorker* picopass_worker) { PicopassPacs* pacs = &dev_data->pacs; ReturnCode err; + // reset device data + for(size_t i = 0; i < PICOPASS_MAX_APP_LIMIT; i++) { + memset(AA1[i].data, 0, sizeof(AA1[i].data)); + } + memset(pacs, 0, sizeof(PicopassPacs)); + + PicopassWorkerEvent nextState = PicopassWorkerEventSuccess; + while(picopass_worker->state == PicopassWorkerStateDetect) { if(picopass_detect_card(1000) == ERR_NONE) { // Process first found device + err = picopass_read_preauth(AA1); + if(err != ERR_NONE) { + FURI_LOG_E(TAG, "picopass_read_preauth error %d", err); + nextState = PicopassWorkerEventFail; + } + + // Thank you proxmark! + pacs->legacy = (memcmp(AA1[5].data, "\xff\xff\xff\xff\xff\xff\xff\xff", 8) == 0); + pacs->se_enabled = (memcmp(AA1[5].data, "\xff\xff\xff\x00\x06\xff\xff\xff", 8) == 0); + if(pacs->se_enabled) { + FURI_LOG_D(TAG, "SE enabled"); + } + err = picopass_read_card(AA1); if(err != ERR_NONE) { FURI_LOG_E(TAG, "picopass_read_card error %d", err); + nextState = PicopassWorkerEventFail; } - err = picopass_device_parse_credential(AA1, pacs); + if(nextState == PicopassWorkerEventSuccess) { + err = picopass_device_parse_credential(AA1, pacs); + } if(err != ERR_NONE) { FURI_LOG_E(TAG, "picopass_device_parse_credential error %d", err); + nextState = PicopassWorkerEventFail; } - err = picopass_device_parse_wiegand(pacs->credential, &pacs->record); + if(nextState == PicopassWorkerEventSuccess) { + err = picopass_device_parse_wiegand(pacs->credential, &pacs->record); + } if(err != ERR_NONE) { FURI_LOG_E(TAG, "picopass_device_parse_wiegand error %d", err); + nextState = PicopassWorkerEventFail; } // Notify caller and exit if(picopass_worker->callback) { - picopass_worker->callback(PicopassWorkerEventSuccess, picopass_worker->context); + picopass_worker->callback(nextState, picopass_worker->context); + } + break; + } + furi_delay_ms(100); + } +} + +void picopass_worker_write(PicopassWorker* picopass_worker) { + PicopassDeviceData* dev_data = picopass_worker->dev_data; + PicopassBlock* AA1 = dev_data->AA1; + ReturnCode err; + PicopassWorkerEvent nextState = PicopassWorkerEventSuccess; + + while(picopass_worker->state == PicopassWorkerStateWrite) { + if(picopass_detect_card(1000) == ERR_NONE) { + err = picopass_write_card(AA1); + if(err != ERR_NONE) { + FURI_LOG_E(TAG, "picopass_write_card error %d", err); + nextState = PicopassWorkerEventFail; + } + + // Notify caller and exit + if(picopass_worker->callback) { + picopass_worker->callback(nextState, picopass_worker->context); } break; } diff --git a/applications/picopass/picopass_worker.h b/applications/plugins/picopass/picopass_worker.h old mode 100755 new mode 100644 similarity index 94% rename from applications/picopass/picopass_worker.h rename to applications/plugins/picopass/picopass_worker.h index 9035f1c89..29a890a18 --- a/applications/picopass/picopass_worker.h +++ b/applications/plugins/picopass/picopass_worker.h @@ -11,6 +11,7 @@ typedef enum { PicopassWorkerStateReady, // Main worker states PicopassWorkerStateDetect, + PicopassWorkerStateWrite, // Transition PicopassWorkerStateStop, } PicopassWorkerState; @@ -23,6 +24,7 @@ typedef enum { PicopassWorkerEventSuccess, PicopassWorkerEventFail, PicopassWorkerEventNoCardDetected, + PicopassWorkerEventSeEnabled, PicopassWorkerEventStartReading, } PicopassWorkerEvent; diff --git a/applications/picopass/picopass_worker_i.h b/applications/plugins/picopass/picopass_worker_i.h similarity index 91% rename from applications/picopass/picopass_worker_i.h rename to applications/plugins/picopass/picopass_worker_i.h index 789951900..9b215fb74 100644 --- a/applications/picopass/picopass_worker_i.h +++ b/applications/plugins/picopass/picopass_worker_i.h @@ -31,3 +31,4 @@ void picopass_worker_change_state(PicopassWorker* picopass_worker, PicopassWorke int32_t picopass_worker_task(void* context); void picopass_worker_detect(PicopassWorker* picopass_worker); +void picopass_worker_write(PicopassWorker* picopass_worker); diff --git a/applications/plugins/picopass/rfal_picopass.c b/applications/plugins/picopass/rfal_picopass.c new file mode 100644 index 000000000..50cd4e95d --- /dev/null +++ b/applications/plugins/picopass/rfal_picopass.c @@ -0,0 +1,215 @@ +#include "rfal_picopass.h" +#include "utils.h" + +#define RFAL_PICOPASS_TXRX_FLAGS \ + (FURI_HAL_NFC_LL_TXRX_FLAGS_CRC_TX_MANUAL | FURI_HAL_NFC_LL_TXRX_FLAGS_AGC_ON | \ + FURI_HAL_NFC_LL_TXRX_FLAGS_PAR_RX_REMV | FURI_HAL_NFC_LL_TXRX_FLAGS_CRC_RX_KEEP) + +#define TAG "RFAL_PICOPASS" + +typedef struct { + uint8_t CMD; + uint8_t CSN[RFAL_PICOPASS_UID_LEN]; +} rfalPicoPassSelectReq; + +typedef struct { + uint8_t CMD; + uint8_t null[4]; + uint8_t mac[4]; +} rfalPicoPassCheckReq; + +static uint16_t rfalPicoPassUpdateCcitt(uint16_t crcSeed, uint8_t dataByte) { + uint16_t crc = crcSeed; + uint8_t dat = dataByte; + + dat ^= (uint8_t)(crc & 0xFFU); + dat ^= (dat << 4); + + crc = (crc >> 8) ^ (((uint16_t)dat) << 8) ^ (((uint16_t)dat) << 3) ^ (((uint16_t)dat) >> 4); + + return crc; +} + +static uint16_t + rfalPicoPassCalculateCcitt(uint16_t preloadValue, const uint8_t* buf, uint16_t length) { + uint16_t crc = preloadValue; + uint16_t index; + + for(index = 0; index < length; index++) { + crc = rfalPicoPassUpdateCcitt(crc, buf[index]); + } + + return crc; +} + +FuriHalNfcReturn rfalPicoPassPollerInitialize(void) { + FuriHalNfcReturn ret; + + ret = furi_hal_nfc_ll_set_mode( + FuriHalNfcModePollPicopass, FuriHalNfcBitrate26p48, FuriHalNfcBitrate26p48); + if(ret != FuriHalNfcReturnOk) { + return ret; + }; + + furi_hal_nfc_ll_set_error_handling(FuriHalNfcErrorHandlingNfc); + furi_hal_nfc_ll_set_guard_time(FURI_HAL_NFC_LL_GT_PICOPASS); + furi_hal_nfc_ll_set_fdt_listen(FURI_HAL_NFC_LL_FDT_LISTEN_PICOPASS_POLLER); + furi_hal_nfc_ll_set_fdt_poll(FURI_HAL_NFC_LL_FDT_POLL_PICOPASS_POLLER); + + return FuriHalNfcReturnOk; +} + +FuriHalNfcReturn rfalPicoPassPollerCheckPresence(void) { + FuriHalNfcReturn ret; + uint8_t txBuf[1] = {RFAL_PICOPASS_CMD_ACTALL}; + uint8_t rxBuf[32] = {0}; + uint16_t recvLen = 0; + uint32_t flags = RFAL_PICOPASS_TXRX_FLAGS; + uint32_t fwt = furi_hal_nfc_ll_ms2fc(20); + + ret = furi_hal_nfc_ll_txrx(txBuf, 1, rxBuf, 32, &recvLen, flags, fwt); + return ret; +} + +FuriHalNfcReturn rfalPicoPassPollerIdentify(rfalPicoPassIdentifyRes* idRes) { + FuriHalNfcReturn ret; + + uint8_t txBuf[1] = {RFAL_PICOPASS_CMD_IDENTIFY}; + uint16_t recvLen = 0; + uint32_t flags = RFAL_PICOPASS_TXRX_FLAGS; + uint32_t fwt = furi_hal_nfc_ll_ms2fc(20); + + ret = furi_hal_nfc_ll_txrx( + txBuf, + sizeof(txBuf), + (uint8_t*)idRes, + sizeof(rfalPicoPassIdentifyRes), + &recvLen, + flags, + fwt); + // printf("identify rx: %d %s\n", recvLen, hex2Str(idRes->CSN, RFAL_PICOPASS_UID_LEN)); + + return ret; +} + +FuriHalNfcReturn rfalPicoPassPollerSelect(uint8_t* csn, rfalPicoPassSelectRes* selRes) { + FuriHalNfcReturn ret; + + rfalPicoPassSelectReq selReq; + selReq.CMD = RFAL_PICOPASS_CMD_SELECT; + ST_MEMCPY(selReq.CSN, csn, RFAL_PICOPASS_UID_LEN); + uint16_t recvLen = 0; + uint32_t flags = RFAL_PICOPASS_TXRX_FLAGS; + uint32_t fwt = furi_hal_nfc_ll_ms2fc(20); + + ret = furi_hal_nfc_ll_txrx( + (uint8_t*)&selReq, + sizeof(rfalPicoPassSelectReq), + (uint8_t*)selRes, + sizeof(rfalPicoPassSelectRes), + &recvLen, + flags, + fwt); + // printf("select rx: %d %s\n", recvLen, hex2Str(selRes->CSN, RFAL_PICOPASS_UID_LEN)); + if(ret == FuriHalNfcReturnTimeout) { + return FuriHalNfcReturnOk; + } + + return ret; +} + +FuriHalNfcReturn rfalPicoPassPollerReadCheck(rfalPicoPassReadCheckRes* rcRes) { + FuriHalNfcReturn ret; + uint8_t txBuf[2] = {RFAL_PICOPASS_CMD_READCHECK, 0x02}; + uint16_t recvLen = 0; + uint32_t flags = RFAL_PICOPASS_TXRX_FLAGS; + uint32_t fwt = furi_hal_nfc_ll_ms2fc(20); + + ret = furi_hal_nfc_ll_txrx( + txBuf, + sizeof(txBuf), + (uint8_t*)rcRes, + sizeof(rfalPicoPassReadCheckRes), + &recvLen, + flags, + fwt); + // printf("readcheck rx: %d %s\n", recvLen, hex2Str(rcRes->CCNR, 8)); + + if(ret == FuriHalNfcReturnCrc) { + return FuriHalNfcReturnOk; + } + + return ret; +} + +FuriHalNfcReturn rfalPicoPassPollerCheck(uint8_t* mac, rfalPicoPassCheckRes* chkRes) { + FuriHalNfcReturn ret; + rfalPicoPassCheckReq chkReq; + chkReq.CMD = RFAL_PICOPASS_CMD_CHECK; + ST_MEMCPY(chkReq.mac, mac, 4); + ST_MEMSET(chkReq.null, 0, 4); + uint16_t recvLen = 0; + uint32_t flags = RFAL_PICOPASS_TXRX_FLAGS; + uint32_t fwt = furi_hal_nfc_ll_ms2fc(20); + + // printf("check tx: %s\n", hex2Str((uint8_t *)&chkReq, sizeof(rfalPicoPassCheckReq))); + ret = furi_hal_nfc_ll_txrx( + (uint8_t*)&chkReq, + sizeof(rfalPicoPassCheckReq), + (uint8_t*)chkRes, + sizeof(rfalPicoPassCheckRes), + &recvLen, + flags, + fwt); + // printf("check rx: %d %s\n", recvLen, hex2Str(chkRes->mac, 4)); + if(ret == FuriHalNfcReturnCrc) { + return FuriHalNfcReturnOk; + } + + return ret; +} + +FuriHalNfcReturn rfalPicoPassPollerReadBlock(uint8_t blockNum, rfalPicoPassReadBlockRes* readRes) { + FuriHalNfcReturn ret; + + uint8_t txBuf[4] = {RFAL_PICOPASS_CMD_READ, 0, 0, 0}; + txBuf[1] = blockNum; + uint16_t crc = rfalPicoPassCalculateCcitt(0xE012, txBuf + 1, 1); + memcpy(txBuf + 2, &crc, sizeof(uint16_t)); + + uint16_t recvLen = 0; + uint32_t flags = RFAL_PICOPASS_TXRX_FLAGS; + uint32_t fwt = furi_hal_nfc_ll_ms2fc(20); + + ret = furi_hal_nfc_ll_txrx( + txBuf, + sizeof(txBuf), + (uint8_t*)readRes, + sizeof(rfalPicoPassReadBlockRes), + &recvLen, + flags, + fwt); + return ret; +} + +FuriHalNfcReturn rfalPicoPassPollerWriteBlock(uint8_t blockNum, uint8_t data[8], uint8_t mac[4]) { + FuriHalNfcReturn ret; + + uint8_t txBuf[14] = {RFAL_PICOPASS_CMD_WRITE, blockNum, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + memcpy(txBuf + 2, data, RFAL_PICOPASS_MAX_BLOCK_LEN); + memcpy(txBuf + 10, mac, 4); + + uint16_t recvLen = 0; + uint32_t flags = RFAL_PICOPASS_TXRX_FLAGS; + uint32_t fwt = furi_hal_nfc_ll_ms2fc(20); + rfalPicoPassReadBlockRes block; + + ret = furi_hal_nfc_ll_txrx( + txBuf, sizeof(txBuf), (uint8_t*)&block, sizeof(block), &recvLen, flags, fwt); + + if(ret == FuriHalNfcReturnOk) { + // TODO: compare response + } + + return ret; +} diff --git a/applications/plugins/picopass/rfal_picopass.h b/applications/plugins/picopass/rfal_picopass.h new file mode 100644 index 000000000..6926b2a79 --- /dev/null +++ b/applications/plugins/picopass/rfal_picopass.h @@ -0,0 +1,48 @@ +#pragma once + +#include + +#define RFAL_PICOPASS_UID_LEN 8 +#define RFAL_PICOPASS_MAX_BLOCK_LEN 8 + +enum { + RFAL_PICOPASS_CMD_ACTALL = 0x0A, + RFAL_PICOPASS_CMD_IDENTIFY = 0x0C, + RFAL_PICOPASS_CMD_SELECT = 0x81, + RFAL_PICOPASS_CMD_READCHECK = 0x88, + RFAL_PICOPASS_CMD_CHECK = 0x05, + RFAL_PICOPASS_CMD_READ = 0x0C, + RFAL_PICOPASS_CMD_WRITE = 0x87, +}; + +typedef struct { + uint8_t CSN[RFAL_PICOPASS_UID_LEN]; // Anti-collision CSN + uint8_t crc[2]; +} rfalPicoPassIdentifyRes; + +typedef struct { + uint8_t CSN[RFAL_PICOPASS_UID_LEN]; // Real CSN + uint8_t crc[2]; +} rfalPicoPassSelectRes; + +typedef struct { + uint8_t CCNR[8]; +} rfalPicoPassReadCheckRes; + +typedef struct { + uint8_t mac[4]; +} rfalPicoPassCheckRes; + +typedef struct { + uint8_t data[RFAL_PICOPASS_MAX_BLOCK_LEN]; + uint8_t crc[2]; +} rfalPicoPassReadBlockRes; + +FuriHalNfcReturn rfalPicoPassPollerInitialize(void); +FuriHalNfcReturn rfalPicoPassPollerCheckPresence(void); +FuriHalNfcReturn rfalPicoPassPollerIdentify(rfalPicoPassIdentifyRes* idRes); +FuriHalNfcReturn rfalPicoPassPollerSelect(uint8_t* csn, rfalPicoPassSelectRes* selRes); +FuriHalNfcReturn rfalPicoPassPollerReadCheck(rfalPicoPassReadCheckRes* rcRes); +FuriHalNfcReturn rfalPicoPassPollerCheck(uint8_t* mac, rfalPicoPassCheckRes* chkRes); +FuriHalNfcReturn rfalPicoPassPollerReadBlock(uint8_t blockNum, rfalPicoPassReadBlockRes* readRes); +FuriHalNfcReturn rfalPicoPassPollerWriteBlock(uint8_t blockNum, uint8_t data[8], uint8_t mac[4]); diff --git a/applications/picopass/scenes/picopass_scene.c b/applications/plugins/picopass/scenes/picopass_scene.c old mode 100755 new mode 100644 similarity index 100% rename from applications/picopass/scenes/picopass_scene.c rename to applications/plugins/picopass/scenes/picopass_scene.c diff --git a/applications/picopass/scenes/picopass_scene.h b/applications/plugins/picopass/scenes/picopass_scene.h similarity index 100% rename from applications/picopass/scenes/picopass_scene.h rename to applications/plugins/picopass/scenes/picopass_scene.h diff --git a/applications/picopass/scenes/picopass_scene_card_menu.c b/applications/plugins/picopass/scenes/picopass_scene_card_menu.c similarity index 100% rename from applications/picopass/scenes/picopass_scene_card_menu.c rename to applications/plugins/picopass/scenes/picopass_scene_card_menu.c diff --git a/applications/picopass/scenes/picopass_scene_config.h b/applications/plugins/picopass/scenes/picopass_scene_config.h old mode 100755 new mode 100644 similarity index 82% rename from applications/picopass/scenes/picopass_scene_config.h rename to applications/plugins/picopass/scenes/picopass_scene_config.h index 87745378b..27d6bbcd7 --- a/applications/picopass/scenes/picopass_scene_config.h +++ b/applications/plugins/picopass/scenes/picopass_scene_config.h @@ -9,3 +9,5 @@ ADD_SCENE(picopass, file_select, FileSelect) ADD_SCENE(picopass, device_info, DeviceInfo) ADD_SCENE(picopass, delete, Delete) ADD_SCENE(picopass, delete_success, DeleteSuccess) +ADD_SCENE(picopass, write_card, WriteCard) +ADD_SCENE(picopass, write_card_success, WriteCardSuccess) diff --git a/applications/picopass/scenes/picopass_scene_delete.c b/applications/plugins/picopass/scenes/picopass_scene_delete.c similarity index 100% rename from applications/picopass/scenes/picopass_scene_delete.c rename to applications/plugins/picopass/scenes/picopass_scene_delete.c diff --git a/applications/picopass/scenes/picopass_scene_delete_success.c b/applications/plugins/picopass/scenes/picopass_scene_delete_success.c old mode 100755 new mode 100644 similarity index 100% rename from applications/picopass/scenes/picopass_scene_delete_success.c rename to applications/plugins/picopass/scenes/picopass_scene_delete_success.c diff --git a/applications/picopass/scenes/picopass_scene_device_info.c b/applications/plugins/picopass/scenes/picopass_scene_device_info.c similarity index 100% rename from applications/picopass/scenes/picopass_scene_device_info.c rename to applications/plugins/picopass/scenes/picopass_scene_device_info.c diff --git a/applications/picopass/scenes/picopass_scene_file_select.c b/applications/plugins/picopass/scenes/picopass_scene_file_select.c similarity index 95% rename from applications/picopass/scenes/picopass_scene_file_select.c rename to applications/plugins/picopass/scenes/picopass_scene_file_select.c index b3d4c3d73..2fc64746e 100644 --- a/applications/picopass/scenes/picopass_scene_file_select.c +++ b/applications/plugins/picopass/scenes/picopass_scene_file_select.c @@ -1,5 +1,5 @@ #include "../picopass_i.h" -#include "picopass/picopass_device.h" +#include "../picopass_device.h" void picopass_scene_file_select_on_enter(void* context) { Picopass* picopass = context; diff --git a/applications/picopass/scenes/picopass_scene_read_card.c b/applications/plugins/picopass/scenes/picopass_scene_read_card.c similarity index 95% rename from applications/picopass/scenes/picopass_scene_read_card.c rename to applications/plugins/picopass/scenes/picopass_scene_read_card.c index 0867898a5..8188207a2 100644 --- a/applications/picopass/scenes/picopass_scene_read_card.c +++ b/applications/plugins/picopass/scenes/picopass_scene_read_card.c @@ -37,8 +37,6 @@ bool picopass_scene_read_card_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(picopass->scene_manager, PicopassSceneReadCardSuccess); consumed = true; } - } else if(event.type == SceneManagerEventTypeTick) { - consumed = true; } return consumed; } diff --git a/applications/picopass/scenes/picopass_scene_read_card_success.c b/applications/plugins/picopass/scenes/picopass_scene_read_card_success.c similarity index 56% rename from applications/picopass/scenes/picopass_scene_read_card_success.c rename to applications/plugins/picopass/scenes/picopass_scene_read_card_success.c index 3866d201c..785f3a7dd 100644 --- a/applications/picopass/scenes/picopass_scene_read_card_success.c +++ b/applications/plugins/picopass/scenes/picopass_scene_read_card_success.c @@ -17,8 +17,10 @@ void picopass_scene_read_card_success_on_enter(void* context) { Picopass* picopass = context; string_t credential_str; string_t wiegand_str; + string_t sio_str; string_init(credential_str); string_init(wiegand_str); + string_init(sio_str); DOLPHIN_DEED(DolphinDeedNfcReadSuccess); @@ -29,40 +31,63 @@ void picopass_scene_read_card_success_on_enter(void* context) { PicopassPacs* pacs = &picopass->dev->dev_data.pacs; Widget* widget = picopass->widget; - size_t bytesLength = 1 + pacs->record.bitLength / 8; - string_set_str(credential_str, ""); - for(uint8_t i = PICOPASS_BLOCK_LEN - bytesLength; i < PICOPASS_BLOCK_LEN; i++) { - string_cat_printf(credential_str, " %02X", pacs->credential[i]); - } + if(pacs->record.bitLength == 0) { + string_cat_printf(wiegand_str, "Read Failed"); + + if(pacs->se_enabled) { + string_cat_printf(credential_str, "SE enabled"); + } + + widget_add_button_element( + widget, + GuiButtonTypeLeft, + "Retry", + picopass_scene_read_card_success_widget_callback, + picopass); - if(pacs->record.valid) { - string_cat_printf( - wiegand_str, "FC: %u CN: %u", pacs->record.FacilityCode, pacs->record.CardNumber); } else { - string_cat_printf(wiegand_str, "%d bits", pacs->record.bitLength); + size_t bytesLength = 1 + pacs->record.bitLength / 8; + string_set_str(credential_str, ""); + for(uint8_t i = PICOPASS_BLOCK_LEN - bytesLength; i < PICOPASS_BLOCK_LEN; i++) { + string_cat_printf(credential_str, " %02X", pacs->credential[i]); + } + + if(pacs->record.valid) { + string_cat_printf( + wiegand_str, "FC: %u CN: %u", pacs->record.FacilityCode, pacs->record.CardNumber); + } else { + string_cat_printf(wiegand_str, "%d bits", pacs->record.bitLength); + } + + if(pacs->sio) { + string_cat_printf(sio_str, "+SIO"); + } + + widget_add_button_element( + widget, + GuiButtonTypeLeft, + "Retry", + picopass_scene_read_card_success_widget_callback, + picopass); + + widget_add_button_element( + widget, + GuiButtonTypeRight, + "More", + picopass_scene_read_card_success_widget_callback, + picopass); } - widget_add_button_element( - widget, - GuiButtonTypeLeft, - "Retry", - picopass_scene_read_card_success_widget_callback, - picopass); - - widget_add_button_element( - widget, - GuiButtonTypeRight, - "More", - picopass_scene_read_card_success_widget_callback, - picopass); - widget_add_string_element( widget, 64, 12, AlignCenter, AlignCenter, FontPrimary, string_get_cstr(wiegand_str)); widget_add_string_element( widget, 64, 32, AlignCenter, AlignCenter, FontSecondary, string_get_cstr(credential_str)); + widget_add_string_element( + widget, 64, 42, AlignCenter, AlignCenter, FontSecondary, string_get_cstr(sio_str)); string_clear(credential_str); string_clear(wiegand_str); + string_clear(sio_str); view_dispatcher_switch_to_view(picopass->view_dispatcher, PicopassViewWidget); } diff --git a/applications/picopass/scenes/picopass_scene_save_name.c b/applications/plugins/picopass/scenes/picopass_scene_save_name.c similarity index 100% rename from applications/picopass/scenes/picopass_scene_save_name.c rename to applications/plugins/picopass/scenes/picopass_scene_save_name.c diff --git a/applications/picopass/scenes/picopass_scene_save_success.c b/applications/plugins/picopass/scenes/picopass_scene_save_success.c similarity index 100% rename from applications/picopass/scenes/picopass_scene_save_success.c rename to applications/plugins/picopass/scenes/picopass_scene_save_success.c diff --git a/applications/picopass/scenes/picopass_scene_saved_menu.c b/applications/plugins/picopass/scenes/picopass_scene_saved_menu.c similarity index 85% rename from applications/picopass/scenes/picopass_scene_saved_menu.c rename to applications/plugins/picopass/scenes/picopass_scene_saved_menu.c index 8f0ce40ba..90a27ee81 100644 --- a/applications/picopass/scenes/picopass_scene_saved_menu.c +++ b/applications/plugins/picopass/scenes/picopass_scene_saved_menu.c @@ -24,6 +24,8 @@ void picopass_scene_saved_menu_on_enter(void* context) { picopass); submenu_add_item( submenu, "Info", SubmenuIndexInfo, picopass_scene_saved_menu_submenu_callback, picopass); + submenu_add_item( + submenu, "Write", SubmenuIndexWrite, picopass_scene_saved_menu_submenu_callback, picopass); submenu_set_selected_item( picopass->submenu, @@ -46,6 +48,9 @@ bool picopass_scene_saved_menu_on_event(void* context, SceneManagerEvent event) } else if(event.event == SubmenuIndexInfo) { scene_manager_next_scene(picopass->scene_manager, PicopassSceneDeviceInfo); consumed = true; + } else if(event.event == SubmenuIndexWrite) { + scene_manager_next_scene(picopass->scene_manager, PicopassSceneWriteCard); + consumed = true; } } diff --git a/applications/picopass/scenes/picopass_scene_start.c b/applications/plugins/picopass/scenes/picopass_scene_start.c similarity index 100% rename from applications/picopass/scenes/picopass_scene_start.c rename to applications/plugins/picopass/scenes/picopass_scene_start.c diff --git a/applications/plugins/picopass/scenes/picopass_scene_write_card.c b/applications/plugins/picopass/scenes/picopass_scene_write_card.c new file mode 100644 index 000000000..a905dca95 --- /dev/null +++ b/applications/plugins/picopass/scenes/picopass_scene_write_card.c @@ -0,0 +1,53 @@ +#include "../picopass_i.h" +#include + +void picopass_write_card_worker_callback(PicopassWorkerEvent event, void* context) { + UNUSED(event); + Picopass* picopass = context; + view_dispatcher_send_custom_event(picopass->view_dispatcher, PicopassCustomEventWorkerExit); +} + +void picopass_scene_write_card_on_enter(void* context) { + Picopass* picopass = context; + DOLPHIN_DEED(DolphinDeedNfcSave); + + // Setup view + Popup* popup = picopass->popup; + popup_set_header(popup, "Writing\npicopass\ncard", 68, 30, AlignLeft, AlignTop); + popup_set_icon(popup, 0, 3, &I_RFIDDolphinSend_97x61); + + // Start worker + view_dispatcher_switch_to_view(picopass->view_dispatcher, PicopassViewPopup); + picopass_worker_start( + picopass->worker, + PicopassWorkerStateWrite, + &picopass->dev->dev_data, + picopass_write_card_worker_callback, + picopass); + + picopass_blink_start(picopass); +} + +bool picopass_scene_write_card_on_event(void* context, SceneManagerEvent event) { + Picopass* picopass = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == PicopassCustomEventWorkerExit) { + scene_manager_next_scene(picopass->scene_manager, PicopassSceneWriteCardSuccess); + consumed = true; + } + } + return consumed; +} + +void picopass_scene_write_card_on_exit(void* context) { + Picopass* picopass = context; + + // Stop worker + picopass_worker_stop(picopass->worker); + // Clear view + popup_reset(picopass->popup); + + picopass_blink_stop(picopass); +} diff --git a/applications/plugins/picopass/scenes/picopass_scene_write_card_success.c b/applications/plugins/picopass/scenes/picopass_scene_write_card_success.c new file mode 100644 index 000000000..108e7d1ce --- /dev/null +++ b/applications/plugins/picopass/scenes/picopass_scene_write_card_success.c @@ -0,0 +1,57 @@ +#include "../picopass_i.h" +#include + +void picopass_scene_write_card_success_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + furi_assert(context); + Picopass* picopass = context; + + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(picopass->view_dispatcher, result); + } +} + +void picopass_scene_write_card_success_on_enter(void* context) { + Picopass* picopass = context; + Widget* widget = picopass->widget; + + DOLPHIN_DEED(DolphinDeedNfcReadSuccess); + + // Send notification + notification_message(picopass->notifications, &sequence_success); + + widget_add_button_element( + widget, + GuiButtonTypeLeft, + "Retry", + picopass_scene_write_card_success_widget_callback, + picopass); + + view_dispatcher_switch_to_view(picopass->view_dispatcher, PicopassViewWidget); +} + +bool picopass_scene_write_card_success_on_event(void* context, SceneManagerEvent event) { + Picopass* picopass = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeLeft) { + consumed = scene_manager_previous_scene(picopass->scene_manager); + } else if(event.event == GuiButtonTypeRight) { + // Clear device name + picopass_device_set_name(picopass->dev, ""); + scene_manager_next_scene(picopass->scene_manager, PicopassSceneCardMenu); + consumed = true; + } + } + return consumed; +} + +void picopass_scene_write_card_success_on_exit(void* context) { + Picopass* picopass = context; + + // Clear view + widget_reset(picopass->widget); +} diff --git a/applications/snake_game/application.fam b/applications/plugins/snake_game/application.fam similarity index 79% rename from applications/snake_game/application.fam rename to applications/plugins/snake_game/application.fam index 5d6ad5276..d55f53bb1 100644 --- a/applications/snake_game/application.fam +++ b/applications/plugins/snake_game/application.fam @@ -6,6 +6,7 @@ App( cdefines=["APP_SNAKE_GAME"], requires=["gui"], stack_size=1 * 1024, - icon="A_Plugins_14", order=30, + fap_icon="snake_10px.png", + fap_category="Games", ) diff --git a/applications/plugins/snake_game/snake_10px.png b/applications/plugins/snake_game/snake_10px.png new file mode 100644 index 000000000..52d9fa7e0 Binary files /dev/null and b/applications/plugins/snake_game/snake_10px.png differ diff --git a/applications/snake_game/snake_game.c b/applications/plugins/snake_game/snake_game.c similarity index 100% rename from applications/snake_game/snake_game.c rename to applications/plugins/snake_game/snake_game.c diff --git a/applications/power/application.fam b/applications/power/application.fam deleted file mode 100644 index 1e503749a..000000000 --- a/applications/power/application.fam +++ /dev/null @@ -1,53 +0,0 @@ -App( - appid="power", - name="PowerSrv", - apptype=FlipperAppType.SERVICE, - entry_point="power_srv", - cdefines=["SRV_POWER"], - requires=[ - "gui", - "cli", - ], - provides=[ - "power_settings", - "power_start", - ], - stack_size=1 * 1024, - order=110, -) - -App( - appid="power_settings", - name="Power", - apptype=FlipperAppType.SETTINGS, - entry_point="power_settings_app", - requires=[ - "gui", - "power", - ], - flags=["InsomniaSafe"], - stack_size=1 * 1024, - order=40, -) - -App( - appid="power_start", - apptype=FlipperAppType.STARTUP, - entry_point="power_on_system_start", - requires=["power"], - order=80, -) - -App( - appid="battery_test", - name="Battery Test", - apptype=FlipperAppType.DEBUG, - entry_point="battery_test_app", - cdefines=["APP_BATTERY_TEST"], - requires=[ - "gui", - "power", - ], - stack_size=1 * 1024, - order=130, -) diff --git a/applications/power/power_cli.h b/applications/power/power_cli.h deleted file mode 100644 index ef55d869c..000000000 --- a/applications/power/power_cli.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -void power_on_system_start(); diff --git a/applications/rpc/application.fam b/applications/rpc/application.fam deleted file mode 100644 index 683396e32..000000000 --- a/applications/rpc/application.fam +++ /dev/null @@ -1,12 +0,0 @@ -App( - appid="rpc", - name="RpcSrv", - apptype=FlipperAppType.SERVICE, - entry_point="rpc_srv", - cdefines=["SRV_RPC"], - requires=[ - "cli", - ], - stack_size=4 * 1024, - order=10, -) diff --git a/applications/services/application.fam b/applications/services/application.fam new file mode 100644 index 000000000..aec49b231 --- /dev/null +++ b/applications/services/application.fam @@ -0,0 +1,13 @@ +App( + appid="basic_services", + name="Basic services", + apptype=FlipperAppType.METAPACKAGE, + provides=[ + "crypto_start", + "rpc_start", + "bt", + "desktop", + "loader", + "power", + ], +) diff --git a/applications/applications.h b/applications/services/applications.h similarity index 100% rename from applications/applications.h rename to applications/services/applications.h diff --git a/applications/services/bt/application.fam b/applications/services/bt/application.fam new file mode 100644 index 000000000..2e97dc1d6 --- /dev/null +++ b/applications/services/bt/application.fam @@ -0,0 +1,25 @@ +App( + appid="bt", + name="BtSrv", + apptype=FlipperAppType.SERVICE, + entry_point="bt_srv", + cdefines=["SRV_BT"], + requires=[ + "cli", + "dialogs", + ], + provides=[ + "bt_start", + "bt_settings", + ], + stack_size=1 * 1024, + order=20, + sdk_headers=["bt_service/bt.h"], +) + +App( + appid="bt_start", + apptype=FlipperAppType.STARTUP, + entry_point="bt_on_system_start", + order=70, +) diff --git a/applications/bt/bt_cli.c b/applications/services/bt/bt_cli.c similarity index 99% rename from applications/bt/bt_cli.c rename to applications/services/bt/bt_cli.c index 79500fac4..ff5ebb448 100644 --- a/applications/bt/bt_cli.c +++ b/applications/services/bt/bt_cli.c @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include diff --git a/applications/bt/bt_service/bt.c b/applications/services/bt/bt_service/bt.c similarity index 100% rename from applications/bt/bt_service/bt.c rename to applications/services/bt/bt_service/bt.c diff --git a/applications/bt/bt_service/bt.h b/applications/services/bt/bt_service/bt.h similarity index 100% rename from applications/bt/bt_service/bt.h rename to applications/services/bt/bt_service/bt.h diff --git a/applications/bt/bt_service/bt_api.c b/applications/services/bt/bt_service/bt_api.c similarity index 100% rename from applications/bt/bt_service/bt_api.c rename to applications/services/bt/bt_service/bt_api.c diff --git a/applications/bt/bt_service/bt_i.h b/applications/services/bt/bt_service/bt_i.h similarity index 92% rename from applications/bt/bt_service/bt_i.h rename to applications/services/bt/bt_service/bt_i.h index a45a36c9e..5769243ec 100644 --- a/applications/bt/bt_service/bt_i.h +++ b/applications/services/bt/bt_service/bt_i.h @@ -11,10 +11,10 @@ #include #include -#include -#include +#include +#include -#include "../bt_settings.h" +#include #define BT_API_UNLOCK_EVENT (1UL << 0) diff --git a/applications/bt/bt_service/bt_keys_filename.h b/applications/services/bt/bt_service/bt_keys_filename.h similarity index 100% rename from applications/bt/bt_service/bt_keys_filename.h rename to applications/services/bt/bt_service/bt_keys_filename.h diff --git a/applications/bt/bt_service/bt_keys_storage.c b/applications/services/bt/bt_service/bt_keys_storage.c similarity index 100% rename from applications/bt/bt_service/bt_keys_storage.c rename to applications/services/bt/bt_service/bt_keys_storage.c diff --git a/applications/bt/bt_service/bt_keys_storage.h b/applications/services/bt/bt_service/bt_keys_storage.h similarity index 100% rename from applications/bt/bt_service/bt_keys_storage.h rename to applications/services/bt/bt_service/bt_keys_storage.h diff --git a/applications/bt/bt_settings.c b/applications/services/bt/bt_settings.c similarity index 100% rename from applications/bt/bt_settings.c rename to applications/services/bt/bt_settings.c diff --git a/applications/bt/bt_settings.h b/applications/services/bt/bt_settings.h similarity index 100% rename from applications/bt/bt_settings.h rename to applications/services/bt/bt_settings.h diff --git a/applications/bt/bt_settings_filename.h b/applications/services/bt/bt_settings_filename.h similarity index 100% rename from applications/bt/bt_settings_filename.h rename to applications/services/bt/bt_settings_filename.h diff --git a/applications/cli/application.fam b/applications/services/cli/application.fam similarity index 81% rename from applications/cli/application.fam rename to applications/services/cli/application.fam index 73c70aa44..7a57bb607 100644 --- a/applications/cli/application.fam +++ b/applications/services/cli/application.fam @@ -6,4 +6,5 @@ App( cdefines=["SRV_CLI"], stack_size=4 * 1024, order=30, + sdk_headers=["cli.h", "cli_vcp.h"], ) diff --git a/applications/cli/cli.c b/applications/services/cli/cli.c similarity index 100% rename from applications/cli/cli.c rename to applications/services/cli/cli.c diff --git a/applications/cli/cli.h b/applications/services/cli/cli.h similarity index 100% rename from applications/cli/cli.h rename to applications/services/cli/cli.h diff --git a/applications/cli/cli_command_gpio.c b/applications/services/cli/cli_command_gpio.c similarity index 100% rename from applications/cli/cli_command_gpio.c rename to applications/services/cli/cli_command_gpio.c diff --git a/applications/cli/cli_command_gpio.h b/applications/services/cli/cli_command_gpio.h similarity index 100% rename from applications/cli/cli_command_gpio.h rename to applications/services/cli/cli_command_gpio.h diff --git a/applications/cli/cli_commands.c b/applications/services/cli/cli_commands.c similarity index 98% rename from applications/cli/cli_commands.c rename to applications/services/cli/cli_commands.c index 177a274a1..a6dd672fc 100644 --- a/applications/cli/cli_commands.c +++ b/applications/services/cli/cli_commands.c @@ -281,6 +281,9 @@ void cli_command_free(Cli* cli, string_t args, void* context) { printf("Total heap size: %d\r\n", memmgr_get_total_heap()); printf("Minimum heap size: %d\r\n", memmgr_get_minimum_free_heap()); printf("Maximum heap block: %d\r\n", memmgr_heap_get_max_free_block()); + + printf("Pool free: %d\r\n", memmgr_pool_get_free()); + printf("Maximum pool block: %d\r\n", memmgr_pool_get_max_block()); } void cli_command_free_blocks(Cli* cli, string_t args, void* context) { diff --git a/applications/cli/cli_commands.h b/applications/services/cli/cli_commands.h similarity index 100% rename from applications/cli/cli_commands.h rename to applications/services/cli/cli_commands.h diff --git a/applications/cli/cli_i.h b/applications/services/cli/cli_i.h old mode 100755 new mode 100644 similarity index 92% rename from applications/cli/cli_i.h rename to applications/services/cli/cli_i.h index 8f0bd85d5..ba4582d0d --- a/applications/cli/cli_i.h +++ b/applications/services/cli/cli_i.h @@ -9,17 +9,21 @@ #include #include +#include "cli_vcp.h" + #define CLI_LINE_SIZE_MAX #define CLI_COMMANDS_TREE_RANK 4 +#ifdef __cplusplus +extern "C" { +#endif + typedef struct { CliCallback callback; void* context; uint32_t flags; } CliCommand; -typedef struct CliSession CliSession; - struct CliSession { void (*init)(void); void (*deinit)(void); @@ -57,3 +61,7 @@ void cli_reset(Cli* cli); void cli_putc(Cli* cli, char c); void cli_stdout_callback(void* _cookie, const char* data, size_t size); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/applications/cli/cli_vcp.c b/applications/services/cli/cli_vcp.c similarity index 99% rename from applications/cli/cli_vcp.c rename to applications/services/cli/cli_vcp.c index 5a8b44dcf..f2893a48b 100644 --- a/applications/cli/cli_vcp.c +++ b/applications/services/cli/cli_vcp.c @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/applications/cli/cli_vcp.h b/applications/services/cli/cli_vcp.h similarity index 80% rename from applications/cli/cli_vcp.h rename to applications/services/cli/cli_vcp.h index 2bd47efb2..3aef2ef70 100644 --- a/applications/cli/cli_vcp.h +++ b/applications/services/cli/cli_vcp.h @@ -5,12 +5,12 @@ #pragma once -#include "cli_i.h" - #ifdef __cplusplus extern "C" { #endif +typedef struct CliSession CliSession; + extern CliSession cli_vcp; #ifdef __cplusplus diff --git a/applications/crypto/application.fam b/applications/services/crypto/application.fam similarity index 100% rename from applications/crypto/application.fam rename to applications/services/crypto/application.fam diff --git a/applications/crypto/crypto_cli.c b/applications/services/crypto/crypto_cli.c similarity index 100% rename from applications/crypto/crypto_cli.c rename to applications/services/crypto/crypto_cli.c diff --git a/applications/desktop/animations/animation_manager.c b/applications/services/desktop/animations/animation_manager.c similarity index 100% rename from applications/desktop/animations/animation_manager.c rename to applications/services/desktop/animations/animation_manager.c diff --git a/applications/desktop/animations/animation_manager.h b/applications/services/desktop/animations/animation_manager.h similarity index 100% rename from applications/desktop/animations/animation_manager.h rename to applications/services/desktop/animations/animation_manager.h diff --git a/applications/desktop/animations/animation_storage.c b/applications/services/desktop/animations/animation_storage.c similarity index 100% rename from applications/desktop/animations/animation_storage.c rename to applications/services/desktop/animations/animation_storage.c diff --git a/applications/desktop/animations/animation_storage.h b/applications/services/desktop/animations/animation_storage.h similarity index 100% rename from applications/desktop/animations/animation_storage.h rename to applications/services/desktop/animations/animation_storage.h diff --git a/applications/desktop/animations/animation_storage_i.h b/applications/services/desktop/animations/animation_storage_i.h similarity index 100% rename from applications/desktop/animations/animation_storage_i.h rename to applications/services/desktop/animations/animation_storage_i.h diff --git a/applications/desktop/animations/views/bubble_animation_view.c b/applications/services/desktop/animations/views/bubble_animation_view.c similarity index 100% rename from applications/desktop/animations/views/bubble_animation_view.c rename to applications/services/desktop/animations/views/bubble_animation_view.c diff --git a/applications/desktop/animations/views/bubble_animation_view.h b/applications/services/desktop/animations/views/bubble_animation_view.h similarity index 100% rename from applications/desktop/animations/views/bubble_animation_view.h rename to applications/services/desktop/animations/views/bubble_animation_view.h diff --git a/applications/desktop/animations/views/one_shot_animation_view.c b/applications/services/desktop/animations/views/one_shot_animation_view.c similarity index 100% rename from applications/desktop/animations/views/one_shot_animation_view.c rename to applications/services/desktop/animations/views/one_shot_animation_view.c diff --git a/applications/desktop/animations/views/one_shot_animation_view.h b/applications/services/desktop/animations/views/one_shot_animation_view.h similarity index 100% rename from applications/desktop/animations/views/one_shot_animation_view.h rename to applications/services/desktop/animations/views/one_shot_animation_view.h diff --git a/applications/desktop/application.fam b/applications/services/desktop/application.fam similarity index 59% rename from applications/desktop/application.fam rename to applications/services/desktop/application.fam index 5f3dcdfda..da6e2b802 100644 --- a/applications/desktop/application.fam +++ b/applications/services/desktop/application.fam @@ -15,16 +15,3 @@ App( stack_size=2 * 1024, order=60, ) - -App( - appid="desktop_settings", - name="Desktop", - apptype=FlipperAppType.SETTINGS, - entry_point="desktop_settings_app", - requires=[ - "desktop", - "gui", - ], - stack_size=1 * 1024, - order=50, -) diff --git a/applications/desktop/desktop.c b/applications/services/desktop/desktop.c similarity index 86% rename from applications/desktop/desktop.c rename to applications/services/desktop/desktop.c index 578066a6a..b45a9d621 100644 --- a/applications/desktop/desktop.c +++ b/applications/services/desktop/desktop.c @@ -32,13 +32,18 @@ static void desktop_loader_callback(const void* message, void* context) { view_dispatcher_send_custom_event(desktop->view_dispatcher, DesktopGlobalAfterAppFinished); } } - -static void desktop_lock_icon_callback(Canvas* canvas, void* context) { +static void desktop_lock_icon_draw_callback(Canvas* canvas, void* context) { UNUSED(context); furi_assert(canvas); canvas_draw_icon(canvas, 0, 0, &I_Lock_8x8); } +static void desktop_dummy_mode_icon_draw_callback(Canvas* canvas, void* context) { + UNUSED(context); + furi_assert(canvas); + canvas_draw_icon(canvas, 0, 0, &I_GameMode_11x8); +} + static bool desktop_custom_event_callback(void* context, uint32_t event) { furi_assert(context); Desktop* desktop = (Desktop*)context; @@ -52,7 +57,7 @@ static bool desktop_custom_event_callback(void* context, uint32_t event) { animation_manager_load_and_continue_animation(desktop->animation_manager); // TODO: Implement a message mechanism for loading settings and (optionally) // locking and unlocking - LOAD_DESKTOP_SETTINGS(&desktop->settings); + DESKTOP_SETTINGS_LOAD(&desktop->settings); desktop_auto_lock_arm(desktop); return true; case DesktopGlobalAutoLock: @@ -127,7 +132,7 @@ void desktop_lock(Desktop* desktop) { } void desktop_unlock(Desktop* desktop) { - view_port_enabled_set(desktop->lock_viewport, false); + view_port_enabled_set(desktop->lock_icon_viewport, false); Gui* gui = furi_record_open(RECORD_GUI); gui_set_lockdown(gui, false); furi_record_close(RECORD_GUI); @@ -136,6 +141,13 @@ void desktop_unlock(Desktop* desktop) { desktop_auto_lock_arm(desktop); } +void desktop_set_dummy_mode_state(Desktop* desktop, bool enabled) { + view_port_enabled_set(desktop->dummy_mode_icon_viewport, enabled); + desktop_main_set_dummy_mode_state(desktop->main_view, enabled); + desktop->settings.dummy_mode = enabled; + DESKTOP_SETTINGS_SAVE(&desktop->settings); +} + Desktop* desktop_alloc() { Desktop* desktop = malloc(sizeof(Desktop)); @@ -212,11 +224,20 @@ Desktop* desktop_alloc() { desktop_view_slideshow_get_view(desktop->slideshow_view)); // Lock icon - desktop->lock_viewport = view_port_alloc(); - view_port_set_width(desktop->lock_viewport, icon_get_width(&I_Lock_8x8)); - view_port_draw_callback_set(desktop->lock_viewport, desktop_lock_icon_callback, desktop); - view_port_enabled_set(desktop->lock_viewport, false); - gui_add_view_port(desktop->gui, desktop->lock_viewport, GuiLayerStatusBarLeft); + desktop->lock_icon_viewport = view_port_alloc(); + view_port_set_width(desktop->lock_icon_viewport, icon_get_width(&I_Lock_8x8)); + view_port_draw_callback_set( + desktop->lock_icon_viewport, desktop_lock_icon_draw_callback, desktop); + view_port_enabled_set(desktop->lock_icon_viewport, false); + gui_add_view_port(desktop->gui, desktop->lock_icon_viewport, GuiLayerStatusBarLeft); + + // Dummy mode icon + desktop->dummy_mode_icon_viewport = view_port_alloc(); + view_port_set_width(desktop->dummy_mode_icon_viewport, icon_get_width(&I_GameMode_11x8)); + view_port_draw_callback_set( + desktop->dummy_mode_icon_viewport, desktop_dummy_mode_icon_draw_callback, desktop); + view_port_enabled_set(desktop->dummy_mode_icon_viewport, false); + gui_add_view_port(desktop->gui, desktop->dummy_mode_icon_viewport, GuiLayerStatusBarLeft); // Special case: autostart application is already running desktop->loader = furi_record_open(RECORD_LOADER); @@ -301,12 +322,15 @@ int32_t desktop_srv(void* p) { UNUSED(p); Desktop* desktop = desktop_alloc(); - bool loaded = LOAD_DESKTOP_SETTINGS(&desktop->settings); + bool loaded = DESKTOP_SETTINGS_LOAD(&desktop->settings); if(!loaded) { memset(&desktop->settings, 0, sizeof(desktop->settings)); - SAVE_DESKTOP_SETTINGS(&desktop->settings); + DESKTOP_SETTINGS_SAVE(&desktop->settings); } + view_port_enabled_set(desktop->dummy_mode_icon_viewport, desktop->settings.dummy_mode); + desktop_main_set_dummy_mode_state(desktop->main_view, desktop->settings.dummy_mode); + scene_manager_next_scene(desktop->scene_manager, DesktopSceneMain); desktop_pin_lock_init(&desktop->settings); diff --git a/applications/desktop/desktop.h b/applications/services/desktop/desktop.h similarity index 100% rename from applications/desktop/desktop.h rename to applications/services/desktop/desktop.h diff --git a/applications/desktop/desktop_i.h b/applications/services/desktop/desktop_i.h similarity index 91% rename from applications/desktop/desktop_i.h rename to applications/services/desktop/desktop_i.h index 0b5d607d1..8034bbc3a 100644 --- a/applications/desktop/desktop_i.h +++ b/applications/services/desktop/desktop_i.h @@ -9,7 +9,7 @@ #include "views/desktop_view_lock_menu.h" #include "views/desktop_view_debug.h" #include "views/desktop_view_slideshow.h" -#include "desktop/desktop_settings/desktop_settings.h" +#include #include #include @@ -57,7 +57,8 @@ struct Desktop { DesktopSettings settings; DesktopViewPinInput* pin_input_view; - ViewPort* lock_viewport; + ViewPort* lock_icon_viewport; + ViewPort* dummy_mode_icon_viewport; AnimationManager* animation_manager; @@ -75,3 +76,4 @@ Desktop* desktop_alloc(); void desktop_free(Desktop* desktop); void desktop_lock(Desktop* desktop); void desktop_unlock(Desktop* desktop); +void desktop_set_dummy_mode_state(Desktop* desktop, bool enabled); diff --git a/applications/desktop/desktop_settings/desktop_settings.h b/applications/services/desktop/desktop_settings.h similarity index 89% rename from applications/desktop/desktop_settings/desktop_settings.h rename to applications/services/desktop/desktop_settings.h index 800847d56..3b10fbb17 100644 --- a/applications/desktop/desktop_settings/desktop_settings.h +++ b/applications/services/desktop/desktop_settings.h @@ -8,7 +8,7 @@ #include #include -#define DESKTOP_SETTINGS_VER (4) +#define DESKTOP_SETTINGS_VER (5) #define DESKTOP_SETTINGS_PATH INT_PATH(DESKTOP_SETTINGS_FILE_NAME) #define DESKTOP_SETTINGS_MAGIC (0x17) @@ -16,7 +16,7 @@ #define DESKTOP_SETTINGS_RUN_PIN_SETUP_ARG "run_pin_setup" -#define SAVE_DESKTOP_SETTINGS(x) \ +#define DESKTOP_SETTINGS_SAVE(x) \ saved_struct_save( \ DESKTOP_SETTINGS_PATH, \ (x), \ @@ -24,7 +24,7 @@ DESKTOP_SETTINGS_MAGIC, \ DESKTOP_SETTINGS_VER) -#define LOAD_DESKTOP_SETTINGS(x) \ +#define DESKTOP_SETTINGS_LOAD(x) \ saved_struct_load( \ DESKTOP_SETTINGS_PATH, \ (x), \ @@ -46,4 +46,5 @@ typedef struct { PinCode pin_code; uint8_t is_locked; uint32_t auto_lock_delay_ms; + uint8_t dummy_mode; } DesktopSettings; diff --git a/applications/desktop/desktop_settings/desktop_settings_filename.h b/applications/services/desktop/desktop_settings_filename.h similarity index 100% rename from applications/desktop/desktop_settings/desktop_settings_filename.h rename to applications/services/desktop/desktop_settings_filename.h diff --git a/applications/desktop/helpers/pin_lock.c b/applications/services/desktop/helpers/pin_lock.c similarity index 96% rename from applications/desktop/helpers/pin_lock.c rename to applications/services/desktop/helpers/pin_lock.c index 0495b675d..22fcabe7d 100644 --- a/applications/desktop/helpers/pin_lock.c +++ b/applications/services/desktop/helpers/pin_lock.c @@ -8,6 +8,7 @@ #include "../helpers/pin_lock.h" #include "../desktop_i.h" +#include #include static const NotificationSequence sequence_pin_fail = { @@ -71,7 +72,7 @@ void desktop_pin_lock(DesktopSettings* settings) { cli_session_close(cli); furi_record_close(RECORD_CLI); settings->is_locked = 1; - SAVE_DESKTOP_SETTINGS(settings); + DESKTOP_SETTINGS_SAVE(settings); } void desktop_pin_unlock(DesktopSettings* settings) { @@ -82,7 +83,7 @@ void desktop_pin_unlock(DesktopSettings* settings) { cli_session_open(cli, &cli_vcp); furi_record_close(RECORD_CLI); settings->is_locked = 0; - SAVE_DESKTOP_SETTINGS(settings); + DESKTOP_SETTINGS_SAVE(settings); } void desktop_pin_lock_init(DesktopSettings* settings) { @@ -94,7 +95,7 @@ void desktop_pin_lock_init(DesktopSettings* settings) { } else { if(desktop_pin_lock_is_locked()) { settings->is_locked = 1; - SAVE_DESKTOP_SETTINGS(settings); + DESKTOP_SETTINGS_SAVE(settings); } } } else { diff --git a/applications/desktop/helpers/pin_lock.h b/applications/services/desktop/helpers/pin_lock.h similarity index 91% rename from applications/desktop/helpers/pin_lock.h rename to applications/services/desktop/helpers/pin_lock.h index 4454cda54..028ae6d22 100644 --- a/applications/desktop/helpers/pin_lock.h +++ b/applications/services/desktop/helpers/pin_lock.h @@ -2,7 +2,7 @@ #include #include #include "../desktop.h" -#include "../desktop_settings/desktop_settings.h" +#include void desktop_pin_lock_error_notify(); diff --git a/applications/desktop/helpers/slideshow.c b/applications/services/desktop/helpers/slideshow.c similarity index 100% rename from applications/desktop/helpers/slideshow.c rename to applications/services/desktop/helpers/slideshow.c diff --git a/applications/desktop/helpers/slideshow.h b/applications/services/desktop/helpers/slideshow.h similarity index 100% rename from applications/desktop/helpers/slideshow.h rename to applications/services/desktop/helpers/slideshow.h diff --git a/applications/desktop/helpers/slideshow_filename.h b/applications/services/desktop/helpers/slideshow_filename.h similarity index 100% rename from applications/desktop/helpers/slideshow_filename.h rename to applications/services/desktop/helpers/slideshow_filename.h diff --git a/applications/desktop/scenes/desktop_scene.c b/applications/services/desktop/scenes/desktop_scene.c similarity index 100% rename from applications/desktop/scenes/desktop_scene.c rename to applications/services/desktop/scenes/desktop_scene.c diff --git a/applications/desktop/scenes/desktop_scene.h b/applications/services/desktop/scenes/desktop_scene.h similarity index 100% rename from applications/desktop/scenes/desktop_scene.h rename to applications/services/desktop/scenes/desktop_scene.h diff --git a/applications/desktop/scenes/desktop_scene_config.h b/applications/services/desktop/scenes/desktop_scene_config.h similarity index 100% rename from applications/desktop/scenes/desktop_scene_config.h rename to applications/services/desktop/scenes/desktop_scene_config.h diff --git a/applications/desktop/scenes/desktop_scene_debug.c b/applications/services/desktop/scenes/desktop_scene_debug.c similarity index 100% rename from applications/desktop/scenes/desktop_scene_debug.c rename to applications/services/desktop/scenes/desktop_scene_debug.c diff --git a/applications/desktop/scenes/desktop_scene_fault.c b/applications/services/desktop/scenes/desktop_scene_fault.c similarity index 100% rename from applications/desktop/scenes/desktop_scene_fault.c rename to applications/services/desktop/scenes/desktop_scene_fault.c diff --git a/applications/desktop/scenes/desktop_scene_hw_mismatch.c b/applications/services/desktop/scenes/desktop_scene_hw_mismatch.c similarity index 100% rename from applications/desktop/scenes/desktop_scene_hw_mismatch.c rename to applications/services/desktop/scenes/desktop_scene_hw_mismatch.c diff --git a/applications/desktop/scenes/desktop_scene_i.h b/applications/services/desktop/scenes/desktop_scene_i.h similarity index 100% rename from applications/desktop/scenes/desktop_scene_i.h rename to applications/services/desktop/scenes/desktop_scene_i.h diff --git a/applications/desktop/scenes/desktop_scene_lock_menu.c b/applications/services/desktop/scenes/desktop_scene_lock_menu.c similarity index 75% rename from applications/desktop/scenes/desktop_scene_lock_menu.c rename to applications/services/desktop/scenes/desktop_scene_lock_menu.c index a86bb184b..365fe1702 100644 --- a/applications/desktop/scenes/desktop_scene_lock_menu.c +++ b/applications/services/desktop/scenes/desktop_scene_lock_menu.c @@ -6,7 +6,7 @@ #include #include "../desktop_i.h" -#include "../desktop_settings/desktop_settings.h" +#include #include "../views/desktop_view_lock_menu.h" #include "desktop_scene_i.h" #include "desktop_scene.h" @@ -22,10 +22,11 @@ void desktop_scene_lock_menu_callback(DesktopEvent event, void* context) { void desktop_scene_lock_menu_on_enter(void* context) { Desktop* desktop = (Desktop*)context; - LOAD_DESKTOP_SETTINGS(&desktop->settings); + DESKTOP_SETTINGS_LOAD(&desktop->settings); scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 0); desktop_lock_menu_set_callback(desktop->lock_menu, desktop_scene_lock_menu_callback, desktop); - desktop_lock_menu_pin_set(desktop->lock_menu, desktop->settings.pin_code.length > 0); + desktop_lock_menu_set_pin_state(desktop->lock_menu, desktop->settings.pin_code.length > 0); + desktop_lock_menu_set_dummy_mode_state(desktop->lock_menu, desktop->settings.dummy_mode); desktop_lock_menu_set_idx(desktop->lock_menu, 0); view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewIdLockMenu); @@ -39,9 +40,9 @@ bool desktop_scene_lock_menu_on_event(void* context, SceneManagerEvent event) { bool check_pin_changed = scene_manager_get_scene_state(desktop->scene_manager, DesktopSceneLockMenu); if(check_pin_changed) { - LOAD_DESKTOP_SETTINGS(&desktop->settings); + DESKTOP_SETTINGS_LOAD(&desktop->settings); if(desktop->settings.pin_code.length > 0) { - desktop_lock_menu_pin_set(desktop->lock_menu, 1); + desktop_lock_menu_set_pin_state(desktop->lock_menu, true); scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 0); } } @@ -67,15 +68,21 @@ bool desktop_scene_lock_menu_on_event(void* context, SceneManagerEvent event) { } consumed = true; break; - case DesktopLockMenuEventExit: - scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 0); + case DesktopLockMenuEventDummyModeOn: + desktop_set_dummy_mode_state(desktop, true); + scene_manager_search_and_switch_to_previous_scene( + desktop->scene_manager, DesktopSceneMain); + break; + case DesktopLockMenuEventDummyModeOff: + desktop_set_dummy_mode_state(desktop, false); scene_manager_search_and_switch_to_previous_scene( desktop->scene_manager, DesktopSceneMain); - consumed = true; break; default: break; } + } else if(event.type == SceneManagerEventTypeBack) { + scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 0); } return consumed; } diff --git a/applications/desktop/scenes/desktop_scene_locked.c b/applications/services/desktop/scenes/desktop_scene_locked.c similarity index 97% rename from applications/desktop/scenes/desktop_scene_locked.c rename to applications/services/desktop/scenes/desktop_scene_locked.c index c377d40ab..af19efc74 100644 --- a/applications/desktop/scenes/desktop_scene_locked.c +++ b/applications/services/desktop/scenes/desktop_scene_locked.c @@ -46,13 +46,13 @@ void desktop_scene_locked_on_enter(void* context) { uint32_t state = scene_manager_get_scene_state(desktop->scene_manager, DesktopSceneLocked); if(state == SCENE_LOCKED_FIRST_ENTER) { bool pin_locked = desktop_pin_lock_is_locked(); - view_port_enabled_set(desktop->lock_viewport, true); + view_port_enabled_set(desktop->lock_icon_viewport, true); Gui* gui = furi_record_open(RECORD_GUI); gui_set_lockdown(gui, true); furi_record_close(RECORD_GUI); if(pin_locked) { - LOAD_DESKTOP_SETTINGS(&desktop->settings); + DESKTOP_SETTINGS_LOAD(&desktop->settings); desktop_view_locked_lock(desktop->locked_view, true); uint32_t pin_timeout = desktop_pin_lock_get_fail_timeout(); if(pin_timeout > 0) { diff --git a/applications/desktop/scenes/desktop_scene_main.c b/applications/services/desktop/scenes/desktop_scene_main.c similarity index 89% rename from applications/desktop/scenes/desktop_scene_main.c rename to applications/services/desktop/scenes/desktop_scene_main.c index bc4101ffd..dc9ac04d0 100644 --- a/applications/desktop/scenes/desktop_scene_main.c +++ b/applications/services/desktop/scenes/desktop_scene_main.c @@ -113,7 +113,7 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) { } case DesktopMainEventOpenFavoritePrimary: - LOAD_DESKTOP_SETTINGS(&desktop->settings); + DESKTOP_SETTINGS_LOAD(&desktop->settings); if(desktop->settings.favorite_primary < FLIPPER_APPS_COUNT) { LoaderStatus status = loader_start( desktop->loader, FLIPPER_APPS[desktop->settings.favorite_primary].name, NULL); @@ -126,7 +126,7 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) { consumed = true; break; case DesktopMainEventOpenFavoriteSecondary: - LOAD_DESKTOP_SETTINGS(&desktop->settings); + DESKTOP_SETTINGS_LOAD(&desktop->settings); if(desktop->settings.favorite_secondary < FLIPPER_APPS_COUNT) { LoaderStatus status = loader_start( desktop->loader, @@ -157,6 +157,21 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) { } consumed = true; break; + case DesktopMainEventOpenPassport: { + LoaderStatus status = loader_start(desktop->loader, "Passport", NULL); + if(status != LoaderStatusOk) { + FURI_LOG_E(TAG, "loader_start failed: %d", status); + } + break; + } + case DesktopMainEventOpenGameMenu: { + LoaderStatus status = loader_start( + desktop->loader, "Applications", EXT_PATH("/apps/Games/snake_game.fap")); + if(status != LoaderStatusOk) { + FURI_LOG_E(TAG, "loader_start failed: %d", status); + } + break; + } case DesktopLockedEventUpdate: desktop_view_locked_update(desktop->locked_view); consumed = true; diff --git a/applications/desktop/scenes/desktop_scene_pin_input.c b/applications/services/desktop/scenes/desktop_scene_pin_input.c similarity index 100% rename from applications/desktop/scenes/desktop_scene_pin_input.c rename to applications/services/desktop/scenes/desktop_scene_pin_input.c diff --git a/applications/desktop/scenes/desktop_scene_pin_timeout.c b/applications/services/desktop/scenes/desktop_scene_pin_timeout.c similarity index 100% rename from applications/desktop/scenes/desktop_scene_pin_timeout.c rename to applications/services/desktop/scenes/desktop_scene_pin_timeout.c diff --git a/applications/desktop/scenes/desktop_scene_slideshow.c b/applications/services/desktop/scenes/desktop_scene_slideshow.c similarity index 100% rename from applications/desktop/scenes/desktop_scene_slideshow.c rename to applications/services/desktop/scenes/desktop_scene_slideshow.c diff --git a/applications/desktop/views/desktop_events.h b/applications/services/desktop/views/desktop_events.h similarity index 88% rename from applications/desktop/views/desktop_events.h rename to applications/services/desktop/views/desktop_events.h index 5d130be9b..a7e610fff 100644 --- a/applications/desktop/views/desktop_events.h +++ b/applications/services/desktop/views/desktop_events.h @@ -7,9 +7,11 @@ typedef enum { DesktopMainEventOpenFavoriteSecondary, DesktopMainEventOpenMenu, DesktopMainEventOpenDebug, - DesktopMainEventOpenPassport, /**< Broken, don't use it */ + DesktopMainEventOpenPassport, DesktopMainEventOpenPowerOff, + DesktopMainEventOpenGameMenu, + DesktopLockedEventUnlocked, DesktopLockedEventUpdate, DesktopLockedEventShowPinInput, @@ -28,7 +30,8 @@ typedef enum { DesktopLockMenuEventLock, DesktopLockMenuEventPinLock, - DesktopLockMenuEventExit, + DesktopLockMenuEventDummyModeOn, + DesktopLockMenuEventDummyModeOff, DesktopAnimationEventCheckAnimation, DesktopAnimationEventNewIdleAnimation, diff --git a/applications/desktop/views/desktop_view_debug.c b/applications/services/desktop/views/desktop_view_debug.c similarity index 100% rename from applications/desktop/views/desktop_view_debug.c rename to applications/services/desktop/views/desktop_view_debug.c diff --git a/applications/desktop/views/desktop_view_debug.h b/applications/services/desktop/views/desktop_view_debug.h similarity index 100% rename from applications/desktop/views/desktop_view_debug.h rename to applications/services/desktop/views/desktop_view_debug.h diff --git a/applications/services/desktop/views/desktop_view_lock_menu.c b/applications/services/desktop/views/desktop_view_lock_menu.c new file mode 100644 index 000000000..294191bf2 --- /dev/null +++ b/applications/services/desktop/views/desktop_view_lock_menu.c @@ -0,0 +1,160 @@ +#include +#include + +#include "../desktop_i.h" +#include "desktop_view_lock_menu.h" + +typedef enum { + DesktopLockMenuIndexLock, + DesktopLockMenuIndexPinLock, + DesktopLockMenuIndexDummy, + + DesktopLockMenuIndexTotalCount +} DesktopLockMenuIndex; + +void desktop_lock_menu_set_callback( + DesktopLockMenuView* lock_menu, + DesktopLockMenuViewCallback callback, + void* context) { + furi_assert(lock_menu); + furi_assert(callback); + lock_menu->callback = callback; + lock_menu->context = context; +} + +void desktop_lock_menu_set_pin_state(DesktopLockMenuView* lock_menu, bool pin_is_set) { + with_view_model( + lock_menu->view, (DesktopLockMenuViewModel * model) { + model->pin_is_set = pin_is_set; + return true; + }); +} + +void desktop_lock_menu_set_dummy_mode_state(DesktopLockMenuView* lock_menu, bool dummy_mode) { + with_view_model( + lock_menu->view, (DesktopLockMenuViewModel * model) { + model->dummy_mode = dummy_mode; + return true; + }); +} + +void desktop_lock_menu_set_idx(DesktopLockMenuView* lock_menu, uint8_t idx) { + furi_assert(idx < DesktopLockMenuIndexTotalCount); + with_view_model( + lock_menu->view, (DesktopLockMenuViewModel * model) { + model->idx = idx; + return true; + }); +} + +void desktop_lock_menu_draw_callback(Canvas* canvas, void* model) { + DesktopLockMenuViewModel* m = model; + + canvas_set_color(canvas, ColorBlack); + canvas_draw_icon(canvas, -57, 0 + STATUS_BAR_Y_SHIFT, &I_DoorLeft_70x55); + canvas_draw_icon(canvas, 116, 0 + STATUS_BAR_Y_SHIFT, &I_DoorRight_70x55); + canvas_set_font(canvas, FontSecondary); + + for(uint8_t i = 0; i < DesktopLockMenuIndexTotalCount; ++i) { + const char* str = NULL; + + if(i == DesktopLockMenuIndexLock) { + str = "Lock"; + } else if(i == DesktopLockMenuIndexPinLock) { + if(m->pin_is_set) { + str = "Lock with PIN"; + } else { + str = "Set PIN"; + } + } else if(i == DesktopLockMenuIndexDummy) { + if(m->dummy_mode) { + str = "Brainiac Mode"; + } else { + str = "Dummy Mode"; + } + } + + if(str) + canvas_draw_str_aligned( + canvas, 64, 9 + (i * 17) + STATUS_BAR_Y_SHIFT, AlignCenter, AlignCenter, str); + + if(m->idx == i) elements_frame(canvas, 15, 1 + (i * 17) + STATUS_BAR_Y_SHIFT, 98, 15); + } +} + +View* desktop_lock_menu_get_view(DesktopLockMenuView* lock_menu) { + furi_assert(lock_menu); + return lock_menu->view; +} + +bool desktop_lock_menu_input_callback(InputEvent* event, void* context) { + furi_assert(event); + furi_assert(context); + + DesktopLockMenuView* lock_menu = context; + uint8_t idx = 0; + bool consumed = false; + bool dummy_mode = false; + + with_view_model( + lock_menu->view, (DesktopLockMenuViewModel * model) { + bool ret = false; + if((event->type == InputTypeShort) || (event->type == InputTypeRepeat)) { + if(event->key == InputKeyUp) { + if(model->idx == 0) { + model->idx = DesktopLockMenuIndexTotalCount - 1; + } else { + model->idx = CLAMP(model->idx - 1, DesktopLockMenuIndexTotalCount - 1, 0); + } + ret = true; + consumed = true; + } else if(event->key == InputKeyDown) { + if(model->idx == DesktopLockMenuIndexTotalCount - 1) { + model->idx = 0; + } else { + model->idx = CLAMP(model->idx + 1, DesktopLockMenuIndexTotalCount - 1, 0); + } + ret = true; + consumed = true; + } + } + idx = model->idx; + dummy_mode = model->dummy_mode; + return ret; + }); + + if(event->key == InputKeyOk) { + if((idx == DesktopLockMenuIndexLock) && (event->type == InputTypeShort)) { + lock_menu->callback(DesktopLockMenuEventLock, lock_menu->context); + } else if((idx == DesktopLockMenuIndexPinLock) && (event->type == InputTypeShort)) { + lock_menu->callback(DesktopLockMenuEventPinLock, lock_menu->context); + } else if(idx == DesktopLockMenuIndexDummy) { + if((dummy_mode == false) && (event->type == InputTypeShort)) { + lock_menu->callback(DesktopLockMenuEventDummyModeOn, lock_menu->context); + } else if((dummy_mode == true) && (event->type == InputTypeShort)) { + lock_menu->callback(DesktopLockMenuEventDummyModeOff, lock_menu->context); + } + } + consumed = true; + } + + return consumed; +} + +DesktopLockMenuView* desktop_lock_menu_alloc() { + DesktopLockMenuView* lock_menu = malloc(sizeof(DesktopLockMenuView)); + lock_menu->view = view_alloc(); + view_allocate_model(lock_menu->view, ViewModelTypeLocking, sizeof(DesktopLockMenuViewModel)); + view_set_context(lock_menu->view, lock_menu); + view_set_draw_callback(lock_menu->view, (ViewDrawCallback)desktop_lock_menu_draw_callback); + view_set_input_callback(lock_menu->view, desktop_lock_menu_input_callback); + + return lock_menu; +} + +void desktop_lock_menu_free(DesktopLockMenuView* lock_menu_view) { + furi_assert(lock_menu_view); + + view_free(lock_menu_view->view); + free(lock_menu_view); +} diff --git a/applications/desktop/views/desktop_view_lock_menu.h b/applications/services/desktop/views/desktop_view_lock_menu.h similarity index 77% rename from applications/desktop/views/desktop_view_lock_menu.h rename to applications/services/desktop/views/desktop_view_lock_menu.h index e9928a385..812aa9f99 100644 --- a/applications/desktop/views/desktop_view_lock_menu.h +++ b/applications/services/desktop/views/desktop_view_lock_menu.h @@ -17,8 +17,8 @@ struct DesktopLockMenuView { typedef struct { uint8_t idx; - uint8_t hint_timeout; - bool pin_set; + bool pin_is_set; + bool dummy_mode; } DesktopLockMenuViewModel; void desktop_lock_menu_set_callback( @@ -27,7 +27,8 @@ void desktop_lock_menu_set_callback( void* context); View* desktop_lock_menu_get_view(DesktopLockMenuView* lock_menu); -void desktop_lock_menu_pin_set(DesktopLockMenuView* lock_menu, bool pin_is_set); +void desktop_lock_menu_set_pin_state(DesktopLockMenuView* lock_menu, bool pin_is_set); +void desktop_lock_menu_set_dummy_mode_state(DesktopLockMenuView* lock_menu, bool dummy_mode); void desktop_lock_menu_set_idx(DesktopLockMenuView* lock_menu, uint8_t idx); DesktopLockMenuView* desktop_lock_menu_alloc(); void desktop_lock_menu_free(DesktopLockMenuView* lock_menu); diff --git a/applications/desktop/views/desktop_view_locked.c b/applications/services/desktop/views/desktop_view_locked.c similarity index 99% rename from applications/desktop/views/desktop_view_locked.c rename to applications/services/desktop/views/desktop_view_locked.c index 58ed4face..915b26103 100644 --- a/applications/desktop/views/desktop_view_locked.c +++ b/applications/services/desktop/views/desktop_view_locked.c @@ -6,7 +6,7 @@ #include #include -#include "../desktop_settings/desktop_settings.h" +#include #include "../desktop_i.h" #include "desktop_view_locked.h" diff --git a/applications/desktop/views/desktop_view_locked.h b/applications/services/desktop/views/desktop_view_locked.h similarity index 94% rename from applications/desktop/views/desktop_view_locked.h rename to applications/services/desktop/views/desktop_view_locked.h index b0a0aa303..ea065e398 100644 --- a/applications/desktop/views/desktop_view_locked.h +++ b/applications/services/desktop/views/desktop_view_locked.h @@ -1,6 +1,6 @@ #pragma once -#include "../desktop_settings/desktop_settings.h" +#include #include "../views/desktop_events.h" #include diff --git a/applications/desktop/views/desktop_view_main.c b/applications/services/desktop/views/desktop_view_main.c similarity index 52% rename from applications/desktop/views/desktop_view_main.c rename to applications/services/desktop/views/desktop_view_main.c index 2b1d61f41..0edc0b703 100644 --- a/applications/desktop/views/desktop_view_main.c +++ b/applications/services/desktop/views/desktop_view_main.c @@ -14,6 +14,7 @@ struct DesktopMainView { DesktopMainViewCallback callback; void* context; TimerHandle_t poweroff_timer; + bool dummy_mode; }; #define DESKTOP_MAIN_VIEW_POWEROFF_TIMEOUT 5000 @@ -38,29 +39,48 @@ View* desktop_main_get_view(DesktopMainView* main_view) { return main_view->view; } -bool desktop_main_input(InputEvent* event, void* context) { +void desktop_main_set_dummy_mode_state(DesktopMainView* main_view, bool dummy_mode) { + furi_assert(main_view); + main_view->dummy_mode = dummy_mode; +} + +bool desktop_main_input_callback(InputEvent* event, void* context) { furi_assert(event); furi_assert(context); DesktopMainView* main_view = context; - if(event->type == InputTypeShort) { - if(event->key == InputKeyOk) { - main_view->callback(DesktopMainEventOpenMenu, main_view->context); - } else if(event->key == InputKeyUp) { - main_view->callback(DesktopMainEventOpenLockMenu, main_view->context); - } else if(event->key == InputKeyDown) { - main_view->callback(DesktopMainEventOpenArchive, main_view->context); - } else if(event->key == InputKeyLeft) { - main_view->callback(DesktopMainEventOpenFavoritePrimary, main_view->context); - } else if(event->key == InputKeyRight) { - main_view->callback(DesktopMainEventOpenPassport, main_view->context); + if(main_view->dummy_mode == false) { + if(event->type == InputTypeShort) { + if(event->key == InputKeyOk) { + main_view->callback(DesktopMainEventOpenMenu, main_view->context); + } else if(event->key == InputKeyUp) { + main_view->callback(DesktopMainEventOpenLockMenu, main_view->context); + } else if(event->key == InputKeyDown) { + main_view->callback(DesktopMainEventOpenArchive, main_view->context); + } else if(event->key == InputKeyLeft) { + main_view->callback(DesktopMainEventOpenFavoritePrimary, main_view->context); + } + // Right key is handled by animation manager + } else if(event->type == InputTypeLong) { + if(event->key == InputKeyDown) { + main_view->callback(DesktopMainEventOpenDebug, main_view->context); + } else if(event->key == InputKeyLeft) { + main_view->callback(DesktopMainEventOpenFavoriteSecondary, main_view->context); + } } - } else if(event->type == InputTypeLong) { - if(event->key == InputKeyDown) { - main_view->callback(DesktopMainEventOpenDebug, main_view->context); - } else if(event->key == InputKeyLeft) { - main_view->callback(DesktopMainEventOpenFavoriteSecondary, main_view->context); + } else { + if(event->type == InputTypeShort) { + if(event->key == InputKeyOk) { + main_view->callback(DesktopMainEventOpenGameMenu, main_view->context); + } else if(event->key == InputKeyUp) { + main_view->callback(DesktopMainEventOpenLockMenu, main_view->context); + } else if(event->key == InputKeyDown) { + main_view->callback(DesktopMainEventOpenPassport, main_view->context); + } else if(event->key == InputKeyLeft) { + main_view->callback(DesktopMainEventOpenPassport, main_view->context); + } + // Right key is handled by animation manager } } @@ -84,7 +104,7 @@ DesktopMainView* desktop_main_alloc() { main_view->view = view_alloc(); view_allocate_model(main_view->view, ViewModelTypeLockFree, 1); view_set_context(main_view->view, main_view); - view_set_input_callback(main_view->view, desktop_main_input); + view_set_input_callback(main_view->view, desktop_main_input_callback); main_view->poweroff_timer = xTimerCreate( NULL, diff --git a/applications/desktop/views/desktop_view_main.h b/applications/services/desktop/views/desktop_view_main.h similarity index 84% rename from applications/desktop/views/desktop_view_main.h rename to applications/services/desktop/views/desktop_view_main.h index 329d95486..b5492b1be 100644 --- a/applications/desktop/views/desktop_view_main.h +++ b/applications/services/desktop/views/desktop_view_main.h @@ -13,5 +13,6 @@ void desktop_main_set_callback( void* context); View* desktop_main_get_view(DesktopMainView* main_view); +void desktop_main_set_dummy_mode_state(DesktopMainView* main_view, bool dummy_mode); DesktopMainView* desktop_main_alloc(); void desktop_main_free(DesktopMainView* main_view); diff --git a/applications/desktop/views/desktop_view_pin_input.c b/applications/services/desktop/views/desktop_view_pin_input.c similarity index 99% rename from applications/desktop/views/desktop_view_pin_input.c rename to applications/services/desktop/views/desktop_view_pin_input.c index d6ce1a02a..bf05f06b9 100644 --- a/applications/desktop/views/desktop_view_pin_input.c +++ b/applications/services/desktop/views/desktop_view_pin_input.c @@ -6,7 +6,7 @@ #include #include "desktop_view_pin_input.h" -#include "../desktop_settings/desktop_settings.h" +#include #define NO_ACTIVITY_TIMEOUT 15000 @@ -117,7 +117,7 @@ static void desktop_view_pin_input_draw_cells(Canvas* canvas, DesktopViewPinInpu canvas_draw_icon(canvas, x + 3, y + 2, &I_Pin_arrow_down_7x9); break; case InputKeyUp: - canvas_draw_icon(canvas, x + 3, y + 2, &I_Pin_arrow_up7x9); + canvas_draw_icon(canvas, x + 3, y + 2, &I_Pin_arrow_up_7x9); break; case InputKeyLeft: canvas_draw_icon(canvas, x + 2, y + 3, &I_Pin_arrow_left_9x7); diff --git a/applications/desktop/views/desktop_view_pin_input.h b/applications/services/desktop/views/desktop_view_pin_input.h similarity index 96% rename from applications/desktop/views/desktop_view_pin_input.h rename to applications/services/desktop/views/desktop_view_pin_input.h index 3e39fd207..40eee4cc9 100644 --- a/applications/desktop/views/desktop_view_pin_input.h +++ b/applications/services/desktop/views/desktop_view_pin_input.h @@ -1,7 +1,7 @@ #pragma once #include -#include "desktop/desktop_settings/desktop_settings.h" +#include typedef void (*DesktopViewPinInputCallback)(void*); typedef void (*DesktopViewPinInputDoneCallback)(const PinCode* pin_code, void*); diff --git a/applications/desktop/views/desktop_view_pin_setup_done.c b/applications/services/desktop/views/desktop_view_pin_setup_done.c similarity index 100% rename from applications/desktop/views/desktop_view_pin_setup_done.c rename to applications/services/desktop/views/desktop_view_pin_setup_done.c diff --git a/applications/desktop/views/desktop_view_pin_setup_done.h b/applications/services/desktop/views/desktop_view_pin_setup_done.h similarity index 100% rename from applications/desktop/views/desktop_view_pin_setup_done.h rename to applications/services/desktop/views/desktop_view_pin_setup_done.h diff --git a/applications/desktop/views/desktop_view_pin_timeout.c b/applications/services/desktop/views/desktop_view_pin_timeout.c similarity index 100% rename from applications/desktop/views/desktop_view_pin_timeout.c rename to applications/services/desktop/views/desktop_view_pin_timeout.c diff --git a/applications/desktop/views/desktop_view_pin_timeout.h b/applications/services/desktop/views/desktop_view_pin_timeout.h similarity index 100% rename from applications/desktop/views/desktop_view_pin_timeout.h rename to applications/services/desktop/views/desktop_view_pin_timeout.h diff --git a/applications/desktop/views/desktop_view_slideshow.c b/applications/services/desktop/views/desktop_view_slideshow.c similarity index 100% rename from applications/desktop/views/desktop_view_slideshow.c rename to applications/services/desktop/views/desktop_view_slideshow.c diff --git a/applications/desktop/views/desktop_view_slideshow.h b/applications/services/desktop/views/desktop_view_slideshow.h similarity index 100% rename from applications/desktop/views/desktop_view_slideshow.h rename to applications/services/desktop/views/desktop_view_slideshow.h diff --git a/applications/dialogs/application.fam b/applications/services/dialogs/application.fam similarity index 87% rename from applications/dialogs/application.fam rename to applications/services/dialogs/application.fam index 0a18c79a3..eb2b40e28 100644 --- a/applications/dialogs/application.fam +++ b/applications/services/dialogs/application.fam @@ -7,4 +7,5 @@ App( requires=["gui"], stack_size=1 * 1024, order=40, + sdk_headers=["dialogs.h"], ) diff --git a/applications/dialogs/dialogs.c b/applications/services/dialogs/dialogs.c similarity index 78% rename from applications/dialogs/dialogs.c rename to applications/services/dialogs/dialogs.c index 381da1635..e2db4a0f8 100644 --- a/applications/dialogs/dialogs.c +++ b/applications/services/dialogs/dialogs.c @@ -4,6 +4,18 @@ #include "dialogs_module_file_browser.h" #include "dialogs_module_message.h" +void dialog_file_browser_set_basic_options( + DialogsFileBrowserOptions* options, + const char* extension, + const Icon* icon) { + options->extension = extension; + options->skip_assets = true; + options->icon = icon; + options->hide_ext = true; + options->item_loader_callback = NULL; + options->item_loader_context = NULL; +} + static DialogsApp* dialogs_app_alloc() { DialogsApp* app = malloc(sizeof(DialogsApp)); app->message_queue = furi_message_queue_alloc(8, sizeof(DialogsAppMessage)); diff --git a/applications/dialogs/dialogs.h b/applications/services/dialogs/dialogs.h similarity index 80% rename from applications/dialogs/dialogs.h rename to applications/services/dialogs/dialogs.h index 946ab6cf0..2522c8b54 100644 --- a/applications/dialogs/dialogs.h +++ b/applications/services/dialogs/dialogs.h @@ -2,6 +2,7 @@ #include #include #include "m-string.h" +#include #ifdef __cplusplus extern "C" { @@ -16,24 +17,48 @@ typedef struct DialogsApp DialogsApp; /****************** FILE BROWSER ******************/ /** - * Shows and processes the file browser dialog - * @param context api pointer - * @param result_path selected file path string pointer - * @param path preselected file path string pointer + * File browser dialog extra options * @param extension file extension to be offered for selection * @param skip_assets true - do not show assets folders * @param icon file icon pointer, NULL for default icon * @param hide_ext true - hide extensions for files + * @param item_loader_callback callback function for providing custom icon & entry name + * @param hide_ext callback context + */ +typedef struct { + const char* extension; + bool skip_assets; + const Icon* icon; + bool hide_ext; + FileBrowserLoadItemCallback item_loader_callback; + void* item_loader_context; +} DialogsFileBrowserOptions; + +/** + * Initialize file browser dialog options + * and set default values + * @param options pointer to options structure + * @param extension file extension to filter + * @param icon file icon pointer, NULL for default icon + */ +void dialog_file_browser_set_basic_options( + DialogsFileBrowserOptions* options, + const char* extension, + const Icon* icon); + +/** + * Shows and processes the file browser dialog + * @param context api pointer + * @param result_path selected file path string pointer + * @param path preselected file path string pointer + * @param options file browser dialog extra options, may be null * @return bool whether a file was selected */ bool dialog_file_browser_show( DialogsApp* context, string_ptr result_path, string_ptr path, - const char* extension, - bool skip_assets, - const Icon* icon, - bool hide_ext); + const DialogsFileBrowserOptions* options); /****************** MESSAGE ******************/ diff --git a/applications/dialogs/dialogs_api.c b/applications/services/dialogs/dialogs_api.c similarity index 82% rename from applications/dialogs/dialogs_api.c rename to applications/services/dialogs/dialogs_api.c index 72aa2a1b8..fd3b2e961 100644 --- a/applications/dialogs/dialogs_api.c +++ b/applications/services/dialogs/dialogs_api.c @@ -9,22 +9,20 @@ bool dialog_file_browser_show( DialogsApp* context, string_ptr result_path, string_ptr path, - const char* extension, - bool skip_assets, - const Icon* icon, - bool hide_ext) { + const DialogsFileBrowserOptions* options) { FuriApiLock lock = API_LOCK_INIT_LOCKED(); furi_check(lock != NULL); DialogsAppData data = { .file_browser = { - .extension = extension, + .extension = options ? options->extension : "", .result_path = result_path, - .file_icon = icon, - .hide_ext = hide_ext, - .skip_assets = skip_assets, + .file_icon = options ? options->icon : NULL, + .hide_ext = options ? options->hide_ext : true, + .skip_assets = options ? options->skip_assets : true, .preselected_filename = path, - + .item_callback = options ? options->item_loader_callback : NULL, + .item_callback_context = options ? options->item_loader_context : NULL, }}; DialogsAppReturn return_data; diff --git a/applications/dialogs/dialogs_api_lock.h b/applications/services/dialogs/dialogs_api_lock.h similarity index 100% rename from applications/dialogs/dialogs_api_lock.h rename to applications/services/dialogs/dialogs_api_lock.h diff --git a/applications/dialogs/dialogs_i.h b/applications/services/dialogs/dialogs_i.h similarity index 85% rename from applications/dialogs/dialogs_i.h rename to applications/services/dialogs/dialogs_i.h index 36bee0248..76495d31b 100644 --- a/applications/dialogs/dialogs_i.h +++ b/applications/services/dialogs/dialogs_i.h @@ -2,6 +2,7 @@ #include "dialogs.h" #include "dialogs_message.h" #include "view_holder.h" +#include #ifdef __cplusplus extern "C" { diff --git a/applications/dialogs/dialogs_message.h b/applications/services/dialogs/dialogs_message.h similarity index 92% rename from applications/dialogs/dialogs_message.h rename to applications/services/dialogs/dialogs_message.h index ccfbdece5..2dc66f133 100644 --- a/applications/dialogs/dialogs_message.h +++ b/applications/services/dialogs/dialogs_message.h @@ -15,6 +15,8 @@ typedef struct { const Icon* file_icon; string_ptr result_path; string_ptr preselected_filename; + FileBrowserLoadItemCallback item_callback; + void* item_callback_context; } DialogsAppMessageDataFileBrowser; typedef struct { diff --git a/applications/dialogs/dialogs_module_file_browser.c b/applications/services/dialogs/dialogs_module_file_browser.c similarity index 95% rename from applications/dialogs/dialogs_module_file_browser.c rename to applications/services/dialogs/dialogs_module_file_browser.c index f5355571a..166fd1113 100644 --- a/applications/dialogs/dialogs_module_file_browser.c +++ b/applications/services/dialogs/dialogs_module_file_browser.c @@ -39,6 +39,7 @@ bool dialogs_app_process_module_file_browser(const DialogsAppMessageDataFileBrow file_browser, dialogs_app_file_browser_callback, file_browser_context); file_browser_configure( file_browser, data->extension, data->skip_assets, data->file_icon, data->hide_ext); + file_browser_set_item_callback(file_browser, data->item_callback, data->item_callback_context); file_browser_start(file_browser, data->preselected_filename); view_holder_set_view(view_holder, file_browser_get_view(file_browser)); diff --git a/applications/dialogs/dialogs_module_file_browser.h b/applications/services/dialogs/dialogs_module_file_browser.h similarity index 100% rename from applications/dialogs/dialogs_module_file_browser.h rename to applications/services/dialogs/dialogs_module_file_browser.h diff --git a/applications/dialogs/dialogs_module_message.c b/applications/services/dialogs/dialogs_module_message.c similarity index 100% rename from applications/dialogs/dialogs_module_message.c rename to applications/services/dialogs/dialogs_module_message.c diff --git a/applications/dialogs/dialogs_module_message.h b/applications/services/dialogs/dialogs_module_message.h similarity index 100% rename from applications/dialogs/dialogs_module_message.h rename to applications/services/dialogs/dialogs_module_message.h diff --git a/applications/dialogs/view_holder.c b/applications/services/dialogs/view_holder.c similarity index 100% rename from applications/dialogs/view_holder.c rename to applications/services/dialogs/view_holder.c diff --git a/applications/dialogs/view_holder.h b/applications/services/dialogs/view_holder.h similarity index 100% rename from applications/dialogs/view_holder.h rename to applications/services/dialogs/view_holder.h diff --git a/applications/services/dolphin/application.fam b/applications/services/dolphin/application.fam new file mode 100644 index 000000000..78a097e67 --- /dev/null +++ b/applications/services/dolphin/application.fam @@ -0,0 +1,10 @@ +App( + appid="dolphin", + name="DolphinSrv", + apptype=FlipperAppType.SERVICE, + entry_point="dolphin_srv", + cdefines=["SRV_DOLPHIN"], + stack_size=1 * 1024, + order=50, + sdk_headers=["dolphin.h"], +) diff --git a/applications/dolphin/dolphin.c b/applications/services/dolphin/dolphin.c similarity index 100% rename from applications/dolphin/dolphin.c rename to applications/services/dolphin/dolphin.c diff --git a/applications/dolphin/dolphin.h b/applications/services/dolphin/dolphin.h similarity index 100% rename from applications/dolphin/dolphin.h rename to applications/services/dolphin/dolphin.h diff --git a/applications/dolphin/dolphin_i.h b/applications/services/dolphin/dolphin_i.h similarity index 100% rename from applications/dolphin/dolphin_i.h rename to applications/services/dolphin/dolphin_i.h diff --git a/applications/dolphin/helpers/dolphin_deed.c b/applications/services/dolphin/helpers/dolphin_deed.c similarity index 100% rename from applications/dolphin/helpers/dolphin_deed.c rename to applications/services/dolphin/helpers/dolphin_deed.c diff --git a/applications/dolphin/helpers/dolphin_deed.h b/applications/services/dolphin/helpers/dolphin_deed.h similarity index 100% rename from applications/dolphin/helpers/dolphin_deed.h rename to applications/services/dolphin/helpers/dolphin_deed.h diff --git a/applications/dolphin/helpers/dolphin_state.c b/applications/services/dolphin/helpers/dolphin_state.c similarity index 100% rename from applications/dolphin/helpers/dolphin_state.c rename to applications/services/dolphin/helpers/dolphin_state.c diff --git a/applications/dolphin/helpers/dolphin_state.h b/applications/services/dolphin/helpers/dolphin_state.h similarity index 100% rename from applications/dolphin/helpers/dolphin_state.h rename to applications/services/dolphin/helpers/dolphin_state.h diff --git a/applications/dolphin/helpers/dolphin_state_filename.h b/applications/services/dolphin/helpers/dolphin_state_filename.h similarity index 100% rename from applications/dolphin/helpers/dolphin_state_filename.h rename to applications/services/dolphin/helpers/dolphin_state_filename.h diff --git a/applications/services/gui/application.fam b/applications/services/gui/application.fam new file mode 100644 index 000000000..7fad7b4ea --- /dev/null +++ b/applications/services/gui/application.fam @@ -0,0 +1,36 @@ +App( + appid="gui", + name="GuiSrv", + apptype=FlipperAppType.SERVICE, + entry_point="gui_srv", + cdefines=["SRV_GUI"], + requires=[ + "input", + "notification", + ], + stack_size=2 * 1024, + order=70, + sdk_headers=[ + "gui.h", + "elements.h", + "view_dispatcher.h", + "view_stack.h", + "modules/button_menu.h", + "modules/byte_input.h", + "modules/popup.h", + "modules/text_input.h", + "modules/widget.h", + "modules/validators.h", + "modules/file_browser.h", + "modules/button_panel.h", + "modules/variable_item_list.h", + "modules/file_browser_worker.h", + "modules/menu.h", + "modules/dialog_ex.h", + "modules/loading.h", + "modules/text_box.h", + "modules/submenu.h", + "modules/widget_elements/widget_element.h", + "modules/empty_screen.h", + ], +) diff --git a/applications/gui/canvas.c b/applications/services/gui/canvas.c similarity index 100% rename from applications/gui/canvas.c rename to applications/services/gui/canvas.c diff --git a/applications/gui/canvas.h b/applications/services/gui/canvas.h old mode 100755 new mode 100644 similarity index 100% rename from applications/gui/canvas.h rename to applications/services/gui/canvas.h diff --git a/applications/gui/canvas_i.h b/applications/services/gui/canvas_i.h similarity index 100% rename from applications/gui/canvas_i.h rename to applications/services/gui/canvas_i.h diff --git a/applications/gui/elements.c b/applications/services/gui/elements.c similarity index 100% rename from applications/gui/elements.c rename to applications/services/gui/elements.c diff --git a/applications/gui/elements.h b/applications/services/gui/elements.h similarity index 100% rename from applications/gui/elements.h rename to applications/services/gui/elements.h diff --git a/applications/gui/gui.c b/applications/services/gui/gui.c similarity index 100% rename from applications/gui/gui.c rename to applications/services/gui/gui.c diff --git a/applications/gui/gui.h b/applications/services/gui/gui.h similarity index 100% rename from applications/gui/gui.h rename to applications/services/gui/gui.h diff --git a/applications/gui/gui_i.h b/applications/services/gui/gui_i.h similarity index 100% rename from applications/gui/gui_i.h rename to applications/services/gui/gui_i.h diff --git a/applications/gui/icon.c b/applications/services/gui/icon.c similarity index 100% rename from applications/gui/icon.c rename to applications/services/gui/icon.c diff --git a/applications/gui/icon.h b/applications/services/gui/icon.h similarity index 100% rename from applications/gui/icon.h rename to applications/services/gui/icon.h diff --git a/applications/gui/icon_animation.c b/applications/services/gui/icon_animation.c similarity index 100% rename from applications/gui/icon_animation.c rename to applications/services/gui/icon_animation.c diff --git a/applications/gui/icon_animation.h b/applications/services/gui/icon_animation.h similarity index 100% rename from applications/gui/icon_animation.h rename to applications/services/gui/icon_animation.h diff --git a/applications/gui/icon_animation_i.h b/applications/services/gui/icon_animation_i.h similarity index 100% rename from applications/gui/icon_animation_i.h rename to applications/services/gui/icon_animation_i.h diff --git a/applications/gui/icon_i.h b/applications/services/gui/icon_i.h similarity index 100% rename from applications/gui/icon_i.h rename to applications/services/gui/icon_i.h diff --git a/applications/gui/modules/button_menu.c b/applications/services/gui/modules/button_menu.c similarity index 100% rename from applications/gui/modules/button_menu.c rename to applications/services/gui/modules/button_menu.c diff --git a/applications/gui/modules/button_menu.h b/applications/services/gui/modules/button_menu.h similarity index 100% rename from applications/gui/modules/button_menu.h rename to applications/services/gui/modules/button_menu.h diff --git a/applications/gui/modules/button_panel.c b/applications/services/gui/modules/button_panel.c similarity index 100% rename from applications/gui/modules/button_panel.c rename to applications/services/gui/modules/button_panel.c diff --git a/applications/gui/modules/button_panel.h b/applications/services/gui/modules/button_panel.h similarity index 100% rename from applications/gui/modules/button_panel.h rename to applications/services/gui/modules/button_panel.h diff --git a/applications/gui/modules/byte_input.c b/applications/services/gui/modules/byte_input.c similarity index 100% rename from applications/gui/modules/byte_input.c rename to applications/services/gui/modules/byte_input.c diff --git a/applications/gui/modules/byte_input.h b/applications/services/gui/modules/byte_input.h similarity index 100% rename from applications/gui/modules/byte_input.h rename to applications/services/gui/modules/byte_input.h diff --git a/applications/gui/modules/dialog_ex.c b/applications/services/gui/modules/dialog_ex.c old mode 100755 new mode 100644 similarity index 100% rename from applications/gui/modules/dialog_ex.c rename to applications/services/gui/modules/dialog_ex.c diff --git a/applications/gui/modules/dialog_ex.h b/applications/services/gui/modules/dialog_ex.h similarity index 100% rename from applications/gui/modules/dialog_ex.h rename to applications/services/gui/modules/dialog_ex.h diff --git a/applications/gui/modules/empty_screen.c b/applications/services/gui/modules/empty_screen.c similarity index 100% rename from applications/gui/modules/empty_screen.c rename to applications/services/gui/modules/empty_screen.c diff --git a/applications/gui/modules/empty_screen.h b/applications/services/gui/modules/empty_screen.h similarity index 100% rename from applications/gui/modules/empty_screen.h rename to applications/services/gui/modules/empty_screen.h diff --git a/applications/gui/modules/file_browser.c b/applications/services/gui/modules/file_browser.c similarity index 85% rename from applications/gui/modules/file_browser.c rename to applications/services/gui/modules/file_browser.c index a987eb1ef..1c0c8c74c 100644 --- a/applications/gui/modules/file_browser.c +++ b/applications/services/gui/modules/file_browser.c @@ -16,7 +16,9 @@ #define FRAME_HEIGHT 12 #define Y_OFFSET 3 -#define ITEM_LIST_LEN_MAX 100 +#define ITEM_LIST_LEN_MAX 50 + +#define CUSTOM_ICON_MAX_SIZE 32 typedef enum { BrowserItemTypeLoading, @@ -28,25 +30,47 @@ typedef enum { typedef struct { string_t path; BrowserItemType type; + uint8_t* custom_icon_data; + string_t display_name; } BrowserItem_t; static void BrowserItem_t_init(BrowserItem_t* obj) { obj->type = BrowserItemTypeLoading; string_init(obj->path); + string_init(obj->display_name); + obj->custom_icon_data = NULL; } static void BrowserItem_t_init_set(BrowserItem_t* obj, const BrowserItem_t* src) { obj->type = src->type; string_init_set(obj->path, src->path); + string_init_set(obj->display_name, src->display_name); + if(src->custom_icon_data) { + obj->custom_icon_data = malloc(CUSTOM_ICON_MAX_SIZE); + memcpy(obj->custom_icon_data, src->custom_icon_data, CUSTOM_ICON_MAX_SIZE); + } else { + obj->custom_icon_data = NULL; + } } static void BrowserItem_t_set(BrowserItem_t* obj, const BrowserItem_t* src) { obj->type = src->type; string_set(obj->path, src->path); + string_set(obj->display_name, src->display_name); + if(src->custom_icon_data) { + obj->custom_icon_data = malloc(CUSTOM_ICON_MAX_SIZE); + memcpy(obj->custom_icon_data, src->custom_icon_data, CUSTOM_ICON_MAX_SIZE); + } else { + obj->custom_icon_data = NULL; + } } static void BrowserItem_t_clear(BrowserItem_t* obj) { string_clear(obj->path); + string_clear(obj->display_name); + if(obj->custom_icon_data) { + free(obj->custom_icon_data); + } } ARRAY_DEF( @@ -62,10 +86,14 @@ struct FileBrowser { BrowserWorker* worker; const char* ext_filter; bool skip_assets; + bool hide_ext; FileBrowserCallback callback; void* context; + FileBrowserLoadItemCallback item_callback; + void* item_context; + string_ptr result_path; }; @@ -148,6 +176,7 @@ void file_browser_configure( browser->ext_filter = extension; browser->skip_assets = skip_assets; + browser->hide_ext = hide_ext; with_view_model( browser->view, (FileBrowserModel * model) { @@ -186,6 +215,14 @@ void file_browser_set_callback(FileBrowser* browser, FileBrowserCallback callbac browser->callback = callback; } +void file_browser_set_item_callback( + FileBrowser* browser, + FileBrowserLoadItemCallback callback, + void* context) { + browser->item_context = context; + browser->item_callback = callback; +} + static bool browser_is_item_in_array(FileBrowserModel* model, uint32_t idx) { size_t array_size = items_array_size(model->items); @@ -304,18 +341,43 @@ static void browser_list_item_cb(void* context, string_t item_path, bool is_fold FileBrowser* browser = (FileBrowser*)context; BrowserItem_t item; + item.custom_icon_data = NULL; if(!is_last) { - BrowserItem_t_init(&item); - string_set(item.path, item_path); - item.type = (is_folder) ? BrowserItemTypeFolder : BrowserItemTypeFile; + string_init_set(item.path, item_path); + string_init(item.display_name); + if(is_folder) { + item.type = BrowserItemTypeFolder; + } else { + item.type = BrowserItemTypeFile; + if(browser->item_callback) { + item.custom_icon_data = malloc(CUSTOM_ICON_MAX_SIZE); + if(!browser->item_callback( + item_path, + browser->item_context, + &item.custom_icon_data, + item.display_name)) { + free(item.custom_icon_data); + item.custom_icon_data = NULL; + } + } + } + + if(string_empty_p(item.display_name)) { + path_extract_filename( + item_path, + item.display_name, + (browser->hide_ext) && (item.type == BrowserItemTypeFile)); + } with_view_model( browser->view, (FileBrowserModel * model) { items_array_push_back(model->items, item); - return false; + // TODO: calculate if element is visible + return true; }); - BrowserItem_t_clear(&item); + string_clear(item.display_name); + string_clear(item.path); } else { with_view_model( browser->view, (FileBrowserModel * model) { @@ -372,13 +434,16 @@ static void browser_draw_list(Canvas* canvas, FileBrowserModel* model) { int32_t idx = CLAMP((uint32_t)(i + model->list_offset), model->item_cnt, 0u); BrowserItemType item_type = BrowserItemTypeLoading; + uint8_t* custom_icon_data = NULL; if(browser_is_item_in_array(model, idx)) { BrowserItem_t* item = items_array_get( model->items, CLAMP(idx - model->array_offset, (int32_t)(array_size - 1), 0)); item_type = item->type; - path_extract_filename( - item->path, filename, (model->hide_ext) && (item_type == BrowserItemTypeFile)); + string_set(filename, item->display_name); + if(item_type == BrowserItemTypeFile) { + custom_icon_data = item->custom_icon_data; + } } else { string_set_str(filename, "---"); } @@ -396,7 +461,11 @@ static void browser_draw_list(Canvas* canvas, FileBrowserModel* model) { canvas_set_color(canvas, ColorBlack); } - if((item_type == BrowserItemTypeFile) && (model->file_icon)) { + if(custom_icon_data) { + // Currently only 10*10 icons are supported + canvas_draw_bitmap( + canvas, 2, Y_OFFSET + 1 + i * FRAME_HEIGHT, 10, 10, custom_icon_data); + } else if((item_type == BrowserItemTypeFile) && (model->file_icon)) { canvas_draw_icon(canvas, 2, Y_OFFSET + 1 + i * FRAME_HEIGHT, model->file_icon); } else if(BrowserItemIcons[item_type] != NULL) { canvas_draw_icon( diff --git a/applications/gui/modules/file_browser.h b/applications/services/gui/modules/file_browser.h similarity index 76% rename from applications/gui/modules/file_browser.h rename to applications/services/gui/modules/file_browser.h index ebc64509a..57a9f096a 100644 --- a/applications/gui/modules/file_browser.h +++ b/applications/services/gui/modules/file_browser.h @@ -15,6 +15,9 @@ extern "C" { typedef struct FileBrowser FileBrowser; typedef void (*FileBrowserCallback)(void* context); +typedef bool ( + *FileBrowserLoadItemCallback)(string_t path, void* context, uint8_t** icon, string_t item_name); + FileBrowser* file_browser_alloc(string_ptr result_path); void file_browser_free(FileBrowser* browser); @@ -34,6 +37,11 @@ void file_browser_stop(FileBrowser* browser); void file_browser_set_callback(FileBrowser* browser, FileBrowserCallback callback, void* context); +void file_browser_set_item_callback( + FileBrowser* browser, + FileBrowserLoadItemCallback callback, + void* context); + #ifdef __cplusplus } #endif diff --git a/applications/gui/modules/file_browser_worker.c b/applications/services/gui/modules/file_browser_worker.c similarity index 100% rename from applications/gui/modules/file_browser_worker.c rename to applications/services/gui/modules/file_browser_worker.c diff --git a/applications/gui/modules/file_browser_worker.h b/applications/services/gui/modules/file_browser_worker.h similarity index 100% rename from applications/gui/modules/file_browser_worker.h rename to applications/services/gui/modules/file_browser_worker.h diff --git a/applications/gui/modules/loading.c b/applications/services/gui/modules/loading.c similarity index 100% rename from applications/gui/modules/loading.c rename to applications/services/gui/modules/loading.c diff --git a/applications/gui/modules/loading.h b/applications/services/gui/modules/loading.h similarity index 100% rename from applications/gui/modules/loading.h rename to applications/services/gui/modules/loading.h diff --git a/applications/gui/modules/menu.c b/applications/services/gui/modules/menu.c similarity index 100% rename from applications/gui/modules/menu.c rename to applications/services/gui/modules/menu.c diff --git a/applications/gui/modules/menu.h b/applications/services/gui/modules/menu.h old mode 100755 new mode 100644 similarity index 100% rename from applications/gui/modules/menu.h rename to applications/services/gui/modules/menu.h diff --git a/applications/gui/modules/popup.c b/applications/services/gui/modules/popup.c similarity index 100% rename from applications/gui/modules/popup.c rename to applications/services/gui/modules/popup.c diff --git a/applications/gui/modules/popup.h b/applications/services/gui/modules/popup.h similarity index 100% rename from applications/gui/modules/popup.h rename to applications/services/gui/modules/popup.h diff --git a/applications/gui/modules/submenu.c b/applications/services/gui/modules/submenu.c similarity index 100% rename from applications/gui/modules/submenu.c rename to applications/services/gui/modules/submenu.c diff --git a/applications/gui/modules/submenu.h b/applications/services/gui/modules/submenu.h similarity index 100% rename from applications/gui/modules/submenu.h rename to applications/services/gui/modules/submenu.h diff --git a/applications/gui/modules/text_box.c b/applications/services/gui/modules/text_box.c old mode 100755 new mode 100644 similarity index 100% rename from applications/gui/modules/text_box.c rename to applications/services/gui/modules/text_box.c diff --git a/applications/gui/modules/text_box.h b/applications/services/gui/modules/text_box.h old mode 100755 new mode 100644 similarity index 100% rename from applications/gui/modules/text_box.h rename to applications/services/gui/modules/text_box.h diff --git a/applications/gui/modules/text_input.c b/applications/services/gui/modules/text_input.c similarity index 99% rename from applications/gui/modules/text_input.c rename to applications/services/gui/modules/text_input.c index 26f74e7ac..b8098a3b9 100644 --- a/applications/gui/modules/text_input.c +++ b/applications/services/gui/modules/text_input.c @@ -463,8 +463,6 @@ void text_input_free(TextInput* text_input) { // Send stop command furi_timer_stop(text_input->timer); - // Wait till timer stop - while(furi_timer_is_running(text_input->timer)) furi_delay_tick(1); // Release allocated memory furi_timer_free(text_input->timer); diff --git a/applications/gui/modules/text_input.h b/applications/services/gui/modules/text_input.h similarity index 100% rename from applications/gui/modules/text_input.h rename to applications/services/gui/modules/text_input.h diff --git a/applications/gui/modules/validators.c b/applications/services/gui/modules/validators.c similarity index 92% rename from applications/gui/modules/validators.c rename to applications/services/gui/modules/validators.c index ac293f8cb..d5fb0fa22 100644 --- a/applications/gui/modules/validators.c +++ b/applications/services/gui/modules/validators.c @@ -1,6 +1,6 @@ #include #include "validators.h" -#include "applications/storage/storage.h" +#include struct ValidatorIsFile { char* app_path_folder; @@ -42,7 +42,9 @@ ValidatorIsFile* validator_is_file_alloc_init( instance->app_path_folder = strdup(app_path_folder); instance->app_extension = app_extension; - instance->current_name = strdup(current_name); + if(current_name != NULL) { + instance->current_name = strdup(current_name); + } return instance; } diff --git a/applications/gui/modules/validators.h b/applications/services/gui/modules/validators.h similarity index 100% rename from applications/gui/modules/validators.h rename to applications/services/gui/modules/validators.h diff --git a/applications/gui/modules/variable_item_list.c b/applications/services/gui/modules/variable_item_list.c similarity index 100% rename from applications/gui/modules/variable_item_list.c rename to applications/services/gui/modules/variable_item_list.c diff --git a/applications/gui/modules/variable_item_list.h b/applications/services/gui/modules/variable_item_list.h old mode 100755 new mode 100644 similarity index 100% rename from applications/gui/modules/variable_item_list.h rename to applications/services/gui/modules/variable_item_list.h diff --git a/applications/gui/modules/widget.c b/applications/services/gui/modules/widget.c similarity index 99% rename from applications/gui/modules/widget.c rename to applications/services/gui/modules/widget.c index b37a64701..802f76e24 100644 --- a/applications/gui/modules/widget.c +++ b/applications/services/gui/modules/widget.c @@ -1,6 +1,7 @@ #include #include "widget.h" #include +#include "widget_elements/widget_element_i.h" ARRAY_DEF(ElementArray, WidgetElement*, M_PTR_OPLIST); diff --git a/applications/gui/modules/widget.h b/applications/services/gui/modules/widget.h old mode 100755 new mode 100644 similarity index 98% rename from applications/gui/modules/widget.h rename to applications/services/gui/modules/widget.h index 03586165c..50c261751 --- a/applications/gui/modules/widget.h +++ b/applications/services/gui/modules/widget.h @@ -4,8 +4,8 @@ */ #pragma once - -#include "widget_elements/widget_element_i.h" +#include +#include "widget_elements/widget_element.h" #ifdef __cplusplus extern "C" { diff --git a/applications/services/gui/modules/widget_elements/widget_element.h b/applications/services/gui/modules/widget_elements/widget_element.h new file mode 100644 index 000000000..679904173 --- /dev/null +++ b/applications/services/gui/modules/widget_elements/widget_element.h @@ -0,0 +1,22 @@ +/** + * @file widget_element_i.h + * GUI: internal Widget Element API + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + GuiButtonTypeLeft, + GuiButtonTypeCenter, + GuiButtonTypeRight, +} GuiButtonType; + +typedef void (*ButtonCallback)(GuiButtonType result, InputType type, void* context); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/applications/gui/modules/widget_elements/widget_element_button.c b/applications/services/gui/modules/widget_elements/widget_element_button.c similarity index 100% rename from applications/gui/modules/widget_elements/widget_element_button.c rename to applications/services/gui/modules/widget_elements/widget_element_button.c diff --git a/applications/gui/modules/widget_elements/widget_element_frame.c b/applications/services/gui/modules/widget_elements/widget_element_frame.c old mode 100755 new mode 100644 similarity index 100% rename from applications/gui/modules/widget_elements/widget_element_frame.c rename to applications/services/gui/modules/widget_elements/widget_element_frame.c diff --git a/applications/gui/modules/widget_elements/widget_element_i.h b/applications/services/gui/modules/widget_elements/widget_element_i.h old mode 100755 new mode 100644 similarity index 90% rename from applications/gui/modules/widget_elements/widget_element_i.h rename to applications/services/gui/modules/widget_elements/widget_element_i.h index 316ed7400..67dea4b1f --- a/applications/gui/modules/widget_elements/widget_element_i.h +++ b/applications/services/gui/modules/widget_elements/widget_element_i.h @@ -7,14 +7,11 @@ #include #include #include +#include "widget_element.h" -typedef enum { - GuiButtonTypeLeft, - GuiButtonTypeCenter, - GuiButtonTypeRight, -} GuiButtonType; - -typedef void (*ButtonCallback)(GuiButtonType result, InputType type, void* context); +#ifdef __cplusplus +extern "C" { +#endif typedef struct WidgetElement WidgetElement; typedef struct Widget Widget; @@ -88,3 +85,7 @@ WidgetElement* widget_element_text_scroll_create( uint8_t width, uint8_t height, const char* text); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/applications/gui/modules/widget_elements/widget_element_icon.c b/applications/services/gui/modules/widget_elements/widget_element_icon.c similarity index 100% rename from applications/gui/modules/widget_elements/widget_element_icon.c rename to applications/services/gui/modules/widget_elements/widget_element_icon.c diff --git a/applications/gui/modules/widget_elements/widget_element_string.c b/applications/services/gui/modules/widget_elements/widget_element_string.c old mode 100755 new mode 100644 similarity index 100% rename from applications/gui/modules/widget_elements/widget_element_string.c rename to applications/services/gui/modules/widget_elements/widget_element_string.c diff --git a/applications/gui/modules/widget_elements/widget_element_string_multiline.c b/applications/services/gui/modules/widget_elements/widget_element_string_multiline.c similarity index 100% rename from applications/gui/modules/widget_elements/widget_element_string_multiline.c rename to applications/services/gui/modules/widget_elements/widget_element_string_multiline.c diff --git a/applications/gui/modules/widget_elements/widget_element_text_box.c b/applications/services/gui/modules/widget_elements/widget_element_text_box.c similarity index 100% rename from applications/gui/modules/widget_elements/widget_element_text_box.c rename to applications/services/gui/modules/widget_elements/widget_element_text_box.c diff --git a/applications/gui/modules/widget_elements/widget_element_text_scroll.c b/applications/services/gui/modules/widget_elements/widget_element_text_scroll.c similarity index 100% rename from applications/gui/modules/widget_elements/widget_element_text_scroll.c rename to applications/services/gui/modules/widget_elements/widget_element_text_scroll.c diff --git a/applications/gui/scene_manager.c b/applications/services/gui/scene_manager.c old mode 100755 new mode 100644 similarity index 100% rename from applications/gui/scene_manager.c rename to applications/services/gui/scene_manager.c diff --git a/applications/gui/scene_manager.h b/applications/services/gui/scene_manager.h old mode 100755 new mode 100644 similarity index 100% rename from applications/gui/scene_manager.h rename to applications/services/gui/scene_manager.h diff --git a/applications/gui/scene_manager_i.h b/applications/services/gui/scene_manager_i.h old mode 100755 new mode 100644 similarity index 100% rename from applications/gui/scene_manager_i.h rename to applications/services/gui/scene_manager_i.h diff --git a/applications/gui/view.c b/applications/services/gui/view.c similarity index 100% rename from applications/gui/view.c rename to applications/services/gui/view.c diff --git a/applications/gui/view.h b/applications/services/gui/view.h similarity index 100% rename from applications/gui/view.h rename to applications/services/gui/view.h diff --git a/applications/gui/view_dispatcher.c b/applications/services/gui/view_dispatcher.c similarity index 100% rename from applications/gui/view_dispatcher.c rename to applications/services/gui/view_dispatcher.c diff --git a/applications/gui/view_dispatcher.h b/applications/services/gui/view_dispatcher.h old mode 100755 new mode 100644 similarity index 100% rename from applications/gui/view_dispatcher.h rename to applications/services/gui/view_dispatcher.h diff --git a/applications/gui/view_dispatcher_i.h b/applications/services/gui/view_dispatcher_i.h similarity index 100% rename from applications/gui/view_dispatcher_i.h rename to applications/services/gui/view_dispatcher_i.h diff --git a/applications/gui/view_i.h b/applications/services/gui/view_i.h similarity index 100% rename from applications/gui/view_i.h rename to applications/services/gui/view_i.h diff --git a/applications/gui/view_port.c b/applications/services/gui/view_port.c similarity index 100% rename from applications/gui/view_port.c rename to applications/services/gui/view_port.c diff --git a/applications/gui/view_port.h b/applications/services/gui/view_port.h similarity index 100% rename from applications/gui/view_port.h rename to applications/services/gui/view_port.h diff --git a/applications/gui/view_port_i.h b/applications/services/gui/view_port_i.h similarity index 100% rename from applications/gui/view_port_i.h rename to applications/services/gui/view_port_i.h diff --git a/applications/gui/view_stack.c b/applications/services/gui/view_stack.c similarity index 100% rename from applications/gui/view_stack.c rename to applications/services/gui/view_stack.c diff --git a/applications/gui/view_stack.h b/applications/services/gui/view_stack.h similarity index 100% rename from applications/gui/view_stack.h rename to applications/services/gui/view_stack.h diff --git a/applications/input/application.fam b/applications/services/input/application.fam similarity index 86% rename from applications/input/application.fam rename to applications/services/input/application.fam index 545630e6e..d344fc350 100644 --- a/applications/input/application.fam +++ b/applications/services/input/application.fam @@ -6,4 +6,5 @@ App( cdefines=["SRV_INPUT"], stack_size=1 * 1024, order=80, + sdk_headers=["input.h"], ) diff --git a/applications/input/input.c b/applications/services/input/input.c similarity index 100% rename from applications/input/input.c rename to applications/services/input/input.c diff --git a/applications/input/input.h b/applications/services/input/input.h similarity index 94% rename from applications/input/input.h rename to applications/services/input/input.h index 001ab1e2e..bd0ba3902 100644 --- a/applications/input/input.h +++ b/applications/services/input/input.h @@ -7,6 +7,10 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + #define RECORD_INPUT_EVENTS "input_events" /** Input Types @@ -38,3 +42,7 @@ const char* input_get_key_name(InputKey key); * @return string */ const char* input_get_type_name(InputType type); + +#ifdef __cplusplus +} +#endif diff --git a/applications/input/input_cli.c b/applications/services/input/input_cli.c similarity index 100% rename from applications/input/input_cli.c rename to applications/services/input/input_cli.c diff --git a/applications/input/input_i.h b/applications/services/input/input_i.h similarity index 100% rename from applications/input/input_i.h rename to applications/services/input/input_i.h diff --git a/applications/loader/application.fam b/applications/services/loader/application.fam similarity index 87% rename from applications/loader/application.fam rename to applications/services/loader/application.fam index c1ba4e549..91103e46e 100644 --- a/applications/loader/application.fam +++ b/applications/services/loader/application.fam @@ -7,4 +7,5 @@ App( requires=["gui"], stack_size=2 * 1024, order=90, + sdk_headers=["loader.h"], ) diff --git a/applications/loader/loader.c b/applications/services/loader/loader.c similarity index 99% rename from applications/loader/loader.c rename to applications/services/loader/loader.c index 9ece7f271..cf7e5a108 100644 --- a/applications/loader/loader.c +++ b/applications/services/loader/loader.c @@ -388,7 +388,7 @@ static void loader_build_menu() { loader_submenu_callback, (void*)LoaderMenuViewPlugins); } - if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug) && (FLIPPER_DEBUG_APPS_COUNT > 0)) { menu_add_item( loader_instance->primary_menu, "Debug Tools", diff --git a/applications/loader/loader.h b/applications/services/loader/loader.h similarity index 93% rename from applications/loader/loader.h rename to applications/services/loader/loader.h index 8f95d81b2..954e79c57 100644 --- a/applications/loader/loader.h +++ b/applications/services/loader/loader.h @@ -3,6 +3,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + #define RECORD_LOADER "loader" typedef struct Loader Loader; @@ -49,3 +53,7 @@ void loader_update_menu(); /** Show primary loader */ FuriPubSub* loader_get_pubsub(Loader* instance); + +#ifdef __cplusplus +} +#endif diff --git a/applications/loader/loader_i.h b/applications/services/loader/loader_i.h similarity index 100% rename from applications/loader/loader_i.h rename to applications/services/loader/loader_i.h diff --git a/applications/notification/application.fam b/applications/services/notification/application.fam similarity index 54% rename from applications/notification/application.fam rename to applications/services/notification/application.fam index be730d510..82f94085a 100644 --- a/applications/notification/application.fam +++ b/applications/services/notification/application.fam @@ -8,14 +8,5 @@ App( provides=["notification_settings"], stack_size=int(1.5 * 1024), order=100, -) - -App( - appid="notification_settings", - name="LCD and Notifications", - apptype=FlipperAppType.SETTINGS, - entry_point="notification_settings_app", - requires=["notification"], - stack_size=1 * 1024, - order=20, + sdk_headers=["notification.h", "notification_messages.h"], ) diff --git a/applications/notification/notification.h b/applications/services/notification/notification.h similarity index 100% rename from applications/notification/notification.h rename to applications/services/notification/notification.h diff --git a/applications/notification/notification_app.c b/applications/services/notification/notification_app.c similarity index 100% rename from applications/notification/notification_app.c rename to applications/services/notification/notification_app.c diff --git a/applications/notification/notification_app.h b/applications/services/notification/notification_app.h similarity index 100% rename from applications/notification/notification_app.h rename to applications/services/notification/notification_app.h diff --git a/applications/notification/notification_app_api.c b/applications/services/notification/notification_app_api.c similarity index 100% rename from applications/notification/notification_app_api.c rename to applications/services/notification/notification_app_api.c diff --git a/applications/notification/notification_messages.c b/applications/services/notification/notification_messages.c similarity index 100% rename from applications/notification/notification_messages.c rename to applications/services/notification/notification_messages.c diff --git a/applications/notification/notification_messages.h b/applications/services/notification/notification_messages.h similarity index 100% rename from applications/notification/notification_messages.h rename to applications/services/notification/notification_messages.h diff --git a/applications/notification/notification_messages_notes.c b/applications/services/notification/notification_messages_notes.c similarity index 100% rename from applications/notification/notification_messages_notes.c rename to applications/services/notification/notification_messages_notes.c diff --git a/applications/notification/notification_messages_notes.h b/applications/services/notification/notification_messages_notes.h similarity index 100% rename from applications/notification/notification_messages_notes.h rename to applications/services/notification/notification_messages_notes.h diff --git a/applications/notification/notification_settings_filename.h b/applications/services/notification/notification_settings_filename.h similarity index 100% rename from applications/notification/notification_settings_filename.h rename to applications/services/notification/notification_settings_filename.h diff --git a/applications/services/power/application.fam b/applications/services/power/application.fam new file mode 100644 index 000000000..f14d88c54 --- /dev/null +++ b/applications/services/power/application.fam @@ -0,0 +1,26 @@ +App( + appid="power", + name="PowerSrv", + apptype=FlipperAppType.SERVICE, + entry_point="power_srv", + cdefines=["SRV_POWER"], + requires=[ + "gui", + "cli", + ], + provides=[ + "power_settings", + "power_start", + ], + stack_size=1 * 1024, + order=110, + sdk_headers=["power_service/power.h"], +) + +App( + appid="power_start", + apptype=FlipperAppType.STARTUP, + entry_point="power_on_system_start", + requires=["power"], + order=80, +) diff --git a/applications/power/power_cli.c b/applications/services/power/power_cli.c similarity index 100% rename from applications/power/power_cli.c rename to applications/services/power/power_cli.c diff --git a/applications/services/power/power_cli.h b/applications/services/power/power_cli.h new file mode 100644 index 000000000..1517c6140 --- /dev/null +++ b/applications/services/power/power_cli.h @@ -0,0 +1,11 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +void power_on_system_start(); + +#ifdef __cplusplus +} +#endif diff --git a/applications/power/power_service/power.c b/applications/services/power/power_service/power.c similarity index 98% rename from applications/power/power_service/power.c rename to applications/services/power/power_service/power.c index 1c4118cab..82644e5b0 100644 --- a/applications/power/power_service/power.c +++ b/applications/services/power/power_service/power.c @@ -160,6 +160,9 @@ void power_free(Power* power) { power->input_events_subscription = NULL; } + //Auto shutdown timer + furi_timer_free(power->auto_shutdown_timer); + // Records furi_record_close(RECORD_NOTIFICATION); furi_record_close(RECORD_GUI); @@ -197,6 +200,7 @@ static void power_check_charging_state(Power* power) { static bool power_update_info(Power* power) { PowerInfo info; + info.is_charging = furi_hal_power_is_charging(); info.gauge_is_ok = furi_hal_power_gauge_is_ok(); info.charge = furi_hal_power_get_pct(); info.health = furi_hal_power_get_bat_health_pct(); @@ -212,6 +216,7 @@ static bool power_update_info(Power* power) { furi_mutex_acquire(power->api_mtx, FuriWaitForever); bool need_refresh = power->info.charge != info.charge; + need_refresh |= power->info.is_charging != info.is_charging; power->info = info; furi_mutex_release(power->api_mtx); diff --git a/applications/power/power_service/power.h b/applications/services/power/power_service/power.h similarity index 95% rename from applications/power/power_service/power.h rename to applications/services/power/power_service/power.h index c516f28f6..bdf5fa529 100644 --- a/applications/power/power_service/power.h +++ b/applications/services/power/power_service/power.h @@ -4,6 +4,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + #define RECORD_POWER "power" typedef struct Power Power; @@ -32,6 +36,7 @@ typedef struct { typedef struct { bool gauge_is_ok; + bool is_charging; float current_charger; float current_gauge; @@ -87,3 +92,7 @@ bool power_is_battery_healthy(Power* power); * @param enable true - enable, false - disable */ void power_enable_low_battery_level_notification(Power* power, bool enable); + +#ifdef __cplusplus +} +#endif diff --git a/applications/power/power_service/power_api.c b/applications/services/power/power_service/power_api.c similarity index 100% rename from applications/power/power_service/power_api.c rename to applications/services/power/power_service/power_api.c diff --git a/applications/power/power_service/power_i.h b/applications/services/power/power_service/power_i.h old mode 100755 new mode 100644 similarity index 96% rename from applications/power/power_service/power_i.h rename to applications/services/power/power_service/power_i.h index 8e4486fef..dbd9fd240 --- a/applications/power/power_service/power_i.h +++ b/applications/services/power/power_service/power_i.h @@ -8,7 +8,7 @@ #include #include "views/power_off.h" -#include "power/power_settings.h" +#include #include "views/power_unplug_usb.h" #include diff --git a/applications/power/power_service/views/power_off.c b/applications/services/power/power_service/views/power_off.c similarity index 100% rename from applications/power/power_service/views/power_off.c rename to applications/services/power/power_service/views/power_off.c diff --git a/applications/power/power_service/views/power_off.h b/applications/services/power/power_service/views/power_off.h similarity index 100% rename from applications/power/power_service/views/power_off.h rename to applications/services/power/power_service/views/power_off.h diff --git a/applications/power/power_service/views/power_unplug_usb.c b/applications/services/power/power_service/views/power_unplug_usb.c similarity index 100% rename from applications/power/power_service/views/power_unplug_usb.c rename to applications/services/power/power_service/views/power_unplug_usb.c diff --git a/applications/power/power_service/views/power_unplug_usb.h b/applications/services/power/power_service/views/power_unplug_usb.h similarity index 100% rename from applications/power/power_service/views/power_unplug_usb.h rename to applications/services/power/power_service/views/power_unplug_usb.h diff --git a/applications/power/power_settings.h b/applications/services/power/power_settings.h similarity index 100% rename from applications/power/power_settings.h rename to applications/services/power/power_settings.h diff --git a/applications/power/power_settings_filename.h b/applications/services/power/power_settings_filename.h similarity index 100% rename from applications/power/power_settings_filename.h rename to applications/services/power/power_settings_filename.h diff --git a/applications/services/rpc/application.fam b/applications/services/rpc/application.fam new file mode 100644 index 000000000..7c0b68133 --- /dev/null +++ b/applications/services/rpc/application.fam @@ -0,0 +1,9 @@ +App( + appid="rpc_start", + apptype=FlipperAppType.STARTUP, + entry_point="rpc_on_system_start", + cdefines=["SRV_RPC"], + requires=["cli"], + order=10, + sdk_headers=["rpc_app.h"], +) diff --git a/applications/rpc/rpc.c b/applications/services/rpc/rpc.c similarity index 99% rename from applications/rpc/rpc.c rename to applications/services/rpc/rpc.c index d767a928d..abba6ea42 100644 --- a/applications/rpc/rpc.c +++ b/applications/services/rpc/rpc.c @@ -395,7 +395,7 @@ void rpc_session_close(RpcSession* session) { furi_thread_flags_set(furi_thread_get_id(session->thread), RpcEvtDisconnect); } -int32_t rpc_srv(void* p) { +void rpc_on_system_start(void* p) { UNUSED(p); Rpc* rpc = malloc(sizeof(Rpc)); @@ -406,8 +406,6 @@ int32_t rpc_srv(void* p) { cli, "start_rpc_session", CliCommandFlagParallelSafe, rpc_cli_command_start_session, rpc); furi_record_create(RECORD_RPC, rpc); - - return 0; } void rpc_add_handler(RpcSession* session, pb_size_t message_tag, RpcHandler* handler) { diff --git a/applications/rpc/rpc.h b/applications/services/rpc/rpc.h similarity index 98% rename from applications/rpc/rpc.h rename to applications/services/rpc/rpc.h index dea8b749f..40493949d 100644 --- a/applications/rpc/rpc.h +++ b/applications/services/rpc/rpc.h @@ -5,6 +5,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + #define RPC_BUFFER_SIZE (1024) #define RPC_MAX_MESSAGE_SIZE (1536) @@ -114,3 +118,7 @@ size_t rpc_session_feed(RpcSession* session, uint8_t* buffer, size_t size, TickT * @return bytes available in buffer */ size_t rpc_session_get_available_size(RpcSession* session); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/applications/rpc/rpc_app.c b/applications/services/rpc/rpc_app.c similarity index 100% rename from applications/rpc/rpc_app.c rename to applications/services/rpc/rpc_app.c diff --git a/applications/rpc/rpc_app.h b/applications/services/rpc/rpc_app.h similarity index 100% rename from applications/rpc/rpc_app.h rename to applications/services/rpc/rpc_app.h diff --git a/applications/rpc/rpc_cli.c b/applications/services/rpc/rpc_cli.c similarity index 100% rename from applications/rpc/rpc_cli.c rename to applications/services/rpc/rpc_cli.c diff --git a/applications/rpc/rpc_debug.c b/applications/services/rpc/rpc_debug.c similarity index 100% rename from applications/rpc/rpc_debug.c rename to applications/services/rpc/rpc_debug.c diff --git a/applications/rpc/rpc_gpio.c b/applications/services/rpc/rpc_gpio.c similarity index 100% rename from applications/rpc/rpc_gpio.c rename to applications/services/rpc/rpc_gpio.c diff --git a/applications/rpc/rpc_gui.c b/applications/services/rpc/rpc_gui.c similarity index 100% rename from applications/rpc/rpc_gui.c rename to applications/services/rpc/rpc_gui.c diff --git a/applications/rpc/rpc_i.h b/applications/services/rpc/rpc_i.h similarity index 100% rename from applications/rpc/rpc_i.h rename to applications/services/rpc/rpc_i.h diff --git a/applications/rpc/rpc_storage.c b/applications/services/rpc/rpc_storage.c similarity index 100% rename from applications/rpc/rpc_storage.c rename to applications/services/rpc/rpc_storage.c diff --git a/applications/rpc/rpc_system.c b/applications/services/rpc/rpc_system.c similarity index 100% rename from applications/rpc/rpc_system.c rename to applications/services/rpc/rpc_system.c diff --git a/applications/storage/application.fam b/applications/services/storage/application.fam similarity index 92% rename from applications/storage/application.fam rename to applications/services/storage/application.fam index 21089635b..7aa721cc3 100644 --- a/applications/storage/application.fam +++ b/applications/services/storage/application.fam @@ -8,6 +8,7 @@ App( provides=["storage_start"], stack_size=3 * 1024, order=120, + sdk_headers=["storage.h"], ) App( diff --git a/applications/storage/filesystem_api.c b/applications/services/storage/filesystem_api.c similarity index 100% rename from applications/storage/filesystem_api.c rename to applications/services/storage/filesystem_api.c diff --git a/applications/storage/filesystem_api_defines.h b/applications/services/storage/filesystem_api_defines.h similarity index 100% rename from applications/storage/filesystem_api_defines.h rename to applications/services/storage/filesystem_api_defines.h diff --git a/applications/storage/filesystem_api_internal.h b/applications/services/storage/filesystem_api_internal.h similarity index 100% rename from applications/storage/filesystem_api_internal.h rename to applications/services/storage/filesystem_api_internal.h diff --git a/applications/storage/storage.c b/applications/services/storage/storage.c similarity index 100% rename from applications/storage/storage.c rename to applications/services/storage/storage.c diff --git a/applications/storage/storage.h b/applications/services/storage/storage.h similarity index 100% rename from applications/storage/storage.h rename to applications/services/storage/storage.h diff --git a/applications/storage/storage_cli.c b/applications/services/storage/storage_cli.c similarity index 100% rename from applications/storage/storage_cli.c rename to applications/services/storage/storage_cli.c diff --git a/applications/storage/storage_external_api.c b/applications/services/storage/storage_external_api.c similarity index 100% rename from applications/storage/storage_external_api.c rename to applications/services/storage/storage_external_api.c diff --git a/applications/storage/storage_glue.c b/applications/services/storage/storage_glue.c similarity index 100% rename from applications/storage/storage_glue.c rename to applications/services/storage/storage_glue.c diff --git a/applications/storage/storage_glue.h b/applications/services/storage/storage_glue.h similarity index 100% rename from applications/storage/storage_glue.h rename to applications/services/storage/storage_glue.h diff --git a/applications/storage/storage_i.h b/applications/services/storage/storage_i.h similarity index 100% rename from applications/storage/storage_i.h rename to applications/services/storage/storage_i.h diff --git a/applications/storage/storage_internal_api.c b/applications/services/storage/storage_internal_api.c similarity index 100% rename from applications/storage/storage_internal_api.c rename to applications/services/storage/storage_internal_api.c diff --git a/applications/storage/storage_message.h b/applications/services/storage/storage_message.h similarity index 100% rename from applications/storage/storage_message.h rename to applications/services/storage/storage_message.h diff --git a/applications/storage/storage_processing.c b/applications/services/storage/storage_processing.c similarity index 100% rename from applications/storage/storage_processing.c rename to applications/services/storage/storage_processing.c diff --git a/applications/storage/storage_processing.h b/applications/services/storage/storage_processing.h similarity index 100% rename from applications/storage/storage_processing.h rename to applications/services/storage/storage_processing.h diff --git a/applications/storage/storage_sd_api.c b/applications/services/storage/storage_sd_api.c similarity index 100% rename from applications/storage/storage_sd_api.c rename to applications/services/storage/storage_sd_api.c diff --git a/applications/storage/storage_sd_api.h b/applications/services/storage/storage_sd_api.h similarity index 100% rename from applications/storage/storage_sd_api.h rename to applications/services/storage/storage_sd_api.h diff --git a/applications/storage/storage_test_app.c b/applications/services/storage/storage_test_app.c similarity index 100% rename from applications/storage/storage_test_app.c rename to applications/services/storage/storage_test_app.c diff --git a/applications/storage/storages/sd_notify.c b/applications/services/storage/storages/sd_notify.c similarity index 100% rename from applications/storage/storages/sd_notify.c rename to applications/services/storage/storages/sd_notify.c diff --git a/applications/storage/storages/sd_notify.h b/applications/services/storage/storages/sd_notify.h similarity index 100% rename from applications/storage/storages/sd_notify.h rename to applications/services/storage/storages/sd_notify.h diff --git a/applications/storage/storages/storage_ext.c b/applications/services/storage/storages/storage_ext.c similarity index 100% rename from applications/storage/storages/storage_ext.c rename to applications/services/storage/storages/storage_ext.c diff --git a/applications/storage/storages/storage_ext.h b/applications/services/storage/storages/storage_ext.h similarity index 100% rename from applications/storage/storages/storage_ext.h rename to applications/services/storage/storages/storage_ext.h diff --git a/applications/storage/storages/storage_int.c b/applications/services/storage/storages/storage_int.c similarity index 99% rename from applications/storage/storages/storage_int.c rename to applications/services/storage/storages/storage_int.c index 0765a92dc..cae61f16e 100644 --- a/applications/storage/storages/storage_int.c +++ b/applications/services/storage/storages/storage_int.c @@ -9,7 +9,7 @@ /* When less than LFS_RESERVED_PAGES_COUNT are left free, creation & * modification of non-dot files is restricted */ -#define LFS_RESERVED_PAGES_COUNT 5 +#define LFS_RESERVED_PAGES_COUNT 3 typedef struct { const size_t start_address; diff --git a/applications/storage/storages/storage_int.h b/applications/services/storage/storages/storage_int.h similarity index 100% rename from applications/storage/storages/storage_int.h rename to applications/services/storage/storages/storage_int.h diff --git a/applications/about/about.c b/applications/settings/about/about.c similarity index 100% rename from applications/about/about.c rename to applications/settings/about/about.c diff --git a/applications/about/application.fam b/applications/settings/about/application.fam similarity index 100% rename from applications/about/application.fam rename to applications/settings/about/application.fam diff --git a/applications/settings/application.fam b/applications/settings/application.fam new file mode 100644 index 000000000..cc4b9703d --- /dev/null +++ b/applications/settings/application.fam @@ -0,0 +1,10 @@ +App( + appid="settings_apps", + name="Basic settings apps bundle", + apptype=FlipperAppType.METAPACKAGE, + provides=[ + "passport", + "system_settings", + "about", + ], +) diff --git a/applications/settings/bt_settings_app/application.fam b/applications/settings/bt_settings_app/application.fam new file mode 100644 index 000000000..7a985046b --- /dev/null +++ b/applications/settings/bt_settings_app/application.fam @@ -0,0 +1,12 @@ +App( + appid="bt_settings", + name="Bluetooth", + apptype=FlipperAppType.SETTINGS, + entry_point="bt_settings_app", + stack_size=1 * 1024, + requires=[ + "bt", + "gui", + ], + order=10, +) diff --git a/applications/bt/bt_settings_app/bt_settings_app.c b/applications/settings/bt_settings_app/bt_settings_app.c old mode 100755 new mode 100644 similarity index 100% rename from applications/bt/bt_settings_app/bt_settings_app.c rename to applications/settings/bt_settings_app/bt_settings_app.c diff --git a/applications/bt/bt_settings_app/bt_settings_app.h b/applications/settings/bt_settings_app/bt_settings_app.h old mode 100755 new mode 100644 similarity index 96% rename from applications/bt/bt_settings_app/bt_settings_app.h rename to applications/settings/bt_settings_app/bt_settings_app.h index 5b4a8d139..c45ff3db0 --- a/applications/bt/bt_settings_app/bt_settings_app.h +++ b/applications/settings/bt_settings_app/bt_settings_app.h @@ -11,7 +11,7 @@ #include #include -#include "../bt_settings.h" +#include #include "scenes/bt_settings_scene.h" enum BtSettingsCustomEvent { diff --git a/applications/bt/bt_settings_app/scenes/bt_settings_scene.c b/applications/settings/bt_settings_app/scenes/bt_settings_scene.c similarity index 100% rename from applications/bt/bt_settings_app/scenes/bt_settings_scene.c rename to applications/settings/bt_settings_app/scenes/bt_settings_scene.c diff --git a/applications/bt/bt_settings_app/scenes/bt_settings_scene.h b/applications/settings/bt_settings_app/scenes/bt_settings_scene.h similarity index 100% rename from applications/bt/bt_settings_app/scenes/bt_settings_scene.h rename to applications/settings/bt_settings_app/scenes/bt_settings_scene.h diff --git a/applications/bt/bt_settings_app/scenes/bt_settings_scene_config.h b/applications/settings/bt_settings_app/scenes/bt_settings_scene_config.h old mode 100755 new mode 100644 similarity index 100% rename from applications/bt/bt_settings_app/scenes/bt_settings_scene_config.h rename to applications/settings/bt_settings_app/scenes/bt_settings_scene_config.h diff --git a/applications/bt/bt_settings_app/scenes/bt_settings_scene_forget_dev_confirm.c b/applications/settings/bt_settings_app/scenes/bt_settings_scene_forget_dev_confirm.c old mode 100755 new mode 100644 similarity index 100% rename from applications/bt/bt_settings_app/scenes/bt_settings_scene_forget_dev_confirm.c rename to applications/settings/bt_settings_app/scenes/bt_settings_scene_forget_dev_confirm.c diff --git a/applications/bt/bt_settings_app/scenes/bt_settings_scene_forget_dev_success.c b/applications/settings/bt_settings_app/scenes/bt_settings_scene_forget_dev_success.c old mode 100755 new mode 100644 similarity index 100% rename from applications/bt/bt_settings_app/scenes/bt_settings_scene_forget_dev_success.c rename to applications/settings/bt_settings_app/scenes/bt_settings_scene_forget_dev_success.c diff --git a/applications/bt/bt_settings_app/scenes/bt_settings_scene_start.c b/applications/settings/bt_settings_app/scenes/bt_settings_scene_start.c old mode 100755 new mode 100644 similarity index 100% rename from applications/bt/bt_settings_app/scenes/bt_settings_scene_start.c rename to applications/settings/bt_settings_app/scenes/bt_settings_scene_start.c diff --git a/applications/settings/desktop_settings/application.fam b/applications/settings/desktop_settings/application.fam new file mode 100644 index 000000000..d01a28d36 --- /dev/null +++ b/applications/settings/desktop_settings/application.fam @@ -0,0 +1,12 @@ +App( + appid="desktop_settings", + name="Desktop", + apptype=FlipperAppType.SETTINGS, + entry_point="desktop_settings_app", + requires=[ + "desktop", + "gui", + ], + stack_size=1 * 1024, + order=50, +) diff --git a/applications/desktop/desktop_settings/desktop_settings_app.c b/applications/settings/desktop_settings/desktop_settings_app.c similarity index 97% rename from applications/desktop/desktop_settings/desktop_settings_app.c rename to applications/settings/desktop_settings/desktop_settings_app.c index 89513a8b8..a2ed8b724 100644 --- a/applications/desktop/desktop_settings/desktop_settings_app.c +++ b/applications/settings/desktop_settings/desktop_settings_app.c @@ -4,7 +4,7 @@ #include "desktop_settings_app.h" #include "scenes/desktop_settings_scene.h" -#include "../views/desktop_view_pin_input.h" +#include static bool desktop_settings_custom_event_callback(void* context, uint32_t event) { furi_assert(context); @@ -89,7 +89,7 @@ void desktop_settings_app_free(DesktopSettingsApp* app) { extern int32_t desktop_settings_app(void* p) { DesktopSettingsApp* app = desktop_settings_app_alloc(); - LOAD_DESKTOP_SETTINGS(&app->settings); + DESKTOP_SETTINGS_LOAD(&app->settings); if(p && (strcmp(p, DESKTOP_SETTINGS_RUN_PIN_SETUP_ARG) == 0)) { scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinSetupHowto); } else { diff --git a/applications/desktop/desktop_settings/desktop_settings_app.h b/applications/settings/desktop_settings/desktop_settings_app.h similarity index 92% rename from applications/desktop/desktop_settings/desktop_settings_app.h rename to applications/settings/desktop_settings/desktop_settings_app.h index 93ca7b35c..25c5b3adb 100644 --- a/applications/desktop/desktop_settings/desktop_settings_app.h +++ b/applications/settings/desktop_settings/desktop_settings_app.h @@ -7,8 +7,8 @@ #include #include -#include "desktop_settings.h" -#include "desktop/views/desktop_view_pin_input.h" +#include +#include #include "views/desktop_settings_view_pin_setup_howto.h" #include "views/desktop_settings_view_pin_setup_howto2.h" diff --git a/applications/desktop/desktop_settings/scenes/desktop_settings_scene.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene.c similarity index 100% rename from applications/desktop/desktop_settings/scenes/desktop_settings_scene.c rename to applications/settings/desktop_settings/scenes/desktop_settings_scene.c diff --git a/applications/desktop/desktop_settings/scenes/desktop_settings_scene.h b/applications/settings/desktop_settings/scenes/desktop_settings_scene.h similarity index 100% rename from applications/desktop/desktop_settings/scenes/desktop_settings_scene.h rename to applications/settings/desktop_settings/scenes/desktop_settings_scene.h diff --git a/applications/desktop/desktop_settings/scenes/desktop_settings_scene_config.h b/applications/settings/desktop_settings/scenes/desktop_settings_scene_config.h similarity index 100% rename from applications/desktop/desktop_settings/scenes/desktop_settings_scene_config.h rename to applications/settings/desktop_settings/scenes/desktop_settings_scene_config.h diff --git a/applications/desktop/desktop_settings/scenes/desktop_settings_scene_favorite.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_favorite.c similarity index 97% rename from applications/desktop/desktop_settings/scenes/desktop_settings_scene_favorite.c rename to applications/settings/desktop_settings/scenes/desktop_settings_scene_favorite.c index 0ec18af7a..d8c579b3e 100644 --- a/applications/desktop/desktop_settings/scenes/desktop_settings_scene_favorite.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_favorite.c @@ -56,6 +56,6 @@ bool desktop_settings_scene_favorite_on_event(void* context, SceneManagerEvent e void desktop_settings_scene_favorite_on_exit(void* context) { DesktopSettingsApp* app = context; - SAVE_DESKTOP_SETTINGS(&app->settings); + DESKTOP_SETTINGS_SAVE(&app->settings); submenu_reset(app->submenu); } diff --git a/applications/desktop/desktop_settings/scenes/desktop_settings_scene_i.h b/applications/settings/desktop_settings/scenes/desktop_settings_scene_i.h similarity index 100% rename from applications/desktop/desktop_settings/scenes/desktop_settings_scene_i.h rename to applications/settings/desktop_settings/scenes/desktop_settings_scene_i.h diff --git a/applications/desktop/desktop_settings/scenes/desktop_settings_scene_pin_auth.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_auth.c similarity index 95% rename from applications/desktop/desktop_settings/scenes/desktop_settings_scene_pin_auth.c rename to applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_auth.c index c43fff6ad..5fed235ce 100644 --- a/applications/desktop/desktop_settings/scenes/desktop_settings_scene_pin_auth.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_auth.c @@ -1,10 +1,10 @@ #include #include #include -#include "../../helpers/pin_lock.h" +#include #include "../desktop_settings_app.h" -#include "desktop/desktop_settings/desktop_settings.h" -#include "desktop/views/desktop_view_pin_input.h" +#include +#include #include "desktop_settings_scene.h" #include "desktop_settings_scene_i.h" @@ -33,7 +33,7 @@ static void pin_auth_back_callback(void* context) { void desktop_settings_scene_pin_auth_on_enter(void* context) { DesktopSettingsApp* app = context; - LOAD_DESKTOP_SETTINGS(&app->settings); + DESKTOP_SETTINGS_LOAD(&app->settings); furi_assert(app->settings.pin_code.length > 0); desktop_view_pin_input_set_context(app->pin_input_view, app); diff --git a/applications/desktop/desktop_settings/scenes/desktop_settings_scene_pin_disable.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_disable.c similarity index 92% rename from applications/desktop/desktop_settings/scenes/desktop_settings_scene_pin_disable.c rename to applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_disable.c index f6f6b2562..7fbcc3252 100644 --- a/applications/desktop/desktop_settings/scenes/desktop_settings_scene_pin_disable.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_disable.c @@ -4,8 +4,7 @@ #include #include "../desktop_settings_app.h" -#include "../desktop_settings.h" -#include "desktop/desktop_settings/desktop_settings.h" +#include #include "desktop_settings_scene.h" #define SCENE_EVENT_EXIT (0U) @@ -21,7 +20,7 @@ void desktop_settings_scene_pin_disable_on_enter(void* context) { DesktopSettingsApp* app = context; app->settings.pin_code.length = 0; memset(app->settings.pin_code.data, '0', sizeof(app->settings.pin_code.data)); - SAVE_DESKTOP_SETTINGS(&app->settings); + DESKTOP_SETTINGS_SAVE(&app->settings); popup_set_context(app->popup, app); popup_set_callback(app->popup, pin_disable_back_callback); diff --git a/applications/desktop/desktop_settings/scenes/desktop_settings_scene_pin_error.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_error.c similarity index 95% rename from applications/desktop/desktop_settings/scenes/desktop_settings_scene_pin_error.c rename to applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_error.c index 38852dd8b..dd1e85795 100644 --- a/applications/desktop/desktop_settings/scenes/desktop_settings_scene_pin_error.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_error.c @@ -2,11 +2,11 @@ #include #include -#include "desktop/desktop_settings/desktop_settings.h" -#include "desktop/views/desktop_view_pin_input.h" +#include +#include #include "desktop_settings_scene.h" #include "desktop_settings_scene_i.h" -#include "../../helpers/pin_lock.h" +#include #include "../desktop_settings_app.h" #define SCENE_EVENT_EXIT (0U) diff --git a/applications/desktop/desktop_settings/scenes/desktop_settings_scene_pin_menu.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_menu.c similarity index 100% rename from applications/desktop/desktop_settings/scenes/desktop_settings_scene_pin_menu.c rename to applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_menu.c diff --git a/applications/desktop/desktop_settings/scenes/desktop_settings_scene_pin_setup.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_setup.c similarity index 96% rename from applications/desktop/desktop_settings/scenes/desktop_settings_scene_pin_setup.c rename to applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_setup.c index b536a343a..bf0f48ae6 100644 --- a/applications/desktop/desktop_settings/scenes/desktop_settings_scene_pin_setup.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_setup.c @@ -3,11 +3,11 @@ #include #include "../desktop_settings_app.h" -#include "desktop/desktop_settings/desktop_settings.h" -#include "desktop/views/desktop_view_pin_input.h" +#include +#include #include "desktop_settings_scene.h" #include "desktop_settings_scene_i.h" -#include "../../helpers/pin_lock.h" +#include #define SCENE_EVENT_EXIT (0U) #define SCENE_EVENT_1ST_PIN_ENTERED (1U) diff --git a/applications/desktop/desktop_settings/scenes/desktop_settings_scene_pin_setup_done.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_setup_done.c similarity index 95% rename from applications/desktop/desktop_settings/scenes/desktop_settings_scene_pin_setup_done.c rename to applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_setup_done.c index 424084288..f6ceb96de 100644 --- a/applications/desktop/desktop_settings/scenes/desktop_settings_scene_pin_setup_done.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_setup_done.c @@ -6,8 +6,8 @@ #include #include "../desktop_settings_app.h" -#include "desktop/desktop_settings/desktop_settings.h" -#include "desktop/views/desktop_view_pin_input.h" +#include +#include #include "desktop_settings_scene.h" #define SCENE_EVENT_DONE (0U) @@ -24,7 +24,7 @@ void desktop_settings_scene_pin_setup_done_on_enter(void* context) { DesktopSettingsApp* app = context; app->settings.pin_code = app->pincode_buffer; - SAVE_DESKTOP_SETTINGS(&app->settings); + DESKTOP_SETTINGS_SAVE(&app->settings); NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION); notification_message(notification, &sequence_single_vibro); furi_record_close(RECORD_NOTIFICATION); diff --git a/applications/desktop/desktop_settings/scenes/desktop_settings_scene_pin_setup_howto.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_setup_howto.c similarity index 100% rename from applications/desktop/desktop_settings/scenes/desktop_settings_scene_pin_setup_howto.c rename to applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_setup_howto.c diff --git a/applications/desktop/desktop_settings/scenes/desktop_settings_scene_pin_setup_howto2.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_setup_howto2.c similarity index 100% rename from applications/desktop/desktop_settings/scenes/desktop_settings_scene_pin_setup_howto2.c rename to applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_setup_howto2.c diff --git a/applications/desktop/desktop_settings/scenes/desktop_settings_scene_start.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c similarity index 98% rename from applications/desktop/desktop_settings/scenes/desktop_settings_scene_start.c rename to applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c index 8e649c695..8530a1a7d 100644 --- a/applications/desktop/desktop_settings/scenes/desktop_settings_scene_start.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c @@ -96,5 +96,5 @@ bool desktop_settings_scene_start_on_event(void* context, SceneManagerEvent even void desktop_settings_scene_start_on_exit(void* context) { DesktopSettingsApp* app = context; variable_item_list_reset(app->variable_item_list); - SAVE_DESKTOP_SETTINGS(&app->settings); + DESKTOP_SETTINGS_SAVE(&app->settings); } diff --git a/applications/desktop/desktop_settings/views/desktop_settings_view_pin_setup_howto.c b/applications/settings/desktop_settings/views/desktop_settings_view_pin_setup_howto.c similarity index 100% rename from applications/desktop/desktop_settings/views/desktop_settings_view_pin_setup_howto.c rename to applications/settings/desktop_settings/views/desktop_settings_view_pin_setup_howto.c diff --git a/applications/desktop/desktop_settings/views/desktop_settings_view_pin_setup_howto.h b/applications/settings/desktop_settings/views/desktop_settings_view_pin_setup_howto.h similarity index 100% rename from applications/desktop/desktop_settings/views/desktop_settings_view_pin_setup_howto.h rename to applications/settings/desktop_settings/views/desktop_settings_view_pin_setup_howto.h diff --git a/applications/desktop/desktop_settings/views/desktop_settings_view_pin_setup_howto2.c b/applications/settings/desktop_settings/views/desktop_settings_view_pin_setup_howto2.c similarity index 100% rename from applications/desktop/desktop_settings/views/desktop_settings_view_pin_setup_howto2.c rename to applications/settings/desktop_settings/views/desktop_settings_view_pin_setup_howto2.c diff --git a/applications/desktop/desktop_settings/views/desktop_settings_view_pin_setup_howto2.h b/applications/settings/desktop_settings/views/desktop_settings_view_pin_setup_howto2.h similarity index 100% rename from applications/desktop/desktop_settings/views/desktop_settings_view_pin_setup_howto2.h rename to applications/settings/desktop_settings/views/desktop_settings_view_pin_setup_howto2.h diff --git a/applications/dolphin/application.fam b/applications/settings/dolphin_passport/application.fam similarity index 56% rename from applications/dolphin/application.fam rename to applications/settings/dolphin_passport/application.fam index 1ee0e3cfe..4167e9dcd 100644 --- a/applications/dolphin/application.fam +++ b/applications/settings/dolphin_passport/application.fam @@ -1,13 +1,3 @@ -App( - appid="dolphin", - name="DolphinSrv", - apptype=FlipperAppType.SERVICE, - entry_point="dolphin_srv", - cdefines=["SRV_DOLPHIN"], - stack_size=1 * 1024, - order=50, -) - App( appid="passport", name="Passport", diff --git a/applications/dolphin/passport/passport.c b/applications/settings/dolphin_passport/passport.c similarity index 100% rename from applications/dolphin/passport/passport.c rename to applications/settings/dolphin_passport/passport.c diff --git a/applications/settings/notification_settings/application.fam b/applications/settings/notification_settings/application.fam new file mode 100644 index 000000000..117a83870 --- /dev/null +++ b/applications/settings/notification_settings/application.fam @@ -0,0 +1,9 @@ +App( + appid="notification_settings", + name="LCD and Notifications", + apptype=FlipperAppType.SETTINGS, + entry_point="notification_settings_app", + requires=["notification"], + stack_size=1 * 1024, + order=20, +) diff --git a/applications/notification/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c similarity index 99% rename from applications/notification/notification_settings_app.c rename to applications/settings/notification_settings/notification_settings_app.c index 894938f4c..d462163ad 100644 --- a/applications/notification/notification_settings_app.c +++ b/applications/settings/notification_settings/notification_settings_app.c @@ -1,5 +1,5 @@ #include -#include "notification_app.h" +#include #include #include #include diff --git a/applications/settings/power_settings_app/application.fam b/applications/settings/power_settings_app/application.fam new file mode 100644 index 000000000..a5b1966b2 --- /dev/null +++ b/applications/settings/power_settings_app/application.fam @@ -0,0 +1,13 @@ +App( + appid="power_settings", + name="Power", + apptype=FlipperAppType.SETTINGS, + entry_point="power_settings_app", + requires=[ + "gui", + "power", + ], + flags=["InsomniaSafe"], + stack_size=1 * 1024, + order=40, +) diff --git a/applications/power/power_settings_app/power_settings_app.c b/applications/settings/power_settings_app/power_settings_app.c similarity index 100% rename from applications/power/power_settings_app/power_settings_app.c rename to applications/settings/power_settings_app/power_settings_app.c diff --git a/applications/power/power_settings_app/power_settings_app.h b/applications/settings/power_settings_app/power_settings_app.h similarity index 96% rename from applications/power/power_settings_app/power_settings_app.h rename to applications/settings/power_settings_app/power_settings_app.h index 3ce42892b..9d2221b48 100644 --- a/applications/power/power_settings_app/power_settings_app.h +++ b/applications/settings/power_settings_app/power_settings_app.h @@ -12,7 +12,7 @@ #include #include -#include "power/power_settings.h" +#include #include "scenes/power_settings_scene.h" typedef struct { diff --git a/applications/power/power_settings_app/scenes/power_settings_scene.c b/applications/settings/power_settings_app/scenes/power_settings_scene.c similarity index 100% rename from applications/power/power_settings_app/scenes/power_settings_scene.c rename to applications/settings/power_settings_app/scenes/power_settings_scene.c diff --git a/applications/power/power_settings_app/scenes/power_settings_scene.h b/applications/settings/power_settings_app/scenes/power_settings_scene.h similarity index 100% rename from applications/power/power_settings_app/scenes/power_settings_scene.h rename to applications/settings/power_settings_app/scenes/power_settings_scene.h diff --git a/applications/power/power_settings_app/scenes/power_settings_scene_battery_info.c b/applications/settings/power_settings_app/scenes/power_settings_scene_battery_info.c old mode 100755 new mode 100644 similarity index 100% rename from applications/power/power_settings_app/scenes/power_settings_scene_battery_info.c rename to applications/settings/power_settings_app/scenes/power_settings_scene_battery_info.c diff --git a/applications/power/power_settings_app/scenes/power_settings_scene_config.h b/applications/settings/power_settings_app/scenes/power_settings_scene_config.h old mode 100755 new mode 100644 similarity index 100% rename from applications/power/power_settings_app/scenes/power_settings_scene_config.h rename to applications/settings/power_settings_app/scenes/power_settings_scene_config.h diff --git a/applications/power/power_settings_app/scenes/power_settings_scene_power_off.c b/applications/settings/power_settings_app/scenes/power_settings_scene_power_off.c similarity index 100% rename from applications/power/power_settings_app/scenes/power_settings_scene_power_off.c rename to applications/settings/power_settings_app/scenes/power_settings_scene_power_off.c diff --git a/applications/power/power_settings_app/scenes/power_settings_scene_reboot.c b/applications/settings/power_settings_app/scenes/power_settings_scene_reboot.c old mode 100755 new mode 100644 similarity index 100% rename from applications/power/power_settings_app/scenes/power_settings_scene_reboot.c rename to applications/settings/power_settings_app/scenes/power_settings_scene_reboot.c diff --git a/applications/power/power_settings_app/scenes/power_settings_scene_shutdown_idle.c b/applications/settings/power_settings_app/scenes/power_settings_scene_shutdown_idle.c similarity index 100% rename from applications/power/power_settings_app/scenes/power_settings_scene_shutdown_idle.c rename to applications/settings/power_settings_app/scenes/power_settings_scene_shutdown_idle.c diff --git a/applications/power/power_settings_app/scenes/power_settings_scene_start.c b/applications/settings/power_settings_app/scenes/power_settings_scene_start.c old mode 100755 new mode 100644 similarity index 100% rename from applications/power/power_settings_app/scenes/power_settings_scene_start.c rename to applications/settings/power_settings_app/scenes/power_settings_scene_start.c diff --git a/applications/power/power_settings_app/views/battery_info.c b/applications/settings/power_settings_app/views/battery_info.c similarity index 100% rename from applications/power/power_settings_app/views/battery_info.c rename to applications/settings/power_settings_app/views/battery_info.c diff --git a/applications/power/power_settings_app/views/battery_info.h b/applications/settings/power_settings_app/views/battery_info.h similarity index 100% rename from applications/power/power_settings_app/views/battery_info.h rename to applications/settings/power_settings_app/views/battery_info.h diff --git a/applications/storage_settings/application.fam b/applications/settings/storage_settings/application.fam similarity index 100% rename from applications/storage_settings/application.fam rename to applications/settings/storage_settings/application.fam diff --git a/applications/storage_settings/scenes/storage_settings_scene.c b/applications/settings/storage_settings/scenes/storage_settings_scene.c similarity index 100% rename from applications/storage_settings/scenes/storage_settings_scene.c rename to applications/settings/storage_settings/scenes/storage_settings_scene.c diff --git a/applications/storage_settings/scenes/storage_settings_scene.h b/applications/settings/storage_settings/scenes/storage_settings_scene.h similarity index 100% rename from applications/storage_settings/scenes/storage_settings_scene.h rename to applications/settings/storage_settings/scenes/storage_settings_scene.h diff --git a/applications/storage_settings/scenes/storage_settings_scene_benchmark.c b/applications/settings/storage_settings/scenes/storage_settings_scene_benchmark.c similarity index 100% rename from applications/storage_settings/scenes/storage_settings_scene_benchmark.c rename to applications/settings/storage_settings/scenes/storage_settings_scene_benchmark.c diff --git a/applications/storage_settings/scenes/storage_settings_scene_config.h b/applications/settings/storage_settings/scenes/storage_settings_scene_config.h similarity index 100% rename from applications/storage_settings/scenes/storage_settings_scene_config.h rename to applications/settings/storage_settings/scenes/storage_settings_scene_config.h diff --git a/applications/storage_settings/scenes/storage_settings_scene_factory_reset.c b/applications/settings/storage_settings/scenes/storage_settings_scene_factory_reset.c similarity index 100% rename from applications/storage_settings/scenes/storage_settings_scene_factory_reset.c rename to applications/settings/storage_settings/scenes/storage_settings_scene_factory_reset.c diff --git a/applications/storage_settings/scenes/storage_settings_scene_format_confirm.c b/applications/settings/storage_settings/scenes/storage_settings_scene_format_confirm.c similarity index 100% rename from applications/storage_settings/scenes/storage_settings_scene_format_confirm.c rename to applications/settings/storage_settings/scenes/storage_settings_scene_format_confirm.c diff --git a/applications/storage_settings/scenes/storage_settings_scene_formatting.c b/applications/settings/storage_settings/scenes/storage_settings_scene_formatting.c old mode 100755 new mode 100644 similarity index 100% rename from applications/storage_settings/scenes/storage_settings_scene_formatting.c rename to applications/settings/storage_settings/scenes/storage_settings_scene_formatting.c diff --git a/applications/storage_settings/scenes/storage_settings_scene_internal_info.c b/applications/settings/storage_settings/scenes/storage_settings_scene_internal_info.c similarity index 100% rename from applications/storage_settings/scenes/storage_settings_scene_internal_info.c rename to applications/settings/storage_settings/scenes/storage_settings_scene_internal_info.c diff --git a/applications/storage_settings/scenes/storage_settings_scene_sd_info.c b/applications/settings/storage_settings/scenes/storage_settings_scene_sd_info.c similarity index 100% rename from applications/storage_settings/scenes/storage_settings_scene_sd_info.c rename to applications/settings/storage_settings/scenes/storage_settings_scene_sd_info.c diff --git a/applications/storage_settings/scenes/storage_settings_scene_start.c b/applications/settings/storage_settings/scenes/storage_settings_scene_start.c similarity index 100% rename from applications/storage_settings/scenes/storage_settings_scene_start.c rename to applications/settings/storage_settings/scenes/storage_settings_scene_start.c diff --git a/applications/storage_settings/scenes/storage_settings_scene_unmount_confirm.c b/applications/settings/storage_settings/scenes/storage_settings_scene_unmount_confirm.c similarity index 100% rename from applications/storage_settings/scenes/storage_settings_scene_unmount_confirm.c rename to applications/settings/storage_settings/scenes/storage_settings_scene_unmount_confirm.c diff --git a/applications/storage_settings/scenes/storage_settings_scene_unmounted.c b/applications/settings/storage_settings/scenes/storage_settings_scene_unmounted.c similarity index 100% rename from applications/storage_settings/scenes/storage_settings_scene_unmounted.c rename to applications/settings/storage_settings/scenes/storage_settings_scene_unmounted.c diff --git a/applications/storage_settings/storage_settings.c b/applications/settings/storage_settings/storage_settings.c similarity index 100% rename from applications/storage_settings/storage_settings.c rename to applications/settings/storage_settings/storage_settings.c diff --git a/applications/storage_settings/storage_settings.h b/applications/settings/storage_settings/storage_settings.h similarity index 100% rename from applications/storage_settings/storage_settings.h rename to applications/settings/storage_settings/storage_settings.h diff --git a/applications/settings/system/application.fam b/applications/settings/system/application.fam new file mode 100644 index 000000000..0fc456b2f --- /dev/null +++ b/applications/settings/system/application.fam @@ -0,0 +1,9 @@ +App( + appid="system_settings", + name="System", + apptype=FlipperAppType.SETTINGS, + entry_point="system_settings_app", + requires=["gui"], + stack_size=1 * 1024, + order=70, +) diff --git a/applications/system/system_settings.c b/applications/settings/system/system_settings.c similarity index 100% rename from applications/system/system_settings.c rename to applications/settings/system/system_settings.c diff --git a/applications/system/system_settings.h b/applications/settings/system/system_settings.h old mode 100755 new mode 100644 similarity index 100% rename from applications/system/system_settings.h rename to applications/settings/system/system_settings.h diff --git a/applications/system/application.fam b/applications/system/application.fam index 0fc456b2f..a59f840e4 100644 --- a/applications/system/application.fam +++ b/applications/system/application.fam @@ -1,9 +1,10 @@ App( - appid="system_settings", - name="System", - apptype=FlipperAppType.SETTINGS, - entry_point="system_settings_app", - requires=["gui"], - stack_size=1 * 1024, - order=70, + appid="system_apps", + name="Applications not shown in menus", + apptype=FlipperAppType.METAPACKAGE, + provides=[ + "updater_app", + "storage_move_to_sd", + # "archive", + ], ) diff --git a/applications/storage_move_to_sd/application.fam b/applications/system/storage_move_to_sd/application.fam similarity index 100% rename from applications/storage_move_to_sd/application.fam rename to applications/system/storage_move_to_sd/application.fam diff --git a/applications/storage_move_to_sd/scenes/storage_move_to_sd_scene.c b/applications/system/storage_move_to_sd/scenes/storage_move_to_sd_scene.c similarity index 100% rename from applications/storage_move_to_sd/scenes/storage_move_to_sd_scene.c rename to applications/system/storage_move_to_sd/scenes/storage_move_to_sd_scene.c diff --git a/applications/storage_move_to_sd/scenes/storage_move_to_sd_scene.h b/applications/system/storage_move_to_sd/scenes/storage_move_to_sd_scene.h similarity index 100% rename from applications/storage_move_to_sd/scenes/storage_move_to_sd_scene.h rename to applications/system/storage_move_to_sd/scenes/storage_move_to_sd_scene.h diff --git a/applications/storage_move_to_sd/scenes/storage_move_to_sd_scene_config.h b/applications/system/storage_move_to_sd/scenes/storage_move_to_sd_scene_config.h similarity index 100% rename from applications/storage_move_to_sd/scenes/storage_move_to_sd_scene_config.h rename to applications/system/storage_move_to_sd/scenes/storage_move_to_sd_scene_config.h diff --git a/applications/storage_move_to_sd/scenes/storage_move_to_sd_scene_confirm.c b/applications/system/storage_move_to_sd/scenes/storage_move_to_sd_scene_confirm.c similarity index 100% rename from applications/storage_move_to_sd/scenes/storage_move_to_sd_scene_confirm.c rename to applications/system/storage_move_to_sd/scenes/storage_move_to_sd_scene_confirm.c diff --git a/applications/storage_move_to_sd/scenes/storage_move_to_sd_scene_progress.c b/applications/system/storage_move_to_sd/scenes/storage_move_to_sd_scene_progress.c similarity index 100% rename from applications/storage_move_to_sd/scenes/storage_move_to_sd_scene_progress.c rename to applications/system/storage_move_to_sd/scenes/storage_move_to_sd_scene_progress.c diff --git a/applications/storage_move_to_sd/storage_move_to_sd.c b/applications/system/storage_move_to_sd/storage_move_to_sd.c similarity index 100% rename from applications/storage_move_to_sd/storage_move_to_sd.c rename to applications/system/storage_move_to_sd/storage_move_to_sd.c diff --git a/applications/storage_move_to_sd/storage_move_to_sd.h b/applications/system/storage_move_to_sd/storage_move_to_sd.h similarity index 100% rename from applications/storage_move_to_sd/storage_move_to_sd.h rename to applications/system/storage_move_to_sd/storage_move_to_sd.h diff --git a/applications/updater/application.fam b/applications/system/updater/application.fam similarity index 100% rename from applications/updater/application.fam rename to applications/system/updater/application.fam diff --git a/applications/updater/cli/updater_cli.c b/applications/system/updater/cli/updater_cli.c similarity index 100% rename from applications/updater/cli/updater_cli.c rename to applications/system/updater/cli/updater_cli.c diff --git a/applications/updater/scenes/updater_scene.c b/applications/system/updater/scenes/updater_scene.c similarity index 100% rename from applications/updater/scenes/updater_scene.c rename to applications/system/updater/scenes/updater_scene.c diff --git a/applications/updater/scenes/updater_scene.h b/applications/system/updater/scenes/updater_scene.h similarity index 100% rename from applications/updater/scenes/updater_scene.h rename to applications/system/updater/scenes/updater_scene.h diff --git a/applications/updater/scenes/updater_scene_config.h b/applications/system/updater/scenes/updater_scene_config.h similarity index 100% rename from applications/updater/scenes/updater_scene_config.h rename to applications/system/updater/scenes/updater_scene_config.h diff --git a/applications/updater/scenes/updater_scene_error.c b/applications/system/updater/scenes/updater_scene_error.c similarity index 98% rename from applications/updater/scenes/updater_scene_error.c rename to applications/system/updater/scenes/updater_scene_error.c index 362c471a6..21bf16372 100644 --- a/applications/updater/scenes/updater_scene_error.c +++ b/applications/system/updater/scenes/updater_scene_error.c @@ -1,4 +1,4 @@ -#include "updater/updater_i.h" +#include "../updater_i.h" #include "updater_scene.h" #include diff --git a/applications/updater/scenes/updater_scene_loadcfg.c b/applications/system/updater/scenes/updater_scene_loadcfg.c similarity index 99% rename from applications/updater/scenes/updater_scene_loadcfg.c rename to applications/system/updater/scenes/updater_scene_loadcfg.c index 1fd87d002..c7f48c78b 100644 --- a/applications/updater/scenes/updater_scene_loadcfg.c +++ b/applications/system/updater/scenes/updater_scene_loadcfg.c @@ -1,4 +1,4 @@ -#include "updater/updater_i.h" +#include "../updater_i.h" #include "updater_scene.h" #include diff --git a/applications/updater/scenes/updater_scene_main.c b/applications/system/updater/scenes/updater_scene_main.c similarity index 98% rename from applications/updater/scenes/updater_scene_main.c rename to applications/system/updater/scenes/updater_scene_main.c index 5f7aeaca4..2ef0732ca 100644 --- a/applications/updater/scenes/updater_scene_main.c +++ b/applications/system/updater/scenes/updater_scene_main.c @@ -3,8 +3,8 @@ #include #include -#include "updater/updater_i.h" -#include "updater/views/updater_main.h" +#include "../updater_i.h" +#include "../views/updater_main.h" #include "updater_scene.h" static void sd_mount_callback(const void* message, void* context) { diff --git a/applications/updater/updater.c b/applications/system/updater/updater.c similarity index 100% rename from applications/updater/updater.c rename to applications/system/updater/updater.c diff --git a/applications/updater/updater_i.h b/applications/system/updater/updater_i.h similarity index 100% rename from applications/updater/updater_i.h rename to applications/system/updater/updater_i.h diff --git a/applications/updater/util/update_task.c b/applications/system/updater/util/update_task.c similarity index 100% rename from applications/updater/util/update_task.c rename to applications/system/updater/util/update_task.c diff --git a/applications/updater/util/update_task.h b/applications/system/updater/util/update_task.h similarity index 100% rename from applications/updater/util/update_task.h rename to applications/system/updater/util/update_task.h diff --git a/applications/updater/util/update_task_i.h b/applications/system/updater/util/update_task_i.h similarity index 100% rename from applications/updater/util/update_task_i.h rename to applications/system/updater/util/update_task_i.h diff --git a/applications/updater/util/update_task_worker_backup.c b/applications/system/updater/util/update_task_worker_backup.c similarity index 100% rename from applications/updater/util/update_task_worker_backup.c rename to applications/system/updater/util/update_task_worker_backup.c diff --git a/applications/updater/util/update_task_worker_flasher.c b/applications/system/updater/util/update_task_worker_flasher.c similarity index 100% rename from applications/updater/util/update_task_worker_flasher.c rename to applications/system/updater/util/update_task_worker_flasher.c diff --git a/applications/updater/views/updater_main.c b/applications/system/updater/views/updater_main.c similarity index 100% rename from applications/updater/views/updater_main.c rename to applications/system/updater/views/updater_main.c diff --git a/applications/updater/views/updater_main.h b/applications/system/updater/views/updater_main.h similarity index 100% rename from applications/updater/views/updater_main.h rename to applications/system/updater/views/updater_main.h diff --git a/applications_user/.gitignore b/applications_user/.gitignore new file mode 100644 index 000000000..72e8ffc0d --- /dev/null +++ b/applications_user/.gitignore @@ -0,0 +1 @@ +* diff --git a/applications_user/README.md b/applications_user/README.md new file mode 100644 index 000000000..8bb7823c1 --- /dev/null +++ b/applications_user/README.md @@ -0,0 +1 @@ +Put your custom applications in this folder. \ No newline at end of file diff --git a/assets/.gitignore b/assets/.gitignore index eb20456f1..9bc0bdc0c 100644 --- a/assets/.gitignore +++ b/assets/.gitignore @@ -1,2 +1,3 @@ -/headers /core2_firmware +/resources/Manifest +/resources/apps/* \ No newline at end of file diff --git a/assets/SConscript b/assets/SConscript index ecb109567..47713d1a6 100644 --- a/assets/SConscript +++ b/assets/SConscript @@ -1,13 +1,5 @@ Import("env") -# HACHHACK -# Currently injected to CPPPATH by libs - since they are built earlier and depend on assets -# env.Append( -# CPPPATH=[ -# Dir("./compiled"), -# ] -# ) - assetsenv = env.Clone( tools=["fbt_assets"], FW_LIB_NAME="assets", @@ -27,7 +19,9 @@ if not assetsenv["VERBOSE"]: icons_src = assetsenv.GlobRecursive("*.png", "icons") icons_src += assetsenv.GlobRecursive("frame_rate", "icons") -icons = assetsenv.IconBuilder(Dir("compiled"), Dir("#/assets/icons")) +icons = assetsenv.IconBuilder( + assetsenv.Dir("compiled"), ICON_SRC_DIR=assetsenv.Dir("#/assets/icons") +) assetsenv.Depends(icons, icons_src) assetsenv.Alias("icons", icons) @@ -92,7 +86,6 @@ if assetsenv["IS_BASE_FIRMWARE"]: assetsenv.Alias("dolphin_ext", dolphin_external) # Resources manifest - resources = assetsenv.Command( "#/assets/resources/Manifest", assetsenv.GlobRecursive("*", "resources", exclude="Manifest"), @@ -101,11 +94,14 @@ if assetsenv["IS_BASE_FIRMWARE"]: "${RESMANIFESTCOMSTR}", ), ) - assetsenv.Precious(resources) - assetsenv.NoClean(resources) assetsenv.AlwaysBuild(resources) + assetsenv.Clean( + resources, + assetsenv.Dir("#/assets/resources/apps"), + ) # Exporting resources node to external environment + env["FW_ASSETS_HEADERS"] = assets_parts env["FW_RESOURCES"] = resources assetsenv.Alias("resources", resources) diff --git a/assets/icons/Common/Round_loader_8x8/frame_01.png b/assets/icons/Common/Round_loader_8x8/frame_01.png new file mode 100644 index 000000000..a5dc239d8 Binary files /dev/null and b/assets/icons/Common/Round_loader_8x8/frame_01.png differ diff --git a/assets/icons/Common/Round_loader_8x8/frame_02.png b/assets/icons/Common/Round_loader_8x8/frame_02.png new file mode 100644 index 000000000..162d8a8f4 Binary files /dev/null and b/assets/icons/Common/Round_loader_8x8/frame_02.png differ diff --git a/assets/icons/Common/Round_loader_8x8/frame_03.png b/assets/icons/Common/Round_loader_8x8/frame_03.png new file mode 100644 index 000000000..5483e4734 Binary files /dev/null and b/assets/icons/Common/Round_loader_8x8/frame_03.png differ diff --git a/assets/icons/Common/Round_loader_8x8/frame_04.png b/assets/icons/Common/Round_loader_8x8/frame_04.png new file mode 100644 index 000000000..ce2fbbd47 Binary files /dev/null and b/assets/icons/Common/Round_loader_8x8/frame_04.png differ diff --git a/assets/icons/Common/Round_loader_8x8/frame_05.png b/assets/icons/Common/Round_loader_8x8/frame_05.png new file mode 100644 index 000000000..8b786c029 Binary files /dev/null and b/assets/icons/Common/Round_loader_8x8/frame_05.png differ diff --git a/assets/icons/Common/Round_loader_8x8/frame_rate b/assets/icons/Common/Round_loader_8x8/frame_rate new file mode 100644 index 000000000..d8263ee98 --- /dev/null +++ b/assets/icons/Common/Round_loader_8x8/frame_rate @@ -0,0 +1 @@ +2 \ No newline at end of file diff --git a/assets/icons/NFC/Keychain.png b/assets/icons/NFC/ArrowC_1_36x36.png similarity index 84% rename from assets/icons/NFC/Keychain.png rename to assets/icons/NFC/ArrowC_1_36x36.png index 7ba1b11da..3a0c6dd0c 100644 Binary files a/assets/icons/NFC/Keychain.png and b/assets/icons/NFC/ArrowC_1_36x36.png differ diff --git a/assets/icons/NFC/Keychain_39x36.png b/assets/icons/NFC/Keychain_39x36.png new file mode 100644 index 000000000..d15850b5b Binary files /dev/null and b/assets/icons/NFC/Keychain_39x36.png differ diff --git a/assets/icons/NFC/NFC_manual.png b/assets/icons/NFC/NFC_manual_60x50.png similarity index 100% rename from assets/icons/NFC/NFC_manual.png rename to assets/icons/NFC/NFC_manual_60x50.png diff --git a/assets/icons/NFC/Reader_detect.png b/assets/icons/NFC/Reader_detect.png deleted file mode 100644 index 56d3663ea..000000000 Binary files a/assets/icons/NFC/Reader_detect.png and /dev/null differ diff --git a/assets/icons/NFC/Reader_detect_43x40.png b/assets/icons/NFC/Reader_detect_43x40.png new file mode 100644 index 000000000..d833a5277 Binary files /dev/null and b/assets/icons/NFC/Reader_detect_43x40.png differ diff --git a/assets/icons/NFC/Restoring.png b/assets/icons/NFC/Restoring_38x32.png similarity index 100% rename from assets/icons/NFC/Restoring.png rename to assets/icons/NFC/Restoring_38x32.png diff --git a/assets/icons/NFC/Tap_reader_36x38.png b/assets/icons/NFC/Tap_reader_36x38.png new file mode 100644 index 000000000..4e0ba8f05 Binary files /dev/null and b/assets/icons/NFC/Tap_reader_36x38.png differ diff --git a/assets/icons/PIN/Pin_arrow_up7x9.png b/assets/icons/PIN/Pin_arrow_up_7x9.png similarity index 100% rename from assets/icons/PIN/Pin_arrow_up7x9.png rename to assets/icons/PIN/Pin_arrow_up_7x9.png diff --git a/assets/icons/StatusBar/GameMode_11x8.png b/assets/icons/StatusBar/GameMode_11x8.png new file mode 100644 index 000000000..49f2e25bf Binary files /dev/null and b/assets/icons/StatusBar/GameMode_11x8.png differ diff --git a/assets/resources/Manifest b/assets/resources/Manifest deleted file mode 100644 index 8bfdcef7e..000000000 --- a/assets/resources/Manifest +++ /dev/null @@ -1,241 +0,0 @@ -V:0 -T:1660218073 -D:badusb -D:dolphin -D:infrared -D:music_player -D:nfc -D:subghz -D:u2f -F:0e41ba26498b7511d7c9e6e6b5e3b149:1592:badusb/demo_macos.txt -F:46a332993ca94b9aa692030ebaa19c70:1552:badusb/demo_windows.txt -D:dolphin/L1_Boxing_128x64 -D:dolphin/L1_Cry_128x64 -D:dolphin/L1_Furippa1_128x64 -D:dolphin/L1_Laptop_128x51 -D:dolphin/L1_Leaving_sad_128x64 -D:dolphin/L1_Mad_fist_128x64 -D:dolphin/L1_Read_books_128x64 -D:dolphin/L1_Recording_128x51 -D:dolphin/L1_Sleep_128x64 -D:dolphin/L1_Waves_128x50 -D:dolphin/L2_Furippa2_128x64 -D:dolphin/L2_Hacking_pc_128x64 -D:dolphin/L2_Soldering_128x64 -D:dolphin/L3_Furippa3_128x64 -D:dolphin/L3_Hijack_radio_128x64 -D:dolphin/L3_Lab_research_128x54 -F:d1148ab5354eaf4fa7f959589d840932:1563:dolphin/manifest.txt -F:d37be8444102ec5cde5fe3a85d55b57d:481:dolphin/L1_Boxing_128x64/frame_0.bm -F:54fb07443bc153ded9589b74d23b4263:461:dolphin/L1_Boxing_128x64/frame_1.bm -F:e007afe130d699c715b99ce8e5b407bd:531:dolphin/L1_Boxing_128x64/frame_2.bm -F:a999a9a6c76c66158f1aa5ccb56de7c9:437:dolphin/L1_Boxing_128x64/frame_3.bm -F:ec6af9cb451ab16c0fa62e95e8134b49:459:dolphin/L1_Boxing_128x64/frame_4.bm -F:2aa0c1e7bf1131b9dc172aa595ec01f2:450:dolphin/L1_Boxing_128x64/frame_5.bm -F:bbc8f750d17d156438c5cfe1122ec7f4:442:dolphin/L1_Boxing_128x64/frame_6.bm -F:f6e51ada3e3285e330714dab5b4277dd:418:dolphin/L1_Boxing_128x64/meta.txt -F:ab33a6f37209541f3db938d1cfe1706f:889:dolphin/L1_Cry_128x64/frame_0.bm -F:1b3fdeb404af0f7402caa5a5e091a8f8:911:dolphin/L1_Cry_128x64/frame_1.bm -F:4db644b173af72f3d371d2bd81f76b05:910:dolphin/L1_Cry_128x64/frame_2.bm -F:cd4c0ef67a8e514edecd9600242db068:923:dolphin/L1_Cry_128x64/frame_3.bm -F:ee02e9589e0714d3e2bc0d93aa294ccb:894:dolphin/L1_Cry_128x64/frame_4.bm -F:7703a7d9745d13b45d73ce4b86b4cdc8:940:dolphin/L1_Cry_128x64/frame_5.bm -F:ee6de6a0ed903317c4948cb445e0a9a8:915:dolphin/L1_Cry_128x64/frame_6.bm -F:a3892e45826c66f48d3d64fb81521446:934:dolphin/L1_Cry_128x64/frame_7.bm -F:680b12cc4dad722d6583b7e710bfc297:516:dolphin/L1_Cry_128x64/meta.txt -F:4911eaa7cb84ced19e5dea2af51b91a5:294:dolphin/L1_Furippa1_128x64/frame_0.bm -F:5669bee57c7b3d93a1665dd87fd5372a:325:dolphin/L1_Furippa1_128x64/frame_1.bm -F:80b48a77682b853e6236cd1c89083e6f:465:dolphin/L1_Furippa1_128x64/frame_10.bm -F:9d8ea10bf3d3831cb4a94957dc0b41c6:698:dolphin/L1_Furippa1_128x64/frame_11.bm -F:2dbb3125ea63550906fba8f7ec7b1da3:541:dolphin/L1_Furippa1_128x64/frame_12.bm -F:6a06b718957dca9caa63a4f3baa73abb:584:dolphin/L1_Furippa1_128x64/frame_13.bm -F:5450bf16c3d2fceaf5e6ea585b7ef7c1:610:dolphin/L1_Furippa1_128x64/frame_14.bm -F:535c0eca62703eb7df36f17334a6191b:719:dolphin/L1_Furippa1_128x64/frame_15.bm -F:7c03af85ade9b791755f3a4d106c2b7c:458:dolphin/L1_Furippa1_128x64/frame_16.bm -F:41b8fea16ad8705f4594e6119eade395:400:dolphin/L1_Furippa1_128x64/frame_17.bm -F:2db7fd3da5208a8e41902ae27cf41702:333:dolphin/L1_Furippa1_128x64/frame_18.bm -F:7e47428442e0f04959fc6afde979936e:351:dolphin/L1_Furippa1_128x64/frame_2.bm -F:0eb187078f169d7a852e97ecf430aea0:324:dolphin/L1_Furippa1_128x64/frame_3.bm -F:967c402971a442a5bf28eba804bb3ff4:387:dolphin/L1_Furippa1_128x64/frame_4.bm -F:175cb930fba0fc86f54a3a109b741708:390:dolphin/L1_Furippa1_128x64/frame_5.bm -F:f8c3ee1ab657549d1d00c1c72d8d2ff5:407:dolphin/L1_Furippa1_128x64/frame_6.bm -F:4911eaa7cb84ced19e5dea2af51b91a5:294:dolphin/L1_Furippa1_128x64/frame_7.bm -F:8f649ff34b224f4e564644a4494c54ed:283:dolphin/L1_Furippa1_128x64/frame_8.bm -F:3ec3c40d26bf8d3e691b1335d20d4ec0:312:dolphin/L1_Furippa1_128x64/frame_9.bm -F:ebe088426d184cf6651288accd21add6:241:dolphin/L1_Furippa1_128x64/meta.txt -F:d02fdfd1a3b89da00d2acf32bd09da80:555:dolphin/L1_Laptop_128x51/frame_0.bm -F:7e29ea503d41023fa3895d15458f106d:557:dolphin/L1_Laptop_128x51/frame_1.bm -F:eb55e0629de873f537d8412ced528eb4:560:dolphin/L1_Laptop_128x51/frame_2.bm -F:1516472ab3c140dd5bd4d089caa44747:556:dolphin/L1_Laptop_128x51/frame_3.bm -F:61172f89cf0a17bd7f978edccdeed166:560:dolphin/L1_Laptop_128x51/frame_4.bm -F:9d54913928c7e9477b6b8a43f3767621:554:dolphin/L1_Laptop_128x51/frame_5.bm -F:5243d6272bbb213e9c17af07ee011402:553:dolphin/L1_Laptop_128x51/frame_6.bm -F:aa68e0f28f117891ba0f4d7613224fc6:560:dolphin/L1_Laptop_128x51/frame_7.bm -F:9ef1935ab29fe70bbc517f4b602547d7:403:dolphin/L1_Laptop_128x51/meta.txt -F:6ce34e62c5bf4764a4163101afe63e60:514:dolphin/L1_Leaving_sad_128x64/frame_0.bm -F:19a0e0c518d222d91d24b8712ab6bb80:526:dolphin/L1_Leaving_sad_128x64/frame_1.bm -F:837bfb424c8d8a3bfbda7d6a28ba5a5c:316:dolphin/L1_Leaving_sad_128x64/frame_10.bm -F:1a69b6f63a96e0958837ea8b21db3966:294:dolphin/L1_Leaving_sad_128x64/frame_11.bm -F:c3ea827593a4563d544dfb7e99d73885:322:dolphin/L1_Leaving_sad_128x64/frame_12.bm -F:1e3842669191fe9599f830ac133e0751:542:dolphin/L1_Leaving_sad_128x64/frame_2.bm -F:9161660e6827bd776a15eefa2a8add19:557:dolphin/L1_Leaving_sad_128x64/frame_3.bm -F:d01a79fdb4f84397d82bf9927aeb71e0:488:dolphin/L1_Leaving_sad_128x64/frame_4.bm -F:316e30ef319c080fab2a79c21e526319:469:dolphin/L1_Leaving_sad_128x64/frame_5.bm -F:09a812d59b60b5fe7724057daa14ad60:499:dolphin/L1_Leaving_sad_128x64/frame_6.bm -F:9eb07b76cc864a0ce2918d68e41d4500:486:dolphin/L1_Leaving_sad_128x64/frame_7.bm -F:cf8c4cc4abbd700b096037b7ebfd0e31:403:dolphin/L1_Leaving_sad_128x64/frame_8.bm -F:889728ded689203aa82193e573912d18:317:dolphin/L1_Leaving_sad_128x64/frame_9.bm -F:2bff1f09ad1e9059a60e08990ca1d414:477:dolphin/L1_Leaving_sad_128x64/meta.txt -F:c31a882e95ed5c69fd63226db2188710:520:dolphin/L1_Mad_fist_128x64/frame_0.bm -F:740326828f6ba6e29373943ba835e77f:540:dolphin/L1_Mad_fist_128x64/frame_1.bm -F:0c9693dda040fd73ca6d773a10924bd8:542:dolphin/L1_Mad_fist_128x64/frame_10.bm -F:425c1d101debd1e9502db2628640b704:505:dolphin/L1_Mad_fist_128x64/frame_11.bm -F:aa576f7dbd14ec682f6c50314165fb14:501:dolphin/L1_Mad_fist_128x64/frame_12.bm -F:712335eabefb8c7bb7fb2f4301419c10:500:dolphin/L1_Mad_fist_128x64/frame_13.bm -F:b6e11711ea4dcc2e64f267d888f91baf:515:dolphin/L1_Mad_fist_128x64/frame_2.bm -F:61bdd22a2b1e67efe093b6acf7dfadce:538:dolphin/L1_Mad_fist_128x64/frame_3.bm -F:20ae06a3ce7a07656e578edb024e2b3f:512:dolphin/L1_Mad_fist_128x64/frame_4.bm -F:45cf2bd55365a7328df39fe98a496cc9:519:dolphin/L1_Mad_fist_128x64/frame_5.bm -F:4b8840eebb3a4a1ead69a7130816047e:524:dolphin/L1_Mad_fist_128x64/frame_6.bm -F:0de4497a5fbf80cc93e523465c5e3122:515:dolphin/L1_Mad_fist_128x64/frame_7.bm -F:32d8ddeb19bfa415fe283666b1e323a2:517:dolphin/L1_Mad_fist_128x64/frame_8.bm -F:a42a0578c2d0411500fb3485a3beb536:526:dolphin/L1_Mad_fist_128x64/frame_9.bm -F:10a521c78168a5928c859494e2a61cd2:349:dolphin/L1_Mad_fist_128x64/meta.txt -F:61565b7be9a69a60ce2dbae0273df347:653:dolphin/L1_Read_books_128x64/frame_0.bm -F:cf5a2d423540e3af37e789d70c9c1fbf:653:dolphin/L1_Read_books_128x64/frame_1.bm -F:c91935861979d024e6637b8810889878:650:dolphin/L1_Read_books_128x64/frame_2.bm -F:0c007a30f396f3e7a0ded2b24080357d:646:dolphin/L1_Read_books_128x64/frame_3.bm -F:323a52816dd79d6d3186f451e26e06ad:650:dolphin/L1_Read_books_128x64/frame_4.bm -F:494f27958f4cea9b94d09cf27725c5cd:652:dolphin/L1_Read_books_128x64/frame_5.bm -F:a6a7491fe80255e1745c9f293da52805:646:dolphin/L1_Read_books_128x64/frame_6.bm -F:238497e6643fd491cd6002e98c615c05:647:dolphin/L1_Read_books_128x64/frame_7.bm -F:300651e8f53d9a29ae38d4b9292c73cf:643:dolphin/L1_Read_books_128x64/frame_8.bm -F:3d9568deeff646b677092902a98f9ceb:325:dolphin/L1_Read_books_128x64/meta.txt -F:2aba555567ab70cff003ded4138c6721:663:dolphin/L1_Recording_128x51/frame_0.bm -F:8456c6e86825957e5662e2f08eb6c116:657:dolphin/L1_Recording_128x51/frame_1.bm -F:2e4a1aca5afa5a6ab254884210875eb4:629:dolphin/L1_Recording_128x51/frame_10.bm -F:9f1cf96598e3d935879b1d0c97705778:659:dolphin/L1_Recording_128x51/frame_11.bm -F:409abfeca974e5649affcd1faafea988:628:dolphin/L1_Recording_128x51/frame_2.bm -F:66b2a5abf05acbf79f9943e01b8b8cec:654:dolphin/L1_Recording_128x51/frame_3.bm -F:d55c5ed28c2ff48f42ab30b420d64fa3:662:dolphin/L1_Recording_128x51/frame_4.bm -F:2ce12d8cfdd953c9dadb9459c580a320:622:dolphin/L1_Recording_128x51/frame_5.bm -F:da631e3837fcdf3ee9e6abdf17fb764b:664:dolphin/L1_Recording_128x51/frame_6.bm -F:604a7cdac2491c9bc2e88b9e91c99dcc:626:dolphin/L1_Recording_128x51/frame_7.bm -F:fc94649dc98244dd9a0ab7fe62721d3c:663:dolphin/L1_Recording_128x51/frame_8.bm -F:b2475ab8ee26cbd9a403ee603520bd35:661:dolphin/L1_Recording_128x51/frame_9.bm -F:a7c2b3b420706712149cc2426c68df4f:219:dolphin/L1_Recording_128x51/meta.txt -F:9858fd34b55cebcb9be50c5710212a13:580:dolphin/L1_Sleep_128x64/frame_0.bm -F:e47ef8c846083b8fde028b1724861444:589:dolphin/L1_Sleep_128x64/frame_1.bm -F:9749bd05b47fd07cc3a41ab201f86bf4:582:dolphin/L1_Sleep_128x64/frame_2.bm -F:edf11266b20b846ace622e41cd36906b:597:dolphin/L1_Sleep_128x64/frame_3.bm -F:8fbb96a9d809d85fa6bad931fe4e6fe2:510:dolphin/L1_Sleep_128x64/meta.txt -F:283b41f1b2c581c510ff176293b7288a:443:dolphin/L1_Waves_128x50/frame_0.bm -F:c9fc5127e1d8a4217b6b177716725ba0:448:dolphin/L1_Waves_128x50/frame_1.bm -F:8e0797bf26d5d8d3cbeb99798c222b80:463:dolphin/L1_Waves_128x50/frame_2.bm -F:da02b1deb3119b31f2b8f182d5bf3242:472:dolphin/L1_Waves_128x50/frame_3.bm -F:8e6fb4133acbda7e5bb9adad0aed306c:620:dolphin/L1_Waves_128x50/meta.txt -F:be80d2fa903e3250b69c063a1eef0621:350:dolphin/L2_Furippa2_128x64/frame_0.bm -F:9e628f5e154f12d6c57b13befed1f5f6:385:dolphin/L2_Furippa2_128x64/frame_1.bm -F:80b48a77682b853e6236cd1c89083e6f:465:dolphin/L2_Furippa2_128x64/frame_10.bm -F:9d8ea10bf3d3831cb4a94957dc0b41c6:698:dolphin/L2_Furippa2_128x64/frame_11.bm -F:2dbb3125ea63550906fba8f7ec7b1da3:541:dolphin/L2_Furippa2_128x64/frame_12.bm -F:6a06b718957dca9caa63a4f3baa73abb:584:dolphin/L2_Furippa2_128x64/frame_13.bm -F:5450bf16c3d2fceaf5e6ea585b7ef7c1:610:dolphin/L2_Furippa2_128x64/frame_14.bm -F:e3c92103f403857b502081d3b058e53a:740:dolphin/L2_Furippa2_128x64/frame_15.bm -F:432669d796bbf7be1d14f5b7db036a92:533:dolphin/L2_Furippa2_128x64/frame_16.bm -F:53485c6b465c80a1ce8ddf03c4976039:451:dolphin/L2_Furippa2_128x64/frame_17.bm -F:333b75b16c088428a28259c931630fb9:397:dolphin/L2_Furippa2_128x64/frame_18.bm -F:ed02d68380382361f3f01cbf01d13b0c:402:dolphin/L2_Furippa2_128x64/frame_2.bm -F:b0ba042d7b60dc5681182b1d4005f0a2:374:dolphin/L2_Furippa2_128x64/frame_3.bm -F:518a84fa5a4e9e7f84246d5d82e87f15:440:dolphin/L2_Furippa2_128x64/frame_4.bm -F:9b7b0ae6f4f55d30cb43b0465216aa25:449:dolphin/L2_Furippa2_128x64/frame_5.bm -F:03b153949b0dae2efe1fc5f0dc57a0ef:466:dolphin/L2_Furippa2_128x64/frame_6.bm -F:be80d2fa903e3250b69c063a1eef0621:350:dolphin/L2_Furippa2_128x64/frame_7.bm -F:a8433f451cf3efc4ce2fb04a38c1f84f:319:dolphin/L2_Furippa2_128x64/frame_8.bm -F:d32a11bf9779d57191c1e59fe69cf83d:317:dolphin/L2_Furippa2_128x64/frame_9.bm -F:ebe088426d184cf6651288accd21add6:241:dolphin/L2_Furippa2_128x64/meta.txt -F:af4ec0085c29732085c51b18dc97bc27:543:dolphin/L2_Hacking_pc_128x64/frame_0.bm -F:eb141965fb6fb9f8b28766bac92abe1a:545:dolphin/L2_Hacking_pc_128x64/frame_1.bm -F:f7b33d3541dab08aaf4e8375e262b982:548:dolphin/L2_Hacking_pc_128x64/frame_2.bm -F:03634d90c54fd235aa76c0f9f794c80b:608:dolphin/L2_Hacking_pc_128x64/frame_3.bm -F:4c77406302f3fb74f8bdba568097082a:609:dolphin/L2_Hacking_pc_128x64/frame_4.bm -F:b0d1783358094534ac95b3455124d5fe:409:dolphin/L2_Hacking_pc_128x64/meta.txt -F:584c92e6fb15e99389b84d567e6d4d02:699:dolphin/L2_Soldering_128x64/frame_0.bm -F:3fa01b93460379204b6d14f43573b4f3:688:dolphin/L2_Soldering_128x64/frame_1.bm -F:6fad29757d4b7231b1d0ec53d0529b45:699:dolphin/L2_Soldering_128x64/frame_10.bm -F:e82c83e5a03abf4f6a1efd0a0f1ca33a:689:dolphin/L2_Soldering_128x64/frame_2.bm -F:7f9f310e22ef85af225dd1aefa2c47ba:689:dolphin/L2_Soldering_128x64/frame_3.bm -F:1ff31af6f90f07c0cdfa3283f52a5adc:693:dolphin/L2_Soldering_128x64/frame_4.bm -F:1a8f25aff949860cc6ffc79b4f48d5dd:696:dolphin/L2_Soldering_128x64/frame_5.bm -F:dbaa75feb8aebaf9b1cc5201c29952b8:712:dolphin/L2_Soldering_128x64/frame_6.bm -F:ee356bd981fba90c402d8e08d3015792:732:dolphin/L2_Soldering_128x64/frame_7.bm -F:09d5c5a685df606562d407bb9dac798e:705:dolphin/L2_Soldering_128x64/frame_8.bm -F:5451816e73bad029b3b9f3f55d294582:698:dolphin/L2_Soldering_128x64/frame_9.bm -F:c38ffad11987faf5ba6e363ead705e78:319:dolphin/L2_Soldering_128x64/meta.txt -F:2e083023ab65d1f99bba71f9aae6db9a:398:dolphin/L3_Furippa3_128x64/frame_0.bm -F:8cf20e07d84fd6a1157ba932beca70ea:438:dolphin/L3_Furippa3_128x64/frame_1.bm -F:018344c951691b7b1d77c1c6729d3e42:559:dolphin/L3_Furippa3_128x64/frame_10.bm -F:07008e2508064ab7a8467802472a9803:728:dolphin/L3_Furippa3_128x64/frame_11.bm -F:2dbb3125ea63550906fba8f7ec7b1da3:541:dolphin/L3_Furippa3_128x64/frame_12.bm -F:6a06b718957dca9caa63a4f3baa73abb:584:dolphin/L3_Furippa3_128x64/frame_13.bm -F:5450bf16c3d2fceaf5e6ea585b7ef7c1:610:dolphin/L3_Furippa3_128x64/frame_14.bm -F:e333224a4bed87b606df57a252ed4887:741:dolphin/L3_Furippa3_128x64/frame_15.bm -F:a20a6abfbd66fc3f92c66adacc4444a3:559:dolphin/L3_Furippa3_128x64/frame_16.bm -F:c1e051dce6b90e4f69b4792d0356a6b3:492:dolphin/L3_Furippa3_128x64/frame_17.bm -F:377f3621507c6590120cbc1c8ca92999:445:dolphin/L3_Furippa3_128x64/frame_18.bm -F:81f09c0fcd2bddb8a107a199e7149230:463:dolphin/L3_Furippa3_128x64/frame_2.bm -F:ed7fd1ada1070493462c1899f7372baf:424:dolphin/L3_Furippa3_128x64/frame_3.bm -F:e5fb2cdc4e08d6abff3191d37a1007ed:499:dolphin/L3_Furippa3_128x64/frame_4.bm -F:923a05250e5a93c7db7bbbf48448d164:504:dolphin/L3_Furippa3_128x64/frame_5.bm -F:1e9628db28a9a908c4a4b24cb16c5d20:521:dolphin/L3_Furippa3_128x64/frame_6.bm -F:2e083023ab65d1f99bba71f9aae6db9a:398:dolphin/L3_Furippa3_128x64/frame_7.bm -F:f1ec6e12daba9490f9e2e0e308ae3f83:419:dolphin/L3_Furippa3_128x64/frame_8.bm -F:106997120ad4cd23bd51e6f26bd7d74d:435:dolphin/L3_Furippa3_128x64/frame_9.bm -F:ebe088426d184cf6651288accd21add6:241:dolphin/L3_Furippa3_128x64/meta.txt -F:42970030123b2468984785fea7c60318:524:dolphin/L3_Hijack_radio_128x64/frame_0.bm -F:491c6d8ef21e48ca0f6b5fbd269c820b:527:dolphin/L3_Hijack_radio_128x64/frame_1.bm -F:ff499c8716c5f7fc1110a5ee82bda20c:550:dolphin/L3_Hijack_radio_128x64/frame_10.bm -F:ee39d82d6efc6a6992d19b6d75a6c509:572:dolphin/L3_Hijack_radio_128x64/frame_11.bm -F:5d14e8cb9d67bf8f597d6c749d07a135:539:dolphin/L3_Hijack_radio_128x64/frame_12.bm -F:9461004b75a34a36097668159c4cabe6:579:dolphin/L3_Hijack_radio_128x64/frame_13.bm -F:c925d4b1dff9c81463944cf930d7da8d:526:dolphin/L3_Hijack_radio_128x64/frame_2.bm -F:f98ed80cfab3a94b580be81654401c89:529:dolphin/L3_Hijack_radio_128x64/frame_3.bm -F:97ba548c27732be9e05fb8f7be8204ce:571:dolphin/L3_Hijack_radio_128x64/frame_4.bm -F:524932eb2391057fc1dea7237c7086e3:574:dolphin/L3_Hijack_radio_128x64/frame_5.bm -F:8eb9672f719926ac9c4c158575f388cd:524:dolphin/L3_Hijack_radio_128x64/frame_6.bm -F:7ca93fbab93bc278d4a11089d624a07b:655:dolphin/L3_Hijack_radio_128x64/frame_7.bm -F:37b4368f0b7235f3a7347bf499541666:645:dolphin/L3_Hijack_radio_128x64/frame_8.bm -F:ea9c3d7bab4756c2916369d5e130fa71:611:dolphin/L3_Hijack_radio_128x64/frame_9.bm -F:8583743f18a12ff647d3478e7aebdad6:230:dolphin/L3_Hijack_radio_128x64/meta.txt -F:f5f02a9df03bba734bdb7ed3297795f0:611:dolphin/L3_Lab_research_128x54/frame_0.bm -F:8f9655ad286464159443922d00e45620:614:dolphin/L3_Lab_research_128x54/frame_1.bm -F:7793b1bc107d4ea2e311e92dc16bf946:576:dolphin/L3_Lab_research_128x54/frame_10.bm -F:f24b8409f9dc770f3845424fe0ab489e:585:dolphin/L3_Lab_research_128x54/frame_11.bm -F:4ea93c4482dac43f40b67cc308f21e6d:571:dolphin/L3_Lab_research_128x54/frame_12.bm -F:cf3bb68dc78c568db22f37057a9fdd66:615:dolphin/L3_Lab_research_128x54/frame_13.bm -F:79719219aaebc95ea525def9173cabf5:618:dolphin/L3_Lab_research_128x54/frame_2.bm -F:05572cfd756704acd6ce9d6c15d03fc0:608:dolphin/L3_Lab_research_128x54/frame_3.bm -F:a26604a0d5427d5cf62a7a911a68b16c:615:dolphin/L3_Lab_research_128x54/frame_4.bm -F:9edc345fe53017970f93dc680818e63e:618:dolphin/L3_Lab_research_128x54/frame_5.bm -F:cf3bb68dc78c568db22f37057a9fdd66:615:dolphin/L3_Lab_research_128x54/frame_6.bm -F:5442895c85f769349288aa3df0990f9d:585:dolphin/L3_Lab_research_128x54/frame_7.bm -F:33b8fde22f34ef556b64b77164bc19b0:578:dolphin/L3_Lab_research_128x54/frame_8.bm -F:f267f0654781049ca323b11bb4375519:581:dolphin/L3_Lab_research_128x54/frame_9.bm -F:41106c0cbc5144f151b2b2d3daaa0527:727:dolphin/L3_Lab_research_128x54/meta.txt -D:infrared/assets -F:a565c3a381695a5f2ba7a0698460238c:74833:infrared/assets/tv.ir -F:a157a80f5a668700403d870c23b9567d:470:music_player/Marble_Machine.fmf -D:nfc/assets -F:81dc04c7b181f94b644079a71476dff4:4742:nfc/assets/aid.nfc -F:86efbebdf41bb6bf15cc51ef88f069d5:2565:nfc/assets/country_code.nfc -F:41b4f08774249014cb8d3dffa5f5c07d:1757:nfc/assets/currency_code.nfc -F:c60e862919731b0bd538a1001bbc1098:17453:nfc/assets/mf_classic_dict.nfc -D:subghz/assets -F:dda1ef895b8a25fde57c874feaaef997:650:subghz/assets/came_atomo -F:788eef2cc74e29f3388463d6607dab0d:3264:subghz/assets/keeloq_mfcodes -F:9214f9c10463b746a27e82ce0b96e040:465:subghz/assets/keeloq_mfcodes_user -F:653bd8d349055a41e1152e557d4a52d3:202:subghz/assets/nice_flor_s -F:c1c63fbd5f5aa3ea504027014652191f:1150:subghz/assets/setting_user -D:u2f/assets -F:7e11e688e39034bbb9d88410044795e1:365:u2f/assets/cert.der -F:f60b88c20ed479ed9684e249f7134618:264:u2f/assets/cert_key.u2f diff --git a/assets/unit_tests/subghz/clemsa.sub b/assets/unit_tests/subghz/clemsa.sub new file mode 100644 index 000000000..b07d031f0 --- /dev/null +++ b/assets/unit_tests/subghz/clemsa.sub @@ -0,0 +1,7 @@ +Filetype: Flipper SubGhz Key File +Version: 1 +Frequency: 433920000 +Preset: FuriHalSubGhzPresetOok650Async +Protocol: Clemsa +Bit: 18 +Key: 00 00 00 00 00 02 FC AA diff --git a/assets/unit_tests/subghz/clemsa_raw.sub b/assets/unit_tests/subghz/clemsa_raw.sub new file mode 100644 index 000000000..5f86de98c --- /dev/null +++ b/assets/unit_tests/subghz/clemsa_raw.sub @@ -0,0 +1,14 @@ +Filetype: Flipper SubGhz RAW File +Version: 1 +Frequency: 433920000 +Preset: FuriHalSubGhzPresetOok650Async +Protocol: RAW +RAW_Data: -334 10811 -4320 65 -100 65 -698 10157 -7550 65 -200 165 -166 133 -66 531 -66 331 -102 197 -132 133 -298 99 -132 263 -200 261 -988 99 -262 131 -296 97 -132 229 -100 459 -100 131 -132 393 -100 1119 -100 8325 -6376 133 -366 131 -562 65 -1034 131 -198 563 -168 365 -66 229 -332 297 -100 231 -166 429 -132 295 -166 97 -100 195 -724 97 -132 97 -1088 163 -200 1651 -100 2885 -8520 365 -166 97 -1558 163 -198 163 -132 465 -134 131 -66 267 -198 65 -232 299 -66 165 -166 65 -498 165 -100 233 -200 133 -166 131 -68 821 -100 263 -66 7633 -7610 1259 -200 99 -98 165 -1196 99 -132 263 -266 99 -200 463 -66 627 -66 1981 -98 7801 -4004 97 -628 65 -264 133 -1088 163 -134 131 -928 297 -166 133 -134 131 -266 297 -596 229 -164 427 -564 197 -166 265 -198 65 -100 559 -6708 131 -132 131 -430 527 -200 367 -66 263 -198 233 -98 299 -68 365 -296 465 -132 855 -66 857 -98 4741 -8312 99 -364 163 -200 133 -1428 529 -132 65 -166 595 -1392 97 -100 97 -132 99 -264 199 -828 99 -398 297 -66 233 -98 861 -100 663 -100 2357 -100 5075 -4640 131 -3312 231 -100 363 -132 99 -296 99 -132 165 -132 363 -98 165 -130 65 -98 165 -132 163 -130 63 -164 297 -198 9769 -3852 133 -98 67 -1226 329 -526 99 -164 295 -496 1713 -196 1681 -130 131 -132 5497 -7230 65 -1150 133 -330 259 -66 329 -100 97 -988 165 -134 197 -166 67 -100 361 -68 461 -100 231 -132 165 -66 365 -264 231 -100 99 -98 265 -696 99 -166 199 -100 101 -962 7101 -6484 363 -760 363 -132 265 -134 431 -264 329 -66 427 -330 263 -164 593 -130 231 -130 627 -66 399 -432 329 -526 131 -100 591 -166 9305 -4044 65 -3532 361 -98 163 -66 461 -264 197 -98 391 -66 329 -132 165 -136 463 -66 529 -166 131 -100 199 -264 133 -66 361 -98 689 -66 229 -198 627 -66 297 -100 261 -66 1685 -134 7883 -3932 229 -728 133 -98 133 -862 65 -132 99 -498 297 -166 133 -332 197 -132 693 -198 97 -656 1087 -64 6209 -6164 131 -266 99 -496 165 -432 67 -100 97 -330 821 -98 361 -100 493 -164 133 -66 197 -200 431 -66 65 -66 399 -66 331 -200 199 -402 131 -664 10955 -5314 65 -262 97 -198 97 -724 99 -196 65 -592 327 -66 625 -262 131 -66 197 -64 427 -132 65 -628 265 -332 329 -368 789 -66 8809 -6238 129 -328 295 -232 363 -98 431 -100 199 -98 261 -530 561 -592 263 -132 1645 -5358 65 -764 65 -330 165 -1158 197 -432 265 -98 397 -166 463 -498 561 -398 199 -66 199 -66 3479 +RAW_Data: -12124 165 -626 65 -890 229 -362 1329 -66 2187 -98 2081 -66 725 -134 3309 -9856 165 -166 263 -198 65 -960 653 -66 261 -66 821 -66 12463 -4032 97 -166 97 -924 65 -464 97 -68 163 -198 165 -100 263 -232 97 -366 633 -12244 65 -332 231 -200 197 -134 197 -234 2457 -134 399 -132 923 -198 197 -64 331 -132 295 -66 11377 -3896 163 -98 65 -194 131 -132 231 -366 131 -132 65 -1050 197 -200 299 -66 3007 -100 11685 -6172 133 -1154 491 -100 293 -200 65 -98 429 -266 463 -64 797 -98 265 -266 397 -132 1227 -66 8485 -4224 97 -166 65 -100 199 -2706 65 -66 263 -98 299 -298 231 -100 499 -66 97 -134 295 -66 431 -198 565 -66 2093 -100 533 -4056 65 -1482 229 -1160 165 -168 299 -166 459 -66 165 -134 99 -100 497 -166 397 -200 431 -200 65 -66 661 -164 529 -66 4671 -8442 131 -100 65 -66 165 -530 131 -132 597 -66 963 -488 275 -2806 2641 -438 2639 -420 2691 -412 2677 -404 2669 -416 2693 -416 361 -2730 367 -2724 2665 -422 355 -2726 2687 -394 399 -2698 2697 -390 375 -2732 2701 -388 355 -21244 2697 -416 377 -2722 2675 -416 2689 -388 2707 -396 2679 -414 2689 -392 2717 -388 375 -2706 383 -2732 2673 -396 365 -2734 2695 -386 377 -2728 2689 -384 389 -2730 2671 -386 379 -21252 2693 -416 347 -2748 2687 -396 2707 -384 2701 -388 2679 -412 2701 -418 2669 -404 363 -2726 385 -2698 2699 -416 355 -2706 2689 -416 365 -2736 2673 -386 415 -2692 2709 -378 361 -21270 2685 -452 311 -2774 2637 -442 2665 -418 2661 -448 2653 -408 2703 -384 2687 -410 365 -2738 355 -2742 2689 -382 371 -2738 2677 -384 415 -2700 2673 -410 363 -2730 2701 -386 357 -21270 2705 -398 361 -2740 2689 -386 2679 -414 2687 -410 2673 -418 2697 -386 2681 -412 383 -2702 395 -2706 2703 -380 385 -2696 2709 -418 355 -2702 2699 -418 361 -2700 2717 -386 375 -21242 2697 -418 355 -2748 2695 -382 2683 -410 2703 -380 2707 -384 2705 -404 2675 -416 383 -2700 359 -2728 2695 -382 385 -2728 2687 -416 357 -2708 2705 -386 389 -2700 2717 -388 373 -21234 2721 -418 353 -2724 2667 -416 2705 -380 2693 -386 2711 -384 2691 -422 2699 -398 365 -2726 385 -2700 2703 -378 361 -2728 2697 -420 357 -2704 2711 -388 377 -2734 2667 -406 363 -21260 2699 -418 361 -2702 2711 -380 2695 -416 2689 -402 2687 -384 2695 -416 2677 -408 361 -2732 385 -2704 2707 -414 325 -2730 2695 -418 361 -2728 2669 -414 385 -2702 2701 -414 355 -21246 2705 -378 379 -2728 2693 -384 2715 -380 2717 -386 2695 -390 2709 -388 2683 -420 355 -2730 385 -2700 2685 -416 347 -2748 2683 -396 365 -2740 2667 -416 385 -2696 2693 -414 349 -21260 2689 -452 319 -2762 2631 -476 2627 -430 2689 +RAW_Data: -416 2667 -412 2671 -416 2689 -424 347 -2732 353 -2738 2669 -410 363 -2728 2689 -410 349 -2742 2677 -386 415 -2696 2705 -380 361 -21254 2717 -386 413 -2700 2693 -380 2695 -416 2691 -398 2679 -416 2699 -384 2709 -382 367 -2726 361 -2730 2707 -382 377 -2728 2675 -386 411 -2684 2713 -414 357 -2704 2707 -388 357 -21276 2699 -382 385 -2724 2689 -416 2661 -416 2685 -384 2723 -388 2703 -400 2677 -416 385 -2696 357 -2724 2713 -384 375 -2726 2673 -420 355 -2728 2685 -396 397 -2688 2697 -408 363 -21252 2667 -484 311 -2766 2635 -476 2637 -420 2665 -448 2651 -408 2701 -384 2697 -406 355 -2758 327 -2736 2685 -420 361 -2728 2683 -384 385 -2726 2685 -414 357 -2708 2711 -388 375 -21246 2689 -448 323 -2750 2695 -378 2715 -386 2687 -392 2711 -384 2683 -416 2705 -412 327 -2732 387 -2728 2679 -416 357 -2738 2659 -418 363 -2732 2677 -386 413 -2700 2695 -380 391 -21258 2679 -406 383 -2706 2695 -384 2703 -418 2679 -404 2705 -380 2687 -418 2669 -410 359 -2726 387 -2696 2707 -416 357 -2710 2693 -418 361 -2730 2691 -380 385 -2730 2677 -414 357 -21254 2711 -382 385 -2700 2713 -414 2667 -384 2705 -418 2675 -406 2699 -382 2689 -418 365 -2726 377 -2708 2701 -384 389 -2698 2709 -398 361 -2738 2669 -416 385 -2692 2687 -418 357 -77456 131 -398 197 -132 295 -330 97 -132 229 -164 459 -164 295 -264 393 -264 719 -64 427 -98 855 -134 395 -98 297 -164 263 -262 65 -100 63 -132 197 -328 1185 -66 9359 -6420 261 -664 131 -100 299 -134 301 -232 363 -232 299 -200 165 -166 427 -230 299 -164 361 -394 1025 -100 225 -820 165 -1248 491 -100 293 -66 261 -264 131 -98 589 -164 655 -132 427 -132 295 -164 129 -132 163 -328 263 -196 627 -566 129 -100 131 -98 2377 -130 1255 -3878 297 -232 195 -132 65 -98 165 -596 397 -266 99 -198 363 -98 923 -100 431 -66 1383 -3724 297 -166 165 -66 99 -398 265 -266 463 -232 133 -232 65 -230 65 -266 959 -200 99 -298 231 -68 65 -100 97 -398 363 -132 199 -134 133 -134 133 -266 593 -66 363 -66 827 -2374 65 -1724 399 -166 265 -100 331 -198 165 -398 233 -98 233 -66 165 -266 97 -66 231 -132 165 -298 395 -234 99 -132 65 -100 99 -132 131 -66 297 -264 197 -194 229 -530 2189 -166 9577 -3702 199 -98 465 -398 97 -134 395 -132 429 -100 529 -68 263 -132 265 -368 263 -860 97 -100 163 -196 427 -98 163 -166 327 -98 493 -166 327 -98 233 -5094 99 -198 97 -100 65 -1250 131 -560 855 -66 855 -262 859 -164 10219 -7528 761 -66 1121 -100 429 -298 331 -232 263 -166 261 -166 265 -100 1427 -98 9787 -6682 131 -564 429 +RAW_Data: -66 529 -66 2519 -66 265 -68 10101 -1794 65 -1890 393 -562 97 -132 197 -98 493 -330 97 -164 97 -230 327 -326 99 -100 97 -164 65 -132 293 -98 297 -166 161 -130 297 -230 1391 -68 11185 -3800 229 -230 297 -66 65 -198 65 -466 99 -464 99 -430 67 -698 295 -132 165 -164 1095 -66 299 -66 1321 -264 12675 -66 99 -166 229 -134 65 -330 165 -164 65 -890 131 -830 67 -66 1157 -100 167 -168 265 -66 827 -66 2047 -100 261 -594 2279 -134 10701 -3890 163 -1384 67 -98 99 -1322 99 -98 65 -398 823 -66 65 -68 927 -100 495 -132 593 -100 165 -198 1387 -1022 131 -728 99 -662 97 -462 495 -200 829 -330 563 -100 297 -330 65 -598 165 -592 295 -166 131 -764 165 -164 565 -66 131 -166 165 -66 9675 -5052 165 -2878 199 -66 265 -432 265 -66 267 -898 163 -132 231 -198 229 -164 97 -100 4445 -66 7853 -636 199 -662 265 -298 233 -1428 331 -134 1791 -66 1649 -66 297 -100 361 -198 559 -98 363 -200 1315 -66 265 -98 1049 -132 1647 -66 265 -822 295 -526 131 -1712 199 -166 231 -200 165 -66 265 -166 97 -132 163 -164 395 -630 495 -168 297 -298 229 -266 629 -200 133 -132 133 -166 65 -132 99 -100 131 -66 67 -98 133 -496 1391 -98 1751 -164 359 -132 97 -164 263 -64 691 -66 199 -66 293 -98 589 -198 11299 -3968 65 -68 65 -2702 65 -1186 927 -166 65 -66 429 -134 197 -134 529 -200 67 -66 231 -100 2151 -4014 97 -1486 99 -464 65 -330 129 -330 331 -134 599 -66 497 -200 165 -66 661 -166 6881 -8830 295 -100 197 -232 725 -134 299 -166 229 -166 525 -198 295 -66 459 -66 329 -230 595 -98 299 -132 329 -66 99 -98 163 -134 229 -100 8345 -6726 131 -132 295 -66 1579 -66 329 -98 501 -132 231 -66 491 -298 331 -266 363 -132 1193 -168 8847 -4194 199 -828 65 -100 195 -262 197 -298 65 -898 65 -132 629 -66 229 -100 291 -100 623 -66 295 -66 461 -132 529 -632 597 -132 65 -100 97 -134 297 -100 297 -166 397 -168 527 -134 9603 -3850 99 -200 67 -896 959 -198 165 -100 229 -266 531 -64 165 -132 163 -296 3715 -11994 165 -1492 429 -68 263 -100 265 -330 199 -64 495 -132 363 -66 63 -166 297 -398 65 -100 231 -332 199 -100 7683 -4916 65 -1294 297 -1022 1325 -166 393 -132 165 -498 1255 -134 197 -198 427 -164 329 -132 631 -594 199 -196 99 -100 265 -134 1457 -100 3649 -8592 67 -268 131 -332 99 -100 65 -760 101 -198 297 -168 199 -132 369 -100 97 -132 99 -232 397 -198 99 -134 97 -100 231 -332 131 -796 329 -266 263 +RAW_Data: -100 10841 -4030 163 -164 197 -398 195 -592 65 -132 63 -430 295 -298 263 -200 3517 -132 3763 -12296 99 -330 361 -98 99 -200 65 -430 165 -166 2327 -100 4051 -66 9653 -3478 197 -66 163 -198 167 -66 65 -598 165 -298 131 -666 199 -198 299 -298 165 -200 565 -66 797 -98 1125 -98 825 -100 4113 -6956 65 -5536 165 -266 99 -232 461 -198 65 -200 1989 -66 295 -66 723 -66 65 -98 329 -98 955 -66 559 -232 331 -66 10851 -1048 65 -3748 65 -498 99 -1392 99 -794 529 -98 331 -98 397 -164 363 -394 331 -266 299 -230 165 -66 3001 -568 197 -2872 2579 -468 2637 -472 2599 -488 2647 -426 2653 -448 2665 -392 379 -2734 381 -2700 2691 -388 377 -2732 2669 -420 355 -2726 2687 -394 403 -2706 2687 -388 377 -21248 2717 -388 377 -2738 2659 -408 2703 -382 2689 -416 2679 -408 2701 -382 2687 -418 365 -2736 365 -2722 2689 -384 391 -2696 2707 -386 379 -2734 2665 -410 361 -2726 2703 -418 357 -21246 2679 -466 297 -2768 2657 -448 2627 -434 2669 -450 2653 -416 2673 -408 2697 -386 383 -2728 369 -2706 2701 -382 387 -2726 2687 -418 357 -2708 2693 -418 361 -2702 2709 -396 401 -21232 2689 -406 361 -2736 2695 -386 2695 -406 2695 -382 2687 -418 2675 -410 2693 -414 375 -2692 389 -2706 2701 -404 363 -2724 2695 -388 389 -2702 2719 -358 405 -2704 2701 -402 363 -21262 2677 -414 367 -2738 2677 -386 2693 -420 2701 -400 2677 -386 2695 -420 2669 -430 369 -2718 353 -2730 2673 -412 361 -2734 2691 -420 357 -2698 2701 -394 401 -2702 2687 -424 347 -21244 2701 -418 365 -2726 2703 -382 2697 -420 2675 -400 2685 -384 2721 -398 2667 -418 355 -2744 343 -2722 2703 -420 353 -2724 2689 -396 363 -2736 2687 -390 377 -2730 2697 -386 357 -21274 2683 -414 375 -2726 2667 -420 2703 -398 2677 -388 2695 -420 2699 -398 2671 -384 415 -2698 357 -2738 2695 -382 383 -2724 2685 -416 357 -2706 2707 -384 391 -2726 2671 -384 415 -21238 2651 -476 293 -2776 2653 -462 2641 -446 2661 -422 2663 -418 2689 -412 2683 -414 357 -2706 385 -2698 2715 -378 379 -2710 2719 -388 377 -2708 2695 -406 361 -2724 2689 -416 361 -21244 2703 -386 413 -2698 2697 -414 2689 -384 2685 -386 2719 -378 2701 -416 2689 -386 377 -2728 387 -2700 2673 -410 361 -2730 2695 -420 357 -2732 2679 -386 377 -2734 2699 -378 361 -21262 2697 -392 405 -2702 2687 -406 2703 -382 2703 -418 2671 -406 2677 -416 2695 -386 387 -2700 381 -2704 2695 -418 357 -2712 2721 -388 375 -2702 2693 -408 363 -2730 2693 -420 355 -21248 2653 -494 289 -91206 131 -132 97 -232 559 -132 591 -98 691 -66 131 -130 297 -66 231 -66 331 -66 433 -100 499 -132 231 -166 197 -134 593 -100 11707 -4456 133 -200 131 +RAW_Data: -66 133 -66 97 -166 561 -100 895 -132 1323 -66 10873 -3752 99 -722 229 -394 97 -66 99 -98 99 -328 297 -328 265 -298 3089 -132 10573 -1460 133 -432 99 -232 99 -132 333 -232 731 -164 65 -166 165 -132 131 -330 65 -98 131 -596 65 -198 133 -98 397 -568 65 -132 1157 -166 195 -130 131 -64 99 -66 63 -198 265 -98 297 -66 63 -166 295 -100 1747 -232 6099 -11348 199 -528 297 -266 97 -598 99 -198 231 -64 4433 -334 65 -298 65 -3284 67 -530 97 -432 133 -2356 493 -68 231 -168 297 -266 427 -100 559 -98 229 -460 197 -66 261 -132 65 -98 565 -132 231 -66 497 -100 3491 -12356 65 -660 197 -198 165 -132 331 -134 65 -98 2651 -134 4531 -10850 65 -1322 263 -68 431 -232 165 -134 165 -202 231 -300 5625 -66 6951 -8162 65 -398 99 -596 65 -132 461 -598 429 -132 97 -132 463 -232 229 -98 329 -100 397 -100 363 -100 231 -200 163 -200 961 -66 693 -100 397 -134 10601 -3872 263 -100 165 -100 131 -198 99 -696 233 -1524 331 -132 131 -164 229 -132 493 -98 631 -134 231 -100 595 -66 295 -66 5965 -8248 99 -296 99 -98 397 -66 65 -924 229 -398 299 -98 1425 -130 565 -198 827 -262 429 -598 725 -704 729 -12290 131 -98 99 -98 65 -100 163 -164 65 -494 231 -100 97 -100 863 -66 1751 -3948 165 -100 195 -66 165 -296 65 -2042 99 -200 495 -132 557 -100 827 -98 167 -66 433 -100 661 -164 689 -98 10803 -3906 231 -296 295 -232 99 -234 131 -332 395 -266 1283 -164 755 -466 397 -164 335 -66 1355 -14376 557 -66 331 -68 431 -134 599 -364 229 -100 763 -98 265 -132 525 -166 99 -396 495 -98 3867 -134 595 -168 865 -166 503 -200 467 -134 8145 -458 235 -794 599 -458 265 -436 231 -426 333 -368 299 -730 689 -360 327 -370 363 -326 367 -668 733 -328 363 -302 397 -328 371 -296 393 -666 725 -622 795 -634 433 -264 1023 -228 5041 -762 585 -466 233 -826 235 -470 631 -368 299 -402 299 -726 361 -328 331 -370 363 -332 701 -298 401 -692 369 -302 759 -268 461 -236 435 -622 423 -260 465 -266 719 -13608 65 -624 197 -558 921 -164 1315 -134 465 -134 263 -100 295 -132 293 -66 329 -98 197 -132 9977 -5036 197 -798 333 -828 295 -100 197 -100 165 -66 665 -100 763 -300 297 -166 165 -98 823 -8348 229 -100 427 -196 263 -624 197 -134 797 -100 263 -68 529 -132 233 -134 165 -264 131 -132 559 -66 263 -228 927 -132 731 -102 1061 -66 863 -8206 131 -332 299 -166 461 -100 99 -66 429 -66 3271 -98 465 -100 401 -232 331 -66 397 -430 10341 +RAW_Data: -5434 65 -298 133 -132 131 -68 231 -200 661 -132 9517 -424 97 -1456 99 -1694 393 -100 131 -560 131 -196 197 -298 65 -428 229 -196 297 -266 131 -166 2435 -66 10161 -11230 65 -1320 131 -298 265 -532 231 -200 1291 -68 631 -66 12645 -4048 133 -66 67 -132 167 -266 163 -66 397 -132 197 -132 299 -98 197 -198 2903 -66 2361 -66 9627 -3588 197 -332 165 -68 331 -68 197 -132 99 -100 663 -66 363 -230 231 -166 131 -100 201 -298 163 -132 133 -202 363 -300 397 -102 263 -100 165 -66 1221 -66 1479 -132 165 -98 229 -12976 263 -66 363 -134 231 -66 629 -132 327 -100 97 -130 99 -164 227 -64 297 -132 397 -164 425 -198 97 -198 99 -66 365 -164 199 -102 97 -66 1817 -13524 231 -134 16907 -4086 233 -630 65 -396 201 -66 165 -198 67 -198 99 -664 2117 -166 12473 -446 2649 -440 2661 -420 2651 -422 2681 -418 2703 -400 365 -2724 387 -2696 2695 -414 357 -2704 2707 -386 389 -2700 2687 -392 405 -2706 2695 -402 363 -21268 2707 -388 377 -2706 2691 -404 2699 -382 2717 -382 2707 -378 2693 -416 2687 -396 363 -2736 355 -2748 2659 -416 365 -2708 2715 -388 377 -2708 2697 -404 363 -2730 2673 -420 355 -21268 2655 -460 319 -2766 2663 -448 2631 -436 2665 -418 2683 -410 2681 -416 2701 -386 383 -2700 375 -2744 2669 -416 353 -2730 2685 -416 357 -2708 2721 -380 369 -2724 2697 -382 385 -21260 2701 -418 353 -2720 2673 -418 2675 -408 2693 -384 2715 -386 2717 -386 2691 -404 363 -2732 387 -2702 2669 -412 359 -2736 2699 -380 381 -2728 2675 -416 381 -2720 2675 -414 347 -21280 2685 -390 377 -2724 2689 -416 2673 -408 2705 -382 2695 -410 2689 -414 2661 -418 385 -2704 369 -2704 2693 -416 375 -2726 2661 -420 355 -2728 2711 -388 375 -2702 2691 -410 363 -21252 2659 -488 287 -2794 2651 -448 2629 -436 2671 -416 2695 -416 2663 -406 2699 -384 383 -2730 367 -2702 2695 -418 385 -2702 2685 -412 349 -2744 2693 -366 389 -2714 2693 -394 381 -21266 2685 -418 363 -2730 2683 -382 2693 -418 2675 -410 2699 -384 2719 -382 2707 -380 359 -2734 387 -2704 2709 -380 361 -2732 2699 -418 357 -2728 2667 -416 383 -2696 2709 -380 391 -21228 2685 -458 307 -2800 2647 -412 2659 -432 2667 -416 2695 -416 2675 -406 2675 -416 383 -2700 361 -2730 2687 -414 375 -2696 2701 -420 353 -2720 2711 -382 367 -2728 2675 -416 385 -21222 2735 -386 355 -2744 2687 -396 2679 -418 2701 -386 2705 -382 2681 -410 2697 -384 385 -2736 365 -2704 2715 -384 377 -2696 2697 -416 349 -2722 2707 -386 379 -2732 2671 -410 361 -21258 2681 -464 297 -2796 2629 -456 2655 -420 2661 -448 2663 -404 2695 -382 2715 -380 371 -2740 355 -2744 2679 -384 391 -2728 2675 -388 379 +RAW_Data: -2728 2695 -414 357 -2704 2705 -418 357 -21262 2673 -416 383 -2696 2709 -380 2703 -384 2699 -418 2671 -408 2695 -382 2713 -386 379 -2730 357 -2732 2695 -384 383 -2730 2679 -416 357 -2708 2701 -410 349 -2736 2697 -382 385 -21252 2669 -478 289 -2790 2647 -426 2651 -444 2653 -430 2659 -418 2695 -414 2681 -402 349 -2738 383 -2722 2677 -414 347 -2744 2691 -382 369 -2730 2691 -384 383 -2734 2679 -414 347 -21264 2705 -386 379 -2736 2667 -410 2695 -382 2715 -380 2709 -420 2665 -392 2713 -382 383 -2730 365 -2728 2665 -418 383 -2696 2693 -418 357 -2710 2711 -380 375 -2718 2701 -416 357 -21238 2677 -484 311 -2766 2635 -444 2657 -420 2663 -422 2695 -416 2667 -428 2675 -396 363 -73890 133 -98 131 -132 129 -658 99 -66 853 -100 63 -100 361 -98 1589 -66 1231 -132 65 -100 297 -198 65 -132 265 -66 9857 -4672 165 -1030 97 -1394 65 -200 2687 -68 6873 -8336 99 -1156 97 -66 163 -232 163 -262 197 -132 295 -132 263 -166 953 -100 263 -130 393 -164 295 -64 329 -66 393 -164 823 -130 165 -66 6133 -8436 165 -164 265 -266 65 -362 197 -696 3181 -132 363 -98 65 -166 131 -66 399 -132 663 -396 329 -66 7335 -7578 497 -230 627 -264 99 -366 99 -132 131 -134 265 -498 163 -100 1323 -66 265 -66 1129 -100 399 -132 365 -100 795 -68 397 -98 597 -364 297 -132 361 -132 265 -132 8591 -4740 65 -100 131 -166 199 -1088 97 -296 99 -528 131 -98 661 -66 401 -198 1157 -166 361 -164 495 -100 165 -66 297 -100 1423 -66 3067 -5658 67 -6406 197 -1092 65 -530 659 -68 265 -100 991 -68 231 -230 297 -66 327 -66 131 -132 659 -134 131 -100 1183 -132 263 -98 621 -66 2075 -6976 65 -5138 67 -132 129 -664 67 -132 165 -100 331 -466 231 -68 467 -98 563 -66 231 -100 531 -66 465 -66 1023 -166 297 -134 3409 -12290 67 -164 99 -532 133 -166 263 -66 231 -66 721 -64 131 -68 959 -134 495 -100 299 -98 497 -98 365 -100 397 -232 297 -98 531 -66 3029 -12216 265 -132 99 -364 199 -234 131 -66 431 -166 333 -166 397 -132 327 -100 395 -66 197 -132 395 -66 527 -98 295 -100 97 -98 789 -132 363 -132 297 -200 2815 -4914 65 -6620 65 -462 65 -134 297 -66 497 -264 231 -198 2773 -134 365 -100 831 -166 131 -100 297 -132 861 -132 299 -100 561 -66 1381 -6946 65 -5516 231 -266 97 -1362 1093 -68 1621 -134 165 -332 297 -98 361 -228 97 -132 797 -98 3487 -13224 229 -164 65 -132 913 -66 1123 -98 527 -134 929 -98 723 -100 12259 -270 165 -132 67 -132 165 -1326 99 -98 65 -1194 431 -66 695 -66 733 -134 197 +RAW_Data: -134 10801 -166 67 -6130 133 -198 231 -334 365 -98 229 -132 165 -68 231 -166 14501 -524 65 -328 131 -498 129 -1288 65 -494 163 -64 165 -66 527 -132 131 -132 1019 -198 129 -166 393 -198 65 -164 6411 -66 3255 -10642 65 -1320 165 -164 493 -492 559 -264 2555 -66 695 -66 1657 -164 855 -66 4001 -10526 97 -596 133 -298 67 -264 65 -300 65 -100 263 -166 231 -134 99 -100 2703 -68 13643 -4922 297 -100 65 -232 133 -198 331 -300 231 -66 331 -100 12047 -3872 97 -196 65 -494 329 -66 65 -890 97 -98 229 -164 195 -596 797 -66 861 -132 65 -66 231 -100 565 -66 65 -66 1297 -132 265 -66 363 -134 265 -364 297 -164 299 -134 297 -134 495 -98 11309 -3790 131 -1380 65 -758 65 -164 129 -460 65 -360 199 -100 563 -68 497 -198 363 -266 263 -100 165 -66 697 -66 1933 -13594 65 -762 1223 -132 1119 -196 361 -134 131 -100 793 -166 695 -68 231 -68 463 -66 11727 -4204 363 -264 131 -132 133 -1124 97 -100 163 -100 327 -100 331 -198 397 -66 397 -100 395 -100 163 -66 197 -564 1059 -7962 65 -100 65 -198 129 -362 99 -394 197 -296 495 -100 1357 -68 459 -66 593 -66 265 -68 301 -132 465 -66 231 -200 397 -66 397 -232 199 -298 12077 -4350 231 -796 363 -198 133 -264 65 -1132 597 -332 3295 -100 755 -98 231 -164 97 -264 459 -166 759 -164 3265 -12138 99 -232 99 -1228 1025 -100 393 -66 531 -132 693 -132 1063 -66 427 -64 297 -294 229 -98 9723 -5404 67 -466 99 -796 267 -98 201 -100 167 -264 461 -98 1415 -66 861 -66 267 -66 331 -134 1663 -66 2089 -7012 65 -100 101 -4804 431 -728 99 -100 65 -100 995 -134 165 -66 929 -100 65 -66 927 -100 1093 -168 99 -100 497 -66 665 -200 6517 -8312 165 -66 129 -66 559 -166 99 -430 65 -398 67 -66 593 -198 459 -132 261 -132 263 -130 723 -66 459 -100 325 -166 67 -198 559 -66 493 -66 11475 -3896 99 -266 99 -66 197 -1092 129 -198 361 -166 163 -98 263 -196 759 -100 265 -100 365 -630 4635 -12748 65 -1712 461 -100 497 -66 395 -98 265 -98 229 -164 529 -132 297 -66 565 -132 987 -132 8665 -2820 2265 -450 313 -2774 2643 -442 325 -2772 2665 -416 359 -2734 2667 -386 379 -21274 2657 -474 293 -2810 2619 -466 2613 -476 2629 -452 2663 -388 2683 -418 2705 -400 365 -2722 387 -2700 2697 -380 361 -2732 2691 -418 361 -2732 2667 -416 383 -2698 2697 -416 357 -21238 2715 -384 383 -2732 2685 -416 2667 -416 2695 -398 2671 -418 2687 -390 2713 -382 383 -2730 365 -2728 2661 -416 379 -2716 2685 -384 379 -2720 2703 -378 401 -2718 2671 diff --git a/assets/unit_tests/subghz/intertechno_v3.sub b/assets/unit_tests/subghz/intertechno_v3.sub new file mode 100644 index 000000000..af68b7455 --- /dev/null +++ b/assets/unit_tests/subghz/intertechno_v3.sub @@ -0,0 +1,7 @@ +Filetype: Flipper SubGhz Key File +Version: 1 +Frequency: 433920000 +Preset: FuriHalSubGhzPresetOok650Async +Protocol: Intertechno_V3 +Bit: 32 +Key: 00 00 00 00 3F 86 C5 9F diff --git a/assets/unit_tests/subghz/intertechno_v3_raw.sub b/assets/unit_tests/subghz/intertechno_v3_raw.sub new file mode 100644 index 000000000..2cfc79511 --- /dev/null +++ b/assets/unit_tests/subghz/intertechno_v3_raw.sub @@ -0,0 +1,13 @@ +Filetype: Flipper SubGhz RAW File +Version: 1 +Frequency: 433920000 +Preset: FuriHalSubGhzPresetOok650Async +Protocol: RAW +RAW_Data: 15041 -66 15883 -66 12643 -66 12681 -66 3413 -68 2713 -68 33389 -66 1445 -66 1279 -68 1027 -66 6911 -98 25229 -66 3967 -100 3019 -100 6131 -66 955 -66 3605 -66 12411 -98 1419 -66 3593 -68 2753 -66 2457 -66 6007 -66 627 -100 1597 -66 3071 -98 22749 -66 333 -66 12829 -66 4313 -132 855 -66 44097 -64 20391 -98 29999 -66 3539 -98 557 -66 1489 -100 4081 -100 3857 -64 2895 -132 2261 -166 3089 -66 2429 -68 34467 -66 3585 -66 3087 -66 3329 -132 5287 -66 1063 -98 15259 -100 2535 -66 995 -66 13057 -100 24233 -68 531 -100 26415 -66 1761 -100 2717 -66 4071 -100 12191 -66 23367 -68 2323 -66 19809 -248 245 -1388 255 -242 275 -1358 273 -1370 277 -246 277 -1368 275 -246 275 -1362 275 -244 275 -1364 275 -244 275 -1362 275 -244 275 -1328 273 -278 273 -1358 275 -246 275 -238 263 -1384 275 -246 273 -1358 275 -244 273 -1358 275 -246 275 -1360 275 -1344 277 -246 275 -1358 275 -244 275 -234 263 -1382 277 -1344 277 -246 279 -1362 275 -246 271 -234 261 -1380 275 -246 273 -1360 275 -246 275 -1366 277 -1340 277 -248 279 -238 263 -1382 275 -1344 277 -246 279 -1364 277 -244 275 -234 263 -1382 277 -244 273 -1358 275 -1344 277 -248 279 -1368 275 -244 273 -1360 239 -280 271 -1358 275 -244 275 -1358 275 -174 269 -10298 289 -2660 267 -238 299 -1356 275 -244 275 -1356 275 -1344 277 -248 277 -1360 275 -246 275 -1328 309 -244 273 -1358 277 -244 275 -1356 275 -246 273 -1326 309 -244 275 -1356 275 -246 273 -234 263 -1380 277 -246 273 -1326 309 -244 273 -1356 277 -246 277 -1358 275 -1338 279 -248 279 -1364 275 -246 273 -234 261 -1380 277 -1344 279 -250 277 -1330 309 -244 273 -232 261 -1384 275 -246 273 -1356 275 -248 275 -1360 275 -1340 279 -248 277 -236 263 -1380 277 -1342 279 -248 279 -1366 275 -246 273 -234 263 -1380 275 -246 275 -1358 275 -1340 279 -248 281 -1336 309 -244 273 -1358 275 -246 273 -1360 275 -244 273 -1358 275 -176 267 -10306 257 -2646 299 -234 301 -1354 277 -246 275 -1356 277 -1340 279 -250 279 -1332 309 -244 275 -1358 275 -248 273 -1326 309 -246 273 -1326 309 -244 275 -1356 277 -248 275 -1328 309 -246 273 -234 261 -1382 277 -246 277 -1326 309 -244 275 -1358 277 -246 277 -1356 277 -1346 277 -250 277 -1358 277 -246 275 -234 263 -1382 279 -1346 279 -248 281 -1330 307 -246 273 -236 261 -1380 277 -246 277 -1360 277 -246 277 -1360 275 -1344 279 -248 279 -236 263 -1384 277 -1340 279 -250 281 -1338 307 -246 271 -234 261 -1384 277 -246 275 -1356 277 -1340 279 -250 283 -1336 309 -246 273 -1356 277 -246 273 -1360 277 -246 +RAW_Data: 275 -1328 309 -174 269 -10296 289 -2648 267 -238 299 -1356 277 -246 275 -1324 307 -1342 279 -250 277 -1330 309 -244 275 -1362 277 -244 275 -1356 275 -248 273 -1328 309 -244 273 -1328 309 -244 275 -1360 277 -246 275 -234 259 -1384 277 -246 275 -1360 275 -246 273 -1358 277 -248 277 -1362 275 -1344 277 -248 277 -1328 307 -246 273 -236 261 -1384 277 -1348 279 -248 279 -1360 277 -246 273 -234 263 -1388 275 -246 275 -1360 277 -248 279 -1368 277 -1344 279 -248 279 -240 265 -1386 275 -1342 279 -286 247 -1372 275 -248 275 -238 265 -1386 277 -248 275 -1360 275 -1344 277 -286 247 -1374 275 -246 275 -1362 277 -246 275 -1360 277 -248 275 -1326 307 -174 269 -10290 287 -2654 269 -236 301 -1352 275 -248 273 -1326 311 -1340 277 -248 277 -1328 309 -244 273 -1358 275 -244 275 -1326 309 -244 273 -1356 277 -244 273 -1356 275 -246 275 -1358 275 -244 275 -234 261 -1382 277 -246 273 -1358 275 -246 273 -1360 277 -246 273 -1324 309 -1340 277 -248 277 -1328 307 -246 271 -234 259 -1382 277 -1346 279 -248 277 -1330 309 -244 271 -232 259 -1382 277 -244 275 -1356 277 -248 273 -1354 277 -1342 277 -248 275 -236 261 -1380 277 -1344 277 -248 279 -1330 307 -246 273 -234 261 -1378 277 -246 273 -1356 277 -1342 277 -248 277 -1330 309 -244 273 -1322 307 -246 273 -1326 309 -244 273 -1322 309 -176 267 -10298 257 -2682 265 -236 299 -1324 309 -248 273 -1324 311 -1342 277 -246 279 -1360 277 -244 275 -1362 275 -244 275 -1358 275 -244 275 -1360 275 -246 273 -1360 275 -244 277 -1360 275 -246 273 -234 263 -1384 275 -246 273 -1358 275 -246 275 -1360 277 -246 277 -1356 277 -1342 279 -248 277 -1364 275 -244 275 -234 261 -1384 275 -1344 277 -250 279 -1366 275 -246 273 -236 263 -1384 277 -246 275 -1358 277 -246 277 -1362 277 -1342 279 -248 279 -236 265 -1382 277 -1346 277 -248 281 -1366 275 -246 275 -234 265 -1384 275 -246 273 -1358 277 -1344 279 -248 279 -1364 275 -244 275 -1324 309 -246 273 -1324 307 -246 273 -1326 309 -174 267 -118796 133 -100 131 -892 329 -166 199 -132 131 -166 99 -100 265 -264 4663 -134 4889 -100 365 -98 5921 -100 5903 -68 4877 -98 2953 -98 1645 -64 1687 -66 981 -98 10769 -66 18319 -66 4831 -66 13301 -66 893 -132 5967 -100 15949 -66 3749 -66 497 -100 625 -66 1147 -66 469 -66 1261 -66 3651 -100 265 -100 26741 -68 6873 -66 4485 -100 2667 -68 3159 -68 2857 -132 2655 -66 12903 -66 1277 -66 1711 -66 787 -100 1327 -198 727 -64 1677 -100 1187 -66 1019 -66 891 -66 4303 -100 11297 -66 3923 -254 253 -1380 247 -292 253 -1344 +RAW_Data: 277 -1346 277 -250 279 -1364 275 -244 275 -1362 275 -244 275 -1356 275 -246 273 -1358 241 -278 273 -1356 275 -246 273 -1360 275 -246 273 -234 263 -1382 275 -244 273 -1358 275 -246 273 -1360 275 -246 273 -1358 275 -1340 277 -248 277 -1362 275 -246 273 -234 261 -1380 277 -1344 277 -248 279 -1362 275 -244 273 -236 261 -1380 275 -244 275 -1360 275 -246 275 -1358 275 -1346 277 -246 275 -236 263 -1384 275 -1342 277 -248 277 -1364 277 -244 273 -234 261 -1378 277 -246 273 -1356 277 -1340 277 -248 281 -1334 307 -246 271 -1356 275 -246 273 -1358 275 -244 273 -1326 309 -174 267 -10296 257 -2650 297 -232 263 -1384 277 -244 273 -1358 275 -1340 279 -248 279 -1328 309 -244 275 -1328 307 -244 273 -1356 275 -244 275 -1358 275 -246 273 -1324 309 -244 275 -1328 307 -244 273 -234 261 -1382 275 -246 273 -1326 309 -244 273 -1358 275 -246 273 -1358 275 -1338 279 -248 279 -1330 309 -244 273 -232 261 -1380 277 -1344 279 -248 279 -1330 309 -244 271 -234 261 -1382 275 -246 273 -1358 277 -244 275 -1330 309 -1338 277 -246 277 -236 263 -1380 277 -1342 277 -248 279 -1364 275 -246 273 -232 261 -1380 275 -248 275 -1328 307 -1338 277 -248 279 -1334 309 -244 271 -1358 275 -244 275 -1324 307 -246 271 -1328 309 -174 265 -10270 291 -2640 297 -232 297 -1350 277 -248 275 -1326 309 -1340 277 -248 277 -1328 309 -244 273 -1358 275 -246 273 -1326 309 -244 273 -1354 275 -246 273 -1330 307 -244 273 -1358 275 -246 273 -234 263 -1380 275 -246 273 -1358 275 -246 273 -1360 275 -244 273 -1358 275 -1340 277 -248 279 -1364 275 -244 273 -232 261 -1380 277 -1342 279 -250 279 -1332 307 -244 271 -234 261 -1378 277 -246 273 -1358 275 -248 275 -1360 275 -1340 277 -248 275 -236 263 -1382 277 -1344 277 -246 277 -1364 275 -246 273 -234 259 -1380 275 -246 273 -1362 275 -1342 275 -248 277 -1334 309 -244 271 -1356 275 -244 275 -1326 307 -244 273 -1356 275 -176 267 -10290 289 -2644 267 -238 301 -1320 309 -246 273 -1324 309 -1340 277 -248 277 -1328 307 -246 273 -1326 307 -246 273 -1324 309 -246 273 -1322 309 -246 273 -1322 307 -246 275 -1326 309 -246 273 -234 259 -1382 275 -246 275 -1322 309 -246 273 -1326 309 -246 273 -1326 309 -1340 277 -248 275 -1326 309 -246 273 -232 261 -1380 279 -1346 277 -250 277 -1328 309 -244 271 -232 261 -1380 277 -246 273 -1358 275 -248 273 -1328 307 -1340 277 -248 277 -236 261 -1380 277 -1344 277 -248 279 -1328 309 -244 275 -232 261 -1378 277 -248 273 -1326 309 -1344 277 -248 277 -1358 277 -246 273 -1328 307 -244 271 -1324 309 -244 +RAW_Data: 273 -1324 309 -174 267 -10270 289 -2638 297 -234 297 -1352 275 -248 275 -1328 307 -1340 277 -248 275 -1330 309 -244 273 -1358 275 -244 275 -1326 309 -244 271 -1356 275 -244 275 -1326 307 -246 273 -1326 309 -244 273 -234 261 -1378 275 -248 275 -1326 309 -244 271 -1356 277 -248 273 -1328 309 -1338 277 -248 277 -1328 309 -244 271 -232 261 -1380 277 -1348 279 -248 277 -1328 307 -246 271 -234 259 -1384 275 -244 275 -1356 277 -246 275 -1326 309 -1344 275 -248 275 -236 261 -1378 277 -1342 277 -250 279 -1334 309 -244 271 -232 261 -1380 277 -246 273 -1326 307 -1344 277 -248 277 -1328 309 -246 273 -1326 309 -244 271 -1324 309 -244 273 -1324 307 -176 267 -10288 287 -2618 299 -236 299 -1354 277 -244 273 -1326 307 -1340 279 -248 275 -1328 309 -244 275 -1326 309 -246 273 -1324 307 -246 273 -1322 309 -244 273 -1322 309 -244 275 -1328 309 -246 273 -232 261 -1380 277 -246 275 -1324 309 -244 273 -1356 277 -246 275 -1324 309 -1340 279 -246 277 -1328 309 -244 273 -232 261 -1382 277 -1344 279 -250 277 -1324 309 -246 273 -234 261 -1380 277 -246 273 -1358 277 -246 273 -1328 309 -1340 277 -248 275 -236 261 -1380 275 -1344 279 -248 279 -1360 277 -244 273 -234 261 -1380 277 -246 275 -1354 277 -1344 277 -248 277 -1328 311 -246 273 -1324 307 -244 273 -1324 309 -244 273 -1320 309 -176 269 -118210 761 -168 267 -66 563 -132 99 -132 3543 -66 5345 -100 4355 -66 4617 -68 20503 -166 2379 -132 293 -98 4117 -66 1151 -98 3353 -66 3485 -66 2491 -66 6133 -66 233 -68 16307 -68 16959 -98 357 -66 5419 -134 799 -100 327 -100 791 -66 2481 -66 963 -100 3481 -98 1679 -134 2473 -100 227 -68 3087 -66 11527 -130 4305 -98 435 -66 563 -100 2887 -100 267 -66 1787 -66 9655 -66 4793 -100 2119 -66 359 -98 1313 -132 3393 -234 995 -66 2681 -98 99 -130 1379 -100 3757 -100 21695 -132 5135 -100 693 -98 4631 -100 2325 -68 4937 -66 10409 -98 897 -100 1287 -66 2565 -66 3753 -66 4055 -66 2023 -68 1961 -68 629 -66 431 -66 5039 -66 2155 -100 2673 -66 1163 -98 6539 -100 825 -66 1197 -100 3053 -66 13973 -68 15515 -100 1861 -66 1027 -66 797 -98 959 -98 787 -132 787 -64 3811 -132 1747 -66 6683 -66 1033 -68 24927 -66 1259 -100 1125 -68 663 -66 1687 -66 4357 -132 4567 -66 3969 -98 3317 -132 433 -134 6043 -66 3249 -100 431 -98 2367 -100 11265 -66 5085 -68 2355 -64 1815 -66 1395 -274 241 -1366 275 -244 275 -1362 275 -1338 277 -284 243 -1368 239 -278 275 -1362 275 -244 275 -1360 241 -278 273 -1356 275 -246 275 -1360 239 -280 275 -1360 +RAW_Data: 275 -244 275 -234 263 -1386 239 -280 273 -1356 275 -244 273 -1360 275 -244 277 -1364 275 -1336 277 -248 277 -1366 275 -244 273 -234 263 -1386 275 -1340 277 -248 279 -1364 275 -244 275 -234 263 -1384 273 -244 275 -1358 275 -244 275 -1364 275 -1342 275 -248 277 -236 265 -1384 275 -1340 277 -282 243 -1366 275 -246 273 -236 263 -1382 277 -244 275 -1358 275 -1342 277 -248 277 -1364 275 -246 275 -1360 239 -280 273 -1358 241 -278 275 -1356 275 -210 233 -10302 257 -2652 297 -232 297 -1354 277 -244 275 -1358 275 -1340 279 -248 279 -1360 275 -246 275 -1360 275 -246 273 -1360 275 -244 275 -1328 309 -242 273 -1324 309 -244 275 -1360 275 -246 273 -234 261 -1384 275 -246 273 -1358 275 -244 275 -1358 277 -248 273 -1358 275 -1340 279 -248 277 -1334 307 -242 273 -232 261 -1380 277 -1348 277 -250 277 -1364 275 -244 275 -234 261 -1380 277 -244 275 -1358 277 -246 277 -1360 277 -1342 275 -248 275 -236 263 -1380 277 -1344 277 -248 279 -1368 275 -244 275 -232 261 -1382 277 -244 275 -1356 275 -1344 277 -248 279 -1362 275 -246 275 -1360 275 -246 273 -1356 275 -246 273 -1356 275 -176 267 -10302 257 -2648 299 -234 297 -1352 277 -246 275 -1326 309 -1340 279 -248 277 -1330 309 -244 275 -1328 309 -244 273 -1324 309 -244 275 -1324 309 -246 273 -1324 307 -246 275 -1328 309 -244 273 -234 261 -1378 277 -248 275 -1328 309 -244 273 -1356 277 -248 275 -1326 309 -1344 277 -248 275 -1326 309 -246 273 -234 259 -1380 277 -1348 281 -248 279 -1328 307 -246 273 -234 259 -1382 277 -246 275 -1360 275 -248 275 -1324 309 -1340 279 -248 277 -238 261 -1382 277 -1344 277 -248 279 -1330 311 -244 273 -234 259 -1378 277 -248 275 -1326 309 -1340 279 -248 279 -1336 307 -246 271 -1324 309 -244 275 -1324 307 -246 273 -1326 309 -174 269 -10296 257 -2648 299 -234 297 -1352 277 -248 273 -1326 309 -1342 277 -248 277 -1328 309 -246 275 -1328 309 -244 273 -1326 309 -244 273 -1322 309 -244 273 -1328 307 -244 275 -1328 309 -246 273 -234 261 -1382 277 -246 275 -1326 309 -244 273 -1352 277 -248 275 -1330 309 -1340 277 -248 277 -1328 309 -244 275 -232 261 -1384 277 -1342 279 -250 279 -1328 309 -244 273 -234 263 -1380 277 -246 273 -1360 277 -246 275 -1326 309 -1340 277 -250 277 -236 263 -1382 277 -1342 277 -248 279 -1362 277 -246 273 -234 263 -1382 277 -244 275 -1356 277 -1340 279 -248 279 -1362 275 -246 275 -1328 307 -246 273 -1356 275 -246 273 -1356 275 -174 269 -10292 287 -2650 269 -236 301 -1354 275 -248 273 -1358 275 -1340 279 -248 277 -1332 307 -246 275 -1328 +RAW_Data: 309 -244 273 -1324 309 -244 273 -1356 275 -246 273 -1358 275 -244 277 -1330 309 -244 273 -234 261 -1382 277 -244 275 -1358 275 -246 273 -1356 277 -248 275 -1360 275 -1340 277 -248 277 -1360 275 -246 273 -236 261 -1382 279 -1344 279 -248 279 -1360 277 -244 273 -234 261 -1380 277 -246 275 -1360 277 -246 273 -1360 275 -1342 279 -248 275 -236 263 -1382 275 -1344 279 -248 279 -1362 277 -246 273 -234 263 -1380 277 -246 275 -1356 275 -1342 277 -248 281 -1336 307 -246 271 -1354 277 -246 275 -1328 307 -244 273 -1352 277 -176 269 -10300 257 -2650 299 -232 297 -1354 277 -246 275 -1356 277 -1342 277 -248 279 -1328 309 -244 275 -1360 275 -246 273 -1328 307 -246 273 -1356 277 -246 277 -1326 309 -244 277 -1360 277 -246 273 -234 263 -1384 277 -246 275 -1324 309 -246 275 -1358 277 -246 277 -1360 277 -1344 277 -248 277 -1326 309 -246 273 -236 261 -1382 277 -1348 279 -250 281 -1330 307 -246 273 -234 263 -1386 277 -244 275 -1356 277 -248 277 -1362 277 -1342 277 -250 277 -238 263 -1384 277 -1342 277 -250 281 -1332 309 -246 273 -234 263 -1380 277 -246 275 -1360 277 -1342 279 -248 281 -1334 307 -246 273 -1356 275 -248 275 -1328 309 -244 275 -1324 309 -176 269 -115034 163 -362 67 -894 529 -166 14663 -98 4135 -66 3681 -100 299 -68 9829 -66 3517 -64 21569 -66 3251 -66 2209 -64 23701 -66 3359 -68 1057 -66 723 -66 299 -134 765 -66 589 -98 1687 -134 2153 -66 3081 -68 10447 -66 11643 -66 2451 -66 2277 -66 2897 -66 755 -100 5539 -64 5117 -132 4867 -134 3931 -64 625 -66 1317 -98 11597 -66 2255 -66 1165 -66 1123 -66 6371 -100 699 -68 1811 -66 621 -68 2191 -64 1291 -134 3003 -66 2423 -64 1463 -66 663 -100 1127 -100 6169 -100 489 -100 6087 -100 2027 -66 1195 -66 13195 -66 557 -66 40423 -98 1919 -100 1061 -132 201 -66 2553 -132 12549 -66 1789 -100 921 -134 1067 -66 729 -66 10029 -66 3909 -100 265 -100 16017 -134 21177 -68 2461 -66 2215 -68 1197 -66 5911 -66 2645 -66 3419 -132 16275 -64 5091 -68 2123 -66 2677 -64 10305 -66 12381 -100 427 -166 25331 -66 2457 -66 11859 -248 279 -1368 275 -246 275 -1360 275 -1340 277 -246 279 -1364 239 -278 275 -1358 275 -244 275 -1362 239 -278 273 -1358 239 -280 271 -1360 241 -278 273 -1360 275 -244 275 -234 261 -1384 239 -280 273 -1356 275 -244 273 -1360 275 -244 275 -1358 275 -1344 277 -248 275 -1358 275 -244 273 -236 261 -1384 275 -1342 279 -246 279 -1360 275 -244 275 -234 263 -1384 239 -278 273 -1358 275 -244 275 -1362 275 -1342 275 -248 275 -238 263 -1382 275 -1344 275 -248 +RAW_Data: 277 -1364 275 -244 273 -234 263 -1380 275 -246 273 -1358 275 -1342 277 -246 279 -1366 275 -244 273 -1362 239 -278 239 -1386 275 -246 273 -1360 241 -208 269 -10290 257 -2686 265 -232 265 -1384 275 -246 275 -1358 275 -1344 277 -248 275 -1358 275 -246 275 -1360 277 -244 273 -1326 309 -244 271 -1354 275 -244 275 -1358 275 -246 273 -1358 275 -246 273 -234 263 -1378 275 -246 275 -1360 275 -244 273 -1356 275 -246 275 -1360 275 -1342 277 -246 277 -1360 275 -246 273 -232 261 -1382 277 -1342 279 -248 279 -1360 275 -244 275 -232 261 -1380 277 -244 275 -1356 277 -246 277 -1360 275 -1342 277 -246 275 -236 263 -1384 275 -1342 277 -248 277 -1362 275 -246 273 -234 261 -1378 277 -246 275 -1328 307 -1340 277 -246 279 -1366 275 -244 273 -1326 307 -244 273 -1324 309 -244 273 -1356 275 -174 267 -10304 255 -2648 297 -230 263 -1382 277 -244 275 -1330 307 -1338 277 -248 277 -1330 309 -244 273 -1356 275 -246 273 -1362 275 -244 273 -1356 275 -244 273 -1326 307 -244 273 -1360 273 -246 273 -236 261 -1380 275 -244 275 -1328 307 -244 273 -1358 275 -244 275 -1360 275 -1342 277 -246 277 -1364 275 -244 271 -232 261 -1384 277 -1340 279 -248 279 -1360 275 -246 273 -234 261 -1380 275 -244 275 -1360 277 -244 275 -1356 275 -1342 279 -246 277 -236 263 -1382 275 -1340 277 -248 279 -1366 275 -246 271 -234 261 -1382 277 -244 275 -1354 275 -1342 277 -248 277 -1364 273 -246 273 -1362 275 -244 271 -1360 275 -244 273 -1358 275 -174 267 -10272 289 -2646 265 -262 261 -1382 277 -244 275 -1356 275 -1342 277 -248 277 -1364 275 -244 275 -1360 275 -244 273 -1358 275 -244 273 -1358 275 -244 273 -1326 307 -244 275 -1358 275 -246 273 -234 261 -1382 275 -246 273 -1358 275 -244 273 -1358 275 -246 275 -1360 275 -1338 277 -248 277 -1362 277 -244 271 -234 261 -1380 277 -1344 279 -248 277 -1332 273 -278 271 -234 261 -1382 275 -244 275 -1356 277 -246 275 -1360 277 -1340 277 -246 277 -234 263 -1384 275 -1342 277 -248 277 -1366 275 -244 273 -234 261 -1380 275 -246 273 -1360 275 -1340 277 -246 279 -1334 307 -244 273 -1356 275 -246 273 -1360 275 -244 271 -1354 277 -174 269 -10300 257 -2648 297 -230 263 -1384 277 -244 273 -1356 277 -1342 277 -248 277 -1362 275 -244 275 -1330 307 -244 273 -1324 309 -244 273 -1324 307 -246 273 -1326 307 -244 273 -1358 275 -246 273 -234 261 -1380 277 -246 273 -1358 275 -244 275 -1354 277 -248 275 -1360 275 -1338 279 -246 277 -1360 275 -244 273 -234 261 -1378 279 -1344 279 -248 279 -1330 309 -244 271 -232 261 -1380 277 -246 273 -1360 +RAW_Data: 277 -244 275 -1360 275 -1340 277 -246 277 -236 261 -1380 275 -1346 277 -248 277 -1362 275 -246 273 -234 263 -1380 275 -244 275 -1358 275 -1340 277 -248 279 -1334 309 -244 273 -1324 307 -246 273 -1356 275 -244 273 -1356 275 -174 269 -10302 257 -2644 297 -232 263 -1384 277 -246 275 -1354 275 -1344 277 -248 275 -1360 275 -246 275 -1358 275 -246 273 -1326 307 -246 273 -1324 307 -244 273 -1328 307 -244 273 -1358 275 -244 273 -236 261 -1380 275 -246 273 -1358 275 -244 273 -1358 275 -246 273 -1360 275 -1344 275 -248 275 -1360 275 -244 273 -234 261 -1378 277 -1344 279 -248 277 -1362 275 -246 273 -234 261 -1378 275 -244 275 -1360 275 -246 275 -1358 275 -1344 277 -246 277 -234 263 -1380 275 -1338 279 -246 281 -1368 275 -244 271 -234 261 -1386 275 -244 271 -1358 275 -1342 277 -246 279 -1362 275 -244 275 -1326 273 -278 273 -1358 239 -278 273 -1358 275 -174 267 -127478 195 -964 2317 -66 763 -98 1455 -100 16109 -66 5683 -98 11469 -66 34413 -66 5443 -66 11613 -66 2737 -66 12191 -66 2951 -68 1851 -68 1895 -68 2643 diff --git a/assets/unit_tests/subghz/oregon2_raw.sub b/assets/unit_tests/subghz/oregon2_raw.sub new file mode 100644 index 000000000..549a60db3 --- /dev/null +++ b/assets/unit_tests/subghz/oregon2_raw.sub @@ -0,0 +1,20 @@ +Filetype: Flipper SubGhz RAW File +Version: 1 +Frequency: 433920000 +Preset: FuriHalSubGhzPresetOok270Async +Protocol: RAW +RAW_Data: 889 -130 325 -64 457 -560 165 -68 199 -170 67 -66 265 -132 133 -666 67 -166 431 -66 201 -98 297 -100 595 -66 199 -134 65 -100 795 -132 99 -168 501 -200 331 -132 265 -102 265 -134 423 -98 521 -226 65 -166 431 -134 99 -100 133 -464 195 -326 623 -100 673 -98 321 -200 65 -136 369 -166 65 -68 97 -166 165 -334 265 -102 231 -166 101 -170 65 -170 265 -136 931 -100 133 -134 563 -66 333 -100 427 -66 163 -390 231 -66 193 -130 461 -166 557 -100 99 -198 263 -100 197 -294 231 -232 299 -134 199 -170 267 -134 631 -98 235 -100 499 -68 463 -100 65 -134 335 -170 273 -134 297 -100 67 -66 197 -166 67 -134 301 -168 537 -470 99 -134 433 -132 199 -192 261 -100 523 -164 459 -132 259 -332 359 -64 227 -96 131 -132 687 -132 363 -136 329 -434 99 -334 133 -100 401 -132 233 -700 233 -170 337 -66 371 -68 233 -202 531 -266 731 -66 465 -100 167 -100 133 -232 335 -166 239 -102 367 -232 231 -100 167 -134 201 -136 301 -168 199 -300 231 -98 237 -134 233 -102 329 -132 261 -134 199 -66 265 -136 99 -170 167 -134 199 -166 167 -136 367 -298 197 -200 99 -166 469 -136 439 -66 303 -134 295 -100 433 -134 899 -266 363 -132 197 -160 555 -324 129 -96 97 -128 257 -132 97 -394 257 -98 195 -166 459 -332 395 -132 633 -134 301 -100 131 -332 169 -168 395 -166 263 -540 783 -100 287 -130 295 -96 225 -296 133 -98 99 -100 461 -164 545 -130 99 -66 301 -68 265 -100 235 -134 235 -70 333 -102 497 -66 233 -364 301 -170 103 -66 165 -336 733 -200 133 -100 263 -102 65 -136 465 -200 1035 -198 165 -170 67 -302 631 -100 429 -332 65 -128 129 -130 159 -128 159 -66 161 -96 325 -164 261 -100 197 -162 65 -96 99 -130 65 -102 333 -100 199 -98 389 -330 129 -128 229 -66 425 -366 229 -64 261 -100 227 -96 227 -526 301 -200 97 -66 699 -334 67 -100 399 -198 787 -98 297 -134 429 -100 3245 -64 527 -98 131 -526 633 -68 133 -302 1459 -164 971 -102 237 -136 1439 -266 1131 -66 599 -200 303 -332 325 -130 389 -166 371 -66 333 -102 65 -100 233 -234 327 -266 233 -166 297 -100 225 -130 163 -336 99 -596 199 -330 131 -66 331 -338 263 -358 197 -168 877 -66 227 -96 63 -130 263 -162 225 -290 197 -198 357 -132 297 -262 165 -456 227 -98 399 -296 95 -132 99 -98 457 -200 199 -168 535 -100 567 -134 327 -130 193 -130 683 -102 101 -132 233 -170 943 -166 827 -66 267 -102 503 -68 1325 -164 +RAW_Data: 1607 -68 233 -166 1167 -70 531 -134 335 -168 131 -66 299 -402 899 -66 461 -66 457 -98 953 -98 165 -66 293 -230 881 -64 393 -166 589 -66 289 -66 1093 -204 333 -98 2745 -132 2019 -170 925 -68 269 -102 1469 -136 2301 -68 1355 -100 527 -66 975 -68 1445 -98 2397 -100 1733 -66 703 -100 995 -100 135 -136 235 -202 167 -134 2071 -166 339 -170 201 -268 129 -66 465 -66 365 -100 197 -164 129 -98 161 -96 423 -66 675 -66 1543 -136 567 -200 767 -202 65 -100 1401 -66 623 -136 567 -234 67 -236 197 -194 97 -66 263 -66 1827 -392 1893 -98 165 -268 133 -132 231 -162 225 -98 695 -198 563 -100 301 -332 267 -102 341 -66 99 -132 1299 -130 525 -68 161 -96 357 -98 353 -100 131 -100 131 -98 163 -132 323 -100 535 -66 1323 -130 133 -66 235 -134 1497 -132 387 -98 129 -162 2623 -134 163 -68 167 -66 959 -232 495 -68 131 -134 867 -134 865 -66 333 -98 305 -134 231 -98 765 -198 397 -432 165 -66 165 -366 265 -102 541 -100 261 -162 331 -134 457 -66 491 -196 97 -266 193 -262 65 -166 231 -266 497 -360 263 -98 587 -164 259 -98 231 -66 359 -100 267 -102 271 -168 97 -262 63 -66 261 -130 227 -130 295 -164 65 -66 265 -200 597 -134 267 -170 603 -100 97 -466 231 -264 97 -168 99 -66 65 -200 199 -100 267 -404 303 -102 201 -204 235 -134 131 -198 335 -298 327 -130 291 -164 63 -162 295 -262 197 -130 95 -130 195 -96 159 -130 161 -66 231 -100 165 -66 199 -134 363 -66 267 -168 165 -168 167 -100 165 -530 363 -432 99 -232 65 -132 395 -328 229 -98 197 -132 161 -96 191 -292 197 -204 133 -100 399 -166 531 -332 235 -168 99 -66 325 -158 553 -132 129 -226 231 -134 99 -462 129 -64 289 -100 193 -66 355 -164 291 -198 131 -298 197 -198 373 -268 335 -234 427 -68 199 -132 267 -232 131 -66 783 -326 63 -162 161 -130 227 -66 259 -562 233 -464 303 -102 201 -334 301 -134 297 -198 229 -66 127 -166 99 -100 197 -198 571 -66 457 -134 361 -424 131 -328 163 -98 63 -100 505 -102 201 -1094 229 -164 65 -230 789 -236 2505 -166 201 -170 163 -64 1139 -66 927 -100 295 -198 723 -100 365 -66 459 -196 3033 -272 199 -66 499 -202 1319 -232 295 -298 131 -362 97 -164 129 -132 65 -98 197 -130 129 -98 261 -130 97 -98 229 -96 425 -66 227 -166 483 -66 163 -326 567 -68 235 -68 67 -66 167 -66 235 -330 425 -164 63 -66 427 -102 167 -66 669 -132 429 -200 65 -102 133 -100 197 -368 +RAW_Data: 65 -134 2481 -228 65 -130 229 -228 763 -136 603 -166 1619 -98 1763 -102 837 -166 321 -66 951 -130 2067 -66 259 -132 1835 -66 437 -102 701 -66 565 -68 363 -70 1113 -66 1989 -164 257 -128 351 -162 1055 -232 265 -170 309 -200 435 -166 833 -102 2467 -132 595 -66 773 -166 1615 -98 131 -96 485 -64 517 -166 197 -68 1231 -68 403 -100 263 -134 233 -100 503 -100 333 -266 729 -66 199 -100 369 -68 1239 -100 197 -68 299 -170 337 -100 825 -132 163 -66 4205 -64 161 -100 635 -66 907 -66 1017 -166 1709 -100 201 -266 657 -68 463 -166 331 -164 293 -64 259 -162 129 -262 597 -134 701 -136 67 -168 235 -136 303 -170 1417 -66 263 -98 857 -100 659 -166 97 -100 2497 -64 2495 -98 719 -128 227 -130 2217 -164 623 -264 719 -134 329 -98 1371 -100 553 -294 165 -66 1163 -100 329 -196 649 -200 1123 -68 263 -100 593 -266 333 -102 1133 -136 131 -132 603 -200 1819 -66 489 -66 563 -266 1113 -230 165 -66 423 -68 335 -100 101 -100 1073 -132 897 -100 101 -100 499 -134 173 -138 763 -238 371 -130 403 -166 203 -102 271 -136 269 -166 99 -168 263 -96 425 -66 331 -234 133 -400 231 -132 453 -66 459 -164 199 -68 237 -132 163 -198 161 -196 265 -132 65 -64 195 -130 357 -164 663 -68 167 -600 131 -98 133 -304 203 -134 433 -98 261 -130 199 -100 237 -100 229 -326 99 -98 331 -132 99 -294 165 -66 303 -134 99 -232 133 -136 99 -68 267 -198 233 -138 67 -166 367 -100 333 -168 267 -200 369 -266 135 -404 1939 -132 231 -160 161 -64 293 -98 331 -132 339 -104 135 -100 197 -430 263 -202 233 -64 195 -162 129 -64 227 -298 265 -68 697 -66 301 -68 231 -300 131 -368 769 -234 265 -98 195 -324 97 -752 229 -126 355 -98 257 -98 287 -64 427 -132 295 -262 197 -170 369 -102 267 -100 169 -68 201 -102 2551 -136 635 -134 639 -134 99 -132 197 -200 371 -66 731 -132 199 -138 733 -304 433 -68 729 -440 197 -68 99 -102 165 -266 261 -164 491 -296 489 -194 257 -164 133 -134 237 -68 335 -98 227 -130 229 -98 295 -98 231 -202 267 -236 233 -136 331 -130 195 -128 261 -430 261 -162 97 -224 99 -130 193 -96 197 -162 229 -396 97 -98 227 -364 267 -100 99 -100 233 -236 697 -164 227 -196 63 -98 327 -230 325 -66 129 -196 95 -98 195 -130 325 -430 131 -194 129 -454 161 -196 235 -68 433 -134 667 -164 355 -236 101 -98 2143 -134 1827 -198 63 -198 65 -64 2859 -64 619 -66 97 -130 3157 -66 679 -194 1491 -98 +RAW_Data: 951 -64 393 -100 955 -132 4715 -100 131 -66 199 -204 1541 -66 929 -130 1347 -166 665 -132 233 -132 67 -102 433 -100 595 -228 997 -66 505 -68 133 -98 231 -68 571 -134 1371 -232 231 -270 135 -102 97 -66 867 -100 269 -68 967 -100 1649 -66 65 -66 951 -68 65 -202 363 -200 779 -102 1449 -294 419 -130 361 -230 1079 -164 163 -260 893 -102 333 -100 533 -166 467 -100 135 -66 135 -202 369 -100 199 -100 269 -134 301 -166 229 -66 101 -134 199 -134 1293 -64 779 -62 831 -66 1243 -68 267 -102 197 -100 395 -98 455 -64 621 -132 877 -98 199 -100 2101 -134 503 -100 2035 -134 735 -236 475 -136 237 -132 133 -134 1229 -100 133 -66 167 -68 2655 -100 1807 -100 1095 -264 825 -98 163 -66 491 -98 161 -128 953 -100 773 -100 131 -66 67 -134 457 -130 63 -64 389 -98 715 -66 425 -300 97 -100 1515 -66 303 -68 99 -98 721 -64 887 -132 65 -132 165 -66 635 -68 2801 -66 1561 -100 751 -98 129 -64 725 -136 201 -100 333 -204 573 -104 1745 -134 99 -66 129 -64 595 -134 167 -102 337 -134 567 -134 1131 -138 1207 -100 269 -68 135 -100 1143 -134 2139 -68 1701 -162 991 -596 431 -66 99 -132 657 -66 391 -320 357 -260 259 -98 429 -66 163 -228 65 -130 227 -66 261 -166 99 -98 131 -366 199 -134 463 -102 201 -98 231 -102 639 -238 301 -568 169 -610 265 -102 841 -198 297 -100 335 -132 263 -266 265 -68 469 -134 267 -68 933 -298 333 -298 729 -168 135 -136 437 -132 1137 -134 199 -68 265 -132 463 -166 129 -130 227 -98 297 -98 65 -132 97 -202 199 -232 305 -66 165 -198 365 -66 99 -98 299 -170 65 -136 301 -232 99 -564 133 -132 233 -170 99 -102 131 -134 65 -204 101 -98 297 -98 167 -762 233 -298 99 -326 395 -66 299 -132 369 -504 333 -98 483 -200 457 -164 63 -164 329 -162 65 -622 231 -268 131 -132 133 -134 131 -134 131 -66 99 -100 231 -66 167 -336 165 -98 197 -100 97 -264 321 -98 521 -132 163 -130 129 -294 297 -134 101 -102 265 -168 497 -68 197 -68 499 -134 269 -398 267 -130 203 -302 65 -498 271 -136 465 -292 131 -294 163 -198 329 -96 129 -98 193 -130 391 -330 165 -134 167 -170 297 -102 133 -136 135 -366 199 -132 423 -132 395 -168 65 -166 401 -98 229 -98 329 -98 99 -130 129 -228 261 -160 127 -426 389 -162 193 -132 131 -100 231 -168 67 -304 201 -68 765 -132 161 -162 193 -64 195 -64 295 -130 787 -98 419 -528 429 -66 363 -134 131 -100 133 -200 331 -98 +RAW_Data: 431 -66 1167 -68 937 -68 1003 -66 99 -132 941 -134 65 -66 365 -274 165 -236 367 -96 557 -134 675 -66 261 -164 127 -96 391 -164 161 -98 391 -292 163 -98 519 -196 165 -98 523 -66 195 -160 3343 -66 661 -100 2589 -136 307 -100 629 -136 639 -100 133 -168 405 -100 267 -66 465 -132 1171 -64 749 -64 165 -98 983 -100 163 -202 537 -66 327 -100 669 -100 401 -236 2885 -164 439 -134 97 -426 1931 -66 1385 -98 715 -98 519 -66 289 -162 97 -360 297 -166 163 -66 289 -66 555 -334 167 -230 429 -102 267 -132 943 -136 401 -68 929 -130 193 -68 467 -198 335 -66 963 -100 597 -132 197 -260 523 -232 1115 -102 1935 -66 1395 -134 305 -100 99 -66 199 -66 1071 -66 2357 -66 367 -498 769 -234 163 -130 191 -64 1211 -200 133 -102 201 -100 561 -366 361 -98 195 -100 537 -64 165 -196 1041 -332 133 -102 441 -230 4217 -66 1033 -66 167 -66 933 -100 565 -66 331 -164 673 -104 441 -66 533 -66 2095 -164 525 -66 297 -170 965 -198 421 -100 663 -832 65 -100 331 -164 231 -166 135 -168 237 -466 761 -134 891 -196 791 -198 257 -160 161 -98 293 -66 1081 -98 229 -130 327 -66 1301 -200 331 -166 101 -66 461 -100 2619 -132 1663 -98 1609 -134 499 -332 165 -370 67 -264 97 -96 259 -98 701 -402 197 -128 527 -236 233 -102 167 -134 303 -134 99 -166 299 -132 165 -200 467 -68 305 -168 207 -102 465 -102 729 -136 101 -374 327 -96 259 -98 467 -202 65 -66 673 -98 335 -404 135 -66 339 -204 99 -366 233 -68 365 -166 133 -102 867 -198 163 -162 163 -294 463 -332 165 -68 269 -268 331 -100 131 -166 299 -132 231 -400 263 -164 131 -266 267 -264 367 -66 371 -134 229 -104 267 -232 67 -466 265 -100 101 -100 165 -200 65 -200 301 -66 199 -168 233 -98 267 -66 67 -134 261 -196 261 -234 427 -294 65 -194 193 -66 259 -132 849 -96 63 -198 167 -294 95 -98 361 -164 261 -196 131 -132 437 -100 597 -262 327 -162 295 -98 295 -164 259 -196 425 -230 321 -66 195 -66 261 -496 99 -200 529 -132 133 -966 133 -132 165 -66 63 -128 491 -402 65 -262 299 -66 299 -202 265 -100 99 -668 97 -134 65 -100 101 -66 65 -266 691 -66 431 -166 167 -134 199 -370 899 -134 99 -100 1093 -166 163 -166 399 -98 327 -100 99 -168 135 -200 133 -202 429 -98 65 -98 197 -556 65 -66 97 -326 331 -166 333 -200 135 -100 235 -234 265 -98 65 -68 135 -66 335 -66 133 -298 99 -66 233 -164 435 -232 97 -132 97 -392 +RAW_Data: 99 -198 819 -66 1235 -98 321 -132 1091 -66 1307 -98 3059 -164 3305 -64 227 -98 591 -98 129 -66 229 -98 2143 -98 939 -68 563 -100 361 -232 945 -164 257 -96 229 -230 387 -64 195 -130 981 -294 587 -162 193 -98 1337 -66 293 -98 2665 -66 297 -98 647 -66 459 -132 491 -164 489 -96 595 -66 899 -66 837 -64 1151 -196 259 -98 357 -164 891 -132 1359 -134 197 -98 97 -98 261 -64 229 -96 461 -136 693 -100 201 -98 865 -66 599 -100 517 -132 709 -66 293 -298 655 -66 197 -130 129 -66 197 -98 4291 -66 673 -66 667 -132 1473 -132 133 -104 99 -66 163 -168 333 -134 1743 -132 1097 -132 99 -68 167 -602 1323 -352 99 -166 753 -98 423 -98 97 -66 1317 -228 1309 -98 1849 -66 1939 -132 601 -100 665 -100 1875 -66 695 -132 425 -66 425 -66 263 -134 165 -134 99 -98 829 -66 601 -166 131 -102 565 -66 301 -100 1099 -100 601 -138 533 -66 667 -234 561 -66 99 -68 2741 -98 199 -100 531 -168 101 -434 1027 -68 431 -66 403 -132 99 -98 565 -132 135 -100 399 -166 271 -236 233 -166 197 -366 99 -66 99 -168 503 -66 199 -170 207 -100 673 -368 99 -66 263 -168 133 -98 397 -268 337 -66 131 -132 231 -132 501 -134 99 -168 567 -138 103 -136 267 -298 231 -134 197 -160 321 -332 231 -98 131 -164 257 -64 163 -328 395 -66 331 -202 65 -168 133 -68 167 -100 233 -102 335 -66 197 -326 1101 -132 589 -100 811 -132 399 -136 269 -102 497 -66 559 -100 129 -98 855 -68 637 -102 65 -200 875 -68 233 -166 167 -66 529 -202 235 -102 231 -66 1237 -66 733 -98 1723 -132 101 -100 297 -66 829 -232 197 -100 367 -134 169 -166 167 -434 633 -100 235 -200 131 -134 233 -100 131 -100 331 -134 495 -432 65 -528 161 -130 295 -132 337 -136 133 -166 165 -100 269 -240 201 -336 133 -166 165 -238 199 -202 431 -434 99 -134 501 -166 231 -96 559 -202 167 -66 717 -98 987 -198 65 -64 163 -64 227 -98 555 -164 199 -64 361 -66 163 -98 129 -162 97 -130 161 -460 197 -230 681 -98 197 -98 329 -100 267 -266 291 -264 65 -100 329 -100 459 -200 363 -98 165 -134 231 -134 301 -134 231 -302 99 -132 101 -134 267 -136 233 -68 393 -422 163 -166 361 -166 99 -134 365 -134 133 -336 401 -66 495 -132 401 -168 133 -402 501 -136 1093 -862 165 -132 293 -300 289 -66 131 -164 391 -134 99 -360 359 -130 323 -200 423 -98 195 -162 295 -132 161 -98 129 -782 131 -426 227 -64 259 -166 63 -160 323 -98 261 -230 +RAW_Data: 231 -66 921 -66 355 -64 1019 -98 227 -258 163 -66 597 -232 1313 -132 163 -404 467 -236 901 -164 483 -98 195 -96 489 -134 103 -238 169 -66 67 -68 299 -100 497 -68 65 -134 1635 -304 1153 -100 539 -168 265 -200 499 -166 535 -100 397 -168 931 -100 131 -66 631 -134 897 -270 1233 -100 65 -132 131 -334 663 -66 163 -66 131 -132 705 -98 571 -200 433 -100 237 -234 229 -132 1627 -66 569 -100 715 -66 1863 -272 265 -68 301 -98 465 -68 97 -134 99 -66 395 -136 1405 -66 529 -132 63 -196 579 -132 413 -260 129 -136 101 -166 1201 -134 833 -134 393 -66 335 -172 201 -68 1027 -96 753 -64 815 -66 97 -64 1341 -132 289 -160 127 -66 99 -228 1083 -96 163 -66 259 -64 159 -98 2409 -168 767 -200 367 -66 1675 -66 1067 -98 3407 -200 99 -66 1403 -166 99 -134 439 -200 329 -136 599 -66 637 -66 835 -66 1099 -98 99 -66 463 -166 165 -100 461 -164 3037 -66 655 -66 97 -98 229 -130 355 -132 1443 -66 527 -98 881 -98 229 -162 127 -96 583 -64 65 -162 489 -166 885 -194 257 -98 1539 -66 293 -166 229 -132 655 -98 757 -49522 271 -758 689 -1264 737 -670 293 -1152 811 -1144 341 -664 773 -678 327 -1118 807 -1144 835 -1146 781 -1126 873 -1096 347 -622 877 -624 321 -1106 843 -1098 871 -1098 843 -1106 379 -610 841 -584 381 -1122 365 -602 845 -1116 837 -610 381 -1056 889 -1078 383 -614 827 -1110 877 -592 353 -1108 845 -1120 839 -1120 347 -602 849 -1110 865 -612 361 -1072 869 -1114 351 -618 861 -618 343 -1090 853 -1106 387 -618 797 -674 347 -1084 389 -574 867 -584 381 -1114 841 -1102 845 -1116 839 -1112 843 -1098 875 -1086 383 -584 865 -588 375 -1100 861 -1112 851 -1084 853 -1108 847 -1106 381 -584 857 -610 383 -1080 357 -602 871 -602 385 -1084 383 -616 823 -610 373 -1086 381 -590 871 -1084 839 -628 353 -1102 875 -1100 349 -9404 875 -1060 871 -1086 887 -1088 879 -1058 863 -1086 855 -1132 845 -1078 871 -1076 857 -1098 881 -1082 861 -1088 843 -1120 853 -1074 879 -1074 879 -1068 889 -614 341 -1090 387 -616 863 -624 345 -1088 391 -590 857 -612 385 -1058 393 -596 843 -1088 889 -1078 879 -578 387 -1082 875 -1076 415 -550 881 -1070 877 -592 391 -1114 821 -1104 373 -620 821 -624 361 -1072 903 -1086 855 -1092 843 -1086 905 -1054 387 -614 863 -618 347 -1088 853 -1114 845 -1090 867 -1070 381 -610 885 -584 385 -1052 407 -578 877 -1052 899 -600 389 -1048 907 -1074 383 -586 877 -1072 877 -594 359 -1076 875 -1082 891 -1088 363 -616 855 -1084 857 -592 381 -1088 883 -1086 385 -572 +RAW_Data: 889 -624 353 -1082 853 -1096 379 -594 853 -624 353 -1092 417 -582 847 -612 385 -1076 847 -1080 883 -1052 913 -1044 907 -1076 849 -1088 383 -602 867 -616 361 -1068 901 -1072 865 -1104 831 -1080 879 -1098 397 -586 855 -626 355 -1084 381 -592 873 -616 351 -1084 385 -624 821 -620 359 -1086 387 -584 883 -1086 877 -592 355 -1106 853 -1086 387 -69570 97 -100 99 -2620 131 -636 333 -102 235 -236 67 -68 363 -66 201 -100 567 -102 267 -164 101 -134 65 -68 197 -68 297 -166 671 -100 469 -336 165 -100 201 -66 169 -230 169 -204 329 -624 67 -98 265 -232 193 -168 299 -100 235 -138 101 -370 165 -294 333 -622 231 -130 129 -130 353 -132 195 -162 359 -164 67 -68 333 -100 133 -688 235 -236 497 -198 293 -98 129 -296 293 -164 229 -128 229 -132 193 -400 165 -66 163 -98 361 -164 355 -196 587 -164 131 -98 263 -554 99 -130 129 -130 191 -464 99 -132 67 -100 167 -604 329 -66 199 -68 133 -102 163 -66 2971 -132 785 -66 329 -96 323 -100 201 -136 301 -66 1959 -166 867 -134 467 -66 297 -100 835 -100 753 -166 165 -64 67 -370 335 -66 559 -232 165 -334 65 -162 129 -354 163 -64 131 -134 265 -300 263 -132 267 -296 327 -198 99 -132 535 -132 469 -866 231 -860 99 -232 503 -134 99 -198 233 -134 267 -200 97 -358 297 -164 259 -98 227 -166 135 -66 323 -100 97 -294 131 -164 129 -98 295 -96 129 -426 299 -100 67 -102 623 -100 163 -194 127 -360 563 -134 199 -428 493 -98 229 -130 257 -64 165 -100 131 -98 163 -692 357 -64 161 -98 321 -64 389 -230 65 -692 227 -130 261 -132 231 -162 287 -298 97 -460 393 -130 301 -168 331 -100 269 -202 101 -134 201 -102 99 -132 199 -204 235 -664 65 -562 133 -328 463 -100 291 -194 159 -162 227 -98 293 -328 165 -128 227 -574 535 -332 197 -168 65 -300 131 -66 389 -1078 131 -64 259 -64 223 -98 257 -164 63 -328 433 -134 65 -602 131 -68 333 -136 369 -66 297 -264 427 -66 97 -130 429 -102 133 -136 203 -240 167 -236 329 -526 67 -132 133 -168 331 -360 65 -66 331 -296 267 -134 469 -132 595 -230 661 -662 299 -100 265 -200 203 -168 801 -100 133 -68 399 -132 99 -100 161 -390 65 -298 65 -98 261 -130 161 -128 257 -66 67 -134 621 -98 227 -328 99 -230 129 -294 193 -96 195 -318 425 -526 129 -196 163 -162 65 -132 293 -130 63 -66 325 -128 63 -130 293 -66 199 -200 269 -206 133 -198 325 -98 163 -100 97 -98 261 -164 67 -98 167 -430 131 -494 131 -164 +RAW_Data: 97 -98 861 -66 1199 -166 231 -100 651 -166 197 -104 439 -98 131 -64 493 -98 883 -96 99 -98 3327 -66 131 -264 733 -134 2133 -166 131 -102 303 -136 535 -134 701 -98 355 -228 131 -202 99 -134 99 -100 791 -166 169 -202 671 -100 741 -100 263 -66 165 -68 935 -132 197 -198 673 -100 605 -66 1457 -98 1195 -166 2347 -134 505 -100 1469 -66 391 -100 229 -100 1171 -98 939 -100 459 -170 369 -134 231 -162 127 -98 95 -66 195 -98 195 -66 299 -100 331 -98 65 -232 369 -132 201 -68 167 -166 1481 -102 501 -160 1257 -66 2307 -64 623 -164 2079 -66 1101 -98 423 -64 659 -68 431 -136 99 -100 435 -130 167 -168 835 -200 135 -104 133 -100 503 -68 1437 -232 821 -132 357 -96 463 -66 263 -64 683 -132 165 -96 655 -166 3939 -100 1169 -132 2443 -98 197 -132 425 -234 233 -162 1043 -66 197 -100 2793 -134 167 -104 675 -100 197 -134 1367 -102 763 -132 265 -230 133 -102 365 -100 167 -66 1069 -66 837 -100 295 -160 97 -64 129 -132 617 -164 197 -100 133 -136 337 -172 133 -66 557 -98 951 -66 263 -130 587 -66 729 -196 335 -166 933 -432 369 -100 199 -296 225 -98 355 -66 129 -64 557 -98 289 -66 355 -128 193 -162 267 -134 299 -98 165 -170 303 -640 1031 -134 99 -66 135 -68 771 -166 171 -104 201 -134 131 -68 635 -428 661 -292 749 -430 1161 -100 905 -98 65 -98 657 -262 2837 -132 67 -66 265 -132 631 -66 1037 -296 97 -98 1703 -302 367 -100 505 -232 497 -362 333 -134 591 -100 755 -232 67 -130 587 -66 231 -168 65 -332 99 -66 267 -232 393 -134 65 -132 131 -428 133 -200 165 -202 199 -168 165 -102 269 -100 333 -852 201 -134 233 -202 65 -200 563 -768 265 -136 169 -102 169 -598 333 -202 267 -134 267 -328 163 -130 625 -500 199 -200 99 -270 65 -134 65 -198 65 -100 99 -596 493 -66 99 -66 331 -232 103 -136 373 -168 831 -170 65 -672 163 -102 133 -136 331 -100 333 -234 101 -100 99 -200 99 -100 201 -302 199 -600 301 -202 135 -134 705 -166 435 -530 97 -198 131 -198 195 -66 163 -392 293 -66 295 -370 229 -198 65 -100 405 -134 165 -134 133 -170 337 -236 205 -274 267 -134 329 -132 195 -132 503 -132 133 -136 133 -334 197 -196 299 -168 101 -100 233 -100 439 -134 301 -332 331 -298 433 -406 433 -68 167 -100 203 -100 101 -102 99 -328 397 -234 205 -168 133 -364 63 -202 397 -198 95 -394 267 -134 569 -66 201 -102 133 -136 101 -102 99 -132 99 -196 197 -498 197 -102 135 -170 +RAW_Data: 331 -164 63 -162 1267 -66 163 -130 129 -66 725 -164 231 -64 853 -66 101 -134 199 -102 99 -68 365 -66 357 -130 815 -64 357 -98 97 -98 97 -66 65 -466 231 -172 3749 -66 849 -130 917 -64 327 -64 1013 -98 555 -332 795 -100 571 -132 769 -132 401 -134 1297 -134 377 -138 435 -100 401 -100 667 -100 1761 -66 667 -66 1533 -236 233 -98 885 -130 457 -66 999 -66 165 -66 833 -134 695 -166 501 -66 499 -200 329 -64 197 -134 441 -100 2099 -98 491 -134 197 -130 2225 -132 65 -100 689 -64 193 -160 159 -96 195 -98 323 -164 259 -98 535 -472 771 -66 665 -270 665 -66 595 -266 2191 -64 643 -98 1287 -98 741 -100 233 -200 569 -194 261 -68 637 -100 97 -66 491 -158 395 -138 1017 -66 627 -262 559 -64 327 -98 263 -134 99 -102 201 -102 337 -66 167 -68 679 -100 471 -134 195 -66 133 -202 693 -96 197 -98 391 -164 99 -98 3883 -194 461 -100 237 -168 1891 -68 301 -68 969 -166 1439 -294 551 -130 389 -98 99 -196 167 -102 505 -66 569 -234 901 -98 407 -136 469 -66 769 -98 769 -166 1263 -266 297 -98 1701 -200 203 -168 329 -232 65 -100 329 -164 803 -100 135 -200 233 -166 135 -272 265 -134 197 -100 133 -134 539 -232 197 -396 165 -366 263 -68 233 -102 365 -132 233 -100 135 -266 199 -234 167 -232 97 -524 127 -128 389 -98 305 -364 261 -130 257 -162 589 -464 361 -66 229 -134 161 -100 203 -432 265 -66 199 -66 199 -366 229 -236 99 -134 99 -100 131 -168 133 -100 131 -236 267 -132 297 -264 291 -132 167 -234 65 -100 199 -66 333 -730 237 -440 365 -102 99 -100 99 -132 99 -100 1429 -134 427 -100 97 -100 131 -164 799 -170 1077 -100 431 -66 133 -168 737 -134 197 -230 65 -102 803 -132 491 -98 429 -198 471 -134 365 -66 299 -236 65 -66 2837 -102 399 -64 585 -64 523 -196 97 -98 295 -196 555 -160 261 -500 299 -396 333 -236 133 -68 327 -100 199 -204 699 -66 701 -100 65 -164 65 -370 195 -196 97 -66 193 -130 129 -360 195 -130 231 -96 291 -64 455 -228 293 -196 291 -162 97 -194 621 -130 847 -66 395 -66 161 -128 193 -130 293 -98 231 -170 67 -134 297 -360 167 -266 263 -526 263 -132 229 -98 191 -160 159 -100 721 -234 101 -100 99 -130 259 -258 265 -632 687 -164 133 -134 631 -100 199 -102 165 -560 299 -200 265 -332 431 -870 99 -266 503 -364 135 -66 269 -68 499 -100 265 -102 263 -102 569 -234 719 -132 99 -196 419 -262 163 -688 95 -66 165 -128 95 -66 +RAW_Data: 295 -98 987 -196 517 -100 489 -66 355 -132 563 -198 867 -134 1413 -134 541 -134 767 -100 193 -98 1799 -102 467 -134 299 -96 323 -66 261 -100 259 -66 229 -96 851 -66 369 -266 469 -66 101 -98 163 -136 267 -432 859 -130 523 -66 197 -134 1027 -132 227 -194 393 -98 807 -166 235 -100 133 -66 165 -102 133 -136 371 -162 1411 -132 865 -200 471 -100 133 -68 299 -66 633 -98 329 -234 401 -98 1505 -132 133 -134 331 -262 163 -66 261 -98 289 -64 201 -68 1055 -96 391 -66 951 -298 265 -202 297 -66 401 -68 131 -100 1733 -98 941 -66 803 -98 847 -64 3701 -100 721 -160 357 -166 1799 -66 329 -100 99 -102 363 -198 167 -136 197 -66 567 -66 199 -236 1247 -166 2455 -68 1107 -200 235 -100 2355 -130 913 -98 877 -98 163 -196 97 -66 427 -100 801 -134 867 -98 263 -68 441 -134 561 -98 1671 -134 865 -68 935 -132 163 -102 975 -66 1343 -132 1339 -134 369 -100 1107 -66 1167 -168 631 -232 835 -66 1027 -132 333 -166 265 -98 1207 -98 223 -98 455 -64 2095 -134 933 -136 233 -68 335 -136 305 -100 1737 -66 427 -100 263 -130 323 -66 227 -66 717 -100 265 -100 65 -128 355 -66 367 -132 95 -230 229 -100 131 -64 493 -132 291 -396 393 -130 259 -196 227 -288 397 -68 229 -430 99 -302 237 -700 65 -66 65 -100 133 -200 101 -336 133 -166 237 -202 67 -302 67 -68 333 -132 263 -102 267 -296 163 -166 233 -168 363 -64 295 -298 537 -166 431 -200 431 -166 63 -258 363 -164 563 -234 199 -68 299 -100 325 -754 295 -196 65 -98 165 -132 301 -134 131 -134 97 -68 405 -68 233 -134 271 -134 67 -168 101 -136 133 -366 99 -132 67 -132 265 -200 233 -100 201 -136 101 -66 263 -132 129 -66 293 -582 263 -132 1103 -134 203 -168 97 -66 197 -264 131 -168 133 -132 65 -134 199 -134 101 -100 131 -436 99 -232 97 -398 231 -362 65 -202 301 -396 297 -98 199 -134 265 -164 101 -168 267 -102 405 -170 99 -102 397 -132 97 -98 295 -98 1179 -100 135 -136 131 -134 765 -134 465 -168 439 -232 403 -100 65 -134 931 -100 169 -136 237 -68 231 -234 199 -68 401 -134 541 -166 429 -166 1607 -368 533 -66 363 -66 133 -134 433 -166 297 -238 201 -100 201 -170 199 -134 273 -136 99 -134 167 -238 133 -66 265 -134 165 -132 165 -132 97 -228 723 -198 415 -64 491 -298 257 -66 231 -192 225 -96 227 -98 193 -96 521 -198 65 -66 231 -166 163 -98 465 -66 133 -132 195 -130 225 -162 521 -130 63 -66 199 -228 +RAW_Data: 817 -162 449 -160 719 -198 469 -68 133 -68 1101 -132 593 -230 1105 -100 131 -134 231 -66 329 -196 685 -96 557 -68 1263 -68 101 -68 397 -100 65 -66 625 -66 97 -132 1099 -66 493 -66 757 -98 1151 -66 303 -134 1901 -66 99 -100 665 -262 991 -98 791 -66 1925 -168 865 -232 835 -98 505 -102 99 -100 535 -100 169 -134 427 -132 863 -68 167 -134 975 -100 133 -268 1339 -100 1453 -66 1445 -162 195 -64 3623 -66 237 -68 1063 -308 1449 -98 1111 -132 167 -102 855 -270 199 -134 297 -134 267 -168 863 -234 637 -66 567 -230 99 -200 3325 -198 845 -66 289 -66 131 -66 815 -130 1093 -100 167 -100 429 -98 1703 -166 195 -64 971 -98 163 -192 195 -168 439 -132 329 -132 67 -134 67 -134 1591 -168 407 -100 867 -68 399 -134 661 -100 663 -66 237 -136 395 -232 131 -66 695 -100 627 -264 913 -66 1083 -98 287 -66 199 -132 335 -100 1031 -68 99 -100 3815 -98 165 -66 129 -98 163 -128 563 -98 779 -96 223 -64 161 -164 2025 -66 1741 -172 101 -136 203 -102 665 -100 475 -64 167 -100 637 -98 997 -170 1207 -136 233 -166 233 -168 635 -132 199 -100 235 -270 199 -98 131 -102 169 -170 293 -98 323 -164 427 -334 233 -168 267 -68 369 -100 263 -368 101 -66 665 -98 265 -100 133 -100 99 -168 133 -66 133 -132 133 -66 269 -134 435 -68 267 -136 271 -500 163 -100 163 -166 355 -132 97 -98 323 -194 63 -688 463 -130 97 -396 65 -100 357 -194 461 -98 161 -130 223 -162 165 -352 461 -300 267 -166 233 -464 329 -100 293 -362 163 -228 289 -66 229 -66 195 -162 325 -66 261 -98 127 -424 299 -302 367 -68 265 -272 429 -98 161 -98 393 -296 65 -130 161 -196 261 -66 473 -234 97 -98 263 -160 323 -98 67 -132 697 -298 99 -134 233 -202 97 -134 301 -200 307 -100 101 -134 865 -166 231 -202 233 -100 301 -170 169 -102 169 -200 65 -98 595 -166 231 -234 661 -66 473 -334 165 -304 365 -266 97 -502 363 -134 133 -236 65 -100 99 -134 99 -170 235 -66 333 -100 195 -100 133 -300 133 -102 301 -304 65 -100 99 -100 131 -202 135 -134 65 -200 363 -66 263 -498 67 -68 295 -194 321 -368 435 -100 97 -664 99 -100 569 -66 133 -66 67 -134 199 -136 101 -68 301 -68 405 -198 133 -132 581 -132 165 -98 159 -98 197 -66 229 -130 131 -294 133 -96 423 -100 427 -300 357 -132 291 -64 95 -194 455 -98 263 -100 359 -196 65 -162 227 -162 157 -96 157 -230 589 -132 325 -134 535 -66 267 -100 135 -302 +RAW_Data: 131 -134 599 -166 393 -98 369 -236 197 -100 401 -232 569 -134 135 -70 337 -134 101 -136 135 -100 1895 -66 401 -170 503 -66 1633 -66 601 -66 355 -96 683 -100 729 -68 133 -132 433 -68 569 -100 133 -68 201 -132 835 -100 465 -68 527 -98 193 -200 1129 -166 535 -100 199 -98 259 -132 227 -64 1597 -98 261 -192 753 -100 911 -66 667 -298 131 -100 263 -66 1051 -230 787 -66 935 -66 233 -98 885 -236 431 -66 197 -162 521 -68 167 -196 263 -96 589 -98 517 -66 1439 -64 777 -66 3219 -132 679 -134 205 -68 507 -198 749 -200 199 -168 167 -100 133 -134 201 -68 731 -66 495 -198 737 -66 237 -68 135 -100 167 -234 1535 -68 873 -66 373 -66 67 -232 297 -68 65 -66 1095 -68 327 -130 63 -132 1715 -66 2261 -100 321 -132 197 -164 457 -232 1291 -132 405 -68 1001 -68 1133 -272 471 -66 99 -134 1403 -68 167 -68 1091 -336 933 -134 1207 -132 265 -68 267 -66 99 -366 265 -66 1469 -258 367 -168 429 -132 129 -66 491 -132 343 -100 65 -100 263 -136 199 -164 273 -204 791 -100 901 -66 167 -98 165 -64 559 -132 619 -132 1087 -128 2283 -398 1467 -164 259 -130 1927 -130 421 -98 1085 -66 705 -68 1843 -168 875 -170 203 -136 341 -640 199 -66 133 -554 161 -196 63 -66 521 -292 163 -160 95 -158 127 -192 197 -100 587 -130 397 -662 261 -66 193 -130 259 -66 361 -64 459 -98 197 -560 655 -130 389 -66 1135 -100 133 -130 131 -98 1011 -100 561 -66 685 -164 457 -132 2469 -200 609 -66 665 -66 67 -132 327 -200 1657 -134 919 -132 651 -100 327 -230 191 -130 263 -358 95 -130 549 -98 99 -68 299 -100 461 -132 99 -472 165 -134 99 -66 99 -132 399 -102 169 -102 697 -166 233 -132 333 -632 197 -164 865 -266 101 -68 533 -166 299 -100 163 -228 259 -66 327 -200 65 -66 229 -100 363 -230 197 -336 165 -102 893 -300 65 -132 231 -370 265 -230 99 -98 229 -518 199 -100 401 -724 225 -98 63 -96 231 -64 291 -292 65 -98 131 -98 159 -158 127 -194 161 -292 65 -98 133 -66 297 -66 303 -168 97 -168 231 -234 269 -532 135 -168 99 -168 301 -528 99 -506 199 -368 399 -132 329 -372 99 -68 133 -264 197 -100 201 -200 67 -134 131 -270 133 -134 133 -198 327 -200 65 -100 331 -262 161 -166 469 -534 167 -738 131 -100 367 -232 101 -100 265 -604 65 -170 99 -166 299 -102 169 -132 99 -398 229 -330 197 -166 335 -366 97 -98 131 -200 269 -100 199 -168 131 -134 537 -98 265 -100 335 -236 99 -366 +RAW_Data: 459 -100 453 -130 419 -130 519 -96 63 -130 2077 -66 767 -64 127 -134 1961 -296 529 -202 637 -134 527 -100 201 -68 633 -66 163 -360 1029 -68 765 -100 867 -66 503 -100 131 -66 841 -98 165 -68 237 -66 509 -100 501 -302 235 -66 99 -164 227 -130 551 -196 327 -66 1571 -132 99 -68 867 -66 163 -96 161 -130 129 -130 549 -130 487 -166 1801 -66 229 -66 197 -232 325 -66 425 -198 131 -64 295 -166 735 -66 533 -98 227 -130 129 -262 425 -100 263 -66 129 -132 97 -168 971 -170 405 -68 199 -134 475 -202 297 -98 1445 -98 395 -196 161 -66 225 -134 1803 -100 473 -102 1499 -66 199 -100 701 -132 165 -68 133 -102 303 -98 735 -102 805 -100 827 -100 235 -100 65 -266 637 -68 693 -66 1383 -228 819 -66 233 -304 435 -198 203 -136 1135 -270 1709 -64 227 -64 581 -134 505 -66 2203 -64 293 -64 753 -66 551 -132 747 -64 1303 -64 463 -66 229 -102 1877 -266 871 -166 1357 -64 819 -66 465 -198 693 -68 165 -64 95 -128 3785 -132 1465 -100 299 -102 329 -164 595 -134 1029 -66 299 -168 1263 -166 331 -68 967 -100 101 -102 603 -260 165 -132 467 -66 233 -66 235 -102 475 -100 135 -68 301 -134 297 -98 131 -102 269 -466 99 -134 237 -166 135 -168 203 -102 265 -68 503 -66 233 -66 637 -134 101 -200 199 -166 293 -554 361 -328 367 -264 533 -238 167 -68 135 -170 99 -300 591 -298 133 -236 299 -66 231 -368 263 -232 435 -136 133 -102 133 -200 133 -134 163 -134 167 -168 299 -66 265 -100 133 -240 135 -132 263 -170 269 -200 501 -396 263 -98 227 -132 129 -292 427 -66 165 -102 627 -602 99 -66 301 -168 199 -100 563 -330 165 -134 233 -136 65 -332 499 -100 131 -232 325 -96 65 -132 195 -98 393 -624 323 -68 133 -98 195 -162 231 -100 263 -132 231 -102 133 -236 99 -236 231 -166 65 -102 133 -268 101 -102 299 -136 267 -164 493 -64 229 -258 291 -326 263 -198 391 -134 167 -202 365 -594 133 -102 201 -134 503 -396 429 -204 169 -400 197 -170 267 -132 403 -466 297 -98 469 -234 395 -132 233 -100 165 -100 165 -66 197 -68 297 -166 501 -134 133 -100 65 -166 631 -68 297 -134 199 -100 165 -68 299 -266 133 -66 165 -100 231 -490 557 -134 371 -164 299 -170 733 -164 239 -334 335 -66 299 -300 199 -170 103 -100 233 -102 641 -168 65 -100 995 -66 265 -160 259 -130 129 -226 425 -100 355 -726 97 -688 99 -66 233 -266 299 -942 167 -102 167 -166 65 -100 367 -136 99 -134 199 -134 267 -164 +RAW_Data: 67 -68 233 -66 899 -66 163 -96 485 -98 355 -130 943 -100 235 -168 499 -104 1367 -98 297 -100 635 -68 1169 -100 67 -134 835 -264 959 -164 129 -98 419 -196 589 -66 421 -66 1717 -100 133 -100 265 -134 227 -356 455 -166 163 -66 1055 -100 1455 -134 463 -98 2191 -132 295 -132 335 -66 709 -64 619 -98 959 -68 835 -170 603 -134 1033 -134 635 -168 759 -232 397 -198 397 -164 1267 -166 257 -198 1295 -100 239 -104 563 -204 335 -198 203 -68 901 -68 1255 -134 1697 -66 793 -66 1691 -68 201 -100 765 -66 165 -132 131 -230 131 -66 917 -66 335 -338 231 -170 827 -98 199 -136 301 -196 65 -98 199 -200 765 -134 403 -98 333 -68 1691 -132 2565 -64 569 -170 1255 -264 65 -132 1243 -132 2527 -66 259 -66 1739 -100 1309 -198 167 -238 337 -66 131 -68 1973 -362 299 -100 1387 -96 129 -164 423 -230 3875 -96 4283 -98 165 -98 515 -134 469 -68 171 -102 1163 -100 65 -298 461 -66 367 -136 205 -168 371 -98 491 -164 161 -262 1093 -100 299 -100 269 -334 1205 -98 63 -98 261 -64 457 -98 diff --git a/assets/unit_tests/subghz/test_random_raw.sub b/assets/unit_tests/subghz/test_random_raw.sub index 06dfb9b4b..7d342bb93 100644 --- a/assets/unit_tests/subghz/test_random_raw.sub +++ b/assets/unit_tests/subghz/test_random_raw.sub @@ -139,3 +139,24 @@ RAW_Data: 277 -244 275 -1360 275 -1340 277 -246 277 -236 261 -1380 275 -1346 277 RAW_Data: 29262 361 -68 2635 -66 24113 -66 1131 -100 4157 -66 26253 -130 621 -18438 99 -298 231 -66 197 -496 753 -230 7503 -16526 65 -396 65 -296 99 -196 293 -64 429 -132 397 -66 329 -66 37701 -66 13475 -100 54967 -64 18209 -18340 97 -462 197 -98 587 -232 97 -100 259 -98 197 -262 297 -64 557 -100 599 -100 333 -234 42493 -13212 6449 -206 173 -214 217 -176 195 -218 181 -218 181 -182 217 -182 217 -176 187 -214 215 -180 217 -182 217 -182 217 -178 185 -424 1177 -388 387 -240 381 -214 181 -398 211 -380 419 -176 217 -394 203 -394 205 -380 189 -402 421 -168 219 -398 393 -190 191 -398 205 -406 185 -402 381 -212 215 -362 241 -378 421 -176 377 -218 197 -378 427 -210 393 -172 429 -172 397 -212 217 -362 389 -228 197 -372 417 -204 395 -210 181 -398 391 -192 201 -216888 761 -200 299 -166 695 -132 15435 -66 5611 -66 21049 -66 4947 -66 2355 -66 1921 -100 2223 -100 2107 -100 397 -98 3643 -66 5301 -98 14205 -66 37371 -246 175 -216 179 -216 177 -224 149 -246 159 -228 181 -212 201 -204 159 -244 151 -254 169 -214 181 -210 197 -182 181 -454 1141 -444 357 -228 361 -246 177 -396 209 -412 367 -188 187 -434 201 -394 185 -406 193 -402 377 -238 181 -386 381 -234 153 -424 205 -412 157 -412 383 -240 181 -398 203 -392 385 -236 371 -212 179 -400 383 -240 359 -210 375 -220 381 -246 175 -394 383 -240 181 -398 363 -222 379 -246 175 -394 383 -204 217 -182856 99 -66 99 -300 133 -402 65 -198 99 -328 65 -100 491 -164 593 -100 3547 -64 361 -66 789 -68 2521 -66 22883 -66 2659 -98 3309 -130 3789 -100 9689 -17178 99 -1388 65 -266 197 -100 131 -134 99 -232 627 -130 233 -66 1949 -100 14567 -198 165 -256 181 -208 159 -214 183 -220 163 -244 149 -246 159 -236 181 -254 141 -226 151 -246 157 -228 181 -212 201 -400 1163 -428 379 -230 355 -244 177 -396 207 -412 367 -222 157 -418 189 -410 207 -412 171 -430 357 -226 165 -404 413 -204 181 -428 173 -428 169 -426 353 -236 173 -414 173 -408 381 -244 337 -222 201 -408 397 -208 393 -204 395 -208 359 -246 177 -394 387 -200 205 -380 415 -202 395 -208 181 -432 357 -226 169 -195084 65 -300 763 -66 297 -364 593 -68 2883 -66 1357 -68 363 -98 3841 -66 3119 -66 5153 -66 4023 -268 143 -246 133 -290 141 -250 139 -254 141 -226 181 -248 137 -254 143 -252 139 -252 143 -230 181 -250 139 -254 145 -436 1135 -448 349 -240 347 -254 157 -434 167 -426 377 -226 157 -434 167 -426 155 -440 163 -434 375 -206 215 -380 381 -234 153 RAW_Data: -424 205 -412 159 -412 381 -240 181 -398 203 -392 387 -236 369 -212 179 -400 383 -240 359 -244 339 -222 381 -246 175 -394 383 -240 181 -398 363 -222 381 -244 175 -392 383 -240 181 -184002 99 -360 63 -330 65 -132 129 -232 97 -198 295 -328 6031 -66 831 -132 3417 -66 2187 -64 2183 -100 6535 -66 1127 -66 2569 -66 2031 -66 2271 -66 2183 -66 3815 -66 3803 -66 493 -66 1909 -66 1627 -98 4805 -17512 67 -2164 131 -498 265 -430 163 -98 97 -64 99 -230 99 -100 229 -230 165 -196 63 -132 99 -66 927 -66 14955 -66 19621 -68 2627 -66 14305 -68 23247 -66 2891 -66 3941 -66 3021 -212 173 -242 181 -218 181 -214 181 -208 157 -250 141 -248 181 -218 179 -214 179 -210 159 -250 179 -214 181 -218 181 -404 1153 -404 389 -244 375 -192 181 -436 161 -414 383 -240 181 -398 205 -392 201 -394 205 -394 365 -246 177 -396 383 -204 217 -398 171 -426 167 -428 353 -242 173 -420 173 -408 373 -220 403 -208 175 -422 381 -194 399 -228 357 -246 355 -210 215 -400 387 -208 181 -398 391 -226 353 -246 177 -398 383 -204 217 -185098 163 -166 525 -98 293 -100 63 -66 229 -66 1183 -66 1507 -66 3089 -98 30187 -66 2847 -19112 133 -364 131 -394 97 -166 295 -66 229 -164 227 -66 263 -130 623 -98 2071 -66 493 -66 787 -98 691 -64 10249 -132 3879 -66 1949 -66 3453 -198 23157 -66 2845 -100 1193 -66 1587 -100 3797 -98 3187 -100 3319 -66 22119 -98 5513 -226 155 -244 153 -256 131 -248 151 -246 159 -262 121 -274 133 -272 127 -244 153 -254 167 -248 145 -244 133 -252 177 -398 1169 -418 381 -238 359 -242 141 -430 169 -426 357 -274 139 -422 171 -442 173 -428 167 -426 353 -236 171 -416 379 -226 149 -436 161 -438 173 -406 381 -234 153 -424 205 -380 389 -244 359 -206 215 -384 381 -246 335 -224 383 -246 355 -244 179 -404 385 -206 181 -432 359 -226 355 -246 175 -398 383 -240 181 -179760 97 -168 727 -66 97 -332 1389 -66 2793 -66 4955 -100 12453 -100 2425 -66 21965 -66 3809 -68 1683 -66 3095 -66 2153 -64 999 -208 173 -220 181 -214 191 -196 181 -212 183 -220 191 -212 181 -214 191 -198 181 -212 181 -222 191 -212 181 -214 191 -416 1167 -424 369 -220 373 -210 209 -390 207 -376 403 -190 187 -418 189 -408 209 -412 173 -428 357 -226 169 -404 399 -208 179 -412 209 -396 169 -428 355 -230 201 -378 205 -406 381 -244 339 -222 193 -400 413 -204 393 -208 347 -220 401 -210 175 -422 383 -202 217 -398 365 -222 377 -246 175 -390 385 -204 217 -179890 165 -1552 131 -164 65 RAW_Data: -1448 361 -17056 131 -134 233 -1462 131 -166 953 -100 261 -164 5077 -272 137 -268 143 -252 141 -248 143 -246 159 -252 141 -244 143 -290 107 -276 145 -244 131 -250 179 -248 143 -252 141 -414 1165 -424 373 -236 359 -242 145 -434 169 -428 355 -230 169 -442 173 -434 157 -406 193 -402 379 -238 181 -422 335 -252 157 -434 167 -428 185 -406 381 -208 211 -390 207 -410 381 -200 373 -236 171 -414 383 -202 393 -210 379 -220 373 -208 211 -390 383 -204 217 -398 365 -220 379 -244 175 -394 381 -240 181 -161030 97 -166 167 -930 593 -2670 1091 -132 229 -98 461 -164 1649 -66 6311 -100 44723 -16832 67 -2656 131 -132 99 -132 263 -100 399 -68 893 -18950 99 -164 165 -198 525 -998 335 -66 565 -66 1057 -17880 97 -360 195 -262 131 -332 625 -98 197 -230 455 -98 9343 -16498 67 -368 131 -598 65 -1066 333 -300 789 -130 757 -66 87207 -16554 97 -3520 97 -786 591 -64 461 -98 21495 -66 24811 -18448 131 -296 491 -134 163 -760 1091 -230 893 -66 927 -68 4581 -68 32965 -64 45217 -17292 131 -1684 231 -132 327 -64 163 -330 263 -230 25751 +RAW_Data: -66 529 -66 2519 -66 265 -68 10101 -1794 65 -1890 393 -562 97 -132 197 -98 493 -330 97 -164 97 -230 327 -326 99 -100 97 -164 65 -132 293 -98 297 -166 161 -130 297 -230 1391 -68 11185 -3800 229 -230 297 -66 65 -198 65 -466 99 -464 99 -430 67 -698 295 -132 165 -164 1095 -66 299 -66 1321 -264 12675 -66 99 -166 229 -134 65 -330 165 -164 65 -890 131 -830 67 -66 1157 -100 167 -168 265 -66 827 -66 2047 -100 261 -594 2279 -134 10701 -3890 163 -1384 67 -98 99 -1322 99 -98 65 -398 823 -66 65 -68 927 -100 495 -132 593 -100 165 -198 1387 -1022 131 -728 99 -662 97 -462 495 -200 829 -330 563 -100 297 -330 65 -598 165 -592 295 -166 131 -764 165 -164 565 -66 131 -166 165 -66 9675 -5052 165 -2878 199 -66 265 -432 265 -66 267 -898 163 -132 231 -198 229 -164 97 -100 4445 -66 7853 -636 199 -662 265 -298 233 -1428 331 -134 1791 -66 1649 -66 297 -100 361 -198 559 -98 363 -200 1315 -66 265 -98 1049 -132 1647 -66 265 -822 295 -526 131 -1712 199 -166 231 -200 165 -66 265 -166 97 -132 163 -164 395 -630 495 -168 297 -298 229 -266 629 -200 133 -132 133 -166 65 -132 99 -100 131 -66 67 -98 133 -496 1391 -98 1751 -164 359 -132 97 -164 263 -64 691 -66 199 -66 293 -98 589 -198 11299 -3968 65 -68 65 -2702 65 -1186 927 -166 65 -66 429 -134 197 -134 529 -200 67 -66 231 -100 2151 -4014 97 -1486 99 -464 65 -330 129 -330 331 -134 599 -66 497 -200 165 -66 661 -166 6881 -8830 295 -100 197 -232 725 -134 299 -166 229 -166 525 -198 295 -66 459 -66 329 -230 595 -98 299 -132 329 -66 99 -98 163 -134 229 -100 8345 -6726 131 -132 295 -66 1579 -66 329 -98 501 -132 231 -66 491 -298 331 -266 363 -132 1193 -168 8847 -4194 199 -828 65 -100 195 -262 197 -298 65 -898 65 -132 629 -66 229 -100 291 -100 623 -66 295 -66 461 -132 529 -632 597 -132 65 -100 97 -134 297 -100 297 -166 397 -168 527 -134 9603 -3850 99 -200 67 -896 959 -198 165 -100 229 -266 531 -64 165 -132 163 -296 3715 -11994 165 -1492 429 -68 263 -100 265 -330 199 -64 495 -132 363 -66 63 -166 297 -398 65 -100 231 -332 199 -100 7683 -4916 65 -1294 297 -1022 1325 -166 393 -132 165 -498 1255 -134 197 -198 427 -164 329 -132 631 -594 199 -196 99 -100 265 -134 1457 -100 3649 -8592 67 -268 131 -332 99 -100 65 -760 101 -198 297 -168 199 -132 369 -100 97 -132 99 -232 397 -198 99 -134 97 -100 231 -332 131 -796 329 -266 263 +RAW_Data: -100 10841 -4030 163 -164 197 -398 195 -592 65 -132 63 -430 295 -298 263 -200 3517 -132 3763 -12296 99 -330 361 -98 99 -200 65 -430 165 -166 2327 -100 4051 -66 9653 -3478 197 -66 163 -198 167 -66 65 -598 165 -298 131 -666 199 -198 299 -298 165 -200 565 -66 797 -98 1125 -98 825 -100 4113 -6956 65 -5536 165 -266 99 -232 461 -198 65 -200 1989 -66 295 -66 723 -66 65 -98 329 -98 955 -66 559 -232 331 -66 10851 -1048 65 -3748 65 -498 99 -1392 99 -794 529 -98 331 -98 397 -164 363 -394 331 -266 299 -230 165 -66 3001 -568 197 -2872 2579 -468 2637 -472 2599 -488 2647 -426 2653 -448 2665 -392 379 -2734 381 -2700 2691 -388 377 -2732 2669 -420 355 -2726 2687 -394 403 -2706 2687 -388 377 -21248 2717 -388 377 -2738 2659 -408 2703 -382 2689 -416 2679 -408 2701 -382 2687 -418 365 -2736 365 -2722 2689 -384 391 -2696 2707 -386 379 -2734 2665 -410 361 -2726 2703 -418 357 -21246 2679 -466 297 -2768 2657 -448 2627 -434 2669 -450 2653 -416 2673 -408 2697 -386 383 -2728 369 -2706 2701 -382 387 -2726 2687 -418 357 -2708 2693 -418 361 -2702 2709 -396 401 -21232 2689 -406 361 -2736 2695 -386 2695 -406 2695 -382 2687 -418 2675 -410 2693 -414 375 -2692 389 -2706 2701 -404 363 -2724 2695 -388 389 -2702 2719 -358 405 -2704 2701 -402 363 -21262 2677 -414 367 -2738 2677 -386 2693 -420 2701 -400 2677 -386 2695 -420 2669 -430 369 -2718 353 -2730 2673 -412 361 -2734 2691 -420 357 -2698 2701 -394 401 -2702 2687 -424 347 -21244 2701 -418 365 -2726 2703 -382 2697 -420 2675 -400 2685 -384 2721 -398 2667 -418 355 -2744 343 -2722 2703 -420 353 -2724 2689 -396 363 -2736 2687 -390 377 -2730 2697 -386 357 -21274 2683 -414 375 -2726 2667 -420 2703 -398 2677 -388 2695 -420 2699 -398 2671 -384 415 -2698 357 -2738 2695 -382 383 -2724 2685 -416 357 -2706 2707 -384 391 -2726 2671 -384 415 -21238 2651 -476 293 -2776 2653 -462 2641 -446 2661 -422 2663 -418 2689 -412 2683 -414 357 -2706 385 -2698 2715 -378 379 -2710 2719 -388 377 -2708 2695 -406 361 -2724 2689 -416 361 -21244 2703 -386 413 -2698 2697 -414 2689 -384 2685 -386 2719 -378 2701 -416 2689 -386 377 -2728 387 -2700 2673 -410 361 -2730 2695 -420 357 -2732 2679 -386 377 -2734 2699 -378 361 -21262 2697 -392 405 -2702 2687 -406 2703 -382 2703 -418 2671 -406 2677 -416 2695 -386 387 -2700 381 -2704 2695 -418 357 -2712 2721 -388 375 -2702 2693 -408 363 -2730 2693 -420 355 -21248 2653 -494 289 -91206 131 -132 97 -232 559 -132 591 -98 691 -66 131 -130 297 -66 231 -66 331 -66 433 -100 499 -132 231 -166 197 -134 593 -100 11707 -4456 133 -200 131 +RAW_Data: -66 133 -66 97 -166 561 -100 895 -132 1323 -66 10873 -3752 99 -722 229 -394 97 -66 99 -98 99 -328 297 -328 265 -298 3089 -132 10573 -1460 133 -432 99 -232 99 -132 333 -232 731 -164 65 -166 165 -132 131 -330 65 -98 131 -596 65 -198 133 -98 397 -568 65 -132 1157 -166 195 -130 131 -64 99 -66 63 -198 265 -98 297 -66 63 -166 295 -100 1747 -232 6099 -11348 199 -528 297 -266 97 -598 99 -198 231 -64 4433 -334 65 -298 65 -3284 67 -530 97 -432 133 -2356 493 -68 231 -168 297 -266 427 -100 559 -98 229 -460 197 -66 261 -132 65 -98 565 -132 231 -66 497 -100 3491 -12356 65 -660 197 -198 165 -132 331 -134 65 -98 2651 -134 4531 -10850 65 -1322 263 -68 431 -232 165 -134 165 -202 231 -300 5625 -66 6951 -8162 65 -398 99 -596 65 -132 461 -598 429 -132 97 -132 463 -232 229 -98 329 -100 397 -100 363 -100 231 -200 163 -200 961 -66 693 -100 397 -134 10601 -3872 263 -100 165 -100 131 -198 99 -696 233 -1524 331 -132 131 -164 229 -132 493 -98 631 -134 231 -100 595 -66 295 -66 5965 -8248 99 -296 99 -98 397 -66 65 -924 229 -398 299 -98 1425 -130 565 -198 827 -262 429 -598 725 -704 729 -12290 131 -98 99 -98 65 -100 163 -164 65 -494 231 -100 97 -100 863 -66 1751 -3948 165 -100 195 -66 165 -296 65 -2042 99 -200 495 -132 557 -100 827 -98 167 -66 433 -100 661 -164 689 -98 10803 -3906 231 -296 295 -232 99 -234 131 -332 395 -266 1283 -164 755 -466 397 -164 335 -66 1355 -14376 557 -66 331 -68 431 -134 599 -364 229 -100 763 -98 265 -132 525 -166 99 -396 495 -98 3867 -134 595 -168 865 -166 503 -200 467 -134 8145 -458 235 -794 599 -458 265 -436 231 -426 333 -368 299 -730 689 -360 327 -370 363 -326 367 -668 733 -328 363 -302 397 -328 371 -296 393 -666 725 -622 795 -634 433 -264 1023 -228 5041 -762 585 -466 233 -826 235 -470 631 -368 299 -402 299 -726 361 -328 331 -370 363 -332 701 -298 401 -692 369 -302 759 -268 461 -236 435 -622 423 -260 465 -266 719 -13608 65 -624 197 -558 921 -164 1315 -134 465 -134 263 -100 295 -132 293 -66 329 -98 197 -132 9977 -5036 197 -798 333 -828 295 -100 197 -100 165 -66 665 -100 763 -300 297 -166 165 -98 823 -8348 229 -100 427 -196 263 -624 197 -134 797 -100 263 -68 529 -132 233 -134 165 -264 131 -132 559 -66 263 -228 927 -132 731 -102 1061 -66 863 -8206 131 -332 299 -166 461 -100 99 -66 429 -66 3271 -98 465 -100 401 -232 331 -66 397 -430 10341 +RAW_Data: -5434 65 -298 133 -132 131 -68 231 -200 661 -132 9517 -424 97 -1456 99 -1694 393 -100 131 -560 131 -196 197 -298 65 -428 229 -196 297 -266 131 -166 2435 -66 10161 -11230 65 -1320 131 -298 265 -532 231 -200 1291 -68 631 -66 12645 -4048 133 -66 67 -132 167 -266 163 -66 397 -132 197 -132 299 -98 197 -198 2903 -66 2361 -66 9627 -3588 197 -332 165 -68 331 -68 197 -132 99 -100 663 -66 363 -230 231 -166 131 -100 201 -298 163 -132 133 -202 363 -300 397 -102 263 -100 165 -66 1221 -66 1479 -132 165 -98 229 -12976 263 -66 363 -134 231 -66 629 -132 327 -100 97 -130 99 -164 227 -64 297 -132 397 -164 425 -198 97 -198 99 -66 365 -164 199 -102 97 -66 1817 -13524 231 -134 16907 -4086 233 -630 65 -396 201 -66 165 -198 67 -198 99 -664 2117 -166 12473 -446 2649 -440 2661 -420 2651 -422 2681 -418 2703 -400 365 -2724 387 -2696 2695 -414 357 -2704 2707 -386 389 -2700 2687 -392 405 -2706 2695 -402 363 -21268 2707 -388 377 -2706 2691 -404 2699 -382 2717 -382 2707 -378 2693 -416 2687 -396 363 -2736 355 -2748 2659 -416 365 -2708 2715 -388 377 -2708 2697 -404 363 -2730 2673 -420 355 -21268 2655 -460 319 -2766 2663 -448 2631 -436 2665 -418 2683 -410 2681 -416 2701 -386 383 -2700 375 -2744 2669 -416 353 -2730 2685 -416 357 -2708 2721 -380 369 -2724 2697 -382 385 -21260 2701 -418 353 -2720 2673 -418 2675 -408 2693 -384 2715 -386 2717 -386 2691 -404 363 -2732 387 -2702 2669 -412 359 -2736 2699 -380 381 -2728 2675 -416 381 -2720 2675 -414 347 -21280 2685 -390 377 -2724 2689 -416 2673 -408 2705 -382 2695 -410 2689 -414 2661 -418 385 -2704 369 -2704 2693 -416 375 -2726 2661 -420 355 -2728 2711 -388 375 -2702 2691 -410 363 -21252 2659 -488 287 -2794 2651 -448 2629 -436 2671 -416 2695 -416 2663 -406 2699 -384 383 -2730 367 -2702 2695 -418 385 -2702 2685 -412 349 -2744 2693 -366 389 -2714 2693 -394 381 -21266 2685 -418 363 -2730 2683 -382 2693 -418 2675 -410 2699 -384 2719 -382 2707 -380 359 -2734 387 -2704 2709 -380 361 -2732 2699 -418 357 -2728 2667 -416 383 -2696 2709 -380 391 -21228 2685 -458 307 -2800 2647 -412 2659 -432 2667 -416 2695 -416 2675 -406 2675 -416 383 -2700 361 -2730 2687 -414 375 -2696 2701 -420 353 -2720 2711 -382 367 -2728 2675 -416 385 -21222 2735 -386 355 -2744 2687 -396 2679 -418 2701 -386 2705 -382 2681 -410 2697 -384 385 -2736 365 -2704 2715 -384 377 -2696 2697 -416 349 -2722 2707 -386 379 -2732 2671 -410 361 -21258 2681 -464 297 -2796 2629 -456 2655 -420 2661 -448 2663 -404 2695 -382 2715 -380 371 -2740 355 -2744 2679 -384 391 -2728 2675 -388 379 +RAW_Data: -2728 2695 -414 357 -2704 2705 -418 357 -21262 2673 -416 383 -2696 2709 -380 2703 -384 2699 -418 2671 -408 2695 -382 2713 -386 379 -2730 357 -2732 2695 -384 383 -2730 2679 -416 357 -2708 2701 -410 349 -2736 2697 -382 385 -21252 2669 -478 289 -2790 2647 -426 2651 -444 2653 -430 2659 -418 2695 -414 2681 -402 349 -2738 383 -2722 2677 -414 347 -2744 2691 -382 369 -2730 2691 -384 383 -2734 2679 -414 347 -21264 2705 -386 379 -2736 2667 -410 2695 -382 2715 -380 2709 -420 2665 -392 2713 -382 383 -2730 365 -2728 2665 -418 383 -2696 2693 -418 357 -2710 2711 -380 375 -2718 2701 -416 357 -21238 2677 -484 311 -2766 2635 -444 2657 -420 2663 -422 2695 -416 2667 -428 2675 -396 363 -73890 133 -98 131 -132 129 -658 99 -66 853 -100 63 -100 361 -98 1589 -66 1231 -132 65 -100 297 -198 65 -132 265 -66 9857 -4672 165 -1030 97 -1394 65 -200 2687 -68 6873 -8336 99 -1156 97 -66 163 -232 163 -262 197 -132 295 -132 263 -166 953 -100 263 -130 393 -164 295 -64 329 -66 393 -164 823 -130 165 -66 6133 -8436 165 -164 265 -266 65 -362 197 -696 3181 -132 363 -98 65 -166 131 -66 399 -132 663 -396 329 -66 7335 -7578 497 -230 627 -264 99 -366 99 -132 131 -134 265 -498 163 -100 1323 -66 265 -66 1129 -100 399 -132 365 -100 795 -68 397 -98 597 -364 297 -132 361 -132 265 -132 8591 -4740 65 -100 131 -166 199 -1088 97 -296 99 -528 131 -98 661 -66 401 -198 1157 -166 361 -164 495 -100 165 -66 297 -100 1423 -66 3067 -5658 67 -6406 197 -1092 65 -530 659 -68 265 -100 991 -68 231 -230 297 -66 327 -66 131 -132 659 -134 131 -100 1183 -132 263 -98 621 -66 2075 -6976 65 -5138 67 -132 129 -664 67 -132 165 -100 331 -466 231 -68 467 -98 563 -66 231 -100 531 -66 465 -66 1023 -166 297 -134 3409 -12290 67 -164 99 -532 133 -166 263 -66 231 -66 721 -64 131 -68 959 -134 495 -100 299 -98 497 -98 365 -100 397 -232 297 -98 531 -66 3029 -12216 265 -132 99 -364 199 -234 131 -66 431 -166 333 -166 397 -132 327 -100 395 -66 197 -132 395 -66 527 -98 295 -100 97 -98 789 -132 363 -132 297 -200 2815 -4914 65 -6620 65 -462 65 -134 297 -66 497 -264 231 -198 2773 -134 365 -100 831 -166 131 -100 297 -132 861 -132 299 -100 561 -66 1381 -6946 65 -5516 231 -266 97 -1362 1093 -68 1621 -134 165 -332 297 -98 361 -228 97 -132 797 -98 3487 -13224 229 -164 65 -132 913 -66 1123 -98 527 -134 929 -98 723 -100 12259 -270 165 -132 67 -132 165 -1326 99 -98 65 -1194 431 -66 695 -66 733 -134 197 +RAW_Data: -134 10801 -166 67 -6130 133 -198 231 -334 365 -98 229 -132 165 -68 231 -166 14501 -524 65 -328 131 -498 129 -1288 65 -494 163 -64 165 -66 527 -132 131 -132 1019 -198 129 -166 393 -198 65 -164 6411 -66 3255 -10642 65 -1320 165 -164 493 -492 559 -264 2555 -66 695 -66 1657 -164 855 -66 4001 -10526 97 -596 133 -298 67 -264 65 -300 65 -100 263 -166 231 -134 99 -100 2703 -68 13643 -4922 297 -100 65 -232 133 -198 331 -300 231 -66 331 -100 12047 -3872 97 -196 65 -494 329 -66 65 -890 97 -98 229 -164 195 -596 797 -66 861 -132 65 -66 231 -100 565 -66 65 -66 1297 -132 265 -66 363 -134 265 -364 297 -164 299 -134 297 -134 495 -98 11309 -3790 131 -1380 65 -758 65 -164 129 -460 65 -360 199 -100 563 -68 497 -198 363 -266 263 -100 165 -66 697 -66 1933 -13594 65 -762 1223 -132 1119 -196 361 -134 131 -100 793 -166 695 -68 231 -68 463 -66 11727 -4204 363 -264 131 -132 133 -1124 97 -100 163 -100 327 -100 331 -198 397 -66 397 -100 395 -100 163 -66 197 -564 1059 -7962 65 -100 65 -198 129 -362 99 -394 197 -296 495 -100 1357 -68 459 -66 593 -66 265 -68 301 -132 465 -66 231 -200 397 -66 397 -232 199 -298 12077 -4350 231 -796 363 -198 133 -264 65 -1132 597 -332 3295 -100 755 -98 231 -164 97 -264 459 -166 759 -164 3265 -12138 99 -232 99 -1228 1025 -100 393 -66 531 -132 693 -132 1063 -66 427 -64 297 -294 229 -98 9723 -5404 67 -466 99 -796 267 -98 201 -100 167 -264 461 -98 1415 -66 861 -66 267 -66 331 -134 1663 -66 2089 -7012 65 -100 101 -4804 431 -728 99 -100 65 -100 995 -134 165 -66 929 -100 65 -66 927 -100 1093 -168 99 -100 497 -66 665 -200 6517 -8312 165 -66 129 -66 559 -166 99 -430 65 -398 67 -66 593 -198 459 -132 261 -132 263 -130 723 -66 459 -100 325 -166 67 -198 559 -66 493 -66 11475 -3896 99 -266 99 -66 197 -1092 129 -198 361 -166 163 -98 263 -196 759 -100 265 -100 365 -630 4635 -12748 65 -1712 461 -100 497 -66 395 -98 265 -98 229 -164 529 -132 297 -66 565 -132 987 -132 8665 -2820 2265 -450 313 -2774 2643 -442 325 -2772 2665 -416 359 -2734 2667 -386 379 -21274 2657 -474 293 -2810 2619 -466 2613 -476 2629 -452 2663 -388 2683 -418 2705 -400 365 -2722 387 -2700 2697 -380 361 -2732 2691 -418 361 -2732 2667 -416 383 -2698 2697 -416 357 -21238 2715 -384 383 -2732 2685 -416 2667 -416 2695 -398 2671 -418 2687 -390 2713 -382 383 -2730 365 -2728 2661 -416 379 -2716 2685 -384 379 -2720 2703 -378 401 -2718 2671 +RAW_Data: 889 -130 325 -64 457 -560 165 -68 199 -170 67 -66 265 -132 133 -666 67 -166 431 -66 201 -98 297 -100 595 -66 199 -134 65 -100 795 -132 99 -168 501 -200 331 -132 265 -102 265 -134 423 -98 521 -226 65 -166 431 -134 99 -100 133 -464 195 -326 623 -100 673 -98 321 -200 65 -136 369 -166 65 -68 97 -166 165 -334 265 -102 231 -166 101 -170 65 -170 265 -136 931 -100 133 -134 563 -66 333 -100 427 -66 163 -390 231 -66 193 -130 461 -166 557 -100 99 -198 263 -100 197 -294 231 -232 299 -134 199 -170 267 -134 631 -98 235 -100 499 -68 463 -100 65 -134 335 -170 273 -134 297 -100 67 -66 197 -166 67 -134 301 -168 537 -470 99 -134 433 -132 199 -192 261 -100 523 -164 459 -132 259 -332 359 -64 227 -96 131 -132 687 -132 363 -136 329 -434 99 -334 133 -100 401 -132 233 -700 233 -170 337 -66 371 -68 233 -202 531 -266 731 -66 465 -100 167 -100 133 -232 335 -166 239 -102 367 -232 231 -100 167 -134 201 -136 301 -168 199 -300 231 -98 237 -134 233 -102 329 -132 261 -134 199 -66 265 -136 99 -170 167 -134 199 -166 167 -136 367 -298 197 -200 99 -166 469 -136 439 -66 303 -134 295 -100 433 -134 899 -266 363 -132 197 -160 555 -324 129 -96 97 -128 257 -132 97 -394 257 -98 195 -166 459 -332 395 -132 633 -134 301 -100 131 -332 169 -168 395 -166 263 -540 783 -100 287 -130 295 -96 225 -296 133 -98 99 -100 461 -164 545 -130 99 -66 301 -68 265 -100 235 -134 235 -70 333 -102 497 -66 233 -364 301 -170 103 -66 165 -336 733 -200 133 -100 263 -102 65 -136 465 -200 1035 -198 165 -170 67 -302 631 -100 429 -332 65 -128 129 -130 159 -128 159 -66 161 -96 325 -164 261 -100 197 -162 65 -96 99 -130 65 -102 333 -100 199 -98 389 -330 129 -128 229 -66 425 -366 229 -64 261 -100 227 -96 227 -526 301 -200 97 -66 699 -334 67 -100 399 -198 787 -98 297 -134 429 -100 3245 -64 527 -98 131 -526 633 -68 133 -302 1459 -164 971 -102 237 -136 1439 -266 1131 -66 599 -200 303 -332 325 -130 389 -166 371 -66 333 -102 65 -100 233 -234 327 -266 233 -166 297 -100 225 -130 163 -336 99 -596 199 -330 131 -66 331 -338 263 -358 197 -168 877 -66 227 -96 63 -130 263 -162 225 -290 197 -198 357 -132 297 -262 165 -456 227 -98 399 -296 95 -132 99 -98 457 -200 199 -168 535 -100 567 -134 327 -130 193 -130 683 -102 101 -132 233 -170 943 -166 827 -66 267 -102 503 -68 1325 -164 +RAW_Data: 1607 -68 233 -166 1167 -70 531 -134 335 -168 131 -66 299 -402 899 -66 461 -66 457 -98 953 -98 165 -66 293 -230 881 -64 393 -166 589 -66 289 -66 1093 -204 333 -98 2745 -132 2019 -170 925 -68 269 -102 1469 -136 2301 -68 1355 -100 527 -66 975 -68 1445 -98 2397 -100 1733 -66 703 -100 995 -100 135 -136 235 -202 167 -134 2071 -166 339 -170 201 -268 129 -66 465 -66 365 -100 197 -164 129 -98 161 -96 423 -66 675 -66 1543 -136 567 -200 767 -202 65 -100 1401 -66 623 -136 567 -234 67 -236 197 -194 97 -66 263 -66 1827 -392 1893 -98 165 -268 133 -132 231 -162 225 -98 695 -198 563 -100 301 -332 267 -102 341 -66 99 -132 1299 -130 525 -68 161 -96 357 -98 353 -100 131 -100 131 -98 163 -132 323 -100 535 -66 1323 -130 133 -66 235 -134 1497 -132 387 -98 129 -162 2623 -134 163 -68 167 -66 959 -232 495 -68 131 -134 867 -134 865 -66 333 -98 305 -134 231 -98 765 -198 397 -432 165 -66 165 -366 265 -102 541 -100 261 -162 331 -134 457 -66 491 -196 97 -266 193 -262 65 -166 231 -266 497 -360 263 -98 587 -164 259 -98 231 -66 359 -100 267 -102 271 -168 97 -262 63 -66 261 -130 227 -130 295 -164 65 -66 265 -200 597 -134 267 -170 603 -100 97 -466 231 -264 97 -168 99 -66 65 -200 199 -100 267 -404 303 -102 201 -204 235 -134 131 -198 335 -298 327 -130 291 -164 63 -162 295 -262 197 -130 95 -130 195 -96 159 -130 161 -66 231 -100 165 -66 199 -134 363 -66 267 -168 165 -168 167 -100 165 -530 363 -432 99 -232 65 -132 395 -328 229 -98 197 -132 161 -96 191 -292 197 -204 133 -100 399 -166 531 -332 235 -168 99 -66 325 -158 553 -132 129 -226 231 -134 99 -462 129 -64 289 -100 193 -66 355 -164 291 -198 131 -298 197 -198 373 -268 335 -234 427 -68 199 -132 267 -232 131 -66 783 -326 63 -162 161 -130 227 -66 259 -562 233 -464 303 -102 201 -334 301 -134 297 -198 229 -66 127 -166 99 -100 197 -198 571 -66 457 -134 361 -424 131 -328 163 -98 63 -100 505 -102 201 -1094 229 -164 65 -230 789 -236 2505 -166 201 -170 163 -64 1139 -66 927 -100 295 -198 723 -100 365 -66 459 -196 3033 -272 199 -66 499 -202 1319 -232 295 -298 131 -362 97 -164 129 -132 65 -98 197 -130 129 -98 261 -130 97 -98 229 -96 425 -66 227 -166 483 -66 163 -326 567 -68 235 -68 67 -66 167 -66 235 -330 425 -164 63 -66 427 -102 167 -66 669 -132 429 -200 65 -102 133 -100 197 -368 +RAW_Data: 65 -134 2481 -228 65 -130 229 -228 763 -136 603 -166 1619 -98 1763 -102 837 -166 321 -66 951 -130 2067 -66 259 -132 1835 -66 437 -102 701 -66 565 -68 363 -70 1113 -66 1989 -164 257 -128 351 -162 1055 -232 265 -170 309 -200 435 -166 833 -102 2467 -132 595 -66 773 -166 1615 -98 131 -96 485 -64 517 -166 197 -68 1231 -68 403 -100 263 -134 233 -100 503 -100 333 -266 729 -66 199 -100 369 -68 1239 -100 197 -68 299 -170 337 -100 825 -132 163 -66 4205 -64 161 -100 635 -66 907 -66 1017 -166 1709 -100 201 -266 657 -68 463 -166 331 -164 293 -64 259 -162 129 -262 597 -134 701 -136 67 -168 235 -136 303 -170 1417 -66 263 -98 857 -100 659 -166 97 -100 2497 -64 2495 -98 719 -128 227 -130 2217 -164 623 -264 719 -134 329 -98 1371 -100 553 -294 165 -66 1163 -100 329 -196 649 -200 1123 -68 263 -100 593 -266 333 -102 1133 -136 131 -132 603 -200 1819 -66 489 -66 563 -266 1113 -230 165 -66 423 -68 335 -100 101 -100 1073 -132 897 -100 101 -100 499 -134 173 -138 763 -238 371 -130 403 -166 203 -102 271 -136 269 -166 99 -168 263 -96 425 -66 331 -234 133 -400 231 -132 453 -66 459 -164 199 -68 237 -132 163 -198 161 -196 265 -132 65 -64 195 -130 357 -164 663 -68 167 -600 131 -98 133 -304 203 -134 433 -98 261 -130 199 -100 237 -100 229 -326 99 -98 331 -132 99 -294 165 -66 303 -134 99 -232 133 -136 99 -68 267 -198 233 -138 67 -166 367 -100 333 -168 267 -200 369 -266 135 -404 1939 -132 231 -160 161 -64 293 -98 331 -132 339 -104 135 -100 197 -430 263 -202 233 -64 195 -162 129 -64 227 -298 265 -68 697 -66 301 -68 231 -300 131 -368 769 -234 265 -98 195 -324 97 -752 229 -126 355 -98 257 -98 287 -64 427 -132 295 -262 197 -170 369 -102 267 -100 169 -68 201 -102 2551 -136 635 -134 639 -134 99 -132 197 -200 371 -66 731 -132 199 -138 733 -304 433 -68 729 -440 197 -68 99 -102 165 -266 261 -164 491 -296 489 -194 257 -164 133 -134 237 -68 335 -98 227 -130 229 -98 295 -98 231 -202 267 -236 233 -136 331 -130 195 -128 261 -430 261 -162 97 -224 99 -130 193 -96 197 -162 229 -396 97 -98 227 -364 267 -100 99 -100 233 -236 697 -164 227 -196 63 -98 327 -230 325 -66 129 -196 95 -98 195 -130 325 -430 131 -194 129 -454 161 -196 235 -68 433 -134 667 -164 355 -236 101 -98 2143 -134 1827 -198 63 -198 65 -64 2859 -64 619 -66 97 -130 3157 -66 679 -194 1491 -98 +RAW_Data: 951 -64 393 -100 955 -132 4715 -100 131 -66 199 -204 1541 -66 929 -130 1347 -166 665 -132 233 -132 67 -102 433 -100 595 -228 997 -66 505 -68 133 -98 231 -68 571 -134 1371 -232 231 -270 135 -102 97 -66 867 -100 269 -68 967 -100 1649 -66 65 -66 951 -68 65 -202 363 -200 779 -102 1449 -294 419 -130 361 -230 1079 -164 163 -260 893 -102 333 -100 533 -166 467 -100 135 -66 135 -202 369 -100 199 -100 269 -134 301 -166 229 -66 101 -134 199 -134 1293 -64 779 -62 831 -66 1243 -68 267 -102 197 -100 395 -98 455 -64 621 -132 877 -98 199 -100 2101 -134 503 -100 2035 -134 735 -236 475 -136 237 -132 133 -134 1229 -100 133 -66 167 -68 2655 -100 1807 -100 1095 -264 825 -98 163 -66 491 -98 161 -128 953 -100 773 -100 131 -66 67 -134 457 -130 63 -64 389 -98 715 -66 425 -300 97 -100 1515 -66 303 -68 99 -98 721 -64 887 -132 65 -132 165 -66 635 -68 2801 -66 1561 -100 751 -98 129 -64 725 -136 201 -100 333 -204 573 -104 1745 -134 99 -66 129 -64 595 -134 167 -102 337 -134 567 -134 1131 -138 1207 -100 269 -68 135 -100 1143 -134 2139 -68 1701 -162 991 -596 431 -66 99 -132 657 -66 391 -320 357 -260 259 -98 429 -66 163 -228 65 -130 227 -66 261 -166 99 -98 131 -366 199 -134 463 -102 201 -98 231 -102 639 -238 301 -568 169 -610 265 -102 841 -198 297 -100 335 -132 263 -266 265 -68 469 -134 267 -68 933 -298 333 -298 729 -168 135 -136 437 -132 1137 -134 199 -68 265 -132 463 -166 129 -130 227 -98 297 -98 65 -132 97 -202 199 -232 305 -66 165 -198 365 -66 99 -98 299 -170 65 -136 301 -232 99 -564 133 -132 233 -170 99 -102 131 -134 65 -204 101 -98 297 -98 167 -762 233 -298 99 -326 395 -66 299 -132 369 -504 333 -98 483 -200 457 -164 63 -164 329 -162 65 -622 231 -268 131 -132 133 -134 131 -134 131 -66 99 -100 231 -66 167 -336 165 -98 197 -100 97 -264 321 -98 521 -132 163 -130 129 -294 297 -134 101 -102 265 -168 497 -68 197 -68 499 -134 269 -398 267 -130 203 -302 65 -498 271 -136 465 -292 131 -294 163 -198 329 -96 129 -98 193 -130 391 -330 165 -134 167 -170 297 -102 133 -136 135 -366 199 -132 423 -132 395 -168 65 -166 401 -98 229 -98 329 -98 99 -130 129 -228 261 -160 127 -426 389 -162 193 -132 131 -100 231 -168 67 -304 201 -68 765 -132 161 -162 193 -64 195 -64 295 -130 787 -98 419 -528 429 -66 363 -134 131 -100 133 -200 331 -98 +RAW_Data: 431 -66 1167 -68 937 -68 1003 -66 99 -132 941 -134 65 -66 365 -274 165 -236 367 -96 557 -134 675 -66 261 -164 127 -96 391 -164 161 -98 391 -292 163 -98 519 -196 165 -98 523 -66 195 -160 3343 -66 661 -100 2589 -136 307 -100 629 -136 639 -100 133 -168 405 -100 267 -66 465 -132 1171 -64 749 -64 165 -98 983 -100 163 -202 537 -66 327 -100 669 -100 401 -236 2885 -164 439 -134 97 -426 1931 -66 1385 -98 715 -98 519 -66 289 -162 97 -360 297 -166 163 -66 289 -66 555 -334 167 -230 429 -102 267 -132 943 -136 401 -68 929 -130 193 -68 467 -198 335 -66 963 -100 597 -132 197 -260 523 -232 1115 -102 1935 -66 1395 -134 305 -100 99 -66 199 -66 1071 -66 2357 -66 367 -498 769 -234 163 -130 191 -64 1211 -200 133 -102 201 -100 561 -366 361 -98 195 -100 537 -64 165 -196 1041 -332 133 -102 441 -230 4217 -66 1033 -66 167 -66 933 -100 565 -66 331 -164 673 -104 441 -66 533 -66 2095 -164 525 -66 297 -170 965 -198 421 -100 663 -832 65 -100 331 -164 231 -166 135 -168 237 -466 761 -134 891 -196 791 -198 257 -160 161 -98 293 -66 1081 -98 229 -130 327 -66 1301 -200 331 -166 101 -66 461 -100 2619 -132 1663 -98 1609 -134 499 -332 165 -370 67 -264 97 -96 259 -98 701 -402 197 -128 527 -236 233 -102 167 -134 303 -134 99 -166 299 -132 165 -200 467 -68 305 -168 207 -102 465 -102 729 -136 101 -374 327 -96 259 -98 467 -202 65 -66 673 -98 335 -404 135 -66 339 -204 99 -366 233 -68 365 -166 133 -102 867 -198 163 -162 163 -294 463 -332 165 -68 269 -268 331 -100 131 -166 299 -132 231 -400 263 -164 131 -266 267 -264 367 -66 371 -134 229 -104 267 -232 67 -466 265 -100 101 -100 165 -200 65 -200 301 -66 199 -168 233 -98 267 -66 67 -134 261 -196 261 -234 427 -294 65 -194 193 -66 259 -132 849 -96 63 -198 167 -294 95 -98 361 -164 261 -196 131 -132 437 -100 597 -262 327 -162 295 -98 295 -164 259 -196 425 -230 321 -66 195 -66 261 -496 99 -200 529 -132 133 -966 133 -132 165 -66 63 -128 491 -402 65 -262 299 -66 299 -202 265 -100 99 -668 97 -134 65 -100 101 -66 65 -266 691 -66 431 -166 167 -134 199 -370 899 -134 99 -100 1093 -166 163 -166 399 -98 327 -100 99 -168 135 -200 133 -202 429 -98 65 -98 197 -556 65 -66 97 -326 331 -166 333 -200 135 -100 235 -234 265 -98 65 -68 135 -66 335 -66 133 -298 99 -66 233 -164 435 -232 97 -132 97 -392 +RAW_Data: 99 -198 819 -66 1235 -98 321 -132 1091 -66 1307 -98 3059 -164 3305 -64 227 -98 591 -98 129 -66 229 -98 2143 -98 939 -68 563 -100 361 -232 945 -164 257 -96 229 -230 387 -64 195 -130 981 -294 587 -162 193 -98 1337 -66 293 -98 2665 -66 297 -98 647 -66 459 -132 491 -164 489 -96 595 -66 899 -66 837 -64 1151 -196 259 -98 357 -164 891 -132 1359 -134 197 -98 97 -98 261 -64 229 -96 461 -136 693 -100 201 -98 865 -66 599 -100 517 -132 709 -66 293 -298 655 -66 197 -130 129 -66 197 -98 4291 -66 673 -66 667 -132 1473 -132 133 -104 99 -66 163 -168 333 -134 1743 -132 1097 -132 99 -68 167 -602 1323 -352 99 -166 753 -98 423 -98 97 -66 1317 -228 1309 -98 1849 -66 1939 -132 601 -100 665 -100 1875 -66 695 -132 425 -66 425 -66 263 -134 165 -134 99 -98 829 -66 601 -166 131 -102 565 -66 301 -100 1099 -100 601 -138 533 -66 667 -234 561 -66 99 -68 2741 -98 199 -100 531 -168 101 -434 1027 -68 431 -66 403 -132 99 -98 565 -132 135 -100 399 -166 271 -236 233 -166 197 -366 99 -66 99 -168 503 -66 199 -170 207 -100 673 -368 99 -66 263 -168 133 -98 397 -268 337 -66 131 -132 231 -132 501 -134 99 -168 567 -138 103 -136 267 -298 231 -134 197 -160 321 -332 231 -98 131 -164 257 -64 163 -328 395 -66 331 -202 65 -168 133 -68 167 -100 233 -102 335 -66 197 -326 1101 -132 589 -100 811 -132 399 -136 269 -102 497 -66 559 -100 129 -98 855 -68 637 -102 65 -200 875 -68 233 -166 167 -66 529 -202 235 -102 231 -66 1237 -66 733 -98 1723 -132 101 -100 297 -66 829 -232 197 -100 367 -134 169 -166 167 -434 633 -100 235 -200 131 -134 233 -100 131 -100 331 -134 495 -432 65 -528 161 -130 295 -132 337 -136 133 -166 165 -100 269 -240 201 -336 133 -166 165 -238 199 -202 431 -434 99 -134 501 -166 231 -96 559 -202 167 -66 717 -98 987 -198 65 -64 163 -64 227 -98 555 -164 199 -64 361 -66 163 -98 129 -162 97 -130 161 -460 197 -230 681 -98 197 -98 329 -100 267 -266 291 -264 65 -100 329 -100 459 -200 363 -98 165 -134 231 -134 301 -134 231 -302 99 -132 101 -134 267 -136 233 -68 393 -422 163 -166 361 -166 99 -134 365 -134 133 -336 401 -66 495 -132 401 -168 133 -402 501 -136 1093 -862 165 -132 293 -300 289 -66 131 -164 391 -134 99 -360 359 -130 323 -200 423 -98 195 -162 295 -132 161 -98 129 -782 131 -426 227 -64 259 -166 63 -160 323 -98 261 -230 +RAW_Data: 231 -66 921 -66 355 -64 1019 -98 227 -258 163 -66 597 -232 1313 -132 163 -404 467 -236 901 -164 483 -98 195 -96 489 -134 103 -238 169 -66 67 -68 299 -100 497 -68 65 -134 1635 -304 1153 -100 539 -168 265 -200 499 -166 535 -100 397 -168 931 -100 131 -66 631 -134 897 -270 1233 -100 65 -132 131 -334 663 -66 163 -66 131 -132 705 -98 571 -200 433 -100 237 -234 229 -132 1627 -66 569 -100 715 -66 1863 -272 265 -68 301 -98 465 -68 97 -134 99 -66 395 -136 1405 -66 529 -132 63 -196 579 -132 413 -260 129 -136 101 -166 1201 -134 833 -134 393 -66 335 -172 201 -68 1027 -96 753 -64 815 -66 97 -64 1341 -132 289 -160 127 -66 99 -228 1083 -96 163 -66 259 -64 159 -98 2409 -168 767 -200 367 -66 1675 -66 1067 -98 3407 -200 99 -66 1403 -166 99 -134 439 -200 329 -136 599 -66 637 -66 835 -66 1099 -98 99 -66 463 -166 165 -100 461 -164 3037 -66 655 -66 97 -98 229 -130 355 -132 1443 -66 527 -98 881 -98 229 -162 127 -96 583 -64 65 -162 489 -166 885 -194 257 -98 1539 -66 293 -166 229 -132 655 -98 757 -49522 271 -758 689 -1264 737 -670 293 -1152 811 -1144 341 -664 773 -678 327 -1118 807 -1144 835 -1146 781 -1126 873 -1096 347 -622 877 -624 321 -1106 843 -1098 871 -1098 843 -1106 379 -610 841 -584 381 -1122 365 -602 845 -1116 837 -610 381 -1056 889 -1078 383 -614 827 -1110 877 -592 353 -1108 845 -1120 839 -1120 347 -602 849 -1110 865 -612 361 -1072 869 -1114 351 -618 861 -618 343 -1090 853 -1106 387 -618 797 -674 347 -1084 389 -574 867 -584 381 -1114 841 -1102 845 -1116 839 -1112 843 -1098 875 -1086 383 -584 865 -588 375 -1100 861 -1112 851 -1084 853 -1108 847 -1106 381 -584 857 -610 383 -1080 357 -602 871 -602 385 -1084 383 -616 823 -610 373 -1086 381 -590 871 -1084 839 -628 353 -1102 875 -1100 349 -9404 875 -1060 871 -1086 887 -1088 879 -1058 863 -1086 855 -1132 845 -1078 871 -1076 857 -1098 881 -1082 861 -1088 843 -1120 853 -1074 879 -1074 879 -1068 889 -614 341 -1090 387 -616 863 -624 345 -1088 391 -590 857 -612 385 -1058 393 -596 843 -1088 889 -1078 879 -578 387 -1082 875 -1076 415 -550 881 -1070 877 -592 391 -1114 821 -1104 373 -620 821 -624 361 -1072 903 -1086 855 -1092 843 -1086 905 -1054 387 -614 863 -618 347 -1088 853 -1114 845 -1090 867 -1070 381 -610 885 -584 385 -1052 407 -578 877 -1052 899 -600 389 -1048 907 -1074 383 -586 877 -1072 877 -594 359 -1076 875 -1082 891 -1088 363 -616 855 -1084 857 -592 381 -1088 883 -1086 385 -572 +RAW_Data: 889 -624 353 -1082 853 -1096 379 -594 853 -624 353 -1092 417 -582 847 -612 385 -1076 847 -1080 883 -1052 913 -1044 907 -1076 849 -1088 383 -602 867 -616 361 -1068 901 -1072 865 -1104 831 -1080 879 -1098 397 -586 855 -626 355 -1084 381 -592 873 -616 351 -1084 385 -624 821 -620 359 -1086 387 -584 883 -1086 877 -592 355 -1106 853 -1086 387 -69570 97 -100 99 -2620 131 -636 333 -102 235 -236 67 -68 363 -66 201 -100 567 -102 267 -164 101 -134 65 -68 197 -68 297 -166 671 -100 469 -336 165 -100 201 -66 169 -230 169 -204 329 -624 67 -98 265 -232 193 -168 299 -100 235 -138 101 -370 165 -294 333 -622 231 -130 129 -130 353 -132 195 -162 359 -164 67 -68 333 -100 133 -688 235 -236 497 -198 293 -98 129 -296 293 -164 229 -128 229 -132 193 -400 165 -66 163 -98 361 -164 355 -196 587 -164 131 -98 263 -554 99 -130 129 -130 191 -464 99 -132 67 -100 167 -604 329 -66 199 -68 133 -102 163 -66 2971 -132 785 -66 329 -96 323 -100 201 -136 301 -66 1959 -166 867 -134 467 -66 297 -100 835 -100 753 -166 165 -64 67 -370 335 -66 559 -232 165 -334 65 -162 129 -354 163 -64 131 -134 265 -300 263 -132 267 -296 327 -198 99 -132 535 -132 469 -866 231 -860 99 -232 503 -134 99 -198 233 -134 267 -200 97 -358 297 -164 259 -98 227 -166 135 -66 323 -100 97 -294 131 -164 129 -98 295 -96 129 -426 299 -100 67 -102 623 -100 163 -194 127 -360 563 -134 199 -428 493 -98 229 -130 257 -64 165 -100 131 -98 163 -692 357 -64 161 -98 321 -64 389 -230 65 -692 227 -130 261 -132 231 -162 287 -298 97 -460 393 -130 301 -168 331 -100 269 -202 101 -134 201 -102 99 -132 199 -204 235 -664 65 -562 133 -328 463 -100 291 -194 159 -162 227 -98 293 -328 165 -128 227 -574 535 -332 197 -168 65 -300 131 -66 389 -1078 131 -64 259 -64 223 -98 257 -164 63 -328 433 -134 65 -602 131 -68 333 -136 369 -66 297 -264 427 -66 97 -130 429 -102 133 -136 203 -240 167 -236 329 -526 67 -132 133 -168 331 -360 65 -66 331 -296 267 -134 469 -132 595 -230 661 -662 299 -100 265 -200 203 -168 801 -100 133 -68 399 -132 99 -100 161 -390 65 -298 65 -98 261 -130 161 -128 257 -66 67 -134 621 -98 227 -328 99 -230 129 -294 193 -96 195 -318 425 -526 129 -196 163 -162 65 -132 293 -130 63 -66 325 -128 63 -130 293 -66 199 -200 269 -206 133 -198 325 -98 163 -100 97 -98 261 -164 67 -98 167 -430 131 -494 131 -164 +RAW_Data: 97 -98 861 -66 1199 -166 231 -100 651 -166 197 -104 439 -98 131 -64 493 -98 883 -96 99 -98 3327 -66 131 -264 733 -134 2133 -166 131 -102 303 -136 535 -134 701 -98 355 -228 131 -202 99 -134 99 -100 791 -166 169 -202 671 -100 741 -100 263 -66 165 -68 935 -132 197 -198 673 -100 605 -66 1457 -98 1195 -166 2347 -134 505 -100 1469 -66 391 -100 229 -100 1171 -98 939 -100 459 -170 369 -134 231 -162 127 -98 95 -66 195 -98 195 -66 299 -100 331 -98 65 -232 369 -132 201 -68 167 -166 1481 -102 501 -160 1257 -66 2307 -64 623 -164 2079 -66 1101 -98 423 -64 659 -68 431 -136 99 -100 435 -130 167 -168 835 -200 135 -104 133 -100 503 -68 1437 -232 821 -132 357 -96 463 -66 263 -64 683 -132 165 -96 655 -166 3939 -100 1169 -132 2443 -98 197 -132 425 -234 233 -162 1043 -66 197 -100 2793 -134 167 -104 675 -100 197 -134 1367 -102 763 -132 265 -230 133 -102 365 -100 167 -66 1069 -66 837 -100 295 -160 97 -64 129 -132 617 -164 197 -100 133 -136 337 -172 133 -66 557 -98 951 -66 263 -130 587 -66 729 -196 335 -166 933 -432 369 -100 199 -296 225 -98 355 -66 129 -64 557 -98 289 -66 355 -128 193 -162 267 -134 299 -98 165 -170 303 -640 1031 -134 99 -66 135 -68 771 -166 171 -104 201 -134 131 -68 635 -428 661 -292 749 -430 1161 -100 905 -98 65 -98 657 -262 2837 -132 67 -66 265 -132 631 -66 1037 -296 97 -98 1703 -302 367 -100 505 -232 497 -362 333 -134 591 -100 755 -232 67 -130 587 -66 231 -168 65 -332 99 -66 267 -232 393 -134 65 -132 131 -428 133 -200 165 -202 199 -168 165 -102 269 -100 333 -852 201 -134 233 -202 65 -200 563 -768 265 -136 169 -102 169 -598 333 -202 267 -134 267 -328 163 -130 625 -500 199 -200 99 -270 65 -134 65 -198 65 -100 99 -596 493 -66 99 -66 331 -232 103 -136 373 -168 831 -170 65 -672 163 -102 133 -136 331 -100 333 -234 101 -100 99 -200 99 -100 201 -302 199 -600 301 -202 135 -134 705 -166 435 -530 97 -198 131 -198 195 -66 163 -392 293 -66 295 -370 229 -198 65 -100 405 -134 165 -134 133 -170 337 -236 205 -274 267 -134 329 -132 195 -132 503 -132 133 -136 133 -334 197 -196 299 -168 101 -100 233 -100 439 -134 301 -332 331 -298 433 -406 433 -68 167 -100 203 -100 101 -102 99 -328 397 -234 205 -168 133 -364 63 -202 397 -198 95 -394 267 -134 569 -66 201 -102 133 -136 101 -102 99 -132 99 -196 197 -498 197 -102 135 -170 +RAW_Data: 331 -164 63 -162 1267 -66 163 -130 129 -66 725 -164 231 -64 853 -66 101 -134 199 -102 99 -68 365 -66 357 -130 815 -64 357 -98 97 -98 97 -66 65 -466 231 -172 3749 -66 849 -130 917 -64 327 -64 1013 -98 555 -332 795 -100 571 -132 769 -132 401 -134 1297 -134 377 -138 435 -100 401 -100 667 -100 1761 -66 667 -66 1533 -236 233 -98 885 -130 457 -66 999 -66 165 -66 833 -134 695 -166 501 -66 499 -200 329 -64 197 -134 441 -100 2099 -98 491 -134 197 -130 2225 -132 65 -100 689 -64 193 -160 159 -96 195 -98 323 -164 259 -98 535 -472 771 -66 665 -270 665 -66 595 -266 2191 -64 643 -98 1287 -98 741 -100 233 -200 569 -194 261 -68 637 -100 97 -66 491 -158 395 -138 1017 -66 627 -262 559 -64 327 -98 263 -134 99 -102 201 -102 337 -66 167 -68 679 -100 471 -134 195 -66 133 -202 693 -96 197 -98 391 -164 99 -98 3883 -194 461 -100 237 -168 1891 -68 301 -68 969 -166 1439 -294 551 -130 389 -98 99 -196 167 -102 505 -66 569 -234 901 -98 407 -136 469 -66 769 -98 769 -166 1263 -266 297 -98 1701 -200 203 -168 329 -232 65 -100 329 -164 803 -100 135 -200 233 -166 135 -272 265 -134 197 -100 133 -134 539 -232 197 -396 165 -366 263 -68 233 -102 365 -132 233 -100 135 -266 199 -234 167 -232 97 -524 127 -128 389 -98 305 -364 261 -130 257 -162 589 -464 361 -66 229 -134 161 -100 203 -432 265 -66 199 -66 199 -366 229 -236 99 -134 99 -100 131 -168 133 -100 131 -236 267 -132 297 -264 291 -132 167 -234 65 -100 199 -66 333 -730 237 -440 365 -102 99 -100 99 -132 99 -100 1429 -134 427 -100 97 -100 131 -164 799 -170 1077 -100 431 -66 133 -168 737 -134 197 -230 65 -102 803 -132 491 -98 429 -198 471 -134 365 -66 299 -236 65 -66 2837 -102 399 -64 585 -64 523 -196 97 -98 295 -196 555 -160 261 -500 299 -396 333 -236 133 -68 327 -100 199 -204 699 -66 701 -100 65 -164 65 -370 195 -196 97 -66 193 -130 129 -360 195 -130 231 -96 291 -64 455 -228 293 -196 291 -162 97 -194 621 -130 847 -66 395 -66 161 -128 193 -130 293 -98 231 -170 67 -134 297 -360 167 -266 263 -526 263 -132 229 -98 191 -160 159 -100 721 -234 101 -100 99 -130 259 -258 265 -632 687 -164 133 -134 631 -100 199 -102 165 -560 299 -200 265 -332 431 -870 99 -266 503 -364 135 -66 269 -68 499 -100 265 -102 263 -102 569 -234 719 -132 99 -196 419 -262 163 -688 95 -66 165 -128 95 -66 +RAW_Data: 295 -98 987 -196 517 -100 489 -66 355 -132 563 -198 867 -134 1413 -134 541 -134 767 -100 193 -98 1799 -102 467 -134 299 -96 323 -66 261 -100 259 -66 229 -96 851 -66 369 -266 469 -66 101 -98 163 -136 267 -432 859 -130 523 -66 197 -134 1027 -132 227 -194 393 -98 807 -166 235 -100 133 -66 165 -102 133 -136 371 -162 1411 -132 865 -200 471 -100 133 -68 299 -66 633 -98 329 -234 401 -98 1505 -132 133 -134 331 -262 163 -66 261 -98 289 -64 201 -68 1055 -96 391 -66 951 -298 265 -202 297 -66 401 -68 131 -100 1733 -98 941 -66 803 -98 847 -64 3701 -100 721 -160 357 -166 1799 -66 329 -100 99 -102 363 -198 167 -136 197 -66 567 -66 199 -236 1247 -166 2455 -68 1107 -200 235 -100 2355 -130 913 -98 877 -98 163 -196 97 -66 427 -100 801 -134 867 -98 263 -68 441 -134 561 -98 1671 -134 865 -68 935 -132 163 -102 975 -66 1343 -132 1339 -134 369 -100 1107 -66 1167 -168 631 -232 835 -66 1027 -132 333 -166 265 -98 1207 -98 223 -98 455 -64 2095 -134 933 -136 233 -68 335 -136 305 -100 1737 -66 427 -100 263 -130 323 -66 227 -66 717 -100 265 -100 65 -128 355 -66 367 -132 95 -230 229 -100 131 -64 493 -132 291 -396 393 -130 259 -196 227 -288 397 -68 229 -430 99 -302 237 -700 65 -66 65 -100 133 -200 101 -336 133 -166 237 -202 67 -302 67 -68 333 -132 263 -102 267 -296 163 -166 233 -168 363 -64 295 -298 537 -166 431 -200 431 -166 63 -258 363 -164 563 -234 199 -68 299 -100 325 -754 295 -196 65 -98 165 -132 301 -134 131 -134 97 -68 405 -68 233 -134 271 -134 67 -168 101 -136 133 -366 99 -132 67 -132 265 -200 233 -100 201 -136 101 -66 263 -132 129 -66 293 -582 263 -132 1103 -134 203 -168 97 -66 197 -264 131 -168 133 -132 65 -134 199 -134 101 -100 131 -436 99 -232 97 -398 231 -362 65 -202 301 -396 297 -98 199 -134 265 -164 101 -168 267 -102 405 -170 99 -102 397 -132 97 -98 295 -98 1179 -100 135 -136 131 -134 765 -134 465 -168 439 -232 403 -100 65 -134 931 -100 169 -136 237 -68 231 -234 199 -68 401 -134 541 -166 429 -166 1607 -368 533 -66 363 -66 133 -134 433 -166 297 -238 201 -100 201 -170 199 -134 273 -136 99 -134 167 -238 133 -66 265 -134 165 -132 165 -132 97 -228 723 -198 415 -64 491 -298 257 -66 231 -192 225 -96 227 -98 193 -96 521 -198 65 -66 231 -166 163 -98 465 -66 133 -132 195 -130 225 -162 521 -130 63 -66 199 -228 +RAW_Data: 817 -162 449 -160 719 -198 469 -68 133 -68 1101 -132 593 -230 1105 -100 131 -134 231 -66 329 -196 685 -96 557 -68 1263 -68 101 -68 397 -100 65 -66 625 -66 97 -132 1099 -66 493 -66 757 -98 1151 -66 303 -134 1901 -66 99 -100 665 -262 991 -98 791 -66 1925 -168 865 -232 835 -98 505 -102 99 -100 535 -100 169 -134 427 -132 863 -68 167 -134 975 -100 133 -268 1339 -100 1453 -66 1445 -162 195 -64 3623 -66 237 -68 1063 -308 1449 -98 1111 -132 167 -102 855 -270 199 -134 297 -134 267 -168 863 -234 637 -66 567 -230 99 -200 3325 -198 845 -66 289 -66 131 -66 815 -130 1093 -100 167 -100 429 -98 1703 -166 195 -64 971 -98 163 -192 195 -168 439 -132 329 -132 67 -134 67 -134 1591 -168 407 -100 867 -68 399 -134 661 -100 663 -66 237 -136 395 -232 131 -66 695 -100 627 -264 913 -66 1083 -98 287 -66 199 -132 335 -100 1031 -68 99 -100 3815 -98 165 -66 129 -98 163 -128 563 -98 779 -96 223 -64 161 -164 2025 -66 1741 -172 101 -136 203 -102 665 -100 475 -64 167 -100 637 -98 997 -170 1207 -136 233 -166 233 -168 635 -132 199 -100 235 -270 199 -98 131 -102 169 -170 293 -98 323 -164 427 -334 233 -168 267 -68 369 -100 263 -368 101 -66 665 -98 265 -100 133 -100 99 -168 133 -66 133 -132 133 -66 269 -134 435 -68 267 -136 271 -500 163 -100 163 -166 355 -132 97 -98 323 -194 63 -688 463 -130 97 -396 65 -100 357 -194 461 -98 161 -130 223 -162 165 -352 461 -300 267 -166 233 -464 329 -100 293 -362 163 -228 289 -66 229 -66 195 -162 325 -66 261 -98 127 -424 299 -302 367 -68 265 -272 429 -98 161 -98 393 -296 65 -130 161 -196 261 -66 473 -234 97 -98 263 -160 323 -98 67 -132 697 -298 99 -134 233 -202 97 -134 301 -200 307 -100 101 -134 865 -166 231 -202 233 -100 301 -170 169 -102 169 -200 65 -98 595 -166 231 -234 661 -66 473 -334 165 -304 365 -266 97 -502 363 -134 133 -236 65 -100 99 -134 99 -170 235 -66 333 -100 195 -100 133 -300 133 -102 301 -304 65 -100 99 -100 131 -202 135 -134 65 -200 363 -66 263 -498 67 -68 295 -194 321 -368 435 -100 97 -664 99 -100 569 -66 133 -66 67 -134 199 -136 101 -68 301 -68 405 -198 133 -132 581 -132 165 -98 159 -98 197 -66 229 -130 131 -294 133 -96 423 -100 427 -300 357 -132 291 -64 95 -194 455 -98 263 -100 359 -196 65 -162 227 -162 157 -96 157 -230 589 -132 325 -134 535 -66 267 -100 135 -302 +RAW_Data: 131 -134 599 -166 393 -98 369 -236 197 -100 401 -232 569 -134 135 -70 337 -134 101 -136 135 -100 1895 -66 401 -170 503 -66 1633 -66 601 -66 355 -96 683 -100 729 -68 133 -132 433 -68 569 -100 133 -68 201 -132 835 -100 465 -68 527 -98 193 -200 1129 -166 535 -100 199 -98 259 -132 227 -64 1597 -98 261 -192 753 -100 911 -66 667 -298 131 -100 263 -66 1051 -230 787 -66 935 -66 233 -98 885 -236 431 -66 197 -162 521 -68 167 -196 263 -96 589 -98 517 -66 1439 -64 777 -66 3219 -132 679 -134 205 -68 507 -198 749 -200 199 -168 167 -100 133 -134 201 -68 731 -66 495 -198 737 -66 237 -68 135 -100 167 -234 1535 -68 873 -66 373 -66 67 -232 297 -68 65 -66 1095 -68 327 -130 63 -132 1715 -66 2261 -100 321 -132 197 -164 457 -232 1291 -132 405 -68 1001 -68 1133 -272 471 -66 99 -134 1403 -68 167 -68 1091 -336 933 -134 1207 -132 265 -68 267 -66 99 -366 265 -66 1469 -258 367 -168 429 -132 129 -66 491 -132 343 -100 65 -100 263 -136 199 -164 273 -204 791 -100 901 -66 167 -98 165 -64 559 -132 619 -132 1087 -128 2283 -398 1467 -164 259 -130 1927 -130 421 -98 1085 -66 705 -68 1843 -168 875 -170 203 -136 341 -640 199 -66 133 -554 161 -196 63 -66 521 -292 163 -160 95 -158 127 -192 197 -100 587 -130 397 -662 261 -66 193 -130 259 -66 361 -64 459 -98 197 -560 655 -130 389 -66 1135 -100 133 -130 131 -98 1011 -100 561 -66 685 -164 457 -132 2469 -200 609 -66 665 -66 67 -132 327 -200 1657 -134 919 -132 651 -100 327 -230 191 -130 263 -358 95 -130 549 -98 99 -68 299 -100 461 -132 99 -472 165 -134 99 -66 99 -132 399 -102 169 -102 697 -166 233 -132 333 -632 197 -164 865 -266 101 -68 533 -166 299 -100 163 -228 259 -66 327 -200 65 -66 229 -100 363 -230 197 -336 165 -102 893 -300 65 -132 231 -370 265 -230 99 -98 229 -518 199 -100 401 -724 225 -98 63 -96 231 -64 291 -292 65 -98 131 -98 159 -158 127 -194 161 -292 65 -98 133 -66 297 -66 303 -168 97 -168 231 -234 269 -532 135 -168 99 -168 301 -528 99 -506 199 -368 399 -132 329 -372 99 -68 133 -264 197 -100 201 -200 67 -134 131 -270 133 -134 133 -198 327 -200 65 -100 331 -262 161 -166 469 -534 167 -738 131 -100 367 -232 101 -100 265 -604 65 -170 99 -166 299 -102 169 -132 99 -398 229 -330 197 -166 335 -366 97 -98 131 -200 269 -100 199 -168 131 -134 537 -98 265 -100 335 -236 99 -366 +RAW_Data: 459 -100 453 -130 419 -130 519 -96 63 -130 2077 -66 767 -64 127 -134 1961 -296 529 -202 637 -134 527 -100 201 -68 633 -66 163 -360 1029 -68 765 -100 867 -66 503 -100 131 -66 841 -98 165 -68 237 -66 509 -100 501 -302 235 -66 99 -164 227 -130 551 -196 327 -66 1571 -132 99 -68 867 -66 163 -96 161 -130 129 -130 549 -130 487 -166 1801 -66 229 -66 197 -232 325 -66 425 -198 131 -64 295 -166 735 -66 533 -98 227 -130 129 -262 425 -100 263 -66 129 -132 97 -168 971 -170 405 -68 199 -134 475 -202 297 -98 1445 -98 395 -196 161 -66 225 -134 1803 -100 473 -102 1499 -66 199 -100 701 -132 165 -68 133 -102 303 -98 735 -102 805 -100 827 -100 235 -100 65 -266 637 -68 693 -66 1383 -228 819 -66 233 -304 435 -198 203 -136 1135 -270 1709 -64 227 -64 581 -134 505 -66 2203 -64 293 -64 753 -66 551 -132 747 -64 1303 -64 463 -66 229 -102 1877 -266 871 -166 1357 -64 819 -66 465 -198 693 -68 165 -64 95 -128 3785 -132 1465 -100 299 -102 329 -164 595 -134 1029 -66 299 -168 1263 -166 331 -68 967 -100 101 -102 603 -260 165 -132 467 -66 233 -66 235 -102 475 -100 135 -68 301 -134 297 -98 131 -102 269 -466 99 -134 237 -166 135 -168 203 -102 265 -68 503 -66 233 -66 637 -134 101 -200 199 -166 293 -554 361 -328 367 -264 533 -238 167 -68 135 -170 99 -300 591 -298 133 -236 299 -66 231 -368 263 -232 435 -136 133 -102 133 -200 133 -134 163 -134 167 -168 299 -66 265 -100 133 -240 135 -132 263 -170 269 -200 501 -396 263 -98 227 -132 129 -292 427 -66 165 -102 627 -602 99 -66 301 -168 199 -100 563 -330 165 -134 233 -136 65 -332 499 -100 131 -232 325 -96 65 -132 195 -98 393 -624 323 -68 133 -98 195 -162 231 -100 263 -132 231 -102 133 -236 99 -236 231 -166 65 -102 133 -268 101 -102 299 -136 267 -164 493 -64 229 -258 291 -326 263 -198 391 -134 167 -202 365 -594 133 -102 201 -134 503 -396 429 -204 169 -400 197 -170 267 -132 403 -466 297 -98 469 -234 395 -132 233 -100 165 -100 165 -66 197 -68 297 -166 501 -134 133 -100 65 -166 631 -68 297 -134 199 -100 165 -68 299 -266 133 -66 165 -100 231 -490 557 -134 371 -164 299 -170 733 -164 239 -334 335 -66 299 -300 199 -170 103 -100 233 -102 641 -168 65 -100 995 -66 265 -160 259 -130 129 -226 425 -100 355 -726 97 -688 99 -66 233 -266 299 -942 167 -102 167 -166 65 -100 367 -136 99 -134 199 -134 267 -164 +RAW_Data: 67 -68 233 -66 899 -66 163 -96 485 -98 355 -130 943 -100 235 -168 499 -104 1367 -98 297 -100 635 -68 1169 -100 67 -134 835 -264 959 -164 129 -98 419 -196 589 -66 421 -66 1717 -100 133 -100 265 -134 227 -356 455 -166 163 -66 1055 -100 1455 -134 463 -98 2191 -132 295 -132 335 -66 709 -64 619 -98 959 -68 835 -170 603 -134 1033 -134 635 -168 759 -232 397 -198 397 -164 1267 -166 257 -198 1295 -100 239 -104 563 -204 335 -198 203 -68 901 -68 1255 -134 1697 -66 793 -66 1691 -68 201 -100 765 -66 165 -132 131 -230 131 -66 917 -66 335 -338 231 -170 827 -98 199 -136 301 -196 65 -98 199 -200 765 -134 403 -98 333 -68 1691 -132 2565 -64 569 -170 1255 -264 65 -132 1243 -132 2527 -66 259 -66 1739 -100 1309 -198 167 -238 337 -66 131 -68 1973 -362 299 -100 1387 -96 129 -164 423 -230 3875 -96 4283 -98 165 -98 515 -134 469 -68 171 -102 1163 -100 65 -298 461 -66 367 -136 205 -168 371 -98 491 -164 161 -262 1093 -100 299 -100 269 -334 1205 -98 63 -98 261 -64 457 -98 diff --git a/debug/flipperapps.py b/debug/flipperapps.py new file mode 100644 index 000000000..c8d3fcdb9 --- /dev/null +++ b/debug/flipperapps.py @@ -0,0 +1,157 @@ +from dataclasses import dataclass +from typing import Tuple, Dict +import struct +import posixpath +import os +import zlib + +import gdb + + +def get_file_crc32(filename): + with open(filename, "rb") as f: + return zlib.crc32(f.read()) + + +@dataclass +class AppState: + name: str + text_address: int = 0 + entry_address: int = 0 + other_sections: Dict[str, int] = None + debug_link_elf: str = "" + debug_link_crc: int = 0 + + def __post_init__(self): + if self.other_sections is None: + self.other_sections = {} + + def get_original_elf_path(self, elf_path="build/latest/.extapps") -> str: + return ( + posixpath.join(elf_path, self.debug_link_elf) + if elf_path + else self.debug_link_elf + ) + + def is_debug_available(self) -> bool: + have_debug_info = bool(self.debug_link_elf and self.debug_link_crc) + if not have_debug_info: + print("No debug info available for this app") + return False + debug_elf_path = self.get_original_elf_path() + debug_elf_crc32 = get_file_crc32(debug_elf_path) + if self.debug_link_crc != debug_elf_crc32: + print( + f"Debug info ({debug_elf_path}) CRC mismatch: {self.debug_link_crc:08x} != {debug_elf_crc32:08x}, rebuild app" + ) + return False + return True + + def get_gdb_load_command(self) -> str: + load_path = self.get_original_elf_path() + print(f"Loading debug information from {load_path}") + load_command = ( + f"add-symbol-file -readnow {load_path} 0x{self.text_address:08x} " + ) + load_command += " ".join( + f"-s {name} 0x{address:08x}" + for name, address in self.other_sections.items() + ) + return load_command + + def get_gdb_unload_command(self) -> str: + return f"remove-symbol-file -a 0x{self.text_address:08x}" + + def is_loaded_in_gdb(self, gdb_app) -> bool: + # Avoid constructing full app wrapper for comparison + return self.entry_address == int(gdb_app["entry"]) + + @staticmethod + def parse_debug_link_data(section_data: bytes) -> Tuple[str, int]: + # Debug link format: a null-terminated string with debuggable file name + # Padded with 0's to multiple of 4 bytes + # Followed by 4 bytes of CRC32 checksum of that file + elf_name = section_data[:-4].decode("utf-8").split("\x00")[0] + crc32 = struct.unpack(" "AppState": + state = AppState(str(gdb_app["manifest"]["name"].string())) + state.entry_address = int(gdb_app["entry"]) + + app_state = gdb_app["state"] + if debug_link_size := int(app_state["debug_link_size"]): + debug_link_data = ( + gdb.selected_inferior() + .read_memory(int(app_state["debug_link"]), debug_link_size) + .tobytes() + ) + state.debug_link_elf, state.debug_link_crc = AppState.parse_debug_link_data( + debug_link_data + ) + + for idx in range(app_state["mmap_entry_count"]): + mmap_entry = app_state["mmap_entries"][idx] + section_name = mmap_entry["name"].string() + section_addr = int(mmap_entry["address"]) + if section_name == ".text": + state.text_address = section_addr + else: + state.other_sections[section_name] = section_addr + + return state + + +class FlipperAppDebugHelper: + def __init__(self): + self.app_ptr = None + self.app_type_ptr = None + self.current_app: AppState = None + + def attach_fw(self) -> None: + self.app_ptr = gdb.lookup_global_symbol("last_loaded_app") + self.app_type_ptr = gdb.lookup_type("FlipperApplication").pointer() + self._check_app_state() + + def _check_app_state(self) -> None: + app_ptr_value = self.app_ptr.value() + if not app_ptr_value and self.current_app: + # There is an ELF loaded in GDB, but nothing is running on the device + self._unload_debug_elf() + elif app_ptr_value: + # There is an app running on the device + loaded_app = app_ptr_value.cast(self.app_type_ptr).dereference() + + if self.current_app and not self.current_app.is_loaded_in_gdb(loaded_app): + # Currently loaded ELF is not the one running on the device + self._unload_debug_elf() + + if not self.current_app: + # Load ELF for the app running on the device + self._load_debug_elf(loaded_app) + + def _unload_debug_elf(self) -> None: + try: + gdb.execute(self.current_app.get_gdb_unload_command()) + except gdb.error as e: + print(f"Failed to unload debug ELF: {e} (might not be an error)") + self.current_app = None + + def _load_debug_elf(self, app_object) -> None: + self.current_app = AppState.from_gdb(app_object) + + if self.current_app.is_debug_available(): + gdb.execute(self.current_app.get_gdb_load_command()) + + def handle_stop(self, event) -> None: + self._check_app_state() + + +helper = FlipperAppDebugHelper() +try: + helper.attach_fw() + print("Support for Flipper external apps debug is enabled") + gdb.events.stop.connect(helper.handle_stop) +except gdb.error as e: + print(f"Support for Flipper external apps debug is not available: {e}") diff --git a/documentation/AppManifests.md b/documentation/AppManifests.md index 7b1177890..7bc8d0a47 100644 --- a/documentation/AppManifests.md +++ b/documentation/AppManifests.md @@ -1,3 +1,82 @@ # Flipper Application Manifests (.fam) -TBD \ No newline at end of file +All components of Flipper Zero firmware — services, user applications, system settings — are developed independently. Each component has a build system manifest file, named `application.fam`, which defines basic properties of that component and its relations to other parts of the system. + +When building firmware, **`fbt`** collects all application manifests and processes their dependencies. Then it builds only those components that are referenced in the current build configuration. See [fbt docs](./fbt.md#firmware-application-set) for details on build configurations. + +## Application definition + +Properties of a firmware component are declared in a form of a Python code snippet, forming a call to App() function with various parameters. + +Only 2 parameters are mandatory: ***appid*** and ***apptype***, others are optional and may only be meaningful for certain application types. + +### Parameters + +* **appid**: string, application id within the build system. Used for specifying which applications to include in build configuration and to resolve dependencies and conflicts. + +* **apptype**: member of FlipperAppType.* enumeration. Valid values are: + +| Enum member | Firmware component type | +|--------------|--------------------------| +| SERVICE | System service, created at early startup | +| SYSTEM | Application not being shown in any menus. Can be started by other apps or from CLI | +| APP | Regular application for main menu | +| PLUGIN | Application to be built as a part of firmware an to be placed in Plugins menu | +| DEBUG | Application only visible in Debug menu with debug mode enabled | +| ARCHIVE | One and only Archive app | +| SETTINGS | Application to be placed in System settings menu | +| STARTUP | Callback function to run at system startup. Does not define a separate app | +| EXTERNAL | Application to be built as .fap plugin | +| METAPACKAGE | Does not define any code to be run, used for declaring dependencies and application bundles | + +* **name**: Name that is displayed in menus. +* **entry_point**: C function to be used as application's entry point. +* **flags**: Internal flags for system apps. Do not use. +* **cdefines**: C preprocessor definitions to declare globally for other apps when current application is included in active build configuration. +* **requires**: List of application IDs to also include in build configuration, when current application is referenced in list of applications to build. +* **conflicts**: List of application IDs that current application conflicts with. If any of them is found in constructed application list, **`fbt`** will abort firmware build process. +* **provides**: Functionally identical to ***requires*** field. +* **stack_size**: Stack size, in bytes, to allocate for application on its startup. Note that allocating a stack that is too small for an app to run will cause system crash due to stack overflow, and allocating too much stack space will reduce usable heap memory size for apps to process data. *Note: you can use `ps` and `free` CLI commands to profile your app's memory usage.* +* **icon**: Animated icon name from built-in assets to be used when building app as a part of firmware. +* **order**: Order of an application within its group when sorting entries in it. The lower the order is, the closer to the start of the list the item is placed. *Used for ordering startup hooks and menu entries.* +* **sdk_headers**: List of C header files from this app's code to include in API definitions for external applications. + +The following parameters are used only for [FAPs](./AppsOnSDCard.md): + +* **sources**: list of file name masks, used for gathering sources within app folder. Default value of ["\*.c\*"] includes C and CPP source files. +* **fap_version**: string, 2 numbers in form of "x.y": application version to be embedded within .fap file. +* **fap_icon**: name of a .png file, 1-bit color depth, 10x10px, to be embedded within .fap file. +* **fap_libs**: list of extra libraries to link application against. Provides access to extra functions that are not exported as a part of main firmware at expense of increased .fap file size and RAM consumption. +* **fap_category**: string, may be empty. App subcategory, also works as path of FAP within apps folder in the file system. +* **fap_description**: string, may be empty. Short application descriotion. +* **fap_author**: string, may be empty. Application's author. +* **fap_weburl**: string, may be empty. Application's homepage. + + +## .fam file contents + +.fam file contains one or more Application definitions. For example, here's a part of `applications/service/bt/application.fam`: + +```python +App( + appid="bt_start", + apptype=FlipperAppType.STARTUP, + entry_point="bt_on_system_start", + order=70, +) + +App( + appid="bt_settings", + name="Bluetooth", + apptype=FlipperAppType.SETTINGS, + entry_point="bt_settings_app", + stack_size=1 * 1024, + requires=[ + "bt", + "gui", + ], + order=10, +) +``` + +For more examples, see .fam files from various firmware parts. diff --git a/documentation/AppsOnSDCard.md b/documentation/AppsOnSDCard.md new file mode 100644 index 000000000..525821530 --- /dev/null +++ b/documentation/AppsOnSDCard.md @@ -0,0 +1,72 @@ +# FAP (Flipper Application Package) + +[fbt](./fbt.md) has support for building applications as FAP files. FAP are essentially .elf executables with extra metadata and resources bundled in. + +FAPs are built with `firmware_extapps` (or `plugin_dist`) **`fbt`** targets. + +FAPs do not depend on being run on a specific firmware version. Compatibility is determined by the FAP's metadata, which includes the required [API version](#api-versioning). + + +## How to set up an application to be built as a FAP + +FAPs are created and developed the same way as internal applications that are part of the firmware. + +To build your application as a FAP, just create a folder with your app's source code in `applications_user`, then write its code the way you'd do when creating a regular built-in application. Then configure its `application.fam` manifest — and set its *apptype* to FlipperAppType.EXTERNAL. See [Application Manifests](./AppManifests.md#application-definition) for more details. + + * To build your application, run `./fbt firmware_{APPID}`, where APPID is your application's ID in its manifest. + * To build your app, then upload it over USB & run it on Flipper, use `./fbt launch_app APPSRC=applications/path/to/app`. This command is configured in default [VSCode profile](../.vscode/ReadMe.md) as "Launch App on Flipper" build action (Ctrl+Shift+B menu). + * To build all FAPs, run `./fbt plugin_dist`. + + +## Debugging FAPs + +**`fbt`** includes a script for gdb-py to provide debugging support for FAPs, `debug/flipperapps.py`. It is loaded in default debugging configurations by **`fbt`** and stock VSCode configurations. + +With it, you can debug FAPs as if they were a part of main firmware — inspect variables, set breakpoints, step through the code, etc. + +### Setting up debugging environment + +Debugging support script looks up debugging information in latest firmware build dir (`build/latest`). That directory is symlinked by fbt to the latest firmware configuration (Debug or Release) build dir, when you run `./fbt` for chosen configuration. See [fbt docs](./fbt.md#nb) for details. + +So, to debug FAPs, do the following: +1. Build firmware with `./fbt` +2. Flash it with `./fbt flash` +3. [Build your FAP](#how-to-set-up-an-application-to-be-built-as-a-fap) and run it on Flipper. + +After that, you can attach with `./fbt debug` or VSCode and use all debug features. + +It is **important** that firmware and application build type (debug/release) match, and that matching firmware folder is linked as `build/latest`. Otherwise, debugging will not work. + + +## How Flipper runs an application from SD card + +Flipper's MCU cannot run code directly from external storage, so it needs to be copied to RAM first. That is done by the App Loader application, which is responsible for loading the FAP from SD card, verifying its integrity and compatibility, copying it to RAM and adjusting it for its new location. + +Since FAP has to be loaded to RAM to be executed, the amount of RAM available for allocations from heap is reduced compared to running the same app from flash, as a part of firmware. Note that the amount of occupied RAM is less than total FAP file size, since only code and data sections are allocated, while FAP file includes extra information only used at app load time. + +Applications are built for a specific API version. It is a part of the hardware target's definition and contains a major and minor version number. Application loader checks if the application's major API version matches firmware's major API version. + +App loader allocates memory for the application and copies it to RAM, processing relocations and providing concrete addresses for imported symbols using the [symbol table](#symbol-table). Then it starts the application. + + +## API Versioning + +Not all parts of firmware are available for external applications. A subset of available functions and variables is defined in "api_symbols.csv" file, which is a part of firmware target definition in `firmware/targets/` directory. + +**`fbt`** uses semantic versioning for API versioning. Major version is incremented when there are breaking changes in the API, minor version is incremented when there are new features added. + +Breaking changes include: +- removal of a function or a global variable; +- changing the signature of a function. + +API versioning is mostly automated by **`fbt`**. When rebuilding the firmware, **`fbt`** checks if there are any changes in the API exposed by headers gathered from `SDK_HEADERS`. If there are, it stops the build, adjusts the API version and asks the user to go through the changes in .csv file. New entries are marked with "`?`" mark, and the user is supposed to change the mark to "`+`" for the entry to be exposed for FAPs, "`-`" for it to be unavailable. + +**`fbt`** will not allow building a firmware until all "`?`" entries are changed to "`+`" or "`-`". + +**NB:** **`fbt`** automatically manages the API version. The only case where manually incrementing the major API version is allowed (and required) is when existing "`+`" entries are to be changed to "`-`". + +### Symbol Table + +The symbol table is a list of symbols exported by firmware and available for external applications. It is generated by **`fbt`** from the API symbols file and is used by the App Loader to resolve addresses of imported symbols. It is build as a part of the `fap_loader` application. + +**`fbt`** also checks if all imported symbols are present in the symbol table. If there are any missing symbols, it will issue a warning listing them. Such application won't be able to run on the device until all requires symbols are provided in the symbol table. diff --git a/documentation/OTA.md b/documentation/OTA.md index 2a6b09846..836bc1b71 100644 --- a/documentation/OTA.md +++ b/documentation/OTA.md @@ -1,8 +1,8 @@ # Executing code from RAM -In Flipper firmware, we have a special boot mode that loads a specially crafted system image into RAM and transfers control to it. System image executing in RAM has full write access to whole Flipper's flash memory — something that's not possible when running main code from same flash. +In Flipper firmware, we have a special boot mode that loads a specially crafted system image into RAM and transfers control to it. System image executing in RAM has full write access to whole Flipper's flash memory — something that's not possible when running main code from the same flash. -We leverage that boot mode to perform OTA firmware updates, including operations on radio stack running on second MCU core. +We leverage that boot mode to perform OTA firmware updates, including operations on a radio stack running on the second MCU core. # How does Flipper OTA work? @@ -22,16 +22,16 @@ For that, main firmware loads an updater image - a customized build of main Flip First, if there's a Radio stack image bundled with the update, updater compares its version with currently installed one. If they don't match, updater performs stack deinstallation followed by writing and installing a new one. The installation itself is performed by proprietary software, FUS, running on Core2, and leads to a series of system restarts. -Then updater validates and corrects Option Bytes — a special memory region containing low-level configuration for Flipper's MCU. +Then, updater validates and corrects Option Bytes — a special memory region containing low-level configuration for Flipper's MCU. After that, updater loads a `.dfu` file with firmware to be flashed, checks its integrity using CRC32, writes it to system flash and validates written data. ## 3. Restoring internal storage and updating resources -After performing operations on flash memory, system restarts into newly flashed firmware. Then it performs restoration of previously backed up `/int` contents. +After performing operations on flash memory, the system restarts into newly flashed firmware. Then it performs restoration of previously backed up `/int` contents. -If update package contains an additional resources archive, it is extracted onto SD card. +If the update package contains an additional resources archive, it is extracted onto SD card. # Update manifest @@ -40,13 +40,13 @@ Update packages come with a manifest that contains a description of its contents ## Mandatory fields -Update manifest must contain the following keys in given order: +An update manifest must contain the following keys in given order: * __Filetype__: a constant string, "Flipper firmware upgrade configuration"; * __Version__: manifest version. Current value is 2; -* __Info__: arbitraty string, describing package contents; +* __Info__: arbitrary string, describing package contents; * __Target__: hardware revision the package is built for; @@ -56,7 +56,7 @@ Update manifest must contain the following keys in given order: ## Optional fields -Other fields may have empty values, is such case updater skips all operations related to such values. +Other fields may have empty values, is such case, updater skips all operations related to such values. * __Radio__: file name of radio stack image, provided by STM; @@ -66,16 +66,16 @@ Other fields may have empty values, is such case updater skips all operations re * __Radio CRC__: CRC32 of radio image; -* __Resources__: file name of TAR acrhive with resources to be extracted on SD card; +* __Resources__: file name of TAR archive with resources to be extracted on SD card; * __OB reference__, __OB mask__, __OB write mask__: reference values for validating and correcting option bytes. # OTA update error codes -We designed the OTA update process to be as fail-safe as possible. We don't start any risky operation before validating all related pieces of data to ensure we don't leave the device in partially updated, or bricked, state. +We designed the OTA update process to be as fail-safe as possible. We don't start any risky operation before validating all related pieces of data to ensure we don't leave the device in a partially updated, or bricked, state. -Even if something goes wrong, Updater gives you an option to retry failed operations, and reports its state with an error code. These error codes have an `[XX-YY]` format, where `XX` encodes an operation that failed, and `YY` contains extra details on its progress where the error occured. +Even if something goes wrong, Updater gives you an option to retry failed operations, and reports its state with an error code. These error codes have an `[XX-YY]` format, where `XX` encodes an operation that failed, and `YY` contains extra details on its progress where the error occurred. | Stage description | Code | Progress | Description | |:-----------------------:|-------:|------------|--------------------------------------------| diff --git a/documentation/fbt.md b/documentation/fbt.md index 53fc4b5e3..3eee6baaa 100644 --- a/documentation/fbt.md +++ b/documentation/fbt.md @@ -6,7 +6,6 @@ It is invoked by `./fbt` in the firmware project root directory. Internally, it ## Requirements Please install Python packages required by assets build scripts: `pip3 install -r scripts/requirements.txt` -Make sure that `gcc-arm-none-eabi` toolchain & OpenOCD executables are in system's PATH. ## NB @@ -39,11 +38,12 @@ To run cleanup (think of `make clean`) for specified targets, add `-c` option. ## FBT targets -FBT keeps track of internal dependencies, so you only need to build the highest-level target you need, and FBT will make sure everything they depend on is up-to-date. +**`fbt`** keeps track of internal dependencies, so you only need to build the highest-level target you need, and **`fbt`** will make sure everything they depend on is up-to-date. ### High-level (what you most likely need) - `fw_dist` - build & publish firmware to `dist` folder. This is a default target, when no other are specified +- `plugin_dist` - build external plugins & publish to `dist` folder - `updater_package`, `updater_minpackage` - build self-update package. Minimal version only inclues firmware's DFU file; full version also includes radio stack & resources for SD card - `copro_dist` - bundle Core2 FUS+stack binaries for qFlipper - `flash` - flash attached device with OpenOCD over ST-Link @@ -54,7 +54,7 @@ FBT keeps track of internal dependencies, so you only need to build the highest- - `blackmagic` - debug firmware with Blackmagic probe (WiFi dev board) - `openocd` - just start OpenOCD - `get_blackmagic` - output blackmagic address in gdb remote format. Useful for IDE integration -- `lint`, `format` - run clang-tidy on C source code to check and reformat it according to `.clang-format` specs +- `lint`, `format` - run clang-format on C source code to check and reformat it according to `.clang-format` specs - `lint_py`, `format_py` - run [black](https://black.readthedocs.io/en/stable/index.html) on Python source code, build system files & application manifests ### Firmware targets @@ -83,7 +83,7 @@ FBT keeps track of internal dependencies, so you only need to build the highest- ## Command-line parameters - `--options optionfile.py` (default value `fbt_options.py`) - load file with multiple configuration values -- `--with-updater` - enables updater-related targets and dependency tracking. Enabling this option introduces extra startup time costs, so use it when bundling update packages. _Explicily enabling this should no longer be required, fbt now has specific handling for updater-related targets_ +- `--with-updater` - enables updater-related targets and dependency tracking. Enabling this option introduces extra startup time costs, so use it when bundling update packages. _Explicily enabling this should no longer be required, **`fbt`** now has specific handling for updater-related targets_ - `--extra-int-apps=app1,app2,appN` - forces listed apps to be built as internal with `firmware` target - `--extra-ext-apps=app1,app2,appN` - forces listed apps to be built as external with `firmware_extapps` target diff --git a/fbt_options.py b/fbt_options.py index b154d26aa..716f99fdf 100644 --- a/fbt_options.py +++ b/fbt_options.py @@ -66,22 +66,18 @@ LOADER_AUTOSTART = "" FIRMWARE_APPS = { "default": [ - "crypto_start", # Svc "basic_services", # Apps - "basic_apps", - "updater_app", - "storage_move_to_sd", - "archive", + "main_apps", + "system_apps", # Settings - "passport", - "system_settings", - "about", - # Plugins - "basic_plugins", + "settings_apps", + # Stock plugins - no longer built into fw, now they're .faps + # Yet you can still build them as a part of fw + # "basic_plugins", # Debug - "debug_apps", + # "debug_apps", ], "unit_tests": [ "basic_services", diff --git a/firmware.scons b/firmware.scons index f47e9ff26..530634ef2 100644 --- a/firmware.scons +++ b/firmware.scons @@ -1,6 +1,6 @@ Import("ENV", "fw_build_meta") -import os +import itertools from fbt.util import ( should_gen_cdb_and_link_dir, @@ -13,6 +13,7 @@ env = ENV.Clone( ("compilation_db", {"COMPILATIONDB_COMSTR": "\tCDB\t${TARGET}"}), "fwbin", "fbt_apps", + "fbt_sdk", ], COMPILATIONDB_USE_ABSPATH=False, BUILD_DIR=fw_build_meta["build_dir"], @@ -28,7 +29,7 @@ env = ENV.Clone( ], CPPPATH=[ "#/furi", - "#/applications", + *(f"#/{app_dir[0]}" for app_dir in ENV["APPDIRS"] if app_dir[1]), "#/firmware/targets/f${TARGET_HW}/ble_glue", "#/firmware/targets/f${TARGET_HW}/fatfs", "#/firmware/targets/f${TARGET_HW}/furi_hal", @@ -58,6 +59,15 @@ env = ENV.Clone( "FURI_DEBUG" if ENV["DEBUG"] else "FURI_NDEBUG", ], }, + "flipper_application": { + "CCFLAGS": [ + "-Og", + ], + "CPPDEFINES": [ + "NDEBUG", + "FURI_DEBUG" if ENV["DEBUG"] else "FURI_NDEBUG", + ], + }, }, ) @@ -80,6 +90,12 @@ if not env["VERBOSE"]: HEXCOMSTR="\tHEX\t${TARGET}", BINCOMSTR="\tBIN\t${TARGET}", DFUCOMSTR="\tDFU\t${TARGET}", + SDK_PREGEN_COMSTR="\tPREGEN\t${TARGET}", + SDK_COMSTR="\tSDKSRC\t${TARGET}", + SDKSYM_UPDATER_COMSTR="\tSDKCHK\t${TARGET}", + SDKSYM_GENERATOR_COMSTR="\tSDKSYM\t${TARGET}", + APPMETA_COMSTR="\tAPPMETA\t${TARGET}", + APPMETAEMBED_COMSTR="\tFAP\t${TARGET}", ) @@ -127,11 +143,13 @@ fwenv.LoadApplicationManifests() fwenv.PrepareApplicationsBuild() # Build external apps -extapps = SConscript("applications/extapps.scons", exports={"ENV": fwenv}) +extapps = fwenv["FW_EXTAPPS"] = SConscript( + "site_scons/extapps.scons", exports={"ENV": fwenv} +) # Add preprocessor definitions for current set of apps -fwenv.AppendUnique( +fwenv.Append( CPPDEFINES=fwenv["APPBUILD"].get_apps_cdefs(), ) @@ -141,23 +159,26 @@ apps_c = fwenv.ApplicationsC( "applications/applications.c", [Value(fwenv["APPS"]), Value(fwenv["LOADER_AUTOSTART"])], ) + # Adding dependency on manifest files so apps.c is rebuilt when any manifest is changed -fwenv.Depends(apps_c, fwenv.GlobRecursive("*.fam", "#/applications")) +for app_dir, _ in env["APPDIRS"]: + app_dir_node = env.Dir("#").Dir(app_dir) + fwenv.Depends(apps_c, fwenv.GlobRecursive("*.fam", app_dir_node)) sources = [apps_c] # Gather sources only from app folders in current configuration -for app_folder in fwenv["APPBUILD"].get_builtin_app_folders(): - sources += fwenv.GlobRecursive("*.c*", os.path.join("applications", app_folder)) +sources.extend( + itertools.chain.from_iterable( + fwenv.GlobRecursive(source_type, appdir.relpath) + for appdir, source_type in fwenv["APPBUILD"].get_builtin_app_folders() + ) +) fwenv.AppendUnique( LINKFLAGS=[ "-specs=nano.specs", "-specs=nosys.specs", - "-Wl,--start-group", - "-lstdc++", - "-lsupc++", - "-Wl,--end-group", "-Wl,--gc-sections", "-Wl,--undefined=uxTopUsedPriority", "-Wl,--wrap,_malloc_r", @@ -174,7 +195,6 @@ fwenv.AppendUnique( # print(fwenv.Dump()) # Full firmware definition - fwelf = fwenv["FW_ELF"] = fwenv.Program( "${FIRMWARE_BUILD_CFG}", sources, @@ -199,8 +219,8 @@ fwelf = fwenv["FW_ELF"] = fwenv.Program( "assets", "misc", "mbedtls", - "loclass", "lfrfid", + "flipper_application", # 2nd round "flipperformat", "toolbox", @@ -248,6 +268,8 @@ if should_gen_cdb_and_link_dir(fwenv, BUILD_TARGETS): Precious(fwcdb) NoClean(fwcdb) Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_cdb", fwcdb) + AlwaysBuild(fwenv["FIRMWARE_BUILD_CFG"] + "_cdb", fwcdb) + Alias(fwcdb, "") fw_artifacts.append(fwcdb) # Adding as a phony target, so folder link is updated even if elf didn't change @@ -263,5 +285,42 @@ if should_gen_cdb_and_link_dir(fwenv, BUILD_TARGETS): Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_all", fw_artifacts) +if fwenv["IS_BASE_FIRMWARE"]: + sdk_source = fwenv.SDKPrebuilder( + "sdk_origin", + [], + # Filtering out things cxxheaderparser cannot handle + SDK_PP_FLAGS=[ + '-D"_Static_assert(x,y)="', + '-D"__asm__(x)="', + '-D"__attribute__(x)="', + "-Drestrict=", + "-D_Noreturn=", + "-D__restrict=", + "-D__extension__=", + "-D__inline=inline", + "-D__inline__=inline", + ], + ) + Depends(sdk_source, (fwenv["SDK_HEADERS"], fwenv["FW_ASSETS_HEADERS"])) + + sdk_tree = fwenv.SDKTree("sdk/sdk.opts", "sdk_origin") + AlwaysBuild(sdk_tree) + Alias("sdk_tree", sdk_tree) + + sdk_apicheck = fwenv.SDKSymUpdater(fwenv.subst("$SDK_DEFINITION"), "sdk_origin") + Precious(sdk_apicheck) + NoClean(sdk_apicheck) + AlwaysBuild(sdk_apicheck) + Alias("sdk_check", sdk_apicheck) + + sdk_apisyms = fwenv.SDKSymGenerator( + "assets/compiled/symbols.h", fwenv.subst("$SDK_DEFINITION") + ) + Alias("api_syms", sdk_apisyms) + + if fwenv["FORCE"]: + fwenv.AlwaysBuild(sdk_source, sdk_tree, sdk_apicheck, sdk_apisyms) + Return("fwenv") diff --git a/firmware/SConscript b/firmware/SConscript index 3530ed827..5795e242b 100644 --- a/firmware/SConscript +++ b/firmware/SConscript @@ -1,6 +1,16 @@ Import("env") -env.Append(LINT_SOURCES=["firmware"]) +env.Append( + LINT_SOURCES=["firmware"], + # SDK_HEADERS=[env.File("#/firmware/targets/furi_hal_include/furi_hal.h")], + SDK_HEADERS=[ + *env.GlobRecursive("*.h", "#/firmware/targets/furi_hal_include", "*_i.h"), + *env.GlobRecursive("*.h", "#/firmware/targets/f${TARGET_HW}/furi_hal", "*_i.h"), + File("#/firmware/targets/f7/platform_specific/intrinsic_export.h"), + ], +) +env.SetDefault(SDK_DEFINITION=env.File("./targets/f${TARGET_HW}/api_symbols.csv")) + libenv = env.Clone(FW_LIB_NAME="flipper${TARGET_HW}") libenv.Append( diff --git a/firmware/targets/f7/Inc/FreeRTOSConfig.h b/firmware/targets/f7/Inc/FreeRTOSConfig.h index f54d774ca..ab2dc14ef 100644 --- a/firmware/targets/f7/Inc/FreeRTOSConfig.h +++ b/firmware/targets/f7/Inc/FreeRTOSConfig.h @@ -14,7 +14,7 @@ extern uint32_t SystemCoreClock; #define configENABLE_MPU 0 #define configUSE_PREEMPTION 1 -#define configSUPPORT_STATIC_ALLOCATION 0 +#define configSUPPORT_STATIC_ALLOCATION 1 #define configSUPPORT_DYNAMIC_ALLOCATION 1 #define configUSE_IDLE_HOOK 0 #define configUSE_TICK_HOOK 0 diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv new file mode 100644 index 000000000..331cda812 --- /dev/null +++ b/firmware/targets/f7/api_symbols.csv @@ -0,0 +1,2972 @@ +entry,status,name,type,params +Version,+,1.6,, +Header,+,applications/services/bt/bt_service/bt.h,, +Header,+,applications/services/cli/cli.h,, +Header,+,applications/services/cli/cli_vcp.h,, +Header,+,applications/services/dialogs/dialogs.h,, +Header,+,applications/services/dolphin/dolphin.h,, +Header,+,applications/services/gui/elements.h,, +Header,+,applications/services/gui/gui.h,, +Header,+,applications/services/gui/modules/button_menu.h,, +Header,+,applications/services/gui/modules/button_panel.h,, +Header,+,applications/services/gui/modules/byte_input.h,, +Header,+,applications/services/gui/modules/dialog_ex.h,, +Header,+,applications/services/gui/modules/empty_screen.h,, +Header,+,applications/services/gui/modules/file_browser.h,, +Header,+,applications/services/gui/modules/file_browser_worker.h,, +Header,+,applications/services/gui/modules/loading.h,, +Header,+,applications/services/gui/modules/menu.h,, +Header,+,applications/services/gui/modules/popup.h,, +Header,+,applications/services/gui/modules/submenu.h,, +Header,+,applications/services/gui/modules/text_box.h,, +Header,+,applications/services/gui/modules/text_input.h,, +Header,+,applications/services/gui/modules/validators.h,, +Header,+,applications/services/gui/modules/variable_item_list.h,, +Header,+,applications/services/gui/modules/widget.h,, +Header,+,applications/services/gui/modules/widget_elements/widget_element.h,, +Header,+,applications/services/gui/view_dispatcher.h,, +Header,+,applications/services/gui/view_stack.h,, +Header,+,applications/services/input/input.h,, +Header,+,applications/services/loader/loader.h,, +Header,+,applications/services/notification/notification.h,, +Header,+,applications/services/notification/notification_messages.h,, +Header,+,applications/services/power/power_service/power.h,, +Header,+,applications/services/rpc/rpc_app.h,, +Header,+,applications/services/storage/storage.h,, +Header,+,firmware/targets/f7/furi_hal/furi_hal_clock.h,, +Header,+,firmware/targets/f7/furi_hal/furi_hal_console.h,, +Header,+,firmware/targets/f7/furi_hal/furi_hal_flash.h,, +Header,+,firmware/targets/f7/furi_hal/furi_hal_gpio.h,, +Header,+,firmware/targets/f7/furi_hal/furi_hal_i2c_config.h,, +Header,+,firmware/targets/f7/furi_hal/furi_hal_i2c_types.h,, +Header,+,firmware/targets/f7/furi_hal/furi_hal_idle_timer.h,, +Header,+,firmware/targets/f7/furi_hal/furi_hal_interrupt.h,, +Header,+,firmware/targets/f7/furi_hal/furi_hal_os.h,, +Header,+,firmware/targets/f7/furi_hal/furi_hal_resources.h,, +Header,+,firmware/targets/f7/furi_hal/furi_hal_spi_config.h,, +Header,+,firmware/targets/f7/furi_hal/furi_hal_spi_types.h,, +Header,+,firmware/targets/f7/furi_hal/furi_hal_subghz_configs.h,, +Header,+,firmware/targets/f7/furi_hal/furi_hal_uart.h,, +Header,+,firmware/targets/f7/furi_hal/furi_hal_usb_cdc.h,, +Header,+,firmware/targets/f7/platform_specific/intrinsic_export.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_bt.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_bt_hid.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_bt_serial.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_compress.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_cortex.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_crypto.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_debug.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_i2c.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_ibutton.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_info.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_infrared.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_light.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_memory.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_mpu.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_nfc.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_power.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_random.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_region.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_rfid.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_rtc.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_sd.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_speaker.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_spi.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_subghz.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_usb.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_usb_hid.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_usb_hid_u2f.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_version.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_vibro.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_adc.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_bus.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_comp.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_cortex.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_crc.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_crs.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_dma.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_dmamux.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_exti.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_gpio.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_hsem.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_i2c.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_ipcc.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_iwdg.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_lptim.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_lpuart.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_pka.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_pwr.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_rcc.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_rng.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_rtc.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_spi.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_system.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_tim.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_usart.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_utils.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_wwdg.h,, +Header,+,lib/flipper_application/flipper_application.h,, +Header,+,lib/flipper_format/flipper_format.h,, +Header,+,lib/flipper_format/flipper_format_i.h,, +Header,+,lib/lfrfid/lfrfid_dict_file.h,, +Header,+,lib/lfrfid/lfrfid_raw_file.h,, +Header,+,lib/lfrfid/lfrfid_raw_worker.h,, +Header,+,lib/lfrfid/lfrfid_worker.h,, +Header,+,lib/lfrfid/protocols/lfrfid_protocols.h,, +Header,+,lib/lfrfid/tools/bit_lib.h,, +Header,+,lib/micro-ecc/uECC.h,, +Header,+,lib/one_wire/ibutton/ibutton_worker.h,, +Header,+,lib/one_wire/maxim_crc.h,, +Header,+,lib/one_wire/one_wire_device.h,, +Header,+,lib/one_wire/one_wire_host.h,, +Header,+,lib/one_wire/one_wire_host_timing.h,, +Header,+,lib/one_wire/one_wire_slave.h,, +Header,+,lib/print/wrappers.h,, +Header,+,lib/subghz/environment.h,, +Header,+,lib/subghz/protocols/raw.h,, +Header,+,lib/subghz/receiver.h,, +Header,+,lib/subghz/subghz_tx_rx_worker.h,, +Header,+,lib/subghz/subghz_worker.h,, +Header,+,lib/subghz/transmitter.h,, +Header,+,lib/toolbox/args.h,, +Header,+,lib/toolbox/crc32_calc.h,, +Header,+,lib/toolbox/dir_walk.h,, +Header,+,lib/toolbox/hmac_sha256.h,, +Header,+,lib/toolbox/manchester_decoder.h,, +Header,+,lib/toolbox/manchester_encoder.h,, +Header,+,lib/toolbox/md5.h,, +Header,+,lib/toolbox/path.h,, +Header,+,lib/toolbox/protocols/protocol_dict.h,, +Header,+,lib/toolbox/random_name.h,, +Header,+,lib/toolbox/saved_struct.h,, +Header,+,lib/toolbox/stream/buffered_file_stream.h,, +Header,+,lib/toolbox/stream/file_stream.h,, +Header,+,lib/toolbox/stream/stream.h,, +Header,+,lib/toolbox/stream/string_stream.h,, +Header,+,lib/toolbox/tar/tar_archive.h,, +Header,+,lib/toolbox/version.h,, +Function,-,LL_ADC_CommonDeInit,ErrorStatus,ADC_Common_TypeDef* +Function,-,LL_ADC_CommonInit,ErrorStatus,"ADC_Common_TypeDef*, LL_ADC_CommonInitTypeDef*" +Function,-,LL_ADC_CommonStructInit,void,LL_ADC_CommonInitTypeDef* +Function,-,LL_ADC_DeInit,ErrorStatus,ADC_TypeDef* +Function,-,LL_ADC_INJ_Init,ErrorStatus,"ADC_TypeDef*, LL_ADC_INJ_InitTypeDef*" +Function,-,LL_ADC_INJ_StructInit,void,LL_ADC_INJ_InitTypeDef* +Function,-,LL_ADC_Init,ErrorStatus,"ADC_TypeDef*, LL_ADC_InitTypeDef*" +Function,-,LL_ADC_REG_Init,ErrorStatus,"ADC_TypeDef*, LL_ADC_REG_InitTypeDef*" +Function,-,LL_ADC_REG_StructInit,void,LL_ADC_REG_InitTypeDef* +Function,-,LL_ADC_StructInit,void,LL_ADC_InitTypeDef* +Function,-,LL_COMP_DeInit,ErrorStatus,COMP_TypeDef* +Function,-,LL_COMP_Init,ErrorStatus,"COMP_TypeDef*, LL_COMP_InitTypeDef*" +Function,-,LL_COMP_StructInit,void,LL_COMP_InitTypeDef* +Function,-,LL_CRC_DeInit,ErrorStatus,CRC_TypeDef* +Function,-,LL_CRS_DeInit,ErrorStatus, +Function,-,LL_DMA_DeInit,ErrorStatus,"DMA_TypeDef*, uint32_t" +Function,-,LL_DMA_Init,ErrorStatus,"DMA_TypeDef*, uint32_t, LL_DMA_InitTypeDef*" +Function,-,LL_DMA_StructInit,void,LL_DMA_InitTypeDef* +Function,-,LL_EXTI_DeInit,ErrorStatus, +Function,-,LL_EXTI_Init,ErrorStatus,LL_EXTI_InitTypeDef* +Function,-,LL_EXTI_StructInit,void,LL_EXTI_InitTypeDef* +Function,-,LL_GPIO_DeInit,ErrorStatus,GPIO_TypeDef* +Function,-,LL_GPIO_Init,ErrorStatus,"GPIO_TypeDef*, LL_GPIO_InitTypeDef*" +Function,-,LL_GPIO_StructInit,void,LL_GPIO_InitTypeDef* +Function,-,LL_I2C_DeInit,ErrorStatus,I2C_TypeDef* +Function,-,LL_I2C_Init,ErrorStatus,"I2C_TypeDef*, LL_I2C_InitTypeDef*" +Function,-,LL_I2C_StructInit,void,LL_I2C_InitTypeDef* +Function,-,LL_Init1msTick,void,uint32_t +Function,-,LL_LPTIM_DeInit,ErrorStatus,LPTIM_TypeDef* +Function,-,LL_LPTIM_Disable,void,LPTIM_TypeDef* +Function,-,LL_LPTIM_Init,ErrorStatus,"LPTIM_TypeDef*, LL_LPTIM_InitTypeDef*" +Function,-,LL_LPTIM_StructInit,void,LL_LPTIM_InitTypeDef* +Function,-,LL_LPUART_DeInit,ErrorStatus,USART_TypeDef* +Function,-,LL_LPUART_Init,ErrorStatus,"USART_TypeDef*, LL_LPUART_InitTypeDef*" +Function,-,LL_LPUART_StructInit,void,LL_LPUART_InitTypeDef* +Function,-,LL_PKA_DeInit,ErrorStatus,PKA_TypeDef* +Function,-,LL_PKA_Init,ErrorStatus,"PKA_TypeDef*, LL_PKA_InitTypeDef*" +Function,-,LL_PKA_StructInit,void,LL_PKA_InitTypeDef* +Function,-,LL_PLL_ConfigSystemClock_HSE,ErrorStatus,"uint32_t, LL_UTILS_PLLInitTypeDef*, LL_UTILS_ClkInitTypeDef*" +Function,-,LL_PLL_ConfigSystemClock_HSI,ErrorStatus,"LL_UTILS_PLLInitTypeDef*, LL_UTILS_ClkInitTypeDef*" +Function,-,LL_PLL_ConfigSystemClock_MSI,ErrorStatus,"LL_UTILS_PLLInitTypeDef*, LL_UTILS_ClkInitTypeDef*" +Function,-,LL_PWR_DeInit,ErrorStatus, +Function,-,LL_RCC_DeInit,ErrorStatus, +Function,-,LL_RCC_GetADCClockFreq,uint32_t,uint32_t +Function,-,LL_RCC_GetCLK48ClockFreq,uint32_t,uint32_t +Function,-,LL_RCC_GetI2CClockFreq,uint32_t,uint32_t +Function,-,LL_RCC_GetLPTIMClockFreq,uint32_t,uint32_t +Function,-,LL_RCC_GetLPUARTClockFreq,uint32_t,uint32_t +Function,-,LL_RCC_GetRFWKPClockFreq,uint32_t, +Function,-,LL_RCC_GetRNGClockFreq,uint32_t,uint32_t +Function,-,LL_RCC_GetRTCClockFreq,uint32_t, +Function,-,LL_RCC_GetSAIClockFreq,uint32_t,uint32_t +Function,-,LL_RCC_GetSMPSClockFreq,uint32_t, +Function,-,LL_RCC_GetSystemClocksFreq,void,LL_RCC_ClocksTypeDef* +Function,-,LL_RCC_GetUSARTClockFreq,uint32_t,uint32_t +Function,-,LL_RCC_GetUSBClockFreq,uint32_t,uint32_t +Function,-,LL_RNG_DeInit,ErrorStatus,RNG_TypeDef* +Function,-,LL_RNG_Init,ErrorStatus,"RNG_TypeDef*, LL_RNG_InitTypeDef*" +Function,-,LL_RNG_StructInit,void,LL_RNG_InitTypeDef* +Function,-,LL_RTC_ALMA_Init,ErrorStatus,"RTC_TypeDef*, uint32_t, LL_RTC_AlarmTypeDef*" +Function,-,LL_RTC_ALMA_StructInit,void,LL_RTC_AlarmTypeDef* +Function,-,LL_RTC_ALMB_Init,ErrorStatus,"RTC_TypeDef*, uint32_t, LL_RTC_AlarmTypeDef*" +Function,-,LL_RTC_ALMB_StructInit,void,LL_RTC_AlarmTypeDef* +Function,-,LL_RTC_DATE_Init,ErrorStatus,"RTC_TypeDef*, uint32_t, LL_RTC_DateTypeDef*" +Function,-,LL_RTC_DATE_StructInit,void,LL_RTC_DateTypeDef* +Function,-,LL_RTC_DeInit,ErrorStatus,RTC_TypeDef* +Function,-,LL_RTC_EnterInitMode,ErrorStatus,RTC_TypeDef* +Function,-,LL_RTC_ExitInitMode,ErrorStatus,RTC_TypeDef* +Function,-,LL_RTC_Init,ErrorStatus,"RTC_TypeDef*, LL_RTC_InitTypeDef*" +Function,-,LL_RTC_StructInit,void,LL_RTC_InitTypeDef* +Function,-,LL_RTC_TIME_Init,ErrorStatus,"RTC_TypeDef*, uint32_t, LL_RTC_TimeTypeDef*" +Function,-,LL_RTC_TIME_StructInit,void,LL_RTC_TimeTypeDef* +Function,-,LL_RTC_WaitForSynchro,ErrorStatus,RTC_TypeDef* +Function,-,LL_SPI_DeInit,ErrorStatus,SPI_TypeDef* +Function,-,LL_SPI_Init,ErrorStatus,"SPI_TypeDef*, LL_SPI_InitTypeDef*" +Function,-,LL_SPI_StructInit,void,LL_SPI_InitTypeDef* +Function,-,LL_SetFlashLatency,ErrorStatus,uint32_t +Function,-,LL_SetSystemCoreClock,void,uint32_t +Function,-,LL_TIM_BDTR_Init,ErrorStatus,"TIM_TypeDef*, LL_TIM_BDTR_InitTypeDef*" +Function,-,LL_TIM_BDTR_StructInit,void,LL_TIM_BDTR_InitTypeDef* +Function,-,LL_TIM_DeInit,ErrorStatus,TIM_TypeDef* +Function,-,LL_TIM_ENCODER_Init,ErrorStatus,"TIM_TypeDef*, LL_TIM_ENCODER_InitTypeDef*" +Function,-,LL_TIM_ENCODER_StructInit,void,LL_TIM_ENCODER_InitTypeDef* +Function,-,LL_TIM_HALLSENSOR_Init,ErrorStatus,"TIM_TypeDef*, LL_TIM_HALLSENSOR_InitTypeDef*" +Function,-,LL_TIM_HALLSENSOR_StructInit,void,LL_TIM_HALLSENSOR_InitTypeDef* +Function,-,LL_TIM_IC_Init,ErrorStatus,"TIM_TypeDef*, uint32_t, LL_TIM_IC_InitTypeDef*" +Function,-,LL_TIM_IC_StructInit,void,LL_TIM_IC_InitTypeDef* +Function,+,LL_TIM_Init,ErrorStatus,"TIM_TypeDef*, LL_TIM_InitTypeDef*" +Function,+,LL_TIM_OC_Init,ErrorStatus,"TIM_TypeDef*, uint32_t, LL_TIM_OC_InitTypeDef*" +Function,-,LL_TIM_OC_StructInit,void,LL_TIM_OC_InitTypeDef* +Function,-,LL_TIM_StructInit,void,LL_TIM_InitTypeDef* +Function,-,LL_USART_ClockInit,ErrorStatus,"USART_TypeDef*, LL_USART_ClockInitTypeDef*" +Function,-,LL_USART_ClockStructInit,void,LL_USART_ClockInitTypeDef* +Function,-,LL_USART_DeInit,ErrorStatus,USART_TypeDef* +Function,-,LL_USART_Init,ErrorStatus,"USART_TypeDef*, LL_USART_InitTypeDef*" +Function,-,LL_USART_StructInit,void,LL_USART_InitTypeDef* +Function,-,LL_mDelay,void,uint32_t +Function,-,SystemCoreClockUpdate,void, +Function,-,SystemInit,void, +Function,-,_Exit,void,int +Function,-,__assert,void,"const char*, int, const char*" +Function,+,__assert_func,void,"const char*, int, const char*, const char*" +Function,+,__clear_cache,void,"void*, void*" +Function,-,__eprintf,void,"const char*, const char*, unsigned int, const char*" +Function,+,__errno,int*, +Function,-,__fpclassifyd,int,double +Function,-,__fpclassifyf,int,float +Function,-,__getdelim,ssize_t,"char**, size_t*, int, FILE*" +Function,-,__getline,ssize_t,"char**, size_t*, FILE*" +Function,-,__isinfd,int,double +Function,-,__isinff,int,float +Function,-,__isnand,int,double +Function,-,__isnanf,int,float +Function,-,__itoa,char*,"int, char*, int" +Function,-,__locale_mb_cur_max,int, +Function,+,__retarget_lock_acquire,void,_LOCK_T +Function,+,__retarget_lock_acquire_recursive,void,_LOCK_T +Function,-,__retarget_lock_close,void,_LOCK_T +Function,+,__retarget_lock_close_recursive,void,_LOCK_T +Function,-,__retarget_lock_init,void,_LOCK_T* +Function,+,__retarget_lock_init_recursive,void,_LOCK_T* +Function,+,__retarget_lock_release,void,_LOCK_T +Function,+,__retarget_lock_release_recursive,void,_LOCK_T +Function,-,__retarget_lock_try_acquire,int,_LOCK_T +Function,-,__retarget_lock_try_acquire_recursive,int,_LOCK_T +Function,-,__signbitd,int,double +Function,-,__signbitf,int,float +Function,-,__signgam,int*, +Function,-,__srget_r,int,"_reent*, FILE*" +Function,-,__swbuf_r,int,"_reent*, int, FILE*" +Function,-,__utoa,char*,"unsigned, char*, int" +Function,+,__wrap___assert,void,"const char*, int, const char*" +Function,+,__wrap___assert_func,void,"const char*, int, const char*, const char*" +Function,+,__wrap_fflush,int,FILE* +Function,+,__wrap_printf,int,"const char*, ..." +Function,+,__wrap_putc,int,"int, FILE*" +Function,+,__wrap_putchar,int,int +Function,+,__wrap_puts,int,const char* +Function,+,__wrap_snprintf,int,"char*, size_t, const char*, ..." +Function,+,__wrap_vsnprintf,int,"char*, size_t, const char*, va_list" +Function,-,_asiprintf_r,int,"_reent*, char**, const char*, ..." +Function,-,_asniprintf_r,char*,"_reent*, char*, size_t*, const char*, ..." +Function,-,_asnprintf_r,char*,"_reent*, char*, size_t*, const char*, ..." +Function,-,_asprintf_r,int,"_reent*, char**, const char*, ..." +Function,-,_atoi_r,int,"_reent*, const char*" +Function,-,_atol_r,long,"_reent*, const char*" +Function,-,_atoll_r,long long,"_reent*, const char*" +Function,-,_calloc_r,void*,"_reent*, size_t, size_t" +Function,-,_diprintf_r,int,"_reent*, int, const char*, ..." +Function,-,_dprintf_r,int,"_reent*, int, const char*, ..." +Function,-,_drand48_r,double,_reent* +Function,-,_dtoa_r,char*,"_reent*, double, int, int, int*, int*, char**" +Function,-,_erand48_r,double,"_reent*, unsigned short[3]" +Function,-,_fclose_r,int,"_reent*, FILE*" +Function,-,_fcloseall_r,int,_reent* +Function,-,_fdopen_r,FILE*,"_reent*, int, const char*" +Function,-,_fflush_r,int,"_reent*, FILE*" +Function,-,_fgetc_r,int,"_reent*, FILE*" +Function,-,_fgetc_unlocked_r,int,"_reent*, FILE*" +Function,-,_fgetpos_r,int,"_reent*, FILE*, fpos_t*" +Function,-,_fgets_r,char*,"_reent*, char*, int, FILE*" +Function,-,_fgets_unlocked_r,char*,"_reent*, char*, int, FILE*" +Function,-,_findenv,char*,"const char*, int*" +Function,-,_findenv_r,char*,"_reent*, const char*, int*" +Function,-,_fiprintf_r,int,"_reent*, FILE*, const char*, ..." +Function,-,_fiscanf_r,int,"_reent*, FILE*, const char*, ..." +Function,-,_fmemopen_r,FILE*,"_reent*, void*, size_t, const char*" +Function,-,_fopen_r,FILE*,"_reent*, const char*, const char*" +Function,-,_fopencookie_r,FILE*,"_reent*, void*, const char*, cookie_io_functions_t" +Function,-,_fprintf_r,int,"_reent*, FILE*, const char*, ..." +Function,-,_fpurge_r,int,"_reent*, FILE*" +Function,-,_fputc_r,int,"_reent*, int, FILE*" +Function,-,_fputc_unlocked_r,int,"_reent*, int, FILE*" +Function,-,_fputs_r,int,"_reent*, const char*, FILE*" +Function,-,_fputs_unlocked_r,int,"_reent*, const char*, FILE*" +Function,-,_fread_r,size_t,"_reent*, void*, size_t, size_t, FILE*" +Function,-,_fread_unlocked_r,size_t,"_reent*, void*, size_t, size_t, FILE*" +Function,-,_free_r,void,"_reent*, void*" +Function,-,_freopen_r,FILE*,"_reent*, const char*, const char*, FILE*" +Function,-,_fscanf_r,int,"_reent*, FILE*, const char*, ..." +Function,-,_fseek_r,int,"_reent*, FILE*, long, int" +Function,-,_fseeko_r,int,"_reent*, FILE*, _off_t, int" +Function,-,_fsetpos_r,int,"_reent*, FILE*, const fpos_t*" +Function,-,_ftell_r,long,"_reent*, FILE*" +Function,-,_ftello_r,_off_t,"_reent*, FILE*" +Function,-,_funopen_r,FILE*,"_reent*, const void*, int (*)(void*, char*, int), int (*)(void*, const char*, int), fpos_t (*)(void*, fpos_t, int), int (*)(void*)" +Function,-,_fwrite_r,size_t,"_reent*, const void*, size_t, size_t, FILE*" +Function,-,_fwrite_unlocked_r,size_t,"_reent*, const void*, size_t, size_t, FILE*" +Function,-,_getc_r,int,"_reent*, FILE*" +Function,-,_getc_unlocked_r,int,"_reent*, FILE*" +Function,-,_getchar_r,int,_reent* +Function,-,_getchar_unlocked_r,int,_reent* +Function,-,_getenv_r,char*,"_reent*, const char*" +Function,-,_gets_r,char*,"_reent*, char*" +Function,-,_iprintf_r,int,"_reent*, const char*, ..." +Function,-,_iscanf_r,int,"_reent*, const char*, ..." +Function,-,_jrand48_r,long,"_reent*, unsigned short[3]" +Function,-,_l64a_r,char*,"_reent*, long" +Function,-,_lcong48_r,void,"_reent*, unsigned short[7]" +Function,-,_lrand48_r,long,_reent* +Function,-,_malloc_r,void*,"_reent*, size_t" +Function,-,_mblen_r,int,"_reent*, const char*, size_t, _mbstate_t*" +Function,-,_mbstowcs_r,size_t,"_reent*, wchar_t*, const char*, size_t, _mbstate_t*" +Function,-,_mbtowc_r,int,"_reent*, wchar_t*, const char*, size_t, _mbstate_t*" +Function,-,_mkdtemp_r,char*,"_reent*, char*" +Function,-,_mkostemp_r,int,"_reent*, char*, int" +Function,-,_mkostemps_r,int,"_reent*, char*, int, int" +Function,-,_mkstemp_r,int,"_reent*, char*" +Function,-,_mkstemps_r,int,"_reent*, char*, int" +Function,-,_mktemp_r,char*,"_reent*, char*" +Function,-,_mrand48_r,long,_reent* +Function,-,_mstats_r,void,"_reent*, char*" +Function,-,_nrand48_r,long,"_reent*, unsigned short[3]" +Function,-,_open_memstream_r,FILE*,"_reent*, char**, size_t*" +Function,-,_perror_r,void,"_reent*, const char*" +Function,-,_printf_r,int,"_reent*, const char*, ..." +Function,-,_putc_r,int,"_reent*, int, FILE*" +Function,-,_putc_unlocked_r,int,"_reent*, int, FILE*" +Function,-,_putchar,void,char +Function,-,_putchar_r,int,"_reent*, int" +Function,-,_putchar_unlocked_r,int,"_reent*, int" +Function,-,_putenv_r,int,"_reent*, char*" +Function,-,_puts_r,int,"_reent*, const char*" +Function,-,_realloc_r,void*,"_reent*, void*, size_t" +Function,-,_reallocf_r,void*,"_reent*, void*, size_t" +Function,-,_reclaim_reent,void,_reent* +Function,-,_remove_r,int,"_reent*, const char*" +Function,-,_rename_r,int,"_reent*, const char*, const char*" +Function,-,_rewind_r,void,"_reent*, FILE*" +Function,-,_scanf_r,int,"_reent*, const char*, ..." +Function,-,_seed48_r,unsigned short*,"_reent*, unsigned short[3]" +Function,-,_setenv_r,int,"_reent*, const char*, const char*, int" +Function,-,_siprintf_r,int,"_reent*, char*, const char*, ..." +Function,-,_siscanf_r,int,"_reent*, const char*, const char*, ..." +Function,-,_sniprintf_r,int,"_reent*, char*, size_t, const char*, ..." +Function,-,_snprintf_r,int,"_reent*, char*, size_t, const char*, ..." +Function,-,_sprintf_r,int,"_reent*, char*, const char*, ..." +Function,-,_srand48_r,void,"_reent*, long" +Function,-,_sscanf_r,int,"_reent*, const char*, const char*, ..." +Function,-,_strdup_r,char*,"_reent*, const char*" +Function,-,_strerror_r,char*,"_reent*, int, int, int*" +Function,-,_strndup_r,char*,"_reent*, const char*, size_t" +Function,-,_strtod_r,double,"_reent*, const char*, char**" +Function,-,_strtol_r,long,"_reent*, const char*, char**, int" +Function,-,_strtold_r,long double,"_reent*, const char*, char**" +Function,-,_strtoll_r,long long,"_reent*, const char*, char**, int" +Function,-,_strtoul_r,unsigned long,"_reent*, const char*, char**, int" +Function,-,_strtoull_r,unsigned long long,"_reent*, const char*, char**, int" +Function,-,_system_r,int,"_reent*, const char*" +Function,-,_tempnam_r,char*,"_reent*, const char*, const char*" +Function,-,_tmpfile_r,FILE*,_reent* +Function,-,_tmpnam_r,char*,"_reent*, char*" +Function,-,_ungetc_r,int,"_reent*, int, FILE*" +Function,-,_unsetenv_r,int,"_reent*, const char*" +Function,-,_vasiprintf_r,int,"_reent*, char**, const char*, __gnuc_va_list" +Function,-,_vasniprintf_r,char*,"_reent*, char*, size_t*, const char*, __gnuc_va_list" +Function,-,_vasnprintf_r,char*,"_reent*, char*, size_t*, const char*, __gnuc_va_list" +Function,-,_vasprintf_r,int,"_reent*, char**, const char*, __gnuc_va_list" +Function,-,_vdiprintf_r,int,"_reent*, int, const char*, __gnuc_va_list" +Function,-,_vdprintf_r,int,"_reent*, int, const char*, __gnuc_va_list" +Function,-,_vfiprintf_r,int,"_reent*, FILE*, const char*, __gnuc_va_list" +Function,-,_vfiscanf_r,int,"_reent*, FILE*, const char*, __gnuc_va_list" +Function,-,_vfprintf_r,int,"_reent*, FILE*, const char*, __gnuc_va_list" +Function,-,_vfscanf_r,int,"_reent*, FILE*, const char*, __gnuc_va_list" +Function,-,_viprintf_r,int,"_reent*, const char*, __gnuc_va_list" +Function,-,_viscanf_r,int,"_reent*, const char*, __gnuc_va_list" +Function,-,_vprintf_r,int,"_reent*, const char*, __gnuc_va_list" +Function,-,_vscanf_r,int,"_reent*, const char*, __gnuc_va_list" +Function,-,_vsiprintf_r,int,"_reent*, char*, const char*, __gnuc_va_list" +Function,-,_vsiscanf_r,int,"_reent*, const char*, const char*, __gnuc_va_list" +Function,-,_vsniprintf_r,int,"_reent*, char*, size_t, const char*, __gnuc_va_list" +Function,-,_vsnprintf_r,int,"_reent*, char*, size_t, const char*, __gnuc_va_list" +Function,-,_vsprintf_r,int,"_reent*, char*, const char*, __gnuc_va_list" +Function,-,_vsscanf_r,int,"_reent*, const char*, const char*, __gnuc_va_list" +Function,-,_wcstombs_r,size_t,"_reent*, char*, const wchar_t*, size_t, _mbstate_t*" +Function,-,_wctomb_r,int,"_reent*, char*, wchar_t, _mbstate_t*" +Function,-,a64l,long,const char* +Function,+,abort,void, +Function,-,abs,int,int +Function,-,acos,double,double +Function,-,acosf,float,float +Function,-,acosh,double,double +Function,-,acoshf,float,float +Function,-,acoshl,long double,long double +Function,-,acosl,long double,long double +Function,+,acquire_mutex,void*,"ValueMutex*, uint32_t" +Function,-,aligned_alloc,void*,"size_t, size_t" +Function,-,aligned_free,void,void* +Function,-,aligned_malloc,void*,"size_t, size_t" +Function,-,arc4random,__uint32_t, +Function,-,arc4random_buf,void,"void*, size_t" +Function,-,arc4random_uniform,__uint32_t,__uint32_t +Function,+,args_char_to_hex,_Bool,"char, char, uint8_t*" +Function,+,args_get_first_word_length,size_t,string_t +Function,+,args_length,size_t,string_t +Function,+,args_read_hex_bytes,_Bool,"string_t, uint8_t*, size_t" +Function,+,args_read_int_and_trim,_Bool,"string_t, int*" +Function,+,args_read_probably_quoted_string_and_trim,_Bool,"string_t, string_t" +Function,+,args_read_string_and_trim,_Bool,"string_t, string_t" +Function,-,asin,double,double +Function,-,asinf,float,float +Function,-,asinh,double,double +Function,-,asinhf,float,float +Function,-,asinhl,long double,long double +Function,-,asinl,long double,long double +Function,-,asiprintf,int,"char**, const char*, ..." +Function,-,asniprintf,char*,"char*, size_t*, const char*, ..." +Function,-,asnprintf,char*,"char*, size_t*, const char*, ..." +Function,-,asprintf,int,"char**, const char*, ..." +Function,-,at_quick_exit,int,void (*)() +Function,-,atan,double,double +Function,-,atan2,double,"double, double" +Function,-,atan2f,float,"float, float" +Function,-,atan2l,long double,"long double, long double" +Function,-,atanf,float,float +Function,-,atanh,double,double +Function,-,atanhf,float,float +Function,-,atanhl,long double,long double +Function,-,atanl,long double,long double +Function,-,atexit,int,void (*)() +Function,-,atof,double,const char* +Function,-,atoff,float,const char* +Function,+,atoi,int,const char* +Function,-,atol,long,const char* +Function,-,atoll,long long,const char* +Function,-,basename,char*,const char* +Function,-,bcmp,int,"const void*, const void*, size_t" +Function,-,bcopy,void,"const void*, void*, size_t" +Function,+,bit_lib_add_parity,size_t,"const uint8_t*, size_t, uint8_t*, size_t, uint8_t, uint8_t, BitLibParity" +Function,+,bit_lib_copy_bits,void,"uint8_t*, size_t, size_t, const uint8_t*, size_t" +Function,+,bit_lib_crc16,uint16_t,"const uint8_t*, size_t, uint16_t, uint16_t, _Bool, _Bool, uint16_t" +Function,+,bit_lib_crc8,uint16_t,"const uint8_t*, size_t, uint8_t, uint8_t, _Bool, _Bool, uint8_t" +Function,+,bit_lib_get_bit,_Bool,"const uint8_t*, size_t" +Function,+,bit_lib_get_bit_count,uint8_t,uint32_t +Function,+,bit_lib_get_bits,uint8_t,"const uint8_t*, size_t, uint8_t" +Function,+,bit_lib_get_bits_16,uint16_t,"const uint8_t*, size_t, uint8_t" +Function,+,bit_lib_get_bits_32,uint32_t,"const uint8_t*, size_t, uint8_t" +Function,+,bit_lib_print_bits,void,"const uint8_t*, size_t" +Function,+,bit_lib_print_regions,void,"const BitLibRegion*, size_t, const uint8_t*, size_t" +Function,+,bit_lib_push_bit,void,"uint8_t*, size_t, _Bool" +Function,+,bit_lib_remove_bit_every_nth,size_t,"uint8_t*, size_t, uint8_t, uint8_t" +Function,+,bit_lib_reverse_16_fast,uint16_t,uint16_t +Function,+,bit_lib_reverse_8_fast,uint8_t,uint8_t +Function,+,bit_lib_reverse_bits,void,"uint8_t*, size_t, uint8_t" +Function,+,bit_lib_set_bit,void,"uint8_t*, size_t, _Bool" +Function,+,bit_lib_set_bits,void,"uint8_t*, size_t, uint8_t, uint8_t" +Function,+,bit_lib_test_parity,_Bool,"const uint8_t*, size_t, uint8_t, BitLibParity, uint8_t" +Function,+,bit_lib_test_parity_32,_Bool,"uint32_t, BitLibParity" +Function,+,ble_app_get_key_storage_buff,void,"uint8_t**, uint16_t*" +Function,+,ble_app_init,_Bool, +Function,+,ble_app_thread_stop,void, +Function,+,ble_glue_force_c2_mode,BleGlueCommandResult,BleGlueC2Mode +Function,-,ble_glue_fus_get_status,BleGlueCommandResult, +Function,-,ble_glue_fus_stack_delete,BleGlueCommandResult, +Function,-,ble_glue_fus_stack_install,BleGlueCommandResult,"uint32_t, uint32_t" +Function,-,ble_glue_fus_wait_operation,BleGlueCommandResult, +Function,+,ble_glue_get_c2_info,const BleGlueC2Info*, +Function,-,ble_glue_get_c2_status,BleGlueStatus, +Function,+,ble_glue_init,void, +Function,+,ble_glue_is_alive,_Bool, +Function,+,ble_glue_is_radio_stack_ready,_Bool, +Function,+,ble_glue_reinit_c2,_Bool, +Function,+,ble_glue_set_key_storage_changed_callback,void,"BleGlueKeyStorageChangedCallback, void*" +Function,+,ble_glue_start,_Bool, +Function,+,ble_glue_thread_stop,void, +Function,+,ble_glue_wait_for_c2_start,_Bool,int32_t +Function,-,bsearch,void*,"const void*, const void*, size_t, size_t, __compar_fn_t" +Function,+,bt_disconnect,void,Bt* +Function,+,bt_forget_bonded_devices,void,Bt* +Function,+,bt_set_profile,_Bool,"Bt*, BtProfile" +Function,+,bt_set_status_changed_callback,void,"Bt*, BtStatusChangedCallback, void*" +Function,+,buffered_file_stream_alloc,Stream*,Storage* +Function,+,buffered_file_stream_close,_Bool,Stream* +Function,+,buffered_file_stream_get_error,FS_Error,Stream* +Function,+,buffered_file_stream_open,_Bool,"Stream*, const char*, FS_AccessMode, FS_OpenMode" +Function,+,buffered_file_stream_sync,_Bool,Stream* +Function,+,button_menu_add_item,ButtonMenuItem*,"ButtonMenu*, const char*, int32_t, ButtonMenuItemCallback, ButtonMenuItemType, void*" +Function,+,button_menu_alloc,ButtonMenu*, +Function,+,button_menu_free,void,ButtonMenu* +Function,+,button_menu_get_view,View*,ButtonMenu* +Function,+,button_menu_reset,void,ButtonMenu* +Function,+,button_menu_set_header,void,"ButtonMenu*, const char*" +Function,+,button_menu_set_selected_item,void,"ButtonMenu*, uint32_t" +Function,+,button_panel_add_item,void,"ButtonPanel*, uint32_t, uint16_t, uint16_t, uint16_t, uint16_t, const Icon*, const Icon*, ButtonItemCallback, void*" +Function,+,button_panel_add_label,void,"ButtonPanel*, uint16_t, uint16_t, Font, const char*" +Function,+,button_panel_alloc,ButtonPanel*, +Function,+,button_panel_free,void,ButtonPanel* +Function,+,button_panel_get_view,View*,ButtonPanel* +Function,+,button_panel_reserve,void,"ButtonPanel*, size_t, size_t" +Function,+,button_panel_reset,void,ButtonPanel* +Function,+,byte_input_alloc,ByteInput*, +Function,+,byte_input_free,void,ByteInput* +Function,+,byte_input_get_view,View*,ByteInput* +Function,+,byte_input_set_header_text,void,"ByteInput*, const char*" +Function,+,byte_input_set_result_callback,void,"ByteInput*, ByteInputCallback, ByteChangedCallback, void*, uint8_t*, uint8_t" +Function,-,bzero,void,"void*, size_t" +Function,-,calloc,void*,"size_t, size_t" +Function,+,canvas_clear,void,Canvas* +Function,+,canvas_current_font_height,uint8_t,Canvas* +Function,+,canvas_draw_bitmap,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t, const uint8_t*" +Function,+,canvas_draw_box,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t" +Function,+,canvas_draw_circle,void,"Canvas*, uint8_t, uint8_t, uint8_t" +Function,+,canvas_draw_disc,void,"Canvas*, uint8_t, uint8_t, uint8_t" +Function,+,canvas_draw_dot,void,"Canvas*, uint8_t, uint8_t" +Function,+,canvas_draw_frame,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t" +Function,+,canvas_draw_glyph,void,"Canvas*, uint8_t, uint8_t, uint16_t" +Function,+,canvas_draw_icon,void,"Canvas*, uint8_t, uint8_t, const Icon*" +Function,+,canvas_draw_icon_animation,void,"Canvas*, uint8_t, uint8_t, IconAnimation*" +Function,+,canvas_draw_line,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t" +Function,+,canvas_draw_rbox,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t" +Function,+,canvas_draw_rframe,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t" +Function,+,canvas_draw_str,void,"Canvas*, uint8_t, uint8_t, const char*" +Function,+,canvas_draw_str_aligned,void,"Canvas*, uint8_t, uint8_t, Align, Align, const char*" +Function,+,canvas_draw_triangle,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t, CanvasDirection" +Function,+,canvas_draw_xbm,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t, const uint8_t*" +Function,+,canvas_get_font_params,CanvasFontParameters*,"Canvas*, Font" +Function,+,canvas_glyph_width,uint8_t,"Canvas*, char" +Function,+,canvas_height,uint8_t,Canvas* +Function,+,canvas_invert_color,void,Canvas* +Function,+,canvas_set_bitmap_mode,void,"Canvas*, _Bool" +Function,+,canvas_set_color,void,"Canvas*, Color" +Function,+,canvas_set_font,void,"Canvas*, Font" +Function,+,canvas_set_font_direction,void,"Canvas*, CanvasDirection" +Function,+,canvas_string_width,uint16_t,"Canvas*, const char*" +Function,+,canvas_width,uint8_t,Canvas* +Function,-,cbrt,double,double +Function,-,cbrtf,float,float +Function,-,cbrtl,long double,long double +Function,+,cc1101_calibrate,void,FuriHalSpiBusHandle* +Function,+,cc1101_flush_rx,void,FuriHalSpiBusHandle* +Function,+,cc1101_flush_tx,void,FuriHalSpiBusHandle* +Function,-,cc1101_get_partnumber,uint8_t,FuriHalSpiBusHandle* +Function,+,cc1101_get_rssi,uint8_t,FuriHalSpiBusHandle* +Function,+,cc1101_get_status,CC1101Status,FuriHalSpiBusHandle* +Function,-,cc1101_get_version,uint8_t,FuriHalSpiBusHandle* +Function,+,cc1101_read_fifo,uint8_t,"FuriHalSpiBusHandle*, uint8_t*, uint8_t*" +Function,+,cc1101_read_reg,CC1101Status,"FuriHalSpiBusHandle*, uint8_t, uint8_t*" +Function,+,cc1101_reset,void,FuriHalSpiBusHandle* +Function,+,cc1101_set_frequency,uint32_t,"FuriHalSpiBusHandle*, uint32_t" +Function,-,cc1101_set_intermediate_frequency,uint32_t,"FuriHalSpiBusHandle*, uint32_t" +Function,+,cc1101_set_pa_table,void,"FuriHalSpiBusHandle*, const uint8_t[8]" +Function,+,cc1101_shutdown,void,FuriHalSpiBusHandle* +Function,+,cc1101_strobe,CC1101Status,"FuriHalSpiBusHandle*, uint8_t" +Function,+,cc1101_switch_to_idle,void,FuriHalSpiBusHandle* +Function,+,cc1101_switch_to_rx,void,FuriHalSpiBusHandle* +Function,+,cc1101_switch_to_tx,void,FuriHalSpiBusHandle* +Function,+,cc1101_write_fifo,uint8_t,"FuriHalSpiBusHandle*, const uint8_t*, uint8_t" +Function,+,cc1101_write_reg,CC1101Status,"FuriHalSpiBusHandle*, uint8_t, uint8_t" +Function,-,ceil,double,double +Function,-,ceilf,float,float +Function,-,ceill,long double,long double +Function,-,cfree,void,void* +Function,-,clearerr,void,FILE* +Function,-,clearerr_unlocked,void,FILE* +Function,+,cli_add_command,void,"Cli*, const char*, CliCommandFlag, CliCallback, void*" +Function,+,cli_cmd_interrupt_received,_Bool,Cli* +Function,+,cli_delete_command,void,"Cli*, const char*" +Function,+,cli_getc,char,Cli* +Function,+,cli_is_connected,_Bool,Cli* +Function,+,cli_nl,void, +Function,+,cli_print_usage,void,"const char*, const char*, const char*" +Function,+,cli_read,size_t,"Cli*, uint8_t*, size_t" +Function,+,cli_read_timeout,size_t,"Cli*, uint8_t*, size_t, uint32_t" +Function,+,cli_session_close,void,Cli* +Function,+,cli_session_open,void,"Cli*, void*" +Function,+,cli_write,void,"Cli*, const uint8_t*, size_t" +Function,-,copysign,double,"double, double" +Function,-,copysignf,float,"float, float" +Function,-,copysignl,long double,"long double, long double" +Function,-,cos,double,double +Function,-,cosf,float,float +Function,-,cosh,double,double +Function,-,coshf,float,float +Function,-,coshl,long double,long double +Function,-,cosl,long double,long double +Function,+,crc32_calc_buffer,uint32_t,"uint32_t, const void*, size_t" +Function,+,crc32_calc_file,uint32_t,"File*, const FileCrcProgressCb, void*" +Function,-,ctermid,char*,char* +Function,-,cuserid,char*,char* +Function,+,delete_mutex,_Bool,ValueMutex* +Function,+,dialog_ex_alloc,DialogEx*, +Function,+,dialog_ex_disable_extended_events,void,DialogEx* +Function,+,dialog_ex_enable_extended_events,void,DialogEx* +Function,+,dialog_ex_free,void,DialogEx* +Function,+,dialog_ex_get_view,View*,DialogEx* +Function,+,dialog_ex_reset,void,DialogEx* +Function,+,dialog_ex_set_center_button_text,void,"DialogEx*, const char*" +Function,+,dialog_ex_set_context,void,"DialogEx*, void*" +Function,+,dialog_ex_set_header,void,"DialogEx*, const char*, uint8_t, uint8_t, Align, Align" +Function,+,dialog_ex_set_icon,void,"DialogEx*, uint8_t, uint8_t, const Icon*" +Function,+,dialog_ex_set_left_button_text,void,"DialogEx*, const char*" +Function,+,dialog_ex_set_result_callback,void,"DialogEx*, DialogExResultCallback" +Function,+,dialog_ex_set_right_button_text,void,"DialogEx*, const char*" +Function,+,dialog_ex_set_text,void,"DialogEx*, const char*, uint8_t, uint8_t, Align, Align" +Function,+,dialog_file_browser_set_basic_options,void,"DialogsFileBrowserOptions*, const char*, const Icon*" +Function,+,dialog_file_browser_show,_Bool,"DialogsApp*, string_ptr, string_ptr, const DialogsFileBrowserOptions*" +Function,+,dialog_message_alloc,DialogMessage*, +Function,+,dialog_message_free,void,DialogMessage* +Function,+,dialog_message_set_buttons,void,"DialogMessage*, const char*, const char*, const char*" +Function,+,dialog_message_set_header,void,"DialogMessage*, const char*, uint8_t, uint8_t, Align, Align" +Function,+,dialog_message_set_icon,void,"DialogMessage*, const Icon*, uint8_t, uint8_t" +Function,+,dialog_message_set_text,void,"DialogMessage*, const char*, uint8_t, uint8_t, Align, Align" +Function,+,dialog_message_show,DialogMessageButton,"DialogsApp*, const DialogMessage*" +Function,+,dialog_message_show_storage_error,void,"DialogsApp*, const char*" +Function,-,digital_signal_alloc,DigitalSignal*,uint32_t +Function,-,digital_signal_append,_Bool,"DigitalSignal*, DigitalSignal*" +Function,-,digital_signal_free,void,DigitalSignal* +Function,-,digital_signal_get_edge,uint32_t,"DigitalSignal*, uint32_t" +Function,-,digital_signal_get_edges_cnt,uint32_t,DigitalSignal* +Function,-,digital_signal_get_start_level,_Bool,DigitalSignal* +Function,-,digital_signal_prepare_arr,void,DigitalSignal* +Function,-,digital_signal_send,void,"DigitalSignal*, const GpioPin*" +Function,-,diprintf,int,"int, const char*, ..." +Function,+,dir_walk_alloc,DirWalk*,Storage* +Function,+,dir_walk_close,void,DirWalk* +Function,+,dir_walk_free,void,DirWalk* +Function,+,dir_walk_get_error,FS_Error,DirWalk* +Function,+,dir_walk_open,_Bool,"DirWalk*, const char*" +Function,+,dir_walk_read,DirWalkResult,"DirWalk*, string_t, FileInfo*" +Function,+,dir_walk_set_filter_cb,void,"DirWalk*, DirWalkFilterCb, void*" +Function,+,dir_walk_set_recursive,void,"DirWalk*, _Bool" +Function,-,div,div_t,"int, int" +Function,+,dolphin_deed,void,"Dolphin*, DolphinDeed" +Function,+,dolphin_deed_get_app,DolphinApp,DolphinDeed +Function,+,dolphin_deed_get_app_limit,uint8_t,DolphinApp +Function,+,dolphin_deed_get_weight,uint8_t,DolphinDeed +Function,+,dolphin_flush,void,Dolphin* +Function,+,dolphin_get_pubsub,FuriPubSub*,Dolphin* +Function,+,dolphin_stats,DolphinStats,Dolphin* +Function,+,dolphin_upgrade_level,void,Dolphin* +Function,-,dprintf,int,"int, const char*, ..." +Function,-,drand48,double, +Function,-,drem,double,"double, double" +Function,-,dremf,float,"float, float" +Function,-,eTaskConfirmSleepModeStatus,eSleepModeStatus, +Function,-,eTaskGetState,eTaskState,TaskHandle_t +Function,+,elements_bold_rounded_frame,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t" +Function,+,elements_bubble,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t" +Function,+,elements_bubble_str,void,"Canvas*, uint8_t, uint8_t, const char*, Align, Align" +Function,+,elements_button_center,void,"Canvas*, const char*" +Function,+,elements_button_left,void,"Canvas*, const char*" +Function,+,elements_button_right,void,"Canvas*, const char*" +Function,+,elements_frame,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t" +Function,+,elements_multiline_text,void,"Canvas*, uint8_t, uint8_t, const char*" +Function,+,elements_multiline_text_aligned,void,"Canvas*, uint8_t, uint8_t, Align, Align, const char*" +Function,+,elements_multiline_text_framed,void,"Canvas*, uint8_t, uint8_t, const char*" +Function,+,elements_progress_bar,void,"Canvas*, uint8_t, uint8_t, uint8_t, float" +Function,+,elements_scrollbar,void,"Canvas*, uint16_t, uint16_t" +Function,+,elements_scrollbar_pos,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint16_t, uint16_t" +Function,+,elements_slightly_rounded_box,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t" +Function,+,elements_slightly_rounded_frame,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t" +Function,+,elements_string_fit_width,void,"Canvas*, string_t, uint8_t" +Function,+,elements_text_box,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t, Align, Align, const char*, _Bool" +Function,+,empty_screen_alloc,EmptyScreen*, +Function,+,empty_screen_free,void,EmptyScreen* +Function,+,empty_screen_get_view,View*,EmptyScreen* +Function,-,erand48,double,unsigned short[3] +Function,-,erf,double,double +Function,-,erfc,double,double +Function,-,erfcf,float,float +Function,-,erfcl,long double,long double +Function,-,erff,float,float +Function,-,erfl,long double,long double +Function,-,exit,void,int +Function,-,exp,double,double +Function,-,exp10,double,double +Function,-,exp10f,float,float +Function,-,exp2,double,double +Function,-,exp2f,float,float +Function,-,exp2l,long double,long double +Function,-,expf,float,float +Function,-,expl,long double,long double +Function,-,explicit_bzero,void,"void*, size_t" +Function,-,expm1,double,double +Function,-,expm1f,float,float +Function,-,expm1l,long double,long double +Function,-,fabs,double,double +Function,-,fabsf,float,float +Function,-,fabsl,long double,long double +Function,-,fclose,int,FILE* +Function,-,fcloseall,int, +Function,-,fdim,double,"double, double" +Function,-,fdimf,float,"float, float" +Function,-,fdiml,long double,"long double, long double" +Function,-,fdopen,FILE*,"int, const char*" +Function,-,feof,int,FILE* +Function,-,feof_unlocked,int,FILE* +Function,-,ferror,int,FILE* +Function,-,ferror_unlocked,int,FILE* +Function,-,fflush,int,FILE* +Function,-,fflush_unlocked,int,FILE* +Function,-,ffs,int,int +Function,-,ffsl,int,long +Function,-,ffsll,int,long long +Function,-,fgetc,int,FILE* +Function,-,fgetc_unlocked,int,FILE* +Function,-,fgetpos,int,"FILE*, fpos_t*" +Function,-,fgets,char*,"char*, int, FILE*" +Function,-,fgets_unlocked,char*,"char*, int, FILE*" +Function,+,file_browser_alloc,FileBrowser*,string_ptr +Function,+,file_browser_configure,void,"FileBrowser*, const char*, _Bool, const Icon*, _Bool" +Function,+,file_browser_free,void,FileBrowser* +Function,+,file_browser_get_view,View*,FileBrowser* +Function,+,file_browser_set_callback,void,"FileBrowser*, FileBrowserCallback, void*" +Function,+,file_browser_set_item_callback,void,"FileBrowser*, FileBrowserLoadItemCallback, void*" +Function,+,file_browser_start,void,"FileBrowser*, string_t" +Function,+,file_browser_stop,void,FileBrowser* +Function,+,file_browser_worker_alloc,BrowserWorker*,"string_t, const char*, _Bool" +Function,+,file_browser_worker_folder_enter,void,"BrowserWorker*, string_t, int32_t" +Function,+,file_browser_worker_folder_exit,void,BrowserWorker* +Function,+,file_browser_worker_folder_refresh,void,"BrowserWorker*, int32_t" +Function,+,file_browser_worker_free,void,BrowserWorker* +Function,+,file_browser_worker_load,void,"BrowserWorker*, uint32_t, uint32_t" +Function,+,file_browser_worker_set_callback_context,void,"BrowserWorker*, void*" +Function,+,file_browser_worker_set_config,void,"BrowserWorker*, string_t, const char*, _Bool" +Function,+,file_browser_worker_set_folder_callback,void,"BrowserWorker*, BrowserWorkerFolderOpenCallback" +Function,+,file_browser_worker_set_item_callback,void,"BrowserWorker*, BrowserWorkerListItemCallback" +Function,+,file_browser_worker_set_list_callback,void,"BrowserWorker*, BrowserWorkerListLoadCallback" +Function,+,file_browser_worker_set_long_load_callback,void,"BrowserWorker*, BrowserWorkerLongLoadCallback" +Function,+,file_stream_alloc,Stream*,Storage* +Function,+,file_stream_close,_Bool,Stream* +Function,+,file_stream_get_error,FS_Error,Stream* +Function,+,file_stream_open,_Bool,"Stream*, const char*, FS_AccessMode, FS_OpenMode" +Function,-,fileno,int,FILE* +Function,-,fileno_unlocked,int,FILE* +Function,+,filesystem_api_error_get_desc,const char*,FS_Error +Function,-,finite,int,double +Function,-,finitef,int,float +Function,-,finitel,int,long double +Function,-,fiprintf,int,"FILE*, const char*, ..." +Function,-,fiscanf,int,"FILE*, const char*, ..." +Function,+,flipper_application_alloc,FlipperApplication*,"Storage*, const ElfApiInterface*" +Function,+,flipper_application_free,void,FlipperApplication* +Function,-,flipper_application_get_entry_address,const void*,FlipperApplication* +Function,+,flipper_application_get_manifest,const FlipperApplicationManifest*,FlipperApplication* +Function,-,flipper_application_get_state,const FlipperApplicationState*,FlipperApplication* +Function,-,flipper_application_get_thread,FuriThread*,FlipperApplication* +Function,+,flipper_application_load_status_to_string,const char*,FlipperApplicationLoadStatus +Function,+,flipper_application_map_to_memory,FlipperApplicationLoadStatus,FlipperApplication* +Function,+,flipper_application_preload,FlipperApplicationPreloadStatus,"FlipperApplication*, const char*" +Function,-,flipper_application_preload_status_to_string,const char*,FlipperApplicationPreloadStatus +Function,+,flipper_application_spawn,FuriThread*,"FlipperApplication*, void*" +Function,+,flipper_format_buffered_file_alloc,FlipperFormat*,Storage* +Function,+,flipper_format_buffered_file_close,_Bool,FlipperFormat* +Function,+,flipper_format_buffered_file_open_existing,_Bool,"FlipperFormat*, const char*" +Function,+,flipper_format_delete_key,_Bool,"FlipperFormat*, const char*" +Function,+,flipper_format_file_alloc,FlipperFormat*,Storage* +Function,+,flipper_format_file_close,_Bool,FlipperFormat* +Function,+,flipper_format_file_open_always,_Bool,"FlipperFormat*, const char*" +Function,+,flipper_format_file_open_append,_Bool,"FlipperFormat*, const char*" +Function,+,flipper_format_file_open_existing,_Bool,"FlipperFormat*, const char*" +Function,+,flipper_format_file_open_new,_Bool,"FlipperFormat*, const char*" +Function,+,flipper_format_free,void,FlipperFormat* +Function,+,flipper_format_get_raw_stream,Stream*,FlipperFormat* +Function,+,flipper_format_get_value_count,_Bool,"FlipperFormat*, const char*, uint32_t*" +Function,+,flipper_format_insert_or_update_bool,_Bool,"FlipperFormat*, const char*, const _Bool*, const uint16_t" +Function,+,flipper_format_insert_or_update_float,_Bool,"FlipperFormat*, const char*, const float*, const uint16_t" +Function,+,flipper_format_insert_or_update_hex,_Bool,"FlipperFormat*, const char*, const uint8_t*, const uint16_t" +Function,+,flipper_format_insert_or_update_int32,_Bool,"FlipperFormat*, const char*, const int32_t*, const uint16_t" +Function,+,flipper_format_insert_or_update_string,_Bool,"FlipperFormat*, const char*, string_t" +Function,+,flipper_format_insert_or_update_string_cstr,_Bool,"FlipperFormat*, const char*, const char*" +Function,+,flipper_format_insert_or_update_uint32,_Bool,"FlipperFormat*, const char*, const uint32_t*, const uint16_t" +Function,+,flipper_format_key_exist,_Bool,"FlipperFormat*, const char*" +Function,+,flipper_format_read_bool,_Bool,"FlipperFormat*, const char*, _Bool*, const uint16_t" +Function,+,flipper_format_read_float,_Bool,"FlipperFormat*, const char*, float*, const uint16_t" +Function,+,flipper_format_read_header,_Bool,"FlipperFormat*, string_t, uint32_t*" +Function,+,flipper_format_read_hex,_Bool,"FlipperFormat*, const char*, uint8_t*, const uint16_t" +Function,+,flipper_format_read_hex_uint64,_Bool,"FlipperFormat*, const char*, uint64_t*, const uint16_t" +Function,+,flipper_format_read_int32,_Bool,"FlipperFormat*, const char*, int32_t*, const uint16_t" +Function,+,flipper_format_read_string,_Bool,"FlipperFormat*, const char*, string_t" +Function,+,flipper_format_read_uint32,_Bool,"FlipperFormat*, const char*, uint32_t*, const uint16_t" +Function,+,flipper_format_rewind,_Bool,FlipperFormat* +Function,+,flipper_format_seek_to_end,_Bool,FlipperFormat* +Function,+,flipper_format_set_strict_mode,void,"FlipperFormat*, _Bool" +Function,+,flipper_format_string_alloc,FlipperFormat*, +Function,+,flipper_format_update_bool,_Bool,"FlipperFormat*, const char*, const _Bool*, const uint16_t" +Function,+,flipper_format_update_float,_Bool,"FlipperFormat*, const char*, const float*, const uint16_t" +Function,+,flipper_format_update_hex,_Bool,"FlipperFormat*, const char*, const uint8_t*, const uint16_t" +Function,+,flipper_format_update_int32,_Bool,"FlipperFormat*, const char*, const int32_t*, const uint16_t" +Function,+,flipper_format_update_string,_Bool,"FlipperFormat*, const char*, string_t" +Function,+,flipper_format_update_string_cstr,_Bool,"FlipperFormat*, const char*, const char*" +Function,+,flipper_format_update_uint32,_Bool,"FlipperFormat*, const char*, const uint32_t*, const uint16_t" +Function,+,flipper_format_write_bool,_Bool,"FlipperFormat*, const char*, const _Bool*, const uint16_t" +Function,+,flipper_format_write_comment,_Bool,"FlipperFormat*, string_t" +Function,+,flipper_format_write_comment_cstr,_Bool,"FlipperFormat*, const char*" +Function,+,flipper_format_write_float,_Bool,"FlipperFormat*, const char*, const float*, const uint16_t" +Function,+,flipper_format_write_header,_Bool,"FlipperFormat*, string_t, const uint32_t" +Function,+,flipper_format_write_header_cstr,_Bool,"FlipperFormat*, const char*, const uint32_t" +Function,+,flipper_format_write_hex,_Bool,"FlipperFormat*, const char*, const uint8_t*, const uint16_t" +Function,+,flipper_format_write_hex_uint64,_Bool,"FlipperFormat*, const char*, const uint64_t*, const uint16_t" +Function,+,flipper_format_write_int32,_Bool,"FlipperFormat*, const char*, const int32_t*, const uint16_t" +Function,+,flipper_format_write_string,_Bool,"FlipperFormat*, const char*, string_t" +Function,+,flipper_format_write_string_cstr,_Bool,"FlipperFormat*, const char*, const char*" +Function,+,flipper_format_write_uint32,_Bool,"FlipperFormat*, const char*, const uint32_t*, const uint16_t" +Function,-,flockfile,void,FILE* +Function,-,floor,double,double +Function,-,floorf,float,float +Function,-,floorl,long double,long double +Function,-,fls,int,int +Function,-,flsl,int,long +Function,-,flsll,int,long long +Function,-,fma,double,"double, double, double" +Function,-,fmaf,float,"float, float, float" +Function,-,fmal,long double,"long double, long double, long double" +Function,-,fmax,double,"double, double" +Function,-,fmaxf,float,"float, float" +Function,-,fmaxl,long double,"long double, long double" +Function,-,fmemopen,FILE*,"void*, size_t, const char*" +Function,-,fmin,double,"double, double" +Function,-,fminf,float,"float, float" +Function,-,fminl,long double,"long double, long double" +Function,-,fmod,double,"double, double" +Function,-,fmodf,float,"float, float" +Function,-,fmodl,long double,"long double, long double" +Function,-,fopen,FILE*,"const char*, const char*" +Function,-,fopencookie,FILE*,"void*, const char*, cookie_io_functions_t" +Function,-,fprintf,int,"FILE*, const char*, ..." +Function,-,fpurge,int,FILE* +Function,-,fputc,int,"int, FILE*" +Function,-,fputc_unlocked,int,"int, FILE*" +Function,-,fputs,int,"const char*, FILE*" +Function,-,fputs_unlocked,int,"const char*, FILE*" +Function,-,fread,size_t,"void*, size_t, size_t, FILE*" +Function,-,fread_unlocked,size_t,"void*, size_t, size_t, FILE*" +Function,+,free,void,void* +Function,-,freopen,FILE*,"const char*, const char*, FILE*" +Function,-,frexp,double,"double, int*" +Function,-,frexpf,float,"float, int*" +Function,-,frexpl,long double,"long double, int*" +Function,-,fscanf,int,"FILE*, const char*, ..." +Function,-,fseek,int,"FILE*, long, int" +Function,-,fseeko,int,"FILE*, off_t, int" +Function,-,fsetpos,int,"FILE*, const fpos_t*" +Function,-,ftell,long,FILE* +Function,-,ftello,off_t,FILE* +Function,-,ftrylockfile,int,FILE* +Function,-,funlockfile,void,FILE* +Function,-,funopen,FILE*,"const void*, int (*)(void*, char*, int), int (*)(void*, const char*, int), fpos_t (*)(void*, fpos_t, int), int (*)(void*)" +Function,+,furi_crash,void,const char* +Function,+,furi_delay_ms,void,uint32_t +Function,+,furi_delay_tick,void,uint32_t +Function,+,furi_delay_until_tick,FuriStatus,uint32_t +Function,+,furi_delay_us,void,uint32_t +Function,+,furi_event_flag_alloc,FuriEventFlag*, +Function,+,furi_event_flag_clear,uint32_t,"FuriEventFlag*, uint32_t" +Function,+,furi_event_flag_free,void,FuriEventFlag* +Function,+,furi_event_flag_get,uint32_t,FuriEventFlag* +Function,+,furi_event_flag_set,uint32_t,"FuriEventFlag*, uint32_t" +Function,+,furi_event_flag_wait,uint32_t,"FuriEventFlag*, uint32_t, uint32_t, uint32_t" +Function,+,furi_get_tick,uint32_t, +Function,+,furi_hal_bt_change_app,_Bool,"FuriHalBtProfile, GapEventCallback, void*" +Function,+,furi_hal_bt_clear_white_list,_Bool, +Function,+,furi_hal_bt_dump_state,void,string_t +Function,+,furi_hal_bt_ensure_c2_mode,_Bool,BleGlueC2Mode +Function,+,furi_hal_bt_get_key_storage_buff,void,"uint8_t**, uint16_t*" +Function,+,furi_hal_bt_get_radio_stack,FuriHalBtStack, +Function,+,furi_hal_bt_get_rssi,float, +Function,+,furi_hal_bt_get_transmitted_packets,uint32_t, +Function,+,furi_hal_bt_hid_consumer_key_press,_Bool,uint16_t +Function,+,furi_hal_bt_hid_consumer_key_release,_Bool,uint16_t +Function,+,furi_hal_bt_hid_consumer_key_release_all,_Bool, +Function,+,furi_hal_bt_hid_kb_press,_Bool,uint16_t +Function,+,furi_hal_bt_hid_kb_release,_Bool,uint16_t +Function,+,furi_hal_bt_hid_kb_release_all,_Bool, +Function,+,furi_hal_bt_hid_mouse_move,_Bool,"int8_t, int8_t" +Function,+,furi_hal_bt_hid_mouse_press,_Bool,uint8_t +Function,+,furi_hal_bt_hid_mouse_release,_Bool,uint8_t +Function,+,furi_hal_bt_hid_mouse_release_all,_Bool, +Function,+,furi_hal_bt_hid_mouse_scroll,_Bool,int8_t +Function,+,furi_hal_bt_hid_start,void, +Function,+,furi_hal_bt_hid_stop,void, +Function,-,furi_hal_bt_init,void, +Function,+,furi_hal_bt_is_active,_Bool, +Function,+,furi_hal_bt_is_alive,_Bool, +Function,+,furi_hal_bt_is_ble_gatt_gap_supported,_Bool, +Function,+,furi_hal_bt_is_testing_supported,_Bool, +Function,+,furi_hal_bt_lock_core2,void, +Function,+,furi_hal_bt_nvm_sram_sem_acquire,void, +Function,+,furi_hal_bt_nvm_sram_sem_release,void, +Function,+,furi_hal_bt_reinit,void, +Function,+,furi_hal_bt_serial_notify_buffer_is_empty,void, +Function,+,furi_hal_bt_serial_set_event_callback,void,"uint16_t, FuriHalBtSerialCallback, void*" +Function,+,furi_hal_bt_serial_start,void, +Function,+,furi_hal_bt_serial_stop,void, +Function,+,furi_hal_bt_serial_tx,_Bool,"uint8_t*, uint16_t" +Function,+,furi_hal_bt_set_key_storage_change_callback,void,"BleGlueKeyStorageChangedCallback, void*" +Function,+,furi_hal_bt_start_advertising,void, +Function,+,furi_hal_bt_start_app,_Bool,"FuriHalBtProfile, GapEventCallback, void*" +Function,+,furi_hal_bt_start_packet_rx,void,"uint8_t, uint8_t" +Function,+,furi_hal_bt_start_packet_tx,void,"uint8_t, uint8_t, uint8_t" +Function,+,furi_hal_bt_start_radio_stack,_Bool, +Function,+,furi_hal_bt_start_rx,void,uint8_t +Function,+,furi_hal_bt_start_tone_tx,void,"uint8_t, uint8_t" +Function,+,furi_hal_bt_stop_advertising,void, +Function,+,furi_hal_bt_stop_packet_test,uint16_t, +Function,+,furi_hal_bt_stop_rx,void, +Function,+,furi_hal_bt_stop_tone_tx,void, +Function,+,furi_hal_bt_unlock_core2,void, +Function,+,furi_hal_bt_update_battery_level,void,uint8_t +Function,+,furi_hal_bt_update_power_state,void, +Function,+,furi_hal_cdc_get_ctrl_line_state,uint8_t,uint8_t +Function,+,furi_hal_cdc_get_port_settings,usb_cdc_line_coding*,uint8_t +Function,+,furi_hal_cdc_receive,int32_t,"uint8_t, uint8_t*, uint16_t" +Function,+,furi_hal_cdc_send,void,"uint8_t, uint8_t*, uint16_t" +Function,+,furi_hal_cdc_set_callbacks,void,"uint8_t, CdcCallbacks*, void*" +Function,+,furi_hal_clock_deinit_early,void, +Function,-,furi_hal_clock_init,void, +Function,-,furi_hal_clock_init_early,void, +Function,-,furi_hal_clock_resume_tick,void, +Function,-,furi_hal_clock_suspend_tick,void, +Function,-,furi_hal_clock_switch_to_hsi,void, +Function,-,furi_hal_clock_switch_to_pll,void, +Function,-,furi_hal_compress_alloc,FuriHalCompress*,uint16_t +Function,-,furi_hal_compress_decode,_Bool,"FuriHalCompress*, uint8_t*, size_t, uint8_t*, size_t, size_t*" +Function,-,furi_hal_compress_encode,_Bool,"FuriHalCompress*, uint8_t*, size_t, uint8_t*, size_t, size_t*" +Function,-,furi_hal_compress_free,void,FuriHalCompress* +Function,-,furi_hal_compress_icon_decode,void,"const uint8_t*, uint8_t**" +Function,-,furi_hal_compress_icon_init,void, +Function,+,furi_hal_console_disable,void, +Function,+,furi_hal_console_enable,void, +Function,-,furi_hal_console_init,void, +Function,+,furi_hal_console_printf,void,"const char[], ..." +Function,+,furi_hal_console_puts,void,const char* +Function,+,furi_hal_console_set_tx_callback,void,"FuriHalConsoleTxCallback, void*" +Function,+,furi_hal_console_tx,void,"const uint8_t*, size_t" +Function,+,furi_hal_console_tx_with_new_line,void,"const uint8_t*, size_t" +Function,+,furi_hal_cortex_delay_us,void,uint32_t +Function,-,furi_hal_cortex_init_early,void, +Function,+,furi_hal_cortex_instructions_per_microsecond,uint32_t, +Function,+,furi_hal_crypto_decrypt,_Bool,"const uint8_t*, uint8_t*, size_t" +Function,+,furi_hal_crypto_encrypt,_Bool,"const uint8_t*, uint8_t*, size_t" +Function,-,furi_hal_crypto_init,void, +Function,+,furi_hal_crypto_store_add_key,_Bool,"FuriHalCryptoKey*, uint8_t*" +Function,+,furi_hal_crypto_store_load_key,_Bool,"uint8_t, const uint8_t*" +Function,+,furi_hal_crypto_store_unload_key,_Bool,uint8_t +Function,+,furi_hal_crypto_verify_enclave,_Bool,"uint8_t*, uint8_t*" +Function,+,furi_hal_crypto_verify_key,_Bool,uint8_t +Function,+,furi_hal_debug_disable,void, +Function,+,furi_hal_debug_enable,void, +Function,-,furi_hal_deinit_early,void, +Function,-,furi_hal_flash_erase,_Bool,uint8_t +Function,-,furi_hal_flash_get_base,size_t, +Function,-,furi_hal_flash_get_cycles_count,size_t, +Function,-,furi_hal_flash_get_free_end_address,const void*, +Function,-,furi_hal_flash_get_free_page_count,size_t, +Function,-,furi_hal_flash_get_free_page_start_address,size_t, +Function,-,furi_hal_flash_get_free_start_address,const void*, +Function,-,furi_hal_flash_get_page_number,int16_t,size_t +Function,-,furi_hal_flash_get_page_size,size_t, +Function,-,furi_hal_flash_get_read_block_size,size_t, +Function,-,furi_hal_flash_get_write_block_size,size_t, +Function,-,furi_hal_flash_init,void, +Function,-,furi_hal_flash_ob_apply,void, +Function,-,furi_hal_flash_ob_get_raw_ptr,const FuriHalFlashRawOptionByteData*, +Function,-,furi_hal_flash_ob_set_word,_Bool,"size_t, const uint32_t" +Function,-,furi_hal_flash_program_page,_Bool,"const uint8_t, const uint8_t*, uint16_t" +Function,-,furi_hal_flash_write_dword,_Bool,"size_t, uint64_t" +Function,+,furi_hal_gpio_add_int_callback,void,"const GpioPin*, GpioExtiCallback, void*" +Function,+,furi_hal_gpio_disable_int_callback,void,const GpioPin* +Function,+,furi_hal_gpio_enable_int_callback,void,const GpioPin* +Function,+,furi_hal_gpio_init,void,"const GpioPin*, const GpioMode, const GpioPull, const GpioSpeed" +Function,+,furi_hal_gpio_init_ex,void,"const GpioPin*, const GpioMode, const GpioPull, const GpioSpeed, const GpioAltFn" +Function,+,furi_hal_gpio_init_simple,void,"const GpioPin*, const GpioMode" +Function,+,furi_hal_gpio_remove_int_callback,void,const GpioPin* +Function,+,furi_hal_hid_consumer_key_press,_Bool,uint16_t +Function,+,furi_hal_hid_consumer_key_release,_Bool,uint16_t +Function,+,furi_hal_hid_get_led_state,uint8_t, +Function,+,furi_hal_hid_is_connected,_Bool, +Function,+,furi_hal_hid_kb_press,_Bool,uint16_t +Function,+,furi_hal_hid_kb_release,_Bool,uint16_t +Function,+,furi_hal_hid_kb_release_all,_Bool, +Function,+,furi_hal_hid_mouse_move,_Bool,"int8_t, int8_t" +Function,+,furi_hal_hid_mouse_press,_Bool,uint8_t +Function,+,furi_hal_hid_mouse_release,_Bool,uint8_t +Function,+,furi_hal_hid_mouse_scroll,_Bool,int8_t +Function,+,furi_hal_hid_set_state_callback,void,"HidStateCallback, void*" +Function,+,furi_hal_hid_u2f_get_request,uint32_t,uint8_t* +Function,+,furi_hal_hid_u2f_is_connected,_Bool, +Function,+,furi_hal_hid_u2f_send_response,void,"uint8_t*, uint8_t" +Function,+,furi_hal_hid_u2f_set_callback,void,"HidU2fCallback, void*" +Function,+,furi_hal_i2c_acquire,void,FuriHalI2cBusHandle* +Function,+,furi_hal_i2c_deinit_early,void, +Function,-,furi_hal_i2c_init,void, +Function,-,furi_hal_i2c_init_early,void, +Function,+,furi_hal_i2c_is_device_ready,_Bool,"FuriHalI2cBusHandle*, uint8_t, uint32_t" +Function,+,furi_hal_i2c_read_mem,_Bool,"FuriHalI2cBusHandle*, uint8_t, uint8_t, uint8_t*, uint8_t, uint32_t" +Function,+,furi_hal_i2c_read_reg_16,_Bool,"FuriHalI2cBusHandle*, uint8_t, uint8_t, uint16_t*, uint32_t" +Function,+,furi_hal_i2c_read_reg_8,_Bool,"FuriHalI2cBusHandle*, uint8_t, uint8_t, uint8_t*, uint32_t" +Function,+,furi_hal_i2c_release,void,FuriHalI2cBusHandle* +Function,+,furi_hal_i2c_rx,_Bool,"FuriHalI2cBusHandle*, const uint8_t, uint8_t*, const uint8_t, uint32_t" +Function,+,furi_hal_i2c_trx,_Bool,"FuriHalI2cBusHandle*, const uint8_t, const uint8_t*, const uint8_t, uint8_t*, const uint8_t, uint32_t" +Function,+,furi_hal_i2c_tx,_Bool,"FuriHalI2cBusHandle*, const uint8_t, const uint8_t*, const uint8_t, uint32_t" +Function,+,furi_hal_i2c_write_mem,_Bool,"FuriHalI2cBusHandle*, uint8_t, uint8_t, uint8_t*, uint8_t, uint32_t" +Function,+,furi_hal_i2c_write_reg_16,_Bool,"FuriHalI2cBusHandle*, uint8_t, uint8_t, uint16_t, uint32_t" +Function,+,furi_hal_i2c_write_reg_8,_Bool,"FuriHalI2cBusHandle*, uint8_t, uint8_t, uint8_t, uint32_t" +Function,+,furi_hal_ibutton_add_interrupt,void,"GpioExtiCallback, void*" +Function,+,furi_hal_ibutton_emulate_set_next,void,uint32_t +Function,+,furi_hal_ibutton_emulate_start,void,"uint32_t, FuriHalIbuttonEmulateCallback, void*" +Function,+,furi_hal_ibutton_emulate_stop,void, +Function,-,furi_hal_ibutton_init,void, +Function,+,furi_hal_ibutton_pin_get_level,_Bool, +Function,+,furi_hal_ibutton_pin_high,void, +Function,+,furi_hal_ibutton_pin_low,void, +Function,+,furi_hal_ibutton_remove_interrupt,void, +Function,+,furi_hal_ibutton_start_drive,void, +Function,+,furi_hal_ibutton_start_drive_in_isr,void, +Function,+,furi_hal_ibutton_start_interrupt,void, +Function,+,furi_hal_ibutton_start_interrupt_in_isr,void, +Function,+,furi_hal_ibutton_stop,void, +Function,+,furi_hal_info_get,void,"FuriHalInfoValueCallback, void*" +Function,+,furi_hal_infrared_async_rx_set_capture_isr_callback,void,"FuriHalInfraredRxCaptureCallback, void*" +Function,+,furi_hal_infrared_async_rx_set_timeout,void,uint32_t +Function,+,furi_hal_infrared_async_rx_set_timeout_isr_callback,void,"FuriHalInfraredRxTimeoutCallback, void*" +Function,+,furi_hal_infrared_async_rx_start,void, +Function,+,furi_hal_infrared_async_rx_stop,void, +Function,+,furi_hal_infrared_async_tx_set_data_isr_callback,void,"FuriHalInfraredTxGetDataISRCallback, void*" +Function,+,furi_hal_infrared_async_tx_set_signal_sent_isr_callback,void,"FuriHalInfraredTxSignalSentISRCallback, void*" +Function,+,furi_hal_infrared_async_tx_start,void,"uint32_t, float" +Function,+,furi_hal_infrared_async_tx_stop,void, +Function,+,furi_hal_infrared_async_tx_wait_termination,void, +Function,+,furi_hal_infrared_is_busy,_Bool, +Function,-,furi_hal_init,void, +Function,-,furi_hal_init_early,void, +Function,-,furi_hal_interrupt_init,void, +Function,+,furi_hal_interrupt_set_isr,void,"FuriHalInterruptId, FuriHalInterruptISR, void*" +Function,+,furi_hal_interrupt_set_isr_ex,void,"FuriHalInterruptId, uint16_t, FuriHalInterruptISR, void*" +Function,+,furi_hal_light_blink_set_color,void,Light +Function,+,furi_hal_light_blink_start,void,"Light, uint8_t, uint16_t, uint16_t" +Function,+,furi_hal_light_blink_stop,void, +Function,-,furi_hal_light_init,void, +Function,+,furi_hal_light_sequence,void,const char* +Function,+,furi_hal_light_set,void,"Light, uint8_t" +Function,+,furi_hal_memory_alloc,void*,size_t +Function,+,furi_hal_memory_get_free,size_t, +Function,+,furi_hal_memory_init,void, +Function,+,furi_hal_memory_max_pool_block,size_t, +Function,+,furi_hal_mpu_disable,void, +Function,+,furi_hal_mpu_enable,void, +Function,-,furi_hal_mpu_init,void, +Function,+,furi_hal_mpu_protect_disable,void,FuriHalMpuRegion +Function,+,furi_hal_mpu_protect_no_access,void,"FuriHalMpuRegion, uint32_t, FuriHalMPURegionSize" +Function,+,furi_hal_mpu_protect_read_only,void,"FuriHalMpuRegion, uint32_t, FuriHalMPURegionSize" +Function,+,furi_hal_nfc_activate_nfca,_Bool,"uint32_t, uint32_t*" +Function,+,furi_hal_nfc_detect,_Bool,"FuriHalNfcDevData*, uint32_t" +Function,+,furi_hal_nfc_emulate_nfca,_Bool,"uint8_t*, uint8_t, uint8_t*, uint8_t, FuriHalNfcEmulateCallback, void*, uint32_t" +Function,+,furi_hal_nfc_exit_sleep,void, +Function,+,furi_hal_nfc_field_off,void, +Function,+,furi_hal_nfc_field_on,void, +Function,-,furi_hal_nfc_init,void, +Function,+,furi_hal_nfc_is_busy,_Bool, +Function,+,furi_hal_nfc_is_init,_Bool, +Function,+,furi_hal_nfc_listen,_Bool,"uint8_t*, uint8_t, uint8_t*, uint8_t, _Bool, uint32_t" +Function,+,furi_hal_nfc_listen_rx,_Bool,"FuriHalNfcTxRxContext*, uint32_t" +Function,+,furi_hal_nfc_listen_sleep,void, +Function,+,furi_hal_nfc_listen_start,void,FuriHalNfcDevData* +Function,+,furi_hal_nfc_ll_poll,void, +Function,+,furi_hal_nfc_ll_set_error_handling,void,FuriHalNfcErrorHandling +Function,+,furi_hal_nfc_ll_set_fdt_listen,void,uint32_t +Function,+,furi_hal_nfc_ll_set_fdt_poll,void,uint32_t +Function,+,furi_hal_nfc_ll_set_guard_time,void,uint32_t +Function,+,furi_hal_nfc_ll_set_mode,FuriHalNfcReturn,"FuriHalNfcMode, FuriHalNfcBitrate, FuriHalNfcBitrate" +Function,+,furi_hal_nfc_ll_txrx,FuriHalNfcReturn,"uint8_t*, uint16_t, uint8_t*, uint16_t, uint16_t*, uint32_t, uint32_t" +Function,+,furi_hal_nfc_ll_txrx_off,void, +Function,+,furi_hal_nfc_ll_txrx_on,void, +Function,+,furi_hal_nfc_sleep,void, +Function,+,furi_hal_nfc_start_sleep,void, +Function,+,furi_hal_nfc_stop,void, +Function,+,furi_hal_nfc_stop_cmd,void, +Function,+,furi_hal_nfc_tx_rx,_Bool,"FuriHalNfcTxRxContext*, uint16_t" +Function,+,furi_hal_nfc_tx_rx_full,_Bool,FuriHalNfcTxRxContext* +Function,-,furi_hal_os_init,void, +Function,+,furi_hal_os_tick,void, +Function,+,furi_hal_power_check_otg_status,void, +Function,+,furi_hal_power_deep_sleep_available,_Bool, +Function,+,furi_hal_power_disable_external_3_3v,void, +Function,+,furi_hal_power_disable_otg,void, +Function,+,furi_hal_power_dump_state,void, +Function,+,furi_hal_power_enable_external_3_3v,void, +Function,+,furi_hal_power_enable_otg,void, +Function,+,furi_hal_power_gauge_is_ok,_Bool, +Function,+,furi_hal_power_get_bat_health_pct,uint8_t, +Function,+,furi_hal_power_get_battery_current,float,FuriHalPowerIC +Function,+,furi_hal_power_get_battery_design_capacity,uint32_t, +Function,+,furi_hal_power_get_battery_full_capacity,uint32_t, +Function,+,furi_hal_power_get_battery_remaining_capacity,uint32_t, +Function,+,furi_hal_power_get_battery_temperature,float,FuriHalPowerIC +Function,+,furi_hal_power_get_battery_voltage,float,FuriHalPowerIC +Function,+,furi_hal_power_get_pct,uint8_t, +Function,+,furi_hal_power_get_usb_voltage,float, +Function,+,furi_hal_power_info_get,void,"FuriHalPowerInfoCallback, void*" +Function,-,furi_hal_power_init,void, +Function,+,furi_hal_power_insomnia_enter,void, +Function,+,furi_hal_power_insomnia_exit,void, +Function,-,furi_hal_power_insomnia_level,uint16_t, +Function,+,furi_hal_power_is_charging,_Bool, +Function,+,furi_hal_power_is_otg_enabled,_Bool, +Function,+,furi_hal_power_off,void, +Function,+,furi_hal_power_reset,void, +Function,+,furi_hal_power_shutdown,void, +Function,+,furi_hal_power_sleep,void, +Function,+,furi_hal_power_sleep_available,_Bool, +Function,+,furi_hal_power_suppress_charge_enter,void, +Function,+,furi_hal_power_suppress_charge_exit,void, +Function,+,furi_hal_random_fill_buf,void,"uint8_t*, uint32_t" +Function,+,furi_hal_random_get,uint32_t, +Function,+,furi_hal_region_get,const FuriHalRegion*, +Function,+,furi_hal_region_get_band,const FuriHalRegionBand*,uint32_t +Function,+,furi_hal_region_get_name,const char*, +Function,-,furi_hal_region_init,void, +Function,+,furi_hal_region_is_frequency_allowed,_Bool,uint32_t +Function,+,furi_hal_region_is_provisioned,_Bool, +Function,+,furi_hal_region_set,void,FuriHalRegion* +Function,+,furi_hal_resources_deinit_early,void, +Function,-,furi_hal_resources_init,void, +Function,-,furi_hal_resources_init_early,void, +Function,+,furi_hal_rfid_change_read_config,void,"float, float" +Function,+,furi_hal_rfid_comp_set_callback,void,"FuriHalRfidCompCallback, void*" +Function,+,furi_hal_rfid_comp_start,void, +Function,+,furi_hal_rfid_comp_stop,void, +Function,-,furi_hal_rfid_init,void, +Function,+,furi_hal_rfid_pin_pull_pulldown,void, +Function,+,furi_hal_rfid_pin_pull_release,void, +Function,+,furi_hal_rfid_pins_emulate,void, +Function,+,furi_hal_rfid_pins_read,void, +Function,+,furi_hal_rfid_pins_reset,void, +Function,+,furi_hal_rfid_set_emulate_period,void,uint32_t +Function,+,furi_hal_rfid_set_emulate_pulse,void,uint32_t +Function,+,furi_hal_rfid_set_read_period,void,uint32_t +Function,+,furi_hal_rfid_set_read_pulse,void,uint32_t +Function,+,furi_hal_rfid_tim_emulate,void,float +Function,+,furi_hal_rfid_tim_emulate_dma_start,void,"uint32_t*, uint32_t*, size_t, FuriHalRfidDMACallback, void*" +Function,+,furi_hal_rfid_tim_emulate_dma_stop,void, +Function,+,furi_hal_rfid_tim_emulate_start,void,"FuriHalRfidEmulateCallback, void*" +Function,+,furi_hal_rfid_tim_emulate_stop,void, +Function,+,furi_hal_rfid_tim_read,void,"float, float" +Function,+,furi_hal_rfid_tim_read_capture_start,void,"FuriHalRfidReadCaptureCallback, void*" +Function,+,furi_hal_rfid_tim_read_capture_stop,void, +Function,+,furi_hal_rfid_tim_read_start,void, +Function,+,furi_hal_rfid_tim_read_stop,void, +Function,+,furi_hal_rfid_tim_reset,void, +Function,+,furi_hal_rtc_datetime_to_timestamp,uint32_t,FuriHalRtcDateTime* +Function,+,furi_hal_rtc_deinit_early,void, +Function,+,furi_hal_rtc_get_boot_mode,FuriHalRtcBootMode, +Function,+,furi_hal_rtc_get_datetime,void,FuriHalRtcDateTime* +Function,+,furi_hal_rtc_get_fault_data,uint32_t, +Function,+,furi_hal_rtc_get_log_level,uint8_t, +Function,+,furi_hal_rtc_get_pin_fails,uint32_t, +Function,+,furi_hal_rtc_get_register,uint32_t,FuriHalRtcRegister +Function,-,furi_hal_rtc_init,void, +Function,-,furi_hal_rtc_init_early,void, +Function,+,furi_hal_rtc_is_flag_set,_Bool,FuriHalRtcFlag +Function,+,furi_hal_rtc_reset_flag,void,FuriHalRtcFlag +Function,+,furi_hal_rtc_set_boot_mode,void,FuriHalRtcBootMode +Function,+,furi_hal_rtc_set_datetime,void,FuriHalRtcDateTime* +Function,+,furi_hal_rtc_set_fault_data,void,uint32_t +Function,+,furi_hal_rtc_set_flag,void,FuriHalRtcFlag +Function,+,furi_hal_rtc_set_log_level,void,uint8_t +Function,+,furi_hal_rtc_set_pin_fails,void,uint32_t +Function,+,furi_hal_rtc_set_register,void,"FuriHalRtcRegister, uint32_t" +Function,+,furi_hal_rtc_validate_datetime,_Bool,FuriHalRtcDateTime* +Function,-,furi_hal_speaker_init,void, +Function,+,furi_hal_speaker_set_volume,void,float +Function,+,furi_hal_speaker_start,void,"float, float" +Function,+,furi_hal_speaker_stop,void, +Function,+,furi_hal_spi_acquire,void,FuriHalSpiBusHandle* +Function,+,furi_hal_spi_bus_deinit,void,FuriHalSpiBus* +Function,+,furi_hal_spi_bus_handle_deinit,void,FuriHalSpiBusHandle* +Function,+,furi_hal_spi_bus_handle_init,void,FuriHalSpiBusHandle* +Function,+,furi_hal_spi_bus_init,void,FuriHalSpiBus* +Function,+,furi_hal_spi_bus_rx,_Bool,"FuriHalSpiBusHandle*, uint8_t*, size_t, uint32_t" +Function,+,furi_hal_spi_bus_trx,_Bool,"FuriHalSpiBusHandle*, uint8_t*, uint8_t*, size_t, uint32_t" +Function,+,furi_hal_spi_bus_tx,_Bool,"FuriHalSpiBusHandle*, uint8_t*, size_t, uint32_t" +Function,+,furi_hal_spi_deinit_early,void, +Function,-,furi_hal_spi_init,void, +Function,+,furi_hal_spi_init_early,void, +Function,+,furi_hal_spi_release,void,FuriHalSpiBusHandle* +Function,-,furi_hal_subghz_dump_state,void, +Function,+,furi_hal_subghz_flush_rx,void, +Function,+,furi_hal_subghz_flush_tx,void, +Function,+,furi_hal_subghz_get_lqi,uint8_t, +Function,+,furi_hal_subghz_get_rssi,float, +Function,+,furi_hal_subghz_idle,void, +Function,-,furi_hal_subghz_init,void, +Function,+,furi_hal_subghz_is_async_tx_complete,_Bool, +Function,+,furi_hal_subghz_is_frequency_valid,_Bool,uint32_t +Function,+,furi_hal_subghz_is_rx_data_crc_valid,_Bool, +Function,+,furi_hal_subghz_load_custom_preset,void,uint8_t* +Function,+,furi_hal_subghz_load_patable,void,const uint8_t[8] +Function,+,furi_hal_subghz_load_preset,void,FuriHalSubGhzPreset +Function,+,furi_hal_subghz_load_registers,void,uint8_t* +Function,+,furi_hal_subghz_read_packet,void,"uint8_t*, uint8_t*" +Function,+,furi_hal_subghz_reset,void, +Function,+,furi_hal_subghz_rx,void, +Function,+,furi_hal_subghz_rx_pipe_not_empty,_Bool, +Function,+,furi_hal_subghz_set_frequency,uint32_t,uint32_t +Function,+,furi_hal_subghz_set_frequency_and_path,uint32_t,uint32_t +Function,+,furi_hal_subghz_set_path,void,FuriHalSubGhzPath +Function,-,furi_hal_subghz_shutdown,void, +Function,+,furi_hal_subghz_sleep,void, +Function,+,furi_hal_subghz_start_async_rx,void,"FuriHalSubGhzCaptureCallback, void*" +Function,+,furi_hal_subghz_start_async_tx,_Bool,"FuriHalSubGhzAsyncTxCallback, void*" +Function,+,furi_hal_subghz_stop_async_rx,void, +Function,+,furi_hal_subghz_stop_async_tx,void, +Function,+,furi_hal_subghz_tx,_Bool, +Function,+,furi_hal_subghz_write_packet,void,"const uint8_t*, uint8_t" +Function,+,furi_hal_switch,void,void* +Function,+,furi_hal_uart_deinit,void,FuriHalUartId +Function,+,furi_hal_uart_init,void,"FuriHalUartId, uint32_t" +Function,+,furi_hal_uart_resume,void,FuriHalUartId +Function,+,furi_hal_uart_set_br,void,"FuriHalUartId, uint32_t" +Function,+,furi_hal_uart_set_irq_cb,void,"FuriHalUartId, void (*)(UartIrqEvent, uint8_t, void*), void*" +Function,+,furi_hal_uart_suspend,void,FuriHalUartId +Function,+,furi_hal_uart_tx,void,"FuriHalUartId, uint8_t*, size_t" +Function,+,furi_hal_usb_disable,void, +Function,+,furi_hal_usb_enable,void, +Function,+,furi_hal_usb_get_config,FuriHalUsbInterface*, +Function,-,furi_hal_usb_init,void, +Function,+,furi_hal_usb_is_locked,_Bool, +Function,+,furi_hal_usb_lock,void, +Function,+,furi_hal_usb_reinit,void, +Function,+,furi_hal_usb_set_config,_Bool,"FuriHalUsbInterface*, void*" +Function,-,furi_hal_usb_set_state_callback,void,"FuriHalUsbStateCallback, void*" +Function,+,furi_hal_usb_unlock,void, +Function,+,furi_hal_version_do_i_belong_here,_Bool, +Function,+,furi_hal_version_get_ble_local_device_name_ptr,const char*, +Function,+,furi_hal_version_get_ble_mac,const uint8_t*, +Function,+,furi_hal_version_get_device_name_ptr,const char*, +Function,+,furi_hal_version_get_firmware_version,const Version*, +Function,+,furi_hal_version_get_hw_body,uint8_t, +Function,+,furi_hal_version_get_hw_color,FuriHalVersionColor, +Function,+,furi_hal_version_get_hw_connect,uint8_t, +Function,+,furi_hal_version_get_hw_display,FuriHalVersionDisplay, +Function,+,furi_hal_version_get_hw_region,FuriHalVersionRegion, +Function,+,furi_hal_version_get_hw_region_name,const char*, +Function,+,furi_hal_version_get_hw_target,uint8_t, +Function,+,furi_hal_version_get_hw_timestamp,uint32_t, +Function,+,furi_hal_version_get_hw_version,uint8_t, +Function,+,furi_hal_version_get_model_name,const char*, +Function,+,furi_hal_version_get_name_ptr,const char*, +Function,+,furi_hal_version_get_otp_version,FuriHalVersionOtpVersion, +Function,-,furi_hal_version_init,void, +Function,+,furi_hal_version_uid,const uint8_t*, +Function,+,furi_hal_version_uid_size,size_t, +Function,-,furi_hal_vibro_init,void, +Function,+,furi_hal_vibro_on,void,_Bool +Function,+,furi_halt,void,const char* +Function,-,furi_init,void, +Function,+,furi_kernel_get_tick_frequency,uint32_t, +Function,+,furi_kernel_lock,int32_t, +Function,+,furi_kernel_restore_lock,int32_t,int32_t +Function,+,furi_kernel_unlock,int32_t, +Function,+,furi_log_get_level,FuriLogLevel, +Function,-,furi_log_init,void, +Function,+,furi_log_print_format,void,"FuriLogLevel, const char*, const char*, ..." +Function,+,furi_log_set_level,void,FuriLogLevel +Function,-,furi_log_set_puts,void,FuriLogPuts +Function,-,furi_log_set_timestamp,void,FuriLogTimestamp +Function,+,furi_message_queue_alloc,FuriMessageQueue*,"uint32_t, uint32_t" +Function,+,furi_message_queue_free,void,FuriMessageQueue* +Function,+,furi_message_queue_get,FuriStatus,"FuriMessageQueue*, void*, uint32_t" +Function,+,furi_message_queue_get_capacity,uint32_t,FuriMessageQueue* +Function,+,furi_message_queue_get_count,uint32_t,FuriMessageQueue* +Function,+,furi_message_queue_get_message_size,uint32_t,FuriMessageQueue* +Function,+,furi_message_queue_get_space,uint32_t,FuriMessageQueue* +Function,+,furi_message_queue_put,FuriStatus,"FuriMessageQueue*, const void*, uint32_t" +Function,+,furi_message_queue_reset,FuriStatus,FuriMessageQueue* +Function,+,furi_ms_to_ticks,uint32_t,uint32_t +Function,+,furi_mutex_acquire,FuriStatus,"FuriMutex*, uint32_t" +Function,+,furi_mutex_alloc,FuriMutex*,FuriMutexType +Function,+,furi_mutex_free,void,FuriMutex* +Function,+,furi_mutex_get_owner,FuriThreadId,FuriMutex* +Function,+,furi_mutex_release,FuriStatus,FuriMutex* +Function,+,furi_pubsub_alloc,FuriPubSub*, +Function,-,furi_pubsub_free,void,FuriPubSub* +Function,+,furi_pubsub_publish,void,"FuriPubSub*, void*" +Function,+,furi_pubsub_subscribe,FuriPubSubSubscription*,"FuriPubSub*, FuriPubSubCallback, void*" +Function,+,furi_pubsub_unsubscribe,void,"FuriPubSub*, FuriPubSubSubscription*" +Function,+,furi_record_close,void,const char* +Function,+,furi_record_create,void,"const char*, void*" +Function,-,furi_record_destroy,_Bool,const char* +Function,+,furi_record_exists,_Bool,const char* +Function,-,furi_record_init,void, +Function,+,furi_record_open,void*,const char* +Function,+,furi_run,void, +Function,+,furi_semaphore_acquire,FuriStatus,"FuriSemaphore*, uint32_t" +Function,+,furi_semaphore_alloc,FuriSemaphore*,"uint32_t, uint32_t" +Function,+,furi_semaphore_free,void,FuriSemaphore* +Function,+,furi_semaphore_get_count,uint32_t,FuriSemaphore* +Function,+,furi_semaphore_release,FuriStatus,FuriSemaphore* +Function,+,furi_thread_alloc,FuriThread*, +Function,+,furi_thread_catch,void, +Function,-,furi_thread_disable_heap_trace,void,FuriThread* +Function,+,furi_thread_enable_heap_trace,void,FuriThread* +Function,+,furi_thread_enumerate,uint32_t,"FuriThreadId*, uint32_t" +Function,+,furi_thread_flags_clear,uint32_t,uint32_t +Function,+,furi_thread_flags_get,uint32_t, +Function,+,furi_thread_flags_set,uint32_t,"FuriThreadId, uint32_t" +Function,+,furi_thread_flags_wait,uint32_t,"uint32_t, uint32_t, uint32_t" +Function,+,furi_thread_free,void,FuriThread* +Function,+,furi_thread_get_current,FuriThread*, +Function,+,furi_thread_get_current_id,FuriThreadId, +Function,+,furi_thread_get_heap_size,size_t,FuriThread* +Function,+,furi_thread_get_id,FuriThreadId,FuriThread* +Function,+,furi_thread_get_name,const char*,FuriThreadId +Function,+,furi_thread_get_return_code,int32_t,FuriThread* +Function,+,furi_thread_get_stack_space,uint32_t,FuriThreadId +Function,+,furi_thread_get_state,FuriThreadState,FuriThread* +Function,+,furi_thread_join,_Bool,FuriThread* +Function,+,furi_thread_mark_as_service,void,FuriThread* +Function,+,furi_thread_set_callback,void,"FuriThread*, FuriThreadCallback" +Function,+,furi_thread_set_context,void,"FuriThread*, void*" +Function,+,furi_thread_set_name,void,"FuriThread*, const char*" +Function,+,furi_thread_set_priority,void,"FuriThread*, FuriThreadPriority" +Function,+,furi_thread_set_stack_size,void,"FuriThread*, size_t" +Function,+,furi_thread_set_state_callback,void,"FuriThread*, FuriThreadStateCallback" +Function,+,furi_thread_set_state_context,void,"FuriThread*, void*" +Function,+,furi_thread_set_stdout_callback,_Bool,FuriThreadStdoutWriteCallback +Function,+,furi_thread_start,void,FuriThread* +Function,+,furi_thread_stdout_flush,int32_t, +Function,+,furi_thread_stdout_write,size_t,"const char*, size_t" +Function,+,furi_thread_yield,void, +Function,+,furi_timer_alloc,FuriTimer*,"FuriTimerCallback, FuriTimerType, void*" +Function,+,furi_timer_free,void,FuriTimer* +Function,+,furi_timer_is_running,uint32_t,FuriTimer* +Function,+,furi_timer_start,FuriStatus,"FuriTimer*, uint32_t" +Function,+,furi_timer_stop,FuriStatus,FuriTimer* +Function,-,fwrite,size_t,"const void*, size_t, size_t, FILE*" +Function,-,fwrite_unlocked,size_t,"const void*, size_t, size_t, FILE*" +Function,-,gamma,double,double +Function,-,gamma_r,double,"double, int*" +Function,-,gammaf,float,float +Function,-,gammaf_r,float,"float, int*" +Function,-,gap_get_state,GapState, +Function,-,gap_init,_Bool,"GapConfig*, GapEventCallback, void*" +Function,-,gap_start_advertising,void, +Function,-,gap_stop_advertising,void, +Function,-,gap_thread_stop,void, +Function,-,getc,int,FILE* +Function,-,getc_unlocked,int,FILE* +Function,-,getchar,int, +Function,-,getchar_unlocked,int, +Function,-,getenv,char*,const char* +Function,-,gets,char*,char* +Function,-,getsubopt,int,"char**, char**, char**" +Function,-,getw,int,FILE* +Function,+,gui_add_framebuffer_callback,void,"Gui*, GuiCanvasCommitCallback, void*" +Function,+,gui_add_view_port,void,"Gui*, ViewPort*, GuiLayer" +Function,+,gui_get_framebuffer_size,size_t,Gui* +Function,+,gui_remove_framebuffer_callback,void,"Gui*, GuiCanvasCommitCallback, void*" +Function,+,gui_remove_view_port,void,"Gui*, ViewPort*" +Function,+,gui_set_lockdown,void,"Gui*, _Bool" +Function,-,gui_view_port_send_to_back,void,"Gui*, ViewPort*" +Function,+,gui_view_port_send_to_front,void,"Gui*, ViewPort*" +Function,+,hal_sd_detect,_Bool, +Function,+,hal_sd_detect_init,void, +Function,+,hal_sd_detect_set_low,void, +Function,+,hmac_sha256_finish,void,"const hmac_sha256_context*, const uint8_t*, uint8_t*" +Function,+,hmac_sha256_init,void,"hmac_sha256_context*, const uint8_t*" +Function,+,hmac_sha256_update,void,"const hmac_sha256_context*, const uint8_t*, unsigned" +Function,-,hypot,double,"double, double" +Function,-,hypotf,float,"float, float" +Function,-,hypotl,long double,"long double, long double" +Function,+,ibutton_key_alloc,iButtonKey*, +Function,+,ibutton_key_clear_data,void,iButtonKey* +Function,+,ibutton_key_dallas_crc_is_valid,_Bool,iButtonKey* +Function,+,ibutton_key_dallas_is_1990_key,_Bool,iButtonKey* +Function,+,ibutton_key_free,void,iButtonKey* +Function,+,ibutton_key_get_data_p,const uint8_t*,iButtonKey* +Function,+,ibutton_key_get_data_size,uint8_t,iButtonKey* +Function,+,ibutton_key_get_max_size,uint8_t, +Function,+,ibutton_key_get_size_by_type,uint8_t,iButtonKeyType +Function,+,ibutton_key_get_string_by_type,const char*,iButtonKeyType +Function,+,ibutton_key_get_type,iButtonKeyType,iButtonKey* +Function,+,ibutton_key_get_type_by_string,_Bool,"const char*, iButtonKeyType*" +Function,+,ibutton_key_set,void,"iButtonKey*, const iButtonKey*" +Function,+,ibutton_key_set_data,void,"iButtonKey*, uint8_t*, uint8_t" +Function,+,ibutton_key_set_type,void,"iButtonKey*, iButtonKeyType" +Function,+,ibutton_worker_alloc,iButtonWorker*, +Function,+,ibutton_worker_emulate_set_callback,void,"iButtonWorker*, iButtonWorkerEmulateCallback, void*" +Function,+,ibutton_worker_emulate_start,void,"iButtonWorker*, iButtonKey*" +Function,+,ibutton_worker_free,void,iButtonWorker* +Function,+,ibutton_worker_read_set_callback,void,"iButtonWorker*, iButtonWorkerReadCallback, void*" +Function,+,ibutton_worker_read_start,void,"iButtonWorker*, iButtonKey*" +Function,+,ibutton_worker_start_thread,void,iButtonWorker* +Function,+,ibutton_worker_stop,void,iButtonWorker* +Function,+,ibutton_worker_stop_thread,void,iButtonWorker* +Function,+,ibutton_worker_write_set_callback,void,"iButtonWorker*, iButtonWorkerWriteCallback, void*" +Function,+,ibutton_worker_write_start,void,"iButtonWorker*, iButtonKey*" +Function,+,icon_animation_alloc,IconAnimation*,const Icon* +Function,+,icon_animation_free,void,IconAnimation* +Function,+,icon_animation_get_height,uint8_t,IconAnimation* +Function,+,icon_animation_get_width,uint8_t,IconAnimation* +Function,+,icon_animation_is_last_frame,_Bool,IconAnimation* +Function,+,icon_animation_set_update_callback,void,"IconAnimation*, IconAnimationCallback, void*" +Function,+,icon_animation_start,void,IconAnimation* +Function,+,icon_animation_stop,void,IconAnimation* +Function,+,icon_get_data,const uint8_t*,const Icon* +Function,+,icon_get_height,uint8_t,const Icon* +Function,+,icon_get_width,uint8_t,const Icon* +Function,-,ilogb,int,double +Function,-,ilogbf,int,float +Function,-,ilogbl,int,long double +Function,-,index,char*,"const char*, int" +Function,-,infinity,double, +Function,-,infinityf,float, +Function,+,init_mutex,_Bool,"ValueMutex*, void*, size_t" +Function,-,initstate,char*,"unsigned, char*, size_t" +Function,+,input_get_key_name,const char*,InputKey +Function,+,input_get_type_name,const char*,InputType +Function,-,iprintf,int,"const char*, ..." +Function,-,isalnum,int,int +Function,-,isalnum_l,int,"int, locale_t" +Function,-,isalpha,int,int +Function,-,isalpha_l,int,"int, locale_t" +Function,-,isascii,int,int +Function,-,isascii_l,int,"int, locale_t" +Function,-,isblank,int,int +Function,-,isblank_l,int,"int, locale_t" +Function,-,iscanf,int,"const char*, ..." +Function,-,iscntrl,int,int +Function,-,iscntrl_l,int,"int, locale_t" +Function,-,isdigit,int,int +Function,-,isdigit_l,int,"int, locale_t" +Function,-,isgraph,int,int +Function,-,isgraph_l,int,"int, locale_t" +Function,-,isinf,int,double +Function,-,isinff,int,float +Function,-,islower,int,int +Function,-,islower_l,int,"int, locale_t" +Function,-,isnan,int,double +Function,-,isnanf,int,float +Function,-,isprint,int,int +Function,-,isprint_l,int,"int, locale_t" +Function,-,ispunct,int,int +Function,-,ispunct_l,int,"int, locale_t" +Function,-,isspace,int,int +Function,-,isspace_l,int,"int, locale_t" +Function,-,isupper,int,int +Function,-,isupper_l,int,"int, locale_t" +Function,-,isxdigit,int,int +Function,-,isxdigit_l,int,"int, locale_t" +Function,-,itoa,char*,"int, char*, int" +Function,-,j0,double,double +Function,-,j0f,float,float +Function,-,j1,double,double +Function,-,j1f,float,float +Function,-,jn,double,"int, double" +Function,-,jnf,float,"int, float" +Function,-,jrand48,long,unsigned short[3] +Function,-,l64a,char*,long +Function,-,labs,long,long +Function,-,lcong48,void,unsigned short[7] +Function,-,ldexp,double,"double, int" +Function,-,ldexpf,float,"float, int" +Function,-,ldexpl,long double,"long double, int" +Function,-,ldiv,ldiv_t,"long, long" +Function,+,lfrfid_dict_file_load,ProtocolId,"ProtocolDict*, const char*" +Function,+,lfrfid_dict_file_save,_Bool,"ProtocolDict*, ProtocolId, const char*" +Function,+,lfrfid_raw_file_alloc,LFRFIDRawFile*,Storage* +Function,+,lfrfid_raw_file_free,void,LFRFIDRawFile* +Function,+,lfrfid_raw_file_open_read,_Bool,"LFRFIDRawFile*, const char*" +Function,+,lfrfid_raw_file_open_write,_Bool,"LFRFIDRawFile*, const char*" +Function,+,lfrfid_raw_file_read_header,_Bool,"LFRFIDRawFile*, float*, float*" +Function,+,lfrfid_raw_file_read_pair,_Bool,"LFRFIDRawFile*, uint32_t*, uint32_t*, _Bool*" +Function,+,lfrfid_raw_file_write_buffer,_Bool,"LFRFIDRawFile*, uint8_t*, size_t" +Function,+,lfrfid_raw_file_write_header,_Bool,"LFRFIDRawFile*, float, float, uint32_t" +Function,+,lfrfid_raw_worker_alloc,LFRFIDRawWorker*, +Function,+,lfrfid_raw_worker_free,void,LFRFIDRawWorker* +Function,+,lfrfid_raw_worker_start_emulate,void,"LFRFIDRawWorker*, const char*, LFRFIDWorkerEmulateRawCallback, void*" +Function,+,lfrfid_raw_worker_start_read,void,"LFRFIDRawWorker*, const char*, float, float, LFRFIDWorkerReadRawCallback, void*" +Function,+,lfrfid_raw_worker_stop,void,LFRFIDRawWorker* +Function,+,lfrfid_worker_alloc,LFRFIDWorker*,ProtocolDict* +Function,+,lfrfid_worker_emulate_raw_start,void,"LFRFIDWorker*, const char*, LFRFIDWorkerEmulateRawCallback, void*" +Function,+,lfrfid_worker_emulate_start,void,"LFRFIDWorker*, LFRFIDProtocol" +Function,+,lfrfid_worker_free,void,LFRFIDWorker* +Function,+,lfrfid_worker_read_raw_start,void,"LFRFIDWorker*, const char*, LFRFIDWorkerReadType, LFRFIDWorkerReadRawCallback, void*" +Function,+,lfrfid_worker_read_start,void,"LFRFIDWorker*, LFRFIDWorkerReadType, LFRFIDWorkerReadCallback, void*" +Function,+,lfrfid_worker_start_thread,void,LFRFIDWorker* +Function,+,lfrfid_worker_stop,void,LFRFIDWorker* +Function,+,lfrfid_worker_stop_thread,void,LFRFIDWorker* +Function,+,lfrfid_worker_write_start,void,"LFRFIDWorker*, LFRFIDProtocol, LFRFIDWorkerWriteCallback, void*" +Function,-,lgamma,double,double +Function,-,lgamma_r,double,"double, int*" +Function,-,lgammaf,float,float +Function,-,lgammaf_r,float,"float, int*" +Function,-,lgammal,long double,long double +Function,-,llabs,long long,long long +Function,-,lldiv,lldiv_t,"long long, long long" +Function,-,llrint,long long int,double +Function,-,llrintf,long long int,float +Function,-,llrintl,long long int,long double +Function,-,llround,long long int,double +Function,-,llroundf,long long int,float +Function,-,llroundl,long long int,long double +Function,+,loader_get_pubsub,FuriPubSub*,Loader* +Function,+,loader_is_locked,_Bool,Loader* +Function,+,loader_lock,_Bool,Loader* +Function,+,loader_show_menu,void, +Function,+,loader_start,LoaderStatus,"Loader*, const char*, const char*" +Function,+,loader_unlock,void,Loader* +Function,+,loader_update_menu,void, +Function,+,loading_alloc,Loading*, +Function,+,loading_free,void,Loading* +Function,+,loading_get_view,View*,Loading* +Function,-,log,double,double +Function,-,log10,double,double +Function,-,log10f,float,float +Function,-,log10l,long double,long double +Function,-,log1p,double,double +Function,-,log1pf,float,float +Function,-,log1pl,long double,long double +Function,-,log2,double,double +Function,-,log2f,float,float +Function,-,log2l,long double,long double +Function,-,logb,double,double +Function,-,logbf,float,float +Function,-,logbl,long double,long double +Function,-,logf,float,float +Function,-,logl,long double,long double +Function,-,lrand48,long, +Function,-,lrint,long int,double +Function,-,lrintf,long int,float +Function,-,lrintl,long int,long double +Function,-,lround,long int,double +Function,-,lroundf,long int,float +Function,-,lroundl,long,long double +Function,+,malloc,void*,size_t +Function,+,manchester_advance,_Bool,"ManchesterState, ManchesterEvent, ManchesterState*, _Bool*" +Function,+,manchester_encoder_advance,_Bool,"ManchesterEncoderState*, const _Bool, ManchesterEncoderResult*" +Function,+,manchester_encoder_finish,ManchesterEncoderResult,ManchesterEncoderState* +Function,+,manchester_encoder_reset,void,ManchesterEncoderState* +Function,+,maxim_crc8,uint8_t,"const uint8_t*, const uint8_t, const uint8_t" +Function,-,mblen,int,"const char*, size_t" +Function,-,mbstowcs,size_t,"wchar_t*, const char*, size_t" +Function,-,mbtowc,int,"wchar_t*, const char*, size_t" +Function,+,md5,void,"const unsigned char*, size_t, unsigned char[16]" +Function,+,md5_finish,void,"md5_context*, unsigned char[16]" +Function,+,md5_process,void,"md5_context*, const unsigned char[64]" +Function,+,md5_starts,void,md5_context* +Function,+,md5_update,void,"md5_context*, const unsigned char*, size_t" +Function,-,memccpy,void*,"void*, const void*, int, size_t" +Function,+,memchr,void*,"const void*, int, size_t" +Function,+,memcmp,int,"const void*, const void*, size_t" +Function,+,memcpy,void*,"void*, const void*, size_t" +Function,-,memmem,void*,"const void*, size_t, const void*, size_t" +Function,-,memmgr_alloc_from_pool,void*,size_t +Function,+,memmgr_get_free_heap,size_t, +Function,+,memmgr_get_minimum_free_heap,size_t, +Function,+,memmgr_get_total_heap,size_t, +Function,+,memmgr_heap_disable_thread_trace,void,FuriThreadId +Function,+,memmgr_heap_enable_thread_trace,void,FuriThreadId +Function,+,memmgr_heap_get_max_free_block,size_t, +Function,+,memmgr_heap_get_thread_memory,size_t,FuriThreadId +Function,+,memmgr_heap_printf_free_blocks,void, +Function,-,memmgr_pool_get_free,size_t, +Function,-,memmgr_pool_get_max_block,size_t, +Function,+,memmove,void*,"void*, const void*, size_t" +Function,-,mempcpy,void*,"void*, const void*, size_t" +Function,-,memrchr,void*,"const void*, int, size_t" +Function,+,memset,void*,"void*, int, size_t" +Function,+,menu_add_item,void,"Menu*, const char*, const Icon*, uint32_t, MenuItemCallback, void*" +Function,+,menu_alloc,Menu*, +Function,+,menu_free,void,Menu* +Function,+,menu_get_view,View*,Menu* +Function,+,menu_reset,void,Menu* +Function,+,menu_set_selected_item,void,"Menu*, uint32_t" +Function,-,mkdtemp,char*,char* +Function,-,mkostemp,int,"char*, int" +Function,-,mkostemps,int,"char*, int, int" +Function,-,mkstemp,int,char* +Function,-,mkstemps,int,"char*, int" +Function,-,mktemp,char*,char* +Function,-,modf,double,"double, double*" +Function,-,modff,float,"float, float*" +Function,-,modfl,long double,"long double, long double*" +Function,-,mrand48,long, +Function,-,nan,double,const char* +Function,-,nanf,float,const char* +Function,-,nanl,long double,const char* +Function,-,nearbyint,double,double +Function,-,nearbyintf,float,float +Function,-,nearbyintl,long double,long double +Function,-,nextafter,double,"double, double" +Function,-,nextafterf,float,"float, float" +Function,-,nextafterl,long double,"long double, long double" +Function,-,nexttoward,double,"double, long double" +Function,-,nexttowardf,float,"float, long double" +Function,-,nexttowardl,long double,"long double, long double" +Function,-,nfca_append_crc16,void,"uint8_t*, uint16_t" +Function,-,nfca_emulation_handler,_Bool,"uint8_t*, uint16_t, uint8_t*, uint16_t*" +Function,-,nfca_get_crc16,uint16_t,"uint8_t*, uint16_t" +Function,-,nfca_signal_alloc,NfcaSignal*, +Function,-,nfca_signal_encode,void,"NfcaSignal*, uint8_t*, uint16_t, uint8_t*" +Function,-,nfca_signal_free,void,NfcaSignal* +Function,+,notification_internal_message,void,"NotificationApp*, const NotificationSequence*" +Function,+,notification_internal_message_block,void,"NotificationApp*, const NotificationSequence*" +Function,+,notification_message,void,"NotificationApp*, const NotificationSequence*" +Function,+,notification_message_block,void,"NotificationApp*, const NotificationSequence*" +Function,-,nrand48,long,unsigned short[3] +Function,-,on_exit,int,"void (*)(int, void*), void*" +Function,+,onewire_device_alloc,OneWireDevice*,"uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t" +Function,+,onewire_device_attach,void,"OneWireDevice*, OneWireSlave*" +Function,+,onewire_device_detach,void,OneWireDevice* +Function,+,onewire_device_free,void,OneWireDevice* +Function,+,onewire_device_get_id_p,uint8_t*,OneWireDevice* +Function,+,onewire_device_send_id,void,OneWireDevice* +Function,+,onewire_host_alloc,OneWireHost*, +Function,+,onewire_host_free,void,OneWireHost* +Function,+,onewire_host_read,uint8_t,OneWireHost* +Function,+,onewire_host_read_bit,_Bool,OneWireHost* +Function,+,onewire_host_read_bytes,void,"OneWireHost*, uint8_t*, uint16_t" +Function,+,onewire_host_reset,_Bool,OneWireHost* +Function,+,onewire_host_reset_search,void,OneWireHost* +Function,+,onewire_host_search,uint8_t,"OneWireHost*, uint8_t*, OneWireHostSearchMode" +Function,+,onewire_host_skip,void,OneWireHost* +Function,+,onewire_host_start,void,OneWireHost* +Function,+,onewire_host_stop,void,OneWireHost* +Function,+,onewire_host_target_search,void,"OneWireHost*, uint8_t" +Function,+,onewire_host_write,void,"OneWireHost*, uint8_t" +Function,+,onewire_host_write_bit,void,"OneWireHost*, _Bool" +Function,+,onewire_slave_alloc,OneWireSlave*, +Function,+,onewire_slave_attach,void,"OneWireSlave*, OneWireDevice*" +Function,+,onewire_slave_detach,void,OneWireSlave* +Function,+,onewire_slave_free,void,OneWireSlave* +Function,+,onewire_slave_set_result_callback,void,"OneWireSlave*, OneWireSlaveResultCallback, void*" +Function,+,onewire_slave_start,void,OneWireSlave* +Function,+,onewire_slave_stop,void,OneWireSlave* +Function,-,open_memstream,FILE*,"char**, size_t*" +Function,+,path_append,void,"string_t, const char*" +Function,+,path_concat,void,"const char*, const char*, string_t" +Function,+,path_contains_only_ascii,_Bool,const char* +Function,+,path_extract_basename,void,"const char*, string_t" +Function,+,path_extract_dirname,void,"const char*, string_t" +Function,+,path_extract_extension,void,"string_t, char*, size_t" +Function,+,path_extract_filename,void,"string_t, string_t, _Bool" +Function,+,path_extract_filename_no_ext,void,"const char*, string_t" +Function,-,pcTaskGetName,char*,TaskHandle_t +Function,-,pcTimerGetName,const char*,TimerHandle_t +Function,-,pclose,int,FILE* +Function,-,perror,void,const char* +Function,-,platformDisableIrqCallback,void, +Function,-,platformEnableIrqCallback,void, +Function,-,platformProtectST25RComm,void, +Function,-,platformSetIrqCallback,void,PlatformIrqCallback +Function,-,platformSpiTxRx,_Bool,"const uint8_t*, uint8_t*, uint16_t" +Function,-,platformUnprotectST25RComm,void, +Function,-,popen,FILE*,"const char*, const char*" +Function,+,popup_alloc,Popup*, +Function,+,popup_disable_timeout,void,Popup* +Function,+,popup_enable_timeout,void,Popup* +Function,+,popup_free,void,Popup* +Function,+,popup_get_view,View*,Popup* +Function,+,popup_reset,void,Popup* +Function,+,popup_set_callback,void,"Popup*, PopupCallback" +Function,+,popup_set_context,void,"Popup*, void*" +Function,+,popup_set_header,void,"Popup*, const char*, uint8_t, uint8_t, Align, Align" +Function,+,popup_set_icon,void,"Popup*, uint8_t, uint8_t, const Icon*" +Function,+,popup_set_text,void,"Popup*, const char*, uint8_t, uint8_t, Align, Align" +Function,+,popup_set_timeout,void,"Popup*, uint32_t" +Function,-,posix_memalign,int,"void**, size_t, size_t" +Function,-,pow,double,"double, double" +Function,-,pow10,double,double +Function,-,pow10f,float,float +Function,-,power_enable_low_battery_level_notification,void,"Power*, _Bool" +Function,+,power_get_info,void,"Power*, PowerInfo*" +Function,+,power_get_pubsub,FuriPubSub*,Power* +Function,+,power_is_battery_healthy,_Bool,Power* +Function,+,power_off,void,Power* +Function,+,power_reboot,void,PowerBootMode +Function,+,powf,float,"float, float" +Function,-,powl,long double,"long double, long double" +Function,-,printf,int,"const char*, ..." +Function,+,protocol_dict_alloc,ProtocolDict*,"const ProtocolBase**, size_t" +Function,+,protocol_dict_decoders_feed,ProtocolId,"ProtocolDict*, _Bool, uint32_t" +Function,+,protocol_dict_decoders_feed_by_feature,ProtocolId,"ProtocolDict*, uint32_t, _Bool, uint32_t" +Function,+,protocol_dict_decoders_feed_by_id,ProtocolId,"ProtocolDict*, size_t, _Bool, uint32_t" +Function,+,protocol_dict_decoders_start,void,ProtocolDict* +Function,+,protocol_dict_encoder_start,_Bool,"ProtocolDict*, size_t" +Function,+,protocol_dict_encoder_yield,LevelDuration,"ProtocolDict*, size_t" +Function,+,protocol_dict_free,void,ProtocolDict* +Function,+,protocol_dict_get_data,void,"ProtocolDict*, size_t, uint8_t*, size_t" +Function,+,protocol_dict_get_data_size,size_t,"ProtocolDict*, size_t" +Function,+,protocol_dict_get_features,uint32_t,"ProtocolDict*, size_t" +Function,+,protocol_dict_get_manufacturer,const char*,"ProtocolDict*, size_t" +Function,+,protocol_dict_get_max_data_size,size_t,ProtocolDict* +Function,+,protocol_dict_get_name,const char*,"ProtocolDict*, size_t" +Function,+,protocol_dict_get_protocol_by_name,ProtocolId,"ProtocolDict*, const char*" +Function,+,protocol_dict_get_validate_count,uint32_t,"ProtocolDict*, size_t" +Function,+,protocol_dict_get_write_data,_Bool,"ProtocolDict*, size_t, void*" +Function,+,protocol_dict_render_brief_data,void,"ProtocolDict*, string_t, size_t" +Function,+,protocol_dict_render_data,void,"ProtocolDict*, string_t, size_t" +Function,+,protocol_dict_set_data,void,"ProtocolDict*, size_t, const uint8_t*, size_t" +Function,-,pselect,int,"int, fd_set*, fd_set*, fd_set*, const timespec*, const sigset_t*" +Function,-,putc,int,"int, FILE*" +Function,-,putc_unlocked,int,"int, FILE*" +Function,-,putchar,int,int +Function,-,putchar_unlocked,int,int +Function,-,putenv,int,char* +Function,-,puts,int,const char* +Function,-,putw,int,"int, FILE*" +Function,-,pvPortMalloc,void*,size_t +Function,-,pvTaskGetThreadLocalStoragePointer,void*,"TaskHandle_t, BaseType_t" +Function,-,pvTaskIncrementMutexHeldCount,TaskHandle_t, +Function,-,pvTimerGetTimerID,void*,const TimerHandle_t +Function,-,pxPortInitialiseStack,StackType_t*,"StackType_t*, TaskFunction_t, void*" +Function,-,qsort,void,"void*, size_t, size_t, __compar_fn_t" +Function,-,qsort_r,void,"void*, size_t, size_t, int (*)(const void*, const void*, void*), void*" +Function,-,quick_exit,void,int +Function,+,rand,int, +Function,-,rand_r,int,unsigned* +Function,+,random,long, +Function,-,rawmemchr,void*,"const void*, int" +Function,-,read_mutex,_Bool,"ValueMutex*, void*, size_t, uint32_t" +Function,+,realloc,void*,"void*, size_t" +Function,-,reallocarray,void*,"void*, size_t, size_t" +Function,-,reallocf,void*,"void*, size_t" +Function,-,realpath,char*,"const char*, char*" +Function,+,release_mutex,_Bool,"ValueMutex*, const void*" +Function,-,remainder,double,"double, double" +Function,-,remainderf,float,"float, float" +Function,-,remainderl,long double,"long double, long double" +Function,-,remove,int,const char* +Function,-,remquo,double,"double, double, int*" +Function,-,remquof,float,"float, float, int*" +Function,-,remquol,long double,"long double, long double, int*" +Function,-,rename,int,"const char*, const char*" +Function,-,renameat,int,"int, const char*, int, const char*" +Function,-,rewind,void,FILE* +Function,-,rfalAdjustRegulators,ReturnCode,uint16_t* +Function,-,rfalCalibrate,ReturnCode, +Function,-,rfalDeinitialize,ReturnCode, +Function,-,rfalDisableObsvMode,void, +Function,-,rfalFeliCaPoll,ReturnCode,"rfalFeliCaPollSlots, uint16_t, uint8_t, rfalFeliCaPollRes*, uint8_t, uint8_t*, uint8_t*" +Function,-,rfalFieldOff,ReturnCode, +Function,+,rfalFieldOnAndStartGT,ReturnCode, +Function,-,rfalGetBitRate,ReturnCode,"rfalBitRate*, rfalBitRate*" +Function,-,rfalGetErrorHandling,rfalEHandling, +Function,-,rfalGetFDTListen,uint32_t, +Function,-,rfalGetFDTPoll,uint32_t, +Function,-,rfalGetGT,uint32_t, +Function,-,rfalGetMode,rfalMode, +Function,-,rfalGetObsvMode,void,"uint8_t*, uint8_t*" +Function,-,rfalGetTransceiveRSSI,ReturnCode,uint16_t* +Function,-,rfalGetTransceiveState,rfalTransceiveState, +Function,-,rfalGetTransceiveStatus,ReturnCode, +Function,-,rfalISO14443ATransceiveAnticollisionFrame,ReturnCode,"uint8_t*, uint8_t*, uint8_t*, uint16_t*, uint32_t" +Function,-,rfalISO14443ATransceiveShortFrame,ReturnCode,"rfal14443AShortFrameCmd, uint8_t*, uint8_t, uint16_t*, uint32_t" +Function,-,rfalISO15693TransceiveAnticollisionFrame,ReturnCode,"uint8_t*, uint8_t, uint8_t*, uint8_t, uint16_t*" +Function,-,rfalISO15693TransceiveEOF,ReturnCode,"uint8_t*, uint8_t, uint16_t*" +Function,-,rfalISO15693TransceiveEOFAnticollision,ReturnCode,"uint8_t*, uint8_t, uint16_t*" +Function,-,rfalInitialize,ReturnCode, +Function,-,rfalIsExtFieldOn,_Bool, +Function,-,rfalIsGTExpired,_Bool, +Function,-,rfalIsTransceiveInRx,_Bool, +Function,-,rfalIsTransceiveInTx,_Bool, +Function,-,rfalIsoDepATTRIB,ReturnCode,"const uint8_t*, uint8_t, rfalBitRate, rfalBitRate, rfalIsoDepFSxI, uint8_t, uint8_t, const uint8_t*, uint8_t, uint32_t, rfalIsoDepAttribRes*, uint8_t*" +Function,-,rfalIsoDepDeselect,ReturnCode, +Function,-,rfalIsoDepFSxI2FSx,uint16_t,uint8_t +Function,-,rfalIsoDepFWI2FWT,uint32_t,uint8_t +Function,-,rfalIsoDepGetApduTransceiveStatus,ReturnCode, +Function,-,rfalIsoDepGetMaxInfLen,uint16_t, +Function,-,rfalIsoDepGetTransceiveStatus,ReturnCode, +Function,-,rfalIsoDepInitialize,void, +Function,-,rfalIsoDepInitializeWithParams,void,"rfalComplianceMode, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t" +Function,-,rfalIsoDepIsAttrib,_Bool,"const uint8_t*, uint8_t" +Function,-,rfalIsoDepIsRats,_Bool,"const uint8_t*, uint8_t" +Function,-,rfalIsoDepListenGetActivationStatus,ReturnCode, +Function,-,rfalIsoDepListenStartActivation,ReturnCode,"rfalIsoDepAtsParam*, const rfalIsoDepAttribResParam*, const uint8_t*, uint16_t, rfalIsoDepListenActvParam" +Function,-,rfalIsoDepPPS,ReturnCode,"uint8_t, rfalBitRate, rfalBitRate, rfalIsoDepPpsRes*" +Function,-,rfalIsoDepPollAGetActivationStatus,ReturnCode, +Function,-,rfalIsoDepPollAHandleActivation,ReturnCode,"rfalIsoDepFSxI, uint8_t, rfalBitRate, rfalIsoDepDevice*" +Function,-,rfalIsoDepPollAStartActivation,ReturnCode,"rfalIsoDepFSxI, uint8_t, rfalBitRate, rfalIsoDepDevice*" +Function,-,rfalIsoDepPollBGetActivationStatus,ReturnCode, +Function,-,rfalIsoDepPollBHandleActivation,ReturnCode,"rfalIsoDepFSxI, uint8_t, rfalBitRate, uint8_t, const rfalNfcbListenDevice*, const uint8_t*, uint8_t, rfalIsoDepDevice*" +Function,-,rfalIsoDepPollBStartActivation,ReturnCode,"rfalIsoDepFSxI, uint8_t, rfalBitRate, uint8_t, const rfalNfcbListenDevice*, const uint8_t*, uint8_t, rfalIsoDepDevice*" +Function,-,rfalIsoDepPollHandleSParameters,ReturnCode,"rfalIsoDepDevice*, rfalBitRate, rfalBitRate" +Function,-,rfalIsoDepRATS,ReturnCode,"rfalIsoDepFSxI, uint8_t, rfalIsoDepAts*, uint8_t*" +Function,-,rfalIsoDepStartApduTransceive,ReturnCode,rfalIsoDepApduTxRxParam +Function,-,rfalIsoDepStartTransceive,ReturnCode,rfalIsoDepTxRxParam +Function,-,rfalListenGetState,rfalLmState,"_Bool*, rfalBitRate*" +Function,-,rfalListenSetState,ReturnCode,rfalLmState +Function,-,rfalListenSleepStart,ReturnCode,"rfalLmState, uint8_t*, uint16_t, uint16_t*" +Function,-,rfalListenStart,ReturnCode,"uint32_t, const rfalLmConfPA*, const rfalLmConfPB*, const rfalLmConfPF*, uint8_t*, uint16_t, uint16_t*" +Function,-,rfalListenStop,ReturnCode, +Function,+,rfalLowPowerModeStart,ReturnCode, +Function,+,rfalLowPowerModeStop,ReturnCode, +Function,-,rfalNfcDataExchangeCustomStart,ReturnCode,"uint8_t*, uint16_t, uint8_t**, uint16_t**, uint32_t, uint32_t" +Function,-,rfalNfcDataExchangeGetStatus,ReturnCode, +Function,-,rfalNfcDataExchangeStart,ReturnCode,"uint8_t*, uint16_t, uint8_t**, uint16_t**, uint32_t, uint32_t" +Function,-,rfalNfcDeactivate,ReturnCode,_Bool +Function,-,rfalNfcDepATR,ReturnCode,"const rfalNfcDepAtrParam*, rfalNfcDepAtrRes*, uint8_t*" +Function,-,rfalNfcDepCalculateRWT,uint32_t,uint8_t +Function,-,rfalNfcDepDSL,ReturnCode, +Function,-,rfalNfcDepGetPduTransceiveStatus,ReturnCode, +Function,-,rfalNfcDepGetTransceiveStatus,ReturnCode, +Function,-,rfalNfcDepInitialize,void, +Function,-,rfalNfcDepInitiatorHandleActivation,ReturnCode,"rfalNfcDepAtrParam*, rfalBitRate, rfalNfcDepDevice*" +Function,-,rfalNfcDepIsAtrReq,_Bool,"const uint8_t*, uint16_t, uint8_t*" +Function,-,rfalNfcDepListenGetActivationStatus,ReturnCode, +Function,-,rfalNfcDepListenStartActivation,ReturnCode,"const rfalNfcDepTargetParam*, const uint8_t*, uint16_t, rfalNfcDepListenActvParam" +Function,-,rfalNfcDepPSL,ReturnCode,"uint8_t, uint8_t" +Function,-,rfalNfcDepRLS,ReturnCode, +Function,-,rfalNfcDepSetDeactivatingCallback,void,rfalNfcDepDeactCallback +Function,-,rfalNfcDepStartPduTransceive,ReturnCode,rfalNfcDepPduTxRxParam +Function,-,rfalNfcDepStartTransceive,ReturnCode,const rfalNfcDepTxRxParam* +Function,-,rfalNfcDepTargetRcvdATR,_Bool, +Function,-,rfalNfcDiscover,ReturnCode,const rfalNfcDiscoverParam* +Function,-,rfalNfcGetActiveDevice,ReturnCode,rfalNfcDevice** +Function,-,rfalNfcGetDevicesFound,ReturnCode,"rfalNfcDevice**, uint8_t*" +Function,-,rfalNfcGetState,rfalNfcState, +Function,-,rfalNfcInitialize,ReturnCode, +Function,-,rfalNfcSelect,ReturnCode,uint8_t +Function,-,rfalNfcWorker,void, +Function,-,rfalNfcaListenerIsSleepReq,_Bool,"const uint8_t*, uint16_t" +Function,-,rfalNfcaPollerCheckPresence,ReturnCode,"rfal14443AShortFrameCmd, rfalNfcaSensRes*" +Function,-,rfalNfcaPollerFullCollisionResolution,ReturnCode,"rfalComplianceMode, uint8_t, rfalNfcaListenDevice*, uint8_t*" +Function,-,rfalNfcaPollerGetFullCollisionResolutionStatus,ReturnCode, +Function,-,rfalNfcaPollerInitialize,ReturnCode, +Function,-,rfalNfcaPollerSelect,ReturnCode,"const uint8_t*, uint8_t, rfalNfcaSelRes*" +Function,-,rfalNfcaPollerSingleCollisionResolution,ReturnCode,"uint8_t, _Bool*, rfalNfcaSelRes*, uint8_t*, uint8_t*" +Function,-,rfalNfcaPollerSleep,ReturnCode, +Function,-,rfalNfcaPollerSleepFullCollisionResolution,ReturnCode,"uint8_t, rfalNfcaListenDevice*, uint8_t*" +Function,-,rfalNfcaPollerStartFullCollisionResolution,ReturnCode,"rfalComplianceMode, uint8_t, rfalNfcaListenDevice*, uint8_t*" +Function,-,rfalNfcaPollerTechnologyDetection,ReturnCode,"rfalComplianceMode, rfalNfcaSensRes*" +Function,-,rfalNfcbPollerCheckPresence,ReturnCode,"rfalNfcbSensCmd, rfalNfcbSlots, rfalNfcbSensbRes*, uint8_t*" +Function,-,rfalNfcbPollerCollisionResolution,ReturnCode,"rfalComplianceMode, uint8_t, rfalNfcbListenDevice*, uint8_t*" +Function,-,rfalNfcbPollerInitialize,ReturnCode, +Function,-,rfalNfcbPollerInitializeWithParams,ReturnCode,"uint8_t, uint8_t" +Function,-,rfalNfcbPollerSleep,ReturnCode,const uint8_t* +Function,-,rfalNfcbPollerSlotMarker,ReturnCode,"uint8_t, rfalNfcbSensbRes*, uint8_t*" +Function,-,rfalNfcbPollerSlottedCollisionResolution,ReturnCode,"rfalComplianceMode, uint8_t, rfalNfcbSlots, rfalNfcbSlots, rfalNfcbListenDevice*, uint8_t*, _Bool*" +Function,-,rfalNfcbPollerTechnologyDetection,ReturnCode,"rfalComplianceMode, rfalNfcbSensbRes*, uint8_t*" +Function,-,rfalNfcbTR2ToFDT,uint32_t,uint8_t +Function,-,rfalNfcfListenerIsT3TReq,_Bool,"const uint8_t*, uint16_t, uint8_t*" +Function,-,rfalNfcfPollerCheck,ReturnCode,"const uint8_t*, const rfalNfcfServBlockListParam*, uint8_t*, uint16_t, uint16_t*" +Function,-,rfalNfcfPollerCheckPresence,ReturnCode, +Function,-,rfalNfcfPollerCollisionResolution,ReturnCode,"rfalComplianceMode, uint8_t, rfalNfcfListenDevice*, uint8_t*" +Function,-,rfalNfcfPollerInitialize,ReturnCode,rfalBitRate +Function,-,rfalNfcfPollerPoll,ReturnCode,"rfalFeliCaPollSlots, uint16_t, uint8_t, rfalFeliCaPollRes*, uint8_t*, uint8_t*" +Function,-,rfalNfcfPollerUpdate,ReturnCode,"const uint8_t*, const rfalNfcfServBlockListParam*, uint8_t*, uint16_t, const uint8_t*, uint8_t*, uint16_t" +Function,-,rfalNfcvPollerCheckPresence,ReturnCode,rfalNfcvInventoryRes* +Function,-,rfalNfcvPollerCollisionResolution,ReturnCode,"rfalComplianceMode, uint8_t, rfalNfcvListenDevice*, uint8_t*" +Function,-,rfalNfcvPollerExtendedGetSystemInformation,ReturnCode,"uint8_t, const uint8_t*, uint8_t, uint8_t*, uint16_t, uint16_t*" +Function,-,rfalNfcvPollerExtendedLockSingleBlock,ReturnCode,"uint8_t, const uint8_t*, uint16_t" +Function,-,rfalNfcvPollerExtendedReadMultipleBlocks,ReturnCode,"uint8_t, const uint8_t*, uint16_t, uint16_t, uint8_t*, uint16_t, uint16_t*" +Function,-,rfalNfcvPollerExtendedReadSingleBlock,ReturnCode,"uint8_t, const uint8_t*, uint16_t, uint8_t*, uint16_t, uint16_t*" +Function,-,rfalNfcvPollerExtendedWriteMultipleBlocks,ReturnCode,"uint8_t, const uint8_t*, uint16_t, uint16_t, uint8_t*, uint16_t, uint8_t, const uint8_t*, uint16_t" +Function,-,rfalNfcvPollerExtendedWriteSingleBlock,ReturnCode,"uint8_t, const uint8_t*, uint16_t, const uint8_t*, uint8_t" +Function,-,rfalNfcvPollerGetSystemInformation,ReturnCode,"uint8_t, const uint8_t*, uint8_t*, uint16_t, uint16_t*" +Function,-,rfalNfcvPollerInitialize,ReturnCode, +Function,-,rfalNfcvPollerInventory,ReturnCode,"rfalNfcvNumSlots, uint8_t, const uint8_t*, rfalNfcvInventoryRes*, uint16_t*" +Function,-,rfalNfcvPollerLockBlock,ReturnCode,"uint8_t, const uint8_t*, uint8_t" +Function,-,rfalNfcvPollerReadMultipleBlocks,ReturnCode,"uint8_t, const uint8_t*, uint8_t, uint8_t, uint8_t*, uint16_t, uint16_t*" +Function,-,rfalNfcvPollerReadSingleBlock,ReturnCode,"uint8_t, const uint8_t*, uint8_t, uint8_t*, uint16_t, uint16_t*" +Function,-,rfalNfcvPollerSelect,ReturnCode,"uint8_t, const uint8_t*" +Function,-,rfalNfcvPollerSleep,ReturnCode,"uint8_t, const uint8_t*" +Function,-,rfalNfcvPollerSleepCollisionResolution,ReturnCode,"uint8_t, rfalNfcvListenDevice*, uint8_t*" +Function,-,rfalNfcvPollerTransceiveReq,ReturnCode,"uint8_t, uint8_t, uint8_t, const uint8_t*, const uint8_t*, uint16_t, uint8_t*, uint16_t, uint16_t*" +Function,-,rfalNfcvPollerWriteMultipleBlocks,ReturnCode,"uint8_t, const uint8_t*, uint8_t, uint8_t, uint8_t*, uint16_t, uint8_t, const uint8_t*, uint16_t" +Function,-,rfalNfcvPollerWriteSingleBlock,ReturnCode,"uint8_t, const uint8_t*, uint8_t, const uint8_t*, uint8_t" +Function,-,rfalSetBitRate,ReturnCode,"rfalBitRate, rfalBitRate" +Function,-,rfalSetErrorHandling,void,rfalEHandling +Function,-,rfalSetFDTListen,void,uint32_t +Function,-,rfalSetFDTPoll,void,uint32_t +Function,-,rfalSetGT,void,uint32_t +Function,-,rfalSetMode,ReturnCode,"rfalMode, rfalBitRate, rfalBitRate" +Function,-,rfalSetObsvMode,void,"uint8_t, uint8_t" +Function,-,rfalSetPostTxRxCallback,void,rfalPostTxRxCallback +Function,-,rfalSetPreTxRxCallback,void,rfalPreTxRxCallback +Function,-,rfalSetUpperLayerCallback,void,rfalUpperLayerCallback +Function,-,rfalSt25tbPollerCheckPresence,ReturnCode,uint8_t* +Function,-,rfalSt25tbPollerCollisionResolution,ReturnCode,"uint8_t, rfalSt25tbListenDevice*, uint8_t*" +Function,-,rfalSt25tbPollerCompletion,ReturnCode, +Function,-,rfalSt25tbPollerGetUID,ReturnCode,rfalSt25tbUID* +Function,-,rfalSt25tbPollerInitialize,ReturnCode, +Function,-,rfalSt25tbPollerInitiate,ReturnCode,uint8_t* +Function,-,rfalSt25tbPollerPcall,ReturnCode,uint8_t* +Function,-,rfalSt25tbPollerReadBlock,ReturnCode,"uint8_t, rfalSt25tbBlock*" +Function,-,rfalSt25tbPollerResetToInventory,ReturnCode, +Function,-,rfalSt25tbPollerSelect,ReturnCode,uint8_t +Function,-,rfalSt25tbPollerSlotMarker,ReturnCode,"uint8_t, uint8_t*" +Function,-,rfalSt25tbPollerWriteBlock,ReturnCode,"uint8_t, const rfalSt25tbBlock*" +Function,-,rfalStartTransceive,ReturnCode,const rfalTransceiveContext* +Function,-,rfalT1TPollerInitialize,ReturnCode, +Function,-,rfalT1TPollerRall,ReturnCode,"const uint8_t*, uint8_t*, uint16_t, uint16_t*" +Function,-,rfalT1TPollerRid,ReturnCode,rfalT1TRidRes* +Function,-,rfalT1TPollerWrite,ReturnCode,"const uint8_t*, uint8_t, uint8_t" +Function,-,rfalTransceiveBitsBlockingTx,ReturnCode,"uint8_t*, uint16_t, uint8_t*, uint16_t, uint16_t*, uint32_t, uint32_t" +Function,-,rfalTransceiveBlockingRx,ReturnCode, +Function,-,rfalTransceiveBlockingTx,ReturnCode,"uint8_t*, uint16_t, uint8_t*, uint16_t, uint16_t*, uint32_t, uint32_t" +Function,-,rfalTransceiveBlockingTxRx,ReturnCode,"uint8_t*, uint16_t, uint8_t*, uint16_t, uint16_t*, uint32_t, uint32_t" +Function,-,rfalWakeUpModeHasWoke,_Bool, +Function,-,rfalWakeUpModeStart,ReturnCode,const rfalWakeUpConfig* +Function,-,rfalWakeUpModeStop,ReturnCode, +Function,+,rfalWorker,void, +Function,-,rfal_platform_spi_acquire,void, +Function,-,rfal_platform_spi_release,void, +Function,-,rfal_set_callback_context,void,void* +Function,-,rfal_set_state_changed_callback,void,RfalStateChangedCallback +Function,-,rindex,char*,"const char*, int" +Function,-,rint,double,double +Function,-,rintf,float,float +Function,-,rintl,long double,long double +Function,-,round,double,double +Function,+,roundf,float,float +Function,-,roundl,long double,long double +Function,+,rpc_session_close,void,RpcSession* +Function,+,rpc_session_feed,size_t,"RpcSession*, uint8_t*, size_t, TickType_t" +Function,+,rpc_session_get_available_size,size_t,RpcSession* +Function,+,rpc_session_open,RpcSession*,Rpc* +Function,+,rpc_session_set_buffer_is_empty_callback,void,"RpcSession*, RpcBufferIsEmptyCallback" +Function,+,rpc_session_set_close_callback,void,"RpcSession*, RpcSessionClosedCallback" +Function,+,rpc_session_set_context,void,"RpcSession*, void*" +Function,+,rpc_session_set_send_bytes_callback,void,"RpcSession*, RpcSendBytesCallback" +Function,+,rpc_session_set_terminated_callback,void,"RpcSession*, RpcSessionTerminatedCallback" +Function,+,rpc_system_app_confirm,void,"RpcAppSystem*, RpcAppSystemEvent, _Bool" +Function,+,rpc_system_app_get_data,const char*,RpcAppSystem* +Function,+,rpc_system_app_send_exited,void,RpcAppSystem* +Function,+,rpc_system_app_send_started,void,RpcAppSystem* +Function,+,rpc_system_app_set_callback,void,"RpcAppSystem*, RpcAppSystemCallback, void*" +Function,-,rpmatch,int,const char* +Function,+,saved_struct_load,_Bool,"const char*, void*, size_t, uint8_t, uint8_t" +Function,+,saved_struct_save,_Bool,"const char*, void*, size_t, uint8_t, uint8_t" +Function,-,scalbln,double,"double, long int" +Function,-,scalblnf,float,"float, long int" +Function,-,scalblnl,long double,"long double, long" +Function,-,scalbn,double,"double, int" +Function,+,scalbnf,float,"float, int" +Function,-,scalbnl,long double,"long double, int" +Function,-,scanf,int,"const char*, ..." +Function,+,scene_manager_alloc,SceneManager*,"const SceneManagerHandlers*, void*" +Function,+,scene_manager_free,void,SceneManager* +Function,+,scene_manager_get_scene_state,uint32_t,"SceneManager*, uint32_t" +Function,+,scene_manager_handle_back_event,_Bool,SceneManager* +Function,+,scene_manager_handle_custom_event,_Bool,"SceneManager*, uint32_t" +Function,+,scene_manager_handle_tick_event,void,SceneManager* +Function,+,scene_manager_has_previous_scene,_Bool,"SceneManager*, uint32_t" +Function,+,scene_manager_next_scene,void,"SceneManager*, uint32_t" +Function,+,scene_manager_previous_scene,_Bool,SceneManager* +Function,+,scene_manager_search_and_switch_to_another_scene,_Bool,"SceneManager*, uint32_t" +Function,+,scene_manager_search_and_switch_to_previous_scene,_Bool,"SceneManager*, uint32_t" +Function,+,scene_manager_search_and_switch_to_previous_scene_one_of,_Bool,"SceneManager*, const uint32_t*, size_t" +Function,+,scene_manager_set_scene_state,void,"SceneManager*, uint32_t, uint32_t" +Function,+,scene_manager_stop,void,SceneManager* +Function,+,sd_api_get_fs_type_text,const char*,SDFsType +Function,-,secure_getenv,char*,const char* +Function,-,seed48,unsigned short*,unsigned short[3] +Function,-,select,int,"int, fd_set*, fd_set*, fd_set*, timeval*" +Function,-,serial_svc_is_started,_Bool, +Function,-,serial_svc_notify_buffer_is_empty,void, +Function,-,serial_svc_set_callbacks,void,"uint16_t, SerialServiceEventCallback, void*" +Function,-,serial_svc_start,void, +Function,-,serial_svc_stop,void, +Function,-,serial_svc_update_tx,_Bool,"uint8_t*, uint16_t" +Function,+,set_random_name,void,"char*, uint8_t" +Function,-,setbuf,void,"FILE*, char*" +Function,-,setbuffer,void,"FILE*, char*, int" +Function,-,setenv,int,"const char*, const char*, int" +Function,-,setkey,void,const char* +Function,-,setlinebuf,int,FILE* +Function,-,setstate,char*,char* +Function,-,setvbuf,int,"FILE*, char*, int, size_t" +Function,+,sha256,void,"const unsigned char*, unsigned int, unsigned char[32]" +Function,+,sha256_finish,void,"sha256_context*, unsigned char[32]" +Function,+,sha256_process,void,sha256_context* +Function,+,sha256_start,void,sha256_context* +Function,+,sha256_update,void,"sha256_context*, const unsigned char*, unsigned int" +Function,-,sin,double,double +Function,-,sincos,void,"double, double*, double*" +Function,-,sincosf,void,"float, float*, float*" +Function,-,sinf,float,float +Function,-,sinh,double,double +Function,-,sinhf,float,float +Function,-,sinhl,long double,long double +Function,-,sinl,long double,long double +Function,-,siprintf,int,"char*, const char*, ..." +Function,-,siscanf,int,"const char*, const char*, ..." +Function,-,sniprintf,int,"char*, size_t, const char*, ..." +Function,+,snprintf,int,"char*, size_t, const char*, ..." +Function,-,sprintf,int,"char*, const char*, ..." +Function,-,sqrt,double,double +Function,-,sqrtf,float,float +Function,-,sqrtl,long double,long double +Function,+,srand,void,unsigned +Function,-,srand48,void,long +Function,-,srandom,void,unsigned +Function,+,sscanf,int,"const char*, const char*, ..." +Function,+,storage_common_copy,FS_Error,"Storage*, const char*, const char*" +Function,+,storage_common_fs_info,FS_Error,"Storage*, const char*, uint64_t*, uint64_t*" +Function,+,storage_common_merge,FS_Error,"Storage*, const char*, const char*" +Function,+,storage_common_mkdir,FS_Error,"Storage*, const char*" +Function,+,storage_common_remove,FS_Error,"Storage*, const char*" +Function,+,storage_common_rename,FS_Error,"Storage*, const char*, const char*" +Function,+,storage_common_stat,FS_Error,"Storage*, const char*, FileInfo*" +Function,+,storage_dir_close,_Bool,File* +Function,+,storage_dir_open,_Bool,"File*, const char*" +Function,+,storage_dir_read,_Bool,"File*, FileInfo*, char*, uint16_t" +Function,-,storage_dir_rewind,_Bool,File* +Function,+,storage_error_get_desc,const char*,FS_Error +Function,+,storage_file_alloc,File*,Storage* +Function,+,storage_file_close,_Bool,File* +Function,+,storage_file_eof,_Bool,File* +Function,+,storage_file_exists,_Bool,"Storage*, const char*" +Function,+,storage_file_free,void,File* +Function,+,storage_file_get_error,FS_Error,File* +Function,+,storage_file_get_error_desc,const char*,File* +Function,-,storage_file_get_internal_error,int32_t,File* +Function,+,storage_file_is_dir,_Bool,File* +Function,+,storage_file_is_open,_Bool,File* +Function,+,storage_file_open,_Bool,"File*, const char*, FS_AccessMode, FS_OpenMode" +Function,+,storage_file_read,uint16_t,"File*, void*, uint16_t" +Function,+,storage_file_seek,_Bool,"File*, uint32_t, _Bool" +Function,+,storage_file_size,uint64_t,File* +Function,-,storage_file_sync,_Bool,File* +Function,+,storage_file_tell,uint64_t,File* +Function,+,storage_file_truncate,_Bool,File* +Function,+,storage_file_write,uint16_t,"File*, const void*, uint16_t" +Function,+,storage_get_next_filename,void,"Storage*, const char*, const char*, const char*, string_t, uint8_t" +Function,+,storage_get_pubsub,FuriPubSub*,Storage* +Function,+,storage_int_backup,FS_Error,"Storage*, const char*" +Function,+,storage_int_restore,FS_Error,"Storage*, const char*, Storage_name_converter" +Function,+,storage_sd_format,FS_Error,Storage* +Function,+,storage_sd_info,FS_Error,"Storage*, SDInfo*" +Function,+,storage_sd_status,FS_Error,Storage* +Function,+,storage_sd_unmount,FS_Error,Storage* +Function,+,storage_simply_mkdir,_Bool,"Storage*, const char*" +Function,+,storage_simply_remove,_Bool,"Storage*, const char*" +Function,+,storage_simply_remove_recursive,_Bool,"Storage*, const char*" +Function,-,stpcpy,char*,"char*, const char*" +Function,-,stpncpy,char*,"char*, const char*, size_t" +Function,-,strcasecmp,int,"const char*, const char*" +Function,-,strcasecmp_l,int,"const char*, const char*, locale_t" +Function,+,strcasestr,char*,"const char*, const char*" +Function,-,strcat,char*,"char*, const char*" +Function,+,strchr,char*,"const char*, int" +Function,-,strchrnul,char*,"const char*, int" +Function,+,strcmp,int,"const char*, const char*" +Function,-,strcoll,int,"const char*, const char*" +Function,-,strcoll_l,int,"const char*, const char*, locale_t" +Function,+,strcpy,char*,"char*, const char*" +Function,+,strcspn,size_t,"const char*, const char*" +Function,+,strdup,char*,const char* +Function,+,stream_clean,void,Stream* +Function,+,stream_copy,size_t,"Stream*, Stream*, size_t" +Function,+,stream_copy_full,size_t,"Stream*, Stream*" +Function,+,stream_delete,_Bool,"Stream*, size_t" +Function,+,stream_delete_and_insert,_Bool,"Stream*, size_t, StreamWriteCB, const void*" +Function,+,stream_delete_and_insert_char,_Bool,"Stream*, size_t, char" +Function,+,stream_delete_and_insert_cstring,_Bool,"Stream*, size_t, const char*" +Function,+,stream_delete_and_insert_format,_Bool,"Stream*, size_t, const char*, ..." +Function,+,stream_delete_and_insert_string,_Bool,"Stream*, size_t, string_t" +Function,+,stream_delete_and_insert_vaformat,_Bool,"Stream*, size_t, const char*, va_list" +Function,+,stream_dump_data,void,Stream* +Function,+,stream_eof,_Bool,Stream* +Function,+,stream_free,void,Stream* +Function,+,stream_insert,_Bool,"Stream*, const uint8_t*, size_t" +Function,+,stream_insert_char,_Bool,"Stream*, char" +Function,+,stream_insert_cstring,_Bool,"Stream*, const char*" +Function,+,stream_insert_format,_Bool,"Stream*, const char*, ..." +Function,+,stream_insert_string,_Bool,"Stream*, string_t" +Function,+,stream_insert_vaformat,_Bool,"Stream*, const char*, va_list" +Function,+,stream_load_from_file,size_t,"Stream*, Storage*, const char*" +Function,+,stream_read,size_t,"Stream*, uint8_t*, size_t" +Function,+,stream_read_line,_Bool,"Stream*, string_t" +Function,+,stream_rewind,_Bool,Stream* +Function,+,stream_save_to_file,size_t,"Stream*, Storage*, const char*, FS_OpenMode" +Function,+,stream_seek,_Bool,"Stream*, int32_t, StreamOffset" +Function,+,stream_size,size_t,Stream* +Function,+,stream_split,_Bool,"Stream*, Stream*, Stream*" +Function,+,stream_tell,size_t,Stream* +Function,+,stream_write,size_t,"Stream*, const uint8_t*, size_t" +Function,+,stream_write_char,size_t,"Stream*, char" +Function,+,stream_write_cstring,size_t,"Stream*, const char*" +Function,+,stream_write_format,size_t,"Stream*, const char*, ..." +Function,+,stream_write_string,size_t,"Stream*, string_t" +Function,+,stream_write_vaformat,size_t,"Stream*, const char*, va_list" +Function,-,strerror,char*,int +Function,-,strerror_l,char*,"int, locale_t" +Function,-,strerror_r,char*,"int, char*, size_t" +Function,+,string_stream_alloc,Stream*, +Function,-,strlcat,size_t,"char*, const char*, size_t" +Function,+,strlcpy,size_t,"char*, const char*, size_t" +Function,+,strlen,size_t,const char* +Function,-,strlwr,char*,char* +Function,+,strncasecmp,int,"const char*, const char*, size_t" +Function,-,strncasecmp_l,int,"const char*, const char*, size_t, locale_t" +Function,-,strncat,char*,"char*, const char*, size_t" +Function,+,strncmp,int,"const char*, const char*, size_t" +Function,+,strncpy,char*,"char*, const char*, size_t" +Function,-,strndup,char*,"const char*, size_t" +Function,-,strnlen,size_t,"const char*, size_t" +Function,-,strnstr,char*,"const char*, const char*, size_t" +Function,-,strpbrk,char*,"const char*, const char*" +Function,+,strrchr,char*,"const char*, int" +Function,-,strsep,char*,"char**, const char*" +Function,-,strsignal,char*,int +Function,+,strspn,size_t,"const char*, const char*" +Function,+,strstr,char*,"const char*, const char*" +Function,-,strtod,double,"const char*, char**" +Function,-,strtod_l,double,"const char*, char**, locale_t" +Function,+,strtof,float,"const char*, char**" +Function,-,strtof_l,float,"const char*, char**, locale_t" +Function,-,strtok,char*,"char*, const char*" +Function,-,strtok_r,char*,"char*, const char*, char**" +Function,+,strtol,long,"const char*, char**, int" +Function,-,strtol_l,long,"const char*, char**, int, locale_t" +Function,-,strtold,long double,"const char*, char**" +Function,-,strtold_l,long double,"const char*, char**, locale_t" +Function,-,strtoll,long long,"const char*, char**, int" +Function,-,strtoll_l,long long,"const char*, char**, int, locale_t" +Function,+,strtoul,unsigned long,"const char*, char**, int" +Function,-,strtoul_l,unsigned long,"const char*, char**, int, locale_t" +Function,+,strtoull,unsigned long long,"const char*, char**, int" +Function,-,strtoull_l,unsigned long long,"const char*, char**, int, locale_t" +Function,-,strupr,char*,char* +Function,-,strverscmp,int,"const char*, const char*" +Function,-,strxfrm,size_t,"char*, const char*, size_t" +Function,-,strxfrm_l,size_t,"char*, const char*, size_t, locale_t" +Function,+,subghz_environment_alloc,SubGhzEnvironment*, +Function,+,subghz_environment_free,void,SubGhzEnvironment* +Function,-,subghz_environment_get_came_atomo_rainbow_table_file_name,const char*,SubGhzEnvironment* +Function,-,subghz_environment_get_keystore,SubGhzKeystore*,SubGhzEnvironment* +Function,-,subghz_environment_get_nice_flor_s_rainbow_table_file_name,const char*,SubGhzEnvironment* +Function,+,subghz_environment_load_keystore,_Bool,"SubGhzEnvironment*, const char*" +Function,-,subghz_environment_set_came_atomo_rainbow_table_file_name,void,"SubGhzEnvironment*, const char*" +Function,-,subghz_environment_set_nice_flor_s_rainbow_table_file_name,void,"SubGhzEnvironment*, const char*" +Function,-,subghz_keystore_alloc,SubGhzKeystore*, +Function,-,subghz_keystore_free,void,SubGhzKeystore* +Function,-,subghz_keystore_get_data,SubGhzKeyArray_t*,SubGhzKeystore* +Function,-,subghz_keystore_load,_Bool,"SubGhzKeystore*, const char*" +Function,-,subghz_keystore_raw_encrypted_save,_Bool,"const char*, const char*, uint8_t*" +Function,-,subghz_keystore_raw_get_data,_Bool,"const char*, size_t, uint8_t*, size_t" +Function,-,subghz_keystore_save,_Bool,"SubGhzKeystore*, const char*, uint8_t*" +Function,-,subghz_protocol_decoder_base_deserialize,_Bool,"SubGhzProtocolDecoderBase*, FlipperFormat*" +Function,-,subghz_protocol_decoder_base_get_hash_data,uint8_t,SubGhzProtocolDecoderBase* +Function,-,subghz_protocol_decoder_base_get_string,_Bool,"SubGhzProtocolDecoderBase*, string_t" +Function,+,subghz_protocol_decoder_base_serialize,_Bool,"SubGhzProtocolDecoderBase*, FlipperFormat*, SubGhzPresetDefinition*" +Function,-,subghz_protocol_decoder_base_set_decoder_callback,void,"SubGhzProtocolDecoderBase*, SubGhzProtocolDecoderBaseRxCallback, void*" +Function,+,subghz_protocol_decoder_raw_alloc,void*,SubGhzEnvironment* +Function,+,subghz_protocol_decoder_raw_deserialize,_Bool,"void*, FlipperFormat*" +Function,+,subghz_protocol_decoder_raw_feed,void,"void*, _Bool, uint32_t" +Function,+,subghz_protocol_decoder_raw_free,void,void* +Function,+,subghz_protocol_decoder_raw_get_string,void,"void*, string_t" +Function,+,subghz_protocol_decoder_raw_reset,void,void* +Function,+,subghz_protocol_encoder_raw_alloc,void*,SubGhzEnvironment* +Function,+,subghz_protocol_encoder_raw_deserialize,_Bool,"void*, FlipperFormat*" +Function,+,subghz_protocol_encoder_raw_free,void,void* +Function,+,subghz_protocol_encoder_raw_stop,void,void* +Function,+,subghz_protocol_encoder_raw_yield,LevelDuration,void* +Function,+,subghz_protocol_raw_file_encoder_worker_set_callback_end,void,"SubGhzProtocolEncoderRAW*, SubGhzProtocolEncoderRAWCallbackEnd, void*" +Function,+,subghz_protocol_raw_gen_fff_data,void,"FlipperFormat*, const char*" +Function,+,subghz_protocol_raw_get_sample_write,size_t,SubGhzProtocolDecoderRAW* +Function,+,subghz_protocol_raw_save_to_file_init,_Bool,"SubGhzProtocolDecoderRAW*, const char*, SubGhzPresetDefinition*" +Function,+,subghz_protocol_raw_save_to_file_stop,void,SubGhzProtocolDecoderRAW* +Function,+,subghz_receiver_alloc_init,SubGhzReceiver*,SubGhzEnvironment* +Function,+,subghz_receiver_decode,void,"SubGhzReceiver*, _Bool, uint32_t" +Function,+,subghz_receiver_free,void,SubGhzReceiver* +Function,+,subghz_receiver_reset,void,SubGhzReceiver* +Function,+,subghz_receiver_search_decoder_base_by_name,SubGhzProtocolDecoderBase*,"SubGhzReceiver*, const char*" +Function,+,subghz_receiver_set_filter,void,"SubGhzReceiver*, SubGhzProtocolFlag" +Function,+,subghz_receiver_set_rx_callback,void,"SubGhzReceiver*, SubGhzReceiverCallback, void*" +Function,+,subghz_transmitter_alloc_init,SubGhzTransmitter*,"SubGhzEnvironment*, const char*" +Function,+,subghz_transmitter_deserialize,_Bool,"SubGhzTransmitter*, FlipperFormat*" +Function,+,subghz_transmitter_free,void,SubGhzTransmitter* +Function,+,subghz_transmitter_get_protocol_instance,SubGhzProtocolEncoderBase*,SubGhzTransmitter* +Function,+,subghz_transmitter_stop,_Bool,SubGhzTransmitter* +Function,+,subghz_transmitter_yield,LevelDuration,void* +Function,+,subghz_tx_rx_worker_alloc,SubGhzTxRxWorker*, +Function,+,subghz_tx_rx_worker_available,size_t,SubGhzTxRxWorker* +Function,+,subghz_tx_rx_worker_free,void,SubGhzTxRxWorker* +Function,+,subghz_tx_rx_worker_is_running,_Bool,SubGhzTxRxWorker* +Function,+,subghz_tx_rx_worker_read,size_t,"SubGhzTxRxWorker*, uint8_t*, size_t" +Function,+,subghz_tx_rx_worker_set_callback_have_read,void,"SubGhzTxRxWorker*, SubGhzTxRxWorkerCallbackHaveRead, void*" +Function,+,subghz_tx_rx_worker_start,_Bool,"SubGhzTxRxWorker*, uint32_t" +Function,+,subghz_tx_rx_worker_stop,void,SubGhzTxRxWorker* +Function,+,subghz_tx_rx_worker_write,_Bool,"SubGhzTxRxWorker*, uint8_t*, size_t" +Function,+,subghz_worker_alloc,SubGhzWorker*, +Function,+,subghz_worker_free,void,SubGhzWorker* +Function,+,subghz_worker_is_running,_Bool,SubGhzWorker* +Function,+,subghz_worker_rx_callback,void,"_Bool, uint32_t, void*" +Function,+,subghz_worker_set_context,void,"SubGhzWorker*, void*" +Function,+,subghz_worker_set_overrun_callback,void,"SubGhzWorker*, SubGhzWorkerOverrunCallback" +Function,+,subghz_worker_set_pair_callback,void,"SubGhzWorker*, SubGhzWorkerPairCallback" +Function,+,subghz_worker_start,void,SubGhzWorker* +Function,+,subghz_worker_stop,void,SubGhzWorker* +Function,+,submenu_add_item,void,"Submenu*, const char*, uint32_t, SubmenuItemCallback, void*" +Function,+,submenu_alloc,Submenu*, +Function,+,submenu_free,void,Submenu* +Function,+,submenu_get_view,View*,Submenu* +Function,+,submenu_reset,void,Submenu* +Function,+,submenu_set_header,void,"Submenu*, const char*" +Function,+,submenu_set_selected_item,void,"Submenu*, uint32_t" +Function,-,system,int,const char* +Function,+,t5577_write,void,LFRFIDT5577* +Function,-,tan,double,double +Function,-,tanf,float,float +Function,-,tanh,double,double +Function,-,tanhf,float,float +Function,-,tanhl,long double,long double +Function,-,tanl,long double,long double +Function,+,tar_archive_add_dir,_Bool,"TarArchive*, const char*, const char*" +Function,+,tar_archive_add_file,_Bool,"TarArchive*, const char*, const char*, const int32_t" +Function,+,tar_archive_alloc,TarArchive*,Storage* +Function,+,tar_archive_dir_add_element,_Bool,"TarArchive*, const char*" +Function,+,tar_archive_file_add_data_block,_Bool,"TarArchive*, const uint8_t*, const int32_t" +Function,+,tar_archive_file_add_header,_Bool,"TarArchive*, const char*, const int32_t" +Function,+,tar_archive_file_finalize,_Bool,TarArchive* +Function,+,tar_archive_finalize,_Bool,TarArchive* +Function,+,tar_archive_free,void,TarArchive* +Function,+,tar_archive_get_entries_count,int32_t,TarArchive* +Function,+,tar_archive_open,_Bool,"TarArchive*, const char*, TarOpenMode" +Function,+,tar_archive_set_file_callback,void,"TarArchive*, tar_unpack_file_cb, void*" +Function,+,tar_archive_store_data,_Bool,"TarArchive*, const char*, const uint8_t*, const int32_t" +Function,+,tar_archive_unpack_to,_Bool,"TarArchive*, const char*, Storage_name_converter" +Function,-,tempnam,char*,"const char*, const char*" +Function,+,text_box_alloc,TextBox*, +Function,+,text_box_free,void,TextBox* +Function,+,text_box_get_view,View*,TextBox* +Function,+,text_box_reset,void,TextBox* +Function,+,text_box_set_focus,void,"TextBox*, TextBoxFocus" +Function,+,text_box_set_font,void,"TextBox*, TextBoxFont" +Function,+,text_box_set_text,void,"TextBox*, const char*" +Function,+,text_input_alloc,TextInput*, +Function,+,text_input_free,void,TextInput* +Function,+,text_input_get_validator_callback,TextInputValidatorCallback,TextInput* +Function,+,text_input_get_validator_callback_context,void*,TextInput* +Function,+,text_input_get_view,View*,TextInput* +Function,+,text_input_reset,void,TextInput* +Function,+,text_input_set_header_text,void,"TextInput*, const char*" +Function,+,text_input_set_result_callback,void,"TextInput*, TextInputCallback, void*, char*, size_t, _Bool" +Function,+,text_input_set_validator,void,"TextInput*, TextInputValidatorCallback, void*" +Function,-,tgamma,double,double +Function,-,tgammaf,float,float +Function,-,tgammal,long double,long double +Function,+,timerCalculateTimer,uint32_t,uint16_t +Function,-,timerDelay,void,uint16_t +Function,+,timerIsExpired,_Bool,uint32_t +Function,-,timerStopwatchMeasure,uint32_t, +Function,-,timerStopwatchStart,void, +Function,-,timingsafe_bcmp,int,"const void*, const void*, size_t" +Function,-,timingsafe_memcmp,int,"const void*, const void*, size_t" +Function,-,tmpfile,FILE*, +Function,-,tmpnam,char*,char* +Function,-,toascii,int,int +Function,-,toascii_l,int,"int, locale_t" +Function,-,tolower,int,int +Function,-,tolower_l,int,"int, locale_t" +Function,-,toupper,int,int +Function,-,toupper_l,int,"int, locale_t" +Function,-,trunc,double,double +Function,-,truncf,float,float +Function,-,truncl,long double,long double +Function,-,uECC_compress,void,"const uint8_t*, uint8_t*, uECC_Curve" +Function,+,uECC_compute_public_key,int,"const uint8_t*, uint8_t*, uECC_Curve" +Function,-,uECC_curve_private_key_size,int,uECC_Curve +Function,-,uECC_curve_public_key_size,int,uECC_Curve +Function,-,uECC_decompress,void,"const uint8_t*, uint8_t*, uECC_Curve" +Function,-,uECC_get_rng,uECC_RNG_Function, +Function,-,uECC_make_key,int,"uint8_t*, uint8_t*, uECC_Curve" +Function,-,uECC_secp160r1,uECC_Curve, +Function,-,uECC_secp192r1,uECC_Curve, +Function,-,uECC_secp224r1,uECC_Curve, +Function,-,uECC_secp256k1,uECC_Curve, +Function,+,uECC_secp256r1,uECC_Curve, +Function,+,uECC_set_rng,void,uECC_RNG_Function +Function,-,uECC_shared_secret,int,"const uint8_t*, const uint8_t*, uint8_t*, uECC_Curve" +Function,+,uECC_sign,int,"const uint8_t*, const uint8_t*, unsigned, uint8_t*, uECC_Curve" +Function,-,uECC_sign_deterministic,int,"const uint8_t*, const uint8_t*, unsigned, const uECC_HashContext*, uint8_t*, uECC_Curve" +Function,-,uECC_valid_public_key,int,"const uint8_t*, uECC_Curve" +Function,-,uECC_verify,int,"const uint8_t*, const uint8_t*, unsigned, const uint8_t*, uECC_Curve" +Function,-,ulTaskGenericNotifyTake,uint32_t,"UBaseType_t, BaseType_t, TickType_t" +Function,-,ulTaskGenericNotifyValueClear,uint32_t,"TaskHandle_t, UBaseType_t, uint32_t" +Function,-,ulTaskGetIdleRunTimeCounter,uint32_t, +Function,-,ulTaskGetIdleRunTimePercent,uint32_t, +Function,-,ungetc,int,"int, FILE*" +Function,-,unsetenv,int,const char* +Function,-,usbd_poll,void,usbd_device* +Function,-,utoa,char*,"unsigned, char*, int" +Function,-,uxListRemove,UBaseType_t,ListItem_t* +Function,-,uxTaskGetNumberOfTasks,UBaseType_t, +Function,-,uxTaskGetStackHighWaterMark,UBaseType_t,TaskHandle_t +Function,-,uxTaskGetStackHighWaterMark2,uint16_t,TaskHandle_t +Function,-,uxTaskGetSystemState,UBaseType_t,"TaskStatus_t*, const UBaseType_t, uint32_t*" +Function,-,uxTaskGetTaskNumber,UBaseType_t,TaskHandle_t +Function,-,uxTaskPriorityGet,UBaseType_t,const TaskHandle_t +Function,-,uxTaskPriorityGetFromISR,UBaseType_t,const TaskHandle_t +Function,-,uxTaskResetEventItemValue,TickType_t, +Function,-,uxTimerGetReloadMode,UBaseType_t,TimerHandle_t +Function,-,uxTimerGetTimerNumber,UBaseType_t,TimerHandle_t +Function,-,vApplicationGetIdleTaskMemory,void,"StaticTask_t**, StackType_t**, uint32_t*" +Function,-,vApplicationGetTimerTaskMemory,void,"StaticTask_t**, StackType_t**, uint32_t*" +Function,-,vListInitialise,void,List_t* +Function,-,vListInitialiseItem,void,ListItem_t* +Function,-,vListInsert,void,"List_t*, ListItem_t*" +Function,-,vListInsertEnd,void,"List_t*, ListItem_t*" +Function,-,vPortDefineHeapRegions,void,const HeapRegion_t* +Function,-,vPortEndScheduler,void, +Function,+,vPortEnterCritical,void, +Function,+,vPortExitCritical,void, +Function,-,vPortFree,void,void* +Function,-,vPortGetHeapStats,void,HeapStats_t* +Function,-,vPortInitialiseBlocks,void, +Function,-,vPortSuppressTicksAndSleep,void,TickType_t +Function,-,vTaskAllocateMPURegions,void,"TaskHandle_t, const MemoryRegion_t*" +Function,-,vTaskDelay,void,const TickType_t +Function,-,vTaskDelete,void,TaskHandle_t +Function,-,vTaskEndScheduler,void, +Function,-,vTaskGenericNotifyGiveFromISR,void,"TaskHandle_t, UBaseType_t, BaseType_t*" +Function,-,vTaskGetInfo,void,"TaskHandle_t, TaskStatus_t*, BaseType_t, eTaskState" +Function,-,vTaskGetRunTimeStats,void,char* +Function,-,vTaskInternalSetTimeOutState,void,TimeOut_t* +Function,-,vTaskList,void,char* +Function,-,vTaskMissedYield,void, +Function,-,vTaskPlaceOnEventList,void,"List_t*, const TickType_t" +Function,-,vTaskPlaceOnEventListRestricted,void,"List_t*, TickType_t, const BaseType_t" +Function,-,vTaskPlaceOnUnorderedEventList,void,"List_t*, const TickType_t, const TickType_t" +Function,-,vTaskPriorityDisinheritAfterTimeout,void,"const TaskHandle_t, UBaseType_t" +Function,+,vTaskPrioritySet,void,"TaskHandle_t, UBaseType_t" +Function,-,vTaskRemoveFromUnorderedEventList,void,"ListItem_t*, const TickType_t" +Function,-,vTaskResume,void,TaskHandle_t +Function,-,vTaskSetTaskNumber,void,"TaskHandle_t, const UBaseType_t" +Function,-,vTaskSetThreadLocalStoragePointer,void,"TaskHandle_t, BaseType_t, void*" +Function,-,vTaskSetTimeOutState,void,TimeOut_t* +Function,-,vTaskStartScheduler,void, +Function,-,vTaskStepTick,void,const TickType_t +Function,-,vTaskSuspend,void,TaskHandle_t +Function,-,vTaskSuspendAll,void, +Function,-,vTaskSwitchContext,void, +Function,-,vTimerSetReloadMode,void,"TimerHandle_t, const UBaseType_t" +Function,-,vTimerSetTimerID,void,"TimerHandle_t, void*" +Function,-,vTimerSetTimerNumber,void,"TimerHandle_t, UBaseType_t" +Function,+,validator_is_file_alloc_init,ValidatorIsFile*,"const char*, const char*, const char*" +Function,+,validator_is_file_callback,_Bool,"const char*, string_t, void*" +Function,+,validator_is_file_free,void,ValidatorIsFile* +Function,+,variable_item_get_context,void*,VariableItem* +Function,+,variable_item_get_current_value_index,uint8_t,VariableItem* +Function,+,variable_item_list_add,VariableItem*,"VariableItemList*, const char*, uint8_t, VariableItemChangeCallback, void*" +Function,+,variable_item_list_alloc,VariableItemList*, +Function,+,variable_item_list_free,void,VariableItemList* +Function,+,variable_item_list_get_selected_item_index,uint8_t,VariableItemList* +Function,+,variable_item_list_get_view,View*,VariableItemList* +Function,+,variable_item_list_reset,void,VariableItemList* +Function,+,variable_item_list_set_enter_callback,void,"VariableItemList*, VariableItemListEnterCallback, void*" +Function,+,variable_item_list_set_selected_item,void,"VariableItemList*, uint8_t" +Function,+,variable_item_set_current_value_index,void,"VariableItem*, uint8_t" +Function,+,variable_item_set_current_value_text,void,"VariableItem*, const char*" +Function,-,vasiprintf,int,"char**, const char*, __gnuc_va_list" +Function,-,vasniprintf,char*,"char*, size_t*, const char*, __gnuc_va_list" +Function,-,vasnprintf,char*,"char*, size_t*, const char*, __gnuc_va_list" +Function,-,vasprintf,int,"char**, const char*, __gnuc_va_list" +Function,-,vdiprintf,int,"int, const char*, __gnuc_va_list" +Function,-,vdprintf,int,"int, const char*, __gnuc_va_list" +Function,+,version_get,const Version*, +Function,+,version_get_builddate,const char*,const Version* +Function,+,version_get_dirty_flag,_Bool,const Version* +Function,+,version_get_gitbranch,const char*,const Version* +Function,+,version_get_gitbranchnum,const char*,const Version* +Function,+,version_get_githash,const char*,const Version* +Function,+,version_get_target,uint8_t,const Version* +Function,+,version_get_version,const char*,const Version* +Function,-,vfiprintf,int,"FILE*, const char*, __gnuc_va_list" +Function,-,vfiscanf,int,"FILE*, const char*, __gnuc_va_list" +Function,-,vfprintf,int,"FILE*, const char*, __gnuc_va_list" +Function,-,vfscanf,int,"FILE*, const char*, __gnuc_va_list" +Function,+,view_alloc,View*, +Function,+,view_allocate_model,void,"View*, ViewModelType, size_t" +Function,+,view_commit_model,void,"View*, _Bool" +Function,+,view_dispatcher_add_view,void,"ViewDispatcher*, uint32_t, View*" +Function,+,view_dispatcher_alloc,ViewDispatcher*, +Function,+,view_dispatcher_attach_to_gui,void,"ViewDispatcher*, Gui*, ViewDispatcherType" +Function,+,view_dispatcher_enable_queue,void,ViewDispatcher* +Function,+,view_dispatcher_free,void,ViewDispatcher* +Function,+,view_dispatcher_remove_view,void,"ViewDispatcher*, uint32_t" +Function,+,view_dispatcher_run,void,ViewDispatcher* +Function,+,view_dispatcher_send_custom_event,void,"ViewDispatcher*, uint32_t" +Function,+,view_dispatcher_send_to_back,void,ViewDispatcher* +Function,+,view_dispatcher_send_to_front,void,ViewDispatcher* +Function,+,view_dispatcher_set_custom_event_callback,void,"ViewDispatcher*, ViewDispatcherCustomEventCallback" +Function,+,view_dispatcher_set_event_callback_context,void,"ViewDispatcher*, void*" +Function,+,view_dispatcher_set_navigation_event_callback,void,"ViewDispatcher*, ViewDispatcherNavigationEventCallback" +Function,+,view_dispatcher_set_tick_event_callback,void,"ViewDispatcher*, ViewDispatcherTickEventCallback, uint32_t" +Function,+,view_dispatcher_stop,void,ViewDispatcher* +Function,+,view_dispatcher_switch_to_view,void,"ViewDispatcher*, uint32_t" +Function,+,view_free,void,View* +Function,+,view_free_model,void,View* +Function,+,view_get_model,void*,View* +Function,+,view_port_alloc,ViewPort*, +Function,+,view_port_draw_callback_set,void,"ViewPort*, ViewPortDrawCallback, void*" +Function,+,view_port_enabled_set,void,"ViewPort*, _Bool" +Function,+,view_port_free,void,ViewPort* +Function,-,view_port_get_height,uint8_t,ViewPort* +Function,+,view_port_get_orientation,ViewPortOrientation,const ViewPort* +Function,+,view_port_get_width,uint8_t,ViewPort* +Function,+,view_port_input_callback_set,void,"ViewPort*, ViewPortInputCallback, void*" +Function,+,view_port_is_enabled,_Bool,ViewPort* +Function,-,view_port_set_height,void,"ViewPort*, uint8_t" +Function,+,view_port_set_orientation,void,"ViewPort*, ViewPortOrientation" +Function,+,view_port_set_width,void,"ViewPort*, uint8_t" +Function,+,view_port_update,void,ViewPort* +Function,+,view_set_context,void,"View*, void*" +Function,-,view_set_custom_callback,void,"View*, ViewCustomCallback" +Function,+,view_set_draw_callback,void,"View*, ViewDrawCallback" +Function,+,view_set_enter_callback,void,"View*, ViewCallback" +Function,+,view_set_exit_callback,void,"View*, ViewCallback" +Function,+,view_set_input_callback,void,"View*, ViewInputCallback" +Function,+,view_set_orientation,void,"View*, ViewOrientation" +Function,+,view_set_previous_callback,void,"View*, ViewNavigationCallback" +Function,+,view_set_update_callback,void,"View*, ViewUpdateCallback" +Function,+,view_set_update_callback_context,void,"View*, void*" +Function,+,view_stack_add_view,void,"ViewStack*, View*" +Function,+,view_stack_alloc,ViewStack*, +Function,+,view_stack_free,void,ViewStack* +Function,+,view_stack_get_view,View*,ViewStack* +Function,+,view_stack_remove_view,void,"ViewStack*, View*" +Function,+,view_tie_icon_animation,void,"View*, IconAnimation*" +Function,-,viprintf,int,"const char*, __gnuc_va_list" +Function,-,viscanf,int,"const char*, __gnuc_va_list" +Function,-,vprintf,int,"const char*, __gnuc_va_list" +Function,-,vscanf,int,"const char*, __gnuc_va_list" +Function,-,vsiprintf,int,"char*, const char*, __gnuc_va_list" +Function,-,vsiscanf,int,"const char*, const char*, __gnuc_va_list" +Function,-,vsniprintf,int,"char*, size_t, const char*, __gnuc_va_list" +Function,-,vsnprintf,int,"char*, size_t, const char*, __gnuc_va_list" +Function,-,vsprintf,int,"char*, const char*, __gnuc_va_list" +Function,-,vsscanf,int,"const char*, const char*, __gnuc_va_list" +Function,-,wcstombs,size_t,"char*, const wchar_t*, size_t" +Function,-,wctomb,int,"char*, wchar_t" +Function,+,widget_add_button_element,void,"Widget*, GuiButtonType, const char*, ButtonCallback, void*" +Function,+,widget_add_frame_element,void,"Widget*, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t" +Function,+,widget_add_icon_element,void,"Widget*, uint8_t, uint8_t, const Icon*" +Function,+,widget_add_string_element,void,"Widget*, uint8_t, uint8_t, Align, Align, Font, const char*" +Function,+,widget_add_string_multiline_element,void,"Widget*, uint8_t, uint8_t, Align, Align, Font, const char*" +Function,+,widget_add_text_box_element,void,"Widget*, uint8_t, uint8_t, uint8_t, uint8_t, Align, Align, const char*, _Bool" +Function,+,widget_add_text_scroll_element,void,"Widget*, uint8_t, uint8_t, uint8_t, uint8_t, const char*" +Function,+,widget_alloc,Widget*, +Function,+,widget_free,void,Widget* +Function,+,widget_get_view,View*,Widget* +Function,+,widget_reset,void,Widget* +Function,-,write_mutex,_Bool,"ValueMutex*, void*, size_t, uint32_t" +Function,-,xPortGetFreeHeapSize,size_t, +Function,-,xPortGetMinimumEverFreeHeapSize,size_t, +Function,-,xPortStartScheduler,BaseType_t, +Function,-,xTaskAbortDelay,BaseType_t,TaskHandle_t +Function,-,xTaskCallApplicationTaskHook,BaseType_t,"TaskHandle_t, void*" +Function,-,xTaskCatchUpTicks,BaseType_t,TickType_t +Function,-,xTaskCheckForTimeOut,BaseType_t,"TimeOut_t*, TickType_t*" +Function,-,xTaskCreate,BaseType_t,"TaskFunction_t, const char*, const uint16_t, void*, UBaseType_t, TaskHandle_t*" +Function,-,xTaskCreateStatic,TaskHandle_t,"TaskFunction_t, const char*, const uint32_t, void*, UBaseType_t, StackType_t*, StaticTask_t*" +Function,-,xTaskDelayUntil,BaseType_t,"TickType_t*, const TickType_t" +Function,-,xTaskGenericNotify,BaseType_t,"TaskHandle_t, UBaseType_t, uint32_t, eNotifyAction, uint32_t*" +Function,-,xTaskGenericNotifyFromISR,BaseType_t,"TaskHandle_t, UBaseType_t, uint32_t, eNotifyAction, uint32_t*, BaseType_t*" +Function,-,xTaskGenericNotifyStateClear,BaseType_t,"TaskHandle_t, UBaseType_t" +Function,-,xTaskGenericNotifyWait,BaseType_t,"UBaseType_t, uint32_t, uint32_t, uint32_t*, TickType_t" +Function,-,xTaskGetCurrentTaskHandle,TaskHandle_t, +Function,+,xTaskGetHandle,TaskHandle_t,const char* +Function,-,xTaskGetIdleTaskHandle,TaskHandle_t, +Function,+,xTaskGetSchedulerState,BaseType_t, +Function,+,xTaskGetTickCount,TickType_t, +Function,-,xTaskGetTickCountFromISR,TickType_t, +Function,-,xTaskIncrementTick,BaseType_t, +Function,-,xTaskPriorityDisinherit,BaseType_t,const TaskHandle_t +Function,-,xTaskPriorityInherit,BaseType_t,const TaskHandle_t +Function,-,xTaskRemoveFromEventList,BaseType_t,const List_t* +Function,-,xTaskResumeAll,BaseType_t, +Function,-,xTaskResumeFromISR,BaseType_t,TaskHandle_t +Function,-,xTimerCreate,TimerHandle_t,"const char*, const TickType_t, const UBaseType_t, void*, TimerCallbackFunction_t" +Function,-,xTimerCreateStatic,TimerHandle_t,"const char*, const TickType_t, const UBaseType_t, void*, TimerCallbackFunction_t, StaticTimer_t*" +Function,-,xTimerCreateTimerTask,BaseType_t, +Function,-,xTimerGenericCommand,BaseType_t,"TimerHandle_t, const BaseType_t, const TickType_t, BaseType_t*, const TickType_t" +Function,-,xTimerGetExpiryTime,TickType_t,TimerHandle_t +Function,-,xTimerGetPeriod,TickType_t,TimerHandle_t +Function,-,xTimerGetTimerDaemonTaskHandle,TaskHandle_t, +Function,-,xTimerIsTimerActive,BaseType_t,TimerHandle_t +Function,-,xTimerPendFunctionCall,BaseType_t,"PendedFunction_t, void*, uint32_t, TickType_t" +Function,-,xTimerPendFunctionCallFromISR,BaseType_t,"PendedFunction_t, void*, uint32_t, BaseType_t*" +Function,-,y0,double,double +Function,-,y0f,float,float +Function,-,y1,double,double +Function,-,y1f,float,float +Function,-,yn,double,"int, double" +Function,-,ynf,float,"int, float" +Variable,-,AHBPrescTable,const uint32_t[16], +Variable,-,APBPrescTable,const uint32_t[8], +Variable,+,A_125khz_14,const Icon, +Variable,+,A_BadUsb_14,const Icon, +Variable,+,A_Debug_14,const Icon, +Variable,+,A_FileManager_14,const Icon, +Variable,+,A_GPIO_14,const Icon, +Variable,+,A_Infrared_14,const Icon, +Variable,+,A_Levelup1_128x64,const Icon, +Variable,+,A_Levelup2_128x64,const Icon, +Variable,+,A_Loading_24,const Icon, +Variable,+,A_NFC_14,const Icon, +Variable,+,A_Plugins_14,const Icon, +Variable,+,A_Round_loader_8x8,const Icon, +Variable,+,A_Settings_14,const Icon, +Variable,+,A_Sub1ghz_14,const Icon, +Variable,+,A_U2F_14,const Icon, +Variable,+,A_iButton_14,const Icon, +Variable,-,ITM_RxBuffer,volatile int32_t, +Variable,+,I_125_10px,const Icon, +Variable,+,I_ActiveConnection_50x64,const Icon, +Variable,+,I_ArrowC_1_36x36,const Icon, +Variable,+,I_ArrowDownEmpty_14x15,const Icon, +Variable,+,I_ArrowDownFilled_14x15,const Icon, +Variable,+,I_ArrowUpEmpty_14x15,const Icon, +Variable,+,I_ArrowUpFilled_14x15,const Icon, +Variable,+,I_Attention_5x8,const Icon, +Variable,+,I_Auth_62x31,const Icon, +Variable,+,I_BLE_Pairing_128x64,const Icon, +Variable,+,I_Background_128x11,const Icon, +Variable,+,I_BatteryBody_52x28,const Icon, +Variable,+,I_Battery_16x16,const Icon, +Variable,+,I_Battery_26x8,const Icon, +Variable,+,I_Ble_connected_15x15,const Icon, +Variable,+,I_Ble_disconnected_15x15,const Icon, +Variable,+,I_Bluetooth_Connected_16x8,const Icon, +Variable,+,I_Bluetooth_Idle_5x8,const Icon, +Variable,+,I_ButtonCenter_7x7,const Icon, +Variable,+,I_ButtonDown_7x4,const Icon, +Variable,+,I_ButtonLeftSmall_3x5,const Icon, +Variable,+,I_ButtonLeft_4x7,const Icon, +Variable,+,I_ButtonRightSmall_3x5,const Icon, +Variable,+,I_ButtonRight_4x7,const Icon, +Variable,+,I_ButtonUp_7x4,const Icon, +Variable,+,I_Button_18x18,const Icon, +Variable,+,I_Certification1_103x56,const Icon, +Variable,+,I_Certification2_98x33,const Icon, +Variable,+,I_Charging_lightning_9x10,const Icon, +Variable,+,I_Charging_lightning_mask_9x10,const Icon, +Variable,+,I_Circles_47x47,const Icon, +Variable,+,I_Clock_18x18,const Icon, +Variable,+,I_Connect_me_62x31,const Icon, +Variable,+,I_Connected_62x31,const Icon, +Variable,+,I_Cry_dolph_55x52,const Icon, +Variable,+,I_DFU_128x50,const Icon, +Variable,+,I_Detailed_chip_17x13,const Icon, +Variable,+,I_DolphinCommon_56x48,const Icon, +Variable,+,I_DolphinMafia_115x62,const Icon, +Variable,+,I_DolphinNice_96x59,const Icon, +Variable,+,I_DolphinReadingSuccess_59x63,const Icon, +Variable,+,I_DolphinWait_61x59,const Icon, +Variable,+,I_DoorLeft_70x55,const Icon, +Variable,+,I_DoorRight_70x55,const Icon, +Variable,+,I_Down_25x27,const Icon, +Variable,+,I_Down_hvr_25x27,const Icon, +Variable,+,I_Drive_112x35,const Icon, +Variable,+,I_Error_18x18,const Icon, +Variable,+,I_Error_62x31,const Icon, +Variable,+,I_EviSmile1_18x21,const Icon, +Variable,+,I_EviSmile2_18x21,const Icon, +Variable,+,I_EviWaiting1_18x21,const Icon, +Variable,+,I_EviWaiting2_18x21,const Icon, +Variable,+,I_FaceCharging_29x14,const Icon, +Variable,+,I_FaceConfused_29x14,const Icon, +Variable,+,I_FaceNopower_29x14,const Icon, +Variable,+,I_FaceNormal_29x14,const Icon, +Variable,+,I_GameMode_11x8,const Icon, +Variable,+,I_Health_16x16,const Icon, +Variable,+,I_InfraredArrowDown_4x8,const Icon, +Variable,+,I_InfraredArrowUp_4x8,const Icon, +Variable,+,I_InfraredLearnShort_128x31,const Icon, +Variable,+,I_KeyBackspaceSelected_16x9,const Icon, +Variable,+,I_KeyBackspace_16x9,const Icon, +Variable,+,I_KeySaveSelected_24x11,const Icon, +Variable,+,I_KeySave_24x11,const Icon, +Variable,+,I_Keychain_39x36,const Icon, +Variable,+,I_Left_mouse_icon_9x9,const Icon, +Variable,+,I_Lock_7x8,const Icon, +Variable,+,I_Lock_8x8,const Icon, +Variable,+,I_MHz_25x11,const Icon, +Variable,+,I_Medium_chip_22x21,const Icon, +Variable,+,I_Mute_25x27,const Icon, +Variable,+,I_Mute_hvr_25x27,const Icon, +Variable,+,I_NFC_manual_60x50,const Icon, +Variable,+,I_Nfc_10px,const Icon, +Variable,+,I_Ok_btn_9x9,const Icon, +Variable,+,I_Ok_btn_pressed_13x13,const Icon, +Variable,+,I_Percent_10x14,const Icon, +Variable,+,I_Pin_arrow_down_7x9,const Icon, +Variable,+,I_Pin_arrow_left_9x7,const Icon, +Variable,+,I_Pin_arrow_right_9x7,const Icon, +Variable,+,I_Pin_arrow_up_7x9,const Icon, +Variable,+,I_Pin_attention_dpad_29x29,const Icon, +Variable,+,I_Pin_back_arrow_10x8,const Icon, +Variable,+,I_Pin_back_full_40x8,const Icon, +Variable,+,I_Pin_pointer_5x3,const Icon, +Variable,+,I_Pin_star_7x7,const Icon, +Variable,+,I_Power_25x27,const Icon, +Variable,+,I_Power_hvr_25x27,const Icon, +Variable,+,I_Pressed_Button_13x13,const Icon, +Variable,+,I_Quest_7x8,const Icon, +Variable,+,I_RFIDBigChip_37x36,const Icon, +Variable,+,I_RFIDDolphinReceive_97x61,const Icon, +Variable,+,I_RFIDDolphinSend_97x61,const Icon, +Variable,+,I_RFIDDolphinSuccess_108x57,const Icon, +Variable,+,I_Reader_detect_43x40,const Icon, +Variable,+,I_Restoring_38x32,const Icon, +Variable,+,I_Right_mouse_icon_9x9,const Icon, +Variable,+,I_SDQuestion_35x43,const Icon, +Variable,+,I_SDcardFail_11x8,const Icon, +Variable,+,I_SDcardMounted_11x8,const Icon, +Variable,+,I_Scanning_123x52,const Icon, +Variable,+,I_Smile_18x18,const Icon, +Variable,+,I_Space_65x18,const Icon, +Variable,+,I_Tap_reader_36x38,const Icon, +Variable,+,I_Temperature_16x16,const Icon, +Variable,+,I_Unlock_7x8,const Icon, +Variable,+,I_Unplug_bg_bottom_128x10,const Icon, +Variable,+,I_Unplug_bg_top_128x14,const Icon, +Variable,+,I_Up_25x27,const Icon, +Variable,+,I_Up_hvr_25x27,const Icon, +Variable,+,I_Updating_32x40,const Icon, +Variable,+,I_UsbTree_48x22,const Icon, +Variable,+,I_Vol_down_25x27,const Icon, +Variable,+,I_Vol_down_hvr_25x27,const Icon, +Variable,+,I_Vol_up_25x27,const Icon, +Variable,+,I_Vol_up_hvr_25x27,const Icon, +Variable,+,I_Voldwn_6x6,const Icon, +Variable,+,I_Voltage_16x16,const Icon, +Variable,+,I_Volup_8x6,const Icon, +Variable,+,I_WarningDolphin_45x42,const Icon, +Variable,+,I_Warning_30x23,const Icon, +Variable,+,I_back_10px,const Icon, +Variable,+,I_badusb_10px,const Icon, +Variable,+,I_dir_10px,const Icon, +Variable,+,I_iButtonDolphinVerySuccess_108x52,const Icon, +Variable,+,I_iButtonKey_49x44,const Icon, +Variable,+,I_ibutt_10px,const Icon, +Variable,+,I_ir_10px,const Icon, +Variable,+,I_loading_10px,const Icon, +Variable,+,I_music_10px,const Icon, +Variable,+,I_passport_bad1_46x49,const Icon, +Variable,+,I_passport_bad2_46x49,const Icon, +Variable,+,I_passport_bad3_46x49,const Icon, +Variable,+,I_passport_bottom_128x18,const Icon, +Variable,+,I_passport_happy1_46x49,const Icon, +Variable,+,I_passport_happy2_46x49,const Icon, +Variable,+,I_passport_happy3_46x49,const Icon, +Variable,+,I_passport_left_6x46,const Icon, +Variable,+,I_passport_okay1_46x49,const Icon, +Variable,+,I_passport_okay2_46x49,const Icon, +Variable,+,I_passport_okay3_46x49,const Icon, +Variable,+,I_sub1_10px,const Icon, +Variable,+,I_u2f_10px,const Icon, +Variable,+,I_unknown_10px,const Icon, +Variable,+,I_update_10px,const Icon, +Variable,-,MSIRangeTable,const uint32_t[16], +Variable,-,SmpsPrescalerTable,const uint32_t[4][6], +Variable,+,SystemCoreClock,uint32_t, +Variable,+,_ctype_,const char[], +Variable,+,_global_impure_ptr,_reent*, +Variable,+,_impure_ptr,_reent*, +Variable,-,_sys_errlist,const char*[], +Variable,-,_sys_nerr,int, +Variable,+,cli_vcp,CliSession, +Variable,+,furi_hal_i2c_bus_external,FuriHalI2cBus, +Variable,+,furi_hal_i2c_bus_power,FuriHalI2cBus, +Variable,+,furi_hal_i2c_handle_external,FuriHalI2cBusHandle, +Variable,+,furi_hal_i2c_handle_power,FuriHalI2cBusHandle, +Variable,+,furi_hal_sd_spi_handle,FuriHalSpiBusHandle*, +Variable,+,furi_hal_spi_bus_d,FuriHalSpiBus, +Variable,+,furi_hal_spi_bus_handle_display,FuriHalSpiBusHandle, +Variable,+,furi_hal_spi_bus_handle_external,FuriHalSpiBusHandle, +Variable,+,furi_hal_spi_bus_handle_nfc,FuriHalSpiBusHandle, +Variable,+,furi_hal_spi_bus_handle_sd_fast,FuriHalSpiBusHandle, +Variable,+,furi_hal_spi_bus_handle_sd_slow,FuriHalSpiBusHandle, +Variable,+,furi_hal_spi_bus_handle_subghz,FuriHalSpiBusHandle, +Variable,+,furi_hal_spi_bus_r,FuriHalSpiBus, +Variable,+,furi_hal_spi_preset_1edge_low_16m,const LL_SPI_InitTypeDef, +Variable,+,furi_hal_spi_preset_1edge_low_2m,const LL_SPI_InitTypeDef, +Variable,+,furi_hal_spi_preset_1edge_low_4m,const LL_SPI_InitTypeDef, +Variable,+,furi_hal_spi_preset_1edge_low_8m,const LL_SPI_InitTypeDef, +Variable,+,furi_hal_spi_preset_2edge_low_8m,const LL_SPI_InitTypeDef, +Variable,+,gpio_button_back,const GpioPin, +Variable,+,gpio_button_down,const GpioPin, +Variable,+,gpio_button_left,const GpioPin, +Variable,+,gpio_button_ok,const GpioPin, +Variable,+,gpio_button_right,const GpioPin, +Variable,+,gpio_button_up,const GpioPin, +Variable,+,gpio_cc1101_g0,const GpioPin, +Variable,+,gpio_display_cs,const GpioPin, +Variable,+,gpio_display_di,const GpioPin, +Variable,+,gpio_display_rst_n,const GpioPin, +Variable,+,gpio_ext_pa4,const GpioPin, +Variable,+,gpio_ext_pa6,const GpioPin, +Variable,+,gpio_ext_pa7,const GpioPin, +Variable,+,gpio_ext_pb2,const GpioPin, +Variable,+,gpio_ext_pb3,const GpioPin, +Variable,+,gpio_ext_pc0,const GpioPin, +Variable,+,gpio_ext_pc1,const GpioPin, +Variable,+,gpio_ext_pc3,const GpioPin, +Variable,+,gpio_i2c_power_scl,const GpioPin, +Variable,+,gpio_i2c_power_sda,const GpioPin, +Variable,+,gpio_infrared_rx,const GpioPin, +Variable,+,gpio_infrared_tx,const GpioPin, +Variable,+,gpio_nfc_cs,const GpioPin, +Variable,+,gpio_nfc_irq_rfid_pull,const GpioPin, +Variable,+,gpio_rf_sw_0,const GpioPin, +Variable,+,gpio_rfid_carrier,const GpioPin, +Variable,+,gpio_rfid_carrier_out,const GpioPin, +Variable,+,gpio_rfid_data_in,const GpioPin, +Variable,+,gpio_sdcard_cd,const GpioPin, +Variable,+,gpio_sdcard_cs,const GpioPin, +Variable,+,gpio_speaker,const GpioPin, +Variable,+,gpio_spi_d_miso,const GpioPin, +Variable,+,gpio_spi_d_mosi,const GpioPin, +Variable,+,gpio_spi_d_sck,const GpioPin, +Variable,+,gpio_spi_r_miso,const GpioPin, +Variable,+,gpio_spi_r_mosi,const GpioPin, +Variable,+,gpio_spi_r_sck,const GpioPin, +Variable,+,gpio_subghz_cs,const GpioPin, +Variable,+,gpio_usart_rx,const GpioPin, +Variable,+,gpio_usart_tx,const GpioPin, +Variable,+,gpio_usb_dm,const GpioPin, +Variable,+,gpio_usb_dp,const GpioPin, +Variable,+,ibutton_gpio,const GpioPin, +Variable,+,input_pins,const InputPin[], +Variable,+,input_pins_count,const size_t, +Variable,+,lfrfid_protocols,const ProtocolBase*[], +Variable,+,message_blink_set_color_blue,const NotificationMessage, +Variable,+,message_blink_set_color_cyan,const NotificationMessage, +Variable,+,message_blink_set_color_green,const NotificationMessage, +Variable,+,message_blink_set_color_magenta,const NotificationMessage, +Variable,+,message_blink_set_color_red,const NotificationMessage, +Variable,+,message_blink_set_color_white,const NotificationMessage, +Variable,+,message_blink_set_color_yellow,const NotificationMessage, +Variable,+,message_blink_start_10,const NotificationMessage, +Variable,+,message_blink_start_100,const NotificationMessage, +Variable,+,message_blink_stop,const NotificationMessage, +Variable,+,message_blue_0,const NotificationMessage, +Variable,+,message_blue_255,const NotificationMessage, +Variable,+,message_click,const NotificationMessage, +Variable,+,message_delay_1,const NotificationMessage, +Variable,+,message_delay_10,const NotificationMessage, +Variable,+,message_delay_100,const NotificationMessage, +Variable,+,message_delay_1000,const NotificationMessage, +Variable,+,message_delay_25,const NotificationMessage, +Variable,+,message_delay_250,const NotificationMessage, +Variable,+,message_delay_50,const NotificationMessage, +Variable,+,message_delay_500,const NotificationMessage, +Variable,+,message_display_backlight_enforce_auto,const NotificationMessage, +Variable,+,message_display_backlight_enforce_on,const NotificationMessage, +Variable,+,message_display_backlight_off,const NotificationMessage, +Variable,+,message_display_backlight_on,const NotificationMessage, +Variable,+,message_do_not_reset,const NotificationMessage, +Variable,+,message_force_display_brightness_setting_1f,const NotificationMessage, +Variable,+,message_force_speaker_volume_setting_1f,const NotificationMessage, +Variable,+,message_force_vibro_setting_off,const NotificationMessage, +Variable,+,message_force_vibro_setting_on,const NotificationMessage, +Variable,+,message_green_0,const NotificationMessage, +Variable,+,message_green_255,const NotificationMessage, +Variable,+,message_note_a0,const NotificationMessage, +Variable,+,message_note_a1,const NotificationMessage, +Variable,+,message_note_a2,const NotificationMessage, +Variable,+,message_note_a3,const NotificationMessage, +Variable,+,message_note_a4,const NotificationMessage, +Variable,+,message_note_a5,const NotificationMessage, +Variable,+,message_note_a6,const NotificationMessage, +Variable,+,message_note_a7,const NotificationMessage, +Variable,+,message_note_a8,const NotificationMessage, +Variable,+,message_note_as0,const NotificationMessage, +Variable,+,message_note_as1,const NotificationMessage, +Variable,+,message_note_as2,const NotificationMessage, +Variable,+,message_note_as3,const NotificationMessage, +Variable,+,message_note_as4,const NotificationMessage, +Variable,+,message_note_as5,const NotificationMessage, +Variable,+,message_note_as6,const NotificationMessage, +Variable,+,message_note_as7,const NotificationMessage, +Variable,+,message_note_as8,const NotificationMessage, +Variable,+,message_note_b0,const NotificationMessage, +Variable,+,message_note_b1,const NotificationMessage, +Variable,+,message_note_b2,const NotificationMessage, +Variable,+,message_note_b3,const NotificationMessage, +Variable,+,message_note_b4,const NotificationMessage, +Variable,+,message_note_b5,const NotificationMessage, +Variable,+,message_note_b6,const NotificationMessage, +Variable,+,message_note_b7,const NotificationMessage, +Variable,+,message_note_b8,const NotificationMessage, +Variable,+,message_note_c0,const NotificationMessage, +Variable,+,message_note_c1,const NotificationMessage, +Variable,+,message_note_c2,const NotificationMessage, +Variable,+,message_note_c3,const NotificationMessage, +Variable,+,message_note_c4,const NotificationMessage, +Variable,+,message_note_c5,const NotificationMessage, +Variable,+,message_note_c6,const NotificationMessage, +Variable,+,message_note_c7,const NotificationMessage, +Variable,+,message_note_c8,const NotificationMessage, +Variable,+,message_note_cs0,const NotificationMessage, +Variable,+,message_note_cs1,const NotificationMessage, +Variable,+,message_note_cs2,const NotificationMessage, +Variable,+,message_note_cs3,const NotificationMessage, +Variable,+,message_note_cs4,const NotificationMessage, +Variable,+,message_note_cs5,const NotificationMessage, +Variable,+,message_note_cs6,const NotificationMessage, +Variable,+,message_note_cs7,const NotificationMessage, +Variable,+,message_note_cs8,const NotificationMessage, +Variable,+,message_note_d0,const NotificationMessage, +Variable,+,message_note_d1,const NotificationMessage, +Variable,+,message_note_d2,const NotificationMessage, +Variable,+,message_note_d3,const NotificationMessage, +Variable,+,message_note_d4,const NotificationMessage, +Variable,+,message_note_d5,const NotificationMessage, +Variable,+,message_note_d6,const NotificationMessage, +Variable,+,message_note_d7,const NotificationMessage, +Variable,+,message_note_d8,const NotificationMessage, +Variable,+,message_note_ds0,const NotificationMessage, +Variable,+,message_note_ds1,const NotificationMessage, +Variable,+,message_note_ds2,const NotificationMessage, +Variable,+,message_note_ds3,const NotificationMessage, +Variable,+,message_note_ds4,const NotificationMessage, +Variable,+,message_note_ds5,const NotificationMessage, +Variable,+,message_note_ds6,const NotificationMessage, +Variable,+,message_note_ds7,const NotificationMessage, +Variable,+,message_note_ds8,const NotificationMessage, +Variable,+,message_note_e0,const NotificationMessage, +Variable,+,message_note_e1,const NotificationMessage, +Variable,+,message_note_e2,const NotificationMessage, +Variable,+,message_note_e3,const NotificationMessage, +Variable,+,message_note_e4,const NotificationMessage, +Variable,+,message_note_e5,const NotificationMessage, +Variable,+,message_note_e6,const NotificationMessage, +Variable,+,message_note_e7,const NotificationMessage, +Variable,+,message_note_e8,const NotificationMessage, +Variable,+,message_note_f0,const NotificationMessage, +Variable,+,message_note_f1,const NotificationMessage, +Variable,+,message_note_f2,const NotificationMessage, +Variable,+,message_note_f3,const NotificationMessage, +Variable,+,message_note_f4,const NotificationMessage, +Variable,+,message_note_f5,const NotificationMessage, +Variable,+,message_note_f6,const NotificationMessage, +Variable,+,message_note_f7,const NotificationMessage, +Variable,+,message_note_f8,const NotificationMessage, +Variable,+,message_note_fs0,const NotificationMessage, +Variable,+,message_note_fs1,const NotificationMessage, +Variable,+,message_note_fs2,const NotificationMessage, +Variable,+,message_note_fs3,const NotificationMessage, +Variable,+,message_note_fs4,const NotificationMessage, +Variable,+,message_note_fs5,const NotificationMessage, +Variable,+,message_note_fs6,const NotificationMessage, +Variable,+,message_note_fs7,const NotificationMessage, +Variable,+,message_note_fs8,const NotificationMessage, +Variable,+,message_note_g0,const NotificationMessage, +Variable,+,message_note_g1,const NotificationMessage, +Variable,+,message_note_g2,const NotificationMessage, +Variable,+,message_note_g3,const NotificationMessage, +Variable,+,message_note_g4,const NotificationMessage, +Variable,+,message_note_g5,const NotificationMessage, +Variable,+,message_note_g6,const NotificationMessage, +Variable,+,message_note_g7,const NotificationMessage, +Variable,+,message_note_g8,const NotificationMessage, +Variable,+,message_note_gs0,const NotificationMessage, +Variable,+,message_note_gs1,const NotificationMessage, +Variable,+,message_note_gs2,const NotificationMessage, +Variable,+,message_note_gs3,const NotificationMessage, +Variable,+,message_note_gs4,const NotificationMessage, +Variable,+,message_note_gs5,const NotificationMessage, +Variable,+,message_note_gs6,const NotificationMessage, +Variable,+,message_note_gs7,const NotificationMessage, +Variable,+,message_note_gs8,const NotificationMessage, +Variable,+,message_red_0,const NotificationMessage, +Variable,+,message_red_255,const NotificationMessage, +Variable,+,message_sound_off,const NotificationMessage, +Variable,+,message_vibro_off,const NotificationMessage, +Variable,+,message_vibro_on,const NotificationMessage, +Variable,+,periph_power,const GpioPin, +Variable,+,sequence_audiovisual_alert,const NotificationSequence, +Variable,+,sequence_blink_blue_10,const NotificationSequence, +Variable,+,sequence_blink_blue_100,const NotificationSequence, +Variable,+,sequence_blink_cyan_10,const NotificationSequence, +Variable,+,sequence_blink_cyan_100,const NotificationSequence, +Variable,+,sequence_blink_green_10,const NotificationSequence, +Variable,+,sequence_blink_green_100,const NotificationSequence, +Variable,+,sequence_blink_magenta_10,const NotificationSequence, +Variable,+,sequence_blink_magenta_100,const NotificationSequence, +Variable,+,sequence_blink_red_10,const NotificationSequence, +Variable,+,sequence_blink_red_100,const NotificationSequence, +Variable,+,sequence_blink_start_blue,const NotificationSequence, +Variable,+,sequence_blink_start_cyan,const NotificationSequence, +Variable,+,sequence_blink_start_green,const NotificationSequence, +Variable,+,sequence_blink_start_magenta,const NotificationSequence, +Variable,+,sequence_blink_start_red,const NotificationSequence, +Variable,+,sequence_blink_start_yellow,const NotificationSequence, +Variable,+,sequence_blink_stop,const NotificationSequence, +Variable,+,sequence_blink_white_100,const NotificationSequence, +Variable,+,sequence_blink_yellow_10,const NotificationSequence, +Variable,+,sequence_blink_yellow_100,const NotificationSequence, +Variable,+,sequence_charged,const NotificationSequence, +Variable,+,sequence_charging,const NotificationSequence, +Variable,+,sequence_display_backlight_enforce_auto,const NotificationSequence, +Variable,+,sequence_display_backlight_enforce_on,const NotificationSequence, +Variable,+,sequence_display_backlight_off,const NotificationSequence, +Variable,+,sequence_display_backlight_off_delay_1000,const NotificationSequence, +Variable,+,sequence_display_backlight_on,const NotificationSequence, +Variable,+,sequence_double_vibro,const NotificationSequence, +Variable,+,sequence_error,const NotificationSequence, +Variable,+,sequence_not_charging,const NotificationSequence, +Variable,+,sequence_reset_blue,const NotificationSequence, +Variable,+,sequence_reset_display,const NotificationSequence, +Variable,+,sequence_reset_green,const NotificationSequence, +Variable,+,sequence_reset_red,const NotificationSequence, +Variable,+,sequence_reset_rgb,const NotificationSequence, +Variable,+,sequence_reset_sound,const NotificationSequence, +Variable,+,sequence_reset_vibro,const NotificationSequence, +Variable,+,sequence_set_blue_255,const NotificationSequence, +Variable,+,sequence_set_green_255,const NotificationSequence, +Variable,+,sequence_set_only_blue_255,const NotificationSequence, +Variable,+,sequence_set_only_green_255,const NotificationSequence, +Variable,+,sequence_set_only_red_255,const NotificationSequence, +Variable,+,sequence_set_red_255,const NotificationSequence, +Variable,+,sequence_set_vibro_on,const NotificationSequence, +Variable,+,sequence_single_vibro,const NotificationSequence, +Variable,+,sequence_solid_yellow,const NotificationSequence, +Variable,+,sequence_success,const NotificationSequence, +Variable,+,subghz_protocol_raw,const SubGhzProtocol, +Variable,+,subghz_protocol_raw_decoder,const SubGhzProtocolDecoder, +Variable,+,subghz_protocol_raw_encoder,const SubGhzProtocolEncoder, +Variable,-,suboptarg,char*, +Variable,+,usb_cdc_dual,FuriHalUsbInterface, +Variable,+,usb_cdc_single,FuriHalUsbInterface, +Variable,+,usb_hid,FuriHalUsbInterface, +Variable,+,usb_hid_u2f,FuriHalUsbInterface, +Variable,+,usbd_devfs,const usbd_driver, +Variable,+,vibro_gpio,const GpioPin, diff --git a/firmware/targets/f7/application-ext.ld b/firmware/targets/f7/application-ext.ld index 45fe431cd..8f79675be 100644 --- a/firmware/targets/f7/application-ext.ld +++ b/firmware/targets/f7/application-ext.ld @@ -1,9 +1,17 @@ +FORCE_COMMON_ALLOCATION + SECTIONS { - .text 0x00000000 : + .text 0x00000000 : ALIGN(4) { *(.text) + *(.stub) + *(.text*) *(.text.*) + *(.text._*) + + KEEP (*(.init)) + KEEP (*(.fini)) } .rodata : @@ -20,15 +28,22 @@ SECTIONS *(.data.*) } + .bss : { *(.bss) - *(.bss.*) + *(.bss*) *(.sbss) - *(.sbss.*) + *(.sbss*) *(COMMON) } + .ARM.attributes : + { + *(.ARM.attributes) + *(.ARM.attributes.*) + } + /DISCARD/ : { *(.comment) diff --git a/firmware/targets/f7/fatfs/sector_cache.c b/firmware/targets/f7/fatfs/sector_cache.c new file mode 100644 index 000000000..5a4f1b978 --- /dev/null +++ b/firmware/targets/f7/fatfs/sector_cache.c @@ -0,0 +1,59 @@ +#include "sector_cache.h" + +#include +#include +#include +#include +#include + +#define SECTOR_SIZE 512 +#define N_SECTORS 8 + +typedef struct { + uint32_t itr; + uint32_t sectors[N_SECTORS]; + uint8_t sector_data[N_SECTORS][SECTOR_SIZE]; +} SectorCache; + +static SectorCache* cache = NULL; + +void sector_cache_init() { + if(cache == NULL) { + cache = furi_hal_memory_alloc(sizeof(SectorCache)); + } + + if(cache != NULL) { + FURI_LOG_I("SectorCache", "Initializing sector cache"); + memset(cache, 0, sizeof(SectorCache)); + } else { + FURI_LOG_E("SectorCache", "Cannot enable sector cache"); + } +} + +uint8_t* sector_cache_get(uint32_t n_sector) { + if(cache != NULL && n_sector != 0) { + for(int sector_i = 0; sector_i < N_SECTORS; ++sector_i) { + if(cache->sectors[sector_i] == n_sector) { + return cache->sector_data[sector_i]; + } + } + } + return NULL; +} + +void sector_cache_put(uint32_t n_sector, uint8_t* data) { + if(cache == NULL) return; + cache->sectors[cache->itr % N_SECTORS] = n_sector; + memcpy(cache->sector_data[cache->itr % N_SECTORS], data, SECTOR_SIZE); + cache->itr++; +} + +void sector_cache_invalidate_range(uint32_t start_sector, uint32_t end_sector) { + if(cache == NULL) return; + for(int sector_i = 0; sector_i < N_SECTORS; ++sector_i) { + if((cache->sectors[sector_i] >= start_sector) && + (cache->sectors[sector_i] <= end_sector)) { + cache->sectors[sector_i] = 0; + } + } +} \ No newline at end of file diff --git a/firmware/targets/f7/fatfs/sector_cache.h b/firmware/targets/f7/fatfs/sector_cache.h new file mode 100644 index 000000000..5fe4a2ed8 --- /dev/null +++ b/firmware/targets/f7/fatfs/sector_cache.h @@ -0,0 +1,36 @@ +#pragma once +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Init sector cache system + */ +void sector_cache_init(); + +/** + * @brief Get sector data from cache + * @param n_sector Sector number + * @return Pointer to sector data or NULL if not found + */ +uint8_t* sector_cache_get(uint32_t n_sector); + +/** + * @brief Put sector data to cache + * @param n_sector Sector number + * @param data Pointer to sector data + */ +void sector_cache_put(uint32_t n_sector, uint8_t* data); + +/** + * @brief Invalidate sector cache for given range + * @param start_sector Start sector number + * @param end_sector End sector number + */ +void sector_cache_invalidate_range(uint32_t start_sector, uint32_t end_sector); + +#ifdef __cplusplus +} +#endif diff --git a/firmware/targets/f7/fatfs/stm32_adafruit_sd.c b/firmware/targets/f7/fatfs/stm32_adafruit_sd.c index 6db430a53..07cae31fe 100644 --- a/firmware/targets/f7/fatfs/stm32_adafruit_sd.c +++ b/firmware/targets/f7/fatfs/stm32_adafruit_sd.c @@ -92,6 +92,7 @@ #include "string.h" #include "stdio.h" #include +#include "sector_cache.h" /** @addtogroup BSP * @{ @@ -377,6 +378,8 @@ uint8_t BSP_SD_Init(bool reset_card) { furi_hal_sd_spi_handle = NULL; furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_slow); + sector_cache_init(); + /* SD initialized and set to SPI mode properly */ return res; } @@ -427,9 +430,15 @@ uint8_t uint32_t offset = 0; uint32_t addr; uint8_t retr = BSP_SD_ERROR; - uint8_t* ptr = NULL; SD_CmdAnswer_typedef response; uint16_t BlockSize = 512; + uint8_t* cached_data; + + bool single_sector_read = (NumOfBlocks == 1); + if(single_sector_read && (cached_data = sector_cache_get(ReadAddr))) { + memcpy(pData, cached_data, BlockSize); + return BSP_SD_OK; + } /* Send CMD16 (SD_CMD_SET_BLOCKLEN) to set the size of the block and Check if the SD acknowledged the set block length command: R1 response (0x00: no errors) */ @@ -440,12 +449,6 @@ uint8_t goto error; } - ptr = malloc(sizeof(uint8_t) * BlockSize); - if(ptr == NULL) { - goto error; - } - memset(ptr, SD_DUMMY_BYTE, sizeof(uint8_t) * BlockSize); - /* Initialize the address */ addr = (ReadAddr * ((flag_SDHC == 1) ? 1 : BlockSize)); @@ -461,7 +464,7 @@ uint8_t /* Now look for the data token to signify the start of the data */ if(SD_WaitData(SD_TOKEN_START_DATA_SINGLE_BLOCK_READ) == BSP_SD_OK) { /* Read the SD block data : read NumByteToRead data */ - SD_IO_WriteReadData(ptr, (uint8_t*)pData + offset, BlockSize); + SD_IO_WriteReadData(NULL, (uint8_t*)pData + offset, BlockSize); /* Set next read address*/ offset += BlockSize; @@ -479,13 +482,16 @@ uint8_t SD_IO_WriteByte(SD_DUMMY_BYTE); } + if(single_sector_read) { + sector_cache_put(ReadAddr, (uint8_t*)pData); + } + retr = BSP_SD_OK; error: /* Send dummy byte: 8 Clock pulses of delay */ SD_IO_CSState(1); SD_IO_WriteByte(SD_DUMMY_BYTE); - if(ptr != NULL) free(ptr); /* Return the reponse */ return retr; @@ -509,9 +515,9 @@ uint8_t BSP_SD_WriteBlocks( uint32_t offset = 0; uint32_t addr; uint8_t retr = BSP_SD_ERROR; - uint8_t* ptr = NULL; SD_CmdAnswer_typedef response; uint16_t BlockSize = 512; + sector_cache_invalidate_range(WriteAddr, WriteAddr + NumOfBlocks); /* Send CMD16 (SD_CMD_SET_BLOCKLEN) to set the size of the block and Check if the SD acknowledged the set block length command: R1 response (0x00: no errors) */ @@ -522,11 +528,6 @@ uint8_t BSP_SD_WriteBlocks( goto error; } - ptr = malloc(sizeof(uint8_t) * BlockSize); - if(ptr == NULL) { - goto error; - } - /* Initialize the address */ addr = (WriteAddr * ((flag_SDHC == 1) ? 1 : BlockSize)); @@ -547,7 +548,7 @@ uint8_t BSP_SD_WriteBlocks( SD_IO_WriteByte(SD_TOKEN_START_DATA_SINGLE_BLOCK_WRITE); /* Write the block data to SD */ - SD_IO_WriteReadData((uint8_t*)pData + offset, ptr, BlockSize); + SD_IO_WriteReadData((uint8_t*)pData + offset, NULL, BlockSize); /* Set next write address */ offset += BlockSize; @@ -569,7 +570,7 @@ uint8_t BSP_SD_WriteBlocks( retr = BSP_SD_OK; error: - if(ptr != NULL) free(ptr); + /* Send dummy byte: 8 Clock pulses of delay */ SD_IO_CSState(1); SD_IO_WriteByte(SD_DUMMY_BYTE); diff --git a/firmware/targets/f7/furi_hal/furi_hal.c b/firmware/targets/f7/furi_hal/furi_hal.c index d0856127a..141efdb60 100644 --- a/firmware/targets/f7/furi_hal/furi_hal.c +++ b/firmware/targets/f7/furi_hal/furi_hal.c @@ -1,5 +1,6 @@ #include #include +#include #include @@ -78,6 +79,7 @@ void furi_hal_init() { furi_hal_rfid_init(); #endif furi_hal_bt_init(); + furi_hal_memory_init(); furi_hal_compress_icon_init(); // FatFS driver initialization diff --git a/firmware/targets/f7/furi_hal/furi_hal_clock.h b/firmware/targets/f7/furi_hal/furi_hal_clock.h index 9cb11db4b..6cebb20c6 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_clock.h +++ b/firmware/targets/f7/furi_hal/furi_hal_clock.h @@ -1,5 +1,9 @@ #pragma once +#ifdef __cplusplus +extern "C" { +#endif + /** Early initialization */ void furi_hal_clock_init_early(); @@ -20,3 +24,7 @@ void furi_hal_clock_suspend_tick(); /** Continue SysTick counter operation */ void furi_hal_clock_resume_tick(); + +#ifdef __cplusplus +} +#endif diff --git a/firmware/targets/f7/furi_hal/furi_hal_flash.h b/firmware/targets/f7/furi_hal/furi_hal_flash.h index eac80d95e..1ed4c0399 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_flash.h +++ b/firmware/targets/f7/furi_hal/furi_hal_flash.h @@ -4,6 +4,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + #define FURI_HAL_FLASH_OB_RAW_SIZE_BYTES 0x80 #define FURI_HAL_FLASH_OB_SIZE_WORDS (FURI_HAL_FLASH_OB_RAW_SIZE_BYTES / sizeof(uint32_t)) #define FURI_HAL_FLASH_OB_TOTAL_VALUES (FURI_HAL_FLASH_OB_SIZE_WORDS / 2) @@ -142,3 +146,7 @@ void furi_hal_flash_ob_apply(); * @return pointer to read-only data of OB (raw + complementary values) */ const FuriHalFlashRawOptionByteData* furi_hal_flash_ob_get_raw_ptr(); + +#ifdef __cplusplus +} +#endif diff --git a/firmware/targets/f7/furi_hal/furi_hal_memory.c b/firmware/targets/f7/furi_hal/furi_hal_memory.c new file mode 100644 index 000000000..43dc56f11 --- /dev/null +++ b/firmware/targets/f7/furi_hal/furi_hal_memory.c @@ -0,0 +1,119 @@ +#include +#include +#include + +#define TAG "FuriHalMemory" + +typedef enum { + SRAM_A, + SRAM_B, + SRAM_MAX, +} SRAM; + +typedef struct { + void* start; + uint32_t size; +} FuriHalMemoryRegion; + +typedef struct { + FuriHalMemoryRegion region[SRAM_MAX]; +} FuriHalMemory; + +static FuriHalMemory* furi_hal_memory = NULL; + +extern const void __sram2a_start__; +extern const void __sram2a_free__; +extern const void __sram2b_start__; + +void furi_hal_memory_init() { + if(furi_hal_rtc_get_boot_mode() != FuriHalRtcBootModeNormal) { + return; + } + + if(!ble_glue_wait_for_c2_start(FURI_HAL_BT_C2_START_TIMEOUT)) { + FURI_LOG_E(TAG, "C2 start timeout"); + return; + } + + FuriHalMemory* memory = malloc(sizeof(FuriHalMemory)); + + const BleGlueC2Info* c2_ver = ble_glue_get_c2_info(); + + if(c2_ver->mode == BleGlueC2ModeStack) { + uint32_t sram2a_busy_size = (uint32_t)&__sram2a_free__ - (uint32_t)&__sram2a_start__; + uint32_t sram2a_unprotected_size = (32 - c2_ver->MemorySizeSram2A) * 1024; + uint32_t sram2b_unprotected_size = (32 - c2_ver->MemorySizeSram2B) * 1024; + + memory->region[SRAM_A].start = (uint8_t*)&__sram2a_free__; + memory->region[SRAM_B].start = (uint8_t*)&__sram2b_start__; + + if(sram2a_unprotected_size > sram2a_busy_size) { + memory->region[SRAM_A].size = sram2a_unprotected_size - sram2a_busy_size; + } else { + memory->region[SRAM_A].size = 0; + } + memory->region[SRAM_B].size = sram2b_unprotected_size; + + FURI_LOG_I( + TAG, "SRAM2A: 0x%p, %d", memory->region[SRAM_A].start, memory->region[SRAM_A].size); + FURI_LOG_I( + TAG, "SRAM2B: 0x%p, %d", memory->region[SRAM_B].start, memory->region[SRAM_B].size); + + if((memory->region[SRAM_A].size > 0) || (memory->region[SRAM_B].size > 0)) { + if((memory->region[SRAM_A].size > 0)) { + FURI_LOG_I(TAG, "SRAM2A clear"); + memset(memory->region[SRAM_A].start, 0, memory->region[SRAM_A].size); + } + if((memory->region[SRAM_B].size > 0)) { + FURI_LOG_I(TAG, "SRAM2B clear"); + memset(memory->region[SRAM_B].start, 0, memory->region[SRAM_B].size); + } + furi_hal_memory = memory; + FURI_LOG_I(TAG, "Enabled"); + } else { + free(memory); + FURI_LOG_E(TAG, "No SRAM2 available"); + } + } else { + free(memory); + FURI_LOG_E(TAG, "No Core2 available"); + } +} + +void* furi_hal_memory_alloc(size_t size) { + if(furi_hal_memory == NULL) { + return NULL; + } + + for(int i = 0; i < SRAM_MAX; i++) { + if(furi_hal_memory->region[i].size >= size) { + void* ptr = furi_hal_memory->region[i].start; + furi_hal_memory->region[i].start += size; + furi_hal_memory->region[i].size -= size; + return ptr; + } + } + return NULL; +} + +size_t furi_hal_memory_get_free() { + if(furi_hal_memory == NULL) return 0; + + size_t free = 0; + for(int i = 0; i < SRAM_MAX; i++) { + free += furi_hal_memory->region[i].size; + } + return free; +} + +size_t furi_hal_memory_max_pool_block() { + if(furi_hal_memory == NULL) return 0; + + size_t max = 0; + for(int i = 0; i < SRAM_MAX; i++) { + if(furi_hal_memory->region[i].size > max) { + max = furi_hal_memory->region[i].size; + } + } + return max; +} \ No newline at end of file diff --git a/firmware/targets/f7/furi_hal/furi_hal_nfc.c b/firmware/targets/f7/furi_hal/furi_hal_nfc.c index 2d6db8fbf..de67bbc35 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_nfc.c +++ b/firmware/targets/f7/furi_hal/furi_hal_nfc.c @@ -39,6 +39,10 @@ bool furi_hal_nfc_is_busy() { return rfalNfcGetState() != RFAL_NFC_STATE_IDLE; } +bool furi_hal_nfc_is_init() { + return rfalNfcGetState() != RFAL_NFC_STATE_NOTINIT; +} + void furi_hal_nfc_field_on() { furi_hal_nfc_exit_sleep(); st25r3916TxRxOn(); @@ -124,7 +128,9 @@ bool furi_hal_nfc_detect(FuriHalNfcDevData* nfc_data, uint32_t timeout) { } nfc_data->cuid = (cuid_start[0] << 24) | (cuid_start[1] << 16) | (cuid_start[2] << 8) | (cuid_start[3]); - } else if(dev_list[0].type == RFAL_NFC_LISTEN_TYPE_NFCB) { + } else if( + dev_list[0].type == RFAL_NFC_LISTEN_TYPE_NFCB || + dev_list[0].type == RFAL_NFC_LISTEN_TYPE_ST25TB) { nfc_data->type = FuriHalNfcTypeB; } else if(dev_list[0].type == RFAL_NFC_LISTEN_TYPE_NFCF) { nfc_data->type = FuriHalNfcTypeF; @@ -215,7 +221,6 @@ bool furi_hal_nfc_listen( } rfalLowPowerModeStop(); rfalNfcDiscoverParam params = { - .compMode = RFAL_COMPLIANCE_MODE_NFC, .techs2Find = RFAL_NFC_LISTEN_TECH_A, .totalDuration = 1000, .devLimit = 1, @@ -228,6 +233,11 @@ bool furi_hal_nfc_listen( .notifyCb = NULL, .activate_after_sak = activate_after_sak, }; + if(FURI_BIT(sak, 5)) { + params.compMode = RFAL_COMPLIANCE_MODE_EMV; + } else { + params.compMode = RFAL_COMPLIANCE_MODE_NFC; + } params.lmConfigPA.nfcidLen = uid_len; memcpy(params.lmConfigPA.nfcid, uid, uid_len); params.lmConfigPA.SENS_RES[0] = atqa[0]; @@ -269,6 +279,10 @@ void furi_hal_nfc_listen_sleep() { st25r3916ExecuteCommand(ST25R3916_CMD_GOTO_SLEEP); } +void furi_hal_nfc_stop_cmd() { + st25r3916ExecuteCommand(ST25R3916_CMD_STOP); +} + bool furi_hal_nfc_listen_rx(FuriHalNfcTxRxContext* tx_rx, uint32_t timeout_ms) { furi_assert(tx_rx); @@ -281,6 +295,9 @@ bool furi_hal_nfc_listen_rx(FuriHalNfcTxRxContext* tx_rx, uint32_t timeout_ms) { if(st25r3916GetInterrupt(ST25R3916_IRQ_MASK_RXE)) { furi_hal_nfc_read_fifo(tx_rx->rx_data, &tx_rx->rx_bits); data_received = true; + if(tx_rx->sniff_rx) { + tx_rx->sniff_rx(tx_rx->rx_data, tx_rx->rx_bits, false, tx_rx->sniff_context); + } break; } continue; @@ -495,14 +512,14 @@ static bool furi_hal_nfc_transparent_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_ furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_nfc); st25r3916ExecuteCommand(ST25R3916_CMD_UNMASK_RECEIVE_DATA); - if(tx_rx->sniff_tx) { - tx_rx->sniff_tx(tx_rx->tx_data, tx_rx->tx_bits, false, tx_rx->sniff_context); - } - // Manually wait for interrupt furi_hal_gpio_init(&gpio_nfc_irq_rfid_pull, GpioModeInput, GpioPullDown, GpioSpeedVeryHigh); st25r3916ClearAndEnableInterrupts(ST25R3916_IRQ_MASK_RXE); + if(tx_rx->sniff_tx) { + tx_rx->sniff_tx(tx_rx->tx_data, tx_rx->tx_bits, false, tx_rx->sniff_context); + } + uint32_t irq = 0; uint8_t rxe = 0; uint32_t start = DWT->CYCCNT; @@ -725,3 +742,46 @@ void furi_hal_nfc_sleep() { rfalNfcDeactivate(false); rfalLowPowerModeStart(); } + +FuriHalNfcReturn furi_hal_nfc_ll_set_mode(FuriHalNfcMode mode, FuriHalNfcBitrate txBR, FuriHalNfcBitrate rxBR) { + return rfalSetMode((rfalMode)mode, (rfalBitRate)txBR, (rfalBitRate)rxBR); +} + +void furi_hal_nfc_ll_set_error_handling(FuriHalNfcErrorHandling eHandling) { + rfalSetErrorHandling((rfalEHandling)eHandling); +} + +void furi_hal_nfc_ll_set_guard_time(uint32_t cycles) { + rfalSetGT(cycles); +} + +void furi_hal_nfc_ll_set_fdt_listen(uint32_t cycles) { + rfalSetFDTListen(cycles); +} + +void furi_hal_nfc_ll_set_fdt_poll(uint32_t FDTPoll) { + rfalSetFDTPoll(FDTPoll); +} + +void furi_hal_nfc_ll_txrx_on() { + st25r3916TxRxOn(); +} + +void furi_hal_nfc_ll_txrx_off() { + st25r3916TxRxOff(); +} + +FuriHalNfcReturn furi_hal_nfc_ll_txrx( + uint8_t* txBuf, + uint16_t txBufLen, + uint8_t* rxBuf, + uint16_t rxBufLen, + uint16_t* actLen, + uint32_t flags, + uint32_t fwt) { + return rfalTransceiveBlockingTxRx(txBuf, txBufLen, rxBuf, rxBufLen, actLen, flags, fwt); +} + +void furi_hal_nfc_ll_poll() { + rfalWorker(); +} \ No newline at end of file diff --git a/firmware/targets/f7/furi_hal/furi_hal_spi.c b/firmware/targets/f7/furi_hal/furi_hal_spi.c index f8c5a2c78..2d54278d6 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_spi.c +++ b/firmware/targets/f7/furi_hal/furi_hal_spi.c @@ -139,8 +139,6 @@ bool furi_hal_spi_bus_trx( uint32_t timeout) { furi_assert(handle); furi_assert(handle->bus->current_handle == handle); - furi_assert(tx_buffer); - furi_assert(rx_buffer); furi_assert(size > 0); bool ret = true; @@ -149,15 +147,23 @@ bool furi_hal_spi_bus_trx( while(size > 0) { if(tx_size > 0 && LL_SPI_IsActiveFlag_TXE(handle->bus->spi) && tx_allowed) { - LL_SPI_TransmitData8(handle->bus->spi, *tx_buffer); - tx_buffer++; + if(tx_buffer) { + LL_SPI_TransmitData8(handle->bus->spi, *tx_buffer); + tx_buffer++; + } else { + LL_SPI_TransmitData8(handle->bus->spi, 0xFF); + } tx_size--; tx_allowed = false; } if(LL_SPI_IsActiveFlag_RXNE(handle->bus->spi)) { - *rx_buffer = LL_SPI_ReceiveData8(handle->bus->spi); - rx_buffer++; + if(rx_buffer) { + *rx_buffer = LL_SPI_ReceiveData8(handle->bus->spi); + rx_buffer++; + } else { + LL_SPI_ReceiveData8(handle->bus->spi); + } size--; tx_allowed = true; } diff --git a/firmware/targets/f7/furi_hal/furi_hal_subghz.c b/firmware/targets/f7/furi_hal/furi_hal_subghz.c index ade462389..b73d074fd 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_subghz.c +++ b/firmware/targets/f7/furi_hal/furi_hal_subghz.c @@ -17,6 +17,27 @@ #define TAG "FuriHalSubGhz" +/* + * Uncomment define to enable duplication of + * IO GO0 CC1101 to an external comb. + * Debug pin can be assigned + * gpio_ext_pc0 + * gpio_ext_pc1 + * gpio_ext_pc3 + * gpio_ext_pb2 + * gpio_ext_pb3 + * gpio_ext_pa4 + * gpio_ext_pa6 + * gpio_ext_pa7 + * Attention this setting switches pin to output. + * Make sure it is not connected directly to power or ground + */ + +//#define SUBGHZ_DEBUG_CC1101_PIN gpio_ext_pa7 +#ifdef SUBGHZ_DEBUG_CC1101_PIN +uint32_t subghz_debug_gpio_buff[2]; +#endif + typedef struct { volatile SubGhzState state; volatile SubGhzRegulation regulation; @@ -361,6 +382,9 @@ static void furi_hal_subghz_capture_ISR() { LL_TIM_ClearFlag_CC1(TIM2); furi_hal_subghz_capture_delta_duration = LL_TIM_IC_GetCaptureCH1(TIM2); if(furi_hal_subghz_capture_callback) { +#ifdef SUBGHZ_DEBUG_CC1101_PIN + furi_hal_gpio_write(&SUBGHZ_DEBUG_CC1101_PIN, false); +#endif furi_hal_subghz_capture_callback( true, furi_hal_subghz_capture_delta_duration, @@ -371,6 +395,9 @@ static void furi_hal_subghz_capture_ISR() { if(LL_TIM_IsActiveFlag_CC2(TIM2)) { LL_TIM_ClearFlag_CC2(TIM2); if(furi_hal_subghz_capture_callback) { +#ifdef SUBGHZ_DEBUG_CC1101_PIN + furi_hal_gpio_write(&SUBGHZ_DEBUG_CC1101_PIN, true); +#endif furi_hal_subghz_capture_callback( false, LL_TIM_IC_GetCaptureCH2(TIM2) - furi_hal_subghz_capture_delta_duration, @@ -432,6 +459,11 @@ void furi_hal_subghz_start_async_rx(FuriHalSubGhzCaptureCallback callback, void* LL_TIM_SetCounter(TIM2, 0); LL_TIM_EnableCounter(TIM2); +#ifdef SUBGHZ_DEBUG_CC1101_PIN + furi_hal_gpio_init( + &SUBGHZ_DEBUG_CC1101_PIN, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); +#endif + // Switch to RX furi_hal_subghz_rx(); } @@ -445,6 +477,11 @@ void furi_hal_subghz_stop_async_rx() { FURI_CRITICAL_ENTER(); LL_TIM_DeInit(TIM2); + +#ifdef SUBGHZ_DEBUG_CC1101_PIN + furi_hal_gpio_init(&SUBGHZ_DEBUG_CC1101_PIN, GpioModeAnalog, GpioPullNo, GpioSpeedLow); +#endif + FURI_CRITICAL_EXIT(); furi_hal_interrupt_set_isr(FuriHalInterruptIdTIM2, NULL, NULL); @@ -630,6 +667,32 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void* LL_TIM_SetCounter(TIM2, 0); LL_TIM_EnableCounter(TIM2); + +#ifdef SUBGHZ_DEBUG_CC1101_PIN + furi_hal_gpio_init( + &SUBGHZ_DEBUG_CC1101_PIN, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); + + const GpioPin* gpio = &SUBGHZ_DEBUG_CC1101_PIN; + subghz_debug_gpio_buff[0] = gpio->pin; + subghz_debug_gpio_buff[1] = (uint32_t)gpio->pin << GPIO_NUMBER; + + dma_config.MemoryOrM2MDstAddress = (uint32_t)subghz_debug_gpio_buff; + dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (gpio->port->BSRR); + dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; + dma_config.Mode = LL_DMA_MODE_CIRCULAR; + dma_config.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; + dma_config.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; + dma_config.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; + dma_config.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; + dma_config.NbData = 2; + dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; + dma_config.Priority = LL_DMA_PRIORITY_VERYHIGH; + LL_DMA_Init(DMA1, LL_DMA_CHANNEL_2, &dma_config); + LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_2, 2); + LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2); + +#endif + return true; } @@ -661,6 +724,12 @@ void furi_hal_subghz_stop_async_tx() { // Deinitialize GPIO furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + +#ifdef SUBGHZ_DEBUG_CC1101_PIN + LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_2); + furi_hal_gpio_init(&SUBGHZ_DEBUG_CC1101_PIN, GpioModeAnalog, GpioPullNo, GpioSpeedLow); +#endif + FURI_CRITICAL_EXIT(); free(furi_hal_subghz_async_tx.buffer); diff --git a/firmware/targets/f7/furi_hal/furi_hal_usb_cdc.c b/firmware/targets/f7/furi_hal/furi_hal_usb_cdc.c index 69a7fb3ce..88deafdcc 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_usb_cdc.c +++ b/firmware/targets/f7/furi_hal/furi_hal_usb_cdc.c @@ -1,7 +1,7 @@ #include "furi_hal_version.h" #include "furi_hal_usb_i.h" #include "furi_hal_usb.h" -#include "furi_hal_usb_cdc_i.h" +#include "furi_hal_usb_cdc.h" #include #include "usb.h" diff --git a/firmware/targets/f7/furi_hal/furi_hal_usb_cdc_i.h b/firmware/targets/f7/furi_hal/furi_hal_usb_cdc.h similarity index 91% rename from firmware/targets/f7/furi_hal/furi_hal_usb_cdc_i.h rename to firmware/targets/f7/furi_hal/furi_hal_usb_cdc.h index 4ba150eb5..89b68991b 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_usb_cdc_i.h +++ b/firmware/targets/f7/furi_hal/furi_hal_usb_cdc.h @@ -5,6 +5,10 @@ #define CDC_DATA_SZ 64 +#ifdef __cplusplus +extern "C" { +#endif + typedef struct { void (*tx_ep_callback)(void* context); void (*rx_ep_callback)(void* context); @@ -22,3 +26,7 @@ uint8_t furi_hal_cdc_get_ctrl_line_state(uint8_t if_num); void furi_hal_cdc_send(uint8_t if_num, uint8_t* buf, uint16_t len); int32_t furi_hal_cdc_receive(uint8_t if_num, uint8_t* buf, uint16_t max_len); + +#ifdef __cplusplus +} +#endif diff --git a/firmware/targets/f7/platform_specific/intrinsic_export.h b/firmware/targets/f7/platform_specific/intrinsic_export.h new file mode 100644 index 000000000..8dbc4bd03 --- /dev/null +++ b/firmware/targets/f7/platform_specific/intrinsic_export.h @@ -0,0 +1,11 @@ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void __clear_cache(void*, void*); + +#ifdef __cplusplus +} +#endif diff --git a/firmware/targets/f7/stm32wb55xx_flash.ld b/firmware/targets/f7/stm32wb55xx_flash.ld index 20314ba3c..e1fb98b9f 100644 --- a/firmware/targets/f7/stm32wb55xx_flash.ld +++ b/firmware/targets/f7/stm32wb55xx_flash.ld @@ -57,7 +57,8 @@ MEMORY { FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K RAM1 (xrw) : ORIGIN = 0x20000008, LENGTH = 0x2FFF8 -RAM_SHARED (xrw) : ORIGIN = 0x20030000, LENGTH = 10K +RAM2A (xrw) : ORIGIN = 0x20030000, LENGTH = 10K +RAM2B (xrw) : ORIGIN = 0x20038000, LENGTH = 10K } /* Define output sections */ @@ -130,7 +131,7 @@ SECTIONS _sidata = LOADADDR(.data); /* Initialized data sections goes into RAM, load LMA copy after code */ - .data : + .data : { . = ALIGN(4); _sdata = .; /* create a global symbol at data start */ @@ -142,7 +143,6 @@ SECTIONS _edata = .; /* define a global symbol at data end */ } >RAM1 AT> FLASH - /* Uninitialized data section */ . = ALIGN(4); .bss : @@ -160,7 +160,8 @@ SECTIONS } >RAM1 /* User_heap_stack section, used to check that there is enough RAM left */ - ._user_heap_stack(NOLOAD): + /* DSECT: https://software-dl.ti.com/ccs/esd/documents/sdto_cgt_linker_special_section_types.html */ + ._user_heap_stack(DSECT): { . = ALIGN(8); __heap_start__ = .; @@ -171,11 +172,11 @@ SECTIONS } >RAM1 /* Free Flash space, that can be used for internal storage */ - .free_flash(NOLOAD): + .free_flash(DSECT): { __free_flash_start__ = .; . = ORIGIN(FLASH) + LENGTH(FLASH); - } >FLASH + } >FLASH /* Remove information from the standard libraries */ /DISCARD/ : @@ -186,9 +187,12 @@ SECTIONS } .ARM.attributes 0 : { *(.ARM.attributes) } - MAPPING_TABLE (NOLOAD) : { *(MAPPING_TABLE) } >RAM_SHARED - MB_MEM1 (NOLOAD) : { *(MB_MEM1) } >RAM_SHARED - MB_MEM2 (NOLOAD) : { _sMB_MEM2 = . ; *(MB_MEM2) ; _eMB_MEM2 = . ; } >RAM_SHARED + ._sram2a_start : { . = ALIGN(4); __sram2a_start__ = .; } >RAM2A + MAPPING_TABLE (NOLOAD) : { *(MAPPING_TABLE) } >RAM2A + MB_MEM1 (NOLOAD) : { *(MB_MEM1) } >RAM2A + MB_MEM2 (NOLOAD) : { _sMB_MEM2 = . ; *(MB_MEM2) ; _eMB_MEM2 = . ; } >RAM2A + ._sram2a_free : { . = ALIGN(4); __sram2a_free__ = .; } >RAM2A + ._sram2b_start : { . = ALIGN(4); __sram2b_start__ = .; } >RAM2B } diff --git a/firmware/targets/f7/stm32wb55xx_ram_fw.ld b/firmware/targets/f7/stm32wb55xx_ram_fw.ld index 8c4d41c5b..db9e407c9 100644 --- a/firmware/targets/f7/stm32wb55xx_ram_fw.ld +++ b/firmware/targets/f7/stm32wb55xx_ram_fw.ld @@ -57,7 +57,8 @@ MEMORY { FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K RAM1 (xrw) : ORIGIN = 0x20000000, LENGTH = 0x30000 -RAM_SHARED (xrw) : ORIGIN = 0x20030000, LENGTH = 10K +RAM2A (xrw) : ORIGIN = 0x20030000, LENGTH = 10K +RAM2B (xrw) : ORIGIN = 0x20038000, LENGTH = 10K } /* Define output sections */ @@ -158,7 +159,7 @@ SECTIONS } >RAM1 /* User_heap_stack section, used to check that there is enough RAM left */ - ._user_heap_stack : + ._user_heap_stack(DSECT) : { . = ALIGN(8); __heap_start__ = .; @@ -169,7 +170,7 @@ SECTIONS } >RAM1 /* Free Flash space, that can be used for internal storage */ - /*.free_flash(NOLOAD): + /*.free_flash(DSECT): { __free_flash_start__ = .; . = ORIGIN(FLASH) + LENGTH(FLASH); @@ -184,9 +185,12 @@ SECTIONS } .ARM.attributes 0 : { *(.ARM.attributes) } - MAPPING_TABLE (NOLOAD) : { *(MAPPING_TABLE) } >RAM_SHARED - MB_MEM1 (NOLOAD) : { *(MB_MEM1) } >RAM_SHARED - MB_MEM2 (NOLOAD) : { _sMB_MEM2 = . ; *(MB_MEM2) ; _eMB_MEM2 = . ; } >RAM_SHARED + ._sram2a_start : { . = ALIGN(4); __sram2a_start__ = .; } >RAM2A + MAPPING_TABLE (NOLOAD) : { *(MAPPING_TABLE) } >RAM2A + MB_MEM1 (NOLOAD) : { *(MB_MEM1) } >RAM2A + MB_MEM2 (NOLOAD) : { _sMB_MEM2 = . ; *(MB_MEM2) ; _eMB_MEM2 = . ; } >RAM2A + ._sram2a_free : { . = ALIGN(4); __sram2a_free__ = .; } >RAM2A + ._sram2b_start : { . = ALIGN(4); __sram2b_start__ = .; } >RAM2B } diff --git a/firmware/targets/furi_hal_include/furi_hal.h b/firmware/targets/furi_hal_include/furi_hal.h index 2a372a6c3..8613c4d5e 100644 --- a/firmware/targets/furi_hal_include/furi_hal.h +++ b/firmware/targets/furi_hal_include/furi_hal.h @@ -6,7 +6,8 @@ #pragma once #ifdef __cplusplus -template struct STOP_EXTERNING_ME {}; +template +struct STOP_EXTERNING_ME {}; #endif #include "furi_hal_cortex.h" diff --git a/firmware/targets/furi_hal_include/furi_hal_bt_hid.h b/firmware/targets/furi_hal_include/furi_hal_bt_hid.h index e35edd01c..4e74bbda7 100644 --- a/firmware/targets/furi_hal_include/furi_hal_bt_hid.h +++ b/firmware/targets/furi_hal_include/furi_hal_bt_hid.h @@ -3,6 +3,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + /** Start Hid Keyboard Profile */ void furi_hal_bt_hid_start(); @@ -81,3 +85,7 @@ bool furi_hal_bt_hid_consumer_key_release(uint16_t button); * @param button key code */ bool furi_hal_bt_hid_consumer_key_release_all(); + +#ifdef __cplusplus +} +#endif diff --git a/firmware/targets/furi_hal_include/furi_hal_bt_serial.h b/firmware/targets/furi_hal_include/furi_hal_bt_serial.h index 9cc4ba5bb..e1b7af224 100644 --- a/firmware/targets/furi_hal_include/furi_hal_bt_serial.h +++ b/firmware/targets/furi_hal_include/furi_hal_bt_serial.h @@ -2,6 +2,10 @@ #include "serial_service.h" +#ifdef __cplusplus +extern "C" { +#endif + #define FURI_HAL_BT_SERIAL_PACKET_SIZE_MAX SERIAL_SVC_DATA_LEN_MAX /** Serial service callback type */ @@ -38,3 +42,7 @@ void furi_hal_bt_serial_notify_buffer_is_empty(); * @return true on success */ bool furi_hal_bt_serial_tx(uint8_t* data, uint16_t size); + +#ifdef __cplusplus +} +#endif diff --git a/firmware/targets/furi_hal_include/furi_hal_compress.h b/firmware/targets/furi_hal_include/furi_hal_compress.h index 17ce3e691..f80aee516 100644 --- a/firmware/targets/furi_hal_include/furi_hal_compress.h +++ b/firmware/targets/furi_hal_include/furi_hal_compress.h @@ -8,6 +8,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + /** Defines encoder and decoder window size */ #define FURI_HAL_COMPRESS_EXP_BUFF_SIZE_LOG (8) @@ -77,3 +81,7 @@ bool furi_hal_compress_decode( uint8_t* data_out, size_t data_out_size, size_t* data_res_size); + +#ifdef __cplusplus +} +#endif diff --git a/firmware/targets/furi_hal_include/furi_hal_crypto.h b/firmware/targets/furi_hal_include/furi_hal_crypto.h index fc3974bbe..81788e96e 100644 --- a/firmware/targets/furi_hal_include/furi_hal_crypto.h +++ b/firmware/targets/furi_hal_include/furi_hal_crypto.h @@ -8,6 +8,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + /** FuriHalCryptoKey Type */ typedef enum { FuriHalCryptoKeyTypeMaster, /**< Master key */ @@ -82,3 +86,7 @@ bool furi_hal_crypto_encrypt(const uint8_t* input, uint8_t* output, size_t size) * @return true on success */ bool furi_hal_crypto_decrypt(const uint8_t* input, uint8_t* output, size_t size); + +#ifdef __cplusplus +} +#endif diff --git a/firmware/targets/furi_hal_include/furi_hal_memory.h b/firmware/targets/furi_hal_include/furi_hal_memory.h new file mode 100644 index 000000000..e9efa08c1 --- /dev/null +++ b/firmware/targets/furi_hal_include/furi_hal_memory.h @@ -0,0 +1,44 @@ +/** + * @file furi_hal_memory.h + * Memory HAL API + */ + +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Init memory pool manager + */ +void furi_hal_memory_init(); + +/** + * @brief Allocate memory from separate memory pool. That memory can't be freed. + * + * @param size + * @return void* + */ +void* furi_hal_memory_alloc(size_t size); + +/** + * @brief Get free memory pool size + * + * @return size_t + */ +size_t furi_hal_memory_get_free(); + +/** + * @brief Get max free block size from memory pool + * + * @return size_t + */ +size_t furi_hal_memory_max_pool_block(); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/firmware/targets/furi_hal_include/furi_hal_nfc.h b/firmware/targets/furi_hal_include/furi_hal_nfc.h index 71186076f..537e0abf0 100644 --- a/firmware/targets/furi_hal_include/furi_hal_nfc.h +++ b/firmware/targets/furi_hal_include/furi_hal_nfc.h @@ -5,16 +5,15 @@ #pragma once -#include #include #include #include -#include - #ifdef __cplusplus extern "C" { #endif +#include +#include #define FURI_HAL_NFC_UID_MAX_LEN 10 #define FURI_HAL_NFC_DATA_BUFF_SIZE (512) @@ -108,6 +107,12 @@ void furi_hal_nfc_init(); */ bool furi_hal_nfc_is_busy(); +/** Check if nfc is initialized + * + * @return true if initialized + */ + bool furi_hal_nfc_is_init(); + /** NFC field on */ void furi_hal_nfc_field_on(); @@ -120,6 +125,8 @@ void furi_hal_nfc_field_off(); */ void furi_hal_nfc_start_sleep(); +void furi_hal_nfc_stop_cmd(); + /** NFC stop sleep */ void furi_hal_nfc_exit_sleep(); @@ -227,6 +234,158 @@ void furi_hal_nfc_sleep(); void furi_hal_nfc_stop(); + +/* Low level transport API, use it to implement your own transport layers */ + +#define furi_hal_nfc_ll_ms2fc rfalConvMsTo1fc + +#define FURI_HAL_NFC_LL_TXRX_FLAGS_CRC_TX_MANUAL RFAL_TXRX_FLAGS_CRC_TX_MANUAL +#define FURI_HAL_NFC_LL_TXRX_FLAGS_AGC_ON RFAL_TXRX_FLAGS_AGC_ON +#define FURI_HAL_NFC_LL_TXRX_FLAGS_PAR_RX_REMV RFAL_TXRX_FLAGS_PAR_RX_REMV +#define FURI_HAL_NFC_LL_TXRX_FLAGS_CRC_RX_KEEP RFAL_TXRX_FLAGS_CRC_RX_KEEP + +typedef enum { + FuriHalNfcReturnOk = 0, /*!< no error occurred */ + FuriHalNfcReturnNomem = 1, /*!< not enough memory to perform the requested operation */ + FuriHalNfcReturnBusy = 2, /*!< device or resource busy */ + FuriHalNfcReturnIo = 3, /*!< generic IO error */ + FuriHalNfcReturnTimeout = 4, /*!< error due to timeout */ + FuriHalNfcReturnRequest = 5, /*!< invalid request or requested function can't be executed at the moment */ + FuriHalNfcReturnNomsg = 6, /*!< No message of desired type */ + FuriHalNfcReturnParam = 7, /*!< Parameter error */ + FuriHalNfcReturnSystem = 8, /*!< System error */ + FuriHalNfcReturnFraming = 9, /*!< Framing error */ + FuriHalNfcReturnOverrun = 10, /*!< lost one or more received bytes */ + FuriHalNfcReturnProto = 11, /*!< protocol error */ + FuriHalNfcReturnInternal = 12, /*!< Internal Error */ + FuriHalNfcReturnAgain = 13, /*!< Call again */ + FuriHalNfcReturnMemCorrupt = 14, /*!< memory corruption */ + FuriHalNfcReturnNotImplemented = 15, /*!< not implemented */ + FuriHalNfcReturnPcCorrupt = 16, /*!< Program Counter has been manipulated or spike/noise trigger illegal operation */ + FuriHalNfcReturnSend = 17, /*!< error sending*/ + FuriHalNfcReturnIgnore = 18, /*!< indicates error detected but to be ignored */ + FuriHalNfcReturnSemantic = 19, /*!< indicates error in state machine (unexpected cmd) */ + FuriHalNfcReturnSyntax = 20, /*!< indicates error in state machine (unknown cmd) */ + FuriHalNfcReturnCrc = 21, /*!< crc error */ + FuriHalNfcReturnNotfound = 22, /*!< transponder not found */ + FuriHalNfcReturnNotunique = 23, /*!< transponder not unique - more than one transponder in field */ + FuriHalNfcReturnNotsupp = 24, /*!< requested operation not supported */ + FuriHalNfcReturnWrite = 25, /*!< write error */ + FuriHalNfcReturnFifo = 26, /*!< fifo over or underflow error */ + FuriHalNfcReturnPar = 27, /*!< parity error */ + FuriHalNfcReturnDone = 28, /*!< transfer has already finished */ + FuriHalNfcReturnRfCollision = 29, /*!< collision error (Bit Collision or during RF Collision avoidance ) */ + FuriHalNfcReturnHwOverrun = 30, /*!< lost one or more received bytes */ + FuriHalNfcReturnReleaseReq = 31, /*!< device requested release */ + FuriHalNfcReturnSleepReq = 32, /*!< device requested sleep */ + FuriHalNfcReturnWrongState = 33, /*!< incorrent state for requested operation */ + FuriHalNfcReturnMaxReruns = 34, /*!< blocking procedure reached maximum runs */ + FuriHalNfcReturnDisabled = 35, /*!< operation aborted due to disabled configuration */ + FuriHalNfcReturnHwMismatch = 36, /*!< expected hw do not match */ + FuriHalNfcReturnLinkLoss = 37, /*!< Other device's field didn't behave as expected: turned off by Initiator in Passive mode, or AP2P did not turn on field */ + FuriHalNfcReturnInvalidHandle = 38, /*!< invalid or not initalized device handle */ + FuriHalNfcReturnIncompleteByte = 40, /*!< Incomplete byte rcvd */ + FuriHalNfcReturnIncompleteByte01 = 41, /*!< Incomplete byte rcvd - 1 bit */ + FuriHalNfcReturnIncompleteByte02 = 42, /*!< Incomplete byte rcvd - 2 bit */ + FuriHalNfcReturnIncompleteByte03 = 43, /*!< Incomplete byte rcvd - 3 bit */ + FuriHalNfcReturnIncompleteByte04 = 44, /*!< Incomplete byte rcvd - 4 bit */ + FuriHalNfcReturnIncompleteByte05 = 45, /*!< Incomplete byte rcvd - 5 bit */ + FuriHalNfcReturnIncompleteByte06 = 46, /*!< Incomplete byte rcvd - 6 bit */ + FuriHalNfcReturnIncompleteByte07 = 47, /*!< Incomplete byte rcvd - 7 bit */ +} FuriHalNfcReturn; + +typedef enum { + FuriHalNfcModeNone = 0, /*!< No mode selected/defined */ + FuriHalNfcModePollNfca = 1, /*!< Mode to perform as NFCA (ISO14443A) Poller (PCD) */ + FuriHalNfcModePollNfcaT1t = 2, /*!< Mode to perform as NFCA T1T (Topaz) Poller (PCD) */ + FuriHalNfcModePollNfcb = 3, /*!< Mode to perform as NFCB (ISO14443B) Poller (PCD) */ + FuriHalNfcModePollBPrime = 4, /*!< Mode to perform as B' Calypso (Innovatron) (PCD) */ + FuriHalNfcModePollBCts = 5, /*!< Mode to perform as CTS Poller (PCD) */ + FuriHalNfcModePollNfcf = 6, /*!< Mode to perform as NFCF (FeliCa) Poller (PCD) */ + FuriHalNfcModePollNfcv = 7, /*!< Mode to perform as NFCV (ISO15963) Poller (PCD) */ + FuriHalNfcModePollPicopass = 8, /*!< Mode to perform as PicoPass / iClass Poller (PCD) */ + FuriHalNfcModePollActiveP2p = 9, /*!< Mode to perform as Active P2P (ISO18092) Initiator */ + FuriHalNfcModeListenNfca = 10, /*!< Mode to perform as NFCA (ISO14443A) Listener (PICC) */ + FuriHalNfcModeListenNfcb = 11, /*!< Mode to perform as NFCA (ISO14443B) Listener (PICC) */ + FuriHalNfcModeListenNfcf = 12, /*!< Mode to perform as NFCA (ISO15963) Listener (PICC) */ + FuriHalNfcModeListenActiveP2p = 13 /*!< Mode to perform as Active P2P (ISO18092) Target */ +} FuriHalNfcMode; + +typedef enum { + FuriHalNfcBitrate106 = 0, /*!< Bit Rate 106 kbit/s (fc/128) */ + FuriHalNfcBitrate212 = 1, /*!< Bit Rate 212 kbit/s (fc/64) */ + FuriHalNfcBitrate424 = 2, /*!< Bit Rate 424 kbit/s (fc/32) */ + FuriHalNfcBitrate848 = 3, /*!< Bit Rate 848 kbit/s (fc/16) */ + FuriHalNfcBitrate1695 = 4, /*!< Bit Rate 1695 kbit/s (fc/8) */ + FuriHalNfcBitrate3390 = 5, /*!< Bit Rate 3390 kbit/s (fc/4) */ + FuriHalNfcBitrate6780 = 6, /*!< Bit Rate 6780 kbit/s (fc/2) */ + FuriHalNfcBitrate13560 = 7, /*!< Bit Rate 13560 kbit/s (fc) */ + FuriHalNfcBitrate52p97 = 0xEB, /*!< Bit Rate 52.97 kbit/s (fc/256) Fast Mode VICC->VCD */ + FuriHalNfcBitrate26p48 = 0xEC, /*!< Bit Rate 26,48 kbit/s (fc/512) NFCV VICC->VCD & VCD->VICC 1of4 */ + FuriHalNfcBitrate1p66 = 0xED, /*!< Bit Rate 1,66 kbit/s (fc/8192) NFCV VCD->VICC 1of256 */ + FuriHalNfcBitrateKeep = 0xFF /*!< Value indicating to keep the same previous bit rate */ +} FuriHalNfcBitrate; + +FuriHalNfcReturn furi_hal_nfc_ll_set_mode(FuriHalNfcMode mode, FuriHalNfcBitrate txBR, FuriHalNfcBitrate rxBR); + +#define FURI_HAL_NFC_LL_GT_NFCA furi_hal_nfc_ll_ms2fc(5U) /*!< GTA Digital 2.0 6.10.4.1 & B.2 */ +#define FURI_HAL_NFC_LL_GT_NFCB furi_hal_nfc_ll_ms2fc(5U) /*!< GTB Digital 2.0 7.9.4.1 & B.3 */ +#define FURI_HAL_NFC_LL_GT_NFCF furi_hal_nfc_ll_ms2fc(20U) /*!< GTF Digital 2.0 8.7.4.1 & B.4 */ +#define FURI_HAL_NFC_LL_GT_NFCV furi_hal_nfc_ll_ms2fc(5U) /*!< GTV Digital 2.0 9.7.5.1 & B.5 */ +#define FURI_HAL_NFC_LL_GT_PICOPASS furi_hal_nfc_ll_ms2fc(1U) /*!< GT Picopass */ +#define FURI_HAL_NFC_LL_GT_AP2P furi_hal_nfc_ll_ms2fc(5U) /*!< TIRFG Ecma 340 11.1.1 */ +#define FURI_HAL_NFC_LL_GT_AP2P_ADJUSTED furi_hal_nfc_ll_ms2fc(5U + 25U) /*!< Adjusted GT for greater interoperability (Sony XPERIA P, Nokia N9, Huawei P2) */ + +void furi_hal_nfc_ll_set_guard_time(uint32_t cycles); + +typedef enum { + FuriHalNfcErrorHandlingNone = 0, /*!< No special error handling will be performed */ + FuriHalNfcErrorHandlingNfc = 1, /*!< Error handling set to perform as NFC compliant device */ + FuriHalNfcErrorHandlingEmvco = 2 /*!< Error handling set to perform as EMVCo compliant device */ +} FuriHalNfcErrorHandling; + +void furi_hal_nfc_ll_set_error_handling(FuriHalNfcErrorHandling eHandling); + +/* RFAL Frame Delay Time (FDT) Listen default values */ +#define FURI_HAL_NFC_LL_FDT_LISTEN_NFCA_POLLER 1172U /*!< FDTA,LISTEN,MIN (n=9) Last bit: Logic "1" - tnn,min/2 Digital 1.1 6.10 ; EMV CCP Spec Book D v2.01 4.8.1.3 */ +#define FURI_HAL_NFC_LL_FDT_LISTEN_NFCB_POLLER 1008U /*!< TR0B,MIN Digital 1.1 7.1.3 & A.3 ; EMV CCP Spec Book D v2.01 4.8.1.3 & Table A.5 */ +#define FURI_HAL_NFC_LL_FDT_LISTEN_NFCF_POLLER 2672U /*!< TR0F,LISTEN,MIN Digital 1.1 8.7.1.1 & A.4 */ +#define FURI_HAL_NFC_LL_FDT_LISTEN_NFCV_POLLER 4310U /*!< FDTV,LISTEN,MIN t1 min Digital 2.1 B.5 ; ISO15693-3 2009 9.1 */ +#define FURI_HAL_NFC_LL_FDT_LISTEN_PICOPASS_POLLER 3400U /*!< ISO15693 t1 min - observed adjustment */ +#define FURI_HAL_NFC_LL_FDT_LISTEN_AP2P_POLLER 64U /*!< FDT AP2P No actual FDTListen is required as fields switch and collision avoidance */ +#define FURI_HAL_NFC_LL_FDT_LISTEN_NFCA_LISTENER 1172U /*!< FDTA,LISTEN,MIN Digital 1.1 6.10 */ +#define FURI_HAL_NFC_LL_FDT_LISTEN_NFCB_LISTENER 1024U /*!< TR0B,MIN Digital 1.1 7.1.3 & A.3 ; EMV CCP Spec Book D v2.01 4.8.1.3 & Table A.5 */ +#define FURI_HAL_NFC_LL_FDT_LISTEN_NFCF_LISTENER 2688U /*!< TR0F,LISTEN,MIN Digital 2.1 8.7.1.1 & B.4 */ +#define FURI_HAL_NFC_LL_FDT_LISTEN_AP2P_LISTENER 64U /*!< FDT AP2P No actual FDTListen exists as fields switch and collision avoidance */ + +void furi_hal_nfc_ll_set_fdt_listen(uint32_t cycles); + +/* RFAL Frame Delay Time (FDT) Poll default values */ +#define FURI_HAL_NFC_LL_FDT_POLL_NFCA_POLLER 6780U /*!< FDTA,POLL,MIN Digital 1.1 6.10.3.1 & A.2 */ +#define FURI_HAL_NFC_LL_FDT_POLL_NFCA_T1T_POLLER 384U /*!< RRDDT1T,MIN,B1 Digital 1.1 10.7.1 & A.5 */ +#define FURI_HAL_NFC_LL_FDT_POLL_NFCB_POLLER 6780U /*!< FDTB,POLL,MIN = TR2B,MIN,DEFAULT Digital 1.1 7.9.3 & A.3 ; EMVCo 3.0 FDTB,PCD,MIN Table A.5 */ +#define FURI_HAL_NFC_LL_FDT_POLL_NFCF_POLLER 6800U /*!< FDTF,POLL,MIN Digital 2.1 8.7.3 & B.4 */ +#define FURI_HAL_NFC_LL_FDT_POLL_NFCV_POLLER 4192U /*!< FDTV,POLL Digital 2.1 9.7.3.1 & B.5 */ +#define FURI_HAL_NFC_LL_FDT_POLL_PICOPASS_POLLER 1790U /*!< FDT Max */ +#define FURI_HAL_NFC_LL_FDT_POLL_AP2P_POLLER 0U /*!< FDT AP2P No actual FDTPoll exists as fields switch and collision avoidance */ + +void furi_hal_nfc_ll_set_fdt_poll(uint32_t FDTPoll); + +void furi_hal_nfc_ll_txrx_on(); + +void furi_hal_nfc_ll_txrx_off(); + +FuriHalNfcReturn furi_hal_nfc_ll_txrx( + uint8_t* txBuf, + uint16_t txBufLen, + uint8_t* rxBuf, + uint16_t rxBufLen, + uint16_t* actLen, + uint32_t flags, + uint32_t fwt); + +void furi_hal_nfc_ll_poll(); + #ifdef __cplusplus } #endif diff --git a/firmware/targets/furi_hal_include/furi_hal_power.h b/firmware/targets/furi_hal_include/furi_hal_power.h index 16af959cf..3ab30c424 100644 --- a/firmware/targets/furi_hal_include/furi_hal_power.h +++ b/firmware/targets/furi_hal_include/furi_hal_power.h @@ -156,12 +156,6 @@ float furi_hal_power_get_battery_current(FuriHalPowerIC ic); */ float furi_hal_power_get_battery_temperature(FuriHalPowerIC ic); -/** Get System voltage in V - * - * @return voltage in V - */ -float furi_hal_power_get_system_voltage(); - /** Get USB voltage in V * * @return voltage in V diff --git a/firmware/targets/furi_hal_include/furi_hal_region.h b/firmware/targets/furi_hal_include/furi_hal_region.h index 10d519ab7..accd7e127 100644 --- a/firmware/targets/furi_hal_include/furi_hal_region.h +++ b/firmware/targets/furi_hal_include/furi_hal_region.h @@ -4,6 +4,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + typedef struct { uint32_t start; uint32_t end; @@ -71,3 +75,7 @@ bool furi_hal_region_is_frequency_allowed(uint32_t frequency); * @return { description_of_the_return_value } */ const FuriHalRegionBand* furi_hal_region_get_band(uint32_t frequency); + +#ifdef __cplusplus +} +#endif diff --git a/firmware/targets/furi_hal_include/furi_hal_usb.h b/firmware/targets/furi_hal_include/furi_hal_usb.h index 33115c116..8b49f6c65 100644 --- a/firmware/targets/furi_hal_include/furi_hal_usb.h +++ b/firmware/targets/furi_hal_include/furi_hal_usb.h @@ -2,6 +2,10 @@ #include "usb.h" +#ifdef __cplusplus +extern "C" { +#endif + typedef struct FuriHalUsbInterface FuriHalUsbInterface; struct FuriHalUsbInterface { @@ -81,3 +85,7 @@ void furi_hal_usb_set_state_callback(FuriHalUsbStateCallback cb, void* ctx); /** Restart USB device */ void furi_hal_usb_reinit(); + +#ifdef __cplusplus +} +#endif diff --git a/firmware/targets/furi_hal_include/furi_hal_usb_hid.h b/firmware/targets/furi_hal_include/furi_hal_usb_hid.h index 97bac7f04..f4b40c89d 100644 --- a/firmware/targets/furi_hal_include/furi_hal_usb_hid.h +++ b/firmware/targets/furi_hal_include/furi_hal_usb_hid.h @@ -5,6 +5,10 @@ #include "hid_usage_consumer.h" #include "hid_usage_led.h" +#ifdef __cplusplus +extern "C" { +#endif + #define HID_KEYBOARD_NONE 0x00 // Remapping the colon key which is shift + ; to comma #define HID_KEYBOARD_COMMA HID_KEYBOARD_COLON @@ -251,3 +255,7 @@ bool furi_hal_hid_consumer_key_press(uint16_t button); * @param button key code */ bool furi_hal_hid_consumer_key_release(uint16_t button); + +#ifdef __cplusplus +} +#endif diff --git a/firmware/targets/furi_hal_include/furi_hal_usb_hid_u2f.h b/firmware/targets/furi_hal_include/furi_hal_usb_hid_u2f.h index e9bf57657..1b20a33c4 100644 --- a/firmware/targets/furi_hal_include/furi_hal_usb_hid_u2f.h +++ b/firmware/targets/furi_hal_include/furi_hal_usb_hid_u2f.h @@ -1,5 +1,9 @@ #pragma once +#ifdef __cplusplus +extern "C" { +#endif + #define HID_U2F_PACKET_LEN 64 typedef enum { @@ -34,3 +38,7 @@ uint32_t furi_hal_hid_u2f_get_request(uint8_t* data); * @param len packet length */ void furi_hal_hid_u2f_send_response(uint8_t* data, uint8_t len); + +#ifdef __cplusplus +} +#endif diff --git a/furi/core/core_defines.h b/furi/core/core_defines.h index 801810f6a..487fe2ca3 100644 --- a/furi/core/core_defines.h +++ b/furi/core/core_defines.h @@ -85,7 +85,11 @@ extern "C" { #endif #ifndef FURI_BIT_SET -#define FURI_BIT_SET(x, n) ((x) |= (1 << (n))) +#define FURI_BIT_SET(x, n) \ + ({ \ + __typeof__(x) _x = (1); \ + (x) |= (_x << (n)); \ + }) #endif #ifndef FURI_BIT_CLEAR diff --git a/furi/core/memmgr.c b/furi/core/memmgr.c index 80f87b930..768adc05d 100644 --- a/furi/core/memmgr.c +++ b/furi/core/memmgr.c @@ -1,6 +1,7 @@ #include "memmgr.h" #include "common_defines.h" #include +#include extern void* pvPortMalloc(size_t xSize); extern void vPortFree(void* pv); @@ -77,3 +78,34 @@ void* __wrap__realloc_r(struct _reent* r, void* ptr, size_t size) { UNUSED(r); return realloc(ptr, size); } + +void* memmgr_alloc_from_pool(size_t size) { + void* p = furi_hal_memory_alloc(size); + if(p == NULL) p = malloc(size); + + return p; +} + +size_t memmgr_pool_get_free(void) { + return furi_hal_memory_get_free(); +} + +size_t memmgr_pool_get_max_block(void) { + return furi_hal_memory_max_pool_block(); +} + +void* aligned_malloc(size_t size, size_t alignment) { + void* p1; // original block + void** p2; // aligned block + int offset = alignment - 1 + sizeof(void*); + if((p1 = (void*)malloc(size + offset)) == NULL) { + return NULL; + } + p2 = (void**)(((size_t)(p1) + offset) & ~(alignment - 1)); + p2[-1] = p1; + return p2; +} + +void aligned_free(void* p) { + free(((void**)p)[-1]); +} \ No newline at end of file diff --git a/furi/core/memmgr.h b/furi/core/memmgr.h index d7285fb23..d3ad0c87c 100644 --- a/furi/core/memmgr.h +++ b/furi/core/memmgr.h @@ -35,6 +35,43 @@ size_t memmgr_get_total_heap(void); */ size_t memmgr_get_minimum_free_heap(void); +/** + * An aligned version of malloc, used when you need to get the aligned space on the heap + * Freeing the received address is performed ONLY through the aligned_free function + * @param size + * @param alignment + * @return void* + */ +void* aligned_malloc(size_t size, size_t alignment); + +/** + * Freed space obtained through the aligned_malloc function + * @param p pointer to result of aligned_malloc + */ +void aligned_free(void* p); + +/** + * @brief Allocate memory from separate memory pool. That memory can't be freed. + * + * @param size + * @return void* + */ +void* memmgr_alloc_from_pool(size_t size); + +/** + * @brief Get free memory pool size + * + * @return size_t + */ +size_t memmgr_pool_get_free(void); + +/** + * @brief Get max free block size from memory pool + * + * @return size_t + */ +size_t memmgr_pool_get_max_block(void); + #ifdef __cplusplus } #endif diff --git a/furi/core/thread.c b/furi/core/thread.c index 044f83711..a68472b56 100644 --- a/furi/core/thread.c +++ b/furi/core/thread.c @@ -7,7 +7,9 @@ #include "mutex.h" #include +#include "log.h" #include +#include #include #define THREAD_NOTIFY_INDEX 1 // Index 0 is used for stream buffers @@ -20,6 +22,7 @@ struct FuriThreadStdout { }; struct FuriThread { + bool is_service; FuriThreadState state; int32_t ret; @@ -84,6 +87,11 @@ static void furi_thread_body(void* context) { furi_assert(thread->state == FuriThreadStateRunning); furi_thread_set_state(thread, FuriThreadStateStopped); + if(thread->is_service) { + FURI_LOG_E( + "Service", "%s thread exited. Thread memory cannot be reclaimed.", thread->name); + } + // clear thread local storage __furi_thread_stdout_flush(thread); furi_assert(pvTaskGetThreadLocalStoragePointer(NULL, 0) != NULL); @@ -96,7 +104,7 @@ static void furi_thread_body(void* context) { FuriThread* furi_thread_alloc() { FuriThread* thread = malloc(sizeof(FuriThread)); string_init(thread->output.buffer); - + thread->is_service = false; return thread; } @@ -117,6 +125,10 @@ void furi_thread_set_name(FuriThread* thread, const char* name) { thread->name = name ? strdup(name) : NULL; } +void furi_thread_mark_as_service(FuriThread* thread) { + thread->is_service = true; +} + void furi_thread_set_stack_size(FuriThread* thread, size_t stack_size) { furi_assert(thread); furi_assert(thread->state == FuriThreadStateStopped); @@ -168,15 +180,23 @@ void furi_thread_start(FuriThread* thread) { furi_thread_set_state(thread, FuriThreadStateStarting); - BaseType_t ret = xTaskCreate( - furi_thread_body, - thread->name, - thread->stack_size / 4, - thread, - thread->priority ? thread->priority : FuriThreadPriorityNormal, - &thread->task_handle); + uint32_t stack = thread->stack_size / 4; + UBaseType_t priority = thread->priority ? thread->priority : FuriThreadPriorityNormal; + if(thread->is_service) { + thread->task_handle = xTaskCreateStatic( + furi_thread_body, + thread->name, + stack, + thread, + priority, + memmgr_alloc_from_pool(sizeof(StackType_t) * stack), + memmgr_alloc_from_pool(sizeof(StaticTask_t))); + } else { + BaseType_t ret = xTaskCreate( + furi_thread_body, thread->name, stack, thread, priority, &thread->task_handle); + furi_check(ret == pdPASS); + } - furi_check(ret == pdPASS); furi_check(thread->task_handle); } diff --git a/furi/core/thread.h b/furi/core/thread.h index 7f746f03f..f15b9ff66 100644 --- a/furi/core/thread.h +++ b/furi/core/thread.h @@ -73,6 +73,13 @@ void furi_thread_free(FuriThread* thread); */ void furi_thread_set_name(FuriThread* thread, const char* name); +/** Mark thread as service + * The service cannot be stopped or removed, and cannot exit from the thread body + * + * @param thread + */ +void furi_thread_mark_as_service(FuriThread* thread); + /** Set FuriThread stack size * * @param thread FuriThread instance diff --git a/furi/core/timer.c b/furi/core/timer.c index 807f477e4..462a2e89e 100644 --- a/furi/core/timer.c +++ b/furi/core/timer.c @@ -1,5 +1,7 @@ #include "timer.h" #include "check.h" +#include "memmgr.h" +#include "kernel.h" #include "core/common_defines.h" #include @@ -39,7 +41,7 @@ FuriTimer* furi_timer_alloc(FuriTimerCallback func, FuriTimerType type, void* co /* Dynamic memory allocation is available: if memory for callback and */ /* its context is not provided, allocate it from dynamic memory pool */ if(callb == NULL) { - callb = (TimerCallback_t*)pvPortMalloc(sizeof(TimerCallback_t)); + callb = (TimerCallback_t*)malloc(sizeof(TimerCallback_t)); if(callb != NULL) { /* Callback memory was allocated from dynamic pool, set flag */ @@ -65,7 +67,7 @@ FuriTimer* furi_timer_alloc(FuriTimerCallback func, FuriTimerType type, void* co if((hTimer == NULL) && (callb != NULL) && (callb_dyn == 1U)) { /* Failed to create a timer, release allocated resources */ callb = (TimerCallback_t*)((uint32_t)callb & ~1U); - vPortFree(callb); + free(callb); } } @@ -82,14 +84,16 @@ void furi_timer_free(FuriTimer* instance) { callb = (TimerCallback_t*)pvTimerGetTimerID(hTimer); - if(xTimerDelete(hTimer, portMAX_DELAY) == pdPASS) { - if((uint32_t)callb & 1U) { - /* Callback memory was allocated from dynamic pool, clear flag */ - callb = (TimerCallback_t*)((uint32_t)callb & ~1U); + furi_check(xTimerDelete(hTimer, portMAX_DELAY) == pdPASS); - /* Return allocated memory to dynamic pool */ - vPortFree(callb); - } + while (furi_timer_is_running(instance)) furi_delay_tick(2); + + if((uint32_t)callb & 1U) { + /* Callback memory was allocated from dynamic pool, clear flag */ + callb = (TimerCallback_t*)((uint32_t)callb & ~1U); + + /* Return allocated memory to dynamic pool */ + free(callb); } } @@ -120,11 +124,8 @@ FuriStatus furi_timer_stop(FuriTimer* instance) { if(xTimerIsTimerActive(hTimer) == pdFALSE) { stat = FuriStatusErrorResource; } else { - if(xTimerStop(hTimer, portMAX_DELAY) == pdPASS) { - stat = FuriStatusOk; - } else { - stat = FuriStatusError; - } + furi_check(xTimerStop(hTimer, portMAX_DELAY) == pdPASS); + stat = FuriStatusOk; } /* Return execution status */ diff --git a/furi/flipper.c b/furi/flipper.c index c7d7c5a6c..2acfea015 100755 --- a/furi/flipper.c +++ b/furi/flipper.c @@ -2,6 +2,7 @@ #include #include #include +#include #define TAG "Flipper" @@ -38,9 +39,28 @@ void flipper_init() { furi_thread_set_name(thread, FLIPPER_SERVICES[i].name); furi_thread_set_stack_size(thread, FLIPPER_SERVICES[i].stack_size); furi_thread_set_callback(thread, FLIPPER_SERVICES[i].app); + furi_thread_mark_as_service(thread); furi_thread_start(thread); } FURI_LOG_I(TAG, "services startup complete"); } + +void vApplicationGetIdleTaskMemory( + StaticTask_t** tcb_ptr, + StackType_t** stack_ptr, + uint32_t* stack_size) { + *tcb_ptr = memmgr_alloc_from_pool(sizeof(StaticTask_t)); + *stack_ptr = memmgr_alloc_from_pool(sizeof(StackType_t) * configMINIMAL_STACK_SIZE); + *stack_size = configMINIMAL_STACK_SIZE; +} + +void vApplicationGetTimerTaskMemory( + StaticTask_t** tcb_ptr, + StackType_t** stack_ptr, + uint32_t* stack_size) { + *tcb_ptr = memmgr_alloc_from_pool(sizeof(StaticTask_t)); + *stack_ptr = memmgr_alloc_from_pool(sizeof(StackType_t) * configTIMER_TASK_STACK_DEPTH); + *stack_size = configTIMER_TASK_STACK_DEPTH; +} \ No newline at end of file diff --git a/lib/SConscript b/lib/SConscript index 4498c4c9c..2822684bc 100644 --- a/lib/SConscript +++ b/lib/SConscript @@ -15,7 +15,15 @@ env.Append( "lib/u8g2", "lib/update_util", "lib/print", - ] + ], + SDK_HEADERS=[ + File("#/lib/one_wire/one_wire_host_timing.h"), + File("#/lib/one_wire/one_wire_host.h"), + File("#/lib/one_wire/one_wire_slave.h"), + File("#/lib/one_wire/one_wire_device.h"), + File("#/lib/one_wire/ibutton/ibutton_worker.h"), + File("#/lib/one_wire/maxim_crc.h"), + ], ) env.Append( @@ -24,7 +32,7 @@ env.Append( "#/lib", # TODO: remove! "#/lib/mlib", # Ugly hack - "${BUILD_DIR}/assets/compiled", + Dir("../assets/compiled"), ], CPPDEFINES=[ '"M_MEMORY_FULL(x)=abort()"', @@ -76,8 +84,8 @@ libs = env.BuildModules( "nfc", "appframe", "misc", - "loclass", "lfrfid", + "flipper_application", ], ) diff --git a/lib/ST25RFAL002/include/rfal_picopass.h b/lib/ST25RFAL002/include/rfal_picopass.h deleted file mode 100644 index 2baf96f37..000000000 --- a/lib/ST25RFAL002/include/rfal_picopass.h +++ /dev/null @@ -1,64 +0,0 @@ - -#ifndef RFAL_PICOPASS_H -#define RFAL_PICOPASS_H - -/* - ****************************************************************************** - * INCLUDES - ****************************************************************************** - */ -#include "platform.h" -#include "rfal_rf.h" -#include "rfal_crc.h" -#include "st_errno.h" - -#define RFAL_PICOPASS_UID_LEN 8 -#define RFAL_PICOPASS_MAX_BLOCK_LEN 8 - -#define RFAL_PICOPASS_TXRX_FLAGS \ - (RFAL_TXRX_FLAGS_CRC_TX_MANUAL | RFAL_TXRX_FLAGS_AGC_ON | RFAL_TXRX_FLAGS_PAR_RX_REMV | \ - RFAL_TXRX_FLAGS_CRC_RX_KEEP) - -enum { - RFAL_PICOPASS_CMD_ACTALL = 0x0A, - RFAL_PICOPASS_CMD_IDENTIFY = 0x0C, - RFAL_PICOPASS_CMD_SELECT = 0x81, - RFAL_PICOPASS_CMD_READCHECK = 0x88, - RFAL_PICOPASS_CMD_CHECK = 0x05, - RFAL_PICOPASS_CMD_READ = 0x0C, - RFAL_PICOPASS_CMD_WRITE = 0x0C, -}; - -typedef struct { - uint8_t CSN[RFAL_PICOPASS_UID_LEN]; // Anti-collision CSN - uint8_t crc[2]; -} rfalPicoPassIdentifyRes; - -typedef struct { - uint8_t CSN[RFAL_PICOPASS_UID_LEN]; // Real CSN - uint8_t crc[2]; -} rfalPicoPassSelectRes; - -typedef struct { - uint8_t CCNR[8]; -} rfalPicoPassReadCheckRes; - -typedef struct { - uint8_t mac[4]; -} rfalPicoPassCheckRes; - -typedef struct { - uint8_t data[RFAL_PICOPASS_MAX_BLOCK_LEN]; - uint8_t crc[2]; -} rfalPicoPassReadBlockRes; - -ReturnCode rfalPicoPassPollerInitialize(void); -ReturnCode rfalPicoPassPollerCheckPresence(void); -ReturnCode rfalPicoPassPollerIdentify(rfalPicoPassIdentifyRes* idRes); -ReturnCode rfalPicoPassPollerSelect(uint8_t* csn, rfalPicoPassSelectRes* selRes); -ReturnCode rfalPicoPassPollerReadCheck(rfalPicoPassReadCheckRes* rcRes); -ReturnCode rfalPicoPassPollerCheck(uint8_t* mac, rfalPicoPassCheckRes* chkRes); -ReturnCode rfalPicoPassPollerReadBlock(uint8_t blockNum, rfalPicoPassReadBlockRes* readRes); -ReturnCode rfalPicoPassPollerWriteBlock(uint8_t blockNum, uint8_t data[8], uint8_t mac[4]); - -#endif /* RFAL_PICOPASS_H */ diff --git a/lib/ST25RFAL002/source/rfal_nfc.c b/lib/ST25RFAL002/source/rfal_nfc.c old mode 100755 new mode 100644 diff --git a/lib/ST25RFAL002/source/rfal_picopass.c b/lib/ST25RFAL002/source/rfal_picopass.c deleted file mode 100644 index d4422e412..000000000 --- a/lib/ST25RFAL002/source/rfal_picopass.c +++ /dev/null @@ -1,186 +0,0 @@ - -#include "rfal_picopass.h" -#include "utils.h" - -typedef struct { - uint8_t CMD; - uint8_t CSN[RFAL_PICOPASS_UID_LEN]; -} rfalPicoPassSelectReq; - -typedef struct { - uint8_t CMD; - uint8_t null[4]; - uint8_t mac[4]; -} rfalPicoPassCheckReq; - -ReturnCode rfalPicoPassPollerInitialize(void) { - ReturnCode ret; - - EXIT_ON_ERR(ret, rfalSetMode(RFAL_MODE_POLL_PICOPASS, RFAL_BR_26p48, RFAL_BR_26p48)); - rfalSetErrorHandling(RFAL_ERRORHANDLING_NFC); - - rfalSetGT(RFAL_GT_PICOPASS); - rfalSetFDTListen(RFAL_FDT_LISTEN_PICOPASS_POLLER); - rfalSetFDTPoll(RFAL_FDT_POLL_PICOPASS_POLLER); - - return ERR_NONE; -} - -ReturnCode rfalPicoPassPollerCheckPresence(void) { - ReturnCode ret; - uint8_t txBuf[1] = {RFAL_PICOPASS_CMD_ACTALL}; - uint8_t rxBuf[32] = {0}; - uint16_t recvLen = 0; - uint32_t flags = RFAL_PICOPASS_TXRX_FLAGS; - uint32_t fwt = rfalConvMsTo1fc(20); - - ret = rfalTransceiveBlockingTxRx(txBuf, 1, rxBuf, 32, &recvLen, flags, fwt); - return ret; -} - -ReturnCode rfalPicoPassPollerIdentify(rfalPicoPassIdentifyRes* idRes) { - ReturnCode ret; - - uint8_t txBuf[1] = {RFAL_PICOPASS_CMD_IDENTIFY}; - uint16_t recvLen = 0; - uint32_t flags = RFAL_PICOPASS_TXRX_FLAGS; - uint32_t fwt = rfalConvMsTo1fc(20); - - ret = rfalTransceiveBlockingTxRx( - txBuf, - sizeof(txBuf), - (uint8_t*)idRes, - sizeof(rfalPicoPassIdentifyRes), - &recvLen, - flags, - fwt); - // printf("identify rx: %d %s\n", recvLen, hex2Str(idRes->CSN, RFAL_PICOPASS_UID_LEN)); - - return ret; -} - -ReturnCode rfalPicoPassPollerSelect(uint8_t* csn, rfalPicoPassSelectRes* selRes) { - ReturnCode ret; - - rfalPicoPassSelectReq selReq; - selReq.CMD = RFAL_PICOPASS_CMD_SELECT; - ST_MEMCPY(selReq.CSN, csn, RFAL_PICOPASS_UID_LEN); - uint16_t recvLen = 0; - uint32_t flags = RFAL_PICOPASS_TXRX_FLAGS; - uint32_t fwt = rfalConvMsTo1fc(20); - - ret = rfalTransceiveBlockingTxRx( - (uint8_t*)&selReq, - sizeof(rfalPicoPassSelectReq), - (uint8_t*)selRes, - sizeof(rfalPicoPassSelectRes), - &recvLen, - flags, - fwt); - // printf("select rx: %d %s\n", recvLen, hex2Str(selRes->CSN, RFAL_PICOPASS_UID_LEN)); - if(ret == ERR_TIMEOUT) { - return ERR_NONE; - } - - return ret; -} - -ReturnCode rfalPicoPassPollerReadCheck(rfalPicoPassReadCheckRes* rcRes) { - ReturnCode ret; - uint8_t txBuf[2] = {RFAL_PICOPASS_CMD_READCHECK, 0x02}; - uint16_t recvLen = 0; - uint32_t flags = RFAL_PICOPASS_TXRX_FLAGS; - uint32_t fwt = rfalConvMsTo1fc(20); - - ret = rfalTransceiveBlockingTxRx( - txBuf, - sizeof(txBuf), - (uint8_t*)rcRes, - sizeof(rfalPicoPassReadCheckRes), - &recvLen, - flags, - fwt); - // printf("readcheck rx: %d %s\n", recvLen, hex2Str(rcRes->CCNR, 8)); - - if(ret == ERR_CRC) { - return ERR_NONE; - } - - return ret; -} - -ReturnCode rfalPicoPassPollerCheck(uint8_t* mac, rfalPicoPassCheckRes* chkRes) { - ReturnCode ret; - rfalPicoPassCheckReq chkReq; - chkReq.CMD = RFAL_PICOPASS_CMD_CHECK; - ST_MEMCPY(chkReq.mac, mac, 4); - ST_MEMSET(chkReq.null, 0, 4); - uint16_t recvLen = 0; - uint32_t flags = RFAL_PICOPASS_TXRX_FLAGS; - uint32_t fwt = rfalConvMsTo1fc(20); - - // printf("check tx: %s\n", hex2Str((uint8_t *)&chkReq, sizeof(rfalPicoPassCheckReq))); - ret = rfalTransceiveBlockingTxRx( - (uint8_t*)&chkReq, - sizeof(rfalPicoPassCheckReq), - (uint8_t*)chkRes, - sizeof(rfalPicoPassCheckRes), - &recvLen, - flags, - fwt); - // printf("check rx: %d %s\n", recvLen, hex2Str(chkRes->mac, 4)); - if(ret == ERR_CRC) { - return ERR_NONE; - } - - return ret; -} - -ReturnCode rfalPicoPassPollerReadBlock(uint8_t blockNum, rfalPicoPassReadBlockRes* readRes) { - ReturnCode ret; - - uint8_t txBuf[4] = {RFAL_PICOPASS_CMD_READ, 0, 0, 0}; - txBuf[1] = blockNum; - uint16_t crc = rfalCrcCalculateCcitt(0xE012, txBuf + 1, 1); - memcpy(txBuf + 2, &crc, sizeof(uint16_t)); - - uint16_t recvLen = 0; - uint32_t flags = RFAL_PICOPASS_TXRX_FLAGS; - uint32_t fwt = rfalConvMsTo1fc(20); - - ret = rfalTransceiveBlockingTxRx( - txBuf, - sizeof(txBuf), - (uint8_t*)readRes, - sizeof(rfalPicoPassReadBlockRes), - &recvLen, - flags, - fwt); - return ret; -} - -ReturnCode rfalPicoPassPollerWriteBlock(uint8_t blockNum, uint8_t data[8], uint8_t mac[4]) { - ReturnCode ret; - - uint8_t txBuf[14] = {RFAL_PICOPASS_CMD_WRITE, blockNum, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - memcpy(txBuf + 2, data, RFAL_PICOPASS_MAX_BLOCK_LEN); - memcpy(txBuf + 10, mac, 4); - - uint16_t recvLen = 0; - uint32_t flags = RFAL_PICOPASS_TXRX_FLAGS; - uint32_t fwt = rfalConvMsTo1fc(20); - rfalPicoPassReadBlockRes readRes; - - ret = rfalTransceiveBlockingTxRx( - txBuf, - sizeof(txBuf), - (uint8_t*)&readRes, - sizeof(rfalPicoPassReadBlockRes), - &recvLen, - flags, - fwt); - - // TODO: compare response - - return ret; -} diff --git a/lib/STM32CubeWB.scons b/lib/STM32CubeWB.scons index 80d06b5fc..e8350ea99 100644 --- a/lib/STM32CubeWB.scons +++ b/lib/STM32CubeWB.scons @@ -13,6 +13,11 @@ env.Append( "USE_FULL_ASSERT", "USE_FULL_LL_DRIVER", ], + SDK_HEADERS=env.GlobRecursive( + "*_ll_*.h", + "#/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/", + exclude="*usb.h", + ), ) if env["RAM_EXEC"]: diff --git a/lib/app-scened-template/generic_scene.hpp b/lib/app-scened-template/generic_scene.hpp index 979e97478..bcdf0b464 100644 --- a/lib/app-scened-template/generic_scene.hpp +++ b/lib/app-scened-template/generic_scene.hpp @@ -1,4 +1,5 @@ -template class GenericScene { +template +class GenericScene { public: virtual void on_enter(TApp* app, bool need_restore) = 0; virtual bool on_event(TApp* app, typename TApp::Event* event) = 0; diff --git a/lib/app-scened-template/record_controller.hpp b/lib/app-scened-template/record_controller.hpp index 9b14274a8..171115e15 100644 --- a/lib/app-scened-template/record_controller.hpp +++ b/lib/app-scened-template/record_controller.hpp @@ -6,7 +6,8 @@ * * @tparam TRecordClass record class */ -template class RecordController { +template +class RecordController { public: /** * @brief Construct a new Record Controller object for record with record name diff --git a/lib/app-scened-template/scene_controller.hpp b/lib/app-scened-template/scene_controller.hpp index 678f6c0df..052eca731 100644 --- a/lib/app-scened-template/scene_controller.hpp +++ b/lib/app-scened-template/scene_controller.hpp @@ -11,7 +11,8 @@ * @tparam TScene generic scene class * @tparam TApp application class */ -template class SceneController { +template +class SceneController { public: /** * @brief Add scene to scene container diff --git a/lib/app-scened-template/typeindex_no_rtti.hpp b/lib/app-scened-template/typeindex_no_rtti.hpp index 4ac52725f..0f399385a 100644 --- a/lib/app-scened-template/typeindex_no_rtti.hpp +++ b/lib/app-scened-template/typeindex_no_rtti.hpp @@ -33,12 +33,14 @@ namespace ext { /** * Dummy type for tag-dispatching. */ -template struct tag_type {}; +template +struct tag_type {}; /** * A value of tag_type. */ -template constexpr tag_type tag{}; +template +constexpr tag_type tag{}; /** * A type_index implementation without RTTI. @@ -47,7 +49,8 @@ struct type_index { /** * Creates a type_index object for the specified type. */ - template type_index(tag_type) noexcept : hash_code_{index} { + template + type_index(tag_type) noexcept : hash_code_{index} { } /** @@ -61,7 +64,8 @@ private: /** * Unique integral index associated to template type argument. */ - template static std::size_t const index; + template + static std::size_t const index; /** * Global counter for generating index values. @@ -75,14 +79,16 @@ private: std::size_t hash_code_; }; -template std::size_t const type_index::index = type_index::counter()++; +template +std::size_t const type_index::index = type_index::counter()++; /** * Creates a type_index object for the specified type. * * Equivalent to `ext::type_index{ext::tag}`. */ -template type_index make_type_index() noexcept { +template +type_index make_type_index() noexcept { return tag; } @@ -111,7 +117,8 @@ inline bool operator>=(type_index const& a, type_index const& b) noexcept { } } -template <> struct std::hash { +template <> +struct std::hash { using argument_type = ext::type_index; using result_type = std::size_t; diff --git a/lib/app-scened-template/view_controller.hpp b/lib/app-scened-template/view_controller.hpp index 15028f533..8c48fcf74 100644 --- a/lib/app-scened-template/view_controller.hpp +++ b/lib/app-scened-template/view_controller.hpp @@ -12,7 +12,8 @@ * @tparam TApp application class * @tparam TViewModules variadic list of ViewModules */ -template class ViewController { +template +class ViewController { public: ViewController() { event_queue = furi_message_queue_alloc(10, sizeof(typename TApp::Event)); @@ -44,7 +45,8 @@ public: * @tparam T Concrete ViewModule class * @return T* ViewModule pointer */ - template T* get() { + template + T* get() { uint32_t view_index = ext::make_type_index().hash_code(); furi_check(holder.count(view_index) != 0); return static_cast(holder[view_index]); @@ -56,7 +58,8 @@ public: * @tparam T Concrete ViewModule class * @return T* ViewModule pointer */ - template operator T*() { + template + operator T*() { uint32_t view_index = ext::make_type_index().hash_code(); furi_check(holder.count(view_index) != 0); return static_cast(holder[view_index]); @@ -68,7 +71,8 @@ public: * @tparam T Concrete ViewModule class * @return T* ViewModule pointer */ - template void switch_to() { + template + void switch_to() { uint32_t view_index = ext::make_type_index().hash_code(); furi_check(holder.count(view_index) != 0); view_dispatcher_switch_to_view(view_dispatcher, view_index); diff --git a/lib/cxxheaderparser b/lib/cxxheaderparser new file mode 160000 index 000000000..ba4222560 --- /dev/null +++ b/lib/cxxheaderparser @@ -0,0 +1 @@ +Subproject commit ba4222560fc1040670b1a917d5d357198e8ec5d6 diff --git a/lib/digital_signal/digital_signal.h b/lib/digital_signal/digital_signal.h index d828444ca..90905d74b 100644 --- a/lib/digital_signal/digital_signal.h +++ b/lib/digital_signal/digital_signal.h @@ -6,6 +6,10 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + typedef struct { bool start_level; uint32_t edge_cnt; @@ -29,3 +33,7 @@ uint32_t digital_signal_get_edges_cnt(DigitalSignal* signal); uint32_t digital_signal_get_edge(DigitalSignal* signal, uint32_t edge_num); void digital_signal_send(DigitalSignal* signal, const GpioPin* gpio); + +#ifdef __cplusplus +} +#endif diff --git a/lib/flipper_application/SConscript b/lib/flipper_application/SConscript new file mode 100644 index 000000000..3a5e7f4db --- /dev/null +++ b/lib/flipper_application/SConscript @@ -0,0 +1,20 @@ +Import("env") + +env.Append( + CPPPATH=[ + "#/lib/flipper_application", + ], + SDK_HEADERS=[ + File("#/lib/flipper_application/flipper_application.h"), + ], +) + + +libenv = env.Clone(FW_LIB_NAME="flipper_application") +libenv.ApplyLibFlags() + +sources = libenv.GlobRecursive("*.c") + +lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) +libenv.Install("${LIB_DIST_DIR}", lib) +Return("lib") diff --git a/lib/flipper_application/application_manifest.h b/lib/flipper_application/application_manifest.h new file mode 100644 index 000000000..6aa20e481 --- /dev/null +++ b/lib/flipper_application/application_manifest.h @@ -0,0 +1,45 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define FAP_MANIFEST_MAGIC 0x52474448 +#define FAP_MANIFEST_SUPPORTED_VERSION 1 + +#define FAP_MANIFEST_MAX_APP_NAME_LENGTH 32 +#define FAP_MANIFEST_MAX_ICON_SIZE 32 // TODO: reduce size? + +#pragma pack(push, 1) + +typedef struct { + uint32_t manifest_magic; + uint32_t manifest_version; + union { + struct { + uint16_t minor; + uint16_t major; + }; + uint32_t version; + } api_version; + uint16_t hardware_target_id; +} FlipperApplicationManifestBase; + +typedef struct { + FlipperApplicationManifestBase base; + uint16_t stack_size; + uint32_t app_version; + char name[FAP_MANIFEST_MAX_APP_NAME_LENGTH]; + char has_icon; + char icon[FAP_MANIFEST_MAX_ICON_SIZE]; +} FlipperApplicationManifestV1; + +typedef FlipperApplicationManifestV1 FlipperApplicationManifest; + +#pragma pack(pop) + +#ifdef __cplusplus +} +#endif diff --git a/lib/flipper_application/elf/elf.h b/lib/flipper_application/elf/elf.h new file mode 100644 index 000000000..f1697ba48 --- /dev/null +++ b/lib/flipper_application/elf/elf.h @@ -0,0 +1,1148 @@ +#ifndef _ELF_H +#define _ELF_H 1 + +/* Standard ELF types. */ + +#include + +/* Type for a 16-bit quantity. */ +typedef uint16_t Elf32_Half; +typedef uint16_t Elf64_Half; + +/* Types for signed and unsigned 32-bit quantities. */ +typedef uint32_t Elf32_Word; +typedef int32_t Elf32_Sword; +typedef uint32_t Elf64_Word; +typedef int32_t Elf64_Sword; + +/* Types for signed and unsigned 64-bit quantities. */ +typedef uint64_t Elf32_Xword; +typedef int64_t Elf32_Sxword; +typedef uint64_t Elf64_Xword; +typedef int64_t Elf64_Sxword; + +/* Type of addresses. */ +typedef uint32_t Elf32_Addr; +typedef uint64_t Elf64_Addr; + +/* Type of file offsets. */ +typedef uint32_t Elf32_Off; +typedef uint64_t Elf64_Off; + +/* Type for section indices, which are 16-bit quantities. */ +typedef uint16_t Elf32_Section; +typedef uint16_t Elf64_Section; + +/* Type for version symbol information. */ +typedef Elf32_Half Elf32_Versym; +typedef Elf64_Half Elf64_Versym; + +/* The ELF file header. This appears at the start of every ELF file. */ + +#define EI_NIDENT (16) + +typedef struct { + unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ + Elf32_Half e_type; /* Object file type */ + Elf32_Half e_machine; /* Architecture */ + Elf32_Word e_version; /* Object file version */ + Elf32_Addr e_entry; /* Entry point virtual address */ + Elf32_Off e_phoff; /* Program header table file offset */ + Elf32_Off e_shoff; /* Section header table file offset */ + Elf32_Word e_flags; /* Processor-specific flags */ + Elf32_Half e_ehsize; /* ELF header size in bytes */ + Elf32_Half e_phentsize; /* Program header table entry size */ + Elf32_Half e_phnum; /* Program header table entry count */ + Elf32_Half e_shentsize; /* Section header table entry size */ + Elf32_Half e_shnum; /* Section header table entry count */ + Elf32_Half e_shstrndx; /* Section header string table index */ +} Elf32_Ehdr; + +typedef struct { + unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ + Elf64_Half e_type; /* Object file type */ + Elf64_Half e_machine; /* Architecture */ + Elf64_Word e_version; /* Object file version */ + Elf64_Addr e_entry; /* Entry point virtual address */ + Elf64_Off e_phoff; /* Program header table file offset */ + Elf64_Off e_shoff; /* Section header table file offset */ + Elf64_Word e_flags; /* Processor-specific flags */ + Elf64_Half e_ehsize; /* ELF header size in bytes */ + Elf64_Half e_phentsize; /* Program header table entry size */ + Elf64_Half e_phnum; /* Program header table entry count */ + Elf64_Half e_shentsize; /* Section header table entry size */ + Elf64_Half e_shnum; /* Section header table entry count */ + Elf64_Half e_shstrndx; /* Section header string table index */ +} Elf64_Ehdr; + +/* Fields in the e_ident array. The EI_* macros are indices into the + array. The macros under each EI_* macro are the values the byte + may have. */ + +#define EI_MAG0 0 /* File identification byte 0 index */ +#define ELFMAG0 0x7f /* Magic number byte 0 */ + +#define EI_MAG1 1 /* File identification byte 1 index */ +#define ELFMAG1 'E' /* Magic number byte 1 */ + +#define EI_MAG2 2 /* File identification byte 2 index */ +#define ELFMAG2 'L' /* Magic number byte 2 */ + +#define EI_MAG3 3 /* File identification byte 3 index */ +#define ELFMAG3 'F' /* Magic number byte 3 */ + +/* Conglomeration of the identification bytes, for easy testing as a word. */ +#define ELFMAG "\177ELF" +#define SELFMAG 4 + +#define EI_CLASS 4 /* File class byte index */ +#define ELFCLASSNONE 0 /* Invalid class */ +#define ELFCLASS32 1 /* 32-bit objects */ +#define ELFCLASS64 2 /* 64-bit objects */ +#define ELFCLASSNUM 3 + +#define EI_DATA 5 /* Data encoding byte index */ +#define ELFDATANONE 0 /* Invalid data encoding */ +#define ELFDATA2LSB 1 /* 2's complement, little endian */ +#define ELFDATA2MSB 2 /* 2's complement, big endian */ +#define ELFDATANUM 3 + +#define EI_VERSION 6 /* File version byte index */ +/* Value must be EV_CURRENT */ + +#define EI_OSABI 7 /* OS ABI identification */ +#define ELFOSABI_NONE 0 /* UNIX System V ABI */ +#define ELFOSABI_SYSV 0 /* Alias. */ +#define ELFOSABI_HPUX 1 /* HP-UX */ +#define ELFOSABI_NETBSD 2 /* NetBSD. */ +#define ELFOSABI_LINUX 3 /* Linux. */ +#define ELFOSABI_SOLARIS 6 /* Sun Solaris. */ +#define ELFOSABI_AIX 7 /* IBM AIX. */ +#define ELFOSABI_IRIX 8 /* SGI Irix. */ +#define ELFOSABI_FREEBSD 9 /* FreeBSD. */ +#define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX. */ +#define ELFOSABI_MODESTO 11 /* Novell Modesto. */ +#define ELFOSABI_OPENBSD 12 /* OpenBSD. */ +#define ELFOSABI_ARM 97 /* ARM */ +#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ + +#define EI_ABIVERSION 8 /* ABI version */ + +#define EI_PAD 9 /* Byte index of padding bytes */ + +/* Legal values for e_type (object file type). */ + +#define ET_NONE 0 /* No file type */ +#define ET_REL 1 /* Relocatable file */ +#define ET_EXEC 2 /* Executable file */ +#define ET_DYN 3 /* Shared object file */ +#define ET_CORE 4 /* Core file */ +#define ET_NUM 5 /* Number of defined types */ +#define ET_LOOS 0xfe00 /* OS-specific range start */ +#define ET_HIOS 0xfeff /* OS-specific range end */ +#define ET_LOPROC 0xff00 /* Processor-specific range start */ +#define ET_HIPROC 0xffff /* Processor-specific range end */ + +/* Legal values for e_machine (architecture). */ + +#define EM_NONE 0 /* No machine */ +#define EM_M32 1 /* AT&T WE 32100 */ +#define EM_SPARC 2 /* SUN SPARC */ +#define EM_386 3 /* Intel 80386 */ +#define EM_68K 4 /* Motorola m68k family */ +#define EM_88K 5 /* Motorola m88k family */ +#define EM_860 7 /* Intel 80860 */ +#define EM_MIPS 8 /* MIPS R3000 big-endian */ +#define EM_S370 9 /* IBM System/370 */ +#define EM_MIPS_RS3_LE 10 /* MIPS R3000 little-endian */ + +#define EM_PARISC 15 /* HPPA */ +#define EM_VPP500 17 /* Fujitsu VPP500 */ +#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */ +#define EM_960 19 /* Intel 80960 */ +#define EM_PPC 20 /* PowerPC */ +#define EM_PPC64 21 /* PowerPC 64-bit */ +#define EM_S390 22 /* IBM S390 */ + +#define EM_V800 36 /* NEC V800 series */ +#define EM_FR20 37 /* Fujitsu FR20 */ +#define EM_RH32 38 /* TRW RH-32 */ +#define EM_RCE 39 /* Motorola RCE */ +#define EM_ARM 40 /* ARM */ +#define EM_FAKE_ALPHA 41 /* Digital Alpha */ +#define EM_SH 42 /* Hitachi SH */ +#define EM_SPARCV9 43 /* SPARC v9 64-bit */ +#define EM_TRICORE 44 /* Siemens Tricore */ +#define EM_ARC 45 /* Argonaut RISC Core */ +#define EM_H8_300 46 /* Hitachi H8/300 */ +#define EM_H8_300H 47 /* Hitachi H8/300H */ +#define EM_H8S 48 /* Hitachi H8S */ +#define EM_H8_500 49 /* Hitachi H8/500 */ +#define EM_IA_64 50 /* Intel Merced */ +#define EM_MIPS_X 51 /* Stanford MIPS-X */ +#define EM_COLDFIRE 52 /* Motorola Coldfire */ +#define EM_68HC12 53 /* Motorola M68HC12 */ +#define EM_MMA 54 /* Fujitsu MMA Multimedia Accelerator*/ +#define EM_PCP 55 /* Siemens PCP */ +#define EM_NCPU 56 /* Sony nCPU embeeded RISC */ +#define EM_NDR1 57 /* Denso NDR1 microprocessor */ +#define EM_STARCORE 58 /* Motorola Start*Core processor */ +#define EM_ME16 59 /* Toyota ME16 processor */ +#define EM_ST100 60 /* STMicroelectronic ST100 processor */ +#define EM_TINYJ 61 /* Advanced Logic Corp. Tinyj emb.fam*/ +#define EM_X86_64 62 /* AMD x86-64 architecture */ +#define EM_PDSP 63 /* Sony DSP Processor */ + +#define EM_FX66 66 /* Siemens FX66 microcontroller */ +#define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 mc */ +#define EM_ST7 68 /* STmicroelectronics ST7 8 bit mc */ +#define EM_68HC16 69 /* Motorola MC68HC16 microcontroller */ +#define EM_68HC11 70 /* Motorola MC68HC11 microcontroller */ +#define EM_68HC08 71 /* Motorola MC68HC08 microcontroller */ +#define EM_68HC05 72 /* Motorola MC68HC05 microcontroller */ +#define EM_SVX 73 /* Silicon Graphics SVx */ +#define EM_ST19 74 /* STMicroelectronics ST19 8 bit mc */ +#define EM_VAX 75 /* Digital VAX */ +#define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */ +#define EM_JAVELIN 77 /* Infineon Technologies 32-bit embedded processor */ +#define EM_FIREPATH 78 /* Element 14 64-bit DSP Processor */ +#define EM_ZSP 79 /* LSI Logic 16-bit DSP Processor */ +#define EM_MMIX 80 /* Donald Knuth's educational 64-bit processor */ +#define EM_HUANY 81 /* Harvard University machine-independent object files */ +#define EM_PRISM 82 /* SiTera Prism */ +#define EM_AVR 83 /* Atmel AVR 8-bit microcontroller */ +#define EM_FR30 84 /* Fujitsu FR30 */ +#define EM_D10V 85 /* Mitsubishi D10V */ +#define EM_D30V 86 /* Mitsubishi D30V */ +#define EM_V850 87 /* NEC v850 */ +#define EM_M32R 88 /* Mitsubishi M32R */ +#define EM_MN10300 89 /* Matsushita MN10300 */ +#define EM_MN10200 90 /* Matsushita MN10200 */ +#define EM_PJ 91 /* picoJava */ +#define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */ +#define EM_ARC_A5 93 /* ARC Cores Tangent-A5 */ +#define EM_XTENSA 94 /* Tensilica Xtensa Architecture */ +#define EM_NUM 95 + +/* Legal values for e_version (version). */ + +#define EV_NONE 0 /* Invalid ELF version */ +#define EV_CURRENT 1 /* Current version */ +#define EV_NUM 2 + +/* Section header. */ + +typedef struct { + Elf32_Word sh_name; /* Section name (string tbl index) */ + Elf32_Word sh_type; /* Section type */ + Elf32_Word sh_flags; /* Section flags */ + Elf32_Addr sh_addr; /* Section virtual addr at execution */ + Elf32_Off sh_offset; /* Section file offset */ + Elf32_Word sh_size; /* Section size in bytes */ + Elf32_Word sh_link; /* Link to another section */ + Elf32_Word sh_info; /* Additional section information */ + Elf32_Word sh_addralign; /* Section alignment */ + Elf32_Word sh_entsize; /* Entry size if section holds table */ +} Elf32_Shdr; + +typedef struct { + Elf64_Word sh_name; /* Section name (string tbl index) */ + Elf64_Word sh_type; /* Section type */ + Elf64_Xword sh_flags; /* Section flags */ + Elf64_Addr sh_addr; /* Section virtual addr at execution */ + Elf64_Off sh_offset; /* Section file offset */ + Elf64_Xword sh_size; /* Section size in bytes */ + Elf64_Word sh_link; /* Link to another section */ + Elf64_Word sh_info; /* Additional section information */ + Elf64_Xword sh_addralign; /* Section alignment */ + Elf64_Xword sh_entsize; /* Entry size if section holds table */ +} Elf64_Shdr; + +/* Special section indices. */ + +#define SHN_UNDEF 0 /* Undefined section */ +#define SHN_LORESERVE 0xff00 /* Start of reserved indices */ +#define SHN_LOPROC 0xff00 /* Start of processor-specific */ +#define SHN_BEFORE \ + 0xff00 /* Order section before all others + (Solaris). */ +#define SHN_AFTER \ + 0xff01 /* Order section after all others + (Solaris). */ +#define SHN_HIPROC 0xff1f /* End of processor-specific */ +#define SHN_LOOS 0xff20 /* Start of OS-specific */ +#define SHN_HIOS 0xff3f /* End of OS-specific */ +#define SHN_ABS 0xfff1 /* Associated symbol is absolute */ +#define SHN_COMMON 0xfff2 /* Associated symbol is common */ +#define SHN_XINDEX 0xffff /* Index is in extra table. */ +#define SHN_HIRESERVE 0xffff /* End of reserved indices */ + +/* Legal values for sh_type (section type). */ + +#define SHT_NULL 0 /* Section header table entry unused */ +#define SHT_PROGBITS 1 /* Program data */ +#define SHT_SYMTAB 2 /* Symbol table */ +#define SHT_STRTAB 3 /* String table */ +#define SHT_RELA 4 /* Relocation entries with addends */ +#define SHT_HASH 5 /* Symbol hash table */ +#define SHT_DYNAMIC 6 /* Dynamic linking information */ +#define SHT_NOTE 7 /* Notes */ +#define SHT_NOBITS 8 /* Program space with no data (bss) */ +#define SHT_REL 9 /* Relocation entries, no addends */ +#define SHT_SHLIB 10 /* Reserved */ +#define SHT_DYNSYM 11 /* Dynamic linker symbol table */ +#define SHT_INIT_ARRAY 14 /* Array of constructors */ +#define SHT_FINI_ARRAY 15 /* Array of destructors */ +#define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */ +#define SHT_GROUP 17 /* Section group */ +#define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */ +#define SHT_NUM 19 /* Number of defined types. */ +#define SHT_LOOS 0x60000000 /* Start OS-specific. */ +#define SHT_GNU_ATTRIBUTES 0x6ffffff5 /* Object attributes. */ +#define SHT_GNU_HASH 0x6ffffff6 /* GNU-style hash table. */ +#define SHT_GNU_LIBLIST 0x6ffffff7 /* Prelink library list */ +#define SHT_CHECKSUM 0x6ffffff8 /* Checksum for DSO content. */ +#define SHT_LOSUNW 0x6ffffffa /* Sun-specific low bound. */ +#define SHT_SUNW_move 0x6ffffffa +#define SHT_SUNW_COMDAT 0x6ffffffb +#define SHT_SUNW_syminfo 0x6ffffffc +#define SHT_GNU_verdef 0x6ffffffd /* Version definition section. */ +#define SHT_GNU_verneed 0x6ffffffe /* Version needs section. */ +#define SHT_GNU_versym 0x6fffffff /* Version symbol table. */ +#define SHT_HISUNW 0x6fffffff /* Sun-specific high bound. */ +#define SHT_HIOS 0x6fffffff /* End OS-specific type */ +#define SHT_LOPROC 0x70000000 /* Start of processor-specific */ +#define SHT_HIPROC 0x7fffffff /* End of processor-specific */ +#define SHT_LOUSER 0x80000000 /* Start of application-specific */ +#define SHT_HIUSER 0x8fffffff /* End of application-specific */ + +/* Legal values for sh_flags (section flags). */ + +#define SHF_WRITE (1 << 0) /* Writable */ +#define SHF_ALLOC (1 << 1) /* Occupies memory during execution */ +#define SHF_EXECINSTR (1 << 2) /* Executable */ +#define SHF_MERGE (1 << 4) /* Might be merged */ +#define SHF_STRINGS (1 << 5) /* Contains nul-terminated strings */ +#define SHF_INFO_LINK (1 << 6) /* `sh_info' contains SHT index */ +#define SHF_LINK_ORDER (1 << 7) /* Preserve order after combining */ +#define SHF_OS_NONCONFORMING \ + (1 << 8) /* Non-standard OS specific handling + required */ +#define SHF_GROUP (1 << 9) /* Section is member of a group. */ +#define SHF_TLS (1 << 10) /* Section hold thread-local data. */ +#define SHF_MASKOS 0x0ff00000 /* OS-specific. */ +#define SHF_MASKPROC 0xf0000000 /* Processor-specific */ +#define SHF_ORDERED \ + (1 << 30) /* Special ordering requirement + (Solaris). */ +#define SHF_EXCLUDE \ + (1 << 31) /* Section is excluded unless + referenced or allocated (Solaris).*/ + +/* Section group handling. */ +#define GRP_COMDAT 0x1 /* Mark group as COMDAT. */ + +/* Symbol table entry. */ + +typedef struct { + Elf32_Word st_name; /* Symbol name (string tbl index) */ + Elf32_Addr st_value; /* Symbol value */ + Elf32_Word st_size; /* Symbol size */ + unsigned char st_info; /* Symbol type and binding */ + unsigned char st_other; /* Symbol visibility */ + Elf32_Section st_shndx; /* Section index */ +} Elf32_Sym; + +typedef struct { + Elf64_Word st_name; /* Symbol name (string tbl index) */ + unsigned char st_info; /* Symbol type and binding */ + unsigned char st_other; /* Symbol visibility */ + Elf64_Section st_shndx; /* Section index */ + Elf64_Addr st_value; /* Symbol value */ + Elf64_Xword st_size; /* Symbol size */ +} Elf64_Sym; + +/* The syminfo section if available contains additional information about + every dynamic symbol. */ + +typedef struct { + Elf32_Half si_boundto; /* Direct bindings, symbol bound to */ + Elf32_Half si_flags; /* Per symbol flags */ +} Elf32_Syminfo; + +typedef struct { + Elf64_Half si_boundto; /* Direct bindings, symbol bound to */ + Elf64_Half si_flags; /* Per symbol flags */ +} Elf64_Syminfo; + +/* Possible values for si_boundto. */ +#define SYMINFO_BT_SELF 0xffff /* Symbol bound to self */ +#define SYMINFO_BT_PARENT 0xfffe /* Symbol bound to parent */ +#define SYMINFO_BT_LOWRESERVE 0xff00 /* Beginning of reserved entries */ + +/* Possible bitmasks for si_flags. */ +#define SYMINFO_FLG_DIRECT 0x0001 /* Direct bound symbol */ +#define SYMINFO_FLG_PASSTHRU 0x0002 /* Pass-thru symbol for translator */ +#define SYMINFO_FLG_COPY 0x0004 /* Symbol is a copy-reloc */ +#define SYMINFO_FLG_LAZYLOAD \ + 0x0008 /* Symbol bound to object to be lazy + loaded */ +/* Syminfo version values. */ +#define SYMINFO_NONE 0 +#define SYMINFO_CURRENT 1 +#define SYMINFO_NUM 2 + +/* How to extract and insert information held in the st_info field. */ + +#define ELF32_ST_BIND(val) (((unsigned char)(val)) >> 4) +#define ELF32_ST_TYPE(val) ((val)&0xf) +#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type)&0xf)) + +/* Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field. */ +#define ELF64_ST_BIND(val) ELF32_ST_BIND(val) +#define ELF64_ST_TYPE(val) ELF32_ST_TYPE(val) +#define ELF64_ST_INFO(bind, type) ELF32_ST_INFO((bind), (type)) + +/* Legal values for ST_BIND subfield of st_info (symbol binding). */ + +#define STB_LOCAL 0 /* Local symbol */ +#define STB_GLOBAL 1 /* Global symbol */ +#define STB_WEAK 2 /* Weak symbol */ +#define STB_NUM 3 /* Number of defined types. */ +#define STB_LOOS 10 /* Start of OS-specific */ +#define STB_GNU_UNIQUE 10 /* Unique symbol. */ +#define STB_HIOS 12 /* End of OS-specific */ +#define STB_LOPROC 13 /* Start of processor-specific */ +#define STB_HIPROC 15 /* End of processor-specific */ + +/* Legal values for ST_TYPE subfield of st_info (symbol type). */ + +#define STT_NOTYPE 0 /* Symbol type is unspecified */ +#define STT_OBJECT 1 /* Symbol is a data object */ +#define STT_FUNC 2 /* Symbol is a code object */ +#define STT_SECTION 3 /* Symbol associated with a section */ +#define STT_FILE 4 /* Symbol's name is file name */ +#define STT_COMMON 5 /* Symbol is a common data object */ +#define STT_TLS 6 /* Symbol is thread-local data object*/ +#define STT_NUM 7 /* Number of defined types. */ +#define STT_LOOS 10 /* Start of OS-specific */ +#define STT_GNU_IFUNC 10 /* Symbol is indirect code object */ +#define STT_HIOS 12 /* End of OS-specific */ +#define STT_LOPROC 13 /* Start of processor-specific */ +#define STT_HIPROC 15 /* End of processor-specific */ + +/* Symbol table indices are found in the hash buckets and chain table + of a symbol hash table section. This special index value indicates + the end of a chain, meaning no further symbols are found in that bucket. */ + +#define STN_UNDEF 0 /* End of a chain. */ + +/* How to extract and insert information held in the st_other field. */ + +#define ELF32_ST_VISIBILITY(o) ((o)&0x03) + +/* For ELF64 the definitions are the same. */ +#define ELF64_ST_VISIBILITY(o) ELF32_ST_VISIBILITY(o) + +/* Symbol visibility specification encoded in the st_other field. */ +#define STV_DEFAULT 0 /* Default symbol visibility rules */ +#define STV_INTERNAL 1 /* Processor specific hidden class */ +#define STV_HIDDEN 2 /* Sym unavailable in other modules */ +#define STV_PROTECTED 3 /* Not preemptible, not exported */ + +/* Relocation table entry without addend (in section of type SHT_REL). */ + +typedef struct { + Elf32_Addr r_offset; /* Address */ + Elf32_Word r_info; /* Relocation type and symbol index */ +} Elf32_Rel; + +/* I have seen two different definitions of the Elf64_Rel and + Elf64_Rela structures, so we'll leave them out until Novell (or + whoever) gets their act together. */ +/* The following, at least, is used on Sparc v9, MIPS, and Alpha. */ + +typedef struct { + Elf64_Addr r_offset; /* Address */ + Elf64_Xword r_info; /* Relocation type and symbol index */ +} Elf64_Rel; + +/* Relocation table entry with addend (in section of type SHT_RELA). */ + +typedef struct { + Elf32_Addr r_offset; /* Address */ + Elf32_Word r_info; /* Relocation type and symbol index */ + Elf32_Sword r_addend; /* Addend */ +} Elf32_Rela; + +typedef struct { + Elf64_Addr r_offset; /* Address */ + Elf64_Xword r_info; /* Relocation type and symbol index */ + Elf64_Sxword r_addend; /* Addend */ +} Elf64_Rela; + +/* How to extract and insert information held in the r_info field. */ + +#define ELF32_R_SYM(val) ((val) >> 8) +#define ELF32_R_TYPE(val) ((val)&0xff) +#define ELF32_R_INFO(sym, type) (((sym) << 8) + ((type)&0xff)) + +#define ELF64_R_SYM(i) ((i) >> 32) +#define ELF64_R_TYPE(i) ((i)&0xffffffff) +#define ELF64_R_INFO(sym, type) ((((Elf64_Xword)(sym)) << 32) + (type)) + +/* Program segment header. */ + +typedef struct { + Elf32_Word p_type; /* Segment type */ + Elf32_Off p_offset; /* Segment file offset */ + Elf32_Addr p_vaddr; /* Segment virtual address */ + Elf32_Addr p_paddr; /* Segment physical address */ + Elf32_Word p_filesz; /* Segment size in file */ + Elf32_Word p_memsz; /* Segment size in memory */ + Elf32_Word p_flags; /* Segment flags */ + Elf32_Word p_align; /* Segment alignment */ +} Elf32_Phdr; + +typedef struct { + Elf64_Word p_type; /* Segment type */ + Elf64_Word p_flags; /* Segment flags */ + Elf64_Off p_offset; /* Segment file offset */ + Elf64_Addr p_vaddr; /* Segment virtual address */ + Elf64_Addr p_paddr; /* Segment physical address */ + Elf64_Xword p_filesz; /* Segment size in file */ + Elf64_Xword p_memsz; /* Segment size in memory */ + Elf64_Xword p_align; /* Segment alignment */ +} Elf64_Phdr; + +/* Legal values for p_type (segment type). */ + +#define PT_NULL 0 /* Program header table entry unused */ +#define PT_LOAD 1 /* Loadable program segment */ +#define PT_DYNAMIC 2 /* Dynamic linking information */ +#define PT_INTERP 3 /* Program interpreter */ +#define PT_NOTE 4 /* Auxiliary information */ +#define PT_SHLIB 5 /* Reserved */ +#define PT_PHDR 6 /* Entry for header table itself */ +#define PT_TLS 7 /* Thread-local storage segment */ +#define PT_NUM 8 /* Number of defined types */ +#define PT_LOOS 0x60000000 /* Start of OS-specific */ +#define PT_GNU_EH_FRAME 0x6474e550 /* GCC .eh_frame_hdr segment */ +#define PT_GNU_STACK 0x6474e551 /* Indicates stack executability */ +#define PT_GNU_RELRO 0x6474e552 /* Read-only after relocation */ +#define PT_LOSUNW 0x6ffffffa +#define PT_SUNWBSS 0x6ffffffa /* Sun Specific segment */ +#define PT_SUNWSTACK 0x6ffffffb /* Stack segment */ +#define PT_HISUNW 0x6fffffff +#define PT_HIOS 0x6fffffff /* End of OS-specific */ +#define PT_LOPROC 0x70000000 /* Start of processor-specific */ +#define PT_HIPROC 0x7fffffff /* End of processor-specific */ + +/* Legal values for p_flags (segment flags). */ + +#define PF_X (1 << 0) /* Segment is executable */ +#define PF_W (1 << 1) /* Segment is writable */ +#define PF_R (1 << 2) /* Segment is readable */ +#define PF_MASKOS 0x0ff00000 /* OS-specific */ +#define PF_MASKPROC 0xf0000000 /* Processor-specific */ + +/* Legal values for note segment descriptor types for core files. */ + +#define NT_PRSTATUS 1 /* Contains copy of prstatus struct */ +#define NT_FPREGSET 2 /* Contains copy of fpregset struct */ +#define NT_PRPSINFO 3 /* Contains copy of prpsinfo struct */ +#define NT_PRXREG 4 /* Contains copy of prxregset struct */ +#define NT_TASKSTRUCT 4 /* Contains copy of task structure */ +#define NT_PLATFORM 5 /* String from sysinfo(SI_PLATFORM) */ +#define NT_AUXV 6 /* Contains copy of auxv array */ +#define NT_GWINDOWS 7 /* Contains copy of gwindows struct */ +#define NT_ASRS 8 /* Contains copy of asrset struct */ +#define NT_PSTATUS 10 /* Contains copy of pstatus struct */ +#define NT_PSINFO 13 /* Contains copy of psinfo struct */ +#define NT_PRCRED 14 /* Contains copy of prcred struct */ +#define NT_UTSNAME 15 /* Contains copy of utsname struct */ +#define NT_LWPSTATUS 16 /* Contains copy of lwpstatus struct */ +#define NT_LWPSINFO 17 /* Contains copy of lwpinfo struct */ +#define NT_PRFPXREG 20 /* Contains copy of fprxregset struct */ +#define NT_PRXFPREG 0x46e62b7f /* Contains copy of user_fxsr_struct */ +#define NT_PPC_VMX 0x100 /* PowerPC Altivec/VMX registers */ +#define NT_PPC_SPE 0x101 /* PowerPC SPE/EVR registers */ +#define NT_PPC_VSX 0x102 /* PowerPC VSX registers */ +#define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */ +#define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */ + +/* Legal values for the note segment descriptor types for object files. */ + +#define NT_VERSION 1 /* Contains a version string. */ + +/* Dynamic section entry. */ + +typedef struct { + Elf32_Sword d_tag; /* Dynamic entry type */ + union { + Elf32_Word d_val; /* Integer value */ + Elf32_Addr d_ptr; /* Address value */ + } d_un; +} Elf32_Dyn; + +typedef struct { + Elf64_Sxword d_tag; /* Dynamic entry type */ + union { + Elf64_Xword d_val; /* Integer value */ + Elf64_Addr d_ptr; /* Address value */ + } d_un; +} Elf64_Dyn; + +/* Legal values for d_tag (dynamic entry type). */ + +#define DT_NULL 0 /* Marks end of dynamic section */ +#define DT_NEEDED 1 /* Name of needed library */ +#define DT_PLTRELSZ 2 /* Size in bytes of PLT relocs */ +#define DT_PLTGOT 3 /* Processor defined value */ +#define DT_HASH 4 /* Address of symbol hash table */ +#define DT_STRTAB 5 /* Address of string table */ +#define DT_SYMTAB 6 /* Address of symbol table */ +#define DT_RELA 7 /* Address of Rela relocs */ +#define DT_RELASZ 8 /* Total size of Rela relocs */ +#define DT_RELAENT 9 /* Size of one Rela reloc */ +#define DT_STRSZ 10 /* Size of string table */ +#define DT_SYMENT 11 /* Size of one symbol table entry */ +#define DT_INIT 12 /* Address of init function */ +#define DT_FINI 13 /* Address of termination function */ +#define DT_SONAME 14 /* Name of shared object */ +#define DT_RPATH 15 /* Library search path (deprecated) */ +#define DT_SYMBOLIC 16 /* Start symbol search here */ +#define DT_REL 17 /* Address of Rel relocs */ +#define DT_RELSZ 18 /* Total size of Rel relocs */ +#define DT_RELENT 19 /* Size of one Rel reloc */ +#define DT_PLTREL 20 /* Type of reloc in PLT */ +#define DT_DEBUG 21 /* For debugging; unspecified */ +#define DT_TEXTREL 22 /* Reloc might modify .text */ +#define DT_JMPREL 23 /* Address of PLT relocs */ +#define DT_BIND_NOW 24 /* Process relocations of object */ +#define DT_INIT_ARRAY 25 /* Array with addresses of init fct */ +#define DT_FINI_ARRAY 26 /* Array with addresses of fini fct */ +#define DT_INIT_ARRAYSZ 27 /* Size in bytes of DT_INIT_ARRAY */ +#define DT_FINI_ARRAYSZ 28 /* Size in bytes of DT_FINI_ARRAY */ +#define DT_RUNPATH 29 /* Library search path */ +#define DT_FLAGS 30 /* Flags for the object being loaded */ +#define DT_ENCODING 32 /* Start of encoded range */ +#define DT_PREINIT_ARRAY 32 /* Array with addresses of preinit fct*/ +#define DT_PREINIT_ARRAYSZ 33 /* size in bytes of DT_PREINIT_ARRAY */ +#define DT_NUM 34 /* Number used */ +#define DT_LOOS 0x6000000d /* Start of OS-specific */ +#define DT_HIOS 0x6ffff000 /* End of OS-specific */ +#define DT_LOPROC 0x70000000 /* Start of processor-specific */ +#define DT_HIPROC 0x7fffffff /* End of processor-specific */ +#define DT_PROCNUM DT_MIPS_NUM /* Most used by any processor */ + +/* DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the + Dyn.d_un.d_val field of the Elf*_Dyn structure. This follows Sun's + approach. */ +#define DT_VALRNGLO 0x6ffffd00 +#define DT_GNU_PRELINKED 0x6ffffdf5 /* Prelinking timestamp */ +#define DT_GNU_CONFLICTSZ 0x6ffffdf6 /* Size of conflict section */ +#define DT_GNU_LIBLISTSZ 0x6ffffdf7 /* Size of library list */ +#define DT_CHECKSUM 0x6ffffdf8 +#define DT_PLTPADSZ 0x6ffffdf9 +#define DT_MOVEENT 0x6ffffdfa +#define DT_MOVESZ 0x6ffffdfb +#define DT_FEATURE_1 0x6ffffdfc /* Feature selection (DTF_*). */ +#define DT_POSFLAG_1 \ + 0x6ffffdfd /* Flags for DT_* entries, effecting + the following DT_* entry. */ +#define DT_SYMINSZ 0x6ffffdfe /* Size of syminfo table (in bytes) */ +#define DT_SYMINENT 0x6ffffdff /* Entry size of syminfo */ +#define DT_VALRNGHI 0x6ffffdff +#define DT_VALTAGIDX(tag) (DT_VALRNGHI - (tag)) /* Reverse order! */ +#define DT_VALNUM 12 + +/* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the + Dyn.d_un.d_ptr field of the Elf*_Dyn structure. + + If any adjustment is made to the ELF object after it has been + built these entries will need to be adjusted. */ +#define DT_ADDRRNGLO 0x6ffffe00 +#define DT_GNU_HASH 0x6ffffef5 /* GNU-style hash table. */ +#define DT_TLSDESC_PLT 0x6ffffef6 +#define DT_TLSDESC_GOT 0x6ffffef7 +#define DT_GNU_CONFLICT 0x6ffffef8 /* Start of conflict section */ +#define DT_GNU_LIBLIST 0x6ffffef9 /* Library list */ +#define DT_CONFIG 0x6ffffefa /* Configuration information. */ +#define DT_DEPAUDIT 0x6ffffefb /* Dependency auditing. */ +#define DT_AUDIT 0x6ffffefc /* Object auditing. */ +#define DT_PLTPAD 0x6ffffefd /* PLT padding. */ +#define DT_MOVETAB 0x6ffffefe /* Move table. */ +#define DT_SYMINFO 0x6ffffeff /* Syminfo table. */ +#define DT_ADDRRNGHI 0x6ffffeff +#define DT_ADDRTAGIDX(tag) (DT_ADDRRNGHI - (tag)) /* Reverse order! */ +#define DT_ADDRNUM 11 + +/* The versioning entry types. The next are defined as part of the + GNU extension. */ +#define DT_VERSYM 0x6ffffff0 + +#define DT_RELACOUNT 0x6ffffff9 +#define DT_RELCOUNT 0x6ffffffa + +/* These were chosen by Sun. */ +#define DT_FLAGS_1 0x6ffffffb /* State flags, see DF_1_* below. */ +#define DT_VERDEF \ + 0x6ffffffc /* Address of version definition + table */ +#define DT_VERDEFNUM 0x6ffffffd /* Number of version definitions */ +#define DT_VERNEED \ + 0x6ffffffe /* Address of table with needed + versions */ +#define DT_VERNEEDNUM 0x6fffffff /* Number of needed versions */ +#define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) /* Reverse order! */ +#define DT_VERSIONTAGNUM 16 + +/* Sun added these machine-independent extensions in the "processor-specific" + range. Be compatible. */ +#define DT_AUXILIARY 0x7ffffffd /* Shared object to load before self */ +#define DT_FILTER 0x7fffffff /* Shared object to get values from */ +#define DT_EXTRATAGIDX(tag) ((Elf32_Word) - ((Elf32_Sword)(tag) << 1 >> 1) - 1) +#define DT_EXTRANUM 3 + +/* Values of `d_un.d_val' in the DT_FLAGS entry. */ +#define DF_ORIGIN 0x00000001 /* Object may use DF_ORIGIN */ +#define DF_SYMBOLIC 0x00000002 /* Symbol resolutions starts here */ +#define DF_TEXTREL 0x00000004 /* Object contains text relocations */ +#define DF_BIND_NOW 0x00000008 /* No lazy binding for this object */ +#define DF_STATIC_TLS 0x00000010 /* Module uses the static TLS model */ + +/* State flags selectable in the `d_un.d_val' element of the DT_FLAGS_1 + entry in the dynamic section. */ +#define DF_1_NOW 0x00000001 /* Set RTLD_NOW for this object. */ +#define DF_1_GLOBAL 0x00000002 /* Set RTLD_GLOBAL for this object. */ +#define DF_1_GROUP 0x00000004 /* Set RTLD_GROUP for this object. */ +#define DF_1_NODELETE 0x00000008 /* Set RTLD_NODELETE for this object.*/ +#define DF_1_LOADFLTR 0x00000010 /* Trigger filtee loading at runtime.*/ +#define DF_1_INITFIRST 0x00000020 /* Set RTLD_INITFIRST for this object*/ +#define DF_1_NOOPEN 0x00000040 /* Set RTLD_NOOPEN for this object. */ +#define DF_1_ORIGIN 0x00000080 /* $ORIGIN must be handled. */ +#define DF_1_DIRECT 0x00000100 /* Direct binding enabled. */ +#define DF_1_TRANS 0x00000200 +#define DF_1_INTERPOSE 0x00000400 /* Object is used to interpose. */ +#define DF_1_NODEFLIB 0x00000800 /* Ignore default lib search path. */ +#define DF_1_NODUMP 0x00001000 /* Object can't be dldump'ed. */ +#define DF_1_CONFALT 0x00002000 /* Configuration alternative created.*/ +#define DF_1_ENDFILTEE 0x00004000 /* Filtee terminates filters search. */ +#define DF_1_DISPRELDNE 0x00008000 /* Disp reloc applied at build time. */ +#define DF_1_DISPRELPND 0x00010000 /* Disp reloc applied at run-time. */ + +/* Flags for the feature selection in DT_FEATURE_1. */ +#define DTF_1_PARINIT 0x00000001 +#define DTF_1_CONFEXP 0x00000002 + +/* Flags in the DT_POSFLAG_1 entry effecting only the next DT_* entry. */ +#define DF_P1_LAZYLOAD 0x00000001 /* Lazyload following object. */ +#define DF_P1_GROUPPERM \ + 0x00000002 /* Symbols from next object are not + generally available. */ + +/* Version definition sections. */ + +typedef struct { + Elf32_Half vd_version; /* Version revision */ + Elf32_Half vd_flags; /* Version information */ + Elf32_Half vd_ndx; /* Version Index */ + Elf32_Half vd_cnt; /* Number of associated aux entries */ + Elf32_Word vd_hash; /* Version name hash value */ + Elf32_Word vd_aux; /* Offset in bytes to verdaux array */ + Elf32_Word vd_next; /* Offset in bytes to next verdef + entry */ +} Elf32_Verdef; + +typedef struct { + Elf64_Half vd_version; /* Version revision */ + Elf64_Half vd_flags; /* Version information */ + Elf64_Half vd_ndx; /* Version Index */ + Elf64_Half vd_cnt; /* Number of associated aux entries */ + Elf64_Word vd_hash; /* Version name hash value */ + Elf64_Word vd_aux; /* Offset in bytes to verdaux array */ + Elf64_Word vd_next; /* Offset in bytes to next verdef + entry */ +} Elf64_Verdef; + +/* Legal values for vd_version (version revision). */ +#define VER_DEF_NONE 0 /* No version */ +#define VER_DEF_CURRENT 1 /* Current version */ +#define VER_DEF_NUM 2 /* Given version number */ + +/* Legal values for vd_flags (version information flags). */ +#define VER_FLG_BASE 0x1 /* Version definition of file itself */ +#define VER_FLG_WEAK 0x2 /* Weak version identifier */ + +/* Versym symbol index values. */ +#define VER_NDX_LOCAL 0 /* Symbol is local. */ +#define VER_NDX_GLOBAL 1 /* Symbol is global. */ +#define VER_NDX_LORESERVE 0xff00 /* Beginning of reserved entries. */ +#define VER_NDX_ELIMINATE 0xff01 /* Symbol is to be eliminated. */ + +/* Auxialiary version information. */ + +typedef struct { + Elf32_Word vda_name; /* Version or dependency names */ + Elf32_Word vda_next; /* Offset in bytes to next verdaux + entry */ +} Elf32_Verdaux; + +typedef struct { + Elf64_Word vda_name; /* Version or dependency names */ + Elf64_Word vda_next; /* Offset in bytes to next verdaux + entry */ +} Elf64_Verdaux; + +/* Version dependency section. */ + +typedef struct { + Elf32_Half vn_version; /* Version of structure */ + Elf32_Half vn_cnt; /* Number of associated aux entries */ + Elf32_Word vn_file; /* Offset of filename for this + dependency */ + Elf32_Word vn_aux; /* Offset in bytes to vernaux array */ + Elf32_Word vn_next; /* Offset in bytes to next verneed + entry */ +} Elf32_Verneed; + +typedef struct { + Elf64_Half vn_version; /* Version of structure */ + Elf64_Half vn_cnt; /* Number of associated aux entries */ + Elf64_Word vn_file; /* Offset of filename for this + dependency */ + Elf64_Word vn_aux; /* Offset in bytes to vernaux array */ + Elf64_Word vn_next; /* Offset in bytes to next verneed + entry */ +} Elf64_Verneed; + +/* Legal values for vn_version (version revision). */ +#define VER_NEED_NONE 0 /* No version */ +#define VER_NEED_CURRENT 1 /* Current version */ +#define VER_NEED_NUM 2 /* Given version number */ + +/* Auxiliary needed version information. */ + +typedef struct { + Elf32_Word vna_hash; /* Hash value of dependency name */ + Elf32_Half vna_flags; /* Dependency specific information */ + Elf32_Half vna_other; /* Unused */ + Elf32_Word vna_name; /* Dependency name string offset */ + Elf32_Word vna_next; /* Offset in bytes to next vernaux + entry */ +} Elf32_Vernaux; + +typedef struct { + Elf64_Word vna_hash; /* Hash value of dependency name */ + Elf64_Half vna_flags; /* Dependency specific information */ + Elf64_Half vna_other; /* Unused */ + Elf64_Word vna_name; /* Dependency name string offset */ + Elf64_Word vna_next; /* Offset in bytes to next vernaux + entry */ +} Elf64_Vernaux; + +/* Legal values for vna_flags. */ +#define VER_FLG_WEAK 0x2 /* Weak version identifier */ + +/* Auxiliary vector. */ + +/* This vector is normally only used by the program interpreter. The + usual definition in an ABI supplement uses the name auxv_t. The + vector is not usually defined in a standard file, but it + can't hurt. We rename it to avoid conflicts. The sizes of these + types are an arrangement between the exec server and the program + interpreter, so we don't fully specify them here. */ + +typedef struct { + uint32_t a_type; /* Entry type */ + union { + uint32_t a_val; /* Integer value */ + /* We use to have pointer elements added here. We cannot do that, + though, since it does not work when using 32-bit definitions + on 64-bit platforms and vice versa. */ + } a_un; +} Elf32_auxv_t; + +typedef struct { + uint64_t a_type; /* Entry type */ + union { + uint64_t a_val; /* Integer value */ + /* We use to have pointer elements added here. We cannot do that, + though, since it does not work when using 32-bit definitions + on 64-bit platforms and vice versa. */ + } a_un; +} Elf64_auxv_t; + +/* Legal values for a_type (entry type). */ + +#define AT_NULL 0 /* End of vector */ +#define AT_IGNORE 1 /* Entry should be ignored */ +#define AT_EXECFD 2 /* File descriptor of program */ +#define AT_PHDR 3 /* Program headers for program */ +#define AT_PHENT 4 /* Size of program header entry */ +#define AT_PHNUM 5 /* Number of program headers */ +#define AT_PAGESZ 6 /* System page size */ +#define AT_BASE 7 /* Base address of interpreter */ +#define AT_FLAGS 8 /* Flags */ +#define AT_ENTRY 9 /* Entry point of program */ +#define AT_NOTELF 10 /* Program is not ELF */ +#define AT_UID 11 /* Real uid */ +#define AT_EUID 12 /* Effective uid */ +#define AT_GID 13 /* Real gid */ +#define AT_EGID 14 /* Effective gid */ +#define AT_CLKTCK 17 /* Frequency of times() */ + +/* Some more special a_type values describing the hardware. */ +#define AT_PLATFORM 15 /* String identifying platform. */ +#define AT_HWCAP \ + 16 /* Machine dependent hints about + processor capabilities. */ + +/* This entry gives some information about the FPU initialization + performed by the kernel. */ +#define AT_FPUCW 18 /* Used FPU control word. */ + +/* Cache block sizes. */ +#define AT_DCACHEBSIZE 19 /* Data cache block size. */ +#define AT_ICACHEBSIZE 20 /* Instruction cache block size. */ +#define AT_UCACHEBSIZE 21 /* Unified cache block size. */ + +/* A special ignored value for PPC, used by the kernel to control the + interpretation of the AUXV. Must be > 16. */ +#define AT_IGNOREPPC 22 /* Entry should be ignored. */ + +#define AT_SECURE 23 /* Boolean, was exec setuid-like? */ + +#define AT_BASE_PLATFORM 24 /* String identifying real platforms.*/ + +#define AT_RANDOM 25 /* Address of 16 random bytes. */ + +#define AT_EXECFN 31 /* Filename of executable. */ + +/* Pointer to the global system page used for system calls and other + nice things. */ +#define AT_SYSINFO 32 +#define AT_SYSINFO_EHDR 33 + +/* Shapes of the caches. Bits 0-3 contains associativity; bits 4-7 contains + log2 of line size; mask those to get cache size. */ +#define AT_L1I_CACHESHAPE 34 +#define AT_L1D_CACHESHAPE 35 +#define AT_L2_CACHESHAPE 36 +#define AT_L3_CACHESHAPE 37 + +/* Note section contents. Each entry in the note section begins with + a header of a fixed form. */ + +typedef struct { + Elf32_Word n_namesz; /* Length of the note's name. */ + Elf32_Word n_descsz; /* Length of the note's descriptor. */ + Elf32_Word n_type; /* Type of the note. */ +} Elf32_Nhdr; + +typedef struct { + Elf64_Word n_namesz; /* Length of the note's name. */ + Elf64_Word n_descsz; /* Length of the note's descriptor. */ + Elf64_Word n_type; /* Type of the note. */ +} Elf64_Nhdr; + +/* Known names of notes. */ + +/* Solaris entries in the note section have this name. */ +#define ELF_NOTE_SOLARIS "SUNW Solaris" + +/* Note entries for GNU systems have this name. */ +#define ELF_NOTE_GNU "GNU" + +/* Defined types of notes for Solaris. */ + +/* Value of descriptor (one word) is desired pagesize for the binary. */ +#define ELF_NOTE_PAGESIZE_HINT 1 + +/* Defined note types for GNU systems. */ + +/* ABI information. The descriptor consists of words: + word 0: OS descriptor + word 1: major version of the ABI + word 2: minor version of the ABI + word 3: subminor version of the ABI +*/ +#define NT_GNU_ABI_TAG 1 +#define ELF_NOTE_ABI NT_GNU_ABI_TAG /* Old name. */ + +/* Known OSes. These values can appear in word 0 of an + NT_GNU_ABI_TAG note section entry. */ +#define ELF_NOTE_OS_LINUX 0 +#define ELF_NOTE_OS_GNU 1 +#define ELF_NOTE_OS_SOLARIS2 2 +#define ELF_NOTE_OS_FREEBSD 3 + +/* Synthetic hwcap information. The descriptor begins with two words: + word 0: number of entries + word 1: bitmask of enabled entries + Then follow variable-length entries, one byte followed by a + '\0'-terminated hwcap name string. The byte gives the bit + number to test if enabled, (1U << bit) & bitmask. */ +#define NT_GNU_HWCAP 2 + +/* Build ID bits as generated by ld --build-id. + The descriptor consists of any nonzero number of bytes. */ +#define NT_GNU_BUILD_ID 3 + +/* Version note generated by GNU gold containing a version string. */ +#define NT_GNU_GOLD_VERSION 4 + +/* Move records. */ +typedef struct { + Elf32_Xword m_value; /* Symbol value. */ + Elf32_Word m_info; /* Size and index. */ + Elf32_Word m_poffset; /* Symbol offset. */ + Elf32_Half m_repeat; /* Repeat count. */ + Elf32_Half m_stride; /* Stride info. */ +} Elf32_Move; + +typedef struct { + Elf64_Xword m_value; /* Symbol value. */ + Elf64_Xword m_info; /* Size and index. */ + Elf64_Xword m_poffset; /* Symbol offset. */ + Elf64_Half m_repeat; /* Repeat count. */ + Elf64_Half m_stride; /* Stride info. */ +} Elf64_Move; + +/* Macro to construct move records. */ +#define ELF32_M_SYM(info) ((info) >> 8) +#define ELF32_M_SIZE(info) ((unsigned char)(info)) +#define ELF32_M_INFO(sym, size) (((sym) << 8) + (unsigned char)(size)) + +#define ELF64_M_SYM(info) ELF32_M_SYM(info) +#define ELF64_M_SIZE(info) ELF32_M_SIZE(info) +#define ELF64_M_INFO(sym, size) ELF32_M_INFO(sym, size) + +/* ARM specific declarations */ + +/* Processor specific flags for the ELF header e_flags field. */ +#define EF_ARM_RELEXEC 0x01 +#define EF_ARM_HASENTRY 0x02 +#define EF_ARM_INTERWORK 0x04 +#define EF_ARM_APCS_26 0x08 +#define EF_ARM_APCS_FLOAT 0x10 +#define EF_ARM_PIC 0x20 +#define EF_ARM_ALIGN8 0x40 /* 8-bit structure alignment is in use */ +#define EF_ARM_NEW_ABI 0x80 +#define EF_ARM_OLD_ABI 0x100 +#define EF_ARM_SOFT_FLOAT 0x200 +#define EF_ARM_VFP_FLOAT 0x400 +#define EF_ARM_MAVERICK_FLOAT 0x800 + +/* Other constants defined in the ARM ELF spec. version B-01. */ +/* NB. These conflict with values defined above. */ +#define EF_ARM_SYMSARESORTED 0x04 +#define EF_ARM_DYNSYMSUSESEGIDX 0x08 +#define EF_ARM_MAPSYMSFIRST 0x10 +#define EF_ARM_EABIMASK 0XFF000000 + +/* Constants defined in AAELF. */ +#define EF_ARM_BE8 0x00800000 +#define EF_ARM_LE8 0x00400000 + +#define EF_ARM_EABI_VERSION(flags) ((flags)&EF_ARM_EABIMASK) +#define EF_ARM_EABI_UNKNOWN 0x00000000 +#define EF_ARM_EABI_VER1 0x01000000 +#define EF_ARM_EABI_VER2 0x02000000 +#define EF_ARM_EABI_VER3 0x03000000 +#define EF_ARM_EABI_VER4 0x04000000 +#define EF_ARM_EABI_VER5 0x05000000 + +/* Additional symbol types for Thumb. */ +#define STT_ARM_TFUNC STT_LOPROC /* A Thumb function. */ +#define STT_ARM_16BIT STT_HIPROC /* A Thumb label. */ + +/* ARM-specific values for sh_flags */ +#define SHF_ARM_ENTRYSECT 0x10000000 /* Section contains an entry point */ +#define SHF_ARM_COMDEF \ + 0x80000000 /* Section may be multiply defined + in the input to a link step. */ + +/* ARM-specific program header flags */ +#define PF_ARM_SB \ + 0x10000000 /* Segment contains the location + addressed by the static base. */ +#define PF_ARM_PI 0x20000000 /* Position-independent segment. */ +#define PF_ARM_ABS 0x40000000 /* Absolute segment. */ + +/* Processor specific values for the Phdr p_type field. */ +#define PT_ARM_EXIDX (PT_LOPROC + 1) /* ARM unwind segment. */ + +/* Processor specific values for the Shdr sh_type field. */ +#define SHT_ARM_EXIDX (SHT_LOPROC + 1) /* ARM unwind section. */ +#define SHT_ARM_PREEMPTMAP (SHT_LOPROC + 2) /* Preemption details. */ +#define SHT_ARM_ATTRIBUTES (SHT_LOPROC + 3) /* ARM attributes section. */ + +/* ARM relocs. */ + +#define R_ARM_NONE 0 /* No reloc */ +#define R_ARM_PC24 1 /* PC relative 26 bit branch */ +#define R_ARM_ABS32 2 /* Direct 32 bit */ +#define R_ARM_REL32 3 /* PC relative 32 bit */ +#define R_ARM_PC13 4 +#define R_ARM_ABS16 5 /* Direct 16 bit */ +#define R_ARM_ABS12 6 /* Direct 12 bit */ +#define R_ARM_THM_ABS5 7 +#define R_ARM_ABS8 8 /* Direct 8 bit */ +#define R_ARM_SBREL32 9 +#define R_ARM_THM_PC22 10 +#define R_ARM_THM_PC8 11 +#define R_ARM_AMP_VCALL9 12 +#define R_ARM_SWI24 13 +#define R_ARM_THM_SWI8 14 +#define R_ARM_XPC25 15 +#define R_ARM_THM_XPC22 16 +#define R_ARM_TLS_DTPMOD32 17 /* ID of module containing symbol */ +#define R_ARM_TLS_DTPOFF32 18 /* Offset in TLS block */ +#define R_ARM_TLS_TPOFF32 19 /* Offset in static TLS block */ +#define R_ARM_COPY 20 /* Copy symbol at runtime */ +#define R_ARM_GLOB_DAT 21 /* Create GOT entry */ +#define R_ARM_JUMP_SLOT 22 /* Create PLT entry */ +#define R_ARM_RELATIVE 23 /* Adjust by program base */ +#define R_ARM_GOTOFF 24 /* 32 bit offset to GOT */ +#define R_ARM_GOTPC 25 /* 32 bit PC relative offset to GOT */ +#define R_ARM_GOT32 26 /* 32 bit GOT entry */ +#define R_ARM_PLT32 27 /* 32 bit PLT address */ +#define R_ARM_THM_JUMP24 30 /* Thumb32 ((S + A) | T) - P */ +#define R_ARM_ALU_PCREL_7_0 32 +#define R_ARM_ALU_PCREL_15_8 33 +#define R_ARM_ALU_PCREL_23_15 34 +#define R_ARM_LDR_SBREL_11_0 35 +#define R_ARM_ALU_SBREL_19_12 36 +#define R_ARM_ALU_SBREL_27_20 37 +#define R_ARM_GNU_VTENTRY 100 +#define R_ARM_GNU_VTINHERIT 101 +#define R_ARM_THM_PC11 102 /* thumb unconditional branch */ +#define R_ARM_THM_PC9 103 /* thumb conditional branch */ +#define R_ARM_TLS_GD32 \ + 104 /* PC-rel 32 bit for global dynamic + thread local data */ +#define R_ARM_TLS_LDM32 \ + 105 /* PC-rel 32 bit for local dynamic + thread local data */ +#define R_ARM_TLS_LDO32 \ + 106 /* 32 bit offset relative to TLS + block */ +#define R_ARM_TLS_IE32 \ + 107 /* PC-rel 32 bit for GOT entry of + static TLS block offset */ +#define R_ARM_TLS_LE32 \ + 108 /* 32 bit offset relative to static + TLS block */ +#define R_ARM_RXPC25 249 +#define R_ARM_RSBREL32 250 +#define R_ARM_THM_RPC22 251 +#define R_ARM_RREL32 252 +#define R_ARM_RABS22 253 +#define R_ARM_RPC24 254 +#define R_ARM_RBASE 255 +/* Keep this the last entry. */ +#define R_ARM_NUM 256 + +#endif /* elf.h */ diff --git a/lib/flipper_application/elf/elf_api_interface.h b/lib/flipper_application/elf/elf_api_interface.h new file mode 100644 index 000000000..505f4f718 --- /dev/null +++ b/lib/flipper_application/elf/elf_api_interface.h @@ -0,0 +1,12 @@ +#pragma once + +#include +#include + +#define ELF_INVALID_ADDRESS 0xFFFFFFFF + +typedef struct { + uint16_t api_version_major; + uint16_t api_version_minor; + bool (*resolver_callback)(const char* name, Elf32_Addr* address); +} ElfApiInterface; diff --git a/lib/flipper_application/flipper_applicaiton_i.c b/lib/flipper_application/flipper_applicaiton_i.c new file mode 100644 index 000000000..a2a069eeb --- /dev/null +++ b/lib/flipper_application/flipper_applicaiton_i.c @@ -0,0 +1,477 @@ +#include "flipper_application_i.h" +#include + +#define TAG "fapp-i" + +#define RESOLVER_THREAD_YIELD_STEP 30 + +#define IS_FLAGS_SET(v, m) ((v & m) == m) +#define SECTION_OFFSET(e, n) (e->section_table + n * sizeof(Elf32_Shdr)) +#define SYMBOL_OFFSET(e, n) (e->_table + n * sizeof(Elf32_Shdr)) + +bool flipper_application_load_elf_headers(FlipperApplication* e, const char* path) { + Elf32_Ehdr h; + Elf32_Shdr sH; + + if(!storage_file_open(e->fd, path, FSAM_READ, FSOM_OPEN_EXISTING) || + !storage_file_seek(e->fd, 0, true) || + storage_file_read(e->fd, &h, sizeof(h)) != sizeof(h) || + !storage_file_seek(e->fd, h.e_shoff + h.e_shstrndx * sizeof(sH), true) || + storage_file_read(e->fd, &sH, sizeof(Elf32_Shdr)) != sizeof(Elf32_Shdr)) { + return false; + } + + e->entry = h.e_entry; + e->sections = h.e_shnum; + e->section_table = h.e_shoff; + e->section_table_strings = sH.sh_offset; + return true; +} + +static bool flipper_application_load_metadata(FlipperApplication* e, Elf32_Shdr* sh) { + if(sh->sh_size < sizeof(e->manifest)) { + return false; + } + + return storage_file_seek(e->fd, sh->sh_offset, true) && + storage_file_read(e->fd, &e->manifest, sh->sh_size) == sh->sh_size; +} + +static bool flipper_application_load_debug_link(FlipperApplication* e, Elf32_Shdr* sh) { + e->state.debug_link_size = sh->sh_size; + e->state.debug_link = malloc(sh->sh_size); + + return storage_file_seek(e->fd, sh->sh_offset, true) && + storage_file_read(e->fd, e->state.debug_link, sh->sh_size) == sh->sh_size; +} + +static FindFlags_t flipper_application_preload_section( + FlipperApplication* e, + Elf32_Shdr* sh, + const char* name, + int n) { + FURI_LOG_D(TAG, "Processing: %s", name); + + const struct { + const char* name; + uint16_t* ptr_section_idx; + FindFlags_t flags; + } lookup_sections[] = { + {".text", &e->text.sec_idx, FoundText}, + {".rodata", &e->rodata.sec_idx, FoundRodata}, + {".data", &e->data.sec_idx, FoundData}, + {".bss", &e->bss.sec_idx, FoundBss}, + {".rel.text", &e->text.rel_sec_idx, FoundRelText}, + {".rel.rodata", &e->rodata.rel_sec_idx, FoundRelRodata}, + {".rel.data", &e->data.rel_sec_idx, FoundRelData}, + }; + + for(size_t i = 0; i < COUNT_OF(lookup_sections); i++) { + if(strcmp(name, lookup_sections[i].name) == 0) { + *lookup_sections[i].ptr_section_idx = n; + return lookup_sections[i].flags; + } + } + + if(strcmp(name, ".symtab") == 0) { + e->symbol_table = sh->sh_offset; + e->symbol_count = sh->sh_size / sizeof(Elf32_Sym); + return FoundSymTab; + } else if(strcmp(name, ".strtab") == 0) { + e->symbol_table_strings = sh->sh_offset; + return FoundStrTab; + } else if(strcmp(name, ".fapmeta") == 0) { + // Load metadata immediately + if(flipper_application_load_metadata(e, sh)) { + return FoundFappManifest; + } + } else if(strcmp(name, ".gnu_debuglink") == 0) { + if(flipper_application_load_debug_link(e, sh)) { + return FoundDebugLink; + } + } + return FoundERROR; +} + +static bool + read_string_from_offset(FlipperApplication* e, off_t offset, char* buffer, size_t buffer_size) { + bool success = false; + + off_t old = storage_file_tell(e->fd); + if(storage_file_seek(e->fd, offset, true) && + (storage_file_read(e->fd, buffer, buffer_size) == buffer_size)) { + success = true; + } + storage_file_seek(e->fd, old, true); + + return success; +} + +static bool read_section_name(FlipperApplication* e, off_t off, char* buf, size_t max) { + return read_string_from_offset(e, e->section_table_strings + off, buf, max); +} + +static bool read_symbol_name(FlipperApplication* e, off_t off, char* buf, size_t max) { + return read_string_from_offset(e, e->symbol_table_strings + off, buf, max); +} + +static bool read_section_header(FlipperApplication* e, int n, Elf32_Shdr* h) { + off_t offset = SECTION_OFFSET(e, n); + return storage_file_seek(e->fd, offset, true) && + storage_file_read(e->fd, h, sizeof(Elf32_Shdr)) == sizeof(Elf32_Shdr); +} + +static bool read_section(FlipperApplication* e, int n, Elf32_Shdr* h, char* name, size_t nlen) { + if(!read_section_header(e, n, h)) { + return false; + } + if(!h->sh_name) { + return true; + } + return read_section_name(e, h->sh_name, name, nlen); +} + +bool flipper_application_load_section_table(FlipperApplication* e) { + furi_check(e->state.mmap_entry_count == 0); + + size_t n; + FindFlags_t found = FoundERROR; + FURI_LOG_D(TAG, "Scan ELF indexs..."); + for(n = 1; n < e->sections; n++) { + Elf32_Shdr section_header; + char name[33] = {0}; + if(!read_section_header(e, n, §ion_header)) { + return false; + } + if(section_header.sh_name && + !read_section_name(e, section_header.sh_name, name, sizeof(name))) { + return false; + } + + FURI_LOG_T(TAG, "Examining section %d %s", n, name); + FindFlags_t section_flags = + flipper_application_preload_section(e, §ion_header, name, n); + found |= section_flags; + if((section_flags & FoundGdbSection) != 0) { + e->state.mmap_entry_count++; + } + if(IS_FLAGS_SET(found, FoundAll)) { + return true; + } + } + + FURI_LOG_D(TAG, "Load symbols done"); + return IS_FLAGS_SET(found, FoundValid); +} + +static const char* type_to_str(int symt) { +#define STRCASE(name) \ + case name: \ + return #name; + switch(symt) { + STRCASE(R_ARM_NONE) + STRCASE(R_ARM_ABS32) + STRCASE(R_ARM_THM_PC22) + STRCASE(R_ARM_THM_JUMP24) + default: + return "R_"; + } +#undef STRCASE +} + +static void relocate_jmp_call(Elf32_Addr relAddr, int type, Elf32_Addr symAddr) { + UNUSED(type); + uint16_t upper_insn = ((uint16_t*)relAddr)[0]; + uint16_t lower_insn = ((uint16_t*)relAddr)[1]; + uint32_t S = (upper_insn >> 10) & 1; + uint32_t J1 = (lower_insn >> 13) & 1; + uint32_t J2 = (lower_insn >> 11) & 1; + + int32_t offset = (S << 24) | /* S -> offset[24] */ + ((~(J1 ^ S) & 1) << 23) | /* J1 -> offset[23] */ + ((~(J2 ^ S) & 1) << 22) | /* J2 -> offset[22] */ + ((upper_insn & 0x03ff) << 12) | /* imm10 -> offset[12:21] */ + ((lower_insn & 0x07ff) << 1); /* imm11 -> offset[1:11] */ + if(offset & 0x01000000) offset -= 0x02000000; + + offset += symAddr - relAddr; + + S = (offset >> 24) & 1; + J1 = S ^ (~(offset >> 23) & 1); + J2 = S ^ (~(offset >> 22) & 1); + + upper_insn = ((upper_insn & 0xf800) | (S << 10) | ((offset >> 12) & 0x03ff)); + ((uint16_t*)relAddr)[0] = upper_insn; + + lower_insn = ((lower_insn & 0xd000) | (J1 << 13) | (J2 << 11) | ((offset >> 1) & 0x07ff)); + ((uint16_t*)relAddr)[1] = lower_insn; +} + +static bool relocate_symbol(Elf32_Addr relAddr, int type, Elf32_Addr symAddr) { + switch(type) { + case R_ARM_ABS32: + *((uint32_t*)relAddr) += symAddr; + FURI_LOG_D(TAG, " R_ARM_ABS32 relocated is 0x%08X", (unsigned int)*((uint32_t*)relAddr)); + break; + case R_ARM_THM_PC22: + case R_ARM_THM_JUMP24: + relocate_jmp_call(relAddr, type, symAddr); + FURI_LOG_D( + TAG, " R_ARM_THM_CALL/JMP relocated is 0x%08X", (unsigned int)*((uint32_t*)relAddr)); + break; + default: + FURI_LOG_D(TAG, " Undefined relocation %d", type); + return false; + } + return true; +} + +static ELFSection_t* section_of(FlipperApplication* e, int index) { + if(e->text.sec_idx == index) { + return &e->text; + } else if(e->data.sec_idx == index) { + return &e->data; + } else if(e->bss.sec_idx == index) { + return &e->bss; + } else if(e->rodata.sec_idx == index) { + return &e->rodata; + } + return NULL; +} + +static Elf32_Addr address_of(FlipperApplication* e, Elf32_Sym* sym, const char* sName) { + if(sym->st_shndx == SHN_UNDEF) { + Elf32_Addr addr = 0; + if(e->api_interface->resolver_callback(sName, &addr)) { + return addr; + } + } else { + ELFSection_t* symSec = section_of(e, sym->st_shndx); + if(symSec) { + return ((Elf32_Addr)symSec->data) + sym->st_value; + } + } + FURI_LOG_D(TAG, " Can not find address for symbol %s", sName); + return ELF_INVALID_ADDRESS; +} + +static bool read_symbol(FlipperApplication* e, int n, Elf32_Sym* sym, char* name, size_t nlen) { + bool success = false; + off_t old = storage_file_tell(e->fd); + off_t pos = e->symbol_table + n * sizeof(Elf32_Sym); + if(storage_file_seek(e->fd, pos, true) && + storage_file_read(e->fd, sym, sizeof(Elf32_Sym)) == sizeof(Elf32_Sym)) { + if(sym->st_name) + success = read_symbol_name(e, sym->st_name, name, nlen); + else { + Elf32_Shdr shdr; + success = read_section(e, sym->st_shndx, &shdr, name, nlen); + } + } + storage_file_seek(e->fd, old, true); + return success; +} + +static bool + relocation_cache_get(RelocationAddressCache_t cache, int symEntry, Elf32_Addr* symAddr) { + Elf32_Addr* addr = RelocationAddressCache_get(cache, symEntry); + if(addr) { + *symAddr = *addr; + return true; + } else { + return false; + } +} + +static void + relocation_cache_put(RelocationAddressCache_t cache, int symEntry, Elf32_Addr symAddr) { + RelocationAddressCache_set_at(cache, symEntry, symAddr); +} + +#define MAX_SYMBOL_NAME_LEN 128u + +static bool relocate(FlipperApplication* e, Elf32_Shdr* h, ELFSection_t* s) { + if(s->data) { + Elf32_Rel rel; + size_t relEntries = h->sh_size / sizeof(rel); + size_t relCount; + (void)storage_file_seek(e->fd, h->sh_offset, true); + FURI_LOG_D(TAG, " Offset Info Type Name"); + + int relocate_result = true; + char symbol_name[MAX_SYMBOL_NAME_LEN + 1] = {0}; + + for(relCount = 0; relCount < relEntries; relCount++) { + if(relCount % RESOLVER_THREAD_YIELD_STEP == 0) { + FURI_LOG_D(TAG, " reloc YIELD"); + furi_delay_tick(1); + } + + if(storage_file_read(e->fd, &rel, sizeof(Elf32_Rel)) != sizeof(Elf32_Rel)) { + FURI_LOG_E(TAG, " reloc read fail"); + return false; + } + + Elf32_Addr symAddr; + + int symEntry = ELF32_R_SYM(rel.r_info); + int relType = ELF32_R_TYPE(rel.r_info); + Elf32_Addr relAddr = ((Elf32_Addr)s->data) + rel.r_offset; + + if(!relocation_cache_get(e->relocation_cache, symEntry, &symAddr)) { + Elf32_Sym sym; + if(!read_symbol(e, symEntry, &sym, symbol_name, MAX_SYMBOL_NAME_LEN)) { + FURI_LOG_E(TAG, " symbol read fail"); + return false; + } + + FURI_LOG_D( + TAG, + " %08X %08X %-16s %s", + (unsigned int)rel.r_offset, + (unsigned int)rel.r_info, + type_to_str(relType), + symbol_name); + + symAddr = address_of(e, &sym, symbol_name); + relocation_cache_put(e->relocation_cache, symEntry, symAddr); + } + + if(symAddr != ELF_INVALID_ADDRESS) { + FURI_LOG_D( + TAG, + " symAddr=%08X relAddr=%08X", + (unsigned int)symAddr, + (unsigned int)relAddr); + if(!relocate_symbol(relAddr, relType, symAddr)) { + relocate_result = false; + } + } else { + FURI_LOG_D(TAG, " No symbol address of %s", symbol_name); + relocate_result = false; + } + } + + return relocate_result; + } else + FURI_LOG_I(TAG, "Section not loaded"); + + return false; +} + +static bool flipper_application_load_section_data(FlipperApplication* e, ELFSection_t* s) { + Elf32_Shdr section_header; + if(s->sec_idx == 0) { + FURI_LOG_I(TAG, "Section is not present"); + return true; + } + + if(!read_section_header(e, s->sec_idx, §ion_header)) { + return false; + } + + if(section_header.sh_size == 0) { + FURI_LOG_I(TAG, "No data for section"); + return true; + } + + s->data = aligned_malloc(section_header.sh_size, section_header.sh_addralign); + // e->state.mmap_entry_count++; + + if(section_header.sh_type == SHT_NOBITS) { + /* section is empty (.bss?) */ + /* no need to memset - allocator already did that */ + /* memset(s->data, 0, h->sh_size); */ + FURI_LOG_D(TAG, "0x%X", s->data); + return true; + } + + if((!storage_file_seek(e->fd, section_header.sh_offset, true)) || + (storage_file_read(e->fd, s->data, section_header.sh_size) != section_header.sh_size)) { + FURI_LOG_E(TAG, " seek/read fail"); + flipper_application_free_section(s); + return false; + } + + FURI_LOG_D(TAG, "0x%X", s->data); + return true; +} + +static bool flipper_application_relocate_section(FlipperApplication* e, ELFSection_t* s) { + Elf32_Shdr section_header; + if(s->rel_sec_idx) { + FURI_LOG_D(TAG, "Relocating section"); + if(read_section_header(e, s->rel_sec_idx, §ion_header)) + return relocate(e, §ion_header, s); + else { + FURI_LOG_E(TAG, "Error reading section header"); + return false; + } + } else + FURI_LOG_D(TAG, "No relocation index"); /* Not an error */ + return true; +} + +FlipperApplicationLoadStatus flipper_application_load_sections(FlipperApplication* e) { + FlipperApplicationLoadStatus status = FlipperApplicationLoadStatusSuccess; + RelocationAddressCache_init(e->relocation_cache); + size_t start = furi_get_tick(); + + struct { + ELFSection_t* section; + const char* name; + } sections[] = { + {&e->text, ".text"}, + {&e->rodata, ".rodata"}, + {&e->data, ".data"}, + {&e->bss, ".bss"}, + }; + + for(size_t i = 0; i < COUNT_OF(sections); i++) { + if(!flipper_application_load_section_data(e, sections[i].section)) { + FURI_LOG_E(TAG, "Error loading section '%s'", sections[i].name); + status = FlipperApplicationLoadStatusUnspecifiedError; + } + } + + if(status == FlipperApplicationLoadStatusSuccess) { + for(size_t i = 0; i < COUNT_OF(sections); i++) { + if(!flipper_application_relocate_section(e, sections[i].section)) { + FURI_LOG_E(TAG, "Error relocating section '%s'", sections[i].name); + status = FlipperApplicationLoadStatusMissingImports; + } + } + } + + if(status == FlipperApplicationLoadStatusSuccess) { + e->state.mmap_entries = + malloc(sizeof(FlipperApplicationMemoryMapEntry) * e->state.mmap_entry_count); + uint32_t mmap_entry_idx = 0; + for(size_t i = 0; i < COUNT_OF(sections); i++) { + const void* data_ptr = sections[i].section->data; + if(data_ptr) { + FURI_LOG_I(TAG, "0x%X %s", (uint32_t)data_ptr, sections[i].name); + e->state.mmap_entries[mmap_entry_idx].address = (uint32_t)data_ptr; + e->state.mmap_entries[mmap_entry_idx].name = sections[i].name; + mmap_entry_idx++; + } + } + furi_check(mmap_entry_idx == e->state.mmap_entry_count); + + /* Fixing up entry point */ + e->entry += (uint32_t)e->text.data; + } + + FURI_LOG_D(TAG, "Relocation cache size: %u", RelocationAddressCache_size(e->relocation_cache)); + RelocationAddressCache_clear(e->relocation_cache); + FURI_LOG_I(TAG, "Loaded in %ums", (size_t)(furi_get_tick() - start)); + + return status; +} + +void flipper_application_free_section(ELFSection_t* s) { + if(s->data) { + aligned_free(s->data); + } + s->data = NULL; +} diff --git a/lib/flipper_application/flipper_application.c b/lib/flipper_application/flipper_application.c new file mode 100644 index 000000000..6e84cce38 --- /dev/null +++ b/lib/flipper_application/flipper_application.c @@ -0,0 +1,131 @@ +#include "flipper_application.h" +#include "flipper_application_i.h" + +#define TAG "fapp" + +/* For debugger access to app state */ +FlipperApplication* last_loaded_app = NULL; + +FlipperApplication* + flipper_application_alloc(Storage* storage, const ElfApiInterface* api_interface) { + FlipperApplication* app = malloc(sizeof(FlipperApplication)); + app->api_interface = api_interface; + app->fd = storage_file_alloc(storage); + app->thread = NULL; + return app; +} + +void flipper_application_free(FlipperApplication* app) { + furi_assert(app); + + if(app->thread) { + furi_thread_join(app->thread); + furi_thread_free(app->thread); + } + + last_loaded_app = NULL; + + if(app->state.debug_link_size) { + free(app->state.debug_link); + } + + if(app->state.mmap_entries) { + free(app->state.mmap_entries); + } + + ELFSection_t* sections[] = {&app->text, &app->rodata, &app->data, &app->bss}; + for(size_t i = 0; i < COUNT_OF(sections); i++) { + flipper_application_free_section(sections[i]); + } + + storage_file_free(app->fd); + + free(app); +} + +/* Parse headers, load manifest */ +FlipperApplicationPreloadStatus + flipper_application_preload(FlipperApplication* app, const char* path) { + if(!flipper_application_load_elf_headers(app, path) || + !flipper_application_load_section_table(app)) { + return FlipperApplicationPreloadStatusInvalidFile; + } + + if((app->manifest.base.manifest_magic != FAP_MANIFEST_MAGIC) && + (app->manifest.base.manifest_version == FAP_MANIFEST_SUPPORTED_VERSION)) { + return FlipperApplicationPreloadStatusInvalidManifest; + } + + if(app->manifest.base.api_version.major != app->api_interface->api_version_major /* || + app->manifest.base.api_version.minor > app->api_interface->api_version_minor */) { + return FlipperApplicationPreloadStatusApiMismatch; + } + + return FlipperApplicationPreloadStatusSuccess; +} + +const FlipperApplicationManifest* flipper_application_get_manifest(FlipperApplication* app) { + return &app->manifest; +} + +FlipperApplicationLoadStatus flipper_application_map_to_memory(FlipperApplication* app) { + last_loaded_app = app; + return flipper_application_load_sections(app); +} + +const FlipperApplicationState* flipper_application_get_state(FlipperApplication* app) { + return &app->state; +} + +FuriThread* flipper_application_spawn(FlipperApplication* app, void* args) { + furi_check(app->thread == NULL); + + const FlipperApplicationManifest* manifest = flipper_application_get_manifest(app); + furi_check(manifest->stack_size > 0); + + app->thread = furi_thread_alloc(); + furi_thread_set_stack_size(app->thread, manifest->stack_size); + furi_thread_set_name(app->thread, manifest->name); + furi_thread_set_callback(app->thread, (entry_t*)app->entry); + furi_thread_set_context(app->thread, args); + + return app->thread; +} + +FuriThread* flipper_application_get_thread(FlipperApplication* app) { + return app->thread; +} + +void const* flipper_application_get_entry_address(FlipperApplication* app) { + return (void*)app->entry; +} + +static const char* preload_status_strings[] = { + [FlipperApplicationPreloadStatusSuccess] = "Success", + [FlipperApplicationPreloadStatusUnspecifiedError] = "Unknown error", + [FlipperApplicationPreloadStatusInvalidFile] = "Invalid file", + [FlipperApplicationPreloadStatusInvalidManifest] = "Invalid file manifest", + [FlipperApplicationPreloadStatusApiMismatch] = "API version mismatch", + [FlipperApplicationPreloadStatusTargetMismatch] = "Hardware target mismatch", +}; + +static const char* load_status_strings[] = { + [FlipperApplicationLoadStatusSuccess] = "Success", + [FlipperApplicationLoadStatusUnspecifiedError] = "Unknown error", + [FlipperApplicationLoadStatusNoFreeMemory] = "Out of memory", + [FlipperApplicationLoadStatusMissingImports] = "Found unsatisfied imports", +}; + +const char* flipper_application_preload_status_to_string(FlipperApplicationPreloadStatus status) { + if(status >= COUNT_OF(preload_status_strings) || preload_status_strings[status] == NULL) { + return "Unknown error"; + } + return preload_status_strings[status]; +} + +const char* flipper_application_load_status_to_string(FlipperApplicationLoadStatus status) { + if(status >= COUNT_OF(load_status_strings) || load_status_strings[status] == NULL) { + return "Unknown error"; + } + return load_status_strings[status]; +} diff --git a/lib/flipper_application/flipper_application.h b/lib/flipper_application/flipper_application.h new file mode 100644 index 000000000..34de40388 --- /dev/null +++ b/lib/flipper_application/flipper_application.h @@ -0,0 +1,129 @@ +#pragma once + +#include "application_manifest.h" +#include "elf/elf_api_interface.h" + +#include +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + FlipperApplicationPreloadStatusSuccess = 0, + FlipperApplicationPreloadStatusUnspecifiedError, + FlipperApplicationPreloadStatusInvalidFile, + FlipperApplicationPreloadStatusInvalidManifest, + FlipperApplicationPreloadStatusApiMismatch, + FlipperApplicationPreloadStatusTargetMismatch, +} FlipperApplicationPreloadStatus; + +typedef enum { + FlipperApplicationLoadStatusSuccess = 0, + FlipperApplicationLoadStatusUnspecifiedError, + FlipperApplicationLoadStatusNoFreeMemory, + FlipperApplicationLoadStatusMissingImports, +} FlipperApplicationLoadStatus; + +/** + * @brief Get text description of preload status + * @param status Status code + * @return String pointer to description + */ +const char* flipper_application_preload_status_to_string(FlipperApplicationPreloadStatus status); + +/** + * @brief Get text description of load status + * @param status Status code + * @return String pointer to description + */ +const char* flipper_application_load_status_to_string(FlipperApplicationLoadStatus status); + +typedef struct FlipperApplication FlipperApplication; + +typedef struct { + const char* name; + uint32_t address; +} FlipperApplicationMemoryMapEntry; + +typedef struct { + uint32_t mmap_entry_count; + FlipperApplicationMemoryMapEntry* mmap_entries; + uint32_t debug_link_size; + uint8_t* debug_link; +} FlipperApplicationState; + +/** + * @brief Initialize FlipperApplication object + * @param storage Storage instance + * @param api_interface ELF API interface to use for pre-loading and symbol resolving + * @return Application instance + */ +FlipperApplication* + flipper_application_alloc(Storage* storage, const ElfApiInterface* api_interface); + +/** + * @brief Destroy FlipperApplication object + * @param app Application pointer + */ +void flipper_application_free(FlipperApplication* app); + +/** + * @brief Validate elf file and load application metadata + * @param app Application pointer + * @return Preload result code + */ +FlipperApplicationPreloadStatus + flipper_application_preload(FlipperApplication* app, const char* path); + +/** + * @brief Get pointer to application manifest for preloaded application + * @param app Application pointer + * @return Pointer to application manifest + */ +const FlipperApplicationManifest* flipper_application_get_manifest(FlipperApplication* app); + +/** + * @brief Load sections and process relocations for already pre-loaded application + * @param app Application pointer + * @return Load result code + */ +FlipperApplicationLoadStatus flipper_application_map_to_memory(FlipperApplication* app); + +/** + * @brief Get state object for loaded application + * @param app Application pointer + * @return Pointer to state object + */ +const FlipperApplicationState* flipper_application_get_state(FlipperApplication* app); + +/** + * @brief Create application thread at entry point address, using app name and + * stack size from metadata. Returned thread isn't started yet. + * Can be only called once for application instance. + * @param app Applicaiton pointer + * @param args Object to pass to app's entry point + * @return Created thread + */ +FuriThread* flipper_application_spawn(FlipperApplication* app, void* args); + +/** + * @brief Get previously spawned thread + * @param app Application pointer + * @return Created thread + */ +FuriThread* flipper_application_get_thread(FlipperApplication* app); + +/** + * @brief Return relocated and valid address of app's entry point + * @param app Application pointer + * @return Address of app's entry point + */ +void const* flipper_application_get_entry_address(FlipperApplication* app); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/lib/flipper_application/flipper_application_i.h b/lib/flipper_application/flipper_application_i.h new file mode 100644 index 000000000..8adf5c0d2 --- /dev/null +++ b/lib/flipper_application/flipper_application_i.h @@ -0,0 +1,99 @@ +#pragma once + +#include "elf.h" +#include "flipper_application.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +DICT_DEF2(RelocationAddressCache, int, M_DEFAULT_OPLIST, Elf32_Addr, M_DEFAULT_OPLIST) + +/** + * Callable elf entry type + */ +typedef int32_t(entry_t)(void*); + +typedef struct { + void* data; + uint16_t sec_idx; + uint16_t rel_sec_idx; +} ELFSection_t; + +struct FlipperApplication { + const ElfApiInterface* api_interface; + File* fd; + FlipperApplicationState state; + FlipperApplicationManifest manifest; + + size_t sections; + off_t section_table; + off_t section_table_strings; + + size_t symbol_count; + off_t symbol_table; + off_t symbol_table_strings; + off_t entry; + + ELFSection_t text; + ELFSection_t rodata; + ELFSection_t data; + ELFSection_t bss; + + FuriThread* thread; + RelocationAddressCache_t relocation_cache; +}; + +typedef enum { + FoundERROR = 0, + FoundSymTab = (1 << 0), + FoundStrTab = (1 << 2), + FoundText = (1 << 3), + FoundRodata = (1 << 4), + FoundData = (1 << 5), + FoundBss = (1 << 6), + FoundRelText = (1 << 7), + FoundRelRodata = (1 << 8), + FoundRelData = (1 << 9), + FoundRelBss = (1 << 10), + FoundFappManifest = (1 << 11), + FoundDebugLink = (1 << 12), + FoundValid = FoundSymTab | FoundStrTab | FoundFappManifest, + FoundExec = FoundValid | FoundText, + FoundGdbSection = FoundText | FoundRodata | FoundData | FoundBss, + FoundAll = FoundSymTab | FoundStrTab | FoundText | FoundRodata | FoundData | FoundBss | + FoundRelText | FoundRelRodata | FoundRelData | FoundRelBss | FoundDebugLink, +} FindFlags_t; + +/** + * @brief Load and validate basic ELF file headers + * @param e Application instance + * @param path FS path to application file + * @return true if ELF file is valid + */ +bool flipper_application_load_elf_headers(FlipperApplication* e, const char* path); + +/** + * @brief Iterate over all sections and save related indexes + * @param e Application instance + * @return true if all required sections are found + */ +bool flipper_application_load_section_table(FlipperApplication* e); + +/** + * @brief Load section data to memory and process relocations + * @param e Application instance + * @return Status code + */ +FlipperApplicationLoadStatus flipper_application_load_sections(FlipperApplication* e); + +/** + * @brief Release section data + * @param s section pointer + */ +void flipper_application_free_section(ELFSection_t* s); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/lib/flipper_format/SConscript b/lib/flipper_format/SConscript index e5d61a075..5e185678b 100644 --- a/lib/flipper_format/SConscript +++ b/lib/flipper_format/SConscript @@ -4,6 +4,10 @@ env.Append( CPPPATH=[ "#/lib/flipper_format", ], + SDK_HEADERS=[ + File("#/lib/flipper_format/flipper_format.h"), + File("#/lib/flipper_format/flipper_format_i.h"), + ], ) diff --git a/lib/flipper_format/flipper_format_stream.c b/lib/flipper_format/flipper_format_stream.c index 81189b69b..e4b7b3003 100644 --- a/lib/flipper_format/flipper_format_stream.c +++ b/lib/flipper_format/flipper_format_stream.c @@ -356,7 +356,7 @@ bool flipper_format_stream_read_value_line( uint8_t* data = _data; if(string_size(value) >= 2) { // sscanf "%02X" does not work here - if(hex_chars_to_uint8( + if(hex_char_to_uint8( string_get_char(value, 0), string_get_char(value, 1), &data[i])) { diff --git a/lib/lfrfid/SConscript b/lib/lfrfid/SConscript index 8d3542883..fd29ca2ef 100644 --- a/lib/lfrfid/SConscript +++ b/lib/lfrfid/SConscript @@ -7,6 +7,14 @@ env.Append( CPPPATH=[ "#/lib/lfrfid", ], + SDK_HEADERS=[ + File("#/lib/lfrfid/lfrfid_worker.h"), + File("#/lib/lfrfid/lfrfid_raw_worker.h"), + File("#/lib/lfrfid/lfrfid_raw_file.h"), + File("#/lib/lfrfid/lfrfid_dict_file.h"), + File("#/lib/lfrfid/tools/bit_lib.h"), + File("#/lib/lfrfid/protocols/lfrfid_protocols.h"), + ], ) libenv = env.Clone(FW_LIB_NAME="lfrfid") diff --git a/lib/lfrfid/lfrfid_worker_modes.c b/lib/lfrfid/lfrfid_worker_modes.c index f41a7194a..16936cca1 100644 --- a/lib/lfrfid/lfrfid_worker_modes.c +++ b/lib/lfrfid/lfrfid_worker_modes.c @@ -27,16 +27,16 @@ #define LFRFID_WORKER_READ_DROP_TIME_MS 50 #define LFRFID_WORKER_READ_STABILIZE_TIME_MS 450 -#define LFRFID_WORKER_READ_SWITCH_TIME_MS 1500 +#define LFRFID_WORKER_READ_SWITCH_TIME_MS 2000 -#define LFRFID_WORKER_WRITE_VERIFY_TIME_MS 1500 +#define LFRFID_WORKER_WRITE_VERIFY_TIME_MS 2000 #define LFRFID_WORKER_WRITE_DROP_TIME_MS 50 #define LFRFID_WORKER_WRITE_TOO_LONG_TIME_MS 10000 #define LFRFID_WORKER_WRITE_MAX_UNSUCCESSFUL_READS 5 #define LFRFID_WORKER_READ_BUFFER_SIZE 512 -#define LFRFID_WORKER_READ_BUFFER_COUNT 8 +#define LFRFID_WORKER_READ_BUFFER_COUNT 16 #define LFRFID_WORKER_EMULATE_BUFFER_SIZE 1024 @@ -132,6 +132,8 @@ static LFRFIDWorkerReadState lfrfid_worker_read_internal( #ifdef LFRFID_WORKER_READ_DEBUG_GPIO furi_hal_gpio_init_simple(LFRFID_WORKER_READ_DEBUG_GPIO_VALUE, GpioModeOutputPushPull); furi_hal_gpio_init_simple(LFRFID_WORKER_READ_DEBUG_GPIO_LOAD, GpioModeOutputPushPull); + furi_hal_gpio_write(LFRFID_WORKER_READ_DEBUG_GPIO_VALUE, false); + furi_hal_gpio_write(LFRFID_WORKER_READ_DEBUG_GPIO_LOAD, false); #endif LFRFIDWorkerReadContext ctx; @@ -171,10 +173,16 @@ static LFRFIDWorkerReadState lfrfid_worker_read_internal( if(buffer_stream_get_overrun_count(ctx.stream) > 0) { FURI_LOG_E(TAG, "Read overrun, recovering"); buffer_stream_reset(ctx.stream); +#ifdef LFRFID_WORKER_READ_DEBUG_GPIO + furi_hal_gpio_write(LFRFID_WORKER_READ_DEBUG_GPIO_LOAD, false); +#endif continue; } if(buffer == NULL) { +#ifdef LFRFID_WORKER_READ_DEBUG_GPIO + furi_hal_gpio_write(LFRFID_WORKER_READ_DEBUG_GPIO_LOAD, false); +#endif continue; } @@ -261,24 +269,26 @@ static LFRFIDWorkerReadState lfrfid_worker_read_internal( last_read_count = 0; } - string_t string_info; - string_init(string_info); - for(uint8_t i = 0; i < protocol_data_size; i++) { - if(i != 0) { - string_cat_printf(string_info, " "); + if(furi_log_get_level() >= FuriLogLevelDebug) { + string_t string_info; + string_init(string_info); + for(uint8_t i = 0; i < protocol_data_size; i++) { + if(i != 0) { + string_cat_printf(string_info, " "); + } + + string_cat_printf(string_info, "%02X", protocol_data[i]); } - string_cat_printf(string_info, "%02X", protocol_data[i]); + FURI_LOG_D( + TAG, + "%s, %d, [%s]", + protocol_dict_get_name(worker->protocols, protocol), + last_read_count, + string_get_cstr(string_info)); + string_clear(string_info); } - FURI_LOG_D( - TAG, - "%s, %d, [%s]", - protocol_dict_get_name(worker->protocols, protocol), - last_read_count, - string_get_cstr(string_info)); - string_clear(string_info); - protocol_dict_decoders_start(worker->protocols); } } @@ -321,6 +331,8 @@ static LFRFIDWorkerReadState lfrfid_worker_read_internal( free(last_data); #ifdef LFRFID_WORKER_READ_DEBUG_GPIO + furi_hal_gpio_write(LFRFID_WORKER_READ_DEBUG_GPIO_VALUE, false); + furi_hal_gpio_write(LFRFID_WORKER_READ_DEBUG_GPIO_LOAD, false); furi_hal_gpio_init_simple(LFRFID_WORKER_READ_DEBUG_GPIO_VALUE, GpioModeAnalog); furi_hal_gpio_init_simple(LFRFID_WORKER_READ_DEBUG_GPIO_LOAD, GpioModeAnalog); #endif @@ -522,9 +534,17 @@ static void lfrfid_worker_mode_write_process(LFRFIDWorker* worker) { &read_result); if(state == LFRFIDWorkerReadOK) { - protocol_dict_get_data(worker->protocols, protocol, read_data, data_size); + bool read_success = false; - if(memcmp(read_data, verify_data, data_size) == 0) { + if(read_result == protocol) { + protocol_dict_get_data(worker->protocols, protocol, read_data, data_size); + + if(memcmp(read_data, verify_data, data_size) == 0) { + read_success = true; + } + } + + if(read_success) { if(worker->write_cb) { worker->write_cb(LFRFIDWorkerWriteOK, worker->cb_ctx); } diff --git a/lib/lfrfid/protocols/lfrfid_protocols.c b/lib/lfrfid/protocols/lfrfid_protocols.c index 5df01b19e..bd29bd8e0 100644 --- a/lib/lfrfid/protocols/lfrfid_protocols.c +++ b/lib/lfrfid/protocols/lfrfid_protocols.c @@ -8,6 +8,13 @@ #include "protocol_fdx_b.h" #include "protocol_hid_generic.h" #include "protocol_hid_ex_generic.h" +#include "protocol_pyramid.h" +#include "protocol_viking.h" +#include "protocol_jablotron.h" +#include "protocol_paradox.h" +#include "protocol_pac_stanley.h" +#include "protocol_keri.h" +#include "protocol_gallagher.h" const ProtocolBase* lfrfid_protocols[] = { [LFRFIDProtocolEM4100] = &protocol_em4100, @@ -19,4 +26,11 @@ const ProtocolBase* lfrfid_protocols[] = { [LFRFIDProtocolFDXB] = &protocol_fdx_b, [LFRFIDProtocolHidGeneric] = &protocol_hid_generic, [LFRFIDProtocolHidExGeneric] = &protocol_hid_ex_generic, + [LFRFIDProtocolPyramid] = &protocol_pyramid, + [LFRFIDProtocolViking] = &protocol_viking, + [LFRFIDProtocolJablotron] = &protocol_jablotron, + [LFRFIDProtocolParadox] = &protocol_paradox, + [LFRFIDProtocolPACStanley] = &protocol_pac_stanley, + [LFRFIDProtocolKeri] = &protocol_keri, + [LFRFIDProtocolGallagher] = &protocol_gallagher, }; \ No newline at end of file diff --git a/lib/lfrfid/protocols/lfrfid_protocols.h b/lib/lfrfid/protocols/lfrfid_protocols.h index 4b8f6573d..26065c9aa 100644 --- a/lib/lfrfid/protocols/lfrfid_protocols.h +++ b/lib/lfrfid/protocols/lfrfid_protocols.h @@ -17,7 +17,13 @@ typedef enum { LFRFIDProtocolFDXB, LFRFIDProtocolHidGeneric, LFRFIDProtocolHidExGeneric, - + LFRFIDProtocolPyramid, + LFRFIDProtocolViking, + LFRFIDProtocolJablotron, + LFRFIDProtocolParadox, + LFRFIDProtocolPACStanley, + LFRFIDProtocolKeri, + LFRFIDProtocolGallagher, LFRFIDProtocolMax, } LFRFIDProtocol; diff --git a/lib/lfrfid/protocols/protocol_awid.c b/lib/lfrfid/protocols/protocol_awid.c index 243b5edeb..7131d30dc 100644 --- a/lib/lfrfid/protocols/protocol_awid.c +++ b/lib/lfrfid/protocols/protocol_awid.c @@ -53,7 +53,7 @@ void protocol_awid_decoder_start(ProtocolAwid* protocol) { memset(protocol->encoded_data, 0, AWID_ENCODED_DATA_SIZE); }; -static bool protocol_awid_can_be_decoded(const uint8_t* data) { +static bool protocol_awid_can_be_decoded(uint8_t* data) { bool result = false; // Index map @@ -77,6 +77,12 @@ static bool protocol_awid_can_be_decoded(const uint8_t* data) { bool parity_error = bit_lib_test_parity(data, 8, 88, BitLibParityOdd, 4); if(parity_error) break; + bit_lib_remove_bit_every_nth(data, 8, 88, 4); + + // Avoid detection for invalid formats + uint8_t len = bit_lib_get_bits(data, 8, 8); + if(len != 26 && len != 50 && len != 37 && len != 34) break; + result = true; } while(false); @@ -84,7 +90,6 @@ static bool protocol_awid_can_be_decoded(const uint8_t* data) { } static void protocol_awid_decode(uint8_t* encoded_data, uint8_t* decoded_data) { - bit_lib_remove_bit_every_nth(encoded_data, 8, 88, 4); bit_lib_copy_bits(decoded_data, 0, 66, encoded_data, 8); } @@ -200,6 +205,10 @@ bool protocol_awid_write_data(ProtocolAwid* protocol, void* data) { LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data; bool result = false; + // Correct protocol data by redecoding + protocol_awid_encode(protocol->data, (uint8_t*)protocol->encoded_data); + protocol_awid_decode(protocol->encoded_data, protocol->data); + protocol_awid_encode(protocol->data, (uint8_t*)protocol->encoded_data); if(request->write_type == LFRFIDWriteTypeT5577) { diff --git a/lib/lfrfid/protocols/protocol_em4100.c b/lib/lfrfid/protocols/protocol_em4100.c index 92721fcdc..6959f753b 100644 --- a/lib/lfrfid/protocols/protocol_em4100.c +++ b/lib/lfrfid/protocols/protocol_em4100.c @@ -248,6 +248,14 @@ bool protocol_em4100_write_data(ProtocolEM4100* protocol, void* data) { LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data; bool result = false; + // Correct protocol data by redecoding + protocol_em4100_encoder_start(protocol); + em4100_decode( + (uint8_t*)&protocol->encoded_data, + sizeof(EM4100DecodedData), + protocol->data, + EM4100_DECODED_DATA_SIZE); + protocol_em4100_encoder_start(protocol); if(request->write_type == LFRFIDWriteTypeT5577) { @@ -264,7 +272,7 @@ bool protocol_em4100_write_data(ProtocolEM4100* protocol, void* data) { void protocol_em4100_render_data(ProtocolEM4100* protocol, string_t result) { uint8_t* data = protocol->data; - string_printf(result, "ID: %03u,%05u", data[2], (uint16_t)((data[3] << 8) | (data[4]))); + string_printf(result, "FC: %03u, Card: %05u", data[2], (uint16_t)((data[3] << 8) | (data[4]))); }; const ProtocolBase protocol_em4100 = { diff --git a/lib/lfrfid/protocols/protocol_fdx_a.c b/lib/lfrfid/protocols/protocol_fdx_a.c index 23f9e2857..554b9071e 100644 --- a/lib/lfrfid/protocols/protocol_fdx_a.c +++ b/lib/lfrfid/protocols/protocol_fdx_a.c @@ -178,6 +178,10 @@ bool protocol_fdx_a_write_data(ProtocolFDXA* protocol, void* data) { LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data; bool result = false; + // Correct protocol data by redecoding + protocol_fdx_a_encoder_start(protocol); + protocol_fdx_a_decode(protocol->encoded_data, protocol->data); + protocol_fdx_a_encoder_start(protocol); if(request->write_type == LFRFIDWriteTypeT5577) { diff --git a/lib/lfrfid/protocols/protocol_fdx_b.c b/lib/lfrfid/protocols/protocol_fdx_b.c index f68a884e8..f42b4ed93 100644 --- a/lib/lfrfid/protocols/protocol_fdx_b.c +++ b/lib/lfrfid/protocols/protocol_fdx_b.c @@ -334,6 +334,10 @@ bool protocol_fdx_b_write_data(ProtocolFDXB* protocol, void* data) { LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data; bool result = false; + // Correct protocol data by redecoding + protocol_fdx_b_encoder_start(protocol); + protocol_fdx_b_decode(protocol); + protocol_fdx_b_encoder_start(protocol); if(request->write_type == LFRFIDWriteTypeT5577) { diff --git a/lib/lfrfid/protocols/protocol_gallagher.c b/lib/lfrfid/protocols/protocol_gallagher.c new file mode 100644 index 000000000..5d8245301 --- /dev/null +++ b/lib/lfrfid/protocols/protocol_gallagher.c @@ -0,0 +1,304 @@ +#include +#include +#include +#include +#include "lfrfid_protocols.h" + +#define GALLAGHER_CLOCK_PER_BIT (32) + +#define GALLAGHER_ENCODED_BIT_SIZE (96) +#define GALLAGHER_ENCODED_BYTE_SIZE ((GALLAGHER_ENCODED_BIT_SIZE) / 8) +#define GALLAGHER_PREAMBLE_BIT_SIZE (16) +#define GALLAGHER_PREAMBLE_BYTE_SIZE ((GALLAGHER_PREAMBLE_BIT_SIZE) / 8) +#define GALLAGHER_ENCODED_BYTE_FULL_SIZE \ + (GALLAGHER_ENCODED_BYTE_SIZE + GALLAGHER_PREAMBLE_BYTE_SIZE) +#define GALLAGHER_DECODED_DATA_SIZE 8 + +#define GALLAGHER_READ_SHORT_TIME (128) +#define GALLAGHER_READ_LONG_TIME (256) +#define GALLAGHER_READ_JITTER_TIME (60) + +#define GALLAGHER_READ_SHORT_TIME_LOW (GALLAGHER_READ_SHORT_TIME - GALLAGHER_READ_JITTER_TIME) +#define GALLAGHER_READ_SHORT_TIME_HIGH (GALLAGHER_READ_SHORT_TIME + GALLAGHER_READ_JITTER_TIME) +#define GALLAGHER_READ_LONG_TIME_LOW (GALLAGHER_READ_LONG_TIME - GALLAGHER_READ_JITTER_TIME) +#define GALLAGHER_READ_LONG_TIME_HIGH (GALLAGHER_READ_LONG_TIME + GALLAGHER_READ_JITTER_TIME) + +typedef struct { + uint8_t data[GALLAGHER_DECODED_DATA_SIZE]; + uint8_t encoded_data[GALLAGHER_ENCODED_BYTE_FULL_SIZE]; + + uint8_t encoded_data_index; + bool encoded_polarity; + + ManchesterState decoder_manchester_state; +} ProtocolGallagher; + +ProtocolGallagher* protocol_gallagher_alloc(void) { + ProtocolGallagher* proto = malloc(sizeof(ProtocolGallagher)); + return (void*)proto; +}; + +void protocol_gallagher_free(ProtocolGallagher* protocol) { + free(protocol); +}; + +uint8_t* protocol_gallagher_get_data(ProtocolGallagher* protocol) { + return protocol->data; +}; + +static void protocol_gallagher_scramble(uint8_t* data, size_t length) { + const uint8_t lut[] = { + 0xa3, 0xb0, 0x80, 0xc6, 0xb2, 0xf4, 0x5c, 0x6c, 0x81, 0xf1, 0xbb, 0xeb, 0x55, 0x67, 0x3c, + 0x05, 0x1a, 0x0e, 0x61, 0xf6, 0x22, 0xce, 0xaa, 0x8f, 0xbd, 0x3b, 0x1f, 0x5e, 0x44, 0x04, + 0x51, 0x2e, 0x4d, 0x9a, 0x84, 0xea, 0xf8, 0x66, 0x74, 0x29, 0x7f, 0x70, 0xd8, 0x31, 0x7a, + 0x6d, 0xa4, 0x00, 0x82, 0xb9, 0x5f, 0xb4, 0x16, 0xab, 0xff, 0xc2, 0x39, 0xdc, 0x19, 0x65, + 0x57, 0x7c, 0x20, 0xfa, 0x5a, 0x49, 0x13, 0xd0, 0xfb, 0xa8, 0x91, 0x73, 0xb1, 0x33, 0x18, + 0xbe, 0x21, 0x72, 0x48, 0xb6, 0xdb, 0xa0, 0x5d, 0xcc, 0xe6, 0x17, 0x27, 0xe5, 0xd4, 0x53, + 0x42, 0xf3, 0xdd, 0x7b, 0x24, 0xac, 0x2b, 0x58, 0x1e, 0xa7, 0xe7, 0x86, 0x40, 0xd3, 0x98, + 0x97, 0x71, 0xcb, 0x3a, 0x0f, 0x01, 0x9b, 0x6e, 0x1b, 0xfc, 0x34, 0xa6, 0xda, 0x07, 0x0c, + 0xae, 0x37, 0xca, 0x54, 0xfd, 0x26, 0xfe, 0x0a, 0x45, 0xa2, 0x2a, 0xc4, 0x12, 0x0d, 0xf5, + 0x4f, 0x69, 0xe0, 0x8a, 0x77, 0x60, 0x3f, 0x99, 0x95, 0xd2, 0x38, 0x36, 0x62, 0xb7, 0x32, + 0x7e, 0x79, 0xc0, 0x46, 0x93, 0x2f, 0xa5, 0xba, 0x5b, 0xaf, 0x52, 0x1d, 0xc3, 0x75, 0xcf, + 0xd6, 0x4c, 0x83, 0xe8, 0x3d, 0x30, 0x4e, 0xbc, 0x08, 0x2d, 0x09, 0x06, 0xd9, 0x25, 0x9e, + 0x89, 0xf2, 0x96, 0x88, 0xc1, 0x8c, 0x94, 0x0b, 0x28, 0xf0, 0x47, 0x63, 0xd5, 0xb3, 0x68, + 0x56, 0x9c, 0xf9, 0x6f, 0x41, 0x50, 0x85, 0x8b, 0x9d, 0x59, 0xbf, 0x9f, 0xe2, 0x8e, 0x6a, + 0x11, 0x23, 0xa1, 0xcd, 0xb5, 0x7d, 0xc7, 0xa9, 0xc8, 0xef, 0xdf, 0x02, 0xb8, 0x03, 0x6b, + 0x35, 0x3e, 0x2c, 0x76, 0xc9, 0xde, 0x1c, 0x4b, 0xd1, 0xed, 0x14, 0xc5, 0xad, 0xe9, 0x64, + 0x4a, 0xec, 0x8d, 0xf7, 0x10, 0x43, 0x78, 0x15, 0x87, 0xe4, 0xd7, 0x92, 0xe1, 0xee, 0xe3, + 0x90}; + for(size_t i = 0; i < length; i++) { + data[i] = lut[data[i]]; + } +} + +static void protocol_gallagher_descramble(uint8_t* data, size_t length) { + const uint8_t lut[] = { + 0x2f, 0x6e, 0xdd, 0xdf, 0x1d, 0x0f, 0xb0, 0x76, 0xad, 0xaf, 0x7f, 0xbb, 0x77, 0x85, 0x11, + 0x6d, 0xf4, 0xd2, 0x84, 0x42, 0xeb, 0xf7, 0x34, 0x55, 0x4a, 0x3a, 0x10, 0x71, 0xe7, 0xa1, + 0x62, 0x1a, 0x3e, 0x4c, 0x14, 0xd3, 0x5e, 0xb2, 0x7d, 0x56, 0xbc, 0x27, 0x82, 0x60, 0xe3, + 0xae, 0x1f, 0x9b, 0xaa, 0x2b, 0x95, 0x49, 0x73, 0xe1, 0x92, 0x79, 0x91, 0x38, 0x6c, 0x19, + 0x0e, 0xa9, 0xe2, 0x8d, 0x66, 0xc7, 0x5a, 0xf5, 0x1c, 0x80, 0x99, 0xbe, 0x4e, 0x41, 0xf0, + 0xe8, 0xa6, 0x20, 0xab, 0x87, 0xc8, 0x1e, 0xa0, 0x59, 0x7b, 0x0c, 0xc3, 0x3c, 0x61, 0xcc, + 0x40, 0x9e, 0x06, 0x52, 0x1b, 0x32, 0x8c, 0x12, 0x93, 0xbf, 0xef, 0x3b, 0x25, 0x0d, 0xc2, + 0x88, 0xd1, 0xe0, 0x07, 0x2d, 0x70, 0xc6, 0x29, 0x6a, 0x4d, 0x47, 0x26, 0xa3, 0xe4, 0x8b, + 0xf6, 0x97, 0x2c, 0x5d, 0x3d, 0xd7, 0x96, 0x28, 0x02, 0x08, 0x30, 0xa7, 0x22, 0xc9, 0x65, + 0xf8, 0xb7, 0xb4, 0x8a, 0xca, 0xb9, 0xf2, 0xd0, 0x17, 0xff, 0x46, 0xfb, 0x9a, 0xba, 0x8f, + 0xb6, 0x69, 0x68, 0x8e, 0x21, 0x6f, 0xc4, 0xcb, 0xb3, 0xce, 0x51, 0xd4, 0x81, 0x00, 0x2e, + 0x9c, 0x74, 0x63, 0x45, 0xd9, 0x16, 0x35, 0x5f, 0xed, 0x78, 0x9f, 0x01, 0x48, 0x04, 0xc1, + 0x33, 0xd6, 0x4f, 0x94, 0xde, 0x31, 0x9d, 0x0a, 0xac, 0x18, 0x4b, 0xcd, 0x98, 0xb8, 0x37, + 0xa2, 0x83, 0xec, 0x03, 0xd8, 0xda, 0xe5, 0x7a, 0x6b, 0x53, 0xd5, 0x15, 0xa4, 0x43, 0xe9, + 0x90, 0x67, 0x58, 0xc0, 0xa5, 0xfa, 0x2a, 0xb1, 0x75, 0x50, 0x39, 0x5c, 0xe6, 0xdc, 0x89, + 0xfc, 0xcf, 0xfe, 0xf9, 0x57, 0x54, 0x64, 0xa8, 0xee, 0x23, 0x0b, 0xf1, 0xea, 0xfd, 0xdb, + 0xbd, 0x09, 0xb5, 0x5b, 0x05, 0x86, 0x13, 0xf3, 0x24, 0xc5, 0x3f, 0x44, 0x72, 0x7c, 0x7e, + 0x36}; + + for(size_t i = 0; i < length; i++) { + data[i] = lut[data[i]]; + } +} + +static void protocol_gallagher_decode(ProtocolGallagher* protocol) { + bit_lib_remove_bit_every_nth(protocol->encoded_data, 16, 9 * 8, 9); + protocol_gallagher_descramble(protocol->encoded_data + 2, 8); + + // Region code + bit_lib_set_bits(protocol->data, 0, (protocol->encoded_data[5] & 0x1E) >> 1, 4); + + // Issue Level + bit_lib_set_bits(protocol->data, 4, (protocol->encoded_data[9] & 0x0F), 4); + + // Facility Code + uint32_t fc = (protocol->encoded_data[7] & 0x0F) << 12 | protocol->encoded_data[3] << 4 | + ((protocol->encoded_data[9] >> 4) & 0x0F); + protocol->data[3] = (uint8_t)fc; + protocol->data[2] = (uint8_t)(fc >>= 8); + protocol->data[1] = (uint8_t)(fc >>= 8); + + // Card Number + uint32_t card = protocol->encoded_data[2] << 16 | (protocol->encoded_data[6] & 0x1F) << 11 | + protocol->encoded_data[4] << 3 | (protocol->encoded_data[5] & 0xE0) >> 5; + protocol->data[7] = (uint8_t)card; + protocol->data[6] = (uint8_t)(card >>= 8); + protocol->data[5] = (uint8_t)(card >>= 8); + protocol->data[4] = (uint8_t)(card >>= 8); +} + +static bool protocol_gallagher_can_be_decoded(ProtocolGallagher* protocol) { + // check 16 bits preamble + if(bit_lib_get_bits_16(protocol->encoded_data, 0, 16) != 0b0111111111101010) return false; + + // check next 16 bits preamble + if(bit_lib_get_bits_16(protocol->encoded_data, 96, 16) != 0b0111111111101010) return false; + + uint8_t checksum_arr[8] = {0}; + for(int i = 0, pos = 0; i < 8; i++) { + // Following the preamble, every 9th bit is a checksum-bit for the preceding byte + pos = 16 + (9 * i); + checksum_arr[i] = bit_lib_get_bits(protocol->encoded_data, pos, 8); + } + uint8_t crc = bit_lib_get_bits(protocol->encoded_data, 16 + (9 * 8), 8); + uint8_t calc_crc = bit_lib_crc8(checksum_arr, 8, 0x7, 0x2c, false, false, 0x00); + + // crc + if(crc != calc_crc) return false; + + return true; +} + +void protocol_gallagher_decoder_start(ProtocolGallagher* protocol) { + memset(protocol->encoded_data, 0, GALLAGHER_ENCODED_BYTE_FULL_SIZE); + manchester_advance( + protocol->decoder_manchester_state, + ManchesterEventReset, + &protocol->decoder_manchester_state, + NULL); +}; + +bool protocol_gallagher_decoder_feed(ProtocolGallagher* protocol, bool level, uint32_t duration) { + bool result = false; + + ManchesterEvent event = ManchesterEventReset; + + if(duration > GALLAGHER_READ_SHORT_TIME_LOW && duration < GALLAGHER_READ_SHORT_TIME_HIGH) { + if(!level) { + event = ManchesterEventShortHigh; + } else { + event = ManchesterEventShortLow; + } + } else if(duration > GALLAGHER_READ_LONG_TIME_LOW && duration < GALLAGHER_READ_LONG_TIME_HIGH) { + if(!level) { + event = ManchesterEventLongHigh; + } else { + event = ManchesterEventLongLow; + } + } + + if(event != ManchesterEventReset) { + bool data; + bool data_ok = manchester_advance( + protocol->decoder_manchester_state, event, &protocol->decoder_manchester_state, &data); + + if(data_ok) { + bit_lib_push_bit(protocol->encoded_data, GALLAGHER_ENCODED_BYTE_FULL_SIZE, data); + + if(protocol_gallagher_can_be_decoded(protocol)) { + protocol_gallagher_decode(protocol); + result = true; + } + } + } + + return result; +}; + +bool protocol_gallagher_encoder_start(ProtocolGallagher* protocol) { + // Preamble + bit_lib_set_bits(protocol->encoded_data, 0, 0b01111111, 8); + bit_lib_set_bits(protocol->encoded_data, 8, 0b11101010, 8); + + uint8_t rc = bit_lib_get_bits(protocol->data, 0, 4); + uint8_t il = bit_lib_get_bits(protocol->data, 4, 4); + uint32_t fc = bit_lib_get_bits_32(protocol->data, 8, 24); + uint32_t cn = bit_lib_get_bits_32(protocol->data, 32, 32); + + uint8_t payload[8] = {0}; + payload[0] = (cn & 0xffffff) >> 16; + payload[1] = (fc & 0xfff) >> 4; + payload[2] = (cn & 0x7ff) >> 3; + payload[3] = (cn & 0x7) << 5 | (rc & 0xf) << 1; + payload[4] = (cn & 0xffff) >> 11; + payload[5] = (fc & 0xffff) >> 12; + payload[6] = 0; + payload[7] = (fc & 0xf) << 4 | (il & 0xf); + + // Gallagher scramble + protocol_gallagher_scramble(payload, 8); + + for(int i = 0; i < 8; i++) { + // data byte + bit_lib_set_bits(protocol->encoded_data, 16 + (i * 9), payload[i], 8); + + // every byte is followed by a bit which is the inverse of the last bit + bit_lib_set_bit(protocol->encoded_data, 16 + (i * 9) + 8, !(payload[i] & 0x1)); + } + + // checksum + uint8_t crc = bit_lib_crc8(payload, 8, 0x7, 0x2c, false, false, 0x00); + bit_lib_set_bits(protocol->encoded_data, 16 + (9 * 8), crc, 8); + + return true; +}; + +LevelDuration protocol_gallagher_encoder_yield(ProtocolGallagher* protocol) { + bool level = bit_lib_get_bit(protocol->encoded_data, protocol->encoded_data_index); + uint32_t duration = GALLAGHER_CLOCK_PER_BIT / 2; + + if(protocol->encoded_polarity) { + protocol->encoded_polarity = false; + } else { + level = !level; + + protocol->encoded_polarity = true; + bit_lib_increment_index(protocol->encoded_data_index, GALLAGHER_ENCODED_BIT_SIZE); + } + + return level_duration_make(level, duration); +}; + +bool protocol_gallagher_write_data(ProtocolGallagher* protocol, void* data) { + LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data; + bool result = false; + + // Correct protocol data by redecoding + protocol_gallagher_encoder_start(protocol); + protocol_gallagher_decode(protocol); + + protocol_gallagher_encoder_start(protocol); + + if(request->write_type == LFRFIDWriteTypeT5577) { + request->t5577.block[0] = + (LFRFID_T5577_MODULATION_MANCHESTER | LFRFID_T5577_BITRATE_RF_32 | + (3 << LFRFID_T5577_MAXBLOCK_SHIFT)); + request->t5577.block[1] = bit_lib_get_bits_32(protocol->encoded_data, 0, 32); + request->t5577.block[2] = bit_lib_get_bits_32(protocol->encoded_data, 32, 32); + request->t5577.block[3] = bit_lib_get_bits_32(protocol->encoded_data, 64, 32); + request->t5577.blocks_to_write = 4; + result = true; + } + return result; +}; + +void protocol_gallagher_render_data(ProtocolGallagher* protocol, string_t result) { + UNUSED(protocol); + uint8_t rc = bit_lib_get_bits(protocol->data, 0, 4); + uint8_t il = bit_lib_get_bits(protocol->data, 4, 4); + uint32_t fc = bit_lib_get_bits_32(protocol->data, 8, 24); + uint32_t card_id = bit_lib_get_bits_32(protocol->data, 32, 32); + + string_cat_printf(result, "Region: %u, Issue Level: %u\r\n", rc, il); + string_cat_printf(result, "FC: %u, C: %lu\r\n", fc, card_id); +}; + +const ProtocolBase protocol_gallagher = { + .name = "Gallagher", + .manufacturer = "Gallagher", + .data_size = GALLAGHER_DECODED_DATA_SIZE, + .features = LFRFIDFeatureASK, + .validate_count = 3, + .alloc = (ProtocolAlloc)protocol_gallagher_alloc, + .free = (ProtocolFree)protocol_gallagher_free, + .get_data = (ProtocolGetData)protocol_gallagher_get_data, + .decoder = + { + .start = (ProtocolDecoderStart)protocol_gallagher_decoder_start, + .feed = (ProtocolDecoderFeed)protocol_gallagher_decoder_feed, + }, + .encoder = + { + .start = (ProtocolEncoderStart)protocol_gallagher_encoder_start, + .yield = (ProtocolEncoderYield)protocol_gallagher_encoder_yield, + }, + .render_data = (ProtocolRenderData)protocol_gallagher_render_data, + .render_brief_data = (ProtocolRenderData)protocol_gallagher_render_data, + .write_data = (ProtocolWriteData)protocol_gallagher_write_data, +}; \ No newline at end of file diff --git a/lib/lfrfid/protocols/protocol_gallagher.h b/lib/lfrfid/protocols/protocol_gallagher.h new file mode 100644 index 000000000..2d922f605 --- /dev/null +++ b/lib/lfrfid/protocols/protocol_gallagher.h @@ -0,0 +1,4 @@ +#pragma once +#include + +extern const ProtocolBase protocol_gallagher; \ No newline at end of file diff --git a/lib/lfrfid/protocols/protocol_h10301.c b/lib/lfrfid/protocols/protocol_h10301.c index f30f75fac..6c50c667a 100644 --- a/lib/lfrfid/protocols/protocol_h10301.c +++ b/lib/lfrfid/protocols/protocol_h10301.c @@ -337,6 +337,10 @@ bool protocol_h10301_write_data(ProtocolH10301* protocol, void* data) { LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data; bool result = false; + // Correct protocol data by redecoding + protocol_h10301_encoder_start(protocol); + protocol_h10301_decode(protocol->encoded_data, protocol->data); + protocol_h10301_encoder_start(protocol); if(request->write_type == LFRFIDWriteTypeT5577) { diff --git a/lib/lfrfid/protocols/protocol_hid_ex_generic.c b/lib/lfrfid/protocols/protocol_hid_ex_generic.c index e0a852661..17b75528c 100644 --- a/lib/lfrfid/protocols/protocol_hid_ex_generic.c +++ b/lib/lfrfid/protocols/protocol_hid_ex_generic.c @@ -171,6 +171,10 @@ bool protocol_hid_ex_generic_write_data(ProtocolHIDEx* protocol, void* data) { LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data; bool result = false; + // Correct protocol data by redecoding + protocol_hid_ex_generic_encoder_start(protocol); + protocol_hid_ex_generic_decode(protocol->encoded_data, protocol->data); + protocol_hid_ex_generic_encoder_start(protocol); if(request->write_type == LFRFIDWriteTypeT5577) { diff --git a/lib/lfrfid/protocols/protocol_hid_generic.c b/lib/lfrfid/protocols/protocol_hid_generic.c index 2516d6810..da5f5b7c8 100644 --- a/lib/lfrfid/protocols/protocol_hid_generic.c +++ b/lib/lfrfid/protocols/protocol_hid_generic.c @@ -203,6 +203,10 @@ bool protocol_hid_generic_write_data(ProtocolHID* protocol, void* data) { LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data; bool result = false; + // Correct protocol data by redecoding + protocol_hid_generic_encoder_start(protocol); + protocol_hid_generic_decode(protocol->encoded_data, protocol->data); + protocol_hid_generic_encoder_start(protocol); if(request->write_type == LFRFIDWriteTypeT5577) { diff --git a/lib/lfrfid/protocols/protocol_io_prox_xsf.c b/lib/lfrfid/protocols/protocol_io_prox_xsf.c index 66b1610bf..f53eac686 100644 --- a/lib/lfrfid/protocols/protocol_io_prox_xsf.c +++ b/lib/lfrfid/protocols/protocol_io_prox_xsf.c @@ -259,6 +259,10 @@ bool protocol_io_prox_xsf_write_data(ProtocolIOProxXSF* protocol, void* data) { LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data; bool result = false; + // Correct protocol data by redecoding + protocol_io_prox_xsf_encode(protocol->data, protocol->encoded_data); + protocol_io_prox_xsf_decode(protocol->encoded_data, protocol->data); + protocol_io_prox_xsf_encode(protocol->data, protocol->encoded_data); if(request->write_type == LFRFIDWriteTypeT5577) { diff --git a/lib/lfrfid/protocols/protocol_jablotron.c b/lib/lfrfid/protocols/protocol_jablotron.c new file mode 100644 index 000000000..89a59a2d7 --- /dev/null +++ b/lib/lfrfid/protocols/protocol_jablotron.c @@ -0,0 +1,211 @@ +#include +#include "toolbox/level_duration.h" +#include "protocol_jablotron.h" +#include +#include +#include "lfrfid_protocols.h" + +#define JABLOTRON_ENCODED_BIT_SIZE (64) +#define JABLOTRON_ENCODED_BYTE_SIZE (((JABLOTRON_ENCODED_BIT_SIZE) / 8)) +#define JABLOTRON_PREAMBLE_BIT_SIZE (16) +#define JABLOTRON_PREAMBLE_BYTE_SIZE (2) +#define JABLOTRON_ENCODED_BYTE_FULL_SIZE \ + (JABLOTRON_ENCODED_BYTE_SIZE + JABLOTRON_PREAMBLE_BYTE_SIZE) + +#define JABLOTRON_DECODED_DATA_SIZE (5) + +#define JABLOTRON_SHORT_TIME (256) +#define JABLOTRON_LONG_TIME (512) +#define JABLOTRON_JITTER_TIME (120) + +#define JABLOTRON_SHORT_TIME_LOW (JABLOTRON_SHORT_TIME - JABLOTRON_JITTER_TIME) +#define JABLOTRON_SHORT_TIME_HIGH (JABLOTRON_SHORT_TIME + JABLOTRON_JITTER_TIME) +#define JABLOTRON_LONG_TIME_LOW (JABLOTRON_LONG_TIME - JABLOTRON_JITTER_TIME) +#define JABLOTRON_LONG_TIME_HIGH (JABLOTRON_LONG_TIME + JABLOTRON_JITTER_TIME) + +typedef struct { + bool last_short; + bool last_level; + size_t encoded_index; + uint8_t encoded_data[JABLOTRON_ENCODED_BYTE_FULL_SIZE]; + uint8_t data[JABLOTRON_DECODED_DATA_SIZE]; +} ProtocolJablotron; + +ProtocolJablotron* protocol_jablotron_alloc(void) { + ProtocolJablotron* protocol = malloc(sizeof(ProtocolJablotron)); + return protocol; +}; + +void protocol_jablotron_free(ProtocolJablotron* protocol) { + free(protocol); +}; + +uint8_t* protocol_jablotron_get_data(ProtocolJablotron* proto) { + return proto->data; +}; + +void protocol_jablotron_decoder_start(ProtocolJablotron* protocol) { + memset(protocol->encoded_data, 0, JABLOTRON_ENCODED_BYTE_FULL_SIZE); + protocol->last_short = false; +}; + +uint8_t protocol_jablotron_checksum(uint8_t* bits) { + uint8_t chksum = 0; + for(uint8_t i = 16; i < 56; i += 8) { + chksum += bit_lib_get_bits(bits, i, 8); + } + chksum ^= 0x3A; + return chksum; +} + +uint64_t protocol_jablotron_card_id(uint8_t* bytes) { + uint64_t id = 0; + for(int i = 0; i < 5; i++) { + id *= 100; + id += ((bytes[i] & 0xF0) >> 4) * 10 + (bytes[i] & 0x0F); + } + return id; +} + +static bool protocol_jablotron_can_be_decoded(ProtocolJablotron* protocol) { + // check 11 bits preamble + if(bit_lib_get_bits_16(protocol->encoded_data, 0, 16) != 0b1111111111111111) return false; + // check next 11 bits preamble + if(bit_lib_get_bits_16(protocol->encoded_data, 64, 16) != 0b1111111111111111) return false; + + uint8_t checksum = bit_lib_get_bits(protocol->encoded_data, 56, 8); + if(checksum != protocol_jablotron_checksum(protocol->encoded_data)) return false; + + return true; +} + +void protocol_jablotron_decode(ProtocolJablotron* protocol) { + bit_lib_copy_bits(protocol->data, 0, 40, protocol->encoded_data, 16); +} + +bool protocol_jablotron_decoder_feed(ProtocolJablotron* protocol, bool level, uint32_t duration) { + UNUSED(level); + bool pushed = false; + + // Bi-Phase Manchester decoding + if(duration >= JABLOTRON_SHORT_TIME_LOW && duration <= JABLOTRON_SHORT_TIME_HIGH) { + if(protocol->last_short == false) { + protocol->last_short = true; + } else { + pushed = true; + bit_lib_push_bit(protocol->encoded_data, JABLOTRON_ENCODED_BYTE_FULL_SIZE, false); + protocol->last_short = false; + } + } else if(duration >= JABLOTRON_LONG_TIME_LOW && duration <= JABLOTRON_LONG_TIME_HIGH) { + if(protocol->last_short == false) { + pushed = true; + bit_lib_push_bit(protocol->encoded_data, JABLOTRON_ENCODED_BYTE_FULL_SIZE, true); + } else { + // reset + protocol->last_short = false; + } + } else { + // reset + protocol->last_short = false; + } + + if(pushed && protocol_jablotron_can_be_decoded(protocol)) { + protocol_jablotron_decode(protocol); + return true; + } + + return false; +}; + +bool protocol_jablotron_encoder_start(ProtocolJablotron* protocol) { + // preamble + bit_lib_set_bits(protocol->encoded_data, 0, 0b11111111, 8); + bit_lib_set_bits(protocol->encoded_data, 8, 0b11111111, 8); + + // Full code + bit_lib_copy_bits(protocol->encoded_data, 16, 40, protocol->data, 0); + + // Checksum + bit_lib_set_bits( + protocol->encoded_data, 56, protocol_jablotron_checksum(protocol->encoded_data), 8); + + protocol->encoded_index = 0; + protocol->last_short = false; + protocol->last_level = false; + return true; +}; + +LevelDuration protocol_jablotron_encoder_yield(ProtocolJablotron* protocol) { + uint32_t duration; + protocol->last_level = !protocol->last_level; + + bool bit = bit_lib_get_bit(protocol->encoded_data, protocol->encoded_index); + + // Bi-Phase Manchester encoder + if(bit) { + // one long pulse for 1 + duration = JABLOTRON_LONG_TIME / 8; + bit_lib_increment_index(protocol->encoded_index, JABLOTRON_ENCODED_BIT_SIZE); + } else { + // two short pulses for 0 + duration = JABLOTRON_SHORT_TIME / 8; + if(protocol->last_short) { + bit_lib_increment_index(protocol->encoded_index, JABLOTRON_ENCODED_BIT_SIZE); + protocol->last_short = false; + } else { + protocol->last_short = true; + } + } + + return level_duration_make(protocol->last_level, duration); +}; + +void protocol_jablotron_render_data(ProtocolJablotron* protocol, string_t result) { + uint64_t id = protocol_jablotron_card_id(protocol->data); + string_printf(result, "ID: %llX\r\n", id); +}; + +bool protocol_jablotron_write_data(ProtocolJablotron* protocol, void* data) { + LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data; + bool result = false; + + // Correct protocol data by redecoding + protocol_jablotron_encoder_start(protocol); + protocol_jablotron_decode(protocol); + + protocol_jablotron_encoder_start(protocol); + + if(request->write_type == LFRFIDWriteTypeT5577) { + request->t5577.block[0] = LFRFID_T5577_MODULATION_DIPHASE | LFRFID_T5577_BITRATE_RF_64 | + (2 << LFRFID_T5577_MAXBLOCK_SHIFT); + request->t5577.block[1] = bit_lib_get_bits_32(protocol->encoded_data, 0, 32); + request->t5577.block[2] = bit_lib_get_bits_32(protocol->encoded_data, 32, 32); + request->t5577.blocks_to_write = 3; + result = true; + } + return result; +}; + +const ProtocolBase protocol_jablotron = { + .name = "Jablotron", + .manufacturer = "Jablotron", + .data_size = JABLOTRON_DECODED_DATA_SIZE, + .features = LFRFIDFeatureASK, + .validate_count = 3, + .alloc = (ProtocolAlloc)protocol_jablotron_alloc, + .free = (ProtocolFree)protocol_jablotron_free, + .get_data = (ProtocolGetData)protocol_jablotron_get_data, + .decoder = + { + .start = (ProtocolDecoderStart)protocol_jablotron_decoder_start, + .feed = (ProtocolDecoderFeed)protocol_jablotron_decoder_feed, + }, + .encoder = + { + .start = (ProtocolEncoderStart)protocol_jablotron_encoder_start, + .yield = (ProtocolEncoderYield)protocol_jablotron_encoder_yield, + }, + .render_data = (ProtocolRenderData)protocol_jablotron_render_data, + .render_brief_data = (ProtocolRenderData)protocol_jablotron_render_data, + .write_data = (ProtocolWriteData)protocol_jablotron_write_data, +}; \ No newline at end of file diff --git a/lib/lfrfid/protocols/protocol_jablotron.h b/lib/lfrfid/protocols/protocol_jablotron.h new file mode 100644 index 000000000..4de57de42 --- /dev/null +++ b/lib/lfrfid/protocols/protocol_jablotron.h @@ -0,0 +1,4 @@ +#pragma once +#include + +extern const ProtocolBase protocol_jablotron; \ No newline at end of file diff --git a/lib/lfrfid/protocols/protocol_keri.c b/lib/lfrfid/protocols/protocol_keri.c new file mode 100644 index 000000000..7e6625546 --- /dev/null +++ b/lib/lfrfid/protocols/protocol_keri.c @@ -0,0 +1,264 @@ +#include +#include +#include +#include "lfrfid_protocols.h" + +#define KERI_PREAMBLE_BIT_SIZE (33) +#define KERI_PREAMBLE_DATA_SIZE (5) + +#define KERI_ENCODED_BIT_SIZE (64) +#define KERI_ENCODED_DATA_SIZE (((KERI_ENCODED_BIT_SIZE) / 8) + KERI_PREAMBLE_DATA_SIZE) +#define KERI_ENCODED_DATA_LAST ((KERI_ENCODED_BIT_SIZE) / 8) + +#define KERI_DECODED_BIT_SIZE (28) +#define KERI_DECODED_DATA_SIZE (4) + +#define KERI_US_PER_BIT (255) +#define KERI_ENCODER_PULSES_PER_BIT (16) + +typedef struct { + uint8_t data_index; + uint8_t bit_clock_index; + bool last_bit; + bool current_polarity; + bool pulse_phase; +} ProtocolKeriEncoder; + +typedef struct { + uint8_t encoded_data[KERI_ENCODED_DATA_SIZE]; + uint8_t negative_encoded_data[KERI_ENCODED_DATA_SIZE]; + uint8_t corrupted_encoded_data[KERI_ENCODED_DATA_SIZE]; + uint8_t corrupted_negative_encoded_data[KERI_ENCODED_DATA_SIZE]; + + uint8_t data[KERI_DECODED_DATA_SIZE]; + ProtocolKeriEncoder encoder; +} ProtocolKeri; + +ProtocolKeri* protocol_keri_alloc(void) { + ProtocolKeri* protocol = malloc(sizeof(ProtocolKeri)); + return protocol; +}; + +void protocol_keri_free(ProtocolKeri* protocol) { + free(protocol); +}; + +uint8_t* protocol_keri_get_data(ProtocolKeri* protocol) { + return protocol->data; +}; + +void protocol_keri_decoder_start(ProtocolKeri* protocol) { + memset(protocol->encoded_data, 0, KERI_ENCODED_DATA_SIZE); + memset(protocol->negative_encoded_data, 0, KERI_ENCODED_DATA_SIZE); + memset(protocol->corrupted_encoded_data, 0, KERI_ENCODED_DATA_SIZE); + memset(protocol->corrupted_negative_encoded_data, 0, KERI_ENCODED_DATA_SIZE); +}; + +static bool protocol_keri_check_preamble(uint8_t* data, size_t bit_index) { + // Preamble 11100000 00000000 00000000 00000000 1 + if(*(uint32_t*)&data[bit_index / 8] != 0b00000000000000000000000011100000) return false; + if(bit_lib_get_bit(data, bit_index + 32) != 1) return false; + return true; +} + +static bool protocol_keri_can_be_decoded(uint8_t* data) { + if(!protocol_keri_check_preamble(data, 0)) return false; + if(!protocol_keri_check_preamble(data, 64)) return false; + ///if(bit_lib_get_bit(data, 61) != 0) return false; + //if(bit_lib_get_bit(data, 60) != 0) return false; + return true; +} + +static bool protocol_keri_decoder_feed_internal(bool polarity, uint32_t time, uint8_t* data) { + time += (KERI_US_PER_BIT / 2); + + size_t bit_count = (time / KERI_US_PER_BIT); + bool result = false; + + if(bit_count < KERI_ENCODED_BIT_SIZE) { + for(size_t i = 0; i < bit_count; i++) { + bit_lib_push_bit(data, KERI_ENCODED_DATA_SIZE, polarity); + if(protocol_keri_can_be_decoded(data)) { + result = true; + break; + } + } + } + + return result; +} + +static void protocol_keri_descramble(uint32_t* fc, uint32_t* cn, uint32_t* internal_id) { + const uint8_t card_to_id[] = {255, 255, 255, 255, 13, 12, 20, 5, 16, 6, 21, + 17, 8, 255, 0, 7, 10, 15, 255, 11, 4, 1, + 255, 18, 255, 19, 2, 14, 3, 9, 255, 255}; + + const uint8_t card_to_fc[] = {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 0, 255, 255, 255, 255, 2, 255, 255, 255, + 3, 255, 4, 255, 255, 255, 255, 255, 1, 255}; + + *fc = 0; + *cn = 0; + for(uint8_t card_idx = 0; card_idx < 32; card_idx++) { + bool bit = (*internal_id >> card_idx) & 1; + // Card ID + if(card_to_id[card_idx] < 32) { + *cn = *cn | (bit << card_to_id[card_idx]); + } + // Card FC + if(card_to_fc[card_idx] < 32) { + *fc = *fc | (bit << card_to_fc[card_idx]); + } + } +} + +static void protocol_keri_decoder_save(uint8_t* data_to, const uint8_t* data_from) { + uint32_t id = bit_lib_get_bits_32(data_from, 32, 32); + data_to[3] = (uint8_t)id; + data_to[2] = (uint8_t)(id >>= 8); + data_to[1] = (uint8_t)(id >>= 8); + data_to[0] = (uint8_t)(id >>= 8); +} + +bool protocol_keri_decoder_feed(ProtocolKeri* protocol, bool level, uint32_t duration) { + bool result = false; + + if(duration > (KERI_US_PER_BIT / 2)) { + if(protocol_keri_decoder_feed_internal(level, duration, protocol->encoded_data)) { + protocol_keri_decoder_save(protocol->data, protocol->encoded_data); + result = true; + return result; + } + + if(protocol_keri_decoder_feed_internal(!level, duration, protocol->negative_encoded_data)) { + protocol_keri_decoder_save(protocol->data, protocol->negative_encoded_data); + result = true; + return result; + } + } + + if(duration > (KERI_US_PER_BIT / 4)) { + // Try to decode wrong phase synced data + if(level) { + duration += 120; + } else { + if(duration > 120) { + duration -= 120; + } + } + + if(protocol_keri_decoder_feed_internal(level, duration, protocol->corrupted_encoded_data)) { + protocol_keri_decoder_save(protocol->data, protocol->corrupted_encoded_data); + + result = true; + return result; + } + + if(protocol_keri_decoder_feed_internal( + !level, duration, protocol->corrupted_negative_encoded_data)) { + protocol_keri_decoder_save(protocol->data, protocol->corrupted_negative_encoded_data); + + result = true; + return result; + } + } + + return result; +}; + +bool protocol_keri_encoder_start(ProtocolKeri* protocol) { + memset(protocol->encoded_data, 0, KERI_ENCODED_DATA_SIZE); + *(uint32_t*)&protocol->encoded_data[0] = 0b00000000000000000000000011100000; + bit_lib_copy_bits(protocol->encoded_data, 32, 32, protocol->data, 0); + + protocol->encoder.last_bit = + bit_lib_get_bit(protocol->encoded_data, KERI_ENCODED_BIT_SIZE - 1); + protocol->encoder.data_index = 0; + protocol->encoder.current_polarity = true; + protocol->encoder.pulse_phase = true; + protocol->encoder.bit_clock_index = 0; + + return true; +}; + +LevelDuration protocol_keri_encoder_yield(ProtocolKeri* protocol) { + LevelDuration level_duration; + ProtocolKeriEncoder* encoder = &protocol->encoder; + + if(encoder->pulse_phase) { + level_duration = level_duration_make(encoder->current_polarity, 1); + encoder->pulse_phase = false; + } else { + level_duration = level_duration_make(!encoder->current_polarity, 1); + encoder->pulse_phase = true; + + encoder->bit_clock_index++; + if(encoder->bit_clock_index >= KERI_ENCODER_PULSES_PER_BIT) { + encoder->bit_clock_index = 0; + + bool current_bit = bit_lib_get_bit(protocol->encoded_data, encoder->data_index); + + if(current_bit != encoder->last_bit) { + encoder->current_polarity = !encoder->current_polarity; + } + + encoder->last_bit = current_bit; + + bit_lib_increment_index(encoder->data_index, KERI_ENCODED_BIT_SIZE); + } + } + + return level_duration; +}; + +void protocol_keri_render_data(ProtocolKeri* protocol, string_t result) { + uint32_t data = bit_lib_get_bits_32(protocol->data, 0, 32); + uint32_t internal_id = data & 0x7FFFFFFF; + uint32_t fc = 0; + uint32_t cn = 0; + protocol_keri_descramble(&fc, &cn, &data); + string_printf(result, "Internal ID: %u\r\nFC: %u, Card: %u\r\n", internal_id, fc, cn); +} + +bool protocol_keri_write_data(ProtocolKeri* protocol, void* data) { + LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data; + bool result = false; + + protocol_keri_encoder_start(protocol); + + if(request->write_type == LFRFIDWriteTypeT5577) { + request->t5577.block[0] = LFRFID_T5577_TESTMODE_DISABLED | LFRFID_T5577_X_MODE | + LFRFID_T5577_MODULATION_PSK1 | LFRFID_T5577_PSKCF_RF_2 | + (2 << LFRFID_T5577_MAXBLOCK_SHIFT); + request->t5577.block[0] |= 0xF << 18; + request->t5577.block[1] = bit_lib_get_bits_32(protocol->encoded_data, 0, 32); + request->t5577.block[2] = bit_lib_get_bits_32(protocol->encoded_data, 32, 32); + request->t5577.blocks_to_write = 3; + result = true; + } + return result; +}; + +const ProtocolBase protocol_keri = { + .name = "Keri", + .manufacturer = "Keri", + .data_size = KERI_DECODED_DATA_SIZE, + .features = LFRFIDFeaturePSK, + .validate_count = 6, + .alloc = (ProtocolAlloc)protocol_keri_alloc, + .free = (ProtocolFree)protocol_keri_free, + .get_data = (ProtocolGetData)protocol_keri_get_data, + .decoder = + { + .start = (ProtocolDecoderStart)protocol_keri_decoder_start, + .feed = (ProtocolDecoderFeed)protocol_keri_decoder_feed, + }, + .encoder = + { + .start = (ProtocolEncoderStart)protocol_keri_encoder_start, + .yield = (ProtocolEncoderYield)protocol_keri_encoder_yield, + }, + .render_data = (ProtocolRenderData)protocol_keri_render_data, + .render_brief_data = (ProtocolRenderData)protocol_keri_render_data, + .write_data = (ProtocolWriteData)protocol_keri_write_data, +}; \ No newline at end of file diff --git a/lib/lfrfid/protocols/protocol_keri.h b/lib/lfrfid/protocols/protocol_keri.h new file mode 100644 index 000000000..4cf5f370c --- /dev/null +++ b/lib/lfrfid/protocols/protocol_keri.h @@ -0,0 +1,4 @@ +#pragma once +#include + +extern const ProtocolBase protocol_keri; diff --git a/lib/lfrfid/protocols/protocol_pac_stanley.c b/lib/lfrfid/protocols/protocol_pac_stanley.c new file mode 100644 index 000000000..b5e1ebddc --- /dev/null +++ b/lib/lfrfid/protocols/protocol_pac_stanley.c @@ -0,0 +1,231 @@ +#include +#include +#include +#include +#include +#include "lfrfid_protocols.h" + +#define PAC_STANLEY_ENCODED_BIT_SIZE (128) +#define PAC_STANLEY_ENCODED_BYTE_SIZE (((PAC_STANLEY_ENCODED_BIT_SIZE) / 8)) +#define PAC_STANLEY_PREAMBLE_BIT_SIZE (8) +#define PAC_STANLEY_PREAMBLE_BYTE_SIZE (1) +#define PAC_STANLEY_ENCODED_BYTE_FULL_SIZE \ + (PAC_STANLEY_ENCODED_BYTE_SIZE + PAC_STANLEY_PREAMBLE_BYTE_SIZE) +#define PAC_STANLEY_BYTE_LENGTH (10) // start bit, 7 data bits, parity bit, stop bit +#define PAC_STANLEY_DATA_START_INDEX 8 + (3 * PAC_STANLEY_BYTE_LENGTH) + 1 + +#define PAC_STANLEY_DECODED_DATA_SIZE (4) +#define PAC_STANLEY_ENCODED_DATA_SIZE (sizeof(ProtocolPACStanley)) + +#define PAC_STANLEY_CLOCKS_IN_US (32) +#define PAC_STANLEY_CYCLE_LENGTH (256) +#define PAC_STANLEY_MIN_TIME (60) +#define PAC_STANLEY_MAX_TIME (4000) + +typedef struct { + bool inverted; + bool got_preamble; + size_t encoded_index; + uint8_t encoded_data[PAC_STANLEY_ENCODED_BYTE_FULL_SIZE]; + uint8_t data[PAC_STANLEY_DECODED_DATA_SIZE]; +} ProtocolPACStanley; + +ProtocolPACStanley* protocol_pac_stanley_alloc(void) { + ProtocolPACStanley* protocol = malloc(sizeof(ProtocolPACStanley)); + return (void*)protocol; +} + +void protocol_pac_stanley_free(ProtocolPACStanley* protocol) { + free(protocol); +} + +uint8_t* protocol_pac_stanley_get_data(ProtocolPACStanley* protocol) { + return protocol->data; +} + +static void protocol_pac_stanley_decode(ProtocolPACStanley* protocol) { + uint8_t asciiCardId[8]; + for(size_t idx = 0; idx < 8; idx++) { + uint8_t byte = bit_lib_reverse_8_fast(bit_lib_get_bits( + protocol->encoded_data, + PAC_STANLEY_DATA_START_INDEX + (PAC_STANLEY_BYTE_LENGTH * idx), + 8)); + asciiCardId[idx] = byte & 0x7F; // discard the parity bit + } + + hex_chars_to_uint8((char*)asciiCardId, protocol->data); +} + +static bool protocol_pac_stanley_can_be_decoded(ProtocolPACStanley* protocol) { + // Check preamble + if(bit_lib_get_bits(protocol->encoded_data, 0, 8) != 0b11111111) return false; + if(bit_lib_get_bit(protocol->encoded_data, 8) != 0) return false; + if(bit_lib_get_bit(protocol->encoded_data, 9) != 0) return false; + if(bit_lib_get_bit(protocol->encoded_data, 10) != 1) return false; + if(bit_lib_get_bits(protocol->encoded_data, 11, 8) != 0b00000010) return false; + + // Check next preamble + if(bit_lib_get_bits(protocol->encoded_data, 128, 8) != 0b11111111) return false; + + // Checksum + uint8_t checksum = 0; + uint8_t stripped_byte; + for(size_t idx = 0; idx < 9; idx++) { + uint8_t byte = bit_lib_reverse_8_fast(bit_lib_get_bits( + protocol->encoded_data, + PAC_STANLEY_DATA_START_INDEX + (PAC_STANLEY_BYTE_LENGTH * idx), + 8)); + stripped_byte = byte & 0x7F; // discard the parity bit + if(bit_lib_test_parity_32(stripped_byte, BitLibParityOdd) != (byte & 0x80) >> 7) { + return false; + } + if(idx < 8) checksum ^= stripped_byte; + } + if(stripped_byte != checksum) return false; + return true; +} + +void protocol_pac_stanley_decoder_start(ProtocolPACStanley* protocol) { + memset(protocol->data, 0, PAC_STANLEY_DECODED_DATA_SIZE); + protocol->inverted = false; + protocol->got_preamble = false; +} + +bool protocol_pac_stanley_decoder_feed(ProtocolPACStanley* protocol, bool level, uint32_t duration) { + bool pushed = false; + + if(duration > PAC_STANLEY_MAX_TIME) return false; + + uint8_t pulses = (uint8_t)round((float)duration / PAC_STANLEY_CYCLE_LENGTH); + + // Handle last stopbit & preamble (1 sb, 8 bit preamble) + if(pulses >= 9 && !protocol->got_preamble) { + pulses = 8; + protocol->got_preamble = true; + protocol->inverted = !level; + } else if(pulses >= 9 && protocol->got_preamble) { + protocol->got_preamble = false; + } else if(pulses == 0 && duration > PAC_STANLEY_MIN_TIME) { + pulses = 1; + } + + if(pulses) { + for(uint8_t i = 0; i < pulses; i++) { + bit_lib_push_bit( + protocol->encoded_data, + PAC_STANLEY_ENCODED_BYTE_FULL_SIZE, + level ^ protocol->inverted); + } + pushed = true; + } + + if(pushed && protocol_pac_stanley_can_be_decoded(protocol)) { + protocol_pac_stanley_decode(protocol); + return true; + } + + return false; +} + +bool protocol_pac_stanley_encoder_start(ProtocolPACStanley* protocol) { + memset(protocol->encoded_data, 0, PAC_STANLEY_ENCODED_BYTE_SIZE); + + uint8_t idbytes[10]; + idbytes[0] = '2'; + idbytes[1] = '0'; + + uint8_to_hex_chars(protocol->data, &idbytes[2], 8); + + // insert start and stop bits + for(size_t i = 0; i < 16; i++) protocol->encoded_data[i] = 0x40 >> (i + 3) % 5 * 2; + + protocol->encoded_data[0] = 0xFF; // mark + stop + protocol->encoded_data[1] = 0x20; // start + reflect8(STX) + + uint8_t checksum = 0; + for(size_t i = 2; i < 13; i++) { + uint8_t shift = 7 - (i + 3) % 4 * 2; + uint8_t index = i + (i - 1) / 4; + + uint16_t pattern; + if(i < 12) { + pattern = bit_lib_reverse_8_fast(idbytes[i - 2]); + pattern |= bit_lib_test_parity_32(pattern, BitLibParityOdd); + if(i > 3) checksum ^= idbytes[i - 2]; + } else { + pattern = (bit_lib_reverse_8_fast(checksum) & 0xFE) | + (bit_lib_test_parity_32(checksum, BitLibParityOdd)); + } + pattern <<= shift; + + protocol->encoded_data[index] |= pattern >> 8 & 0xFF; + protocol->encoded_data[index + 1] |= pattern & 0xFF; + } + + protocol->encoded_index = 0; + return true; +} + +LevelDuration protocol_pac_stanley_encoder_yield(ProtocolPACStanley* protocol) { + uint16_t length = PAC_STANLEY_CLOCKS_IN_US; + bool bit = bit_lib_get_bit(protocol->encoded_data, protocol->encoded_index); + bit_lib_increment_index(protocol->encoded_index, PAC_STANLEY_ENCODED_BIT_SIZE); + while(bit_lib_get_bit(protocol->encoded_data, protocol->encoded_index) == bit) { + length += PAC_STANLEY_CLOCKS_IN_US; + bit_lib_increment_index(protocol->encoded_index, PAC_STANLEY_ENCODED_BIT_SIZE); + } + + return level_duration_make(bit, length); +} + +bool protocol_pac_stanley_write_data(ProtocolPACStanley* protocol, void* data) { + LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data; + bool result = false; + + // Correct protocol data by redecoding + protocol_pac_stanley_encoder_start(protocol); + protocol_pac_stanley_decode(protocol); + + protocol_pac_stanley_encoder_start(protocol); + + if(request->write_type == LFRFIDWriteTypeT5577) { + request->t5577.block[0] = LFRFID_T5577_MODULATION_DIRECT | LFRFID_T5577_BITRATE_RF_32 | + (4 << LFRFID_T5577_MAXBLOCK_SHIFT); + request->t5577.block[1] = bit_lib_get_bits_32(protocol->encoded_data, 0, 32); + request->t5577.block[2] = bit_lib_get_bits_32(protocol->encoded_data, 32, 32); + request->t5577.block[3] = bit_lib_get_bits_32(protocol->encoded_data, 64, 32); + request->t5577.block[4] = bit_lib_get_bits_32(protocol->encoded_data, 96, 32); + request->t5577.blocks_to_write = 5; + result = true; + } + return result; +} + +void protocol_pac_stanley_render_data(ProtocolPACStanley* protocol, string_t result) { + uint8_t* data = protocol->data; + string_printf(result, "CIN: %02X%02X%02X%02X", data[0], data[1], data[2], data[3]); +} + +const ProtocolBase protocol_pac_stanley = { + .name = "PAC/Stanley", + .manufacturer = "N/A", + .data_size = PAC_STANLEY_DECODED_DATA_SIZE, + .features = LFRFIDFeatureASK, + .validate_count = 3, + .alloc = (ProtocolAlloc)protocol_pac_stanley_alloc, + .free = (ProtocolFree)protocol_pac_stanley_free, + .get_data = (ProtocolGetData)protocol_pac_stanley_get_data, + .decoder = + { + .start = (ProtocolDecoderStart)protocol_pac_stanley_decoder_start, + .feed = (ProtocolDecoderFeed)protocol_pac_stanley_decoder_feed, + }, + .encoder = + { + .start = (ProtocolEncoderStart)protocol_pac_stanley_encoder_start, + .yield = (ProtocolEncoderYield)protocol_pac_stanley_encoder_yield, + }, + .render_data = (ProtocolRenderData)protocol_pac_stanley_render_data, + .render_brief_data = (ProtocolRenderData)protocol_pac_stanley_render_data, + .write_data = (ProtocolWriteData)protocol_pac_stanley_write_data, +}; \ No newline at end of file diff --git a/lib/lfrfid/protocols/protocol_pac_stanley.h b/lib/lfrfid/protocols/protocol_pac_stanley.h new file mode 100644 index 000000000..3ca329cf7 --- /dev/null +++ b/lib/lfrfid/protocols/protocol_pac_stanley.h @@ -0,0 +1,4 @@ +#pragma once +#include + +extern const ProtocolBase protocol_pac_stanley; \ No newline at end of file diff --git a/lib/lfrfid/protocols/protocol_paradox.c b/lib/lfrfid/protocols/protocol_paradox.c new file mode 100644 index 000000000..b0b3e71d6 --- /dev/null +++ b/lib/lfrfid/protocols/protocol_paradox.c @@ -0,0 +1,205 @@ +#include +#include +#include +#include +#include +#include "lfrfid_protocols.h" + +#define JITTER_TIME (20) +#define MIN_TIME (64 - JITTER_TIME) +#define MAX_TIME (80 + JITTER_TIME) + +#define PARADOX_DECODED_DATA_SIZE (6) + +#define PARADOX_PREAMBLE_LENGTH (8) +#define PARADOX_ENCODED_BIT_SIZE (96) +#define PARADOX_ENCODED_DATA_SIZE (((PARADOX_ENCODED_BIT_SIZE) / 8) + 1) +#define PARADOX_ENCODED_DATA_LAST (PARADOX_ENCODED_DATA_SIZE - 1) + +typedef struct { + FSKDemod* fsk_demod; +} ProtocolParadoxDecoder; + +typedef struct { + FSKOsc* fsk_osc; + uint8_t encoded_index; +} ProtocolParadoxEncoder; + +typedef struct { + ProtocolParadoxDecoder decoder; + ProtocolParadoxEncoder encoder; + uint8_t encoded_data[PARADOX_ENCODED_DATA_SIZE]; + uint8_t data[PARADOX_DECODED_DATA_SIZE]; +} ProtocolParadox; + +ProtocolParadox* protocol_paradox_alloc(void) { + ProtocolParadox* protocol = malloc(sizeof(ProtocolParadox)); + protocol->decoder.fsk_demod = fsk_demod_alloc(MIN_TIME, 6, MAX_TIME, 5); + protocol->encoder.fsk_osc = fsk_osc_alloc(8, 10, 50); + + return protocol; +}; + +void protocol_paradox_free(ProtocolParadox* protocol) { + fsk_demod_free(protocol->decoder.fsk_demod); + fsk_osc_free(protocol->encoder.fsk_osc); + free(protocol); +}; + +uint8_t* protocol_paradox_get_data(ProtocolParadox* protocol) { + return protocol->data; +}; + +void protocol_paradox_decoder_start(ProtocolParadox* protocol) { + memset(protocol->encoded_data, 0, PARADOX_ENCODED_DATA_SIZE); +}; + +static bool protocol_paradox_can_be_decoded(ProtocolParadox* protocol) { + // check preamble + if(protocol->encoded_data[0] != 0b00001111 || + protocol->encoded_data[PARADOX_ENCODED_DATA_LAST] != 0b00001111) + return false; + + for(uint32_t i = PARADOX_PREAMBLE_LENGTH; i < 96; i += 2) { + if(bit_lib_get_bit(protocol->encoded_data, i) == + bit_lib_get_bit(protocol->encoded_data, i + 1)) { + return false; + } + } + + return true; +} + +static void protocol_paradox_decode(uint8_t* encoded_data, uint8_t* decoded_data) { + for(uint32_t i = PARADOX_PREAMBLE_LENGTH; i < 96; i += 2) { + if(bit_lib_get_bits(encoded_data, i, 2) == 0b01) { + bit_lib_push_bit(decoded_data, PARADOX_DECODED_DATA_SIZE, 0); + } else if(bit_lib_get_bits(encoded_data, i, 2) == 0b10) { + bit_lib_push_bit(decoded_data, PARADOX_DECODED_DATA_SIZE, 1); + } + } + bit_lib_push_bit(decoded_data, PARADOX_DECODED_DATA_SIZE, 0); + bit_lib_push_bit(decoded_data, PARADOX_DECODED_DATA_SIZE, 0); + bit_lib_push_bit(decoded_data, PARADOX_DECODED_DATA_SIZE, 0); + bit_lib_push_bit(decoded_data, PARADOX_DECODED_DATA_SIZE, 0); +} + +bool protocol_paradox_decoder_feed(ProtocolParadox* protocol, bool level, uint32_t duration) { + bool value; + uint32_t count; + + fsk_demod_feed(protocol->decoder.fsk_demod, level, duration, &value, &count); + if(count > 0) { + for(size_t i = 0; i < count; i++) { + bit_lib_push_bit(protocol->encoded_data, PARADOX_ENCODED_DATA_SIZE, value); + if(protocol_paradox_can_be_decoded(protocol)) { + protocol_paradox_decode(protocol->encoded_data, protocol->data); + + return true; + } + } + } + + return false; +}; + +static void protocol_paradox_encode(const uint8_t* decoded_data, uint8_t* encoded_data) { + // preamble + bit_lib_set_bits(encoded_data, 0, 0b00001111, 8); + + for(size_t i = 0; i < 44; i++) { + if(bit_lib_get_bit(decoded_data, i)) { + bit_lib_set_bits(encoded_data, PARADOX_PREAMBLE_LENGTH + i * 2, 0b10, 2); + } else { + bit_lib_set_bits(encoded_data, PARADOX_PREAMBLE_LENGTH + i * 2, 0b01, 2); + } + } +}; + +bool protocol_paradox_encoder_start(ProtocolParadox* protocol) { + protocol_paradox_encode(protocol->data, (uint8_t*)protocol->encoded_data); + protocol->encoder.encoded_index = 0; + fsk_osc_reset(protocol->encoder.fsk_osc); + return true; +}; + +LevelDuration protocol_paradox_encoder_yield(ProtocolParadox* protocol) { + bool level; + uint32_t duration; + + bool bit = bit_lib_get_bit(protocol->encoded_data, protocol->encoder.encoded_index); + bool advance = fsk_osc_next_half(protocol->encoder.fsk_osc, bit, &level, &duration); + + if(advance) { + bit_lib_increment_index(protocol->encoder.encoded_index, PARADOX_ENCODED_BIT_SIZE); + } + return level_duration_make(level, duration); +}; + +void protocol_paradox_render_data(ProtocolParadox* protocol, string_t result) { + uint8_t* decoded_data = protocol->data; + uint8_t fc = bit_lib_get_bits(decoded_data, 10, 8); + uint16_t card_id = bit_lib_get_bits_16(decoded_data, 18, 16); + + string_cat_printf(result, "Facility: %u\r\n", fc); + string_cat_printf(result, "Card: %lu\r\n", card_id); + string_cat_printf(result, "Data: "); + for(size_t i = 0; i < PARADOX_DECODED_DATA_SIZE; i++) { + string_cat_printf(result, "%02X", decoded_data[i]); + } +}; + +void protocol_paradox_render_brief_data(ProtocolParadox* protocol, string_t result) { + uint8_t* decoded_data = protocol->data; + + uint8_t fc = bit_lib_get_bits(decoded_data, 10, 8); + uint16_t card_id = bit_lib_get_bits_16(decoded_data, 18, 16); + + string_cat_printf(result, "FC: %03u, Card: %05u", fc, card_id); +}; + +bool protocol_paradox_write_data(ProtocolParadox* protocol, void* data) { + LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data; + bool result = false; + + // Correct protocol data by redecoding + protocol_paradox_encode(protocol->data, (uint8_t*)protocol->encoded_data); + protocol_paradox_decode(protocol->encoded_data, protocol->data); + + protocol_paradox_encode(protocol->data, (uint8_t*)protocol->encoded_data); + + if(request->write_type == LFRFIDWriteTypeT5577) { + request->t5577.block[0] = LFRFID_T5577_MODULATION_FSK2a | LFRFID_T5577_BITRATE_RF_50 | + (3 << LFRFID_T5577_MAXBLOCK_SHIFT); + request->t5577.block[1] = bit_lib_get_bits_32(protocol->encoded_data, 0, 32); + request->t5577.block[2] = bit_lib_get_bits_32(protocol->encoded_data, 32, 32); + request->t5577.block[3] = bit_lib_get_bits_32(protocol->encoded_data, 64, 32); + request->t5577.blocks_to_write = 4; + result = true; + } + return result; +}; + +const ProtocolBase protocol_paradox = { + .name = "Paradox", + .manufacturer = "Paradox", + .data_size = PARADOX_DECODED_DATA_SIZE, + .features = LFRFIDFeatureASK, + .validate_count = 3, + .alloc = (ProtocolAlloc)protocol_paradox_alloc, + .free = (ProtocolFree)protocol_paradox_free, + .get_data = (ProtocolGetData)protocol_paradox_get_data, + .decoder = + { + .start = (ProtocolDecoderStart)protocol_paradox_decoder_start, + .feed = (ProtocolDecoderFeed)protocol_paradox_decoder_feed, + }, + .encoder = + { + .start = (ProtocolEncoderStart)protocol_paradox_encoder_start, + .yield = (ProtocolEncoderYield)protocol_paradox_encoder_yield, + }, + .render_data = (ProtocolRenderData)protocol_paradox_render_data, + .render_brief_data = (ProtocolRenderData)protocol_paradox_render_brief_data, + .write_data = (ProtocolWriteData)protocol_paradox_write_data, +}; \ No newline at end of file diff --git a/lib/lfrfid/protocols/protocol_paradox.h b/lib/lfrfid/protocols/protocol_paradox.h new file mode 100644 index 000000000..a80696c35 --- /dev/null +++ b/lib/lfrfid/protocols/protocol_paradox.h @@ -0,0 +1,4 @@ +#pragma once +#include + +extern const ProtocolBase protocol_paradox; \ No newline at end of file diff --git a/lib/lfrfid/protocols/protocol_pyramid.c b/lib/lfrfid/protocols/protocol_pyramid.c new file mode 100644 index 000000000..1bba98718 --- /dev/null +++ b/lib/lfrfid/protocols/protocol_pyramid.c @@ -0,0 +1,281 @@ +#include +#include +#include +#include +#include "lfrfid_protocols.h" +#include + +#define JITTER_TIME (20) +#define MIN_TIME (64 - JITTER_TIME) +#define MAX_TIME (80 + JITTER_TIME) + +#define PYRAMID_DATA_SIZE 13 +#define PYRAMID_PREAMBLE_SIZE 3 + +#define PYRAMID_ENCODED_DATA_SIZE \ + (PYRAMID_PREAMBLE_SIZE + PYRAMID_DATA_SIZE + PYRAMID_PREAMBLE_SIZE) +#define PYRAMID_ENCODED_BIT_SIZE ((PYRAMID_PREAMBLE_SIZE + PYRAMID_DATA_SIZE) * 8) +#define PYRAMID_DECODED_DATA_SIZE (4) +#define PYRAMID_DECODED_BIT_SIZE ((PYRAMID_ENCODED_BIT_SIZE - PYRAMID_PREAMBLE_SIZE * 8) / 2) + +typedef struct { + FSKDemod* fsk_demod; +} ProtocolPyramidDecoder; + +typedef struct { + FSKOsc* fsk_osc; + uint8_t encoded_index; + uint32_t pulse; +} ProtocolPyramidEncoder; + +typedef struct { + ProtocolPyramidDecoder decoder; + ProtocolPyramidEncoder encoder; + uint8_t encoded_data[PYRAMID_ENCODED_DATA_SIZE]; + uint8_t data[PYRAMID_DECODED_DATA_SIZE]; +} ProtocolPyramid; + +ProtocolPyramid* protocol_pyramid_alloc(void) { + ProtocolPyramid* protocol = malloc(sizeof(ProtocolPyramid)); + protocol->decoder.fsk_demod = fsk_demod_alloc(MIN_TIME, 6, MAX_TIME, 5); + protocol->encoder.fsk_osc = fsk_osc_alloc(8, 10, 50); + + return protocol; +}; + +void protocol_pyramid_free(ProtocolPyramid* protocol) { + fsk_demod_free(protocol->decoder.fsk_demod); + fsk_osc_free(protocol->encoder.fsk_osc); + free(protocol); +}; + +uint8_t* protocol_pyramid_get_data(ProtocolPyramid* protocol) { + return protocol->data; +}; + +void protocol_pyramid_decoder_start(ProtocolPyramid* protocol) { + memset(protocol->encoded_data, 0, PYRAMID_ENCODED_DATA_SIZE); +}; + +static bool protocol_pyramid_can_be_decoded(uint8_t* data) { + // check preamble + if(bit_lib_get_bits_16(data, 0, 16) != 0b0000000000000001 || + bit_lib_get_bits(data, 16, 8) != 0b00000001) { + return false; + } + + if(bit_lib_get_bits_16(data, 128, 16) != 0b0000000000000001 || + bit_lib_get_bits(data, 136, 8) != 0b00000001) { + return false; + } + + uint8_t checksum = bit_lib_get_bits(data, 120, 8); + uint8_t checksum_data[13] = {0x00}; + for(uint8_t i = 0; i < 13; i++) { + checksum_data[i] = bit_lib_get_bits(data, 16 + (i * 8), 8); + } + + uint8_t calc_checksum = bit_lib_crc8(checksum_data, 13, 0x31, 0x00, true, true, 0x00); + if(checksum != calc_checksum) return false; + + // Remove parity + bit_lib_remove_bit_every_nth(data, 8, 15 * 8, 8); + + // Determine Startbit and format + int j; + for(j = 0; j < 105; ++j) { + if(bit_lib_get_bit(data, j)) break; + } + uint8_t fmt_len = 105 - j; + + // Only suppport 26bit format for now + if(fmt_len != 26) return false; + + return true; +} + +static void protocol_pyramid_decode(ProtocolPyramid* protocol) { + // Format + bit_lib_set_bits(protocol->data, 0, 26, 8); + + // Facility Code + bit_lib_copy_bits(protocol->data, 8, 8, protocol->encoded_data, 73 + 8); + + // Card Number + bit_lib_copy_bits(protocol->data, 16, 16, protocol->encoded_data, 81 + 8); +} + +bool protocol_pyramid_decoder_feed(ProtocolPyramid* protocol, bool level, uint32_t duration) { + bool value; + uint32_t count; + bool result = false; + + fsk_demod_feed(protocol->decoder.fsk_demod, level, duration, &value, &count); + if(count > 0) { + for(size_t i = 0; i < count; i++) { + bit_lib_push_bit(protocol->encoded_data, PYRAMID_ENCODED_DATA_SIZE, value); + if(protocol_pyramid_can_be_decoded(protocol->encoded_data)) { + protocol_pyramid_decode(protocol); + result = true; + } + } + } + + return result; +}; + +bool protocol_pyramid_get_parity(const uint8_t* bits, uint8_t type, int length) { + int x; + for(x = 0; length > 0; --length) x += bit_lib_get_bit(bits, length - 1); + x %= 2; + return x ^ type; +} + +void protocol_pyramid_add_wiegand_parity( + uint8_t* target, + uint8_t target_position, + uint8_t* source, + uint8_t length) { + bit_lib_set_bit( + target, target_position, protocol_pyramid_get_parity(source, 0 /* even */, length / 2)); + bit_lib_copy_bits(target, target_position + 1, length, source, 0); + bit_lib_set_bit( + target, + target_position + length + 1, + protocol_pyramid_get_parity(source + length / 2, 1 /* odd */, length / 2)); +} + +static void protocol_pyramid_encode(ProtocolPyramid* protocol) { + memset(protocol->encoded_data, 0, sizeof(protocol->encoded_data)); + + uint8_t pre[16]; + memset(pre, 0, sizeof(pre)); + + // Format start bit + bit_lib_set_bit(pre, 79, 1); + + uint8_t wiegand[3]; + memset(wiegand, 0, sizeof(wiegand)); + + // FC + bit_lib_copy_bits(wiegand, 0, 8, protocol->data, 8); + + // CardNum + bit_lib_copy_bits(wiegand, 8, 16, protocol->data, 16); + + // Wiegand parity + protocol_pyramid_add_wiegand_parity(pre, 80, wiegand, 24); + + bit_lib_add_parity(pre, 8, protocol->encoded_data, 8, 102, 8, 1); + + // Add checksum + uint8_t checksum_buffer[13]; + for(uint8_t i = 0; i < 13; i++) + checksum_buffer[i] = bit_lib_get_bits(protocol->encoded_data, 16 + (i * 8), 8); + + uint8_t crc = bit_lib_crc8(checksum_buffer, 13, 0x31, 0x00, true, true, 0x00); + bit_lib_set_bits(protocol->encoded_data, 120, crc, 8); +} + +bool protocol_pyramid_encoder_start(ProtocolPyramid* protocol) { + protocol->encoder.encoded_index = 0; + protocol->encoder.pulse = 0; + protocol_pyramid_encode(protocol); + + return true; +}; + +LevelDuration protocol_pyramid_encoder_yield(ProtocolPyramid* protocol) { + bool level = 0; + uint32_t duration = 0; + + // if pulse is zero, we need to output high, otherwise we need to output low + if(protocol->encoder.pulse == 0) { + // get bit + uint8_t bit = bit_lib_get_bit(protocol->encoded_data, protocol->encoder.encoded_index); + + // get pulse from oscillator + bool advance = fsk_osc_next(protocol->encoder.fsk_osc, bit, &duration); + + if(advance) { + bit_lib_increment_index(protocol->encoder.encoded_index, PYRAMID_ENCODED_BIT_SIZE); + } + + // duration diveded by 2 because we need to output high and low + duration = duration / 2; + protocol->encoder.pulse = duration; + level = true; + } else { + // output low half and reset pulse + duration = protocol->encoder.pulse; + protocol->encoder.pulse = 0; + level = false; + } + + return level_duration_make(level, duration); +}; + +bool protocol_pyramid_write_data(ProtocolPyramid* protocol, void* data) { + LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data; + bool result = false; + + // Correct protocol data by redecoding + protocol_pyramid_encode(protocol); + protocol_pyramid_decode(protocol); + + protocol_pyramid_encoder_start(protocol); + + if(request->write_type == LFRFIDWriteTypeT5577) { + request->t5577.block[0] = LFRFID_T5577_MODULATION_FSK2a | LFRFID_T5577_BITRATE_RF_50 | + (4 << LFRFID_T5577_MAXBLOCK_SHIFT); + request->t5577.block[1] = bit_lib_get_bits_32(protocol->encoded_data, 0, 32); + request->t5577.block[2] = bit_lib_get_bits_32(protocol->encoded_data, 32, 32); + request->t5577.block[3] = bit_lib_get_bits_32(protocol->encoded_data, 64, 32); + request->t5577.block[4] = bit_lib_get_bits_32(protocol->encoded_data, 96, 32); + request->t5577.blocks_to_write = 5; + result = true; + } + return result; +}; + +void protocol_pyramid_render_data(ProtocolPyramid* protocol, string_t result) { + uint8_t* decoded_data = protocol->data; + uint8_t format_length = decoded_data[0]; + + string_cat_printf(result, "Format: 26\r\n", format_length); + if(format_length == 26) { + uint8_t facility; + bit_lib_copy_bits(&facility, 0, 8, decoded_data, 8); + + uint16_t card_id; + bit_lib_copy_bits((uint8_t*)&card_id, 8, 8, decoded_data, 16); + bit_lib_copy_bits((uint8_t*)&card_id, 0, 8, decoded_data, 24); + string_cat_printf(result, "FC: %03u, Card: %05u", facility, card_id); + } else { + string_cat_printf(result, "Data: unknown"); + } +}; + +const ProtocolBase protocol_pyramid = { + .name = "Pyramid", + .manufacturer = "Farpointe", + .data_size = PYRAMID_DECODED_DATA_SIZE, + .features = LFRFIDFeatureASK, + .validate_count = 3, + .alloc = (ProtocolAlloc)protocol_pyramid_alloc, + .free = (ProtocolFree)protocol_pyramid_free, + .get_data = (ProtocolGetData)protocol_pyramid_get_data, + .decoder = + { + .start = (ProtocolDecoderStart)protocol_pyramid_decoder_start, + .feed = (ProtocolDecoderFeed)protocol_pyramid_decoder_feed, + }, + .encoder = + { + .start = (ProtocolEncoderStart)protocol_pyramid_encoder_start, + .yield = (ProtocolEncoderYield)protocol_pyramid_encoder_yield, + }, + .render_data = (ProtocolRenderData)protocol_pyramid_render_data, + .render_brief_data = (ProtocolRenderData)protocol_pyramid_render_data, + .write_data = (ProtocolWriteData)protocol_pyramid_write_data, +}; diff --git a/lib/lfrfid/protocols/protocol_pyramid.h b/lib/lfrfid/protocols/protocol_pyramid.h new file mode 100644 index 000000000..940ecaec2 --- /dev/null +++ b/lib/lfrfid/protocols/protocol_pyramid.h @@ -0,0 +1,4 @@ +#pragma once +#include + +extern const ProtocolBase protocol_pyramid; diff --git a/lib/lfrfid/protocols/protocol_viking.c b/lib/lfrfid/protocols/protocol_viking.c new file mode 100644 index 000000000..f252cc2c3 --- /dev/null +++ b/lib/lfrfid/protocols/protocol_viking.c @@ -0,0 +1,205 @@ +#include +#include +#include +#include +#include "lfrfid_protocols.h" + +#define VIKING_CLOCK_PER_BIT (32) + +#define VIKING_ENCODED_BIT_SIZE (64) +#define VIKING_ENCODED_BYTE_SIZE (((VIKING_ENCODED_BIT_SIZE) / 8)) +#define VIKING_PREAMBLE_BIT_SIZE (24) +#define VIKING_PREAMBLE_BYTE_SIZE (3) +#define VIKING_ENCODED_BYTE_FULL_SIZE (VIKING_ENCODED_BYTE_SIZE + VIKING_PREAMBLE_BYTE_SIZE) +#define VIKING_DECODED_DATA_SIZE 4 + +#define VIKING_READ_SHORT_TIME (128) +#define VIKING_READ_LONG_TIME (256) +#define VIKING_READ_JITTER_TIME (60) + +#define VIKING_READ_SHORT_TIME_LOW (VIKING_READ_SHORT_TIME - VIKING_READ_JITTER_TIME) +#define VIKING_READ_SHORT_TIME_HIGH (VIKING_READ_SHORT_TIME + VIKING_READ_JITTER_TIME) +#define VIKING_READ_LONG_TIME_LOW (VIKING_READ_LONG_TIME - VIKING_READ_JITTER_TIME) +#define VIKING_READ_LONG_TIME_HIGH (VIKING_READ_LONG_TIME + VIKING_READ_JITTER_TIME) + +typedef struct { + uint8_t data[VIKING_DECODED_DATA_SIZE]; + uint8_t encoded_data[VIKING_ENCODED_BYTE_FULL_SIZE]; + + uint8_t encoded_data_index; + bool encoded_polarity; + + ManchesterState decoder_manchester_state; +} ProtocolViking; + +ProtocolViking* protocol_viking_alloc(void) { + ProtocolViking* proto = malloc(sizeof(ProtocolViking)); + return (void*)proto; +}; + +void protocol_viking_free(ProtocolViking* protocol) { + free(protocol); +}; + +uint8_t* protocol_viking_get_data(ProtocolViking* protocol) { + return protocol->data; +}; + +static void protocol_viking_decode(ProtocolViking* protocol) { + // Copy Card ID + bit_lib_copy_bits(protocol->data, 0, 32, protocol->encoded_data, 24); +} + +static bool protocol_viking_can_be_decoded(ProtocolViking* protocol) { + // check 24 bits preamble + if(bit_lib_get_bits_16(protocol->encoded_data, 0, 16) != 0b1111001000000000) return false; + if(bit_lib_get_bits(protocol->encoded_data, 16, 8) != 0b00000000) return false; + + // check next 24 bits preamble + if(bit_lib_get_bits_16(protocol->encoded_data, 64, 16) != 0b1111001000000000) return false; + if(bit_lib_get_bits(protocol->encoded_data, 80, 8) != 0b00000000) return false; + + // Checksum + uint32_t checksum = bit_lib_get_bits(protocol->encoded_data, 0, 8) ^ + bit_lib_get_bits(protocol->encoded_data, 8, 8) ^ + bit_lib_get_bits(protocol->encoded_data, 16, 8) ^ + bit_lib_get_bits(protocol->encoded_data, 24, 8) ^ + bit_lib_get_bits(protocol->encoded_data, 32, 8) ^ + bit_lib_get_bits(protocol->encoded_data, 40, 8) ^ + bit_lib_get_bits(protocol->encoded_data, 48, 8) ^ + bit_lib_get_bits(protocol->encoded_data, 56, 8) ^ 0xA8; + if(checksum != 0) return false; + + return true; +} + +void protocol_viking_decoder_start(ProtocolViking* protocol) { + memset(protocol->encoded_data, 0, VIKING_ENCODED_BYTE_FULL_SIZE); + manchester_advance( + protocol->decoder_manchester_state, + ManchesterEventReset, + &protocol->decoder_manchester_state, + NULL); +}; + +bool protocol_viking_decoder_feed(ProtocolViking* protocol, bool level, uint32_t duration) { + bool result = false; + + ManchesterEvent event = ManchesterEventReset; + + if(duration > VIKING_READ_SHORT_TIME_LOW && duration < VIKING_READ_SHORT_TIME_HIGH) { + if(!level) { + event = ManchesterEventShortHigh; + } else { + event = ManchesterEventShortLow; + } + } else if(duration > VIKING_READ_LONG_TIME_LOW && duration < VIKING_READ_LONG_TIME_HIGH) { + if(!level) { + event = ManchesterEventLongHigh; + } else { + event = ManchesterEventLongLow; + } + } + + if(event != ManchesterEventReset) { + bool data; + bool data_ok = manchester_advance( + protocol->decoder_manchester_state, event, &protocol->decoder_manchester_state, &data); + + if(data_ok) { + bit_lib_push_bit(protocol->encoded_data, VIKING_ENCODED_BYTE_FULL_SIZE, data); + + if(protocol_viking_can_be_decoded(protocol)) { + protocol_viking_decode(protocol); + result = true; + } + } + } + + return result; +}; + +bool protocol_viking_encoder_start(ProtocolViking* protocol) { + // Preamble + bit_lib_set_bits(protocol->encoded_data, 0, 0b11110010, 8); + bit_lib_set_bits(protocol->encoded_data, 8, 0b00000000, 8); + bit_lib_set_bits(protocol->encoded_data, 16, 0b00000000, 8); + + // Card Id + bit_lib_copy_bits(protocol->encoded_data, 24, 32, protocol->data, 0); + + // Checksum + uint32_t id = bit_lib_get_bits_32(protocol->data, 0, 32); + uint8_t checksum = ((id >> 24) & 0xFF) ^ ((id >> 16) & 0xFF) ^ ((id >> 8) & 0xFF) ^ + (id & 0xFF) ^ 0xF2 ^ 0xA8; + bit_lib_set_bits(protocol->encoded_data, 56, checksum, 8); + + return true; +}; + +LevelDuration protocol_viking_encoder_yield(ProtocolViking* protocol) { + bool level = bit_lib_get_bit(protocol->encoded_data, protocol->encoded_data_index); + uint32_t duration = VIKING_CLOCK_PER_BIT / 2; + + if(protocol->encoded_polarity) { + protocol->encoded_polarity = false; + } else { + level = !level; + + protocol->encoded_polarity = true; + bit_lib_increment_index(protocol->encoded_data_index, VIKING_ENCODED_BIT_SIZE); + } + + return level_duration_make(level, duration); +}; + +bool protocol_viking_write_data(ProtocolViking* protocol, void* data) { + LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data; + bool result = false; + + // Correct protocol data by redecoding + protocol_viking_encoder_start(protocol); + protocol_viking_decode(protocol); + + protocol_viking_encoder_start(protocol); + + if(request->write_type == LFRFIDWriteTypeT5577) { + request->t5577.block[0] = + (LFRFID_T5577_MODULATION_MANCHESTER | LFRFID_T5577_BITRATE_RF_32 | + (2 << LFRFID_T5577_MAXBLOCK_SHIFT)); + request->t5577.block[1] = bit_lib_get_bits_32(protocol->encoded_data, 0, 32); + request->t5577.block[2] = bit_lib_get_bits_32(protocol->encoded_data, 32, 32); + request->t5577.blocks_to_write = 3; + result = true; + } + return result; +}; + +void protocol_viking_render_data(ProtocolViking* protocol, string_t result) { + uint32_t id = bit_lib_get_bits_32(protocol->data, 0, 32); + string_printf(result, "ID: %08lX\r\n", id); +}; + +const ProtocolBase protocol_viking = { + .name = "Viking", + .manufacturer = "Viking", + .data_size = VIKING_DECODED_DATA_SIZE, + .features = LFRFIDFeatureASK, + .validate_count = 3, + .alloc = (ProtocolAlloc)protocol_viking_alloc, + .free = (ProtocolFree)protocol_viking_free, + .get_data = (ProtocolGetData)protocol_viking_get_data, + .decoder = + { + .start = (ProtocolDecoderStart)protocol_viking_decoder_start, + .feed = (ProtocolDecoderFeed)protocol_viking_decoder_feed, + }, + .encoder = + { + .start = (ProtocolEncoderStart)protocol_viking_encoder_start, + .yield = (ProtocolEncoderYield)protocol_viking_encoder_yield, + }, + .render_data = (ProtocolRenderData)protocol_viking_render_data, + .render_brief_data = (ProtocolRenderData)protocol_viking_render_data, + .write_data = (ProtocolWriteData)protocol_viking_write_data, +}; \ No newline at end of file diff --git a/lib/lfrfid/protocols/protocol_viking.h b/lib/lfrfid/protocols/protocol_viking.h new file mode 100644 index 000000000..3286e03a7 --- /dev/null +++ b/lib/lfrfid/protocols/protocol_viking.h @@ -0,0 +1,4 @@ +#pragma once +#include + +extern const ProtocolBase protocol_viking; diff --git a/lib/lfrfid/tools/bit_lib.c b/lib/lfrfid/tools/bit_lib.c index b57bda8a8..c84f4b7ed 100644 --- a/lib/lfrfid/tools/bit_lib.c +++ b/lib/lfrfid/tools/bit_lib.c @@ -129,6 +129,45 @@ bool bit_lib_test_parity( return result; } +size_t bit_lib_add_parity( + const uint8_t* data, + size_t position, + uint8_t* dest, + size_t dest_position, + uint8_t source_length, + uint8_t parity_length, + BitLibParity parity) { + uint32_t parity_word = 0; + size_t j = 0, bit_count = 0; + for(int word = 0; word < source_length; word += parity_length - 1) { + for(int bit = 0; bit < parity_length - 1; bit++) { + parity_word = (parity_word << 1) | bit_lib_get_bit(data, position + word + bit); + bit_lib_set_bit( + dest, dest_position + j++, bit_lib_get_bit(data, position + word + bit)); + } + // if parity fails then return 0 + switch(parity) { + case BitLibParityAlways0: + bit_lib_set_bit(dest, dest_position + j++, 0); + break; // marker bit which should be a 0 + case BitLibParityAlways1: + bit_lib_set_bit(dest, dest_position + j++, 1); + break; // marker bit which should be a 1 + default: + bit_lib_set_bit( + dest, + dest_position + j++, + (bit_lib_test_parity_32(parity_word, BitLibParityOdd) ^ parity) ^ 1); + break; + } + bit_count += parity_length; + parity_word = 0; + } + // if we got here then all the parities passed + // return bit count + return bit_count; +} + size_t bit_lib_remove_bit_every_nth(uint8_t* data, size_t position, uint8_t length, uint8_t n) { size_t counter = 0; size_t result_counter = 0; @@ -262,6 +301,43 @@ uint16_t bit_lib_reverse_16_fast(uint16_t data) { return result; } +uint8_t bit_lib_reverse_8_fast(uint8_t byte) { + byte = (byte & 0xF0) >> 4 | (byte & 0x0F) << 4; + byte = (byte & 0xCC) >> 2 | (byte & 0x33) << 2; + byte = (byte & 0xAA) >> 1 | (byte & 0x55) << 1; + return byte; +} + +uint16_t bit_lib_crc8( + uint8_t const* data, + size_t data_size, + uint8_t polynom, + uint8_t init, + bool ref_in, + bool ref_out, + uint8_t xor_out) { + uint8_t crc = init; + + for(size_t i = 0; i < data_size; ++i) { + uint8_t byte = data[i]; + if(ref_in) bit_lib_reverse_bits(&byte, 0, 8); + crc ^= byte; + + for(size_t j = 8; j > 0; --j) { + if(crc & TOPBIT(8)) { + crc = (crc << 1) ^ polynom; + } else { + crc = (crc << 1); + } + } + } + + if(ref_out) bit_lib_reverse_bits(&crc, 0, 8); + crc ^= xor_out; + + return crc; +} + uint16_t bit_lib_crc16( uint8_t const* data, size_t data_size, diff --git a/lib/lfrfid/tools/bit_lib.h b/lib/lfrfid/tools/bit_lib.h index 24aae0e9c..1b048db35 100644 --- a/lib/lfrfid/tools/bit_lib.h +++ b/lib/lfrfid/tools/bit_lib.h @@ -7,6 +7,8 @@ extern "C" { #endif +#define TOPBIT(X) (1 << (X - 1)) + typedef enum { BitLibParityEven, BitLibParityOdd, @@ -114,6 +116,27 @@ bool bit_lib_test_parity( BitLibParity parity, uint8_t parity_length); +/** + * @brief Add parity to bit array + * + * @param data Source bit array + * @param position Start position + * @param dest Destination bit array + * @param dest_position Destination position + * @param source_length Source bit count + * @param parity_length Parity block length + * @param parity Parity to test against + * @return size_t + */ +size_t bit_lib_add_parity( + const uint8_t* data, + size_t position, + uint8_t* dest, + size_t dest_position, + uint8_t source_length, + uint8_t parity_length, + BitLibParity parity); + /** * @brief Remove bit every n in array and shift array left. Useful to remove parity. * @@ -194,6 +217,35 @@ void bit_lib_print_regions( */ uint16_t bit_lib_reverse_16_fast(uint16_t data); +/** + * @brief Reverse bits in uint8_t, faster than generic bit_lib_reverse_bits. + * + * @param byte Byte + * @return uint8_t the reversed byte + */ +uint8_t bit_lib_reverse_8_fast(uint8_t byte); + +/** + * @brief Slow, but generic CRC8 implementation + * + * @param data + * @param data_size + * @param polynom CRC polynom + * @param init init value + * @param ref_in true if the right bit is older + * @param ref_out true to reverse output + * @param xor_out xor output with this value + * @return uint8_t + */ +uint16_t bit_lib_crc8( + uint8_t const* data, + size_t data_size, + uint8_t polynom, + uint8_t init, + bool ref_in, + bool ref_out, + uint8_t xor_out); + /** * @brief Slow, but generic CRC16 implementation * diff --git a/lib/lfs_config.h b/lib/lfs_config.h index 59b3c486e..ff8bc4b23 100644 --- a/lib/lfs_config.h +++ b/lib/lfs_config.h @@ -5,21 +5,26 @@ #ifdef FURI_NDEBUG #define LFS_NO_ASSERT #define LFS_ASSERT(x) -#else +#else #define LFS_ASSERT furi_assert #endif #define LFS_TAG "Lfs" +#ifdef FURI_LFS_DEBUG #define LFS_TRACE(...) FURI_LOG_T(LFS_TAG, __VA_ARGS__); #define LFS_DEBUG(...) FURI_LOG_D(LFS_TAG, __VA_ARGS__); +#else +#define LFS_TRACE(...) + +#define LFS_DEBUG(...) +#endif // FURI_LFS_DEBUG #define LFS_WARN(...) FURI_LOG_W(LFS_TAG, __VA_ARGS__); #define LFS_ERROR(...) FURI_LOG_E(LFS_TAG, __VA_ARGS__); - // Because crc #undef LFS_CONFIG @@ -35,16 +40,13 @@ #ifndef LFS_NO_ASSERT #include #endif -#if !defined(LFS_NO_DEBUG) || \ - !defined(LFS_NO_WARN) || \ - !defined(LFS_NO_ERROR) || \ - defined(LFS_YES_TRACE) +#if !defined(LFS_NO_DEBUG) || !defined(LFS_NO_WARN) || !defined(LFS_NO_ERROR) || \ + defined(LFS_YES_TRACE) #include #endif #ifdef __cplusplus -extern "C" -{ +extern "C" { #endif // Builtin functions, these may be replaced by more efficient @@ -66,21 +68,29 @@ static inline uint32_t lfs_aligndown(uint32_t a, uint32_t alignment) { } static inline uint32_t lfs_alignup(uint32_t a, uint32_t alignment) { - return lfs_aligndown(a + alignment-1, alignment); + return lfs_aligndown(a + alignment - 1, alignment); } // Find the smallest power of 2 greater than or equal to a static inline uint32_t lfs_npw2(uint32_t a) { #if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM)) - return 32 - __builtin_clz(a-1); + return 32 - __builtin_clz(a - 1); #else uint32_t r = 0; uint32_t s; a -= 1; - s = (a > 0xffff) << 4; a >>= s; r |= s; - s = (a > 0xff ) << 3; a >>= s; r |= s; - s = (a > 0xf ) << 2; a >>= s; r |= s; - s = (a > 0x3 ) << 1; a >>= s; r |= s; + s = (a > 0xffff) << 4; + a >>= s; + r |= s; + s = (a > 0xff) << 3; + a >>= s; + r |= s; + s = (a > 0xf) << 2; + a >>= s; + r |= s; + s = (a > 0x3) << 1; + a >>= s; + r |= s; return (r | (a >> 1)) + 1; #endif } @@ -114,20 +124,23 @@ static inline int lfs_scmp(uint32_t a, uint32_t b) { // Convert between 32-bit little-endian and native order static inline uint32_t lfs_fromle32(uint32_t a) { -#if !defined(LFS_NO_INTRINSICS) && ( \ - (defined( BYTE_ORDER ) && defined( ORDER_LITTLE_ENDIAN ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \ - (defined(__BYTE_ORDER ) && defined(__ORDER_LITTLE_ENDIAN ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \ - (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) +#if !defined(LFS_NO_INTRINSICS) && \ + ((defined(BYTE_ORDER) && defined(ORDER_LITTLE_ENDIAN) && \ + BYTE_ORDER == ORDER_LITTLE_ENDIAN) || \ + (defined(__BYTE_ORDER) && defined(__ORDER_LITTLE_ENDIAN) && \ + __BYTE_ORDER == __ORDER_LITTLE_ENDIAN) || \ + (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \ + __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) return a; -#elif !defined(LFS_NO_INTRINSICS) && ( \ - (defined( BYTE_ORDER ) && defined( ORDER_BIG_ENDIAN ) && BYTE_ORDER == ORDER_BIG_ENDIAN ) || \ - (defined(__BYTE_ORDER ) && defined(__ORDER_BIG_ENDIAN ) && __BYTE_ORDER == __ORDER_BIG_ENDIAN ) || \ - (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) +#elif !defined(LFS_NO_INTRINSICS) && \ + ((defined(BYTE_ORDER) && defined(ORDER_BIG_ENDIAN) && BYTE_ORDER == ORDER_BIG_ENDIAN) || \ + (defined(__BYTE_ORDER) && defined(__ORDER_BIG_ENDIAN) && \ + __BYTE_ORDER == __ORDER_BIG_ENDIAN) || \ + (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \ + __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) return __builtin_bswap32(a); #else - return (((uint8_t*)&a)[0] << 0) | - (((uint8_t*)&a)[1] << 8) | - (((uint8_t*)&a)[2] << 16) | + return (((uint8_t*)&a)[0] << 0) | (((uint8_t*)&a)[1] << 8) | (((uint8_t*)&a)[2] << 16) | (((uint8_t*)&a)[3] << 24); #endif } @@ -138,21 +151,24 @@ static inline uint32_t lfs_tole32(uint32_t a) { // Convert between 32-bit big-endian and native order static inline uint32_t lfs_frombe32(uint32_t a) { -#if !defined(LFS_NO_INTRINSICS) && ( \ - (defined( BYTE_ORDER ) && defined( ORDER_LITTLE_ENDIAN ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \ - (defined(__BYTE_ORDER ) && defined(__ORDER_LITTLE_ENDIAN ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \ - (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) +#if !defined(LFS_NO_INTRINSICS) && \ + ((defined(BYTE_ORDER) && defined(ORDER_LITTLE_ENDIAN) && \ + BYTE_ORDER == ORDER_LITTLE_ENDIAN) || \ + (defined(__BYTE_ORDER) && defined(__ORDER_LITTLE_ENDIAN) && \ + __BYTE_ORDER == __ORDER_LITTLE_ENDIAN) || \ + (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \ + __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) return __builtin_bswap32(a); -#elif !defined(LFS_NO_INTRINSICS) && ( \ - (defined( BYTE_ORDER ) && defined( ORDER_BIG_ENDIAN ) && BYTE_ORDER == ORDER_BIG_ENDIAN ) || \ - (defined(__BYTE_ORDER ) && defined(__ORDER_BIG_ENDIAN ) && __BYTE_ORDER == __ORDER_BIG_ENDIAN ) || \ - (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) +#elif !defined(LFS_NO_INTRINSICS) && \ + ((defined(BYTE_ORDER) && defined(ORDER_BIG_ENDIAN) && BYTE_ORDER == ORDER_BIG_ENDIAN) || \ + (defined(__BYTE_ORDER) && defined(__ORDER_BIG_ENDIAN) && \ + __BYTE_ORDER == __ORDER_BIG_ENDIAN) || \ + (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \ + __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) return a; #else - return (((uint8_t*)&a)[0] << 24) | - (((uint8_t*)&a)[1] << 16) | - (((uint8_t*)&a)[2] << 8) | - (((uint8_t*)&a)[3] << 0); + return (((uint8_t*)&a)[0] << 24) | (((uint8_t*)&a)[1] << 16) | (((uint8_t*)&a)[2] << 8) | + (((uint8_t*)&a)[3] << 0); #endif } @@ -161,11 +177,11 @@ static inline uint32_t lfs_tobe32(uint32_t a) { } // Calculate CRC-32 with polynomial = 0x04c11db7 -uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size); +uint32_t lfs_crc(uint32_t crc, const void* buffer, size_t size); // Allocate memory, only used if buffers are not provided to littlefs // Note, memory must be 64-bit aligned -static inline void *lfs_malloc(size_t size) { +static inline void* lfs_malloc(size_t size) { #ifndef LFS_NO_MALLOC return malloc(size); #else @@ -175,7 +191,7 @@ static inline void *lfs_malloc(size_t size) { } // Deallocate memory, only used if buffers are not provided to littlefs -static inline void lfs_free(void *p) { +static inline void lfs_free(void* p) { #ifndef LFS_NO_MALLOC free(p); #else @@ -183,7 +199,6 @@ static inline void lfs_free(void *p) { #endif } - #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/lib/littlefs b/lib/littlefs index 1863dc788..40dba4a55 160000 --- a/lib/littlefs +++ b/lib/littlefs @@ -1 +1 @@ -Subproject commit 1863dc7883d82bd6ca79faa164b65341064d1c16 +Subproject commit 40dba4a556e0d81dfbe64301a6aa4e18ceca896c diff --git a/lib/loclass.scons b/lib/loclass.scons deleted file mode 100644 index a657f0424..000000000 --- a/lib/loclass.scons +++ /dev/null @@ -1,17 +0,0 @@ -Import("env") - -env.Append( - CPPPATH=[ - "#/lib/loclass", - ], -) - - -libenv = env.Clone(FW_LIB_NAME="loclass") -libenv.ApplyLibFlags() - -sources = Glob("loclass/*.c", source=True) - -lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) -libenv.Install("${LIB_DIST_DIR}", lib) -Return("lib") diff --git a/lib/mbedtls.scons b/lib/mbedtls.scons index e39d9dae8..b57221a49 100644 --- a/lib/mbedtls.scons +++ b/lib/mbedtls.scons @@ -11,6 +11,14 @@ env.Append( libenv = env.Clone(FW_LIB_NAME="mbedtls") libenv.ApplyLibFlags() +libenv.AppendUnique( + CCFLAGS=[ + # Required for lib to be linkable with .faps + "-mword-relocations", + "-mlong-calls", + ], +) + sources = [ "mbedtls/library/des.c", "mbedtls/library/sha1.c", diff --git a/lib/misc.scons b/lib/misc.scons index 5a826b18d..b7d8554b5 100644 --- a/lib/misc.scons +++ b/lib/misc.scons @@ -12,6 +12,9 @@ env.Append( CPPDEFINES=[ "PB_ENABLE_MALLOC", ], + SDK_HEADERS=[ + File("#/lib/micro-ecc/uECC.h"), + ], ) diff --git a/lib/nfc/helpers/mf_classic_dict.c b/lib/nfc/helpers/mf_classic_dict.c index 410ddbd8b..a615e7899 100644 --- a/lib/nfc/helpers/mf_classic_dict.c +++ b/lib/nfc/helpers/mf_classic_dict.c @@ -86,38 +86,30 @@ void mf_classic_dict_free(MfClassicDict* dict) { free(dict); } +static void mf_classic_dict_int_to_str(uint8_t* key_int, string_t key_str) { + string_reset(key_str); + for(size_t i = 0; i < 6; i++) { + string_cat_printf(key_str, "%02X", key_int[i]); + } +} + +static void mf_classic_dict_str_to_int(string_t key_str, uint64_t* key_int) { + uint8_t key_byte_tmp; + + *key_int = 0ULL; + for(uint8_t i = 0; i < 12; i += 2) { + args_char_to_hex( + string_get_char(key_str, i), string_get_char(key_str, i + 1), &key_byte_tmp); + *key_int |= (uint8_t)key_byte_tmp << 8 * (5 - i / 2); + } +} + uint32_t mf_classic_dict_get_total_keys(MfClassicDict* dict) { furi_assert(dict); return dict->total_keys; } -bool mf_classic_dict_get_next_key(MfClassicDict* dict, uint64_t* key) { - furi_assert(dict); - furi_assert(dict->stream); - - uint8_t key_byte_tmp = 0; - string_t next_line; - string_init(next_line); - - bool key_read = false; - *key = 0ULL; - while(!key_read) { - if(!stream_read_line(dict->stream, next_line)) break; - if(string_get_char(next_line, 0) == '#') continue; - if(string_size(next_line) != NFC_MF_CLASSIC_KEY_LEN) continue; - for(uint8_t i = 0; i < 12; i += 2) { - args_char_to_hex( - string_get_char(next_line, i), string_get_char(next_line, i + 1), &key_byte_tmp); - *key |= (uint64_t)key_byte_tmp << 8 * (5 - i / 2); - } - key_read = true; - } - - string_clear(next_line); - return key_read; -} - bool mf_classic_dict_rewind(MfClassicDict* dict) { furi_assert(dict); furi_assert(dict->stream); @@ -125,24 +117,194 @@ bool mf_classic_dict_rewind(MfClassicDict* dict) { return stream_rewind(dict->stream); } -bool mf_classic_dict_add_key(MfClassicDict* dict, uint8_t* key) { +bool mf_classic_dict_get_next_key_str(MfClassicDict* dict, string_t key) { furi_assert(dict); furi_assert(dict->stream); - string_t key_str; - string_init(key_str); - for(size_t i = 0; i < 6; i++) { - string_cat_printf(key_str, "%02X", key[i]); + bool key_read = false; + string_reset(key); + while(!key_read) { + if(!stream_read_line(dict->stream, key)) break; + if(string_get_char(key, 0) == '#') continue; + if(string_size(key) != NFC_MF_CLASSIC_KEY_LEN) continue; + string_left(key, 12); + key_read = true; } - string_cat_printf(key_str, "\n"); + + return key_read; +} + +bool mf_classic_dict_get_next_key(MfClassicDict* dict, uint64_t* key) { + furi_assert(dict); + furi_assert(dict->stream); + + string_t temp_key; + string_init(temp_key); + bool key_read = mf_classic_dict_get_next_key_str(dict, temp_key); + if(key_read) { + mf_classic_dict_str_to_int(temp_key, key); + } + string_clear(temp_key); + return key_read; +} + +bool mf_classic_dict_is_key_present_str(MfClassicDict* dict, string_t key) { + furi_assert(dict); + furi_assert(dict->stream); + + string_t next_line; + string_init(next_line); + + bool key_found = false; + stream_rewind(dict->stream); + while(!key_found) { + if(!stream_read_line(dict->stream, next_line)) break; + if(string_get_char(next_line, 0) == '#') continue; + if(string_size(next_line) != NFC_MF_CLASSIC_KEY_LEN) continue; + string_left(next_line, 12); + if(!string_equal_p(key, next_line)) continue; + key_found = true; + } + + string_clear(next_line); + return key_found; +} + +bool mf_classic_dict_is_key_present(MfClassicDict* dict, uint8_t* key) { + string_t temp_key; + + string_init(temp_key); + mf_classic_dict_int_to_str(key, temp_key); + bool key_found = mf_classic_dict_is_key_present_str(dict, temp_key); + string_clear(temp_key); + return key_found; +} + +bool mf_classic_dict_add_key_str(MfClassicDict* dict, string_t key) { + furi_assert(dict); + furi_assert(dict->stream); + + string_cat_printf(key, "\n"); bool key_added = false; do { if(!stream_seek(dict->stream, 0, StreamOffsetFromEnd)) break; - if(!stream_insert_string(dict->stream, key_str)) break; + if(!stream_insert_string(dict->stream, key)) break; + dict->total_keys++; key_added = true; } while(false); - string_clear(key_str); + string_left(key, 12); return key_added; } + +bool mf_classic_dict_add_key(MfClassicDict* dict, uint8_t* key) { + furi_assert(dict); + furi_assert(dict->stream); + + string_t temp_key; + string_init(temp_key); + mf_classic_dict_int_to_str(key, temp_key); + bool key_added = mf_classic_dict_add_key_str(dict, temp_key); + + string_clear(temp_key); + return key_added; +} + +bool mf_classic_dict_get_key_at_index_str(MfClassicDict* dict, string_t key, uint32_t target) { + furi_assert(dict); + furi_assert(dict->stream); + + string_t next_line; + uint32_t index = 0; + string_init(next_line); + string_reset(key); + + bool key_found = false; + while(!key_found) { + if(!stream_read_line(dict->stream, next_line)) break; + if(string_get_char(next_line, 0) == '#') continue; + if(string_size(next_line) != NFC_MF_CLASSIC_KEY_LEN) continue; + if(index++ != target) continue; + string_set_n(key, next_line, 0, 12); + key_found = true; + } + + string_clear(next_line); + return key_found; +} + +bool mf_classic_dict_get_key_at_index(MfClassicDict* dict, uint64_t* key, uint32_t target) { + furi_assert(dict); + furi_assert(dict->stream); + + string_t temp_key; + string_init(temp_key); + bool key_found = mf_classic_dict_get_key_at_index_str(dict, temp_key, target); + if(key_found) { + mf_classic_dict_str_to_int(temp_key, key); + } + string_clear(temp_key); + return key_found; +} + +bool mf_classic_dict_find_index_str(MfClassicDict* dict, string_t key, uint32_t* target) { + furi_assert(dict); + furi_assert(dict->stream); + + string_t next_line; + string_init(next_line); + + bool key_found = false; + uint32_t index = 0; + stream_rewind(dict->stream); + while(!key_found) { + if(!stream_read_line(dict->stream, next_line)) break; + if(string_get_char(next_line, 0) == '#') continue; + if(string_size(next_line) != NFC_MF_CLASSIC_KEY_LEN) continue; + string_left(next_line, 12); + if(!string_equal_p(key, next_line)) continue; + key_found = true; + *target = index; + } + + string_clear(next_line); + return key_found; +} + +bool mf_classic_dict_find_index(MfClassicDict* dict, uint8_t* key, uint32_t* target) { + furi_assert(dict); + furi_assert(dict->stream); + + string_t temp_key; + string_init(temp_key); + mf_classic_dict_int_to_str(key, temp_key); + bool key_found = mf_classic_dict_find_index_str(dict, temp_key, target); + + string_clear(temp_key); + return key_found; +} + +bool mf_classic_dict_delete_index(MfClassicDict* dict, uint32_t target) { + furi_assert(dict); + furi_assert(dict->stream); + + string_t next_line; + string_init(next_line); + uint32_t index = 0; + + bool key_removed = false; + while(!key_removed) { + if(!stream_read_line(dict->stream, next_line)) break; + if(string_get_char(next_line, 0) == '#') continue; + if(string_size(next_line) != NFC_MF_CLASSIC_KEY_LEN) continue; + if(index++ != target) continue; + stream_seek(dict->stream, -NFC_MF_CLASSIC_KEY_LEN, StreamOffsetFromCurrent); + if(!stream_delete(dict->stream, NFC_MF_CLASSIC_KEY_LEN)) break; + dict->total_keys--; + key_removed = true; + } + + string_clear(next_line); + return key_removed; +} diff --git a/lib/nfc/helpers/mf_classic_dict.h b/lib/nfc/helpers/mf_classic_dict.h index 2654e668c..aaea3c400 100644 --- a/lib/nfc/helpers/mf_classic_dict.h +++ b/lib/nfc/helpers/mf_classic_dict.h @@ -21,8 +21,26 @@ void mf_classic_dict_free(MfClassicDict* dict); uint32_t mf_classic_dict_get_total_keys(MfClassicDict* dict); -bool mf_classic_dict_get_next_key(MfClassicDict* dict, uint64_t* key); - bool mf_classic_dict_rewind(MfClassicDict* dict); +bool mf_classic_dict_is_key_present(MfClassicDict* dict, uint8_t* key); + +bool mf_classic_dict_is_key_present_str(MfClassicDict* dict, string_t key); + +bool mf_classic_dict_get_next_key(MfClassicDict* dict, uint64_t* key); + +bool mf_classic_dict_get_next_key_str(MfClassicDict* dict, string_t key); + +bool mf_classic_dict_get_key_at_index(MfClassicDict* dict, uint64_t* key, uint32_t target); + +bool mf_classic_dict_get_key_at_index_str(MfClassicDict* dict, string_t key, uint32_t target); + bool mf_classic_dict_add_key(MfClassicDict* dict, uint8_t* key); + +bool mf_classic_dict_add_key_str(MfClassicDict* dict, string_t key); + +bool mf_classic_dict_find_index(MfClassicDict* dict, uint8_t* key, uint32_t* target); + +bool mf_classic_dict_find_index_str(MfClassicDict* dict, string_t key, uint32_t* target); + +bool mf_classic_dict_delete_index(MfClassicDict* dict, uint32_t target); diff --git a/lib/nfc/helpers/mfkey32.c b/lib/nfc/helpers/mfkey32.c new file mode 100644 index 000000000..64b06e259 --- /dev/null +++ b/lib/nfc/helpers/mfkey32.c @@ -0,0 +1,230 @@ +#include "mfkey32.h" + +#include +#include +#include +#include +#include + +#include +#include + +#define TAG "Mfkey32" + +#define MFKEY32_LOGS_PATH EXT_PATH("nfc/.mfkey32.log") + +typedef enum { + Mfkey32StateIdle, + Mfkey32StateAuthReceived, + Mfkey32StateAuthNtSent, + Mfkey32StateAuthArNrReceived, +} Mfkey32State; + +typedef struct { + uint32_t cuid; + uint8_t sector; + MfClassicKey key; + uint32_t nt0; + uint32_t nr0; + uint32_t ar0; + uint32_t nt1; + uint32_t nr1; + uint32_t ar1; +} Mfkey32Params; + +ARRAY_DEF(Mfkey32Params, Mfkey32Params, M_POD_OPLIST); + +typedef struct { + uint8_t sector; + MfClassicKey key; + uint32_t nt; + uint32_t nr; + uint32_t ar; +} Mfkey32Nonce; + +struct Mfkey32 { + Mfkey32State state; + Stream* file_stream; + Mfkey32Params_t params_arr; + Mfkey32Nonce nonce; + uint32_t cuid; + Mfkey32ParseDataCallback callback; + void* context; +}; + +Mfkey32* mfkey32_alloc(uint32_t cuid) { + Mfkey32* instance = malloc(sizeof(Mfkey32)); + instance->cuid = cuid; + instance->state = Mfkey32StateIdle; + Storage* storage = furi_record_open(RECORD_STORAGE); + instance->file_stream = buffered_file_stream_alloc(storage); + if(!buffered_file_stream_open( + instance->file_stream, MFKEY32_LOGS_PATH, FSAM_WRITE, FSOM_OPEN_APPEND)) { + buffered_file_stream_close(instance->file_stream); + stream_free(instance->file_stream); + free(instance); + instance = NULL; + } else { + Mfkey32Params_init(instance->params_arr); + } + + furi_record_close(RECORD_STORAGE); + + return instance; +} + +void mfkey32_free(Mfkey32* instance) { + furi_assert(instance != NULL); + + Mfkey32Params_clear(instance->params_arr); + buffered_file_stream_close(instance->file_stream); + stream_free(instance->file_stream); + free(instance); +} + +void mfkey32_set_callback(Mfkey32* instance, Mfkey32ParseDataCallback callback, void* context) { + furi_assert(instance); + furi_assert(callback); + + instance->callback = callback; + instance->context = context; +} + +static bool mfkey32_write_params(Mfkey32* instance, Mfkey32Params* params) { + string_t str; + string_init_printf( + str, + "Sector %d key %c cuid %08x nt0 %08x nr0 %08x ar0 %08x nt1 %08x nr1 %08x ar1 %08x\n", + params->sector, + params->key == MfClassicKeyA ? 'A' : 'B', + params->cuid, + params->nt0, + params->nr0, + params->ar0, + params->nt1, + params->nr1, + params->ar1); + bool write_success = stream_write_string(instance->file_stream, str); + string_clear(str); + return write_success; +} + +static void mfkey32_add_params(Mfkey32* instance) { + Mfkey32Nonce* nonce = &instance->nonce; + bool nonce_added = false; + // Search if we partially collected params + if(Mfkey32Params_size(instance->params_arr)) { + Mfkey32Params_it_t it; + for(Mfkey32Params_it(it, instance->params_arr); !Mfkey32Params_end_p(it); + Mfkey32Params_next(it)) { + Mfkey32Params* params = Mfkey32Params_ref(it); + if((params->sector == nonce->sector) && (params->key == nonce->key)) { + params->nt1 = nonce->nt; + params->nr1 = nonce->nr; + params->ar1 = nonce->ar; + nonce_added = true; + FURI_LOG_I( + TAG, + "Params for sector %d key %c collected", + params->sector, + params->key == MfClassicKeyA ? 'A' : 'B'); + // Write on sd card + if(mfkey32_write_params(instance, params)) { + Mfkey32Params_remove(instance->params_arr, it); + if(instance->callback) { + instance->callback(Mfkey32EventParamCollected, instance->context); + } + } + } + } + } + if(!nonce_added) { + Mfkey32Params params = { + .sector = nonce->sector, + .key = nonce->key, + .cuid = instance->cuid, + .nt0 = nonce->nt, + .nr0 = nonce->nr, + .ar0 = nonce->ar, + }; + Mfkey32Params_push_back(instance->params_arr, params); + } +} + +void mfkey32_process_data( + Mfkey32* instance, + uint8_t* data, + uint16_t len, + bool reader_to_tag, + bool crc_dropped) { + furi_assert(instance); + furi_assert(data); + + Mfkey32Nonce* nonce = &instance->nonce; + uint16_t data_len = len; + if((data_len > 3) && !crc_dropped) { + data_len -= 2; + } + + bool data_processed = false; + if(instance->state == Mfkey32StateIdle) { + if(reader_to_tag) { + if((data[0] == 0x60) || (data[0] == 0x61)) { + nonce->key = data[0] == 0x60 ? MfClassicKeyA : MfClassicKeyB; + nonce->sector = mf_classic_get_sector_by_block(data[1]); + instance->state = Mfkey32StateAuthReceived; + data_processed = true; + } + } + } else if(instance->state == Mfkey32StateAuthReceived) { + if(!reader_to_tag) { + if(len == 4) { + nonce->nt = nfc_util_bytes2num(data, 4); + instance->state = Mfkey32StateAuthNtSent; + data_processed = true; + } + } + } else if(instance->state == Mfkey32StateAuthNtSent) { + if(reader_to_tag) { + if(len == 8) { + nonce->nr = nfc_util_bytes2num(data, 4); + nonce->ar = nfc_util_bytes2num(&data[4], 4); + mfkey32_add_params(instance); + instance->state = Mfkey32StateIdle; + } + } + } + if(!data_processed) { + instance->state = Mfkey32StateIdle; + } +} + +uint16_t mfkey32_get_auth_sectors(string_t data_str) { + furi_assert(data_str); + + uint16_t nonces_num = 0; + Storage* storage = furi_record_open(RECORD_STORAGE); + Stream* file_stream = buffered_file_stream_alloc(storage); + string_t temp_str; + string_init(temp_str); + + do { + if(!buffered_file_stream_open( + file_stream, MFKEY32_LOGS_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) + break; + while(true) { + if(!stream_read_line(file_stream, temp_str)) break; + size_t uid_pos = string_search_str(temp_str, "cuid"); + string_left(temp_str, uid_pos); + string_push_back(temp_str, '\n'); + string_cat(data_str, temp_str); + nonces_num++; + } + } while(false); + + buffered_file_stream_close(file_stream); + stream_free(file_stream); + string_clear(temp_str); + + return nonces_num; +} diff --git a/lib/nfc/helpers/mfkey32.h b/lib/nfc/helpers/mfkey32.h new file mode 100644 index 000000000..c4f13cc2c --- /dev/null +++ b/lib/nfc/helpers/mfkey32.h @@ -0,0 +1,27 @@ +#pragma once + +#include +#include + +typedef struct Mfkey32 Mfkey32; + +typedef enum { + Mfkey32EventParamCollected, +} Mfkey32Event; + +typedef void (*Mfkey32ParseDataCallback)(Mfkey32Event event, void* context); + +Mfkey32* mfkey32_alloc(uint32_t cuid); + +void mfkey32_free(Mfkey32* instance); + +void mfkey32_process_data( + Mfkey32* instance, + uint8_t* data, + uint16_t len, + bool reader_to_tag, + bool crc_dropped); + +void mfkey32_set_callback(Mfkey32* instance, Mfkey32ParseDataCallback callback, void* context); + +uint16_t mfkey32_get_auth_sectors(string_t string); diff --git a/lib/nfc/helpers/nfc_debug_log.c b/lib/nfc/helpers/nfc_debug_log.c new file mode 100644 index 000000000..1cbc5224f --- /dev/null +++ b/lib/nfc/helpers/nfc_debug_log.c @@ -0,0 +1,72 @@ +#include "nfc_debug_log.h" + +#include +#include +#include + +#define TAG "NfcDebugLog" + +#define NFC_DEBUG_PCAP_FILENAME EXT_PATH("nfc/debug.txt") + +struct NfcDebugLog { + Stream* file_stream; + string_t data_str; +}; + +NfcDebugLog* nfc_debug_log_alloc() { + NfcDebugLog* instance = malloc(sizeof(NfcDebugLog)); + + Storage* storage = furi_record_open(RECORD_STORAGE); + instance->file_stream = buffered_file_stream_alloc(storage); + + if(!buffered_file_stream_open( + instance->file_stream, NFC_DEBUG_PCAP_FILENAME, FSAM_WRITE, FSOM_OPEN_APPEND)) { + buffered_file_stream_close(instance->file_stream); + stream_free(instance->file_stream); + instance->file_stream = NULL; + } + + if(!instance->file_stream) { + free(instance); + instance = NULL; + } else { + string_init(instance->data_str); + } + furi_record_close(RECORD_STORAGE); + + return instance; +} + +void nfc_debug_log_free(NfcDebugLog* instance) { + furi_assert(instance); + furi_assert(instance->file_stream); + furi_assert(instance->data_str); + + buffered_file_stream_close(instance->file_stream); + stream_free(instance->file_stream); + string_clear(instance->data_str); + + free(instance); +} + +void nfc_debug_log_process_data( + NfcDebugLog* instance, + uint8_t* data, + uint16_t len, + bool reader_to_tag, + bool crc_dropped) { + furi_assert(instance); + furi_assert(instance->file_stream); + furi_assert(instance->data_str); + furi_assert(data); + UNUSED(crc_dropped); + + string_printf(instance->data_str, "%lu %c:", furi_get_tick(), reader_to_tag ? 'R' : 'T'); + uint16_t data_len = len; + for(size_t i = 0; i < data_len; i++) { + string_cat_printf(instance->data_str, " %02x", data[i]); + } + string_push_back(instance->data_str, '\n'); + + stream_write_string(instance->file_stream, instance->data_str); +} diff --git a/lib/nfc/helpers/nfc_debug_log.h b/lib/nfc/helpers/nfc_debug_log.h new file mode 100644 index 000000000..261b8008b --- /dev/null +++ b/lib/nfc/helpers/nfc_debug_log.h @@ -0,0 +1,17 @@ +#pragma once + +#include +#include + +typedef struct NfcDebugLog NfcDebugLog; + +NfcDebugLog* nfc_debug_log_alloc(); + +void nfc_debug_log_free(NfcDebugLog* instance); + +void nfc_debug_log_process_data( + NfcDebugLog* instance, + uint8_t* data, + uint16_t len, + bool reader_to_tag, + bool crc_dropped); diff --git a/lib/nfc/helpers/nfc_debug_pcap.c b/lib/nfc/helpers/nfc_debug_pcap.c index 48d72bfbf..6c7654ad5 100644 --- a/lib/nfc/helpers/nfc_debug_pcap.c +++ b/lib/nfc/helpers/nfc_debug_pcap.c @@ -1,7 +1,9 @@ #include "nfc_debug_pcap.h" +#include +#include +#include #include -#include #define TAG "NfcDebugPcap" @@ -16,48 +18,94 @@ #define DATA_PCD_TO_PICC_CRC_DROPPED 0xFA #define NFC_DEBUG_PCAP_FILENAME EXT_PATH("nfc/debug.pcap") -#define NFC_DEBUG_PCAP_BUFFER_SIZE 64 -struct NfcDebugPcapWorker { - bool alive; - Storage* storage; - File* file; - StreamBufferHandle_t stream; - FuriThread* thread; +struct NfcDebugPcap { + Stream* file_stream; }; -static File* nfc_debug_pcap_open(Storage* storage) { - File* file = storage_file_alloc(storage); - if(!storage_file_open(file, NFC_DEBUG_PCAP_FILENAME, FSAM_WRITE, FSOM_OPEN_APPEND)) { - storage_file_free(file); - return NULL; - } - if(!storage_file_tell(file)) { - struct { - uint32_t magic; - uint16_t major, minor; - uint32_t reserved[2]; - uint32_t snaplen; - uint32_t link_type; - } __attribute__((__packed__)) pcap_hdr = { - .magic = PCAP_MAGIC, - .major = PCAP_MAJOR, - .minor = PCAP_MINOR, - .snaplen = FURI_HAL_NFC_DATA_BUFF_SIZE, - .link_type = DLT_ISO_14443, - }; - if(storage_file_write(file, &pcap_hdr, sizeof(pcap_hdr)) != sizeof(pcap_hdr)) { - FURI_LOG_E(TAG, "Failed to write pcap header"); +static Stream* nfc_debug_pcap_open(Storage* storage) { + Stream* stream = NULL; + stream = buffered_file_stream_alloc(storage); + if(!buffered_file_stream_open(stream, NFC_DEBUG_PCAP_FILENAME, FSAM_WRITE, FSOM_OPEN_APPEND)) { + buffered_file_stream_close(stream); + stream_free(stream); + stream = NULL; + } else { + if(!stream_tell(stream)) { + struct { + uint32_t magic; + uint16_t major, minor; + uint32_t reserved[2]; + uint32_t snaplen; + uint32_t link_type; + } __attribute__((__packed__)) pcap_hdr = { + .magic = PCAP_MAGIC, + .major = PCAP_MAJOR, + .minor = PCAP_MINOR, + .snaplen = FURI_HAL_NFC_DATA_BUFF_SIZE, + .link_type = DLT_ISO_14443, + }; + if(stream_write(stream, (uint8_t*)&pcap_hdr, sizeof(pcap_hdr)) != sizeof(pcap_hdr)) { + FURI_LOG_E(TAG, "Failed to write pcap header"); + buffered_file_stream_close(stream); + stream_free(stream); + stream = NULL; + } } } - return file; + return stream; } -static void - nfc_debug_pcap_write(NfcDebugPcapWorker* instance, uint8_t event, uint8_t* data, uint16_t len) { +NfcDebugPcap* nfc_debug_pcap_alloc() { + NfcDebugPcap* instance = malloc(sizeof(NfcDebugPcap)); + + Storage* storage = furi_record_open(RECORD_STORAGE); + instance->file_stream = nfc_debug_pcap_open(storage); + if(!instance->file_stream) { + free(instance); + instance = NULL; + } + furi_record_close(RECORD_STORAGE); + + return instance; +} + +void nfc_debug_pcap_free(NfcDebugPcap* instance) { + furi_assert(instance); + furi_assert(instance->file_stream); + + buffered_file_stream_close(instance->file_stream); + stream_free(instance->file_stream); + + free(instance); +} + +void nfc_debug_pcap_process_data( + NfcDebugPcap* instance, + uint8_t* data, + uint16_t len, + bool reader_to_tag, + bool crc_dropped) { + furi_assert(instance); + furi_assert(data); FuriHalRtcDateTime datetime; furi_hal_rtc_get_datetime(&datetime); + uint8_t event = 0; + if(reader_to_tag) { + if(crc_dropped) { + event = DATA_PCD_TO_PICC_CRC_DROPPED; + } else { + event = DATA_PCD_TO_PICC; + } + } else { + if(crc_dropped) { + event = DATA_PICC_TO_PCD_CRC_DROPPED; + } else { + event = DATA_PICC_TO_PCD; + } + } + struct { // https://wiki.wireshark.org/Development/LibpcapFileFormat#record-packet-header uint32_t ts_sec; @@ -77,90 +125,6 @@ static void .event = event, .len = len << 8 | len >> 8, }; - xStreamBufferSend(instance->stream, &pkt_hdr, sizeof(pkt_hdr), FuriWaitForever); - xStreamBufferSend(instance->stream, data, len, FuriWaitForever); -} - -static void - nfc_debug_pcap_write_tx(uint8_t* data, uint16_t bits, bool crc_dropped, void* context) { - NfcDebugPcapWorker* instance = context; - uint8_t event = crc_dropped ? DATA_PCD_TO_PICC_CRC_DROPPED : DATA_PCD_TO_PICC; - nfc_debug_pcap_write(instance, event, data, bits / 8); -} - -static void - nfc_debug_pcap_write_rx(uint8_t* data, uint16_t bits, bool crc_dropped, void* context) { - NfcDebugPcapWorker* instance = context; - uint8_t event = crc_dropped ? DATA_PICC_TO_PCD_CRC_DROPPED : DATA_PICC_TO_PCD; - nfc_debug_pcap_write(instance, event, data, bits / 8); -} - -int32_t nfc_debug_pcap_thread(void* context) { - NfcDebugPcapWorker* instance = context; - uint8_t buffer[NFC_DEBUG_PCAP_BUFFER_SIZE]; - - while(instance->alive) { - size_t ret = - xStreamBufferReceive(instance->stream, buffer, NFC_DEBUG_PCAP_BUFFER_SIZE, 50); - if(storage_file_write(instance->file, buffer, ret) != ret) { - FURI_LOG_E(TAG, "Failed to write pcap data"); - } - } - - return 0; -} - -NfcDebugPcapWorker* nfc_debug_pcap_alloc(Storage* storage) { - NfcDebugPcapWorker* instance = malloc(sizeof(NfcDebugPcapWorker)); - - instance->alive = true; - - instance->storage = storage; - - instance->file = nfc_debug_pcap_open(storage); - - instance->stream = xStreamBufferCreate(4096, 1); - - instance->thread = furi_thread_alloc(); - furi_thread_set_name(instance->thread, "PcapWorker"); - furi_thread_set_stack_size(instance->thread, 1024); - furi_thread_set_callback(instance->thread, nfc_debug_pcap_thread); - furi_thread_set_context(instance->thread, instance); - furi_thread_start(instance->thread); - - return instance; -} - -void nfc_debug_pcap_free(NfcDebugPcapWorker* instance) { - furi_assert(instance); - - instance->alive = false; - - furi_thread_join(instance->thread); - furi_thread_free(instance->thread); - - vStreamBufferDelete(instance->stream); - - if(instance->file) storage_file_free(instance->file); - - instance->storage = NULL; - - free(instance); -} - -void nfc_debug_pcap_prepare_tx_rx( - NfcDebugPcapWorker* instance, - FuriHalNfcTxRxContext* tx_rx, - bool is_picc) { - if(!instance || !instance->file) return; - - if(is_picc) { - tx_rx->sniff_tx = nfc_debug_pcap_write_rx; - tx_rx->sniff_rx = nfc_debug_pcap_write_tx; - } else { - tx_rx->sniff_tx = nfc_debug_pcap_write_tx; - tx_rx->sniff_rx = nfc_debug_pcap_write_rx; - } - - tx_rx->sniff_context = instance; + stream_write(instance->file_stream, (uint8_t*)&pkt_hdr, sizeof(pkt_hdr)); + stream_write(instance->file_stream, data, len); } diff --git a/lib/nfc/helpers/nfc_debug_pcap.h b/lib/nfc/helpers/nfc_debug_pcap.h index 6d2a449ae..eeddc5611 100644 --- a/lib/nfc/helpers/nfc_debug_pcap.h +++ b/lib/nfc/helpers/nfc_debug_pcap.h @@ -1,21 +1,17 @@ #pragma once -#include -#include +#include +#include -typedef struct NfcDebugPcapWorker NfcDebugPcapWorker; +typedef struct NfcDebugPcap NfcDebugPcap; -NfcDebugPcapWorker* nfc_debug_pcap_alloc(Storage* storage); +NfcDebugPcap* nfc_debug_pcap_alloc(); -void nfc_debug_pcap_free(NfcDebugPcapWorker* instance); +void nfc_debug_pcap_free(NfcDebugPcap* instance); -/** Prepare tx/rx context for debug pcap logging, if enabled. - * - * @param instance NfcDebugPcapWorker* instance, can be NULL - * @param tx_rx TX/RX context to log - * @param is_picc if true, record Flipper as PICC, else PCD. - */ -void nfc_debug_pcap_prepare_tx_rx( - NfcDebugPcapWorker* instance, - FuriHalNfcTxRxContext* tx_rx, - bool is_picc); +void nfc_debug_pcap_process_data( + NfcDebugPcap* instance, + uint8_t* data, + uint16_t len, + bool reader_to_tag, + bool crc_dropped); diff --git a/lib/nfc/helpers/reader_analyzer.c b/lib/nfc/helpers/reader_analyzer.c new file mode 100644 index 000000000..680b8cef9 --- /dev/null +++ b/lib/nfc/helpers/reader_analyzer.c @@ -0,0 +1,261 @@ +#include "reader_analyzer.h" +#include +#include +#include +#include + +#include "mfkey32.h" +#include "nfc_debug_pcap.h" +#include "nfc_debug_log.h" + +#define TAG "ReaderAnalyzer" + +#define READER_ANALYZER_MAX_BUFF_SIZE (1024) + +typedef struct { + bool reader_to_tag; + bool crc_dropped; + uint16_t len; +} ReaderAnalyzerHeader; + +typedef enum { + ReaderAnalyzerNfcDataMfClassic, +} ReaderAnalyzerNfcData; + +struct ReaderAnalyzer { + FuriHalNfcDevData nfc_data; + + bool alive; + StreamBufferHandle_t stream; + FuriThread* thread; + + ReaderAnalyzerParseDataCallback callback; + void* context; + + ReaderAnalyzerMode mode; + Mfkey32* mfkey32; + NfcDebugLog* debug_log; + NfcDebugPcap* pcap; +}; + +const FuriHalNfcDevData reader_analyzer_nfc_data[] = { + [ReaderAnalyzerNfcDataMfClassic] = + {.sak = 0x08, + .atqa = {0x44, 0x00}, + .interface = FuriHalNfcInterfaceRf, + .type = FuriHalNfcTypeA, + .uid_len = 7, + .uid = {0x04, 0x77, 0x70, 0x2A, 0x23, 0x4F, 0x80}, + .cuid = 0x2A234F80}, +}; + +void reader_analyzer_parse(ReaderAnalyzer* instance, uint8_t* buffer, size_t size) { + if(size < sizeof(ReaderAnalyzerHeader)) return; + + size_t bytes_i = 0; + while(bytes_i < size) { + ReaderAnalyzerHeader* header = (ReaderAnalyzerHeader*)&buffer[bytes_i]; + uint16_t len = header->len; + if(bytes_i + len > size) break; + bytes_i += sizeof(ReaderAnalyzerHeader); + if(instance->mfkey32) { + mfkey32_process_data( + instance->mfkey32, + &buffer[bytes_i], + len, + header->reader_to_tag, + header->crc_dropped); + } + if(instance->pcap) { + nfc_debug_pcap_process_data( + instance->pcap, &buffer[bytes_i], len, header->reader_to_tag, header->crc_dropped); + } + if(instance->debug_log) { + nfc_debug_log_process_data( + instance->debug_log, + &buffer[bytes_i], + len, + header->reader_to_tag, + header->crc_dropped); + } + bytes_i += len; + } +} + +int32_t reader_analyzer_thread(void* context) { + ReaderAnalyzer* reader_analyzer = context; + uint8_t buffer[READER_ANALYZER_MAX_BUFF_SIZE] = {}; + + while(reader_analyzer->alive || !xStreamBufferIsEmpty(reader_analyzer->stream)) { + size_t ret = xStreamBufferReceive( + reader_analyzer->stream, buffer, READER_ANALYZER_MAX_BUFF_SIZE, 50); + if(ret) { + reader_analyzer_parse(reader_analyzer, buffer, ret); + } + } + + return 0; +} + +ReaderAnalyzer* reader_analyzer_alloc() { + ReaderAnalyzer* instance = malloc(sizeof(ReaderAnalyzer)); + + instance->nfc_data = reader_analyzer_nfc_data[ReaderAnalyzerNfcDataMfClassic]; + instance->alive = false; + instance->stream = + xStreamBufferCreate(READER_ANALYZER_MAX_BUFF_SIZE, sizeof(ReaderAnalyzerHeader)); + + instance->thread = furi_thread_alloc(); + furi_thread_set_name(instance->thread, "ReaderAnalyzerWorker"); + furi_thread_set_stack_size(instance->thread, 2048); + furi_thread_set_callback(instance->thread, reader_analyzer_thread); + furi_thread_set_context(instance->thread, instance); + furi_thread_set_priority(instance->thread, FuriThreadPriorityLow); + + return instance; +} + +static void reader_analyzer_mfkey_callback(Mfkey32Event event, void* context) { + furi_assert(context); + ReaderAnalyzer* instance = context; + + if(event == Mfkey32EventParamCollected) { + if(instance->callback) { + instance->callback(ReaderAnalyzerEventMfkeyCollected, instance->context); + } + } +} + +void reader_analyzer_start(ReaderAnalyzer* instance, ReaderAnalyzerMode mode) { + furi_assert(instance); + + xStreamBufferReset(instance->stream); + if(mode & ReaderAnalyzerModeDebugLog) { + instance->debug_log = nfc_debug_log_alloc(); + } + if(mode & ReaderAnalyzerModeMfkey) { + instance->mfkey32 = mfkey32_alloc(instance->nfc_data.cuid); + if(instance->mfkey32) { + mfkey32_set_callback(instance->mfkey32, reader_analyzer_mfkey_callback, instance); + } + } + if(mode & ReaderAnalyzerModeDebugPcap) { + instance->pcap = nfc_debug_pcap_alloc(); + } + + instance->alive = true; + furi_thread_start(instance->thread); +} + +void reader_analyzer_stop(ReaderAnalyzer* instance) { + furi_assert(instance); + + instance->alive = false; + furi_thread_join(instance->thread); + + if(instance->debug_log) { + nfc_debug_log_free(instance->debug_log); + instance->debug_log = NULL; + } + if(instance->mfkey32) { + mfkey32_free(instance->mfkey32); + instance->mfkey32 = NULL; + } + if(instance->pcap) { + nfc_debug_pcap_free(instance->pcap); + } +} + +void reader_analyzer_free(ReaderAnalyzer* instance) { + furi_assert(instance); + + reader_analyzer_stop(instance); + furi_thread_free(instance->thread); + vStreamBufferDelete(instance->stream); + free(instance); +} + +void reader_analyzer_set_callback( + ReaderAnalyzer* instance, + ReaderAnalyzerParseDataCallback callback, + void* context) { + furi_assert(instance); + furi_assert(callback); + + instance->callback = callback; + instance->context = context; +} + +NfcProtocol + reader_analyzer_guess_protocol(ReaderAnalyzer* instance, uint8_t* buff_rx, uint16_t len) { + furi_assert(instance); + furi_assert(buff_rx); + UNUSED(len); + NfcProtocol protocol = NfcDeviceProtocolUnknown; + + if((buff_rx[0] == 0x60) || (buff_rx[0] == 0x61)) { + protocol = NfcDeviceProtocolMifareClassic; + } + + return protocol; +} + +FuriHalNfcDevData* reader_analyzer_get_nfc_data(ReaderAnalyzer* instance) { + furi_assert(instance); + + return &instance->nfc_data; +} + +static void reader_analyzer_write( + ReaderAnalyzer* instance, + uint8_t* data, + uint16_t len, + bool reader_to_tag, + bool crc_dropped) { + ReaderAnalyzerHeader header = { + .reader_to_tag = reader_to_tag, .crc_dropped = crc_dropped, .len = len}; + size_t data_sent = 0; + data_sent = xStreamBufferSend( + instance->stream, &header, sizeof(ReaderAnalyzerHeader), FuriWaitForever); + if(data_sent != sizeof(ReaderAnalyzerHeader)) { + FURI_LOG_W(TAG, "Sent %d out of %d bytes", data_sent, sizeof(ReaderAnalyzerHeader)); + } + data_sent = xStreamBufferSend(instance->stream, data, len, FuriWaitForever); + if(data_sent != len) { + FURI_LOG_W(TAG, "Sent %d out of %d bytes", data_sent, len); + } +} + +static void + reader_analyzer_write_rx(uint8_t* data, uint16_t bits, bool crc_dropped, void* context) { + UNUSED(crc_dropped); + ReaderAnalyzer* reader_analyzer = context; + uint16_t bytes = bits < 8 ? 1 : bits / 8; + reader_analyzer_write(reader_analyzer, data, bytes, false, crc_dropped); +} + +static void + reader_analyzer_write_tx(uint8_t* data, uint16_t bits, bool crc_dropped, void* context) { + UNUSED(crc_dropped); + ReaderAnalyzer* reader_analyzer = context; + uint16_t bytes = bits < 8 ? 1 : bits / 8; + reader_analyzer_write(reader_analyzer, data, bytes, true, crc_dropped); +} + +void reader_analyzer_prepare_tx_rx( + ReaderAnalyzer* instance, + FuriHalNfcTxRxContext* tx_rx, + bool is_picc) { + furi_assert(instance); + furi_assert(tx_rx); + + if(is_picc) { + tx_rx->sniff_tx = reader_analyzer_write_rx; + tx_rx->sniff_rx = reader_analyzer_write_tx; + } else { + tx_rx->sniff_rx = reader_analyzer_write_rx; + tx_rx->sniff_tx = reader_analyzer_write_tx; + } + + tx_rx->sniff_context = instance; +} diff --git a/lib/nfc/helpers/reader_analyzer.h b/lib/nfc/helpers/reader_analyzer.h new file mode 100644 index 000000000..cc501f5a6 --- /dev/null +++ b/lib/nfc/helpers/reader_analyzer.h @@ -0,0 +1,41 @@ +#pragma once + +#include +#include + +typedef enum { + ReaderAnalyzerModeDebugLog = 0x01, + ReaderAnalyzerModeMfkey = 0x02, + ReaderAnalyzerModeDebugPcap = 0x04, +} ReaderAnalyzerMode; + +typedef enum { + ReaderAnalyzerEventMfkeyCollected, +} ReaderAnalyzerEvent; + +typedef struct ReaderAnalyzer ReaderAnalyzer; + +typedef void (*ReaderAnalyzerParseDataCallback)(ReaderAnalyzerEvent event, void* context); + +ReaderAnalyzer* reader_analyzer_alloc(); + +void reader_analyzer_free(ReaderAnalyzer* instance); + +void reader_analyzer_set_callback( + ReaderAnalyzer* instance, + ReaderAnalyzerParseDataCallback callback, + void* context); + +void reader_analyzer_start(ReaderAnalyzer* instance, ReaderAnalyzerMode mode); + +void reader_analyzer_stop(ReaderAnalyzer* instance); + +NfcProtocol + reader_analyzer_guess_protocol(ReaderAnalyzer* instance, uint8_t* buff_rx, uint16_t len); + +FuriHalNfcDevData* reader_analyzer_get_nfc_data(ReaderAnalyzer* instance); + +void reader_analyzer_prepare_tx_rx( + ReaderAnalyzer* instance, + FuriHalNfcTxRxContext* tx_rx, + bool is_picc); diff --git a/lib/nfc/nfc_device.c b/lib/nfc/nfc_device.c index 0bfdb3dac..dd78e2daf 100644 --- a/lib/nfc/nfc_device.c +++ b/lib/nfc/nfc_device.c @@ -195,6 +195,7 @@ bool nfc_device_load_mifare_ul_data(FlipperFormat* file, NfcDevice* dev) { } data->data_size = pages_total * 4; data->data_read = pages_read * 4; + if(data->data_size > MF_UL_MAX_DUMP_SIZE || data->data_read > MF_UL_MAX_DUMP_SIZE) break; bool pages_parsed = true; for(uint16_t i = 0; i < pages_total; i++) { string_printf(temp_str, "Page %d", i); @@ -782,7 +783,7 @@ static void nfc_device_load_mifare_classic_block( char hi = string_get_char(block_str, 3 * i); char low = string_get_char(block_str, 3 * i + 1); uint8_t byte = 0; - if(hex_chars_to_uint8(hi, low, &byte)) { + if(hex_char_to_uint8(hi, low, &byte)) { block_tmp.value[i] = byte; } else { FURI_BIT_SET(block_unknown_bytes_mask, i); @@ -1181,8 +1182,19 @@ bool nfc_file_select(NfcDevice* dev) { // Input events and views are managed by file_browser string_t nfc_app_folder; string_init_set_str(nfc_app_folder, NFC_APP_FOLDER); - bool res = dialog_file_browser_show( - dev->dialogs, dev->load_path, nfc_app_folder, NFC_APP_EXTENSION, true, &I_Nfc_10px, true); + + const DialogsFileBrowserOptions browser_options = { + .extension = NFC_APP_EXTENSION, + .skip_assets = true, + .icon = &I_Nfc_10px, + .hide_ext = true, + .item_loader_callback = NULL, + .item_loader_context = NULL, + }; + + bool res = + dialog_file_browser_show(dev->dialogs, dev->load_path, nfc_app_folder, &browser_options); + string_clear(nfc_app_folder); if(res) { string_t filename; diff --git a/lib/nfc/nfc_worker.c b/lib/nfc/nfc_worker.c index f07ea616c..2feae443f 100644 --- a/lib/nfc/nfc_worker.c +++ b/lib/nfc/nfc_worker.c @@ -28,9 +28,7 @@ NfcWorker* nfc_worker_alloc() { } nfc_worker_change_state(nfc_worker, NfcWorkerStateReady); - if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { - nfc_worker->debug_pcap_worker = nfc_debug_pcap_alloc(nfc_worker->storage); - } + nfc_worker->reader_analyzer = reader_analyzer_alloc(nfc_worker->storage); return nfc_worker; } @@ -42,7 +40,7 @@ void nfc_worker_free(NfcWorker* nfc_worker) { furi_record_close(RECORD_STORAGE); - if(nfc_worker->debug_pcap_worker) nfc_debug_pcap_free(nfc_worker->debug_pcap_worker); + reader_analyzer_free(nfc_worker->reader_analyzer); free(nfc_worker); } @@ -105,6 +103,8 @@ int32_t nfc_worker_task(void* context) { nfc_worker_mf_ultralight_read_auth(nfc_worker); } else if(nfc_worker->state == NfcWorkerStateMfClassicDictAttack) { nfc_worker_mf_classic_dict_attack(nfc_worker); + } else if(nfc_worker->state == NfcWorkerStateAnalyzeReader) { + nfc_worker_analyze_reader(nfc_worker); } furi_hal_nfc_sleep(); nfc_worker_change_state(nfc_worker, NfcWorkerStateReady); @@ -117,9 +117,31 @@ static bool nfc_worker_read_mf_ultralight(NfcWorker* nfc_worker, FuriHalNfcTxRxC MfUltralightReader reader = {}; MfUltralightData data = {}; - nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, tx_rx, false); + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + reader_analyzer_prepare_tx_rx(nfc_worker->reader_analyzer, tx_rx, false); + reader_analyzer_start(nfc_worker->reader_analyzer, ReaderAnalyzerModeDebugLog); + } + do { - // Read card + // Try to read supported card + FURI_LOG_I(TAG, "Trying to read a supported card ..."); + for(size_t i = 0; i < NfcSupportedCardTypeEnd; i++) { + if(nfc_supported_card[i].protocol == NfcDeviceProtocolMifareUl) { + if(nfc_supported_card[i].verify(nfc_worker, tx_rx)) { + if(nfc_supported_card[i].read(nfc_worker, tx_rx)) { + read_success = true; + nfc_supported_card[i].parse(nfc_worker->dev_data); + break; + } + } else { + furi_hal_nfc_sleep(); + } + } + } + if(read_success) break; + furi_hal_nfc_sleep(); + + // Otherwise, try to read as usual if(!furi_hal_nfc_detect(&nfc_worker->dev_data->nfc_data, 200)) break; if(!mf_ul_read_card(tx_rx, &reader, &data)) break; // Copy data @@ -127,6 +149,10 @@ static bool nfc_worker_read_mf_ultralight(NfcWorker* nfc_worker, FuriHalNfcTxRxC read_success = true; } while(false); + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + reader_analyzer_stop(nfc_worker->reader_analyzer); + } + return read_success; } @@ -134,17 +160,24 @@ static bool nfc_worker_read_mf_classic(NfcWorker* nfc_worker, FuriHalNfcTxRxCont furi_assert(nfc_worker->callback); bool read_success = false; - nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, tx_rx, false); + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + reader_analyzer_prepare_tx_rx(nfc_worker->reader_analyzer, tx_rx, false); + reader_analyzer_start(nfc_worker->reader_analyzer, ReaderAnalyzerModeDebugLog); + } + do { // Try to read supported card - FURI_LOG_I(TAG, "Try read supported card ..."); + FURI_LOG_I(TAG, "Trying to read a supported card ..."); for(size_t i = 0; i < NfcSupportedCardTypeEnd; i++) { if(nfc_supported_card[i].protocol == NfcDeviceProtocolMifareClassic) { if(nfc_supported_card[i].verify(nfc_worker, tx_rx)) { if(nfc_supported_card[i].read(nfc_worker, tx_rx)) { read_success = true; nfc_supported_card[i].parse(nfc_worker->dev_data); + break; } + } else { + furi_hal_nfc_sleep(); } } } @@ -162,6 +195,9 @@ static bool nfc_worker_read_mf_classic(NfcWorker* nfc_worker, FuriHalNfcTxRxCont } } while(false); + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + reader_analyzer_stop(nfc_worker->reader_analyzer); + } return read_success; } @@ -169,13 +205,21 @@ static bool nfc_worker_read_mf_desfire(NfcWorker* nfc_worker, FuriHalNfcTxRxCont bool read_success = false; MifareDesfireData* data = &nfc_worker->dev_data->mf_df_data; - nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, tx_rx, false); + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + reader_analyzer_prepare_tx_rx(nfc_worker->reader_analyzer, tx_rx, false); + reader_analyzer_start(nfc_worker->reader_analyzer, ReaderAnalyzerModeDebugLog); + } + do { if(!furi_hal_nfc_detect(&nfc_worker->dev_data->nfc_data, 300)) break; if(!mf_df_read_card(tx_rx, data)) break; read_success = true; } while(false); + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + reader_analyzer_stop(nfc_worker->reader_analyzer); + } + return read_success; } @@ -184,7 +228,11 @@ static bool nfc_worker_read_bank_card(NfcWorker* nfc_worker, FuriHalNfcTxRxConte EmvApplication emv_app = {}; EmvData* result = &nfc_worker->dev_data->emv_data; - nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, tx_rx, false); + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + reader_analyzer_prepare_tx_rx(nfc_worker->reader_analyzer, tx_rx, false); + reader_analyzer_start(nfc_worker->reader_analyzer, ReaderAnalyzerModeDebugLog); + } + do { // Read card if(!furi_hal_nfc_detect(&nfc_worker->dev_data->nfc_data, 300)) break; @@ -211,6 +259,10 @@ static bool nfc_worker_read_bank_card(NfcWorker* nfc_worker, FuriHalNfcTxRxConte read_success = true; } while(false); + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + reader_analyzer_stop(nfc_worker->reader_analyzer); + } + return read_success; } @@ -320,18 +372,14 @@ void nfc_worker_read(NfcWorker* nfc_worker) { void nfc_worker_emulate_uid(NfcWorker* nfc_worker) { FuriHalNfcTxRxContext tx_rx = {}; - nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, &tx_rx, true); FuriHalNfcDevData* data = &nfc_worker->dev_data->nfc_data; NfcReaderRequestData* reader_data = &nfc_worker->dev_data->reader_data; // TODO add support for RATS - // Now remove bit 6 in SAK to support ISO-14443A-3 emulation // Need to save ATS to support ISO-14443A-4 emulation - uint8_t sak = data->sak; - FURI_BIT_CLEAR(sak, 5); while(nfc_worker->state == NfcWorkerStateUidEmulate) { - if(furi_hal_nfc_listen(data->uid, data->uid_len, data->atqa, sak, true, 100)) { + if(furi_hal_nfc_listen(data->uid, data->uid_len, data->atqa, data->sak, false, 100)) { if(furi_hal_nfc_tx_rx(&tx_rx, 100)) { reader_data->size = tx_rx.rx_bits / 8; if(reader_data->size > 0) { @@ -349,7 +397,6 @@ void nfc_worker_emulate_uid(NfcWorker* nfc_worker) { void nfc_worker_emulate_apdu(NfcWorker* nfc_worker) { FuriHalNfcTxRxContext tx_rx = {}; - nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, &tx_rx, true); FuriHalNfcDevData params = { .uid = {0xCF, 0x72, 0xd4, 0x40}, .uid_len = 4, @@ -358,6 +405,11 @@ void nfc_worker_emulate_apdu(NfcWorker* nfc_worker) { .type = FuriHalNfcTypeA, }; + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + reader_analyzer_prepare_tx_rx(nfc_worker->reader_analyzer, &tx_rx, true); + reader_analyzer_start(nfc_worker->reader_analyzer, ReaderAnalyzerModeDebugLog); + } + while(nfc_worker->state == NfcWorkerStateEmulateApdu) { if(furi_hal_nfc_listen(params.uid, params.uid_len, params.atqa, params.sak, false, 300)) { FURI_LOG_D(TAG, "POS terminal detected"); @@ -370,6 +422,10 @@ void nfc_worker_emulate_apdu(NfcWorker* nfc_worker) { furi_hal_nfc_sleep(); furi_delay_ms(20); } + + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + reader_analyzer_stop(nfc_worker->reader_analyzer); + } } void nfc_worker_emulate_mf_ultralight(NfcWorker* nfc_worker) { @@ -484,7 +540,6 @@ void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker) { void nfc_worker_emulate_mf_classic(NfcWorker* nfc_worker) { FuriHalNfcTxRxContext tx_rx = {}; - nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, &tx_rx, true); FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; MfClassicEmulator emulator = { .cuid = nfc_util_bytes2num(&nfc_data->uid[nfc_data->uid_len - 4], 4), @@ -525,6 +580,11 @@ void nfc_worker_mf_ultralight_read_auth(NfcWorker* nfc_worker) { MfUltralightReader reader = {}; mf_ul_reset(data); + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + reader_analyzer_prepare_tx_rx(nfc_worker->reader_analyzer, &tx_rx, true); + reader_analyzer_start(nfc_worker->reader_analyzer, ReaderAnalyzerModeDebugLog); + } + uint32_t key = 0; uint16_t pack = 0; while(nfc_worker->state == NfcWorkerStateReadMfUltralightReadAuth) { @@ -577,4 +637,61 @@ void nfc_worker_mf_ultralight_read_auth(NfcWorker* nfc_worker) { furi_delay_ms(10); } } + + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + reader_analyzer_stop(nfc_worker->reader_analyzer); + } +} + +static void nfc_worker_reader_analyzer_callback(ReaderAnalyzerEvent event, void* context) { + furi_assert(context); + NfcWorker* nfc_worker = context; + + if(event == ReaderAnalyzerEventMfkeyCollected) { + if(nfc_worker->callback) { + nfc_worker->callback(NfcWorkerEventDetectReaderMfkeyCollected, nfc_worker->context); + } + } +} + +void nfc_worker_analyze_reader(NfcWorker* nfc_worker) { + FuriHalNfcTxRxContext tx_rx = {}; + + ReaderAnalyzer* reader_analyzer = nfc_worker->reader_analyzer; + FuriHalNfcDevData* nfc_data = reader_analyzer_get_nfc_data(reader_analyzer); + MfClassicEmulator emulator = { + .cuid = nfc_util_bytes2num(&nfc_data->uid[nfc_data->uid_len - 4], 4), + .data = nfc_worker->dev_data->mf_classic_data, + .data_changed = false, + }; + NfcaSignal* nfca_signal = nfca_signal_alloc(); + tx_rx.nfca_signal = nfca_signal; + reader_analyzer_prepare_tx_rx(reader_analyzer, &tx_rx, true); + reader_analyzer_start(nfc_worker->reader_analyzer, ReaderAnalyzerModeMfkey); + reader_analyzer_set_callback(reader_analyzer, nfc_worker_reader_analyzer_callback, nfc_worker); + + rfal_platform_spi_acquire(); + + FURI_LOG_D(TAG, "Start reader analyzer"); + while(nfc_worker->state == NfcWorkerStateAnalyzeReader) { + furi_hal_nfc_stop_cmd(); + furi_delay_ms(5); + furi_hal_nfc_listen_start(nfc_data); + if(furi_hal_nfc_listen_rx(&tx_rx, 300)) { + NfcProtocol protocol = + reader_analyzer_guess_protocol(reader_analyzer, tx_rx.rx_data, tx_rx.rx_bits / 8); + if(protocol == NfcDeviceProtocolMifareClassic) { + mf_classic_emulator(&emulator, &tx_rx); + } + } else { + FURI_LOG_D(TAG, "No data from reader"); + continue; + } + } + + rfal_platform_spi_release(); + + reader_analyzer_stop(nfc_worker->reader_analyzer); + + nfca_signal_free(nfca_signal); } diff --git a/lib/nfc/nfc_worker.h b/lib/nfc/nfc_worker.h old mode 100755 new mode 100644 index 22cbc3dcc..b7bf4da9a --- a/lib/nfc/nfc_worker.h +++ b/lib/nfc/nfc_worker.h @@ -16,6 +16,7 @@ typedef enum { NfcWorkerStateMfClassicEmulate, NfcWorkerStateReadMfUltralightReadAuth, NfcWorkerStateMfClassicDictAttack, + NfcWorkerStateAnalyzeReader, // Debug NfcWorkerStateEmulateApdu, NfcWorkerStateField, @@ -54,8 +55,12 @@ typedef enum { NfcWorkerEventFoundKeyA, NfcWorkerEventFoundKeyB, + // Detect Reader events + NfcWorkerEventDetectReaderMfkeyCollected, + // Mifare Ultralight events NfcWorkerEventMfUltralightPassKey, + } NfcWorkerEvent; typedef bool (*NfcWorkerCallback)(NfcWorkerEvent event, void* context); diff --git a/lib/nfc/nfc_worker_i.h b/lib/nfc/nfc_worker_i.h index 1e98879a7..526182f9a 100644 --- a/lib/nfc/nfc_worker_i.h +++ b/lib/nfc/nfc_worker_i.h @@ -12,8 +12,7 @@ #include #include #include - -#include "helpers/nfc_debug_pcap.h" +#include struct NfcWorker { FuriThread* thread; @@ -27,7 +26,7 @@ struct NfcWorker { NfcWorkerState state; - NfcDebugPcapWorker* debug_pcap_worker; + ReaderAnalyzer* reader_analyzer; }; void nfc_worker_change_state(NfcWorker* nfc_worker, NfcWorkerState state); @@ -49,3 +48,5 @@ void nfc_worker_mf_ultralight_read_auth(NfcWorker* nfc_worker); void nfc_worker_mf_ul_auth_attack(NfcWorker* nfc_worker); void nfc_worker_emulate_apdu(NfcWorker* nfc_worker); + +void nfc_worker_analyze_reader(NfcWorker* nfc_worker); diff --git a/lib/nfc/parsers/all_in_one.c b/lib/nfc/parsers/all_in_one.c new file mode 100644 index 000000000..b49a32f7c --- /dev/null +++ b/lib/nfc/parsers/all_in_one.c @@ -0,0 +1,113 @@ +#include "nfc_supported_card.h" +#include "all_in_one.h" + +#include +#include + +#include "furi_hal.h" + +#define ALL_IN_ONE_LAYOUT_UNKNOWN 0 +#define ALL_IN_ONE_LAYOUT_A 1 +#define ALL_IN_ONE_LAYOUT_D 2 +#define ALL_IN_ONE_LAYOUT_E2 3 +#define ALL_IN_ONE_LAYOUT_E3 4 +#define ALL_IN_ONE_LAYOUT_E5 5 +#define ALL_IN_ONE_LAYOUT_2 6 + +uint8_t all_in_one_get_layout(NfcDeviceData* dev_data) { + // I absolutely hate what's about to happen here. + + // Switch on the second half of the third byte of page 5 + FURI_LOG_I("all_in_one", "Layout byte: %02x", dev_data->mf_ul_data.data[(4 * 5) + 2]); + FURI_LOG_I( + "all_in_one", "Layout half-byte: %02x", dev_data->mf_ul_data.data[(4 * 5) + 3] & 0x0F); + switch(dev_data->mf_ul_data.data[(4 * 5) + 2] & 0x0F) { + // If it is A, the layout type is a type A layout + case 0x0A: + return ALL_IN_ONE_LAYOUT_A; + case 0x0D: + return ALL_IN_ONE_LAYOUT_D; + case 0x02: + return ALL_IN_ONE_LAYOUT_2; + default: + FURI_LOG_I( + "all_in_one", + "Unknown layout type: %d", + dev_data->mf_ul_data.data[(4 * 5) + 2] & 0x0F); + return ALL_IN_ONE_LAYOUT_UNKNOWN; + } +} + +bool all_in_one_parser_verify(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) { + UNUSED(nfc_worker); + // If this is a all_in_one pass, first 2 bytes of page 4 are 0x45 0xD9 + MfUltralightReader reader = {}; + MfUltralightData data = {}; + + if(!mf_ul_read_card(tx_rx, &reader, &data)) { + return false; + } else { + if(data.data[4 * 4] == 0x45 && data.data[4 * 4 + 1] == 0xD9) { + FURI_LOG_I("all_in_one", "Pass verified"); + return true; + } + } + return false; +} + +bool all_in_one_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) { + MfUltralightReader reader = {}; + MfUltralightData data = {}; + if(!mf_ul_read_card(tx_rx, &reader, &data)) { + return false; + } else { + memcpy(&nfc_worker->dev_data->mf_ul_data, &data, sizeof(data)); + FURI_LOG_I("all_in_one", "Card read"); + return true; + } +} + +bool all_in_one_parser_parse(NfcDeviceData* dev_data) { + if(dev_data->mf_ul_data.data[4 * 4] != 0x45 || dev_data->mf_ul_data.data[4 * 4 + 1] != 0xD9) { + FURI_LOG_I("all_in_one", "Pass not verified"); + return false; + } + + // If the layout is a then the ride count is stored in the first byte of page 8 + uint8_t ride_count = 0; + uint32_t serial = 0; + if(all_in_one_get_layout(dev_data) == ALL_IN_ONE_LAYOUT_A) { + ride_count = dev_data->mf_ul_data.data[4 * 8]; + } else if(all_in_one_get_layout(dev_data) == ALL_IN_ONE_LAYOUT_D) { + // If the layout is D, the ride count is stored in the second byte of page 9 + ride_count = dev_data->mf_ul_data.data[4 * 9 + 1]; + // I hate this with a burning passion. + + // The number starts at the second half of the third byte on page 4, and is 32 bits long + // So we get the second half of the third byte, then bytes 4-6, and then the first half of the 7th byte + // B8 17 A2 A4 BD becomes 81 7A 2A 4B + serial = (dev_data->mf_ul_data.data[4 * 4 + 2] & 0x0F) << 28 | + dev_data->mf_ul_data.data[4 * 4 + 3] << 20 | + dev_data->mf_ul_data.data[4 * 4 + 4] << 12 | + dev_data->mf_ul_data.data[4 * 4 + 5] << 4 | + (dev_data->mf_ul_data.data[4 * 4 + 6] >> 4); + } else { + FURI_LOG_I("all_in_one", "Unknown layout: %d", all_in_one_get_layout(dev_data)); + ride_count = 137; + } + + // I hate this with a burning passion. + + // The number starts at the second half of the third byte on page 4, and is 32 bits long + // So we get the second half of the third byte, then bytes 4-6, and then the first half of the 7th byte + // B8 17 A2 A4 BD becomes 81 7A 2A 4B + serial = + (dev_data->mf_ul_data.data[4 * 4 + 2] & 0x0F) << 28 | + dev_data->mf_ul_data.data[4 * 4 + 3] << 20 | dev_data->mf_ul_data.data[4 * 4 + 4] << 12 | + dev_data->mf_ul_data.data[4 * 4 + 5] << 4 | (dev_data->mf_ul_data.data[4 * 4 + 6] >> 4); + + // Format string for rides count + string_printf( + dev_data->parsed_data, "\e#All-In-One\nNumber: %u\nRides left: %u", serial, ride_count); + return true; +} \ No newline at end of file diff --git a/lib/nfc/parsers/all_in_one.h b/lib/nfc/parsers/all_in_one.h new file mode 100644 index 000000000..9b646d4dc --- /dev/null +++ b/lib/nfc/parsers/all_in_one.h @@ -0,0 +1,9 @@ +#pragma once + +#include "nfc_supported_card.h" + +bool all_in_one_parser_verify(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx); + +bool all_in_one_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx); + +bool all_in_one_parser_parse(NfcDeviceData* dev_data); \ No newline at end of file diff --git a/lib/nfc/parsers/nfc_supported_card.c b/lib/nfc/parsers/nfc_supported_card.c index 480c970e7..fc2dc34e0 100644 --- a/lib/nfc/parsers/nfc_supported_card.c +++ b/lib/nfc/parsers/nfc_supported_card.c @@ -1,14 +1,54 @@ #include "nfc_supported_card.h" -#include "troyka_parser.h" +#include "plantain_parser.h" +#include "troika_parser.h" +#include "plantain_4k_parser.h" +#include "troika_4k_parser.h" +#include "two_cities.h" +#include "all_in_one.h" NfcSupportedCard nfc_supported_card[NfcSupportedCardTypeEnd] = { - [NfcSupportedCardTypeTroyka] = + [NfcSupportedCardTypePlantain] = { .protocol = NfcDeviceProtocolMifareClassic, - .verify = troyka_parser_verify, - .read = troyka_parser_read, - .parse = troyka_parser_parse, + .verify = plantain_parser_verify, + .read = plantain_parser_read, + .parse = plantain_parser_parse, + }, + [NfcSupportedCardTypeTroika] = + { + .protocol = NfcDeviceProtocolMifareClassic, + .verify = troika_parser_verify, + .read = troika_parser_read, + .parse = troika_parser_parse, + }, + [NfcSupportedCardTypePlantain4K] = + { + .protocol = NfcDeviceProtocolMifareClassic, + .verify = plantain_4k_parser_verify, + .read = plantain_4k_parser_read, + .parse = plantain_4k_parser_parse, + }, + [NfcSupportedCardTypeTroika4K] = + { + .protocol = NfcDeviceProtocolMifareClassic, + .verify = troika_4k_parser_verify, + .read = troika_4k_parser_read, + .parse = troika_4k_parser_parse, + }, + [NfcSupportedCardTypeTwoCities] = + { + .protocol = NfcDeviceProtocolMifareClassic, + .verify = two_cities_parser_verify, + .read = two_cities_parser_read, + .parse = two_cities_parser_parse, + }, + [NfcSupportedCardTypeAllInOne] = + { + .protocol = NfcDeviceProtocolMifareUl, + .verify = all_in_one_parser_verify, + .read = all_in_one_parser_read, + .parse = all_in_one_parser_parse, }, }; diff --git a/lib/nfc/parsers/nfc_supported_card.h b/lib/nfc/parsers/nfc_supported_card.h index 9b5d1c053..d34b5794a 100644 --- a/lib/nfc/parsers/nfc_supported_card.h +++ b/lib/nfc/parsers/nfc_supported_card.h @@ -7,7 +7,12 @@ #include typedef enum { - NfcSupportedCardTypeTroyka, + NfcSupportedCardTypePlantain, + NfcSupportedCardTypeTroika, + NfcSupportedCardTypePlantain4K, + NfcSupportedCardTypeTroika4K, + NfcSupportedCardTypeTwoCities, + NfcSupportedCardTypeAllInOne, NfcSupportedCardTypeEnd, } NfcSupportedCardType; diff --git a/lib/nfc/parsers/plantain_4k_parser.c b/lib/nfc/parsers/plantain_4k_parser.c new file mode 100644 index 000000000..77387707b --- /dev/null +++ b/lib/nfc/parsers/plantain_4k_parser.c @@ -0,0 +1,153 @@ +#include "nfc_supported_card.h" +#include "plantain_parser.h" // For luhn and string_push_uint64 + +#include +#include + +#include "furi_hal.h" + +static const MfClassicAuthContext plantain_keys_4k[] = { + {.sector = 0, .key_a = 0xFFFFFFFFFFFF, .key_b = 0xFFFFFFFFFFFF}, + {.sector = 1, .key_a = 0xffffffffffff, .key_b = 0xffffffffffff}, + {.sector = 2, .key_a = 0xffffffffffff, .key_b = 0xffffffffffff}, + {.sector = 3, .key_a = 0xffffffffffff, .key_b = 0xffffffffffff}, + {.sector = 4, .key_a = 0xe56ac127dd45, .key_b = 0x19fc84a3784b}, + {.sector = 5, .key_a = 0x77dabc9825e1, .key_b = 0x9764fec3154a}, + {.sector = 6, .key_a = 0xffffffffffff, .key_b = 0xffffffffffff}, + {.sector = 7, .key_a = 0xffffffffffff, .key_b = 0xffffffffffff}, + {.sector = 8, .key_a = 0x26973ea74321, .key_b = 0xd27058c6e2c7}, + {.sector = 9, .key_a = 0xeb0a8ff88ade, .key_b = 0x578a9ada41e3}, + {.sector = 10, .key_a = 0xea0fd73cb149, .key_b = 0x29c35fa068fb}, + {.sector = 11, .key_a = 0xc76bf71a2509, .key_b = 0x9ba241db3f56}, + {.sector = 12, .key_a = 0xacffffffffff, .key_b = 0x71f3a315ad26}, + {.sector = 13, .key_a = 0xffffffffffff, .key_b = 0xffffffffffff}, + {.sector = 14, .key_a = 0xffffffffffff, .key_b = 0xffffffffffff}, + {.sector = 15, .key_a = 0xffffffffffff, .key_b = 0xffffffffffff}, + {.sector = 16, .key_a = 0x72f96bdd3714, .key_b = 0x462225cd34cf}, + {.sector = 17, .key_a = 0x044ce1872bc3, .key_b = 0x8c90c70cff4a}, + {.sector = 18, .key_a = 0xbc2d1791dec1, .key_b = 0xca96a487de0b}, + {.sector = 19, .key_a = 0x8791b2ccb5c4, .key_b = 0xc956c3b80da3}, + {.sector = 20, .key_a = 0x8e26e45e7d65, .key_b = 0x8e65b3af7d22}, + {.sector = 21, .key_a = 0x0f318130ed18, .key_b = 0x0c420a20e056}, + {.sector = 22, .key_a = 0x045ceca15535, .key_b = 0x31bec3d9e510}, + {.sector = 23, .key_a = 0x9d993c5d4ef4, .key_b = 0x86120e488abf}, + {.sector = 24, .key_a = 0xc65d4eaa645b, .key_b = 0xb69d40d1a439}, + {.sector = 25, .key_a = 0x3a8a139c20b4, .key_b = 0x8818a9c5d406}, + {.sector = 26, .key_a = 0xbaff3053b496, .key_b = 0x4b7cb25354d3}, + {.sector = 27, .key_a = 0x7413b599c4ea, .key_b = 0xb0a2AAF3A1BA}, + {.sector = 28, .key_a = 0x0ce7cd2cc72b, .key_b = 0xfa1fbb3f0f1f}, + {.sector = 29, .key_a = 0x0be5fac8b06a, .key_b = 0x6f95887a4fd3}, + {.sector = 30, .key_a = 0x0eb23cc8110b, .key_b = 0x04dc35277635}, + {.sector = 31, .key_a = 0xbc4580b7f20b, .key_b = 0xd0a4131fb290}, + {.sector = 32, .key_a = 0x7a396f0d633d, .key_b = 0xad2bdc097023}, + {.sector = 33, .key_a = 0xa3faa6daff67, .key_b = 0x7600e889adf9}, + {.sector = 34, .key_a = 0xfd8705e721b0, .key_b = 0x296fc317a513}, + {.sector = 35, .key_a = 0x22052b480d11, .key_b = 0xe19504c39461}, + {.sector = 36, .key_a = 0xa7141147d430, .key_b = 0xff16014fefc7}, + {.sector = 37, .key_a = 0x8a8d88151a00, .key_b = 0x038b5f9b5a2a}, + {.sector = 38, .key_a = 0xb27addfb64b0, .key_b = 0x152fd0c420a7}, + {.sector = 39, .key_a = 0x7259fa0197c6, .key_b = 0x5583698df085}, +}; + +bool plantain_4k_parser_verify(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) { + furi_assert(nfc_worker); + UNUSED(nfc_worker); + + if(nfc_worker->dev_data->mf_classic_data.type != MfClassicType4k) { + return false; + } + + uint8_t sector = 8; + uint8_t block = mf_classic_get_sector_trailer_block_num_by_sector(sector); + FURI_LOG_D("Plant4K", "Verifying sector %d", sector); + if(mf_classic_authenticate(tx_rx, block, 0x26973ea74321, MfClassicKeyA)) { + FURI_LOG_D("Plant4K", "Sector %d verified", sector); + return true; + } + return false; +} + +bool plantain_4k_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) { + furi_assert(nfc_worker); + + MfClassicReader reader = {}; + FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; + reader.type = mf_classic_get_classic_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak); + for(size_t i = 0; i < COUNT_OF(plantain_keys_4k); i++) { + mf_classic_reader_add_sector( + &reader, + plantain_keys_4k[i].sector, + plantain_keys_4k[i].key_a, + plantain_keys_4k[i].key_b); + FURI_LOG_T("plant4k", "Added sector %d", plantain_keys_4k[i].sector); + } + for(int i = 0; i < 5; i++) { + if(mf_classic_read_card(tx_rx, &reader, &nfc_worker->dev_data->mf_classic_data) == 40) { + return true; + } + } + return false; +} + +bool plantain_4k_parser_parse(NfcDeviceData* dev_data) { + MfClassicData* data = &dev_data->mf_classic_data; + + // Verify key + MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(data, 8); + uint64_t key = nfc_util_bytes2num(sec_tr->key_a, 6); + if(key != plantain_keys_4k[8].key_a) return false; + + // Point to block 0 of sector 4, value 0 + uint8_t* temp_ptr = &data->block[4 * 4].value[0]; + // Read first 4 bytes of block 0 of sector 4 from last to first and convert them to uint32_t + // 38 18 00 00 becomes 00 00 18 38, and equals to 6200 decimal + uint32_t balance = + ((temp_ptr[3] << 24) | (temp_ptr[2] << 16) | (temp_ptr[1] << 8) | temp_ptr[0]) / 100; + // Read card number + // Point to block 0 of sector 0, value 0 + temp_ptr = &data->block[0 * 4].value[0]; + // Read first 7 bytes of block 0 of sector 0 from last to first and convert them to uint64_t + // 80 5C 23 8A 16 31 04 becomes 04 31 16 8A 23 5C 80, and equals to 36130104729284868 decimal + uint8_t card_number_arr[7]; + for(size_t i = 0; i < 7; i++) { + card_number_arr[i] = temp_ptr[6 - i]; + } + // Copy card number to uint64_t + uint64_t card_number = 0; + for(size_t i = 0; i < 7; i++) { + card_number = (card_number << 8) | card_number_arr[i]; + } + // Convert card number to string + string_t card_number_str; + string_init(card_number_str); + // Should look like "361301047292848684" + // %llu doesn't work for some reason in sprintf, so we use string_push_uint64 instead + string_push_uint64(card_number, card_number_str); + // Add suffix with luhn checksum (1 digit) to the card number string + string_t card_number_suffix; + string_init(card_number_suffix); + + // The number to calculate the checksum on doesn't fit into uint64_t, idk + //uint8_t luhn_checksum = plantain_calculate_luhn(card_number); + + // // Convert luhn checksum to string + // string_t luhn_checksum_str; + // string_init(luhn_checksum_str); + // string_push_uint64(luhn_checksum, luhn_checksum_str); + + string_cat_printf(card_number_suffix, "-"); + // FURI_LOG_D("plant4k", "Card checksum: %d", luhn_checksum); + string_cat_printf(card_number_str, string_get_cstr(card_number_suffix)); + // Free all not needed strings + string_clear(card_number_suffix); + // string_clear(luhn_checksum_str); + + string_printf( + dev_data->parsed_data, + "\e#Plantain\nN:%s\nBalance:%d\n", + string_get_cstr(card_number_str), + balance); + string_clear(card_number_str); + + return true; +} diff --git a/lib/nfc/parsers/plantain_4k_parser.h b/lib/nfc/parsers/plantain_4k_parser.h new file mode 100644 index 000000000..29998af15 --- /dev/null +++ b/lib/nfc/parsers/plantain_4k_parser.h @@ -0,0 +1,9 @@ +#pragma once + +#include "nfc_supported_card.h" + +bool plantain_4k_parser_verify(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx); + +bool plantain_4k_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx); + +bool plantain_4k_parser_parse(NfcDeviceData* dev_data); diff --git a/lib/nfc/parsers/plantain_parser.c b/lib/nfc/parsers/plantain_parser.c new file mode 100644 index 000000000..ff81b8e9b --- /dev/null +++ b/lib/nfc/parsers/plantain_parser.c @@ -0,0 +1,147 @@ +#include "nfc_supported_card.h" + +#include +#include + +#include "furi_hal.h" + +static const MfClassicAuthContext plantain_keys[] = { + {.sector = 0, .key_a = 0xffffffffffff, .key_b = 0xffffffffffff}, + {.sector = 1, .key_a = 0xffffffffffff, .key_b = 0xffffffffffff}, + {.sector = 2, .key_a = 0xffffffffffff, .key_b = 0xffffffffffff}, + {.sector = 3, .key_a = 0xffffffffffff, .key_b = 0xffffffffffff}, + {.sector = 4, .key_a = 0xe56ac127dd45, .key_b = 0x19fc84a3784b}, + {.sector = 5, .key_a = 0x77dabc9825e1, .key_b = 0x9764fec3154a}, + {.sector = 6, .key_a = 0xffffffffffff, .key_b = 0xffffffffffff}, + {.sector = 7, .key_a = 0xffffffffffff, .key_b = 0xffffffffffff}, + {.sector = 8, .key_a = 0x26973ea74321, .key_b = 0xd27058c6e2c7}, + {.sector = 9, .key_a = 0xeb0a8ff88ade, .key_b = 0x578a9ada41e3}, + {.sector = 10, .key_a = 0xea0fd73cb149, .key_b = 0x29c35fa068fb}, + {.sector = 11, .key_a = 0xc76bf71a2509, .key_b = 0x9ba241db3f56}, + {.sector = 12, .key_a = 0xacffffffffff, .key_b = 0x71f3a315ad26}, + {.sector = 13, .key_a = 0xffffffffffff, .key_b = 0xffffffffffff}, + {.sector = 14, .key_a = 0xffffffffffff, .key_b = 0xffffffffffff}, + {.sector = 15, .key_a = 0xffffffffffff, .key_b = 0xffffffffffff}, +}; + +bool plantain_parser_verify(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) { + furi_assert(nfc_worker); + UNUSED(nfc_worker); + if(nfc_worker->dev_data->mf_classic_data.type != MfClassicType1k) { + return false; + } + + uint8_t sector = 8; + uint8_t block = mf_classic_get_sector_trailer_block_num_by_sector(sector); + FURI_LOG_D("Plant", "Verifying sector %d", sector); + if(mf_classic_authenticate(tx_rx, block, 0x26973ea74321, MfClassicKeyA)) { + FURI_LOG_D("Plant", "Sector %d verified", sector); + return true; + } + return false; +} + +bool plantain_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) { + furi_assert(nfc_worker); + + MfClassicReader reader = {}; + FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; + reader.type = mf_classic_get_classic_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak); + for(size_t i = 0; i < COUNT_OF(plantain_keys); i++) { + mf_classic_reader_add_sector( + &reader, plantain_keys[i].sector, plantain_keys[i].key_a, plantain_keys[i].key_b); + } + + return mf_classic_read_card(tx_rx, &reader, &nfc_worker->dev_data->mf_classic_data) == 16; +} + +void string_push_uint64(uint64_t input, string_t output) { + const uint8_t base = 10; + + do { + char c = input % base; + input /= base; + + if(c < 10) + c += '0'; + else + c += 'A' - 10; + string_push_back(output, c); + } while(input); + + // reverse string + for(uint8_t i = 0; i < string_size(output) / 2; i++) { + char c = string_get_char(output, i); + string_set_char(output, i, string_get_char(output, string_size(output) - i - 1)); + string_set_char(output, string_size(output) - i - 1, c); + } +} + +uint8_t plantain_calculate_luhn(uint64_t number) { + // No. + UNUSED(number); + return 0; +} + +bool plantain_parser_parse(NfcDeviceData* dev_data) { + MfClassicData* data = &dev_data->mf_classic_data; + + // Verify key + MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(data, 8); + uint64_t key = nfc_util_bytes2num(sec_tr->key_a, 6); + if(key != plantain_keys[8].key_a) return false; + + // Point to block 0 of sector 4, value 0 + uint8_t* temp_ptr = &data->block[4 * 4].value[0]; + // Read first 4 bytes of block 0 of sector 4 from last to first and convert them to uint32_t + // 38 18 00 00 becomes 00 00 18 38, and equals to 6200 decimal + uint32_t balance = + ((temp_ptr[3] << 24) | (temp_ptr[2] << 16) | (temp_ptr[1] << 8) | temp_ptr[0]) / 100; + // Read card number + // Point to block 0 of sector 0, value 0 + temp_ptr = &data->block[0 * 4].value[0]; + // Read first 7 bytes of block 0 of sector 0 from last to first and convert them to uint64_t + // 80 5C 23 8A 16 31 04 becomes 04 31 16 8A 23 5C 80, and equals to 36130104729284868 decimal + uint8_t card_number_arr[7]; + for(size_t i = 0; i < 7; i++) { + card_number_arr[i] = temp_ptr[6 - i]; + } + // Copy card number to uint64_t + uint64_t card_number = 0; + for(size_t i = 0; i < 7; i++) { + card_number = (card_number << 8) | card_number_arr[i]; + } + // Convert card number to string + string_t card_number_str; + string_init(card_number_str); + // Should look like "361301047292848684" + // %llu doesn't work for some reason in sprintf, so we use string_push_uint64 instead + string_push_uint64(card_number, card_number_str); + // Add suffix with luhn checksum (1 digit) to the card number string + string_t card_number_suffix; + string_init(card_number_suffix); + + // The number to calculate the checksum on doesn't fit into uint64_t, idk + //uint8_t luhn_checksum = plantain_calculate_luhn(card_number); + + // // Convert luhn checksum to string + // string_t luhn_checksum_str; + // string_init(luhn_checksum_str); + // string_push_uint64(luhn_checksum, luhn_checksum_str); + + string_cat_printf(card_number_suffix, "-"); + // FURI_LOG_D("plant4k", "Card checksum: %d", luhn_checksum); + string_cat_printf(card_number_str, string_get_cstr(card_number_suffix)); + // Free all not needed strings + string_clear(card_number_suffix); + // string_clear(luhn_checksum_str); + + string_printf( + dev_data->parsed_data, + "\e#Plantain\nN:%s\nBalance:%d\n", + string_get_cstr(card_number_str), + balance); + string_clear(card_number_str); + + return true; +} diff --git a/lib/nfc/parsers/plantain_parser.h b/lib/nfc/parsers/plantain_parser.h new file mode 100644 index 000000000..d37f0dd48 --- /dev/null +++ b/lib/nfc/parsers/plantain_parser.h @@ -0,0 +1,13 @@ +#pragma once + +#include "nfc_supported_card.h" + +bool plantain_parser_verify(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx); + +bool plantain_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx); + +bool plantain_parser_parse(NfcDeviceData* dev_data); + +void string_push_uint64(uint64_t input, string_t output); + +uint8_t plantain_calculate_luhn(uint64_t number); diff --git a/lib/nfc/parsers/troika_4k_parser.c b/lib/nfc/parsers/troika_4k_parser.c new file mode 100644 index 000000000..8c32381f2 --- /dev/null +++ b/lib/nfc/parsers/troika_4k_parser.c @@ -0,0 +1,104 @@ +#include "nfc_supported_card.h" + +#include +#include + +static const MfClassicAuthContext troika_4k_keys[] = { + {.sector = 0, .key_a = 0xa0a1a2a3a4a5, .key_b = 0xfbf225dc5d58}, + {.sector = 1, .key_a = 0xa82607b01c0d, .key_b = 0x2910989b6880}, + {.sector = 2, .key_a = 0x2aa05ed1856f, .key_b = 0xeaac88e5dc99}, + {.sector = 3, .key_a = 0x2aa05ed1856f, .key_b = 0xeaac88e5dc99}, + {.sector = 4, .key_a = 0x73068f118c13, .key_b = 0x2b7f3253fac5}, + {.sector = 5, .key_a = 0xFBC2793D540B, .key_b = 0xd3a297dc2698}, + {.sector = 6, .key_a = 0x2aa05ed1856f, .key_b = 0xeaac88e5dc99}, + {.sector = 7, .key_a = 0xae3d65a3dad4, .key_b = 0x0f1c63013dbb}, + {.sector = 8, .key_a = 0xa73f5dc1d333, .key_b = 0xe35173494a81}, + {.sector = 9, .key_a = 0x69a32f1c2f19, .key_b = 0x6b8bd9860763}, + {.sector = 10, .key_a = 0x9becdf3d9273, .key_b = 0xf8493407799d}, + {.sector = 11, .key_a = 0x08b386463229, .key_b = 0x5efbaecef46b}, + {.sector = 12, .key_a = 0xcd4c61c26e3d, .key_b = 0x31c7610de3b0}, + {.sector = 13, .key_a = 0xa82607b01c0d, .key_b = 0x2910989b6880}, + {.sector = 14, .key_a = 0x0e8f64340ba4, .key_b = 0x4acec1205d75}, + {.sector = 15, .key_a = 0x2aa05ed1856f, .key_b = 0xeaac88e5dc99}, + {.sector = 16, .key_a = 0x6b02733bb6ec, .key_b = 0x7038cd25c408}, + {.sector = 17, .key_a = 0x403d706ba880, .key_b = 0xb39d19a280df}, + {.sector = 18, .key_a = 0xc11f4597efb5, .key_b = 0x70d901648cb9}, + {.sector = 19, .key_a = 0x0db520c78c1c, .key_b = 0x73e5b9d9d3a4}, + {.sector = 20, .key_a = 0x3ebce0925b2f, .key_b = 0x372cc880f216}, + {.sector = 21, .key_a = 0x16a27af45407, .key_b = 0x9868925175ba}, + {.sector = 22, .key_a = 0xaba208516740, .key_b = 0xce26ecb95252}, + {.sector = 23, .key_a = 0xCD64E567ABCD, .key_b = 0x8f79c4fd8a01}, + {.sector = 24, .key_a = 0x764cd061f1e6, .key_b = 0xa74332f74994}, + {.sector = 25, .key_a = 0x1cc219e9fec1, .key_b = 0xb90de525ceb6}, + {.sector = 26, .key_a = 0x2fe3cb83ea43, .key_b = 0xfba88f109b32}, + {.sector = 27, .key_a = 0x07894ffec1d6, .key_b = 0xefcb0e689db3}, + {.sector = 28, .key_a = 0x04c297b91308, .key_b = 0xc8454c154cb5}, + {.sector = 29, .key_a = 0x7a38e3511a38, .key_b = 0xab16584c972a}, + {.sector = 30, .key_a = 0x7545df809202, .key_b = 0xecf751084a80}, + {.sector = 31, .key_a = 0x5125974cd391, .key_b = 0xd3eafb5df46d}, + {.sector = 32, .key_a = 0x7a86aa203788, .key_b = 0xe41242278ca2}, + {.sector = 33, .key_a = 0xafcef64c9913, .key_b = 0x9db96dca4324}, + {.sector = 34, .key_a = 0x04eaa462f70b, .key_b = 0xac17b93e2fae}, + {.sector = 35, .key_a = 0xe734c210f27e, .key_b = 0x29ba8c3e9fda}, + {.sector = 36, .key_a = 0xd5524f591eed, .key_b = 0x5daf42861b4d}, + {.sector = 37, .key_a = 0xe4821a377b75, .key_b = 0xe8709e486465}, + {.sector = 38, .key_a = 0x518dc6eea089, .key_b = 0x97c64ac98ca4}, + {.sector = 39, .key_a = 0xbb52f8cce07f, .key_b = 0x6b6119752c70}, +}; + +bool troika_4k_parser_verify(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) { + furi_assert(nfc_worker); + + if(nfc_worker->dev_data->mf_classic_data.type != MfClassicType4k) { + return false; + } + + uint8_t sector = 11; + uint8_t block = mf_classic_get_sector_trailer_block_num_by_sector(sector); + FURI_LOG_D("Troika", "Verifying sector %d", sector); + if(mf_classic_authenticate(tx_rx, block, 0x08b386463229, MfClassicKeyA)) { + FURI_LOG_D("Troika", "Sector %d verified", sector); + return true; + } + return false; +} + +bool troika_4k_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) { + furi_assert(nfc_worker); + + MfClassicReader reader = {}; + FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; + reader.type = mf_classic_get_classic_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak); + for(size_t i = 0; i < COUNT_OF(troika_4k_keys); i++) { + mf_classic_reader_add_sector( + &reader, troika_4k_keys[i].sector, troika_4k_keys[i].key_a, troika_4k_keys[i].key_b); + } + + return mf_classic_read_card(tx_rx, &reader, &nfc_worker->dev_data->mf_classic_data) == 40; +} + +bool troika_4k_parser_parse(NfcDeviceData* dev_data) { + MfClassicData* data = &dev_data->mf_classic_data; + + // Verify key + MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(data, 4); + uint64_t key = nfc_util_bytes2num(sec_tr->key_a, 6); + if(key != troika_4k_keys[4].key_a) return false; + + // Verify card type + if(data->type != MfClassicType4k) return false; + + uint8_t* temp_ptr = &data->block[8 * 4 + 1].value[5]; + uint16_t balance = ((temp_ptr[0] << 8) | temp_ptr[1]) / 25; + temp_ptr = &data->block[8 * 4].value[3]; + uint32_t number = 0; + for(size_t i = 0; i < 4; i++) { + number <<= 8; + number |= temp_ptr[i]; + } + number >>= 4; + + string_printf(dev_data->parsed_data, "\e#Troika\nNum: %ld\nBalance: %d rur.", number, balance); + + return true; +} diff --git a/lib/nfc/parsers/troika_4k_parser.h b/lib/nfc/parsers/troika_4k_parser.h new file mode 100644 index 000000000..c1d6f01d3 --- /dev/null +++ b/lib/nfc/parsers/troika_4k_parser.h @@ -0,0 +1,9 @@ +#pragma once + +#include "nfc_supported_card.h" + +bool troika_4k_parser_verify(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx); + +bool troika_4k_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx); + +bool troika_4k_parser_parse(NfcDeviceData* dev_data); diff --git a/lib/nfc/parsers/troyka_parser.c b/lib/nfc/parsers/troika_parser.c similarity index 68% rename from lib/nfc/parsers/troyka_parser.c rename to lib/nfc/parsers/troika_parser.c index 51ffa42e1..f396b1680 100644 --- a/lib/nfc/parsers/troyka_parser.c +++ b/lib/nfc/parsers/troika_parser.c @@ -3,7 +3,7 @@ #include #include -static const MfClassicAuthContext troyka_keys[] = { +static const MfClassicAuthContext troika_keys[] = { {.sector = 0, .key_a = 0xa0a1a2a3a4a5, .key_b = 0xfbf225dc5d58}, {.sector = 1, .key_a = 0xa82607b01c0d, .key_b = 0x2910989b6880}, {.sector = 2, .key_a = 0x2aa05ed1856f, .key_b = 0xeaac88e5dc99}, @@ -22,42 +22,50 @@ static const MfClassicAuthContext troyka_keys[] = { {.sector = 15, .key_a = 0x2aa05ed1856f, .key_b = 0xeaac88e5dc99}, }; -bool troyka_parser_verify(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) { +bool troika_parser_verify(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) { furi_assert(nfc_worker); UNUSED(nfc_worker); + if(nfc_worker->dev_data->mf_classic_data.type != MfClassicType1k) { + return false; + } - MfClassicAuthContext auth_ctx = { - .key_a = MF_CLASSIC_NO_KEY, - .key_b = MF_CLASSIC_NO_KEY, - .sector = 8, - }; - return mf_classic_auth_attempt(tx_rx, &auth_ctx, 0xa73f5dc1d333); + uint8_t sector = 11; + uint8_t block = mf_classic_get_sector_trailer_block_num_by_sector(sector); + FURI_LOG_D("Troika", "Verifying sector %d", sector); + if(mf_classic_authenticate(tx_rx, block, 0x08b386463229, MfClassicKeyA)) { + FURI_LOG_D("Troika", "Sector %d verified", sector); + return true; + } + return false; } -bool troyka_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) { +bool troika_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) { furi_assert(nfc_worker); MfClassicReader reader = {}; FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; reader.type = mf_classic_get_classic_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak); - for(size_t i = 0; i < COUNT_OF(troyka_keys); i++) { + for(size_t i = 0; i < COUNT_OF(troika_keys); i++) { mf_classic_reader_add_sector( - &reader, troyka_keys[i].sector, troyka_keys[i].key_a, troyka_keys[i].key_b); + &reader, troika_keys[i].sector, troika_keys[i].key_a, troika_keys[i].key_b); } return mf_classic_read_card(tx_rx, &reader, &nfc_worker->dev_data->mf_classic_data) == 16; } -bool troyka_parser_parse(NfcDeviceData* dev_data) { +bool troika_parser_parse(NfcDeviceData* dev_data) { MfClassicData* data = &dev_data->mf_classic_data; - bool troyka_parsed = false; + bool troika_parsed = false; do { // Verify key MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(data, 8); uint64_t key = nfc_util_bytes2num(sec_tr->key_a, 6); - if(key != troyka_keys[8].key_a) break; + if(key != troika_keys[8].key_a) break; + + // Verify card type + if(data->type != MfClassicType1k) break; // Parse data uint8_t* temp_ptr = &data->block[8 * 4 + 1].value[5]; @@ -71,9 +79,9 @@ bool troyka_parser_parse(NfcDeviceData* dev_data) { number >>= 4; string_printf( - dev_data->parsed_data, "\e#Troyka\nNum: %ld\nBalance: %d rur.", number, balance); - troyka_parsed = true; + dev_data->parsed_data, "\e#Troika\nNum: %ld\nBalance: %d rur.", number, balance); + troika_parsed = true; } while(false); - return troyka_parsed; + return troika_parsed; } diff --git a/lib/nfc/parsers/troika_parser.h b/lib/nfc/parsers/troika_parser.h new file mode 100644 index 000000000..2aae48d29 --- /dev/null +++ b/lib/nfc/parsers/troika_parser.h @@ -0,0 +1,9 @@ +#pragma once + +#include "nfc_supported_card.h" + +bool troika_parser_verify(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx); + +bool troika_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx); + +bool troika_parser_parse(NfcDeviceData* dev_data); diff --git a/lib/nfc/parsers/troyka_parser.h b/lib/nfc/parsers/troyka_parser.h deleted file mode 100644 index 445fe40e5..000000000 --- a/lib/nfc/parsers/troyka_parser.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include "nfc_supported_card.h" - -bool troyka_parser_verify(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx); - -bool troyka_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx); - -bool troyka_parser_parse(NfcDeviceData* dev_data); diff --git a/lib/nfc/parsers/two_cities.c b/lib/nfc/parsers/two_cities.c new file mode 100644 index 000000000..d052dff19 --- /dev/null +++ b/lib/nfc/parsers/two_cities.c @@ -0,0 +1,171 @@ +#include "nfc_supported_card.h" +#include "plantain_parser.h" // For plantain-specific stuff + +#include +#include + +#include "furi_hal.h" + +static const MfClassicAuthContext two_cities_keys_4k[] = { + {.sector = 0, .key_a = 0xffffffffffff, .key_b = 0xffffffffffff}, + {.sector = 1, .key_a = 0xffffffffffff, .key_b = 0xffffffffffff}, + {.sector = 2, .key_a = 0x2aa05ed1856f, .key_b = 0xeaac88e5dc99}, + {.sector = 3, .key_a = 0x2aa05ed1856f, .key_b = 0xeaac88e5dc99}, + {.sector = 4, .key_a = 0xe56ac127dd45, .key_b = 0x19fc84a3784b}, + {.sector = 5, .key_a = 0x77dabc9825e1, .key_b = 0x9764fec3154a}, + {.sector = 6, .key_a = 0x2aa05ed1856f, .key_b = 0xeaac88e5dc99}, + {.sector = 7, .key_a = 0xffffffffffff, .key_b = 0xffffffffffff}, + {.sector = 8, .key_a = 0xa73f5dc1d333, .key_b = 0xe35173494a81}, + {.sector = 9, .key_a = 0x69a32f1c2f19, .key_b = 0x6b8bd9860763}, + {.sector = 10, .key_a = 0xea0fd73cb149, .key_b = 0x29c35fa068fb}, + {.sector = 11, .key_a = 0xc76bf71a2509, .key_b = 0x9ba241db3f56}, + {.sector = 12, .key_a = 0xacffffffffff, .key_b = 0x71f3a315ad26}, + {.sector = 13, .key_a = 0xffffffffffff, .key_b = 0xffffffffffff}, + {.sector = 14, .key_a = 0xffffffffffff, .key_b = 0xffffffffffff}, + {.sector = 15, .key_a = 0x2aa05ed1856f, .key_b = 0xeaac88e5dc99}, + {.sector = 16, .key_a = 0x72f96bdd3714, .key_b = 0x462225cd34cf}, + {.sector = 17, .key_a = 0x044ce1872bc3, .key_b = 0x8c90c70cff4a}, + {.sector = 18, .key_a = 0xbc2d1791dec1, .key_b = 0xca96a487de0b}, + {.sector = 19, .key_a = 0x8791b2ccb5c4, .key_b = 0xc956c3b80da3}, + {.sector = 20, .key_a = 0x8e26e45e7d65, .key_b = 0x8e65b3af7d22}, + {.sector = 21, .key_a = 0x0f318130ed18, .key_b = 0x0c420a20e056}, + {.sector = 22, .key_a = 0x045ceca15535, .key_b = 0x31bec3d9e510}, + {.sector = 23, .key_a = 0x9d993c5d4ef4, .key_b = 0x86120e488abf}, + {.sector = 24, .key_a = 0xc65d4eaa645b, .key_b = 0xb69d40d1a439}, + {.sector = 25, .key_a = 0x3a8a139c20b4, .key_b = 0x8818a9c5d406}, + {.sector = 26, .key_a = 0xbaff3053b496, .key_b = 0x4b7cb25354d3}, + {.sector = 27, .key_a = 0x7413b599c4ea, .key_b = 0xb0a2AAF3A1BA}, + {.sector = 28, .key_a = 0x0ce7cd2cc72b, .key_b = 0xfa1fbb3f0f1f}, + {.sector = 29, .key_a = 0x0be5fac8b06a, .key_b = 0x6f95887a4fd3}, + {.sector = 30, .key_a = 0x26973ea74321, .key_b = 0xd27058c6e2c7}, + {.sector = 31, .key_a = 0xeb0a8ff88ade, .key_b = 0x578a9ada41e3}, + {.sector = 32, .key_a = 0x7a396f0d633d, .key_b = 0xad2bdc097023}, + {.sector = 33, .key_a = 0xa3faa6daff67, .key_b = 0x7600e889adf9}, + {.sector = 34, .key_a = 0x2aa05ed1856f, .key_b = 0xeaac88e5dc99}, + {.sector = 35, .key_a = 0x2aa05ed1856f, .key_b = 0xeaac88e5dc99}, + {.sector = 36, .key_a = 0xa7141147d430, .key_b = 0xff16014fefc7}, + {.sector = 37, .key_a = 0x8a8d88151a00, .key_b = 0x038b5f9b5a2a}, + {.sector = 38, .key_a = 0xb27addfb64b0, .key_b = 0x152fd0c420a7}, + {.sector = 39, .key_a = 0x7259fa0197c6, .key_b = 0x5583698df085}, +}; + +bool two_cities_parser_verify(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) { + furi_assert(nfc_worker); + UNUSED(nfc_worker); + + if(nfc_worker->dev_data->mf_classic_data.type != MfClassicType4k) { + return false; + } + + uint8_t sector = 4; + uint8_t block = mf_classic_get_sector_trailer_block_num_by_sector(sector); + FURI_LOG_D("2cities", "Verifying sector %d", sector); + if(mf_classic_authenticate(tx_rx, block, 0xe56ac127dd45, MfClassicKeyA)) { + FURI_LOG_D("2cities", "Sector %d verified", sector); + return true; + } + return false; +} + +bool two_cities_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) { + furi_assert(nfc_worker); + + MfClassicReader reader = {}; + FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; + reader.type = mf_classic_get_classic_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak); + for(size_t i = 0; i < COUNT_OF(two_cities_keys_4k); i++) { + mf_classic_reader_add_sector( + &reader, + two_cities_keys_4k[i].sector, + two_cities_keys_4k[i].key_a, + two_cities_keys_4k[i].key_b); + FURI_LOG_T("2cities", "Added sector %d", two_cities_keys_4k[i].sector); + } + + return mf_classic_read_card(tx_rx, &reader, &nfc_worker->dev_data->mf_classic_data) == 40; +} + +bool two_cities_parser_parse(NfcDeviceData* dev_data) { + MfClassicData* data = &dev_data->mf_classic_data; + + // Verify key + MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(data, 4); + uint64_t key = nfc_util_bytes2num(sec_tr->key_a, 6); + if(key != two_cities_keys_4k[4].key_a) return false; + + // ===== + // PLANTAIN + // ===== + + // Point to block 0 of sector 4, value 0 + uint8_t* temp_ptr = &data->block[4 * 4].value[0]; + // Read first 4 bytes of block 0 of sector 4 from last to first and convert them to uint32_t + // 38 18 00 00 becomes 00 00 18 38, and equals to 6200 decimal + uint32_t balance = + ((temp_ptr[3] << 24) | (temp_ptr[2] << 16) | (temp_ptr[1] << 8) | temp_ptr[0]) / 100; + // Read card number + // Point to block 0 of sector 0, value 0 + temp_ptr = &data->block[0 * 4].value[0]; + // Read first 7 bytes of block 0 of sector 0 from last to first and convert them to uint64_t + // 80 5C 23 8A 16 31 04 becomes 04 31 16 8A 23 5C 80, and equals to 36130104729284868 decimal + uint8_t card_number_arr[7]; + for(size_t i = 0; i < 7; i++) { + card_number_arr[i] = temp_ptr[6 - i]; + } + // Copy card number to uint64_t + uint64_t card_number = 0; + for(size_t i = 0; i < 7; i++) { + card_number = (card_number << 8) | card_number_arr[i]; + } + // Convert card number to string + string_t card_number_str; + string_init(card_number_str); + // Should look like "361301047292848684" + // %llu doesn't work for some reason in sprintf, so we use string_push_uint64 instead + string_push_uint64(card_number, card_number_str); + // Add suffix with luhn checksum (1 digit) to the card number string + string_t card_number_suffix; + string_init(card_number_suffix); + + // The number to calculate the checksum on doesn't fit into uint64_t, idk + //uint8_t luhn_checksum = two_cities_calculate_luhn(card_number); + + // // Convert luhn checksum to string + // string_t luhn_checksum_str; + // string_init(luhn_checksum_str); + // string_push_uint64(luhn_checksum, luhn_checksum_str); + + string_cat_printf(card_number_suffix, "-"); + // FURI_LOG_D("plant4k", "Card checksum: %d", luhn_checksum); + string_cat_printf(card_number_str, string_get_cstr(card_number_suffix)); + // Free all not needed strings + string_clear(card_number_suffix); + // string_clear(luhn_checksum_str); + + // ===== + // --PLANTAIN-- + // ===== + // TROIKA + // ===== + + uint8_t* troika_temp_ptr = &data->block[8 * 4 + 1].value[5]; + uint16_t troika_balance = ((troika_temp_ptr[0] << 8) | troika_temp_ptr[1]) / 25; + troika_temp_ptr = &data->block[8 * 4].value[3]; + uint32_t troika_number = 0; + for(size_t i = 0; i < 4; i++) { + troika_number <<= 8; + troika_number |= troika_temp_ptr[i]; + } + troika_number >>= 4; + + string_printf( + dev_data->parsed_data, + "\e#Troika+Plantain\nPN: %s\nPB: %d rur.\nTN: %d\nTB: %d rur.\n", + string_get_cstr(card_number_str), + balance, + troika_number, + troika_balance); + string_clear(card_number_str); + + return true; +} diff --git a/lib/nfc/parsers/two_cities.h b/lib/nfc/parsers/two_cities.h new file mode 100644 index 000000000..e735bea8e --- /dev/null +++ b/lib/nfc/parsers/two_cities.h @@ -0,0 +1,9 @@ +#pragma once + +#include "nfc_supported_card.h" + +bool two_cities_parser_verify(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx); + +bool two_cities_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx); + +bool two_cities_parser_parse(NfcDeviceData* dev_data); diff --git a/lib/nfc/protocols/emv.h b/lib/nfc/protocols/emv.h old mode 100755 new mode 100644 diff --git a/lib/nfc/protocols/mifare_ultralight.c b/lib/nfc/protocols/mifare_ultralight.c index f637d378a..b3d80deb3 100644 --- a/lib/nfc/protocols/mifare_ultralight.c +++ b/lib/nfc/protocols/mifare_ultralight.c @@ -940,7 +940,7 @@ static bool mf_ul_check_lock(MfUltralightEmulator* emulator, int16_t write_page) if(write_page >= 512) return true; break; default: - furi_assert(false); + furi_crash("Unknown MFUL"); return true; } @@ -967,8 +967,7 @@ static bool mf_ul_check_lock(MfUltralightEmulator* emulator, int16_t write_page) else if(write_page == 41) shift = 12; else { - furi_assert(false); - shift = 0; + furi_crash("Unknown MFUL"); } break; @@ -999,8 +998,7 @@ static bool mf_ul_check_lock(MfUltralightEmulator* emulator, int16_t write_page) shift = (write_page - 16) / 32; break; default: - furi_assert(false); - shift = 0; + furi_crash("Unknown MFUL"); break; } @@ -1177,8 +1175,7 @@ static void mf_ul_emulate_write( block_lock_count = 8; break; default: - furi_assert(false); - block_lock_count = 0; + furi_crash("Unknown MFUL"); break; } diff --git a/lib/nfc/protocols/nfca.c b/lib/nfc/protocols/nfca.c old mode 100755 new mode 100644 diff --git a/lib/print/SConscript b/lib/print/SConscript index 412d17a66..d4a55ab84 100644 --- a/lib/print/SConscript +++ b/lib/print/SConscript @@ -96,6 +96,12 @@ for wrapped_fn in wrapped_fn_list: ] ) +env.Append( + SDK_HEADERS=[ + File("#/lib/print/wrappers.h"), + ], +) + libenv = env.Clone(FW_LIB_NAME="print") libenv.ApplyLibFlags() libenv.Append(CCFLAGS=["-Wno-double-promotion"]) diff --git a/lib/print/wrappers.c b/lib/print/wrappers.c index 3fe446657..5cfe10600 100644 --- a/lib/print/wrappers.c +++ b/lib/print/wrappers.c @@ -1,11 +1,10 @@ -#include -#include +#include "wrappers.h" + #include #include #include #include #include -#include #include "printf_tiny.h" void _putchar(char character) { diff --git a/lib/print/wrappers.h b/lib/print/wrappers.h new file mode 100644 index 000000000..b6f0f004b --- /dev/null +++ b/lib/print/wrappers.h @@ -0,0 +1,25 @@ +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void _putchar(char character); +int __wrap_printf(const char* format, ...); +int __wrap_vsnprintf(char* str, size_t size, const char* format, va_list args); +int __wrap_puts(const char* str); +int __wrap_putchar(int ch); +int __wrap_putc(int ch, FILE* stream); +int __wrap_snprintf(char* str, size_t size, const char* format, ...); +int __wrap_fflush(FILE* stream); + +__attribute__((__noreturn__)) void __wrap___assert(const char* file, int line, const char* e); + +__attribute__((__noreturn__)) void + __wrap___assert_func(const char* file, int line, const char* func, const char* e); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/lib/subghz/SConscript b/lib/subghz/SConscript index 3c6728afe..eff2f168e 100644 --- a/lib/subghz/SConscript +++ b/lib/subghz/SConscript @@ -4,6 +4,14 @@ env.Append( CPPPATH=[ "#/lib/subghz", ], + SDK_HEADERS=[ + File("#/lib/subghz/environment.h"), + File("#/lib/subghz/receiver.h"), + File("#/lib/subghz/subghz_worker.h"), + File("#/lib/subghz/subghz_tx_rx_worker.h"), + File("#/lib/subghz/transmitter.h"), + File("#/lib/subghz/protocols/raw.h"), + ], ) libenv = env.Clone(FW_LIB_NAME="subghz") diff --git a/lib/subghz/environment.h b/lib/subghz/environment.h index b8e73e33b..d4678e413 100644 --- a/lib/subghz/environment.h +++ b/lib/subghz/environment.h @@ -4,6 +4,10 @@ #include "subghz_keystore.h" +#ifdef __cplusplus +extern "C" { +#endif + typedef struct SubGhzEnvironment SubGhzEnvironment; /** @@ -64,3 +68,7 @@ void subghz_environment_set_nice_flor_s_rainbow_table_file_name( */ const char* subghz_environment_get_nice_flor_s_rainbow_table_file_name(SubGhzEnvironment* instance); + +#ifdef __cplusplus +} +#endif diff --git a/lib/subghz/protocols/base.h b/lib/subghz/protocols/base.h index a1a7478d9..fdd135671 100644 --- a/lib/subghz/protocols/base.h +++ b/lib/subghz/protocols/base.h @@ -2,6 +2,10 @@ #include "../types.h" +#ifdef __cplusplus +extern "C" { +#endif + typedef struct SubGhzProtocolDecoderBase SubGhzProtocolDecoderBase; typedef void ( @@ -77,3 +81,7 @@ struct SubGhzProtocolEncoderBase { // Callback section }; + +#ifdef __cplusplus +} +#endif diff --git a/lib/subghz/protocols/bett.c b/lib/subghz/protocols/bett.c index aca8b8c4f..08080dc6c 100644 --- a/lib/subghz/protocols/bett.c +++ b/lib/subghz/protocols/bett.c @@ -92,7 +92,7 @@ void* subghz_protocol_encoder_bett_alloc(SubGhzEnvironment* environment) { instance->generic.protocol_name = instance->base.protocol->name; instance->encoder.repeat = 10; - instance->encoder.size_upload = 52; //max 24bit*2 + 2 (start, stop) + instance->encoder.size_upload = 52; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; return instance; @@ -233,7 +233,8 @@ void subghz_protocol_decoder_bett_feed(void* context, bool level, uint32_t durat case BETTDecoderStepReset: if((!level) && (DURATION_DIFF(duration, subghz_protocol_bett_const.te_short * 44) < (subghz_protocol_bett_const.te_delta * 15))) { - //Found Preambula + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; instance->decoder.parser_step = BETTDecoderStepCheckDuration; } break; @@ -288,20 +289,6 @@ void subghz_protocol_decoder_bett_feed(void* context, bool level, uint32_t durat } } -/** - * Analysis of received data - * @param instance Pointer to a SubGhzBlockGeneric* instance - */ -static void subghz_protocol_bett_check_remote_controller(SubGhzBlockGeneric* instance) { - uint32_t code_found_reverse = - subghz_protocol_blocks_reverse_key(instance->data, instance->data_count_bit); - - instance->serial = (code_found_reverse & 0xFF) << 12 | - ((code_found_reverse >> 8) & 0xFF) << 4 | - ((code_found_reverse >> 20) & 0x0F); - instance->btn = ((code_found_reverse >> 16) & 0x0F); -} - uint8_t subghz_protocol_decoder_bett_get_hash_data(void* context) { furi_assert(context); SubGhzProtocolDecoderBETT* instance = context; @@ -339,8 +326,7 @@ bool subghz_protocol_decoder_bett_deserialize(void* context, FlipperFormat* flip void subghz_protocol_decoder_bett_get_string(void* context, string_t output) { furi_assert(context); SubGhzProtocolDecoderBETT* instance = context; - subghz_protocol_bett_check_remote_controller(&instance->generic); - uint32_t data = (uint32_t)(instance->generic.data & 0xFFFFFF); + uint32_t data = (uint32_t)(instance->generic.data & 0x3FFFF); string_cat_printf( output, "%s %dbit\r\n" @@ -350,7 +336,7 @@ void subghz_protocol_decoder_bett_get_string(void* context, string_t output) { " -: " DIP_PATTERN "\r\n", instance->generic.protocol_name, instance->generic.data_count_bit, - (uint32_t)(instance->generic.data & 0xFFFFFF), + data, SHOW_DIP_P(data, DIP_P), SHOW_DIP_P(data, DIP_O), SHOW_DIP_P(data, DIP_N)); diff --git a/lib/subghz/protocols/came.c b/lib/subghz/protocols/came.c index 37048017e..14c66b7fa 100644 --- a/lib/subghz/protocols/came.c +++ b/lib/subghz/protocols/came.c @@ -13,6 +13,9 @@ */ #define TAG "SubGhzProtocolCAME" +#define CAME_24_COUNT_BIT 24 +#define PRASTEL_COUNT_BIT 25 +#define PRASTEL_NAME "Prastel" static const SubGhzBlockConst subghz_protocol_came_const = { .te_short = 320, @@ -112,8 +115,11 @@ static bool subghz_protocol_encoder_came_get_upload(SubGhzProtocolEncoderCame* i instance->encoder.size_upload = size_upload; } //Send header - instance->encoder.upload[index++] = - level_duration_make(false, (uint32_t)subghz_protocol_came_const.te_short * 36); + instance->encoder.upload[index++] = level_duration_make( + false, + ((instance->generic.data_count_bit == CAME_24_COUNT_BIT) ? + (uint32_t)subghz_protocol_came_const.te_short * 76 : + (uint32_t)subghz_protocol_came_const.te_short * 39)); //Send start bit instance->encoder.upload[index++] = level_duration_make(true, (uint32_t)subghz_protocol_came_const.te_short); @@ -147,8 +153,8 @@ bool subghz_protocol_encoder_came_deserialize(void* context, FlipperFormat* flip } if((instance->generic.data_count_bit != subghz_protocol_came_const.min_count_bit_for_found) && - (instance->generic.data_count_bit != - 2 * subghz_protocol_came_const.min_count_bit_for_found)) { + (instance->generic.data_count_bit != CAME_24_COUNT_BIT) && + (instance->generic.data_count_bit != PRASTEL_COUNT_BIT)) { FURI_LOG_E(TAG, "Wrong number of bits in key"); break; } @@ -213,8 +219,8 @@ void subghz_protocol_decoder_came_feed(void* context, bool level, uint32_t durat SubGhzProtocolDecoderCame* instance = context; switch(instance->decoder.parser_step) { case CameDecoderStepReset: - if((!level) && (DURATION_DIFF(duration, subghz_protocol_came_const.te_short * 51) < - subghz_protocol_came_const.te_delta * 51)) { //Need protocol 36 te_short + if((!level) && (DURATION_DIFF(duration, subghz_protocol_came_const.te_short * 56) < + subghz_protocol_came_const.te_delta * 47)) { //Found header CAME instance->decoder.parser_step = CameDecoderStepFoundStartBit; } @@ -306,8 +312,8 @@ bool subghz_protocol_decoder_came_deserialize(void* context, FlipperFormat* flip } if((instance->generic.data_count_bit != subghz_protocol_came_const.min_count_bit_for_found) && - (instance->generic.data_count_bit != - 2 * subghz_protocol_came_const.min_count_bit_for_found)) { + (instance->generic.data_count_bit != CAME_24_COUNT_BIT) && + (instance->generic.data_count_bit != PRASTEL_COUNT_BIT)) { FURI_LOG_E(TAG, "Wrong number of bits in key"); break; } @@ -332,7 +338,8 @@ void subghz_protocol_decoder_came_get_string(void* context, string_t output) { "%s %dbit\r\n" "Key:0x%08lX\r\n" "Yek:0x%08lX\r\n", - instance->generic.protocol_name, + (instance->generic.data_count_bit == PRASTEL_COUNT_BIT ? PRASTEL_NAME : + instance->generic.protocol_name), instance->generic.data_count_bit, code_found_lo, code_found_reverse_lo); diff --git a/lib/subghz/protocols/chamberlain_code.c b/lib/subghz/protocols/chamberlain_code.c index 6c99d8451..51f2bcd32 100644 --- a/lib/subghz/protocols/chamberlain_code.c +++ b/lib/subghz/protocols/chamberlain_code.c @@ -215,7 +215,7 @@ bool subghz_protocol_encoder_chamb_code_deserialize(void* context, FlipperFormat FURI_LOG_E(TAG, "Deserialize error"); break; } - if(instance->generic.data_count_bit < + if(instance->generic.data_count_bit > subghz_protocol_chamb_code_const.min_count_bit_for_found) { FURI_LOG_E(TAG, "Wrong number of bits in key"); break; @@ -441,7 +441,7 @@ bool subghz_protocol_decoder_chamb_code_deserialize(void* context, FlipperFormat if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { break; } - if(instance->generic.data_count_bit < + if(instance->generic.data_count_bit > subghz_protocol_chamb_code_const.min_count_bit_for_found) { FURI_LOG_E(TAG, "Wrong number of bits in key"); break; diff --git a/lib/subghz/protocols/clemsa.c b/lib/subghz/protocols/clemsa.c new file mode 100644 index 000000000..357a0b06d --- /dev/null +++ b/lib/subghz/protocols/clemsa.c @@ -0,0 +1,365 @@ +#include "clemsa.h" + +#include "../blocks/const.h" +#include "../blocks/decoder.h" +#include "../blocks/encoder.h" +#include "../blocks/generic.h" +#include "../blocks/math.h" + +// protocol BERNER / ELKA / TEDSEN / TELETASTER +#define TAG "SubGhzProtocolClemsa" + +#define DIP_P 0b11 //(+) +#define DIP_O 0b10 //(0) +#define DIP_N 0b00 //(-) + +#define DIP_PATTERN "%c%c%c%c%c%c%c%c" +#define SHOW_DIP_P(dip, check_dip) \ + ((((dip >> 0xE) & 0x3) == check_dip) ? '*' : '_'), \ + ((((dip >> 0xC) & 0x3) == check_dip) ? '*' : '_'), \ + ((((dip >> 0xA) & 0x3) == check_dip) ? '*' : '_'), \ + ((((dip >> 0x8) & 0x3) == check_dip) ? '*' : '_'), \ + ((((dip >> 0x6) & 0x3) == check_dip) ? '*' : '_'), \ + ((((dip >> 0x4) & 0x3) == check_dip) ? '*' : '_'), \ + ((((dip >> 0x2) & 0x3) == check_dip) ? '*' : '_'), \ + ((((dip >> 0x0) & 0x3) == check_dip) ? '*' : '_') + +static const SubGhzBlockConst subghz_protocol_clemsa_const = { + .te_short = 385, + .te_long = 2695, + .te_delta = 150, + .min_count_bit_for_found = 18, +}; + +struct SubGhzProtocolDecoderClemsa { + SubGhzProtocolDecoderBase base; + + SubGhzBlockDecoder decoder; + SubGhzBlockGeneric generic; +}; + +struct SubGhzProtocolEncoderClemsa { + SubGhzProtocolEncoderBase base; + + SubGhzProtocolBlockEncoder encoder; + SubGhzBlockGeneric generic; +}; + +typedef enum { + ClemsaDecoderStepReset = 0, + ClemsaDecoderStepSaveDuration, + ClemsaDecoderStepCheckDuration, +} ClemsaDecoderStep; + +const SubGhzProtocolDecoder subghz_protocol_clemsa_decoder = { + .alloc = subghz_protocol_decoder_clemsa_alloc, + .free = subghz_protocol_decoder_clemsa_free, + + .feed = subghz_protocol_decoder_clemsa_feed, + .reset = subghz_protocol_decoder_clemsa_reset, + + .get_hash_data = subghz_protocol_decoder_clemsa_get_hash_data, + .serialize = subghz_protocol_decoder_clemsa_serialize, + .deserialize = subghz_protocol_decoder_clemsa_deserialize, + .get_string = subghz_protocol_decoder_clemsa_get_string, +}; + +const SubGhzProtocolEncoder subghz_protocol_clemsa_encoder = { + .alloc = subghz_protocol_encoder_clemsa_alloc, + .free = subghz_protocol_encoder_clemsa_free, + + .deserialize = subghz_protocol_encoder_clemsa_deserialize, + .stop = subghz_protocol_encoder_clemsa_stop, + .yield = subghz_protocol_encoder_clemsa_yield, +}; + +const SubGhzProtocol subghz_protocol_clemsa = { + .name = SUBGHZ_PROTOCOL_CLEMSA_NAME, + .type = SubGhzProtocolTypeStatic, + .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | + SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send, + + .decoder = &subghz_protocol_clemsa_decoder, + .encoder = &subghz_protocol_clemsa_encoder, +}; + +void* subghz_protocol_encoder_clemsa_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolEncoderClemsa* instance = malloc(sizeof(SubGhzProtocolEncoderClemsa)); + + instance->base.protocol = &subghz_protocol_clemsa; + instance->generic.protocol_name = instance->base.protocol->name; + + instance->encoder.repeat = 10; + instance->encoder.size_upload = 52; + instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); + instance->encoder.is_running = false; + return instance; +} + +void subghz_protocol_encoder_clemsa_free(void* context) { + furi_assert(context); + SubGhzProtocolEncoderClemsa* instance = context; + free(instance->encoder.upload); + free(instance); +} + +/** + * Generating an upload from data. + * @param instance Pointer to a SubGhzProtocolEncoderClemsa instance + * @return true On success + */ +static bool subghz_protocol_encoder_clemsa_get_upload(SubGhzProtocolEncoderClemsa* instance) { + furi_assert(instance); + size_t index = 0; + size_t size_upload = (instance->generic.data_count_bit * 2); + if(size_upload > instance->encoder.size_upload) { + FURI_LOG_E(TAG, "Size upload exceeds allocated encoder buffer."); + return false; + } else { + instance->encoder.size_upload = size_upload; + } + + for(uint8_t i = instance->generic.data_count_bit; i > 1; i--) { + if(bit_read(instance->generic.data, i - 1)) { + //send bit 1 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_clemsa_const.te_long); + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_clemsa_const.te_short); + } else { + //send bit 0 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_clemsa_const.te_short); + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_clemsa_const.te_long); + } + } + if(bit_read(instance->generic.data, 0)) { + //send bit 1 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_clemsa_const.te_long); + instance->encoder.upload[index++] = level_duration_make( + false, + (uint32_t)subghz_protocol_clemsa_const.te_short + + subghz_protocol_clemsa_const.te_long * 7); + } else { + //send bit 0 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_clemsa_const.te_short); + instance->encoder.upload[index++] = level_duration_make( + false, + (uint32_t)subghz_protocol_clemsa_const.te_long + + subghz_protocol_clemsa_const.te_long * 7); + } + return true; +} + +bool subghz_protocol_encoder_clemsa_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolEncoderClemsa* instance = context; + bool res = false; + do { + if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + FURI_LOG_E(TAG, "Deserialize error"); + break; + } + if(instance->generic.data_count_bit != + subghz_protocol_clemsa_const.min_count_bit_for_found) { + FURI_LOG_E(TAG, "Wrong number of bits in key"); + break; + } + //optional parameter parameter + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + + subghz_protocol_encoder_clemsa_get_upload(instance); + instance->encoder.is_running = true; + + res = true; + } while(false); + + return res; +} + +void subghz_protocol_encoder_clemsa_stop(void* context) { + SubGhzProtocolEncoderClemsa* instance = context; + instance->encoder.is_running = false; +} + +LevelDuration subghz_protocol_encoder_clemsa_yield(void* context) { + SubGhzProtocolEncoderClemsa* instance = context; + + if(instance->encoder.repeat == 0 || !instance->encoder.is_running) { + instance->encoder.is_running = false; + return level_duration_reset(); + } + + LevelDuration ret = instance->encoder.upload[instance->encoder.front]; + + if(++instance->encoder.front == instance->encoder.size_upload) { + instance->encoder.repeat--; + instance->encoder.front = 0; + } + + return ret; +} + +void* subghz_protocol_decoder_clemsa_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolDecoderClemsa* instance = malloc(sizeof(SubGhzProtocolDecoderClemsa)); + instance->base.protocol = &subghz_protocol_clemsa; + instance->generic.protocol_name = instance->base.protocol->name; + return instance; +} + +void subghz_protocol_decoder_clemsa_free(void* context) { + furi_assert(context); + SubGhzProtocolDecoderClemsa* instance = context; + free(instance); +} + +void subghz_protocol_decoder_clemsa_reset(void* context) { + furi_assert(context); + SubGhzProtocolDecoderClemsa* instance = context; + instance->decoder.parser_step = ClemsaDecoderStepReset; +} + +void subghz_protocol_decoder_clemsa_feed(void* context, bool level, uint32_t duration) { + furi_assert(context); + SubGhzProtocolDecoderClemsa* instance = context; + + switch(instance->decoder.parser_step) { + case ClemsaDecoderStepReset: + if((!level) && (DURATION_DIFF(duration, subghz_protocol_clemsa_const.te_short * 51) < + subghz_protocol_clemsa_const.te_delta * 25)) { + instance->decoder.parser_step = ClemsaDecoderStepSaveDuration; + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + } + break; + + case ClemsaDecoderStepSaveDuration: + if(level) { + instance->decoder.te_last = duration; + instance->decoder.parser_step = ClemsaDecoderStepCheckDuration; + } else { + instance->decoder.parser_step = ClemsaDecoderStepReset; + } + break; + + case ClemsaDecoderStepCheckDuration: + if(!level) { + if((DURATION_DIFF(instance->decoder.te_last, subghz_protocol_clemsa_const.te_short) < + subghz_protocol_clemsa_const.te_delta) && + (DURATION_DIFF(duration, subghz_protocol_clemsa_const.te_long) < + subghz_protocol_clemsa_const.te_delta * 3)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + instance->decoder.parser_step = ClemsaDecoderStepSaveDuration; + } else if( + (DURATION_DIFF(instance->decoder.te_last, subghz_protocol_clemsa_const.te_long) < + subghz_protocol_clemsa_const.te_delta * 3) && + (DURATION_DIFF(duration, subghz_protocol_clemsa_const.te_short) < + subghz_protocol_clemsa_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + instance->decoder.parser_step = ClemsaDecoderStepSaveDuration; + } else if( + DURATION_DIFF(duration, subghz_protocol_clemsa_const.te_short * 51) < + subghz_protocol_clemsa_const.te_delta * 25) { + if((DURATION_DIFF( + instance->decoder.te_last, subghz_protocol_clemsa_const.te_short) < + subghz_protocol_clemsa_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + } else if((DURATION_DIFF( + instance->decoder.te_last, subghz_protocol_clemsa_const.te_long) < + subghz_protocol_clemsa_const.te_delta * 3)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + } else { + instance->decoder.parser_step = ClemsaDecoderStepReset; + } + + if(instance->decoder.decode_count_bit == + subghz_protocol_clemsa_const.min_count_bit_for_found) { + instance->generic.data = instance->decoder.decode_data; + instance->generic.data_count_bit = instance->decoder.decode_count_bit; + + if(instance->base.callback) + instance->base.callback(&instance->base, instance->base.context); + } + instance->decoder.parser_step = ClemsaDecoderStepSaveDuration; + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + + } else { + instance->decoder.parser_step = ClemsaDecoderStepReset; + } + } else { + instance->decoder.parser_step = ClemsaDecoderStepReset; + } + break; + } +} + +/** + * Analysis of received data + * @param instance Pointer to a SubGhzBlockGeneric* instance + */ +static void subghz_protocol_clemsa_check_remote_controller(SubGhzBlockGeneric* instance) { + instance->serial = (instance->data >> 2) & 0xFFFF; + instance->btn = (instance->data & 0x03); +} + +uint8_t subghz_protocol_decoder_clemsa_get_hash_data(void* context) { + furi_assert(context); + SubGhzProtocolDecoderClemsa* instance = context; + return subghz_protocol_blocks_get_hash_data( + &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); +} + +bool subghz_protocol_decoder_clemsa_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzPresetDefinition* preset) { + furi_assert(context); + SubGhzProtocolDecoderClemsa* instance = context; + return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); +} + +bool subghz_protocol_decoder_clemsa_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolDecoderClemsa* instance = context; + bool ret = false; + do { + if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + break; + } + if(instance->generic.data_count_bit != + subghz_protocol_clemsa_const.min_count_bit_for_found) { + FURI_LOG_E(TAG, "Wrong number of bits in key"); + break; + } + ret = true; + } while(false); + return ret; +} + +void subghz_protocol_decoder_clemsa_get_string(void* context, string_t output) { + furi_assert(context); + SubGhzProtocolDecoderClemsa* instance = context; + subghz_protocol_clemsa_check_remote_controller(&instance->generic); + //uint32_t data = (uint32_t)(instance->generic.data & 0xFFFFFF); + string_cat_printf( + output, + "%s %dbit\r\n" + "Key:%05lX Btn %X\r\n" + " +: " DIP_PATTERN "\r\n" + " o: " DIP_PATTERN "\r\n" + " -: " DIP_PATTERN "\r\n", + instance->generic.protocol_name, + instance->generic.data_count_bit, + (uint32_t)(instance->generic.data & 0x3FFFF), + instance->generic.btn, + SHOW_DIP_P(instance->generic.serial, DIP_P), + SHOW_DIP_P(instance->generic.serial, DIP_O), + SHOW_DIP_P(instance->generic.serial, DIP_N)); +} diff --git a/lib/subghz/protocols/clemsa.h b/lib/subghz/protocols/clemsa.h new file mode 100644 index 000000000..a83983122 --- /dev/null +++ b/lib/subghz/protocols/clemsa.h @@ -0,0 +1,107 @@ +#pragma once + +#include "base.h" + +#define SUBGHZ_PROTOCOL_CLEMSA_NAME "Clemsa" + +typedef struct SubGhzProtocolDecoderClemsa SubGhzProtocolDecoderClemsa; +typedef struct SubGhzProtocolEncoderClemsa SubGhzProtocolEncoderClemsa; + +extern const SubGhzProtocolDecoder subghz_protocol_clemsa_decoder; +extern const SubGhzProtocolEncoder subghz_protocol_clemsa_encoder; +extern const SubGhzProtocol subghz_protocol_clemsa; + +/** + * Allocate SubGhzProtocolEncoderClemsa. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolEncoderClemsa* pointer to a SubGhzProtocolEncoderClemsa instance + */ +void* subghz_protocol_encoder_clemsa_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolEncoderClemsa. + * @param context Pointer to a SubGhzProtocolEncoderClemsa instance + */ +void subghz_protocol_encoder_clemsa_free(void* context); + +/** + * Deserialize and generating an upload to send. + * @param context Pointer to a SubGhzProtocolEncoderClemsa instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool subghz_protocol_encoder_clemsa_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Forced transmission stop. + * @param context Pointer to a SubGhzProtocolEncoderClemsa instance + */ +void subghz_protocol_encoder_clemsa_stop(void* context); + +/** + * Getting the level and duration of the upload to be loaded into DMA. + * @param context Pointer to a SubGhzProtocolEncoderClemsa instance + * @return LevelDuration + */ +LevelDuration subghz_protocol_encoder_clemsa_yield(void* context); + +/** + * Allocate SubGhzProtocolDecoderClemsa. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolDecoderClemsa* pointer to a SubGhzProtocolDecoderClemsa instance + */ +void* subghz_protocol_decoder_clemsa_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolDecoderClemsa. + * @param context Pointer to a SubGhzProtocolDecoderClemsa instance + */ +void subghz_protocol_decoder_clemsa_free(void* context); + +/** + * Reset decoder SubGhzProtocolDecoderClemsa. + * @param context Pointer to a SubGhzProtocolDecoderClemsa instance + */ +void subghz_protocol_decoder_clemsa_reset(void* context); + +/** + * Parse a raw sequence of levels and durations received from the air. + * @param context Pointer to a SubGhzProtocolDecoderClemsa instance + * @param level Signal level true-high false-low + * @param duration Duration of this level in, us + */ +void subghz_protocol_decoder_clemsa_feed(void* context, bool level, uint32_t duration); + +/** + * Getting the hash sum of the last randomly received parcel. + * @param context Pointer to a SubGhzProtocolDecoderClemsa instance + * @return hash Hash sum + */ +uint8_t subghz_protocol_decoder_clemsa_get_hash_data(void* context); + +/** + * Serialize data SubGhzProtocolDecoderClemsa. + * @param context Pointer to a SubGhzProtocolDecoderClemsa instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param preset The modulation on which the signal was received, SubGhzPresetDefinition + * @return true On success + */ +bool subghz_protocol_decoder_clemsa_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzPresetDefinition* preset); + +/** + * Deserialize data SubGhzProtocolDecoderClemsa. + * @param context Pointer to a SubGhzProtocolDecoderClemsa instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool subghz_protocol_decoder_clemsa_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Getting a textual representation of the received data. + * @param context Pointer to a SubGhzProtocolDecoderClemsa instance + * @param output Resulting text + */ +void subghz_protocol_decoder_clemsa_get_string(void* context, string_t output); diff --git a/lib/subghz/protocols/intertechno_v3.c b/lib/subghz/protocols/intertechno_v3.c new file mode 100644 index 000000000..e70bb8c8b --- /dev/null +++ b/lib/subghz/protocols/intertechno_v3.c @@ -0,0 +1,472 @@ +#include "intertechno_v3.h" + +#include "../blocks/const.h" +#include "../blocks/decoder.h" +#include "../blocks/encoder.h" +#include "../blocks/generic.h" +#include "../blocks/math.h" + +#define TAG "SubGhzProtocolIntertechnoV3" + +#define CH_PATTERN "%c%c%c%c" +#define CNT_TO_CH(ch) \ + (ch & 0x8 ? '1' : '0'), (ch & 0x4 ? '1' : '0'), (ch & 0x2 ? '1' : '0'), (ch & 0x1 ? '1' : '0') + +#define INTERTECHNO_V3_DIMMING_COUNT_BIT 36 + +static const SubGhzBlockConst subghz_protocol_intertechno_v3_const = { + .te_short = 275, + .te_long = 1375, + .te_delta = 150, + .min_count_bit_for_found = 32, +}; + +struct SubGhzProtocolDecoderIntertechno_V3 { + SubGhzProtocolDecoderBase base; + + SubGhzBlockDecoder decoder; + SubGhzBlockGeneric generic; +}; + +struct SubGhzProtocolEncoderIntertechno_V3 { + SubGhzProtocolEncoderBase base; + + SubGhzProtocolBlockEncoder encoder; + SubGhzBlockGeneric generic; +}; + +typedef enum { + IntertechnoV3DecoderStepReset = 0, + IntertechnoV3DecoderStepStartSync, + IntertechnoV3DecoderStepFoundSync, + IntertechnoV3DecoderStepStartDuration, + IntertechnoV3DecoderStepSaveDuration, + IntertechnoV3DecoderStepCheckDuration, + IntertechnoV3DecoderStepEndDuration, +} IntertechnoV3DecoderStep; + +const SubGhzProtocolDecoder subghz_protocol_intertechno_v3_decoder = { + .alloc = subghz_protocol_decoder_intertechno_v3_alloc, + .free = subghz_protocol_decoder_intertechno_v3_free, + + .feed = subghz_protocol_decoder_intertechno_v3_feed, + .reset = subghz_protocol_decoder_intertechno_v3_reset, + + .get_hash_data = subghz_protocol_decoder_intertechno_v3_get_hash_data, + .serialize = subghz_protocol_decoder_intertechno_v3_serialize, + .deserialize = subghz_protocol_decoder_intertechno_v3_deserialize, + .get_string = subghz_protocol_decoder_intertechno_v3_get_string, +}; + +const SubGhzProtocolEncoder subghz_protocol_intertechno_v3_encoder = { + .alloc = subghz_protocol_encoder_intertechno_v3_alloc, + .free = subghz_protocol_encoder_intertechno_v3_free, + + .deserialize = subghz_protocol_encoder_intertechno_v3_deserialize, + .stop = subghz_protocol_encoder_intertechno_v3_stop, + .yield = subghz_protocol_encoder_intertechno_v3_yield, +}; + +const SubGhzProtocol subghz_protocol_intertechno_v3 = { + .name = SUBGHZ_PROTOCOL_INTERTECHNO_V3_NAME, + .type = SubGhzProtocolTypeStatic, + .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_868 | + SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_Load | + SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send, + + .decoder = &subghz_protocol_intertechno_v3_decoder, + .encoder = &subghz_protocol_intertechno_v3_encoder, +}; + +void* subghz_protocol_encoder_intertechno_v3_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolEncoderIntertechno_V3* instance = + malloc(sizeof(SubGhzProtocolEncoderIntertechno_V3)); + + instance->base.protocol = &subghz_protocol_intertechno_v3; + instance->generic.protocol_name = instance->base.protocol->name; + + instance->encoder.repeat = 10; + instance->encoder.size_upload = 256; + instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); + instance->encoder.is_running = false; + return instance; +} + +void subghz_protocol_encoder_intertechno_v3_free(void* context) { + furi_assert(context); + SubGhzProtocolEncoderIntertechno_V3* instance = context; + free(instance->encoder.upload); + free(instance); +} + +/** + * Generating an upload from data. + * @param instance Pointer to a SubGhzProtocolEncoderIntertechno_V3 instance + * @return true On success + */ +static bool subghz_protocol_encoder_intertechno_v3_get_upload( + SubGhzProtocolEncoderIntertechno_V3* instance) { + furi_assert(instance); + size_t index = 0; + + //Send header + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_intertechno_v3_const.te_short); + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_intertechno_v3_const.te_short * 38); + //Send sync + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_intertechno_v3_const.te_short); + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_intertechno_v3_const.te_short * 10); + //Send key data + for(uint8_t i = instance->generic.data_count_bit; i > 0; i--) { + if((instance->generic.data_count_bit == INTERTECHNO_V3_DIMMING_COUNT_BIT) && (i == 9)) { + //send bit dimm + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_intertechno_v3_const.te_short); + instance->encoder.upload[index++] = level_duration_make( + false, (uint32_t)subghz_protocol_intertechno_v3_const.te_short); + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_intertechno_v3_const.te_short); + instance->encoder.upload[index++] = level_duration_make( + false, (uint32_t)subghz_protocol_intertechno_v3_const.te_short); + } else if(bit_read(instance->generic.data, i - 1)) { + //send bit 1 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_intertechno_v3_const.te_short); + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_intertechno_v3_const.te_long); + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_intertechno_v3_const.te_short); + instance->encoder.upload[index++] = level_duration_make( + false, (uint32_t)subghz_protocol_intertechno_v3_const.te_short); + } else { + //send bit 0 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_intertechno_v3_const.te_short); + instance->encoder.upload[index++] = level_duration_make( + false, (uint32_t)subghz_protocol_intertechno_v3_const.te_short); + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_intertechno_v3_const.te_short); + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_intertechno_v3_const.te_long); + } + } + instance->encoder.size_upload = index; + return true; +} + +bool subghz_protocol_encoder_intertechno_v3_deserialize( + void* context, + FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolEncoderIntertechno_V3* instance = context; + bool res = false; + do { + if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + FURI_LOG_E(TAG, "Deserialize error"); + break; + } + if((instance->generic.data_count_bit != + subghz_protocol_intertechno_v3_const.min_count_bit_for_found) && + (instance->generic.data_count_bit != INTERTECHNO_V3_DIMMING_COUNT_BIT)) { + FURI_LOG_E(TAG, "Wrong number of bits in key"); + break; + } + //optional parameter parameter + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + + subghz_protocol_encoder_intertechno_v3_get_upload(instance); + instance->encoder.is_running = true; + + res = true; + } while(false); + + return res; +} + +void subghz_protocol_encoder_intertechno_v3_stop(void* context) { + SubGhzProtocolEncoderIntertechno_V3* instance = context; + instance->encoder.is_running = false; +} + +LevelDuration subghz_protocol_encoder_intertechno_v3_yield(void* context) { + SubGhzProtocolEncoderIntertechno_V3* instance = context; + + if(instance->encoder.repeat == 0 || !instance->encoder.is_running) { + instance->encoder.is_running = false; + return level_duration_reset(); + } + + LevelDuration ret = instance->encoder.upload[instance->encoder.front]; + + if(++instance->encoder.front == instance->encoder.size_upload) { + instance->encoder.repeat--; + instance->encoder.front = 0; + } + + return ret; +} + +void* subghz_protocol_decoder_intertechno_v3_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolDecoderIntertechno_V3* instance = + malloc(sizeof(SubGhzProtocolDecoderIntertechno_V3)); + instance->base.protocol = &subghz_protocol_intertechno_v3; + instance->generic.protocol_name = instance->base.protocol->name; + return instance; +} + +void subghz_protocol_decoder_intertechno_v3_free(void* context) { + furi_assert(context); + SubGhzProtocolDecoderIntertechno_V3* instance = context; + free(instance); +} + +void subghz_protocol_decoder_intertechno_v3_reset(void* context) { + furi_assert(context); + SubGhzProtocolDecoderIntertechno_V3* instance = context; + instance->decoder.parser_step = IntertechnoV3DecoderStepReset; +} + +void subghz_protocol_decoder_intertechno_v3_feed(void* context, bool level, uint32_t duration) { + furi_assert(context); + SubGhzProtocolDecoderIntertechno_V3* instance = context; + switch(instance->decoder.parser_step) { + case IntertechnoV3DecoderStepReset: + if((!level) && + (DURATION_DIFF(duration, subghz_protocol_intertechno_v3_const.te_short * 37) < + subghz_protocol_intertechno_v3_const.te_delta * 15)) { + instance->decoder.parser_step = IntertechnoV3DecoderStepStartSync; + } + break; + case IntertechnoV3DecoderStepStartSync: + if(level && (DURATION_DIFF(duration, subghz_protocol_intertechno_v3_const.te_short) < + subghz_protocol_intertechno_v3_const.te_delta)) { + instance->decoder.parser_step = IntertechnoV3DecoderStepFoundSync; + } else { + instance->decoder.parser_step = IntertechnoV3DecoderStepReset; + } + break; + + case IntertechnoV3DecoderStepFoundSync: + if(!level && (DURATION_DIFF(duration, subghz_protocol_intertechno_v3_const.te_short * 10) < + subghz_protocol_intertechno_v3_const.te_delta * 3)) { + instance->decoder.parser_step = IntertechnoV3DecoderStepStartDuration; + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + } else { + instance->decoder.parser_step = IntertechnoV3DecoderStepReset; + } + break; + + case IntertechnoV3DecoderStepStartDuration: + if(level && (DURATION_DIFF(duration, subghz_protocol_intertechno_v3_const.te_short) < + subghz_protocol_intertechno_v3_const.te_delta)) { + instance->decoder.parser_step = IntertechnoV3DecoderStepSaveDuration; + } else { + instance->decoder.parser_step = IntertechnoV3DecoderStepReset; + } + break; + + case IntertechnoV3DecoderStepSaveDuration: + if(!level) { //save interval + if(duration >= (subghz_protocol_intertechno_v3_const.te_short * 11)) { + instance->decoder.parser_step = IntertechnoV3DecoderStepStartSync; + if((instance->decoder.decode_count_bit == + subghz_protocol_intertechno_v3_const.min_count_bit_for_found) || + (instance->decoder.decode_count_bit == INTERTECHNO_V3_DIMMING_COUNT_BIT)) { + instance->generic.data = instance->decoder.decode_data; + instance->generic.data_count_bit = instance->decoder.decode_count_bit; + + if(instance->base.callback) + instance->base.callback(&instance->base, instance->base.context); + } + break; + } + instance->decoder.te_last = duration; + instance->decoder.parser_step = IntertechnoV3DecoderStepCheckDuration; + } else { + instance->decoder.parser_step = IntertechnoV3DecoderStepReset; + } + break; + case IntertechnoV3DecoderStepCheckDuration: + if(level) { + //Add 0 bit + if((DURATION_DIFF( + instance->decoder.te_last, subghz_protocol_intertechno_v3_const.te_short) < + subghz_protocol_intertechno_v3_const.te_delta) && + (DURATION_DIFF(duration, subghz_protocol_intertechno_v3_const.te_short) < + subghz_protocol_intertechno_v3_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + instance->decoder.parser_step = IntertechnoV3DecoderStepEndDuration; + } else if( + //Add 1 bit + (DURATION_DIFF( + instance->decoder.te_last, subghz_protocol_intertechno_v3_const.te_long) < + subghz_protocol_intertechno_v3_const.te_delta * 2) && + (DURATION_DIFF(duration, subghz_protocol_intertechno_v3_const.te_short) < + subghz_protocol_intertechno_v3_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + instance->decoder.parser_step = IntertechnoV3DecoderStepEndDuration; + + } else if( + //Add dimm_state + (DURATION_DIFF( + instance->decoder.te_last, subghz_protocol_intertechno_v3_const.te_short) < + subghz_protocol_intertechno_v3_const.te_delta * 2) && + (DURATION_DIFF(duration, subghz_protocol_intertechno_v3_const.te_short) < + subghz_protocol_intertechno_v3_const.te_delta) && + (instance->decoder.decode_count_bit == 27)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + instance->decoder.parser_step = IntertechnoV3DecoderStepEndDuration; + + } else + instance->decoder.parser_step = IntertechnoV3DecoderStepReset; + } else { + instance->decoder.parser_step = IntertechnoV3DecoderStepReset; + } + break; + + case IntertechnoV3DecoderStepEndDuration: + if(!level && ((DURATION_DIFF(duration, subghz_protocol_intertechno_v3_const.te_short) < + subghz_protocol_intertechno_v3_const.te_delta) || + (DURATION_DIFF(duration, subghz_protocol_intertechno_v3_const.te_long) < + subghz_protocol_intertechno_v3_const.te_delta * 2))) { + instance->decoder.parser_step = IntertechnoV3DecoderStepStartDuration; + } else { + instance->decoder.parser_step = IntertechnoV3DecoderStepReset; + } + break; + } +} + +/** + * Analysis of received data + * @param instance Pointer to a SubGhzBlockGeneric* instance + */ +static void subghz_protocol_intertechno_v3_check_remote_controller(SubGhzBlockGeneric* instance) { + /* + * A frame is either 32 or 36 bits: + * + * _ + * start bit: | |__________ (T,10T) + * _ _ + * '0': | |_| |_____ (T,T,T,5T) + * _ _ + * '1': | |_____| |_ (T,5T,T,T) + * _ _ + * dimm: | |_| |_ (T,T,T,T) + * + * _ + * stop bit: | |____...____ (T,38T) + * + * if frame 32 bits + * SSSSSSSSSSSSSSSSSSSSSSSSSS all_ch on/off ~ch + * Key:0x3F86C59F => 00111111100001101100010110 0 1 1111 + * + * if frame 36 bits + * SSSSSSSSSSSSSSSSSSSSSSSSSS all_ch dimm ~ch dimm_level + * Key:0x42D2E8856 => 01000010110100101110100010 0 X 0101 0110 + * + */ + + if(instance->data_count_bit == subghz_protocol_intertechno_v3_const.min_count_bit_for_found) { + instance->serial = (instance->data >> 6) & 0x3FFFFFF; + if((instance->data >> 5) & 0x1) { + instance->cnt = 1 << 5; + } else { + instance->cnt = (~instance->data & 0xF); + } + instance->btn = (instance->data >> 4) & 0x1; + } else if(instance->data_count_bit == INTERTECHNO_V3_DIMMING_COUNT_BIT) { + instance->serial = (instance->data >> 10) & 0x3FFFFFF; + if((instance->data >> 9) & 0x1) { + instance->cnt = 1 << 5; + } else { + instance->cnt = (~(instance->data >> 4) & 0xF); + } + instance->btn = (instance->data) & 0xF; + } else { + instance->serial = 0; + instance->cnt = 0; + instance->btn = 0; + } +} + +uint8_t subghz_protocol_decoder_intertechno_v3_get_hash_data(void* context) { + furi_assert(context); + SubGhzProtocolDecoderIntertechno_V3* instance = context; + return subghz_protocol_blocks_get_hash_data( + &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); +} + +bool subghz_protocol_decoder_intertechno_v3_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzPresetDefinition* preset) { + furi_assert(context); + SubGhzProtocolDecoderIntertechno_V3* instance = context; + return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); +} + +bool subghz_protocol_decoder_intertechno_v3_deserialize( + void* context, + FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolDecoderIntertechno_V3* instance = context; + bool ret = false; + do { + if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + break; + } + if((instance->generic.data_count_bit != + subghz_protocol_intertechno_v3_const.min_count_bit_for_found) && + (instance->generic.data_count_bit != INTERTECHNO_V3_DIMMING_COUNT_BIT)) { + FURI_LOG_E(TAG, "Wrong number of bits in key"); + break; + } + ret = true; + } while(false); + return ret; +} + +void subghz_protocol_decoder_intertechno_v3_get_string(void* context, string_t output) { + furi_assert(context); + SubGhzProtocolDecoderIntertechno_V3* instance = context; + + subghz_protocol_intertechno_v3_check_remote_controller(&instance->generic); + + string_cat_printf( + output, + "%.11s %db\r\n" + "Key:0x%08llX\r\n" + "Sn:%07lX\r\n", + instance->generic.protocol_name, + instance->generic.data_count_bit, + instance->generic.data, + instance->generic.serial); + + if(instance->generic.data_count_bit == + subghz_protocol_intertechno_v3_const.min_count_bit_for_found) { + if(instance->generic.cnt >> 5) { + string_cat_printf( + output, "Ch: All Btn:%s\r\n", (instance->generic.btn ? "On" : "Off")); + } else { + string_cat_printf( + output, + "Ch:" CH_PATTERN " Btn:%s\r\n", + CNT_TO_CH(instance->generic.cnt), + (instance->generic.btn ? "On" : "Off")); + } + } else if(instance->generic.data_count_bit == INTERTECHNO_V3_DIMMING_COUNT_BIT) { + string_cat_printf( + output, + "Ch:" CH_PATTERN " Dimm:%d%%\r\n", + CNT_TO_CH(instance->generic.cnt), + (int)(6.67 * (float)instance->generic.btn)); + } +} diff --git a/lib/subghz/protocols/intertechno_v3.h b/lib/subghz/protocols/intertechno_v3.h new file mode 100644 index 000000000..65d6f61d1 --- /dev/null +++ b/lib/subghz/protocols/intertechno_v3.h @@ -0,0 +1,111 @@ +#pragma once + +#include "base.h" + +#define SUBGHZ_PROTOCOL_INTERTECHNO_V3_NAME "Intertechno_V3" + +typedef struct SubGhzProtocolDecoderIntertechno_V3 SubGhzProtocolDecoderIntertechno_V3; +typedef struct SubGhzProtocolEncoderIntertechno_V3 SubGhzProtocolEncoderIntertechno_V3; + +extern const SubGhzProtocolDecoder subghz_protocol_intertechno_v3_decoder; +extern const SubGhzProtocolEncoder subghz_protocol_intertechno_v3_encoder; +extern const SubGhzProtocol subghz_protocol_intertechno_v3; + +/** + * Allocate SubGhzProtocolEncoderIntertechno_V3. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolEncoderIntertechno_V3* pointer to a SubGhzProtocolEncoderIntertechno_V3 instance + */ +void* subghz_protocol_encoder_intertechno_v3_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolEncoderIntertechno_V3. + * @param context Pointer to a SubGhzProtocolEncoderIntertechno_V3 instance + */ +void subghz_protocol_encoder_intertechno_v3_free(void* context); + +/** + * Deserialize and generating an upload to send. + * @param context Pointer to a SubGhzProtocolEncoderIntertechno_V3 instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool subghz_protocol_encoder_intertechno_v3_deserialize( + void* context, + FlipperFormat* flipper_format); + +/** + * Forced transmission stop. + * @param context Pointer to a SubGhzProtocolEncoderIntertechno_V3 instance + */ +void subghz_protocol_encoder_intertechno_v3_stop(void* context); + +/** + * Getting the level and duration of the upload to be loaded into DMA. + * @param context Pointer to a SubGhzProtocolEncoderIntertechno_V3 instance + * @return LevelDuration + */ +LevelDuration subghz_protocol_encoder_intertechno_v3_yield(void* context); + +/** + * Allocate SubGhzProtocolDecoderIntertechno_V3. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolDecoderIntertechno_V3* pointer to a SubGhzProtocolDecoderIntertechno_V3 instance + */ +void* subghz_protocol_decoder_intertechno_v3_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolDecoderIntertechno_V3. + * @param context Pointer to a SubGhzProtocolDecoderIntertechno_V3 instance + */ +void subghz_protocol_decoder_intertechno_v3_free(void* context); + +/** + * Reset decoder SubGhzProtocolDecoderIntertechno_V3. + * @param context Pointer to a SubGhzProtocolDecoderIntertechno_V3 instance + */ +void subghz_protocol_decoder_intertechno_v3_reset(void* context); + +/** + * Parse a raw sequence of levels and durations received from the air. + * @param context Pointer to a SubGhzProtocolDecoderIntertechno_V3 instance + * @param level Signal level true-high false-low + * @param duration Duration of this level in, us + */ +void subghz_protocol_decoder_intertechno_v3_feed(void* context, bool level, uint32_t duration); + +/** + * Getting the hash sum of the last randomly received parcel. + * @param context Pointer to a SubGhzProtocolDecoderIntertechno_V3 instance + * @return hash Hash sum + */ +uint8_t subghz_protocol_decoder_intertechno_v3_get_hash_data(void* context); + +/** + * Serialize data SubGhzProtocolDecoderIntertechno_V3. + * @param context Pointer to a SubGhzProtocolDecoderIntertechno_V3 instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param preset The modulation on which the signal was received, SubGhzPresetDefinition + * @return true On success + */ +bool subghz_protocol_decoder_intertechno_v3_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzPresetDefinition* preset); + +/** + * Deserialize data SubGhzProtocolDecoderIntertechno_V3. + * @param context Pointer to a SubGhzProtocolDecoderIntertechno_V3 instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool subghz_protocol_decoder_intertechno_v3_deserialize( + void* context, + FlipperFormat* flipper_format); + +/** + * Getting a textual representation of the received data. + * @param context Pointer to a SubGhzProtocolDecoderIntertechno_V3 instance + * @param output Resulting text + */ +void subghz_protocol_decoder_intertechno_v3_get_string(void* context, string_t output); diff --git a/lib/subghz/protocols/keeloq.c b/lib/subghz/protocols/keeloq.c index 88738f3fb..0321a8767 100644 --- a/lib/subghz/protocols/keeloq.c +++ b/lib/subghz/protocols/keeloq.c @@ -407,7 +407,7 @@ void subghz_protocol_decoder_keeloq_feed(void* context, bool level, uint32_t dur (DURATION_DIFF(instance->decoder.te_last, subghz_protocol_keeloq_const.te_short) < subghz_protocol_keeloq_const.te_delta) && (DURATION_DIFF(duration, subghz_protocol_keeloq_const.te_long) < - subghz_protocol_keeloq_const.te_delta)) { + subghz_protocol_keeloq_const.te_delta * 2)) { if(instance->decoder.decode_count_bit < subghz_protocol_keeloq_const.min_count_bit_for_found) { subghz_protocol_blocks_add_bit(&instance->decoder, 1); @@ -415,7 +415,7 @@ void subghz_protocol_decoder_keeloq_feed(void* context, bool level, uint32_t dur instance->decoder.parser_step = KeeloqDecoderStepSaveDuration; } else if( (DURATION_DIFF(instance->decoder.te_last, subghz_protocol_keeloq_const.te_long) < - subghz_protocol_keeloq_const.te_delta) && + subghz_protocol_keeloq_const.te_delta * 2) && (DURATION_DIFF(duration, subghz_protocol_keeloq_const.te_short) < subghz_protocol_keeloq_const.te_delta)) { if(instance->decoder.decode_count_bit < diff --git a/lib/subghz/protocols/magellen.c b/lib/subghz/protocols/magellen.c index 859f80351..bb0600a74 100644 --- a/lib/subghz/protocols/magellen.c +++ b/lib/subghz/protocols/magellen.c @@ -360,11 +360,11 @@ static void subghz_protocol_magellen_check_remote_controller(SubGhzBlockGeneric* * 0x1275EC => 0x12-event codes, 0x75EC-serial (dec 117236) * * event codes -* bit_0: 1-alarm, 0-close +* bit_0: 1-Open/Motion, 0-close/ok * bit_1: 1-Tamper On (alarm), 0-Tamper Off (ok) * bit_2: ? * bit_3: 1-power on -* bit_4: model type - door alarm +* bit_4: model type - wireless reed * bit_5: model type - motion sensor * bit_6: ? * bit_7: ? @@ -379,11 +379,12 @@ static void subghz_protocol_magellen_get_event_serialize(uint8_t event, string_t string_cat_printf( output, "%s%s%s%s%s%s%s%s", - (event & 0x1 ? " Alarm" : "Ok"), + ((event >> 4) & 0x1 ? (event & 0x1 ? " Open" : " Close") : + (event & 0x1 ? " Motion" : " Ok")), ((event >> 1) & 0x1 ? ", Tamper On (Alarm)" : ""), ((event >> 2) & 0x1 ? ", ?" : ""), ((event >> 3) & 0x1 ? ", Power On" : ""), - ((event >> 4) & 0x1 ? ", MT:Door_Alarm" : ""), + ((event >> 4) & 0x1 ? ", MT:Wireless_Reed" : ""), ((event >> 5) & 0x1 ? ", MT:Motion_Sensor" : ""), ((event >> 6) & 0x1 ? ", ?" : ""), ((event >> 7) & 0x1 ? ", ?" : "")); diff --git a/lib/subghz/protocols/oregon2.c b/lib/subghz/protocols/oregon2.c new file mode 100644 index 000000000..84bb38be4 --- /dev/null +++ b/lib/subghz/protocols/oregon2.c @@ -0,0 +1,324 @@ +#include "oregon2.h" +#include "../blocks/const.h" +#include "../blocks/decoder.h" +#include "../blocks/generic.h" +#include "../blocks/math.h" +#include +#include +#include + +#define TAG "SubGhzProtocolOregon2" + +static const SubGhzBlockConst oregon2_const = { + .te_long = 1000, + .te_short = 500, + .te_delta = 200, + .min_count_bit_for_found = 32, +}; + +#define OREGON2_PREAMBLE_BITS 19 +#define OREGON2_PREAMBLE_MASK ((1 << (OREGON2_PREAMBLE_BITS + 1)) - 1) +#define OREGON2_SENSOR_ID(d) (((d) >> 16) & 0xFFFF) +#define OREGON2_CHECKSUM_BITS 8 + +// 15 ones + 0101 (inverted A) +#define OREGON2_PREAMBLE 0b1111111111111110101 + +// bit indicating the low battery +#define OREGON2_FLAG_BAT_LOW 0x4 + +struct SubGhzProtocolDecoderOregon2 { + SubGhzProtocolDecoderBase base; + + SubGhzBlockDecoder decoder; + SubGhzBlockGeneric generic; + ManchesterState manchester_state; + bool prev_bit; + bool have_bit; + + uint8_t var_bits; + uint32_t var_data; +}; + +typedef struct SubGhzProtocolDecoderOregon2 SubGhzProtocolDecoderOregon2; + +typedef enum { + Oregon2DecoderStepReset = 0, + Oregon2DecoderStepFoundPreamble, + Oregon2DecoderStepVarData, +} Oregon2DecoderStep; + +void* subghz_protocol_decoder_oregon2_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolDecoderOregon2* instance = malloc(sizeof(SubGhzProtocolDecoderOregon2)); + instance->base.protocol = &subghz_protocol_oregon2; + instance->generic.protocol_name = instance->base.protocol->name; + return instance; +} + +void subghz_protocol_decoder_oregon2_free(void* context) { + furi_assert(context); + SubGhzProtocolDecoderOregon2* instance = context; + free(instance); +} + +void subghz_protocol_decoder_oregon2_reset(void* context) { + furi_assert(context); + SubGhzProtocolDecoderOregon2* instance = context; + instance->decoder.parser_step = Oregon2DecoderStepReset; + instance->decoder.decode_data = 0UL; + instance->decoder.decode_count_bit = 0; + manchester_advance( + instance->manchester_state, ManchesterEventReset, &instance->manchester_state, NULL); + instance->have_bit = false; + instance->var_data = 0; + instance->var_bits = 0; +} + +static ManchesterEvent level_and_duration_to_event(bool level, uint32_t duration) { + bool is_long = false; + + if(DURATION_DIFF(duration, oregon2_const.te_long) < oregon2_const.te_delta) { + is_long = true; + } else if(DURATION_DIFF(duration, oregon2_const.te_short) < oregon2_const.te_delta) { + is_long = false; + } else { + return ManchesterEventReset; + } + + if(level) + return is_long ? ManchesterEventLongHigh : ManchesterEventShortHigh; + else + return is_long ? ManchesterEventLongLow : ManchesterEventShortLow; +} + +// From sensor id code return amount of bits in variable section +static uint8_t oregon2_sensor_id_var_bits(uint16_t sensor_id) { + if(sensor_id == 0xEC40) return 16; + return 0; +} + +void subghz_protocol_decoder_oregon2_feed(void* context, bool level, uint32_t duration) { + furi_assert(context); + SubGhzProtocolDecoderOregon2* instance = context; + // oregon v2.1 signal is inverted + ManchesterEvent event = level_and_duration_to_event(!level, duration); + bool data; + + // low-level bit sequence decoding + if(event == ManchesterEventReset) { + instance->decoder.parser_step = Oregon2DecoderStepReset; + instance->have_bit = false; + instance->decoder.decode_data = 0UL; + instance->decoder.decode_count_bit = 0; + } + if(manchester_advance(instance->manchester_state, event, &instance->manchester_state, &data)) { + if(instance->have_bit) { + if(!instance->prev_bit && data) { + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + } else if(instance->prev_bit && !data) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + } else { + subghz_protocol_decoder_oregon2_reset(context); + } + instance->have_bit = false; + } else { + instance->prev_bit = data; + instance->have_bit = true; + } + } + + switch(instance->decoder.parser_step) { + case Oregon2DecoderStepReset: + // waiting for fixed oregon2 preamble + if(instance->decoder.decode_count_bit >= OREGON2_PREAMBLE_BITS && + ((instance->decoder.decode_data & OREGON2_PREAMBLE_MASK) == OREGON2_PREAMBLE)) { + instance->decoder.parser_step = Oregon2DecoderStepFoundPreamble; + instance->decoder.decode_count_bit = 0; + instance->decoder.decode_data = 0UL; + } + break; + case Oregon2DecoderStepFoundPreamble: + // waiting for fixed oregon2 data + if(instance->decoder.decode_count_bit == 32) { + instance->generic.data = instance->decoder.decode_data; + instance->generic.data_count_bit = instance->decoder.decode_count_bit; + instance->decoder.decode_data = 0UL; + instance->decoder.decode_count_bit = 0; + + // reverse nibbles in decoded data + instance->generic.data = (instance->generic.data & 0x55555555) << 1 | + (instance->generic.data & 0xAAAAAAAA) >> 1; + instance->generic.data = (instance->generic.data & 0x33333333) << 2 | + (instance->generic.data & 0xCCCCCCCC) >> 2; + + instance->var_bits = + oregon2_sensor_id_var_bits(OREGON2_SENSOR_ID(instance->generic.data)); + + if(!instance->var_bits) { + // sensor is not supported, stop decoding, but showing the decoded fixed part + instance->decoder.parser_step = Oregon2DecoderStepReset; + if(instance->base.callback) + instance->base.callback(&instance->base, instance->base.context); + } else { + instance->decoder.parser_step = Oregon2DecoderStepVarData; + } + } + break; + case Oregon2DecoderStepVarData: + // waiting for variable (sensor-specific data) + if(instance->decoder.decode_count_bit == instance->var_bits + OREGON2_CHECKSUM_BITS) { + instance->var_data = instance->decoder.decode_data & 0xFFFFFFFF; + + // reverse nibbles in var data + instance->var_data = (instance->var_data & 0x55555555) << 1 | + (instance->var_data & 0xAAAAAAAA) >> 1; + instance->var_data = (instance->var_data & 0x33333333) << 2 | + (instance->var_data & 0xCCCCCCCC) >> 2; + + instance->decoder.parser_step = Oregon2DecoderStepReset; + if(instance->base.callback) + instance->base.callback(&instance->base, instance->base.context); + } + break; + } +} + +uint8_t subghz_protocol_decoder_oregon2_get_hash_data(void* context) { + furi_assert(context); + SubGhzProtocolDecoderOregon2* instance = context; + return subghz_protocol_blocks_get_hash_data( + &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); +} + +bool subghz_protocol_decoder_oregon2_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzPresetDefinition* preset) { + furi_assert(context); + SubGhzProtocolDecoderOregon2* instance = context; + if(!subghz_block_generic_serialize(&instance->generic, flipper_format, preset)) return false; + uint32_t temp = instance->var_bits; + if(!flipper_format_write_uint32(flipper_format, "VarBits", &temp, 1)) { + FURI_LOG_E(TAG, "Error adding VarBits"); + return false; + } + if(!flipper_format_write_hex( + flipper_format, + "VarData", + (const uint8_t*)&instance->var_data, + sizeof(instance->var_data))) { + FURI_LOG_E(TAG, "Error adding VarData"); + return false; + } + return true; +} + +bool subghz_protocol_decoder_oregon2_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolDecoderOregon2* instance = context; + bool ret = false; + uint32_t temp_data; + do { + if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + break; + } + if(!flipper_format_read_uint32(flipper_format, "VarBits", &temp_data, 1)) { + FURI_LOG_E(TAG, "Missing VarLen"); + break; + } + instance->var_bits = (uint8_t)temp_data; + if(!flipper_format_read_hex( + flipper_format, + "VarData", + (uint8_t*)&instance->var_data, + sizeof(instance->var_data))) { + FURI_LOG_E(TAG, "Missing VarData"); + break; + } + if(instance->generic.data_count_bit != oregon2_const.min_count_bit_for_found) { + FURI_LOG_E(TAG, "Wrong number of bits in key: %d", instance->generic.data_count_bit); + break; + } + ret = true; + } while(false); + return ret; +} + +// append string of the variable data +static void + oregon2_var_data_append_string(uint16_t sensor_id, uint32_t var_data, string_t output) { + uint32_t val; + + if(sensor_id == 0xEC40) { + val = ((var_data >> 4) & 0xF) * 10 + ((var_data >> 8) & 0xF); + string_cat_printf( + output, + "Temp: %s%d.%d C\r\n", + (var_data & 0xF) ? "-" : "+", + val, + (uint32_t)(var_data >> 12) & 0xF); + } +} + +static void oregon2_append_check_sum(uint32_t fix_data, uint32_t var_data, string_t output) { + uint8_t sum = fix_data & 0xF; + uint8_t ref_sum = var_data & 0xFF; + var_data >>= 8; + + for(uint8_t i = 1; i < 8; i++) { + fix_data >>= 4; + var_data >>= 4; + sum += (fix_data & 0xF) + (var_data & 0xF); + } + + // swap calculated sum nibbles + sum = (((sum >> 4) & 0xF) | (sum << 4)) & 0xFF; + if(sum == ref_sum) + string_cat_printf(output, "Sum ok: 0x%hhX", ref_sum); + else + string_cat_printf(output, "Sum err: 0x%hhX vs 0x%hhX", ref_sum, sum); +} + +void subghz_protocol_decoder_oregon2_get_string(void* context, string_t output) { + furi_assert(context); + SubGhzProtocolDecoderOregon2* instance = context; + uint16_t sensor_id = OREGON2_SENSOR_ID(instance->generic.data); + string_cat_printf( + output, + "%s\r\n" + "ID: 0x%04lX, ch: %d%s, rc: 0x%02lX\r\n", + instance->generic.protocol_name, + (uint32_t)sensor_id, + (uint32_t)(instance->generic.data >> 12) & 0xF, + ((instance->generic.data & OREGON2_FLAG_BAT_LOW) ? ", low bat" : ""), + (uint32_t)(instance->generic.data >> 4) & 0xFF); + + if(instance->var_bits > 0) { + oregon2_var_data_append_string( + sensor_id, instance->var_data >> OREGON2_CHECKSUM_BITS, output); + oregon2_append_check_sum((uint32_t)instance->generic.data, instance->var_data, output); + } +} + +const SubGhzProtocolDecoder subghz_protocol_oregon2_decoder = { + .alloc = subghz_protocol_decoder_oregon2_alloc, + .free = subghz_protocol_decoder_oregon2_free, + + .feed = subghz_protocol_decoder_oregon2_feed, + .reset = subghz_protocol_decoder_oregon2_reset, + + .get_hash_data = subghz_protocol_decoder_oregon2_get_hash_data, + .serialize = subghz_protocol_decoder_oregon2_serialize, + .deserialize = subghz_protocol_decoder_oregon2_deserialize, + .get_string = subghz_protocol_decoder_oregon2_get_string, +}; + +const SubGhzProtocol subghz_protocol_oregon2 = { + .name = SUBGHZ_PROTOCOL_OREGON2_NAME, + .type = SubGhzProtocolTypeStatic, + .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | + SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save, + + .decoder = &subghz_protocol_oregon2_decoder, +}; diff --git a/lib/subghz/protocols/oregon2.h b/lib/subghz/protocols/oregon2.h new file mode 100644 index 000000000..981b25999 --- /dev/null +++ b/lib/subghz/protocols/oregon2.h @@ -0,0 +1,5 @@ +#pragma once + +#include "base.h" +#define SUBGHZ_PROTOCOL_OREGON2_NAME "Oregon2" +extern const SubGhzProtocol subghz_protocol_oregon2; diff --git a/lib/subghz/protocols/raw.h b/lib/subghz/protocols/raw.h index 00654ad28..b52a7d84e 100644 --- a/lib/subghz/protocols/raw.h +++ b/lib/subghz/protocols/raw.h @@ -4,6 +4,10 @@ #define SUBGHZ_PROTOCOL_RAW_NAME "RAW" +#ifdef __cplusplus +extern "C" { +#endif + typedef void (*SubGhzProtocolEncoderRAWCallbackEnd)(void* context); typedef struct SubGhzProtocolDecoderRAW SubGhzProtocolDecoderRAW; @@ -99,12 +103,6 @@ void subghz_protocol_encoder_raw_free(void* context); */ void subghz_protocol_encoder_raw_stop(void* context); -/** - * Сallback on completion of file transfer. - * @param context Pointer to a SubGhzProtocolEncoderRAW instance - */ -void subghz_protocol_raw_file_encoder_worker_callback_end(void* context); - /** * Set callback on completion of file transfer. * @param instance Pointer to a SubGhzProtocolEncoderRAW instance @@ -137,3 +135,7 @@ bool subghz_protocol_encoder_raw_deserialize(void* context, FlipperFormat* flipp * @return LevelDuration */ LevelDuration subghz_protocol_encoder_raw_yield(void* context); + +#ifdef __cplusplus +} +#endif diff --git a/lib/subghz/protocols/registry.c b/lib/subghz/protocols/registry.c index b72278788..453fa747a 100644 --- a/lib/subghz/protocols/registry.c +++ b/lib/subghz/protocols/registry.c @@ -11,9 +11,8 @@ const SubGhzProtocol* subghz_protocol_registry[] = { &subghz_protocol_secplus_v1, &subghz_protocol_megacode, &subghz_protocol_holtek, &subghz_protocol_chamb_code, &subghz_protocol_power_smart, &subghz_protocol_marantec, &subghz_protocol_bett, &subghz_protocol_doitrand, &subghz_protocol_phoenix_v2, - &subghz_protocol_honeywell_wdb, &subghz_protocol_magellen, - -}; + &subghz_protocol_honeywell_wdb, &subghz_protocol_magellen, &subghz_protocol_intertechno_v3, + &subghz_protocol_clemsa, &subghz_protocol_oregon2}; const SubGhzProtocol* subghz_protocol_registry_get_by_name(const char* name) { for(size_t i = 0; i < subghz_protocol_registry_count(); i++) { diff --git a/lib/subghz/protocols/registry.h b/lib/subghz/protocols/registry.h index 36a560765..8eb464ada 100644 --- a/lib/subghz/protocols/registry.h +++ b/lib/subghz/protocols/registry.h @@ -34,6 +34,9 @@ #include "phoenix_v2.h" #include "honeywell_wdb.h" #include "magellen.h" +#include "intertechno_v3.h" +#include "clemsa.h" +#include "oregon2.h" /** * Registration by name SubGhzProtocol. diff --git a/lib/subghz/receiver.h b/lib/subghz/receiver.h index 1357ecbed..2ef722d1f 100644 --- a/lib/subghz/receiver.h +++ b/lib/subghz/receiver.h @@ -3,6 +3,10 @@ #include "types.h" #include "protocols/base.h" +#ifdef __cplusplus +extern "C" { +#endif + typedef struct SubGhzReceiver SubGhzReceiver; typedef void (*SubGhzReceiverCallback)( @@ -63,3 +67,7 @@ void subghz_receiver_set_filter(SubGhzReceiver* instance, SubGhzProtocolFlag fil */ SubGhzProtocolDecoderBase* subghz_receiver_search_decoder_base_by_name(SubGhzReceiver* instance, const char* decoder_name); + +#ifdef __cplusplus +} +#endif diff --git a/lib/subghz/subghz_keystore.c b/lib/subghz/subghz_keystore.c index 0abd2d5e6..4d2eb0e50 100644 --- a/lib/subghz/subghz_keystore.c +++ b/lib/subghz/subghz_keystore.c @@ -114,62 +114,69 @@ static bool subghz_keystore_read_file(SubGhzKeystore* instance, Stream* stream, char* encrypted_line = malloc(SUBGHZ_KEYSTORE_FILE_ENCRYPTED_LINE_SIZE); size_t encrypted_line_cursor = 0; - if(iv) furi_hal_crypto_store_load_key(SUBGHZ_KEYSTORE_FILE_ENCRYPTION_KEY_SLOT, iv); - - size_t ret = 0; do { - ret = stream_read(stream, buffer, FILE_BUFFER_SIZE); - for(uint16_t i = 0; i < ret; i++) { - if(buffer[i] == '\n' && encrypted_line_cursor > 0) { - // Process line - if(iv) { - // Data alignment check, 32 instead of 16 because of hex encoding - size_t len = strlen(encrypted_line); - if(len % 32 == 0) { - // Inplace hex to bin conversion - for(size_t i = 0; i < len; i += 2) { - uint8_t hi_nibble = 0; - uint8_t lo_nibble = 0; - hex_char_to_hex_nibble(encrypted_line[i], &hi_nibble); - hex_char_to_hex_nibble(encrypted_line[i + 1], &lo_nibble); - encrypted_line[i / 2] = (hi_nibble << 4) | lo_nibble; - } - len /= 2; - - if(furi_hal_crypto_decrypt( - (uint8_t*)encrypted_line, (uint8_t*)decrypted_line, len)) { - subghz_keystore_process_line(instance, decrypted_line); - } else { - FURI_LOG_E(TAG, "Decryption failed"); - result = false; - break; - } - } else { - FURI_LOG_E(TAG, "Invalid encrypted data: %s", encrypted_line); - } - } else { - subghz_keystore_process_line(instance, encrypted_line); - } - // reset line buffer - memset(decrypted_line, 0, SUBGHZ_KEYSTORE_FILE_DECRYPTED_LINE_SIZE); - memset(encrypted_line, 0, SUBGHZ_KEYSTORE_FILE_ENCRYPTED_LINE_SIZE); - encrypted_line_cursor = 0; - } else if(buffer[i] == '\r' || buffer[i] == '\n') { - // do not add line endings to the buffer - } else { - if(encrypted_line_cursor < SUBGHZ_KEYSTORE_FILE_ENCRYPTED_LINE_SIZE) { - encrypted_line[encrypted_line_cursor] = buffer[i]; - encrypted_line_cursor++; - } else { - FURI_LOG_E(TAG, "Malformed file"); - result = false; - break; - } + if(iv) { + if(!furi_hal_crypto_store_load_key(SUBGHZ_KEYSTORE_FILE_ENCRYPTION_KEY_SLOT, iv)) { + FURI_LOG_E(TAG, "Unable to load decryption key"); + break; } } - } while(ret > 0 && result); - if(iv) furi_hal_crypto_store_unload_key(SUBGHZ_KEYSTORE_FILE_ENCRYPTION_KEY_SLOT); + size_t ret = 0; + do { + ret = stream_read(stream, buffer, FILE_BUFFER_SIZE); + for(uint16_t i = 0; i < ret; i++) { + if(buffer[i] == '\n' && encrypted_line_cursor > 0) { + // Process line + if(iv) { + // Data alignment check, 32 instead of 16 because of hex encoding + size_t len = strlen(encrypted_line); + if(len % 32 == 0) { + // Inplace hex to bin conversion + for(size_t i = 0; i < len; i += 2) { + uint8_t hi_nibble = 0; + uint8_t lo_nibble = 0; + hex_char_to_hex_nibble(encrypted_line[i], &hi_nibble); + hex_char_to_hex_nibble(encrypted_line[i + 1], &lo_nibble); + encrypted_line[i / 2] = (hi_nibble << 4) | lo_nibble; + } + len /= 2; + + if(furi_hal_crypto_decrypt( + (uint8_t*)encrypted_line, (uint8_t*)decrypted_line, len)) { + subghz_keystore_process_line(instance, decrypted_line); + } else { + FURI_LOG_E(TAG, "Decryption failed"); + result = false; + break; + } + } else { + FURI_LOG_E(TAG, "Invalid encrypted data: %s", encrypted_line); + } + } else { + subghz_keystore_process_line(instance, encrypted_line); + } + // reset line buffer + memset(decrypted_line, 0, SUBGHZ_KEYSTORE_FILE_DECRYPTED_LINE_SIZE); + memset(encrypted_line, 0, SUBGHZ_KEYSTORE_FILE_ENCRYPTED_LINE_SIZE); + encrypted_line_cursor = 0; + } else if(buffer[i] == '\r' || buffer[i] == '\n') { + // do not add line endings to the buffer + } else { + if(encrypted_line_cursor < SUBGHZ_KEYSTORE_FILE_ENCRYPTED_LINE_SIZE) { + encrypted_line[encrypted_line_cursor] = buffer[i]; + encrypted_line_cursor++; + } else { + FURI_LOG_E(TAG, "Malformed file"); + result = false; + break; + } + } + } + } while(ret > 0 && result); + + if(iv) furi_hal_crypto_store_unload_key(SUBGHZ_KEYSTORE_FILE_ENCRYPTION_KEY_SLOT); + } while(false); free(encrypted_line); free(decrypted_line); diff --git a/lib/subghz/subghz_keystore.h b/lib/subghz/subghz_keystore.h index be9a19df6..2b7880f07 100644 --- a/lib/subghz/subghz_keystore.h +++ b/lib/subghz/subghz_keystore.h @@ -4,6 +4,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + typedef struct { string_t name; uint64_t key; @@ -70,3 +74,7 @@ bool subghz_keystore_raw_encrypted_save( * @return true On success */ bool subghz_keystore_raw_get_data(const char* file_name, size_t offset, uint8_t* data, size_t len); + +#ifdef __cplusplus +} +#endif diff --git a/lib/subghz/subghz_tx_rx_worker.h b/lib/subghz/subghz_tx_rx_worker.h index 3f3f82769..ddc02e749 100644 --- a/lib/subghz/subghz_tx_rx_worker.h +++ b/lib/subghz/subghz_tx_rx_worker.h @@ -2,6 +2,10 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + typedef void (*SubGhzTxRxWorkerCallbackHaveRead)(void* context); typedef struct SubGhzTxRxWorker SubGhzTxRxWorker; @@ -79,3 +83,7 @@ void subghz_tx_rx_worker_stop(SubGhzTxRxWorker* instance); * @return bool - true if running */ bool subghz_tx_rx_worker_is_running(SubGhzTxRxWorker* instance); + +#ifdef __cplusplus +} +#endif diff --git a/lib/subghz/subghz_worker.h b/lib/subghz/subghz_worker.h index bb303165c..f85b1fdc7 100644 --- a/lib/subghz/subghz_worker.h +++ b/lib/subghz/subghz_worker.h @@ -2,6 +2,10 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + typedef struct SubGhzWorker SubGhzWorker; typedef void (*SubGhzWorkerOverrunCallback)(void* context); @@ -62,3 +66,7 @@ void subghz_worker_stop(SubGhzWorker* instance); * @return bool - true if running */ bool subghz_worker_is_running(SubGhzWorker* instance); + +#ifdef __cplusplus +} +#endif diff --git a/lib/subghz/transmitter.h b/lib/subghz/transmitter.h index 53f10b075..cce98a463 100644 --- a/lib/subghz/transmitter.h +++ b/lib/subghz/transmitter.h @@ -4,6 +4,10 @@ #include "environment.h" #include "protocols/base.h" +#ifdef __cplusplus +extern "C" { +#endif + typedef struct SubGhzTransmitter SubGhzTransmitter; /** @@ -45,3 +49,7 @@ bool subghz_transmitter_deserialize(SubGhzTransmitter* instance, FlipperFormat* * @return LevelDuration */ LevelDuration subghz_transmitter_yield(void* context); + +#ifdef __cplusplus +} +#endif diff --git a/lib/toolbox/SConscript b/lib/toolbox/SConscript index e4f2cbd02..d631431ee 100644 --- a/lib/toolbox/SConscript +++ b/lib/toolbox/SConscript @@ -7,6 +7,25 @@ env.Append( CPPPATH=[ "#/lib/toolbox", ], + SDK_HEADERS=[ + File("#/lib/toolbox/manchester_decoder.h"), + File("#/lib/toolbox/manchester_encoder.h"), + File("#/lib/toolbox/path.h"), + File("#/lib/toolbox/random_name.h"), + File("#/lib/toolbox/hmac_sha256.h"), + File("#/lib/toolbox/crc32_calc.h"), + File("#/lib/toolbox/dir_walk.h"), + File("#/lib/toolbox/md5.h"), + File("#/lib/toolbox/args.h"), + File("#/lib/toolbox/saved_struct.h"), + File("#/lib/toolbox/version.h"), + File("#/lib/toolbox/tar/tar_archive.h"), + File("#/lib/toolbox/stream/stream.h"), + File("#/lib/toolbox/stream/file_stream.h"), + File("#/lib/toolbox/stream/string_stream.h"), + File("#/lib/toolbox/stream/buffered_file_stream.h"), + File("#/lib/toolbox/protocols/protocol_dict.h"), + ], ) diff --git a/lib/toolbox/hex.c b/lib/toolbox/hex.c index 41bb24bba..7b2719b79 100644 --- a/lib/toolbox/hex.c +++ b/lib/toolbox/hex.c @@ -15,7 +15,7 @@ bool hex_char_to_hex_nibble(char c, uint8_t* nibble) { } } -bool hex_chars_to_uint8(char hi, char low, uint8_t* value) { +bool hex_char_to_uint8(char hi, char low, uint8_t* value) { uint8_t hi_nibble_value, low_nibble_value; if(hex_char_to_hex_nibble(hi, &hi_nibble_value) && @@ -27,13 +27,29 @@ bool hex_chars_to_uint8(char hi, char low, uint8_t* value) { } } +bool hex_chars_to_uint8(const char* value_str, uint8_t* value) { + bool parse_success = false; + while(*value_str && value_str[1]) { + parse_success = hex_char_to_uint8(*value_str, value_str[1], value++); + if(!parse_success) break; + value_str += 2; + } + return parse_success; +} + bool hex_chars_to_uint64(const char* value_str, uint64_t* value) { uint8_t* _value = (uint8_t*)value; bool parse_success = false; for(uint8_t i = 0; i < 8; i++) { - parse_success = hex_chars_to_uint8(value_str[i * 2], value_str[i * 2 + 1], &_value[7 - i]); + parse_success = hex_char_to_uint8(value_str[i * 2], value_str[i * 2 + 1], &_value[7 - i]); if(!parse_success) break; } return parse_success; } + +void uint8_to_hex_chars(const uint8_t* src, uint8_t* target, int length) { + const char chars[] = "0123456789ABCDEF"; + while(--length >= 0) + target[length] = chars[(src[length >> 1] >> ((1 - (length & 1)) << 2)) & 0xF]; +} diff --git a/lib/toolbox/hex.h b/lib/toolbox/hex.h index c6683a52c..740f23b77 100644 --- a/lib/toolbox/hex.h +++ b/lib/toolbox/hex.h @@ -14,14 +14,22 @@ extern "C" { */ bool hex_char_to_hex_nibble(char c, uint8_t* nibble); -/** Convert ASCII hex values to byte +/** Convert ASCII hex value to byte * @param hi hi nibble text * @param low low nibble text * @param value output value * * @return bool conversion status */ -bool hex_chars_to_uint8(char hi, char low, uint8_t* value); +bool hex_char_to_uint8(char hi, char low, uint8_t* value); + +/** Convert ASCII hex values to uint8_t + * @param value_str ASCII data + * @param value output value + * + * @return bool conversion status + */ +bool hex_chars_to_uint8(const char* value_str, uint8_t* value); /** Convert ASCII hex values to uint64_t * @param value_str ASCII 64 bi data @@ -31,6 +39,14 @@ bool hex_chars_to_uint8(char hi, char low, uint8_t* value); */ bool hex_chars_to_uint64(const char* value_str, uint64_t* value); +/** Convert uint8_t to ASCII hex values + * @param src source data + * @param target output value + * @param length data length + * + */ +void uint8_to_hex_chars(const uint8_t* src, uint8_t* target, int length); + #ifdef __cplusplus } #endif diff --git a/lib/toolbox/hmac_sha256.h b/lib/toolbox/hmac_sha256.h index 01fc0b146..add123142 100644 --- a/lib/toolbox/hmac_sha256.h +++ b/lib/toolbox/hmac_sha256.h @@ -1,3 +1,10 @@ +#pragma once + +#include "sha256.h" + +#ifdef __cplusplus +extern "C" { +#endif typedef struct hmac_context { void (*init_hash)(const struct hmac_context* context); @@ -25,3 +32,7 @@ void hmac_sha256_update( unsigned message_size); void hmac_sha256_finish(const hmac_sha256_context* ctx, const uint8_t* K, uint8_t* hash_result); + +#ifdef __cplusplus +} +#endif diff --git a/lib/toolbox/saved_struct.h b/lib/toolbox/saved_struct.h index aae41bd61..aaa04eef5 100644 --- a/lib/toolbox/saved_struct.h +++ b/lib/toolbox/saved_struct.h @@ -4,6 +4,14 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + bool saved_struct_load(const char* path, void* data, size_t size, uint8_t magic, uint8_t version); bool saved_struct_save(const char* path, void* data, size_t size, uint8_t magic, uint8_t version); + +#ifdef __cplusplus +} +#endif diff --git a/lib/toolbox/sha256.h b/lib/toolbox/sha256.h index 85b9709db..c544d3ebb 100644 --- a/lib/toolbox/sha256.h +++ b/lib/toolbox/sha256.h @@ -1,3 +1,9 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + #define SHA256_DIGEST_SIZE 32 #define SHA256_BLOCK_SIZE 64 @@ -12,3 +18,7 @@ void sha256_start(sha256_context* ctx); void sha256_finish(sha256_context* ctx, unsigned char output[32]); void sha256_update(sha256_context* ctx, const unsigned char* input, unsigned int ilen); void sha256_process(sha256_context* ctx); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/lib/toolbox/tar/tar_archive.c b/lib/toolbox/tar/tar_archive.c index 5ac89a0fd..0d42d162c 100644 --- a/lib/toolbox/tar/tar_archive.c +++ b/lib/toolbox/tar/tar_archive.c @@ -294,6 +294,7 @@ bool tar_archive_add_file( break; } + success = true; // if file is empty, that's not an error uint16_t bytes_read = 0; while((bytes_read = storage_file_read(src_file, file_buffer, FILE_BLOCK_SIZE))) { success = tar_archive_file_add_data_block(archive, file_buffer, bytes_read); diff --git a/lib/u8g2/u8g2_glue.c b/lib/u8g2/u8g2_glue.c index 77f37f14c..17a702b50 100644 --- a/lib/u8g2/u8g2_glue.c +++ b/lib/u8g2/u8g2_glue.c @@ -225,7 +225,7 @@ uint8_t u8x8_d_st756x_flipper(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* * RR = 10 / ((1 - (63 - 32) / 162) * 2.1) ~= 5.88 is 6 (0b110) * Bias = 1/9 (false) */ - u8x8_d_st756x_init(u8x8, 32, 0b110, false); + u8x8_d_st756x_init(u8x8, 31, 0b110, false); } else { /* ERC v1(ST7565) and v2(ST7567) * EV = 33 @@ -233,7 +233,7 @@ uint8_t u8x8_d_st756x_flipper(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* * RR = 9.3 / ((1 - (63 - 32) / 162) * 2.1) ~= 5.47 is 5.5 (0b101) * Bias = 1/9 (false) */ - u8x8_d_st756x_init(u8x8, 33, 0b101, false); + u8x8_d_st756x_init(u8x8, 32, 0b101, false); } break; case U8X8_MSG_DISPLAY_SET_FLIP_MODE: diff --git a/lib/update_util/lfs_backup.c b/lib/update_util/lfs_backup.c index 724da3657..089f032d4 100644 --- a/lib/update_util/lfs_backup.c +++ b/lib/update_util/lfs_backup.c @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #define LFS_BACKUP_DEFAULT_LOCATION EXT_PATH(LFS_BACKUP_DEFAULT_FILENAME) @@ -42,8 +42,7 @@ bool lfs_backup_create(Storage* storage, const char* destination) { bool lfs_backup_exists(Storage* storage, const char* source) { const char* final_source = source && strlen(source) ? source : LFS_BACKUP_DEFAULT_LOCATION; - FileInfo fi; - return storage_common_stat(storage, final_source, &fi) == FSE_OK; + return storage_common_stat(storage, final_source, NULL) == FSE_OK; } bool lfs_backup_unpack(Storage* storage, const char* source) { diff --git a/lib/update_util/update_operation.c b/lib/update_util/update_operation.c index 138828ff0..56f412a95 100644 --- a/lib/update_util/update_operation.c +++ b/lib/update_util/update_operation.c @@ -12,7 +12,7 @@ #define UPDATE_ROOT_DIR EXT_PATH("update") /* Need at least 4 free LFS pages before update */ -#define UPDATE_MIN_INT_FREE_SPACE 4 * 4 * 1024 +#define UPDATE_MIN_INT_FREE_SPACE 2 * 4 * 1024 static const char* update_prepare_result_descr[] = { [UpdatePrepareResultOK] = "OK", diff --git a/scripts/ReadMe.md b/scripts/ReadMe.md index d06303957..d37e67c90 100644 --- a/scripts/ReadMe.md +++ b/scripts/ReadMe.md @@ -26,7 +26,6 @@ Also display type, region and etc... ## Core1 and Core2 firmware flashing -Main flashing sequence can be found in root `Makefile`. Core2 goes first, then Core1. Never flash FUS or you will loose your job, girlfriend and keys in secure enclave. diff --git a/scripts/assets.py b/scripts/assets.py index b27b29efd..1f36a135b 100755 --- a/scripts/assets.py +++ b/scripts/assets.py @@ -3,16 +3,12 @@ from flipper.app import App from flipper.assets.icon import file2image -import logging -import argparse -import subprocess -import io import os -import sys ICONS_SUPPORTED_FORMATS = ["png"] ICONS_TEMPLATE_H_HEADER = """#pragma once + #include """ diff --git a/scripts/get_env.py b/scripts/get_env.py new file mode 100644 index 000000000..d05273094 --- /dev/null +++ b/scripts/get_env.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python3 + +import ssl +import json +import os +import shlex +import re +import string +import random +import argparse +import datetime +import urllib.request + + +def id_gen(size=5, chars=string.ascii_uppercase + string.digits): + return "".join(random.choice(chars) for _ in range(size)) + + +def parse_args(): + parser = argparse.ArgumentParser() + parser.add_argument("--event_file", help="Current GitHub event file", required=True) + parser.add_argument( + "--type", + help="Event file type", + required=True, + choices=["pull", "tag", "other"], + ) + args = parser.parse_args() + return args + + +def get_commit_json(event): + context = ssl._create_unverified_context() + with urllib.request.urlopen( + event["pull_request"]["_links"]["commits"]["href"], context=context + ) as commit_file: + commit_json = json.loads(commit_file.read().decode("utf-8")) + return commit_json + + +def get_details(event, args): + data = {} + current_time = datetime.datetime.utcnow().date() + if args.type == "pull": + commit_json = get_commit_json(event) + data["commit_comment"] = shlex.quote(commit_json[-1]["commit"]["message"]) + data["commit_hash"] = commit_json[-1]["sha"] + ref = event["pull_request"]["head"]["ref"] + data["pull_id"] = event["pull_request"]["number"] + data["pull_name"] = shlex.quote(event["pull_request"]["title"]) + elif args.type == "tag": + data["commit_comment"] = shlex.quote(event["head_commit"]["message"]) + data["commit_hash"] = event["head_commit"]["id"] + ref = event["ref"] + else: + data["commit_comment"] = shlex.quote(event["commits"][-1]["message"]) + data["commit_hash"] = event["commits"][-1]["id"] + ref = event["ref"] + data["commit_sha"] = data["commit_hash"][:8] + data["branch_name"] = re.sub("refs/\w+/", "", ref) + data["suffix"] = ( + data["branch_name"].replace("/", "_") + + "-" + + current_time.strftime("%d%m%Y") + + "-" + + data["commit_sha"] + ) + if ref.startswith("refs/tags/"): + data["suffix"] = data["branch_name"].replace("/", "_") + return data + + +def add_env(name, value, file): + delimeter = id_gen() + print(f"{name}<<{delimeter}", file=file) + print(f"{value}", file=file) + print(f"{delimeter}", file=file) + + +def add_envs(data, env_file, args): + add_env("COMMIT_MSG", data["commit_comment"], env_file) + add_env("COMMIT_HASH", data["commit_hash"], env_file) + add_env("COMMIT_SHA", data["commit_sha"], env_file) + add_env("SUFFIX", data["suffix"], env_file) + add_env("BRANCH_NAME", data["branch_name"], env_file) + add_env("DIST_SUFFIX", data["suffix"], env_file) + add_env("WORKFLOW_BRANCH_OR_TAG", data["branch_name"], env_file) + if args.type == "pull": + add_env("PULL_ID", data["pull_id"], env_file) + add_env("PULL_NAME", data["pull_name"], env_file) + + +def main(): + args = parse_args() + event_file = open(args.event_file) + event = json.load(event_file) + env_file = open(os.environ["GITHUB_ENV"], "a") + data = get_details(event, args) + add_envs(data, env_file, args) + event_file.close() + env_file.close() + + +if __name__ == "__main__": + main() diff --git a/scripts/lint.py b/scripts/lint.py index b3c3e7da4..30a5699a7 100755 --- a/scripts/lint.py +++ b/scripts/lint.py @@ -88,7 +88,7 @@ class Main(App): def _fix_filename(self, filename: str): return filename.replace("-", "_") - def _replace_occurance(self, sources: list, old: str, new: str): + def _replace_occurrence(self, sources: list, old: str, new: str): old = old.encode() new = new.encode() for source in sources: @@ -102,7 +102,7 @@ class Main(App): pattern = re.compile(SOURCE_CODE_FILE_PATTERN) good = [] bad = [] - # Check sources for invalid filesname + # Check sources for invalid filenames for source in sources: basename = os.path.basename(source) if not pattern.match(basename): @@ -113,40 +113,63 @@ class Main(App): bad.append((source, basename, new_basename)) else: good.append(source) - # Notify about errors or replace all occurances + # Notify about errors or replace all occurrences if dry_run: if len(bad) > 0: self.logger.error(f"Found {len(bad)} incorrectly named files") self.logger.info(bad) return False else: - # Replace occurances in text files + # Replace occurrences in text files for source, old, new in bad: - self._replace_occurance(sources, old, new) + self._replace_occurrence(sources, old, new) # Rename files for source, old, new in bad: shutil.move(source, source.replace(old, new)) return True - def check(self): + def _apply_file_permissions(self, sources: list, dry_run: bool = False): + execute_permissions = 0o111 + pattern = re.compile(SOURCE_CODE_FILE_PATTERN) + good = [] + bad = [] + # Check sources for unexpected execute permissions + for source in sources: + st = os.stat(source) + perms_too_many = st.st_mode & execute_permissions + if perms_too_many: + good_perms = st.st_mode & ~perms_too_many + bad.append((source, oct(perms_too_many), good_perms)) + else: + good.append(source) + # Notify or fix + if dry_run: + if len(bad) > 0: + self.logger.error(f"Found {len(bad)} incorrect permissions") + self.logger.info([record[0:2] for record in bad]) + return False + else: + for source, perms_too_many, new_perms in bad: + os.chmod(source, new_perms) + return True + + def _perform(self, dry_run: bool): result = 0 sources = self._find_sources(self.args.input) - if not self._format_sources(sources, dry_run=True): - result |= 0b01 - if not self._apply_file_naming_convention(sources, dry_run=True): - result |= 0b10 + if not self._format_sources(sources, dry_run=dry_run): + result |= 0b001 + if not self._apply_file_naming_convention(sources, dry_run=dry_run): + result |= 0b010 + if not self._apply_file_permissions(sources, dry_run=dry_run): + result |= 0b100 self._check_folders(self.args.input) return result + def check(self): + return self._perform(dry_run=True) + def format(self): - result = 0 - sources = self._find_sources(self.args.input) - if not self._format_sources(sources): - result |= 0b01 - if not self._apply_file_naming_convention(sources): - result |= 0b10 - self._check_folders(self.args.input) - return result + return self._perform(dry_run=False) if __name__ == "__main__": diff --git a/scripts/runfap.py b/scripts/runfap.py new file mode 100644 index 000000000..c2c0f78d5 --- /dev/null +++ b/scripts/runfap.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python3 + +import posixpath +from typing import final +from flipper.app import App +from flipper.storage import FlipperStorage +from flipper.utils.cdc import resolve_port + +import logging +import os +import pathlib +import serial.tools.list_ports as list_ports + + +class Main(App): + def init(self): + self.parser.add_argument("-p", "--port", help="CDC Port", default="auto") + + self.parser.add_argument("fap_src_path", help="App file to upload") + self.parser.add_argument( + "--fap_dst_dir", help="Upload path", default="/ext/apps", required=False + ) + self.parser.set_defaults(func=self.install) + + # logging + self.logger = logging.getLogger() + + # make directory with exist check + def mkdir_on_storage(self, storage, flipper_dir_path): + if not storage.exist_dir(flipper_dir_path): + self.logger.debug(f'"{flipper_dir_path}" does not exist, creating') + if not storage.mkdir(flipper_dir_path): + self.logger.error(f"Error: {storage.last_error}") + return False + else: + self.logger.debug(f'"{flipper_dir_path}" already exists') + return True + + # send file with exist check and hash check + def send_file_to_storage(self, storage, flipper_file_path, local_file_path, force): + exists = storage.exist_file(flipper_file_path) + do_upload = not exists + if exists: + hash_local = storage.hash_local(local_file_path) + hash_flipper = storage.hash_flipper(flipper_file_path) + self.logger.debug(f"hash check: local {hash_local}, flipper {hash_flipper}") + do_upload = force or (hash_local != hash_flipper) + + if do_upload: + self.logger.info(f'Sending "{local_file_path}" to "{flipper_file_path}"') + if not storage.send_file(local_file_path, flipper_file_path): + self.logger.error(f"Error: {storage.last_error}") + return False + return True + + def install(self): + if not (port := resolve_port(self.logger, self.args.port)): + return 1 + + storage = FlipperStorage(port) + storage.start() + + try: + fap_local_path = self.args.fap_src_path + self.args.fap_dst_dir = self.args.fap_dst_dir.rstrip("/\\") + + if not os.path.isfile(fap_local_path): + self.logger.error(f"Error: source .fap ({fap_local_path}) not found") + return -1 + + fap_dst_path = posixpath.join( + self.args.fap_dst_dir, os.path.basename(fap_local_path) + ) + + self.logger.info(f'Installing "{fap_local_path}" to {fap_dst_path}') + + if not self.mkdir_on_storage(storage, self.args.fap_dst_dir): + self.logger.error(f"Error: cannot create dir: {storage.last_error}") + return -2 + + if not self.send_file_to_storage( + storage, fap_dst_path, fap_local_path, False + ): + self.logger.error(f"Error: upload failed: {storage.last_error}") + return -3 + + storage.send_and_wait_eol(f'loader open "Applications" {fap_dst_path}\r') + result = storage.read.until(storage.CLI_EOL) + if len(result): + self.logger.error(f"Unexpected response: {result.decode('ascii')}") + return -4 + + return 0 + finally: + storage.stop() + + +if __name__ == "__main__": + Main()() diff --git a/scripts/toolchain/fbtenv.cmd b/scripts/toolchain/fbtenv.cmd index f955a4db3..1403837d9 100644 --- a/scripts/toolchain/fbtenv.cmd +++ b/scripts/toolchain/fbtenv.cmd @@ -13,7 +13,7 @@ if not [%FBT_NOENV%] == [] ( exit /b 0 ) -set "FLIPPER_TOOLCHAIN_VERSION=9" +set "FLIPPER_TOOLCHAIN_VERSION=15" set "FBT_TOOLCHAIN_ROOT=%FBT_ROOT%\toolchain\i686-windows" diff --git a/scripts/toolchain/fbtenv.sh b/scripts/toolchain/fbtenv.sh index 6f3e8c661..f68e4c0ba 100755 --- a/scripts/toolchain/fbtenv.sh +++ b/scripts/toolchain/fbtenv.sh @@ -5,7 +5,7 @@ # public variables DEFAULT_SCRIPT_PATH="$(pwd -P)"; SCRIPT_PATH="${SCRIPT_PATH:-$DEFAULT_SCRIPT_PATH}"; -FBT_TOOLCHAIN_VERSION="${FBT_TOOLCHAIN_VERSION:-"8"}"; +FBT_TOOLCHAIN_VERSION="${FBT_TOOLCHAIN_VERSION:-"15"}"; FBT_TOOLCHAIN_PATH="${FBT_TOOLCHAIN_PATH:-$SCRIPT_PATH}"; fbtenv_show_usage() @@ -13,6 +13,9 @@ fbtenv_show_usage() echo "Running this script manually is wrong, please source it"; echo "Example:"; printf "\tsource scripts/toolchain/fbtenv.sh\n"; + echo "To restore your enviroment source fbtenv.sh with '--restore'." + echo "Example:"; + printf "\tsource scripts/toolchain/fbtenv.sh --restore\n"; } fbtenv_curl() @@ -25,9 +28,27 @@ fbtenv_wget() wget --show-progress --progress=bar:force -qO "$1" "$2"; } +fbtenv_restore_env() +{ + TOOLCHAIN_ARCH_DIR_SED="$(echo "$TOOLCHAIN_ARCH_DIR" | sed 's/\//\\\//g')" + PATH="$(echo "$PATH" | /usr/bin/sed "s/$TOOLCHAIN_ARCH_DIR_SED\/python\/bin://g")"; + PATH="$(echo "$PATH" | /usr/bin/sed "s/$TOOLCHAIN_ARCH_DIR_SED\/bin://g")"; + PATH="$(echo "$PATH" | /usr/bin/sed "s/$TOOLCHAIN_ARCH_DIR_SED\/protobuf\/bin://g")"; + PATH="$(echo "$PATH" | /usr/bin/sed "s/$TOOLCHAIN_ARCH_DIR_SED\/openocd\/bin://g")"; + if [ -n "${PS1:-""}" ]; then + PS1="$(echo "$PS1" | sed 's/\[fbt\]//g')"; + elif [ -n "${PROMPT:-""}" ]; then + PROMPT="$(echo "$PROMPT" | sed 's/\[fbt\]//g')"; + fi + unset SCRIPT_PATH; + unset FBT_TOOLCHAIN_VERSION; + unset FBT_TOOLCHAIN_PATH; +} + fbtenv_check_sourced() { case "${ZSH_EVAL_CONTEXT:-""}" in *:file:*) + setopt +o nomatch; # disabling 'no match found' warning in zsh return 0;; esac if [ ${0##*/} = "fbtenv.sh" ]; then # exluding script itself @@ -43,13 +64,13 @@ fbtenv_check_sourced() fbtenv_chck_many_source() { - if ! echo "${PS1:-""}" | grep -q "[fbt]"; then - if ! echo "${PROMPT:-""}" | grep -q "[fbt]"; then + if ! echo "${PS1:-""}" | grep -qF "[fbt]"; then + if ! echo "${PROMPT:-""}" | grep -qF "[fbt]"; then return 0; fi fi - echo "Warning! It script seen to be sourced more then once!"; - echo "It may signalise what you are making some mistakes, please open a new shell!"; + echo "Warning! FBT environment script sourced more than once!"; + echo "This may signal that you are making mistakes, please open a new shell!"; return 1; } @@ -138,15 +159,17 @@ fbtenv_download_toolchain_tar() { echo "Downloading toolchain:"; mkdir -p "$FBT_TOOLCHAIN_PATH/toolchain" || return 1; - "$FBT_DOWNLOADER" "$FBT_TOOLCHAIN_PATH/toolchain/$TOOLCHAIN_TAR" "$TOOLCHAIN_URL" || return 1; + "$FBT_DOWNLOADER" "$FBT_TOOLCHAIN_PATH/toolchain/$TOOLCHAIN_TAR.part" "$TOOLCHAIN_URL" || return 1; + # restoring oroginal filename if file downloaded successfully + mv "$FBT_TOOLCHAIN_PATH/toolchain/$TOOLCHAIN_TAR.part" "$FBT_TOOLCHAIN_PATH/toolchain/$TOOLCHAIN_TAR" echo "done"; return 0; } fbtenv_remove_old_tooclhain() { - printf "Removing old toolchain (if exist).."; - rm -rf "${TOOLCHAIN_ARCH_DIR}"; + printf "Removing old toolchain.."; + rm -rf "${TOOLCHAIN_ARCH_DIR:?}"; echo "done"; } @@ -175,8 +198,12 @@ fbtenv_unpack_toolchain() fbtenv_clearing() { printf "Clearing.."; - rm -rf "${FBT_TOOLCHAIN_PATH:?}/toolchain/$TOOLCHAIN_TAR"; + if [ -n "${FBT_TOOLCHAIN_PATH:-""}" ]; then + rm -rf "${FBT_TOOLCHAIN_PATH:?}/toolchain/"*.tar.gz; + rm -rf "${FBT_TOOLCHAIN_PATH:?}/toolchain/"*.part; + fi echo "done"; + trap - 2; return 0; } @@ -222,12 +249,13 @@ fbtenv_download_toolchain() fbtenv_check_tar || return 1; TOOLCHAIN_TAR="$(basename "$TOOLCHAIN_URL")"; TOOLCHAIN_DIR="$(echo "$TOOLCHAIN_TAR" | sed "s/-$FBT_TOOLCHAIN_VERSION.tar.gz//g")"; + trap fbtenv_clearing 2; # trap will be restored in fbtenv_clearing if ! fbtenv_check_downloaded_toolchain; then fbtenv_curl_wget_check || return 1; - fbtenv_download_toolchain_tar; + fbtenv_download_toolchain_tar || return 1; fi fbtenv_remove_old_tooclhain; - fbtenv_unpack_toolchain || { fbtenv_clearing && return 1; }; + fbtenv_unpack_toolchain || return 1; fbtenv_clearing; return 0; } @@ -235,15 +263,19 @@ fbtenv_download_toolchain() fbtenv_main() { fbtenv_check_sourced || return 1; - fbtenv_chck_many_source; # many source it's just a warning - fbtenv_set_shell_prompt; - fbtenv_check_script_path || return 1; fbtenv_get_kernel_type || return 1; + if [ "$1" = "--restore" ]; then + fbtenv_restore_env; + return 0; + fi + fbtenv_chck_many_source; # many source it's just a warning + fbtenv_check_script_path || return 1; fbtenv_check_download_toolchain || return 1; + fbtenv_set_shell_prompt; PATH="$TOOLCHAIN_ARCH_DIR/python/bin:$PATH"; PATH="$TOOLCHAIN_ARCH_DIR/bin:$PATH"; PATH="$TOOLCHAIN_ARCH_DIR/protobuf/bin:$PATH"; PATH="$TOOLCHAIN_ARCH_DIR/openocd/bin:$PATH"; } -fbtenv_main; +fbtenv_main "${1:-""}"; diff --git a/site_scons/cc.scons b/site_scons/cc.scons index e71db2ba2..c923b3872 100644 --- a/site_scons/cc.scons +++ b/site_scons/cc.scons @@ -11,6 +11,7 @@ ENV.AppendUnique( "-fno-use-cxa-atexit", "-fno-exceptions", "-fno-threadsafe-statics", + "-ftemplate-depth=4096", ], CCFLAGS=[ "-mcpu=cortex-m4", diff --git a/site_scons/commandline.scons b/site_scons/commandline.scons index 4c96268b6..2eeda2479 100644 --- a/site_scons/commandline.scons +++ b/site_scons/commandline.scons @@ -68,6 +68,11 @@ vars.AddVariables( "7", ], ), + BoolVariable( + "DEBUG_TOOLS", + help="Enable debug tools to be built", + default=False, + ), ) vars.Add( @@ -186,21 +191,17 @@ vars.Add( help="Map of (configuration_name->application_list)", default={ "default": ( - "crypto_start", # Svc "basic_services", # Apps - "basic_apps", - "updater_app", - "archive", + "main_apps", + "system_apps", # Settings - "passport", - "system_settings", - "about", + "settings_apps", # Plugins - "basic_plugins", + # "basic_plugins", # Debug - "debug_apps", + # "debug_apps", ) }, ) @@ -211,4 +212,26 @@ vars.Add( default="default", ) +vars.Add( + "APPSRC", + help="Application source directory for app to build & upload", + default="", +) + +# List of tuples (directory, add_to_global_include_path) +vars.Add( + "APPDIRS", + help="Directories to search for firmware components & external apps", + default=[ + ("applications", False), + ("applications/services", True), + ("applications/main", True), + ("applications/settings", False), + ("applications/system", False), + ("applications/debug", False), + ("applications/plugins", False), + ("applications_user", False), + ], +) + Return("vars") diff --git a/site_scons/extapps.scons b/site_scons/extapps.scons new file mode 100644 index 000000000..4cb5e35cf --- /dev/null +++ b/site_scons/extapps.scons @@ -0,0 +1,97 @@ +Import("ENV") + + +from fbt.appmanifest import FlipperAppType + +appenv = ENV.Clone( + tools=[("fbt_extapps", {"EXT_APPS_WORK_DIR": ENV.subst("${BUILD_DIR}/.extapps")})] +) + +appenv.Replace( + LINKER_SCRIPT="application-ext", +) + +appenv.AppendUnique( + CCFLAGS=[ + "-ggdb3", + "-mword-relocations", + "-mlong-calls", + "-fno-common", + "-nostdlib", + "-fvisibility=hidden", + ], + LINKFLAGS=[ + "-Ur", + "-Wl,-Ur", + # "-Wl,--orphan-handling=error", + "-Bsymbolic", + "-nostartfiles", + "-mlong-calls", + "-fno-common", + "-nostdlib", + "-Wl,--gc-sections", + "-Wl,--no-export-dynamic", + "-fvisibility=hidden", + "-Wl,-e${APP_ENTRY}", + "-Xlinker", + "-Map=${TARGET}.map", + "-specs=nano.specs", + "-specs=nosys.specs", + ], + LIBS=[ + "m", + "gcc", + "stdc++", + "supc++", + ], +) + + +extapps = appenv["_extapps"] = { + "compact": {}, + "debug": {}, + "validators": {}, + "dist": {}, +} + + +def build_app_as_external(env, appdef): + compact_elf, debug_elf, validator = env.BuildAppElf(appdef) + extapps["compact"][appdef.appid] = compact_elf + extapps["debug"][appdef.appid] = debug_elf + extapps["validators"][appdef.appid] = validator + extapps["dist"][appdef.appid] = (appdef.fap_category, compact_elf) + + +apps_to_build_as_faps = [ + FlipperAppType.PLUGIN, + FlipperAppType.EXTERNAL, +] +if appenv["DEBUG_TOOLS"]: + apps_to_build_as_faps.append(FlipperAppType.DEBUG) + +for apptype in apps_to_build_as_faps: + for app in appenv["APPBUILD"].get_apps_of_type(apptype, True): + build_app_as_external(appenv, app) + +# Ugly access to global option +if extra_app_list := GetOption("extra_ext_apps"): + for extra_app in extra_app_list.split(","): + build_app_as_external(appenv, appenv["APPMGR"].get(extra_app)) + + +if appenv["FORCE"]: + appenv.AlwaysBuild(extapps["compact"].values()) + +Alias(appenv["FIRMWARE_BUILD_CFG"] + "_extapps", extapps["compact"].values()) + +if appsrc := appenv.subst("$APPSRC"): + app_manifest, fap_file = appenv.GetExtAppFromPath(appsrc) + appenv.PhonyTarget( + "launch_app", + '${PYTHON3} scripts/runfap.py ${SOURCE} --fap_dst_dir "/ext/apps/${FAP_CATEGORY}"', + source=fap_file, + FAP_CATEGORY=app_manifest.fap_category, + ) + +Return("extapps") diff --git a/site_scons/fbt/appmanifest.py b/site_scons/fbt/appmanifest.py index aacf248ec..a0ab5e7c6 100644 --- a/site_scons/fbt/appmanifest.py +++ b/site_scons/fbt/appmanifest.py @@ -1,5 +1,5 @@ from dataclasses import dataclass, field -from typing import List, Optional +from typing import List, Optional, Tuple from enum import Enum import os @@ -25,7 +25,7 @@ class FlipperAppType(Enum): class FlipperApplication: appid: str apptype: FlipperAppType - name: Optional[str] = None + name: Optional[str] = "" entry_point: Optional[str] = None flags: List[str] = field(default_factory=lambda: ["Default"]) cdefines: List[str] = field(default_factory=list) @@ -35,7 +35,19 @@ class FlipperApplication: stack_size: int = 2048 icon: Optional[str] = None order: int = 0 - _appdir: Optional[str] = None + sdk_headers: List[str] = field(default_factory=list) + # .fap-specific + sources: List[str] = field(default_factory=lambda: ["*.c*"]) + fap_version: Tuple[int] = field(default_factory=lambda: (0, 0)) + fap_icon: Optional[str] = None + fap_libs: List[str] = field(default_factory=list) + fap_category: str = "" + fap_description: str = "" + fap_author: str = "" + fap_weburl: str = "" + # Internally used by fbt + _appdir: Optional[object] = None + _apppath: Optional[str] = None class AppManager: @@ -50,7 +62,13 @@ class AppManager: f"Missing application manifest for '{appname}'" ) - def load_manifest(self, app_manifest_path: str, app_dir_name: str): + def find_by_appdir(self, appdir: str): + for app in self.known_apps.values(): + if app._appdir.name == appdir: + return app + return None + + def load_manifest(self, app_manifest_path: str, app_dir_node: object): if not os.path.exists(app_manifest_path): raise FlipperManifestException( f"App manifest not found at path {app_manifest_path}" @@ -61,7 +79,14 @@ class AppManager: def App(*args, **kw): nonlocal app_manifests - app_manifests.append(FlipperApplication(*args, **kw, _appdir=app_dir_name)) + app_manifests.append( + FlipperApplication( + *args, + **kw, + _appdir=app_dir_node, + _apppath=os.path.dirname(app_manifest_path), + ), + ) try: with open(app_manifest_path, "rt") as manifest_file: @@ -172,19 +197,32 @@ class AppBuildset: cdefs.update(app.cdefines) return sorted(list(cdefs)) - def get_apps_of_type(self, apptype: FlipperAppType): + def get_sdk_headers(self): + sdk_headers = [] + for app in self.apps: + sdk_headers.extend([app._appdir.File(header) for header in app.sdk_headers]) + return sdk_headers + + def get_apps_of_type(self, apptype: FlipperAppType, all_known: bool = False): return sorted( - filter(lambda app: app.apptype == apptype, self.apps), + filter( + lambda app: app.apptype == apptype, + self.appmgr.known_apps.values() if all_known else self.apps, + ), key=lambda app: app.order, ) + def get_builtin_apps(self): + return list( + filter(lambda app: app.apptype in self.BUILTIN_APP_TYPES, self.apps) + ) + def get_builtin_app_folders(self): return sorted( set( - app._appdir - for app in filter( - lambda app: app.apptype in self.BUILTIN_APP_TYPES, self.apps - ) + (app._appdir, source_type) + for app in self.get_builtin_apps() + for source_type in app.sources ) ) diff --git a/site_scons/fbt/elfmanifest.py b/site_scons/fbt/elfmanifest.py new file mode 100644 index 000000000..313a64c09 --- /dev/null +++ b/site_scons/fbt/elfmanifest.py @@ -0,0 +1,85 @@ +from dataclasses import dataclass +import os + +import struct +from dataclasses import dataclass, field + +from .appmanifest import FlipperApplication + + +_MANIFEST_MAGIC = 0x52474448 + + +@dataclass +class ElfManifestBaseHeader: + manifest_version: int + api_version: int + hardware_target_id: int + + manifest_magic: int = 0x52474448 + + def as_bytes(self): + return struct.pack( + " 32: + raise ValueError( + f"Flipper app icon must be 32 bytes or less, but {len(image.data)} bytes were given" + ) + image_data = image.data + + app_version_as_int = ((app_manifest.fap_version[0] & 0xFFFF) << 16) | ( + app_manifest.fap_version[1] & 0xFFFF + ) + + data = ElfManifestBaseHeader( + manifest_version=1, + api_version=sdk_version, + hardware_target_id=hardware_target, + ).as_bytes() + data += ElfManifestV1( + stack_size=app_manifest.stack_size, + app_version=app_version_as_int, + name=app_manifest.name, + icon=image_data, + ).as_bytes() + + return data diff --git a/site_scons/fbt/sdk.py b/site_scons/fbt/sdk.py new file mode 100644 index 000000000..3d4a17b2f --- /dev/null +++ b/site_scons/fbt/sdk.py @@ -0,0 +1,519 @@ +import operator +import os +import csv +import operator + +from enum import Enum, auto +from typing import List, Set, ClassVar, Any +from dataclasses import dataclass, field + +from cxxheaderparser.parser import CxxParser + + +# 'Fixing' complaints about typedefs +CxxParser._fundamentals.discard("wchar_t") + +from cxxheaderparser.types import ( + EnumDecl, + Field, + ForwardDecl, + FriendDecl, + Function, + Method, + Typedef, + UsingAlias, + UsingDecl, + Variable, + Pointer, + Type, + PQName, + NameSpecifier, + FundamentalSpecifier, + Parameter, + Array, + Value, + Token, + FunctionType, +) + +from cxxheaderparser.parserstate import ( + State, + EmptyBlockState, + ClassBlockState, + ExternBlockState, + NamespaceBlockState, +) + + +@dataclass(frozen=True) +class ApiEntryFunction: + name: str + returns: str + params: str + + csv_type: ClassVar[str] = "Function" + + def dictify(self): + return dict(name=self.name, type=self.returns, params=self.params) + + +@dataclass(frozen=True) +class ApiEntryVariable: + name: str + var_type: str + + csv_type: ClassVar[str] = "Variable" + + def dictify(self): + return dict(name=self.name, type=self.var_type, params=None) + + +@dataclass(frozen=True) +class ApiHeader: + name: str + + csv_type: ClassVar[str] = "Header" + + def dictify(self): + return dict(name=self.name, type=None, params=None) + + +@dataclass +class ApiEntries: + # These are sets, to avoid creating duplicates when we have multiple + # declarations with same signature + functions: Set[ApiEntryFunction] = field(default_factory=set) + variables: Set[ApiEntryVariable] = field(default_factory=set) + headers: Set[ApiHeader] = field(default_factory=set) + + +class SymbolManager: + def __init__(self): + self.api = ApiEntries() + self.name_hashes = set() + + # Calculate hash of name and raise exception if it already is in the set + def _name_check(self, name: str): + name_hash = gnu_sym_hash(name) + if name_hash in self.name_hashes: + raise Exception(f"Hash collision on {name}") + self.name_hashes.add(name_hash) + + def add_function(self, function_def: ApiEntryFunction): + if function_def in self.api.functions: + return + self._name_check(function_def.name) + self.api.functions.add(function_def) + + def add_variable(self, variable_def: ApiEntryVariable): + if variable_def in self.api.variables: + return + self._name_check(variable_def.name) + self.api.variables.add(variable_def) + + def add_header(self, header: str): + self.api.headers.add(ApiHeader(header)) + + +def gnu_sym_hash(name: str): + h = 0x1505 + for c in name: + h = (h << 5) + h + ord(c) + return str(hex(h))[-8:] + + +class SdkCollector: + def __init__(self): + self.symbol_manager = SymbolManager() + + def add_header_to_sdk(self, header: str): + self.symbol_manager.add_header(header) + + def process_source_file_for_sdk(self, file_path: str): + visitor = SdkCxxVisitor(self.symbol_manager) + with open(file_path, "rt") as f: + content = f.read() + parser = CxxParser(file_path, content, visitor, None) + parser.parse() + + def get_api(self): + return self.symbol_manager.api + + +def stringify_array_dimension(size_descr): + if not size_descr: + return "" + return stringify_descr(size_descr) + + +def stringify_array_descr(type_descr): + assert isinstance(type_descr, Array) + return ( + stringify_descr(type_descr.array_of), + stringify_array_dimension(type_descr.size), + ) + + +def stringify_descr(type_descr): + if isinstance(type_descr, (NameSpecifier, FundamentalSpecifier)): + return type_descr.name + elif isinstance(type_descr, PQName): + return "::".join(map(stringify_descr, type_descr.segments)) + elif isinstance(type_descr, Pointer): + # Hack + if isinstance(type_descr.ptr_to, FunctionType): + return stringify_descr(type_descr.ptr_to) + return f"{stringify_descr(type_descr.ptr_to)}*" + elif isinstance(type_descr, Type): + return ( + f"{'const ' if type_descr.const else ''}" + f"{'volatile ' if type_descr.volatile else ''}" + f"{stringify_descr(type_descr.typename)}" + ) + elif isinstance(type_descr, Parameter): + return stringify_descr(type_descr.type) + elif isinstance(type_descr, Array): + # Hack for 2d arrays + if isinstance(type_descr.array_of, Array): + argtype, dimension = stringify_array_descr(type_descr.array_of) + return ( + f"{argtype}[{stringify_array_dimension(type_descr.size)}][{dimension}]" + ) + return f"{stringify_descr(type_descr.array_of)}[{stringify_array_dimension(type_descr.size)}]" + elif isinstance(type_descr, Value): + return " ".join(map(stringify_descr, type_descr.tokens)) + elif isinstance(type_descr, FunctionType): + return f"{stringify_descr(type_descr.return_type)} (*)({', '.join(map(stringify_descr, type_descr.parameters))})" + elif isinstance(type_descr, Token): + return type_descr.value + elif type_descr is None: + return "" + else: + raise Exception("unsupported type_descr: %s" % type_descr) + + +class SdkCxxVisitor: + def __init__(self, symbol_manager: SymbolManager): + self.api = symbol_manager + + def on_variable(self, state: State, v: Variable) -> None: + if not v.extern: + return + + self.api.add_variable( + ApiEntryVariable( + stringify_descr(v.name), + stringify_descr(v.type), + ) + ) + + def on_function(self, state: State, fn: Function) -> None: + if fn.inline or fn.has_body: + return + + self.api.add_function( + ApiEntryFunction( + stringify_descr(fn.name), + stringify_descr(fn.return_type), + ", ".join(map(stringify_descr, fn.parameters)) + + (", ..." if fn.vararg else ""), + ) + ) + + def on_define(self, state: State, content: str) -> None: + pass + + def on_pragma(self, state: State, content: str) -> None: + pass + + def on_include(self, state: State, filename: str) -> None: + pass + + def on_empty_block_start(self, state: EmptyBlockState) -> None: + pass + + def on_empty_block_end(self, state: EmptyBlockState) -> None: + pass + + def on_extern_block_start(self, state: ExternBlockState) -> None: + pass + + def on_extern_block_end(self, state: ExternBlockState) -> None: + pass + + def on_namespace_start(self, state: NamespaceBlockState) -> None: + pass + + def on_namespace_end(self, state: NamespaceBlockState) -> None: + pass + + def on_forward_decl(self, state: State, fdecl: ForwardDecl) -> None: + pass + + def on_typedef(self, state: State, typedef: Typedef) -> None: + pass + + def on_using_namespace(self, state: State, namespace: List[str]) -> None: + pass + + def on_using_alias(self, state: State, using: UsingAlias) -> None: + pass + + def on_using_declaration(self, state: State, using: UsingDecl) -> None: + pass + + def on_enum(self, state: State, enum: EnumDecl) -> None: + pass + + def on_class_start(self, state: ClassBlockState) -> None: + pass + + def on_class_field(self, state: State, f: Field) -> None: + pass + + def on_class_method(self, state: ClassBlockState, method: Method) -> None: + pass + + def on_class_friend(self, state: ClassBlockState, friend: FriendDecl) -> None: + pass + + def on_class_end(self, state: ClassBlockState) -> None: + pass + + +@dataclass(frozen=True) +class SdkVersion: + major: int = 0 + minor: int = 0 + + csv_type: ClassVar[str] = "Version" + + def __str__(self) -> str: + return f"{self.major}.{self.minor}" + + def as_int(self) -> int: + return ((self.major & 0xFFFF) << 16) | (self.minor & 0xFFFF) + + @staticmethod + def from_str(s: str) -> "SdkVersion": + major, minor = s.split(".") + return SdkVersion(int(major), int(minor)) + + def dictify(self) -> dict: + return dict(name=str(self), type=None, params=None) + + +class VersionBump(Enum): + NONE = auto() + MAJOR = auto() + MINOR = auto() + + +class ApiEntryState(Enum): + PENDING = "?" + APPROVED = "+" + DISABLED = "-" + # Special value for API version entry so users have less incentive to edit it + VERSION_PENDING = "v" + + +# Class that stores all known API entries, both enabled and disabled. +# Also keeps track of API versioning +# Allows comparison and update from newly-generated API +class SdkCache: + CSV_FIELD_NAMES = ("entry", "status", "name", "type", "params") + + def __init__(self, cache_file: str, load_version_only=False): + self.cache_file_name = cache_file + self.version = SdkVersion(0, 0) + self.sdk = ApiEntries() + self.disabled_entries = set() + self.new_entries = set() + self.loaded_dirty_version = False + + self.version_action = VersionBump.NONE + self._load_version_only = load_version_only + self.load_cache() + + def is_buildable(self) -> bool: + return ( + self.version != SdkVersion(0, 0) + and self.version_action == VersionBump.NONE + and not self._have_pending_entries() + ) + + def _filter_enabled(self, sdk_entries): + return sorted( + filter(lambda e: e not in self.disabled_entries, sdk_entries), + key=operator.attrgetter("name"), + ) + + def get_valid_names(self): + syms = set(map(lambda e: e.name, self.get_functions())) + syms.update(map(lambda e: e.name, self.get_variables())) + return syms + + def get_functions(self): + return self._filter_enabled(self.sdk.functions) + + def get_variables(self): + return self._filter_enabled(self.sdk.variables) + + def get_headers(self): + return self._filter_enabled(self.sdk.headers) + + def _get_entry_status(self, entry) -> str: + if entry in self.disabled_entries: + return ApiEntryState.DISABLED + elif entry in self.new_entries: + if isinstance(entry, SdkVersion): + return ApiEntryState.VERSION_PENDING + return ApiEntryState.PENDING + else: + return ApiEntryState.APPROVED + + def _format_entry(self, obj): + obj_dict = obj.dictify() + obj_dict.update( + dict( + entry=obj.csv_type, + status=self._get_entry_status(obj).value, + ) + ) + return obj_dict + + def save(self) -> None: + if self._load_version_only: + raise Exception("Only SDK version was loaded, cannot save") + + if self.version_action == VersionBump.MINOR: + self.version = SdkVersion(self.version.major, self.version.minor + 1) + elif self.version_action == VersionBump.MAJOR: + self.version = SdkVersion(self.version.major + 1, 0) + + if self._have_pending_entries(): + self.new_entries.add(self.version) + print( + f"API version is still WIP: {self.version}. Review the changes and re-run command." + ) + print(f"Entries to review:") + print( + "\n".join( + map( + str, + filter( + lambda e: not isinstance(e, SdkVersion), self.new_entries + ), + ) + ) + ) + else: + print(f"API version {self.version} is up to date") + + regenerate_csv = ( + self.loaded_dirty_version + or self._have_pending_entries() + or self.version_action != VersionBump.NONE + ) + + if regenerate_csv: + str_cache_entries = [self.version] + name_getter = operator.attrgetter("name") + str_cache_entries.extend(sorted(self.sdk.headers, key=name_getter)) + str_cache_entries.extend(sorted(self.sdk.functions, key=name_getter)) + str_cache_entries.extend(sorted(self.sdk.variables, key=name_getter)) + + with open(self.cache_file_name, "wt", newline="") as f: + writer = csv.DictWriter(f, fieldnames=SdkCache.CSV_FIELD_NAMES) + writer.writeheader() + + for entry in str_cache_entries: + writer.writerow(self._format_entry(entry)) + + def _process_entry(self, entry_dict: dict) -> None: + entry_class = entry_dict["entry"] + entry_status = entry_dict["status"] + entry_name = entry_dict["name"] + + entry = None + if entry_class == SdkVersion.csv_type: + self.version = SdkVersion.from_str(entry_name) + if entry_status == ApiEntryState.VERSION_PENDING.value: + self.loaded_dirty_version = True + elif entry_class == ApiHeader.csv_type: + self.sdk.headers.add(entry := ApiHeader(entry_name)) + elif entry_class == ApiEntryFunction.csv_type: + self.sdk.functions.add( + entry := ApiEntryFunction( + entry_name, + entry_dict["type"], + entry_dict["params"], + ) + ) + elif entry_class == ApiEntryVariable.csv_type: + self.sdk.variables.add( + entry := ApiEntryVariable(entry_name, entry_dict["type"]) + ) + else: + print(entry_dict) + raise Exception("Unknown entry type: %s" % entry_class) + + if entry is None: + return + + if entry_status == ApiEntryState.DISABLED.value: + self.disabled_entries.add(entry) + elif entry_status == ApiEntryState.PENDING.value: + self.new_entries.add(entry) + + def load_cache(self) -> None: + if not os.path.exists(self.cache_file_name): + raise Exception( + f"Cannot load symbol cache '{self.cache_file_name}'! File does not exist" + ) + + with open(self.cache_file_name, "rt") as f: + reader = csv.DictReader(f) + for row in reader: + self._process_entry(row) + if self._load_version_only and row.get("entry") == SdkVersion.csv_type: + break + + def _have_pending_entries(self) -> bool: + return any( + filter( + lambda e: not isinstance(e, SdkVersion), + self.new_entries, + ) + ) + + def sync_sets( + self, known_set: Set[Any], new_set: Set[Any], update_version: bool = True + ): + new_entries = new_set - known_set + if new_entries: + print(f"New: {new_entries}") + known_set |= new_entries + self.new_entries |= new_entries + if update_version and self.version_action == VersionBump.NONE: + self.version_action = VersionBump.MINOR + removed_entries = known_set - new_set + if removed_entries: + print(f"Removed: {removed_entries}") + known_set -= removed_entries + # If any of removed entries was a part of active API, that's a major bump + if update_version and any( + filter( + lambda e: e not in self.disabled_entries + and e not in self.new_entries, + removed_entries, + ) + ): + self.version_action = VersionBump.MAJOR + self.disabled_entries -= removed_entries + self.new_entries -= removed_entries + + def validate_api(self, api: ApiEntries) -> None: + self.sync_sets(self.sdk.headers, api.headers, False) + self.sync_sets(self.sdk.functions, api.functions) + self.sync_sets(self.sdk.variables, api.variables) diff --git a/site_scons/fbt/version.py b/site_scons/fbt/version.py index 4745c7002..1b1c166f2 100644 --- a/site_scons/fbt/version.py +++ b/site_scons/fbt/version.py @@ -1,7 +1,9 @@ import subprocess import datetime +from functools import cache +@cache def get_fast_git_version_id(): try: version = ( diff --git a/site_scons/site_init.py b/site_scons/site_init.py index 817269e28..2d83d8816 100644 --- a/site_scons/site_init.py +++ b/site_scons/site_init.py @@ -5,6 +5,7 @@ import os import atexit sys.path.insert(0, os.path.join(os.getcwd(), "scripts")) +sys.path.insert(0, os.path.join(os.getcwd(), "lib/cxxheaderparser")) def bf_to_str(bf): diff --git a/site_scons/site_tools/blackmagic.py b/site_scons/site_tools/blackmagic.py index ec48c15fd..0b1142683 100644 --- a/site_scons/site_tools/blackmagic.py +++ b/site_scons/site_tools/blackmagic.py @@ -63,7 +63,7 @@ class BlackmagicResolver: if probe := self.get_serial() or self.get_networked(): return probe - raise Exception("Please specify BLACKMAGIC=...") + raise StopError("Please specify BLACKMAGIC=...") def generate(env): diff --git a/site_scons/site_tools/fbt_apps.py b/site_scons/site_tools/fbt_apps.py index 3dc35049b..ef5e9b9d9 100644 --- a/site_scons/site_tools/fbt_apps.py +++ b/site_scons/site_tools/fbt_apps.py @@ -18,18 +18,26 @@ from fbt.appmanifest import ( def LoadApplicationManifests(env): appmgr = env["APPMGR"] = AppManager() - for entry in env.Glob("#/applications/*", ondisk=True, source=True): - if isinstance(entry, SCons.Node.FS.Dir) and not str(entry).startswith("."): - try: - app_manifest_file_path = os.path.join(entry.abspath, "application.fam") - appmgr.load_manifest(app_manifest_file_path, entry.name) - env.Append(PY_LINT_SOURCES=[app_manifest_file_path]) - except FlipperManifestException as e: - warn(WarningOnByDefault, str(e)) + for app_dir, _ in env["APPDIRS"]: + app_dir_node = env.Dir("#").Dir(app_dir) + + for entry in app_dir_node.glob("*", ondisk=True, source=True): + if isinstance(entry, SCons.Node.FS.Dir) and not str(entry).startswith("."): + try: + app_manifest_file_path = os.path.join( + entry.abspath, "application.fam" + ) + appmgr.load_manifest(app_manifest_file_path, entry) + env.Append(PY_LINT_SOURCES=[app_manifest_file_path]) + except FlipperManifestException as e: + warn(WarningOnByDefault, str(e)) def PrepareApplicationsBuild(env): - env["APPBUILD"] = env["APPMGR"].filter_apps(env["APPS"]) + appbuild = env["APPBUILD"] = env["APPMGR"].filter_apps(env["APPS"]) + env.Append( + SDK_HEADERS=appbuild.get_sdk_headers(), + ) env["APPBUILD_DUMP"] = env.Action( DumpApplicationConfig, "\tINFO\t", diff --git a/site_scons/site_tools/fbt_assets.py b/site_scons/site_tools/fbt_assets.py index c844db36b..877948471 100644 --- a/site_scons/site_tools/fbt_assets.py +++ b/site_scons/site_tools/fbt_assets.py @@ -13,11 +13,11 @@ def icons_emitter(target, source, env): "compiled/assets_icons.c", "compiled/assets_icons.h", ] + source = env.GlobRecursive("*.*", env["ICON_SRC_DIR"]) return target, source def proto_emitter(target, source, env): - out_path = target[0].path target = [] for src in source: basename = os.path.splitext(src.name)[0] @@ -109,7 +109,7 @@ def generate(env): BUILDERS={ "IconBuilder": Builder( action=Action( - '${PYTHON3} "${ASSETS_COMPILER}" icons ${SOURCE.posix} ${TARGET.dir.posix}', + '${PYTHON3} "${ASSETS_COMPILER}" icons ${ICON_SRC_DIR} ${TARGET.dir}', "${ICONSCOMSTR}", ), emitter=icons_emitter, diff --git a/site_scons/site_tools/fbt_dist.py b/site_scons/site_tools/fbt_dist.py index 399b7ecdd..2b5c83dff 100644 --- a/site_scons/site_tools/fbt_dist.py +++ b/site_scons/site_tools/fbt_dist.py @@ -4,7 +4,7 @@ from SCons.Script import Mkdir from SCons.Defaults import Touch -def get_variant_dirname(env, project=None): +def GetProjetDirName(env, project=None): parts = [f"f{env['TARGET_HW']}"] if project: parts.append(project) @@ -21,7 +21,7 @@ def get_variant_dirname(env, project=None): def create_fw_build_targets(env, configuration_name): - flavor = get_variant_dirname(env, configuration_name) + flavor = GetProjetDirName(env, configuration_name) build_dir = env.Dir("build").Dir(flavor).abspath return env.SConscript( "firmware.scons", @@ -49,7 +49,7 @@ def AddFwProject(env, base_env, fw_type, fw_env_key): ], ) - env.Replace(DIST_DIR=get_variant_dirname(env)) + env.Replace(DIST_DIR=env.GetProjetDirName()) return project_env @@ -115,6 +115,7 @@ def generate(env): env.AddMethod(AddFwProject) env.AddMethod(DistCommand) env.AddMethod(AddOpenOCDFlashTarget) + env.AddMethod(GetProjetDirName) env.AddMethod(AddJFlashTarget) env.AddMethod(AddUsbFlashTarget) diff --git a/site_scons/site_tools/fbt_extapps.py b/site_scons/site_tools/fbt_extapps.py index 17c4bf6c5..4b5845305 100644 --- a/site_scons/site_tools/fbt_extapps.py +++ b/site_scons/site_tools/fbt_extapps.py @@ -1,29 +1,151 @@ +from SCons.Builder import Builder +from SCons.Action import Action +from SCons.Errors import UserError +import SCons.Warnings + import os +import pathlib +from fbt.elfmanifest import assemble_manifest_data +from fbt.sdk import SdkCache +import itertools def BuildAppElf(env, app): work_dir = env.subst("$EXT_APPS_WORK_DIR") - app_target_name = os.path.join(work_dir, app.appid) + app_alias = f"{env['FIRMWARE_BUILD_CFG']}_{app.appid}" - app_elf = env.Program( - app_target_name, - env.GlobRecursive("*.c*", os.path.join(work_dir, app._appdir)), - APP_ENTRY=app.entry_point, + app_original_elf = os.path.join(work_dir, f"{app.appid}_d") + app_sources = list( + itertools.chain.from_iterable( + env.GlobRecursive(source_type, os.path.join(work_dir, app._appdir.relpath)) + for source_type in app.sources + ) ) - app_elf_dump = env.ObjDump(app_target_name) + app_elf_raw = env.Program( + app_original_elf, + app_sources, + APP_ENTRY=app.entry_point, + LIBS=env["LIBS"] + app.fap_libs, + ) + + app_elf_dump = env.ObjDump(app_elf_raw) env.Alias(f"{app_alias}_list", app_elf_dump) - app_stripped_elf = env.ELFStripper( - os.path.join(env.subst("$PLUGIN_ELF_DIR"), app.appid), app_elf + app_elf_augmented = env.EmbedAppMetadata( + os.path.join(env.subst("$PLUGIN_ELF_DIR"), app.appid), + app_elf_raw, + APP=app, ) - env.Alias(app_alias, app_stripped_elf) - return app_stripped_elf + + env.Depends(app_elf_augmented, [env["SDK_DEFINITION"], env.Value(app)]) + if app.fap_icon: + env.Depends( + app_elf_augmented, + env.File(f"{app._apppath}/{app.fap_icon}"), + ) + env.Alias(app_alias, app_elf_augmented) + + app_elf_import_validator = env.ValidateAppImports(app_elf_augmented) + env.AlwaysBuild(app_elf_import_validator) + return (app_elf_augmented, app_elf_raw, app_elf_import_validator) + + +def prepare_app_metadata(target, source, env): + sdk_cache = SdkCache(env.subst("$SDK_DEFINITION"), load_version_only=True) + + if not sdk_cache.is_buildable(): + raise UserError( + "SDK version is not finalized, please review changes and re-run operation" + ) + + app = env["APP"] + meta_file_name = source[0].path + ".meta" + with open(meta_file_name, "wb") as f: + # f.write(f"hello this is {app}") + f.write( + assemble_manifest_data( + app_manifest=app, + hardware_target=int(env.subst("$TARGET_HW")), + sdk_version=sdk_cache.version.as_int(), + ) + ) + + +def validate_app_imports(target, source, env): + sdk_cache = SdkCache(env.subst("$SDK_DEFINITION"), load_version_only=False) + app_syms = set() + with open(target[0].path, "rt") as f: + for line in f: + app_syms.add(line.split()[0]) + unresolved_syms = app_syms - sdk_cache.get_valid_names() + if unresolved_syms: + SCons.Warnings.warn( + SCons.Warnings.LinkWarning, + f"{source[0].path}: app won't run. Unresolved symbols: {unresolved_syms}", + ) + + +def GetExtAppFromPath(env, app_dir): + if not app_dir: + raise UserError("APPSRC= not set") + + appmgr = env["APPMGR"] + + app = None + for dir_part in reversed(pathlib.Path(app_dir).parts): + if app := appmgr.find_by_appdir(dir_part): + break + if not app: + raise UserError(f"Failed to resolve application for given APPSRC={app_dir}") + + app_elf = env["_extapps"]["compact"].get(app.appid, None) + if not app_elf: + raise UserError(f"No external app found for {app.appid}") + + return (app, app_elf[0]) def generate(env, **kw): - env.SetDefault(EXT_APPS_WORK_DIR=kw.get("EXT_APPS_WORK_DIR", ".extapps")) - env.VariantDir(env.subst("$EXT_APPS_WORK_DIR"), ".", duplicate=False) + env.SetDefault(EXT_APPS_WORK_DIR=kw.get("EXT_APPS_WORK_DIR")) + env.VariantDir(env.subst("$EXT_APPS_WORK_DIR"), env.Dir("#"), duplicate=False) + env.AddMethod(BuildAppElf) + env.AddMethod(GetExtAppFromPath) + env.Append( + BUILDERS={ + "EmbedAppMetadata": Builder( + action=[ + Action(prepare_app_metadata, "$APPMETA_COMSTR"), + Action( + "${OBJCOPY} " + "--remove-section .ARM.attributes " + "--add-section .fapmeta=${SOURCE}.meta " + "--set-section-flags .fapmeta=contents,noload,readonly,data " + "--strip-debug --strip-unneeded " + "--add-gnu-debuglink=${SOURCE} " + "${SOURCES} ${TARGET}", + "$APPMETAEMBED_COMSTR", + ), + ], + suffix=".fap", + src_suffix=".elf", + ), + "ValidateAppImports": Builder( + action=[ + Action( + "@${NM} -P -u ${SOURCE} > ${TARGET}", + None, # "$APPDUMP_COMSTR", + ), + Action( + validate_app_imports, + None, # "$APPCHECK_COMSTR", + ), + ], + suffix=".impsyms", + src_suffix=".fap", + ), + } + ) def exists(env): diff --git a/site_scons/site_tools/fbt_sdk.py b/site_scons/site_tools/fbt_sdk.py new file mode 100644 index 000000000..f6c2d452e --- /dev/null +++ b/site_scons/site_tools/fbt_sdk.py @@ -0,0 +1,209 @@ +from SCons.Builder import Builder +from SCons.Action import Action +from SCons.Errors import UserError + +# from SCons.Scanner import C +from SCons.Script import Mkdir, Copy, Delete, Entry +from SCons.Util import LogicalLines + +import os.path +import posixpath +import pathlib + +from fbt.sdk import SdkCollector, SdkCache + + +def prebuild_sdk_emitter(target, source, env): + target.append(env.ChangeFileExtension(target[0], ".d")) + target.append(env.ChangeFileExtension(target[0], ".i.c")) + return target, source + + +def prebuild_sdk_create_origin_file(target, source, env): + mega_file = env.subst("${TARGET}.c", target=target[0]) + with open(mega_file, "wt") as sdk_c: + sdk_c.write("\n".join(f"#include <{h.path}>" for h in env["SDK_HEADERS"])) + + +class SdkTreeBuilder: + def __init__(self, env, target, source) -> None: + self.env = env + self.target = target + self.source = source + + self.header_depends = [] + self.header_dirs = [] + + self.target_sdk_dir = env.subst("f${TARGET_HW}_sdk") + self.sdk_deploy_dir = target[0].Dir(self.target_sdk_dir) + + def _parse_sdk_depends(self): + deps_file = self.source[0] + with open(deps_file.path, "rt") as deps_f: + lines = LogicalLines(deps_f).readlines() + _, depends = lines[0].split(":", 1) + self.header_depends = list( + filter(lambda fname: fname.endswith(".h"), depends.split()), + ) + self.header_dirs = sorted( + set(map(os.path.normpath, map(os.path.dirname, self.header_depends))) + ) + + def _generate_sdk_meta(self): + filtered_paths = [self.target_sdk_dir] + full_fw_paths = list( + map( + os.path.normpath, + (self.env.Dir(inc_dir).relpath for inc_dir in self.env["CPPPATH"]), + ) + ) + + sdk_dirs = ", ".join(f"'{dir}'" for dir in self.header_dirs) + for dir in full_fw_paths: + if dir in sdk_dirs: + filtered_paths.append( + posixpath.normpath(posixpath.join(self.target_sdk_dir, dir)) + ) + + sdk_env = self.env.Clone() + sdk_env.Replace(CPPPATH=filtered_paths) + with open(self.target[0].path, "wt") as f: + cmdline_options = sdk_env.subst( + "$CCFLAGS $_CCCOMCOM", target=Entry("dummy") + ) + f.write(cmdline_options.replace("\\", "/")) + f.write("\n") + + def _create_deploy_commands(self): + dirs_to_create = set( + self.sdk_deploy_dir.Dir(dirpath) for dirpath in self.header_dirs + ) + actions = [ + Delete(self.sdk_deploy_dir), + Mkdir(self.sdk_deploy_dir), + ] + actions += [Mkdir(d) for d in dirs_to_create] + + actions += [ + Copy( + self.sdk_deploy_dir.File(h).path, + h, + ) + for h in self.header_depends + ] + return actions + + def generate_actions(self): + self._parse_sdk_depends() + self._generate_sdk_meta() + + return self._create_deploy_commands() + + +def deploy_sdk_tree(target, source, env, for_signature): + if for_signature: + return [] + + sdk_tree = SdkTreeBuilder(env, target, source) + return sdk_tree.generate_actions() + + +def gen_sdk_data(sdk_cache: SdkCache): + api_def = [] + api_def.extend( + (f"#include <{h.name}>" for h in sdk_cache.get_headers()), + ) + + api_def.append(f"const int elf_api_version = {sdk_cache.version.as_int()};") + + api_def.append( + "static constexpr auto elf_api_table = sort(create_array_t(" + ) + + api_lines = [] + for fun_def in sdk_cache.get_functions(): + api_lines.append( + f"API_METHOD({fun_def.name}, {fun_def.returns}, ({fun_def.params}))" + ) + + for var_def in sdk_cache.get_variables(): + api_lines.append(f"API_VARIABLE({var_def.name}, {var_def.var_type })") + + api_def.append(",\n".join(api_lines)) + + api_def.append("));") + return api_def + + +def _check_sdk_is_up2date(sdk_cache: SdkCache): + if not sdk_cache.is_buildable(): + raise UserError( + "SDK version is not finalized, please review changes and re-run operation" + ) + + +def validate_sdk_cache(source, target, env): + # print(f"Generating SDK for {source[0]} to {target[0]}") + current_sdk = SdkCollector() + current_sdk.process_source_file_for_sdk(source[0].path) + for h in env["SDK_HEADERS"]: + current_sdk.add_header_to_sdk(pathlib.Path(h.path).as_posix()) + + sdk_cache = SdkCache(target[0].path) + sdk_cache.validate_api(current_sdk.get_api()) + sdk_cache.save() + _check_sdk_is_up2date(sdk_cache) + + +def generate_sdk_symbols(source, target, env): + sdk_cache = SdkCache(source[0].path) + _check_sdk_is_up2date(sdk_cache) + + api_def = gen_sdk_data(sdk_cache) + with open(target[0].path, "wt") as f: + f.write("\n".join(api_def)) + + +def generate(env, **kw): + env.Append( + BUILDERS={ + "SDKPrebuilder": Builder( + emitter=prebuild_sdk_emitter, + action=[ + Action( + prebuild_sdk_create_origin_file, + "$SDK_PREGEN_COMSTR", + ), + Action( + "$CC -o $TARGET -E -P $CCFLAGS $_CCCOMCOM $SDK_PP_FLAGS -MMD ${TARGET}.c", + "$SDK_COMSTR", + ), + ], + suffix=".i", + ), + "SDKTree": Builder( + generator=deploy_sdk_tree, + src_suffix=".d", + ), + "SDKSymUpdater": Builder( + action=Action( + validate_sdk_cache, + "$SDKSYM_UPDATER_COMSTR", + ), + suffix=".csv", + src_suffix=".i", + ), + "SDKSymGenerator": Builder( + action=Action( + generate_sdk_symbols, + "$SDKSYM_GENERATOR_COMSTR", + ), + suffix=".h", + src_suffix=".csv", + ), + } + ) + + +def exists(env): + return True diff --git a/site_scons/site_tools/fwbin.py b/site_scons/site_tools/fwbin.py index 37e64e56d..678b04998 100644 --- a/site_scons/site_tools/fwbin.py +++ b/site_scons/site_tools/fwbin.py @@ -3,12 +3,14 @@ from SCons.Action import Action import SCons __OBJCOPY_ARM_BIN = "arm-none-eabi-objcopy" +__NM_ARM_BIN = "arm-none-eabi-nm" def generate(env): env.SetDefault( BIN2DFU="${ROOT_DIR.abspath}/scripts/bin2dfu.py", OBJCOPY=__OBJCOPY_ARM_BIN, # FIXME + NM=__NM_ARM_BIN, # FIXME ) env.Append( BUILDERS={ diff --git a/site_scons/site_tools/sconsmodular.py b/site_scons/site_tools/sconsmodular.py index 778c664e4..b115706cb 100644 --- a/site_scons/site_tools/sconsmodular.py +++ b/site_scons/site_tools/sconsmodular.py @@ -40,10 +40,15 @@ def PhonyTarget(env, name, action, source=None, **kw): return command +def ChangeFileExtension(env, fnode, ext): + return env.File(f"#{os.path.splitext(fnode.path)[0]}{ext}") + + def generate(env): env.AddMethod(BuildModule) env.AddMethod(BuildModules) env.AddMethod(PhonyTarget) + env.AddMethod(ChangeFileExtension) def exists(env):