mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-06-20 20:38:24 -07:00
V50 Release (#340)
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
|
||||
export VERSION_TAG="$(python -c 'import fbt_options; print(fbt_options.DIST_SUFFIX, end="")')"
|
||||
echo "VERSION_TAG=${VERSION_TAG}" >> $GITHUB_ENV
|
||||
@@ -0,0 +1,65 @@
|
||||
#!/usr/bin/env python
|
||||
import nextcloud_client
|
||||
import datetime as dt
|
||||
import requests
|
||||
import json
|
||||
import os
|
||||
|
||||
dev_share = os.environ["NC_HOST"] + "s/sGHsQB94a9x5CRs/download?path=/&files={files}"
|
||||
|
||||
if __name__ == "__main__":
|
||||
with open(os.environ["GITHUB_EVENT_PATH"], "r") as f:
|
||||
event = json.load(f)
|
||||
|
||||
client = nextcloud_client.Client(os.environ["NC_HOST"])
|
||||
client.login(os.environ["NC_USER"], os.environ["NC_PASS"])
|
||||
|
||||
for file in (
|
||||
os.environ["ARTIFACT_TGZ"],
|
||||
os.environ["ARTIFACT_SDK"],
|
||||
):
|
||||
path = f"XFW-Dev/{file}"
|
||||
# try:
|
||||
# client.delete(path)
|
||||
# except Exception:
|
||||
# pass
|
||||
client.put_file(path, file)
|
||||
|
||||
requests.post(
|
||||
os.environ["BUILD_WEBHOOK"],
|
||||
headers={"Accept": "application/json", "Content-Type": "application/json"},
|
||||
json={
|
||||
"content": None,
|
||||
"embeds": [
|
||||
{
|
||||
"title": "Devbuild infos:",
|
||||
"description": "",
|
||||
"url": "",
|
||||
"color": 16734443,
|
||||
"fields": [
|
||||
{
|
||||
"name": "Changes since last commit:",
|
||||
"value": f"[Compare {event['before'][:7]} to {event['after'][:7]}]({event['compare']})"
|
||||
},
|
||||
{
|
||||
"name": "Changes since last release:",
|
||||
"value": f"[Compare release to {event['after'][:7]}]({event['compare'].rsplit('/', 1)[0] + '/main...' + event['after']})"
|
||||
},
|
||||
{
|
||||
"name": "Firmware download:",
|
||||
"value": f"- [Download SDK for development]({dev_share.format(files=os.environ['ARTIFACT_SDK'])})\n- [Download Firmware TGZ]({dev_share.format(files=os.environ['ARTIFACT_TGZ'])})"
|
||||
}
|
||||
],
|
||||
"author": {
|
||||
"name": "Build Succeeded!",
|
||||
"icon_url": "https://cdn.discordapp.com/emojis/1080005692485795930.png"
|
||||
},
|
||||
"footer": {
|
||||
"text": "Build go brrrr",
|
||||
"icon_url": "https://cdn.discordapp.com/emojis/1059798228725403719.png"
|
||||
},
|
||||
"timestamp": dt.datetime.utcnow().isoformat()
|
||||
}
|
||||
],
|
||||
},
|
||||
)
|
||||
@@ -21,7 +21,8 @@ if __name__ == "__main__":
|
||||
|
||||
artifacts = {
|
||||
os.environ['ARTIFACT_TGZ']: "application/gzip",
|
||||
os.environ['ARTIFACT_ZIP']: "application/zip"
|
||||
os.environ['ARTIFACT_ZIP']: "application/zip",
|
||||
os.environ['ARTIFACT_SDK']: "application/zip",
|
||||
}
|
||||
|
||||
for asset in release["assets"]:
|
||||
@@ -59,7 +60,7 @@ if __name__ == "__main__":
|
||||
|
||||
body = release["body"]
|
||||
body = re.sub(
|
||||
r"(https://github\.com/ClaraCrazy/Flipper-Xtreme/releases/download/[A-Za-z0-9_-]+?/)[A-Za-z0-9_-]+",
|
||||
r"(https://github\.com/Flipper-XFW/Xtreme-Firmware/releases/download/[A-Za-z0-9_-]+?/)[A-Za-z0-9_-]+",
|
||||
r"\1" + os.environ['VERSION_TAG'],
|
||||
body
|
||||
)
|
||||
|
||||
@@ -3,12 +3,16 @@ export ARTIFACT_DIR="${VERSION_TAG}"
|
||||
|
||||
export ARTIFACT_TGZ="${VERSION_TAG}.tgz"
|
||||
export ARTIFACT_ZIP="${VERSION_TAG}.zip"
|
||||
export ARTIFACT_SDK="${VERSION_TAG}-sdk.zip"
|
||||
cd dist/${DEFAULT_TARGET}-*
|
||||
mv ${DEFAULT_TARGET}-update-* ${ARTIFACT_DIR}
|
||||
tar --format=ustar -czvf ../../${ARTIFACT_TGZ} ${ARTIFACT_DIR}
|
||||
cd ${ARTIFACT_DIR}
|
||||
7z a ../../../${ARTIFACT_ZIP} .
|
||||
cd ../../..
|
||||
cd ..
|
||||
mv flipper-z-${DEFAULT_TARGET}-sdk-*.zip ../../${ARTIFACT_SDK}
|
||||
cd ../..
|
||||
|
||||
echo "ARTIFACT_TGZ=${ARTIFACT_TGZ}" >> $GITHUB_ENV
|
||||
echo "ARTIFACT_ZIP=${ARTIFACT_ZIP}" >> $GITHUB_ENV
|
||||
echo "ARTIFACT_SDK=${ARTIFACT_SDK}" >> $GITHUB_ENV
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
## ⬇️ Download
|
||||
>### [🖥️ Web Updater (chrome)](https://flipper-xtre.me/update) [recommended]
|
||||
|
||||
>### [🐬 qFlipper Package (.tgz)](https://github.com/ClaraCrazy/Flipper-Xtreme/releases/download/{VERSION_TAG}/{ARTIFACT_TGZ})
|
||||
>### [🐬 qFlipper Package (.tgz)](https://github.com/Flipper-XFW/Xtreme-Firmware/releases/download/{VERSION_TAG}/{ARTIFACT_TGZ})
|
||||
|
||||
>### [📦 Zipped Archive (.zip)](https://github.com/ClaraCrazy/Flipper-Xtreme/releases/download/{VERSION_TAG}/{ARTIFACT_ZIP})
|
||||
>### [📦 Zipped Archive (.zip)](https://github.com/Flipper-XFW/Xtreme-Firmware/releases/download/{VERSION_TAG}/{ARTIFACT_ZIP})
|
||||
|
||||
**Check the [install guide](https://github.com/ClaraCrazy/Flipper-Xtreme#install) if you're not sure, or [join our Discord](https://discord.gg/flipper-xtreme) if you have questions or encounter issues!**
|
||||
**Check the [install guide](https://github.com/Flipper-XFW/Xtreme-Firmware#install) if you're not sure, or [join our Discord](https://discord.gg/flipper-xtreme) if you have questions or encounter issues!**
|
||||
|
||||
## ❤️ Support
|
||||
If you like what you're seeing, **please consider donating to us**. We won't ever put this behind a paywall, but we'd still appreciate a few bucks!
|
||||
|
||||
@@ -1,4 +1,13 @@
|
||||
#!/bin/bash
|
||||
|
||||
export VERSION_TAG="$(python -c 'import fbt_options; print(fbt_options.DIST_SUFFIX)')"
|
||||
export VERSION_TAG="$(python -c '''
|
||||
import datetime as dt
|
||||
import json
|
||||
import os
|
||||
with open(os.environ["GITHUB_EVENT_PATH"], "r") as f:
|
||||
event = json.load(f)
|
||||
version = int(event["pull_request"]["title"].removeprefix("V").removesuffix(" Release").removesuffix(" Hotfix"))
|
||||
date = dt.datetime.now().strftime("%d%m%Y")
|
||||
print(f"XFW-{version:04}_{date}", end="")
|
||||
''')"
|
||||
echo "VERSION_TAG=${VERSION_TAG}" >> $GITHUB_ENV
|
||||
|
||||
@@ -16,7 +16,16 @@ if __name__ == "__main__":
|
||||
|
||||
match os.environ["GITHUB_EVENT_NAME"]:
|
||||
case "push":
|
||||
webhook = "BUILD_WEBHOOK"
|
||||
count = len(event["commits"])
|
||||
if count == 20:
|
||||
count = int(requests.get(
|
||||
event["compare"].replace("github.com", "api.github.com/repos"),
|
||||
headers={
|
||||
"Accept": "application/vnd.github.v3+json",
|
||||
"Authorization": f"token {os.environ['GITHUB_TOKEN']}"
|
||||
}
|
||||
).json()["total_commits"])
|
||||
branch = event["ref"].removeprefix("refs/heads/")
|
||||
change = (
|
||||
"Force Push"
|
||||
|
||||
+23
-28
@@ -9,6 +9,10 @@ on:
|
||||
- '*'
|
||||
pull_request:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
TARGETS: f7
|
||||
DEFAULT_TARGET: f7
|
||||
@@ -24,47 +28,38 @@ jobs:
|
||||
fetch-depth: 0
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
|
||||
- name: "Read version tag"
|
||||
run: bash .github/workflow_data/commit.sh
|
||||
|
||||
- name: 'Build the firmware'
|
||||
run: |
|
||||
set -e
|
||||
for TARGET in ${TARGETS}; do
|
||||
TARGET_HW="$(echo "${TARGET}" | sed 's/f//')"; \
|
||||
./fbt TARGET_HW=$TARGET_HW updater_package
|
||||
./fbt TARGET_HW=$TARGET_HW DIST_SUFFIX=$VERSION_TAG updater_package
|
||||
done
|
||||
|
||||
- name: "Check for uncommitted changes"
|
||||
run: |
|
||||
git diff --exit-code
|
||||
|
||||
- name: 'Updater artifact'
|
||||
- name: 'Dist artifact'
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: updater
|
||||
name: dist
|
||||
path: |
|
||||
dist/${{ env.DEFAULT_TARGET }}-*/${{ env.DEFAULT_TARGET }}-update-*/
|
||||
dist/${{ env.DEFAULT_TARGET }}-*/
|
||||
|
||||
# - name: 'Find Previous Comment'
|
||||
# if: ${{ github.event.pull_request }}
|
||||
# uses: peter-evans/find-comment@v1
|
||||
# id: fc
|
||||
# with:
|
||||
# issue-number: ${{ github.event.pull_request.number }}
|
||||
# comment-author: 'github-actions[bot]'
|
||||
# body-includes: 'Compiled firmware:'
|
||||
- name: "Make tgz, zip and sdk"
|
||||
run: bash .github/workflow_data/package.sh
|
||||
|
||||
# - name: Artifact info
|
||||
# id: artifact-info
|
||||
# uses: dawidd6/action-download-artifact@v2
|
||||
# with:
|
||||
# dry_run: true
|
||||
|
||||
# - name: 'Create or update comment'
|
||||
# if: ${{ github.event.pull_request}}
|
||||
# uses: peter-evans/create-or-update-comment@v1
|
||||
# with:
|
||||
# comment-id: ${{ steps.fc.outputs.comment-id }}
|
||||
# issue-number: ${{ github.event.pull_request.number }}
|
||||
# body: |
|
||||
# **Compiled firmware:**
|
||||
# - [📦 Update package](${{steps.artifact-info.outputs.artifacts[0].archive_download_url}})
|
||||
# edit-mode: replace
|
||||
- name: Send devbuild webhook
|
||||
if: "github.event_name == 'push' && github.ref_name == 'dev'"
|
||||
env:
|
||||
NC_HOST: "https://cloud.cynthialabs.net/"
|
||||
NC_USER: "${{ secrets.NC_USER }}"
|
||||
NC_PASS: "${{ secrets.NC_PASS }}"
|
||||
BUILD_WEBHOOK: ${{ secrets.BUILD_WEBHOOK }}
|
||||
run: |
|
||||
python -m pip install pyncclient
|
||||
python .github/workflow_data/devbuild.py
|
||||
|
||||
@@ -31,22 +31,22 @@ jobs:
|
||||
fetch-depth: 0
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
|
||||
- name: "Read version tag"
|
||||
run: bash .github/workflow_data/version.sh
|
||||
|
||||
- name: 'Build the firmware'
|
||||
run: |
|
||||
set -e
|
||||
for TARGET in ${TARGETS}; do
|
||||
TARGET_HW="$(echo "${TARGET}" | sed 's/f//')"; \
|
||||
./fbt TARGET_HW=$TARGET_HW FORCE_NO_DIRTY=1 updater_package
|
||||
./fbt TARGET_HW=$TARGET_HW DIST_SUFFIX=$VERSION_TAG FORCE_NO_DIRTY=1 updater_package
|
||||
done
|
||||
|
||||
- name: "Check for uncommitted changes"
|
||||
run: |
|
||||
git diff --exit-code
|
||||
|
||||
- name: "Read version tag"
|
||||
run: bash .github/workflow_data/version.sh
|
||||
|
||||
- name: "Make tgz and zip"
|
||||
- name: "Make tgz, zip and sdk"
|
||||
run: bash .github/workflow_data/package.sh
|
||||
|
||||
- name: "Upload hotfix"
|
||||
|
||||
@@ -12,8 +12,8 @@ jobs:
|
||||
release:
|
||||
if: |
|
||||
github.event.pull_request.head.repo.full_name == github.event.pull_request.base.repo.full_name &&
|
||||
endsWith(github.event.pull_request.title, ' Release Candidate Changes') &&
|
||||
github.event.review.author_association == 'OWNER' &&
|
||||
endsWith(github.event.pull_request.title, ' Release') &&
|
||||
github.event.review.author_association == 'MEMBER' &&
|
||||
startsWith(github.event.pull_request.title, 'V') &&
|
||||
github.event.pull_request.base.ref == 'main' &&
|
||||
github.event.pull_request.head.ref == 'dev' &&
|
||||
@@ -31,22 +31,22 @@ jobs:
|
||||
fetch-depth: 0
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
|
||||
- name: "Read version tag"
|
||||
run: bash .github/workflow_data/version.sh
|
||||
|
||||
- name: 'Build the firmware'
|
||||
run: |
|
||||
set -e
|
||||
for TARGET in ${TARGETS}; do
|
||||
TARGET_HW="$(echo "${TARGET}" | sed 's/f//')"; \
|
||||
./fbt TARGET_HW=$TARGET_HW FORCE_NO_DIRTY=1 updater_package
|
||||
./fbt TARGET_HW=$TARGET_HW DIST_SUFFIX=$VERSION_TAG FORCE_NO_DIRTY=1 updater_package
|
||||
done
|
||||
|
||||
- name: "Check for uncommitted changes"
|
||||
run: |
|
||||
git diff --exit-code
|
||||
|
||||
- name: "Read version tag"
|
||||
run: bash .github/workflow_data/version.sh
|
||||
|
||||
- name: "Make tgz and zip"
|
||||
- name: "Make tgz, zip and sdk"
|
||||
run: bash .github/workflow_data/package.sh
|
||||
|
||||
- name: "Update release notes"
|
||||
@@ -76,6 +76,7 @@ jobs:
|
||||
files: |
|
||||
${{ env.ARTIFACT_TGZ }}
|
||||
${{ env.ARTIFACT_ZIP }}
|
||||
${{ env.ARTIFACT_SDK }}
|
||||
name: "${{ env.VERSION_TAG }}"
|
||||
tag_name: "${{ env.VERSION_TAG }}"
|
||||
target_commitish: ${{ github.event.pull_request.base.ref }}
|
||||
|
||||
@@ -39,5 +39,7 @@ jobs:
|
||||
|
||||
- name: Send webhook
|
||||
env:
|
||||
DEV_WEBHOOK: "https://discord.com/api/webhooks/${{ secrets.DEV_WEBHOOK_ID }}/${{ secrets.DEV_WEBHOOK_TOKEN }}"
|
||||
BUILD_WEBHOOK: ${{ secrets.BUILD_WEBHOOK }}
|
||||
DEV_WEBHOOK: ${{ secrets.DEV_WEBHOOK }}
|
||||
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
||||
run: python .github/workflow_data/webhook.py
|
||||
|
||||
+4
-4
@@ -78,7 +78,7 @@ commitnotes.md
|
||||
fbt_options.py
|
||||
|
||||
# Asset packs
|
||||
assets/dolphin/custom/*
|
||||
!assets/dolphin/custom/WatchDogs/
|
||||
!assets/dolphin/custom/ReadMe.md
|
||||
assets/resources/dolphin_custom/
|
||||
assets/asset_packs/*
|
||||
!assets/asset_packs/WatchDogs/
|
||||
!assets/asset_packs/ReadMe.md
|
||||
assets/resources/asset_packs/
|
||||
|
||||
Vendored
+39
-15
@@ -4,16 +4,28 @@
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "[Release] Build",
|
||||
"label": "[Release] Build Firmware",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt COMPACT=1 DEBUG=0"
|
||||
},
|
||||
{
|
||||
"label": "[Debug] Build",
|
||||
"label": "[Debug] Build Firmware",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt FIRMWARE_APP_SET=debug_pack"
|
||||
"command": "./fbt"
|
||||
},
|
||||
{
|
||||
"label": "[FBT] Format",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt format"
|
||||
},
|
||||
{
|
||||
"label": "[FBT] Clear",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt -c"
|
||||
},
|
||||
{
|
||||
"label": "[Release] Flash (ST-Link)",
|
||||
@@ -25,7 +37,7 @@
|
||||
"label": "[Debug] Flash (ST-Link)",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt FIRMWARE_APP_SET=debug_pack FORCE=1 flash"
|
||||
"command": "./fbt FORCE=1 flash"
|
||||
},
|
||||
{
|
||||
"label": "[Release] Flash (blackmagic)",
|
||||
@@ -37,7 +49,7 @@
|
||||
"label": "[Debug] Flash (blackmagic)",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt FIRMWARE_APP_SET=debug_pack FORCE=1 flash_blackmagic"
|
||||
"command": "./fbt FORCE=1 flash_blackmagic"
|
||||
},
|
||||
{
|
||||
"label": "[Release] Flash (JLink)",
|
||||
@@ -49,7 +61,7 @@
|
||||
"label": "[Debug] Flash (JLink)",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt FIRMWARE_APP_SET=debug_pack FORCE=1 jflash"
|
||||
"command": "./fbt FORCE=1 jflash"
|
||||
},
|
||||
{
|
||||
"label": "[Release] Build update bundle",
|
||||
@@ -61,7 +73,7 @@
|
||||
"label": "[Debug] Build update bundle",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt FIRMWARE_APP_SET=debug_pack updater_package"
|
||||
"command": "./fbt updater_package"
|
||||
},
|
||||
{
|
||||
"label": "[Release] Build updater",
|
||||
@@ -73,13 +85,13 @@
|
||||
"label": "[Debug] Build updater",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt FIRMWARE_APP_SET=debug_pack updater_all"
|
||||
"command": "./fbt updater_all"
|
||||
},
|
||||
{
|
||||
"label": "[Debug] Flash (USB, w/o resources)",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt FIRMWARE_APP_SET=debug_pack FORCE=1 flash_usb"
|
||||
"command": "./fbt FORCE=1 flash_usb"
|
||||
},
|
||||
{
|
||||
"label": "[Release] Flash (USB, w/o resources)",
|
||||
@@ -97,7 +109,7 @@
|
||||
"label": "[Debug] Flash (USB, with resources)",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt FIRMWARE_APP_SET=debug_pack FORCE=1 flash_usb_full"
|
||||
"command": "./fbt FORCE=1 flash_usb_full"
|
||||
},
|
||||
{
|
||||
"label": "[Release] Flash (USB, with resources)",
|
||||
@@ -123,17 +135,29 @@
|
||||
"type": "shell",
|
||||
"command": "./fbt COMPACT=1 DEBUG=0 fap_dist"
|
||||
},
|
||||
{
|
||||
"label": "[Debug] Build App",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt build APPSRC=${relativeFileDirname}"
|
||||
},
|
||||
{
|
||||
"label": "[Release] Build App",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt COMPACT=1 DEBUG=0 build APPSRC=${relativeFileDirname}"
|
||||
},
|
||||
{
|
||||
"label": "[Debug] Launch App on Flipper",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt launch_app APPSRC=${relativeFileDirname}"
|
||||
"command": "./fbt launch APPSRC=${relativeFileDirname}"
|
||||
},
|
||||
{
|
||||
"label": "[Release] Launch App on Flipper",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt COMPACT=1 DEBUG=0 launch_app APPSRC=${relativeFileDirname}"
|
||||
"command": "./fbt COMPACT=1 DEBUG=0 launch APPSRC=${relativeFileDirname}"
|
||||
},
|
||||
{
|
||||
"label": "[Debug] Launch App on Flipper with Serial Console",
|
||||
@@ -148,13 +172,13 @@
|
||||
"label": "[Debug] Build and upload all FAPs to Flipper over USB",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt faps_copy"
|
||||
"command": "./fbt fap_deploy"
|
||||
},
|
||||
{
|
||||
"label": "[Release] Build and upload all FAPs to Flipper over USB",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt COMPACT=1 DEBUG=0 faps_copy"
|
||||
"command": "./fbt COMPACT=1 DEBUG=0 fap_deploy"
|
||||
},
|
||||
{
|
||||
// Press Ctrl+] to quit
|
||||
@@ -163,7 +187,7 @@
|
||||
"command": "./fbt cli",
|
||||
"group": "none",
|
||||
"isBackground": true,
|
||||
"options": {
|
||||
"options": {
|
||||
"env": {
|
||||
"FBT_NO_SYNC": "0"
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<h1 align="center">XFW - <code>Xtreme Firmware</code> for the Flipper Zero</h1>
|
||||
|
||||
<p align="center">
|
||||
<img src="https://github.com/ClaraCrazy/Flipper-Xtreme/assets/55334727/767a3e1b-a96c-43c8-b58f-a49a533b3bb4">
|
||||
<img src="https://github.com/Flipper-XFW/Xtreme-Firmware/assets/55334727/767a3e1b-a96c-43c8-b58f-a49a533b3bb4">
|
||||
</p>
|
||||
|
||||
<h2 align="center">
|
||||
<a href="https://flipper-xtre.me">Website</a> | <a href="https://github.com/ClaraCrazy/Flipper-Xtreme#What-makes-it-special">Intro</a> | <a href="https://github.com/ClaraCrazy/Flipper-Xtreme#Install">Install</a> | <a href="https://github.com/ClaraCrazy/Flipper-Xtreme#list-of-changes">Changelog</a> | <a href="https://github.com/ClaraCrazy/Flipper-Xtreme/wiki">Wiki</a> | <a href="https://discord.gg/flipper-xtreme">Discord</a> | <a href="https://github.com/ClaraCrazy/Flipper-Xtreme#%EF%B8%8F-support">Donate</a>
|
||||
<a href="https://flipper-xtre.me">Website</a> | <a href="https://github.com/Flipper-XFW/Xtreme-Firmware#What-makes-it-special">Intro</a> | <a href="https://github.com/Flipper-XFW/Xtreme-Firmware#Install">Install</a> | <a href="https://github.com/Flipper-XFW/Xtreme-Firmware#list-of-changes">Changelog</a> | <a href="https://github.com/Flipper-XFW/Xtreme-Firmware/wiki">Wiki</a> | <a href="https://discord.gg/flipper-xtreme">Discord</a> | <a href="https://github.com/Flipper-XFW/Xtreme-Firmware#%EF%B8%8F-support">Donate</a>
|
||||
</h2>
|
||||
|
||||
This firmware is a complete overhaul of the [Official Firmware](https://github.com/flipperdevices/flipperzero-firmware), and also features lots of awesome code-bits from [Unleashed](https://github.com/DarkFlippers/unleashed-firmware).
|
||||
@@ -24,7 +24,7 @@ The goal of this Firmware is to regularly bring out amazing updates based on wha
|
||||
|
||||
- <h4>Customizable: Dont like the Animations, want to turn on/off the Home screen icons (battery, SD card etc), change the flippers name or anything like that? You absolutely can. No need to mess with code or deal with weird manifest files. Its all done with an App.</h4>
|
||||
<br><br>
|
||||
Note, the below mentioned changes are only a few things we did. For a full list click [here](https://github.com/ClaraCrazy/Flipper-Xtreme/wiki/Customization)
|
||||
Note, the below mentioned changes are only a few things we did. For a full list click [here](https://github.com/Flipper-XFW/Xtreme-Firmware/wiki/Customization)
|
||||
|
||||
-----
|
||||
<br>
|
||||
@@ -44,7 +44,7 @@ Also, perhaps a bigger height, with set width (yes distrotion issues ik) so it f
|
||||
|
||||
- <ins><b>Interface:</b></ins> Customize every bit of your Flipper, from the desktop animations, to the main menu apps, lockscreen style etc.
|
||||
|
||||
- <ins><b>Protocols:</b></ins> Here you can toggle between USB & Bluetooth mode for <a href="https://github.com/ClaraCrazy/Flipper-Xtreme/wiki/Generic-Guides#badbt--kb">BadKB</a>, and manage custom Subghz frequencies.
|
||||
- <ins><b>Protocols:</b></ins> Here you can toggle between USB & Bluetooth mode for <a href="https://github.com/Flipper-XFW/Xtreme-Firmware/wiki/Generic-Guides#badbt--kb">BadKB</a>, and manage custom Subghz frequencies.
|
||||
|
||||
- <ins><b>Misc:</b></ins> All the other options that don't fit elsewhere. Change your Flipper's name, xp level, and configure the <a href="https://github.com/Z3BRO/Flipper-Zero-RGB-Backlight">RGB backlight</a>.
|
||||
|
||||
@@ -60,14 +60,14 @@ Also, perhaps a bigger height, with set width (yes distrotion issues ik) so it f
|
||||
We created our own, new & improved Animation / Asset system, that we can finally reveal. It lets you to create and cycle through your own `Asset Packs` with only a few button presses, allowing you to easily load custom Animations and Icons like never before.
|
||||
|
||||
<img src="https://user-images.githubusercontent.com/55334727/214010675-9eddb8f5-1dd6-4cf4-a0ee-e37af8b6c933.PNG" align="left" width="200px"/>
|
||||
You can easily create your own pack, or find some user made ones in the discord channel. Check <a href="https://github.com/ClaraCrazy/Flipper-Xtreme/wiki/Asset-Packs">here</a> for a tutorial on creating your own. Essentially, we got our own <code>Anims</code> & <code>Icons</code> folders, inside each <code>Asset Pack</code>.
|
||||
You can easily create your own pack, or find some user made ones in the discord channel. Check <a href="https://github.com/Flipper-XFW/Xtreme-Firmware/wiki/Asset-Packs">here</a> for a tutorial on creating your own. Essentially, we got our own <code>Anims</code> & <code>Icons</code> folders, inside each <code>Asset Pack</code>.
|
||||
|
||||
<br clear="left"/>
|
||||
|
||||
<br>
|
||||
|
||||
<img src="https://user-images.githubusercontent.com/55334727/214016338-95a619c7-88d2-4db5-bb7a-75282d9082b8.png" align="left" width="200px"/>
|
||||
Once you have some packs, upload them to your Flipper in <code>SD/dolphin_custom</code> (if you did this right you should see <code>SD/dolphin_custom/PackName/Anims</code> and/or <code>SD/dolphin_custom/PackName/Icons</code>).
|
||||
Once you have some packs, upload them to your Flipper in <code>SD/asset_packs</code> (if you did this right you should see <code>SD/asset_packs/PackName/Anims</code> and/or <code>SD/asset_packs/PackName/Icons</code>).
|
||||
|
||||
|
||||
<br clear="left"/>
|
||||
@@ -160,21 +160,21 @@ There are 3 methods to install Xtreme, we recommend you use the **Web Updater**,
|
||||
<br>
|
||||
|
||||
> <details><summary><code>Web Updater (Chrome)</code></summary><ul>
|
||||
> <li>Open the <a href="https://github.com/ClaraCrazy/Flipper-Xtreme/releases/latest">latest release page</a> and click on the <code>Web Updater</code> link</li>
|
||||
> <li>Open the <a href="https://github.com/Flipper-XFW/Xtreme-Firmware/releases/latest">latest release page</a> and click on the <code>Web Updater</code> link</li>
|
||||
> <li>Make sure qFlipper is closed</li>
|
||||
> <li>Click <code>Connect</code> and select your Flipper from the list</li>
|
||||
> <li>Click <code>Flash</code> and wait for the update to complete</li>
|
||||
> </ul></details>
|
||||
|
||||
> <details><summary><code>qFlipper Package (.tgz)</code></summary><ul>
|
||||
> <li>Download the qFlipper package (.tgz) from the <a href="https://github.com/ClaraCrazy/Flipper-Xtreme/releases/latest">latest release page</a></li>
|
||||
> <li>Download the qFlipper package (.tgz) from the <a href="https://github.com/Flipper-XFW/Xtreme-Firmware/releases/latest">latest release page</a></li>
|
||||
> <li>Open <a href="https://flipperzero.one/update">qFlipper</a> and connect your Flipper</li>
|
||||
> <li>Click <code>Install from file</code></li>
|
||||
> <li>Select the .tgz you downloaded and wait for the update to complete</li>
|
||||
> </ul></details>
|
||||
|
||||
> <details><summary><code>Zipped Archive (.zip)</code></summary><ul>
|
||||
> <li>Download the zipped archive (.zip) from the <a href="https://github.com/ClaraCrazy/Flipper-Xtreme/releases/latest">latest release page</a></li>
|
||||
> <li>Download the zipped archive (.zip) from the <a href="https://github.com/Flipper-XFW/Xtreme-Firmware/releases/latest">latest release page</a></li>
|
||||
> <li>Extract the archive. This is now your new Firmware folder</li>
|
||||
> <li>Open <a href="https://flipperzero.one/update">qFlipper</a>, head to <code>SD/Update</code> and simply move the firmware folder there</li>
|
||||
> <li>On the Flipper, hit the <code>Arrow Down</code> button, this will get you to the file menu. In there simply search for your updates folder</li>
|
||||
@@ -192,31 +192,28 @@ There are 3 methods to install Xtreme, we recommend you use the **Web Updater**,
|
||||
|
||||
```bash
|
||||
To download the needed tools:
|
||||
$ git clone --recursive https://github.com/ClaraCrazy/Flipper-Xtreme.git
|
||||
$ cd Flipper-Xtreme/
|
||||
$ git clone --recursive --jobs 8 https://github.com/Flipper-XFW/Xtreme-Firmware.git
|
||||
$ cd Xtreme-Firmware/
|
||||
|
||||
To flash directly to the Flipper (Needs to be connected via USB, qFlipper closed)
|
||||
$ ./fbt flash_usb
|
||||
$ ./fbt flash_usb_full
|
||||
|
||||
To just compile firmware
|
||||
To compile a TGZ package
|
||||
$ ./fbt updater_package
|
||||
|
||||
If building FAPS:
|
||||
$ ./fbt fap_dist
|
||||
|
||||
If building image assets:
|
||||
$ ./fbt resources icons dolphin_ext
|
||||
To build and launch a single app:
|
||||
$ ./fbt launch APPSRC=some_appid
|
||||
```
|
||||
|
||||
----
|
||||
<h2 align="center">Stargazers over time</h2>
|
||||
|
||||
[](https://starchart.cc/ClaraCrazy/Flipper-Xtreme)
|
||||
[](https://starchart.cc/Flipper-XFW/Xtreme-Firmware)
|
||||
|
||||
----
|
||||
<h2 align="center">Contributors</h2>
|
||||
|
||||
[](https://github.com/ClaraCrazy/Flipper-Xtreme/graphs/contributors)
|
||||
[](https://github.com/Flipper-XFW/Xtreme-Firmware/graphs/contributors)
|
||||
|
||||
|
||||
## ❤️ Support
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
App(
|
||||
appid="subghz_test",
|
||||
name="Sub-Ghz test",
|
||||
apptype=FlipperAppType.DEBUG,
|
||||
targets=["f7"],
|
||||
entry_point="subghz_test_app",
|
||||
requires=["gui"],
|
||||
stack_size=4 * 1024,
|
||||
order=50,
|
||||
fap_icon="subghz_test_10px.png",
|
||||
fap_category="Debug",
|
||||
fap_icon_assets="images",
|
||||
fap_version="0.1",
|
||||
)
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
typedef enum {
|
||||
//SubGhzTestCustomEvent
|
||||
SubGhzTestCustomEventStartId = 100,
|
||||
SubGhzTestCustomEventSceneShowOnlyRX,
|
||||
} SubGhzTestCustomEvent;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
#include "subghz_testing.h"
|
||||
#include "subghz_test_frequency.h"
|
||||
|
||||
const uint32_t subghz_frequencies_testing[] = {
|
||||
/* 300 - 348 */
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
#include "../subghz_i.h"
|
||||
#include "../subghz_test_app_i.h"
|
||||
|
||||
extern const uint32_t subghz_frequencies_testing[];
|
||||
extern const uint32_t subghz_frequencies_count_testing;
|
||||
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
|
||||
#define SUBGHZ_TEST_VERSION_APP "0.1"
|
||||
#define SUBGHZ_TEST_DEVELOPED "SkorP"
|
||||
#define SUBGHZ_TEST_GITHUB "https://github.com/flipperdevices/flipperzero-firmware"
|
||||
|
||||
typedef enum {
|
||||
SubGhzTestViewVariableItemList,
|
||||
SubGhzTestViewSubmenu,
|
||||
SubGhzTestViewStatic,
|
||||
SubGhzTestViewCarrier,
|
||||
SubGhzTestViewPacket,
|
||||
SubGhzTestViewWidget,
|
||||
SubGhzTestViewPopup,
|
||||
} SubGhzTestView;
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
@@ -0,0 +1,244 @@
|
||||
#include "math.h"
|
||||
|
||||
uint64_t subghz_protocol_blocks_reverse_key(uint64_t key, uint8_t bit_count) {
|
||||
uint64_t reverse_key = 0;
|
||||
for(uint8_t i = 0; i < bit_count; i++) {
|
||||
reverse_key = reverse_key << 1 | bit_read(key, i);
|
||||
}
|
||||
return reverse_key;
|
||||
}
|
||||
|
||||
uint8_t subghz_protocol_blocks_get_parity(uint64_t key, uint8_t bit_count) {
|
||||
uint8_t parity = 0;
|
||||
for(uint8_t i = 0; i < bit_count; i++) {
|
||||
parity += bit_read(key, i);
|
||||
}
|
||||
return parity & 0x01;
|
||||
}
|
||||
|
||||
uint8_t subghz_protocol_blocks_crc4(
|
||||
uint8_t const message[],
|
||||
size_t size,
|
||||
uint8_t polynomial,
|
||||
uint8_t init) {
|
||||
uint8_t remainder = init << 4; // LSBs are unused
|
||||
uint8_t poly = polynomial << 4;
|
||||
uint8_t bit;
|
||||
|
||||
while(size--) {
|
||||
remainder ^= *message++;
|
||||
for(bit = 0; bit < 8; bit++) {
|
||||
if(remainder & 0x80) {
|
||||
remainder = (remainder << 1) ^ poly;
|
||||
} else {
|
||||
remainder = (remainder << 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return remainder >> 4 & 0x0f; // discard the LSBs
|
||||
}
|
||||
|
||||
uint8_t subghz_protocol_blocks_crc7(
|
||||
uint8_t const message[],
|
||||
size_t size,
|
||||
uint8_t polynomial,
|
||||
uint8_t init) {
|
||||
uint8_t remainder = init << 1; // LSB is unused
|
||||
uint8_t poly = polynomial << 1;
|
||||
|
||||
for(size_t byte = 0; byte < size; ++byte) {
|
||||
remainder ^= message[byte];
|
||||
for(uint8_t bit = 0; bit < 8; ++bit) {
|
||||
if(remainder & 0x80) {
|
||||
remainder = (remainder << 1) ^ poly;
|
||||
} else {
|
||||
remainder = (remainder << 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return remainder >> 1 & 0x7f; // discard the LSB
|
||||
}
|
||||
|
||||
uint8_t subghz_protocol_blocks_crc8(
|
||||
uint8_t const message[],
|
||||
size_t size,
|
||||
uint8_t polynomial,
|
||||
uint8_t init) {
|
||||
uint8_t remainder = init;
|
||||
|
||||
for(size_t byte = 0; byte < size; ++byte) {
|
||||
remainder ^= message[byte];
|
||||
for(uint8_t bit = 0; bit < 8; ++bit) {
|
||||
if(remainder & 0x80) {
|
||||
remainder = (remainder << 1) ^ polynomial;
|
||||
} else {
|
||||
remainder = (remainder << 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return remainder;
|
||||
}
|
||||
|
||||
uint8_t subghz_protocol_blocks_crc8le(
|
||||
uint8_t const message[],
|
||||
size_t size,
|
||||
uint8_t polynomial,
|
||||
uint8_t init) {
|
||||
uint8_t remainder = subghz_protocol_blocks_reverse_key(init, 8);
|
||||
polynomial = subghz_protocol_blocks_reverse_key(polynomial, 8);
|
||||
|
||||
for(size_t byte = 0; byte < size; ++byte) {
|
||||
remainder ^= message[byte];
|
||||
for(uint8_t bit = 0; bit < 8; ++bit) {
|
||||
if(remainder & 1) {
|
||||
remainder = (remainder >> 1) ^ polynomial;
|
||||
} else {
|
||||
remainder = (remainder >> 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return remainder;
|
||||
}
|
||||
|
||||
uint16_t subghz_protocol_blocks_crc16lsb(
|
||||
uint8_t const message[],
|
||||
size_t size,
|
||||
uint16_t polynomial,
|
||||
uint16_t init) {
|
||||
uint16_t remainder = init;
|
||||
|
||||
for(size_t byte = 0; byte < size; ++byte) {
|
||||
remainder ^= message[byte];
|
||||
for(uint8_t bit = 0; bit < 8; ++bit) {
|
||||
if(remainder & 1) {
|
||||
remainder = (remainder >> 1) ^ polynomial;
|
||||
} else {
|
||||
remainder = (remainder >> 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return remainder;
|
||||
}
|
||||
|
||||
uint16_t subghz_protocol_blocks_crc16(
|
||||
uint8_t const message[],
|
||||
size_t size,
|
||||
uint16_t polynomial,
|
||||
uint16_t init) {
|
||||
uint16_t remainder = init;
|
||||
|
||||
for(size_t byte = 0; byte < size; ++byte) {
|
||||
remainder ^= message[byte] << 8;
|
||||
for(uint8_t bit = 0; bit < 8; ++bit) {
|
||||
if(remainder & 0x8000) {
|
||||
remainder = (remainder << 1) ^ polynomial;
|
||||
} else {
|
||||
remainder = (remainder << 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return remainder;
|
||||
}
|
||||
|
||||
uint8_t subghz_protocol_blocks_lfsr_digest8(
|
||||
uint8_t const message[],
|
||||
size_t size,
|
||||
uint8_t gen,
|
||||
uint8_t key) {
|
||||
uint8_t sum = 0;
|
||||
for(size_t byte = 0; byte < size; ++byte) {
|
||||
uint8_t data = message[byte];
|
||||
for(int i = 7; i >= 0; --i) {
|
||||
// XOR key into sum if data bit is set
|
||||
if((data >> i) & 1) sum ^= key;
|
||||
|
||||
// roll the key right (actually the LSB is dropped here)
|
||||
// and apply the gen (needs to include the dropped LSB as MSB)
|
||||
if(key & 1)
|
||||
key = (key >> 1) ^ gen;
|
||||
else
|
||||
key = (key >> 1);
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
uint8_t subghz_protocol_blocks_lfsr_digest8_reflect(
|
||||
uint8_t const message[],
|
||||
size_t size,
|
||||
uint8_t gen,
|
||||
uint8_t key) {
|
||||
uint8_t sum = 0;
|
||||
// Process message from last byte to first byte (reflected)
|
||||
for(int byte = size - 1; byte >= 0; --byte) {
|
||||
uint8_t data = message[byte];
|
||||
// Process individual bits of each byte (reflected)
|
||||
for(uint8_t i = 0; i < 8; ++i) {
|
||||
// XOR key into sum if data bit is set
|
||||
if((data >> i) & 1) {
|
||||
sum ^= key;
|
||||
}
|
||||
|
||||
// roll the key left (actually the LSB is dropped here)
|
||||
// and apply the gen (needs to include the dropped lsb as MSB)
|
||||
if(key & 0x80)
|
||||
key = (key << 1) ^ gen;
|
||||
else
|
||||
key = (key << 1);
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
uint16_t subghz_protocol_blocks_lfsr_digest16(
|
||||
uint8_t const message[],
|
||||
size_t size,
|
||||
uint16_t gen,
|
||||
uint16_t key) {
|
||||
uint16_t sum = 0;
|
||||
for(size_t byte = 0; byte < size; ++byte) {
|
||||
uint8_t data = message[byte];
|
||||
for(int8_t i = 7; i >= 0; --i) {
|
||||
// if data bit is set then xor with key
|
||||
if((data >> i) & 1) sum ^= key;
|
||||
|
||||
// roll the key right (actually the LSB is dropped here)
|
||||
// and apply the gen (needs to include the dropped LSB as MSB)
|
||||
if(key & 1)
|
||||
key = (key >> 1) ^ gen;
|
||||
else
|
||||
key = (key >> 1);
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
uint8_t subghz_protocol_blocks_add_bytes(uint8_t const message[], size_t size) {
|
||||
uint32_t result = 0;
|
||||
for(size_t i = 0; i < size; ++i) {
|
||||
result += message[i];
|
||||
}
|
||||
return (uint8_t)result;
|
||||
}
|
||||
|
||||
uint8_t subghz_protocol_blocks_parity8(uint8_t byte) {
|
||||
byte ^= byte >> 4;
|
||||
byte &= 0xf;
|
||||
return (0x6996 >> byte) & 1;
|
||||
}
|
||||
|
||||
uint8_t subghz_protocol_blocks_parity_bytes(uint8_t const message[], size_t size) {
|
||||
uint8_t result = 0;
|
||||
for(size_t i = 0; i < size; ++i) {
|
||||
result ^= subghz_protocol_blocks_parity8(message[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
uint8_t subghz_protocol_blocks_xor_bytes(uint8_t const message[], size_t size) {
|
||||
uint8_t result = 0;
|
||||
for(size_t i = 0; i < size; ++i) {
|
||||
result ^= message[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#define bit_read(value, bit) (((value) >> (bit)) & 0x01)
|
||||
#define bit_set(value, bit) \
|
||||
({ \
|
||||
__typeof__(value) _one = (1); \
|
||||
(value) |= (_one << (bit)); \
|
||||
})
|
||||
#define bit_clear(value, bit) \
|
||||
({ \
|
||||
__typeof__(value) _one = (1); \
|
||||
(value) &= ~(_one << (bit)); \
|
||||
})
|
||||
#define bit_write(value, bit, bitvalue) (bitvalue ? bit_set(value, bit) : bit_clear(value, bit))
|
||||
#define DURATION_DIFF(x, y) (((x) < (y)) ? ((y) - (x)) : ((x) - (y)))
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Flip the data bitwise
|
||||
*
|
||||
* @param key In data
|
||||
* @param bit_count number of data bits
|
||||
*
|
||||
* @return Reverse data
|
||||
*/
|
||||
uint64_t subghz_protocol_blocks_reverse_key(uint64_t key, uint8_t bit_count);
|
||||
|
||||
/** Get parity the data bitwise
|
||||
*
|
||||
* @param key In data
|
||||
* @param bit_count number of data bits
|
||||
*
|
||||
* @return parity
|
||||
*/
|
||||
uint8_t subghz_protocol_blocks_get_parity(uint64_t key, uint8_t bit_count);
|
||||
|
||||
/** CRC-4
|
||||
*
|
||||
* @param message array of bytes to check
|
||||
* @param size number of bytes in message
|
||||
* @param polynomial CRC polynomial
|
||||
* @param init starting crc value
|
||||
*
|
||||
* @return CRC value
|
||||
*/
|
||||
uint8_t subghz_protocol_blocks_crc4(
|
||||
uint8_t const message[],
|
||||
size_t size,
|
||||
uint8_t polynomial,
|
||||
uint8_t init);
|
||||
|
||||
/** CRC-7
|
||||
*
|
||||
* @param message array of bytes to check
|
||||
* @param size number of bytes in message
|
||||
* @param polynomial CRC polynomial
|
||||
* @param init starting crc value
|
||||
*
|
||||
* @return CRC value
|
||||
*/
|
||||
uint8_t subghz_protocol_blocks_crc7(
|
||||
uint8_t const message[],
|
||||
size_t size,
|
||||
uint8_t polynomial,
|
||||
uint8_t init);
|
||||
|
||||
/** Generic Cyclic Redundancy Check CRC-8. Example polynomial: 0x31 = x8 + x5 +
|
||||
* x4 + 1 (x8 is implicit) Example polynomial: 0x80 = x8 + x7 (a normal
|
||||
* bit-by-bit parity XOR)
|
||||
*
|
||||
* @param message array of bytes to check
|
||||
* @param size number of bytes in message
|
||||
* @param polynomial byte is from x^7 to x^0 (x^8 is implicitly one)
|
||||
* @param init starting crc value
|
||||
*
|
||||
* @return CRC value
|
||||
*/
|
||||
uint8_t subghz_protocol_blocks_crc8(
|
||||
uint8_t const message[],
|
||||
size_t size,
|
||||
uint8_t polynomial,
|
||||
uint8_t init);
|
||||
|
||||
/** "Little-endian" Cyclic Redundancy Check CRC-8 LE Input and output are
|
||||
* reflected, i.e. least significant bit is shifted in first
|
||||
*
|
||||
* @param message array of bytes to check
|
||||
* @param size number of bytes in message
|
||||
* @param polynomial CRC polynomial
|
||||
* @param init starting crc value
|
||||
*
|
||||
* @return CRC value
|
||||
*/
|
||||
uint8_t subghz_protocol_blocks_crc8le(
|
||||
uint8_t const message[],
|
||||
size_t size,
|
||||
uint8_t polynomial,
|
||||
uint8_t init);
|
||||
|
||||
/** CRC-16 LSB. Input and output are reflected, i.e. least significant bit is
|
||||
* shifted in first. Note that poly and init already need to be reflected
|
||||
*
|
||||
* @param message array of bytes to check
|
||||
* @param size number of bytes in message
|
||||
* @param polynomial CRC polynomial
|
||||
* @param init starting crc value
|
||||
*
|
||||
* @return CRC value
|
||||
*/
|
||||
uint16_t subghz_protocol_blocks_crc16lsb(
|
||||
uint8_t const message[],
|
||||
size_t size,
|
||||
uint16_t polynomial,
|
||||
uint16_t init);
|
||||
|
||||
/** CRC-16
|
||||
*
|
||||
* @param message array of bytes to check
|
||||
* @param size number of bytes in message
|
||||
* @param polynomial CRC polynomial
|
||||
* @param init starting crc value
|
||||
*
|
||||
* @return CRC value
|
||||
*/
|
||||
uint16_t subghz_protocol_blocks_crc16(
|
||||
uint8_t const message[],
|
||||
size_t size,
|
||||
uint16_t polynomial,
|
||||
uint16_t init);
|
||||
|
||||
/** Digest-8 by "LFSR-based Toeplitz hash"
|
||||
*
|
||||
* @param message bytes of message data
|
||||
* @param size number of bytes to digest
|
||||
* @param gen key stream generator, needs to includes the MSB if the
|
||||
* LFSR is rolling
|
||||
* @param key initial key
|
||||
*
|
||||
* @return digest value
|
||||
*/
|
||||
uint8_t subghz_protocol_blocks_lfsr_digest8(
|
||||
uint8_t const message[],
|
||||
size_t size,
|
||||
uint8_t gen,
|
||||
uint8_t key);
|
||||
|
||||
/** Digest-8 by "LFSR-based Toeplitz hash", byte reflect, bit reflect
|
||||
*
|
||||
* @param message bytes of message data
|
||||
* @param size number of bytes to digest
|
||||
* @param gen key stream generator, needs to includes the MSB if the
|
||||
* LFSR is rolling
|
||||
* @param key initial key
|
||||
*
|
||||
* @return digest value
|
||||
*/
|
||||
uint8_t subghz_protocol_blocks_lfsr_digest8_reflect(
|
||||
uint8_t const message[],
|
||||
size_t size,
|
||||
uint8_t gen,
|
||||
uint8_t key);
|
||||
|
||||
/** Digest-16 by "LFSR-based Toeplitz hash"
|
||||
*
|
||||
* @param message bytes of message data
|
||||
* @param size number of bytes to digest
|
||||
* @param gen key stream generator, needs to includes the MSB if the
|
||||
* LFSR is rolling
|
||||
* @param key initial key
|
||||
*
|
||||
* @return digest value
|
||||
*/
|
||||
uint16_t subghz_protocol_blocks_lfsr_digest16(
|
||||
uint8_t const message[],
|
||||
size_t size,
|
||||
uint16_t gen,
|
||||
uint16_t key);
|
||||
|
||||
/** Compute Addition of a number of bytes
|
||||
*
|
||||
* @param message bytes of message data
|
||||
* @param size number of bytes to sum
|
||||
*
|
||||
* @return summation value
|
||||
*/
|
||||
uint8_t subghz_protocol_blocks_add_bytes(uint8_t const message[], size_t size);
|
||||
|
||||
/** Compute bit parity of a single byte (8 bits)
|
||||
*
|
||||
* @param byte single byte to check
|
||||
*
|
||||
* @return 1 odd parity, 0 even parity
|
||||
*/
|
||||
uint8_t subghz_protocol_blocks_parity8(uint8_t byte);
|
||||
|
||||
/** Compute bit parity of a number of bytes
|
||||
*
|
||||
* @param message bytes of message data
|
||||
* @param size number of bytes to sum
|
||||
*
|
||||
* @return 1 odd parity, 0 even parity
|
||||
*/
|
||||
uint8_t subghz_protocol_blocks_parity_bytes(uint8_t const message[], size_t size);
|
||||
|
||||
/** Compute XOR (byte-wide parity) of a number of bytes
|
||||
*
|
||||
* @param message bytes of message data
|
||||
* @param size number of bytes to sum
|
||||
*
|
||||
* @return summation value, per bit-position 1 odd parity, 0 even parity
|
||||
*/
|
||||
uint8_t subghz_protocol_blocks_xor_bytes(uint8_t const message[], size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
#include "princeton_for_testing.h"
|
||||
|
||||
#include <furi_hal.h>
|
||||
#include "../blocks/math.h"
|
||||
#include "math.h"
|
||||
|
||||
/*
|
||||
* Help
|
||||
+3
-1
@@ -1,6 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "base.h"
|
||||
//#include "base.h"
|
||||
#include <furi.h>
|
||||
#include <lib/toolbox/level_duration.h>
|
||||
|
||||
/** SubGhzDecoderPrinceton anonymous type */
|
||||
typedef struct SubGhzDecoderPrinceton SubGhzDecoderPrinceton;
|
||||
@@ -0,0 +1,30 @@
|
||||
#include "../subghz_test_app_i.h"
|
||||
|
||||
// Generate scene on_enter handlers array
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
|
||||
void (*const subghz_test_scene_on_enter_handlers[])(void*) = {
|
||||
#include "subghz_test_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 subghz_test_scene_on_event_handlers[])(void* context, SceneManagerEvent event) = {
|
||||
#include "subghz_test_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 subghz_test_scene_on_exit_handlers[])(void* context) = {
|
||||
#include "subghz_test_scene_config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Initialize scene handlers configuration structure
|
||||
const SceneManagerHandlers subghz_test_scene_handlers = {
|
||||
.on_enter_handlers = subghz_test_scene_on_enter_handlers,
|
||||
.on_event_handlers = subghz_test_scene_on_event_handlers,
|
||||
.on_exit_handlers = subghz_test_scene_on_exit_handlers,
|
||||
.scene_num = SubGhzTestSceneNum,
|
||||
};
|
||||
+8
-8
@@ -3,27 +3,27 @@
|
||||
#include <gui/scene_manager.h>
|
||||
|
||||
// Generate scene id and total number
|
||||
#define ADD_SCENE(prefix, name, id) SubRemScene##id,
|
||||
#define ADD_SCENE(prefix, name, id) SubGhzTestScene##id,
|
||||
typedef enum {
|
||||
#include "subrem_scene_config.h"
|
||||
SubRemSceneNum,
|
||||
} SubRemScene;
|
||||
#include "subghz_test_scene_config.h"
|
||||
SubGhzTestSceneNum,
|
||||
} SubGhzTestScene;
|
||||
#undef ADD_SCENE
|
||||
|
||||
extern const SceneManagerHandlers subrem_scene_handlers;
|
||||
extern const SceneManagerHandlers subghz_test_scene_handlers;
|
||||
|
||||
// Generate scene on_enter handlers declaration
|
||||
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
|
||||
#include "subrem_scene_config.h"
|
||||
#include "subghz_test_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 "subrem_scene_config.h"
|
||||
#include "subghz_test_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 "subrem_scene_config.h"
|
||||
#include "subghz_test_scene_config.h"
|
||||
#undef ADD_SCENE
|
||||
@@ -0,0 +1,66 @@
|
||||
#include "../subghz_test_app_i.h"
|
||||
|
||||
void subghz_test_scene_about_widget_callback(GuiButtonType result, InputType type, void* context) {
|
||||
SubGhzTestApp* app = context;
|
||||
if(type == InputTypeShort) {
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, result);
|
||||
}
|
||||
}
|
||||
|
||||
void subghz_test_scene_about_on_enter(void* context) {
|
||||
SubGhzTestApp* app = context;
|
||||
|
||||
FuriString* temp_str;
|
||||
temp_str = furi_string_alloc();
|
||||
furi_string_printf(temp_str, "\e#%s\n", "Information");
|
||||
|
||||
furi_string_cat_printf(temp_str, "Version: %s\n", SUBGHZ_TEST_VERSION_APP);
|
||||
furi_string_cat_printf(temp_str, "Developed by: %s\n", SUBGHZ_TEST_DEVELOPED);
|
||||
furi_string_cat_printf(temp_str, "Github: %s\n\n", SUBGHZ_TEST_GITHUB);
|
||||
|
||||
furi_string_cat_printf(temp_str, "\e#%s\n", "Description");
|
||||
furi_string_cat_printf(
|
||||
temp_str,
|
||||
"This application is designed\nto test the functionality of the\nbuilt-in CC1101 module.\n\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! Sub-Ghz Test \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, SubGhzTestViewWidget);
|
||||
}
|
||||
|
||||
bool subghz_test_scene_about_on_event(void* context, SceneManagerEvent event) {
|
||||
SubGhzTestApp* app = context;
|
||||
bool consumed = false;
|
||||
UNUSED(app);
|
||||
UNUSED(event);
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void subghz_test_scene_about_on_exit(void* context) {
|
||||
SubGhzTestApp* app = context;
|
||||
|
||||
// Clear views
|
||||
widget_reset(app->widget);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
#include "../subghz_test_app_i.h"
|
||||
|
||||
void subghz_test_scene_carrier_callback(SubGhzTestCarrierEvent event, void* context) {
|
||||
furi_assert(context);
|
||||
SubGhzTestApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, event);
|
||||
}
|
||||
|
||||
void subghz_test_scene_carrier_on_enter(void* context) {
|
||||
SubGhzTestApp* app = context;
|
||||
subghz_test_carrier_set_callback(
|
||||
app->subghz_test_carrier, subghz_test_scene_carrier_callback, app);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, SubGhzTestViewCarrier);
|
||||
}
|
||||
|
||||
bool subghz_test_scene_carrier_on_event(void* context, SceneManagerEvent event) {
|
||||
SubGhzTestApp* app = context;
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubGhzTestCarrierEventOnlyRx) {
|
||||
scene_manager_next_scene(app->scene_manager, SubGhzTestSceneShowOnlyRx);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void subghz_test_scene_carrier_on_exit(void* context) {
|
||||
UNUSED(context);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
ADD_SCENE(subghz_test, start, Start)
|
||||
ADD_SCENE(subghz_test, about, About)
|
||||
ADD_SCENE(subghz_test, carrier, Carrier)
|
||||
ADD_SCENE(subghz_test, packet, Packet)
|
||||
ADD_SCENE(subghz_test, static, Static)
|
||||
ADD_SCENE(subghz_test, show_only_rx, ShowOnlyRx)
|
||||
@@ -0,0 +1,29 @@
|
||||
#include "../subghz_test_app_i.h"
|
||||
|
||||
void subghz_test_scene_packet_callback(SubGhzTestPacketEvent event, void* context) {
|
||||
furi_assert(context);
|
||||
SubGhzTestApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, event);
|
||||
}
|
||||
|
||||
void subghz_test_scene_packet_on_enter(void* context) {
|
||||
SubGhzTestApp* app = context;
|
||||
subghz_test_packet_set_callback(
|
||||
app->subghz_test_packet, subghz_test_scene_packet_callback, app);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, SubGhzTestViewPacket);
|
||||
}
|
||||
|
||||
bool subghz_test_scene_packet_on_event(void* context, SceneManagerEvent event) {
|
||||
SubGhzTestApp* app = context;
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubGhzTestPacketEventOnlyRx) {
|
||||
scene_manager_next_scene(app->scene_manager, SubGhzTestSceneShowOnlyRx);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void subghz_test_scene_packet_on_exit(void* context) {
|
||||
UNUSED(context);
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
#include "../subghz_test_app_i.h"
|
||||
#include <subghz_test_icons.h>
|
||||
|
||||
void subghz_test_scene_show_only_rx_popup_callback(void* context) {
|
||||
SubGhzTestApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, SubGhzTestCustomEventSceneShowOnlyRX);
|
||||
}
|
||||
|
||||
void subghz_test_scene_show_only_rx_on_enter(void* context) {
|
||||
SubGhzTestApp* app = context;
|
||||
|
||||
// Setup view
|
||||
Popup* popup = app->popup;
|
||||
|
||||
const char* header_text = "Transmission is blocked";
|
||||
const char* message_text = "Transmission on\nthis frequency is\nrestricted in\nyour region";
|
||||
if(!furi_hal_region_is_provisioned()) {
|
||||
header_text = "Firmware update needed";
|
||||
message_text = "Please update\nfirmware before\nusing this feature\nflipp.dev/upd";
|
||||
}
|
||||
|
||||
popup_set_header(popup, header_text, 63, 3, AlignCenter, AlignTop);
|
||||
popup_set_text(popup, message_text, 0, 17, AlignLeft, AlignTop);
|
||||
popup_set_icon(popup, 72, 17, &I_DolphinCommon_56x48);
|
||||
|
||||
popup_set_timeout(popup, 1500);
|
||||
popup_set_context(popup, app);
|
||||
popup_set_callback(popup, subghz_test_scene_show_only_rx_popup_callback);
|
||||
popup_enable_timeout(popup);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, SubGhzTestViewPopup);
|
||||
}
|
||||
|
||||
bool subghz_test_scene_show_only_rx_on_event(void* context, SceneManagerEvent event) {
|
||||
SubGhzTestApp* app = context;
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubGhzTestCustomEventSceneShowOnlyRX) {
|
||||
scene_manager_previous_scene(app->scene_manager);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void subghz_test_scene_show_only_rx_on_exit(void* context) {
|
||||
SubGhzTestApp* app = context;
|
||||
Popup* popup = app->popup;
|
||||
|
||||
popup_reset(popup);
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
#include "../subghz_test_app_i.h"
|
||||
|
||||
typedef enum {
|
||||
SubmenuIndexSubGhzTestCarrier,
|
||||
SubmenuIndexSubGhzTestPacket,
|
||||
SubmenuIndexSubGhzTestStatic,
|
||||
SubmenuIndexSubGhzTestAbout,
|
||||
} SubmenuIndex;
|
||||
|
||||
void subghz_test_scene_start_submenu_callback(void* context, uint32_t index) {
|
||||
SubGhzTestApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, index);
|
||||
}
|
||||
|
||||
void subghz_test_scene_start_on_enter(void* context) {
|
||||
SubGhzTestApp* app = context;
|
||||
Submenu* submenu = app->submenu;
|
||||
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Carrier",
|
||||
SubmenuIndexSubGhzTestCarrier,
|
||||
subghz_test_scene_start_submenu_callback,
|
||||
app);
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Packet",
|
||||
SubmenuIndexSubGhzTestPacket,
|
||||
subghz_test_scene_start_submenu_callback,
|
||||
app);
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Static",
|
||||
SubmenuIndexSubGhzTestStatic,
|
||||
subghz_test_scene_start_submenu_callback,
|
||||
app);
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"About",
|
||||
SubmenuIndexSubGhzTestAbout,
|
||||
subghz_test_scene_start_submenu_callback,
|
||||
app);
|
||||
|
||||
submenu_set_selected_item(
|
||||
submenu, scene_manager_get_scene_state(app->scene_manager, SubGhzTestSceneStart));
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, SubGhzTestViewSubmenu);
|
||||
}
|
||||
|
||||
bool subghz_test_scene_start_on_event(void* context, SceneManagerEvent event) {
|
||||
SubGhzTestApp* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubmenuIndexSubGhzTestAbout) {
|
||||
scene_manager_next_scene(app->scene_manager, SubGhzTestSceneAbout);
|
||||
consumed = true;
|
||||
} else if(event.event == SubmenuIndexSubGhzTestCarrier) {
|
||||
scene_manager_next_scene(app->scene_manager, SubGhzTestSceneCarrier);
|
||||
consumed = true;
|
||||
} else if(event.event == SubmenuIndexSubGhzTestPacket) {
|
||||
scene_manager_next_scene(app->scene_manager, SubGhzTestScenePacket);
|
||||
consumed = true;
|
||||
} else if(event.event == SubmenuIndexSubGhzTestStatic) {
|
||||
scene_manager_next_scene(app->scene_manager, SubGhzTestSceneStatic);
|
||||
consumed = true;
|
||||
}
|
||||
scene_manager_set_scene_state(app->scene_manager, SubGhzTestSceneStart, event.event);
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void subghz_test_scene_start_on_exit(void* context) {
|
||||
SubGhzTestApp* app = context;
|
||||
submenu_reset(app->submenu);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
#include "../subghz_test_app_i.h"
|
||||
|
||||
void subghz_test_scene_static_callback(SubGhzTestStaticEvent event, void* context) {
|
||||
furi_assert(context);
|
||||
SubGhzTestApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, event);
|
||||
}
|
||||
|
||||
void subghz_test_scene_static_on_enter(void* context) {
|
||||
SubGhzTestApp* app = context;
|
||||
subghz_test_static_set_callback(
|
||||
app->subghz_test_static, subghz_test_scene_static_callback, app);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, SubGhzTestViewStatic);
|
||||
}
|
||||
|
||||
bool subghz_test_scene_static_on_event(void* context, SceneManagerEvent event) {
|
||||
SubGhzTestApp* app = context;
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubGhzTestStaticEventOnlyRx) {
|
||||
scene_manager_next_scene(app->scene_manager, SubGhzTestSceneShowOnlyRx);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void subghz_test_scene_static_on_exit(void* context) {
|
||||
UNUSED(context);
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 181 B |
@@ -0,0 +1,139 @@
|
||||
#include "subghz_test_app_i.h"
|
||||
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
|
||||
static bool subghz_test_app_custom_event_callback(void* context, uint32_t event) {
|
||||
furi_assert(context);
|
||||
SubGhzTestApp* app = context;
|
||||
return scene_manager_handle_custom_event(app->scene_manager, event);
|
||||
}
|
||||
|
||||
static bool subghz_test_app_back_event_callback(void* context) {
|
||||
furi_assert(context);
|
||||
SubGhzTestApp* app = context;
|
||||
return scene_manager_handle_back_event(app->scene_manager);
|
||||
}
|
||||
|
||||
static void subghz_test_app_tick_event_callback(void* context) {
|
||||
furi_assert(context);
|
||||
SubGhzTestApp* app = context;
|
||||
scene_manager_handle_tick_event(app->scene_manager);
|
||||
}
|
||||
|
||||
SubGhzTestApp* subghz_test_app_alloc() {
|
||||
SubGhzTestApp* app = malloc(sizeof(SubGhzTestApp));
|
||||
|
||||
// GUI
|
||||
app->gui = furi_record_open(RECORD_GUI);
|
||||
|
||||
// View Dispatcher
|
||||
app->view_dispatcher = view_dispatcher_alloc();
|
||||
app->scene_manager = scene_manager_alloc(&subghz_test_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, subghz_test_app_custom_event_callback);
|
||||
view_dispatcher_set_navigation_event_callback(
|
||||
app->view_dispatcher, subghz_test_app_back_event_callback);
|
||||
view_dispatcher_set_tick_event_callback(
|
||||
app->view_dispatcher, subghz_test_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, SubGhzTestViewSubmenu, submenu_get_view(app->submenu));
|
||||
|
||||
// Widget
|
||||
app->widget = widget_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, SubGhzTestViewWidget, widget_get_view(app->widget));
|
||||
|
||||
// Popup
|
||||
app->popup = popup_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, SubGhzTestViewPopup, popup_get_view(app->popup));
|
||||
|
||||
// Carrier Test Module
|
||||
app->subghz_test_carrier = subghz_test_carrier_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher,
|
||||
SubGhzTestViewCarrier,
|
||||
subghz_test_carrier_get_view(app->subghz_test_carrier));
|
||||
|
||||
// Packet Test
|
||||
app->subghz_test_packet = subghz_test_packet_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher,
|
||||
SubGhzTestViewPacket,
|
||||
subghz_test_packet_get_view(app->subghz_test_packet));
|
||||
|
||||
// Static send
|
||||
app->subghz_test_static = subghz_test_static_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher,
|
||||
SubGhzTestViewStatic,
|
||||
subghz_test_static_get_view(app->subghz_test_static));
|
||||
|
||||
scene_manager_next_scene(app->scene_manager, SubGhzTestSceneStart);
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
void subghz_test_app_free(SubGhzTestApp* app) {
|
||||
furi_assert(app);
|
||||
|
||||
// Submenu
|
||||
view_dispatcher_remove_view(app->view_dispatcher, SubGhzTestViewSubmenu);
|
||||
submenu_free(app->submenu);
|
||||
|
||||
// Widget
|
||||
view_dispatcher_remove_view(app->view_dispatcher, SubGhzTestViewWidget);
|
||||
widget_free(app->widget);
|
||||
|
||||
// Popup
|
||||
view_dispatcher_remove_view(app->view_dispatcher, SubGhzTestViewPopup);
|
||||
popup_free(app->popup);
|
||||
|
||||
// Carrier Test
|
||||
view_dispatcher_remove_view(app->view_dispatcher, SubGhzTestViewCarrier);
|
||||
subghz_test_carrier_free(app->subghz_test_carrier);
|
||||
|
||||
// Packet Test
|
||||
view_dispatcher_remove_view(app->view_dispatcher, SubGhzTestViewPacket);
|
||||
subghz_test_packet_free(app->subghz_test_packet);
|
||||
|
||||
// Static
|
||||
view_dispatcher_remove_view(app->view_dispatcher, SubGhzTestViewStatic);
|
||||
subghz_test_static_free(app->subghz_test_static);
|
||||
|
||||
// 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);
|
||||
|
||||
free(app);
|
||||
}
|
||||
|
||||
int32_t subghz_test_app(void* p) {
|
||||
UNUSED(p);
|
||||
SubGhzTestApp* subghz_test_app = subghz_test_app_alloc();
|
||||
|
||||
view_dispatcher_run(subghz_test_app->view_dispatcher);
|
||||
|
||||
subghz_test_app_free(subghz_test_app);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
#include "subghz_test_app_i.h"
|
||||
|
||||
#include <furi.h>
|
||||
|
||||
#define TAG "SubGhzTest"
|
||||
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include "helpers/subghz_test_types.h"
|
||||
#include "helpers/subghz_test_event.h"
|
||||
|
||||
#include "scenes/subghz_test_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 <gui/modules/popup.h>
|
||||
#include <notification/notification_messages.h>
|
||||
|
||||
#include "views/subghz_test_static.h"
|
||||
#include "views/subghz_test_carrier.h"
|
||||
#include "views/subghz_test_packet.h"
|
||||
|
||||
typedef struct SubGhzTestApp SubGhzTestApp;
|
||||
|
||||
struct SubGhzTestApp {
|
||||
Gui* gui;
|
||||
ViewDispatcher* view_dispatcher;
|
||||
SceneManager* scene_manager;
|
||||
NotificationApp* notifications;
|
||||
Submenu* submenu;
|
||||
Widget* widget;
|
||||
Popup* popup;
|
||||
SubGhzTestStatic* subghz_test_static;
|
||||
SubGhzTestCarrier* subghz_test_carrier;
|
||||
SubGhzTestPacket* subghz_test_packet;
|
||||
};
|
||||
+49
-13
@@ -1,6 +1,7 @@
|
||||
#include "subghz_test_carrier.h"
|
||||
#include "../subghz_i.h"
|
||||
#include "../helpers/subghz_testing.h"
|
||||
#include "../subghz_test_app_i.h"
|
||||
#include "../helpers/subghz_test_frequency.h"
|
||||
#include <lib/subghz/devices/cc1101_configs.h>
|
||||
|
||||
#include <math.h>
|
||||
#include <furi.h>
|
||||
@@ -11,6 +12,7 @@ struct SubGhzTestCarrier {
|
||||
View* view;
|
||||
FuriTimer* timer;
|
||||
SubGhzTestCarrierCallback callback;
|
||||
// const SubGhzDevice* radio_device;
|
||||
void* context;
|
||||
};
|
||||
|
||||
@@ -83,6 +85,7 @@ void subghz_test_carrier_draw(Canvas* canvas, SubGhzTestCarrierModel* model) {
|
||||
bool subghz_test_carrier_input(InputEvent* event, void* context) {
|
||||
furi_assert(context);
|
||||
SubGhzTestCarrier* subghz_test_carrier = context;
|
||||
// const SubGhzDevice* radio_device = subghz_test_carrier->radio_device;
|
||||
|
||||
if(event->key == InputKeyBack || event->type != InputTypeShort) {
|
||||
return false;
|
||||
@@ -93,6 +96,7 @@ bool subghz_test_carrier_input(InputEvent* event, void* context) {
|
||||
SubGhzTestCarrierModel * model,
|
||||
{
|
||||
furi_hal_subghz_idle();
|
||||
// subghz_devices_idle(radio_device);
|
||||
|
||||
if(event->key == InputKeyLeft) {
|
||||
if(model->frequency > 0) model->frequency--;
|
||||
@@ -113,24 +117,36 @@ bool subghz_test_carrier_input(InputEvent* event, void* context) {
|
||||
model->real_frequency =
|
||||
furi_hal_subghz_set_frequency(subghz_frequencies_testing[model->frequency]);
|
||||
furi_hal_subghz_set_path(model->path);
|
||||
// model->real_frequency = subghz_devices_set_frequency(
|
||||
// radio_device, subghz_frequencies_testing[model->frequency]);
|
||||
|
||||
if(model->status == SubGhzTestCarrierModelStatusRx) {
|
||||
furi_hal_gpio_init(
|
||||
furi_hal_subghz.cc1101_g0_pin, GpioModeInput, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_subghz_rx();
|
||||
// furi_hal_gpio_init(
|
||||
// subghz_devices_get_data_gpio(radio_device),
|
||||
// GpioModeInput,
|
||||
// GpioPullNo,
|
||||
// GpioSpeedLow);
|
||||
// subghz_devices_set_rx(radio_device);
|
||||
} else {
|
||||
furi_hal_gpio_init(
|
||||
furi_hal_subghz.cc1101_g0_pin,
|
||||
GpioModeOutputPushPull,
|
||||
GpioPullNo,
|
||||
GpioSpeedLow);
|
||||
furi_hal_gpio_write(furi_hal_subghz.cc1101_g0_pin, true);
|
||||
&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_write(&gpio_cc1101_g0, true);
|
||||
if(!furi_hal_subghz_tx()) {
|
||||
furi_hal_gpio_init(
|
||||
furi_hal_subghz.cc1101_g0_pin, GpioModeInput, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow);
|
||||
subghz_test_carrier->callback(
|
||||
SubGhzTestCarrierEventOnlyRx, subghz_test_carrier->context);
|
||||
}
|
||||
// if(!subghz_devices_set_tx(radio_device)) {
|
||||
// furi_hal_gpio_init(
|
||||
// subghz_devices_get_data_gpio(radio_device),
|
||||
// GpioModeInput,
|
||||
// GpioPullNo,
|
||||
// GpioSpeedLow);
|
||||
// subghz_test_carrier->callback(
|
||||
// SubGhzTestCarrierEventOnlyRx, subghz_test_carrier->context);
|
||||
// }
|
||||
}
|
||||
},
|
||||
true);
|
||||
@@ -141,11 +157,19 @@ bool subghz_test_carrier_input(InputEvent* event, void* context) {
|
||||
void subghz_test_carrier_enter(void* context) {
|
||||
furi_assert(context);
|
||||
SubGhzTestCarrier* subghz_test_carrier = context;
|
||||
// furi_assert(subghz_test_carrier->radio_device);
|
||||
// const SubGhzDevice* radio_device = subghz_test_carrier->radio_device;
|
||||
|
||||
furi_hal_subghz_reset();
|
||||
furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async);
|
||||
furi_hal_subghz_load_custom_preset(subghz_device_cc1101_preset_ook_650khz_async_regs);
|
||||
|
||||
furi_hal_gpio_init(furi_hal_subghz.cc1101_g0_pin, GpioModeInput, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow);
|
||||
|
||||
// subghz_devices_reset(radio_device);
|
||||
// subghz_devices_load_preset(radio_device, FuriHalSubGhzPresetOok650Async, NULL);
|
||||
|
||||
// furi_hal_gpio_init(
|
||||
// subghz_devices_get_data_gpio(radio_device), GpioModeInput, GpioPullNo, GpioSpeedLow);
|
||||
|
||||
with_view_model(
|
||||
subghz_test_carrier->view,
|
||||
@@ -154,6 +178,8 @@ void subghz_test_carrier_enter(void* context) {
|
||||
model->frequency = subghz_frequencies_433_92_testing; // 433
|
||||
model->real_frequency =
|
||||
furi_hal_subghz_set_frequency(subghz_frequencies_testing[model->frequency]);
|
||||
// model->real_frequency = subghz_devices_set_frequency(
|
||||
// radio_device, subghz_frequencies_testing[model->frequency]);
|
||||
model->path = FuriHalSubGhzPathIsolate; // isolate
|
||||
model->rssi = 0.0f;
|
||||
model->status = SubGhzTestCarrierModelStatusRx;
|
||||
@@ -161,6 +187,7 @@ void subghz_test_carrier_enter(void* context) {
|
||||
true);
|
||||
|
||||
furi_hal_subghz_rx();
|
||||
// subghz_devices_set_rx(radio_device);
|
||||
|
||||
furi_timer_start(subghz_test_carrier->timer, furi_kernel_get_tick_frequency() / 4);
|
||||
}
|
||||
@@ -173,6 +200,7 @@ void subghz_test_carrier_exit(void* context) {
|
||||
|
||||
// Reinitialize IC to default state
|
||||
furi_hal_subghz_sleep();
|
||||
// subghz_devices_sleep(subghz_test_carrier->radio_device);
|
||||
}
|
||||
|
||||
void subghz_test_carrier_rssi_timer_callback(void* context) {
|
||||
@@ -185,6 +213,7 @@ void subghz_test_carrier_rssi_timer_callback(void* context) {
|
||||
{
|
||||
if(model->status == SubGhzTestCarrierModelStatusRx) {
|
||||
model->rssi = furi_hal_subghz_get_rssi();
|
||||
// model->rssi = subghz_devices_get_rssi(subghz_test_carrier->radio_device);
|
||||
}
|
||||
},
|
||||
false);
|
||||
@@ -220,3 +249,10 @@ View* subghz_test_carrier_get_view(SubGhzTestCarrier* subghz_test_carrier) {
|
||||
furi_assert(subghz_test_carrier);
|
||||
return subghz_test_carrier->view;
|
||||
}
|
||||
|
||||
// void subghz_test_carrier_set_radio(
|
||||
// SubGhzTestCarrier* subghz_test_carrier,
|
||||
// const SubGhzDevice* radio_device) {
|
||||
// furi_assert(subghz_test_carrier);
|
||||
// subghz_test_carrier->radio_device = radio_device;
|
||||
// }
|
||||
+5
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
// #include <lib/subghz/devices/devices.h>
|
||||
|
||||
typedef enum {
|
||||
SubGhzTestCarrierEventOnlyRx,
|
||||
@@ -20,3 +21,7 @@ SubGhzTestCarrier* subghz_test_carrier_alloc();
|
||||
void subghz_test_carrier_free(SubGhzTestCarrier* subghz_test_carrier);
|
||||
|
||||
View* subghz_test_carrier_get_view(SubGhzTestCarrier* subghz_test_carrier);
|
||||
|
||||
// void subghz_test_carrier_set_radio(
|
||||
// SubGhzTestCarrier* subghz_test_carrier,
|
||||
// const SubGhzDevice* radio_device);
|
||||
+5
-4
@@ -1,13 +1,14 @@
|
||||
#include "subghz_test_packet.h"
|
||||
#include "../subghz_i.h"
|
||||
#include "../helpers/subghz_testing.h"
|
||||
#include "../subghz_test_app_i.h"
|
||||
#include "../helpers/subghz_test_frequency.h"
|
||||
#include <lib/subghz/devices/cc1101_configs.h>
|
||||
|
||||
#include <math.h>
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <input/input.h>
|
||||
#include <toolbox/level_duration.h>
|
||||
#include <lib/subghz/protocols/princeton_for_testing.h>
|
||||
#include "../protocol/princeton_for_testing.h"
|
||||
|
||||
#define SUBGHZ_TEST_PACKET_COUNT 500
|
||||
|
||||
@@ -194,7 +195,7 @@ void subghz_test_packet_enter(void* context) {
|
||||
SubGhzTestPacket* instance = context;
|
||||
|
||||
furi_hal_subghz_reset();
|
||||
furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async);
|
||||
furi_hal_subghz_load_custom_preset(subghz_device_cc1101_preset_ook_650khz_async_regs);
|
||||
|
||||
with_view_model(
|
||||
instance->view,
|
||||
+7
-7
@@ -1,13 +1,14 @@
|
||||
#include "subghz_test_static.h"
|
||||
#include "../subghz_i.h"
|
||||
#include "../helpers/subghz_testing.h"
|
||||
#include "../subghz_test_app_i.h"
|
||||
#include "../helpers/subghz_test_frequency.h"
|
||||
#include <lib/subghz/devices/cc1101_configs.h>
|
||||
|
||||
#include <math.h>
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <input/input.h>
|
||||
#include <notification/notification_messages.h>
|
||||
#include <lib/subghz/protocols/princeton_for_testing.h>
|
||||
#include "../protocol/princeton_for_testing.h"
|
||||
|
||||
#define TAG "SubGhzTestStatic"
|
||||
|
||||
@@ -141,11 +142,10 @@ void subghz_test_static_enter(void* context) {
|
||||
SubGhzTestStatic* instance = context;
|
||||
|
||||
furi_hal_subghz_reset();
|
||||
furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async);
|
||||
furi_hal_subghz_load_custom_preset(subghz_device_cc1101_preset_ook_650khz_async_regs);
|
||||
|
||||
furi_hal_gpio_init(
|
||||
furi_hal_subghz.cc1101_g0_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_write(furi_hal_subghz.cc1101_g0_pin, false);
|
||||
furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_write(&gpio_cc1101_g0, false);
|
||||
instance->status_tx = SubGhzTestStaticStatusIDLE;
|
||||
|
||||
with_view_model(
|
||||
@@ -425,6 +425,7 @@ MU_TEST(infrared_test_decoder_mixed) {
|
||||
infrared_test_run_decoder(InfraredProtocolSamsung32, 1);
|
||||
infrared_test_run_decoder(InfraredProtocolSIRC, 3);
|
||||
infrared_test_run_decoder(InfraredProtocolKaseikyo, 1);
|
||||
infrared_test_run_decoder(InfraredProtocolRCA, 1);
|
||||
}
|
||||
|
||||
MU_TEST(infrared_test_decoder_nec) {
|
||||
@@ -499,6 +500,15 @@ MU_TEST(infrared_test_decoder_kaseikyo) {
|
||||
infrared_test_run_decoder(InfraredProtocolKaseikyo, 6);
|
||||
}
|
||||
|
||||
MU_TEST(infrared_test_decoder_rca) {
|
||||
infrared_test_run_decoder(InfraredProtocolRCA, 1);
|
||||
infrared_test_run_decoder(InfraredProtocolRCA, 2);
|
||||
infrared_test_run_decoder(InfraredProtocolRCA, 3);
|
||||
infrared_test_run_decoder(InfraredProtocolRCA, 4);
|
||||
infrared_test_run_decoder(InfraredProtocolRCA, 5);
|
||||
infrared_test_run_decoder(InfraredProtocolRCA, 6);
|
||||
}
|
||||
|
||||
MU_TEST(infrared_test_encoder_decoder_all) {
|
||||
infrared_test_run_encoder_decoder(InfraredProtocolNEC, 1);
|
||||
infrared_test_run_encoder_decoder(InfraredProtocolNECext, 1);
|
||||
@@ -509,6 +519,7 @@ MU_TEST(infrared_test_encoder_decoder_all) {
|
||||
infrared_test_run_encoder_decoder(InfraredProtocolRC5, 1);
|
||||
infrared_test_run_encoder_decoder(InfraredProtocolSIRC, 1);
|
||||
infrared_test_run_encoder_decoder(InfraredProtocolKaseikyo, 1);
|
||||
infrared_test_run_encoder_decoder(InfraredProtocolRCA, 1);
|
||||
}
|
||||
|
||||
MU_TEST_SUITE(infrared_test) {
|
||||
@@ -527,6 +538,7 @@ MU_TEST_SUITE(infrared_test) {
|
||||
MU_RUN_TEST(infrared_test_decoder_samsung32);
|
||||
MU_RUN_TEST(infrared_test_decoder_necext1);
|
||||
MU_RUN_TEST(infrared_test_decoder_kaseikyo);
|
||||
MU_RUN_TEST(infrared_test_decoder_rca);
|
||||
MU_RUN_TEST(infrared_test_decoder_mixed);
|
||||
MU_RUN_TEST(infrared_test_encoder_decoder_all);
|
||||
}
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <stm32wbxx_ll_tim.h>
|
||||
#include <storage/storage.h>
|
||||
#include <lib/flipper_format/flipper_format.h>
|
||||
#include <lib/nfc/protocols/nfca.h>
|
||||
#include <lib/nfc/helpers/mf_classic_dict.h>
|
||||
#include <lib/digital_signal/digital_signal.h>
|
||||
#include <lib/pulse_reader/pulse_reader.h>
|
||||
#include <lib/nfc/nfc_device.h>
|
||||
#include <lib/nfc/helpers/nfc_generators.h>
|
||||
|
||||
@@ -224,153 +222,6 @@ MU_TEST(nfc_digital_signal_test) {
|
||||
"NFC long digital signal test failed\r\n");
|
||||
}
|
||||
|
||||
static bool nfc_test_pulse_reader_toggle(
|
||||
uint32_t usec_low,
|
||||
uint32_t usec_high,
|
||||
uint32_t period_count,
|
||||
uint32_t tolerance) {
|
||||
furi_assert(nfc_test);
|
||||
|
||||
bool success = false;
|
||||
uint32_t pulses = 0;
|
||||
const GpioPin* gpio_in = &gpio_ext_pa6;
|
||||
const GpioPin* gpio_out = &gpio_ext_pa7;
|
||||
PulseReader* reader = NULL;
|
||||
|
||||
do {
|
||||
reader = pulse_reader_alloc(gpio_in, 512);
|
||||
|
||||
if(!reader) {
|
||||
FURI_LOG_E(TAG, "failed to allocate pulse reader");
|
||||
break;
|
||||
}
|
||||
|
||||
/* use TIM1 to create a specific number of pulses with defined duty cycle
|
||||
but first set the IO to high, so the low/high pulse can get detected */
|
||||
furi_hal_gpio_init(gpio_out, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
|
||||
furi_hal_gpio_write(gpio_out, true);
|
||||
|
||||
LL_TIM_DeInit(TIM1);
|
||||
|
||||
LL_TIM_SetCounterMode(TIM1, LL_TIM_COUNTERMODE_UP);
|
||||
LL_TIM_SetRepetitionCounter(TIM1, 0);
|
||||
LL_TIM_SetClockDivision(TIM1, LL_TIM_CLOCKDIVISION_DIV1);
|
||||
LL_TIM_SetClockSource(TIM1, LL_TIM_CLOCKSOURCE_INTERNAL);
|
||||
LL_TIM_DisableARRPreload(TIM1);
|
||||
|
||||
LL_TIM_OC_DisablePreload(TIM1, LL_TIM_CHANNEL_CH1);
|
||||
LL_TIM_OC_SetMode(TIM1, LL_TIM_CHANNEL_CH1, LL_TIM_OCMODE_PWM2);
|
||||
LL_TIM_OC_SetPolarity(TIM1, LL_TIM_CHANNEL_CH1N, LL_TIM_OCPOLARITY_HIGH);
|
||||
LL_TIM_OC_DisableFast(TIM1, LL_TIM_CHANNEL_CH1);
|
||||
LL_TIM_CC_EnableChannel(TIM1, LL_TIM_CHANNEL_CH1N);
|
||||
|
||||
LL_TIM_EnableAllOutputs(TIM1);
|
||||
|
||||
/* now calculate the TIM1 period and compare values */
|
||||
uint32_t freq_div = 64 * (usec_low + usec_high);
|
||||
uint32_t prescaler = freq_div / 0x10000LU;
|
||||
uint32_t period = freq_div / (prescaler + 1);
|
||||
uint32_t compare = 64 * usec_low / (prescaler + 1);
|
||||
|
||||
LL_TIM_SetPrescaler(TIM1, prescaler);
|
||||
LL_TIM_SetAutoReload(TIM1, period - 1);
|
||||
LL_TIM_SetCounter(TIM1, period - 1);
|
||||
LL_TIM_OC_SetCompareCH1(TIM1, compare);
|
||||
|
||||
/* timer is ready to launch, now start the pulse reader */
|
||||
pulse_reader_set_timebase(reader, PulseReaderUnitMicrosecond);
|
||||
pulse_reader_start(reader);
|
||||
|
||||
/* and quickly enable and switch over the GPIO to the generated signal */
|
||||
LL_TIM_EnableCounter(TIM1);
|
||||
furi_hal_gpio_init_ex(
|
||||
gpio_out, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedVeryHigh, GpioAltFn1TIM1);
|
||||
|
||||
/* now it's time to parse the pulses received by the reader */
|
||||
uint32_t timer_pulses = period_count;
|
||||
uint32_t prev_cnt = 0;
|
||||
|
||||
while(timer_pulses > 0) {
|
||||
/* whenever the counter gets reset, we went through a full period */
|
||||
uint32_t cur_cnt = LL_TIM_GetCounter(TIM1);
|
||||
if(cur_cnt < prev_cnt) {
|
||||
timer_pulses--;
|
||||
}
|
||||
prev_cnt = cur_cnt;
|
||||
}
|
||||
/* quickly halt the counter to keep a static signal */
|
||||
LL_TIM_DisableCounter(TIM1);
|
||||
|
||||
do {
|
||||
/* as all edges were sampled asynchronously, the timeout can be zero */
|
||||
uint32_t length = pulse_reader_receive(reader, 0);
|
||||
|
||||
/* in the last pulse, we expect a "no edge" return value. if seen that, test succeeded. */
|
||||
if(pulses > period_count * 2) {
|
||||
if(length != PULSE_READER_NO_EDGE) {
|
||||
FURI_LOG_E(
|
||||
TAG,
|
||||
"last pulse expected to be PULSE_READER_NO_EDGE, but was %lu.",
|
||||
length);
|
||||
break;
|
||||
}
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
/* else we shall never see "no edge" or "lost edge" */
|
||||
if(length == PULSE_READER_NO_EDGE) {
|
||||
FURI_LOG_E(TAG, "%lu. pulse not expected to be PULSE_READER_NO_EDGE", pulses);
|
||||
break;
|
||||
}
|
||||
if(length == PULSE_READER_LOST_EDGE) {
|
||||
FURI_LOG_E(TAG, "%lu. pulse not expected to be PULSE_READER_LOST_EDGE", pulses);
|
||||
break;
|
||||
}
|
||||
|
||||
if(pulses > 0) {
|
||||
/* throw away the first pulse, which is the 1->0 from the first start and will be irrelevant for our test */
|
||||
bool phase = ((pulses - 1) % 2) == 1;
|
||||
uint32_t expected = phase ? usec_high : usec_low;
|
||||
uint32_t deviation = abs((int32_t)length - (int32_t)expected);
|
||||
|
||||
if(deviation > tolerance) {
|
||||
FURI_LOG_E(
|
||||
TAG,
|
||||
"%lu. pulse expected %lu, but pulse was %lu.",
|
||||
pulses,
|
||||
expected,
|
||||
length);
|
||||
break;
|
||||
}
|
||||
}
|
||||
pulses++;
|
||||
} while(true);
|
||||
} while(false);
|
||||
|
||||
if(reader != NULL) {
|
||||
pulse_reader_stop(reader);
|
||||
pulse_reader_free(reader);
|
||||
}
|
||||
|
||||
LL_TIM_DeInit(TIM1);
|
||||
furi_hal_gpio_init_simple(gpio_in, GpioModeAnalog);
|
||||
furi_hal_gpio_init_simple(gpio_out, GpioModeAnalog);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
MU_TEST(nfc_pulse_reader_test) {
|
||||
mu_assert(nfc_test_pulse_reader_toggle(1500, 2500, 50, 10), "1 ms signal failed\r\n");
|
||||
mu_assert(nfc_test_pulse_reader_toggle(10000, 10000, 10, 10), "10 ms signal failed\r\n");
|
||||
mu_assert(nfc_test_pulse_reader_toggle(100000, 100000, 5, 50), "100 ms signal failed\r\n");
|
||||
mu_assert(nfc_test_pulse_reader_toggle(100, 900, 50, 10), "1 ms asymmetric signal failed\r\n");
|
||||
mu_assert(
|
||||
nfc_test_pulse_reader_toggle(3333, 6666, 10, 10), "10 ms asymmetric signal failed\r\n");
|
||||
mu_assert(
|
||||
nfc_test_pulse_reader_toggle(25000, 75000, 5, 10), "100 ms asymmetric signal failed\r\n");
|
||||
}
|
||||
|
||||
MU_TEST(mf_classic_dict_test) {
|
||||
MfClassicDict* instance = NULL;
|
||||
uint64_t key = 0;
|
||||
@@ -705,7 +556,6 @@ MU_TEST(mf_classic_4k_7b_file_test) {
|
||||
MU_TEST_SUITE(nfc) {
|
||||
nfc_test_alloc();
|
||||
|
||||
MU_RUN_TEST(nfc_pulse_reader_test);
|
||||
MU_RUN_TEST(nfca_file_test);
|
||||
MU_RUN_TEST(mf_mini_file_test);
|
||||
MU_RUN_TEST(mf_classic_1k_4b_file_test);
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
#include <lib/subghz/subghz_file_encoder_worker.h>
|
||||
#include <lib/subghz/protocols/protocol_items.h>
|
||||
#include <flipper_format/flipper_format_i.h>
|
||||
#include <lib/subghz/devices/devices.h>
|
||||
#include <lib/subghz/devices/cc1101_configs.h>
|
||||
|
||||
#define TAG "SubGhz TEST"
|
||||
#define KEYSTORE_DIR_NAME EXT_PATH("subghz/assets/keeloq_mfcodes")
|
||||
@@ -49,12 +51,15 @@ static void subghz_test_init(void) {
|
||||
subghz_environment_set_protocol_registry(
|
||||
environment_handler, (void*)&subghz_protocol_registry);
|
||||
|
||||
subghz_devices_init();
|
||||
|
||||
receiver_handler = subghz_receiver_alloc_init(environment_handler);
|
||||
subghz_receiver_set_filter(receiver_handler, SubGhzProtocolFlag_Decodable);
|
||||
subghz_receiver_set_rx_callback(receiver_handler, subghz_test_rx_callback, NULL);
|
||||
}
|
||||
|
||||
static void subghz_test_deinit(void) {
|
||||
subghz_devices_deinit();
|
||||
subghz_receiver_free(receiver_handler);
|
||||
subghz_environment_free(environment_handler);
|
||||
}
|
||||
@@ -68,7 +73,7 @@ static bool subghz_decoder_test(const char* path, const char* name_decoder) {
|
||||
|
||||
if(decoder) {
|
||||
file_worker_encoder_handler = subghz_file_encoder_worker_alloc();
|
||||
if(subghz_file_encoder_worker_start(file_worker_encoder_handler, path)) {
|
||||
if(subghz_file_encoder_worker_start(file_worker_encoder_handler, path, NULL)) {
|
||||
// the worker needs a file in order to open and read part of the file
|
||||
furi_delay_ms(100);
|
||||
|
||||
@@ -108,7 +113,7 @@ static bool subghz_decode_random_test(const char* path) {
|
||||
uint32_t test_start = furi_get_tick();
|
||||
|
||||
file_worker_encoder_handler = subghz_file_encoder_worker_alloc();
|
||||
if(subghz_file_encoder_worker_start(file_worker_encoder_handler, path)) {
|
||||
if(subghz_file_encoder_worker_start(file_worker_encoder_handler, path, NULL)) {
|
||||
// the worker needs a file in order to open and read part of the file
|
||||
furi_delay_ms(100);
|
||||
|
||||
@@ -318,7 +323,7 @@ bool subghz_hal_async_tx_test_run(SubGhzHalAsyncTxTestType type) {
|
||||
SubGhzHalAsyncTxTest test = {0};
|
||||
test.type = type;
|
||||
furi_hal_subghz_reset();
|
||||
furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async);
|
||||
furi_hal_subghz_load_custom_preset(subghz_device_cc1101_preset_ook_650khz_async_regs);
|
||||
furi_hal_subghz_set_frequency_and_path(433920000);
|
||||
|
||||
if(!furi_hal_subghz_start_async_tx(subghz_hal_async_tx_test_yield, &test)) {
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
# Placeholder
|
||||
App(
|
||||
appid="drivers",
|
||||
name="Drivers device",
|
||||
apptype=FlipperAppType.METAPACKAGE,
|
||||
)
|
||||
@@ -0,0 +1,9 @@
|
||||
App(
|
||||
appid="radio_device_cc1101_ext",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
targets=["f7"],
|
||||
entry_point="subghz_device_cc1101_ext_ep",
|
||||
requires=["subghz"],
|
||||
sdk_headers=["cc1101_ext/cc1101_ext_interconnect.h"],
|
||||
fap_libs=["hwdrivers"],
|
||||
)
|
||||
@@ -0,0 +1,815 @@
|
||||
#include "cc1101_ext.h"
|
||||
#include <lib/subghz/devices/cc1101_configs.h>
|
||||
|
||||
#include <furi_hal_version.h>
|
||||
#include <furi_hal_rtc.h>
|
||||
#include <furi_hal_spi.h>
|
||||
#include <furi_hal_interrupt.h>
|
||||
#include <furi_hal_resources.h>
|
||||
#include <furi_hal_bus.h>
|
||||
|
||||
#include <stm32wbxx_ll_dma.h>
|
||||
#include <furi_hal_cortex.h>
|
||||
|
||||
#include <furi.h>
|
||||
#include <cc1101.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define TAG "SubGhz_Device_CC1101_Ext"
|
||||
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_TX_GPIO &gpio_ext_pb2
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_EXTENDED_RANGE false
|
||||
|
||||
/* DMA Channels definition */
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_DMA DMA2
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_CHANNEL LL_DMA_CHANNEL_3
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_CHANNEL LL_DMA_CHANNEL_4
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_CHANNEL LL_DMA_CHANNEL_5
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_IRQ FuriHalInterruptIdDma2Ch3
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF \
|
||||
SUBGHZ_DEVICE_CC1101_EXT_DMA, SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_CHANNEL
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF \
|
||||
SUBGHZ_DEVICE_CC1101_EXT_DMA, SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_CHANNEL
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_DEF \
|
||||
SUBGHZ_DEVICE_CC1101_EXT_DMA, SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_CHANNEL
|
||||
|
||||
/** Low level buffer dimensions and guard times */
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_FULL (256)
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_HALF \
|
||||
(SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_FULL / 2)
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_GUARD_TIME 999 << 1
|
||||
|
||||
/** SubGhz state */
|
||||
typedef enum {
|
||||
SubGhzDeviceCC1101ExtStateInit, /**< Init pending */
|
||||
SubGhzDeviceCC1101ExtStateIdle, /**< Idle, energy save mode */
|
||||
SubGhzDeviceCC1101ExtStateAsyncRx, /**< Async RX started */
|
||||
SubGhzDeviceCC1101ExtStateAsyncTx, /**< Async TX started, DMA and timer is on */
|
||||
SubGhzDeviceCC1101ExtStateAsyncTxEnd, /**< Async TX complete, cleanup needed */
|
||||
} SubGhzDeviceCC1101ExtState;
|
||||
|
||||
/** SubGhz regulation, receive transmission on the current frequency for the
|
||||
* region */
|
||||
typedef enum {
|
||||
SubGhzDeviceCC1101ExtRegulationOnlyRx, /**only Rx*/
|
||||
SubGhzDeviceCC1101ExtRegulationTxRx, /**TxRx*/
|
||||
} SubGhzDeviceCC1101ExtRegulation;
|
||||
|
||||
typedef struct {
|
||||
uint32_t* buffer;
|
||||
LevelDuration carry_ld;
|
||||
SubGhzDeviceCC1101ExtCallback callback;
|
||||
void* callback_context;
|
||||
uint32_t gpio_tx_buff[2];
|
||||
uint32_t debug_gpio_buff[2];
|
||||
} SubGhzDeviceCC1101ExtAsyncTx;
|
||||
|
||||
typedef struct {
|
||||
uint32_t capture_delta_duration;
|
||||
SubGhzDeviceCC1101ExtCaptureCallback capture_callback;
|
||||
void* capture_callback_context;
|
||||
} SubGhzDeviceCC1101ExtAsyncRx;
|
||||
|
||||
typedef struct {
|
||||
volatile SubGhzDeviceCC1101ExtState state;
|
||||
volatile SubGhzDeviceCC1101ExtRegulation regulation;
|
||||
const GpioPin* async_mirror_pin;
|
||||
FuriHalSpiBusHandle* spi_bus_handle;
|
||||
const GpioPin* g0_pin;
|
||||
SubGhzDeviceCC1101ExtAsyncTx async_tx;
|
||||
SubGhzDeviceCC1101ExtAsyncRx async_rx;
|
||||
} SubGhzDeviceCC1101Ext;
|
||||
|
||||
static SubGhzDeviceCC1101Ext* subghz_device_cc1101_ext = NULL;
|
||||
|
||||
static bool subghz_device_cc1101_ext_check_init() {
|
||||
furi_assert(subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateInit);
|
||||
subghz_device_cc1101_ext->state = SubGhzDeviceCC1101ExtStateIdle;
|
||||
|
||||
bool ret = false;
|
||||
CC1101Status cc1101_status = {0};
|
||||
|
||||
furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
FuriHalCortexTimer timer = furi_hal_cortex_timer_get(100 * 1000);
|
||||
do {
|
||||
// Reset
|
||||
furi_hal_gpio_init(
|
||||
subghz_device_cc1101_ext->g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_init(
|
||||
subghz_device_cc1101_ext->spi_bus_handle->miso,
|
||||
GpioModeInput,
|
||||
GpioPullUp,
|
||||
GpioSpeedLow);
|
||||
|
||||
cc1101_status = cc1101_reset(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
if(cc1101_status.CHIP_RDYn != 0) {
|
||||
//timeout or error
|
||||
break;
|
||||
}
|
||||
cc1101_status = cc1101_write_reg(
|
||||
subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG0, CC1101IocfgHighImpedance);
|
||||
if(cc1101_status.CHIP_RDYn != 0) {
|
||||
//timeout or error
|
||||
break;
|
||||
}
|
||||
// Prepare GD0 for power on self test
|
||||
furi_hal_gpio_init(
|
||||
subghz_device_cc1101_ext->g0_pin, GpioModeInput, GpioPullUp, GpioSpeedLow);
|
||||
|
||||
// GD0 low
|
||||
cc1101_status = cc1101_write_reg(
|
||||
subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG0, CC1101IocfgHW);
|
||||
if(cc1101_status.CHIP_RDYn != 0) {
|
||||
//timeout or error
|
||||
break;
|
||||
}
|
||||
while(furi_hal_gpio_read(subghz_device_cc1101_ext->g0_pin) != false) {
|
||||
if(furi_hal_cortex_timer_is_expired(timer)) {
|
||||
//timeout
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(furi_hal_cortex_timer_is_expired(timer)) {
|
||||
//timeout
|
||||
break;
|
||||
}
|
||||
|
||||
// GD0 high
|
||||
furi_hal_gpio_init(
|
||||
subghz_device_cc1101_ext->g0_pin, GpioModeInput, GpioPullDown, GpioSpeedLow);
|
||||
cc1101_status = cc1101_write_reg(
|
||||
subghz_device_cc1101_ext->spi_bus_handle,
|
||||
CC1101_IOCFG0,
|
||||
CC1101IocfgHW | CC1101_IOCFG_INV);
|
||||
if(cc1101_status.CHIP_RDYn != 0) {
|
||||
//timeout or error
|
||||
break;
|
||||
}
|
||||
while(furi_hal_gpio_read(subghz_device_cc1101_ext->g0_pin) != true) {
|
||||
if(furi_hal_cortex_timer_is_expired(timer)) {
|
||||
//timeout
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(furi_hal_cortex_timer_is_expired(timer)) {
|
||||
//timeout
|
||||
break;
|
||||
}
|
||||
|
||||
// Reset GD0 to floating state
|
||||
cc1101_status = cc1101_write_reg(
|
||||
subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG0, CC1101IocfgHighImpedance);
|
||||
if(cc1101_status.CHIP_RDYn != 0) {
|
||||
//timeout or error
|
||||
break;
|
||||
}
|
||||
furi_hal_gpio_init(
|
||||
subghz_device_cc1101_ext->g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
|
||||
// Go to sleep
|
||||
cc1101_status = cc1101_shutdown(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
if(cc1101_status.CHIP_RDYn != 0) {
|
||||
//timeout or error
|
||||
break;
|
||||
}
|
||||
ret = true;
|
||||
} while(false);
|
||||
|
||||
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
|
||||
if(ret) {
|
||||
FURI_LOG_I(TAG, "Init OK");
|
||||
} else {
|
||||
FURI_LOG_E(TAG, "Init failed");
|
||||
furi_hal_gpio_init(
|
||||
subghz_device_cc1101_ext->g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool subghz_device_cc1101_ext_alloc() {
|
||||
furi_assert(subghz_device_cc1101_ext == NULL);
|
||||
subghz_device_cc1101_ext = malloc(sizeof(SubGhzDeviceCC1101Ext));
|
||||
subghz_device_cc1101_ext->state = SubGhzDeviceCC1101ExtStateInit;
|
||||
subghz_device_cc1101_ext->regulation = SubGhzDeviceCC1101ExtRegulationTxRx;
|
||||
subghz_device_cc1101_ext->async_mirror_pin = NULL;
|
||||
subghz_device_cc1101_ext->spi_bus_handle = &furi_hal_spi_bus_handle_external;
|
||||
subghz_device_cc1101_ext->g0_pin = SUBGHZ_DEVICE_CC1101_EXT_TX_GPIO;
|
||||
|
||||
subghz_device_cc1101_ext->async_rx.capture_delta_duration = 0;
|
||||
|
||||
furi_hal_spi_bus_handle_init(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
return subghz_device_cc1101_ext_check_init();
|
||||
}
|
||||
|
||||
void subghz_device_cc1101_ext_free() {
|
||||
furi_assert(subghz_device_cc1101_ext != NULL);
|
||||
furi_hal_spi_bus_handle_deinit(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
free(subghz_device_cc1101_ext);
|
||||
subghz_device_cc1101_ext = NULL;
|
||||
}
|
||||
|
||||
void subghz_device_cc1101_ext_set_async_mirror_pin(const GpioPin* pin) {
|
||||
subghz_device_cc1101_ext->async_mirror_pin = pin;
|
||||
}
|
||||
|
||||
const GpioPin* subghz_device_cc1101_ext_get_data_gpio() {
|
||||
return subghz_device_cc1101_ext->g0_pin;
|
||||
}
|
||||
|
||||
bool subghz_device_cc1101_ext_is_connect() {
|
||||
bool ret = false;
|
||||
|
||||
if(subghz_device_cc1101_ext == NULL) { // not initialized
|
||||
ret = subghz_device_cc1101_ext_alloc();
|
||||
subghz_device_cc1101_ext_free();
|
||||
} else { // initialized
|
||||
furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
uint8_t partnumber = cc1101_get_partnumber(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
ret = (partnumber != 0) && (partnumber != 0xFF);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void subghz_device_cc1101_ext_sleep() {
|
||||
furi_assert(subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateIdle);
|
||||
furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
|
||||
cc1101_switch_to_idle(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
|
||||
cc1101_write_reg(
|
||||
subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG0, CC1101IocfgHighImpedance);
|
||||
furi_hal_gpio_init(subghz_device_cc1101_ext->g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
|
||||
cc1101_shutdown(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
|
||||
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
}
|
||||
|
||||
void subghz_device_cc1101_ext_dump_state() {
|
||||
furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
printf(
|
||||
"[subghz_device_cc1101_ext] cc1101 chip %d, version %d\r\n",
|
||||
cc1101_get_partnumber(subghz_device_cc1101_ext->spi_bus_handle),
|
||||
cc1101_get_version(subghz_device_cc1101_ext->spi_bus_handle));
|
||||
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
}
|
||||
|
||||
void subghz_device_cc1101_ext_load_custom_preset(const uint8_t* preset_data) {
|
||||
//load config
|
||||
furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
cc1101_reset(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
uint32_t i = 0;
|
||||
uint8_t pa[8] = {0};
|
||||
while(preset_data[i]) {
|
||||
cc1101_write_reg(
|
||||
subghz_device_cc1101_ext->spi_bus_handle, preset_data[i], preset_data[i + 1]);
|
||||
i += 2;
|
||||
}
|
||||
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
|
||||
//load pa table
|
||||
memcpy(&pa[0], &preset_data[i + 2], 8);
|
||||
subghz_device_cc1101_ext_load_patable(pa);
|
||||
|
||||
//show debug
|
||||
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
|
||||
i = 0;
|
||||
FURI_LOG_D(TAG, "Loading custom preset");
|
||||
while(preset_data[i]) {
|
||||
FURI_LOG_D(TAG, "Reg[%lu]: %02X=%02X", i, preset_data[i], preset_data[i + 1]);
|
||||
i += 2;
|
||||
}
|
||||
for(uint8_t y = i; y < i + 10; y++) {
|
||||
FURI_LOG_D(TAG, "PA[%u]: %02X", y, preset_data[y]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void subghz_device_cc1101_ext_load_registers(const uint8_t* data) {
|
||||
furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
cc1101_reset(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
uint32_t i = 0;
|
||||
while(data[i]) {
|
||||
cc1101_write_reg(subghz_device_cc1101_ext->spi_bus_handle, data[i], data[i + 1]);
|
||||
i += 2;
|
||||
}
|
||||
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
}
|
||||
|
||||
void subghz_device_cc1101_ext_load_patable(const uint8_t data[8]) {
|
||||
furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
cc1101_set_pa_table(subghz_device_cc1101_ext->spi_bus_handle, data);
|
||||
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
}
|
||||
|
||||
void subghz_device_cc1101_ext_write_packet(const uint8_t* data, uint8_t size) {
|
||||
furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
cc1101_flush_tx(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
cc1101_write_reg(subghz_device_cc1101_ext->spi_bus_handle, CC1101_FIFO, size);
|
||||
cc1101_write_fifo(subghz_device_cc1101_ext->spi_bus_handle, data, size);
|
||||
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
}
|
||||
|
||||
void subghz_device_cc1101_ext_flush_rx() {
|
||||
furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
cc1101_flush_rx(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
}
|
||||
|
||||
void subghz_device_cc1101_ext_flush_tx() {
|
||||
furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
cc1101_flush_tx(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
}
|
||||
|
||||
bool subghz_device_cc1101_ext_rx_pipe_not_empty() {
|
||||
CC1101RxBytes status[1];
|
||||
furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
cc1101_read_reg(
|
||||
subghz_device_cc1101_ext->spi_bus_handle,
|
||||
(CC1101_STATUS_RXBYTES) | CC1101_BURST,
|
||||
(uint8_t*)status);
|
||||
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
// TODO: you can add a buffer overflow flag if needed
|
||||
if(status->NUM_RXBYTES > 0) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool subghz_device_cc1101_ext_is_rx_data_crc_valid() {
|
||||
furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
uint8_t data[1];
|
||||
cc1101_read_reg(
|
||||
subghz_device_cc1101_ext->spi_bus_handle, CC1101_STATUS_LQI | CC1101_BURST, data);
|
||||
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
if(((data[0] >> 7) & 0x01)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void subghz_device_cc1101_ext_read_packet(uint8_t* data, uint8_t* size) {
|
||||
furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
cc1101_read_fifo(subghz_device_cc1101_ext->spi_bus_handle, data, size);
|
||||
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
}
|
||||
|
||||
void subghz_device_cc1101_ext_shutdown() {
|
||||
furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
// Reset and shutdown
|
||||
cc1101_shutdown(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
}
|
||||
|
||||
void subghz_device_cc1101_ext_reset() {
|
||||
furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
furi_hal_gpio_init(subghz_device_cc1101_ext->g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
cc1101_switch_to_idle(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
cc1101_reset(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
cc1101_write_reg(
|
||||
subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG0, CC1101IocfgHighImpedance);
|
||||
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
}
|
||||
|
||||
void subghz_device_cc1101_ext_idle() {
|
||||
furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
cc1101_switch_to_idle(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
}
|
||||
|
||||
void subghz_device_cc1101_ext_rx() {
|
||||
furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
cc1101_switch_to_rx(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
}
|
||||
|
||||
bool subghz_device_cc1101_ext_tx() {
|
||||
if(subghz_device_cc1101_ext->regulation != SubGhzDeviceCC1101ExtRegulationTxRx) return false;
|
||||
furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
cc1101_switch_to_tx(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
return true;
|
||||
}
|
||||
|
||||
float subghz_device_cc1101_ext_get_rssi() {
|
||||
furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
int32_t rssi_dec = cc1101_get_rssi(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
|
||||
float rssi = rssi_dec;
|
||||
if(rssi_dec >= 128) {
|
||||
rssi = ((rssi - 256.0f) / 2.0f) - 74.0f;
|
||||
} else {
|
||||
rssi = (rssi / 2.0f) - 74.0f;
|
||||
}
|
||||
|
||||
return rssi;
|
||||
}
|
||||
|
||||
uint8_t subghz_device_cc1101_ext_get_lqi() {
|
||||
furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
uint8_t data[1];
|
||||
cc1101_read_reg(
|
||||
subghz_device_cc1101_ext->spi_bus_handle, CC1101_STATUS_LQI | CC1101_BURST, data);
|
||||
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
return data[0] & 0x7F;
|
||||
}
|
||||
|
||||
bool subghz_device_cc1101_ext_is_frequency_valid(uint32_t value) {
|
||||
if(!(value >= 281000000 && value <= 361000000) &&
|
||||
!(value >= 378000000 && value <= 481000000) &&
|
||||
!(value >= 749000000 && value <= 962000000)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool subghz_device_cc1101_ext_is_tx_allowed(uint32_t value) {
|
||||
if(!(SUBGHZ_DEVICE_CC1101_EXT_EXTENDED_RANGE) &&
|
||||
!(value >= 299999755 && value <= 350000335) && // was increased from 348 to 350
|
||||
!(value >= 386999938 && value <= 467750000) && // was increased from 464 to 467.75
|
||||
!(value >= 778999847 && value <= 928000000)) {
|
||||
FURI_LOG_I(TAG, "Frequency blocked - outside default range");
|
||||
return false;
|
||||
} else if(
|
||||
(SUBGHZ_DEVICE_CC1101_EXT_EXTENDED_RANGE) &&
|
||||
!subghz_device_cc1101_ext_is_frequency_valid(value)) {
|
||||
FURI_LOG_I(TAG, "Frequency blocked - outside extended range");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t subghz_device_cc1101_ext_set_frequency(uint32_t value) {
|
||||
if(subghz_device_cc1101_ext_is_tx_allowed(value)) {
|
||||
subghz_device_cc1101_ext->regulation = SubGhzDeviceCC1101ExtRegulationTxRx;
|
||||
} else {
|
||||
subghz_device_cc1101_ext->regulation = SubGhzDeviceCC1101ExtRegulationTxRx;
|
||||
}
|
||||
|
||||
furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
uint32_t real_frequency =
|
||||
cc1101_set_frequency(subghz_device_cc1101_ext->spi_bus_handle, value);
|
||||
cc1101_calibrate(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
|
||||
while(true) {
|
||||
CC1101Status status = cc1101_get_status(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
if(status.STATE == CC1101StateIDLE) break;
|
||||
}
|
||||
|
||||
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
return real_frequency;
|
||||
}
|
||||
|
||||
static bool subghz_device_cc1101_ext_start_debug() {
|
||||
bool ret = false;
|
||||
if(subghz_device_cc1101_ext->async_mirror_pin != NULL) {
|
||||
furi_hal_gpio_init(
|
||||
subghz_device_cc1101_ext->async_mirror_pin,
|
||||
GpioModeOutputPushPull,
|
||||
GpioPullNo,
|
||||
GpioSpeedVeryHigh);
|
||||
ret = true;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool subghz_device_cc1101_ext_stop_debug() {
|
||||
bool ret = false;
|
||||
if(subghz_device_cc1101_ext->async_mirror_pin != NULL) {
|
||||
furi_hal_gpio_init(
|
||||
subghz_device_cc1101_ext->async_mirror_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
ret = true;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void subghz_device_cc1101_ext_capture_ISR() {
|
||||
if(!furi_hal_gpio_read(subghz_device_cc1101_ext->g0_pin)) {
|
||||
if(subghz_device_cc1101_ext->async_rx.capture_callback) {
|
||||
if(subghz_device_cc1101_ext->async_mirror_pin != NULL)
|
||||
furi_hal_gpio_write(subghz_device_cc1101_ext->async_mirror_pin, false);
|
||||
|
||||
subghz_device_cc1101_ext->async_rx.capture_callback(
|
||||
true,
|
||||
LL_TIM_GetCounter(TIM17) << 1,
|
||||
(void*)subghz_device_cc1101_ext->async_rx.capture_callback_context);
|
||||
}
|
||||
} else {
|
||||
if(subghz_device_cc1101_ext->async_rx.capture_callback) {
|
||||
if(subghz_device_cc1101_ext->async_mirror_pin != NULL)
|
||||
furi_hal_gpio_write(subghz_device_cc1101_ext->async_mirror_pin, true);
|
||||
|
||||
subghz_device_cc1101_ext->async_rx.capture_callback(
|
||||
false,
|
||||
LL_TIM_GetCounter(TIM17) << 1,
|
||||
(void*)subghz_device_cc1101_ext->async_rx.capture_callback_context);
|
||||
}
|
||||
}
|
||||
LL_TIM_SetCounter(TIM17, 4); //8>>1
|
||||
}
|
||||
|
||||
void subghz_device_cc1101_ext_start_async_rx(
|
||||
SubGhzDeviceCC1101ExtCaptureCallback callback,
|
||||
void* context) {
|
||||
furi_assert(subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateIdle);
|
||||
subghz_device_cc1101_ext->state = SubGhzDeviceCC1101ExtStateAsyncRx;
|
||||
|
||||
subghz_device_cc1101_ext->async_rx.capture_callback = callback;
|
||||
subghz_device_cc1101_ext->async_rx.capture_callback_context = context;
|
||||
|
||||
furi_hal_bus_enable(FuriHalBusTIM17);
|
||||
|
||||
// Configure TIM
|
||||
//Set the timer resolution to 2 µs
|
||||
LL_TIM_SetPrescaler(TIM17, (64 << 1) - 1);
|
||||
LL_TIM_SetCounterMode(TIM17, LL_TIM_COUNTERMODE_UP);
|
||||
LL_TIM_SetAutoReload(TIM17, 0xFFFF);
|
||||
LL_TIM_SetClockDivision(TIM17, LL_TIM_CLOCKDIVISION_DIV1);
|
||||
|
||||
// Timer: advanced
|
||||
LL_TIM_SetClockSource(TIM17, LL_TIM_CLOCKSOURCE_INTERNAL);
|
||||
LL_TIM_DisableARRPreload(TIM17);
|
||||
LL_TIM_DisableDMAReq_TRIG(TIM17);
|
||||
LL_TIM_DisableIT_TRIG(TIM17);
|
||||
|
||||
furi_hal_gpio_init(
|
||||
subghz_device_cc1101_ext->g0_pin, GpioModeInterruptRiseFall, GpioPullUp, GpioSpeedVeryHigh);
|
||||
furi_hal_gpio_remove_int_callback(subghz_device_cc1101_ext->g0_pin);
|
||||
furi_hal_gpio_add_int_callback(
|
||||
subghz_device_cc1101_ext->g0_pin,
|
||||
subghz_device_cc1101_ext_capture_ISR,
|
||||
subghz_device_cc1101_ext->async_rx.capture_callback);
|
||||
|
||||
// Start timer
|
||||
LL_TIM_SetCounter(TIM17, 0);
|
||||
LL_TIM_EnableCounter(TIM17);
|
||||
|
||||
// Start debug
|
||||
subghz_device_cc1101_ext_start_debug();
|
||||
|
||||
// Switch to RX
|
||||
subghz_device_cc1101_ext_rx();
|
||||
|
||||
//Clear the variable after the end of the session
|
||||
subghz_device_cc1101_ext->async_rx.capture_delta_duration = 0;
|
||||
}
|
||||
|
||||
void subghz_device_cc1101_ext_stop_async_rx() {
|
||||
furi_assert(subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncRx);
|
||||
subghz_device_cc1101_ext->state = SubGhzDeviceCC1101ExtStateIdle;
|
||||
|
||||
// Shutdown radio
|
||||
subghz_device_cc1101_ext_idle();
|
||||
|
||||
FURI_CRITICAL_ENTER();
|
||||
furi_hal_bus_disable(FuriHalBusTIM17);
|
||||
|
||||
// Stop debug
|
||||
subghz_device_cc1101_ext_stop_debug();
|
||||
|
||||
FURI_CRITICAL_EXIT();
|
||||
furi_hal_gpio_remove_int_callback(subghz_device_cc1101_ext->g0_pin);
|
||||
furi_hal_gpio_init(subghz_device_cc1101_ext->g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
}
|
||||
|
||||
static void subghz_device_cc1101_ext_async_tx_refill(uint32_t* buffer, size_t samples) {
|
||||
furi_assert(subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTx);
|
||||
while(samples > 0) {
|
||||
bool is_odd = samples % 2;
|
||||
LevelDuration ld;
|
||||
if(level_duration_is_reset(subghz_device_cc1101_ext->async_tx.carry_ld)) {
|
||||
ld = subghz_device_cc1101_ext->async_tx.callback(
|
||||
subghz_device_cc1101_ext->async_tx.callback_context);
|
||||
} else {
|
||||
ld = subghz_device_cc1101_ext->async_tx.carry_ld;
|
||||
subghz_device_cc1101_ext->async_tx.carry_ld = level_duration_reset();
|
||||
}
|
||||
|
||||
if(level_duration_is_wait(ld)) {
|
||||
*buffer = SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_GUARD_TIME;
|
||||
buffer++;
|
||||
samples--;
|
||||
} else if(level_duration_is_reset(ld)) {
|
||||
*buffer = 0;
|
||||
buffer++;
|
||||
samples--;
|
||||
LL_DMA_DisableIT_HT(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF);
|
||||
LL_DMA_DisableIT_TC(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF);
|
||||
LL_TIM_EnableIT_UPDATE(TIM17);
|
||||
break;
|
||||
} else {
|
||||
bool level = level_duration_get_level(ld);
|
||||
|
||||
// Inject guard time if level is incorrect
|
||||
if(is_odd != level) {
|
||||
*buffer = SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_GUARD_TIME;
|
||||
buffer++;
|
||||
samples--;
|
||||
|
||||
// Special case: prevent buffer overflow if sample is last
|
||||
if(samples == 0) {
|
||||
subghz_device_cc1101_ext->async_tx.carry_ld = ld;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t duration = level_duration_get_duration(ld);
|
||||
furi_assert(duration > 0);
|
||||
*buffer = duration >> 1;
|
||||
buffer++;
|
||||
samples--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void subghz_device_cc1101_ext_async_tx_dma_isr() {
|
||||
furi_assert(subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTx);
|
||||
|
||||
#if SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_CHANNEL == LL_DMA_CHANNEL_3
|
||||
if(LL_DMA_IsActiveFlag_HT3(SUBGHZ_DEVICE_CC1101_EXT_DMA)) {
|
||||
LL_DMA_ClearFlag_HT3(SUBGHZ_DEVICE_CC1101_EXT_DMA);
|
||||
subghz_device_cc1101_ext_async_tx_refill(
|
||||
subghz_device_cc1101_ext->async_tx.buffer,
|
||||
SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_HALF);
|
||||
}
|
||||
if(LL_DMA_IsActiveFlag_TC3(SUBGHZ_DEVICE_CC1101_EXT_DMA)) {
|
||||
LL_DMA_ClearFlag_TC3(SUBGHZ_DEVICE_CC1101_EXT_DMA);
|
||||
subghz_device_cc1101_ext_async_tx_refill(
|
||||
subghz_device_cc1101_ext->async_tx.buffer +
|
||||
SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_HALF,
|
||||
SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_HALF);
|
||||
}
|
||||
#else
|
||||
#error Update this code. Would you kindly?
|
||||
#endif
|
||||
}
|
||||
|
||||
static void subghz_device_cc1101_ext_async_tx_timer_isr() {
|
||||
if(LL_TIM_IsActiveFlag_UPDATE(TIM17)) {
|
||||
if(LL_TIM_GetAutoReload(TIM17) == 0) {
|
||||
LL_DMA_DisableChannel(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF);
|
||||
furi_hal_gpio_write(subghz_device_cc1101_ext->g0_pin, false);
|
||||
if(subghz_device_cc1101_ext->async_mirror_pin != NULL)
|
||||
furi_hal_gpio_write(subghz_device_cc1101_ext->async_mirror_pin, false);
|
||||
LL_TIM_DisableCounter(TIM17);
|
||||
subghz_device_cc1101_ext->state = SubGhzDeviceCC1101ExtStateAsyncTxEnd;
|
||||
}
|
||||
LL_TIM_ClearFlag_UPDATE(TIM17);
|
||||
}
|
||||
}
|
||||
|
||||
bool subghz_device_cc1101_ext_start_async_tx(SubGhzDeviceCC1101ExtCallback callback, void* context) {
|
||||
furi_assert(subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateIdle);
|
||||
furi_assert(callback);
|
||||
|
||||
//If transmission is prohibited by regional settings
|
||||
if(subghz_device_cc1101_ext->regulation != SubGhzDeviceCC1101ExtRegulationTxRx) return false;
|
||||
|
||||
subghz_device_cc1101_ext->async_tx.callback = callback;
|
||||
subghz_device_cc1101_ext->async_tx.callback_context = context;
|
||||
|
||||
subghz_device_cc1101_ext->state = SubGhzDeviceCC1101ExtStateAsyncTx;
|
||||
|
||||
subghz_device_cc1101_ext->async_tx.buffer =
|
||||
malloc(SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_FULL * sizeof(uint32_t));
|
||||
|
||||
//Signal generation with mem-to-mem DMA
|
||||
furi_hal_gpio_write(subghz_device_cc1101_ext->g0_pin, false);
|
||||
furi_hal_gpio_init(
|
||||
subghz_device_cc1101_ext->g0_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
|
||||
|
||||
// Configure DMA update timer
|
||||
LL_DMA_SetMemoryAddress(
|
||||
SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF, (uint32_t)subghz_device_cc1101_ext->async_tx.buffer);
|
||||
LL_DMA_SetPeriphAddress(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF, (uint32_t) & (TIM17->ARR));
|
||||
LL_DMA_ConfigTransfer(
|
||||
SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF,
|
||||
LL_DMA_DIRECTION_MEMORY_TO_PERIPH | LL_DMA_MODE_CIRCULAR | LL_DMA_PERIPH_NOINCREMENT |
|
||||
LL_DMA_MEMORY_INCREMENT | LL_DMA_PDATAALIGN_WORD | LL_DMA_MDATAALIGN_WORD |
|
||||
LL_DMA_MODE_NORMAL);
|
||||
LL_DMA_SetDataLength(
|
||||
SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF, SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_FULL);
|
||||
LL_DMA_SetPeriphRequest(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF, LL_DMAMUX_REQ_TIM17_UP);
|
||||
|
||||
LL_DMA_EnableIT_TC(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF);
|
||||
LL_DMA_EnableIT_HT(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF);
|
||||
LL_DMA_EnableChannel(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF);
|
||||
|
||||
furi_hal_interrupt_set_isr(
|
||||
SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_IRQ, subghz_device_cc1101_ext_async_tx_dma_isr, NULL);
|
||||
|
||||
furi_hal_bus_enable(FuriHalBusTIM17);
|
||||
|
||||
// Configure TIM
|
||||
// Set the timer resolution to 2 µs
|
||||
LL_TIM_SetPrescaler(TIM17, (64 << 1) - 1);
|
||||
LL_TIM_SetCounterMode(TIM17, LL_TIM_COUNTERMODE_UP);
|
||||
LL_TIM_SetAutoReload(TIM17, 0xFFFF);
|
||||
LL_TIM_SetClockDivision(TIM17, LL_TIM_CLOCKDIVISION_DIV1);
|
||||
LL_TIM_SetClockSource(TIM17, LL_TIM_CLOCKSOURCE_INTERNAL);
|
||||
LL_TIM_DisableARRPreload(TIM17);
|
||||
|
||||
furi_hal_interrupt_set_isr(
|
||||
FuriHalInterruptIdTim1TrgComTim17, subghz_device_cc1101_ext_async_tx_timer_isr, NULL);
|
||||
|
||||
subghz_device_cc1101_ext_async_tx_refill(
|
||||
subghz_device_cc1101_ext->async_tx.buffer, SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_FULL);
|
||||
|
||||
// Configure tx gpio dma
|
||||
const GpioPin* gpio = subghz_device_cc1101_ext->g0_pin;
|
||||
|
||||
subghz_device_cc1101_ext->async_tx.gpio_tx_buff[0] = (uint32_t)gpio->pin << GPIO_NUMBER;
|
||||
subghz_device_cc1101_ext->async_tx.gpio_tx_buff[1] = gpio->pin;
|
||||
|
||||
LL_DMA_SetMemoryAddress(
|
||||
SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF,
|
||||
(uint32_t)subghz_device_cc1101_ext->async_tx.gpio_tx_buff);
|
||||
LL_DMA_SetPeriphAddress(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF, (uint32_t) & (gpio->port->BSRR));
|
||||
LL_DMA_ConfigTransfer(
|
||||
SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF,
|
||||
LL_DMA_DIRECTION_MEMORY_TO_PERIPH | LL_DMA_MODE_CIRCULAR | LL_DMA_PERIPH_NOINCREMENT |
|
||||
LL_DMA_MEMORY_INCREMENT | LL_DMA_PDATAALIGN_WORD | LL_DMA_MDATAALIGN_WORD |
|
||||
LL_DMA_PRIORITY_HIGH);
|
||||
LL_DMA_SetDataLength(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF, 2);
|
||||
LL_DMA_SetPeriphRequest(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF, LL_DMAMUX_REQ_TIM17_UP);
|
||||
LL_DMA_EnableChannel(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF);
|
||||
|
||||
// Start debug
|
||||
if(subghz_device_cc1101_ext_start_debug()) {
|
||||
gpio = subghz_device_cc1101_ext->async_mirror_pin;
|
||||
subghz_device_cc1101_ext->async_tx.debug_gpio_buff[0] = (uint32_t)gpio->pin << GPIO_NUMBER;
|
||||
subghz_device_cc1101_ext->async_tx.debug_gpio_buff[1] = gpio->pin;
|
||||
|
||||
LL_DMA_SetMemoryAddress(
|
||||
SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_DEF,
|
||||
(uint32_t)subghz_device_cc1101_ext->async_tx.debug_gpio_buff);
|
||||
LL_DMA_SetPeriphAddress(
|
||||
SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_DEF, (uint32_t) & (gpio->port->BSRR));
|
||||
LL_DMA_ConfigTransfer(
|
||||
SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_DEF,
|
||||
LL_DMA_DIRECTION_MEMORY_TO_PERIPH | LL_DMA_MODE_CIRCULAR | LL_DMA_PERIPH_NOINCREMENT |
|
||||
LL_DMA_MEMORY_INCREMENT | LL_DMA_PDATAALIGN_WORD | LL_DMA_MDATAALIGN_WORD |
|
||||
LL_DMA_PRIORITY_LOW);
|
||||
LL_DMA_SetDataLength(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_DEF, 2);
|
||||
LL_DMA_SetPeriphRequest(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_DEF, LL_DMAMUX_REQ_TIM17_UP);
|
||||
LL_DMA_EnableChannel(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_DEF);
|
||||
}
|
||||
|
||||
// Start counter
|
||||
LL_TIM_EnableDMAReq_UPDATE(TIM17);
|
||||
LL_TIM_GenerateEvent_UPDATE(TIM17);
|
||||
|
||||
subghz_device_cc1101_ext_tx();
|
||||
|
||||
LL_TIM_SetCounter(TIM17, 0);
|
||||
LL_TIM_EnableCounter(TIM17);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool subghz_device_cc1101_ext_is_async_tx_complete() {
|
||||
return subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTxEnd;
|
||||
}
|
||||
|
||||
void subghz_device_cc1101_ext_stop_async_tx() {
|
||||
furi_assert(
|
||||
subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTx ||
|
||||
subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTxEnd);
|
||||
|
||||
// Shutdown radio
|
||||
subghz_device_cc1101_ext_idle();
|
||||
|
||||
// Deinitialize Timer
|
||||
FURI_CRITICAL_ENTER();
|
||||
furi_hal_bus_disable(FuriHalBusTIM17);
|
||||
furi_hal_interrupt_set_isr(FuriHalInterruptIdTim1TrgComTim17, NULL, NULL);
|
||||
|
||||
// Deinitialize DMA
|
||||
LL_DMA_DeInit(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF);
|
||||
LL_DMA_DisableChannel(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF);
|
||||
furi_hal_interrupt_set_isr(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_IRQ, NULL, NULL);
|
||||
|
||||
// Deinitialize GPIO
|
||||
furi_hal_gpio_write(subghz_device_cc1101_ext->g0_pin, false);
|
||||
furi_hal_gpio_init(subghz_device_cc1101_ext->g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
|
||||
// Stop debug
|
||||
if(subghz_device_cc1101_ext_stop_debug()) {
|
||||
LL_DMA_DisableChannel(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_DEF);
|
||||
}
|
||||
|
||||
FURI_CRITICAL_EXIT();
|
||||
|
||||
free(subghz_device_cc1101_ext->async_tx.buffer);
|
||||
|
||||
subghz_device_cc1101_ext->state = SubGhzDeviceCC1101ExtStateIdle;
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
/**
|
||||
* @file furi_hal_subghz.h
|
||||
* SubGhz HAL API
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <lib/subghz/devices/preset.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <toolbox/level_duration.h>
|
||||
#include <furi_hal_gpio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Mirror RX/TX async modulation signal to specified pin
|
||||
*
|
||||
* @warning Configures pin to output mode. Make sure it is not connected
|
||||
* directly to power or ground.
|
||||
*
|
||||
* @param[in] pin pointer to the gpio pin structure or NULL to disable
|
||||
*/
|
||||
void subghz_device_cc1101_ext_set_async_mirror_pin(const GpioPin* pin);
|
||||
|
||||
/** Get data GPIO
|
||||
*
|
||||
* @return pointer to the gpio pin structure
|
||||
*/
|
||||
const GpioPin* subghz_device_cc1101_ext_get_data_gpio();
|
||||
|
||||
/** Initialize device
|
||||
*
|
||||
* @return true if success
|
||||
*/
|
||||
bool subghz_device_cc1101_ext_alloc();
|
||||
|
||||
/** Deinitialize device
|
||||
*/
|
||||
void subghz_device_cc1101_ext_free();
|
||||
|
||||
/** Check and switch to power save mode Used by internal API-HAL
|
||||
* initialization routine Can be used to reinitialize device to safe state and
|
||||
* send it to sleep
|
||||
*/
|
||||
bool subghz_device_cc1101_ext_is_connect();
|
||||
|
||||
/** Send device to sleep mode
|
||||
*/
|
||||
void subghz_device_cc1101_ext_sleep();
|
||||
|
||||
/** Dump info to stdout
|
||||
*/
|
||||
void subghz_device_cc1101_ext_dump_state();
|
||||
|
||||
/** Load custom registers from preset
|
||||
*
|
||||
* @param preset_data registers to load
|
||||
*/
|
||||
void subghz_device_cc1101_ext_load_custom_preset(const uint8_t* preset_data);
|
||||
|
||||
/** Load registers
|
||||
*
|
||||
* @param data Registers data
|
||||
*/
|
||||
void subghz_device_cc1101_ext_load_registers(const uint8_t* data);
|
||||
|
||||
/** Load PATABLE
|
||||
*
|
||||
* @param data 8 uint8_t values
|
||||
*/
|
||||
void subghz_device_cc1101_ext_load_patable(const uint8_t data[8]);
|
||||
|
||||
/** Write packet to FIFO
|
||||
*
|
||||
* @param data bytes array
|
||||
* @param size size
|
||||
*/
|
||||
void subghz_device_cc1101_ext_write_packet(const uint8_t* data, uint8_t size);
|
||||
|
||||
/** Check if receive pipe is not empty
|
||||
*
|
||||
* @return true if not empty
|
||||
*/
|
||||
bool subghz_device_cc1101_ext_rx_pipe_not_empty();
|
||||
|
||||
/** Check if received data crc is valid
|
||||
*
|
||||
* @return true if valid
|
||||
*/
|
||||
bool subghz_device_cc1101_ext_is_rx_data_crc_valid();
|
||||
|
||||
/** Read packet from FIFO
|
||||
*
|
||||
* @param data pointer
|
||||
* @param size size
|
||||
*/
|
||||
void subghz_device_cc1101_ext_read_packet(uint8_t* data, uint8_t* size);
|
||||
|
||||
/** Flush rx FIFO buffer
|
||||
*/
|
||||
void subghz_device_cc1101_ext_flush_rx();
|
||||
|
||||
/** Flush tx FIFO buffer
|
||||
*/
|
||||
void subghz_device_cc1101_ext_flush_tx();
|
||||
|
||||
/** Shutdown Issue SPWD command
|
||||
* @warning registers content will be lost
|
||||
*/
|
||||
void subghz_device_cc1101_ext_shutdown();
|
||||
|
||||
/** Reset Issue reset command
|
||||
* @warning registers content will be lost
|
||||
*/
|
||||
void subghz_device_cc1101_ext_reset();
|
||||
|
||||
/** Switch to Idle
|
||||
*/
|
||||
void subghz_device_cc1101_ext_idle();
|
||||
|
||||
/** Switch to Receive
|
||||
*/
|
||||
void subghz_device_cc1101_ext_rx();
|
||||
|
||||
/** Switch to Transmit
|
||||
*
|
||||
* @return true if the transfer is allowed by belonging to the region
|
||||
*/
|
||||
bool subghz_device_cc1101_ext_tx();
|
||||
|
||||
/** Get RSSI value in dBm
|
||||
*
|
||||
* @return RSSI value
|
||||
*/
|
||||
float subghz_device_cc1101_ext_get_rssi();
|
||||
|
||||
/** Get LQI
|
||||
*
|
||||
* @return LQI value
|
||||
*/
|
||||
uint8_t subghz_device_cc1101_ext_get_lqi();
|
||||
|
||||
/** Check if frequency is in valid range
|
||||
*
|
||||
* @param value frequency in Hz
|
||||
*
|
||||
* @return true if frequency is valid, otherwise false
|
||||
*/
|
||||
bool subghz_device_cc1101_ext_is_frequency_valid(uint32_t value);
|
||||
|
||||
/** Set frequency
|
||||
*
|
||||
* @param value frequency in Hz
|
||||
*
|
||||
* @return real frequency in Hz
|
||||
*/
|
||||
uint32_t subghz_device_cc1101_ext_set_frequency(uint32_t value);
|
||||
|
||||
/* High Level API */
|
||||
|
||||
/** Signal Timings Capture callback */
|
||||
typedef void (*SubGhzDeviceCC1101ExtCaptureCallback)(bool level, uint32_t duration, void* context);
|
||||
|
||||
/** Enable signal timings capture Initializes GPIO and TIM2 for timings capture
|
||||
*
|
||||
* @param callback SubGhzDeviceCC1101ExtCaptureCallback
|
||||
* @param context callback context
|
||||
*/
|
||||
void subghz_device_cc1101_ext_start_async_rx(
|
||||
SubGhzDeviceCC1101ExtCaptureCallback callback,
|
||||
void* context);
|
||||
|
||||
/** Disable signal timings capture Resets GPIO and TIM2
|
||||
*/
|
||||
void subghz_device_cc1101_ext_stop_async_rx();
|
||||
|
||||
/** Async TX callback type
|
||||
* @param context callback context
|
||||
* @return LevelDuration
|
||||
*/
|
||||
typedef LevelDuration (*SubGhzDeviceCC1101ExtCallback)(void* context);
|
||||
|
||||
/** Start async TX Initializes GPIO, TIM2 and DMA1 for signal output
|
||||
*
|
||||
* @param callback SubGhzDeviceCC1101ExtCallback
|
||||
* @param context callback context
|
||||
*
|
||||
* @return true if the transfer is allowed by belonging to the region
|
||||
*/
|
||||
bool subghz_device_cc1101_ext_start_async_tx(SubGhzDeviceCC1101ExtCallback callback, void* context);
|
||||
|
||||
/** Wait for async transmission to complete
|
||||
*
|
||||
* @return true if TX complete
|
||||
*/
|
||||
bool subghz_device_cc1101_ext_is_async_tx_complete();
|
||||
|
||||
/** Stop async transmission and cleanup resources Resets GPIO, TIM2, and DMA1
|
||||
*/
|
||||
void subghz_device_cc1101_ext_stop_async_tx();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,110 @@
|
||||
#include "cc1101_ext_interconnect.h"
|
||||
#include "cc1101_ext.h"
|
||||
#include <lib/subghz/devices/cc1101_configs.h>
|
||||
|
||||
#define TAG "SubGhzDeviceCC1101Ext"
|
||||
|
||||
static bool subghz_device_cc1101_ext_interconnect_is_frequency_valid(uint32_t frequency) {
|
||||
bool ret = subghz_device_cc1101_ext_is_frequency_valid(frequency);
|
||||
if(!ret) {
|
||||
furi_crash("SubGhz: Incorrect frequency.");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint32_t subghz_device_cc1101_ext_interconnect_set_frequency(uint32_t frequency) {
|
||||
subghz_device_cc1101_ext_interconnect_is_frequency_valid(frequency);
|
||||
return subghz_device_cc1101_ext_set_frequency(frequency);
|
||||
}
|
||||
|
||||
static bool subghz_device_cc1101_ext_interconnect_start_async_tx(void* callback, void* context) {
|
||||
return subghz_device_cc1101_ext_start_async_tx(
|
||||
(SubGhzDeviceCC1101ExtCallback)callback, context);
|
||||
}
|
||||
|
||||
static void subghz_device_cc1101_ext_interconnect_start_async_rx(void* callback, void* context) {
|
||||
subghz_device_cc1101_ext_start_async_rx(
|
||||
(SubGhzDeviceCC1101ExtCaptureCallback)callback, context);
|
||||
}
|
||||
|
||||
static void subghz_device_cc1101_ext_interconnect_load_preset(
|
||||
FuriHalSubGhzPreset preset,
|
||||
uint8_t* preset_data) {
|
||||
switch(preset) {
|
||||
case FuriHalSubGhzPresetOok650Async:
|
||||
subghz_device_cc1101_ext_load_custom_preset(
|
||||
subghz_device_cc1101_preset_ook_650khz_async_regs);
|
||||
break;
|
||||
case FuriHalSubGhzPresetOok270Async:
|
||||
subghz_device_cc1101_ext_load_custom_preset(
|
||||
subghz_device_cc1101_preset_ook_270khz_async_regs);
|
||||
break;
|
||||
case FuriHalSubGhzPreset2FSKDev238Async:
|
||||
subghz_device_cc1101_ext_load_custom_preset(
|
||||
subghz_device_cc1101_preset_2fsk_dev2_38khz_async_regs);
|
||||
break;
|
||||
case FuriHalSubGhzPreset2FSKDev476Async:
|
||||
subghz_device_cc1101_ext_load_custom_preset(
|
||||
subghz_device_cc1101_preset_2fsk_dev47_6khz_async_regs);
|
||||
break;
|
||||
case FuriHalSubGhzPresetMSK99_97KbAsync:
|
||||
subghz_device_cc1101_ext_load_custom_preset(
|
||||
subghz_device_cc1101_preset_msk_99_97kb_async_regs);
|
||||
break;
|
||||
case FuriHalSubGhzPresetGFSK9_99KbAsync:
|
||||
subghz_device_cc1101_ext_load_custom_preset(
|
||||
subghz_device_cc1101_preset_gfsk_9_99kb_async_regs);
|
||||
break;
|
||||
|
||||
default:
|
||||
subghz_device_cc1101_ext_load_custom_preset(preset_data);
|
||||
}
|
||||
}
|
||||
|
||||
const SubGhzDeviceInterconnect subghz_device_cc1101_ext_interconnect = {
|
||||
.begin = subghz_device_cc1101_ext_alloc,
|
||||
.end = subghz_device_cc1101_ext_free,
|
||||
.is_connect = subghz_device_cc1101_ext_is_connect,
|
||||
.reset = subghz_device_cc1101_ext_reset,
|
||||
.sleep = subghz_device_cc1101_ext_sleep,
|
||||
.idle = subghz_device_cc1101_ext_idle,
|
||||
.load_preset = subghz_device_cc1101_ext_interconnect_load_preset,
|
||||
.set_frequency = subghz_device_cc1101_ext_interconnect_set_frequency,
|
||||
.is_frequency_valid = subghz_device_cc1101_ext_is_frequency_valid,
|
||||
.set_async_mirror_pin = subghz_device_cc1101_ext_set_async_mirror_pin,
|
||||
.get_data_gpio = subghz_device_cc1101_ext_get_data_gpio,
|
||||
|
||||
.set_tx = subghz_device_cc1101_ext_tx,
|
||||
.flush_tx = subghz_device_cc1101_ext_flush_tx,
|
||||
.start_async_tx = subghz_device_cc1101_ext_interconnect_start_async_tx,
|
||||
.is_async_complete_tx = subghz_device_cc1101_ext_is_async_tx_complete,
|
||||
.stop_async_tx = subghz_device_cc1101_ext_stop_async_tx,
|
||||
|
||||
.set_rx = subghz_device_cc1101_ext_rx,
|
||||
.flush_rx = subghz_device_cc1101_ext_flush_rx,
|
||||
.start_async_rx = subghz_device_cc1101_ext_interconnect_start_async_rx,
|
||||
.stop_async_rx = subghz_device_cc1101_ext_stop_async_rx,
|
||||
|
||||
.get_rssi = subghz_device_cc1101_ext_get_rssi,
|
||||
.get_lqi = subghz_device_cc1101_ext_get_lqi,
|
||||
|
||||
.rx_pipe_not_empty = subghz_device_cc1101_ext_rx_pipe_not_empty,
|
||||
.is_rx_data_crc_valid = subghz_device_cc1101_ext_is_rx_data_crc_valid,
|
||||
.read_packet = subghz_device_cc1101_ext_read_packet,
|
||||
.write_packet = subghz_device_cc1101_ext_write_packet,
|
||||
};
|
||||
|
||||
const SubGhzDevice subghz_device_cc1101_ext = {
|
||||
.name = SUBGHZ_DEVICE_CC1101_EXT_NAME,
|
||||
.interconnect = &subghz_device_cc1101_ext_interconnect,
|
||||
};
|
||||
|
||||
static const FlipperAppPluginDescriptor subghz_device_cc1101_ext_descriptor = {
|
||||
.appid = SUBGHZ_RADIO_DEVICE_PLUGIN_APP_ID,
|
||||
.ep_api_version = SUBGHZ_RADIO_DEVICE_PLUGIN_API_VERSION,
|
||||
.entry_point = &subghz_device_cc1101_ext,
|
||||
};
|
||||
|
||||
const FlipperAppPluginDescriptor* subghz_device_cc1101_ext_ep() {
|
||||
return &subghz_device_cc1101_ext_descriptor;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
#include <lib/subghz/devices/types.h>
|
||||
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_NAME "cc1101_ext"
|
||||
|
||||
typedef struct SubGhzDeviceCC1101Ext SubGhzDeviceCC1101Ext;
|
||||
|
||||
const FlipperAppPluginDescriptor* subghz_device_cc1101_ext_ep();
|
||||
@@ -18,7 +18,7 @@ Before launching the application, connect the sensor to Flipper's external GPIO
|
||||
In order to launch this demo, follow the steps below:
|
||||
1. Make sure your Flipper has an SD card installed.
|
||||
2. Connect your Flipper to the computer via a USB cable.
|
||||
3. Run `./fbt launch_app APPSRC=example_thermo` in your terminal emulator of choice.
|
||||
3. Run `./fbt launch APPSRC=example_thermo` in your terminal emulator of choice.
|
||||
|
||||
## Changing the data pin
|
||||
It is possible to use other GPIO pin as a 1-Wire data pin. In order to change it, set the `THERMO_GPIO_PIN` macro to any of the options listed below:
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
App(
|
||||
appid="mass_storage",
|
||||
name="USB Mass Storage",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="mass_storage_app",
|
||||
cdefines=["APP_MASS_STORAGE"],
|
||||
requires=["gui"],
|
||||
stack_size=1 * 1024,
|
||||
order=2,
|
||||
# fap_icon="",
|
||||
fap_category="Misc",
|
||||
)
|
||||
@@ -1,54 +0,0 @@
|
||||
#include "../mass_storage_app_i.h"
|
||||
#include <assets_icons.h>
|
||||
|
||||
typedef enum {
|
||||
SubghzCustomEventErrorBack,
|
||||
} MassStorageCustomEvent;
|
||||
|
||||
static void
|
||||
mass_storage_scene_error_event_callback(GuiButtonType result, InputType type, void* context) {
|
||||
furi_assert(context);
|
||||
MassStorageApp* app = context;
|
||||
|
||||
if((result == GuiButtonTypeLeft) && (type == InputTypeShort)) {
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, SubghzCustomEventErrorBack);
|
||||
}
|
||||
}
|
||||
|
||||
void mass_storage_scene_error_on_enter(void* context) {
|
||||
MassStorageApp* app = context;
|
||||
|
||||
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 requires a\nmass_storage/\ndirectory.");
|
||||
|
||||
widget_add_button_element(
|
||||
app->widget, GuiButtonTypeLeft, "Back", mass_storage_scene_error_event_callback, app);
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, MassStorageAppViewError);
|
||||
}
|
||||
|
||||
bool mass_storage_scene_error_on_event(void* context, SceneManagerEvent event) {
|
||||
MassStorageApp* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubghzCustomEventErrorBack) {
|
||||
view_dispatcher_stop(app->view_dispatcher);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void mass_storage_scene_error_on_exit(void* context) {
|
||||
MassStorageApp* app = context;
|
||||
widget_reset(app->widget);
|
||||
}
|
||||
+1
@@ -4,6 +4,7 @@
|
||||
#include <input/input.h>
|
||||
#include <notification/notification.h>
|
||||
#include <notification/notification_messages.h>
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
static int matrix[6][7] = {0};
|
||||
static int cursorx = 3;
|
||||
|
||||
+2
-2
@@ -2,7 +2,6 @@
|
||||
#include <storage/storage.h>
|
||||
|
||||
#include <furi.h>
|
||||
|
||||
#include "tracking/imu/imu.h"
|
||||
|
||||
#define TAG "AirMouseApp"
|
||||
@@ -54,8 +53,9 @@ AirMouse* air_mouse_app_alloc() {
|
||||
AirMouse* app = malloc(sizeof(AirMouse));
|
||||
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
storage_simply_mkdir(storage, EXT_PATH("apps_data/air_mouse"));
|
||||
storage_common_migrate(
|
||||
storage, EXT_PATH(".calibration.data"), APP_DATA_PATH("calibration.data"));
|
||||
storage, EXT_PATH(".calibration.data"), EXT_PATH("apps_data/air_mouse/calibration.data"));
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
|
||||
// Gui
|
||||
|
||||
@@ -6,4 +6,6 @@ App(
|
||||
stack_size=10 * 1024,
|
||||
fap_category="GPIO",
|
||||
fap_icon="mouse_10px.png",
|
||||
fap_version="0.6",
|
||||
sources=["*.c", "*.cc"],
|
||||
)
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "util/vector.h"
|
||||
|
||||
#define CALIBRATION_DATA_VER (1)
|
||||
#define CALIBRATION_DATA_PATH APP_DATA_PATH("calibration.data")
|
||||
#define CALIBRATION_DATA_PATH EXT_PATH("apps_data/air_mouse/calibration.data")
|
||||
#define CALIBRATION_DATA_MAGIC (0x23)
|
||||
|
||||
#define CALIBRATION_DATA_SAVE(x) \
|
||||
|
||||
+3
-5
@@ -13,7 +13,8 @@
|
||||
#include <math.h>
|
||||
#include <notification/notification.h>
|
||||
#include <notification/notification_messages.h>
|
||||
#include <asteroids_icons.h>
|
||||
#include "asteroids_icons.h"
|
||||
#include <assets_icons.h>
|
||||
|
||||
#define TAG "Asteroids" // Used for logging
|
||||
#define DEBUG_MSG 0
|
||||
@@ -28,9 +29,7 @@
|
||||
#define MAXPOWERUPS 3 /* Max powerups allowed on screen */
|
||||
#define POWERUPSTTL 400 /* Max powerup time to live, in ticks. */
|
||||
#define SHIP_HIT_ANIMATION_LEN 15
|
||||
// Tick runs in thread, cant use APP_DATA_PATH()
|
||||
#define SAVING_DIRECTORY EXT_PATH("apps_data/asteroids")
|
||||
#define SAVING_FILENAME SAVING_DIRECTORY "/game_asteroids.save"
|
||||
#define SAVING_FILENAME APP_DATA_PATH("game_asteroids.save")
|
||||
#ifndef PI
|
||||
#define PI 3.14159265358979f
|
||||
#endif
|
||||
@@ -1147,7 +1146,6 @@ void game_tick(void* ctx) {
|
||||
|
||||
bool load_game(AsteroidsApp* app) {
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
storage_common_mkdir(storage, SAVING_DIRECTORY);
|
||||
storage_common_migrate(storage, EXT_PATH("apps/Games/game_asteroids.save"), SAVING_FILENAME);
|
||||
|
||||
File* file = storage_file_alloc(storage);
|
||||
|
||||
+3
-3
@@ -5,12 +5,12 @@ App(
|
||||
entry_point="barcode_main",
|
||||
requires=["gui", "storage"],
|
||||
stack_size=2 * 1024,
|
||||
fap_category="Misc",
|
||||
fap_category="Tools",
|
||||
fap_icon="images/barcode_10.png",
|
||||
fap_icon_assets="images",
|
||||
fap_icon_assets_symbol="barcode_app",
|
||||
fap_file_assets="barcode_encoding_files",
|
||||
fap_author="@Kingal1337",
|
||||
fap_weburl="https://github.com/Kingal1337/flipper-barcode-generator",
|
||||
fap_version="1.0",
|
||||
fap_version="1.1",
|
||||
fap_description="App allows you to display various barcodes on flipper screen",
|
||||
)
|
||||
|
||||
+7
-7
@@ -23,17 +23,17 @@
|
||||
#define BARCODE_HEIGHT 50
|
||||
#define BARCODE_Y_START 3
|
||||
|
||||
//the folder where the encodings are located
|
||||
#define BARCODE_DATA_FILE_DIR_PATH EXT_PATH("apps_data/barcode_data")
|
||||
|
||||
//the folder where the codabar encoding table is located
|
||||
#define CODABAR_DICT_FILE_PATH BARCODE_DATA_FILE_DIR_PATH "/codabar_encodings.txt"
|
||||
#define CODABAR_DICT_FILE_PATH APP_ASSETS_PATH("codabar_encodings.txt")
|
||||
|
||||
//the folder where the code 39 encoding table is located
|
||||
#define CODE39_DICT_FILE_PATH BARCODE_DATA_FILE_DIR_PATH "/code39_encodings.txt"
|
||||
#define CODE39_DICT_FILE_PATH APP_ASSETS_PATH("code39_encodings.txt")
|
||||
|
||||
//the folder where the code 128 encoding table is located
|
||||
#define CODE128_DICT_FILE_PATH BARCODE_DATA_FILE_DIR_PATH "/code128_encodings.txt"
|
||||
#define CODE128_DICT_FILE_PATH APP_ASSETS_PATH("code128_encodings.txt")
|
||||
|
||||
//the folder where the code 128 C encoding table is located
|
||||
#define CODE128C_DICT_FILE_PATH APP_ASSETS_PATH("code128c_encodings.txt")
|
||||
|
||||
//the folder where the user stores their barcodes
|
||||
#define DEFAULT_USER_BARCODES EXT_PATH("apps_data/barcodes")
|
||||
@@ -85,4 +85,4 @@ uint32_t main_menu_callback(void* context);
|
||||
|
||||
uint32_t exit_callback(void* context);
|
||||
|
||||
int32_t barcode_main(void* p);
|
||||
int32_t barcode_main(void* p);
|
||||
|
||||
+12
-1
@@ -43,6 +43,14 @@ void init_types() {
|
||||
code_128->start_pos = 0;
|
||||
barcode_type_objs[CODE128] = code_128;
|
||||
|
||||
BarcodeTypeObj* code_128c = malloc(sizeof(BarcodeTypeObj));
|
||||
code_128c->name = "CODE-128C";
|
||||
code_128c->type = CODE128C;
|
||||
code_128c->min_digits = 2;
|
||||
code_128c->max_digits = -1;
|
||||
code_128c->start_pos = 0;
|
||||
barcode_type_objs[CODE128C] = code_128c;
|
||||
|
||||
BarcodeTypeObj* codabar = malloc(sizeof(BarcodeTypeObj));
|
||||
codabar->name = "Codabar";
|
||||
codabar->type = CODABAR;
|
||||
@@ -82,6 +90,9 @@ BarcodeTypeObj* get_type(FuriString* type_string) {
|
||||
if(furi_string_cmp_str(type_string, "CODE-128") == 0) {
|
||||
return barcode_type_objs[CODE128];
|
||||
}
|
||||
if(furi_string_cmp_str(type_string, "CODE-128C") == 0) {
|
||||
return barcode_type_objs[CODE128C];
|
||||
}
|
||||
if(furi_string_cmp_str(type_string, "Codabar") == 0) {
|
||||
return barcode_type_objs[CODABAR];
|
||||
}
|
||||
@@ -133,4 +144,4 @@ const char* get_error_code_message(ErrorCode error_code) {
|
||||
default:
|
||||
return "Could not read barcode data";
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
+3
-2
@@ -3,7 +3,7 @@
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
|
||||
#define NUMBER_OF_BARCODE_TYPES 7
|
||||
#define NUMBER_OF_BARCODE_TYPES 8
|
||||
|
||||
typedef enum {
|
||||
WrongNumberOfDigits, //There is too many or too few digits in the barcode
|
||||
@@ -22,6 +22,7 @@ typedef enum {
|
||||
EAN13,
|
||||
CODE39,
|
||||
CODE128,
|
||||
CODE128C,
|
||||
CODABAR,
|
||||
|
||||
UNKNOWN
|
||||
@@ -51,4 +52,4 @@ void init_types();
|
||||
void free_types();
|
||||
BarcodeTypeObj* get_type(FuriString* type_string);
|
||||
const char* get_error_code_name(ErrorCode error_code);
|
||||
const char* get_error_code_message(ErrorCode error_code);
|
||||
const char* get_error_code_message(ErrorCode error_code);
|
||||
|
||||
+130
-1
@@ -13,6 +13,9 @@ void barcode_loader(BarcodeData* barcode_data) {
|
||||
case CODE128:
|
||||
code_128_loader(barcode_data);
|
||||
break;
|
||||
case CODE128C:
|
||||
code_128c_loader(barcode_data);
|
||||
break;
|
||||
case CODABAR:
|
||||
codabar_loader(barcode_data);
|
||||
break;
|
||||
@@ -39,6 +42,7 @@ int calculate_check_digit(BarcodeData* barcode_data) {
|
||||
break;
|
||||
case CODE39:
|
||||
case CODE128:
|
||||
case CODE128C:
|
||||
case CODABAR:
|
||||
case UNKNOWN:
|
||||
default:
|
||||
@@ -345,6 +349,131 @@ void code_128_loader(BarcodeData* barcode_data) {
|
||||
furi_string_free(barcode_bits);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a code 128 C barcode
|
||||
*/
|
||||
void code_128c_loader(BarcodeData* barcode_data) {
|
||||
int barcode_length = furi_string_size(barcode_data->raw_data);
|
||||
|
||||
//the start code for character set C
|
||||
int start_code_value = 105;
|
||||
|
||||
//The bits for the start code
|
||||
const char* start_code_bits = "11010011100";
|
||||
|
||||
//The bits for the stop code
|
||||
const char* stop_code_bits = "1100011101011";
|
||||
|
||||
int min_digits = barcode_data->type_obj->min_digits;
|
||||
|
||||
int checksum_adder = start_code_value;
|
||||
int checksum_digits = 0;
|
||||
|
||||
//the calculated check digit
|
||||
int final_check_digit = 0;
|
||||
|
||||
// check the length of the barcode, must contain atleast 2 character,
|
||||
// this can have as many characters as it wants, it might not fit on the screen
|
||||
// code 128 C: the length must be even
|
||||
if((barcode_length < min_digits) || (barcode_length & 1)) {
|
||||
barcode_data->reason = WrongNumberOfDigits;
|
||||
barcode_data->valid = false;
|
||||
return;
|
||||
}
|
||||
//Open Storage
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
FlipperFormat* ff = flipper_format_file_alloc(storage);
|
||||
|
||||
FuriString* barcode_bits = furi_string_alloc();
|
||||
|
||||
//add the start code
|
||||
furi_string_cat(barcode_bits, start_code_bits);
|
||||
|
||||
if(!flipper_format_file_open_existing(ff, CODE128C_DICT_FILE_PATH)) {
|
||||
FURI_LOG_E(TAG, "c128c Could not open file %s", CODE128C_DICT_FILE_PATH);
|
||||
barcode_data->reason = MissingEncodingTable;
|
||||
barcode_data->valid = false;
|
||||
} else {
|
||||
FuriString* value = furi_string_alloc();
|
||||
FuriString* char_bits = furi_string_alloc();
|
||||
for(int i = 0; i < barcode_length; i += 2) {
|
||||
char barcode_char1 = furi_string_get_char(barcode_data->raw_data, i);
|
||||
char barcode_char2 = furi_string_get_char(barcode_data->raw_data, i + 1);
|
||||
FURI_LOG_I(TAG, "c128c bc1='%c' bc2='%c'", barcode_char1, barcode_char2);
|
||||
|
||||
char current_chars[4];
|
||||
snprintf(current_chars, 3, "%c%c", barcode_char1, barcode_char2);
|
||||
FURI_LOG_I(TAG, "c128c current_chars='%s'", current_chars);
|
||||
|
||||
//using the value of the characters, get the characters bits
|
||||
if(!flipper_format_read_string(ff, current_chars, char_bits)) {
|
||||
FURI_LOG_E(TAG, "c128c Could not read \"%s\" string", current_chars);
|
||||
barcode_data->reason = EncodingTableError;
|
||||
barcode_data->valid = false;
|
||||
break;
|
||||
} else {
|
||||
//add the bits to the full barcode
|
||||
furi_string_cat(barcode_bits, char_bits);
|
||||
|
||||
// calculate the checksum
|
||||
checksum_digits += 1;
|
||||
checksum_adder += (atoi(current_chars) * checksum_digits);
|
||||
|
||||
FURI_LOG_I(
|
||||
TAG,
|
||||
"c128c \"%s\" string: %s : %s : %d : %d : %d",
|
||||
current_chars,
|
||||
furi_string_get_cstr(char_bits),
|
||||
furi_string_get_cstr(value),
|
||||
checksum_digits,
|
||||
(atoi(furi_string_get_cstr(value)) * checksum_digits),
|
||||
checksum_adder);
|
||||
}
|
||||
//bring the file pointer back to the begining
|
||||
flipper_format_rewind(ff);
|
||||
}
|
||||
//calculate the check digit and convert it into a c string for lookup in the encoding table
|
||||
final_check_digit = checksum_adder % 103;
|
||||
FURI_LOG_I(TAG, "c128c finale_check_digit=%d", final_check_digit);
|
||||
|
||||
int length = snprintf(NULL, 0, "%d", final_check_digit);
|
||||
if(final_check_digit < 100) length = 2;
|
||||
char* final_check_digit_string = malloc(length + 1);
|
||||
snprintf(final_check_digit_string, length + 1, "%02d", final_check_digit);
|
||||
|
||||
//after the checksum has been calculated, add the bits to the full barcode
|
||||
if(!flipper_format_read_string(ff, final_check_digit_string, char_bits)) {
|
||||
FURI_LOG_E(TAG, "c128c cksum Could not read \"%s\" string", final_check_digit_string);
|
||||
barcode_data->reason = EncodingTableError;
|
||||
barcode_data->valid = false;
|
||||
} else {
|
||||
//add the check digit bits to the full barcode
|
||||
furi_string_cat(barcode_bits, char_bits);
|
||||
|
||||
FURI_LOG_I(
|
||||
TAG,
|
||||
"check digit \"%s\" string: %s",
|
||||
final_check_digit_string,
|
||||
furi_string_get_cstr(char_bits));
|
||||
}
|
||||
|
||||
free(final_check_digit_string);
|
||||
furi_string_free(value);
|
||||
furi_string_free(char_bits);
|
||||
}
|
||||
|
||||
//add the stop code
|
||||
furi_string_cat(barcode_bits, stop_code_bits);
|
||||
|
||||
//Close Storage
|
||||
flipper_format_free(ff);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
|
||||
FURI_LOG_I(TAG, "c128c %s", furi_string_get_cstr(barcode_bits));
|
||||
furi_string_cat(barcode_data->correct_data, barcode_bits);
|
||||
furi_string_free(barcode_bits);
|
||||
}
|
||||
|
||||
void codabar_loader(BarcodeData* barcode_data) {
|
||||
int barcode_length = furi_string_size(barcode_data->raw_data);
|
||||
|
||||
@@ -400,4 +529,4 @@ void codabar_loader(BarcodeData* barcode_data) {
|
||||
|
||||
furi_string_cat(barcode_data->correct_data, barcode_bits);
|
||||
furi_string_free(barcode_bits);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -10,5 +10,6 @@ void ean_8_loader(BarcodeData* barcode_data);
|
||||
void ean_13_loader(BarcodeData* barcode_data);
|
||||
void code_39_loader(BarcodeData* barcode_data);
|
||||
void code_128_loader(BarcodeData* barcode_data);
|
||||
void code_128c_loader(BarcodeData* barcode_data);
|
||||
void codabar_loader(BarcodeData* barcode_data);
|
||||
void barcode_loader(BarcodeData* barcode_data);
|
||||
void barcode_loader(BarcodeData* barcode_data);
|
||||
|
||||
+2
-1
@@ -406,6 +406,7 @@ static void barcode_draw_callback(Canvas* canvas, void* ctx) {
|
||||
draw_code_39(canvas, data);
|
||||
break;
|
||||
case CODE128:
|
||||
case CODE128C:
|
||||
draw_code_128(canvas, data);
|
||||
break;
|
||||
case CODABAR:
|
||||
@@ -506,4 +507,4 @@ void barcode_free(Barcode* barcode) {
|
||||
View* barcode_get_view(Barcode* barcode) {
|
||||
furi_assert(barcode);
|
||||
return barcode->view;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -1,6 +1,7 @@
|
||||
|
||||
#include <gui/gui.h>
|
||||
#include <stdlib.h>
|
||||
#include <dolphin/dolphin.h>
|
||||
#include <dialogs/dialogs.h>
|
||||
#include <gui/canvas_i.h>
|
||||
|
||||
@@ -629,4 +630,4 @@ free_and_exit:
|
||||
furi_message_queue_free(event_queue);
|
||||
|
||||
return return_code;
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,6 @@
|
||||
#include <input/input.h>
|
||||
#include <notification/notification.h>
|
||||
#include <notification/notification_messages.h>
|
||||
#include <gui/canvas_i.h>
|
||||
#include "bomberduck_icons.h"
|
||||
|
||||
int max(int a, int b) {
|
||||
|
||||
@@ -8,6 +8,7 @@ App(
|
||||
stack_size=2 * 1024,
|
||||
fap_icon="bpm_10px.png",
|
||||
fap_category="Media",
|
||||
fap_icon_assets="icons",
|
||||
order=15,
|
||||
fap_author="@panki27",
|
||||
fap_weburl="https://github.com/panki27/bpm-tapper",
|
||||
|
||||
+2
-1
@@ -4,7 +4,8 @@
|
||||
#include <gui/gui.h>
|
||||
#include <input/input.h>
|
||||
#include <stdlib.h>
|
||||
#include "assets_icons.h"
|
||||
#include "bpm_tapper_icons.h"
|
||||
#include <assets_icons.h>
|
||||
|
||||
typedef enum {
|
||||
EventTypeTick,
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ App(
|
||||
],
|
||||
stack_size=8 * 1024,
|
||||
fap_icon="bfico.png",
|
||||
fap_category="Misc",
|
||||
fap_category="Tools",
|
||||
fap_icon_assets="icons",
|
||||
fap_author="@nymda",
|
||||
fap_weburl="https://github.com/nymda/FlipperZeroBrainfuck",
|
||||
|
||||
+1
-2
@@ -29,7 +29,7 @@ typedef unsigned char byte;
|
||||
|
||||
#include <storage/storage.h>
|
||||
#include <lib/toolbox/path.h>
|
||||
#include <brainfuck_icons.h>
|
||||
#include "brainfuck_icons.h"
|
||||
#include <assets_icons.h>
|
||||
|
||||
#include <storage/storage.h>
|
||||
@@ -38,7 +38,6 @@ typedef unsigned char byte;
|
||||
#include <toolbox/stream/file_stream.h>
|
||||
|
||||
#include <notification/notification_messages.h>
|
||||
#include <notification/notification_app.h>
|
||||
|
||||
#define BF_INST_BUFFER_SIZE 2048
|
||||
#define BF_OUTPUT_SIZE 512
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
+9
-3
@@ -20,6 +20,12 @@ typedef struct {
|
||||
int right;
|
||||
} bMapping;
|
||||
|
||||
#ifdef FW_ORIGIN_Official
|
||||
#define FONT_NAME FontSecondary
|
||||
#else
|
||||
#define FONT_NAME FontBatteryPercent
|
||||
#endif
|
||||
|
||||
static bool bf_dev_process_up(BFDevEnv* devEnv);
|
||||
static bool bf_dev_process_down(BFDevEnv* devEnv);
|
||||
static bool bf_dev_process_left(BFDevEnv* devEnv);
|
||||
@@ -63,7 +69,7 @@ static void bf_dev_draw_button(Canvas* canvas, int x, int y, bool selected, cons
|
||||
if(selected) {
|
||||
canvas_draw_rbox(canvas, x, y, BT_X, BT_Y, 3);
|
||||
canvas_invert_color(canvas);
|
||||
canvas_set_font(canvas, FontBatteryPercent);
|
||||
canvas_set_font(canvas, FONT_NAME);
|
||||
canvas_draw_str_aligned(
|
||||
canvas, x + (BT_X / 2), y + (BT_Y / 2) - 1, AlignCenter, AlignCenter, lbl);
|
||||
canvas_invert_color(canvas);
|
||||
@@ -73,7 +79,7 @@ static void bf_dev_draw_button(Canvas* canvas, int x, int y, bool selected, cons
|
||||
canvas_draw_rbox(canvas, x + 2, y - 1, BT_X - 2, BT_Y - 1, 3);
|
||||
canvas_invert_color(canvas);
|
||||
canvas_draw_rframe(canvas, x, y, BT_X, BT_Y, 3);
|
||||
canvas_set_font(canvas, FontBatteryPercent);
|
||||
canvas_set_font(canvas, FONT_NAME);
|
||||
canvas_draw_str_aligned(
|
||||
canvas, x + (BT_X / 2), y + (BT_Y / 2) - 1, AlignCenter, AlignCenter, lbl);
|
||||
}
|
||||
@@ -131,7 +137,7 @@ static void bf_dev_draw_callback(Canvas* canvas, void* _model) {
|
||||
//textbox
|
||||
//grossly overcomplicated. not fixing it.
|
||||
canvas_draw_rframe(canvas, 1, 1, 126, 33, 2);
|
||||
canvas_set_font(canvas, FontBatteryPercent);
|
||||
canvas_set_font(canvas, FONT_NAME);
|
||||
|
||||
int dbOffset = 0;
|
||||
if(appDev->dataSize > 72) {
|
||||
|
||||
+1
-1
@@ -111,7 +111,7 @@ void rShift() {
|
||||
|
||||
memset((tmp + stackSize) - BF_STACK_STEP_SIZE, 0x00, BF_STACK_STEP_SIZE);
|
||||
bfStack = (uint8_t*)tmp;
|
||||
}
|
||||
};
|
||||
if(stackPtr > stackSizeReal) {
|
||||
stackSizeReal = stackPtr;
|
||||
}
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ App(
|
||||
],
|
||||
stack_size=2 * 1024,
|
||||
fap_icon="caesar_cipher_icon.png",
|
||||
fap_category="Misc",
|
||||
fap_category="Tools",
|
||||
order=20,
|
||||
fap_author="@panki27",
|
||||
fap_weburl="https://github.com/panki27/caesar-cipher",
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ App(
|
||||
stack_size=1 * 1024,
|
||||
order=45,
|
||||
fap_icon="calcIcon.png",
|
||||
fap_category="Misc",
|
||||
fap_category="Tools",
|
||||
fap_author="@n-o-T-I-n-s-a-n-e",
|
||||
fap_weburl="https://github.com/n-o-T-I-n-s-a-n-e",
|
||||
fap_version="1.0",
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
App(
|
||||
appid="camerasuite",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
cdefines=["APP_CAMERA_SUITE"],
|
||||
entry_point="camera_suite_app",
|
||||
fap_author="Cody Tolene",
|
||||
fap_category="GPIO",
|
||||
fap_description="A camera suite application for the Flipper Zero ESP32-CAM module.",
|
||||
fap_icon="icons/camera_suite.png",
|
||||
fap_weburl="https://github.com/CodyTolene/Flipper-Zero-Cam",
|
||||
name="[ESP32] Camera Suite",
|
||||
order=1,
|
||||
requires=["gui", "storage"],
|
||||
stack_size=8 * 1024,
|
||||
)
|
||||
+139
@@ -0,0 +1,139 @@
|
||||
#include "camera_suite.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
bool camera_suite_custom_event_callback(void* context, uint32_t event) {
|
||||
furi_assert(context);
|
||||
CameraSuite* app = context;
|
||||
return scene_manager_handle_custom_event(app->scene_manager, event);
|
||||
}
|
||||
|
||||
void camera_suite_tick_event_callback(void* context) {
|
||||
furi_assert(context);
|
||||
CameraSuite* app = context;
|
||||
scene_manager_handle_tick_event(app->scene_manager);
|
||||
}
|
||||
|
||||
//leave app if back button pressed
|
||||
bool camera_suite_navigation_event_callback(void* context) {
|
||||
furi_assert(context);
|
||||
CameraSuite* app = context;
|
||||
return scene_manager_handle_back_event(app->scene_manager);
|
||||
}
|
||||
|
||||
CameraSuite* camera_suite_app_alloc() {
|
||||
CameraSuite* app = malloc(sizeof(CameraSuite));
|
||||
app->gui = furi_record_open(RECORD_GUI);
|
||||
app->notification = furi_record_open(RECORD_NOTIFICATION);
|
||||
|
||||
//Turn backlight on, believe me this makes testing your app easier
|
||||
notification_message(app->notification, &sequence_display_backlight_on);
|
||||
|
||||
//Scene additions
|
||||
app->view_dispatcher = view_dispatcher_alloc();
|
||||
view_dispatcher_enable_queue(app->view_dispatcher);
|
||||
|
||||
app->scene_manager = scene_manager_alloc(&camera_suite_scene_handlers, app);
|
||||
view_dispatcher_set_event_callback_context(app->view_dispatcher, app);
|
||||
view_dispatcher_set_navigation_event_callback(
|
||||
app->view_dispatcher, camera_suite_navigation_event_callback);
|
||||
view_dispatcher_set_tick_event_callback(
|
||||
app->view_dispatcher, camera_suite_tick_event_callback, 100);
|
||||
view_dispatcher_set_custom_event_callback(
|
||||
app->view_dispatcher, camera_suite_custom_event_callback);
|
||||
app->submenu = submenu_alloc();
|
||||
|
||||
// Set defaults, in case no config loaded
|
||||
app->orientation = 0; // Orientation is "portrait", zero degrees by default.
|
||||
app->haptic = 1; // Haptic is on by default
|
||||
app->speaker = 1; // Speaker is on by default
|
||||
app->led = 1; // LED is on by default
|
||||
|
||||
// Load configs
|
||||
camera_suite_read_settings(app);
|
||||
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, CameraSuiteViewIdMenu, submenu_get_view(app->submenu));
|
||||
|
||||
app->camera_suite_view_start = camera_suite_view_start_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher,
|
||||
CameraSuiteViewIdStartscreen,
|
||||
camera_suite_view_start_get_view(app->camera_suite_view_start));
|
||||
|
||||
app->camera_suite_view_style_1 = camera_suite_view_style_1_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher,
|
||||
CameraSuiteViewIdScene1,
|
||||
camera_suite_view_style_1_get_view(app->camera_suite_view_style_1));
|
||||
|
||||
app->camera_suite_view_style_2 = camera_suite_view_style_2_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher,
|
||||
CameraSuiteViewIdScene2,
|
||||
camera_suite_view_style_2_get_view(app->camera_suite_view_style_2));
|
||||
|
||||
app->camera_suite_view_guide = camera_suite_view_guide_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher,
|
||||
CameraSuiteViewIdGuide,
|
||||
camera_suite_view_guide_get_view(app->camera_suite_view_guide));
|
||||
|
||||
app->button_menu = button_menu_alloc();
|
||||
|
||||
app->variable_item_list = variable_item_list_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher,
|
||||
CameraSuiteViewIdSettings,
|
||||
variable_item_list_get_view(app->variable_item_list));
|
||||
|
||||
//End Scene Additions
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
void camera_suite_app_free(CameraSuite* app) {
|
||||
furi_assert(app);
|
||||
|
||||
// Scene manager
|
||||
scene_manager_free(app->scene_manager);
|
||||
|
||||
// View Dispatcher
|
||||
view_dispatcher_remove_view(app->view_dispatcher, CameraSuiteViewIdMenu);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, CameraSuiteViewIdScene1);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, CameraSuiteViewIdScene2);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, CameraSuiteViewIdGuide);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, CameraSuiteViewIdSettings);
|
||||
submenu_free(app->submenu);
|
||||
|
||||
view_dispatcher_free(app->view_dispatcher);
|
||||
furi_record_close(RECORD_GUI);
|
||||
|
||||
// Free remaining resources
|
||||
camera_suite_view_start_free(app->camera_suite_view_start);
|
||||
camera_suite_view_style_1_free(app->camera_suite_view_style_1);
|
||||
camera_suite_view_style_2_free(app->camera_suite_view_style_2);
|
||||
camera_suite_view_guide_free(app->camera_suite_view_guide);
|
||||
button_menu_free(app->button_menu);
|
||||
variable_item_list_free(app->variable_item_list);
|
||||
|
||||
app->gui = NULL;
|
||||
app->notification = NULL;
|
||||
|
||||
//Remove whatever is left
|
||||
free(app);
|
||||
}
|
||||
|
||||
/** Main entry point for initialization. */
|
||||
int32_t camera_suite_app(void* p) {
|
||||
UNUSED(p);
|
||||
CameraSuite* app = camera_suite_app_alloc();
|
||||
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
|
||||
// Init with start scene.
|
||||
scene_manager_next_scene(app->scene_manager, CameraSuiteSceneStart);
|
||||
furi_hal_power_suppress_charge_enter();
|
||||
view_dispatcher_run(app->view_dispatcher);
|
||||
camera_suite_save_settings(app);
|
||||
furi_hal_power_suppress_charge_exit();
|
||||
camera_suite_app_free(app);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
#pragma once
|
||||
|
||||
#include "helpers/camera_suite_storage.h"
|
||||
#include "scenes/camera_suite_scene.h"
|
||||
#include "views/camera_suite_view_guide.h"
|
||||
#include "views/camera_suite_view_start.h"
|
||||
#include "views/camera_suite_view_style_1.h"
|
||||
#include "views/camera_suite_view_style_2.h"
|
||||
#include <assets_icons.h>
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <gui/gui.h>
|
||||
#include <gui/modules/button_menu.h>
|
||||
#include <gui/modules/submenu.h>
|
||||
#include <gui/modules/variable_item_list.h>
|
||||
#include <gui/scene_manager.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <input/input.h>
|
||||
#include <notification/notification_messages.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define TAG "Camera Suite"
|
||||
|
||||
typedef struct {
|
||||
Gui* gui;
|
||||
NotificationApp* notification;
|
||||
ViewDispatcher* view_dispatcher;
|
||||
Submenu* submenu;
|
||||
SceneManager* scene_manager;
|
||||
VariableItemList* variable_item_list;
|
||||
CameraSuiteViewStart* camera_suite_view_start;
|
||||
CameraSuiteViewStyle1* camera_suite_view_style_1;
|
||||
CameraSuiteViewStyle2* camera_suite_view_style_2;
|
||||
CameraSuiteViewGuide* camera_suite_view_guide;
|
||||
uint32_t orientation;
|
||||
uint32_t haptic;
|
||||
uint32_t speaker;
|
||||
uint32_t led;
|
||||
ButtonMenu* button_menu;
|
||||
} CameraSuite;
|
||||
|
||||
typedef enum {
|
||||
CameraSuiteViewIdStartscreen,
|
||||
CameraSuiteViewIdMenu,
|
||||
CameraSuiteViewIdScene1,
|
||||
CameraSuiteViewIdScene2,
|
||||
CameraSuiteViewIdGuide,
|
||||
CameraSuiteViewIdSettings,
|
||||
} CameraSuiteViewId;
|
||||
|
||||
typedef enum {
|
||||
CameraSuiteOrientation0,
|
||||
CameraSuiteOrientation90,
|
||||
CameraSuiteOrientation180,
|
||||
CameraSuiteOrientation270,
|
||||
} CameraSuiteOrientationState;
|
||||
|
||||
typedef enum {
|
||||
CameraSuiteHapticOff,
|
||||
CameraSuiteHapticOn,
|
||||
} CameraSuiteHapticState;
|
||||
|
||||
typedef enum {
|
||||
CameraSuiteSpeakerOff,
|
||||
CameraSuiteSpeakerOn,
|
||||
} CameraSuiteSpeakerState;
|
||||
|
||||
typedef enum {
|
||||
CameraSuiteLedOff,
|
||||
CameraSuiteLedOn,
|
||||
} CameraSuiteLedState;
|
||||
@@ -0,0 +1,74 @@
|
||||
#pragma once
|
||||
|
||||
typedef enum {
|
||||
// Scene events: Start menu
|
||||
CameraSuiteCustomEventStartUp,
|
||||
CameraSuiteCustomEventStartDown,
|
||||
CameraSuiteCustomEventStartLeft,
|
||||
CameraSuiteCustomEventStartRight,
|
||||
CameraSuiteCustomEventStartOk,
|
||||
CameraSuiteCustomEventStartBack,
|
||||
// Scene events: Camera style 1
|
||||
CameraSuiteCustomEventSceneStyle1Up,
|
||||
CameraSuiteCustomEventSceneStyle1Down,
|
||||
CameraSuiteCustomEventSceneStyle1Left,
|
||||
CameraSuiteCustomEventSceneStyle1Right,
|
||||
CameraSuiteCustomEventSceneStyle1Ok,
|
||||
CameraSuiteCustomEventSceneStyle1Back,
|
||||
// Scene events: Camera style 2
|
||||
CameraSuiteCustomEventSceneStyle2Up,
|
||||
CameraSuiteCustomEventSceneStyle2Down,
|
||||
CameraSuiteCustomEventSceneStyle2Left,
|
||||
CameraSuiteCustomEventSceneStyle2Right,
|
||||
CameraSuiteCustomEventSceneStyle2Ok,
|
||||
CameraSuiteCustomEventSceneStyle2Back,
|
||||
// Scene events: Guide
|
||||
CameraSuiteCustomEventSceneGuideUp,
|
||||
CameraSuiteCustomEventSceneGuideDown,
|
||||
CameraSuiteCustomEventSceneGuideLeft,
|
||||
CameraSuiteCustomEventSceneGuideRight,
|
||||
CameraSuiteCustomEventSceneGuideOk,
|
||||
CameraSuiteCustomEventSceneGuideBack,
|
||||
} CameraSuiteCustomEvent;
|
||||
|
||||
enum CameraSuiteCustomEventType {
|
||||
// Reserve first 100 events for button types and indexes, starting from 0.
|
||||
CameraSuiteCustomEventMenuVoid,
|
||||
CameraSuiteCustomEventMenuSelected,
|
||||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
typedef union {
|
||||
uint32_t packed_value;
|
||||
struct {
|
||||
uint16_t type;
|
||||
int16_t value;
|
||||
} content;
|
||||
} CameraSuiteCustomEventMenu;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
static inline uint32_t camera_suite_custom_menu_event_pack(uint16_t type, int16_t value) {
|
||||
CameraSuiteCustomEventMenu event = {.content = {.type = type, .value = value}};
|
||||
return event.packed_value;
|
||||
}
|
||||
|
||||
static inline void
|
||||
camera_suite_custom_menu_event_unpack(uint32_t packed_value, uint16_t* type, int16_t* value) {
|
||||
CameraSuiteCustomEventMenu event = {.packed_value = packed_value};
|
||||
if(type) *type = event.content.type;
|
||||
if(value) *value = event.content.value;
|
||||
}
|
||||
|
||||
static inline uint16_t camera_suite_custom_menu_event_get_type(uint32_t packed_value) {
|
||||
uint16_t type;
|
||||
camera_suite_custom_menu_event_unpack(packed_value, &type, NULL);
|
||||
return type;
|
||||
}
|
||||
|
||||
static inline int16_t camera_suite_custom_menu_event_get_value(uint32_t packed_value) {
|
||||
int16_t value;
|
||||
camera_suite_custom_menu_event_unpack(packed_value, NULL, &value);
|
||||
return value;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
#include "camera_suite_haptic.h"
|
||||
#include "../camera_suite.h"
|
||||
|
||||
void camera_suite_play_happy_bump(void* context) {
|
||||
CameraSuite* app = context;
|
||||
if(app->haptic != 1) {
|
||||
return;
|
||||
}
|
||||
notification_message(app->notification, &sequence_set_vibro_on);
|
||||
furi_thread_flags_wait(0, FuriFlagWaitAny, 20);
|
||||
notification_message(app->notification, &sequence_reset_vibro);
|
||||
}
|
||||
|
||||
void camera_suite_play_bad_bump(void* context) {
|
||||
CameraSuite* app = context;
|
||||
if(app->haptic != 1) {
|
||||
return;
|
||||
}
|
||||
notification_message(app->notification, &sequence_set_vibro_on);
|
||||
furi_thread_flags_wait(0, FuriFlagWaitAny, 100);
|
||||
notification_message(app->notification, &sequence_reset_vibro);
|
||||
}
|
||||
|
||||
void camera_suite_play_long_bump(void* context) {
|
||||
CameraSuite* app = context;
|
||||
if(app->haptic != 1) {
|
||||
return;
|
||||
}
|
||||
for(int i = 0; i < 4; i++) {
|
||||
notification_message(app->notification, &sequence_set_vibro_on);
|
||||
furi_thread_flags_wait(0, FuriFlagWaitAny, 50);
|
||||
notification_message(app->notification, &sequence_reset_vibro);
|
||||
furi_thread_flags_wait(0, FuriFlagWaitAny, 100);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
#include <notification/notification_messages.h>
|
||||
|
||||
void camera_suite_play_happy_bump(void* context);
|
||||
|
||||
void camera_suite_play_bad_bump(void* context);
|
||||
|
||||
void camera_suite_play_long_bump(void* context);
|
||||
@@ -0,0 +1,38 @@
|
||||
#include "camera_suite_led.h"
|
||||
#include "../camera_suite.h"
|
||||
|
||||
void camera_suite_led_set_rgb(void* context, int red, int green, int blue) {
|
||||
CameraSuite* app = context;
|
||||
if(app->led != 1) {
|
||||
return;
|
||||
}
|
||||
NotificationMessage notification_led_message_1;
|
||||
notification_led_message_1.type = NotificationMessageTypeLedRed;
|
||||
NotificationMessage notification_led_message_2;
|
||||
notification_led_message_2.type = NotificationMessageTypeLedGreen;
|
||||
NotificationMessage notification_led_message_3;
|
||||
notification_led_message_3.type = NotificationMessageTypeLedBlue;
|
||||
|
||||
notification_led_message_1.data.led.value = red;
|
||||
notification_led_message_2.data.led.value = green;
|
||||
notification_led_message_3.data.led.value = blue;
|
||||
const NotificationSequence notification_sequence = {
|
||||
¬ification_led_message_1,
|
||||
¬ification_led_message_2,
|
||||
¬ification_led_message_3,
|
||||
&message_do_not_reset,
|
||||
NULL,
|
||||
};
|
||||
notification_message(app->notification, ¬ification_sequence);
|
||||
//Delay, prevent removal from RAM before LED value set.
|
||||
furi_thread_flags_wait(0, FuriFlagWaitAny, 10);
|
||||
}
|
||||
|
||||
void camera_suite_led_reset(void* context) {
|
||||
CameraSuite* app = context;
|
||||
notification_message(app->notification, &sequence_reset_red);
|
||||
notification_message(app->notification, &sequence_reset_green);
|
||||
notification_message(app->notification, &sequence_reset_blue);
|
||||
//Delay, prevent removal from RAM before LED value set.
|
||||
furi_thread_flags_wait(0, FuriFlagWaitAny, 300);
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
void camera_suite_led_set_rgb(void* context, int red, int green, int blue);
|
||||
|
||||
void camera_suite_led_reset(void* context);
|
||||
@@ -0,0 +1,26 @@
|
||||
#include "camera_suite_speaker.h"
|
||||
#include "../camera_suite.h"
|
||||
|
||||
#define NOTE_INPUT 587.33f
|
||||
|
||||
void camera_suite_play_input_sound(void* context) {
|
||||
CameraSuite* app = context;
|
||||
if(app->speaker != 1) {
|
||||
return;
|
||||
}
|
||||
float volume = 1.0f;
|
||||
if(furi_hal_speaker_is_mine() || furi_hal_speaker_acquire(30)) {
|
||||
furi_hal_speaker_start(NOTE_INPUT, volume);
|
||||
}
|
||||
}
|
||||
|
||||
void camera_suite_stop_all_sound(void* context) {
|
||||
CameraSuite* app = context;
|
||||
if(app->speaker != 1) {
|
||||
return;
|
||||
}
|
||||
if(furi_hal_speaker_is_mine()) {
|
||||
furi_hal_speaker_stop();
|
||||
furi_hal_speaker_release();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
#define NOTE_INPUT 587.33f
|
||||
|
||||
void camera_suite_play_input_sound(void* context);
|
||||
|
||||
void camera_suite_stop_all_sound(void* context);
|
||||
@@ -0,0 +1,113 @@
|
||||
#include "camera_suite_storage.h"
|
||||
|
||||
static Storage* camera_suite_open_storage() {
|
||||
return furi_record_open(RECORD_STORAGE);
|
||||
}
|
||||
|
||||
static void camera_suite_close_storage() {
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
}
|
||||
|
||||
static void camera_suite_close_config_file(FlipperFormat* file) {
|
||||
if(file == NULL) return;
|
||||
flipper_format_file_close(file);
|
||||
flipper_format_free(file);
|
||||
}
|
||||
|
||||
void camera_suite_save_settings(void* context) {
|
||||
CameraSuite* app = context;
|
||||
|
||||
FURI_LOG_D(TAG, "Saving Settings");
|
||||
Storage* storage = camera_suite_open_storage();
|
||||
FlipperFormat* fff_file = flipper_format_file_alloc(storage);
|
||||
|
||||
// Overwrite wont work, so delete first
|
||||
if(storage_file_exists(storage, BOILERPLATE_SETTINGS_SAVE_PATH)) {
|
||||
storage_simply_remove(storage, BOILERPLATE_SETTINGS_SAVE_PATH);
|
||||
}
|
||||
|
||||
// Open File, create if not exists
|
||||
if(!storage_common_stat(storage, BOILERPLATE_SETTINGS_SAVE_PATH, NULL) == FSE_OK) {
|
||||
FURI_LOG_D(
|
||||
TAG, "Config file %s is not found. Will create new.", BOILERPLATE_SETTINGS_SAVE_PATH);
|
||||
if(storage_common_stat(storage, CONFIG_FILE_DIRECTORY_PATH, NULL) == FSE_NOT_EXIST) {
|
||||
FURI_LOG_D(
|
||||
TAG, "Directory %s doesn't exist. Will create new.", CONFIG_FILE_DIRECTORY_PATH);
|
||||
if(!storage_simply_mkdir(storage, CONFIG_FILE_DIRECTORY_PATH)) {
|
||||
FURI_LOG_E(TAG, "Error creating directory %s", CONFIG_FILE_DIRECTORY_PATH);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!flipper_format_file_open_new(fff_file, BOILERPLATE_SETTINGS_SAVE_PATH)) {
|
||||
//totp_close_config_file(fff_file);
|
||||
FURI_LOG_E(TAG, "Error creating new file %s", BOILERPLATE_SETTINGS_SAVE_PATH);
|
||||
camera_suite_close_storage();
|
||||
return;
|
||||
}
|
||||
|
||||
// Store Settings
|
||||
flipper_format_write_header_cstr(
|
||||
fff_file, BOILERPLATE_SETTINGS_HEADER, BOILERPLATE_SETTINGS_FILE_VERSION);
|
||||
flipper_format_write_uint32(
|
||||
fff_file, BOILERPLATE_SETTINGS_KEY_ORIENTATION, &app->orientation, 1);
|
||||
flipper_format_write_uint32(fff_file, BOILERPLATE_SETTINGS_KEY_HAPTIC, &app->haptic, 1);
|
||||
flipper_format_write_uint32(fff_file, BOILERPLATE_SETTINGS_KEY_SPEAKER, &app->speaker, 1);
|
||||
flipper_format_write_uint32(fff_file, BOILERPLATE_SETTINGS_KEY_LED, &app->led, 1);
|
||||
|
||||
if(!flipper_format_rewind(fff_file)) {
|
||||
camera_suite_close_config_file(fff_file);
|
||||
FURI_LOG_E(TAG, "Rewind error");
|
||||
camera_suite_close_storage();
|
||||
return;
|
||||
}
|
||||
|
||||
camera_suite_close_config_file(fff_file);
|
||||
camera_suite_close_storage();
|
||||
}
|
||||
|
||||
void camera_suite_read_settings(void* context) {
|
||||
CameraSuite* app = context;
|
||||
Storage* storage = camera_suite_open_storage();
|
||||
FlipperFormat* fff_file = flipper_format_file_alloc(storage);
|
||||
|
||||
if(storage_common_stat(storage, BOILERPLATE_SETTINGS_SAVE_PATH, NULL) != FSE_OK) {
|
||||
camera_suite_close_config_file(fff_file);
|
||||
camera_suite_close_storage();
|
||||
return;
|
||||
}
|
||||
uint32_t file_version;
|
||||
FuriString* temp_str = furi_string_alloc();
|
||||
|
||||
if(!flipper_format_file_open_existing(fff_file, BOILERPLATE_SETTINGS_SAVE_PATH)) {
|
||||
FURI_LOG_E(TAG, "Cannot open file %s", BOILERPLATE_SETTINGS_SAVE_PATH);
|
||||
camera_suite_close_config_file(fff_file);
|
||||
camera_suite_close_storage();
|
||||
return;
|
||||
}
|
||||
|
||||
if(!flipper_format_read_header(fff_file, temp_str, &file_version)) {
|
||||
FURI_LOG_E(TAG, "Missing Header Data");
|
||||
camera_suite_close_config_file(fff_file);
|
||||
camera_suite_close_storage();
|
||||
return;
|
||||
}
|
||||
|
||||
if(file_version < BOILERPLATE_SETTINGS_FILE_VERSION) {
|
||||
FURI_LOG_I(TAG, "old config version, will be removed.");
|
||||
camera_suite_close_config_file(fff_file);
|
||||
camera_suite_close_storage();
|
||||
return;
|
||||
}
|
||||
|
||||
flipper_format_read_uint32(
|
||||
fff_file, BOILERPLATE_SETTINGS_KEY_ORIENTATION, &app->orientation, 1);
|
||||
flipper_format_read_uint32(fff_file, BOILERPLATE_SETTINGS_KEY_HAPTIC, &app->haptic, 1);
|
||||
flipper_format_read_uint32(fff_file, BOILERPLATE_SETTINGS_KEY_SPEAKER, &app->speaker, 1);
|
||||
flipper_format_read_uint32(fff_file, BOILERPLATE_SETTINGS_KEY_LED, &app->led, 1);
|
||||
|
||||
flipper_format_rewind(fff_file);
|
||||
|
||||
camera_suite_close_config_file(fff_file);
|
||||
camera_suite_close_storage();
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <storage/storage.h>
|
||||
#include <flipper_format/flipper_format_i.h>
|
||||
#include "../camera_suite.h"
|
||||
|
||||
#define BOILERPLATE_SETTINGS_FILE_VERSION 1
|
||||
#define CONFIG_FILE_DIRECTORY_PATH EXT_PATH("apps_data/camera_suite")
|
||||
#define BOILERPLATE_SETTINGS_SAVE_PATH CONFIG_FILE_DIRECTORY_PATH "/camera_suite.conf"
|
||||
#define BOILERPLATE_SETTINGS_SAVE_PATH_TMP BOILERPLATE_SETTINGS_SAVE_PATH ".tmp"
|
||||
#define BOILERPLATE_SETTINGS_HEADER "Camera Suite Config File"
|
||||
#define BOILERPLATE_SETTINGS_KEY_ORIENTATION "Orientation"
|
||||
#define BOILERPLATE_SETTINGS_KEY_HAPTIC "Haptic"
|
||||
#define BOILERPLATE_SETTINGS_KEY_LED "Led"
|
||||
#define BOILERPLATE_SETTINGS_KEY_SPEAKER "Speaker"
|
||||
#define BOILERPLATE_SETTINGS_KEY_SAVE_SETTINGS "SaveSettings"
|
||||
|
||||
void camera_suite_save_settings(void* context);
|
||||
|
||||
void camera_suite_read_settings(void* context);
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 2.3 KiB |
@@ -0,0 +1,30 @@
|
||||
#include "camera_suite_scene.h"
|
||||
|
||||
// Generate scene on_enter handlers array
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
|
||||
void (*const camera_suite_on_enter_handlers[])(void*) = {
|
||||
#include "camera_suite_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 camera_suite_on_event_handlers[])(void* context, SceneManagerEvent event) = {
|
||||
#include "camera_suite_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 camera_suite_on_exit_handlers[])(void* context) = {
|
||||
#include "camera_suite_scene_config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Initialize scene handlers configuration structure
|
||||
const SceneManagerHandlers camera_suite_scene_handlers = {
|
||||
.on_enter_handlers = camera_suite_on_enter_handlers,
|
||||
.on_event_handlers = camera_suite_on_event_handlers,
|
||||
.on_exit_handlers = camera_suite_on_exit_handlers,
|
||||
.scene_num = CameraSuiteSceneNum,
|
||||
};
|
||||
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/scene_manager.h>
|
||||
|
||||
// Generate scene id and total number
|
||||
#define ADD_SCENE(prefix, name, id) CameraSuiteScene##id,
|
||||
typedef enum {
|
||||
#include "camera_suite_scene_config.h"
|
||||
CameraSuiteSceneNum,
|
||||
} CameraSuiteScene;
|
||||
#undef ADD_SCENE
|
||||
|
||||
extern const SceneManagerHandlers camera_suite_scene_handlers;
|
||||
|
||||
// Generate scene on_enter handlers declaration
|
||||
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
|
||||
#include "camera_suite_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 "camera_suite_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 "camera_suite_scene_config.h"
|
||||
#undef ADD_SCENE
|
||||
@@ -0,0 +1,6 @@
|
||||
ADD_SCENE(camera_suite, start, Start)
|
||||
ADD_SCENE(camera_suite, menu, Menu)
|
||||
ADD_SCENE(camera_suite, style_1, Style_1)
|
||||
ADD_SCENE(camera_suite, style_2, Style_2)
|
||||
ADD_SCENE(camera_suite, guide, Guide)
|
||||
ADD_SCENE(camera_suite, settings, Settings)
|
||||
@@ -0,0 +1,51 @@
|
||||
#include "../camera_suite.h"
|
||||
#include "../helpers/camera_suite_custom_event.h"
|
||||
#include "../views/camera_suite_view_guide.h"
|
||||
|
||||
void camera_suite_view_guide_callback(CameraSuiteCustomEvent event, void* context) {
|
||||
furi_assert(context);
|
||||
CameraSuite* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, event);
|
||||
}
|
||||
|
||||
void camera_suite_scene_guide_on_enter(void* context) {
|
||||
furi_assert(context);
|
||||
CameraSuite* app = context;
|
||||
camera_suite_view_guide_set_callback(
|
||||
app->camera_suite_view_guide, camera_suite_view_guide_callback, app);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, CameraSuiteViewIdGuide);
|
||||
}
|
||||
|
||||
bool camera_suite_scene_guide_on_event(void* context, SceneManagerEvent event) {
|
||||
CameraSuite* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
switch(event.event) {
|
||||
case CameraSuiteCustomEventSceneGuideLeft:
|
||||
case CameraSuiteCustomEventSceneGuideRight:
|
||||
case CameraSuiteCustomEventSceneGuideUp:
|
||||
case CameraSuiteCustomEventSceneGuideDown:
|
||||
// Do nothing.
|
||||
break;
|
||||
case CameraSuiteCustomEventSceneGuideBack:
|
||||
notification_message(app->notification, &sequence_reset_red);
|
||||
notification_message(app->notification, &sequence_reset_green);
|
||||
notification_message(app->notification, &sequence_reset_blue);
|
||||
if(!scene_manager_search_and_switch_to_previous_scene(
|
||||
app->scene_manager, CameraSuiteSceneMenu)) {
|
||||
scene_manager_stop(app->scene_manager);
|
||||
view_dispatcher_stop(app->view_dispatcher);
|
||||
}
|
||||
consumed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void camera_suite_scene_guide_on_exit(void* context) {
|
||||
CameraSuite* app = context;
|
||||
UNUSED(app);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user