mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-05-13 02:38:35 -07:00
Merge branch 'DigitalSequence_PulseReader' into ISO15693
This commit is contained in:
@@ -14,7 +14,7 @@ body:
|
|||||||
description: |
|
description: |
|
||||||
Please describe your feature request in as many details as possible.
|
Please describe your feature request in as many details as possible.
|
||||||
- Describe what it should do.
|
- Describe what it should do.
|
||||||
- Note whetever it is to extend existing functionality or introduce new functionality.
|
- Note whether it is to extend existing functionality or introduce new functionality.
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
|
|||||||
71
.github/workflows/unit_tests.yml
vendored
71
.github/workflows/unit_tests.yml
vendored
@@ -9,7 +9,7 @@ env:
|
|||||||
FBT_TOOLCHAIN_PATH: /opt
|
FBT_TOOLCHAIN_PATH: /opt
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
run_units_on_test_bench:
|
run_units_on_bench:
|
||||||
runs-on: [self-hosted, FlipperZeroTest]
|
runs-on: [self-hosted, FlipperZeroTest]
|
||||||
steps:
|
steps:
|
||||||
- name: 'Decontaminate previous build leftovers'
|
- name: 'Decontaminate previous build leftovers'
|
||||||
@@ -29,81 +29,38 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
echo "flipper=/dev/ttyACM0" >> $GITHUB_OUTPUT
|
echo "flipper=/dev/ttyACM0" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: 'Flashing target firmware'
|
|
||||||
id: first_full_flash
|
|
||||||
run: |
|
|
||||||
./fbt flash_usb_full PORT=${{steps.device.outputs.flipper}} FORCE=1
|
|
||||||
source scripts/toolchain/fbtenv.sh
|
|
||||||
python3 scripts/testing/await_flipper.py ${{steps.device.outputs.flipper}}
|
|
||||||
|
|
||||||
- name: 'Validating updater'
|
|
||||||
id: second_full_flash
|
|
||||||
if: success()
|
|
||||||
run: |
|
|
||||||
./fbt flash_usb_full PORT=${{steps.device.outputs.flipper}} FORCE=1
|
|
||||||
source scripts/toolchain/fbtenv.sh
|
|
||||||
python3 scripts/testing/await_flipper.py ${{steps.device.outputs.flipper}}
|
|
||||||
|
|
||||||
- name: 'Flash unit tests firmware'
|
- name: 'Flash unit tests firmware'
|
||||||
id: flashing
|
id: flashing
|
||||||
if: success()
|
if: success()
|
||||||
run: |
|
run: |
|
||||||
./fbt flash OPENOCD_ADAPTER_SERIAL=2A0906016415303030303032 FIRMWARE_APP_SET=unit_tests FORCE=1
|
./fbt flash OPENOCD_ADAPTER_SERIAL=2A0906016415303030303032 FIRMWARE_APP_SET=unit_tests FORCE=1
|
||||||
|
|
||||||
- name: 'Wait for flipper to finish updating'
|
- name: 'Wait for flipper and format ext'
|
||||||
id: connect
|
id: format_ext
|
||||||
if: steps.flashing.outcome == 'success'
|
if: steps.flashing.outcome == 'success'
|
||||||
run: |
|
run: |
|
||||||
source scripts/toolchain/fbtenv.sh
|
source scripts/toolchain/fbtenv.sh
|
||||||
python3 scripts/testing/await_flipper.py ${{steps.device.outputs.flipper}}
|
python3 scripts/testing/await_flipper.py ${{steps.device.outputs.flipper}}
|
||||||
|
python3 scripts/storage.py -p ${{steps.device.outputs.flipper}} format_ext
|
||||||
|
|
||||||
- name: 'Copy assets and unit tests data to flipper'
|
- name: 'Copy assets and unit data, reboot and wait for flipper'
|
||||||
id: copy
|
id: copy
|
||||||
if: steps.connect.outcome == 'success'
|
if: steps.format_ext.outcome == 'success'
|
||||||
run: |
|
run: |
|
||||||
source scripts/toolchain/fbtenv.sh
|
source scripts/toolchain/fbtenv.sh
|
||||||
|
python3 scripts/storage.py -p ${{steps.device.outputs.flipper}} -f send assets/resources /ext
|
||||||
python3 scripts/storage.py -p ${{steps.device.outputs.flipper}} -f send assets/unit_tests /ext/unit_tests
|
python3 scripts/storage.py -p ${{steps.device.outputs.flipper}} -f send assets/unit_tests /ext/unit_tests
|
||||||
|
python3 scripts/power.py -p ${{steps.device.outputs.flipper}} reboot
|
||||||
|
python3 scripts/testing/await_flipper.py ${{steps.device.outputs.flipper}}
|
||||||
|
|
||||||
- name: 'Run units and validate results'
|
- name: 'Run units and validate results'
|
||||||
|
id: run_units
|
||||||
if: steps.copy.outcome == 'success'
|
if: steps.copy.outcome == 'success'
|
||||||
run: |
|
run: |
|
||||||
source scripts/toolchain/fbtenv.sh
|
source scripts/toolchain/fbtenv.sh
|
||||||
python3 scripts/testing/units.py ${{steps.device.outputs.flipper}}
|
python3 scripts/testing/units.py ${{steps.device.outputs.flipper}}
|
||||||
|
|
||||||
- name: 'Get last release tag'
|
- name: 'Check GDB output'
|
||||||
id: release_tag
|
if: failure()
|
||||||
if: always()
|
|
||||||
run: |
|
run: |
|
||||||
echo "tag=$(git tag -l --sort=-version:refname | grep -v "rc\|RC" | head -1)" >> $GITHUB_OUTPUT
|
./fbt gdb_trace_all OPENOCD_ADAPTER_SERIAL=2A0906016415303030303032 FIRMWARE_APP_SET=unit_tests FORCE=1
|
||||||
|
|
||||||
- name: 'Decontaminate previous build leftovers'
|
|
||||||
if: always()
|
|
||||||
run: |
|
|
||||||
if [ -d .git ]; then
|
|
||||||
git submodule status || git checkout "$(git rev-list --max-parents=0 HEAD | tail -n 1)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: 'Checkout latest release'
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
if: always()
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
ref: ${{ steps.release_tag.outputs.tag }}
|
|
||||||
|
|
||||||
- name: 'Flash last release'
|
|
||||||
if: always()
|
|
||||||
run: |
|
|
||||||
./fbt flash OPENOCD_ADAPTER_SERIAL=2A0906016415303030303032 FIRMWARE_APP_SET=unit_tests FORCE=1
|
|
||||||
|
|
||||||
- name: 'Wait for flipper to finish updating'
|
|
||||||
if: always()
|
|
||||||
run: |
|
|
||||||
source scripts/toolchain/fbtenv.sh
|
|
||||||
python3 scripts/testing/await_flipper.py ${{steps.device.outputs.flipper}}
|
|
||||||
|
|
||||||
- name: 'Format flipper SD card'
|
|
||||||
id: format
|
|
||||||
if: always()
|
|
||||||
run: |
|
|
||||||
source scripts/toolchain/fbtenv.sh
|
|
||||||
python3 scripts/storage.py -p ${{steps.device.outputs.flipper}} format_ext
|
|
||||||
|
|||||||
77
.github/workflows/updater_test.yml
vendored
Normal file
77
.github/workflows/updater_test.yml
vendored
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
name: 'Updater test'
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
env:
|
||||||
|
TARGETS: f7
|
||||||
|
DEFAULT_TARGET: f7
|
||||||
|
FBT_TOOLCHAIN_PATH: /opt
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test_updater_on_bench:
|
||||||
|
runs-on: [self-hosted, FlipperZeroTest] # currently on same bench as units, needs different bench
|
||||||
|
steps:
|
||||||
|
- 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@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
ref: ${{ github.event.pull_request.head.sha }}
|
||||||
|
|
||||||
|
- name: 'Get flipper from device manager (mock)'
|
||||||
|
id: device
|
||||||
|
run: |
|
||||||
|
echo "flipper=/dev/ttyACM0" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: 'Flashing target firmware'
|
||||||
|
id: first_full_flash
|
||||||
|
run: |
|
||||||
|
source scripts/toolchain/fbtenv.sh
|
||||||
|
./fbt flash_usb_full PORT=${{steps.device.outputs.flipper}} FORCE=1
|
||||||
|
python3 scripts/testing/await_flipper.py ${{steps.device.outputs.flipper}}
|
||||||
|
|
||||||
|
- name: 'Validating updater'
|
||||||
|
id: second_full_flash
|
||||||
|
if: success()
|
||||||
|
run: |
|
||||||
|
source scripts/toolchain/fbtenv.sh
|
||||||
|
./fbt flash_usb PORT=${{steps.device.outputs.flipper}} FORCE=1
|
||||||
|
python3 scripts/testing/await_flipper.py ${{steps.device.outputs.flipper}}
|
||||||
|
|
||||||
|
- name: 'Get last release tag'
|
||||||
|
id: release_tag
|
||||||
|
if: failure()
|
||||||
|
run: |
|
||||||
|
echo "tag=$(git tag -l --sort=-version:refname | grep -v "rc\|RC" | head -1)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: 'Decontaminate previous build leftovers'
|
||||||
|
if: failure()
|
||||||
|
run: |
|
||||||
|
if [ -d .git ]; then
|
||||||
|
git submodule status || git checkout "$(git rev-list --max-parents=0 HEAD | tail -n 1)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: 'Checkout latest release'
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
if: failure()
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
ref: ${{ steps.release_tag.outputs.tag }}
|
||||||
|
|
||||||
|
- name: 'Flash last release'
|
||||||
|
if: failure()
|
||||||
|
run: |
|
||||||
|
./fbt flash OPENOCD_ADAPTER_SERIAL=2A0906016415303030303032 FORCE=1
|
||||||
|
|
||||||
|
- name: 'Wait for flipper and format ext'
|
||||||
|
if: failure()
|
||||||
|
run: |
|
||||||
|
source scripts/toolchain/fbtenv.sh
|
||||||
|
python3 scripts/testing/await_flipper.py ${{steps.device.outputs.flipper}}
|
||||||
|
python3 scripts/storage.py -p ${{steps.device.outputs.flipper}} format_ext
|
||||||
@@ -3,15 +3,15 @@
|
|||||||
Nice to see you reading this document, we really appreciate it.
|
Nice to see you reading this document, we really appreciate it.
|
||||||
|
|
||||||
As all documents of this kind it's unable to cover everything.
|
As all documents of this kind it's unable to cover everything.
|
||||||
But it will cover general rules that we enforcing on PR review.
|
But it will cover general rules that we are enforcing on PR review.
|
||||||
|
|
||||||
Also we already have automatic rules checking and formatting,
|
Also, we already have automatic rules checking and formatting,
|
||||||
but it got it's limitations and this guide is still mandatory.
|
but it got its limitations and this guide is still mandatory.
|
||||||
|
|
||||||
Some part of this project do have it's own naming and coding guides.
|
Some part of this project do have its own naming and coding guides.
|
||||||
For example: assets. Take a look into `ReadMe.md` in assets folder for more details.
|
For example: assets. Take a look into `ReadMe.md` in assets folder for more details.
|
||||||
|
|
||||||
Also 3rd party libraries are none of our concern.
|
Also, 3rd party libraries are none of our concern.
|
||||||
|
|
||||||
And yes, this set is not final and we are open to discussion.
|
And yes, this set is not final and we are open to discussion.
|
||||||
If you want to add/remove/change something here please feel free to open new ticket.
|
If you want to add/remove/change something here please feel free to open new ticket.
|
||||||
@@ -30,7 +30,7 @@ Our guide is inspired by, but not claiming to be compatible with:
|
|||||||
|
|
||||||
Code we write is intended to be public.
|
Code we write is intended to be public.
|
||||||
Avoid one-liners from hell and keep code complexity under control.
|
Avoid one-liners from hell and keep code complexity under control.
|
||||||
Try to make code self explanatory and add comments if needed.
|
Try to make code self-explanatory and add comments if needed.
|
||||||
Leave references to standards that you are implementing.
|
Leave references to standards that you are implementing.
|
||||||
Use project wiki to document new/reverse engineered standards.
|
Use project wiki to document new/reverse engineered standards.
|
||||||
|
|
||||||
@@ -89,7 +89,7 @@ Enforced by linter.
|
|||||||
Suffixes:
|
Suffixes:
|
||||||
|
|
||||||
- `alloc` - allocate and init instance. C style constructor. Returns pointer to instance.
|
- `alloc` - allocate and init instance. C style constructor. Returns pointer to instance.
|
||||||
- `free` - deinit and release instance. C style destructor. Takes pointer to instance.
|
- `free` - de-init and release instance. C style destructor. Takes pointer to instance.
|
||||||
|
|
||||||
# C++ coding style
|
# C++ coding style
|
||||||
|
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ Before writing code and creating PR make sure that it aligns with our mission an
|
|||||||
- PR that contains code intended to commit crimes is not going to be accepted.
|
- PR that contains code intended to commit crimes is not going to be accepted.
|
||||||
- Your PR must comply with our [Coding Style](CODING_STYLE.md)
|
- Your PR must comply with our [Coding Style](CODING_STYLE.md)
|
||||||
- Your PR must contain code compatible with project [LICENSE](LICENSE).
|
- Your PR must contain code compatible with project [LICENSE](LICENSE).
|
||||||
- PR will only be merged if it pass CI/CD.
|
- PR will only be merged if it passes CI/CD.
|
||||||
- PR will only be merged if it pass review by code owner.
|
- PR will only be merged if it passes review by code owner.
|
||||||
|
|
||||||
Feel free to ask questions in issues if you're not sure.
|
Feel free to ask questions in issues if you're not sure.
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ Commit the changes once you are happy with them. Make sure that code compilation
|
|||||||
### Pull Request
|
### Pull Request
|
||||||
|
|
||||||
When you're done making the changes, open a pull request, often referred to as a PR.
|
When you're done making the changes, open a pull request, often referred to as a PR.
|
||||||
- Fill out the "Ready for review" template so we can review your PR. This template helps reviewers understand your changes and the purpose of your pull request.
|
- Fill out the "Ready for review" template, so we can review your PR. This template helps reviewers understand your changes and the purpose of your pull request.
|
||||||
- Don't forget to [link PR to issue](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue) if you are solving one.
|
- Don't forget to [link PR to issue](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue) if you are solving one.
|
||||||
- Enable the checkbox to [allow maintainer edits](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/allowing-changes-to-a-pull-request-branch-created-from-a-fork) so the branch can be updated for a merge.
|
- Enable the checkbox to [allow maintainer edits](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/allowing-changes-to-a-pull-request-branch-created-from-a-fork) so the branch can be updated for a merge.
|
||||||
Once you submit your PR, a Docs team member will review your proposal. We may ask questions or request for additional information.
|
Once you submit your PR, a Docs team member will review your proposal. We may ask questions or request for additional information.
|
||||||
|
|||||||
14
SConstruct
14
SConstruct
@@ -194,6 +194,20 @@ firmware_bm_flash = distenv.PhonyTarget(
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
gdb_backtrace_all_threads = distenv.PhonyTarget(
|
||||||
|
"gdb_trace_all",
|
||||||
|
"$GDB $GDBOPTS $SOURCES $GDBFLASH",
|
||||||
|
source=firmware_env["FW_ELF"],
|
||||||
|
GDBOPTS="${GDBOPTS_BASE}",
|
||||||
|
GDBREMOTE="${OPENOCD_GDB_PIPE}",
|
||||||
|
GDBFLASH=[
|
||||||
|
"-ex",
|
||||||
|
"thread apply all bt",
|
||||||
|
"-ex",
|
||||||
|
"quit",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
# Debugging firmware
|
# Debugging firmware
|
||||||
firmware_debug = distenv.PhonyTarget(
|
firmware_debug = distenv.PhonyTarget(
|
||||||
"debug",
|
"debug",
|
||||||
|
|||||||
@@ -60,7 +60,13 @@ static void dict_attack_draw_callback(Canvas* canvas, void* model) {
|
|||||||
if(progress > 1.0) {
|
if(progress > 1.0) {
|
||||||
progress = 1.0;
|
progress = 1.0;
|
||||||
}
|
}
|
||||||
snprintf(draw_str, sizeof(draw_str), "%d/%d", m->dict_keys_current, m->dict_keys_total);
|
if(m->dict_keys_current == 0) {
|
||||||
|
// Cause when people see 0 they think it's broken
|
||||||
|
snprintf(draw_str, sizeof(draw_str), "%d/%d", 1, m->dict_keys_total);
|
||||||
|
} else {
|
||||||
|
snprintf(
|
||||||
|
draw_str, sizeof(draw_str), "%d/%d", m->dict_keys_current, m->dict_keys_total);
|
||||||
|
}
|
||||||
elements_progress_bar_with_text(canvas, 0, 20, 128, dict_progress, draw_str);
|
elements_progress_bar_with_text(canvas, 0, 20, 128, dict_progress, draw_str);
|
||||||
canvas_set_font(canvas, FontSecondary);
|
canvas_set_font(canvas, FontSecondary);
|
||||||
snprintf(draw_str, sizeof(draw_str), "Keys found: %d/%d", m->keys_found, m->keys_total);
|
snprintf(draw_str, sizeof(draw_str), "Keys found: %d/%d", m->keys_found, m->keys_total);
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ Version: 1
|
|||||||
- `Name` - name of animation. Must be exact animation directory name.
|
- `Name` - name of animation. Must be exact animation directory name.
|
||||||
- `Min butthurt`, `Max butthurt` - range of dolphin's butthurt for this animation.
|
- `Min butthurt`, `Max butthurt` - range of dolphin's butthurt for this animation.
|
||||||
- `Min level`, `Max level` - range of dolphin's level for this animation. If 0, this animation doesn't participate in random idle animation selection and can only be selected by exact name.
|
- `Min level`, `Max level` - range of dolphin's level for this animation. If 0, this animation doesn't participate in random idle animation selection and can only be selected by exact name.
|
||||||
- `Weight` - chance of this animation to be choosen at random animation selection.
|
- `Weight` - chance of this animation to be chosen at random animation selection.
|
||||||
|
|
||||||
Some animations can be excluded from participation in random animation selection, such as `L1_NoSd_128x49`.
|
Some animations can be excluded from participation in random animation selection, such as `L1_NoSd_128x49`.
|
||||||
|
|
||||||
|
|||||||
@@ -57,8 +57,10 @@ The following parameters are used only for [FAPs](./AppsOnSDCard.md):
|
|||||||
* **fap_weburl**: string, may be empty. Application's homepage.
|
* **fap_weburl**: string, may be empty. Application's homepage.
|
||||||
* **fap_icon_assets**: string. If present defines a folder name to be used for gathering image assets for this application. These images will be preprocessed and built alongside the application. See [FAP assets](./AppsOnSDCard.md#fap-assets) for details.
|
* **fap_icon_assets**: string. If present defines a folder name to be used for gathering image assets for this application. These images will be preprocessed and built alongside the application. See [FAP assets](./AppsOnSDCard.md#fap-assets) for details.
|
||||||
* **fap_extbuild**: provides support for parts of application sources to be built by external tools. Contains a list of `ExtFile(path="file name", command="shell command")` definitions. **`fbt`** will run the specified command for each file in the list.
|
* **fap_extbuild**: provides support for parts of application sources to be built by external tools. Contains a list of `ExtFile(path="file name", command="shell command")` definitions. **`fbt`** will run the specified command for each file in the list.
|
||||||
|
|
||||||
Note that commands are executed at the firmware root folder's root, and all intermediate files must be placed in an application's temporary build folder. For that, you can use pattern expansion by **`fbt`**: `${FAP_WORK_DIR}` will be replaced with the path to the application's temporary build folder, and `${FAP_SRC_DIR}` will be replaced with the path to the application's source folder. You can also use other variables defined internally by **`fbt`**.
|
Note that commands are executed at the firmware root folder's root, and all intermediate files must be placed in an application's temporary build folder. For that, you can use pattern expansion by **`fbt`**: `${FAP_WORK_DIR}` will be replaced with the path to the application's temporary build folder, and `${FAP_SRC_DIR}` will be replaced with the path to the application's source folder. You can also use other variables defined internally by **`fbt`**.
|
||||||
|
|
||||||
|
|
||||||
Example for building an app from Rust sources:
|
Example for building an app from Rust sources:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ With it, you can debug FAPs as if they were a part of main firmware — inspect
|
|||||||
|
|
||||||
### Setting up debugging environment
|
### Setting up debugging environment
|
||||||
|
|
||||||
Debugging support script looks up debugging information in latest firmware build dir (`build/latest`). That directory is symlinked by fbt to the latest firmware configuration (Debug or Release) build dir, when you run `./fbt` for chosen configuration. See [fbt docs](./fbt.md#nb) for details.
|
Debugging support script looks up debugging information in the latest firmware build dir (`build/latest`). That directory is symlinked by fbt to the latest firmware configuration (Debug or Release) build dir, when you run `./fbt` for chosen configuration. See [fbt docs](./fbt.md#nb) for details.
|
||||||
|
|
||||||
So, to debug FAPs, do the following:
|
So, to debug FAPs, do the following:
|
||||||
1. Build firmware with `./fbt`
|
1. Build firmware with `./fbt`
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Key Combos
|
# Key Combos
|
||||||
|
|
||||||
There are times when your flipper feels blue and doesn't respond to your commands.
|
There are times when your Flipper feels blue and doesn't respond to your commands.
|
||||||
In that case, you may find this guide useful.
|
In that case, you may find this guide useful.
|
||||||
|
|
||||||
|
|
||||||
@@ -12,10 +12,10 @@ In that case, you may find this guide useful.
|
|||||||
- Press `LEFT` and `BACK` and hold for a couple of seconds
|
- Press `LEFT` and `BACK` and hold for a couple of seconds
|
||||||
- Release `LEFT` and `BACK`
|
- Release `LEFT` and `BACK`
|
||||||
|
|
||||||
This combo performs hardware reset by pulling MCU reset line down.
|
This combo performs a hardware reset by pulling MCU reset line down.
|
||||||
Main components involved: Keys -> DD8(NC7SZ32M5X, OR-gate) -> DD1(STM32WB55, MCU)
|
Main components involved: Keys -> DD8(NC7SZ32M5X, OR-gate) -> DD1(STM32WB55, MCU)
|
||||||
|
|
||||||
There is 1 case when it's not working:
|
There is 1 case where it does not work:
|
||||||
|
|
||||||
- MCU debug block is active and holding reset line from inside.
|
- MCU debug block is active and holding reset line from inside.
|
||||||
|
|
||||||
@@ -25,32 +25,32 @@ There is 1 case when it's not working:
|
|||||||
- Disconnect USB and any external power supplies
|
- Disconnect USB and any external power supplies
|
||||||
- Disconnect USB once again
|
- Disconnect USB once again
|
||||||
- Make sure that you've disconnected USB and any external power supplies
|
- Make sure that you've disconnected USB and any external power supplies
|
||||||
- Press `BACK` and hold for 30 seconds (Only will work with USB Disconnected)
|
- Press `BACK` and hold for 30 seconds (Will only work with USB disconnected)
|
||||||
- If you have not disconnected USB, then disconnect USB and repeat previous step
|
- If you have not disconnected USB, then disconnect USB and repeat previous step
|
||||||
- Release `BACK` key
|
- Release `BACK` key
|
||||||
|
|
||||||
This combo performs a reset by switching SYS power line off and then on.
|
This combo performs a reset by switching SYS power line off and then on.
|
||||||
Main components involved: Keys -> DD6(bq25896, charger)
|
Main components involved: Keys -> DD6(bq25896, charger)
|
||||||
|
|
||||||
There is 1 case when it's not working:
|
There is 1 case where it does not work:
|
||||||
|
|
||||||
- Power supply is connected to USB or 5V_ext
|
- Power supply is connected to USB or 5V_ext
|
||||||
|
|
||||||
|
|
||||||
### Software DFU
|
### Software DFU
|
||||||
|
|
||||||
- Press `LEFT` on boot to enter DFU with flipper boot-loader
|
- Press `LEFT` on boot to enter DFU with Flipper boot-loader
|
||||||
|
|
||||||
There is 1 case when it's not working:
|
There is 1 case where it does not work:
|
||||||
|
|
||||||
- Flipper Boot-loader is damaged or absent
|
- Flipper boot-loader is damaged or absent
|
||||||
|
|
||||||
|
|
||||||
### Hardware DFU
|
### Hardware DFU
|
||||||
|
|
||||||
- Press `OK` on boot to enter DFU with ST boot-loader
|
- Press `OK` on boot to enter DFU with ST boot-loader
|
||||||
|
|
||||||
There is 1 case when it's not working:
|
There is 1 case where it does not work:
|
||||||
|
|
||||||
- Option Bytes are damaged or set to ignore `OK` key
|
- Option Bytes are damaged or set to ignore `OK` key
|
||||||
|
|
||||||
@@ -65,25 +65,25 @@ There is 1 case when it's not working:
|
|||||||
- Device will enter DFU with indication (Blue LED + DFU Screen)
|
- Device will enter DFU with indication (Blue LED + DFU Screen)
|
||||||
- Release `LEFT`
|
- Release `LEFT`
|
||||||
|
|
||||||
This combo performs hardware reset by pulling MCU reset line down.
|
This combo performs a hardware reset by pulling MCU reset line down.
|
||||||
Then `LEFT` key indicates to boot-loader that DFU mode is requested.
|
Then, `LEFT` key indicates to the boot-loader that DFU mode is requested.
|
||||||
|
|
||||||
There are 2 cases when it's not working:
|
There are 2 cases where it does not work:
|
||||||
|
|
||||||
- MCU debug block is active and holding reset line from inside
|
- MCU debug block is active and holding reset line from inside
|
||||||
- Flipper Boot-loader is damaged or absent
|
- Flipper boot-loader is damaged or absent
|
||||||
|
|
||||||
|
|
||||||
### Hardware Reset + Hardware DFU
|
### Hardware Reset + Hardware DFU
|
||||||
|
|
||||||
- Press `LEFT` and `BACK` and `OK` and hold for a couple of seconds
|
- Press `LEFT`, `BACK` and `OK` and hold for a couple of seconds
|
||||||
- Release `BACK` and `LEFT`
|
- Release `BACK` and `LEFT`
|
||||||
- Device will enter DFU without indication
|
- Device will enter DFU without indication
|
||||||
|
|
||||||
This combo performs hardware reset by pulling MCU reset line down.
|
This combo performs a hardware reset by pulling MCU reset line down.
|
||||||
Then `OK` key forces MCU to load internal boot-loader.
|
Then, `OK` key forces MCU to load internal boot-loader.
|
||||||
|
|
||||||
There are 2 cases when it's not working:
|
There are 2 cases where it does not work:
|
||||||
|
|
||||||
- MCU debug block is active and holding reset line from inside
|
- MCU debug block is active and holding reset line from inside
|
||||||
- Option Bytes are damaged or set to ignore `OK` key
|
- Option Bytes are damaged or set to ignore `OK` key
|
||||||
@@ -96,15 +96,15 @@ There are 2 cases when it's not working:
|
|||||||
- Release `BACK`
|
- Release `BACK`
|
||||||
- Device will enter DFU with indication (Blue LED + DFU Screen)
|
- Device will enter DFU with indication (Blue LED + DFU Screen)
|
||||||
- Release `LEFT`
|
- Release `LEFT`
|
||||||
- Plug USB
|
- Plug in USB
|
||||||
|
|
||||||
This combo performs reset by switching SYS power line off and then on.
|
This combo performs a reset by switching SYS power line off and then on.
|
||||||
Then `LEFT` key indicates to boot-loader that DFU mode requested.
|
Then, `LEFT` key indicates to boot-loader that DFU mode requested.
|
||||||
|
|
||||||
There are 2 cases when it's not working:
|
There are 2 cases where it does not work:
|
||||||
|
|
||||||
- Power supply is connected to USB or 5V_ext
|
- Power supply is connected to USB or 5V_ext
|
||||||
- Flipper Boot-loader is damaged or absent
|
- Flipper boot-loader is damaged or absent
|
||||||
|
|
||||||
|
|
||||||
### Hardware Power Reset + Hardware DFU
|
### Hardware Power Reset + Hardware DFU
|
||||||
@@ -115,10 +115,10 @@ There are 2 cases when it's not working:
|
|||||||
- Device will enter DFU without indication
|
- Device will enter DFU without indication
|
||||||
- Plug USB
|
- Plug USB
|
||||||
|
|
||||||
This combo performs reset by switching SYS power line off and then on.
|
This combo performs a reset by switching SYS power line off and then on.
|
||||||
Then `OK` key forces MCU to load internal boot-loader.
|
Then, `OK` key forces MCU to load internal boot-loader.
|
||||||
|
|
||||||
There are 2 cases when it's not working:
|
There are 2 cases where it does not work:
|
||||||
|
|
||||||
- Power supply is connected to USB or 5V_ext
|
- Power supply is connected to USB or 5V_ext
|
||||||
- Option Bytes are damaged or set to ignore `OK` key
|
- Option Bytes are damaged or set to ignore `OK` key
|
||||||
@@ -131,4 +131,4 @@ If none of the described methods were useful:
|
|||||||
- Disconnect the battery and connect again (Requires disassembly)
|
- Disconnect the battery and connect again (Requires disassembly)
|
||||||
- Try to Flash device with ST-Link or other programmer that supports SWD
|
- Try to Flash device with ST-Link or other programmer that supports SWD
|
||||||
|
|
||||||
If you still here and your device is not working: it's not a software issue.
|
If you still are here and your device is not working: it's not a software issue.
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
# Command syntax
|
# Command syntax
|
||||||
BadUsb app uses extended Duckyscript syntax. It is compatible with classic USB Rubber Ducky 1.0 scripts, but provides some additional commands and features, such as custom USB ID, ALT+Numpad input method, SYSRQ command and more fuctional keys.
|
BadUsb app uses extended Duckyscript syntax. It is compatible with classic USB Rubber Ducky 1.0 scripts, but provides some additional commands and features, such as custom USB ID, ALT+Numpad input method, SYSRQ command and more functional keys.
|
||||||
# Script file format
|
# Script file format
|
||||||
BadUsb app can execute only text scrips from .txt files, no compilation is required. Both `\n` and `\r\n` line endings are supported. Empty lines are allowed. You can use spaces ore tabs for line indentation.
|
BadUsb app can execute only text scrips from .txt files, no compilation is required. Both `\n` and `\r\n` line endings are supported. Empty lines are allowed. You can use spaces ore tabs for line indentation.
|
||||||
# Command set
|
# Command set
|
||||||
|
|||||||
@@ -95,17 +95,17 @@ Note: a single parsed signal must be represented as an array of size 1.
|
|||||||
| data | raw | uint32 | Ditto. |
|
| data | raw | uint32 | Ditto. |
|
||||||
|
|
||||||
#### Signal names
|
#### Signal names
|
||||||
The signal names in an `.irtest` file folow a convention `<name><test_number>`, where the name is one of:
|
The signal names in an `.irtest` file follow a convention `<name><test_number>`, where the name is one of:
|
||||||
- decoder_input
|
- decoder_input
|
||||||
- decoder_expected
|
- decoder_expected
|
||||||
- encoder_decoder_input,
|
- encoder_decoder_input,
|
||||||
|
|
||||||
and the number is a sequential integer: 1, 2, 3...etc, which produces names like `decoder_input1`, `encoder_decoder_input3`, and so on.
|
and the number is a sequential integer: 1, 2, 3...etc, which produces names like `decoder_input1`, `encoder_decoder_input3`, and so on.
|
||||||
|
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
| --------------------- | ------------ | ----------- |
|
| --------------------- | ------------ |-------------------------------------------------------------------------------------------------------|
|
||||||
| decoder_input | raw | A raw signal contaning the decoder input. Is also used as the expected encoder output. |
|
| decoder_input | raw | A raw signal containing the decoder input. Is also used as the expected encoder output. |
|
||||||
| decoder_expected | parsed_array | An array of parsed signals containing the expected decoder output. Is also used as the encoder input. |
|
| decoder_expected | parsed_array | An array of parsed signals containing the expected decoder output. Is also used as the encoder input. |
|
||||||
| encoder_decoder_input | parsed_array | An array of parsed signals containing both the encoder-decoder input and expected output. |
|
| encoder_decoder_input | parsed_array | An array of parsed signals containing both the encoder-decoder input and expected output. |
|
||||||
|
|
||||||
See [Unit Tests](/documentation/UnitTests.md#infrared) for more info.
|
See [Unit Tests](/documentation/UnitTests.md#infrared) for more info.
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ This file format is used to store the UID, SAK and ATQA of a Mifare Ultralight/N
|
|||||||
|
|
||||||
The "Signature" field contains the reply of the tag to the READ_SIG command. More on that can be found here: <https://www.nxp.com/docs/en/data-sheet/MF0ULX1.pdf> (page 31)
|
The "Signature" field contains the reply of the tag to the READ_SIG command. More on that can be found here: <https://www.nxp.com/docs/en/data-sheet/MF0ULX1.pdf> (page 31)
|
||||||
|
|
||||||
The "Mifare version" field is not related to the file format version, but to the Mifare Ultralight version. It contains the responce of the tag to the GET_VERSION command. More on that can be found here: <https://www.nxp.com/docs/en/data-sheet/MF0ULX1.pdf> (page 21)
|
The "Mifare version" field is not related to the file format version, but to the Mifare Ultralight version. It contains the response of the tag to the GET_VERSION command. More on that can be found here: <https://www.nxp.com/docs/en/data-sheet/MF0ULX1.pdf> (page 21)
|
||||||
|
|
||||||
Other fields are the direct representation of the card's internal state, more on them can be found in the same datasheet.
|
Other fields are the direct representation of the card's internal state, more on them can be found in the same datasheet.
|
||||||
|
|
||||||
|
|||||||
@@ -197,7 +197,7 @@ For each key, a name and encryption method must be specified, according to comme
|
|||||||
|
|
||||||
## SubGhz `setting_user` File
|
## SubGhz `setting_user` File
|
||||||
|
|
||||||
This file contains additional radio presets and frequencies for SubGhz application. It is used to add new presets and frequencies for existing presets. This file is be loaded on subghz application start and is located at path `/ext/subghz/assets/setting_user`.
|
This file contains additional radio presets and frequencies for SubGhz application. It is used to add new presets and frequencies for existing presets. This file is being loaded on subghz application start and is located at path `/ext/subghz/assets/setting_user`.
|
||||||
|
|
||||||
### File Format
|
### File Format
|
||||||
|
|
||||||
|
|||||||
@@ -14,9 +14,9 @@ What does it do?
|
|||||||
|-----------|-------------------|-----------------------|-----------------------|
|
|-----------|-------------------|-----------------------|-----------------------|
|
||||||
| f7 | 0x08000000 | L+Back, release both | L+Back, release Back |
|
| f7 | 0x08000000 | L+Back, release both | L+Back, release Back |
|
||||||
|
|
||||||
Also there is a "hardware" ST bootloader combo available even on a bricked or empty device: L+Ok+Back, release Back, Left.
|
Also, there is a "hardware" ST bootloader combo available even on a bricked or empty device: L+Ok+Back, release Back, Left.
|
||||||
Target independent code and headers in `target/include` folders. More details in `documentation/KeyCombo.md`
|
Target independent code and headers in `target/include` folders. More details in `documentation/KeyCombo.md`
|
||||||
|
|
||||||
# Building
|
# Building
|
||||||
|
|
||||||
Check out `documentation/fbt.md` on how to build and flash firmware.
|
Check out `documentation/fbt.md` on how to build and flash firmware.
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
- `infrared` - Infrared library
|
- `infrared` - Infrared library
|
||||||
- `libusb_stm32` - STM32 USB library
|
- `libusb_stm32` - STM32 USB library
|
||||||
- `littlefs` - Internal storage file system
|
- `littlefs` - Internal storage file system
|
||||||
- `micro-ecc` - Elliptic Curve Crpytography library
|
- `micro-ecc` - Elliptic Curve Crytography library
|
||||||
- `microtar` - TAR archive support library
|
- `microtar` - TAR archive support library
|
||||||
- `mlib` - Algorithms and containers
|
- `mlib` - Algorithms and containers
|
||||||
- `nanopb` - Nano Protobuf library
|
- `nanopb` - Nano Protobuf library
|
||||||
|
|||||||
@@ -4,6 +4,30 @@
|
|||||||
#include <furi_hal_resources.h>
|
#include <furi_hal_resources.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
|
#include <stm32wbxx_ll_dma.h>
|
||||||
|
#include <stm32wbxx_ll_tim.h>
|
||||||
|
|
||||||
|
struct DigitalSequence {
|
||||||
|
uint8_t signals_size;
|
||||||
|
bool bake;
|
||||||
|
uint32_t sequence_used;
|
||||||
|
uint32_t sequence_size;
|
||||||
|
DigitalSignal** signals;
|
||||||
|
bool* signals_prolonged;
|
||||||
|
uint8_t* sequence;
|
||||||
|
const GpioPin* gpio;
|
||||||
|
uint32_t send_time;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DigitalSignalInternals {
|
||||||
|
uint32_t reload_reg_entries;
|
||||||
|
uint32_t reload_reg_remainder;
|
||||||
|
uint32_t gpio_buff[2];
|
||||||
|
const GpioPin* gpio;
|
||||||
|
LL_DMA_InitTypeDef dma_config_gpio;
|
||||||
|
LL_DMA_InitTypeDef dma_config_timer;
|
||||||
|
};
|
||||||
|
|
||||||
#define TAG "DigitalSignal"
|
#define TAG "DigitalSignal"
|
||||||
|
|
||||||
#define F_TIM (64000000.0)
|
#define F_TIM (64000000.0)
|
||||||
@@ -17,28 +41,29 @@ DigitalSignal* digital_signal_alloc(uint32_t max_edges_cnt) {
|
|||||||
signal->edge_timings = malloc(signal->edges_max_cnt * sizeof(uint32_t));
|
signal->edge_timings = malloc(signal->edges_max_cnt * sizeof(uint32_t));
|
||||||
signal->edge_cnt = 0;
|
signal->edge_cnt = 0;
|
||||||
signal->reload_reg_buff = malloc(signal->edges_max_cnt * sizeof(uint32_t));
|
signal->reload_reg_buff = malloc(signal->edges_max_cnt * sizeof(uint32_t));
|
||||||
signal->reload_reg_entries = 0;
|
|
||||||
signal->reload_reg_remainder = 0;
|
|
||||||
|
|
||||||
signal->dma_config_gpio.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH;
|
signal->internals = malloc(sizeof(DigitalSignalInternals));
|
||||||
signal->dma_config_gpio.Mode = LL_DMA_MODE_CIRCULAR;
|
signal->internals->reload_reg_entries = 0;
|
||||||
signal->dma_config_gpio.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT;
|
signal->internals->reload_reg_remainder = 0;
|
||||||
signal->dma_config_gpio.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT;
|
signal->internals->dma_config_gpio.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH;
|
||||||
signal->dma_config_gpio.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD;
|
signal->internals->dma_config_gpio.Mode = LL_DMA_MODE_CIRCULAR;
|
||||||
signal->dma_config_gpio.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD;
|
signal->internals->dma_config_gpio.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT;
|
||||||
signal->dma_config_gpio.NbData = 2;
|
signal->internals->dma_config_gpio.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT;
|
||||||
signal->dma_config_gpio.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP;
|
signal->internals->dma_config_gpio.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD;
|
||||||
signal->dma_config_gpio.Priority = LL_DMA_PRIORITY_VERYHIGH;
|
signal->internals->dma_config_gpio.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD;
|
||||||
|
signal->internals->dma_config_gpio.NbData = 2;
|
||||||
|
signal->internals->dma_config_gpio.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP;
|
||||||
|
signal->internals->dma_config_gpio.Priority = LL_DMA_PRIORITY_VERYHIGH;
|
||||||
|
|
||||||
signal->dma_config_timer.PeriphOrM2MSrcAddress = (uint32_t) & (TIM2->ARR);
|
signal->internals->dma_config_timer.PeriphOrM2MSrcAddress = (uint32_t) & (TIM2->ARR);
|
||||||
signal->dma_config_timer.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH;
|
signal->internals->dma_config_timer.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH;
|
||||||
signal->dma_config_timer.Mode = LL_DMA_MODE_NORMAL;
|
signal->internals->dma_config_timer.Mode = LL_DMA_MODE_NORMAL;
|
||||||
signal->dma_config_timer.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT;
|
signal->internals->dma_config_timer.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT;
|
||||||
signal->dma_config_timer.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT;
|
signal->internals->dma_config_timer.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT;
|
||||||
signal->dma_config_timer.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD;
|
signal->internals->dma_config_timer.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD;
|
||||||
signal->dma_config_timer.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD;
|
signal->internals->dma_config_timer.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD;
|
||||||
signal->dma_config_timer.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP;
|
signal->internals->dma_config_timer.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP;
|
||||||
signal->dma_config_timer.Priority = LL_DMA_PRIORITY_HIGH;
|
signal->internals->dma_config_timer.Priority = LL_DMA_PRIORITY_HIGH;
|
||||||
|
|
||||||
return signal;
|
return signal;
|
||||||
}
|
}
|
||||||
@@ -48,6 +73,7 @@ void digital_signal_free(DigitalSignal* signal) {
|
|||||||
|
|
||||||
free(signal->edge_timings);
|
free(signal->edge_timings);
|
||||||
free(signal->reload_reg_buff);
|
free(signal->reload_reg_buff);
|
||||||
|
free(signal->internals);
|
||||||
free(signal);
|
free(signal);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,29 +159,30 @@ void digital_signal_prepare_arr(DigitalSignal* signal) {
|
|||||||
furi_assert(signal);
|
furi_assert(signal);
|
||||||
|
|
||||||
/* set up signal polarities */
|
/* set up signal polarities */
|
||||||
if(signal->gpio) {
|
if(signal->internals->gpio) {
|
||||||
uint32_t bit_set = signal->gpio->pin;
|
uint32_t bit_set = signal->internals->gpio->pin;
|
||||||
uint32_t bit_reset = signal->gpio->pin << 16;
|
uint32_t bit_reset = signal->internals->gpio->pin << 16;
|
||||||
|
|
||||||
if(signal->start_level) {
|
if(signal->start_level) {
|
||||||
signal->gpio_buff[0] = bit_set;
|
signal->internals->gpio_buff[0] = bit_set;
|
||||||
signal->gpio_buff[1] = bit_reset;
|
signal->internals->gpio_buff[1] = bit_reset;
|
||||||
} else {
|
} else {
|
||||||
signal->gpio_buff[0] = bit_reset;
|
signal->internals->gpio_buff[0] = bit_reset;
|
||||||
signal->gpio_buff[1] = bit_set;
|
signal->internals->gpio_buff[1] = bit_set;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set up edge timings */
|
/* set up edge timings */
|
||||||
signal->reload_reg_entries = 0;
|
signal->internals->reload_reg_entries = 0;
|
||||||
|
|
||||||
for(size_t pos = 0; pos < signal->edge_cnt; pos++) {
|
for(size_t pos = 0; pos < signal->edge_cnt; pos++) {
|
||||||
uint32_t pulse_duration = signal->edge_timings[pos] + signal->reload_reg_remainder;
|
uint32_t pulse_duration =
|
||||||
|
signal->edge_timings[pos] + signal->internals->reload_reg_remainder;
|
||||||
uint32_t pulse_ticks = (pulse_duration + T_TIM_DIV2) / T_TIM;
|
uint32_t pulse_ticks = (pulse_duration + T_TIM_DIV2) / T_TIM;
|
||||||
signal->reload_reg_remainder = pulse_duration - (pulse_ticks * T_TIM);
|
signal->internals->reload_reg_remainder = pulse_duration - (pulse_ticks * T_TIM);
|
||||||
|
|
||||||
if(pulse_ticks > 1) {
|
if(pulse_ticks > 1) {
|
||||||
signal->reload_reg_buff[signal->reload_reg_entries++] = pulse_ticks - 1;
|
signal->reload_reg_buff[signal->internals->reload_reg_entries++] = pulse_ticks - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -175,18 +202,20 @@ static void digital_signal_stop_timer() {
|
|||||||
static bool digital_signal_setup_dma(DigitalSignal* signal) {
|
static bool digital_signal_setup_dma(DigitalSignal* signal) {
|
||||||
furi_assert(signal);
|
furi_assert(signal);
|
||||||
|
|
||||||
if(!signal->reload_reg_entries) {
|
if(!signal->internals->reload_reg_entries) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
signal->dma_config_gpio.MemoryOrM2MDstAddress = (uint32_t)signal->gpio_buff;
|
signal->internals->dma_config_gpio.MemoryOrM2MDstAddress =
|
||||||
signal->dma_config_gpio.PeriphOrM2MSrcAddress = (uint32_t) & (signal->gpio->port->BSRR);
|
(uint32_t)signal->internals->gpio_buff;
|
||||||
signal->dma_config_timer.MemoryOrM2MDstAddress = (uint32_t)signal->reload_reg_buff;
|
signal->internals->dma_config_gpio.PeriphOrM2MSrcAddress =
|
||||||
signal->dma_config_timer.NbData = signal->reload_reg_entries;
|
(uint32_t) & (signal->internals->gpio->port->BSRR);
|
||||||
|
signal->internals->dma_config_timer.MemoryOrM2MDstAddress = (uint32_t)signal->reload_reg_buff;
|
||||||
|
signal->internals->dma_config_timer.NbData = signal->internals->reload_reg_entries;
|
||||||
|
|
||||||
/* set up DMA channel 1 and 2 for GPIO and timer copy operations */
|
/* set up DMA channel 1 and 2 for GPIO and timer copy operations */
|
||||||
LL_DMA_Init(DMA1, LL_DMA_CHANNEL_1, &signal->dma_config_gpio);
|
LL_DMA_Init(DMA1, LL_DMA_CHANNEL_1, &signal->internals->dma_config_gpio);
|
||||||
LL_DMA_Init(DMA1, LL_DMA_CHANNEL_2, &signal->dma_config_timer);
|
LL_DMA_Init(DMA1, LL_DMA_CHANNEL_2, &signal->internals->dma_config_timer);
|
||||||
|
|
||||||
/* enable both DMA channels */
|
/* enable both DMA channels */
|
||||||
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1);
|
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1);
|
||||||
@@ -220,8 +249,9 @@ void digital_signal_send(DigitalSignal* signal, const GpioPin* gpio) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Configure gpio as output */
|
/* Configure gpio as output */
|
||||||
signal->gpio = gpio;
|
signal->internals->gpio = gpio;
|
||||||
furi_hal_gpio_init(signal->gpio, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
|
furi_hal_gpio_init(
|
||||||
|
signal->internals->gpio, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
|
||||||
|
|
||||||
/* single signal, add a temporary, terminating edge at the end */
|
/* single signal, add a temporary, terminating edge at the end */
|
||||||
signal->edge_timings[signal->edge_cnt++] = 10;
|
signal->edge_timings[signal->edge_cnt++] = 10;
|
||||||
@@ -282,8 +312,8 @@ void digital_sequence_set_signal(
|
|||||||
furi_assert(signal_index < sequence->signals_size);
|
furi_assert(signal_index < sequence->signals_size);
|
||||||
|
|
||||||
sequence->signals[signal_index] = signal;
|
sequence->signals[signal_index] = signal;
|
||||||
signal->gpio = sequence->gpio;
|
signal->internals->gpio = sequence->gpio;
|
||||||
signal->reload_reg_remainder = 0;
|
signal->internals->reload_reg_remainder = 0;
|
||||||
|
|
||||||
digital_signal_prepare_arr(signal);
|
digital_signal_prepare_arr(signal);
|
||||||
}
|
}
|
||||||
@@ -304,54 +334,71 @@ void digital_sequence_add(DigitalSequence* sequence, uint8_t signal_index) {
|
|||||||
sequence->sequence[sequence->sequence_used++] = signal_index;
|
sequence->sequence[sequence->sequence_used++] = signal_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
void digital_signal_update_dma(DigitalSignal* signal) {
|
#if defined(DIGITAL_SIGNAL_PORTABLE_CODE)
|
||||||
|
|
||||||
|
static void digital_signal_update_dma(DigitalSignal* signal) {
|
||||||
|
LL_DMA_SetMemoryAddress(DMA1, LL_DMA_CHANNEL_1, (uint32_t)signal->internals->gpio_buff);
|
||||||
|
LL_DMA_SetMemoryAddress(DMA1, LL_DMA_CHANNEL_2, (uint32_t)signal->reload_reg_buff);
|
||||||
|
LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_1, 2);
|
||||||
|
LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_2, signal->internals->reload_reg_entries);
|
||||||
|
|
||||||
|
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1);
|
||||||
|
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static void digital_signal_update_dma(DigitalSignal* signal) {
|
||||||
volatile uint32_t dma1_data[] = {
|
volatile uint32_t dma1_data[] = {
|
||||||
/* R6 */ (uint32_t) & (DMA1_Channel1->CCR),
|
/* R6 */ (uint32_t) & (DMA1_Channel1->CCR),
|
||||||
/* R7 */ DMA1_Channel1->CCR & ~DMA_CCR_EN,
|
/* R7 */ DMA1_Channel1->CCR & ~DMA_CCR_EN,
|
||||||
/* R8 */ 2,
|
/* R8 */ 2,
|
||||||
/* R9 */ (uint32_t) & (signal->gpio->port->BSRR),
|
/* R9 */ (uint32_t) & (signal->internals->gpio->port->BSRR),
|
||||||
/* R10 */ (uint32_t)signal->gpio_buff,
|
/* R10 */ (uint32_t)signal->internals->gpio_buff,
|
||||||
/* R11 */ DMA1_Channel1->CCR | DMA_CCR_EN};
|
/* R11 */ DMA1_Channel1->CCR | DMA_CCR_EN};
|
||||||
|
|
||||||
volatile uint32_t dma2_data[] = {
|
volatile uint32_t dma2_data[] = {
|
||||||
/* R0 */ (uint32_t) & (DMA1_Channel2->CCR),
|
/* R0 */ (uint32_t) & (DMA1_Channel2->CCR),
|
||||||
/* R1 */ DMA1_Channel2->CCR & ~DMA_CCR_EN,
|
/* R1 */ DMA1_Channel2->CCR & ~DMA_CCR_EN,
|
||||||
/* R2 */ (uint32_t)signal->reload_reg_entries,
|
/* R2 */ (uint32_t)signal->internals->reload_reg_entries,
|
||||||
/* R3 */ (uint32_t) & (TIM2->ARR),
|
/* R3 */ (uint32_t) & (TIM2->ARR),
|
||||||
/* R4 */ (uint32_t)signal->reload_reg_buff,
|
/* R4 */ (uint32_t)signal->reload_reg_buff,
|
||||||
/* R5 */ DMA1_Channel2->CCR | DMA_CCR_EN};
|
/* R5 */ DMA1_Channel2->CCR | DMA_CCR_EN};
|
||||||
|
|
||||||
/* hurry when setting up next transfer */
|
/* hurry when setting up next transfer */
|
||||||
asm volatile("\t"
|
asm volatile(
|
||||||
"MOV r6, %[data1]\n\t"
|
"\t"
|
||||||
"MOV r7, %[data2]\n\t"
|
"MOV r6, %[data1]\n\t"
|
||||||
|
"MOV r7, %[data2]\n\t"
|
||||||
|
|
||||||
"PUSH {r0-r12}\n\t"
|
"PUSH {r0-r12}\n\t"
|
||||||
|
|
||||||
"LDM r7, {r0-r5}\n\t"
|
"LDM r7, {r0-r5}\n\t" /* prepare registers with values to write into DMA config */
|
||||||
"LDM r6, {r6-r11}\n\t"
|
"LDM r6, {r6-r11}\n\t"
|
||||||
|
|
||||||
"loop:\n\t"
|
"loop:\n\t"
|
||||||
"LDR r12, [r0, #4]\n\t"
|
"LDR r12, [r0, #4]\n\t" /* read DMA_CNDTRx to get remaining transfers */
|
||||||
"CMP r12, #0\n\t"
|
"CMP r12, #0\n\t"
|
||||||
"BNE loop\n\t"
|
"BNE loop\n\t"
|
||||||
|
|
||||||
"STM r6, {r7-r10}\n\t" /* disable channel and set up new parameters */
|
"STM r6, {r7-r10}\n\t" /* disable channel and set up new parameters */
|
||||||
"STR r11, [r6, #0]\n\t" /* enable channel again */
|
"STR r11, [r6, #0]\n\t" /* enable channel again */
|
||||||
"STM r0, {r1-r4}\n\t" /* disable channel and set up new parameters */
|
"STM r0, {r1-r4}\n\t" /* disable channel and set up new parameters */
|
||||||
"STR r5, [r0, #0]\n\t" /* enable channel again */
|
"STR r5, [r0, #0]\n\t" /* enable channel again */
|
||||||
|
|
||||||
"POP {r0-r12}\n\t"
|
"POP {r0-r12}\n\t"
|
||||||
|
|
||||||
: /* no outputs*/
|
: /* no outputs*/
|
||||||
: /* inputs */
|
: /* inputs */
|
||||||
[data1] "r"(dma1_data), [data2] "r"(dma2_data)
|
[data1] "r"(dma1_data), [data2] "r"(dma2_data)
|
||||||
: "r6", "r7");
|
: "r6", "r7");
|
||||||
|
|
||||||
LL_DMA_ClearFlag_TC1(DMA1);
|
LL_DMA_ClearFlag_TC1(DMA1);
|
||||||
LL_DMA_ClearFlag_TC2(DMA1);
|
LL_DMA_ClearFlag_TC2(DMA1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
static bool digital_sequence_send_signal(DigitalSequence* sequence, DigitalSignal* signal) {
|
static bool digital_sequence_send_signal(DigitalSequence* sequence, DigitalSignal* signal) {
|
||||||
furi_assert(sequence);
|
furi_assert(sequence);
|
||||||
furi_assert(signal);
|
furi_assert(signal);
|
||||||
@@ -443,7 +490,7 @@ bool digital_sequence_send(DigitalSequence* sequence) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* update the total remainder */
|
/* update the total remainder */
|
||||||
remainder += sig->reload_reg_remainder;
|
remainder += sig->internals->reload_reg_remainder;
|
||||||
|
|
||||||
/* do we need to update the prolongation? */
|
/* do we need to update the prolongation? */
|
||||||
if(needs_prolongation != sequence->signals_prolonged[signal_index]) {
|
if(needs_prolongation != sequence->signals_prolonged[signal_index]) {
|
||||||
|
|||||||
@@ -5,8 +5,6 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include <furi_hal_gpio.h>
|
#include <furi_hal_gpio.h>
|
||||||
#include <stm32wbxx_ll_dma.h>
|
|
||||||
#include <stm32wbxx_ll_tim.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@@ -18,31 +16,20 @@ extern "C" {
|
|||||||
#define DIGITAL_SIGNAL_NS(x) (x * 100UL)
|
#define DIGITAL_SIGNAL_NS(x) (x * 100UL)
|
||||||
#define DIGITAL_SIGNAL_PS(x) (x / 10UL)
|
#define DIGITAL_SIGNAL_PS(x) (x / 10UL)
|
||||||
|
|
||||||
typedef struct {
|
/* using an anonymous type for the internals */
|
||||||
|
typedef struct DigitalSignalInternals DigitalSignalInternals;
|
||||||
|
|
||||||
|
/* and a public one for accessing user-side fields */
|
||||||
|
typedef struct DigitalSignal {
|
||||||
bool start_level;
|
bool start_level;
|
||||||
uint32_t edge_cnt;
|
uint32_t edge_cnt;
|
||||||
uint32_t edges_max_cnt;
|
uint32_t edges_max_cnt;
|
||||||
uint32_t* edge_timings;
|
uint32_t* edge_timings;
|
||||||
uint32_t* reload_reg_buff;
|
uint32_t* reload_reg_buff; /* internal, but used by unit tests */
|
||||||
uint32_t reload_reg_entries;
|
DigitalSignalInternals* internals;
|
||||||
uint32_t reload_reg_remainder;
|
|
||||||
uint32_t gpio_buff[2];
|
|
||||||
const GpioPin* gpio;
|
|
||||||
LL_DMA_InitTypeDef dma_config_gpio;
|
|
||||||
LL_DMA_InitTypeDef dma_config_timer;
|
|
||||||
} DigitalSignal;
|
} DigitalSignal;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct DigitalSequence DigitalSequence;
|
||||||
uint8_t signals_size;
|
|
||||||
bool bake;
|
|
||||||
uint32_t sequence_used;
|
|
||||||
uint32_t sequence_size;
|
|
||||||
DigitalSignal** signals;
|
|
||||||
bool* signals_prolonged;
|
|
||||||
uint8_t* sequence;
|
|
||||||
const GpioPin* gpio;
|
|
||||||
uint32_t send_time;
|
|
||||||
} DigitalSequence;
|
|
||||||
|
|
||||||
DigitalSignal* digital_signal_alloc(uint32_t max_edges_cnt);
|
DigitalSignal* digital_signal_alloc(uint32_t max_edges_cnt);
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,32 @@
|
|||||||
|
#include "pulse_reader.h"
|
||||||
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <furi.h>
|
#include <furi.h>
|
||||||
#include <furi_hal.h>
|
#include <furi_hal.h>
|
||||||
#include <furi_hal_gpio.h>
|
#include <furi_hal_gpio.h>
|
||||||
|
|
||||||
#include "pulse_reader.h"
|
#include <stm32wbxx_ll_dma.h>
|
||||||
|
#include <stm32wbxx_ll_dmamux.h>
|
||||||
|
#include <stm32wbxx_ll_tim.h>
|
||||||
|
#include <stm32wbxx_ll_exti.h>
|
||||||
|
|
||||||
|
struct PulseReader {
|
||||||
|
uint32_t* timer_buffer;
|
||||||
|
uint32_t* gpio_buffer;
|
||||||
|
uint32_t size;
|
||||||
|
uint32_t pos;
|
||||||
|
uint32_t timer_value;
|
||||||
|
uint32_t gpio_value;
|
||||||
|
uint32_t gpio_mask;
|
||||||
|
uint32_t unit_multiplier;
|
||||||
|
uint32_t unit_divider;
|
||||||
|
uint32_t bit_time;
|
||||||
|
uint32_t dma_channel;
|
||||||
|
const GpioPin* gpio;
|
||||||
|
GpioPull pull;
|
||||||
|
LL_DMA_InitTypeDef dma_config_timer;
|
||||||
|
LL_DMA_InitTypeDef dma_config_gpio;
|
||||||
|
};
|
||||||
|
|
||||||
#define GPIO_PIN_MAP(pin, prefix) \
|
#define GPIO_PIN_MAP(pin, prefix) \
|
||||||
(((pin) == (LL_GPIO_PIN_0)) ? prefix##0 : \
|
(((pin) == (LL_GPIO_PIN_0)) ? prefix##0 : \
|
||||||
|
|||||||
@@ -3,10 +3,6 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stm32wbxx_ll_dma.h>
|
|
||||||
#include <stm32wbxx_ll_dmamux.h>
|
|
||||||
#include <stm32wbxx_ll_tim.h>
|
|
||||||
#include <stm32wbxx_ll_exti.h>
|
|
||||||
|
|
||||||
#include <furi_hal_gpio.h>
|
#include <furi_hal_gpio.h>
|
||||||
|
|
||||||
@@ -28,23 +24,8 @@ typedef enum {
|
|||||||
PulseReaderUnitMicrosecond,
|
PulseReaderUnitMicrosecond,
|
||||||
} PulseReaderUnit;
|
} PulseReaderUnit;
|
||||||
|
|
||||||
typedef struct {
|
/* using an anonymous type */
|
||||||
uint32_t* timer_buffer;
|
typedef struct PulseReader PulseReader;
|
||||||
uint32_t* gpio_buffer;
|
|
||||||
uint32_t size;
|
|
||||||
uint32_t pos;
|
|
||||||
uint32_t timer_value;
|
|
||||||
uint32_t gpio_value;
|
|
||||||
uint32_t gpio_mask;
|
|
||||||
uint32_t unit_multiplier;
|
|
||||||
uint32_t unit_divider;
|
|
||||||
uint32_t bit_time;
|
|
||||||
uint32_t dma_channel;
|
|
||||||
const GpioPin* gpio;
|
|
||||||
GpioPull pull;
|
|
||||||
LL_DMA_InitTypeDef dma_config_timer;
|
|
||||||
LL_DMA_InitTypeDef dma_config_gpio;
|
|
||||||
} PulseReader;
|
|
||||||
|
|
||||||
/** Allocate a PulseReader object
|
/** Allocate a PulseReader object
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -27,14 +27,14 @@ Also display type, region and etc...
|
|||||||
## Core1 and Core2 firmware flashing
|
## Core1 and Core2 firmware flashing
|
||||||
|
|
||||||
Core2 goes first, then Core1.
|
Core2 goes first, then Core1.
|
||||||
Never flash FUS or you will loose your job, girlfriend and keys in secure enclave.
|
Never flash FUS or you will lose your job, girlfriend and keys in secure enclave.
|
||||||
|
|
||||||
## Option Bytes
|
## Option Bytes
|
||||||
|
|
||||||
!!! Setting incorrect Option Bytes may brick your MCU !!!
|
!!! Setting incorrect Option Bytes may brick your MCU !!!
|
||||||
|
|
||||||
Defaults are mostly OK, but there are couple things that we'd like to tune.
|
Defaults are mostly OK, but there are couple things that we'd like to tune.
|
||||||
Also OB may be damaged, so we've made couple scripts to check and set option bytes.
|
Also, OB may be damaged, so we've made couple scripts to check and set option bytes.
|
||||||
|
|
||||||
!!! Setting incorrect Option Bytes may brick your MCU !!!
|
!!! Setting incorrect Option Bytes may brick your MCU !!!
|
||||||
|
|
||||||
@@ -69,4 +69,4 @@ Then run
|
|||||||
python scripts/slideshow.py -i assets/slideshow/my_show/ -o assets/slideshow/my_show/.slideshow
|
python scripts/slideshow.py -i assets/slideshow/my_show/ -o assets/slideshow/my_show/.slideshow
|
||||||
```
|
```
|
||||||
|
|
||||||
Upload generated .slideshow file to Flipper's internal storage and restart it.
|
Upload generated .slideshow file to Flipper's internal storage and restart it.
|
||||||
|
|||||||
68
scripts/power.py
Executable file
68
scripts/power.py
Executable file
@@ -0,0 +1,68 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
from flipper.app import App
|
||||||
|
from flipper.storage import FlipperStorage
|
||||||
|
from flipper.utils.cdc import resolve_port
|
||||||
|
|
||||||
|
|
||||||
|
class Main(App):
|
||||||
|
# this is basic use without sub-commands, simply to reboot flipper / power it off, not meant as a full CLI wrapper
|
||||||
|
def init(self):
|
||||||
|
self.parser.add_argument("-p", "--port", help="CDC Port", default="auto")
|
||||||
|
|
||||||
|
self.subparsers = self.parser.add_subparsers(help="sub-command help")
|
||||||
|
|
||||||
|
self.parser_power_off = self.subparsers.add_parser(
|
||||||
|
"power_off", help="Power off command, won't return to CLI"
|
||||||
|
)
|
||||||
|
self.parser_power_off.set_defaults(func=self.power_off)
|
||||||
|
|
||||||
|
self.parser_reboot = self.subparsers.add_parser(
|
||||||
|
"reboot", help="Reboot command help"
|
||||||
|
)
|
||||||
|
self.parser_reboot.set_defaults(func=self.reboot)
|
||||||
|
|
||||||
|
self.parser_reboot2dfu = self.subparsers.add_parser(
|
||||||
|
"reboot2dfu", help="Reboot to DFU, won't return to CLI"
|
||||||
|
)
|
||||||
|
self.parser_reboot2dfu.set_defaults(func=self.reboot2dfu)
|
||||||
|
|
||||||
|
def _get_flipper(self):
|
||||||
|
if not (port := resolve_port(self.logger, self.args.port)):
|
||||||
|
return None
|
||||||
|
|
||||||
|
flipper = FlipperStorage(port)
|
||||||
|
flipper.start()
|
||||||
|
return flipper
|
||||||
|
|
||||||
|
def power_off(self):
|
||||||
|
if not (flipper := self._get_flipper()):
|
||||||
|
return 1
|
||||||
|
|
||||||
|
self.logger.debug("Powering off")
|
||||||
|
flipper.send("power off" + "\r")
|
||||||
|
flipper.stop()
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def reboot(self):
|
||||||
|
if not (flipper := self._get_flipper()):
|
||||||
|
return 1
|
||||||
|
|
||||||
|
self.logger.debug("Rebooting")
|
||||||
|
flipper.send("power reboot" + "\r")
|
||||||
|
flipper.stop()
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def reboot2dfu(self):
|
||||||
|
if not (flipper := self._get_flipper()):
|
||||||
|
return 1
|
||||||
|
|
||||||
|
self.logger.debug("Rebooting to DFU")
|
||||||
|
flipper.send("power reboot2dfu" + "\r")
|
||||||
|
flipper.stop()
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
Main()()
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
import logging
|
||||||
import sys, os, time
|
import os
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
|
|
||||||
def flp_serial_by_name(flp_name):
|
def flp_serial_by_name(flp_name):
|
||||||
@@ -31,6 +33,12 @@ def main():
|
|||||||
flipper_name = sys.argv[1]
|
flipper_name = sys.argv[1]
|
||||||
elapsed = 0
|
elapsed = 0
|
||||||
flipper = flp_serial_by_name(flipper_name)
|
flipper = flp_serial_by_name(flipper_name)
|
||||||
|
logging.basicConfig(
|
||||||
|
format="%(asctime)s %(levelname)-8s %(message)s",
|
||||||
|
level=logging.INFO,
|
||||||
|
datefmt="%Y-%m-%d %H:%M:%S",
|
||||||
|
)
|
||||||
|
logging.info("Waiting for Flipper to be ready...")
|
||||||
|
|
||||||
while flipper == "" and elapsed < UPDATE_TIMEOUT:
|
while flipper == "" and elapsed < UPDATE_TIMEOUT:
|
||||||
elapsed += 1
|
elapsed += 1
|
||||||
@@ -38,9 +46,11 @@ def main():
|
|||||||
flipper = flp_serial_by_name(flipper_name)
|
flipper = flp_serial_by_name(flipper_name)
|
||||||
|
|
||||||
if flipper == "":
|
if flipper == "":
|
||||||
print(f"Cannot find {flipper_name} flipper. Guess your flipper swam away")
|
logging.error("Flipper not found!")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
logging.info(f"Found Flipper at {flipper}")
|
||||||
|
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,28 +1,32 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
import logging
|
||||||
import sys, os
|
|
||||||
import serial
|
|
||||||
import re
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import serial
|
||||||
from await_flipper import flp_serial_by_name
|
from await_flipper import flp_serial_by_name
|
||||||
|
|
||||||
|
|
||||||
LEAK_THRESHOLD = 3000 # added until units are fixed
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
logging.basicConfig(
|
||||||
|
format="%(asctime)s %(levelname)-8s %(message)s",
|
||||||
|
level=logging.INFO,
|
||||||
|
datefmt="%Y-%m-%d %H:%M:%S",
|
||||||
|
)
|
||||||
|
logging.info("Trying to run units on flipper")
|
||||||
flp_serial = flp_serial_by_name(sys.argv[1])
|
flp_serial = flp_serial_by_name(sys.argv[1])
|
||||||
|
|
||||||
if flp_serial == "":
|
if flp_serial == "":
|
||||||
print("Name or serial port is invalid")
|
logging.error("Flipper not found!")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
with serial.Serial(flp_serial, timeout=1) as flipper:
|
with serial.Serial(flp_serial, timeout=1) as flipper:
|
||||||
|
logging.info(f"Found Flipper at {flp_serial}")
|
||||||
flipper.baudrate = 230400
|
flipper.baudrate = 230400
|
||||||
flipper.flushOutput()
|
flipper.flushOutput()
|
||||||
flipper.flushInput()
|
flipper.flushInput()
|
||||||
|
|
||||||
flipper.timeout = 300
|
flipper.timeout = 180
|
||||||
|
|
||||||
flipper.read_until(b">: ").decode("utf-8")
|
flipper.read_until(b">: ").decode("utf-8")
|
||||||
flipper.write(b"unit_tests\r")
|
flipper.write(b"unit_tests\r")
|
||||||
@@ -41,9 +45,13 @@ def main():
|
|||||||
status_pattern = re.compile(status_re)
|
status_pattern = re.compile(status_re)
|
||||||
|
|
||||||
tests, time, leak, status = None, None, None, None
|
tests, time, leak, status = None, None, None, None
|
||||||
|
total = 0
|
||||||
|
|
||||||
for line in lines:
|
for line in lines:
|
||||||
print(line)
|
logging.info(line)
|
||||||
|
if "()" in line:
|
||||||
|
total += 1
|
||||||
|
|
||||||
if not tests:
|
if not tests:
|
||||||
tests = re.match(tests_pattern, line)
|
tests = re.match(tests_pattern, line)
|
||||||
if not time:
|
if not time:
|
||||||
@@ -53,8 +61,8 @@ def main():
|
|||||||
if not status:
|
if not status:
|
||||||
status = re.match(status_pattern, line)
|
status = re.match(status_pattern, line)
|
||||||
|
|
||||||
if leak is None or time is None or leak is None or status is None:
|
if None in (tests, time, leak, status):
|
||||||
print("Failed to get data. Or output is corrupt")
|
logging.error(f"Failed to parse output: {leak} {time} {leak} {status}")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
leak = int(re.findall(r"[- ]\d+", leak.group(0))[0])
|
leak = int(re.findall(r"[- ]\d+", leak.group(0))[0])
|
||||||
@@ -62,16 +70,18 @@ def main():
|
|||||||
tests = int(re.findall(r"\d+", tests.group(0))[0])
|
tests = int(re.findall(r"\d+", tests.group(0))[0])
|
||||||
time = int(re.findall(r"\d+", time.group(0))[0])
|
time = int(re.findall(r"\d+", time.group(0))[0])
|
||||||
|
|
||||||
if tests > 0 or leak > LEAK_THRESHOLD or status != "PASSED":
|
if tests > 0 or status != "PASSED":
|
||||||
print(f"Got {tests} failed tests.")
|
logging.error(f"Got {tests} failed tests.")
|
||||||
print(f"Leaked {leak} bytes.")
|
logging.error(f"Leaked (not failing on this stat): {leak}")
|
||||||
print(f"Status by flipper: {status}")
|
logging.error(f"Status: {status}")
|
||||||
print(f"Time elapsed {time/1000} seconds.")
|
logging.error(f"Time: {time/1000} seconds")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
print(
|
logging.info(f"Leaked (not failing on this stat): {leak}")
|
||||||
f"Tests ran successfully! Time elapsed {time/1000} seconds. Passed {tests} tests."
|
logging.info(
|
||||||
|
f"Tests ran successfully! Time elapsed {time/1000} seconds. Passed {total} tests."
|
||||||
)
|
)
|
||||||
|
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user