diff --git a/.github/actions/make-release/action.yml b/.github/actions/make-release/action.yml new file mode 100644 index 00000000000..61a51952b98 --- /dev/null +++ b/.github/actions/make-release/action.yml @@ -0,0 +1,81 @@ +--- +name: "Action release" +description: "Steps to build release" +author: "DerSkythe" + +inputs: + release_type: + description: 'release_type' + required: true + release_version: + description: 'release_version' + required: true + firmware_version: + description: 'firmware_version' + required: true + repo_self: + description: 'REPO_SELF' + required: true + gh_token: + description: 'github_gh_token' + required: true + owner: + description: 'owner' + required: true + current_tag: + description: 'current_tag' + required: true + remote_tag_info: + description: 'remote_tag_info' + required: true + +# outputs: +# make-minor-release: +# description: "make-minor-release" +# value: ${{ steps.make-minor-release.outputs }} +# make-major-release: +# description: "make-minor-release" +# value: ${{ steps.make-major-release.outputs }} + +runs: + using: "composite" + steps: + - name: Minor release + if: ${{ inputs.release_type == 2 }} + id: make-minor-release + uses: softprops/action-gh-release@v1 + with: + tag_name: 'v${{ inputs.release_version }}' + name: 'Minor update v${{ inputs.release_version }}' + token: ${{ inputs.gh_token }} + draft: true + generate_release_notes: true + #target_commitish: ${{ github.SHA }} + append_body: true + body: 'Rebuild with new version of firmware.\n\nSee: [CHANGELOG](${{ inputs.firmware_version }}/blob/dev/CHANGELOG.md)\n${{ inputs.remote_tag_info }}' + repository: '${{ inputs.repo_self }}' + + - name: Major release + if: ${{ inputs.release_type == 1 }} + id: make-major-release + uses: softprops/action-gh-release@v1 + with: + tag_name: 'v${{ inputs.release_version }}' + name: Release v${{ inputs.release_version }} + token: ${{ inputs.gh_token }} + draft: true + generate_release_notes: true + #target_commitish: ${{ github.SHA }} + append_body: true + body: 'New version is rolling out!' + repository: '${{ inputs.repo_self }}' + + - name: Update Firmware variable and create UPDATE release if necessary + if: ${{ success() }} + env: + GITHUB_TOKEN: ${{ inputs.gh_token }} + OWNER: ${{ inputs.owner }} + shell: bash + run: | + gh variable set FIRMWARE_VERSION -b '${{ inputs.firmware_version }}' -R '${{ inputs.repo_self }}' + gh variable set RELEASE_VERSION -b '${{ inputs.release_version }}' -R '${{ inputs.repo_self }}' diff --git a/.github/check-version.ps1 b/.github/check-version.ps1 new file mode 100644 index 00000000000..c2cbefdb558 --- /dev/null +++ b/.github/check-version.ps1 @@ -0,0 +1,141 @@ +######################################## +Set-StrictMode -Version 3.0 # +$ErrorActionPreference = "Stop" # +######################################## + +[string]$FirmwareVersion = $args[0] +[string]$ReleaseVersion = $args[1] +[string]$RepoSelf = $args[2] +[string]$RepoUnleashed = $args[3] +[bool]$ForGithubActions = $true + +################################################################################################################################ +function CleanInput +{ + param( + [string] + $DurtyString + ) + return $DurtyString -replace ('[^a-zA-Z\d_\-\,\.\t\n\r\:\;]', '') +} + +################################################################################################################################ + +$Output = @{ + RELEASE_VERSION = $ReleaseVersion + CURRENT_TAG = $FirmwareVersion + REMOTE_TAG_INFO = $FirmwareVersion + RELEASE_TYPE = 0 +} + +$Release = @(` + (CleanInput ` + (gh release list -L 1 --repo $RepoUnleashed)` + ) -split "`t") + +$FirmwareVersionNumber = 0 +$StoredFirmwareVersionNumber = 0 +$LatestFirmware = $Release[2] +if ($Release[2] -match '\-(\d+)$') +{ + $FirmwareVersionNumber = [int]($Matches[1]) +} +else +{ + Write-Error ('::error title=Invalid firmware number::Error during execution this tags {0}' -f $FirmwareVersionNumber) + exit 1 +} +if ($FirmwareVersion -match '\-(\d+)$') +{ + $StoredFirmwareVersionNumber = [int]($Matches[1]) +} +else +{ + Write-Error ('::error title=Invalid STORED firmware number::Error during execution this version {0}' -f $FirmwareVersion) + exit 1 +} +$Delta = ( [DateTime]::Now - [DateTime]::Parse($Release[3])) +Write-Host "FirmwareVersionNumber: $FirmwareVersionNumber, Delta: $Delta" +#exit 0 + +$NewVersionFw = $false +Write-Host ('Latest firmware {0}' -f $FirmwareVersionNumber) + +$Output.REMOTE_TAG_INFO = Write-Host ('[{0}]({1}/releases/tag/{2})' ` + -f $LatestFirmware, $RepoUnleashed, $LatestFirmware) +if (($FirmwareVersionNumber -gt $StoredFirmwareVersionNumber) -and ( $Delta -gt [TimeSpan]::FromMinutes(10))) +{ + $Output.REMOTE_TAG_INFO = $LatestFirmware + $NewVersionFw = $true +} +elseif ($FirmwareVersionNumber -lt $StoredFirmwareVersionNumber) +{ + Write-Error ('::error title=Invalid check of stored::Version in repo: {0}, but we think it is {1}' ` + -f $FirmwareVersionNumber, $StoredFirmwareVersionNumber) + exit 1 +} + +$PublishDates = (gh api -H "Accept: application/vnd.github+json" ` + -H "X-GitHub-Api-Version: 2022-11-28" "/repos/$( $RepoSelf )/releases?per_page=1" ` + | ConvertFrom-Json | Select-Object published_at, created_at) +$LastPublished = ($null -eq $PublishDates.published_at ? $PublishDates.created_at : $PublishDates.published_at) +$Delta = ([DateTime]::Now - $LastPublished) + +$Release = (gh api -H "Accept: application/vnd.github+json" ` + -H "X-GitHub-Api-Version: 2022-11-28" "/repos/$( $RepoSelf )/tags?per_page=1" ` + | ConvertFrom-Json).name +Write-Host ('Release {0}' -f $Release) -ForegroundColor Gray -BackgroundColor Blue +$LatestTag = $Release.Substring(1) + +$CurrentVersion = [version]::Parse($ReleaseVersion) +$ParsedRepoVersion = [version]::Parse($LatestTag) + +Write-Host ('Current tag:Repos tag {0}, {1}' -f $CurrentVersion, $ParsedRepoVersion) ` + -ForegroundColor Gray -BackgroundColor Blue +Write-Debug ('::debug Current tag:Repos tag {0}, {1}' -f $CurrentVersion, $ParsedRepoVersion) + +if (($CurrentVersion -lt $ParsedRepoVersion) -and ( $Delta -gt [TimeSpan]::FromMinutes(10))) +{ + $Tag = ('{0}.{1}.{2}' -f $ParsedRepoVersion.Major, $ParsedRepoVersion.Minor, $ParsedRepoVersion.Build) + + $Output.RELEASE_VERSION = $Tag + $Output.RELEASE_TYPE = 2 + + Write-Host ('::warning title=New release!::Release {0}' -f $Tag) +} +elseif ( $NewVersionFw ) +{ + $Tag = ('{0}.{1}.{2}' -f $CurrentVersion.Major, $CurrentVersion.Minor, ($CurrentVersion.Build + 1)) + + $Output.RELEASE_VERSION = $Tag + $Output.RELEASE_TYPE = 1 + + Write-Host ('::warning title=Firmware was changed!::New version is {0}, need to create release {1}' -f $LatestFirmware, $Tag) +} +elseif ( ($Delta -gt [TimeSpan]::FromMinutes(10)) -and ($CurrentVersion -gt $ParsedRepoVersion)) +{ + Write-Host ('::warning title=Invalid version!::Version in settings: {0}, but repo version is {1}. Going to change variable' ` + -f $CurrentVersion, $ParsedRepoVersion) + + $Output.RELEASE_VERSION = $ParsedRepoVersion + $Output.RELEASE_TYPE = 3 +} +else +{ + # none to release + Write-Host 'No new versions, sorry' +} + +$Output.CURRENT_TAG = $LatestTag + +if($ForGithubActions) { + $Plain = New-Object -TypeName "System.Text.StringBuilder"; + $Output.GetEnumerator() | ForEach-Object { + [void]$Plain.Append($_.Key) + [void]$Plain.Append('=') + [void]$Plain.AppendLine($_.Value) + } + Write-Output $Plain.ToString() +} else { + $Output +} diff --git a/.github/workflows/build-with-firmwware.yml b/.github/workflows/build-with-firmwware.yml index 1f4fb987f10..145352dee9c 100644 --- a/.github/workflows/build-with-firmwware.yml +++ b/.github/workflows/build-with-firmwware.yml @@ -9,7 +9,7 @@ on: required: false type: string release: - types: [unpublished] + types: [created] push: paths: - .github/workflows/build-with-firmware.yml @@ -30,6 +30,7 @@ jobs: IGNORED_PATH: "applications_user/subbrute" RELATIVE_PATH: "applications/external/subbrute" CURRENT_VERSION: ${{ vars.RELEASE_VERSION }} + RELEASE_VERSION: ${{ vars.RELEASE_VERSION }} strategy: fail-fast: false matrix: @@ -156,8 +157,8 @@ jobs: if: ${{ success() }} shell: pwsh env: - ZIP_NAME: "SubGHz_Bruteforcer_${{ env.RELEASE_VERSION }}_${{ matrix.firmware }}.zip" - TGZ_NAME: "SubGHz_Bruteforcer_${{ env.RELEASE_VERSION }}_${{ matrix.firmware }}.tgz" + ZIP_NAME: "subghz_bruteforcer_${{ env.RELEASE_VERSION }}_${{ matrix.firmware }}.zip" + TGZ_NAME: "subghz_bruteforcer_${{ env.RELEASE_VERSION }}_${{ matrix.firmware }}.tgz" run: | function Format-Bytes { param( diff --git a/.github/workflows/version-check.yml b/.github/workflows/version-check.yml index ced41782b2a..061745a6ee7 100644 --- a/.github/workflows/version-check.yml +++ b/.github/workflows/version-check.yml @@ -1,169 +1,67 @@ -name: "Version check for NEW release" -run-name: " Version check for NEW release ${{ inputs.DEPLOY_TARGET }} by @${{ github.ACTOR }}" - -on: - workflow_dispatch: - push: - branches: - - master - schedule: - - cron: "*/30 * * * *" - -permissions: - contents: write - -jobs: - pull-request: - concurrency: - group: check-for-new-versions - cancel-in-progress: false - runs-on: ubuntu-latest - env: - REPO_UNLEASHED: ${{ vars.REPO_UNLEASHED }} - RELEASE_VERSION: ${{ vars.RELEASE_VERSION }} - FIRMWARE_VERSION: ${{ vars.FIRMWARE_VERSION }} - REPO_SELF: ${{ vars.REPO_SELF }} - CHECKOUT_DIR: "firmware" - steps: - - name: Copy Repo Files - uses: actions/checkout@v3 - with: - repository: "${{ env.REPO_SELF }}" - path: "${{ env.CHECKOUT_DIR }}" - clean: "true" - submodules: "true" - token: ${{ secrets.FLIPPER_TOKEN }} - - name: Check firmware release - shell: pwsh - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - function CleanInput - { - param( - [string] - $DurtyString - ) - return $DurtyString -replace ('[^a-zA-Z\d_\-\,\.\t\n\r\:\;]', '') - } - - $Release = @(` - (CleanInput ` - (gh release list -L 1 --repo '${{ env.REPO_UNLEASHED }}')` - ) -split "`t") - - $FirmwareVersionNumber = 0 - $StoredFirmwareVersionNumber = 0 - if ($Release[2] -match '\-(\d+)$') - { - $FirmwareVersionNumber = [int]($Matches[1]) - } - else - { - Write-Error ('::error title=Invalid firmware number::Error during execution this tags {0}' -f $FirmwareVersionNumber) - exit 1 - } - if ('${{ env.FIRMWARE_VERSION }}' -match '\-(\d+)$') - { - $StoredFirmwareVersionNumber = [int]($Matches[1]) - } - else - { - Write-Error ('::error title=Invalid STORED firmware number::Error during execution this version {0}' -f '${{ env.FIRMWARE_VERSION }}') - exit 1 - } - - $LatestFirmware = CleanInput ((CleanInput (gh release list -L 1 --repo '${{ env.REPO_SELF }}') -replace '\t', ';') | ` - ConvertFrom-Csv -Delimiter ';' -Header name, flag, tag).tag - - $Delta = ( [DateTime]::Now - [DateTime]::Parse($Release[3]) ) - $NewVersionFw = $false - Write-Host ('Latest firmware {0}' -f $LatestFirmware) -ForegroundColor Gray -BackgroundColor Magenta - Write-Debug ('::debug LatestFirmware {0}' -f $LatestFirmware) - - Write-Output ('REMOTE_TAG_INFO=[{0}]({1}/releases/tag/{2})' -f $LatestFirmware, '${{ env.REPO_UNLEASHED }}', $LatestFirmware) >> $env:GITHUB_ENV - if (($FirmwareVersionNumber -gt $StoredFirmwareVersionNumber) -and ( $Delta -gt [TimeSpan]::FromMinutes(10))) - { - Write-Debug ('::debug LatestFirmware {0}' -f $LatestFirmware) - Write-Output ('FIRMWARE_VERSION={0}' -f $LatestFirmware) >> $env:GITHUB_ENV - $NewVersionFw = $true - } - elseif ($FirmwareVersionNumber -lt $StoredFirmwareVersionNumber) - { - Write-Error ('::error title=Invalid check of stored::Version in repo: {0}, but we think it is {1}' -f $FirmwareVersionNumber, $StoredFirmwareVersionNumber) - exit 1 - } - - $LastPublished = (gh api -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28" '/repos/${{ vars.REPO_SELF }}/releases?per_page=1' | ConvertFrom-Json).published_at - $Delta = ([DateTime]::Now - $LastPublished) - - $Release = (gh api -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28" '/repos/${{ vars.REPO_SELF }}/tags?per_page=1' | ConvertFrom-Json).name - Write-Host ('Release {0}' -f $Release) -ForegroundColor Gray -BackgroundColor Magenta - $LatestTag = $Release.Substring(1) - - $CurrentVersion = [version]::Parse('${{ env.RELEASE_VERSION }}') - $ParsedRepoVersion = [version]::Parse($LatestTag) - Write-Host ('Current tag:Repos tag {0}, {1}' -f $CurrentVersion, $ParsedRepoVersion) -ForegroundColor Gray -BackgroundColor Magenta - Write-Debug ('::debug Current tag:Repos tag {0}, {1}' -f $CurrentVersion, $ParsedRepoVersion) - if (($CurrentVersion -lt $ParsedRepoVersion) -and ( $Delta -gt [TimeSpan]::FromMinutes(10))) - { - $Tag = ('{0}.{1}.{2}' -f $ParsedRepoVersion.Major, $ParsedRepoVersion.Minor, $ParsedRepoVersion.Build) - - Write-Output ('RELEASE_VERSION={0}' -f $Tag) >> $env:GITHUB_ENV - Write-Output ('RELEASE_TYPE=2' -f $Tag) >> $env:GITHUB_ENV - - Write-Output ('::warning title=New release!::Release {0}' -f $Tag) - } - elseif ( $NewVersionFw ) - { - $Tag = ('{0}.{1}.{2}' -f $CurrentVersion.Major, $CurrentVersion.Minor, ($CurrentVersion.Build + 1)) - - Write-Output ('RELEASE_VERSION={0}' -f $Tag) >> $env:GITHUB_ENV - Write-Output ('RELEASE_TYPE=1' -f $Tag) >> $env:GITHUB_ENV - - Write-Output ('::warning title=Firmware was changed!::New version is {0}, creating release {1}' -f $LatestFirmware, $Tag) - } - elseif ( ($Delta -gt [TimeSpan]::FromMinutes(10)) -and ($CurrentVersion -gt $ParsedRepoVersion)) - { - Write-Output ('::warning title=Invalid version!::Version in settings: {0}, but repo version is {1}. Going to change variable' -f $CurrentVersion, $ParsedRepoVersion) - Write-Output ('RELEASE_VERSION={0}' -f $ParsedRepoVersion) >> $env:GITHUB_ENV - Write-Output ('RELEASE_TYPE=3' -f $Tag) >> $env:GITHUB_ENV - } - else - { - # none to release - Write-Host 'No new versions, sorry' - } - Write-Output ('CURRENT_TAG={0}' -f $LatestTag) >> $env:GITHUB_ENV - - - name: Update Firmware variable and create UPDATE release if necessary - if: ${{ success() && env.RELEASE_TYPE == 1 }} - env: - GITHUB_TOKEN: ${{ secrets.FLIPPER_TOKEN }} - OWNER: ${{ github.repository_owner }} - run: | - gh release create 'v${{ env.RELEASE_VERSION }}' --latest --draft \ - --notes 'Rebuild with new version of firmware.\n\nSee: [CHANGELOG](${{ env.FIRMWARE_VERSION }}/blob/dev/CHANGELOG.md)\n${{ env.REMOTE_TAG_INFO}}' \ - --title 'Minor update v${{ env.RELEASE_VERSION }}' --verify-tag -R '${{ env.REPO_SELF }}' - gh variable set FIRMWARE_VERSION -b '${{ env.FIRMWARE_VERSION }}' -R '${{ env.REPO_SELF }}' - gh variable set RELEASE_VERSION -b '${{ env.RELEASE_VERSION }}' -R '${{ env.REPO_SELF }}' - - name: Update release variable and create NEW release if necessary - if: ${{ success() && env.RELEASE_TYPE == 2 }} - env: - GITHUB_TOKEN: ${{ secrets.FLIPPER_TOKEN }} - OWNER: ${{ github.repository_owner }} - run: | - gh release create 'v${{ env.RELEASE_VERSION }}' --notes-start-tag 'v${{ env.CURRENT_TAG }}' --generate-notes --draft --latest \ - --notes 'New version is rolling out!' --verify-tag --title 'Release v${{ env.RELEASE_VERSION }}' -R '${{ env.REPO_SELF }}' - - gh variable set FIRMWARE_VERSION -b '${{ env.FIRMWARE_VERSION }}' -R '${{ env.REPO_SELF }}' - gh variable set RELEASE_VERSION -b '${{ env.RELEASE_VERSION }}' -R '${{ env.REPO_SELF }}' - - name: Current settings in repo invalid. Changing - if: ${{ success() && env.RELEASE_TYPE > 2 }} - env: - GITHUB_TOKEN: ${{ secrets.FLIPPER_TOKEN }} - OWNER: ${{ github.repository_owner }} - run: | - gh variable set RELEASE_VERSION -b ${{ env.RELEASE_VERSION }} -R ${{ env.REPO_SELF }} - -# EOF +name: "Version check for NEW release" +run-name: " Version check for NEW release ${{ inputs.DEPLOY_TARGET }} by @${{ github.ACTOR }}" + +on: + workflow_dispatch: + push: + branches: + - master + schedule: + - cron: "*/30 * * * *" + +permissions: + contents: write + +jobs: + pull-request: + concurrency: + group: check-for-new-versions + cancel-in-progress: false + runs-on: ubuntu-latest + env: + REPO_UNLEASHED: ${{ vars.REPO_UNLEASHED }} + CURRENT_TAG: ${{ vars.FIRMWARE_VERSION }} + REMOTE_TAG_INFO: '' + RELEASE_VERSION: ${{ vars.RELEASE_VERSION }} + FIRMWARE_VERSION: ${{ vars.FIRMWARE_VERSION }} + REPO_SELF: ${{ vars.REPO_SELF }} + CHECKOUT_DIR: "firmware" + RELEASE_TYPE: 0 + steps: + - name: Copy Repo Files + uses: actions/checkout@v3 + with: + repository: "${{ env.REPO_SELF }}" + clean: "true" + submodules: "true" + token: ${{ secrets.FLIPPER_TOKEN }} + - name: Check firmware release + shell: pwsh + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + ./.github/check-version.ps1 '${{ env.FIRMWARE_VERSION }}' '${{ env.RELEASE_VERSION }}' '${{ env.REPO_SELF }}' '${{ env.REPO_UNLEASHED }}' | %{ Write-Output($_) >> $Env:GITHUB_ENV } + - name: Print env values + run: env + - name: Create release if necessary + if: ${{ success() && (env.RELEASE_TYPE == 2 || env.RELEASE_TYPE == 1 )}} + uses: ./.github/actions/make-release + with: + gh_token: ${{ secrets.FLIPPER_TOKEN }} + release_type: ${{ env.RELEASE_TYPE }} + release_version: ${{ env.RELEASE_VERSION }} + firmware_version: ${{ env.REMOTE_TAG_INFO }} + repo_self: ${{ env.REPO_SELF }} + owner: ${{ github.repository_owner }} + current_tag: ${{ env.CURRENT_TAG }} + remote_tag_info: ${{ env.REMOTE_TAG_INFO }} + + - name: Current settings in repo invalid. Changing + if: ${{ success() && env.RELEASE_TYPE > 2 }} + env: + GITHUB_TOKEN: ${{ secrets.FLIPPER_TOKEN }} + OWNER: ${{ github.repository_owner }} + run: | + gh variable set RELEASE_VERSION -b ${{ env.RELEASE_VERSION }} -R ${{ env.REPO_SELF }} + +# EOF diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000000..3f0c19d9780 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/.idea/.idea.subbrute.dir/.idea/workspace.xml + +.DS_Store diff --git a/.idea/.idea.subbrute.dir/.idea/.gitignore b/.idea/.idea.subbrute.dir/.idea/.gitignore new file mode 100644 index 00000000000..879083b3452 --- /dev/null +++ b/.idea/.idea.subbrute.dir/.idea/.gitignore @@ -0,0 +1,13 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Rider ignored files +/modules.xml +/contentModel.xml +/.idea.subbrute.iml +/projectSettingsUpdater.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/.idea.subbrute.dir/.idea/encodings.xml b/.idea/.idea.subbrute.dir/.idea/encodings.xml new file mode 100644 index 00000000000..df87cf951fb --- /dev/null +++ b/.idea/.idea.subbrute.dir/.idea/encodings.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/.idea.subbrute.dir/.idea/git_toolbox_prj.xml b/.idea/.idea.subbrute.dir/.idea/git_toolbox_prj.xml new file mode 100644 index 00000000000..38839fe3ed3 --- /dev/null +++ b/.idea/.idea.subbrute.dir/.idea/git_toolbox_prj.xml @@ -0,0 +1,15 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/.idea.subbrute.dir/.idea/indexLayout.xml b/.idea/.idea.subbrute.dir/.idea/indexLayout.xml new file mode 100644 index 00000000000..f5a863a7cd3 --- /dev/null +++ b/.idea/.idea.subbrute.dir/.idea/indexLayout.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/.idea.subbrute.dir/.idea/misc.xml b/.idea/.idea.subbrute.dir/.idea/misc.xml new file mode 100644 index 00000000000..409aba973ae --- /dev/null +++ b/.idea/.idea.subbrute.dir/.idea/misc.xml @@ -0,0 +1,13 @@ + + + + + + \ No newline at end of file diff --git a/.idea/.idea.subbrute.dir/.idea/projectSettingsUpdater.xml b/.idea/.idea.subbrute.dir/.idea/projectSettingsUpdater.xml new file mode 100644 index 00000000000..bd1d7c7922b --- /dev/null +++ b/.idea/.idea.subbrute.dir/.idea/projectSettingsUpdater.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/.idea.subbrute.dir/.idea/vcs.xml b/.idea/.idea.subbrute.dir/.idea/vcs.xml new file mode 100644 index 00000000000..c8397c94c0e --- /dev/null +++ b/.idea/.idea.subbrute.dir/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000000..efac4f90313 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,11 @@ +{ + "githubPullRequests.ignoredPullRequestBranches": [ + "master" + ], + "workbench.colorCustomizations": { + "list.errorForeground": "#00AA00", + "list.warningForeground": "#00d9ff", + "gitDecoration.modifiedResourceForeground": "#00ffb3", + "gitDecoration.untrackedResourceForeground": "#f7aeae" + } +} diff --git a/LICENSE b/LICENSE index 06dcf7e8734..26bfc7e1cec 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,21 @@ -MIT License - -Copyright (c) 2022 Der Skythe - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +MIT License + +Copyright (c) 2022 Der Skythe + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index bd262f49b03..01bfde10808 100644 --- a/README.md +++ b/README.md @@ -1,76 +1,76 @@ -# SubGHz Bruteforcer Plugin for Flipper Zero - -SubGhz Bruteforcer from [Unleashed Firmware](https://github.com/DarkFlippers/unleashed-firmware) - -### Disclaimer - -This software is for experimental purposes only and is not meant for any illegal activity/purposes. -We do not condone illegal activity and strongly encourage keeping transmissions to legal/valid uses allowed by law. - -### Supported Protocols: - -#### CAME - -- CAME 12bit 303MHz -- CAME 12bit 307MHz -- CAME 12bit 315MHz -- CAME 12bit 433MHz -- CAME 12bit 868MHz - -#### NICE - -- NICE 12bit 433MHz -- NICE 12bit 868MHz - -#### Ansonic - -- Ansonic 12bit 433.075MHz -- Ansonic 12bit 433.920MHz -- Ansonic 12bit 434.075MHz - -#### Holtek - -- Holtek HT12X 12bit FM 433.920MHz (TE: 204us) -- Holtek HT12X 12bit AM 433.920MHz (TE: 433us) -- Holtek HT12X 12bit AM 315MHz (TE: 433us) -- Holtek HT12X 12bit AM 868MHz (TE: 433us) -- Holtek HT12X 12bit AM 915MHz (TE: 433us) -#### Chamberlain - -- Chamberlain 9bit 300MHz -- Chamberlain 9bit 315MHz -- Chamberlain 9bit 390MHz -- Chamberlain 9bit 433MHz -- Chamberlain 8bit 300MHz -- Chamberlain 8bit 315MHz -- Chamberlain 8bit 390MHz -- Chamberlain 7bit 300MHz -- Chamberlain 7bit 315MHz -- Chamberlain 7bit 390MHz - -#### Linear - -- Linear 10bit 300MHz -- Linear 10bit 310MHz -- Linear Delta 3 8bit 310MHz - -#### UNILARM - -- UNILARM 25bit 330MHz (TE: 209us) (only dip switch combinations, not full 25bit bruteforce) -- UNILARM 25bit 433MHz (TE: 209us) (only dip switch combinations, not full 25bit bruteforce) - -#### SMC5326 - -- SMC5326 25bit 330MHz (TE: 320us) (only dip switch combinations, not full 25bit bruteforce) -- SMC5326 25bit 433MHz (TE: 320us) (only dip switch combinations, not full 25bit bruteforce) - -#### PT2260 - -- PT2260 24bit 315MHz (TE: 286us) (only for 8 dip switch remote, not full 24bit bruteforce) -- PT2260 24bit 330MHz (TE: 286us) (only for 8 dip switch remote, not full 24bit bruteforce) -- PT2260 24bit 390MHz (TE: 286us) (only for 8 dip switch remote, not full 24bit bruteforce) -- PT2260 24bit 433MHz (TE: 286us) (only for 8 dip switch remote, not full 24bit bruteforce) - -#### Additional - -- BF Existing dump works for most other static protocols supported by Flipper Zero +# SubGHz Bruteforcer Plugin for Flipper Zero + +SubGhz Bruteforcer from [Unleashed Firmware](https://github.com/DarkFlippers/unleashed-firmware) + +### Disclaimer + +This software is for experimental purposes only and is not meant for any illegal activity/purposes. +We do not condone illegal activity and strongly encourage keeping transmissions to legal/valid uses allowed by law. + +### Supported Protocols: + +#### CAME + +- CAME 12bit 303MHz +- CAME 12bit 307MHz +- CAME 12bit 315MHz +- CAME 12bit 433MHz +- CAME 12bit 868MHz + +#### NICE + +- NICE 12bit 433MHz +- NICE 12bit 868MHz + +#### Ansonic + +- Ansonic 12bit 433.075MHz +- Ansonic 12bit 433.920MHz +- Ansonic 12bit 434.075MHz + +#### Holtek + +- Holtek HT12X 12bit FM 433.920MHz (TE: 204us) +- Holtek HT12X 12bit AM 433.920MHz (TE: 433us) +- Holtek HT12X 12bit AM 315MHz (TE: 433us) +- Holtek HT12X 12bit AM 868MHz (TE: 433us) +- Holtek HT12X 12bit AM 915MHz (TE: 433us) +#### Chamberlain + +- Chamberlain 9bit 300MHz +- Chamberlain 9bit 315MHz +- Chamberlain 9bit 390MHz +- Chamberlain 9bit 433MHz +- Chamberlain 8bit 300MHz +- Chamberlain 8bit 315MHz +- Chamberlain 8bit 390MHz +- Chamberlain 7bit 300MHz +- Chamberlain 7bit 315MHz +- Chamberlain 7bit 390MHz + +#### Linear + +- Linear 10bit 300MHz +- Linear 10bit 310MHz +- Linear Delta 3 8bit 310MHz + +#### UNILARM + +- UNILARM 25bit 330MHz (TE: 209us) (only dip switch combinations, not full 25bit bruteforce) +- UNILARM 25bit 433MHz (TE: 209us) (only dip switch combinations, not full 25bit bruteforce) + +#### SMC5326 + +- SMC5326 25bit 330MHz (TE: 320us) (only dip switch combinations, not full 25bit bruteforce) +- SMC5326 25bit 433MHz (TE: 320us) (only dip switch combinations, not full 25bit bruteforce) + +#### PT2260 + +- PT2260 24bit 315MHz (TE: 286us) (only for 8 dip switch remote, not full 24bit bruteforce) +- PT2260 24bit 330MHz (TE: 286us) (only for 8 dip switch remote, not full 24bit bruteforce) +- PT2260 24bit 390MHz (TE: 286us) (only for 8 dip switch remote, not full 24bit bruteforce) +- PT2260 24bit 433MHz (TE: 286us) (only for 8 dip switch remote, not full 24bit bruteforce) + +#### Additional + +- BF Existing dump works for most other static protocols supported by Flipper Zero diff --git a/application.fam b/application.fam index a1ab9672320..783a6ff658d 100644 --- a/application.fam +++ b/application.fam @@ -1,12 +1,12 @@ -App( - appid="SubGHz_Bruteforcer", - name="Sub-GHz Bruteforcer", - apptype=FlipperAppType.EXTERNAL, - entry_point="subbrute_app", - requires=["gui","dialogs"], - stack_size=2 * 1024, - order=11, - fap_icon="images/subbrute_10px.png", - fap_category="Sub-GHz", - fap_icon_assets="images", -) +App( + appid="subghz_bruteforcer", + name="Sub-GHz Bruteforcer", + apptype=FlipperAppType.EXTERNAL, + entry_point="subbrute_app", + requires=["gui","dialogs"], + stack_size=2 * 1024, + order=11, + fap_icon="images/subbrute_10px.png", + fap_category="Sub-GHz", + fap_icon_assets="images", +) diff --git a/helpers/gui_top_buttons.c b/helpers/gui_top_buttons.c index 0415c5ae7b6..4e77c87c3a6 100644 --- a/helpers/gui_top_buttons.c +++ b/helpers/gui_top_buttons.c @@ -1,59 +1,59 @@ -#include "gui_top_buttons.h" - -void elements_button_top_left(Canvas* canvas, const char* str) { - const Icon* icon = &I_ButtonUp_7x4; - - const uint8_t button_height = 12; - const uint8_t vertical_offset = 3; - const uint8_t horizontal_offset = 3; - const uint8_t string_width = canvas_string_width(canvas, str); - const uint8_t icon_h_offset = 3; - const uint8_t icon_width_with_offset = icon_get_width(icon) + icon_h_offset; - const uint8_t icon_v_offset = icon_get_height(icon) + vertical_offset; - const uint8_t button_width = string_width + horizontal_offset * 2 + icon_width_with_offset; - - const uint8_t x = 0; - const uint8_t y = 0 + button_height; - - uint8_t line_x = x + button_width; - uint8_t line_y = y - button_height; - canvas_draw_box(canvas, x, line_y, button_width, button_height); - canvas_draw_line(canvas, line_x + 0, line_y, line_x + 0, y - 1); - canvas_draw_line(canvas, line_x + 1, line_y, line_x + 1, y - 2); - canvas_draw_line(canvas, line_x + 2, line_y, line_x + 2, y - 3); - - canvas_invert_color(canvas); - canvas_draw_icon(canvas, x + horizontal_offset, y - icon_v_offset, icon); - canvas_draw_str( - canvas, x + horizontal_offset + icon_width_with_offset, y - vertical_offset, str); - canvas_invert_color(canvas); -} - -void elements_button_top_right(Canvas* canvas, const char* str) { - const Icon* icon = &I_ButtonDown_7x4; - - const uint8_t button_height = 12; - const uint8_t vertical_offset = 3; - const uint8_t horizontal_offset = 3; - const uint8_t string_width = canvas_string_width(canvas, str); - const uint8_t icon_h_offset = 3; - const uint8_t icon_width_with_offset = icon_get_width(icon) + icon_h_offset; - const uint8_t icon_v_offset = icon_get_height(icon) + vertical_offset + 1; - const uint8_t button_width = string_width + horizontal_offset * 2 + icon_width_with_offset; - - const uint8_t x = canvas_width(canvas); - const uint8_t y = 0 + button_height; - - uint8_t line_x = x - button_width; - uint8_t line_y = y - button_height; - canvas_draw_box(canvas, line_x, line_y, button_width, button_height); - canvas_draw_line(canvas, line_x - 1, line_y, line_x - 1, y - 1); - canvas_draw_line(canvas, line_x - 2, line_y, line_x - 2, y - 2); - canvas_draw_line(canvas, line_x - 3, line_y, line_x - 3, y - 3); - - canvas_invert_color(canvas); - canvas_draw_str(canvas, x - button_width + horizontal_offset, y - vertical_offset, str); - canvas_draw_icon( - canvas, x - horizontal_offset - icon_get_width(icon), y - icon_v_offset, icon); - canvas_invert_color(canvas); +#include "gui_top_buttons.h" + +void elements_button_top_left(Canvas* canvas, const char* str) { + const Icon* icon = &I_ButtonUp_7x4; + + const uint8_t button_height = 12; + const uint8_t vertical_offset = 3; + const uint8_t horizontal_offset = 3; + const uint8_t string_width = canvas_string_width(canvas, str); + const uint8_t icon_h_offset = 3; + const uint8_t icon_width_with_offset = icon_get_width(icon) + icon_h_offset; + const uint8_t icon_v_offset = icon_get_height(icon) + vertical_offset; + const uint8_t button_width = string_width + horizontal_offset * 2 + icon_width_with_offset; + + const uint8_t x = 0; + const uint8_t y = 0 + button_height; + + uint8_t line_x = x + button_width; + uint8_t line_y = y - button_height; + canvas_draw_box(canvas, x, line_y, button_width, button_height); + canvas_draw_line(canvas, line_x + 0, line_y, line_x + 0, y - 1); + canvas_draw_line(canvas, line_x + 1, line_y, line_x + 1, y - 2); + canvas_draw_line(canvas, line_x + 2, line_y, line_x + 2, y - 3); + + canvas_invert_color(canvas); + canvas_draw_icon(canvas, x + horizontal_offset, y - icon_v_offset, icon); + canvas_draw_str( + canvas, x + horizontal_offset + icon_width_with_offset, y - vertical_offset, str); + canvas_invert_color(canvas); +} + +void elements_button_top_right(Canvas* canvas, const char* str) { + const Icon* icon = &I_ButtonDown_7x4; + + const uint8_t button_height = 12; + const uint8_t vertical_offset = 3; + const uint8_t horizontal_offset = 3; + const uint8_t string_width = canvas_string_width(canvas, str); + const uint8_t icon_h_offset = 3; + const uint8_t icon_width_with_offset = icon_get_width(icon) + icon_h_offset; + const uint8_t icon_v_offset = icon_get_height(icon) + vertical_offset + 1; + const uint8_t button_width = string_width + horizontal_offset * 2 + icon_width_with_offset; + + const uint8_t x = canvas_width(canvas); + const uint8_t y = 0 + button_height; + + uint8_t line_x = x - button_width; + uint8_t line_y = y - button_height; + canvas_draw_box(canvas, line_x, line_y, button_width, button_height); + canvas_draw_line(canvas, line_x - 1, line_y, line_x - 1, y - 1); + canvas_draw_line(canvas, line_x - 2, line_y, line_x - 2, y - 2); + canvas_draw_line(canvas, line_x - 3, line_y, line_x - 3, y - 3); + + canvas_invert_color(canvas); + canvas_draw_str(canvas, x - button_width + horizontal_offset, y - vertical_offset, str); + canvas_draw_icon( + canvas, x - horizontal_offset - icon_get_width(icon), y - icon_v_offset, icon); + canvas_invert_color(canvas); } \ No newline at end of file diff --git a/helpers/gui_top_buttons.h b/helpers/gui_top_buttons.h index b5ca507b7eb..c0d8041bf3f 100644 --- a/helpers/gui_top_buttons.h +++ b/helpers/gui_top_buttons.h @@ -1,21 +1,21 @@ -#pragma once - -#include -#include -#include -#include -#include - -/** - * Thanks to the author of metronome - * @param canvas - * @param str - */ -void elements_button_top_left(Canvas* canvas, const char* str); - -/** - * Thanks to the author of metronome - * @param canvas - * @param str - */ +#pragma once + +#include +#include +#include +#include +#include + +/** + * Thanks to the author of metronome + * @param canvas + * @param str + */ +void elements_button_top_left(Canvas* canvas, const char* str); + +/** + * Thanks to the author of metronome + * @param canvas + * @param str + */ void elements_button_top_right(Canvas* canvas, const char* str); \ No newline at end of file diff --git a/helpers/subbrute_worker.c b/helpers/subbrute_worker.c index 118e63c6595..27ce966a49d 100644 --- a/helpers/subbrute_worker.c +++ b/helpers/subbrute_worker.c @@ -1,437 +1,459 @@ -#include "subbrute_worker_private.h" -#include -#include -#include -#include -#include - -#define TAG "SubBruteWorker" -#define SUBBRUTE_TX_TIMEOUT 5 -#define SUBBRUTE_MANUAL_TRANSMIT_INTERVAL 400 - -SubBruteWorker* subbrute_worker_alloc() { - SubBruteWorker* instance = malloc(sizeof(SubBruteWorker)); - - instance->state = SubBruteWorkerStateIDLE; - instance->step = 0; - instance->worker_running = false; - instance->initiated = false; - instance->last_time_tx_data = 0; - instance->load_index = 0; - - instance->thread = furi_thread_alloc(); - furi_thread_set_name(instance->thread, "SubBruteAttackWorker"); - furi_thread_set_stack_size(instance->thread, 2048); - furi_thread_set_context(instance->thread, instance); - furi_thread_set_callback(instance->thread, subbrute_worker_thread); - - instance->context = NULL; - instance->callback = NULL; - - instance->decoder_result = NULL; - instance->transmitter = NULL; - instance->environment = subghz_environment_alloc(); - subghz_environment_set_protocol_registry( - instance->environment, (void*)&subghz_protocol_registry); - - instance->transmit_mode = false; - - return instance; -} - -void subbrute_worker_free(SubBruteWorker* instance) { - furi_assert(instance); - - // I don't know how to free this - instance->decoder_result = NULL; - - if(instance->transmitter != NULL) { - subghz_transmitter_free(instance->transmitter); - instance->transmitter = NULL; - } - - subghz_environment_free(instance->environment); - instance->environment = NULL; - - furi_thread_free(instance->thread); - - free(instance); -} - -uint64_t subbrute_worker_get_step(SubBruteWorker* instance) { - return instance->step; -} - -bool subbrute_worker_set_step(SubBruteWorker* instance, uint64_t step) { - furi_assert(instance); - if(!subbrute_worker_can_manual_transmit(instance)) { - FURI_LOG_W(TAG, "Cannot set step during running mode"); - return false; - } - - instance->step = step; - - return true; -} - -bool subbrute_worker_init_default_attack( - SubBruteWorker* instance, - SubBruteAttacks attack_type, - uint64_t step, - const SubBruteProtocol* protocol, - uint8_t extra_repeats) { - furi_assert(instance); - - if(instance->worker_running) { - FURI_LOG_W(TAG, "Init Worker when it's running"); - subbrute_worker_stop(instance); - } - - instance->attack = attack_type; - instance->frequency = protocol->frequency; - instance->preset = protocol->preset; - instance->file = protocol->file; - instance->step = step; - instance->bits = protocol->bits; - instance->te = protocol->te; - instance->repeat = protocol->repeat + extra_repeats; - instance->load_index = 0; - instance->file_key = 0; - instance->two_bytes = false; - - instance->max_value = - subbrute_protocol_calc_max_value(instance->attack, instance->bits, instance->two_bytes); - - instance->initiated = true; - instance->state = SubBruteWorkerStateReady; - subbrute_worker_send_callback(instance); -#ifdef FURI_DEBUG - FURI_LOG_I( - TAG, - "subbrute_worker_init_default_attack: %s, bits: %d, preset: %s, file: %s, te: %ld, repeat: %d, max_value: %lld", - subbrute_protocol_name(instance->attack), - instance->bits, - subbrute_protocol_preset(instance->preset), - subbrute_protocol_file(instance->file), - instance->te, - instance->repeat, - instance->max_value); -#endif - - return true; -} - -bool subbrute_worker_init_file_attack( - SubBruteWorker* instance, - uint64_t step, - uint8_t load_index, - uint64_t file_key, - SubBruteProtocol* protocol, - uint8_t extra_repeats, - bool two_bytes) { - furi_assert(instance); - - if(instance->worker_running) { - FURI_LOG_W(TAG, "Init Worker when it's running"); - subbrute_worker_stop(instance); - } - - instance->attack = SubBruteAttackLoadFile; - instance->frequency = protocol->frequency; - instance->preset = protocol->preset; - instance->file = protocol->file; - instance->step = step; - instance->bits = protocol->bits; - instance->te = protocol->te; - instance->load_index = load_index; - instance->repeat = protocol->repeat + extra_repeats; - instance->file_key = file_key; - instance->two_bytes = two_bytes; - - instance->max_value = - subbrute_protocol_calc_max_value(instance->attack, instance->bits, instance->two_bytes); - - instance->initiated = true; - instance->state = SubBruteWorkerStateReady; - subbrute_worker_send_callback(instance); -#ifdef FURI_DEBUG - FURI_LOG_I( - TAG, - "subbrute_worker_init_file_attack: %s, bits: %d, preset: %s, file: %s, te: %ld, repeat: %d, max_value: %lld, key: %llX", - subbrute_protocol_name(instance->attack), - instance->bits, - subbrute_protocol_preset(instance->preset), - subbrute_protocol_file(instance->file), - instance->te, - instance->repeat, - instance->max_value, - instance->file_key); -#endif - - return true; -} - -bool subbrute_worker_start(SubBruteWorker* instance) { - furi_assert(instance); - - if(!instance->initiated) { - FURI_LOG_W(TAG, "Worker not init!"); - return false; - } - - if(instance->worker_running) { - FURI_LOG_W(TAG, "Worker is already running!"); - return false; - } - if(instance->state != SubBruteWorkerStateReady && - instance->state != SubBruteWorkerStateFinished) { - FURI_LOG_W(TAG, "Worker cannot start, invalid device state: %d", instance->state); - return false; - } - - instance->worker_running = true; - furi_thread_start(instance->thread); - - return true; -} - -void subbrute_worker_stop(SubBruteWorker* instance) { - furi_assert(instance); - - if(!instance->worker_running) { - return; - } - - instance->worker_running = false; - furi_thread_join(instance->thread); - - furi_hal_subghz_set_path(FuriHalSubGhzPathIsolate); - furi_hal_subghz_sleep(); -} - -bool subbrute_worker_transmit_current_key(SubBruteWorker* instance, uint64_t step) { - furi_assert(instance); - - if(!instance->initiated) { - FURI_LOG_W(TAG, "Worker not init!"); - return false; - } - if(instance->worker_running) { - FURI_LOG_W(TAG, "Worker in running state!"); - return false; - } - if(instance->state != SubBruteWorkerStateReady && - instance->state != SubBruteWorkerStateFinished) { - FURI_LOG_W(TAG, "Invalid state for running worker! State: %d", instance->state); - return false; - } - - uint32_t ticks = furi_get_tick(); - if((ticks - instance->last_time_tx_data) < SUBBRUTE_MANUAL_TRANSMIT_INTERVAL) { -#if FURI_DEBUG - FURI_LOG_D(TAG, "Need to wait, current: %ld", ticks - instance->last_time_tx_data); -#endif - return false; - } - - instance->last_time_tx_data = ticks; - instance->step = step; - - bool result; - instance->protocol_name = subbrute_protocol_file(instance->file); - FlipperFormat* flipper_format = flipper_format_string_alloc(); - Stream* stream = flipper_format_get_raw_stream(flipper_format); - - stream_clean(stream); - - if(instance->attack == SubBruteAttackLoadFile) { - subbrute_protocol_file_payload( - stream, - step, - instance->bits, - instance->te, - instance->repeat, - instance->load_index, - instance->file_key, - instance->two_bytes); - } else { - subbrute_protocol_default_payload( - stream, instance->file, step, instance->bits, instance->te, instance->repeat); - } - - // size_t written = stream_write_string(stream, payload); - // if(written <= 0) { - // FURI_LOG_W(TAG, "Error creating packet! EXIT"); - // result = false; - // } else { - subbrute_worker_subghz_transmit(instance, flipper_format); - - result = true; -#if FURI_DEBUG - FURI_LOG_D(TAG, "Manual transmit done"); -#endif - // } - - flipper_format_free(flipper_format); - // furi_string_free(payload); - - return result; -} - -bool subbrute_worker_is_running(SubBruteWorker* instance) { - return instance->worker_running; -} - -bool subbrute_worker_can_manual_transmit(SubBruteWorker* instance) { - furi_assert(instance); - - if(!instance->initiated) { - FURI_LOG_W(TAG, "Worker not init!"); - return false; - } - - return !instance->worker_running && instance->state != SubBruteWorkerStateIDLE && - instance->state != SubBruteWorkerStateTx && - ((furi_get_tick() - instance->last_time_tx_data) > SUBBRUTE_MANUAL_TRANSMIT_INTERVAL); -} - -void subbrute_worker_set_callback( - SubBruteWorker* instance, - SubBruteWorkerCallback callback, - void* context) { - furi_assert(instance); - - instance->callback = callback; - instance->context = context; -} - -void subbrute_worker_subghz_transmit(SubBruteWorker* instance, FlipperFormat* flipper_format) { - while(instance->transmit_mode) { - furi_delay_ms(SUBBRUTE_TX_TIMEOUT); - } - instance->transmit_mode = true; - if(instance->transmitter != NULL) { - subghz_transmitter_free(instance->transmitter); - instance->transmitter = NULL; - } - instance->transmitter = - subghz_transmitter_alloc_init(instance->environment, instance->protocol_name); - subghz_transmitter_deserialize(instance->transmitter, flipper_format); - furi_hal_subghz_reset(); - furi_hal_subghz_load_preset(instance->preset); - furi_hal_subghz_set_frequency_and_path(instance->frequency); - furi_hal_subghz_start_async_tx(subghz_transmitter_yield, instance->transmitter); - - while(!furi_hal_subghz_is_async_tx_complete()) { - furi_delay_ms(SUBBRUTE_TX_TIMEOUT); - } - furi_hal_subghz_stop_async_tx(); - - furi_hal_subghz_set_path(FuriHalSubGhzPathIsolate); - furi_hal_subghz_sleep(); - subghz_transmitter_free(instance->transmitter); - instance->transmitter = NULL; - - instance->transmit_mode = false; -} - -void subbrute_worker_send_callback(SubBruteWorker* instance) { - if(instance->callback != NULL) { - instance->callback(instance->context, instance->state); - } -} - -/** - * Entrypoint for worker - * - * @param context SubBruteWorker* - * @return 0 if ok - */ -int32_t subbrute_worker_thread(void* context) { - furi_assert(context); - SubBruteWorker* instance = (SubBruteWorker*)context; - - if(!instance->worker_running) { - FURI_LOG_W(TAG, "Worker is not set to running state!"); - return -1; - } - if(instance->state != SubBruteWorkerStateReady && - instance->state != SubBruteWorkerStateFinished) { - FURI_LOG_W(TAG, "Invalid state for running worker! State: %d", instance->state); - return -2; - } -#ifdef FURI_DEBUG - FURI_LOG_I(TAG, "Worker start"); -#endif - - SubBruteWorkerState local_state = instance->state = SubBruteWorkerStateTx; - subbrute_worker_send_callback(instance); - - instance->protocol_name = subbrute_protocol_file(instance->file); - - FlipperFormat* flipper_format = flipper_format_string_alloc(); - Stream* stream = flipper_format_get_raw_stream(flipper_format); - - while(instance->worker_running) { - stream_clean(stream); - if(instance->attack == SubBruteAttackLoadFile) { - subbrute_protocol_file_payload( - stream, - instance->step, - instance->bits, - instance->te, - instance->repeat, - instance->load_index, - instance->file_key, - instance->two_bytes); - } else { - subbrute_protocol_default_payload( - stream, - instance->file, - instance->step, - instance->bits, - instance->te, - instance->repeat); - } -#ifdef FURI_DEBUG - //FURI_LOG_I(TAG, "Payload: %s", furi_string_get_cstr(payload)); - //furi_delay_ms(SUBBRUTE_MANUAL_TRANSMIT_INTERVAL / 4); -#endif - - // size_t written = stream_write_stream_write_string(stream, payload); - // if(written <= 0) { - // FURI_LOG_W(TAG, "Error creating packet! BREAK"); - // instance->worker_running = false; - // local_state = SubBruteWorkerStateIDLE; - // furi_string_free(payload); - // break; - // } - - subbrute_worker_subghz_transmit(instance, flipper_format); - - if(instance->step + 1 > instance->max_value) { -#ifdef FURI_DEBUG - FURI_LOG_I(TAG, "Worker finished to end"); -#endif - local_state = SubBruteWorkerStateFinished; - // furi_string_free(payload); - break; - } - instance->step++; - - // furi_string_free(payload); - furi_delay_ms(SUBBRUTE_TX_TIMEOUT); - } - - flipper_format_free(flipper_format); - - instance->worker_running = false; // Because we have error states - instance->state = local_state == SubBruteWorkerStateTx ? SubBruteWorkerStateReady : - local_state; - subbrute_worker_send_callback(instance); - -#ifdef FURI_DEBUG - FURI_LOG_I(TAG, "Worker stop"); -#endif - return 0; -} +#include "subbrute_worker_private.h" +#include +#include +#include +#include +#include + +#define TAG "SubBruteWorker" +#define SUBBRUTE_TX_TIMEOUT 6 +#define SUBBRUTE_MANUAL_TRANSMIT_INTERVAL 250 + +SubBruteWorker* subbrute_worker_alloc() { + SubBruteWorker* instance = malloc(sizeof(SubBruteWorker)); + + instance->state = SubBruteWorkerStateIDLE; + instance->step = 0; + instance->worker_running = false; + instance->initiated = false; + instance->last_time_tx_data = 0; + instance->load_index = 0; + + instance->thread = furi_thread_alloc(); + furi_thread_set_name(instance->thread, "SubBruteAttackWorker"); + furi_thread_set_stack_size(instance->thread, 2048); + furi_thread_set_context(instance->thread, instance); + furi_thread_set_callback(instance->thread, subbrute_worker_thread); + + instance->context = NULL; + instance->callback = NULL; + + instance->tx_timeout_ms = SUBBRUTE_TX_TIMEOUT; + instance->decoder_result = NULL; + instance->transmitter = NULL; + instance->environment = subghz_environment_alloc(); + subghz_environment_set_protocol_registry( + instance->environment, (void*)&subghz_protocol_registry); + + instance->transmit_mode = false; + + return instance; +} + +void subbrute_worker_free(SubBruteWorker* instance) { + furi_assert(instance); + + // I don't know how to free this + instance->decoder_result = NULL; + + if(instance->transmitter != NULL) { + subghz_transmitter_free(instance->transmitter); + instance->transmitter = NULL; + } + + subghz_environment_free(instance->environment); + instance->environment = NULL; + + furi_thread_free(instance->thread); + + free(instance); +} + +uint64_t subbrute_worker_get_step(SubBruteWorker* instance) { + return instance->step; +} + +bool subbrute_worker_set_step(SubBruteWorker* instance, uint64_t step) { + furi_assert(instance); + if(!subbrute_worker_can_manual_transmit(instance)) { + FURI_LOG_W(TAG, "Cannot set step during running mode"); + return false; + } + + instance->step = step; + + return true; +} + +bool subbrute_worker_init_default_attack( + SubBruteWorker* instance, + SubBruteAttacks attack_type, + uint64_t step, + const SubBruteProtocol* protocol, + uint8_t extra_repeats) { + furi_assert(instance); + + if(instance->worker_running) { + FURI_LOG_W(TAG, "Init Worker when it's running"); + subbrute_worker_stop(instance); + } + + instance->attack = attack_type; + instance->frequency = protocol->frequency; + instance->preset = protocol->preset; + instance->file = protocol->file; + instance->step = step; + instance->bits = protocol->bits; + instance->te = protocol->te; + instance->repeat = protocol->repeat + extra_repeats; + instance->load_index = 0; + instance->file_key = 0; + instance->two_bytes = false; + + instance->max_value = + subbrute_protocol_calc_max_value(instance->attack, instance->bits, instance->two_bytes); + + instance->initiated = true; + instance->state = SubBruteWorkerStateReady; + subbrute_worker_send_callback(instance); +#ifdef FURI_DEBUG + FURI_LOG_I( + TAG, + "subbrute_worker_init_default_attack: %s, bits: %d, preset: %s, file: %s, te: %ld, repeat: %d, max_value: %lld", + subbrute_protocol_name(instance->attack), + instance->bits, + subbrute_protocol_preset(instance->preset), + subbrute_protocol_file(instance->file), + instance->te, + instance->repeat, + instance->max_value); +#endif + + return true; +} + +bool subbrute_worker_init_file_attack( + SubBruteWorker* instance, + uint64_t step, + uint8_t load_index, + uint64_t file_key, + SubBruteProtocol* protocol, + uint8_t extra_repeats, + bool two_bytes) { + furi_assert(instance); + + if(instance->worker_running) { + FURI_LOG_W(TAG, "Init Worker when it's running"); + subbrute_worker_stop(instance); + } + + instance->attack = SubBruteAttackLoadFile; + instance->frequency = protocol->frequency; + instance->preset = protocol->preset; + instance->file = protocol->file; + instance->step = step; + instance->bits = protocol->bits; + instance->te = protocol->te; + instance->load_index = load_index; + instance->repeat = protocol->repeat + extra_repeats; + instance->file_key = file_key; + instance->two_bytes = two_bytes; + + instance->max_value = + subbrute_protocol_calc_max_value(instance->attack, instance->bits, instance->two_bytes); + + instance->initiated = true; + instance->state = SubBruteWorkerStateReady; + subbrute_worker_send_callback(instance); +#ifdef FURI_DEBUG + FURI_LOG_I( + TAG, + "subbrute_worker_init_file_attack: %s, bits: %d, preset: %s, file: %s, te: %ld, repeat: %d, max_value: %lld, key: %llX", + subbrute_protocol_name(instance->attack), + instance->bits, + subbrute_protocol_preset(instance->preset), + subbrute_protocol_file(instance->file), + instance->te, + instance->repeat, + instance->max_value, + instance->file_key); +#endif + + return true; +} + +bool subbrute_worker_start(SubBruteWorker* instance) { + furi_assert(instance); + + if(!instance->initiated) { + FURI_LOG_W(TAG, "Worker not init!"); + return false; + } + + if(instance->worker_running) { + FURI_LOG_W(TAG, "Worker is already running!"); + return false; + } + if(instance->state != SubBruteWorkerStateReady && + instance->state != SubBruteWorkerStateFinished) { + FURI_LOG_W(TAG, "Worker cannot start, invalid device state: %d", instance->state); + return false; + } + + instance->worker_running = true; + furi_thread_start(instance->thread); + + return true; +} + +void subbrute_worker_stop(SubBruteWorker* instance) { + furi_assert(instance); + + if(!instance->worker_running) { + return; + } + + instance->worker_running = false; + furi_thread_join(instance->thread); + + furi_hal_subghz_set_path(FuriHalSubGhzPathIsolate); + furi_hal_subghz_idle(); + furi_hal_subghz_sleep(); +} + +bool subbrute_worker_transmit_current_key(SubBruteWorker* instance, uint64_t step) { + furi_assert(instance); + + if(!instance->initiated) { + FURI_LOG_W(TAG, "Worker not init!"); + return false; + } + if(instance->worker_running) { + FURI_LOG_W(TAG, "Worker in running state!"); + return false; + } + if(instance->state != SubBruteWorkerStateReady && + instance->state != SubBruteWorkerStateFinished) { + FURI_LOG_W(TAG, "Invalid state for running worker! State: %d", instance->state); + return false; + } + + uint32_t ticks = furi_get_tick(); + if((ticks - instance->last_time_tx_data) < SUBBRUTE_MANUAL_TRANSMIT_INTERVAL) { +#if FURI_DEBUG + FURI_LOG_D(TAG, "Need to wait, current: %ld", ticks - instance->last_time_tx_data); +#endif + return false; + } + + instance->last_time_tx_data = ticks; + instance->step = step; + + bool result; + instance->protocol_name = subbrute_protocol_file(instance->file); + FlipperFormat* flipper_format = flipper_format_string_alloc(); + Stream* stream = flipper_format_get_raw_stream(flipper_format); + + stream_clean(stream); + + if(instance->attack == SubBruteAttackLoadFile) { + subbrute_protocol_file_payload( + stream, + step, + instance->bits, + instance->te, + instance->repeat, + instance->load_index, + instance->file_key, + instance->two_bytes); + } else { + subbrute_protocol_default_payload( + stream, instance->file, step, instance->bits, instance->te, instance->repeat); + } + + // size_t written = stream_write_string(stream, payload); + // if(written <= 0) { + // FURI_LOG_W(TAG, "Error creating packet! EXIT"); + // result = false; + // } else { + subbrute_worker_subghz_transmit(instance, flipper_format); + + result = true; +#if FURI_DEBUG + FURI_LOG_D(TAG, "Manual transmit done"); +#endif + // } + + flipper_format_free(flipper_format); + // furi_string_free(payload); + + return result; +} + +bool subbrute_worker_is_running(SubBruteWorker* instance) { + return instance->worker_running; +} + +bool subbrute_worker_can_manual_transmit(SubBruteWorker* instance) { + furi_assert(instance); + + if(!instance->initiated) { + FURI_LOG_W(TAG, "Worker not init!"); + return false; + } + + return !instance->worker_running && instance->state != SubBruteWorkerStateIDLE && + instance->state != SubBruteWorkerStateTx && + ((furi_get_tick() - instance->last_time_tx_data) > SUBBRUTE_MANUAL_TRANSMIT_INTERVAL); +} + +void subbrute_worker_set_callback( + SubBruteWorker* instance, + SubBruteWorkerCallback callback, + void* context) { + furi_assert(instance); + + instance->callback = callback; + instance->context = context; +} + +void subbrute_worker_subghz_transmit(SubBruteWorker* instance, FlipperFormat* flipper_format) { + const uint8_t timeout = instance->tx_timeout_ms; + while(instance->transmit_mode) { + furi_delay_ms(timeout); + } + instance->transmit_mode = true; + if(instance->transmitter != NULL) { + subghz_transmitter_free(instance->transmitter); + instance->transmitter = NULL; + } + instance->transmitter = + subghz_transmitter_alloc_init(instance->environment, instance->protocol_name); + subghz_transmitter_deserialize(instance->transmitter, flipper_format); + furi_hal_subghz_reset(); + furi_hal_subghz_idle(); + furi_hal_subghz_load_preset(instance->preset); + furi_hal_subghz_set_frequency_and_path(instance->frequency); + furi_hal_subghz_start_async_tx(subghz_transmitter_yield, instance->transmitter); + + while(!furi_hal_subghz_is_async_tx_complete()) { + furi_delay_ms(timeout); + } + furi_hal_subghz_stop_async_tx(); + + //furi_hal_subghz_set_path(FuriHalSubGhzPathIsolate); + furi_hal_subghz_idle(); + //furi_hal_subghz_sleep(); + subghz_transmitter_stop(instance->transmitter); + subghz_transmitter_free(instance->transmitter); + instance->transmitter = NULL; + + instance->transmit_mode = false; +} + +void subbrute_worker_send_callback(SubBruteWorker* instance) { + if(instance->callback != NULL) { + instance->callback(instance->context, instance->state); + } +} + +/** + * Entrypoint for worker + * + * @param context SubBruteWorker* + * @return 0 if ok + */ +int32_t subbrute_worker_thread(void* context) { + furi_assert(context); + SubBruteWorker* instance = (SubBruteWorker*)context; + + if(!instance->worker_running) { + FURI_LOG_W(TAG, "Worker is not set to running state!"); + return -1; + } + if(instance->state != SubBruteWorkerStateReady && + instance->state != SubBruteWorkerStateFinished) { + FURI_LOG_W(TAG, "Invalid state for running worker! State: %d", instance->state); + return -2; + } +#ifdef FURI_DEBUG + FURI_LOG_I(TAG, "Worker start"); +#endif + + SubBruteWorkerState local_state = instance->state = SubBruteWorkerStateTx; + subbrute_worker_send_callback(instance); + + instance->protocol_name = subbrute_protocol_file(instance->file); + + FlipperFormat* flipper_format = flipper_format_string_alloc(); + Stream* stream = flipper_format_get_raw_stream(flipper_format); + + while(instance->worker_running) { + stream_clean(stream); + if(instance->attack == SubBruteAttackLoadFile) { + subbrute_protocol_file_payload( + stream, + instance->step, + instance->bits, + instance->te, + instance->repeat, + instance->load_index, + instance->file_key, + instance->two_bytes); + } else { + subbrute_protocol_default_payload( + stream, + instance->file, + instance->step, + instance->bits, + instance->te, + instance->repeat); + } +#ifdef FURI_DEBUG + //FURI_LOG_I(TAG, "Payload: %s", furi_string_get_cstr(payload)); + //furi_delay_ms(SUBBRUTE_MANUAL_TRANSMIT_INTERVAL / 4); +#endif + + // size_t written = stream_write_stream_write_string(stream, payload); + // if(written <= 0) { + // FURI_LOG_W(TAG, "Error creating packet! BREAK"); + // instance->worker_running = false; + // local_state = SubBruteWorkerStateIDLE; + // furi_string_free(payload); + // break; + // } + + subbrute_worker_subghz_transmit(instance, flipper_format); + + if(instance->step + 1 > instance->max_value) { +#ifdef FURI_DEBUG + FURI_LOG_I(TAG, "Worker finished to end"); +#endif + local_state = SubBruteWorkerStateFinished; + // furi_string_free(payload); + break; + } + instance->step++; + + // furi_string_free(payload); + furi_delay_ms(instance->tx_timeout_ms); + } + + flipper_format_free(flipper_format); + + instance->worker_running = false; // Because we have error states + instance->state = local_state == SubBruteWorkerStateTx ? SubBruteWorkerStateReady : + local_state; + subbrute_worker_send_callback(instance); + +#ifdef FURI_DEBUG + FURI_LOG_I(TAG, "Worker stop"); +#endif + return 0; +} + +uint8_t subbrute_worker_get_timeout(SubBruteWorker* instance) { + return instance->tx_timeout_ms; +} + +void subbrute_worker_timeout_inc(SubBruteWorker* instance) { + if(instance->tx_timeout_ms < 255) { + instance->tx_timeout_ms++; + } +} + +void subbrute_worker_timeout_dec(SubBruteWorker* instance) { + if(instance->tx_timeout_ms > 0) { + instance->tx_timeout_ms--; + } +} \ No newline at end of file diff --git a/helpers/subbrute_worker.h b/helpers/subbrute_worker.h index 4046f997c4e..2f1030c78e2 100644 --- a/helpers/subbrute_worker.h +++ b/helpers/subbrute_worker.h @@ -1,42 +1,48 @@ -#pragma once - -#include "../subbrute_protocols.h" - -typedef enum { - SubBruteWorkerStateIDLE, - SubBruteWorkerStateReady, - SubBruteWorkerStateTx, - SubBruteWorkerStateFinished -} SubBruteWorkerState; - -typedef void (*SubBruteWorkerCallback)(void* context, SubBruteWorkerState state); - -typedef struct SubBruteWorker SubBruteWorker; - -SubBruteWorker* subbrute_worker_alloc(); -void subbrute_worker_free(SubBruteWorker* instance); -uint64_t subbrute_worker_get_step(SubBruteWorker* instance); -bool subbrute_worker_set_step(SubBruteWorker* instance, uint64_t step); -bool subbrute_worker_is_running(SubBruteWorker* instance); -bool subbrute_worker_init_default_attack( - SubBruteWorker* instance, - SubBruteAttacks attack_type, - uint64_t step, - const SubBruteProtocol* protocol, - uint8_t extra_repeats); -bool subbrute_worker_init_file_attack( - SubBruteWorker* instance, - uint64_t step, - uint8_t load_index, - uint64_t file_key, - SubBruteProtocol* protocol, - uint8_t extra_repeats, - bool two_bytes); -bool subbrute_worker_start(SubBruteWorker* instance); -void subbrute_worker_stop(SubBruteWorker* instance); -bool subbrute_worker_transmit_current_key(SubBruteWorker* instance, uint64_t step); -bool subbrute_worker_can_manual_transmit(SubBruteWorker* instance); -void subbrute_worker_set_callback( - SubBruteWorker* instance, - SubBruteWorkerCallback callback, - void* context); \ No newline at end of file +#pragma once + +#include "../subbrute_protocols.h" + +typedef enum { + SubBruteWorkerStateIDLE, + SubBruteWorkerStateReady, + SubBruteWorkerStateTx, + SubBruteWorkerStateFinished +} SubBruteWorkerState; + +typedef void (*SubBruteWorkerCallback)(void* context, SubBruteWorkerState state); + +typedef struct SubBruteWorker SubBruteWorker; + +SubBruteWorker* subbrute_worker_alloc(); +void subbrute_worker_free(SubBruteWorker* instance); +uint64_t subbrute_worker_get_step(SubBruteWorker* instance); +bool subbrute_worker_set_step(SubBruteWorker* instance, uint64_t step); +bool subbrute_worker_is_running(SubBruteWorker* instance); +bool subbrute_worker_init_default_attack( + SubBruteWorker* instance, + SubBruteAttacks attack_type, + uint64_t step, + const SubBruteProtocol* protocol, + uint8_t extra_repeats); +bool subbrute_worker_init_file_attack( + SubBruteWorker* instance, + uint64_t step, + uint8_t load_index, + uint64_t file_key, + SubBruteProtocol* protocol, + uint8_t extra_repeats, + bool two_bytes); +bool subbrute_worker_start(SubBruteWorker* instance); +void subbrute_worker_stop(SubBruteWorker* instance); +bool subbrute_worker_transmit_current_key(SubBruteWorker* instance, uint64_t step); +bool subbrute_worker_can_manual_transmit(SubBruteWorker* instance); +void subbrute_worker_set_callback( + SubBruteWorker* instance, + SubBruteWorkerCallback callback, + void* context); + +uint8_t subbrute_worker_get_timeout(SubBruteWorker* instance); + +void subbrute_worker_timeout_inc(SubBruteWorker* instance); + +void subbrute_worker_timeout_dec(SubBruteWorker* instance); diff --git a/helpers/subbrute_worker_private.h b/helpers/subbrute_worker_private.h index e38e77dc46f..b497db67637 100644 --- a/helpers/subbrute_worker_private.h +++ b/helpers/subbrute_worker_private.h @@ -1,48 +1,49 @@ -#pragma once - -#include "subbrute_worker.h" -#include -#include -#include -#include - -struct SubBruteWorker { - SubBruteWorkerState state; - volatile bool worker_running; - volatile bool initiated; - volatile bool transmit_mode; - - // Current step - uint64_t step; - - // SubGhz - FuriThread* thread; - SubGhzProtocolDecoderBase* decoder_result; - SubGhzEnvironment* environment; - SubGhzTransmitter* transmitter; - const char* protocol_name; - - // Initiated values - SubBruteAttacks attack; // Attack state - uint32_t frequency; - FuriHalSubGhzPreset preset; - SubBruteFileProtocol file; - uint8_t bits; - uint32_t te; - uint8_t repeat; - uint8_t load_index; // Index of group to bruteforce in loaded file - uint64_t file_key; - uint64_t max_value; // Max step - bool two_bytes; - - // Manual transmit - uint32_t last_time_tx_data; - - // Callback for changed states - SubBruteWorkerCallback callback; - void* context; -}; - -int32_t subbrute_worker_thread(void* context); -void subbrute_worker_subghz_transmit(SubBruteWorker* instance, FlipperFormat* flipper_format); +#pragma once + +#include "subbrute_worker.h" +#include +#include +#include +#include + +struct SubBruteWorker { + SubBruteWorkerState state; + volatile bool worker_running; + volatile bool initiated; + volatile bool transmit_mode; + + // Current step + uint64_t step; + + // SubGhz + FuriThread* thread; + SubGhzProtocolDecoderBase* decoder_result; + SubGhzEnvironment* environment; + SubGhzTransmitter* transmitter; + const char* protocol_name; + uint8_t tx_timeout_ms; + + // Initiated values + SubBruteAttacks attack; // Attack state + uint32_t frequency; + FuriHalSubGhzPreset preset; + SubBruteFileProtocol file; + uint8_t bits; + uint32_t te; + uint8_t repeat; + uint8_t load_index; // Index of group to bruteforce in loaded file + uint64_t file_key; + uint64_t max_value; // Max step + bool two_bytes; + + // Manual transmit + uint32_t last_time_tx_data; + + // Callback for changed states + SubBruteWorkerCallback callback; + void* context; +}; + +int32_t subbrute_worker_thread(void* context); +void subbrute_worker_subghz_transmit(SubBruteWorker* instance, FlipperFormat* flipper_format); void subbrute_worker_send_callback(SubBruteWorker* instance); \ No newline at end of file diff --git a/scenes/subbrute_scene.h b/scenes/subbrute_scene.h index c048985e24f..a4f3b64c68b 100644 --- a/scenes/subbrute_scene.h +++ b/scenes/subbrute_scene.h @@ -1,29 +1,29 @@ -#pragma once - -#include - -// Generate scene id and total number -#define ADD_SCENE(prefix, name, id) SubBruteScene##id, -typedef enum { -#include "subbrute_scene_config.h" - SubBruteSceneNum, -} SubBruteScene; -#undef ADD_SCENE - -extern const SceneManagerHandlers subbrute_scene_handlers; - -// Generate scene on_enter handlers declaration -#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*); -#include "subbrute_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 "subbrute_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 "subbrute_scene_config.h" -#undef ADD_SCENE +#pragma once + +#include + +// Generate scene id and total number +#define ADD_SCENE(prefix, name, id) SubBruteScene##id, +typedef enum { +#include "subbrute_scene_config.h" + SubBruteSceneNum, +} SubBruteScene; +#undef ADD_SCENE + +extern const SceneManagerHandlers subbrute_scene_handlers; + +// Generate scene on_enter handlers declaration +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*); +#include "subbrute_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 "subbrute_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 "subbrute_scene_config.h" +#undef ADD_SCENE diff --git a/scenes/subbrute_scene_config.h b/scenes/subbrute_scene_config.h index 3541df9aca0..bcdd95a8a81 100644 --- a/scenes/subbrute_scene_config.h +++ b/scenes/subbrute_scene_config.h @@ -1,7 +1,8 @@ -ADD_SCENE(subbrute, load_file, LoadFile) -ADD_SCENE(subbrute, load_select, LoadSelect) -ADD_SCENE(subbrute, run_attack, RunAttack) -ADD_SCENE(subbrute, save_name, SaveName) -ADD_SCENE(subbrute, save_success, SaveSuccess) -ADD_SCENE(subbrute, setup_attack, SetupAttack) +ADD_SCENE(subbrute, load_file, LoadFile) +ADD_SCENE(subbrute, load_select, LoadSelect) +ADD_SCENE(subbrute, run_attack, RunAttack) +ADD_SCENE(subbrute, save_name, SaveName) +ADD_SCENE(subbrute, save_success, SaveSuccess) +ADD_SCENE(subbrute, setup_attack, SetupAttack) +ADD_SCENE(subbrute, setup_extra, SetupExtra) ADD_SCENE(subbrute, start, Start) \ No newline at end of file diff --git a/scenes/subbrute_scene_load_file.c b/scenes/subbrute_scene_load_file.c index 8aae1bcadf4..6f0ca53094c 100644 --- a/scenes/subbrute_scene_load_file.c +++ b/scenes/subbrute_scene_load_file.c @@ -1,91 +1,91 @@ -#include "../subbrute_i.h" -#include "subbrute_scene.h" - -#define TAG "SubBruteSceneLoadFile" - -void subbrute_scene_load_file_on_enter(void* context) { - furi_assert(context); - SubBruteState* instance = (SubBruteState*)context; - - // Input events and views are managed by file_browser - FuriString* app_folder; - FuriString* load_path; - load_path = furi_string_alloc(); - app_folder = furi_string_alloc_set(SUBBRUTE_PATH); - - DialogsFileBrowserOptions browser_options; - dialog_file_browser_set_basic_options(&browser_options, SUBBRUTE_FILE_EXT, &I_sub1_10px); - - SubBruteFileResult load_result = SubBruteFileResultUnknown; - // TODO: DELETE IT -#ifdef SUBBRUTE_FAST_TRACK - bool res = true; - furi_string_printf(load_path, "%s", "/ext/subghz/princeton.sub"); -#else - bool res = - dialog_file_browser_show(instance->dialogs, load_path, app_folder, &browser_options); -#endif -#ifdef FURI_DEBUG - FURI_LOG_D( - TAG, - "load_path: %s, app_folder: %s", - furi_string_get_cstr(load_path), - furi_string_get_cstr(app_folder)); -#endif - if(res) { - load_result = - subbrute_device_load_from_file(instance->device, furi_string_get_cstr(load_path)); - if(load_result == SubBruteFileResultOk) { - uint8_t extra_repeats = subbrute_main_view_get_extra_repeats(instance->view_main); - - load_result = subbrute_device_attack_set( - instance->device, SubBruteAttackLoadFile, extra_repeats); - if(load_result == SubBruteFileResultOk) { - if(!subbrute_worker_init_file_attack( - instance->worker, - instance->device->current_step, - instance->device->bit_index, - instance->device->key_from_file, - instance->device->file_protocol_info, - extra_repeats, - instance->device->two_bytes)) { - furi_crash("Invalid attack set!"); - } - // Ready to run! - FURI_LOG_I(TAG, "Ready to run"); - res = true; - } - } - - if(load_result == SubBruteFileResultOk) { - scene_manager_next_scene(instance->scene_manager, SubBruteSceneLoadSelect); - } else { - FURI_LOG_E(TAG, "Returned error: %d", load_result); - - FuriString* dialog_msg; - dialog_msg = furi_string_alloc(); - furi_string_cat_printf( - dialog_msg, "Cannot parse\nfile: %s", subbrute_device_error_get_desc(load_result)); - dialog_message_show_storage_error(instance->dialogs, furi_string_get_cstr(dialog_msg)); - furi_string_free(dialog_msg); - scene_manager_search_and_switch_to_previous_scene( - instance->scene_manager, SubBruteSceneStart); - } - } else { - scene_manager_search_and_switch_to_previous_scene( - instance->scene_manager, SubBruteSceneStart); - } - - furi_string_free(app_folder); - furi_string_free(load_path); -} - -void subbrute_scene_load_file_on_exit(void* context) { - UNUSED(context); -} - -bool subbrute_scene_load_file_on_event(void* context, SceneManagerEvent event) { - UNUSED(context); - UNUSED(event); - return false; +#include "../subbrute_i.h" +#include "subbrute_scene.h" + +#define TAG "SubBruteSceneLoadFile" + +void subbrute_scene_load_file_on_enter(void* context) { + furi_assert(context); + SubBruteState* instance = (SubBruteState*)context; + + // Input events and views are managed by file_browser + FuriString* app_folder; + FuriString* load_path; + load_path = furi_string_alloc(); + app_folder = furi_string_alloc_set(SUBBRUTE_PATH); + + DialogsFileBrowserOptions browser_options; + dialog_file_browser_set_basic_options(&browser_options, SUBBRUTE_FILE_EXT, &I_sub1_10px); + + SubBruteFileResult load_result = SubBruteFileResultUnknown; + // TODO: DELETE IT +#ifdef SUBBRUTE_FAST_TRACK + bool res = true; + furi_string_printf(load_path, "%s", "/ext/subghz/princeton.sub"); +#else + bool res = + dialog_file_browser_show(instance->dialogs, load_path, app_folder, &browser_options); +#endif +#ifdef FURI_DEBUG + FURI_LOG_D( + TAG, + "load_path: %s, app_folder: %s", + furi_string_get_cstr(load_path), + furi_string_get_cstr(app_folder)); +#endif + if(res) { + load_result = + subbrute_device_load_from_file(instance->device, furi_string_get_cstr(load_path)); + if(load_result == SubBruteFileResultOk) { + uint8_t extra_repeats = subbrute_main_view_get_extra_repeats(instance->view_main); + + load_result = subbrute_device_attack_set( + instance->device, SubBruteAttackLoadFile, extra_repeats); + if(load_result == SubBruteFileResultOk) { + if(!subbrute_worker_init_file_attack( + instance->worker, + instance->device->current_step, + instance->device->bit_index, + instance->device->key_from_file, + instance->device->file_protocol_info, + extra_repeats, + instance->device->two_bytes)) { + furi_crash("Invalid attack set!"); + } + // Ready to run! + FURI_LOG_I(TAG, "Ready to run"); + res = true; + } + } + + if(load_result == SubBruteFileResultOk) { + scene_manager_next_scene(instance->scene_manager, SubBruteSceneLoadSelect); + } else { + FURI_LOG_E(TAG, "Returned error: %d", load_result); + + FuriString* dialog_msg; + dialog_msg = furi_string_alloc(); + furi_string_cat_printf( + dialog_msg, "Cannot parse\nfile: %s", subbrute_device_error_get_desc(load_result)); + dialog_message_show_storage_error(instance->dialogs, furi_string_get_cstr(dialog_msg)); + furi_string_free(dialog_msg); + scene_manager_search_and_switch_to_previous_scene( + instance->scene_manager, SubBruteSceneStart); + } + } else { + scene_manager_search_and_switch_to_previous_scene( + instance->scene_manager, SubBruteSceneStart); + } + + furi_string_free(app_folder); + furi_string_free(load_path); +} + +void subbrute_scene_load_file_on_exit(void* context) { + UNUSED(context); +} + +bool subbrute_scene_load_file_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + UNUSED(event); + return false; } \ No newline at end of file diff --git a/scenes/subbrute_scene_load_select.c b/scenes/subbrute_scene_load_select.c index d018e8b4d6e..a31f828e6f2 100644 --- a/scenes/subbrute_scene_load_select.c +++ b/scenes/subbrute_scene_load_select.c @@ -1,82 +1,82 @@ -#include "../subbrute_i.h" -#include "subbrute_scene.h" - -#define TAG "SubBruteSceneStart" - -void subbrute_scene_load_select_callback(SubBruteCustomEvent event, void* context) { - furi_assert(context); - - SubBruteState* instance = (SubBruteState*)context; - view_dispatcher_send_custom_event(instance->view_dispatcher, event); -} - -void subbrute_scene_load_select_on_enter(void* context) { - furi_assert(context); -#ifdef FURI_DEBUG - FURI_LOG_I(TAG, "subbrute_scene_load_select_on_enter"); -#endif - SubBruteState* instance = (SubBruteState*)context; - SubBruteMainView* view = instance->view_main; - - instance->current_view = SubBruteViewMain; - subbrute_main_view_set_callback(view, subbrute_scene_load_select_callback, instance); - subbrute_main_view_set_index( - view, 7, true, instance->device->two_bytes, instance->device->key_from_file); - - view_dispatcher_switch_to_view(instance->view_dispatcher, instance->current_view); -} - -void subbrute_scene_load_select_on_exit(void* context) { - UNUSED(context); -#ifdef FURI_DEBUG - FURI_LOG_I(TAG, "subbrute_scene_load_select_on_exit"); -#endif -} - -bool subbrute_scene_load_select_on_event(void* context, SceneManagerEvent event) { - SubBruteState* instance = (SubBruteState*)context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == SubBruteCustomEventTypeIndexSelected) { - /*#ifdef FURI_DEBUG && !SUBBRUTE_FAST_TRACK - view_dispatcher_stop(instance->view_dispatcher); - consumed = true; -#else*/ - instance->device->current_step = 0; - instance->device->bit_index = subbrute_main_view_get_index(instance->view_main); - instance->device->two_bytes = subbrute_main_view_get_two_bytes(instance->view_main); - uint8_t extra_repeats = subbrute_main_view_get_extra_repeats(instance->view_main); - instance->device->max_value = subbrute_protocol_calc_max_value( - instance->device->attack, - instance->device->bit_index, - instance->device->two_bytes); - - if(!subbrute_worker_init_file_attack( - instance->worker, - instance->device->current_step, - instance->device->bit_index, - instance->device->key_from_file, - instance->device->file_protocol_info, - extra_repeats, - instance->device->two_bytes)) { - furi_crash("Invalid attack set!"); - } - scene_manager_next_scene(instance->scene_manager, SubBruteSceneSetupAttack); - /*#endif*/ - consumed = true; - } /* else if(event.event == SubBruteCustomEventTypeChangeStepUp) { - instance->device->two_bytes = true; - } else if(event.event == SubBruteCustomEventTypeChangeStepDown) { - instance->device->two_bytes = false; - }*/ - } else if(event.type == SceneManagerEventTypeBack) { - if(!scene_manager_search_and_switch_to_previous_scene( - instance->scene_manager, SubBruteSceneStart)) { - scene_manager_next_scene(instance->scene_manager, SubBruteSceneStart); - } - consumed = true; - } - - return consumed; +#include "../subbrute_i.h" +#include "subbrute_scene.h" + +#define TAG "SubBruteSceneStart" + +void subbrute_scene_load_select_callback(SubBruteCustomEvent event, void* context) { + furi_assert(context); + + SubBruteState* instance = (SubBruteState*)context; + view_dispatcher_send_custom_event(instance->view_dispatcher, event); +} + +void subbrute_scene_load_select_on_enter(void* context) { + furi_assert(context); +#ifdef FURI_DEBUG + FURI_LOG_I(TAG, "subbrute_scene_load_select_on_enter"); +#endif + SubBruteState* instance = (SubBruteState*)context; + SubBruteMainView* view = instance->view_main; + + instance->current_view = SubBruteViewMain; + subbrute_main_view_set_callback(view, subbrute_scene_load_select_callback, instance); + subbrute_main_view_set_index( + view, 7, true, instance->device->two_bytes, instance->device->key_from_file); + + view_dispatcher_switch_to_view(instance->view_dispatcher, instance->current_view); +} + +void subbrute_scene_load_select_on_exit(void* context) { + UNUSED(context); +#ifdef FURI_DEBUG + FURI_LOG_I(TAG, "subbrute_scene_load_select_on_exit"); +#endif +} + +bool subbrute_scene_load_select_on_event(void* context, SceneManagerEvent event) { + SubBruteState* instance = (SubBruteState*)context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubBruteCustomEventTypeIndexSelected) { + /*#ifdef FURI_DEBUG && !SUBBRUTE_FAST_TRACK + view_dispatcher_stop(instance->view_dispatcher); + consumed = true; +#else*/ + instance->device->current_step = 0; + instance->device->bit_index = subbrute_main_view_get_index(instance->view_main); + instance->device->two_bytes = subbrute_main_view_get_two_bytes(instance->view_main); + uint8_t extra_repeats = subbrute_main_view_get_extra_repeats(instance->view_main); + instance->device->max_value = subbrute_protocol_calc_max_value( + instance->device->attack, + instance->device->bit_index, + instance->device->two_bytes); + + if(!subbrute_worker_init_file_attack( + instance->worker, + instance->device->current_step, + instance->device->bit_index, + instance->device->key_from_file, + instance->device->file_protocol_info, + extra_repeats, + instance->device->two_bytes)) { + furi_crash("Invalid attack set!"); + } + scene_manager_next_scene(instance->scene_manager, SubBruteSceneSetupAttack); + /*#endif*/ + consumed = true; + } /* else if(event.event == SubBruteCustomEventTypeChangeStepUp) { + instance->device->two_bytes = true; + } else if(event.event == SubBruteCustomEventTypeChangeStepDown) { + instance->device->two_bytes = false; + }*/ + } else if(event.type == SceneManagerEventTypeBack) { + if(!scene_manager_search_and_switch_to_previous_scene( + instance->scene_manager, SubBruteSceneStart)) { + scene_manager_next_scene(instance->scene_manager, SubBruteSceneStart); + } + consumed = true; + } + + return consumed; } \ No newline at end of file diff --git a/scenes/subbrute_scene_run_attack.c b/scenes/subbrute_scene_run_attack.c index 2f22c25d4c1..922fce8fa33 100644 --- a/scenes/subbrute_scene_run_attack.c +++ b/scenes/subbrute_scene_run_attack.c @@ -1,104 +1,104 @@ -#include "../subbrute_i.h" -#include "subbrute_scene.h" - -#define TAG "SubBruteSceneRunAttack" - -static void subbrute_scene_run_attack_callback(SubBruteCustomEvent event, void* context) { - furi_assert(context); - - SubBruteState* instance = (SubBruteState*)context; - view_dispatcher_send_custom_event(instance->view_dispatcher, event); -} - -static void - subbrute_scene_run_attack_device_state_changed(void* context, SubBruteWorkerState state) { - furi_assert(context); - - SubBruteState* instance = (SubBruteState*)context; - - if(state == SubBruteWorkerStateIDLE) { - // Can't be IDLE on this step! - view_dispatcher_send_custom_event(instance->view_dispatcher, SubBruteCustomEventTypeError); - } else if(state == SubBruteWorkerStateFinished) { - view_dispatcher_send_custom_event( - instance->view_dispatcher, SubBruteCustomEventTypeTransmitFinished); - } -} -void subbrute_scene_run_attack_on_exit(void* context) { - furi_assert(context); - SubBruteState* instance = (SubBruteState*)context; - - notification_message(instance->notifications, &sequence_blink_stop); - subbrute_worker_stop(instance->worker); -} - -void subbrute_scene_run_attack_on_enter(void* context) { - furi_assert(context); - SubBruteState* instance = (SubBruteState*)context; - SubBruteAttackView* view = instance->view_attack; - - instance->current_view = SubBruteViewAttack; - subbrute_attack_view_set_callback(view, subbrute_scene_run_attack_callback, instance); - view_dispatcher_switch_to_view(instance->view_dispatcher, instance->current_view); - - subbrute_worker_set_callback( - instance->worker, subbrute_scene_run_attack_device_state_changed, instance); - - if(!subbrute_worker_is_running(instance->worker)) { - subbrute_worker_set_step(instance->worker, instance->device->current_step); - if(!subbrute_worker_start(instance->worker)) { - view_dispatcher_send_custom_event( - instance->view_dispatcher, SubBruteCustomEventTypeError); - } else { - notification_message(instance->notifications, &sequence_single_vibro); - notification_message(instance->notifications, &sequence_blink_start_yellow); - } - } -} - -bool subbrute_scene_run_attack_on_event(void* context, SceneManagerEvent event) { - SubBruteState* instance = (SubBruteState*)context; - SubBruteAttackView* view = instance->view_attack; - - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - uint64_t step = subbrute_worker_get_step(instance->worker); - instance->device->current_step = step; - subbrute_attack_view_set_current_step(view, step); - - if(event.event == SubBruteCustomEventTypeTransmitFinished) { - notification_message(instance->notifications, &sequence_display_backlight_on); - notification_message(instance->notifications, &sequence_double_vibro); - - scene_manager_next_scene(instance->scene_manager, SubBruteSceneSetupAttack); - } else if( - event.event == SubBruteCustomEventTypeTransmitNotStarted || - event.event == SubBruteCustomEventTypeBackPressed) { - if(subbrute_worker_is_running(instance->worker)) { - // Notify - notification_message(instance->notifications, &sequence_single_vibro); - } - // Stop transmit - scene_manager_search_and_switch_to_previous_scene( - instance->scene_manager, SubBruteSceneSetupAttack); - } else if(event.event == SubBruteCustomEventTypeError) { - notification_message(instance->notifications, &sequence_error); - - // Stop transmit - scene_manager_search_and_switch_to_previous_scene( - instance->scene_manager, SubBruteSceneSetupAttack); - } else if(event.event == SubBruteCustomEventTypeUpdateView) { - //subbrute_attack_view_set_current_step(view, instance->device->current_step); - } - consumed = true; - } else if(event.type == SceneManagerEventTypeTick) { - uint64_t step = subbrute_worker_get_step(instance->worker); - instance->device->current_step = step; - subbrute_attack_view_set_current_step(view, step); - - consumed = true; - } - - return consumed; -} +#include "../subbrute_i.h" +#include "subbrute_scene.h" + +#define TAG "SubBruteSceneRunAttack" + +static void subbrute_scene_run_attack_callback(SubBruteCustomEvent event, void* context) { + furi_assert(context); + + SubBruteState* instance = (SubBruteState*)context; + view_dispatcher_send_custom_event(instance->view_dispatcher, event); +} + +static void + subbrute_scene_run_attack_device_state_changed(void* context, SubBruteWorkerState state) { + furi_assert(context); + + SubBruteState* instance = (SubBruteState*)context; + + if(state == SubBruteWorkerStateIDLE) { + // Can't be IDLE on this step! + view_dispatcher_send_custom_event(instance->view_dispatcher, SubBruteCustomEventTypeError); + } else if(state == SubBruteWorkerStateFinished) { + view_dispatcher_send_custom_event( + instance->view_dispatcher, SubBruteCustomEventTypeTransmitFinished); + } +} +void subbrute_scene_run_attack_on_exit(void* context) { + furi_assert(context); + SubBruteState* instance = (SubBruteState*)context; + + notification_message(instance->notifications, &sequence_blink_stop); + subbrute_worker_stop(instance->worker); +} + +void subbrute_scene_run_attack_on_enter(void* context) { + furi_assert(context); + SubBruteState* instance = (SubBruteState*)context; + SubBruteAttackView* view = instance->view_attack; + + instance->current_view = SubBruteViewAttack; + subbrute_attack_view_set_callback(view, subbrute_scene_run_attack_callback, instance); + view_dispatcher_switch_to_view(instance->view_dispatcher, instance->current_view); + + subbrute_worker_set_callback( + instance->worker, subbrute_scene_run_attack_device_state_changed, instance); + + if(!subbrute_worker_is_running(instance->worker)) { + subbrute_worker_set_step(instance->worker, instance->device->current_step); + if(!subbrute_worker_start(instance->worker)) { + view_dispatcher_send_custom_event( + instance->view_dispatcher, SubBruteCustomEventTypeError); + } else { + notification_message(instance->notifications, &sequence_single_vibro); + notification_message(instance->notifications, &sequence_blink_start_yellow); + } + } +} + +bool subbrute_scene_run_attack_on_event(void* context, SceneManagerEvent event) { + SubBruteState* instance = (SubBruteState*)context; + SubBruteAttackView* view = instance->view_attack; + + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + uint64_t step = subbrute_worker_get_step(instance->worker); + instance->device->current_step = step; + subbrute_attack_view_set_current_step(view, step); + + if(event.event == SubBruteCustomEventTypeTransmitFinished) { + notification_message(instance->notifications, &sequence_display_backlight_on); + notification_message(instance->notifications, &sequence_double_vibro); + + scene_manager_next_scene(instance->scene_manager, SubBruteSceneSetupAttack); + } else if( + event.event == SubBruteCustomEventTypeTransmitNotStarted || + event.event == SubBruteCustomEventTypeBackPressed) { + if(subbrute_worker_is_running(instance->worker)) { + // Notify + notification_message(instance->notifications, &sequence_single_vibro); + } + // Stop transmit + scene_manager_search_and_switch_to_previous_scene( + instance->scene_manager, SubBruteSceneSetupAttack); + } else if(event.event == SubBruteCustomEventTypeError) { + notification_message(instance->notifications, &sequence_error); + + // Stop transmit + scene_manager_search_and_switch_to_previous_scene( + instance->scene_manager, SubBruteSceneSetupAttack); + } else if(event.event == SubBruteCustomEventTypeUpdateView) { + //subbrute_attack_view_set_current_step(view, instance->device->current_step); + } + consumed = true; + } else if(event.type == SceneManagerEventTypeTick) { + uint64_t step = subbrute_worker_get_step(instance->worker); + instance->device->current_step = step; + subbrute_attack_view_set_current_step(view, step); + + consumed = true; + } + + return consumed; +} diff --git a/scenes/subbrute_scene_save_name.c b/scenes/subbrute_scene_save_name.c index bb129e9486d..8f53753d6bd 100644 --- a/scenes/subbrute_scene_save_name.c +++ b/scenes/subbrute_scene_save_name.c @@ -1,84 +1,84 @@ -#include "../subbrute_i.h" -#include "subbrute_scene.h" -#include - -#define TAG "SubBruteSceneSaveFile" - -void subbrute_scene_save_name_on_enter(void* context) { - SubBruteState* instance = (SubBruteState*)context; - - // Setup view - TextInput* text_input = instance->text_input; - set_random_name(instance->text_store, sizeof(instance->text_store)); - - text_input_set_header_text(text_input, "Name of file"); - text_input_set_result_callback( - text_input, - subbrute_text_input_callback, - instance, - instance->text_store, - SUBBRUTE_MAX_LEN_NAME, - true); - - furi_string_reset(instance->file_path); - furi_string_set_str(instance->file_path, SUBBRUTE_PATH); - - ValidatorIsFile* validator_is_file = validator_is_file_alloc_init( - furi_string_get_cstr(instance->file_path), SUBBRUTE_FILE_EXT, ""); - text_input_set_validator(text_input, validator_is_file_callback, validator_is_file); - - view_dispatcher_switch_to_view(instance->view_dispatcher, SubBruteViewTextInput); -} - -bool subbrute_scene_save_name_on_event(void* context, SceneManagerEvent event) { - SubBruteState* instance = (SubBruteState*)context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeBack) { - scene_manager_previous_scene(instance->scene_manager); - return true; - } else if( - event.type == SceneManagerEventTypeCustom && - event.event == SubBruteCustomEventTypeTextEditDone) { -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "Saving: %s", instance->text_store); -#endif - bool success = false; - if(strcmp(instance->text_store, "")) { - furi_string_reset(instance->file_path); - furi_string_cat_printf( - instance->file_path, - "%s/%s%s", - SUBBRUTE_PATH, - instance->text_store, - SUBBRUTE_FILE_EXT); - - if(subbrute_device_save_file( - instance->device, furi_string_get_cstr(instance->file_path))) { - scene_manager_next_scene(instance->scene_manager, SubBruteSceneSaveSuccess); - success = true; - consumed = true; - } - } - - if(!success) { - dialog_message_show_storage_error(instance->dialogs, "Error during saving!"); - consumed = scene_manager_search_and_switch_to_previous_scene( - instance->scene_manager, SubBruteSceneSetupAttack); - } - } - return consumed; -} - -void subbrute_scene_save_name_on_exit(void* context) { - SubBruteState* instance = (SubBruteState*)context; - - // Clear view - void* validator_context = text_input_get_validator_callback_context(instance->text_input); - text_input_set_validator(instance->text_input, NULL, NULL); - validator_is_file_free(validator_context); - - text_input_reset(instance->text_input); - - furi_string_reset(instance->file_path); -} +#include "../subbrute_i.h" +#include "subbrute_scene.h" +#include + +#define TAG "SubBruteSceneSaveFile" + +void subbrute_scene_save_name_on_enter(void* context) { + SubBruteState* instance = (SubBruteState*)context; + + // Setup view + TextInput* text_input = instance->text_input; + set_random_name(instance->text_store, sizeof(instance->text_store)); + + text_input_set_header_text(text_input, "Name of file"); + text_input_set_result_callback( + text_input, + subbrute_text_input_callback, + instance, + instance->text_store, + SUBBRUTE_MAX_LEN_NAME, + true); + + furi_string_reset(instance->file_path); + furi_string_set_str(instance->file_path, SUBBRUTE_PATH); + + ValidatorIsFile* validator_is_file = validator_is_file_alloc_init( + furi_string_get_cstr(instance->file_path), SUBBRUTE_FILE_EXT, ""); + text_input_set_validator(text_input, validator_is_file_callback, validator_is_file); + + view_dispatcher_switch_to_view(instance->view_dispatcher, SubBruteViewTextInput); +} + +bool subbrute_scene_save_name_on_event(void* context, SceneManagerEvent event) { + SubBruteState* instance = (SubBruteState*)context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeBack) { + scene_manager_previous_scene(instance->scene_manager); + return true; + } else if( + event.type == SceneManagerEventTypeCustom && + event.event == SubBruteCustomEventTypeTextEditDone) { +#ifdef FURI_DEBUG + FURI_LOG_D(TAG, "Saving: %s", instance->text_store); +#endif + bool success = false; + if(strcmp(instance->text_store, "")) { + furi_string_reset(instance->file_path); + furi_string_cat_printf( + instance->file_path, + "%s/%s%s", + SUBBRUTE_PATH, + instance->text_store, + SUBBRUTE_FILE_EXT); + + if(subbrute_device_save_file( + instance->device, furi_string_get_cstr(instance->file_path))) { + scene_manager_next_scene(instance->scene_manager, SubBruteSceneSaveSuccess); + success = true; + consumed = true; + } + } + + if(!success) { + dialog_message_show_storage_error(instance->dialogs, "Error during saving!"); + consumed = scene_manager_search_and_switch_to_previous_scene( + instance->scene_manager, SubBruteSceneSetupAttack); + } + } + return consumed; +} + +void subbrute_scene_save_name_on_exit(void* context) { + SubBruteState* instance = (SubBruteState*)context; + + // Clear view + void* validator_context = text_input_get_validator_callback_context(instance->text_input); + text_input_set_validator(instance->text_input, NULL, NULL); + validator_is_file_free(validator_context); + + text_input_reset(instance->text_input); + + furi_string_reset(instance->file_path); +} diff --git a/scenes/subbrute_scene_save_success.c b/scenes/subbrute_scene_save_success.c index 20b1a0de416..058c06e9b25 100644 --- a/scenes/subbrute_scene_save_success.c +++ b/scenes/subbrute_scene_save_success.c @@ -1,51 +1,51 @@ -#include "../subbrute_i.h" -#include "subbrute_scene.h" - -void subbrute_scene_save_success_on_enter(void* context) { - furi_assert(context); - SubBruteState* instance = context; - - // Setup view - Popup* popup = instance->popup; - popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); - popup_set_header(popup, "Saved!", 13, 22, AlignLeft, AlignBottom); - popup_set_timeout(popup, 1500); - popup_set_context(popup, instance); - popup_set_callback(popup, subbrute_popup_closed_callback); - popup_enable_timeout(popup); - view_dispatcher_switch_to_view(instance->view_dispatcher, SubBruteViewPopup); -} - -bool subbrute_scene_save_success_on_event(void* context, SceneManagerEvent event) { - furi_assert(context); - - SubBruteState* instance = (SubBruteState*)context; - //SubBruteMainView* view = instance->view_main; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == SubBruteCustomEventTypePopupClosed) { - if(!scene_manager_search_and_switch_to_previous_scene( - instance->scene_manager, SubBruteSceneSetupAttack)) { - scene_manager_next_scene(instance->scene_manager, SubBruteSceneStart); - } - return true; - } - } - return false; -} - -void subbrute_scene_save_success_on_exit(void* context) { - furi_assert(context); - - SubBruteState* instance = (SubBruteState*)context; - - // Clear view - Popup* popup = instance->popup; - popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom); - popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop); - popup_set_icon(popup, 0, 0, NULL); - popup_set_callback(popup, NULL); - popup_set_context(popup, NULL); - popup_set_timeout(popup, 0); - popup_disable_timeout(popup); -} +#include "../subbrute_i.h" +#include "subbrute_scene.h" + +void subbrute_scene_save_success_on_enter(void* context) { + furi_assert(context); + SubBruteState* instance = context; + + // Setup view + Popup* popup = instance->popup; + popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); + popup_set_header(popup, "Saved!", 13, 22, AlignLeft, AlignBottom); + popup_set_timeout(popup, 1500); + popup_set_context(popup, instance); + popup_set_callback(popup, subbrute_popup_closed_callback); + popup_enable_timeout(popup); + view_dispatcher_switch_to_view(instance->view_dispatcher, SubBruteViewPopup); +} + +bool subbrute_scene_save_success_on_event(void* context, SceneManagerEvent event) { + furi_assert(context); + + SubBruteState* instance = (SubBruteState*)context; + //SubBruteMainView* view = instance->view_main; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubBruteCustomEventTypePopupClosed) { + if(!scene_manager_search_and_switch_to_previous_scene( + instance->scene_manager, SubBruteSceneSetupAttack)) { + scene_manager_next_scene(instance->scene_manager, SubBruteSceneStart); + } + return true; + } + } + return false; +} + +void subbrute_scene_save_success_on_exit(void* context) { + furi_assert(context); + + SubBruteState* instance = (SubBruteState*)context; + + // Clear view + Popup* popup = instance->popup; + popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom); + popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop); + popup_set_icon(popup, 0, 0, NULL); + popup_set_callback(popup, NULL); + popup_set_context(popup, NULL); + popup_set_timeout(popup, 0); + popup_disable_timeout(popup); +} diff --git a/scenes/subbrute_scene_setup_attack.c b/scenes/subbrute_scene_setup_attack.c index c2877c7cb6f..fe507b14179 100644 --- a/scenes/subbrute_scene_setup_attack.c +++ b/scenes/subbrute_scene_setup_attack.c @@ -1,138 +1,140 @@ -#include "../subbrute_i.h" -#include "subbrute_scene.h" - -#define TAG "SubBruteSceneSetupAttack" - -static void subbrute_scene_setup_attack_callback(SubBruteCustomEvent event, void* context) { - furi_assert(context); - - SubBruteState* instance = (SubBruteState*)context; - view_dispatcher_send_custom_event(instance->view_dispatcher, event); -} - -static void - subbrute_scene_setup_attack_device_state_changed(void* context, SubBruteWorkerState state) { - furi_assert(context); - - SubBruteState* instance = (SubBruteState*)context; - - if(state == SubBruteWorkerStateIDLE) { - // Can't be IDLE on this step! - view_dispatcher_send_custom_event(instance->view_dispatcher, SubBruteCustomEventTypeError); - } -} - -void subbrute_scene_setup_attack_on_enter(void* context) { - furi_assert(context); - SubBruteState* instance = (SubBruteState*)context; - SubBruteAttackView* view = instance->view_attack; - - notification_message(instance->notifications, &sequence_reset_vibro); - -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "Enter Attack: %s", subbrute_protocol_name(instance->device->attack)); -#endif - - subbrute_worker_set_callback( - instance->worker, subbrute_scene_setup_attack_device_state_changed, context); - if(subbrute_worker_is_running(instance->worker)) { - subbrute_worker_stop(instance->worker); - instance->device->current_step = subbrute_worker_get_step(instance->worker); - } - - subbrute_attack_view_init_values( - view, - instance->device->attack, - instance->device->max_value, - instance->device->current_step, - false, - instance->device->extra_repeats); - - instance->current_view = SubBruteViewAttack; - subbrute_attack_view_set_callback(view, subbrute_scene_setup_attack_callback, instance); - view_dispatcher_switch_to_view(instance->view_dispatcher, instance->current_view); -} - -void subbrute_scene_setup_attack_on_exit(void* context) { - furi_assert(context); -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "subbrute_scene_setup_attack_on_exit"); -#endif - SubBruteState* instance = (SubBruteState*)context; - subbrute_worker_stop(instance->worker); - notification_message(instance->notifications, &sequence_blink_stop); - notification_message(instance->notifications, &sequence_reset_vibro); -} - -bool subbrute_scene_setup_attack_on_event(void* context, SceneManagerEvent event) { - SubBruteState* instance = (SubBruteState*)context; - SubBruteAttackView* view = instance->view_attack; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == SubBruteCustomEventTypeTransmitStarted) { - scene_manager_next_scene(instance->scene_manager, SubBruteSceneRunAttack); - } else if(event.event == SubBruteCustomEventTypeSaveFile) { - subbrute_attack_view_init_values( - view, - instance->device->attack, - instance->device->max_value, - instance->device->current_step, - false, - instance->device->extra_repeats); - scene_manager_next_scene(instance->scene_manager, SubBruteSceneSaveName); - } else if(event.event == SubBruteCustomEventTypeBackPressed) { - subbrute_attack_view_init_values( - view, - instance->device->attack, - instance->device->max_value, - instance->device->current_step, - false, - instance->device->extra_repeats); - scene_manager_next_scene(instance->scene_manager, SubBruteSceneStart); - } else if(event.event == SubBruteCustomEventTypeError) { - notification_message(instance->notifications, &sequence_error); - } else if(event.event == SubBruteCustomEventTypeTransmitCustom) { - // We can transmit only in not working states - if(subbrute_worker_can_manual_transmit(instance->worker)) { - // MANUAL Transmit! - // Blink - notification_message(instance->notifications, &sequence_blink_green_100); - subbrute_worker_transmit_current_key( - instance->worker, instance->device->current_step); - // Stop - notification_message(instance->notifications, &sequence_blink_stop); - } - } else if(event.event == SubBruteCustomEventTypeChangeStepUp) { - // +1 - uint64_t step = subbrute_device_add_step(instance->device, 1); - subbrute_worker_set_step(instance->worker, step); - subbrute_attack_view_set_current_step(view, step); - } else if(event.event == SubBruteCustomEventTypeChangeStepUpMore) { - // +50 - uint64_t step = subbrute_device_add_step(instance->device, 50); - subbrute_worker_set_step(instance->worker, step); - subbrute_attack_view_set_current_step(view, step); - } else if(event.event == SubBruteCustomEventTypeChangeStepDown) { - // -1 - uint64_t step = subbrute_device_add_step(instance->device, -1); - subbrute_worker_set_step(instance->worker, step); - subbrute_attack_view_set_current_step(view, step); - } else if(event.event == SubBruteCustomEventTypeChangeStepDownMore) { - // -50 - uint64_t step = subbrute_device_add_step(instance->device, -50); - subbrute_worker_set_step(instance->worker, step); - subbrute_attack_view_set_current_step(view, step); - } - - consumed = true; - } else if(event.type == SceneManagerEventTypeTick) { - if(subbrute_worker_is_running(instance->worker)) { - instance->device->current_step = subbrute_worker_get_step(instance->worker); - } - subbrute_attack_view_set_current_step(view, instance->device->current_step); - consumed = true; - } - - return consumed; -} +#include "../subbrute_i.h" +#include "subbrute_scene.h" + +#define TAG "SubBruteSceneSetupAttack" + +static void subbrute_scene_setup_attack_callback(SubBruteCustomEvent event, void* context) { + furi_assert(context); + + SubBruteState* instance = (SubBruteState*)context; + view_dispatcher_send_custom_event(instance->view_dispatcher, event); +} + +static void + subbrute_scene_setup_attack_device_state_changed(void* context, SubBruteWorkerState state) { + furi_assert(context); + + SubBruteState* instance = (SubBruteState*)context; + + if(state == SubBruteWorkerStateIDLE) { + // Can't be IDLE on this step! + view_dispatcher_send_custom_event(instance->view_dispatcher, SubBruteCustomEventTypeError); + } +} + +void subbrute_scene_setup_attack_on_enter(void* context) { + furi_assert(context); + SubBruteState* instance = (SubBruteState*)context; + SubBruteAttackView* view = instance->view_attack; + + notification_message(instance->notifications, &sequence_reset_vibro); + +#ifdef FURI_DEBUG + FURI_LOG_D(TAG, "Enter Attack: %s", subbrute_protocol_name(instance->device->attack)); +#endif + + subbrute_worker_set_callback( + instance->worker, subbrute_scene_setup_attack_device_state_changed, context); + if(subbrute_worker_is_running(instance->worker)) { + subbrute_worker_stop(instance->worker); + instance->device->current_step = subbrute_worker_get_step(instance->worker); + } + + subbrute_attack_view_init_values( + view, + instance->device->attack, + instance->device->max_value, + instance->device->current_step, + false, + instance->device->extra_repeats); + + instance->current_view = SubBruteViewAttack; + subbrute_attack_view_set_callback(view, subbrute_scene_setup_attack_callback, instance); + view_dispatcher_switch_to_view(instance->view_dispatcher, instance->current_view); +} + +void subbrute_scene_setup_attack_on_exit(void* context) { + furi_assert(context); +#ifdef FURI_DEBUG + FURI_LOG_D(TAG, "subbrute_scene_setup_attack_on_exit"); +#endif + SubBruteState* instance = (SubBruteState*)context; + subbrute_worker_stop(instance->worker); + notification_message(instance->notifications, &sequence_blink_stop); + notification_message(instance->notifications, &sequence_reset_vibro); +} + +bool subbrute_scene_setup_attack_on_event(void* context, SceneManagerEvent event) { + SubBruteState* instance = (SubBruteState*)context; + SubBruteAttackView* view = instance->view_attack; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubBruteCustomEventTypeTransmitStarted) { + scene_manager_next_scene(instance->scene_manager, SubBruteSceneRunAttack); + } else if(event.event == SubBruteCustomEventTypeSaveFile) { + subbrute_attack_view_init_values( + view, + instance->device->attack, + instance->device->max_value, + instance->device->current_step, + false, + instance->device->extra_repeats); + scene_manager_next_scene(instance->scene_manager, SubBruteSceneSaveName); + } else if(event.event == SubBruteCustomEventTypeExtraSettings) { + scene_manager_next_scene(instance->scene_manager, SubBruteSceneSetupExtra); + } else if(event.event == SubBruteCustomEventTypeBackPressed) { + subbrute_attack_view_init_values( + view, + instance->device->attack, + instance->device->max_value, + instance->device->current_step, + false, + instance->device->extra_repeats); + scene_manager_next_scene(instance->scene_manager, SubBruteSceneStart); + } else if(event.event == SubBruteCustomEventTypeError) { + notification_message(instance->notifications, &sequence_error); + } else if(event.event == SubBruteCustomEventTypeTransmitCustom) { + // We can transmit only in not working states + if(subbrute_worker_can_manual_transmit(instance->worker)) { + // MANUAL Transmit! + // Blink + notification_message(instance->notifications, &sequence_blink_green_100); + subbrute_worker_transmit_current_key( + instance->worker, instance->device->current_step); + // Stop + notification_message(instance->notifications, &sequence_blink_stop); + } + } else if(event.event == SubBruteCustomEventTypeChangeStepUp) { + // +1 + uint64_t step = subbrute_device_add_step(instance->device, 1); + subbrute_worker_set_step(instance->worker, step); + subbrute_attack_view_set_current_step(view, step); + } else if(event.event == SubBruteCustomEventTypeChangeStepUpMore) { + // +50 + uint64_t step = subbrute_device_add_step(instance->device, 50); + subbrute_worker_set_step(instance->worker, step); + subbrute_attack_view_set_current_step(view, step); + } else if(event.event == SubBruteCustomEventTypeChangeStepDown) { + // -1 + uint64_t step = subbrute_device_add_step(instance->device, -1); + subbrute_worker_set_step(instance->worker, step); + subbrute_attack_view_set_current_step(view, step); + } else if(event.event == SubBruteCustomEventTypeChangeStepDownMore) { + // -50 + uint64_t step = subbrute_device_add_step(instance->device, -50); + subbrute_worker_set_step(instance->worker, step); + subbrute_attack_view_set_current_step(view, step); + } + + consumed = true; + } else if(event.type == SceneManagerEventTypeTick) { + if(subbrute_worker_is_running(instance->worker)) { + instance->device->current_step = subbrute_worker_get_step(instance->worker); + } + subbrute_attack_view_set_current_step(view, instance->device->current_step); + consumed = true; + } + + return consumed; +} diff --git a/scenes/subbrute_scene_setup_extra.c b/scenes/subbrute_scene_setup_extra.c new file mode 100644 index 00000000000..21d073cc813 --- /dev/null +++ b/scenes/subbrute_scene_setup_extra.c @@ -0,0 +1,66 @@ +#include "../subbrute_i.h" +#include "subbrute_scene.h" + +#define TAG "SubBruteSceneLoadFile" + +void setup_extra_widget_callback(GuiButtonType result, InputType type, void* context); + +static void setup_extra_widget_draw(void* context) { + furi_assert(context); + SubBruteState* instance = context; + + Widget* widget = instance->widget; + + widget_add_button_element( + widget, GuiButtonTypeLeft, "-TD", setup_extra_widget_callback, instance); + widget_add_button_element( + widget, GuiButtonTypeRight, "TD+", setup_extra_widget_callback, instance); + + char str[20]; + snprintf(&str[0], 20, "%d", subbrute_worker_get_timeout(instance->worker)); + + widget_add_string_element( + instance->widget, 64, 15, AlignCenter, AlignCenter, FontPrimary, "Time Delay"); + + widget_add_string_element( + instance->widget, 64, 32, AlignCenter, AlignCenter, FontBigNumbers, &str[0]); +} + +void setup_extra_widget_callback(GuiButtonType result, InputType type, void* context) { + furi_assert(context); + SubBruteState* instance = context; + + if((result == GuiButtonTypeLeft) && ((type == InputTypeShort) || (type == InputTypeRepeat))) { + widget_reset(instance->widget); + subbrute_worker_timeout_dec(instance->worker); + setup_extra_widget_draw(instance); + } else if( + (result == GuiButtonTypeRight) && + ((type == InputTypeShort) || (type == InputTypeRepeat))) { + widget_reset(instance->widget); + subbrute_worker_timeout_inc(instance->worker); + setup_extra_widget_draw(instance); + } +} + +void subbrute_scene_setup_extra_on_enter(void* context) { + furi_assert(context); + SubBruteState* instance = context; + + setup_extra_widget_draw(instance); + + view_dispatcher_switch_to_view(instance->view_dispatcher, SubBruteViewWidget); +} + +void subbrute_scene_setup_extra_on_exit(void* context) { + furi_assert(context); + SubBruteState* instance = context; + + widget_reset(instance->widget); +} + +bool subbrute_scene_setup_extra_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + UNUSED(event); + return false; +} \ No newline at end of file diff --git a/scenes/subbrute_scene_start.c b/scenes/subbrute_scene_start.c index 256762d920e..42ce529e0eb 100644 --- a/scenes/subbrute_scene_start.c +++ b/scenes/subbrute_scene_start.c @@ -1,89 +1,89 @@ -#include "../subbrute_i.h" -#include "subbrute_scene.h" - -#define TAG "SubBruteSceneStart" - -void subbrute_scene_start_callback(SubBruteCustomEvent event, void* context) { - furi_assert(context); - - SubBruteState* instance = (SubBruteState*)context; -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "subbrute_scene_start_callback"); -#endif - view_dispatcher_send_custom_event(instance->view_dispatcher, event); -} - -void subbrute_scene_start_on_enter(void* context) { - furi_assert(context); -#ifdef FURI_DEBUG - FURI_LOG_I(TAG, "subbrute_scene_start_on_enter"); -#endif - SubBruteState* instance = (SubBruteState*)context; - SubBruteMainView* view = instance->view_main; - - instance->current_view = SubBruteViewMain; - subbrute_main_view_set_callback(view, subbrute_scene_start_callback, instance); - subbrute_main_view_set_index( - view, instance->device->attack, false, instance->device->two_bytes, 0); - - view_dispatcher_switch_to_view(instance->view_dispatcher, instance->current_view); - - // TODO: DELETE IT -#ifdef SUBBRUTE_FAST_TRACK - scene_manager_next_scene(instance->scene_manager, SubBruteSceneLoadFile); -#endif -} - -void subbrute_scene_start_on_exit(void* context) { - UNUSED(context); -#ifdef FURI_DEBUG - FURI_LOG_I(TAG, "subbrute_scene_start_on_exit"); -#endif -} - -bool subbrute_scene_start_on_event(void* context, SceneManagerEvent event) { - SubBruteState* instance = (SubBruteState*)context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { -#ifdef FURI_DEBUG - FURI_LOG_D( - TAG, - "Event: %ld, SubBruteCustomEventTypeMenuSelected: %s, SubBruteCustomEventTypeLoadFile: %s", - event.event, - event.event == SubBruteCustomEventTypeMenuSelected ? "true" : "false", - event.event == SubBruteCustomEventTypeLoadFile ? "true" : "false"); -#endif - if(event.event == SubBruteCustomEventTypeMenuSelected) { - SubBruteAttacks attack = subbrute_main_view_get_index(instance->view_main); - uint8_t extra_repeats = subbrute_main_view_get_extra_repeats(instance->view_main); - - if((subbrute_device_attack_set(instance->device, attack, extra_repeats) != - SubBruteFileResultOk) || - (!subbrute_worker_init_default_attack( - instance->worker, - attack, - instance->device->current_step, - instance->device->protocol_info, - instance->device->extra_repeats))) { - furi_crash("Invalid attack set!"); - } - scene_manager_next_scene(instance->scene_manager, SubBruteSceneSetupAttack); - - consumed = true; - } else if(event.event == SubBruteCustomEventTypeLoadFile) { - //uint8_t extra_repeats = subbrute_main_view_get_extra_repeats(instance->view_main); - - //instance->device->extra_repeats = extra_repeats; - scene_manager_next_scene(instance->scene_manager, SubBruteSceneLoadFile); - consumed = true; - } - } else if(event.type == SceneManagerEventTypeBack) { - //exit app - scene_manager_stop(instance->scene_manager); - view_dispatcher_stop(instance->view_dispatcher); - consumed = true; - } - - return consumed; +#include "../subbrute_i.h" +#include "subbrute_scene.h" + +#define TAG "SubBruteSceneStart" + +void subbrute_scene_start_callback(SubBruteCustomEvent event, void* context) { + furi_assert(context); + + SubBruteState* instance = (SubBruteState*)context; +#ifdef FURI_DEBUG + FURI_LOG_D(TAG, "subbrute_scene_start_callback"); +#endif + view_dispatcher_send_custom_event(instance->view_dispatcher, event); +} + +void subbrute_scene_start_on_enter(void* context) { + furi_assert(context); +#ifdef FURI_DEBUG + FURI_LOG_I(TAG, "subbrute_scene_start_on_enter"); +#endif + SubBruteState* instance = (SubBruteState*)context; + SubBruteMainView* view = instance->view_main; + + instance->current_view = SubBruteViewMain; + subbrute_main_view_set_callback(view, subbrute_scene_start_callback, instance); + subbrute_main_view_set_index( + view, instance->device->attack, false, instance->device->two_bytes, 0); + + view_dispatcher_switch_to_view(instance->view_dispatcher, instance->current_view); + + // TODO: DELETE IT +#ifdef SUBBRUTE_FAST_TRACK + scene_manager_next_scene(instance->scene_manager, SubBruteSceneLoadFile); +#endif +} + +void subbrute_scene_start_on_exit(void* context) { + UNUSED(context); +#ifdef FURI_DEBUG + FURI_LOG_I(TAG, "subbrute_scene_start_on_exit"); +#endif +} + +bool subbrute_scene_start_on_event(void* context, SceneManagerEvent event) { + SubBruteState* instance = (SubBruteState*)context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { +#ifdef FURI_DEBUG + FURI_LOG_D( + TAG, + "Event: %ld, SubBruteCustomEventTypeMenuSelected: %s, SubBruteCustomEventTypeLoadFile: %s", + event.event, + event.event == SubBruteCustomEventTypeMenuSelected ? "true" : "false", + event.event == SubBruteCustomEventTypeLoadFile ? "true" : "false"); +#endif + if(event.event == SubBruteCustomEventTypeMenuSelected) { + SubBruteAttacks attack = subbrute_main_view_get_index(instance->view_main); + uint8_t extra_repeats = subbrute_main_view_get_extra_repeats(instance->view_main); + + if((subbrute_device_attack_set(instance->device, attack, extra_repeats) != + SubBruteFileResultOk) || + (!subbrute_worker_init_default_attack( + instance->worker, + attack, + instance->device->current_step, + instance->device->protocol_info, + instance->device->extra_repeats))) { + furi_crash("Invalid attack set!"); + } + scene_manager_next_scene(instance->scene_manager, SubBruteSceneSetupAttack); + + consumed = true; + } else if(event.event == SubBruteCustomEventTypeLoadFile) { + //uint8_t extra_repeats = subbrute_main_view_get_extra_repeats(instance->view_main); + + //instance->device->extra_repeats = extra_repeats; + scene_manager_next_scene(instance->scene_manager, SubBruteSceneLoadFile); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeBack) { + //exit app + scene_manager_stop(instance->scene_manager); + view_dispatcher_stop(instance->view_dispatcher); + consumed = true; + } + + return consumed; } \ No newline at end of file diff --git a/scenes/subbute_scene.c b/scenes/subbute_scene.c index 6d9ba9799a1..69b041d076e 100644 --- a/scenes/subbute_scene.c +++ b/scenes/subbute_scene.c @@ -1,30 +1,30 @@ -#include "subbrute_scene.h" - -// Generate scene on_enter handlers array -#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter, -void (*const subbrute_on_enter_handlers[])(void*) = { -#include "subbrute_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 subbrute_on_event_handlers[])(void* context, SceneManagerEvent event) = { -#include "subbrute_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 subbrute_on_exit_handlers[])(void* context) = { -#include "subbrute_scene_config.h" -}; -#undef ADD_SCENE - -// Initialize scene handlers configuration structure -const SceneManagerHandlers subbrute_scene_handlers = { - .on_enter_handlers = subbrute_on_enter_handlers, - .on_event_handlers = subbrute_on_event_handlers, - .on_exit_handlers = subbrute_on_exit_handlers, - .scene_num = SubBruteSceneNum, -}; +#include "subbrute_scene.h" + +// Generate scene on_enter handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter, +void (*const subbrute_on_enter_handlers[])(void*) = { +#include "subbrute_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 subbrute_on_event_handlers[])(void* context, SceneManagerEvent event) = { +#include "subbrute_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 subbrute_on_exit_handlers[])(void* context) = { +#include "subbrute_scene_config.h" +}; +#undef ADD_SCENE + +// Initialize scene handlers configuration structure +const SceneManagerHandlers subbrute_scene_handlers = { + .on_enter_handlers = subbrute_on_enter_handlers, + .on_event_handlers = subbrute_on_event_handlers, + .on_exit_handlers = subbrute_on_exit_handlers, + .scene_num = SubBruteSceneNum, +}; diff --git a/subbrute.c b/subbrute.c index 0bf322bbdfe..d60cf21b827 100644 --- a/subbrute.c +++ b/subbrute.c @@ -1,200 +1,209 @@ -#include "subbrute_i.h" -#include "subbrute_custom_event.h" -#include "scenes/subbrute_scene.h" - -#define TAG "SubBruteApp" - -static bool subbrute_custom_event_callback(void* context, uint32_t event) { - furi_assert(context); - SubBruteState* instance = context; - return scene_manager_handle_custom_event(instance->scene_manager, event); -} - -static bool subbrute_back_event_callback(void* context) { - furi_assert(context); - SubBruteState* instance = context; - return scene_manager_handle_back_event(instance->scene_manager); -} - -static void subbrute_tick_event_callback(void* context) { - furi_assert(context); - SubBruteState* instance = context; - scene_manager_handle_tick_event(instance->scene_manager); -} - -SubBruteState* subbrute_alloc() { - SubBruteState* instance = malloc(sizeof(SubBruteState)); - - memset(instance->text_store, 0, sizeof(instance->text_store)); - instance->file_path = furi_string_alloc(); - - instance->scene_manager = scene_manager_alloc(&subbrute_scene_handlers, instance); - instance->view_dispatcher = view_dispatcher_alloc(); - - instance->gui = furi_record_open(RECORD_GUI); - - view_dispatcher_enable_queue(instance->view_dispatcher); - view_dispatcher_set_event_callback_context(instance->view_dispatcher, instance); - view_dispatcher_set_custom_event_callback( - instance->view_dispatcher, subbrute_custom_event_callback); - view_dispatcher_set_navigation_event_callback( - instance->view_dispatcher, subbrute_back_event_callback); - view_dispatcher_set_tick_event_callback( - instance->view_dispatcher, subbrute_tick_event_callback, 100); - - //Dialog - instance->dialogs = furi_record_open(RECORD_DIALOGS); - - // Notifications - instance->notifications = furi_record_open(RECORD_NOTIFICATION); - - // Devices - instance->device = subbrute_device_alloc(); - - // SubBruteWorker - instance->worker = subbrute_worker_alloc(); - - // TextInput - instance->text_input = text_input_alloc(); - view_dispatcher_add_view( - instance->view_dispatcher, - SubBruteViewTextInput, - text_input_get_view(instance->text_input)); - - // Custom Widget - instance->widget = widget_alloc(); - view_dispatcher_add_view( - instance->view_dispatcher, SubBruteViewWidget, widget_get_view(instance->widget)); - - // Popup - instance->popup = popup_alloc(); - view_dispatcher_add_view( - instance->view_dispatcher, SubBruteViewPopup, popup_get_view(instance->popup)); - - // ViewStack - instance->view_stack = view_stack_alloc(); - view_dispatcher_add_view( - instance->view_dispatcher, SubBruteViewStack, view_stack_get_view(instance->view_stack)); - - // SubBruteMainView - instance->view_main = subbrute_main_view_alloc(); - view_dispatcher_add_view( - instance->view_dispatcher, - SubBruteViewMain, - subbrute_main_view_get_view(instance->view_main)); - - // SubBruteAttackView - instance->view_attack = subbrute_attack_view_alloc(); - view_dispatcher_add_view( - instance->view_dispatcher, - SubBruteViewAttack, - subbrute_attack_view_get_view(instance->view_attack)); - - //instance->flipper_format = flipper_format_string_alloc(); - //instance->environment = subghz_environment_alloc(); - - return instance; -} - -void subbrute_free(SubBruteState* instance) { - furi_assert(instance); - - // SubBruteWorker - subbrute_worker_stop(instance->worker); - subbrute_worker_free(instance->worker); - - // SubBruteDevice - subbrute_device_free(instance->device); - - // Notifications - notification_message(instance->notifications, &sequence_blink_stop); - furi_record_close(RECORD_NOTIFICATION); - instance->notifications = NULL; - - // View Main - view_dispatcher_remove_view(instance->view_dispatcher, SubBruteViewMain); - subbrute_main_view_free(instance->view_main); - - // View Attack - view_dispatcher_remove_view(instance->view_dispatcher, SubBruteViewAttack); - subbrute_attack_view_free(instance->view_attack); - - // TextInput - view_dispatcher_remove_view(instance->view_dispatcher, SubBruteViewTextInput); - text_input_free(instance->text_input); - - // Custom Widget - view_dispatcher_remove_view(instance->view_dispatcher, SubBruteViewWidget); - widget_free(instance->widget); - - // Popup - view_dispatcher_remove_view(instance->view_dispatcher, SubBruteViewPopup); - popup_free(instance->popup); - - // ViewStack - view_dispatcher_remove_view(instance->view_dispatcher, SubBruteViewStack); - view_stack_free(instance->view_stack); - - //Dialog - furi_record_close(RECORD_DIALOGS); - instance->dialogs = NULL; - - // Scene manager - scene_manager_free(instance->scene_manager); - - // View Dispatcher - view_dispatcher_free(instance->view_dispatcher); - - // GUI - furi_record_close(RECORD_GUI); - instance->gui = NULL; - - furi_string_free(instance->file_path); - - // The rest - free(instance); -} - -void subbrute_text_input_callback(void* context) { - furi_assert(context); - SubBruteState* instance = context; - view_dispatcher_send_custom_event( - instance->view_dispatcher, SubBruteCustomEventTypeTextEditDone); -} - -void subbrute_popup_closed_callback(void* context) { - furi_assert(context); - SubBruteState* instance = context; - view_dispatcher_send_custom_event( - instance->view_dispatcher, SubBruteCustomEventTypePopupClosed); -} - -// ENTRYPOINT -int32_t subbrute_app(void* p) { - UNUSED(p); - - SubBruteState* instance = subbrute_alloc(); - view_dispatcher_attach_to_gui( - instance->view_dispatcher, instance->gui, ViewDispatcherTypeFullscreen); - scene_manager_next_scene(instance->scene_manager, SubBruteSceneStart); - - // Enable power for External CC1101 if it is connected - furi_hal_subghz_enable_ext_power(); - // Auto switch to internal radio if external radio is not available - furi_delay_ms(15); - if(!furi_hal_subghz_check_radio()) { - furi_hal_subghz_set_radio_type(SubGhzRadioInternal); - } - - furi_hal_power_suppress_charge_enter(); - - notification_message(instance->notifications, &sequence_display_backlight_on); - view_dispatcher_run(instance->view_dispatcher); - furi_hal_power_suppress_charge_exit(); - // Disable power for External CC1101 if it was enabled and module is connected - furi_hal_subghz_disable_ext_power(); - - subbrute_free(instance); - - return 0; +#include "subbrute_i.h" +#include "subbrute_custom_event.h" +#include "scenes/subbrute_scene.h" + +#define TAG "SubBruteApp" + +static bool subbrute_custom_event_callback(void* context, uint32_t event) { + furi_assert(context); + SubBruteState* instance = context; + return scene_manager_handle_custom_event(instance->scene_manager, event); +} + +static bool subbrute_back_event_callback(void* context) { + furi_assert(context); + SubBruteState* instance = context; + return scene_manager_handle_back_event(instance->scene_manager); +} + +static void subbrute_tick_event_callback(void* context) { + furi_assert(context); + SubBruteState* instance = context; + scene_manager_handle_tick_event(instance->scene_manager); +} + +SubBruteState* subbrute_alloc() { + SubBruteState* instance = malloc(sizeof(SubBruteState)); + + memset(instance->text_store, 0, sizeof(instance->text_store)); + instance->file_path = furi_string_alloc(); + + instance->scene_manager = scene_manager_alloc(&subbrute_scene_handlers, instance); + instance->view_dispatcher = view_dispatcher_alloc(); + + instance->gui = furi_record_open(RECORD_GUI); + + view_dispatcher_enable_queue(instance->view_dispatcher); + view_dispatcher_set_event_callback_context(instance->view_dispatcher, instance); + view_dispatcher_set_custom_event_callback( + instance->view_dispatcher, subbrute_custom_event_callback); + view_dispatcher_set_navigation_event_callback( + instance->view_dispatcher, subbrute_back_event_callback); + view_dispatcher_set_tick_event_callback( + instance->view_dispatcher, subbrute_tick_event_callback, 100); + + //Dialog + instance->dialogs = furi_record_open(RECORD_DIALOGS); + + // Notifications + instance->notifications = furi_record_open(RECORD_NOTIFICATION); + + // Devices + instance->device = subbrute_device_alloc(); + + // SubBruteWorker + instance->worker = subbrute_worker_alloc(); + + // TextInput + instance->text_input = text_input_alloc(); + view_dispatcher_add_view( + instance->view_dispatcher, + SubBruteViewTextInput, + text_input_get_view(instance->text_input)); + + // Custom Widget + instance->widget = widget_alloc(); + view_dispatcher_add_view( + instance->view_dispatcher, SubBruteViewWidget, widget_get_view(instance->widget)); + + // Popup + instance->popup = popup_alloc(); + view_dispatcher_add_view( + instance->view_dispatcher, SubBruteViewPopup, popup_get_view(instance->popup)); + + // ViewStack + instance->view_stack = view_stack_alloc(); + view_dispatcher_add_view( + instance->view_dispatcher, SubBruteViewStack, view_stack_get_view(instance->view_stack)); + + // SubBruteMainView + instance->view_main = subbrute_main_view_alloc(); + view_dispatcher_add_view( + instance->view_dispatcher, + SubBruteViewMain, + subbrute_main_view_get_view(instance->view_main)); + + // SubBruteAttackView + instance->view_attack = subbrute_attack_view_alloc(); + view_dispatcher_add_view( + instance->view_dispatcher, + SubBruteViewAttack, + subbrute_attack_view_get_view(instance->view_attack)); + + //instance->flipper_format = flipper_format_string_alloc(); + //instance->environment = subghz_environment_alloc(); + + // Uncomment to enable Debug pin output on PIN 17(1W) + //furi_hal_subghz_set_async_mirror_pin(&gpio_ibutton); + + return instance; +} + +void subbrute_free(SubBruteState* instance) { + furi_assert(instance); + + // Uncomment to enable Debug pin output on PIN 17(1W) + //furi_hal_subghz_set_async_mirror_pin(NULL); + + // SubBruteWorker + subbrute_worker_stop(instance->worker); + subbrute_worker_free(instance->worker); + + // SubBruteDevice + subbrute_device_free(instance->device); + + // Notifications + notification_message(instance->notifications, &sequence_blink_stop); + furi_record_close(RECORD_NOTIFICATION); + instance->notifications = NULL; + + // View Main + view_dispatcher_remove_view(instance->view_dispatcher, SubBruteViewMain); + subbrute_main_view_free(instance->view_main); + + // View Attack + view_dispatcher_remove_view(instance->view_dispatcher, SubBruteViewAttack); + subbrute_attack_view_free(instance->view_attack); + + // TextInput + view_dispatcher_remove_view(instance->view_dispatcher, SubBruteViewTextInput); + text_input_free(instance->text_input); + + // Custom Widget + view_dispatcher_remove_view(instance->view_dispatcher, SubBruteViewWidget); + widget_free(instance->widget); + + // Popup + view_dispatcher_remove_view(instance->view_dispatcher, SubBruteViewPopup); + popup_free(instance->popup); + + // ViewStack + view_dispatcher_remove_view(instance->view_dispatcher, SubBruteViewStack); + view_stack_free(instance->view_stack); + + //Dialog + furi_record_close(RECORD_DIALOGS); + instance->dialogs = NULL; + + // Scene manager + scene_manager_free(instance->scene_manager); + + // View Dispatcher + view_dispatcher_free(instance->view_dispatcher); + + // GUI + furi_record_close(RECORD_GUI); + instance->gui = NULL; + + furi_string_free(instance->file_path); + + // The rest + free(instance); +} + +void subbrute_text_input_callback(void* context) { + furi_assert(context); + SubBruteState* instance = context; + view_dispatcher_send_custom_event( + instance->view_dispatcher, SubBruteCustomEventTypeTextEditDone); +} + +void subbrute_popup_closed_callback(void* context) { + furi_assert(context); + SubBruteState* instance = context; + view_dispatcher_send_custom_event( + instance->view_dispatcher, SubBruteCustomEventTypePopupClosed); +} + +// ENTRYPOINT +int32_t subbrute_app(void* p) { + UNUSED(p); + + SubBruteState* instance = subbrute_alloc(); + view_dispatcher_attach_to_gui( + instance->view_dispatcher, instance->gui, ViewDispatcherTypeFullscreen); + scene_manager_next_scene(instance->scene_manager, SubBruteSceneStart); + + // Enable power for External CC1101 if it is connected + furi_hal_subghz_enable_ext_power(); + // Auto switch to internal radio if external radio is not available + furi_delay_ms(15); + if(!furi_hal_subghz_check_radio()) { + furi_hal_subghz_select_radio_type(SubGhzRadioInternal); + furi_hal_subghz_init_radio_type(SubGhzRadioInternal); + } + + furi_hal_power_suppress_charge_enter(); + + notification_message(instance->notifications, &sequence_display_backlight_on); + view_dispatcher_run(instance->view_dispatcher); + furi_hal_power_suppress_charge_exit(); + // Disable power for External CC1101 if it was enabled and module is connected + furi_hal_subghz_disable_ext_power(); + // Reinit SPI handles for internal radio / nfc + furi_hal_subghz_init_radio_type(SubGhzRadioInternal); + + subbrute_free(instance); + + return 0; } \ No newline at end of file diff --git a/subbrute.h b/subbrute.h index 5fedb915823..1e08448f119 100644 --- a/subbrute.h +++ b/subbrute.h @@ -1,3 +1,3 @@ -#pragma once - +#pragma once + typedef struct SubBruteState SubBruteState; \ No newline at end of file diff --git a/subbrute_custom_event.h b/subbrute_custom_event.h index 2864f893416..b9fe00db27d 100644 --- a/subbrute_custom_event.h +++ b/subbrute_custom_event.h @@ -1,26 +1,27 @@ -#pragma once - -typedef enum { - // Reserve first 100 events for button types and indexes, starting from 0 - SubBruteCustomEventTypeReserved = 100, - - SubBruteCustomEventTypeBackPressed, - SubBruteCustomEventTypeIndexSelected, - SubBruteCustomEventTypeTransmitStarted, - SubBruteCustomEventTypeError, - SubBruteCustomEventTypeTransmitFinished, - SubBruteCustomEventTypeTransmitNotStarted, - SubBruteCustomEventTypeTransmitCustom, - SubBruteCustomEventTypeSaveFile, - SubBruteCustomEventTypeUpdateView, - SubBruteCustomEventTypeChangeStepUp, - SubBruteCustomEventTypeChangeStepDown, - SubBruteCustomEventTypeChangeStepUpMore, - SubBruteCustomEventTypeChangeStepDownMore, - - SubBruteCustomEventTypeMenuSelected, - SubBruteCustomEventTypeTextEditDone, - SubBruteCustomEventTypePopupClosed, - - SubBruteCustomEventTypeLoadFile, +#pragma once + +typedef enum { + // Reserve first 100 events for button types and indexes, starting from 0 + SubBruteCustomEventTypeReserved = 100, + + SubBruteCustomEventTypeBackPressed, + SubBruteCustomEventTypeIndexSelected, + SubBruteCustomEventTypeTransmitStarted, + SubBruteCustomEventTypeError, + SubBruteCustomEventTypeTransmitFinished, + SubBruteCustomEventTypeTransmitNotStarted, + SubBruteCustomEventTypeTransmitCustom, + SubBruteCustomEventTypeSaveFile, + SubBruteCustomEventTypeExtraSettings, + SubBruteCustomEventTypeUpdateView, + SubBruteCustomEventTypeChangeStepUp, + SubBruteCustomEventTypeChangeStepDown, + SubBruteCustomEventTypeChangeStepUpMore, + SubBruteCustomEventTypeChangeStepDownMore, + + SubBruteCustomEventTypeMenuSelected, + SubBruteCustomEventTypeTextEditDone, + SubBruteCustomEventTypePopupClosed, + + SubBruteCustomEventTypeLoadFile, } SubBruteCustomEvent; \ No newline at end of file diff --git a/subbrute_device.c b/subbrute_device.c index 0971c380ed3..4ef21ad8baf 100644 --- a/subbrute_device.c +++ b/subbrute_device.c @@ -1,460 +1,458 @@ -#include "subbrute_device.h" - -#include -#include -#include -#include -#include -#include - -#define TAG "SubBruteDevice" - -SubBruteDevice* subbrute_device_alloc() { - SubBruteDevice* instance = malloc(sizeof(SubBruteDevice)); - - instance->current_step = 0; - - instance->protocol_info = NULL; - instance->file_protocol_info = NULL; - instance->decoder_result = NULL; - instance->receiver = NULL; - instance->environment = subghz_environment_alloc(); - subghz_environment_set_protocol_registry( - instance->environment, (void*)&subghz_protocol_registry); - -#ifdef FURI_DEBUG - subbrute_device_attack_set_default_values(instance, SubBruteAttackLoadFile); -#else - subbrute_device_attack_set_default_values(instance, SubBruteAttackCAME12bit433); -#endif - return instance; -} - -void subbrute_device_free(SubBruteDevice* instance) { - furi_assert(instance); - - // I don't know how to free this - instance->decoder_result = NULL; - - if(instance->receiver != NULL) { - subghz_receiver_free(instance->receiver); - instance->receiver = NULL; - } - - subghz_environment_free(instance->environment); - instance->environment = NULL; - - subbrute_device_free_protocol_info(instance); - - free(instance); -} - -uint64_t subbrute_device_add_step(SubBruteDevice* instance, int8_t step) { - if(step > 0) { - if((instance->current_step + step) - instance->max_value == 1) { - instance->current_step = 0x00; - } else { - uint64_t value = instance->current_step + step; - if(value == instance->max_value) { - instance->current_step = value; - } else { - instance->current_step = value % instance->max_value; - } - } - } else { - if(instance->current_step + step == 0) { - instance->current_step = 0x00; - } else if(instance->current_step == 0) { - instance->current_step = instance->max_value; - } else { - uint64_t value = ((instance->current_step + step) + instance->max_value); - if(value == instance->max_value) { - instance->current_step = value; - } else { - instance->current_step = value % instance->max_value; - } - } - } - - return instance->current_step; -} - -bool subbrute_device_save_file(SubBruteDevice* instance, const char* dev_file_name) { - furi_assert(instance); - -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "subbrute_device_save_file: %s", dev_file_name); -#endif - - Storage* storage = furi_record_open(RECORD_STORAGE); - FlipperFormat* file = flipper_format_file_alloc(storage); - bool result = false; - do { - if(!flipper_format_file_open_always(file, dev_file_name)) { - FURI_LOG_E(TAG, "Failed to open file: %s", dev_file_name); - break; - } - Stream* stream = flipper_format_get_raw_stream(file); - if(instance->attack == SubBruteAttackLoadFile) { - subbrute_protocol_file_generate_file( - stream, - instance->file_protocol_info->frequency, - instance->file_protocol_info->preset, - instance->file_protocol_info->file, - instance->current_step, - instance->file_protocol_info->bits, - instance->file_protocol_info->te, - instance->file_protocol_info->repeat, - instance->bit_index, - instance->key_from_file, - instance->two_bytes); - } else { - subbrute_protocol_default_generate_file( - stream, - instance->protocol_info->frequency, - instance->protocol_info->preset, - instance->protocol_info->file, - instance->current_step, - instance->protocol_info->bits, - instance->protocol_info->te, - instance->protocol_info->repeat); - } - - result = true; - } while(false); - - if(!result) { - FURI_LOG_E(TAG, "subbrute_device_save_file failed!"); - } - - flipper_format_file_close(file); - flipper_format_free(file); - furi_record_close(RECORD_STORAGE); - - return result; -} - -SubBruteFileResult subbrute_device_attack_set( - SubBruteDevice* instance, - SubBruteAttacks type, - uint8_t extra_repeats) { - furi_assert(instance); -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "subbrute_device_attack_set: %d, extra_repeats: %d", type, extra_repeats); -#endif - subbrute_device_attack_set_default_values(instance, type); - - if(type != SubBruteAttackLoadFile) { - subbrute_device_free_protocol_info(instance); - instance->protocol_info = subbrute_protocol(type); - } - - instance->extra_repeats = extra_repeats; - - // For non-file types we didn't set SubGhzProtocolDecoderBase - instance->receiver = subghz_receiver_alloc_init(instance->environment); - subghz_receiver_set_filter(instance->receiver, SubGhzProtocolFlag_Decodable); - furi_hal_subghz_reset(); - - uint8_t protocol_check_result = SubBruteFileResultProtocolNotFound; -#ifdef FURI_DEBUG - uint8_t bits; - uint32_t te; - uint8_t repeat; - FuriHalSubGhzPreset preset; - SubBruteFileProtocol file; -#endif - if(type != SubBruteAttackLoadFile) { - instance->decoder_result = subghz_receiver_search_decoder_base_by_name( - instance->receiver, subbrute_protocol_file(instance->protocol_info->file)); - - if(!instance->decoder_result || - instance->decoder_result->protocol->type == SubGhzProtocolTypeDynamic) { - FURI_LOG_E(TAG, "Can't load SubGhzProtocolDecoderBase in phase non-file decoder set"); - } else { - protocol_check_result = SubBruteFileResultOk; - - // Calc max value - instance->max_value = subbrute_protocol_calc_max_value( - instance->attack, instance->protocol_info->bits, instance->two_bytes); - } -#ifdef FURI_DEBUG - bits = instance->protocol_info->bits; - te = instance->protocol_info->te; - repeat = instance->protocol_info->repeat + instance->extra_repeats; - preset = instance->protocol_info->preset; - file = instance->protocol_info->file; -#endif - } else { - // And here we need to set preset enum - protocol_check_result = SubBruteFileResultOk; - - // Calc max value - instance->max_value = subbrute_protocol_calc_max_value( - instance->attack, instance->file_protocol_info->bits, instance->two_bytes); -#ifdef FURI_DEBUG - bits = instance->file_protocol_info->bits; - te = instance->file_protocol_info->te; - repeat = instance->file_protocol_info->repeat + instance->extra_repeats; - preset = instance->file_protocol_info->preset; - file = instance->file_protocol_info->file; -#endif - } - - subghz_receiver_free(instance->receiver); - instance->receiver = NULL; - - if(protocol_check_result != SubBruteFileResultOk) { - return SubBruteFileResultProtocolNotFound; - } - -#ifdef FURI_DEBUG - FURI_LOG_I( - TAG, - "subbrute_device_attack_set: %s, bits: %d, preset: %s, file: %s, te: %ld, repeat: %d, max_value: %lld", - subbrute_protocol_name(instance->attack), - bits, - subbrute_protocol_preset(preset), - subbrute_protocol_file(file), - te, - repeat, - instance->max_value); -#endif - - return SubBruteFileResultOk; -} - -uint8_t subbrute_device_load_from_file(SubBruteDevice* instance, const char* file_path) { - furi_assert(instance); -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "subbrute_device_load_from_file: %s", file_path); -#endif - SubBruteFileResult result = SubBruteFileResultUnknown; - - Storage* storage = furi_record_open(RECORD_STORAGE); - FlipperFormat* fff_data_file = flipper_format_file_alloc(storage); - - subbrute_device_free_protocol_info(instance); - instance->file_protocol_info = malloc(sizeof(SubBruteProtocol)); - - FuriString* temp_str; - temp_str = furi_string_alloc(); - uint32_t temp_data32; - - instance->receiver = subghz_receiver_alloc_init(instance->environment); - subghz_receiver_set_filter(instance->receiver, SubGhzProtocolFlag_Decodable); - furi_hal_subghz_reset(); - - do { - if(!flipper_format_file_open_existing(fff_data_file, file_path)) { - FURI_LOG_E(TAG, "Error open file %s", file_path); - result = SubBruteFileResultErrorOpenFile; - break; - } - if(!flipper_format_read_header(fff_data_file, temp_str, &temp_data32)) { - FURI_LOG_E(TAG, "Missing or incorrect header"); - result = SubBruteFileResultMissingOrIncorrectHeader; - break; - } - - // Frequency - if(!flipper_format_read_uint32(fff_data_file, "Frequency", &temp_data32, 1)) { - FURI_LOG_E(TAG, "Missing or incorrect Frequency"); - result = SubBruteFileResultMissingOrIncorrectFrequency; - break; - } - instance->file_protocol_info->frequency = temp_data32; - if(!furi_hal_subghz_is_tx_allowed(instance->file_protocol_info->frequency)) { - result = SubBruteFileResultFrequencyNotAllowed; - break; - } - - // Preset - if(!flipper_format_read_string(fff_data_file, "Preset", temp_str)) { - FURI_LOG_E(TAG, "Preset FAIL"); - result = SubBruteFileResultPresetInvalid; - break; - } - instance->file_protocol_info->preset = subbrute_protocol_convert_preset(temp_str); - - const char* protocol_file = NULL; - // Protocol - if(!flipper_format_read_string(fff_data_file, "Protocol", temp_str)) { - FURI_LOG_E(TAG, "Missing Protocol"); - result = SubBruteFileResultMissingProtocol; - break; - } - instance->file_protocol_info->file = subbrute_protocol_file_protocol_name(temp_str); - protocol_file = subbrute_protocol_file(instance->file_protocol_info->file); -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "Protocol: %s", protocol_file); -#endif - - instance->decoder_result = subghz_receiver_search_decoder_base_by_name( - instance->receiver, furi_string_get_cstr(temp_str)); - - if((!instance->decoder_result) || (strcmp(protocol_file, "RAW") == 0) || - (strcmp(protocol_file, "Unknown") == 0)) { - FURI_LOG_E(TAG, "Protocol unsupported"); - result = SubBruteFileResultProtocolNotSupported; - break; - } - - if(instance->decoder_result->protocol->type == SubGhzProtocolTypeDynamic) { - FURI_LOG_E(TAG, "Protocol is dynamic - not supported"); - result = SubBruteFileResultDynamicProtocolNotValid; - break; - } -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "Decoder: %s", instance->decoder_result->protocol->name); -#endif - - // Bit - if(!flipper_format_read_uint32(fff_data_file, "Bit", &temp_data32, 1)) { - FURI_LOG_E(TAG, "Missing or incorrect Bit"); - result = SubBruteFileResultMissingOrIncorrectBit; - break; - } - instance->file_protocol_info->bits = temp_data32; -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "Bit: %d", instance->file_protocol_info->bits); -#endif - - uint8_t key_data[sizeof(uint64_t)] = {0}; - if(!flipper_format_read_hex(fff_data_file, "Key", key_data, sizeof(uint64_t))) { - FURI_LOG_E(TAG, "Missing Key"); - result = SubBruteFileResultMissingOrIncorrectKey; - break; - } - uint64_t data = 0; - for(uint8_t i = 0; i < sizeof(uint64_t); i++) { - data = (data << 8) | key_data[i]; - } -#if FURI_DEBUG - FURI_LOG_D(TAG, "Key: %.16llX", data); -#endif - instance->key_from_file = data; - - // TE - if(!flipper_format_read_uint32(fff_data_file, "TE", &temp_data32, 1)) { - FURI_LOG_E(TAG, "Missing or incorrect TE"); - //result = SubBruteFileResultMissingOrIncorrectTe; - //break; - } else { - instance->file_protocol_info->te = temp_data32 != 0 ? temp_data32 : 0; - } - - // Repeat - if(flipper_format_read_uint32(fff_data_file, "Repeat", &temp_data32, 1)) { -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "Repeat: %ld", temp_data32); -#endif - instance->file_protocol_info->repeat = (uint8_t)temp_data32; - } else { -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "Repeat: 3 (default)"); -#endif - instance->file_protocol_info->repeat = 3; - } - - result = SubBruteFileResultOk; - } while(0); - - furi_string_free(temp_str); - flipper_format_file_close(fff_data_file); - flipper_format_free(fff_data_file); - furi_record_close(RECORD_STORAGE); - - subghz_receiver_free(instance->receiver); - - instance->decoder_result = NULL; - instance->receiver = NULL; - - if(result == SubBruteFileResultOk) { -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "Loaded successfully"); -#endif - } else { - subbrute_device_free_protocol_info(instance); - } - - return result; -} - -void subbrute_device_attack_set_default_values( - SubBruteDevice* instance, - SubBruteAttacks default_attack) { - furi_assert(instance); -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "subbrute_device_attack_set_default_values"); -#endif - instance->attack = default_attack; - instance->current_step = 0x00; - instance->bit_index = 0x00; - instance->extra_repeats = 0; - instance->two_bytes = false; - - if(default_attack != SubBruteAttackLoadFile) { - instance->max_value = subbrute_protocol_calc_max_value( - instance->attack, instance->bit_index, instance->two_bytes); - } -} - -const char* subbrute_device_error_get_desc(SubBruteFileResult error_id) { - const char* result; - switch(error_id) { - case(SubBruteFileResultOk): - result = "OK"; - break; - case(SubBruteFileResultErrorOpenFile): - result = "invalid name/path"; - break; - case(SubBruteFileResultMissingOrIncorrectHeader): - result = "Missing or incorrect header"; - break; - case(SubBruteFileResultFrequencyNotAllowed): - result = "Invalid frequency!"; - break; - case(SubBruteFileResultMissingOrIncorrectFrequency): - result = "Missing or incorrect Frequency"; - break; - case(SubBruteFileResultPresetInvalid): - result = "Preset FAIL"; - break; - case(SubBruteFileResultMissingProtocol): - result = "Missing Protocol"; - break; - case(SubBruteFileResultProtocolNotSupported): - result = "Protocol unsupported"; - break; - case(SubBruteFileResultDynamicProtocolNotValid): - result = "Dynamic protocol unsupported"; - break; - case(SubBruteFileResultProtocolNotFound): - result = "Protocol not found"; - break; - case(SubBruteFileResultMissingOrIncorrectBit): - result = "Missing or incorrect Bit"; - break; - case(SubBruteFileResultMissingOrIncorrectKey): - result = "Missing or incorrect Key"; - break; - case(SubBruteFileResultMissingOrIncorrectTe): - result = "Missing or incorrect TE"; - break; - case SubBruteFileResultUnknown: - default: - result = "Unknown error"; - break; - } - return result; -} - -void subbrute_device_free_protocol_info(SubBruteDevice* instance) { - furi_assert(instance); - instance->protocol_info = NULL; - if(instance->file_protocol_info) { - free(instance->file_protocol_info); - } - instance->file_protocol_info = NULL; +#include "subbrute_device.h" + +#include +#include +#include +#include +#include +#include + +#define TAG "SubBruteDevice" + +SubBruteDevice* subbrute_device_alloc() { + SubBruteDevice* instance = malloc(sizeof(SubBruteDevice)); + + instance->current_step = 0; + + instance->protocol_info = NULL; + instance->file_protocol_info = NULL; + instance->decoder_result = NULL; + instance->receiver = NULL; + instance->environment = subghz_environment_alloc(); + subghz_environment_set_protocol_registry( + instance->environment, (void*)&subghz_protocol_registry); + +#ifdef FURI_DEBUG + subbrute_device_attack_set_default_values(instance, SubBruteAttackLoadFile); +#else + subbrute_device_attack_set_default_values(instance, SubBruteAttackCAME12bit433); +#endif + return instance; +} + +void subbrute_device_free(SubBruteDevice* instance) { + furi_assert(instance); + + // I don't know how to free this + instance->decoder_result = NULL; + + if(instance->receiver != NULL) { + subghz_receiver_free(instance->receiver); + instance->receiver = NULL; + } + + subghz_environment_free(instance->environment); + instance->environment = NULL; + + subbrute_device_free_protocol_info(instance); + + free(instance); +} + +uint64_t subbrute_device_add_step(SubBruteDevice* instance, int8_t step) { + if(step > 0) { + if((instance->current_step + step) - instance->max_value == 1) { + instance->current_step = 0x00; + } else { + uint64_t value = instance->current_step + step; + if(value == instance->max_value) { + instance->current_step = value; + } else { + instance->current_step = value % instance->max_value; + } + } + } else { + if(instance->current_step + step == 0) { + instance->current_step = 0x00; + } else if(instance->current_step == 0) { + instance->current_step = instance->max_value; + } else { + uint64_t value = ((instance->current_step + step) + instance->max_value); + if(value == instance->max_value) { + instance->current_step = value; + } else { + instance->current_step = value % instance->max_value; + } + } + } + + return instance->current_step; +} + +bool subbrute_device_save_file(SubBruteDevice* instance, const char* dev_file_name) { + furi_assert(instance); + +#ifdef FURI_DEBUG + FURI_LOG_D(TAG, "subbrute_device_save_file: %s", dev_file_name); +#endif + + Storage* storage = furi_record_open(RECORD_STORAGE); + FlipperFormat* file = flipper_format_file_alloc(storage); + bool result = false; + do { + if(!flipper_format_file_open_always(file, dev_file_name)) { + FURI_LOG_E(TAG, "Failed to open file: %s", dev_file_name); + break; + } + Stream* stream = flipper_format_get_raw_stream(file); + if(instance->attack == SubBruteAttackLoadFile) { + subbrute_protocol_file_generate_file( + stream, + instance->file_protocol_info->frequency, + instance->file_protocol_info->preset, + instance->file_protocol_info->file, + instance->current_step, + instance->file_protocol_info->bits, + instance->file_protocol_info->te, + instance->bit_index, + instance->key_from_file, + instance->two_bytes); + } else { + subbrute_protocol_default_generate_file( + stream, + instance->protocol_info->frequency, + instance->protocol_info->preset, + instance->protocol_info->file, + instance->current_step, + instance->protocol_info->bits, + instance->protocol_info->te); + } + + result = true; + } while(false); + + if(!result) { + FURI_LOG_E(TAG, "subbrute_device_save_file failed!"); + } + + flipper_format_file_close(file); + flipper_format_free(file); + furi_record_close(RECORD_STORAGE); + + return result; +} + +SubBruteFileResult subbrute_device_attack_set( + SubBruteDevice* instance, + SubBruteAttacks type, + uint8_t extra_repeats) { + furi_assert(instance); +#ifdef FURI_DEBUG + FURI_LOG_D(TAG, "subbrute_device_attack_set: %d, extra_repeats: %d", type, extra_repeats); +#endif + subbrute_device_attack_set_default_values(instance, type); + + if(type != SubBruteAttackLoadFile) { + subbrute_device_free_protocol_info(instance); + instance->protocol_info = subbrute_protocol(type); + } + + instance->extra_repeats = extra_repeats; + + // For non-file types we didn't set SubGhzProtocolDecoderBase + instance->receiver = subghz_receiver_alloc_init(instance->environment); + subghz_receiver_set_filter(instance->receiver, SubGhzProtocolFlag_Decodable); + furi_hal_subghz_reset(); + + uint8_t protocol_check_result = SubBruteFileResultProtocolNotFound; +#ifdef FURI_DEBUG + uint8_t bits; + uint32_t te; + uint8_t repeat; + FuriHalSubGhzPreset preset; + SubBruteFileProtocol file; +#endif + if(type != SubBruteAttackLoadFile) { + instance->decoder_result = subghz_receiver_search_decoder_base_by_name( + instance->receiver, subbrute_protocol_file(instance->protocol_info->file)); + + if(!instance->decoder_result || + instance->decoder_result->protocol->type == SubGhzProtocolTypeDynamic) { + FURI_LOG_E(TAG, "Can't load SubGhzProtocolDecoderBase in phase non-file decoder set"); + } else { + protocol_check_result = SubBruteFileResultOk; + + // Calc max value + instance->max_value = subbrute_protocol_calc_max_value( + instance->attack, instance->protocol_info->bits, instance->two_bytes); + } +#ifdef FURI_DEBUG + bits = instance->protocol_info->bits; + te = instance->protocol_info->te; + repeat = instance->protocol_info->repeat + instance->extra_repeats; + preset = instance->protocol_info->preset; + file = instance->protocol_info->file; +#endif + } else { + // And here we need to set preset enum + protocol_check_result = SubBruteFileResultOk; + + // Calc max value + instance->max_value = subbrute_protocol_calc_max_value( + instance->attack, instance->file_protocol_info->bits, instance->two_bytes); +#ifdef FURI_DEBUG + bits = instance->file_protocol_info->bits; + te = instance->file_protocol_info->te; + repeat = instance->file_protocol_info->repeat + instance->extra_repeats; + preset = instance->file_protocol_info->preset; + file = instance->file_protocol_info->file; +#endif + } + + subghz_receiver_free(instance->receiver); + instance->receiver = NULL; + + if(protocol_check_result != SubBruteFileResultOk) { + return SubBruteFileResultProtocolNotFound; + } + +#ifdef FURI_DEBUG + FURI_LOG_I( + TAG, + "subbrute_device_attack_set: %s, bits: %d, preset: %s, file: %s, te: %ld, repeat: %d, max_value: %lld", + subbrute_protocol_name(instance->attack), + bits, + subbrute_protocol_preset(preset), + subbrute_protocol_file(file), + te, + repeat, + instance->max_value); +#endif + + return SubBruteFileResultOk; +} + +uint8_t subbrute_device_load_from_file(SubBruteDevice* instance, const char* file_path) { + furi_assert(instance); +#ifdef FURI_DEBUG + FURI_LOG_D(TAG, "subbrute_device_load_from_file: %s", file_path); +#endif + SubBruteFileResult result = SubBruteFileResultUnknown; + + Storage* storage = furi_record_open(RECORD_STORAGE); + FlipperFormat* fff_data_file = flipper_format_file_alloc(storage); + + subbrute_device_free_protocol_info(instance); + instance->file_protocol_info = malloc(sizeof(SubBruteProtocol)); + + FuriString* temp_str; + temp_str = furi_string_alloc(); + uint32_t temp_data32; + + instance->receiver = subghz_receiver_alloc_init(instance->environment); + subghz_receiver_set_filter(instance->receiver, SubGhzProtocolFlag_Decodable); + furi_hal_subghz_reset(); + + do { + if(!flipper_format_file_open_existing(fff_data_file, file_path)) { + FURI_LOG_E(TAG, "Error open file %s", file_path); + result = SubBruteFileResultErrorOpenFile; + break; + } + if(!flipper_format_read_header(fff_data_file, temp_str, &temp_data32)) { + FURI_LOG_E(TAG, "Missing or incorrect header"); + result = SubBruteFileResultMissingOrIncorrectHeader; + break; + } + + // Frequency + if(!flipper_format_read_uint32(fff_data_file, "Frequency", &temp_data32, 1)) { + FURI_LOG_E(TAG, "Missing or incorrect Frequency"); + result = SubBruteFileResultMissingOrIncorrectFrequency; + break; + } + instance->file_protocol_info->frequency = temp_data32; + if(!furi_hal_subghz_is_tx_allowed(instance->file_protocol_info->frequency)) { + result = SubBruteFileResultFrequencyNotAllowed; + break; + } + + // Preset + if(!flipper_format_read_string(fff_data_file, "Preset", temp_str)) { + FURI_LOG_E(TAG, "Preset FAIL"); + result = SubBruteFileResultPresetInvalid; + break; + } + instance->file_protocol_info->preset = subbrute_protocol_convert_preset(temp_str); + + const char* protocol_file = NULL; + // Protocol + if(!flipper_format_read_string(fff_data_file, "Protocol", temp_str)) { + FURI_LOG_E(TAG, "Missing Protocol"); + result = SubBruteFileResultMissingProtocol; + break; + } + instance->file_protocol_info->file = subbrute_protocol_file_protocol_name(temp_str); + protocol_file = subbrute_protocol_file(instance->file_protocol_info->file); +#ifdef FURI_DEBUG + FURI_LOG_D(TAG, "Protocol: %s", protocol_file); +#endif + + instance->decoder_result = subghz_receiver_search_decoder_base_by_name( + instance->receiver, furi_string_get_cstr(temp_str)); + + if((!instance->decoder_result) || (strcmp(protocol_file, "RAW") == 0) || + (strcmp(protocol_file, "Unknown") == 0)) { + FURI_LOG_E(TAG, "Protocol unsupported"); + result = SubBruteFileResultProtocolNotSupported; + break; + } + + if(instance->decoder_result->protocol->type == SubGhzProtocolTypeDynamic) { + FURI_LOG_E(TAG, "Protocol is dynamic - not supported"); + result = SubBruteFileResultDynamicProtocolNotValid; + break; + } +#ifdef FURI_DEBUG + FURI_LOG_D(TAG, "Decoder: %s", instance->decoder_result->protocol->name); +#endif + + // Bit + if(!flipper_format_read_uint32(fff_data_file, "Bit", &temp_data32, 1)) { + FURI_LOG_E(TAG, "Missing or incorrect Bit"); + result = SubBruteFileResultMissingOrIncorrectBit; + break; + } + instance->file_protocol_info->bits = temp_data32; +#ifdef FURI_DEBUG + FURI_LOG_D(TAG, "Bit: %d", instance->file_protocol_info->bits); +#endif + + uint8_t key_data[sizeof(uint64_t)] = {0}; + if(!flipper_format_read_hex(fff_data_file, "Key", key_data, sizeof(uint64_t))) { + FURI_LOG_E(TAG, "Missing Key"); + result = SubBruteFileResultMissingOrIncorrectKey; + break; + } + uint64_t data = 0; + for(uint8_t i = 0; i < sizeof(uint64_t); i++) { + data = (data << 8) | key_data[i]; + } +#if FURI_DEBUG + FURI_LOG_D(TAG, "Key: %.16llX", data); +#endif + instance->key_from_file = data; + + // TE + if(!flipper_format_read_uint32(fff_data_file, "TE", &temp_data32, 1)) { + FURI_LOG_E(TAG, "Missing or incorrect TE"); + //result = SubBruteFileResultMissingOrIncorrectTe; + //break; + } else { + instance->file_protocol_info->te = temp_data32 != 0 ? temp_data32 : 0; + } + + // Repeat + if(flipper_format_read_uint32(fff_data_file, "Repeat", &temp_data32, 1)) { +#ifdef FURI_DEBUG + FURI_LOG_D(TAG, "Repeat: %ld", temp_data32); +#endif + instance->file_protocol_info->repeat = (uint8_t)temp_data32; + } else { +#ifdef FURI_DEBUG + FURI_LOG_D(TAG, "Repeat: 3 (default)"); +#endif + instance->file_protocol_info->repeat = 3; + } + + result = SubBruteFileResultOk; + } while(0); + + furi_string_free(temp_str); + flipper_format_file_close(fff_data_file); + flipper_format_free(fff_data_file); + furi_record_close(RECORD_STORAGE); + + subghz_receiver_free(instance->receiver); + + instance->decoder_result = NULL; + instance->receiver = NULL; + + if(result == SubBruteFileResultOk) { +#ifdef FURI_DEBUG + FURI_LOG_D(TAG, "Loaded successfully"); +#endif + } else { + subbrute_device_free_protocol_info(instance); + } + + return result; +} + +void subbrute_device_attack_set_default_values( + SubBruteDevice* instance, + SubBruteAttacks default_attack) { + furi_assert(instance); +#ifdef FURI_DEBUG + FURI_LOG_D(TAG, "subbrute_device_attack_set_default_values"); +#endif + instance->attack = default_attack; + instance->current_step = 0x00; + instance->bit_index = 0x00; + instance->extra_repeats = 0; + instance->two_bytes = false; + + if(default_attack != SubBruteAttackLoadFile) { + instance->max_value = subbrute_protocol_calc_max_value( + instance->attack, instance->bit_index, instance->two_bytes); + } +} + +const char* subbrute_device_error_get_desc(SubBruteFileResult error_id) { + const char* result; + switch(error_id) { + case(SubBruteFileResultOk): + result = "OK"; + break; + case(SubBruteFileResultErrorOpenFile): + result = "invalid name/path"; + break; + case(SubBruteFileResultMissingOrIncorrectHeader): + result = "Missing or incorrect header"; + break; + case(SubBruteFileResultFrequencyNotAllowed): + result = "Invalid frequency!"; + break; + case(SubBruteFileResultMissingOrIncorrectFrequency): + result = "Missing or incorrect Frequency"; + break; + case(SubBruteFileResultPresetInvalid): + result = "Preset FAIL"; + break; + case(SubBruteFileResultMissingProtocol): + result = "Missing Protocol"; + break; + case(SubBruteFileResultProtocolNotSupported): + result = "Protocol unsupported"; + break; + case(SubBruteFileResultDynamicProtocolNotValid): + result = "Dynamic protocol unsupported"; + break; + case(SubBruteFileResultProtocolNotFound): + result = "Protocol not found"; + break; + case(SubBruteFileResultMissingOrIncorrectBit): + result = "Missing or incorrect Bit"; + break; + case(SubBruteFileResultMissingOrIncorrectKey): + result = "Missing or incorrect Key"; + break; + case(SubBruteFileResultMissingOrIncorrectTe): + result = "Missing or incorrect TE"; + break; + case SubBruteFileResultUnknown: + default: + result = "Unknown error"; + break; + } + return result; +} + +void subbrute_device_free_protocol_info(SubBruteDevice* instance) { + furi_assert(instance); + instance->protocol_info = NULL; + if(instance->file_protocol_info) { + free(instance->file_protocol_info); + } + instance->file_protocol_info = NULL; } \ No newline at end of file diff --git a/subbrute_device.h b/subbrute_device.h index 7ff650e939f..d18662951d4 100644 --- a/subbrute_device.h +++ b/subbrute_device.h @@ -1,75 +1,75 @@ -#pragma once - -#include "subbrute_protocols.h" -#include -#include -#include -#include - -#define SUBBRUTE_TEXT_STORE_SIZE 256 - -#define SUBBRUTE_MAX_LEN_NAME 64 -#define SUBBRUTE_PATH EXT_PATH("subghz") -#define SUBBRUTE_FILE_EXT ".sub" - -#define SUBBRUTE_PAYLOAD_SIZE 16 - -typedef enum { - SubBruteFileResultUnknown, - SubBruteFileResultOk, - SubBruteFileResultErrorOpenFile, - SubBruteFileResultMissingOrIncorrectHeader, - SubBruteFileResultFrequencyNotAllowed, - SubBruteFileResultMissingOrIncorrectFrequency, - SubBruteFileResultPresetInvalid, - SubBruteFileResultMissingProtocol, - SubBruteFileResultProtocolNotSupported, - SubBruteFileResultDynamicProtocolNotValid, - SubBruteFileResultProtocolNotFound, - SubBruteFileResultMissingOrIncorrectBit, - SubBruteFileResultMissingOrIncorrectKey, - SubBruteFileResultMissingOrIncorrectTe, -} SubBruteFileResult; - -typedef struct { - const SubBruteProtocol* protocol_info; - SubBruteProtocol* file_protocol_info; - - // Current step - uint64_t current_step; - - // SubGhz - SubGhzReceiver* receiver; - SubGhzProtocolDecoderBase* decoder_result; - SubGhzEnvironment* environment; - - // Attack state - SubBruteAttacks attack; - uint64_t max_value; - uint8_t extra_repeats; - - // Loaded info for attack type - uint64_t key_from_file; - uint64_t current_key_from_file; - bool two_bytes; - // Index of group to bruteforce in loaded file - uint8_t bit_index; -} SubBruteDevice; - -SubBruteDevice* subbrute_device_alloc(); -void subbrute_device_free(SubBruteDevice* instance); - -bool subbrute_device_save_file(SubBruteDevice* instance, const char* key_name); -const char* subbrute_device_error_get_desc(SubBruteFileResult error_id); -SubBruteFileResult subbrute_device_attack_set( - SubBruteDevice* context, - SubBruteAttacks type, - uint8_t extra_repeats); -uint8_t subbrute_device_load_from_file(SubBruteDevice* context, const char* file_path); - -uint64_t subbrute_device_add_step(SubBruteDevice* instance, int8_t step); - -void subbrute_device_free_protocol_info(SubBruteDevice* instance); -void subbrute_device_attack_set_default_values( - SubBruteDevice* context, +#pragma once + +#include "subbrute_protocols.h" +#include +#include +#include +#include + +#define SUBBRUTE_TEXT_STORE_SIZE 256 + +#define SUBBRUTE_MAX_LEN_NAME 64 +#define SUBBRUTE_PATH EXT_PATH("subghz") +#define SUBBRUTE_FILE_EXT ".sub" + +#define SUBBRUTE_PAYLOAD_SIZE 16 + +typedef enum { + SubBruteFileResultUnknown, + SubBruteFileResultOk, + SubBruteFileResultErrorOpenFile, + SubBruteFileResultMissingOrIncorrectHeader, + SubBruteFileResultFrequencyNotAllowed, + SubBruteFileResultMissingOrIncorrectFrequency, + SubBruteFileResultPresetInvalid, + SubBruteFileResultMissingProtocol, + SubBruteFileResultProtocolNotSupported, + SubBruteFileResultDynamicProtocolNotValid, + SubBruteFileResultProtocolNotFound, + SubBruteFileResultMissingOrIncorrectBit, + SubBruteFileResultMissingOrIncorrectKey, + SubBruteFileResultMissingOrIncorrectTe, +} SubBruteFileResult; + +typedef struct { + const SubBruteProtocol* protocol_info; + SubBruteProtocol* file_protocol_info; + + // Current step + uint64_t current_step; + + // SubGhz + SubGhzReceiver* receiver; + SubGhzProtocolDecoderBase* decoder_result; + SubGhzEnvironment* environment; + + // Attack state + SubBruteAttacks attack; + uint64_t max_value; + uint8_t extra_repeats; + + // Loaded info for attack type + uint64_t key_from_file; + uint64_t current_key_from_file; + bool two_bytes; + // Index of group to bruteforce in loaded file + uint8_t bit_index; +} SubBruteDevice; + +SubBruteDevice* subbrute_device_alloc(); +void subbrute_device_free(SubBruteDevice* instance); + +bool subbrute_device_save_file(SubBruteDevice* instance, const char* key_name); +const char* subbrute_device_error_get_desc(SubBruteFileResult error_id); +SubBruteFileResult subbrute_device_attack_set( + SubBruteDevice* context, + SubBruteAttacks type, + uint8_t extra_repeats); +uint8_t subbrute_device_load_from_file(SubBruteDevice* context, const char* file_path); + +uint64_t subbrute_device_add_step(SubBruteDevice* instance, int8_t step); + +void subbrute_device_free_protocol_info(SubBruteDevice* instance); +void subbrute_device_attack_set_default_values( + SubBruteDevice* context, SubBruteAttacks default_attack); \ No newline at end of file diff --git a/subbrute_i.h b/subbrute_i.h index c50a7ed9b23..90599d3b272 100644 --- a/subbrute_i.h +++ b/subbrute_i.h @@ -1,80 +1,80 @@ -#pragma once - -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "SubGHz_Bruteforcer_icons.h" - -#include - -#include -#include - -#include "subbrute.h" -#include "subbrute_device.h" -#include "helpers/subbrute_worker.h" -#include "views/subbrute_attack_view.h" -#include "views/subbrute_main_view.h" - -#define SUBBRUTEFORCER_VER "Sub-GHz BruteForcer 3.5" - -#ifdef FURI_DEBUG -//#define SUBBRUTE_FAST_TRACK false -#endif - -typedef enum { - SubBruteViewNone, - SubBruteViewMain, - SubBruteViewAttack, - SubBruteViewTextInput, - SubBruteViewDialogEx, - SubBruteViewPopup, - SubBruteViewWidget, - SubBruteViewStack, -} SubBruteView; - -struct SubBruteState { - // GUI elements - NotificationApp* notifications; - Gui* gui; - ViewDispatcher* view_dispatcher; - ViewStack* view_stack; - TextInput* text_input; - Popup* popup; - Widget* widget; - DialogsApp* dialogs; - - // Text store - char text_store[SUBBRUTE_MAX_LEN_NAME]; - FuriString* file_path; - - // Views - SubBruteMainView* view_main; - SubBruteAttackView* view_attack; - SubBruteView current_view; - - // Scene - SceneManager* scene_manager; - - // SubBruteDevice - SubBruteDevice* device; - // SubBruteWorker - SubBruteWorker* worker; -}; - -void subbrute_show_loading_popup(void* context, bool show); -void subbrute_text_input_callback(void* context); +#pragma once + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "subghz_bruteforcer_icons.h" + +#include + +#include +#include + +#include "subbrute.h" +#include "subbrute_device.h" +#include "helpers/subbrute_worker.h" +#include "views/subbrute_attack_view.h" +#include "views/subbrute_main_view.h" + +#define SUBBRUTEFORCER_VER "Sub-GHz BruteForcer 3.6" + +#ifdef FURI_DEBUG +//#define SUBBRUTE_FAST_TRACK false +#endif + +typedef enum { + SubBruteViewNone, + SubBruteViewMain, + SubBruteViewAttack, + SubBruteViewTextInput, + SubBruteViewDialogEx, + SubBruteViewPopup, + SubBruteViewWidget, + SubBruteViewStack, +} SubBruteView; + +struct SubBruteState { + // GUI elements + NotificationApp* notifications; + Gui* gui; + ViewDispatcher* view_dispatcher; + ViewStack* view_stack; + TextInput* text_input; + Popup* popup; + Widget* widget; + DialogsApp* dialogs; + + // Text store + char text_store[SUBBRUTE_MAX_LEN_NAME]; + FuriString* file_path; + + // Views + SubBruteMainView* view_main; + SubBruteAttackView* view_attack; + SubBruteView current_view; + + // Scene + SceneManager* scene_manager; + + // SubBruteDevice + SubBruteDevice* device; + // SubBruteWorker + SubBruteWorker* worker; +}; + +void subbrute_show_loading_popup(void* context, bool show); +void subbrute_text_input_callback(void* context); void subbrute_popup_closed_callback(void* context); \ No newline at end of file diff --git a/subbrute_protocols.c b/subbrute_protocols.c index 6c6781b7861..ba04374cd38 100644 --- a/subbrute_protocols.c +++ b/subbrute_protocols.c @@ -1,881 +1,876 @@ -#include "subbrute_protocols.h" -#include "math.h" -#include - -#define TAG "SubBruteProtocols" - -/** - * CAME 12bit 303MHz - */ -const SubBruteProtocol subbrute_protocol_came_12bit_303 = { - .frequency = 303875000, - .bits = 12, - .te = 0, - .repeat = 3, - .preset = FuriHalSubGhzPresetOok650Async, - .file = CAMEFileProtocol}; - -/** - * CAME 12bit 307MHz - */ -const SubBruteProtocol subbrute_protocol_came_12bit_307 = { - .frequency = 307800000, - .bits = 12, - .te = 0, - .repeat = 3, - .preset = FuriHalSubGhzPresetOok650Async, - .file = CAMEFileProtocol}; - -/** - * CAME 12bit 315MHz - */ -const SubBruteProtocol subbrute_protocol_came_12bit_315 = { - .frequency = 315000000, - .bits = 12, - .te = 0, - .repeat = 3, - .preset = FuriHalSubGhzPresetOok650Async, - .file = CAMEFileProtocol}; - -/** - * CAME 12bit 433MHz - */ -const SubBruteProtocol subbrute_protocol_came_12bit_433 = { - .frequency = 433920000, - .bits = 12, - .te = 0, - .repeat = 3, - .preset = FuriHalSubGhzPresetOok650Async, - .file = CAMEFileProtocol}; - -/** - * CAME 12bit 868MHz - */ -const SubBruteProtocol subbrute_protocol_came_12bit_868 = { - .frequency = 868350000, - .bits = 12, - .te = 0, - .repeat = 3, - .preset = FuriHalSubGhzPresetOok650Async, - .file = CAMEFileProtocol}; - -/** - * NICE 12bit 433MHz - */ -const SubBruteProtocol subbrute_protocol_nice_12bit_433 = { - .frequency = 433920000, - .bits = 12, - .te = 0, - .repeat = 3, - .preset = FuriHalSubGhzPresetOok650Async, - .file = NICEFileProtocol}; - -/** - * NICE 12bit 868MHz - */ -const SubBruteProtocol subbrute_protocol_nice_12bit_868 = { - .frequency = 868350000, - .bits = 12, - .te = 0, - .repeat = 3, - .preset = FuriHalSubGhzPresetOok650Async, - .file = NICEFileProtocol}; - -/** - * Ansonic 12bit 433.075MHz - */ -const SubBruteProtocol subbrute_protocol_ansonic_12bit_433075 = { - .frequency = 433075000, - .bits = 12, - .te = 0, - .repeat = 3, - .preset = FuriHalSubGhzPreset2FSKDev238Async, - .file = AnsonicFileProtocol}; - -/** - * Ansonic 12bit 433.92MHz - */ -const SubBruteProtocol subbrute_protocol_ansonic_12bit_433 = { - .frequency = 433920000, - .bits = 12, - .te = 0, - .repeat = 3, - .preset = FuriHalSubGhzPreset2FSKDev238Async, - .file = AnsonicFileProtocol}; - -/** - * Ansonic 12bit 434.075MHz - */ -const SubBruteProtocol subbrute_protocol_ansonic_12bit_434 = { - .frequency = 434075000, - .bits = 12, - .te = 0, - .repeat = 3, - .preset = FuriHalSubGhzPreset2FSKDev238Async, - .file = AnsonicFileProtocol}; - -/** - * Chamberlain 9bit 300MHz - */ -const SubBruteProtocol subbrute_protocol_chamberlain_9bit_300 = { - .frequency = 300000000, - .bits = 9, - .te = 0, - .repeat = 3, - .preset = FuriHalSubGhzPresetOok650Async, - .file = ChamberlainFileProtocol}; - -/** - * Chamberlain 9bit 315MHz - */ -const SubBruteProtocol subbrute_protocol_chamberlain_9bit_315 = { - .frequency = 315000000, - .bits = 9, - .te = 0, - .repeat = 3, - .preset = FuriHalSubGhzPresetOok650Async, - .file = ChamberlainFileProtocol}; - -/** - * Chamberlain 9bit 390MHz - */ -const SubBruteProtocol subbrute_protocol_chamberlain_9bit_390 = { - .frequency = 390000000, - .bits = 9, - .te = 0, - .repeat = 3, - .preset = FuriHalSubGhzPresetOok650Async, - .file = ChamberlainFileProtocol}; - -/** - * Chamberlain 9bit 433MHz - */ -const SubBruteProtocol subbrute_protocol_chamberlain_9bit_433 = { - .frequency = 433920000, - .bits = 9, - .te = 0, - .repeat = 3, - .preset = FuriHalSubGhzPresetOok650Async, - .file = ChamberlainFileProtocol}; - -/** - * Chamberlain 8bit 300MHz - */ -const SubBruteProtocol subbrute_protocol_chamberlain_8bit_300 = { - .frequency = 300000000, - .bits = 8, - .te = 0, - .repeat = 3, - .preset = FuriHalSubGhzPresetOok650Async, - .file = ChamberlainFileProtocol}; - -/** - * Chamberlain 8bit 315MHz - */ -const SubBruteProtocol subbrute_protocol_chamberlain_8bit_315 = { - .frequency = 315000000, - .bits = 8, - .te = 0, - .repeat = 3, - .preset = FuriHalSubGhzPresetOok650Async, - .file = ChamberlainFileProtocol}; - -/** - * Chamberlain 8bit 390MHz - */ -const SubBruteProtocol subbrute_protocol_chamberlain_8bit_390 = { - .frequency = 390000000, - .bits = 8, - .te = 0, - .repeat = 3, - .preset = FuriHalSubGhzPresetOok650Async, - .file = ChamberlainFileProtocol}; - -/** - * Chamberlain 7bit 300MHz - */ -const SubBruteProtocol subbrute_protocol_chamberlain_7bit_300 = { - .frequency = 300000000, - .bits = 7, - .te = 0, - .repeat = 3, - .preset = FuriHalSubGhzPresetOok650Async, - .file = ChamberlainFileProtocol}; - -/** - * Chamberlain 7bit 315MHz - */ -const SubBruteProtocol subbrute_protocol_chamberlain_7bit_315 = { - .frequency = 315000000, - .bits = 7, - .te = 0, - .repeat = 3, - .preset = FuriHalSubGhzPresetOok650Async, - .file = ChamberlainFileProtocol}; - -/** - * Chamberlain 7bit 390MHz - */ -const SubBruteProtocol subbrute_protocol_chamberlain_7bit_390 = { - .frequency = 390000000, - .bits = 7, - .te = 0, - .repeat = 3, - .preset = FuriHalSubGhzPresetOok650Async, - .file = ChamberlainFileProtocol}; - -/** - * Linear 10bit 300MHz - */ -const SubBruteProtocol subbrute_protocol_linear_10bit_300 = { - .frequency = 300000000, - .bits = 10, - .te = 0, - .repeat = 5, - .preset = FuriHalSubGhzPresetOok650Async, - .file = LinearFileProtocol}; - -/** - * Linear 10bit 310MHz - */ -const SubBruteProtocol subbrute_protocol_linear_10bit_310 = { - .frequency = 310000000, - .bits = 10, - .te = 0, - .repeat = 5, - .preset = FuriHalSubGhzPresetOok650Async, - .file = LinearFileProtocol}; - -/** - * Linear Delta 3 8bit 310MHz - */ -const SubBruteProtocol subbrute_protocol_linear_delta_8bit_310 = { - .frequency = 310000000, - .bits = 8, - .te = 0, - .repeat = 5, - .preset = FuriHalSubGhzPresetOok650Async, - .file = LinearDeltaFileProtocol}; - -/** - * UNILARM 24bit 330MHz - */ -const SubBruteProtocol subbrute_protocol_unilarm_24bit_330 = { - .frequency = 330000000, - .bits = 25, - .te = 209, - .repeat = 4, - .preset = FuriHalSubGhzPresetOok650Async, - .file = UNILARMFileProtocol}; - -/** - * UNILARM 24bit 433MHz - */ -const SubBruteProtocol subbrute_protocol_unilarm_24bit_433 = { - .frequency = 433920000, - .bits = 25, - .te = 209, - .repeat = 4, - .preset = FuriHalSubGhzPresetOok650Async, - .file = UNILARMFileProtocol}; - -/** - * SMC5326 24bit 330MHz - */ -const SubBruteProtocol subbrute_protocol_smc5326_24bit_330 = { - .frequency = 330000000, - .bits = 25, - .te = 320, - .repeat = 4, - .preset = FuriHalSubGhzPresetOok650Async, - .file = SMC5326FileProtocol}; - -/** - * SMC5326 24bit 433MHz - */ -const SubBruteProtocol subbrute_protocol_smc5326_24bit_433 = { - .frequency = 433920000, - .bits = 25, - .te = 320, - .repeat = 4, - .preset = FuriHalSubGhzPresetOok650Async, - .file = SMC5326FileProtocol}; - -/** - * PT2260 (Princeton) 24bit 315MHz - */ -const SubBruteProtocol subbrute_protocol_pt2260_24bit_315 = { - .frequency = 315000000, - .bits = 24, - .te = 286, - .repeat = 4, - .preset = FuriHalSubGhzPresetOok650Async, - .file = PT2260FileProtocol}; - -/** - * PT2260 (Princeton) 24bit 330MHz - */ -const SubBruteProtocol subbrute_protocol_pt2260_24bit_330 = { - .frequency = 330000000, - .bits = 24, - .te = 286, - .repeat = 4, - .preset = FuriHalSubGhzPresetOok650Async, - .file = PT2260FileProtocol}; - -/** - * PT2260 (Princeton) 24bit 390MHz - */ -const SubBruteProtocol subbrute_protocol_pt2260_24bit_390 = { - .frequency = 390000000, - .bits = 24, - .te = 286, - .repeat = 4, - .preset = FuriHalSubGhzPresetOok650Async, - .file = PT2260FileProtocol}; - -/** - * PT2260 (Princeton) 24bit 433MHz - */ -const SubBruteProtocol subbrute_protocol_pt2260_24bit_433 = { - .frequency = 433920000, - .bits = 24, - .te = 286, - .repeat = 4, - .preset = FuriHalSubGhzPresetOok650Async, - .file = PT2260FileProtocol}; - -/** - * Holtek FM 12bit 433MHz - */ -const SubBruteProtocol subbrute_protocol_holtek_12bit_433 = { - .frequency = 433920000, - .bits = 12, - .te = 204, - .repeat = 4, - .preset = FuriHalSubGhzPreset2FSKDev476Async, - .file = HoltekFileProtocol}; - -/** - * Holtek AM 12bit 433MHz - */ -const SubBruteProtocol subbrute_protocol_holtek_12bit_am_433 = { - .frequency = 433920000, - .bits = 12, - .te = 433, - .repeat = 3, - .preset = FuriHalSubGhzPresetOok650Async, - .file = HoltekFileProtocol}; - -/** - * Holtek AM 12bit 315MHz - */ -const SubBruteProtocol subbrute_protocol_holtek_12bit_am_315 = { - .frequency = 315000000, - .bits = 12, - .te = 433, - .repeat = 3, - .preset = FuriHalSubGhzPresetOok650Async, - .file = HoltekFileProtocol}; - -/** - * Holtek AM 12bit 868MHz - */ -const SubBruteProtocol subbrute_protocol_holtek_12bit_am_868 = { - .frequency = 868350000, - .bits = 12, - .te = 433, - .repeat = 3, - .preset = FuriHalSubGhzPresetOok650Async, - .file = HoltekFileProtocol}; - -/** - * Holtek AM 12bit 915MHz - */ -const SubBruteProtocol subbrute_protocol_holtek_12bit_am_915 = { - .frequency = 915000000, - .bits = 12, - .te = 433, - .repeat = 3, - .preset = FuriHalSubGhzPresetOok650Async, - .file = HoltekFileProtocol}; - -/** - * BF existing dump - */ -const SubBruteProtocol subbrute_protocol_load_file = - {0, 0, 0, 3, FuriHalSubGhzPresetOok650Async, UnknownFileProtocol}; - -static const char* subbrute_protocol_names[] = { - [SubBruteAttackCAME12bit303] = "CAME 12bit 303MHz", - [SubBruteAttackCAME12bit307] = "CAME 12bit 307MHz", - [SubBruteAttackCAME12bit315] = "CAME 12bit 315MHz", - [SubBruteAttackCAME12bit433] = "CAME 12bit 433MHz", - [SubBruteAttackCAME12bit868] = "CAME 12bit 868MHz", - [SubBruteAttackNICE12bit433] = "NICE 12bit 433MHz", - [SubBruteAttackNICE12bit868] = "NICE 12bit 868MHz", - [SubBruteAttackAnsonic12bit433075] = "Ansonic 12bit 433.07MHz", - [SubBruteAttackAnsonic12bit433] = "Ansonic 12bit 433.92MHz", - [SubBruteAttackAnsonic12bit434] = "Ansonic 12bit 434.07MHz", - [SubBruteAttackHoltek12bitFM433] = "Holtek FM 12bit 433MHz", - [SubBruteAttackHoltek12bitAM433] = "Holtek AM 12bit 433MHz", - [SubBruteAttackHoltek12bitAM315] = "Holtek AM 12bit 315MHz", - [SubBruteAttackHoltek12bitAM868] = "Holtek AM 12bit 868MHz", - [SubBruteAttackHoltek12bitAM915] = "Holtek AM 12bit 915MHz", - [SubBruteAttackChamberlain9bit300] = "Chamberlain 9bit 300MHz", - [SubBruteAttackChamberlain9bit315] = "Chamberlain 9bit 315MHz", - [SubBruteAttackChamberlain9bit390] = "Chamberlain 9bit 390MHz", - [SubBruteAttackChamberlain9bit433] = "Chamberlain 9bit 433MHz", - [SubBruteAttackChamberlain8bit300] = "Chamberlain 8bit 300MHz", - [SubBruteAttackChamberlain8bit315] = "Chamberlain 8bit 315MHz", - [SubBruteAttackChamberlain8bit390] = "Chamberlain 8bit 390MHz", - [SubBruteAttackChamberlain7bit300] = "Chamberlain 7bit 300MHz", - [SubBruteAttackChamberlain7bit315] = "Chamberlain 7bit 315MHz", - [SubBruteAttackChamberlain7bit390] = "Chamberlain 7bit 390MHz", - [SubBruteAttackLinear10bit300] = "Linear 10bit 300MHz", - [SubBruteAttackLinear10bit310] = "Linear 10bit 310MHz", - [SubBruteAttackLinearDelta8bit310] = "LinearDelta3 8bit 310MHz", - [SubBruteAttackUNILARM24bit330] = "UNILARM 25bit 330MHz", - [SubBruteAttackUNILARM24bit433] = "UNILARM 25bit 433MHz", - [SubBruteAttackSMC532624bit330] = "SMC5326 25bit 330MHz", - [SubBruteAttackSMC532624bit433] = "SMC5326 25bit 433MHz", - [SubBruteAttackPT226024bit315] = "PT2260 24bit 315MHz", - [SubBruteAttackPT226024bit330] = "PT2260 24bit 330MHz", - [SubBruteAttackPT226024bit390] = "PT2260 24bit 390MHz", - [SubBruteAttackPT226024bit433] = "PT2260 24bit 433MHz", - [SubBruteAttackLoadFile] = "BF existing dump", - [SubBruteAttackTotalCount] = "Total Count", -}; - -static const char* subbrute_protocol_presets[] = { - [FuriHalSubGhzPresetIDLE] = "FuriHalSubGhzPresetIDLE", - [FuriHalSubGhzPresetOok270Async] = "FuriHalSubGhzPresetOok270Async", - [FuriHalSubGhzPresetOok650Async] = "FuriHalSubGhzPresetOok650Async", - [FuriHalSubGhzPreset2FSKDev238Async] = "FuriHalSubGhzPreset2FSKDev238Async", - [FuriHalSubGhzPreset2FSKDev476Async] = "FuriHalSubGhzPreset2FSKDev476Async", - [FuriHalSubGhzPresetMSK99_97KbAsync] = "FuriHalSubGhzPresetMSK99_97KbAsync", - [FuriHalSubGhzPresetGFSK9_99KbAsync] = "FuriHalSubGhzPresetGFSK9_99KbAsync", -}; - -const SubBruteProtocol* subbrute_protocol_registry[] = { - [SubBruteAttackCAME12bit303] = &subbrute_protocol_came_12bit_303, - [SubBruteAttackCAME12bit307] = &subbrute_protocol_came_12bit_307, - [SubBruteAttackCAME12bit315] = &subbrute_protocol_came_12bit_315, - [SubBruteAttackCAME12bit433] = &subbrute_protocol_came_12bit_433, - [SubBruteAttackCAME12bit868] = &subbrute_protocol_came_12bit_868, - [SubBruteAttackNICE12bit433] = &subbrute_protocol_nice_12bit_433, - [SubBruteAttackNICE12bit868] = &subbrute_protocol_nice_12bit_868, - [SubBruteAttackAnsonic12bit433075] = &subbrute_protocol_ansonic_12bit_433075, - [SubBruteAttackAnsonic12bit433] = &subbrute_protocol_ansonic_12bit_433, - [SubBruteAttackAnsonic12bit434] = &subbrute_protocol_ansonic_12bit_434, - [SubBruteAttackHoltek12bitFM433] = &subbrute_protocol_holtek_12bit_433, - [SubBruteAttackHoltek12bitAM433] = &subbrute_protocol_holtek_12bit_am_433, - [SubBruteAttackHoltek12bitAM315] = &subbrute_protocol_holtek_12bit_am_315, - [SubBruteAttackHoltek12bitAM868] = &subbrute_protocol_holtek_12bit_am_868, - [SubBruteAttackHoltek12bitAM915] = &subbrute_protocol_holtek_12bit_am_915, - [SubBruteAttackChamberlain9bit300] = &subbrute_protocol_chamberlain_9bit_300, - [SubBruteAttackChamberlain9bit315] = &subbrute_protocol_chamberlain_9bit_315, - [SubBruteAttackChamberlain9bit390] = &subbrute_protocol_chamberlain_9bit_390, - [SubBruteAttackChamberlain9bit433] = &subbrute_protocol_chamberlain_9bit_433, - [SubBruteAttackChamberlain8bit300] = &subbrute_protocol_chamberlain_8bit_300, - [SubBruteAttackChamberlain8bit315] = &subbrute_protocol_chamberlain_8bit_315, - [SubBruteAttackChamberlain8bit390] = &subbrute_protocol_chamberlain_8bit_390, - [SubBruteAttackChamberlain7bit300] = &subbrute_protocol_chamberlain_7bit_300, - [SubBruteAttackChamberlain7bit315] = &subbrute_protocol_chamberlain_7bit_315, - [SubBruteAttackChamberlain7bit390] = &subbrute_protocol_chamberlain_7bit_390, - [SubBruteAttackLinear10bit300] = &subbrute_protocol_linear_10bit_300, - [SubBruteAttackLinear10bit310] = &subbrute_protocol_linear_10bit_310, - [SubBruteAttackLinearDelta8bit310] = &subbrute_protocol_linear_delta_8bit_310, - [SubBruteAttackUNILARM24bit330] = &subbrute_protocol_unilarm_24bit_330, - [SubBruteAttackUNILARM24bit433] = &subbrute_protocol_unilarm_24bit_433, - [SubBruteAttackSMC532624bit330] = &subbrute_protocol_smc5326_24bit_330, - [SubBruteAttackSMC532624bit433] = &subbrute_protocol_smc5326_24bit_433, - [SubBruteAttackPT226024bit315] = &subbrute_protocol_pt2260_24bit_315, - [SubBruteAttackPT226024bit330] = &subbrute_protocol_pt2260_24bit_330, - [SubBruteAttackPT226024bit390] = &subbrute_protocol_pt2260_24bit_390, - [SubBruteAttackPT226024bit433] = &subbrute_protocol_pt2260_24bit_433, - [SubBruteAttackLoadFile] = &subbrute_protocol_load_file}; - -static const char* subbrute_protocol_file_types[] = { - [CAMEFileProtocol] = "CAME", - [NICEFileProtocol] = "Nice FLO", - [ChamberlainFileProtocol] = "Cham_Code", - [LinearFileProtocol] = "Linear", - [LinearDeltaFileProtocol] = "LinearDelta3", - [PrincetonFileProtocol] = "Princeton", - [RAWFileProtocol] = "RAW", - [BETTFileProtocol] = "BETT", - [ClemsaFileProtocol] = "Clemsa", - [DoitrandFileProtocol] = "Doitrand", - [GateTXFileProtocol] = "GateTX", - [MagellanFileProtocol] = "Magellan", - [IntertechnoV3FileProtocol] = "Intertechno_V3", - [AnsonicFileProtocol] = "Ansonic", - [SMC5326FileProtocol] = "SMC5326", - [UNILARMFileProtocol] = "SMC5326", - [PT2260FileProtocol] = "Princeton", - [HoneywellFileProtocol] = "Honeywell", - [HoltekFileProtocol] = "Holtek_HT12X", - [UnknownFileProtocol] = "Unknown"}; - -/** - * Values to not use less memory for packet parse operations - */ -static const char* subbrute_key_file_start_no_tail = - "Filetype: Flipper SubGhz Key File\nVersion: 1\nFrequency: %u\nPreset: %s\nProtocol: %s\nBit: %d\nKey: %s\nRepeat: %d\n"; -static const char* subbrute_key_file_start_with_tail = - "Filetype: Flipper SubGhz Key File\nVersion: 1\nFrequency: %u\nPreset: %s\nProtocol: %s\nBit: %d\nKey: %s\nTE: %d\nRepeat: %d\n"; -static const char* subbrute_key_small_no_tail = "Bit: %d\nKey: %s\nRepeat: %d\n"; -//static const char* subbrute_key_small_raw = -// "Filetype: Flipper SubGhz Key File\nVersion: 1\nFrequency: %u\nPreset: %s\nProtocol: %s\nBit: %d\n"; -static const char* subbrute_key_small_with_tail = "Bit: %d\nKey: %s\nTE: %d\nRepeat: %d\n"; - -const char* subbrute_protocol_name(SubBruteAttacks index) { - return subbrute_protocol_names[index]; -} - -const SubBruteProtocol* subbrute_protocol(SubBruteAttacks index) { - return subbrute_protocol_registry[index]; -} - -uint8_t subbrute_protocol_repeats_count(SubBruteAttacks index) { - return subbrute_protocol_registry[index]->repeat; -} - -const char* subbrute_protocol_preset(FuriHalSubGhzPreset preset) { - return subbrute_protocol_presets[preset]; -} - -const char* subbrute_protocol_file(SubBruteFileProtocol protocol) { - return subbrute_protocol_file_types[protocol]; -} - -FuriHalSubGhzPreset subbrute_protocol_convert_preset(FuriString* preset_name) { - for(size_t i = FuriHalSubGhzPresetIDLE; i < FuriHalSubGhzPresetCustom; i++) { - if(furi_string_cmp_str(preset_name, subbrute_protocol_presets[i]) == 0) { - return i; - } - } - - return FuriHalSubGhzPresetIDLE; -} - -SubBruteFileProtocol subbrute_protocol_file_protocol_name(FuriString* name) { - for(size_t i = CAMEFileProtocol; i < TotalFileProtocol - 1; i++) { - if(furi_string_cmp_str(name, subbrute_protocol_file_types[i]) == 0) { - return i; - } - } - - return UnknownFileProtocol; -} - -void subbrute_protocol_create_candidate_for_existing_file( - FuriString* candidate, - uint64_t step, - uint8_t bit_index, - uint64_t file_key, - bool two_bytes) { - uint8_t p[8]; - for(int i = 0; i < 8; i++) { - p[i] = (uint8_t)(file_key >> 8 * (7 - i)) & 0xFF; - } - uint8_t low_byte = step & (0xff); - uint8_t high_byte = (step >> 8) & 0xff; - - size_t size = sizeof(uint64_t); - for(uint8_t i = 0; i < size; i++) { - if(i == bit_index - 1 && two_bytes) { - furi_string_cat_printf(candidate, "%02X %02X", high_byte, low_byte); - i++; - } else if(i == bit_index) { - furi_string_cat_printf(candidate, "%02X", low_byte); - } else if(p[i] != 0) { - furi_string_cat_printf(candidate, "%02X", p[i]); - } else { - furi_string_cat_printf(candidate, "%s", "00"); - } - - if(i < size - 1) { - furi_string_push_back(candidate, ' '); - } - } - -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "file candidate: %s, step: %lld", furi_string_get_cstr(candidate), step); -#endif -} - -void subbrute_protocol_create_candidate_for_default( - FuriString* candidate, - SubBruteFileProtocol file, - uint64_t step) { - uint8_t p[8]; - if(file == SMC5326FileProtocol) { - const uint8_t lut[] = {0x00, 0x02, 0x03}; // 00, 10, 11 - const uint64_t gate1 = 0x01D5; // 111010101 - //const uint8_t gate2 = 0x0175; // 101110101 - - uint64_t total = 0; - for(size_t j = 0; j < 8; j++) { - total |= lut[step % 3] << (2 * j); - double sub_step = step / 3; - step = (uint64_t)floor(sub_step); - } - total <<= 9; - total |= gate1; - - for(int i = 0; i < 8; i++) { - p[i] = (uint8_t)(total >> 8 * (7 - i)) & 0xFF; - } - } else if(file == UNILARMFileProtocol) { - const uint8_t lut[] = {0x00, 0x02, 0x03}; // 00, 10, 11 - const uint64_t gate1 = 3 << 7; - //const uint8_t gate2 = 3 << 5; - - uint64_t total = 0; - for(size_t j = 0; j < 8; j++) { - total |= lut[step % 3] << (2 * j); - double sub_step = step / 3; - step = (uint64_t)floor(sub_step); - } - total <<= 9; - total |= gate1; - - for(int i = 0; i < 8; i++) { - p[i] = (uint8_t)(total >> 8 * (7 - i)) & 0xFF; - } - } else if(file == PT2260FileProtocol) { - const uint8_t lut[] = {0x00, 0x01, 0x03}; // 00, 01, 11 - const uint64_t button_open = 0x03; // 11 - //const uint8_t button_lock = 0x0C; // 1100 - //const uint8_t button_stop = 0x30; // 110000 - //const uint8_t button_close = 0xC0; // 11000000 - - uint64_t total = 0; - for(size_t j = 0; j < 8; j++) { - total |= lut[step % 3] << (2 * j); - double sub_step = step / 3; - step = (uint64_t)floor(sub_step); - } - total <<= 8; - total |= button_open; - - for(int i = 0; i < 8; i++) { - p[i] = (uint8_t)(total >> 8 * (7 - i)) & 0xFF; - } - } else { - for(int i = 0; i < 8; i++) { - p[i] = (uint8_t)(step >> 8 * (7 - i)) & 0xFF; - } - } - - size_t size = sizeof(uint64_t); - for(uint8_t i = 0; i < size; i++) { - if(p[i] != 0) { - furi_string_cat_printf(candidate, "%02X", p[i]); - } else { - furi_string_cat_printf(candidate, "%s", "00"); - } - - if(i < size - 1) { - furi_string_push_back(candidate, ' '); - } - } - -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "candidate: %s, step: %lld", furi_string_get_cstr(candidate), step); -#endif -} - -void subbrute_protocol_default_payload( - Stream* stream, - SubBruteFileProtocol file, - uint64_t step, - uint8_t bits, - uint32_t te, - uint8_t repeat) { - FuriString* candidate = furi_string_alloc(); - subbrute_protocol_create_candidate_for_default(candidate, file, step); - -#ifdef FURI_DEBUG - FURI_LOG_D( - TAG, - "candidate: %s, step: %lld, repeat: %d, te: %s", - furi_string_get_cstr(candidate), - step, - repeat, - te ? "true" : "false"); -#endif - stream_clean(stream); - if(te) { - stream_write_format( - stream, - subbrute_key_small_with_tail, - bits, - furi_string_get_cstr(candidate), - te, - repeat); - } else { - stream_write_format( - stream, subbrute_key_small_no_tail, bits, furi_string_get_cstr(candidate), repeat); - } - - furi_string_free(candidate); -} - -void subbrute_protocol_file_payload( - Stream* stream, - uint64_t step, - uint8_t bits, - uint32_t te, - uint8_t repeat, - uint8_t bit_index, - uint64_t file_key, - bool two_bytes) { - FuriString* candidate = furi_string_alloc(); - subbrute_protocol_create_candidate_for_existing_file( - candidate, step, bit_index, file_key, two_bytes); - -#ifdef FURI_DEBUG - FURI_LOG_D( - TAG, - "candidate: %s, step: %lld, repeat: %d, te: %s", - furi_string_get_cstr(candidate), - step, - repeat, - te ? "true" : "false"); -#endif - stream_clean(stream); - - if(te) { - stream_write_format( - stream, - subbrute_key_small_with_tail, - bits, - furi_string_get_cstr(candidate), - te, - repeat); - } else { - stream_write_format( - stream, subbrute_key_small_no_tail, bits, furi_string_get_cstr(candidate), repeat); - } - - furi_string_free(candidate); -} - -void subbrute_protocol_default_generate_file( - Stream* stream, - uint32_t frequency, - FuriHalSubGhzPreset preset, - SubBruteFileProtocol file, - uint64_t step, - uint8_t bits, - uint32_t te, - uint8_t repeat) { - FuriString* candidate = furi_string_alloc(); - subbrute_protocol_create_candidate_for_default(candidate, file, step); - -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "candidate: %s, step: %lld", furi_string_get_cstr(candidate), step); -#endif - stream_clean(stream); - - if(te) { - stream_write_format( - stream, - subbrute_key_file_start_with_tail, - frequency, - subbrute_protocol_preset(preset), - subbrute_protocol_file(file), - bits, - furi_string_get_cstr(candidate), - te, - repeat); - } else { - stream_write_format( - stream, - subbrute_key_file_start_no_tail, - frequency, - subbrute_protocol_preset(preset), - subbrute_protocol_file(file), - bits, - furi_string_get_cstr(candidate), - repeat); - } - - furi_string_free(candidate); -} - -void subbrute_protocol_file_generate_file( - Stream* stream, - uint32_t frequency, - FuriHalSubGhzPreset preset, - SubBruteFileProtocol file, - uint64_t step, - uint8_t bits, - uint32_t te, - uint8_t repeat, - uint8_t bit_index, - uint64_t file_key, - bool two_bytes) { - FuriString* candidate = furi_string_alloc(); - // char subbrute_payload_byte[8]; - //furi_string_set_str(candidate, file_key); - subbrute_protocol_create_candidate_for_existing_file( - candidate, step, bit_index, file_key, two_bytes); - - stream_clean(stream); - if(te) { - stream_write_format( - stream, - subbrute_key_file_start_with_tail, - frequency, - subbrute_protocol_preset(preset), - subbrute_protocol_file(file), - bits, - furi_string_get_cstr(candidate), - te, - repeat); - } else { - stream_write_format( - stream, - subbrute_key_file_start_no_tail, - frequency, - subbrute_protocol_preset(preset), - subbrute_protocol_file(file), - bits, - furi_string_get_cstr(candidate), - repeat); - } - - furi_string_free(candidate); -} - -uint64_t - subbrute_protocol_calc_max_value(SubBruteAttacks attack_type, uint8_t bits, bool two_bytes) { - uint64_t max_value; - if(attack_type == SubBruteAttackLoadFile) { - max_value = two_bytes ? 0xFFFF : 0xFF; - } else if( - attack_type == SubBruteAttackSMC532624bit330 || - attack_type == SubBruteAttackSMC532624bit433 || - attack_type == SubBruteAttackUNILARM24bit330 || - attack_type == SubBruteAttackUNILARM24bit433 || - attack_type == SubBruteAttackPT226024bit315 || - attack_type == SubBruteAttackPT226024bit330 || - attack_type == SubBruteAttackPT226024bit390 || - attack_type == SubBruteAttackPT226024bit433) { - max_value = 6561; - } else { - FuriString* max_value_s; - max_value_s = furi_string_alloc(); - for(uint8_t i = 0; i < bits; i++) { - furi_string_cat_printf(max_value_s, "1"); - } - max_value = (uint64_t)strtol(furi_string_get_cstr(max_value_s), NULL, 2); - furi_string_free(max_value_s); - } - - return max_value; +#include "subbrute_protocols.h" +#include "math.h" +#include + +#define TAG "SubBruteProtocols" + +/** + * CAME 12bit 303MHz + */ +const SubBruteProtocol subbrute_protocol_came_12bit_303 = { + .frequency = 303875000, + .bits = 12, + .te = 0, + .repeat = 3, + .preset = FuriHalSubGhzPresetOok650Async, + .file = CAMEFileProtocol}; + +/** + * CAME 12bit 307MHz + */ +const SubBruteProtocol subbrute_protocol_came_12bit_307 = { + .frequency = 307800000, + .bits = 12, + .te = 0, + .repeat = 3, + .preset = FuriHalSubGhzPresetOok650Async, + .file = CAMEFileProtocol}; + +/** + * CAME 12bit 315MHz + */ +const SubBruteProtocol subbrute_protocol_came_12bit_315 = { + .frequency = 315000000, + .bits = 12, + .te = 0, + .repeat = 3, + .preset = FuriHalSubGhzPresetOok650Async, + .file = CAMEFileProtocol}; + +/** + * CAME 12bit 433MHz + */ +const SubBruteProtocol subbrute_protocol_came_12bit_433 = { + .frequency = 433920000, + .bits = 12, + .te = 0, + .repeat = 3, + .preset = FuriHalSubGhzPresetOok650Async, + .file = CAMEFileProtocol}; + +/** + * CAME 12bit 868MHz + */ +const SubBruteProtocol subbrute_protocol_came_12bit_868 = { + .frequency = 868350000, + .bits = 12, + .te = 0, + .repeat = 3, + .preset = FuriHalSubGhzPresetOok650Async, + .file = CAMEFileProtocol}; + +/** + * NICE 12bit 433MHz + */ +const SubBruteProtocol subbrute_protocol_nice_12bit_433 = { + .frequency = 433920000, + .bits = 12, + .te = 0, + .repeat = 3, + .preset = FuriHalSubGhzPresetOok650Async, + .file = NICEFileProtocol}; + +/** + * NICE 12bit 868MHz + */ +const SubBruteProtocol subbrute_protocol_nice_12bit_868 = { + .frequency = 868350000, + .bits = 12, + .te = 0, + .repeat = 3, + .preset = FuriHalSubGhzPresetOok650Async, + .file = NICEFileProtocol}; + +/** + * Ansonic 12bit 433.075MHz + */ +const SubBruteProtocol subbrute_protocol_ansonic_12bit_433075 = { + .frequency = 433075000, + .bits = 12, + .te = 0, + .repeat = 3, + .preset = FuriHalSubGhzPreset2FSKDev238Async, + .file = AnsonicFileProtocol}; + +/** + * Ansonic 12bit 433.92MHz + */ +const SubBruteProtocol subbrute_protocol_ansonic_12bit_433 = { + .frequency = 433920000, + .bits = 12, + .te = 0, + .repeat = 3, + .preset = FuriHalSubGhzPreset2FSKDev238Async, + .file = AnsonicFileProtocol}; + +/** + * Ansonic 12bit 434.075MHz + */ +const SubBruteProtocol subbrute_protocol_ansonic_12bit_434 = { + .frequency = 434075000, + .bits = 12, + .te = 0, + .repeat = 3, + .preset = FuriHalSubGhzPreset2FSKDev238Async, + .file = AnsonicFileProtocol}; + +/** + * Chamberlain 9bit 300MHz + */ +const SubBruteProtocol subbrute_protocol_chamberlain_9bit_300 = { + .frequency = 300000000, + .bits = 9, + .te = 0, + .repeat = 3, + .preset = FuriHalSubGhzPresetOok650Async, + .file = ChamberlainFileProtocol}; + +/** + * Chamberlain 9bit 315MHz + */ +const SubBruteProtocol subbrute_protocol_chamberlain_9bit_315 = { + .frequency = 315000000, + .bits = 9, + .te = 0, + .repeat = 3, + .preset = FuriHalSubGhzPresetOok650Async, + .file = ChamberlainFileProtocol}; + +/** + * Chamberlain 9bit 390MHz + */ +const SubBruteProtocol subbrute_protocol_chamberlain_9bit_390 = { + .frequency = 390000000, + .bits = 9, + .te = 0, + .repeat = 3, + .preset = FuriHalSubGhzPresetOok650Async, + .file = ChamberlainFileProtocol}; + +/** + * Chamberlain 9bit 433MHz + */ +const SubBruteProtocol subbrute_protocol_chamberlain_9bit_433 = { + .frequency = 433920000, + .bits = 9, + .te = 0, + .repeat = 3, + .preset = FuriHalSubGhzPresetOok650Async, + .file = ChamberlainFileProtocol}; + +/** + * Chamberlain 8bit 300MHz + */ +const SubBruteProtocol subbrute_protocol_chamberlain_8bit_300 = { + .frequency = 300000000, + .bits = 8, + .te = 0, + .repeat = 3, + .preset = FuriHalSubGhzPresetOok650Async, + .file = ChamberlainFileProtocol}; + +/** + * Chamberlain 8bit 315MHz + */ +const SubBruteProtocol subbrute_protocol_chamberlain_8bit_315 = { + .frequency = 315000000, + .bits = 8, + .te = 0, + .repeat = 3, + .preset = FuriHalSubGhzPresetOok650Async, + .file = ChamberlainFileProtocol}; + +/** + * Chamberlain 8bit 390MHz + */ +const SubBruteProtocol subbrute_protocol_chamberlain_8bit_390 = { + .frequency = 390000000, + .bits = 8, + .te = 0, + .repeat = 3, + .preset = FuriHalSubGhzPresetOok650Async, + .file = ChamberlainFileProtocol}; + +/** + * Chamberlain 7bit 300MHz + */ +const SubBruteProtocol subbrute_protocol_chamberlain_7bit_300 = { + .frequency = 300000000, + .bits = 7, + .te = 0, + .repeat = 3, + .preset = FuriHalSubGhzPresetOok650Async, + .file = ChamberlainFileProtocol}; + +/** + * Chamberlain 7bit 315MHz + */ +const SubBruteProtocol subbrute_protocol_chamberlain_7bit_315 = { + .frequency = 315000000, + .bits = 7, + .te = 0, + .repeat = 3, + .preset = FuriHalSubGhzPresetOok650Async, + .file = ChamberlainFileProtocol}; + +/** + * Chamberlain 7bit 390MHz + */ +const SubBruteProtocol subbrute_protocol_chamberlain_7bit_390 = { + .frequency = 390000000, + .bits = 7, + .te = 0, + .repeat = 3, + .preset = FuriHalSubGhzPresetOok650Async, + .file = ChamberlainFileProtocol}; + +/** + * Linear 10bit 300MHz + */ +const SubBruteProtocol subbrute_protocol_linear_10bit_300 = { + .frequency = 300000000, + .bits = 10, + .te = 0, + .repeat = 5, + .preset = FuriHalSubGhzPresetOok650Async, + .file = LinearFileProtocol}; + +/** + * Linear 10bit 310MHz + */ +const SubBruteProtocol subbrute_protocol_linear_10bit_310 = { + .frequency = 310000000, + .bits = 10, + .te = 0, + .repeat = 5, + .preset = FuriHalSubGhzPresetOok650Async, + .file = LinearFileProtocol}; + +/** + * Linear Delta 3 8bit 310MHz + */ +const SubBruteProtocol subbrute_protocol_linear_delta_8bit_310 = { + .frequency = 310000000, + .bits = 8, + .te = 0, + .repeat = 5, + .preset = FuriHalSubGhzPresetOok650Async, + .file = LinearDeltaFileProtocol}; + +/** + * UNILARM 24bit 330MHz + */ +const SubBruteProtocol subbrute_protocol_unilarm_24bit_330 = { + .frequency = 330000000, + .bits = 25, + .te = 209, + .repeat = 4, + .preset = FuriHalSubGhzPresetOok650Async, + .file = UNILARMFileProtocol}; + +/** + * UNILARM 24bit 433MHz + */ +const SubBruteProtocol subbrute_protocol_unilarm_24bit_433 = { + .frequency = 433920000, + .bits = 25, + .te = 209, + .repeat = 4, + .preset = FuriHalSubGhzPresetOok650Async, + .file = UNILARMFileProtocol}; + +/** + * SMC5326 24bit 330MHz + */ +const SubBruteProtocol subbrute_protocol_smc5326_24bit_330 = { + .frequency = 330000000, + .bits = 25, + .te = 320, + .repeat = 4, + .preset = FuriHalSubGhzPresetOok650Async, + .file = SMC5326FileProtocol}; + +/** + * SMC5326 24bit 433MHz + */ +const SubBruteProtocol subbrute_protocol_smc5326_24bit_433 = { + .frequency = 433920000, + .bits = 25, + .te = 320, + .repeat = 4, + .preset = FuriHalSubGhzPresetOok650Async, + .file = SMC5326FileProtocol}; + +/** + * PT2260 (Princeton) 24bit 315MHz + */ +const SubBruteProtocol subbrute_protocol_pt2260_24bit_315 = { + .frequency = 315000000, + .bits = 24, + .te = 286, + .repeat = 4, + .preset = FuriHalSubGhzPresetOok650Async, + .file = PT2260FileProtocol}; + +/** + * PT2260 (Princeton) 24bit 330MHz + */ +const SubBruteProtocol subbrute_protocol_pt2260_24bit_330 = { + .frequency = 330000000, + .bits = 24, + .te = 286, + .repeat = 4, + .preset = FuriHalSubGhzPresetOok650Async, + .file = PT2260FileProtocol}; + +/** + * PT2260 (Princeton) 24bit 390MHz + */ +const SubBruteProtocol subbrute_protocol_pt2260_24bit_390 = { + .frequency = 390000000, + .bits = 24, + .te = 286, + .repeat = 4, + .preset = FuriHalSubGhzPresetOok650Async, + .file = PT2260FileProtocol}; + +/** + * PT2260 (Princeton) 24bit 433MHz + */ +const SubBruteProtocol subbrute_protocol_pt2260_24bit_433 = { + .frequency = 433920000, + .bits = 24, + .te = 286, + .repeat = 4, + .preset = FuriHalSubGhzPresetOok650Async, + .file = PT2260FileProtocol}; + +/** + * Holtek FM 12bit 433MHz + */ +const SubBruteProtocol subbrute_protocol_holtek_12bit_433 = { + .frequency = 433920000, + .bits = 12, + .te = 204, + .repeat = 4, + .preset = FuriHalSubGhzPreset2FSKDev476Async, + .file = HoltekFileProtocol}; + +/** + * Holtek AM 12bit 433MHz + */ +const SubBruteProtocol subbrute_protocol_holtek_12bit_am_433 = { + .frequency = 433920000, + .bits = 12, + .te = 433, + .repeat = 3, + .preset = FuriHalSubGhzPresetOok650Async, + .file = HoltekFileProtocol}; + +/** + * Holtek AM 12bit 315MHz + */ +const SubBruteProtocol subbrute_protocol_holtek_12bit_am_315 = { + .frequency = 315000000, + .bits = 12, + .te = 433, + .repeat = 3, + .preset = FuriHalSubGhzPresetOok650Async, + .file = HoltekFileProtocol}; + +/** + * Holtek AM 12bit 868MHz + */ +const SubBruteProtocol subbrute_protocol_holtek_12bit_am_868 = { + .frequency = 868350000, + .bits = 12, + .te = 433, + .repeat = 3, + .preset = FuriHalSubGhzPresetOok650Async, + .file = HoltekFileProtocol}; + +/** + * Holtek AM 12bit 915MHz + */ +const SubBruteProtocol subbrute_protocol_holtek_12bit_am_915 = { + .frequency = 915000000, + .bits = 12, + .te = 433, + .repeat = 3, + .preset = FuriHalSubGhzPresetOok650Async, + .file = HoltekFileProtocol}; + +/** + * BF existing dump + */ +const SubBruteProtocol subbrute_protocol_load_file = + {0, 0, 0, 3, FuriHalSubGhzPresetOok650Async, UnknownFileProtocol}; + +static const char* subbrute_protocol_names[] = { + [SubBruteAttackCAME12bit303] = "CAME 12bit 303MHz", + [SubBruteAttackCAME12bit307] = "CAME 12bit 307MHz", + [SubBruteAttackCAME12bit315] = "CAME 12bit 315MHz", + [SubBruteAttackCAME12bit433] = "CAME 12bit 433MHz", + [SubBruteAttackCAME12bit868] = "CAME 12bit 868MHz", + [SubBruteAttackNICE12bit433] = "NICE 12bit 433MHz", + [SubBruteAttackNICE12bit868] = "NICE 12bit 868MHz", + [SubBruteAttackAnsonic12bit433075] = "Ansonic 12bit 433.07MHz", + [SubBruteAttackAnsonic12bit433] = "Ansonic 12bit 433.92MHz", + [SubBruteAttackAnsonic12bit434] = "Ansonic 12bit 434.07MHz", + [SubBruteAttackHoltek12bitFM433] = "Holtek FM 12bit 433MHz", + [SubBruteAttackHoltek12bitAM433] = "Holtek AM 12bit 433MHz", + [SubBruteAttackHoltek12bitAM315] = "Holtek AM 12bit 315MHz", + [SubBruteAttackHoltek12bitAM868] = "Holtek AM 12bit 868MHz", + [SubBruteAttackHoltek12bitAM915] = "Holtek AM 12bit 915MHz", + [SubBruteAttackChamberlain9bit300] = "Chamberlain 9bit 300MHz", + [SubBruteAttackChamberlain9bit315] = "Chamberlain 9bit 315MHz", + [SubBruteAttackChamberlain9bit390] = "Chamberlain 9bit 390MHz", + [SubBruteAttackChamberlain9bit433] = "Chamberlain 9bit 433MHz", + [SubBruteAttackChamberlain8bit300] = "Chamberlain 8bit 300MHz", + [SubBruteAttackChamberlain8bit315] = "Chamberlain 8bit 315MHz", + [SubBruteAttackChamberlain8bit390] = "Chamberlain 8bit 390MHz", + [SubBruteAttackChamberlain7bit300] = "Chamberlain 7bit 300MHz", + [SubBruteAttackChamberlain7bit315] = "Chamberlain 7bit 315MHz", + [SubBruteAttackChamberlain7bit390] = "Chamberlain 7bit 390MHz", + [SubBruteAttackLinear10bit300] = "Linear 10bit 300MHz", + [SubBruteAttackLinear10bit310] = "Linear 10bit 310MHz", + [SubBruteAttackLinearDelta8bit310] = "LinearDelta3 8bit 310MHz", + [SubBruteAttackUNILARM24bit330] = "UNILARM 25bit 330MHz", + [SubBruteAttackUNILARM24bit433] = "UNILARM 25bit 433MHz", + [SubBruteAttackSMC532624bit330] = "SMC5326 25bit 330MHz", + [SubBruteAttackSMC532624bit433] = "SMC5326 25bit 433MHz", + [SubBruteAttackPT226024bit315] = "PT2260 24bit 315MHz", + [SubBruteAttackPT226024bit330] = "PT2260 24bit 330MHz", + [SubBruteAttackPT226024bit390] = "PT2260 24bit 390MHz", + [SubBruteAttackPT226024bit433] = "PT2260 24bit 433MHz", + [SubBruteAttackLoadFile] = "BF existing dump", + [SubBruteAttackTotalCount] = "Total Count", +}; + +static const char* subbrute_protocol_presets[] = { + [FuriHalSubGhzPresetIDLE] = "FuriHalSubGhzPresetIDLE", + [FuriHalSubGhzPresetOok270Async] = "FuriHalSubGhzPresetOok270Async", + [FuriHalSubGhzPresetOok650Async] = "FuriHalSubGhzPresetOok650Async", + [FuriHalSubGhzPreset2FSKDev238Async] = "FuriHalSubGhzPreset2FSKDev238Async", + [FuriHalSubGhzPreset2FSKDev476Async] = "FuriHalSubGhzPreset2FSKDev476Async", + [FuriHalSubGhzPresetMSK99_97KbAsync] = "FuriHalSubGhzPresetMSK99_97KbAsync", + [FuriHalSubGhzPresetGFSK9_99KbAsync] = "FuriHalSubGhzPresetGFSK9_99KbAsync", +}; + +const SubBruteProtocol* subbrute_protocol_registry[] = { + [SubBruteAttackCAME12bit303] = &subbrute_protocol_came_12bit_303, + [SubBruteAttackCAME12bit307] = &subbrute_protocol_came_12bit_307, + [SubBruteAttackCAME12bit315] = &subbrute_protocol_came_12bit_315, + [SubBruteAttackCAME12bit433] = &subbrute_protocol_came_12bit_433, + [SubBruteAttackCAME12bit868] = &subbrute_protocol_came_12bit_868, + [SubBruteAttackNICE12bit433] = &subbrute_protocol_nice_12bit_433, + [SubBruteAttackNICE12bit868] = &subbrute_protocol_nice_12bit_868, + [SubBruteAttackAnsonic12bit433075] = &subbrute_protocol_ansonic_12bit_433075, + [SubBruteAttackAnsonic12bit433] = &subbrute_protocol_ansonic_12bit_433, + [SubBruteAttackAnsonic12bit434] = &subbrute_protocol_ansonic_12bit_434, + [SubBruteAttackHoltek12bitFM433] = &subbrute_protocol_holtek_12bit_433, + [SubBruteAttackHoltek12bitAM433] = &subbrute_protocol_holtek_12bit_am_433, + [SubBruteAttackHoltek12bitAM315] = &subbrute_protocol_holtek_12bit_am_315, + [SubBruteAttackHoltek12bitAM868] = &subbrute_protocol_holtek_12bit_am_868, + [SubBruteAttackHoltek12bitAM915] = &subbrute_protocol_holtek_12bit_am_915, + [SubBruteAttackChamberlain9bit300] = &subbrute_protocol_chamberlain_9bit_300, + [SubBruteAttackChamberlain9bit315] = &subbrute_protocol_chamberlain_9bit_315, + [SubBruteAttackChamberlain9bit390] = &subbrute_protocol_chamberlain_9bit_390, + [SubBruteAttackChamberlain9bit433] = &subbrute_protocol_chamberlain_9bit_433, + [SubBruteAttackChamberlain8bit300] = &subbrute_protocol_chamberlain_8bit_300, + [SubBruteAttackChamberlain8bit315] = &subbrute_protocol_chamberlain_8bit_315, + [SubBruteAttackChamberlain8bit390] = &subbrute_protocol_chamberlain_8bit_390, + [SubBruteAttackChamberlain7bit300] = &subbrute_protocol_chamberlain_7bit_300, + [SubBruteAttackChamberlain7bit315] = &subbrute_protocol_chamberlain_7bit_315, + [SubBruteAttackChamberlain7bit390] = &subbrute_protocol_chamberlain_7bit_390, + [SubBruteAttackLinear10bit300] = &subbrute_protocol_linear_10bit_300, + [SubBruteAttackLinear10bit310] = &subbrute_protocol_linear_10bit_310, + [SubBruteAttackLinearDelta8bit310] = &subbrute_protocol_linear_delta_8bit_310, + [SubBruteAttackUNILARM24bit330] = &subbrute_protocol_unilarm_24bit_330, + [SubBruteAttackUNILARM24bit433] = &subbrute_protocol_unilarm_24bit_433, + [SubBruteAttackSMC532624bit330] = &subbrute_protocol_smc5326_24bit_330, + [SubBruteAttackSMC532624bit433] = &subbrute_protocol_smc5326_24bit_433, + [SubBruteAttackPT226024bit315] = &subbrute_protocol_pt2260_24bit_315, + [SubBruteAttackPT226024bit330] = &subbrute_protocol_pt2260_24bit_330, + [SubBruteAttackPT226024bit390] = &subbrute_protocol_pt2260_24bit_390, + [SubBruteAttackPT226024bit433] = &subbrute_protocol_pt2260_24bit_433, + [SubBruteAttackLoadFile] = &subbrute_protocol_load_file}; + +static const char* subbrute_protocol_file_types[] = { + [CAMEFileProtocol] = "CAME", + [NICEFileProtocol] = "Nice FLO", + [ChamberlainFileProtocol] = "Cham_Code", + [LinearFileProtocol] = "Linear", + [LinearDeltaFileProtocol] = "LinearDelta3", + [PrincetonFileProtocol] = "Princeton", + [RAWFileProtocol] = "RAW", + [BETTFileProtocol] = "BETT", + [ClemsaFileProtocol] = "Clemsa", + [DoitrandFileProtocol] = "Doitrand", + [GateTXFileProtocol] = "GateTX", + [MagellanFileProtocol] = "Magellan", + [IntertechnoV3FileProtocol] = "Intertechno_V3", + [AnsonicFileProtocol] = "Ansonic", + [SMC5326FileProtocol] = "SMC5326", + [UNILARMFileProtocol] = "SMC5326", + [PT2260FileProtocol] = "Princeton", + [HoneywellFileProtocol] = "Honeywell", + [HoltekFileProtocol] = "Holtek_HT12X", + [UnknownFileProtocol] = "Unknown"}; + +/** + * Values to not use less memory for packet parse operations + */ +static const char* subbrute_key_file_start_no_tail = + "Filetype: Flipper SubGhz Key File\nVersion: 1\nFrequency: %u\nPreset: %s\nProtocol: %s\nBit: %d\nKey: %s\n"; +static const char* subbrute_key_file_start_with_tail = + "Filetype: Flipper SubGhz Key File\nVersion: 1\nFrequency: %u\nPreset: %s\nProtocol: %s\nBit: %d\nKey: %s\nTE: %d\n"; +static const char* subbrute_key_small_no_tail = "Bit: %d\nKey: %s\nRepeat: %d\n"; +//static const char* subbrute_key_small_raw = +// "Filetype: Flipper SubGhz Key File\nVersion: 1\nFrequency: %u\nPreset: %s\nProtocol: %s\nBit: %d\n"; +static const char* subbrute_key_small_with_tail = "Bit: %d\nKey: %s\nTE: %d\nRepeat: %d\n"; + +const char* subbrute_protocol_name(SubBruteAttacks index) { + return subbrute_protocol_names[index]; +} + +const SubBruteProtocol* subbrute_protocol(SubBruteAttacks index) { + return subbrute_protocol_registry[index]; +} + +uint8_t subbrute_protocol_repeats_count(SubBruteAttacks index) { + return subbrute_protocol_registry[index]->repeat; +} + +const char* subbrute_protocol_preset(FuriHalSubGhzPreset preset) { + return subbrute_protocol_presets[preset]; +} + +const char* subbrute_protocol_file(SubBruteFileProtocol protocol) { + return subbrute_protocol_file_types[protocol]; +} + +FuriHalSubGhzPreset subbrute_protocol_convert_preset(FuriString* preset_name) { + for(size_t i = FuriHalSubGhzPresetIDLE; i < FuriHalSubGhzPresetCustom; i++) { + if(furi_string_cmp_str(preset_name, subbrute_protocol_presets[i]) == 0) { + return i; + } + } + + return FuriHalSubGhzPresetIDLE; +} + +SubBruteFileProtocol subbrute_protocol_file_protocol_name(FuriString* name) { + for(size_t i = CAMEFileProtocol; i < TotalFileProtocol - 1; i++) { + if(furi_string_cmp_str(name, subbrute_protocol_file_types[i]) == 0) { + return i; + } + } + + return UnknownFileProtocol; +} + +void subbrute_protocol_create_candidate_for_existing_file( + FuriString* candidate, + uint64_t step, + uint8_t bit_index, + uint64_t file_key, + bool two_bytes) { + uint8_t p[8]; + for(int i = 0; i < 8; i++) { + p[i] = (uint8_t)(file_key >> 8 * (7 - i)) & 0xFF; + } + uint8_t low_byte = step & (0xff); + uint8_t high_byte = (step >> 8) & 0xff; + + size_t size = sizeof(uint64_t); + for(uint8_t i = 0; i < size; i++) { + if(i == bit_index - 1 && two_bytes) { + furi_string_cat_printf(candidate, "%02X %02X", high_byte, low_byte); + i++; + } else if(i == bit_index) { + furi_string_cat_printf(candidate, "%02X", low_byte); + } else if(p[i] != 0) { + furi_string_cat_printf(candidate, "%02X", p[i]); + } else { + furi_string_cat_printf(candidate, "%s", "00"); + } + + if(i < size - 1) { + furi_string_push_back(candidate, ' '); + } + } + +#ifdef FURI_DEBUG + FURI_LOG_D(TAG, "file candidate: %s, step: %lld", furi_string_get_cstr(candidate), step); +#endif +} + +void subbrute_protocol_create_candidate_for_default( + FuriString* candidate, + SubBruteFileProtocol file, + uint64_t step) { + uint8_t p[8]; + if(file == SMC5326FileProtocol) { + const uint8_t lut[] = {0x00, 0x02, 0x03}; // 00, 10, 11 + const uint64_t gate1 = 0x01D5; // 111010101 + //const uint8_t gate2 = 0x0175; // 101110101 + + uint64_t total = 0; + for(size_t j = 0; j < 8; j++) { + total |= lut[step % 3] << (2 * j); + double sub_step = step / 3; + step = (uint64_t)floor(sub_step); + } + total <<= 9; + total |= gate1; + + for(int i = 0; i < 8; i++) { + p[i] = (uint8_t)(total >> 8 * (7 - i)) & 0xFF; + } + } else if(file == UNILARMFileProtocol) { + const uint8_t lut[] = {0x00, 0x02, 0x03}; // 00, 10, 11 + const uint64_t gate1 = 3 << 7; + //const uint8_t gate2 = 3 << 5; + + uint64_t total = 0; + for(size_t j = 0; j < 8; j++) { + total |= lut[step % 3] << (2 * j); + double sub_step = step / 3; + step = (uint64_t)floor(sub_step); + } + total <<= 9; + total |= gate1; + + for(int i = 0; i < 8; i++) { + p[i] = (uint8_t)(total >> 8 * (7 - i)) & 0xFF; + } + } else if(file == PT2260FileProtocol) { + const uint8_t lut[] = {0x00, 0x01, 0x03}; // 00, 01, 11 + const uint64_t button_open = 0x03; // 11 + //const uint8_t button_lock = 0x0C; // 1100 + //const uint8_t button_stop = 0x30; // 110000 + //const uint8_t button_close = 0xC0; // 11000000 + + uint64_t total = 0; + for(size_t j = 0; j < 8; j++) { + total |= lut[step % 3] << (2 * j); + double sub_step = step / 3; + step = (uint64_t)floor(sub_step); + } + total <<= 8; + total |= button_open; + + for(int i = 0; i < 8; i++) { + p[i] = (uint8_t)(total >> 8 * (7 - i)) & 0xFF; + } + } else { + for(int i = 0; i < 8; i++) { + p[i] = (uint8_t)(step >> 8 * (7 - i)) & 0xFF; + } + } + + size_t size = sizeof(uint64_t); + for(uint8_t i = 0; i < size; i++) { + if(p[i] != 0) { + furi_string_cat_printf(candidate, "%02X", p[i]); + } else { + furi_string_cat_printf(candidate, "%s", "00"); + } + + if(i < size - 1) { + furi_string_push_back(candidate, ' '); + } + } + +#ifdef FURI_DEBUG + FURI_LOG_D(TAG, "candidate: %s, step: %lld", furi_string_get_cstr(candidate), step); +#endif +} + +void subbrute_protocol_default_payload( + Stream* stream, + SubBruteFileProtocol file, + uint64_t step, + uint8_t bits, + uint32_t te, + uint8_t repeat) { + FuriString* candidate = furi_string_alloc(); + subbrute_protocol_create_candidate_for_default(candidate, file, step); + +#ifdef FURI_DEBUG + FURI_LOG_D( + TAG, + "candidate: %s, step: %lld, repeat: %d, te: %s", + furi_string_get_cstr(candidate), + step, + repeat, + te ? "true" : "false"); +#endif + stream_clean(stream); + if(te) { + stream_write_format( + stream, + subbrute_key_small_with_tail, + bits, + furi_string_get_cstr(candidate), + te, + repeat); + } else { + stream_write_format( + stream, subbrute_key_small_no_tail, bits, furi_string_get_cstr(candidate), repeat); + } + + furi_string_free(candidate); +} + +void subbrute_protocol_file_payload( + Stream* stream, + uint64_t step, + uint8_t bits, + uint32_t te, + uint8_t repeat, + uint8_t bit_index, + uint64_t file_key, + bool two_bytes) { + FuriString* candidate = furi_string_alloc(); + subbrute_protocol_create_candidate_for_existing_file( + candidate, step, bit_index, file_key, two_bytes); + +#ifdef FURI_DEBUG + FURI_LOG_D( + TAG, + "candidate: %s, step: %lld, repeat: %d, te: %s", + furi_string_get_cstr(candidate), + step, + repeat, + te ? "true" : "false"); +#endif + stream_clean(stream); + + if(te) { + stream_write_format( + stream, + subbrute_key_small_with_tail, + bits, + furi_string_get_cstr(candidate), + te, + repeat); + } else { + stream_write_format( + stream, subbrute_key_small_no_tail, bits, furi_string_get_cstr(candidate), repeat); + } + + furi_string_free(candidate); +} + +void subbrute_protocol_default_generate_file( + Stream* stream, + uint32_t frequency, + FuriHalSubGhzPreset preset, + SubBruteFileProtocol file, + uint64_t step, + uint8_t bits, + uint32_t te) { + FuriString* candidate = furi_string_alloc(); + subbrute_protocol_create_candidate_for_default(candidate, file, step); + +#ifdef FURI_DEBUG + FURI_LOG_D(TAG, "candidate: %s, step: %lld", furi_string_get_cstr(candidate), step); +#endif + stream_clean(stream); + + if(te) { + stream_write_format( + stream, + subbrute_key_file_start_with_tail, + frequency, + subbrute_protocol_preset(preset), + subbrute_protocol_file(file), + bits, + furi_string_get_cstr(candidate), + te); + } else { + stream_write_format( + stream, + subbrute_key_file_start_no_tail, + frequency, + subbrute_protocol_preset(preset), + subbrute_protocol_file(file), + bits, + furi_string_get_cstr(candidate)); + } + + furi_string_free(candidate); +} + +void subbrute_protocol_file_generate_file( + Stream* stream, + uint32_t frequency, + FuriHalSubGhzPreset preset, + SubBruteFileProtocol file, + uint64_t step, + uint8_t bits, + uint32_t te, + uint8_t bit_index, + uint64_t file_key, + bool two_bytes) { + FuriString* candidate = furi_string_alloc(); + // char subbrute_payload_byte[8]; + //furi_string_set_str(candidate, file_key); + subbrute_protocol_create_candidate_for_existing_file( + candidate, step, bit_index, file_key, two_bytes); + + stream_clean(stream); + + if(te) { + stream_write_format( + stream, + subbrute_key_file_start_with_tail, + frequency, + subbrute_protocol_preset(preset), + subbrute_protocol_file(file), + bits, + furi_string_get_cstr(candidate), + te); + } else { + stream_write_format( + stream, + subbrute_key_file_start_no_tail, + frequency, + subbrute_protocol_preset(preset), + subbrute_protocol_file(file), + bits, + furi_string_get_cstr(candidate)); + } + + furi_string_free(candidate); +} + +uint64_t + subbrute_protocol_calc_max_value(SubBruteAttacks attack_type, uint8_t bits, bool two_bytes) { + uint64_t max_value; + if(attack_type == SubBruteAttackLoadFile) { + max_value = two_bytes ? 0xFFFF : 0xFF; + } else if( + attack_type == SubBruteAttackSMC532624bit330 || + attack_type == SubBruteAttackSMC532624bit433 || + attack_type == SubBruteAttackUNILARM24bit330 || + attack_type == SubBruteAttackUNILARM24bit433 || + attack_type == SubBruteAttackPT226024bit315 || + attack_type == SubBruteAttackPT226024bit330 || + attack_type == SubBruteAttackPT226024bit390 || + attack_type == SubBruteAttackPT226024bit433) { + max_value = 6561; + } else { + FuriString* max_value_s; + max_value_s = furi_string_alloc(); + for(uint8_t i = 0; i < bits; i++) { + furi_string_cat_printf(max_value_s, "1"); + } + max_value = (uint64_t)strtol(furi_string_get_cstr(max_value_s), NULL, 2); + furi_string_free(max_value_s); + } + + return max_value; } \ No newline at end of file diff --git a/subbrute_protocols.h b/subbrute_protocols.h index 2f41b185b09..f5a6cae6f72 100644 --- a/subbrute_protocols.h +++ b/subbrute_protocols.h @@ -1,128 +1,126 @@ -#pragma once - -#include -#include -#include -#include - -typedef enum { - CAMEFileProtocol, - NICEFileProtocol, - ChamberlainFileProtocol, - LinearFileProtocol, - LinearDeltaFileProtocol, - PrincetonFileProtocol, - RAWFileProtocol, - BETTFileProtocol, - ClemsaFileProtocol, - DoitrandFileProtocol, - GateTXFileProtocol, - MagellanFileProtocol, - IntertechnoV3FileProtocol, - AnsonicFileProtocol, - SMC5326FileProtocol, - UNILARMFileProtocol, - PT2260FileProtocol, - HoneywellFileProtocol, - HoltekFileProtocol, - UnknownFileProtocol, - TotalFileProtocol, -} SubBruteFileProtocol; - -typedef enum { - SubBruteAttackCAME12bit303, - SubBruteAttackCAME12bit307, - SubBruteAttackCAME12bit315, - SubBruteAttackCAME12bit433, - SubBruteAttackCAME12bit868, - SubBruteAttackNICE12bit433, - SubBruteAttackNICE12bit868, - SubBruteAttackAnsonic12bit433075, - SubBruteAttackAnsonic12bit433, - SubBruteAttackAnsonic12bit434, - SubBruteAttackHoltek12bitFM433, - SubBruteAttackHoltek12bitAM433, - SubBruteAttackHoltek12bitAM315, - SubBruteAttackHoltek12bitAM868, - SubBruteAttackHoltek12bitAM915, - SubBruteAttackChamberlain9bit300, - SubBruteAttackChamberlain9bit315, - SubBruteAttackChamberlain9bit390, - SubBruteAttackChamberlain9bit433, - SubBruteAttackChamberlain8bit300, - SubBruteAttackChamberlain8bit315, - SubBruteAttackChamberlain8bit390, - SubBruteAttackChamberlain7bit300, - SubBruteAttackChamberlain7bit315, - SubBruteAttackChamberlain7bit390, - SubBruteAttackLinear10bit300, - SubBruteAttackLinear10bit310, - SubBruteAttackLinearDelta8bit310, - SubBruteAttackUNILARM24bit330, - SubBruteAttackUNILARM24bit433, - SubBruteAttackSMC532624bit330, - SubBruteAttackSMC532624bit433, - SubBruteAttackPT226024bit315, - SubBruteAttackPT226024bit330, - SubBruteAttackPT226024bit390, - SubBruteAttackPT226024bit433, - SubBruteAttackLoadFile, - SubBruteAttackTotalCount, -} SubBruteAttacks; - -typedef struct { - uint32_t frequency; - uint8_t bits; - uint32_t te; - uint8_t repeat; - FuriHalSubGhzPreset preset; - SubBruteFileProtocol file; -} SubBruteProtocol; - -const SubBruteProtocol* subbrute_protocol(SubBruteAttacks index); -const char* subbrute_protocol_preset(FuriHalSubGhzPreset preset); -const char* subbrute_protocol_file(SubBruteFileProtocol protocol); -FuriHalSubGhzPreset subbrute_protocol_convert_preset(FuriString* preset_name); -SubBruteFileProtocol subbrute_protocol_file_protocol_name(FuriString* name); -uint8_t subbrute_protocol_repeats_count(SubBruteAttacks index); -const char* subbrute_protocol_name(SubBruteAttacks index); - -void subbrute_protocol_default_payload( - Stream* stream, - SubBruteFileProtocol file, - uint64_t step, - uint8_t bits, - uint32_t te, - uint8_t repeat); -void subbrute_protocol_file_payload( - Stream* stream, - uint64_t step, - uint8_t bits, - uint32_t te, - uint8_t repeat, - uint8_t bit_index, - uint64_t file_key, - bool two_bytes); -void subbrute_protocol_default_generate_file( - Stream* stream, - uint32_t frequency, - FuriHalSubGhzPreset preset, - SubBruteFileProtocol file, - uint64_t step, - uint8_t bits, - uint32_t te, - uint8_t repeat); -void subbrute_protocol_file_generate_file( - Stream* stream, - uint32_t frequency, - FuriHalSubGhzPreset preset, - SubBruteFileProtocol file, - uint64_t step, - uint8_t bits, - uint32_t te, - uint8_t repeat, - uint8_t bit_index, - uint64_t file_key, - bool two_bytes); -uint64_t +#pragma once + +#include +#include +#include +#include + +typedef enum { + CAMEFileProtocol, + NICEFileProtocol, + ChamberlainFileProtocol, + LinearFileProtocol, + LinearDeltaFileProtocol, + PrincetonFileProtocol, + RAWFileProtocol, + BETTFileProtocol, + ClemsaFileProtocol, + DoitrandFileProtocol, + GateTXFileProtocol, + MagellanFileProtocol, + IntertechnoV3FileProtocol, + AnsonicFileProtocol, + SMC5326FileProtocol, + UNILARMFileProtocol, + PT2260FileProtocol, + HoneywellFileProtocol, + HoltekFileProtocol, + UnknownFileProtocol, + TotalFileProtocol, +} SubBruteFileProtocol; + +typedef enum { + SubBruteAttackCAME12bit303, + SubBruteAttackCAME12bit307, + SubBruteAttackCAME12bit315, + SubBruteAttackCAME12bit433, + SubBruteAttackCAME12bit868, + SubBruteAttackNICE12bit433, + SubBruteAttackNICE12bit868, + SubBruteAttackAnsonic12bit433075, + SubBruteAttackAnsonic12bit433, + SubBruteAttackAnsonic12bit434, + SubBruteAttackHoltek12bitFM433, + SubBruteAttackHoltek12bitAM433, + SubBruteAttackHoltek12bitAM315, + SubBruteAttackHoltek12bitAM868, + SubBruteAttackHoltek12bitAM915, + SubBruteAttackChamberlain9bit300, + SubBruteAttackChamberlain9bit315, + SubBruteAttackChamberlain9bit390, + SubBruteAttackChamberlain9bit433, + SubBruteAttackChamberlain8bit300, + SubBruteAttackChamberlain8bit315, + SubBruteAttackChamberlain8bit390, + SubBruteAttackChamberlain7bit300, + SubBruteAttackChamberlain7bit315, + SubBruteAttackChamberlain7bit390, + SubBruteAttackLinear10bit300, + SubBruteAttackLinear10bit310, + SubBruteAttackLinearDelta8bit310, + SubBruteAttackUNILARM24bit330, + SubBruteAttackUNILARM24bit433, + SubBruteAttackSMC532624bit330, + SubBruteAttackSMC532624bit433, + SubBruteAttackPT226024bit315, + SubBruteAttackPT226024bit330, + SubBruteAttackPT226024bit390, + SubBruteAttackPT226024bit433, + SubBruteAttackLoadFile, + SubBruteAttackTotalCount, +} SubBruteAttacks; + +typedef struct { + uint32_t frequency; + uint8_t bits; + uint32_t te; + uint8_t repeat; + FuriHalSubGhzPreset preset; + SubBruteFileProtocol file; +} SubBruteProtocol; + +const SubBruteProtocol* subbrute_protocol(SubBruteAttacks index); +const char* subbrute_protocol_preset(FuriHalSubGhzPreset preset); +const char* subbrute_protocol_file(SubBruteFileProtocol protocol); +FuriHalSubGhzPreset subbrute_protocol_convert_preset(FuriString* preset_name); +SubBruteFileProtocol subbrute_protocol_file_protocol_name(FuriString* name); +uint8_t subbrute_protocol_repeats_count(SubBruteAttacks index); +const char* subbrute_protocol_name(SubBruteAttacks index); + +void subbrute_protocol_default_payload( + Stream* stream, + SubBruteFileProtocol file, + uint64_t step, + uint8_t bits, + uint32_t te, + uint8_t repeat); +void subbrute_protocol_file_payload( + Stream* stream, + uint64_t step, + uint8_t bits, + uint32_t te, + uint8_t repeat, + uint8_t bit_index, + uint64_t file_key, + bool two_bytes); +void subbrute_protocol_default_generate_file( + Stream* stream, + uint32_t frequency, + FuriHalSubGhzPreset preset, + SubBruteFileProtocol file, + uint64_t step, + uint8_t bits, + uint32_t te); +void subbrute_protocol_file_generate_file( + Stream* stream, + uint32_t frequency, + FuriHalSubGhzPreset preset, + SubBruteFileProtocol file, + uint64_t step, + uint8_t bits, + uint32_t te, + uint8_t bit_index, + uint64_t file_key, + bool two_bytes); +uint64_t subbrute_protocol_calc_max_value(SubBruteAttacks attack_type, uint8_t bits, bool two_bytes); \ No newline at end of file diff --git a/views/subbrute_attack_view.c b/views/subbrute_attack_view.c index d7770bb4420..1590644227c 100644 --- a/views/subbrute_attack_view.c +++ b/views/subbrute_attack_view.c @@ -1,341 +1,344 @@ -#include "subbrute_attack_view.h" -#include "../subbrute_i.h" -#include "../subbrute_protocols.h" -#include "../helpers/gui_top_buttons.h" - -#include -#include -#include -#include -#include - -#define TAG "SubBruteAttackView" - -struct SubBruteAttackView { - View* view; - SubBruteAttackViewCallback callback; - void* context; - SubBruteAttacks attack_type; - uint64_t max_value; - uint64_t current_step; - bool is_attacking; - uint8_t extra_repeats; -}; - -typedef struct { - SubBruteAttacks attack_type; - uint64_t max_value; - uint64_t current_step; - uint8_t extra_repeats; - bool is_attacking; - IconAnimation* icon; -} SubBruteAttackViewModel; - -void subbrute_attack_view_set_callback( - SubBruteAttackView* instance, - SubBruteAttackViewCallback callback, - void* context) { - furi_assert(instance); - furi_assert(callback); - - instance->callback = callback; - instance->context = context; -} - -bool subbrute_attack_view_input(InputEvent* event, void* context) { - furi_assert(event); - furi_assert(context); - SubBruteAttackView* instance = context; -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "InputKey: %d", event->key); -#endif - - if(event->key == InputKeyBack && event->type == InputTypeShort) { - instance->is_attacking = false; - with_view_model( - instance->view, - SubBruteAttackViewModel * model, - { model->is_attacking = false; }, - true); - - instance->callback(SubBruteCustomEventTypeBackPressed, instance->context); - return true; - } - - bool update = false; - - if(!instance->is_attacking) { - if(event->type == InputTypeShort && event->key == InputKeyOk) { -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "InputKey: %d OK", event->key); -#endif - instance->is_attacking = true; - instance->callback(SubBruteCustomEventTypeTransmitStarted, instance->context); - update = true; - } else if(event->key == InputKeyUp) { - instance->callback(SubBruteCustomEventTypeSaveFile, instance->context); - update = true; - } else if(event->key == InputKeyDown) { - instance->callback(SubBruteCustomEventTypeTransmitCustom, instance->context); - update = true; - } else if(event->type == InputTypeShort) { - if(event->key == InputKeyLeft) { - instance->callback(SubBruteCustomEventTypeChangeStepDown, instance->context); - } else if(event->key == InputKeyRight) { - instance->callback(SubBruteCustomEventTypeChangeStepUp, instance->context); - } - update = true; - } else if(event->type == InputTypeRepeat) { - if(event->key == InputKeyLeft) { - instance->callback(SubBruteCustomEventTypeChangeStepDownMore, instance->context); - } else if(event->key == InputKeyRight) { - instance->callback(SubBruteCustomEventTypeChangeStepUpMore, instance->context); - } - update = true; - } - } else { - // ATTACK Mode! - if((event->type == InputTypeShort || event->type == InputTypeRepeat) && - (event->key == InputKeyOk || event->key == InputKeyBack)) { - instance->is_attacking = false; - instance->callback(SubBruteCustomEventTypeTransmitNotStarted, instance->context); - - update = true; - } - } - - if(update) { - with_view_model( - instance->view, - SubBruteAttackViewModel * model, - { - if(model->is_attacking != instance->is_attacking) { - if(instance->is_attacking) { - icon_animation_stop(model->icon); - icon_animation_start(model->icon); - } else { - icon_animation_stop(model->icon); - } - } - - model->attack_type = instance->attack_type; - model->max_value = instance->max_value; - model->current_step = instance->current_step; - model->is_attacking = instance->is_attacking; - }, - true); - } - - return true; -} - -SubBruteAttackView* subbrute_attack_view_alloc() { - SubBruteAttackView* instance = malloc(sizeof(SubBruteAttackView)); - - instance->view = view_alloc(); - view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(SubBruteAttackViewModel)); - view_set_context(instance->view, instance); - - with_view_model( - instance->view, - SubBruteAttackViewModel * model, - { - model->icon = icon_animation_alloc(&A_Sub1ghz_14); - view_tie_icon_animation(instance->view, model->icon); - }, - true); - - view_set_draw_callback(instance->view, (ViewDrawCallback)subbrute_attack_view_draw); - view_set_input_callback(instance->view, subbrute_attack_view_input); - view_set_enter_callback(instance->view, subbrute_attack_view_enter); - view_set_exit_callback(instance->view, subbrute_attack_view_exit); - - instance->attack_type = SubBruteAttackTotalCount; - instance->max_value = 0x00; - instance->current_step = 0; - instance->is_attacking = false; - - return instance; -} - -void subbrute_attack_view_enter(void* context) { - furi_assert(context); - -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "subbrute_attack_view_enter"); -#endif -} - -void subbrute_attack_view_free(SubBruteAttackView* instance) { - furi_assert(instance); - -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "subbrute_attack_view_free"); -#endif - - with_view_model( - instance->view, - SubBruteAttackViewModel * model, - { icon_animation_free(model->icon); }, - false); - - view_free(instance->view); - free(instance); -} - -View* subbrute_attack_view_get_view(SubBruteAttackView* instance) { - furi_assert(instance); - return instance->view; -} - -void subbrute_attack_view_set_current_step(SubBruteAttackView* instance, uint64_t current_step) { - furi_assert(instance); -#ifdef FURI_DEBUG - //FURI_LOG_D(TAG, "Set step: %d", current_step); -#endif - instance->current_step = current_step; - with_view_model( - instance->view, - SubBruteAttackViewModel * model, - { model->current_step = current_step; }, - true); -} - -// We need to call init every time, because not every time we calls enter -// normally, call enter only once -void subbrute_attack_view_init_values( - SubBruteAttackView* instance, - uint8_t index, - uint64_t max_value, - uint64_t current_step, - bool is_attacking, - uint8_t extra_repeats) { -#ifdef FURI_DEBUG - FURI_LOG_I( - TAG, - "INIT, attack_type: %d, max_value: %lld, current_step: %lld, extra_repeats: %d", - index, - max_value, - current_step, - extra_repeats); -#endif - instance->attack_type = index; - instance->max_value = max_value; - instance->current_step = current_step; - instance->is_attacking = is_attacking; - instance->extra_repeats = extra_repeats; - - with_view_model( - instance->view, - SubBruteAttackViewModel * model, - { - model->max_value = max_value; - model->attack_type = index; - model->current_step = current_step; - model->is_attacking = is_attacking; - model->extra_repeats = extra_repeats; - if(is_attacking) { - icon_animation_start(model->icon); - } else { - icon_animation_stop(model->icon); - } - }, - true); -} - -void subbrute_attack_view_exit(void* context) { - furi_assert(context); - SubBruteAttackView* instance = context; -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "subbrute_attack_view_exit"); -#endif - with_view_model( - instance->view, - SubBruteAttackViewModel * model, - { icon_animation_stop(model->icon); }, - false); -} - -void subbrute_attack_view_draw(Canvas* canvas, void* context) { - furi_assert(context); - SubBruteAttackViewModel* model = (SubBruteAttackViewModel*)context; - char buffer[64]; - - const char* attack_name = NULL; - attack_name = subbrute_protocol_name(model->attack_type); - - // Title - if(model->is_attacking) { - canvas_set_color(canvas, ColorBlack); - canvas_set_font(canvas, FontSecondary); - canvas_draw_str_aligned(canvas, 64, 2, AlignCenter, AlignTop, attack_name); - } - - // Current Step / Max value - const uint8_t y_frequency = 17; - if(model->max_value > 9999) { - canvas_set_font(canvas, FontBigNumbers); - snprintf(buffer, sizeof(buffer), "%05d/", (int)model->current_step); - canvas_draw_str_aligned(canvas, 5, y_frequency, AlignLeft, AlignTop, buffer); - - // Second part with another font, because BigNumber is out of screen bounds - canvas_set_font(canvas, FontPrimary); - snprintf(buffer, sizeof(buffer), "%05d", (int)model->max_value); - canvas_draw_str_aligned(canvas, 107, y_frequency + 13, AlignRight, AlignBottom, buffer); - } else if(model->max_value <= 0xFF) { - canvas_set_font(canvas, FontBigNumbers); - snprintf( - buffer, sizeof(buffer), "%03d/%03d", (int)model->current_step, (int)model->max_value); - canvas_draw_str_aligned(canvas, 64, y_frequency, AlignCenter, AlignTop, buffer); - } else { - canvas_set_font(canvas, FontBigNumbers); - snprintf( - buffer, sizeof(buffer), "%04d/%04d", (int)model->current_step, (int)model->max_value); - canvas_draw_str_aligned(canvas, 64, y_frequency, AlignCenter, AlignTop, buffer); - } - canvas_set_font(canvas, FontSecondary); - - memset(buffer, 0, sizeof(buffer)); - if(!model->is_attacking) { - canvas_set_color(canvas, ColorBlack); - canvas_set_font(canvas, FontSecondary); - canvas_draw_str_aligned(canvas, 64, 44, AlignCenter, AlignBottom, attack_name); - - snprintf( - buffer, - sizeof(buffer), - "x%d", - model->extra_repeats + subbrute_protocol_repeats_count(model->attack_type)); - canvas_draw_str_aligned(canvas, 60, 6, AlignCenter, AlignCenter, buffer); - - elements_button_left(canvas, "-1"); - elements_button_right(canvas, "+1"); - elements_button_center(canvas, "Start"); - elements_button_top_left(canvas, "Save"); - elements_button_top_right(canvas, "Resend"); - } else { - // canvas_draw_icon_animation - const uint8_t icon_h_offset = 0; - const uint8_t icon_width_with_offset = - icon_animation_get_width(model->icon) + icon_h_offset; - const uint8_t icon_v_offset = icon_animation_get_height(model->icon); // + vertical_offset; - const uint8_t x = canvas_width(canvas); - const uint8_t y = canvas_height(canvas); - canvas_draw_icon_animation( - canvas, x - icon_width_with_offset, y - icon_v_offset, model->icon); - // Progress bar - // Resolution: 128x64 px - float progress_value = (float)model->current_step / model->max_value; - elements_progress_bar(canvas, 8, 37, 110, progress_value > 1 ? 1 : progress_value); - - snprintf( - buffer, - sizeof(buffer), - "x%d", - model->extra_repeats + subbrute_protocol_repeats_count(model->attack_type)); - canvas_draw_str(canvas, 4, y - 8, buffer); - canvas_draw_str(canvas, 4, y - 1, "repeats"); - - elements_button_center(canvas, "Stop"); - } -} +#include "subbrute_attack_view.h" +#include "../subbrute_i.h" +#include "../subbrute_protocols.h" +#include "../helpers/gui_top_buttons.h" + +#include +#include +#include +#include +#include + +#define TAG "SubBruteAttackView" + +struct SubBruteAttackView { + View* view; + SubBruteAttackViewCallback callback; + void* context; + SubBruteAttacks attack_type; + uint64_t max_value; + uint64_t current_step; + bool is_attacking; + uint8_t extra_repeats; +}; + +typedef struct { + SubBruteAttacks attack_type; + uint64_t max_value; + uint64_t current_step; + uint8_t extra_repeats; + bool is_attacking; + IconAnimation* icon; +} SubBruteAttackViewModel; + +void subbrute_attack_view_set_callback( + SubBruteAttackView* instance, + SubBruteAttackViewCallback callback, + void* context) { + furi_assert(instance); + furi_assert(callback); + + instance->callback = callback; + instance->context = context; +} + +bool subbrute_attack_view_input(InputEvent* event, void* context) { + furi_assert(event); + furi_assert(context); + SubBruteAttackView* instance = context; +#ifdef FURI_DEBUG + FURI_LOG_D(TAG, "InputKey: %d", event->key); +#endif + + if(event->key == InputKeyBack && event->type == InputTypeShort) { + instance->is_attacking = false; + with_view_model( + instance->view, + SubBruteAttackViewModel * model, + { model->is_attacking = false; }, + true); + + instance->callback(SubBruteCustomEventTypeBackPressed, instance->context); + return true; + } + + bool update = false; + + if(!instance->is_attacking) { + if(event->type == InputTypeShort && event->key == InputKeyOk) { +#ifdef FURI_DEBUG + FURI_LOG_D(TAG, "InputKey: %d OK", event->key); +#endif + instance->is_attacking = true; + instance->callback(SubBruteCustomEventTypeTransmitStarted, instance->context); + update = true; + } else if(event->key == InputKeyUp && event->type == InputTypeShort) { + instance->callback(SubBruteCustomEventTypeSaveFile, instance->context); + update = true; + } else if(event->key == InputKeyUp && event->type == InputTypeLong) { + instance->callback(SubBruteCustomEventTypeExtraSettings, instance->context); + update = true; + } else if(event->key == InputKeyDown) { + instance->callback(SubBruteCustomEventTypeTransmitCustom, instance->context); + update = true; + } else if(event->type == InputTypeShort) { + if(event->key == InputKeyLeft) { + instance->callback(SubBruteCustomEventTypeChangeStepDown, instance->context); + } else if(event->key == InputKeyRight) { + instance->callback(SubBruteCustomEventTypeChangeStepUp, instance->context); + } + update = true; + } else if(event->type == InputTypeRepeat) { + if(event->key == InputKeyLeft) { + instance->callback(SubBruteCustomEventTypeChangeStepDownMore, instance->context); + } else if(event->key == InputKeyRight) { + instance->callback(SubBruteCustomEventTypeChangeStepUpMore, instance->context); + } + update = true; + } + } else { + // ATTACK Mode! + if((event->type == InputTypeShort || event->type == InputTypeRepeat) && + (event->key == InputKeyOk || event->key == InputKeyBack)) { + instance->is_attacking = false; + instance->callback(SubBruteCustomEventTypeTransmitNotStarted, instance->context); + + update = true; + } + } + + if(update) { + with_view_model( + instance->view, + SubBruteAttackViewModel * model, + { + if(model->is_attacking != instance->is_attacking) { + if(instance->is_attacking) { + icon_animation_stop(model->icon); + icon_animation_start(model->icon); + } else { + icon_animation_stop(model->icon); + } + } + + model->attack_type = instance->attack_type; + model->max_value = instance->max_value; + model->current_step = instance->current_step; + model->is_attacking = instance->is_attacking; + }, + true); + } + + return true; +} + +SubBruteAttackView* subbrute_attack_view_alloc() { + SubBruteAttackView* instance = malloc(sizeof(SubBruteAttackView)); + + instance->view = view_alloc(); + view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(SubBruteAttackViewModel)); + view_set_context(instance->view, instance); + + with_view_model( + instance->view, + SubBruteAttackViewModel * model, + { + model->icon = icon_animation_alloc(&A_Sub1ghz_14); + view_tie_icon_animation(instance->view, model->icon); + }, + true); + + view_set_draw_callback(instance->view, (ViewDrawCallback)subbrute_attack_view_draw); + view_set_input_callback(instance->view, subbrute_attack_view_input); + view_set_enter_callback(instance->view, subbrute_attack_view_enter); + view_set_exit_callback(instance->view, subbrute_attack_view_exit); + + instance->attack_type = SubBruteAttackTotalCount; + instance->max_value = 0x00; + instance->current_step = 0; + instance->is_attacking = false; + + return instance; +} + +void subbrute_attack_view_enter(void* context) { + furi_assert(context); + +#ifdef FURI_DEBUG + FURI_LOG_D(TAG, "subbrute_attack_view_enter"); +#endif +} + +void subbrute_attack_view_free(SubBruteAttackView* instance) { + furi_assert(instance); + +#ifdef FURI_DEBUG + FURI_LOG_D(TAG, "subbrute_attack_view_free"); +#endif + + with_view_model( + instance->view, + SubBruteAttackViewModel * model, + { icon_animation_free(model->icon); }, + false); + + view_free(instance->view); + free(instance); +} + +View* subbrute_attack_view_get_view(SubBruteAttackView* instance) { + furi_assert(instance); + return instance->view; +} + +void subbrute_attack_view_set_current_step(SubBruteAttackView* instance, uint64_t current_step) { + furi_assert(instance); +#ifdef FURI_DEBUG + //FURI_LOG_D(TAG, "Set step: %d", current_step); +#endif + instance->current_step = current_step; + with_view_model( + instance->view, + SubBruteAttackViewModel * model, + { model->current_step = current_step; }, + true); +} + +// We need to call init every time, because not every time we calls enter +// normally, call enter only once +void subbrute_attack_view_init_values( + SubBruteAttackView* instance, + uint8_t index, + uint64_t max_value, + uint64_t current_step, + bool is_attacking, + uint8_t extra_repeats) { +#ifdef FURI_DEBUG + FURI_LOG_I( + TAG, + "INIT, attack_type: %d, max_value: %lld, current_step: %lld, extra_repeats: %d", + index, + max_value, + current_step, + extra_repeats); +#endif + instance->attack_type = index; + instance->max_value = max_value; + instance->current_step = current_step; + instance->is_attacking = is_attacking; + instance->extra_repeats = extra_repeats; + + with_view_model( + instance->view, + SubBruteAttackViewModel * model, + { + model->max_value = max_value; + model->attack_type = index; + model->current_step = current_step; + model->is_attacking = is_attacking; + model->extra_repeats = extra_repeats; + if(is_attacking) { + icon_animation_start(model->icon); + } else { + icon_animation_stop(model->icon); + } + }, + true); +} + +void subbrute_attack_view_exit(void* context) { + furi_assert(context); + SubBruteAttackView* instance = context; +#ifdef FURI_DEBUG + FURI_LOG_D(TAG, "subbrute_attack_view_exit"); +#endif + with_view_model( + instance->view, + SubBruteAttackViewModel * model, + { icon_animation_stop(model->icon); }, + false); +} + +void subbrute_attack_view_draw(Canvas* canvas, void* context) { + furi_assert(context); + SubBruteAttackViewModel* model = (SubBruteAttackViewModel*)context; + char buffer[64]; + + const char* attack_name = NULL; + attack_name = subbrute_protocol_name(model->attack_type); + + // Title + if(model->is_attacking) { + canvas_set_color(canvas, ColorBlack); + canvas_set_font(canvas, FontSecondary); + canvas_draw_str_aligned(canvas, 64, 2, AlignCenter, AlignTop, attack_name); + } + + // Current Step / Max value + const uint8_t y_frequency = 17; + if(model->max_value > 9999) { + canvas_set_font(canvas, FontBigNumbers); + snprintf(buffer, sizeof(buffer), "%05d/", (int)model->current_step); + canvas_draw_str_aligned(canvas, 5, y_frequency, AlignLeft, AlignTop, buffer); + + // Second part with another font, because BigNumber is out of screen bounds + canvas_set_font(canvas, FontPrimary); + snprintf(buffer, sizeof(buffer), "%05d", (int)model->max_value); + canvas_draw_str_aligned(canvas, 107, y_frequency + 13, AlignRight, AlignBottom, buffer); + } else if(model->max_value <= 0xFF) { + canvas_set_font(canvas, FontBigNumbers); + snprintf( + buffer, sizeof(buffer), "%03d/%03d", (int)model->current_step, (int)model->max_value); + canvas_draw_str_aligned(canvas, 64, y_frequency, AlignCenter, AlignTop, buffer); + } else { + canvas_set_font(canvas, FontBigNumbers); + snprintf( + buffer, sizeof(buffer), "%04d/%04d", (int)model->current_step, (int)model->max_value); + canvas_draw_str_aligned(canvas, 64, y_frequency, AlignCenter, AlignTop, buffer); + } + canvas_set_font(canvas, FontSecondary); + + memset(buffer, 0, sizeof(buffer)); + if(!model->is_attacking) { + canvas_set_color(canvas, ColorBlack); + canvas_set_font(canvas, FontSecondary); + canvas_draw_str_aligned(canvas, 64, 44, AlignCenter, AlignBottom, attack_name); + + snprintf( + buffer, + sizeof(buffer), + "x%d", + model->extra_repeats + subbrute_protocol_repeats_count(model->attack_type)); + canvas_draw_str_aligned(canvas, 60, 6, AlignCenter, AlignCenter, buffer); + + elements_button_left(canvas, "-1"); + elements_button_right(canvas, "+1"); + elements_button_center(canvas, "Start"); + elements_button_top_left(canvas, "Save"); + elements_button_top_right(canvas, "Resend"); + } else { + // canvas_draw_icon_animation + const uint8_t icon_h_offset = 0; + const uint8_t icon_width_with_offset = + icon_animation_get_width(model->icon) + icon_h_offset; + const uint8_t icon_v_offset = icon_animation_get_height(model->icon); // + vertical_offset; + const uint8_t x = canvas_width(canvas); + const uint8_t y = canvas_height(canvas); + canvas_draw_icon_animation( + canvas, x - icon_width_with_offset, y - icon_v_offset, model->icon); + // Progress bar + // Resolution: 128x64 px + float progress_value = (float)model->current_step / model->max_value; + elements_progress_bar(canvas, 8, 37, 110, progress_value > 1 ? 1 : progress_value); + + snprintf( + buffer, + sizeof(buffer), + "x%d", + model->extra_repeats + subbrute_protocol_repeats_count(model->attack_type)); + canvas_draw_str(canvas, 4, y - 8, buffer); + canvas_draw_str(canvas, 4, y - 1, "repeats"); + + elements_button_center(canvas, "Stop"); + } +} diff --git a/views/subbrute_attack_view.h b/views/subbrute_attack_view.h index 55e3a8222f3..c744ffbfef1 100644 --- a/views/subbrute_attack_view.h +++ b/views/subbrute_attack_view.h @@ -1,25 +1,25 @@ -#pragma once - -#include "../subbrute_custom_event.h" -#include -#include -#include - -typedef void (*SubBruteAttackViewCallback)(SubBruteCustomEvent event, void* context); -typedef struct SubBruteAttackView SubBruteAttackView; - -void subbrute_attack_view_set_callback( - SubBruteAttackView* instance, - SubBruteAttackViewCallback callback, - void* context); -SubBruteAttackView* subbrute_attack_view_alloc(); -void subbrute_attack_view_free(SubBruteAttackView* instance); -View* subbrute_attack_view_get_view(SubBruteAttackView* instance); -void subbrute_attack_view_set_current_step(SubBruteAttackView* instance, uint64_t current_step); -void subbrute_attack_view_init_values( - SubBruteAttackView* instance, - uint8_t index, - uint64_t max_value, - uint64_t current_step, - bool is_attacking, +#pragma once + +#include "../subbrute_custom_event.h" +#include +#include +#include + +typedef void (*SubBruteAttackViewCallback)(SubBruteCustomEvent event, void* context); +typedef struct SubBruteAttackView SubBruteAttackView; + +void subbrute_attack_view_set_callback( + SubBruteAttackView* instance, + SubBruteAttackViewCallback callback, + void* context); +SubBruteAttackView* subbrute_attack_view_alloc(); +void subbrute_attack_view_free(SubBruteAttackView* instance); +View* subbrute_attack_view_get_view(SubBruteAttackView* instance); +void subbrute_attack_view_set_current_step(SubBruteAttackView* instance, uint64_t current_step); +void subbrute_attack_view_init_values( + SubBruteAttackView* instance, + uint8_t index, + uint64_t max_value, + uint64_t current_step, + bool is_attacking, uint8_t extra_repeats); \ No newline at end of file diff --git a/views/subbrute_main_view.c b/views/subbrute_main_view.c index c21f2ea33aa..4d018bf664f 100644 --- a/views/subbrute_main_view.c +++ b/views/subbrute_main_view.c @@ -1,463 +1,468 @@ -#include "subbrute_main_view.h" -#include "../subbrute_i.h" -#include "../subbrute_protocols.h" -#include "../helpers/gui_top_buttons.h" - -#include -#include -#include - -#define STATUS_BAR_Y_SHIFT 14 -#define TAG "SubBruteMainView" - -#define ITEMS_ON_SCREEN 3 -#define ITEMS_INTERVAL 1 -#define ITEM_WIDTH 14 -#define ITEM_Y 27 -#define ITEM_HEIGHT 13 -#define TEXT_X 6 -#define TEXT_Y 37 -#define TEXT_INTERVAL 3 -#define TEXT_WIDTH 12 -#define ITEM_FRAME_RADIUS 2 - -struct SubBruteMainView { - View* view; - SubBruteMainViewCallback callback; - void* context; - uint8_t index; - bool is_select_byte; - bool two_bytes; - uint64_t key_from_file; - uint8_t extra_repeats; - uint8_t window_position; -}; - -typedef struct { - uint8_t index; - uint8_t extra_repeats; - uint8_t window_position; - bool is_select_byte; - bool two_bytes; - uint64_t key_from_file; -} SubBruteMainViewModel; - -void subbrute_main_view_set_callback( - SubBruteMainView* instance, - SubBruteMainViewCallback callback, - void* context) { - furi_assert(instance); - furi_assert(callback); - - instance->callback = callback; - instance->context = context; -} - -void subbrute_main_view_center_displayed_key( - Canvas* canvas, - uint64_t key, - uint8_t index, - bool two_bytes) { - uint8_t text_x = TEXT_X; - uint8_t item_x = TEXT_X - ITEMS_INTERVAL; - canvas_set_font(canvas, FontSecondary); - - for(int i = 0; i < 8; i++) { - char current_value[3] = {0}; - uint8_t byte_value = (uint8_t)(key >> 8 * (7 - i)) & 0xFF; - snprintf(current_value, sizeof(current_value), "%02X", byte_value); - - // For two bytes we need to select prev location - if(!two_bytes && i == index) { - canvas_set_color(canvas, ColorBlack); - canvas_draw_rbox( - canvas, item_x - 1, ITEM_Y, ITEM_WIDTH + 1, ITEM_HEIGHT, ITEM_FRAME_RADIUS); - canvas_set_color(canvas, ColorWhite); - canvas_draw_str(canvas, text_x, TEXT_Y, current_value); - } else if(two_bytes && (i == index || i == index - 1)) { - if(i == index) { - canvas_set_color(canvas, ColorBlack); - canvas_draw_rbox( - canvas, - item_x - ITEMS_INTERVAL - ITEM_WIDTH - 1, - ITEM_Y, - ITEM_WIDTH * 2 + ITEMS_INTERVAL * 2 + 1, - ITEM_HEIGHT, - ITEM_FRAME_RADIUS); - - canvas_set_color(canvas, ColorWhite); - canvas_draw_str(canvas, text_x, TEXT_Y, current_value); - - // Redraw prev element with white - memset(current_value, 0, sizeof(current_value)); - byte_value = (uint8_t)(key >> 8 * (7 - i + 1)) & 0xFF; - snprintf(current_value, sizeof(current_value), "%02X", byte_value); - canvas_draw_str( - canvas, text_x - (TEXT_WIDTH + TEXT_INTERVAL), TEXT_Y, current_value); - } else { - canvas_set_color(canvas, ColorWhite); - canvas_draw_str(canvas, text_x, TEXT_Y, current_value); - } - } else { - canvas_set_color(canvas, ColorBlack); - canvas_draw_str(canvas, text_x, TEXT_Y, current_value); - } - text_x = text_x + TEXT_WIDTH + TEXT_INTERVAL; - item_x = item_x + ITEM_WIDTH + ITEMS_INTERVAL; - } - - // Return normal color - canvas_set_color(canvas, ColorBlack); -} - -void subbrute_main_view_draw(Canvas* canvas, SubBruteMainViewModel* model) { - uint16_t screen_width = canvas_width(canvas); - uint16_t screen_height = canvas_height(canvas); - - if(model->is_select_byte) { -#ifdef FURI_DEBUG - //FURI_LOG_D(TAG, "key_from_file: %s", model->key_from_file); -#endif - //char msg_index[18]; - //snprintf(msg_index, sizeof(msg_index), "Field index: %d", model->index); - canvas_set_font(canvas, FontSecondary); - canvas_draw_str_aligned( - canvas, 64, 17, AlignCenter, AlignTop, "Please select values to calc:"); - - subbrute_main_view_center_displayed_key( - canvas, model->key_from_file, model->index, model->two_bytes); - //const char* line = furi_string_get_cstr(menu_items); - //canvas_set_font(canvas, FontSecondary); - //canvas_draw_str_aligned( - // canvas, 64, 37, AlignCenter, AlignTop, furi_string_get_cstr(menu_items)); - - elements_button_center(canvas, "Select"); - if(model->index > 0) { - elements_button_left(canvas, " "); - } - if(model->index < 7) { - elements_button_right(canvas, " "); - } - // Switch to another mode - if(model->two_bytes) { - elements_button_top_left(canvas, "One byte"); - } else { - elements_button_top_left(canvas, "Two bytes"); - } - } else { - // Title - canvas_set_font(canvas, FontPrimary); - canvas_draw_box(canvas, 0, 0, canvas_width(canvas), STATUS_BAR_Y_SHIFT); - canvas_invert_color(canvas); - canvas_draw_str_aligned(canvas, 64, 3, AlignCenter, AlignTop, SUBBRUTEFORCER_VER); - canvas_invert_color(canvas); - - // Menu - canvas_set_color(canvas, ColorBlack); - canvas_set_font(canvas, FontSecondary); - const uint8_t item_height = 16; - -#ifdef FURI_DEBUG - //FURI_LOG_D(TAG, "window_position: %d, index: %d", model->window_position, model->index); -#endif - for(uint8_t position = 0; position < SubBruteAttackTotalCount; ++position) { - uint8_t item_position = position - model->window_position; - - if(item_position < ITEMS_ON_SCREEN) { - if(model->index == position) { - canvas_draw_str_aligned( - canvas, - 4, - 9 + (item_position * item_height) + STATUS_BAR_Y_SHIFT, - AlignLeft, - AlignCenter, - subbrute_protocol_name(position)); - - if(model->extra_repeats > 0) { - canvas_set_font(canvas, FontBatteryPercent); - char buffer[10]; - snprintf( - buffer, - sizeof(buffer), - "x%d", - model->extra_repeats + subbrute_protocol_repeats_count(model->index)); - canvas_draw_str_aligned( - canvas, - screen_width - 15, - 9 + (item_position * item_height) + STATUS_BAR_Y_SHIFT, - AlignLeft, - AlignCenter, - buffer); - canvas_set_font(canvas, FontSecondary); - } - - elements_frame( - canvas, 1, 1 + (item_position * item_height) + STATUS_BAR_Y_SHIFT, 124, 15); - } else { - canvas_draw_str_aligned( - canvas, - 4, - 9 + (item_position * item_height) + STATUS_BAR_Y_SHIFT, - AlignLeft, - AlignCenter, - subbrute_protocol_name(position)); - } - } - } - - elements_scrollbar_pos( - canvas, - screen_width, - STATUS_BAR_Y_SHIFT + 2, - screen_height - STATUS_BAR_Y_SHIFT, - model->index, - SubBruteAttackTotalCount); - } -} - -bool subbrute_main_view_input(InputEvent* event, void* context) { - furi_assert(event); - furi_assert(context); - - if(event->key == InputKeyBack && event->type == InputTypeShort) { -#ifdef FURI_DEBUG - FURI_LOG_I(TAG, "InputKey: BACK"); -#endif - return false; - } - - SubBruteMainView* instance = context; -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "InputKey: %d, extra_repeats: %d", event->key, instance->extra_repeats); -#endif - const uint8_t min_value = 0; - const uint8_t correct_total = SubBruteAttackTotalCount - 1; - uint8_t max_repeats = 9 - subbrute_protocol_repeats_count(instance->index); - - bool updated = false; - bool consumed = false; - bool is_short = (event->type == InputTypeShort) || (event->type == InputTypeRepeat); - - if(!instance->is_select_byte) { - if(event->key == InputKeyUp && is_short) { - if(instance->index == min_value) { - instance->index = correct_total; - } else { - instance->index = CLAMP(instance->index - 1, correct_total, min_value); - } - instance->extra_repeats = 0; - updated = true; - consumed = true; - } else if(event->key == InputKeyDown && is_short) { - if(instance->index == correct_total) { - instance->index = min_value; - } else { - instance->index = CLAMP(instance->index + 1, correct_total, min_value); - } - instance->extra_repeats = 0; - updated = true; - consumed = true; - } else if(event->key == InputKeyLeft && is_short) { - instance->extra_repeats = CLAMP(instance->extra_repeats - 1, max_repeats, 0); - - updated = true; - consumed = true; - } else if(event->key == InputKeyRight && is_short) { - instance->extra_repeats = CLAMP(instance->extra_repeats + 1, max_repeats, 0); - - updated = true; - consumed = true; - } else if(event->key == InputKeyOk && is_short) { - if(instance->index == SubBruteAttackLoadFile) { - instance->callback(SubBruteCustomEventTypeLoadFile, instance->context); - } else { - instance->callback(SubBruteCustomEventTypeMenuSelected, instance->context); - } - consumed = true; - updated = true; - } - if(updated) { - instance->window_position = instance->index; - if(instance->window_position > 0) { - instance->window_position -= 1; - } - - if(SubBruteAttackTotalCount <= ITEMS_ON_SCREEN) { - instance->window_position = 0; - } else { - if(instance->window_position >= (SubBruteAttackTotalCount - ITEMS_ON_SCREEN)) { - instance->window_position = (SubBruteAttackTotalCount - ITEMS_ON_SCREEN); - } - } - } - } else if(is_short) { - if(event->key == InputKeyLeft) { - if((instance->index > 0 && !instance->two_bytes) || - (instance->two_bytes && instance->index > 1)) { - instance->index--; - } - updated = true; - consumed = true; - } else if(event->key == InputKeyRight) { - if(instance->index < 7) { - instance->index++; - } - updated = true; - consumed = true; - } else if(event->key == InputKeyUp) { - instance->two_bytes = !instance->two_bytes; - // Because index is changing - if(instance->two_bytes && instance->index < 7) { - instance->index++; - } - // instance->callback( - // instance->two_bytes ? SubBruteCustomEventTypeChangeStepUp : - // SubBruteCustomEventTypeChangeStepDown, - // instance->context); - - updated = true; - consumed = true; - } else if(event->key == InputKeyOk) { - instance->callback(SubBruteCustomEventTypeIndexSelected, instance->context); - consumed = true; - updated = true; - } - } - - if(updated) { - with_view_model( - instance->view, - SubBruteMainViewModel * model, - { - model->index = instance->index; - model->window_position = instance->window_position; - model->key_from_file = instance->key_from_file; - model->is_select_byte = instance->is_select_byte; - model->two_bytes = instance->two_bytes; - model->extra_repeats = instance->extra_repeats; - }, - true); - } - - return consumed; -} - -void subbrute_main_view_enter(void* context) { - furi_assert(context); - -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "subbrute_main_view_enter"); -#endif -} - -void subbrute_main_view_exit(void* context) { - furi_assert(context); - -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "subbrute_main_view_exit"); -#endif -} - -SubBruteMainView* subbrute_main_view_alloc() { - SubBruteMainView* instance = malloc(sizeof(SubBruteMainView)); - instance->view = view_alloc(); - view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(SubBruteMainViewModel)); - view_set_context(instance->view, instance); - view_set_draw_callback(instance->view, (ViewDrawCallback)subbrute_main_view_draw); - view_set_input_callback(instance->view, subbrute_main_view_input); - view_set_enter_callback(instance->view, subbrute_main_view_enter); - view_set_exit_callback(instance->view, subbrute_main_view_exit); - - instance->index = 0; - instance->window_position = 0; - instance->key_from_file = 0; - instance->is_select_byte = false; - instance->two_bytes = false; - instance->extra_repeats = 0; - with_view_model( - instance->view, - SubBruteMainViewModel * model, - { - model->index = instance->index; - model->window_position = instance->window_position; - model->key_from_file = instance->key_from_file; - model->is_select_byte = instance->is_select_byte; - model->two_bytes = instance->two_bytes; - model->extra_repeats = instance->extra_repeats; - }, - true); - - return instance; -} - -void subbrute_main_view_free(SubBruteMainView* instance) { - furi_assert(instance); - - view_free(instance->view); - free(instance); -} - -View* subbrute_main_view_get_view(SubBruteMainView* instance) { - furi_assert(instance); - return instance->view; -} - -void subbrute_main_view_set_index( - SubBruteMainView* instance, - uint8_t idx, - bool is_select_byte, - bool two_bytes, - uint64_t key_from_file) { - furi_assert(instance); - furi_assert(idx < SubBruteAttackTotalCount); -#ifdef FURI_DEBUG - FURI_LOG_I(TAG, "Set index: %d, is_select_byte: %d", idx, is_select_byte); -#endif - instance->is_select_byte = is_select_byte; - instance->two_bytes = two_bytes; - instance->key_from_file = key_from_file; - instance->index = idx; - instance->window_position = idx; - - if(!is_select_byte) { - if(instance->window_position > 0) { - instance->window_position -= 1; - } - - if(SubBruteAttackTotalCount <= ITEMS_ON_SCREEN) { - instance->window_position = 0; - } else { - if(instance->window_position >= (SubBruteAttackTotalCount - ITEMS_ON_SCREEN)) { - instance->window_position = (SubBruteAttackTotalCount - ITEMS_ON_SCREEN); - } - } - } - - with_view_model( - instance->view, - SubBruteMainViewModel * model, - { - model->index = instance->index; - model->window_position = instance->window_position; - model->key_from_file = instance->key_from_file; - model->is_select_byte = instance->is_select_byte; - model->two_bytes = instance->two_bytes; - model->extra_repeats = instance->extra_repeats; - }, - true); -} - -SubBruteAttacks subbrute_main_view_get_index(SubBruteMainView* instance) { - furi_assert(instance); - return instance->index; -} - -uint8_t subbrute_main_view_get_extra_repeats(SubBruteMainView* instance) { - furi_assert(instance); - return instance->extra_repeats; -} - -bool subbrute_main_view_get_two_bytes(SubBruteMainView* instance) { - furi_assert(instance); - return instance->two_bytes; +#include "subbrute_main_view.h" +#include "../subbrute_i.h" +#include "../subbrute_protocols.h" +#include "../helpers/gui_top_buttons.h" + +#include +#include +#include + +#define STATUS_BAR_Y_SHIFT 14 +#define TAG "SubBruteMainView" + +#define ITEMS_ON_SCREEN 3 +#define ITEMS_INTERVAL 1 +#define ITEM_WIDTH 14 +#define ITEM_Y 27 +#define ITEM_HEIGHT 13 +#define TEXT_X 6 +#define TEXT_Y 37 +#define TEXT_INTERVAL 3 +#define TEXT_WIDTH 12 +#define ITEM_FRAME_RADIUS 2 + +struct SubBruteMainView { + View* view; + SubBruteMainViewCallback callback; + void* context; + uint8_t index; + bool is_select_byte; + bool two_bytes; + uint64_t key_from_file; + uint8_t extra_repeats; + uint8_t window_position; +}; + +typedef struct { + uint8_t index; + uint8_t extra_repeats; + uint8_t window_position; + bool is_select_byte; + bool two_bytes; + uint64_t key_from_file; +} SubBruteMainViewModel; + +void subbrute_main_view_set_callback( + SubBruteMainView* instance, + SubBruteMainViewCallback callback, + void* context) { + furi_assert(instance); + furi_assert(callback); + + instance->callback = callback; + instance->context = context; +} + +void subbrute_main_view_center_displayed_key( + Canvas* canvas, + uint64_t key, + uint8_t index, + bool two_bytes) { + uint8_t text_x = TEXT_X; + uint8_t item_x = TEXT_X - ITEMS_INTERVAL; + canvas_set_font(canvas, FontSecondary); + + for(int i = 0; i < 8; i++) { + char current_value[3] = {0}; + uint8_t byte_value = (uint8_t)(key >> 8 * (7 - i)) & 0xFF; + snprintf(current_value, sizeof(current_value), "%02X", byte_value); + + // For two bytes we need to select prev location + if(!two_bytes && i == index) { + canvas_set_color(canvas, ColorBlack); + canvas_draw_rbox( + canvas, item_x - 1, ITEM_Y, ITEM_WIDTH + 1, ITEM_HEIGHT, ITEM_FRAME_RADIUS); + canvas_set_color(canvas, ColorWhite); + canvas_draw_str(canvas, text_x, TEXT_Y, current_value); + } else if(two_bytes && (i == index || i == index - 1)) { + if(i == index) { + canvas_set_color(canvas, ColorBlack); + canvas_draw_rbox( + canvas, + item_x - ITEMS_INTERVAL - ITEM_WIDTH - 1, + ITEM_Y, + ITEM_WIDTH * 2 + ITEMS_INTERVAL * 2 + 1, + ITEM_HEIGHT, + ITEM_FRAME_RADIUS); + + canvas_set_color(canvas, ColorWhite); + canvas_draw_str(canvas, text_x, TEXT_Y, current_value); + + // Redraw prev element with white + memset(current_value, 0, sizeof(current_value)); + byte_value = (uint8_t)(key >> 8 * (7 - i + 1)) & 0xFF; + snprintf(current_value, sizeof(current_value), "%02X", byte_value); + canvas_draw_str( + canvas, text_x - (TEXT_WIDTH + TEXT_INTERVAL), TEXT_Y, current_value); + } else { + canvas_set_color(canvas, ColorWhite); + canvas_draw_str(canvas, text_x, TEXT_Y, current_value); + } + } else { + canvas_set_color(canvas, ColorBlack); + canvas_draw_str(canvas, text_x, TEXT_Y, current_value); + } + text_x = text_x + TEXT_WIDTH + TEXT_INTERVAL; + item_x = item_x + ITEM_WIDTH + ITEMS_INTERVAL; + } + + // Return normal color + canvas_set_color(canvas, ColorBlack); +} + +void subbrute_main_view_draw(Canvas* canvas, SubBruteMainViewModel* model) { + uint16_t screen_width = canvas_width(canvas); + uint16_t screen_height = canvas_height(canvas); + + if(model->is_select_byte) { +#ifdef FURI_DEBUG + //FURI_LOG_D(TAG, "key_from_file: %s", model->key_from_file); +#endif + //char msg_index[18]; + //snprintf(msg_index, sizeof(msg_index), "Field index: %d", model->index); + canvas_set_font(canvas, FontSecondary); + canvas_draw_str_aligned( + canvas, 64, 17, AlignCenter, AlignTop, "Please select values to calc:"); + + subbrute_main_view_center_displayed_key( + canvas, model->key_from_file, model->index, model->two_bytes); + //const char* line = furi_string_get_cstr(menu_items); + //canvas_set_font(canvas, FontSecondary); + //canvas_draw_str_aligned( + // canvas, 64, 37, AlignCenter, AlignTop, furi_string_get_cstr(menu_items)); + + elements_button_center(canvas, "Select"); + if(model->index > 0) { + elements_button_left(canvas, " "); + } + if(model->index < 7) { + elements_button_right(canvas, " "); + } + // Switch to another mode + if(model->two_bytes) { + elements_button_top_left(canvas, "One byte"); + } else { + elements_button_top_left(canvas, "Two bytes"); + } + } else { + // Title + canvas_set_font(canvas, FontPrimary); + canvas_draw_box(canvas, 0, 0, canvas_width(canvas), STATUS_BAR_Y_SHIFT); + canvas_invert_color(canvas); + canvas_draw_str_aligned(canvas, 64, 3, AlignCenter, AlignTop, SUBBRUTEFORCER_VER); + canvas_invert_color(canvas); + + // Menu + canvas_set_color(canvas, ColorBlack); + canvas_set_font(canvas, FontSecondary); + const uint8_t item_height = 16; + +#ifdef FURI_DEBUG + //FURI_LOG_D(TAG, "window_position: %d, index: %d", model->window_position, model->index); +#endif + for(uint8_t position = 0; position < SubBruteAttackTotalCount; ++position) { + uint8_t item_position = position - model->window_position; + + if(item_position < ITEMS_ON_SCREEN) { + if(model->index == position) { + canvas_draw_str_aligned( + canvas, + 3, + 9 + (item_position * item_height) + STATUS_BAR_Y_SHIFT, + AlignLeft, + AlignCenter, + subbrute_protocol_name(position)); + + if(model->extra_repeats > 0) { + canvas_set_font(canvas, FontBatteryPercent); + char buffer[10]; + snprintf( + buffer, + sizeof(buffer), + "x%d", + model->extra_repeats + subbrute_protocol_repeats_count(model->index)); + uint8_t temp_x_offset_repeats = 18; + if(model->extra_repeats + subbrute_protocol_repeats_count(model->index) < + 10) { + temp_x_offset_repeats = 15; + } + canvas_draw_str_aligned( + canvas, + screen_width - temp_x_offset_repeats, + 9 + (item_position * item_height) + STATUS_BAR_Y_SHIFT, + AlignLeft, + AlignCenter, + buffer); + canvas_set_font(canvas, FontSecondary); + } + + elements_frame( + canvas, 1, 1 + (item_position * item_height) + STATUS_BAR_Y_SHIFT, 124, 15); + } else { + canvas_draw_str_aligned( + canvas, + 4, + 9 + (item_position * item_height) + STATUS_BAR_Y_SHIFT, + AlignLeft, + AlignCenter, + subbrute_protocol_name(position)); + } + } + } + + elements_scrollbar_pos( + canvas, + screen_width, + STATUS_BAR_Y_SHIFT + 2, + screen_height - STATUS_BAR_Y_SHIFT, + model->index, + SubBruteAttackTotalCount); + } +} + +bool subbrute_main_view_input(InputEvent* event, void* context) { + furi_assert(event); + furi_assert(context); + + if(event->key == InputKeyBack && event->type == InputTypeShort) { +#ifdef FURI_DEBUG + FURI_LOG_I(TAG, "InputKey: BACK"); +#endif + return false; + } + + SubBruteMainView* instance = context; +#ifdef FURI_DEBUG + FURI_LOG_D(TAG, "InputKey: %d, extra_repeats: %d", event->key, instance->extra_repeats); +#endif + const uint8_t min_value = 0; + const uint8_t correct_total = SubBruteAttackTotalCount - 1; + uint8_t max_repeats = 14 - subbrute_protocol_repeats_count(instance->index); + + bool updated = false; + bool consumed = false; + bool is_short = (event->type == InputTypeShort) || (event->type == InputTypeRepeat); + + if(!instance->is_select_byte) { + if(event->key == InputKeyUp && is_short) { + if(instance->index == min_value) { + instance->index = correct_total; + } else { + instance->index = CLAMP(instance->index - 1, correct_total, min_value); + } + instance->extra_repeats = 0; + updated = true; + consumed = true; + } else if(event->key == InputKeyDown && is_short) { + if(instance->index == correct_total) { + instance->index = min_value; + } else { + instance->index = CLAMP(instance->index + 1, correct_total, min_value); + } + instance->extra_repeats = 0; + updated = true; + consumed = true; + } else if(event->key == InputKeyLeft && is_short) { + instance->extra_repeats = CLAMP(instance->extra_repeats - 1, max_repeats, 0); + + updated = true; + consumed = true; + } else if(event->key == InputKeyRight && is_short) { + instance->extra_repeats = CLAMP(instance->extra_repeats + 1, max_repeats, 0); + + updated = true; + consumed = true; + } else if(event->key == InputKeyOk && is_short) { + if(instance->index == SubBruteAttackLoadFile) { + instance->callback(SubBruteCustomEventTypeLoadFile, instance->context); + } else { + instance->callback(SubBruteCustomEventTypeMenuSelected, instance->context); + } + consumed = true; + updated = true; + } + if(updated) { + instance->window_position = instance->index; + if(instance->window_position > 0) { + instance->window_position -= 1; + } + + if(SubBruteAttackTotalCount <= ITEMS_ON_SCREEN) { + instance->window_position = 0; + } else { + if(instance->window_position >= (SubBruteAttackTotalCount - ITEMS_ON_SCREEN)) { + instance->window_position = (SubBruteAttackTotalCount - ITEMS_ON_SCREEN); + } + } + } + } else if(is_short) { + if(event->key == InputKeyLeft) { + if((instance->index > 0 && !instance->two_bytes) || + (instance->two_bytes && instance->index > 1)) { + instance->index--; + } + updated = true; + consumed = true; + } else if(event->key == InputKeyRight) { + if(instance->index < 7) { + instance->index++; + } + updated = true; + consumed = true; + } else if(event->key == InputKeyUp) { + instance->two_bytes = !instance->two_bytes; + // Because index is changing + if(instance->two_bytes && instance->index < 7) { + instance->index++; + } + // instance->callback( + // instance->two_bytes ? SubBruteCustomEventTypeChangeStepUp : + // SubBruteCustomEventTypeChangeStepDown, + // instance->context); + + updated = true; + consumed = true; + } else if(event->key == InputKeyOk) { + instance->callback(SubBruteCustomEventTypeIndexSelected, instance->context); + consumed = true; + updated = true; + } + } + + if(updated) { + with_view_model( + instance->view, + SubBruteMainViewModel * model, + { + model->index = instance->index; + model->window_position = instance->window_position; + model->key_from_file = instance->key_from_file; + model->is_select_byte = instance->is_select_byte; + model->two_bytes = instance->two_bytes; + model->extra_repeats = instance->extra_repeats; + }, + true); + } + + return consumed; +} + +void subbrute_main_view_enter(void* context) { + furi_assert(context); + +#ifdef FURI_DEBUG + FURI_LOG_D(TAG, "subbrute_main_view_enter"); +#endif +} + +void subbrute_main_view_exit(void* context) { + furi_assert(context); + +#ifdef FURI_DEBUG + FURI_LOG_D(TAG, "subbrute_main_view_exit"); +#endif +} + +SubBruteMainView* subbrute_main_view_alloc() { + SubBruteMainView* instance = malloc(sizeof(SubBruteMainView)); + instance->view = view_alloc(); + view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(SubBruteMainViewModel)); + view_set_context(instance->view, instance); + view_set_draw_callback(instance->view, (ViewDrawCallback)subbrute_main_view_draw); + view_set_input_callback(instance->view, subbrute_main_view_input); + view_set_enter_callback(instance->view, subbrute_main_view_enter); + view_set_exit_callback(instance->view, subbrute_main_view_exit); + + instance->index = 0; + instance->window_position = 0; + instance->key_from_file = 0; + instance->is_select_byte = false; + instance->two_bytes = false; + instance->extra_repeats = 0; + with_view_model( + instance->view, + SubBruteMainViewModel * model, + { + model->index = instance->index; + model->window_position = instance->window_position; + model->key_from_file = instance->key_from_file; + model->is_select_byte = instance->is_select_byte; + model->two_bytes = instance->two_bytes; + model->extra_repeats = instance->extra_repeats; + }, + true); + + return instance; +} + +void subbrute_main_view_free(SubBruteMainView* instance) { + furi_assert(instance); + + view_free(instance->view); + free(instance); +} + +View* subbrute_main_view_get_view(SubBruteMainView* instance) { + furi_assert(instance); + return instance->view; +} + +void subbrute_main_view_set_index( + SubBruteMainView* instance, + uint8_t idx, + bool is_select_byte, + bool two_bytes, + uint64_t key_from_file) { + furi_assert(instance); + furi_assert(idx < SubBruteAttackTotalCount); +#ifdef FURI_DEBUG + FURI_LOG_I(TAG, "Set index: %d, is_select_byte: %d", idx, is_select_byte); +#endif + instance->is_select_byte = is_select_byte; + instance->two_bytes = two_bytes; + instance->key_from_file = key_from_file; + instance->index = idx; + instance->window_position = idx; + + if(!is_select_byte) { + if(instance->window_position > 0) { + instance->window_position -= 1; + } + + if(SubBruteAttackTotalCount <= ITEMS_ON_SCREEN) { + instance->window_position = 0; + } else { + if(instance->window_position >= (SubBruteAttackTotalCount - ITEMS_ON_SCREEN)) { + instance->window_position = (SubBruteAttackTotalCount - ITEMS_ON_SCREEN); + } + } + } + + with_view_model( + instance->view, + SubBruteMainViewModel * model, + { + model->index = instance->index; + model->window_position = instance->window_position; + model->key_from_file = instance->key_from_file; + model->is_select_byte = instance->is_select_byte; + model->two_bytes = instance->two_bytes; + model->extra_repeats = instance->extra_repeats; + }, + true); +} + +SubBruteAttacks subbrute_main_view_get_index(SubBruteMainView* instance) { + furi_assert(instance); + return instance->index; +} + +uint8_t subbrute_main_view_get_extra_repeats(SubBruteMainView* instance) { + furi_assert(instance); + return instance->extra_repeats; +} + +bool subbrute_main_view_get_two_bytes(SubBruteMainView* instance) { + furi_assert(instance); + return instance->two_bytes; } \ No newline at end of file diff --git a/views/subbrute_main_view.h b/views/subbrute_main_view.h index 003cd9817db..b554cb21296 100644 --- a/views/subbrute_main_view.h +++ b/views/subbrute_main_view.h @@ -1,32 +1,32 @@ -#pragma once - -#include "../subbrute_custom_event.h" -#include "../subbrute_protocols.h" -#include -#include -#include - -typedef void (*SubBruteMainViewCallback)(SubBruteCustomEvent event, void* context); -typedef struct SubBruteMainView SubBruteMainView; - -void subbrute_main_view_set_callback( - SubBruteMainView* instance, - SubBruteMainViewCallback callback, - void* context); - -SubBruteMainView* subbrute_main_view_alloc(); -void subbrute_main_view_free(SubBruteMainView* instance); -View* subbrute_main_view_get_view(SubBruteMainView* instance); -void subbrute_main_view_set_index( - SubBruteMainView* instance, - uint8_t idx, - bool is_select_byte, - bool two_bytes, - uint64_t file_key); -SubBruteAttacks subbrute_main_view_get_index(SubBruteMainView* instance); -uint8_t subbrute_main_view_get_extra_repeats(SubBruteMainView* instance); -bool subbrute_main_view_get_two_bytes(SubBruteMainView* instance); -void subbrute_attack_view_enter(void* context); -void subbrute_attack_view_exit(void* context); -bool subbrute_attack_view_input(InputEvent* event, void* context); +#pragma once + +#include "../subbrute_custom_event.h" +#include "../subbrute_protocols.h" +#include +#include +#include + +typedef void (*SubBruteMainViewCallback)(SubBruteCustomEvent event, void* context); +typedef struct SubBruteMainView SubBruteMainView; + +void subbrute_main_view_set_callback( + SubBruteMainView* instance, + SubBruteMainViewCallback callback, + void* context); + +SubBruteMainView* subbrute_main_view_alloc(); +void subbrute_main_view_free(SubBruteMainView* instance); +View* subbrute_main_view_get_view(SubBruteMainView* instance); +void subbrute_main_view_set_index( + SubBruteMainView* instance, + uint8_t idx, + bool is_select_byte, + bool two_bytes, + uint64_t file_key); +SubBruteAttacks subbrute_main_view_get_index(SubBruteMainView* instance); +uint8_t subbrute_main_view_get_extra_repeats(SubBruteMainView* instance); +bool subbrute_main_view_get_two_bytes(SubBruteMainView* instance); +void subbrute_attack_view_enter(void* context); +void subbrute_attack_view_exit(void* context); +bool subbrute_attack_view_input(InputEvent* event, void* context); void subbrute_attack_view_draw(Canvas* canvas, void* context); \ No newline at end of file