diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..372557fb --- /dev/null +++ b/.gitattributes @@ -0,0 +1,30 @@ +LICENSE text eol=lf +*.md text eol=lf +*.c text eol=lf +*.cc text eol=lf +*.h text eol=lf +*.cc text eol=lf +*.S text eol=lf +*.s text eol=lf +*.hex -crlf -diff +*.elf -crlf -diff +*.ld text eol=lf +Makefile text eol=lf +*.mk text eol=lf +*.nomk text eol=lf +*.pl text eol=lf +*.js text eol=lf +*.json text eol=lf +*.html text eol=lf +*.css text eol=lf +*.svg text eol=lf +*.png -crlf -diff +*.yml text eol=lf +*.xml text eol=lf +*.mcm text eol=lf +*.nsi text eol=lf +*.nsh text eol=lf +*.lua text eol=lf +*.txt text eol=lf +*.sh text eol=lf +*.config text eol=lf diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..86e8d583 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,2 @@ +custom: https://paypal.me/betaflight +patreon: betaflight diff --git a/.github/issue_template.md b/.github/issue_template.md new file mode 100644 index 00000000..5c797982 --- /dev/null +++ b/.github/issue_template.md @@ -0,0 +1,12 @@ +# If your issue looks like a hardware fault or a configuration problem please don't raise an issue here. + +## Please consider using other user support options such as asking the manufacturer of the hardware you are using, RCGroups: https://rcgroups.com/forums/showthread.php?t=2464844, or Slack (registration at https://slack.betaflight.com/) or other user support forums & groups (e.g. Facebook). + +## If you believe there is an issue with the firmware itself please follow these steps: +1. Describe your problem; +2. Include ways to reproduce the problem; +3. Provide as much information as possible about your hardware and software, including: +- what hardware / software you are using; +- the version of all the software used; +- how things are connected / wired up. +4. Remove this Text :). diff --git a/.github/no-response.yml b/.github/no-response.yml new file mode 100644 index 00000000..f6a2a8d9 --- /dev/null +++ b/.github/no-response.yml @@ -0,0 +1,12 @@ +# Configuration for probot-no-response - https://github.com/probot/no-response + +# Number of days of inactivity before an Issue is closed for lack of response +daysUntilClose: 1 +# Label requiring a response +responseRequiredLabel: Missing Information +# Comment to post when closing an Issue for lack of response. Set to `false` to disable +closeComment: > + This issue has been automatically closed because the information we asked + to be provided when opening it was not supplied by the original author. + With only the information that is currently in the issue, we don't have + enough information to take action. diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 00000000..a509065d --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,19 @@ +## Important considerations when opening a pull request: + +1. Make sure you do not make the changes you want to open a pull request for on the `master` branch of your fork, or open the pull request from the `master` branch of your fork. Some of our integrations will fail if you do this, resulting in your pull request not being accepted. If this is your first pull request, it is probably a good idea to first read up on how opening pull requests work (https://opensource.com/article/19/7/create-pull-request-github is a good introduction); + +2. Pull requests will only be accepted if they are opened against the `master` branch of our repository. Pull requests opened against other branches without prior consent from the maintainers will be closed; + +3. Please follow the coding style guidelines: https://github.com/betaflight/betaflight/blob/master/docs/development/CodingStyle.md + +4. Keep your pull requests as small and concise as possible. One pull request should only ever add / update one feature. If the change that you are proposing has a wider scope, consider splitting it over multiple pull requests. In particular, pull requests that combine changes to features and one or more new targets are not acceptable. + +5. Ideally, a pull request should contain only one commit, with a descriptive message. If your changes use more than one commit, rebase / squash them into one commit before submitting a pull request. If you need to amend your pull request, make sure that the additional commit has a descriptive message, or - even better - use `git commit --amend` to amend your original commit. + +6. All pull requests are reviewed. Be ready to receive constructive criticism, and to learn and improve your coding style. Also, be ready to clarify anything that isn't already sufficiently explained in the code and text of the pull request, and to defend your ideas. + +7. We use continuous integration (CI) with [Travis](https://travis-ci.com/betaflight) to build all targets and run the test suite for every pull request. Pull requests that fail any of the builds or fail tests will most likely not be reviewed before they are fixed to build successfully and pass the tests. In order to get a quick idea if there are things that need fixing **before** opening a pull request or pushing an update into an existing pull request, run `make pre-push` to run a representative subset of the CI build. _Note: This is not an exhaustive test (which will take hours to run on any desktop type system), so even if this passes the CI build might still fail._ + +8. If your pull request is a fix for one or more issues that are open in GitHub, add a comment to your pull request, and add the issue numbers of the issues that are fixed in the form `Fixes #`. This will cause the issues to be closed when the pull request is merged; + +9. Remove this Text :). diff --git a/.github/release.yml b/.github/release.yml new file mode 100644 index 00000000..6c1dd378 --- /dev/null +++ b/.github/release.yml @@ -0,0 +1,26 @@ +changelog: + exclude: + labels: + - "cleanup" + - "RN: IGNORE" + categories: + - title: Features + labels: + - "RN: FEATURE" + - "RN: MAJOR FEATURE" + - "RN: MINOR FEATURE" + - title: Improvements + labels: + - "RN: IMPROVEMENT" + - "RN: UI" + - "RN: REFACTOR" + - "RN: FONT" + - title: Fixes + labels: + - "RN: BUGFIX" + - title: Translation + labels: + - "RN: TRANSLATION" + - title: Known Issues + labels: + - BUG diff --git a/.github/stale.yml b/.github/stale.yml deleted file mode 100644 index 74406576..00000000 --- a/.github/stale.yml +++ /dev/null @@ -1,55 +0,0 @@ -# Configuration for probot-stale - https://github.com/probot/stale - -# Number of days of inactivity before an Issue or Pull Request becomes stale -daysUntilStale: 30 - -# Number of days of inactivity before a stale Issue or Pull Request is closed. -# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. -daysUntilClose: 7 - -# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable -exemptLabels: - - BUG - - Feature Request - - Pinned - -# Set to true to ignore issues in a project (defaults to false) -exemptProjects: false - -# Set to true to ignore issues in a milestone (defaults to false) -exemptMilestones: true - -# Label to use when marking as stale -staleLabel: Inactive - -# Comment to post when marking as stale. Set to `false` to disable -markComment: > - This issue / pull request has been automatically marked as stale because it - has not had recent activity. It will be closed if no further activity occurs - within a week. - -# Comment to post when removing the stale label. -# unmarkComment: > -# Your comment here. - -# Comment to post when closing a stale Issue or Pull Request. -closeComment: > - Automatically closing as inactive. - -# Limit the number of actions per hour, from 1-30. Default is 30 -limitPerRun: 30 - -# Limit to only `issues` or `pulls` -# only: issues - -# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls': -# pulls: -# daysUntilStale: 30 -# markComment: > -# This pull request has been automatically marked as stale because it has not had -# recent activity. It will be closed if no further activity occurs. Thank you -# for your contributions. - -# issues: -# exemptLabels: -# - confirmed diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml new file mode 100644 index 00000000..7d7fe79d --- /dev/null +++ b/.github/workflows/build-release.yml @@ -0,0 +1,39 @@ +name: Release + +on: + release: + types: [published] + +jobs: + ci: + name: CI + uses: ./.github/workflows/ci.yml + with: + release_build: true + + release: + name: Release + needs: ci + runs-on: ubuntu-22.04 + steps: + - name: Code Checkout + uses: actions/checkout@v4 + + - name: Fetch build artifacts + uses: actions/download-artifact@v4.1.7 + + - name: List assets + run: ls -al Assets + + - name: Attach assets to release + run: | + set -x + ASSETS=() + for asset in Assets/*.zip; do + ASSETS+=("$asset") + echo "$asset" + done + TAG_NAME="${GITHUB_REF##*/}" + gh release upload "${TAG_NAME}" "${ASSETS[@]}" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..b9c9b0f1 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,38 @@ +# Builds Betaflight Lua Scripts. +# +# After building, artifacts are kept for 7 days. + +name: CI + +on: + workflow_call: + inputs: + release_build: + description: 'Specifies if it is a debug build or a release build' + default: false + required: false + type: boolean + +jobs: + build: + name: Build + runs-on: ubuntu-22.04 + steps: + - name: Code Checkout + uses: actions/checkout@v4 + + - name: Install Lua + run: sudo apt-get -y install lua5.2 + + - name: Install Zip + run: sudo apt-get -y install zip + + - name: Execute Build + run: make release + + - name: Publish build artifacts + uses: actions/upload-artifact@v4.3.0 + with: + name: Assets + path: ./release/*.zip + retention-days: 7 diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml new file mode 100644 index 00000000..c60f4255 --- /dev/null +++ b/.github/workflows/nightly.yml @@ -0,0 +1,68 @@ +# You'll need to setup the follwing environment variables: +# env.repo_nightly - The repository to release nightly builds to e.g. betaflight-tx-lua-scripts-nightlies +# env.release_notes - The release notes to be published as part of the github release +# env.debug_release_notes - The release notes to be published as part of the github debug release +# secrets.REPO_TOKEN - A GitHub token with permissions to push and publish releases to the nightly repo + +env: + repo_nightly: betaflight/betaflight-tx-lua-scripts-nightlies + debug_release_notes: > + This is an automated development build. + It may be unstable and result in corrupted configurations or data loss. + **Use only for testing.** + release_notes: This is a release build. + +name: Nightly + +on: + push: + branches: + - master + +jobs: + ci: + name: CI + uses: ./.github/workflows/ci.yml + with: + release_build: false + + release: + name: Nightly release + needs: ci + runs-on: ubuntu-22.04 + steps: + - name: Code Checkout + uses: actions/checkout@v4 + + - name: Fetch build artifacts + uses: actions/download-artifact@v4.1.7 + + - name: Select release notes + id: notes + run: | + set -- Assets/*.zip + echo "notes=$(test -e "$1" && echo '${{ env.debug_release_notes }}' || echo '${{ env.release_notes }}')" >> $GITHUB_OUTPUT + - name: Get current date + id: date + run: echo "today=$(date '+%Y%m%d')" >> $GITHUB_OUTPUT + + - name: Release + uses: softprops/action-gh-release@1e07f4398721186383de40550babbdf2b84acfc5 # v0.1.14 + with: + token: ${{ secrets.REPO_TOKEN }} + repository: ${{ env.repo_nightly }} + tag_name: v${{ steps.date.outputs.today }}.${{ github.run_number }} + files: Assets/*.zip + draft: false + prerelease: false + fail_on_unmatched_files: true + body: | + ${{ steps.notes.outputs.notes }} + ### Repository: + ${{ github.repository }} ([link](${{ github.event.repository.html_url }})) + ### Branch: + ${{ github.ref_name }} ([link](${{ github.event.repository.html_url }}/tree/${{ github.ref_name }})) + ### Latest changeset: + ${{ github.event.head_commit.id }} ([link](${{ github.event.head_commit.url }})) + ### Changes: + ${{ github.event.head_commit.message }} diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml new file mode 100644 index 00000000..c207e7e4 --- /dev/null +++ b/.github/workflows/pr.yml @@ -0,0 +1,12 @@ +name: PR + +on: + pull_request: + branches: + - master + - '*-maintenance' + +jobs: + ci: + name: CI + uses: ./.github/workflows/ci.yml diff --git a/.github/workflows/stale.yaml b/.github/workflows/stale.yaml new file mode 100644 index 00000000..74c4c2cd --- /dev/null +++ b/.github/workflows/stale.yaml @@ -0,0 +1,32 @@ +name: 'Close stale issues' + +on: + schedule: + - cron: "30 4 * * *" + +jobs: + stale: + name: 'Check and close stale issues' + runs-on: ubuntu-latest + steps: + - uses: actions/stale@v3 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + operations-per-run: 30 + days-before-stale: 30 + days-before-close: 7 + stale-issue-message: > + This issue has been automatically marked as stale because it + has not had recent activity. It will be closed if no further activity occurs + within a week. + close-issue-message: 'Issue closed automatically as inactive.' + exempt-issue-labels: 'BUG,Feature Request,Pinned' + stale-issue-label: 'Inactive' + stale-pr-message: > + This pull request has been automatically marked as stale because it + has not had recent activity. It will be closed if no further activity occurs + within a week. + close-pr-message: 'Pull request closed automatically as inactive.' + exempt-pr-labels: 'Pinned' + stale-pr-label: 'Inactive' + exempt-all-milestones: true diff --git a/.gitignore b/.gitignore index 95b7ddbd..63c3ae72 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ # Compiled Lua sources luac.out -# luarocks build files +# Luarocks build files *.src.rock *.zip *.tar.gz @@ -42,6 +42,9 @@ luac.out # Eclipse .project -#directories +# Visual Studio Code +.vscode + +# Directories tmp obj diff --git a/.travis.yml b/.travis.yml index a52cac45..2f510d40 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,3 +18,16 @@ language: c install: script: ./bin/build.sh + +# Notifications are encrypted to betaflight/betaflight to avoid spam from forks +# Command: `travis encrypt "" --com -r betaflight/blackbox-log-viewer +notifications: + slack: + rooms: + - secure: O3Wc0/JyHXJHbTKNqNqf05zZuYNa57TcmXTuml/CSpnEHzoCuphq9N769HSg9szZPvyw27VdK2VZ7bXl28i/thXmPjkGkKnCk0mV3Jd2rnn6UNMF2E33Qymjup02cActNWSxmPQEDPmIZIC0qTyZ9HBs/9Fun/BXQpIKl0SBDe/N1Cz3YIclF3RkGIk8GwDE9IChQi6f6vf+nXaUXOgVMqDG0ZfuIFdW/sEuDjqBPx+GXQrnHgJLpVb/tFrTtQz69A6zsUwcxODaxVYavtLgTgWV7dTufnSo1cM/2hIjXaV0BO2mwbgeAM4thaKnUkfywy4yBTd7m3W80pdsV5/amyok7VsjynkLKKtyQAnNv47/kAeEbzlOmh666LdI9hnFI/HPg2n0zfI7rsX3reU13tkQHbJJSxaxSPA/61fQ1qYxNsr2OJ+MVkyuSUlCczyVzvAsT4eNAA16EDpCat6HeiIXgkrRpiPMWIBh62EUxbI/hirhlv31GAAkl5AuEGx23gSW6bDQrT+W8qJQVA3ClYDZ+HL34zS+JQ4MzVRQRqxF57Jnuxz4evhaVVa7rgKBylOn5IzpIQanmxEM0H0CEpzt7+zFb3OFAQDsVdPR0xXBmA/ATW78xYLgwkjiwmrITIwTTa6scPiSjGWij1L2mnvVepHGdqhpfKNddlDiEkY= + webhooks: + urls: + - secure: pjDcl+AVC2Nppo49jmGGv61cgbDBQRUq/B/eAE23kord/W9WeIPEw0BV5fj4Mt5KTDDkfqyLaKgo6UO0XFcWLbqp0HRzWVsBNSc6PLzWlO3ZpuwrhtH8TrhH18iJLoGJcb6kHvCLqLf6PO6LKihVG9TG6MKl41grZD5auw/0iKzweFSxZts01Z83xzZkmOYgTQzaLMeGozV2P3x1C1cjFD8woInKG8YQhxDyYacXcdFKboQXAjD8lRNrE0nrHmLXQx6q7Dwf15lg0xkFsvKB0NivBGwBQY+zUBankweghVAazOahtO9m1w20iEZS9jhekmodAHWrMEH9TSkWMt+T1S0EqPp9/i2ZiPh5WSLfWQ32GQkOGGA05GxTQMK0xxwPe0yEtORS2tEoluERq/xQaIx5HYubG7QrF1bo8K+KoNaHrLOuNKcdTbiDc9GUQW24zbD85S1UFhO3+H5It/aHBIWSQuNgENw6tp5i9O79ZIJbLjA23J2GY43Red0rTrSAsM3JMO6ktQhAP2IJ3NOvoOpoI/rH1c+PGzxFJnhc42Xo/Npyfdr3L7zNPiKhsGkY8QUe3sd5T6iPOXeUWhx1PdVqExjzJiTyzyGe5PGtZAB1vIjpRY5Jl7wbGYzxpBO3qhBukapWGy+UqUyEj9g5x2lT6W1AcwA0cbwFhAMmulA= + on_success: always # options: [always|never|change] default: always + on_failure: always # options: [always|never|change] default: always + on_start: always # options: [always|never|change] default: always diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..f858f60d --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,46 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at conduct-violations@betaflight.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..bad6bbd9 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,13 @@ +# Issues and Support. + +Please remember the issue tracker on github is _not_ for user support. Please also do not email developers directly for support. Instead please use IRC or the forums first, then if the problem is confirmed create an issue that details how to repeat the problem so it can be investigated. + +Issues created without steps to repeat are likely to be closed. E-mail requests for support will go un-answered; All support needs to be public so that other people can read the problems and solutions. + +Remember that issues that are due to mis-configuration, wiring or failure to read documentation just takes time away from the developers and can often be solved without developer interaction by other users. + +Please search for existing issues *before* creating new ones. + +# Developers + +Please refer to the development section in the [this folder](https://github.com/betaflight/betaflight/tree/master/docs/development). diff --git a/LICENSE b/LICENSE index 9cecc1d4..f288702d 100644 --- a/LICENSE +++ b/LICENSE @@ -1,7 +1,7 @@ GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 - Copyright (C) 2007 Free Software Foundation, Inc. + Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. @@ -631,8 +631,8 @@ to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. - {one line to give the program's name and a brief idea of what it does.} - Copyright (C) {year} {name of author} + + Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -645,14 +645,14 @@ the "copyright" line and a pointer to where the full notice is found. GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program. If not, see . + along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: - {project} Copyright (C) {year} {fullname} + Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. @@ -664,11 +664,11 @@ might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see -. +. The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read -. +. diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..f1a618d9 --- /dev/null +++ b/Makefile @@ -0,0 +1,16 @@ +DIR := ${CURDIR} + +all: files + +files: + @bin/build.sh + +clean: + @rm -rf obj/* + +release: clean files + @RELEASE_DIR=release; \ + FILE_NAME="betaflight-tx-lua-scripts_$$(git describe --abbrev=0 --tags).zip"; \ + mkdir -p $${RELEASE_DIR}; \ + rm -f $${RELEASE_DIR}/$${FILE_NAME}; \ + zip -q -r $${RELEASE_DIR}/$${FILE_NAME} obj/ diff --git a/README.md b/README.md index 58199bf7..67a520b6 100644 --- a/README.md +++ b/README.md @@ -1,53 +1,91 @@ -# betaflight-tx-lua-scripts +![BF lua logo light mode](docs/assets/images/bf_lua_logo_light_mode.png#gh-light-mode-only) +![BF lua logo dark mode](docs/assets/images/bf_lua_logo_dark_mode.png#gh-dark-mode-only) -### Important: + [![Latest version](https://img.shields.io/github/v/release/betaflight/betaflight-tx-lua-scripts)](https://github.com/betaflight/betaflight-tx-lua-scripts/releases) [![Build](https://img.shields.io/github/actions/workflow/status/betaflight/betaflight-tx-lua-scripts/nightly.yml?branch=master)](https://github.com/betaflight/betaflight-tx-lua-scripts/actions/workflows/nightly.yml) [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) -Some changes in the recently released OpenTX 2.2.1 cause this version to have less RAM available for lua scripts than previous versions. This often leads to problems when using the Betaflight TX lua scripts on the Taranis X9D. A discussion of these problems can be found [here](https://github.com/betaflight/betaflight-tx-lua-scripts/issues/97). -A potential fix to increase the amount of RAM available has been identified: (https://github.com/opentx/opentx/pull/5579). -For now, the recommendation is for users wanting to update OpenTX from 2.2.0 to 2.2.1 on a Taranis X9D (and keep using the Betaflight TX lua scripts) to hold on and monitor the situation, in the hope that OpenTX will release a version with this bugfix in the near future. +## Requirements -### How to download the scripts +- Betaflight - As a best practice, it is recommended to use the most recent stable release of Betaflight to obtain the best possible results; +- Telemetry - Telemetry has to be enabled in Betaflight Receiver tab and supported by the TX / RX for the scripts to be able to communicate with the flight controller; +- OpenTX - 2.3.12 or newer; +- EdgeTX - 2.4.0 or newer; +- ExpressLRS - 2.0.1 or newer; +- TBS Crossfire/Tracer TX / RX - v2.11 or newer; +- FrSky TX / RX with support for SmartPort - While most receivers with SmartPort support work fine, it is recommended to update the receiver to the most recent firmware version to correct any known bugs in telemetry. +- ImmersionRC Ghost RX module - Latest firmware and module set to RF Mode "Race250" - see (Ghost receiver manual pg 36-38) (Other RF Modes have issues or do not have telemetry to allow Betaflight LUA to work). +- Baud rate - Set to 400K in EdgeTX/OpenTX for Crossfire, Tracer, ExpressLRS. -Please visit the [releases page](https://github.com/betaflight/betaflight-tx-lua-scripts/releases) to download a zip file containing latest version. +## Installing -## Firmware Considerations -- Betaflight - As a best practice, it is recommended to use the most recent stable release of Betaflight to obtain the best possible results. -- Crossfire - v2.11 or greater -- FrSky - While most receivers work fine, it's recommended to update the XSR family of receivers to their most recent firmware version to correct any known bugs in SmartPort telemetry. +**!! IMPORTANT: DON'T COPY THE CONTENTS OF THIS REPOSITORY ONTO YOUR SDCARD !!** -## Installing +Download a zip file containing the latest version from the [releases page](https://github.com/betaflight/betaflight-tx-lua-scripts/releases). + +Unzip the files from the link above and drag the contents of the `obj` folder to your radios SD card. If you do this correctly, the `SCRIPTS` directory will merge with your existing directories, placing the scripts in their appropriate paths. You will know if you did this correctly if the `bf.lua` file shows up in your `/SCRIPTS/TOOLS` directory. + +![Install](docs/assets/images/install.gif) + +## How to use + +Navigate to the TOOLS menu in OpenTX, select "Betaflight setup" or "Betaflight CMS" and press the [ENTER] button. The first time the script is launched after a clean install or upgrade it will go through it's compile procedure and exit back to the TOOLS menu when it's done. + +### Betaflight setup + +The "Betaflight setup" script lets you configure Betaflight through the MSP protocol. + +![Betaflight setup](docs/assets/images/how_to_use.gif) + +#### Controls + +- [+] / [-] / [ROTARY ENCODER] - Used to navigate. +- [PAGE] - Press to move to the next page. Long press to move to the previous page. +- [ENTER] - Press to access the selected element. Long press to open the function menu. +- [EXIT] - Press to go back or exit the script. + +#### Saving your changes + +Any changes to parameters in the script will not take effect until a save is manually initiated. Change the parameters you want to change, open the function menu by long pressing [ENTER] and select "save page" to send the modified parameters back to the flight controller. + +#### Setting up VTX tables + +If you are using a VTX that supports the SmartAudio or Tramp protocols then bands and channels etc. are managed using VTX tables since Betaflight version 4.1.0. The script will be downloading and storing the current VTX table for every model the first time the model is connected and the script is run. If you change the VTX table, you have to re-load the updated VTX table in the script, by choosing the 'vtx tables' option in the function menu. + +Depending on the size of the vtx tables and the telemetry protocol used, downloading the vtx tables can take a while. + +![Download VTX tables](docs/assets/images/download_vtx_tables.gif) + +Please note that if the "VTX" feature wasn't included in your Betaflight firmware build, the downloading of the VTX tables will be skipped and the VTX menu item won't be available. The initial setup of the VTX/VTX tables must be done using the [Configurator](https://github.com/betaflight/betaflight-configurator). + +### Betaflight CMS + +**!! IMPORTANT: TBS Crossfire/Tracer only !!** + +"Betaflight CMS" lets you access the same CMS menu that is available in the OSD. + +![Betaflight CMS](docs/assets/images/how_to_use_cms.gif) + +#### Controls -!! IMPORTANT: DON'T COPY THE CONTENTS OF THIS REPOSITORY ONTO YOUR SDCARD !! +- [PITCH] - Navigate the current menu. +- [ROLL] - Enter menu or change selected parameter. +- [YAW] - Left to go back and right to enter the "SAVE / EXIT" menu. +- [+] / [ENTER] - Manual refresh. Press if the script doesn't update. +- [EXIT] - Close CMS menu and exit script. **!! IMPORTANT: Single press only. Long press will exit the script without closing CMS and as a result you will not be able to arm !!** -Unzip the files from the link above and drag the contents to your radio. If you do this correctly, the SCRIPTS directory will merge with your existing directories, placing the scripts in their appropriate paths. You will know if you did this correctly if the bf.lua file shows up in your /SCRIPTS/TELEMETRY directory. +### Background script -The src directory is not required for use and is only available for maintenance of the code. While it may work to use this directory, you may encounter memory issues on your transmitter. +The optional background script offers RTC synchronization and RSSI through MSP. RSSI will only be sent if no other RSSI source is detected. It can be setup as a special or global function in OpenTX. The image below shows how to run the background script as a special function. -How to install: +![Background script setup](docs/assets/images/background_script_setup.png) -Bootloader Method -1. Power off your transmitter and power it back on in boot loader mode. -2. Connect a USB cable and open the SD card drive on your computer. -3. Unzip the file and copy the scripts to the root of the SD card. -4. Unplug the USB cable and power cycle your transmitter. +## Unstable testing versions -Manual method (varies, based on the model of your transmitter) -1. Power off your transmitter. -2. Remove the SD card and plug it into a computer -3. Unzip the file and copy the scripts to the root of the SD card. -4. Reinsert your SD card into the transmitter -5. Power up your transmitter. +Unstable testing versions of the latest builds of the Lua Script can be downloaded from [here](https://github.com/betaflight/betaflight-tx-lua-scripts-nightlies/releases). -If you copied the files correctly, you can now go into the telemetry screen setup page and set up the script as telemetry page. +Be aware that these versions are intended for testing / feedback only, and may be buggy or broken. Caution is advised when using these versions. -## Adding the script as a telemetry page -Setting up the script as a telemetry page will enable access at the press of a button. (For now, this only applies to the Taranis X9D series). -1. Hit the [MENU] button and select the model for which you would like to enable the script. -2. While on the [MODEL SELECTION] screen, long-press the [PAGE] button to navigate to the [DISPLAY] page. -3. Use the [-] button to move the cursor down to [Screen 1] and hit [ENT]. -4. Use the [+] or [-] buttons to select the [Script] option and press [ENT]. -5. Press [-] to move the cursor to the script selection field and hit [ENT]. -6. Select 'bf' and hit [ENT]. -7. Long-press [EXIT] to return to your model screen. +## Building from source -To invoke the script, simply long-press the [PAGE] button from the model screen. +- Be sure to have `make` and `luac` in version 5.2 installed in the path +- Run `make` from the root folder +- The installation files will be created in the `obj` folder. Copy the files to your transmitter as instructed in the '[Installing](#installing)' section as if you unzipped from a downloaded file. diff --git a/bin/build.sh b/bin/build.sh index ff6dbdf0..be6cb2ac 100755 --- a/bin/build.sh +++ b/bin/build.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash if [ -d obj ]; then rm -fR obj/* @@ -16,20 +16,31 @@ if [ ${#MANIFEST[@]} -eq 0 ]; then exit 1 fi +SCRIPTS_LUA=obj/SCRIPTS/BF/COMPILE/scripts.lua + +echo 'local scripts = {' >> $SCRIPTS_LUA +for f in ${MANIFEST[@]}; +do + echo ' ''"'${f/\obj/}'",' >> $SCRIPTS_LUA +done +echo '}' >> $SCRIPTS_LUA +echo 'return scripts[...]' >> $SCRIPTS_LUA + +MANIFEST+=($SCRIPTS_LUA); + for f in ${MANIFEST[@]}; do SRC_NAME=$f - OBJ_NAME=$(dirname ${f})/$(basename ${f} .lua).luac - echo -e "Compiling file \e[1m${SRC_NAME}\e[21m..." - luac -s -o ${OBJ_NAME} ${SRC_NAME} + echo -e "Testing file \e[1m${SRC_NAME}\e[21m..." + luac -p ${SRC_NAME} _fail=$? if [[ $_fail -ne 0 ]]; then LAST_FAILURE=$_fail - echo -e "\e[1m\e[39m[\e[31mBUILD FAILED\e[39m]\e[21m Compilation error in file ${SRC_NAME}\e[1m" + echo -e "\e[1m\e[39m[\e[31mBUILD FAILED\e[39m]\e[21m Error in file ${SRC_NAME}\e[1m" fi done if [[ $LAST_FAILURE -eq 0 ]]; then - echo -e "\e[1m\e[39m[\e[32mTEST SUCCESSFUL\e[39m]\e[21m All lua files built successfully!" + echo -e "\e[1m\e[39m[\e[32mTEST SUCCESSFUL\e[39m]\e[21m" fi exit $LAST_FAILURE diff --git a/docs/assets/images/background_script_setup.png b/docs/assets/images/background_script_setup.png new file mode 100644 index 00000000..09b48066 Binary files /dev/null and b/docs/assets/images/background_script_setup.png differ diff --git a/docs/assets/images/bf_lua_logo_dark_mode.png b/docs/assets/images/bf_lua_logo_dark_mode.png new file mode 100644 index 00000000..3ff9afa4 Binary files /dev/null and b/docs/assets/images/bf_lua_logo_dark_mode.png differ diff --git a/docs/assets/images/bf_lua_logo_light_mode.png b/docs/assets/images/bf_lua_logo_light_mode.png new file mode 100644 index 00000000..09a1cac2 Binary files /dev/null and b/docs/assets/images/bf_lua_logo_light_mode.png differ diff --git a/docs/assets/images/download_vtx_tables.gif b/docs/assets/images/download_vtx_tables.gif new file mode 100644 index 00000000..350d1200 Binary files /dev/null and b/docs/assets/images/download_vtx_tables.gif differ diff --git a/docs/assets/images/how_to_use.gif b/docs/assets/images/how_to_use.gif new file mode 100644 index 00000000..70b5f252 Binary files /dev/null and b/docs/assets/images/how_to_use.gif differ diff --git a/docs/assets/images/how_to_use_cms.gif b/docs/assets/images/how_to_use_cms.gif new file mode 100644 index 00000000..05014782 Binary files /dev/null and b/docs/assets/images/how_to_use_cms.gif differ diff --git a/docs/assets/images/install.gif b/docs/assets/images/install.gif new file mode 100644 index 00000000..d6f4d0c6 Binary files /dev/null and b/docs/assets/images/install.gif differ diff --git a/src/BF/bf.lua b/src/BF/bf.lua deleted file mode 100644 index 4cdecc5b..00000000 --- a/src/BF/bf.lua +++ /dev/null @@ -1,12 +0,0 @@ -SCRIPT_HOME = "/SCRIPTS/BF" - -protocol = assert(loadScript(SCRIPT_HOME.."/protocols.lua"))() -radio = assert(loadScript(SCRIPT_HOME.."/radios.lua"))() - -assert(loadScript(radio.preLoad))() -assert(loadScript(protocol.transport))() -assert(loadScript(SCRIPT_HOME.."/MSP/common.lua"))() - -local run_ui = assert(loadScript(SCRIPT_HOME.."/ui.lua"))() - -return { run=run_ui } diff --git a/src/SCRIPTS/BF/BOARD_INFO/readme.txt b/src/SCRIPTS/BF/BOARD_INFO/readme.txt new file mode 100644 index 00000000..2fe32c7e --- /dev/null +++ b/src/SCRIPTS/BF/BOARD_INFO/readme.txt @@ -0,0 +1 @@ +Board info downloaded from the flight controller will be stored in this folder. diff --git a/src/SCRIPTS/BF/CMS/common.lua b/src/SCRIPTS/BF/CMS/common.lua new file mode 100644 index 00000000..5581d822 --- /dev/null +++ b/src/SCRIPTS/BF/CMS/common.lua @@ -0,0 +1,121 @@ +local CONST = { + bitmask = { + firstChunk = 0x80, + lastChunk = 0x40, + batchId = 0x3F, + rleCharValueMask = 0x7F, + rleCharRepeatedMask = 0x80 + }, + offset = { + meta = 1, + sequence = 2, + data = 3 + } +} + +local function cRleDecode(buf) + local dest = {} + local rpt = false + local c = nil + for i = 1, #buf do + if (rpt == false) then + c = bit32.band(buf[i], CONST.bitmask.rleCharValueMask) + if (bit32.band(buf[i], CONST.bitmask.rleCharRepeatedMask) > 0) then + rpt = true + else + dest[#dest + 1] = c + end + else + for j = 1, buf[i] do + dest[#dest + 1] = c + end + rpt = false + end + end + return dest +end + +screen = { + config = nil, + buffer = {}, + data = {}, + batchId = 0, + sequence = 0, + redraws = 2, + reset = function() + screen.data = {} + screen.batchId = 0 + screen.sequence = 0 + end, + draw = function() + lcd.clear() + lcd.drawText(screen.config.refresh.left, screen.config.refresh.top, screen.config.refresh.text, screen.config.textSize) + for char = 1, #screen.buffer do + if (screen.buffer[char] ~= 32) then -- skip spaces to avoid CPU spikes + local c = string.char(screen.buffer[char]) + local row = math.ceil(char / screen.config.cols) + local col = char - ((row - 1) * screen.config.cols) + local xPos = ((col - 1) * screen.config.pixelsPerChar) + screen.config.xIndent + 1 + local yPos = ((row - 1) * screen.config.pixelsPerRow) + screen.config.yOffset + 1 + lcd.drawText(xPos, yPos, c, screen.config.textSize) + end + end + end, +} + +cms = { + menuOpen = false, + synced = false, + init = function(cmsConfig) + screen.config = assert(cmsConfig, "Resolution not supported") + screen.reset() + protocol.cms.close() + cms.menuOpen = false + cms.synced = false + end, + open = function() + protocol.cms.open(screen.config.rows, screen.config.cols) + end, + refresh = function() + protocol.cms.refresh() + end, + close = function() + protocol.cms.close() + cms.menuOpen = false + end, + update = function() + local command, data = protocol.cms.poll() + if (command == "update") then + local firstChunk = bit32.btest(data[CONST.offset.meta], CONST.bitmask.firstChunk) + local lastChunk = bit32.btest(data[CONST.offset.meta], CONST.bitmask.lastChunk) + local batchId = bit32.band(data[CONST.offset.meta], CONST.bitmask.batchId) + local sequence = data[CONST.offset.sequence] + if firstChunk then + screen.reset() + screen.batchId = batchId + screen.sequence = 0 + end + if (screen.batchId == batchId) and (screen.sequence == sequence) then + screen.sequence = sequence + 1 + for i = CONST.offset.data, #data do + screen.data[#screen.data + 1] = data[i] + end + if lastChunk then + screen.buffer = cRleDecode(screen.data) + screen.redraws = 2 + screen.reset() + cms.synced = true + end + else + protocol.cms.refresh() + end + cms.menuOpen = true + elseif (command == "clear") then + screen.reset() + end + if screen.redraws > 0 then + screen.draw() + screen.redraws = screen.redraws - 1 + end + end +} diff --git a/src/SCRIPTS/BF/CMS/crsf.lua b/src/SCRIPTS/BF/CMS/crsf.lua new file mode 100644 index 00000000..83c17337 --- /dev/null +++ b/src/SCRIPTS/BF/CMS/crsf.lua @@ -0,0 +1,64 @@ +local CONST = { + frame = { + destination = 1, + source = 2, + command = 3, + content = 4 + }, + address = { + transmitter = 0xEA, + betaflight = 0xC8 + }, + frameType = { + displayPort = 0x7D + }, + command = { + update = 0x01, + clear = 0x02, + open = 0x03, + close = 0x04, + refresh = 0x05 + } +} + +local function crsfDisplayPortCmd(cmd, data) + local payloadOut = { CONST.address.betaflight, CONST.address.transmitter, cmd } + if data ~= nil then + for i = 1, #(data) do + payloadOut[3 + i] = data[i] + end + end + return crossfireTelemetryPush(CONST.frameType.displayPort, payloadOut) +end + +protocol.cms.poll = function() + local command = nil + local dataOut = {} + local frameType, data = crossfireTelemetryPop() + if (data ~= nil) and (#data > 2) then + if (frameType == CONST.frameType.displayPort) and (data[CONST.frame.destination] == CONST.address.transmitter) and (data[CONST.frame.source] == CONST.address.betaflight) then + for k,v in pairs(CONST.command) do + if (v == data[CONST.frame.command]) then + command = k + end + end + for i = CONST.frame.content, #data do + dataOut[#dataOut + 1] = data[i] + end + end + end + return command, dataOut +end + +protocol.cms.open = function(rows, cols) + return crsfDisplayPortCmd(CONST.command.open, { rows, cols }) +end + +protocol.cms.close = function() + return crsfDisplayPortCmd(CONST.command.close, nil) +end + +protocol.cms.refresh = function() + return crsfDisplayPortCmd(CONST.command.refresh, nil) +end + diff --git a/src/SCRIPTS/BF/COMPILE/compile.lua b/src/SCRIPTS/BF/COMPILE/compile.lua new file mode 100644 index 00000000..b6f8fd22 --- /dev/null +++ b/src/SCRIPTS/BF/COMPILE/compile.lua @@ -0,0 +1,22 @@ +local i = 1 + +local function compile() + local script = assert(loadScript("COMPILE/scripts.lua"))(i) + collectgarbage() + i = i + 1 + if script then + lcd.clear() + lcd.drawText(2, 2, "Compiling...", SMLSIZE) + lcd.drawText(2, 22, script, SMLSIZE) + assert(loadScript(script, 'c')) + collectgarbage() + return 0 + end + local file = io.open("COMPILE/scripts_compiled.lua", 'w') + io.write(file, "return true") + io.close(file) + assert(loadScript("COMPILE/scripts_compiled.lua", 'c')) + return 1 +end + +return compile diff --git a/src/SCRIPTS/BF/COMPILE/scripts_compiled.lua b/src/SCRIPTS/BF/COMPILE/scripts_compiled.lua new file mode 100644 index 00000000..585a20e0 --- /dev/null +++ b/src/SCRIPTS/BF/COMPILE/scripts_compiled.lua @@ -0,0 +1 @@ +return false diff --git a/src/SCRIPTS/BF/CONFIRM/acc_cal.lua b/src/SCRIPTS/BF/CONFIRM/acc_cal.lua new file mode 100644 index 00000000..41a3c8de --- /dev/null +++ b/src/SCRIPTS/BF/CONFIRM/acc_cal.lua @@ -0,0 +1,25 @@ +local template = assert(loadScript(radio.template))() +local margin = template.margin +local indent = template.indent +local lineSpacing = template.lineSpacing +local tableSpacing = template.tableSpacing +local sp = template.listSpacing.field +local yMinLim = radio.yMinLimit +local x = margin +local y = yMinLim - lineSpacing +local inc = { x = function(val) x = x + val return x end, y = function(val) y = y + val return y end } +local labels = {} +local fields = {} + +labels[#labels + 1] = { t = "Make sure the craft is level", x = x, y = inc.y(lineSpacing) } +labels[#labels + 1] = { t = "and stable, then press", x = x, y = inc.y(lineSpacing) } +labels[#labels + 1] = { t = "[ENTER] to calibrate, or", x = x, y = inc.y(lineSpacing) } +labels[#labels + 1] = { t = "[EXIT] to cancel.", x = x, y = inc.y(lineSpacing) } +fields[#fields + 1] = { x = x, y = inc.y(lineSpacing), value = "", ro = true } + +return { + title = "Accelerometer", + labels = labels, + fields = fields, + init = assert(loadScript("acc_cal.lua"))(), +} diff --git a/src/SCRIPTS/BF/CONFIRM/pwm.lua b/src/SCRIPTS/BF/CONFIRM/pwm.lua new file mode 100644 index 00000000..f2c90233 --- /dev/null +++ b/src/SCRIPTS/BF/CONFIRM/pwm.lua @@ -0,0 +1,21 @@ +local template = assert(loadScript(radio.template))() +local margin = template.margin +local lineSpacing = template.lineSpacing +local yMinLim = radio.yMinLimit +local x = margin +local y = yMinLim - lineSpacing +local inc = { x = function(val) x = x + val return x end, y = function(val) y = y + val return y end } +local labels = {} +local fields = {} + +labels[#labels + 1] = { t = "Download Board Info? Press", x = x, y = inc.y(lineSpacing) } +labels[#labels + 1] = { t = "[ENTER] to download, or", x = x, y = inc.y(lineSpacing) } +labels[#labels + 1] = { t = "[EXIT] to cancel.", x = x, y = inc.y(lineSpacing) } +fields[#fields + 1] = { x = x, y = inc.y(lineSpacing), value = "", ro = true } + +return { + title = "Board Info", + labels = labels, + fields = fields, + init = assert(loadScript("board_info.lua"))(), +} diff --git a/src/SCRIPTS/BF/CONFIRM/vtx_tables.lua b/src/SCRIPTS/BF/CONFIRM/vtx_tables.lua new file mode 100644 index 00000000..f619fda5 --- /dev/null +++ b/src/SCRIPTS/BF/CONFIRM/vtx_tables.lua @@ -0,0 +1,21 @@ +local template = assert(loadScript(radio.template))() +local margin = template.margin +local lineSpacing = template.lineSpacing +local yMinLim = radio.yMinLimit +local x = margin +local y = yMinLim - lineSpacing +local inc = { x = function(val) x = x + val return x end, y = function(val) y = y + val return y end } +local labels = {} +local fields = {} + +labels[#labels + 1] = { t = "Download VTX tables? Press", x = x, y = inc.y(lineSpacing) } +labels[#labels + 1] = { t = "[ENTER] to download, or", x = x, y = inc.y(lineSpacing) } +labels[#labels + 1] = { t = "[EXIT] to cancel.", x = x, y = inc.y(lineSpacing) } +fields[#fields + 1] = { x = x, y = inc.y(lineSpacing), value = "", ro = true } + +return { + title = "VTX Tables", + labels = labels, + fields = fields, + init = assert(loadScript("vtx_tables.lua"))(), +} diff --git a/src/SCRIPTS/BF/HORUS/filters.lua b/src/SCRIPTS/BF/HORUS/filters.lua deleted file mode 100644 index b1bf7bb8..00000000 --- a/src/SCRIPTS/BF/HORUS/filters.lua +++ /dev/null @@ -1,44 +0,0 @@ - -return { - read = 92, -- MSP_FILTER_CONFIG - write = 93, -- MSP_SET_FILTER_CONFIG - eepromWrite = true, - reboot = false, - title = "Filters", - minBytes = 18, - text= { - -- Column headers - { t = "Gy LP", x = 60, y = 68, to = SMLSIZE }, - { t = "Gy NF1", x = 125, y = 68, to = SMLSIZE }, - { t = "Gy NF2", x = 190, y = 68, to = SMLSIZE }, - { t = "DT LP", x = 255, y = 68, to = SMLSIZE }, - { t = "DT NF", x = 315, y = 68, to = SMLSIZE }, - { t = "Yaw LP", x = 385, y = 68, to = SMLSIZE }, - - -- Line titles - { t = "Hz", x = 48, y = 110, to = SMLSIZE + RIGHT }, - { t = "COff", x = 48, y = 155, to = SMLSIZE + RIGHT }, - - { t = "DTerm LP Type", x = 60, y = 208 }, - }, - fields = { - { x = 60, y = 110, min = 0, max = 255, vals = { 1 }, to = MIDSIZE }, - - { x = 125, y = 110, min = 0, max = 16000, vals = { 6, 7 }, to = MIDSIZE }, - { x = 125, y = 155, min = 0, max = 16000, vals = { 8, 9 }, to = MIDSIZE }, - - { x = 190, y = 110, min = 0, max = 16000, vals = { 14, 15 }, to = MIDSIZE }, - { x = 190, y = 155, min = 0, max = 16000, vals = { 16, 17 }, to = MIDSIZE }, - - { x = 255, y = 110, min = 0, max = 16000, vals = { 2, 3 }, to = MIDSIZE }, - - { x = 315, y = 110, min = 0, max = 16000, vals = { 10, 11 }, to = MIDSIZE }, - { x = 315, y = 155, min = 0, max = 16000, vals = { 12, 13 }, to = MIDSIZE }, - - { x = 391, y = 110, min = 0, max = 500, vals = { 4, 5 }, to = MIDSIZE }, - - { x = 208, y = 208, min = 0, max = 2, vals = { 18 }, to = MIDSIZE, - table = { [0] = "PT1", [1] = "BIQUAD", [2] = "FIR" } - }, - } -} diff --git a/src/SCRIPTS/BF/HORUS/horuspre.lua b/src/SCRIPTS/BF/HORUS/horuspre.lua deleted file mode 100644 index 409b4943..00000000 --- a/src/SCRIPTS/BF/HORUS/horuspre.lua +++ /dev/null @@ -1,18 +0,0 @@ -PageFiles = -{ - "pids.lua", - "rates1.lua", - "rates2.lua", - "filters.lua", - "pwm.lua", - "rx.lua", - "vtx.lua" -} - -backgroundFill = TEXT_BGCOLOR -foregroundColor = LINE_COLOR -globalTextOptions = TEXT_COLOR - -MenuBox = { x=120, y=100, w=200, x_offset=68, h_line=20, h_offset=6 } -SaveBox = { x=120, y=100, w=180, x_offset=12, h=60, h_offset=12 } -NoTelem = { 192, LCD_H - 28, "No Telemetry", TEXT_COLOR + INVERS + BLINK } diff --git a/src/SCRIPTS/BF/HORUS/pids.lua b/src/SCRIPTS/BF/HORUS/pids.lua deleted file mode 100644 index 273cec79..00000000 --- a/src/SCRIPTS/BF/HORUS/pids.lua +++ /dev/null @@ -1,30 +0,0 @@ - -return { - read = 112, -- MSP_PID - write = 202, -- MSP_SET_PID - title = "PIDs", - reboot = false, - eepromWrite = true, - minBytes = 8, - text = { - { t = "P", x = 142, y = 48, to = MIDSIZE }, - { t = "I", x = 244, y = 48, to = MIDSIZE }, - { t = "D", x = 342, y = 48, to = MIDSIZE }, - { t = "ROLL", x = 28, y = 100 }, - { t = "PITCH", x = 28, y = 150 }, - { t = "YAW", x = 28, y = 200 }, - }, - fields = { - -- P - { x = 140, y = 100, min = 0, max = 200, vals = { 1 }, to = MIDSIZE }, - { x = 140, y = 150, min = 0, max = 200, vals = { 4 }, to = MIDSIZE }, - { x = 140, y = 200, min = 0, max = 200, vals = { 7 }, to = MIDSIZE }, - -- I - { x = 240, y = 100, min = 0, max = 200, vals = { 2 }, to = MIDSIZE }, - { x = 240, y = 150, min = 0, max = 200, vals = { 5 }, to = MIDSIZE }, - { x = 240, y = 200, min = 0, max = 200, vals = { 8 }, to = MIDSIZE }, - -- D - { x = 340, y = 100, min = 0, max = 200, vals = { 3 }, to = MIDSIZE }, - { x = 340, y = 150, min = 0, max = 200, vals = { 6 }, to = MIDSIZE }, - }, -} diff --git a/src/SCRIPTS/BF/HORUS/pwm.lua b/src/SCRIPTS/BF/HORUS/pwm.lua deleted file mode 100644 index 0b225e56..00000000 --- a/src/SCRIPTS/BF/HORUS/pwm.lua +++ /dev/null @@ -1,66 +0,0 @@ -return { - read = 90, -- MSP_ADVANCED_CONFIG - write = 91, -- MSP_SET_ADVANCED_CONFIG - reboot = true, - eepromWrite = true, - title = "PWM", - minBytes = 9, - text= { - { t = "Protocol", x = 36, y = 68 }, - { t = "32K", x = 36, y = 110 }, - { t = "Gyro Rt", x = 36, y = 155 }, - { t = "PID Rt", x = 36, y = 200 }, - { t = "Unsynced", x = 232, y = 110 }, - { t = "PWM Rate", x = 232, y = 155 }, - { t = "Idle Offset", x = 232, y = 200 } - }, - fields = { - { x = 130, y = 68, vals = { 4 }, min = 0, max = 9, to = MIDSIZE, - table = { [0] = "OFF", "ONESHOT125", "ONESHOT42", - "MULTISHOT","BRUSHED", - "DSHOT150", "DSHOT300", "DSHOT600","DSHOT1200", - "PROSHOT1000" } - }, - { x = 130, y = 110, vals = { 9 }, min = 0, max = 1, to = MIDSIZE, - table = { [0] = "OFF", "ON" }, - upd = function(self) self.updateRateTables(self) end - }, - { x = 130, y = 155, vals = { 1 }, min = 1, max = 32, to = MIDSIZE, - upd = function(self) self.updatePidRateTable(self) end - }, - { x = 130, y = 200, vals = { 2 }, min = 1, max = 16, to = MIDSIZE }, - { x = 350, y = 110, vals = { 3 }, min = 0, max = 1, to = MIDSIZE, - table = { [0] = "OFF", "ON" } }, - { x = 350, y = 155, vals = { 5, 6 }, min = 200, max = 32000, to = MIDSIZE }, - { x = 350, y = 200, vals = { 7, 8 }, min = 0, max = 2000, scale = 100, to = MIDSIZE }, - }, - calculateGyroRates = function(self, baseRate) - self.gyroRates = {} - self.fields[2].table = {} - for i=1, 32 do - self.gyroRates[i] = baseRate/i - local fmt = nil - self.fields[2].table[i] = string.format("%.2f",baseRate/i) - end - end, - calculatePidRates = function(self, baseRate) - self.fields[3].table = {} - for i=1, 16 do - self.fields[3].table[i] = string.format("%.2f",baseRate/i) - end - end, - updateRateTables = function(self) - if self.values[9] == 0 then - self.calculateGyroRates(self, 8) - self.calculatePidRates(self, 8) - elseif self.values[9] == 1 then - self.calculateGyroRates(self, 32) - self.calculatePidRates(self, 32) - end - end, - updatePidRateTable = function(self) - local newRateIdx = self.values[1] - local newRate = self.gyroRates[newRateIdx] - self.calculatePidRates(self, newRate) - end -} diff --git a/src/SCRIPTS/BF/HORUS/rates1.lua b/src/SCRIPTS/BF/HORUS/rates1.lua deleted file mode 100644 index 74277587..00000000 --- a/src/SCRIPTS/BF/HORUS/rates1.lua +++ /dev/null @@ -1,43 +0,0 @@ -return { - read = 111, -- MSP_RC_TUNING - write = 204, -- MSP_SET_RC_TUNING - title = "Rates (1/2)", - reboot = false, - eepromWrite = true, - minBytes = 12, - text = { - { t = "RC", x = 100, y = 52 }, - { t = "Rate", x = 94, y = 70 }, - { t = "Super", x = 148, y = 52 }, - { t = "Rate", x = 152, y = 70 }, - { t = "RC", x = 214, y = 52 }, - { t = "Expo", x = 207, y = 70 }, - { t = "Throttle", x = 288, y = 68 }, - { t = "Mid", x = 288, y = 100 }, - { t = "Exp", x = 288, y = 150 }, - { t = "TPA", x = 374, y = 68 }, - { t = "Thr", x = 374, y = 100 }, - { t = "Brk", x = 374, y = 150 }, - { t = "ROLL", x = 28, y = 100 }, - { t = "PITCH", x = 28, y = 150 }, - { t = "YAW", x = 28, y = 200 }, - }, - fields = { - -- RC Rates - { x = 102, y = 125, vals = { 1 }, min = 0, max = 255, scale = 100, to=MIDSIZE }, - { x = 102, y = 200, vals = { 12 }, min = 0, max = 255, scale = 100, to=MIDSIZE }, - -- Super Rates - { x = 158, y = 100, vals = { 3 }, min = 0, max = 100, scale = 100, to=MIDSIZE }, - { x = 158, y = 150, vals = { 4 }, min = 0, max = 100, scale = 100, to=MIDSIZE }, - { x = 158, y = 200, vals = { 5 }, min = 0, max = 255, scale = 100, to=MIDSIZE }, - -- RC Expo - { x = 216, y = 125, vals = { 2 }, min = 0, max = 100, scale = 100, to=MIDSIZE }, - { x = 216, y = 200, vals = { 11 }, min = 0, max = 100, scale = 100, to=MIDSIZE }, - -- Throttle - { x = 330, y = 100, vals = { 7 }, min = 0, max = 100, scale = 100, to=MIDSIZE }, - { x = 330, y = 150, vals = { 8 }, min = 0, max = 100, scale = 100, to=MIDSIZE }, - -- TPA - { x = 416, y = 100, vals = { 6 } , min = 0, max = 100, scale = 100, to=MIDSIZE }, - { x = 416, y = 150, vals = { 9, 10 }, min = 1000, max = 2000, to=MIDSIZE } - }, -} \ No newline at end of file diff --git a/src/SCRIPTS/BF/HORUS/rates2.lua b/src/SCRIPTS/BF/HORUS/rates2.lua deleted file mode 100644 index 42490091..00000000 --- a/src/SCRIPTS/BF/HORUS/rates2.lua +++ /dev/null @@ -1,30 +0,0 @@ - -return { - read = 94, -- MSP_PID_ADVANCED - write = 95, -- MSP_SET_PID_ADVANCED - title = "Rates (2/2)", - reboot = false, - eepromWrite = true, - minBytes = 23, - text = { - { t = "Anti-Gravity", x = 28, y = 62 }, - { t = "Gain", x = 38, y = 100 }, - { t = "Threshold", x = 38, y = 142 }, - { t = "Dterm Setpoint", x = 232, y = 62 }, - { t = "Weight", x = 242, y = 100 }, - { t = "Transition", x = 242, y = 142 }, - { t = "VBAT Compensation", x = 28, y = 200 } - }, - fields = { - -- GAIN - { x = 144, y = 100, min = 1000, max = 30000, vals = { 22, 23 }, to = MIDSIZE, scale = 1000, mult = 100 }, - -- THRESHOLD - { x = 144, y = 142, min = 20, max = 1000, vals = { 20, 21 }, to = MIDSIZE }, - -- WEIGHT - { x = 348, y = 100, min = 0, max = 254, vals = { 10 }, to = MIDSIZE, scale = 100 }, - -- TRANSITION - { x = 348, y = 142, min = 0, max = 100, vals = { 9 }, to = MIDSIZE, scale = 100 }, - -- VBAT COMPENSATION - { x = 236, y = 200, min = 0, max = 1, vals = { 8 }, to = MIDSIZE, table = { [0]="OFF", "ON" } }, - } -} diff --git a/src/SCRIPTS/BF/HORUS/rx.lua b/src/SCRIPTS/BF/HORUS/rx.lua deleted file mode 100644 index 0aa1b4c9..00000000 --- a/src/SCRIPTS/BF/HORUS/rx.lua +++ /dev/null @@ -1,25 +0,0 @@ -return { - read = 44, -- MSP_RX_CONFIG - write = 45, -- MSP_SET_RX_CONFIG - title = "RX", - reboot = false, - eepromWrite = true, - minBytes = 23, - text= { - { t = "Stick Min", x = 36, y = 68 }, - { t = "Stick Mid", x = 36, y = 110 }, - { t = "Stick Max", x = 36, y = 155 }, - { t = "Cam Angle", x = 232, y = 68 }, - { t = "Interp", x = 232, y = 110 }, - { t = "Interp Int", x = 232, y = 155 } - }, - fields = { - { x = 130, y = 68, min = 1000, max = 2000, vals = { 6, 7 }, to = MIDSIZE }, - { x = 130, y = 110, min = 1000, max = 2000, vals = { 4, 5 }, to = MIDSIZE }, - { x = 130, y = 155, min = 1000, max = 2000, vals = { 2, 3 }, to = MIDSIZE }, - { x = 350, y = 68, min = 0, max = 50, vals = { 23 }, to = MIDSIZE }, - { x = 350, y = 110, min = 0, max = 3, vals = { 13 }, to = MIDSIZE, - table={ [0]="Off", "Preset", "Auto", "Manual"} }, - { x = 350, y = 155, min = 1, max = 50, vals = { 14 }, to = MIDSIZE } - }, -} diff --git a/src/SCRIPTS/BF/MSP/common.lua b/src/SCRIPTS/BF/MSP/common.lua index 21c22572..467c1ce1 100644 --- a/src/SCRIPTS/BF/MSP/common.lua +++ b/src/SCRIPTS/BF/MSP/common.lua @@ -1,13 +1,13 @@ - -- Protocol version -MSP_VERSION = bit32.lshift(1,5) -MSP_STARTFLAG = bit32.lshift(1,4) +local MSP_VERSION = bit32.lshift(1,5) +local MSP_STARTFLAG = bit32.lshift(1,4) -- Sequence number for next MSP packet local mspSeq = 0 local mspRemoteSeq = 0 local mspRxBuf = {} -local mspRxIdx = 1 +local mspRxError = false +local mspRxSize = 0 local mspRxCRC = 0 local mspRxReq = 0 local mspStarted = false @@ -15,9 +15,6 @@ local mspLastReq = 0 local mspTxBuf = {} local mspTxIdx = 1 local mspTxCRC = 0 -local mspTxPk = 0 - -mspPendingRequest = false function mspProcessTxQ() if (#(mspTxBuf) == 0) then @@ -34,10 +31,7 @@ function mspProcessTxQ() payload[1] = payload[1] + MSP_STARTFLAG end local i = 2 - while (i <= protocol.maxTxBufferSize) do - if mspTxIdx > #(mspTxBuf) then - break - end + while (i <= protocol.maxTxBufferSize) and mspTxIdx <= #mspTxBuf do payload[i] = mspTxBuf[mspTxIdx] mspTxIdx = mspTxIdx + 1 mspTxCRC = bit32.bxor(mspTxCRC,payload[i]) @@ -45,23 +39,13 @@ function mspProcessTxQ() end if i <= protocol.maxTxBufferSize then payload[i] = mspTxCRC - i = i + 1 - -- zero fill - while i <= protocol.maxTxBufferSize do - payload[i] = 0 - i = i + 1 - end - if protocol.mspSend(payload) then - mspTxPk = mspTxPk + 1 - end + protocol.mspSend(payload) mspTxBuf = {} mspTxIdx = 1 - mspTxCRC = 0 + mspTxCRC = 0 return false end - if protocol.mspSend(payload) then - mspTxPk = mspTxPk + 1 - end + protocol.mspSend(payload) return true end @@ -80,59 +64,57 @@ function mspSendRequest(cmd, payload) end function mspReceivedReply(payload) - local idx = 1 - local head = payload[idx] - local err_flag = (bit32.band(head,0x20) ~= 0) + local idx = 1 + local status = payload[idx] + local version = bit32.rshift(bit32.band(status, 0x60), 5) + local start = bit32.btest(status, 0x10) + local seq = bit32.band(status, 0x0F) idx = idx + 1 - if err_flag then - -- error flag set - mspStarted = false - return nil - end - local start = (bit32.band(head,0x10) ~= 0) - local seq = bit32.band(head,0x0F) if start then - -- start flag set - mspRxIdx = 1 mspRxBuf = {} + mspRxError = bit32.btest(status, 0x80) mspRxSize = payload[idx] - mspRxCRC = bit32.bxor(mspRxSize,mspLastReq) - mspRxReq = mspLastReq + mspRxReq = mspLastReq idx = idx + 1 - mspStarted = true + if version == 1 then + mspRxReq = payload[idx] + idx = idx + 1 + end + mspRxCRC = bit32.bxor(mspRxSize, mspRxReq) + if mspRxReq == mspLastReq then + mspStarted = true + end elseif not mspStarted then return nil elseif bit32.band(mspRemoteSeq + 1, 0x0F) ~= seq then mspStarted = false return nil end - while (idx <= protocol.maxRxBufferSize) and (mspRxIdx <= mspRxSize) do - mspRxBuf[mspRxIdx] = payload[idx] - mspRxCRC = bit32.bxor(mspRxCRC,payload[idx]) - mspRxIdx = mspRxIdx + 1 + while (idx <= protocol.maxRxBufferSize) and (#mspRxBuf < mspRxSize) do + mspRxBuf[#mspRxBuf + 1] = payload[idx] + mspRxCRC = bit32.bxor(mspRxCRC, payload[idx]) idx = idx + 1 end if idx > protocol.maxRxBufferSize then mspRemoteSeq = seq - return true + return false end + mspStarted = false -- check CRC - if mspRxCRC ~= payload[idx] then - mspStarted = false + if mspRxCRC ~= payload[idx] and version == 0 then return nil end - mspStarted = false - return mspRxBuf + return true end function mspPollReply() while true do - ret = protocol.mspPoll() - if type(ret) == "table" then - return mspRxReq, ret - else - break - end + local mspData = protocol.mspPoll() + if mspData == nil then + return nil + elseif mspReceivedReply(mspData) then + mspLastReq = 0 + return mspRxReq, mspRxBuf, mspRxError + end end - return nil end diff --git a/src/SCRIPTS/BF/MSP/crsf.lua b/src/SCRIPTS/BF/MSP/crsf.lua index 4dccb563..9fb4eeed 100644 --- a/src/SCRIPTS/BF/MSP/crsf.lua +++ b/src/SCRIPTS/BF/MSP/crsf.lua @@ -1,21 +1,19 @@ - -- CRSF Devices -CRSF_ADDRESS_BETAFLIGHT = 0xC8 -CRSF_ADDRESS_RADIO_TRANSMITTER = 0xEA +local CRSF_ADDRESS_BETAFLIGHT = 0xC8 +local CRSF_ADDRESS_RADIO_TRANSMITTER = 0xEA -- CRSF Frame Types -CRSF_FRAMETYPE_MSP_REQ = 0x7A -- response request using msp sequence as command -CRSF_FRAMETYPE_MSP_RESP = 0x7B -- reply with 60 byte chunked binary -CRSF_FRAMETYPE_MSP_WRITE = 0x7C -- write with 60 byte chunked binary +local CRSF_FRAMETYPE_MSP_REQ = 0x7A -- response request using msp sequence as command +local CRSF_FRAMETYPE_MSP_RESP = 0x7B -- reply with 60 byte chunked binary +local CRSF_FRAMETYPE_MSP_WRITE = 0x7C -- write with 60 byte chunked binary -crsfMspCmd = 0 -crsfMspHeader = {} +local crsfMspCmd = 0 protocol.mspSend = function(payload) local payloadOut = { CRSF_ADDRESS_BETAFLIGHT, CRSF_ADDRESS_RADIO_TRANSMITTER } for i=1, #(payload) do payloadOut[i+2] = payload[i] end - return crossfireTelemetryPush(crsfMspCmd, payloadOut) + return protocol.push(crsfMspCmd, payloadOut) end protocol.mspRead = function(cmd) @@ -29,15 +27,16 @@ protocol.mspWrite = function(cmd, payload) end protocol.mspPoll = function() - local command, data = crossfireTelemetryPop() - if command == CRSF_FRAMETYPE_MSP_RESP then - if data[1] == CRSF_ADDRESS_RADIO_TRANSMITTER and data[2] == CRSF_ADDRESS_BETAFLIGHT then + while true do + local cmd, data = crossfireTelemetryPop() + if cmd == CRSF_FRAMETYPE_MSP_RESP and data[1] == CRSF_ADDRESS_RADIO_TRANSMITTER and data[2] == CRSF_ADDRESS_BETAFLIGHT then local mspData = {} - for i=3, #(data) do - mspData[i-2] = data[i] + for i = 3, #data do + mspData[i - 2] = data[i] end - return mspReceivedReply(mspData) + return mspData + elseif cmd == nil then + return nil end end - return nil end diff --git a/src/SCRIPTS/BF/MSP/ghst.lua b/src/SCRIPTS/BF/MSP/ghst.lua new file mode 100644 index 00000000..53ef6166 --- /dev/null +++ b/src/SCRIPTS/BF/MSP/ghst.lua @@ -0,0 +1,31 @@ +-- GHST Frame Types +local GHST_FRAMETYPE_MSP_REQ = 0x21 +local GHST_FRAMETYPE_MSP_WRITE = 0x22 +local GHST_FRAMETYPE_MSP_RESP = 0x28 + +local ghstMspType = 0 + +protocol.mspSend = function(payload) + return protocol.push(ghstMspType, payload) +end + +protocol.mspRead = function(cmd) + ghstMspType = GHST_FRAMETYPE_MSP_REQ + return mspSendRequest(cmd, {}) +end + +protocol.mspWrite = function(cmd, payload) + ghstMspType = GHST_FRAMETYPE_MSP_WRITE + return mspSendRequest(cmd, payload) +end + +protocol.mspPoll = function() + while true do + local type, data = ghostTelemetryPop() + if type == GHST_FRAMETYPE_MSP_RESP then + return data + elseif type == nil then + return nil + end + end +end diff --git a/src/SCRIPTS/BF/MSP/messages.lua b/src/SCRIPTS/BF/MSP/messages.lua new file mode 100644 index 00000000..c778be8a --- /dev/null +++ b/src/SCRIPTS/BF/MSP/messages.lua @@ -0,0 +1,85 @@ +MSP_PID_FORMAT = { + read = 112, -- MSP_PID + write = 202, -- MSP_SET_PID + minBytes = 8, + fields = { + -- P + { vals = { 1 } }, + { vals = { 4 } }, + { vals = { 7 } }, + -- I + { vals = { 2 } }, + { vals = { 5 } }, + { vals = { 8 } }, + -- D + { vals = { 3 } }, + { vals = { 6 } }, + }, +} + +MSP_PID_ADVANCED_FORMAT = { + read = 94, -- MSP_PID_ADVANCED + write = 95, -- MSP_SET_PID_ADVANCED + minBytes = 23, + fields = { + -- weight + { vals = { 10 }, scale = 100 }, + -- transition + { vals = { 9 }, scale = 100 }, + }, +} + +local INTRO_DELAY = 1600 +local READOUT_DELAY = 500 + +function extractMspValues(cmd, rx_buf, msgFormat, msgValues) + if cmd == nil or rx_buf == nil then + return + end + if cmd ~= msgFormat.read then + return + end + if #(rx_buf) > 0 then + msgValues.raw = {} + for i=1,#(rx_buf) do + msgValues.raw[i] = rx_buf[i] + end + + msgValues.values = {} + for i=1,#(msgFormat.fields) do + if (#(msgValues.raw) or 0) >= msgFormat.minBytes then + local f = msgFormat.fields[i] + if f.vals then + local value = 0; + for idx=1, #(f.vals) do + local raw_val = msgValues.raw[f.vals[idx]] + raw_val = bit32.lshift(raw_val, (idx-1)*8) + value = bit32.bor(value, raw_val) + end + msgValues.values[i] = value/(f.scale or 1) + end + end + end + end +end + +function readoutMsp(msgFormat, msg) + local t = getTime() + if msg.lastTrigger == nil or msg.lastTrigger + INTRO_DELAY <= t then + playFile(msg.intro) + msg.lastTrigger = t + elseif msg.reqTS == nil or msg.reqTS + READOUT_DELAY <= t then + protocol.mspRead(msgFormat.read) + msg.reqTS = t + else + local cmd, rx_buf = mspPollReply() + extractMspValues(cmd, rx_buf, msgFormat, msg) + if msg.raw then + for i=1,#(msg.readoutValues) do + playNumber(msg.values[msg.readoutValues[i]], 0) + end + msg.raw = nil + end + end + mspProcessTxQ() +end diff --git a/src/SCRIPTS/BF/MSP/sp.lua b/src/SCRIPTS/BF/MSP/sp.lua index 5174a2e8..7d2bc991 100644 --- a/src/SCRIPTS/BF/MSP/sp.lua +++ b/src/SCRIPTS/BF/MSP/sp.lua @@ -1,17 +1,18 @@ +local LOCAL_SENSOR_ID = 0x0D +local SMARTPORT_REMOTE_SENSOR_ID = 0x1B +local FPORT_REMOTE_SENSOR_ID = 0x00 +local REQUEST_FRAME_ID = 0x30 +local REPLY_FRAME_ID = 0x32 -LOCAL_SENSOR_ID = 0x0D -SMARTPORT_REMOTE_SENSOR_ID = 0x1B -FPORT_REMOTE_SENSOR_ID = 0x00 -REQUEST_FRAME_ID = 0x30 -REPLY_FRAME_ID = 0x32 +local lastSensorId, lastFrameId, lastDataId, lastValue protocol.mspSend = function(payload) - local dataId = 0 - dataId = payload[1] + bit32.lshift(payload[2],8) + local dataId = payload[1] + bit32.lshift(payload[2], 8) local value = 0 - value = payload[3] + bit32.lshift(payload[4],8) - + bit32.lshift(payload[5],16) + bit32.lshift(payload[6],24) - return sportTelemetryPush(LOCAL_SENSOR_ID, REQUEST_FRAME_ID, dataId, value) + for i = 3, #payload do + value = value + bit32.lshift(payload[i], (i - 3) * 8) + end + return protocol.push(LOCAL_SENSOR_ID, REQUEST_FRAME_ID, dataId, value) end protocol.mspRead = function(cmd) @@ -22,21 +23,42 @@ protocol.mspWrite = function(cmd, payload) return mspSendRequest(cmd, payload) end +-- Discards duplicate data from lua input buffer +local function smartPortTelemetryPop() + while true do + local sensorId, frameId, dataId, value = sportTelemetryPop() + if not sensorId then + return nil + elseif (lastSensorId == sensorId) and (lastFrameId == frameId) and (lastDataId == dataId) and (lastValue == value) then + -- Keep checking + else + lastSensorId = sensorId + lastFrameId = frameId + lastDataId = dataId + lastValue = value + return sensorId, frameId, dataId, value + end + end +end + protocol.mspPoll = function() - local sensorId, frameId, dataId, value = sportTelemetryPop() - if (sensorId == SMARTPORT_REMOTE_SENSOR_ID or sensorId == FPORT_REMOTE_SENSOR_ID) and frameId == REPLY_FRAME_ID then - local payload = {} - payload[1] = bit32.band(dataId,0xFF) - dataId = bit32.rshift(dataId,8) - payload[2] = bit32.band(dataId,0xFF) - payload[3] = bit32.band(value,0xFF) - value = bit32.rshift(value,8) - payload[4] = bit32.band(value,0xFF) - value = bit32.rshift(value,8) - payload[5] = bit32.band(value,0xFF) - value = bit32.rshift(value,8) - payload[6] = bit32.band(value,0xFF) - return mspReceivedReply(payload) + while true do + local sensorId, frameId, dataId, value = smartPortTelemetryPop() + if (sensorId == SMARTPORT_REMOTE_SENSOR_ID or sensorId == FPORT_REMOTE_SENSOR_ID) and frameId == REPLY_FRAME_ID then + local payload = {} + payload[1] = bit32.band(dataId, 0xFF) + dataId = bit32.rshift(dataId, 8) + payload[2] = bit32.band(dataId, 0xFF) + payload[3] = bit32.band(value, 0xFF) + value = bit32.rshift(value, 8) + payload[4] = bit32.band(value, 0xFF) + value = bit32.rshift(value, 8) + payload[5] = bit32.band(value, 0xFF) + value = bit32.rshift(value, 8) + payload[6] = bit32.band(value, 0xFF) + return payload + elseif sensorId == nil then + return nil + end end - return nil end diff --git a/src/SCRIPTS/BF/PAGES/INIT/pwm.lua b/src/SCRIPTS/BF/PAGES/INIT/pwm.lua new file mode 100644 index 00000000..34232f85 --- /dev/null +++ b/src/SCRIPTS/BF/PAGES/INIT/pwm.lua @@ -0,0 +1,15 @@ +local function precondition() + if apiVersion < 1.44 then + -- BOARD_INFO is unavailable below 1.44 + return nil + end + local hasBoardInfo = loadScript("BOARD_INFO/"..mcuId..".lua") + collectgarbage() + if hasBoardInfo then + return nil + else + return "CONFIRM/pwm.lua" + end +end + +return precondition() diff --git a/src/SCRIPTS/BF/PAGES/INIT/vtx.lua b/src/SCRIPTS/BF/PAGES/INIT/vtx.lua new file mode 100644 index 00000000..ac5dbe33 --- /dev/null +++ b/src/SCRIPTS/BF/PAGES/INIT/vtx.lua @@ -0,0 +1,11 @@ +local function precondition() + local hasVtxTable = loadScript("VTX_TABLES/"..mcuId..".lua") + collectgarbage() + if hasVtxTable then + return nil + else + return "CONFIRM/vtx_tables.lua" + end +end + +return precondition() diff --git a/src/SCRIPTS/BF/PAGES/acc_trim.lua b/src/SCRIPTS/BF/PAGES/acc_trim.lua new file mode 100644 index 00000000..96ab0896 --- /dev/null +++ b/src/SCRIPTS/BF/PAGES/acc_trim.lua @@ -0,0 +1,27 @@ +local template = assert(loadScript(radio.template))() +local margin = template.margin +local indent = template.indent +local lineSpacing = template.lineSpacing +local tableSpacing = template.tableSpacing +local sp = template.listSpacing.field +local yMinLim = radio.yMinLimit +local x = margin +local y = yMinLim - lineSpacing +local inc = { x = function(val) x = x + val return x end, y = function(val) y = y + val return y end } +local labels = {} +local fields = {} + +labels[#labels + 1] = { t = "Trim Accelerometer", x = x, y = inc.y(lineSpacing) } +fields[#fields + 1] = { t = "Pitch", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = -300, max = 300, vals = { 1, 2 } } +fields[#fields + 1] = { t = "Roll", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = -300, max = 300, vals = { 3, 4 } } + +return { + read = 240, -- MSP_ACC_TRIM + write = 239, -- MSP_SET_ACC_TRIM + title = "Acc", + reboot = false, + eepromWrite = true, + minBytes = 4, + labels = labels, + fields = fields, +} diff --git a/src/SCRIPTS/BF/PAGES/battery.lua b/src/SCRIPTS/BF/PAGES/battery.lua new file mode 100644 index 00000000..43a08f1f --- /dev/null +++ b/src/SCRIPTS/BF/PAGES/battery.lua @@ -0,0 +1,31 @@ +local template = assert(loadScript(radio.template))() +local margin = template.margin +local indent = template.indent +local lineSpacing = template.lineSpacing +local tableSpacing = template.tableSpacing +local sp = template.listSpacing.field +local yMinLim = radio.yMinLimit +local x = margin +local y = yMinLim - lineSpacing +local inc = { x = function(val) x = x + val return x end, y = function(val) y = y + val return y end } +local labels = {} +local fields = {} + +labels[#labels + 1] = { t = "Voltage Settings", x = x, y = inc.y(lineSpacing) } +fields[#fields + 1] = { t = "Minimum Cell", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 500, vals = { 8, 9 }, scale = 100 } +fields[#fields + 1] = { t = "Maximum Cell", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 500, vals = { 10, 11 }, scale = 100 } +fields[#fields + 1] = { t = "Warning Cell", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 500, vals = { 12, 13 }, scale = 100 } + +labels[#labels + 1] = { t = "Capacity Settings", x = x, y = inc.y(lineSpacing) } +fields[#fields + 1] = { t = "Battery Capacity", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, mult = 25, max = 20000, vals = { 4, 5 } } + +return { + read = 32, -- MSP_BATTERY_CONFIG + write = 33, -- MSP_SET_BATTERY_CONFIG + title = "Battery", + reboot = false, + eepromWrite = true, + minBytes = 13, + labels = labels, + fields = fields +} diff --git a/src/SCRIPTS/BF/PAGES/failsafe.lua b/src/SCRIPTS/BF/PAGES/failsafe.lua new file mode 100644 index 00000000..5269a390 --- /dev/null +++ b/src/SCRIPTS/BF/PAGES/failsafe.lua @@ -0,0 +1,45 @@ +local template = assert(loadScript(radio.template))() +local margin = template.margin +local indent = template.indent +local lineSpacing = template.lineSpacing +local tableSpacing = template.tableSpacing +local sp = template.listSpacing.field +local yMinLim = radio.yMinLimit +local x = margin +local y = yMinLim - lineSpacing +local inc = { x = function(val) x = x + val return x end, y = function(val) y = y + val return y end } +local labels = {} +local fields = {} + +local procedure = { [0] = "Land", "Drop" } + +if apiVersion >= 1.39 then + procedure[#procedure + 1] = "Rescue" +end + +if apiVersion >= 1.39 then + labels[#labels + 1] = { t = "Failsafe Switch", x = x, y = inc.y(lineSpacing) } + fields[#fields + 1] = { t = "Action", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 2, vals = { 5 }, table = { [0] = "Stage 1", "Kill", "Stage 2" } } +else + fields[#fields + 1] = { t = "Kill switch", x = x, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 1, vals = { 5 }, table = { [0] = "OFF", "ON" } } +end + +labels[#labels + 1] = { t = "Stage 2 Settings" , x = x, y = inc.y(lineSpacing) } +fields[#fields + 1] = { t = "Procedure", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = #procedure, vals = { 8 }, table = procedure } +fields[#fields + 1] = { t = "Guard Time", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 200, vals = { 1 }, scale = 10 } +fields[#fields + 1] = { t = "Thrl Low Delay", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 300, vals = { 6, 7 }, scale = 10 } + +labels[#labels + 1] = { t = "Stage 2 Land Settings", x = x, y = inc.y(lineSpacing) } +fields[#fields + 1] = { t = "Thrl Land Value", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 750, max = 2250, vals = { 3, 4 } } +fields[#fields + 1] = { t = "Motor Off Delay", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 200, vals = { 2 }, scale = 10 } + +return { + read = 75, -- MSP_FAILSAFE_CONFIG + write = 76, -- MSP_SET_FAILSAFE_CONFIG + title = "Failsafe", + reboot = true, + eepromWrite = true, + minBytes = 8, + labels = labels, + fields = fields, +} diff --git a/src/SCRIPTS/BF/PAGES/filters1.lua b/src/SCRIPTS/BF/PAGES/filters1.lua new file mode 100644 index 00000000..4b85a745 --- /dev/null +++ b/src/SCRIPTS/BF/PAGES/filters1.lua @@ -0,0 +1,107 @@ +local template = assert(loadScript(radio.template))() +local margin = template.margin +local indent = template.indent +local lineSpacing = template.lineSpacing +local tableSpacing = template.tableSpacing +local sp = template.listSpacing.field +local yMinLim = radio.yMinLimit +local x = margin +local y = yMinLim - lineSpacing +local inc = { x = function(val) x = x + val return x end, y = function(val) y = y + val return y end } +local labels = {} +local fields = {} + +local gyroFilterType = { [0] = "PT1", "BIQUAD" } + +if apiVersion >= 1.44 then + gyroFilterType[#gyroFilterType + 1] = "PT2" + gyroFilterType[#gyroFilterType + 1] = "PT3" +end + +local dtermFilterType = gyroFilterType + +if apiVersion >= 1.36 and apiVersion <= 1.38 then + dtermFilterType = { [0] = "PT1", "BIQUAD", "FIR" } +end + +local dtermFilterType2 = gyroFilterType + +if apiVersion >= 1.41 then + labels[#labels + 1] = { t = "Gyro Lowpass 1 Dynamic", x = x, y = inc.y(lineSpacing) } + fields[#fields + 1] = { t = "Min Cutoff", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 1000, vals = { 30, 31 } } + fields[#fields + 1] = { t = "Max Cutoff", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 1000, vals = { 32, 33 } } + fields[#fields + 1] = { t = "Filter Type", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = #gyroFilterType, vals = { 25 }, table = gyroFilterType } +end + +if apiVersion >= 1.16 then + labels[#labels + 1] = { t = "Gyro Lowpass 1", x = x, y = inc.y(lineSpacing) } + if apiVersion >= 1.39 then + fields[#fields + 1] = { t = "Cutoff", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 16000, vals = { 21, 22 } } + fields[#fields + 1] = { t = "Filter Type", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = #gyroFilterType, vals = { 25 }, table = gyroFilterType } + else + fields[#fields + 1] = { t = "Cutoff", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 255, vals = { 1 } } + end +end + +if apiVersion >= 1.39 then + labels[#labels + 1] = { t = "Gyro Lowpass 2", x = x, y = inc.y(lineSpacing) } + fields[#fields + 1] = { t = "Cutoff", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 16000, vals = { 23, 24 } } + fields[#fields + 1] = { t = "Filter Type", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = #gyroFilterType, vals = { 26 }, table = gyroFilterType } +end + +if apiVersion >= 1.20 then + labels[#labels + 1] = { t = "Gyro Notch 1", x = x, y = inc.y(lineSpacing) } + fields[#fields + 1] = { t = "Center", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 16000, vals = { 6, 7 } } + fields[#fields + 1] = { t = "Cutoff", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 16000, vals = { 8, 9 } } +end + +if apiVersion >= 1.21 then + labels[#labels + 1] = { t = "Gyro Notch 2", x = x, y = inc.y(lineSpacing) } + fields[#fields + 1] = { t = "Center", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 16000, vals = { 14, 15 } } + fields[#fields + 1] = { t = "Cutoff", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 16000, vals = { 16, 17 } } +end + +if apiVersion >= 1.41 then + labels[#labels + 1] = { t = "D Term Lowpass 1 Dynamic", x = x, y = inc.y(lineSpacing) } + fields[#fields + 1] = { t = "Min Cutoff", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 1000, vals = { 34, 35 } } + fields[#fields + 1] = { t = "Max Cutoff", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 1000, vals = { 36, 37 } } + fields[#fields + 1] = { t = "Filter Type", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = #dtermFilterType, vals = { 18 }, table = dtermFilterType } +end + +if apiVersion >= 1.16 then + labels[#labels + 1] = { t = "D Term Lowpass 1", x = x, y = inc.y(lineSpacing) } + fields[#fields + 1] = { t = "Cutoff", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 16000, vals = { 2, 3 } } + if apiVersion >= 1.36 then + fields[#fields + 1] = { t = "Filter Type", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = #dtermFilterType, vals = { 18 }, table = dtermFilterType } + end +end + +if apiVersion >= 1.39 then + labels[#labels + 1] = { t = "D Term Lowpass 2", x = x, y = inc.y(lineSpacing) } + fields[#fields + 1] = { t = "Cutoff", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 16000, vals = { 27, 28 } } + if apiVersion >= 1.41 then + fields[#fields + 1] = { t = "Filter Type", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = #dtermFilterType2, vals = { 29 }, table = dtermFilterType2 } + end +end + +if apiVersion >= 1.20 then + labels[#labels + 1] = { t = "D Term Notch", x = x, y = inc.y(lineSpacing) } + fields[#fields + 1] = { t = "Center", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 16000, vals = { 10, 11 } } + fields[#fields + 1] = { t = "Cutoff", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 16000, vals = { 12, 13 } } +end + +if apiVersion >= 1.16 then + labels[#labels + 1] = { t = "Yaw Lowpass", x = x, y = inc.y(lineSpacing) } + fields[#fields + 1] = { t = "Cutoff", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 500, vals = { 4, 5 } } +end + +return { + read = 92, -- MSP_FILTER_CONFIG + write = 93, -- MSP_SET_FILTER_CONFIG + eepromWrite = true, + reboot = false, + title = "Filters (1/2)", + minBytes = 5, + labels = labels, + fields = fields, +} diff --git a/src/SCRIPTS/BF/PAGES/filters2.lua b/src/SCRIPTS/BF/PAGES/filters2.lua new file mode 100644 index 00000000..7fb2e44f --- /dev/null +++ b/src/SCRIPTS/BF/PAGES/filters2.lua @@ -0,0 +1,52 @@ +local template = assert(loadScript(radio.template))() +local margin = template.margin +local indent = template.indent +local lineSpacing = template.lineSpacing +local tableSpacing = template.tableSpacing +local sp = template.listSpacing.field +local yMinLim = radio.yMinLimit +local x = margin +local y = yMinLim - lineSpacing +local inc = { x = function(val) x = x + val return x end, y = function(val) y = y + val return y end } +local labels = {} +local fields = {} + +if apiVersion >= 1.42 then + labels[#labels + 1] = { t = "Gyro RPM Filter", x = x, y = inc.y(lineSpacing) } + fields[#fields + 1] = { t = "Harmonics", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 3, vals = { 44 } } + fields[#fields + 1] = { t = "Min Frequency", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 50, max = 200, vals = { 45 } } + labels[#labels + 1] = { t = "Dynamic Notch Filter", x = x, y = inc.y(lineSpacing) } + if apiVersion < 1.43 then + fields[#fields + 1] = { t = "Range", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 3, vals = { 38 }, table = { [0]="HIGH", "MEDIUM", "LOW", "AUTO" } } + end + if apiVersion >= 1.44 then + fields[#fields + 1] = { t = "Count", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 5, vals = { 49 } } + else + fields[#fields + 1] = { t = "Width %", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 20, vals = { 39 } } + end + fields[#fields + 1] = { t = "Q", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 1, max = 1000, vals = { 40, 41 } } + if apiVersion >= 1.43 then + fields[#fields + 1] = { t = "Min Frequency", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 60, max = 250, vals = { 42, 43 } } + fields[#fields + 1] = { t = "Max Frequency", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 200, max = 1000, vals = { 46, 47 } } + else + fields[#fields + 1] = { t = "Min Frequency", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 60, max = 1000, vals = { 42, 43 } } + end +end + +return { + read = 92, -- MSP_FILTER_CONFIG + write = 93, -- MSP_SET_FILTER_CONFIG + eepromWrite = true, + reboot = false, + title = "Filters (2/2)", + minBytes = 5, + labels = labels, + fields = fields, + postLoad = function(self) + self.rpmHarmonics = self.values[44] + end, + preSave = function(self) + self.reboot = self.values[44] == 0 and self.rpmHarmonics ~= 0 and apiVersion <= 1.43 + return self.values + end, +} diff --git a/src/SCRIPTS/BF/PAGES/gpspids.lua b/src/SCRIPTS/BF/PAGES/gpspids.lua new file mode 100644 index 00000000..a28685f1 --- /dev/null +++ b/src/SCRIPTS/BF/PAGES/gpspids.lua @@ -0,0 +1,54 @@ +local template = assert(loadScript(radio.template))() +local margin = template.margin +local indent = template.indent +local lineSpacing = template.lineSpacing +local tableSpacing = template.tableSpacing +local sp = template.listSpacing.field +local yMinLim = radio.yMinLimit +local x = margin +local y = yMinLim - lineSpacing +local inc = { x = function(val) x = x + val return x end, y = function(val) y = y + val return y end } +local labels = {} +local fields = {} + +if apiVersion >= 1.41 then + x = margin + y = yMinLim - tableSpacing.header + labels[#labels + 1] = { t = "", x = x, y = inc.y(tableSpacing.header) } + labels[#labels + 1] = { t = "Throttle", x = x, y = inc.y(tableSpacing.row) } + labels[#labels + 1] = { t = "Velocity", x = x, y = inc.y(tableSpacing.row) } + labels[#labels + 1] = { t = "Yaw", x = x, y = inc.y(tableSpacing.row) } + + x = x + tableSpacing.col*1.3 + y = yMinLim - tableSpacing.header + + labels[#labels + 1] = { t = "P", x = x, y = inc.y(tableSpacing.header) } + fields[#fields + 1] = { x = x, y = inc.y(tableSpacing.row), min = 0, max = 200, vals = { 1, 2 } } + fields[#fields + 1] = { x = x, y = inc.y(tableSpacing.row), min = 0, max = 200, vals = { 7, 8 } } + fields[#fields + 1] = { x = x, y = inc.y(tableSpacing.row), min = 0, max = 500, vals = { 13, 14 } } + + x = x + tableSpacing.col + y = yMinLim - tableSpacing.header + + labels[#labels + 1] = { t = "I", x = x, y = inc.y(tableSpacing.header) } + fields[#fields + 1] = { x = x, y = inc.y(tableSpacing.row), min = 0, max = 200, vals = { 3, 4 } } + fields[#fields + 1] = { x = x, y = inc.y(tableSpacing.row), min = 0, max = 200, vals = { 9, 10 } } + + x = x + tableSpacing.col + y = yMinLim - tableSpacing.header + + labels[#labels + 1] = { t = "D", x = x, y = inc.y(tableSpacing.header) } + fields[#fields + 1] = { x = x, y = inc.y(tableSpacing.row), min = 0, max = 200, vals = { 5, 6 } } + fields[#fields + 1] = { x = x, y = inc.y(tableSpacing.row), min = 0, max = 200, vals = { 11, 12 } } +end + +return { + read = 136, -- MSP_GPS_RESCUE_PIDS + write = 226, -- MSP_SET_GPS_RESCUE_PIDS + title = "GPS Rescue / PIDs", + reboot = false, + eepromWrite = true, + minBytes = 14, + labels = labels, + fields = fields, +} diff --git a/src/SCRIPTS/BF/PAGES/pid_advanced.lua b/src/SCRIPTS/BF/PAGES/pid_advanced.lua new file mode 100644 index 00000000..5be23f12 --- /dev/null +++ b/src/SCRIPTS/BF/PAGES/pid_advanced.lua @@ -0,0 +1,107 @@ +local template = assert(loadScript(radio.template))() +local margin = template.margin +local indent = template.indent +local lineSpacing = template.lineSpacing +local tableSpacing = template.tableSpacing +local sp = template.listSpacing.field +local yMinLim = radio.yMinLimit +local x = margin +local y = yMinLim - lineSpacing +local inc = { x = function(val) x = x + val return x end, y = function(val) y = y + val return y end } +local labels = {} +local fields = {} + +if apiVersion >= 1.31 then + labels[#labels + 1] = { t = "Angle/Horizon", x = x, y = inc.y(lineSpacing) } + fields[#fields + 1] = { t = "Angle Limit", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 10, max = 90, vals = { 18 } } + if apiVersion < 1.36 then + fields[#fields + 1] = { t = "Stick Sensitivity", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 10, max = 200, vals = { 19 } } + end +end + +if apiVersion >= 1.40 then + labels[#labels + 1] = { t = "Acro Trainer", x = x, y = inc.y(lineSpacing) } + fields[#fields + 1] = { t = "Angle Limit", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 20, max = 80, vals = { 32 } } + fields[#fields + 1] = { t = "Throttle Boost", x = x, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 100, vals = { 31 } } + fields[#fields + 1] = { t = "Absolute Control", x = x, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 20, vals = { 30 } } + fields[#fields + 1] = { t = "I Term Rotation", x = x, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 1, vals = { 26 }, table = { [0] = "OFF", "ON" } } +end + +if apiVersion >= 1.43 then + fields[#fields + 1] = { t = "Motor Output Limit",x = x, y = inc.y(lineSpacing), sp = x + sp, min = 1, max = 100, vals = { 48 } } + if apiVersion >= 1.45 then + fields[#fields + 1] = { t = "Dynamic Idle", x = x, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 200, vals = { 50 } } + else + fields[#fields + 1] = { t = "Dynamic Idle", x = x, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 100, vals = { 50 } } + end +end + +if apiVersion >= 1.16 and apiVersion <= 1.43 then + fields[#fields + 1] = { t = "VBAT Compensation", x = x, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 1, vals = { 8 }, table = { [0] = "OFF", "ON" } } +end + +if apiVersion >= 1.44 then + fields[#fields + 1] = { t = "Vbat Sag Comp", x = x, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 150, vals = { 56 } } + fields[#fields + 1] = { t = "Thrust Linear", x = x, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 150, vals = { 57 } } +end + +if apiVersion >= 1.45 then + labels[#labels + 1] = { t = "TPA", x = x, y = inc.y(lineSpacing) } + fields[#fields + 1] = { t = "Mode", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 1, vals = { 58 }, table = { [0] = "PD", "D" } } + fields[#fields + 1] = { t = "Rate", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 100, vals = { 59 } , scale = 100 } + fields[#fields + 1] = { t = "Breakpoint", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 750, max = 2250, vals = { 60, 61 } } +end + +if apiVersion >= 1.40 and apiVersion <= 1.41 then + fields[#fields + 1] = { t = "Smart Feedforward", x = x, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 1, vals = { 27 }, table = { [0] = "OFF", "ON" } } +end + +if apiVersion >= 1.41 then + fields[#fields + 1] = { t = "Integrated Yaw", x = x, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 1, vals = { 45 }, table = { [0] = "OFF", "ON" } } +end + +if apiVersion >= 1.40 then + labels[#labels + 1] = { t = "I Term Relax", x = x, y = inc.y(lineSpacing) } + fields[#fields + 1] = { t = "Axes", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 4, vals = { 28 }, table = { [0] = "NONE", "RP", "RPY", "RP (inc)", "RPY (inc)" } } + fields[#fields + 1] = { t = "Type", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 1, vals = { 29 }, table = { [0] = "Gyro", "Setpoint" } } + if apiVersion >= 1.43 then + fields[#fields + 1] = { t = "Cutoff", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 1, max = 50, vals = { 47 } } + elseif apiVersion >= 1.42 then + fields[#fields + 1] = { t = "Cutoff", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 1, max = 100, vals = { 47 } } + end +end + +if apiVersion >= 1.36 then + labels[#labels + 1] = { t = "Anti Gravity", x = x, y = inc.y(lineSpacing) } + if apiVersion >= 1.40 and apiVersion <= 1.44 then + fields[#fields + 1] = { t = "Mode", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 1, vals = { 39 }, table = { [0] = "Smooth", "Step" } } + end + if apiVersion >= 1.45 then + fields[#fields + 1] = { t = "Gain", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 250, vals = { 22, 23 }, scale = 10 } + elseif apiVersion >= 1.44 then + fields[#fields + 1] = { t = "Gain", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 30000, vals = { 22, 23 }, scale = 1000, mult = 100 } + else + fields[#fields + 1] = { t = "Gain", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 1000, max = 30000, vals = { 22, 23 }, scale = 1000, mult = 100 } + end + if apiVersion <= 1.44 then + fields[#fields + 1] = { t = "Threshold", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 20, max = 1000, vals = { 20, 21 } } + end +end + +return { + read = 94, -- MSP_PID_ADVANCED + write = 95, -- MSP_SET_PID_ADVANCED + title = "PID Advanced", + reboot = false, + eepromWrite = true, + minBytes = 8, + labels = labels, + fields = fields, + postLoad = function(self) + self.dynamicIdle = self.values[50] + end, + preSave = function(self) + self.reboot = self.values[50] ~= self.dynamicIdle and apiVersion <= 1.43 + return self.values + end, +} diff --git a/src/SCRIPTS/BF/PAGES/pids1.lua b/src/SCRIPTS/BF/PAGES/pids1.lua new file mode 100644 index 00000000..5102e316 --- /dev/null +++ b/src/SCRIPTS/BF/PAGES/pids1.lua @@ -0,0 +1,67 @@ +local template = assert(loadScript(radio.template))() +local margin = template.margin +local indent = template.indent +local lineSpacing = template.lineSpacing +local tableSpacing = template.tableSpacing +local sp = template.listSpacing.field +local yMinLim = radio.yMinLimit +local x = margin +local y = yMinLim - lineSpacing +local inc = { x = function(val) x = x + val return x end, y = function(val) y = y + val return y end } +local labels = {} +local fields = {} + +local pidMax = 200 +local dLabel = "D" + +if apiVersion >= 1.44 then + pidMax = 250 + dLabel = "D Max" +end + +if apiVersion >= 1.16 then + x = margin + y = yMinLim - tableSpacing.header + + labels[#labels + 1] = { t = "", x = x, y = inc.y(tableSpacing.header) } + labels[#labels + 1] = { t = "ROLL", x = x, y = inc.y(tableSpacing.row) } + labels[#labels + 1] = { t = "PITCH", x = x, y = inc.y(tableSpacing.row) } + labels[#labels + 1] = { t = "YAW", x = x, y = inc.y(tableSpacing.row) } + + x = x + tableSpacing.col + y = yMinLim - tableSpacing.header + + labels[#labels + 1] = { t = "P", x = x, y = inc.y(tableSpacing.header) } + fields[#fields + 1] = { x = x, y = inc.y(tableSpacing.row), min = 0, max = pidMax, vals = { 1 } } + fields[#fields + 1] = { x = x, y = inc.y(tableSpacing.row), min = 0, max = pidMax, vals = { 4 } } + fields[#fields + 1] = { x = x, y = inc.y(tableSpacing.row), min = 0, max = pidMax, vals = { 7 } } + + x = x + tableSpacing.col + y = yMinLim - tableSpacing.header + + labels[#labels + 1] = { t = "I", x = x, y = inc.y(tableSpacing.header) } + fields[#fields + 1] = { x = x, y = inc.y(tableSpacing.row), min = 0, max = pidMax, vals = { 2 } } + fields[#fields + 1] = { x = x, y = inc.y(tableSpacing.row), min = 0, max = pidMax, vals = { 5 } } + fields[#fields + 1] = { x = x, y = inc.y(tableSpacing.row), min = 0, max = pidMax, vals = { 8 } } + + x = x + tableSpacing.col + y = yMinLim - tableSpacing.header + + labels[#labels + 1] = { t = dLabel, x = x, y = inc.y(tableSpacing.header) } + fields[#fields + 1] = { x = x, y = inc.y(tableSpacing.row), min = 0, max = pidMax, vals = { 3 } } + fields[#fields + 1] = { x = x, y = inc.y(tableSpacing.row), min = 0, max = pidMax, vals = { 6 } } + if apiVersion >= 1.41 then + fields[#fields + 1] = { x = x, y = inc.y(tableSpacing.row), min = 0, max = pidMax, vals = { 9 } } + end +end + +return { + read = 112, -- MSP_PID + write = 202, -- MSP_SET_PID + title = "PIDs (1/2)", + reboot = false, + eepromWrite = true, + minBytes = 9, + labels = labels, + fields = fields, +} diff --git a/src/SCRIPTS/BF/PAGES/pids2.lua b/src/SCRIPTS/BF/PAGES/pids2.lua new file mode 100644 index 00000000..5acca134 --- /dev/null +++ b/src/SCRIPTS/BF/PAGES/pids2.lua @@ -0,0 +1,88 @@ +local template = assert(loadScript(radio.template))() +local margin = template.margin +local indent = template.indent +local lineSpacing = template.lineSpacing +local tableSpacing = template.tableSpacing +local sp = template.listSpacing.field +local yMinLim = radio.yMinLimit +local x = margin +local y = yMinLim - lineSpacing +local inc = { x = function(val) x = x + val return x end, y = function(val) y = y + val return y end } +local labels = {} +local fields = {} + +local dMinMax = 100 + +if apiVersion >= 1.44 then + dMinMax = 250 +end + +if apiVersion >= 1.40 then + x = margin + y = yMinLim - tableSpacing.header + + labels[#labels + 1] = { t = "", x = x, y = inc.y(tableSpacing.header) } + labels[#labels + 1] = { t = "ROLL", x = x, y = inc.y(tableSpacing.row) } + labels[#labels + 1] = { t = "PITCH", x = x, y = inc.y(tableSpacing.row) } + labels[#labels + 1] = { t = "YAW", x = x, y = inc.y(tableSpacing.row) } + + x = x + tableSpacing.col + y = yMinLim - tableSpacing.header + + labels[#labels + 1] = { t = "FF", x = x, y = inc.y(tableSpacing.header) } + fields[#fields + 1] = { x = x, y = inc.y(tableSpacing.row), min = 0, max = 2000, vals = { 33, 34 } } + fields[#fields + 1] = { x = x, y = inc.y(tableSpacing.row), min = 0, max = 2000, vals = { 35, 36 } } + fields[#fields + 1] = { x = x, y = inc.y(tableSpacing.row), min = 0, max = 2000, vals = { 37, 38 } } + + if apiVersion >= 1.41 then + x = x + tableSpacing.col + y = yMinLim - tableSpacing.header + + labels[#labels + 1] = { t = "D Min", x = x, y = inc.y(tableSpacing.header) } + fields[#fields + 1] = { x = x, y = inc.y(tableSpacing.row), min = 0, max = dMinMax, vals = { 40 } } + fields[#fields + 1] = { x = x, y = inc.y(tableSpacing.row), min = 0, max = dMinMax, vals = { 41 } } + fields[#fields + 1] = { x = x, y = inc.y(tableSpacing.row), min = 0, max = dMinMax, vals = { 42 } } + end + + x = margin + y = inc.y(lineSpacing*0.4) +end + +if apiVersion >= 1.40 then + labels[#labels + 1] = { t = "Feedforward", x = x, y = inc.y(lineSpacing) } + if apiVersion >= 1.44 then + fields[#fields + 1] = { t = "Jitter Reduction", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 20, vals = { 55 } } + fields[#fields + 1] = { t = "Smoothness", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 75, vals = { 52 } } + fields[#fields + 1] = { t = "Averaging", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 3, vals = { 51 }, table = { [0] = "OFF", "2_POINT", "3_POINT", "4_POINT" } } + fields[#fields + 1] = { t = "Boost", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 50, vals = { 53 } } + fields[#fields + 1] = { t = "Max Rate Limit", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 150, vals = { 54 } } + end + fields[#fields + 1] = { t = "Transition", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 100, vals = { 9 }, scale = 100 } +end + +if apiVersion >= 1.41 then + labels[#labels + 1] = { t = "D Min", x = x, y = inc.y(lineSpacing) } + fields[#fields + 1] = { t = "Gain", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 100, vals = { 43 } } + fields[#fields + 1] = { t = "Advance", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 200, vals = { 44 } } +end + +if apiVersion >= 1.21 and apiVersion <= 1.39 then + labels[#labels + 1] = { t = "Dterm Setpoint", x = x, y = inc.y(lineSpacing) } + if apiVersion >= 1.21 and apiVersion <= 1.38 then + fields[#fields + 1] = { t = "Weight", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 254, vals = { 10 }, scale = 100 } + else + fields[#fields + 1] = { t = "Weight", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 254, vals = { 25 }, scale = 100 } + end + fields[#fields + 1] = { t = "Transition", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 100, vals = { 9 }, scale = 100 } +end + +return { + read = 94, -- MSP_PID_ADVANCED + write = 95, -- MSP_SET_PID_ADVANCED + title = "PIDs (2/2)", + reboot = false, + eepromWrite = true, + minBytes = 17, + labels = labels, + fields = fields, +} diff --git a/src/SCRIPTS/BF/PAGES/pos_osd.lua b/src/SCRIPTS/BF/PAGES/pos_osd.lua new file mode 100644 index 00000000..2e5c2628 --- /dev/null +++ b/src/SCRIPTS/BF/PAGES/pos_osd.lua @@ -0,0 +1,159 @@ +local template = assert(loadScript(radio.template))() +local margin = template.margin +local lineSpacing = template.lineSpacing +local tableSpacing = template.tableSpacing +local yMinLim = radio.yMinLimit +local x = margin +local y = yMinLim - lineSpacing +local inc = { x = function(val) x = x + val return x end, y = function(val) y = y + val return y end } +local labels = {} +local fields = {} + +local items = { + {["address"] = 0, ["firstVal"] = 11, ["secondVal"] = 12, ["nameCli"] = "rssi_pos"}, + {["address"] = 1, ["firstVal"] = 13, ["secondVal"] = 14, ["nameCli"] = "vbat_pos"}, + {["address"] = 2, ["firstVal"] = 15, ["secondVal"] = 16, ["nameCli"] = "crosshairs_pos"}, + {["address"] = 3, ["firstVal"] = 17, ["secondVal"] = 18, ["nameCli"] = "ah_pos"}, + {["address"] = 4, ["firstVal"] = 19, ["secondVal"] = 20, ["nameCli"] = "ah_sbar_pos"}, + {["address"] = 5, ["firstVal"] = 21, ["secondVal"] = 22, ["nameCli"] = "tim_1_pos"}, + {["address"] = 6, ["firstVal"] = 23, ["secondVal"] = 24, ["nameCli"] = "tim_2_pos"}, + {["address"] = 7, ["firstVal"] = 25, ["secondVal"] = 26, ["nameCli"] = "flymode_pos"}, + {["address"] = 8, ["firstVal"] = 27, ["secondVal"] = 28, ["nameCli"] = "craft_name_pos"}, + {["address"] = 9, ["firstVal"] = 29, ["secondVal"] = 30, ["nameCli"] = "throttle_pos"}, + {["address"] = 10, ["firstVal"] = 31, ["secondVal"] = 32, ["nameCli"] = "vtx_channel_pos"}, + {["address"] = 11, ["firstVal"] = 33, ["secondVal"] = 34, ["nameCli"] = "current_pos"}, + {["address"] = 12, ["firstVal"] = 35, ["secondVal"] = 36, ["nameCli"] = "mah_drawn_pos"}, + {["address"] = 13, ["firstVal"] = 37, ["secondVal"] = 38, ["nameCli"] = "gps_speed_pos"}, + {["address"] = 14, ["firstVal"] = 39, ["secondVal"] = 40, ["nameCli"] = "gps_sats_pos"}, + {["address"] = 15, ["firstVal"] = 41, ["secondVal"] = 42, ["nameCli"] = "altitude_pos"}, + {["address"] = 16, ["firstVal"] = 43, ["secondVal"] = 44, ["nameCli"] = "pid_roll_pos"}, + {["address"] = 17, ["firstVal"] = 45, ["secondVal"] = 46, ["nameCli"] = "pid_pitch_pos"}, + {["address"] = 18, ["firstVal"] = 47, ["secondVal"] = 48, ["nameCli"] = "pid_yaw_pos"}, + {["address"] = 19, ["firstVal"] = 49, ["secondVal"] = 50, ["nameCli"] = "power_pos"}, + {["address"] = 20, ["firstVal"] = 51, ["secondVal"] = 52, ["nameCli"] = "pidrate_profile_pos"}, + {["address"] = 21, ["firstVal"] = 53, ["secondVal"] = 54, ["nameCli"] = "warnings_pos"}, + {["address"] = 22, ["firstVal"] = 55, ["secondVal"] = 56, ["nameCli"] = "avg_cell_voltage_pos"}, + {["address"] = 23, ["firstVal"] = 57, ["secondVal"] = 58, ["nameCli"] = "gps_lon_pos"}, + {["address"] = 24, ["firstVal"] = 59, ["secondVal"] = 60, ["nameCli"] = "gps_lat_pos"}, + {["address"] = 25, ["firstVal"] = 61, ["secondVal"] = 62, ["nameCli"] = "debug_pos"}, + {["address"] = 26, ["firstVal"] = 63, ["secondVal"] = 64, ["nameCli"] = "pit_ang_pos"}, + {["address"] = 27, ["firstVal"] = 65, ["secondVal"] = 66, ["nameCli"] = "rol_ang_pos"}, + {["address"] = 28, ["firstVal"] = 67, ["secondVal"] = 68, ["nameCli"] = "battery_usage_pos"}, + {["address"] = 29, ["firstVal"] = 69, ["secondVal"] = 70, ["nameCli"] = "disarmed_pos"}, + {["address"] = 30, ["firstVal"] = 71, ["secondVal"] = 72, ["nameCli"] = "home_dir_pos"}, + {["address"] = 31, ["firstVal"] = 73, ["secondVal"] = 74, ["nameCli"] = "home_dist_pos"}, + {["address"] = 32, ["firstVal"] = 75, ["secondVal"] = 76, ["nameCli"] = "nheading_pos"}, + {["address"] = 33, ["firstVal"] = 77, ["secondVal"] = 78, ["nameCli"] = "nvario_pos"}, + {["address"] = 34, ["firstVal"] = 79, ["secondVal"] = 80, ["nameCli"] = "compass_bar_pos"}, + {["address"] = 35, ["firstVal"] = 81, ["secondVal"] = 82, ["nameCli"] = "esc_tmp_pos"}, + {["address"] = 36, ["firstVal"] = 83, ["secondVal"] = 84, ["nameCli"] = "esc_rpm_pos"}, + {["address"] = 37, ["firstVal"] = 85, ["secondVal"] = 86, ["nameCli"] = "remaining_time_estimate_pos"}, + {["address"] = 38, ["firstVal"] = 87, ["secondVal"] = 88, ["nameCli"] = "rtc_date_time_pos"}, + {["address"] = 39, ["firstVal"] = 89, ["secondVal"] = 90, ["nameCli"] = "adjustment_range_pos"}, + {["address"] = 40, ["firstVal"] = 91, ["secondVal"] = 92, ["nameCli"] = "core_temp_pos"}, + {["address"] = 41, ["firstVal"] = 93, ["secondVal"] = 94, ["nameCli"] = "anti_gravity_pos"}, + {["address"] = 42, ["firstVal"] = 95, ["secondVal"] = 96, ["nameCli"] = "g_force_pos"}, + {["address"] = 43, ["firstVal"] = 97, ["secondVal"] = 98, ["nameCli"] = "motor_diag_pos"}, + {["address"] = 44, ["firstVal"] = 99, ["secondVal"] = 100, ["nameCli"] = "log_status_pos"}, + {["address"] = 45, ["firstVal"] = 101, ["secondVal"] = 102, ["nameCli"] = "flip_arrow_pos"}, + {["address"] = 46, ["firstVal"] = 103, ["secondVal"] = 104, ["nameCli"] = "link_quality_pos"}, + {["address"] = 47, ["firstVal"] = 105, ["secondVal"] = 106, ["nameCli"] = "flight_dist_pos"}, + {["address"] = 48, ["firstVal"] = 107, ["secondVal"] = 108, ["nameCli"] = "stick_overlay_left_pos"}, + {["address"] = 49, ["firstVal"] = 109, ["secondVal"] = 110, ["nameCli"] = "stick_overlay_right_pos"}, + {["address"] = 50, ["firstVal"] = 111, ["secondVal"] = 112, ["nameCli"] = "display_name_pos"}, + {["address"] = 51, ["firstVal"] = 113, ["secondVal"] = 114, ["nameCli"] = "esc_rpm_freq_pos"}, + {["address"] = 52, ["firstVal"] = 115, ["secondVal"] = 116, ["nameCli"] = "rate_profile_name_pos"}, + {["address"] = 53, ["firstVal"] = 117, ["secondVal"] = 118, ["nameCli"] = "pid_profile_name_pos"}, + {["address"] = 54, ["firstVal"] = 119, ["secondVal"] = 120, ["nameCli"] = "profile_name_pos"}, + {["address"] = 55, ["firstVal"] = 121, ["secondVal"] = 122, ["nameCli"] = "rssi_dbm_pos"}, + {["address"] = 56, ["firstVal"] = 123, ["secondVal"] = 124, ["nameCli"] = "rcchannels_pos"}, + {["address"] = 57, ["firstVal"] = 125, ["secondVal"] = 126, ["nameCli"] = "camera_frame_pos"}, + {["address"] = 58, ["firstVal"] = 127, ["secondVal"] = 128, ["nameCli"] = "efficiency_pos"}, + {["address"] = 59, ["firstVal"] = 129, ["secondVal"] = 130, ["nameCli"] = "total_flights_pos"}, + {["address"] = 60, ["firstVal"] = 131, ["secondVal"] = 132, ["nameCli"] = "up_down_reference_pos"}, + {["address"] = 61, ["firstVal"] = 133, ["secondVal"] = 134, ["nameCli"] = "link_tx_power_pos"}, + {["address"] = 62, ["firstVal"] = 135, ["secondVal"] = 136, ["nameCli"] = "wh_drawn_pos"}, + {["address"] = 63, ["firstVal"] = 137, ["secondVal"] = 138, ["nameCli"] = "aux_pos"}, + {["address"] = 64, ["firstVal"] = 139, ["secondVal"] = 140, ["nameCli"] = "ready_mode_pos"}, + {["address"] = 65, ["firstVal"] = 141, ["secondVal"] = 142, ["nameCli"] = "rsnr_pos"}, + {["address"] = 66, ["firstVal"] = 143, ["secondVal"] = 144, ["nameCli"] = "sys_goggle_voltage_pos"}, + {["address"] = 67, ["firstVal"] = 145, ["secondVal"] = 146, ["nameCli"] = "sys_vtx_voltage_pos"}, + {["address"] = 68, ["firstVal"] = 147, ["secondVal"] = 148, ["nameCli"] = "sys_bitrate_pos"}, + {["address"] = 69, ["firstVal"] = 149, ["secondVal"] = 150, ["nameCli"] = "sys_delay_pos"}, + {["address"] = 70, ["firstVal"] = 151, ["secondVal"] = 152, ["nameCli"] = "sys_distance_pos"}, + {["address"] = 71, ["firstVal"] = 153, ["secondVal"] = 154, ["nameCli"] = "sys_lq_pos"}, + {["address"] = 72, ["firstVal"] = 155, ["secondVal"] = 156, ["nameCli"] = "sys_goggle_dvr_pos"}, + {["address"] = 73, ["firstVal"] = 157, ["secondVal"] = 158, ["nameCli"] = "sys_vtx_dvr_pos"}, + {["address"] = 74, ["firstVal"] = 159, ["secondVal"] = 160, ["nameCli"] = "sys_warnings_pos"}, + {["address"] = 75, ["firstVal"] = 161, ["secondVal"] = 162, ["nameCli"] = "sys_vtx_temp_pos"}, + {["address"] = 76, ["firstVal"] = 163, ["secondVal"] = 164, ["nameCli"] = "sys_fan_speed_pos"}, +} + +address = address or 0 +local firstVal = items[address + 1]["firstVal"] +local secondVal = items[address + 1]["secondVal"] +local nameCli = items[address + 1]["nameCli"] + +x = margin +y = yMinLim - tableSpacing.header + +fields[#fields + 1] = { x = x, y = inc.y(tableSpacing.header), min = 0, max = (#items - 1), vals = { 1 }, upd = function(self) self.updateItems(self) end } +labels[#labels + 1] = { t = nameCli, x = x + tableSpacing.col * 1, y = y } + +labels[#labels + 1] = { t = "POS", x = x, y = inc.y(tableSpacing.header) } +labels[#labels + 1] = { t = "OP1", x = x + tableSpacing.col, y = y } +labels[#labels + 1] = { t = "OP2", x = x + tableSpacing.col * 2, y = y } +labels[#labels + 1] = { t = "OP3", x = x + tableSpacing.col * 3, y = y } + +fields[#fields + 1] = { x = x, y = inc.y(tableSpacing.row), min = 0, max = 2047, vals = { 2, 3 } } +fields[#fields + 1] = { x = x + tableSpacing.col, y = y, min = 0, max = 1, vals = { 1, 2 }, table = { [0] = "OFF", "ON" } } +fields[#fields + 1] = { x = x + tableSpacing.col * 2, y = y, min = 0, max = 1, vals = { 1, 2 }, table = { [0] = "OFF", "ON" } } +fields[#fields + 1] = { x = x + tableSpacing.col * 3, y = y, min = 0, max = 1, vals = { 1, 2 }, table = { [0] = "OFF", "ON" } } + +return { + read = 84, -- MSP_OSD_CONFIG + write = 85, -- MSP_SET_OSD_CONFIG + title = "OSD Elements", + reboot = false, + eepromWrite = true, + minBytes = 3, + labels = labels, + fields = fields, + postLoad = function(self) + self.fields[1].value = address + self.fields[2].value, self.fields[3].value, self.fields[4].value, self.fields[5].value = self.splitVal(self, self.values[firstVal], self.values[secondVal]) + end, + preSave = function(self) + self.values = {} + self.values[1] = self.fields[1].value + local combineValue = self.checkProfile(self, self.fields[2].value, self.fields[3].value, self.fields[4].value, self.fields[5].value) + self.values[2] = bit32.band(combineValue, 0xFF) + self.values[3] = bit32.rshift(combineValue, 8) + return self.values + end, + checkProfile = function(_, value, profileFirst, profileSecond, profileThird) + local profiles = profileFirst + bit32.lshift(profileSecond, 1) + bit32.lshift(profileThird, 2) + local output = bit32.replace(value, profiles, 11, 3) + return output + end, + splitVal = function(_, inputFirstVal, inputSecondVal) + local inputVal = inputFirstVal + bit32.lshift(inputSecondVal, 8) + local profiles = bit32.extract(inputVal, 11, 3) + local fieldPos = bit32.extract(inputVal, 0, 11) + local fieldFirstProfile = bit32.band(bit32.rshift(profiles, 0), 1) + local FieldSecondProfile = bit32.band(bit32.rshift(profiles, 1), 1) + local FieldThirdProfile = bit32.band(bit32.rshift(profiles, 2), 1) + return fieldPos, fieldFirstProfile, FieldSecondProfile, FieldThirdProfile + end, + updateItems = function(self) + if self.fields[1].value ~= items[address + 1]["address"] then + address = self.fields[1].value + firstVal = items[address + 1]["firstVal"] + secondVal = items[address + 1]["secondVal"] + address = items[address + 1]["address"] + nameCli = items[address + 1]["nameCli"] + self.labels[1].t = nameCli + self.fields[2].value, self.fields[3].value, self.fields[4].value, self.fields[5].value = self.splitVal(self, self.values[firstVal], self.values[secondVal]) + end + end +} diff --git a/src/SCRIPTS/BF/PAGES/profiles.lua b/src/SCRIPTS/BF/PAGES/profiles.lua new file mode 100644 index 00000000..c59ad529 --- /dev/null +++ b/src/SCRIPTS/BF/PAGES/profiles.lua @@ -0,0 +1,46 @@ +local template = assert(loadScript(radio.template))() +local margin = template.margin +local indent = template.indent +local lineSpacing = template.lineSpacing +local tableSpacing = template.tableSpacing +local sp = template.listSpacing.field +local yMinLim = radio.yMinLimit +local x = margin +local y = yMinLim - lineSpacing +local inc = { x = function(val) x = x + val return x end, y = function(val) y = y + val return y end } +local labels = {} +local fields = {} + +local RATEPROFILE_MASK = bit32.lshift(1, 7) +local profileNumbers = { [0] = "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" } + +fields[#fields + 1] = { t = "PID Profile", x = x, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 1, vals = { 11 }, table = profileNumbers } +fields[#fields + 1] = { t = "Rate Profile", x = x, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 5, vals = { 15 }, table = profileNumbers } + +return { + read = 150, -- MSP_STATUS_EX + write = 210, -- MSP_SELECT_SETTING + title = "Profiles", + reboot = false, + eepromWrite = true, + minBytes = 11, + labels = labels, + fields = fields, + pidProfile = 0, + postLoad = function(self) + local pidProfileCount = self.values[14] + self.fields[1].max = pidProfileCount - 1 + self.pidProfile = self.fields[1].value + end, + preSave = function(self) + local value = 0 + if self.fields[1].value ~= self.pidProfile then + value = self.fields[1].value + else + value = bit32.bor(self.fields[2].value, RATEPROFILE_MASK) + end + self.values = {} + self.values[1] = value + return self.values + end, +} diff --git a/src/SCRIPTS/BF/PAGES/pwm.lua b/src/SCRIPTS/BF/PAGES/pwm.lua new file mode 100644 index 00000000..0712d7a5 --- /dev/null +++ b/src/SCRIPTS/BF/PAGES/pwm.lua @@ -0,0 +1,115 @@ +local template = assert(loadScript(radio.template))() +local margin = template.margin +local indent = template.indent +local lineSpacing = template.lineSpacing +local tableSpacing = template.tableSpacing +local sp = template.listSpacing.field +local yMinLim = radio.yMinLimit +local x = margin +local y = yMinLim - lineSpacing +local inc = { x = function(val) x = x + val return x end, y = function(val) y = y + val return y end } +local labels = {} +local fields = {} + +local gyroSampleRateKhz + +if apiVersion >= 1.44 then + gyroSampleRateKhz = assert(loadScript("BOARD_INFO/"..mcuId..".lua"))().gyroSampleRateHz / 1000 +end + +local escProtocols = { [0] = "PWM", "OS125", "OS42", "MSHOT" } + +if apiVersion >= 1.20 then + escProtocols[#escProtocols + 1] = "BRSH" +end +if apiVersion >= 1.31 then + escProtocols[#escProtocols + 1] = "DS150" + escProtocols[#escProtocols + 1] = "DS300" + escProtocols[#escProtocols + 1] = "DS600" + if apiVersion < 1.42 then + escProtocols[#escProtocols + 1] = "DS1200" + end + if apiVersion >= 1.36 then + escProtocols[#escProtocols + 1] = "PS1000" + end +end + +if apiVersion >= 1.43 then + escProtocols[#escProtocols + 1] = "DISABLED" +end + +labels[#labels + 1] = { t = "System Config", x = x, y = inc.y(lineSpacing) } +if apiVersion >= 1.31 and apiVersion <= 1.40 then + fields[#fields + 1] = { t = "32kHz Sampling", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 1, vals = { 9 }, table = { [0] = "OFF", "ON" }, upd = function(self) self.updateRateTables(self) end } +end +if apiVersion >= 1.44 then + fields[#fields + 1] = { t = "Gyro Update", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 1, max = 32, vals = { 1 }, table = {}, upd = function(self) self.updatePidRateTable(self) end, mult = -1, ro = true } +elseif apiVersion <= 1.42 then + fields[#fields + 1] = { t = "Gyro Update", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 1, max = 32, vals = { 1 }, table = {}, upd = function(self) self.updatePidRateTable(self) end, mult = -1 } +end +if apiVersion <= 1.42 or apiVersion >= 1.44 then + fields[#fields + 1] = { t = "PID Loop", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 1, max = 16, vals = { 2 }, table = {}, mult = -1 } +end + +labels[#labels + 1] = { t = "ESC/Motor", x = x, y = inc.y(lineSpacing) } +fields[#fields + 1] = { t = "Protocol", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = #escProtocols, vals = { 4 }, table = escProtocols } +if apiVersion >= 1.31 then + fields[#fields + 1] = { t = "Idle Throttle %", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 2000, vals = { 7, 8 }, scale = 100 } +end +fields[#fields + 1] = { t = "Unsynced PWM", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 1, vals = { 3 }, table = { [0] = "OFF", "ON" } } +fields[#fields + 1] = { t = "Frequency", x = x + indent*2, y = inc.y(lineSpacing), sp = x + sp, min = 200, max = 32000, vals = { 5, 6 }, } + +return { + read = 90, -- MSP_ADVANCED_CONFIG + write = 91, -- MSP_SET_ADVANCED_CONFIG + reboot = true, + eepromWrite = true, + title = "PWM", + minBytes = 6, + labels = labels, + fields = fields, + gyroRates = {}, + getGyroDenomFieldIndex = function(self) + for i=1,#self.fields do + if self.fields[i].vals[1] == 1 then + return i + end + end + end, + getPidDenomFieldIndex = function(self) + for i=1,#self.fields do + if self.fields[i].vals[1] == 2 then + return i + end + end + end, + calculateGyroRates = function(self, baseRate) + local idx = self.getGyroDenomFieldIndex(self) + baseRate = gyroSampleRateKhz or baseRate + for i=1, 32 do + self.gyroRates[i] = baseRate/i + self.fields[idx].table[i] = string.format("%.2f",baseRate/i) + end + end, + calculatePidRates = function(self, baseRate) + local idx = self.getPidDenomFieldIndex(self) + for i=1, 16 do + self.fields[idx].table[i] = string.format("%.2f",baseRate/i) + end + end, + updateRateTables = function(self) + if (self.values[9] or 0) == 0 then + self.calculateGyroRates(self, 8) + self.calculatePidRates(self, 8) + elseif self.values[9] == 1 then + self.calculateGyroRates(self, 32) + self.calculatePidRates(self, 32) + end + end, + updatePidRateTable = function(self) + self.updateRateTables(self) + local newRateIdx = self.values[1] + local newRate = self.gyroRates[newRateIdx] + self.calculatePidRates(self, newRate) + end +} diff --git a/src/SCRIPTS/BF/PAGES/rates.lua b/src/SCRIPTS/BF/PAGES/rates.lua new file mode 100644 index 00000000..a1571237 --- /dev/null +++ b/src/SCRIPTS/BF/PAGES/rates.lua @@ -0,0 +1,138 @@ +local template = assert(loadScript(radio.template))() +local margin = template.margin +local indent = template.indent +local lineSpacing = template.lineSpacing +local tableSpacing = template.tableSpacing +local sp = template.listSpacing.field +local yMinLim = radio.yMinLimit +local x = margin +local y = yMinLim - lineSpacing +local inc = { x = function(val) x = x + val return x end, y = function(val) y = y + val return y end } +local labels = {} +local fields = {} + +if apiVersion >= 1.16 then + y = yMinLim - tableSpacing.header + + labels[#labels + 1] = { t = "", x = x, y = inc.y(tableSpacing.header) } + labels[#labels + 1] = { t = "", x = x, y = inc.y(tableSpacing.header) } + labels[#labels + 1] = { t = "ROLL", x = x, y = inc.y(tableSpacing.row) } + labels[#labels + 1] = { t = "PITCH", x = x, y = inc.y(tableSpacing.row) } + labels[#labels + 1] = { t = "YAW", x = x, y = inc.y(tableSpacing.row) } + + x = x + tableSpacing.col + y = yMinLim - tableSpacing.header + + labels[#labels + 1] = { t = "RC", x = x, y = inc.y(tableSpacing.header) } + labels[#labels + 1] = { t = "Rate", x = x, y = inc.y(tableSpacing.header) } + if apiVersion >= 1.37 then + fields[#fields + 1] = { x = x, y = inc.y(tableSpacing.row), min = 0, max = 255, vals = { 1 }, scale = 100 } + fields[#fields + 1] = { x = x, y = inc.y(tableSpacing.row), min = 0, max = 255, vals = { 13 }, scale = 100 } + else + fields[#fields + 1] = { x = x, y = inc.y(tableSpacing.row*1.5), min = 0, max = 255, vals = { 1 }, scale = 100 } + inc.y(tableSpacing.row*0.5) + end + fields[#fields + 1] = { x = x, y = inc.y(tableSpacing.row), min = 0, max = 255, vals = { 12 }, scale = 100 } + + x = x + tableSpacing.col + y = yMinLim - tableSpacing.header + + labels[#labels + 1] = { t = "Super", x = x, y = inc.y(tableSpacing.header) } + labels[#labels + 1] = { t = "Rate", x = x, y = inc.y(tableSpacing.header) } + fields[#fields + 1] = { x = x, y = inc.y(tableSpacing.row), min = 0, max = 100, vals = { 3 }, scale = 100 } + fields[#fields + 1] = { x = x, y = inc.y(tableSpacing.row), min = 0, max = 100, vals = { 4 }, scale = 100 } + fields[#fields + 1] = { x = x, y = inc.y(tableSpacing.row), min = 0, max = 255, vals = { 5 }, scale = 100 } + + x = x + tableSpacing.col + y = yMinLim - tableSpacing.header + + labels[#labels + 1] = { t = "RC", x = x, y = inc.y(tableSpacing.header) } + labels[#labels + 1] = { t = "Expo", x = x, y = inc.y(tableSpacing.header) } + if apiVersion >= 1.37 then + fields[#fields + 1] = { x = x, y = inc.y(tableSpacing.row), min = 0, max = 100, vals = { 2 }, scale = 100 } + fields[#fields + 1] = { x = x, y = inc.y(tableSpacing.row), min = 0, max = 100, vals = { 14 }, scale = 100 } + else + fields[#fields + 1] = { x = x, y = inc.y(tableSpacing.row*1.5), min = 0, max = 100, vals = { 2 }, scale = 100 } + inc.y(tableSpacing.row*0.5) + end + fields[#fields + 1] = { x = x, y = inc.y(tableSpacing.row), min = 0, max = 100, vals = { 11 }, scale = 100 } + + x = margin + inc.y(lineSpacing*0.4) +end + +if apiVersion >= 1.43 then + fields[#fields + 1] = { t = "Rates Type", x = x, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 4, vals = { 23 }, table = { [0] = "BF", "RF", "KISS", "ACTUAL", "QUICK"}, postEdit = function(self) self.updateRatesType(self, true) end } +end + +if apiVersion >= 1.16 then + labels[#labels + 1] = { t = "Throttle", x = x, y = inc.y(lineSpacing) } + fields[#fields + 1] = { t = "Mid", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 100, vals = { 7 }, scale = 100 } + fields[#fields + 1] = { t = "Expo", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 100, vals = { 8 }, scale = 100 } + if apiVersion >= 1.41 then + fields[#fields + 1] = { t = "Limit Type", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 2, vals = { 15 }, table = { [0] = "OFF", "SCALE", "CLIP" } } + fields[#fields + 1] = { t = "Limit %", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 25, max = 100, vals = { 16 } } + end +end + +if apiVersion >= 1.16 and apiVersion <= 1.44 then + labels[#labels + 1] = { t = "TPA", x = x, y = inc.y(lineSpacing) } + fields[#fields + 1] = { t = "Rate", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 100, vals = { 6 } , scale = 100 } + fields[#fields + 1] = { t = "Breakpoint", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 1000, max = 2000, vals = { 9, 10 } } +end + +return { + read = 111, -- MSP_RC_TUNING + write = 204, -- MSP_SET_RC_TUNING + title = "Rates", + reboot = false, + eepromWrite = true, + minBytes = 12, + labels = labels, + fields = fields, + ratesType, + getRatesType = function(self) + for i = 1, #self.fields do + if self.fields[i].vals and self.fields[i].vals[1] == 23 then + return self.fields[i].table[self.fields[i].value] + end + end + end, + updateRatesType = function(self, applyDefaults) + local ratesTable = assert(loadScript("RATETABLES/"..self.getRatesType(self)..".lua"))() + for i = 1, #ratesTable.labels do + self.labels[i].t = ratesTable.labels[i] + end + for i = 1, #ratesTable.fields do + for k, v in pairs(ratesTable.fields[i]) do + self.fields[i][k] = v + end + end + if applyDefaults and self.ratesType ~= self.getRatesType(self) then + for i = 1, #ratesTable.defaults do + local f = self.fields[i] + f.value = ratesTable.defaults[i] + for idx=1, #f.vals do + self.values[f.vals[idx]] = bit32.rshift(math.floor(f.value*(f.scale or 1) + 0.5), (idx-1)*8) + end + end + else + for i = 1, 9 do + local f = self.fields[i] + f.value = 0 + for idx=1, #f.vals do + local raw_val = self.values[f.vals[idx]] or 0 + raw_val = bit32.lshift(raw_val, (idx-1)*8) + f.value = bit32.bor(f.value, raw_val) + end + f.value = f.value/(f.scale or 1) + end + end + self.ratesType = self.getRatesType(self) + end, + postLoad = function(self) + if apiVersion >= 1.43 then + self.updateRatesType(self) + end + end, +} diff --git a/src/SCRIPTS/BF/PAGES/rescue.lua b/src/SCRIPTS/BF/PAGES/rescue.lua new file mode 100644 index 00000000..cdbd21a4 --- /dev/null +++ b/src/SCRIPTS/BF/PAGES/rescue.lua @@ -0,0 +1,53 @@ +local template = assert(loadScript(radio.template))() +local margin = template.margin +local indent = template.indent +local lineSpacing = template.lineSpacing +local tableSpacing = template.tableSpacing +local sp = template.listSpacing.field +local yMinLim = radio.yMinLimit +local x = margin +local y = yMinLim - lineSpacing +local inc = { x = function(val) x = x + val return x end, y = function(val) y = y + val return y end } +local labels = {} +local fields = {} + +if apiVersion >= 1.41 then + fields[#fields + 1] = { t = "Min Sats.", x = x, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 50, vals = { 16 } } + fields[#fields + 1] = { t = "Angle", x = x, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 200, vals = { 1, 2 } } + fields[#fields + 1] = { t = "Initial Altitude", x = x, y = inc.y(lineSpacing), sp = x + sp, min = 20, max = 100, vals = { 3, 4 } } + fields[#fields + 1] = { t = "Descent Distance", x = x, y = inc.y(lineSpacing), sp = x + sp, min = 30, max = 500, vals = { 5, 6 } } + + if apiVersion >= 1.45 then + fields[#fields + 1] = { t = "Ground Speed", x = x, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 3000, vals = { 7, 8 }, scale = 100 } + else + fields[#fields + 1] = { t = "Ground Speed", x = x, y = inc.y(lineSpacing), sp = x + sp, min = 30, max = 3000, vals = { 7, 8 } } + end + + if apiVersion >= 1.43 then + fields[#fields + 1] = { t = "Ascend Rate", x = x, y = inc.y(lineSpacing), sp = x + sp, min = 100, max = 2500, vals = { 17, 18 }, scale = 100 } + fields[#fields + 1] = { t = "Descend Rate", x = x, y = inc.y(lineSpacing), sp = x + sp, min = 100, max = 500, vals = { 19, 20 }, scale = 100 } + fields[#fields + 1] = { t = "Arm w/o fix", x = x, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 1, vals = { 21 }, table = { [0]="OFF","ON"} } + fields[#fields + 1] = { t = "Altitude Mode",x = x, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 2, vals = { 22 }, table = { [0]="Maximum", "Fixed", "Current"} } + end + + fields[#fields + 1] = { t = "Sanity Check", x = x, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 2, vals = { 15 }, table = { [0]="OFF","ON","FS_ONLY"} } + labels[#labels + 1] = { t = "Throttle", x = x, y = inc.y(lineSpacing) } + fields[#fields + 1] = { t = "Min", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 1000, max = 2000, vals = { 9, 10 } } + fields[#fields + 1] = { t = "Hover", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 1000, max = 2000, vals = { 13, 14 } } + fields[#fields + 1] = { t = "Max", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 1000, max = 2000, vals = { 11, 12 } } + + if apiVersion >= 1.44 then + fields[#fields + 1] = { t = "Min Dth", x = x, y = inc.y(lineSpacing), sp = x + sp, min = 50, max = 1000, vals = { 23, 24 } } + end +end + +return { + read = 135, -- MSP_GPS_RESCUE + write = 225, -- MSP_SET_GPS_RESCUE + title = "GPS Rescue", + reboot = false, + eepromWrite = true, + minBytes = 16, + labels = labels, + fields = fields, +} diff --git a/src/SCRIPTS/BF/PAGES/rx.lua b/src/SCRIPTS/BF/PAGES/rx.lua new file mode 100644 index 00000000..a78540c2 --- /dev/null +++ b/src/SCRIPTS/BF/PAGES/rx.lua @@ -0,0 +1,65 @@ +local template = assert(loadScript(radio.template))() +local margin = template.margin +local indent = template.indent +local lineSpacing = template.lineSpacing +local tableSpacing = template.tableSpacing +local sp = template.listSpacing.field +local yMinLim = radio.yMinLimit +local x = margin +local y = yMinLim - lineSpacing +local inc = { x = function(val) x = x + val return x end, y = function(val) y = y + val return y end } +local labels = {} +local fields = {} + +if apiVersion >= 1.16 then + labels[#labels + 1] = { t = "Stick", x = x, y = inc.y(lineSpacing) } + fields[#fields + 1] = { t = "Low", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 1000, max = 2000, vals = { 6, 7 } } + fields[#fields + 1] = { t = "Center", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 1000, max = 2000, vals = { 4, 5 } } + fields[#fields + 1] = { t = "High", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 1000, max = 2000, vals = { 2, 3 } } +end + +if apiVersion >= 1.44 then + labels[#labels + 1] = { t = "RC Smoothing", x = x, y = inc.y(lineSpacing) } + fields[#fields + 1] = { t = "Mode", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 1, vals = { 25 }, table = { [0] = "ON", "OFF" } } + labels[#labels + 1] = { t = "Cutoffs", x = x + indent, y = inc.y(lineSpacing) } + fields[#fields + 1] = { t = "Setpoint", x = x + indent*2, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 255, vals = { 26 }, table = { [0] = "Auto" } } + fields[#fields + 1] = { t = "Feedforward", x = x + indent*2, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 255, vals = { 27 }, table = { [0] = "Auto" } } + labels[#labels + 1] = { t = "Auto Smoothness", x = x + indent, y = inc.y(lineSpacing) } + fields[#fields + 1] = { t = "Setpoint", x = x + indent*2, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 250, vals = { 31 } } +else + if apiVersion >= 1.40 then + labels[#labels + 1] = { t = "RC Smoothing", x = x, y = inc.y(lineSpacing) } + fields[#fields + 1] = { t = "Type", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 1, vals = { 25 }, table = { [0] = "Interpolation", "Filter" } } + fields[#fields + 1] = { t = "Channels", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 4, vals = { 24 }, table = { [0] = "RP", "RPY", "RPYT", "T", "RT" } } + labels[#labels + 1] = { t = "Input Filter", x = x, y = inc.y(lineSpacing) } + fields[#fields + 1] = { t = "Cutoff", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 255, vals = { 26 }, table = { [0] = "Auto" } } + fields[#fields + 1] = { t = "Type", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 1, vals = { 28 }, table = { [0] = "PT1", "BIQUAD"} } + labels[#labels + 1] = { t = "Derivative Filter", x = x, y = inc.y(lineSpacing) } + fields[#fields + 1] = { t = "Cutoff", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 255, vals = { 27 }, table = { [0] = "Auto" } } + fields[#fields + 1] = { t = "Type", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 3, vals = { 29 }, table = { [0] = "Off", "PT1", "BIQUAD", "Auto"} } + end + + if apiVersion >= 1.20 then + fields[#fields + 1] = { t = "Interpolation", x = x, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 3, vals = { 13 }, table={ [0]="Off", "Preset", "Auto", "Manual"} } + fields[#fields + 1] = { t = "Interval", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 1, max = 50, vals = { 14 } } + end + + if apiVersion >= 1.42 then + fields[#fields + 1] = { t = "Auto Smoothness", x = x, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 50, vals = { 31 } } + end +end + +if apiVersion >= 1.31 then + fields[#fields + 1] = { t = "Cam Angle", x = x, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 90, vals = { 23 } } +end + +return { + read = 44, -- MSP_RX_CONFIG + write = 45, -- MSP_SET_RX_CONFIG + title = "RX", + reboot = false, + eepromWrite = true, + minBytes = 12, + labels = labels, + fields = fields, +} diff --git a/src/SCRIPTS/BF/PAGES/simplified_tuning.lua b/src/SCRIPTS/BF/PAGES/simplified_tuning.lua new file mode 100644 index 00000000..addaf165 --- /dev/null +++ b/src/SCRIPTS/BF/PAGES/simplified_tuning.lua @@ -0,0 +1,40 @@ +local template = assert(loadScript(radio.template))() +local margin = template.margin +local indent = template.indent +local lineSpacing = template.lineSpacing +local tableSpacing = template.tableSpacing +local sp = template.listSpacing.field +local yMinLim = radio.yMinLimit +local x = margin +local y = yMinLim - lineSpacing +local inc = { x = function(val) x = x + val return x end, y = function(val) y = y + val return y end } +local labels = {} +local fields = {} + +labels[#labels + 1] = { t = "Simplified PID", x = x, y = inc.y(lineSpacing) } +fields[#fields + 1] = { t = "PID Tuning", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 2, vals = { 1 }, table = { [0] = "OFF", "RP", "RPY" } } +fields[#fields + 1] = { t = "D Gains", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 200, vals = { 5 }, scale = 100, mult = 5 } +fields[#fields + 1] = { t = "P&I Gains", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 200, vals = { 6 }, scale = 100, mult = 5 } +fields[#fields + 1] = { t = "FF Gains", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 200, vals = { 8 }, scale = 100, mult = 5 } +fields[#fields + 1] = { t = "D Max", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 200, vals = { 7 }, scale = 100, mult = 5 } +fields[#fields + 1] = { t = "I Gains", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 200, vals = { 4 }, scale = 100, mult = 5 } +fields[#fields + 1] = { t = "Pitch:Roll D", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 200, vals = { 3 }, scale = 100, mult = 5 } +fields[#fields + 1] = { t = "Pitch:Roll P,I&FF", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 200, vals = { 9 }, scale = 100, mult = 5 } +fields[#fields + 1] = { t = "Master Multiplier", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 200, vals = { 2 }, scale = 100, mult = 5 } + +labels[#labels + 1] = { t = "Simplified Filter", x = x, y = inc.y(lineSpacing) } +fields[#fields + 1] = { t = "Gyro Tuning", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 1, vals = { 36 }, table = { [0] = "OFF", "ON" } } +fields[#fields + 1] = { t = "Gyro Multiplier", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 10, max = 200, vals = { 37 }, scale = 100, mult = 5 } +fields[#fields + 1] = { t = "D Tuning", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 1, vals = { 18 }, table = { [0] = "OFF", "ON" } } +fields[#fields + 1] = { t = "D Multiplier", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 10, max = 200, vals = { 19 }, scale = 100, mult = 5 } + +return { + read = 140, -- MSP_SIMPLIFIED_TUNING + write = 141, -- MSP_SET_SIMPLIFIED_TUNING + title = "Simplified Tuning", + reboot = false, + eepromWrite = true, + minBytes = 53, + labels = labels, + fields = fields, +} diff --git a/src/SCRIPTS/BF/HORUS/vtx.lua b/src/SCRIPTS/BF/PAGES/vtx.lua similarity index 72% rename from src/SCRIPTS/BF/HORUS/vtx.lua rename to src/SCRIPTS/BF/PAGES/vtx.lua index 01cd6060..7c61da3d 100644 --- a/src/SCRIPTS/BF/HORUS/vtx.lua +++ b/src/SCRIPTS/BF/PAGES/vtx.lua @@ -1,3 +1,44 @@ +local template = assert(loadScript(radio.template))() +local margin = template.margin +local lineSpacing = template.lineSpacing +local sp = template.listSpacing.field +local yMinLim = radio.yMinLimit +local x = margin +local y = yMinLim - lineSpacing +local inc = { x = function(val) x = x + val return x end, y = function(val) y = y + val return y end } +local labels = {} +local fields = {} + +local vtx_tables +if apiVersion >= 1.42 then + vtx_tables = assert(loadScript("VTX_TABLES/"..mcuId..".lua"), "No VTX table!")() +else + vtx_tables = assert(loadScript("VTX_TABLES/vtx_defaults.lua"))() +end +local deviceTable = { [1]="6705", [3]="SA", [4]="Tramp", [255]="None" } +local pitModeTable = { [0]="OFF", "ON" } + +if apiVersion >= 1.36 then + fields[#fields + 1] = { t = "Band", x = x, y = inc.y(lineSpacing), sp = x + sp, min=0, max=#(vtx_tables.bandTable), vals = { 2 }, table = vtx_tables.bandTable, upd = function(self) self.handleBandChanUpdate(self) end } + fields[#fields + 1] = { t = "Channel", x = x, y = inc.y(lineSpacing), sp = x + sp, min=1, max=vtx_tables.frequenciesPerBand, vals = { 3 }, upd = function(self) self.handleBandChanUpdate(self) end } + fields[#fields + 1] = { t = "Power", x = x, y = inc.y(lineSpacing), sp = x + sp, min=1, vals = { 4 }, upd = function(self) self.updatePowerTable(self) end } + fields[#fields + 1] = { t = "Pit Mode", x = x, y = inc.y(lineSpacing), sp = x + sp, min=0, max=#(pitModeTable), vals = { 5 }, table = pitModeTable } + fields[#fields + 1] = { t = "Protocol", x = x, y = inc.y(lineSpacing), sp = x + sp, vals = { 1 }, write = false, ro = true, table = deviceTable } +end + +if apiVersion >= 1.37 then + fields[#fields + 1] = { t = "Frequency", x = x, y = inc.y(lineSpacing), sp = x + sp, min = 5000, max = 5999, vals = { 6 }, upd = function(self) self.handleFreqValUpdate(self) end } +elseif apiVersion >= 1.36 then + fields[#fields + 1] = { t = "Frequency", x = x, y = inc.y(lineSpacing), sp = x + sp, min = 5000, max = 5999, ro = true } +end + +-- Vals Fields +-- 1 Device Type Band +-- 2 Band Channel +-- 3 Channel Power +-- 4 Power Pit +-- 5 Pit Device Type +-- 6 Freq Frequency return { read = 88, -- MSP_VTX_CONFIG @@ -11,43 +52,9 @@ return { prevFreqVal = 0, lastFreqUpdTS = 0, freqModCounter = 0, - text= { - { t = "Band", x = 36, y = 110 }, - { t = "Channel", x = 36, y = 155 }, - { t = "Power", x = 232, y = 110 }, - { t = "Pit", x = 232, y = 155 }, - { t = "Proto", x = 36, y = 68 }, - { t = "Freq", x = 232, y = 68 }, - }, - fields = { - -- Band - { x = 130, y = 110, min=0, max=5, vals = { 2 }, to = MIDSIZE, - table = { [0]="U", "A", "B", "E", "F", "R" }, - upd = function(self) self.handleBandChanUpdate(self) end }, - -- Channel - { x = 130, y = 155, min=1, max=8, vals = { 3 }, to = MIDSIZE, - upd = function(self) self.handleBandChanUpdate(self) end }, - -- Power - { x = 350, y = 110, min=1, vals = { 4 }, to = MIDSIZE, - upd = function(self) self.updatePowerTable(self) end }, - -- Pit mode - { x = 350, y = 155, min=0, max=1, vals = { 5 }, to = MIDSIZE, - table = { [0]="OFF", "ON" } }, - -- Proto - { x = 130, y = 68, vals = { 1 }, to = MIDSIZE, - write = false, ro = true, - table = { [1]="RTC6705",[3]="SmartAudio",[4]="Tramp",[255]="None"} }, - -- Freq - { x = 350, y = 68, min = 5000, max = 5999, vals = { 6 }, to = MIDSIZE, - upd = function(self) self.handleFreqValUpdate(self) end }, - }, - freqLookup = { - { 5865, 5845, 5825, 5805, 5785, 5765, 5745, 5725 }, -- Boscam A - { 5733, 5752, 5771, 5790, 5809, 5828, 5847, 5866 }, -- Boscam B - { 5705, 5685, 5665, 5645, 5885, 5905, 5925, 5945 }, -- Boscam E - { 5740, 5760, 5780, 5800, 5820, 5840, 5860, 5880 }, -- FatShark - { 5658, 5695, 5732, 5769, 5806, 5843, 5880, 5917 }, -- RaceBand - }, + labels = labels, + fields = fields, + freqLookup = vtx_tables.frequencyTable, postLoad = function (self) if (self.values[2] or 0) < 0 or (self.values[3] or 0) == 0 or (self.values[4] or 0) == 0 then self.values = {} @@ -191,17 +198,28 @@ return { end, updatePowerTable = function(self) if self.values and not self.fields[3].table then - if self.values[1] == 1 then -- RTC6705 - self.fields[3].table = { 25, 200 } - self.fields[3].max = 2 - self.fields[4].t = nil -- don't display Pit field - self.fields[4].table = { [0]="", "" } - elseif self.values[1] == 3 then -- SmartAudio - self.fields[3].table = { 25, 200, 500, 800 } - self.fields[3].max = 4 - elseif self.values[1] == 4 then -- Tramp - self.fields[3].table = { 25, 100, 200, 400, 600 } - self.fields[3].max = 5 + if vtx_tables.powerTable then + self.fields[3].table = vtx_tables.powerTable + self.fields[3].max = #(vtx_tables.powerTable) + else + if self.values[1] == 1 then -- RTC6705 + self.fields[3].table = { 25, 200 } + self.fields[3].max = 2 + self.fields[4].t = nil -- don't display Pit field + self.fields[4].table = { [0]="", "" } + elseif self.values[1] == 3 then -- SmartAudio + self.fields[3].table = { 25, 200, 500, 800 } + self.fields[3].max = 4 + elseif self.values[1] == 4 then -- Tramp + self.fields[3].table = { 25, 100, 200, 400, 600 } + self.fields[3].max = 5 + elseif self.values[1] == 255 then -- None/Unknown + self.fields[3].t = nil -- don't display Power field + self.fields[3].max = 1 + self.fields[3].table = { [1]="" } + self.fields[4].t = nil -- don't display Pit field + self.fields[4].table = { [0]="", "" } + end end end end, @@ -260,4 +278,4 @@ return { end end end -} \ No newline at end of file +} diff --git a/src/SCRIPTS/BF/RATETABLES/ACTUAL.lua b/src/SCRIPTS/BF/RATETABLES/ACTUAL.lua new file mode 100644 index 00000000..42bf533d --- /dev/null +++ b/src/SCRIPTS/BF/RATETABLES/ACTUAL.lua @@ -0,0 +1,15 @@ +return { + labels = { "", "", "ROLL", "PITCH", "YAW", "Cntr", "Sens", "Max", "Rate", "", "Expo" }, + fields = { + { min = 1, max = 200, scale = 0.1 }, + { min = 1, max = 200, scale = 0.1 }, + { min = 1, max = 200, scale = 0.1 }, + { min = 0, max = 200, scale = 0.1 }, + { min = 0, max = 200, scale = 0.1 }, + { min = 0, max = 200, scale = 0.1 }, + { min = 0, max = 100, scale = 100 }, + { min = 0, max = 100, scale = 100 }, + { min = 0, max = 100, scale = 100 } + }, + defaults = { 200, 200, 200, 670, 670, 670, 0.54, 0.54, 0.54 } +} diff --git a/src/SCRIPTS/BF/RATETABLES/BF.lua b/src/SCRIPTS/BF/RATETABLES/BF.lua new file mode 100644 index 00000000..343d6df3 --- /dev/null +++ b/src/SCRIPTS/BF/RATETABLES/BF.lua @@ -0,0 +1,15 @@ +return { + labels = { "", "", "ROLL", "PITCH", "YAW", "RC", "Rate", "Super", "Rate", "RC", "Expo" }, + fields = { + { min = 0, max = 255, scale = 100 }, + { min = 0, max = 255, scale = 100 }, + { min = 0, max = 255, scale = 100 }, + { min = 0, max = 100, scale = 100 }, + { min = 0, max = 100, scale = 100 }, + { min = 0, max = 255, scale = 100 }, + { min = 0, max = 100, scale = 100 }, + { min = 0, max = 100, scale = 100 }, + { min = 0, max = 100, scale = 100 } + }, + defaults = { 1.0, 1.0, 1.0, 0.7, 0.7, 0.7, 0.0, 0.0, 0.0 } +} diff --git a/src/SCRIPTS/BF/RATETABLES/KISS.lua b/src/SCRIPTS/BF/RATETABLES/KISS.lua new file mode 100644 index 00000000..f365f270 --- /dev/null +++ b/src/SCRIPTS/BF/RATETABLES/KISS.lua @@ -0,0 +1,15 @@ +return { + labels = { "", "", "ROLL", "PITCH", "YAW", "RC", "Rate", "", "Rate", "RC", "Curve" }, + fields = { + { min = 1, max = 255, scale = 100 }, + { min = 1, max = 255, scale = 100 }, + { min = 1, max = 255, scale = 100 }, + { min = 0, max = 99, scale = 100 }, + { min = 0, max = 99, scale = 100 }, + { min = 0, max = 99, scale = 100 }, + { min = 0, max = 100, scale = 100 }, + { min = 0, max = 100, scale = 100 }, + { min = 0, max = 100, scale = 100 } + }, + defaults = { 1.0, 1.0, 1.0, 0.7, 0.7, 0.7, 0.0, 0.0, 0.0 } +} diff --git a/src/SCRIPTS/BF/RATETABLES/QUICK.lua b/src/SCRIPTS/BF/RATETABLES/QUICK.lua new file mode 100644 index 00000000..367eeef0 --- /dev/null +++ b/src/SCRIPTS/BF/RATETABLES/QUICK.lua @@ -0,0 +1,15 @@ +return { + labels = { "", "", "ROLL", "PITCH", "YAW", "RC", "Rate", "Max", "Rate", "", "Expo" }, + fields = { + { min = 1, max = 255, scale = 100 }, + { min = 1, max = 255, scale = 100 }, + { min = 1, max = 255, scale = 100 }, + { min = 0, max = 200, scale = 0.1 }, + { min = 0, max = 200, scale = 0.1 }, + { min = 0, max = 200, scale = 0.1 }, + { min = 0, max = 100, scale = 100 }, + { min = 0, max = 100, scale = 100 }, + { min = 0, max = 100, scale = 100 } + }, + defaults = { 1.0, 1.0, 1.0, 670, 670, 670, 0.0, 0.0, 0.0 } +} diff --git a/src/SCRIPTS/BF/RATETABLES/RF.lua b/src/SCRIPTS/BF/RATETABLES/RF.lua new file mode 100644 index 00000000..12f74f36 --- /dev/null +++ b/src/SCRIPTS/BF/RATETABLES/RF.lua @@ -0,0 +1,15 @@ +return { + labels = { "", "", "ROLL", "PITCH", "YAW", "", "Rate", "", "Acro+", "", "Expo" }, + fields = { + { min = 1, max = 200, scale = 0.1 }, + { min = 1, max = 200, scale = 0.1 }, + { min = 1, max = 200, scale = 0.1 }, + { min = 0, max = 100, scale = 1 }, + { min = 0, max = 100, scale = 1 }, + { min = 0, max = 100, scale = 1 }, + { min = 0, max = 100, scale = 1 }, + { min = 0, max = 100, scale = 1 }, + { min = 0, max = 100, scale = 1 } + }, + defaults = { 370, 370, 370, 80, 80, 80, 50, 50, 50 } +} diff --git a/src/SCRIPTS/BF/TEMPLATES/128x64.lua b/src/SCRIPTS/BF/TEMPLATES/128x64.lua new file mode 100644 index 00000000..76e110f0 --- /dev/null +++ b/src/SCRIPTS/BF/TEMPLATES/128x64.lua @@ -0,0 +1,7 @@ +return { + margin = 2, + indent = 6, + lineSpacing = 8, + listSpacing = { line = 8, field = 88 }, + tableSpacing = { row = 10, col = 30, header = 8 }, +} diff --git a/src/SCRIPTS/BF/TEMPLATES/128x96.lua b/src/SCRIPTS/BF/TEMPLATES/128x96.lua new file mode 100644 index 00000000..76e110f0 --- /dev/null +++ b/src/SCRIPTS/BF/TEMPLATES/128x96.lua @@ -0,0 +1,7 @@ +return { + margin = 2, + indent = 6, + lineSpacing = 8, + listSpacing = { line = 8, field = 88 }, + tableSpacing = { row = 10, col = 30, header = 8 }, +} diff --git a/src/SCRIPTS/BF/TEMPLATES/212x64.lua b/src/SCRIPTS/BF/TEMPLATES/212x64.lua new file mode 100644 index 00000000..76e110f0 --- /dev/null +++ b/src/SCRIPTS/BF/TEMPLATES/212x64.lua @@ -0,0 +1,7 @@ +return { + margin = 2, + indent = 6, + lineSpacing = 8, + listSpacing = { line = 8, field = 88 }, + tableSpacing = { row = 10, col = 30, header = 8 }, +} diff --git a/src/SCRIPTS/BF/TEMPLATES/320x480.lua b/src/SCRIPTS/BF/TEMPLATES/320x480.lua new file mode 100644 index 00000000..74213779 --- /dev/null +++ b/src/SCRIPTS/BF/TEMPLATES/320x480.lua @@ -0,0 +1,7 @@ +return { + margin = 5, + indent = 15, + lineSpacing = 20, + listSpacing = { line = 20, field = 170 }, + tableSpacing = { row = 25, col = 60, header = 20 }, +} diff --git a/src/SCRIPTS/BF/TEMPLATES/480x272.lua b/src/SCRIPTS/BF/TEMPLATES/480x272.lua new file mode 100644 index 00000000..74213779 --- /dev/null +++ b/src/SCRIPTS/BF/TEMPLATES/480x272.lua @@ -0,0 +1,7 @@ +return { + margin = 5, + indent = 15, + lineSpacing = 20, + listSpacing = { line = 20, field = 170 }, + tableSpacing = { row = 25, col = 60, header = 20 }, +} diff --git a/src/SCRIPTS/BF/TEMPLATES/480x320.lua b/src/SCRIPTS/BF/TEMPLATES/480x320.lua new file mode 100644 index 00000000..cf01908c --- /dev/null +++ b/src/SCRIPTS/BF/TEMPLATES/480x320.lua @@ -0,0 +1,7 @@ +return { + margin = 5, + indent = 15, + lineSpacing = 22, + listSpacing = { line = 20, field = 170 }, + tableSpacing = { row = 25, col = 60, header = 20 }, +} diff --git a/src/SCRIPTS/BF/VTX_TABLES/vtx_defaults.lua b/src/SCRIPTS/BF/VTX_TABLES/vtx_defaults.lua new file mode 100644 index 00000000..3062297f --- /dev/null +++ b/src/SCRIPTS/BF/VTX_TABLES/vtx_defaults.lua @@ -0,0 +1,11 @@ +return { + frequencyTable = { + { 5865, 5845, 5825, 5805, 5785, 5765, 5745, 5725 }, -- Boscam A + { 5733, 5752, 5771, 5790, 5809, 5828, 5847, 5866 }, -- Boscam B + { 5705, 5685, 5665, 5645, 5885, 5905, 5925, 5945 }, -- Boscam E + { 5740, 5760, 5780, 5800, 5820, 5840, 5860, 5880 }, -- FatShark + { 5658, 5695, 5732, 5769, 5806, 5843, 5880, 5917 }, -- RaceBand + }, + frequenciesPerBand = 8, + bandTable = { [0]="U", "A", "B", "E", "F", "R" }, +} diff --git a/src/SCRIPTS/BF/X7/filters1.lua b/src/SCRIPTS/BF/X7/filters1.lua deleted file mode 100644 index 8866008f..00000000 --- a/src/SCRIPTS/BF/X7/filters1.lua +++ /dev/null @@ -1,25 +0,0 @@ - -return { - read = 92, -- MSP_FILTER_CONFIG - write = 93, -- MSP_SET_FILTER_CONFIG - eepromWrite = true, - reboot = false, - title = "Filt (1/2)", - minBytes = 18, - text= { - { t = "LPF", x = 43, y = 14, to = SMLSIZE }, - { t = "Gyro", x = 20, y = 24, to = SMLSIZE }, - { t = "DTerm", x = 15, y = 34, to = SMLSIZE }, - { t = "Yaw", x = 25, y = 44, to = SMLSIZE }, - { t = "Gyro 1", x = 75, y = 14, to = SMLSIZE }, - { t = "Hz", x = 73, y = 24, to = SMLSIZE }, - { t = "CO", x = 73, y = 34, to = SMLSIZE }, - }, - fields = { - { x = 43, y = 24, min = 0, max = 255, to = SMLSIZE, vals = { 1 } }, - { x = 43, y = 34, min = 0, max = 16000, to = SMLSIZE, vals = { 2, 3 } }, - { x = 43, y = 44, min = 0, max = 500, to = SMLSIZE, vals = { 4, 5 } }, - { x = 85, y = 24, min = 0, max = 16000, to = SMLSIZE, vals = { 6, 7 } }, - { x = 85, y = 34, min = 0, max = 16000, to = SMLSIZE, vals = { 8, 9 } }, - } -} diff --git a/src/SCRIPTS/BF/X7/filters2.lua b/src/SCRIPTS/BF/X7/filters2.lua deleted file mode 100644 index 2aae4c00..00000000 --- a/src/SCRIPTS/BF/X7/filters2.lua +++ /dev/null @@ -1,25 +0,0 @@ - -return { - read = 92, -- MSP_FILTER_CONFIG - write = 93, -- MSP_SET_FILTER_CONFIG - eepromWrite = true, - reboot = false, - title = "Filt (2/2)", - minBytes = 18, - text= { - { t = "Gyro 2", x = 30, y = 14, to = SMLSIZE }, - { t = "Hz", x = 28, y = 24, to = SMLSIZE }, - { t = "CO", x = 28, y = 34, to = SMLSIZE }, - { t = "DTerm", x = 73, y = 14, to = SMLSIZE }, - { t = "Hz", x = 73, y = 24, to = SMLSIZE }, - { t = "CO", x = 73, y = 34, to = SMLSIZE }, - { t = "DTerm LP Type", x = 18, y = 44, to = SMLSIZE }, - }, - fields = { - { x = 41, y = 24, min = 0, max = 16000, to = SMLSIZE, vals = { 14, 15 } }, - { x = 41, y = 34, min = 0, max = 16000, to = SMLSIZE, vals = { 16, 17 } }, - { x = 86, y = 24, min = 0, max = 16000, to = SMLSIZE, vals = { 10, 11 } }, - { x = 86, y = 34, min = 0, max = 16000, to = SMLSIZE, vals = { 12, 13 } }, - { x = 86, y = 44, min = 0, max = 2, to = SMLSIZE, vals = { 18 }, table = { [0] = "PT1", [1] = "BIQUAD", [2] = "FIR" } }, - } -} diff --git a/src/SCRIPTS/BF/X7/pids.lua b/src/SCRIPTS/BF/X7/pids.lua deleted file mode 100644 index 535a280c..00000000 --- a/src/SCRIPTS/BF/X7/pids.lua +++ /dev/null @@ -1,30 +0,0 @@ - -return { - read = 112, -- MSP_PID - write = 202, -- MSP_SET_PID - title = "PIDs", - reboot = false, - eepromWrite = true, - minBytes = 8, - text = { - { t = "P", x = 45, y = 14, to=SMLSIZE }, - { t = "I", x = 73, y = 14, to=SMLSIZE }, - { t = "D", x = 101, y = 14, to=SMLSIZE }, - { t = "ROLL", x = 10, y = 26, to=SMLSIZE }, - { t = "PITCH", x = 10, y = 36, to=SMLSIZE }, - { t = "YAW", x = 10, y = 46, to=SMLSIZE }, - }, - fields = { - -- P - { x = 41, y = 26, min = 0, max = 200, vals = { 1 }, to=SMLSIZE }, - { x = 41, y = 36, min = 0, max = 200, vals = { 4 }, to=SMLSIZE }, - { x = 41, y = 46, min = 0, max = 200, vals = { 7 }, to=SMLSIZE }, - -- I - { x = 69, y = 26, min = 0, max = 200, vals = { 2 }, to=SMLSIZE }, - { x = 69, y = 36, min = 0, max = 200, vals = { 5 }, to=SMLSIZE }, - { x = 69, y = 46, min = 0, max = 200, vals = { 8 }, to=SMLSIZE }, - -- D - { x = 97, y = 26, min = 0, max = 200, vals = { 3 }, to=SMLSIZE }, - { x = 97, y = 36, min = 0, max = 200, vals = { 6 }, to=SMLSIZE }, - }, -} \ No newline at end of file diff --git a/src/SCRIPTS/BF/X7/pwm.lua b/src/SCRIPTS/BF/X7/pwm.lua deleted file mode 100644 index 4a5af779..00000000 --- a/src/SCRIPTS/BF/X7/pwm.lua +++ /dev/null @@ -1,55 +0,0 @@ -return { - read = 90, -- MSP_ADVANCED_CONFIG - write = 91, -- MSP_SET_ADVANCED_CONFIG - reboot = true, - eepromWrite = true, - title = "PWM", - minBytes = 9, - text= { - { t = "32K", x = 10, y = 14, to = SMLSIZE }, - { t = "Gyro", x = 10, y = 24, to = SMLSIZE }, - { t = "PID", x = 10, y = 34, to = SMLSIZE }, - { t = "Prot", x = 55, y = 14, to = SMLSIZE }, - { t = "Unsync", x = 55, y = 24, to = SMLSIZE }, - { t = "PWM", x = 55, y = 34, to = SMLSIZE }, - { t = "Offset", x =45, y = 44, to = SMLSIZE } - }, - fields = { - { x = 32, y = 14, vals = { 9 }, min = 0, max = 1, to = SMLSIZE, table = { [0] = "OFF", "ON" }, upd = function(self) self.updateRateTables(self) end }, - { x = 32, y = 24, vals = { 1 }, min = 1, max = 32, to = SMLSIZE, upd = function(self) self.updatePidRateTable(self) end }, - { x = 32, y = 34, vals = { 2 }, min = 1, max = 16, to = SMLSIZE, }, - { x = 85, y = 14, vals = { 4 }, min = 0, max = 9, to = SMLSIZE, table = { [0] = "OFF", "OS125", "OS42", "MSHOT","BRSH", "DS150", "DS300", "DS600","DS1200", "PS1000" } }, - { x = 85, y = 24, vals = { 3 }, min = 0, max = 1, to = SMLSIZE, table = { [0] = "OFF", "ON" } }, - { x = 85, y = 34, vals = { 5, 6 }, min = 200, max = 32000, to = SMLSIZE }, - { x = 85, y = 44, vals = { 7, 8 }, min = 0, max = 2000, to = SMLSIZE, scale = 100 }, - }, - calculateGyroRates = function(self, baseRate) - self.gyroRates = {} - self.fields[2].table = {} - for i=1, 32 do - self.gyroRates[i] = baseRate/i - local fmt = nil - self.fields[2].table[i] = string.format("%.2f",baseRate/i) - end - end, - calculatePidRates = function(self, baseRate) - self.fields[3].table = {} - for i=1, 16 do - self.fields[3].table[i] = string.format("%.2f",baseRate/i) - end - end, - updateRateTables = function(self) - if self.values[9] == 0 then - self.calculateGyroRates(self, 8) - self.calculatePidRates(self, 8) - elseif self.values[9] == 1 then - self.calculateGyroRates(self, 32) - self.calculatePidRates(self, 32) - end - end, - updatePidRateTable = function(self) - local newRateIdx = self.values[1] - local newRate = self.gyroRates[newRateIdx] - self.calculatePidRates(self, newRate) - end -} diff --git a/src/SCRIPTS/BF/X7/rates1.lua b/src/SCRIPTS/BF/X7/rates1.lua deleted file mode 100644 index cb6c0dd9..00000000 --- a/src/SCRIPTS/BF/X7/rates1.lua +++ /dev/null @@ -1,28 +0,0 @@ -return { - read = 111, -- MSP_RC_TUNING - write = 204, -- MSP_SET_RC_TUNING - title = "Rates (1/4)", - reboot = false, - eepromWrite = true, - minBytes = 12, - text = { - { t = "RC", x = 43, y = 11, to = SMLSIZE }, - { t = "Rate", x = 38, y = 18, to = SMLSIZE }, - { t = "Super", x = 63, y = 11, to = SMLSIZE }, - { t = "Rate", x = 66, y = 18, to = SMLSIZE }, - { t = "RC", x = 99, y = 11, to = SMLSIZE }, - { t = "Expo", x = 94, y = 18, to = SMLSIZE }, - { t = "ROLL", x = 10, y = 26, to = SMLSIZE }, - { t = "PITCH", x = 10, y = 36, to = SMLSIZE }, - { t = "YAW", x = 10, y = 46, to = SMLSIZE }, - }, - fields = { - { x = 39, y = 31, to=SMLSIZE, vals = { 1 }, min = 0, max = 255, scale = 100 }, - { x = 39, y = 46, to=SMLSIZE, vals = { 12 }, min = 0, max = 255, scale = 100 }, - { x = 66, y = 26, to=SMLSIZE, vals = { 3 }, min = 0, max = 100, scale = 100 }, - { x = 66, y = 36, to=SMLSIZE, vals = { 4 }, min = 0, max = 100, scale = 100 }, - { x = 66, y = 46, to=SMLSIZE, vals = { 5 }, min = 0, max = 255, scale = 100 }, - { x = 94, y = 31, to=SMLSIZE, vals = { 2 }, min = 0, max = 100, scale = 100 }, - { x = 94, y = 46, to=SMLSIZE, vals = { 11 }, min = 0, max = 100, scale = 100 } - }, -} \ No newline at end of file diff --git a/src/SCRIPTS/BF/X7/rates2.lua b/src/SCRIPTS/BF/X7/rates2.lua deleted file mode 100644 index 91b3a93d..00000000 --- a/src/SCRIPTS/BF/X7/rates2.lua +++ /dev/null @@ -1,22 +0,0 @@ -return { - read = 111, -- MSP_RC_TUNING - write = 204, -- MSP_SET_RC_TUNING - title = "Rates (2/4)", - reboot = false, - eepromWrite = true, - minBytes = 12, - text = { - { t = "Throttle", x = 26, y = 15, to = SMLSIZE }, - { t = "Mid", x = 26, y = 28, to = SMLSIZE }, - { t = "Exp", x = 26, y = 43, to = SMLSIZE }, - { t = "TPA", x = 86, y = 15, to = SMLSIZE }, - { t = "Thr", x = 68, y = 28, to = SMLSIZE }, - { t = "Brk", x = 68, y = 43, to = SMLSIZE }, - }, - fields = { - { x = 44, y = 28, to=SMLSIZE, vals = { 7 }, min = 0, max = 100, scale = 100 }, - { x = 44, y = 43, to=SMLSIZE, vals = { 8 }, min = 0, max = 100, scale = 100 }, - { x = 86, y = 28, to=SMLSIZE, vals = { 6 } , min = 0, max = 100, scale = 100 }, - { x = 86, y = 43, to=SMLSIZE, vals = { 9, 10 }, min = 1000, max = 2000 }, - }, -} \ No newline at end of file diff --git a/src/SCRIPTS/BF/X7/rates3.lua b/src/SCRIPTS/BF/X7/rates3.lua deleted file mode 100644 index ef5082cd..00000000 --- a/src/SCRIPTS/BF/X7/rates3.lua +++ /dev/null @@ -1,19 +0,0 @@ - -return { - read = 94, -- MSP_PID_ADVANCED - write = 95, -- MSP_SET_PID_ADVANCED - title = "Rates (3/4)", - reboot = false, - eepromWrite = true, - minBytes = 23, - text = { - { t = "Anti-Grav Gain", x = 15, y = 17, to = SMLSIZE }, - { t = "Anti-Grav Thr", x = 15, y = 30, to = SMLSIZE }, - { t = "VBAT Compens", x = 15, y = 43, to = SMLSIZE } - }, - fields = { - { x = 90, y = 17, to=SMLSIZE, min = 1000, max = 30000, vals = { 22, 23 }, scale = 1000, mult = 100 }, - { x = 90, y = 30, to=SMLSIZE, min = 20, max = 1000, vals = { 20, 21 } }, - { x = 90, y = 43, to=SMLSIZE, min = 0, max = 1, vals = { 8 }, table = { [0]="OFF", "ON" } }, - } -} diff --git a/src/SCRIPTS/BF/X7/rates4.lua b/src/SCRIPTS/BF/X7/rates4.lua deleted file mode 100644 index 67850705..00000000 --- a/src/SCRIPTS/BF/X7/rates4.lua +++ /dev/null @@ -1,18 +0,0 @@ - -return { - read = 94, -- MSP_PID_ADVANCED - write = 95, -- MSP_SET_PID_ADVANCED - title = "Rates (4/4)", - reboot = false, - eepromWrite = true, - minBytes = 23, - text = { - { t = "Dterm Setpoint", x = 28, y = 15, to = SMLSIZE }, - { t = "Weight", x = 33, y = 28, to = SMLSIZE }, - { t = "Transn", x = 33, y = 41, to = SMLSIZE }, - }, - fields = { - { x = 78, y = 28, to=SMLSIZE, min = 0, max = 254, vals = { 10 }, scale = 100 }, - { x = 78, y = 41, to=SMLSIZE, min = 0, max = 100, vals = { 9 }, scale = 100 }, - } -} \ No newline at end of file diff --git a/src/SCRIPTS/BF/X7/vtx.lua b/src/SCRIPTS/BF/X7/vtx.lua deleted file mode 100644 index 9f627eb8..00000000 --- a/src/SCRIPTS/BF/X7/vtx.lua +++ /dev/null @@ -1,242 +0,0 @@ - -return { - read = 88, -- MSP_VTX_CONFIG - write = 89, -- MSP_VTX_SET_CONFIG - eepromWrite = true, - reboot = false, - title = "VTX", - minBytes = 5, - prevBandVal = 0, - prevChanVal = 0, - prevFreqVal = 0, - lastFreqUpdTS = 0, - freqModCounter = 0, - text = {}, - fields = { - { t = "Band", x = 10, y = 14, sp = 30, min=0, max=5, vals = { 2 }, to = SMLSIZE, table = { [0]="U", "A", "B", "E", "F", "R" }, upd = function(self) self.handleBandChanUpdate(self) end }, - { t = "Chan", x = 10, y = 24, sp = 30, min=1, max=8, vals = { 3 }, to = SMLSIZE, upd = function(self) self.handleBandChanUpdate(self) end }, - { t = "Power", x = 10, y = 34, sp = 30, min=1, vals = { 4 }, to = SMLSIZE, upd = function(self) self.updatePowerTable(self) end }, - { t = "Pit", x = 10, y = 44, sp = 30, min=0, max=1, vals = { 5 }, to = SMLSIZE, table = { [0]="OFF", "ON" } }, - { t = "Dev", x = 70, y = 14, sp = 25, write = false, ro = true, vals = { 1 }, to = SMLSIZE , table = { [1]="6705",[3]="SA",[4]="Tramp",[255]="None"} }, - { t = "Freq", x = 70, y = 24, sp = 25, min = 5000, max = 5999, vals = { 6 }, to = SMLSIZE, upd = function(self) self.handleFreqValUpdate(self) end }, - }, - freqLookup = { - { 5865, 5845, 5825, 5805, 5785, 5765, 5745, 5725 }, -- Boscam A - { 5733, 5752, 5771, 5790, 5809, 5828, 5847, 5866 }, -- Boscam B - { 5705, 5685, 5665, 5645, 5885, 5905, 5925, 5945 }, -- Boscam E - { 5740, 5760, 5780, 5800, 5820, 5840, 5860, 5880 }, -- FatShark - { 5658, 5695, 5732, 5769, 5806, 5843, 5880, 5917 }, -- RaceBand - }, - postLoad = function (self) - if (self.values[2] or 0) < 0 or (self.values[3] or 0) == 0 or (self.values[4] or 0) == 0 then - self.values = {} - else - self.prevBandVal = 0 -- reset value trackers - self.prevChanVal = 0 - self.prevFreqVal = 0 - local rFreq - if (self.values[7] or 0) > 0 then - rFreq = math.floor(self.values[6] + (self.values[7] * 256)) - else - rFreq = 0 - end - if (self.values[2] or 0) > 0 then -- band != 0 - if rFreq > 0 then - self.prevFreqVal = rFreq - self.prevBandVal = self.values[2] - self.prevChanVal = self.values[3] - self.fields[1].min = 0 -- make sure 'U' band allowed - self.eepromWrite = true - self.fields[6].value = rFreq - self.values[6] = rFreq - else -- if user freq not supported then - self.fields[1].min = 1 -- don't allow 'U' band - self.eepromWrite = false -- don't write EEPROM on older Betaflight versions - end - else -- band == 0 - if rFreq > 0 then - self.prevFreqVal = rFreq - self.fields[1].min = 0 -- make sure 'U' band allowed - self.eepromWrite = true - self.fields[6].value = rFreq - self.values[6] = rFreq - -- set chan via freq / 100 - self.prevChanVal = clipValue(math.floor((rFreq - 5100) / 100), - self.fields[2].min, self.fields[2].max) - self.fields[2].value = self.prevChanVal - self.values[3] = self.prevChanVal - else - self.values = {} - end - end - end - end, - preSave = function(self) - local valsTemp = {} - if self.values then - local channel - if self.values[2] > 0 then -- band != 0 - channel = (self.values[2]-1)*8 + self.values[3]-1 - elseif self.fields[6].value then -- band == 0 - channel = self.fields[6].value - else - channel = 24 - end - valsTemp[1] = bit32.band(channel,0xFF) - valsTemp[2] = bit32.rshift(channel,8) - valsTemp[3] = self.values[4] - valsTemp[4] = self.values[5] - end - return valsTemp - end, - -- find closest value in freq table that is above/below given freq - findNextInFreqTable = function(self, newFreq) - local startBand - local endBand - local incFlag -- freq increasing or decreasing - if newFreq > self.prevFreqVal then - incFlag = 1 - startBand = 1 - endBand = self.fields[1].max - else - incFlag = -1 - startBand = self.fields[1].max - endBand = 1 - end - local curBand = self.values[2] - local curChan = self.values[3] - local selBand = 0 - local selChan = 0 - local selFreq = 0 - local diffVal = 9999 - local fVal - local minChan = self.fields[2].min - local maxChan = self.fields[2].max - -- need to scan bands in same "direction" as 'incFlag' - -- so same-freq selections will be handled properly (F8 & R7) - for band=startBand,endBand,incFlag do - for chan=minChan,maxChan do - if band ~= curBand or chan ~= curChan then -- don't reselect same band/chan - fVal = self.freqLookup[band][chan] - if incFlag > 0 then - if fVal >= self.prevFreqVal and fVal - self.prevFreqVal < diffVal then - -- if same freq then only select if "next" band: - if fVal ~= self.prevFreqVal or band > curBand then - selBand = band - selChan = chan - selFreq = fVal - diffVal = fVal - self.prevFreqVal - end - end - else - if fVal <= self.prevFreqVal and self.prevFreqVal - fVal < diffVal then - -- if same freq then only select if "previous" band: - if fVal ~= self.prevFreqVal or band < curBand then - selBand = band - selChan = chan - selFreq = fVal - diffVal = self.prevFreqVal - fVal - end - end - end - end - end - end - return selFreq, selBand, selChan - end, - -- returns the next user-frequency value in MHz; implements an - -- "exponential" modification rate so dialing in values is faster - getNextUserFreqValue = function(self, newFreq) - local now = getTime() -- track rate of change for possible mod speedup - if now < self.lastFreqUpdTS + 15 then - self.freqModCounter = self.freqModCounter + (15-(self.lastFreqUpdTS-now)) -- increase counter for mod speedup - else - self.freqModCounter = 0 -- no mod speedup - end - local uFreq - if self.freqModCounter > 65 then -- rate is fast enough; do mod speedup - if newFreq > self.prevFreqVal then - uFreq = clipValue(newFreq + math.floor(self.freqModCounter / 65), - self.fields[6].min, self.fields[6].max) - else - uFreq = clipValue(newFreq - math.floor(self.freqModCounter / 65), - self.fields[6].min, self.fields[6].max) - end - else - uFreq = newFreq - end - self.lastFreqUpdTS = now - return uFreq - end, - updatePowerTable = function(self) - if self.values and not self.fields[3].table then - if self.values[1] == 1 then -- RTC6705 - self.fields[3].table = { 25, 200 } - self.fields[3].max = 2 - self.fields[4].t = nil -- don't display Pit field - self.fields[4].table = { [0]="", "" } - elseif self.values[1] == 3 then -- SmartAudio - self.fields[3].table = { 25, 200, 500, 800 } - self.fields[3].max = 4 - elseif self.values[1] == 4 then -- Tramp - self.fields[3].table = { 25, 100, 200, 400, 600 } - self.fields[3].max = 5 - end - end - end, - handleBandChanUpdate = function(self) - if (#(self.values) or 0) >= self.minBytes then - if (self.values[3] or 0) > 0 then - if self.values[2] ~= self.prevBandVal or self.values[3] ~= self.prevChanVal then - if self.values[2] > 0 then -- band != 0 - self.prevFreqVal = self.freqLookup[self.values[2]][self.values[3]] - else -- band == 0; set freq via channel*100 - self.prevFreqVal = math.floor(5100 + (self.values[3] * 100)) - end - self.fields[6].value = self.prevFreqVal - self.values[6] = self.prevFreqVal - self.prevBandVal = self.values[2] - self.prevChanVal = self.values[3] - end - end - end - end, - handleFreqValUpdate = function(self) - if (#(self.values) or 0) >= self.minBytes and (self.fields[6].value or 0) > 0 then - local newFreq = self.fields[6].value - if newFreq ~= self.prevFreqVal then - if self.values[2] == 0 then - -- band == 0 - local uFreq = self.getNextUserFreqValue(self, newFreq) - self.prevFreqVal = uFreq - if uFreq ~= newFreq then - self.fields[6].value = uFreq - self.values[6] = uFreq - end - -- set channel value via freq/100 - self.prevChanVal = clipValue(math.floor((self.prevFreqVal - 5100) / 100), - self.fields[2].min, self.fields[2].max) - self.fields[2].value = self.prevChanVal - self.values[3] = self.prevChanVal - else - -- band != 0; find closest freq in table that is above/below dialed freq - local selFreq, selBand, selChan = self.findNextInFreqTable(self, newFreq) - if selFreq > 0 then - self.prevFreqVal = selFreq - self.prevBandVal = selBand - self.prevChanVal = selChan - self.fields[6].value = selFreq -- using new freq from table - self.values[6] = selFreq - self.fields[1].value = self.prevBandVal -- set band value for freq - self.values[2] = self.prevBandVal - self.fields[2].value = self.prevChanVal -- set channel value for freq - self.values[3] = self.prevChanVal - else - self.fields[6].value = self.prevFreqVal -- if no match then revert freq - self.values[6] = self.prevFreqVal - end - end - end - end - end -} \ No newline at end of file diff --git a/src/SCRIPTS/BF/X7/x7pre.lua b/src/SCRIPTS/BF/X7/x7pre.lua deleted file mode 100644 index aa955f62..00000000 --- a/src/SCRIPTS/BF/X7/x7pre.lua +++ /dev/null @@ -1,16 +0,0 @@ -PageFiles = -{ - "pids.lua", - "rates1.lua", - "rates2.lua", - "rates3.lua", - "rates4.lua", - "filters1.lua", - "filters2.lua", - "pwm.lua", - "vtx.lua" -} - -MenuBox = { x=15, y=12, w=100, x_offset=36, h_line=8, h_offset=3 } -SaveBox = { x=15, y=12, w=100, x_offset=4, h=30, h_offset=5 } -NoTelem = { 30, 55, "No Telemetry", BLINK } diff --git a/src/SCRIPTS/BF/X9/filters.lua b/src/SCRIPTS/BF/X9/filters.lua deleted file mode 100644 index 758e47a9..00000000 --- a/src/SCRIPTS/BF/X9/filters.lua +++ /dev/null @@ -1,37 +0,0 @@ - -return { - read = 92, -- MSP_FILTER_CONFIG - write = 93, -- MSP_SET_FILTER_CONFIG - eepromWrite = true, - reboot = false, - title = "Filters", - minBytes = 18, - text= { - { t = "LPF", x = 43, y = 14, to = SMLSIZE }, - { t = "Gyro", x = 15, y = 24, to = SMLSIZE }, - { t = "DTerm", x = 10, y = 34, to = SMLSIZE }, - { t = "Yaw", x = 20, y = 44, to = SMLSIZE }, - { t = "Gyro 1", x = 75, y = 14, to = SMLSIZE }, - { t = "Hz", x = 68, y = 24, to = SMLSIZE }, - { t = "CO", x = 68, y = 34, to = SMLSIZE }, - { t = "Gyro 2", x = 120, y = 14, to = SMLSIZE }, - { t = "Hz", x = 113, y = 24, to = SMLSIZE }, - { t = "CO", x = 113, y = 34, to = SMLSIZE }, - { t = "DTerm", x = 168, y = 14, to = SMLSIZE }, - { t = "Hz", x = 158, y = 24, to = SMLSIZE }, - { t = "CO", x = 158, y = 34, to = SMLSIZE }, - { t = "DTerm LP Type", x = 108, y = 44, to = SMLSIZE }, - }, - fields = { - { x = 38, y = 24, min = 0, max = 255, to = SMLSIZE, vals = { 1 } }, - { x = 38, y = 34, min = 0, max = 16000, to = SMLSIZE, vals = { 2, 3 } }, - { x = 38, y = 44, min = 0, max = 500, to = SMLSIZE, vals = { 4, 5 } }, - { x = 81, y = 24, min = 0, max = 16000, to = SMLSIZE, vals = { 6, 7 } }, - { x = 81, y = 34, min = 0, max = 16000, to = SMLSIZE, vals = { 8, 9 } }, - { x = 126, y = 24, min = 0, max = 16000, to = SMLSIZE, vals = { 14, 15 } }, - { x = 126, y = 34, min = 0, max = 16000, to = SMLSIZE, vals = { 16, 17 } }, - { x = 171, y = 24, min = 0, max = 16000, to = SMLSIZE, vals = { 10, 11 } }, - { x = 171, y = 34, min = 0, max = 16000, to = SMLSIZE, vals = { 12, 13 } }, - { x = 171, y = 44, min = 0, max = 2, to = SMLSIZE, vals = { 18 }, table = { [0] = "PT1", [1] = "BIQUAD", [2] = "FIR" } }, - } -} diff --git a/src/SCRIPTS/BF/X9/pids.lua b/src/SCRIPTS/BF/X9/pids.lua deleted file mode 100644 index 2d98ff56..00000000 --- a/src/SCRIPTS/BF/X9/pids.lua +++ /dev/null @@ -1,31 +0,0 @@ - -return { - read = 112, -- MSP_PID - write = 202, -- MSP_SET_PID - title = "PIDs", - reboot = false, - eepromWrite = true, - minBytes = 8, - text = { - { t = "P", x = 70, y = 14, to = SMLSIZE }, - { t = "I", x = 98, y = 14, to = SMLSIZE }, - { t = "D", x = 126, y = 14, to = SMLSIZE }, - { t = "ROLL", x = 25, y = 26, to = SMLSIZE }, - { t = "PITCH", x = 25, y = 36, to = SMLSIZE }, - { t = "YAW", x = 25, y = 46, to = SMLSIZE }, - }, - fields = { - -- P - { x = 66, y = 26, min = 0, max = 200, vals = { 1 }, to = SMLSIZE }, - { x = 66, y = 36, min = 0, max = 200, vals = { 4 }, to = SMLSIZE }, - { x = 66, y = 46, min = 0, max = 200, vals = { 7 }, to = SMLSIZE }, - -- I - { x = 94, y = 26, min = 0, max = 200, vals = { 2 }, to = SMLSIZE }, - { x = 94, y = 36, min = 0, max = 200, vals = { 5 }, to = SMLSIZE }, - { x = 94, y = 46, min = 0, max = 200, vals = { 8 }, to = SMLSIZE }, - -- D - { x = 122, y = 26, min = 0, max = 200, vals = { 3 }, to = SMLSIZE }, - { x = 122, y = 36, min = 0, max = 200, vals = { 6 }, to = SMLSIZE }, - --{ x = 122, y = 46, i = 9 }, - }, -} \ No newline at end of file diff --git a/src/SCRIPTS/BF/X9/pwm.lua b/src/SCRIPTS/BF/X9/pwm.lua deleted file mode 100644 index 8ba7ce9a..00000000 --- a/src/SCRIPTS/BF/X9/pwm.lua +++ /dev/null @@ -1,55 +0,0 @@ -return { - read = 90, -- MSP_ADVANCED_CONFIG - write = 91, -- MSP_SET_ADVANCED_CONFIG - reboot = true, - eepromWrite = true, - title = "PWM", - minBytes = 9, - text= { - { t = "32K", x = 48, y = 14, to = SMLSIZE }, - { t = "Gyro Rt", x = 29, y = 24, to = SMLSIZE }, - { t = "PID Rt", x = 35, y = 34, to = SMLSIZE }, - { t = "Protocol", x = 107, y = 14, to = SMLSIZE }, - { t = "Unsynced", x = 106, y = 24, to = SMLSIZE }, - { t = "PWM Rate", x = 105, y = 34, to = SMLSIZE }, - { t = "Idle Offset", x =94, y = 44, to = SMLSIZE } - }, - fields = { - { x = 65, y = 14, vals = { 9 }, min = 0, max = 1, to = SMLSIZE, table = { [0] = "OFF", "ON" }, upd = function(self) self.updateRateTables(self) end }, - { x = 65, y = 24, vals = { 1 }, min = 1, max = 32, to = SMLSIZE, upd = function(self) self.updatePidRateTable(self) end }, - { x = 65, y = 34, vals = { 2 }, min = 1, max = 16, to = SMLSIZE, }, - { x = 148, y = 14, vals = { 4 }, min = 0, max = 9, to = SMLSIZE, table = { [0] = "OFF", "ONESHOT125", "ONESHOT42", "MULTISHOT","BRUSHED", "DSHOT150", "DSHOT300", "DSHOT600","DSHOT1200", "PROSHOT1000" } }, - { x = 148, y = 24, vals = { 3 }, min = 0, max = 1, to = SMLSIZE, table = { [0] = "OFF", "ON" } }, - { x = 148, y = 34, vals = { 5, 6 }, min = 200, max = 32000, to = SMLSIZE }, - { x = 148, y = 44, vals = { 7, 8 }, min = 0, max = 2000, to = SMLSIZE, scale = 100 }, - }, - calculateGyroRates = function(self, baseRate) - self.gyroRates = {} - self.fields[2].table = {} - for i=1, 32 do - self.gyroRates[i] = baseRate/i - local fmt = nil - self.fields[2].table[i] = string.format("%.2f",baseRate/i) - end - end, - calculatePidRates = function(self, baseRate) - self.fields[3].table = {} - for i=1, 16 do - self.fields[3].table[i] = string.format("%.2f",baseRate/i) - end - end, - updateRateTables = function(self) - if self.values[9] == 0 then - self.calculateGyroRates(self, 8) - self.calculatePidRates(self, 8) - elseif self.values[9] == 1 then - self.calculateGyroRates(self, 32) - self.calculatePidRates(self, 32) - end - end, - updatePidRateTable = function(self) - local newRateIdx = self.values[1] - local newRate = self.gyroRates[newRateIdx] - self.calculatePidRates(self, newRate) - end -} diff --git a/src/SCRIPTS/BF/X9/rates1.lua b/src/SCRIPTS/BF/X9/rates1.lua deleted file mode 100644 index 1d74d467..00000000 --- a/src/SCRIPTS/BF/X9/rates1.lua +++ /dev/null @@ -1,38 +0,0 @@ -return { - read = 111, -- MSP_RC_TUNING - write = 204, -- MSP_SET_RC_TUNING - title = "Rates (1/2)", - reboot = false, - eepromWrite = true, - minBytes = 12, - text = { - { t = "RC", x = 43, y = 11, to = SMLSIZE }, - { t = "Rate", x = 38, y = 18, to = SMLSIZE }, - { t = "Super", x = 63, y = 11, to = SMLSIZE }, - { t = "Rate", x = 66, y = 18, to = SMLSIZE }, - { t = "RC", x = 99, y = 11, to = SMLSIZE }, - { t = "Expo", x = 94, y = 18, to = SMLSIZE }, - { t = "Throttle", x = 126, y = 18, to = SMLSIZE }, - { t = "Mid", x = 126, y = 31, to = SMLSIZE }, - { t = "Exp", x = 126, y = 46, to = SMLSIZE }, - { t = "TPA", x = 186, y = 18, to = SMLSIZE }, - { t = "Thr", x = 168, y = 31, to = SMLSIZE }, - { t = "Brk", x = 168, y = 46, to = SMLSIZE }, - { t = "ROLL", x = 8, y = 26, to = SMLSIZE }, - { t = "PITCH", x = 8, y = 36, to = SMLSIZE }, - { t = "YAW", x = 8, y = 46, to = SMLSIZE }, - }, - fields = { - { x = 39, y = 31, vals = { 1 }, min = 0, max = 255, scale = 100, to = SMLSIZE }, - { x = 39, y = 46, vals = { 12 }, min = 0, max = 255, scale = 100, to = SMLSIZE }, - { x = 66, y = 26, vals = { 3 }, min = 0, max = 100, scale = 100, to = SMLSIZE }, - { x = 66, y = 36, vals = { 4 }, min = 0, max = 100, scale = 100, to = SMLSIZE }, - { x = 66, y = 46, vals = { 5 }, min = 0, max = 255, scale = 100, to = SMLSIZE }, - { x = 94, y = 31, vals = { 2 }, min = 0, max = 100, scale = 100, to = SMLSIZE }, - { x = 94, y = 46, vals = { 11 }, min = 0, max = 100, scale = 100, to = SMLSIZE }, - { x = 144, y = 31, vals = { 7 }, min = 0, max = 100, scale = 100, to = SMLSIZE }, - { x = 144, y = 46, vals = { 8 }, min = 0, max = 100, scale = 100, to = SMLSIZE }, - { x = 186, y = 31, vals = { 6 } , min = 0, max = 100, scale = 100, to = SMLSIZE }, - { x = 186, y = 46, vals = { 9, 10 }, min = 1000, max = 2000, to = SMLSIZE }, - }, -} \ No newline at end of file diff --git a/src/SCRIPTS/BF/X9/rates2.lua b/src/SCRIPTS/BF/X9/rates2.lua deleted file mode 100644 index 8aeb8d2b..00000000 --- a/src/SCRIPTS/BF/X9/rates2.lua +++ /dev/null @@ -1,25 +0,0 @@ - -return { - read = 94, -- MSP_PID_ADVANCED - write = 95, -- MSP_SET_PID_ADVANCED - title = "Rates (2/2)", - reboot = false, - eepromWrite = true, - minBytes = 23, - text = { - { t = "Anti-Gravity", x = 35, y = 13, to = SMLSIZE }, - { t = "Gain", x = 15, y = 23, to = SMLSIZE }, - { t = "Thr", x = 20, y = 33, to = SMLSIZE }, - { t = "Dterm Setpoint", x = 130, y = 13, to = SMLSIZE }, - { t = "Wgt", x = 110, y = 23, to = SMLSIZE }, - { t = "Trn", x = 110, y = 33, to = SMLSIZE }, - { t = "VBAT Compensation", x = 15, y = 44, to = SMLSIZE } - }, - fields = { - { x = 55, y = 23, min = 1000, max = 30000, vals = { 22, 23 }, scale = 1000, mult = 100, to = SMLSIZE }, - { x = 55, y = 33, min = 20, max = 1000, vals = { 20, 21 }, to = SMLSIZE }, - { x = 150, y = 23, min = 0, max = 254, vals = { 10 }, scale = 100, to = SMLSIZE }, - { x = 150, y = 33, min = 0, max = 100, vals = { 9 }, scale = 100, to = SMLSIZE }, - { x = 110, y = 44, min = 0, max = 1, vals = { 8 }, table = { [0]="OFF", "ON" }, to = SMLSIZE }, - } -} diff --git a/src/SCRIPTS/BF/X9/rx.lua b/src/SCRIPTS/BF/X9/rx.lua deleted file mode 100644 index 191c1c6d..00000000 --- a/src/SCRIPTS/BF/X9/rx.lua +++ /dev/null @@ -1,17 +0,0 @@ -return { - read = 44, -- MSP_RX_CONFIG - write = 45, -- MSP_SET_RX_CONFIG - title = "RX", - reboot = false, - eepromWrite = true, - minBytes = 23, - text = {}, - fields = { - { t = "Stick Min", x = 30, y = 20, sp = 45, min = 1000, max = 2000, vals = { 6, 7 }, to = SMLSIZE }, - { t = "Stick Mid", x = 30, y = 30, sp = 45, min = 1000, max = 2000, vals = { 4, 5 }, to = SMLSIZE }, - { t = "Stick Max", x = 30, y = 40, sp = 45, min = 1000, max = 2000, vals = { 2, 3 }, to = SMLSIZE }, - { t = "Cam Angle", x = 110, y = 20, sp = 50, min = 0, max = 50, vals = { 23 }, to = SMLSIZE }, - { t = "Interp", x = 110, y = 30, sp = 50, min = 0, max = 3, vals = { 13 }, to = SMLSIZE, table={ [0]="Off", "Preset", "Auto", "Manual"} }, - { t = "Interp Int", x = 110, y = 40, sp = 50, min = 1, max = 50, vals = { 14 }, to = SMLSIZE }, - }, -} \ No newline at end of file diff --git a/src/SCRIPTS/BF/X9/vtx.lua b/src/SCRIPTS/BF/X9/vtx.lua deleted file mode 100644 index 476a88e4..00000000 --- a/src/SCRIPTS/BF/X9/vtx.lua +++ /dev/null @@ -1,242 +0,0 @@ - -return { - read = 88, -- MSP_VTX_CONFIG - write = 89, -- MSP_VTX_SET_CONFIG - eepromWrite = true, - reboot = false, - title = "VTX", - minBytes = 5, - prevBandVal = 0, - prevChanVal = 0, - prevFreqVal = 0, - lastFreqUpdTS = 0, - freqModCounter = 0, - text = {}, - fields = { - { t = "Band", x = 25, y = 14, sp = 50, min=0, max=5, vals = { 2 }, to = SMLSIZE, table = { [0]="U", "A", "B", "E", "F", "R" }, upd = function(self) self.handleBandChanUpdate(self) end }, - { t = "Channel", x = 25, y = 24, sp = 50, min=1, max=8, vals = { 3 }, to = SMLSIZE, upd = function(self) self.handleBandChanUpdate(self) end }, - { t = "Power", x = 25, y = 34, sp = 50, min=1, vals = { 4 }, to = SMLSIZE, upd = function(self) self.updatePowerTable(self) end }, - { t = "Pit", x = 25, y = 44, sp = 50, min=0, max=1, vals = { 5 }, to = SMLSIZE, table = { [0]="OFF", "ON" } }, - { t = "Dev", x = 100, y = 14, sp = 32, write = false, ro = true, vals = { 1 }, to = SMLSIZE, table = { [1]="RTC6705",[3]="SmartAudio",[4]="Tramp",[255]="None"} }, - { t = "Freq", x = 100, y = 24, sp = 32, min = 5000, max = 5999, vals = { 6 }, to = SMLSIZE, upd = function(self) self.handleFreqValUpdate(self) end }, - }, - freqLookup = { - { 5865, 5845, 5825, 5805, 5785, 5765, 5745, 5725 }, -- Boscam A - { 5733, 5752, 5771, 5790, 5809, 5828, 5847, 5866 }, -- Boscam B - { 5705, 5685, 5665, 5645, 5885, 5905, 5925, 5945 }, -- Boscam E - { 5740, 5760, 5780, 5800, 5820, 5840, 5860, 5880 }, -- FatShark - { 5658, 5695, 5732, 5769, 5806, 5843, 5880, 5917 }, -- RaceBand - }, - postLoad = function (self) - if (self.values[2] or 0) < 0 or (self.values[3] or 0) == 0 or (self.values[4] or 0) == 0 then - self.values = {} - else - self.prevBandVal = 0 -- reset value trackers - self.prevChanVal = 0 - self.prevFreqVal = 0 - local rFreq - if (self.values[7] or 0) > 0 then - rFreq = math.floor(self.values[6] + (self.values[7] * 256)) - else - rFreq = 0 - end - if (self.values[2] or 0) > 0 then -- band != 0 - if rFreq > 0 then - self.prevFreqVal = rFreq - self.prevBandVal = self.values[2] - self.prevChanVal = self.values[3] - self.fields[1].min = 0 -- make sure 'U' band allowed - self.eepromWrite = true - self.fields[6].value = rFreq - self.values[6] = rFreq - else -- if user freq not supported then - self.fields[1].min = 1 -- don't allow 'U' band - self.eepromWrite = false -- don't write EEPROM on older Betaflight versions - end - else -- band == 0 - if rFreq > 0 then - self.prevFreqVal = rFreq - self.fields[1].min = 0 -- make sure 'U' band allowed - self.eepromWrite = true - self.fields[6].value = rFreq - self.values[6] = rFreq - -- set chan via freq / 100 - self.prevChanVal = clipValue(math.floor((rFreq - 5100) / 100), - self.fields[2].min, self.fields[2].max) - self.fields[2].value = self.prevChanVal - self.values[3] = self.prevChanVal - else - self.values = {} - end - end - end - end, - preSave = function(self) - local valsTemp = {} - if self.values then - local channel - if self.values[2] > 0 then -- band != 0 - channel = (self.values[2]-1)*8 + self.values[3]-1 - elseif self.fields[6].value then -- band == 0 - channel = self.fields[6].value - else - channel = 24 - end - valsTemp[1] = bit32.band(channel,0xFF) - valsTemp[2] = bit32.rshift(channel,8) - valsTemp[3] = self.values[4] - valsTemp[4] = self.values[5] - end - return valsTemp - end, - -- find closest value in freq table that is above/below given freq - findNextInFreqTable = function(self, newFreq) - local startBand - local endBand - local incFlag -- freq increasing or decreasing - if newFreq > self.prevFreqVal then - incFlag = 1 - startBand = 1 - endBand = self.fields[1].max - else - incFlag = -1 - startBand = self.fields[1].max - endBand = 1 - end - local curBand = self.values[2] - local curChan = self.values[3] - local selBand = 0 - local selChan = 0 - local selFreq = 0 - local diffVal = 9999 - local fVal - local minChan = self.fields[2].min - local maxChan = self.fields[2].max - -- need to scan bands in same "direction" as 'incFlag' - -- so same-freq selections will be handled properly (F8 & R7) - for band=startBand,endBand,incFlag do - for chan=minChan,maxChan do - if band ~= curBand or chan ~= curChan then -- don't reselect same band/chan - fVal = self.freqLookup[band][chan] - if incFlag > 0 then - if fVal >= self.prevFreqVal and fVal - self.prevFreqVal < diffVal then - -- if same freq then only select if "next" band: - if fVal ~= self.prevFreqVal or band > curBand then - selBand = band - selChan = chan - selFreq = fVal - diffVal = fVal - self.prevFreqVal - end - end - else - if fVal <= self.prevFreqVal and self.prevFreqVal - fVal < diffVal then - -- if same freq then only select if "previous" band: - if fVal ~= self.prevFreqVal or band < curBand then - selBand = band - selChan = chan - selFreq = fVal - diffVal = self.prevFreqVal - fVal - end - end - end - end - end - end - return selFreq, selBand, selChan - end, - -- returns the next user-frequency value in MHz; implements an - -- "exponential" modification rate so dialing in values is faster - getNextUserFreqValue = function(self, newFreq) - local now = getTime() -- track rate of change for possible mod speedup - if now < self.lastFreqUpdTS + 15 then - self.freqModCounter = self.freqModCounter + (15-(self.lastFreqUpdTS-now)) -- increase counter for mod speedup - else - self.freqModCounter = 0 -- no mod speedup - end - local uFreq - if self.freqModCounter > 65 then -- rate is fast enough; do mod speedup - if newFreq > self.prevFreqVal then - uFreq = clipValue(newFreq + math.floor(self.freqModCounter / 65), - self.fields[6].min, self.fields[6].max) - else - uFreq = clipValue(newFreq - math.floor(self.freqModCounter / 65), - self.fields[6].min, self.fields[6].max) - end - else - uFreq = newFreq - end - self.lastFreqUpdTS = now - return uFreq - end, - updatePowerTable = function(self) - if self.values and not self.fields[3].table then - if self.values[1] == 1 then -- RTC6705 - self.fields[3].table = { 25, 200 } - self.fields[3].max = 2 - self.fields[4].t = nil -- don't display Pit field - self.fields[4].table = { [0]="", "" } - elseif self.values[1] == 3 then -- SmartAudio - self.fields[3].table = { 25, 200, 500, 800 } - self.fields[3].max = 4 - elseif self.values[1] == 4 then -- Tramp - self.fields[3].table = { 25, 100, 200, 400, 600 } - self.fields[3].max = 5 - end - end - end, - handleBandChanUpdate = function(self) - if (#(self.values) or 0) >= self.minBytes then - if (self.values[3] or 0) > 0 then - if self.values[2] ~= self.prevBandVal or self.values[3] ~= self.prevChanVal then - if self.values[2] > 0 then -- band != 0 - self.prevFreqVal = self.freqLookup[self.values[2]][self.values[3]] - else -- band == 0; set freq via channel*100 - self.prevFreqVal = math.floor(5100 + (self.values[3] * 100)) - end - self.fields[6].value = self.prevFreqVal - self.values[6] = self.prevFreqVal - self.prevBandVal = self.values[2] - self.prevChanVal = self.values[3] - end - end - end - end, - handleFreqValUpdate = function(self) - if (#(self.values) or 0) >= self.minBytes and (self.fields[6].value or 0) > 0 then - local newFreq = self.fields[6].value - if newFreq ~= self.prevFreqVal then - if self.values[2] == 0 then - -- band == 0 - local uFreq = self.getNextUserFreqValue(self, newFreq) - self.prevFreqVal = uFreq - if uFreq ~= newFreq then - self.fields[6].value = uFreq - self.values[6] = uFreq - end - -- set channel value via freq/100 - self.prevChanVal = clipValue(math.floor((self.prevFreqVal - 5100) / 100), - self.fields[2].min, self.fields[2].max) - self.fields[2].value = self.prevChanVal - self.values[3] = self.prevChanVal - else - -- band != 0; find closest freq in table that is above/below dialed freq - local selFreq, selBand, selChan = self.findNextInFreqTable(self, newFreq) - if selFreq > 0 then - self.prevFreqVal = selFreq - self.prevBandVal = selBand - self.prevChanVal = selChan - self.fields[6].value = selFreq -- using new freq from table - self.values[6] = selFreq - self.fields[1].value = self.prevBandVal -- set band value for freq - self.values[2] = self.prevBandVal - self.fields[2].value = self.prevChanVal -- set channel value for freq - self.values[3] = self.prevChanVal - else - self.fields[6].value = self.prevFreqVal -- if no match then revert freq - self.values[6] = self.prevFreqVal - end - end - end - end - end -} \ No newline at end of file diff --git a/src/SCRIPTS/BF/X9/x9pre.lua b/src/SCRIPTS/BF/X9/x9pre.lua deleted file mode 100644 index 0c11078d..00000000 --- a/src/SCRIPTS/BF/X9/x9pre.lua +++ /dev/null @@ -1,14 +0,0 @@ -PageFiles = -{ - "pids.lua", - "rates1.lua", - "rates2.lua", - "filters.lua", - "pwm.lua", - "rx.lua", - "vtx.lua" -} - -MenuBox = { x=40, y=12, w=120, x_offset=36, h_line=8, h_offset=3 } -SaveBox = { x=40, y=12, w=120, x_offset=4, h=30, h_offset=5 } -NoTelem = { 70, 55, "No Telemetry", BLINK } diff --git a/src/SCRIPTS/BF/acc_cal.lua b/src/SCRIPTS/BF/acc_cal.lua new file mode 100644 index 00000000..0ebfc17b --- /dev/null +++ b/src/SCRIPTS/BF/acc_cal.lua @@ -0,0 +1,24 @@ +local MSP_ACC_CALIBRATION = 205 +local accCalibrated = false +local lastRunTS = 0 +local INTERVAL = 500 + +local function processMspReply(cmd,rx_buf,err) + if cmd == MSP_ACC_CALIBRATION and not err then + accCalibrated = true + end +end + +local function accCal() + if lastRunTS == 0 or lastRunTS + INTERVAL < getTime() then + lastRunTS = getTime() + if not accCalibrated then + protocol.mspRead(MSP_ACC_CALIBRATION) + end + end + mspProcessTxQ() + processMspReply(mspPollReply()) + return accCalibrated +end + +return { f = accCal, t = "Calibrating Accelerometer" } diff --git a/src/SCRIPTS/BF/api_version.lua b/src/SCRIPTS/BF/api_version.lua new file mode 100644 index 00000000..5bcb4c2b --- /dev/null +++ b/src/SCRIPTS/BF/api_version.lua @@ -0,0 +1,26 @@ +local MSP_API_VERSION = 1 + +local apiVersionReceived = false +local lastRunTS = 0 +local INTERVAL = 50 + +local function processMspReply(cmd,rx_buf,err) + if cmd == MSP_API_VERSION and #rx_buf >= 3 and not err then + apiVersion = rx_buf[2] + rx_buf[3] / 100 + apiVersionReceived = true + end +end + +local function getApiVersion() + if lastRunTS == 0 or lastRunTS + INTERVAL < getTime() then + protocol.mspRead(MSP_API_VERSION) + lastRunTS = getTime() + end + + mspProcessTxQ() + processMspReply(mspPollReply()) + + return apiVersionReceived +end + +return { f = getApiVersion, t = "Waiting for API version" } diff --git a/src/SCRIPTS/BF/background.lua b/src/SCRIPTS/BF/background.lua index 58b1ae05..a0086f58 100644 --- a/src/SCRIPTS/BF/background.lua +++ b/src/SCRIPTS/BF/background.lua @@ -1,94 +1,45 @@ -local INTERVAL = 50 -- in 1/100th seconds -local MSP_SET_RTC = 246 -local MSP_TX_INFO = 186 - -local lastRunTS -local sensorId = -1 +local apiVersionReceived = false local timeIsSet = false -local mspMsgQueued = false - -local function getSensorValue() - if sensorId == -1 then - local sensor = getFieldInfo(protocol.stateSensor) - if type(sensor) == "table" then - sensorId = sensor['id'] or -1 - end - end - return getValue(sensorId) -end - -local function modelActive(sensorValue) - return type(sensorValue) == "number" and sensorValue > 0 -end - -local function init() - lastRunTS = 0 -end +local getApiVersion, setRtc, rssiTask +local rssiEnabled = true local function run_bg() - -- run in intervals - - if lastRunTS == 0 or lastRunTS + INTERVAL < getTime() then - mspMsgQueued = false - -- ------------------------------------ - -- SYNC DATE AND TIME - -- ------------------------------------ - local sensorValue = getSensorValue() - - if not timeIsSet and modelActive(sensorValue) then - -- Send datetime when the telemetry connection is available - -- assuming when sensor value higher than 0 there is an telemetry connection - -- only send datetime one time after telemetry connection became available - -- or when connection is restored after e.g. lipo refresh - local now = getDateTime() - local year = now.year; - - values = {} - values[1] = bit32.band(year, 0xFF) - year = bit32.rshift(year, 8) - values[2] = bit32.band(year, 0xFF) - values[3] = now.mon - values[4] = now.day - values[5] = now.hour - values[6] = now.min - values[7] = now.sec - - -- send msp message - protocol.mspWrite(MSP_SET_RTC, values) - mspMsgQueued = true - - timeIsSet = true - elseif not modelActive(sensorValue) then - timeIsSet = false - end - - - -- ------------------------------------ - -- SEND RSSI VALUE - -- ------------------------------------ - - if mspMsgQueued == false then - local rssi, alarm_low, alarm_crit = getRSSI() - -- Scale the [0, 85] (empirical) RSSI values to [0, 255] - rssi = rssi * 3 - if rssi > 255 then - rssi = 255 + if getRSSI() > 0 then + -- Send data when the telemetry connection is available + -- assuming when sensor value higher than 0 there is an telemetry connection + if not apiVersionReceived then + getApiVersion = getApiVersion or assert(loadScript("api_version.lua"))() + apiVersionReceived = getApiVersion.f() + if apiVersionReceived then + getApiVersion = nil + collectgarbage() + end + elseif not timeIsSet then + setRtc = setRtc or assert(loadScript("rtc.lua"))() + timeIsSet = setRtc.f() + if timeIsSet then + setRtc = nil + collectgarbage() + end + elseif rssiEnabled and apiVersion >= 1.37 then + rssiTask = rssiTask or assert(loadScript("rssi.lua"))() + rssiEnabled = rssiTask() + if not rssiEnabled then + rssiTask = nil + collectgarbage() end - - values = {} - values[1] = rssi - - -- send msp message - protocol.mspWrite(MSP_TX_INFO, values) - mspMsgQueued = true end - - lastRunTS = getTime() + else + apiVersionReceived = false + timeIsSet = false + rssiEnabled = true + if getApiVersion or setRtc or rssiTask then + getApiVersion = nil + setRtc = nil + rssiTask = nil + collectgarbage() + end end - - -- process queue - mspProcessTxQ() - end -return { init=init, run_bg=run_bg } +return run_bg diff --git a/src/SCRIPTS/BF/board_info.lua b/src/SCRIPTS/BF/board_info.lua new file mode 100644 index 00000000..2ba3ec1c --- /dev/null +++ b/src/SCRIPTS/BF/board_info.lua @@ -0,0 +1,137 @@ +local MSP_BOARD_INFO = 4 + +local boardInfoReceived = false + +local boardIdentifier = "" +local hardwareRevision = 0 +local boardType = 0 +local targetCapabilities = 0 +local targetName = "" +local boardName = "" +local manufacturerId = "" +local signature = {} +local mcuTypeId = 255 +local configurationState = 0 +local gyroSampleRateHz = 0 +local configurationProblems = 0 +local spiRegisteredDeviceCount = 0 +local i2cRegisteredDeviceCount = 0 + +local lastRunTS = 0 +local INTERVAL = 100 + +local function processMspReply(cmd, payload, err) + if cmd == MSP_BOARD_INFO and not err then + local length + local i = 1 + length = 4 + for c = 1, 4 do + boardIdentifier = boardIdentifier..string.char(payload[i]) + i = i + 1 + end + for idx = 1, 2 do + local raw_val = bit32.lshift(payload[i], (idx-1)*8) + hardwareRevision = bit32.bor(hardwareRevision, raw_val) + i = i + 1 + end + if apiVersion >= 1.35 then + boardType = payload[i] + end + i = i + 1 + if apiVersion >= 1.37 then + targetCapabilities = payload[i] + i = i + 1 + length = payload[i] + i = i + 1 + for c = 1, length do + targetName = targetName..string.char(payload[i]) + i = i + 1 + end + end + if apiVersion >= 1.39 then + length = payload[i] + i = i + 1 + for c = 1, length do + boardName = boardName..string.char(payload[i]) + i = i + 1 + end + length = payload[i] + i = i + 1 + for c = 1, length do + manufacturerId = manufacturerId..string.char(payload[i]) + i = i + 1 + end + length = 32 + for c = 1, 32 do + signature[#signature + 1] = payload[i] + i = i + 1 + end + end + i = i + 1 + if apiVersion >= 1.41 then + mcuTypeId = payload[i] + end + i = i + 1 + if apiVersion >= 1.42 then + configurationState = payload[i] + end + if apiVersion >= 1.43 then + for idx = 1, 2 do + local raw_val = bit32.lshift(payload[i], (idx-1)*8) + gyroSampleRateHz = bit32.bor(gyroSampleRateHz, raw_val) + i = i + 1 + end + for idx = 1, 4 do + local raw_val = bit32.lshift(payload[i], (idx-1)*8) + configurationProblems = bit32.bor(configurationProblems, raw_val) + i = i + 1 + end + end + if apiVersion >= 1.44 then + spiRegisteredDeviceCount = payload[i] + i = i + 1 + i2cRegisteredDeviceCount = payload[i] + end + boardInfoReceived = true + end +end + +local function getBoardInfo() + if lastRunTS + INTERVAL < getTime() then + lastRunTS = getTime() + if not boardInfoReceived then + protocol.mspRead(MSP_BOARD_INFO) + end + end + mspProcessTxQ() + processMspReply(mspPollReply()) + if boardInfoReceived then + local f = io.open("BOARD_INFO/"..mcuId..".lua", 'w') + io.write(f, "return {", "\n") + io.write(f, " boardIdentifier = "..'"'..boardIdentifier..'"'..",", "\n") + io.write(f, " hardwareRevision = "..tostring(hardwareRevision)..",", "\n") + io.write(f, " boardType = "..tostring(boardType)..",", "\n") + io.write(f, " targetCapabilities = "..tostring(targetCapabilities)..",", "\n") + io.write(f, " targetName = "..'"'..targetName..'"'..",", "\n") + io.write(f, " boardName = "..'"'..boardName..'"'..",", "\n") + io.write(f, " manufacturerId = "..'"'..manufacturerId..'"'..",", "\n") + local signatureString = " signature = { " + for i = 1, #signature do + signatureString = signatureString..tostring(signature[i])..", " + end + signatureString = signatureString.."}," + io.write(f, signatureString, "\n") + io.write(f, " mcuTypeId = "..tostring(mcuTypeId)..",", "\n") + io.write(f, " configurationState = "..tostring(configurationState)..",", "\n") + io.write(f, " gyroSampleRateHz = "..tostring(gyroSampleRateHz)..",", "\n") + io.write(f, " configurationProblems = "..tostring(configurationProblems)..",", "\n") + io.write(f, " spiRegisteredDeviceCount = "..tostring(spiRegisteredDeviceCount)..",", "\n") + io.write(f, " i2cRegisteredDeviceCount = "..tostring(i2cRegisteredDeviceCount)..",", "\n") + io.write(f, "}", "\n") + io.close(f) + assert(loadScript("BOARD_INFO/"..mcuId..".lua", 'c')) + end + return boardInfoReceived +end + +return { f = getBoardInfo, t = "Downloading board info" } diff --git a/src/SCRIPTS/BF/cms.lua b/src/SCRIPTS/BF/cms.lua new file mode 100644 index 00000000..fdb5752c --- /dev/null +++ b/src/SCRIPTS/BF/cms.lua @@ -0,0 +1,35 @@ +local lastMenuEventTime = 0 +local INTERVAL = 80 + +local function init() + cms.init(radio) +end + +local function stickMovement() + local threshold = 30 + return math.abs(getValue('ele')) > threshold or math.abs(getValue('ail')) > threshold or math.abs(getValue('rud')) > threshold +end + +local function run(event) + cms.update() + if cms.menuOpen == false then + cms.open() + end + if event == radio.refresh.event then + cms.synced = false + lastMenuEventTime = 0 + elseif stickMovement() then + cms.synced = false + lastMenuEventTime = getTime() + elseif event == EVT_VIRTUAL_EXIT then + cms.close() + return 1 + end + if lastMenuEventTime + INTERVAL < getTime() and not cms.synced then + lastMenuEventTime = getTime() + cms.refresh() + end + return 0 +end + +return { init=init, run=run } diff --git a/src/SCRIPTS/BF/events.lua b/src/SCRIPTS/BF/events.lua deleted file mode 100644 index e66d14c4..00000000 --- a/src/SCRIPTS/BF/events.lua +++ /dev/null @@ -1,29 +0,0 @@ - -return -{ - press = { - minus = EVT_MINUS_FIRST, - plus = EVT_PLUS_FIRST, - pageDown = EVT_PAGEDN_FIRST, - pageUp = EVT_PAGEUP_FIRST or EVT_LEFT_BREAK - }, - longPress = { - enter = EVT_ENTER_LONG, - menu = EVT_MENU_LONG or EVT_RIGHT_LONG - }, - repeatPress = { - minus = EVT_MINUS_REPT, - plus = EVT_PLUS_REPT - }, - release = { - enter = EVT_ENTER_BREAK, - exit = EVT_EXIT_BREAK, - menu = EVT_MENU_BREAK or EVT_RIGHT_BREAK, - minus = EVT_MINUS_BREAK, - plus = EVT_PLUS_BREAK - }, - dial = { - left = EVT_ROT_LEFT or EVT_UP_BREAK, - right = EVT_ROT_RIGHT or EVT_DOWN_BREAK - } -} diff --git a/src/SCRIPTS/BF/features.lua b/src/SCRIPTS/BF/features.lua new file mode 100644 index 00000000..c76251cf --- /dev/null +++ b/src/SCRIPTS/BF/features.lua @@ -0,0 +1,8 @@ +local features = { + vtx = true, + gps = true, + osdSD = true, + blackbox = true, +} + +return features diff --git a/src/SCRIPTS/BF/features_info.lua b/src/SCRIPTS/BF/features_info.lua new file mode 100644 index 00000000..5fe599bd --- /dev/null +++ b/src/SCRIPTS/BF/features_info.lua @@ -0,0 +1,102 @@ +local MSP_GPS_CONFIG = 135 +local MSP_VTX_CONFIG = 88 +local MSP_OSD_CONFIG = 84 + +local MSP_BUILD_INFO = 5 + +local BUILD_OPTION_GPS = 16412 +local BUILD_OPTION_VTX = 16421 +local BUILD_OPTION_OSD_SD = 16416 + +local isGpsRead = false +local isVtxRead = false +local isOsdSDRead = false + +local lastRunTS = 0 +local INTERVAL = 100 +local isInFlight = false + +local returnTable = { + f = nil, + t = "", +} + +local function processBuildInfoReply(payload) + local headLength = 26 -- DATE(11) + TIME(8) + REVISION(7) + local optionsLength = #payload - headLength + if (optionsLength <= 0) or ((optionsLength % 2) ~= 0) then + return -- invalid payload + end + + features.gps = false + features.vtx = false + features.osdSD = false + for i = headLength + 1, #payload, 2 do + local byte1 = bit32.lshift(payload[i], 0) + local byte2 = bit32.lshift(payload[i + 1], 8) + local word = bit32.bor(byte1, byte2) + if word == BUILD_OPTION_GPS then + features.gps = true + elseif word == BUILD_OPTION_VTX then + features.vtx = true + elseif word == BUILD_OPTION_OSD_SD then + features.osdSD = true + end + end +end + +local function processMspReply(cmd, payload, err) + isInFlight = false + local isOkay = not err + if cmd == MSP_BUILD_INFO then + isGpsRead = true + isVtxRead = true + isOsdSDRead = true + if isOkay then + processBuildInfoReply(payload) + end + elseif cmd == MSP_GPS_CONFIG then + isGpsRead = true + local providerSet = payload[1] ~= 0 + features.gps = isOkay and providerSet + elseif cmd == MSP_VTX_CONFIG then + isVtxRead = true + local vtxTableAvailable = payload[12] ~= 0 + features.vtx = isOkay and vtxTableAvailable + elseif cmd == MSP_OSD_CONFIG then + isOsdSDRead = true + local osdSDAvailable = payload[1] ~= 0 + features.osdSD = isOkay and osdSDAvailable + end +end + +local function updateFeatures() + if lastRunTS + INTERVAL < getTime() then + lastRunTS = getTime() + local cmd + if apiVersion >= 1.46 then + cmd = MSP_BUILD_INFO + returnTable.t = "Checking options..." + elseif not isGpsRead then + cmd = MSP_GPS_CONFIG + returnTable.t = "Checking GPS..." + elseif not isVtxRead then + cmd = MSP_VTX_CONFIG + returnTable.t = "Checking VTX..." + elseif not isOsdSDRead then + cmd = MSP_OSD_CONFIG + returnTable.t = "Checking OSD (SD)..." + end + if cmd and not isInFlight then + protocol.mspRead(cmd) + isInFlight = true + end + end + mspProcessTxQ() + processMspReply(mspPollReply()) + return isGpsRead and isVtxRead and isOsdSDRead +end + +returnTable.f = updateFeatures + +return returnTable diff --git a/src/SCRIPTS/BF/mcu_id.lua b/src/SCRIPTS/BF/mcu_id.lua new file mode 100644 index 00000000..f3c84387 --- /dev/null +++ b/src/SCRIPTS/BF/mcu_id.lua @@ -0,0 +1,37 @@ +local MSP_UID = 160 + +local MCUIdReceived = false + +local lastRunTS = 0 +local INTERVAL = 100 + +local function processMspReply(cmd, payload, err) + if cmd == MSP_UID and not err then + local i = 1 + local id = "" + for j = 1, 3 do + local s = "" + for k = 1, 4 do + s = string.format("%02x", payload[i])..s + i = i + 1 + end + id = id..s + end + mcuId = id + MCUIdReceived = true + end +end + +local function getMCUId() + if lastRunTS + INTERVAL < getTime() then + lastRunTS = getTime() + if not MCUIdReceived then + protocol.mspRead(MSP_UID) + end + end + mspProcessTxQ() + processMspReply(mspPollReply()) + return MCUIdReceived +end + +return { f = getMCUId, t = "Waiting for device ID" } diff --git a/src/SCRIPTS/BF/pages.lua b/src/SCRIPTS/BF/pages.lua new file mode 100644 index 00000000..4deddf51 --- /dev/null +++ b/src/SCRIPTS/BF/pages.lua @@ -0,0 +1,71 @@ +local PageFiles = {} + +if apiVersion >= 1.36 and features.vtx then + PageFiles[#PageFiles + 1] = { title = "VTX Settings", script = "vtx.lua", init = "PAGES/INIT/vtx.lua" } +end + +if apiVersion >= 1.16 then + PageFiles[#PageFiles + 1] = { title = "Profiles", script = "profiles.lua" } +end + +if apiVersion >= 1.16 then + PageFiles[#PageFiles + 1] = { title = "PIDs 1", script = "pids1.lua" } +end + +if apiVersion >= 1.21 then + PageFiles[#PageFiles + 1] = { title = "PIDs 2", script = "pids2.lua" } +end + +if apiVersion >= 1.16 then + PageFiles[#PageFiles + 1] = { title = "Rates", script = "rates.lua" } +end + +if apiVersion >= 1.16 then + PageFiles[#PageFiles + 1] = { title = "Advanced PIDs", script = "pid_advanced.lua" } +end + +if apiVersion >= 1.44 then + PageFiles[#PageFiles + 1] = { title = "Simplified Tuning", script = "simplified_tuning.lua" } +end + +if apiVersion >= 1.16 then + PageFiles[#PageFiles + 1] = { title = "Filters 1", script = "filters1.lua" } +end + +if apiVersion >= 1.42 then + PageFiles[#PageFiles + 1] = { title = "Filters 2", script = "filters2.lua" } +end + +if apiVersion >= 1.16 then + PageFiles[#PageFiles + 1] = { title = "System / Motor", script = "pwm.lua", init = "PAGES/INIT/pwm.lua" } +end + +if apiVersion >= 1.41 then + PageFiles[#PageFiles + 1] = { title = "Battery", script = "battery.lua" } +end + +if apiVersion >= 1.16 then + PageFiles[#PageFiles + 1] = { title = "Receiver", script = "rx.lua" } +end + +if apiVersion >= 1.16 then + PageFiles[#PageFiles + 1] = { title = "Failsafe", script = "failsafe.lua" } +end + +if apiVersion >= 1.41 and features.gps then + PageFiles[#PageFiles + 1] = { title = "GPS Rescue", script = "rescue.lua" } +end + +if apiVersion >= 1.41 and features.gps then + PageFiles[#PageFiles + 1] = { title = "GPS PIDs", script = "gpspids.lua" } +end + +if apiVersion >= 1.16 then + PageFiles[#PageFiles + 1] = { title = "Trim Accelerometer", script = "acc_trim.lua" } +end + +if apiVersion >= 1.45 and features.osdSD then + PageFiles[#PageFiles + 1] = { title = "OSD Elements", script = "pos_osd.lua" } +end + +return PageFiles diff --git a/src/SCRIPTS/BF/protocols.lua b/src/SCRIPTS/BF/protocols.lua index f556b285..80348218 100644 --- a/src/SCRIPTS/BF/protocols.lua +++ b/src/SCRIPTS/BF/protocols.lua @@ -2,42 +2,47 @@ local supportedProtocols = { smartPort = { - transport = SCRIPT_HOME.."/MSP/sp.lua", - rssi = function() return getValue("RSSI") end, - exitFunc = function() return 0 end, - stateSensor = "Tmp1", + mspTransport = "MSP/sp.lua", push = sportTelemetryPush, maxTxBufferSize = 6, maxRxBufferSize = 6, saveMaxRetries = 2, - saveTimeout = 300 + saveTimeout = 500, + cms = {}, }, crsf = { - transport = SCRIPT_HOME.."/MSP/crsf.lua", - rssi = function() return getValue("TQly") end, - exitFunc = function() return "/CROSSFIRE/crossfire.lua" end, - stateSensor = "1RSS", + mspTransport = "MSP/crsf.lua", + cmsTransport = "CMS/crsf.lua", push = crossfireTelemetryPush, maxTxBufferSize = 8, maxRxBufferSize = 58, saveMaxRetries = 2, - saveTimeout = 150 + saveTimeout = 150, + cms = {}, + }, + ghst = + { + mspTransport = "MSP/ghst.lua", + push = ghostTelemetryPush, + maxTxBufferSize = 10, -- Tx -> Rx (Push) + maxRxBufferSize = 6, -- Rx -> Tx (Pop) + saveMaxRetries = 2, + saveTimeout = 250, + cms = {}, } } -function getProtocol() - if supportedProtocols.smartPort.push() then +local function getProtocol() + if supportedProtocols.smartPort.push() ~= nil then return supportedProtocols.smartPort - elseif supportedProtocols.crsf.push() then + elseif supportedProtocols.crsf.push() ~= nil then return supportedProtocols.crsf + elseif supportedProtocols.ghst.push() ~= nil then + return supportedProtocols.ghst end end -local protocol = getProtocol() - -if not protocol then - error("Telemetry protocol not supported!") -end +local protocol = assert(getProtocol(), "Telemetry protocol not supported!") return protocol diff --git a/src/SCRIPTS/BF/radios.lua b/src/SCRIPTS/BF/radios.lua index 871b6d9f..b6d5e22a 100644 --- a/src/SCRIPTS/BF/radios.lua +++ b/src/SCRIPTS/BF/radios.lua @@ -1,47 +1,159 @@ -lcdResolution = +local supportedRadios = { - low = 0, - high = 1 -} - -local supportedPlatforms = { - x7 = + ["128x64"] = { - templateHome = SCRIPT_HOME.."/X7/", - preLoad = SCRIPT_HOME.."/X7/x7pre.lua", - resolution = lcdResolution.low + msp = { + template = "TEMPLATES/128x64.lua", + MenuBox = { x=15, y=12, w=100, x_offset=36, h_line=8, h_offset=3 }, + SaveBox = { x=15, y=12, w=100, x_offset=4, h=30, h_offset=5 }, + NoTelem = { 30, 55, "No Telemetry", BLINK }, + textSize = SMLSIZE, + yMinLimit = 12, + yMaxLimit = 52, + }, + cms = { + rows = 8, + cols = 26, + pixelsPerRow = 8, + pixelsPerChar = 5, + xIndent = 0, + yOffset = 0, + textSize = SMLSIZE, + refresh = { + event = EVT_VIRTUAL_ENTER, + text = "Refresh: [ENT]", + top = 1, + left = 64, + }, + }, }, - x9 = + ["128x96"] = { - templateHome = SCRIPT_HOME.."/X9/", - preLoad = SCRIPT_HOME.."/X9/x9pre.lua", - resolution = lcdResolution.low + msp = { + template = "TEMPLATES/128x96.lua", + MenuBox = { x=15, y=12, w=100, x_offset=36, h_line=8, h_offset=3 }, + SaveBox = { x=15, y=12, w=100, x_offset=4, h=30, h_offset=5 }, + NoTelem = { 30, 87, "No Telemetry", BLINK }, + textSize = SMLSIZE, + yMinLimit = 12, + yMaxLimit = 84, + }, + cms = { + rows = 12, + cols = 26, + pixelsPerRow = 8, + pixelsPerChar = 5, + xIndent = 0, + yOffset = 0, + textSize = SMLSIZE, + refresh = { + event = EVT_VIRTUAL_ENTER, + text = "Refresh: [ENT]", + top = 1, + left = 64, + }, + }, }, - horus = + ["212x64"] = { - templateHome=SCRIPT_HOME.."/HORUS/", - preLoad=SCRIPT_HOME.."/HORUS/horuspre.lua", - resolution = lcdResolution.high + msp = { + template = "TEMPLATES/212x64.lua", + MenuBox = { x=40, y=12, w=120, x_offset=36, h_line=8, h_offset=3 }, + SaveBox = { x=40, y=12, w=120, x_offset=4, h=30, h_offset=5 }, + NoTelem = { 70, 55, "No Telemetry", BLINK }, + textSize = SMLSIZE, + yMinLimit = 12, + yMaxLimit = 52, + }, + cms = { + rows = 8, + cols = 32, + pixelsPerRow = 8, + pixelsPerChar = 6, + xIndent = 0, + yOffset = 0, + textSize = SMLSIZE, + refresh = { + event = EVT_VIRTUAL_INC, + text = "Refresh: [+]", + top = 1, + left = 156, + } + }, + }, + ["480x272"] = + { + msp = { + template = "TEMPLATES/480x272.lua", + highRes = true, + MenuBox = { x=120, y=100, w=200, x_offset=68, h_line=20, h_offset=6 }, + SaveBox = { x=120, y=100, w=180, x_offset=12, h=60, h_offset=12 }, + NoTelem = { 192, LCD_H - 28, "No Telemetry", (TEXT_COLOR or 0) + INVERS + BLINK }, + textSize = 0, + yMinLimit = 35, + yMaxLimit = 235, + }, + cms = { + rows = 9, + cols = 32, + pixelsPerRow = 24, + pixelsPerChar = 14, + xIndent = 14, + yOffset = 32, + textSize = MIDSIZE, + refresh = { + event = EVT_VIRTUAL_ENTER, + text = "Refresh: [ENT]", + top = 1, + left = 300, + } + }, + }, + ["480x320"] = + { + msp = { + template = "TEMPLATES/480x320.lua", + highRes = true, + MenuBox = { x=120, y=100, w=200, x_offset=68, h_line=20, h_offset=6 }, + SaveBox = { x=120, y=100, w=180, x_offset=12, h=60, h_offset=12 }, + NoTelem = { 192, LCD_H - 28, "No Telemetry", (TEXT_COLOR or 0) + INVERS + BLINK }, + textSize = 0, + yMinLimit = 35, + yMaxLimit = 280, + }, + cms = { + rows = 9, + cols = 32, + pixelsPerRow = 24, + pixelsPerChar = 14, + xIndent = 14, + yOffset = 32, + textSize = MIDSIZE, + refresh = { + event = EVT_VIRTUAL_ENTER, + text = "Refresh: [ENT]", + top = 1, + left = 300, + } + }, + }, + ["320x480"] = + { + msp = { + template = "TEMPLATES/320x480.lua", + highRes = true, + MenuBox = { x= (LCD_W -200)/2, y=LCD_H/2, w=200, x_offset=68, h_line=20, h_offset=6 }, + SaveBox = { x= (LCD_W -200)/2, y=LCD_H/2, w=180, x_offset=12, h=60, h_offset=12 }, + NoTelem = { LCD_W/2 - 50, LCD_H - 28, "No Telemetry", (TEXT_COLOR or 0) + INVERS + BLINK }, + textSize = 0, + yMinLimit = 35, + yMaxLimit = 435, + }, + cms = nil, }, } -local supportedRadios = -{ - ["x7"] = supportedPlatforms.x7, - ["x7s"] = supportedPlatforms.x7, - ["xlite"] = supportedPlatforms.x7, - ["x9d"] = supportedPlatforms.x9, - ["x9d+"] = supportedPlatforms.x9, - ["x9e"] = supportedPlatforms.x9, - ["x10"] = supportedPlatforms.horus, - ["x12s"] = supportedPlatforms.horus, -} - -local ver, rad, maj, min, rev = getVersion() -local radio = supportedRadios[rad] - -if not radio then - error("Radio not supported: "..rad) -end +local resolution = LCD_W.."x"..LCD_H +local radio = assert(supportedRadios[resolution], resolution.." not supported") return radio diff --git a/src/SCRIPTS/BF/rssi.lua b/src/SCRIPTS/BF/rssi.lua new file mode 100644 index 00000000..dc31dd03 --- /dev/null +++ b/src/SCRIPTS/BF/rssi.lua @@ -0,0 +1,46 @@ +local MSP_SET_TX_INFO = 186 +local MSP_TX_INFO = 187 + +local RSSI_SOURCE_NONE = 0 +local RSSI_SOURCE_MSP = 4 + +local rssiSourceReceived = false +local rssiSource = RSSI_SOURCE_NONE +local lastRunTS = 0 +local INTERVAL = 50 + +local function processMspReply(cmd,rx_buf,err) + if cmd == MSP_TX_INFO and #rx_buf >= 1 and not err then + rssiSource = rx_buf[1] + rssiSourceReceived = true + end +end + +local function rssiTask() + if lastRunTS == 0 or lastRunTS + INTERVAL < getTime() then + if not rssiSourceReceived then + protocol.mspRead(MSP_TX_INFO) + elseif rssiSource == RSSI_SOURCE_NONE or rssiSource == RSSI_SOURCE_MSP then + local rssi, alarm_low, alarm_crit = getRSSI() + -- Scale the [0, 99] RSSI values to [0, 255] + rssi = rssi * 255 / 99 + if rssi > 255 then + rssi = 255 + end + + local values = {} + values[1] = rssi + + protocol.mspWrite(MSP_SET_TX_INFO, values) + end + lastRunTS = getTime() + end + + mspProcessTxQ() + + processMspReply(mspPollReply()) + + return rssiSource == RSSI_SOURCE_NONE or rssiSource == RSSI_SOURCE_MSP +end + +return rssiTask diff --git a/src/SCRIPTS/BF/rtc.lua b/src/SCRIPTS/BF/rtc.lua new file mode 100644 index 00000000..f0cd3306 --- /dev/null +++ b/src/SCRIPTS/BF/rtc.lua @@ -0,0 +1,54 @@ +local MSP_SET_RTC = 246 + +local timeIsSet = false +local lastRunTS = 0 +local INTERVAL = 50 + +local function processMspReply(cmd,rx_buf,err) + if cmd == MSP_SET_RTC and not err then + timeIsSet = true + end +end + +local function setRtc() + if lastRunTS == 0 or lastRunTS + INTERVAL < getTime() then + -- only send datetime one time after telemetry connection became available + -- or when connection is restored after e.g. lipo refresh + local values = {} + if apiVersion >= 1.41 then + -- format: seconds after the epoch (32) / milliseconds (16) + local now = getRtcTime() + + for i = 1, 4 do + values[i] = bit32.band(now, 0xFF) + now = bit32.rshift(now, 8) + end + + values[5] = 0 -- we don't have milliseconds + values[6] = 0 + else + -- format: year (16) / month (8) / day (8) / hour (8) / min (8) / sec (8) + local now = getDateTime() + local year = now.year + + values[1] = bit32.band(year, 0xFF) + year = bit32.rshift(year, 8) + values[2] = bit32.band(year, 0xFF) + values[3] = now.mon + values[4] = now.day + values[5] = now.hour + values[6] = now.min + values[7] = now.sec + end + + protocol.mspWrite(MSP_SET_RTC, values) + lastRunTS = getTime() + end + + mspProcessTxQ() + processMspReply(mspPollReply()) + + return timeIsSet +end + +return { f = setRtc, t = "" } diff --git a/src/SCRIPTS/BF/ui.lua b/src/SCRIPTS/BF/ui.lua index 2c470b37..df45bba1 100644 --- a/src/SCRIPTS/BF/ui.lua +++ b/src/SCRIPTS/BF/ui.lua @@ -1,63 +1,67 @@ -local userEvent = assert(loadScript(SCRIPT_HOME.."/events.lua"))() +local uiStatus = +{ + init = 1, + mainMenu = 2, + pages = 3, + confirm = 4, +} local pageStatus = { - display = 2, - editing = 3, - saving = 4, - displayMenu = 5, + display = 1, + editing = 2, + saving = 3, } local uiMsp = { reboot = 68, - eepromWrite = 250 + eepromWrite = 250, } -local currentState = pageStatus.display -local requestTimeout = 80 -- 800ms request timeout +local uiState = uiStatus.init +local prevUiState +local pageState = pageStatus.display +local requestTimeout = 80 local currentPage = 1 -local currentLine = 1 +local currentField = 1 local saveTS = 0 -local saveTimeout = 0 +local saveTimeout = protocol.saveTimeout local saveRetries = 0 -local saveMaxRetries = 0 -local pageRequested = false -local telemetryScreenActive = false -local menuActive = false -local lastRunTS = 0 +local saveMaxRetries = protocol.saveMaxRetries +local popupMenuActive = 1 local killEnterBreak = 0 +local pageScrollY = 0 +local mainMenuScrollY = 0 +local PageFiles, Page, init, popupMenu -Page = nil +local backgroundFill = TEXT_BGCOLOR or ERASE +local foregroundColor = LINE_COLOR or SOLID -backgroundFill = backgroundFill or ERASE -foregroundColor = foregroundColor or SOLID -globalTextOptions = globalTextOptions or 0 +local globalTextOptions = TEXT_COLOR or 0 -local function saveSettings(new) +local function saveSettings() if Page.values then + local payload = Page.values if Page.preSave then payload = Page.preSave(Page) - else - payload = Page.values end protocol.mspWrite(Page.write, payload) saveTS = getTime() - if currentState == pageStatus.saving then + if pageState == pageStatus.saving then saveRetries = saveRetries + 1 else - currentState = pageStatus.saving + pageState = pageStatus.saving saveRetries = 0 - saveMaxRetries = protocol.saveMaxRetries or 2 -- default 2 - saveTimeout = protocol.saveTimeout or 150 -- default 1.5s end end end local function invalidatePages() Page = nil - currentState = pageStatus.display + pageState = pageStatus.display saveTS = 0 + collectgarbage() end local function rebootFc() @@ -69,62 +73,66 @@ local function eepromWrite() protocol.mspRead(uiMsp.eepromWrite) end -local menuList = { - { - t = "save page", - f = saveSettings - }, - { - t = "reload", - f = invalidatePages - }, - { - t = "reboot", - f = rebootFc - } -} +local function confirm(page) + prevUiState = uiState + uiState = uiStatus.confirm + invalidatePages() + currentField = 1 + Page = assert(loadScript(page))() + collectgarbage() +end -local function processMspReply(cmd,rx_buf) - if cmd == nil or rx_buf == nil then - return +local function createPopupMenu() + popupMenuActive = 1 + popupMenu = {} + if uiState == uiStatus.pages then + popupMenu[#popupMenu + 1] = { t = "save page", f = saveSettings } + popupMenu[#popupMenu + 1] = { t = "reload", f = invalidatePages } + end + popupMenu[#popupMenu + 1] = { t = "reboot", f = rebootFc } + popupMenu[#popupMenu + 1] = { t = "acc cal", f = function() confirm("CONFIRM/acc_cal.lua") end } + if apiVersion >= 1.42 then + popupMenu[#popupMenu + 1] = { t = "vtx tables", f = function() confirm("CONFIRM/vtx_tables.lua") end } + end + if apiVersion >= 1.44 then + popupMenu[#popupMenu + 1] = { t = "board info", f = function() confirm("CONFIRM/pwm.lua") end } end - if cmd == Page.write then +end + +local function processMspReply(cmd,rx_buf,err) + if not Page or not rx_buf then + elseif cmd == Page.write then if Page.eepromWrite then eepromWrite() else invalidatePages() end - pageRequested = false - return - end - if cmd == uiMsp.eepromWrite then + elseif cmd == uiMsp.eepromWrite then if Page.reboot then rebootFc() end invalidatePages() - return - end - if cmd ~= Page.read then - return - end - if #(rx_buf) > 0 then - Page.values = {} - for i=1,#(rx_buf) do - Page.values[i] = rx_buf[i] - end - - for i=1,#(Page.fields) do - if (#(Page.values) or 0) >= Page.minBytes then - local f = Page.fields[i] - if f.vals then - f.value = 0; - for idx=1, #(f.vals) do - local raw_val = (Page.values[f.vals[idx]] or 0) - raw_val = bit32.lshift(raw_val, (idx-1)*8) - f.value = bit32.bor(f.value, raw_val) - end - f.value = f.value/(f.scale or 1) - end + elseif cmd == Page.read and err then + Page.fields = { { x = 6, y = radio.yMinLimit, value = "", ro = true } } + Page.labels = { { x = 6, y = radio.yMinLimit, t = "N/A" } } + elseif cmd == Page.read and #rx_buf > 0 then + Page.values = rx_buf + for i=1,#Page.fields do + if #Page.values >= Page.minBytes then + local f = Page.fields[i] + if f.vals then + f.value = 0 + for idx=1, #f.vals do + local raw_val = Page.values[f.vals[idx]] or 0 + raw_val = bit32.lshift(raw_val, (idx-1)*8) + f.value = bit32.bor(f.value, raw_val) + end + local bits = #f.vals * 8 + if f.min and f.min < 0 and bit32.btest(f.value, bit32.lshift(1, bits - 1)) then + f.value = f.value - (2 ^ bits) + end + f.value = f.value/(f.scale or 1) + end end end if Page.postLoad then @@ -134,70 +142,82 @@ local function processMspReply(cmd,rx_buf) end local function incMax(val, inc, base) - return ((val + inc + base - 1) % base) + 1 + return ((val + inc + base - 1) % base) + 1 +end + +function clipValue(val,min,max) + if val < min then + val = min + elseif val > max then + val = max + end + return val end local function incPage(inc) - currentPage = incMax(currentPage, inc, #(PageFiles)) - Page = nil - currentLine = 1 - collectgarbage() + currentPage = incMax(currentPage, inc, #PageFiles) + currentField = 1 + invalidatePages() end -local function incLine(inc) - currentLine = incMax(currentLine, inc, #(Page.fields)) +local function incField(inc) + currentField = clipValue(currentField + inc, 1, #Page.fields) end -local function incMenu(inc) - menuActive = incMax(menuActive, inc, #(menuList)) +local function incMainMenu(inc) + currentPage = clipValue(currentPage + inc, 1, #PageFiles) +end + +local function incPopupMenu(inc) + popupMenuActive = clipValue(popupMenuActive + inc, 1, #popupMenu) end local function requestPage() - if Page.read and ((Page.reqTS == nil) or (Page.reqTS + requestTimeout <= getTime())) then + if Page.read and ((not Page.reqTS) or (Page.reqTS + requestTimeout <= getTime())) then Page.reqTS = getTime() protocol.mspRead(Page.read) end end -function drawScreenTitle(screen_title) - if radio.resolution == lcdResolution.low then - lcd.drawFilledRectangle(0, 0, LCD_W, 10) - lcd.drawText(1,1,screen_title,INVERS) - else +local function drawScreenTitle(screenTitle) + if radio.highRes then lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR) - lcd.drawText(5,5,screen_title, MENU_TITLE_COLOR) + lcd.drawText(5,5,screenTitle, MENU_TITLE_COLOR) + else + lcd.drawFilledRectangle(0, 0, LCD_W, 10, FORCE) + lcd.drawText(1,1,screenTitle,INVERS) end end local function drawScreen() - local screen_title = Page.title - drawScreenTitle("Betaflight / "..screen_title) - for i=1,#(Page.text) do - local f = Page.text[i] - local textOptions = (f.to or 0) + globalTextOptions - lcd.drawText(f.x, f.y, f.t, textOptions) + local yMinLim = radio.yMinLimit + local yMaxLim = radio.yMaxLimit + local currentFieldY = Page.fields[currentField].y + local textOptions = radio.textSize + globalTextOptions + if currentFieldY <= Page.fields[1].y then + pageScrollY = 0 + elseif currentFieldY - pageScrollY <= yMinLim then + pageScrollY = currentFieldY - yMinLim + elseif currentFieldY - pageScrollY >= yMaxLim then + pageScrollY = currentFieldY - yMaxLim + end + for i=1,#Page.labels do + local f = Page.labels[i] + local y = f.y - pageScrollY + if y >= 0 and y <= LCD_H then + lcd.drawText(f.x, y, f.t, textOptions) + end end local val = "---" - for i=1,#(Page.fields) do + for i=1,#Page.fields do local f = Page.fields[i] - local text_options = (f.to or 0) + globalTextOptions - local heading_options = text_options - local value_options = text_options - if i == currentLine then - value_options = text_options + INVERS - if currentState == pageStatus.editing then - value_options = value_options + BLINK - end - end - local spacing = 20 - if f.t ~= nil then - lcd.drawText(f.x, f.y, f.t, heading_options) - if f.sp ~= nil then - spacing = f.sp + local valueOptions = textOptions + if i == currentField then + valueOptions = valueOptions + INVERS + if pageState == pageStatus.editing then + valueOptions = valueOptions + BLINK end - else - spacing = 0 - end + end if f.value then if f.upd and Page.values then f.upd(Page) @@ -207,155 +227,216 @@ local function drawScreen() val = f.table[f.value] end end - lcd.drawText(f.x + spacing, f.y, val, value_options) - end -end - -function clipValue(val,min,max) - if val < min then - val = min - elseif val > max then - val = max + local y = f.y - pageScrollY + if y >= 0 and y <= LCD_H then + if f.t then + lcd.drawText(f.x, y, f.t, textOptions) + end + lcd.drawText(f.sp or f.x, y, val, valueOptions) + end end - return val -end - -local function getCurrentField() - return Page.fields[currentLine] + drawScreenTitle("Betaflight / "..Page.title) end local function incValue(inc) - local f = Page.fields[currentLine] - local idx = f.i or currentLine - local scale = (f.scale or 1) - f.value = clipValue(f.value + ((inc*(f.mult or 1))/scale), (f.min/scale) or 0, (f.max/scale) or 255) - for idx=1, #(f.vals) do - Page.values[f.vals[idx]] = bit32.rshift(f.value * scale, (idx-1)*8) + local f = Page.fields[currentField] + local scale = f.scale or 1 + local mult = f.mult or 1 + f.value = clipValue(f.value + inc*mult/scale, (f.min or 0)/scale, (f.max or 255)/scale) + f.value = math.floor(f.value*scale/mult + 0.5)*mult/scale + for idx=1, #f.vals do + Page.values[f.vals[idx]] = bit32.rshift(math.floor(f.value*scale + 0.5), (idx-1)*8) end if f.upd and Page.values then f.upd(Page) end end -local function drawMenu() - local x = MenuBox.x - local y = MenuBox.y - local w = MenuBox.w - local h_line = MenuBox.h_line - local h_offset = MenuBox.h_offset - local h = #(menuList) * h_line + h_offset*2 +local function drawPopupMenu() + local x = radio.MenuBox.x + local y = radio.MenuBox.y + local w = radio.MenuBox.w + local h_line = radio.MenuBox.h_line + local h_offset = radio.MenuBox.h_offset + local h = #popupMenu * h_line + h_offset*2 lcd.drawFilledRectangle(x,y,w,h,backgroundFill) lcd.drawRectangle(x,y,w-1,h-1,foregroundColor) lcd.drawText(x+h_line/2,y+h_offset,"Menu:",globalTextOptions) - for i,e in ipairs(menuList) do - local text_options = globalTextOptions - if menuActive == i then - text_options = text_options + INVERS + for i,e in ipairs(popupMenu) do + local textOptions = globalTextOptions + if popupMenuActive == i then + textOptions = textOptions + INVERS end - lcd.drawText(x+MenuBox.x_offset,y+(i-1)*h_line+h_offset,e.t,text_options) + lcd.drawText(x+radio.MenuBox.x_offset,y+(i-1)*h_line+h_offset,e.t,textOptions) end end -function run_ui(event) - local now = getTime() - -- if lastRunTS old than 500ms - if lastRunTS + 50 < now then - invalidatePages() - end - lastRunTS = now - if (currentState == pageStatus.saving) then - if (saveTS + saveTimeout < now) then - if saveRetries < saveMaxRetries then - saveSettings() +local function run_ui(event) + if popupMenu then + drawPopupMenu() + if event == EVT_VIRTUAL_EXIT then + popupMenu = nil + elseif event == EVT_VIRTUAL_PREV then + incPopupMenu(-1) + elseif event == EVT_VIRTUAL_NEXT then + incPopupMenu(1) + elseif event == EVT_VIRTUAL_ENTER then + if killEnterBreak == 1 then + killEnterBreak = 0 else - -- max retries reached - currentState = pageStatus.display + popupMenu[popupMenuActive].f() + popupMenu = nil + end + end + elseif uiState == uiStatus.init then + lcd.clear() + drawScreenTitle("Betaflight Config") + init = init or assert(loadScript("ui_init.lua"))() + lcd.drawText(6, radio.yMinLimit, init.t) + if not init.f() then + return 0 + end + init = nil + PageFiles = assert(loadScript("pages.lua"))() + invalidatePages() + uiState = prevUiState or uiStatus.mainMenu + prevUiState = nil + elseif uiState == uiStatus.mainMenu then + if event == EVT_VIRTUAL_EXIT then + return 2 + elseif event == EVT_VIRTUAL_NEXT then + incMainMenu(1) + elseif event == EVT_VIRTUAL_PREV then + incMainMenu(-1) + elseif event == EVT_VIRTUAL_ENTER then + uiState = uiStatus.pages + elseif event == EVT_VIRTUAL_ENTER_LONG then + killEnterBreak = 1 + createPopupMenu() + end + lcd.clear() + local yMinLim = radio.yMinLimit + local yMaxLim = radio.yMaxLimit + local lineSpacing = 10 + if radio.highRes then + lineSpacing = 25 + end + local currentFieldY = (currentPage-1)*lineSpacing + yMinLim + if currentFieldY <= yMinLim then + mainMenuScrollY = 0 + elseif currentFieldY - mainMenuScrollY <= yMinLim then + mainMenuScrollY = currentFieldY - yMinLim + elseif currentFieldY - mainMenuScrollY >= yMaxLim then + mainMenuScrollY = currentFieldY - yMaxLim + end + for i=1, #PageFiles do + local attr = currentPage == i and INVERS or 0 + local y = (i-1)*lineSpacing + yMinLim - mainMenuScrollY + if y >= 0 and y <= LCD_H then + lcd.drawText(6, y, PageFiles[i].title, attr) + end + end + drawScreenTitle("Betaflight Config") + elseif uiState == uiStatus.pages then + if pageState == pageStatus.saving then + if saveTS + saveTimeout < getTime() then + if saveRetries < saveMaxRetries then + saveSettings() + else + pageState = pageStatus.display + invalidatePages() + end + end + elseif pageState == pageStatus.display then + if event == EVT_VIRTUAL_PREV_PAGE then + incPage(-1) + killEvents(event) -- X10/T16 issue: pageUp is a long press + elseif event == EVT_VIRTUAL_NEXT_PAGE then + incPage(1) + elseif event == EVT_VIRTUAL_PREV or event == EVT_VIRTUAL_PREV_REPT then + incField(-1) + elseif event == EVT_VIRTUAL_NEXT or event == EVT_VIRTUAL_NEXT_REPT then + incField(1) + elseif event == EVT_VIRTUAL_ENTER then + if Page then + local f = Page.fields[currentField] + if Page.values and f.vals and Page.values[f.vals[#f.vals]] and not f.ro then + pageState = pageStatus.editing + end + end + elseif event == EVT_VIRTUAL_ENTER_LONG then + killEnterBreak = 1 + createPopupMenu() + elseif event == EVT_VIRTUAL_EXIT then invalidatePages() + currentField = 1 + uiState = uiStatus.mainMenu + return 0 + end + elseif pageState == pageStatus.editing then + if event == EVT_VIRTUAL_EXIT or event == EVT_VIRTUAL_ENTER then + if Page.fields[currentField].postEdit then + Page.fields[currentField].postEdit(Page) + end + pageState = pageStatus.display + elseif event == EVT_VIRTUAL_INC or event == EVT_VIRTUAL_INC_REPT then + incValue(1) + elseif event == EVT_VIRTUAL_DEC or event == EVT_VIRTUAL_DEC_REPT then + incValue(-1) end end - end - -- process send queue - mspProcessTxQ() - -- navigation - if (event == userEvent.longPress.menu) then -- Taranis QX7 / X9 - menuActive = 1 - currentState = pageStatus.displayMenu - elseif userEvent.press.pageDown and (event == userEvent.longPress.enter) then -- Horus - menuActive = 1 - killEnterBreak = 1 - currentState = pageStatus.displayMenu - -- menu is currently displayed - elseif currentState == pageStatus.displayMenu then - if event == userEvent.release.exit then - currentState = pageStatus.display - elseif event == userEvent.release.plus or event == userEvent.dial.left then - incMenu(-1) - elseif event == userEvent.release.minus or event == userEvent.dial.right then - incMenu(1) - elseif event == userEvent.release.enter then - if killEnterBreak == 1 then - killEnterBreak = 0 + if not Page then + local function selectPage(page) + Page = assert(loadScript("PAGES/"..page))() + collectgarbage() + end + + local selectedPage = PageFiles[currentPage] + if selectedPage.init then + local initScript = assert(loadScript(selectedPage.init), "Missing init script")() + collectgarbage() + if initScript then + confirm(initScript) + else + selectPage(selectedPage.script) + end else - currentState = pageStatus.display - menuList[menuActive].f() + selectPage(selectedPage.script) end end - -- normal page viewing - elseif currentState <= pageStatus.display then - if event == userEvent.press.pageUp then - incPage(-1) - elseif event == userEvent.release.menu or event == userEvent.press.pageDown then - incPage(1) - elseif event == userEvent.release.plus or event == userEvent.dial.left then - incLine(-1) - elseif event == userEvent.release.minus or event == userEvent.dial.right then - incLine(1) - elseif event == userEvent.release.enter then - local field = Page.fields[currentLine] - local idx = field.i or currentLine - if Page.values and Page.values[idx] and (field.ro ~= true) then - currentState = pageStatus.editing + if not Page.values and pageState == pageStatus.display then + requestPage() + end + lcd.clear() + drawScreen() + if pageState == pageStatus.saving then + local saveMsg = "Saving..." + if saveRetries > 0 then + saveMsg = "Retrying" end - elseif event == userEvent.release.exit then - return protocol.exitFunc(); + lcd.drawFilledRectangle(radio.SaveBox.x,radio.SaveBox.y,radio.SaveBox.w,radio.SaveBox.h,backgroundFill) + lcd.drawRectangle(radio.SaveBox.x,radio.SaveBox.y,radio.SaveBox.w,radio.SaveBox.h,SOLID) + lcd.drawText(radio.SaveBox.x+radio.SaveBox.x_offset,radio.SaveBox.y+radio.SaveBox.h_offset,saveMsg,DBLSIZE + globalTextOptions) end - -- editing value - elseif currentState == pageStatus.editing then - if (event == userEvent.release.exit) or (event == userEvent.release.enter) then - currentState = pageStatus.display - elseif event == userEvent.press.plus or event == userEvent.repeatPress.plus or event == userEvent.dial.right then - incValue(1) - elseif event == userEvent.press.minus or event == userEvent.repeatPress.minus or event == userEvent.dial.left then - incValue(-1) + elseif uiState == uiStatus.confirm then + lcd.clear() + drawScreen() + if event == EVT_VIRTUAL_ENTER then + uiState = uiStatus.init + init = Page.init + invalidatePages() + elseif event == EVT_VIRTUAL_EXIT then + invalidatePages() + uiState = prevUiState + prevUiState = nil end end - if Page == nil then - Page = assert(loadScript(radio.templateHome .. PageFiles[currentPage]))() - end - if not Page.values and currentState == pageStatus.display then - requestPage() - end - lcd.clear() - if TEXT_BGCOLOR then - lcd.drawFilledRectangle(0, 0, LCD_W, LCD_H, TEXT_BGCOLOR) - end - drawScreen() - if protocol.rssi() == 0 then - lcd.drawText(NoTelem[1],NoTelem[2],NoTelem[3],NoTelem[4]) - end - if currentState == pageStatus.displayMenu then - drawMenu() - elseif currentState == pageStatus.saving then - lcd.drawFilledRectangle(SaveBox.x,SaveBox.y,SaveBox.w,SaveBox.h,backgroundFill) - lcd.drawRectangle(SaveBox.x,SaveBox.y,SaveBox.w,SaveBox.h,SOLID) - if saveRetries <= 0 then - lcd.drawText(SaveBox.x+SaveBox.x_offset,SaveBox.y+SaveBox.h_offset,"Saving...",DBLSIZE + BLINK + (globalTextOptions)) - else - lcd.drawText(SaveBox.x+SaveBox.x_offset,SaveBox.y+SaveBox.h_offset,"Retrying",DBLSIZE + (globalTextOptions)) - end + if getRSSI() == 0 then + lcd.drawText(radio.NoTelem[1],radio.NoTelem[2],radio.NoTelem[3],radio.NoTelem[4]) end + mspProcessTxQ() processMspReply(mspPollReply()) return 0 end diff --git a/src/SCRIPTS/BF/ui_init.lua b/src/SCRIPTS/BF/ui_init.lua new file mode 100644 index 00000000..c00f0351 --- /dev/null +++ b/src/SCRIPTS/BF/ui_init.lua @@ -0,0 +1,42 @@ +local apiVersionReceived = false +local mcuIdReceived = false +local featuresReceived = false +local getApiVersion, getMCUId, getFeaturesInfo +local returnTable = { f = nil, t = "" } + +local function init() + if getRSSI() == 0 then + returnTable.t = "Waiting for connection" + elseif not apiVersionReceived then + getApiVersion = getApiVersion or assert(loadScript("api_version.lua"))() + returnTable.t = getApiVersion.t + apiVersionReceived = getApiVersion.f() + if apiVersionReceived then + getApiVersion = nil + collectgarbage() + end + elseif not mcuIdReceived and apiVersion >= 1.42 then + getMCUId = getMCUId or assert(loadScript("mcu_id.lua"))() + returnTable.t = getMCUId.t + mcuIdReceived = getMCUId.f() + if mcuIdReceived then + getMCUId = nil + collectgarbage() + end + elseif not featuresReceived and apiVersion >= 1.41 then + getFeaturesInfo = getFeaturesInfo or assert(loadScript("features_info.lua"))() + returnTable.t = getFeaturesInfo.t + featuresReceived = getFeaturesInfo.f() + if featuresReceived then + getFeaturesInfo = nil + collectgarbage() + end + else + return true + end + return apiVersionReceived and mcuId and featuresReceived +end + +returnTable.f = init + +return returnTable diff --git a/src/SCRIPTS/BF/vtx_tables.lua b/src/SCRIPTS/BF/vtx_tables.lua new file mode 100644 index 00000000..13f05265 --- /dev/null +++ b/src/SCRIPTS/BF/vtx_tables.lua @@ -0,0 +1,132 @@ +local MSP_VTX_CONFIG = 88 +local MSP_VTXTABLE_BAND = 137 +local MSP_VTXTABLE_POWERLEVEL = 138 + +local vtxTableAvailable = false +local vtxConfigReceived = false +local vtxFrequencyTableReceived = false +local vtxPowerTableReceived = false +local vtxTablesReceived = false +local requestedBand = 1 +local requestedPowerLevel = 1 +local vtxTableConfig = {} +local frequencyTable = {} +local bandTable = {} +local powerTable = {} + +local lastRunTS = 0 +local INTERVAL = 100 + +local function processMspReply(cmd, payload, err) + if cmd == MSP_VTX_CONFIG then + if err then + -- Vtx not available. Create empty vtx table to skip future download attempts + frequencyTable[1] = {} + vtxTableConfig.channels = 0 + bandTable = { [0] = "U", "1" } + powerTable = { "LV0" } + vtxConfigReceived = true + vtxTableAvailable = true + vtxFrequencyTableReceived = true + vtxPowerTableReceived = true + features.vtx = false + return + end + vtxConfigReceived = true + vtxTableAvailable = payload[12] ~= 0 + features.vtx = vtxTableAvailable + vtxTableConfig.bands = payload[13] + vtxTableConfig.channels = payload[14] + vtxTableConfig.powerLevels = payload[15] + end + if cmd == MSP_VTXTABLE_BAND and payload[1] == requestedBand then + local i = 1 + local receivedBand = payload[i] + i = i + 1 + local bandNameLength = payload[i] + i = i + bandNameLength + 1 + bandTable[receivedBand] = string.char(payload[i]) + i = i + 2 + local channels = payload[i] + i = i + 1 + frequencyTable[receivedBand] = {} + for channel = 1, channels do + local frequency = 0 + for idx=1, 2 do + local raw_val = payload[i] + raw_val = bit32.lshift(raw_val, (idx-1)*8) + frequency = bit32.bor(frequency, raw_val) + i = i + 1 + end + frequencyTable[receivedBand][channel] = frequency + end + requestedBand = requestedBand + 1 + vtxFrequencyTableReceived = requestedBand > vtxTableConfig.bands + end + if cmd == MSP_VTXTABLE_POWERLEVEL and payload[1] == requestedPowerLevel then + local i = 1 + local powerLevel = payload[i] + i = i + 3 + local powerLabelLength = payload[i] + i = i + 1 + powerTable[powerLevel] = '' + for c = 1, powerLabelLength do + powerTable[powerLevel] = powerTable[powerLevel]..string.char(payload[i]) + i = i + 1 + end + requestedPowerLevel = requestedPowerLevel + 1 + vtxPowerTableReceived = requestedPowerLevel > vtxTableConfig.powerLevels + end +end + +local function getVtxTables() + if lastRunTS + INTERVAL < getTime() then + lastRunTS = getTime() + if not vtxConfigReceived then + protocol.mspRead(MSP_VTX_CONFIG) + elseif vtxConfigReceived and not vtxTableAvailable then + return true + elseif not vtxFrequencyTableReceived then + protocol.mspWrite(MSP_VTXTABLE_BAND, { requestedBand }) + elseif not vtxPowerTableReceived then + protocol.mspWrite(MSP_VTXTABLE_POWERLEVEL, { requestedPowerLevel }) + else + vtxTablesReceived = true + end + end + if vtxTablesReceived then + local f = io.open("VTX_TABLES/"..mcuId..".lua", 'w') + io.write(f, "return {", "\n") + io.write(f, " frequencyTable = {", "\n") + for i = 1, #frequencyTable do + local frequencyString = " { " + for k = 1, #frequencyTable[i] do + frequencyString = frequencyString..tostring(frequencyTable[i][k])..", " + end + frequencyString = frequencyString.."}," + io.write(f, frequencyString, "\n") + end + io.write(f, " },", "\n") + io.write(f, " frequenciesPerBand = "..tostring(vtxTableConfig.channels)..",", "\n") + local bandString = " bandTable = { [0]=\"U\", " + for i = 1, #bandTable do + bandString = bandString.."\""..bandTable[i].."\", " + end + bandString = bandString.."}," + io.write(f, bandString, "\n") + local powerString = " powerTable = { " + for i = 1, #powerTable do + powerString = powerString.."\""..powerTable[i].."\", " + end + powerString = powerString.."}," + io.write(f, powerString, "\n") + io.write(f, "}", "\n") + io.close(f) + assert(loadScript("VTX_TABLES/"..mcuId..".lua", 'c')) + end + mspProcessTxQ() + processMspReply(mspPollReply()) + return vtxTablesReceived +end + +return { f = getVtxTables, t = "Downloading VTX tables" } diff --git a/src/SCRIPTS/FUNCTIONS/bfbkgd.lua b/src/SCRIPTS/FUNCTIONS/bfbkgd.lua new file mode 100644 index 00000000..137000ba --- /dev/null +++ b/src/SCRIPTS/FUNCTIONS/bfbkgd.lua @@ -0,0 +1,8 @@ +chdir("/SCRIPTS/BF") +apiVersion = 0 +protocol = assert(loadScript("protocols.lua"))() +assert(loadScript(protocol.mspTransport))() +assert(loadScript("MSP/common.lua"))() +local background = assert(loadScript("background.lua"))() + +return { run=background } diff --git a/src/SCRIPTS/FUNCTIONS/bfpids.lua b/src/SCRIPTS/FUNCTIONS/bfpids.lua new file mode 100644 index 00000000..c2041e22 --- /dev/null +++ b/src/SCRIPTS/FUNCTIONS/bfpids.lua @@ -0,0 +1,44 @@ +chdir("/SCRIPTS/BF") + +assert(loadScript("MSP/messages.lua"))() + +local msg_p = { + intro = "p.wav", + readoutValues = {1, 2, 3}, +} + +local msg_i = { + intro = "i.wav", + readoutValues = {4, 5, 6}, +} + +local msg_d = { + intro = "d.wav", + readoutValues = {7, 8}, +} + +local msg_dsetpt = { + intro = "dsetpt.wav", + readoutValues = {1, 2}, +} + +local pidSelectorField = nil + +local function init_pids() + pidSelectorField = getFieldInfo("trim-thr") +end + +local function run_pids() + local pidSelector = getValue(pidSelectorField.id) + if pidSelector > 33 and pidSelector < 99 then + readoutMsp(MSP_PID_FORMAT, msg_p) + elseif pidSelector > 99 and pidSelector < 165 then + readoutMsp(MSP_PID_FORMAT, msg_i) + elseif pidSelector > 165 and pidSelector < 231 then + readoutMsp(MSP_PID_FORMAT, msg_d) + elseif pidSelector > -99 and pidSelector < -33 then + readoutMsp(MSP_PID_ADVANCED_FORMAT, msg_dsetpt) + end +end + +return { init = init_pids, run = run_pids } diff --git a/src/SCRIPTS/TELEMETRY/bf.lua b/src/SCRIPTS/TELEMETRY/bf.lua deleted file mode 100644 index 3083903d..00000000 --- a/src/SCRIPTS/TELEMETRY/bf.lua +++ /dev/null @@ -1,29 +0,0 @@ -SCRIPT_HOME = "/SCRIPTS/BF" - -protocol = assert(loadScript(SCRIPT_HOME.."/protocols.lua"))() -radio = assert(loadScript(SCRIPT_HOME.."/radios.lua"))() - -assert(loadScript(radio.preLoad))() -assert(loadScript(protocol.transport))() -assert(loadScript(SCRIPT_HOME.."/MSP/common.lua"))() - -local run_ui = assert(loadScript(SCRIPT_HOME.."/ui.lua"))() -local background = assert(loadScript(SCRIPT_HOME.."/background.lua"))() - -local MENU_TIMESLICE = 100 - -local lastMenuEvent = 0 - -function run(event) - lastMenuEvent = getTime() - - run_ui(event) -end - -function run_bg() - if lastMenuEvent + MENU_TIMESLICE < getTime() then - background.run_bg() - end -end - -return { init=background.init, run=run, background=run_bg } diff --git a/src/SCRIPTS/TOOLS/bf.lua b/src/SCRIPTS/TOOLS/bf.lua new file mode 100644 index 00000000..2b42f18b --- /dev/null +++ b/src/SCRIPTS/TOOLS/bf.lua @@ -0,0 +1,21 @@ +local toolName = "TNS|Betaflight setup|TNE" +chdir("/SCRIPTS/BF") + +apiVersion = 0 +mcuId = nil + +local run = nil +local scriptsCompiled = assert(loadScript("COMPILE/scripts_compiled.lua"))() + +if scriptsCompiled then + protocol = assert(loadScript("protocols.lua"))() + radio = assert(loadScript("radios.lua"))().msp + assert(loadScript(protocol.mspTransport))() + assert(loadScript("MSP/common.lua"))() + features = assert(loadScript("features.lua"))() + run = assert(loadScript("ui.lua"))() +else + run = assert(loadScript("COMPILE/compile.lua"))() +end + +return { run=run } diff --git a/src/SCRIPTS/TOOLS/bfCms.lua b/src/SCRIPTS/TOOLS/bfCms.lua new file mode 100644 index 00000000..d9a8b0ab --- /dev/null +++ b/src/SCRIPTS/TOOLS/bfCms.lua @@ -0,0 +1,20 @@ +local toolName = "TNS|Betaflight CMS|TNE" +chdir("/SCRIPTS/BF") + +apiVersion = 0 + +local cms = { run = nil, init = nil } +local scriptsCompiled = assert(loadScript("COMPILE/scripts_compiled.lua"))() + +if scriptsCompiled then + protocol = assert(loadScript("protocols.lua"))() + local cmsTransport = assert(protocol.cmsTransport, "Telemetry protocol not supported!") + radio = assert(loadScript("radios.lua"))().cms + assert(loadScript(cmsTransport))() + assert(loadScript("CMS/common.lua"))() + cms = assert(loadScript("cms.lua"))() +else + cms = { run = assert(loadScript("COMPILE/compile.lua"))() } +end + +return cms diff --git a/src/SOUNDS/en/d.wav b/src/SOUNDS/en/d.wav new file mode 100644 index 00000000..cd30cf6d Binary files /dev/null and b/src/SOUNDS/en/d.wav differ diff --git a/src/SOUNDS/en/dsetpt.wav b/src/SOUNDS/en/dsetpt.wav new file mode 100644 index 00000000..24f54c0e Binary files /dev/null and b/src/SOUNDS/en/dsetpt.wav differ diff --git a/src/SOUNDS/en/i.wav b/src/SOUNDS/en/i.wav new file mode 100644 index 00000000..79d4e73c Binary files /dev/null and b/src/SOUNDS/en/i.wav differ diff --git a/src/SOUNDS/en/p.wav b/src/SOUNDS/en/p.wav new file mode 100644 index 00000000..1a944624 Binary files /dev/null and b/src/SOUNDS/en/p.wav differ