Merge branch 'dev' into release
@@ -161,3 +161,10 @@ Max butthurt: 5
|
||||
Min level: 1
|
||||
Max level: 3
|
||||
Weight: 4
|
||||
|
||||
Name: L1_Sad_song_128x64
|
||||
Min butthurt: 8
|
||||
Max butthurt: 13
|
||||
Min level: 1
|
||||
Max level: 3
|
||||
Weight: 4
|
||||
|
||||
@@ -102,8 +102,8 @@ index 0000000..269b544
|
||||
+ .settings_is_loaded = false};
|
||||
+
|
||||
+static const RGBBacklightColor colors[] = {
|
||||
+ {"Orange", 255, 79, 0},
|
||||
+ {"Yellow", 255, 170, 0},
|
||||
+ {"Orange", 255, 60, 0},
|
||||
+ {"Yellow", 255, 150, 0},
|
||||
+ {"Spring", 167, 255, 0},
|
||||
+ {"Lime", 0, 255, 0},
|
||||
+ {"Aqua", 0, 255, 127},
|
||||
@@ -114,7 +114,7 @@ index 0000000..269b544
|
||||
+ {"Magenta", 210, 0, 210},
|
||||
+ {"Pink", 255, 0, 127},
|
||||
+ {"Red", 255, 0, 0},
|
||||
+ {"White", 140, 140, 140},
|
||||
+ {"White", 150, 150, 110},
|
||||
+};
|
||||
+
|
||||
+uint8_t rgb_backlight_get_color_count(void) {
|
||||
|
||||
156
.drone.yml
@@ -15,16 +15,38 @@ steps:
|
||||
- git submodule foreach git config --local gc.auto 0
|
||||
- git log -1 --format='%H'
|
||||
|
||||
- name: "Build firmware"
|
||||
- name: "Build clean"
|
||||
image: hfdj/fztools
|
||||
pull: never
|
||||
commands:
|
||||
- export DIST_SUFFIX=${DRONE_TAG}c
|
||||
- export WORKFLOW_BRANCH_OR_TAG=release-cfw
|
||||
- export FORCE_NO_DIRTY=yes
|
||||
- rm -rf assets/resources/apps/
|
||||
- rm -rf build/
|
||||
- rm -rf dist/
|
||||
- rm -rf .sconsign.dblite
|
||||
- ./fbt COMPACT=1 DEBUG=0 updater_package
|
||||
- mkdir artifacts-clean
|
||||
- mv dist/f7-C/* artifacts-clean/
|
||||
- ls -laS artifacts-clean
|
||||
- ls -laS artifacts-clean/f7-update-${DRONE_TAG}c
|
||||
environment:
|
||||
FBT_TOOLS_CUSTOM_LINK:
|
||||
from_secret: fbt_link
|
||||
|
||||
- name: "Build default"
|
||||
image: hfdj/fztools
|
||||
pull: never
|
||||
commands:
|
||||
- export DIST_SUFFIX=${DRONE_TAG}
|
||||
- export WORKFLOW_BRANCH_OR_TAG=release-cfw
|
||||
- rm -rf assets/resources/apps/
|
||||
- rm -rf build/
|
||||
- rm -rf dist/
|
||||
- rm -rf .sconsign.dblite
|
||||
- export FORCE_NO_DIRTY=yes
|
||||
- wget https://github.com/xMasterX/all-the-plugins/releases/latest/download/all-the-apps-base.tgz
|
||||
- tar zxvf all-the-apps-base.tgz
|
||||
- cp -R base_pack_build/artifacts-base/* assets/resources/apps/
|
||||
- rm -rf base_pack_build
|
||||
- rm -rf all-the-apps-base.tgz
|
||||
- ./fbt COMPACT=1 DEBUG=0 updater_package
|
||||
- mkdir artifacts-default
|
||||
- mv dist/f7-C/* artifacts-default/
|
||||
@@ -38,9 +60,10 @@ steps:
|
||||
image: hfdj/fztools
|
||||
pull: never
|
||||
commands:
|
||||
- git clone https://github.com/xMasterX/all-the-plugins.git
|
||||
- cp -R all-the-plugins/apps/* assets/resources/apps/
|
||||
- rm -rf all-the-plugins
|
||||
- wget https://github.com/xMasterX/all-the-plugins/releases/latest/download/all-the-apps-extra.tgz
|
||||
- tar zxvf all-the-apps-extra.tgz
|
||||
- cp -R extra_pack_build/artifacts-extra/* assets/resources/apps/
|
||||
- rm -rf extra_pack_build
|
||||
- export DIST_SUFFIX=${DRONE_TAG}e
|
||||
- export WORKFLOW_BRANCH_OR_TAG=release-cfw
|
||||
- export FORCE_NO_DIRTY=yes
|
||||
@@ -85,6 +108,11 @@ steps:
|
||||
- export WORKFLOW_BRANCH_OR_TAG=no-custom-anims
|
||||
- export FORCE_NO_DIRTY=yes
|
||||
- rm -f build/f7-firmware-C/toolbox/version.*
|
||||
- wget https://github.com/xMasterX/all-the-plugins/releases/latest/download/all-the-apps-base.tgz
|
||||
- tar zxvf all-the-apps-base.tgz
|
||||
- cp -R base_pack_build/artifacts-base/* assets/resources/apps/
|
||||
- rm -rf base_pack_build
|
||||
- rm -rf all-the-apps-base.tgz
|
||||
- ./fbt COMPACT=1 DEBUG=0 updater_package
|
||||
- mkdir artifacts-ofw-anims
|
||||
- mv dist/f7-C/* artifacts-ofw-anims/
|
||||
@@ -93,6 +121,8 @@ steps:
|
||||
- sed -i 's/(version)/'${DRONE_TAG}'/g' CHANGELOG.md
|
||||
- echo '# [Install via Web Updater](https://lab.flipper.net/?url=https://unleashedflip.com/fw/${DRONE_TAG}/flipper-z-f7-update-'${DRONE_TAG}'.tgz&channel=release-cfw&version='${DRONE_TAG}')' >> CHANGELOG.md
|
||||
- echo '' >> CHANGELOG.md
|
||||
- echo '### [Version with only main apps - Install via Web Updater](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_TAG}'c.tgz&channel=release-cfw&version='${DRONE_TAG}'c)' >> CHANGELOG.md
|
||||
- echo '' >> CHANGELOG.md
|
||||
- echo '### [Version without custom animations - Install via Web Updater](https://lab.flipper.net/?url=https://unleashedflip.com/fw_no_anim/flipper-z-f7-update-'${DRONE_TAG}'n.tgz&channel=release-cfw&version='${DRONE_TAG}'n)' >> CHANGELOG.md
|
||||
- echo '' >> CHANGELOG.md
|
||||
- echo '### [Version with RGB patch - only for hardware mod! - Install via Web Updater](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_TAG}'r.tgz&channel=release-cfw&version='${DRONE_TAG}'r)' >> CHANGELOG.md
|
||||
@@ -107,19 +137,23 @@ steps:
|
||||
commands:
|
||||
- cp artifacts-extra-apps/flipper-z-f7-update-${DRONE_TAG}e.tgz .
|
||||
- cp artifacts-rgb-patch/flipper-z-f7-update-${DRONE_TAG}r.tgz .
|
||||
- cp artifacts-clean/flipper-z-f7-update-${DRONE_TAG}c.tgz .
|
||||
- cp artifacts-ofw-anims/flipper-z-f7-update-${DRONE_TAG}n.tgz .
|
||||
- cp artifacts-default/flipper-z-f7-update-${DRONE_TAG}.tgz .
|
||||
- zip -r artifacts-extra-apps/flipper-z-f7-update-${DRONE_TAG}e.zip artifacts-extra-apps/f7-update-${DRONE_TAG}e
|
||||
- zip -r artifacts-rgb-patch/flipper-z-f7-update-${DRONE_TAG}r.zip artifacts-rgb-patch/f7-update-${DRONE_TAG}r
|
||||
- zip -r artifacts-clean/flipper-z-f7-update-${DRONE_TAG}c.zip artifacts-clean/f7-update-${DRONE_TAG}c
|
||||
- zip -r artifacts-ofw-anims/flipper-z-f7-update-${DRONE_TAG}n.zip artifacts-ofw-anims/f7-update-${DRONE_TAG}n
|
||||
- zip -r artifacts-default/flipper-z-f7-update-${DRONE_TAG}.zip artifacts-default/f7-update-${DRONE_TAG}
|
||||
- tar czpf artifacts-default/flipper-z-any-scripts-${DRONE_TAG}.tgz scripts
|
||||
- rm -rf artifacts-extra-apps/f7-update-${DRONE_TAG}
|
||||
- rm -rf artifacts-rgb-patch/f7-update-${DRONE_TAG}
|
||||
- rm -rf artifacts-clean/f7-update-${DRONE_TAG}
|
||||
- rm -rf artifacts-ofw-anims/f7-update-${DRONE_TAG}
|
||||
- rm -rf artifacts-default/f7-update-${DRONE_TAG}
|
||||
- ls -laS artifacts-extra-apps
|
||||
- ls -laS artifacts-rgb-patch
|
||||
- ls -laS artifacts-clean
|
||||
- ls -laS artifacts-ofw-anims
|
||||
- ls -laS artifacts-default
|
||||
- mv artifacts-default/ ${DRONE_TAG}
|
||||
@@ -191,6 +225,21 @@ steps:
|
||||
from_secret: dep_target_extra
|
||||
source: flipper-z-f7-update-${DRONE_TAG}r.tgz
|
||||
|
||||
- name: "Upload clean version to updates srv"
|
||||
image: appleboy/drone-scp:linux-amd64
|
||||
settings:
|
||||
host:
|
||||
from_secret: dep_host
|
||||
username:
|
||||
from_secret: dep_user
|
||||
password:
|
||||
from_secret: dep_passwd
|
||||
port:
|
||||
from_secret: dep_port
|
||||
target:
|
||||
from_secret: dep_target_extra
|
||||
source: flipper-z-f7-update-${DRONE_TAG}c.tgz
|
||||
|
||||
- name: "Do Github release"
|
||||
image: ddplugins/github-release
|
||||
pull: never
|
||||
@@ -206,6 +255,7 @@ steps:
|
||||
- artifacts-ofw-anims/*.tgz
|
||||
- artifacts-extra-apps/*.tgz
|
||||
- artifacts-rgb-patch/*.tgz
|
||||
- artifacts-clean/*.tgz
|
||||
title: ${DRONE_TAG}
|
||||
note: CHANGELOG.md
|
||||
checksum:
|
||||
@@ -253,6 +303,9 @@ steps:
|
||||
[-Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw/${DRONE_TAG}/flipper-z-f7-update-${DRONE_TAG}.tgz&channel=release-cfw&version=${DRONE_TAG})
|
||||
|
||||
|
||||
[-Version with only main apps - Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-${DRONE_TAG}c.tgz&channel=release-cfw&version=${DRONE_TAG}c)
|
||||
|
||||
|
||||
[-Version without custom animations - Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_no_anim/flipper-z-f7-update-${DRONE_TAG}n.tgz&channel=release-cfw&version=${DRONE_TAG}n)
|
||||
|
||||
|
||||
@@ -275,7 +328,19 @@ steps:
|
||||
commands:
|
||||
- wget "https://raw.githubusercontent.com/fieu/discord.sh/e1dc1a7595efad2cad8f072f0b3531c470f5b7c8/discord.sh"
|
||||
- chmod +x ./discord.sh
|
||||
- ./discord.sh --text 'New Unleashed firmware released!\n\nVersion - '${DRONE_TAG}'\n\n[-> Sponsor our project](https://boosty.to/mmxdev)\n\n[[Github - Changelog]](https://github.com/DarkFlippers/unleashed-firmware/releases/tag/'${DRONE_TAG}')\n\n[-How to install firmware-](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/HowToInstall.md)\n\n[-Download latest extra apps pack-](https://github.com/xMasterX/all-the-plugins/archive/refs/heads/main.zip)\n\n[-Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw/'${DRONE_TAG}'/flipper-z-f7-update-'${DRONE_TAG}'.tgz&channel=release-cfw&version='${DRONE_TAG}')\n\n[-Version without custom animations - Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_no_anim/flipper-z-f7-update-'${DRONE_TAG}'n.tgz&channel=release-cfw&version='${DRONE_TAG}'n)\n\n[-Version with RGB patch - only for hardware mod! - Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_TAG}'r.tgz&channel=release-cfw&version='${DRONE_TAG}'r)\n\n[-Version with RGB patch - only for hardware mod! - Direct download-](https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_TAG}'r.tgz)\n\n[-Version with Extra apps - Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_TAG}'e.tgz&channel=release-cfw&version='${DRONE_TAG}'e)'
|
||||
- ./discord.sh --text 'New Unleashed firmware released!\n\nVersion - '${DRONE_TAG}'\n\n[-> Sponsor our project](https://boosty.to/mmxdev)\n\n[[Github - Changelog]](https://github.com/DarkFlippers/unleashed-firmware/releases/tag/'${DRONE_TAG}')\n\n[-How to install firmware-](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/HowToInstall.md)\n\n[-Download latest extra apps pack-](https://github.com/xMasterX/all-the-plugins/archive/refs/heads/main.zip)\n\n[-Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw/'${DRONE_TAG}'/flipper-z-f7-update-'${DRONE_TAG}'.tgz&channel=release-cfw&version='${DRONE_TAG}')\n\n[-Version with only main apps - Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_TAG}'c.tgz&channel=release-cfw&version='${DRONE_TAG}'c)\n\n[-Version without custom animations - Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_no_anim/flipper-z-f7-update-'${DRONE_TAG}'n.tgz&channel=release-cfw&version='${DRONE_TAG}'n)\n\n[-Version with RGB patch - only for hardware mod! - Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_TAG}'r.tgz&channel=release-cfw&version='${DRONE_TAG}'r)\n\n[-Version with RGB patch - only for hardware mod! - Direct download-](https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_TAG}'r.tgz)\n\n[-Version with Extra apps - Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_TAG}'e.tgz&channel=release-cfw&version='${DRONE_TAG}'e)'
|
||||
|
||||
- name: "Send clean build to telegram"
|
||||
image: appleboy/drone-telegram
|
||||
settings:
|
||||
token:
|
||||
from_secret: tgtoken
|
||||
to:
|
||||
from_secret: tgid
|
||||
format: markdown
|
||||
message: "Build with only main apps:"
|
||||
document:
|
||||
- flipper-z-f7-update-${DRONE_TAG}c.tgz
|
||||
|
||||
- name: "Send extra pack build to telegram"
|
||||
image: appleboy/drone-telegram
|
||||
@@ -314,16 +379,39 @@ steps:
|
||||
- git submodule foreach git config --local gc.auto 0
|
||||
- git log -1 --format='%H'
|
||||
|
||||
- name: "Build dev FW"
|
||||
- name: "Build dev clean"
|
||||
image: hfdj/fztools
|
||||
pull: never
|
||||
commands:
|
||||
- export DIST_SUFFIX=${DRONE_BUILD_NUMBER}c
|
||||
- export WORKFLOW_BRANCH_OR_TAG=dev-cfw
|
||||
- export FORCE_NO_DIRTY=yes
|
||||
- rm -rf assets/resources/apps/
|
||||
- rm -rf build/
|
||||
- rm -rf dist/
|
||||
- rm -rf .sconsign.dblite
|
||||
- ./fbt COMPACT=1 DEBUG=0 updater_package
|
||||
- mkdir artifacts-clean
|
||||
- mv dist/f7-C/* artifacts-clean/
|
||||
- ls -laS artifacts-clean
|
||||
- ls -laS artifacts-clean/f7-update-${DRONE_BUILD_NUMBER}c
|
||||
environment:
|
||||
FBT_TOOLS_CUSTOM_LINK:
|
||||
from_secret: fbt_link
|
||||
|
||||
|
||||
- name: "Build dev default"
|
||||
image: hfdj/fztools
|
||||
pull: never
|
||||
commands:
|
||||
- export DIST_SUFFIX=${DRONE_BUILD_NUMBER}
|
||||
- export WORKFLOW_BRANCH_OR_TAG=dev-cfw
|
||||
- rm -rf assets/resources/apps/
|
||||
- rm -rf build/
|
||||
- rm -rf dist/
|
||||
- rm -rf .sconsign.dblite
|
||||
- export FORCE_NO_DIRTY=yes
|
||||
- wget https://github.com/xMasterX/all-the-plugins/releases/latest/download/all-the-apps-base.tgz
|
||||
- tar zxvf all-the-apps-base.tgz
|
||||
- cp -R base_pack_build/artifacts-base/* assets/resources/apps/
|
||||
- rm -rf base_pack_build
|
||||
- rm -rf all-the-apps-base.tgz
|
||||
- ./fbt COMPACT=1 DEBUG=0 updater_package
|
||||
- mkdir artifacts-default
|
||||
- mv dist/f7-C/* artifacts-default/
|
||||
@@ -337,9 +425,10 @@ steps:
|
||||
image: hfdj/fztools
|
||||
pull: never
|
||||
commands:
|
||||
- git clone --branch dev https://github.com/xMasterX/all-the-plugins.git
|
||||
- cp -R all-the-plugins/apps/* assets/resources/apps/
|
||||
- rm -rf all-the-plugins
|
||||
- wget https://github.com/xMasterX/all-the-plugins/releases/latest/download/all-the-apps-extra.tgz
|
||||
- tar zxvf all-the-apps-extra.tgz
|
||||
- cp -R extra_pack_build/artifacts-extra/* assets/resources/apps/
|
||||
- rm -rf extra_pack_build
|
||||
- export DIST_SUFFIX=${DRONE_BUILD_NUMBER}e
|
||||
- export WORKFLOW_BRANCH_OR_TAG=dev-cfw
|
||||
- export FORCE_NO_DIRTY=yes
|
||||
@@ -376,6 +465,7 @@ steps:
|
||||
commands:
|
||||
- cp artifacts-extra-apps/flipper-z-f7-update-${DRONE_BUILD_NUMBER}e.tgz .
|
||||
- cp artifacts-rgb-patch/flipper-z-f7-update-${DRONE_BUILD_NUMBER}r.tgz .
|
||||
- cp artifacts-clean/flipper-z-f7-update-${DRONE_BUILD_NUMBER}c.tgz .
|
||||
- cp artifacts-default/flipper-z-f7-update-${DRONE_BUILD_NUMBER}.tgz .
|
||||
- rm -rf artifacts-default/f7-update-${DRONE_BUILD_NUMBER}
|
||||
- ls -laS artifacts-default
|
||||
@@ -448,6 +538,21 @@ steps:
|
||||
from_secret: dep_target_extra
|
||||
source: flipper-z-f7-update-${DRONE_BUILD_NUMBER}r.tgz
|
||||
|
||||
- name: "Upload clean version to updates srv"
|
||||
image: appleboy/drone-scp:linux-amd64
|
||||
settings:
|
||||
host:
|
||||
from_secret: dep_host
|
||||
username:
|
||||
from_secret: dep_user
|
||||
password:
|
||||
from_secret: dep_passwd
|
||||
port:
|
||||
from_secret: dep_port
|
||||
target:
|
||||
from_secret: dep_target_extra
|
||||
source: flipper-z-f7-update-${DRONE_BUILD_NUMBER}c.tgz
|
||||
|
||||
- name: "Trigger update server reindex"
|
||||
image: hfdj/fztools
|
||||
pull: never
|
||||
@@ -482,6 +587,9 @@ steps:
|
||||
[-Install via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw/dev/flipper-z-f7-update-${DRONE_BUILD_NUMBER}.tgz&channel=dev-cfw&version=${DRONE_BUILD_NUMBER})
|
||||
|
||||
|
||||
[-Version with only main apps - Install via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-${DRONE_BUILD_NUMBER}c.tgz&channel=dev-cfw&version=${DRONE_BUILD_NUMBER}c)
|
||||
|
||||
|
||||
[-Version with RGB patch - only for hardware mod! - Install via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-${DRONE_BUILD_NUMBER}r.tgz&channel=dev-cfw&version=${DRONE_BUILD_NUMBER}r)
|
||||
|
||||
|
||||
@@ -502,6 +610,18 @@ steps:
|
||||
document:
|
||||
- dev/flipper-z-f7-update-${DRONE_BUILD_NUMBER}.tgz
|
||||
|
||||
- name: "Send clean build to telegram"
|
||||
image: appleboy/drone-telegram
|
||||
settings:
|
||||
token:
|
||||
from_secret: tgtoken
|
||||
to:
|
||||
from_secret: tgid_dev
|
||||
format: markdown
|
||||
message: "Clean (Main apps only) Build:"
|
||||
document:
|
||||
- flipper-z-f7-update-${DRONE_BUILD_NUMBER}c.tgz
|
||||
|
||||
- name: "Send extra pack build to telegram"
|
||||
image: appleboy/drone-telegram
|
||||
settings:
|
||||
@@ -523,7 +643,7 @@ steps:
|
||||
commands:
|
||||
- wget "https://raw.githubusercontent.com/fieu/discord.sh/e1dc1a7595efad2cad8f072f0b3531c470f5b7c8/discord.sh"
|
||||
- chmod +x ./discord.sh
|
||||
- ./discord.sh --text 'Unleashed firmware dev build successful!\n\nBuild - '${DRONE_BUILD_NUMBER}'\n\nCommit - https://github.com/DarkFlippers/unleashed-firmware/commit/'${DRONE_COMMIT_SHA}'\n\n[-> Sponsor our project](https://boosty.to/mmxdev)\n\n[-Version with Extra apps - Install via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_BUILD_NUMBER}'e.tgz&channel=dev-cfw&version='${DRONE_BUILD_NUMBER}'e)\n\n[-Version with RGB patch - only for hardware mod! - Install via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_BUILD_NUMBER}'r.tgz&channel=dev-cfw&version='${DRONE_BUILD_NUMBER}'r)\n\n[-Version with RGB patch - only for hardware mod! - Direct download-](https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_BUILD_NUMBER}'r.tgz)\n\n[-Install via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw/dev/flipper-z-f7-update-'${DRONE_BUILD_NUMBER}'.tgz&channel=dev-cfw&version='${DRONE_BUILD_NUMBER}')'
|
||||
- ./discord.sh --text 'Unleashed firmware dev build successful!\n\nBuild - '${DRONE_BUILD_NUMBER}'\n\nCommit - https://github.com/DarkFlippers/unleashed-firmware/commit/'${DRONE_COMMIT_SHA}'\n\n[-> Sponsor our project](https://boosty.to/mmxdev)\n\n[-Version with Extra apps - Install via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_BUILD_NUMBER}'e.tgz&channel=dev-cfw&version='${DRONE_BUILD_NUMBER}'e)\n\n[-Version with only main apps - Install via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_BUILD_NUMBER}'c.tgz&channel=dev-cfw&version='${DRONE_BUILD_NUMBER}'c)\n\n[-Version with RGB patch - only for hardware mod! - Install via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_BUILD_NUMBER}'r.tgz&channel=dev-cfw&version='${DRONE_BUILD_NUMBER}'r)\n\n[-Version with RGB patch - only for hardware mod! - Direct download-](https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_BUILD_NUMBER}'r.tgz)\n\n[-Install via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw/dev/flipper-z-f7-update-'${DRONE_BUILD_NUMBER}'.tgz&channel=dev-cfw&version='${DRONE_BUILD_NUMBER}')'
|
||||
|
||||
trigger:
|
||||
branch:
|
||||
|
||||
10
.gitmodules
vendored
@@ -10,6 +10,7 @@
|
||||
[submodule "assets/protobuf"]
|
||||
path = assets/protobuf
|
||||
url = https://github.com/flipperdevices/flipperzero-protobuf.git
|
||||
shallow = false
|
||||
[submodule "lib/libusb_stm32"]
|
||||
path = lib/libusb_stm32
|
||||
url = https://github.com/flipperdevices/libusb_stm32.git
|
||||
@@ -25,12 +26,6 @@
|
||||
[submodule "lib/cxxheaderparser"]
|
||||
path = lib/cxxheaderparser
|
||||
url = https://github.com/robotpy/cxxheaderparser.git
|
||||
[submodule "applications/external/dap_link/lib/free-dap"]
|
||||
path = applications/external/dap_link/lib/free-dap
|
||||
url = https://github.com/ataradov/free-dap.git
|
||||
[submodule "applications/external/subbrute"]
|
||||
path = applications/external/subbrute
|
||||
url = https://github.com/DarkFlippers/flipperzero-subbrute.git
|
||||
[submodule "lib/heatshrink"]
|
||||
path = lib/heatshrink
|
||||
url = https://github.com/flipperdevices/heatshrink.git
|
||||
@@ -43,6 +38,3 @@
|
||||
[submodule "lib/stm32wb_copro"]
|
||||
path = lib/stm32wb_copro
|
||||
url = https://github.com/flipperdevices/stm32wb_copro.git
|
||||
[submodule "applications/external/multi_fuzzer"]
|
||||
path = applications/external/multi_fuzzer
|
||||
url = https://github.com/DarkFlippers/Multi_Fuzzer.git
|
||||
|
||||
@@ -1 +1 @@
|
||||
--ignore-ccache -C gccarm --rules-config .pvsconfig -e lib/cmsis_core -e lib/fatfs -e lib/fnv1a-hash -e lib/FreeRTOS-Kernel -e lib/heatshrink -e lib/libusb_stm32 -e lib/littlefs -e lib/mbedtls -e lib/micro-ecc -e lib/microtar -e lib/mlib -e lib/qrcode -e lib/ST25RFAL002 -e lib/stm32wb_cmsis -e lib/stm32wb_copro -e lib/stm32wb_hal -e lib/u8g2 -e lib/nanopb -e */arm-none-eabi/* -e applications/external/dap_link/lib/free-dap
|
||||
--ignore-ccache -C gccarm --rules-config .pvsconfig -e lib/cmsis_core -e lib/fatfs -e lib/fnv1a-hash -e lib/FreeRTOS-Kernel -e lib/heatshrink -e lib/libusb_stm32 -e lib/littlefs -e lib/mbedtls -e lib/micro-ecc -e lib/microtar -e lib/mlib -e lib/qrcode -e lib/ST25RFAL002 -e lib/stm32wb_cmsis -e lib/stm32wb_copro -e lib/stm32wb_hal -e lib/u8g2 -e lib/nanopb -e */arm-none-eabi/*
|
||||
|
||||
9
.vscode/.gitignore
vendored
@@ -1,4 +1,5 @@
|
||||
./c_cpp_properties.json
|
||||
./launch.json
|
||||
./settings.json
|
||||
./tasks.json
|
||||
/c_cpp_properties.json
|
||||
/extensions.json
|
||||
/launch.json
|
||||
/settings.json
|
||||
/tasks.json
|
||||
|
||||
19
.vscode/example/clangd/extensions.json
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
// See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
|
||||
// Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
|
||||
// List of extensions which should be recommended for users of this workspace.
|
||||
"recommendations": [
|
||||
"ms-python.black-formatter",
|
||||
"llvm-vs-code-extensions.vscode-clangd",
|
||||
"amiralizadeh9480.cpp-helper",
|
||||
"marus25.cortex-debug",
|
||||
"zxh404.vscode-proto3",
|
||||
"augustocdias.tasks-shell-input"
|
||||
],
|
||||
// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
|
||||
"unwantedRecommendations": [
|
||||
"twxs.cmake",
|
||||
"ms-vscode.cpptools",
|
||||
"ms-vscode.cmake-tools"
|
||||
]
|
||||
}
|
||||
@@ -13,6 +13,7 @@
|
||||
],
|
||||
// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
|
||||
"unwantedRecommendations": [
|
||||
"llvm-vs-code-extensions.vscode-clangd",
|
||||
"twxs.cmake",
|
||||
"ms-vscode.cmake-tools"
|
||||
]
|
||||
9
.vscode/example/settings.json
vendored
@@ -21,5 +21,10 @@
|
||||
"SConscript": "python",
|
||||
"SConstruct": "python",
|
||||
"*.fam": "python",
|
||||
}
|
||||
}
|
||||
},
|
||||
"clangd.arguments": [
|
||||
// We might be able to tighten this a bit more to only include the correct toolchain.
|
||||
"--query-driver=**",
|
||||
"--compile-commands-dir=${workspaceFolder}/build/latest"
|
||||
]
|
||||
}
|
||||
54
CHANGELOG.md
@@ -1,25 +1,31 @@
|
||||
## New changes
|
||||
* SubGHz: Support for Ebyte E07 module power amp switch (works with TehRabbitt's Flux Capacitor Board) (by @Sil333033) (PR #559 by @Z3BRO) -> Remade by @xMasterX -> Driver code fixed and reworked by @gid9798
|
||||
* Infrared: Update universal remote assets (by @amec0e | PR #570)
|
||||
* Infrared: Update universal AC asset (by @Leptopt1los | PR #569)
|
||||
* Plugins: Add * in NFC Maker keyboard (hold `.`)
|
||||
* Plugins: Update TOTP (Authenticator) [(by akopachov)](https://github.com/akopachov/flipper-zero_authenticator)
|
||||
* Plugins: Update ESP32: WiFi Marauder companion plugin [(by 0xchocolate)](https://github.com/0xchocolate/flipperzero-wifi-marauder)
|
||||
* Plugins: Update ESP32-CAM -> Camera Suite [(by CodyTolene)](https://github.com/CodyTolene/Flipper-Zero-Camera-Suite) -> (PR #562 by @CodyTolene)
|
||||
* OFW PR 2949: IR: buttons move feature rework (by nminaylov)
|
||||
* OFW PR 2941: FDX-B temperature now uses system units (by Astrrra)
|
||||
* OFW: fbtenv: add additional environ variable to control execution flow
|
||||
* OFW: NFC CLI: Fix multiple apdu commands from not working when one of them gives an empty response
|
||||
* OFW: NFC: Fix MFC key invalidation
|
||||
* OFW: Rename Applications to Apps
|
||||
* OFW: Fix about screen
|
||||
* OFW: change FuriThreadPriorityIsr to 31 (configMAX_PRIORITIES-1)
|
||||
* OFW: External apps icounter
|
||||
* OFW: Overly missed feature: Infrared: move button (change button order in a remote)
|
||||
* OFW: Move U2F path to ext
|
||||
* OFW: New RTC flags in device info
|
||||
* OFW: Backlight notification fix
|
||||
* OFW: Fix fbtenv restore
|
||||
* NFC: Add manually MF Classic with custom UID (by @gid9798 | PR #571)
|
||||
* Infrared: Fix crash when frequency is outside of supported range, allow sending broken files by setting frequency to nearest border
|
||||
* Infrared: Updated AC universal asset (Legion LE-F30RH-IN added and other changes) (by @Leptopt1los | PR #577)
|
||||
* SubGHz: Fix Somfy Telis wrong frequency in add manually
|
||||
* SubGHz: Fix frequency out of bounds check causing crash/freeze
|
||||
* RGB Patch: Fix colors
|
||||
* Builds: New build (clean) `c` - comes only with main apps, use in case you don't want preinstalled apps pack
|
||||
* Plugins: Moved into one repo - https://github.com/xMasterX/all-the-plugins
|
||||
* OFW PR 2984: (only buffer changes was merged, other will be later) SubGhz: fix todo (by Skorpionm)
|
||||
* OFW PR 2980: Properly reset the NFC device data (by Astrrra)
|
||||
* OFW: SubGhz: add timeout to subghz_hal_async_tx_test_run
|
||||
* OFW: Improve vscode clangd experience
|
||||
* OFW: Add the Sad song animation
|
||||
* OFW: ufbt: fixed FAP_SRC_DIR
|
||||
* OFW: UI: Clock on Desktop -> Refactoring of our desktop clock
|
||||
* OFW: uFBT: devboard_flash to update WiFi devboard
|
||||
* OFW: FBT: devboard_flash to update WiFi devboard
|
||||
* OFW: Scripts: OB recovery
|
||||
* OFW: Expose additional functions of the crypto engine to user -> **Breaking API change 34.x -> 35.x**
|
||||
* OFW: External apps removed -> In our case - moved into extra plugins repo to separate plugins and firmware
|
||||
* OFW: BadUSB: qFlipper install script for MacOS
|
||||
* OFW: Add compressor.h to the SDK
|
||||
* OFW: fbt: Fix building using path with space
|
||||
* OFW: RPC: md5 in storage list
|
||||
* OFW: Fixes 2957 - subghz decode_raw
|
||||
* OFW: FDX-B temperature in system units
|
||||
* OFW: Infrared: buttons move feature rework
|
||||
|
||||
----
|
||||
|
||||
@@ -47,12 +53,14 @@ and all other great people who supported our project and me (xMasterX), thanks t
|
||||
|
||||
## **Recommended update option - Web Updater**
|
||||
|
||||
### What `n`, `r`, `e` means? What I need to download if I don't want to use Web updater?
|
||||
What build I should download and what this name means - `flipper-z-f7-update-(version)(n / r / e).tgz` ? <br>
|
||||
### What `n`, `r`, `e`, ` `, `c` means? What I need to download if I don't want to use Web updater?
|
||||
What build I should download and what this name means - `flipper-z-f7-update-(version)(n / r / e / c).tgz` ? <br>
|
||||
`flipper-z` = for Flipper Zero device<br>
|
||||
`f7` = Hardware version - same for all flipper zero devices<br>
|
||||
`update` = Update package, contains updater, all assets (plugins, IR libs, etc.), and firmware itself<br>
|
||||
`(version)` = Firmware version<br>
|
||||
` ` = this build comes with 3 custom animations, and default apps preinstalled<br>
|
||||
`c` = this build comes with 3 custom animations, and only main apps (Clean build)<br>
|
||||
`n` = this build comes without our custom animations (we have only 3 of them), only official flipper animations<br>
|
||||
`e` = build has 🎲 [extra apps pack](https://github.com/xMasterX/all-the-plugins) preinstalled<br>
|
||||
`r` = RGB patch (+ extra apps) for flippers with rgb backlight mod (this is hardware mod!) (Works only on modded flippers!) (do not install on non modded device!)
|
||||
|
||||
56
ReadMe.md
@@ -138,57 +138,7 @@ You can support us by using links or addresses below:
|
||||
|
||||
### Community apps included:
|
||||
|
||||
- **RFID Fuzzer** [(by @gid9798)](https://github.com/DarkFlippers/Multi_Fuzzer) (original by Ganapati & xMasterX)
|
||||
- **iButton Fuzzer** [(by @gid9798)](https://github.com/DarkFlippers/Multi_Fuzzer) (original by xMasterX)
|
||||
- **Sub-GHz bruteforcer** [(by @derskythe & xMasterX)](https://github.com/derskythe/flipperzero-subbrute) [(original by Ganapati & xMasterX)](https://github.com/DarkFlippers/unleashed-firmware/pull/57)
|
||||
- **Sub-GHz playlist** [(by darmiel)](https://github.com/DarkFlippers/unleashed-firmware/pull/62)
|
||||
- ESP8266 Deauther plugin [(by SequoiaSan)](https://github.com/SequoiaSan/FlipperZero-Wifi-ESP8266-Deauther-Module)
|
||||
- WiFi Scanner plugin [(by SequoiaSan)](https://github.com/SequoiaSan/FlipperZero-WiFi-Scanner_Module)
|
||||
- MultiConverter plugin [(by theisolinearchip)](https://github.com/theisolinearchip/flipperzero_stuff)
|
||||
- WAV Player [(OFW: DrZlo13)](https://github.com/flipperdevices/flipperzero-firmware/tree/zlo/wav-player) - Fixed and improved by [LTVA1](https://github.com/LTVA1/wav_player) -> Also outputs audio on `PA6` - `3(A6)` pin
|
||||
- Barcode Generator [(by Kingal1337)](https://github.com/Kingal1337/flipper-barcode-generator)
|
||||
- GPIO: Sentry Safe plugin [(by H4ckd4ddy)](https://github.com/H4ckd4ddy/flipperzero-sentry-safe-plugin)
|
||||
- ESP32: WiFi Marauder companion plugin [(by 0xchocolate)](https://github.com/0xchocolate/flipperzero-wifi-marauder) - Saving .pcap on flipper microSD [by tcpassos](https://github.com/tcpassos/flipperzero-firmware-with-wifi-marauder-companion) -> Only with custom marauder build (It is necessary to uncomment "#define WRITE_PACKETS_SERIAL" in configs.h (in marauder fw) and compile the firmware for the wifi board.) Or download precompiled build -> [Download esp32_marauder_ver_flipper_sd_serial.bin](https://github.com/justcallmekoko/ESP32Marauder/releases/latest)
|
||||
- NRF24: Sniffer & MouseJacker (with changes) [(by mothball187)](https://github.com/mothball187/flipperzero-nrf24/tree/main/mousejacker)
|
||||
- Simple Clock (timer by GMMan) [(original by CompaqDisc)](https://gist.github.com/CompaqDisc/4e329c501bd03c1e801849b81f48ea61)
|
||||
- **Sub-GHz Remote** [(by @gid9798)](https://github.com/gid9798)
|
||||
- Spectrum Analyzer (with changes) [(by jolcese)](https://github.com/jolcese/flipperzero-firmware/tree/spectrum/applications/spectrum_analyzer) - [Ultra Narrow mode & scan channels non-consecutively](https://github.com/theY4Kman/flipperzero-firmware/commits?author=theY4Kman)
|
||||
- Metronome [(by panki27)](https://github.com/panki27/Metronome)
|
||||
- DTMF Dolphin [(by litui)](https://github.com/litui/dtmf_dolphin)
|
||||
- **TOTP (Authenticator)** [(by akopachov)](https://github.com/akopachov/flipper-zero_authenticator)
|
||||
- GPS [(by ezod)](https://github.com/ezod/flipperzero-gps) works with module `NMEA 0183` via UART (13TX, 14RX, GND pins on Flipper)
|
||||
- i2c Tools [(by NaejEL)](https://github.com/NaejEL/flipperzero-i2ctools) - C0 -> SCL / C1 -> SDA / GND -> GND | 3v3 logic levels only!
|
||||
- HC-SR04 Distance sensor - Ported and modified by @xMasterX [(original by Sanqui)](https://github.com/Sanqui/flipperzero-firmware/tree/hc_sr04) - How to connect -> (5V -> VCC) / (GND -> GND) / (13|TX -> Trig) / (14|RX -> Echo)
|
||||
- Morse Code [(by wh00hw)](https://github.com/wh00hw/MorseCodeFAP)
|
||||
- **Unitemp - Temperature sensors reader** (DHT11/22, DS18B20, BMP280, HTU21x and more) [(by quen0n)](https://github.com/quen0n/unitemp-flipperzero)
|
||||
- Lightmeter [(by oleksiikutuzov)](https://github.com/oleksiikutuzov/flipperzero-lightmeter)
|
||||
- HEX Viewer [(by QtRoS)](https://github.com/QtRoS/flipper-zero-hex-viewer)
|
||||
- POCSAG Pager [(by xMasterX & Shmuma)](https://github.com/xMasterX/flipper-pager)
|
||||
- Text Viewer [(by kowalski7cc & kyhwana)](https://github.com/kowalski7cc/flipper-zero-text-viewer/tree/refactor-text-app)
|
||||
- **UART Terminal** [(by cool4uma)](https://github.com/cool4uma/UART_Terminal/tree/main)
|
||||
- **ProtoView** [(by antirez)](https://github.com/antirez/protoview)
|
||||
- **SWD Probe** [(by g3gg0)](https://github.com/g3gg0/flipper-swd_probe)
|
||||
- IR Scope [(by kallanreed)](https://github.com/DarkFlippers/unleashed-firmware/pull/407)
|
||||
- **BadBT** plugin (BT version of BadKB) [(by Willy-JL, ClaraCrazy, XFW contributors)](https://github.com/ClaraCrazy/Flipper-Xtreme/tree/dev/applications/main/bad_kb) (See in Applications->Tools) - (aka BadUSB via Bluetooth)
|
||||
- **Mifare Nested** [(by AloneLiberty)](https://github.com/AloneLiberty/FlipperNested) - Works with PC and python app `FlipperNested`
|
||||
- **NFC Maker** plugin (make tags with URLs, Wifi and other things) [(by Willy-JL)](https://github.com/ClaraCrazy/Flipper-Xtreme/tree/dev/applications/external/nfc_maker)
|
||||
- ESP32-CAM -> Camera Suite [(by CodyTolene)](https://github.com/CodyTolene/Flipper-Zero-Camera-Suite)
|
||||
|
||||
Games:
|
||||
- DOOM (ported and fixed by @xMasterX & @Svarich & @hedger) [(original by p4nic4ttack)](https://github.com/p4nic4ttack/doom-flipper-zero/)
|
||||
- Zombiez [(Reworked By DevMilanIan)](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/pull/240) [(Original By Dooskington)](https://github.com/Dooskington/flipperzero-zombiez)
|
||||
- Flappy Bird [(by DroomOne)](https://github.com/DroomOne/flipperzero-firmware/tree/dev/applications/flappy_bird)
|
||||
- Arkanoid (refactored by xMasterX) [(by gotnull)](https://github.com/gotnull/flipperzero-firmware-wPlugins)
|
||||
- Tic Tac Toe (refactored by xMasterX) [(by gotnull)](https://github.com/gotnull/flipperzero-firmware-wPlugins)
|
||||
- Tetris (with fixes) [(by jeffplang)](https://github.com/jeffplang/flipperzero-firmware/tree/tetris_game/applications/tetris_game)
|
||||
- Minesweeper [(by panki27)](https://github.com/panki27/minesweeper)
|
||||
- Heap Defence (aka Stack Attack) - Ported to latest firmware by @xMasterX - [(original by wquinoa & Vedmein)](https://github.com/Vedmein/flipperzero-firmware/tree/hd/svisto-perdelki)
|
||||
- Game15 [(by x27)](https://github.com/x27/flipperzero-game15)
|
||||
- Solitaire [(by teeebor)](https://github.com/teeebor/flipper_games)
|
||||
- BlackJack [(by teeebor)](https://github.com/teeebor/flipper_games)
|
||||
- 2048 game [(by eugene-kirzhanov)](https://github.com/eugene-kirzhanov/flipper-zero-2048-game)
|
||||
- Bomberduck [(by leo-need-more-coffee)](https://github.com/leo-need-more-coffee/flipperzero-bomberduck)
|
||||
- JetPack Joyride [(by timstrasser)](https://github.com/timstrasser)
|
||||
#### See full list and sources here: https://github.com/xMasterX/all-the-plugins/tree/dev
|
||||
|
||||
|
||||
# Instructions
|
||||
@@ -234,9 +184,9 @@ Games:
|
||||
|
||||
## [- How to use: Unitemp - Temperature sensors reader](https://github.com/quen0n/unitemp-flipperzero#readme)
|
||||
|
||||
## [- How to use: [NMEA] GPS](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/applications/external/gps_nmea_uart/README.md)
|
||||
## [- How to use: [NMEA] GPS](https://github.com/xMasterX/all-the-plugins/blob/dev/base_pack/gps_nmea_uart/README.md)
|
||||
|
||||
## [- How to use: i2c Tools](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/applications/external/flipper_i2ctools/README.md)
|
||||
## [- How to use: i2c Tools](https://github.com/xMasterX/all-the-plugins/blob/dev/base_pack/flipper_i2ctools/README.md)
|
||||
|
||||
## [- How to use: [NRF24] plugins](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/NRF24.md)
|
||||
|
||||
|
||||
13
SConstruct
@@ -45,6 +45,7 @@ distenv = coreenv.Clone(
|
||||
],
|
||||
ENV=os.environ,
|
||||
UPDATE_BUNDLE_DIR="dist/${DIST_DIR}/f${TARGET_HW}-update-${DIST_SUFFIX}",
|
||||
VSCODE_LANG_SERVER=ARGUMENTS.get("LANG_SERVER", "cpptools"),
|
||||
)
|
||||
|
||||
firmware_env = distenv.AddFwProject(
|
||||
@@ -327,6 +328,9 @@ distenv.PhonyTarget(
|
||||
"cli", "${PYTHON3} ${FBT_SCRIPT_DIR}/serial_cli.py -p ${FLIP_PORT}"
|
||||
)
|
||||
|
||||
# Update WiFi devboard firmware
|
||||
distenv.PhonyTarget("devboard_flash", "${PYTHON3} ${FBT_SCRIPT_DIR}/wifi_board.py")
|
||||
|
||||
|
||||
# Find blackmagic probe
|
||||
distenv.PhonyTarget(
|
||||
@@ -345,7 +349,14 @@ distenv.PhonyTarget(
|
||||
)
|
||||
|
||||
# Prepare vscode environment
|
||||
vscode_dist = distenv.Install("#.vscode", distenv.Glob("#.vscode/example/*"))
|
||||
VSCODE_LANG_SERVER = cmd_environment["LANG_SERVER"]
|
||||
vscode_dist = distenv.Install(
|
||||
"#.vscode",
|
||||
[
|
||||
distenv.Glob("#.vscode/example/*.json"),
|
||||
distenv.Glob(f"#.vscode/example/{VSCODE_LANG_SERVER}/*.json"),
|
||||
],
|
||||
)
|
||||
distenv.Precious(vscode_dist)
|
||||
distenv.NoClean(vscode_dist)
|
||||
distenv.Alias("vscode_dist", vscode_dist)
|
||||
|
||||
@@ -35,21 +35,6 @@ Applications for main Flipper menu.
|
||||
- `u2f` - U2F Application
|
||||
|
||||
|
||||
## External
|
||||
|
||||
External applications deployed to SD Card
|
||||
|
||||
- `clock` - Clock application
|
||||
- `dap_link` - DAP Link OnChip debugger
|
||||
- `hid_app` - USB/BT Remote controller
|
||||
- `music_player` - Music player app (demo)
|
||||
- `nfc_magic` - NFC MFC Magic card application
|
||||
- `picopass` - Picopass reader / writer
|
||||
- `signal_generator` - Signal generator app: PWM and clock generator
|
||||
- `snake_game` - Snake game application
|
||||
- `spi_mem_manager` - SPI Memory reader / flasher
|
||||
- `weather_station` - SubGHz weather station
|
||||
|
||||
## services
|
||||
|
||||
Background services providing system APIs to applications.
|
||||
|
||||
@@ -3,6 +3,7 @@ App(
|
||||
apptype=FlipperAppType.STARTUP,
|
||||
entry_point="unit_tests_on_system_start",
|
||||
cdefines=["APP_UNIT_TESTS"],
|
||||
requires=["system_settings"],
|
||||
provides=["delay_test"],
|
||||
order=100,
|
||||
)
|
||||
|
||||
602
applications/debug/unit_tests/furi_hal/furi_hal_crypto_tests.c
Normal file
@@ -0,0 +1,602 @@
|
||||
#include <stdio.h>
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include "../minunit.h"
|
||||
|
||||
static const uint8_t key_ctr_1[32] = {
|
||||
0x77, 0x6B, 0xEF, 0xF2, 0x85, 0x1D, 0xB0, 0x6F, 0x4C, 0x8A, 0x05, 0x42, 0xC8, 0x69, 0x6F, 0x6C,
|
||||
0x6A, 0x81, 0xAF, 0x1E, 0xEC, 0x96, 0xB4, 0xD3, 0x7F, 0xC1, 0xD6, 0x89, 0xE6, 0xC1, 0xC1, 0x04,
|
||||
};
|
||||
static const uint8_t iv_ctr_1[16] = {
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x60,
|
||||
0xDB,
|
||||
0x56,
|
||||
0x72,
|
||||
0xC9,
|
||||
0x7A,
|
||||
0xA8,
|
||||
0xF0,
|
||||
0xB2,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x01,
|
||||
};
|
||||
static const uint8_t pt_ctr_1[16] = {
|
||||
0x53,
|
||||
0x69,
|
||||
0x6E,
|
||||
0x67,
|
||||
0x6C,
|
||||
0x65,
|
||||
0x20,
|
||||
0x62,
|
||||
0x6C,
|
||||
0x6F,
|
||||
0x63,
|
||||
0x6B,
|
||||
0x20,
|
||||
0x6D,
|
||||
0x73,
|
||||
0x67,
|
||||
};
|
||||
static const uint8_t tv_ctr_ct_1[16] = {
|
||||
0x14,
|
||||
0x5A,
|
||||
0xD0,
|
||||
0x1D,
|
||||
0xBF,
|
||||
0x82,
|
||||
0x4E,
|
||||
0xC7,
|
||||
0x56,
|
||||
0x08,
|
||||
0x63,
|
||||
0xDC,
|
||||
0x71,
|
||||
0xE3,
|
||||
0xE0,
|
||||
0xC0,
|
||||
};
|
||||
|
||||
static const uint8_t key_ctr_2[32] = {
|
||||
0x77, 0x6B, 0xEF, 0xF2, 0x85, 0x1D, 0xB0, 0x6F, 0x4C, 0x8A, 0x05, 0x42, 0xC8, 0x69, 0x6F, 0x6C,
|
||||
0x6A, 0x81, 0xAF, 0x1E, 0xEC, 0x96, 0xB4, 0xD3, 0x7F, 0xC1, 0xD6, 0x89, 0xE6, 0xC1, 0xC1, 0x04,
|
||||
};
|
||||
static const uint8_t iv_ctr_2[16] = {
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x60,
|
||||
0xDB,
|
||||
0x56,
|
||||
0x72,
|
||||
0xC9,
|
||||
0x7A,
|
||||
0xA8,
|
||||
0xF0,
|
||||
0xB2,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x01,
|
||||
};
|
||||
static const uint8_t pt_ctr_2[0] = {};
|
||||
//static const uint8_t tv_ctr_ct_2[0] = {};
|
||||
|
||||
static const uint8_t key_ctr_3[32] = {
|
||||
0xF6, 0xD6, 0x6D, 0x6B, 0xD5, 0x2D, 0x59, 0xBB, 0x07, 0x96, 0x36, 0x58, 0x79, 0xEF, 0xF8, 0x86,
|
||||
0xC6, 0x6D, 0xD5, 0x1A, 0x5B, 0x6A, 0x99, 0x74, 0x4B, 0x50, 0x59, 0x0C, 0x87, 0xA2, 0x38, 0x84,
|
||||
};
|
||||
static const uint8_t iv_ctr_3[16] = {
|
||||
0x00,
|
||||
0xFA,
|
||||
0xAC,
|
||||
0x24,
|
||||
0xC1,
|
||||
0x58,
|
||||
0x5E,
|
||||
0xF1,
|
||||
0x5A,
|
||||
0x43,
|
||||
0xD8,
|
||||
0x75,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x01,
|
||||
};
|
||||
static const uint8_t pt_ctr_3[32] = {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
|
||||
};
|
||||
static const uint8_t tv_ctr_ct_3[32] = {
|
||||
0xF0, 0x5E, 0x23, 0x1B, 0x38, 0x94, 0x61, 0x2C, 0x49, 0xEE, 0x00, 0x0B, 0x80, 0x4E, 0xB2, 0xA9,
|
||||
0xB8, 0x30, 0x6B, 0x50, 0x8F, 0x83, 0x9D, 0x6A, 0x55, 0x30, 0x83, 0x1D, 0x93, 0x44, 0xAF, 0x1C,
|
||||
};
|
||||
|
||||
static const uint8_t key_ctr_4[32] = {
|
||||
0xFF, 0x7A, 0x61, 0x7C, 0xE6, 0x91, 0x48, 0xE4, 0xF1, 0x72, 0x6E, 0x2F, 0x43, 0x58, 0x1D, 0xE2,
|
||||
0xAA, 0x62, 0xD9, 0xF8, 0x05, 0x53, 0x2E, 0xDF, 0xF1, 0xEE, 0xD6, 0x87, 0xFB, 0x54, 0x15, 0x3D,
|
||||
};
|
||||
static const uint8_t iv_ctr_4[16] = {
|
||||
0x00,
|
||||
0x1C,
|
||||
0xC5,
|
||||
0xB7,
|
||||
0x51,
|
||||
0xA5,
|
||||
0x1D,
|
||||
0x70,
|
||||
0xA1,
|
||||
0xC1,
|
||||
0x11,
|
||||
0x48,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x01,
|
||||
};
|
||||
static const uint8_t pt_ctr_4[36] = {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
|
||||
0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23,
|
||||
};
|
||||
static const uint8_t tv_ctr_ct_4[36] = {
|
||||
0xEB, 0x6C, 0x52, 0x82, 0x1D, 0x0B, 0xBB, 0xF7, 0xCE, 0x75, 0x94, 0x46,
|
||||
0x2A, 0xCA, 0x4F, 0xAA, 0xB4, 0x07, 0xDF, 0x86, 0x65, 0x69, 0xFD, 0x07,
|
||||
0xF4, 0x8C, 0xC0, 0xB5, 0x83, 0xD6, 0x07, 0x1F, 0x1E, 0xC0, 0xE6, 0xB8,
|
||||
};
|
||||
|
||||
static const uint8_t key_ctr_5[32] = {
|
||||
0xFF, 0x7A, 0x61, 0x7C, 0xE6, 0x91, 0x48, 0xE4, 0xF1, 0x72, 0x6E, 0x2F, 0x43, 0x58, 0x1D, 0xE2,
|
||||
0xAA, 0x62, 0xD9, 0xF8, 0x05, 0x53, 0x2E, 0xDF, 0xF1, 0xEE, 0xD6, 0x87, 0xFB, 0x54, 0x15, 0x3D,
|
||||
};
|
||||
static const uint8_t iv_ctr_5[16] = {
|
||||
0x00,
|
||||
0x1C,
|
||||
0xC5,
|
||||
0xB7,
|
||||
0x51,
|
||||
0xA5,
|
||||
0x1D,
|
||||
0x70,
|
||||
0xA1,
|
||||
0xC1,
|
||||
0x11,
|
||||
0x48,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x01,
|
||||
};
|
||||
static const uint8_t pt_ctr_5[0] = {};
|
||||
//static const uint8_t tv_ctr_ct_5[0] = {};
|
||||
|
||||
static const uint8_t key_gcm_1[32] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
static const uint8_t iv_gcm_1[16] = {
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
};
|
||||
static const uint8_t pt_gcm_1[0] = {};
|
||||
//static const uint8_t tv_gcm_ct_1[0] = {};
|
||||
static const uint8_t aad_gcm_1[0] = {};
|
||||
static const uint8_t tv_gcm_tag_1[16] = {
|
||||
0x53,
|
||||
0x0F,
|
||||
0x8A,
|
||||
0xFB,
|
||||
0xC7,
|
||||
0x45,
|
||||
0x36,
|
||||
0xB9,
|
||||
0xA9,
|
||||
0x63,
|
||||
0xB4,
|
||||
0xF1,
|
||||
0xC4,
|
||||
0xCB,
|
||||
0x73,
|
||||
0x8B,
|
||||
};
|
||||
|
||||
static const uint8_t key_gcm_2[32] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
static const uint8_t iv_gcm_2[16] = {
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
};
|
||||
static const uint8_t pt_gcm_2[16] = {
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
};
|
||||
static const uint8_t tv_gcm_ct_2[16] = {
|
||||
0xCE,
|
||||
0xA7,
|
||||
0x40,
|
||||
0x3D,
|
||||
0x4D,
|
||||
0x60,
|
||||
0x6B,
|
||||
0x6E,
|
||||
0x07,
|
||||
0x4E,
|
||||
0xC5,
|
||||
0xD3,
|
||||
0xBA,
|
||||
0xF3,
|
||||
0x9D,
|
||||
0x18,
|
||||
};
|
||||
static const uint8_t aad_gcm_2[0] = {};
|
||||
static const uint8_t tv_gcm_tag_2[16] = {
|
||||
0xD0,
|
||||
0xD1,
|
||||
0xC8,
|
||||
0xA7,
|
||||
0x99,
|
||||
0x99,
|
||||
0x6B,
|
||||
0xF0,
|
||||
0x26,
|
||||
0x5B,
|
||||
0x98,
|
||||
0xB5,
|
||||
0xD4,
|
||||
0x8A,
|
||||
0xB9,
|
||||
0x19,
|
||||
};
|
||||
|
||||
static const uint8_t key_gcm_3[32] = {
|
||||
0xFE, 0xFF, 0xE9, 0x92, 0x86, 0x65, 0x73, 0x1C, 0x6D, 0x6A, 0x8F, 0x94, 0x67, 0x30, 0x83, 0x08,
|
||||
0xFE, 0xFF, 0xE9, 0x92, 0x86, 0x65, 0x73, 0x1C, 0x6D, 0x6A, 0x8F, 0x94, 0x67, 0x30, 0x83, 0x08,
|
||||
};
|
||||
static const uint8_t iv_gcm_3[16] = {
|
||||
0xCA,
|
||||
0xFE,
|
||||
0xBA,
|
||||
0xBE,
|
||||
0xFA,
|
||||
0xCE,
|
||||
0xDB,
|
||||
0xAD,
|
||||
0xDE,
|
||||
0xCA,
|
||||
0xF8,
|
||||
0x88,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
};
|
||||
static const uint8_t pt_gcm_3[64] = {
|
||||
0xD9, 0x31, 0x32, 0x25, 0xF8, 0x84, 0x06, 0xE5, 0xA5, 0x59, 0x09, 0xC5, 0xAF, 0xF5, 0x26, 0x9A,
|
||||
0x86, 0xA7, 0xA9, 0x53, 0x15, 0x34, 0xF7, 0xDA, 0x2E, 0x4C, 0x30, 0x3D, 0x8A, 0x31, 0x8A, 0x72,
|
||||
0x1C, 0x3C, 0x0C, 0x95, 0x95, 0x68, 0x09, 0x53, 0x2F, 0xCF, 0x0E, 0x24, 0x49, 0xA6, 0xB5, 0x25,
|
||||
0xB1, 0x6A, 0xED, 0xF5, 0xAA, 0x0D, 0xE6, 0x57, 0xBA, 0x63, 0x7B, 0x39, 0x1A, 0xAF, 0xD2, 0x55,
|
||||
};
|
||||
static const uint8_t tv_gcm_ct_3[64] = {
|
||||
0x52, 0x2D, 0xC1, 0xF0, 0x99, 0x56, 0x7D, 0x07, 0xF4, 0x7F, 0x37, 0xA3, 0x2A, 0x84, 0x42, 0x7D,
|
||||
0x64, 0x3A, 0x8C, 0xDC, 0xBF, 0xE5, 0xC0, 0xC9, 0x75, 0x98, 0xA2, 0xBD, 0x25, 0x55, 0xD1, 0xAA,
|
||||
0x8C, 0xB0, 0x8E, 0x48, 0x59, 0x0D, 0xBB, 0x3D, 0xA7, 0xB0, 0x8B, 0x10, 0x56, 0x82, 0x88, 0x38,
|
||||
0xC5, 0xF6, 0x1E, 0x63, 0x93, 0xBA, 0x7A, 0x0A, 0xBC, 0xC9, 0xF6, 0x62, 0x89, 0x80, 0x15, 0xAD,
|
||||
};
|
||||
static const uint8_t aad_gcm_3[0] = {};
|
||||
static const uint8_t tv_gcm_tag_3[16] = {
|
||||
0xB0,
|
||||
0x94,
|
||||
0xDA,
|
||||
0xC5,
|
||||
0xD9,
|
||||
0x34,
|
||||
0x71,
|
||||
0xBD,
|
||||
0xEC,
|
||||
0x1A,
|
||||
0x50,
|
||||
0x22,
|
||||
0x70,
|
||||
0xE3,
|
||||
0xCC,
|
||||
0x6C,
|
||||
};
|
||||
|
||||
static const uint8_t key_gcm_4[32] = {
|
||||
0xFE, 0xFF, 0xE9, 0x92, 0x86, 0x65, 0x73, 0x1C, 0x6D, 0x6A, 0x8F, 0x94, 0x67, 0x30, 0x83, 0x08,
|
||||
0xFE, 0xFF, 0xE9, 0x92, 0x86, 0x65, 0x73, 0x1C, 0x6D, 0x6A, 0x8F, 0x94, 0x67, 0x30, 0x83, 0x08,
|
||||
};
|
||||
static const uint8_t iv_gcm_4[16] = {
|
||||
0xCA,
|
||||
0xFE,
|
||||
0xBA,
|
||||
0xBE,
|
||||
0xFA,
|
||||
0xCE,
|
||||
0xDB,
|
||||
0xAD,
|
||||
0xDE,
|
||||
0xCA,
|
||||
0xF8,
|
||||
0x88,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
};
|
||||
static const uint8_t pt_gcm_4[60] = {
|
||||
0xD9, 0x31, 0x32, 0x25, 0xF8, 0x84, 0x06, 0xE5, 0xA5, 0x59, 0x09, 0xC5, 0xAF, 0xF5, 0x26,
|
||||
0x9A, 0x86, 0xA7, 0xA9, 0x53, 0x15, 0x34, 0xF7, 0xDA, 0x2E, 0x4C, 0x30, 0x3D, 0x8A, 0x31,
|
||||
0x8A, 0x72, 0x1C, 0x3C, 0x0C, 0x95, 0x95, 0x68, 0x09, 0x53, 0x2F, 0xCF, 0x0E, 0x24, 0x49,
|
||||
0xA6, 0xB5, 0x25, 0xB1, 0x6A, 0xED, 0xF5, 0xAA, 0x0D, 0xE6, 0x57, 0xBA, 0x63, 0x7B, 0x39,
|
||||
};
|
||||
static const uint8_t tv_gcm_ct_4[60] = {
|
||||
0x52, 0x2D, 0xC1, 0xF0, 0x99, 0x56, 0x7D, 0x07, 0xF4, 0x7F, 0x37, 0xA3, 0x2A, 0x84, 0x42,
|
||||
0x7D, 0x64, 0x3A, 0x8C, 0xDC, 0xBF, 0xE5, 0xC0, 0xC9, 0x75, 0x98, 0xA2, 0xBD, 0x25, 0x55,
|
||||
0xD1, 0xAA, 0x8C, 0xB0, 0x8E, 0x48, 0x59, 0x0D, 0xBB, 0x3D, 0xA7, 0xB0, 0x8B, 0x10, 0x56,
|
||||
0x82, 0x88, 0x38, 0xC5, 0xF6, 0x1E, 0x63, 0x93, 0xBA, 0x7A, 0x0A, 0xBC, 0xC9, 0xF6, 0x62,
|
||||
};
|
||||
static const uint8_t aad_gcm_4[20] = {
|
||||
0xFE, 0xED, 0xFA, 0xCE, 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED,
|
||||
0xFA, 0xCE, 0xDE, 0xAD, 0xBE, 0xEF, 0xAB, 0xAD, 0xDA, 0xD2,
|
||||
};
|
||||
static const uint8_t tv_gcm_tag_4[16] = {
|
||||
0x76,
|
||||
0xFC,
|
||||
0x6E,
|
||||
0xCE,
|
||||
0x0F,
|
||||
0x4E,
|
||||
0x17,
|
||||
0x68,
|
||||
0xCD,
|
||||
0xDF,
|
||||
0x88,
|
||||
0x53,
|
||||
0xBB,
|
||||
0x2D,
|
||||
0x55,
|
||||
0x1B,
|
||||
};
|
||||
|
||||
static void furi_hal_crypto_ctr_setup() {
|
||||
}
|
||||
|
||||
static void furi_hal_crypto_ctr_teardown() {
|
||||
}
|
||||
|
||||
static void furi_hal_crypto_gcm_setup() {
|
||||
}
|
||||
|
||||
static void furi_hal_crypto_gcm_teardown() {
|
||||
}
|
||||
|
||||
MU_TEST(furi_hal_crypto_ctr_1) {
|
||||
bool ret = false;
|
||||
uint8_t ct[sizeof(pt_ctr_1)];
|
||||
|
||||
ret = furi_hal_crypto_ctr(key_ctr_1, iv_ctr_1, pt_ctr_1, ct, sizeof(pt_ctr_1));
|
||||
mu_assert(ret, "CTR 1 failed");
|
||||
mu_assert_mem_eq(tv_ctr_ct_1, ct, sizeof(pt_ctr_1));
|
||||
}
|
||||
|
||||
MU_TEST(furi_hal_crypto_ctr_2) {
|
||||
bool ret = false;
|
||||
uint8_t ct[sizeof(pt_ctr_2)];
|
||||
|
||||
ret = furi_hal_crypto_ctr(key_ctr_2, iv_ctr_2, pt_ctr_2, ct, sizeof(pt_ctr_2));
|
||||
mu_assert(ret, "CTR 2 failed");
|
||||
//mu_assert_mem_eq(tv_ctr_ct_2, ct, sizeof(pt_ctr_2));
|
||||
}
|
||||
|
||||
MU_TEST(furi_hal_crypto_ctr_3) {
|
||||
bool ret = false;
|
||||
uint8_t ct[sizeof(pt_ctr_3)];
|
||||
|
||||
ret = furi_hal_crypto_ctr(key_ctr_3, iv_ctr_3, pt_ctr_3, ct, sizeof(pt_ctr_3));
|
||||
mu_assert(ret, "CTR 3 failed");
|
||||
mu_assert_mem_eq(tv_ctr_ct_3, ct, sizeof(pt_ctr_3));
|
||||
}
|
||||
|
||||
MU_TEST(furi_hal_crypto_ctr_4) {
|
||||
bool ret = false;
|
||||
uint8_t ct[sizeof(pt_ctr_4)];
|
||||
|
||||
ret = furi_hal_crypto_ctr(key_ctr_4, iv_ctr_4, pt_ctr_4, ct, sizeof(pt_ctr_4));
|
||||
mu_assert(ret, "CTR 4 failed");
|
||||
mu_assert_mem_eq(tv_ctr_ct_4, ct, sizeof(pt_ctr_4));
|
||||
}
|
||||
|
||||
MU_TEST(furi_hal_crypto_ctr_5) {
|
||||
bool ret = false;
|
||||
uint8_t ct[sizeof(pt_ctr_5)];
|
||||
|
||||
ret = furi_hal_crypto_ctr(key_ctr_5, iv_ctr_5, pt_ctr_5, ct, sizeof(pt_ctr_5));
|
||||
mu_assert(ret, "CTR 5 failed");
|
||||
//mu_assert_mem_eq(tv_ctr_ct_5, ct, sizeof(pt_ctr_5));
|
||||
}
|
||||
|
||||
MU_TEST(furi_hal_crypto_gcm_1) {
|
||||
bool ret = false;
|
||||
uint8_t pt[sizeof(pt_gcm_1)];
|
||||
uint8_t ct[sizeof(pt_gcm_1)];
|
||||
uint8_t tag_enc[16];
|
||||
uint8_t tag_dec[16];
|
||||
|
||||
ret = furi_hal_crypto_gcm(
|
||||
key_gcm_1,
|
||||
iv_gcm_1,
|
||||
aad_gcm_1,
|
||||
sizeof(aad_gcm_1),
|
||||
pt_gcm_1,
|
||||
ct,
|
||||
sizeof(pt_gcm_1),
|
||||
tag_enc,
|
||||
false);
|
||||
mu_assert(ret, "GCM 1 encryption failed");
|
||||
//mu_assert_mem_eq(tv_gcm_ct_1, ct, sizeof(pt_gcm_1));
|
||||
mu_assert_mem_eq(tv_gcm_tag_1, tag_enc, 16);
|
||||
|
||||
ret = furi_hal_crypto_gcm(
|
||||
key_gcm_1, iv_gcm_1, aad_gcm_1, sizeof(aad_gcm_1), ct, pt, sizeof(pt_gcm_1), tag_dec, true);
|
||||
mu_assert(ret, "GCM 1 decryption failed");
|
||||
//mu_assert_mem_eq(pt_gcm_1, pt, sizeof(pt_gcm_1));
|
||||
mu_assert_mem_eq(tv_gcm_tag_1, tag_dec, 16);
|
||||
}
|
||||
|
||||
MU_TEST(furi_hal_crypto_gcm_2) {
|
||||
bool ret = false;
|
||||
uint8_t pt[sizeof(pt_gcm_2)];
|
||||
uint8_t ct[sizeof(pt_gcm_2)];
|
||||
uint8_t tag_enc[16];
|
||||
uint8_t tag_dec[16];
|
||||
|
||||
ret = furi_hal_crypto_gcm(
|
||||
key_gcm_2,
|
||||
iv_gcm_2,
|
||||
aad_gcm_2,
|
||||
sizeof(aad_gcm_2),
|
||||
pt_gcm_2,
|
||||
ct,
|
||||
sizeof(pt_gcm_2),
|
||||
tag_enc,
|
||||
false);
|
||||
mu_assert(ret, "GCM 2 encryption failed");
|
||||
mu_assert_mem_eq(tv_gcm_ct_2, ct, sizeof(pt_gcm_2));
|
||||
mu_assert_mem_eq(tv_gcm_tag_2, tag_enc, 16);
|
||||
|
||||
ret = furi_hal_crypto_gcm(
|
||||
key_gcm_2, iv_gcm_2, aad_gcm_2, sizeof(aad_gcm_2), ct, pt, sizeof(pt_gcm_2), tag_dec, true);
|
||||
mu_assert(ret, "GCM 2 decryption failed");
|
||||
mu_assert_mem_eq(pt_gcm_2, pt, sizeof(pt_gcm_2));
|
||||
mu_assert_mem_eq(tv_gcm_tag_2, tag_dec, 16);
|
||||
}
|
||||
|
||||
MU_TEST(furi_hal_crypto_gcm_3) {
|
||||
bool ret = false;
|
||||
uint8_t pt[sizeof(pt_gcm_3)];
|
||||
uint8_t ct[sizeof(pt_gcm_3)];
|
||||
uint8_t tag_enc[16];
|
||||
uint8_t tag_dec[16];
|
||||
|
||||
ret = furi_hal_crypto_gcm(
|
||||
key_gcm_3,
|
||||
iv_gcm_3,
|
||||
aad_gcm_3,
|
||||
sizeof(aad_gcm_3),
|
||||
pt_gcm_3,
|
||||
ct,
|
||||
sizeof(pt_gcm_3),
|
||||
tag_enc,
|
||||
false);
|
||||
mu_assert(ret, "GCM 3 encryption failed");
|
||||
mu_assert_mem_eq(tv_gcm_ct_3, ct, sizeof(pt_gcm_3));
|
||||
mu_assert_mem_eq(tv_gcm_tag_3, tag_enc, 16);
|
||||
|
||||
ret = furi_hal_crypto_gcm(
|
||||
key_gcm_3, iv_gcm_3, aad_gcm_3, sizeof(aad_gcm_3), ct, pt, sizeof(pt_gcm_3), tag_dec, true);
|
||||
mu_assert(ret, "GCM 3 decryption failed");
|
||||
mu_assert_mem_eq(pt_gcm_3, pt, sizeof(pt_gcm_3));
|
||||
mu_assert_mem_eq(tv_gcm_tag_3, tag_dec, 16);
|
||||
}
|
||||
|
||||
MU_TEST(furi_hal_crypto_gcm_4) {
|
||||
bool ret = false;
|
||||
uint8_t pt[sizeof(pt_gcm_4)];
|
||||
uint8_t ct[sizeof(pt_gcm_4)];
|
||||
uint8_t tag_enc[16];
|
||||
uint8_t tag_dec[16];
|
||||
|
||||
ret = furi_hal_crypto_gcm(
|
||||
key_gcm_4,
|
||||
iv_gcm_4,
|
||||
aad_gcm_4,
|
||||
sizeof(aad_gcm_4),
|
||||
pt_gcm_4,
|
||||
ct,
|
||||
sizeof(pt_gcm_4),
|
||||
tag_enc,
|
||||
false);
|
||||
mu_assert(ret, "GCM 4 encryption failed");
|
||||
mu_assert_mem_eq(tv_gcm_ct_4, ct, sizeof(pt_gcm_4));
|
||||
mu_assert_mem_eq(tv_gcm_tag_4, tag_enc, 16);
|
||||
|
||||
ret = furi_hal_crypto_gcm(
|
||||
key_gcm_4, iv_gcm_4, aad_gcm_4, sizeof(aad_gcm_4), ct, pt, sizeof(pt_gcm_4), tag_dec, true);
|
||||
mu_assert(ret, "GCM 4 decryption failed");
|
||||
mu_assert_mem_eq(pt_gcm_4, pt, sizeof(pt_gcm_4));
|
||||
mu_assert_mem_eq(tv_gcm_tag_4, tag_dec, 16);
|
||||
}
|
||||
|
||||
MU_TEST_SUITE(furi_hal_crypto_ctr_test) {
|
||||
MU_SUITE_CONFIGURE(&furi_hal_crypto_ctr_setup, &furi_hal_crypto_ctr_teardown);
|
||||
MU_RUN_TEST(furi_hal_crypto_ctr_1);
|
||||
MU_RUN_TEST(furi_hal_crypto_ctr_2);
|
||||
MU_RUN_TEST(furi_hal_crypto_ctr_3);
|
||||
MU_RUN_TEST(furi_hal_crypto_ctr_4);
|
||||
MU_RUN_TEST(furi_hal_crypto_ctr_5);
|
||||
}
|
||||
|
||||
MU_TEST_SUITE(furi_hal_crypto_gcm_test) {
|
||||
MU_SUITE_CONFIGURE(&furi_hal_crypto_gcm_setup, &furi_hal_crypto_gcm_teardown);
|
||||
MU_RUN_TEST(furi_hal_crypto_gcm_1);
|
||||
MU_RUN_TEST(furi_hal_crypto_gcm_2);
|
||||
MU_RUN_TEST(furi_hal_crypto_gcm_3);
|
||||
MU_RUN_TEST(furi_hal_crypto_gcm_4);
|
||||
}
|
||||
|
||||
int run_minunit_test_furi_hal_crypto() {
|
||||
MU_RUN_SUITE(furi_hal_crypto_ctr_test);
|
||||
MU_RUN_SUITE(furi_hal_crypto_gcm_test);
|
||||
return MU_EXIT_CODE;
|
||||
}
|
||||
@@ -13,7 +13,7 @@
|
||||
#include <pb.h>
|
||||
#include <pb_encode.h>
|
||||
#include <m-list.h>
|
||||
#include <lib/toolbox/md5.h>
|
||||
#include <lib/toolbox/md5_calc.h>
|
||||
#include <lib/toolbox/path.h>
|
||||
#include <cli/cli.h>
|
||||
#include <loader/loader.h>
|
||||
@@ -287,7 +287,8 @@ static void test_rpc_create_simple_message(
|
||||
PB_Main* message,
|
||||
uint16_t tag,
|
||||
const char* str,
|
||||
uint32_t command_id) {
|
||||
uint32_t command_id,
|
||||
bool flag) {
|
||||
furi_check(message);
|
||||
|
||||
char* str_copy = NULL;
|
||||
@@ -308,6 +309,7 @@ static void test_rpc_create_simple_message(
|
||||
break;
|
||||
case PB_Main_storage_list_request_tag:
|
||||
message->content.storage_list_request.path = str_copy;
|
||||
message->content.storage_list_request.include_md5 = flag;
|
||||
break;
|
||||
case PB_Main_storage_mkdir_request_tag:
|
||||
message->content.storage_mkdir_request.path = str_copy;
|
||||
@@ -419,6 +421,7 @@ static void
|
||||
}
|
||||
mu_check(result_msg_file->size == expected_msg_file->size);
|
||||
mu_check(result_msg_file->type == expected_msg_file->type);
|
||||
mu_assert_string_eq(expected_msg_file->md5sum, result_msg_file->md5sum);
|
||||
|
||||
if(result_msg_file->data && result_msg_file->type != PB_Storage_File_FileType_DIR) {
|
||||
mu_check(!result_msg_file->data == !expected_msg_file->data); // Zlo: WTF???
|
||||
@@ -430,10 +433,10 @@ static void
|
||||
}
|
||||
|
||||
static void test_rpc_compare_messages(PB_Main* result, PB_Main* expected) {
|
||||
mu_check(result->command_id == expected->command_id);
|
||||
mu_check(result->command_status == expected->command_status);
|
||||
mu_check(result->has_next == expected->has_next);
|
||||
mu_check(result->which_content == expected->which_content);
|
||||
mu_assert_int_eq(expected->command_id, result->command_id);
|
||||
mu_assert_int_eq(expected->command_status, result->command_status);
|
||||
mu_assert_int_eq(expected->has_next, result->has_next);
|
||||
mu_assert_int_eq(expected->which_content, result->which_content);
|
||||
if(result->command_status != PB_CommandStatus_OK) {
|
||||
mu_check(result->which_content == PB_Main_empty_tag);
|
||||
}
|
||||
@@ -573,10 +576,15 @@ static void
|
||||
static void test_rpc_storage_list_create_expected_list(
|
||||
MsgList_t msg_list,
|
||||
const char* path,
|
||||
uint32_t command_id) {
|
||||
uint32_t command_id,
|
||||
bool append_md5) {
|
||||
Storage* fs_api = furi_record_open(RECORD_STORAGE);
|
||||
File* dir = storage_file_alloc(fs_api);
|
||||
|
||||
FuriString* md5 = furi_string_alloc();
|
||||
FuriString* md5_path = furi_string_alloc();
|
||||
File* file = storage_file_alloc(fs_api);
|
||||
|
||||
PB_Main response = {
|
||||
.command_id = command_id,
|
||||
.has_next = false,
|
||||
@@ -614,6 +622,17 @@ static void test_rpc_storage_list_create_expected_list(
|
||||
list->file[i].data = NULL;
|
||||
/* memory free inside rpc_encode_and_send() -> pb_release() */
|
||||
list->file[i].name = name;
|
||||
|
||||
if(append_md5 && !file_info_is_dir(&fileinfo)) {
|
||||
furi_string_printf(md5_path, "%s/%s", path, name);
|
||||
|
||||
if(md5_string_calc_file(file, furi_string_get_cstr(md5_path), md5, NULL)) {
|
||||
char* md5sum = list->file[i].md5sum;
|
||||
size_t md5sum_size = sizeof(list->file[i].md5sum);
|
||||
snprintf(md5sum, md5sum_size, "%s", furi_string_get_cstr(md5));
|
||||
}
|
||||
}
|
||||
|
||||
++i;
|
||||
}
|
||||
} else {
|
||||
@@ -626,6 +645,10 @@ static void test_rpc_storage_list_create_expected_list(
|
||||
response.has_next = false;
|
||||
MsgList_push_back(msg_list, response);
|
||||
|
||||
furi_string_free(md5);
|
||||
furi_string_free(md5_path);
|
||||
storage_file_free(file);
|
||||
|
||||
storage_dir_close(dir);
|
||||
storage_file_free(dir);
|
||||
|
||||
@@ -675,16 +698,17 @@ static void test_rpc_free_msg_list(MsgList_t msg_list) {
|
||||
MsgList_clear(msg_list);
|
||||
}
|
||||
|
||||
static void test_rpc_storage_list_run(const char* path, uint32_t command_id) {
|
||||
static void test_rpc_storage_list_run(const char* path, uint32_t command_id, bool md5) {
|
||||
PB_Main request;
|
||||
MsgList_t expected_msg_list;
|
||||
MsgList_init(expected_msg_list);
|
||||
|
||||
test_rpc_create_simple_message(&request, PB_Main_storage_list_request_tag, path, command_id);
|
||||
test_rpc_create_simple_message(
|
||||
&request, PB_Main_storage_list_request_tag, path, command_id, md5);
|
||||
if(!strcmp(path, "/")) {
|
||||
test_rpc_storage_list_create_expected_list_root(expected_msg_list, command_id);
|
||||
} else {
|
||||
test_rpc_storage_list_create_expected_list(expected_msg_list, path, command_id);
|
||||
test_rpc_storage_list_create_expected_list(expected_msg_list, path, command_id, md5);
|
||||
}
|
||||
test_rpc_encode_and_feed_one(&request, 0);
|
||||
test_rpc_decode_and_compare(expected_msg_list, 0);
|
||||
@@ -694,15 +718,25 @@ static void test_rpc_storage_list_run(const char* path, uint32_t command_id) {
|
||||
}
|
||||
|
||||
MU_TEST(test_storage_list) {
|
||||
test_rpc_storage_list_run("/", ++command_id);
|
||||
test_rpc_storage_list_run(EXT_PATH("nfc"), ++command_id);
|
||||
test_rpc_storage_list_run("/", ++command_id, false);
|
||||
test_rpc_storage_list_run(EXT_PATH("nfc"), ++command_id, false);
|
||||
test_rpc_storage_list_run(STORAGE_INT_PATH_PREFIX, ++command_id, false);
|
||||
test_rpc_storage_list_run(STORAGE_EXT_PATH_PREFIX, ++command_id, false);
|
||||
test_rpc_storage_list_run(EXT_PATH("infrared"), ++command_id, false);
|
||||
test_rpc_storage_list_run(EXT_PATH("ibutton"), ++command_id, false);
|
||||
test_rpc_storage_list_run(EXT_PATH("lfrfid"), ++command_id, false);
|
||||
test_rpc_storage_list_run("error_path", ++command_id, false);
|
||||
}
|
||||
|
||||
test_rpc_storage_list_run(STORAGE_INT_PATH_PREFIX, ++command_id);
|
||||
test_rpc_storage_list_run(STORAGE_EXT_PATH_PREFIX, ++command_id);
|
||||
test_rpc_storage_list_run(EXT_PATH("infrared"), ++command_id);
|
||||
test_rpc_storage_list_run(EXT_PATH("ibutton"), ++command_id);
|
||||
test_rpc_storage_list_run(EXT_PATH("lfrfid"), ++command_id);
|
||||
test_rpc_storage_list_run("error_path", ++command_id);
|
||||
MU_TEST(test_storage_list_md5) {
|
||||
test_rpc_storage_list_run("/", ++command_id, true);
|
||||
test_rpc_storage_list_run(EXT_PATH("nfc"), ++command_id, true);
|
||||
test_rpc_storage_list_run(STORAGE_INT_PATH_PREFIX, ++command_id, true);
|
||||
test_rpc_storage_list_run(STORAGE_EXT_PATH_PREFIX, ++command_id, true);
|
||||
test_rpc_storage_list_run(EXT_PATH("infrared"), ++command_id, true);
|
||||
test_rpc_storage_list_run(EXT_PATH("ibutton"), ++command_id, true);
|
||||
test_rpc_storage_list_run(EXT_PATH("lfrfid"), ++command_id, true);
|
||||
test_rpc_storage_list_run("error_path", ++command_id, true);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -770,7 +804,8 @@ static void test_storage_read_run(const char* path, uint32_t command_id) {
|
||||
MsgList_init(expected_msg_list);
|
||||
|
||||
test_rpc_add_read_to_list_by_reading_real_file(expected_msg_list, path, command_id);
|
||||
test_rpc_create_simple_message(&request, PB_Main_storage_read_request_tag, path, command_id);
|
||||
test_rpc_create_simple_message(
|
||||
&request, PB_Main_storage_read_request_tag, path, command_id, false);
|
||||
test_rpc_encode_and_feed_one(&request, 0);
|
||||
test_rpc_decode_and_compare(expected_msg_list, 0);
|
||||
|
||||
@@ -824,7 +859,8 @@ static void test_rpc_storage_info_run(const char* path, uint32_t command_id) {
|
||||
MsgList_t expected_msg_list;
|
||||
MsgList_init(expected_msg_list);
|
||||
|
||||
test_rpc_create_simple_message(&request, PB_Main_storage_info_request_tag, path, command_id);
|
||||
test_rpc_create_simple_message(
|
||||
&request, PB_Main_storage_info_request_tag, path, command_id, false);
|
||||
|
||||
PB_Main* response = MsgList_push_new(expected_msg_list);
|
||||
response->command_id = command_id;
|
||||
@@ -856,7 +892,8 @@ static void test_rpc_storage_stat_run(const char* path, uint32_t command_id) {
|
||||
MsgList_t expected_msg_list;
|
||||
MsgList_init(expected_msg_list);
|
||||
|
||||
test_rpc_create_simple_message(&request, PB_Main_storage_stat_request_tag, path, command_id);
|
||||
test_rpc_create_simple_message(
|
||||
&request, PB_Main_storage_stat_request_tag, path, command_id, false);
|
||||
|
||||
Storage* fs_api = furi_record_open(RECORD_STORAGE);
|
||||
FileInfo fileinfo;
|
||||
@@ -968,7 +1005,11 @@ static void test_storage_write_read_run(
|
||||
test_rpc_add_empty_to_list(expected_msg_list, PB_CommandStatus_OK, *command_id);
|
||||
|
||||
test_rpc_create_simple_message(
|
||||
MsgList_push_raw(input_msg_list), PB_Main_storage_read_request_tag, path, ++*command_id);
|
||||
MsgList_push_raw(input_msg_list),
|
||||
PB_Main_storage_read_request_tag,
|
||||
path,
|
||||
++*command_id,
|
||||
false);
|
||||
test_rpc_add_read_or_write_to_list(
|
||||
expected_msg_list,
|
||||
READ_RESPONSE,
|
||||
@@ -1041,7 +1082,8 @@ MU_TEST(test_storage_interrupt_continuous_same_system) {
|
||||
MsgList_push_new(input_msg_list),
|
||||
PB_Main_storage_mkdir_request_tag,
|
||||
TEST_DIR "dir1",
|
||||
command_id + 1);
|
||||
command_id + 1,
|
||||
false);
|
||||
test_rpc_add_read_or_write_to_list(
|
||||
input_msg_list,
|
||||
WRITE_REQUEST,
|
||||
@@ -1121,7 +1163,8 @@ static void test_storage_delete_run(
|
||||
MsgList_t expected_msg_list;
|
||||
MsgList_init(expected_msg_list);
|
||||
|
||||
test_rpc_create_simple_message(&request, PB_Main_storage_delete_request_tag, path, command_id);
|
||||
test_rpc_create_simple_message(
|
||||
&request, PB_Main_storage_delete_request_tag, path, command_id, false);
|
||||
request.content.storage_delete_request.recursive = recursive;
|
||||
test_rpc_add_empty_to_list(expected_msg_list, status, command_id);
|
||||
|
||||
@@ -1202,7 +1245,8 @@ static void test_storage_mkdir_run(const char* path, size_t command_id, PB_Comma
|
||||
MsgList_t expected_msg_list;
|
||||
MsgList_init(expected_msg_list);
|
||||
|
||||
test_rpc_create_simple_message(&request, PB_Main_storage_mkdir_request_tag, path, command_id);
|
||||
test_rpc_create_simple_message(
|
||||
&request, PB_Main_storage_mkdir_request_tag, path, command_id, false);
|
||||
test_rpc_add_empty_to_list(expected_msg_list, status, command_id);
|
||||
|
||||
test_rpc_encode_and_feed_one(&request, 0);
|
||||
@@ -1229,33 +1273,15 @@ MU_TEST(test_storage_mkdir) {
|
||||
static void test_storage_calculate_md5sum(const char* path, char* md5sum, size_t md5sum_size) {
|
||||
Storage* api = furi_record_open(RECORD_STORAGE);
|
||||
File* file = storage_file_alloc(api);
|
||||
FuriString* md5 = furi_string_alloc();
|
||||
|
||||
if(storage_file_open(file, path, FSAM_READ, FSOM_OPEN_EXISTING)) {
|
||||
const uint16_t once_read_size = 512;
|
||||
const uint8_t hash_size = MD5SUM_SIZE;
|
||||
uint8_t* data = malloc(once_read_size);
|
||||
uint8_t* hash = malloc(sizeof(uint8_t) * hash_size);
|
||||
md5_context* md5_ctx = malloc(sizeof(md5_context));
|
||||
|
||||
md5_starts(md5_ctx);
|
||||
while(true) {
|
||||
uint16_t read_size = storage_file_read(file, data, once_read_size);
|
||||
if(read_size == 0) break;
|
||||
md5_update(md5_ctx, data, read_size);
|
||||
}
|
||||
md5_finish(md5_ctx, hash);
|
||||
free(md5_ctx);
|
||||
|
||||
for(uint8_t i = 0; i < hash_size; i++) {
|
||||
md5sum += snprintf(md5sum, md5sum_size, "%02x", hash[i]);
|
||||
}
|
||||
|
||||
free(hash);
|
||||
free(data);
|
||||
if(md5_string_calc_file(file, path, md5, NULL)) {
|
||||
snprintf(md5sum, md5sum_size, "%s", furi_string_get_cstr(md5));
|
||||
} else {
|
||||
furi_check(0);
|
||||
}
|
||||
|
||||
furi_string_free(md5);
|
||||
storage_file_close(file);
|
||||
storage_file_free(file);
|
||||
|
||||
@@ -1271,11 +1297,12 @@ static void test_storage_md5sum_run(
|
||||
MsgList_t expected_msg_list;
|
||||
MsgList_init(expected_msg_list);
|
||||
|
||||
test_rpc_create_simple_message(&request, PB_Main_storage_md5sum_request_tag, path, command_id);
|
||||
test_rpc_create_simple_message(
|
||||
&request, PB_Main_storage_md5sum_request_tag, path, command_id, false);
|
||||
if(status == PB_CommandStatus_OK) {
|
||||
PB_Main* response = MsgList_push_new(expected_msg_list);
|
||||
test_rpc_create_simple_message(
|
||||
response, PB_Main_storage_md5sum_response_tag, md5sum, command_id);
|
||||
response, PB_Main_storage_md5sum_response_tag, md5sum, command_id, false);
|
||||
response->command_status = status;
|
||||
} else {
|
||||
test_rpc_add_empty_to_list(expected_msg_list, status, command_id);
|
||||
@@ -1433,6 +1460,7 @@ MU_TEST_SUITE(test_rpc_storage) {
|
||||
MU_RUN_TEST(test_storage_info);
|
||||
MU_RUN_TEST(test_storage_stat);
|
||||
MU_RUN_TEST(test_storage_list);
|
||||
MU_RUN_TEST(test_storage_list_md5);
|
||||
MU_RUN_TEST(test_storage_read);
|
||||
MU_RUN_TEST(test_storage_write_read);
|
||||
MU_RUN_TEST(test_storage_write);
|
||||
@@ -1731,7 +1759,8 @@ MU_TEST(test_rpc_multisession_storage) {
|
||||
MsgList_push_raw(input_0),
|
||||
PB_Main_storage_read_request_tag,
|
||||
TEST_DIR "file0.txt",
|
||||
++command_id);
|
||||
++command_id,
|
||||
false);
|
||||
test_rpc_add_read_or_write_to_list(
|
||||
expected_0, READ_RESPONSE, TEST_DIR "file0.txt", pattern, sizeof(pattern), 1, command_id);
|
||||
|
||||
@@ -1739,7 +1768,8 @@ MU_TEST(test_rpc_multisession_storage) {
|
||||
MsgList_push_raw(input_1),
|
||||
PB_Main_storage_read_request_tag,
|
||||
TEST_DIR "file1.txt",
|
||||
++command_id);
|
||||
++command_id,
|
||||
false);
|
||||
test_rpc_add_read_or_write_to_list(
|
||||
expected_1, READ_RESPONSE, TEST_DIR "file1.txt", pattern, sizeof(pattern), 1, command_id);
|
||||
|
||||
|
||||
@@ -582,6 +582,49 @@ MU_TEST(test_storage_common_migrate) {
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
}
|
||||
|
||||
#define MD5_HASH_SIZE (16)
|
||||
#include <lib/toolbox/md5_calc.h>
|
||||
|
||||
MU_TEST(test_md5_calc) {
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
File* file = storage_file_alloc(storage);
|
||||
|
||||
const char* path = UNIT_TESTS_PATH("storage/md5.txt");
|
||||
const char* md5_cstr = "2a456fa43e75088fdde41c93159d62a2";
|
||||
const uint8_t md5[MD5_HASH_SIZE] = {
|
||||
0x2a,
|
||||
0x45,
|
||||
0x6f,
|
||||
0xa4,
|
||||
0x3e,
|
||||
0x75,
|
||||
0x08,
|
||||
0x8f,
|
||||
0xdd,
|
||||
0xe4,
|
||||
0x1c,
|
||||
0x93,
|
||||
0x15,
|
||||
0x9d,
|
||||
0x62,
|
||||
0xa2,
|
||||
};
|
||||
|
||||
uint8_t md5_output[MD5_HASH_SIZE];
|
||||
FuriString* md5_output_str = furi_string_alloc();
|
||||
memset(md5_output, 0, MD5_HASH_SIZE);
|
||||
|
||||
mu_check(md5_calc_file(file, path, md5_output, NULL));
|
||||
mu_check(md5_string_calc_file(file, path, md5_output_str, NULL));
|
||||
|
||||
mu_assert_mem_eq(md5, md5_output, MD5_HASH_SIZE);
|
||||
mu_assert_string_eq(md5_cstr, furi_string_get_cstr(md5_output_str));
|
||||
|
||||
storage_file_free(file);
|
||||
furi_string_free(md5_output_str);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
}
|
||||
|
||||
MU_TEST_SUITE(test_data_path) {
|
||||
MU_RUN_TEST(test_storage_data_path);
|
||||
MU_RUN_TEST(test_storage_data_path_apps);
|
||||
@@ -591,11 +634,16 @@ MU_TEST_SUITE(test_storage_common) {
|
||||
MU_RUN_TEST(test_storage_common_migrate);
|
||||
}
|
||||
|
||||
MU_TEST_SUITE(test_md5_calc_suite) {
|
||||
MU_RUN_TEST(test_md5_calc);
|
||||
}
|
||||
|
||||
int run_minunit_test_storage() {
|
||||
MU_RUN_SUITE(storage_file);
|
||||
MU_RUN_SUITE(storage_dir);
|
||||
MU_RUN_SUITE(storage_rename);
|
||||
MU_RUN_SUITE(test_data_path);
|
||||
MU_RUN_SUITE(test_storage_common);
|
||||
MU_RUN_SUITE(test_md5_calc_suite);
|
||||
return MU_EXIT_CODE;
|
||||
}
|
||||
|
||||
@@ -330,7 +330,12 @@ bool subghz_hal_async_tx_test_run(SubGhzHalAsyncTxTestType type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FuriHalCortexTimer timer = furi_hal_cortex_timer_get(30000000);
|
||||
|
||||
while(!furi_hal_subghz_is_async_tx_complete()) {
|
||||
if(furi_hal_cortex_timer_is_expired(timer)) {
|
||||
return false;
|
||||
}
|
||||
furi_delay_ms(10);
|
||||
}
|
||||
furi_hal_subghz_stop_async_tx();
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
int run_minunit_test_furi();
|
||||
int run_minunit_test_furi_hal();
|
||||
int run_minunit_test_furi_hal_crypto();
|
||||
int run_minunit_test_furi_string();
|
||||
int run_minunit_test_infrared();
|
||||
int run_minunit_test_rpc();
|
||||
@@ -39,6 +40,7 @@ typedef struct {
|
||||
const UnitTest unit_tests[] = {
|
||||
{.name = "furi", .entry = run_minunit_test_furi},
|
||||
{.name = "furi_hal", .entry = run_minunit_test_furi_hal},
|
||||
{.name = "furi_hal_crypto", .entry = run_minunit_test_furi_hal_crypto},
|
||||
{.name = "furi_string", .entry = run_minunit_test_furi_string},
|
||||
{.name = "storage", .entry = run_minunit_test_storage},
|
||||
{.name = "stream", .entry = run_minunit_test_stream},
|
||||
|
||||
@@ -7,6 +7,5 @@ App(
|
||||
requires=["gui"],
|
||||
stack_size=1 * 1024,
|
||||
order=60,
|
||||
fap_icon="../../external/mousejacker/mouse_10px.png",
|
||||
fap_category="Debug",
|
||||
)
|
||||
|
||||
6
applications/external/application.fam
vendored
@@ -1,6 +0,0 @@
|
||||
# Placeholder
|
||||
App(
|
||||
appid="external_apps",
|
||||
name="External apps bundle",
|
||||
apptype=FlipperAppType.METAPACKAGE,
|
||||
)
|
||||
14
applications/external/arkanoid/application.fam
vendored
@@ -1,14 +0,0 @@
|
||||
App(
|
||||
appid="arkanoid",
|
||||
name="Arkanoid",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="arkanoid_game_app",
|
||||
requires=["gui"],
|
||||
stack_size=1 * 1024,
|
||||
order=30,
|
||||
fap_icon="arkanoid_10px.png",
|
||||
fap_category="Games",
|
||||
fap_author="@xMasterX & @gotnull",
|
||||
fap_version="1.0",
|
||||
fap_description="Arkanoid Game",
|
||||
)
|
||||
BIN
applications/external/arkanoid/arkanoid_10px.png
vendored
|
Before Width: | Height: | Size: 1.6 KiB |
479
applications/external/arkanoid/arkanoid_game.c
vendored
@@ -1,479 +0,0 @@
|
||||
#include <furi.h>
|
||||
#include <gui/gui.h>
|
||||
#include <input/input.h>
|
||||
#include <stdlib.h>
|
||||
#include <gui/view.h>
|
||||
#include <notification/notification.h>
|
||||
#include <notification/notification_messages.h>
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
#define TAG "Arkanoid"
|
||||
|
||||
#define FLIPPER_LCD_WIDTH 128
|
||||
#define FLIPPER_LCD_HEIGHT 64
|
||||
#define MAX_SPEED 3
|
||||
|
||||
typedef enum { EventTypeTick, EventTypeKey } EventType;
|
||||
|
||||
typedef struct {
|
||||
//Brick Bounds used in collision detection
|
||||
int leftBrick;
|
||||
int rightBrick;
|
||||
int topBrick;
|
||||
int bottomBrick;
|
||||
bool isHit[4][13]; //Array of if bricks are hit or not
|
||||
} BrickState;
|
||||
|
||||
typedef struct {
|
||||
int dx; //Initial movement of ball
|
||||
int dy; //Initial movement of ball
|
||||
int xb; //Balls starting possition
|
||||
int yb; //Balls starting possition
|
||||
bool released; //If the ball has been released by the player
|
||||
//Ball Bounds used in collision detection
|
||||
int leftBall;
|
||||
int rightBall;
|
||||
int topBall;
|
||||
int bottomBall;
|
||||
} BallState;
|
||||
|
||||
typedef struct {
|
||||
FuriMutex* mutex;
|
||||
BallState ball_state;
|
||||
BrickState brick_state;
|
||||
NotificationApp* notify;
|
||||
unsigned int COLUMNS; //Columns of bricks
|
||||
unsigned int ROWS; //Rows of bricks
|
||||
bool initialDraw; //If the inital draw has happened
|
||||
int xPaddle; //X position of paddle
|
||||
char text[16]; //General string buffer
|
||||
bool bounced; //Used to fix double bounce glitch
|
||||
int lives; //Amount of lives
|
||||
int level; //Current level
|
||||
unsigned int score; //Score for the game
|
||||
unsigned int brickCount; //Amount of bricks hit
|
||||
int tick; //Tick counter
|
||||
bool gameStarted; // Did the game start?
|
||||
int speed; // Ball speed
|
||||
} ArkanoidState;
|
||||
|
||||
typedef struct {
|
||||
EventType type;
|
||||
InputEvent input;
|
||||
} GameEvent;
|
||||
|
||||
static const NotificationSequence sequence_short_sound = {
|
||||
&message_note_c5,
|
||||
&message_delay_50,
|
||||
&message_sound_off,
|
||||
NULL,
|
||||
};
|
||||
|
||||
// generate number in range [min,max)
|
||||
int rand_range(int min, int max) {
|
||||
return min + rand() % (max - min);
|
||||
}
|
||||
|
||||
void move_ball(Canvas* canvas, ArkanoidState* st) {
|
||||
st->tick++;
|
||||
|
||||
int current_speed = abs(st->speed - 1 - MAX_SPEED);
|
||||
if(st->tick % current_speed != 0 && st->tick % (current_speed + 1) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(st->ball_state.released) {
|
||||
//Move ball
|
||||
if(abs(st->ball_state.dx) == 2) {
|
||||
st->ball_state.xb += st->ball_state.dx / 2;
|
||||
// 2x speed is really 1.5 speed
|
||||
if((st->tick / current_speed) % 2 == 0) st->ball_state.xb += st->ball_state.dx / 2;
|
||||
} else {
|
||||
st->ball_state.xb += st->ball_state.dx;
|
||||
}
|
||||
st->ball_state.yb = st->ball_state.yb + st->ball_state.dy;
|
||||
|
||||
//Set bounds
|
||||
st->ball_state.leftBall = st->ball_state.xb;
|
||||
st->ball_state.rightBall = st->ball_state.xb + 2;
|
||||
st->ball_state.topBall = st->ball_state.yb;
|
||||
st->ball_state.bottomBall = st->ball_state.yb + 2;
|
||||
|
||||
//Bounce off top edge
|
||||
if(st->ball_state.yb <= 0) {
|
||||
st->ball_state.yb = 2;
|
||||
st->ball_state.dy = -st->ball_state.dy;
|
||||
}
|
||||
|
||||
//Lose a life if bottom edge hit
|
||||
if(st->ball_state.yb >= FLIPPER_LCD_HEIGHT) {
|
||||
canvas_draw_frame(canvas, st->xPaddle, FLIPPER_LCD_HEIGHT - 1, 11, 1);
|
||||
st->xPaddle = 54;
|
||||
st->ball_state.yb = 60;
|
||||
st->ball_state.released = false;
|
||||
st->lives--;
|
||||
st->gameStarted = false;
|
||||
|
||||
if(rand_range(0, 2) == 0) {
|
||||
st->ball_state.dx = 1;
|
||||
} else {
|
||||
st->ball_state.dx = -1;
|
||||
}
|
||||
}
|
||||
|
||||
//Bounce off left side
|
||||
if(st->ball_state.xb <= 0) {
|
||||
st->ball_state.xb = 2;
|
||||
st->ball_state.dx = -st->ball_state.dx;
|
||||
}
|
||||
|
||||
//Bounce off right side
|
||||
if(st->ball_state.xb >= FLIPPER_LCD_WIDTH - 2) {
|
||||
st->ball_state.xb = FLIPPER_LCD_WIDTH - 4;
|
||||
st->ball_state.dx = -st->ball_state.dx;
|
||||
// arduboy.tunes.tone(523, 250);
|
||||
}
|
||||
|
||||
//Bounce off paddle
|
||||
if(st->ball_state.xb + 1 >= st->xPaddle && st->ball_state.xb <= st->xPaddle + 12 &&
|
||||
st->ball_state.yb + 2 >= FLIPPER_LCD_HEIGHT - 1 &&
|
||||
st->ball_state.yb <= FLIPPER_LCD_HEIGHT) {
|
||||
st->ball_state.dy = -st->ball_state.dy;
|
||||
st->ball_state.dx =
|
||||
((st->ball_state.xb - (st->xPaddle + 6)) / 3); //Applies spin on the ball
|
||||
// prevent straight bounce, but not prevent roguuemaster from stealing
|
||||
if(st->ball_state.dx == 0) {
|
||||
st->ball_state.dx = (rand_range(0, 2) == 1) ? 1 : -1;
|
||||
}
|
||||
}
|
||||
|
||||
//Bounce off Bricks
|
||||
for(unsigned int row = 0; row < st->ROWS; row++) {
|
||||
for(unsigned int column = 0; column < st->COLUMNS; column++) {
|
||||
if(!st->brick_state.isHit[row][column]) {
|
||||
//Sets Brick bounds
|
||||
st->brick_state.leftBrick = 10 * column;
|
||||
st->brick_state.rightBrick = 10 * column + 10;
|
||||
st->brick_state.topBrick = 6 * row + 1;
|
||||
st->brick_state.bottomBrick = 6 * row + 7;
|
||||
|
||||
//If A collison has occured
|
||||
if(st->ball_state.topBall <= st->brick_state.bottomBrick &&
|
||||
st->ball_state.bottomBall >= st->brick_state.topBrick &&
|
||||
st->ball_state.leftBall <= st->brick_state.rightBrick &&
|
||||
st->ball_state.rightBall >= st->brick_state.leftBrick) {
|
||||
st->score += st->level;
|
||||
// Blink led when we hit some brick
|
||||
notification_message(st->notify, &sequence_short_sound);
|
||||
//notification_message(st->notify, &sequence_blink_white_100);
|
||||
|
||||
st->brickCount++;
|
||||
st->brick_state.isHit[row][column] = true;
|
||||
canvas_draw_frame(canvas, 10 * column, 2 + 6 * row, 8, 4);
|
||||
|
||||
//Vertical collision
|
||||
if(st->ball_state.bottomBall > st->brick_state.bottomBrick ||
|
||||
st->ball_state.topBall < st->brick_state.topBrick) {
|
||||
//Only bounce once each ball move
|
||||
if(!st->bounced) {
|
||||
st->ball_state.dy = -st->ball_state.dy;
|
||||
st->ball_state.yb += st->ball_state.dy;
|
||||
st->bounced = true;
|
||||
}
|
||||
}
|
||||
|
||||
//Hoizontal collision
|
||||
if(st->ball_state.leftBall < st->brick_state.leftBrick ||
|
||||
st->ball_state.rightBall > st->brick_state.rightBrick) {
|
||||
//Only bounce once brick each ball move
|
||||
if(!st->bounced) {
|
||||
st->ball_state.dx = -st->ball_state.dx;
|
||||
st->ball_state.xb += st->ball_state.dx;
|
||||
st->bounced = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Reset Bounce
|
||||
st->bounced = false;
|
||||
} else {
|
||||
//Ball follows paddle
|
||||
st->ball_state.xb = st->xPaddle + 5;
|
||||
}
|
||||
}
|
||||
|
||||
void draw_lives(Canvas* canvas, ArkanoidState* arkanoid_state) {
|
||||
if(arkanoid_state->lives == 3) {
|
||||
canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 7);
|
||||
canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 7);
|
||||
canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 8);
|
||||
canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 8);
|
||||
|
||||
canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 11);
|
||||
canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 11);
|
||||
canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 12);
|
||||
canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 12);
|
||||
|
||||
canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 15);
|
||||
canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 15);
|
||||
canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 16);
|
||||
canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 16);
|
||||
} else if(arkanoid_state->lives == 2) {
|
||||
canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 7);
|
||||
canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 7);
|
||||
canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 8);
|
||||
canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 8);
|
||||
|
||||
canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 11);
|
||||
canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 11);
|
||||
canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 12);
|
||||
canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 12);
|
||||
} else {
|
||||
canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 7);
|
||||
canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 7);
|
||||
canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 8);
|
||||
canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 8);
|
||||
}
|
||||
}
|
||||
|
||||
void draw_score(Canvas* canvas, ArkanoidState* arkanoid_state) {
|
||||
snprintf(arkanoid_state->text, sizeof(arkanoid_state->text), "%u", arkanoid_state->score);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
FLIPPER_LCD_WIDTH - 2,
|
||||
FLIPPER_LCD_HEIGHT - 6,
|
||||
AlignRight,
|
||||
AlignBottom,
|
||||
arkanoid_state->text);
|
||||
}
|
||||
|
||||
void draw_ball(Canvas* canvas, ArkanoidState* ast) {
|
||||
canvas_draw_dot(canvas, ast->ball_state.xb, ast->ball_state.yb);
|
||||
canvas_draw_dot(canvas, ast->ball_state.xb + 1, ast->ball_state.yb);
|
||||
canvas_draw_dot(canvas, ast->ball_state.xb, ast->ball_state.yb + 1);
|
||||
canvas_draw_dot(canvas, ast->ball_state.xb + 1, ast->ball_state.yb + 1);
|
||||
|
||||
move_ball(canvas, ast);
|
||||
}
|
||||
|
||||
void draw_paddle(Canvas* canvas, ArkanoidState* arkanoid_state) {
|
||||
canvas_draw_frame(canvas, arkanoid_state->xPaddle, FLIPPER_LCD_HEIGHT - 1, 11, 1);
|
||||
}
|
||||
|
||||
void reset_level(Canvas* canvas, ArkanoidState* arkanoid_state) {
|
||||
//Undraw paddle
|
||||
canvas_draw_frame(canvas, arkanoid_state->xPaddle, FLIPPER_LCD_HEIGHT - 1, 11, 1);
|
||||
|
||||
//Undraw ball
|
||||
canvas_draw_dot(canvas, arkanoid_state->ball_state.xb, arkanoid_state->ball_state.yb);
|
||||
canvas_draw_dot(canvas, arkanoid_state->ball_state.xb + 1, arkanoid_state->ball_state.yb);
|
||||
canvas_draw_dot(canvas, arkanoid_state->ball_state.xb, arkanoid_state->ball_state.yb + 1);
|
||||
canvas_draw_dot(canvas, arkanoid_state->ball_state.xb + 1, arkanoid_state->ball_state.yb + 1);
|
||||
|
||||
//Alter various variables to reset the game
|
||||
arkanoid_state->xPaddle = 54;
|
||||
arkanoid_state->ball_state.yb = 60;
|
||||
arkanoid_state->brickCount = 0;
|
||||
arkanoid_state->ball_state.released = false;
|
||||
arkanoid_state->gameStarted = false;
|
||||
|
||||
// Reset all brick hit states
|
||||
for(unsigned int row = 0; row < arkanoid_state->ROWS; row++) {
|
||||
for(unsigned int column = 0; column < arkanoid_state->COLUMNS; column++) {
|
||||
arkanoid_state->brick_state.isHit[row][column] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void arkanoid_state_init(ArkanoidState* arkanoid_state) {
|
||||
// Init notification
|
||||
arkanoid_state->notify = furi_record_open(RECORD_NOTIFICATION);
|
||||
|
||||
// Set the initial game state
|
||||
arkanoid_state->COLUMNS = 13;
|
||||
arkanoid_state->ROWS = 4;
|
||||
arkanoid_state->ball_state.dx = -1;
|
||||
arkanoid_state->ball_state.dy = -1;
|
||||
arkanoid_state->speed = 2;
|
||||
arkanoid_state->bounced = false;
|
||||
arkanoid_state->lives = 3;
|
||||
arkanoid_state->level = 1;
|
||||
arkanoid_state->score = 0;
|
||||
arkanoid_state->COLUMNS = 13;
|
||||
arkanoid_state->COLUMNS = 13;
|
||||
|
||||
// Reset initial state
|
||||
arkanoid_state->initialDraw = false;
|
||||
arkanoid_state->gameStarted = false;
|
||||
}
|
||||
|
||||
static void arkanoid_draw_callback(Canvas* const canvas, void* ctx) {
|
||||
furi_assert(ctx);
|
||||
ArkanoidState* arkanoid_state = ctx;
|
||||
furi_mutex_acquire(arkanoid_state->mutex, FuriWaitForever);
|
||||
|
||||
//Initial level draw
|
||||
if(!arkanoid_state->initialDraw) {
|
||||
arkanoid_state->initialDraw = true;
|
||||
|
||||
// Set default font for text
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
|
||||
//Draws the new level
|
||||
reset_level(canvas, arkanoid_state);
|
||||
}
|
||||
|
||||
//Draws new bricks and resets their values
|
||||
for(unsigned int row = 0; row < arkanoid_state->ROWS; row++) {
|
||||
for(unsigned int column = 0; column < arkanoid_state->COLUMNS; column++) {
|
||||
if(!arkanoid_state->brick_state.isHit[row][column]) {
|
||||
canvas_draw_frame(canvas, 10 * column, 2 + 6 * row, 8, 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(arkanoid_state->lives > 0) {
|
||||
draw_paddle(canvas, arkanoid_state);
|
||||
draw_ball(canvas, arkanoid_state);
|
||||
draw_score(canvas, arkanoid_state);
|
||||
draw_lives(canvas, arkanoid_state);
|
||||
|
||||
if(arkanoid_state->brickCount == arkanoid_state->ROWS * arkanoid_state->COLUMNS) {
|
||||
arkanoid_state->level++;
|
||||
reset_level(canvas, arkanoid_state);
|
||||
}
|
||||
} else {
|
||||
reset_level(canvas, arkanoid_state);
|
||||
arkanoid_state->initialDraw = false;
|
||||
arkanoid_state->lives = 3;
|
||||
arkanoid_state->score = 0;
|
||||
}
|
||||
|
||||
furi_mutex_release(arkanoid_state->mutex);
|
||||
}
|
||||
|
||||
static void arkanoid_input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) {
|
||||
furi_assert(event_queue);
|
||||
|
||||
GameEvent event = {.type = EventTypeKey, .input = *input_event};
|
||||
furi_message_queue_put(event_queue, &event, FuriWaitForever);
|
||||
}
|
||||
|
||||
static void arkanoid_update_timer_callback(FuriMessageQueue* event_queue) {
|
||||
furi_assert(event_queue);
|
||||
|
||||
GameEvent event = {.type = EventTypeTick};
|
||||
furi_message_queue_put(event_queue, &event, 0);
|
||||
}
|
||||
|
||||
int32_t arkanoid_game_app(void* p) {
|
||||
UNUSED(p);
|
||||
int32_t return_code = 0;
|
||||
|
||||
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(GameEvent));
|
||||
|
||||
ArkanoidState* arkanoid_state = malloc(sizeof(ArkanoidState));
|
||||
arkanoid_state_init(arkanoid_state);
|
||||
|
||||
arkanoid_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
|
||||
if(!arkanoid_state->mutex) {
|
||||
FURI_LOG_E(TAG, "Cannot create mutex\r\n");
|
||||
return_code = 255;
|
||||
goto free_and_exit;
|
||||
}
|
||||
|
||||
// Set system callbacks
|
||||
ViewPort* view_port = view_port_alloc();
|
||||
view_port_draw_callback_set(view_port, arkanoid_draw_callback, arkanoid_state);
|
||||
view_port_input_callback_set(view_port, arkanoid_input_callback, event_queue);
|
||||
|
||||
FuriTimer* timer =
|
||||
furi_timer_alloc(arkanoid_update_timer_callback, FuriTimerTypePeriodic, event_queue);
|
||||
furi_timer_start(timer, furi_kernel_get_tick_frequency() / 22);
|
||||
|
||||
// Open GUI and register view_port
|
||||
Gui* gui = furi_record_open(RECORD_GUI);
|
||||
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
|
||||
|
||||
// Call dolphin deed on game start
|
||||
dolphin_deed(DolphinDeedPluginGameStart);
|
||||
|
||||
GameEvent event;
|
||||
for(bool processing = true; processing;) {
|
||||
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);
|
||||
furi_mutex_acquire(arkanoid_state->mutex, FuriWaitForever);
|
||||
|
||||
if(event_status == FuriStatusOk) {
|
||||
// Key events
|
||||
if(event.type == EventTypeKey) {
|
||||
if(event.input.type == InputTypePress || event.input.type == InputTypeLong ||
|
||||
event.input.type == InputTypeRepeat) {
|
||||
switch(event.input.key) {
|
||||
case InputKeyBack:
|
||||
processing = false;
|
||||
break;
|
||||
case InputKeyRight:
|
||||
if(arkanoid_state->xPaddle < FLIPPER_LCD_WIDTH - 12) {
|
||||
arkanoid_state->xPaddle += 8;
|
||||
}
|
||||
break;
|
||||
case InputKeyLeft:
|
||||
if(arkanoid_state->xPaddle > 0) {
|
||||
arkanoid_state->xPaddle -= 8;
|
||||
}
|
||||
break;
|
||||
case InputKeyUp:
|
||||
if(arkanoid_state->speed < MAX_SPEED) {
|
||||
arkanoid_state->speed++;
|
||||
}
|
||||
break;
|
||||
case InputKeyDown:
|
||||
if(arkanoid_state->speed > 1) {
|
||||
arkanoid_state->speed--;
|
||||
}
|
||||
break;
|
||||
case InputKeyOk:
|
||||
if(arkanoid_state->gameStarted == false) {
|
||||
//Release ball if FIRE pressed
|
||||
arkanoid_state->ball_state.released = true;
|
||||
|
||||
//Apply random direction to ball on release
|
||||
if(rand_range(0, 2) == 0) {
|
||||
arkanoid_state->ball_state.dx = 1;
|
||||
} else {
|
||||
arkanoid_state->ball_state.dx = -1;
|
||||
}
|
||||
|
||||
//Makes sure the ball heads upwards
|
||||
arkanoid_state->ball_state.dy = -1;
|
||||
//start the game flag
|
||||
arkanoid_state->gameStarted = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
view_port_update(view_port);
|
||||
furi_mutex_release(arkanoid_state->mutex);
|
||||
}
|
||||
furi_timer_free(timer);
|
||||
view_port_enabled_set(view_port, false);
|
||||
gui_remove_view_port(gui, view_port);
|
||||
furi_record_close(RECORD_GUI);
|
||||
furi_record_close(RECORD_NOTIFICATION);
|
||||
view_port_free(view_port);
|
||||
furi_mutex_free(arkanoid_state->mutex);
|
||||
|
||||
free_and_exit:
|
||||
free(arkanoid_state);
|
||||
furi_message_queue_free(event_queue);
|
||||
|
||||
return return_code;
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
App(
|
||||
appid="avr_isp",
|
||||
name="AVR Flasher",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="avr_isp_app",
|
||||
requires=["gui"],
|
||||
stack_size=4 * 1024,
|
||||
order=20,
|
||||
fap_icon="avr_app_icon_10x10.png",
|
||||
fap_category="GPIO",
|
||||
fap_icon_assets="images",
|
||||
fap_private_libs=[
|
||||
Lib(
|
||||
name="driver",
|
||||
),
|
||||
],
|
||||
)
|
||||
|
Before Width: | Height: | Size: 3.5 KiB |
@@ -1,179 +0,0 @@
|
||||
#include "avr_isp_app_i.h"
|
||||
|
||||
static bool avr_isp_app_custom_event_callback(void* context, uint32_t event) {
|
||||
furi_assert(context);
|
||||
AvrIspApp* app = context;
|
||||
return scene_manager_handle_custom_event(app->scene_manager, event);
|
||||
}
|
||||
|
||||
static bool avr_isp_app_back_event_callback(void* context) {
|
||||
furi_assert(context);
|
||||
AvrIspApp* app = context;
|
||||
return scene_manager_handle_back_event(app->scene_manager);
|
||||
}
|
||||
|
||||
static void avr_isp_app_tick_event_callback(void* context) {
|
||||
furi_assert(context);
|
||||
AvrIspApp* app = context;
|
||||
scene_manager_handle_tick_event(app->scene_manager);
|
||||
}
|
||||
|
||||
AvrIspApp* avr_isp_app_alloc() {
|
||||
AvrIspApp* app = malloc(sizeof(AvrIspApp));
|
||||
|
||||
app->file_path = furi_string_alloc();
|
||||
furi_string_set(app->file_path, STORAGE_APP_DATA_PATH_PREFIX);
|
||||
app->error = AvrIspErrorNoError;
|
||||
|
||||
// GUI
|
||||
app->gui = furi_record_open(RECORD_GUI);
|
||||
|
||||
// View Dispatcher
|
||||
app->view_dispatcher = view_dispatcher_alloc();
|
||||
app->scene_manager = scene_manager_alloc(&avr_isp_scene_handlers, app);
|
||||
view_dispatcher_enable_queue(app->view_dispatcher);
|
||||
|
||||
view_dispatcher_set_event_callback_context(app->view_dispatcher, app);
|
||||
view_dispatcher_set_custom_event_callback(
|
||||
app->view_dispatcher, avr_isp_app_custom_event_callback);
|
||||
view_dispatcher_set_navigation_event_callback(
|
||||
app->view_dispatcher, avr_isp_app_back_event_callback);
|
||||
view_dispatcher_set_tick_event_callback(
|
||||
app->view_dispatcher, avr_isp_app_tick_event_callback, 100);
|
||||
|
||||
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
|
||||
|
||||
// Open Notification record
|
||||
app->notifications = furi_record_open(RECORD_NOTIFICATION);
|
||||
|
||||
// SubMenu
|
||||
app->submenu = submenu_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, AvrIspViewSubmenu, submenu_get_view(app->submenu));
|
||||
|
||||
// Widget
|
||||
app->widget = widget_alloc();
|
||||
view_dispatcher_add_view(app->view_dispatcher, AvrIspViewWidget, widget_get_view(app->widget));
|
||||
|
||||
// Text Input
|
||||
app->text_input = text_input_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, AvrIspViewTextInput, text_input_get_view(app->text_input));
|
||||
|
||||
// Popup
|
||||
app->popup = popup_alloc();
|
||||
view_dispatcher_add_view(app->view_dispatcher, AvrIspViewPopup, popup_get_view(app->popup));
|
||||
|
||||
//Dialog
|
||||
app->dialogs = furi_record_open(RECORD_DIALOGS);
|
||||
|
||||
// Programmer view
|
||||
app->avr_isp_programmer_view = avr_isp_programmer_view_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher,
|
||||
AvrIspViewProgrammer,
|
||||
avr_isp_programmer_view_get_view(app->avr_isp_programmer_view));
|
||||
|
||||
// Reader view
|
||||
app->avr_isp_reader_view = avr_isp_reader_view_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher,
|
||||
AvrIspViewReader,
|
||||
avr_isp_reader_view_get_view(app->avr_isp_reader_view));
|
||||
|
||||
// Writer view
|
||||
app->avr_isp_writer_view = avr_isp_writer_view_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher,
|
||||
AvrIspViewWriter,
|
||||
avr_isp_writer_view_get_view(app->avr_isp_writer_view));
|
||||
|
||||
// Chip detect view
|
||||
app->avr_isp_chip_detect_view = avr_isp_chip_detect_view_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher,
|
||||
AvrIspViewChipDetect,
|
||||
avr_isp_chip_detect_view_get_view(app->avr_isp_chip_detect_view));
|
||||
|
||||
// Enable 5v power, multiple attempts to avoid issues with power chip protection false triggering
|
||||
uint8_t attempts = 0;
|
||||
while(!furi_hal_power_is_otg_enabled() && attempts++ < 5) {
|
||||
furi_hal_power_enable_otg();
|
||||
furi_delay_ms(10);
|
||||
}
|
||||
|
||||
scene_manager_next_scene(app->scene_manager, AvrIspSceneStart);
|
||||
|
||||
return app;
|
||||
} //-V773
|
||||
|
||||
void avr_isp_app_free(AvrIspApp* app) {
|
||||
furi_assert(app);
|
||||
|
||||
// Disable 5v power
|
||||
if(furi_hal_power_is_otg_enabled()) {
|
||||
furi_hal_power_disable_otg();
|
||||
}
|
||||
|
||||
// Submenu
|
||||
view_dispatcher_remove_view(app->view_dispatcher, AvrIspViewSubmenu);
|
||||
submenu_free(app->submenu);
|
||||
|
||||
// Widget
|
||||
view_dispatcher_remove_view(app->view_dispatcher, AvrIspViewWidget);
|
||||
widget_free(app->widget);
|
||||
|
||||
// TextInput
|
||||
view_dispatcher_remove_view(app->view_dispatcher, AvrIspViewTextInput);
|
||||
text_input_free(app->text_input);
|
||||
|
||||
// Popup
|
||||
view_dispatcher_remove_view(app->view_dispatcher, AvrIspViewPopup);
|
||||
popup_free(app->popup);
|
||||
|
||||
//Dialog
|
||||
furi_record_close(RECORD_DIALOGS);
|
||||
|
||||
// Programmer view
|
||||
view_dispatcher_remove_view(app->view_dispatcher, AvrIspViewProgrammer);
|
||||
avr_isp_programmer_view_free(app->avr_isp_programmer_view);
|
||||
|
||||
// Reader view
|
||||
view_dispatcher_remove_view(app->view_dispatcher, AvrIspViewReader);
|
||||
avr_isp_reader_view_free(app->avr_isp_reader_view);
|
||||
|
||||
// Writer view
|
||||
view_dispatcher_remove_view(app->view_dispatcher, AvrIspViewWriter);
|
||||
avr_isp_writer_view_free(app->avr_isp_writer_view);
|
||||
|
||||
// Chip detect view
|
||||
view_dispatcher_remove_view(app->view_dispatcher, AvrIspViewChipDetect);
|
||||
avr_isp_chip_detect_view_free(app->avr_isp_chip_detect_view);
|
||||
|
||||
// View dispatcher
|
||||
view_dispatcher_free(app->view_dispatcher);
|
||||
scene_manager_free(app->scene_manager);
|
||||
|
||||
// Notifications
|
||||
furi_record_close(RECORD_NOTIFICATION);
|
||||
app->notifications = NULL;
|
||||
|
||||
// Close records
|
||||
furi_record_close(RECORD_GUI);
|
||||
|
||||
// Path strings
|
||||
furi_string_free(app->file_path);
|
||||
|
||||
free(app);
|
||||
}
|
||||
|
||||
int32_t avr_isp_app(void* p) {
|
||||
UNUSED(p);
|
||||
AvrIspApp* avr_isp_app = avr_isp_app_alloc();
|
||||
|
||||
view_dispatcher_run(avr_isp_app->view_dispatcher);
|
||||
|
||||
avr_isp_app_free(avr_isp_app);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
#include "avr_isp_app_i.h"
|
||||
#include <lib/toolbox/path.h>
|
||||
#include <flipper_format/flipper_format_i.h>
|
||||
|
||||
#define TAG "AvrIsp"
|
||||
|
||||
bool avr_isp_load_from_file(AvrIspApp* app) {
|
||||
furi_assert(app);
|
||||
|
||||
FuriString* file_path = furi_string_alloc();
|
||||
FuriString* file_name = furi_string_alloc();
|
||||
|
||||
DialogsFileBrowserOptions browser_options;
|
||||
dialog_file_browser_set_basic_options(
|
||||
&browser_options, AVR_ISP_APP_EXTENSION, &I_avr_app_icon_10x10);
|
||||
browser_options.base_path = STORAGE_APP_DATA_PATH_PREFIX;
|
||||
|
||||
// Input events and views are managed by file_select
|
||||
bool res = dialog_file_browser_show(app->dialogs, file_path, app->file_path, &browser_options);
|
||||
|
||||
if(res) {
|
||||
path_extract_dirname(furi_string_get_cstr(file_path), app->file_path);
|
||||
path_extract_filename(file_path, file_name, true);
|
||||
strncpy(app->file_name_tmp, furi_string_get_cstr(file_name), AVR_ISP_MAX_LEN_NAME);
|
||||
}
|
||||
|
||||
furi_string_free(file_name);
|
||||
furi_string_free(file_path);
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "helpers/avr_isp_types.h"
|
||||
#include <avr_isp_icons.h>
|
||||
|
||||
#include "scenes/avr_isp_scene.h"
|
||||
#include <gui/gui.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <gui/scene_manager.h>
|
||||
#include <gui/modules/submenu.h>
|
||||
#include <gui/modules/widget.h>
|
||||
#include <notification/notification_messages.h>
|
||||
#include <gui/modules/text_input.h>
|
||||
#include <dialogs/dialogs.h>
|
||||
#include <storage/storage.h>
|
||||
#include <gui/modules/popup.h>
|
||||
|
||||
#include "views/avr_isp_view_programmer.h"
|
||||
#include "views/avr_isp_view_reader.h"
|
||||
#include "views/avr_isp_view_writer.h"
|
||||
#include "views/avr_isp_view_chip_detect.h"
|
||||
|
||||
#define AVR_ISP_MAX_LEN_NAME 64
|
||||
|
||||
typedef struct {
|
||||
Gui* gui;
|
||||
ViewDispatcher* view_dispatcher;
|
||||
SceneManager* scene_manager;
|
||||
NotificationApp* notifications;
|
||||
DialogsApp* dialogs;
|
||||
Popup* popup;
|
||||
Submenu* submenu;
|
||||
Widget* widget;
|
||||
TextInput* text_input;
|
||||
FuriString* file_path;
|
||||
char file_name_tmp[AVR_ISP_MAX_LEN_NAME];
|
||||
AvrIspProgrammerView* avr_isp_programmer_view;
|
||||
AvrIspReaderView* avr_isp_reader_view;
|
||||
AvrIspWriterView* avr_isp_writer_view;
|
||||
AvrIspChipDetectView* avr_isp_chip_detect_view;
|
||||
AvrIspError error;
|
||||
} AvrIspApp;
|
||||
|
||||
bool avr_isp_load_from_file(AvrIspApp* app);
|
||||
@@ -1,496 +0,0 @@
|
||||
#include "avr_isp.h"
|
||||
#include "../lib/driver/avr_isp_prog_cmd.h"
|
||||
#include "../lib/driver/avr_isp_spi_sw.h"
|
||||
|
||||
#include <furi.h>
|
||||
|
||||
#define AVR_ISP_PROG_TX_RX_BUF_SIZE 320
|
||||
#define TAG "AvrIsp"
|
||||
|
||||
struct AvrIsp {
|
||||
AvrIspSpiSw* spi;
|
||||
bool pmode;
|
||||
AvrIspCallback callback;
|
||||
void* context;
|
||||
};
|
||||
|
||||
AvrIsp* avr_isp_alloc(void) {
|
||||
AvrIsp* instance = malloc(sizeof(AvrIsp));
|
||||
return instance;
|
||||
}
|
||||
|
||||
void avr_isp_free(AvrIsp* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
if(instance->spi) avr_isp_end_pmode(instance);
|
||||
free(instance);
|
||||
}
|
||||
|
||||
void avr_isp_set_tx_callback(AvrIsp* instance, AvrIspCallback callback, void* context) {
|
||||
furi_assert(instance);
|
||||
furi_assert(context);
|
||||
|
||||
instance->callback = callback;
|
||||
instance->context = context;
|
||||
}
|
||||
|
||||
uint8_t avr_isp_spi_transaction(
|
||||
AvrIsp* instance,
|
||||
uint8_t cmd,
|
||||
uint8_t addr_hi,
|
||||
uint8_t addr_lo,
|
||||
uint8_t data) {
|
||||
furi_assert(instance);
|
||||
|
||||
avr_isp_spi_sw_txrx(instance->spi, cmd);
|
||||
avr_isp_spi_sw_txrx(instance->spi, addr_hi);
|
||||
avr_isp_spi_sw_txrx(instance->spi, addr_lo);
|
||||
return avr_isp_spi_sw_txrx(instance->spi, data);
|
||||
}
|
||||
|
||||
static bool avr_isp_set_pmode(AvrIsp* instance, uint8_t a, uint8_t b, uint8_t c, uint8_t d) {
|
||||
furi_assert(instance);
|
||||
|
||||
uint8_t res = 0;
|
||||
avr_isp_spi_sw_txrx(instance->spi, a);
|
||||
avr_isp_spi_sw_txrx(instance->spi, b);
|
||||
res = avr_isp_spi_sw_txrx(instance->spi, c);
|
||||
avr_isp_spi_sw_txrx(instance->spi, d);
|
||||
return res == 0x53;
|
||||
}
|
||||
|
||||
void avr_isp_end_pmode(AvrIsp* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
if(instance->pmode) {
|
||||
avr_isp_spi_sw_res_set(instance->spi, true);
|
||||
// We're about to take the target out of reset
|
||||
// so configure SPI pins as input
|
||||
if(instance->spi) avr_isp_spi_sw_free(instance->spi);
|
||||
instance->spi = NULL;
|
||||
}
|
||||
|
||||
instance->pmode = false;
|
||||
}
|
||||
|
||||
static bool avr_isp_start_pmode(AvrIsp* instance, AvrIspSpiSwSpeed spi_speed) {
|
||||
furi_assert(instance);
|
||||
|
||||
// Reset target before driving PIN_SCK or PIN_MOSI
|
||||
|
||||
// SPI.begin() will configure SS as output,
|
||||
// so SPI master mode is selected.
|
||||
// We have defined RESET as pin 10,
|
||||
// which for many arduino's is not the SS pin.
|
||||
// So we have to configure RESET as output here,
|
||||
// (reset_target() first sets the correct level)
|
||||
if(instance->spi) avr_isp_spi_sw_free(instance->spi);
|
||||
instance->spi = avr_isp_spi_sw_init(spi_speed);
|
||||
|
||||
avr_isp_spi_sw_res_set(instance->spi, false);
|
||||
// See avr datasheets, chapter "SERIAL_PRG Programming Algorithm":
|
||||
|
||||
// Pulse RESET after PIN_SCK is low:
|
||||
avr_isp_spi_sw_sck_set(instance->spi, false);
|
||||
|
||||
// discharge PIN_SCK, value arbitrally chosen
|
||||
furi_delay_ms(20);
|
||||
avr_isp_spi_sw_res_set(instance->spi, true);
|
||||
|
||||
// Pulse must be minimum 2 target CPU speed cycles
|
||||
// so 100 usec is ok for CPU speeds above 20KHz
|
||||
furi_delay_ms(1);
|
||||
|
||||
avr_isp_spi_sw_res_set(instance->spi, false);
|
||||
|
||||
// Send the enable programming command:
|
||||
// datasheet: must be > 20 msec
|
||||
furi_delay_ms(50);
|
||||
if(avr_isp_set_pmode(instance, AVR_ISP_SET_PMODE)) {
|
||||
instance->pmode = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool avr_isp_auto_set_spi_speed_start_pmode(AvrIsp* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
AvrIspSpiSwSpeed spi_speed[] = {
|
||||
AvrIspSpiSwSpeed1Mhz,
|
||||
AvrIspSpiSwSpeed400Khz,
|
||||
AvrIspSpiSwSpeed250Khz,
|
||||
AvrIspSpiSwSpeed125Khz,
|
||||
AvrIspSpiSwSpeed60Khz,
|
||||
AvrIspSpiSwSpeed40Khz,
|
||||
AvrIspSpiSwSpeed20Khz,
|
||||
AvrIspSpiSwSpeed10Khz,
|
||||
AvrIspSpiSwSpeed5Khz,
|
||||
AvrIspSpiSwSpeed1Khz,
|
||||
};
|
||||
for(uint8_t i = 0; i < COUNT_OF(spi_speed); i++) {
|
||||
if(avr_isp_start_pmode(instance, spi_speed[i])) {
|
||||
AvrIspSignature sig = avr_isp_read_signature(instance);
|
||||
AvrIspSignature sig_examination = avr_isp_read_signature(instance); //-V656
|
||||
uint8_t y = 0;
|
||||
while(y < 8) {
|
||||
if(memcmp((uint8_t*)&sig, (uint8_t*)&sig_examination, sizeof(AvrIspSignature)) !=
|
||||
0)
|
||||
break;
|
||||
sig_examination = avr_isp_read_signature(instance);
|
||||
y++;
|
||||
}
|
||||
if(y == 8) {
|
||||
if(spi_speed[i] > AvrIspSpiSwSpeed1Mhz) {
|
||||
if(i < (COUNT_OF(spi_speed) - 1)) {
|
||||
avr_isp_end_pmode(instance);
|
||||
i++;
|
||||
return avr_isp_start_pmode(instance, spi_speed[i]);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(instance->spi) {
|
||||
avr_isp_spi_sw_free(instance->spi);
|
||||
instance->spi = NULL;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void avr_isp_commit(AvrIsp* instance, uint16_t addr, uint8_t data) {
|
||||
furi_assert(instance);
|
||||
|
||||
avr_isp_spi_transaction(instance, AVR_ISP_COMMIT(addr));
|
||||
/* polling flash */
|
||||
if(data == 0xFF) {
|
||||
furi_delay_ms(5);
|
||||
} else {
|
||||
/* polling flash */
|
||||
uint32_t starttime = furi_get_tick();
|
||||
while((furi_get_tick() - starttime) < 30) {
|
||||
if(avr_isp_spi_transaction(instance, AVR_ISP_READ_FLASH_HI(addr)) != 0xFF) {
|
||||
break;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static uint16_t avr_isp_current_page(AvrIsp* instance, uint32_t addr, uint16_t page_size) {
|
||||
furi_assert(instance);
|
||||
|
||||
uint16_t page = 0;
|
||||
switch(page_size) {
|
||||
case 32:
|
||||
page = addr & 0xFFFFFFF0;
|
||||
break;
|
||||
case 64:
|
||||
page = addr & 0xFFFFFFE0;
|
||||
break;
|
||||
case 128:
|
||||
page = addr & 0xFFFFFFC0;
|
||||
break;
|
||||
case 256:
|
||||
page = addr & 0xFFFFFF80;
|
||||
break;
|
||||
|
||||
default:
|
||||
page = addr;
|
||||
break;
|
||||
}
|
||||
|
||||
return page;
|
||||
}
|
||||
|
||||
static bool avr_isp_flash_write_pages(
|
||||
AvrIsp* instance,
|
||||
uint16_t addr,
|
||||
uint16_t page_size,
|
||||
uint8_t* data,
|
||||
uint32_t data_size) {
|
||||
furi_assert(instance);
|
||||
|
||||
size_t x = 0;
|
||||
uint16_t page = avr_isp_current_page(instance, addr, page_size);
|
||||
|
||||
while(x < data_size) {
|
||||
if(page != avr_isp_current_page(instance, addr, page_size)) {
|
||||
avr_isp_commit(instance, page, data[x - 1]);
|
||||
page = avr_isp_current_page(instance, addr, page_size);
|
||||
}
|
||||
avr_isp_spi_transaction(instance, AVR_ISP_WRITE_FLASH_LO(addr, data[x++]));
|
||||
avr_isp_spi_transaction(instance, AVR_ISP_WRITE_FLASH_HI(addr, data[x++]));
|
||||
addr++;
|
||||
}
|
||||
avr_isp_commit(instance, page, data[x - 1]);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool avr_isp_erase_chip(AvrIsp* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
bool ret = false;
|
||||
if(!instance->pmode) avr_isp_auto_set_spi_speed_start_pmode(instance);
|
||||
if(instance->pmode) {
|
||||
avr_isp_spi_transaction(instance, AVR_ISP_ERASE_CHIP);
|
||||
furi_delay_ms(100);
|
||||
avr_isp_end_pmode(instance);
|
||||
ret = true;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool
|
||||
avr_isp_eeprom_write(AvrIsp* instance, uint16_t addr, uint8_t* data, uint32_t data_size) {
|
||||
furi_assert(instance);
|
||||
|
||||
for(uint16_t i = 0; i < data_size; i++) {
|
||||
avr_isp_spi_transaction(instance, AVR_ISP_WRITE_EEPROM(addr, data[i]));
|
||||
furi_delay_ms(10);
|
||||
addr++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool avr_isp_write_page(
|
||||
AvrIsp* instance,
|
||||
uint32_t mem_type,
|
||||
uint32_t mem_size,
|
||||
uint16_t addr,
|
||||
uint16_t page_size,
|
||||
uint8_t* data,
|
||||
uint32_t data_size) {
|
||||
furi_assert(instance);
|
||||
|
||||
bool ret = false;
|
||||
switch(mem_type) {
|
||||
case STK_SET_FLASH_TYPE:
|
||||
if((addr + data_size / 2) <= mem_size) {
|
||||
ret = avr_isp_flash_write_pages(instance, addr, page_size, data, data_size);
|
||||
}
|
||||
break;
|
||||
|
||||
case STK_SET_EEPROM_TYPE:
|
||||
if((addr + data_size) <= mem_size) {
|
||||
ret = avr_isp_eeprom_write(instance, addr, data, data_size);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
furi_crash(TAG " Incorrect mem type.");
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool avr_isp_flash_read_page(
|
||||
AvrIsp* instance,
|
||||
uint16_t addr,
|
||||
uint16_t page_size,
|
||||
uint8_t* data,
|
||||
uint32_t data_size) {
|
||||
furi_assert(instance);
|
||||
|
||||
if(page_size > data_size) return false;
|
||||
for(uint16_t i = 0; i < page_size; i += 2) {
|
||||
data[i] = avr_isp_spi_transaction(instance, AVR_ISP_READ_FLASH_LO(addr));
|
||||
data[i + 1] = avr_isp_spi_transaction(instance, AVR_ISP_READ_FLASH_HI(addr));
|
||||
addr++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool avr_isp_eeprom_read_page(
|
||||
AvrIsp* instance,
|
||||
uint16_t addr,
|
||||
uint16_t page_size,
|
||||
uint8_t* data,
|
||||
uint32_t data_size) {
|
||||
furi_assert(instance);
|
||||
|
||||
if(page_size > data_size) return false;
|
||||
for(uint16_t i = 0; i < page_size; i++) {
|
||||
data[i] = avr_isp_spi_transaction(instance, AVR_ISP_READ_EEPROM(addr));
|
||||
addr++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool avr_isp_read_page(
|
||||
AvrIsp* instance,
|
||||
uint32_t mem_type,
|
||||
uint16_t addr,
|
||||
uint16_t page_size,
|
||||
uint8_t* data,
|
||||
uint32_t data_size) {
|
||||
furi_assert(instance);
|
||||
|
||||
bool res = false;
|
||||
if(mem_type == STK_SET_FLASH_TYPE)
|
||||
res = avr_isp_flash_read_page(instance, addr, page_size, data, data_size);
|
||||
if(mem_type == STK_SET_EEPROM_TYPE)
|
||||
res = avr_isp_eeprom_read_page(instance, addr, page_size, data, data_size);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
AvrIspSignature avr_isp_read_signature(AvrIsp* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
AvrIspSignature signature;
|
||||
signature.vendor = avr_isp_spi_transaction(instance, AVR_ISP_READ_VENDOR);
|
||||
signature.part_family = avr_isp_spi_transaction(instance, AVR_ISP_READ_PART_FAMILY);
|
||||
signature.part_number = avr_isp_spi_transaction(instance, AVR_ISP_READ_PART_NUMBER);
|
||||
return signature;
|
||||
}
|
||||
|
||||
uint8_t avr_isp_read_lock_byte(AvrIsp* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
uint8_t data = 0;
|
||||
uint32_t starttime = furi_get_tick();
|
||||
while((furi_get_tick() - starttime) < 300) {
|
||||
data = avr_isp_spi_transaction(instance, AVR_ISP_READ_LOCK_BYTE);
|
||||
if(avr_isp_spi_transaction(instance, AVR_ISP_READ_LOCK_BYTE) == data) {
|
||||
break;
|
||||
};
|
||||
data = 0x00;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
bool avr_isp_write_lock_byte(AvrIsp* instance, uint8_t lock) {
|
||||
furi_assert(instance);
|
||||
|
||||
bool ret = false;
|
||||
if(avr_isp_read_lock_byte(instance) == lock) {
|
||||
ret = true;
|
||||
} else {
|
||||
avr_isp_spi_transaction(instance, AVR_ISP_WRITE_LOCK_BYTE(lock));
|
||||
/* polling lock byte */
|
||||
uint32_t starttime = furi_get_tick();
|
||||
while((furi_get_tick() - starttime) < 30) {
|
||||
if(avr_isp_spi_transaction(instance, AVR_ISP_READ_LOCK_BYTE) == lock) {
|
||||
ret = true;
|
||||
break;
|
||||
};
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint8_t avr_isp_read_fuse_low(AvrIsp* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
uint8_t data = 0;
|
||||
uint32_t starttime = furi_get_tick();
|
||||
while((furi_get_tick() - starttime) < 300) {
|
||||
data = avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_LOW);
|
||||
if(avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_LOW) == data) {
|
||||
break;
|
||||
};
|
||||
data = 0x00;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
bool avr_isp_write_fuse_low(AvrIsp* instance, uint8_t lfuse) {
|
||||
furi_assert(instance);
|
||||
|
||||
bool ret = false;
|
||||
if(avr_isp_read_fuse_low(instance) == lfuse) {
|
||||
ret = true;
|
||||
} else {
|
||||
avr_isp_spi_transaction(instance, AVR_ISP_WRITE_FUSE_LOW(lfuse));
|
||||
/* polling fuse */
|
||||
uint32_t starttime = furi_get_tick();
|
||||
while((furi_get_tick() - starttime) < 30) {
|
||||
if(avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_LOW) == lfuse) {
|
||||
ret = true;
|
||||
break;
|
||||
};
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint8_t avr_isp_read_fuse_high(AvrIsp* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
uint8_t data = 0;
|
||||
uint32_t starttime = furi_get_tick();
|
||||
while((furi_get_tick() - starttime) < 300) {
|
||||
data = avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_HIGH);
|
||||
if(avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_HIGH) == data) {
|
||||
break;
|
||||
};
|
||||
data = 0x00;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
bool avr_isp_write_fuse_high(AvrIsp* instance, uint8_t hfuse) {
|
||||
furi_assert(instance);
|
||||
|
||||
bool ret = false;
|
||||
if(avr_isp_read_fuse_high(instance) == hfuse) {
|
||||
ret = true;
|
||||
} else {
|
||||
avr_isp_spi_transaction(instance, AVR_ISP_WRITE_FUSE_HIGH(hfuse));
|
||||
/* polling fuse */
|
||||
uint32_t starttime = furi_get_tick();
|
||||
while((furi_get_tick() - starttime) < 30) {
|
||||
if(avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_HIGH) == hfuse) {
|
||||
ret = true;
|
||||
break;
|
||||
};
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint8_t avr_isp_read_fuse_extended(AvrIsp* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
uint8_t data = 0;
|
||||
uint32_t starttime = furi_get_tick();
|
||||
while((furi_get_tick() - starttime) < 300) {
|
||||
data = avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_EXTENDED);
|
||||
if(avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_EXTENDED) == data) {
|
||||
break;
|
||||
};
|
||||
data = 0x00;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
bool avr_isp_write_fuse_extended(AvrIsp* instance, uint8_t efuse) {
|
||||
furi_assert(instance);
|
||||
|
||||
bool ret = false;
|
||||
if(avr_isp_read_fuse_extended(instance) == efuse) {
|
||||
ret = true;
|
||||
} else {
|
||||
avr_isp_spi_transaction(instance, AVR_ISP_WRITE_FUSE_EXTENDED(efuse));
|
||||
/* polling fuse */
|
||||
uint32_t starttime = furi_get_tick();
|
||||
while((furi_get_tick() - starttime) < 30) {
|
||||
if(avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_EXTENDED) == efuse) {
|
||||
ret = true;
|
||||
break;
|
||||
};
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void avr_isp_write_extended_addr(AvrIsp* instance, uint8_t extended_addr) {
|
||||
furi_assert(instance);
|
||||
|
||||
avr_isp_spi_transaction(instance, AVR_ISP_EXTENDED_ADDR(extended_addr));
|
||||
furi_delay_ms(10);
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <furi_hal.h>
|
||||
|
||||
typedef struct AvrIsp AvrIsp;
|
||||
typedef void (*AvrIspCallback)(void* context);
|
||||
|
||||
struct AvrIspSignature {
|
||||
uint8_t vendor;
|
||||
uint8_t part_family;
|
||||
uint8_t part_number;
|
||||
};
|
||||
|
||||
typedef struct AvrIspSignature AvrIspSignature;
|
||||
|
||||
AvrIsp* avr_isp_alloc(void);
|
||||
|
||||
void avr_isp_free(AvrIsp* instance);
|
||||
|
||||
void avr_isp_set_tx_callback(AvrIsp* instance, AvrIspCallback callback, void* context);
|
||||
|
||||
bool avr_isp_auto_set_spi_speed_start_pmode(AvrIsp* instance);
|
||||
|
||||
AvrIspSignature avr_isp_read_signature(AvrIsp* instance);
|
||||
|
||||
void avr_isp_end_pmode(AvrIsp* instance);
|
||||
|
||||
bool avr_isp_erase_chip(AvrIsp* instance);
|
||||
|
||||
uint8_t avr_isp_spi_transaction(
|
||||
AvrIsp* instance,
|
||||
uint8_t cmd,
|
||||
uint8_t addr_hi,
|
||||
uint8_t addr_lo,
|
||||
uint8_t data);
|
||||
|
||||
bool avr_isp_read_page(
|
||||
AvrIsp* instance,
|
||||
uint32_t memtype,
|
||||
uint16_t addr,
|
||||
uint16_t page_size,
|
||||
uint8_t* data,
|
||||
uint32_t data_size);
|
||||
|
||||
bool avr_isp_write_page(
|
||||
AvrIsp* instance,
|
||||
uint32_t mem_type,
|
||||
uint32_t mem_size,
|
||||
uint16_t addr,
|
||||
uint16_t page_size,
|
||||
uint8_t* data,
|
||||
uint32_t data_size);
|
||||
|
||||
uint8_t avr_isp_read_lock_byte(AvrIsp* instance);
|
||||
|
||||
bool avr_isp_write_lock_byte(AvrIsp* instance, uint8_t lock);
|
||||
|
||||
uint8_t avr_isp_read_fuse_low(AvrIsp* instance);
|
||||
|
||||
bool avr_isp_write_fuse_low(AvrIsp* instance, uint8_t lfuse);
|
||||
|
||||
uint8_t avr_isp_read_fuse_high(AvrIsp* instance);
|
||||
|
||||
bool avr_isp_write_fuse_high(AvrIsp* instance, uint8_t hfuse);
|
||||
|
||||
uint8_t avr_isp_read_fuse_extended(AvrIsp* instance);
|
||||
|
||||
bool avr_isp_write_fuse_extended(AvrIsp* instance, uint8_t efuse);
|
||||
|
||||
void avr_isp_write_extended_addr(AvrIsp* instance, uint8_t extended_addr);
|
||||
@@ -1,23 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
typedef enum {
|
||||
//SubmenuIndex
|
||||
SubmenuIndexAvrIspProgrammer = 10,
|
||||
SubmenuIndexAvrIspReader,
|
||||
SubmenuIndexAvrIspWriter,
|
||||
SubmenuIndexAvrIsWiring,
|
||||
SubmenuIndexAvrIspAbout,
|
||||
|
||||
//AvrIspCustomEvent
|
||||
AvrIspCustomEventSceneChipDetectOk = 100,
|
||||
AvrIspCustomEventSceneReadingOk,
|
||||
AvrIspCustomEventSceneWritingOk,
|
||||
AvrIspCustomEventSceneErrorVerification,
|
||||
AvrIspCustomEventSceneErrorReading,
|
||||
AvrIspCustomEventSceneErrorWriting,
|
||||
AvrIspCustomEventSceneErrorWritingFuse,
|
||||
AvrIspCustomEventSceneInputName,
|
||||
AvrIspCustomEventSceneSuccess,
|
||||
AvrIspCustomEventSceneExit,
|
||||
AvrIspCustomEventSceneExitStartMenu,
|
||||
} AvrIspCustomEvent;
|
||||
@@ -1,32 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
|
||||
#define AVR_ISP_VERSION_APP "0.1"
|
||||
#define AVR_ISP_DEVELOPED "SkorP"
|
||||
#define AVR_ISP_GITHUB "https://github.com/flipperdevices/flipperzero-firmware"
|
||||
|
||||
#define AVR_ISP_APP_FILE_VERSION 1
|
||||
#define AVR_ISP_APP_FILE_TYPE "Flipper Dump AVR"
|
||||
#define AVR_ISP_APP_EXTENSION ".avr"
|
||||
|
||||
typedef enum {
|
||||
//AvrIspViewVariableItemList,
|
||||
AvrIspViewSubmenu,
|
||||
AvrIspViewProgrammer,
|
||||
AvrIspViewReader,
|
||||
AvrIspViewWriter,
|
||||
AvrIspViewWidget,
|
||||
AvrIspViewPopup,
|
||||
AvrIspViewTextInput,
|
||||
AvrIspViewChipDetect,
|
||||
} AvrIspView;
|
||||
|
||||
typedef enum {
|
||||
AvrIspErrorNoError,
|
||||
AvrIspErrorReading,
|
||||
AvrIspErrorWriting,
|
||||
AvrIspErrorVerification,
|
||||
AvrIspErrorWritingFuse,
|
||||
} AvrIspError;
|
||||
@@ -1,266 +0,0 @@
|
||||
#include "avr_isp_worker.h"
|
||||
#include <furi_hal_pwm.h>
|
||||
#include "../lib/driver/avr_isp_prog.h"
|
||||
#include "../lib/driver/avr_isp_prog_cmd.h"
|
||||
#include "../lib/driver/avr_isp_chip_arr.h"
|
||||
|
||||
#include <furi.h>
|
||||
|
||||
#define TAG "AvrIspWorker"
|
||||
|
||||
typedef enum {
|
||||
AvrIspWorkerEvtStop = (1 << 0),
|
||||
|
||||
AvrIspWorkerEvtRx = (1 << 1),
|
||||
AvrIspWorkerEvtTxCoplete = (1 << 2),
|
||||
AvrIspWorkerEvtTx = (1 << 3),
|
||||
AvrIspWorkerEvtState = (1 << 4),
|
||||
|
||||
//AvrIspWorkerEvtCfg = (1 << 5),
|
||||
|
||||
} AvrIspWorkerEvt;
|
||||
|
||||
struct AvrIspWorker {
|
||||
FuriThread* thread;
|
||||
volatile bool worker_running;
|
||||
uint8_t connect_usb;
|
||||
AvrIspWorkerCallback callback;
|
||||
void* context;
|
||||
};
|
||||
|
||||
#define AVR_ISP_WORKER_PROG_ALL_EVENTS (AvrIspWorkerEvtStop)
|
||||
#define AVR_ISP_WORKER_ALL_EVENTS \
|
||||
(AvrIspWorkerEvtTx | AvrIspWorkerEvtTxCoplete | AvrIspWorkerEvtRx | AvrIspWorkerEvtStop | \
|
||||
AvrIspWorkerEvtState)
|
||||
|
||||
//########################/* VCP CDC */#############################################
|
||||
#include "usb_cdc.h"
|
||||
#include <cli/cli_vcp.h>
|
||||
#include <cli/cli.h>
|
||||
#include <furi_hal_usb_cdc.h>
|
||||
|
||||
#define AVR_ISP_VCP_CDC_CH 1
|
||||
#define AVR_ISP_VCP_CDC_PKT_LEN CDC_DATA_SZ
|
||||
#define AVR_ISP_VCP_UART_RX_BUF_SIZE (AVR_ISP_VCP_CDC_PKT_LEN * 5)
|
||||
|
||||
static void vcp_on_cdc_tx_complete(void* context);
|
||||
static void vcp_on_cdc_rx(void* context);
|
||||
static void vcp_state_callback(void* context, uint8_t state);
|
||||
static void vcp_on_cdc_control_line(void* context, uint8_t state);
|
||||
static void vcp_on_line_config(void* context, struct usb_cdc_line_coding* config);
|
||||
|
||||
static const CdcCallbacks cdc_cb = {
|
||||
vcp_on_cdc_tx_complete,
|
||||
vcp_on_cdc_rx,
|
||||
vcp_state_callback,
|
||||
vcp_on_cdc_control_line,
|
||||
vcp_on_line_config,
|
||||
};
|
||||
|
||||
/* VCP callbacks */
|
||||
|
||||
static void vcp_on_cdc_tx_complete(void* context) {
|
||||
furi_assert(context);
|
||||
AvrIspWorker* instance = context;
|
||||
furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerEvtTxCoplete);
|
||||
}
|
||||
|
||||
static void vcp_on_cdc_rx(void* context) {
|
||||
furi_assert(context);
|
||||
AvrIspWorker* instance = context;
|
||||
furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerEvtRx);
|
||||
}
|
||||
|
||||
static void vcp_state_callback(void* context, uint8_t state) {
|
||||
UNUSED(context);
|
||||
|
||||
AvrIspWorker* instance = context;
|
||||
instance->connect_usb = state;
|
||||
furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerEvtState);
|
||||
}
|
||||
|
||||
static void vcp_on_cdc_control_line(void* context, uint8_t state) {
|
||||
UNUSED(context);
|
||||
UNUSED(state);
|
||||
}
|
||||
|
||||
static void vcp_on_line_config(void* context, struct usb_cdc_line_coding* config) {
|
||||
UNUSED(context);
|
||||
UNUSED(config);
|
||||
}
|
||||
|
||||
static void avr_isp_worker_vcp_cdc_init(void* context) {
|
||||
furi_hal_usb_unlock();
|
||||
Cli* cli = furi_record_open(RECORD_CLI);
|
||||
//close cli
|
||||
cli_session_close(cli);
|
||||
//disable callbacks VCP_CDC=0
|
||||
furi_hal_cdc_set_callbacks(0, NULL, NULL);
|
||||
//set 2 cdc
|
||||
furi_check(furi_hal_usb_set_config(&usb_cdc_dual, NULL) == true);
|
||||
//open cli VCP_CDC=0
|
||||
cli_session_open(cli, &cli_vcp);
|
||||
furi_record_close(RECORD_CLI);
|
||||
|
||||
furi_hal_cdc_set_callbacks(AVR_ISP_VCP_CDC_CH, (CdcCallbacks*)&cdc_cb, context);
|
||||
}
|
||||
|
||||
static void avr_isp_worker_vcp_cdc_deinit(void) {
|
||||
//disable callbacks AVR_ISP_VCP_CDC_CH
|
||||
furi_hal_cdc_set_callbacks(AVR_ISP_VCP_CDC_CH, NULL, NULL);
|
||||
|
||||
Cli* cli = furi_record_open(RECORD_CLI);
|
||||
//close cli
|
||||
cli_session_close(cli);
|
||||
furi_hal_usb_unlock();
|
||||
//set 1 cdc
|
||||
furi_check(furi_hal_usb_set_config(&usb_cdc_single, NULL) == true);
|
||||
//open cli VCP_CDC=0
|
||||
cli_session_open(cli, &cli_vcp);
|
||||
furi_record_close(RECORD_CLI);
|
||||
}
|
||||
|
||||
//#################################################################################
|
||||
|
||||
static int32_t avr_isp_worker_prog_thread(void* context) {
|
||||
AvrIspProg* prog = context;
|
||||
FURI_LOG_D(TAG, "AvrIspProgWorker Start");
|
||||
while(1) {
|
||||
if(furi_thread_flags_get() & AvrIspWorkerEvtStop) break;
|
||||
avr_isp_prog_avrisp(prog);
|
||||
}
|
||||
FURI_LOG_D(TAG, "AvrIspProgWorker Stop");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void avr_isp_worker_prog_tx_data(void* context) {
|
||||
furi_assert(context);
|
||||
AvrIspWorker* instance = context;
|
||||
furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerEvtTx);
|
||||
}
|
||||
|
||||
/** Worker thread
|
||||
*
|
||||
* @param context
|
||||
* @return exit code
|
||||
*/
|
||||
static int32_t avr_isp_worker_thread(void* context) {
|
||||
AvrIspWorker* instance = context;
|
||||
avr_isp_worker_vcp_cdc_init(instance);
|
||||
|
||||
/* start PWM on &gpio_ext_pa4 */
|
||||
furi_hal_pwm_start(FuriHalPwmOutputIdLptim2PA4, 4000000, 50);
|
||||
|
||||
AvrIspProg* prog = avr_isp_prog_init();
|
||||
avr_isp_prog_set_tx_callback(prog, avr_isp_worker_prog_tx_data, instance);
|
||||
|
||||
uint8_t buf[AVR_ISP_VCP_UART_RX_BUF_SIZE];
|
||||
size_t len = 0;
|
||||
|
||||
FuriThread* prog_thread =
|
||||
furi_thread_alloc_ex("AvrIspProgWorker", 1024, avr_isp_worker_prog_thread, prog);
|
||||
furi_thread_start(prog_thread);
|
||||
|
||||
FURI_LOG_D(TAG, "Start");
|
||||
|
||||
while(instance->worker_running) {
|
||||
uint32_t events =
|
||||
furi_thread_flags_wait(AVR_ISP_WORKER_ALL_EVENTS, FuriFlagWaitAny, FuriWaitForever);
|
||||
|
||||
if(events & AvrIspWorkerEvtRx) {
|
||||
if(avr_isp_prog_spaces_rx(prog) >= AVR_ISP_VCP_CDC_PKT_LEN) {
|
||||
len = furi_hal_cdc_receive(AVR_ISP_VCP_CDC_CH, buf, AVR_ISP_VCP_CDC_PKT_LEN);
|
||||
// for(uint8_t i = 0; i < len; i++) {
|
||||
// FURI_LOG_I(TAG, "--> %X", buf[i]);
|
||||
// }
|
||||
avr_isp_prog_rx(prog, buf, len);
|
||||
} else {
|
||||
furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerEvtRx);
|
||||
}
|
||||
}
|
||||
|
||||
if((events & AvrIspWorkerEvtTxCoplete) || (events & AvrIspWorkerEvtTx)) {
|
||||
len = avr_isp_prog_tx(prog, buf, AVR_ISP_VCP_CDC_PKT_LEN);
|
||||
|
||||
// for(uint8_t i = 0; i < len; i++) {
|
||||
// FURI_LOG_I(TAG, "<-- %X", buf[i]);
|
||||
// }
|
||||
|
||||
if(len > 0) furi_hal_cdc_send(AVR_ISP_VCP_CDC_CH, buf, len);
|
||||
}
|
||||
|
||||
if(events & AvrIspWorkerEvtStop) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(events & AvrIspWorkerEvtState) {
|
||||
if(instance->callback)
|
||||
instance->callback(instance->context, (bool)instance->connect_usb);
|
||||
}
|
||||
}
|
||||
|
||||
FURI_LOG_D(TAG, "Stop");
|
||||
|
||||
furi_thread_flags_set(furi_thread_get_id(prog_thread), AvrIspWorkerEvtStop);
|
||||
avr_isp_prog_exit(prog);
|
||||
furi_delay_ms(10);
|
||||
furi_thread_join(prog_thread);
|
||||
furi_thread_free(prog_thread);
|
||||
|
||||
avr_isp_prog_free(prog);
|
||||
furi_hal_pwm_stop(FuriHalPwmOutputIdLptim2PA4);
|
||||
avr_isp_worker_vcp_cdc_deinit();
|
||||
return 0;
|
||||
}
|
||||
|
||||
AvrIspWorker* avr_isp_worker_alloc(void* context) {
|
||||
furi_assert(context);
|
||||
UNUSED(context);
|
||||
AvrIspWorker* instance = malloc(sizeof(AvrIspWorker));
|
||||
|
||||
instance->thread = furi_thread_alloc_ex("AvrIspWorker", 2048, avr_isp_worker_thread, instance);
|
||||
return instance;
|
||||
}
|
||||
|
||||
void avr_isp_worker_free(AvrIspWorker* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
furi_check(!instance->worker_running);
|
||||
furi_thread_free(instance->thread);
|
||||
free(instance);
|
||||
}
|
||||
|
||||
void avr_isp_worker_set_callback(
|
||||
AvrIspWorker* instance,
|
||||
AvrIspWorkerCallback callback,
|
||||
void* context) {
|
||||
furi_assert(instance);
|
||||
|
||||
instance->callback = callback;
|
||||
instance->context = context;
|
||||
}
|
||||
|
||||
void avr_isp_worker_start(AvrIspWorker* instance) {
|
||||
furi_assert(instance);
|
||||
furi_assert(!instance->worker_running);
|
||||
|
||||
instance->worker_running = true;
|
||||
|
||||
furi_thread_start(instance->thread);
|
||||
}
|
||||
|
||||
void avr_isp_worker_stop(AvrIspWorker* instance) {
|
||||
furi_assert(instance);
|
||||
furi_assert(instance->worker_running);
|
||||
|
||||
instance->worker_running = false;
|
||||
furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerEvtStop);
|
||||
|
||||
furi_thread_join(instance->thread);
|
||||
}
|
||||
|
||||
bool avr_isp_worker_is_running(AvrIspWorker* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
return instance->worker_running;
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <furi_hal.h>
|
||||
|
||||
typedef struct AvrIspWorker AvrIspWorker;
|
||||
|
||||
typedef void (*AvrIspWorkerCallback)(void* context, bool connect_usb);
|
||||
|
||||
/** Allocate AvrIspWorker
|
||||
*
|
||||
* @param context AvrIsp* context
|
||||
* @return AvrIspWorker*
|
||||
*/
|
||||
AvrIspWorker* avr_isp_worker_alloc(void* context);
|
||||
|
||||
/** Free AvrIspWorker
|
||||
*
|
||||
* @param instance AvrIspWorker instance
|
||||
*/
|
||||
void avr_isp_worker_free(AvrIspWorker* instance);
|
||||
|
||||
/** Callback AvrIspWorker
|
||||
*
|
||||
* @param instance AvrIspWorker instance
|
||||
* @param callback AvrIspWorkerOverrunCallback callback
|
||||
* @param context
|
||||
*/
|
||||
void avr_isp_worker_set_callback(
|
||||
AvrIspWorker* instance,
|
||||
AvrIspWorkerCallback callback,
|
||||
void* context);
|
||||
|
||||
/** Start AvrIspWorker
|
||||
*
|
||||
* @param instance AvrIspWorker instance
|
||||
*/
|
||||
void avr_isp_worker_start(AvrIspWorker* instance);
|
||||
|
||||
/** Stop AvrIspWorker
|
||||
*
|
||||
* @param instance AvrIspWorker instance
|
||||
*/
|
||||
void avr_isp_worker_stop(AvrIspWorker* instance);
|
||||
|
||||
/** Check if worker is running
|
||||
* @param instance AvrIspWorker instance
|
||||
* @return bool - true if running
|
||||
*/
|
||||
bool avr_isp_worker_is_running(AvrIspWorker* instance);
|
||||
@@ -1,99 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <furi_hal.h>
|
||||
|
||||
typedef struct AvrIspWorkerRW AvrIspWorkerRW;
|
||||
|
||||
typedef void (*AvrIspWorkerRWCallback)(
|
||||
void* context,
|
||||
const char* name,
|
||||
bool detect_chip,
|
||||
uint32_t flash_size);
|
||||
|
||||
typedef enum {
|
||||
AvrIspWorkerRWStatusILDE = 0,
|
||||
AvrIspWorkerRWStatusEndReading = 1,
|
||||
AvrIspWorkerRWStatusEndVerification = 2,
|
||||
AvrIspWorkerRWStatusEndWriting = 3,
|
||||
AvrIspWorkerRWStatusEndWritingFuse = 4,
|
||||
|
||||
AvrIspWorkerRWStatusErrorReading = (-1),
|
||||
AvrIspWorkerRWStatusErrorVerification = (-2),
|
||||
AvrIspWorkerRWStatusErrorWriting = (-3),
|
||||
AvrIspWorkerRWStatusErrorWritingFuse = (-4),
|
||||
|
||||
AvrIspWorkerRWStatusReserved = 0x7FFFFFFF, ///< Prevents enum down-size compiler optimization.
|
||||
} AvrIspWorkerRWStatus;
|
||||
|
||||
typedef void (*AvrIspWorkerRWStatusCallback)(void* context, AvrIspWorkerRWStatus status);
|
||||
|
||||
AvrIspWorkerRW* avr_isp_worker_rw_alloc(void* context);
|
||||
|
||||
void avr_isp_worker_rw_free(AvrIspWorkerRW* instance);
|
||||
|
||||
void avr_isp_worker_rw_start(AvrIspWorkerRW* instance);
|
||||
|
||||
void avr_isp_worker_rw_stop(AvrIspWorkerRW* instance);
|
||||
|
||||
bool avr_isp_worker_rw_is_running(AvrIspWorkerRW* instance);
|
||||
|
||||
void avr_isp_worker_rw_set_callback(
|
||||
AvrIspWorkerRW* instance,
|
||||
AvrIspWorkerRWCallback callback,
|
||||
void* context);
|
||||
|
||||
void avr_isp_worker_rw_set_callback_status(
|
||||
AvrIspWorkerRW* instance,
|
||||
AvrIspWorkerRWStatusCallback callback_status,
|
||||
void* context_status);
|
||||
|
||||
bool avr_isp_worker_rw_detect_chip(AvrIspWorkerRW* instance);
|
||||
|
||||
float avr_isp_worker_rw_get_progress_flash(AvrIspWorkerRW* instance);
|
||||
|
||||
float avr_isp_worker_rw_get_progress_eeprom(AvrIspWorkerRW* instance);
|
||||
|
||||
bool avr_isp_worker_rw_read_dump(
|
||||
AvrIspWorkerRW* instance,
|
||||
const char* file_path,
|
||||
const char* file_name);
|
||||
|
||||
void avr_isp_worker_rw_read_dump_start(
|
||||
AvrIspWorkerRW* instance,
|
||||
const char* file_path,
|
||||
const char* file_name);
|
||||
|
||||
bool avr_isp_worker_rw_verification(
|
||||
AvrIspWorkerRW* instance,
|
||||
const char* file_path,
|
||||
const char* file_name);
|
||||
|
||||
void avr_isp_worker_rw_verification_start(
|
||||
AvrIspWorkerRW* instance,
|
||||
const char* file_path,
|
||||
const char* file_name);
|
||||
|
||||
bool avr_isp_worker_rw_check_hex(
|
||||
AvrIspWorkerRW* instance,
|
||||
const char* file_path,
|
||||
const char* file_name);
|
||||
|
||||
bool avr_isp_worker_rw_write_dump(
|
||||
AvrIspWorkerRW* instance,
|
||||
const char* file_path,
|
||||
const char* file_name);
|
||||
|
||||
void avr_isp_worker_rw_write_dump_start(
|
||||
AvrIspWorkerRW* instance,
|
||||
const char* file_path,
|
||||
const char* file_name);
|
||||
|
||||
bool avr_isp_worker_rw_write_fuse(
|
||||
AvrIspWorkerRW* instance,
|
||||
const char* file_path,
|
||||
const char* file_name);
|
||||
|
||||
void avr_isp_worker_rw_write_fuse_start(
|
||||
AvrIspWorkerRW* instance,
|
||||
const char* file_path,
|
||||
const char* file_name);
|
||||
@@ -1,321 +0,0 @@
|
||||
#include "flipper_i32hex_file.h"
|
||||
#include <string.h>
|
||||
#include <storage/storage.h>
|
||||
#include <toolbox/stream/stream.h>
|
||||
#include <toolbox/stream/file_stream.h>
|
||||
#include <toolbox/hex.h>
|
||||
|
||||
//https://en.wikipedia.org/wiki/Intel_HEX
|
||||
|
||||
#define TAG "FlipperI32HexFile"
|
||||
|
||||
#define COUNT_BYTE_PAYLOAD 32 //how much payload will be used
|
||||
|
||||
#define I32HEX_TYPE_DATA 0x00
|
||||
#define I32HEX_TYPE_END_OF_FILE 0x01
|
||||
#define I32HEX_TYPE_EXT_LINEAR_ADDR 0x04
|
||||
#define I32HEX_TYPE_START_LINEAR_ADDR 0x05
|
||||
|
||||
struct FlipperI32HexFile {
|
||||
uint32_t addr;
|
||||
uint32_t addr_last;
|
||||
Storage* storage;
|
||||
Stream* stream;
|
||||
FuriString* str_data;
|
||||
FlipperI32HexFileStatus file_open;
|
||||
};
|
||||
|
||||
FlipperI32HexFile* flipper_i32hex_file_open_write(const char* name, uint32_t start_addr) {
|
||||
furi_assert(name);
|
||||
|
||||
FlipperI32HexFile* instance = malloc(sizeof(FlipperI32HexFile));
|
||||
instance->addr = start_addr;
|
||||
instance->addr_last = 0;
|
||||
instance->storage = furi_record_open(RECORD_STORAGE);
|
||||
instance->stream = file_stream_alloc(instance->storage);
|
||||
|
||||
if(file_stream_open(instance->stream, name, FSAM_WRITE, FSOM_CREATE_ALWAYS)) {
|
||||
instance->file_open = FlipperI32HexFileStatusOpenFileWrite;
|
||||
FURI_LOG_D(TAG, "Open write file %s", name);
|
||||
} else {
|
||||
FURI_LOG_E(TAG, "Failed to open file %s", name);
|
||||
instance->file_open = FlipperI32HexFileStatusErrorNoOpenFile;
|
||||
}
|
||||
instance->str_data = furi_string_alloc(instance->storage);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
FlipperI32HexFile* flipper_i32hex_file_open_read(const char* name) {
|
||||
furi_assert(name);
|
||||
|
||||
FlipperI32HexFile* instance = malloc(sizeof(FlipperI32HexFile));
|
||||
instance->addr = 0;
|
||||
instance->addr_last = 0;
|
||||
instance->storage = furi_record_open(RECORD_STORAGE);
|
||||
instance->stream = file_stream_alloc(instance->storage);
|
||||
|
||||
if(file_stream_open(instance->stream, name, FSAM_READ, FSOM_OPEN_EXISTING)) {
|
||||
instance->file_open = FlipperI32HexFileStatusOpenFileRead;
|
||||
FURI_LOG_D(TAG, "Open read file %s", name);
|
||||
} else {
|
||||
FURI_LOG_E(TAG, "Failed to open file %s", name);
|
||||
instance->file_open = FlipperI32HexFileStatusErrorNoOpenFile;
|
||||
}
|
||||
instance->str_data = furi_string_alloc(instance->storage);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
void flipper_i32hex_file_close(FlipperI32HexFile* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
furi_string_free(instance->str_data);
|
||||
file_stream_close(instance->stream);
|
||||
stream_free(instance->stream);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
}
|
||||
|
||||
FlipperI32HexFileRet flipper_i32hex_file_bin_to_i32hex_set_data(
|
||||
FlipperI32HexFile* instance,
|
||||
uint8_t* data,
|
||||
uint32_t data_size) {
|
||||
furi_assert(instance);
|
||||
furi_assert(data);
|
||||
|
||||
FlipperI32HexFileRet ret = {.status = FlipperI32HexFileStatusOK, .data_size = 0};
|
||||
if(instance->file_open != FlipperI32HexFileStatusOpenFileWrite) {
|
||||
ret.status = FlipperI32HexFileStatusErrorFileWrite;
|
||||
}
|
||||
uint8_t count_byte = 0;
|
||||
uint32_t ind = 0;
|
||||
uint8_t crc = 0;
|
||||
|
||||
furi_string_reset(instance->str_data);
|
||||
|
||||
if((instance->addr_last & 0xFF0000) < (instance->addr & 0xFF0000)) {
|
||||
crc = 0x02 + 0x04 + ((instance->addr >> 24) & 0xFF) + ((instance->addr >> 16) & 0xFF);
|
||||
crc = 0x01 + ~crc;
|
||||
//I32HEX_TYPE_EXT_LINEAR_ADDR
|
||||
furi_string_cat_printf(
|
||||
instance->str_data, ":02000004%04lX%02X\r\n", (instance->addr >> 16), crc);
|
||||
instance->addr_last = instance->addr;
|
||||
}
|
||||
|
||||
while(ind < data_size) {
|
||||
if((ind + COUNT_BYTE_PAYLOAD) > data_size) {
|
||||
count_byte = data_size - ind;
|
||||
} else {
|
||||
count_byte = COUNT_BYTE_PAYLOAD;
|
||||
}
|
||||
//I32HEX_TYPE_DATA
|
||||
furi_string_cat_printf(
|
||||
instance->str_data, ":%02X%04lX00", count_byte, (instance->addr & 0xFFFF));
|
||||
crc = count_byte + ((instance->addr >> 8) & 0xFF) + (instance->addr & 0xFF);
|
||||
|
||||
for(uint32_t i = 0; i < count_byte; i++) {
|
||||
furi_string_cat_printf(instance->str_data, "%02X", *data);
|
||||
crc += *data++;
|
||||
}
|
||||
crc = 0x01 + ~crc;
|
||||
furi_string_cat_printf(instance->str_data, "%02X\r\n", crc);
|
||||
|
||||
ind += count_byte;
|
||||
instance->addr += count_byte;
|
||||
}
|
||||
if(instance->file_open) stream_write_string(instance->stream, instance->str_data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
FlipperI32HexFileRet flipper_i32hex_file_bin_to_i32hex_set_end_line(FlipperI32HexFile* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
FlipperI32HexFileRet ret = {.status = FlipperI32HexFileStatusOK, .data_size = 0};
|
||||
if(instance->file_open != FlipperI32HexFileStatusOpenFileWrite) {
|
||||
ret.status = FlipperI32HexFileStatusErrorFileWrite;
|
||||
}
|
||||
furi_string_reset(instance->str_data);
|
||||
//I32HEX_TYPE_END_OF_FILE
|
||||
furi_string_cat_printf(instance->str_data, ":00000001FF\r\n");
|
||||
if(instance->file_open) stream_write_string(instance->stream, instance->str_data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void flipper_i32hex_file_bin_to_i32hex_set_addr(FlipperI32HexFile* instance, uint32_t addr) {
|
||||
furi_assert(instance);
|
||||
|
||||
instance->addr = addr;
|
||||
}
|
||||
|
||||
const char* flipper_i32hex_file_get_string(FlipperI32HexFile* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
return furi_string_get_cstr(instance->str_data);
|
||||
}
|
||||
|
||||
static FlipperI32HexFileRet flipper_i32hex_file_parse_line(
|
||||
FlipperI32HexFile* instance,
|
||||
const char* str,
|
||||
uint8_t* data,
|
||||
uint32_t data_size) {
|
||||
furi_assert(instance);
|
||||
furi_assert(data);
|
||||
|
||||
char* str1;
|
||||
uint32_t data_wrire_ind = 0;
|
||||
uint32_t data_len = 0;
|
||||
FlipperI32HexFileRet ret = {.status = FlipperI32HexFileStatusErrorData, .data_size = 0};
|
||||
|
||||
//Search for start of data I32HEX
|
||||
str1 = strstr(str, ":");
|
||||
do {
|
||||
if(str1 == NULL) {
|
||||
ret.status = FlipperI32HexFileStatusErrorData;
|
||||
break;
|
||||
}
|
||||
str1++;
|
||||
if(!hex_char_to_uint8(*str1, str1[1], data + data_wrire_ind)) {
|
||||
ret.status = FlipperI32HexFileStatusErrorData;
|
||||
break;
|
||||
}
|
||||
str1++;
|
||||
if(++data_wrire_ind > data_size) {
|
||||
ret.status = FlipperI32HexFileStatusErrorOverflow;
|
||||
break;
|
||||
}
|
||||
data_len = 5 + data[0]; // +5 bytes per header and crc
|
||||
while(data_len > data_wrire_ind) {
|
||||
str1++;
|
||||
if(!hex_char_to_uint8(*str1, str1[1], data + data_wrire_ind)) {
|
||||
ret.status = FlipperI32HexFileStatusErrorData;
|
||||
break;
|
||||
}
|
||||
str1++;
|
||||
if(++data_wrire_ind > data_size) {
|
||||
ret.status = FlipperI32HexFileStatusErrorOverflow;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ret.status = FlipperI32HexFileStatusOK;
|
||||
ret.data_size = data_wrire_ind;
|
||||
|
||||
} while(0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool flipper_i32hex_file_check_data(uint8_t* data, uint32_t data_size) {
|
||||
furi_assert(data);
|
||||
|
||||
uint8_t crc = 0;
|
||||
uint32_t data_read_ind = 0;
|
||||
if(data[0] > data_size) return false;
|
||||
while(data_read_ind < data_size - 1) {
|
||||
crc += data[data_read_ind++];
|
||||
}
|
||||
return data[data_size - 1] == ((1 + ~crc) & 0xFF);
|
||||
}
|
||||
|
||||
static FlipperI32HexFileRet flipper_i32hex_file_parse(
|
||||
FlipperI32HexFile* instance,
|
||||
const char* str,
|
||||
uint8_t* data,
|
||||
uint32_t data_size) {
|
||||
furi_assert(instance);
|
||||
furi_assert(data);
|
||||
|
||||
FlipperI32HexFileRet ret = flipper_i32hex_file_parse_line(instance, str, data, data_size);
|
||||
|
||||
if((ret.status == FlipperI32HexFileStatusOK) && (ret.data_size > 4)) {
|
||||
switch(data[3]) {
|
||||
case I32HEX_TYPE_DATA:
|
||||
if(flipper_i32hex_file_check_data(data, ret.data_size)) {
|
||||
ret.data_size -= 5;
|
||||
memcpy(data, data + 4, ret.data_size);
|
||||
ret.status = FlipperI32HexFileStatusData;
|
||||
} else {
|
||||
ret.status = FlipperI32HexFileStatusErrorCrc;
|
||||
ret.data_size = 0;
|
||||
}
|
||||
break;
|
||||
case I32HEX_TYPE_END_OF_FILE:
|
||||
if(flipper_i32hex_file_check_data(data, ret.data_size)) {
|
||||
ret.status = FlipperI32HexFileStatusEofFile;
|
||||
ret.data_size = 0;
|
||||
} else {
|
||||
ret.status = FlipperI32HexFileStatusErrorCrc;
|
||||
ret.data_size = 0;
|
||||
}
|
||||
break;
|
||||
case I32HEX_TYPE_EXT_LINEAR_ADDR:
|
||||
if(flipper_i32hex_file_check_data(data, ret.data_size)) {
|
||||
data[0] = data[4];
|
||||
data[1] = data[5];
|
||||
data[3] = 0;
|
||||
data[4] = 0;
|
||||
ret.status = FlipperI32HexFileStatusUdateAddr;
|
||||
ret.data_size = 4;
|
||||
} else {
|
||||
ret.status = FlipperI32HexFileStatusErrorCrc;
|
||||
ret.data_size = 0;
|
||||
}
|
||||
break;
|
||||
case I32HEX_TYPE_START_LINEAR_ADDR:
|
||||
ret.status = FlipperI32HexFileStatusErrorUnsupportedCommand;
|
||||
ret.data_size = 0;
|
||||
break;
|
||||
default:
|
||||
ret.status = FlipperI32HexFileStatusErrorUnsupportedCommand;
|
||||
ret.data_size = 0;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
ret.status = FlipperI32HexFileStatusErrorData;
|
||||
ret.data_size = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool flipper_i32hex_file_check(FlipperI32HexFile* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
uint32_t data_size = 280;
|
||||
uint8_t data[280] = {0};
|
||||
bool ret = true;
|
||||
|
||||
if(instance->file_open != FlipperI32HexFileStatusOpenFileRead) {
|
||||
FURI_LOG_E(TAG, "File is not open");
|
||||
ret = false;
|
||||
} else {
|
||||
stream_rewind(instance->stream);
|
||||
|
||||
while(stream_read_line(instance->stream, instance->str_data)) {
|
||||
FlipperI32HexFileRet parse_ret = flipper_i32hex_file_parse(
|
||||
instance, furi_string_get_cstr(instance->str_data), data, data_size);
|
||||
|
||||
if(parse_ret.status < 0) {
|
||||
ret = false;
|
||||
}
|
||||
}
|
||||
stream_rewind(instance->stream);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
FlipperI32HexFileRet flipper_i32hex_file_i32hex_to_bin_get_data(
|
||||
FlipperI32HexFile* instance,
|
||||
uint8_t* data,
|
||||
uint32_t data_size) {
|
||||
furi_assert(instance);
|
||||
furi_assert(data);
|
||||
|
||||
FlipperI32HexFileRet ret = {.status = FlipperI32HexFileStatusOK, .data_size = 0};
|
||||
if(instance->file_open != FlipperI32HexFileStatusOpenFileRead) {
|
||||
ret.status = FlipperI32HexFileStatusErrorFileRead;
|
||||
} else {
|
||||
stream_read_line(instance->stream, instance->str_data);
|
||||
ret = flipper_i32hex_file_parse(
|
||||
instance, furi_string_get_cstr(instance->str_data), data, data_size);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <furi_hal.h>
|
||||
|
||||
typedef struct FlipperI32HexFile FlipperI32HexFile;
|
||||
|
||||
typedef enum {
|
||||
FlipperI32HexFileStatusOK = 0,
|
||||
FlipperI32HexFileStatusData = 2,
|
||||
FlipperI32HexFileStatusUdateAddr = 3,
|
||||
FlipperI32HexFileStatusEofFile = 4,
|
||||
FlipperI32HexFileStatusOpenFileWrite = 5,
|
||||
FlipperI32HexFileStatusOpenFileRead = 6,
|
||||
|
||||
// Errors
|
||||
FlipperI32HexFileStatusErrorCrc = (-1),
|
||||
FlipperI32HexFileStatusErrorOverflow = (-2),
|
||||
FlipperI32HexFileStatusErrorData = (-3),
|
||||
FlipperI32HexFileStatusErrorUnsupportedCommand = (-4),
|
||||
FlipperI32HexFileStatusErrorNoOpenFile = (-5),
|
||||
FlipperI32HexFileStatusErrorFileWrite = (-6),
|
||||
FlipperI32HexFileStatusErrorFileRead = (-7),
|
||||
|
||||
FlipperI32HexFileStatusReserved =
|
||||
0x7FFFFFFF, ///< Prevents enum down-size compiler optimization.
|
||||
} FlipperI32HexFileStatus;
|
||||
|
||||
typedef struct {
|
||||
FlipperI32HexFileStatus status;
|
||||
uint32_t data_size;
|
||||
} FlipperI32HexFileRet;
|
||||
|
||||
FlipperI32HexFile* flipper_i32hex_file_open_write(const char* name, uint32_t start_addr);
|
||||
|
||||
FlipperI32HexFile* flipper_i32hex_file_open_read(const char* name);
|
||||
|
||||
void flipper_i32hex_file_close(FlipperI32HexFile* instance);
|
||||
|
||||
FlipperI32HexFileRet flipper_i32hex_file_bin_to_i32hex_set_data(
|
||||
FlipperI32HexFile* instance,
|
||||
uint8_t* data,
|
||||
uint32_t data_size);
|
||||
|
||||
FlipperI32HexFileRet flipper_i32hex_file_bin_to_i32hex_set_end_line(FlipperI32HexFile* instance);
|
||||
|
||||
const char* flipper_i32hex_file_get_string(FlipperI32HexFile* instance);
|
||||
|
||||
void flipper_i32hex_file_bin_to_i32hex_set_addr(FlipperI32HexFile* instance, uint32_t addr);
|
||||
|
||||
bool flipper_i32hex_file_check(FlipperI32HexFile* instance);
|
||||
|
||||
FlipperI32HexFileRet flipper_i32hex_file_i32hex_to_bin_get_data(
|
||||
FlipperI32HexFile* instance,
|
||||
uint8_t* data,
|
||||
uint32_t data_size);
|
||||
|
Before Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 3.8 KiB |
@@ -1,386 +0,0 @@
|
||||
#include "avr_isp_chip_arr.h"
|
||||
|
||||
#include <furi.h>
|
||||
|
||||
//https://github.com/avrdudes/avrdude/blob/master/src/avrintel.c
|
||||
|
||||
const AvrIspChipArr avr_isp_chip_arr[] = { // Value of -1 typically means unknown
|
||||
//{mcu_name, mcuid, family, {sig, na, ture}, flstart, flsize, pgsiz, nb, bootsz, eestart, eesize, ep, rambeg, ramsiz, nf, nl, ni}, // Source
|
||||
{"ATtiny4", 0, F_AVR8L, {0x1E, 0x8F, 0x0A}, 0, 0x00200, 0x010, 0, 0, 0, 0, 0, 0x0040, 0x0020, 1, 1, 10}, // atdf, avr-gcc 12.2.0, avrdude, boot size (manual)
|
||||
{"ATtiny5", 1, F_AVR8L, {0x1E, 0x8F, 0x09}, 0, 0x00200, 0x010, 0, 0, 0, 0, 0, 0x0040, 0x0020, 1, 1, 11}, // atdf, avr-gcc 12.2.0, avrdude, boot size (manual)
|
||||
{"ATtiny9", 2, F_AVR8L, {0x1E, 0x90, 0x08}, 0, 0x00400, 0x010, 0, 0, 0, 0, 0, 0x0040, 0x0020, 1, 1, 10}, // atdf, avr-gcc 12.2.0, avrdude, boot size (manual)
|
||||
{"ATtiny10", 3, F_AVR8L, {0x1E, 0x90, 0x03}, 0, 0x00400, 0x010, 0, 0, 0, 0, 0, 0x0040, 0x0020, 1, 1, 11}, // atdf, avr-gcc 12.2.0, avrdude, boot size (manual)
|
||||
{"ATtiny20", 4, F_AVR8L, {0x1E, 0x91, 0x0F}, 0, 0x00800, 0x020, 0, 0, 0, 0, 0, 0x0040, 0x0080, 1, 1, 17}, // atdf, avr-gcc 12.2.0, avrdude, boot size (manual)
|
||||
{"ATtiny40", 5, F_AVR8L, {0x1E, 0x92, 0x0E}, 0, 0x01000, 0x040, 0, 0, 0, 0, 0, 0x0040, 0x0100, 1, 1, 18}, // atdf, avr-gcc 12.2.0, avrdude, boot size (manual)
|
||||
{"ATtiny102", 6, F_AVR8L, {0x1E, 0x90, 0x0C}, 0, 0x00400, 0x010, 0, 0, 0, 0, 0, 0x0040, 0x0020, 1, 1, 16}, // atdf, avrdude, boot size (manual)
|
||||
{"ATtiny104", 7, F_AVR8L, {0x1E, 0x90, 0x0B}, 0, 0x00400, 0x010, 0, 0, 0, 0, 0, 0x0040, 0x0020, 1, 1, 16}, // atdf, avrdude, boot size (manual)
|
||||
|
||||
{"ATtiny11", 8, F_AVR8, {0x1E, 0x90, 0x04}, 0, 0x00400, 0x001, 0, 0, 0, 0x0040, 1, 0x0060, 0x0020, 1, 1, 5}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny12", 9, F_AVR8, {0x1E, 0x90, 0x05}, 0, 0x00400, 0x001, 0, 0, 0, 0x0040, 2, 0x0060, 0x0020, 1, 1, 6}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny13", 10, F_AVR8, {0x1E, 0x90, 0x07}, 0, 0x00400, 0x020, 0, 0, 0, 0x0040, 4, 0x0060, 0x0040, 2, 1, 10}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny13A", 11, F_AVR8, {0x1E, 0x90, 0x07}, 0, 0x00400, 0x020, 0, 0, 0, 0x0040, 4, 0x0060, 0x0040, 2, 1, 10}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny15", 12, F_AVR8, {0x1E, 0x90, 0x06}, 0, 0x00400, 0x001, 0, 0, 0, 0x0040, 2, 0x0060, 0x0020, 1, 1, 9}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny22", 13, F_AVR8, {0x1E, 0x91, 0x06}, 0, 0x00800, -1, 0, 0, -1, -1, -1, 0x0060, 0x0080, 1, 1, 3}, // avr-gcc 12.2.0, boot size (manual)
|
||||
{"ATtiny24", 14, F_AVR8, {0x1E, 0x91, 0x0B}, 0, 0x00800, 0x020, 0, 0, 0, 0x0080, 4, 0x0060, 0x0080, 3, 1, 17}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny24A", 15, F_AVR8, {0x1E, 0x91, 0x0B}, 0, 0x00800, 0x020, 0, 0, 0, 0x0080, 4, 0x0060, 0x0080, 3, 1, 17}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny25", 16, F_AVR8, {0x1E, 0x91, 0x08}, 0, 0x00800, 0x020, 0, 0, 0, 0x0080, 4, 0x0060, 0x0080, 3, 1, 15}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny26", 17, F_AVR8, {0x1E, 0x91, 0x09}, 0, 0x00800, 0x020, 0, 0, 0, 0x0080, 4, 0x0060, 0x0080, 2, 1, 12}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny28", 18, F_AVR8, {0x1E, 0x91, 0x07}, 0, 0x00800, 0x002, 0, 0, 0, 0, 0, 0x0060, 0x0020, 1, 1, 6}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny43U", 19, F_AVR8, {0x1E, 0x92, 0x0C}, 0, 0x01000, 0x040, 0, 0, 0, 0x0040, 4, 0x0060, 0x0100, 3, 1, 16}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny44", 20, F_AVR8, {0x1E, 0x92, 0x07}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0060, 0x0100, 3, 1, 17}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny44A", 21, F_AVR8, {0x1E, 0x92, 0x07}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0060, 0x0100, 3, 1, 17}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny45", 22, F_AVR8, {0x1E, 0x92, 0x06}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0060, 0x0100, 3, 1, 15}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny48", 23, F_AVR8, {0x1E, 0x92, 0x09}, 0, 0x01000, 0x040, 0, 0, 0, 0x0040, 4, 0x0100, 0x0100, 3, 1, 20}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny84", 24, F_AVR8, {0x1E, 0x93, 0x0C}, 0, 0x02000, 0x040, 0, 0, 0, 0x0200, 4, 0x0060, 0x0200, 3, 1, 17}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny84A", 25, F_AVR8, {0x1E, 0x93, 0x0C}, 0, 0x02000, 0x040, 0, 0, 0, 0x0200, 4, 0x0060, 0x0200, 3, 1, 17}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny85", 26, F_AVR8, {0x1E, 0x93, 0x0B}, 0, 0x02000, 0x040, 0, 0, 0, 0x0200, 4, 0x0060, 0x0200, 3, 1, 15}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny87", 27, F_AVR8, {0x1E, 0x93, 0x87}, 0, 0x02000, 0x080, 0, 0, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 20}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny88", 28, F_AVR8, {0x1E, 0x93, 0x11}, 0, 0x02000, 0x040, 0, 0, 0, 0x0040, 4, 0x0100, 0x0200, 3, 1, 20}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny167", 29, F_AVR8, {0x1E, 0x94, 0x87}, 0, 0x04000, 0x080, 0, 0, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 20}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny261", 30, F_AVR8, {0x1E, 0x91, 0x0C}, 0, 0x00800, 0x020, 0, 0, 0, 0x0080, 4, 0x0060, 0x0080, 3, 1, 19}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny261A", 31, F_AVR8, {0x1E, 0x91, 0x0C}, 0, 0x00800, 0x020, 0, 0, 0, 0x0080, 4, 0x0060, 0x0080, 3, 1, 19}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny441", 32, F_AVR8, {0x1E, 0x92, 0x15}, 0, 0x01000, 0x010, 0, 0, 0, 0x0100, 4, 0x0100, 0x0100, 3, 1, 30}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny461", 33, F_AVR8, {0x1E, 0x92, 0x08}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0060, 0x0100, 3, 1, 19}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny461A", 34, F_AVR8, {0x1E, 0x92, 0x08}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0060, 0x0100, 3, 1, 19}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny828", 35, F_AVR8, {0x1E, 0x93, 0x14}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0100, 4, 0x0100, 0x0200, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny828R", 36, F_AVR8, {0x1E, 0x93, 0x14}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0100, 4, 0x0100, 0x0200, 3, 1, 26}, // avrdude, from ATtiny828
|
||||
{"ATtiny841", 37, F_AVR8, {0x1E, 0x93, 0x15}, 0, 0x02000, 0x010, 0, 0, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 30}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny861", 38, F_AVR8, {0x1E, 0x93, 0x0D}, 0, 0x02000, 0x040, 0, 0, 0, 0x0200, 4, 0x0060, 0x0200, 3, 1, 19}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny861A", 39, F_AVR8, {0x1E, 0x93, 0x0D}, 0, 0x02000, 0x040, 0, 0, 0, 0x0200, 4, 0x0060, 0x0200, 3, 1, 19}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny1634", 40, F_AVR8, {0x1E, 0x94, 0x12}, 0, 0x04000, 0x020, 0, 0, 0, 0x0100, 4, 0x0100, 0x0400, 3, 1, 28}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny1634R", 41, F_AVR8, {0x1E, 0x94, 0x12}, 0, 0x04000, 0x020, 0, 0, 0, 0x0100, 4, 0x0100, 0x0400, 3, 1, 28}, // avrdude, from ATtiny1634
|
||||
{"ATtiny2313", 42, F_AVR8, {0x1E, 0x91, 0x0A}, 0, 0x00800, 0x020, 0, 0, 0, 0x0080, 4, 0x0060, 0x0080, 3, 1, 19}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny2313A", 43, F_AVR8, {0x1E, 0x91, 0x0A}, 0, 0x00800, 0x020, 0, 0, 0, 0x0080, 4, 0x0060, 0x0080, 3, 1, 21}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny4313", 44, F_AVR8, {0x1E, 0x92, 0x0D}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0060, 0x0100, 3, 1, 21}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega8", 45, F_AVR8, {0x1E, 0x93, 0x07}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0060, 0x0400, 2, 1, 19}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega8A", 46, F_AVR8, {0x1E, 0x93, 0x07}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0060, 0x0400, 2, 1, 19}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega8HVA", 47, F_AVR8, {0x1E, 0x93, 0x10}, 0, 0x02000, 0x080, 0, 0, 0, 0x0100, 4, 0x0100, 0x0200, 1, 1, 21}, // atdf, avr-gcc 12.2.0
|
||||
{"ATmega8U2", 48, F_AVR8, {0x1E, 0x93, 0x89}, 0, 0x02000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 29}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega16", 49, F_AVR8, {0x1E, 0x94, 0x03}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0060, 0x0400, 2, 1, 21}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega16A", 50, F_AVR8, {0x1E, 0x94, 0x03}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0060, 0x0400, 2, 1, 21}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega16HVA", 51, F_AVR8, {0x1E, 0x94, 0x0C}, 0, 0x04000, 0x080, 0, 0, 0, 0x0100, 4, 0x0100, 0x0200, 1, 1, 21}, // atdf, avr-gcc 12.2.0
|
||||
{"ATmega16HVB", 52, F_AVR8, {0x1E, 0x94, 0x0D}, 0, 0x04000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0400, 2, 1, 29}, // atdf, avr-gcc 12.2.0
|
||||
{"ATmega16HVBrevB", 53, F_AVR8, {0x1E, 0x94, 0x0D}, 0, 0x04000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0400, 2, 1, 29}, // atdf, avr-gcc 12.2.0
|
||||
{"ATmega16M1", 54, F_AVR8, {0x1E, 0x94, 0x84}, 0, 0x04000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 31}, // atdf, avr-gcc 12.2.0
|
||||
{"ATmega16HVA2", 55, F_AVR8, {0x1E, 0x94, 0x0E}, 0, 0x04000, 0x080, -1, -1, -1, -1, -1, 0x0100, 0x0400, 2, 1, 22}, // avr-gcc 12.2.0
|
||||
{"ATmega16U2", 56, F_AVR8, {0x1E, 0x94, 0x89}, 0, 0x04000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 29}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega16U4", 57, F_AVR8, {0x1E, 0x94, 0x88}, 0, 0x04000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0500, 3, 1, 43}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega32", 58, F_AVR8, {0x1E, 0x95, 0x02}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0060, 0x0800, 2, 1, 21}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega32A", 59, F_AVR8, {0x1E, 0x95, 0x02}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0060, 0x0800, 2, 1, 21}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega32HVB", 60, F_AVR8, {0x1E, 0x95, 0x10}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 2, 1, 29}, // atdf, avr-gcc 12.2.0
|
||||
{"ATmega32HVBrevB", 61, F_AVR8, {0x1E, 0x95, 0x10}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 2, 1, 29}, // atdf, avr-gcc 12.2.0
|
||||
{"ATmega32C1", 62, F_AVR8, {0x1E, 0x95, 0x86}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 31}, // atdf, avr-gcc 12.2.0
|
||||
{"ATmega32M1", 63, F_AVR8, {0x1E, 0x95, 0x84}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega32U2", 64, F_AVR8, {0x1E, 0x95, 0x8A}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0400, 3, 1, 29}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega32U4", 65, F_AVR8, {0x1E, 0x95, 0x87}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0a00, 3, 1, 43}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega32U6", 66, F_AVR8, {0x1E, 0x95, 0x88}, 0, 0x08000, 0x080, 4, 0x0200, -1, -1, -1, 0x0100, 0x0a00, 3, 1, 38}, // avr-gcc 12.2.0, boot size (manual)
|
||||
{"ATmega48", 67, F_AVR8, {0x1E, 0x92, 0x05}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0100, 0x0200, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega48A", 68, F_AVR8, {0x1E, 0x92, 0x05}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0100, 0x0200, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega48P", 69, F_AVR8, {0x1E, 0x92, 0x0A}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0100, 0x0200, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega48PA", 70, F_AVR8, {0x1E, 0x92, 0x0A}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0100, 0x0200, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega48PB", 71, F_AVR8, {0x1E, 0x92, 0x10}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0100, 0x0200, 3, 1, 27}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega64", 72, F_AVR8, {0x1E, 0x96, 0x02}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 35}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega64A", 73, F_AVR8, {0x1E, 0x96, 0x02}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 35}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega64HVE", 74, F_AVR8, {0x1E, 0x96, 0x10}, 0, 0x10000, 0x080, 4, 0x0400, -1, -1, -1, 0x0100, 0x1000, 2, 1, 25}, // avr-gcc 12.2.0, boot size (manual)
|
||||
{"ATmega64C1", 75, F_AVR8, {0x1E, 0x96, 0x86}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 31}, // atdf, avr-gcc 12.2.0
|
||||
{"ATmega64M1", 76, F_AVR8, {0x1E, 0x96, 0x84}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega64HVE2", 77, F_AVR8, {0x1E, 0x96, 0x10}, 0, 0x10000, 0x080, 4, 0x0400, 0, 0x0400, 4, 0x0100, 0x1000, 2, 1, 25}, // atdf, avr-gcc 12.2.0
|
||||
{"ATmega64RFR2", 78, F_AVR8, {0x1E, 0xA6, 0x02}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0200, 0x2000, 3, 1, 77}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega88", 79, F_AVR8, {0x1E, 0x93, 0x0A}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega88A", 80, F_AVR8, {0x1E, 0x93, 0x0A}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega88P", 81, F_AVR8, {0x1E, 0x93, 0x0F}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega88PA", 82, F_AVR8, {0x1E, 0x93, 0x0F}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega88PB", 83, F_AVR8, {0x1E, 0x93, 0x16}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 27}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega103", 84, F_AVR8, {0x1E, 0x97, 0x01}, 0, 0x20000, 0x100, 0, 0, 0, 0x1000, 1, 0x0060, 0x0fa0, 1, 1, 24}, // avr-gcc 12.2.0, avrdude, boot size (manual)
|
||||
{"ATmega128", 85, F_AVR8, {0x1E, 0x97, 0x02}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0100, 0x1000, 3, 1, 35}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega128A", 86, F_AVR8, {0x1E, 0x97, 0x02}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0100, 0x1000, 3, 1, 35}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega128RFA1", 87, F_AVR8, {0x1E, 0xA7, 0x01}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0200, 0x4000, 3, 1, 72}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega128RFR2", 88, F_AVR8, {0x1E, 0xA7, 0x02}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0200, 0x4000, 3, 1, 77}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega161", 89, F_AVR8, {0x1E, 0x94, 0x01}, 0, 0x04000, 0x080, 1, 0x0400, 0, 0x0200, 1, 0x0060, 0x0400, 1, 1, 21}, // avr-gcc 12.2.0, avrdude, boot size (manual)
|
||||
{"ATmega162", 90, F_AVR8, {0x1E, 0x94, 0x04}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 28}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega163", 91, F_AVR8, {0x1E, 0x94, 0x02}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 1, 0x0060, 0x0400, 2, 1, 18}, // avr-gcc 12.2.0, avrdude, boot size (manual)
|
||||
{"ATmega164A", 92, F_AVR8, {0x1E, 0x94, 0x0F}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega164P", 93, F_AVR8, {0x1E, 0x94, 0x0A}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega164PA", 94, F_AVR8, {0x1E, 0x94, 0x0A}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega165", 95, F_AVR8, {0x1E, 0x94, 0x10}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 22}, // avr-gcc 12.2.0, avrdude, boot size (manual)
|
||||
{"ATmega165A", 96, F_AVR8, {0x1E, 0x94, 0x10}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 22}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega165P", 97, F_AVR8, {0x1E, 0x94, 0x07}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 22}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega165PA", 98, F_AVR8, {0x1E, 0x94, 0x07}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 22}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega168", 99, F_AVR8, {0x1E, 0x94, 0x06}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega168A", 100, F_AVR8, {0x1E, 0x94, 0x06}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega168P", 101, F_AVR8, {0x1E, 0x94, 0x0B}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega168PA", 102, F_AVR8, {0x1E, 0x94, 0x0B}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega168PB", 103, F_AVR8, {0x1E, 0x94, 0x15}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 27}, // atdf, avr-gcc 7.3.0, avrdude
|
||||
{"ATmega169", 104, F_AVR8, {0x1E, 0x94, 0x05}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 23}, // avr-gcc 12.2.0, avrdude, boot size (manual)
|
||||
{"ATmega169A", 105, F_AVR8, {0x1E, 0x94, 0x11}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega169P", 106, F_AVR8, {0x1E, 0x94, 0x05}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega169PA", 107, F_AVR8, {0x1E, 0x94, 0x05}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega256RFR2", 108, F_AVR8, {0x1E, 0xA8, 0x02}, 0, 0x40000, 0x100, 4, 0x0400, 0, 0x2000, 8, 0x0200, 0x8000, 3, 1, 77}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega323", 109, F_AVR8, {0x1E, 0x95, 0x01}, 0, 0x08000, 0x080, 4, 0x0200, -1, -1, -1, 0x0060, 0x0800, 2, 1, 21}, // avr-gcc 12.2.0, boot size (manual)
|
||||
{"ATmega324A", 110, F_AVR8, {0x1E, 0x95, 0x15}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega324P", 111, F_AVR8, {0x1E, 0x95, 0x08}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega324PA", 112, F_AVR8, {0x1E, 0x95, 0x11}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega324PB", 113, F_AVR8, {0x1E, 0x95, 0x17}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 51}, // atdf, avrdude
|
||||
{"ATmega325", 114, F_AVR8, {0x1E, 0x95, 0x05}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 22}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega325A", 115, F_AVR8, {0x1E, 0x95, 0x05}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 22}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega325P", 116, F_AVR8, {0x1E, 0x95, 0x0D}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 22}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega325PA", 117, F_AVR8, {0x1E, 0x95, 0x0D}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 22}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega328", 118, F_AVR8, {0x1E, 0x95, 0x14}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega328P", 119, F_AVR8, {0x1E, 0x95, 0x0F}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega328PB", 120, F_AVR8, {0x1E, 0x95, 0x16}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 45}, // atdf, avr-gcc 7.3.0, avrdude
|
||||
{"ATmega329", 121, F_AVR8, {0x1E, 0x95, 0x03}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega329A", 122, F_AVR8, {0x1E, 0x95, 0x03}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega329P", 123, F_AVR8, {0x1E, 0x95, 0x0B}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega329PA", 124, F_AVR8, {0x1E, 0x95, 0x0B}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega406", 125, F_AVR8, {0x1E, 0x95, 0x07}, 0, 0x0a000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0800, 2, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega640", 126, F_AVR8, {0x1E, 0x96, 0x08}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0200, 0x2000, 3, 1, 57}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega644", 127, F_AVR8, {0x1E, 0x96, 0x09}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 28}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega644A", 128, F_AVR8, {0x1E, 0x96, 0x09}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega644P", 129, F_AVR8, {0x1E, 0x96, 0x0A}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega644PA", 130, F_AVR8, {0x1E, 0x96, 0x0A}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega644RFR2", 131, F_AVR8, {0x1E, 0xA6, 0x03}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0200, 0x2000, 3, 1, 77}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega645", 132, F_AVR8, {0x1E, 0x96, 0x05}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 22}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega645A", 133, F_AVR8, {0x1E, 0x96, 0x05}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 22}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega645P", 134, F_AVR8, {0x1E, 0x96, 0x0D}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 22}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega649", 135, F_AVR8, {0x1E, 0x96, 0x03}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega649A", 136, F_AVR8, {0x1E, 0x96, 0x03}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega649P", 137, F_AVR8, {0x1E, 0x96, 0x0B}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega1280", 138, F_AVR8, {0x1E, 0x97, 0x03}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0200, 0x2000, 3, 1, 57}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega1281", 139, F_AVR8, {0x1E, 0x97, 0x04}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0200, 0x2000, 3, 1, 57}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega1284", 140, F_AVR8, {0x1E, 0x97, 0x06}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0100, 0x4000, 3, 1, 35}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega1284P", 141, F_AVR8, {0x1E, 0x97, 0x05}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0100, 0x4000, 3, 1, 35}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega1284RFR2", 142, F_AVR8, {0x1E, 0xA7, 0x03}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0200, 0x4000, 3, 1, 77}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega2560", 143, F_AVR8, {0x1E, 0x98, 0x01}, 0, 0x40000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0200, 0x2000, 3, 1, 57}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega2561", 144, F_AVR8, {0x1E, 0x98, 0x02}, 0, 0x40000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0200, 0x2000, 3, 1, 57}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega2564RFR2", 145, F_AVR8, {0x1E, 0xA8, 0x03}, 0, 0x40000, 0x100, 4, 0x0400, 0, 0x2000, 8, 0x0200, 0x8000, 3, 1, 77}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega3250", 146, F_AVR8, {0x1E, 0x95, 0x06}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega3250A", 147, F_AVR8, {0x1E, 0x95, 0x06}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega3250P", 148, F_AVR8, {0x1E, 0x95, 0x0E}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega3250PA", 149, F_AVR8, {0x1E, 0x95, 0x0E}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega3290", 150, F_AVR8, {0x1E, 0x95, 0x04}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega3290A", 151, F_AVR8, {0x1E, 0x95, 0x04}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega3290P", 152, F_AVR8, {0x1E, 0x95, 0x0C}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega3290PA", 153, F_AVR8, {0x1E, 0x95, 0x0C}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega6450", 154, F_AVR8, {0x1E, 0x96, 0x06}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega6450A", 155, F_AVR8, {0x1E, 0x96, 0x06}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega6450P", 156, F_AVR8, {0x1E, 0x96, 0x0E}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega6490", 157, F_AVR8, {0x1E, 0x96, 0x04}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega6490A", 158, F_AVR8, {0x1E, 0x96, 0x04}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega6490P", 159, F_AVR8, {0x1E, 0x96, 0x0C}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega8515", 160, F_AVR8, {0x1E, 0x93, 0x06}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0060, 0x0200, 2, 1, 17}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega8535", 161, F_AVR8, {0x1E, 0x93, 0x08}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0060, 0x0200, 2, 1, 21}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"AT43USB320", 162, F_AVR8, {0xff, -1, -1}, 0, 0x10000, -1, -1, -1, -1, -1, -1, 0x0060, 0x0200, -1, -1, 0}, // avr-gcc 12.2.0
|
||||
{"AT43USB355", 163, F_AVR8, {0xff, -1, -1}, 0, 0x06000, -1, -1, -1, -1, -1, -1, 0x0060, 0x0400, -1, -1, 0}, // avr-gcc 12.2.0
|
||||
{"AT76C711", 164, F_AVR8, {0xff, -1, -1}, 0, 0x04000, -1, -1, -1, -1, -1, -1, 0x0060, 0x07a0, -1, -1, 0}, // avr-gcc 12.2.0
|
||||
{"AT86RF401", 165, F_AVR8, {0x1E, 0x91, 0x81}, 0, 0x00800, -1, -1, -1, -1, -1, -1, 0x0060, 0x0080, 0, 1, 3}, // avr-gcc 12.2.0
|
||||
{"AT90PWM1", 166, F_AVR8, {0x1E, 0x93, 0x83}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 32}, // atdf, avr-gcc 12.2.0
|
||||
{"AT90PWM2", 167, F_AVR8, {0x1E, 0x93, 0x81}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 32}, // avr-gcc 12.2.0, avrdude, boot size (manual)
|
||||
{"AT90PWM2B", 168, F_AVR8, {0x1E, 0x93, 0x83}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 32}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"AT90PWM3", 169, F_AVR8, {0x1E, 0x93, 0x81}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 32}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"AT90PWM3B", 170, F_AVR8, {0x1E, 0x93, 0x83}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 32}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"AT90CAN32", 171, F_AVR8, {0x1E, 0x95, 0x81}, 0, 0x08000, 0x100, 4, 0x0400, 0, 0x0400, 8, 0x0100, 0x0800, 3, 1, 37}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"AT90CAN64", 172, F_AVR8, {0x1E, 0x96, 0x81}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 37}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"AT90PWM81", 173, F_AVR8, {0x1E, 0x93, 0x88}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0100, 3, 1, 20}, // atdf, avr-gcc 12.2.0
|
||||
{"AT90USB82", 174, F_AVR8, {0x1E, 0x93, 0x82}, 0, 0x02000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 29}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"AT90SCR100", 175, F_AVR8, {0x1E, 0x96, 0xC1}, 0, 0x10000, 0x100, 4, 0x0200, -1, -1, -1, 0x0100, 0x1000, 3, 1, 38}, // avr-gcc 12.2.0, boot size (manual)
|
||||
{"AT90CAN128", 176, F_AVR8, {0x1E, 0x97, 0x81}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0100, 0x1000, 3, 1, 37}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"AT90PWM161", 177, F_AVR8, {0x1E, 0x94, 0x8B}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 20}, // atdf, avr-gcc 12.2.0
|
||||
{"AT90USB162", 178, F_AVR8, {0x1E, 0x94, 0x82}, 0, 0x04000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 29}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"AT90PWM216", 179, F_AVR8, {0x1E, 0x94, 0x83}, 0, 0x04000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 32}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"AT90PWM316", 180, F_AVR8, {0x1E, 0x94, 0x83}, 0, 0x04000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 32}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"AT90USB646", 181, F_AVR8, {0x1E, 0x96, 0x82}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 38}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"AT90USB647", 182, F_AVR8, {0x1E, 0x96, 0x82}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 38}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"AT90S1200", 183, F_AVR8, {0x1E, 0x90, 0x01}, 0, 0x00400, 0x001, 0, 0, 0, 0x0040, 1, 0x0060, 0x0020, 1, 1, 4}, // avr-gcc 12.2.0, avrdude, boot size (manual)
|
||||
{"AT90USB1286", 184, F_AVR8, {0x1E, 0x97, 0x82}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0100, 0x2000, 3, 1, 38}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"AT90USB1287", 185, F_AVR8, {0x1E, 0x97, 0x82}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0100, 0x2000, 3, 1, 38}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"AT90S2313", 186, F_AVR8, {0x1E, 0x91, 0x01}, 0, 0x00800, 0x001, 0, 0, 0, 0x0080, 1, 0x0060, 0x0080, 1, 1, 11}, // avr-gcc 12.2.0, avrdude, boot size (manual)
|
||||
{"AT90S2323", 187, F_AVR8, {0x1E, 0x91, 0x02}, 0, 0x00800, -1, 0, 0, -1, -1, -1, 0x0060, 0x0080, 1, 1, 3}, // avr-gcc 12.2.0, boot size (manual)
|
||||
{"AT90S2333", 188, F_AVR8, {0x1E, 0x91, 0x05}, 0, 0x00800, 0x001, 0, 0, 0, 0x0080, 1, 0x0060, 0x0080, -1, -1, 14}, // avr-gcc 12.2.0, avrdude, boot size (manual)
|
||||
{"AT90S2343", 189, F_AVR8, {0x1E, 0x91, 0x03}, 0, 0x00800, 0x001, 0, 0, 0, 0x0080, 1, 0x0060, 0x0080, 1, 1, 3}, // avr-gcc 12.2.0, avrdude, boot size (manual)
|
||||
{"AT90S4414", 190, F_AVR8, {0x1E, 0x92, 0x01}, 0, 0x01000, 0x001, 0, 0, 0, 0x0100, 1, 0x0060, 0x0100, 1, 1, 13}, // avr-gcc 12.2.0, avrdude, boot size (manual)
|
||||
{"AT90S4433", 191, F_AVR8, {0x1E, 0x92, 0x03}, 0, 0x01000, 0x001, 0, 0, 0, 0x0100, 1, 0x0060, 0x0080, 1, 1, 14}, // avr-gcc 12.2.0, avrdude, boot size (manual)
|
||||
{"AT90S4434", 192, F_AVR8, {0x1E, 0x92, 0x02}, 0, 0x01000, 0x001, 0, 0, 0, 0x0100, 1, 0x0060, 0x0100, 1, 1, 17}, // avr-gcc 12.2.0, avrdude, boot size (manual)
|
||||
{"AT90S8515", 193, F_AVR8, {0x1E, 0x93, 0x01}, 0, 0x02000, 0x001, 0, 0, 0, 0x0200, 1, 0x0060, 0x0200, 1, 1, 13}, // avr-gcc 12.2.0, avrdude, boot size (manual)
|
||||
{"AT90C8534", 194, F_AVR8, {0xff, -1, -1}, 0, 0x02000, -1, -1, -1, -1, -1, -1, 0x0060, 0x0100, -1, -1, 0}, // avr-gcc 12.2.0
|
||||
{"AT90S8535", 195, F_AVR8, {0x1E, 0x93, 0x03}, 0, 0x02000, 0x001, 0, 0, 0, 0x0200, 1, 0x0060, 0x0200, 1, 1, 17}, // avr-gcc 12.2.0, avrdude, boot size (manual)
|
||||
{"AT94K", 196, F_AVR8, {0xff, -1, -1}, 0, 0x08000, -1, -1, -1, -1, -1, -1, 0x0060, 0x0fa0, -1, -1, 0}, // avr-gcc 12.2.0
|
||||
{"ATA5272", 197, F_AVR8, {0x1E, 0x93, 0x87}, 0, 0x02000, 0x080, 0, 0, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 37}, // atdf, avr-gcc 12.2.0
|
||||
{"ATA5505", 198, F_AVR8, {0x1E, 0x94, 0x87}, 0, 0x04000, 0x080, 0, 0, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 20}, // atdf, avr-gcc 12.2.0
|
||||
{"ATA5700M322", 199, F_AVR8, {0x1E, 0x95, 0x67}, 0x08000, 0x08000, 0x040, 0, 0, 0, 0x0880, 16, 0x0200, 0x0400, 1, 1, 51}, // atdf
|
||||
{"ATA5702M322", 200, F_AVR8, {0x1E, 0x95, 0x69}, 0x08000, 0x08000, 0x040, 0, 0, 0, 0x0880, 16, 0x0200, 0x0400, 1, 1, 51}, // atdf, avr-gcc 12.2.0
|
||||
{"ATA5781", 201, F_AVR8, {0x1E, 0x95, 0x64}, -1, -1, -1, 0, 0, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf
|
||||
{"ATA5782", 202, F_AVR8, {0x1E, 0x95, 0x65}, 0x08000, 0x05000, 0x040, 1, 0x5000, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf, avr-gcc 12.2.0
|
||||
{"ATA5783", 203, F_AVR8, {0x1E, 0x95, 0x66}, -1, -1, -1, 0, 0, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf
|
||||
{"ATA5787", 204, F_AVR8, {0x1E, 0x94, 0x6C}, 0x08000, 0x05200, 0x040, 0, 0, 0, 0x0400, 16, 0x0200, 0x0800, 1, 1, 44}, // atdf
|
||||
{"ATA5790", 205, F_AVR8, {0x1E, 0x94, 0x61}, 0, 0x04000, 0x080, 1, 0x0800, 0, 0x0800, 16, 0x0100, 0x0200, 1, 1, 30}, // atdf, avr-gcc 12.2.0
|
||||
{"ATA5790N", 206, F_AVR8, {0x1E, 0x94, 0x62}, 0, 0x04000, 0x080, 1, 0x0800, 0, 0x0800, 16, 0x0100, 0x0200, 1, 1, 31}, // atdf, avr-gcc 12.2.0
|
||||
{"ATA5791", 207, F_AVR8, {0x1E, 0x94, 0x62}, 0, 0x04000, 0x080, 1, 0x0800, 0, 0x0800, 16, 0x0100, 0x0200, 1, 1, 31}, // atdf, avr-gcc 7.3.0
|
||||
{"ATA5795", 208, F_AVR8, {0x1E, 0x93, 0x61}, 0, 0x02000, 0x040, 1, 0x0800, 0, 0x0800, 16, 0x0100, 0x0200, 1, 1, 23}, // atdf, avr-gcc 12.2.0
|
||||
{"ATA5831", 209, F_AVR8, {0x1E, 0x95, 0x61}, 0x08000, 0x05000, 0x040, 1, 0x5000, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf, avr-gcc 12.2.0
|
||||
{"ATA5832", 210, F_AVR8, {0x1E, 0x95, 0x62}, -1, -1, -1, 0, 0, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf
|
||||
{"ATA5833", 211, F_AVR8, {0x1E, 0x95, 0x63}, -1, -1, -1, 0, 0, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf
|
||||
{"ATA5835", 212, F_AVR8, {0x1E, 0x94, 0x6B}, 0x08000, 0x05200, 0x040, 0, 0, 0, 0x0400, 16, 0x0200, 0x0800, 1, 1, 44}, // atdf
|
||||
{"ATA6285", 213, F_AVR8, {0x1E, 0x93, 0x82}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0140, 4, 0x0100, 0x0200, 2, 1, 27}, // atdf, avr-gcc 12.2.0
|
||||
{"ATA6286", 214, F_AVR8, {0x1E, 0x93, 0x82}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0140, 4, 0x0100, 0x0200, 2, 1, 27}, // atdf, avr-gcc 12.2.0
|
||||
{"ATA6289", 215, F_AVR8, {0x1E, 0x93, 0x82}, 0, 0x02000, 0x040, 4, 0x0100, -1, -1, -1, 0x0100, 0x0200, 2, 1, 27}, // avr-gcc 12.2.0, boot size (manual)
|
||||
{"ATA6612C", 216, F_AVR8, {0x1E, 0x93, 0x0A}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // atdf, avr-gcc 12.2.0
|
||||
{"ATA6613C", 217, F_AVR8, {0x1E, 0x94, 0x06}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // atdf, avr-gcc 12.2.0
|
||||
{"ATA6614Q", 218, F_AVR8, {0x1E, 0x95, 0x0F}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 26}, // atdf, avr-gcc 12.2.0
|
||||
{"ATA6616C", 219, F_AVR8, {0x1E, 0x93, 0x87}, 0, 0x02000, 0x080, 0, 0, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 20}, // atdf, avr-gcc 12.2.0
|
||||
{"ATA6617C", 220, F_AVR8, {0x1E, 0x94, 0x87}, 0, 0x04000, 0x080, 0, 0, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 20}, // atdf, avr-gcc 12.2.0
|
||||
{"ATA8210", 221, F_AVR8, {0x1E, 0x95, 0x65}, 0x08000, 0x05000, 0x040, 1, 0x5000, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf, avr-gcc 7.3.0
|
||||
{"ATA8215", 222, F_AVR8, {0x1E, 0x95, 0x64}, -1, -1, -1, 0, 0, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf
|
||||
{"ATA8510", 223, F_AVR8, {0x1E, 0x95, 0x61}, 0x08000, 0x05000, 0x040, 1, 0x5000, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf, avr-gcc 7.3.0
|
||||
{"ATA8515", 224, F_AVR8, {0x1E, 0x95, 0x63}, -1, -1, -1, 0, 0, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf
|
||||
{"ATA664251", 225, F_AVR8, {0x1E, 0x94, 0x87}, 0, 0x04000, 0x080, 0, 0, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 20}, // atdf, avr-gcc 12.2.0
|
||||
{"M3000", 226, F_AVR8, {0xff, -1, -1}, 0, 0x10000, -1, -1, -1, -1, -1, -1, 0x1000, 0x1000, -1, -1, 0}, // avr-gcc 12.2.0
|
||||
{"LGT8F88P", 227, F_AVR8, {0x1E, 0x93, 0x0F}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // avrdude, from ATmega88
|
||||
{"LGT8F168P", 228, F_AVR8, {0x1E, 0x94, 0x0B}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // avrdude, from ATmega168P
|
||||
{"LGT8F328P", 229, F_AVR8, {0x1E, 0x95, 0x0F}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 26}, // avrdude, from ATmega328P
|
||||
|
||||
{"ATxmega8E5", 230, F_XMEGA, {0x1E, 0x93, 0x41}, 0, 0x02800, 0x080, 1, 0x0800, 0, 0x0200, 32, 0x2000, 0x0400, 7, 1, 43}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATxmega16A4", 231, F_XMEGA, {0x1E, 0x94, 0x41}, 0, 0x05000, 0x100, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x0800, 6, 1, 94}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATxmega16A4U", 232, F_XMEGA, {0x1E, 0x94, 0x41}, 0, 0x05000, 0x100, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x0800, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATxmega16C4", 233, F_XMEGA, {0x1E, 0x94, 0x43}, 0, 0x05000, 0x100, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x0800, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATxmega16D4", 234, F_XMEGA, {0x1E, 0x94, 0x42}, 0, 0x05000, 0x100, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x0800, 6, 1, 91}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATxmega16E5", 235, F_XMEGA, {0x1E, 0x94, 0x45}, 0, 0x05000, 0x080, 1, 0x1000, 0, 0x0200, 32, 0x2000, 0x0800, 7, 1, 43}, // atdf, avr-gcc 7.3.0, avrdude
|
||||
{"ATxmega32C3", 236, F_XMEGA, {0x1E, 0x95, 0x49}, 0, 0x09000, 0x100, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x1000, 6, 1, 127}, // atdf, avr-gcc 12.2.0
|
||||
{"ATxmega32D3", 237, F_XMEGA, {0x1E, 0x95, 0x4A}, 0, 0x09000, 0x100, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x1000, 6, 1, 114}, // atdf, avr-gcc 12.2.0
|
||||
{"ATxmega32A4", 238, F_XMEGA, {0x1E, 0x95, 0x41}, 0, 0x09000, 0x100, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x1000, 6, 1, 94}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATxmega32A4U", 239, F_XMEGA, {0x1E, 0x95, 0x41}, 0, 0x09000, 0x100, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x1000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATxmega32C4", 240, F_XMEGA, {0x1E, 0x95, 0x44}, 0, 0x09000, 0x100, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x1000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATxmega32D4", 241, F_XMEGA, {0x1E, 0x95, 0x42}, 0, 0x09000, 0x100, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x1000, 6, 1, 91}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATxmega32E5", 242, F_XMEGA, {0x1E, 0x95, 0x4C}, 0, 0x09000, 0x080, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x1000, 7, 1, 43}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATxmega64A1", 243, F_XMEGA, {0x1E, 0x96, 0x4E}, 0, 0x11000, 0x100, 1, 0x1000, 0, 0x0800, 32, 0x2000, 0x1000, 6, 1, 125}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATxmega64A1U", 244, F_XMEGA, {0x1E, 0x96, 0x4E}, 0, 0x11000, 0x100, 1, 0x1000, 0, 0x0800, 32, 0x2000, 0x1000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATxmega64B1", 245, F_XMEGA, {0x1E, 0x96, 0x52}, 0, 0x11000, 0x100, 1, 0x1000, 0, 0x0800, 32, 0x2000, 0x1000, 6, 1, 81}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATxmega64A3", 246, F_XMEGA, {0x1E, 0x96, 0x42}, 0, 0x11000, 0x100, 1, 0x1000, 0, 0x0800, 32, 0x2000, 0x1000, 6, 1, 122}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATxmega64A3U", 247, F_XMEGA, {0x1E, 0x96, 0x42}, 0, 0x11000, 0x100, 1, 0x1000, 0, 0x0800, 32, 0x2000, 0x1000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATxmega64B3", 248, F_XMEGA, {0x1E, 0x96, 0x51}, 0, 0x11000, 0x100, 1, 0x1000, 0, 0x0800, 32, 0x2000, 0x1000, 6, 1, 54}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATxmega64C3", 249, F_XMEGA, {0x1E, 0x96, 0x49}, 0, 0x11000, 0x100, 1, 0x1000, 0, 0x0800, 32, 0x2000, 0x1000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATxmega64D3", 250, F_XMEGA, {0x1E, 0x96, 0x4A}, 0, 0x11000, 0x100, 1, 0x1000, 0, 0x0800, 32, 0x2000, 0x1000, 6, 1, 114}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATxmega64A4", 251, F_XMEGA, {0x1E, 0x96, 0x46}, 0, 0x11000, 0x100, -1, -1, 0, 0x0800, 32, -1, -1, -1, -1, 0}, // avrdude
|
||||
{"ATxmega64A4U", 252, F_XMEGA, {0x1E, 0x96, 0x46}, 0, 0x11000, 0x100, 1, 0x1000, 0, 0x0800, 32, 0x2000, 0x1000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATxmega64D4", 253, F_XMEGA, {0x1E, 0x96, 0x47}, 0, 0x11000, 0x100, 1, 0x1000, 0, 0x0800, 32, 0x2000, 0x1000, 6, 1, 91}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATxmega128A1", 254, F_XMEGA, {0x1E, 0x97, 0x4C}, 0, 0x22000, 0x200, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x2000, 6, 1, 125}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATxmega128A1revD", 255, F_XMEGA, {0x1E, 0x97, 0x41}, 0, 0x22000, 0x200, -1, -1, 0, 0x0800, 32, -1, -1, -1, -1, 0}, // avrdude
|
||||
{"ATxmega128A1U", 256, F_XMEGA, {0x1E, 0x97, 0x4C}, 0, 0x22000, 0x200, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x2000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATxmega128B1", 257, F_XMEGA, {0x1E, 0x97, 0x4D}, 0, 0x22000, 0x100, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x2000, 6, 1, 81}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATxmega128A3", 258, F_XMEGA, {0x1E, 0x97, 0x42}, 0, 0x22000, 0x200, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x2000, 6, 1, 122}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATxmega128A3U", 259, F_XMEGA, {0x1E, 0x97, 0x42}, 0, 0x22000, 0x200, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x2000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATxmega128B3", 260, F_XMEGA, {0x1E, 0x97, 0x4B}, 0, 0x22000, 0x100, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x2000, 6, 1, 54}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATxmega128C3", 261, F_XMEGA, {0x1E, 0x97, 0x52}, 0, 0x22000, 0x200, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x2000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATxmega128D3", 262, F_XMEGA, {0x1E, 0x97, 0x48}, 0, 0x22000, 0x200, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x2000, 6, 1, 114}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATxmega128A4", 263, F_XMEGA, {0x1E, 0x97, 0x46}, 0, 0x22000, 0x200, -1, -1, 0, 0x0800, 32, -1, -1, -1, -1, 0}, // avrdude
|
||||
{"ATxmega128A4U", 264, F_XMEGA, {0x1E, 0x97, 0x46}, 0, 0x22000, 0x100, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x2000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATxmega128D4", 265, F_XMEGA, {0x1E, 0x97, 0x47}, 0, 0x22000, 0x100, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x2000, 6, 1, 91}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATxmega192A1", 266, F_XMEGA, {0x1E, 0x97, 0x4E}, 0, 0x32000, 0x200, -1, -1, 0, 0x0800, 32, -1, -1, -1, -1, 0}, // avrdude
|
||||
{"ATxmega192A3", 267, F_XMEGA, {0x1E, 0x97, 0x44}, 0, 0x32000, 0x200, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x4000, 6, 1, 122}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATxmega192A3U", 268, F_XMEGA, {0x1E, 0x97, 0x44}, 0, 0x32000, 0x200, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x4000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATxmega192C3", 269, F_XMEGA, {0x1E, 0x97, 0x51}, 0, 0x32000, 0x200, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x4000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATxmega192D3", 270, F_XMEGA, {0x1E, 0x97, 0x49}, 0, 0x32000, 0x200, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x4000, 6, 1, 114}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATxmega256A1", 271, F_XMEGA, {0x1E, 0x98, 0x46}, 0, 0x42000, 0x200, -1, -1, 0, 0x1000, 32, -1, -1, -1, -1, 0}, // avrdude
|
||||
{"ATxmega256A3", 272, F_XMEGA, {0x1E, 0x98, 0x42}, 0, 0x42000, 0x200, 1, 0x2000, 0, 0x1000, 32, 0x2000, 0x4000, 6, 1, 122}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATxmega256A3B", 273, F_XMEGA, {0x1E, 0x98, 0x43}, 0, 0x42000, 0x200, 1, 0x2000, 0, 0x1000, 32, 0x2000, 0x4000, 6, 1, 122}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATxmega256A3BU", 274, F_XMEGA, {0x1E, 0x98, 0x43}, 0, 0x42000, 0x200, 1, 0x2000, 0, 0x1000, 32, 0x2000, 0x4000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATxmega256A3U", 275, F_XMEGA, {0x1E, 0x98, 0x42}, 0, 0x42000, 0x200, 1, 0x2000, 0, 0x1000, 32, 0x2000, 0x4000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATxmega256C3", 276, F_XMEGA, {0x1E, 0x98, 0x46}, 0, 0x42000, 0x200, 1, 0x2000, 0, 0x1000, 32, 0x2000, 0x4000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATxmega256D3", 277, F_XMEGA, {0x1E, 0x98, 0x44}, 0, 0x42000, 0x200, 1, 0x2000, 0, 0x1000, 32, 0x2000, 0x4000, 6, 1, 114}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATxmega384C3", 278, F_XMEGA, {0x1E, 0x98, 0x45}, 0, 0x62000, 0x200, 1, 0x2000, 0, 0x1000, 32, 0x2000, 0x8000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATxmega384D3", 279, F_XMEGA, {0x1E, 0x98, 0x47}, 0, 0x62000, 0x200, 1, 0x2000, 0, 0x1000, 32, 0x2000, 0x8000, 6, 1, 114}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
|
||||
{"ATtiny202", 280, F_AVR8X, {0x1E, 0x91, 0x23}, 0, 0x00800, 0x040, 1, 0, 0x01400, 0x0040, 32, 0x3f80, 0x0080, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny204", 281, F_AVR8X, {0x1E, 0x91, 0x22}, 0, 0x00800, 0x040, 1, 0, 0x01400, 0x0040, 32, 0x3f80, 0x0080, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny212", 282, F_AVR8X, {0x1E, 0x91, 0x21}, 0, 0x00800, 0x040, 1, 0, 0x01400, 0x0040, 32, 0x3f80, 0x0080, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny214", 283, F_AVR8X, {0x1E, 0x91, 0x20}, 0, 0x00800, 0x040, 1, 0, 0x01400, 0x0040, 32, 0x3f80, 0x0080, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny402", 284, F_AVR8X, {0x1E, 0x92, 0x27}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3f00, 0x0100, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny404", 285, F_AVR8X, {0x1E, 0x92, 0x26}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3f00, 0x0100, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny406", 286, F_AVR8X, {0x1E, 0x92, 0x25}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3f00, 0x0100, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny412", 287, F_AVR8X, {0x1E, 0x92, 0x23}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3f00, 0x0100, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny414", 288, F_AVR8X, {0x1E, 0x92, 0x22}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3f00, 0x0100, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny416", 289, F_AVR8X, {0x1E, 0x92, 0x21}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3f00, 0x0100, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny416auto", 290, F_AVR8X, {0x1E, 0x92, 0x28}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3f00, 0x0100, 10, 1, 26}, // atdf
|
||||
{"ATtiny417", 291, F_AVR8X, {0x1E, 0x92, 0x20}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3f00, 0x0100, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny424", 292, F_AVR8X, {0x1E, 0x92, 0x2C}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3e00, 0x0200, 10, 1, 30}, // atdf, avrdude
|
||||
{"ATtiny426", 293, F_AVR8X, {0x1E, 0x92, 0x2B}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3e00, 0x0200, 10, 1, 30}, // atdf, avrdude
|
||||
{"ATtiny427", 294, F_AVR8X, {0x1E, 0x92, 0x2A}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3e00, 0x0200, 10, 1, 30}, // atdf, avrdude
|
||||
{"ATtiny804", 295, F_AVR8X, {0x1E, 0x93, 0x25}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3e00, 0x0200, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny806", 296, F_AVR8X, {0x1E, 0x93, 0x24}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3e00, 0x0200, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny807", 297, F_AVR8X, {0x1E, 0x93, 0x23}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3e00, 0x0200, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny814", 298, F_AVR8X, {0x1E, 0x93, 0x22}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3e00, 0x0200, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny816", 299, F_AVR8X, {0x1E, 0x93, 0x21}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3e00, 0x0200, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny817", 300, F_AVR8X, {0x1E, 0x93, 0x20}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3e00, 0x0200, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny824", 301, F_AVR8X, {0x1E, 0x93, 0x29}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3c00, 0x0400, 10, 1, 30}, // atdf, avrdude
|
||||
{"ATtiny826", 302, F_AVR8X, {0x1E, 0x93, 0x28}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3c00, 0x0400, 10, 1, 30}, // atdf, avrdude
|
||||
{"ATtiny827", 303, F_AVR8X, {0x1E, 0x93, 0x27}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3c00, 0x0400, 10, 1, 30}, // atdf, avrdude
|
||||
{"ATtiny1604", 304, F_AVR8X, {0x1E, 0x94, 0x25}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3c00, 0x0400, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny1606", 305, F_AVR8X, {0x1E, 0x94, 0x24}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3c00, 0x0400, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny1607", 306, F_AVR8X, {0x1E, 0x94, 0x23}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3c00, 0x0400, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny1614", 307, F_AVR8X, {0x1E, 0x94, 0x22}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3800, 0x0800, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny1616", 308, F_AVR8X, {0x1E, 0x94, 0x21}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3800, 0x0800, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny1617", 309, F_AVR8X, {0x1E, 0x94, 0x20}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3800, 0x0800, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny1624", 310, F_AVR8X, {0x1E, 0x94, 0x2A}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3800, 0x0800, 10, 1, 30}, // atdf, avrdude
|
||||
{"ATtiny1626", 311, F_AVR8X, {0x1E, 0x94, 0x29}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3800, 0x0800, 10, 1, 30}, // atdf, avrdude
|
||||
{"ATtiny1627", 312, F_AVR8X, {0x1E, 0x94, 0x28}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3800, 0x0800, 10, 1, 30}, // atdf, avrdude
|
||||
{"ATtiny3214", 313, F_AVR8X, {0x1E, 0x95, 0x20}, 0, 0x08000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x3800, 0x0800, 10, 1, 31}, // avr-gcc 12.2.0
|
||||
{"ATtiny3216", 314, F_AVR8X, {0x1E, 0x95, 0x21}, 0, 0x08000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x3800, 0x0800, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny3217", 315, F_AVR8X, {0x1E, 0x95, 0x22}, 0, 0x08000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x3800, 0x0800, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATtiny3224", 316, F_AVR8X, {0x1E, 0x95, 0x28}, 0, 0x08000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x3400, 0x0c00, 10, 1, 30}, // atdf, avrdude
|
||||
{"ATtiny3226", 317, F_AVR8X, {0x1E, 0x95, 0x27}, 0, 0x08000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x3400, 0x0c00, 10, 1, 30}, // atdf, avrdude
|
||||
{"ATtiny3227", 318, F_AVR8X, {0x1E, 0x95, 0x26}, 0, 0x08000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x3400, 0x0c00, 10, 1, 30}, // atdf, avrdude
|
||||
{"ATmega808", 319, F_AVR8X, {0x1E, 0x93, 0x26}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3c00, 0x0400, 10, 1, 36}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega809", 320, F_AVR8X, {0x1E, 0x93, 0x2A}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3c00, 0x0400, 10, 1, 40}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega1608", 321, F_AVR8X, {0x1E, 0x94, 0x27}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3800, 0x0800, 10, 1, 36}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega1609", 322, F_AVR8X, {0x1E, 0x94, 0x26}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3800, 0x0800, 10, 1, 40}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega3208", 323, F_AVR8X, {0x1E, 0x95, 0x30}, 0, 0x08000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x3000, 0x1000, 10, 1, 36}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega3209", 324, F_AVR8X, {0x1E, 0x95, 0x31}, 0, 0x08000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x3000, 0x1000, 10, 1, 40}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega4808", 325, F_AVR8X, {0x1E, 0x96, 0x50}, 0, 0x0c000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x2800, 0x1800, 10, 1, 36}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"ATmega4809", 326, F_AVR8X, {0x1E, 0x96, 0x51}, 0, 0x0c000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x2800, 0x1800, 10, 1, 40}, // atdf, avr-gcc 12.2.0, avrdude
|
||||
{"AVR8EA28", 327, F_AVR8X, {0x1E, 0x93, 0x2C}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0200, 8, -1, -1, -1, -1, 0}, // avrdude
|
||||
{"AVR8EA32", 328, F_AVR8X, {0x1E, 0x93, 0x2B}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0200, 8, -1, -1, -1, -1, 0}, // avrdude
|
||||
{"AVR16DD14", 329, F_AVR8X, {0x1E, 0x94, 0x34}, 0, 0x04000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x7800, 0x0800, 16, 4, 36}, // atdf, avrdude
|
||||
{"AVR16DD20", 330, F_AVR8X, {0x1E, 0x94, 0x33}, 0, 0x04000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x7800, 0x0800, 16, 4, 36}, // atdf, avrdude
|
||||
{"AVR16DD28", 331, F_AVR8X, {0x1E, 0x94, 0x32}, 0, 0x04000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x7800, 0x0800, 16, 4, 36}, // atdf, avrdude
|
||||
{"AVR16EA28", 332, F_AVR8X, {0x1E, 0x94, 0x37}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0200, 8, -1, -1, -1, -1, 0}, // avrdude
|
||||
{"AVR16DD32", 333, F_AVR8X, {0x1E, 0x94, 0x31}, 0, 0x04000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x7800, 0x0800, 16, 4, 36}, // atdf, avrdude
|
||||
{"AVR16EA32", 334, F_AVR8X, {0x1E, 0x94, 0x36}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0200, 8, -1, -1, -1, -1, 0}, // avrdude
|
||||
{"AVR16EA48", 335, F_AVR8X, {0x1E, 0x94, 0x35}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0200, 8, -1, -1, -1, -1, 0}, // avrdude
|
||||
{"AVR32DD14", 336, F_AVR8X, {0x1E, 0x95, 0x3B}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x7000, 0x1000, 16, 4, 36}, // atdf, avrdude
|
||||
{"AVR32DD20", 337, F_AVR8X, {0x1E, 0x95, 0x3A}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x7000, 0x1000, 16, 4, 36}, // atdf, avrdude
|
||||
{"AVR32DA28", 338, F_AVR8X, {0x1E, 0x95, 0x34}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x7000, 0x1000, 16, 4, 41}, // atdf, avrdude
|
||||
{"AVR32DB28", 339, F_AVR8X, {0x1E, 0x95, 0x37}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x7000, 0x1000, 16, 4, 42}, // atdf, avrdude
|
||||
{"AVR32DD28", 340, F_AVR8X, {0x1E, 0x95, 0x39}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x7000, 0x1000, 16, 4, 36}, // atdf, avrdude
|
||||
{"AVR32EA28", 341, F_AVR8X, {0x1E, 0x95, 0x3E}, 0, 0x08000, 0x040, 1, 0, 0x01400, 0x0200, 8, -1, -1, -1, -1, 0}, // avrdude
|
||||
{"AVR32DA32", 342, F_AVR8X, {0x1E, 0x95, 0x33}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x7000, 0x1000, 16, 4, 44}, // atdf, avrdude
|
||||
{"AVR32DB32", 343, F_AVR8X, {0x1E, 0x95, 0x36}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x7000, 0x1000, 16, 4, 44}, // atdf, avrdude
|
||||
{"AVR32DD32", 344, F_AVR8X, {0x1E, 0x95, 0x38}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x7000, 0x1000, 16, 4, 36}, // atdf, avrdude
|
||||
{"AVR32EA32", 345, F_AVR8X, {0x1E, 0x95, 0x3D}, 0, 0x08000, 0x040, 1, 0, 0x01400, 0x0200, 8, -1, -1, -1, -1, 0}, // avrdude
|
||||
{"AVR32DA48", 346, F_AVR8X, {0x1E, 0x95, 0x32}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x7000, 0x1000, 16, 4, 58}, // atdf, avrdude
|
||||
{"AVR32DB48", 347, F_AVR8X, {0x1E, 0x95, 0x35}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x7000, 0x1000, 16, 4, 61}, // atdf, avrdude
|
||||
{"AVR32EA48", 348, F_AVR8X, {0x1E, 0x95, 0x3C}, 0, 0x08000, 0x040, 1, 0, 0x01400, 0x0200, 8, -1, -1, -1, -1, 0}, // avrdude
|
||||
{"AVR64DD14", 349, F_AVR8X, {0x1E, 0x96, 0x1D}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x6000, 0x2000, 16, 4, 36}, // atdf, avrdude
|
||||
{"AVR64DD20", 350, F_AVR8X, {0x1E, 0x96, 0x1C}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x6000, 0x2000, 16, 4, 36}, // atdf, avrdude
|
||||
{"AVR64DA28", 351, F_AVR8X, {0x1E, 0x96, 0x15}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x6000, 0x2000, 16, 4, 41}, // atdf, avrdude
|
||||
{"AVR64DB28", 352, F_AVR8X, {0x1E, 0x96, 0x19}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x6000, 0x2000, 16, 4, 42}, // atdf, avrdude
|
||||
{"AVR64DD28", 353, F_AVR8X, {0x1E, 0x96, 0x1B}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x6000, 0x2000, 16, 4, 36}, // atdf, avrdude
|
||||
{"AVR64EA28", 354, F_AVR8X, {0x1E, 0x96, 0x20}, 0, 0x10000, 0x080, 1, 0, 0x01400, 0x0200, 8, 0x6800, 0x1800, 16, 4, 37}, // atdf, avrdude
|
||||
{"AVR64DA32", 355, F_AVR8X, {0x1E, 0x96, 0x14}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x6000, 0x2000, 16, 4, 44}, // atdf, avrdude
|
||||
{"AVR64DB32", 356, F_AVR8X, {0x1E, 0x96, 0x18}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x6000, 0x2000, 16, 4, 44}, // atdf, avrdude
|
||||
{"AVR64DD32", 357, F_AVR8X, {0x1E, 0x96, 0x1A}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x6000, 0x2000, 16, 4, 36}, // atdf, avrdude
|
||||
{"AVR64EA32", 358, F_AVR8X, {0x1E, 0x96, 0x1F}, 0, 0x10000, 0x080, 1, 0, 0x01400, 0x0200, 8, 0x6800, 0x1800, 16, 4, 37}, // atdf, avrdude
|
||||
{"AVR64DA48", 359, F_AVR8X, {0x1E, 0x96, 0x13}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x6000, 0x2000, 16, 4, 58}, // atdf, avrdude
|
||||
{"AVR64DB48", 360, F_AVR8X, {0x1E, 0x96, 0x17}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x6000, 0x2000, 16, 4, 61}, // atdf, avrdude
|
||||
{"AVR64EA48", 361, F_AVR8X, {0x1E, 0x96, 0x1E}, 0, 0x10000, 0x080, 1, 0, 0x01400, 0x0200, 8, 0x6800, 0x1800, 16, 4, 45}, // atdf, avrdude
|
||||
{"AVR64DA64", 362, F_AVR8X, {0x1E, 0x96, 0x12}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x6000, 0x2000, 16, 4, 64}, // atdf, avrdude
|
||||
{"AVR64DB64", 363, F_AVR8X, {0x1E, 0x96, 0x16}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x6000, 0x2000, 16, 4, 65}, // atdf, avrdude
|
||||
{"AVR128DA28", 364, F_AVR8X, {0x1E, 0x97, 0x0A}, 0, 0x20000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x4000, 0x4000, 16, 4, 41}, // atdf, avrdude
|
||||
{"AVR128DB28", 365, F_AVR8X, {0x1E, 0x97, 0x0E}, 0, 0x20000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x4000, 0x4000, 16, 4, 42}, // atdf, avrdude
|
||||
{"AVR128DA32", 366, F_AVR8X, {0x1E, 0x97, 0x09}, 0, 0x20000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x4000, 0x4000, 16, 4, 44}, // atdf, avrdude
|
||||
{"AVR128DB32", 367, F_AVR8X, {0x1E, 0x97, 0x0D}, 0, 0x20000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x4000, 0x4000, 16, 4, 44}, // atdf, avrdude
|
||||
{"AVR128DA48", 368, F_AVR8X, {0x1E, 0x97, 0x08}, 0, 0x20000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x4000, 0x4000, 16, 4, 58}, // atdf, avrdude
|
||||
{"AVR128DB48", 369, F_AVR8X, {0x1E, 0x97, 0x0C}, 0, 0x20000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x4000, 0x4000, 16, 4, 61}, // atdf, avrdude
|
||||
{"AVR128DA64", 370, F_AVR8X, {0x1E, 0x97, 0x07}, 0, 0x20000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x4000, 0x4000, 16, 4, 64}, // atdf, avrdude
|
||||
{"AVR128DB64", 371, F_AVR8X, {0x1E, 0x97, 0x0B}, 0, 0x20000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x4000, 0x4000, 16, 4, 65}, // atdf, avrdude
|
||||
};
|
||||
|
||||
const size_t avr_isp_chip_arr_size = COUNT_OF(avr_isp_chip_arr);
|
||||
@@ -1,33 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <furi_hal.h>
|
||||
|
||||
#define F_AVR8L 1 // TPI programming, ATtiny(4|5|9|10|20|40|102|104)
|
||||
#define F_AVR8 2 // ISP programming with SPI, "classic" AVRs
|
||||
#define F_XMEGA 4 // PDI programming, ATxmega family
|
||||
#define F_AVR8X 8 // UPDI programming, newer 8-bit MCUs
|
||||
|
||||
struct AvrIspChipArr { // Value of -1 typically means unknown
|
||||
const char* name; // Name of part
|
||||
uint16_t mcuid; // ID of MCU in 0..2039
|
||||
uint8_t avrarch; // F_AVR8L, F_AVR8, F_XMEGA or F_AVR8X
|
||||
uint8_t sigs[3]; // Signature bytes
|
||||
int32_t flashoffset; // Flash offset
|
||||
int32_t flashsize; // Flash size
|
||||
int16_t pagesize; // Flash page size
|
||||
int8_t nboots; // Number of supported boot sectors
|
||||
int16_t bootsize; // Size of (smallest) boot sector
|
||||
int32_t eepromoffset; // EEPROM offset
|
||||
int32_t eepromsize; // EEPROM size
|
||||
int32_t eeprompagesize; // EEPROM page size
|
||||
int32_t sramstart; // SRAM offset
|
||||
int32_t sramsize; // SRAM size
|
||||
int8_t nfuses; // Number of fuse bytes
|
||||
int8_t nlocks; // Number of lock bytes
|
||||
uint8_t ninterrupts; // Number of vectors in interrupt vector table
|
||||
};
|
||||
|
||||
typedef struct AvrIspChipArr AvrIspChipArr;
|
||||
|
||||
extern const AvrIspChipArr avr_isp_chip_arr[];
|
||||
extern const size_t avr_isp_chip_arr_size;
|
||||
@@ -1,639 +0,0 @@
|
||||
#include "avr_isp_prog.h"
|
||||
#include "avr_isp_prog_cmd.h"
|
||||
|
||||
#include <furi.h>
|
||||
|
||||
#define AVR_ISP_PROG_TX_RX_BUF_SIZE 320
|
||||
#define TAG "AvrIspProg"
|
||||
|
||||
struct AvrIspProgSignature {
|
||||
uint8_t vendor;
|
||||
uint8_t part_family;
|
||||
uint8_t part_number;
|
||||
};
|
||||
|
||||
typedef struct AvrIspProgSignature AvrIspProgSignature;
|
||||
|
||||
struct AvrIspProgCfgDevice {
|
||||
uint8_t devicecode;
|
||||
uint8_t revision;
|
||||
uint8_t progtype;
|
||||
uint8_t parmode;
|
||||
uint8_t polling;
|
||||
uint8_t selftimed;
|
||||
uint8_t lockbytes;
|
||||
uint8_t fusebytes;
|
||||
uint8_t flashpoll;
|
||||
uint16_t eeprompoll;
|
||||
uint16_t pagesize;
|
||||
uint16_t eepromsize;
|
||||
uint32_t flashsize;
|
||||
};
|
||||
|
||||
typedef struct AvrIspProgCfgDevice AvrIspProgCfgDevice;
|
||||
|
||||
struct AvrIspProg {
|
||||
AvrIspSpiSw* spi;
|
||||
AvrIspProgCfgDevice* cfg;
|
||||
FuriStreamBuffer* stream_rx;
|
||||
FuriStreamBuffer* stream_tx;
|
||||
|
||||
uint16_t error;
|
||||
uint16_t addr;
|
||||
bool pmode;
|
||||
bool exit;
|
||||
bool rst_active_high;
|
||||
uint8_t buff[AVR_ISP_PROG_TX_RX_BUF_SIZE];
|
||||
|
||||
AvrIspProgCallback callback;
|
||||
void* context;
|
||||
};
|
||||
|
||||
static void avr_isp_prog_end_pmode(AvrIspProg* instance);
|
||||
|
||||
AvrIspProg* avr_isp_prog_init(void) {
|
||||
AvrIspProg* instance = malloc(sizeof(AvrIspProg));
|
||||
instance->cfg = malloc(sizeof(AvrIspProgCfgDevice));
|
||||
instance->stream_rx =
|
||||
furi_stream_buffer_alloc(sizeof(int8_t) * AVR_ISP_PROG_TX_RX_BUF_SIZE, sizeof(int8_t));
|
||||
instance->stream_tx =
|
||||
furi_stream_buffer_alloc(sizeof(int8_t) * AVR_ISP_PROG_TX_RX_BUF_SIZE, sizeof(int8_t));
|
||||
instance->rst_active_high = false;
|
||||
instance->exit = false;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void avr_isp_prog_free(AvrIspProg* instance) {
|
||||
furi_assert(instance);
|
||||
if(instance->spi) avr_isp_prog_end_pmode(instance);
|
||||
furi_stream_buffer_free(instance->stream_tx);
|
||||
furi_stream_buffer_free(instance->stream_rx);
|
||||
free(instance->cfg);
|
||||
free(instance);
|
||||
}
|
||||
|
||||
size_t avr_isp_prog_spaces_rx(AvrIspProg* instance) {
|
||||
return furi_stream_buffer_spaces_available(instance->stream_rx);
|
||||
}
|
||||
|
||||
bool avr_isp_prog_rx(AvrIspProg* instance, uint8_t* data, size_t len) {
|
||||
furi_assert(instance);
|
||||
furi_assert(data);
|
||||
furi_assert(len != 0);
|
||||
size_t ret = furi_stream_buffer_send(instance->stream_rx, data, sizeof(uint8_t) * len, 0);
|
||||
return ret == sizeof(uint8_t) * len;
|
||||
}
|
||||
|
||||
size_t avr_isp_prog_tx(AvrIspProg* instance, uint8_t* data, size_t max_len) {
|
||||
furi_assert(instance);
|
||||
return furi_stream_buffer_receive(instance->stream_tx, data, sizeof(int8_t) * max_len, 0);
|
||||
}
|
||||
|
||||
void avr_isp_prog_exit(AvrIspProg* instance) {
|
||||
furi_assert(instance);
|
||||
instance->exit = true;
|
||||
}
|
||||
|
||||
void avr_isp_prog_set_tx_callback(AvrIspProg* instance, AvrIspProgCallback callback, void* context) {
|
||||
furi_assert(instance);
|
||||
furi_assert(context);
|
||||
instance->callback = callback;
|
||||
instance->context = context;
|
||||
}
|
||||
|
||||
static void avr_isp_prog_tx_ch(AvrIspProg* instance, uint8_t data) {
|
||||
furi_assert(instance);
|
||||
furi_stream_buffer_send(instance->stream_tx, &data, sizeof(uint8_t), FuriWaitForever);
|
||||
}
|
||||
|
||||
static uint8_t avr_isp_prog_getch(AvrIspProg* instance) {
|
||||
furi_assert(instance);
|
||||
uint8_t data[1] = {0};
|
||||
while(furi_stream_buffer_receive(instance->stream_rx, &data, sizeof(int8_t), 30) == 0) {
|
||||
if(instance->exit) break;
|
||||
};
|
||||
return data[0];
|
||||
}
|
||||
|
||||
static void avr_isp_prog_fill(AvrIspProg* instance, size_t len) {
|
||||
furi_assert(instance);
|
||||
for(size_t x = 0; x < len; x++) {
|
||||
instance->buff[x] = avr_isp_prog_getch(instance);
|
||||
}
|
||||
}
|
||||
|
||||
static void avr_isp_prog_reset_target(AvrIspProg* instance, bool reset) {
|
||||
furi_assert(instance);
|
||||
avr_isp_spi_sw_res_set(instance->spi, (reset == instance->rst_active_high) ? true : false);
|
||||
}
|
||||
|
||||
static uint8_t avr_isp_prog_spi_transaction(
|
||||
AvrIspProg* instance,
|
||||
uint8_t cmd,
|
||||
uint8_t addr_hi,
|
||||
uint8_t addr_lo,
|
||||
uint8_t data) {
|
||||
furi_assert(instance);
|
||||
|
||||
avr_isp_spi_sw_txrx(instance->spi, cmd);
|
||||
avr_isp_spi_sw_txrx(instance->spi, addr_hi);
|
||||
avr_isp_spi_sw_txrx(instance->spi, addr_lo);
|
||||
return avr_isp_spi_sw_txrx(instance->spi, data);
|
||||
}
|
||||
|
||||
static void avr_isp_prog_empty_reply(AvrIspProg* instance) {
|
||||
furi_assert(instance);
|
||||
if(avr_isp_prog_getch(instance) == CRC_EOP) {
|
||||
avr_isp_prog_tx_ch(instance, STK_INSYNC);
|
||||
avr_isp_prog_tx_ch(instance, STK_OK);
|
||||
} else {
|
||||
instance->error++;
|
||||
avr_isp_prog_tx_ch(instance, STK_NOSYNC);
|
||||
}
|
||||
}
|
||||
|
||||
static void avr_isp_prog_breply(AvrIspProg* instance, uint8_t data) {
|
||||
furi_assert(instance);
|
||||
if(avr_isp_prog_getch(instance) == CRC_EOP) {
|
||||
avr_isp_prog_tx_ch(instance, STK_INSYNC);
|
||||
avr_isp_prog_tx_ch(instance, data);
|
||||
avr_isp_prog_tx_ch(instance, STK_OK);
|
||||
} else {
|
||||
instance->error++;
|
||||
avr_isp_prog_tx_ch(instance, STK_NOSYNC);
|
||||
}
|
||||
}
|
||||
|
||||
static void avr_isp_prog_get_version(AvrIspProg* instance, uint8_t data) {
|
||||
furi_assert(instance);
|
||||
switch(data) {
|
||||
case STK_HW_VER:
|
||||
avr_isp_prog_breply(instance, AVR_ISP_HWVER);
|
||||
break;
|
||||
case STK_SW_MAJOR:
|
||||
avr_isp_prog_breply(instance, AVR_ISP_SWMAJ);
|
||||
break;
|
||||
case STK_SW_MINOR:
|
||||
avr_isp_prog_breply(instance, AVR_ISP_SWMIN);
|
||||
break;
|
||||
case AVP_ISP_CONNECT_TYPE:
|
||||
avr_isp_prog_breply(instance, AVP_ISP_SERIAL_CONNECT_TYPE);
|
||||
break;
|
||||
default:
|
||||
avr_isp_prog_breply(instance, AVR_ISP_RESP_0);
|
||||
}
|
||||
}
|
||||
|
||||
static void avr_isp_prog_set_cfg(AvrIspProg* instance) {
|
||||
furi_assert(instance);
|
||||
// call this after reading cfg packet into buff[]
|
||||
instance->cfg->devicecode = instance->buff[0];
|
||||
instance->cfg->revision = instance->buff[1];
|
||||
instance->cfg->progtype = instance->buff[2];
|
||||
instance->cfg->parmode = instance->buff[3];
|
||||
instance->cfg->polling = instance->buff[4];
|
||||
instance->cfg->selftimed = instance->buff[5];
|
||||
instance->cfg->lockbytes = instance->buff[6];
|
||||
instance->cfg->fusebytes = instance->buff[7];
|
||||
instance->cfg->flashpoll = instance->buff[8];
|
||||
// ignore (instance->buff[9] == instance->buff[8]) //FLASH polling value. Same as <20>flashpoll<6C>
|
||||
instance->cfg->eeprompoll = instance->buff[10] << 8 | instance->buff[11];
|
||||
instance->cfg->pagesize = instance->buff[12] << 8 | instance->buff[13];
|
||||
instance->cfg->eepromsize = instance->buff[14] << 8 | instance->buff[15];
|
||||
instance->cfg->flashsize = instance->buff[16] << 24 | instance->buff[17] << 16 |
|
||||
instance->buff[18] << 8 | instance->buff[19];
|
||||
|
||||
// avr devices have active low reset, at89sx are active high
|
||||
instance->rst_active_high = (instance->cfg->devicecode >= 0xe0);
|
||||
}
|
||||
static bool
|
||||
avr_isp_prog_set_pmode(AvrIspProg* instance, uint8_t a, uint8_t b, uint8_t c, uint8_t d) {
|
||||
furi_assert(instance);
|
||||
uint8_t res = 0;
|
||||
avr_isp_spi_sw_txrx(instance->spi, a);
|
||||
avr_isp_spi_sw_txrx(instance->spi, b);
|
||||
res = avr_isp_spi_sw_txrx(instance->spi, c);
|
||||
avr_isp_spi_sw_txrx(instance->spi, d);
|
||||
return res == 0x53;
|
||||
}
|
||||
|
||||
static void avr_isp_prog_end_pmode(AvrIspProg* instance) {
|
||||
furi_assert(instance);
|
||||
if(instance->pmode) {
|
||||
avr_isp_prog_reset_target(instance, false);
|
||||
// We're about to take the target out of reset
|
||||
// so configure SPI pins as input
|
||||
|
||||
if(instance->spi) avr_isp_spi_sw_free(instance->spi);
|
||||
instance->spi = NULL;
|
||||
}
|
||||
|
||||
instance->pmode = false;
|
||||
}
|
||||
|
||||
static bool avr_isp_prog_start_pmode(AvrIspProg* instance, AvrIspSpiSwSpeed spi_speed) {
|
||||
furi_assert(instance);
|
||||
// Reset target before driving PIN_SCK or PIN_MOSI
|
||||
|
||||
// SPI.begin() will configure SS as output,
|
||||
// so SPI master mode is selected.
|
||||
// We have defined RESET as pin 10,
|
||||
// which for many arduino's is not the SS pin.
|
||||
// So we have to configure RESET as output here,
|
||||
// (reset_target() first sets the correct level)
|
||||
if(instance->spi) avr_isp_spi_sw_free(instance->spi);
|
||||
instance->spi = avr_isp_spi_sw_init(spi_speed);
|
||||
|
||||
avr_isp_prog_reset_target(instance, true);
|
||||
// See avr datasheets, chapter "SERIAL_PRG Programming Algorithm":
|
||||
|
||||
// Pulse RESET after PIN_SCK is low:
|
||||
avr_isp_spi_sw_sck_set(instance->spi, false);
|
||||
|
||||
// discharge PIN_SCK, value arbitrally chosen
|
||||
furi_delay_ms(20);
|
||||
avr_isp_prog_reset_target(instance, false);
|
||||
|
||||
// Pulse must be minimum 2 target CPU speed cycles
|
||||
// so 100 usec is ok for CPU speeds above 20KHz
|
||||
furi_delay_ms(1);
|
||||
|
||||
avr_isp_prog_reset_target(instance, true);
|
||||
|
||||
// Send the enable programming command:
|
||||
// datasheet: must be > 20 msec
|
||||
furi_delay_ms(50);
|
||||
if(avr_isp_prog_set_pmode(instance, AVR_ISP_SET_PMODE)) {
|
||||
instance->pmode = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static AvrIspProgSignature avr_isp_prog_check_signature(AvrIspProg* instance) {
|
||||
furi_assert(instance);
|
||||
AvrIspProgSignature signature;
|
||||
signature.vendor = avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_VENDOR);
|
||||
signature.part_family = avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_PART_FAMILY);
|
||||
signature.part_number = avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_PART_NUMBER);
|
||||
return signature;
|
||||
}
|
||||
|
||||
static bool avr_isp_prog_auto_set_spi_speed_start_pmode(AvrIspProg* instance) {
|
||||
AvrIspSpiSwSpeed spi_speed[] = {
|
||||
AvrIspSpiSwSpeed1Mhz,
|
||||
AvrIspSpiSwSpeed400Khz,
|
||||
AvrIspSpiSwSpeed250Khz,
|
||||
AvrIspSpiSwSpeed125Khz,
|
||||
AvrIspSpiSwSpeed60Khz,
|
||||
AvrIspSpiSwSpeed40Khz,
|
||||
AvrIspSpiSwSpeed20Khz,
|
||||
AvrIspSpiSwSpeed10Khz,
|
||||
AvrIspSpiSwSpeed5Khz,
|
||||
AvrIspSpiSwSpeed1Khz,
|
||||
};
|
||||
for(uint8_t i = 0; i < COUNT_OF(spi_speed); i++) {
|
||||
if(avr_isp_prog_start_pmode(instance, spi_speed[i])) {
|
||||
AvrIspProgSignature sig = avr_isp_prog_check_signature(instance);
|
||||
AvrIspProgSignature sig_examination = avr_isp_prog_check_signature(instance); //-V656
|
||||
uint8_t y = 0;
|
||||
while(y < 8) {
|
||||
if(memcmp(
|
||||
(uint8_t*)&sig, (uint8_t*)&sig_examination, sizeof(AvrIspProgSignature)) !=
|
||||
0)
|
||||
break;
|
||||
sig_examination = avr_isp_prog_check_signature(instance);
|
||||
y++;
|
||||
}
|
||||
if(y == 8) {
|
||||
if(spi_speed[i] > AvrIspSpiSwSpeed1Mhz) {
|
||||
if(i < (COUNT_OF(spi_speed) - 1)) {
|
||||
avr_isp_prog_end_pmode(instance);
|
||||
i++;
|
||||
return avr_isp_prog_start_pmode(instance, spi_speed[i]);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(instance->spi) {
|
||||
avr_isp_spi_sw_free(instance->spi);
|
||||
instance->spi = NULL;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void avr_isp_prog_universal(AvrIspProg* instance) {
|
||||
furi_assert(instance);
|
||||
uint8_t data;
|
||||
|
||||
avr_isp_prog_fill(instance, 4);
|
||||
data = avr_isp_prog_spi_transaction(
|
||||
instance, instance->buff[0], instance->buff[1], instance->buff[2], instance->buff[3]);
|
||||
avr_isp_prog_breply(instance, data);
|
||||
}
|
||||
|
||||
static void avr_isp_prog_commit(AvrIspProg* instance, uint16_t addr, uint8_t data) {
|
||||
furi_assert(instance);
|
||||
avr_isp_prog_spi_transaction(instance, AVR_ISP_COMMIT(addr));
|
||||
/* polling flash */
|
||||
if(data == 0xFF) {
|
||||
furi_delay_ms(5);
|
||||
} else {
|
||||
/* polling flash */
|
||||
uint32_t starttime = furi_get_tick();
|
||||
while((furi_get_tick() - starttime) < 30) {
|
||||
if(avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_FLASH_HI(addr)) != 0xFF) {
|
||||
break;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static uint16_t avr_isp_prog_current_page(AvrIspProg* instance) {
|
||||
furi_assert(instance);
|
||||
uint16_t page = 0;
|
||||
switch(instance->cfg->pagesize) {
|
||||
case 32:
|
||||
page = instance->addr & 0xFFFFFFF0;
|
||||
break;
|
||||
case 64:
|
||||
page = instance->addr & 0xFFFFFFE0;
|
||||
break;
|
||||
case 128:
|
||||
page = instance->addr & 0xFFFFFFC0;
|
||||
break;
|
||||
case 256:
|
||||
page = instance->addr & 0xFFFFFF80;
|
||||
break;
|
||||
|
||||
default:
|
||||
page = instance->addr;
|
||||
break;
|
||||
}
|
||||
|
||||
return page;
|
||||
}
|
||||
|
||||
static uint8_t avr_isp_prog_write_flash_pages(AvrIspProg* instance, size_t length) {
|
||||
furi_assert(instance);
|
||||
size_t x = 0;
|
||||
uint16_t page = avr_isp_prog_current_page(instance);
|
||||
while(x < length) {
|
||||
if(page != avr_isp_prog_current_page(instance)) {
|
||||
--x;
|
||||
avr_isp_prog_commit(instance, page, instance->buff[x++]);
|
||||
page = avr_isp_prog_current_page(instance);
|
||||
}
|
||||
avr_isp_prog_spi_transaction(
|
||||
instance, AVR_ISP_WRITE_FLASH_LO(instance->addr, instance->buff[x++]));
|
||||
|
||||
avr_isp_prog_spi_transaction(
|
||||
instance, AVR_ISP_WRITE_FLASH_HI(instance->addr, instance->buff[x++]));
|
||||
instance->addr++;
|
||||
}
|
||||
|
||||
avr_isp_prog_commit(instance, page, instance->buff[--x]);
|
||||
return STK_OK;
|
||||
}
|
||||
|
||||
static void avr_isp_prog_write_flash(AvrIspProg* instance, size_t length) {
|
||||
furi_assert(instance);
|
||||
avr_isp_prog_fill(instance, length);
|
||||
if(avr_isp_prog_getch(instance) == CRC_EOP) {
|
||||
avr_isp_prog_tx_ch(instance, STK_INSYNC);
|
||||
avr_isp_prog_tx_ch(instance, avr_isp_prog_write_flash_pages(instance, length));
|
||||
} else {
|
||||
instance->error++;
|
||||
avr_isp_prog_tx_ch(instance, STK_NOSYNC);
|
||||
}
|
||||
}
|
||||
|
||||
// write (length) bytes, (start) is a byte address
|
||||
static uint8_t
|
||||
avr_isp_prog_write_eeprom_chunk(AvrIspProg* instance, uint16_t start, uint16_t length) {
|
||||
furi_assert(instance);
|
||||
// this writes byte-by-byte,
|
||||
// page writing may be faster (4 bytes at a time)
|
||||
avr_isp_prog_fill(instance, length);
|
||||
for(uint16_t x = 0; x < length; x++) {
|
||||
uint16_t addr = start + x;
|
||||
avr_isp_prog_spi_transaction(instance, AVR_ISP_WRITE_EEPROM(addr, instance->buff[x]));
|
||||
furi_delay_ms(10);
|
||||
}
|
||||
return STK_OK;
|
||||
}
|
||||
|
||||
static uint8_t avr_isp_prog_write_eeprom(AvrIspProg* instance, size_t length) {
|
||||
furi_assert(instance);
|
||||
// here is a word address, get the byte address
|
||||
uint16_t start = instance->addr * 2;
|
||||
uint16_t remaining = length;
|
||||
if(length > instance->cfg->eepromsize) {
|
||||
instance->error++;
|
||||
return STK_FAILED;
|
||||
}
|
||||
while(remaining > AVR_ISP_EECHUNK) {
|
||||
avr_isp_prog_write_eeprom_chunk(instance, start, AVR_ISP_EECHUNK);
|
||||
start += AVR_ISP_EECHUNK;
|
||||
remaining -= AVR_ISP_EECHUNK;
|
||||
}
|
||||
avr_isp_prog_write_eeprom_chunk(instance, start, remaining);
|
||||
return STK_OK;
|
||||
}
|
||||
|
||||
static void avr_isp_prog_program_page(AvrIspProg* instance) {
|
||||
furi_assert(instance);
|
||||
uint8_t result = STK_FAILED;
|
||||
uint16_t length = avr_isp_prog_getch(instance) << 8 | avr_isp_prog_getch(instance);
|
||||
uint8_t memtype = avr_isp_prog_getch(instance);
|
||||
// flash memory @addr, (length) bytes
|
||||
if(memtype == STK_SET_FLASH_TYPE) {
|
||||
avr_isp_prog_write_flash(instance, length);
|
||||
return;
|
||||
}
|
||||
if(memtype == STK_SET_EEPROM_TYPE) {
|
||||
result = avr_isp_prog_write_eeprom(instance, length);
|
||||
if(avr_isp_prog_getch(instance) == CRC_EOP) {
|
||||
avr_isp_prog_tx_ch(instance, STK_INSYNC);
|
||||
avr_isp_prog_tx_ch(instance, result);
|
||||
|
||||
} else {
|
||||
instance->error++;
|
||||
avr_isp_prog_tx_ch(instance, STK_NOSYNC);
|
||||
}
|
||||
return;
|
||||
}
|
||||
avr_isp_prog_tx_ch(instance, STK_FAILED);
|
||||
return;
|
||||
}
|
||||
|
||||
static uint8_t avr_isp_prog_flash_read_page(AvrIspProg* instance, uint16_t length) {
|
||||
furi_assert(instance);
|
||||
for(uint16_t x = 0; x < length; x += 2) {
|
||||
avr_isp_prog_tx_ch(
|
||||
instance,
|
||||
avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_FLASH_LO(instance->addr)));
|
||||
avr_isp_prog_tx_ch(
|
||||
instance,
|
||||
avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_FLASH_HI(instance->addr)));
|
||||
instance->addr++;
|
||||
}
|
||||
return STK_OK;
|
||||
}
|
||||
|
||||
static uint8_t avr_isp_prog_eeprom_read_page(AvrIspProg* instance, uint16_t length) {
|
||||
furi_assert(instance);
|
||||
// here again we have a word address
|
||||
uint16_t start = instance->addr * 2;
|
||||
for(uint16_t x = 0; x < length; x++) {
|
||||
uint16_t addr = start + x;
|
||||
avr_isp_prog_tx_ch(
|
||||
instance, avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_EEPROM(addr)));
|
||||
}
|
||||
return STK_OK;
|
||||
}
|
||||
|
||||
static void avr_isp_prog_read_page(AvrIspProg* instance) {
|
||||
furi_assert(instance);
|
||||
uint8_t result = STK_FAILED;
|
||||
uint16_t length = avr_isp_prog_getch(instance) << 8 | avr_isp_prog_getch(instance);
|
||||
uint8_t memtype = avr_isp_prog_getch(instance);
|
||||
if(avr_isp_prog_getch(instance) != CRC_EOP) {
|
||||
instance->error++;
|
||||
avr_isp_prog_tx_ch(instance, STK_NOSYNC);
|
||||
return;
|
||||
}
|
||||
avr_isp_prog_tx_ch(instance, STK_INSYNC);
|
||||
if(memtype == STK_SET_FLASH_TYPE) result = avr_isp_prog_flash_read_page(instance, length);
|
||||
if(memtype == STK_SET_EEPROM_TYPE) result = avr_isp_prog_eeprom_read_page(instance, length);
|
||||
avr_isp_prog_tx_ch(instance, result);
|
||||
}
|
||||
|
||||
static void avr_isp_prog_read_signature(AvrIspProg* instance) {
|
||||
furi_assert(instance);
|
||||
if(avr_isp_prog_getch(instance) != CRC_EOP) {
|
||||
instance->error++;
|
||||
avr_isp_prog_tx_ch(instance, STK_NOSYNC);
|
||||
return;
|
||||
}
|
||||
avr_isp_prog_tx_ch(instance, STK_INSYNC);
|
||||
|
||||
avr_isp_prog_tx_ch(instance, avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_VENDOR));
|
||||
avr_isp_prog_tx_ch(instance, avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_PART_FAMILY));
|
||||
avr_isp_prog_tx_ch(instance, avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_PART_NUMBER));
|
||||
|
||||
avr_isp_prog_tx_ch(instance, STK_OK);
|
||||
}
|
||||
|
||||
void avr_isp_prog_avrisp(AvrIspProg* instance) {
|
||||
furi_assert(instance);
|
||||
uint8_t ch = avr_isp_prog_getch(instance);
|
||||
|
||||
switch(ch) {
|
||||
case STK_GET_SYNC:
|
||||
FURI_LOG_D(TAG, "cmd STK_GET_SYNC");
|
||||
instance->error = 0;
|
||||
avr_isp_prog_empty_reply(instance);
|
||||
break;
|
||||
case STK_GET_SIGN_ON:
|
||||
FURI_LOG_D(TAG, "cmd STK_GET_SIGN_ON");
|
||||
if(avr_isp_prog_getch(instance) == CRC_EOP) {
|
||||
avr_isp_prog_tx_ch(instance, STK_INSYNC);
|
||||
|
||||
avr_isp_prog_tx_ch(instance, 'A');
|
||||
avr_isp_prog_tx_ch(instance, 'V');
|
||||
avr_isp_prog_tx_ch(instance, 'R');
|
||||
avr_isp_prog_tx_ch(instance, ' ');
|
||||
avr_isp_prog_tx_ch(instance, 'I');
|
||||
avr_isp_prog_tx_ch(instance, 'S');
|
||||
avr_isp_prog_tx_ch(instance, 'P');
|
||||
|
||||
avr_isp_prog_tx_ch(instance, STK_OK);
|
||||
} else {
|
||||
instance->error++;
|
||||
avr_isp_prog_tx_ch(instance, STK_NOSYNC);
|
||||
}
|
||||
break;
|
||||
case STK_GET_PARAMETER:
|
||||
FURI_LOG_D(TAG, "cmd STK_GET_PARAMETER");
|
||||
avr_isp_prog_get_version(instance, avr_isp_prog_getch(instance));
|
||||
break;
|
||||
case STK_SET_DEVICE:
|
||||
FURI_LOG_D(TAG, "cmd STK_SET_DEVICE");
|
||||
avr_isp_prog_fill(instance, 20);
|
||||
avr_isp_prog_set_cfg(instance);
|
||||
avr_isp_prog_empty_reply(instance);
|
||||
break;
|
||||
case STK_SET_DEVICE_EXT: // ignore for now
|
||||
FURI_LOG_D(TAG, "cmd STK_SET_DEVICE_EXT");
|
||||
avr_isp_prog_fill(instance, 5);
|
||||
avr_isp_prog_empty_reply(instance);
|
||||
break;
|
||||
case STK_ENTER_PROGMODE:
|
||||
FURI_LOG_D(TAG, "cmd STK_ENTER_PROGMODE");
|
||||
if(!instance->pmode) avr_isp_prog_auto_set_spi_speed_start_pmode(instance);
|
||||
avr_isp_prog_empty_reply(instance);
|
||||
break;
|
||||
case STK_LOAD_ADDRESS:
|
||||
FURI_LOG_D(TAG, "cmd STK_LOAD_ADDRESS");
|
||||
instance->addr = avr_isp_prog_getch(instance) | avr_isp_prog_getch(instance) << 8;
|
||||
avr_isp_prog_empty_reply(instance);
|
||||
break;
|
||||
case STK_PROG_FLASH: // ignore for now
|
||||
FURI_LOG_D(TAG, "cmd STK_PROG_FLASH");
|
||||
avr_isp_prog_getch(instance);
|
||||
avr_isp_prog_getch(instance);
|
||||
avr_isp_prog_empty_reply(instance);
|
||||
break;
|
||||
case STK_PROG_DATA: // ignore for now
|
||||
FURI_LOG_D(TAG, "cmd STK_PROG_DATA");
|
||||
avr_isp_prog_getch(instance);
|
||||
avr_isp_prog_empty_reply(instance);
|
||||
break;
|
||||
case STK_PROG_PAGE:
|
||||
FURI_LOG_D(TAG, "cmd STK_PROG_PAGE");
|
||||
avr_isp_prog_program_page(instance);
|
||||
break;
|
||||
case STK_READ_PAGE:
|
||||
FURI_LOG_D(TAG, "cmd STK_READ_PAGE");
|
||||
avr_isp_prog_read_page(instance);
|
||||
break;
|
||||
case STK_UNIVERSAL:
|
||||
FURI_LOG_D(TAG, "cmd STK_UNIVERSAL");
|
||||
avr_isp_prog_universal(instance);
|
||||
break;
|
||||
case STK_LEAVE_PROGMODE:
|
||||
FURI_LOG_D(TAG, "cmd STK_LEAVE_PROGMODE");
|
||||
instance->error = 0;
|
||||
if(instance->pmode) avr_isp_prog_end_pmode(instance);
|
||||
avr_isp_prog_empty_reply(instance);
|
||||
break;
|
||||
case STK_READ_SIGN:
|
||||
FURI_LOG_D(TAG, "cmd STK_READ_SIGN");
|
||||
avr_isp_prog_read_signature(instance);
|
||||
break;
|
||||
// expecting a command, not CRC_EOP
|
||||
// this is how we can get back in sync
|
||||
case CRC_EOP:
|
||||
FURI_LOG_D(TAG, "cmd CRC_EOP");
|
||||
instance->error++;
|
||||
avr_isp_prog_tx_ch(instance, STK_NOSYNC);
|
||||
break;
|
||||
// anything else we will return STK_UNKNOWN
|
||||
default:
|
||||
FURI_LOG_D(TAG, "cmd STK_ERROR_CMD");
|
||||
instance->error++;
|
||||
if(avr_isp_prog_getch(instance) == CRC_EOP)
|
||||
avr_isp_prog_tx_ch(instance, STK_UNKNOWN);
|
||||
else
|
||||
avr_isp_prog_tx_ch(instance, STK_NOSYNC);
|
||||
}
|
||||
|
||||
if(instance->callback) {
|
||||
instance->callback(instance->context);
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "avr_isp_spi_sw.h"
|
||||
#include <furi_hal.h>
|
||||
|
||||
typedef struct AvrIspProg AvrIspProg;
|
||||
typedef void (*AvrIspProgCallback)(void* context);
|
||||
|
||||
AvrIspProg* avr_isp_prog_init(void);
|
||||
void avr_isp_prog_free(AvrIspProg* instance);
|
||||
size_t avr_isp_prog_spaces_rx(AvrIspProg* instance) ;
|
||||
bool avr_isp_prog_rx(AvrIspProg* instance, uint8_t* data, size_t len);
|
||||
size_t avr_isp_prog_tx(AvrIspProg* instance, uint8_t* data, size_t max_len);
|
||||
void avr_isp_prog_avrisp(AvrIspProg* instance);
|
||||
void avr_isp_prog_exit(AvrIspProg* instance);
|
||||
void avr_isp_prog_set_tx_callback(AvrIspProg* instance, AvrIspProgCallback callback, void* context);
|
||||
@@ -1,97 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// http://ww1.microchip.com/downloads/en/appnotes/atmel-0943-in-system-programming_applicationnote_avr910.pdf
|
||||
// AVR ISP Definitions
|
||||
#define AVR_ISP_HWVER 0X02
|
||||
#define AVR_ISP_SWMAJ 0X01
|
||||
#define AVR_ISP_SWMIN 0X12
|
||||
#define AVP_ISP_SERIAL_CONNECT_TYPE 0X53
|
||||
#define AVP_ISP_CONNECT_TYPE 0x93
|
||||
#define AVR_ISP_RESP_0 0X00
|
||||
|
||||
#define AVR_ISP_SET_PMODE 0xAC, 0x53, 0x00, 0x00
|
||||
#define AVR_ISP_READ_VENDOR 0x30, 0x00, 0x00, 0x00
|
||||
#define AVR_ISP_READ_PART_FAMILY 0x30, 0x00, 0x01, 0x00
|
||||
#define AVR_ISP_READ_PART_NUMBER 0x30, 0x00, 0x02, 0x00
|
||||
#define AVR_ISP_ERASE_CHIP \
|
||||
0xAC, 0x80, 0x00, 0x00 //Erase Chip, Wait N ms, Release RESET to end the erase.
|
||||
//The only way to end a Chip Erase cycle is by temporarily releasing the Reset line
|
||||
|
||||
#define AVR_ISP_EXTENDED_ADDR(data) 0x4D, 0x00, data, 0x00
|
||||
#define AVR_ISP_WRITE_FLASH_LO(add, data) 0x40, (add >> 8) & 0xFF, add & 0xFF, data
|
||||
#define AVR_ISP_WRITE_FLASH_HI(add, data) 0x48, (add >> 8) & 0xFF, add & 0xFF, data
|
||||
#define AVR_ISP_READ_FLASH_LO(add) 0x20, (add >> 8) & 0xFF, add & 0xFF, 0x00
|
||||
#define AVR_ISP_READ_FLASH_HI(add) 0x28, (add >> 8) & 0xFF, add & 0xFF, 0x00
|
||||
|
||||
#define AVR_ISP_WRITE_EEPROM(add, data) \
|
||||
0xC0, (add >> 8) & 0xFF, add & 0xFF, data //Send cmd, Wait N ms
|
||||
#define AVR_ISP_READ_EEPROM(add) 0xA0, (add >> 8) & 0xFF, add & 0xFF, 0xFF
|
||||
|
||||
#define AVR_ISP_COMMIT(add) \
|
||||
0x4C, (add >> 8) & 0xFF, add & 0xFF, 0x00 //Send cmd, polling read last addr page
|
||||
|
||||
#define AVR_ISP_OSCCAL(add) 0x38, 0x00, add, 0x00
|
||||
|
||||
#define AVR_ISP_WRITE_LOCK_BYTE(data) 0xAC, 0xE0, 0x00, data //Send cmd, Wait N ms
|
||||
#define AVR_ISP_READ_LOCK_BYTE 0x58, 0x00, 0x00, 0x00
|
||||
#define AVR_ISP_WRITE_FUSE_LOW(data) 0xAC, 0xA0, 0x00, data //Send cmd, Wait N ms
|
||||
#define AVR_ISP_READ_FUSE_LOW 0x50, 0x00, 0x00, 0x00
|
||||
#define AVR_ISP_WRITE_FUSE_HIGH(data) 0xAC, 0xA8, 0x00, data //Send cmd, Wait N ms
|
||||
#define AVR_ISP_READ_FUSE_HIGH 0x58, 0x08, 0x00, 0x00
|
||||
#define AVR_ISP_WRITE_FUSE_EXTENDED(data) 0xAC, 0xA4, 0x00, data //Send cmd, Wait N ms (~write)
|
||||
#define AVR_ISP_READ_FUSE_EXTENDED 0x50, 0x08, 0x00, 0x00
|
||||
|
||||
#define AVR_ISP_EECHUNK 0x20
|
||||
|
||||
// https://www.microchip.com/content/dam/mchp/documents/OTH/ApplicationNotes/ApplicationNotes/doc2525.pdf
|
||||
// STK Definitions
|
||||
#define STK_OK 0x10
|
||||
#define STK_FAILED 0x11
|
||||
#define STK_UNKNOWN 0x12
|
||||
#define STK_INSYNC 0x14
|
||||
#define STK_NOSYNC 0x15
|
||||
#define CRC_EOP 0x20
|
||||
|
||||
#define STK_GET_SYNC 0x30
|
||||
#define STK_GET_SIGN_ON 0x31
|
||||
#define STK_SET_PARAMETER 0x40
|
||||
#define STK_GET_PARAMETER 0x41
|
||||
#define STK_SET_DEVICE 0x42
|
||||
#define STK_SET_DEVICE_EXT 0x45
|
||||
#define STK_ENTER_PROGMODE 0x50
|
||||
#define STK_LEAVE_PROGMODE 0x51
|
||||
#define STK_CHIP_ERASE 0x52
|
||||
#define STK_CHECK_AUTOINC 0x53
|
||||
#define STK_LOAD_ADDRESS 0x55
|
||||
#define STK_UNIVERSAL 0x56
|
||||
#define STK_UNIVERSAL_MULTI 0x57
|
||||
#define STK_PROG_FLASH 0x60
|
||||
#define STK_PROG_DATA 0x61
|
||||
#define STK_PROG_FUSE 0x62
|
||||
#define STK_PROG_FUSE_EXT 0x65
|
||||
#define STK_PROG_LOCK 0x63
|
||||
#define STK_PROG_PAGE 0x64
|
||||
#define STK_READ_FLASH 0x70
|
||||
#define STK_READ_DATA 0x71
|
||||
#define STK_READ_FUSE 0x72
|
||||
#define STK_READ_LOCK 0x73
|
||||
#define STK_READ_PAGE 0x74
|
||||
#define STK_READ_SIGN 0x75
|
||||
#define STK_READ_OSCCAL 0x76
|
||||
#define STK_READ_FUSE_EXT 0x77
|
||||
#define STK_READ_OSCCAL_EXT 0x78
|
||||
#define STK_HW_VER 0x80
|
||||
#define STK_SW_MAJOR 0x81
|
||||
#define STK_SW_MINOR 0x82
|
||||
#define STK_LEDS 0x83
|
||||
#define STK_VTARGET 0x84
|
||||
#define STK_VADJUST 0x85
|
||||
#define STK_OSC_PSCALE 0x86
|
||||
#define STK_OSC_CMATCH 0x87
|
||||
#define STK_SCK_DURATION 0x89
|
||||
#define STK_BUFSIZEL 0x90
|
||||
#define STK_BUFSIZEH 0x91
|
||||
#define STK_STK500_TOPCARD_DETECT 0x98
|
||||
|
||||
#define STK_SET_EEPROM_TYPE 0X45
|
||||
#define STK_SET_FLASH_TYPE 0X46
|
||||
@@ -1,71 +0,0 @@
|
||||
#include "avr_isp_spi_sw.h"
|
||||
|
||||
#include <furi.h>
|
||||
|
||||
#define AVR_ISP_SPI_SW_MISO &gpio_ext_pa6
|
||||
#define AVR_ISP_SPI_SW_MOSI &gpio_ext_pa7
|
||||
#define AVR_ISP_SPI_SW_SCK &gpio_ext_pb3
|
||||
#define AVR_ISP_RESET &gpio_ext_pb2
|
||||
|
||||
struct AvrIspSpiSw {
|
||||
AvrIspSpiSwSpeed speed_wait_time;
|
||||
const GpioPin* miso;
|
||||
const GpioPin* mosi;
|
||||
const GpioPin* sck;
|
||||
const GpioPin* res;
|
||||
};
|
||||
|
||||
AvrIspSpiSw* avr_isp_spi_sw_init(AvrIspSpiSwSpeed speed) {
|
||||
AvrIspSpiSw* instance = malloc(sizeof(AvrIspSpiSw));
|
||||
instance->speed_wait_time = speed;
|
||||
instance->miso = AVR_ISP_SPI_SW_MISO;
|
||||
instance->mosi = AVR_ISP_SPI_SW_MOSI;
|
||||
instance->sck = AVR_ISP_SPI_SW_SCK;
|
||||
instance->res = AVR_ISP_RESET;
|
||||
|
||||
furi_hal_gpio_init(instance->miso, GpioModeInput, GpioPullNo, GpioSpeedVeryHigh);
|
||||
furi_hal_gpio_write(instance->mosi, false);
|
||||
furi_hal_gpio_init(instance->mosi, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
|
||||
furi_hal_gpio_write(instance->sck, false);
|
||||
furi_hal_gpio_init(instance->sck, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
|
||||
furi_hal_gpio_init(instance->res, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
void avr_isp_spi_sw_free(AvrIspSpiSw* instance) {
|
||||
furi_assert(instance);
|
||||
furi_hal_gpio_init(instance->res, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_init(instance->miso, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_init(instance->mosi, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_init(instance->sck, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
free(instance);
|
||||
}
|
||||
|
||||
uint8_t avr_isp_spi_sw_txrx(AvrIspSpiSw* instance, uint8_t data) {
|
||||
furi_assert(instance);
|
||||
for(uint8_t i = 0; i < 8; ++i) {
|
||||
furi_hal_gpio_write(instance->mosi, (data & 0x80) ? true : false);
|
||||
|
||||
furi_hal_gpio_write(instance->sck, true);
|
||||
if(instance->speed_wait_time != AvrIspSpiSwSpeed1Mhz)
|
||||
furi_delay_us(instance->speed_wait_time - 1);
|
||||
|
||||
data = (data << 1) | furi_hal_gpio_read(instance->miso); //-V792
|
||||
|
||||
furi_hal_gpio_write(instance->sck, false);
|
||||
if(instance->speed_wait_time != AvrIspSpiSwSpeed1Mhz)
|
||||
furi_delay_us(instance->speed_wait_time - 1);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
void avr_isp_spi_sw_res_set(AvrIspSpiSw* instance, bool state) {
|
||||
furi_assert(instance);
|
||||
furi_hal_gpio_write(instance->res, state);
|
||||
}
|
||||
|
||||
void avr_isp_spi_sw_sck_set(AvrIspSpiSw* instance, bool state) {
|
||||
furi_assert(instance);
|
||||
furi_hal_gpio_write(instance->sck, state);
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <furi_hal.h>
|
||||
|
||||
typedef enum {
|
||||
AvrIspSpiSwSpeed1Mhz = 0,
|
||||
AvrIspSpiSwSpeed400Khz = 1,
|
||||
AvrIspSpiSwSpeed250Khz = 2,
|
||||
AvrIspSpiSwSpeed125Khz = 4,
|
||||
AvrIspSpiSwSpeed60Khz = 8,
|
||||
AvrIspSpiSwSpeed40Khz = 12,
|
||||
AvrIspSpiSwSpeed20Khz = 24,
|
||||
AvrIspSpiSwSpeed10Khz = 48,
|
||||
AvrIspSpiSwSpeed5Khz = 96,
|
||||
AvrIspSpiSwSpeed1Khz = 480,
|
||||
} AvrIspSpiSwSpeed;
|
||||
|
||||
typedef struct AvrIspSpiSw AvrIspSpiSw;
|
||||
|
||||
AvrIspSpiSw* avr_isp_spi_sw_init(AvrIspSpiSwSpeed speed);
|
||||
void avr_isp_spi_sw_free(AvrIspSpiSw* instance);
|
||||
uint8_t avr_isp_spi_sw_txrx(AvrIspSpiSw* instance, uint8_t data);
|
||||
void avr_isp_spi_sw_res_set(AvrIspSpiSw* instance, bool state);
|
||||
void avr_isp_spi_sw_sck_set(AvrIspSpiSw* instance, bool state);
|
||||
|
Before Width: | Height: | Size: 3.6 KiB |
@@ -1,30 +0,0 @@
|
||||
#include "../avr_isp_app_i.h"
|
||||
|
||||
// Generate scene on_enter handlers array
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
|
||||
void (*const avr_isp_scene_on_enter_handlers[])(void*) = {
|
||||
#include "avr_isp_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 avr_isp_scene_on_event_handlers[])(void* context, SceneManagerEvent event) = {
|
||||
#include "avr_isp_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 avr_isp_scene_on_exit_handlers[])(void* context) = {
|
||||
#include "avr_isp_scene_config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Initialize scene handlers configuration structure
|
||||
const SceneManagerHandlers avr_isp_scene_handlers = {
|
||||
.on_enter_handlers = avr_isp_scene_on_enter_handlers,
|
||||
.on_event_handlers = avr_isp_scene_on_event_handlers,
|
||||
.on_exit_handlers = avr_isp_scene_on_exit_handlers,
|
||||
.scene_num = AvrIspSceneNum,
|
||||
};
|
||||
@@ -1,29 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/scene_manager.h>
|
||||
|
||||
// Generate scene id and total number
|
||||
#define ADD_SCENE(prefix, name, id) AvrIspScene##id,
|
||||
typedef enum {
|
||||
#include "avr_isp_scene_config.h"
|
||||
AvrIspSceneNum,
|
||||
} AvrIspScene;
|
||||
#undef ADD_SCENE
|
||||
|
||||
extern const SceneManagerHandlers avr_isp_scene_handlers;
|
||||
|
||||
// Generate scene on_enter handlers declaration
|
||||
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
|
||||
#include "avr_isp_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 "avr_isp_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 "avr_isp_scene_config.h"
|
||||
#undef ADD_SCENE
|
||||
@@ -1,99 +0,0 @@
|
||||
#include "../avr_isp_app_i.h"
|
||||
#include "../helpers/avr_isp_types.h"
|
||||
|
||||
void avr_isp_scene_about_widget_callback(GuiButtonType result, InputType type, void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
AvrIspApp* app = context;
|
||||
if(type == InputTypeShort) {
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, result);
|
||||
}
|
||||
}
|
||||
|
||||
void avr_isp_scene_about_on_enter(void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
AvrIspApp* app = context;
|
||||
FuriString* temp_str = furi_string_alloc();
|
||||
furi_string_printf(temp_str, "\e#%s\n", "Information");
|
||||
|
||||
furi_string_cat_printf(temp_str, "Version: %s\n", AVR_ISP_VERSION_APP);
|
||||
furi_string_cat_printf(temp_str, "Developed by: %s\n", AVR_ISP_DEVELOPED);
|
||||
furi_string_cat_printf(temp_str, "Github: %s\n\n", AVR_ISP_GITHUB);
|
||||
|
||||
furi_string_cat_printf(temp_str, "\e#%s\n", "Description");
|
||||
furi_string_cat_printf(
|
||||
temp_str,
|
||||
"This application is an AVR in-system programmer based on stk500mk1. It is compatible with AVR-based"
|
||||
" microcontrollers including Arduino. You can also use it to repair the chip if you accidentally"
|
||||
" corrupt the bootloader.\n\n");
|
||||
|
||||
furi_string_cat_printf(temp_str, "\e#%s\n", "What it can do:");
|
||||
furi_string_cat_printf(temp_str, "- Create a dump of your chip on an SD card\n");
|
||||
furi_string_cat_printf(temp_str, "- Flash your chip firmware from the SD card\n");
|
||||
furi_string_cat_printf(temp_str, "- Act as a wired USB ISP using avrdude software\n\n");
|
||||
|
||||
furi_string_cat_printf(temp_str, "\e#%s\n", "Supported chip series:");
|
||||
furi_string_cat_printf(
|
||||
temp_str,
|
||||
"Example command for avrdude flashing: avrdude.exe -p m328p -c stk500v1 -P COMxx -U flash:r:"
|
||||
"X:\\sketch_sample.hex"
|
||||
":i\n");
|
||||
furi_string_cat_printf(
|
||||
temp_str,
|
||||
"Where: "
|
||||
"-p m328p"
|
||||
" brand of your chip, "
|
||||
"-P COMxx"
|
||||
" com port number in the system when "
|
||||
"ISP Programmer"
|
||||
" is enabled\n\n");
|
||||
|
||||
furi_string_cat_printf(temp_str, "\e#%s\n", "Info");
|
||||
furi_string_cat_printf(
|
||||
temp_str,
|
||||
"ATtinyXXXX\nATmegaXXXX\nAT43Uxxx\nAT76C711\nAT86RF401\nAT90xxxxx\nAT94K\n"
|
||||
"ATAxxxxx\nATA664251\nM3000\nLGT8F88P\nLGT8F168P\nLGT8F328P\n");
|
||||
|
||||
furi_string_cat_printf(
|
||||
temp_str, "For a more detailed list of supported chips, see AVRDude help\n");
|
||||
|
||||
widget_add_text_box_element(
|
||||
app->widget,
|
||||
0,
|
||||
0,
|
||||
128,
|
||||
14,
|
||||
AlignCenter,
|
||||
AlignBottom,
|
||||
"\e#\e! \e!\n",
|
||||
false);
|
||||
widget_add_text_box_element(
|
||||
app->widget,
|
||||
0,
|
||||
2,
|
||||
128,
|
||||
14,
|
||||
AlignCenter,
|
||||
AlignBottom,
|
||||
"\e#\e! ISP Programmer \e!\n",
|
||||
false);
|
||||
widget_add_text_scroll_element(app->widget, 0, 16, 128, 50, furi_string_get_cstr(temp_str));
|
||||
furi_string_free(temp_str);
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewWidget);
|
||||
}
|
||||
|
||||
bool avr_isp_scene_about_on_event(void* context, SceneManagerEvent event) {
|
||||
UNUSED(context);
|
||||
UNUSED(event);
|
||||
return false;
|
||||
}
|
||||
|
||||
void avr_isp_scene_about_on_exit(void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
AvrIspApp* app = context;
|
||||
// Clear views
|
||||
widget_reset(app->widget);
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
#include "../avr_isp_app_i.h"
|
||||
|
||||
void avr_isp_scene_chip_detect_callback(AvrIspCustomEvent event, void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
AvrIspApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, event);
|
||||
}
|
||||
|
||||
void avr_isp_scene_chip_detect_on_enter(void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
AvrIspApp* app = context;
|
||||
switch(app->error) {
|
||||
case AvrIspErrorReading:
|
||||
case AvrIspErrorWriting:
|
||||
case AvrIspErrorWritingFuse:
|
||||
avr_isp_chip_detect_set_state(
|
||||
app->avr_isp_chip_detect_view, AvrIspChipDetectViewStateErrorOccured);
|
||||
break;
|
||||
case AvrIspErrorVerification:
|
||||
avr_isp_chip_detect_set_state(
|
||||
app->avr_isp_chip_detect_view, AvrIspChipDetectViewStateErrorVerification);
|
||||
break;
|
||||
|
||||
default:
|
||||
avr_isp_chip_detect_set_state(
|
||||
app->avr_isp_chip_detect_view, AvrIspChipDetectViewStateNoDetect);
|
||||
break;
|
||||
}
|
||||
app->error = AvrIspErrorNoError;
|
||||
avr_isp_chip_detect_view_set_callback(
|
||||
app->avr_isp_chip_detect_view, avr_isp_scene_chip_detect_callback, app);
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewChipDetect);
|
||||
}
|
||||
|
||||
bool avr_isp_scene_chip_detect_on_event(void* context, SceneManagerEvent event) {
|
||||
furi_assert(context);
|
||||
|
||||
AvrIspApp* app = context;
|
||||
bool consumed = false;
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
switch(event.event) {
|
||||
case AvrIspCustomEventSceneChipDetectOk:
|
||||
|
||||
if(scene_manager_get_scene_state(app->scene_manager, AvrIspSceneChipDetect) ==
|
||||
AvrIspViewProgrammer) {
|
||||
scene_manager_next_scene(app->scene_manager, AvrIspSceneProgrammer);
|
||||
} else if(
|
||||
scene_manager_get_scene_state(app->scene_manager, AvrIspSceneChipDetect) ==
|
||||
AvrIspViewReader) {
|
||||
scene_manager_next_scene(app->scene_manager, AvrIspSceneInputName);
|
||||
} else if(
|
||||
scene_manager_get_scene_state(app->scene_manager, AvrIspSceneChipDetect) ==
|
||||
AvrIspViewWriter) {
|
||||
scene_manager_next_scene(app->scene_manager, AvrIspSceneLoad);
|
||||
}
|
||||
|
||||
consumed = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if(event.type == SceneManagerEventTypeTick) {
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void avr_isp_scene_chip_detect_on_exit(void* context) {
|
||||
UNUSED(context);
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
ADD_SCENE(avr_isp, start, Start)
|
||||
ADD_SCENE(avr_isp, about, About)
|
||||
ADD_SCENE(avr_isp, programmer, Programmer)
|
||||
ADD_SCENE(avr_isp, reader, Reader)
|
||||
ADD_SCENE(avr_isp, input_name, InputName)
|
||||
ADD_SCENE(avr_isp, load, Load)
|
||||
ADD_SCENE(avr_isp, writer, Writer)
|
||||
ADD_SCENE(avr_isp, wiring, Wiring)
|
||||
ADD_SCENE(avr_isp, chip_detect, ChipDetect)
|
||||
ADD_SCENE(avr_isp, success, Success)
|
||||
@@ -1,89 +0,0 @@
|
||||
#include "../avr_isp_app_i.h"
|
||||
#include <gui/modules/validators.h>
|
||||
|
||||
#define MAX_TEXT_INPUT_LEN 22
|
||||
|
||||
void avr_isp_scene_input_name_text_callback(void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
AvrIspApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, AvrIspCustomEventSceneInputName);
|
||||
}
|
||||
|
||||
void avr_isp_scene_input_name_get_timefilename(FuriString* name) {
|
||||
FuriHalRtcDateTime datetime = {0};
|
||||
furi_hal_rtc_get_datetime(&datetime);
|
||||
furi_string_printf(
|
||||
name,
|
||||
"AVR_dump-%.4d%.2d%.2d-%.2d%.2d%.2d",
|
||||
datetime.year,
|
||||
datetime.month,
|
||||
datetime.day,
|
||||
datetime.hour,
|
||||
datetime.minute,
|
||||
datetime.second);
|
||||
}
|
||||
|
||||
void avr_isp_scene_input_name_on_enter(void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
AvrIspApp* app = context;
|
||||
// Setup view
|
||||
TextInput* text_input = app->text_input;
|
||||
bool dev_name_empty = false;
|
||||
|
||||
FuriString* file_name = furi_string_alloc();
|
||||
|
||||
avr_isp_scene_input_name_get_timefilename(file_name);
|
||||
furi_string_set(app->file_path, STORAGE_APP_DATA_PATH_PREFIX);
|
||||
//highlighting the entire filename by default
|
||||
dev_name_empty = true;
|
||||
|
||||
strncpy(app->file_name_tmp, furi_string_get_cstr(file_name), AVR_ISP_MAX_LEN_NAME);
|
||||
text_input_set_header_text(text_input, "Name dump");
|
||||
text_input_set_result_callback(
|
||||
text_input,
|
||||
avr_isp_scene_input_name_text_callback,
|
||||
app,
|
||||
app->file_name_tmp,
|
||||
MAX_TEXT_INPUT_LEN, // buffer size
|
||||
dev_name_empty);
|
||||
|
||||
ValidatorIsFile* validator_is_file =
|
||||
validator_is_file_alloc_init(STORAGE_APP_DATA_PATH_PREFIX, AVR_ISP_APP_EXTENSION, "");
|
||||
text_input_set_validator(text_input, validator_is_file_callback, validator_is_file);
|
||||
|
||||
furi_string_free(file_name);
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewTextInput);
|
||||
}
|
||||
|
||||
bool avr_isp_scene_input_name_on_event(void* context, SceneManagerEvent event) {
|
||||
furi_assert(context);
|
||||
|
||||
AvrIspApp* app = context;
|
||||
if(event.type == SceneManagerEventTypeBack) {
|
||||
scene_manager_previous_scene(app->scene_manager);
|
||||
return true;
|
||||
} else if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == AvrIspCustomEventSceneInputName) {
|
||||
if(strcmp(app->file_name_tmp, "") != 0) {
|
||||
scene_manager_next_scene(app->scene_manager, AvrIspSceneReader);
|
||||
} else {
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void avr_isp_scene_input_name_on_exit(void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
AvrIspApp* app = context;
|
||||
// Clear validator
|
||||
void* validator_context = text_input_get_validator_callback_context(app->text_input);
|
||||
text_input_set_validator(app->text_input, NULL, NULL);
|
||||
validator_is_file_free(validator_context);
|
||||
// Clear view
|
||||
text_input_reset(app->text_input);
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
#include "../avr_isp_app_i.h"
|
||||
|
||||
void avr_isp_scene_load_on_enter(void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
AvrIspApp* app = context;
|
||||
if(avr_isp_load_from_file(app)) {
|
||||
scene_manager_next_scene(app->scene_manager, AvrIspSceneWriter);
|
||||
} else {
|
||||
scene_manager_previous_scene(app->scene_manager);
|
||||
}
|
||||
}
|
||||
|
||||
bool avr_isp_scene_load_on_event(void* context, SceneManagerEvent event) {
|
||||
UNUSED(context);
|
||||
UNUSED(event);
|
||||
return false;
|
||||
}
|
||||
|
||||
void avr_isp_scene_load_on_exit(void* context) {
|
||||
UNUSED(context);
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
#include "../avr_isp_app_i.h"
|
||||
|
||||
void avr_isp_scene_programmer_callback(AvrIspCustomEvent event, void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
AvrIspApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, event);
|
||||
}
|
||||
|
||||
void avr_isp_scene_programmer_on_enter(void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
AvrIspApp* app = context;
|
||||
avr_isp_programmer_view_set_callback(
|
||||
app->avr_isp_programmer_view, avr_isp_scene_programmer_callback, app);
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewProgrammer);
|
||||
}
|
||||
|
||||
bool avr_isp_scene_programmer_on_event(void* context, SceneManagerEvent event) {
|
||||
UNUSED(context);
|
||||
UNUSED(event);
|
||||
return false;
|
||||
}
|
||||
|
||||
void avr_isp_scene_programmer_on_exit(void* context) {
|
||||
UNUSED(context);
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
#include "../avr_isp_app_i.h"
|
||||
|
||||
void avr_isp_scene_reader_callback(AvrIspCustomEvent event, void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
AvrIspApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, event);
|
||||
}
|
||||
|
||||
void avr_isp_scene_reader_on_enter(void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
AvrIspApp* app = context;
|
||||
avr_isp_reader_set_file_path(
|
||||
app->avr_isp_reader_view, furi_string_get_cstr(app->file_path), app->file_name_tmp);
|
||||
avr_isp_reader_view_set_callback(app->avr_isp_reader_view, avr_isp_scene_reader_callback, app);
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewReader);
|
||||
}
|
||||
|
||||
bool avr_isp_scene_reader_on_event(void* context, SceneManagerEvent event) {
|
||||
furi_assert(context);
|
||||
|
||||
AvrIspApp* app = context;
|
||||
UNUSED(app);
|
||||
bool consumed = false;
|
||||
if(event.type == SceneManagerEventTypeBack) {
|
||||
//do not handle exit on "Back"
|
||||
consumed = true;
|
||||
} else if(event.type == SceneManagerEventTypeCustom) {
|
||||
switch(event.event) {
|
||||
case AvrIspCustomEventSceneReadingOk:
|
||||
scene_manager_next_scene(app->scene_manager, AvrIspSceneSuccess);
|
||||
consumed = true;
|
||||
break;
|
||||
case AvrIspCustomEventSceneExit:
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
app->scene_manager, AvrIspSceneChipDetect);
|
||||
consumed = true;
|
||||
break;
|
||||
case AvrIspCustomEventSceneErrorVerification:
|
||||
app->error = AvrIspErrorVerification;
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
app->scene_manager, AvrIspSceneChipDetect);
|
||||
consumed = true;
|
||||
break;
|
||||
case AvrIspCustomEventSceneErrorReading:
|
||||
app->error = AvrIspErrorReading;
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
app->scene_manager, AvrIspSceneChipDetect);
|
||||
consumed = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if(event.type == SceneManagerEventTypeTick) {
|
||||
avr_isp_reader_update_progress(app->avr_isp_reader_view);
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void avr_isp_scene_reader_on_exit(void* context) {
|
||||
UNUSED(context);
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
#include "../avr_isp_app_i.h"
|
||||
|
||||
void avr_isp_scene_start_submenu_callback(void* context, uint32_t index) {
|
||||
furi_assert(context);
|
||||
AvrIspApp* app = context;
|
||||
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, index);
|
||||
}
|
||||
|
||||
void avr_isp_scene_start_on_enter(void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
AvrIspApp* app = context;
|
||||
Submenu* submenu = app->submenu;
|
||||
submenu_add_item(
|
||||
submenu, "Dump AVR", SubmenuIndexAvrIspReader, avr_isp_scene_start_submenu_callback, app);
|
||||
submenu_add_item(
|
||||
submenu, "Flash AVR", SubmenuIndexAvrIspWriter, avr_isp_scene_start_submenu_callback, app);
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"ISP Programmer",
|
||||
SubmenuIndexAvrIspProgrammer,
|
||||
avr_isp_scene_start_submenu_callback,
|
||||
app);
|
||||
submenu_add_item(
|
||||
submenu, "Wiring", SubmenuIndexAvrIsWiring, avr_isp_scene_start_submenu_callback, app);
|
||||
submenu_add_item(
|
||||
submenu, "About", SubmenuIndexAvrIspAbout, avr_isp_scene_start_submenu_callback, app);
|
||||
|
||||
submenu_set_selected_item(
|
||||
submenu, scene_manager_get_scene_state(app->scene_manager, AvrIspSceneStart));
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewSubmenu);
|
||||
}
|
||||
|
||||
bool avr_isp_scene_start_on_event(void* context, SceneManagerEvent event) {
|
||||
furi_assert(context);
|
||||
|
||||
AvrIspApp* app = context;
|
||||
bool consumed = false;
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubmenuIndexAvrIspAbout) {
|
||||
scene_manager_next_scene(app->scene_manager, AvrIspSceneAbout);
|
||||
consumed = true;
|
||||
} else if(event.event == SubmenuIndexAvrIspProgrammer) {
|
||||
scene_manager_set_scene_state(
|
||||
app->scene_manager, AvrIspSceneChipDetect, AvrIspViewProgrammer);
|
||||
scene_manager_next_scene(app->scene_manager, AvrIspSceneChipDetect);
|
||||
consumed = true;
|
||||
} else if(event.event == SubmenuIndexAvrIspReader) {
|
||||
scene_manager_set_scene_state(
|
||||
app->scene_manager, AvrIspSceneChipDetect, AvrIspViewReader);
|
||||
scene_manager_next_scene(app->scene_manager, AvrIspSceneChipDetect);
|
||||
consumed = true;
|
||||
} else if(event.event == SubmenuIndexAvrIspWriter) {
|
||||
scene_manager_set_scene_state(
|
||||
app->scene_manager, AvrIspSceneChipDetect, AvrIspViewWriter);
|
||||
scene_manager_next_scene(app->scene_manager, AvrIspSceneChipDetect);
|
||||
consumed = true;
|
||||
} else if(event.event == SubmenuIndexAvrIsWiring) {
|
||||
scene_manager_next_scene(app->scene_manager, AvrIspSceneWiring);
|
||||
consumed = true;
|
||||
}
|
||||
scene_manager_set_scene_state(app->scene_manager, AvrIspSceneStart, event.event);
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void avr_isp_scene_start_on_exit(void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
AvrIspApp* app = context;
|
||||
submenu_reset(app->submenu);
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
#include "../avr_isp_app_i.h"
|
||||
|
||||
void avr_isp_scene_success_popup_callback(void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
AvrIspApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, AvrIspCustomEventSceneSuccess);
|
||||
}
|
||||
|
||||
void avr_isp_scene_success_on_enter(void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
AvrIspApp* app = context;
|
||||
Popup* popup = app->popup;
|
||||
popup_set_icon(popup, 32, 5, &I_dolphin_nice_96x59);
|
||||
popup_set_header(popup, "Success!", 8, 22, AlignLeft, AlignBottom);
|
||||
popup_set_timeout(popup, 1500);
|
||||
popup_set_context(popup, app);
|
||||
popup_set_callback(popup, avr_isp_scene_success_popup_callback);
|
||||
popup_enable_timeout(popup);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewPopup);
|
||||
}
|
||||
|
||||
bool avr_isp_scene_success_on_event(void* context, SceneManagerEvent event) {
|
||||
furi_assert(context);
|
||||
|
||||
AvrIspApp* app = context;
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == AvrIspCustomEventSceneSuccess) {
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
app->scene_manager, AvrIspSceneStart);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void avr_isp_scene_success_on_exit(void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
AvrIspApp* app = context;
|
||||
Popup* popup = app->popup;
|
||||
popup_reset(popup);
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
#include "../avr_isp_app_i.h"
|
||||
|
||||
void avr_isp_scene_wiring_on_enter(void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
AvrIspApp* app = context;
|
||||
widget_add_icon_element(app->widget, 0, 0, &I_avr_wiring);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewWidget);
|
||||
}
|
||||
|
||||
bool avr_isp_scene_wiring_on_event(void* context, SceneManagerEvent event) {
|
||||
UNUSED(context);
|
||||
UNUSED(event);
|
||||
return false;
|
||||
}
|
||||
void avr_isp_scene_wiring_on_exit(void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
AvrIspApp* app = context;
|
||||
widget_reset(app->widget);
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
#include "../avr_isp_app_i.h"
|
||||
|
||||
void avr_isp_scene_writer_callback(AvrIspCustomEvent event, void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
AvrIspApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, event);
|
||||
}
|
||||
|
||||
void avr_isp_scene_writer_on_enter(void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
AvrIspApp* app = context;
|
||||
avr_isp_writer_set_file_path(
|
||||
app->avr_isp_writer_view, furi_string_get_cstr(app->file_path), app->file_name_tmp);
|
||||
avr_isp_writer_view_set_callback(app->avr_isp_writer_view, avr_isp_scene_writer_callback, app);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewWriter);
|
||||
}
|
||||
|
||||
bool avr_isp_scene_writer_on_event(void* context, SceneManagerEvent event) {
|
||||
furi_assert(context);
|
||||
|
||||
AvrIspApp* app = context;
|
||||
bool consumed = false;
|
||||
if(event.type == SceneManagerEventTypeBack) {
|
||||
//do not handle exit on "Back"
|
||||
consumed = true;
|
||||
} else if(event.type == SceneManagerEventTypeCustom) {
|
||||
switch(event.event) {
|
||||
case AvrIspCustomEventSceneExitStartMenu:
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
app->scene_manager, AvrIspSceneStart);
|
||||
consumed = true;
|
||||
break;
|
||||
case AvrIspCustomEventSceneExit:
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
app->scene_manager, AvrIspSceneChipDetect);
|
||||
consumed = true;
|
||||
break;
|
||||
case AvrIspCustomEventSceneErrorVerification:
|
||||
app->error = AvrIspErrorVerification;
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
app->scene_manager, AvrIspSceneChipDetect);
|
||||
consumed = true;
|
||||
break;
|
||||
case AvrIspCustomEventSceneErrorWriting:
|
||||
app->error = AvrIspErrorWriting;
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
app->scene_manager, AvrIspSceneChipDetect);
|
||||
consumed = true;
|
||||
break;
|
||||
case AvrIspCustomEventSceneErrorWritingFuse:
|
||||
app->error = AvrIspErrorWritingFuse;
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
app->scene_manager, AvrIspSceneChipDetect);
|
||||
consumed = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if(event.type == SceneManagerEventTypeTick) {
|
||||
avr_isp_writer_update_progress(app->avr_isp_writer_view);
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void avr_isp_scene_writer_on_exit(void* context) {
|
||||
UNUSED(context);
|
||||
}
|
||||
@@ -1,213 +0,0 @@
|
||||
#include "avr_isp_view_chip_detect.h"
|
||||
#include <avr_isp_icons.h>
|
||||
#include <gui/elements.h>
|
||||
|
||||
#include "../helpers/avr_isp_worker_rw.h"
|
||||
|
||||
struct AvrIspChipDetectView {
|
||||
View* view;
|
||||
AvrIspWorkerRW* avr_isp_worker_rw;
|
||||
AvrIspChipDetectViewCallback callback;
|
||||
void* context;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint16_t idx;
|
||||
const char* name_chip;
|
||||
uint32_t flash_size;
|
||||
AvrIspChipDetectViewState state;
|
||||
} AvrIspChipDetectViewModel;
|
||||
|
||||
void avr_isp_chip_detect_view_set_callback(
|
||||
AvrIspChipDetectView* instance,
|
||||
AvrIspChipDetectViewCallback callback,
|
||||
void* context) {
|
||||
furi_assert(instance);
|
||||
furi_assert(callback);
|
||||
|
||||
instance->callback = callback;
|
||||
instance->context = context;
|
||||
}
|
||||
|
||||
void avr_isp_chip_detect_set_state(AvrIspChipDetectView* instance, AvrIspChipDetectViewState state) {
|
||||
furi_assert(instance);
|
||||
|
||||
with_view_model(
|
||||
instance->view, AvrIspChipDetectViewModel * model, { model->state = state; }, true);
|
||||
}
|
||||
|
||||
void avr_isp_chip_detect_view_draw(Canvas* canvas, AvrIspChipDetectViewModel* model) {
|
||||
canvas_clear(canvas);
|
||||
|
||||
char str_buf[64] = {0};
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
|
||||
switch(model->state) {
|
||||
case AvrIspChipDetectViewStateDetected:
|
||||
canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "AVR chip detected!");
|
||||
canvas_draw_icon(canvas, 29, 14, &I_chip_long_70x22);
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
snprintf(str_buf, sizeof(str_buf), "%ld Kb", model->flash_size / 1024);
|
||||
canvas_draw_str_aligned(canvas, 64, 25, AlignCenter, AlignCenter, str_buf);
|
||||
canvas_draw_str_aligned(canvas, 64, 45, AlignCenter, AlignCenter, model->name_chip);
|
||||
elements_button_right(canvas, "Next");
|
||||
break;
|
||||
case AvrIspChipDetectViewStateErrorOccured:
|
||||
canvas_draw_str_aligned(
|
||||
canvas, 64, 5, AlignCenter, AlignCenter, "Error occured, try again!");
|
||||
canvas_draw_icon(canvas, 29, 14, &I_chip_error_70x22);
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas, 64, 45, AlignCenter, AlignCenter, "Check the wiring and retry");
|
||||
break;
|
||||
case AvrIspChipDetectViewStateErrorVerification:
|
||||
canvas_draw_str_aligned(
|
||||
canvas, 64, 5, AlignCenter, AlignCenter, "Data verification failed");
|
||||
canvas_draw_icon(canvas, 29, 14, &I_chip_error_70x22);
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas, 64, 45, AlignCenter, AlignCenter, "Try to restart the process");
|
||||
break;
|
||||
|
||||
default:
|
||||
//AvrIspChipDetectViewStateNoDetect
|
||||
canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "AVR chip not found!");
|
||||
canvas_draw_icon(canvas, 29, 12, &I_chif_not_found_83x37);
|
||||
|
||||
break;
|
||||
}
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
elements_button_left(canvas, "Retry");
|
||||
}
|
||||
|
||||
bool avr_isp_chip_detect_view_input(InputEvent* event, void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
AvrIspChipDetectView* instance = context;
|
||||
|
||||
if(event->type == InputTypeShort) {
|
||||
if(event->key == InputKeyBack) {
|
||||
return false;
|
||||
} else if(event->key == InputKeyRight) {
|
||||
with_view_model(
|
||||
instance->view,
|
||||
AvrIspChipDetectViewModel * model,
|
||||
{
|
||||
if(model->state == AvrIspChipDetectViewStateDetected) {
|
||||
if(instance->callback)
|
||||
instance->callback(
|
||||
AvrIspCustomEventSceneChipDetectOk, instance->context);
|
||||
}
|
||||
},
|
||||
false);
|
||||
|
||||
} else if(event->key == InputKeyLeft) {
|
||||
bool detect_chip = false;
|
||||
with_view_model(
|
||||
instance->view,
|
||||
AvrIspChipDetectViewModel * model,
|
||||
{
|
||||
if(model->state != AvrIspChipDetectViewStateDetecting) {
|
||||
model->state = AvrIspChipDetectViewStateDetecting;
|
||||
detect_chip = true;
|
||||
}
|
||||
},
|
||||
false);
|
||||
if(detect_chip) avr_isp_worker_rw_detect_chip(instance->avr_isp_worker_rw);
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void avr_isp_chip_detect_detect_chip_callback(
|
||||
void* context,
|
||||
const char* name,
|
||||
bool detect_chip,
|
||||
uint32_t flash_size) {
|
||||
furi_assert(context);
|
||||
|
||||
AvrIspChipDetectView* instance = context;
|
||||
with_view_model(
|
||||
instance->view,
|
||||
AvrIspChipDetectViewModel * model,
|
||||
{
|
||||
model->name_chip = name;
|
||||
model->flash_size = flash_size;
|
||||
if(detect_chip) {
|
||||
model->state = AvrIspChipDetectViewStateDetected;
|
||||
} else {
|
||||
model->state = AvrIspChipDetectViewStateNoDetect;
|
||||
}
|
||||
},
|
||||
true);
|
||||
}
|
||||
void avr_isp_chip_detect_view_enter(void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
AvrIspChipDetectView* instance = context;
|
||||
bool detect_chip = false;
|
||||
with_view_model(
|
||||
instance->view,
|
||||
AvrIspChipDetectViewModel * model,
|
||||
{
|
||||
if(model->state == AvrIspChipDetectViewStateNoDetect ||
|
||||
model->state == AvrIspChipDetectViewStateDetected) {
|
||||
detect_chip = true;
|
||||
}
|
||||
},
|
||||
false);
|
||||
|
||||
//Start avr_isp_worker_rw
|
||||
instance->avr_isp_worker_rw = avr_isp_worker_rw_alloc(instance->context);
|
||||
|
||||
avr_isp_worker_rw_set_callback(
|
||||
instance->avr_isp_worker_rw, avr_isp_chip_detect_detect_chip_callback, instance);
|
||||
|
||||
if(detect_chip) avr_isp_worker_rw_detect_chip(instance->avr_isp_worker_rw);
|
||||
}
|
||||
|
||||
void avr_isp_chip_detect_view_exit(void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
AvrIspChipDetectView* instance = context;
|
||||
|
||||
avr_isp_worker_rw_set_callback(instance->avr_isp_worker_rw, NULL, NULL);
|
||||
avr_isp_worker_rw_free(instance->avr_isp_worker_rw);
|
||||
}
|
||||
|
||||
AvrIspChipDetectView* avr_isp_chip_detect_view_alloc() {
|
||||
AvrIspChipDetectView* instance = malloc(sizeof(AvrIspChipDetectView));
|
||||
|
||||
// View allocation and configuration
|
||||
instance->view = view_alloc();
|
||||
|
||||
view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(AvrIspChipDetectViewModel));
|
||||
view_set_context(instance->view, instance);
|
||||
view_set_draw_callback(instance->view, (ViewDrawCallback)avr_isp_chip_detect_view_draw);
|
||||
view_set_input_callback(instance->view, avr_isp_chip_detect_view_input);
|
||||
view_set_enter_callback(instance->view, avr_isp_chip_detect_view_enter);
|
||||
view_set_exit_callback(instance->view, avr_isp_chip_detect_view_exit);
|
||||
|
||||
with_view_model(
|
||||
instance->view,
|
||||
AvrIspChipDetectViewModel * model,
|
||||
{ model->state = AvrIspChipDetectViewStateNoDetect; },
|
||||
false);
|
||||
return instance;
|
||||
}
|
||||
|
||||
void avr_isp_chip_detect_view_free(AvrIspChipDetectView* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
view_free(instance->view);
|
||||
free(instance);
|
||||
}
|
||||
|
||||
View* avr_isp_chip_detect_view_get_view(AvrIspChipDetectView* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
return instance->view;
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
#include "../helpers/avr_isp_types.h"
|
||||
#include "../helpers/avr_isp_event.h"
|
||||
|
||||
typedef struct AvrIspChipDetectView AvrIspChipDetectView;
|
||||
|
||||
typedef void (*AvrIspChipDetectViewCallback)(AvrIspCustomEvent event, void* context);
|
||||
|
||||
typedef enum {
|
||||
AvrIspChipDetectViewStateNoDetect,
|
||||
AvrIspChipDetectViewStateDetecting,
|
||||
AvrIspChipDetectViewStateDetected,
|
||||
AvrIspChipDetectViewStateErrorOccured,
|
||||
AvrIspChipDetectViewStateErrorVerification,
|
||||
} AvrIspChipDetectViewState;
|
||||
|
||||
void avr_isp_chip_detect_view_set_callback(
|
||||
AvrIspChipDetectView* instance,
|
||||
AvrIspChipDetectViewCallback callback,
|
||||
void* context);
|
||||
|
||||
void avr_isp_chip_detect_set_state(AvrIspChipDetectView* instance, AvrIspChipDetectViewState state);
|
||||
|
||||
AvrIspChipDetectView* avr_isp_chip_detect_view_alloc();
|
||||
|
||||
void avr_isp_chip_detect_view_free(AvrIspChipDetectView* instance);
|
||||
|
||||
View* avr_isp_chip_detect_view_get_view(AvrIspChipDetectView* instance);
|
||||
|
||||
void avr_isp_chip_detect_view_exit(void* context);
|
||||
@@ -1,134 +0,0 @@
|
||||
#include "avr_isp_view_programmer.h"
|
||||
#include <avr_isp_icons.h>
|
||||
|
||||
#include "../helpers/avr_isp_worker.h"
|
||||
#include <gui/elements.h>
|
||||
|
||||
struct AvrIspProgrammerView {
|
||||
View* view;
|
||||
AvrIspWorker* worker;
|
||||
AvrIspProgrammerViewCallback callback;
|
||||
void* context;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
AvrIspProgrammerViewStatus status;
|
||||
} AvrIspProgrammerViewModel;
|
||||
|
||||
void avr_isp_programmer_view_set_callback(
|
||||
AvrIspProgrammerView* instance,
|
||||
AvrIspProgrammerViewCallback callback,
|
||||
void* context) {
|
||||
furi_assert(instance);
|
||||
furi_assert(callback);
|
||||
|
||||
instance->callback = callback;
|
||||
instance->context = context;
|
||||
}
|
||||
|
||||
void avr_isp_programmer_view_draw(Canvas* canvas, AvrIspProgrammerViewModel* model) {
|
||||
canvas_clear(canvas);
|
||||
|
||||
if(model->status == AvrIspProgrammerViewStatusUSBConnect) {
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_icon(canvas, 0, 0, &I_isp_active_128x53);
|
||||
elements_multiline_text(canvas, 45, 10, "ISP mode active");
|
||||
} else {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_icon(canvas, 51, 6, &I_link_waiting_77x56);
|
||||
elements_multiline_text(canvas, 0, 25, "Waiting for\nsoftware\nconnection");
|
||||
}
|
||||
}
|
||||
|
||||
bool avr_isp_programmer_view_input(InputEvent* event, void* context) {
|
||||
furi_assert(context);
|
||||
UNUSED(context);
|
||||
|
||||
if(event->key == InputKeyBack || event->type != InputTypeShort) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void avr_isp_programmer_usb_connect_callback(void* context, bool status_connect) {
|
||||
furi_assert(context);
|
||||
AvrIspProgrammerView* instance = context;
|
||||
|
||||
with_view_model(
|
||||
instance->view,
|
||||
AvrIspProgrammerViewModel * model,
|
||||
{
|
||||
if(status_connect) {
|
||||
model->status = AvrIspProgrammerViewStatusUSBConnect;
|
||||
} else {
|
||||
model->status = AvrIspProgrammerViewStatusNoUSBConnect;
|
||||
}
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
void avr_isp_programmer_view_enter(void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
AvrIspProgrammerView* instance = context;
|
||||
with_view_model(
|
||||
instance->view,
|
||||
AvrIspProgrammerViewModel * model,
|
||||
{ model->status = AvrIspProgrammerViewStatusNoUSBConnect; },
|
||||
true);
|
||||
|
||||
//Start worker
|
||||
instance->worker = avr_isp_worker_alloc(instance->context);
|
||||
|
||||
avr_isp_worker_set_callback(
|
||||
instance->worker, avr_isp_programmer_usb_connect_callback, instance);
|
||||
|
||||
avr_isp_worker_start(instance->worker);
|
||||
}
|
||||
|
||||
void avr_isp_programmer_view_exit(void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
AvrIspProgrammerView* instance = context;
|
||||
//Stop worker
|
||||
if(avr_isp_worker_is_running(instance->worker)) {
|
||||
avr_isp_worker_stop(instance->worker);
|
||||
}
|
||||
avr_isp_worker_set_callback(instance->worker, NULL, NULL);
|
||||
avr_isp_worker_free(instance->worker);
|
||||
}
|
||||
|
||||
AvrIspProgrammerView* avr_isp_programmer_view_alloc() {
|
||||
AvrIspProgrammerView* instance = malloc(sizeof(AvrIspProgrammerView));
|
||||
|
||||
// View allocation and configuration
|
||||
instance->view = view_alloc();
|
||||
|
||||
view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(AvrIspProgrammerViewModel));
|
||||
view_set_context(instance->view, instance);
|
||||
view_set_draw_callback(instance->view, (ViewDrawCallback)avr_isp_programmer_view_draw);
|
||||
view_set_input_callback(instance->view, avr_isp_programmer_view_input);
|
||||
view_set_enter_callback(instance->view, avr_isp_programmer_view_enter);
|
||||
view_set_exit_callback(instance->view, avr_isp_programmer_view_exit);
|
||||
|
||||
with_view_model(
|
||||
instance->view,
|
||||
AvrIspProgrammerViewModel * model,
|
||||
{ model->status = AvrIspProgrammerViewStatusNoUSBConnect; },
|
||||
false);
|
||||
return instance;
|
||||
}
|
||||
|
||||
void avr_isp_programmer_view_free(AvrIspProgrammerView* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
view_free(instance->view);
|
||||
free(instance);
|
||||
}
|
||||
|
||||
View* avr_isp_programmer_view_get_view(AvrIspProgrammerView* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
return instance->view;
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
#include "../helpers/avr_isp_types.h"
|
||||
#include "../helpers/avr_isp_event.h"
|
||||
|
||||
typedef struct AvrIspProgrammerView AvrIspProgrammerView;
|
||||
|
||||
typedef void (*AvrIspProgrammerViewCallback)(AvrIspCustomEvent event, void* context);
|
||||
|
||||
typedef enum {
|
||||
AvrIspProgrammerViewStatusNoUSBConnect,
|
||||
AvrIspProgrammerViewStatusUSBConnect,
|
||||
} AvrIspProgrammerViewStatus;
|
||||
|
||||
void avr_isp_programmer_view_set_callback(
|
||||
AvrIspProgrammerView* instance,
|
||||
AvrIspProgrammerViewCallback callback,
|
||||
void* context);
|
||||
|
||||
AvrIspProgrammerView* avr_isp_programmer_view_alloc();
|
||||
|
||||
void avr_isp_programmer_view_free(AvrIspProgrammerView* instance);
|
||||
|
||||
View* avr_isp_programmer_view_get_view(AvrIspProgrammerView* instance);
|
||||
|
||||
void avr_isp_programmer_view_exit(void* context);
|
||||
@@ -1,215 +0,0 @@
|
||||
#include "avr_isp_view_reader.h"
|
||||
#include <gui/elements.h>
|
||||
|
||||
#include "../helpers/avr_isp_worker_rw.h"
|
||||
|
||||
struct AvrIspReaderView {
|
||||
View* view;
|
||||
AvrIspWorkerRW* avr_isp_worker_rw;
|
||||
const char* file_path;
|
||||
const char* file_name;
|
||||
AvrIspReaderViewCallback callback;
|
||||
void* context;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
AvrIspReaderViewStatus status;
|
||||
float progress_flash;
|
||||
float progress_eeprom;
|
||||
} AvrIspReaderViewModel;
|
||||
|
||||
void avr_isp_reader_update_progress(AvrIspReaderView* instance) {
|
||||
with_view_model(
|
||||
instance->view,
|
||||
AvrIspReaderViewModel * model,
|
||||
{
|
||||
model->progress_flash =
|
||||
avr_isp_worker_rw_get_progress_flash(instance->avr_isp_worker_rw);
|
||||
model->progress_eeprom =
|
||||
avr_isp_worker_rw_get_progress_eeprom(instance->avr_isp_worker_rw);
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
void avr_isp_reader_view_set_callback(
|
||||
AvrIspReaderView* instance,
|
||||
AvrIspReaderViewCallback callback,
|
||||
void* context) {
|
||||
furi_assert(instance);
|
||||
furi_assert(callback);
|
||||
|
||||
instance->callback = callback;
|
||||
instance->context = context;
|
||||
}
|
||||
|
||||
void avr_isp_reader_set_file_path(
|
||||
AvrIspReaderView* instance,
|
||||
const char* file_path,
|
||||
const char* file_name) {
|
||||
furi_assert(instance);
|
||||
|
||||
instance->file_path = file_path;
|
||||
instance->file_name = file_name;
|
||||
}
|
||||
|
||||
void avr_isp_reader_view_draw(Canvas* canvas, AvrIspReaderViewModel* model) {
|
||||
canvas_clear(canvas);
|
||||
char str_buf[64] = {0};
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
switch(model->status) {
|
||||
case AvrIspReaderViewStatusIDLE:
|
||||
canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Press start to dump");
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
elements_button_center(canvas, "Start");
|
||||
break;
|
||||
case AvrIspReaderViewStatusReading:
|
||||
canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Reading dump");
|
||||
break;
|
||||
case AvrIspReaderViewStatusVerification:
|
||||
canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Verifyng dump");
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str(canvas, 0, 27, "Flash");
|
||||
snprintf(str_buf, sizeof(str_buf), "%d%%", (uint8_t)(model->progress_flash * 100));
|
||||
elements_progress_bar_with_text(canvas, 44, 17, 84, model->progress_flash, str_buf);
|
||||
canvas_draw_str(canvas, 0, 43, "EEPROM");
|
||||
snprintf(str_buf, sizeof(str_buf), "%d%%", (uint8_t)(model->progress_eeprom * 100));
|
||||
elements_progress_bar_with_text(canvas, 44, 34, 84, model->progress_eeprom, str_buf);
|
||||
}
|
||||
|
||||
bool avr_isp_reader_view_input(InputEvent* event, void* context) {
|
||||
furi_assert(context);
|
||||
AvrIspReaderView* instance = context;
|
||||
|
||||
bool ret = true;
|
||||
if(event->key == InputKeyBack && event->type == InputTypeShort) {
|
||||
with_view_model(
|
||||
instance->view,
|
||||
AvrIspReaderViewModel * model,
|
||||
{
|
||||
if(model->status == AvrIspReaderViewStatusIDLE) {
|
||||
if(instance->callback)
|
||||
instance->callback(AvrIspCustomEventSceneExit, instance->context);
|
||||
ret = false;
|
||||
}
|
||||
},
|
||||
false);
|
||||
} else if(event->key == InputKeyOk && event->type == InputTypeShort) {
|
||||
with_view_model(
|
||||
instance->view,
|
||||
AvrIspReaderViewModel * model,
|
||||
{
|
||||
if(model->status == AvrIspReaderViewStatusIDLE) {
|
||||
model->status = AvrIspReaderViewStatusReading;
|
||||
avr_isp_worker_rw_read_dump_start(
|
||||
instance->avr_isp_worker_rw, instance->file_path, instance->file_name);
|
||||
}
|
||||
},
|
||||
false);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void avr_isp_reader_callback_status(void* context, AvrIspWorkerRWStatus status) {
|
||||
furi_assert(context);
|
||||
AvrIspReaderView* instance = context;
|
||||
|
||||
with_view_model(
|
||||
instance->view,
|
||||
AvrIspReaderViewModel * model,
|
||||
{
|
||||
switch(status) {
|
||||
case AvrIspWorkerRWStatusEndReading:
|
||||
model->status = AvrIspReaderViewStatusVerification;
|
||||
avr_isp_worker_rw_verification_start(
|
||||
instance->avr_isp_worker_rw, instance->file_path, instance->file_name);
|
||||
model->status = AvrIspReaderViewStatusVerification;
|
||||
break;
|
||||
case AvrIspWorkerRWStatusEndVerification:
|
||||
if(instance->callback)
|
||||
instance->callback(AvrIspCustomEventSceneReadingOk, instance->context);
|
||||
break;
|
||||
case AvrIspWorkerRWStatusErrorVerification:
|
||||
if(instance->callback)
|
||||
instance->callback(AvrIspCustomEventSceneErrorVerification, instance->context);
|
||||
break;
|
||||
|
||||
default:
|
||||
//AvrIspWorkerRWStatusErrorReading;
|
||||
if(instance->callback)
|
||||
instance->callback(AvrIspCustomEventSceneErrorReading, instance->context);
|
||||
break;
|
||||
}
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
void avr_isp_reader_view_enter(void* context) {
|
||||
furi_assert(context);
|
||||
AvrIspReaderView* instance = context;
|
||||
|
||||
with_view_model(
|
||||
instance->view,
|
||||
AvrIspReaderViewModel * model,
|
||||
{
|
||||
model->status = AvrIspReaderViewStatusIDLE;
|
||||
model->progress_flash = 0.0f;
|
||||
model->progress_eeprom = 0.0f;
|
||||
},
|
||||
true);
|
||||
|
||||
//Start avr_isp_worker_rw
|
||||
instance->avr_isp_worker_rw = avr_isp_worker_rw_alloc(instance->context);
|
||||
|
||||
avr_isp_worker_rw_set_callback_status(
|
||||
instance->avr_isp_worker_rw, avr_isp_reader_callback_status, instance);
|
||||
|
||||
avr_isp_worker_rw_start(instance->avr_isp_worker_rw);
|
||||
}
|
||||
|
||||
void avr_isp_reader_view_exit(void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
AvrIspReaderView* instance = context;
|
||||
//Stop avr_isp_worker_rw
|
||||
if(avr_isp_worker_rw_is_running(instance->avr_isp_worker_rw)) {
|
||||
avr_isp_worker_rw_stop(instance->avr_isp_worker_rw);
|
||||
}
|
||||
|
||||
avr_isp_worker_rw_free(instance->avr_isp_worker_rw);
|
||||
}
|
||||
|
||||
AvrIspReaderView* avr_isp_reader_view_alloc() {
|
||||
AvrIspReaderView* instance = malloc(sizeof(AvrIspReaderView));
|
||||
|
||||
// View allocation and configuration
|
||||
instance->view = view_alloc();
|
||||
|
||||
view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(AvrIspReaderViewModel));
|
||||
view_set_context(instance->view, instance);
|
||||
view_set_draw_callback(instance->view, (ViewDrawCallback)avr_isp_reader_view_draw);
|
||||
view_set_input_callback(instance->view, avr_isp_reader_view_input);
|
||||
view_set_enter_callback(instance->view, avr_isp_reader_view_enter);
|
||||
view_set_exit_callback(instance->view, avr_isp_reader_view_exit);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
void avr_isp_reader_view_free(AvrIspReaderView* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
view_free(instance->view);
|
||||
free(instance);
|
||||
}
|
||||
|
||||
View* avr_isp_reader_view_get_view(AvrIspReaderView* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
return instance->view;
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
#include "../helpers/avr_isp_types.h"
|
||||
#include "../helpers/avr_isp_event.h"
|
||||
|
||||
typedef struct AvrIspReaderView AvrIspReaderView;
|
||||
|
||||
typedef void (*AvrIspReaderViewCallback)(AvrIspCustomEvent event, void* context);
|
||||
|
||||
typedef enum {
|
||||
AvrIspReaderViewStatusIDLE,
|
||||
AvrIspReaderViewStatusReading,
|
||||
AvrIspReaderViewStatusVerification,
|
||||
} AvrIspReaderViewStatus;
|
||||
|
||||
void avr_isp_reader_update_progress(AvrIspReaderView* instance);
|
||||
|
||||
void avr_isp_reader_set_file_path(
|
||||
AvrIspReaderView* instance,
|
||||
const char* file_path,
|
||||
const char* file_name);
|
||||
|
||||
void avr_isp_reader_view_set_callback(
|
||||
AvrIspReaderView* instance,
|
||||
AvrIspReaderViewCallback callback,
|
||||
void* context);
|
||||
|
||||
AvrIspReaderView* avr_isp_reader_view_alloc();
|
||||
|
||||
void avr_isp_reader_view_free(AvrIspReaderView* instance);
|
||||
|
||||
View* avr_isp_reader_view_get_view(AvrIspReaderView* instance);
|
||||
|
||||
void avr_isp_reader_view_exit(void* context);
|
||||
@@ -1,268 +0,0 @@
|
||||
#include "avr_isp_view_writer.h"
|
||||
#include <gui/elements.h>
|
||||
|
||||
#include "../helpers/avr_isp_worker_rw.h"
|
||||
#include <float_tools.h>
|
||||
|
||||
struct AvrIspWriterView {
|
||||
View* view;
|
||||
AvrIspWorkerRW* avr_isp_worker_rw;
|
||||
const char* file_path;
|
||||
const char* file_name;
|
||||
AvrIspWriterViewCallback callback;
|
||||
void* context;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
AvrIspWriterViewStatus status;
|
||||
float progress_flash;
|
||||
float progress_eeprom;
|
||||
} AvrIspWriterViewModel;
|
||||
|
||||
void avr_isp_writer_update_progress(AvrIspWriterView* instance) {
|
||||
with_view_model(
|
||||
instance->view,
|
||||
AvrIspWriterViewModel * model,
|
||||
{
|
||||
model->progress_flash =
|
||||
avr_isp_worker_rw_get_progress_flash(instance->avr_isp_worker_rw);
|
||||
model->progress_eeprom =
|
||||
avr_isp_worker_rw_get_progress_eeprom(instance->avr_isp_worker_rw);
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
void avr_isp_writer_view_set_callback(
|
||||
AvrIspWriterView* instance,
|
||||
AvrIspWriterViewCallback callback,
|
||||
void* context) {
|
||||
furi_assert(instance);
|
||||
furi_assert(callback);
|
||||
|
||||
instance->callback = callback;
|
||||
instance->context = context;
|
||||
}
|
||||
|
||||
void avr_isp_writer_set_file_path(
|
||||
AvrIspWriterView* instance,
|
||||
const char* file_path,
|
||||
const char* file_name) {
|
||||
furi_assert(instance);
|
||||
|
||||
instance->file_path = file_path;
|
||||
instance->file_name = file_name;
|
||||
}
|
||||
|
||||
void avr_isp_writer_view_draw(Canvas* canvas, AvrIspWriterViewModel* model) {
|
||||
canvas_clear(canvas);
|
||||
char str_flash[32] = {0};
|
||||
char str_eeprom[32] = {0};
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
|
||||
switch(model->status) {
|
||||
case AvrIspWriterViewStatusIDLE:
|
||||
canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Press start to write");
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
elements_button_center(canvas, "Start");
|
||||
snprintf(str_flash, sizeof(str_flash), "%d%%", (uint8_t)(model->progress_flash * 100));
|
||||
snprintf(str_eeprom, sizeof(str_eeprom), "%d%%", (uint8_t)(model->progress_eeprom * 100));
|
||||
break;
|
||||
case AvrIspWriterViewStatusWriting:
|
||||
if(float_is_equal(model->progress_flash, 0.f)) {
|
||||
canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Verifying firmware");
|
||||
snprintf(str_flash, sizeof(str_flash), "***");
|
||||
snprintf(str_eeprom, sizeof(str_eeprom), "***");
|
||||
} else {
|
||||
canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Writing dump");
|
||||
snprintf(str_flash, sizeof(str_flash), "%d%%", (uint8_t)(model->progress_flash * 100));
|
||||
snprintf(
|
||||
str_eeprom, sizeof(str_eeprom), "%d%%", (uint8_t)(model->progress_eeprom * 100));
|
||||
}
|
||||
break;
|
||||
case AvrIspWriterViewStatusVerification:
|
||||
canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Verifying dump");
|
||||
snprintf(str_flash, sizeof(str_flash), "%d%%", (uint8_t)(model->progress_flash * 100));
|
||||
snprintf(str_eeprom, sizeof(str_eeprom), "%d%%", (uint8_t)(model->progress_eeprom * 100));
|
||||
break;
|
||||
case AvrIspWriterViewStatusWritingFuse:
|
||||
canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Writing fuse");
|
||||
snprintf(str_flash, sizeof(str_flash), "%d%%", (uint8_t)(model->progress_flash * 100));
|
||||
snprintf(str_eeprom, sizeof(str_eeprom), "%d%%", (uint8_t)(model->progress_eeprom * 100));
|
||||
break;
|
||||
case AvrIspWriterViewStatusWritingFuseOk:
|
||||
canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Done!");
|
||||
snprintf(str_flash, sizeof(str_flash), "%d%%", (uint8_t)(model->progress_flash * 100));
|
||||
snprintf(str_eeprom, sizeof(str_eeprom), "%d%%", (uint8_t)(model->progress_eeprom * 100));
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
elements_button_center(canvas, "Reflash");
|
||||
elements_button_right(canvas, "Exit");
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str(canvas, 0, 27, "Flash");
|
||||
// snprintf(str_buf, sizeof(str_buf), "%d%%", (uint8_t)(model->progress_flash * 100));
|
||||
elements_progress_bar_with_text(canvas, 44, 17, 84, model->progress_flash, str_flash);
|
||||
canvas_draw_str(canvas, 0, 43, "EEPROM");
|
||||
// snprintf(str_buf, sizeof(str_buf), "%d%%", (uint8_t)(model->progress_eeprom * 100));
|
||||
elements_progress_bar_with_text(canvas, 44, 34, 84, model->progress_eeprom, str_eeprom);
|
||||
}
|
||||
|
||||
bool avr_isp_writer_view_input(InputEvent* event, void* context) {
|
||||
furi_assert(context);
|
||||
AvrIspWriterView* instance = context;
|
||||
|
||||
bool ret = true;
|
||||
if(event->key == InputKeyBack && event->type == InputTypeShort) {
|
||||
with_view_model(
|
||||
instance->view,
|
||||
AvrIspWriterViewModel * model,
|
||||
{
|
||||
if((model->status == AvrIspWriterViewStatusIDLE) ||
|
||||
(model->status == AvrIspWriterViewStatusWritingFuseOk)) {
|
||||
if(instance->callback)
|
||||
instance->callback(AvrIspCustomEventSceneExit, instance->context);
|
||||
ret = false;
|
||||
}
|
||||
},
|
||||
false);
|
||||
} else if(event->key == InputKeyOk && event->type == InputTypeShort) {
|
||||
with_view_model(
|
||||
instance->view,
|
||||
AvrIspWriterViewModel * model,
|
||||
{
|
||||
if((model->status == AvrIspWriterViewStatusIDLE) ||
|
||||
(model->status == AvrIspWriterViewStatusWritingFuseOk)) {
|
||||
model->status = AvrIspWriterViewStatusWriting;
|
||||
|
||||
avr_isp_worker_rw_write_dump_start(
|
||||
instance->avr_isp_worker_rw, instance->file_path, instance->file_name);
|
||||
}
|
||||
},
|
||||
false);
|
||||
} else if(event->key == InputKeyRight && event->type == InputTypeShort) {
|
||||
with_view_model(
|
||||
instance->view,
|
||||
AvrIspWriterViewModel * model,
|
||||
{
|
||||
if((model->status == AvrIspWriterViewStatusIDLE) ||
|
||||
(model->status == AvrIspWriterViewStatusWritingFuseOk)) {
|
||||
if(instance->callback)
|
||||
instance->callback(AvrIspCustomEventSceneExitStartMenu, instance->context);
|
||||
ret = false;
|
||||
}
|
||||
},
|
||||
false);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void avr_isp_writer_callback_status(void* context, AvrIspWorkerRWStatus status) {
|
||||
furi_assert(context);
|
||||
|
||||
AvrIspWriterView* instance = context;
|
||||
with_view_model(
|
||||
instance->view,
|
||||
AvrIspWriterViewModel * model,
|
||||
{
|
||||
switch(status) {
|
||||
case AvrIspWorkerRWStatusEndWriting:
|
||||
model->status = AvrIspWriterViewStatusVerification;
|
||||
avr_isp_worker_rw_verification_start(
|
||||
instance->avr_isp_worker_rw, instance->file_path, instance->file_name);
|
||||
model->status = AvrIspWriterViewStatusVerification;
|
||||
break;
|
||||
case AvrIspWorkerRWStatusErrorVerification:
|
||||
if(instance->callback)
|
||||
instance->callback(AvrIspCustomEventSceneErrorVerification, instance->context);
|
||||
break;
|
||||
case AvrIspWorkerRWStatusEndVerification:
|
||||
avr_isp_worker_rw_write_fuse_start(
|
||||
instance->avr_isp_worker_rw, instance->file_path, instance->file_name);
|
||||
model->status = AvrIspWriterViewStatusWritingFuse;
|
||||
break;
|
||||
case AvrIspWorkerRWStatusErrorWritingFuse:
|
||||
if(instance->callback)
|
||||
instance->callback(AvrIspCustomEventSceneErrorWritingFuse, instance->context);
|
||||
break;
|
||||
case AvrIspWorkerRWStatusEndWritingFuse:
|
||||
model->status = AvrIspWriterViewStatusWritingFuseOk;
|
||||
break;
|
||||
|
||||
default:
|
||||
//AvrIspWorkerRWStatusErrorWriting;
|
||||
if(instance->callback)
|
||||
instance->callback(AvrIspCustomEventSceneErrorWriting, instance->context);
|
||||
break;
|
||||
}
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
void avr_isp_writer_view_enter(void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
AvrIspWriterView* instance = context;
|
||||
with_view_model(
|
||||
instance->view,
|
||||
AvrIspWriterViewModel * model,
|
||||
{
|
||||
model->status = AvrIspWriterViewStatusIDLE;
|
||||
model->progress_flash = 0.0f;
|
||||
model->progress_eeprom = 0.0f;
|
||||
},
|
||||
true);
|
||||
|
||||
//Start avr_isp_worker_rw
|
||||
instance->avr_isp_worker_rw = avr_isp_worker_rw_alloc(instance->context);
|
||||
|
||||
avr_isp_worker_rw_set_callback_status(
|
||||
instance->avr_isp_worker_rw, avr_isp_writer_callback_status, instance);
|
||||
|
||||
avr_isp_worker_rw_start(instance->avr_isp_worker_rw);
|
||||
}
|
||||
|
||||
void avr_isp_writer_view_exit(void* context) {
|
||||
furi_assert(context);
|
||||
AvrIspWriterView* instance = context;
|
||||
|
||||
//Stop avr_isp_worker_rw
|
||||
if(avr_isp_worker_rw_is_running(instance->avr_isp_worker_rw)) {
|
||||
avr_isp_worker_rw_stop(instance->avr_isp_worker_rw);
|
||||
}
|
||||
|
||||
avr_isp_worker_rw_free(instance->avr_isp_worker_rw);
|
||||
}
|
||||
|
||||
AvrIspWriterView* avr_isp_writer_view_alloc() {
|
||||
AvrIspWriterView* instance = malloc(sizeof(AvrIspWriterView));
|
||||
|
||||
// View allocation and configuration
|
||||
instance->view = view_alloc();
|
||||
|
||||
view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(AvrIspWriterViewModel));
|
||||
view_set_context(instance->view, instance);
|
||||
view_set_draw_callback(instance->view, (ViewDrawCallback)avr_isp_writer_view_draw);
|
||||
view_set_input_callback(instance->view, avr_isp_writer_view_input);
|
||||
view_set_enter_callback(instance->view, avr_isp_writer_view_enter);
|
||||
view_set_exit_callback(instance->view, avr_isp_writer_view_exit);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
void avr_isp_writer_view_free(AvrIspWriterView* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
view_free(instance->view);
|
||||
free(instance);
|
||||
}
|
||||
|
||||
View* avr_isp_writer_view_get_view(AvrIspWriterView* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
return instance->view;
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
#include "../helpers/avr_isp_types.h"
|
||||
#include "../helpers/avr_isp_event.h"
|
||||
|
||||
typedef struct AvrIspWriterView AvrIspWriterView;
|
||||
|
||||
typedef void (*AvrIspWriterViewCallback)(AvrIspCustomEvent event, void* context);
|
||||
|
||||
typedef enum {
|
||||
AvrIspWriterViewStatusIDLE,
|
||||
AvrIspWriterViewStatusWriting,
|
||||
AvrIspWriterViewStatusVerification,
|
||||
AvrIspWriterViewStatusWritingFuse,
|
||||
AvrIspWriterViewStatusWritingFuseOk,
|
||||
} AvrIspWriterViewStatus;
|
||||
|
||||
void avr_isp_writer_update_progress(AvrIspWriterView* instance);
|
||||
|
||||
void avr_isp_writer_set_file_path(
|
||||
AvrIspWriterView* instance,
|
||||
const char* file_path,
|
||||
const char* file_name);
|
||||
|
||||
void avr_isp_writer_view_set_callback(
|
||||
AvrIspWriterView* instance,
|
||||
AvrIspWriterViewCallback callback,
|
||||
void* context);
|
||||
|
||||
AvrIspWriterView* avr_isp_writer_view_alloc();
|
||||
|
||||
void avr_isp_writer_view_free(AvrIspWriterView* instance);
|
||||
|
||||
View* avr_isp_writer_view_get_view(AvrIspWriterView* instance);
|
||||
|
||||
void avr_isp_writer_view_exit(void* context);
|
||||
16
applications/external/bad_bt/application.fam
vendored
@@ -1,16 +0,0 @@
|
||||
App(
|
||||
appid="bad_bt",
|
||||
name="Bad BT",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="bad_bt_app",
|
||||
requires=[
|
||||
"gui",
|
||||
"dialogs",
|
||||
],
|
||||
stack_size=2 * 1024,
|
||||
order=70,
|
||||
fap_libs=["assets"],
|
||||
fap_category="Bluetooth",
|
||||
fap_icon="images/badbt_10px.png",
|
||||
fap_icon_assets="images",
|
||||
)
|
||||
333
applications/external/bad_bt/bad_bt_app.c
vendored
@@ -1,333 +0,0 @@
|
||||
#include "bad_bt_app.h"
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <storage/storage.h>
|
||||
#include <lib/toolbox/path.h>
|
||||
#include <lib/flipper_format/flipper_format.h>
|
||||
|
||||
#include <bt/bt_service/bt_i.h>
|
||||
#include <bt/bt_service/bt.h>
|
||||
|
||||
#define BAD_BT_SETTINGS_FILE_NAME ".badbt.settings"
|
||||
#define BAD_BT_APP_PATH_BOUND_KEYS_FOLDER EXT_PATH("badbt")
|
||||
#define BAD_BT_APP_PATH_BOUND_KEYS_FILE BAD_BT_APP_PATH_BOUND_KEYS_FOLDER "/.badbt.keys"
|
||||
|
||||
#define BAD_BT_SETTINGS_PATH BAD_BT_APP_BASE_CONFIG_FOLDER "/" BAD_BT_SETTINGS_FILE_NAME
|
||||
|
||||
static bool bad_bt_app_custom_event_callback(void* context, uint32_t event) {
|
||||
furi_assert(context);
|
||||
BadBtApp* app = context;
|
||||
return scene_manager_handle_custom_event(app->scene_manager, event);
|
||||
}
|
||||
|
||||
static bool bad_bt_app_back_event_callback(void* context) {
|
||||
furi_assert(context);
|
||||
BadBtApp* app = context;
|
||||
return scene_manager_handle_back_event(app->scene_manager);
|
||||
}
|
||||
|
||||
static void bad_bt_app_tick_event_callback(void* context) {
|
||||
furi_assert(context);
|
||||
BadBtApp* app = context;
|
||||
scene_manager_handle_tick_event(app->scene_manager);
|
||||
}
|
||||
|
||||
static void bad_bt_load_settings(BadBtApp* app) {
|
||||
furi_string_reset(app->keyboard_layout);
|
||||
strcpy(app->config.bt_name, "");
|
||||
memcpy(
|
||||
app->config.bt_mac,
|
||||
furi_hal_bt_get_profile_mac_addr(FuriHalBtProfileHidKeyboard),
|
||||
BAD_BT_MAC_ADDRESS_LEN);
|
||||
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
FlipperFormat* file = flipper_format_file_alloc(storage);
|
||||
if(flipper_format_file_open_existing(file, BAD_BT_SETTINGS_PATH)) {
|
||||
FuriString* tmp_str = furi_string_alloc();
|
||||
if(!flipper_format_read_string(file, "Keyboard_Layout", app->keyboard_layout)) {
|
||||
furi_string_reset(app->keyboard_layout);
|
||||
}
|
||||
if(!flipper_format_read_bool(file, "BT_Remember", &(app->bt_remember), 1)) {
|
||||
app->bt_remember = false;
|
||||
}
|
||||
if(flipper_format_read_string(file, "Bt_Name", tmp_str) && !furi_string_empty(tmp_str)) {
|
||||
strcpy(app->config.bt_name, furi_string_get_cstr(tmp_str));
|
||||
} else {
|
||||
strcpy(app->config.bt_name, "");
|
||||
}
|
||||
if(!flipper_format_read_hex(
|
||||
file, "Bt_Mac", (uint8_t*)&app->config.bt_mac, BAD_BT_MAC_ADDRESS_LEN)) {
|
||||
memcpy(
|
||||
app->config.bt_mac,
|
||||
furi_hal_bt_get_profile_mac_addr(FuriHalBtProfileHidKeyboard),
|
||||
BAD_BT_MAC_ADDRESS_LEN);
|
||||
}
|
||||
furi_string_free(tmp_str);
|
||||
flipper_format_file_close(file);
|
||||
}
|
||||
flipper_format_free(file);
|
||||
|
||||
if(!furi_string_empty(app->keyboard_layout)) {
|
||||
FileInfo layout_file_info;
|
||||
FS_Error file_check_err = storage_common_stat(
|
||||
storage, furi_string_get_cstr(app->keyboard_layout), &layout_file_info);
|
||||
if(file_check_err != FSE_OK) {
|
||||
furi_string_reset(app->keyboard_layout);
|
||||
return;
|
||||
}
|
||||
if(layout_file_info.size != 256) {
|
||||
furi_string_reset(app->keyboard_layout);
|
||||
}
|
||||
}
|
||||
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
}
|
||||
|
||||
static void bad_bt_save_settings(BadBtApp* app) {
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
FlipperFormat* file = flipper_format_file_alloc(storage);
|
||||
if(flipper_format_file_open_always(file, BAD_BT_SETTINGS_PATH)) {
|
||||
flipper_format_write_string(file, "Keyboard_Layout", app->keyboard_layout);
|
||||
flipper_format_write_bool(file, "BT_Remember", &(app->bt_remember), 1);
|
||||
flipper_format_write_string_cstr(file, "Bt_Name", app->config.bt_name);
|
||||
flipper_format_write_hex(
|
||||
file, "Bt_Mac", (uint8_t*)&app->config.bt_mac, BAD_BT_MAC_ADDRESS_LEN);
|
||||
flipper_format_file_close(file);
|
||||
}
|
||||
flipper_format_free(file);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
}
|
||||
|
||||
void bad_bt_reload_worker(BadBtApp* app) {
|
||||
bad_bt_script_close(app->bad_bt_script);
|
||||
app->bad_bt_script = bad_bt_script_open(app->file_path, app->bt, app);
|
||||
bad_bt_script_set_keyboard_layout(app->bad_bt_script, app->keyboard_layout);
|
||||
}
|
||||
|
||||
void bad_kb_config_refresh_menu(BadBtApp* app) {
|
||||
scene_manager_next_scene(app->scene_manager, BadBtSceneConfig);
|
||||
scene_manager_previous_scene(app->scene_manager);
|
||||
}
|
||||
|
||||
int32_t bad_bt_config_switch_mode(BadBtApp* app) {
|
||||
bad_bt_reload_worker(app);
|
||||
furi_hal_bt_start_advertising();
|
||||
bad_kb_config_refresh_menu(app);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bad_bt_config_switch_remember_mode(BadBtApp* app) {
|
||||
if(app->bt_remember) {
|
||||
furi_hal_bt_set_profile_pairing_method(
|
||||
FuriHalBtProfileHidKeyboard, GapPairingPinCodeVerifyYesNo);
|
||||
bt_set_profile_mac_address(app->bt, (uint8_t*)&BAD_BT_BOUND_MAC_ADDRESS);
|
||||
bt_enable_peer_key_update(app->bt);
|
||||
} else {
|
||||
furi_hal_bt_set_profile_pairing_method(FuriHalBtProfileHidKeyboard, GapPairingNone);
|
||||
bt_set_profile_mac_address(app->bt, app->config.bt_mac);
|
||||
bt_disable_peer_key_update(app->bt);
|
||||
}
|
||||
bad_bt_reload_worker(app);
|
||||
}
|
||||
|
||||
int32_t bad_bt_connection_init(BadBtApp* app) {
|
||||
// Set original name and mac address in prev config
|
||||
strcpy(
|
||||
app->prev_config.bt_name, furi_hal_bt_get_profile_adv_name(FuriHalBtProfileHidKeyboard));
|
||||
|
||||
memcpy(app->prev_config.bt_mac, furi_hal_version_get_ble_mac(), BAD_BT_MAC_ADDRESS_LEN);
|
||||
|
||||
bt_timeout = bt_hid_delays[LevelRssi39_0];
|
||||
bt_disconnect(app->bt);
|
||||
// Wait 2nd core to update nvm storage
|
||||
furi_delay_ms(200);
|
||||
bt_keys_storage_set_storage_path(app->bt, BAD_BT_APP_PATH_BOUND_KEYS_FILE);
|
||||
if(strcmp(app->config.bt_name, "") != 0) {
|
||||
furi_hal_bt_set_profile_adv_name(FuriHalBtProfileHidKeyboard, app->config.bt_name);
|
||||
}
|
||||
if(app->bt_remember) {
|
||||
furi_hal_bt_set_profile_mac_addr(
|
||||
FuriHalBtProfileHidKeyboard, (uint8_t*)&BAD_BT_BOUND_MAC_ADDRESS);
|
||||
furi_hal_bt_set_profile_pairing_method(
|
||||
FuriHalBtProfileHidKeyboard, GapPairingPinCodeVerifyYesNo);
|
||||
} else {
|
||||
if(memcmp(
|
||||
app->config.bt_mac, (uint8_t*)&BAD_BT_EMPTY_MAC_ADDRESS, BAD_BT_MAC_ADDRESS_LEN) !=
|
||||
0) {
|
||||
furi_hal_bt_set_profile_mac_addr(FuriHalBtProfileHidKeyboard, app->config.bt_mac);
|
||||
}
|
||||
furi_hal_bt_set_profile_pairing_method(FuriHalBtProfileHidKeyboard, GapPairingNone);
|
||||
}
|
||||
bt_set_profile(app->bt, BtProfileHidKeyboard);
|
||||
if(strcmp(app->config.bt_name, "") == 0) {
|
||||
strcpy(app->config.bt_name, furi_hal_bt_get_profile_adv_name(FuriHalBtProfileHidKeyboard));
|
||||
}
|
||||
if(memcmp(app->config.bt_mac, (uint8_t*)&BAD_BT_EMPTY_MAC_ADDRESS, BAD_BT_MAC_ADDRESS_LEN) ==
|
||||
0) {
|
||||
memcpy(
|
||||
app->config.bt_mac,
|
||||
furi_hal_bt_get_profile_mac_addr(FuriHalBtProfileHidKeyboard),
|
||||
BAD_BT_MAC_ADDRESS_LEN);
|
||||
}
|
||||
|
||||
furi_hal_bt_start_advertising();
|
||||
if(app->bt_remember) {
|
||||
bt_enable_peer_key_update(app->bt);
|
||||
} else {
|
||||
bt_disable_peer_key_update(app->bt);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bad_bt_connection_deinit(BadBtApp* app) {
|
||||
bt_disconnect(app->bt);
|
||||
// Wait 2nd core to update nvm storage
|
||||
furi_delay_ms(200);
|
||||
bt_keys_storage_set_default_path(app->bt);
|
||||
furi_hal_bt_set_profile_adv_name(FuriHalBtProfileHidKeyboard, app->prev_config.bt_name);
|
||||
furi_hal_bt_set_profile_mac_addr(FuriHalBtProfileHidKeyboard, app->prev_config.bt_mac);
|
||||
furi_hal_bt_set_profile_pairing_method(
|
||||
FuriHalBtProfileHidKeyboard, GapPairingPinCodeVerifyYesNo);
|
||||
bt_set_profile(app->bt, BtProfileSerial);
|
||||
bt_enable_peer_key_update(app->bt);
|
||||
}
|
||||
|
||||
BadBtApp* bad_bt_app_alloc(char* arg) {
|
||||
BadBtApp* app = malloc(sizeof(BadBtApp));
|
||||
|
||||
app->bad_bt_script = NULL;
|
||||
|
||||
app->file_path = furi_string_alloc();
|
||||
app->keyboard_layout = furi_string_alloc();
|
||||
if(arg && strlen(arg)) {
|
||||
furi_string_set(app->file_path, arg);
|
||||
}
|
||||
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
storage_simply_mkdir(storage, BAD_BT_APP_BASE_CONFIG_FOLDER);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
|
||||
bad_bt_load_settings(app);
|
||||
|
||||
app->gui = furi_record_open(RECORD_GUI);
|
||||
app->notifications = furi_record_open(RECORD_NOTIFICATION);
|
||||
app->dialogs = furi_record_open(RECORD_DIALOGS);
|
||||
|
||||
app->view_dispatcher = view_dispatcher_alloc();
|
||||
view_dispatcher_enable_queue(app->view_dispatcher);
|
||||
|
||||
app->scene_manager = scene_manager_alloc(&bad_bt_scene_handlers, app);
|
||||
|
||||
view_dispatcher_set_event_callback_context(app->view_dispatcher, app);
|
||||
view_dispatcher_set_tick_event_callback(
|
||||
app->view_dispatcher, bad_bt_app_tick_event_callback, 500);
|
||||
view_dispatcher_set_custom_event_callback(
|
||||
app->view_dispatcher, bad_bt_app_custom_event_callback);
|
||||
view_dispatcher_set_navigation_event_callback(
|
||||
app->view_dispatcher, bad_bt_app_back_event_callback);
|
||||
|
||||
Bt* bt = furi_record_open(RECORD_BT);
|
||||
app->bt = bt;
|
||||
app->bt->suppress_pin_screen = true;
|
||||
|
||||
// Custom Widget
|
||||
app->widget = widget_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, BadBtAppViewError, widget_get_view(app->widget));
|
||||
|
||||
app->var_item_list = variable_item_list_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, BadBtAppViewConfig, variable_item_list_get_view(app->var_item_list));
|
||||
|
||||
app->bad_bt_view = bad_bt_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, BadBtAppViewWork, bad_bt_get_view(app->bad_bt_view));
|
||||
|
||||
app->text_input = text_input_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, BadBtAppViewConfigName, text_input_get_view(app->text_input));
|
||||
|
||||
app->byte_input = byte_input_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, BadBtAppViewConfigMac, byte_input_get_view(app->byte_input));
|
||||
|
||||
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
|
||||
|
||||
app->conn_init_thread = furi_thread_alloc_ex(
|
||||
"BadBtConnInit", 1024, (FuriThreadCallback)bad_bt_connection_init, app);
|
||||
furi_thread_start(app->conn_init_thread);
|
||||
if(!furi_string_empty(app->file_path)) {
|
||||
app->bad_bt_script = bad_bt_script_open(app->file_path, app->bt, app);
|
||||
bad_bt_script_set_keyboard_layout(app->bad_bt_script, app->keyboard_layout);
|
||||
scene_manager_next_scene(app->scene_manager, BadBtSceneWork);
|
||||
} else {
|
||||
furi_string_set(app->file_path, BAD_BT_APP_BASE_FOLDER);
|
||||
scene_manager_next_scene(app->scene_manager, BadBtSceneFileSelect);
|
||||
}
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
void bad_bt_app_free(BadBtApp* app) {
|
||||
furi_assert(app);
|
||||
|
||||
if(app->bad_bt_script) {
|
||||
bad_bt_script_close(app->bad_bt_script);
|
||||
app->bad_bt_script = NULL;
|
||||
}
|
||||
|
||||
// Views
|
||||
view_dispatcher_remove_view(app->view_dispatcher, BadBtAppViewWork);
|
||||
bad_bt_free(app->bad_bt_view);
|
||||
|
||||
// Custom Widget
|
||||
view_dispatcher_remove_view(app->view_dispatcher, BadBtAppViewError);
|
||||
widget_free(app->widget);
|
||||
|
||||
// Variable item list
|
||||
view_dispatcher_remove_view(app->view_dispatcher, BadBtAppViewConfig);
|
||||
variable_item_list_free(app->var_item_list);
|
||||
|
||||
// Text Input
|
||||
view_dispatcher_remove_view(app->view_dispatcher, BadBtAppViewConfigName);
|
||||
text_input_free(app->text_input);
|
||||
|
||||
// Byte Input
|
||||
view_dispatcher_remove_view(app->view_dispatcher, BadBtAppViewConfigMac);
|
||||
byte_input_free(app->byte_input);
|
||||
|
||||
// View dispatcher
|
||||
view_dispatcher_free(app->view_dispatcher);
|
||||
scene_manager_free(app->scene_manager);
|
||||
|
||||
// Restore bt config
|
||||
app->bt->suppress_pin_screen = false;
|
||||
if(app->conn_init_thread) {
|
||||
furi_thread_join(app->conn_init_thread);
|
||||
furi_thread_free(app->conn_init_thread);
|
||||
bad_bt_connection_deinit(app);
|
||||
}
|
||||
|
||||
// Close records
|
||||
furi_record_close(RECORD_GUI);
|
||||
furi_record_close(RECORD_NOTIFICATION);
|
||||
furi_record_close(RECORD_DIALOGS);
|
||||
furi_record_close(RECORD_BT);
|
||||
|
||||
bad_bt_save_settings(app);
|
||||
|
||||
furi_string_free(app->file_path);
|
||||
furi_string_free(app->keyboard_layout);
|
||||
|
||||
free(app);
|
||||
}
|
||||
|
||||
int32_t bad_bt_app(void* p) {
|
||||
BadBtApp* bad_bt_app = bad_bt_app_alloc((char*)p);
|
||||
|
||||
view_dispatcher_run(bad_bt_app->view_dispatcher);
|
||||
|
||||
bad_bt_app_free(bad_bt_app);
|
||||
return 0;
|
||||
}
|
||||
39
applications/external/bad_bt/bad_bt_app.h
vendored
@@ -1,39 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "scenes/bad_bt_scene.h"
|
||||
#include "helpers/ducky_script.h"
|
||||
|
||||
#include <gui/gui.h>
|
||||
#include <assets_icons.h>
|
||||
#include <gui/scene_manager.h>
|
||||
#include <dialogs/dialogs.h>
|
||||
#include <notification/notification_messages.h>
|
||||
#include "bad_bt_icons.h"
|
||||
|
||||
#define BAD_BT_APP_BASE_FOLDER EXT_PATH("badusb")
|
||||
#define BAD_BT_APP_BASE_CONFIG_FOLDER EXT_PATH("badbt")
|
||||
#define BAD_BT_APP_PATH_LAYOUT_FOLDER BAD_BT_APP_BASE_FOLDER "/assets/layouts"
|
||||
#define BAD_BT_APP_SCRIPT_EXTENSION ".txt"
|
||||
#define BAD_BT_APP_LAYOUT_EXTENSION ".kl"
|
||||
|
||||
typedef enum BadBtCustomEvent {
|
||||
BadBtAppCustomEventTextEditResult,
|
||||
BadBtAppCustomEventByteInputDone,
|
||||
BadBtCustomEventErrorBack
|
||||
} BadBtCustomEvent;
|
||||
|
||||
typedef enum {
|
||||
BadBtAppViewError,
|
||||
BadBtAppViewWork,
|
||||
BadBtAppViewConfig,
|
||||
BadBtAppViewConfigMac,
|
||||
BadBtAppViewConfigName
|
||||
} BadBtAppView;
|
||||
|
||||
void bad_bt_config_switch_remember_mode(BadBtApp* app);
|
||||
|
||||
int32_t bad_bt_connection_init(BadBtApp* app);
|
||||
|
||||
void bad_bt_connection_deinit(BadBtApp* app);
|
||||
|
||||
void bad_kb_config_refresh_menu(BadBtApp* app);
|
||||
792
applications/external/bad_bt/helpers/ducky_script.c
vendored
@@ -1,792 +0,0 @@
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <gui/gui.h>
|
||||
#include <input/input.h>
|
||||
#include <lib/toolbox/args.h>
|
||||
#include <furi_hal_bt_hid.h>
|
||||
#include <bt/bt_service/bt.h>
|
||||
#include <storage/storage.h>
|
||||
#include "ducky_script.h"
|
||||
#include "ducky_script_i.h"
|
||||
#include <dolphin/dolphin.h>
|
||||
#include <toolbox/hex.h>
|
||||
#include "../bad_bt_app.h"
|
||||
|
||||
const uint8_t BAD_BT_BOUND_MAC_ADDRESS[BAD_BT_MAC_ADDRESS_LEN] =
|
||||
{0x41, 0x4a, 0xef, 0xb6, 0xa9, 0xd4};
|
||||
const uint8_t BAD_BT_EMPTY_MAC_ADDRESS[BAD_BT_MAC_ADDRESS_LEN] =
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
#define TAG "BadBT"
|
||||
#define WORKER_TAG TAG "Worker"
|
||||
|
||||
#define BADBT_ASCII_TO_KEY(script, x) \
|
||||
(((uint8_t)x < 128) ? (script->layout[(uint8_t)x]) : HID_KEYBOARD_NONE)
|
||||
|
||||
/**
|
||||
* Delays for waiting between HID key press and key release
|
||||
*/
|
||||
const uint8_t bt_hid_delays[LevelRssiNum] = {
|
||||
60, // LevelRssi122_100
|
||||
55, // LevelRssi99_80
|
||||
50, // LevelRssi79_60
|
||||
47, // LevelRssi59_40
|
||||
34, // LevelRssi39_0
|
||||
};
|
||||
|
||||
uint8_t bt_timeout = 0;
|
||||
|
||||
static LevelRssiRange bt_remote_rssi_range(Bt* bt) {
|
||||
uint8_t rssi;
|
||||
|
||||
if(!bt_remote_rssi(bt, &rssi)) return LevelRssiError;
|
||||
|
||||
if(rssi <= 39)
|
||||
return LevelRssi39_0;
|
||||
else if(rssi <= 59)
|
||||
return LevelRssi59_40;
|
||||
else if(rssi <= 79)
|
||||
return LevelRssi79_60;
|
||||
else if(rssi <= 99)
|
||||
return LevelRssi99_80;
|
||||
else if(rssi <= 122)
|
||||
return LevelRssi122_100;
|
||||
|
||||
return LevelRssiError;
|
||||
}
|
||||
|
||||
static inline void update_bt_timeout(Bt* bt) {
|
||||
LevelRssiRange r = bt_remote_rssi_range(bt);
|
||||
if(r < LevelRssiNum) {
|
||||
bt_timeout = bt_hid_delays[r];
|
||||
FURI_LOG_D(WORKER_TAG, "BLE Key timeout : %u", bt_timeout);
|
||||
}
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
WorkerEvtStartStop = (1 << 0),
|
||||
WorkerEvtPauseResume = (1 << 1),
|
||||
WorkerEvtEnd = (1 << 2),
|
||||
WorkerEvtConnect = (1 << 3),
|
||||
WorkerEvtDisconnect = (1 << 4),
|
||||
} WorkerEvtFlags;
|
||||
|
||||
static const char ducky_cmd_id[] = {"ID"};
|
||||
static const char ducky_cmd_bt_id[] = {"BT_ID"};
|
||||
|
||||
static const uint8_t numpad_keys[10] = {
|
||||
HID_KEYPAD_0,
|
||||
HID_KEYPAD_1,
|
||||
HID_KEYPAD_2,
|
||||
HID_KEYPAD_3,
|
||||
HID_KEYPAD_4,
|
||||
HID_KEYPAD_5,
|
||||
HID_KEYPAD_6,
|
||||
HID_KEYPAD_7,
|
||||
HID_KEYPAD_8,
|
||||
HID_KEYPAD_9,
|
||||
};
|
||||
|
||||
uint32_t ducky_get_command_len(const char* line) {
|
||||
uint32_t len = strlen(line);
|
||||
for(uint32_t i = 0; i < len; i++) {
|
||||
if(line[i] == ' ') return i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ducky_is_line_end(const char chr) {
|
||||
return ((chr == ' ') || (chr == '\0') || (chr == '\r') || (chr == '\n'));
|
||||
}
|
||||
|
||||
uint16_t ducky_get_keycode(BadBtScript* bad_bt, const char* param, bool accept_chars) {
|
||||
uint16_t keycode = ducky_get_keycode_by_name(param);
|
||||
if(keycode != HID_KEYBOARD_NONE) {
|
||||
return keycode;
|
||||
}
|
||||
|
||||
if((accept_chars) && (strlen(param) > 0)) {
|
||||
return (BADBT_ASCII_TO_KEY(bad_bt, param[0]) & 0xFF);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ducky_get_number(const char* param, uint32_t* val) {
|
||||
uint32_t value = 0;
|
||||
if(sscanf(param, "%lu", &value) == 1) {
|
||||
*val = value;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ducky_numlock_on(BadBtScript* bad_bt) {
|
||||
UNUSED(bad_bt);
|
||||
if((furi_hal_bt_hid_get_led_state() & HID_KB_LED_NUM) == 0) {
|
||||
furi_hal_bt_hid_kb_press(HID_KEYBOARD_LOCK_NUM_LOCK);
|
||||
furi_delay_ms(bt_timeout);
|
||||
furi_hal_bt_hid_kb_release(HID_KEYBOARD_LOCK_NUM_LOCK);
|
||||
}
|
||||
}
|
||||
|
||||
bool ducky_numpad_press(BadBtScript* bad_bt, const char num) {
|
||||
UNUSED(bad_bt);
|
||||
if((num < '0') || (num > '9')) return false;
|
||||
|
||||
uint16_t key = numpad_keys[num - '0'];
|
||||
furi_hal_bt_hid_kb_press(key);
|
||||
furi_delay_ms(bt_timeout);
|
||||
furi_hal_bt_hid_kb_release(key);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ducky_altchar(BadBtScript* bad_bt, const char* charcode) {
|
||||
uint8_t i = 0;
|
||||
bool state = false;
|
||||
|
||||
furi_hal_bt_hid_kb_press(KEY_MOD_LEFT_ALT);
|
||||
|
||||
while(!ducky_is_line_end(charcode[i])) {
|
||||
state = ducky_numpad_press(bad_bt, charcode[i]);
|
||||
if(state == false) break;
|
||||
i++;
|
||||
}
|
||||
|
||||
furi_hal_bt_hid_kb_release(KEY_MOD_LEFT_ALT);
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
bool ducky_altstring(BadBtScript* bad_bt, const char* param) {
|
||||
uint32_t i = 0;
|
||||
bool state = false;
|
||||
|
||||
while(param[i] != '\0') {
|
||||
if((param[i] < ' ') || (param[i] > '~')) {
|
||||
i++;
|
||||
continue; // Skip non-printable chars
|
||||
}
|
||||
|
||||
char temp_str[4];
|
||||
snprintf(temp_str, 4, "%u", param[i]);
|
||||
|
||||
state = ducky_altchar(bad_bt, temp_str);
|
||||
if(state == false) break;
|
||||
i++;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
int32_t ducky_error(BadBtScript* bad_bt, const char* text, ...) {
|
||||
va_list args;
|
||||
va_start(args, text);
|
||||
|
||||
vsnprintf(bad_bt->st.error, sizeof(bad_bt->st.error), text, args);
|
||||
|
||||
va_end(args);
|
||||
return SCRIPT_STATE_ERROR;
|
||||
}
|
||||
|
||||
bool ducky_string(BadBtScript* bad_bt, const char* param) {
|
||||
uint32_t i = 0;
|
||||
|
||||
while(param[i] != '\0') {
|
||||
if(param[i] != '\n') {
|
||||
uint16_t keycode = BADBT_ASCII_TO_KEY(bad_bt, param[i]);
|
||||
if(keycode != HID_KEYBOARD_NONE) {
|
||||
furi_hal_bt_hid_kb_press(keycode);
|
||||
furi_delay_ms(bt_timeout);
|
||||
furi_hal_bt_hid_kb_release(keycode);
|
||||
}
|
||||
} else {
|
||||
furi_hal_bt_hid_kb_press(HID_KEYBOARD_RETURN);
|
||||
furi_delay_ms(bt_timeout);
|
||||
furi_hal_bt_hid_kb_release(HID_KEYBOARD_RETURN);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
bad_bt->stringdelay = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ducky_string_next(BadBtScript* bad_bt) {
|
||||
if(bad_bt->string_print_pos >= furi_string_size(bad_bt->string_print)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
char print_char = furi_string_get_char(bad_bt->string_print, bad_bt->string_print_pos);
|
||||
|
||||
if(print_char != '\n') {
|
||||
uint16_t keycode = BADBT_ASCII_TO_KEY(bad_bt, print_char);
|
||||
if(keycode != HID_KEYBOARD_NONE) {
|
||||
furi_hal_bt_hid_kb_press(keycode);
|
||||
furi_delay_ms(bt_timeout);
|
||||
furi_hal_bt_hid_kb_release(keycode);
|
||||
}
|
||||
} else {
|
||||
furi_hal_bt_hid_kb_press(HID_KEYBOARD_RETURN);
|
||||
furi_delay_ms(bt_timeout);
|
||||
furi_hal_bt_hid_kb_release(HID_KEYBOARD_RETURN);
|
||||
}
|
||||
|
||||
bad_bt->string_print_pos++;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int32_t ducky_parse_line(BadBtScript* bad_bt, FuriString* line) {
|
||||
uint32_t line_len = furi_string_size(line);
|
||||
const char* line_tmp = furi_string_get_cstr(line);
|
||||
|
||||
if(line_len == 0) {
|
||||
return SCRIPT_STATE_NEXT_LINE; // Skip empty lines
|
||||
}
|
||||
FURI_LOG_D(WORKER_TAG, "line:%s", line_tmp);
|
||||
|
||||
// Ducky Lang Functions
|
||||
int32_t cmd_result = ducky_execute_cmd(bad_bt, line_tmp);
|
||||
if(cmd_result != SCRIPT_STATE_CMD_UNKNOWN) {
|
||||
return cmd_result;
|
||||
}
|
||||
|
||||
// Special keys + modifiers
|
||||
uint16_t key = ducky_get_keycode(bad_bt, line_tmp, false);
|
||||
if(key == HID_KEYBOARD_NONE) {
|
||||
return ducky_error(bad_bt, "No keycode defined for %s", line_tmp);
|
||||
}
|
||||
if((key & 0xFF00) != 0) {
|
||||
// It's a modifier key
|
||||
uint32_t offset = ducky_get_command_len(line_tmp) + 1;
|
||||
// ducky_get_command_len() returns 0 without space, so check for != 1
|
||||
if(offset != 1 && line_len > offset) {
|
||||
// It's also a key combination
|
||||
key |= ducky_get_keycode(bad_bt, line_tmp + offset, true);
|
||||
}
|
||||
}
|
||||
furi_hal_bt_hid_kb_press(key);
|
||||
furi_delay_ms(bt_timeout);
|
||||
furi_hal_bt_hid_kb_release(key);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool ducky_set_bt_id(BadBtScript* bad_bt, const char* line) {
|
||||
size_t line_len = strlen(line);
|
||||
size_t mac_len = BAD_BT_MAC_ADDRESS_LEN * 3;
|
||||
if(line_len < mac_len + 1) return false; // MAC + at least 1 char for name
|
||||
|
||||
uint8_t mac[BAD_BT_MAC_ADDRESS_LEN];
|
||||
for(size_t i = 0; i < BAD_BT_MAC_ADDRESS_LEN; i++) {
|
||||
char a = line[i * 3];
|
||||
char b = line[i * 3 + 1];
|
||||
if((a < 'A' && a > 'F') || (a < '0' && a > '9') || (b < 'A' && b > 'F') ||
|
||||
(b < '0' && b > '9') || !hex_char_to_uint8(a, b, &mac[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
furi_hal_bt_reverse_mac_addr(mac);
|
||||
|
||||
furi_hal_bt_set_profile_adv_name(FuriHalBtProfileHidKeyboard, line + mac_len);
|
||||
bt_set_profile_mac_address(bad_bt->bt, mac);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ducky_script_preload(BadBtScript* bad_bt, File* script_file) {
|
||||
uint8_t ret = 0;
|
||||
uint32_t line_len = 0;
|
||||
|
||||
furi_string_reset(bad_bt->line);
|
||||
|
||||
do {
|
||||
ret = storage_file_read(script_file, bad_bt->file_buf, FILE_BUFFER_LEN);
|
||||
for(uint16_t i = 0; i < ret; i++) {
|
||||
if(bad_bt->file_buf[i] == '\n' && line_len > 0) {
|
||||
bad_bt->st.line_nb++;
|
||||
line_len = 0;
|
||||
} else {
|
||||
if(bad_bt->st.line_nb == 0) { // Save first line
|
||||
furi_string_push_back(bad_bt->line, bad_bt->file_buf[i]);
|
||||
}
|
||||
line_len++;
|
||||
}
|
||||
}
|
||||
if(storage_file_eof(script_file)) {
|
||||
if(line_len > 0) {
|
||||
bad_bt->st.line_nb++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while(ret > 0);
|
||||
|
||||
const char* line_tmp = furi_string_get_cstr(bad_bt->line);
|
||||
if(bad_bt->app->switch_mode_thread) {
|
||||
furi_thread_join(bad_bt->app->switch_mode_thread);
|
||||
furi_thread_free(bad_bt->app->switch_mode_thread);
|
||||
bad_bt->app->switch_mode_thread = NULL;
|
||||
}
|
||||
// Looking for ID or BT_ID command at first line
|
||||
bad_bt->set_usb_id = false;
|
||||
bad_bt->set_bt_id = false;
|
||||
bad_bt->has_usb_id = strncmp(line_tmp, ducky_cmd_id, strlen(ducky_cmd_id)) == 0;
|
||||
// TODO: We setting has_usb_id to its value but ignoring it for now and not using anywhere here, may be used in a future to detect script type
|
||||
bad_bt->has_bt_id = strncmp(line_tmp, ducky_cmd_bt_id, strlen(ducky_cmd_bt_id)) == 0;
|
||||
if(bad_bt->has_bt_id) {
|
||||
if(!bad_bt->app->bt_remember) {
|
||||
bad_bt->set_bt_id = ducky_set_bt_id(bad_bt, &line_tmp[strlen(ducky_cmd_bt_id) + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
bad_kb_config_refresh_menu(bad_bt->app);
|
||||
|
||||
if(!bad_bt->set_bt_id) {
|
||||
const char* bt_name = bad_bt->app->config.bt_name;
|
||||
const uint8_t* bt_mac = bad_bt->app->bt_remember ? (uint8_t*)&BAD_BT_BOUND_MAC_ADDRESS :
|
||||
bad_bt->app->config.bt_mac;
|
||||
bool reset_name = strncmp(
|
||||
bt_name,
|
||||
furi_hal_bt_get_profile_adv_name(FuriHalBtProfileHidKeyboard),
|
||||
BAD_BT_ADV_NAME_MAX_LEN);
|
||||
bool reset_mac = memcmp(
|
||||
bt_mac,
|
||||
furi_hal_bt_get_profile_mac_addr(FuriHalBtProfileHidKeyboard),
|
||||
BAD_BT_MAC_ADDRESS_LEN);
|
||||
if(reset_name && reset_mac) {
|
||||
furi_hal_bt_set_profile_adv_name(FuriHalBtProfileHidKeyboard, bt_name);
|
||||
} else if(reset_name) {
|
||||
bt_set_profile_adv_name(bad_bt->bt, bt_name);
|
||||
}
|
||||
if(reset_mac) {
|
||||
bt_set_profile_mac_address(bad_bt->bt, bt_mac);
|
||||
}
|
||||
}
|
||||
|
||||
storage_file_seek(script_file, 0, true);
|
||||
furi_string_reset(bad_bt->line);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int32_t ducky_script_execute_next(BadBtScript* bad_bt, File* script_file) {
|
||||
int32_t delay_val = 0;
|
||||
|
||||
if(bad_bt->repeat_cnt > 0) {
|
||||
bad_bt->repeat_cnt--;
|
||||
delay_val = ducky_parse_line(bad_bt, bad_bt->line_prev);
|
||||
if(delay_val == SCRIPT_STATE_NEXT_LINE) { // Empty line
|
||||
return 0;
|
||||
} else if(delay_val == SCRIPT_STATE_STRING_START) { // Print string with delays
|
||||
return delay_val;
|
||||
} else if(delay_val == SCRIPT_STATE_WAIT_FOR_BTN) { // wait for button
|
||||
return delay_val;
|
||||
} else if(delay_val < 0) { // Script error
|
||||
bad_bt->st.error_line = bad_bt->st.line_cur - 1;
|
||||
FURI_LOG_E(WORKER_TAG, "Unknown command at line %u", bad_bt->st.line_cur - 1U);
|
||||
return SCRIPT_STATE_ERROR;
|
||||
} else {
|
||||
return (delay_val + bad_bt->defdelay);
|
||||
}
|
||||
}
|
||||
|
||||
furi_string_set(bad_bt->line_prev, bad_bt->line);
|
||||
furi_string_reset(bad_bt->line);
|
||||
|
||||
while(1) {
|
||||
if(bad_bt->buf_len == 0) {
|
||||
bad_bt->buf_len = storage_file_read(script_file, bad_bt->file_buf, FILE_BUFFER_LEN);
|
||||
if(storage_file_eof(script_file)) {
|
||||
if((bad_bt->buf_len < FILE_BUFFER_LEN) && (bad_bt->file_end == false)) {
|
||||
bad_bt->file_buf[bad_bt->buf_len] = '\n';
|
||||
bad_bt->buf_len++;
|
||||
bad_bt->file_end = true;
|
||||
}
|
||||
}
|
||||
|
||||
bad_bt->buf_start = 0;
|
||||
if(bad_bt->buf_len == 0) return SCRIPT_STATE_END;
|
||||
}
|
||||
for(uint8_t i = bad_bt->buf_start; i < (bad_bt->buf_start + bad_bt->buf_len); i++) {
|
||||
if(bad_bt->file_buf[i] == '\n' && furi_string_size(bad_bt->line) > 0) {
|
||||
bad_bt->st.line_cur++;
|
||||
bad_bt->buf_len = bad_bt->buf_len + bad_bt->buf_start - (i + 1);
|
||||
bad_bt->buf_start = i + 1;
|
||||
furi_string_trim(bad_bt->line);
|
||||
delay_val = ducky_parse_line(bad_bt, bad_bt->line);
|
||||
if(delay_val == SCRIPT_STATE_NEXT_LINE) { // Empty line
|
||||
return 0;
|
||||
} else if(delay_val == SCRIPT_STATE_STRING_START) { // Print string with delays
|
||||
return delay_val;
|
||||
} else if(delay_val == SCRIPT_STATE_WAIT_FOR_BTN) { // wait for button
|
||||
return delay_val;
|
||||
} else if(delay_val < 0) {
|
||||
bad_bt->st.error_line = bad_bt->st.line_cur;
|
||||
FURI_LOG_E(WORKER_TAG, "Unknown command at line %u", bad_bt->st.line_cur);
|
||||
return SCRIPT_STATE_ERROR;
|
||||
} else {
|
||||
return (delay_val + bad_bt->defdelay);
|
||||
}
|
||||
} else {
|
||||
furi_string_push_back(bad_bt->line, bad_bt->file_buf[i]);
|
||||
}
|
||||
}
|
||||
bad_bt->buf_len = 0;
|
||||
if(bad_bt->file_end) return SCRIPT_STATE_END;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bad_bt_bt_hid_state_callback(BtStatus status, void* context) {
|
||||
furi_assert(context);
|
||||
BadBtScript* bad_bt = context;
|
||||
bool state = (status == BtStatusConnected);
|
||||
|
||||
if(state == true) {
|
||||
LevelRssiRange r = bt_remote_rssi_range(bad_bt->bt);
|
||||
if(r != LevelRssiError) {
|
||||
bt_timeout = bt_hid_delays[r];
|
||||
}
|
||||
furi_thread_flags_set(furi_thread_get_id(bad_bt->thread), WorkerEvtConnect);
|
||||
} else {
|
||||
furi_thread_flags_set(furi_thread_get_id(bad_bt->thread), WorkerEvtDisconnect);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t bad_bt_flags_get(uint32_t flags_mask, uint32_t timeout) {
|
||||
uint32_t flags = furi_thread_flags_get();
|
||||
furi_check((flags & FuriFlagError) == 0);
|
||||
if(flags == 0) {
|
||||
flags = furi_thread_flags_wait(flags_mask, FuriFlagWaitAny, timeout);
|
||||
furi_check(((flags & FuriFlagError) == 0) || (flags == (unsigned)FuriFlagErrorTimeout));
|
||||
} else {
|
||||
uint32_t state = furi_thread_flags_clear(flags);
|
||||
furi_check((state & FuriFlagError) == 0);
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
static int32_t bad_bt_worker(void* context) {
|
||||
BadBtScript* bad_bt = context;
|
||||
|
||||
BadBtWorkerState worker_state = BadBtStateInit;
|
||||
int32_t delay_val = 0;
|
||||
|
||||
FURI_LOG_I(WORKER_TAG, "Init");
|
||||
File* script_file = storage_file_alloc(furi_record_open(RECORD_STORAGE));
|
||||
bad_bt->line = furi_string_alloc();
|
||||
bad_bt->line_prev = furi_string_alloc();
|
||||
bad_bt->string_print = furi_string_alloc();
|
||||
|
||||
bt_set_status_changed_callback(bad_bt->bt, bad_bt_bt_hid_state_callback, bad_bt);
|
||||
|
||||
while(1) {
|
||||
if(worker_state == BadBtStateInit) { // State: initialization
|
||||
if(storage_file_open(
|
||||
script_file,
|
||||
furi_string_get_cstr(bad_bt->file_path),
|
||||
FSAM_READ,
|
||||
FSOM_OPEN_EXISTING)) {
|
||||
if((ducky_script_preload(bad_bt, script_file)) && (bad_bt->st.line_nb > 0)) {
|
||||
if(furi_hal_bt_is_connected()) {
|
||||
worker_state = BadBtStateIdle; // Ready to run
|
||||
} else {
|
||||
worker_state = BadBtStateNotConnected; // Not connected
|
||||
}
|
||||
|
||||
} else {
|
||||
worker_state = BadBtStateScriptError; // Script preload error
|
||||
}
|
||||
} else {
|
||||
FURI_LOG_E(WORKER_TAG, "File open error");
|
||||
worker_state = BadBtStateFileError; // File open error
|
||||
}
|
||||
bad_bt->st.state = worker_state;
|
||||
|
||||
} else if(worker_state == BadBtStateNotConnected) { // State: Not connected
|
||||
uint32_t flags = bad_bt_flags_get(
|
||||
WorkerEvtEnd | WorkerEvtConnect | WorkerEvtDisconnect | WorkerEvtStartStop,
|
||||
FuriWaitForever);
|
||||
|
||||
if(flags & WorkerEvtEnd) {
|
||||
break;
|
||||
} else if(flags & WorkerEvtConnect) {
|
||||
worker_state = BadBtStateIdle; // Ready to run
|
||||
} else if(flags & WorkerEvtStartStop) {
|
||||
worker_state = BadBtStateWillRun; // Will run when connected
|
||||
}
|
||||
bad_bt->st.state = worker_state;
|
||||
|
||||
} else if(worker_state == BadBtStateIdle) { // State: ready to start
|
||||
uint32_t flags = bad_bt_flags_get(
|
||||
WorkerEvtEnd | WorkerEvtStartStop | WorkerEvtConnect | WorkerEvtDisconnect,
|
||||
FuriWaitForever);
|
||||
|
||||
if(flags & WorkerEvtEnd) {
|
||||
break;
|
||||
} else if(flags & WorkerEvtStartStop) { // Start executing script
|
||||
delay_val = 0;
|
||||
bad_bt->buf_len = 0;
|
||||
bad_bt->st.line_cur = 0;
|
||||
bad_bt->defdelay = 0;
|
||||
bad_bt->stringdelay = 0;
|
||||
bad_bt->repeat_cnt = 0;
|
||||
bad_bt->key_hold_nb = 0;
|
||||
bad_bt->file_end = false;
|
||||
storage_file_seek(script_file, 0, true);
|
||||
bad_bt_script_set_keyboard_layout(bad_bt, bad_bt->keyboard_layout);
|
||||
worker_state = BadBtStateRunning;
|
||||
} else if(flags & WorkerEvtDisconnect) {
|
||||
worker_state = BadBtStateNotConnected; // Disconnected
|
||||
}
|
||||
bad_bt->st.state = worker_state;
|
||||
|
||||
} else if(worker_state == BadBtStateWillRun) { // State: start on connection
|
||||
uint32_t flags = bad_bt_flags_get(
|
||||
WorkerEvtEnd | WorkerEvtConnect | WorkerEvtDisconnect | WorkerEvtStartStop,
|
||||
FuriWaitForever);
|
||||
|
||||
if(flags & WorkerEvtEnd) {
|
||||
break;
|
||||
} else if(flags & WorkerEvtConnect) { // Start executing script
|
||||
delay_val = 0;
|
||||
bad_bt->buf_len = 0;
|
||||
bad_bt->st.line_cur = 0;
|
||||
bad_bt->defdelay = 0;
|
||||
bad_bt->stringdelay = 0;
|
||||
bad_bt->repeat_cnt = 0;
|
||||
bad_bt->file_end = false;
|
||||
storage_file_seek(script_file, 0, true);
|
||||
// extra time for PC to recognize Flipper as keyboard
|
||||
flags = furi_thread_flags_wait(
|
||||
WorkerEvtEnd | WorkerEvtDisconnect | WorkerEvtStartStop,
|
||||
FuriFlagWaitAny | FuriFlagNoClear,
|
||||
1500);
|
||||
if(flags == (unsigned)FuriFlagErrorTimeout) {
|
||||
// If nothing happened - start script execution
|
||||
worker_state = BadBtStateRunning;
|
||||
} else if(flags & WorkerEvtStartStop) {
|
||||
worker_state = BadBtStateIdle;
|
||||
furi_thread_flags_clear(WorkerEvtStartStop);
|
||||
}
|
||||
|
||||
update_bt_timeout(bad_bt->bt);
|
||||
|
||||
bad_bt_script_set_keyboard_layout(bad_bt, bad_bt->keyboard_layout);
|
||||
} else if(flags & WorkerEvtStartStop) { // Cancel scheduled execution
|
||||
worker_state = BadBtStateNotConnected;
|
||||
}
|
||||
bad_bt->st.state = worker_state;
|
||||
|
||||
} else if(worker_state == BadBtStateRunning) { // State: running
|
||||
uint16_t delay_cur = (delay_val > 1000) ? (1000) : (delay_val);
|
||||
uint32_t flags = furi_thread_flags_wait(
|
||||
WorkerEvtEnd | WorkerEvtStartStop | WorkerEvtConnect | WorkerEvtDisconnect,
|
||||
FuriFlagWaitAny,
|
||||
delay_cur);
|
||||
|
||||
delay_val -= delay_cur;
|
||||
if(!(flags & FuriFlagError)) {
|
||||
if(flags & WorkerEvtEnd) {
|
||||
break;
|
||||
} else if(flags & WorkerEvtStartStop) {
|
||||
worker_state = BadBtStateIdle; // Stop executing script
|
||||
|
||||
furi_hal_bt_hid_kb_release_all();
|
||||
|
||||
} else if(flags & WorkerEvtDisconnect) {
|
||||
worker_state = BadBtStateNotConnected; // Disconnected
|
||||
|
||||
furi_hal_bt_hid_kb_release_all();
|
||||
}
|
||||
bad_bt->st.state = worker_state;
|
||||
continue;
|
||||
} else if(
|
||||
(flags == (unsigned)FuriFlagErrorTimeout) ||
|
||||
(flags == (unsigned)FuriFlagErrorResource)) {
|
||||
if(delay_val > 0) {
|
||||
bad_bt->st.delay_remain--;
|
||||
continue;
|
||||
}
|
||||
bad_bt->st.state = BadBtStateRunning;
|
||||
delay_val = ducky_script_execute_next(bad_bt, script_file);
|
||||
if(delay_val == SCRIPT_STATE_ERROR) { // Script error
|
||||
delay_val = 0;
|
||||
worker_state = BadBtStateScriptError;
|
||||
bad_bt->st.state = worker_state;
|
||||
|
||||
furi_hal_bt_hid_kb_release_all();
|
||||
|
||||
} else if(delay_val == SCRIPT_STATE_END) { // End of script
|
||||
delay_val = 0;
|
||||
worker_state = BadBtStateIdle;
|
||||
bad_bt->st.state = BadBtStateDone;
|
||||
|
||||
furi_hal_bt_hid_kb_release_all();
|
||||
|
||||
continue;
|
||||
} else if(delay_val == SCRIPT_STATE_STRING_START) { // Start printing string with delays
|
||||
delay_val = bad_bt->defdelay;
|
||||
bad_bt->string_print_pos = 0;
|
||||
worker_state = BadBtStateStringDelay;
|
||||
} else if(delay_val == SCRIPT_STATE_WAIT_FOR_BTN) { // set state to wait for user input
|
||||
worker_state = BadBtStateWaitForBtn;
|
||||
bad_bt->st.state = BadBtStateWaitForBtn; // Show long delays
|
||||
} else if(delay_val > 1000) {
|
||||
bad_bt->st.state = BadBtStateDelay; // Show long delays
|
||||
bad_bt->st.delay_remain = delay_val / 1000;
|
||||
}
|
||||
} else {
|
||||
furi_check((flags & FuriFlagError) == 0);
|
||||
}
|
||||
} else if(worker_state == BadBtStateWaitForBtn) { // State: Wait for button Press
|
||||
uint16_t delay_cur = (delay_val > 1000) ? (1000) : (delay_val);
|
||||
uint32_t flags = furi_thread_flags_wait(
|
||||
WorkerEvtEnd | WorkerEvtStartStop | WorkerEvtPauseResume | WorkerEvtConnect |
|
||||
WorkerEvtDisconnect,
|
||||
FuriFlagWaitAny,
|
||||
delay_cur);
|
||||
if(!(flags & FuriFlagError)) {
|
||||
if(flags & WorkerEvtEnd) {
|
||||
break;
|
||||
} else if(flags & WorkerEvtStartStop) {
|
||||
delay_val = 0;
|
||||
worker_state = BadBtStateRunning;
|
||||
} else if(flags & WorkerEvtDisconnect) {
|
||||
worker_state = BadBtStateNotConnected; // Disconnected
|
||||
furi_hal_hid_kb_release_all();
|
||||
}
|
||||
bad_bt->st.state = worker_state;
|
||||
continue;
|
||||
}
|
||||
} else if(worker_state == BadBtStateStringDelay) { // State: print string with delays
|
||||
uint32_t flags = furi_thread_flags_wait(
|
||||
WorkerEvtEnd | WorkerEvtStartStop | WorkerEvtPauseResume | WorkerEvtConnect |
|
||||
WorkerEvtDisconnect,
|
||||
FuriFlagWaitAny,
|
||||
bad_bt->stringdelay);
|
||||
|
||||
if(!(flags & FuriFlagError)) {
|
||||
if(flags & WorkerEvtEnd) {
|
||||
break;
|
||||
} else if(flags & WorkerEvtStartStop) {
|
||||
worker_state = BadBtStateIdle; // Stop executing script
|
||||
|
||||
furi_hal_bt_hid_kb_release_all();
|
||||
|
||||
} else if(flags & WorkerEvtDisconnect) {
|
||||
worker_state = BadBtStateNotConnected; // Disconnected
|
||||
|
||||
furi_hal_bt_hid_kb_release_all();
|
||||
}
|
||||
bad_bt->st.state = worker_state;
|
||||
continue;
|
||||
} else if(
|
||||
(flags == (unsigned)FuriFlagErrorTimeout) ||
|
||||
(flags == (unsigned)FuriFlagErrorResource)) {
|
||||
bool string_end = ducky_string_next(bad_bt);
|
||||
if(string_end) {
|
||||
bad_bt->stringdelay = 0;
|
||||
worker_state = BadBtStateRunning;
|
||||
}
|
||||
} else {
|
||||
furi_check((flags & FuriFlagError) == 0);
|
||||
}
|
||||
} else if(
|
||||
(worker_state == BadBtStateFileError) ||
|
||||
(worker_state == BadBtStateScriptError)) { // State: error
|
||||
uint32_t flags =
|
||||
bad_bt_flags_get(WorkerEvtEnd, FuriWaitForever); // Waiting for exit command
|
||||
|
||||
if(flags & WorkerEvtEnd) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
update_bt_timeout(bad_bt->bt);
|
||||
}
|
||||
|
||||
bt_set_status_changed_callback(bad_bt->bt, NULL, NULL);
|
||||
|
||||
storage_file_close(script_file);
|
||||
storage_file_free(script_file);
|
||||
furi_string_free(bad_bt->line);
|
||||
furi_string_free(bad_bt->line_prev);
|
||||
furi_string_free(bad_bt->string_print);
|
||||
|
||||
FURI_LOG_I(WORKER_TAG, "End");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bad_bt_script_set_default_keyboard_layout(BadBtScript* bad_bt) {
|
||||
furi_assert(bad_bt);
|
||||
furi_string_set_str(bad_bt->keyboard_layout, "");
|
||||
memset(bad_bt->layout, HID_KEYBOARD_NONE, sizeof(bad_bt->layout));
|
||||
memcpy(bad_bt->layout, hid_asciimap, MIN(sizeof(hid_asciimap), sizeof(bad_bt->layout)));
|
||||
}
|
||||
|
||||
BadBtScript* bad_bt_script_open(FuriString* file_path, Bt* bt, BadBtApp* app) {
|
||||
furi_assert(file_path);
|
||||
|
||||
BadBtScript* bad_bt = malloc(sizeof(BadBtScript));
|
||||
bad_bt->app = app;
|
||||
bad_bt->file_path = furi_string_alloc();
|
||||
furi_string_set(bad_bt->file_path, file_path);
|
||||
bad_bt->keyboard_layout = furi_string_alloc();
|
||||
bad_bt_script_set_default_keyboard_layout(bad_bt);
|
||||
|
||||
bad_bt->st.state = BadBtStateInit;
|
||||
bad_bt->st.error[0] = '\0';
|
||||
|
||||
bad_bt->bt = bt;
|
||||
|
||||
bad_bt->thread = furi_thread_alloc_ex("BadBtWorker", 2048, bad_bt_worker, bad_bt);
|
||||
furi_thread_start(bad_bt->thread);
|
||||
return bad_bt;
|
||||
}
|
||||
|
||||
void bad_bt_script_close(BadBtScript* bad_bt) {
|
||||
furi_assert(bad_bt);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
furi_thread_flags_set(furi_thread_get_id(bad_bt->thread), WorkerEvtEnd);
|
||||
furi_thread_join(bad_bt->thread);
|
||||
furi_thread_free(bad_bt->thread);
|
||||
furi_string_free(bad_bt->file_path);
|
||||
furi_string_free(bad_bt->keyboard_layout);
|
||||
free(bad_bt);
|
||||
}
|
||||
|
||||
void bad_bt_script_set_keyboard_layout(BadBtScript* bad_bt, FuriString* layout_path) {
|
||||
furi_assert(bad_bt);
|
||||
|
||||
if((bad_bt->st.state == BadBtStateRunning) || (bad_bt->st.state == BadBtStateDelay)) {
|
||||
// do not update keyboard layout while a script is running
|
||||
return;
|
||||
}
|
||||
|
||||
File* layout_file = storage_file_alloc(furi_record_open(RECORD_STORAGE));
|
||||
if(!furi_string_empty(layout_path)) { //-V1051
|
||||
furi_string_set(bad_bt->keyboard_layout, layout_path);
|
||||
if(storage_file_open(
|
||||
layout_file, furi_string_get_cstr(layout_path), FSAM_READ, FSOM_OPEN_EXISTING)) {
|
||||
uint16_t layout[128];
|
||||
if(storage_file_read(layout_file, layout, sizeof(layout)) == sizeof(layout)) {
|
||||
memcpy(bad_bt->layout, layout, sizeof(layout));
|
||||
}
|
||||
}
|
||||
storage_file_close(layout_file);
|
||||
} else {
|
||||
bad_bt_script_set_default_keyboard_layout(bad_bt);
|
||||
}
|
||||
storage_file_free(layout_file);
|
||||
}
|
||||
|
||||
void bad_bt_script_toggle(BadBtScript* bad_bt) {
|
||||
furi_assert(bad_bt);
|
||||
furi_thread_flags_set(furi_thread_get_id(bad_bt->thread), WorkerEvtStartStop);
|
||||
}
|
||||
|
||||
BadBtState* bad_bt_script_get_state(BadBtScript* bad_bt) {
|
||||
furi_assert(bad_bt);
|
||||
return &(bad_bt->st);
|
||||
}
|
||||
154
applications/external/bad_bt/helpers/ducky_script.h
vendored
@@ -1,154 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <bt/bt_service/bt_i.h>
|
||||
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <gui/modules/widget.h>
|
||||
#include <gui/modules/variable_item_list.h>
|
||||
#include <gui/modules/text_input.h>
|
||||
#include <gui/modules/byte_input.h>
|
||||
#include "../views/bad_bt_view.h"
|
||||
|
||||
#define FILE_BUFFER_LEN 16
|
||||
|
||||
typedef enum {
|
||||
LevelRssi122_100,
|
||||
LevelRssi99_80,
|
||||
LevelRssi79_60,
|
||||
LevelRssi59_40,
|
||||
LevelRssi39_0,
|
||||
LevelRssiNum,
|
||||
LevelRssiError = 0xFF,
|
||||
} LevelRssiRange;
|
||||
|
||||
extern const uint8_t bt_hid_delays[LevelRssiNum];
|
||||
|
||||
extern uint8_t bt_timeout;
|
||||
|
||||
typedef enum {
|
||||
BadBtStateInit,
|
||||
BadBtStateNotConnected,
|
||||
BadBtStateIdle,
|
||||
BadBtStateWillRun,
|
||||
BadBtStateRunning,
|
||||
BadBtStateDelay,
|
||||
BadBtStateStringDelay,
|
||||
BadBtStateWaitForBtn,
|
||||
BadBtStateDone,
|
||||
BadBtStateScriptError,
|
||||
BadBtStateFileError,
|
||||
} BadBtWorkerState;
|
||||
|
||||
struct BadBtState {
|
||||
BadBtWorkerState state;
|
||||
uint32_t pin;
|
||||
uint16_t line_cur;
|
||||
uint16_t line_nb;
|
||||
uint32_t delay_remain;
|
||||
uint16_t error_line;
|
||||
char error[64];
|
||||
};
|
||||
|
||||
typedef struct BadBtApp BadBtApp;
|
||||
|
||||
typedef struct {
|
||||
FuriHalUsbHidConfig hid_cfg;
|
||||
FuriThread* thread;
|
||||
BadBtState st;
|
||||
|
||||
FuriString* file_path;
|
||||
FuriString* keyboard_layout;
|
||||
uint8_t file_buf[FILE_BUFFER_LEN + 1];
|
||||
uint8_t buf_start;
|
||||
uint8_t buf_len;
|
||||
bool file_end;
|
||||
|
||||
uint32_t defdelay;
|
||||
uint32_t stringdelay;
|
||||
uint16_t layout[128];
|
||||
|
||||
FuriString* line;
|
||||
FuriString* line_prev;
|
||||
uint32_t repeat_cnt;
|
||||
uint8_t key_hold_nb;
|
||||
|
||||
bool set_usb_id;
|
||||
bool set_bt_id;
|
||||
bool has_usb_id;
|
||||
bool has_bt_id;
|
||||
|
||||
FuriString* string_print;
|
||||
size_t string_print_pos;
|
||||
|
||||
Bt* bt;
|
||||
BadBtApp* app;
|
||||
} BadBtScript;
|
||||
|
||||
BadBtScript* bad_bt_script_open(FuriString* file_path, Bt* bt, BadBtApp* app);
|
||||
|
||||
void bad_bt_script_close(BadBtScript* bad_bt);
|
||||
|
||||
void bad_bt_script_set_keyboard_layout(BadBtScript* bad_bt, FuriString* layout_path);
|
||||
|
||||
void bad_bt_script_start(BadBtScript* bad_bt);
|
||||
|
||||
void bad_bt_script_stop(BadBtScript* bad_bt);
|
||||
|
||||
void bad_bt_script_toggle(BadBtScript* bad_bt);
|
||||
|
||||
BadBtState* bad_bt_script_get_state(BadBtScript* bad_bt);
|
||||
|
||||
#define BAD_BT_ADV_NAME_MAX_LEN FURI_HAL_BT_ADV_NAME_LENGTH
|
||||
#define BAD_BT_MAC_ADDRESS_LEN GAP_MAC_ADDR_SIZE
|
||||
|
||||
// this is the MAC address used when we do not forget paired device (BOUND STATE)
|
||||
extern const uint8_t BAD_BT_BOUND_MAC_ADDRESS[BAD_BT_MAC_ADDRESS_LEN];
|
||||
extern const uint8_t BAD_BT_EMPTY_MAC_ADDRESS[BAD_BT_MAC_ADDRESS_LEN];
|
||||
|
||||
typedef enum {
|
||||
BadBtAppErrorNoFiles,
|
||||
BadBtAppErrorCloseRpc,
|
||||
} BadBtAppError;
|
||||
|
||||
typedef struct {
|
||||
char bt_name[BAD_BT_ADV_NAME_MAX_LEN];
|
||||
uint8_t bt_mac[BAD_BT_MAC_ADDRESS_LEN];
|
||||
GapPairing bt_mode;
|
||||
} BadBtConfig;
|
||||
|
||||
struct BadBtApp {
|
||||
Gui* gui;
|
||||
ViewDispatcher* view_dispatcher;
|
||||
SceneManager* scene_manager;
|
||||
NotificationApp* notifications;
|
||||
DialogsApp* dialogs;
|
||||
Widget* widget;
|
||||
VariableItemList* var_item_list;
|
||||
TextInput* text_input;
|
||||
ByteInput* byte_input;
|
||||
|
||||
BadBtAppError error;
|
||||
FuriString* file_path;
|
||||
FuriString* keyboard_layout;
|
||||
BadBt* bad_bt_view;
|
||||
BadBtScript* bad_bt_script;
|
||||
|
||||
Bt* bt;
|
||||
bool bt_remember;
|
||||
BadBtConfig config;
|
||||
BadBtConfig prev_config;
|
||||
FuriThread* conn_init_thread;
|
||||
FuriThread* switch_mode_thread;
|
||||
};
|
||||
|
||||
int32_t bad_bt_config_switch_mode(BadBtApp* app);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,201 +0,0 @@
|
||||
#include <furi_hal.h>
|
||||
#include <furi_hal_bt_hid.h>
|
||||
#include "ducky_script.h"
|
||||
#include "ducky_script_i.h"
|
||||
|
||||
typedef int32_t (*DuckyCmdCallback)(BadBtScript* bad_bt, const char* line, int32_t param);
|
||||
|
||||
typedef struct {
|
||||
char* name;
|
||||
DuckyCmdCallback callback;
|
||||
int32_t param;
|
||||
} DuckyCmd;
|
||||
|
||||
static int32_t ducky_fnc_delay(BadBtScript* bad_bt, const char* line, int32_t param) {
|
||||
UNUSED(param);
|
||||
|
||||
line = &line[ducky_get_command_len(line) + 1];
|
||||
uint32_t delay_val = 0;
|
||||
bool state = ducky_get_number(line, &delay_val);
|
||||
if((state) && (delay_val > 0)) {
|
||||
return (int32_t)delay_val;
|
||||
}
|
||||
|
||||
return ducky_error(bad_bt, "Invalid number %s", line);
|
||||
}
|
||||
|
||||
static int32_t ducky_fnc_defdelay(BadBtScript* bad_bt, const char* line, int32_t param) {
|
||||
UNUSED(param);
|
||||
|
||||
line = &line[ducky_get_command_len(line) + 1];
|
||||
bool state = ducky_get_number(line, &bad_bt->defdelay);
|
||||
if(!state) {
|
||||
return ducky_error(bad_bt, "Invalid number %s", line);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t ducky_fnc_strdelay(BadBtScript* bad_bt, const char* line, int32_t param) {
|
||||
UNUSED(param);
|
||||
|
||||
line = &line[ducky_get_command_len(line) + 1];
|
||||
bool state = ducky_get_number(line, &bad_bt->stringdelay);
|
||||
if(!state) {
|
||||
return ducky_error(bad_bt, "Invalid number %s", line);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t ducky_fnc_string(BadBtScript* bad_bt, const char* line, int32_t param) {
|
||||
line = &line[ducky_get_command_len(line) + 1];
|
||||
furi_string_set_str(bad_bt->string_print, line);
|
||||
if(param == 1) {
|
||||
furi_string_cat(bad_bt->string_print, "\n");
|
||||
}
|
||||
|
||||
if(bad_bt->stringdelay == 0) { // stringdelay not set - run command immidiately
|
||||
bool state = ducky_string(bad_bt, furi_string_get_cstr(bad_bt->string_print));
|
||||
if(!state) {
|
||||
return ducky_error(bad_bt, "Invalid string %s", line);
|
||||
}
|
||||
} else { // stringdelay is set - run command in thread to keep handling external events
|
||||
return SCRIPT_STATE_STRING_START;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t ducky_fnc_repeat(BadBtScript* bad_bt, const char* line, int32_t param) {
|
||||
UNUSED(param);
|
||||
|
||||
line = &line[ducky_get_command_len(line) + 1];
|
||||
bool state = ducky_get_number(line, &bad_bt->repeat_cnt);
|
||||
if((!state) || (bad_bt->repeat_cnt == 0)) {
|
||||
return ducky_error(bad_bt, "Invalid number %s", line);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t ducky_fnc_sysrq(BadBtScript* bad_bt, const char* line, int32_t param) {
|
||||
UNUSED(param);
|
||||
|
||||
line = &line[ducky_get_command_len(line) + 1];
|
||||
uint16_t key = ducky_get_keycode(bad_bt, line, true);
|
||||
|
||||
furi_hal_bt_hid_kb_press(KEY_MOD_LEFT_ALT | HID_KEYBOARD_PRINT_SCREEN);
|
||||
furi_hal_bt_hid_kb_press(key);
|
||||
furi_delay_ms(bt_timeout);
|
||||
furi_hal_bt_hid_kb_release(key);
|
||||
furi_hal_bt_hid_kb_release(KEY_MOD_LEFT_ALT | HID_KEYBOARD_PRINT_SCREEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t ducky_fnc_altchar(BadBtScript* bad_bt, const char* line, int32_t param) {
|
||||
UNUSED(param);
|
||||
|
||||
line = &line[ducky_get_command_len(line) + 1];
|
||||
ducky_numlock_on(bad_bt);
|
||||
bool state = ducky_altchar(bad_bt, line);
|
||||
if(!state) {
|
||||
return ducky_error(bad_bt, "Invalid altchar %s", line);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t ducky_fnc_altstring(BadBtScript* bad_bt, const char* line, int32_t param) {
|
||||
UNUSED(param);
|
||||
|
||||
line = &line[ducky_get_command_len(line) + 1];
|
||||
ducky_numlock_on(bad_bt);
|
||||
bool state = ducky_altstring(bad_bt, line);
|
||||
if(!state) {
|
||||
return ducky_error(bad_bt, "Invalid altstring %s", line);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t ducky_fnc_hold(BadBtScript* bad_bt, const char* line, int32_t param) {
|
||||
UNUSED(param);
|
||||
|
||||
line = &line[ducky_get_command_len(line) + 1];
|
||||
uint16_t key = ducky_get_keycode(bad_bt, line, true);
|
||||
if(key == HID_KEYBOARD_NONE) {
|
||||
return ducky_error(bad_bt, "No keycode defined for %s", line);
|
||||
}
|
||||
bad_bt->key_hold_nb++;
|
||||
if(bad_bt->key_hold_nb > (HID_KB_MAX_KEYS - 1)) {
|
||||
return ducky_error(bad_bt, "Too many keys are hold");
|
||||
}
|
||||
furi_hal_bt_hid_kb_press(key);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t ducky_fnc_release(BadBtScript* bad_bt, const char* line, int32_t param) {
|
||||
UNUSED(param);
|
||||
|
||||
line = &line[ducky_get_command_len(line) + 1];
|
||||
uint16_t key = ducky_get_keycode(bad_bt, line, true);
|
||||
if(key == HID_KEYBOARD_NONE) {
|
||||
return ducky_error(bad_bt, "No keycode defined for %s", line);
|
||||
}
|
||||
if(bad_bt->key_hold_nb == 0) {
|
||||
return ducky_error(bad_bt, "No keys are hold");
|
||||
}
|
||||
bad_bt->key_hold_nb--;
|
||||
furi_hal_bt_hid_kb_release(key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t ducky_fnc_waitforbutton(BadBtScript* bad_bt, const char* line, int32_t param) {
|
||||
UNUSED(param);
|
||||
UNUSED(bad_bt);
|
||||
UNUSED(line);
|
||||
|
||||
return SCRIPT_STATE_WAIT_FOR_BTN;
|
||||
}
|
||||
|
||||
static const DuckyCmd ducky_commands[] = {
|
||||
{"REM", NULL, -1},
|
||||
{"ID", NULL, -1},
|
||||
{"BT_ID", NULL, -1},
|
||||
{"DELAY", ducky_fnc_delay, -1},
|
||||
{"STRING", ducky_fnc_string, 0},
|
||||
{"STRINGLN", ducky_fnc_string, 1},
|
||||
{"DEFAULT_DELAY", ducky_fnc_defdelay, -1},
|
||||
{"DEFAULTDELAY", ducky_fnc_defdelay, -1},
|
||||
{"STRINGDELAY", ducky_fnc_strdelay, -1},
|
||||
{"STRING_DELAY", ducky_fnc_strdelay, -1},
|
||||
{"REPEAT", ducky_fnc_repeat, -1},
|
||||
{"SYSRQ", ducky_fnc_sysrq, -1},
|
||||
{"ALTCHAR", ducky_fnc_altchar, -1},
|
||||
{"ALTSTRING", ducky_fnc_altstring, -1},
|
||||
{"ALTCODE", ducky_fnc_altstring, -1},
|
||||
{"HOLD", ducky_fnc_hold, -1},
|
||||
{"RELEASE", ducky_fnc_release, -1},
|
||||
{"WAIT_FOR_BUTTON_PRESS", ducky_fnc_waitforbutton, -1},
|
||||
};
|
||||
|
||||
#define TAG "BadBT"
|
||||
#define WORKER_TAG TAG "Worker"
|
||||
|
||||
int32_t ducky_execute_cmd(BadBtScript* bad_bt, const char* line) {
|
||||
size_t cmd_word_len = strcspn(line, " ");
|
||||
for(size_t i = 0; i < COUNT_OF(ducky_commands); i++) {
|
||||
size_t cmd_compare_len = strlen(ducky_commands[i].name);
|
||||
|
||||
if(cmd_compare_len != cmd_word_len) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(strncmp(line, ducky_commands[i].name, cmd_compare_len) == 0) {
|
||||
if(ducky_commands[i].callback == NULL) {
|
||||
return 0;
|
||||
} else {
|
||||
return ((ducky_commands[i].callback)(bad_bt, line, ducky_commands[i].param));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return SCRIPT_STATE_CMD_UNKNOWN;
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include "ducky_script.h"
|
||||
|
||||
#define SCRIPT_STATE_ERROR (-1)
|
||||
#define SCRIPT_STATE_END (-2)
|
||||
#define SCRIPT_STATE_NEXT_LINE (-3)
|
||||
#define SCRIPT_STATE_CMD_UNKNOWN (-4)
|
||||
#define SCRIPT_STATE_STRING_START (-5)
|
||||
#define SCRIPT_STATE_WAIT_FOR_BTN (-6)
|
||||
|
||||
uint16_t ducky_get_keycode(BadBtScript* bad_bt, const char* param, bool accept_chars);
|
||||
|
||||
uint32_t ducky_get_command_len(const char* line);
|
||||
|
||||
bool ducky_is_line_end(const char chr);
|
||||
|
||||
uint16_t ducky_get_keycode_by_name(const char* param);
|
||||
|
||||
bool ducky_get_number(const char* param, uint32_t* val);
|
||||
|
||||
void ducky_numlock_on(BadBtScript* bad_bt);
|
||||
|
||||
bool ducky_numpad_press(BadBtScript* bad_bt, const char num);
|
||||
|
||||
bool ducky_altchar(BadBtScript* bad_bt, const char* charcode);
|
||||
|
||||
bool ducky_altstring(BadBtScript* bad_bt, const char* param);
|
||||
|
||||
bool ducky_string(BadBtScript* bad_bt, const char* param);
|
||||
|
||||
int32_t ducky_execute_cmd(BadBtScript* bad_bt, const char* line);
|
||||
|
||||
int32_t ducky_error(BadBtScript* bad_bt, const char* text, ...);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,78 +0,0 @@
|
||||
#include <furi_hal.h>
|
||||
#include "ducky_script_i.h"
|
||||
|
||||
typedef struct {
|
||||
char* name;
|
||||
uint16_t keycode;
|
||||
} DuckyKey;
|
||||
|
||||
static const DuckyKey ducky_keys[] = {
|
||||
{"CTRL-ALT", KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_ALT},
|
||||
{"CTRL-SHIFT", KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_SHIFT},
|
||||
{"ALT-SHIFT", KEY_MOD_LEFT_ALT | KEY_MOD_LEFT_SHIFT},
|
||||
{"ALT-GUI", KEY_MOD_LEFT_ALT | KEY_MOD_LEFT_GUI},
|
||||
{"GUI-SHIFT", KEY_MOD_LEFT_GUI | KEY_MOD_LEFT_SHIFT},
|
||||
{"GUI-CTRL", KEY_MOD_LEFT_GUI | KEY_MOD_LEFT_CTRL},
|
||||
|
||||
{"CTRL", KEY_MOD_LEFT_CTRL},
|
||||
{"CONTROL", KEY_MOD_LEFT_CTRL},
|
||||
{"SHIFT", KEY_MOD_LEFT_SHIFT},
|
||||
{"ALT", KEY_MOD_LEFT_ALT},
|
||||
{"GUI", KEY_MOD_LEFT_GUI},
|
||||
{"WINDOWS", KEY_MOD_LEFT_GUI},
|
||||
|
||||
{"DOWNARROW", HID_KEYBOARD_DOWN_ARROW},
|
||||
{"DOWN", HID_KEYBOARD_DOWN_ARROW},
|
||||
{"LEFTARROW", HID_KEYBOARD_LEFT_ARROW},
|
||||
{"LEFT", HID_KEYBOARD_LEFT_ARROW},
|
||||
{"RIGHTARROW", HID_KEYBOARD_RIGHT_ARROW},
|
||||
{"RIGHT", HID_KEYBOARD_RIGHT_ARROW},
|
||||
{"UPARROW", HID_KEYBOARD_UP_ARROW},
|
||||
{"UP", HID_KEYBOARD_UP_ARROW},
|
||||
|
||||
{"ENTER", HID_KEYBOARD_RETURN},
|
||||
{"BREAK", HID_KEYBOARD_PAUSE},
|
||||
{"PAUSE", HID_KEYBOARD_PAUSE},
|
||||
{"CAPSLOCK", HID_KEYBOARD_CAPS_LOCK},
|
||||
{"DELETE", HID_KEYBOARD_DELETE_FORWARD},
|
||||
{"BACKSPACE", HID_KEYBOARD_DELETE},
|
||||
{"END", HID_KEYBOARD_END},
|
||||
{"ESC", HID_KEYBOARD_ESCAPE},
|
||||
{"ESCAPE", HID_KEYBOARD_ESCAPE},
|
||||
{"HOME", HID_KEYBOARD_HOME},
|
||||
{"INSERT", HID_KEYBOARD_INSERT},
|
||||
{"NUMLOCK", HID_KEYPAD_NUMLOCK},
|
||||
{"PAGEUP", HID_KEYBOARD_PAGE_UP},
|
||||
{"PAGEDOWN", HID_KEYBOARD_PAGE_DOWN},
|
||||
{"PRINTSCREEN", HID_KEYBOARD_PRINT_SCREEN},
|
||||
{"SCROLLLOCK", HID_KEYBOARD_SCROLL_LOCK},
|
||||
{"SPACE", HID_KEYBOARD_SPACEBAR},
|
||||
{"TAB", HID_KEYBOARD_TAB},
|
||||
{"MENU", HID_KEYBOARD_APPLICATION},
|
||||
{"APP", HID_KEYBOARD_APPLICATION},
|
||||
|
||||
{"F1", HID_KEYBOARD_F1},
|
||||
{"F2", HID_KEYBOARD_F2},
|
||||
{"F3", HID_KEYBOARD_F3},
|
||||
{"F4", HID_KEYBOARD_F4},
|
||||
{"F5", HID_KEYBOARD_F5},
|
||||
{"F6", HID_KEYBOARD_F6},
|
||||
{"F7", HID_KEYBOARD_F7},
|
||||
{"F8", HID_KEYBOARD_F8},
|
||||
{"F9", HID_KEYBOARD_F9},
|
||||
{"F10", HID_KEYBOARD_F10},
|
||||
{"F11", HID_KEYBOARD_F11},
|
||||
{"F12", HID_KEYBOARD_F12},
|
||||
};
|
||||
|
||||
uint16_t ducky_get_keycode_by_name(const char* param) {
|
||||
for(size_t i = 0; i < COUNT_OF(ducky_keys); i++) {
|
||||
size_t key_cmd_len = strlen(ducky_keys[i].name);
|
||||
if((strncmp(param, ducky_keys[i].name, key_cmd_len) == 0) &&
|
||||
(ducky_is_line_end(param[key_cmd_len]))) {
|
||||
return ducky_keys[i].keycode;
|
||||
}
|
||||
}
|
||||
|
||||
return HID_KEYBOARD_NONE;
|
||||
}
|
||||
BIN
applications/external/bad_bt/images/badbt_10px.png
vendored
|
Before Width: | Height: | Size: 576 B |
@@ -1,30 +0,0 @@
|
||||
#include "bad_bt_scene.h"
|
||||
|
||||
// Generate scene on_enter handlers array
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
|
||||
void (*const bad_bt_scene_on_enter_handlers[])(void*) = {
|
||||
#include "bad_bt_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 bad_bt_scene_on_event_handlers[])(void* context, SceneManagerEvent event) = {
|
||||
#include "bad_bt_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 bad_bt_scene_on_exit_handlers[])(void* context) = {
|
||||
#include "bad_bt_scene_config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Initialize scene handlers configuration structure
|
||||
const SceneManagerHandlers bad_bt_scene_handlers = {
|
||||
.on_enter_handlers = bad_bt_scene_on_enter_handlers,
|
||||
.on_event_handlers = bad_bt_scene_on_event_handlers,
|
||||
.on_exit_handlers = bad_bt_scene_on_exit_handlers,
|
||||
.scene_num = BadBtSceneNum,
|
||||
};
|
||||
@@ -1,29 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/scene_manager.h>
|
||||
|
||||
// Generate scene id and total number
|
||||
#define ADD_SCENE(prefix, name, id) BadBtScene##id,
|
||||
typedef enum {
|
||||
#include "bad_bt_scene_config.h"
|
||||
BadBtSceneNum,
|
||||
} BadBtScene;
|
||||
#undef ADD_SCENE
|
||||
|
||||
extern const SceneManagerHandlers bad_bt_scene_handlers;
|
||||
|
||||
// Generate scene on_enter handlers declaration
|
||||
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
|
||||
#include "bad_bt_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 "bad_bt_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 "bad_bt_scene_config.h"
|
||||
#undef ADD_SCENE
|
||||
@@ -1,104 +0,0 @@
|
||||
#include "../bad_bt_app.h"
|
||||
#include "../helpers/ducky_script.h"
|
||||
#include "furi_hal_power.h"
|
||||
|
||||
enum VarItemListIndex {
|
||||
VarItemListIndexKeyboardLayout,
|
||||
VarItemListIndexBtRemember,
|
||||
VarItemListIndexBtDeviceName,
|
||||
VarItemListIndexBtMacAddress,
|
||||
VarItemListIndexRandomizeBtMac,
|
||||
};
|
||||
|
||||
void bad_bt_scene_config_bt_remember_callback(VariableItem* item) {
|
||||
BadBtApp* bad_bt = variable_item_get_context(item);
|
||||
bad_bt->bt_remember = variable_item_get_current_value_index(item);
|
||||
variable_item_set_current_value_text(item, bad_bt->bt_remember ? "ON" : "OFF");
|
||||
view_dispatcher_send_custom_event(bad_bt->view_dispatcher, VarItemListIndexBtRemember);
|
||||
}
|
||||
|
||||
void bad_bt_scene_config_var_item_list_callback(void* context, uint32_t index) {
|
||||
BadBtApp* bad_bt = context;
|
||||
view_dispatcher_send_custom_event(bad_bt->view_dispatcher, index);
|
||||
}
|
||||
|
||||
void bad_bt_scene_config_on_enter(void* context) {
|
||||
BadBtApp* bad_bt = context;
|
||||
VariableItemList* var_item_list = bad_bt->var_item_list;
|
||||
VariableItem* item;
|
||||
|
||||
item = variable_item_list_add(var_item_list, "Keyboard layout", 0, NULL, bad_bt);
|
||||
|
||||
item = variable_item_list_add(
|
||||
var_item_list, "BT Remember", 2, bad_bt_scene_config_bt_remember_callback, bad_bt);
|
||||
variable_item_set_current_value_index(item, bad_bt->bt_remember);
|
||||
variable_item_set_current_value_text(item, bad_bt->bt_remember ? "ON" : "OFF");
|
||||
|
||||
item = variable_item_list_add(var_item_list, "BT Device Name", 0, NULL, bad_bt);
|
||||
if(bad_bt->bad_bt_script->set_bt_id) {
|
||||
variable_item_set_locked(item, true, "Script has\nBT_ID cmd!\nLocked to\nset Name!");
|
||||
}
|
||||
|
||||
item = variable_item_list_add(var_item_list, "BT MAC Address", 0, NULL, bad_bt);
|
||||
if(bad_bt->bt_remember) {
|
||||
variable_item_set_locked(item, true, "Remember\nmust be Off!");
|
||||
} else if(bad_bt->bad_bt_script->set_bt_id) {
|
||||
variable_item_set_locked(item, true, "Script has\nBT_ID cmd!\nLocked to\nset MAC!");
|
||||
}
|
||||
|
||||
item = variable_item_list_add(var_item_list, "Randomize BT MAC", 0, NULL, bad_bt);
|
||||
if(bad_bt->bt_remember) {
|
||||
variable_item_set_locked(item, true, "Remember\nmust be Off!");
|
||||
} else if(bad_bt->bad_bt_script->set_bt_id) {
|
||||
variable_item_set_locked(item, true, "Script has\nBT_ID cmd!\nLocked to\nset MAC!");
|
||||
}
|
||||
|
||||
variable_item_list_set_enter_callback(
|
||||
var_item_list, bad_bt_scene_config_var_item_list_callback, bad_bt);
|
||||
|
||||
variable_item_list_set_selected_item(
|
||||
var_item_list, scene_manager_get_scene_state(bad_bt->scene_manager, BadBtSceneConfig));
|
||||
|
||||
view_dispatcher_switch_to_view(bad_bt->view_dispatcher, BadBtAppViewConfig);
|
||||
}
|
||||
|
||||
bool bad_bt_scene_config_on_event(void* context, SceneManagerEvent event) {
|
||||
BadBtApp* bad_bt = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
scene_manager_set_scene_state(bad_bt->scene_manager, BadBtSceneConfig, event.event);
|
||||
consumed = true;
|
||||
switch(event.event) {
|
||||
case VarItemListIndexKeyboardLayout:
|
||||
scene_manager_next_scene(bad_bt->scene_manager, BadBtSceneConfigLayout);
|
||||
break;
|
||||
case VarItemListIndexBtRemember:
|
||||
bad_bt_config_switch_remember_mode(bad_bt);
|
||||
scene_manager_previous_scene(bad_bt->scene_manager);
|
||||
scene_manager_next_scene(bad_bt->scene_manager, BadBtSceneConfig);
|
||||
break;
|
||||
case VarItemListIndexBtDeviceName:
|
||||
scene_manager_next_scene(bad_bt->scene_manager, BadBtSceneConfigName);
|
||||
break;
|
||||
case VarItemListIndexBtMacAddress:
|
||||
scene_manager_next_scene(bad_bt->scene_manager, BadBtSceneConfigMac);
|
||||
break;
|
||||
case VarItemListIndexRandomizeBtMac:
|
||||
furi_hal_random_fill_buf(bad_bt->config.bt_mac, BAD_BT_MAC_ADDRESS_LEN);
|
||||
bt_set_profile_mac_address(bad_bt->bt, bad_bt->config.bt_mac);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void bad_bt_scene_config_on_exit(void* context) {
|
||||
BadBtApp* bad_bt = context;
|
||||
VariableItemList* var_item_list = bad_bt->var_item_list;
|
||||
|
||||
variable_item_list_reset(var_item_list);
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
ADD_SCENE(bad_bt, file_select, FileSelect)
|
||||
ADD_SCENE(bad_bt, work, Work)
|
||||
ADD_SCENE(bad_bt, error, Error)
|
||||
ADD_SCENE(bad_bt, config, Config)
|
||||
ADD_SCENE(bad_bt, config_layout, ConfigLayout)
|
||||
ADD_SCENE(bad_bt, config_name, ConfigName)
|
||||
ADD_SCENE(bad_bt, config_mac, ConfigMac)
|
||||
@@ -1,47 +0,0 @@
|
||||
#include "../bad_bt_app.h"
|
||||
#include "furi_hal_power.h"
|
||||
#include <storage/storage.h>
|
||||
|
||||
static bool bad_bt_layout_select(BadBtApp* bad_bt) {
|
||||
furi_assert(bad_bt);
|
||||
|
||||
FuriString* predefined_path;
|
||||
predefined_path = furi_string_alloc();
|
||||
if(!furi_string_empty(bad_bt->keyboard_layout)) {
|
||||
furi_string_set(predefined_path, bad_bt->keyboard_layout);
|
||||
} else {
|
||||
furi_string_set(predefined_path, BAD_BT_APP_PATH_LAYOUT_FOLDER);
|
||||
}
|
||||
|
||||
DialogsFileBrowserOptions browser_options;
|
||||
dialog_file_browser_set_basic_options(
|
||||
&browser_options, BAD_BT_APP_LAYOUT_EXTENSION, &I_keyboard_10px);
|
||||
browser_options.base_path = BAD_BT_APP_PATH_LAYOUT_FOLDER;
|
||||
browser_options.skip_assets = false;
|
||||
|
||||
// Input events and views are managed by file_browser
|
||||
bool res = dialog_file_browser_show(
|
||||
bad_bt->dialogs, bad_bt->keyboard_layout, predefined_path, &browser_options);
|
||||
|
||||
furi_string_free(predefined_path);
|
||||
return res;
|
||||
}
|
||||
|
||||
void bad_bt_scene_config_layout_on_enter(void* context) {
|
||||
BadBtApp* bad_bt = context;
|
||||
|
||||
if(bad_bt_layout_select(bad_bt)) {
|
||||
bad_bt_script_set_keyboard_layout(bad_bt->bad_bt_script, bad_bt->keyboard_layout);
|
||||
}
|
||||
scene_manager_previous_scene(bad_bt->scene_manager);
|
||||
}
|
||||
|
||||
bool bad_bt_scene_config_layout_on_event(void* context, SceneManagerEvent event) {
|
||||
UNUSED(context);
|
||||
UNUSED(event);
|
||||
return false;
|
||||
}
|
||||
|
||||
void bad_bt_scene_config_layout_on_exit(void* context) {
|
||||
UNUSED(context);
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
#include "../bad_bt_app.h"
|
||||
|
||||
#define TAG "BadBtConfigMac"
|
||||
|
||||
void bad_bt_scene_config_mac_byte_input_callback(void* context) {
|
||||
BadBtApp* bad_bt = context;
|
||||
|
||||
view_dispatcher_send_custom_event(bad_bt->view_dispatcher, BadBtAppCustomEventByteInputDone);
|
||||
}
|
||||
|
||||
void bad_bt_scene_config_mac_on_enter(void* context) {
|
||||
BadBtApp* bad_bt = context;
|
||||
|
||||
furi_hal_bt_reverse_mac_addr(bad_bt->config.bt_mac);
|
||||
|
||||
// Setup view
|
||||
ByteInput* byte_input = bad_bt->byte_input;
|
||||
byte_input_set_header_text(byte_input, "Set BT MAC address");
|
||||
byte_input_set_result_callback(
|
||||
byte_input,
|
||||
bad_bt_scene_config_mac_byte_input_callback,
|
||||
NULL,
|
||||
bad_bt,
|
||||
bad_bt->config.bt_mac,
|
||||
GAP_MAC_ADDR_SIZE);
|
||||
view_dispatcher_switch_to_view(bad_bt->view_dispatcher, BadBtAppViewConfigMac);
|
||||
}
|
||||
|
||||
bool bad_bt_scene_config_mac_on_event(void* context, SceneManagerEvent event) {
|
||||
BadBtApp* bad_bt = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == BadBtAppCustomEventByteInputDone) {
|
||||
scene_manager_previous_scene(bad_bt->scene_manager);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void bad_bt_scene_config_mac_on_exit(void* context) {
|
||||
BadBtApp* bad_bt = context;
|
||||
|
||||
furi_hal_bt_reverse_mac_addr(bad_bt->config.bt_mac);
|
||||
|
||||
bt_set_profile_mac_address(bad_bt->bt, bad_bt->config.bt_mac);
|
||||
|
||||
// Clear view
|
||||
byte_input_set_result_callback(bad_bt->byte_input, NULL, NULL, NULL, NULL, 0);
|
||||
byte_input_set_header_text(bad_bt->byte_input, "");
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
#include "../bad_bt_app.h"
|
||||
|
||||
static void bad_bt_scene_config_name_text_input_callback(void* context) {
|
||||
BadBtApp* bad_bt = context;
|
||||
|
||||
view_dispatcher_send_custom_event(bad_bt->view_dispatcher, BadBtAppCustomEventTextEditResult);
|
||||
}
|
||||
|
||||
void bad_bt_scene_config_name_on_enter(void* context) {
|
||||
BadBtApp* bad_bt = context;
|
||||
TextInput* text_input = bad_bt->text_input;
|
||||
|
||||
text_input_set_header_text(text_input, "Set BT device name");
|
||||
|
||||
text_input_set_result_callback(
|
||||
text_input,
|
||||
bad_bt_scene_config_name_text_input_callback,
|
||||
bad_bt,
|
||||
bad_bt->config.bt_name,
|
||||
BAD_BT_ADV_NAME_MAX_LEN,
|
||||
true);
|
||||
|
||||
view_dispatcher_switch_to_view(bad_bt->view_dispatcher, BadBtAppViewConfigName);
|
||||
}
|
||||
|
||||
bool bad_bt_scene_config_name_on_event(void* context, SceneManagerEvent event) {
|
||||
BadBtApp* bad_bt = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
consumed = true;
|
||||
if(event.event == BadBtAppCustomEventTextEditResult) {
|
||||
bt_set_profile_adv_name(bad_bt->bt, bad_bt->config.bt_name);
|
||||
}
|
||||
scene_manager_previous_scene(bad_bt->scene_manager);
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void bad_bt_scene_config_name_on_exit(void* context) {
|
||||
BadBtApp* bad_bt = context;
|
||||
TextInput* text_input = bad_bt->text_input;
|
||||
|
||||
text_input_reset(text_input);
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
#include "../bad_bt_app.h"
|
||||
|
||||
static void
|
||||
bad_bt_scene_error_event_callback(GuiButtonType result, InputType type, void* context) {
|
||||
furi_assert(context);
|
||||
BadBtApp* app = context;
|
||||
|
||||
if((result == GuiButtonTypeLeft) && (type == InputTypeShort)) {
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, BadBtCustomEventErrorBack);
|
||||
}
|
||||
}
|
||||
|
||||
void bad_bt_scene_error_on_enter(void* context) {
|
||||
BadBtApp* app = context;
|
||||
|
||||
if(app->error == BadBtAppErrorNoFiles) {
|
||||
widget_add_icon_element(app->widget, 0, 0, &I_SDQuestion_35x43);
|
||||
widget_add_string_multiline_element(
|
||||
app->widget,
|
||||
81,
|
||||
4,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
FontSecondary,
|
||||
"No SD card or\napp data found.\nThis app will not\nwork without\nrequired files.");
|
||||
widget_add_button_element(
|
||||
app->widget, GuiButtonTypeLeft, "Back", bad_bt_scene_error_event_callback, app);
|
||||
} else if(app->error == BadBtAppErrorCloseRpc) {
|
||||
widget_add_icon_element(app->widget, 78, 0, &I_ActiveConnection_50x64);
|
||||
widget_add_string_multiline_element(
|
||||
app->widget, 3, 2, AlignLeft, AlignTop, FontPrimary, "Connection\nis active!");
|
||||
widget_add_string_multiline_element(
|
||||
app->widget,
|
||||
3,
|
||||
30,
|
||||
AlignLeft,
|
||||
AlignTop,
|
||||
FontSecondary,
|
||||
"Disconnect from\nPC or phone to\nuse this function.");
|
||||
}
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, BadBtAppViewError);
|
||||
}
|
||||
|
||||
bool bad_bt_scene_error_on_event(void* context, SceneManagerEvent event) {
|
||||
BadBtApp* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == BadBtCustomEventErrorBack) {
|
||||
view_dispatcher_stop(app->view_dispatcher);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void bad_bt_scene_error_on_exit(void* context) {
|
||||
BadBtApp* app = context;
|
||||
widget_reset(app->widget);
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
#include "../bad_bt_app.h"
|
||||
#include <furi_hal_power.h>
|
||||
#include <storage/storage.h>
|
||||
|
||||
static bool bad_bt_file_select(BadBtApp* bad_bt) {
|
||||
furi_assert(bad_bt);
|
||||
|
||||
DialogsFileBrowserOptions browser_options;
|
||||
dialog_file_browser_set_basic_options(
|
||||
&browser_options, BAD_BT_APP_SCRIPT_EXTENSION, &I_badbt_10px);
|
||||
browser_options.base_path = BAD_BT_APP_BASE_FOLDER;
|
||||
browser_options.skip_assets = true;
|
||||
|
||||
// Input events and views are managed by file_browser
|
||||
bool res = dialog_file_browser_show(
|
||||
bad_bt->dialogs, bad_bt->file_path, bad_bt->file_path, &browser_options);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void bad_bt_scene_file_select_on_enter(void* context) {
|
||||
BadBtApp* bad_bt = context;
|
||||
|
||||
if(bad_bt->bad_bt_script) {
|
||||
bad_bt_script_close(bad_bt->bad_bt_script);
|
||||
bad_bt->bad_bt_script = NULL;
|
||||
}
|
||||
|
||||
if(bad_bt_file_select(bad_bt)) {
|
||||
bad_bt->bad_bt_script = bad_bt_script_open(bad_bt->file_path, bad_bt->bt, bad_bt);
|
||||
bad_bt_script_set_keyboard_layout(bad_bt->bad_bt_script, bad_bt->keyboard_layout);
|
||||
|
||||
scene_manager_next_scene(bad_bt->scene_manager, BadBtSceneWork);
|
||||
} else {
|
||||
view_dispatcher_stop(bad_bt->view_dispatcher);
|
||||
}
|
||||
}
|
||||
|
||||
bool bad_bt_scene_file_select_on_event(void* context, SceneManagerEvent event) {
|
||||
UNUSED(context);
|
||||
UNUSED(event);
|
||||
// BadBtApp* bad_bt = context;
|
||||
return false;
|
||||
}
|
||||
|
||||
void bad_bt_scene_file_select_on_exit(void* context) {
|
||||
UNUSED(context);
|
||||
// BadBtApp* bad_bt = context;
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
#include "../helpers/ducky_script.h"
|
||||
#include "../bad_bt_app.h"
|
||||
#include "../views/bad_bt_view.h"
|
||||
#include <furi_hal.h>
|
||||
#include "toolbox/path.h"
|
||||
|
||||
void bad_bt_scene_work_button_callback(InputKey key, void* context) {
|
||||
furi_assert(context);
|
||||
BadBtApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, key);
|
||||
}
|
||||
|
||||
bool bad_bt_scene_work_on_event(void* context, SceneManagerEvent event) {
|
||||
BadBtApp* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == InputKeyLeft) {
|
||||
if(bad_bt_is_idle_state(app->bad_bt_view)) {
|
||||
scene_manager_next_scene(app->scene_manager, BadBtSceneConfig);
|
||||
}
|
||||
consumed = true;
|
||||
} else if(event.event == InputKeyOk) {
|
||||
bad_bt_script_toggle(app->bad_bt_script);
|
||||
consumed = true;
|
||||
}
|
||||
} else if(event.type == SceneManagerEventTypeTick) {
|
||||
bad_bt_set_state(app->bad_bt_view, bad_bt_script_get_state(app->bad_bt_script));
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void bad_bt_scene_work_on_enter(void* context) {
|
||||
BadBtApp* app = context;
|
||||
|
||||
FuriString* file_name;
|
||||
file_name = furi_string_alloc();
|
||||
path_extract_filename(app->file_path, file_name, true);
|
||||
bad_bt_set_file_name(app->bad_bt_view, furi_string_get_cstr(file_name));
|
||||
furi_string_free(file_name);
|
||||
|
||||
FuriString* layout;
|
||||
layout = furi_string_alloc();
|
||||
path_extract_filename(app->keyboard_layout, layout, true);
|
||||
bad_bt_set_layout(app->bad_bt_view, furi_string_get_cstr(layout));
|
||||
furi_string_free(layout);
|
||||
|
||||
bad_bt_set_state(app->bad_bt_view, bad_bt_script_get_state(app->bad_bt_script));
|
||||
|
||||
bad_bt_set_button_callback(app->bad_bt_view, bad_bt_scene_work_button_callback, app);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, BadBtAppViewWork);
|
||||
}
|
||||
|
||||
void bad_bt_scene_work_on_exit(void* context) {
|
||||
UNUSED(context);
|
||||
}
|
||||
233
applications/external/bad_bt/views/bad_bt_view.c
vendored
@@ -1,233 +0,0 @@
|
||||
#include "bad_bt_view.h"
|
||||
#include "../helpers/ducky_script.h"
|
||||
#include "../bad_bt_app.h"
|
||||
#include <toolbox/path.h>
|
||||
#include <gui/elements.h>
|
||||
#include <assets_icons.h>
|
||||
|
||||
#define MAX_NAME_LEN 64
|
||||
|
||||
typedef struct {
|
||||
char file_name[MAX_NAME_LEN];
|
||||
char layout[MAX_NAME_LEN];
|
||||
BadBtState state;
|
||||
uint8_t anim_frame;
|
||||
} BadBtModel;
|
||||
|
||||
static void bad_bt_draw_callback(Canvas* canvas, void* _model) {
|
||||
BadBtModel* model = _model;
|
||||
|
||||
FuriString* disp_str;
|
||||
disp_str = furi_string_alloc_set("(BT) ");
|
||||
furi_string_cat_str(disp_str, model->file_name);
|
||||
elements_string_fit_width(canvas, disp_str, 128 - 2);
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str(canvas, 2, 8, furi_string_get_cstr(disp_str));
|
||||
|
||||
if(strlen(model->layout) == 0) {
|
||||
furi_string_set(disp_str, "(default)");
|
||||
} else {
|
||||
furi_string_reset(disp_str);
|
||||
furi_string_push_back(disp_str, '(');
|
||||
for(size_t i = 0; i < strlen(model->layout); i++)
|
||||
furi_string_push_back(disp_str, model->layout[i]);
|
||||
furi_string_push_back(disp_str, ')');
|
||||
}
|
||||
if(model->state.pin) {
|
||||
furi_string_cat_printf(disp_str, " PIN: %ld", model->state.pin);
|
||||
}
|
||||
elements_string_fit_width(canvas, disp_str, 128 - 2);
|
||||
canvas_draw_str(
|
||||
canvas, 2, 8 + canvas_current_font_height(canvas), furi_string_get_cstr(disp_str));
|
||||
|
||||
furi_string_reset(disp_str);
|
||||
|
||||
if((model->state.state == BadBtStateIdle) || (model->state.state == BadBtStateDone) ||
|
||||
(model->state.state == BadBtStateNotConnected)) {
|
||||
elements_button_center(canvas, "Run");
|
||||
elements_button_left(canvas, "Config");
|
||||
} else if((model->state.state == BadBtStateRunning) || (model->state.state == BadBtStateDelay)) {
|
||||
elements_button_center(canvas, "Stop");
|
||||
} else if(model->state.state == BadBtStateWaitForBtn) {
|
||||
elements_button_center(canvas, "Press to continue");
|
||||
} else if(model->state.state == BadBtStateWillRun) {
|
||||
elements_button_center(canvas, "Cancel");
|
||||
}
|
||||
|
||||
if(model->state.state == BadBtStateNotConnected) {
|
||||
canvas_draw_icon(canvas, 4, 26, &I_Clock_18x18);
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(canvas, 127, 31, AlignRight, AlignBottom, "Connect to");
|
||||
canvas_draw_str_aligned(canvas, 127, 43, AlignRight, AlignBottom, "a device");
|
||||
} else if(model->state.state == BadBtStateWillRun) {
|
||||
canvas_draw_icon(canvas, 4, 26, &I_Clock_18x18);
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(canvas, 127, 31, AlignRight, AlignBottom, "Will run");
|
||||
canvas_draw_str_aligned(canvas, 127, 43, AlignRight, AlignBottom, "on connect");
|
||||
} else if(model->state.state == BadBtStateFileError) {
|
||||
canvas_draw_icon(canvas, 4, 26, &I_Error_18x18);
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(canvas, 127, 31, AlignRight, AlignBottom, "File");
|
||||
canvas_draw_str_aligned(canvas, 127, 43, AlignRight, AlignBottom, "ERROR");
|
||||
} else if(model->state.state == BadBtStateScriptError) {
|
||||
canvas_draw_icon(canvas, 4, 26, &I_Error_18x18);
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(canvas, 127, 33, AlignRight, AlignBottom, "ERROR:");
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
furi_string_printf(disp_str, "line %u", model->state.error_line);
|
||||
canvas_draw_str_aligned(
|
||||
canvas, 127, 46, AlignRight, AlignBottom, furi_string_get_cstr(disp_str));
|
||||
furi_string_reset(disp_str);
|
||||
furi_string_set_str(disp_str, model->state.error);
|
||||
elements_string_fit_width(canvas, disp_str, canvas_width(canvas));
|
||||
canvas_draw_str_aligned(
|
||||
canvas, 127, 56, AlignRight, AlignBottom, furi_string_get_cstr(disp_str));
|
||||
furi_string_reset(disp_str);
|
||||
} else if(model->state.state == BadBtStateIdle) {
|
||||
canvas_draw_icon(canvas, 4, 26, &I_Smile_18x18);
|
||||
canvas_set_font(canvas, FontBigNumbers);
|
||||
canvas_draw_str_aligned(canvas, 114, 40, AlignRight, AlignBottom, "0");
|
||||
canvas_draw_icon(canvas, 117, 26, &I_Percent_10x14);
|
||||
} else if(model->state.state == BadBtStateRunning) {
|
||||
if(model->anim_frame == 0) {
|
||||
canvas_draw_icon(canvas, 4, 23, &I_EviSmile1_18x21);
|
||||
} else {
|
||||
canvas_draw_icon(canvas, 4, 23, &I_EviSmile2_18x21);
|
||||
}
|
||||
canvas_set_font(canvas, FontBigNumbers);
|
||||
furi_string_printf(
|
||||
disp_str, "%u", ((model->state.line_cur - 1) * 100) / model->state.line_nb);
|
||||
canvas_draw_str_aligned(
|
||||
canvas, 114, 40, AlignRight, AlignBottom, furi_string_get_cstr(disp_str));
|
||||
furi_string_reset(disp_str);
|
||||
canvas_draw_icon(canvas, 117, 26, &I_Percent_10x14);
|
||||
} else if(model->state.state == BadBtStateDone) {
|
||||
canvas_draw_icon(canvas, 4, 23, &I_EviSmile1_18x21);
|
||||
canvas_set_font(canvas, FontBigNumbers);
|
||||
canvas_draw_str_aligned(canvas, 114, 40, AlignRight, AlignBottom, "100");
|
||||
furi_string_reset(disp_str);
|
||||
canvas_draw_icon(canvas, 117, 26, &I_Percent_10x14);
|
||||
} else if(model->state.state == BadBtStateDelay) {
|
||||
if(model->anim_frame == 0) {
|
||||
canvas_draw_icon(canvas, 4, 23, &I_EviWaiting1_18x21);
|
||||
} else {
|
||||
canvas_draw_icon(canvas, 4, 23, &I_EviWaiting2_18x21);
|
||||
}
|
||||
canvas_set_font(canvas, FontBigNumbers);
|
||||
furi_string_printf(
|
||||
disp_str, "%u", ((model->state.line_cur - 1) * 100) / model->state.line_nb);
|
||||
canvas_draw_str_aligned(
|
||||
canvas, 114, 40, AlignRight, AlignBottom, furi_string_get_cstr(disp_str));
|
||||
furi_string_reset(disp_str);
|
||||
canvas_draw_icon(canvas, 117, 26, &I_Percent_10x14);
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
furi_string_printf(disp_str, "delay %lus", model->state.delay_remain);
|
||||
canvas_draw_str_aligned(
|
||||
canvas, 127, 50, AlignRight, AlignBottom, furi_string_get_cstr(disp_str));
|
||||
furi_string_reset(disp_str);
|
||||
} else {
|
||||
canvas_draw_icon(canvas, 4, 26, &I_Clock_18x18);
|
||||
}
|
||||
|
||||
furi_string_free(disp_str);
|
||||
}
|
||||
|
||||
static bool bad_bt_input_callback(InputEvent* event, void* context) {
|
||||
furi_assert(context);
|
||||
BadBt* bad_bt = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event->type == InputTypeShort) {
|
||||
if((event->key == InputKeyLeft) || (event->key == InputKeyOk)) {
|
||||
consumed = true;
|
||||
furi_assert(bad_bt->callback);
|
||||
bad_bt->callback(event->key, bad_bt->context);
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
BadBt* bad_bt_alloc() {
|
||||
BadBt* bad_bt = malloc(sizeof(BadBt));
|
||||
|
||||
bad_bt->view = view_alloc();
|
||||
view_allocate_model(bad_bt->view, ViewModelTypeLocking, sizeof(BadBtModel));
|
||||
view_set_context(bad_bt->view, bad_bt);
|
||||
view_set_draw_callback(bad_bt->view, bad_bt_draw_callback);
|
||||
view_set_input_callback(bad_bt->view, bad_bt_input_callback);
|
||||
|
||||
return bad_bt;
|
||||
}
|
||||
|
||||
void bad_bt_free(BadBt* bad_bt) {
|
||||
furi_assert(bad_bt);
|
||||
view_free(bad_bt->view);
|
||||
free(bad_bt);
|
||||
}
|
||||
|
||||
View* bad_bt_get_view(BadBt* bad_bt) {
|
||||
furi_assert(bad_bt);
|
||||
return bad_bt->view;
|
||||
}
|
||||
|
||||
void bad_bt_set_button_callback(BadBt* bad_bt, BadBtButtonCallback callback, void* context) {
|
||||
furi_assert(bad_bt);
|
||||
furi_assert(callback);
|
||||
with_view_model(
|
||||
bad_bt->view,
|
||||
BadBtModel * model,
|
||||
{
|
||||
UNUSED(model);
|
||||
bad_bt->callback = callback;
|
||||
bad_bt->context = context;
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
void bad_bt_set_file_name(BadBt* bad_bt, const char* name) {
|
||||
furi_assert(name);
|
||||
with_view_model(
|
||||
bad_bt->view, BadBtModel * model, { strlcpy(model->file_name, name, MAX_NAME_LEN); }, true);
|
||||
}
|
||||
|
||||
void bad_bt_set_layout(BadBt* bad_bt, const char* layout) {
|
||||
furi_assert(layout);
|
||||
with_view_model(
|
||||
bad_bt->view, BadBtModel * model, { strlcpy(model->layout, layout, MAX_NAME_LEN); }, true);
|
||||
}
|
||||
|
||||
void bad_bt_set_state(BadBt* bad_bt, BadBtState* st) {
|
||||
furi_assert(st);
|
||||
uint32_t pin = 0;
|
||||
if(bad_bt->context != NULL) {
|
||||
BadBtApp* app = bad_bt->context;
|
||||
if(app->bt != NULL) {
|
||||
pin = app->bt->pin;
|
||||
}
|
||||
}
|
||||
st->pin = pin;
|
||||
with_view_model(
|
||||
bad_bt->view,
|
||||
BadBtModel * model,
|
||||
{
|
||||
memcpy(&(model->state), st, sizeof(BadBtState));
|
||||
model->anim_frame ^= 1;
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
bool bad_bt_is_idle_state(BadBt* bad_bt) {
|
||||
bool is_idle = false;
|
||||
with_view_model(
|
||||
bad_bt->view,
|
||||
BadBtModel * model,
|
||||
{
|
||||
if((model->state.state == BadBtStateIdle) || (model->state.state == BadBtStateDone) ||
|
||||
(model->state.state == BadBtStateNotConnected)) {
|
||||
is_idle = true;
|
||||
}
|
||||
},
|
||||
false);
|
||||
return is_idle;
|
||||
}
|
||||
29
applications/external/bad_bt/views/bad_bt_view.h
vendored
@@ -1,29 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
|
||||
typedef void (*BadBtButtonCallback)(InputKey key, void* context);
|
||||
|
||||
typedef struct {
|
||||
View* view;
|
||||
BadBtButtonCallback callback;
|
||||
void* context;
|
||||
} BadBt;
|
||||
|
||||
typedef struct BadBtState BadBtState;
|
||||
|
||||
BadBt* bad_bt_alloc();
|
||||
|
||||
void bad_bt_free(BadBt* bad_bt);
|
||||
|
||||
View* bad_bt_get_view(BadBt* bad_bt);
|
||||
|
||||
void bad_bt_set_button_callback(BadBt* bad_bt, BadBtButtonCallback callback, void* context);
|
||||
|
||||
void bad_bt_set_file_name(BadBt* bad_bt, const char* name);
|
||||
|
||||
void bad_bt_set_layout(BadBt* bad_bt, const char* layout);
|
||||
|
||||
void bad_bt_set_state(BadBt* bad_bt, BadBtState* st);
|
||||
|
||||
bool bad_bt_is_idle_state(BadBt* bad_bt);
|
||||
22
applications/external/barcode_gen/LICENSE
vendored
@@ -1,22 +0,0 @@
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 Alan Tsui
|
||||
|
||||
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.
|
||||