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/README.md b/README.md
index eb175806..67a520b6 100644
--- a/README.md
+++ b/README.md
@@ -1,11 +1,19 @@
-# Betaflight TX Lua Scripts
+
+
-## Firmware Considerations
+ [](https://github.com/betaflight/betaflight-tx-lua-scripts/releases) [](https://github.com/betaflight/betaflight-tx-lua-scripts/actions/workflows/nightly.yml) [](https://www.gnu.org/licenses/gpl-3.0)
+
+## Requirements
- Betaflight - As a best practice, it is recommended to use the most recent stable release of Betaflight to obtain the best possible results;
-- OpenTX - 2.3.4 or newer;
-- Crossfire TX / RX - v2.11 or newer;
-- FrSky TX / RX - 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.
+- 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.
## Installing
@@ -15,38 +23,66 @@ Download a zip file containing the latest version from the [releases page](https
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.
-### How to install
+
+
+## How to use
-Bootloader Method
+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.
-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.
+### Betaflight setup
-Manual method (varies, based on the model of your transmitter)
+The "Betaflight setup" script lets you configure Betaflight through the MSP protocol.
-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.
+
-If you copied the files correctly, you can now go into the OpenTx Tools screen from the main menu and access the Betaflight Configuration tool. The first time you run the script, a message 'Compiling...' will appear in the display before the script is started - this is normal, and is done to minimise the RAM usage of the script.
+#### Controls
-### Running the script as a telemetry page
+- [+] / [-] / [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.
-Due to issues with input mapping and memory overruns, running the script as a telemetry page **is no longer supported**. The only way to run the script is through the Tools screen in the OpenTX main menu.
+#### Saving your changes
-### Setting up VTX Tables
+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.
+
+
+
+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.
+
+
+
+#### Controls
+
+- [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 !!**
+
### Background script
-The optional background script offers RTC synchronization and RSSI through MSP. 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.
-
+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.
+
+
+
+## Unstable testing versions
+
+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).
+Be aware that these versions are intended for testing / feedback only, and may be buggy or broken. Caution is advised when using these versions.
## Building from source
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
deleted file mode 100644
index 66f7f867..00000000
--- a/azure-pipelines.yml
+++ /dev/null
@@ -1,72 +0,0 @@
-# Builds the Betaflight TX lua scripts.
-#
-# After building, artifacts are released to a seperate repository.
-#
-# Azure Pipelines requires the following extensions to be installed:
-# - GitHub Tool: https://marketplace.visualstudio.com/items?itemName=marcelo-formentao.github-tools
-#
-# You'll also need to setup the follwing pipeline variables:
-# "releaseNotes" - This is used to add the release notes in the windows job in the build stage so they can be published as part of the github release in the release stage
-# "endpoint" - The name of the github endpoint link setup in AzDo - setup when linking AzDo and GitHub
-# "owner" - The owner of the repository to release to e.g. betaflight
-# "repoName" - The name of the repository to release to e.g. betaflight-configurator-nightly
-
-variables:
- owner: betaflight
- repoName: betaflight-tx-lua-scripts-nightlies
- releaseNotes: This is a nightly build off the tip of 'master'. It may be unstable and result in corrupted configurations or data loss. **Use only for testing.**
-
-name: $(Date:yyyyMMdd).$(BuildID)
-trigger:
- batch: true
- branches:
- include:
- - master
-pr: none
-
-stages:
-- stage: Build
- jobs:
- - job: 'Linux'
- pool:
- vmImage: 'ubuntu-16.04'
- steps:
- - script: sudo apt-get -y install lua5.2
- displayName: 'Install lua compiler.'
- - script: make release -C $(System.DefaultWorkingDirectory)
- displayName: 'Test and build the release.'
- - task: PublishPipelineArtifact@1
- displayName: 'Publish release'
- inputs:
- artifactName: betaflight-tx-lua-scripts
- targetPath: '$(System.DefaultWorkingDirectory)/release'
-
-- stage: Release
- jobs:
- - job: Release
- steps:
- - task: DownloadPipelineArtifact@2
- inputs:
- buildType: 'current'
- targetPath: '$(Pipeline.Workspace)'
- - task: GitHubReleasePublish@1
- inputs:
- githubEndpoint: '$(endpoint)'
- manuallySetRepository: true
- githubOwner: '$(owner)'
- githubRepositoryName: '$(repoName)'
- githubReleaseNotes: |+
- $(releaseNotes)
-
- ### Changes:
- $(Build.SourceVersionMessage)
- githubReleaseDraft: false
- githubReleasePrerelease: false
- githubIgnoreAssets: false
- githubReleaseAsset: |
- $(Pipeline.Workspace)/betaflight-tx-lua-scripts/**
- githubReuseRelease: true
- githubReuseDraftOnly: true
- githubSkipDuplicatedAssets: false
- githubEditRelease: false
- githubDeleteEmptyTag: false
diff --git a/bin/build.sh b/bin/build.sh
index a58209fa..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/*
diff --git a/docs/assets/images/background_script_setup.png b/docs/assets/images/background_script_setup.png
index fabb458e..09b48066 100644
Binary files a/docs/assets/images/background_script_setup.png 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/use_tools_menu_instead_of_this.txt b/src/BF/use_tools_menu_instead_of_this.txt
deleted file mode 100644
index e69de29b..00000000
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/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/MSP/common.lua b/src/SCRIPTS/BF/MSP/common.lua
index 46648991..467c1ce1 100644
--- a/src/SCRIPTS/BF/MSP/common.lua
+++ b/src/SCRIPTS/BF/MSP/common.lua
@@ -6,6 +6,8 @@ local MSP_STARTFLAG = bit32.lshift(1,4)
local mspSeq = 0
local mspRemoteSeq = 0
local mspRxBuf = {}
+local mspRxError = false
+local mspRxSize = 0
local mspRxCRC = 0
local mspRxReq = 0
local mspStarted = false
@@ -37,12 +39,6 @@ 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
protocol.mspSend(payload)
mspTxBuf = {}
mspTxIdx = 1
@@ -68,25 +64,26 @@ 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
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
@@ -95,30 +92,29 @@ function mspReceivedReply(payload)
end
while (idx <= protocol.maxRxBufferSize) and (#mspRxBuf < mspRxSize) do
mspRxBuf[#mspRxBuf + 1] = payload[idx]
- mspRxCRC = bit32.bxor(mspRxCRC,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
+ if mspRxCRC ~= payload[idx] and version == 0 then
return nil
end
- return mspRxBuf
+ return true
end
function mspPollReply()
while true do
- local ret = protocol.mspPoll()
- if type(ret) == "table" then
+ local mspData = protocol.mspPoll()
+ if mspData == nil then
+ return nil
+ elseif mspReceivedReply(mspData) then
mspLastReq = 0
- return mspRxReq, ret
- else
- break
- end
+ 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 63c92006..9fb4eeed 100644
--- a/src/SCRIPTS/BF/MSP/crsf.lua
+++ b/src/SCRIPTS/BF/MSP/crsf.lua
@@ -6,7 +6,7 @@ local CRSF_FRAMETYPE_MSP_REQ = 0x7A -- response request using msp
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
+local crsfMspCmd = 0
protocol.mspSend = function(payload)
local payloadOut = { CRSF_ADDRESS_BETAFLIGHT, CRSF_ADDRESS_RADIO_TRANSMITTER }
@@ -27,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/sp.lua b/src/SCRIPTS/BF/MSP/sp.lua
index eaabe8cd..7d2bc991 100644
--- a/src/SCRIPTS/BF/MSP/sp.lua
+++ b/src/SCRIPTS/BF/MSP/sp.lua
@@ -7,9 +7,11 @@ local REPLY_FRAME_ID = 0x32
local lastSensorId, lastFrameId, lastDataId, lastValue
protocol.mspSend = function(payload)
- local dataId = payload[1] + bit32.lshift(payload[2],8)
- local value = payload[3] + bit32.lshift(payload[4],8)
- + bit32.lshift(payload[5],16) + bit32.lshift(payload[6],24)
+ local dataId = payload[1] + bit32.lshift(payload[2], 8)
+ local value = 0
+ 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
@@ -40,20 +42,23 @@ local function smartPortTelemetryPop()
end
protocol.mspPoll = function()
- 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 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
index d7eb5937..4b85a745 100644
--- a/src/SCRIPTS/BF/PAGES/filters1.lua
+++ b/src/SCRIPTS/BF/PAGES/filters1.lua
@@ -1,9 +1,4 @@
-local template = loadScript(radio.templateHome.."filters1.lua")
-if template then
- template = template()
-else
- template = assert(loadScript(radio.templateHome.."default_template.lua"))()
-end
+local template = assert(loadScript(radio.template))()
local margin = template.margin
local indent = template.indent
local lineSpacing = template.lineSpacing
@@ -16,73 +11,86 @@ local inc = { x = function(val) x = x + val return x end, y = function(val) y =
local labels = {}
local fields = {}
-if apiVersion >= 1.041 then
+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 = 1, vals = { 25 }, table = { [0] = "PT1", [1] = "BIQUAD" } }
+ 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.016 then
+if apiVersion >= 1.16 then
labels[#labels + 1] = { t = "Gyro Lowpass 1", x = x, y = inc.y(lineSpacing) }
- if apiVersion >= 1.039 then
+ 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 = 1, vals = { 25 }, table = { [0] = "PT1", [1] = "BIQUAD" } }
+ 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.039 then
+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 = 1, vals = { 26 }, table = { [0] = "PT1", [1] = "BIQUAD" } }
+ 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.020 then
+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.021 then
+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.041 then
+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 = 1, vals = { 18 }, table = { [0] = "PT1", [1] = "BIQUAD" } }
+ 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.016 then
+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.036 and apiVersion <= 1.038 then
- fields[#fields + 1] = { t = "Filter Type", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 2, vals = { 18 }, table = { [0] = "PT1", [1] = "BIQUAD", [2] = "FIR" } }
- elseif apiVersion >= 1.039 then
- fields[#fields + 1] = { t = "Filter Type", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 1, vals = { 18 }, table = { [0] = "PT1", [1] = "BIQUAD" } }
+ 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.039 then
+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.041 then
- fields[#fields + 1] = { t = "Filter Type", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 1, vals = { 29 }, table = { [0] = "PT1", [1] = "BIQUAD" } }
+ 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.020 then
+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.016 then
+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
diff --git a/src/SCRIPTS/BF/PAGES/filters2.lua b/src/SCRIPTS/BF/PAGES/filters2.lua
index 5984a61c..7fb2e44f 100644
--- a/src/SCRIPTS/BF/PAGES/filters2.lua
+++ b/src/SCRIPTS/BF/PAGES/filters2.lua
@@ -1,9 +1,4 @@
-local template = loadScript(radio.templateHome.."filters2.lua")
-if template then
- template = template()
-else
- template = assert(loadScript(radio.templateHome.."default_template.lua"))()
-end
+local template = assert(loadScript(radio.template))()
local margin = template.margin
local indent = template.indent
local lineSpacing = template.lineSpacing
@@ -16,17 +11,21 @@ local inc = { x = function(val) x = x + val return x end, y = function(val) y =
local labels = {}
local fields = {}
-if apiVersion >= 1.042 then
+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.043 then
+ 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
- fields[#fields + 1] = { t = "Width %", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 20, vals = { 39 } }
+ 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.043 then
+ 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
@@ -47,7 +46,7 @@ return {
self.rpmHarmonics = self.values[44]
end,
preSave = function(self)
- self.reboot = self.values[44] == 0 and self.rpmHarmonics ~= 0
+ 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
index dd6af065..a28685f1 100644
--- a/src/SCRIPTS/BF/PAGES/gpspids.lua
+++ b/src/SCRIPTS/BF/PAGES/gpspids.lua
@@ -1,9 +1,4 @@
-local template = loadScript(radio.templateHome.."gpspids.lua")
-if template then
- template = template()
-else
- template = assert(loadScript(radio.templateHome.."default_template.lua"))()
-end
+local template = assert(loadScript(radio.template))()
local margin = template.margin
local indent = template.indent
local lineSpacing = template.lineSpacing
@@ -16,7 +11,7 @@ local inc = { x = function(val) x = x + val return x end, y = function(val) y =
local labels = {}
local fields = {}
-if apiVersion >= 1.041 then
+if apiVersion >= 1.41 then
x = margin
y = yMinLim - tableSpacing.header
labels[#labels + 1] = { t = "", x = x, y = inc.y(tableSpacing.header) }
diff --git a/src/SCRIPTS/BF/PAGES/pid_advanced.lua b/src/SCRIPTS/BF/PAGES/pid_advanced.lua
index f9250841..5be23f12 100644
--- a/src/SCRIPTS/BF/PAGES/pid_advanced.lua
+++ b/src/SCRIPTS/BF/PAGES/pid_advanced.lua
@@ -1,9 +1,4 @@
-local template = loadScript(radio.templateHome.."pid_advanced.lua")
-if template then
- template = template()
-else
- template = assert(loadScript(radio.templateHome.."default_template.lua"))()
-end
+local template = assert(loadScript(radio.template))()
local margin = template.margin
local indent = template.indent
local lineSpacing = template.lineSpacing
@@ -16,48 +11,81 @@ local inc = { x = function(val) x = x + val return x end, y = function(val) y =
local labels = {}
local fields = {}
-if apiVersion >= 1.040 then
+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" } }
+ 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.043 then
- fields[#fields + 1] = { t = "Dynamic Idle", x = x, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 100, vals = { 50 } }
+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.016 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" } }
+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.040 and apiVersion <= 1.041 then
+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.040 then
+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.043 then
+ 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.042 then
+ 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.041 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.036 then
+if apiVersion >= 1.36 then
labels[#labels + 1] = { t = "Anti Gravity", x = x, y = inc.y(lineSpacing) }
- if apiVersion >= 1.040 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" } }
+ 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
- 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 }
- fields[#fields + 1] = { t = "Threshold", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 20, max = 1000, vals = { 20, 21 } }
end
return {
@@ -73,7 +101,7 @@ return {
self.dynamicIdle = self.values[50]
end,
preSave = function(self)
- self.reboot = self.values[50] ~= self.dynamicIdle
+ 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
index b3e9830f..5102e316 100644
--- a/src/SCRIPTS/BF/PAGES/pids1.lua
+++ b/src/SCRIPTS/BF/PAGES/pids1.lua
@@ -1,9 +1,4 @@
-local template = loadScript(radio.templateHome.."pids1.lua")
-if template then
- template = template()
-else
- template = assert(loadScript(radio.templateHome.."default_template.lua"))()
-end
+local template = assert(loadScript(radio.template))()
local margin = template.margin
local indent = template.indent
local lineSpacing = template.lineSpacing
@@ -16,7 +11,15 @@ local inc = { x = function(val) x = x + val return x end, y = function(val) y =
local labels = {}
local fields = {}
-if apiVersion >= 1.016 then
+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
@@ -29,26 +32,26 @@ if apiVersion >= 1.016 then
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 } }
- fields[#fields + 1] = { x = x, y = inc.y(tableSpacing.row), min = 0, max = 200, vals = { 4 } }
- fields[#fields + 1] = { x = x, y = inc.y(tableSpacing.row), min = 0, max = 200, vals = { 7 } }
+ 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 = 200, vals = { 2 } }
- fields[#fields + 1] = { x = x, y = inc.y(tableSpacing.row), min = 0, max = 200, vals = { 5 } }
- fields[#fields + 1] = { x = x, y = inc.y(tableSpacing.row), min = 0, max = 200, vals = { 8 } }
+ 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 = "D", x = x, y = inc.y(tableSpacing.header) }
- fields[#fields + 1] = { x = x, y = inc.y(tableSpacing.row), min = 0, max = 200, vals = { 3 } }
- fields[#fields + 1] = { x = x, y = inc.y(tableSpacing.row), min = 0, max = 200, vals = { 6 } }
- if apiVersion >= 1.041 then
- fields[#fields + 1] = { x = x, y = inc.y(tableSpacing.row), min = 0, max = 200, vals = { 9 } }
+ 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
diff --git a/src/SCRIPTS/BF/PAGES/pids2.lua b/src/SCRIPTS/BF/PAGES/pids2.lua
index b4c3a68d..5acca134 100644
--- a/src/SCRIPTS/BF/PAGES/pids2.lua
+++ b/src/SCRIPTS/BF/PAGES/pids2.lua
@@ -1,9 +1,4 @@
-local template = loadScript(radio.templateHome.."pids2.lua")
-if template then
- template = template()
-else
- template = assert(loadScript(radio.templateHome.."default_template.lua"))()
-end
+local template = assert(loadScript(radio.template))()
local margin = template.margin
local indent = template.indent
local lineSpacing = template.lineSpacing
@@ -16,7 +11,13 @@ local inc = { x = function(val) x = x + val return x end, y = function(val) y =
local labels = {}
local fields = {}
-if apiVersion >= 1.040 then
+local dMinMax = 100
+
+if apiVersion >= 1.44 then
+ dMinMax = 250
+end
+
+if apiVersion >= 1.40 then
x = margin
y = yMinLim - tableSpacing.header
@@ -33,36 +34,41 @@ if apiVersion >= 1.040 then
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.041 then
+ 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 = 100, vals = { 40 } }
- fields[#fields + 1] = { x = x, y = inc.y(tableSpacing.row), min = 0, max = 100, vals = { 41 } }
- fields[#fields + 1] = { x = x, y = inc.y(tableSpacing.row), min = 0, max = 100, vals = { 42 } }
+ 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.040 then
- labels[#labels + 1] = { t = "Feedforward", x = x, y = inc.y(lineSpacing) }
- fields[#fields + 1] = { t = "Transition", x = x + indent, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 100, vals = { 9 }, scale = 100 }
+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.041 then
+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.021 and apiVersion <= 1.039 then
+if apiVersion >= 1.21 and apiVersion <= 1.39 then
labels[#labels + 1] = { t = "Dterm Setpoint", x = x, y = inc.y(lineSpacing) }
- if apiVersion >= 1.021 and apiVersion <= 1.038 then
+ 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 }
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
index 7cb40a4e..0712d7a5 100644
--- a/src/SCRIPTS/BF/PAGES/pwm.lua
+++ b/src/SCRIPTS/BF/PAGES/pwm.lua
@@ -1,9 +1,4 @@
-local template = loadScript(radio.templateHome.."pwm.lua")
-if template then
- template = template()
-else
- template = assert(loadScript(radio.templateHome.."default_template.lua"))()
-end
+local template = assert(loadScript(radio.template))()
local margin = template.margin
local indent = template.indent
local lineSpacing = template.lineSpacing
@@ -16,44 +11,53 @@ local inc = { x = function(val) x = x + val return x end, y = function(val) y =
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.020 then
+if apiVersion >= 1.20 then
escProtocols[#escProtocols + 1] = "BRSH"
end
-if apiVersion >= 1.031 then
+if apiVersion >= 1.31 then
escProtocols[#escProtocols + 1] = "DS150"
escProtocols[#escProtocols + 1] = "DS300"
escProtocols[#escProtocols + 1] = "DS600"
- if apiVersion < 1.042 then
+ if apiVersion < 1.42 then
escProtocols[#escProtocols + 1] = "DS1200"
end
- if apiVersion >= 1.036 then
+ if apiVersion >= 1.36 then
escProtocols[#escProtocols + 1] = "PS1000"
end
end
-if apiVersion >= 1.043 then
+if apiVersion >= 1.43 then
escProtocols[#escProtocols + 1] = "DISABLED"
end
-if apiVersion >= 1.031 and apiVersion <= 1.040 then
- fields[#fields + 1] = { t = "32kHz Sampling", x = x, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 1, vals = { 9 }, table = { [0] = "OFF", "ON" }, upd = function(self) self.updateRateTables(self) 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.016 then
- if apiVersion <= 1.042 then
- fields[#fields + 1] = { t = "Gyro Update", x = x, y = inc.y(lineSpacing), sp = x + sp, min = 1, max = 32, vals = { 1 }, table = {}, upd = function(self) self.updatePidRateTable(self) end }
- fields[#fields + 1] = { t = "PID Loop", x = x, y = inc.y(lineSpacing), sp = x + sp, min = 1, max = 16, vals = { 2 }, table = {} }
- end
- fields[#fields + 1] = { t = "Protocol", x = x, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = #escProtocols, vals = { 4 }, table = escProtocols }
- fields[#fields + 1] = { t = "Unsynced PWM", x = x, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 1, vals = { 3 }, table = { [0] = "OFF", "ON" } }
- fields[#fields + 1] = { t = "PWM Frequency", x = x, y = inc.y(lineSpacing), sp = x + sp, min = 200, max = 32000, vals = { 5, 6 }, }
+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
-if apiVersion >= 1.031 then
- fields[#fields + 1] = { t = "Idle Throttle %", x = x, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 2000, vals = { 7, 8 }, scale = 100 }
+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
@@ -81,6 +85,7 @@ return {
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)
diff --git a/src/SCRIPTS/BF/PAGES/rates.lua b/src/SCRIPTS/BF/PAGES/rates.lua
index 6f348e6b..a1571237 100644
--- a/src/SCRIPTS/BF/PAGES/rates.lua
+++ b/src/SCRIPTS/BF/PAGES/rates.lua
@@ -1,9 +1,4 @@
-local template = loadScript(radio.templateHome.."rates.lua")
-if template then
- template = template()
-else
- template = assert(loadScript(radio.templateHome.."default_template.lua"))()
-end
+local template = assert(loadScript(radio.template))()
local margin = template.margin
local indent = template.indent
local lineSpacing = template.lineSpacing
@@ -16,7 +11,7 @@ local inc = { x = function(val) x = x + val return x end, y = function(val) y =
local labels = {}
local fields = {}
-if apiVersion >= 1.016 then
+if apiVersion >= 1.16 then
y = yMinLim - tableSpacing.header
labels[#labels + 1] = { t = "", x = x, y = inc.y(tableSpacing.header) }
@@ -30,7 +25,7 @@ if apiVersion >= 1.016 then
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.037 then
+ 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
@@ -53,7 +48,7 @@ if apiVersion >= 1.016 then
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.037 then
+ 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
@@ -66,17 +61,21 @@ if apiVersion >= 1.016 then
inc.y(lineSpacing*0.4)
end
-if apiVersion >= 1.016 then
+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.041 then
+ 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.016 then
+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 } }
@@ -91,4 +90,49 @@ return {
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
index ecc9785a..cdbd21a4 100644
--- a/src/SCRIPTS/BF/PAGES/rescue.lua
+++ b/src/SCRIPTS/BF/PAGES/rescue.lua
@@ -1,9 +1,4 @@
-local template = loadScript(radio.templateHome.."rescue.lua")
-if template then
- template = template()
-else
- template = assert(loadScript(radio.templateHome.."default_template.lua"))()
-end
+local template = assert(loadScript(radio.template))()
local margin = template.margin
local indent = template.indent
local lineSpacing = template.lineSpacing
@@ -16,15 +11,23 @@ local inc = { x = function(val) x = x + val return x end, y = function(val) y =
local labels = {}
local fields = {}
-if apiVersion >= 1.041 then
+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 } }
- fields[#fields + 1] = { t = "Ground Speed", x = x, y = inc.y(lineSpacing), sp = x + sp, min = 30, max = 3000, vals = { 7, 8 } }
- if apiVersion >= 1.043 then
+ 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"} }
@@ -32,6 +35,10 @@ if apiVersion >= 1.041 then
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 {
diff --git a/src/SCRIPTS/BF/PAGES/rx.lua b/src/SCRIPTS/BF/PAGES/rx.lua
index f9939b5e..a78540c2 100644
--- a/src/SCRIPTS/BF/PAGES/rx.lua
+++ b/src/SCRIPTS/BF/PAGES/rx.lua
@@ -1,9 +1,4 @@
-local template = loadScript(radio.templateHome.."rx.lua")
-if template then
- template = template()
-else
- template = assert(loadScript(radio.templateHome.."default_template.lua"))()
-end
+local template = assert(loadScript(radio.template))()
local margin = template.margin
local indent = template.indent
local lineSpacing = template.lineSpacing
@@ -16,20 +11,46 @@ local inc = { x = function(val) x = x + val return x end, y = function(val) y =
local labels = {}
local fields = {}
-if apiVersion >= 1.016 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 } }
+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.020 then
- fields[#fields + 1] = { t = "Interp", 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 = "Interp Int", x = x, y = inc.y(lineSpacing), sp = x + sp, min = 1, max = 50, vals = { 14 } }
+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.031 then
- fields[#fields + 1] = { t = "Cam Angle", x = x, y = inc.y(lineSpacing), sp = x + sp, min = 0, max = 90, vals = { 23 } }
+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 {
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/PAGES/vtx.lua b/src/SCRIPTS/BF/PAGES/vtx.lua
index dc2168d5..7c61da3d 100644
--- a/src/SCRIPTS/BF/PAGES/vtx.lua
+++ b/src/SCRIPTS/BF/PAGES/vtx.lua
@@ -1,22 +1,6 @@
-local md = model.getInfo();
-local vtx_tables = loadScript("/BF/VTX/"..md.name..".lua")
-if vtx_tables then
- vtx_tables = vtx_tables()
-else
- vtx_tables = assert(loadScript("/BF/VTX/vtx_defaults.lua"))()
-end
-local deviceTable = { [1]="6705", [3]="SA", [4]="Tramp", [255]="None" }
-local pitModeTable = { [0]="OFF", "ON" }
-local template = loadScript(radio.templateHome.."vtx.lua")
-if template then
- template = template()
-else
- template = assert(loadScript(radio.templateHome.."default_template.lua"))()
-end
+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
@@ -25,7 +9,16 @@ local inc = { x = function(val) x = x + val return x end, y = function(val) y =
local labels = {}
local fields = {}
-if apiVersion >= 1.036 then
+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 }
@@ -33,9 +26,9 @@ if apiVersion >= 1.036 then
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.037 then
+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.036 then
+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
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/default_template.lua b/src/SCRIPTS/BF/TEMPLATES/128x64.lua
similarity index 100%
rename from src/SCRIPTS/BF/TEMPLATES/128x64/default_template.lua
rename to src/SCRIPTS/BF/TEMPLATES/128x64.lua
diff --git a/src/SCRIPTS/BF/TEMPLATES/212x64/default_template.lua b/src/SCRIPTS/BF/TEMPLATES/128x96.lua
similarity index 100%
rename from src/SCRIPTS/BF/TEMPLATES/212x64/default_template.lua
rename to src/SCRIPTS/BF/TEMPLATES/128x96.lua
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/default_template.lua b/src/SCRIPTS/BF/TEMPLATES/320x480.lua
similarity index 100%
rename from src/SCRIPTS/BF/TEMPLATES/320x480/default_template.lua
rename to src/SCRIPTS/BF/TEMPLATES/320x480.lua
diff --git a/src/SCRIPTS/BF/TEMPLATES/480x272/default_template.lua b/src/SCRIPTS/BF/TEMPLATES/480x272.lua
similarity index 100%
rename from src/SCRIPTS/BF/TEMPLATES/480x272/default_template.lua
rename to src/SCRIPTS/BF/TEMPLATES/480x272.lua
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/BF/VTX/vtx_defaults.lua b/src/SCRIPTS/BF/VTX_TABLES/vtx_defaults.lua
similarity index 100%
rename from src/BF/VTX/vtx_defaults.lua
rename to src/SCRIPTS/BF/VTX_TABLES/vtx_defaults.lua
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 203be3e7..a0086f58 100644
--- a/src/SCRIPTS/BF/background.lua
+++ b/src/SCRIPTS/BF/background.lua
@@ -1,58 +1,41 @@
-local sensorId = -1
-local dataInitialised = false
-local data_init = nil
+local apiVersionReceived = false
+local timeIsSet = false
+local getApiVersion, setRtc, rssiTask
local rssiEnabled = true
-local rssiTask = nil
-
-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 run_bg()
- local sensorValue = getSensorValue()
- if modelActive(sensorValue) then
+ 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 dataInitialised then
- if not data_init then
- data_init = assert(loadScript("data_init.lua"))()
- end
-
- dataInitialised = data_init()
-
- if dataInitialised then
- data_init = nil
-
+ if not apiVersionReceived then
+ getApiVersion = getApiVersion or assert(loadScript("api_version.lua"))()
+ apiVersionReceived = getApiVersion.f()
+ if apiVersionReceived then
+ getApiVersion = nil
collectgarbage()
end
- elseif rssiEnabled and apiVersion >= 1.037 then
- if not rssiTask then
- rssiTask = assert(loadScript("rssi.lua"))()
+ 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
end
else
- dataInitialised = false
+ apiVersionReceived = false
+ timeIsSet = false
rssiEnabled = true
- if data_init or rssiTask then
- data_init = nil
+ if getApiVersion or setRtc or rssiTask then
+ getApiVersion = nil
+ setRtc = nil
rssiTask = nil
collectgarbage()
end
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/data_init.lua b/src/SCRIPTS/BF/data_init.lua
deleted file mode 100644
index ae4da07f..00000000
--- a/src/SCRIPTS/BF/data_init.lua
+++ /dev/null
@@ -1,66 +0,0 @@
-local MSP_API_VERSION = 1
-local MSP_SET_RTC = 246
-
-local apiVersionReceived = false
-local timeIsSet = false
-local lastRunTS = 0
-local INTERVAL = 50
-
-local function processMspReply(cmd,rx_buf)
- if cmd == MSP_API_VERSION and #rx_buf >= 3 then
- apiVersion = rx_buf[2] + rx_buf[3] / 1000
-
- apiVersionReceived = true
- end
- if cmd == MSP_SET_RTC then
- timeIsSet = true
- end
-end
-
-local function init()
- if lastRunTS == 0 or lastRunTS + INTERVAL < getTime() then
- if not apiVersionReceived then
- protocol.mspRead(MSP_API_VERSION)
- elseif apiVersionReceived and not timeIsSet 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.041 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)
- end
- lastRunTS = getTime()
- end
-
- mspProcessTxQ()
-
- processMspReply(mspPollReply())
-
- return apiVersionReceived and timeIsSet
-end
-
-return init
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
index 2fcdf6f8..4deddf51 100644
--- a/src/SCRIPTS/BF/pages.lua
+++ b/src/SCRIPTS/BF/pages.lua
@@ -1,47 +1,71 @@
local PageFiles = {}
-if apiVersion >= 1.036 then
- PageFiles[#PageFiles + 1] = { title = "VTX Settings", script = "vtx.lua" }
+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.016 then
+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.021 then
+if apiVersion >= 1.21 then
PageFiles[#PageFiles + 1] = { title = "PIDs 2", script = "pids2.lua" }
end
-if apiVersion >= 1.016 then
+if apiVersion >= 1.16 then
PageFiles[#PageFiles + 1] = { title = "Rates", script = "rates.lua" }
end
-if apiVersion >= 1.016 then
+if apiVersion >= 1.16 then
PageFiles[#PageFiles + 1] = { title = "Advanced PIDs", script = "pid_advanced.lua" }
end
-if apiVersion >= 1.016 then
+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.042 then
+if apiVersion >= 1.42 then
PageFiles[#PageFiles + 1] = { title = "Filters 2", script = "filters2.lua" }
end
-if apiVersion >= 1.016 then
- PageFiles[#PageFiles + 1] = { title = "Gyro / Motor", script = "pwm.lua" }
+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.016 then
+if apiVersion >= 1.16 then
PageFiles[#PageFiles + 1] = { title = "Receiver", script = "rx.lua" }
end
-if apiVersion >= 1.041 then
+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.041 then
+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 d0c1951d..80348218 100644
--- a/src/SCRIPTS/BF/protocols.lua
+++ b/src/SCRIPTS/BF/protocols.lua
@@ -2,25 +2,34 @@ local supportedProtocols =
{
smartPort =
{
- transport = "MSP/sp.lua",
- rssi = function() return getValue("RSSI") end,
- stateSensor = "Tmp1",
+ mspTransport = "MSP/sp.lua",
push = sportTelemetryPush,
maxTxBufferSize = 6,
maxRxBufferSize = 6,
saveMaxRetries = 2,
- saveTimeout = 500
+ saveTimeout = 500,
+ cms = {},
},
crsf =
{
- transport = "MSP/crsf.lua",
- rssi = function() return getValue("TQly") 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 = {},
}
}
@@ -29,6 +38,8 @@ local function getProtocol()
return supportedProtocols.smartPort
elseif supportedProtocols.crsf.push() ~= nil then
return supportedProtocols.crsf
+ elseif supportedProtocols.ghst.push() ~= nil then
+ return supportedProtocols.ghst
end
end
diff --git a/src/SCRIPTS/BF/radios.lua b/src/SCRIPTS/BF/radios.lua
index 6f200e4c..b6d5e22a 100644
--- a/src/SCRIPTS/BF/radios.lua
+++ b/src/SCRIPTS/BF/radios.lua
@@ -2,45 +2,154 @@ local supportedRadios =
{
["128x64"] =
{
- templateHome = "TEMPLATES/128x64/",
- 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,
+ 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,
+ },
+ },
+ },
+ ["128x96"] =
+ {
+ 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,
+ },
+ },
},
["212x64"] =
{
- templateHome = "TEMPLATES/212x64/",
- 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,
+ 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"] =
{
- templateHome = "TEMPLATES/480x272/",
- 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,
+ 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"] =
+ ["320x480"] =
{
- templateHome = "TEMPLATES/320x480/",
- 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,
+ 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,
},
}
diff --git a/src/SCRIPTS/BF/rssi.lua b/src/SCRIPTS/BF/rssi.lua
index 401e7103..dc31dd03 100644
--- a/src/SCRIPTS/BF/rssi.lua
+++ b/src/SCRIPTS/BF/rssi.lua
@@ -9,8 +9,8 @@ local rssiSource = RSSI_SOURCE_NONE
local lastRunTS = 0
local INTERVAL = 50
-local function processMspReply(cmd,rx_buf)
- if cmd == MSP_TX_INFO and #rx_buf >= 1 then
+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
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 c65dfd09..df45bba1 100644
--- a/src/SCRIPTS/BF/ui.lua
+++ b/src/SCRIPTS/BF/ui.lua
@@ -1,25 +1,26 @@
local uiStatus =
{
init = 1,
- pages = 2,
- mainMenu = 3,
+ mainMenu = 2,
+ pages = 3,
+ confirm = 4,
}
local pageStatus =
{
- display = 2,
- editing = 3,
- saving = 4,
- popupMenu = 5,
+ display = 1,
+ editing = 2,
+ saving = 3,
}
local uiMsp =
{
reboot = 68,
- eepromWrite = 250
+ eepromWrite = 250,
}
local uiState = uiStatus.init
+local prevUiState
local pageState = pageStatus.display
local requestTimeout = 80
local currentPage = 1
@@ -32,7 +33,7 @@ local popupMenuActive = 1
local killEnterBreak = 0
local pageScrollY = 0
local mainMenuScrollY = 0
-local PageFiles, Page, init, popupMenuList
+local PageFiles, Page, init, popupMenu
local backgroundFill = TEXT_BGCOLOR or ERASE
local foregroundColor = LINE_COLOR or SOLID
@@ -72,26 +73,33 @@ local function eepromWrite()
protocol.mspRead(uiMsp.eepromWrite)
end
-local function getVtxTables()
- uiState = uiStatus.init
- PageFiles = nil
+local function confirm(page)
+ prevUiState = uiState
+ uiState = uiStatus.confirm
invalidatePages()
- io.close(io.open("/BF/VTX/"..model.getInfo().name..".lua", 'w'))
- return 0
+ currentField = 1
+ Page = assert(loadScript(page))()
+ collectgarbage()
end
local function createPopupMenu()
- popupMenuList = {
- { t = "save page", f = saveSettings },
- { t = "reload", f = invalidatePages },
- { t = "reboot", f = rebootFc },
- }
- if apiVersion >= 1.042 then
- popupMenuList[#popupMenuList + 1] = { t = "vtx tables", f = getVtxTables }
+ 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
end
-local function processMspReply(cmd,rx_buf)
+local function processMspReply(cmd,rx_buf,err)
if not Page or not rx_buf then
elseif cmd == Page.write then
if Page.eepromWrite then
@@ -104,6 +112,9 @@ local function processMspReply(cmd,rx_buf)
rebootFc()
end
invalidatePages()
+ 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
@@ -116,6 +127,10 @@ local function processMspReply(cmd,rx_buf)
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
@@ -154,7 +169,7 @@ local function incMainMenu(inc)
end
local function incPopupMenu(inc)
- popupMenuActive = clipValue(popupMenuActive + inc, 1, #popupMenuList)
+ popupMenuActive = clipValue(popupMenuActive + inc, 1, #popupMenu)
end
local function requestPage()
@@ -169,7 +184,7 @@ local function drawScreenTitle(screenTitle)
lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR)
lcd.drawText(5,5,screenTitle, MENU_TITLE_COLOR)
else
- lcd.drawFilledRectangle(0, 0, LCD_W, 10)
+ lcd.drawFilledRectangle(0, 0, LCD_W, 10, FORCE)
lcd.drawText(1,1,screenTitle,INVERS)
end
end
@@ -179,7 +194,6 @@ local function drawScreen()
local yMaxLim = radio.yMaxLimit
local currentFieldY = Page.fields[currentField].y
local textOptions = radio.textSize + globalTextOptions
- drawScreenTitle("Betaflight / "..Page.title)
if currentFieldY <= Page.fields[1].y then
pageScrollY = 0
elseif currentFieldY - pageScrollY <= yMinLim then
@@ -190,7 +204,7 @@ local function drawScreen()
for i=1,#Page.labels do
local f = Page.labels[i]
local y = f.y - pageScrollY
- if y >= yMinLim and y <= yMaxLim then
+ if y >= 0 and y <= LCD_H then
lcd.drawText(f.x, y, f.t, textOptions)
end
end
@@ -214,13 +228,14 @@ local function drawScreen()
end
end
local y = f.y - pageScrollY
- if y >= yMinLim and y <= yMaxLim then
+ 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
+ drawScreenTitle("Betaflight / "..Page.title)
end
local function incValue(inc)
@@ -243,13 +258,13 @@ local function drawPopupMenu()
local w = radio.MenuBox.w
local h_line = radio.MenuBox.h_line
local h_offset = radio.MenuBox.h_offset
- local h = #popupMenuList * h_line + h_offset*2
+ 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(popupMenuList) do
+ for i,e in ipairs(popupMenu) do
local textOptions = globalTextOptions
if popupMenuActive == i then
textOptions = textOptions + INVERS
@@ -259,18 +274,35 @@ local function drawPopupMenu()
end
local function run_ui(event)
- if uiState == uiStatus.init then
+ 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
+ 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"))()
- if not init() then
+ lcd.drawText(6, radio.yMinLimit, init.t)
+ if not init.f() then
return 0
end
init = nil
- createPopupMenu()
PageFiles = assert(loadScript("pages.lua"))()
invalidatePages()
- uiState = uiStatus.mainMenu
+ uiState = prevUiState or uiStatus.mainMenu
+ prevUiState = nil
elseif uiState == uiStatus.mainMenu then
if event == EVT_VIRTUAL_EXIT then
return 2
@@ -280,9 +312,11 @@ local function run_ui(event)
incMainMenu(-1)
elseif event == EVT_VIRTUAL_ENTER then
uiState = uiStatus.pages
+ elseif event == EVT_VIRTUAL_ENTER_LONG then
+ killEnterBreak = 1
+ createPopupMenu()
end
lcd.clear()
- drawScreenTitle("Betaflight Config")
local yMinLim = radio.yMinLimit
local yMaxLim = radio.yMaxLimit
local lineSpacing = 10
@@ -300,10 +334,11 @@ local function run_ui(event)
for i=1, #PageFiles do
local attr = currentPage == i and INVERS or 0
local y = (i-1)*lineSpacing + yMinLim - mainMenuScrollY
- if y >= yMinLim and y <= yMaxLim then
+ 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
@@ -314,21 +349,6 @@ local function run_ui(event)
invalidatePages()
end
end
- elseif pageState == pageStatus.popupMenu then
- if event == EVT_VIRTUAL_EXIT then
- pageState = pageStatus.display
- 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
- pageState = pageStatus.display
- return popupMenuList[popupMenuActive].f() or 0
- end
- end
elseif pageState == pageStatus.display then
if event == EVT_VIRTUAL_PREV_PAGE then
incPage(-1)
@@ -347,9 +367,8 @@ local function run_ui(event)
end
end
elseif event == EVT_VIRTUAL_ENTER_LONG then
- popupMenuActive = 1
killEnterBreak = 1
- pageState = pageStatus.popupMenu
+ createPopupMenu()
elseif event == EVT_VIRTUAL_EXIT then
invalidatePages()
currentField = 1
@@ -358,6 +377,9 @@ local function run_ui(event)
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)
@@ -366,17 +388,30 @@ local function run_ui(event)
end
end
if not Page then
- Page = assert(loadScript("Pages/"..PageFiles[currentPage].script))()
- collectgarbage()
+ 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
+ selectPage(selectedPage.script)
+ end
end
if not Page.values and pageState == pageStatus.display then
requestPage()
end
lcd.clear()
drawScreen()
- if pageState == pageStatus.popupMenu then
- drawPopupMenu()
- elseif pageState == pageStatus.saving then
+ if pageState == pageStatus.saving then
local saveMsg = "Saving..."
if saveRetries > 0 then
saveMsg = "Retrying"
@@ -385,8 +420,20 @@ local function run_ui(event)
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
+ 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 protocol.rssi() == 0 then
+ if getRSSI() == 0 then
lcd.drawText(radio.NoTelem[1],radio.NoTelem[2],radio.NoTelem[3],radio.NoTelem[4])
end
mspProcessTxQ()
diff --git a/src/SCRIPTS/BF/ui_init.lua b/src/SCRIPTS/BF/ui_init.lua
index 8686b5dc..c00f0351 100644
--- a/src/SCRIPTS/BF/ui_init.lua
+++ b/src/SCRIPTS/BF/ui_init.lua
@@ -1,35 +1,42 @@
local apiVersionReceived = false
-local vtxTablesReceived = false
-local data_init, getVtxTables
-local vtxTables = loadScript("/BF/VTX/"..model.getInfo().name..".lua")
-
-if vtxTables and vtxTables() then
- vtxTablesReceived = true
- vtxTables = nil
- collectgarbage()
-end
+local mcuIdReceived = false
+local featuresReceived = false
+local getApiVersion, getMCUId, getFeaturesInfo
+local returnTable = { f = nil, t = "" }
local function init()
- if apiVersion == 0 then
- lcd.drawText(6, radio.yMinLimit, "Initialising")
- data_init = data_init or assert(loadScript("data_init.lua"))()
- data_init()
- elseif apiVersion > 0 and not apiVersionReceived then
- data_init = nil
- apiVersionReceived = true
- collectgarbage()
- elseif apiVersion >= 1.042 and not vtxTablesReceived then
- lcd.drawText(6, radio.yMinLimit, "Downloading VTX Tables")
- getVtxTables = getVtxTables or assert(loadScript("vtx_tables.lua"))()
- vtxTablesReceived = getVtxTables()
- if vtxTablesReceived then
- getVtxTables = nil
+ 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 vtxTablesReceived
+ return apiVersionReceived and mcuId and featuresReceived
end
-return init
+returnTable.f = init
+
+return returnTable
diff --git a/src/SCRIPTS/BF/vtx_tables.lua b/src/SCRIPTS/BF/vtx_tables.lua
index 83ca15ea..13f05265 100644
--- a/src/SCRIPTS/BF/vtx_tables.lua
+++ b/src/SCRIPTS/BF/vtx_tables.lua
@@ -11,17 +11,30 @@ local requestedBand = 1
local requestedPowerLevel = 1
local vtxTableConfig = {}
local frequencyTable = {}
-local frequenciesPerBand = 0
local bandTable = {}
local powerTable = {}
local lastRunTS = 0
local INTERVAL = 100
-local function processMspReply(cmd, payload)
+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]
@@ -82,7 +95,7 @@ local function getVtxTables()
end
end
if vtxTablesReceived then
- local f = io.open("/BF/VTX/"..model.getInfo().name..".lua", 'w')
+ local f = io.open("VTX_TABLES/"..mcuId..".lua", 'w')
io.write(f, "return {", "\n")
io.write(f, " frequencyTable = {", "\n")
for i = 1, #frequencyTable do
@@ -109,11 +122,11 @@ local function getVtxTables()
io.write(f, powerString, "\n")
io.write(f, "}", "\n")
io.close(f)
- assert(loadScript("/BF/VTX/"..model.getInfo().name..".lua", 'c'))
+ assert(loadScript("VTX_TABLES/"..mcuId..".lua", 'c'))
end
mspProcessTxQ()
processMspReply(mspPollReply())
return vtxTablesReceived
end
-return getVtxTables
+return { f = getVtxTables, t = "Downloading VTX tables" }
diff --git a/src/SCRIPTS/FUNCTIONS/bfbkgd.lua b/src/SCRIPTS/FUNCTIONS/bfbkgd.lua
index fcaec519..137000ba 100644
--- a/src/SCRIPTS/FUNCTIONS/bfbkgd.lua
+++ b/src/SCRIPTS/FUNCTIONS/bfbkgd.lua
@@ -1,7 +1,7 @@
chdir("/SCRIPTS/BF")
apiVersion = 0
protocol = assert(loadScript("protocols.lua"))()
-assert(loadScript(protocol.transport))()
+assert(loadScript(protocol.mspTransport))()
assert(loadScript("MSP/common.lua"))()
local background = assert(loadScript("background.lua"))()
diff --git a/src/SCRIPTS/FUNCTIONS/pids.lua b/src/SCRIPTS/FUNCTIONS/bfpids.lua
similarity index 100%
rename from src/SCRIPTS/FUNCTIONS/pids.lua
rename to src/SCRIPTS/FUNCTIONS/bfpids.lua
diff --git a/src/SCRIPTS/TELEMETRY/bf.lua b/src/SCRIPTS/TELEMETRY/bf.lua
deleted file mode 100644
index 3b931cfd..00000000
--- a/src/SCRIPTS/TELEMETRY/bf.lua
+++ /dev/null
@@ -1,6 +0,0 @@
-local function run(event)
- lcd.clear()
- lcd.drawText(2, 2, "Use TOOLS menu instead of this")
-end
-
-return { run=run }
diff --git a/src/SCRIPTS/TOOLS/bf.lua b/src/SCRIPTS/TOOLS/bf.lua
index af3d420b..2b42f18b 100644
--- a/src/SCRIPTS/TOOLS/bf.lua
+++ b/src/SCRIPTS/TOOLS/bf.lua
@@ -2,15 +2,17 @@ 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"))()
- assert(loadScript(protocol.transport))()
+ 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"))()
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