mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-07-12 23:48:10 -07:00
Merge branch 'flipperdevices:dev' into dev
This commit is contained in:
+46
-69
@@ -15,11 +15,8 @@ env:
|
||||
|
||||
jobs:
|
||||
main:
|
||||
runs-on: [self-hosted,FlipperZero]
|
||||
runs-on: [self-hosted,FlipperZeroShell]
|
||||
steps:
|
||||
- name: 'Cleanup workspace'
|
||||
uses: AutoModality/action-clean@v1
|
||||
|
||||
- name: 'Decontaminate previous build leftovers'
|
||||
run: |
|
||||
if [ -d .git ]
|
||||
@@ -32,12 +29,8 @@ jobs:
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
submodules: true
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
|
||||
- name: 'Build docker image'
|
||||
uses: ./.github/actions/docker
|
||||
|
||||
- name: 'Make artifacts directory'
|
||||
run: |
|
||||
test -d artifacts && rm -rf artifacts || true
|
||||
@@ -71,40 +64,38 @@ jobs:
|
||||
run: |
|
||||
tar czpf artifacts/flipper-z-any-scripts-${{steps.names.outputs.suffix}}.tgz scripts
|
||||
|
||||
- name: 'Build the firmware in docker'
|
||||
uses: ./.github/actions/docker
|
||||
with:
|
||||
run: |
|
||||
set -e
|
||||
for TARGET in ${TARGETS}
|
||||
do
|
||||
./fbt TARGET_HW=`echo ${TARGET} | sed 's/f//'` --with-updater updater_package ${{ startsWith(github.ref, 'refs/tags') && 'DEBUG=0 COMPACT=1' || '' }}
|
||||
done
|
||||
- name: 'Build the firmware'
|
||||
run: |
|
||||
set -e
|
||||
for TARGET in ${TARGETS}
|
||||
do
|
||||
FBT_TOOLCHAIN_PATH=/opt ./fbt TARGET_HW=`echo ${TARGET} | sed 's/f//'` updater_package ${{ startsWith(github.ref, 'refs/tags') && 'DEBUG=0 COMPACT=1' || '' }}
|
||||
done
|
||||
|
||||
- name: 'Move upload files'
|
||||
if: ${{ !github.event.pull_request.head.repo.fork }}
|
||||
uses: ./.github/actions/docker
|
||||
with:
|
||||
run: |
|
||||
set -e
|
||||
for TARGET in ${TARGETS}
|
||||
do
|
||||
mv dist/${TARGET}-*/* artifacts/
|
||||
done
|
||||
run: |
|
||||
set -e
|
||||
for TARGET in ${TARGETS}
|
||||
do
|
||||
mv dist/${TARGET}-*/* artifacts/
|
||||
done
|
||||
|
||||
- name: 'Bundle self-update package'
|
||||
if: ${{ !github.event.pull_request.head.repo.fork }}
|
||||
uses: ./.github/actions/docker
|
||||
with:
|
||||
run: |
|
||||
set -e
|
||||
for UPDATEBUNDLE in artifacts/*/
|
||||
do
|
||||
BUNDLE_NAME=`echo $UPDATEBUNDLE | cut -d'/' -f2`
|
||||
echo Packaging ${BUNDLE_NAME}
|
||||
tar czpf artifacts/flipper-z-${BUNDLE_NAME}.tgz -C artifacts ${BUNDLE_NAME}
|
||||
rm -rf artifacts/${BUNDLE_NAME}
|
||||
done
|
||||
run: |
|
||||
set -e
|
||||
for UPDATEBUNDLE in artifacts/*/
|
||||
do
|
||||
BUNDLE_NAME=`echo $UPDATEBUNDLE | cut -d'/' -f2`
|
||||
echo Packaging ${BUNDLE_NAME}
|
||||
tar czpf artifacts/flipper-z-${BUNDLE_NAME}.tgz -C artifacts ${BUNDLE_NAME}
|
||||
rm -rf artifacts/${BUNDLE_NAME}
|
||||
done
|
||||
|
||||
- name: "Check for uncommited changes"
|
||||
run: |
|
||||
git diff --exit-code
|
||||
|
||||
- name: 'Bundle resources'
|
||||
if: ${{ !github.event.pull_request.head.repo.fork }}
|
||||
@@ -113,29 +104,23 @@ jobs:
|
||||
|
||||
- name: 'Bundle core2 firmware'
|
||||
if: ${{ !github.event.pull_request.head.repo.fork }}
|
||||
uses: ./.github/actions/docker
|
||||
with:
|
||||
run: |
|
||||
./fbt copro_dist
|
||||
tar czpf artifacts/flipper-z-any-core2_firmware-${{steps.names.outputs.suffix}}.tgz -C assets core2_firmware
|
||||
run: |
|
||||
FBT_TOOLCHAIN_PATH=/opt ./fbt copro_dist
|
||||
tar czpf artifacts/flipper-z-any-core2_firmware-${{steps.names.outputs.suffix}}.tgz -C assets core2_firmware
|
||||
|
||||
- name: 'Upload artifacts to update server'
|
||||
if: ${{ !github.event.pull_request.head.repo.fork }}
|
||||
uses: burnett01/rsync-deployments@5.1
|
||||
with:
|
||||
switches: -avzP --delete --mkpath
|
||||
path: artifacts/
|
||||
remote_path: "${{ secrets.RSYNC_DEPLOY_BASE_PATH }}${{steps.names.outputs.artifacts-path}}/"
|
||||
remote_host: ${{ secrets.RSYNC_DEPLOY_HOST }}
|
||||
remote_port: ${{ secrets.RSYNC_DEPLOY_PORT }}
|
||||
remote_user: ${{ secrets.RSYNC_DEPLOY_USER }}
|
||||
remote_key: ${{ secrets.RSYNC_DEPLOY_KEY }}
|
||||
run: |
|
||||
echo "${{ secrets.RSYNC_DEPLOY_KEY }}" > deploy_key;
|
||||
chmod 600 ./deploy_key;
|
||||
rsync -avzP --delete --mkpath \
|
||||
-e 'ssh -p ${{ secrets.RSYNC_DEPLOY_PORT }} -i ./deploy_key' \
|
||||
artifacts/ ${{ secrets.RSYNC_DEPLOY_USER }}@${{ secrets.RSYNC_DEPLOY_HOST }}:"${{ secrets.RSYNC_DEPLOY_BASE_PATH }}${{steps.names.outputs.artifacts-path}}/";
|
||||
rm ./deploy_key;
|
||||
|
||||
- name: 'Trigger update server reindex'
|
||||
if: ${{ !github.event.pull_request.head.repo.fork }}
|
||||
uses: wei/curl@master
|
||||
with:
|
||||
args: -X POST -F 'key=${{ secrets.REINDEX_KEY }}' ${{ secrets.REINDEX_URL }}
|
||||
run: curl -X POST -F 'key=${{ secrets.REINDEX_KEY }}' ${{ secrets.REINDEX_URL }}
|
||||
|
||||
- name: 'Find Previous Comment'
|
||||
if: ${{ !github.event.pull_request.head.repo.fork && github.event.pull_request }}
|
||||
@@ -161,11 +146,8 @@ jobs:
|
||||
|
||||
compact:
|
||||
if: ${{ !startsWith(github.ref, 'refs/tags') }}
|
||||
runs-on: [self-hosted,FlipperZero]
|
||||
runs-on: [self-hosted,FlipperZeroShell]
|
||||
steps:
|
||||
- name: 'Cleanup workspace'
|
||||
uses: AutoModality/action-clean@v1
|
||||
|
||||
- name: 'Decontaminate previous build leftovers'
|
||||
run: |
|
||||
if [ -d .git ]
|
||||
@@ -181,9 +163,6 @@ jobs:
|
||||
submodules: true
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
|
||||
- name: 'Build docker image'
|
||||
uses: ./.github/actions/docker
|
||||
|
||||
- name: 'Generate suffix and folder name'
|
||||
id: names
|
||||
run: |
|
||||
@@ -203,12 +182,10 @@ jobs:
|
||||
echo "WORKFLOW_BRANCH_OR_TAG=${BRANCH_OR_TAG}" >> $GITHUB_ENV
|
||||
echo "DIST_SUFFIX=${SUFFIX}" >> $GITHUB_ENV
|
||||
|
||||
- name: 'Build the firmware in docker'
|
||||
uses: ./.github/actions/docker
|
||||
with:
|
||||
run: |
|
||||
set -e
|
||||
for TARGET in ${TARGETS}
|
||||
do
|
||||
./fbt TARGET_HW=`echo ${TARGET} | sed 's/f//'` --with-updater updater_package DEBUG=0 COMPACT=1
|
||||
done
|
||||
- name: 'Build the firmware'
|
||||
run: |
|
||||
set -e
|
||||
for TARGET in ${TARGETS}
|
||||
do
|
||||
FBT_TOOLCHAIN_PATH=/opt ./fbt TARGET_HW=`echo ${TARGET} | sed 's/f//'` updater_package DEBUG=0 COMPACT=1
|
||||
done
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
name: 'Build toolchain Docker image'
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
tags:
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v3
|
||||
with:
|
||||
images: flipperdevices/flipperzero-toolchain
|
||||
flavor: latest=${{ startsWith(github.ref, 'refs/tags/') && !endsWith(github.ref, 'rc')}}
|
||||
tags: |
|
||||
type=ref,event=branch
|
||||
type=ref,event=tag
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Build and push
|
||||
id: docker_build
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
context: docker/
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
platforms: linux/amd64,linux/arm64
|
||||
cache-from: type=registry,ref=flipperdevices/flipperzero-toolchain:buildcache
|
||||
cache-to: type=registry,ref=flipperdevices/flipperzero-toolchain:buildcache,mode=max
|
||||
@@ -1,17 +1,47 @@
|
||||
name: 'Check submodules'
|
||||
name: 'Check submodules branch'
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
- "release*"
|
||||
tags:
|
||||
- '*'
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
protobuf:
|
||||
runs-on: ubuntu-latest
|
||||
check_protobuf:
|
||||
runs-on: [self-hosted, FlipperZeroShell]
|
||||
steps:
|
||||
- name: 'Checkout code'
|
||||
uses: actions/checkout@v2
|
||||
- name: 'Check submodule commit branch'
|
||||
uses: jtmullen/submodule-branch-check-action@v1
|
||||
with:
|
||||
path: assets/protobuf
|
||||
branch: dev
|
||||
fetch_depth: 50
|
||||
- name: 'Decontaminate previous build leftovers'
|
||||
run: |
|
||||
if [ -d .git ]
|
||||
then
|
||||
git submodule status \
|
||||
|| git checkout `git rev-list --max-parents=0 HEAD | tail -n 1`
|
||||
fi
|
||||
|
||||
- name: 'Checkout code'
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: 'Check protobuf branch'
|
||||
run: |
|
||||
SUB_PATH="assets/protobuf";
|
||||
SUB_BRANCH="dev";
|
||||
SUB_COMMITS_MIN=40;
|
||||
cd "$SUB_PATH";
|
||||
SUBMODULE_HASH="$(git rev-parse HEAD)";
|
||||
BRANCHES=$(git branch -r --contains "$SUBMODULE_HASH");
|
||||
COMMITS_IN_BRANCH="$(git rev-list --count dev)";
|
||||
if [ $COMMITS_IN_BRANCH -lt $SUB_COMMITS_MIN ]; then
|
||||
echo "::set-output name=fails::error";
|
||||
echo "::error::Error: Too low commits in $SUB_BRANCH of submodule $SUB_PATH: $COMMITS_IN_BRANCH(expected $SUB_COMMITS_MIN+)";
|
||||
exit 1;
|
||||
fi
|
||||
if ! grep -q "/$SUB_BRANCH" <<< "$BRANCHES"; then
|
||||
echo "::set-output name=fails::error";
|
||||
echo "::error::Error: Submodule $SUB_PATH is not on branch $SUB_BRANCH";
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
name: 'Lint C/C++ with clang-format'
|
||||
|
||||
on:
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
@@ -14,11 +14,8 @@ env:
|
||||
|
||||
jobs:
|
||||
lint_c_cpp:
|
||||
runs-on: [self-hosted,FlipperZero]
|
||||
runs-on: [self-hosted,FlipperZeroShell]
|
||||
steps:
|
||||
- name: 'Cleanup workspace'
|
||||
uses: AutoModality/action-clean@v1
|
||||
|
||||
- name: 'Decontaminate previous build leftovers'
|
||||
run: |
|
||||
if [ -d .git ]
|
||||
@@ -31,23 +28,10 @@ jobs:
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
submodules: true
|
||||
|
||||
- name: 'Docker cache'
|
||||
uses: satackey/action-docker-layer-caching@v0.0.11
|
||||
continue-on-error: true
|
||||
with:
|
||||
key: docker-cache-${{ hashFiles('docker/**') }}-{hash}
|
||||
restore-keys: docker-cache-${{ hashFiles('docker/**') }}-
|
||||
|
||||
- name: 'Build docker image'
|
||||
uses: ./.github/actions/docker
|
||||
|
||||
- name: 'Check code formatting'
|
||||
id: syntax_check
|
||||
uses: ./.github/actions/docker
|
||||
with:
|
||||
run: SET_GH_OUTPUT=1 ./fbt lint
|
||||
run: SET_GH_OUTPUT=1 FBT_TOOLCHAIN_PATH=/opt ./fbt lint
|
||||
|
||||
- name: Report code formatting errors
|
||||
if: failure() && steps.syntax_check.outputs.errors && github.event.pull_request
|
||||
@@ -59,4 +43,4 @@ jobs:
|
||||
```
|
||||
${{ steps.syntax_check.outputs.errors }}
|
||||
```
|
||||
You might want to run `docker compose exec dev make format` for an auto-fix.
|
||||
You might want to run `./fbt format` for an auto-fix.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
name: 'Python Lint'
|
||||
|
||||
on:
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
@@ -11,11 +11,8 @@ on:
|
||||
|
||||
jobs:
|
||||
lint_python:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: [self-hosted,FlipperZeroShell]
|
||||
steps:
|
||||
- name: 'Cleanup workspace'
|
||||
uses: AutoModality/action-clean@v1
|
||||
|
||||
- name: 'Decontaminate previous build leftovers'
|
||||
run: |
|
||||
if [ -d .git ]
|
||||
@@ -29,8 +26,5 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: 'Setup python'
|
||||
uses: actions/setup-python@v2
|
||||
|
||||
- name: 'Check python code with black'
|
||||
uses: psf/black@20.8b1
|
||||
- name: 'Check code formatting'
|
||||
run: SET_GH_OUTPUT=1 FBT_TOOLCHAIN_PATH=/opt ./fbt lint_py
|
||||
|
||||
@@ -7,9 +7,8 @@ on:
|
||||
jobs:
|
||||
reindex:
|
||||
name: 'Reindex updates'
|
||||
runs-on: [self-hosted,FlipperZero]
|
||||
runs-on: [self-hosted,FlipperZeroShell]
|
||||
steps:
|
||||
- name: Trigger reindex
|
||||
uses: wei/curl@master
|
||||
with:
|
||||
args: -X POST -F 'key=${{ secrets.REINDEX_KEY }}' ${{ secrets.REINDEX_URL }}
|
||||
run: |
|
||||
curl -X POST -F 'key=${{ secrets.REINDEX_KEY }}' ${{ secrets.REINDEX_URL }}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
./c_cpp_properties.json
|
||||
./launch.json
|
||||
./settings.json
|
||||
./tasks.json
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Win32",
|
||||
"compilerPath": "${workspaceFolder}/toolchain/i686-windows/bin/arm-none-eabi-gcc.exe",
|
||||
"intelliSenseMode": "gcc-arm",
|
||||
"compileCommands": "${workspaceFolder}/build/latest/compile_commands.json",
|
||||
"configurationProvider": "ms-vscode.cpptools",
|
||||
"cStandard": "gnu17",
|
||||
"cppStandard": "c++17"
|
||||
},
|
||||
{
|
||||
"name": "Linux",
|
||||
"compilerPath": "${workspaceFolder}/toolchain/x86_64-linux/bin/arm-none-eabi-gcc",
|
||||
"intelliSenseMode": "gcc-arm",
|
||||
"compileCommands": "${workspaceFolder}/build/latest/compile_commands.json",
|
||||
"configurationProvider": "ms-vscode.cpptools",
|
||||
"cStandard": "gnu17",
|
||||
"cppStandard": "c++17"
|
||||
},
|
||||
{
|
||||
"name": "Mac",
|
||||
"compilerPath": "${workspaceFolder}/toolchain/x86_64-darwin/bin/arm-none-eabi-gcc",
|
||||
"intelliSenseMode": "gcc-arm",
|
||||
"compileCommands": "${workspaceFolder}/build/latest/compile_commands.json",
|
||||
"configurationProvider": "ms-vscode.cpptools",
|
||||
"cStandard": "gnu17",
|
||||
"cppStandard": "c++17"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
Vendored
+87
@@ -0,0 +1,87 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"inputs": [
|
||||
{
|
||||
"id": "BLACKMAGIC",
|
||||
"type": "command",
|
||||
"command": "shellCommand.execute",
|
||||
"args": {
|
||||
"command": "./fbt get_blackmagic",
|
||||
"description": "Get Blackmagic device",
|
||||
}
|
||||
}
|
||||
],
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Attach FW (ST-Link)",
|
||||
"cwd": "${workspaceFolder}",
|
||||
"executable": "./build/latest/firmware.elf",
|
||||
"request": "attach",
|
||||
"type": "cortex-debug",
|
||||
"servertype": "openocd",
|
||||
"device": "stlink",
|
||||
"svdFile": "./debug/STM32WB55_CM4.svd",
|
||||
"rtos": "FreeRTOS",
|
||||
"configFiles": [
|
||||
"interface/stlink.cfg",
|
||||
"./debug/stm32wbx.cfg",
|
||||
],
|
||||
"postAttachCommands": [
|
||||
// "attach 1",
|
||||
"compare-sections",
|
||||
]
|
||||
// "showDevDebugOutput": "raw",
|
||||
},
|
||||
{
|
||||
"name": "Attach FW (blackmagic)",
|
||||
"cwd": "${workspaceFolder}",
|
||||
"executable": "./build/latest/firmware.elf",
|
||||
"request": "attach",
|
||||
"type": "cortex-debug",
|
||||
"servertype": "external",
|
||||
"gdbTarget": "${input:BLACKMAGIC}",
|
||||
"svdFile": "./debug/STM32WB55_CM4.svd",
|
||||
"rtos": "FreeRTOS",
|
||||
"postAttachCommands": [
|
||||
"monitor swdp_scan",
|
||||
"attach 1",
|
||||
"set confirm off",
|
||||
"set mem inaccessible-by-default off",
|
||||
"compare-sections",
|
||||
]
|
||||
// "showDevDebugOutput": "raw",
|
||||
},
|
||||
{
|
||||
"name": "Attach FW (JLink)",
|
||||
"cwd": "${workspaceFolder}",
|
||||
"executable": "./build/latest/firmware.elf",
|
||||
"request": "attach",
|
||||
"type": "cortex-debug",
|
||||
"servertype": "jlink",
|
||||
"interface": "swd",
|
||||
"device": "STM32WB55RG",
|
||||
"svdFile": "./debug/STM32WB55_CM4.svd",
|
||||
"rtos": "FreeRTOS",
|
||||
// "showDevDebugOutput": "raw",
|
||||
},
|
||||
{
|
||||
"name": "fbt debug",
|
||||
"type": "python",
|
||||
"request": "launch",
|
||||
"program": "./lib/scons/scripts/scons.py",
|
||||
"args": [
|
||||
"sdk"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "python debug",
|
||||
"type": "python",
|
||||
"request": "launch",
|
||||
"program": "${file}",
|
||||
"args": []
|
||||
}
|
||||
]
|
||||
}
|
||||
Vendored
+22
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"C_Cpp.default.cStandard": "gnu17",
|
||||
"C_Cpp.default.cppStandard": "c++17",
|
||||
"python.formatting.provider": "black",
|
||||
"workbench.tree.indent": 12,
|
||||
"cortex-debug.enableTelemetry": false,
|
||||
"cortex-debug.variableUseNaturalFormat": true,
|
||||
"cortex-debug.showRTOS": true,
|
||||
"cortex-debug.armToolchainPath.windows": "${workspaceFolder}/toolchain/i686-windows/bin",
|
||||
"cortex-debug.armToolchainPath.linux": "${workspaceFolder}/toolchain/x86_64-linux/bin",
|
||||
"cortex-debug.armToolchainPath.osx": "${workspaceFolder}/toolchain/x86_64-darwin/bin",
|
||||
"cortex-debug.openocdPath.windows": "${workspaceFolder}/toolchain/i686-windows/openocd/bin/openocd.exe",
|
||||
"cortex-debug.openocdPath.linux": "${workspaceFolder}/toolchain/x86_64-linux/openocd/bin/openocd",
|
||||
"cortex-debug.openocdPath.osx": "${workspaceFolder}/toolchain/x86_64-darwin/openocd/bin/openocd",
|
||||
"editor.formatOnSave": true,
|
||||
"files.associations": {
|
||||
"*.scons": "python",
|
||||
"SConscript": "python",
|
||||
"SConstruct": "python",
|
||||
"*.fam": "python",
|
||||
}
|
||||
}
|
||||
Vendored
+103
@@ -0,0 +1,103 @@
|
||||
{
|
||||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
// for the documentation about the tasks.json format
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "[Release] Build",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt COMPACT=1 DEBUG=0"
|
||||
},
|
||||
{
|
||||
"label": "[Debug] Build",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt"
|
||||
},
|
||||
{
|
||||
"label": "[Release] Flash (ST-Link)",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt COMPACT=1 DEBUG=0 FORCE=1 flash"
|
||||
},
|
||||
{
|
||||
"label": "[Debug] Flash (ST-Link)",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt FORCE=1 flash"
|
||||
},
|
||||
{
|
||||
"label": "[Release] Flash (blackmagic)",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt COMPACT=1 DEBUG=0 FORCE=1 flash_blackmagic"
|
||||
},
|
||||
{
|
||||
"label": "[Debug] Flash (blackmagic)",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt FORCE=1 flash_blackmagic"
|
||||
},
|
||||
{
|
||||
"label": "[Release] Flash (JLink)",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt COMPACT=1 DEBUG=0 FORCE=1 jflash"
|
||||
},
|
||||
{
|
||||
"label": "[Debug] Flash (JLink)",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt FORCE=1 jflash"
|
||||
},
|
||||
{
|
||||
"label": "[Release] Build update bundle",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt update_package COMPACT=1 DEBUG=0"
|
||||
},
|
||||
{
|
||||
"label": "[Debug] Build update bundle",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt update_package"
|
||||
},
|
||||
{
|
||||
"label": "[Release] Build updater",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt updater_all COMPACT=1 DEBUG=0"
|
||||
},
|
||||
{
|
||||
"label": "[Debug] Build updater",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt updater_all"
|
||||
},
|
||||
{
|
||||
"label": "[Debug] Flash (USB, w/o resources)",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt FORCE=1 flash_usb"
|
||||
},
|
||||
{
|
||||
"label": "[Release] Flash (USB, w/o resources)",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt COMPACT=1 DEBUG=0 FORCE=1 flash_usb"
|
||||
},
|
||||
{
|
||||
"label": "[Debug:unit_tests] Flash (USB)",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt FIRMWARE_APP_SET=unit_tests FORCE=1 flash_usb"
|
||||
},
|
||||
{
|
||||
"label": "[Release] Flash (USB, with resources)",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt COMPACT=1 DEBUG=0 FORCE=1 flash_usb_full"
|
||||
},
|
||||
]
|
||||
}
|
||||
Vendored
+15
@@ -0,0 +1,15 @@
|
||||
{
|
||||
// See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
|
||||
// Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
|
||||
// List of extensions which should be recommended for users of this workspace.
|
||||
"recommendations": [
|
||||
"ms-python.black-formatter",
|
||||
"ms-vscode.cpptools",
|
||||
"amiralizadeh9480.cpp-helper",
|
||||
"marus25.cortex-debug",
|
||||
"zxh404.vscode-proto3",
|
||||
"augustocdias.tasks-shell-input"
|
||||
],
|
||||
// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
|
||||
"unwantedRecommendations": []
|
||||
}
|
||||
@@ -29,11 +29,11 @@ They both must be flashed in the order described.
|
||||
|
||||
With Flipper attached over USB:
|
||||
|
||||
`./fbt --with-updater flash_usb`
|
||||
`./fbt flash_usb`
|
||||
|
||||
Just building the package:
|
||||
|
||||
`./fbt --with-updater updater_package`
|
||||
`./fbt updater_package`
|
||||
|
||||
To update, copy the resulting directory to Flipper's SD card and navigate to `update.fuf` file in Archive app.
|
||||
|
||||
|
||||
+91
-23
@@ -7,6 +7,7 @@
|
||||
# construction of certain targets behind command-line options.
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
EnsurePythonVersion(3, 8)
|
||||
|
||||
@@ -33,8 +34,10 @@ coreenv["ROOT_DIR"] = Dir(".")
|
||||
|
||||
# Create a separate "dist" environment and add construction envs to it
|
||||
distenv = coreenv.Clone(
|
||||
tools=["fbt_dist", "openocd", "blackmagic"],
|
||||
OPENOCD_GDB_PIPE=["|openocd -c 'gdb_port pipe; log_output debug/openocd.log' ${[SINGLEQUOTEFUNC(OPENOCD_OPTS)]}"],
|
||||
tools=["fbt_dist", "openocd", "blackmagic", "jflash"],
|
||||
OPENOCD_GDB_PIPE=[
|
||||
"|openocd -c 'gdb_port pipe; log_output debug/openocd.log' ${[SINGLEQUOTEFUNC(OPENOCD_OPTS)]}"
|
||||
],
|
||||
GDBOPTS_BASE=[
|
||||
"-ex",
|
||||
"target extended-remote ${GDBREMOTE}",
|
||||
@@ -61,6 +64,7 @@ distenv = coreenv.Clone(
|
||||
"-ex",
|
||||
"compare-sections",
|
||||
],
|
||||
JFLASHPROJECT="${ROOT_DIR.abspath}/debug/fw.jflash",
|
||||
ENV=os.environ,
|
||||
)
|
||||
|
||||
@@ -71,7 +75,9 @@ firmware_env = distenv.AddFwProject(
|
||||
)
|
||||
|
||||
# If enabled, initialize updater-related targets
|
||||
if GetOption("fullenv"):
|
||||
if GetOption("fullenv") or any(
|
||||
filter(lambda target: "updater" in target or "flash_usb" in target, BUILD_TARGETS)
|
||||
):
|
||||
updater_env = distenv.AddFwProject(
|
||||
base_env=coreenv,
|
||||
fw_type="updater",
|
||||
@@ -79,11 +85,11 @@ if GetOption("fullenv"):
|
||||
)
|
||||
|
||||
# Target for self-update package
|
||||
dist_arguments = [
|
||||
"-r",
|
||||
'"${ROOT_DIR.abspath}/assets/resources"',
|
||||
dist_basic_arguments = [
|
||||
"--bundlever",
|
||||
'"${UPDATE_VERSION_STRING}"',
|
||||
]
|
||||
dist_radio_arguments = [
|
||||
"--radio",
|
||||
'"${ROOT_DIR.abspath}/${COPRO_STACK_BIN_DIR}/${COPRO_STACK_BIN}"',
|
||||
"--radiotype",
|
||||
@@ -92,16 +98,34 @@ if GetOption("fullenv"):
|
||||
"--obdata",
|
||||
'"${ROOT_DIR.abspath}/${COPRO_OB_DATA}"',
|
||||
]
|
||||
if distenv["UPDATE_SPLASH"]:
|
||||
dist_arguments += [
|
||||
dist_resource_arguments = [
|
||||
"-r",
|
||||
'"${ROOT_DIR.abspath}/assets/resources"',
|
||||
]
|
||||
dist_splash_arguments = (
|
||||
[
|
||||
"--splash",
|
||||
distenv.subst("assets/slideshow/$UPDATE_SPLASH"),
|
||||
]
|
||||
if distenv["UPDATE_SPLASH"]
|
||||
else []
|
||||
)
|
||||
|
||||
selfupdate_dist = distenv.DistCommand(
|
||||
"updater_package",
|
||||
(distenv["DIST_DEPENDS"], firmware_env["FW_RESOURCES"]),
|
||||
DIST_EXTRA=dist_arguments,
|
||||
DIST_EXTRA=[
|
||||
*dist_basic_arguments,
|
||||
*dist_radio_arguments,
|
||||
*dist_resource_arguments,
|
||||
*dist_splash_arguments,
|
||||
],
|
||||
)
|
||||
|
||||
selfupdate_min_dist = distenv.DistCommand(
|
||||
"updater_minpackage",
|
||||
distenv["DIST_DEPENDS"],
|
||||
DIST_EXTRA=dist_basic_arguments,
|
||||
)
|
||||
|
||||
# Updater debug
|
||||
@@ -121,18 +145,16 @@ if GetOption("fullenv"):
|
||||
)
|
||||
|
||||
# Installation over USB & CLI
|
||||
usb_update_package = distenv.UsbInstall(
|
||||
"#build/usbinstall.flag",
|
||||
(
|
||||
distenv["DIST_DEPENDS"],
|
||||
firmware_env["FW_RESOURCES"],
|
||||
selfupdate_dist,
|
||||
),
|
||||
usb_update_package = distenv.AddUsbFlashTarget(
|
||||
"#build/usbinstall.flag", (firmware_env["FW_RESOURCES"], selfupdate_dist)
|
||||
)
|
||||
if distenv["FORCE"]:
|
||||
distenv.AlwaysBuild(usb_update_package)
|
||||
distenv.Depends(usb_update_package, selfupdate_dist)
|
||||
distenv.Alias("flash_usb", usb_update_package)
|
||||
distenv.Alias("flash_usb_full", usb_update_package)
|
||||
|
||||
usb_minupdate_package = distenv.AddUsbFlashTarget(
|
||||
"#build/minusbinstall.flag", (selfupdate_min_dist,)
|
||||
)
|
||||
distenv.Alias("flash_usb", usb_minupdate_package)
|
||||
|
||||
|
||||
# Target for copying & renaming binaries to dist folder
|
||||
basic_dist = distenv.DistCommand("fw_dist", distenv["DIST_DEPENDS"])
|
||||
@@ -147,8 +169,9 @@ distenv.Alias("copro_dist", copro_dist)
|
||||
|
||||
firmware_flash = distenv.AddOpenOCDFlashTarget(firmware_env)
|
||||
distenv.Alias("flash", firmware_flash)
|
||||
if distenv["FORCE"]:
|
||||
distenv.AlwaysBuild(firmware_flash)
|
||||
|
||||
firmware_jflash = distenv.AddJFlashTarget(firmware_env)
|
||||
distenv.Alias("jflash", firmware_jflash)
|
||||
|
||||
firmware_bm_flash = distenv.PhonyTarget(
|
||||
"flash_blackmagic",
|
||||
@@ -209,10 +232,55 @@ distenv.PhonyTarget(
|
||||
LINT_SOURCES=firmware_env["LINT_SOURCES"],
|
||||
)
|
||||
|
||||
# PY_LINT_SOURCES contains recursively-built modules' SConscript files + application manifests
|
||||
# Here we add additional Python files residing in repo root
|
||||
firmware_env.Append(
|
||||
PY_LINT_SOURCES=[
|
||||
# Py code folders
|
||||
"site_scons",
|
||||
"scripts",
|
||||
# Extra files
|
||||
"applications/extapps.scons",
|
||||
"SConstruct",
|
||||
"firmware.scons",
|
||||
"fbt_options.py",
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
black_commandline = "@${PYTHON3} -m black ${PY_BLACK_ARGS} ${PY_LINT_SOURCES}"
|
||||
black_base_args = ["--include", '"\\.scons|\\.py|SConscript|SConstruct"']
|
||||
|
||||
distenv.PhonyTarget(
|
||||
"lint_py",
|
||||
black_commandline,
|
||||
PY_BLACK_ARGS=[
|
||||
"--check",
|
||||
"--diff",
|
||||
*black_base_args,
|
||||
],
|
||||
PY_LINT_SOURCES=firmware_env["PY_LINT_SOURCES"],
|
||||
)
|
||||
|
||||
distenv.PhonyTarget(
|
||||
"format_py",
|
||||
black_commandline,
|
||||
PY_BLACK_ARGS=black_base_args,
|
||||
PY_LINT_SOURCES=firmware_env["PY_LINT_SOURCES"],
|
||||
)
|
||||
|
||||
# Start Flipper CLI via PySerial's miniterm
|
||||
distenv.PhonyTarget("cli", "${PYTHON3} scripts/serial_cli.py")
|
||||
|
||||
|
||||
# Find blackmagic probe
|
||||
|
||||
distenv.PhonyTarget(
|
||||
"get_blackmagic",
|
||||
"@echo $( ${BLACKMAGIC_ADDR} $)",
|
||||
)
|
||||
|
||||
# Prepare vscode environment
|
||||
vscode_dist = distenv.Install("#.vscode", distenv.Glob("#.vscode/example/*"))
|
||||
distenv.Precious(vscode_dist)
|
||||
distenv.NoClean(vscode_dist)
|
||||
distenv.Alias("vscode_dist", vscode_dist)
|
||||
|
||||
@@ -45,7 +45,7 @@ static DialogMessageButton compliance_screen(DialogsApp* dialogs, DialogMessage*
|
||||
DialogMessageButton result;
|
||||
|
||||
const char* screen_text = "For all compliance\n"
|
||||
"certificates please visit\n"
|
||||
"certificates please visit:\n"
|
||||
"www.flipp.dev/compliance";
|
||||
|
||||
dialog_message_set_text(message, screen_text, 0, 0, AlignLeft, AlignTop);
|
||||
@@ -91,13 +91,13 @@ static DialogMessageButton hw_version_screen(DialogsApp* dialogs, DialogMessage*
|
||||
furi_hal_version_get_hw_region_name(),
|
||||
my_name ? my_name : "Unknown");
|
||||
|
||||
string_cat_printf(buffer, "Serial number:\n");
|
||||
string_cat_printf(buffer, "Serial Number:\n");
|
||||
const uint8_t* uid = furi_hal_version_uid();
|
||||
for(size_t i = 0; i < furi_hal_version_uid_size(); i++) {
|
||||
string_cat_printf(buffer, "%02X", uid[i]);
|
||||
}
|
||||
|
||||
dialog_message_set_header(message, "HW Version info:", 0, 0, AlignLeft, AlignTop);
|
||||
dialog_message_set_header(message, "HW Version Info:", 0, 0, AlignLeft, AlignTop);
|
||||
dialog_message_set_text(message, string_get_cstr(buffer), 0, 13, AlignLeft, AlignTop);
|
||||
result = dialog_message_show(dialogs, message);
|
||||
dialog_message_set_text(message, NULL, 0, 0, AlignLeft, AlignTop);
|
||||
@@ -133,7 +133,7 @@ static DialogMessageButton fw_version_screen(DialogsApp* dialogs, DialogMessage*
|
||||
version_get_gitbranch(ver));
|
||||
}
|
||||
|
||||
dialog_message_set_header(message, "FW Version info:", 0, 0, AlignLeft, AlignTop);
|
||||
dialog_message_set_header(message, "FW Version Info:", 0, 0, AlignLeft, AlignTop);
|
||||
dialog_message_set_text(message, string_get_cstr(buffer), 0, 13, AlignLeft, AlignTop);
|
||||
result = dialog_message_show(dialogs, message);
|
||||
dialog_message_set_text(message, NULL, 0, 0, AlignLeft, AlignTop);
|
||||
|
||||
@@ -92,8 +92,6 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) {
|
||||
ArchiveBrowserView* browser = archive->browser;
|
||||
ArchiveFile_t* selected = archive_get_current_file(browser);
|
||||
|
||||
const char* name = archive_get_name(browser);
|
||||
bool known_app = archive_is_known_app(selected->type);
|
||||
bool favorites = archive_get_tab(browser) == ArchiveTabFavorites;
|
||||
bool consumed = false;
|
||||
|
||||
@@ -108,18 +106,19 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) {
|
||||
consumed = true;
|
||||
break;
|
||||
case ArchiveBrowserEventFileMenuRun:
|
||||
if(known_app) {
|
||||
if(archive_is_known_app(selected->type)) {
|
||||
archive_run_in_app(browser, selected);
|
||||
archive_show_file_menu(browser, false);
|
||||
}
|
||||
consumed = true;
|
||||
break;
|
||||
case ArchiveBrowserEventFileMenuPin:
|
||||
case ArchiveBrowserEventFileMenuPin: {
|
||||
const char* name = archive_get_name(browser);
|
||||
if(favorites) {
|
||||
archive_favorites_delete(name);
|
||||
archive_file_array_rm_selected(browser);
|
||||
archive_show_file_menu(browser, false);
|
||||
} else if(known_app) {
|
||||
} else if(archive_is_known_app(selected->type)) {
|
||||
if(archive_is_favorite("%s", name)) {
|
||||
archive_favorites_delete("%s", name);
|
||||
} else {
|
||||
@@ -128,12 +127,12 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) {
|
||||
archive_show_file_menu(browser, false);
|
||||
}
|
||||
consumed = true;
|
||||
break;
|
||||
} break;
|
||||
|
||||
case ArchiveBrowserEventFileMenuRename:
|
||||
if(favorites) {
|
||||
browser->callback(ArchiveBrowserEventEnterFavMove, browser->context);
|
||||
} else if((known_app) && (selected->is_app == false)) {
|
||||
} else if((archive_is_known_app(selected->type)) && (selected->is_app == false)) {
|
||||
archive_show_file_menu(browser, false);
|
||||
scene_manager_set_scene_state(
|
||||
archive->scene_manager, ArchiveAppSceneBrowser, SCENE_STATE_NEED_REFRESH);
|
||||
|
||||
@@ -37,7 +37,7 @@ void archive_scene_rename_on_enter(void* context) {
|
||||
false);
|
||||
|
||||
ValidatorIsFile* validator_is_file = validator_is_file_alloc_init(
|
||||
string_get_cstr(archive->browser->path), archive->file_extension, NULL);
|
||||
string_get_cstr(archive->browser->path), archive->file_extension, "");
|
||||
text_input_set_validator(text_input, validator_is_file_callback, validator_is_file);
|
||||
|
||||
string_clear(filename);
|
||||
|
||||
@@ -28,7 +28,7 @@ BadUsbApp* bad_usb_app_alloc(char* arg) {
|
||||
|
||||
string_init(app->file_path);
|
||||
|
||||
if(arg != NULL) {
|
||||
if(arg && strlen(arg)) {
|
||||
string_set_str(app->file_path, arg);
|
||||
}
|
||||
|
||||
@@ -79,7 +79,6 @@ void bad_usb_app_free(BadUsbApp* app) {
|
||||
furi_assert(app);
|
||||
|
||||
// Views
|
||||
view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewFileSelect);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewWork);
|
||||
bad_usb_free(app->bad_usb_view);
|
||||
|
||||
|
||||
@@ -38,6 +38,5 @@ struct BadUsbApp {
|
||||
|
||||
typedef enum {
|
||||
BadUsbAppViewError,
|
||||
BadUsbAppViewFileSelect,
|
||||
BadUsbAppViewWork,
|
||||
} BadUsbAppView;
|
||||
|
||||
@@ -90,7 +90,7 @@ BtHid* bt_hid_app_alloc() {
|
||||
submenu_add_item(
|
||||
app->submenu, "Keyboard", BtHidSubmenuIndexKeyboard, bt_hid_submenu_callback, app);
|
||||
submenu_add_item(
|
||||
app->submenu, "Media player", BtHidSubmenuIndexMedia, bt_hid_submenu_callback, app);
|
||||
app->submenu, "Media Player", BtHidSubmenuIndexMedia, bt_hid_submenu_callback, app);
|
||||
submenu_add_item(app->submenu, "Mouse", BtHidSubmenuIndexMouse, bt_hid_submenu_callback, app);
|
||||
view_set_previous_callback(submenu_get_view(app->submenu), bt_hid_exit);
|
||||
view_dispatcher_add_view(
|
||||
@@ -103,7 +103,7 @@ BtHid* bt_hid_app_alloc() {
|
||||
dialog_ex_set_left_button_text(app->dialog, "Exit");
|
||||
dialog_ex_set_right_button_text(app->dialog, "Stay");
|
||||
dialog_ex_set_center_button_text(app->dialog, "Menu");
|
||||
dialog_ex_set_header(app->dialog, "Close current app?", 16, 12, AlignLeft, AlignTop);
|
||||
dialog_ex_set_header(app->dialog, "Close Current App?", 16, 12, AlignLeft, AlignTop);
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, BtHidViewExitConfirm, dialog_ex_get_view(app->dialog));
|
||||
|
||||
|
||||
@@ -347,7 +347,8 @@ static void bt_close_connection(Bt* bt) {
|
||||
furi_event_flag_set(bt->api_event, BT_API_UNLOCK_EVENT);
|
||||
}
|
||||
|
||||
int32_t bt_srv() {
|
||||
int32_t bt_srv(void* p) {
|
||||
UNUSED(p);
|
||||
Bt* bt = bt_alloc();
|
||||
|
||||
if(furi_hal_rtc_get_boot_mode() != FuriHalRtcBootModeNormal) {
|
||||
|
||||
@@ -10,9 +10,9 @@ void bt_settings_scene_forget_dev_confirm_dialog_callback(DialogExResult result,
|
||||
void bt_settings_scene_forget_dev_confirm_on_enter(void* context) {
|
||||
BtSettingsApp* app = context;
|
||||
DialogEx* dialog = app->dialog;
|
||||
dialog_ex_set_header(dialog, "Unpair all devices?", 64, 3, AlignCenter, AlignTop);
|
||||
dialog_ex_set_header(dialog, "Unpair All Devices?", 64, 3, AlignCenter, AlignTop);
|
||||
dialog_ex_set_text(
|
||||
dialog, "All previous pairings\nwill be lost.", 64, 22, AlignCenter, AlignTop);
|
||||
dialog, "All previous pairings\nwill be lost!", 64, 22, AlignCenter, AlignTop);
|
||||
dialog_ex_set_left_button_text(dialog, "Back");
|
||||
dialog_ex_set_right_button_text(dialog, "Unpair");
|
||||
dialog_ex_set_context(dialog, app);
|
||||
|
||||
@@ -439,9 +439,9 @@ void cli_session_open(Cli* cli, void* session) {
|
||||
cli->session = session;
|
||||
if(cli->session != NULL) {
|
||||
cli->session->init();
|
||||
furi_stdglue_set_thread_stdout_callback(cli->session->tx_stdout);
|
||||
furi_thread_set_stdout_callback(cli->session->tx_stdout);
|
||||
} else {
|
||||
furi_stdglue_set_thread_stdout_callback(NULL);
|
||||
furi_thread_set_stdout_callback(NULL);
|
||||
}
|
||||
furi_semaphore_release(cli->idle_sem);
|
||||
furi_check(furi_mutex_release(cli->mutex) == FuriStatusOk);
|
||||
@@ -455,7 +455,7 @@ void cli_session_close(Cli* cli) {
|
||||
cli->session->deinit();
|
||||
}
|
||||
cli->session = NULL;
|
||||
furi_stdglue_set_thread_stdout_callback(NULL);
|
||||
furi_thread_set_stdout_callback(NULL);
|
||||
furi_check(furi_mutex_release(cli->mutex) == FuriStatusOk);
|
||||
}
|
||||
|
||||
@@ -469,9 +469,9 @@ int32_t cli_srv(void* p) {
|
||||
furi_record_create(RECORD_CLI, cli);
|
||||
|
||||
if(cli->session != NULL) {
|
||||
furi_stdglue_set_thread_stdout_callback(cli->session->tx_stdout);
|
||||
furi_thread_set_stdout_callback(cli->session->tx_stdout);
|
||||
} else {
|
||||
furi_stdglue_set_thread_stdout_callback(NULL);
|
||||
furi_thread_set_stdout_callback(NULL);
|
||||
}
|
||||
|
||||
if(furi_hal_rtc_get_boot_mode() == FuriHalRtcBootModeNormal) {
|
||||
|
||||
@@ -25,7 +25,7 @@ struct CliSession {
|
||||
void (*deinit)(void);
|
||||
size_t (*rx)(uint8_t* buffer, size_t size, uint32_t timeout);
|
||||
void (*tx)(const uint8_t* buffer, size_t size);
|
||||
void (*tx_stdout)(void* _cookie, const char* data, size_t size);
|
||||
void (*tx_stdout)(const char* data, size_t size);
|
||||
bool (*is_connected)(void);
|
||||
};
|
||||
|
||||
|
||||
@@ -277,8 +277,7 @@ static void cli_vcp_tx(const uint8_t* buffer, size_t size) {
|
||||
#endif
|
||||
}
|
||||
|
||||
static void cli_vcp_tx_stdout(void* _cookie, const char* data, size_t size) {
|
||||
UNUSED(_cookie);
|
||||
static void cli_vcp_tx_stdout(const char* data, size_t size) {
|
||||
cli_vcp_tx((const uint8_t*)data, size);
|
||||
}
|
||||
|
||||
|
||||
@@ -26,11 +26,11 @@ static void keypad_test_render_callback(Canvas* canvas, void* ctx) {
|
||||
canvas_clear(canvas);
|
||||
char strings[5][20];
|
||||
|
||||
sprintf(strings[0], "Ok: %d", state->ok);
|
||||
sprintf(strings[1], "L: %d", state->left);
|
||||
sprintf(strings[2], "R: %d", state->right);
|
||||
sprintf(strings[3], "U: %d", state->up);
|
||||
sprintf(strings[4], "D: %d", state->down);
|
||||
snprintf(strings[0], 20, "Ok: %d", state->ok);
|
||||
snprintf(strings[1], 20, "L: %d", state->left);
|
||||
snprintf(strings[2], 20, "R: %d", state->right);
|
||||
snprintf(strings[3], 20, "U: %d", state->up);
|
||||
snprintf(strings[4], 20, "D: %d", state->down);
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str(canvas, 0, 10, "Keypad test");
|
||||
|
||||
@@ -143,7 +143,7 @@ static void bubble_animation_activate(BubbleAnimationView* view, bool force) {
|
||||
furi_assert(view);
|
||||
bool activate = true;
|
||||
BubbleAnimationViewModel* model = view_get_model(view->view);
|
||||
if(!model->current) {
|
||||
if(model->current == NULL) {
|
||||
activate = false;
|
||||
} else if(model->freeze_frame) {
|
||||
activate = false;
|
||||
@@ -151,14 +151,16 @@ static void bubble_animation_activate(BubbleAnimationView* view, bool force) {
|
||||
activate = false;
|
||||
}
|
||||
|
||||
if(!force) {
|
||||
if((model->active_ended_at + model->current->active_cooldown * 1000) >
|
||||
xTaskGetTickCount()) {
|
||||
activate = false;
|
||||
} else if(model->active_shift) {
|
||||
activate = false;
|
||||
} else if(model->current_frame >= model->current->passive_frames) {
|
||||
activate = false;
|
||||
if(model->current != NULL) {
|
||||
if(!force) {
|
||||
if((model->active_ended_at + model->current->active_cooldown * 1000) >
|
||||
xTaskGetTickCount()) {
|
||||
activate = false;
|
||||
} else if(model->active_shift) {
|
||||
activate = false;
|
||||
} else if(model->current_frame >= model->current->passive_frames) {
|
||||
activate = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
view_commit_model(view->view, false);
|
||||
@@ -288,7 +290,10 @@ static void bubble_animation_enter(void* context) {
|
||||
bubble_animation_activate(view, false);
|
||||
|
||||
BubbleAnimationViewModel* model = view_get_model(view->view);
|
||||
uint8_t frame_rate = model->current->icon_animation.frame_rate;
|
||||
uint8_t frame_rate = 0;
|
||||
if(model->current != NULL) {
|
||||
frame_rate = model->current->icon_animation.frame_rate;
|
||||
}
|
||||
view_commit_model(view->view, false);
|
||||
|
||||
if(frame_rate) {
|
||||
|
||||
@@ -90,7 +90,7 @@ void desktop_settings_app_free(DesktopSettingsApp* app) {
|
||||
extern int32_t desktop_settings_app(void* p) {
|
||||
DesktopSettingsApp* app = desktop_settings_app_alloc();
|
||||
LOAD_DESKTOP_SETTINGS(&app->settings);
|
||||
if(!strcmp(p, DESKTOP_SETTINGS_RUN_PIN_SETUP_ARG)) {
|
||||
if(p && (strcmp(p, DESKTOP_SETTINGS_RUN_PIN_SETUP_ARG) == 0)) {
|
||||
scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinSetupHowto);
|
||||
} else {
|
||||
scene_manager_next_scene(app->scene_manager, DesktopSettingsAppSceneStart);
|
||||
|
||||
@@ -23,7 +23,7 @@ void desktop_debug_render(Canvas* canvas, void* model) {
|
||||
const Version* ver;
|
||||
char buffer[64];
|
||||
|
||||
static const char* headers[] = {"FW Version info:", "Dolphin info:"};
|
||||
static const char* headers[] = {"FW Version Info:", "Dolphin Info:"};
|
||||
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
@@ -78,7 +78,6 @@ void desktop_debug_render(Canvas* canvas, void* model) {
|
||||
canvas_draw_str(canvas, 5, 50 + STATUS_BAR_Y_SHIFT, buffer);
|
||||
|
||||
} else {
|
||||
char buffer[64];
|
||||
Dolphin* dolphin = furi_record_open(RECORD_DOLPHIN);
|
||||
DolphinStats stats = dolphin_stats(dolphin);
|
||||
furi_record_close(RECORD_DOLPHIN);
|
||||
@@ -87,18 +86,20 @@ void desktop_debug_render(Canvas* canvas, void* model) {
|
||||
uint32_t remaining = dolphin_state_xp_to_levelup(m->icounter);
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
snprintf(buffer, 64, "Icounter: %ld Butthurt %ld", m->icounter, m->butthurt);
|
||||
snprintf(buffer, sizeof(buffer), "Icounter: %ld Butthurt %ld", m->icounter, m->butthurt);
|
||||
canvas_draw_str(canvas, 5, 19 + STATUS_BAR_Y_SHIFT, buffer);
|
||||
|
||||
snprintf(
|
||||
buffer,
|
||||
64,
|
||||
sizeof(buffer),
|
||||
"Level: %ld To level up: %ld",
|
||||
current_lvl,
|
||||
(remaining == (uint32_t)(-1) ? remaining : 0));
|
||||
canvas_draw_str(canvas, 5, 29 + STATUS_BAR_Y_SHIFT, buffer);
|
||||
|
||||
snprintf(buffer, 64, "%s", asctime(localtime((const time_t*)&m->timestamp)));
|
||||
// even if timestamp is uint64_t, it's safe to cast it to uint32_t, because furi_hal_rtc_datetime_to_timestamp only returns uint32_t
|
||||
snprintf(buffer, sizeof(buffer), "%ld", (uint32_t)m->timestamp);
|
||||
|
||||
canvas_draw_str(canvas, 5, 39 + STATUS_BAR_Y_SHIFT, buffer);
|
||||
canvas_draw_str(canvas, 0, 49 + STATUS_BAR_Y_SHIFT, "[< >] icounter value [ok] save");
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ void desktop_lock_menu_render(Canvas* canvas, void* model) {
|
||||
const char* str = Lockmenu_Items[i];
|
||||
|
||||
if(i == 1 && !m->pin_set) str = "Set PIN";
|
||||
if(m->hint_timeout && m->idx == 2 && m->idx == i) str = "Not implemented";
|
||||
if(m->hint_timeout && m->idx == 2 && m->idx == i) str = "Not Implemented";
|
||||
|
||||
if(str != NULL)
|
||||
canvas_draw_str_aligned(
|
||||
|
||||
@@ -38,6 +38,8 @@ appenv.AppendUnique(
|
||||
"-Wl,--no-export-dynamic",
|
||||
"-fvisibility=hidden",
|
||||
"-Wl,-e${APP_ENTRY}",
|
||||
"-Xlinker",
|
||||
"-Map=${TARGET}.map",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ static bool gpio_test_process_ok(GpioTest* gpio_test, InputEvent* event);
|
||||
static void gpio_test_draw_callback(Canvas* canvas, void* _model) {
|
||||
GpioTestModel* model = _model;
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
elements_multiline_text_aligned(canvas, 64, 2, AlignCenter, AlignTop, "Gpio Output mode test");
|
||||
elements_multiline_text_aligned(canvas, 64, 2, AlignCenter, AlignTop, "GPIO Output Mode Test");
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
elements_multiline_text_aligned(
|
||||
canvas, 64, 16, AlignCenter, AlignTop, "Press < or > to change pin");
|
||||
|
||||
@@ -185,17 +185,19 @@ static void button_menu_process_ok(ButtonMenu* button_menu, InputType type) {
|
||||
return false;
|
||||
});
|
||||
|
||||
if(item->type == ButtonMenuItemTypeControl) {
|
||||
if(type == InputTypeShort) {
|
||||
if(item && item->callback) {
|
||||
item->callback(item->callback_context, item->index, type);
|
||||
if(item) {
|
||||
if(item->type == ButtonMenuItemTypeControl) {
|
||||
if(type == InputTypeShort) {
|
||||
if(item && item->callback) {
|
||||
item->callback(item->callback_context, item->index, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(item->type == ButtonMenuItemTypeCommon) {
|
||||
if((type == InputTypePress) || (type == InputTypeRelease)) {
|
||||
if(item && item->callback) {
|
||||
item->callback(item->callback_context, item->index, type);
|
||||
if(item->type == ButtonMenuItemTypeCommon) {
|
||||
if((type == InputTypePress) || (type == InputTypeRelease)) {
|
||||
if(item && item->callback) {
|
||||
item->callback(item->callback_context, item->index, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,7 +147,7 @@ static void text_input_backspace_cb(TextInputModel* model) {
|
||||
|
||||
static void text_input_view_draw_callback(Canvas* canvas, void* _model) {
|
||||
TextInputModel* model = _model;
|
||||
uint8_t text_length = strlen(model->text_buffer);
|
||||
uint8_t text_length = model->text_buffer ? strlen(model->text_buffer) : 0;
|
||||
uint8_t needed_string_width = canvas_width(canvas) - 8;
|
||||
uint8_t start_pos = 4;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
// #include <gui/view.h>
|
||||
#include <m-string.h>
|
||||
#include <core/common_defines.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
||||
@@ -5,24 +5,10 @@
|
||||
#include "m-string.h"
|
||||
#include <toolbox/path.h>
|
||||
#include <flipper_format/flipper_format.h>
|
||||
#include "rpc/rpc_app.h"
|
||||
#include <rpc/rpc_app.h>
|
||||
|
||||
#define TAG "iButtonApp"
|
||||
|
||||
static const NotificationSequence sequence_blink_start_cyan = {
|
||||
&message_blink_start_10,
|
||||
&message_blink_set_color_cyan,
|
||||
&message_do_not_reset,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const NotificationSequence sequence_blink_start_magenta = {
|
||||
&message_blink_start_10,
|
||||
&message_blink_set_color_magenta,
|
||||
&message_do_not_reset,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const NotificationSequence sequence_blink_set_yellow = {
|
||||
&message_blink_set_color_yellow,
|
||||
NULL,
|
||||
@@ -33,11 +19,6 @@ static const NotificationSequence sequence_blink_set_magenta = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const NotificationSequence sequence_blink_stop = {
|
||||
&message_blink_stop,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const NotificationSequence* ibutton_notification_sequences[] = {
|
||||
&sequence_error,
|
||||
&sequence_success,
|
||||
@@ -58,7 +39,7 @@ static void ibutton_make_app_folder(iButton* ibutton) {
|
||||
}
|
||||
}
|
||||
|
||||
static bool ibutton_load_key_data(iButton* ibutton, string_t key_path, bool show_dialog) {
|
||||
bool ibutton_load_key_data(iButton* ibutton, string_t key_path, bool show_dialog) {
|
||||
FlipperFormat* file = flipper_format_file_alloc(ibutton->storage);
|
||||
bool result = false;
|
||||
string_t data;
|
||||
@@ -99,33 +80,20 @@ static bool ibutton_load_key_data(iButton* ibutton, string_t key_path, bool show
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool ibutton_rpc_command_callback(RpcAppSystemEvent event, const char* arg, void* context) {
|
||||
static void ibutton_rpc_command_callback(RpcAppSystemEvent event, void* context) {
|
||||
furi_assert(context);
|
||||
iButton* ibutton = context;
|
||||
|
||||
bool result = false;
|
||||
|
||||
if(event == RpcAppEventSessionClose) {
|
||||
rpc_system_app_set_callback(ibutton->rpc_ctx, NULL, NULL);
|
||||
ibutton->rpc_ctx = NULL;
|
||||
view_dispatcher_send_custom_event(ibutton->view_dispatcher, iButtonCustomEventRpcExit);
|
||||
result = true;
|
||||
view_dispatcher_send_custom_event(
|
||||
ibutton->view_dispatcher, iButtonCustomEventRpcSessionClose);
|
||||
} else if(event == RpcAppEventAppExit) {
|
||||
view_dispatcher_send_custom_event(ibutton->view_dispatcher, iButtonCustomEventRpcExit);
|
||||
result = true;
|
||||
} else if(event == RpcAppEventLoadFile) {
|
||||
if(arg) {
|
||||
string_set_str(ibutton->file_path, arg);
|
||||
if(ibutton_load_key_data(ibutton, ibutton->file_path, false)) {
|
||||
ibutton_worker_emulate_start(ibutton->key_worker, ibutton->key);
|
||||
view_dispatcher_send_custom_event(
|
||||
ibutton->view_dispatcher, iButtonCustomEventRpcLoad);
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
view_dispatcher_send_custom_event(ibutton->view_dispatcher, iButtonCustomEventRpcLoad);
|
||||
} else {
|
||||
rpc_system_app_confirm(ibutton->rpc_ctx, event, false);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ibutton_custom_event_callback(void* context, uint32_t event) {
|
||||
@@ -366,7 +334,7 @@ int32_t ibutton_app(void* p) {
|
||||
bool key_loaded = false;
|
||||
bool rpc_mode = false;
|
||||
|
||||
if(p) {
|
||||
if(p && strlen(p)) {
|
||||
uint32_t rpc_ctx = 0;
|
||||
if(sscanf(p, "RPC %lX", &rpc_ctx) == 1) {
|
||||
FURI_LOG_D(TAG, "Running in RPC mode");
|
||||
|
||||
@@ -12,4 +12,5 @@ enum iButtonCustomEvent {
|
||||
|
||||
iButtonCustomEventRpcLoad,
|
||||
iButtonCustomEventRpcExit,
|
||||
iButtonCustomEventRpcSessionClose,
|
||||
};
|
||||
|
||||
@@ -78,6 +78,7 @@ typedef enum {
|
||||
} iButtonNotificationMessage;
|
||||
|
||||
bool ibutton_file_select(iButton* ibutton);
|
||||
bool ibutton_load_key_data(iButton* ibutton, string_t key_path, bool show_dialog);
|
||||
bool ibutton_save_key(iButton* ibutton, const char* key_name);
|
||||
bool ibutton_delete_key(iButton* ibutton);
|
||||
void ibutton_text_store_set(iButton* ibutton, const char* text, ...);
|
||||
|
||||
@@ -21,7 +21,7 @@ void ibutton_scene_exit_confirm_on_enter(void* context) {
|
||||
widget_add_string_element(
|
||||
widget, 64, 19, AlignCenter, AlignBottom, FontPrimary, "Exit to iButton menu?");
|
||||
widget_add_string_element(
|
||||
widget, 64, 31, AlignCenter, AlignBottom, FontSecondary, "All unsaved data will be lost.");
|
||||
widget, 64, 31, AlignCenter, AlignBottom, FontSecondary, "All unsaved data will be lost!");
|
||||
|
||||
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewWidget);
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ void ibutton_scene_read_on_enter(void* context) {
|
||||
DOLPHIN_DEED(DolphinDeedIbuttonRead);
|
||||
|
||||
popup_set_header(popup, "iButton", 95, 26, AlignCenter, AlignBottom);
|
||||
popup_set_text(popup, "waiting\nfor key ...", 95, 30, AlignCenter, AlignTop);
|
||||
popup_set_text(popup, "Waiting\nfor key ...", 95, 30, AlignCenter, AlignTop);
|
||||
popup_set_icon(popup, 0, 5, &I_DolphinWait_61x59);
|
||||
|
||||
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewPopup);
|
||||
|
||||
@@ -21,7 +21,7 @@ void ibutton_scene_retry_confirm_on_enter(void* context) {
|
||||
widget_add_string_element(
|
||||
widget, 64, 19, AlignCenter, AlignBottom, FontPrimary, "Return to reading?");
|
||||
widget_add_string_element(
|
||||
widget, 64, 29, AlignCenter, AlignBottom, FontSecondary, "All unsaved data will be lost.");
|
||||
widget, 64, 29, AlignCenter, AlignBottom, FontSecondary, "All unsaved data will be lost!");
|
||||
|
||||
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewWidget);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "../ibutton_i.h"
|
||||
#include <toolbox/path.h>
|
||||
#include <rpc/rpc_app.h>
|
||||
|
||||
void ibutton_scene_rpc_on_enter(void* context) {
|
||||
iButton* ibutton = context;
|
||||
@@ -26,23 +27,40 @@ bool ibutton_scene_rpc_on_event(void* context, SceneManagerEvent event) {
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
consumed = true;
|
||||
if(event.event == iButtonCustomEventRpcLoad) {
|
||||
string_t key_name;
|
||||
string_init(key_name);
|
||||
if(string_end_with_str_p(ibutton->file_path, IBUTTON_APP_EXTENSION)) {
|
||||
path_extract_filename(ibutton->file_path, key_name, true);
|
||||
const char* arg = rpc_system_app_get_data(ibutton->rpc_ctx);
|
||||
bool result = false;
|
||||
if(arg) {
|
||||
string_set_str(ibutton->file_path, arg);
|
||||
if(ibutton_load_key_data(ibutton, ibutton->file_path, false)) {
|
||||
ibutton_worker_emulate_start(ibutton->key_worker, ibutton->key);
|
||||
string_t key_name;
|
||||
string_init(key_name);
|
||||
if(string_end_with_str_p(ibutton->file_path, IBUTTON_APP_EXTENSION)) {
|
||||
path_extract_filename(ibutton->file_path, key_name, true);
|
||||
}
|
||||
|
||||
if(!string_empty_p(key_name)) {
|
||||
ibutton_text_store_set(
|
||||
ibutton, "emulating\n%s", string_get_cstr(key_name));
|
||||
} else {
|
||||
ibutton_text_store_set(ibutton, "emulating");
|
||||
}
|
||||
popup_set_text(popup, ibutton->text_store, 82, 32, AlignCenter, AlignTop);
|
||||
|
||||
ibutton_notification_message(ibutton, iButtonNotificationMessageEmulateStart);
|
||||
|
||||
string_clear(key_name);
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(!string_empty_p(key_name)) {
|
||||
ibutton_text_store_set(ibutton, "emulating\n%s", string_get_cstr(key_name));
|
||||
} else {
|
||||
ibutton_text_store_set(ibutton, "emulating");
|
||||
}
|
||||
popup_set_text(popup, ibutton->text_store, 82, 32, AlignCenter, AlignTop);
|
||||
|
||||
ibutton_notification_message(ibutton, iButtonNotificationMessageEmulateStart);
|
||||
|
||||
string_clear(key_name);
|
||||
rpc_system_app_confirm(ibutton->rpc_ctx, RpcAppEventLoadFile, result);
|
||||
} else if(event.event == iButtonCustomEventRpcExit) {
|
||||
rpc_system_app_confirm(ibutton->rpc_ctx, RpcAppEventAppExit, true);
|
||||
ibutton_notification_message(ibutton, iButtonNotificationMessageBlinkStop);
|
||||
view_dispatcher_stop(ibutton->view_dispatcher);
|
||||
} else if(event.event == iButtonCustomEventRpcSessionClose) {
|
||||
rpc_system_app_set_callback(ibutton->rpc_ctx, NULL, NULL);
|
||||
ibutton->rpc_ctx = NULL;
|
||||
ibutton_notification_message(ibutton, iButtonNotificationMessageBlinkStop);
|
||||
view_dispatcher_stop(ibutton->view_dispatcher);
|
||||
}
|
||||
|
||||
@@ -7,10 +7,12 @@ static const NotificationSequence* infrared_notification_sequences[] = {
|
||||
&sequence_success,
|
||||
&sequence_set_only_green_255,
|
||||
&sequence_reset_green,
|
||||
&sequence_blink_cyan_10,
|
||||
&sequence_blink_magenta_10,
|
||||
&sequence_solid_yellow,
|
||||
&sequence_reset_rgb};
|
||||
&sequence_reset_rgb,
|
||||
&sequence_blink_start_cyan,
|
||||
&sequence_blink_start_magenta,
|
||||
&sequence_blink_stop,
|
||||
};
|
||||
|
||||
static void infrared_make_app_folder(Infrared* infrared) {
|
||||
if(!storage_simply_mkdir(infrared->storage, INFRARED_APP_FOLDER)) {
|
||||
@@ -36,52 +38,29 @@ static void infrared_tick_event_callback(void* context) {
|
||||
scene_manager_handle_tick_event(infrared->scene_manager);
|
||||
}
|
||||
|
||||
static bool
|
||||
infrared_rpc_command_callback(RpcAppSystemEvent event, const char* arg, void* context) {
|
||||
static void infrared_rpc_command_callback(RpcAppSystemEvent event, void* context) {
|
||||
furi_assert(context);
|
||||
Infrared* infrared = context;
|
||||
|
||||
if(!infrared->rpc_ctx) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = false;
|
||||
furi_assert(infrared->rpc_ctx);
|
||||
|
||||
if(event == RpcAppEventSessionClose) {
|
||||
rpc_system_app_set_callback(infrared->rpc_ctx, NULL, NULL);
|
||||
infrared->rpc_ctx = NULL;
|
||||
view_dispatcher_send_custom_event(
|
||||
infrared->view_dispatcher, InfraredCustomEventTypeBackPressed);
|
||||
result = true;
|
||||
infrared->view_dispatcher, InfraredCustomEventTypeRpcSessionClose);
|
||||
} else if(event == RpcAppEventAppExit) {
|
||||
view_dispatcher_send_custom_event(
|
||||
infrared->view_dispatcher, InfraredCustomEventTypeBackPressed);
|
||||
result = true;
|
||||
infrared->view_dispatcher, InfraredCustomEventTypeRpcExit);
|
||||
} else if(event == RpcAppEventLoadFile) {
|
||||
if(arg) {
|
||||
string_set_str(infrared->file_path, arg);
|
||||
result = infrared_remote_load(infrared->remote, infrared->file_path);
|
||||
infrared_worker_tx_set_get_signal_callback(
|
||||
infrared->worker, infrared_worker_tx_get_signal_steady_callback, infrared);
|
||||
infrared_worker_tx_set_signal_sent_callback(
|
||||
infrared->worker, infrared_signal_sent_callback, infrared);
|
||||
view_dispatcher_send_custom_event(
|
||||
infrared->view_dispatcher, InfraredCustomEventTypeRpcLoaded);
|
||||
}
|
||||
view_dispatcher_send_custom_event(
|
||||
infrared->view_dispatcher, InfraredCustomEventTypeRpcLoad);
|
||||
} else if(event == RpcAppEventButtonPress) {
|
||||
if(arg) {
|
||||
size_t button_index = 0;
|
||||
if(infrared_remote_find_button_by_name(infrared->remote, arg, &button_index)) {
|
||||
infrared_tx_start_button_index(infrared, button_index);
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
view_dispatcher_send_custom_event(
|
||||
infrared->view_dispatcher, InfraredCustomEventTypeRpcButtonPress);
|
||||
} else if(event == RpcAppEventButtonRelease) {
|
||||
infrared_tx_stop(infrared);
|
||||
result = true;
|
||||
view_dispatcher_send_custom_event(
|
||||
infrared->view_dispatcher, InfraredCustomEventTypeRpcButtonRelease);
|
||||
} else {
|
||||
rpc_system_app_confirm(infrared->rpc_ctx, event, false);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void infrared_find_vacant_remote_name(string_t name, const char* path) {
|
||||
@@ -324,6 +303,7 @@ void infrared_tx_start_signal(Infrared* infrared, InfraredSignal* signal) {
|
||||
|
||||
DOLPHIN_DEED(DolphinDeedIrSend);
|
||||
infrared_worker_tx_start(infrared->worker);
|
||||
infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStartSend);
|
||||
}
|
||||
|
||||
void infrared_tx_start_button_index(Infrared* infrared, size_t button_index) {
|
||||
@@ -333,14 +313,17 @@ void infrared_tx_start_button_index(Infrared* infrared, size_t button_index) {
|
||||
InfraredSignal* signal = infrared_remote_button_get_signal(button);
|
||||
|
||||
infrared_tx_start_signal(infrared, signal);
|
||||
infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStartSend);
|
||||
}
|
||||
|
||||
void infrared_tx_start_received(Infrared* infrared) {
|
||||
infrared_tx_start_signal(infrared, infrared->received_signal);
|
||||
infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStartSend);
|
||||
}
|
||||
|
||||
void infrared_tx_stop(Infrared* infrared) {
|
||||
infrared_worker_tx_stop(infrared->worker);
|
||||
infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStop);
|
||||
}
|
||||
|
||||
void infrared_text_store_set(Infrared* infrared, uint32_t bank, const char* text, ...) {
|
||||
@@ -377,12 +360,6 @@ void infrared_show_loading_popup(Infrared* infrared, bool show) {
|
||||
}
|
||||
}
|
||||
|
||||
void infrared_signal_sent_callback(void* context) {
|
||||
furi_assert(context);
|
||||
Infrared* infrared = context;
|
||||
infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkSend);
|
||||
}
|
||||
|
||||
void infrared_signal_received_callback(void* context, InfraredWorkerSignal* received_signal) {
|
||||
furi_assert(context);
|
||||
Infrared* infrared = context;
|
||||
@@ -428,7 +405,7 @@ int32_t infrared_app(void* p) {
|
||||
bool is_remote_loaded = false;
|
||||
bool is_rpc_mode = false;
|
||||
|
||||
if(p) {
|
||||
if(p && strlen(p)) {
|
||||
uint32_t rpc_ctx = 0;
|
||||
if(sscanf(p, "RPC %lX", &rpc_ctx) == 1) {
|
||||
infrared->rpc_ctx = (void*)rpc_ctx;
|
||||
|
||||
@@ -27,7 +27,7 @@ static void signal_received_callback(void* context, InfraredWorkerSignal* receiv
|
||||
|
||||
if(infrared_worker_signal_is_decoded(received_signal)) {
|
||||
const InfraredMessage* message = infrared_worker_get_decoded_signal(received_signal);
|
||||
buf_cnt = sniprintf(
|
||||
buf_cnt = snprintf(
|
||||
buf,
|
||||
sizeof(buf),
|
||||
"%s, A:0x%0*lX, C:0x%0*lX%s\r\n",
|
||||
@@ -43,13 +43,13 @@ static void signal_received_callback(void* context, InfraredWorkerSignal* receiv
|
||||
size_t timings_cnt;
|
||||
infrared_worker_get_raw_signal(received_signal, &timings, &timings_cnt);
|
||||
|
||||
buf_cnt = sniprintf(buf, sizeof(buf), "RAW, %d samples:\r\n", timings_cnt);
|
||||
buf_cnt = snprintf(buf, sizeof(buf), "RAW, %d samples:\r\n", timings_cnt);
|
||||
cli_write(cli, (uint8_t*)buf, buf_cnt);
|
||||
for(size_t i = 0; i < timings_cnt; ++i) {
|
||||
buf_cnt = sniprintf(buf, sizeof(buf), "%lu ", timings[i]);
|
||||
buf_cnt = snprintf(buf, sizeof(buf), "%lu ", timings[i]);
|
||||
cli_write(cli, (uint8_t*)buf, buf_cnt);
|
||||
}
|
||||
buf_cnt = sniprintf(buf, sizeof(buf), "\r\n");
|
||||
buf_cnt = snprintf(buf, sizeof(buf), "\r\n");
|
||||
cli_write(cli, (uint8_t*)buf, buf_cnt);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,12 @@ enum InfraredCustomEventType {
|
||||
InfraredCustomEventTypePopupClosed,
|
||||
InfraredCustomEventTypeButtonSelected,
|
||||
InfraredCustomEventTypeBackPressed,
|
||||
InfraredCustomEventTypeRpcLoaded,
|
||||
|
||||
InfraredCustomEventTypeRpcLoad,
|
||||
InfraredCustomEventTypeRpcExit,
|
||||
InfraredCustomEventTypeRpcButtonPress,
|
||||
InfraredCustomEventTypeRpcButtonRelease,
|
||||
InfraredCustomEventTypeRpcSessionClose,
|
||||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
@@ -115,10 +115,11 @@ typedef enum {
|
||||
InfraredNotificationMessageSuccess,
|
||||
InfraredNotificationMessageGreenOn,
|
||||
InfraredNotificationMessageGreenOff,
|
||||
InfraredNotificationMessageBlinkRead,
|
||||
InfraredNotificationMessageBlinkSend,
|
||||
InfraredNotificationMessageYellowOn,
|
||||
InfraredNotificationMessageYellowOff,
|
||||
InfraredNotificationMessageBlinkStartRead,
|
||||
InfraredNotificationMessageBlinkStartSend,
|
||||
InfraredNotificationMessageBlinkStop,
|
||||
} InfraredNotificationMessage;
|
||||
|
||||
bool infrared_add_remote_with_button(Infrared* infrared, const char* name, InfraredSignal* signal);
|
||||
@@ -132,7 +133,6 @@ void infrared_text_store_clear(Infrared* infrared, uint32_t bank);
|
||||
void infrared_play_notification_message(Infrared* infrared, uint32_t message);
|
||||
void infrared_show_loading_popup(Infrared* infrared, bool show);
|
||||
|
||||
void infrared_signal_sent_callback(void* context);
|
||||
void infrared_signal_received_callback(void* context, InfraredWorkerSignal* received_signal);
|
||||
void infrared_text_input_callback(void* context);
|
||||
void infrared_popup_closed_callback(void* context);
|
||||
|
||||
@@ -21,12 +21,14 @@ static void infrared_scene_universal_common_show_popup(Infrared* infrared, uint3
|
||||
infrared_progress_view_set_back_callback(
|
||||
progress, infrared_scene_universal_common_progress_back_callback, infrared);
|
||||
view_stack_add_view(view_stack, infrared_progress_view_get_view(progress));
|
||||
infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStartSend);
|
||||
}
|
||||
|
||||
static void infrared_scene_universal_common_hide_popup(Infrared* infrared) {
|
||||
ViewStack* view_stack = infrared->view_stack;
|
||||
InfraredProgressView* progress = infrared->progress;
|
||||
view_stack_remove_view(view_stack, infrared_progress_view_get_view(progress));
|
||||
infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStop);
|
||||
}
|
||||
|
||||
void infrared_scene_universal_common_on_enter(void* context) {
|
||||
@@ -42,7 +44,6 @@ bool infrared_scene_universal_common_on_event(void* context, SceneManagerEvent e
|
||||
|
||||
if(infrared_brute_force_is_started(brute_force)) {
|
||||
if(event.type == SceneManagerEventTypeTick) {
|
||||
infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkSend);
|
||||
bool success = infrared_brute_force_send_next(brute_force);
|
||||
if(success) {
|
||||
success = infrared_progress_view_increase_progress(infrared->progress);
|
||||
@@ -71,8 +72,6 @@ bool infrared_scene_universal_common_on_event(void* context, SceneManagerEvent e
|
||||
brute_force, infrared_custom_event_get_value(event.event), &record_count)) {
|
||||
DOLPHIN_DEED(DolphinDeedIrBruteForce);
|
||||
infrared_scene_universal_common_show_popup(infrared, record_count);
|
||||
infrared_play_notification_message(
|
||||
infrared, InfraredNotificationMessageBlinkSend);
|
||||
} else {
|
||||
scene_manager_next_scene(scene_manager, InfraredSceneErrorDatabases);
|
||||
}
|
||||
|
||||
@@ -10,13 +10,13 @@ void infrared_scene_ask_back_on_enter(void* context) {
|
||||
DialogEx* dialog_ex = infrared->dialog_ex;
|
||||
|
||||
if(infrared->app_state.is_learning_new_remote) {
|
||||
dialog_ex_set_header(dialog_ex, "Exit to Infrared menu?", 64, 0, AlignCenter, AlignTop);
|
||||
dialog_ex_set_header(dialog_ex, "Exit to Infrared Menu?", 64, 0, AlignCenter, AlignTop);
|
||||
} else {
|
||||
dialog_ex_set_header(dialog_ex, "Exit to remote menu?", 64, 0, AlignCenter, AlignTop);
|
||||
dialog_ex_set_header(dialog_ex, "Exit to Remote Menu?", 64, 0, AlignCenter, AlignTop);
|
||||
}
|
||||
|
||||
dialog_ex_set_text(
|
||||
dialog_ex, "All unsaved data\nwill be lost.", 64, 31, AlignCenter, AlignCenter);
|
||||
dialog_ex, "All unsaved data\nwill be lost!", 64, 31, AlignCenter, AlignCenter);
|
||||
dialog_ex_set_icon(dialog_ex, 0, 0, NULL);
|
||||
dialog_ex_set_left_button_text(dialog_ex, "Exit");
|
||||
dialog_ex_set_center_button_text(dialog_ex, NULL);
|
||||
|
||||
@@ -9,9 +9,9 @@ void infrared_scene_ask_retry_on_enter(void* context) {
|
||||
Infrared* infrared = context;
|
||||
DialogEx* dialog_ex = infrared->dialog_ex;
|
||||
|
||||
dialog_ex_set_header(dialog_ex, "Return to reading?", 64, 0, AlignCenter, AlignTop);
|
||||
dialog_ex_set_header(dialog_ex, "Return to Reading?", 64, 0, AlignCenter, AlignTop);
|
||||
dialog_ex_set_text(
|
||||
dialog_ex, "All unsaved data\nwill be lost.", 64, 31, AlignCenter, AlignCenter);
|
||||
dialog_ex, "All unsaved data\nwill be lost!", 64, 31, AlignCenter, AlignCenter);
|
||||
dialog_ex_set_icon(dialog_ex, 0, 0, NULL);
|
||||
dialog_ex_set_left_button_text(dialog_ex, "Exit");
|
||||
dialog_ex_set_center_button_text(dialog_ex, NULL);
|
||||
|
||||
@@ -65,4 +65,5 @@ void infrared_scene_debug_on_exit(void* context) {
|
||||
InfraredWorker* worker = infrared->worker;
|
||||
infrared_worker_rx_stop(worker);
|
||||
infrared_worker_rx_enable_blink_on_receiving(worker, false);
|
||||
infrared_worker_rx_set_received_signal_callback(worker, NULL, NULL);
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ void infrared_scene_edit_delete_on_enter(void* context) {
|
||||
int32_t current_button_index = infrared->app_state.current_button_index;
|
||||
furi_assert(current_button_index != InfraredButtonIndexNone);
|
||||
|
||||
dialog_ex_set_header(dialog_ex, "Delete button?", 64, 0, AlignCenter, AlignTop);
|
||||
dialog_ex_set_header(dialog_ex, "Delete Button?", 64, 0, AlignCenter, AlignTop);
|
||||
InfraredRemoteButton* current_button =
|
||||
infrared_remote_get_button(remote, current_button_index);
|
||||
InfraredSignal* signal = infrared_remote_button_get_signal(current_button);
|
||||
@@ -45,7 +45,7 @@ void infrared_scene_edit_delete_on_enter(void* context) {
|
||||
}
|
||||
|
||||
} else if(edit_target == InfraredEditTargetRemote) {
|
||||
dialog_ex_set_header(dialog_ex, "Delete remote?", 64, 0, AlignCenter, AlignTop);
|
||||
dialog_ex_set_header(dialog_ex, "Delete Remote?", 64, 0, AlignCenter, AlignTop);
|
||||
infrared_text_store_set(
|
||||
infrared,
|
||||
0,
|
||||
|
||||
@@ -8,6 +8,7 @@ void infrared_scene_learn_on_enter(void* context) {
|
||||
infrared_worker_rx_set_received_signal_callback(
|
||||
worker, infrared_signal_received_callback, context);
|
||||
infrared_worker_rx_start(worker);
|
||||
infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStartRead);
|
||||
|
||||
popup_set_icon(popup, 0, 32, &I_InfraredLearnShort_128x31);
|
||||
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignCenter);
|
||||
@@ -22,10 +23,7 @@ bool infrared_scene_learn_on_event(void* context, SceneManagerEvent event) {
|
||||
Infrared* infrared = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeTick) {
|
||||
infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkRead);
|
||||
consumed = true;
|
||||
} else if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == InfraredCustomEventTypeSignalReceived) {
|
||||
infrared_worker_rx_set_received_signal_callback(infrared->worker, NULL, NULL);
|
||||
infrared_play_notification_message(infrared, InfraredNotificationMessageSuccess);
|
||||
@@ -41,6 +39,7 @@ void infrared_scene_learn_on_exit(void* context) {
|
||||
Infrared* infrared = context;
|
||||
Popup* popup = infrared->popup;
|
||||
infrared_worker_rx_stop(infrared->worker);
|
||||
infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStop);
|
||||
popup_set_icon(popup, 0, 0, NULL);
|
||||
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignCenter);
|
||||
}
|
||||
|
||||
@@ -23,8 +23,6 @@ void infrared_scene_learn_success_on_enter(void* context) {
|
||||
|
||||
infrared_worker_tx_set_get_signal_callback(
|
||||
infrared->worker, infrared_worker_tx_get_signal_steady_callback, context);
|
||||
infrared_worker_tx_set_signal_sent_callback(
|
||||
infrared->worker, infrared_signal_sent_callback, context);
|
||||
|
||||
if(infrared_signal_is_raw(signal)) {
|
||||
InfraredRawSignal* raw = infrared_signal_get_raw_signal(signal);
|
||||
@@ -104,6 +102,8 @@ bool infrared_scene_learn_success_on_event(void* context, SceneManagerEvent even
|
||||
InfraredSceneLearnSuccess,
|
||||
InfraredSceneLearnSuccessStateSending);
|
||||
infrared_tx_start_received(infrared);
|
||||
infrared_play_notification_message(
|
||||
infrared, InfraredNotificationMessageBlinkStartSend);
|
||||
}
|
||||
consumed = true;
|
||||
} else if(event.event == DialogExReleaseCenter) {
|
||||
@@ -111,6 +111,7 @@ bool infrared_scene_learn_success_on_event(void* context, SceneManagerEvent even
|
||||
scene_manager_set_scene_state(
|
||||
scene_manager, InfraredSceneLearnSuccess, InfraredSceneLearnSuccessStateIdle);
|
||||
infrared_tx_stop(infrared);
|
||||
infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStop);
|
||||
infrared_play_notification_message(infrared, InfraredNotificationMessageGreenOff);
|
||||
}
|
||||
consumed = true;
|
||||
@@ -124,7 +125,7 @@ void infrared_scene_learn_success_on_exit(void* context) {
|
||||
Infrared* infrared = context;
|
||||
InfraredWorker* worker = infrared->worker;
|
||||
dialog_ex_reset(infrared->dialog_ex);
|
||||
infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStop);
|
||||
infrared_play_notification_message(infrared, InfraredNotificationMessageGreenOff);
|
||||
infrared_worker_tx_set_get_signal_callback(worker, NULL, NULL);
|
||||
infrared_worker_tx_set_signal_sent_callback(worker, NULL, NULL);
|
||||
}
|
||||
|
||||
@@ -33,8 +33,6 @@ void infrared_scene_remote_on_enter(void* context) {
|
||||
|
||||
infrared_worker_tx_set_get_signal_callback(
|
||||
infrared->worker, infrared_worker_tx_get_signal_steady_callback, infrared);
|
||||
infrared_worker_tx_set_signal_sent_callback(
|
||||
infrared->worker, infrared_signal_sent_callback, infrared);
|
||||
|
||||
size_t button_count = infrared_remote_get_button_count(remote);
|
||||
for(size_t i = 0; i < button_count; ++i) {
|
||||
@@ -112,7 +110,7 @@ bool infrared_scene_remote_on_event(void* context, SceneManagerEvent event) {
|
||||
|
||||
void infrared_scene_remote_on_exit(void* context) {
|
||||
Infrared* infrared = context;
|
||||
infrared_tx_stop(infrared);
|
||||
infrared_worker_tx_set_get_signal_callback(infrared->worker, NULL, NULL);
|
||||
infrared_worker_tx_set_signal_sent_callback(infrared->worker, NULL, NULL);
|
||||
button_menu_reset(infrared->button_menu);
|
||||
}
|
||||
|
||||
@@ -28,12 +28,43 @@ bool infrared_scene_rpc_on_event(void* context, SceneManagerEvent event) {
|
||||
view_dispatcher_stop(infrared->view_dispatcher);
|
||||
} else if(event.event == InfraredCustomEventTypePopupClosed) {
|
||||
view_dispatcher_stop(infrared->view_dispatcher);
|
||||
} else if(event.event == InfraredCustomEventTypeRpcLoaded) {
|
||||
} else if(event.event == InfraredCustomEventTypeRpcLoad) {
|
||||
bool result = false;
|
||||
const char* arg = rpc_system_app_get_data(infrared->rpc_ctx);
|
||||
if(arg) {
|
||||
string_set_str(infrared->file_path, arg);
|
||||
result = infrared_remote_load(infrared->remote, infrared->file_path);
|
||||
infrared_worker_tx_set_get_signal_callback(
|
||||
infrared->worker, infrared_worker_tx_get_signal_steady_callback, infrared);
|
||||
}
|
||||
const char* remote_name = infrared_remote_get_name(infrared->remote);
|
||||
|
||||
infrared_text_store_set(infrared, 0, "loaded\n%s", remote_name);
|
||||
popup_set_text(
|
||||
infrared->popup, infrared->text_store[0], 82, 32, AlignCenter, AlignTop);
|
||||
|
||||
rpc_system_app_confirm(infrared->rpc_ctx, RpcAppEventLoadFile, result);
|
||||
} else if(event.event == InfraredCustomEventTypeRpcButtonPress) {
|
||||
bool result = false;
|
||||
const char* arg = rpc_system_app_get_data(infrared->rpc_ctx);
|
||||
if(arg) {
|
||||
size_t button_index = 0;
|
||||
if(infrared_remote_find_button_by_name(infrared->remote, arg, &button_index)) {
|
||||
infrared_tx_start_button_index(infrared, button_index);
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
rpc_system_app_confirm(infrared->rpc_ctx, RpcAppEventButtonRelease, result);
|
||||
} else if(event.event == InfraredCustomEventTypeRpcButtonRelease) {
|
||||
infrared_tx_stop(infrared);
|
||||
rpc_system_app_confirm(infrared->rpc_ctx, RpcAppEventButtonRelease, true);
|
||||
} else if(event.event == InfraredCustomEventTypeRpcExit) {
|
||||
view_dispatcher_stop(infrared->view_dispatcher);
|
||||
rpc_system_app_confirm(infrared->rpc_ctx, RpcAppEventAppExit, true);
|
||||
} else if(event.event == InfraredCustomEventTypeRpcSessionClose) {
|
||||
rpc_system_app_set_callback(infrared->rpc_ctx, NULL, NULL);
|
||||
infrared->rpc_ctx = NULL;
|
||||
view_dispatcher_stop(infrared->view_dispatcher);
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
@@ -41,5 +72,6 @@ bool infrared_scene_rpc_on_event(void* context, SceneManagerEvent event) {
|
||||
|
||||
void infrared_scene_rpc_on_exit(void* context) {
|
||||
Infrared* infrared = context;
|
||||
infrared_tx_stop(infrared);
|
||||
popup_reset(infrared->popup);
|
||||
}
|
||||
|
||||
@@ -64,7 +64,8 @@ const char* input_get_type_name(InputType type) {
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
int32_t input_srv() {
|
||||
int32_t input_srv(void* p) {
|
||||
UNUSED(p);
|
||||
input = malloc(sizeof(Input));
|
||||
input->thread_id = furi_thread_get_current_id();
|
||||
input->event_pubsub = furi_pubsub_alloc();
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#include <toolbox/path.h>
|
||||
#include <flipper_format/flipper_format.h>
|
||||
|
||||
#include "rpc/rpc_app.h"
|
||||
#include <rpc/rpc_app.h>
|
||||
|
||||
const char* LfRfidApp::app_folder = ANY_PATH("lfrfid");
|
||||
const char* LfRfidApp::app_extension = ".rfid";
|
||||
@@ -48,38 +48,25 @@ LfRfidApp::~LfRfidApp() {
|
||||
}
|
||||
}
|
||||
|
||||
static bool rpc_command_callback(RpcAppSystemEvent event, const char* arg, void* context) {
|
||||
static void rpc_command_callback(RpcAppSystemEvent rpc_event, void* context) {
|
||||
furi_assert(context);
|
||||
LfRfidApp* app = static_cast<LfRfidApp*>(context);
|
||||
|
||||
bool result = false;
|
||||
|
||||
if(event == RpcAppEventSessionClose) {
|
||||
rpc_system_app_set_callback(app->rpc_ctx, NULL, NULL);
|
||||
app->rpc_ctx = NULL;
|
||||
if(rpc_event == RpcAppEventSessionClose) {
|
||||
LfRfidApp::Event event;
|
||||
event.type = LfRfidApp::EventType::RpcSessionClose;
|
||||
app->view_controller.send_event(&event);
|
||||
} else if(rpc_event == RpcAppEventAppExit) {
|
||||
LfRfidApp::Event event;
|
||||
event.type = LfRfidApp::EventType::Exit;
|
||||
app->view_controller.send_event(&event);
|
||||
result = true;
|
||||
} else if(event == RpcAppEventAppExit) {
|
||||
} else if(rpc_event == RpcAppEventLoadFile) {
|
||||
LfRfidApp::Event event;
|
||||
event.type = LfRfidApp::EventType::Exit;
|
||||
event.type = LfRfidApp::EventType::RpcLoadFile;
|
||||
app->view_controller.send_event(&event);
|
||||
result = true;
|
||||
} else if(event == RpcAppEventLoadFile) {
|
||||
if(arg) {
|
||||
string_set_str(app->file_path, arg);
|
||||
if(app->load_key_data(app->file_path, &(app->worker.key), false)) {
|
||||
LfRfidApp::Event event;
|
||||
event.type = LfRfidApp::EventType::EmulateStart;
|
||||
app->view_controller.send_event(&event);
|
||||
app->worker.start_emulate();
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
rpc_system_app_confirm(app->rpc_ctx, rpc_event, false);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void LfRfidApp::run(void* _args) {
|
||||
@@ -87,7 +74,7 @@ void LfRfidApp::run(void* _args) {
|
||||
|
||||
make_app_folder();
|
||||
|
||||
if(strlen(args)) {
|
||||
if(args && strlen(args)) {
|
||||
uint32_t rpc_ctx_ptr = 0;
|
||||
if(sscanf(args, "RPC %lX", &rpc_ctx_ptr) == 1) {
|
||||
rpc_ctx = (RpcAppSystem*)rpc_ctx_ptr;
|
||||
|
||||
@@ -33,6 +33,8 @@ public:
|
||||
Retry,
|
||||
Exit,
|
||||
EmulateStart,
|
||||
RpcLoadFile,
|
||||
RpcSessionClose,
|
||||
};
|
||||
|
||||
enum class SceneType : uint8_t {
|
||||
|
||||
@@ -107,7 +107,7 @@ static void lfrfid_cli_write(Cli* cli, string_t args) {
|
||||
UNUSED(cli);
|
||||
UNUSED(args);
|
||||
// TODO implement rfid write
|
||||
printf("Not implemented :(\r\n");
|
||||
printf("Not Implemented :(\r\n");
|
||||
}
|
||||
|
||||
static void lfrfid_cli_emulate(Cli* cli, string_t args) {
|
||||
|
||||
@@ -2,18 +2,6 @@
|
||||
#include <core/common_defines.h>
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
static const NotificationSequence sequence_blink_start_magenta = {
|
||||
&message_blink_start_10,
|
||||
&message_blink_set_color_magenta,
|
||||
&message_do_not_reset,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const NotificationSequence sequence_blink_stop = {
|
||||
&message_blink_stop,
|
||||
NULL,
|
||||
};
|
||||
|
||||
void LfRfidAppSceneEmulate::on_enter(LfRfidApp* app, bool /* need_restore */) {
|
||||
string_init(data_string);
|
||||
|
||||
|
||||
@@ -17,9 +17,9 @@ void LfRfidAppSceneExitConfirm::on_enter(LfRfidApp* app, bool /* need_restore */
|
||||
auto line_1 = container->add<StringElement>();
|
||||
auto line_2 = container->add<StringElement>();
|
||||
|
||||
line_1->set_text("Exit to RFID menu?", 64, 19, 128 - 2, AlignCenter, AlignBottom, FontPrimary);
|
||||
line_1->set_text("Exit to RFID Menu?", 64, 19, 128 - 2, AlignCenter, AlignBottom, FontPrimary);
|
||||
line_2->set_text(
|
||||
"All unsaved data will be lost.", 64, 31, 0, AlignCenter, AlignBottom, FontSecondary);
|
||||
"All unsaved data will be lost!", 64, 31, 0, AlignCenter, AlignBottom, FontSecondary);
|
||||
|
||||
app->view_controller.switch_to<ContainerVM>();
|
||||
}
|
||||
|
||||
@@ -17,9 +17,9 @@ void LfRfidAppSceneRetryConfirm::on_enter(LfRfidApp* app, bool /* need_restore *
|
||||
auto line_1 = container->add<StringElement>();
|
||||
auto line_2 = container->add<StringElement>();
|
||||
|
||||
line_1->set_text("Return to reading?", 64, 19, 128 - 2, AlignCenter, AlignBottom, FontPrimary);
|
||||
line_1->set_text("Return to Reading?", 64, 19, 128 - 2, AlignCenter, AlignBottom, FontPrimary);
|
||||
line_2->set_text(
|
||||
"All unsaved data will be lost.", 64, 29, 0, AlignCenter, AlignBottom, FontSecondary);
|
||||
"All unsaved data will be lost!", 64, 29, 0, AlignCenter, AlignBottom, FontSecondary);
|
||||
|
||||
app->view_controller.switch_to<ContainerVM>();
|
||||
}
|
||||
|
||||
@@ -1,18 +1,7 @@
|
||||
#include "lfrfid_app_scene_rpc.h"
|
||||
#include <core/common_defines.h>
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
static const NotificationSequence sequence_blink_start_magenta = {
|
||||
&message_blink_start_10,
|
||||
&message_blink_set_color_magenta,
|
||||
&message_do_not_reset,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const NotificationSequence sequence_blink_stop = {
|
||||
&message_blink_stop,
|
||||
NULL,
|
||||
};
|
||||
#include <rpc/rpc_app.h>
|
||||
|
||||
void LfRfidAppSceneRpc::on_enter(LfRfidApp* app, bool /* need_restore */) {
|
||||
auto popup = app->view_controller.get<PopupVM>();
|
||||
@@ -36,6 +25,16 @@ bool LfRfidAppSceneRpc::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
|
||||
LfRfidApp::Event view_event;
|
||||
view_event.type = LfRfidApp::EventType::Back;
|
||||
app->view_controller.send_event(&view_event);
|
||||
rpc_system_app_confirm(app->rpc_ctx, RpcAppEventAppExit, true);
|
||||
} else if(event->type == LfRfidApp::EventType::RpcSessionClose) {
|
||||
// Detach RPC
|
||||
rpc_system_app_set_callback(app->rpc_ctx, NULL, NULL);
|
||||
app->rpc_ctx = NULL;
|
||||
|
||||
consumed = true;
|
||||
LfRfidApp::Event view_event;
|
||||
view_event.type = LfRfidApp::EventType::Back;
|
||||
app->view_controller.send_event(&view_event);
|
||||
} else if(event->type == LfRfidApp::EventType::EmulateStart) {
|
||||
auto popup = app->view_controller.get<PopupVM>();
|
||||
consumed = true;
|
||||
@@ -45,7 +44,22 @@ bool LfRfidAppSceneRpc::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
|
||||
popup->set_text(app->text_store.text, 89, 43, AlignCenter, AlignTop);
|
||||
|
||||
notification_message(app->notification, &sequence_blink_start_magenta);
|
||||
} else if(event->type == LfRfidApp::EventType::RpcLoadFile) {
|
||||
const char* arg = rpc_system_app_get_data(app->rpc_ctx);
|
||||
bool result = false;
|
||||
if(arg) {
|
||||
string_set_str(app->file_path, arg);
|
||||
if(app->load_key_data(app->file_path, &(app->worker.key), false)) {
|
||||
LfRfidApp::Event event;
|
||||
event.type = LfRfidApp::EventType::EmulateStart;
|
||||
app->view_controller.send_event(&event);
|
||||
app->worker.start_emulate();
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
rpc_system_app_confirm(app->rpc_ctx, RpcAppEventLoadFile, result);
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
|
||||
@@ -300,7 +300,7 @@ int32_t music_player_app(void* p) {
|
||||
string_init(file_path);
|
||||
|
||||
do {
|
||||
if(p) {
|
||||
if(p && strlen(p)) {
|
||||
string_cat_str(file_path, p);
|
||||
} else {
|
||||
string_set_str(file_path, MUSIC_PLAYER_APP_PATH_FOLDER);
|
||||
|
||||
@@ -11,4 +11,5 @@ enum NfcCustomEvent {
|
||||
NfcCustomEventDictAttackDone,
|
||||
NfcCustomEventDictAttackSkip,
|
||||
NfcCustomEventRpcLoad,
|
||||
NfcCustomEventRpcSessionClose,
|
||||
};
|
||||
|
||||
+22
-76
@@ -13,78 +13,21 @@ bool nfc_back_event_callback(void* context) {
|
||||
return scene_manager_handle_back_event(nfc->scene_manager);
|
||||
}
|
||||
|
||||
void nfc_rpc_exit_callback(Nfc* nfc) {
|
||||
if(nfc->rpc_state == NfcRpcStateEmulating) {
|
||||
// Stop worker
|
||||
nfc_worker_stop(nfc->worker);
|
||||
} else if(nfc->rpc_state == NfcRpcStateEmulated) {
|
||||
// Stop worker
|
||||
nfc_worker_stop(nfc->worker);
|
||||
// Save data in shadow file
|
||||
nfc_device_save_shadow(nfc->dev, nfc->dev->dev_name);
|
||||
}
|
||||
if(nfc->rpc_ctx) {
|
||||
rpc_system_app_set_callback(nfc->rpc_ctx, NULL, NULL);
|
||||
rpc_system_app_send_exited(nfc->rpc_ctx);
|
||||
nfc->rpc_ctx = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static bool nfc_rpc_emulate_callback(NfcWorkerEvent event, void* context) {
|
||||
UNUSED(event);
|
||||
Nfc* nfc = context;
|
||||
|
||||
nfc->rpc_state = NfcRpcStateEmulated;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool nfc_rpc_command_callback(RpcAppSystemEvent event, const char* arg, void* context) {
|
||||
static void nfc_rpc_command_callback(RpcAppSystemEvent event, void* context) {
|
||||
furi_assert(context);
|
||||
Nfc* nfc = context;
|
||||
|
||||
if(!nfc->rpc_ctx) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = false;
|
||||
furi_assert(nfc->rpc_ctx);
|
||||
|
||||
if(event == RpcAppEventSessionClose) {
|
||||
rpc_system_app_set_callback(nfc->rpc_ctx, NULL, NULL);
|
||||
nfc->rpc_ctx = NULL;
|
||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit);
|
||||
result = true;
|
||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventRpcSessionClose);
|
||||
} else if(event == RpcAppEventAppExit) {
|
||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit);
|
||||
result = true;
|
||||
} else if(event == RpcAppEventLoadFile) {
|
||||
if((arg) && (nfc->rpc_state == NfcRpcStateIdle)) {
|
||||
if(nfc_device_load(nfc->dev, arg, false)) {
|
||||
if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) {
|
||||
nfc_worker_start(
|
||||
nfc->worker,
|
||||
NfcWorkerStateMfUltralightEmulate,
|
||||
&nfc->dev->dev_data,
|
||||
nfc_rpc_emulate_callback,
|
||||
nfc);
|
||||
} else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) {
|
||||
nfc_worker_start(
|
||||
nfc->worker,
|
||||
NfcWorkerStateMfClassicEmulate,
|
||||
&nfc->dev->dev_data,
|
||||
nfc_rpc_emulate_callback,
|
||||
nfc);
|
||||
} else {
|
||||
nfc_worker_start(
|
||||
nfc->worker, NfcWorkerStateUidEmulate, &nfc->dev->dev_data, NULL, nfc);
|
||||
}
|
||||
nfc->rpc_state = NfcRpcStateEmulating;
|
||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventRpcLoad);
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventRpcLoad);
|
||||
} else {
|
||||
rpc_system_app_confirm(nfc->rpc_ctx, event, false);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Nfc* nfc_alloc() {
|
||||
@@ -163,6 +106,21 @@ Nfc* nfc_alloc() {
|
||||
void nfc_free(Nfc* nfc) {
|
||||
furi_assert(nfc);
|
||||
|
||||
if(nfc->rpc_state == NfcRpcStateEmulating) {
|
||||
// Stop worker
|
||||
nfc_worker_stop(nfc->worker);
|
||||
} else if(nfc->rpc_state == NfcRpcStateEmulated) {
|
||||
// Stop worker
|
||||
nfc_worker_stop(nfc->worker);
|
||||
// Save data in shadow file
|
||||
nfc_device_save_shadow(nfc->dev, nfc->dev->dev_name);
|
||||
}
|
||||
if(nfc->rpc_ctx) {
|
||||
rpc_system_app_send_exited(nfc->rpc_ctx);
|
||||
rpc_system_app_set_callback(nfc->rpc_ctx, NULL, NULL);
|
||||
nfc->rpc_ctx = NULL;
|
||||
}
|
||||
|
||||
// Nfc device
|
||||
nfc_device_free(nfc->dev);
|
||||
|
||||
@@ -241,18 +199,6 @@ void nfc_text_store_clear(Nfc* nfc) {
|
||||
memset(nfc->text_store, 0, sizeof(nfc->text_store));
|
||||
}
|
||||
|
||||
static const NotificationSequence sequence_blink_start_blue = {
|
||||
&message_blink_start_10,
|
||||
&message_blink_set_color_blue,
|
||||
&message_do_not_reset,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const NotificationSequence sequence_blink_stop = {
|
||||
&message_blink_stop,
|
||||
NULL,
|
||||
};
|
||||
|
||||
void nfc_blink_start(Nfc* nfc) {
|
||||
notification_message(nfc->notifications, &sequence_blink_start_blue);
|
||||
}
|
||||
@@ -280,7 +226,7 @@ int32_t nfc_app(void* p) {
|
||||
char* args = p;
|
||||
|
||||
// Check argument and run corresponding scene
|
||||
if((*args != '\0')) {
|
||||
if(args && strlen(args)) {
|
||||
nfc_device_set_loading_callback(nfc->dev, nfc_show_loading_popup, nfc);
|
||||
uint32_t rpc_ctx = 0;
|
||||
if(sscanf(p, "RPC %lX", &rpc_ctx) == 1) {
|
||||
|
||||
@@ -102,5 +102,3 @@ void nfc_blink_start(Nfc* nfc);
|
||||
void nfc_blink_stop(Nfc* nfc);
|
||||
|
||||
void nfc_show_loading_popup(void* context, bool show);
|
||||
|
||||
void nfc_rpc_exit_callback(Nfc* nfc);
|
||||
|
||||
@@ -37,7 +37,7 @@ static void nfc_scene_detect_reader_widget_config(Nfc* nfc, bool data_received)
|
||||
|
||||
widget_add_icon_element(widget, 0, 14, &I_Reader_detect);
|
||||
widget_add_string_element(
|
||||
widget, 64, 3, AlignCenter, AlignTop, FontSecondary, "Hold near reader");
|
||||
widget, 64, 3, AlignCenter, AlignTop, FontSecondary, "Hold Near Reader");
|
||||
widget_add_string_element(widget, 55, 22, AlignLeft, AlignTop, FontPrimary, "Emulating...");
|
||||
|
||||
if(data_received) {
|
||||
|
||||
@@ -12,9 +12,9 @@ void nfc_scene_exit_confirm_on_enter(void* context) {
|
||||
|
||||
dialog_ex_set_left_button_text(dialog_ex, "Exit");
|
||||
dialog_ex_set_right_button_text(dialog_ex, "Stay");
|
||||
dialog_ex_set_header(dialog_ex, "Exit to NFC menu?", 64, 11, AlignCenter, AlignTop);
|
||||
dialog_ex_set_header(dialog_ex, "Exit to NFC Menu?", 64, 11, AlignCenter, AlignTop);
|
||||
dialog_ex_set_text(
|
||||
dialog_ex, "All unsaved data\nwill be lost.", 64, 25, AlignCenter, AlignTop);
|
||||
dialog_ex, "All unsaved data\nwill be lost!", 64, 25, AlignCenter, AlignTop);
|
||||
dialog_ex_set_context(dialog_ex, nfc);
|
||||
dialog_ex_set_result_callback(dialog_ex, nfc_scene_exit_confirm_dialog_callback);
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "../nfc_i.h"
|
||||
|
||||
#define TAG "NfcMfClassicDictAttack"
|
||||
|
||||
typedef enum {
|
||||
DictAttackStateIdle,
|
||||
DictAttackStateUserDictInProgress,
|
||||
@@ -32,7 +34,9 @@ static void nfc_scene_mf_classic_dict_attack_update_view(Nfc* nfc) {
|
||||
|
||||
static void nfc_scene_mf_classic_dict_attack_prepare_view(Nfc* nfc, DictAttackState state) {
|
||||
MfClassicData* data = &nfc->dev->dev_data.mf_classic_data;
|
||||
NfcMfClassicDictAttackData* dict_attack_data = &nfc->dev->dev_data.mf_classic_dict_attack_data;
|
||||
NfcWorkerState worker_state = NfcWorkerStateReady;
|
||||
MfClassicDict* dict = NULL;
|
||||
|
||||
// Identify scene state
|
||||
if(state == DictAttackStateIdle) {
|
||||
@@ -47,16 +51,36 @@ static void nfc_scene_mf_classic_dict_attack_prepare_view(Nfc* nfc, DictAttackSt
|
||||
|
||||
// Setup view
|
||||
if(state == DictAttackStateUserDictInProgress) {
|
||||
worker_state = NfcWorkerStateMfClassicUserDictAttack;
|
||||
worker_state = NfcWorkerStateMfClassicDictAttack;
|
||||
dict_attack_set_header(nfc->dict_attack, "Mf Classic User Dict.");
|
||||
} else if(state == DictAttackStateFlipperDictInProgress) {
|
||||
worker_state = NfcWorkerStateMfClassicFlipperDictAttack;
|
||||
dict_attack_set_header(nfc->dict_attack, "Mf Classic Flipper Dict.");
|
||||
dict = mf_classic_dict_alloc(MfClassicDictTypeUser);
|
||||
|
||||
// If failed to load user dictionary - try flipper dictionary
|
||||
if(!dict) {
|
||||
FURI_LOG_E(TAG, "User dictionary not found");
|
||||
state = DictAttackStateFlipperDictInProgress;
|
||||
}
|
||||
}
|
||||
if(state == DictAttackStateFlipperDictInProgress) {
|
||||
worker_state = NfcWorkerStateMfClassicDictAttack;
|
||||
dict_attack_set_header(nfc->dict_attack, "Mf Classic Flipper Dict.");
|
||||
dict = mf_classic_dict_alloc(MfClassicDictTypeFlipper);
|
||||
if(!dict) {
|
||||
FURI_LOG_E(TAG, "Flipper dictionary not found");
|
||||
// Pass through to let worker handle the failure
|
||||
}
|
||||
}
|
||||
// Free previous dictionary
|
||||
if(dict_attack_data->dict) {
|
||||
mf_classic_dict_free(dict_attack_data->dict);
|
||||
}
|
||||
dict_attack_data->dict = dict;
|
||||
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfClassicDictAttack, state);
|
||||
dict_attack_set_callback(nfc->dict_attack, nfc_dict_attack_dict_attack_result_callback, nfc);
|
||||
dict_attack_set_current_sector(nfc->dict_attack, 0);
|
||||
dict_attack_set_card_detected(nfc->dict_attack, data->type);
|
||||
dict_attack_set_total_dict_keys(
|
||||
nfc->dict_attack, dict ? mf_classic_dict_get_total_keys(dict) : 0);
|
||||
nfc_scene_mf_classic_dict_attack_update_view(nfc);
|
||||
nfc_worker_start(
|
||||
nfc->worker, worker_state, &nfc->dev->dev_data, nfc_dict_attack_worker_callback, nfc);
|
||||
@@ -112,6 +136,10 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent
|
||||
nfc_scene_mf_classic_dict_attack_update_view(nfc);
|
||||
dict_attack_inc_current_sector(nfc->dict_attack);
|
||||
consumed = true;
|
||||
} else if(event.event == NfcWorkerEventNewDictKeyBatch) {
|
||||
nfc_scene_mf_classic_dict_attack_update_view(nfc);
|
||||
dict_attack_inc_current_dict_key(nfc->dict_attack, NFC_DICT_KEY_BATCH_SIZE);
|
||||
consumed = true;
|
||||
} else if(event.event == NfcCustomEventDictAttackSkip) {
|
||||
if(state == DictAttackStateUserDictInProgress) {
|
||||
nfc_worker_stop(nfc->worker);
|
||||
@@ -130,8 +158,13 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent
|
||||
|
||||
void nfc_scene_mf_classic_dict_attack_on_exit(void* context) {
|
||||
Nfc* nfc = context;
|
||||
NfcMfClassicDictAttackData* dict_attack_data = &nfc->dev->dev_data.mf_classic_dict_attack_data;
|
||||
// Stop worker
|
||||
nfc_worker_stop(nfc->worker);
|
||||
if(dict_attack_data->dict) {
|
||||
mf_classic_dict_free(dict_attack_data->dict);
|
||||
dict_attack_data->dict = NULL;
|
||||
}
|
||||
dict_attack_reset(nfc->dict_attack);
|
||||
nfc_blink_stop(nfc);
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ void nfc_scene_restore_original_confirm_on_enter(void* context) {
|
||||
Nfc* nfc = context;
|
||||
DialogEx* dialog_ex = nfc->dialog_ex;
|
||||
|
||||
dialog_ex_set_header(dialog_ex, "Restore card data?", 64, 0, AlignCenter, AlignTop);
|
||||
dialog_ex_set_header(dialog_ex, "Restore Card Data?", 64, 0, AlignCenter, AlignTop);
|
||||
dialog_ex_set_icon(dialog_ex, 5, 15, &I_Restoring);
|
||||
dialog_ex_set_text(
|
||||
dialog_ex, "It will be returned\nto its original state.", 47, 21, AlignLeft, AlignTop);
|
||||
|
||||
@@ -12,9 +12,9 @@ void nfc_scene_retry_confirm_on_enter(void* context) {
|
||||
|
||||
dialog_ex_set_left_button_text(dialog_ex, "Retry");
|
||||
dialog_ex_set_right_button_text(dialog_ex, "Stay");
|
||||
dialog_ex_set_header(dialog_ex, "Retry reading?", 64, 11, AlignCenter, AlignTop);
|
||||
dialog_ex_set_header(dialog_ex, "Retry Reading?", 64, 11, AlignCenter, AlignTop);
|
||||
dialog_ex_set_text(
|
||||
dialog_ex, "All unsaved data will be\nlost.", 64, 25, AlignCenter, AlignTop);
|
||||
dialog_ex, "All unsaved data will be\nlost!", 64, 25, AlignCenter, AlignTop);
|
||||
dialog_ex_set_context(dialog_ex, nfc);
|
||||
dialog_ex_set_result_callback(dialog_ex, nfc_scene_retry_confirm_dialog_callback);
|
||||
|
||||
|
||||
@@ -14,6 +14,14 @@ void nfc_scene_rpc_on_enter(void* context) {
|
||||
notification_message(nfc->notifications, &sequence_display_backlight_on);
|
||||
}
|
||||
|
||||
static bool nfc_scene_rpc_emulate_callback(NfcWorkerEvent event, void* context) {
|
||||
UNUSED(event);
|
||||
Nfc* nfc = context;
|
||||
|
||||
nfc->rpc_state = NfcRpcStateEmulated;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool nfc_scene_rpc_on_event(void* context, SceneManagerEvent event) {
|
||||
Nfc* nfc = context;
|
||||
Popup* popup = nfc->popup;
|
||||
@@ -22,13 +30,47 @@ bool nfc_scene_rpc_on_event(void* context, SceneManagerEvent event) {
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
consumed = true;
|
||||
if(event.event == NfcCustomEventViewExit) {
|
||||
rpc_system_app_confirm(nfc->rpc_ctx, RpcAppEventAppExit, true);
|
||||
view_dispatcher_stop(nfc->view_dispatcher);
|
||||
nfc_blink_stop(nfc);
|
||||
} else if(event.event == NfcCustomEventRpcSessionClose) {
|
||||
rpc_system_app_set_callback(nfc->rpc_ctx, NULL, NULL);
|
||||
nfc->rpc_ctx = NULL;
|
||||
view_dispatcher_stop(nfc->view_dispatcher);
|
||||
nfc_blink_stop(nfc);
|
||||
} else if(event.event == NfcCustomEventRpcLoad) {
|
||||
nfc_blink_start(nfc);
|
||||
bool result = false;
|
||||
const char* arg = rpc_system_app_get_data(nfc->rpc_ctx);
|
||||
if((arg) && (nfc->rpc_state == NfcRpcStateIdle)) {
|
||||
if(nfc_device_load(nfc->dev, arg, false)) {
|
||||
if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) {
|
||||
nfc_worker_start(
|
||||
nfc->worker,
|
||||
NfcWorkerStateMfUltralightEmulate,
|
||||
&nfc->dev->dev_data,
|
||||
nfc_scene_rpc_emulate_callback,
|
||||
nfc);
|
||||
} else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) {
|
||||
nfc_worker_start(
|
||||
nfc->worker,
|
||||
NfcWorkerStateMfClassicEmulate,
|
||||
&nfc->dev->dev_data,
|
||||
nfc_scene_rpc_emulate_callback,
|
||||
nfc);
|
||||
} else {
|
||||
nfc_worker_start(
|
||||
nfc->worker, NfcWorkerStateUidEmulate, &nfc->dev->dev_data, NULL, nfc);
|
||||
}
|
||||
nfc->rpc_state = NfcRpcStateEmulating;
|
||||
result = true;
|
||||
|
||||
nfc_text_store_set(nfc, "emulating\n%s", nfc->dev->dev_name);
|
||||
popup_set_text(popup, nfc->text_store, 82, 32, AlignCenter, AlignTop);
|
||||
nfc_blink_start(nfc);
|
||||
nfc_text_store_set(nfc, "emulating\n%s", nfc->dev->dev_name);
|
||||
popup_set_text(popup, nfc->text_store, 82, 32, AlignCenter, AlignTop);
|
||||
}
|
||||
}
|
||||
|
||||
rpc_system_app_confirm(nfc->rpc_ctx, RpcAppEventLoadFile, result);
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
@@ -38,7 +80,6 @@ void nfc_scene_rpc_on_exit(void* context) {
|
||||
Nfc* nfc = context;
|
||||
Popup* popup = nfc->popup;
|
||||
|
||||
nfc_rpc_exit_callback(nfc);
|
||||
nfc_blink_stop(nfc);
|
||||
|
||||
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
enum SubmenuIndex {
|
||||
SubmenuIndexEmulate,
|
||||
SubmenuIndexEditUid,
|
||||
SubmenuIndexRename,
|
||||
SubmenuIndexDelete,
|
||||
SubmenuIndexInfo,
|
||||
@@ -27,6 +28,14 @@ void nfc_scene_saved_menu_on_enter(void* context) {
|
||||
SubmenuIndexEmulate,
|
||||
nfc_scene_saved_menu_submenu_callback,
|
||||
nfc);
|
||||
if(nfc->dev->dev_data.protocol == NfcDeviceProtocolUnknown) {
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Edit UID",
|
||||
SubmenuIndexEditUid,
|
||||
nfc_scene_saved_menu_submenu_callback,
|
||||
nfc);
|
||||
}
|
||||
} else if(
|
||||
nfc->dev->format == NfcDeviceSaveFormatMifareUl ||
|
||||
nfc->dev->format == NfcDeviceSaveFormatMifareClassic) {
|
||||
@@ -71,6 +80,9 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) {
|
||||
} else if(event.event == SubmenuIndexRename) {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
|
||||
consumed = true;
|
||||
} else if(event.event == SubmenuIndexEditUid) {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneSetUid);
|
||||
consumed = true;
|
||||
} else if(event.event == SubmenuIndexDelete) {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneDelete);
|
||||
consumed = true;
|
||||
|
||||
@@ -31,8 +31,16 @@ bool nfc_scene_set_uid_on_event(void* context, SceneManagerEvent event) {
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == NfcCustomEventByteInputDone) {
|
||||
DOLPHIN_DEED(DolphinDeedNfcAdd);
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
|
||||
consumed = true;
|
||||
if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSavedMenu)) {
|
||||
nfc->dev->dev_data.nfc_data = nfc->dev_edit_data;
|
||||
if(nfc_device_save(nfc->dev, nfc->dev->dev_name)) {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess);
|
||||
consumed = true;
|
||||
}
|
||||
} else {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
|
||||
@@ -23,6 +23,8 @@ typedef struct {
|
||||
uint8_t sector_current;
|
||||
uint8_t keys_total;
|
||||
uint8_t keys_found;
|
||||
uint16_t dict_keys_total;
|
||||
uint16_t dict_keys_current;
|
||||
} DictAttackViewModel;
|
||||
|
||||
static void dict_attack_draw_callback(Canvas* canvas, void* model) {
|
||||
@@ -38,8 +40,15 @@ static void dict_attack_draw_callback(Canvas* canvas, void* model) {
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(canvas, 64, 2, AlignCenter, AlignTop, string_get_cstr(m->header));
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
float progress =
|
||||
m->sectors_total == 0 ? 0 : (float)(m->sector_current) / (float)(m->sectors_total);
|
||||
float dict_progress = m->dict_keys_total == 0 ?
|
||||
0 :
|
||||
(float)(m->dict_keys_current) / (float)(m->dict_keys_total);
|
||||
float progress = m->sectors_total == 0 ? 0 :
|
||||
((float)(m->sector_current) + dict_progress) /
|
||||
(float)(m->sectors_total);
|
||||
if(progress > 1.0) {
|
||||
progress = 1.0;
|
||||
}
|
||||
elements_progress_bar(canvas, 5, 15, 120, progress);
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
snprintf(draw_str, sizeof(draw_str), "Keys found: %d/%d", m->keys_found, m->keys_total);
|
||||
@@ -100,6 +109,8 @@ void dict_attack_reset(DictAttack* dict_attack) {
|
||||
model->sector_current = 0;
|
||||
model->keys_total = 0;
|
||||
model->keys_found = 0;
|
||||
model->dict_keys_total = 0;
|
||||
model->dict_keys_current = 0;
|
||||
string_reset(model->header);
|
||||
return false;
|
||||
});
|
||||
@@ -171,6 +182,7 @@ void dict_attack_set_current_sector(DictAttack* dict_attack, uint8_t curr_sec) {
|
||||
with_view_model(
|
||||
dict_attack->view, (DictAttackViewModel * model) {
|
||||
model->sector_current = curr_sec;
|
||||
model->dict_keys_current = 0;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
@@ -181,6 +193,7 @@ void dict_attack_inc_current_sector(DictAttack* dict_attack) {
|
||||
dict_attack->view, (DictAttackViewModel * model) {
|
||||
if(model->sector_current < model->sectors_total) {
|
||||
model->sector_current++;
|
||||
model->dict_keys_current = 0;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
@@ -196,3 +209,23 @@ void dict_attack_inc_keys_found(DictAttack* dict_attack) {
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void dict_attack_set_total_dict_keys(DictAttack* dict_attack, uint16_t dict_keys_total) {
|
||||
furi_assert(dict_attack);
|
||||
with_view_model(
|
||||
dict_attack->view, (DictAttackViewModel * model) {
|
||||
model->dict_keys_total = dict_keys_total;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void dict_attack_inc_current_dict_key(DictAttack* dict_attack, uint16_t keys_tried) {
|
||||
furi_assert(dict_attack);
|
||||
with_view_model(
|
||||
dict_attack->view, (DictAttackViewModel * model) {
|
||||
if(model->dict_keys_current + keys_tried < model->dict_keys_total) {
|
||||
model->dict_keys_current += keys_tried;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -34,3 +34,7 @@ void dict_attack_set_current_sector(DictAttack* dict_attack, uint8_t curr_sec);
|
||||
void dict_attack_inc_current_sector(DictAttack* dict_attack);
|
||||
|
||||
void dict_attack_inc_keys_found(DictAttack* dict_attack);
|
||||
|
||||
void dict_attack_set_total_dict_keys(DictAttack* dict_attack, uint16_t dict_keys_total);
|
||||
|
||||
void dict_attack_inc_current_dict_key(DictAttack* dict_attack, uint16_t keys_tried);
|
||||
|
||||
@@ -431,6 +431,54 @@ const NotificationSequence sequence_blink_white_100 = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
// Hardware blink
|
||||
const NotificationSequence sequence_blink_start_blue = {
|
||||
&message_blink_start_10,
|
||||
&message_blink_set_color_blue,
|
||||
&message_do_not_reset,
|
||||
NULL,
|
||||
};
|
||||
|
||||
const NotificationSequence sequence_blink_start_red = {
|
||||
&message_blink_start_10,
|
||||
&message_blink_set_color_red,
|
||||
&message_do_not_reset,
|
||||
NULL,
|
||||
};
|
||||
|
||||
const NotificationSequence sequence_blink_start_green = {
|
||||
&message_blink_start_10,
|
||||
&message_blink_set_color_green,
|
||||
&message_do_not_reset,
|
||||
NULL,
|
||||
};
|
||||
|
||||
const NotificationSequence sequence_blink_start_yellow = {
|
||||
&message_blink_start_10,
|
||||
&message_blink_set_color_yellow,
|
||||
&message_do_not_reset,
|
||||
NULL,
|
||||
};
|
||||
|
||||
const NotificationSequence sequence_blink_start_cyan = {
|
||||
&message_blink_start_10,
|
||||
&message_blink_set_color_cyan,
|
||||
&message_do_not_reset,
|
||||
NULL,
|
||||
};
|
||||
|
||||
const NotificationSequence sequence_blink_start_magenta = {
|
||||
&message_blink_start_10,
|
||||
&message_blink_set_color_magenta,
|
||||
&message_do_not_reset,
|
||||
NULL,
|
||||
};
|
||||
|
||||
const NotificationSequence sequence_blink_stop = {
|
||||
&message_blink_stop,
|
||||
NULL,
|
||||
};
|
||||
|
||||
//General
|
||||
const NotificationSequence sequence_single_vibro = {
|
||||
&message_vibro_on,
|
||||
|
||||
@@ -122,6 +122,15 @@ extern const NotificationSequence sequence_blink_cyan_100;
|
||||
extern const NotificationSequence sequence_blink_magenta_100;
|
||||
extern const NotificationSequence sequence_blink_white_100;
|
||||
|
||||
// Hardware blink
|
||||
extern const NotificationSequence sequence_blink_start_blue;
|
||||
extern const NotificationSequence sequence_blink_start_red;
|
||||
extern const NotificationSequence sequence_blink_start_green;
|
||||
extern const NotificationSequence sequence_blink_start_yellow;
|
||||
extern const NotificationSequence sequence_blink_start_cyan;
|
||||
extern const NotificationSequence sequence_blink_start_magenta;
|
||||
extern const NotificationSequence sequence_blink_stop;
|
||||
|
||||
// General
|
||||
extern const NotificationSequence sequence_single_vibro;
|
||||
extern const NotificationSequence sequence_double_vibro;
|
||||
|
||||
@@ -13,7 +13,7 @@ void picopass_scene_read_card_on_enter(void* context) {
|
||||
|
||||
// Setup view
|
||||
Popup* popup = picopass->popup;
|
||||
popup_set_header(popup, "Detecting\npicopass card", 70, 34, AlignLeft, AlignTop);
|
||||
popup_set_header(popup, "Detecting\npicopass\ncard", 68, 30, AlignLeft, AlignTop);
|
||||
popup_set_icon(popup, 0, 3, &I_RFIDDolphinReceive_97x61);
|
||||
|
||||
// Start worker
|
||||
|
||||
@@ -57,7 +57,7 @@ BatteryTestApp* battery_test_alloc() {
|
||||
battery_info_get_view(app->batery_info));
|
||||
|
||||
app->dialog = dialog_ex_alloc();
|
||||
dialog_ex_set_header(app->dialog, "Close battery test?", 64, 12, AlignCenter, AlignTop);
|
||||
dialog_ex_set_header(app->dialog, "Close Battery Test?", 64, 12, AlignCenter, AlignTop);
|
||||
dialog_ex_set_left_button_text(app->dialog, "Exit");
|
||||
dialog_ex_set_right_button_text(app->dialog, "Stay");
|
||||
dialog_ex_set_result_callback(app->dialog, battery_test_dialog_callback);
|
||||
|
||||
@@ -200,7 +200,7 @@ static void power_check_battery_level_change(Power* power) {
|
||||
}
|
||||
|
||||
int32_t power_srv(void* p) {
|
||||
(void)p;
|
||||
UNUSED(p);
|
||||
Power* power = power_alloc();
|
||||
power_update_info(power);
|
||||
furi_record_create(RECORD_POWER, power);
|
||||
|
||||
@@ -76,7 +76,7 @@ void power_settings_app_free(PowerSettingsApp* app) {
|
||||
|
||||
int32_t power_settings_app(void* p) {
|
||||
uint32_t first_scene = PowerSettingsAppSceneStart;
|
||||
if(p && !strcmp(p, "off")) {
|
||||
if(p && strlen(p) && !strcmp(p, "off")) {
|
||||
first_scene = PowerSettingsAppScenePowerOff;
|
||||
}
|
||||
PowerSettingsApp* app = power_settings_app_alloc(first_scene);
|
||||
|
||||
@@ -10,7 +10,7 @@ void power_settings_scene_power_off_on_enter(void* context) {
|
||||
PowerSettingsApp* app = context;
|
||||
DialogEx* dialog = app->dialog;
|
||||
|
||||
dialog_ex_set_header(dialog, "Turn off Device?", 64, 2, AlignCenter, AlignTop);
|
||||
dialog_ex_set_header(dialog, "Turn Off Device?", 64, 2, AlignCenter, AlignTop);
|
||||
dialog_ex_set_text(
|
||||
dialog, " I will be\nwaiting for\n you here...", 78, 16, AlignLeft, AlignTop);
|
||||
dialog_ex_set_icon(dialog, 21, 13, &I_Cry_dolph_55x52);
|
||||
|
||||
+94
-53
@@ -6,24 +6,18 @@
|
||||
#include "rpc_app.h"
|
||||
|
||||
#define TAG "RpcSystemApp"
|
||||
#define APP_BUTTON_TIMEOUT 1000
|
||||
|
||||
struct RpcAppSystem {
|
||||
RpcSession* session;
|
||||
RpcAppSystemCallback app_callback;
|
||||
void* app_context;
|
||||
PB_Main* state_msg;
|
||||
FuriTimer* timer;
|
||||
|
||||
uint32_t last_id;
|
||||
char* last_data;
|
||||
};
|
||||
|
||||
static void rpc_system_app_timer_callback(void* context) {
|
||||
furi_assert(context);
|
||||
RpcAppSystem* rpc_app = context;
|
||||
|
||||
if(rpc_app->app_callback) {
|
||||
rpc_app->app_callback(RpcAppEventButtonRelease, NULL, rpc_app->app_context);
|
||||
}
|
||||
}
|
||||
#define RPC_SYSTEM_APP_TEMP_ARGS_SIZE 16
|
||||
|
||||
static void rpc_system_app_start_process(const PB_Main* request, void* context) {
|
||||
furi_assert(request);
|
||||
@@ -33,9 +27,12 @@ static void rpc_system_app_start_process(const PB_Main* request, void* context)
|
||||
RpcAppSystem* rpc_app = context;
|
||||
RpcSession* session = rpc_app->session;
|
||||
furi_assert(session);
|
||||
char args_temp[16];
|
||||
char args_temp[RPC_SYSTEM_APP_TEMP_ARGS_SIZE];
|
||||
|
||||
FURI_LOG_D(TAG, "Start");
|
||||
furi_assert(!rpc_app->last_id);
|
||||
furi_assert(!rpc_app->last_data);
|
||||
|
||||
FURI_LOG_D(TAG, "StartProcess: id %d", request->command_id);
|
||||
|
||||
PB_CommandStatus result = PB_CommandStatus_ERROR_APP_CANT_START;
|
||||
|
||||
@@ -43,9 +40,9 @@ static void rpc_system_app_start_process(const PB_Main* request, void* context)
|
||||
const char* app_name = request->content.app_start_request.name;
|
||||
if(app_name) {
|
||||
const char* app_args = request->content.app_start_request.args;
|
||||
if(strcmp(app_args, "RPC") == 0) {
|
||||
if(app_args && strcmp(app_args, "RPC") == 0) {
|
||||
// If app is being started in RPC mode - pass RPC context via args string
|
||||
snprintf(args_temp, 16, "RPC %08lX", (uint32_t)rpc_app);
|
||||
snprintf(args_temp, RPC_SYSTEM_APP_TEMP_ARGS_SIZE, "RPC %08lX", (uint32_t)rpc_app);
|
||||
app_args = args_temp;
|
||||
}
|
||||
LoaderStatus status = loader_start(loader, app_name, app_args);
|
||||
@@ -58,7 +55,7 @@ static void rpc_system_app_start_process(const PB_Main* request, void* context)
|
||||
} else if(status == LoaderStatusOk) {
|
||||
result = PB_CommandStatus_OK;
|
||||
} else {
|
||||
furi_assert(0);
|
||||
furi_crash("Programming Error");
|
||||
}
|
||||
} else {
|
||||
result = PB_CommandStatus_ERROR_INVALID_PARAMETERS;
|
||||
@@ -66,6 +63,7 @@ static void rpc_system_app_start_process(const PB_Main* request, void* context)
|
||||
|
||||
furi_record_close(RECORD_LOADER);
|
||||
|
||||
FURI_LOG_D(TAG, "StartProcess: response id %d, result %d", request->command_id, result);
|
||||
rpc_send_and_release_empty(session, request->command_id, result);
|
||||
}
|
||||
|
||||
@@ -93,6 +91,7 @@ static void rpc_system_app_lock_status_process(const PB_Main* request, void* con
|
||||
|
||||
furi_record_close(RECORD_LOADER);
|
||||
|
||||
FURI_LOG_D(TAG, "LockStatus: response");
|
||||
rpc_send_and_release(session, &response);
|
||||
pb_release(&PB_Main_msg, &response);
|
||||
}
|
||||
@@ -109,17 +108,17 @@ static void rpc_system_app_exit_request(const PB_Main* request, void* context) {
|
||||
PB_CommandStatus status;
|
||||
|
||||
if(rpc_app->app_callback) {
|
||||
if(rpc_app->app_callback(RpcAppEventAppExit, NULL, rpc_app->app_context)) {
|
||||
status = PB_CommandStatus_OK;
|
||||
furi_timer_stop(rpc_app->timer);
|
||||
} else {
|
||||
status = PB_CommandStatus_ERROR_APP_CMD_ERROR;
|
||||
}
|
||||
FURI_LOG_D(TAG, "ExitRequest: id %d", request->command_id);
|
||||
furi_assert(!rpc_app->last_id);
|
||||
furi_assert(!rpc_app->last_data);
|
||||
rpc_app->last_id = request->command_id;
|
||||
rpc_app->app_callback(RpcAppEventAppExit, rpc_app->app_context);
|
||||
} else {
|
||||
status = PB_CommandStatus_ERROR_APP_NOT_RUNNING;
|
||||
FURI_LOG_E(
|
||||
TAG, "ExitRequest: APP_NOT_RUNNING, id %d, status: %d", request->command_id, status);
|
||||
rpc_send_and_release_empty(session, request->command_id, status);
|
||||
}
|
||||
|
||||
rpc_send_and_release_empty(session, request->command_id, status);
|
||||
}
|
||||
|
||||
static void rpc_system_app_load_file(const PB_Main* request, void* context) {
|
||||
@@ -133,17 +132,18 @@ static void rpc_system_app_load_file(const PB_Main* request, void* context) {
|
||||
|
||||
PB_CommandStatus status;
|
||||
if(rpc_app->app_callback) {
|
||||
const char* file_path = request->content.app_load_file_request.path;
|
||||
if(rpc_app->app_callback(RpcAppEventLoadFile, file_path, rpc_app->app_context)) {
|
||||
status = PB_CommandStatus_OK;
|
||||
} else {
|
||||
status = PB_CommandStatus_ERROR_APP_CMD_ERROR;
|
||||
}
|
||||
FURI_LOG_D(TAG, "LoadFile: id %d", request->command_id);
|
||||
furi_assert(!rpc_app->last_id);
|
||||
furi_assert(!rpc_app->last_data);
|
||||
rpc_app->last_id = request->command_id;
|
||||
rpc_app->last_data = strdup(request->content.app_load_file_request.path);
|
||||
rpc_app->app_callback(RpcAppEventLoadFile, rpc_app->app_context);
|
||||
} else {
|
||||
status = PB_CommandStatus_ERROR_APP_NOT_RUNNING;
|
||||
FURI_LOG_E(
|
||||
TAG, "LoadFile: APP_NOT_RUNNING, id %d, status: %d", request->command_id, status);
|
||||
rpc_send_and_release_empty(session, request->command_id, status);
|
||||
}
|
||||
|
||||
rpc_send_and_release_empty(session, request->command_id, status);
|
||||
}
|
||||
|
||||
static void rpc_system_app_button_press(const PB_Main* request, void* context) {
|
||||
@@ -157,18 +157,18 @@ static void rpc_system_app_button_press(const PB_Main* request, void* context) {
|
||||
|
||||
PB_CommandStatus status;
|
||||
if(rpc_app->app_callback) {
|
||||
const char* args = request->content.app_button_press_request.args;
|
||||
if(rpc_app->app_callback(RpcAppEventButtonPress, args, rpc_app->app_context)) {
|
||||
status = PB_CommandStatus_OK;
|
||||
furi_timer_start(rpc_app->timer, APP_BUTTON_TIMEOUT);
|
||||
} else {
|
||||
status = PB_CommandStatus_ERROR_APP_CMD_ERROR;
|
||||
}
|
||||
FURI_LOG_D(TAG, "ButtonPress");
|
||||
furi_assert(!rpc_app->last_id);
|
||||
furi_assert(!rpc_app->last_data);
|
||||
rpc_app->last_id = request->command_id;
|
||||
rpc_app->last_data = strdup(request->content.app_button_press_request.args);
|
||||
rpc_app->app_callback(RpcAppEventButtonPress, rpc_app->app_context);
|
||||
} else {
|
||||
status = PB_CommandStatus_ERROR_APP_NOT_RUNNING;
|
||||
FURI_LOG_E(
|
||||
TAG, "ButtonPress: APP_NOT_RUNNING, id %d, status: %d", request->command_id, status);
|
||||
rpc_send_and_release_empty(session, request->command_id, status);
|
||||
}
|
||||
|
||||
rpc_send_and_release_empty(session, request->command_id, status);
|
||||
}
|
||||
|
||||
static void rpc_system_app_button_release(const PB_Main* request, void* context) {
|
||||
@@ -182,17 +182,17 @@ static void rpc_system_app_button_release(const PB_Main* request, void* context)
|
||||
|
||||
PB_CommandStatus status;
|
||||
if(rpc_app->app_callback) {
|
||||
if(rpc_app->app_callback(RpcAppEventButtonRelease, NULL, rpc_app->app_context)) {
|
||||
status = PB_CommandStatus_OK;
|
||||
furi_timer_stop(rpc_app->timer);
|
||||
} else {
|
||||
status = PB_CommandStatus_ERROR_APP_CMD_ERROR;
|
||||
}
|
||||
FURI_LOG_D(TAG, "ButtonRelease");
|
||||
furi_assert(!rpc_app->last_id);
|
||||
furi_assert(!rpc_app->last_data);
|
||||
rpc_app->last_id = request->command_id;
|
||||
rpc_app->app_callback(RpcAppEventButtonRelease, rpc_app->app_context);
|
||||
} else {
|
||||
status = PB_CommandStatus_ERROR_APP_NOT_RUNNING;
|
||||
FURI_LOG_E(
|
||||
TAG, "ButtonRelease: APP_NOT_RUNNING, id %d, status: %d", request->command_id, status);
|
||||
rpc_send_and_release_empty(session, request->command_id, status);
|
||||
}
|
||||
|
||||
rpc_send_and_release_empty(session, request->command_id, status);
|
||||
}
|
||||
|
||||
void rpc_system_app_send_started(RpcAppSystem* rpc_app) {
|
||||
@@ -201,6 +201,8 @@ void rpc_system_app_send_started(RpcAppSystem* rpc_app) {
|
||||
furi_assert(session);
|
||||
|
||||
rpc_app->state_msg->content.app_state_response.state = PB_App_AppState_APP_STARTED;
|
||||
|
||||
FURI_LOG_D(TAG, "SendStarted");
|
||||
rpc_send(session, rpc_app->state_msg);
|
||||
}
|
||||
|
||||
@@ -210,9 +212,46 @@ void rpc_system_app_send_exited(RpcAppSystem* rpc_app) {
|
||||
furi_assert(session);
|
||||
|
||||
rpc_app->state_msg->content.app_state_response.state = PB_App_AppState_APP_CLOSED;
|
||||
|
||||
FURI_LOG_D(TAG, "SendExit");
|
||||
rpc_send(session, rpc_app->state_msg);
|
||||
}
|
||||
|
||||
const char* rpc_system_app_get_data(RpcAppSystem* rpc_app) {
|
||||
furi_assert(rpc_app);
|
||||
furi_assert(rpc_app->last_data);
|
||||
return rpc_app->last_data;
|
||||
}
|
||||
|
||||
void rpc_system_app_confirm(RpcAppSystem* rpc_app, RpcAppSystemEvent event, bool result) {
|
||||
furi_assert(rpc_app);
|
||||
RpcSession* session = rpc_app->session;
|
||||
furi_assert(session);
|
||||
furi_assert(rpc_app->last_id);
|
||||
|
||||
PB_CommandStatus status = result ? PB_CommandStatus_OK : PB_CommandStatus_ERROR_APP_CMD_ERROR;
|
||||
|
||||
uint32_t last_id = 0;
|
||||
switch(event) {
|
||||
case RpcAppEventAppExit:
|
||||
case RpcAppEventLoadFile:
|
||||
case RpcAppEventButtonPress:
|
||||
case RpcAppEventButtonRelease:
|
||||
last_id = rpc_app->last_id;
|
||||
rpc_app->last_id = 0;
|
||||
if(rpc_app->last_data) {
|
||||
free(rpc_app->last_data);
|
||||
rpc_app->last_data = NULL;
|
||||
}
|
||||
FURI_LOG_D(TAG, "AppConfirm: event %d last_id %d status %d", event, last_id, status);
|
||||
rpc_send_and_release_empty(session, last_id, status);
|
||||
break;
|
||||
default:
|
||||
furi_crash("RPC App state programming Error");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void rpc_system_app_set_callback(RpcAppSystem* rpc_app, RpcAppSystemCallback callback, void* ctx) {
|
||||
furi_assert(rpc_app);
|
||||
|
||||
@@ -226,8 +265,6 @@ void* rpc_system_app_alloc(RpcSession* session) {
|
||||
RpcAppSystem* rpc_app = malloc(sizeof(RpcAppSystem));
|
||||
rpc_app->session = session;
|
||||
|
||||
rpc_app->timer = furi_timer_alloc(rpc_system_app_timer_callback, FuriTimerTypeOnce, rpc_app);
|
||||
|
||||
// App exit message
|
||||
rpc_app->state_msg = malloc(sizeof(PB_Main));
|
||||
rpc_app->state_msg->which_content = PB_Main_app_state_response_tag;
|
||||
@@ -265,12 +302,16 @@ void rpc_system_app_free(void* context) {
|
||||
RpcSession* session = rpc_app->session;
|
||||
furi_assert(session);
|
||||
|
||||
furi_timer_free(rpc_app->timer);
|
||||
|
||||
if(rpc_app->app_callback) {
|
||||
rpc_app->app_callback(RpcAppEventSessionClose, NULL, rpc_app->app_context);
|
||||
rpc_app->app_callback(RpcAppEventSessionClose, rpc_app->app_context);
|
||||
}
|
||||
|
||||
while(rpc_app->app_callback) {
|
||||
furi_delay_tick(1);
|
||||
}
|
||||
|
||||
if(rpc_app->last_data) free(rpc_app->last_data);
|
||||
|
||||
free(rpc_app->state_msg);
|
||||
free(rpc_app);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ typedef enum {
|
||||
RpcAppEventButtonRelease,
|
||||
} RpcAppSystemEvent;
|
||||
|
||||
typedef bool (*RpcAppSystemCallback)(RpcAppSystemEvent event, const char* arg, void* context);
|
||||
typedef void (*RpcAppSystemCallback)(RpcAppSystemEvent event, void* context);
|
||||
|
||||
typedef struct RpcAppSystem RpcAppSystem;
|
||||
|
||||
@@ -23,6 +23,10 @@ void rpc_system_app_send_started(RpcAppSystem* rpc_app);
|
||||
|
||||
void rpc_system_app_send_exited(RpcAppSystem* rpc_app);
|
||||
|
||||
const char* rpc_system_app_get_data(RpcAppSystem* rpc_app);
|
||||
|
||||
void rpc_system_app_confirm(RpcAppSystem* rpc_app, RpcAppSystemEvent event, bool result);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -541,7 +541,7 @@ static void rpc_system_storage_md5sum_process(const PB_Main* request, void* cont
|
||||
(void)md5sum_size;
|
||||
furi_assert(hash_size <= ((md5sum_size - 1) / 2));
|
||||
for(uint8_t i = 0; i < hash_size; i++) {
|
||||
md5sum += sprintf(md5sum, "%02x", hash[i]);
|
||||
md5sum += snprintf(md5sum, md5sum_size, "%02x", hash[i]);
|
||||
}
|
||||
|
||||
free(hash);
|
||||
@@ -594,23 +594,19 @@ static void rpc_system_storage_backup_create_process(const PB_Main* request, voi
|
||||
|
||||
FURI_LOG_D(TAG, "BackupCreate");
|
||||
|
||||
RpcSession* session = (RpcSession*)context;
|
||||
RpcStorageSystem* rpc_storage = context;
|
||||
RpcSession* session = rpc_storage->session;
|
||||
furi_assert(session);
|
||||
|
||||
PB_Main* response = malloc(sizeof(PB_Main));
|
||||
response->command_id = request->command_id;
|
||||
response->has_next = false;
|
||||
|
||||
Storage* fs_api = furi_record_open(RECORD_STORAGE);
|
||||
|
||||
bool backup_ok =
|
||||
lfs_backup_create(fs_api, request->content.storage_backup_create_request.archive_path);
|
||||
response->command_status = backup_ok ? PB_CommandStatus_OK : PB_CommandStatus_ERROR;
|
||||
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
|
||||
rpc_send_and_release(session, response);
|
||||
free(response);
|
||||
rpc_send_and_release_empty(
|
||||
session, request->command_id, backup_ok ? PB_CommandStatus_OK : PB_CommandStatus_ERROR);
|
||||
}
|
||||
|
||||
static void rpc_system_storage_backup_restore_process(const PB_Main* request, void* context) {
|
||||
@@ -619,24 +615,19 @@ static void rpc_system_storage_backup_restore_process(const PB_Main* request, vo
|
||||
|
||||
FURI_LOG_D(TAG, "BackupRestore");
|
||||
|
||||
RpcSession* session = (RpcSession*)context;
|
||||
RpcStorageSystem* rpc_storage = context;
|
||||
RpcSession* session = rpc_storage->session;
|
||||
furi_assert(session);
|
||||
|
||||
PB_Main* response = malloc(sizeof(PB_Main));
|
||||
response->command_id = request->command_id;
|
||||
response->has_next = false;
|
||||
response->command_status = PB_CommandStatus_OK;
|
||||
|
||||
Storage* fs_api = furi_record_open(RECORD_STORAGE);
|
||||
|
||||
bool backup_ok =
|
||||
lfs_backup_unpack(fs_api, request->content.storage_backup_restore_request.archive_path);
|
||||
response->command_status = backup_ok ? PB_CommandStatus_OK : PB_CommandStatus_ERROR;
|
||||
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
|
||||
rpc_send_and_release(session, response);
|
||||
free(response);
|
||||
rpc_send_and_release_empty(
|
||||
session, request->command_id, backup_ok ? PB_CommandStatus_OK : PB_CommandStatus_ERROR);
|
||||
}
|
||||
|
||||
void* rpc_system_storage_alloc(RpcSession* session) {
|
||||
|
||||
@@ -78,6 +78,8 @@ static void rpc_system_system_device_info_callback(
|
||||
furi_assert(value);
|
||||
RpcSystemContext* ctx = context;
|
||||
|
||||
furi_assert(key);
|
||||
furi_assert(value);
|
||||
char* str_key = strdup(key);
|
||||
char* str_value = strdup(value);
|
||||
|
||||
@@ -232,6 +234,8 @@ static void rpc_system_system_power_info_callback(
|
||||
furi_assert(value);
|
||||
RpcSystemContext* ctx = context;
|
||||
|
||||
furi_assert(key);
|
||||
furi_assert(value);
|
||||
char* str_key = strdup(key);
|
||||
char* str_value = strdup(value);
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ static void storage_cli_format(Cli* cli, string_t path) {
|
||||
if(string_cmp_str(path, STORAGE_INT_PATH_PREFIX) == 0) {
|
||||
storage_cli_print_error(FSE_NOT_IMPLEMENTED);
|
||||
} else if(string_cmp_str(path, STORAGE_EXT_PATH_PREFIX) == 0) {
|
||||
printf("Formatting SD card, all data will be lost. Are you sure (y/n)?\r\n");
|
||||
printf("Formatting SD card, All data will be lost! Are you sure (y/n)?\r\n");
|
||||
char answer = cli_getc(cli);
|
||||
if(answer == 'y' || answer == 'Y') {
|
||||
Storage* api = furi_record_open(RECORD_STORAGE);
|
||||
@@ -581,7 +581,7 @@ void storage_cli(Cli* cli, string_t args, void* context) {
|
||||
static void storage_cli_factory_reset(Cli* cli, string_t args, void* context) {
|
||||
UNUSED(args);
|
||||
UNUSED(context);
|
||||
printf("All data will be lost. Are you sure (y/n)?\r\n");
|
||||
printf("All data will be lost! Are you sure (y/n)?\r\n");
|
||||
char c = cli_getc(cli);
|
||||
if(c == 'y' || c == 'Y') {
|
||||
printf("Data will be wiped after reboot.\r\n");
|
||||
|
||||
@@ -26,8 +26,7 @@ static FS_Error storage_ext_parse_error(SDError error);
|
||||
|
||||
static bool sd_mount_card(StorageData* storage, bool notify) {
|
||||
bool result = false;
|
||||
const uint8_t max_init_counts = 10;
|
||||
uint8_t counter = max_init_counts;
|
||||
uint8_t counter = BSP_SD_MaxMountRetryCount();
|
||||
uint8_t bsp_result;
|
||||
SDData* sd_data = storage->data;
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ static bool
|
||||
static void storage_settings_scene_benchmark(StorageSettings* app) {
|
||||
DialogEx* dialog_ex = app->dialog_ex;
|
||||
uint8_t* bench_data;
|
||||
dialog_ex_set_header(dialog_ex, "Preparing data...", 64, 32, AlignCenter, AlignCenter);
|
||||
dialog_ex_set_header(dialog_ex, "Preparing Data...", 64, 32, AlignCenter, AlignCenter);
|
||||
|
||||
bench_data = malloc(BENCH_DATA_SIZE);
|
||||
for(size_t i = 0; i < BENCH_DATA_SIZE; i++) {
|
||||
@@ -123,7 +123,7 @@ void storage_settings_scene_benchmark_on_enter(void* context) {
|
||||
|
||||
if(sd_status != FSE_OK) {
|
||||
dialog_ex_set_icon(dialog_ex, 72, 14, &I_DolphinFirstStart8_56x51);
|
||||
dialog_ex_set_header(dialog_ex, "SD card not mounted", 64, 3, AlignCenter, AlignTop);
|
||||
dialog_ex_set_header(dialog_ex, "SD Card Not Mounted", 64, 3, AlignCenter, AlignTop);
|
||||
dialog_ex_set_text(
|
||||
dialog_ex, "Try to reinsert\nor format SD\ncard.", 3, 19, AlignLeft, AlignTop);
|
||||
dialog_ex_set_center_button_text(dialog_ex, "Ok");
|
||||
|
||||
@@ -24,7 +24,7 @@ void storage_settings_scene_factory_reset_on_enter(void* context) {
|
||||
dialog_ex_set_header(dialog_ex, "Confirm Factory Reset", 64, 10, AlignCenter, AlignCenter);
|
||||
dialog_ex_set_text(
|
||||
dialog_ex,
|
||||
"Internal storage will be erased\r\nData and setting will be lost",
|
||||
"Internal storage will be erased\r\nData and setting will be lost!",
|
||||
64,
|
||||
32,
|
||||
AlignCenter,
|
||||
|
||||
@@ -15,13 +15,13 @@ void storage_settings_scene_format_confirm_on_enter(void* context) {
|
||||
|
||||
if(sd_status == FSE_NOT_READY) {
|
||||
dialog_ex_set_icon(dialog_ex, 72, 14, &I_DolphinFirstStart8_56x51);
|
||||
dialog_ex_set_header(dialog_ex, "SD card not mounted", 64, 3, AlignCenter, AlignTop);
|
||||
dialog_ex_set_header(dialog_ex, "SD Card Not Mounted", 64, 3, AlignCenter, AlignTop);
|
||||
dialog_ex_set_text(
|
||||
dialog_ex, "Try to reinsert\nor format SD\ncard.", 3, 19, AlignLeft, AlignTop);
|
||||
dialog_ex_set_center_button_text(dialog_ex, "Ok");
|
||||
} else {
|
||||
dialog_ex_set_header(dialog_ex, "Format SD card?", 64, 10, AlignCenter, AlignCenter);
|
||||
dialog_ex_set_text(dialog_ex, "All data will be lost", 64, 32, AlignCenter, AlignCenter);
|
||||
dialog_ex_set_header(dialog_ex, "Format SD Card?", 64, 10, AlignCenter, AlignCenter);
|
||||
dialog_ex_set_text(dialog_ex, "All data will be lost!", 64, 32, AlignCenter, AlignCenter);
|
||||
dialog_ex_set_left_button_text(dialog_ex, "Cancel");
|
||||
dialog_ex_set_right_button_text(dialog_ex, "Format");
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ void storage_settings_scene_formatting_on_enter(void* context) {
|
||||
dialog_ex_set_result_callback(dialog_ex, storage_settings_scene_formatting_dialog_callback);
|
||||
|
||||
if(error != FSE_OK) {
|
||||
dialog_ex_set_header(dialog_ex, "Cannot format SD Card", 64, 10, AlignCenter, AlignCenter);
|
||||
dialog_ex_set_header(dialog_ex, "Cannot Format SD Card", 64, 10, AlignCenter, AlignCenter);
|
||||
dialog_ex_set_text(
|
||||
dialog_ex, storage_error_get_desc(error), 64, 32, AlignCenter, AlignCenter);
|
||||
} else {
|
||||
|
||||
@@ -21,7 +21,7 @@ void storage_settings_scene_internal_info_on_enter(void* context) {
|
||||
|
||||
if(error != FSE_OK) {
|
||||
dialog_ex_set_header(
|
||||
dialog_ex, "Internal storage error", 64, 10, AlignCenter, AlignCenter);
|
||||
dialog_ex, "Internal Storage Error", 64, 10, AlignCenter, AlignCenter);
|
||||
dialog_ex_set_text(
|
||||
dialog_ex, storage_error_get_desc(error), 64, 32, AlignCenter, AlignCenter);
|
||||
} else {
|
||||
|
||||
@@ -19,7 +19,7 @@ void storage_settings_scene_sd_info_on_enter(void* context) {
|
||||
|
||||
if(sd_status != FSE_OK) {
|
||||
dialog_ex_set_icon(dialog_ex, 72, 14, &I_DolphinFirstStart8_56x51);
|
||||
dialog_ex_set_header(dialog_ex, "SD card not mounted", 64, 3, AlignCenter, AlignTop);
|
||||
dialog_ex_set_header(dialog_ex, "SD Card Not Mounted", 64, 3, AlignCenter, AlignTop);
|
||||
dialog_ex_set_text(
|
||||
dialog_ex, "Try to reinsert\nor format SD\ncard.", 3, 19, AlignLeft, AlignTop);
|
||||
dialog_ex_set_center_button_text(dialog_ex, "Ok");
|
||||
|
||||
@@ -15,12 +15,12 @@ void storage_settings_scene_unmount_confirm_on_enter(void* context) {
|
||||
|
||||
if(sd_status == FSE_NOT_READY) {
|
||||
dialog_ex_set_icon(dialog_ex, 72, 14, &I_DolphinFirstStart8_56x51);
|
||||
dialog_ex_set_header(dialog_ex, "SD card not mounted", 64, 3, AlignCenter, AlignTop);
|
||||
dialog_ex_set_header(dialog_ex, "SD Card Not Mounted", 64, 3, AlignCenter, AlignTop);
|
||||
dialog_ex_set_text(
|
||||
dialog_ex, "Try to reinsert\nor format SD\ncard.", 3, 19, AlignLeft, AlignTop);
|
||||
dialog_ex_set_center_button_text(dialog_ex, "Ok");
|
||||
} else {
|
||||
dialog_ex_set_header(dialog_ex, "Unmount SD card?", 64, 10, AlignCenter, AlignCenter);
|
||||
dialog_ex_set_header(dialog_ex, "Unmount SD Card?", 64, 10, AlignCenter, AlignCenter);
|
||||
dialog_ex_set_text(
|
||||
dialog_ex, "SD card will be\nunavailable", 64, 32, AlignCenter, AlignCenter);
|
||||
dialog_ex_set_left_button_text(dialog_ex, "Cancel");
|
||||
|
||||
@@ -16,11 +16,11 @@ void storage_settings_scene_unmounted_on_enter(void* context) {
|
||||
dialog_ex_set_icon(dialog_ex, 72, 14, &I_DolphinFirstStart8_56x51);
|
||||
|
||||
if(error == FSE_OK) {
|
||||
dialog_ex_set_header(dialog_ex, "SD card unmounted", 64, 3, AlignCenter, AlignTop);
|
||||
dialog_ex_set_header(dialog_ex, "SD Card Unmounted", 64, 3, AlignCenter, AlignTop);
|
||||
dialog_ex_set_text(dialog_ex, "You can remove\nSD card now.", 3, 22, AlignLeft, AlignTop);
|
||||
notification_message(app->notification, &sequence_blink_green_100);
|
||||
} else {
|
||||
dialog_ex_set_header(dialog_ex, "Cannot unmount SD Card", 64, 3, AlignCenter, AlignTop);
|
||||
dialog_ex_set_header(dialog_ex, "Cannot Unmount SD Card", 64, 3, AlignCenter, AlignTop);
|
||||
dialog_ex_set_text(dialog_ex, storage_error_get_desc(error), 3, 22, AlignLeft, AlignTop);
|
||||
notification_message(app->notification, &sequence_blink_red_100);
|
||||
}
|
||||
|
||||
@@ -47,6 +47,9 @@ typedef enum {
|
||||
SubGhzCustomEventSceneStay,
|
||||
|
||||
SubGhzCustomEventSceneRpcLoad,
|
||||
SubGhzCustomEventSceneRpcButtonPress,
|
||||
SubGhzCustomEventSceneRpcButtonRelease,
|
||||
SubGhzCustomEventSceneRpcSessionClose,
|
||||
|
||||
SubGhzCustomEventViewReceiverOK,
|
||||
SubGhzCustomEventViewReceiverConfig,
|
||||
|
||||
@@ -72,11 +72,11 @@ typedef enum {
|
||||
SubGhzViewIdTestPacket,
|
||||
} SubGhzViewId;
|
||||
|
||||
struct SubGhzPesetDefinition {
|
||||
struct SubGhzPresetDefinition {
|
||||
string_t name;
|
||||
uint32_t frequency;
|
||||
uint8_t* data;
|
||||
size_t data_size;
|
||||
};
|
||||
|
||||
typedef struct SubGhzPesetDefinition SubGhzPesetDefinition;
|
||||
typedef struct SubGhzPresetDefinition SubGhzPresetDefinition;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user