Sync inav to Gitea
Make sure docs are updated / settings_md (push) Canceled after 0s
Build firmware / test (push) Canceled after 0s
Build firmware / build-SITL-Windows (push) Canceled after 0s
Build firmware / build-SITL-Mac (push) Canceled after 0s
Build firmware / build-SITL-Linux (push) Canceled after 0s
Build firmware / build-SITL-Linux-arm64 (push) Canceled after 0s
Build firmware / upload-artifacts (push) Canceled after 0s
Build firmware / build-single-target (push) Canceled after 0s
Build firmware / build (9) (push) Canceled after 0s
Build firmware / build (8) (push) Canceled after 0s
Build firmware / build (7) (push) Canceled after 0s
Build firmware / build (6) (push) Canceled after 0s
Build firmware / build (5) (push) Canceled after 0s
Build firmware / build (4) (push) Canceled after 0s
Build firmware / build (3) (push) Canceled after 0s
Build firmware / build (2) (push) Canceled after 0s
Build firmware / build (14) (push) Canceled after 0s
Build firmware / build (13) (push) Canceled after 0s
Build firmware / build (12) (push) Canceled after 0s
Build firmware / build (11) (push) Canceled after 0s
Build firmware / build (10) (push) Canceled after 0s
Build firmware / build (1) (push) Canceled after 0s
Build firmware / build (0) (push) Canceled after 0s
Build firmware / detect (push) Canceled after 0s
Build pre-release / build (push) Canceled after 0s
Build pre-release / Release (push) Canceled after 0s

This commit is contained in:
2026-08-03 16:37:40 +08:00
commit dac37fd077
14095 changed files with 5603119 additions and 0 deletions
+5
View File
@@ -0,0 +1,5 @@
;;; Directory Local Variables -*- no-byte-compile: t -*-
;;; For more information see (info "(emacs) Directory Variables")
((nil . ((c-basic-offset . 4)
(c-default-style . "k&r"))))
+7
View File
@@ -0,0 +1,7 @@
.git/
.vagrant/
.vscode/
/build/
/obj/
/tools/
/downloads/
+13
View File
@@ -0,0 +1,13 @@
*.md text
*.c text
*.h text
*.cc text
*.S text
*.s text
*.hex -crlf -diff
*.elf -crlf -diff
*.ld text
Makefile text
*.bat eol=crlf
*.txt text
*.sh text eol=lf
+49
View File
@@ -0,0 +1,49 @@
---
name: "\U0001F41B Bug report"
about: Report an issue to help make INAV better
title: ''
labels: ''
assignees: ''
---
**PLEASE MAKE SURE YOU READ AND UNDERSTAND THE SOCIAL MEDIA SUPPORT CHANNELS. QUESTIONS ABOUT FLASHING, CONFIGURING, PILOTING MAY BE CLOSED WITHOUT FURTHER INTERACTION.**
* [INAV Discord Server](https://discord.gg/peg2hhbYwN)
* [INAV Official on Facebook](https://www.facebook.com/groups/INAVOfficial)
* [INAV Official on Telegram](https://t.me/INAVFlight)
**Please double-check that nobody reported the issue before by using search in this bug tracker.**
**For Bug-Reports, please use the following template and provide as much information as possible. Bug-Reports that don't follow the template, might be closed unanswered. If you are not sure if you found a bug, ask for further input in the community channels or open a Github discussion.**
**PLEASE DELETE THE TEXT ABOVE AFTER READING AND UNDERSTANDING IT**
****
## Current Behavior
<!-- If applicable, add screenshots, videos and blackbox logs to help explain your problem. -->
## Steps to Reproduce
<!-- Steps to reproduce the behavior: -->
1.
2.
3.
4.
## Expected behavior
<!-- A clear and concise description of what you expected to happen. -->
## Suggested solution(s)
<!-- How could we solve this issue? What changes would need to made to INAV? -->
## Additional context
<!-- Add any other context about the problem here. -->
<!-- Go to CLI, execute `diff` command copy its output to [PasteBin](https://pastebin.com) and provide a link to a paste here -->
---
<!-- PLEASE FILL THIS OUT -->
<!-- Use CLI 'version' command to get version string -->
- FC Board name and vendor:
- INAV version string:
+24
View File
@@ -0,0 +1,24 @@
---
name: "\U0001F680Feature request"
about: Suggest a new feature for INAV
title: ''
labels: ''
assignees: ''
---
## Current Behavior
<!-- A clear and concise description of what is the current behavior / usecase. -->
## Desired Behavior
<!-- A clear and concise description of what you want to happen. -->
## Suggested Solution
<!-- Suggest a solution that the community/maintainers/you may take to enable the desired behavior -->
<!-- NOTE: Feature Requests without suggested solutions may not be addressed with the same level of urgency as those that have suggested solutions -->
## Who does this impact? Who is this for?
<!-- Who is this for? All users? Airplane users? Beginners? Advanced? Yourself? People using X, Y, Z, etc.? -->
## Additional context
<!-- Add any other context or links about the feature request here. -->
@@ -0,0 +1,38 @@
This pull requests adds support for ``$TARGET_NAME``
* [ ] Target complies with ``docs/policies/NEW_HARDWARE_POLICY.md``
The following items have been checked and confirmed working by an INAV developer on actual hardware: (feel free to remove non-relevant items)
* [ ] Samples received
* [ ] Flash firmware
* [ ] Calibrate
* [ ] Orientation matches
* [ ] Gyro working
* [ ] Accel working
* [ ] Voltage correct
* [ ] Current correct
* [ ] Baro working
* [ ] Mag I2C Bus
* [ ] Additional I2C2 Buses (Airspeed/other accessories)
* [ ] UART1
* [ ] UART2
* [ ] UART3
* [ ] UART4
* [ ] UART5
* [ ] UART6
* [ ] UART7
* [ ] UART8
* [ ] Analog Camera working
* [ ] Video Out working
* [ ] OSD working
* [ ] LEDs working
* [ ] Buzzer working
* [ ] Motor outputs
* [ ] DShot support on m1-4
* [ ] Servo outputs
* [ ] Blackbox
* [ ] PINIO1
* [ ] PINIO2
* [ ] PINIO3
* [ ] PINIO4
+4
View File
@@ -0,0 +1,4 @@
label-alias:
bug: 'BUG'
feature_request: 'Feature request'
question: 'Support'
+12
View File
@@ -0,0 +1,12 @@
# Configuration for probot-no-response - https://github.com/probot/no-response
# Number of days of inactivity before an Issue is closed for lack of response
daysUntilClose: 3
# Label requiring a response
responseRequiredLabel: Missing Information
# Comment to post when closing an Issue for lack of response. Set to `false` to disable
closeComment: >
This issue has been automatically closed because the information we asked
to be provided when opening it was not supplied by the original author.
With only the information that is currently in the issue, we don't have
enough information to take action.
+226
View File
@@ -0,0 +1,226 @@
#!/bin/bash
#
# Check if parameter group struct modifications include version increments
# This prevents settings corruption when struct layout changes without version bump
#
# Exit codes:
# 0 - No issues found
# 1 - Potential issues detected (will post comment)
# 2 - Script error
set -euo pipefail
# Output file for issues found
ISSUES_FILE=$(mktemp)
trap "rm -f $ISSUES_FILE" EXIT
# Color output for local testing
if [ -t 1 ]; then
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
else
RED=''
GREEN=''
YELLOW=''
NC=''
fi
echo "🔍 Checking for Parameter Group version updates..."
# Get base and head commits
BASE_REF=${GITHUB_BASE_REF:-}
HEAD_REF=${GITHUB_HEAD_REF:-}
if [ -z "$BASE_REF" ] || [ -z "$HEAD_REF" ]; then
echo "⚠️ Warning: Not running in GitHub Actions PR context"
echo "Using git diff against HEAD~1 for local testing"
BASE_COMMIT="HEAD~1"
HEAD_COMMIT="HEAD"
else
BASE_COMMIT="origin/$BASE_REF"
HEAD_COMMIT="HEAD"
fi
# Get list of changed files
CHANGED_FILES=$(git diff --name-only $BASE_COMMIT..$HEAD_COMMIT | grep -E '\.(c|h)$' || true)
if [ -z "$CHANGED_FILES" ]; then
echo "✅ No C/H files changed"
exit 0
fi
echo "📁 Changed files:"
echo "$CHANGED_FILES" | sed 's/^/ /'
# Function to extract PG info from a file
check_file_for_pg_changes() {
local file=$1
local diff_output=$(git diff $BASE_COMMIT..$HEAD_COMMIT -- "$file")
# Check if file contains PG_REGISTER in current version
if ! git show $HEAD_COMMIT:"$file" 2>/dev/null | grep -q "PG_REGISTER"; then
return 0
fi
echo " 🔎 Checking $file (contains PG_REGISTER)"
# Extract all PG_REGISTER lines from the diff (both old and new)
local pg_registers=$(echo "$diff_output" | grep -E "^[-+].*PG_REGISTER" || true)
if [ -z "$pg_registers" ]; then
# PG_REGISTER exists but wasn't changed
# Still need to check if the struct changed
pg_registers=$(git show $HEAD_COMMIT:"$file" | grep "PG_REGISTER" || true)
fi
# Process each PG registration
while IFS= read -r pg_line; do
[ -z "$pg_line" ] && continue
# Extract struct name and version
# Pattern: PG_REGISTER.*\((\w+),\s*(\w+),\s*PG_\w+,\s*(\d+)\)
if [[ $pg_line =~ PG_REGISTER[^(]*\(([^,]+),([^,]+),([^,]+),([^)]+)\) ]]; then
local struct_type="${BASH_REMATCH[1]}"
local pg_name="${BASH_REMATCH[2]}"
local pg_id="${BASH_REMATCH[3]}"
local version="${BASH_REMATCH[4]}"
# Clean up whitespace
struct_type=$(echo "$struct_type" | xargs)
version=$(echo "$version" | xargs)
echo " 📋 Found: $struct_type (version $version)"
# Check if this struct's typedef was modified in ANY changed file
local struct_pattern="typedef struct ${struct_type%_t}_s"
local struct_body_diff=""
local struct_found_in=""
# Search all changed files for this struct definition
while IFS= read -r changed_file; do
[ -z "$changed_file" ] && continue
local file_diff=$(git diff $BASE_COMMIT..$HEAD_COMMIT -- "$changed_file")
local struct_in_file=$(echo "$file_diff" | sed -n "/${struct_pattern}/,/\}.*${struct_type};/p")
if [ -n "$struct_in_file" ]; then
struct_body_diff="$struct_in_file"
struct_found_in="$changed_file"
echo " 🔍 Found struct definition in $changed_file"
break
fi
done <<< "$CHANGED_FILES"
local struct_changes=$(echo "$struct_body_diff" | grep -E "^[-+]" \
| grep -v -E "^[-+]\s*(typedef struct|}|//|\*)" \
| sed -E 's://.*$::' \
| sed -E 's:/\*.*\*/::' \
| tr -d '[:space:]')
if [ -n "$struct_changes" ]; then
echo " ⚠️ Struct definition modified in $struct_found_in"
# Check if version was incremented in PG_REGISTER
local old_version=$(echo "$diff_output" | grep "^-.*PG_REGISTER.*$struct_type" | grep -oP ',\s*\K\d+(?=\s*\))' || echo "")
local new_version=$(echo "$diff_output" | grep "^+.*PG_REGISTER.*$struct_type" | grep -oP ',\s*\K\d+(?=\s*\))' || echo "")
# Find line number of PG_REGISTER for error reporting
local line_num=$(git show $HEAD_COMMIT:"$file" | grep -n "PG_REGISTER.*$struct_type" | cut -d: -f1 | head -1)
if [ -n "$old_version" ] && [ -n "$new_version" ]; then
# PG_REGISTER was modified - check if version increased
if [ "$new_version" -le "$old_version" ]; then
echo " ❌ Version NOT incremented ($old_version$new_version)"
cat >> $ISSUES_FILE << EOF
### \`$struct_type\` ($file:$line_num)
- **Struct modified:** Field changes detected in $struct_found_in
- **Version status:** ❌ Not incremented (version $version)
- **Recommendation:** Increment version from $old_version to $(($old_version + 1))
EOF
else
echo " ✅ Version incremented ($old_version$new_version)"
fi
elif [ -z "$old_version" ] && [ -z "$new_version" ]; then
# PG_REGISTER wasn't modified but struct was - THIS IS THE BUG!
echo " ❌ PG_REGISTER not modified, version still $version"
cat >> $ISSUES_FILE << EOF
### \`$struct_type\` ($file:$line_num)
- **Struct modified:** Field changes detected in $struct_found_in
- **Version status:** ❌ Not incremented (still version $version)
- **Recommendation:** Increment version to $(($version + 1)) in $file
EOF
else
# One exists but not the other - unusual edge case
echo " ⚠️ Unusual version change pattern detected"
cat >> $ISSUES_FILE << EOF
### \`$struct_type\` ($file:$line_num)
- **Struct modified:** Field changes detected in $struct_found_in
- **Version status:** ⚠️ Unusual change pattern (old: ${old_version:-none}, new: ${new_version:-none})
- **Current version:** $version
- **Recommendation:** Manually verify version increment
EOF
fi
else
echo " ✅ Struct unchanged"
fi
fi
done <<< "$pg_registers"
}
# Build list of files to check (changed files + companions with PG_REGISTER)
echo "🔍 Building file list including companions with PG_REGISTER..."
FILES_TO_CHECK=""
ALREADY_ADDED=""
while IFS= read -r file; do
[ -z "$file" ] && continue
# Add this file to check list
if ! echo "$ALREADY_ADDED" | grep -qw "$file"; then
FILES_TO_CHECK="$FILES_TO_CHECK$file"$'\n'
ALREADY_ADDED="$ALREADY_ADDED $file"
fi
# Determine companion file (.c <-> .h)
local companion=""
if [[ "$file" == *.c ]]; then
companion="${file%.c}.h"
elif [[ "$file" == *.h ]]; then
companion="${file%.h}.c"
fi
# If companion exists and contains PG_REGISTER, add it to check list
if [ -n "$companion" ]; then
if git show $HEAD_COMMIT:"$companion" 2>/dev/null | grep -q "PG_REGISTER"; then
if ! echo "$ALREADY_ADDED" | grep -qw "$companion"; then
echo " 📎 Adding $companion (companion of $file with PG_REGISTER)"
FILES_TO_CHECK="$FILES_TO_CHECK$companion"$'\n'
ALREADY_ADDED="$ALREADY_ADDED $companion"
fi
fi
fi
done <<< "$CHANGED_FILES"
# Check each file (including companions)
while IFS= read -r file; do
[ -z "$file" ] && continue
check_file_for_pg_changes "$file"
done <<< "$FILES_TO_CHECK"
# Check if any issues were found
if [ -s $ISSUES_FILE ]; then
echo ""
echo "${YELLOW}⚠️ Potential PG version issues detected${NC}"
echo "Output saved to: $ISSUES_FILE"
cat $ISSUES_FILE
exit 1
else
echo ""
echo "${GREEN}✅ No PG version issues detected${NC}"
exit 0
fi
+58
View File
@@ -0,0 +1,58 @@
# Configuration for probot-stale - https://github.com/probot/stale
# Number of days of inactivity before an Issue or Pull Request becomes stale
daysUntilStale: 60
# 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: 14
# 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 any activity in 60 days. The resources of the INAV team are limited,
and so we are asking for your help.
This issue / pull request will be closed if no further activity occurs within two weeks.
# 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
+127
View File
@@ -0,0 +1,127 @@
# GitHub Actions Workflows
This directory contains automated CI/CD workflows for the INAV project.
## Active Workflows
### Build and Test
#### `ci.yml` - Build Firmware
**Triggers:** Pull requests, pushes to maintenance branches
**Purpose:** Compiles INAV firmware for all targets to verify builds succeed
**Matrix:** 15 parallel build jobs for faster CI
#### `nightly-build.yml` - Nightly Builds
**Triggers:** Scheduled nightly
**Purpose:** Creates nightly development builds for testing
### Documentation
#### `docs.yml` - Documentation Build
**Triggers:** Pull requests affecting documentation
**Purpose:** Validates documentation builds correctly
### Code Quality
#### `pg-version-check.yml` - Parameter Group Version Check
**Triggers:** Pull requests to maintenance-9.x and maintenance-10.x
**Purpose:** Detects parameter group struct modifications and verifies version increments
**Why:** Prevents settings corruption when struct layout changes without version bump
**How it works:**
1. Scans changed .c/.h files for `PG_REGISTER` entries
2. Detects if associated struct typedefs were modified
3. Checks if the PG version parameter was incremented
4. Posts helpful comment if version not incremented
**Reference:** See `docs/development/parameter_groups/` for PG system documentation
**Script:** `.github/scripts/check-pg-versions.sh`
**When to increment PG versions:**
- ✅ Adding/removing fields from struct
- ✅ Changing field types or sizes
- ✅ Reordering fields
- ✅ Adding/removing packing attributes
- ❌ Only changing `PG_RESET_TEMPLATE` default values
- ❌ Only changing comments
### Pull Request Helpers
#### `pr-branch-suggestion.yml` - Branch Targeting Suggestion
**Triggers:** PRs targeting master branch
**Purpose:** Suggests using maintenance-9.x or maintenance-10.x instead
#### `non-code-change.yaml` - Non-Code Change Detection
**Triggers:** Pull requests
**Purpose:** Detects PRs with only documentation/formatting changes
## Configuration Files
- `../.github/stale.yml` - Stale issue/PR management
- `../.github/no-response.yml` - Auto-close issues without response
- `../.github/issue_label_bot.yaml` - Automatic issue labeling
## Adding New Workflows
When adding workflows:
1. **Use descriptive names** - Make purpose clear from filename
2. **Document in this README** - Add entry above with purpose and triggers
3. **Set appropriate permissions** - Principle of least privilege
4. **Test in fork first** - Verify before submitting to main repo
5. **Handle errors gracefully** - Don't block CI unnecessarily
### Common Patterns
**Checkout with history:**
```yaml
- uses: actions/checkout@v4
with:
fetch-depth: 0
```
**Post PR comments:**
```yaml
- uses: actions/github-script@v7
with:
script: |
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: 'Comment text'
});
```
**Run bash scripts:**
```yaml
- run: bash .github/scripts/script-name.sh
env:
GITHUB_BASE_REF: ${{ github.base_ref }}
```
## Permissions
Workflows use GitHub's fine-grained permissions:
- `contents: read` - Read repository code
- `pull-requests: write` - Post/update PR comments
- `actions: read` - Read workflow run data
## Local Testing
Scripts in `.github/scripts/` can be run locally:
```bash
cd inav
export GITHUB_BASE_REF=maintenance-9.x
export GITHUB_HEAD_REF=feature-branch
bash .github/scripts/check-pg-versions.sh
```
## References
- [GitHub Actions Documentation](https://docs.github.com/en/actions)
- [Workflow Syntax](https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions)
- [GitHub Script Action](https://github.com/actions/github-script)
+382
View File
@@ -0,0 +1,382 @@
name: Build firmware
# Don't enable CI on push, just on PR. If you
# are working on the main repo and want to trigger
# a CI build submit a draft PR.
on:
push:
branches:
- '!maintenance-8.x.x'
pull_request:
paths:
- 'src/**'
- '.github/**'
- 'cmake/**'
- 'lib/**'
- 'docs/Settings.md'
- 'CMakeLists.txt'
- '*.sh'
workflow_call:
#inputs:
# release_build:
# description: 'Specifies if it is a build that should include commit hash in hex file names or not'
# default: false
# required: false
# type: boolean
jobs:
detect:
runs-on: ubuntu-latest
outputs:
single_target: ${{ steps.check.outputs.single_target }}
target_names: ${{ steps.check.outputs.target_names }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Detect single-target PR
id: check
run: |
if [ "${{ github.event_name }}" != "pull_request" ]; then
echo "single_target=false" >> $GITHUB_OUTPUT
exit 0
fi
CHANGED=$(git diff --name-only origin/${{ github.base_ref }}...HEAD)
if [ -z "$CHANGED" ]; then
echo "single_target=false" >> $GITHUB_OUTPUT
exit 0
fi
# Fail fast if any changed file is outside src/main/target/<dir>/
NON_TARGET=$(echo "$CHANGED" | grep -Ev '^src/main/target/[^/]+/.+' | head -1)
if [ -n "$NON_TARGET" ]; then
echo "Non-target file changed: $NON_TARGET — full build required"
echo "single_target=false" >> $GITHUB_OUTPUT
exit 0
fi
# Count how many distinct target directories were touched
TARGET_DIRS=$(echo "$CHANGED" | sed -n 's|^src/main/target/\([^/]*\)/.*|\1|p' | sort -u)
DIR_COUNT=$(echo "$TARGET_DIRS" | wc -l)
if [ "$DIR_COUNT" != "1" ]; then
echo "$DIR_COUNT target directories changed — full build required"
echo "single_target=false" >> $GITHUB_OUTPUT
exit 0
fi
TARGET_DIR="$TARGET_DIRS"
CMAKE="src/main/target/${TARGET_DIR}/CMakeLists.txt"
if [ ! -f "$CMAKE" ]; then
echo "No CMakeLists.txt for $TARGET_DIR — full build required"
echo "single_target=false" >> $GITHUB_OUTPUT
exit 0
fi
TARGET_NAMES=$(grep -oP '(?<=\()[^)]+' "$CMAKE" | tr '\n' ' ' | xargs)
if [ -z "$TARGET_NAMES" ]; then
echo "No target names in CMakeLists.txt — full build required"
echo "single_target=false" >> $GITHUB_OUTPUT
exit 0
fi
echo "Single-target PR: building $TARGET_NAMES"
echo "single_target=true" >> $GITHUB_OUTPUT
echo "target_names=$TARGET_NAMES" >> $GITHUB_OUTPUT
build:
needs: [detect]
if: needs.detect.outputs.single_target != 'true'
runs-on: ubuntu-latest
strategy:
matrix:
id: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: sudo apt-get update && sudo apt-get -y install ninja-build
- name: Setup environment
env:
ACTIONS_ALLOW_UNSECURE_COMMANDS: true
run: |
# This is the hash of the commit for the PR
# when the action is triggered by PR, empty otherwise
COMMIT_ID=${{ github.event.pull_request.head.sha }}
# This is the hash of the commit when triggered by push
# but the hash of refs/pull/<n>/merge, which is different
# from the hash of the latest commit in the PR, that's
# why we try github.event.pull_request.head.sha first
COMMIT_ID=${COMMIT_ID:-${{ github.sha }}}
BUILD_SUFFIX=ci-$(date '+%Y%m%d')-$(git rev-parse --short ${COMMIT_ID})
VERSION=$(grep project CMakeLists.txt|awk -F VERSION '{ gsub(/[ \t)]/, "", $2); print $2 }')
echo "BUILD_SUFFIX=${BUILD_SUFFIX}" >> $GITHUB_ENV
echo "BUILD_NAME=inav-${VERSION}-${BUILD_SUFFIX}" >> $GITHUB_ENV
echo "NUM_CORES=$(grep processor /proc/cpuinfo | wc -l)" >> $GITHUB_ENV
- uses: actions/cache@v4
with:
path: downloads
key: ${{ runner.os }}-downloads-${{ hashFiles('CMakeLists.txt') }}-${{ hashFiles('**/cmake/*')}}
- name: Build targets (${{ matrix.id }})
run: mkdir -p build && cd build && cmake -DWARNINGS_AS_ERRORS=ON -DCI_JOB_INDEX=${{ matrix.id }} -DCI_JOB_COUNT=${{ strategy.job-total }} -DBUILD_SUFFIX=${{ env.BUILD_SUFFIX }} -DMAIN_COMPILE_OPTIONS=-pipe -G Ninja .. && ninja -j${{ env.NUM_CORES }} ci
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: matrix-${{ env.BUILD_NAME }}.${{ matrix.id }}
path: ./build/*.hex
retention-days: 1
build-single-target:
needs: [detect]
if: needs.detect.outputs.single_target == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: sudo apt-get update && sudo apt-get -y install ninja-build
- name: Setup environment
env:
ACTIONS_ALLOW_UNSECURE_COMMANDS: true
run: |
COMMIT_ID=${{ github.event.pull_request.head.sha }}
COMMIT_ID=${COMMIT_ID:-${{ github.sha }}}
BUILD_SUFFIX=ci-$(date '+%Y%m%d')-$(git rev-parse --short ${COMMIT_ID})
VERSION=$(grep project CMakeLists.txt|awk -F VERSION '{ gsub(/[ \t)]/, "", $2); print $2 }')
echo "BUILD_SUFFIX=${BUILD_SUFFIX}" >> $GITHUB_ENV
echo "BUILD_NAME=inav-${VERSION}-${BUILD_SUFFIX}" >> $GITHUB_ENV
echo "NUM_CORES=$(grep processor /proc/cpuinfo | wc -l)" >> $GITHUB_ENV
- uses: actions/cache@v4
with:
path: downloads
key: ${{ runner.os }}-downloads-${{ hashFiles('CMakeLists.txt') }}-${{ hashFiles('**/cmake/*')}}
- name: Build targets (${{ needs.detect.outputs.target_names }})
run: mkdir -p build && cd build && cmake -DWARNINGS_AS_ERRORS=ON -DBUILD_SUFFIX=${{ env.BUILD_SUFFIX }} -DMAIN_COMPILE_OPTIONS=-pipe -G Ninja .. && ninja -j${{ env.NUM_CORES }} ${{ needs.detect.outputs.target_names }}
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: matrix-${{ env.BUILD_NAME }}.single
path: ./build/*.hex
retention-days: 1
upload-artifacts:
runs-on: ubuntu-latest
needs: [build, build-single-target]
if: always() && !cancelled() && (needs.build.result == 'success' || needs.build-single-target.result == 'success')
steps:
- uses: actions/checkout@v4
- name: Setup environment
env:
ACTIONS_ALLOW_UNSECURE_COMMANDS: true
run: |
# This is the hash of the commit for the PR
# when the action is triggered by PR, empty otherwise
COMMIT_ID=${{ github.event.pull_request.head.sha }}
# This is the hash of the commit when triggered by push
# but the hash of refs/pull/<n>/merge, which is different
# from the hash of the latest commit in the PR, that's
# why we try github.event.pull_request.head.sha first
COMMIT_ID=${COMMIT_ID:-${{ github.sha }}}
BUILD_SUFFIX=ci-$(date '+%Y%m%d')-$(git rev-parse --short ${COMMIT_ID})
VERSION=$(grep project CMakeLists.txt|awk -F VERSION '{ gsub(/[ \t)]/, "", $2); print $2 }')
echo "BUILD_SUFFIX=${BUILD_SUFFIX}" >> $GITHUB_ENV
echo "BUILD_NAME=inav-${VERSION}-${BUILD_SUFFIX}" >> $GITHUB_ENV
echo "NUM_CORES=$(grep processor /proc/cpuinfo | wc -l)" >> $GITHUB_ENV
- name: Download artifacts
uses: actions/download-artifact@v4
with:
pattern: matrix-inav-*
merge-multiple: true
path: binaries
- name: Build target list
run: |
ls -1 binaries/*.hex | cut -d/ -f2 > targets.txt
- name: Upload firmware images
uses: actions/upload-artifact@v4
with:
name: ${{ env.BUILD_NAME }}
path: binaries/*.hex
- name: Upload firmware images
uses: actions/upload-artifact@v4
with:
name: targets
path: targets.txt
- name: Save PR number
if: github.event_name == 'pull_request'
run: echo "${{ github.event.pull_request.number }}" > pr_number.txt
- name: Upload PR number
if: github.event_name == 'pull_request'
uses: actions/upload-artifact@v4
with:
name: pr-number
path: pr_number.txt
retention-days: 1
build-SITL-Linux-arm64:
runs-on: ubuntu-22.04-arm
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: sudo apt-get update && sudo apt-get -y install ninja-build
- name: Setup environment
env:
ACTIONS_ALLOW_UNSECURE_COMMANDS: true
run: |
# This is the hash of the commit for the PR
# when the action is triggered by PR, empty otherwise
COMMIT_ID=${{ github.event.pull_request.head.sha }}
# This is the hash of the commit when triggered by push
# but the hash of refs/pull/<n>/merge, which is different
# from the hash of the latest commit in the PR, that's
# why we try github.event.pull_request.head.sha first
COMMIT_ID=${COMMIT_ID:-${{ github.sha }}}
BUILD_SUFFIX=ci-$(date '+%Y%m%d')-$(git rev-parse --short ${COMMIT_ID})
VERSION=$(grep project CMakeLists.txt|awk -F VERSION '{ gsub(/[ \t)]/, "", $2); print $2 }')
echo "BUILD_SUFFIX=${BUILD_SUFFIX}" >> $GITHUB_ENV
echo "BUILD_NAME=inav-${VERSION}-${BUILD_SUFFIX}" >> $GITHUB_ENV
echo "NUM_CORES=$(grep processor /proc/cpuinfo | wc -l)" >> $GITHUB_ENV
- name: Build SITL
run: mkdir -p build_SITL && cd build_SITL && cmake -DSITL=ON -DWARNINGS_AS_ERRORS=ON -G Ninja .. && ninja -j${{ env.NUM_CORES }}
- name: Strip version number
run: |
for f in build_SITL/*_SITL; do
mv $f $(echo $f | sed -e 's/_[0-9]\+\.[0-9]\+\.[0-9]\+//')
done
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: ${{ env.BUILD_NAME }}_SITL-Linux-aarch64
path: ./build_SITL/*_SITL
build-SITL-Linux:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: sudo apt-get update && sudo apt-get -y install ninja-build
- name: Setup environment
env:
ACTIONS_ALLOW_UNSECURE_COMMANDS: true
run: |
# This is the hash of the commit for the PR
# when the action is triggered by PR, empty otherwise
COMMIT_ID=${{ github.event.pull_request.head.sha }}
# This is the hash of the commit when triggered by push
# but the hash of refs/pull/<n>/merge, which is different
# from the hash of the latest commit in the PR, that's
# why we try github.event.pull_request.head.sha first
COMMIT_ID=${COMMIT_ID:-${{ github.sha }}}
BUILD_SUFFIX=ci-$(date '+%Y%m%d')-$(git rev-parse --short ${COMMIT_ID})
VERSION=$(grep project CMakeLists.txt|awk -F VERSION '{ gsub(/[ \t)]/, "", $2); print $2 }')
echo "BUILD_SUFFIX=${BUILD_SUFFIX}" >> $GITHUB_ENV
echo "BUILD_NAME=inav-${VERSION}-${BUILD_SUFFIX}" >> $GITHUB_ENV
echo "NUM_CORES=$(grep processor /proc/cpuinfo | wc -l)" >> $GITHUB_ENV
- name: Build SITL
run: mkdir -p build_SITL && cd build_SITL && cmake -DSITL=ON -DWARNINGS_AS_ERRORS=ON -G Ninja .. && ninja -j${{ env.NUM_CORES }}
- name: Strip version number
run: |
for f in build_SITL/*_SITL; do
mv $f $(echo $f | sed -e 's/_[0-9]\+\.[0-9]\+\.[0-9]\+//')
done
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: ${{ env.BUILD_NAME }}_SITL-Linux
path: ./build_SITL/*_SITL
build-SITL-Mac:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: |
brew install ruby
- name: Setup environment
env:
ACTIONS_ALLOW_UNSECURE_COMMANDS: true
run: |
# This is the hash of the commit for the PR
# when the action is triggered by PR, empty otherwise
COMMIT_ID=${{ github.event.pull_request.head.sha }}
# This is the hash of the commit when triggered by push
# but the hash of refs/pull/<n>/merge, which is different
# from the hash of the latest commit in the PR, that's
# why we try github.event.pull_request.head.sha first
COMMIT_ID=${COMMIT_ID:-${{ github.sha }}}
BUILD_SUFFIX=ci-$(date '+%Y%m%d')-$(git rev-parse --short ${COMMIT_ID})
VERSION=$(grep project CMakeLists.txt|awk -F VERSION '{ gsub(/[ \t)]/, "", $2); print $2 }')
echo "BUILD_SUFFIX=${BUILD_SUFFIX}" >> $GITHUB_ENV
echo "BUILD_NAME=inav-${VERSION}-${BUILD_SUFFIX}" >> $GITHUB_ENV
echo "NUM_CORES=$(grep processor /proc/cpuinfo | wc -l)" >> $GITHUB_ENV
- name: Build SITL
run: |
mkdir -p build_SITL && cd build_SITL
cmake -DSITL=ON -DWARNINGS_AS_ERRORS=ON -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" -G Ninja ..
ninja -j4
- name: Strip version number
run: |
for f in build_SITL/*_SITL; do
mv -v $f $(echo $f | sed -Ee 's/_[0-9]+\.[0-9]+\.[0-9]+//')
done
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: ${{ env.BUILD_NAME }}_SITL-MacOS
path: ./build_SITL/*_SITL
build-SITL-Windows:
runs-on: windows-latest
defaults:
run:
shell: C:\tools\cygwin\bin\bash.exe -o igncr '{0}'
steps:
- uses: actions/checkout@v4
- name: Setup Cygwin
uses: egor-tensin/setup-cygwin@v4
with:
packages: cmake ruby ninja gcc-g++ rubygems
- name: Setup environment
env:
ACTIONS_ALLOW_UNSECURE_COMMANDS: true
run: |
# This is the hash of the commit for the PR
# when the action is triggered by PR, empty otherwise
COMMIT_ID=${{ github.event.pull_request.head.sha }}
# This is the hash of the commit when triggered by push
# but the hash of refs/pull/<n>/merge, which is different
# from the hash of the latest commit in the PR, that's
# why we try github.event.pull_request.head.sha first
COMMIT_ID=${COMMIT_ID:-${{ github.sha }}}
BUILD_SUFFIX=ci-$(date '+%Y%m%d')-$(git rev-parse --short ${COMMIT_ID})
VERSION=$( grep project CMakeLists.txt|awk -F VERSION '{ gsub(/[ \t)]/, "", $2); print $2 }' )
echo "BUILD_SUFFIX=${BUILD_SUFFIX}" >> $GITHUB_ENV
echo "BUILD_NAME=inav-${VERSION}-${BUILD_SUFFIX}" >> $GITHUB_ENV
- name: Build SITL
run: gem install getoptlong && mkdir -p build_SITL && cd build_SITL && cmake -DSITL=ON -DWARNINGS_AS_ERRORS=ON -G Ninja .. && ninja -j4
- name: Strip version number
run: |
for f in ./build_SITL/*_SITL.exe; do
mv $f $(echo $f | sed -e 's/_[0-9]\+\.[0-9]\+\.[0-9]\+//')
done
- name: Copy cygwin1.dll
run: cp /bin/cygwin1.dll ./build_SITL/
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: ${{ env.BUILD_NAME }}_SITL-WIN
path: |
./build_SITL/*.exe
./build_SITL/cygwin1.dll
test:
#needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: sudo apt-get update && sudo apt-get -y install ninja-build
- name: Run Tests
run: mkdir -p build && cd build && cmake -DTOOLCHAIN=none -G Ninja .. && ninja check
+27
View File
@@ -0,0 +1,27 @@
name: Make sure docs are updated
on:
pull_request:
paths:
- src/main/fc/settings.yaml
- docs/Settings.md
push:
paths:
- src/main/fc/settings.yaml
- docs/Settings.md
jobs:
settings_md:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: sudo apt-get update && sudo apt-get -y install python3-yaml
- name: Check that Settings.md is up to date
run: |
cp docs/Settings.md{,.ci}
python3 src/utils/update_cli_docs.py -q
if ! diff -q docs/Settings.md{,.ci} >/dev/null; then
echo "::error ::\"docs/Settings.md\" is not up to date, please run \"src/utils/update_cli_docs.py\""
exit 1
fi
+105
View File
@@ -0,0 +1,105 @@
name: Build pre-release
# Don't enable CI on push, just on PR. If you
# are working on the main repo and want to trigger
# a CI build submit a draft PR.
on:
push:
branches:
- master
- maintenance-8.x.x
- maintenance-9.x
paths:
- 'src/**'
- '.github/**'
- 'cmake/**'
- 'lib/**'
- 'docs/Settings.md'
- 'CMakeLists.txt'
- '*.sh'
jobs:
build:
name: build
uses: ./.github/workflows/ci.yml
release:
name: Release
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Get version
id: version
run: |
VERSION=$(grep project CMakeLists.txt|awk -F VERSION '{ gsub(/[ \t\)]/, "", $2); print $2 }')
echo "version=${VERSION}" >> $GITHUB_OUTPUT
- name: Get current date
id: date
run: echo "today=$(date '+%Y%m%d')" >> $GITHUB_OUTPUT
- name: download artifacts
uses: actions/download-artifact@v4
with:
path: hexes
pattern: matrix-inav-*
merge-multiple: true
- name: download sitl linux
uses: actions/download-artifact@v4
with:
path: resources/sitl/linux
pattern: inav-*SITL-Linux
merge-multiple: true
- name: download sitl linux aarch64
uses: actions/download-artifact@v4
with:
path: resources/sitl/linux/arm64
pattern: inav-*SITL-Linux-aarch64
merge-multiple: true
- name: download sitl windows
uses: actions/download-artifact@v4
with:
path: resources/sitl/windows
pattern: inav-*SITL-WIN
merge-multiple: true
- name: download sitl mac
uses: actions/download-artifact@v4
with:
path: resources/sitl/macos
pattern: inav-*SITL-MacOS
merge-multiple: true
- name: Consolidate sitl files
run: |
zip -r -9 sitl-resources.zip resources/
- name: Upload release artifacts
uses: softprops/action-gh-release@v2
with:
name: inav-${{ steps.version.outputs.version }}-dev-${{ steps.date.outputs.today }}-${{ github.run_number }}-${{ github.sha }}
tag_name: v${{ steps.version.outputs.version }}-${{ steps.date.outputs.today }}.${{ github.run_number }}
# To create release on a different repo, we need a token setup
token: ${{ secrets.NIGHTLY_TOKEN }}
repository: iNavFlight/inav-nightly
prerelease: true
draft: false
#generate_release_notes: true
make_latest: false
files: |
hexes/*.hex
sitl-resources.zip
body: |
${{ steps.notes.outputs.notes }}
### Flashing
These are nightly builds and configuration settings can be added and removed often. Flashing with Full chip erase is strongly recommended to avoid issues.
Firmware related issues should be opened in the iNavflight/inav repository, not in inav-nightly.
### 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 }}
+25
View File
@@ -0,0 +1,25 @@
name: Build firmware
# Don't enable CI on push, just on PR. If you
# are working on the main repo and want to trigger
# a CI build submit a draft PR.
on:
pull_request:
paths-ignore:
- 'src/**'
- '.github/**'
- 'cmake/**'
- 'lib/**'
- 'docs/Settings.md'
- 'CMakeLists.txt'
- '*.sh'
jobs:
test:
#needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: sudo apt-get update && sudo apt-get -y install ninja-build
- name: Run Tests
run: mkdir -p build && cd build && cmake -DTOOLCHAIN=none -G Ninja .. && ninja check
+128
View File
@@ -0,0 +1,128 @@
name: Parameter Group Version Check
on:
pull_request:
types: [opened, synchronize, reopened]
branches:
- maintenance-9.x
- maintenance-10.x
paths:
- 'src/**/*.c'
- 'src/**/*.h'
jobs:
check-pg-versions:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- name: Checkout PR code
uses: actions/checkout@v4
with:
fetch-depth: 0 # Need full history to compare with base branch
- name: Fetch base branch
run: |
git fetch origin ${{ github.base_ref }}:refs/remotes/origin/${{ github.base_ref }}
- name: Run PG version check script
id: pg_check
run: |
set +e # Don't fail the workflow, just capture exit code
# Run script and capture output. Exit code 1 is expected for issues.
# The output is captured and encoded to be passed between steps.
output=$(bash .github/scripts/check-pg-versions.sh 2>&1)
exit_code=$?
echo "exit_code=${exit_code}" >> $GITHUB_OUTPUT
echo "output<<EOF" >> $GITHUB_OUTPUT
echo "$output" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
env:
GITHUB_BASE_REF: ${{ github.base_ref }}
GITHUB_HEAD_REF: ${{ github.head_ref }}
- name: Post comment if issues found
if: steps.pg_check.outputs.exit_code == '1'
uses: actions/github-script@v7
with:
script: |
// Use the captured output from the previous step
const output = '${{ steps.pg_check.outputs.output }}';
let issuesContent = '';
try {
// Extract issues from output (everything after the warning line)
const lines = output.split('\n');
let capturing = false;
let issues = [];
for (const line of lines) {
if (line.includes('###')) {
capturing = true;
}
if (capturing) {
issues.push(line);
}
}
issuesContent = issues.join('\n');
} catch (err) {
console.log('Error capturing issues:', err);
issuesContent = '*Unable to extract detailed issues*';
}
const commentBody = '## ⚠️ Parameter Group Version Check\n\n' +
'The following parameter groups may need version increments:\n\n' +
issuesContent + '\n\n' +
'**Why this matters:**\n' +
'Modifying PG struct fields without incrementing the version can cause settings corruption when users flash new firmware. The `pgLoad()` function validates versions and will use defaults if there\'s a mismatch, preventing corruption.\n\n' +
'**When to increment the version:**\n' +
'- ✅ Adding/removing fields\n' +
'- ✅ Changing field types or sizes\n' +
'- ✅ Reordering fields\n' +
'- ✅ Adding/removing packing attributes\n' +
'- ❌ Only changing default values in `PG_RESET_TEMPLATE`\n' +
'- ❌ Only changing comments\n\n' +
'**Reference:**\n' +
'- [Parameter Group Documentation](../docs/development/parameter_groups/)\n' +
'- Example: [PR #11236](https://github.com/iNavFlight/inav/pull/11236) (field removal requiring version increment)\n\n' +
'---\n' +
'*This is an automated check. False positives are possible. If you believe the version increment is not needed, please explain in a comment.*';
try {
// Check if we already commented
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
});
const botComment = comments.find(comment =>
comment.user.login === 'github-actions[bot]' &&
comment.body.includes('Parameter Group Version Check')
);
if (botComment) {
// Update existing comment
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: botComment.id,
body: commentBody
});
console.log('Updated existing PG version check comment');
} else {
// Post new comment
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: commentBody
});
console.log('Posted new PG version check comment');
}
} catch (err) {
core.setFailed(`Failed to post comment: ${err}`);
}
@@ -0,0 +1,41 @@
name: PR Branch Suggestion
on:
pull_request_target:
types: [opened]
branches:
- master
jobs:
suggest-branch:
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- name: Suggest maintenance branch
uses: actions/github-script@v7
with:
script: |
const comment = `### Branch Targeting Suggestion
You've targeted the \`master\` branch with this PR. Please consider if a version branch might be more appropriate:
- **\`maintenance-9.x\`** - If your change is backward-compatible and won't create compatibility issues between INAV firmware and Configurator 9.x versions. This will allow your PR to be included in the next 9.x release.
- **\`maintenance-10.x\`** - If your change introduces compatibility requirements between firmware and configurator that would break 9.x compatibility. This is for PRs which will be included in INAV 10.x
If \`master\` is the correct target for this change, no action is needed.
---
*This is an automated suggestion to help route contributions to the appropriate branch.*`;
try {
await github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: comment
});
} catch (err) {
core.setFailed(`Failed to post suggestion comment: ${err}`);
}
+151
View File
@@ -0,0 +1,151 @@
name: PR Test Builds
# Runs after "Build firmware" completes. Uses workflow_run (rather than
# pull_request directly) so that secrets are available even for PRs from forks.
#
# Requires a repository secret PR_BUILDS_TOKEN with Contents: write access
# to iNavFlight/pr-test-builds (fine-grained PAT or classic PAT with repo scope).
on:
workflow_run:
workflows: ["Build firmware"]
types: [completed]
jobs:
publish:
runs-on: ubuntu-latest
# Only act on pull_request-triggered runs that succeeded.
if: >
github.event.workflow_run.event == 'pull_request' &&
github.event.workflow_run.conclusion == 'success'
# Prevent concurrent runs for the same PR branch racing on the
# release delete/create cycle.
concurrency:
group: pr-test-build-${{ github.event.workflow_run.head_repository.full_name }}-${{ github.event.workflow_run.head_branch }}
cancel-in-progress: true
permissions:
actions: read # to download artifacts from the triggering workflow run
issues: write # github.rest.issues.* endpoints used to post PR comments
pull-requests: write # to post the PR comment
steps:
- name: Download PR number
uses: actions/download-artifact@v4
with:
name: pr-number
run-id: ${{ github.event.workflow_run.id }}
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Read PR number
id: pr
run: |
PR_NUM=$(tr -dc '0-9' < pr_number.txt)
if [ -z "$PR_NUM" ]; then
echo "::error::Invalid PR number in artifact"
exit 1
fi
echo "number=${PR_NUM}" >> $GITHUB_OUTPUT
- name: Download firmware artifacts
uses: actions/download-artifact@v4
with:
pattern: matrix-inav-*
merge-multiple: true
path: hexes
run-id: ${{ github.event.workflow_run.id }}
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Get build info
id: info
run: |
COUNT=$(find hexes -name '*.hex' -type f | wc -l)
if [ "$COUNT" -eq 0 ]; then
echo "::error::No .hex files found in downloaded artifacts"
exit 1
fi
echo "count=${COUNT}" >> $GITHUB_OUTPUT
echo "short_sha=$(echo '${{ github.event.workflow_run.head_sha }}' | cut -c1-7)" >> $GITHUB_OUTPUT
# Delete the previous release for this PR (if any) so assets are replaced
# cleanly on each new commit. --cleanup-tag removes the old tag so it is
# recreated fresh pointing to the new commit.
- name: Delete existing PR release
env:
GH_TOKEN: ${{ secrets.PR_BUILDS_TOKEN }}
run: |
gh release delete "pr-${{ steps.pr.outputs.number }}" \
--repo iNavFlight/pr-test-builds --cleanup-tag --yes 2>/dev/null || true
- name: Create PR release
env:
GH_TOKEN: ${{ secrets.PR_BUILDS_TOKEN }}
PR_NUMBER: ${{ steps.pr.outputs.number }}
SHORT_SHA: ${{ steps.info.outputs.short_sha }}
HEX_COUNT: ${{ steps.info.outputs.count }}
REPO: ${{ github.repository }}
run: |
PR_URL="https://github.com/${REPO}/pull/${PR_NUMBER}"
printf '%s\n\n%s\n\n%s\n' \
"Test build for [PR #${PR_NUMBER}](${PR_URL}) — commit \`${SHORT_SHA}\`" \
"**${HEX_COUNT} targets built.** Find your board's \`.hex\` file by name (e.g. \`MATEKF405SE.hex\`)." \
"> Development build for testing only. Use Full Chip Erase when flashing." \
> release-notes.md
gh release create "pr-${PR_NUMBER}" hexes/*.hex \
--repo iNavFlight/pr-test-builds \
--prerelease \
--title "PR #${PR_NUMBER} (${SHORT_SHA})" \
--notes-file release-notes.md
- name: Post or update PR comment
uses: actions/github-script@v7
env:
PR_NUMBER: ${{ steps.pr.outputs.number }}
SHORT_SHA: ${{ steps.info.outputs.short_sha }}
HEX_COUNT: ${{ steps.info.outputs.count }}
with:
script: |
const prNumber = parseInt(process.env.PR_NUMBER, 10);
if (isNaN(prNumber)) throw new Error(`Invalid PR number: ${process.env.PR_NUMBER}`);
const shortSha = process.env.SHORT_SHA;
const count = process.env.HEX_COUNT;
const releaseUrl = `https://github.com/iNavFlight/pr-test-builds/releases/tag/pr-${prNumber}`;
const body = [
'<!-- pr-test-build -->',
'**Test firmware build ready** — commit `' + shortSha + '`',
'',
`[Download firmware for PR #${prNumber}](${releaseUrl})`,
'',
`${count} targets built. Find your board's \`.hex\` file by name on that page ` +
'(e.g. `MATEKF405SE.hex`). Files are individually downloadable — no GitHub login required.',
'',
'> Development build for testing only. Use Full Chip Erase when flashing.',
].join('\n');
const comments = await github.paginate(
github.rest.issues.listComments,
{
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
}
);
const existing = comments.find(c =>
c.user.type === 'Bot' && c.body.includes('<!-- pr-test-build -->')
);
if (existing) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existing.id,
body,
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
body,
});
}
+52
View File
@@ -0,0 +1,52 @@
*.o
.DS_Store
*~
*.swp
*.uvopt
*.dep
*.bak
*.uvgui.*
*.ubx
.project
.settings
.cproject
.cache/
__pycache__
startup_stm32f10x_md_gcc.s
.vagrant/
#.vscode/
cov-int*
/build/
/build_SITL/
/[hs]itl/
/ninja/
/obj/
/patches/
/tools/
/downloads/
/debug/
/release/
/*_SITL/
# script-generated files
docs/Manual.pdf
README.pdf
# build generated files
/settings.json
# local changes only
make/local.mk
launch.json
.vscode/tasks.json
.vscode/c_cpp_properties.json
/cmake-build-debug/
# Assitnow token and files for test script
tokens.yaml
*.ubx
# Local development files
.semgrepignore
build_sitl/
Executable
+71
View File
@@ -0,0 +1,71 @@
#!/bin/bash
REVISION=$(git rev-parse --short HEAD)
BRANCH=$(git rev-parse --abbrev-ref HEAD)
REVISION=$(git rev-parse --short HEAD)
LAST_COMMIT_DATE=$(git log -1 --date=short --format="%cd")
TARGET_FILE=obj/cleanflight_${TARGET}
TRAVIS_REPO_SLUG=${TRAVIS_REPO_SLUG:=$USER/undefined}
BUILDNAME=${BUILDNAME:=travis}
TRAVIS_BUILD_NUMBER=${TRAVIS_BUILD_NUMBER:=undefined}
CURL_BASEOPTS=(
"--retry" "10"
"--retry-max-time" "120" )
CURL_PUB_BASEOPTS=(
"--form" "revision=${REVISION}"
"--form" "branch=${BRANCH}"
"--form" "travis_build_number=${TRAVIS_BUILD_NUMBER}"
"--form" "last_commit_date=${LAST_COMMIT_DATE}"
"--form" "github_repo=${TRAVIS_REPO_SLUG}"
"--form" "build_name=${BUILDNAME}" )
# A hacky way of running the unit tests at the same time as the normal builds.
if [ $RUNTESTS ] ; then
cd ./src/test && make test
# A hacky way of building the docs at the same time as the normal builds.
elif [ $PUBLISHDOCS ] ; then
if [ $PUBLISH_URL ] ; then
# Patch Gimli to fix underscores_inside_words
curl -L "${CURL_BASEOPTS[@]}" https://github.com/walle/gimli/archive/v0.5.9.tar.gz | tar zxf -
sed -i 's/).render(/, :no_intra_emphasis => true).render(/' gimli-0.5.9/ext/github_markup.rb
cd gimli-0.5.9/
gem build gimli.gemspec && gem install gimli
cd ../
./build_docs.sh
curl -k "${CURL_BASEOPTS[@]}" "${CURL_PUB_BASEOPTS[@]}" --form "manual=@docs/Manual.pdf" ${PUBLISH_URL} || true
fi
elif [ $PUBLISHMETA ] ; then
if [ $PUBLISH_URL ] ; then
RECENT_COMMITS=$(git shortlog -n25)
curl -k "${CURL_BASEOPTS[@]}" "${CURL_PUB_BASEOPTS[@]}" --form "recent_commits=${RECENT_COMMITS}" ${PUBLISH_URL} || true
fi
elif [ $TARGET ] ; then
if [ $PUBLISH_URL ] ; then
make -j2
if [ -f ${TARGET_FILE}.bin ] ; then
TARGET_FILE=${TARGET_FILE}.bin
elif [ -f ${TARGET_FILE}.hex ] ; then
TARGET_FILE=${TARGET_FILE}.hex
else
echo "build artifact (hex or bin) for ${TARGET_FILE} not found, aborting";
exit 1
fi
curl -k "${CURL_BASEOPTS[@]}" "${CURL_PUB_BASEOPTS[@]}" --form "file=@${TARGET_FILE}" ${PUBLISH_URL} || true
exit 0;
else
make -j2 $MAKEFILE
fi
elif [ $GOAL ] ; then
make V=0 $GOAL
else
# No target specified, build all with very low verbosity.
make V=0 all
fi
Executable
+58
View File
@@ -0,0 +1,58 @@
env:
# Specify the main Mafile supported goals.
- GOAL=test
- GOAL=targets-group-1
- GOAL=targets-group-2
- GOAL=targets-group-3
- GOAL=targets-group-4
- GOAL=targets-group-5
- GOAL=targets-group-6
- GOAL=targets-group-7
- GOAL=targets-group-8
- GOAL=targets-group-rest
# use new docker environment
sudo: false
git:
depth: 5
addons:
apt:
packages:
- build-essential
- git
- libc6-i386
- time
# We use cpp for unit tests, and c for the main project.
language: cpp
compiler: clang
before_install:
install:
- make arm_sdk_install
before_script:
- make arm_sdk_version
- clang --version
- clang++ --version
script: ./.travis.sh
cache:
timeout: 1000
directories:
- downloads
- tools
notifications:
#slack: inavflight:UWRoWFJ4cbbpHXT8HJJlAPXa
email: false
webhooks:
urls:
- https://webhooks.gitter.im/e/34e795df229478ac3a3b
on_success: always
on_failure: always
on_start: never
+10
View File
@@ -0,0 +1,10 @@
filetype on
filetype indent on
set expandtab
set bs=2
set sw=4
set ts=4
syn on
+62
View File
@@ -0,0 +1,62 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceRoot}",
"${workspaceRoot}/src/main/**"
],
"browse": {
"limitSymbolsToIncludedHeaders": false,
"path": [
"${workspaceRoot}/**"
]
},
"intelliSenseMode": "msvc-x64",
"cStandard": "c11",
"cppStandard": "c++17",
"defines": [
"USE_OSD",
"USE_GYRO_NOTCH_1",
"USE_GYRO_NOTCH_2",
"USE_DTERM_NOTCH",
"USE_ACC_NOTCH",
"USE_GYRO_BIQUAD_RC_FIR2",
"USE_D_BOOST",
"USE_SERIALSHOT",
"USE_ANTIGRAVITY",
"USE_ASYNC_GYRO_PROCESSING",
"USE_RPM_FILTER",
"USE_GLOBAL_FUNCTIONS",
"USE_DYNAMIC_FILTERS",
"USE_DSHOT",
"FLASH_SIZE 480",
"USE_I2C_IO_EXPANDER",
"USE_PCF8574",
"USE_ESC_SENSOR",
"USE_PROGRAMMING_FRAMEWORK",
"USE_SERIALRX_GHST",
"USE_TELEMETRY_GHST",
"USE_CMS",
"USE_DJI_HD_OSD",
"USE_GYRO_KALMAN",
"USE_RANGEFINDER",
"USE_RATE_DYNAMICS",
"USE_SMITH_PREDICTOR",
"USE_ALPHA_BETA_GAMMA_FILTER",
"USE_MAG_VCM5883",
"USE_TELEMETRY_JETIEXBUS",
"USE_NAV",
"USE_SDCARD_SDIO",
"USE_SDCARD",
"USE_Q_TUNE",
"USE_GYRO_FFT_FILTER",
"USE_BARO_DPS310",
"USE_ADAPTIVE_FILTER",
"MCU_FLASH_SIZE 1024"
],
"configurationProvider": "ms-vscode.cmake-tools"
}
],
"version": 4
}
+20
View File
@@ -0,0 +1,20 @@
{
"files.associations": {
"chrono": "c",
"cmath": "c",
"ranges": "c",
"navigation.h": "c",
"rth_trackback.h": "c",
"platform.h": "c",
"timer.h": "c",
"bus.h": "c",
"io.h": "c",
"fc_core.h": "c"
},
"editor.tabSize": 4,
"editor.insertSpaces": true,
"editor.detectIndentation": false,
"editor.expandTabs": true,
"C_Cpp.clang_format_fallbackStyle": "{ BasedOnStyle: Google, IndentWidth: 4, BreakBeforeBraces: Mozilla }"
}
Vendored Executable
+41
View File
@@ -0,0 +1,41 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "Build AOCODARCH7DUAL",
"type": "shell",
"command": "make AOCODARCH7DUAL",
"group": "build",
"problemMatcher": [],
"options": {
"cwd": "${workspaceFolder}/build"
}
},
{
"label": "Build AOCODARCH7DUAL",
"type": "shell",
"command": "make AOCODARCH7DUAL",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [],
"options": {
"cwd": "${workspaceFolder}/build"
}
}
,
{
"label": "CMAKE Update",
"type": "shell",
"command": "cmake ..",
"group": "build",
"problemMatcher": [],
"options": {
"cwd": "${workspaceFolder}/build"
}
}
]
}
+461
View File
@@ -0,0 +1,461 @@
# AGENT.md - Guide for AI Agents Working with INAV
## Project Overview
**INAV** is a navigation-capable flight controller firmware for multirotor, fixed-wing, and other RC vehicles. It is a community-driven project written primarily in C (C99/C11 standard) with support for STM32 F4, F7, H7, and AT32 microcontrollers.
### Key Characteristics
- **Type**: Embedded firmware for flight controllers
- **Language**: C (C99/C11), with some C++ for unit tests
- **Build System**: CMake (version 3.13+)
- **License**: GNU GPL v3
- **Version**: 9.0.1 (as of this writing)
- **Codebase History**: Evolved from Cleanflight/Baseflight
## Architecture and Structure
### Core Components
The INAV codebase is organized into the following major subsystems:
1. **Flight Control (`fc/`)**: Core flight controller logic, initialization, MSP protocol handling
2. **Sensors (`sensors/`)**: Gyro, accelerometer, compass, barometer, GPS, rangefinder, pitot tube
3. **Flight (`flight/`)**: PID controllers, mixers, altitude hold, position hold, navigation
4. **Navigation (`navigation/`)**: Waypoint missions, RTH (Return to Home), position hold
5. **Drivers (`drivers/`)**: Hardware abstraction layer for MCU peripherals (SPI, I2C, UART, timers, etc.)
6. **IO (`io/`)**: Serial communication, OSD, LED strips, telemetry
7. **RX (`rx/`)**: Radio receiver protocols (CRSF, SBUS, IBUS, etc.)
8. **Scheduler (`scheduler/`)**: Real-time task scheduling
9. **Configuration (`config/`)**: Parameter groups, EEPROM storage, settings management
10. **MSP (`msp/`)**: MultiWii Serial Protocol implementation
11. **Telemetry (`telemetry/`)**: SmartPort, FPort, MAVLink, LTM, CRSF telemetry
12. **Blackbox (`blackbox/`)**: Flight data recorder
13. **Programming (`programming/`)**: Logic conditions and global functions for in-flight programming
### Directory Structure
```
/src/main/ - Main source code
├── build/ - Build configuration and macros
├── common/ - Common utilities (math, filters, utils)
├── config/ - Configuration system (parameter groups)
├── drivers/ - Hardware drivers (MCU-specific)
├── fc/ - Flight controller core
├── flight/ - Flight control algorithms
├── io/ - Input/output (serial, OSD, LED)
├── msp/ - MSP protocol
├── navigation/ - Navigation and autopilot
├── rx/ - Radio receiver protocols
├── sensors/ - Sensor drivers and processing
├── scheduler/ - Task scheduler
├── telemetry/ - Telemetry protocols
└── target/ - Board-specific configurations
/docs/ - Documentation
└── development/ - Developer documentation
/cmake/ - CMake build scripts
/lib/ - External libraries
/tools/ - Build and utility tools
```
## Coding Conventions
### Naming Conventions
1. **Types**: Use `_t` suffix for typedef'd types: `gyroConfig_t`, `pidController_t`
2. **Enums**: Use `_e` suffix for enum types: `portMode_e`, `cfTaskPriority_e`
3. **Functions**: Use camelCase with verb-phrase names: `gyroInit()`, `deleteAllPages()`
4. **Variables**: Use camelCase nouns, avoid noise words like "data" or "info"
5. **Booleans**: Question format: `isOkToArm()`, `canNavigate()`
6. **Constants**: Upper case with underscores: `MAX_GYRO_COUNT`
7. **Macros**: Upper case with underscores: `FASTRAM`, `STATIC_UNIT_TESTED`
### Code Style
- **Indentation**: 4 spaces (no tabs)
- **Braces**: K&R style (opening brace on same line, except for functions)
- **Line Length**: Keep reasonable (typically under 120 characters)
- **Comments**: Explain WHY, not WHAT. Document variables at declaration, not at extern usage
- **Header Guards**: Use `#pragma once` (modern convention used throughout codebase)
### Memory Attributes
INAV uses special memory attributes for performance-critical code on resource-constrained MCUs:
```c
FASTRAM // Fast RAM section (aligned)
EXTENDED_FASTRAM // Extended fast RAM (STM32F4/F7 only)
DMA_RAM // DMA-accessible RAM (STM32H7, AT32F43x)
SLOW_RAM // Slower external RAM - deprecated, o not use
STATIC_FASTRAM // Static variable in fast RAM
STATIC_FASTRAM_UNIT_TESTED // Static fast RAM variable visible in unit tests
```
### Test Visibility Macros
```c
STATIC_UNIT_TESTED // static in production, visible in unit tests
STATIC_INLINE_UNIT_TESTED // static inline in production, visible in tests
INLINE_UNIT_TESTED // inline in production, visible in tests
UNIT_TESTED // Always visible (no storage class)
```
## Build System
### CMake Build Process
INAV uses CMake with custom target definition functions:
1. **Target Definition**: Each board has a `target.h` and optionally `CMakeLists.txt`
2. **Hardware Function**: `target_stm32f405xg(NAME optional_params)`
3. **Build Directory**: Always use out-of-source builds in `/build` directory
### Building a Target
```bash
# From workspace root
cd build
cmake ..
make MATEKF722SE # Build specific target
make # Build all targets
```
### Target Configuration
Targets are defined in `/src/main/target/TARGETNAME/`:
- `target.h`: Hardware pin definitions, feature enables, MCU configuration
- `target.c`: Board-specific initialization code
- `CMakeLists.txt`: Build configuration (optional)
Example target definition:
```c
#define TARGET_BOARD_IDENTIFIER "MF7S"
#define LED0 PA14
#define BEEPER PC13
#define USE_SPI
#define USE_SPI_DEVICE_1
#define SPI1_SCK_PIN PA5
```
### Conditional Compilation
Feature flags control code inclusion:
```c
#ifdef USE_GPS
// GPS code
#endif
#if defined(STM32F4)
// F4-specific code
#elif defined(STM32F7)
// F7-specific code
#endif
```
## Key Concepts
### Parameter Groups (PG)
INAV uses a sophisticated configuration system called "Parameter Groups" for persistent storage:
```c
// Define a configuration structure
typedef struct {
uint8_t gyro_lpf_hz;
uint16_t gyro_kalman_q;
// ...
} gyroConfig_t;
// Register with reset template
PG_REGISTER_WITH_RESET_TEMPLATE(gyroConfig_t, gyroConfig, PG_GYRO_CONFIG, 12);
// Define default values
PG_RESET_TEMPLATE(gyroConfig_t, gyroConfig,
.gyro_lpf_hz = 60,
.gyro_kalman_q = 200,
// ...
);
// Access in code
gyroConfig()->gyro_lpf_hz
```
**Key Functions:**
- `PG_REGISTER_WITH_RESET_TEMPLATE()`: Register with static defaults
- `PG_REGISTER_WITH_RESET_FN()`: Register with function-based initialization
- `PG_REGISTER_ARRAY()`: For arrays of configuration items
- Parameter group IDs are in `config/parameter_group_ids.h`
### Scheduler
INAV uses a priority-based cooperative task scheduler:
```c
typedef enum {
TASK_PRIORITY_IDLE = 0,
TASK_PRIORITY_LOW = 1,
TASK_PRIORITY_MEDIUM = 3,
TASK_PRIORITY_HIGH = 5,
TASK_PRIORITY_REALTIME = 18,
} cfTaskPriority_e;
```
Tasks are defined in `fc/fc_tasks.c` with priority and desired execution period.
### Sensors and Calibration
Sensors use a common pattern:
1. **Detection**: Auto-detect hardware at boot (`gyroDetect()`, `baroDetect()`)
2. **Initialization**: Configure sensor parameters
3. **Calibration**: Zero-offset calibration (gyro, accelerometer)
4. **Data Processing**: Apply calibration, alignment, and filtering
### Flight Control Loop
The main control loop follows this pattern:
1. **Gyro Task** (highest priority): Read gyro, apply filters
2. **PID Task**: Calculate PID corrections
3. **RX Task**: Process radio input
4. **Other Tasks**: Sensors, telemetry, OSD, etc. (lower priority)
### MSP Protocol
MultiWii Serial Protocol is used for configuration and telemetry:
- Request/response model
- Message types defined in `msp/msp_protocol.h`
- Handlers in `fc/fc_msp.c`
## Common Patterns
### Hardware Abstraction
INAV abstracts hardware through resource allocation:
```c
// IO pins
IO_t pin = IOGetByTag(IO_TAG(PA5));
IOInit(pin, OWNER_SPI, RESOURCE_SPI_SCK, 1);
// Timers
const timerHardware_t *timer = timerGetByTag(IO_TAG(PA8), TIM_USE_ANY);
// DMA
dmaIdentifier_e dma = dmaGetIdentifier(DMA1_Stream0);
```
### Error Handling
INAV uses several approaches:
1. **Return codes**: Boolean success/failure or error enums
2. **Diagnostics**: `sensors/diagnostics.c` for sensor health
3. **Status indicators**: Beeper codes, LED patterns for user feedback
4. **Logging**: CLI-based logging system
### Filter Chains
Sensor data typically goes through multiple filtering stages:
```c
// Low-pass filters
gyroLpfApplyFn = lowpassFilterGetApplyFn(filterType);
gyroLpfApplyFn(&gyroLpfState[axis], sample);
// Notch filters (for dynamic filtering)
for (int i = 0; i < dynamicNotchCount; i++) {
sample = biquadFilterApply(&notchFilter[i], sample);
}
```
### Board Alignment
All sensors go through board alignment transforms to correct for mounting orientation:
```c
// Apply board alignment rotation matrix
applySensorAlignment(gyroData, gyroData, gyroAlign);
```
### SITL (Software In The Loop)
INAV can be compiled for host system simulation:
```bash
cmake -DSITL=ON ..
make
```
## Development Workflow
### Branching Strategy
- **`maintenance-X.x`**: Current version development (e.g., `maintenance-9.x`)
- **`maintenance-Y.x`**: Next major version (e.g., `maintenance-10.x`)
- **`master`**: Tracks current version, receives merges from maintenance branches
### Pull Request Guidelines
1. **Target Branch**:
- Bug fixes and backward-compatible features → current maintenance branch
- Breaking changes → next major version maintenance branch
- **Never** target `master` directly
2. **Keep PRs Focused**: One feature/fix per PR
3. **Code Quality**:
- Follow existing code style
- Add unit tests where possible
- Update documentation in `/docs`
- Test on real hardware when possible
4. **Commit Messages**: Clear, descriptive messages
### Important Files to Check
Before making changes, review:
- `docs/development/Development.md` - Development principles
- `docs/development/Contributing.md` - Contribution guidelines
- Target-specific files in `/src/main/target/`
## Important Files and Directories
### Configuration Files
- `platform.h`: Platform-specific includes and defines
- `target.h`: Board-specific hardware configuration
- `config/parameter_group.h`: Parameter group system
- `config/parameter_group_ids.h`: PG ID definitions
- `fc/settings.yaml`: CLI settings definitions
### Core Flight Control
- `fc/fc_core.c`: Main flight control loop
- `fc/fc_init.c`: System initialization
- `fc/fc_tasks.c`: Task scheduler configuration
- `flight/pid.c`: PID controller implementation
- `flight/mixer.c`: Motor mixing
### Key Headers
- `build/build_config.h`: Build-time configuration macros
- `common/axis.h`: Axis definitions (X, Y, Z, ROLL, PITCH, YAW)
- `common/maths.h`: Math utilities and constants
- `common/filter.h`: Digital filter implementations
- `drivers/accgyro/accgyro.h`: Gyro/accelerometer interface
## AI Agent Guidelines
### When Adding Features
1. **Understand the Module**: Read related files in the same directory
2. **Check for Similar Code**: Search for similar features to maintain consistency
3. **Follow Parameter Group Pattern**: New settings should use PG system
4. **Add to Scheduler**: New periodic tasks go in `fc/fc_tasks.c`
5. **Update Documentation**: Add/update files in `/docs`
6. **Consider Target Support**: Use `#ifdef USE_FEATURE` for optional features
7. **Generate CLI setting docs**: Remember to inform user to run `python src/utils/update_cli_docs.py`
8. **Follow conding standard**: Follow MISRA C rules
9. **Increase Paremeterer Group Version**: When changing PG structure, increase version corresponding in `PG_REGISTER`, `PG_REGISTER_WITH_RESET_FN`, `PG_REGISTER_WITH_RESET_TEMPLATE`, `PG_REGISTER_ARRAY` or `PG_REGISTER_ARRAY_WITH_RESET_FN`
### When Fixing Bugs
1. **Review Recent Changes**: Check git history for related modifications
2. **Test Signal Path**: For sensor issues, trace from hardware through filters to consumer
3. **Consider All Platforms**: STM32F4, F7, H7, and AT32 may behave differently
4. **Check Memory Usage**: Embedded system has limited RAM/flash
### When Refactoring
1. **Maintain API Compatibility**: Unless targeting next major version
2. **Preserve Unit Tests**: Update tests to match refactored code
3. **Update Documentation**: Keep docs synchronized with code changes
4. **Consider Performance**: Profile on target hardware, not just host compilation
5. **Check All Callers**: Use grep/search to find all usage sites
### Common Pitfalls to Avoid
1. **Don't Ignore Memory Attributes**: FASTRAM placement affects real-time performance
2. **Don't Break Parameter Groups**: Changing PG structure requires version bump
3. **Don't Assume Hardware**: Always check feature flags (`#ifdef USE_GPS`)
4. **Don't Break MSP**: Changes to MSP protocol affect configurator compatibility
5. **Don't Commit Wrong Branch**: Target maintenance branch, not master
6. **Don't Skip Documentation**: Code without docs increases support burden
7. **Don't Hardcode Values**: Use parameter groups for configurable values
### Searching the Codebase
**Find definitions:**
```bash
grep -r "typedef.*_t" src/main/ # Find all type definitions
grep -r "PG_REGISTER" src/main/ # Find parameter groups
grep -r "TASK_" src/main/ # Find scheduled tasks
```
**Find usage:**
```bash
grep -r "functionName" src/main/
grep -r "USE_GPS" src/main/target/ # Feature support by target
```
**Find similar code:**
- Look in the same directory first
- Check for similar sensor/peripheral implementations
- Review git history: `git log --all --oneline --grep="keyword"`
### Understanding Control Flow
1. **Startup**: `main.c``fc_init.c:init()``fc_tasks.c:tasksInit()`
2. **Main Loop**: `scheduler.c:scheduler()` executes tasks by priority
3. **Critical Path**: Gyro → PID → Mixer → Motors (highest priority)
4. **Configuration**: CLI/MSP → Parameter Groups → EEPROM
### Cross-Platform Considerations
Different MCU families have different characteristics:
- **STM32F4**: Most common, 84-168 MHz, FPU, no cache
- **STM32F7**: Faster, 216 MHz, FPU, I/D cache, requires cache management
- **STM32H7**: Fastest, 480 MHz, more RAM, complex memory architecture (DTCM, SRAM)
- **AT32F43x**: Chinese MCU, STM32F4-compatible, different peripherals
Always test on target or use `#if defined()` guards for MCU-specific code.
## Quick Reference
### File Naming Patterns
- `*_config.h`: Configuration structures (usually with PG)
- `*_impl.h`: Implementation headers (MCU-specific)
- `*_hal.h`: Hardware abstraction layer
- `accgyro_*.c`: Gyro/accelerometer drivers
- `bus_*.c`: Communication bus drivers (SPI, I2C)
### Common Abbreviations
- **FC**: Flight Controller
- **PG**: Parameter Group
- **MSP**: MultiWii Serial Protocol
- **CLI**: Command Line Interface
- **OSD**: On-Screen Display
- **RTH**: Return to Home
- **PID**: Proportional-Integral-Derivative (controller)
- **IMU**: Inertial Measurement Unit (gyro + accel)
- **AHRS**: Attitude and Heading Reference System
- **ESC**: Electronic Speed Controller
- **SITL**: Software In The Loop
- **HITL**: Hardware In The Loop
## Resources
- **Main Repository**: https://github.com/iNavFlight/inav
- **Configurator**: https://github.com/iNavFlight/inav-configurator
- **Discord**: https://discord.gg/peg2hhbYwN
- **Documentation**: https://github.com/iNavFlight/inav/wiki
- **Release Notes**: https://github.com/iNavFlight/inav/releases
## Version Information
This document is accurate for INAV 9.0.1. As the project evolves, some details may change. Always refer to the latest documentation and code for authoritative information.
---
**Remember**: INAV flies aircraft that people build and fly. Code quality, safety, and reliability are paramount. When in doubt, ask the community or maintainers for guidance.
+98
View File
@@ -0,0 +1,98 @@
This is at least a partial credits-file of people that have contributed to the INAV project.
If you believe you should be on this list - feel free to open a PR updating it. For faster
inclusion into this list please provide information about which part of code belongs to you.
Albert Kravcov
Alberto García Hierro
Alex Gorbatchev
Alex Zaitsev
Alexander Fedorov
Alexander van Saase
Alexey Stankevich
Andre Bernet
Andreas Tacke
Andrew Payne
Austin St. Aubin
Bas Huisman
Ben Hitchcock
Boris B
Brnadon Miller
ChiggerPepi
Chris Campbell
Chris Mavrakis
Chris Nisbet
Chris Penny
Damjan Adamic
Darren Lines (Mr.D - RC)
Dave Pitman
David Bieber
Davide Bertola
Denis Kisselev
Dominic Clifton
Frank Zhao
Fredrik Steen
Gareth Wilkins
Gaël James
Gregor Ottmann
Google LLC
Hyon Lim
Hubert Jozwiak
James Harrison
Jan Staal
Jeff Hendrix
Jeremy Waters
Joe Hermaszewski
Joe Poser
Joel Fuster
Johannes Kasberger
Jonas Harnesk
Jonathan Hudson
Joshua Bardwell
Juan González
Kemal Hadimli
Kieran Moore
Konstantin Sharlaimov
Krzysztof Rosinski
Kyle Manna
Larry Davis
Marc Egli
Marcelo Bezerra
Mark Williams
Martin Budden
Matthew Evans
Mauro Mombelli
Max Winterstein
Michael Corcoran
Michael Hope
Michael Jakob
Michel Pastor
Miha Valencic
Mikael Blomqvist
Moritz Ulrich
Moshen Chan
Nathan Tsoi
Nicholas Sherlock
Paul Fertser
Paul Rogalinski
Pawel Spychalski
Petr Ledvina
Phillip Jones
Pierre Hugo
Richard Birkby
Richard Lehey
Richard Marko
Ray Morris (Sensei)
Rimas Avizienis
Sam Cook
Sami Korhonen
Samuel Brucksch
Scott Shawcroft
Sean Vig
Stefan Grufman
Stefan Haubold
Steve Amor
Thomas Buck
Tim Eckel
Trey Marc
Tuomas Kuosmanen
Zap Andersson
+101
View File
@@ -0,0 +1,101 @@
cmake_minimum_required(VERSION 3.13...3.18)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
set(MAIN_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
set(MAIN_LIB_DIR "${CMAKE_CURRENT_SOURCE_DIR}/lib")
set(MAIN_UTILS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src/utils")
set(MAIN_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src/main")
set(SVD_DIR "${CMAKE_CURRENT_SOURCE_DIR}/dev/svd")
set(DOWNLOADS_DIR "${MAIN_DIR}/downloads")
set(TOOLS_DIR "${MAIN_DIR}/tools")
option(SITL "SITL build for host system" OFF)
set(TOOLCHAIN_OPTIONS none arm-none-eabi host)
if (SITL)
if (CMAKE_HOST_APPLE)
set(MACOSX TRUE)
endif()
set(TOOLCHAIN "host" CACHE STRING "Toolchain to use. Available: ${TOOLCHAIN_OPTIONS}")
else()
set(TOOLCHAIN "arm-none-eabi" CACHE STRING "Toolchain to use. Available: ${TOOLCHAIN_OPTIONS}")
endif()
set_property(CACHE TOOLCHAIN PROPERTY STRINGS ${TOOLCHAIN_OPTIONS})
if("" STREQUAL TOOLCHAIN)
set(TOOLCHAIN none)
endif()
if (NOT ${TOOLCHAIN} IN_LIST TOOLCHAIN_OPTIONS)
message(FATAL_ERROR "Invalid toolchain ${TOOLCHAIN}. Valid options are: ${TOOLCHAIN_OPTIONS}")
endif()
option(COMPILER_VERSION_CHECK "Ensure the compiler matches the expected version" ON)
include(GetGitRevisionDescription)
get_git_head_revision(GIT_REFSPEC GIT_SHA1)
string(SUBSTRING ${GIT_SHA1} 0 8 GIT_REV)
# Load settings related functions, so the tests can use them
include(main)
include(settings)
if(TOOLCHAIN STREQUAL none)
add_subdirectory(src/test)
else()
if (SITL)
include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/${TOOLCHAIN}.cmake")
else()
set(CMAKE_TOOLCHAIN_FILE "${CMAKE_CURRENT_SOURCE_DIR}/cmake/${TOOLCHAIN}.cmake")
include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/${TOOLCHAIN}-checks.cmake")
endif()
endif()
project(INAV VERSION 9.1.0)
enable_language(ASM)
if(MACOSX AND SITL)
set(CMAKE_C_STANDARD 11)
else()
set(CMAKE_C_STANDARD 99)
endif()
set(CMAKE_C_EXTENSIONS ON)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_EXTENSIONS ON)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
if(CMAKE_BUILD_TYPE STREQUAL "Release" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
set(IS_RELEASE_BUILD ON)
endif()
set(FIRMWARE_VERSION ${PROJECT_VERSION})
option(WARNINGS_AS_ERRORS "Make all warnings into errors")
message("-- toolchain: ${TOOLCHAIN}, WARNINGS_AS_ERRORS: ${WARNINGS_AS_ERRORS}")
set(COMMON_COMPILE_DEFINITIONS
FC_VERSION_MAJOR=${CMAKE_PROJECT_VERSION_MAJOR}
FC_VERSION_MINOR=${CMAKE_PROJECT_VERSION_MINOR}
FC_VERSION_PATCH_LEVEL=${CMAKE_PROJECT_VERSION_PATCH}
FC_VERSION_TYPE="${VERSION_TYPE}"
)
if (NOT SITL)
include(openocd)
include(svd)
endif()
include(stm32)
include(at32)
include(sitl)
add_subdirectory(src)
collect_targets()
message("-- Build type: ${CMAKE_BUILD_TYPE}")
include(ci)
+23
View File
@@ -0,0 +1,23 @@
FROM ubuntu:jammy
ARG USER_ID
ARG GROUP_ID
ARG GDB
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y git cmake make ruby gcc python3 python3-yaml ninja-build gcc-arm-none-eabi
RUN if [ "$GDB" = "yes" ]; then apt-get install -y gdb; fi
# If a group and user with the same IDs already exist, rename the group and recreate the user after deleting the existing one.
RUN GROUP="$(id -n -g $GROUP_ID)"; if [ -n "$GROUP" ]; then groupmod -n inav "$GROUP"; else groupadd --gid $GROUP_ID inav; fi
RUN USER="$(id -n -u $USER_ID)"; if [ -n "$USER" ]; then userdel -r "$USER"; fi && useradd -m --uid $USER_ID --gid $GROUP_ID inav
USER inav
RUN git config --global --add safe.directory /src
WORKDIR /src/build
ENTRYPOINT ["/src/cmake/docker.sh"]
+31
View File
@@ -0,0 +1,31 @@
[BREAKPOINTS]
ShowInfoWin = 1
EnableFlashBP = 2
BPDuringExecution = 0
[CFI]
CFISize = 0x00
CFIAddr = 0x00
[CPU]
OverrideMemMap = 0
AllowSimulation = 1
ScriptFile=""
[FLASH]
MinNumBytesFlashDL = 0
SkipProgOnCRCMatch = 1
VerifyDownload = 1
AllowCaching = 1
EnableFlashDL = 2
Override = 0
Device="AD7160"
[GENERAL]
WorkRAMSize = 0x00
WorkRAMAddr = 0x00
[SWO]
SWOLogFile=""
[MEM]
RdOverrideOrMask = 0x00
RdOverrideAndMask = 0xFFFFFFFF
RdOverrideAddr = 0xFFFFFFFF
WrOverrideOrMask = 0x00
WrOverrideAndMask = 0xFFFFFFFF
WrOverrideAddr = 0xFFFFFFFF
+674
View File
@@ -0,0 +1,674 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
Vendored
+32
View File
@@ -0,0 +1,32 @@
# -*- mode: ruby -*-
# vi: set ft=ruby :
# All Vagrant configuration is done below. The "2" in Vagrant.configure
# configures the configuration version (we support older styles for
# backwards compatibility). Please don't change it unless you know what
# you're doing.
Vagrant.configure(2) do |config|
# The most common configuration options are documented and commented below.
# For a complete reference, please see the online documentation at
# https://docs.vagrantup.com.
# Every Vagrant development environment requires a box. You can search for
# boxes at https://atlas.hashicorp.com/search.
config.vm.box = "ubuntu/trusty64"
config.vm.synced_folder ".", "/home/vagrant/inav"
config.vm.hostname = "iNavDev"
config.vm.define "iNavDev"
config.vm.provider :virtualbox do |vb|
vb.name = "iNavDev"
end
# Enable provisioning with a shell script. Additional provisioners such as
# Puppet, Chef, Ansible, Salt, and Docker are also available. Please see the
# documentation for more information about their specific syntax and use.
config.vm.provision "shell", inline: <<-SHELL
sudo apt-get remove -y --force-yes gcc-arm-none-eabi ruby
sudo apt-add-repository ppa:brightbox/ruby-ng
sudo add-apt-repository ppa:team-gcc-arm-embedded/ppa
sudo apt-get update
sudo apt-get install -y --force-yes git gcc-arm-embedded ruby2.4 ruby2.4-dev
SHELL
end
+9
View File
@@ -0,0 +1,9 @@
# Boardconfig for AT-LINK for AT32F4-FC
source [find interface/atlink.cfg]
#transport select hla_swd
source [find target/at32f437xM.cfg]
reset_config none separate
+9
View File
@@ -0,0 +1,9 @@
# Boardconfig for ST-Link/V2 with F4-FC
source [find interface/stlink.cfg]
transport select hla_swd
source [find target/stm32f4x.cfg]
reset_config none separate
+9
View File
@@ -0,0 +1,9 @@
# Boardconfig for ST-Link/V2 with F7-FC
source [find interface/stlink.cfg]
transport select hla_swd
source [find target/stm32f7x.cfg]
reset_config none separate
+9
View File
@@ -0,0 +1,9 @@
# Boardconfig for ST-Link/V2 with H7-FC
source [find interface/stlink.cfg]
transport select hla_swd
source [find target/stm32h7x_dual_bank.cfg]
reset_config none separate
Executable
+73
View File
@@ -0,0 +1,73 @@
#!/usr/bin/env bash
set -euo pipefail
if [[ $# == 0 ]]; then
echo -e "\
Usage syntax: ./build.sh <TARGET>
Notes:
* You can specify multiple targets.
./build.sh <TARGET_1> <TARGET_2> <TARGET_N>
* To get a list of release targets use \"release_targets\"
./build.sh release_targets
* To get a list of valid targets use \"valid_targets\"
./build.sh valid_targets
* To get a list of all targets use \"help\". Hint: pipe the output through a pager.
./build.sh help | less
* To build all targets use \"all\"
./build.sh all
* To clean a target prefix it with \"clean_\".
./build.sh clean_MATEKF405SE
* To clean all targets just use \"clean\".
./build.sh clean"
exit 1
fi
run_docker() {
docker run --rm -it -v "$(pwd)":/src inav-build "$@"
}
if [ -z "$(docker images -q inav-build)" ]; then
echo "*** Building Docker image"
docker build -t inav-build \
--build-arg USER_ID="$(id -u)" \
--build-arg GROUP_ID="$(id -g)" .
else
docker build -q -t inav-build \
--build-arg USER_ID="$(id -u)" \
--build-arg GROUP_ID="$(id -g)" . >/dev/null ||
{ echo "*** Building Docker image: ERROR"; exit 1; }
fi
if [ ! -d ./build ]; then
echo -e "*** Creating build directory\n"
mkdir ./build && chmod 777 ./build
fi
if [ ! -d ./downloads ]; then
echo -e "*** Creating downloads directory\n"
mkdir ./downloads && chmod 777 ./downloads
fi
if [ ! -d ./tools ]; then
echo -e "*** Creating tools directory\n"
mkdir ./tools && chmod 777 ./tools
fi
case "$1" in
release_targets)
run_docker targets | sed -n 's/^Release targets: \(.*\)/\1/p'|tr ' ' '\n'
;;
valid_targets)
run_docker targets | sed -n 's/^Valid targets: \(.*\)/\1/p'|tr ' ' '\n'
;;
*)
echo -e "*** Building targets [$@]\n"
run_docker "$@"
if ls ./build/*.hex &> /dev/null; then
echo -e "\n*** Built targets in ./build:"
stat -c "%n (%.19y)" ./build/*.hex
fi
;;
esac
Executable
+59
View File
@@ -0,0 +1,59 @@
#!/bin/bash
filename=Manual
doc_files=(
'Introduction.md'
'Getting Started.md'
'Safety.md'
'Installation.md'
'Configuration.md'
'Cli.md'
'Serial.md'
'Rx.md'
'Spektrum bind.md'
'Failsafe.md'
'Battery.md'
'Gps.md'
'Rssi.md'
'Telemetry.md'
'LedStrip.md'
'Display.md'
'Buzzer.md'
'Sonar.md'
'Profiles.md'
'Inflight Adjustments.md'
'Controls.md'
'Gtune.md'
'Blackbox.md'
'Migrating from baseflight.md'
'Boards.md'
'Board - AlienFlight.md'
'Board - ColibriRace.md'
'Board - Motolab.md'
'Board - Paris Air Hero 32.md'
'Board - Sparky.md'
'Board - RMDO.md'
'Board - SPRacingF3.md'
)
if which gimli >/dev/null; then
echo "Building ${filename}.pdf"
pushd . >/dev/null
cd docs
rm -f ${filename}.md
for i in "${doc_files[@]}"
do
cat "$i" >> ${filename}.md
done
rm -f ${filename}.pdf
gimli -f ${filename}.md -stylesheet override.css \
-w '--toc --title "INAV Manual" --footer-right "[page]" --toc-depth 1'
rm ${filename}.md
popd >/dev/null
else
echo -e "\nFAILED"
echo "Install Gimli to build the PDF documentation"
echo -e "https://github.com/walle/gimli\n"
exit 1
fi
+172
View File
@@ -0,0 +1,172 @@
# - Returns a version string from Git
#
# These functions force a re-configure on each git commit so that you can
# trust the values of the variables in your build system.
#
# get_git_head_revision(<refspecvar> <hashvar> [<additional arguments to git describe> ...])
#
# Returns the refspec and sha hash of the current head revision
#
# git_describe(<var> [<additional arguments to git describe> ...])
#
# Returns the results of git describe on the source tree, and adjusting
# the output so that it tests false if an error occurs.
#
# git_get_exact_tag(<var> [<additional arguments to git describe> ...])
#
# Returns the results of git describe --exact-match on the source tree,
# and adjusting the output so that it tests false if there was no exact
# matching tag.
#
# git_local_changes(<var>)
#
# Returns either "CLEAN" or "DIRTY" with respect to uncommitted changes.
# Uses the return code of "git diff-index --quiet HEAD --".
# Does not regard untracked files.
#
# Requires CMake 2.6 or newer (uses the 'function' command)
#
# Original Author:
# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
# http://academic.cleardefinition.com
# Iowa State University HCI Graduate Program/VRAC
#
# Copyright Iowa State University 2009-2010.
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt)
if(__get_git_revision_description)
return()
endif()
set(__get_git_revision_description YES)
# We must run the following at "include" time, not at function call time,
# to find the path to this module rather than the path to a calling list file
get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH)
function(get_git_head_revision _refspecvar _hashvar)
set(GIT_PARENT_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
set(GIT_DIR "${GIT_PARENT_DIR}/.git")
while(NOT EXISTS "${GIT_DIR}") # .git dir not found, search parent directories
set(GIT_PREVIOUS_PARENT "${GIT_PARENT_DIR}")
get_filename_component(GIT_PARENT_DIR ${GIT_PARENT_DIR} PATH)
if(GIT_PARENT_DIR STREQUAL GIT_PREVIOUS_PARENT)
# We have reached the root directory, we are not in git
set(${_refspecvar} "GITDIR-NOTFOUND" PARENT_SCOPE)
set(${_hashvar} "GITDIR-NOTFOUND" PARENT_SCOPE)
return()
endif()
set(GIT_DIR "${GIT_PARENT_DIR}/.git")
endwhile()
# check if this is a submodule
if(NOT IS_DIRECTORY ${GIT_DIR})
file(READ ${GIT_DIR} submodule)
string(REGEX REPLACE "gitdir: (.*)\n$" "\\1" GIT_DIR_RELATIVE ${submodule})
get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH)
get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE} ABSOLUTE)
endif()
if(NOT IS_DIRECTORY "${GIT_DIR}")
file(READ ${GIT_DIR} worktree)
string(REGEX REPLACE "gitdir: (.*)worktrees(.*)\n$" "\\1" GIT_DIR ${worktree})
endif()
set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data")
if(NOT EXISTS "${GIT_DATA}")
file(MAKE_DIRECTORY "${GIT_DATA}")
endif()
if(NOT EXISTS "${GIT_DIR}/HEAD")
return()
endif()
set(HEAD_FILE "${GIT_DATA}/HEAD")
configure_file("${GIT_DIR}/HEAD" "${HEAD_FILE}" COPYONLY)
configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in"
"${GIT_DATA}/grabRef.cmake"
@ONLY)
include("${GIT_DATA}/grabRef.cmake")
set(${_refspecvar} "${HEAD_REF}" PARENT_SCOPE)
set(${_hashvar} "${HEAD_HASH}" PARENT_SCOPE)
endfunction()
function(git_describe _var)
if(NOT GIT_FOUND)
find_package(Git QUIET)
endif()
get_git_head_revision(refspec hash)
if(NOT GIT_FOUND)
set(${_var} "GIT-NOTFOUND" PARENT_SCOPE)
return()
endif()
if(NOT hash)
set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE)
return()
endif()
# TODO sanitize
#if((${ARGN}" MATCHES "&&") OR
# (ARGN MATCHES "||") OR
# (ARGN MATCHES "\\;"))
# message("Please report the following error to the project!")
# message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}")
#endif()
#message(STATUS "Arguments to execute_process: ${ARGN}")
execute_process(COMMAND
"${GIT_EXECUTABLE}"
describe
${hash}
${ARGN}
WORKING_DIRECTORY
"${CMAKE_CURRENT_SOURCE_DIR}"
RESULT_VARIABLE
res
OUTPUT_VARIABLE
out
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE)
if(NOT res EQUAL 0)
set(out "${out}-${res}-NOTFOUND")
endif()
set(${_var} "${out}" PARENT_SCOPE)
endfunction()
function(git_get_exact_tag _var)
git_describe(out --exact-match ${ARGN})
set(${_var} "${out}" PARENT_SCOPE)
endfunction()
function(git_local_changes _var)
if(NOT GIT_FOUND)
find_package(Git QUIET)
endif()
get_git_head_revision(refspec hash)
if(NOT GIT_FOUND)
set(${_var} "GIT-NOTFOUND" PARENT_SCOPE)
return()
endif()
if(NOT hash)
set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE)
return()
endif()
execute_process(COMMAND
"${GIT_EXECUTABLE}"
diff-index --quiet HEAD --
WORKING_DIRECTORY
"${CMAKE_CURRENT_SOURCE_DIR}"
RESULT_VARIABLE
res
OUTPUT_VARIABLE
out
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE)
if(res EQUAL 0)
set(${_var} "CLEAN" PARENT_SCOPE)
else()
set(${_var} "DIRTY" PARENT_SCOPE)
endif()
endfunction()
+41
View File
@@ -0,0 +1,41 @@
#
# Internal file for GetGitRevisionDescription.cmake
#
# Requires CMake 2.6 or newer (uses the 'function' command)
#
# Original Author:
# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
# http://academic.cleardefinition.com
# Iowa State University HCI Graduate Program/VRAC
#
# Copyright Iowa State University 2009-2010.
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt)
set(HEAD_HASH)
file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024)
string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS)
if(HEAD_CONTENTS MATCHES "ref")
# named branch
string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}")
if(EXISTS "@GIT_DIR@/${HEAD_REF}")
configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
else()
configure_file("@GIT_DIR@/packed-refs" "@GIT_DATA@/packed-refs" COPYONLY)
file(READ "@GIT_DATA@/packed-refs" PACKED_REFS)
if(${PACKED_REFS} MATCHES "([0-9a-z]*) ${HEAD_REF}")
set(HEAD_HASH "${CMAKE_MATCH_1}")
endif()
endif()
else()
# detached HEAD
configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY)
endif()
if(NOT HEAD_HASH)
file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024)
string(STRIP "${HEAD_HASH}" HEAD_HASH)
endif()
+150
View File
@@ -0,0 +1,150 @@
include(gcc)
set(arm_none_eabi_triplet "arm-none-eabi")
# Keep version in sync with the distribution files below
set(arm_none_eabi_gcc_version "13.2.1")
# This is the output directory "pretty" name and URI name prefix
set(base_dir_name "arm-gnu-toolchain-13.2.rel1")
# This is the name inside the archive, which is no longer evincible from URI, alas
set(archive_base_dir_name "arm-gnu-toolchain-13.2.Rel1")
set(arm_none_eabi_base_url "https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel/${base_dir_name}")
# suffix and checksum
set(arm_none_eabi_win32 "mingw-w64-i686-arm-none-eabi.zip" 7fd677088038cdf82f33f149e2e943ee)
set(arm_none_eabi_linux_amd64 "x86_64-arm-none-eabi.tar.xz" 791754852f8c18ea04da7139f153a5b7)
set(arm_none_eabi_linux_aarch64 "aarch64-arm-none-eabi.tar.xz" 5a08122e6d4caf97c6ccd1d29e62599c)
set(arm_none_eabi_darwin_amd64 "darwin-x86_64-arm-none-eabi.tar.xz" 41d49840b0fc676d2ae35aab21a58693)
set(arm_none_eabi_darwin_aarch64 "darwin-arm64-arm-none-eabi.tar.xz" 2c43e9d72206c1f81227b0a685df5ea6)
function(host_uname_machine var)
# We need to call uname -m manually, since at the point
# this file is included CMAKE_HOST_SYSTEM_PROCESSOR is
# empty because we haven't called project() yet.
execute_process(COMMAND uname -m
OUTPUT_STRIP_TRAILING_WHITESPACE
OUTPUT_VARIABLE machine)
set(${var} ${machine} PARENT_SCOPE)
endfunction()
function(arm_none_eabi_gcc_install)
set(dist "")
if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
set(dist ${arm_none_eabi_win32})
elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux" OR CMAKE_HOST_SYSTEM_NAME STREQUAL "FreeBSD")
if(NOT CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux")
message("-- no compiler binaries available for ${CMAKE_HOST_SYSTEM_NAME}, using Linux binaries as a fallback")
endif()
host_uname_machine(machine)
# Linux returns x86_64, FreeBSD returns amd64
if(machine STREQUAL "x86_64" OR machine STREQUAL "amd64")
set(dist ${arm_none_eabi_linux_amd64})
elseif(machine STREQUAL "aarch64")
set(dist ${arm_none_eabi_linux_aarch64})
else()
message("-- no precompiled ${arm_none_eabi_triplet} toolchain for machine ${machine}")
endif()
elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
host_uname_machine(machine)
if(machine STREQUAL "x86_64" OR machine STREQUAL "amd64")
set(dist ${arm_none_eabi_darwin_amd64})
elseif(machine STREQUAL "aarch64" OR machine STREQUAL "arm64")
set(dist ${arm_none_eabi_darwin_aarch64})
else()
message("-- no precompiled ${arm_none_eabi_triplet} toolchain for machine ${machine}")
endif()
endif()
if(dist STREQUAL "")
message(FATAL_ERROR "could not install ${arm_none_eabi_triplet}-gcc automatically")
endif()
list(GET dist 0 dist_suffix)
list(GET dist 1 dist_checksum)
set(dist_url "${arm_none_eabi_base_url}-${dist_suffix}")
string(REPLACE "/" ";" url_parts ${dist_url})
list(LENGTH url_parts n)
math(EXPR last "${n} - 1")
list(GET url_parts ${last} basename)
set(output "${DOWNLOADS_DIR}/${basename}")
message("-- downloading ${arm_none_eabi_triplet}-gcc ${arm_none_eabi_gcc_version} from ${dist_url}")
file(DOWNLOAD ${dist_url} ${output}
INACTIVITY_TIMEOUT 30
STATUS status
SHOW_PROGRESS
EXPECTED_HASH MD5=${dist_checksum}
TLS_VERIFY ON
)
list(GET status 0 status_code)
if(NOT status_code EQUAL 0)
list(GET status 1 status_message)
message(FATAL_ERROR "error downloading ${basename}: ${status_message}")
endif()
message("-- extracting ${basename}")
execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${TOOLS_DIR})
execute_process(COMMAND ${CMAKE_COMMAND} -E tar xf ${output}
RESULT_VARIABLE status
WORKING_DIRECTORY ${TOOLS_DIR}
)
if(NOT status EQUAL 0)
message(FATAL_ERROR "error extracting ${basename}: ${status}")
endif()
string(REPLACE "." ";" url_parts ${dist_suffix})
list(GET url_parts 0 host_dir_name)
set(dir_name "${archive_base_dir_name}-${host_dir_name}")
file(REMOVE_RECURSE "${TOOLS_DIR}/${base_dir_name}")
file(RENAME "${TOOLS_DIR}/${dir_name}" "${TOOLS_DIR}/${base_dir_name}")
# This is **somewhat ugly**
# the newlib distributed by ARM generates suprious warnings from re-entrant POSIX functions
# that INAV doesn't use. These "harmless" warnings can be surpressed by removing the
# errant section from the only libnosys used by INAV ...
# So look the other way ... while this is "fixed"
execute_process(COMMAND arm-none-eabi-objcopy -w -R .gnu.warning.* "${TOOLS_DIR}/${base_dir_name}/arm-none-eabi/lib/thumb/v7e-m+fp/hard/libnosys.a"
RESULT_VARIABLE status
WORKING_DIRECTORY ${TOOLS_DIR}
)
if(NOT status EQUAL 0)
message(FATAL_ERROR "error fixing libnosys.a: ${status}")
endif()
endfunction()
function(arm_none_eabi_gcc_add_path)
set(gcc_path "${TOOLS_DIR}/${base_dir_name}/bin")
if(CMAKE_HOST_SYSTEM MATCHES ".*Windows.*")
set(sep "\\;")
else()
set(sep ":")
endif()
set(ENV{PATH} "${gcc_path}${sep}$ENV{PATH}")
endfunction()
function(arm_none_eabi_gcc_check)
gcc_get_version(version
TRIPLET ${arm_none_eabi_triplet}
PROGRAM_NAME prog
PROGRAM_PATH prog_path
)
if(NOT version)
message("-- could not find ${prog}")
arm_none_eabi_gcc_install()
gcc_get_version(version
TRIPLET ${arm_none_eabi_triplet}
PROGRAM_NAME prog
PROGRAM_PATH prog_path
)
return()
endif()
message("-- found ${prog} ${version} at ${prog_path}")
if(COMPILER_VERSION_CHECK AND NOT arm_none_eabi_gcc_version STREQUAL version)
message("-- expecting ${prog} version ${arm_none_eabi_gcc_version}, but got version ${version} instead")
arm_none_eabi_gcc_install()
unset(gcc CACHE)
gcc_get_version(version
TRIPLET ${arm_none_eabi_triplet}
PROGRAM_NAME prog
PROGRAM_PATH prog_path
)
return()
endif()
endfunction()
arm_none_eabi_gcc_add_path()
arm_none_eabi_gcc_check()
+48
View File
@@ -0,0 +1,48 @@
set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_PROCESSOR arm)
if(WIN32)
set(TOOL_EXECUTABLE_SUFFIX ".exe")
endif()
set(TARGET_TRIPLET "arm-none-eabi")
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
set(CMAKE_ASM_COMPILER "${TARGET_TRIPLET}-gcc${TOOL_EXECUTABLE_SUFFIX}" CACHE INTERNAL "asm compiler")
set(CMAKE_C_COMPILER "${TARGET_TRIPLET}-gcc${TOOL_EXECUTABLE_SUFFIX}" CACHE INTERNAL "c compiler")
set(CMAKE_CXX_COMPILER "${TARGET_TRIPLET}-g++${TOOL_EXECUTABLE_SUFFIX}" CACHE INTERNAL "c++ compiler")
set(CMAKE_OBJCOPY "${TARGET_TRIPLET}-objcopy${TOOL_EXECUTABLE_SUFFIX}" CACHE INTERNAL "objcopy tool")
set(CMAKE_OBJDUMP "${TARGET_TRIPLET}-objdump${TOOL_EXECUTABLE_SUFFIX}" CACHE INTERNAL "objdump tool")
set(CMAKE_SIZE "${TARGET_TRIPLET}-size${TOOL_EXECUTABLE_SUFFIX}" CACHE INTERNAL "size tool")
set(CMAKE_DEBUGGER "${TARGET_TRIPLET}-gdb${TOOL_EXECUTABLE_SUFFIX}" CACHE INTERNAL "debugger")
set(CMAKE_CPPFILT "${TARGET_TRIPLET}-c++filt${TOOL_EXECUTABLE_SUFFIX}" CACHE INTERNAL "c++filt")
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_EXECUTABLE_SUFFIX ".elf")
if(NOT CMAKE_CONFIGURATION_TYPES)
set(CMAKE_CONFIGURATION_TYPES Debug Release RelWithDebInfo)
endif()
if(CMAKE_BUILD_TYPE STREQUAL "")
set(CMAKE_BUILD_TYPE RelWithDebInfo)
endif()
set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "Build Type" FORCE)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS ${CMAKE_CONFIGURATION_TYPES})
set(arm_none_eabi_debug "-Og -g")
# We set -Os or -O2 depending on the MCU family
set(arm_none_eabi_release "-DNDEBUG")
set(arm_none_eabi_relwithdebinfo "-ggdb3 ${arm_none_eabi_release}")
set(CMAKE_C_FLAGS_DEBUG ${arm_none_eabi_debug} CACHE INTERNAL "c compiler flags debug")
set(CMAKE_CXX_FLAGS_DEBUG ${arm_none_eabi_debug} CACHE INTERNAL "c++ compiler flags debug")
set(CMAKE_ASM_FLAGS_DEBUG ${arm_none_eabi_debug} CACHE INTERNAL "asm compiler flags debug")
set(CMAKE_C_FLAGS_RELEASE ${arm_none_eabi_release} CACHE INTERNAL "c compiler flags release")
set(CMAKE_CXX_FLAGS_RELEASE ${arm_none_eabi_release} CACHE INTERNAL "cxx compiler flags release")
set(CMAKE_ASM_FLAGS_RELEASE ${arm_none_eabi_release} CACHE INTERNAL "asm compiler flags release")
set(CMAKE_C_FLAGS_RELWITHDEBINFO ${arm_none_eabi_relwithdebinfo} CACHE INTERNAL "c compiler flags release")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO ${arm_none_eabi_relwithdebinfo} CACHE INTERNAL "cxx compiler flags release")
set(CMAKE_ASM_FLAGS_RELWITHDEBINFO ${arm_none_eabi_relwithdebinfo} CACHE INTERNAL "asm compiler flags release")
+33
View File
@@ -0,0 +1,33 @@
main_sources(BOOTLOADER_SOURCES
common/log.c
common/log.h
common/printf.c
common/printf.h
common/string_light.c
common/string_light.h
common/typeconversion.c
common/typeconversion.h
drivers/bus.c
drivers/bus_busdev_i2c.c
drivers/bus_busdev_spi.c
drivers/bus_i2c_soft.c
drivers/io.c
drivers/light_led.c
drivers/persistent.c
drivers/rcc.c
drivers/serial.c
drivers/system.c
drivers/time.c
drivers/timer.c
drivers/flash_m25p16.c
drivers/flash_w25n.c
drivers/flash.c
fc/firmware_update_common.c
fc/firmware_update_common.h
target/common_hardware.c
)
list(APPEND BOOTLOADER_SOURCES ${MAIN_DIR}/src/bl/bl_main.c)
+4
View File
@@ -0,0 +1,4 @@
main_sources(AT32_STDPERIPH_SRC
drivers/bus_spi_at32f43x.c
drivers/serial_uart_hal_at32f43x.c
)
+442
View File
@@ -0,0 +1,442 @@
include(at32-bootloader)
include(at32f4)
include(CMakeParseArguments)
option(DEBUG_HARDFAULTS "Enable debugging of hard faults via custom handler")
option(SEMIHOSTING "Enable semihosting")
message("-- DEBUG_HARDFAULTS: ${DEBUG_HARDFAULTS}, SEMIHOSTING: ${SEMIHOSTING}")
set(CMSIS_DIR "${MAIN_LIB_DIR}/lib/main/AT32F43x/Drivers/CMSIS")
set(CMSIS_INCLUDE_DIR "${CMSIS_DIR}/cm4/core_support")
# DSP use common
set(CMSIS_DSP_DIR "${MAIN_LIB_DIR}/main/CMSIS/DSP")
set(CMSIS_DSP_INCLUDE_DIR "${CMSIS_DSP_DIR}/Include")
set(CMSIS_DSP_SRC
BasicMathFunctions/arm_scale_f32.c
BasicMathFunctions/arm_sub_f32.c
BasicMathFunctions/arm_mult_f32.c
BasicMathFunctions/arm_offset_f32.c
TransformFunctions/arm_rfft_fast_f32.c
TransformFunctions/arm_cfft_f32.c
TransformFunctions/arm_rfft_fast_init_f32.c
TransformFunctions/arm_cfft_radix8_f32.c
TransformFunctions/arm_bitreversal2.S
CommonTables/arm_common_tables.c
ComplexMathFunctions/arm_cmplx_mag_f32.c
StatisticsFunctions/arm_max_f32.c
StatisticsFunctions/arm_rms_f32.c
StatisticsFunctions/arm_std_f32.c
StatisticsFunctions/arm_mean_f32.c
)
list(TRANSFORM CMSIS_DSP_SRC PREPEND "${CMSIS_DSP_DIR}/Source/")
set(AT32_STARTUP_DIR "${MAIN_SRC_DIR}/startup")
main_sources(AT32_VCP_SRC
drivers/serial_usb_vcp_at32f43x.c
drivers/usb_io.c
)
# SDCARD not supported yet
main_sources(AT32_SDCARD_SRC
drivers/sdcard/sdcard.c
drivers/sdcard/sdcard_spi.c
drivers/sdcard/sdcard_sdio.c
drivers/sdcard/sdcard_standard.c
)
# XXX: This code is not STM32 specific
main_sources(AT32_ASYNCFATFS_SRC
io/asyncfatfs/asyncfatfs.c
io/asyncfatfs/fat_standard.c
)
main_sources(AT32_MSC_SRC
msc/at32_msc_diskio.c
msc/emfat.c
msc/emfat_file.c
)
set(AT32_INCLUDE_DIRS
"${CMSIS_INCLUDE_DIR}"
"${CMSIS_DSP_INCLUDE_DIR}"
"${MAIN_SRC_DIR}/target"
)
set(AT32_DEFINITIONS
)
set(AT32_DEFAULT_HSE_MHZ 8)
set(AT32_LINKER_DIR "${MAIN_SRC_DIR}/target/link")
set(AT32_COMPILE_OPTIONS
-ffunction-sections
-fdata-sections
-fno-common
)
set(AT32_LINK_LIBRARIES
-lm
-lc
)
if(SEMIHOSTING)
list(APPEND AT32_LINK_LIBRARIES --specs=rdimon.specs -lrdimon)
list(APPEND AT32_DEFINITIONS SEMIHOSTING)
else()
list(APPEND AT32_LINK_LIBRARIES -lnosys)
endif()
set(AT32_LINK_OPTIONS
#-nostartfiles
--specs=nano.specs
-static
-Wl,-gc-sections
-Wl,-L${AT32_LINKER_DIR}
-Wl,--cref
-Wl,--no-wchar-size-warning
-Wl,--print-memory-usage
-Wl,--no-warn-rwx-segments
)
# Get target features
macro(get_at32_target_features output_var dir target_name)
execute_process(COMMAND "${CMAKE_C_COMPILER}" -E -dD -D${ARGV2} "${ARGV1}/target.h"
ERROR_VARIABLE _errors
RESULT_VARIABLE _result
OUTPUT_STRIP_TRAILING_WHITESPACE
OUTPUT_VARIABLE _contents)
if(NOT _result EQUAL 0)
message(FATAL_ERROR "error extracting features for AT32 target ${ARGV2}: ${_errors}")
endif()
string(REGEX MATCH "#define[\t ]+USE_VCP" HAS_VCP ${_contents})
if(HAS_VCP)
list(APPEND ${ARGV0} VCP)
endif()
string(REGEX MATCH "define[\t ]+USE_FLASHFS" HAS_FLASHFS ${_contents})
if(HAS_FLASHFS)
list(APPEND ${ARGV0} FLASHFS)
endif()
string(REGEX MATCH "define[\t ]+USE_SDCARD" HAS_SDCARD ${_contents})
if (HAS_SDCARD)
list(APPEND ${ARGV0} SDCARD)
string(REGEX MATCH "define[\t ]+USE_SDCARD_SDIO" HAS_SDIO ${_contents})
if (HAS_SDIO)
list(APPEND ${ARGV0} SDIO)
endif()
endif()
if(HAS_FLASHFS OR HAS_SDCARD)
list(APPEND ${ARGV0} MSC)
endif()
endmacro()
function(get_at32_flash_size out size)
# 4: 16, 6: 32, 8: 64, B: 128, C: 256, D: 384, E: 512, F: 768, G: 1024, H: 1536, I: 2048 KiB
string(TOUPPER ${size} s)
if(${s} STREQUAL "4")
set(${out} 16 PARENT_SCOPE)
return()
endif()
if(${s} STREQUAL "6")
set(${out} 32 PARENT_SCOPE)
return()
endif()
if(${s} STREQUAL "8")
set(${out} 64 PARENT_SCOPE)
return()
endif()
if(${s} STREQUAL "8")
set(${out} 64 PARENT_SCOPE)
return()
endif()
if(${s} STREQUAL "B")
set(${out} 128 PARENT_SCOPE)
return()
endif()
if(${s} STREQUAL "C")
set(${out} 256 PARENT_SCOPE)
return()
endif()
if(${s} STREQUAL "D")
set(${out} 384 PARENT_SCOPE)
return()
endif()
if(${s} STREQUAL "E")
set(${out} 512 PARENT_SCOPE)
return()
endif()
if(${s} STREQUAL "F")
set(${out} 768 PARENT_SCOPE)
return()
endif()
if(${s} STREQUAL "G")
set(${out} 1024 PARENT_SCOPE)
return()
endif()
if(${s} STREQUAL "H")
set(${out} 1536 PARENT_SCOPE)
return()
endif()
if(${s} STREQUAL "I")
set(${out} 2048 PARENT_SCOPE)
return()
endif()
endfunction()
function(add_hex_target name exe hex)
add_custom_target(${name} ALL
cmake -E env PATH="$ENV{PATH}"
# TODO: Overriding the start address with --set-start 0x08000000
# seems to be required due to some incorrect assumptions about .hex
# files in the configurator. Verify wether that's the case and fix
# the bug in configurator or delete this comment.
${CMAKE_OBJCOPY} -Oihex --set-start 0x08000000 $<TARGET_FILE:${exe}> ${hex}
BYPRODUCTS ${hex}
)
endfunction()
function(add_bin_target name exe bin)
add_custom_target(${name}
cmake -E env PATH="$ENV{PATH}"
${CMAKE_OBJCOPY} -Obinary $<TARGET_FILE:${exe}> ${bin}
BYPRODUCTS ${bin}
)
endfunction()
function(generate_map_file target)
if(CMAKE_VERSION VERSION_LESS 3.15)
set(map "$<TARGET_FILE:${target}>.map")
else()
set(map "$<TARGET_FILE_DIR:${target}>/$<TARGET_FILE_BASE_NAME:${target}>.map")
endif()
target_link_options(${target} PRIVATE "-Wl,-Map,${map}")
endfunction()
function(set_linker_script target script)
set(script_path ${AT32_LINKER_DIR}/${args_LINKER_SCRIPT}.ld)
if(NOT EXISTS ${script_path})
message(FATAL_ERROR "linker script ${script_path} doesn't exist")
endif()
set_target_properties(${target} PROPERTIES LINK_DEPENDS ${script_path})
target_link_options(${elf_target} PRIVATE -T${script_path})
endfunction()
function(add_at32_executable)
cmake_parse_arguments(
args
# Boolean arguments
""
# Single value arguments
"FILENAME;NAME;OPTIMIZATION;OUTPUT_BIN_FILENAME;OUTPUT_HEX_FILENAME;OUTPUT_TARGET_NAME"
# Multi-value arguments
"COMPILE_DEFINITIONS;COMPILE_OPTIONS;INCLUDE_DIRECTORIES;LINK_OPTIONS;LINKER_SCRIPT;SOURCES"
# Start parsing after the known arguments
${ARGN}
)
set(elf_target ${args_NAME}.elf)
add_executable(${elf_target})
target_sources(${elf_target} PRIVATE ${args_SOURCES})
target_include_directories(${elf_target} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${args_INCLUDE_DIRECTORIES} ${AT32_INCLUDE_DIRS})
target_compile_definitions(${elf_target} PRIVATE ${args_COMPILE_DEFINITIONS})
target_compile_options(${elf_target} PRIVATE ${AT32_COMPILE_OPTIONS} ${args_COMPILE_OPTIONS})
if(WARNINGS_AS_ERRORS)
target_compile_options(${elf_target} PRIVATE -Werror)
endif()
if (IS_RELEASE_BUILD)
target_compile_options(${elf_target} PRIVATE ${args_OPTIMIZATION})
target_link_options(${elf_target} PRIVATE ${args_OPTIMIZATION})
endif()
target_link_libraries(${elf_target} PRIVATE ${AT32_LINK_LIBRARIES})
target_link_options(${elf_target} PRIVATE ${AT32_LINK_OPTIONS} ${args_LINK_OPTIONS})
generate_map_file(${elf_target})
set_linker_script(${elf_target} ${args_LINKER_SCRIPT})
if(args_FILENAME)
set(basename ${CMAKE_BINARY_DIR}/${args_FILENAME})
set(hex_filename ${basename}.hex)
add_hex_target(${args_NAME} ${elf_target} ${hex_filename})
set(bin_filename ${basename}.bin)
add_bin_target(${args_NAME}.bin ${elf_target} ${bin_filename})
endif()
if(args_OUTPUT_BIN_FILENAME)
set(${args_OUTPUT_BIN_FILENAME} ${bin_filename} PARENT_SCOPE)
endif()
if(args_OUTPUT_TARGET_NAME)
set(${args_OUTPUT_TARGET_NAME} ${elf_target} PARENT_SCOPE)
endif()
if(args_OUTPUT_HEX_FILENAME)
set(${args_OUTPUT_HEX_FILENAME} ${hex_filename} PARENT_SCOPE)
endif()
endfunction()
# Main function of AT32
function(target_at32)
if(NOT arm-none-eabi STREQUAL TOOLCHAIN)
return()
endif()
# Parse keyword arguments
cmake_parse_arguments(
args
# Boolean arguments
"DISABLE_MSC;BOOTLOADER"
# Single value arguments
"HSE_MHZ;LINKER_SCRIPT;NAME;OPENOCD_TARGET;OPTIMIZATION;STARTUP;SVD"
# Multi-value arguments
"COMPILE_DEFINITIONS;COMPILE_OPTIONS;INCLUDE_DIRECTORIES;LINK_OPTIONS;SOURCES;MSC_SOURCES;MSC_INCLUDE_DIRECTORIES;VCP_SOURCES;VCP_INCLUDE_DIRECTORIES"
# Start parsing after the known arguments
${ARGN}
)
set(name ${args_NAME})
if (args_HSE_MHZ)
set(hse_mhz ${args_HSE_MHZ})
else()
set(hse_mhz ${AT32_DEFAULT_HSE_MHZ})
endif()
set(target_sources ${AT32_STARTUP_DIR}/${args_STARTUP})
list(APPEND target_sources ${args_SOURCES})
file(GLOB target_c_sources "${CMAKE_CURRENT_SOURCE_DIR}/*.c")
file(GLOB target_h_sources "${CMAKE_CURRENT_SOURCE_DIR}/*.h")
list(APPEND target_sources ${target_c_sources} ${target_h_sources})
set(target_include_directories ${args_INCLUDE_DIRECTORIES})
set(target_definitions ${AT32_DEFINITIONS} ${COMMON_COMPILE_DEFINITIONS})
get_at32_target_features(features "${CMAKE_CURRENT_SOURCE_DIR}" ${name})
set_property(TARGET ${elf_target} PROPERTY FEATURES ${features})
if(VCP IN_LIST features)
list(APPEND target_sources ${AT32_VCP_SRC} ${args_VCP_SOURCES})
list(APPEND target_include_directories ${args_VCP_INCLUDE_DIRECTORIES})
endif()
if(SDCARD IN_LIST features)
list(APPEND target_sources ${AT32_SDCARD_SRC} ${AT32_ASYNCFATFS_SRC})
endif()
set(msc_sources)
if(NOT args_DISABLE_MSC AND MSC IN_LIST features)
list(APPEND target_include_directories ${args_MSC_INCLUDE_DIRECTORIES})
list(APPEND msc_sources ${AT32_MSC_SRC} ${args_MSC_SOURCES})
list(APPEND target_definitions USE_USB_MSC)
if(FLASHFS IN_LIST features)
list(APPEND msc_sources ${AT32_MSC_FLASH_SRC})
endif()
if (SDCARD IN_LIST features)
list(APPEND msc_sources ${AT32_MSC_SDCARD_SRC})
endif()
endif()
math(EXPR hse_value "${hse_mhz} * 1000000")
list(APPEND target_definitions "HSE_VALUE=${hse_value}")
if (MSP_UART)
list(APPEND target_definitions "MSP_UART=${MSP_UART}")
endif()
if(args_COMPILE_DEFINITIONS)
list(APPEND target_definitions ${args_COMPILE_DEFINITIONS})
endif()
if(DEBUG_HARDFAULTS)
list(APPEND target_definitions DEBUG_HARDFAULTS)
endif()
string(TOLOWER ${PROJECT_NAME} lowercase_project_name)
set(binary_name ${lowercase_project_name}_${FIRMWARE_VERSION}_${name})
if(DEFINED BUILD_SUFFIX AND NOT "" STREQUAL "${BUILD_SUFFIX}")
set(binary_name "${binary_name}_${BUILD_SUFFIX}")
endif()
# Main firmware
add_at32_executable(
NAME ${name}
FILENAME ${binary_name}
SOURCES ${target_sources} ${msc_sources} ${CMSIS_DSP_SRC} ${COMMON_SRC}
COMPILE_DEFINITIONS ${target_definitions}
COMPILE_OPTIONS ${args_COMPILE_OPTIONS}
INCLUDE_DIRECTORIES ${target_include_directories}
LINK_OPTIONS ${args_LINK_OPTIONS}
LINKER_SCRIPT ${args_LINKER_SCRIPT}
OPTIMIZATION ${args_OPTIMIZATION}
OUTPUT_BIN_FILENAME main_bin_filename
OUTPUT_HEX_FILENAME main_hex_filename
OUTPUT_TARGET_NAME main_target_name
)
set_property(TARGET ${main_target_name} PROPERTY OPENOCD_TARGET ${args_OPENOCD_TARGET})
set_property(TARGET ${main_target_name} PROPERTY OPENOCD_DEFAULT_INTERFACE atlink)
set_property(TARGET ${main_target_name} PROPERTY SVD ${args_SVD})
setup_firmware_target(${main_target_name} ${name} ${ARGN})
if(args_BOOTLOADER)
# Bootloader for the target
set(bl_suffix _bl)
add_at32_executable(
NAME ${name}${bl_suffix}
FILENAME ${binary_name}${bl_suffix}
SOURCES ${target_sources} ${BOOTLOADER_SOURCES}
COMPILE_DEFINITIONS ${target_definitions} BOOTLOADER MSP_FIRMWARE_UPDATE
COMPILE_OPTIONS ${args_COMPILE_OPTIONS}
INCLUDE_DIRECTORIES ${target_include_directories}
LINK_OPTIONS ${args_LINK_OPTIONS}
LINKER_SCRIPT ${args_LINKER_SCRIPT}${bl_suffix}
OPTIMIZATION ${args_OPTIMIZATION}
OUTPUT_BIN_FILENAME bl_bin_filename
OUTPUT_HEX_FILENAME bl_hex_filename
OUTPUT_TARGET_NAME bl_target_name
)
setup_executable(${bl_target_name} ${name})
# Main firmware, but for running with the bootloader
set(for_bl_suffix _for_bl)
add_at32_executable(
NAME ${name}${for_bl_suffix}
FILENAME ${binary_name}${for_bl_suffix}
SOURCES ${target_sources} ${msc_sources} ${CMSIS_DSP_SRC} ${COMMON_SRC}
COMPILE_DEFINITIONS ${target_definitions} MSP_FIRMWARE_UPDATE
COMPILE_OPTIONS ${args_COMPILE_OPTIONS}
INCLUDE_DIRECTORIES ${target_include_directories}
LINK_OPTIONS ${args_LINK_OPTIONS}
LINKER_SCRIPT ${args_LINKER_SCRIPT}${for_bl_suffix}
OPTIMIZATION ${args_OPTIMIZATION}
OUTPUT_BIN_FILENAME for_bl_bin_filename
OUTPUT_HEX_FILENAME for_bl_hex_filename
OUTPUT_TARGET_NAME for_bl_target_name
)
setup_executable(${for_bl_target_name} ${name})
# Combined with bootloader and main firmware
set(with_bl_suffix _with_bl)
set(combined_hex ${CMAKE_BINARY_DIR}/${binary_name}${with_bl_suffix}.hex)
set(with_bl_target ${name}${with_bl_suffix})
add_custom_target(${with_bl_target}
${CMAKE_SOURCE_DIR}/src/utils/combine_tool ${bl_bin_filename} ${for_bl_bin_filename} ${combined_hex}
BYPRODUCTS ${combined_hex}
)
add_dependencies(${with_bl_target} ${bl_target_name} ${for_bl_target_name})
endif()
# clean_<target>
set(generator_cmd "")
if (CMAKE_GENERATOR STREQUAL "Unix Makefiles")
set(generator_cmd "make")
elseif(CMAKE_GENERATOR STREQUAL "Ninja")
set(generator_cmd "ninja")
endif()
if (NOT generator_cmd STREQUAL "")
set(clean_target "clean_${name}")
add_custom_target(${clean_target}
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
COMMAND ${generator_cmd} clean
COMMENT "Removing intermediate files for ${name}")
set_property(TARGET ${clean_target} PROPERTY
EXCLUDE_FROM_ALL 1
EXCLUDE_FROM_DEFAULT_BUILD 1)
endif()
endfunction()
+45
View File
@@ -0,0 +1,45 @@
set(AT32_USBCORE_DIR "${MAIN_LIB_DIR}/main/AT32F43x/Middlewares/AT/AT32_USB_Device_Library/Core")
set(AT32_USBCDC_DIR "${MAIN_LIB_DIR}/main/AT32F43x/Middlewares/AT/AT32_USB_Device_Library/Class/usbd_class/cdc")
set(AT32_USBMSC_DIR "${MAIN_LIB_DIR}/main/AT32F43x/Middlewares/AT/AT32_USB_Device_Library/Class/usbd_class/msc")
set(AT32F4_USB_INCLUDE_DIRS
"${AT32_USBCORE_DIR}/Inc"
"${AT32_USBCDC_DIR}"
"${AT32_USBMSC_DIR}"
)
set(AT32_USBCORE_SRC
usb_core.c
usbd_core.c
usbd_int.c
usbd_sdr.c
)
list(TRANSFORM AT32_USBCORE_SRC PREPEND "${AT32_USBCORE_DIR}/Src/")
set(AT32_USBCDC_SRC
"${AT32_USBCDC_DIR}/cdc_class.c"
"${AT32_USBCDC_DIR}/cdc_desc.c"
)
main_sources(AT32F4_VCP_SRC
drivers/serial_usb_vcp_at32f43x.c
drivers/usb_io.c
)
set(AT32F4_USBMSC_SRC
msc_desc.c
msc_class.c
msc_bot_scsi.c
)
main_sources(AT32F4_MSC_SRC
drivers/usb_msc_at32f43x.c
)
list(TRANSFORM AT32F4_USBMSC_SRC PREPEND "${AT32_USBMSC_DIR}/")
list(APPEND AT32F4_USBMSC_SRC ${AT32F4_MSC_SRC})
list(APPEND AT32F4_USB_SRC ${AT32F4_VCP_SRC})
list(APPEND AT32F4_USB_SRC ${AT32_USBCORE_SRC})
list(APPEND AT32F4_USB_SRC ${AT32_USBCDC_SRC})
+114
View File
@@ -0,0 +1,114 @@
include(cortex-m4f)
include(at32-stdperiph)
include(at32f4-usb)
set(AT32F4_STDPERIPH_DIR "${MAIN_LIB_DIR}/main/AT32F43x/Drivers/AT32F43x_StdPeriph_Driver")
set(AT32F4_CMSIS_DEVICE_DIR "${MAIN_LIB_DIR}/main/AT32F43x/Drivers/CMSIS/Device/ST/AT32F43x")
set(AT32F4_CMSIS_DRIVERS_DIR "${MAIN_LIB_DIR}/main/AT32F43x/Drivers/CMSIS")
set(AT32F4_STDPERIPH_SRC_EXCLUDES
at32f435_437_can.c
at32f435_437_dvp.c
at32f435_437_emac
at32f435_437_xmc.c
)
set(AT32F4_STDPERIPH_SRC_DIR "${AT32F4_STDPERIPH_DIR}/src")
glob_except(AT32F4_STDPERIPH_SRC "${AT32F4_STDPERIPH_SRC_DIR}/*.c" "${AT32F4_STDPERIPH_SRC_EXCLUDES}")
list(APPEND AT32F4_STDPERIPH_SRC "${AT32F4_CMSIS_DEVICE_DIR}/at32f435_437_clock.c" )
main_sources(AT32F4_SRC
target/system_at32f435_437.c
config/config_streamer_at32f43x.c
config/config_streamer_ram.c
config/config_streamer_extflash.c
drivers/adc_at32f43x.c
drivers/i2c_application.c
drivers/bus_i2c_at32f43x.c
drivers/bus_spi_at32f43x
drivers/serial_uart_hal_at32f43x.c
drivers/serial_uart_at32f43x.c
drivers/system_at32f43x.c
drivers/timer.c
drivers/timer_impl_stdperiph_at32.c
drivers/timer_at32f43x.c
drivers/uart_inverter.c
drivers/dma_at32f43x.c
)
set(AT32F4_INCLUDE_DIRS
${CMSIS_INCLUDE_DIR}
${CMSIS_DSP_INCLUDE_DIR}
${AT32F4_CMSIS_DRIVERS_DIR}
${AT32F4_STDPERIPH_DIR}/inc
${AT32F4_CMSIS_DEVICE_DIR}
#"${AT32F4_I2C_DIR}"
)
set(AT32F4_DEFINITIONS
${CORTEX_M4F_DEFINITIONS}
AT32F43x
USE_STDPERIPH_DRIVER
)
function(target_at32f43x)
target_at32(
SOURCES ${AT32_STDPERIPH_SRC} ${AT32F4_SRC}
COMPILE_DEFINITIONS ${AT32F4_DEFINITIONS}
COMPILE_OPTIONS ${CORTEX_M4F_COMMON_OPTIONS} ${CORTEX_M4F_COMPILE_OPTIONS}
INCLUDE_DIRECTORIES ${AT32F4_INCLUDE_DIRS}
LINK_OPTIONS ${CORTEX_M4F_COMMON_OPTIONS} ${CORTEX_M4F_LINK_OPTIONS}
MSC_SOURCES ${AT32F4_USBMSC_SRC} ${AT32F4_MSC_SRC}
VCP_SOURCES ${AT32F4_USB_SRC} ${AT32F4_VCP_SRC}
VCP_INCLUDE_DIRECTORIES ${AT32F4_USB_INCLUDE_DIRS}
OPTIMIZATION -O2
OPENOCD_TARGET at32f437xx
${ARGN}
)
endfunction()
#target_at32f43x_xMT7
#target_at32f43x_xGT7
set(at32f43x_xMT7_COMPILE_DEFINITIONS
AT32F437VMT7
MCU_FLASH_SIZE=4032
)
function(target_at32f43x_xMT7 name)
target_at32f43x(
NAME ${name}
STARTUP startup_at32f435_437.s
SOURCES ${AT32F4_STDPERIPH_SRC}
COMPILE_DEFINITIONS ${at32f43x_xMT7_COMPILE_DEFINITIONS}
LINKER_SCRIPT at32_flash_f43xM
#BOOTLOADER
SVD at32f43x_xMT7
${ARGN}
)
endfunction()
set(at32f43x_xGT7_COMPILE_DEFINITIONS
AT32F435RGT7
MCU_FLASH_SIZE=1024
)
function(target_at32f43x_xGT7 name)
target_at32f43x(
NAME ${name}
STARTUP startup_at32f435_437.s
SOURCES ${AT32F4_STDPERIPH_SRC}
COMPILE_DEFINITIONS ${at32f43x_xGT7_COMPILE_DEFINITIONS}
LINKER_SCRIPT at32_flash_f43xG
#BOOTLOADER
SVD at32f43x_xGT7
${ARGN}
)
endfunction()
+22
View File
@@ -0,0 +1,22 @@
if(DEFINED CI_JOB_INDEX AND DEFINED CI_JOB_COUNT)
math(EXPR job_name "${CI_JOB_INDEX}+1")
message("-- configuring CI job ${job_name}/${CI_JOB_COUNT}")
get_property(targets GLOBAL PROPERTY RELEASE_TARGETS)
list(LENGTH targets count)
message("-- ${count} total targets")
math(EXPR per_job "(${count}+${CI_JOB_COUNT}-1)/${CI_JOB_COUNT}")
math(EXPR start "${CI_JOB_INDEX}*${per_job}")
message("-- ${per_job} targets per job, starting at ${start}")
if(${start} LESS ${count})
list(SUBLIST targets ${start} ${per_job} ci_targets)
message("-- will build targets: ${ci_targets}")
add_custom_target(ci
${CMAKE_COMMAND} -E true
DEPENDS ${ci_targets}
)
else()
add_custom_target(ci
${CMAKE_COMMAND} -E true
)
endif()
endif()
+23
View File
@@ -0,0 +1,23 @@
set(CORTEX_M4F_COMMON_OPTIONS
-mthumb
-mcpu=cortex-m4
-march=armv7e-m
-mfloat-abi=hard
-mfpu=fpv4-sp-d16
-fsingle-precision-constant
-Wdouble-promotion
)
set(CORTEX_M4F_COMPILE_OPTIONS
)
set(CORTEX_M4F_LINK_OPTIONS
)
set(CORTEX_M4F_DEFINITIONS
__FPU_PRESENT=1
ARM_MATH_CM4
ARM_MATH_MATRIX_CHECK
ARM_MATH_ROUNDING
UNALIGNED_SUPPORT_DISABLE
)
+22
View File
@@ -0,0 +1,22 @@
set(CORTEX_M7_COMMON_OPTIONS
-mthumb
-mcpu=cortex-m7
-mfloat-abi=hard
-mfpu=fpv5-sp-d16
-fsingle-precision-constant
-Wdouble-promotion
)
set(CORTEX_M7_COMPILE_OPTIONS
)
set(CORTEX_M7_LINK_OPTIONS
)
set(CORTEX_M7_DEFINITIONS
__FPU_PRESENT=1
ARM_MATH_CM7
ARM_MATH_MATRIX_CHECK
ARM_MATH_ROUNDING
UNALIGNED_SUPPORT_DISABLE
)
+29
View File
@@ -0,0 +1,29 @@
#!/bin/bash
set -e
LAST_CMAKE_AT_REV_FILE="docker_cmake.rev"
CURR_REV="$(git rev-parse HEAD)"
initialize_cmake() {
echo -e "*** CMake was not initialized yet, doing it now.\n"
cmake -GNinja ..
echo "$CURR_REV" > "$LAST_CMAKE_AT_REV_FILE"
}
# Check if CMake has never been initialized
if [ ! -f build.ninja ]; then
initialize_cmake
fi
# Check if CMake was initialized for a different Git revision (new targets may have been added)
if [ -f "$LAST_CMAKE_AT_REV_FILE" ]; then
LAST_CMAKE_AT_REV="$(cat $LAST_CMAKE_AT_REV_FILE)"
if [[ "$LAST_CMAKE_AT_REV" != "SKIP" ]] && [[ "$LAST_CMAKE_AT_REV" != "$CURR_REV" ]]; then
initialize_cmake
fi
else
initialize_cmake
fi
# Let Make handle the arguments coming from the build script
ninja "$@"
+7
View File
@@ -0,0 +1,7 @@
#!/bin/bash
rm -r build_SITL
mkdir -p build_SITL
#cmake -DSITL=ON -DWARNINGS_AS_ERRORS=ON -GNinja -B build_SITL ..
cmake -DSITL=ON -DDEBUG=ON -DWARNINGS_AS_ERRORS=ON -GNinja -B build_SITL ..
cd build_SITL
ninja
+3
View File
@@ -0,0 +1,3 @@
#!/bin/bash
cd /src/
python3 src/utils/update_cli_docs.py
+8
View File
@@ -0,0 +1,8 @@
#!/bin/bash
cd build_SITL
#Lauch SITL - configurator only mode
./inav_7.0.0_SITL
#Launch SITL - connect to X-Plane. IP address should be host IP address, not 127.0.0.1. Can be found in X-Plane "Network" tab.
#./inav_7.0.0_SITL --sim=xp --simip=192.168.2.105 --simport=49000
+34
View File
@@ -0,0 +1,34 @@
function(gcc_get_version var)
cmake_parse_arguments(args
""
"TRIPLET;PROGRAM_NAME;PROGRAM_PATH"
""
${ARGN}
)
set(prog "gcc")
if(args_TRIPLET)
set(prog "${args_TRIPLET}-${prog}")
endif()
if(args_PROGRAM_NAME)
set(${args_PROGRAM_NAME} ${prog} PARENT_SCOPE)
endif()
find_program(gcc ${prog})
if (NOT gcc)
set(${var} OFF PARENT_SCOPE)
endif()
if(args_PROGRAM_PATH)
set(${args_PROGRAM_PATH} ${gcc} PARENT_SCOPE)
endif()
execute_process(COMMAND "${gcc}" -dumpversion
OUTPUT_STRIP_TRAILING_WHITESPACE
OUTPUT_VARIABLE version)
if("" STREQUAL version)
set(${var} OFF PARENT_SCOPE)
else()
set(${var} ${version} PARENT_SCOPE)
endif()
endfunction()
+47
View File
@@ -0,0 +1,47 @@
if(NOT CMAKE_CONFIGURATION_TYPES)
set(CMAKE_CONFIGURATION_TYPES Debug Release RelWithDebInfo)
endif()
if(CMAKE_BUILD_TYPE STREQUAL "")
set(CMAKE_BUILD_TYPE RelWithDebInfo)
endif()
if(WIN32)
set(TOOL_EXECUTABLE_SUFFIX ".exe")
endif()
set(CMAKE_ASM_COMPILER "gcc${TOOL_EXECUTABLE_SUFFIX}" CACHE INTERNAL "asm compiler")
set(CMAKE_C_COMPILER "gcc${TOOL_EXECUTABLE_SUFFIX}" CACHE INTERNAL "c compiler")
set(CMAKE_CXX_COMPILER "g++${TOOL_EXECUTABLE_SUFFIX}" CACHE INTERNAL "c++ compiler")
set(CMAKE_OBJCOPY "objcopy${TOOL_EXECUTABLE_SUFFIX}" CACHE INTERNAL "objcopy tool")
set(CMAKE_OBJDUMP "objdump${TOOL_EXECUTABLE_SUFFIX}" CACHE INTERNAL "objdump tool")
set(CMAKE_SIZE "size${TOOL_EXECUTABLE_SUFFIX}" CACHE INTERNAL "size tool")
if(CMAKE_HOST_APPLE)
set(CMAKE_DEBUGGER "lldb${TOOL_EXECUTABLE_SUFFIX}" CACHE INTERNAL "debugger")
else()
set(CMAKE_DEBUGGER "gdb${TOOL_EXECUTABLE_SUFFIX}" CACHE INTERNAL "debugger")
endif()
set(CMAKE_CPPFILT "c++filt${TOOL_EXECUTABLE_SUFFIX}" CACHE INTERNAL "c++filt")
set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "Build Type" FORCE)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS ${CMAKE_CONFIGURATION_TYPES})
set(debug_options "-Og -O0 -g")
set(release_options "-Os -DNDEBUG")
if(CMAKE_HOST_APPLE)
set(relwithdebinfo_options "-g ${release_options}")
else()
set(relwithdebinfo_options "-ggdb3 ${release_options}")
endif()
set(CMAKE_C_FLAGS_DEBUG ${debug_options} CACHE INTERNAL "c compiler flags debug")
set(CMAKE_CXX_FLAGS_DEBUG ${debug_options} CACHE INTERNAL "c++ compiler flags debug")
set(CMAKE_ASM_FLAGS_DEBUG ${debug_options} CACHE INTERNAL "asm compiler flags debug")
set(CMAKE_C_FLAGS_RELEASE ${release_options} CACHE INTERNAL "c compiler flags release")
set(CMAKE_CXX_FLAGS_RELEASE ${release_options} CACHE INTERNAL "cxx compiler flags release")
set(CMAKE_ASM_FLAGS_RELEASE ${release_options} CACHE INTERNAL "asm compiler flags release")
set(CMAKE_C_FLAGS_RELWITHDEBINFO ${relwithdebinfo_options} CACHE INTERNAL "c compiler flags release")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO ${relwithdebinfo_options} CACHE INTERNAL "cxx compiler flags release")
set(CMAKE_ASM_FLAGS_RELWITHDEBINFO ${relwithdebinfo_options} CACHE INTERNAL "asm compiler flags release")
+146
View File
@@ -0,0 +1,146 @@
set(MAIN_INCLUDE_DIRS
"${MAIN_LIB_DIR}"
"${MAIN_SRC_DIR}"
"${MAIN_LIB_DIR}/main/MAVLink"
)
set(MAIN_DEFINITIONS
__FORKNAME__=inav
__REVISION__="${GIT_REV}"
)
# Can't check for OSX yet at this point
if(SITL)
set(MAIN_COMPILE_OPTIONS
-Wall
-Wextra
-Wdouble-promotion
-Wstrict-prototypes
-Werror=switch
#-Wno-unknown-warning-option
)
else()
set(MAIN_COMPILE_OPTIONS
-Wall
-Wextra
-Wunsafe-loop-optimizations
-Wdouble-promotion
-Wstrict-prototypes
-Werror=switch
)
endif()
macro(main_sources var) # list-var src-1...src-n
set(${var} ${ARGN})
list(TRANSFORM ${var} PREPEND "${MAIN_SRC_DIR}/")
endmacro()
function(exclude var excludes)
set(filtered "")
foreach(item ${${var}})
if (NOT ${item} IN_LIST excludes)
list(APPEND filtered ${item})
endif()
endforeach()
set(${var} ${filtered} PARENT_SCOPE)
endfunction()
function(exclude_basenames var excludes)
set(filtered "")
foreach(item ${${var}})
get_filename_component(basename ${item} NAME)
if (NOT ${basename} IN_LIST excludes)
list(APPEND filtered ${item})
endif()
endforeach()
set(${var} ${filtered} PARENT_SCOPE)
endfunction()
function(glob_except var pattern excludes)
file(GLOB results ${pattern})
list(LENGTH results count)
if(count EQUAL 0)
message(FATAL_ERROR "glob with pattern '${pattern}' returned no results")
endif()
exclude_basenames(results "${excludes}")
set(${var} ${results} PARENT_SCOPE)
endfunction()
function(get_generated_files_dir output target_name)
set(${output} ${CMAKE_CURRENT_BINARY_DIR}/${target_name} PARENT_SCOPE)
endfunction()
function(setup_executable exe name)
get_generated_files_dir(generated_dir ${name})
target_compile_options(${exe} PRIVATE ${MAIN_COMPILE_OPTIONS})
target_include_directories(${exe} PRIVATE ${generated_dir} ${MAIN_INCLUDE_DIRS})
target_compile_definitions(${exe} PRIVATE ${MAIN_DEFINITIONS} __TARGET__="${name}" ${name})
# XXX: Don't make SETTINGS_GENERATED_C part of the build,
# since it's compiled via #include in settings.c. This will
# change once we move off PGs
target_sources(${exe} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/${name}/${SETTINGS_GENERATED_H}")
set_target_properties(${exe} PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
)
if(IS_RELEASE_BUILD AND NOT (CMAKE_HOST_APPLE AND SITL))
set_target_properties(${exe} PROPERTIES
INTERPROCEDURAL_OPTIMIZATION ON
)
endif()
endfunction()
function(setup_firmware_target exe name)
setup_executable(${exe} ${name})
enable_settings(${exe} ${name})
get_property(targets GLOBAL PROPERTY VALID_TARGETS)
list(APPEND targets ${name})
set_property(GLOBAL PROPERTY VALID_TARGETS "${targets}")
if(NOT SITL)
setup_openocd(${exe} ${name})
setup_svd(${exe} ${name})
endif()
cmake_parse_arguments(args "SKIP_RELEASES" "" "" ${ARGN})
if(args_SKIP_RELEASES)
set_target_properties(${exe} ${name} PROPERTIES SKIP_RELEASES ON)
endif()
endfunction()
function(exclude_from_all target)
set_target_properties(${target} PROPERTIES
TARGET_MESSAGES OFF
EXCLUDE_FROM_ALL ON
EXCLUDE_FROM_DEFAULT_BUILD ON)
endfunction()
function(collect_targets)
get_property(targets GLOBAL PROPERTY VALID_TARGETS)
list(SORT targets)
set(release_targets)
foreach(target ${targets})
get_target_property(skip_releases ${target} SKIP_RELEASES)
if(NOT skip_releases)
list(APPEND release_targets ${target})
endif()
endforeach()
list(JOIN targets " " target_names)
list(JOIN release_targets " " release_targets_names)
set_property(GLOBAL PROPERTY RELEASE_TARGETS ${release_targets})
set(list_target_name "targets")
add_custom_target(${list_target_name}
COMMAND ${CMAKE_COMMAND} -E echo "Valid targets: ${target_names}"
COMMAND ${CMAKE_COMMAND} -E echo "Release targets: ${release_targets_names}"
)
exclude_from_all(${list_target_name})
set(release_target_name "release")
add_custom_target(${release_target_name}
${CMAKE_COMMAND} -E true
DEPENDS ${release_targets}
)
list(LENGTH targets target_count)
list(LENGTH release_targets release_target_count)
message("-- ${target_count} targets (${release_target_count} for release) found for toolchain ${TOOLCHAIN}")
endfunction()
+84
View File
@@ -0,0 +1,84 @@
set(OPENOCD "" CACHE STRING "path to openocd (default: search for it)")
set(OPENOCD_CFG "" CACHE STRING "path to openocd configuration (default: generate automatically)")
set(OPENOCD_INTERFACE "" CACHE STRING "openocd interface name (default: automatic depending on target)")
if (OPENOCD)
set(OPENOCD_PATH ${OPENOCD})
else()
find_program(OPENOCD_FOUND_PATH NAMES openocd openocd.exe)
if (NOT OPENOCD_FOUND_PATH)
message(STATUS "Could not find openocd, debugging won't be available")
else()
set(OPENOCD_PATH ${OPENOCD_FOUND_PATH})
endif()
endif()
if(OPENOCD_PATH)
# Retrieve version number as a sanity check
execute_process(COMMAND ${OPENOCD_PATH} -v
OUTPUT_QUIET
ERROR_VARIABLE OPENOCD_HELP
RESULT_VARIABLE OPENOCD_RESULT)
string(REPLACE "\n" ";" OPENOCD_HELP_LINES ${OPENOCD_HELP})
list(GET OPENOCD_HELP_LINES 0 OPENOCD_FIRST_HELP_LINE)
string(REPLACE "\r" "" OPENOCD_HELP_LINE ${OPENOCD_FIRST_HELP_LINE})
if (NOT OPENOCD_RESULT EQUAL 0)
# User provided an incorrect path
message(FATAL_ERROR "error executing ${OPENOCD_PATH} (${OPENOCD_RESULT})")
endif()
message(STATUS "using openocd: ${OPENOCD_HELP_LINE}")
add_custom_target(openocd ${OPENOCD_PATH} -f ${OPENOCD_CFG}
COMMENT "Run openocd using OPENOCD_CFG=(${OPENOCD_CFG}) as configuration"
USES_TERMINAL
)
endif()
function(setup_openocd target_exe target_name)
if(OPENOCD_INTERFACE)
set(openocd_interface ${OPENOCD_INTERFACE})
else()
get_property(openocd_interface TARGET ${target_exe} PROPERTY OPENOCD_DEFAULT_INTERFACE)
endif()
get_property(openocd_target TARGET ${target_exe} PROPERTY OPENOCD_TARGET)
if(OPENOCD_CFG OR (openocd_target AND openocd_interface))
set(openocd_run_target "openocd_${target_name}")
if (OPENOCD_CFG AND NOT OPENOCD_CFG STREQUAL "")
get_filename_component(openocd_cfg_path ${OPENOCD_CFG}
ABSOLUTE
BASE_DIR ${CMAKE_BINARY_DIR})
else()
set(openocd_cfg_path ${CMAKE_BINARY_DIR}/openocd/${target_name}.cfg)
add_custom_command(
OUTPUT ${openocd_cfg_path}
COMMENT "Generating openocd configuration for ${openocd_target} via ${openocd_interface}"
COMMAND ${CMAKE_COMMAND} -P ${MAIN_DIR}/cmake/openocd_cfg.cmake
${openocd_target} ${openocd_interface} ${openocd_cfg_path}
)
endif()
# Target for openocd configuration
set(openocd_cfg_target "openocd_cfg_${target_name}")
add_custom_target(${openocd_cfg_target} DEPENDS ${openocd_cfg_path})
exclude_from_all(${openocd_cfg_target})
# Target for running openocd
add_custom_target(${openocd_run_target} ${OPENOCD_PATH} -f ${openocd_cfg_path}
COMMENT "Running openocd for target ${target_name} via ${openocd_interface}"
DEPENDS ${openocd_cfg_path}
USES_TERMINAL
)
exclude_from_all(${openocd_run_target})
# Target for flashing via openocd
set(openocd_flash_target "openocd_flash_${target_name}")
add_custom_target(${openocd_flash_target} ${CMAKE_COMMAND} -E env
OPENOCD_CMD=${OPENOCD_PATH}
${MAIN_UTILS_DIR}/openocd_flash.py -f
${openocd_cfg_path} $<TARGET_FILE:${target_exe}>
COMMENT "Flashing ${target_name} with openocd"
DEPENDS ${openocd_cfg_path} ${target_exe}
)
exclude_from_all(${openocd_flash_target})
endif()
endfunction()
+20
View File
@@ -0,0 +1,20 @@
# This is called from the targets that build the
# openocd.cfg file
if(NOT CMAKE_ARGC EQUAL 6)
message(FATAL_ERROR "usage: cmake -P openocd_cfg.cmake <target> <interface> <output>")
endif()
set(OPENOCD_TARGET ${CMAKE_ARGV3})
set(OPENOCD_INTERFACE ${CMAKE_ARGV4})
set(OUTPUT ${CMAKE_ARGV5})
set(opencd_cfg)
list(APPEND openocd_cfg "source [find interface/${OPENOCD_INTERFACE}.cfg]")
list(APPEND openocd_cfg "source [find target/${OPENOCD_TARGET}.cfg]")
list(APPEND openocd_cfg "init")
list(APPEND openocd_cfg "arm semihosting enable")
list(APPEND openocd_cfg "reset halt")
list(JOIN openocd_cfg "\n" contents)
set(contents "${contents}\n")
file(WRITE ${OUTPUT} ${contents})
+50
View File
@@ -0,0 +1,50 @@
adcChannelConfig_t 4 0
armingConfig_t 6 3
barometerConfig_t 8 5
batteryMetersConfig_t 24 2
beeperConfig_t 12 2
blackboxConfig_t 16 4
compassConfig_t 24 6
displayConfig_t 1 0
djiOsdConfig_t 6 3
escSensorConfig_t 4 1
ezTuneSettings_t 12 1
failsafeConfig_t 22 3
featureConfig_t 4 0
generalSettings_t 1 0
geozone_config_t 20 0
gimbalConfig_t 10 1
gimbalSerialConfig_t 1 0
gpsConfig_t 11 5
gyroConfig_t 64 12
headTrackerConfig_t 16 1
imuConfig_t 16 2
ledPinConfig_t 1 0
logConfig_t 8 0
modeActivationOperatorConfig_t 1 0
motorConfig_t 10 11
navConfig_t 156 7
navFwAutolandConfig_t 16 0
opticalFlowConfig_t 8 2
osdCommonConfig_t 1 0
osdConfig_t 160 15
osdJoystickConfig_t 6 0
pidAutotuneConfig_t 10 2
pidProfile_t 292 11
pitotmeterConfig_t 8 2
positionEstimationConfig_t 72 8
powerLimitsConfig_t 8 1
rangefinderConfig_t 2 3
rcControlsConfig_t 10 4
reversibleMotorsConfig_t 6 0
rpmFilterConfig_t 10 1
rxConfig_t 36 13
servoConfig_t 12 3
smartportMasterConfig_t 2 0
statsConfig_t 20 2
systemConfig_t 40 7
telemetryConfig_t 58 8
timeConfig_t 4 1
vtxConfig_t 55 4
vtxSettingsConfig_t 12 2
pinioBoxConfig_t 4 1
+49
View File
@@ -0,0 +1,49 @@
set(SETTINGS_GENERATED "settings_generated")
set(SETTINGS_GENERATED_C "${SETTINGS_GENERATED}.c")
set(SETTINGS_GENERATED_H "${SETTINGS_GENERATED}.h")
set(SETTINGS_FILE "${MAIN_SRC_DIR}/fc/settings.yaml")
set(SETTINGS_GENERATOR "${MAIN_UTILS_DIR}/settings.rb")
include(CMakeParseArguments)
function(enable_settings exe name)
get_generated_files_dir(dir ${name})
get_target_property(options ${exe} COMPILE_OPTIONS)
get_target_property(includes ${exe} INCLUDE_DIRECTORIES)
list(TRANSFORM includes PREPEND "-I")
get_target_property(defs ${exe} COMPILE_DEFINITIONS)
list(TRANSFORM defs PREPEND "-D")
list(APPEND cflags ${options})
list(APPEND cflags ${includes})
list(APPEND cflags ${defs})
cmake_parse_arguments(
args
# Boolean arguments
""
# Single value arguments
"OUTPUTS;SETTINGS_CXX"
# Multi-value arguments
""
# Start parsing after the known arguments
${ARGN}
)
find_program(RUBY_EXECUTABLE ruby)
if (NOT RUBY_EXECUTABLE)
message(FATAL_ERROR "Could not find ruby")
endif()
if(host STREQUAL TOOLCHAIN)
set(USE_HOST_GCC "-g")
endif()
set(output ${dir}/${SETTINGS_GENERATED_H} ${dir}/${SETTINGS_GENERATED_C})
add_custom_command(
OUTPUT ${output}
COMMAND
${CMAKE_COMMAND} -E env CFLAGS="${cflags}" TARGET=${name} PATH="$ENV{PATH}" SETTINGS_CXX=${args_SETTINGS_CXX}
${RUBY_EXECUTABLE} ${SETTINGS_GENERATOR} ${MAIN_DIR} ${SETTINGS_FILE} -o "${dir}" ${USE_HOST_GCC}
DEPENDS ${SETTINGS_GENERATOR} ${SETTINGS_FILE}
)
set(${args_OUTPUTS} ${output} PARENT_SCOPE)
endfunction()
+176
View File
@@ -0,0 +1,176 @@
main_sources(SITL_COMMON_SRC_EXCLUDES
build/atomic.h
drivers/system.c
drivers/time.c
drivers/timer.c
drivers/rcc.c
drivers/persistent.c
drivers/accgyro/accgyro_mpu.c
drivers/display_ug2864hsweg01.c
io/displayport_oled.c
)
main_sources(SITL_SRC
config/config_streamer_file.c
drivers/serial_tcp.c
drivers/serial_tcp.h
target/SITL/sim/realFlight.c
target/SITL/sim/realFlight.h
target/SITL/sim/simHelper.c
target/SITL/sim/simHelper.h
target/SITL/sim/soap_client.c
target/SITL/sim/soap_client.h
target/SITL/sim/xplane.c
target/SITL/sim/xplane.h
)
if(CMAKE_HOST_APPLE)
set(MACOSX ON)
endif()
set(SITL_LINK_OPTIONS
-Wl,-L${STM32_LINKER_DIR}
)
if(${CYGWIN})
set(SITL_LINK_OPTIONS ${SITL_LINK_OPTIONS} "-static-libgcc")
endif()
set(SITL_LINK_LIBRARIS
-lpthread
-lm
-lc
)
if(NOT MACOSX)
set(SITL_LINK_LIBRARIS ${SITL_LINK_LIBRARIS} -lrt)
endif()
set(SITL_COMPILE_OPTIONS
-Wno-format #Fixme: Compile for 32bit, but settings.rb has to be adjusted
-funsigned-char
)
if(DEBUG)
message(STATUS "Debug mode enabled. Adding -g to SITL_COMPILE_OPTIONS.")
list(APPEND SITL_COMPILE_OPTIONS -g)
endif()
if(ASAN)
message(STATUS "AddressSanitizer enabled.")
list(APPEND SITL_COMPILE_OPTIONS -fsanitize=address -fno-omit-frame-pointer)
list(APPEND SITL_LINK_OPTIONS -fsanitize=address)
endif()
if(NOT MACOSX)
set(SITL_COMPILE_OPTIONS ${SITL_COMPILE_OPTIONS}
-Wno-return-local-addr
-Wno-error=maybe-uninitialized
-fsingle-precision-constant
)
include(CheckLinkerFlag OPTIONAL)
if(COMMAND check_linker_flag)
check_linker_flag(C "-Wl,--no-warn-rwx-segments" LINKER_SUPPORTS_NO_RWX_WARNING)
endif()
if(LINKER_SUPPORTS_NO_RWX_WARNING)
set(SITL_LINK_OPTIONS ${SITL_LINK_OPTIONS} "-Wl,--no-warn-rwx-segments")
endif()
else()
set(SITL_COMPILE_OPTIONS ${SITL_COMPILE_OPTIONS}
)
endif()
set(SITL_DEFINITIONS
SITL_BUILD
)
function (target_sitl name)
if(CMAKE_VERSION VERSION_GREATER 3.22)
set(CMAKE_C_STANDARD 17)
endif()
if(NOT host STREQUAL TOOLCHAIN)
return()
endif()
exclude(COMMON_SRC "${SITL_COMMON_SRC_EXCLUDES}")
set(target_sources)
list(APPEND target_sources ${SITL_SRC})
file(GLOB target_c_sources "${CMAKE_CURRENT_SOURCE_DIR}/*.c")
file(GLOB target_h_sources "${CMAKE_CURRENT_SOURCE_DIR}/*.h")
list(APPEND target_sources ${target_c_sources} ${target_h_sources})
set(target_definitions ${COMMON_COMPILE_DEFINITIONS})
set(hse_mhz ${STM32_DEFAULT_HSE_MHZ})
math(EXPR hse_value "${hse_mhz} * 1000000")
list(APPEND target_definitions "HSE_VALUE=${hse_value}")
if (MSP_UART)
list(APPEND target_definitions "MSP_UART=${MSP_UART}")
endif()
string(TOLOWER ${PROJECT_NAME} lowercase_project_name)
set(binary_name ${lowercase_project_name}_${FIRMWARE_VERSION}_${name})
if(DEFINED BUILD_SUFFIX AND NOT "" STREQUAL "${BUILD_SUFFIX}")
set(binary_name "${binary_name}_${BUILD_SUFFIX}")
endif()
list(APPEND target_definitions ${SITL_DEFINITIONS})
set(exe_target ${name}.elf)
add_executable(${exe_target})
target_sources(${exe_target} PRIVATE ${target_sources} ${COMMON_SRC})
target_include_directories(${exe_target} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_compile_definitions(${exe_target} PRIVATE ${target_definitions})
if(WARNINGS_AS_ERRORS)
target_compile_options(${exe_target} PRIVATE -Werror)
endif()
target_compile_options(${exe_target} PRIVATE ${SITL_COMPILE_OPTIONS})
target_link_libraries(${exe_target} PRIVATE ${SITL_LINK_LIBRARIS})
target_link_options(${exe_target} PRIVATE ${SITL_LINK_OPTIONS})
set(script_path ${MAIN_SRC_DIR}/target/link/sitl.ld)
if(NOT EXISTS ${script_path})
message(FATAL_ERROR "linker script ${script_path} doesn't exist")
endif()
set_target_properties(${exe_target} PROPERTIES LINK_DEPENDS ${script_path})
if(NOT MACOSX)
target_link_options(${exe_target} PRIVATE -T${script_path})
endif()
if(${CYGWIN})
set(exe_filename ${CMAKE_BINARY_DIR}/${binary_name}.exe)
else()
set(exe_filename ${CMAKE_BINARY_DIR}/${binary_name})
endif()
add_custom_target(${name} ALL
cmake -E copy $<TARGET_FILE:${exe_target}> ${exe_filename}
)
setup_firmware_target(${exe_target} ${name} ${ARGN})
#clean_<target>
set(generator_cmd "")
if (CMAKE_GENERATOR STREQUAL "Unix Makefiles")
set(generator_cmd "make")
elseif(CMAKE_GENERATOR STREQUAL "Ninja")
set(generator_cmd "ninja")
endif()
if (NOT generator_cmd STREQUAL "")
set(clean_target "clean_${name}")
add_custom_target(${clean_target}
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
COMMAND ${generator_cmd} clean
COMMENT "Removing intermediate files for ${name}")
set_target_properties(${clean_target} PROPERTIES
EXCLUDE_FROM_ALL ON
EXCLUDE_FROM_DEFAULT_BUILD ON)
endif()
endfunction()
+30
View File
@@ -0,0 +1,30 @@
main_sources(BOOTLOADER_SOURCES
common/log.c
common/log.h
common/printf.c
common/printf.h
common/string_light.c
common/string_light.h
common/typeconversion.c
common/typeconversion.h
drivers/bus.c
drivers/bus_busdev_i2c.c
drivers/bus_busdev_spi.c
drivers/bus_i2c_soft.c
drivers/io.c
drivers/light_led.c
drivers/persistent.c
drivers/rcc.c
drivers/serial.c
drivers/system.c
drivers/time.c
drivers/timer.c
fc/firmware_update_common.c
fc/firmware_update_common.h
target/common_hardware.c
)
list(APPEND BOOTLOADER_SOURCES ${MAIN_DIR}/src/bl/bl_main.c)
+4
View File
@@ -0,0 +1,4 @@
main_sources(STM32_STDPERIPH_SRC
drivers/bus_spi.c
drivers/serial_uart.c
)
+447
View File
@@ -0,0 +1,447 @@
include(stm32-bootloader)
include(stm32f4)
include(stm32f7)
include(stm32h7)
include(CMakeParseArguments)
option(DEBUG_HARDFAULTS "Enable debugging of hard faults via custom handler")
option(SEMIHOSTING "Enable semihosting")
message("-- DEBUG_HARDFAULTS: ${DEBUG_HARDFAULTS}, SEMIHOSTING: ${SEMIHOSTING}")
set(CMSIS_DIR "${MAIN_LIB_DIR}/main/CMSIS")
set(CMSIS_INCLUDE_DIR "${CMSIS_DIR}/Core/Include")
set(CMSIS_DSP_DIR "${MAIN_LIB_DIR}/main/CMSIS/DSP")
set(CMSIS_DSP_INCLUDE_DIR "${CMSIS_DSP_DIR}/Include")
set(CMSIS_DSP_SRC
BasicMathFunctions/arm_scale_f32.c
BasicMathFunctions/arm_sub_f32.c
BasicMathFunctions/arm_mult_f32.c
BasicMathFunctions/arm_offset_f32.c
TransformFunctions/arm_rfft_fast_f32.c
TransformFunctions/arm_cfft_f32.c
TransformFunctions/arm_rfft_fast_init_f32.c
TransformFunctions/arm_cfft_radix8_f32.c
TransformFunctions/arm_bitreversal2.S
CommonTables/arm_common_tables.c
ComplexMathFunctions/arm_cmplx_mag_f32.c
StatisticsFunctions/arm_max_f32.c
StatisticsFunctions/arm_rms_f32.c
StatisticsFunctions/arm_std_f32.c
StatisticsFunctions/arm_mean_f32.c
)
list(TRANSFORM CMSIS_DSP_SRC PREPEND "${CMSIS_DSP_DIR}/Source/")
set(STM32_STARTUP_DIR "${MAIN_SRC_DIR}/startup")
main_sources(STM32_VCP_SRC
drivers/serial_usb_vcp.c
drivers/usb_io.c
)
main_sources(STM32_SDCARD_SRC
drivers/sdcard/sdcard.c
drivers/sdcard/sdcard_spi.c
drivers/sdcard/sdcard_sdio.c
drivers/sdcard/sdcard_standard.c
)
# XXX: This code is not STM32 specific
main_sources(STM32_ASYNCFATFS_SRC
io/asyncfatfs/asyncfatfs.c
io/asyncfatfs/fat_standard.c
)
main_sources(STM32_MSC_SRC
msc/usbd_storage.c
)
main_sources(STM32_MSC_FLASH_SRC
msc/usbd_storage_emfat.c
msc/emfat.c
msc/emfat_file.c
)
main_sources(STM32_MSC_SDCARD_SRC
msc/usbd_storage_sd_spi.c
)
set(STM32_INCLUDE_DIRS
"${CMSIS_INCLUDE_DIR}"
"${CMSIS_DSP_INCLUDE_DIR}"
"${MAIN_SRC_DIR}/target"
)
set(STM32_DEFINITIONS
)
set(STM32_DEFAULT_HSE_MHZ 8)
set(STM32_LINKER_DIR "${MAIN_SRC_DIR}/target/link")
set(STM32_COMPILE_OPTIONS
-ffunction-sections
-fdata-sections
-fno-common
)
set(STM32_LINK_LIBRARIES
-lm
-lc
)
if(SEMIHOSTING)
list(APPEND STM32_LINK_LIBRARIES --specs=rdimon.specs -lrdimon)
list(APPEND STM32_DEFINITIONS SEMIHOSTING)
else()
list(APPEND STM32_LINK_LIBRARIES -lnosys)
endif()
set(STM32_LINK_OPTIONS
-nostartfiles
--specs=nano.specs
-static
-Wl,-gc-sections
-Wl,-L${STM32_LINKER_DIR}
-Wl,--cref
-Wl,--no-wchar-size-warning
-Wl,--print-memory-usage
)
macro(get_stm32_target_features output_var dir target_name)
execute_process(COMMAND "${CMAKE_C_COMPILER}" -E -dD -D${ARGV2} "${ARGV1}/target.h"
ERROR_VARIABLE _errors
RESULT_VARIABLE _result
OUTPUT_STRIP_TRAILING_WHITESPACE
OUTPUT_VARIABLE _contents)
if(NOT _result EQUAL 0)
message(FATAL_ERROR "error extracting features for stm32 target ${ARGV2}: ${_errors}")
endif()
string(REGEX MATCH "#define[\t ]+USE_VCP" HAS_VCP ${_contents})
if(HAS_VCP)
list(APPEND ${ARGV0} VCP)
endif()
string(REGEX MATCH "define[\t ]+USE_FLASHFS" HAS_FLASHFS ${_contents})
if(HAS_FLASHFS)
list(APPEND ${ARGV0} FLASHFS)
endif()
string(REGEX MATCH "define[\t ]+USE_SDCARD" HAS_SDCARD ${_contents})
if (HAS_SDCARD)
list(APPEND ${ARGV0} SDCARD)
string(REGEX MATCH "define[\t ]+USE_SDCARD_SDIO" HAS_SDIO ${_contents})
if (HAS_SDIO)
list(APPEND ${ARGV0} SDIO)
endif()
endif()
if(HAS_FLASHFS OR HAS_SDCARD)
list(APPEND ${ARGV0} MSC)
endif()
endmacro()
function(get_stm32_flash_size out size)
# 4: 16, 6: 32, 8: 64, B: 128, C: 256, D: 384, E: 512, F: 768, G: 1024, H: 1536, I: 2048 KiB
string(TOUPPER ${size} s)
if(${s} STREQUAL "4")
set(${out} 16 PARENT_SCOPE)
return()
endif()
if(${s} STREQUAL "6")
set(${out} 32 PARENT_SCOPE)
return()
endif()
if(${s} STREQUAL "8")
set(${out} 64 PARENT_SCOPE)
return()
endif()
if(${s} STREQUAL "8")
set(${out} 64 PARENT_SCOPE)
return()
endif()
if(${s} STREQUAL "B")
set(${out} 128 PARENT_SCOPE)
return()
endif()
if(${s} STREQUAL "C")
set(${out} 256 PARENT_SCOPE)
return()
endif()
if(${s} STREQUAL "D")
set(${out} 384 PARENT_SCOPE)
return()
endif()
if(${s} STREQUAL "E")
set(${out} 512 PARENT_SCOPE)
return()
endif()
if(${s} STREQUAL "F")
set(${out} 768 PARENT_SCOPE)
return()
endif()
if(${s} STREQUAL "G")
set(${out} 1024 PARENT_SCOPE)
return()
endif()
if(${s} STREQUAL "H")
set(${out} 1536 PARENT_SCOPE)
return()
endif()
if(${s} STREQUAL "I")
set(${out} 2048 PARENT_SCOPE)
return()
endif()
endfunction()
function(add_hex_target name exe hex)
add_custom_target(${name} ALL
cmake -E env PATH="$ENV{PATH}"
# TODO: Overriding the start address with --set-start 0x08000000
# seems to be required due to some incorrect assumptions about .hex
# files in the configurator. Verify wether that's the case and fix
# the bug in configurator or delete this comment.
${CMAKE_OBJCOPY} -Oihex --set-start 0x08000000 $<TARGET_FILE:${exe}> ${hex}
BYPRODUCTS ${hex}
)
endfunction()
function(add_bin_target name exe bin)
add_custom_target(${name}
cmake -E env PATH="$ENV{PATH}"
${CMAKE_OBJCOPY} -Obinary $<TARGET_FILE:${exe}> ${bin}
BYPRODUCTS ${bin}
)
endfunction()
function(generate_map_file target)
if(CMAKE_VERSION VERSION_LESS 3.15)
set(map "$<TARGET_FILE:${target}>.map")
else()
set(map "$<TARGET_FILE_DIR:${target}>/$<TARGET_FILE_BASE_NAME:${target}>.map")
endif()
target_link_options(${target} PRIVATE "-Wl,-Map,${map}")
endfunction()
function(set_linker_script target script)
set(script_path ${STM32_LINKER_DIR}/${args_LINKER_SCRIPT}.ld)
if(NOT EXISTS ${script_path})
message(FATAL_ERROR "linker script ${script_path} doesn't exist")
endif()
set_target_properties(${target} PROPERTIES LINK_DEPENDS ${script_path})
target_link_options(${elf_target} PRIVATE -T${script_path})
endfunction()
function(add_stm32_executable)
cmake_parse_arguments(
args
# Boolean arguments
""
# Single value arguments
"FILENAME;NAME;OPTIMIZATION;OUTPUT_BIN_FILENAME;OUTPUT_HEX_FILENAME;OUTPUT_TARGET_NAME"
# Multi-value arguments
"COMPILE_DEFINITIONS;COMPILE_OPTIONS;INCLUDE_DIRECTORIES;LINK_OPTIONS;LINKER_SCRIPT;SOURCES"
# Start parsing after the known arguments
${ARGN}
)
set(elf_target ${args_NAME}.elf)
add_executable(${elf_target})
target_sources(${elf_target} PRIVATE ${args_SOURCES})
target_include_directories(${elf_target} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${args_INCLUDE_DIRECTORIES} ${STM32_INCLUDE_DIRS})
target_compile_definitions(${elf_target} PRIVATE ${args_COMPILE_DEFINITIONS})
target_compile_options(${elf_target} PRIVATE ${STM32_COMPILE_OPTIONS} ${args_COMPILE_OPTIONS})
if(WARNINGS_AS_ERRORS)
target_compile_options(${elf_target} PRIVATE -Werror)
endif()
if (IS_RELEASE_BUILD)
target_compile_options(${elf_target} PRIVATE ${args_OPTIMIZATION})
target_link_options(${elf_target} PRIVATE ${args_OPTIMIZATION})
endif()
target_link_libraries(${elf_target} PRIVATE ${STM32_LINK_LIBRARIES})
target_link_options(${elf_target} PRIVATE ${STM32_LINK_OPTIONS} ${args_LINK_OPTIONS})
generate_map_file(${elf_target})
set_linker_script(${elf_target} ${args_LINKER_SCRIPT})
if(args_FILENAME)
set(basename ${CMAKE_BINARY_DIR}/${args_FILENAME})
set(hex_filename ${basename}.hex)
add_hex_target(${args_NAME} ${elf_target} ${hex_filename})
set(bin_filename ${basename}.bin)
add_bin_target(${args_NAME}.bin ${elf_target} ${bin_filename})
endif()
if(args_OUTPUT_BIN_FILENAME)
set(${args_OUTPUT_BIN_FILENAME} ${bin_filename} PARENT_SCOPE)
endif()
if(args_OUTPUT_TARGET_NAME)
set(${args_OUTPUT_TARGET_NAME} ${elf_target} PARENT_SCOPE)
endif()
if(args_OUTPUT_HEX_FILENAME)
set(${args_OUTPUT_HEX_FILENAME} ${hex_filename} PARENT_SCOPE)
endif()
endfunction()
function(target_stm32)
if(NOT arm-none-eabi STREQUAL TOOLCHAIN)
return()
endif()
# Parse keyword arguments
cmake_parse_arguments(
args
# Boolean arguments
"DISABLE_MSC;BOOTLOADER;NO_BOOTLOADER"
# Single value arguments
"HSE_MHZ;LINKER_SCRIPT;NAME;OPENOCD_TARGET;OPTIMIZATION;STARTUP;SVD"
# Multi-value arguments
"COMPILE_DEFINITIONS;COMPILE_OPTIONS;INCLUDE_DIRECTORIES;LINK_OPTIONS;SOURCES;MSC_SOURCES;MSC_INCLUDE_DIRECTORIES;VCP_SOURCES;VCP_INCLUDE_DIRECTORIES"
# Start parsing after the known arguments
${ARGN}
)
set(name ${args_NAME})
if (args_HSE_MHZ)
set(hse_mhz ${args_HSE_MHZ})
else()
set(hse_mhz ${STM32_DEFAULT_HSE_MHZ})
endif()
set(target_sources ${STM32_STARTUP_DIR}/${args_STARTUP})
list(APPEND target_sources ${args_SOURCES})
file(GLOB target_c_sources "${CMAKE_CURRENT_SOURCE_DIR}/*.c")
file(GLOB target_h_sources "${CMAKE_CURRENT_SOURCE_DIR}/*.h")
list(APPEND target_sources ${target_c_sources} ${target_h_sources})
set(target_include_directories ${args_INCLUDE_DIRECTORIES})
set(target_definitions ${STM32_DEFINITIONS} ${COMMON_COMPILE_DEFINITIONS})
get_stm32_target_features(features "${CMAKE_CURRENT_SOURCE_DIR}" ${name})
set_property(TARGET ${elf_target} PROPERTY FEATURES ${features})
if(VCP IN_LIST features)
list(APPEND target_sources ${STM32_VCP_SRC} ${args_VCP_SOURCES})
list(APPEND target_include_directories ${args_VCP_INCLUDE_DIRECTORIES})
endif()
if(SDCARD IN_LIST features)
list(APPEND target_sources ${STM32_SDCARD_SRC} ${STM32_ASYNCFATFS_SRC})
endif()
set(msc_sources)
if(NOT args_DISABLE_MSC AND MSC IN_LIST features)
list(APPEND target_include_directories ${args_MSC_INCLUDE_DIRECTORIES})
list(APPEND msc_sources ${STM32_MSC_SRC} ${args_MSC_SOURCES})
list(APPEND target_definitions USE_USB_MSC)
if(FLASHFS IN_LIST features)
list(APPEND msc_sources ${STM32_MSC_FLASH_SRC})
endif()
if (SDCARD IN_LIST features)
list(APPEND msc_sources ${STM32_MSC_SDCARD_SRC})
endif()
endif()
math(EXPR hse_value "${hse_mhz} * 1000000")
list(APPEND target_definitions "HSE_VALUE=${hse_value}")
if (MSP_UART)
list(APPEND target_definitions "MSP_UART=${MSP_UART}")
endif()
if(args_COMPILE_DEFINITIONS)
list(APPEND target_definitions ${args_COMPILE_DEFINITIONS})
endif()
if(DEBUG_HARDFAULTS)
list(APPEND target_definitions DEBUG_HARDFAULTS)
endif()
string(TOLOWER ${PROJECT_NAME} lowercase_project_name)
set(binary_name ${lowercase_project_name}_${FIRMWARE_VERSION}_${name})
if(DEFINED BUILD_SUFFIX AND NOT "" STREQUAL "${BUILD_SUFFIX}")
set(binary_name "${binary_name}_${BUILD_SUFFIX}")
endif()
# Main firmware
add_stm32_executable(
NAME ${name}
FILENAME ${binary_name}
SOURCES ${target_sources} ${msc_sources} ${CMSIS_DSP_SRC} ${COMMON_SRC}
COMPILE_DEFINITIONS ${target_definitions}
COMPILE_OPTIONS ${args_COMPILE_OPTIONS}
INCLUDE_DIRECTORIES ${target_include_directories}
LINK_OPTIONS ${args_LINK_OPTIONS}
LINKER_SCRIPT ${args_LINKER_SCRIPT}
OPTIMIZATION ${args_OPTIMIZATION}
OUTPUT_HEX_FILENAME main_hex_filename
OUTPUT_TARGET_NAME main_target_name
)
set_property(TARGET ${main_target_name} PROPERTY OPENOCD_TARGET ${args_OPENOCD_TARGET})
set_property(TARGET ${main_target_name} PROPERTY OPENOCD_DEFAULT_INTERFACE stlink)
set_property(TARGET ${main_target_name} PROPERTY SVD ${args_SVD})
setup_firmware_target(${main_target_name} ${name} ${ARGN})
if(args_BOOTLOADER AND NOT args_NO_BOOTLOADER)
# Bootloader for the target
set(bl_suffix _bl)
add_stm32_executable(
NAME ${name}${bl_suffix}
FILENAME ${binary_name}${bl_suffix}
SOURCES ${target_sources} ${BOOTLOADER_SOURCES}
COMPILE_DEFINITIONS ${target_definitions} BOOTLOADER MSP_FIRMWARE_UPDATE
COMPILE_OPTIONS ${args_COMPILE_OPTIONS}
INCLUDE_DIRECTORIES ${target_include_directories}
LINK_OPTIONS ${args_LINK_OPTIONS}
LINKER_SCRIPT ${args_LINKER_SCRIPT}${bl_suffix}
OPTIMIZATION ${args_OPTIMIZATION}
OUTPUT_BIN_FILENAME bl_bin_filename
OUTPUT_HEX_FILENAME bl_hex_filename
OUTPUT_TARGET_NAME bl_target_name
)
setup_executable(${bl_target_name} ${name})
# Main firmware, but for running with the bootloader
set(for_bl_suffix _for_bl)
add_stm32_executable(
NAME ${name}${for_bl_suffix}
FILENAME ${binary_name}${for_bl_suffix}
SOURCES ${target_sources} ${msc_sources} ${CMSIS_DSP_SRC} ${COMMON_SRC}
COMPILE_DEFINITIONS ${target_definitions} MSP_FIRMWARE_UPDATE
COMPILE_OPTIONS ${args_COMPILE_OPTIONS}
INCLUDE_DIRECTORIES ${target_include_directories}
LINK_OPTIONS ${args_LINK_OPTIONS}
LINKER_SCRIPT ${args_LINKER_SCRIPT}${for_bl_suffix}
OPTIMIZATION ${args_OPTIMIZATION}
OUTPUT_BIN_FILENAME for_bl_bin_filename
OUTPUT_HEX_FILENAME for_bl_hex_filename
OUTPUT_TARGET_NAME for_bl_target_name
)
setup_executable(${for_bl_target_name} ${name})
# Combined with bootloader and main firmware
set(with_bl_suffix _with_bl)
set(combined_hex ${CMAKE_BINARY_DIR}/${binary_name}${with_bl_suffix}.hex)
set(with_bl_target ${name}${with_bl_suffix})
add_custom_target(${with_bl_target}
${CMAKE_SOURCE_DIR}/src/utils/combine_tool ${bl_bin_filename} ${for_bl_bin_filename} ${combined_hex}
BYPRODUCTS ${combined_hex}
)
add_dependencies(${with_bl_target} ${bl_target_name} ${for_bl_target_name})
endif()
# clean_<target>
set(generator_cmd "")
if (CMAKE_GENERATOR STREQUAL "Unix Makefiles")
set(generator_cmd "make")
elseif(CMAKE_GENERATOR STREQUAL "Ninja")
set(generator_cmd "ninja")
endif()
if (NOT generator_cmd STREQUAL "")
set(clean_target "clean_${name}")
add_custom_target(${clean_target}
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
COMMAND ${generator_cmd} clean
COMMENT "Removing intermediate files for ${name}")
set_property(TARGET ${clean_target} PROPERTY
EXCLUDE_FROM_ALL 1
EXCLUDE_FROM_DEFAULT_BUILD 1)
endif()
endfunction()
+59
View File
@@ -0,0 +1,59 @@
set(STM32_USBOTG_DIR "${MAIN_LIB_DIR}/main/STM32_USB_OTG_Driver")
set(STM32_USBCORE_DIR "${MAIN_LIB_DIR}/main/STM32_USB_Device_Library/Core")
set(STM32_USBCDC_DIR "${MAIN_LIB_DIR}/main/STM32_USB_Device_Library/Class/cdc")
set(STM32_USBHID_DIR "${MAIN_LIB_DIR}/main/STM32_USB_Device_Library/Class/hid")
set(STM32_USBWRAPPER_DIR "${MAIN_LIB_DIR}/main/STM32_USB_Device_Library/Class/hid_cdc_wrapper")
set(STM32_USBMSC_DIR "${MAIN_LIB_DIR}/main/STM32_USB_Device_Library/Class/msc")
set(STM32F4_USB_INCLUDE_DIRS
"${STM32_USBOTG_DIR}/inc"
"${STM32_USBCORE_DIR}/inc"
"${STM32_USBCDC_DIR}/inc"
"${STM32_USBHID_DIR}/inc"
"${STM32_USBWRAPPER_DIR}/inc"
"${STM32_USBMSC_DIR}/inc"
)
set(STM32_USBOTG_SRC
usb_core.c
usb_dcd.c
usb_dcd_int.c
)
list(TRANSFORM STM32_USBOTG_SRC PREPEND "${STM32_USBOTG_DIR}/src/")
set(STM32_USBCORE_SRC
usbd_core.c
usbd_ioreq.c
usbd_req.c
)
list(TRANSFORM STM32_USBCORE_SRC PREPEND "${STM32_USBCORE_DIR}/src/")
set(STM32_USBCDC_SRC
"${STM32_USBCDC_DIR}/src/usbd_cdc_core.c"
)
set(STM32_USBHID_SRC
"${STM32_USBHID_DIR}/src/usbd_hid_core.c"
)
set(STM32_USBWRAPPER_SRC
"${STM32_USBWRAPPER_DIR}/src/usbd_hid_cdc_wrapper.c"
)
set(STM32F4_USBMSC_SRC
usbd_msc_bot.c
usbd_msc_core.c
usbd_msc_data.c
usbd_msc_scsi.c
)
main_sources(STM32F4_MSC_SRC
msc/usbd_msc_desc.c
)
list(TRANSFORM STM32F4_USBMSC_SRC PREPEND "${STM32_USBMSC_DIR}/src/")
list(APPEND STM32F4_USBMSC_SRC ${STM32F4_MSC_SRC})
list(APPEND STM32F4_USB_SRC ${STM32_USBOTG_SRC})
list(APPEND STM32F4_USB_SRC ${STM32_USBCORE_SRC})
list(APPEND STM32F4_USB_SRC ${STM32_USBCDC_SRC})
list(APPEND STM32F4_USB_SRC ${STM32_USBHID_SRC})
list(APPEND STM32F4_USB_SRC ${STM32_USBWRAPPER_SRC})
+158
View File
@@ -0,0 +1,158 @@
include(cortex-m4f)
include(stm32-stdperiph)
include(stm32f4-usb)
set(STM32F4_STDPERIPH_DIR "${MAIN_LIB_DIR}/main/STM32F4/Drivers/STM32F4xx_StdPeriph_Driver")
set(STM32F4_CMSIS_DEVICE_DIR "${MAIN_LIB_DIR}/main/STM32F4/Drivers/CMSIS/Device/ST/STM32F4xx")
set(STM32F4_CMSIS_DRIVERS_DIR "${MAIN_LIB_DIR}/main/STM32F4/Drivers/CMSIS")
set(STM32F4_VCP_DIR "${MAIN_SRC_DIR}/vcpf4")
set(STM32F4_STDPERIPH_SRC_EXCLUDES
stm32f4xx_can.c
stm32f4xx_cec.c
stm32f4xx_crc.c
stm32f4xx_cryp.c
stm32f4xx_cryp_aes.c
stm32f4xx_cryp_des.c
stm32f4xx_cryp_tdes.c
stm32f4xx_dbgmcu.c
stm32f4xx_dsi.c
stm32f4xx_flash_ramfunc.c
stm32f4xx_fmpi2c.c
stm32f4xx_fmc.c
stm32f4xx_hash.c
stm32f4xx_hash_md5.c
stm32f4xx_hash_sha1.c
stm32f4xx_lptim.c
stm32f4xx_qspi.c
stm32f4xx_sai.c
stm32f4xx_spdifrx.c
)
set(STM32F4_STDPERIPH_SRC_DIR "${STM32F4_STDPERIPH_DIR}/src")
glob_except(STM32F4_STDPERIPH_SRC "${STM32F4_STDPERIPH_SRC_DIR}/*.c" "${STM32F4_STDPERIPH_SRC_EXCLUDES}")
main_sources(STM32F4_SRC
target/system_stm32f4xx.c
config/config_streamer_stm32f4.c
config/config_streamer_ram.c
config/config_streamer_extflash.c
drivers/adc_stm32f4xx.c
drivers/adc_stm32f4xx.c
drivers/bus_i2c_stm32f40x.c
drivers/serial_uart_stm32f4xx.c
drivers/system_stm32f4xx.c
drivers/timer.c
drivers/timer_impl_stdperiph.c
drivers/timer_stm32f4xx.c
drivers/uart_inverter.c
drivers/dma_stm32f4xx.c
drivers/sdcard/sdmmc_sdio_f4xx.c
)
set(STM32F4_VCP_SRC
stm32f4xx_it.c
usb_bsp.c
usbd_desc.c
usbd_usr.c
usbd_cdc_vcp.c
)
list(TRANSFORM STM32F4_VCP_SRC PREPEND "${STM32F4_VCP_DIR}/")
main_sources(STM32F4_MSC_SRC
drivers/usb_msc_f4xx.c
)
set(STM32F4_INCLUDE_DIRS
"${CMSIS_INCLUDE_DIR}"
"${CMSIS_DSP_INCLUDE_DIR}"
"${STM32F4_STDPERIPH_DIR}/inc"
"${STM32F4_CMSIS_DEVICE_DIR}"
"${STM32F4_CMSIS_DRIVERS_DIR}"
"${STM32F4_VCP_DIR}"
)
set(STM32F4_DEFINITIONS
${CORTEX_M4F_DEFINITIONS}
STM32F4
USE_STDPERIPH_DRIVER
)
function(target_stm32f4xx)
target_stm32(
SOURCES ${STM32_STDPERIPH_SRC} ${STM32F4_SRC}
COMPILE_DEFINITIONS ${STM32F4_DEFINITIONS}
COMPILE_OPTIONS ${CORTEX_M4F_COMMON_OPTIONS} ${CORTEX_M4F_COMPILE_OPTIONS}
INCLUDE_DIRECTORIES ${STM32F4_INCLUDE_DIRS}
LINK_OPTIONS ${CORTEX_M4F_COMMON_OPTIONS} ${CORTEX_M4F_LINK_OPTIONS}
MSC_SOURCES ${STM32F4_USBMSC_SRC} ${STM32F4_MSC_SRC}
VCP_SOURCES ${STM32F4_USB_SRC} ${STM32F4_VCP_SRC}
VCP_INCLUDE_DIRECTORIES ${STM32F4_USB_INCLUDE_DIRS}
OPTIMIZATION -O2
OPENOCD_TARGET stm32f4x
${ARGN}
)
endfunction()
set(STM32F405_COMPILE_DEFINITIONS
STM32F40_41xxx
STM32F405xx
MCU_FLASH_SIZE=1024
)
function(target_stm32f405xg name)
target_stm32f4xx(
NAME ${name}
STARTUP startup_stm32f40xx.s
SOURCES ${STM32F4_STDPERIPH_SRC}
COMPILE_DEFINITIONS ${STM32F405_COMPILE_DEFINITIONS}
LINKER_SCRIPT stm32_flash_f405xg
SVD STM32F405
BOOTLOADER
${ARGN}
)
endfunction()
set(STM32F411_OR_F427_STDPERIPH_SRC ${STM32F4_STDPERIPH_SRC})
set(STM32F411_OR_F427_STDPERIPH_SRC_EXCLUDES "stm32f4xx_fsmc.c")
exclude_basenames(STM32F411_OR_F427_STDPERIPH_SRC ${STM32F411_OR_F427_STDPERIPH_SRC_EXCLUDES})
set(STM32F411_COMPILE_DEFINITIONS
STM32F411xE
MCU_FLASH_SIZE=512
OPTIMIZATION -Os
)
function(target_stm32f411xe name)
target_stm32f4xx(
NAME ${name}
STARTUP startup_stm32f411xe.s
SOURCES ${STM32F411_OR_F427_STDPERIPH_SRC}
COMPILE_DEFINITIONS ${STM32F411_COMPILE_DEFINITIONS}
LINKER_SCRIPT stm32_flash_f411xe
SVD STM32F411
${ARGN}
)
endfunction()
set(STM32F427_COMPILE_DEFINITIONS
STM32F427_437xx
MCU_FLASH_SIZE=1024
)
function(target_stm32f427xg name)
target_stm32f4xx(
NAME ${name}
STARTUP startup_stm32f427xx.s
SOURCES ${STM32F411_OR_F427_STDPERIPH_SRC}
COMPILE_DEFINITIONS ${STM32F427_COMPILE_DEFINITIONS}
LINKER_SCRIPT stm32_flash_f427xg
SVD STM32F411
${ARGN}
)
endfunction()
+48
View File
@@ -0,0 +1,48 @@
set(STM32F7_USBCORE_DIR "${MAIN_LIB_DIR}/main/STM32F7/Middlewares/ST/STM32_USB_Device_Library/Core")
set(STM32F7_USBCORE_SRC
usbd_core.c
usbd_ctlreq.c
usbd_ioreq.c
)
list(TRANSFORM STM32F7_USBCORE_SRC PREPEND "${STM32F7_USBCORE_DIR}/Src/")
set(STM32F7_USBCDC_DIR "${MAIN_LIB_DIR}/main/STM32F7/Middlewares/ST/STM32_USB_Device_Library/Class/CDC")
set(STM32F7_USBCDC_SRC
usbd_cdc.c
)
list(TRANSFORM STM32F7_USBCDC_SRC PREPEND "${STM32F7_USBCDC_DIR}/Src/")
set(STM32F7_USBHID_DIR "${MAIN_LIB_DIR}/main/STM32F7/Middlewares/ST/STM32_USB_Device_Library/Class/HID")
set(STM32F7_USBHID_SRC
usbd_hid.c
)
list(TRANSFORM STM32F7_USBHID_SRC PREPEND "${STM32F7_USBHID_DIR}/Src/")
set(STM32F7_USBCDCHID_DIR "${MAIN_LIB_DIR}/main/STM32F7/Middlewares/ST/STM32_USB_Device_Library/Class/CDC_HID")
set(STM32F7_USBCDCHID_SRC
usbd_cdc_hid.c
)
list(TRANSFORM STM32F7_USBCDCHID_SRC PREPEND "${STM32F7_USBCDCHID_DIR}/Src/")
set(STM32F7_USBMSC_DIR "${MAIN_LIB_DIR}/main/STM32F7/Middlewares/ST/STM32_USB_Device_Library/Class/MSC")
set(STM32F7_USBMSC_SRC
usbd_msc.c
usbd_msc_bot.c
usbd_msc_data.c
usbd_msc_scsi.c
)
list(TRANSFORM STM32F7_USBMSC_SRC PREPEND "${STM32F7_USBMSC_DIR}/Src/")
set(STM32F7_USB_INCLUDE_DIRS
"${STM32F7_USBCORE_DIR}/Inc"
"${STM32F7_USBCDC_DIR}/Inc"
"${STM32F7_USBHID_DIR}/Inc"
"${STM32F7_USBCDCHID_DIR}/Inc"
"${STM32F7_USBMSC_DIR}/Inc"
)
list(APPEND STM32F7_USB_SRC ${STM32F7_USBCORE_SRC})
list(APPEND STM32F7_USB_SRC ${STM32F7_USBCDC_SRC})
list(APPEND STM32F7_USB_SRC ${STM32F7_USBHID_SRC})
list(APPEND STM32F7_USB_SRC ${STM32F7_USBCDCHID_SRC})
list(APPEND STM32F7_USB_SRC ${STM32F7_USBMSC_SRC})
+144
View File
@@ -0,0 +1,144 @@
include(cortex-m7)
include(stm32f7-usb)
set(STM32F7_HAL_DIR "${MAIN_LIB_DIR}/main/STM32F7/Drivers/STM32F7xx_HAL_Driver")
set(STM32F7_HAL_SRC
stm32f7xx_hal.c
stm32f7xx_hal_adc.c
stm32f7xx_hal_adc_ex.c
stm32f7xx_hal_cortex.c
stm32f7xx_hal_dac.c
stm32f7xx_hal_dac_ex.c
stm32f7xx_hal_dma.c
stm32f7xx_hal_dma_ex.c
stm32f7xx_hal_flash.c
stm32f7xx_hal_flash_ex.c
stm32f7xx_hal_gpio.c
stm32f7xx_hal_i2c.c
stm32f7xx_hal_i2c_ex.c
stm32f7xx_hal_pcd.c
stm32f7xx_hal_pcd_ex.c
stm32f7xx_hal_pwr.c
stm32f7xx_hal_pwr_ex.c
stm32f7xx_hal_rcc.c
stm32f7xx_hal_rcc_ex.c
stm32f7xx_hal_rtc.c
stm32f7xx_hal_rtc_ex.c
stm32f7xx_hal_spi.c
stm32f7xx_hal_tim.c
stm32f7xx_hal_tim_ex.c
stm32f7xx_hal_uart.c
stm32f7xx_hal_usart.c
stm32f7xx_ll_dma.c
stm32f7xx_ll_dma2d.c
stm32f7xx_ll_gpio.c
stm32f7xx_ll_rcc.c
stm32f7xx_ll_spi.c
stm32f7xx_ll_tim.c
stm32f7xx_ll_usb.c
stm32f7xx_ll_utils.c
stm32f7xx_hal_sd.c
stm32f7xx_ll_sdmmc.c
)
list(TRANSFORM STM32F7_HAL_SRC PREPEND "${STM32F7_HAL_DIR}/Src/")
set(STM32F7_CMSIS_DEVICE_DIR "${MAIN_LIB_DIR}/main/STM32F7/Drivers/CMSIS/Device/ST/STM32F7xx")
set(STM32F7_VCP_DIR "${MAIN_SRC_DIR}/vcp_hal")
set(STM32F7_VCP_SRC
usbd_desc.c
usbd_conf_stm32f7xx.c
usbd_cdc_interface.c
)
list(TRANSFORM STM32F7_VCP_SRC PREPEND "${STM32F7_VCP_DIR}/")
set(STM32F7_INCLUDE_DIRS
${STM32F7_HAL_DIR}/Inc
${STM32F7_CMSIS_DEVICE_DIR}/Include
)
main_sources(STM32F7_SRC
target/system_stm32f7xx.c
config/config_streamer_stm32f7.c
config/config_streamer_ram.c
config/config_streamer_extflash.c
drivers/adc_stm32f7xx.c
drivers/bus_i2c_hal.c
drivers/dma_stm32f7xx.c
drivers/bus_spi_hal_ll.c
drivers/timer.c
drivers/timer_impl_hal.c
drivers/timer_stm32f7xx.c
drivers/system_stm32f7xx.c
drivers/serial_uart_stm32f7xx.c
drivers/serial_uart_hal.c
drivers/sdcard/sdmmc_sdio_hal.c
)
main_sources(STM32F7_MSC_SRC
drivers/usb_msc_f7xx.c
)
set(STM32F7_DEFINITIONS
${CORTEX_M7_DEFINITIONS}
USE_HAL_DRIVER
USE_FULL_LL_DRIVER
)
function(target_stm32f7xx)
target_stm32(
SOURCES ${STM32F7_HAL_SRC} ${STM32F7_SRC}
COMPILE_DEFINITIONS ${STM32F7_DEFINITIONS}
COMPILE_OPTIONS ${CORTEX_M7_COMMON_OPTIONS} ${CORTEX_M7_COMPILE_OPTIONS}
INCLUDE_DIRECTORIES ${STM32F7_INCLUDE_DIRS}
LINK_OPTIONS ${CORTEX_M7_COMMON_OPTIONS} ${CORTEX_M7_LINK_OPTIONS}
MSC_SOURCES ${STM32F7_USBMSC_SRC} ${STM32F7_MSC_SRC}
VCP_SOURCES ${STM32F7_USB_SRC} ${STM32F7_VCP_SRC}
VCP_INCLUDE_DIRECTORIES ${STM32F7_USB_INCLUDE_DIRS} ${STM32F7_VCP_DIR}
OPENOCD_TARGET stm32f7x
BOOTLOADER
${ARGN}
)
endfunction()
macro(define_target_stm32f7 subfamily size)
function(target_stm32f7${subfamily}x${size} name)
set(func_ARGV ARGV)
string(TOUPPER ${size} upper_size)
get_stm32_flash_size(flash_size ${size})
if(flash_size GREATER 512)
set(opt -O2)
else()
set(opt -Os)
endif()
set(definitions
STM32F7
STM32F7${subfamily}xx
STM32F7${subfamily}x${upper_size}
MCU_FLASH_SIZE=${flash_size}
)
target_stm32f7xx(
NAME ${name}
STARTUP startup_stm32f7${subfamily}xx.s
COMPILE_DEFINITIONS ${definitions}
LINKER_SCRIPT stm32_flash_f7${subfamily}x${size}
OPTIMIZATION ${opt}
${${func_ARGV}}
)
endfunction()
endmacro()
define_target_stm32f7(22 e)
define_target_stm32f7(45 g)
define_target_stm32f7(46 g)
define_target_stm32f7(65 g)
define_target_stm32f7(65 i)
+41
View File
@@ -0,0 +1,41 @@
set(STM32H7_USBCORE_DIR "${MAIN_LIB_DIR}/main/STM32H7/Middlewares/ST/STM32_USB_Device_Library/Core")
set(STM32H7_USBCORE_SRC
usbd_core.c
usbd_ctlreq.c
usbd_ioreq.c
)
list(TRANSFORM STM32H7_USBCORE_SRC PREPEND "${STM32H7_USBCORE_DIR}/Src/")
set(STM32H7_USBCDC_DIR "${MAIN_LIB_DIR}/main/STM32H7/Middlewares/ST/STM32_USB_Device_Library/Class/CDC")
set(STM32H7_USBCDC_SRC
usbd_cdc.c
)
list(TRANSFORM STM32H7_USBCDC_SRC PREPEND "${STM32H7_USBCDC_DIR}/Src/")
set(STM32H7_USBHID_DIR "${MAIN_LIB_DIR}/main/STM32H7/Middlewares/ST/STM32_USB_Device_Library/Class/HID")
set(STM32H7_USBHID_SRC
usbd_hid.c
)
list(TRANSFORM STM32H7_USBHID_SRC PREPEND "${STM32H7_USBHID_DIR}/Src/")
set(STM32H7_USBMSC_DIR "${MAIN_LIB_DIR}/main/STM32H7/Middlewares/ST/STM32_USB_Device_Library/Class/MSC")
set(STM32H7_USBMSC_SRC
usbd_msc.c
usbd_msc_bot.c
usbd_msc_data.c
usbd_msc_scsi.c
)
list(TRANSFORM STM32H7_USBMSC_SRC PREPEND "${STM32H7_USBMSC_DIR}/Src/")
set(STM32H7_USB_INCLUDE_DIRS
"${STM32H7_USBCORE_DIR}/Inc"
"${STM32H7_USBCDC_DIR}/Inc"
"${STM32H7_USBHID_DIR}/Inc"
"${STM32H7_USBMSC_DIR}/Inc"
)
list(APPEND STM32H7_USB_SRC ${STM32H7_USBCORE_SRC})
list(APPEND STM32H7_USB_SRC ${STM32H7_USBCDC_SRC})
list(APPEND STM32H7_USB_SRC ${STM32H7_USBHID_SRC})
#XXX: Not working yet
#list(APPEND STM32H7_USB_SRC ${STM32H7_USBMSC_SRC})
+225
View File
@@ -0,0 +1,225 @@
include(cortex-m7)
include(stm32h7-usb)
set(STM32H7_CMSIS_DEVICE_DIR "${MAIN_LIB_DIR}/main/STM32H7/Drivers/CMSIS/Device/ST/STM32H7xx")
set(STM32H7_HAL_DIR "${MAIN_LIB_DIR}/main/STM32H7/Drivers/STM32H7xx_HAL_Driver")
set(STM32H7_HAL_SRC
stm32h7xx_hal.c
stm32h7xx_hal_adc.c
stm32h7xx_hal_adc_ex.c
# stm32h7xx_hal_cec.c
# stm32h7xx_hal_comp.c
stm32h7xx_hal_cortex.c
# stm32h7xx_hal_crc.c
# stm32h7xx_hal_crc_ex.c
# stm32h7xx_hal_cryp.c
# stm32h7xx_hal_cryp_ex.c
stm32h7xx_hal_dac.c
stm32h7xx_hal_dac_ex.c
# stm32h7xx_hal_dcmi.c
# stm32h7xx_hal_dfsdm.c
# stm32h7xx_hal_dfsdm_ex.c
stm32h7xx_hal_dma.c
# stm32h7xx_hal_dma2d.c
stm32h7xx_hal_dma_ex.c
# stm32h7xx_hal_dsi.c
stm32h7xx_hal_dts.c
# stm32h7xx_hal_eth.c
# stm32h7xx_hal_eth_ex.c
stm32h7xx_hal_exti.c
# stm32h7xx_hal_fdcan.c
stm32h7xx_hal_flash.c
stm32h7xx_hal_flash_ex.c
stm32h7xx_hal_gfxmmu.c
stm32h7xx_hal_gpio.c
# stm32h7xx_hal_hash.c
# stm32h7xx_hal_hash_ex.c
# stm32h7xx_hal_hcd.c
# stm32h7xx_hal_hrtim.c
# stm32h7xx_hal_hsem.c
stm32h7xx_hal_i2c.c
stm32h7xx_hal_i2c_ex.c
# stm32h7xx_hal_i2s.c
# stm32h7xx_hal_i2s_ex.c
# stm32h7xx_hal_irda.c
# stm32h7xx_hal_iwdg.c
# stm32h7xx_hal_jpeg.c
# stm32h7xx_hal_lptim.c
# stm32h7xx_hal_ltdc.c
# stm32h7xx_hal_ltdc_ex.c
# stm32h7xx_hal_mdios.c
# stm32h7xx_hal_mdma.c
# stm32h7xx_hal_mmc.c
# stm32h7xx_hal_mmc_ex.c
# stm32h7xx_hal_nand.c
# stm32h7xx_hal_nor.c
# stm32h7xx_hal_opamp.c
# stm32h7xx_hal_opamp_ex.c
stm32h7xx_hal_ospi.c
stm32h7xx_hal_otfdec.c
stm32h7xx_hal_pcd.c
stm32h7xx_hal_pcd_ex.c
stm32h7xx_hal_pssi.c
stm32h7xx_hal_pwr.c
stm32h7xx_hal_pwr_ex.c
stm32h7xx_hal_qspi.c
# stm32h7xx_hal_ramecc.c
stm32h7xx_hal_rcc.c
stm32h7xx_hal_rcc_ex.c
# stm32h7xx_hal_rng.c
# stm32h7xx_hal_rng_ex.c
stm32h7xx_hal_rtc.c
stm32h7xx_hal_rtc_ex.c
# stm32h7xx_hal_sai.c
# stm32h7xx_hal_sai_ex.c
stm32h7xx_hal_sd.c
stm32h7xx_hal_sd_ex.c
# stm32h7xx_hal_sdram.c
# stm32h7xx_hal_smartcard.c
# stm32h7xx_hal_smartcard_ex.c
# stm32h7xx_hal_smbus.c
# stm32h7xx_hal_spdifrx.c
stm32h7xx_hal_spi.c
stm32h7xx_hal_spi_ex.c
# stm32h7xx_hal_sram.c
# stm32h7xx_hal_swpmi.c
stm32h7xx_hal_tim.c
stm32h7xx_hal_tim_ex.c
stm32h7xx_hal_uart.c
stm32h7xx_hal_uart_ex.c
# stm32h7xx_hal_usart.c
# stm32h7xx_hal_usart_ex.c
# stm32h7xx_hal_wwdg.c
# stm32h7xx_ll_adc.c
# stm32h7xx_ll_bdma.c
# stm32h7xx_ll_comp.c
# stm32h7xx_ll_crc.c
stm32h7xx_ll_crs.c
# stm32h7xx_ll_dac.c
# stm32h7xx_ll_delayblock.c
stm32h7xx_ll_dma.c
# stm32h7xx_ll_dma2d.c
stm32h7xx_ll_exti.c
# stm32h7xx_ll_fmc.c
# stm32h7xx_ll_gpio.c
# stm32h7xx_ll_hrtim.c
stm32h7xx_ll_i2c.c
# stm32h7xx_ll_lptim.c
# stm32h7xx_ll_lpuart.c
# stm32h7xx_ll_mdma.c
# stm32h7xx_ll_opamp.c
# stm32h7xx_ll_pwr.c
# stm32h7xx_ll_rcc.c
# stm32h7xx_ll_rng.c
# stm32h7xx_ll_rtc.c
stm32h7xx_ll_sdmmc.c
stm32h7xx_ll_spi.c
# stm32h7xx_ll_swpmi.c
stm32h7xx_ll_tim.c
# stm32h7xx_ll_usart.c
stm32h7xx_ll_usb.c
# stm32h7xx_ll_utils.c
)
list(TRANSFORM STM32H7_HAL_SRC PREPEND "${STM32H7_HAL_DIR}/Src/")
set(STM32H7_VCP_DIR "${MAIN_SRC_DIR}/vcp_hal")
set(STM32H7_VCP_SRC
usbd_desc.c
usbd_conf_stm32h7xx.c
usbd_cdc_interface.c
)
list(TRANSFORM STM32H7_VCP_SRC PREPEND "${STM32H7_VCP_DIR}/")
set(STM32H7_INCLUDE_DIRS
${STM32H7_HAL_DIR}/Inc
${STM32H7_CMSIS_DEVICE_DIR}/Include
)
main_sources(STM32H7_SRC
target/system_stm32h7xx.c
config/config_streamer_stm32h7.c
config/config_streamer_ram.c
config/config_streamer_extflash.c
drivers/adc_stm32h7xx.c
drivers/bus_i2c_hal.c
drivers/dma_stm32h7xx.c
drivers/bus_spi_hal_ll.c
drivers/bus_quadspi.c
drivers/bus_quadspi_hal.c
drivers/memprot.h
drivers/memprot_hal.c
drivers/memprot_stm32h7xx.c
drivers/timer.c
drivers/timer_impl_hal.c
drivers/timer_stm32h7xx.c
drivers/system_stm32h7xx.c
drivers/serial_uart_stm32h7xx.c
drivers/serial_uart_hal.c
drivers/sdio.h
drivers/sdcard/sdmmc_sdio_hal.c
)
main_sources(STM32H7_MSC_SRC
drivers/usb_msc_h7xx.c
)
set(STM32H7_DEFINITIONS
${CORTEX_M7_DEFINITIONS}
USE_HAL_DRIVER
USE_FULL_LL_DRIVER
MAX_MPU_REGIONS=16
)
function(target_stm32h7xx)
target_stm32(
SOURCES ${STM32H7_HAL_SRC} ${STM32H7_SRC}
COMPILE_DEFINITIONS ${STM32H7_DEFINITIONS}
COMPILE_OPTIONS ${CORTEX_M7_COMMON_OPTIONS} ${CORTEX_M7_COMPILE_OPTIONS}
INCLUDE_DIRECTORIES ${STM32H7_INCLUDE_DIRS}
LINK_OPTIONS ${CORTEX_M7_COMMON_OPTIONS} ${CORTEX_M7_LINK_OPTIONS}
MSC_SOURCES ${STM32H7_USBMSC_SRC} ${STM32H7_MSC_SRC}
VCP_SOURCES ${STM32H7_USB_SRC} ${STM32H7_VCP_SRC}
VCP_INCLUDE_DIRECTORIES ${STM32H7_USB_INCLUDE_DIRS} ${STM32H7_VCP_DIR}
OPTIMIZATION -O2
OPENOCD_TARGET stm32h7x
# BOOTLOADER
${ARGN}
)
endfunction()
macro(define_target_stm32h7 subfamily size)
function(target_stm32h7${subfamily}x${size} name)
set(func_ARGV ARGV)
string(TOUPPER ${size} upper_size)
get_stm32_flash_size(flash_size ${size})
set(definitions
STM32H7
STM32H7${subfamily}xx
STM32H7${subfamily}x${upper_size}
# stm32h743xx.h defined FLASH_SIZE, used by HAL, but in bytes
# use MCU_FLASH_SIZE since we use KiB in our code
MCU_FLASH_SIZE=${flash_size}
)
target_stm32h7xx(
NAME ${name}
STARTUP startup_stm32h7${subfamily}xx.s
COMPILE_DEFINITIONS ${definitions}
LINKER_SCRIPT stm32_flash_h7${subfamily}x${size}
${${func_ARGV}}
SVD STM32H7${subfamily}
)
endfunction()
endmacro()
define_target_stm32h7(43 i)
define_target_stm32h7(A3 i)
+16
View File
@@ -0,0 +1,16 @@
function(setup_svd target_exe target_name)
get_property(svd_name TARGET ${target_exe} PROPERTY SVD)
set(svd_target_name "svd_${target_name}")
if (svd_name AND NOT svd_name STREQUAL "")
add_custom_target(${svd_target_name}
COMMAND ${CMAKE_COMMAND} -E copy
${SVD_DIR}/${svd_name}.svd
${CMAKE_BINARY_DIR}/svd/${target_name}.svd
)
else()
add_custom_target(${svd_target_name}
${CMAKE_COMMAND} -E echo "target ${target_name} does not declare an SVD filename"
COMMAND ${CMAKE_COMMAND} -E false)
endif()
exclude_from_all(${svd_target_name})
endfunction()
+224
View File
@@ -0,0 +1,224 @@
#!/bin/bash
#
# PG Validation for Release Preparation
#
# This script validates Parameter Group struct sizes against the reference
# target (SPEEDYBEEF745AIO) to catch unversioned struct changes before release.
#
# Usage: ./cmake/validate-pg-for-release.sh
#
# Exit codes:
# 0 - Validation passed
# 1 - Validation failed (size changed without version increment)
# 2 - Build or setup error
#
set -euo pipefail
SCRIPT_DIR=$(dirname "$0")
REPO_ROOT=$(cd "$SCRIPT_DIR/.." && pwd)
REFERENCE_TARGET="SPEEDYBEEF745AIO"
BUILD_DIR="$REPO_ROOT/build"
DB_FILE="$SCRIPT_DIR/pg_struct_sizes.reference.db"
echo "🔍 Validating PG struct sizes for release..."
echo ""
# Check prerequisites
if ! command -v arm-none-eabi-gcc &> /dev/null; then
echo "❌ Error: arm-none-eabi-gcc not found" >&2
echo " Install ARM toolchain first" >&2
exit 2
fi
if ! command -v cmake &> /dev/null; then
echo "❌ Error: cmake not found" >&2
exit 2
fi
if [ ! -f "$DB_FILE" ]; then
echo "❌ Error: Reference database not found: $DB_FILE" >&2
exit 2
fi
# Setup build directory
if [ ! -d "$BUILD_DIR" ]; then
echo "📁 Creating build directory..."
mkdir -p "$BUILD_DIR"
cd "$BUILD_DIR"
cmake -G "Unix Makefiles" ..
else
echo "📁 Using existing build directory"
cd "$BUILD_DIR"
fi
# Build reference target
echo "🔨 Building reference target: $REFERENCE_TARGET..."
echo " (This may take a few minutes on first build)"
echo ""
BUILD_LOG=$(mktemp)
if ! make "$REFERENCE_TARGET.elf" > "$BUILD_LOG" 2>&1; then
echo "❌ Build failed. See $BUILD_LOG for details" >&2
tail -30 "$BUILD_LOG" >&2
exit 2
fi
rm -f "$BUILD_LOG"
ELF_FILE="$BUILD_DIR/bin/$REFERENCE_TARGET.elf"
if [ ! -f "$ELF_FILE" ]; then
echo "❌ Error: ELF file not found: $ELF_FILE" >&2
exit 2
fi
echo "✓ Build completed successfully"
echo ""
# Extract PG struct sizes from ELF binary
echo "📊 Extracting PG struct sizes from binary..."
echo ""
# Detect architecture for correct nm command
if command -v arm-none-eabi-nm &> /dev/null && [[ $(file "$ELF_FILE") == *"ARM"* ]]; then
NM_CMD="arm-none-eabi-nm"
else
NM_CMD="nm"
fi
# Extract current sizes and versions
TEMP_CURRENT=$(mktemp)
cd "$REPO_ROOT"
$NM_CMD --print-size "$ELF_FILE" 2>/dev/null | grep "pgResetTemplate_" | \
while read addr size_hex type symbol; do
# Extract config name from symbol
config_name="${symbol#pgResetTemplate_}"
# Convert hex size to decimal
size_dec=$((16#$size_hex))
# Find corresponding struct type and version from PG_REGISTER
pg_register_line=$(grep -rh "PG_REGISTER.*$config_name" src/main --include="*.c" 2>/dev/null | head -1)
struct_type=$(echo "$pg_register_line" | grep -oP 'PG_REGISTER[^(]*\(\K[^,]+' | head -1)
if [ -z "$struct_type" ]; then
# Fallback: convert config name to struct type
struct_type="${config_name}_t"
fi
# Extract PG version (4th parameter in PG_REGISTER)
version=$(echo "$pg_register_line" | grep -oP 'PG_REGISTER[^(]*\([^,]+,[^,]+,[^,]+,\s*\K\d+' | head -1)
if [ -z "$version" ]; then
version="0"
fi
printf "%-30s %3s %s\n" "$struct_type" "$size_dec" "$version"
done | sort -u > "$TEMP_CURRENT"
# Validate against reference database
echo "🔍 Validating against reference database..."
echo ""
FAILED=0
ISSUES=""
UPDATED=""
# Check each struct in current binary
while read -r struct_type current_size current_version; do
[ -z "$struct_type" ] && continue
# Look up in database
db_entry=$(grep "^$struct_type " "$DB_FILE" 2>/dev/null || echo "")
if [ -z "$db_entry" ]; then
# New struct not in database - add it automatically
if [ -z "$current_version" ]; then
echo " ⚠️ Warning: Cannot find PG version for new struct $struct_type" >&2
echo " ️ New: $struct_type (${current_size}B) - skipping (no PG_REGISTER found)"
continue
fi
echo " New: $struct_type (${current_size}B, v$current_version)"
# Add to database
printf "%-30s %3s %s\n" "$struct_type" "$current_size" "$current_version" >> "$DB_FILE"
UPDATED="$UPDATED\n • $struct_type: NEW (${current_size}B, v$current_version)"
continue
fi
db_size=$(echo "$db_entry" | awk '{print $2}')
db_version=$(echo "$db_entry" | awk '{print $3}')
if [ "$current_size" != "$db_size" ]; then
# Size changed - check if version was incremented
if [ -z "$current_version" ]; then
echo " ⚠️ Warning: Cannot find PG version for $struct_type" >&2
continue
fi
if [ "$current_version" -le "$db_version" ]; then
# SIZE CHANGED BUT VERSION NOT INCREMENTED - FAIL BUILD
echo "$struct_type: size changed ${db_size}B → ${current_size}B but version not incremented (still v$current_version)"
ISSUES="$ISSUES\n • $struct_type: ${db_size}B → ${current_size}B (version $current_version should be $((current_version + 1)))"
FAILED=1
else
# Version was incremented - this is valid, update database
echo "$struct_type: size changed ${db_size}B → ${current_size}B with version increment v$db_version → v$current_version"
# Update database entry with new size and version
sed -i "s|^$struct_type[[:space:]]\+[0-9]\+[[:space:]]\+[0-9]\+$|$(printf "%-30s %3s %s" "$struct_type" "$current_size" "$current_version")|" "$DB_FILE"
UPDATED="$UPDATED\n • $struct_type: ${db_size}B → ${current_size}B (v$db_version → v$current_version)"
fi
else
# Size unchanged
echo "$struct_type (${current_size}B)"
fi
done < "$TEMP_CURRENT"
rm -f "$TEMP_CURRENT"
# Report results
echo ""
if [ $FAILED -eq 1 ]; then
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "❌ PG VALIDATION FAILED - DO NOT PROCEED WITH RELEASE"
echo ""
echo "The following structs changed size without version increments:"
echo -e "$ISSUES"
echo ""
echo "Action required:"
echo " 1. Identify which PR(s) changed the affected struct(s)"
echo " 2. Create hotfix PR to increment PG version(s)"
echo " 3. Merge hotfix to target branch"
echo " 4. Re-run this validation"
echo ""
echo "Fix: Increment PG version in PG_REGISTER for affected structs"
echo ""
echo "See claude/release-manager/guides/7-pg-validation.md for details"
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
exit 1
fi
if [ -n "$UPDATED" ]; then
echo "📝 Database auto-updated for structs with version increments:"
echo -e "$UPDATED"
echo ""
fi
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "✅ PG VALIDATION PASSED"
echo ""
echo "All struct sizes validated successfully against reference target."
echo "Safe to proceed with release preparation."
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
exit 0
File diff suppressed because it is too large Load Diff
+61681
View File
File diff suppressed because it is too large Load Diff
+27110
View File
File diff suppressed because it is too large Load Diff
+63121
View File
File diff suppressed because it is too large Load Diff
+57155
View File
File diff suppressed because it is too large Load Diff
+61861
View File
File diff suppressed because it is too large Load Diff
+71136
View File
File diff suppressed because it is too large Load Diff
+70681
View File
File diff suppressed because it is too large Load Diff
+105015
View File
File diff suppressed because it is too large Load Diff
+28
View File
@@ -0,0 +1,28 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
// ******* INAV ********
// Define the following values in settings.json
// - BUILD_DIR: Relative path to the build directory
// - TARGET: Target name that you want to launch
"version": "0.2.0",
"configurations": [
{
"name": "Cortex Debug",
"cwd": "${workspaceRoot}",
"executable": "${config:BUILD_DIR}/bin/${config:TARGET}.elf",
"request": "launch",
"type": "cortex-debug",
"servertype": "openocd",
"device": "${config:TARGET}",
"configFiles": [
"${config:BUILD_DIR}/openocd/${config:TARGET}.cfg"
],
"preLaunchTask": "openocd-debug-prepare",
"svdFile": "${config:BUILD_DIR}/svd/${config:TARGET}.svd",
}
]
}
+51
View File
@@ -0,0 +1,51 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"options": {
"env": {
"TARGET": "${config:TARGET}",
}
},
"tasks": [
{
"label": "target",
"type": "shell",
"command": "make", "args": ["-C", "${config:BUILD_DIR}", "${config:TARGET}"],
"problemMatcher": "$gcc",
"group": {
"kind": "build",
"isDefault": true
},
"presentation": {
"echo": true,
"reveal": "always",
"focus": false,
}
},
{
"label": "flash",
"type": "shell",
"command": "make", "args": ["-C", "${config:BUILD_DIR}", "openocd_flash_${config:TARGET}"],
"dependsOn": "elf"
},
{
"label": "svd",
"type": "shell",
"command": "make", "args": ["-C", "${config:BUILD_DIR}", "svd_${config:TARGET}"],
"problemMatcher": []
},
{
"label": "openocd-cfg",
"type": "shell",
"command": "make", "args": ["-C", "${config:BUILD_DIR}", "openocd_cfg_${config:TARGET}"],
"problemMatcher": []
},
{
"label": "openocd-debug-prepare",
"type": "shell",
"dependsOn": ["svd", "openocd-cfg", "flash"],
"problemMatcher": []
}
]
}
+74
View File
@@ -0,0 +1,74 @@
# 1-wire passthrough esc programming
### ESCs must have the BlHeli Bootloader.
If your ESCs didn't come with BlHeli Bootloader, you'll need to flash them with an ArduinoISP programmer first. [Here's a guide](http://bit.ly/blheli-f20).
This is the option you need to select for the bootloader:
![Flashing BlHeli Bootloader](assets/images/blheli-bootloader.png)
Currently supported on all boards with at least 128kB of flash memory (all F3, F4 and F7).
## Usage
- Plug in the USB cable and connect to your board with the INAV configurator.
- Open the BlHeli Suite.
- Ensure you have selected the correct Atmel or SILABS "Cleanflight" option under the "Select ATMEL / SILABS Interface" menu option.
- Ensure you have port for your external USB/UART adapter selected, if you're using one, otherwise pick the same COM port that you normally use for INAV.
- Click "Connect" and wait for the connection to complete. If you get a COM error, hit connect again. It will probably work.
- Use the boxes at the bottom to select the ESCs you have connected. Note that the boxes correspond directly to the ports on your flight controller. For example if you have motors on ports 1-4, pick boxes 1-4 or in the case of a tri-copter that uses motors on ports 3, 4 and 5, select those ports in BlHeli.
- Click "Read Setup"
- Use BlHeli suite as normal.
- When you're finished with one ESC, click "Disconnect"
## Implementing and Configuring targets
The following parameters can be used to enable and configure this in the related target.h file:
USE_SERIAL_1WIRE Enables the 1wire code, defined in target.h
- For new targets
- in `target.h`
```
// Turn on serial 1wire passthrough
#define USE_SERIAL_1WIRE
// How many escs does this board support?
#define ESC_COUNT 6
// STM32F3DISCOVERY TX - PC3 connects to UART RX
#define S1W_TX_GPIO GPIOC
#define S1W_TX_PIN GPIO_Pin_3
// STM32F3DISCOVERY RX - PC1 connects to UART TX
#define S1W_RX_GPIO GPIOC
#define S1W_RX_PIN GPIO_Pin_1
```
- in `serial_1wire.c`
```
// Define your esc hardware
#if defined(STM32F3DISCOVERY)
const escHardware_t escHardware[ESC_COUNT] = {
{ GPIOD, 12 },
{ GPIOD, 13 },
{ GPIOD, 14 },
{ GPIOD, 15 },
{ GPIOA, 1 },
{ GPIOA, 2 }
};
```
## Development Notes
On the STM32F3DISCOVERY, an external pullup on the ESC line may be necessary. I needed a 3v, 4.7k pullup.
+111
View File
@@ -0,0 +1,111 @@
# ADS-B
[Automatic Dependent Surveillance Broadcast](https://en.wikipedia.org/wiki/Automatic_Dependent_Surveillance%E2%80%93Broadcast)
is an air traffic surveillance technology that enables aircraft to be accurately tracked by air traffic controllers and other pilots without the need for conventional radar.
## Current state
OSD can be configured to shows the closest aircraft.
## OSD ADSB Info element
* "-" no ADSB device detected
* "H" IMU heading is not valid
* "G" no GPS fix or less than 4 stats
* "[Number]" count of ADSB aircrafts
## OSD ADSB Warning element
OSD can be configured to simple view (one line) or to extended view (two lines) by \
`set osd_adsb_warning_style=EXTENDED`
### Simple view
`{distance to vehicle} {direction to vehicle} {altitude diff}`
### Extended view
`{distance to vehicle} {direction to vehicle} {altitude diff}` \
`{Emiter Type} {Vehicle direction} {Vehicle Speed}`
![ADSB OSD](assets/images/adsb-info.png)
## Hardware
All ADSB receivers which can send Mavlink [ADSB_VEHICLE](https://mavlink.io/en/messages/common.html#ADSB_VEHICLE) message are supported
* [PINGRX](https://uavionix.com/product/pingrx-pro/) (not tested)
* [TT-SC1](https://www.aerobits.pl/product/aero/) (tested)
* [ADSBee1090](https://pantsforbirds.com/adsbee-1090/) (tested)
* [SoftRF](https://github.com/lyusupov/SoftRF/wiki/Nano-Edition) (tested)
## TT-SC1 settings
* download software for ADSB TT-SC1 from https://www.aerobits.pl/product/aero/ , file Micro_ADSB_App-vX.XX.X_win_setup.zip and install it
* connect your ADSB to FC, connect both RX and TX pins
* in INAV configurator ports TAB set telemetry MAVLINK, and baudrate 115200
* go to CLI in inav configurator and set serialpassthrough for port you connected ADSB ```serialpassthrough [PORT_YOU_SELECTED - 1] 115200 rxtx``` and close configurator
* open ADSB program you installed, got to settings and set "telemetry" = MAVLINK,
PCB board for TT-SC1-B module https://oshwlab.com/error414/adsb-power-board
![TT-SC1 settings](Screenshots/ADSB_TTSC01_settings.png)
## ADSBee 1090 settings
* connect to ADSBee1090 via USB and set COMMS_UART to mavlink2 \
``
AT+PROTOCOL=COMMS_UART,MAVLINK2
``\
``
AT+BAUDRATE=COMMS_UART,115200
``\
It's recommended to turn of wifi \
``
AT+ESP32_ENABLE=0
``\
``
AT+SETTINGS=SAVE
``
* in INAV configurator ports TAB set telemetry MAVLINK, and baudrate 115200
* https://pantsforbirds.com/adsbee-1090/quick-start/
## SoftRF settings
SoftRF supports only MAVLink version 1.
```
set mavlink_version = 1
save
```
The baud rate for SoftRF is 57600. INAV provides minimal support for SoftRF and supports only
the mandatory MAVLink messages: `MAVLINK_MSG_ID_HEARTBEAT`, `MAVLINK_MSG_ID_SYSTEM_TIME`, and `MAVLINK_MSG_ID_GPS_RAW_INT`.
The following messages are not supported: `MAVLINK_MSG_ID_SYS_STATUS`, `MAVLINK_MSG_ID_VFR_HUD`, and `MAVLINK_MSG_ID_ATTITUDE`.
## Alert and Warning
The ADS-B warning/alert system supports two operating modes, controlled by the parameter osd_adsb_calculation_use_cpa (ON or OFF).
---
### ADS-B Warning and Alert Messages (CPA Mode OFF)
The ADS-B warning/alert system supports two operating modes, controlled by the parameter **osd_adsb_calculation_use_cpa** (ON or OFF).
When **osd_adsb_calculation_use_cpa = OFF**, the system evaluates only the **current distance between the aircraft and the UAV**. The aircraft with the **shortest distance** is always selected for monitoring.
- If the aircraft enters the **warning zone** (`adsb_distance_warning`), the corresponding **OSD element is displayed**.
- If the aircraft enters the **alert zone** (`adsb_distance_alert`), the **OSD element starts blinking**, indicating a higher-priority alert.
This mode therefore provides a simple proximity-based warning determined purely by real-time distance.
---
### ADS-B Warning and Alert Messages (CPA Mode ON)
When **osd_adsb_calculation_use_cpa = ON**, the system evaluates aircraft using the **Closest Point of Approach (CPA)** and predicted trajectories, not only the current distance.
1. **Aircraft already inside the alert zone**
If one or more aircraft are currently inside the **alert zone** (`adsb_distance_alert`), the **closest aircraft** to the UAV is selected and the **OSD element blinks**.
2. **Aircraft in the warning zone, none predicted to enter the alert zone**
If aircraft are present in the **warning zone** (`adsb_distance_warning`), but none of them are predicted to enter the **alert zone** (their CPA distance is greater than `adsb_distance_alert`), the **closest aircraft to the UAV** is selected and the **OSD element remains steady** (no blinking).
3. **Aircraft in the warning zone, one predicted to enter the alert zone**
If at least one aircraft in the **warning zone** is predicted to enter the **alert zone**, that aircraft is selected and the **OSD element blinks**.
4. **Aircraft in the warning zone, multiple predicted to enter the alert zone**
If multiple aircraft are predicted to enter the **alert zone**, the system selects the aircraft that will **reach the alert zone first**, and the **OSD element blinks**.
![ADSB CPA_ON](assets/images/adsb-CPA-on.png)
+161
View File
@@ -0,0 +1,161 @@
# MSP Extensions
INAV includes a number of extensions to the MultiWii Serial Protocol (MSP). This document describes
those extensions in order that 3rd party tools may identify INAV firmware and react appropriately.
Issue the MSP_API_VERSION command to find out if the firmware supports them.
## Mode Ranges
### MSP\_MODE\_RANGES
The MSP\_MODE\_RANGES returns the current auxiliary mode settings from the flight controller. It should be invoked
before any modification is made to the configuration.
The message returns a group of 4 unsigned bytes for each 'slot' available in the flight controller. The number of
slots should be calculated from the size of the returned message.
| Command | Msg Id | Direction | Notes |
|---------|--------|-----------|-------|
| MSP\_MODE\_RANGES | 34 | to FC | Following this command, the FC returns a block of 4 bytes for each auxiliary mode 'slot'|
Unassigned slots have rangeStartStep == rangeEndStep. Each element contains the following fields.
| Data | Type | Notes |
|------|------|-------|
| permanentId | uint8 | See [Modes in the wiki](https://github.com/iNavFlight/inav/wiki/Modes) for a definition of the permanent ids |
| auxChannelIndex | uint8 | The Aux switch number (indexed from 0) |
| rangeStartStep | uint8 | The start value for this element in 'blocks' of 25 where 0 == 900 and 48 == 2100 |
| rangeEndStep | uint8 | The end value for this element in 'blocks' of 25 where 0 == 900 and 48 == 2100 |
Thus, for a INAV firmware with 40 slots 160 bytes would be returned in response to MSP\_MODE\_RANGES,
### MSP\_SET\_MODE\_RANGE
The MSP\_SET\_MODE\_RANGE is used to inform the flight controller of
auxiliary mode settings. The client *must* return all auxiliary
elements, including those that have been disabled or are undefined, by
sending this message for all auxiliary slots.
| Command | Msg Id | Direction |
|---------|--------|-----------|
| MSP\_SET\_MODE\_RANGE | 35 | to FC |
| Data | Type | Notes |
|------|------|-------|
| sequence id | uint8 | A monotonically increasing ID, from 0 to the number of slots -1 |
| permanentId | uint8 | See [Modes in the wiki](https://github.com/iNavFlight/inav/wiki/Modes) for a definition of the permanent ids |
| auxChannelIndex | uint8 | The Aux channel number (indexed from 0) |
| rangeStartStep | uint8 | The start value for this element in 'blocks' of 25 where 0 == 900 and 48 == 2100 |
| rangeEndStep | uint8 | The end value for this element in 'blocks' of 25 where 0 == 900 and 48 == 2100 |
### Implementation Notes
* The client should make no assumptions about the number of slots available. Rather, the number should be computed
from the size of the MSP\_MODE\_RANGES message divided by the size of the returned data element (4 bytes);
* The client should ensure that all changed items are returned to the flight controller, including those where a
switch or range has been disabled;
* A 'null' return, with all values other than the sequence id set to 0, must be made for all unused slots, up to
the maximum number of slots calculated from the initial message.
## Adjustment Ranges
### MSP\_ADJUSTMENT\_RANGES
The MSP\_ADJUSTMENT\_RANGES returns the current adjustment range settings from
the flight controller. It should be invoked before any modification is
made to the configuration.
The message returns a group of 6 unsigned bytes for each 'slot'
available in the flight controller. The number of slots should be
calculated from the size of the returned message.
| Command | Msg Id | Direction | Notes |
|---------|--------|-----------|-------|
| MSP\_ADJUSTMENT\_RANGES | 52 | to FC | Following this command, the FC returns a block of 6 bytes for each adjustment range 'slot'|
Unassigned slots have rangeStartStep == rangeEndStep. Each element contains the following fields.
| Data | Type | Notes |
|------|------|-------|
| adjustmentStateIndex | uint8 | See below |
| auxChannelIndex | uint8 | The Aux channel number (indexed from 0) used to activate the adjustment |
| rangeStartStep | uint8 | The start value for this element in 'blocks' of 25 where 0 == 900 and 48 == 2100 |
| rangeEndStep | uint8 | The end value for this element in 'blocks' of 25 where 0 == 900 and 48 == 2100 |
| adjustmentFunction | uint8 | See below |
| auxSwitchChannelIndex | uint8 | The Aux channel number used to perform the function (indexed from 0) |
Thus, for a INAV firmware with 12 slots 72 bytes would be returned in response to MSP\_ADJUSTMENT\_RANGES,
### MSP\_SET\_ADJUSTMENT\_RANGE
The MSP\_SET\_ADJUSTMENT\_RANGE is used to inform the flight controller of
adjustment range settings. The client *must* return all adjustment range
elements, including those that have been disabled or are undefined, by
sending this message for all adjustment range slots.
| Command | Msg Id | Direction |
|---------|--------|-----------|
| MSP\_SET\_ADJUSTMENT\_RANGE | 53 | to FC |
| Data | Type | Notes |
|------|------|-------|
| sequence id | uint8 | A monotonically increasing ID, from 0 to the number of slots -1 |
| adjustmentStateIndex | uint8 | See below |
| auxChannelIndex | uint8 | The Aux channel number (indexed from 0) |
| rangeStartStep | uint8 | The start value for this element in 'blocks' of 25 where 0 == 900 and 48 == 2100 |
| rangeEndStep | uint8 | The end value for this element in 'blocks' of 25 where 0 == 900 and 48 == 2100 |
| adjustmentFunction | uint8 | See below |
| auxSwitchChannelIndex | uint8 | The Aux channel number used to perform the function (indexed from 0) |
### MSP\_SET\_1WIRE
The MSP\_SET\_1WIRE is used to enable serial1wire passthrough
note: it would be ideal to disable this when armed
| Command | Msg Id | Direction |
|---------|--------|-----------|
| MSP\_SET\_1WIRE | 243 | to FC |
| Data | Type | Notes |
|------|------|-------|
| esc id | uint8 | A monotonically increasing ID, from 0 to the number of escs -1 |
#### AdjustmentIndex
The FC maintains internal state for each adjustmentStateIndex, currently 4 simultaneous adjustment states are maintained. Multiple adjustment ranges
can be configured to use the same state but care should be taken not to send multiple adjustment ranges that when active would confict.
e.g. Configuring two identical adjustment ranges using the same slot would conflict, but configuring two adjustment ranges that used
only one half of the possible channel range each but used the same adjustmentStateIndex would not conflict.
The FC does NOT check for conflicts.
#### AdjustmentFunction
There are many adjustments that can be made, the numbers of them and their use is found in the documentation of the cli `adjrange` command in the 'Inflight Adjustents' section.
### Implementation Notes
* The client should make no assumptions about the number of slots available. Rather, the number should be computed
from the size of the MSP\_ADJUSTMENT\_RANGES message divided by the size of the returned data element (6 bytes);
* The client should ensure that all changed items are returned to the flight controller, including those where a
switch or range has been disabled;
* A 'null' return, with all values except for the sequence id set to 0, must be made for all unused slots,
up to the maximum number of slots calculated from the initial message.
## Deprecated MSP
The following MSP commands are replaced by the MSP\_MODE\_RANGES and
MSP\_SET\_MODE\_RANGE extensions, and are not recognised by
INAV.
* MSP\_BOX
* MSP\_SET\_BOX
See also
--------
[The wiki](https://github.com/iNavFlight/inav/wiki/Modes) describes the user visible implementation for the INAV
modes extension.
+59
View File
@@ -0,0 +1,59 @@
# Airplane Autotune instructions
Airplane PIFF autotune is inspired by ArduPilot Plane firmware.
Getting a good set of roll/pitch/yaw PIFF parameters for your aircraft is essential for stable flight. To help with this it is highly recommended that you use the AUTOTUNE system described below.
## What AUTOTUNE does
The AUTOTUNE mode is a flight mode that acts on top of normal ANGLE/HORIZON/ACRO mode and uses changes in flight attitude input by the pilot to learn the tuning values for roll, pitch and yaw tuning.
In general pilot needs to activate AUTOTUNE mode while in the air and then fly the plane for a few minutes. While flying the pilot needs to input as many sharp attitude changes as possible so that the autotune code can learn how the aircraft responds and figure out PIFF gains.
## Before flying with AUTOTUNE
Before taking off you need to set up a few parameters for your airplane:
parameter | explanation
--------- | -----------
roll_rate | Maximum roll rate limit for your ariplane. Must not exceed physical limit of your plane
pitch_rate | Maximum pitch rate limit for your ariplane. Must not exceed physical limit of your plane
yaw_rate | Maximum yaw rate limit for your ariplane. Must not exceed physical limit of your plane
fw_p_level | Self-leveling strength. Bigger value means sharper response
fw_i_level | Self-leveling filtering. Usual value for airplanes is 1-5 Hz
max_angle_inclination_rll | Maximum roll angle in [0.1 deg] units
max_angle_inclination_pit | Maximum pitch angle in [0.1 deg] units
tpa_breakpoint | Cruise throttle (expected throttle that you would be flying most of the time)
tpa_rate | Amount of TPS curve to apply (usually should be in range 50-80 for most airplanes)
For most hobby-sized airplanes roll/pitch rate limits should be in range 70-120 deg/s (7-12 for `roll_rate` and `pitch_rate` values). Small and agile flying wings can reach 180-200 deg/s.
Other things to check:
* It's highly recommended that you fly in MANUAL and trim your servo midpoints for stable flight
* Make sure you have center of gravity according to manual to your aircraft
* Check that your failsafe activates correctly (test on the ground with propeller off for safety)
## Flying in AUTOTUNE
Once you are all setup you can take off normally and switch to AUTOTUNE mode once you have gained altitude.
When you engage AUTOTUNE mode a few things will happen:
* The autotune system will immediately setup some default values for your roll, pitch and yaw P and I gains
* The autotune system will monitor requested roll and pitch rates (as determined by your transmitter stick movements). When the demanded roll or pitch rate exceeds certain threshold the autotune system will use the response of the aircraft to learn roll or pitch tuning values
* Every 5 seconds the autotune system will store the snapshot of parameters you have. When you switch out of AUTOTUNE mode the last remembered parameters are restored
* You may find the plane is quite sluggish when you first enter AUTOTUNE. You will find that as the tune progresses this will get better. Make sure your flight area has plenty of room for slow large-radius turns.
* Don't land in AUTOTUNE mode - during landing airplane doesn't reach it full performance which may be read by autotune system as insufficient gains.
The key to a successful autotune is to input rapid movements with the transmitter sticks. You should only do one of either roll or pitch at a time, and you should move the stick rapidly to the maximum deflection.
## Don't stop too early
The more you fly the better it will get. Let autotune analyze how your airplane behaves and figure decent tune for you. Once you feel that airplane is flying good in AUTOTUNE - keep flying well past that point to finalize the tune.
## Completing the tune
Once you have tuned reasonable PIFF parameters with AUTOTUNE you should complete the tune by switching out of AUTOTUNE to ANGLE or MANUAL and landing the airplane.
Note that AUTOTUNE mode doesn't automatically save parameters to EEPROM. You need to disarm and issue a [stick command](Controls.md) to save configuration parameters.
+107
View File
@@ -0,0 +1,107 @@
# Backup and Restore
INAV Configurator can automatically back up your configuration before flashing firmware and offer to restore it afterwards. When upgrading across major versions (e.g. 7.x → 8.x → 9.x), settings are automatically migrated to the new firmware format.
For manual CLI-based backup and restore, see the [CLI documentation](Cli.md#backup-via-cli).
## Automatic Backup & Restore During Firmware Flash
### What happens automatically
1. **Before flashing** (with or without Full Chip Erase enabled): Your current CLI configuration (`diff all`) is automatically captured and saved to the backup directory.
2. **After flashing**: Depending on the situation, the Configurator offers to restore your settings if Full Chip Erase was enabled:
| Scenario | Behavior |
|----------|----------|
| **Patch update** (e.g. 8.0.0 → 8.0.1) | Auto-restore offered immediately |
| **Minor update** (e.g. 8.0.0 → 8.1.0) | Auto-restore offered immediately |
| **Major upgrade** (e.g. 7.x → 8.x) with migration profile available | Migration preview shown — confirm to restore with converted settings |
| **Major upgrade** without migration profile | Warning shown — restore still possible but some settings may fail |
| **Major downgrade** (e.g. 9.x → 7.x) | Auto-restore blocked — manual restore only (settings may be incompatible) |
| **Local firmware file** (loaded from disk) | No auto-restore offered — backup is still saved |
| **Flash without Full Chip Erase** | Backup taken, no restore offered |
### Migration Preview
When updating across major versions (e.g. 7.x → 9.x), the Configurator shows a **migration preview overlay** before restoring. This lists:
- **Removed settings** — settings that no longer exist in the new firmware (will be skipped)
- **Renamed settings** — settings whose name changed (automatically converted)
- **Renamed commands** — CLI commands that were renamed (automatically converted)
- **Value replacements** — setting values that changed meaning (automatically converted)
- **Setting remappings** — numeric IDs that were renumbered (automatically converted)
- **Warnings** — settings whose semantics changed and require manual review
You can review all changes before confirming or cancelling the restore.
Multi-step migrations are handled automatically. For example, a 7.x → 9.x upgrade applies migration profiles in sequence (7→8, then 8→9).
## Manual Backup & Restore
The Firmware Flasher tab provides three buttons:
- **Backup Config** — saves your current CLI configuration to a file (opens save dialog)
- **Restore Config** — loads a backup file and restores it to your flight controller
- If the backup is from a different major version, the migration preview is shown first
- If no migration profile exists for the version gap, a warning is shown but you can still proceed
- **Open Backups Folder** — opens the backup directory in your file manager
For CLI-based backup and restore procedures, see [Backup via CLI](Cli.md#backup-via-cli) and [Restore via CLI](Cli.md#restore-via-cli).
## Backup File Location
Backups are stored in your OS-specific application data directory:
| OS | Path |
|----|------|
| **Windows** | `%APPDATA%/inav-configurator/backups/` |
| **macOS** | `~/Library/Application Support/inav-configurator/backups/` |
| **Linux** | `~/.config/inav-configurator/backups/` |
Use the **Open Backups Folder** button in the Firmware Flasher tab to open this directory.
## Backup File Naming
| Type | Format |
|------|--------|
| Auto-backups | `UPDATE_inav_backup_{version}_{board}_{YYYY-MM-DD_HHMMSS}.txt` |
| Manual backups | `inav_backup_{version}_{board}_{YYYY-MM-DD_HHMMSS}.txt` |
Auto-backups are pruned automatically — only the 10 most recent are kept. Files you rename are never pruned.
## Backup File Format
Backup files are plain-text CLI dumps with a metadata header:
```
# INAV Backup
# Version: 8.0.0
# Board: SPEEDYBEEF405V4
# Date: 2026-04-11T10:30:00.000Z
# Craft: MyQuad
#
# INAV/SPEEDYBEEF405V4 8.0.0 Apr 1 2026 / 12:00:00 (abc1234)
# GCC-13.2.1
# ...
set gyro_main_lpf_hz = 110
set acc_hardware = AUTO
...
```
You can open and edit these files with any text editor.
## Restore Error Handling
If errors occur during restore (e.g. unknown settings, invalid values):
- An error dialog shows the affected lines
- You can choose:
- **Save anyway** — saves the successfully applied settings and reboots
- **Abort** — discards all changes and exits CLI mode
## Tips
- **Always flash with Full Chip Erase** when upgrading to a new version. This ensures clean defaults and triggers automatic backup and restore.
- **Review migration previews carefully** — especially the warnings section, which highlights settings whose meaning may have changed.
- **Keep manual backups** before major upgrades. While auto-backup handles this, having an extra copy in a known location gives peace of mind.
- **Use `diff` over `dump`** for backups. The `diff` format only stores settings that differ from defaults, which makes restoring safer across versions. The auto-backup feature already uses `diff all`.
+509
View File
@@ -0,0 +1,509 @@
# Battery Monitoring
INAV has a battery monitoring feature. The voltage of the main battery can be measured by the system and used to trigger a low-battery warning [buzzer](Buzzer.md), on-board status LED flashing and LED strip patterns.
Low battery warnings can:
* Help ensure you have time to safely land the aircraft
* Help maintain the life and safety of your LiPo/LiFe batteries, which should not be discharged below manufacturer recommendations
Minimum and maximum cell voltages can be set, and these voltages are used to auto-detect the number of cells in the battery when it is first connected.
Per-cell monitoring is not supported, as we only use one ADC to read the battery voltage.
## Supported targets
All targets support battery voltage monitoring unless stated.
## Connections
When dealing with batteries **ALWAYS CHECK POLARITY!**
Measure expected voltages **first** and then connect to the flight controller. Powering the flight controller with
incorrect voltage or reversed polarity will likely fry your flight controller. Ensure your flight controller
has a voltage divider capable of measuring your particular battery voltage.
On the first battery connection is always advisable to use a current limiter device to limit damages if something is wrong in the setup.
### Sparky
See the [Sparky board chapter](Board%20-%20Sparky.md).
## Voltage measurement
Enable the `VBAT` feature to enable the measurement of the battery voltage and the use of the voltage based OSD battery gauge, voltage based and energy based battery alarms.
### Calibration
`vbat_scale` - Adjust this setting to match actual measured battery voltage to reported value. Increasing this value increases the measured voltage.
### Voltage measurement source
Two voltage sources are available: raw voltage and sag compensated voltage. The raw voltage is the voltage directly measured at the battery while the sag compensated voltage is calculated by an algorithm aiming to provide a stable voltage source for gauges, telemetry and alarms. When the current drawn from a battery varies the provided voltage also varies due to the internal resistance of the battery, it is called sag. The sag can often trigger the battery alarms before the battery is empty and if you are relying on the battery voltage to know the charge state of your battery you have to land or cut the throttle to know the real, without load, battery voltage. The sag compensation algorithm simulates a battery with zero internal resistance and provides a stable reading independent from the drawn current.
You can select the voltage source used for battery alarms and telemetry with the `bat_voltage_source` setting. It can be set to either `RAW` for using raw battery voltage or `SAG_COMP` for using the calculated sag compensated voltage.
You can see an illustration of the sag compensation algorithm in action in the following graph:
![Voltage graph](assets/images/sag_compensated_battery_voltage_plot.png)
### Voltage based OSD gauge and alarms
Up to 3 battery profiles are supported. You can select the battery profile from the GUI, OSD menu, [stick commands](Controls.md) and CLI command `battery_profile n`. Each profile stores the following voltage settings:
`bat_cells` - Specify the number of cells of your battery. Allows the automatic selection of the battery profile when set to a value greater than 0. Set to 0 (default) for auto-detecting the number of cells (see next setting)
`vbat_cell_detect_voltage` - Maximum voltage per cell, used for auto-detecting the number of cells of the battery. Should be higher than maximum cell voltage to take into account possible drift in measured voltage and keep cell count detection accurate (0.01V unit, i.e. 430 = 4.30V)
`vbat_max_cell_voltage` - Maximum voltage per cell when the battery is fully charged. Used for the OSD voltage based battery gauge (0.01V unit, i.e. 420 = 4.20V)
`vbat_warning_cell_voltage` - Cell warning voltage. A cell voltage bellow this value triggers the first (short beeps) voltage based battery alarm if used and also the blinking of the OSD voltage indicator if the battery capacity is not used instead (see bellow) (0.01V unit, i.e. 370 = 3.70V)
`vbat_min_cell_voltage` - Cell minimum voltage. A cell voltage bellow this value triggers the second (long beeps) voltage based battery alarm if used and the OSD gauge will display 0% if the battery capacity is not used instead (see bellow) (0.01V unit, i.e. 350 = 3.50V)
e.g.
```
battery_profile 1
set vbat_scale = 1100
set vbat_max_cell_voltage = 430
set vbat_warning_cell_voltage = 340
set vbat_min_cell_voltage = 330
```
# Current Monitoring
Current monitoring (amperage) is supported by connecting a current meter to the appropriate current meter ADC input (see the documentation for your particular board).
When enabled, the following values calculated and used by the telemetry and OLED display subsystems:
* Amps
* mAh used
* Capacity remaining
## Configuration
Enable current monitoring using the CLI command:
```
feature CURRENT_METER
```
Configure the current meter type using the `current_meter_type` settings here:
| Value | Sensor Type |
| ----- | ---------------------- |
| 0 | None |
| 1 | ADC/hardware sensor |
| 2 | Virtual sensor |
Configure capacity using the `battery_capacity` setting, in mAh units.
If you're using an OSD that expects the multiwii current meter output value, then set `multiwii_current_meter_output` to `1` (this multiplies amperage sent to MSP by 10).
### ADC Sensor
The current meter may need to be configured so the value read at the ADC input matches actual current draw. Just like you need a voltmeter to correctly calibrate your voltage reading you also need an ammeter to calibrate the current sensor.
Use the following settings to adjust calibration:
`current_meter_scale`
`current_meter_offset`
### Virtual Sensor
The virtual sensor uses the throttle position to calculate an estimated current value. This is useful when a real sensor is not available. The following settings adjust the virtual sensor calibration:
| Setting | Description |
| ----------------------------- | -------------------------------------------------------- |
| `current_meter_scale` | The throttle scaling factor [centiamps, i.e. 1/100th A] |
| `current_meter_offset` | The current at zero throttle (while disarmed) [centiamps, i.e. 1/100th A] |
There are two simple methods to tune these parameters: one uses a battery charger and another depends on actual current measurements.
#### Tuning Using Actual Current Measurements
If you know your craft's current draw while disarmed (Imin) and at maximum throttle while armed (Imax), calculate the scaling factors as follows:
```
current_meter_scale = (Imax - Imin) * 100000 / (Tmax + (Tmax * Tmax / 50))
current_meter_offset = Imin * 100
```
Note: Tmax is maximum throttle offset (i.e. for `max_throttle` = 1850, Tmax = 1850 - 1000 = 850)
For example, assuming a maximum current of 34.2A, a minimum current of 2.8A, and a Tmax `max_throttle` = 1850:
```
current_meter_scale = (Imax - Imin) * 100000 / (Tmax + (Tmax * Tmax / 50))
= (34.2 - 2.8) * 100000 / (850 + (850 * 850 / 50))
= 205
current_meter_offset = Imin * 100 = 280
```
#### Tuning Using Battery Charger Measurement
If you cannot measure current draw directly, you can approximate it indirectly using your battery charger.
However, note it may be difficult to adjust `current_meter_offset` using this method unless you can
measure the actual current draw with the craft disarmed.
Note:
+ This method depends on the accuracy of your battery charger; results may vary.
+ If you add or replace equipment that changes the in-flight current draw (e.g. video transmitter,
camera, gimbal, motors, prop pitch/sizes, ESCs, etc.), you should recalibrate.
The general method is:
1. Fully charge your flight battery
2. Fly your craft, using >50% of your battery pack capacity (estimated)
3. Note INAV's reported mAh draw
4. Re-charge your flight battery, noting the mAh charging data needed to restore the pack to fully charged
5. Adjust `current_meter_scale` to according to the formula given below
6. Repeat and test
Given (a) the reported mAh draw and the (b) mAh charging data, calculate a new `current_meter_scale` value as follows:
```
current_meter_scale = (reported_draw_mAh / charging_data_mAh) * old_current_meter_scale
```
For example, assuming:
+ A INAV reported current draw of 1260 mAh
+ Charging data to restore full charge of 1158 mAh
+ A existing `current_meter_scale` value of 400 (the default)
Then the updated `current_meter_scale` is:
```
current_meter_scale = (reported_draw_mAh / charging_data_mAh) * old_current_meter_scale
= (1260 / 1158) * 400
= 435
```
## Power and Current Limiting
INAV includes an advanced power and current limiting system to protect your battery and ESCs from excessive discharge rates. This feature automatically reduces throttle output when current or power draw exceeds configured limits.
### Why Use Power Limiting?
Power and current limiting helps:
- **Protect batteries** from exceeding their C-rating and getting damaged
- **Prevent voltage sag** and brown-outs during high-throttle maneuvers
- **Extend battery lifespan** by avoiding excessive discharge rates
- **Improve safety** by preventing ESC or battery overheating
- **Comply with regulations** that may limit power output
### How It Works
The power limiter uses a PI (Proportional-Integral) controller to smoothly reduce throttle when current or power exceeds limits. It supports two operating modes:
1. **Continuous Limit**: The sustained current/power that can be drawn indefinitely
2. **Burst Limit**: A higher current/power allowed for a short duration before falling back to the continuous limit
This burst mode allows brief high-power maneuvers (like punch-outs or quick climbs) while protecting the battery during sustained high-throttle flight.
### Configuration
Power limiting requires a current sensor (`CURRENT_METER` feature). Power-based limiting additionally requires voltage measurement (`VBAT` feature).
#### Basic Settings (per battery profile)
| Setting | Description | Unit | Range |
|---------|-------------|------|-------|
| `limit_cont_current` | Continuous current limit | dA (deci-amps) | 0-2000 (0-200A) |
| `limit_burst_current` | Burst current limit | dA | 0-2000 (0-200A) |
| `limit_burst_current_time` | Duration burst is allowed | ds (deci-seconds) | 0-600 (0-60s) |
| `limit_burst_current_falldown_time` | Ramp-down duration from burst to continuous | ds | 0-600 (0-60s) |
| `limit_cont_power` | Continuous power limit | dW (deci-watts) | 0-20000 (0-2000W) |
| `limit_burst_power` | Burst power limit | dW | 0-20000 (0-2000W) |
| `limit_burst_power_time` | Duration burst power is allowed | ds | 0-600 (0-60s) |
| `limit_burst_power_falldown_time` | Ramp-down duration for power | ds | 0-600 (0-60s) |
**Note**: Set any limit to `0` to disable that specific limiter.
#### Advanced Tuning Settings
| Setting | Description | Default | Range |
|---------|-------------|---------|-------|
| `limit_pi_p` | Proportional gain for PI controller | 100 | 10-500 |
| `limit_pi_i` | Integral gain for PI controller | 15 | 10-200 |
| `limit_attn_filter_cutoff` | Low-pass filter cutoff frequency | 50 Hz | 10-200 |
### Example Configurations
#### Example 1: Simple Current Limiting (50A continuous)
Protect a 1500mAh 4S 50C battery (75A max burst, 50A continuous safe):
```
battery_profile 1
set limit_cont_current = 500 # 50A continuous
set limit_burst_current = 750 # 75A burst
set limit_burst_current_time = 100 # 10 seconds
set limit_burst_current_falldown_time = 20 # 2 second ramp-down
```
#### Example 2: Power Limiting for Racing (500W limit)
Limit total system power for racing class restrictions:
```
battery_profile 1
set limit_cont_power = 4500 # 450W continuous
set limit_burst_power = 5000 # 500W burst
set limit_burst_power_time = 50 # 5 seconds
set limit_burst_power_falldown_time = 10 # 1 second ramp-down
```
#### Example 3: Combined Current and Power Limiting
Protect both battery (current) and ESCs (power):
```
battery_profile 1
# Current limits (battery protection)
set limit_cont_current = 600 # 60A continuous
set limit_burst_current = 800 # 80A burst
set limit_burst_current_time = 100 # 10 seconds
# Power limits (ESC protection)
set limit_cont_power = 8000 # 800W continuous
set limit_burst_power = 10000 # 1000W burst
set limit_burst_power_time = 100 # 10 seconds
```
### Understanding Burst Mode
When you exceed the continuous limit, the system uses "burst reserve" (like a capacitor):
- **Burst reserve** starts full and depletes when current/power exceeds the continuous limit
- When reserve is empty, the limit drops to the continuous value
- The `falldown_time` setting creates a smooth ramp-down instead of an abrupt drop
- Reserve recharges when current/power drops below the continuous limit
**Example timeline** (60A continuous, 80A burst, 10s burst time, 2s falldown):
```
Time Limit Reason
---- ----- ------
0s 80A Full burst reserve
5s 80A Still have reserve (using 5s of 10s)
10s 80A Reserve depleted
10-12s 80→60A Ramping down over 2 seconds
12s+ 60A Continuous limit active
```
### OSD Elements
Three OSD elements display power limiting status:
- **`OSD_PLIMIT_REMAINING_BURST_TIME`**: Shows remaining burst time in seconds
- **`OSD_PLIMIT_ACTIVE_CURRENT_LIMIT`**: Shows current limit being enforced (blinks when limiting)
- **`OSD_PLIMIT_ACTIVE_POWER_LIMIT`**: Shows power limit being enforced (blinks when limiting)
Enable these in the OSD tab to monitor limiting during flight.
### Calibration Tips
1. **Find your battery's limits**: Check manufacturer specifications for continuous and burst C-ratings
- Continuous limit = `battery_capacity_mAh × continuous_C_rating / 100` (in dA)
- Burst limit = `battery_capacity_mAh × burst_C_rating / 100` (in dA)
2. **Test incrementally**: Start with conservative limits and increase gradually
3. **Monitor in flight**: Use OSD elements to see when limiting activates
4. **Calibrate current sensor**: Accurate current readings are critical - see "Current Monitoring" section above
5. **Tune PI controller**: If limiting feels abrupt or causes oscillation, adjust `limit_pi_p` and `limit_pi_i`:
- Increase P for faster response (may cause oscillation)
- Increase I for better steady-state accuracy
- Decrease if throttle oscillates during limiting
### Notes
- Power limiting is part of the battery profile system - each profile can have different limits
- Both current and power limiting can be active simultaneously - the most restrictive applies
- Limiting is applied smoothly via PI controller to avoid abrupt throttle cuts
- The system uses instantaneous current/power readings for responsive limiting
- Set limits to `0` to disable a specific limiter while keeping others active
## Battery capacity monitoring
For the capacity monitoring to work you need a current sensor (`CURRENT_METER` feature). For monitoring energy in milliWatt hour you also need voltage measurement (`VBAT` feature). For best results the current and voltage readings have to be calibrated.
It is possible to display the remaining battery capacity in the OSD and also use the battery capacity thresholds (`battery_capacity_warning` and `battery_capacity_critical`) for battery alarms.
For the remaining battery capacity to be displayed users need to set the `battery_capacity` setting (>0) and the battery to be full when plugged in. If the `battery_capacity` setting is set to 0 the remaining battery capacity item in the OSD will display `NA` and the battery gauge will use an estimation based on the battery voltage otherwise it will display the remaining battery capacity down to the `battery_capacity_critical` setting (battery considered empty) and the battery gauge will be based on the remaining capacity. For the capacity thresholds to be used for alarms the `battery_capacity_warning` and `battery_capacity_critical` settings also needs to be set (>0) and the plugged in battery to be full when plugged in. The battery capacity settings unit can be set using the `battery_capacity_unit`. MilliAmpere hour and milliWatt hour units are supported. The value are absolute meaning that `battery_capacity_warning` is the battery capacity left when the battery is entering the `warning` state and `battery_capacity_critical` is the battery capacity left when the battery is considered empty and entering the `critical` state.
For the battery to be considered full the mean cell voltage of the battery needs to be above `vbat_max_cell_voltage - 140mV` (by default 4.1V). So a 3S battery will be considered full above 12.3V and a 4S battery above 16.24V. If the battery plugged in is not considered full the remaining battery capacity OSD item will show `NF` (Not Full).
For the remaining battery capacity and battery gauge to be the most precise (linear relative to throttle from full to empty) when using battery capacity monitoring users should use the milliWatt hour unit for the battery capacity settings.
### Example configuration
```
set battery_capacity_unit = MAH // battery capacity values are specified in milliAmpere hour
set battery_capacity = 2200 // battery capacity is 2200mAh
set battery_capacity_warning = 660 // the battery warning alarm will sound and the capacity related OSD items will blink when left capacity is less than 660 mAh (30% of battery capacity)
set battery_capacity_critical = 440 // the battery critical alarm will sound and the OSD battery gauge and remaining capacity item will be empty when left capacity is less than 440 mAh (20% of battery capacity)
```
Note that in this example even though your warning capacity (`battery_capacity_warning`) is set to 30% (660mAh), since 440mAh (`battery_capacity_critical`) is considered empty (0% left), the OSD capacity related items will only start to blink when the remaining battery percentage shown on the OSD is below 12%: (`battery_capacity_warning`-`battery_capacity_critical`)*100/(`battery_capacity`-`battery_capacity_critical`)=(660-440)*100/(2200-440)=12.5
## Battery profiles
Up to 3 battery profiles are supported. You can select the battery profile from the GUI, OSD menu, [stick commands](Controls.md) and CLI command `battery_profile n`. Battery profiles store the following settings (see above for an explanation of each setting):
- `bat_cells`
- `vbat_cell_detect_voltage`
- `vbat_max_cell_voltage`
- `vbat_warning_cell_voltage`
- `vbat_min_cell_voltage`
- `battery_capacity`
- `battery_capacity_warning`
- `battery_capacity_critical`
- `throttle_idle`
- `throttle_scale`
- `turtle_mode_power_factor`
- `nav_fw_cruise_thr`
- `nav_fw_min_thr`
- `nav_fw_max_thr`
- `nav_fw_pitch2thr`
- `nav_fw_launch_thr`
- `nav_fw_launch_idle_thr`
- `failsafe_throttle`
- `nav_mc_hover_thr`
To enable the automatic battery profile switching based on battery voltage enable the `BAT_PROF_AUTOSWITCH` feature. For a profile to be automatically selected the number of cells of the battery needs to be specified (>0).
### Battery profiles configuration examples
#### Simple example
In this example we want to use two different type of batteries for the same aircraft and switch manually between them. The first battery is a Li-Po (4.20V/cell) and the second battery is a Li-Ion (4.10V/cell).
```
battery_profile 1
set bat_cells = 0
set vbat_max_cell_voltage = 420
set vbat_warning_cell_voltage = 370
set vbat_min_cell_voltage = 340
battery_profile 2
set bat_cells = 0
set vbat_max_cell_voltage = 410
set vbat_warning_cell_voltage = 280
set vbat_min_cell_voltage = 250
```
#### Simple example with automatic profile switching
In this example we want to use two different batteries for the same aircraft and automatically switch between them when the battery is plugged in. The first battery is a Li-Po 2200mAh 3S and the second battery is a LiPo 1500mAh 4S. Since the INAV defaults for the cell detection voltage and max voltage are adequate for standard LiPo batteries they will not be modified. The warning and minimum voltage are not modified either in this example but you can set them to the value you like. Since we are using battery capacities only the warning voltage (kept at default in this example) will be used and only for triggering the battery voltage indicator blinking in the OSD.
```
feature BAT_PROF_AUTOSWITCH
battery_profile 1
set bat_cells = 3
set battery_capacity = 2200
set battery_capacity_warning = 440
set battery_capacity_critical = 220
battery_profile 2
set bat_cells = 4
set battery_capacity = 1500
set battery_capacity_warning = 300
set battery_capacity_critical = 150
```
#### Advanced automatic switching example
Profile 1 is for a 3S 2200mAh Li-Po pack (max 4.20V/cell), profile 2 for a 3S 4000mAh Li-Ion pack (max 4.10V/cell) and profile 3 for a 4S 1500mAh Li-Po pack (max 4.20V/cell).
With this configuration if the battery plugged in is less than 12.36V (3 x 4.12) the profile 2 will be automatically selected else if the battery voltage is less than 12.66V (3 x 4.22) the profile 1 will be automatically selected else if the battery voltage is less 17.20V (4 x 4.3) the profile 3 will be automatically selected. If a matching profile can't be found the last selected profile is used.
```
feature BAT_PROF_AUTOSWITCH
battery_profile 1
set bat_cells = 3
set vbat_cell_detect_voltage = 422
set vbat_max_cell_voltage = 420
set vbat_warning_cell_voltage = 350
set vbat_min_cell_voltage = 330
set battery_capacity = 2200
set battery_capacity_warning = 440
set battery_capacity_critical = 220
battery_profile 2
set bat_cells = 3
set vbat_cell_detect_voltage = 412
set vbat_max_cell_voltage = 410
set vbat_warning_cell_voltage = 300
set vbat_min_cell_voltage = 280
set battery_capacity = 4000
set battery_capacity_warning = 800
set battery_capacity_critical = 400
battery_profile 3
set bat_cells = 4
set vbat_cell_detect_voltage = 430
set vbat_max_cell_voltage = 420
set vbat_warning_cell_voltage = 350
set vbat_min_cell_voltage = 330
set battery_capacity = 1500
set battery_capacity_warning = 300
set battery_capacity_critical = 150
```
#### Change control profile based on battery profile
You can change the control profile, automatically, based on the battery profile. This allows for fine tuning of each power choice.
```
feature BAT_PROF_AUTOSWITCH
battery_profile 1
set bat_cells = 3
set controlrate_profile = 1
battery_profile 2
set bat_cells = 4
set controlrate_profile = 2
```
## Remaining flight time and flight distance estimation
The estimated remaining flight time and flight distance estimations can be displayed on the OSD (for fixed wing only for the moment). They are calculated from the GPS distance from home, remaining battery capacity and average power draw. They are taking into account the requested altitude change and heading to home change after altitude change following the switch to RTH. They are also taking into account the estimated wind if `osd_estimations_wind_compensation` is set to `ON`. When the timer and distance indicator reach 0 they will blink and you need to go home in a straight line manually or by engaging RTH. You should be left with at least `rth_energy_margin`% of battery left when arriving home if the cruise speed and power are set correctly (see bellow).
To use this feature the following conditions need to be met:
- The `VBAT`, `CURRENT_METER` and `GPS` features need to be enabled
- The battery capacity needs to be specified in mWh (`battery_capacity` setting > 0 and `battery_capacity_unit` set to `MWH`)
- The average ground speed of the aircraft without wind at cruise throttle needs to be set (`nav_fw_cruise_speed` setting in cm/s)
- The average power draw at zero throttle needs to be specified (`idle_power` setting in 0.01W unit)
- The average power draw at cruise throttle needs to be specified (`cruise_power` setting in 0.01W unit)
- The battery needs to be full when plugged in (voltage >= (`vbat_max_cell_voltage` - 100mV) * cells)
It is advised to set `nav_fw_cruise_speed` a bit lower than the real speed and `cruise_power` 10% higher than the power at cruise throttle to ensure variations in throttle during cruise won't cause the aircraft to draw more energy than estimated.
If `---` is displayed during flight instead of the remaining flight time/distance it means at least one of the above conditions aren't met. If the OSD element is blinking and the digits are replaced by the horizontal wind symbol it means that the estimated horizontal wind is too strong to be able to return home at `nav_fw_cruise_speed`.
## Automatic throttle compensation based on battery voltage
This features aims to compensate the throttle to get constant thrust with the same throttle request despite the battery voltage going down during flight. It can be used by enabling the `THR_VBAT_COMP` feature. This feature needs the sag compensated voltage which needs a current sensor (real or virtual) to be calculated.
It is working like this: `used_throttle = requested_throttle * (1 + (battery_full_voltage / sag_compensated_voltage - 1) * thr_comp_weight)`.
The default `thr_comp_weight` of 1 should be close to ideal but if you want to tune this feature you need to find the difference in throttle value to achieve the same thrust (same power) when your battery is full and when your battery is almost empty then set `thr_comp_weight` to `(empty_battery_throttle / full_battery_throttle - 1) / (battery_full_voltage / battery_empty_sag_compensated_voltage - 1)`
Example:
If the drawn power is 100W when the battery is full (12.6V) with 53% throttle and the drawn power is 100W with 58% throttle when the battery is almost empty with the sag compensated voltage being 11.0V `thr_comp_weight` needs to be set to this value to compensate the throttle automatically:
`(58 / 53 - 1) / (12.6 / 11.0 - 1) = 0.649`
Known limitation: it doesn't work in 3D mode (3D feature)
+240
View File
@@ -0,0 +1,240 @@
# Blackbox flight data recorder
![Rendered flight log frame](Screenshots/blackbox-screenshot-1.jpg)
## Introduction
This feature transmits your flight data information on every control loop iteration over a serial port to an external logging device to be recorded, SD card, or to a dataflash chip which is present on some flight controllers.
After your flight, you can view the resulting logs using the interactive log viewer:
https://github.com/iNavFlight/blackbox-log-viewer
You can also use the `blackbox_decode` tool to turn the logs into CSV files for analysis, or render your flight log as a
video using the `blackbox_render` tool. Those tools can be found in this repository:
https://github.com/iNavFlight/blackbox-tools
## Logged data
The blackbox records flight data on every iteration of the flight control loop. It records the current time in microseconds, P, I and D corrections for each axis, your RC command stick positions (after applying expo curves), gyroscope data, accelerometer data (after your configured low-pass filtering), barometer and rangefinder readings, 3-axis magnetometer readings, raw VBAT and current measurements, RSSI, and the command being sent to each motor speed controller. This is all stored without any approximation or loss of precision, so even quite subtle problems should be
detectable from the fight data log.
GPS data is logged whenever new GPS data is available. Although the CSV decoder will decode this data, the video renderer does not yet show any of the GPS information (this will be added later).
## Supported configurations
The maximum data rate that can be recorded to the flight log is fairly restricted, so anything that increases the load can cause the flight log to drop frames and contain errors.
The Blackbox is typically used on tricopters and quadcopters. Although it will work on hexacopters and octocopters, because these craft have more motors to record, they must transmit more data to the flight log. This can increase the number of dropped frames. Although the browser-based log viewer supports hexacopters and octocopters, the command-line `blackbox_render` tool currently only supports tri- and quadcopters.
INAV's `looptime` setting decides how frequently an update is saved to the flight log. The default looptime on INAV is 2000us. If you're using a looptime smaller than about 2400, you may experience some dropped frames due to the high required data rate. In that case you will need to reduce the sampling rate in the Blackbox settings, or increase your logger's baudrate to 250000. See the later section on configuring the Blackbox feature for details.
## Setting up logging
First, you must enable the Blackbox feature. In the [INAV Configurator][] enter the Configuration tab, tick the "BLACKBOX" feature at the bottom of the page, and click "Save and reboot"
Now you must decide which device to store your flight logs on. You can either transmit the log data over a serial port to an external logging device like the [OpenLog serial data logger][] to be recorded to a microSDHC card, or if you have a compatible flight controller you can store the logs on the onboard dataflash storage instead.
### OpenLog serial data logger
The OpenLog is a small logging device which attaches to your flight controller using a serial port and logs your flights to a MicroSD card.
The OpenLog ships from SparkFun with standard "OpenLog 3" firmware installed. Although this original OpenLog firmware will work with the Blackbox, in order to reduce the number of dropped frames it should be reflashed with the higher performance [OpenLog Blackbox firmware][]. The special Blackbox variant of the OpenLog firmware also ensures that the OpenLog is using INAV compatible settings, and defaults to 115200 baud.
You can find the Blackbox version of the OpenLog firmware [here](https://github.com/iNavFlight/openlog-blackbox-firmware), along with instructions for installing it onto your OpenLog.
[OpenLog serial data logger]: https://www.sparkfun.com/products/9530
[OpenLog Blackbox firmware]: https://github.com/iNavFlight/openlog-blackbox-firmware
#### microSDHC
Your choice of microSDHC card is very important to the performance of the system. The OpenLog relies on being able to make many small writes to the card with minimal delay, which not every card is good at. A faster SD-card speed rating is not a guarantee of better performance.
##### microSDHC cards known to have poor performance
- Generic 4GB Class 4 microSDHC card - the rate of missing frames is about 1%, and is concentrated around the most interesting parts of the log!
- Sandisk Ultra 32GB (unlike the smaller 16GB version, this version has poor write latency)
##### microSDHC cards known to have good performance
- Transcend 16GB Class 10 UHS-I microSDHC (typical error rate < 0.1%)
- Sandisk Extreme 16GB Class 10 UHS-I microSDHC (typical error rate < 0.1%)
- Sandisk Ultra 16GB (it performs only half as well as the Extreme in theory, but still very good)
You should format any card you use with the [SD Association's special formatting tool][] , as it will give the OpenLog the best chance of writing at high speed. You must format it with either FAT, or with FAT32 (recommended).
[SD Association's special formatting tool]: https://www.sdcard.org/downloads/formatter_4/
### Choosing a serial port for the OpenLog
First, tell the Blackbox to log using a serial port (rather than to an onboard dataflash chip). Go to the Configurator's CLI tab, enter `set blackbox_device=SERIAL` to switch logging to serial, and save.
You need to let INAV know which of [your serial ports][] you connect your OpenLog to (i.e. the Blackbox port), which you can do on the Configurator's Ports tab.
You should use a hardware serial port. SoftSerial ports can be used for the Blackbox. However, because they are limited to 19200 baud, your logging rate will need to be severely reduced to compensate. Therefore the use of SoftSerial is not recommended.
When using a hardware serial port, Blackbox should be set to at least 115200 baud on that port. When using fast looptimes (<2500), a baud rate of 250000 should be used instead in order to reduce dropped frames.
The serial port used for Blackbox cannot be shared with any other function (e.g. GPS, telemetry) except the MSP protocol. If MSP is used on the same port as Blackbox, then MSP will be active when the board is disarmed, and Blackbox will be active when the board is armed. This will mean that you can't use the Configurator or any other function that requires MSP, such as an OSD or a Bluetooth wireless configuration app, while the board is armed.
Connect the "TX" pin of the serial port you've chosen to the OpenLog's "RXI" pin. Don't connect the serial port's RX pin to the OpenLog, as this will cause the OpenLog to interfere with any shared functions on the serial port while disarmed.
The key criteria to choose a serial port are:
* Should be a hardware serial port rather than SoftSerial.
* Cannot be shared with any other function (GPS, telemetry) except MSP.
* If MSP is used on the same UART, MSP will stop working when the board is armed.
#### OpenLog configuration
Power up the OpenLog with a microSD card inside, wait 10 seconds or so, then power it down and plug the microSD card into your computer. You should find a "CONFIG.TXT" file on the card, open it up in a text editor. You should see the baud rate that the OpenLog has been configured for (usually 115200 or 9600 from the factory). Set the baud rate to match the rate you entered for the Blackbox in the Configurator's Port tab (typically 115200 or 250000).
Save the file and put the card back into your OpenLog, it will use those settings from now on.
If your OpenLog didn't write a CONFIG.TXT file, create a CONFIG.TXT file with these contents and store it in the root of the MicroSD card:
```
115200
baud
```
If you are using the original OpenLog firmware, use this configuration instead:
```
115200,26,0,0,1,0,1
baud,escape,esc#,mode,verb,echo,ignoreRX
```
#### OpenLog protection
The OpenLog can be wrapped in black electrical tape or heat-shrink in order to insulate it from conductive frames (like carbon fibre), but this makes its status LEDs impossible to see. I recommend wrapping it with some clear heatshrink tubing instead.
![OpenLog installed](Wiring/blackbox-installation-1.jpg "OpenLog installed with double-sided tape, SDCard slot pointing outward")
### Onboard dataflash storage
Some flight controllers have an onboard SPI NOR dataflash chip which can be used to store flight logs instead of using an OpenLog.
These chips are also supported:
* Micron/ST M25P16 - 16 Mbit / 2 MByte
* Micron N25Q064 - 64 Mbit / 8 MByte
* Winbond W25Q64 - 64 Mbit / 8 MByte
* Micron N25Q0128 - 128 Mbit / 16 MByte
* Winbond W25Q128 - 128 Mbit / 16 MByte
* Puya PY25Q128HA - 128 Mbit / 16 MByte
* Winbond W25N01 - 1 Gbit / 128 MByte
* Winbond W25N02 - 2 Gbit / 256 MByte
#### Enable recording to dataflash
On the Configurator's CLI tab, you must enter `set blackbox_device=SPIFLASH` to switch to logging to an onboard dataflash chip, then save.
[your serial ports]: https://github.com/iNavFlight/inav/blob/master/docs/Serial.md
[INAV Configurator]: https://chrome.google.com/webstore/detail/inav-configurator/fmaidjmgkdkpafmbnmigkpdnpdhopgel
## Configuring the Blackbox
The Blackbox currently provides two settings (`blackbox_rate_num` and `blackbox_rate_denom`) that allow you to control the rate at which data is logged. These two together form a fraction (`blackbox_rate_num / blackbox_rate_denom`) which decides what portion of the flight controller's control loop iterations should be logged. The default is 1/1 which logs every iteration.
If you're using a slower MicroSD card, you may need to reduce your logging rate to reduce the number of corrupted logged frames that `blackbox_decode` complains about. A rate of 1/2 is likely to work for most craft.
You can change the logging rate settings by entering the CLI tab in the [INAV Configurator][] and using the `set` command, like so:
```
set blackbox_rate_num = 1
set blackbox_rate_denom = 2
```
The data rate for my quadcopter using a looptime of 2400 and a rate of 1/1 is about 10.25kB/s. This allows about 18 days of flight logs to fit on my OpenLog's 16GB MicroSD card, which ought to be enough for anybody :).
If you are logging using SoftSerial, you will almost certainly need to reduce your logging rate to 1/32. Even at that logging rate, looptimes faster than about 1000 cannot be successfully logged.
If you're logging to an onboard dataflash chip instead of an OpenLog, be aware that the 2MB of storage space it offers is pretty small. At the default 1/1 logging rate, and a 2400 looptime, this is only enough for about 3 minutes of flight. This could be long enough for you to investigate some flying problem with your craft, but you may want to reduce the logging rate in order to extend your recording time.
To maximize your recording time, you could drop the rate all the way down to 1/32 which would result in a logging rate of about 10-20Hz and about 650 bytes/second of data. At that logging rate, a 2MB dataflash chip can store around 50 minutes of flight data, though the level of detail is severely reduced and you could not diagnose flight problems like vibration or PID setting issues.
The CLI command `blackbox` allows setting which Blackbox fields are recorded to conserve space and bandwidth. Possible fields are:
* `NAV_ACC` - Navigation accelerometer readouts
* `NAV_PID` - Navigation PID debug
* `NAV_POS` - Current and target position and altitude
* `MAG` - Magnetometer raw values
* `ACC` - Accelerometer raw values
* `ATTI` - Attitude as computed by INAV position estimator
* `RC_DATA` - RC channels 1-4 as returned by the radio receiver
* `RC_COMMAND` - RC_DATA converted to [-500:500] scale (for A,E,R) with expo and deadband
* `MOTORS` - motor output
* `GYRO_RAW` - Raw Gyro data
* `PEAKS_R` - Roll axis noise peak
* `PEAKS_P` - Pitch axis noise peak
* `PEAKS_Y` - Yaw axis noise peak
* `SERVOS` - Servo outputs (for planes, tris, etc.)
Usage:
* `blackbox` currently enabled Blackbox fields
* `blackbox list` all available fields
* `blackbox -MOTORS` disable MOTORS logging
* `blackbox MOTORS` enable MOTORS logging
### Debug Mode Logging
In addition to the standard blackbox fields above, INAV supports logging debug values for troubleshooting and analysis via the `debug_mode` setting. When a debug mode is active, it populates 8 debug values (`debug[0]` through `debug[7]`) with mode-specific data that gets logged to the blackbox.
Available debug modes include:
- `FLOW_RAW` - Optical flow sensor raw data (useful for sensor alignment)
- `LANDING` - Landing mode debugging
- `POS_EST` - Position estimation debugging
- `GPS` - GPS debugging
- `ALTITUDE` - Altitude estimation debugging
- And 20+ other modes for specific subsystems
To use debug mode logging:
```
set debug_mode = FLOW_RAW # Enable a specific debug mode
set debug_mode = NONE # Disable debug mode (default)
```
You can view current debug values in the CLI with the `debug` command, or display them in real-time on your OSD using the `OSD_DEBUG` element.
For technical details on debug logging and blackbox internals, see the [Blackbox Internals](development/Blackbox%20Internals.md) documentation.
## Usage
The Blackbox starts recording data as soon as you arm your craft, and stops when you disarm.
If your craft has a buzzer attached, you can use INAV's arming beep to synchronize your Blackbox log with your flight video. INAV's arming beep is a "long, short" pattern. The beginning of the first long beep will be shown as a blue line in the flight data log, which you can sync against your recorded audio track.
You should wait a few seconds after disarming your craft to allow the Blackbox to finish saving its data.
### Usage - OpenLog
Each time the OpenLog is power-cycled, it begins a fresh new log file. If you arm and disarm several times without cycling the power (recording several flights), those logs will be combined together into one file. The command line tools will ask you to pick which one of these flights you want to display/decode.
Don't insert or remove the SD card while the OpenLog is powered up.
### Usage - Dataflash chip
After your flights, you can use the [INAV Configurator][] to download the contents of the dataflash to your computer. Go to the "dataflash" tab and click the "save flash to file..." button. Saving the log can take 2 or 3 minutes.
![Dataflash tab in Configurator](Screenshots/blackbox-dataflash.png)
After downloading the log, be sure to erase the chip to make it ready for reuse by clicking the "erase flash" button.
If you try to start recording a new flight when the dataflash is already full, Blackbox logging will be disabled and nothing will be recorded.
### Usage - Logging switch
If you're recording to an onboard flash chip, you probably want to disable Blackbox recording when not required in order to save storage space. To do this, you can add a Blackbox flight mode to one of your AUX channels on the Configurator's modes tab. Once you've added a mode, Blackbox will only log flight data when the mode is active.
A log header will always be recorded at arming time, even if logging is paused. You can freely pause and resume logging while in flight.
## Viewing recorded logs
After your flights, you'll have a series of flight log files with a .TXT extension.
You can view these .TXT flight log files interactively using your web browser with the INAV Blackbox Explorer:
https://github.com/iNavFlight/blackbox-log-viewer
This allows you to scroll around a graphed version of your log and examine your log in detail. You can also export a video of your log to share it with others!
You can decode your logs with the `blackbox_decode` tool to create CSV (comma-separated values) files for analysis, or render them into a series of PNG frames with `blackbox_render` tool, which you could then convert into a video using another software package.
You'll find those tools along with instructions for using them in this repository:
https://github.com/iNavFlight/blackbox-tools
+36
View File
@@ -0,0 +1,36 @@
# Flight controller hardware
### Recommended boards
These boards are well tested with INAV and are known to be of good quality and reliability.
| Board name | CPU Family | Target name(s) | GPS | Compass | Barometer | Telemetry | RX | Blackbox |
|---------------------------|:----------:|:-------------------------:|:----:|:-------:|:--------------:|:---------:|:------------------------------:|:--------------------:|
| [Diatone Mamba H743](https://inavflight.com/shop/s/bg/1929033) | H7 | MAMBAH743 | All | All | All | All | All | SERIAL, SD |
| [Matek F765-WSE](https://inavflight.com/shop/s/bg/1890404) | F7 | MATEKF765SE | All | All | All | All | All | SERIAL, SD |
| [Matek F722-SE](https://inavflight.com/shop/p/MATEKF722SE) | F7 | MATEKF722SE | All | All | All | All | All | SERIAL, SD |
| [Holybro Kakute H7](https://inavflight.com/shop/s/bg/1914066) | H7 | KAKUTEH7 | All | All | All | All | All | SERIAL, SD |
It's possible to find more supported and tested boards [here](https://github.com/iNavFlight/inav/wiki/Welcome-to-INAV,-useful-links-and-products)
There is also a [full list of all supported boards](https://github.com/iNavFlight/inav/wiki/Boards,-Targets-and-PWM-allocations).
### Boards documentation
See the [docs/boards](https://github.com/iNavFlight/inav/tree/master/docs/boards) folder for additional information regards to many targets in INAV, to example help in finding pinout and features. _Feel free to help improve the docs._
### Boards based on F4/F7 CPUs
These boards are powerful and in general support everything INAV is capable of. Limitations are quite rare and are usually caused by hardware design issues.
### Boards based on F3 CPUs
Boards based on STM32F3 MCUs are no longer supported by latest INAV version. Last release is 2.6.1.
### Boards based on F1 CPUs
Boards based on STM32F1 CPUs are no longer supported by latest INAV version. Last release is 1.7.3
### Not recommended for new setups
F1 and F3 boards are no longer recommended. Users should choose a board from the supported F4 or F7 devices available in the latest release.
+79
View File
@@ -0,0 +1,79 @@
# Broken USB recovery
It is possible to flash INAV without USB over UART 1 or 3.
## Prerequisites:
- USB/UART adapter (FT232, CP2102, etc.)
- STM32 Cube Programmer (https://www.st.com/en/development-tools/stm32cubeprog.html)
To gain access to the FC via Configurator, MSP must be activated on a UART as standard. Some FCs already have this enabled by default, if not a custom firmware must be created.
The following targets have MSP activated on a UART by default:
| Target | Standard MSP Port |
|-----------| ----------- |
| AOCODARCF4V3 | UART5 |
| ATOMRCF405NAVI_DELUXE | UART1 |
| FF_F35_LIGHTNING | UART1 |
| FLYCOLORF7V2 | UART4 |
| GEPRCF405_BT_HD | UART5* |
| GEPRCF722_BT_HD | UART4* |
| IFLIGHT_BLITZ_F7_AIO | UART1 |
| JHEMCUF405WING | UART6 |
| JHEMCUH743HD | UART4 |
| KAKUTEH7 | UART1 and UART2* |
| KAKUTEH7WING | UART6 |
| MAMBAF405_2022A | UART4 |
| MAMBAF405US | UART4 |
| MAMBAF722 | UART4 |
| MAMBAF722 APP | UART4*|
| MAMBAF722WING | UART4 |
| MAMBAF722_X8 | UART4 |
| MAMBAH743 | UART4* |
| MATEKF405SE | UART1 |
| NEUTRONRCH743BT | UART3* |
| SDMODELH7V1 | UART1 and UART2 |
| SKYSTARSH743HD | UART4 |
| SPEEDYBEEF4 | UART5* |
| SPEEDYBEEF405MINI | UART4* |
| SPEEDYBEEF405V3 | UART4* |
| SPEEDYBEEF405V4 | UART4* |
| SPEEDYBEEF405WING | UART6 |
| SPEEDYBEEF7 | UART6 |
| SPRACINGF4EVO | UART1 |
| TMOTORF7V2 | UART5 |
(*) No Pads/Pins, Port is used interally (Bluetooth)
## Custom firmware:
If the FC does not have MSP activated on a UART by default or does not have a connector for it, a custom firmware must be built.
The following procedure describes the process under Windows 10/11:
Please read [Building in Windows 2010 or 11 with Linux Subsystem](https://github.com/iNavFlight/inav/blob/master/docs/development/Building%20in%20Windows%2010%20or%2011%20with%20Linux%20Subsystem.md)
and follow the instructions up to "Building with Make".
In the step 'prepare build environment' add the option `-DMSP_UART=SERIAL_PORT_USARTX` to `cmake`
Replace the X in SERIAL_PORT_USARTX with the number of UART/serial port on which MSP is to be activated.
Example:
For UART 2: `cmake -DMSP_UART=SERIAL_PORT_USART2 ..`
For UART 3: `cmake -DMSP_UART=SERIAL_PORT_USART3 ..`
etc.
Build the firmware as described in the document above (`make [YOUR_TARGET]`).
## Flashing via Uart:
1. Disconnect ALL peripherals and the USB Cable from the FC. To power the FC use a battery or use the 5V provided from the USB/Serial Converter.
2. Connect UART 1 or 3 (other UARTS will not work) and GND to the USB/Serial converter (RX -> TX, TX -> RX)
3. Keep the boot/dfu button pressed
4. Switch on the FC / supply with power
5. Start STM32 CubeProgrammer and go to "Erasing & Programming", second option in the menu.
6. Select UART (blue dropdown field) and select the COM port of the USB/Serial adapter and press "Connect". The corresponding processor should now be displayed below.
7. Click on "Full flash erase". This is also necessary if you are flashing the same firmware version that was previously on the FC, otherwise MSP may not be activated on the UART.
8. Under "Download" load the previously created firmware (`INAV_X.X.X_[Your Target].hex`) or the standard firmware if UART is already activated there. The option "Verify programming" is optional but recommended. Make sure that "Skip flash erase while programming" is NOT activated.
9. Click "Start Programming"
After the process is completed, switch the FC off and on again and then the Configurator can connect to the FC via USB/serial adapter and the previously configured UART.
+130
View File
@@ -0,0 +1,130 @@
# Buzzer
INAV supports a buzzer which is used for the following purposes:
* Low and critical battery alarms (when battery monitoring enabled)
* Arm/disarm tones (and warning beeps while armed)
* Notification of calibration complete status
* TX-AUX operated beeping - useful for locating your aircraft after a crash
* Failsafe status
* Flight mode change
* Rate profile change (via TX-AUX switch)
If the arm/disarm is via the control stick, holding the stick in the disarm position will sound a repeating tone. This can be used as a lost-model locator.
Three beeps immediately after powering the board means that the gyroscope calibration has completed successfully. INAV calibrates the gyro automatically upon every power-up. It is important that the copter stay still on the ground until the three beeps sound, so that gyro calibration isn't thrown off. If you move the copter significantly during calibration, INAV will detect this, and will automatically re-start the calibration once the copter is still again. This will delay the "three beeps" tone. If you move the copter just a little bit, the gyro calibration may be incorrect, and the copter may not fly correctly. In this case, the gyro calibration can be performed manually via [stick command](Controls.md), or you may simply power cycle the board.
There is a special arming tone used if a GPS fix has been attained, and there's a "ready" tone sounded after a GPS fix has been attained (only happens once). The tone sounded via the TX-AUX-switch will count out the number of satellites (if GPS fix).
The CLI command `play_sound` is useful for demonstrating the buzzer tones. Repeatedly entering the command will play the various tones in turn. Entering the command with a numeric-index parameter (see below) will play the associated tone.
Buzzer is enabled by default on platforms that have buzzer connections.
## Tone sequences
Buzzer tone sequences (square wave generation) are made so that : 1st, 3rd, 5th, .. are the delays how long the beeper is on and 2nd, 4th, 6th, .. are the delays how long beeper is off. Delays are in milliseconds/10 (i.e., 5 => 50ms).
Sequences:
0 GYRO_CALIBRATED 20, 10, 20, 10, 20, 10 Gyro is calibrated
1 RX_LOST_LANDING 10, 10, 10, 10, 10, 40, 40, 10, 40, 10, 40, 40, 10, 10, 10, 10, 10, 70 SOS morse code
2 RX_LOST 50, 50 TX off or signal lost (repeats until TX is okay)
3 DISARMING 15, 5, 15, 5 Disarming the board
4 ARMING 30, 5, 5, 5 Arming the board
5 ARMING_GPS_FIX 5, 5, 15, 5, 5, 5, 15, 30 Arming and GPS has fix
6 BAT_CRIT_LOW 50, 2 Battery is critically low (repeats)
7 BAT_LOW 25, 50 Battery is getting low (repeats)
8 NULL multi beeps GPS status (sat count)
9 RX_SET 10, 10 RX is set (when aux channel is set for beep or beep sequence how many satellites has found if GPS enabled)
10 ACC_CALIBRATION 5, 5, 5, 5 ACC inflight calibration completed
11 ACC_CALIBRATION_FAIL 20, 15, 35, 5 ACC inflight calibration failed
12 READY_BEEP 4, 5, 4, 5, 8, 5, 15, 5, 8, 5, 4, 5, 4, 5 GPS locked and copter ready
13 NULL multi beeps Variable # of beeps (confirmation, GPS sat count, etc)
14 DISARM_REPEAT 0, 100, 10 Stick held in disarm position (after pause)
15 ARMED 0, 245, 10, 5 Board is armed (after pause ; repeats until board is disarmed or throttle is increased)
You can use [this tool](https://www.mrd-rc.com/tutorials-tools-and-testing/useful-tools/helpful-inav-buzzer-code-checker/) to hear current buzzer sequences or enter custom sequences.
## Controlling buzzer usage
The usage of the buzzer can be controlled by the CLI `beeper` command.
### List current usage
```
beeper
```
### List all buzzer setting options
```
beeper list
```
giving:
```
Available: RUNTIME_CALIBRATION HW_FAILURE RX_LOST RX_LOST_LANDING DISARMING ARMING ARMING_GPS_FIX BAT_CRIT_LOW
BAT_LOW GPS_STATUS RX_SET ACTION_SUCCESS ACTION_FAIL READY_BEEP MULTI_BEEPS DISARM_REPEAT ARMED SYSTEM_INIT
ON_USB LAUNCH_MODE CAM_CONNECTION_OPEN CAM_CONNECTION_CLOSED ALL PREFERED
```
The `beeper` command syntax follows that of the `feature` command; a minus (`-`) in front of a name disables that function.
So to disable the beeper / buzzer when powered by USB (may enhance domestic harmony):
```
beeper -ON_USB
```
Now the `beeper` command will show:
```
# beeper
Disabled: ON_USB
```
*Note: SYSTEM_INIT sequence is not affected by ON_USB setting and will still be played on USB connection. Disable both ON_USB and SYSTEM_INIT to disable buzzer completely when FC is powered from USB.*
*Note: ON_USB setting requires present and configured battery voltage metter.*
To disable all features use:
```
beeper -ALL
```
To store current set to preferences use (preferences also require ```save```):
```
beeper PREFERED
```
To restore set from preferences use:
```
beeper -PREFERED
```
To activate an external beeper via aux channel switch, assign aux channel and set both:
```
beeper RX_SET
beeper MULTI_BEEPS
```
If MULTI_BEEPS is not set, the beeper will not sound after GPS lock.
As with other CLI commands, the `save` command is needed to save the new settings.
## Types of buzzer supported
Most FCs require ACTIVE buzzers. Active buzzers are enabled/disabled by simply enabling or disabling a GPIO output pin on the board.
This means the buzzer must be able to generate its own tone simply by having power applied to it.
Passive buzzers that need an analog or PWM signal do not work and will make clicking noises or no sound at all.
Passive buzzers are supported on FCs which are designed to work with passive buzzers only (so far there is no available, except rare cases like Matek F765-WSE where passive buzzer is preinstalled).
Examples of a known-working buzzers.
* [Hcm1205x Miniature Buzzer 5v](http://www.rapidonline.com/Audio-Visual/Hcm1205x-Miniature-Buzzer-5v-35-0055)
* [MultiComp MCKPX-G1205A-3700 TRANSDUCER, THRU-HOLE, 4V, 30MA](http://uk.farnell.com/multicomp/mckpx-g1205a-3700/transducer-thru-hole-4v-30ma/dp/2135914?CMP=i-bf9f-00001000)
* [3-24V Piezo Electronic Tone Buzzer Alarm 95DB](https://inavflight.com/shop/s/bg/919348)
+15
View File
@@ -0,0 +1,15 @@
# Channel forwarding
Starting from INAV 2.0, _channel forwarding_ feature is removed. Channel forwarding functionality can be configured using _Mixer Configurator Tab_ instead.
Channel forwarding using mixer works for all flight controllers that supports servos in either multirotor or airplane configuration. Bear in mind, that some boards might not have any servo outputs in multirotor configuration. In this case, channel forwarding will just not work. Refer to the board documentation to find out if servos are available in multirotor configuration.
## How to setup channel forwarding
![Mixer GUI](assets/images/mixer_forwarding.png)
1. Open Mixer tab
1. Add new _servo rule_ for given servo index
1. Choose source as one of _RC Roll_, _RC Pitch_, _RC Yaw_, _RC Throttle_ or _RC Channel 5_ to _RC Channel 16_
1. When required, servo direction can be modified by applying negative weight
1. It is possible to limit servo speed. Refer to [Mixer documentation](Mixer.md)
+251
View File
@@ -0,0 +1,251 @@
# Command Line Interface (CLI)
INAV has a command line interface (CLI) that can be used to change settings and configure the FC.
## Accessing the CLI.
The CLI can be accessed via the GUI tool or via a terminal emulator connected to the CLI serial port.
1. Connect your terminal emulator to the CLI serial port (which, by default, is the same as the MSP serial port)
2. Use the baudrate specified by msp_baudrate (115200 by default).
3. Send a `#` character.
To save your settings type in 'save', saving will reboot the flight controller.
To exit the CLI without saving power off the flight controller or type in 'exit'.
To see a list of other commands type in 'help' and press return.
To dump your configuration (including the current profile), use the 'dump' or 'diff' command.
See the other documentation sections for details of the cli commands and settings that are available.
## Backup via CLI
> **Note:** The INAV Configurator now performs automatic backups before flashing and can restore settings afterwards, including migration across major versions. See [Backup and Restore](Backup%20and%20Restore.md) for details. The CLI method below remains available for manual backup.
Disconnect main power, connect to cli via USB/FTDI.
dump using cli
```
control_profile 0
dump
```
dump control_profiles using cli if you use them
```
control_profile 1
dump control_profile
control_profile 2
dump control_profile
```
copy screen output to a file and save it.
Alternatively, use the `diff` command to dump only those settings that differ from their default values (those that have been changed).
## Restore via CLI.
Use the cli `defaults` command first.
When restoring from backup it's a good idea to do a dump of the latest defaults so you know what has changed - if you do this each time a firmware release is created you will be able to see the cli changes between firmware versions. If you blindly restore your backup you would not benefit from these new defaults or may even end up with completely wrong settings in case some parameters changed semantics and/or value ranges.
It may be good idea to restore settings using the `diff` output rather than complete `dump`. This way you can have more control on what is restored and the risk of mistakenly restoring bad values if the semantics changes is minimised.
To perform the restore simply paste the saved commands in the Configurator CLI tab and then type `save`.
After restoring it's always a good idea to `dump` or `diff` the settings once again and compare the output with previous one to verify if everything is set as it should be.
## Flight Controller opereration while connected to the CLI
While connected to the CLI, all Logical Switches are temporarily disabled (5.1.0 onwards).
## CLI Command Reference
| `Command` | Description |
|-----------| ----------- |
| `adjrange` | Configure adjustment ranges |
| `assert` | |
| `aux` | Configure modes |
| `batch` | Start or end a batch of commands |
| `battery_profile` | Change battery profile |
| `beeper` | Show/set beeper (buzzer) [usage](Buzzer.md) |
| `bind_msp_rx` | Initiate binding for MSP receivers (mLRS) |
| `bind_rx` | Initiate binding for SRXL2 or CRSF receivers |
| `blackbox` | Configure blackbox fields |
| `bootlog` | Show init logs from [serial_printf_debugging](./development/serial_printf_debugging.md) |
| `color` | Configure colors |
| `defaults` | Reset to defaults and reboot |
| `dfu` | DFU mode on reboot |
| `diff` | List configuration changes from default |
| `dump` | Dump configuration |
| `exit` | |
| `feature` | List or enable <val> or disable <-val> |
| `flash_erase` | Erase flash chip |
| `flash_info` | Show flash chip info |
| `flash_read` | |
| `flash_write` | |
| `get` | Get variable value |
| `gpspassthrough` | Passthrough gps to serial |
| `gvar` | Configure global variables |
| `help` | Displays CLI help and command parameters / options |
| `led` | Configure leds |
| `logic` | Configure logic conditions |
| `map` | Configure rc channel order |
| `memory` | View memory usage |
| `mmix` | Custom motor mixer |
| `mode_color` | Configure mode and special colors |
| `motor` | Get/set motor |
| `msc` | Enter USB Mass storage mode. See [USB MSC documentation](USB_Mass_Storage_(MSC)_mode.md) for usage information. |
| `osd_layout` | Get or set the layout of OSD items |
| `pid` | Configurable PID controllers |
| `play_sound` | `<index>`, or none for next item |
| `control_profile` | Change profile |
| `resource` | View currently used resources |
| `rxrange` | Configure rx channel ranges |
| `safehome` | Define safe home locations. See the [safehome documentation](Safehomes.md) for usage information. |
| `save` | Save and reboot |
| `sd_info` | Sdcard info |
| `serial` | Configure serial ports. [Usage](Serial.md) |
| `serialpassthrough` | Passthrough serial data to port, with `<id> <baud> <mode> <options>`, where `id` is the zero based port index, `baud` is a standard baud rate, mode is `rx`, `tx`, or both (`rxtx`), and options is a short string like `8N1` or `8E2` |
| `servo` | Configure servos |
| `set` | Change setting with name=value or blank or * for list |
| `smix` | Custom servo mixer |
| `status` | Show status. Error codes can be looked up [here](https://github.com/iNavFlight/inav/wiki/%22Something%22-is-disabled----Reasons) |
| `tasks` | Show task stats |
| `temp_sensor` | List or configure temperature sensor(s). See [temperature sensors documentation](Temperature-sensors.md) for more information. |
| `timer_output_mode` | Override automatic timer / pwm function allocation. [Additional Information](#timer_outout_mode)|
| `version` | Show version |
| `wp` | List or configure waypoints. See the [navigation documentation](Navigation.md#cli-command-wp-to-manage-waypoints). |
Notes:
* Available commands depend upon hardware specific and debug build options. Not all commands are available in every FC.
* The above list shows the output available in the CLI `help` command. This may also show additional information.
### serial
The syntax of the `serial` command is `serial <id> <function_value> <msp-baudrate> <gps-baudrate> <telemetry-baudate> <peripheral-baudrate>`.
A shorter form is also supported to enable and disable a single function using `serial <id> +n` and `serial <id> -n`, where n is the a serial function identifier. The following values are available:
| Function | Bit Identifier | Numeric value |
|-----------------------|---------------|----------------|
| MSP | 0 | 1 |
| GPS | 1 | 2 |
| TELEMETRY_FRSKY | 2 | 4 |
| TELEMETRY_HOTT | 3 | 8 |
| TELEMETRY_LTM | 4 | 16 |
| TELEMETRY_SMARTPORT | 5 | 32 |
| RX_SERIAL | 6 | 64 |
| BLACKBOX | 7 | 128 |
| TELEMETRY_MAVLINK | 8 | 256 |
| TELEMETRY_IBUS | 9 | 512 |
| RCDEVICE | 10 | 1024 |
| VTX_SMARTAUDIO | 11 | 2048 |
| VTX_TRAMP | 12 | 4096 |
| UAV_INTERCONNECT | 13 | 8192 |
| OPTICAL_FLOW | 14 | 16384 |
| LOG | 15 | 32768 |
| RANGEFINDER | 16 | 65536 |
| VTX_FFPV | 17 | 131072 |
| ESCSERIAL | 18 | 262144 |
| TELEMETRY_SIM | 19 | 524288 |
| FRSKY_OSD | 20 | 1048576 |
| DJI_HD_OSD | 21 | 2097152 |
| SERVO_SERIAL | 22 | 4194304 |
| TELEMETRY_SMARTPORT_MASTER | 23 | 8388608 |
| UNUSED | 24 | 16777216 |
| MSP_DISPLAYPORT | 25 | 33554432 |
| GIMBAL_SERIAL | 26 | 67108864 |
| HEADTRACKER_SERIAL | 27 | 134217728 |
Thus, to enable MSP and LTM on a port, one would use the function **value** of 17 (1 << 0)+(1<<4), aka 1+16, aka 17.
```
serial 0 17 57600 57600 57600 57600
```
but to remove LTM using the +/- shorthand, use the **bit Id** (4, TELEMETRY_LTM):
```
serial 0 -4
```
`serial` can also be used without any argument to print the current configuration of all the serial ports.
### `timer_output_mode`
Since INAV 7, the firmware can dynamically allocate servo and motor outputs. This removes the need for bespoke targets for special cases (e.g. `MATEKF405` and `MATEKF405_SERVOS6`).
#### Syntax
```
timer_output_mode [timer [function]]
```
where:
* Without parameters, lists the current timers and modes
* With just a `timer` lists the mode for that timer
* With both `timer` and `function`, sets the function for that timers
Note:
* `timer` identifies the timer **index** (from 0); thus is one less than the corresponding `TIMn` definition in a target's `target.c`.
* The function is one of `AUTO` (the default), `MOTORS` or `SERVOS`.
Motors are allocated first, hence having a servo before a motor may require use of `timer_output_mode`.
#### Example
The original `MATEKF405` target defined a multi-rotor (MR) servo on output S1. The later `MATEKF405_SERVOS6` target defined (for MR) S1 as a motor and S6 as a servo. This was more logical, but annoying for anyone who had a legacy `MATEKF405` tricopter with the servo on S1.
#### Solution
There is now a single `MATEKF405` target. The `target.c` sets the relevant outputs as:
```
DEF_TIM(TIM3, CH1, PC6, TIM_USE_OUTPUT_AUTO, 0, 0), // S1
DEF_TIM(TIM8, CH2, PC7, TIM_USE_OUTPUT_AUTO, 0, 1), // S2 UP(2,1)
DEF_TIM(TIM8, CH3, PC8, TIM_USE_OUTPUT_AUTO, 0, 1), // S3 UP(2,1)
DEF_TIM(TIM8, CH4, PC9, TIM_USE_OUTPUT_AUTO, 0, 0), // S4 UP(2,1)
DEF_TIM(TIM2, CH1, PA15, TIM_USE_MC_MOTOR | TIM_USE_LED, 0, 0), // S5 UP(1,7)
DEF_TIM(TIM1, CH1, PA8, TIM_USE_OUTPUT_AUTO, 0, 0), // S6 UP(2,5)
DEF_TIM(TIM4, CH3, PB8, TIM_USE_OUTPUT_AUTO, 0, 0), // S7 D(1,7)!S5 UP(2,6)
```
Using the "motors first" allocation, the servo would end up on S6, which in the legacy "tricopter servo on S1" case is not desired.
Forcing the S1 output (`TIM3`) to servo is achieved by:
```
timer_output_mode 2 SERVOS
```
with resulting `resource` output:
```
C06: SERVO4 OUT
C07: MOTOR1 OUT
C08: MOTOR2 OUT
C09: MOTOR3 OUT
```
Note that the `timer` **index** in the `timer_output_mode` line is one less than the mnemonic in `target.c`, `timer` of 2 for `TIM3`.
Note that the usual caveat that one should not share a timer with both a motor and a servo still apply.
## Flash chip management
For targets that have a flash data chip, typically used for blackbox logs, the following additional comamnds are provided.
| Command | Effect |
| ------- | ------ |
| `flash_erase` | Erases the flash chip |
| `flash_info` | Displays flash chip information (used, free etc.) |
| `flash_read <length> <address>` | Reads `length` bytes from `address` |
| `flash_write <address> <data>` | Writes `data` to `address` |
## CLI Variable Reference
See [Settings.md](Settings.md).
+35
View File
@@ -0,0 +1,35 @@
# Configuration
INAV is configured primarily using the INAV Configurator GUI.
Both the command line interface and GUI are accessible by connecting to a serial port on the target,
be it a USB virtual serial port, physical hardware UART port or a SoftSerial port.
See the Serial section for more information and see the Board specific sections for details of the serial ports available on the board you are using.
The GUI cannot currently configure all aspects of the system, the CLI must be used to enable or configure
some features and settings.
__The INAV Configurator now (versions after 9.0.x) automatically backs up your settings before flashing firmware and can restore them afterwards (when Full Chip Erase is enabled), including automatic migration across major versions. For details, see [Backup and Restore](Backup%20and%20Restore.md). You can also manually backup and restore settings using the [CLI](Cli.md#backup-via-cli).__
## GUI
![INAV Gui](Screenshots/cleanflight-gui.png)
The GUI tool is the preferred way of configuration. The GUI tool also includes a terminal which
can be used to interact with the CLI.
[INAV Configurator on Chrome store](https://chrome.google.com/webstore/detail/inav-configurator/fmaidjmgkdkpafmbnmigkpdnpdhopgel)
If you cannot use the latest version of the GUI to access the FC due to firmware compatibility issues you can still access the FC via the CLI to backup your settings, or you can install an old version of the configurator.
Old versions of the configurator can be downloaded from the configurator releases page: https://github.com/iNavFlight/inav-configurator/releases
See the README file that comes with the configurator for installation instructions.
## CLI
INAV can also be configured by a command line interface.
See the CLI section of the documentation for more details.
+170
View File
@@ -0,0 +1,170 @@
# Control Profiles
A profile is a set of configuration settings.
Currently, INAV gives you three control profiles. The default control profile is `1`.
## Changing control profiles
### Stick Commands
Control profiles can be selected using a GUI or the following stick combinations:
| Profile # | Throttle | Yaw | Pitch | Roll |
| -------- | -------- | ----- | ------ | ------ |
| 1 | Down | Left | Middle | Left |
| 2 | Down | Left | Up | Middle |
| 3 | Down | Left | Middle | Right |
### CLI
The CLI `control_profile` command can also be used to change control profiles:
```
control_profile <index>
```
### Programming (4.0.0 onwards)
You can change control profiles using the programming frame work. This allows a lot of flexability in how you change profiles.
For example, using a simple switch on channel 15.
[![For example, using a simple switch](https://i.imgur.com/SS9CaaOl.png)](https://i.imgur.com/SS9CaaO.png)
Or using the speed to change control profiles. In this example:
- when lower than 25 cm/s (basically not flying), control profiles are not effected.
- Below 2682 cm/s (60 mph | 97 Km/h) use control profile 1
- Above 5364 cm/s (120 mph | 193 Km/h) use control profile 3
- Between 2683 and 5364 cm/s, use control profile 2
[![Using speed to change profiles](https://i.imgur.com/WjkuhhWl.png)](https://i.imgur.com/WjkuhhW.png)
> [!NOTE]
> From INAV 8.0, the programming framework operator is **Set Control Profile** and the **Flight** Operand is **Active Control Profile**. Pre-INAV 8.0, they were **Set Profile** and **Active Profile** respectively.
#### Configurator use with control profile changing logic.
If you have logic conditions that change the profiles. You may find that if you manually change the control profile; using the drop down boxes in the top right of Configurator. That they switch back to a different control profile. This is because the logic conditions are still running in the background. If this is the case, the simplest solutuion is to temporarily disable the switches that trigger the `Set Control Profile` operations. Remember to re-enable these switches after you have made your changes.
[![Disabled SET PROFILE switches](https://i.imgur.com/AeH9ll7l.png)](https://i.imgur.com/AeH9ll7.png)
## Profile Contents
The values contained within a control profile can be seen by using the CLI `dump control_profile` command.
e.g
```
# dump control_profile
# control_profile
control_profile 1
set mc_p_pitch = 40
set mc_i_pitch = 30
set mc_d_pitch = 23
set mc_cd_pitch = 60
set mc_p_roll = 40
set mc_i_roll = 30
set mc_d_roll = 23
set mc_cd_roll = 60
set mc_p_yaw = 85
set mc_i_yaw = 45
set mc_d_yaw = 0
set mc_cd_yaw = 60
set mc_p_level = 20
set mc_i_level = 15
set mc_d_level = 75
set fw_p_pitch = 5
set fw_i_pitch = 7
set fw_d_pitch = 0
set fw_ff_pitch = 50
set fw_p_roll = 5
set fw_i_roll = 7
set fw_d_roll = 0
set fw_ff_roll = 50
set fw_p_yaw = 6
set fw_i_yaw = 10
set fw_d_yaw = 0
set fw_ff_yaw = 60
set fw_p_level = 20
set fw_i_level = 5
set fw_d_level = 75
set max_angle_inclination_rll = 300
set max_angle_inclination_pit = 300
set dterm_lpf_hz = 110
set dterm_lpf_type = PT2
set yaw_lpf_hz = 0
set fw_iterm_throw_limit = 165
set fw_loiter_direction = RIGHT
set fw_reference_airspeed = 1500.000
set fw_turn_assist_yaw_gain = 1.000
set fw_turn_assist_pitch_gain = 1.000
set fw_iterm_limit_stick_position = 0.500
set fw_yaw_iterm_freeze_bank_angle = 0
set pidsum_limit = 500
set pidsum_limit_yaw = 350
set iterm_windup = 50
set rate_accel_limit_roll_pitch = 0
set rate_accel_limit_yaw = 10000
set heading_hold_rate_limit = 90
set nav_mc_pos_z_p = 50
set nav_mc_vel_z_p = 100
set nav_mc_vel_z_i = 50
set nav_mc_vel_z_d = 10
set nav_mc_pos_xy_p = 65
set nav_mc_vel_xy_p = 40
set nav_mc_vel_xy_i = 15
set nav_mc_vel_xy_d = 100
set nav_mc_vel_xy_ff = 40
set nav_mc_heading_p = 60
set nav_mc_vel_xy_dterm_lpf_hz = 2.000
set nav_mc_vel_xy_dterm_attenuation = 90
set nav_mc_vel_xy_dterm_attenuation_start = 10
set nav_mc_vel_xy_dterm_attenuation_end = 60
set nav_fw_pos_z_p = 40
set nav_fw_pos_z_i = 5
set nav_fw_pos_z_d = 10
set nav_fw_pos_xy_p = 75
set nav_fw_pos_xy_i = 5
set nav_fw_pos_xy_d = 8
set nav_fw_heading_p = 60
set nav_fw_pos_hdg_p = 30
set nav_fw_pos_hdg_i = 2
set nav_fw_pos_hdg_d = 0
set nav_fw_pos_hdg_pidsum_limit = 350
set mc_iterm_relax = RP
set mc_iterm_relax_cutoff = 15
set d_boost_min = 0.500
set d_boost_max = 1.250
set d_boost_max_at_acceleration = 7500.000
set d_boost_gyro_delta_lpf_hz = 80
set antigravity_gain = 1.000
set antigravity_accelerator = 1.000
set antigravity_cutoff_lpf_hz = 15
set pid_type = AUTO
set mc_cd_lpf_hz = 30
set fw_level_pitch_trim = 0.000
set smith_predictor_strength = 0.500
set smith_predictor_delay = 0.000
set smith_predictor_lpf_hz = 50
set fw_level_pitch_gain = 5.000
set thr_mid = 50
set thr_expo = 0
set tpa_rate = 0
set tpa_breakpoint = 1500
set fw_tpa_time_constant = 0
set rc_expo = 70
set rc_yaw_expo = 20
set roll_rate = 20
set pitch_rate = 20
set yaw_rate = 20
set manual_rc_expo = 70
set manual_rc_yaw_expo = 20
set manual_roll_rate = 100
set manual_pitch_rate = 100
set manual_yaw_rate = 100
set fpv_mix_degrees = 0
set rate_dynamics_center_sensitivity = 100
set rate_dynamics_end_sensitivity = 100
set rate_dynamics_center_correction = 10
set rate_dynamics_end_correction = 10
set rate_dynamics_center_weight = 0
set rate_dynamics_end_weight = 0
```
+116
View File
@@ -0,0 +1,116 @@
# Controls
## Arming
When armed, the aircraft is ready to fly and the motors will spin when throttle is applied. With multirotors, the motors will spin at a slow speed when armed (this feature may be disabled by setting MOTOR_STOP, but for safety reasons, that is not recommended).
Arming and disarming is done using a switch, set up on the modes page. (NOTE: Stick arming was removed in INAV 2.2)
**YAW STICK ARMING OVERRIDE:**
Arming is disabled when Nav modes are configured and no GPS lock is available or if a WP mission is loaded but the first WP is farther than the `nav_wp_safe_distance` setting. This Arming block can be bypassed if need be by setting `nav_extra_arming_safety` to `ALLOW_BYPASS` and moving the Yaw stick to the high position when the Arm switch is used. This bypasses GPS Arm blocking pre INAV 4.0.0 and both GPS and "First WP too far" Arm blocking from INAV 4.0.0.
## Stick Positions
The three stick positions are:
|Position | Approx. Channel Input|
|----------------|----------------------|
|LOW | 1000 |
|CENTER | 1500 |
|HIGH | 2000 |
The stick positions are combined to activate different functions:
| Function | Throttle | Yaw | Pitch | Roll |
| ----------------------------- | -------- | ------- | ------ | ------ |
| Control Profile 1 | LOW | LOW | CENTER | LOW |
| Control Profile 2 | LOW | LOW | HIGH | CENTER |
| Control Profile 3 | LOW | LOW | CENTER | HIGH |
| Battery profile 1 | HIGH | LOW | CENTER | LOW |
| Battery profile 2 | HIGH | LOW | HIGH | CENTER |
| Battery profile 3 | HIGH | LOW | CENTER | HIGH |
| Calibrate Gyro | LOW | LOW | LOW | CENTER |
| Calibrate Acc | HIGH | LOW | LOW | CENTER |
| Calibrate Compass/Zero Yaw | HIGH | HIGH | LOW | CENTER |
| Trim Acc Left | HIGH | CENTER | CENTER | LOW |
| Trim Acc Right | HIGH | CENTER | CENTER | HIGH |
| Trim Acc Forwards | HIGH | CENTER | HIGH | CENTER |
| Trim Acc Backwards | HIGH | CENTER | LOW | CENTER |
| Save current waypoint mission | LOW | CENTER | HIGH | LOW |
| Load current waypoint mission | LOW | CENTER | HIGH | HIGH |
| Unload waypoint mission | LOW | CENTER | LOW | HIGH |
| Increase WP mission index | LOW | CENTER | CENTER | HIGH |
| Decrease WP mission index | LOW | CENTER | CENTER | LOW |
| Bypass Nav Arm disable | LOW | HIGH | CENTER | CENTER |
| Save setting | LOW | LOW | LOW | HIGH |
| Enter OSD Menu (CMS) | CENTER | LOW | HIGH | CENTER |
| Enter Camera OSD(RuncamDevice)| CENTER | HIGH | CENTER | CENTER |
| Exit Camera OSD (RuncamDevice)| CENTER | LOW | CENTER | CENTER |
| Confirm - Camera OSD | CENTER | HIGH | CENTER | CENTER |
| Navigation - Camera OSD | CENTER | CENTER | * | * |
For graphical stick position in all transmitter modes, check out [this page](https://www.mrd-rc.com/tutorials-tools-and-testing/inav-flight/inav-stick-commands-for-all-transmitter-modes/).
![Stick Positions](assets/images/StickPositions.png)
## Compass Calibration and Yaw Zero Reset
The stick function `Calibrate Compass/Zero Yaw` provides 2 functions depending on whether or not a compass is available.
If a compass is available the stick function initiates the compass calibration routine.
If no compass is available the stick function will reset the current yaw/heading estimate to zero (North) and also set the heading as trusted. This is useful on multirotors, allowing the craft yaw/heading to be correctly aligned to actual North simply by physically pointing the craft North then using the stick function to zero the yaw estimate. Since this also sets the heading as trusted Nav modes reliant on heading will be available immediately after arming without the need to fly fast enough to obtain a valid heading from GPS ground course.
## Yaw control
While arming/disarming with sticks, your yaw stick will be moving to extreme values. In order to prevent your craft from trying to yaw during arming/disarming while on the ground, your yaw input will not cause the craft to yaw when the throttle is LOW (i.e. below the `min_check` setting).
For tricopters, you may want to retain the ability to yaw while on the ground, so that you can verify that your tail servo is working correctly before takeoff. You can do this by setting `tri_unarmed_servo` to `1` on the CLI (this is the default). If you are having issues with your tail rotor contacting the ground during arm/disarm, you can set this to `0` instead. Check this table to decide which setting will suit you:
<table>
<tr>
<th colspan="5">Is yaw control of the tricopter allowed?</th>
</tr>
<tr>
<th></th><th colspan="2">Disarmed</th><th colspan="2">Armed</th>
</tr>
<tr>
<th></th><th>Throttle low</th><th>Throttle normal</th><th>Throttle low</th><th>Throttle normal</th>
</tr>
<tr>
<td rowspan="2">tri_unarmed_servo = 0</td><td>No</td><td>No</td><td>No</td><td>Yes</td>
</tr>
<tr>
<td>No</td><td>No</td><td>No</td><td>Yes</td>
</tr>
<tr>
<td rowspan="2">tri_unarmed_servo = 1</td><td>Yes</td><td>Yes</td><td>Yes</td><td>Yes</td>
</tr>
<tr>
<td>Yes</td><td>Yes</td><td>Yes</td><td>Yes</td>
</tr>
</table>
## Throttle settings and their interaction
*Terminology. After INAV 2.3, the setting `min_throttle` was replaced with `throttle_idle` which is more appropriate to modern hardware. In this document `min_throttle` may be taken as either the older `min_throttle` value, or the throttle value calculated from the modern `throttle_idle` setting. The way that `throttle_idle` generates a throttle value is described in `Cli.md`.*
`min_command` -
With motor stop enabled this is the command sent to the esc's when the throttle is below min_check or disarmed. With motor stop disabled, this is the command sent only when the copter is disarmed. This must be set well below motors spinning for safety.
`min_check` -
With switch arming mode is in use, lowering your throttle below min_check will result in motors spinning at `throttle_idle` (min_throttle). When using the default stick arming, lowering your throttle below min_check will result in motors spinning at min_throttle and yaw being disabled so that you may arm/disarm. With motor stop enabled, lowering your throttle below min_check will also result in motors off and the esc's being sent min_command. Min_check must be set to a level that is 100% reliably met by the throttle throw. A setting too low may result in a dangerous condition where the copter cant be disarmed. It is ok to set this below `throttle_idle` (min_throttle) because the FC will automaticly scale the output to the ESCs
`throttle_idle` (previously `min_throttle)` -
Typically set to just above reliable spin up of all motors. Sometimes this is set slightly higher for prop stall prevention during advanced maneuvers or sometimes considerably higher to produce a desired result. When armed with motor stop off, your motors will spin at this command so keep that in mind from a safety stand point.
`max_check` -
Throttle positions above this level will send max_command to the ESCs.
`max_throttle` -
This is the max command to the ESCs from the flight controller.
In depth videos explaining these terms are available from Joshua Bardwell here:
https://www.youtube.com/watch?v=WFU3VewGbbA
https://www.youtube.com/watch?v=YNRl0OTKRGA
+50
View File
@@ -0,0 +1,50 @@
# DJI compatible MSP DisplayPort OSD (DJI O3 "Canvas Mode")
INAV 6.0 includes a special mode for MSP DisplayPort that supports DJI's incomplete implementations of MSP DisplayPort. This can be found on products like the DJI O3 Air Unit. INAV 6.1 expands this to include HD canvas sizes from BetaFlight 4.4.
Different flight controller firmware have different OSD symbols and elements and require different fonts. BetaFlight's font is a single page and supports a maximum of 256 glyphs, INAV's font is currently 2 pages and supports up to 512 different glyphs. DJI's font is single page and based, but not the same as, BetaFlight's font.
While there is some overlap between the glyphs in DJI and INAV, it is not possible to perform a 1 to 1 mapping for all the them. In cases where there is no suitable glyph in the DJI font, a question mark `?` will be displayed.
This mode can be enabled by selecting DJI43COMPAT or DJIHDCOMPAT as video format in the OSD tab of the configurator or by typing the following command on the CLI:
`set osd_video_system = DJI43COMPAT`
or
`set osd_video_system = DJIHDCOMPAT`
## Limitations
* Canvas size needs to be manually changed to HD on the Display menu in DJI's goggles (you may need a firmware update) and set as DJIHDCOMPAT in the OSD tab of the configurator.
* Unsupported Glyphs show up as `?`
## FAQ
### I see a lot of `?` on my OSD.
That is expected. When your INAV OSD widgets use glyphs that don't have a suitable mapping in DJI's font.
### Does it work with the G2 and Original Air Unit/Vista?
Yes.
### Is this a replacement for WTFOS?
Not exactly. WTFOS is a full implementation of MSP-Displayport for rooted Air Unit/Vista/Googles V2 and actually works much better than DJI compatibility mode. It can use all of INAV's OSD elements as intended. If you have the option of WTFOS or DJI compatability mode. WTFOS is the best option.
### Can INAV fix DJI's product?
No. OSD renderinng happens on the googles/air unit side of things. Please ask DJI to fix their incomplete MSP DisplayPort implemenation. You can probably request it in [DJI's forum](https://forum.dji.com/forum.php?mod=forumdisplay&fid=129&filter=typeid&typeid=767). To see what you're missing out on with O3. Check out what WTFOS did with the original system. Not only could the pilots upload the fonts of their choosing (who doesn't want a cool SneakyFPV font on their OSD). But there were no problems supporting and firmware. Plus, there was even an option to save the OSD to a file and overlay that over your DVR video. If you're reading this far. Please recommend to DJI that they fix their product, to at least what was possible with WTFOS.
### DJI's font now has more symbols, can you update INAV?
Maybe. If a future version of DJI's font includes more Glyphs that can be mapped into INAV. It is fairly simple to add the mapping. However, the best solution would be full support of MSP DisplayPort by DJI. Then there will never be an issue with missing icons. As the latest INAV font would be able to be uploaded on to the goggles.
### Can you replace glyph `X` with text `x description`?
While it might technically be possible to replace some glyphs with text in multiple cells, it will introduce a lot of complexity in the OSD rendering and configuration for something we hope is a temporary workaround.
### Does DJI support Canvas Mode?
Actually, no. What DJI calls Canvas Mode is actually MSP DisplayPort and is a character based OSD. Currently, the only true implementaion of Canvas Mode is with FrSKY PixelOSD. This was found on some F722 flight controllers from Matek.

Some files were not shown because too many files have changed in this diff Show More