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