From 3108dc7c8c093f6235f201e3bcddf2500f125f92 Mon Sep 17 00:00:00 2001 From: Konstantin Volkov <72250702+doomwastaken@users.noreply.github.com> Date: Wed, 28 Dec 2022 17:16:06 +0300 Subject: [PATCH 1/5] Splitting units and updater benches (#2165) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * test run, moved updated to separate physical runner/flipper/card * simplified units, removed re-flashing, moved format to beginning of run * added reboot requence and mini optimizations * forgot gitadd, added script modifications, workflow changes * fixed linter issues * moved updater to unit bench for speed up * changes to units, flash (not full) on second update, new fbt GDB thread check * changed serial of second device * testing pipelines, added failing unit test * fixed gdb step * fixed gdb step v2 electric boogaloo * fixed gdb step v3, fixed target * reverted while1 in units, tests complete * testing colored output * trying different term setting * debug outputs for terminal * fixed typo in SConstruct and another terminal test * reverted changes, no colored output, for production * fixed log output to readable format * fixed linter Co-authored-by: Konstantin Volkov Co-authored-by: あく --- .github/workflows/unit_tests.yml | 71 ++++++--------------------- .github/workflows/updater_test.yml | 77 ++++++++++++++++++++++++++++++ SConstruct | 14 ++++++ scripts/power.py | 68 ++++++++++++++++++++++++++ scripts/testing/await_flipper.py | 16 +++++-- scripts/testing/units.py | 46 +++++++++++------- 6 files changed, 214 insertions(+), 78 deletions(-) create mode 100644 .github/workflows/updater_test.yml create mode 100755 scripts/power.py diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index eb687b6c9..ac3fc3684 100644 --- a/.github/workflows/unit_tests.yml +++ b/.github/workflows/unit_tests.yml @@ -9,7 +9,7 @@ env: FBT_TOOLCHAIN_PATH: /opt jobs: - run_units_on_test_bench: + run_units_on_bench: runs-on: [self-hosted, FlipperZeroTest] steps: - name: 'Decontaminate previous build leftovers' @@ -29,81 +29,38 @@ jobs: run: | 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' id: flashing if: success() - run: | + run: | ./fbt flash OPENOCD_ADAPTER_SERIAL=2A0906016415303030303032 FIRMWARE_APP_SET=unit_tests FORCE=1 - - name: 'Wait for flipper to finish updating' - id: connect + - name: 'Wait for flipper and format ext' + id: format_ext if: steps.flashing.outcome == 'success' 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 - - name: 'Copy assets and unit tests data to flipper' + - name: 'Copy assets and unit data, reboot and wait for flipper' id: copy - if: steps.connect.outcome == 'success' + if: steps.format_ext.outcome == 'success' run: | 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/power.py -p ${{steps.device.outputs.flipper}} reboot + python3 scripts/testing/await_flipper.py ${{steps.device.outputs.flipper}} - name: 'Run units and validate results' + id: run_units if: steps.copy.outcome == 'success' run: | source scripts/toolchain/fbtenv.sh python3 scripts/testing/units.py ${{steps.device.outputs.flipper}} - - name: 'Get last release tag' - id: release_tag - if: always() + - name: 'Check GDB output' + 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: 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 + ./fbt gdb_trace_all OPENOCD_ADAPTER_SERIAL=2A0906016415303030303032 FIRMWARE_APP_SET=unit_tests FORCE=1 diff --git a/.github/workflows/updater_test.yml b/.github/workflows/updater_test.yml new file mode 100644 index 000000000..d4ca56fad --- /dev/null +++ b/.github/workflows/updater_test.yml @@ -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 diff --git a/SConstruct b/SConstruct index 474175c14..138b52d93 100644 --- a/SConstruct +++ b/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 firmware_debug = distenv.PhonyTarget( "debug", diff --git a/scripts/power.py b/scripts/power.py new file mode 100755 index 000000000..45a130c59 --- /dev/null +++ b/scripts/power.py @@ -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()() diff --git a/scripts/testing/await_flipper.py b/scripts/testing/await_flipper.py index 704d75a75..2b4c8b4c3 100755 --- a/scripts/testing/await_flipper.py +++ b/scripts/testing/await_flipper.py @@ -1,6 +1,8 @@ #!/usr/bin/env python3 - -import sys, os, time +import logging +import os +import sys +import time def flp_serial_by_name(flp_name): @@ -31,6 +33,12 @@ def main(): flipper_name = sys.argv[1] elapsed = 0 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: elapsed += 1 @@ -38,9 +46,11 @@ def main(): flipper = flp_serial_by_name(flipper_name) if flipper == "": - print(f"Cannot find {flipper_name} flipper. Guess your flipper swam away") + logging.error("Flipper not found!") sys.exit(1) + logging.info(f"Found Flipper at {flipper}") + sys.exit(0) diff --git a/scripts/testing/units.py b/scripts/testing/units.py index 83b07899a..5083bcd43 100755 --- a/scripts/testing/units.py +++ b/scripts/testing/units.py @@ -1,28 +1,32 @@ #!/usr/bin/env python3 - -import sys, os -import serial +import logging import re +import sys +import serial from await_flipper import flp_serial_by_name -LEAK_THRESHOLD = 3000 # added until units are fixed - - 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]) if flp_serial == "": - print("Name or serial port is invalid") + logging.error("Flipper not found!") sys.exit(1) with serial.Serial(flp_serial, timeout=1) as flipper: + logging.info(f"Found Flipper at {flp_serial}") flipper.baudrate = 230400 flipper.flushOutput() flipper.flushInput() - flipper.timeout = 300 + flipper.timeout = 180 flipper.read_until(b">: ").decode("utf-8") flipper.write(b"unit_tests\r") @@ -41,9 +45,13 @@ def main(): status_pattern = re.compile(status_re) tests, time, leak, status = None, None, None, None + total = 0 for line in lines: - print(line) + logging.info(line) + if "()" in line: + total += 1 + if not tests: tests = re.match(tests_pattern, line) if not time: @@ -53,8 +61,8 @@ def main(): if not status: status = re.match(status_pattern, line) - if leak is None or time is None or leak is None or status is None: - print("Failed to get data. Or output is corrupt") + if None in (tests, time, leak, status): + logging.error(f"Failed to parse output: {leak} {time} {leak} {status}") sys.exit(1) 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]) time = int(re.findall(r"\d+", time.group(0))[0]) - if tests > 0 or leak > LEAK_THRESHOLD or status != "PASSED": - print(f"Got {tests} failed tests.") - print(f"Leaked {leak} bytes.") - print(f"Status by flipper: {status}") - print(f"Time elapsed {time/1000} seconds.") + if tests > 0 or status != "PASSED": + logging.error(f"Got {tests} failed tests.") + logging.error(f"Leaked (not failing on this stat): {leak}") + logging.error(f"Status: {status}") + logging.error(f"Time: {time/1000} seconds") sys.exit(1) - print( - f"Tests ran successfully! Time elapsed {time/1000} seconds. Passed {tests} tests." + logging.info(f"Leaked (not failing on this stat): {leak}") + logging.info( + f"Tests ran successfully! Time elapsed {time/1000} seconds. Passed {total} tests." ) + sys.exit(0) From 27ee0f73f7b81e6791c07f036939015dec9f6a85 Mon Sep 17 00:00:00 2001 From: Konstantin Volkov <72250702+doomwastaken@users.noreply.github.com> Date: Wed, 28 Dec 2022 17:30:20 +0300 Subject: [PATCH 2/5] Fixing various typos in readme files #2208 Co-authored-by: Konstantin Volkov --- .github/ISSUE_TEMPLATE/03_feature_request.yml | 2 +- CODING_STYLE.md | 14 +++++++------- CONTRIBUTING.md | 6 +++--- assets/dolphin/ReadMe.md | 2 +- documentation/AppManifests.md | 2 ++ documentation/AppsOnSDCard.md | 2 +- documentation/file_formats/BadUsbScriptFormat.md | 2 +- documentation/file_formats/InfraredFileFormats.md | 10 +++++----- documentation/file_formats/NfcFileFormats.md | 2 +- documentation/file_formats/SubGhzFileFormats.md | 2 +- firmware/ReadMe.md | 4 ++-- lib/ReadMe.md | 2 +- scripts/ReadMe.md | 6 +++--- 13 files changed, 29 insertions(+), 27 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/03_feature_request.yml b/.github/ISSUE_TEMPLATE/03_feature_request.yml index 2af114547..052cd3404 100644 --- a/.github/ISSUE_TEMPLATE/03_feature_request.yml +++ b/.github/ISSUE_TEMPLATE/03_feature_request.yml @@ -14,7 +14,7 @@ body: description: | Please describe your feature request in as many details as possible. - 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: required: true - type: textarea diff --git a/CODING_STYLE.md b/CODING_STYLE.md index 31426b941..6c7d6d792 100644 --- a/CODING_STYLE.md +++ b/CODING_STYLE.md @@ -3,15 +3,15 @@ Nice to see you reading this document, we really appreciate it. 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, -but it got it's limitations and this guide is still mandatory. +Also, we already have automatic rules checking and formatting, +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. -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. 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. 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. Use project wiki to document new/reverse engineered standards. @@ -89,7 +89,7 @@ Enforced by linter. Suffixes: - `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 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index dc1d41e27..3f4853116 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -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. - Your PR must comply with our [Coding Style](CODING_STYLE.md) - 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 pass review by code owner. +- PR will only be merged if it passes CI/CD. +- PR will only be merged if it passes review by code owner. 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 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. - 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. diff --git a/assets/dolphin/ReadMe.md b/assets/dolphin/ReadMe.md index 643086c26..e7572571c 100644 --- a/assets/dolphin/ReadMe.md +++ b/assets/dolphin/ReadMe.md @@ -26,7 +26,7 @@ Version: 1 - `Name` - name of animation. Must be exact animation directory name. - `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. -- `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`. diff --git a/documentation/AppManifests.md b/documentation/AppManifests.md index 10970bdba..2ffa3c0c2 100644 --- a/documentation/AppManifests.md +++ b/documentation/AppManifests.md @@ -57,8 +57,10 @@ The following parameters are used only for [FAPs](./AppsOnSDCard.md): * **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_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`**. + Example for building an app from Rust sources: ```python diff --git a/documentation/AppsOnSDCard.md b/documentation/AppsOnSDCard.md index 4acb3ec37..d38837276 100644 --- a/documentation/AppsOnSDCard.md +++ b/documentation/AppsOnSDCard.md @@ -37,7 +37,7 @@ With it, you can debug FAPs as if they were a part of main firmware — inspect ### 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: 1. Build firmware with `./fbt` diff --git a/documentation/file_formats/BadUsbScriptFormat.md b/documentation/file_formats/BadUsbScriptFormat.md index 321eff246..713a9ff26 100644 --- a/documentation/file_formats/BadUsbScriptFormat.md +++ b/documentation/file_formats/BadUsbScriptFormat.md @@ -1,5 +1,5 @@ # 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 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 diff --git a/documentation/file_formats/InfraredFileFormats.md b/documentation/file_formats/InfraredFileFormats.md index a6d6c276d..409bf26e8 100644 --- a/documentation/file_formats/InfraredFileFormats.md +++ b/documentation/file_formats/InfraredFileFormats.md @@ -95,17 +95,17 @@ Note: a single parsed signal must be represented as an array of size 1. | data | raw | uint32 | Ditto. | #### Signal names -The signal names in an `.irtest` file folow a convention ``, where the name is one of: +The signal names in an `.irtest` file follow a convention ``, where the name is one of: - decoder_input - decoder_expected - 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. -| Name | Type | Description | -| --------------------- | ------------ | ----------- | -| decoder_input | raw | A raw signal contaning the decoder input. Is also used as the expected encoder output. | +| Name | Type | Description | +| --------------------- | ------------ |-------------------------------------------------------------------------------------------------------| +| 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. | -| 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. diff --git a/documentation/file_formats/NfcFileFormats.md b/documentation/file_formats/NfcFileFormats.md index 90dcaea1c..e04f3b68c 100644 --- a/documentation/file_formats/NfcFileFormats.md +++ b/documentation/file_formats/NfcFileFormats.md @@ -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: (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: (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: (page 21) Other fields are the direct representation of the card's internal state, more on them can be found in the same datasheet. diff --git a/documentation/file_formats/SubGhzFileFormats.md b/documentation/file_formats/SubGhzFileFormats.md index ae80e6e0e..1446ecd0d 100644 --- a/documentation/file_formats/SubGhzFileFormats.md +++ b/documentation/file_formats/SubGhzFileFormats.md @@ -197,7 +197,7 @@ For each key, a name and encryption method must be specified, according to comme ## 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 diff --git a/firmware/ReadMe.md b/firmware/ReadMe.md index d2baedfd1..c39f8c4ab 100644 --- a/firmware/ReadMe.md +++ b/firmware/ReadMe.md @@ -14,9 +14,9 @@ What does it do? |-----------|-------------------|-----------------------|-----------------------| | 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` # Building -Check out `documentation/fbt.md` on how to build and flash firmware. \ No newline at end of file +Check out `documentation/fbt.md` on how to build and flash firmware. diff --git a/lib/ReadMe.md b/lib/ReadMe.md index 9cd846a0a..82dcb74c7 100644 --- a/lib/ReadMe.md +++ b/lib/ReadMe.md @@ -11,7 +11,7 @@ - `infrared` - Infrared library - `libusb_stm32` - STM32 USB library - `littlefs` - Internal storage file system -- `micro-ecc` - Elliptic Curve Crpytography library +- `micro-ecc` - Elliptic Curve Crytography library - `microtar` - TAR archive support library - `mlib` - Algorithms and containers - `nanopb` - Nano Protobuf library diff --git a/scripts/ReadMe.md b/scripts/ReadMe.md index d37e67c90..a9feba11b 100644 --- a/scripts/ReadMe.md +++ b/scripts/ReadMe.md @@ -27,14 +27,14 @@ Also display type, region and etc... ## Core1 and Core2 firmware flashing 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 !!! Setting incorrect Option Bytes may brick your MCU !!! 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 !!! @@ -69,4 +69,4 @@ Then run 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. \ No newline at end of file +Upload generated .slideshow file to Flipper's internal storage and restart it. From 4accce93cfaacee809e431bd9d33363344974ca2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zo=C3=AB=20Prosvetova?= <109866245+ZoeMeetAgain@users.noreply.github.com> Date: Wed, 28 Dec 2022 15:39:36 +0100 Subject: [PATCH 3/5] Update KeyCombo.md (#2213) Grammatical corrections and changes --- documentation/KeyCombo.md | 52 +++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/documentation/KeyCombo.md b/documentation/KeyCombo.md index e6f55dc52..93ceb204c 100644 --- a/documentation/KeyCombo.md +++ b/documentation/KeyCombo.md @@ -1,6 +1,6 @@ # 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. @@ -12,10 +12,10 @@ In that case, you may find this guide useful. - Press `LEFT` and `BACK` and hold for a couple of seconds - 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) -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. @@ -25,32 +25,32 @@ There is 1 case when it's not working: - Disconnect USB and any external power supplies - Disconnect USB once again - 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 - Release `BACK` key This combo performs a reset by switching SYS power line off and then on. 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 ### 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 - 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 @@ -65,25 +65,25 @@ There is 1 case when it's not working: - Device will enter DFU with indication (Blue LED + DFU Screen) - Release `LEFT` -This combo performs hardware reset by pulling MCU reset line down. -Then `LEFT` key indicates to boot-loader that DFU mode is requested. +This combo performs a hardware reset by pulling MCU reset line down. +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 -- Flipper Boot-loader is damaged or absent +- Flipper boot-loader is damaged or absent ### 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` - Device will enter DFU without indication -This combo performs hardware reset by pulling MCU reset line down. -Then `OK` key forces MCU to load internal boot-loader. +This combo performs a hardware reset by pulling MCU reset line down. +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 - 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` - Device will enter DFU with indication (Blue LED + DFU Screen) - Release `LEFT` -- Plug USB +- Plug in USB -This combo performs reset by switching SYS power line off and then on. -Then `LEFT` key indicates to boot-loader that DFU mode requested. +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. -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 -- Flipper Boot-loader is damaged or absent +- Flipper boot-loader is damaged or absent ### Hardware Power Reset + Hardware DFU @@ -115,10 +115,10 @@ There are 2 cases when it's not working: - Device will enter DFU without indication - Plug USB -This combo performs reset by switching SYS power line off and then on. -Then `OK` key forces MCU to load internal boot-loader. +This combo performs a reset by switching SYS power line off and then on. +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 - 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) - 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. \ No newline at end of file From d58b9f3fe84f6a0ce1f2e8dc88e3a8f946bbd1f7 Mon Sep 17 00:00:00 2001 From: Astra <93453568+Astrrra@users.noreply.github.com> Date: Wed, 28 Dec 2022 17:09:33 +0200 Subject: [PATCH 4/5] Fix MFC bruteforce progress bar (#2203) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- applications/main/nfc/views/dict_attack.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/applications/main/nfc/views/dict_attack.c b/applications/main/nfc/views/dict_attack.c index 5ae204a06..a539e514b 100644 --- a/applications/main/nfc/views/dict_attack.c +++ b/applications/main/nfc/views/dict_attack.c @@ -60,7 +60,13 @@ static void dict_attack_draw_callback(Canvas* canvas, void* model) { if(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); canvas_set_font(canvas, FontSecondary); snprintf(draw_str, sizeof(draw_str), "Keys found: %d/%d", m->keys_found, m->keys_total); From 3a42ab189f526af8c29447177618cc184ba96ebe Mon Sep 17 00:00:00 2001 From: "g3gg0.de" Date: Wed, 28 Dec 2022 22:43:39 +0100 Subject: [PATCH 5/5] make structures private, add C implementation of digital_signal_update_dma() --- lib/digital_signal/digital_signal.c | 179 ++++++++++++++++++---------- lib/digital_signal/digital_signal.h | 29 ++--- lib/pulse_reader/pulse_reader.c | 25 +++- lib/pulse_reader/pulse_reader.h | 23 +--- 4 files changed, 147 insertions(+), 109 deletions(-) diff --git a/lib/digital_signal/digital_signal.c b/lib/digital_signal/digital_signal.c index 9ba5cc901..12b543273 100644 --- a/lib/digital_signal/digital_signal.c +++ b/lib/digital_signal/digital_signal.c @@ -4,6 +4,30 @@ #include #include +#include +#include + +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 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_cnt = 0; 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->dma_config_gpio.Mode = LL_DMA_MODE_CIRCULAR; - signal->dma_config_gpio.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; - signal->dma_config_gpio.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; - signal->dma_config_gpio.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; - signal->dma_config_gpio.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; - signal->dma_config_gpio.NbData = 2; - signal->dma_config_gpio.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; - signal->dma_config_gpio.Priority = LL_DMA_PRIORITY_VERYHIGH; + signal->internals = malloc(sizeof(DigitalSignalInternals)); + signal->internals->reload_reg_entries = 0; + signal->internals->reload_reg_remainder = 0; + signal->internals->dma_config_gpio.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; + signal->internals->dma_config_gpio.Mode = LL_DMA_MODE_CIRCULAR; + signal->internals->dma_config_gpio.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; + signal->internals->dma_config_gpio.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; + signal->internals->dma_config_gpio.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; + 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->dma_config_timer.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; - signal->dma_config_timer.Mode = LL_DMA_MODE_NORMAL; - signal->dma_config_timer.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; - signal->dma_config_timer.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; - signal->dma_config_timer.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; - signal->dma_config_timer.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; - signal->dma_config_timer.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; - signal->dma_config_timer.Priority = LL_DMA_PRIORITY_HIGH; + signal->internals->dma_config_timer.PeriphOrM2MSrcAddress = (uint32_t) & (TIM2->ARR); + signal->internals->dma_config_timer.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; + signal->internals->dma_config_timer.Mode = LL_DMA_MODE_NORMAL; + signal->internals->dma_config_timer.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; + signal->internals->dma_config_timer.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; + signal->internals->dma_config_timer.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; + signal->internals->dma_config_timer.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; + signal->internals->dma_config_timer.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; + signal->internals->dma_config_timer.Priority = LL_DMA_PRIORITY_HIGH; return signal; } @@ -48,6 +73,7 @@ void digital_signal_free(DigitalSignal* signal) { free(signal->edge_timings); free(signal->reload_reg_buff); + free(signal->internals); free(signal); } @@ -133,29 +159,30 @@ void digital_signal_prepare_arr(DigitalSignal* signal) { furi_assert(signal); /* set up signal polarities */ - if(signal->gpio) { - uint32_t bit_set = signal->gpio->pin; - uint32_t bit_reset = signal->gpio->pin << 16; + if(signal->internals->gpio) { + uint32_t bit_set = signal->internals->gpio->pin; + uint32_t bit_reset = signal->internals->gpio->pin << 16; if(signal->start_level) { - signal->gpio_buff[0] = bit_set; - signal->gpio_buff[1] = bit_reset; + signal->internals->gpio_buff[0] = bit_set; + signal->internals->gpio_buff[1] = bit_reset; } else { - signal->gpio_buff[0] = bit_reset; - signal->gpio_buff[1] = bit_set; + signal->internals->gpio_buff[0] = bit_reset; + signal->internals->gpio_buff[1] = bit_set; } } /* 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++) { - 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; - 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) { - 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) { furi_assert(signal); - if(!signal->reload_reg_entries) { + if(!signal->internals->reload_reg_entries) { return false; } - signal->dma_config_gpio.MemoryOrM2MDstAddress = (uint32_t)signal->gpio_buff; - signal->dma_config_gpio.PeriphOrM2MSrcAddress = (uint32_t) & (signal->gpio->port->BSRR); - signal->dma_config_timer.MemoryOrM2MDstAddress = (uint32_t)signal->reload_reg_buff; - signal->dma_config_timer.NbData = signal->reload_reg_entries; + signal->internals->dma_config_gpio.MemoryOrM2MDstAddress = + (uint32_t)signal->internals->gpio_buff; + signal->internals->dma_config_gpio.PeriphOrM2MSrcAddress = + (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 */ - LL_DMA_Init(DMA1, LL_DMA_CHANNEL_1, &signal->dma_config_gpio); - LL_DMA_Init(DMA1, LL_DMA_CHANNEL_2, &signal->dma_config_timer); + LL_DMA_Init(DMA1, LL_DMA_CHANNEL_1, &signal->internals->dma_config_gpio); + LL_DMA_Init(DMA1, LL_DMA_CHANNEL_2, &signal->internals->dma_config_timer); /* enable both DMA channels */ 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 */ - signal->gpio = gpio; - furi_hal_gpio_init(signal->gpio, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); + signal->internals->gpio = gpio; + furi_hal_gpio_init( + signal->internals->gpio, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); /* single signal, add a temporary, terminating edge at the end */ signal->edge_timings[signal->edge_cnt++] = 10; @@ -282,8 +312,8 @@ void digital_sequence_set_signal( furi_assert(signal_index < sequence->signals_size); sequence->signals[signal_index] = signal; - signal->gpio = sequence->gpio; - signal->reload_reg_remainder = 0; + signal->internals->gpio = sequence->gpio; + signal->internals->reload_reg_remainder = 0; 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; } -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[] = { /* R6 */ (uint32_t) & (DMA1_Channel1->CCR), /* R7 */ DMA1_Channel1->CCR & ~DMA_CCR_EN, /* R8 */ 2, - /* R9 */ (uint32_t) & (signal->gpio->port->BSRR), - /* R10 */ (uint32_t)signal->gpio_buff, + /* R9 */ (uint32_t) & (signal->internals->gpio->port->BSRR), + /* R10 */ (uint32_t)signal->internals->gpio_buff, /* R11 */ DMA1_Channel1->CCR | DMA_CCR_EN}; volatile uint32_t dma2_data[] = { /* R0 */ (uint32_t) & (DMA1_Channel2->CCR), /* 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), /* R4 */ (uint32_t)signal->reload_reg_buff, /* R5 */ DMA1_Channel2->CCR | DMA_CCR_EN}; /* hurry when setting up next transfer */ - asm volatile("\t" - "MOV r6, %[data1]\n\t" - "MOV r7, %[data2]\n\t" + asm volatile( + "\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 r6, {r6-r11}\n\t" + "LDM r7, {r0-r5}\n\t" /* prepare registers with values to write into DMA config */ + "LDM r6, {r6-r11}\n\t" - "loop:\n\t" - "LDR r12, [r0, #4]\n\t" - "CMP r12, #0\n\t" - "BNE loop\n\t" + "loop:\n\t" + "LDR r12, [r0, #4]\n\t" /* read DMA_CNDTRx to get remaining transfers */ + "CMP r12, #0\n\t" + "BNE loop\n\t" - "STM r6, {r7-r10}\n\t" /* disable channel and set up new parameters */ - "STR r11, [r6, #0]\n\t" /* enable channel again */ - "STM r0, {r1-r4}\n\t" /* disable channel and set up new parameters */ - "STR r5, [r0, #0]\n\t" /* enable channel again */ + "STM r6, {r7-r10}\n\t" /* disable channel and set up new parameters */ + "STR r11, [r6, #0]\n\t" /* enable channel again */ + "STM r0, {r1-r4}\n\t" /* disable channel and set up new parameters */ + "STR r5, [r0, #0]\n\t" /* enable channel again */ - "POP {r0-r12}\n\t" + "POP {r0-r12}\n\t" - : /* no outputs*/ - : /* inputs */ - [data1] "r"(dma1_data), [data2] "r"(dma2_data) - : "r6", "r7"); + : /* no outputs*/ + : /* inputs */ + [data1] "r"(dma1_data), [data2] "r"(dma2_data) + : "r6", "r7"); LL_DMA_ClearFlag_TC1(DMA1); LL_DMA_ClearFlag_TC2(DMA1); } +#endif + static bool digital_sequence_send_signal(DigitalSequence* sequence, DigitalSignal* signal) { furi_assert(sequence); furi_assert(signal); @@ -443,7 +490,7 @@ bool digital_sequence_send(DigitalSequence* sequence) { } /* update the total remainder */ - remainder += sig->reload_reg_remainder; + remainder += sig->internals->reload_reg_remainder; /* do we need to update the prolongation? */ if(needs_prolongation != sequence->signals_prolonged[signal_index]) { diff --git a/lib/digital_signal/digital_signal.h b/lib/digital_signal/digital_signal.h index 9a91c8b45..2cb107486 100644 --- a/lib/digital_signal/digital_signal.h +++ b/lib/digital_signal/digital_signal.h @@ -5,8 +5,6 @@ #include #include -#include -#include #ifdef __cplusplus extern "C" { @@ -18,31 +16,20 @@ extern "C" { #define DIGITAL_SIGNAL_NS(x) (x * 100UL) #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; uint32_t edge_cnt; uint32_t edges_max_cnt; uint32_t* edge_timings; - uint32_t* reload_reg_buff; - 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; + uint32_t* reload_reg_buff; /* internal, but used by unit tests */ + DigitalSignalInternals* internals; } DigitalSignal; -typedef struct { - 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; +typedef struct DigitalSequence DigitalSequence; DigitalSignal* digital_signal_alloc(uint32_t max_edges_cnt); diff --git a/lib/pulse_reader/pulse_reader.c b/lib/pulse_reader/pulse_reader.c index 3d9508f9a..84ce2ff23 100644 --- a/lib/pulse_reader/pulse_reader.c +++ b/lib/pulse_reader/pulse_reader.c @@ -1,9 +1,32 @@ +#include "pulse_reader.h" + #include #include #include #include -#include "pulse_reader.h" +#include +#include +#include +#include + +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) \ (((pin) == (LL_GPIO_PIN_0)) ? prefix##0 : \ diff --git a/lib/pulse_reader/pulse_reader.h b/lib/pulse_reader/pulse_reader.h index be0ad7012..08056a0ac 100644 --- a/lib/pulse_reader/pulse_reader.h +++ b/lib/pulse_reader/pulse_reader.h @@ -3,10 +3,6 @@ #include #include #include -#include -#include -#include -#include #include @@ -28,23 +24,8 @@ typedef enum { PulseReaderUnitMicrosecond, } PulseReaderUnit; -typedef struct { - 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; -} PulseReader; +/* using an anonymous type */ +typedef struct PulseReader PulseReader; /** Allocate a PulseReader object *