Compare commits
29
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ce23bcf91f | ||
|
|
d3d606c1d5 | ||
|
|
b5940fc9f0 | ||
|
|
9b11352d42 | ||
|
|
1daeb2edce | ||
|
|
f6956160bb | ||
|
|
63d0781e29 | ||
|
|
bfc536f96c | ||
|
|
7d7bfbcf24 | ||
|
|
8fcaf5ff30 | ||
|
|
3773683df6 | ||
|
|
2c782223a5 | ||
|
|
dcabb85000 | ||
|
|
9c3ceaf6e9 | ||
|
|
b2c07708bd | ||
|
|
b5737d089b | ||
|
|
3ccec98b58 | ||
|
|
30a3f39ed0 | ||
|
|
55da30ab58 | ||
|
|
078cd68191 | ||
|
|
e932c9786f | ||
|
|
8d1659a993 | ||
|
|
d04509bbf0 | ||
|
|
8d1674c3e5 | ||
|
|
af87c55530 | ||
|
|
1898aec281 | ||
|
|
dd2a4a3121 | ||
|
|
a77836279a | ||
|
|
ebc41e571c |
@@ -76,7 +76,7 @@ runs:
|
||||
done
|
||||
|
||||
- name: PlatformIO ${{ inputs.arch }} download cache
|
||||
uses: actions/cache@v6
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ~/.platformio/.cache
|
||||
key: pio-cache-${{ inputs.arch }}-${{ hashFiles('.github/actions/**', '**.ini') }}
|
||||
|
||||
@@ -5,7 +5,7 @@ runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ jobs:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
path: meshtasticd
|
||||
|
||||
@@ -23,7 +23,7 @@ jobs:
|
||||
outputs:
|
||||
artifact-id: ${{ steps.upload-firmware.outputs.artifact-id }}
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
runs-on: macos-${{ inputs.macos_ver }}
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ jobs:
|
||||
- stm32
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: 3.x
|
||||
@@ -64,7 +64,7 @@ jobs:
|
||||
if: ${{ inputs.target != '' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
- name: Get release version string
|
||||
run: |
|
||||
echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
||||
@@ -93,7 +93,7 @@ jobs:
|
||||
needs: [version, build]
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
ref: ${{github.event.pull_request.head.ref}}
|
||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||
|
||||
@@ -47,7 +47,7 @@ jobs:
|
||||
runs-on: ${{ inputs.runs-on }}
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
|
||||
@@ -103,7 +103,7 @@ jobs:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
|
||||
@@ -1,190 +0,0 @@
|
||||
name: Post Web Flasher Link Comment
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: [CI]
|
||||
types: [completed]
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
actions: read
|
||||
|
||||
jobs:
|
||||
post-flasher-link:
|
||||
if: >
|
||||
github.event.workflow_run.event == 'pull_request' &&
|
||||
github.event.workflow_run.conclusion != 'cancelled' &&
|
||||
github.repository == 'meshtastic/firmware'
|
||||
continue-on-error: true
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
# Per-board manifests carry the firmware's own metadata (activelySupported,
|
||||
# displayName, ...) generated from each target's custom_meshtastic_* config.
|
||||
- name: Download board manifests
|
||||
uses: actions/download-artifact@v8
|
||||
continue-on-error: true
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
run-id: ${{ github.event.workflow_run.id }}
|
||||
pattern: manifest-*
|
||||
path: ./manifests
|
||||
merge-multiple: true
|
||||
|
||||
- name: Post or update web flasher link comment
|
||||
uses: actions/github-script@v9
|
||||
with:
|
||||
script: |
|
||||
const marker = '<!-- web-flasher-link -->';
|
||||
const run = context.payload.workflow_run;
|
||||
const { owner, repo } = context.repo;
|
||||
|
||||
// Resolve the PR number (run.pull_requests is empty for fork PRs)
|
||||
let prNumber = run.pull_requests?.[0]?.number;
|
||||
if (!prNumber) {
|
||||
const { data: prs } = await github.rest.repos.listPullRequestsAssociatedWithCommit({
|
||||
owner, repo, commit_sha: run.head_sha,
|
||||
});
|
||||
prNumber = (prs.find((pr) => pr.head.sha === run.head_sha) ?? prs[0])?.number;
|
||||
}
|
||||
if (!prNumber) {
|
||||
core.info('No pull request associated with this run; skipping.');
|
||||
return;
|
||||
}
|
||||
|
||||
const { data: pr } = await github.rest.pulls.get({ owner, repo, pull_number: prNumber });
|
||||
|
||||
// Only comment on PRs authored by members of the organization.
|
||||
// author_association MEMBER is computed by GitHub and reflects org
|
||||
// membership (including concealed members); OWNER covers a repo owner.
|
||||
const allowedAssociations = ['OWNER', 'MEMBER'];
|
||||
if (!allowedAssociations.includes(pr.author_association)) {
|
||||
core.info(`Author association ${pr.author_association} is not an org member; skipping.`);
|
||||
return;
|
||||
}
|
||||
if (pr.state !== 'open') {
|
||||
core.info('Pull request is not open; skipping.');
|
||||
return;
|
||||
}
|
||||
if (pr.head.sha !== run.head_sha) {
|
||||
core.info('Run is for an outdated commit; skipping.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Require at least one per-arch firmware artifact from gather-artifacts
|
||||
const artifacts = await github.paginate(github.rest.actions.listWorkflowRunArtifacts, {
|
||||
owner, repo, run_id: run.id, per_page: 100,
|
||||
});
|
||||
const archRe = /^firmware-(esp32|esp32s3|esp32c3|esp32c6|nrf52840|rp2040|rp2350|stm32)-(\d+\.\d+\.\d+\.[0-9a-f]+)$/;
|
||||
const archArtifacts = artifacts.filter((a) => archRe.test(a.name) && !a.expired);
|
||||
if (archArtifacts.length === 0) {
|
||||
core.info('No per-arch firmware artifacts found; skipping.');
|
||||
return;
|
||||
}
|
||||
|
||||
const version = archRe.exec(archArtifacts[0].name)[2];
|
||||
const expiresAt = archArtifacts[0].expires_at
|
||||
? new Date(archArtifacts[0].expires_at).toISOString().slice(0, 10)
|
||||
: null;
|
||||
|
||||
// Read each built board's manifest (.mt.json). activelySupported,
|
||||
// displayName and architecture come straight from the board's
|
||||
// custom_meshtastic_* platformio config, so the list is in sync with
|
||||
// the firmware itself — no external device database needed.
|
||||
const fs = require('fs');
|
||||
let boards = [];
|
||||
try {
|
||||
boards = fs.readdirSync('./manifests')
|
||||
.filter((f) => f.endsWith('.mt.json'))
|
||||
.map((f) => {
|
||||
try { return JSON.parse(fs.readFileSync(`./manifests/${f}`, 'utf8')); }
|
||||
catch { return null; }
|
||||
})
|
||||
.filter((m) => m && m.activelySupported === true && m.platformioTarget)
|
||||
.map((m) => ({
|
||||
board: m.platformioTarget,
|
||||
platform: m.architecture || '',
|
||||
// displayName is maintainer-authored text; escape table-breaking pipes
|
||||
displayName: String(m.displayName || m.platformioTarget).replace(/\|/g, '\\|'),
|
||||
image: Array.isArray(m.images) && m.images[0] ? String(m.images[0]) : '',
|
||||
}))
|
||||
.sort((a, b) => a.board.localeCompare(b.board));
|
||||
} catch (e) {
|
||||
core.warning(`Could not read board manifests: ${e.message}`);
|
||||
}
|
||||
|
||||
const flasherUrl = `https://flasher.meshtastic.org/?pr=${prNumber}`;
|
||||
// Device illustrations are served by the flasher from the same image
|
||||
// names the manifest declares (custom_meshtastic_images). The flasher
|
||||
// serves its SPA shell (HTML, 200) for unknown paths, so confirm each
|
||||
// image really resolves to an image before linking it.
|
||||
const imageBase = 'https://flasher.meshtastic.org/img/devices/';
|
||||
await Promise.all(boards.map(async (b) => {
|
||||
if (!b.image) return;
|
||||
try {
|
||||
const res = await fetch(`${imageBase}${encodeURIComponent(b.image)}`);
|
||||
const type = res.headers.get('content-type') || '';
|
||||
if (!res.ok || !type.startsWith('image/')) b.image = '';
|
||||
} catch { b.image = ''; }
|
||||
}));
|
||||
|
||||
const boardLines = boards
|
||||
.map((b) => {
|
||||
const img = b.image ? `<img src="${imageBase}${encodeURIComponent(b.image)}" alt="" height="34">` : '';
|
||||
return `| ${img} | ${b.displayName} | [\`${b.board}\`](${flasherUrl}&device=${encodeURIComponent(b.board)}) | ${b.platform} |`;
|
||||
})
|
||||
.join('\n');
|
||||
|
||||
// Shields.io badges. Only non-user-controlled, charset-constrained values
|
||||
// (version, commit sha, counts, dates) go into badge URLs — never board
|
||||
// names or the PR title — so the rendered comment cannot be spoofed.
|
||||
const shieldText = (s) =>
|
||||
encodeURIComponent(String(s).replace(/-/g, '--').replace(/_/g, '__').replace(/ /g, '_'));
|
||||
const shield = (label, message, color) =>
|
||||
`https://img.shields.io/badge/${shieldText(label)}-${shieldText(message)}-${color}`;
|
||||
const buttonUrl =
|
||||
`https://img.shields.io/badge/${shieldText('Flash this PR in the Web Flasher')}-2C2D3C?style=for-the-badge`;
|
||||
const badges = [
|
||||
`})`,
|
||||
`, '2C2D3C')})`,
|
||||
`})`,
|
||||
];
|
||||
if (expiresAt) badges.push(`})`);
|
||||
|
||||
// Only render the board table when there are supported boards to list
|
||||
const boardTable = boards.length > 0 ? [
|
||||
`<details><summary>Supported boards built by this PR (${boards.length})</summary>`,
|
||||
'',
|
||||
'| | Device | Board | Platform |',
|
||||
'| --- | --- | --- | --- |',
|
||||
boardLines,
|
||||
'',
|
||||
'</details>',
|
||||
'',
|
||||
] : [];
|
||||
|
||||
const body = [
|
||||
marker,
|
||||
'## ⚡ Try this PR in the Web Flasher',
|
||||
'',
|
||||
`[](${flasherUrl})`,
|
||||
'',
|
||||
badges.join(' '),
|
||||
'',
|
||||
'> [!WARNING]',
|
||||
'> This is an automated, unreviewed CI test build. Back up your device configuration',
|
||||
'> before flashing, and only flash devices you are able to recover.',
|
||||
'',
|
||||
...boardTable,
|
||||
`*Build artifacts expire${expiresAt ? ` on ${expiresAt}` : ' after 30 days'}. Updated for \`${run.head_sha.slice(0, 7)}\`.*`,
|
||||
].join('\n');
|
||||
|
||||
// Sticky comment: update in place when the marker is found
|
||||
const comments = await github.paginate(github.rest.issues.listComments, {
|
||||
owner, repo, issue_number: prNumber, per_page: 100,
|
||||
});
|
||||
const existing = comments.find((c) => c.body?.includes(marker));
|
||||
if (existing) {
|
||||
await github.rest.issues.updateComment({ owner, repo, comment_id: existing.id, body });
|
||||
} else {
|
||||
await github.rest.issues.createComment({ owner, repo, issue_number: prNumber, body });
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
name: Post Web Flasher Build Placeholder
|
||||
|
||||
# Drops an immediate "build in progress" comment when a PR opens, so the web
|
||||
# flasher entry shows up right away. The real CI-driven workflow
|
||||
# (flasher-link-comment.yml) later replaces it in place via the shared marker.
|
||||
#
|
||||
# SECURITY: this uses pull_request_target (write token, runs for fork PRs) but is
|
||||
# safe because it never checks out or runs PR code and posts a fully static body
|
||||
# — no PR title, branch name, or other untrusted input is used anywhere.
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [opened, reopened]
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
post-placeholder:
|
||||
if: github.repository == 'meshtastic/firmware'
|
||||
continue-on-error: true
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Post web flasher build-in-progress placeholder
|
||||
uses: actions/github-script@v9
|
||||
with:
|
||||
script: |
|
||||
const marker = '<!-- web-flasher-link -->';
|
||||
const { owner, repo } = context.repo;
|
||||
const pr = context.payload.pull_request;
|
||||
|
||||
// Only org members get the flasher comment (matches the real workflow)
|
||||
const allowedAssociations = ['OWNER', 'MEMBER'];
|
||||
if (!allowedAssociations.includes(pr.author_association)) {
|
||||
core.info(`Author association ${pr.author_association} is not an org member; skipping.`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Only seed a placeholder when no flasher comment exists yet — never
|
||||
// overwrite a real (or existing placeholder) comment.
|
||||
const comments = await github.paginate(github.rest.issues.listComments, {
|
||||
owner, repo, issue_number: pr.number, per_page: 100,
|
||||
});
|
||||
if (comments.some((c) => c.body?.includes(marker))) {
|
||||
core.info('Flasher comment already exists; nothing to do.');
|
||||
return;
|
||||
}
|
||||
|
||||
const body = [
|
||||
marker,
|
||||
'## ⚡ Try this PR in the Web Flasher',
|
||||
'',
|
||||
'> [!NOTE]',
|
||||
'> Building this pull request… the flash button, badges and supported-board',
|
||||
'> list will appear here automatically once CI finishes.',
|
||||
].join('\n');
|
||||
|
||||
await github.rest.issues.createComment({
|
||||
owner, repo, issue_number: pr.number, body,
|
||||
});
|
||||
@@ -18,7 +18,7 @@ jobs:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ jobs:
|
||||
- check
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: 3.x
|
||||
@@ -64,7 +64,7 @@ jobs:
|
||||
version:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
- name: Get release version string
|
||||
run: |
|
||||
echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
||||
@@ -86,7 +86,7 @@ jobs:
|
||||
runs-on: ${{ github.repository_owner == 'meshtastic' && 'arctastic' || 'ubuntu-latest' }}
|
||||
if: ${{ github.event_name != 'workflow_dispatch' && github.repository == 'meshtastic/firmware' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Check ${{ matrix.check.board }}
|
||||
@@ -189,7 +189,7 @@ jobs:
|
||||
needs: [version, build]
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- uses: actions/download-artifact@v8
|
||||
with:
|
||||
@@ -245,6 +245,48 @@ jobs:
|
||||
path: ./*.elf
|
||||
retention-days: 30
|
||||
|
||||
shame:
|
||||
if: github.repository == 'meshtastic/firmware'
|
||||
continue-on-error: true
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build]
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
if: github.event_name == 'pull_request'
|
||||
with:
|
||||
filter: blob:none # means we download all the git history but none of the commit (except ones with checkout like the head)
|
||||
fetch-depth: 0
|
||||
- name: Download the current manifests
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
path: ./manifests-new/
|
||||
pattern: manifest-*
|
||||
merge-multiple: true
|
||||
- name: Upload combined manifests for later commit and global stats crunching.
|
||||
uses: actions/upload-artifact@v7
|
||||
id: upload-manifest
|
||||
with:
|
||||
name: manifests-${{ github.sha }}
|
||||
overwrite: true
|
||||
path: manifests-new/*.mt.json
|
||||
- name: Find the merge base
|
||||
if: github.event_name == 'pull_request'
|
||||
run: echo "MERGE_BASE=$(git merge-base "origin/$base" "$head")" >> $GITHUB_ENV
|
||||
env:
|
||||
base: ${{ github.base_ref }}
|
||||
head: ${{ github.sha }}
|
||||
# Currently broken (for-loop through EVERY artifact -- rate limiting)
|
||||
# - name: Download the old manifests
|
||||
# if: github.event_name == 'pull_request'
|
||||
# run: gh run download -R "$repo" --name "manifests-$merge_base" --dir manifest-old/
|
||||
# env:
|
||||
# GH_TOKEN: ${{ github.token }}
|
||||
# merge_base: ${{ env.MERGE_BASE }}
|
||||
# repo: ${{ github.repository }}
|
||||
# - name: Do scan and post comment
|
||||
# if: github.event_name == 'pull_request'
|
||||
# run: python3 bin/shame.py ${{ github.event.pull_request.number }} manifests-old/ manifests-new/
|
||||
|
||||
release-artifacts:
|
||||
permissions: # Needed for 'gh release upload'.
|
||||
contents: write
|
||||
@@ -261,7 +303,7 @@ jobs:
|
||||
# - MacOS
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
@@ -362,7 +404,7 @@ jobs:
|
||||
needs: [release-artifacts, version]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v6
|
||||
@@ -417,7 +459,7 @@ jobs:
|
||||
esp32,esp32s3,esp32c3,esp32c6,nrf52840,rp2040,rp2350,stm32
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Trunk Check
|
||||
uses: trunk-io/trunk-action@v1.3.1
|
||||
@@ -31,7 +31,7 @@ jobs:
|
||||
pull-requests: write # For trunk to create PRs
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Trunk Upgrade
|
||||
uses: trunk-io/trunk-action/upgrade@v1.3.1
|
||||
|
||||
@@ -33,7 +33,7 @@ jobs:
|
||||
needs: build-debian-src
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
path: meshtasticd
|
||||
|
||||
@@ -23,7 +23,7 @@ jobs:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ jobs:
|
||||
needs: build-debian-src
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
path: meshtasticd
|
||||
|
||||
@@ -40,7 +40,7 @@ jobs:
|
||||
checks: write
|
||||
pull-requests: write
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ jobs:
|
||||
shell: bash
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
# Always use master branch for version bumps
|
||||
ref: master
|
||||
|
||||
@@ -21,7 +21,7 @@ jobs:
|
||||
steps:
|
||||
# step 1
|
||||
- name: clone application source code
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
|
||||
# step 2
|
||||
- name: full scan
|
||||
|
||||
@@ -13,7 +13,7 @@ jobs:
|
||||
steps:
|
||||
# step 1
|
||||
- name: clone application source code
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ jobs:
|
||||
name: Native Simulator Tests
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
@@ -68,7 +68,7 @@ jobs:
|
||||
name: Native PlatformIO Tests
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
@@ -123,7 +123,7 @@ jobs:
|
||||
- platformio-tests
|
||||
if: always()
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Get release version string
|
||||
run: echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
||||
|
||||
@@ -20,7 +20,7 @@ jobs:
|
||||
runs-on: test-runner
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
|
||||
# - uses: actions/setup-python@v6
|
||||
# with:
|
||||
|
||||
@@ -18,7 +18,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Trunk Check
|
||||
uses: trunk-io/trunk-action@v1.3.1
|
||||
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Trunk Check
|
||||
uses: trunk-io/trunk-action@v1.3.1
|
||||
|
||||
@@ -11,23 +11,18 @@ jobs:
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Update submodule
|
||||
if: ${{ github.ref_name == 'master' || github.ref_name == 'develop' }}
|
||||
working-directory: protobufs
|
||||
env:
|
||||
# Use the branch that triggered the workflow as the protobuf branch.
|
||||
GIT_BRANCH: ${{ github.ref_name }}
|
||||
if: ${{ github.ref == 'refs/heads/master' || github.ref == 'refs/heads/develop' }}
|
||||
run: |
|
||||
git fetch --prune origin $GIT_BRANCH
|
||||
git checkout origin/$GIT_BRANCH
|
||||
git submodule update --remote protobufs
|
||||
|
||||
- name: Download nanopb
|
||||
run: |
|
||||
wget https://github.com/nanopb/nanopb/releases/download/nanopb-0.4.9.1/nanopb-0.4.9.1-linux-x86.tar.gz
|
||||
wget https://jpa.kapsi.fi/nanopb/download/nanopb-0.4.9.1-linux-x86.tar.gz
|
||||
tar xvzf nanopb-0.4.9.1-linux-x86.tar.gz
|
||||
mv nanopb-0.4.9.1-linux-x86 nanopb-0.4.9
|
||||
|
||||
@@ -38,7 +33,7 @@ jobs:
|
||||
- name: Create pull request
|
||||
uses: peter-evans/create-pull-request@v8
|
||||
with:
|
||||
branch: create-pull-request/update-protobufs-${{ github.ref_name }}
|
||||
branch: create-pull-request/update-protobufs
|
||||
labels: submodules
|
||||
title: Update protobufs and classes
|
||||
commit-message: Update protobufs
|
||||
|
||||
+8
-8
@@ -4,21 +4,21 @@ cli:
|
||||
plugins:
|
||||
sources:
|
||||
- id: trunk
|
||||
ref: v1.10.2
|
||||
ref: v1.10.0
|
||||
uri: https://github.com/trunk-io/plugins
|
||||
lint:
|
||||
enabled:
|
||||
- checkov@3.3.1
|
||||
- renovate@43.236.0
|
||||
- prettier@3.8.4
|
||||
- trufflehog@3.95.6
|
||||
- checkov@3.2.532
|
||||
- renovate@43.209.1
|
||||
- prettier@3.8.3
|
||||
- trufflehog@3.95.5
|
||||
- yamllint@1.38.0
|
||||
- bandit@1.9.4
|
||||
- trivy@0.71.2
|
||||
- trivy@0.71.0
|
||||
- taplo@0.10.0
|
||||
- ruff@0.15.18
|
||||
- ruff@0.15.15
|
||||
- isort@8.0.1
|
||||
- markdownlint@0.49.0
|
||||
- markdownlint@0.48.0
|
||||
- oxipng@10.1.1
|
||||
- svgo@4.0.1
|
||||
- actionlint@1.7.12
|
||||
|
||||
+2
-2
@@ -4,7 +4,7 @@
|
||||
# trunk-ignore-all(hadolint/DL3013): Do not pin pip package versions
|
||||
|
||||
# Ensure the Alpine version is updated in both stages of the container!
|
||||
FROM alpine:3.24 AS builder
|
||||
FROM alpine:3.23 AS builder
|
||||
ARG PIO_ENV=native
|
||||
|
||||
# Enable Alpine community repository (for 'py3-grpcio-tools')
|
||||
@@ -35,7 +35,7 @@ RUN bash ./bin/build-native.sh "$PIO_ENV" && \
|
||||
|
||||
# ##### PRODUCTION BUILD #############
|
||||
|
||||
FROM alpine:3.24
|
||||
FROM alpine:3.23
|
||||
LABEL org.opencontainers.image.title="Meshtastic" \
|
||||
org.opencontainers.image.description="Alpine Meshtastic daemon" \
|
||||
org.opencontainers.image.url="https://meshtastic.org" \
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
# https://github.com/wehooper4/Meshtastic-Hardware/tree/main/NebraHat
|
||||
# Use for 1 watt hat
|
||||
Meta:
|
||||
name: NebraHat 1W
|
||||
support: community
|
||||
compatible:
|
||||
- raspberry-pi
|
||||
|
||||
Lora:
|
||||
Module: sx1262 # Nebra SX1262 Pi Hat - 1W
|
||||
DIO2_AS_RF_SWITCH: true
|
||||
DIO3_TCXO_VOLTAGE: true
|
||||
# CS: 8 # Newer version of MeshtasticD do not need this? If issues uncomment this line
|
||||
IRQ: 22
|
||||
Busy: 4
|
||||
Reset: 18
|
||||
RXen: 25
|
||||
I2C:
|
||||
I2CDevice: /dev/i2c-1
|
||||
@@ -1,20 +0,0 @@
|
||||
# https://github.com/wehooper4/Meshtastic-Hardware/tree/main/NebraHat
|
||||
# Use for 2 watt hat
|
||||
Meta:
|
||||
name: NebraHat 2W
|
||||
support: community
|
||||
compatible:
|
||||
- raspberry-pi
|
||||
|
||||
Lora:
|
||||
Module: sx1262 # Nebra SX1262 Pi Hat - 2W
|
||||
DIO2_AS_RF_SWITCH: true
|
||||
DIO3_TCXO_VOLTAGE: true
|
||||
SX126X_MAX_POWER: 8
|
||||
# CS: 8 # Newer version of MeshtasticD do not need this? If issues uncomment this line
|
||||
IRQ: 22
|
||||
Busy: 4
|
||||
Reset: 18
|
||||
RXen: 25
|
||||
I2C:
|
||||
I2CDevice: /dev/i2c-1
|
||||
@@ -18,4 +18,4 @@ Lora:
|
||||
DIO3_TCXO_VOLTAGE: true
|
||||
DIO2_AS_RF_SWITCH: true
|
||||
spidev: spidev0.0
|
||||
# CS: 8
|
||||
# CS: 8
|
||||
@@ -18,4 +18,4 @@ Lora:
|
||||
DIO3_TCXO_VOLTAGE: true
|
||||
DIO2_AS_RF_SWITCH: true
|
||||
spidev: spidev0.1
|
||||
# CS: 7
|
||||
# CS: 7
|
||||
@@ -1,19 +0,0 @@
|
||||
# https://github.com/wehooper4/Meshtastic-Hardware/tree/main/ZebraHAT
|
||||
# Use for 1 watt hat
|
||||
Meta:
|
||||
name: ZebraHat 1W
|
||||
support: community
|
||||
compatible:
|
||||
- raspberry-pi
|
||||
|
||||
Lora:
|
||||
Module: sx1262 # Zebra SX1262 Pi Hat - 1W
|
||||
DIO2_AS_RF_SWITCH: true
|
||||
DIO3_TCXO_VOLTAGE: true
|
||||
SX126X_MAX_POWER: 18
|
||||
CS: 24
|
||||
IRQ: 22
|
||||
Busy: 27
|
||||
Reset: 17
|
||||
I2C:
|
||||
I2CDevice: /dev/i2c-1
|
||||
@@ -1,20 +0,0 @@
|
||||
# https://github.com/wehooper4/Meshtastic-Hardware/tree/main/ZebraHAT
|
||||
# Use for 2 watt hat
|
||||
Meta:
|
||||
name: ZebraHat 2W
|
||||
support: community
|
||||
compatible:
|
||||
- raspberry-pi
|
||||
|
||||
Lora:
|
||||
Module: sx1262 # Zebra SX1262 Pi Hat - 2W
|
||||
DIO2_AS_RF_SWITCH: true
|
||||
DIO3_TCXO_VOLTAGE: true
|
||||
SX126X_MAX_POWER: 8
|
||||
CS: 24
|
||||
IRQ: 22
|
||||
Busy: 27
|
||||
Reset: 17
|
||||
RXen: 25
|
||||
I2C:
|
||||
I2CDevice: /dev/i2c-1
|
||||
@@ -29,8 +29,6 @@ Lora:
|
||||
- pin: 50 # GPIO1_C2 (physical 16)
|
||||
gpiochip: 1
|
||||
line: 18
|
||||
DIO3_TCXO_VOLTAGE: true
|
||||
DIO2_AS_RF_SWITCH: true
|
||||
spidev: spidev0.1
|
||||
# CS: # GPIO0_A7 (SPI1_CSN1, physical 26)
|
||||
# pin: 7
|
||||
|
||||
@@ -29,8 +29,6 @@ Lora:
|
||||
- pin: 50 # GPIO1_C2 (physical 16)
|
||||
gpiochip: 1
|
||||
line: 18
|
||||
DIO3_TCXO_VOLTAGE: true
|
||||
DIO2_AS_RF_SWITCH: true
|
||||
spidev: spidev0.1
|
||||
# CS: # GPIO0_A7 (SPI1_CSN1, physical 26)
|
||||
# pin: 7
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
# Station G3 + BQ35LORA900V1M Primary Slot
|
||||
# Board Doc: https://wiki.bqvoy.com/en/devkits/station-g3
|
||||
Meta:
|
||||
name: B&Q Station G3 + BQ35LORA900V1M Primary Slot
|
||||
support: official
|
||||
compatible:
|
||||
- luckfox-lyra-zero-w # Armbian
|
||||
|
||||
Lora:
|
||||
Module: sx1262
|
||||
IRQ: # GPIO0_A5 (physical 15)
|
||||
pin: 5
|
||||
gpiochip: 0
|
||||
line: 5
|
||||
Reset: # GPIO1_D1 (physical 36)
|
||||
pin: 57
|
||||
gpiochip: 1
|
||||
line: 25
|
||||
Busy: # GPIO0_B4 (physical 18)
|
||||
pin: 12
|
||||
gpiochip: 0
|
||||
line: 12
|
||||
DIO3_TCXO_VOLTAGE: true
|
||||
DIO2_AS_RF_SWITCH: true
|
||||
spidev: spidev0.0
|
||||
# CS: # GPIO0_B2 (physical 24)
|
||||
# pin: 10
|
||||
# gpiochip: 0
|
||||
# line: 10
|
||||
@@ -29,8 +29,6 @@ Lora:
|
||||
- pin: 13 # GPIO0_B5
|
||||
gpiochip: 0
|
||||
line: 13
|
||||
DIO3_TCXO_VOLTAGE: true
|
||||
DIO2_AS_RF_SWITCH: true
|
||||
spidev: spidev0.1
|
||||
# CS: # GPIO0_B1
|
||||
# pin: 9
|
||||
|
||||
@@ -29,8 +29,6 @@ Lora:
|
||||
- pin: 13 # GPIO0_B5
|
||||
gpiochip: 0
|
||||
line: 13
|
||||
DIO3_TCXO_VOLTAGE: true
|
||||
DIO2_AS_RF_SWITCH: true
|
||||
spidev: spidev0.1
|
||||
# CS: # GPIO0_B1
|
||||
# pin: 9
|
||||
|
||||
@@ -31,8 +31,6 @@ Lora:
|
||||
- pin: 103 # GPIO3_A7 (physical 16)
|
||||
gpiochip: 3
|
||||
line: 7
|
||||
DIO3_TCXO_VOLTAGE: true
|
||||
DIO2_AS_RF_SWITCH: true
|
||||
spidev: spidev0.1
|
||||
# CS: # GPIO0_B7 (SPI0_CSN1, physical 26)
|
||||
# pin: 15
|
||||
|
||||
@@ -31,8 +31,6 @@ Lora:
|
||||
- pin: 103 # GPIO3_A7 (physical 16)
|
||||
gpiochip: 3
|
||||
line: 7
|
||||
DIO3_TCXO_VOLTAGE: true
|
||||
DIO2_AS_RF_SWITCH: true
|
||||
spidev: spidev0.1
|
||||
# CS: # GPIO0_B7 (SPI0_CSN1, physical 26)
|
||||
# pin: 15
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
# Station G3 + BQ35LORA900V1M Primary Slot
|
||||
# Board Doc: https://wiki.bqvoy.com/en/devkits/station-g3
|
||||
Meta:
|
||||
name: B&Q Station G3 + BQ35LORA900V1M Primary Slot
|
||||
support: official
|
||||
compatible:
|
||||
- raspberry-pi
|
||||
|
||||
Lora:
|
||||
Module: sx1262
|
||||
IRQ: 22
|
||||
Reset: 16
|
||||
Busy: 24
|
||||
DIO3_TCXO_VOLTAGE: true
|
||||
DIO2_AS_RF_SWITCH: true
|
||||
spidev: spidev0.0
|
||||
#CS: 8
|
||||
@@ -1,5 +1,3 @@
|
||||
# This config works with all revisions of the Meshtoad USB radio.
|
||||
|
||||
Meta:
|
||||
name: meshtoad-e22
|
||||
support: official
|
||||
|
||||
@@ -87,12 +87,6 @@
|
||||
</screenshots>
|
||||
|
||||
<releases>
|
||||
<release version="2.7.27" date="2026-06-24">
|
||||
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.27</url>
|
||||
</release>
|
||||
<release version="2.7.26" date="2026-06-10">
|
||||
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.26</url>
|
||||
</release>
|
||||
<release version="2.7.25" date="2026-05-23">
|
||||
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.25</url>
|
||||
</release>
|
||||
|
||||
Vendored
-12
@@ -1,15 +1,3 @@
|
||||
meshtasticd (2.7.27.0) unstable; urgency=medium
|
||||
|
||||
* Version 2.7.27
|
||||
|
||||
-- GitHub Actions <github-actions[bot]@users.noreply.github.com> Wed, 24 Jun 2026 11:20:05 +0000
|
||||
|
||||
meshtasticd (2.7.26.0) unstable; urgency=medium
|
||||
|
||||
* Version 2.7.26
|
||||
|
||||
-- GitHub Actions <github-actions[bot]@users.noreply.github.com> Wed, 10 Jun 2026 00:19:23 +0000
|
||||
|
||||
meshtasticd (2.7.25.0) unstable; urgency=medium
|
||||
|
||||
* Version 2.7.25
|
||||
|
||||
+4
-4
@@ -126,7 +126,7 @@ lib_deps =
|
||||
[device-ui_base]
|
||||
lib_deps =
|
||||
# renovate: datasource=git-refs depName=meshtastic/device-ui packageName=https://github.com/meshtastic/device-ui gitBranch=master
|
||||
https://github.com/meshtastic/device-ui/archive/1c45ebc7433acb8ba3fe96a6f7deca9c43fa54cf.zip
|
||||
https://github.com/meshtastic/device-ui/archive/502ba30dbccc6a323f1d4f7ca961131c27f60672.zip
|
||||
|
||||
; Common libs for environmental measurements in telemetry module
|
||||
[environmental_base]
|
||||
@@ -199,8 +199,6 @@ lib_deps =
|
||||
https://github.com/adafruit/Adafruit_TSL2561/archive/refs/tags/1.1.3.zip
|
||||
# renovate: datasource=github-tags depName=BH1750_WE packageName=wollewald/BH1750_WE
|
||||
https://github.com/wollewald/BH1750_WE/archive/refs/tags/1.1.10.zip
|
||||
# renovate: datasource=github-tags depName=Adafruit SHTC3 packageName=adafruit/Adafruit_SHTC3
|
||||
https://github.com/adafruit/Adafruit_SHTC3/archive/refs/tags/1.0.2.zip
|
||||
|
||||
; Common environmental sensor libraries (not included in native / portduino)
|
||||
[environmental_extra_common]
|
||||
@@ -209,6 +207,8 @@ lib_deps =
|
||||
https://github.com/adafruit/Adafruit_BMP3XX/archive/refs/tags/2.1.6.zip
|
||||
# renovate: datasource=github-tags depName=Adafruit MAX1704X packageName=adafruit/Adafruit_MAX1704X
|
||||
https://github.com/adafruit/Adafruit_MAX1704X/archive/refs/tags/1.0.3.zip
|
||||
# renovate: datasource=github-tags depName=Adafruit SHTC3 packageName=adafruit/Adafruit_SHTC3
|
||||
https://github.com/adafruit/Adafruit_SHTC3/archive/refs/tags/1.0.2.zip
|
||||
# renovate: datasource=github-tags depName=Adafruit LPS2X packageName=adafruit/Adafruit_LPS2X
|
||||
https://github.com/adafruit/Adafruit_LPS2X/archive/refs/tags/2.0.6.zip
|
||||
# renovate: datasource=github-tags depName=Adafruit SHT31 packageName=adafruit/Adafruit_SHT31
|
||||
@@ -230,7 +230,7 @@ lib_deps =
|
||||
# renovate: datasource=github-tags depName=Sensirion I2C SFA3x packageName=sensirion/arduino-i2c-sfa3x
|
||||
https://github.com/Sensirion/arduino-i2c-sfa3x/archive/refs/tags/1.0.0.zip
|
||||
# renovate: datasource=github-tags depName=Sensirion I2C SCD30 packageName=sensirion/arduino-i2c-scd30
|
||||
https://github.com/Sensirion/arduino-i2c-scd30/archive/1.1.1.zip
|
||||
https://github.com/Sensirion/arduino-i2c-scd30/archive/refs/tags/1.0.0.zip
|
||||
|
||||
; Environmental sensors with BSEC2 (Bosch proprietary IAQ)
|
||||
[environmental_extra]
|
||||
|
||||
+1
-1
Submodule protobufs updated: 6b1ded4396...59cb394dcf
+27
-101
@@ -99,87 +99,48 @@ bool renameFile(const char *pathFrom, const char *pathTo)
|
||||
#endif
|
||||
}
|
||||
|
||||
#include <cstring>
|
||||
#include <new>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* @brief Get the list of files in a directory.
|
||||
*
|
||||
* This function returns a list of files in a directory. The list includes the full path of each file.
|
||||
* We can't use SPILOCK here because of recursion. Callers of this function should use SPILOCK.
|
||||
*
|
||||
* @param dirname The name of the directory.
|
||||
* @param levels The number of levels of subdirectories to list.
|
||||
* @return A vector of strings containing the full path of each file in the directory.
|
||||
*/
|
||||
std::vector<meshtastic_FileInfo> getFiles(const char *dirname, uint8_t levels)
|
||||
{
|
||||
std::vector<meshtastic_FileInfo> filenames = {};
|
||||
#ifdef FSCom
|
||||
namespace
|
||||
{
|
||||
bool pathEndsWithDot(const char *path)
|
||||
{
|
||||
if (!path)
|
||||
return false;
|
||||
|
||||
size_t length = strlen(path);
|
||||
return length > 0 && path[length - 1] == '.';
|
||||
}
|
||||
|
||||
bool copyFilePath(char *dest, size_t destSize, const char *path, bool *wasLimited)
|
||||
{
|
||||
if (!path || destSize == 0) {
|
||||
if (wasLimited)
|
||||
*wasLimited = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strlcpy(dest, path, destSize) >= destSize) {
|
||||
if (wasLimited)
|
||||
*wasLimited = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void collectFiles(const char *dirname, uint8_t levels, size_t maxCount, std::vector<meshtastic_FileInfo> &filenames,
|
||||
bool *wasLimited)
|
||||
{
|
||||
if (!dirname)
|
||||
return;
|
||||
|
||||
File root = FSCom.open(dirname, FILE_O_READ);
|
||||
if (!root)
|
||||
return;
|
||||
if (!root.isDirectory()) {
|
||||
root.close();
|
||||
return;
|
||||
}
|
||||
return filenames;
|
||||
if (!root.isDirectory())
|
||||
return filenames;
|
||||
|
||||
File file = root.openNextFile();
|
||||
// file.name()[0] check is a workaround for a bug in the Adafruit LittleFS nrf52 glue (see issue 4395)
|
||||
while (file && file.name()[0]) {
|
||||
if (filenames.size() >= maxCount) {
|
||||
if (wasLimited)
|
||||
*wasLimited = true;
|
||||
file.close();
|
||||
break;
|
||||
}
|
||||
const char *fileName = file.name();
|
||||
if (file.isDirectory() && !pathEndsWithDot(fileName)) {
|
||||
char pathBuffer[sizeof(((meshtastic_FileInfo *)nullptr)->file_name)] = {};
|
||||
while (file) {
|
||||
if (file.isDirectory() && !String(file.name()).endsWith(".")) {
|
||||
if (levels) {
|
||||
#ifdef ARCH_ESP32
|
||||
const char *subDirPath = file.path();
|
||||
std::vector<meshtastic_FileInfo> subDirFilenames = getFiles(file.path(), levels - 1);
|
||||
#else
|
||||
const char *subDirPath = fileName;
|
||||
std::vector<meshtastic_FileInfo> subDirFilenames = getFiles(file.name(), levels - 1);
|
||||
#endif
|
||||
bool hasSubDirPath = copyFilePath(pathBuffer, sizeof(pathBuffer), subDirPath, wasLimited);
|
||||
file.close();
|
||||
|
||||
if (levels && hasSubDirPath) {
|
||||
collectFiles(pathBuffer, levels - 1, maxCount, filenames, wasLimited);
|
||||
} else if (wasLimited) {
|
||||
*wasLimited = true;
|
||||
filenames.insert(filenames.end(), subDirFilenames.begin(), subDirFilenames.end());
|
||||
file.close();
|
||||
}
|
||||
} else {
|
||||
meshtastic_FileInfo fileInfo = {"", static_cast<uint32_t>(file.size())};
|
||||
#ifdef ARCH_ESP32
|
||||
bool hasFilePath = copyFilePath(fileInfo.file_name, sizeof(fileInfo.file_name), file.path(), wasLimited);
|
||||
strcpy(fileInfo.file_name, file.path());
|
||||
#else
|
||||
bool hasFilePath = copyFilePath(fileInfo.file_name, sizeof(fileInfo.file_name), file.name(), wasLimited);
|
||||
strcpy(fileInfo.file_name, file.name());
|
||||
#endif
|
||||
if (hasFilePath && !pathEndsWithDot(fileInfo.file_name)) {
|
||||
if (!String(fileInfo.file_name).endsWith(".")) {
|
||||
filenames.push_back(fileInfo);
|
||||
}
|
||||
file.close();
|
||||
@@ -187,41 +148,6 @@ void collectFiles(const char *dirname, uint8_t levels, size_t maxCount, std::vec
|
||||
file = root.openNextFile();
|
||||
}
|
||||
root.close();
|
||||
}
|
||||
} // namespace
|
||||
#endif
|
||||
|
||||
// Callers must hold the SPI lock; recursion prevents taking it here.
|
||||
std::vector<meshtastic_FileInfo> getFiles(const char *dirname, uint8_t levels, size_t maxCount, bool *wasLimited)
|
||||
{
|
||||
std::vector<meshtastic_FileInfo> filenames = {};
|
||||
if (wasLimited)
|
||||
*wasLimited = false;
|
||||
#ifdef FSCom
|
||||
#if defined(__cpp_exceptions) || defined(__EXCEPTIONS)
|
||||
size_t reservedCount = maxCount;
|
||||
while (reservedCount > 0) {
|
||||
try {
|
||||
filenames.reserve(reservedCount);
|
||||
break;
|
||||
} catch (const std::bad_alloc &) {
|
||||
reservedCount /= 2;
|
||||
} catch (const std::length_error &) {
|
||||
reservedCount /= 2;
|
||||
}
|
||||
}
|
||||
if (reservedCount == 0) {
|
||||
if (wasLimited)
|
||||
*wasLimited = true;
|
||||
return filenames;
|
||||
}
|
||||
if (reservedCount < maxCount) {
|
||||
if (wasLimited)
|
||||
*wasLimited = true;
|
||||
maxCount = reservedCount;
|
||||
}
|
||||
#endif
|
||||
collectFiles(dirname, levels, maxCount, filenames, wasLimited);
|
||||
#endif
|
||||
return filenames;
|
||||
}
|
||||
@@ -409,4 +335,4 @@ void setupSDCard()
|
||||
LOG_DEBUG("Total space: %lu MB", (uint32_t)(SD.totalBytes() / (1024 * 1024)));
|
||||
LOG_DEBUG("Used space: %lu MB", (uint32_t)(SD.usedBytes() / (1024 * 1024)));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -52,7 +52,7 @@ void fsInit();
|
||||
void fsListFiles();
|
||||
bool copyFile(const char *from, const char *to);
|
||||
bool renameFile(const char *pathFrom, const char *pathTo);
|
||||
std::vector<meshtastic_FileInfo> getFiles(const char *dirname, uint8_t levels, size_t maxCount = 64, bool *wasLimited = nullptr);
|
||||
std::vector<meshtastic_FileInfo> getFiles(const char *dirname, uint8_t levels);
|
||||
void listDir(const char *dirname, uint8_t levels, bool del = false);
|
||||
void rmDir(const char *dirname);
|
||||
void setupSDCard();
|
||||
void setupSDCard();
|
||||
@@ -360,7 +360,6 @@ void MessageStore::clearAllMessages()
|
||||
resetMessagePool();
|
||||
|
||||
#ifdef FSCom
|
||||
concurrency::LockGuard guard(spiLock);
|
||||
SafeFile f(filename.c_str(), false);
|
||||
uint8_t count = 0;
|
||||
f.write(&count, 1); // write "0 messages"
|
||||
|
||||
+3
-5
@@ -832,10 +832,7 @@ void GPS::setPowerState(GPSPowerState newState, uint32_t sleepTime)
|
||||
switch (newState) {
|
||||
case GPS_ACTIVE:
|
||||
case GPS_IDLE:
|
||||
if (oldState == GPS_ACTIVE)
|
||||
break;
|
||||
gotTime = false;
|
||||
if (oldState == GPS_IDLE) // If hardware already awake, no changes needed
|
||||
if (oldState == GPS_ACTIVE || oldState == GPS_IDLE) // If hardware already awake, no changes needed
|
||||
break;
|
||||
if (oldState != GPS_ACTIVE && oldState != GPS_IDLE) // If hardware just waking now, clear buffer
|
||||
clearBuffer();
|
||||
@@ -1145,7 +1142,8 @@ int32_t GPS::runOnce()
|
||||
// if gps_update_interval is <=10s, GPS never goes off, so we treat that differently
|
||||
uint32_t updateInterval = Default::getConfiguredOrDefaultMs(config.position.gps_update_interval);
|
||||
|
||||
// 1. Got a time for the first time this cycle
|
||||
// 1. Got a time for the first time
|
||||
bool gotTime = (getRTCQuality() >= RTCQualityGPS);
|
||||
if (!gotTime && lookForTime()) { // Note: we count on this && short-circuiting and not resetting the RTC time
|
||||
gotTime = true;
|
||||
}
|
||||
|
||||
@@ -163,7 +163,6 @@ class GPS : private concurrency::OSThread
|
||||
uint32_t lastChecksumFailCount = 0;
|
||||
uint8_t currentStep = 0;
|
||||
int32_t currentDelay = 2000;
|
||||
bool gotTime = false;
|
||||
|
||||
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
|
||||
// (20210908) TinyGps++ can only read the GPGSA "FIX TYPE" field
|
||||
|
||||
+2
-2
@@ -262,8 +262,8 @@ RTCSetResult perhapsSetRTC(RTCQuality q, const struct timeval *tv, bool forceUpd
|
||||
} else if (q == RTCQualityGPS) {
|
||||
shouldSet = true;
|
||||
LOG_DEBUG("Reapply GPS time: %ld secs", printableEpoch);
|
||||
} else if (q == RTCQualityNTP && !Throttle::isWithinTimespanMs(lastSetMsec, (30 * 60 * 1000UL))) {
|
||||
// Every 30 minutes we will slam in a new NTP or Phone GPS / NTP time, to correct for local RTC clock drift
|
||||
} else if (q == RTCQualityNTP && !Throttle::isWithinTimespanMs(lastSetMsec, (12 * 60 * 60 * 1000UL))) {
|
||||
// Every 12 hrs we will slam in a new NTP or Phone GPS / NTP time, to correct for local RTC clock drift
|
||||
shouldSet = true;
|
||||
LOG_DEBUG("Reapply external time to correct clock drift %ld secs", printableEpoch);
|
||||
} else {
|
||||
|
||||
@@ -383,8 +383,10 @@ void InputBroker::Init()
|
||||
rotaryEncoderInterruptImpl1 = nullptr;
|
||||
}
|
||||
#endif
|
||||
#if !MESHTASTIC_EXCLUDE_I2C
|
||||
cardKbI2cImpl = new CardKbI2cImpl();
|
||||
cardKbI2cImpl->init();
|
||||
#endif
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
i2cButton = new i2cButtonThread("i2cButtonThread");
|
||||
#endif
|
||||
|
||||
+27
-5
@@ -221,6 +221,8 @@ bool pauseBluetoothLogging = false;
|
||||
|
||||
bool pmu_found;
|
||||
|
||||
uint8_t pa_fan_percentage = 50;
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_I2C
|
||||
// Array map of sensor types with i2c address and wire as we'll find in the i2c scan
|
||||
std::pair<uint8_t, TwoWire *> nodeTelemetrySensorsMap[_meshtastic_TelemetrySensorType_MAX + 1] = {};
|
||||
@@ -994,16 +996,36 @@ void setup()
|
||||
mqttInit();
|
||||
#endif
|
||||
|
||||
#ifdef RF95_FAN_EN
|
||||
// Ability to disable FAN if PIN has been set with RF95_FAN_EN.
|
||||
#ifdef RADIO_FAN_EN
|
||||
// Ability to disable FAN if PIN has been set with RADIO_FAN_EN.
|
||||
// Make sure LoRa has been started before disabling FAN.
|
||||
if (config.lora.pa_fan_disabled)
|
||||
digitalWrite(RF95_FAN_EN, LOW ^ 0);
|
||||
#ifdef RADIO_FAN_PWM
|
||||
#if defined(ARCH_ESP32)
|
||||
// Set up PWM at Channel 1 at 25KHz, using 8-bit resolution
|
||||
// Turn ON/OFF fan to the specified value if enabled by config.
|
||||
// code by https://github.com/gjelsoe/
|
||||
if (ledcSetup(1, 25000, 8)) {
|
||||
ledcAttachPin(RADIO_FAN_EN, 1);
|
||||
LOG_INFO("PWM init C1 P%d\n", RADIO_FAN_EN);
|
||||
// Set PWM duty cycle based on fan disabled state
|
||||
ledcWrite(1, config.lora.pa_fan_disabled ? 0 : (pa_fan_percentage * 2.55));
|
||||
} else {
|
||||
LOG_WARN("PWM init fail P%d\n", RADIO_FAN_EN);
|
||||
}
|
||||
#elif defined(ARCH_NRF52)
|
||||
pinMode(RADIO_FAN_EN, OUTPUT);
|
||||
analogWrite(RADIO_FAN_EN, config.lora.pa_fan_disabled ? 0 : (pa_fan_percentage * 2.55));
|
||||
#endif
|
||||
#else
|
||||
// Set up as ON/OFF switch of fan; default on unless disabled by config.
|
||||
pinMode(RADIO_FAN_EN, OUTPUT);
|
||||
digitalWrite(RADIO_FAN_EN, config.lora.pa_fan_disabled ? (LOW ^ 0) : (HIGH ^ 0));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef ARCH_PORTDUINO
|
||||
|
||||
// Initialize Wifi
|
||||
// Initialize Wifi
|
||||
#if HAS_WIFI
|
||||
initWifi();
|
||||
#endif
|
||||
|
||||
@@ -90,6 +90,8 @@ extern bool suppressRebootBanner;
|
||||
|
||||
extern uint32_t serialSinceMsec;
|
||||
|
||||
extern uint8_t pa_fan_percentage;
|
||||
|
||||
// If a thread does something that might need for it to be rescheduled ASAP it can set this flag
|
||||
// This will suppress the current delay and instead try to run ASAP.
|
||||
extern bool runASAP;
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
#if RADIOLIB_EXCLUDE_LR11X0 != 1
|
||||
#include "LR11x0Interface.h"
|
||||
#include "RadioExternalPa.h"
|
||||
#include "Throttle.h"
|
||||
#include "configuration.h"
|
||||
#include "error.h"
|
||||
#include "main.h"
|
||||
#include "mesh/NodeDB.h"
|
||||
#ifdef LR11X0_DIO_AS_RF_SWITCH
|
||||
#include "rfswitch.h"
|
||||
@@ -54,6 +56,8 @@ template <typename T> bool LR11x0Interface<T>::init()
|
||||
digitalWrite(LR11X0_POWER_EN, HIGH);
|
||||
#endif
|
||||
|
||||
enableFan();
|
||||
|
||||
#if ARCH_PORTDUINO
|
||||
float tcxoVoltage = (float)portduino_config.dio3_tcxo_voltage / 1000;
|
||||
// FIXME: correct logic to default to not using TCXO if no voltage is specified for LR11x0_DIO3_TCXO_VOLTAGE
|
||||
@@ -184,8 +188,10 @@ template <typename T> bool LR11x0Interface<T>::reconfigure()
|
||||
if (err != RADIOLIB_ERR_NONE)
|
||||
RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_INVALID_RADIO_SETTING);
|
||||
|
||||
if (power > LR1110_MAX_POWER) // This chip has lower power limits than some
|
||||
power = LR1110_MAX_POWER;
|
||||
// Re-apply regulatory limits and any external-PA power mapping. applyModemConfig()
|
||||
// (run by the base reconfigure()) reset `power` to the requested total, so without
|
||||
// this a runtime tx_power change would skip region clamping and external-PA mapping.
|
||||
limitPower(LR1110_MAX_POWER);
|
||||
if ((power > LR1120_MAX_POWER) && (config.lora.region == meshtastic_Config_LoRaConfig_RegionCode_LORA_24)) // 2.4G power limit
|
||||
power = LR1120_MAX_POWER;
|
||||
|
||||
@@ -236,6 +242,7 @@ template <typename T> void LR11x0Interface<T>::addReceiveMetadata(meshtastic_Mes
|
||||
*/
|
||||
template <typename T> void LR11x0Interface<T>::configHardwareForSend()
|
||||
{
|
||||
radioExternalPaTxEnable(); // bias an external PA (if any) before we transmit
|
||||
RadioLibInterface::configHardwareForSend();
|
||||
}
|
||||
|
||||
@@ -250,6 +257,8 @@ template <typename T> void LR11x0Interface<T>::startReceive()
|
||||
|
||||
setStandby();
|
||||
|
||||
radioExternalPaRxIdle(); // drop external PA bias while receiving/idle
|
||||
|
||||
lora.setPreambleLength(preambleLength); // Solve RX ack fail after direct message sent. Not sure why this is needed.
|
||||
|
||||
// We use a 16 bit preamble so this should save some power by letting radio sit in standby mostly.
|
||||
@@ -337,6 +346,8 @@ template <typename T> bool LR11x0Interface<T>::sleep()
|
||||
LOG_DEBUG("LR11x0 entering sleep mode");
|
||||
setStandby(); // Stop any pending operations
|
||||
|
||||
radioExternalPaSleep(); // power down an external PA (if any)
|
||||
|
||||
// turn off TCXO if it was powered
|
||||
lora.setTCXO(0);
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include "FSCommon.h"
|
||||
#include "MeshRadio.h"
|
||||
#include "MeshService.h"
|
||||
#include "MessageStore.h"
|
||||
#include "NodeDB.h"
|
||||
#include "PacketHistory.h"
|
||||
#include "PowerFSM.h"
|
||||
@@ -525,9 +524,6 @@ bool NodeDB::factoryReset(bool eraseBleBonds)
|
||||
if (transmitHistory) {
|
||||
transmitHistory->clear();
|
||||
}
|
||||
#if HAS_SCREEN
|
||||
messageStore.clearAllMessages();
|
||||
#endif
|
||||
// second, install default state (this will deal with the duplicate mac address issue)
|
||||
installDefaultNodeDatabase();
|
||||
installDefaultDeviceState();
|
||||
|
||||
+7
-30
@@ -36,17 +36,6 @@
|
||||
// Flag to indicate a heartbeat was received and we should send queue status
|
||||
bool heartbeatReceived = false;
|
||||
|
||||
namespace
|
||||
{
|
||||
constexpr uint8_t FILES_MANIFEST_LEVELS = 3;
|
||||
constexpr size_t FILES_MANIFEST_MAX_COUNT = 64;
|
||||
|
||||
void releaseFilesManifest(std::vector<meshtastic_FileInfo> &filesManifest)
|
||||
{
|
||||
std::vector<meshtastic_FileInfo>().swap(filesManifest);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
PhoneAPI::PhoneAPI()
|
||||
{
|
||||
lastContactMsec = millis();
|
||||
@@ -81,23 +70,10 @@ void PhoneAPI::handleStartConfig()
|
||||
state = STATE_SEND_MY_INFO;
|
||||
}
|
||||
pauseBluetoothLogging = true;
|
||||
// Manifest is never read on the node-info-only path (STATE_SEND_FILEMANIFEST
|
||||
// short-circuits to sendConfigComplete), so skip the SPI lock + FS walk.
|
||||
if (config_nonce != SPECIAL_NONCE_ONLY_NODES) {
|
||||
bool filesManifestLimited = false;
|
||||
{
|
||||
concurrency::LockGuard guard(spiLock);
|
||||
filesManifest = getFiles("/", FILES_MANIFEST_LEVELS, FILES_MANIFEST_MAX_COUNT, &filesManifestLimited);
|
||||
}
|
||||
if (filesManifestLimited) {
|
||||
LOG_WARN("Got %zu files in manifest (limited to %zu entries/depth %u)", filesManifest.size(),
|
||||
FILES_MANIFEST_MAX_COUNT, static_cast<unsigned>(FILES_MANIFEST_LEVELS));
|
||||
} else {
|
||||
LOG_DEBUG("Got %zu files in manifest", filesManifest.size());
|
||||
}
|
||||
} else {
|
||||
releaseFilesManifest(filesManifest);
|
||||
}
|
||||
spiLock->lock();
|
||||
filesManifest = getFiles("/", 10);
|
||||
spiLock->unlock();
|
||||
LOG_DEBUG("Got %d files in manifest", filesManifest.size());
|
||||
|
||||
LOG_INFO("Start API client config millis=%u", millis());
|
||||
// Protect against concurrent BLE callbacks: they run in NimBLE's FreeRTOS task and also touch nodeInfoQueue.
|
||||
@@ -146,7 +122,8 @@ void PhoneAPI::close()
|
||||
nodeInfoQueue.clear();
|
||||
}
|
||||
packetForPhone = NULL;
|
||||
releaseFilesManifest(filesManifest);
|
||||
filesManifest.clear();
|
||||
filesManifest.shrink_to_fit();
|
||||
lastPortNumToRadio.clear();
|
||||
fromRadioNum = 0;
|
||||
config_nonce = 0;
|
||||
@@ -555,7 +532,7 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
if (config_state == filesManifest.size() ||
|
||||
config_nonce == SPECIAL_NONCE_ONLY_NODES) { // also handles an empty filesManifest
|
||||
config_state = 0;
|
||||
releaseFilesManifest(filesManifest);
|
||||
filesManifest.clear();
|
||||
// Skip to complete packet
|
||||
sendConfigComplete();
|
||||
} else {
|
||||
|
||||
@@ -154,10 +154,7 @@ bool RF95Interface::init()
|
||||
digitalWrite(RF95_TXEN, 0);
|
||||
#endif
|
||||
|
||||
#ifdef RF95_FAN_EN
|
||||
pinMode(RF95_FAN_EN, OUTPUT);
|
||||
digitalWrite(RF95_FAN_EN, 1);
|
||||
#endif
|
||||
enableFan();
|
||||
|
||||
#ifdef RF95_RXEN
|
||||
pinMode(RF95_RXEN, OUTPUT);
|
||||
@@ -335,10 +332,7 @@ bool RF95Interface::sleep()
|
||||
// put chipset into sleep mode
|
||||
setStandby(); // First cancel any active receiving/sending
|
||||
lora->sleep();
|
||||
|
||||
#ifdef RF95_FAN_EN
|
||||
digitalWrite(RF95_FAN_EN, 0);
|
||||
#endif
|
||||
disableFan();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
#include "RadioExternalPa.h"
|
||||
|
||||
// Weak default implementations: no external PA. A board with an external PA
|
||||
// provides strong overrides (see e.g.
|
||||
// src/platform/extra_variants/radiomaster_nomad_gemini/variant.cpp).
|
||||
|
||||
int8_t __attribute__((weak)) radioExternalPaMapPower(int8_t requestedTotalDbm, float freqHz)
|
||||
{
|
||||
(void)freqHz;
|
||||
(void)requestedTotalDbm;
|
||||
return RADIO_EXTERNAL_PA_NO_MAP;
|
||||
}
|
||||
|
||||
void __attribute__((weak)) radioExternalPaTxEnable() {}
|
||||
|
||||
void __attribute__((weak)) radioExternalPaRxIdle() {}
|
||||
|
||||
void __attribute__((weak)) radioExternalPaSleep() {}
|
||||
@@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* Generic hooks for boards with an external power amplifier whose gain/bias is
|
||||
* controlled outside the LoRa transceiver (e.g. an analog PA biased through a DAC
|
||||
* pin, as on the RadioMaster Nomad Gemini).
|
||||
*
|
||||
* All four functions have weak no-op / pass-through defaults (see RadioExternalPa.cpp),
|
||||
* so boards without an external PA are completely unaffected. A board provides an
|
||||
* external PA by giving STRONG overrides (typically in its
|
||||
* src/platform/extra_variants/<board>/variant.cpp).
|
||||
*
|
||||
* Relationship to the existing TX_GAIN_LORA / LoRaFEMInterface mechanisms:
|
||||
* - TX_GAIN_LORA assumes the chip output index is a non-negative dBm value.
|
||||
* - LoRaFEMInterface models *digital* front-end modules (discrete enable pins).
|
||||
* An analog PA that needs the transceiver driven at negative dBm fits neither, so it
|
||||
* is handled here instead.
|
||||
*/
|
||||
|
||||
/// Sentinel returned by radioExternalPaMapPower() when the board has no external PA.
|
||||
#define RADIO_EXTERNAL_PA_NO_MAP INT8_MIN
|
||||
|
||||
/**
|
||||
* Map a desired *total* radiated output power to the transceiver chip output power.
|
||||
*
|
||||
* Called from RadioInterface::limitPower() AFTER regional/regulatory clamping, so
|
||||
* @p requestedTotalDbm is already the legal total output we want out of the antenna.
|
||||
* The override returns the chip output power (dBm, may be negative) that, combined
|
||||
* with the external PA gain, yields that total, and configures/stashes the PA bias.
|
||||
*
|
||||
* @param requestedTotalDbm desired total output power in dBm (already region-limited)
|
||||
* @param freqHz operating frequency in Hz (for band-dependent PAs)
|
||||
* @return chip output power in dBm, or RADIO_EXTERNAL_PA_NO_MAP if no external PA
|
||||
*/
|
||||
int8_t radioExternalPaMapPower(int8_t requestedTotalDbm, float freqHz);
|
||||
|
||||
/// Engage the external PA bias for transmit (called just before a transmission).
|
||||
void radioExternalPaTxEnable();
|
||||
|
||||
/// Drop the external PA bias for receive/idle (called when entering RX/standby).
|
||||
void radioExternalPaRxIdle();
|
||||
|
||||
/// Power the external PA fully down (called when the radio goes to sleep).
|
||||
void radioExternalPaSleep();
|
||||
+35
-24
@@ -9,6 +9,7 @@
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
#include "RF95Interface.h"
|
||||
#include "RadioExternalPa.h"
|
||||
#include "Router.h"
|
||||
#include "SX1262Interface.h"
|
||||
#include "SX1268Interface.h"
|
||||
@@ -32,8 +33,6 @@
|
||||
#include "STM32WLE5JCInterface.h"
|
||||
#endif
|
||||
|
||||
Observable<uint32_t> RadioInterface::loraRxPacketObservable;
|
||||
|
||||
#define RDEF(name, freq_start, freq_end, duty_cycle, spacing, power_limit, audio_permitted, frequency_switching, wide_lora) \
|
||||
{ \
|
||||
meshtastic_Config_LoRaConfig_RegionCode_##name, freq_start, freq_end, duty_cycle, spacing, power_limit, audio_permitted, \
|
||||
@@ -919,38 +918,50 @@ void RadioInterface::limitPower(int8_t loraMaxPower)
|
||||
power = maxPower;
|
||||
}
|
||||
|
||||
// Boards with an external PA controlled outside the transceiver (e.g. an analog PA
|
||||
// biased through a DAC pin) map the desired total output to a possibly-negative chip
|
||||
// output power here. This is applied even for licensed operators, because it reflects
|
||||
// a hardware gain stage, not a regulatory limit (the regulatory clamp above already
|
||||
// honors the license). Pass-through by default; see RadioExternalPa.h.
|
||||
int8_t externalPaChip = radioExternalPaMapPower(power, getFreq());
|
||||
if (externalPaChip != RADIO_EXTERNAL_PA_NO_MAP) {
|
||||
LOG_INFO("External PA: %d dBm total -> chip %d dBm", power, externalPaChip);
|
||||
power = externalPaChip;
|
||||
} else {
|
||||
#if HAS_LORA_FEM
|
||||
if (!devicestate.owner.is_licensed) {
|
||||
power = loraFEMInterface.powerConversion(power);
|
||||
}
|
||||
if (!devicestate.owner.is_licensed) {
|
||||
power = loraFEMInterface.powerConversion(power);
|
||||
}
|
||||
#else
|
||||
// todo:All entries containing "lora fem" are grouped together above.
|
||||
#ifdef ARCH_PORTDUINO
|
||||
size_t num_pa_points = portduino_config.num_pa_points;
|
||||
const uint16_t *tx_gain = portduino_config.tx_gain_lora;
|
||||
size_t num_pa_points = portduino_config.num_pa_points;
|
||||
const uint16_t *tx_gain = portduino_config.tx_gain_lora;
|
||||
#else
|
||||
size_t num_pa_points = NUM_PA_POINTS;
|
||||
const uint16_t tx_gain[NUM_PA_POINTS] = {TX_GAIN_LORA};
|
||||
size_t num_pa_points = NUM_PA_POINTS;
|
||||
const uint16_t tx_gain[NUM_PA_POINTS] = {TX_GAIN_LORA};
|
||||
#endif
|
||||
|
||||
if (num_pa_points == 1) {
|
||||
if (tx_gain[0] > 0 && !devicestate.owner.is_licensed) {
|
||||
LOG_INFO("Requested Tx power: %d dBm; Device LoRa Tx gain: %d dB", power, tx_gain[0]);
|
||||
power -= tx_gain[0];
|
||||
}
|
||||
} else if (!devicestate.owner.is_licensed) {
|
||||
// we have an array of PA gain values. Find the highest power setting that works.
|
||||
for (int radio_dbm = 0; radio_dbm < (int)num_pa_points; radio_dbm++) {
|
||||
if (((radio_dbm + tx_gain[radio_dbm]) > power) ||
|
||||
((radio_dbm == (int)(num_pa_points - 1)) && ((radio_dbm + tx_gain[radio_dbm]) <= power))) {
|
||||
// we've exceeded the power limit, or hit the max we can do
|
||||
LOG_INFO("Requested Tx power: %d dBm; Device LoRa Tx gain: %d dB", power, tx_gain[radio_dbm]);
|
||||
power -= tx_gain[radio_dbm];
|
||||
break;
|
||||
if (num_pa_points == 1) {
|
||||
if (tx_gain[0] > 0 && !devicestate.owner.is_licensed) {
|
||||
LOG_INFO("Requested Tx power: %d dBm; Device LoRa Tx gain: %d dB", power, tx_gain[0]);
|
||||
power -= tx_gain[0];
|
||||
}
|
||||
} else if (!devicestate.owner.is_licensed) {
|
||||
// we have an array of PA gain values. Find the highest power setting that works.
|
||||
for (int radio_dbm = 0; radio_dbm < (int)num_pa_points; radio_dbm++) {
|
||||
if (((radio_dbm + tx_gain[radio_dbm]) > power) ||
|
||||
((radio_dbm == (int)(num_pa_points - 1)) && ((radio_dbm + tx_gain[radio_dbm]) <= power))) {
|
||||
// we've exceeded the power limit, or hit the max we can do
|
||||
LOG_INFO("Requested Tx power: %d dBm; Device LoRa Tx gain: %d dB", power, tx_gain[radio_dbm]);
|
||||
power -= tx_gain[radio_dbm];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (power > loraMaxPower) // Clamp power to maximum defined level
|
||||
power = loraMaxPower;
|
||||
|
||||
|
||||
@@ -123,9 +123,6 @@ class RadioInterface
|
||||
|
||||
virtual ~RadioInterface() {}
|
||||
|
||||
/// Fires once per valid received LoRa packet (arg = sender NodeNum). Used e.g. to flash LED_LORA.
|
||||
static Observable<uint32_t> loraRxPacketObservable;
|
||||
|
||||
/**
|
||||
* Coerce LoRa config fields (bandwidth/spread_factor) derived from presets.
|
||||
* This is used during early bootstrapping so UIs that display these fields directly remain consistent.
|
||||
|
||||
@@ -509,9 +509,6 @@ void RadioLibInterface::completeSending()
|
||||
// that can take a long time
|
||||
auto p = sendingPacket;
|
||||
sendingPacket = NULL;
|
||||
#ifdef LED_LORA
|
||||
digitalWrite(LED_LORA, LED_STATE_OFF);
|
||||
#endif
|
||||
|
||||
if (p) {
|
||||
// Packet has been sent, count it toward our TX airtime utilization.
|
||||
@@ -614,10 +611,6 @@ void RadioLibInterface::handleReceiveInterrupt()
|
||||
|
||||
printPacket("Lora RX", mp);
|
||||
|
||||
#ifdef LED_LORA
|
||||
loraRxPacketObservable.notifyObservers(mp->from);
|
||||
#endif
|
||||
|
||||
airTime->logAirtime(RX_LOG, rxMsec);
|
||||
|
||||
deliverToReceiver(mp);
|
||||
@@ -693,11 +686,41 @@ bool RadioLibInterface::startSend(meshtastic_MeshPacket *txp)
|
||||
enableInterrupt(isrTxLevel0);
|
||||
lastTxStart = millis();
|
||||
printPacket("Started Tx", txp);
|
||||
#ifdef LED_LORA
|
||||
digitalWrite(LED_LORA, LED_STATE_ON);
|
||||
#endif
|
||||
}
|
||||
|
||||
return res == RADIOLIB_ERR_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
void RadioLibInterface::enableFan()
|
||||
{
|
||||
#ifdef RADIO_FAN_EN
|
||||
|
||||
#ifdef RADIO_FAN_PWM
|
||||
#if defined(ARCH_ESP32)
|
||||
ledcWrite(1, config.lora.pa_fan_disabled ? 0 : (pa_fan_percentage * 2.55));
|
||||
#elif defined(ARCH_NRF52)
|
||||
analogWrite(RADIO_FAN_EN, config.lora.pa_fan_disabled ? 0 : (pa_fan_percentage * 2.55));
|
||||
#endif
|
||||
#else
|
||||
pinMode(RADIO_FAN_EN, OUTPUT);
|
||||
digitalWrite(RADIO_FAN_EN, config.lora.pa_fan_disabled ? 0 : 1);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void RadioLibInterface::disableFan()
|
||||
{
|
||||
#ifdef RADIO_FAN_EN
|
||||
#ifdef RADIO_FAN_PWM
|
||||
#if defined(ARCH_ESP32)
|
||||
ledcWrite(1, 0);
|
||||
#elif defined(ARCH_NRF52)
|
||||
analogWrite(RADIO_FAN_EN, 0);
|
||||
#endif
|
||||
#else
|
||||
pinMode(RADIO_FAN_EN, OUTPUT);
|
||||
digitalWrite(RADIO_FAN_EN, 0);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -203,6 +203,9 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified
|
||||
/** Attempt to find a packet in the TxQueue. Returns true if the packet was found. */
|
||||
virtual bool findInTxQueue(NodeNum from, PacketId id) override;
|
||||
|
||||
void enableFan();
|
||||
void disableFan();
|
||||
|
||||
/**
|
||||
* Update the noise floor measurement by sampling RSSI from a slow path.
|
||||
* This should not be called from radio interrupt or TX/RX critical paths.
|
||||
|
||||
@@ -64,10 +64,7 @@ template <typename T> bool SX126xInterface<T>::init()
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef RF95_FAN_EN
|
||||
pinMode(RF95_FAN_EN, OUTPUT);
|
||||
digitalWrite(RF95_FAN_EN, HIGH);
|
||||
#endif
|
||||
enableFan();
|
||||
|
||||
#if ARCH_PORTDUINO
|
||||
tcxoVoltage = (float)portduino_config.dio3_tcxo_voltage / 1000;
|
||||
|
||||
@@ -35,10 +35,7 @@ template <typename T> bool SX128xInterface<T>::init()
|
||||
digitalWrite(SX128X_POWER_EN, HIGH);
|
||||
#endif
|
||||
|
||||
#ifdef RF95_FAN_EN
|
||||
pinMode(RF95_FAN_EN, OUTPUT);
|
||||
digitalWrite(RF95_FAN_EN, 1);
|
||||
#endif
|
||||
enableFan();
|
||||
|
||||
#if ARCH_PORTDUINO
|
||||
if (portduino_config.lora_rxen_pin.pin != RADIOLIB_NC) {
|
||||
|
||||
@@ -30,7 +30,7 @@ PB_BIND(meshtastic_AircraftTrack, meshtastic_AircraftTrack, AUTO)
|
||||
PB_BIND(meshtastic_CotGeoPoint, meshtastic_CotGeoPoint, AUTO)
|
||||
|
||||
|
||||
PB_BIND(meshtastic_DrawnShape, meshtastic_DrawnShape, AUTO)
|
||||
PB_BIND(meshtastic_DrawnShape, meshtastic_DrawnShape, 2)
|
||||
|
||||
|
||||
PB_BIND(meshtastic_Marker, meshtastic_Marker, AUTO)
|
||||
@@ -63,15 +63,6 @@ PB_BIND(meshtastic_TAKEnvironment, meshtastic_TAKEnvironment, AUTO)
|
||||
PB_BIND(meshtastic_SensorFov, meshtastic_SensorFov, AUTO)
|
||||
|
||||
|
||||
PB_BIND(meshtastic_TakTalkMessage, meshtastic_TakTalkMessage, AUTO)
|
||||
|
||||
|
||||
PB_BIND(meshtastic_TakTalkRoomData, meshtastic_TakTalkRoomData, AUTO)
|
||||
|
||||
|
||||
PB_BIND(meshtastic_Marti, meshtastic_Marti, AUTO)
|
||||
|
||||
|
||||
PB_BIND(meshtastic_TAKPacketV2, meshtastic_TAKPacketV2, 2)
|
||||
|
||||
|
||||
|
||||
@@ -325,15 +325,7 @@ typedef enum _meshtastic_CotType {
|
||||
meshtastic_CotType_CotType_b_a_o_c = 123,
|
||||
/* t-s: Task / engage request. Structured payload carried via the new
|
||||
TaskRequest typed variant. */
|
||||
meshtastic_CotType_CotType_t_s = 124,
|
||||
/* m-t-t: TAKTALK voice/text chat message. Payload carried via the
|
||||
TakTalkMessage typed variant (text, chatroom_id, lang, from_voice). */
|
||||
meshtastic_CotType_CotType_m_t_t = 125,
|
||||
/* y-: TAKTALK room/membership broadcast. Payload carried via the
|
||||
TakTalkRoomData typed variant (sender_callsign, room_id, room_name,
|
||||
participants). The CoT type literally has a trailing dash and no
|
||||
second atom — not a typo. */
|
||||
meshtastic_CotType_CotType_y = 126
|
||||
meshtastic_CotType_CotType_t_s = 124
|
||||
} meshtastic_CotType;
|
||||
|
||||
/* Geopoint and altitude source */
|
||||
@@ -561,18 +553,6 @@ typedef struct _meshtastic_GeoChat {
|
||||
/* Receipt kind discriminator. See ReceiptType doc. Default ReceiptType_None
|
||||
means this is a regular chat message, not a receipt. */
|
||||
meshtastic_GeoChat_ReceiptType receipt_type;
|
||||
/* BCP-47-ish language tag or human-readable name (e.g. "en", "English")
|
||||
that the originator's TAKTALK plugin recorded for the message. */
|
||||
pb_callback_t lang;
|
||||
/* TAKTALK chatroom UUID (e.g. "30b2755c-c547-44ef-a0cc-cdbd8a15616f") that
|
||||
the receiver's TAKTALK plugin uses to thread the message under the
|
||||
right room. Resolved to a friendly name via TakTalkRoomData broadcasts. */
|
||||
pb_callback_t room_id;
|
||||
/* TAKTALK voice profile pointer. Often empty in practice (the empty
|
||||
marker `<voice_profile_id/>` still signals TAKTALK origination), so
|
||||
receivers should treat empty-but-present as the equivalent of the
|
||||
marker rather than a missing field. */
|
||||
pb_callback_t voice_profile_id;
|
||||
} meshtastic_GeoChat;
|
||||
|
||||
/* ATAK Group
|
||||
@@ -735,7 +715,12 @@ typedef struct _meshtastic_DrawnShape {
|
||||
uint32_t fill_argb;
|
||||
/* Whether labels are rendered on this shape. */
|
||||
bool labels_on;
|
||||
/* True if the sender truncated the vertex columns to fit the pool. */
|
||||
/* Vertex list for polyline/polygon/rectangle shapes. Capped at 32 by
|
||||
the nanopb pool; senders MUST truncate longer inputs and set
|
||||
`truncated = true`. */
|
||||
pb_size_t vertices_count;
|
||||
meshtastic_CotGeoPoint vertices[32];
|
||||
/* True if the sender truncated `vertices` to fit the pool. */
|
||||
bool truncated; /* --- Bullseye-only fields. All ignored unless kind == Kind_Bullseye. --- */
|
||||
/* Bullseye distance in meters * 10 (e.g. 3285 = 328.5 m). 0 = unset. */
|
||||
uint32_t bullseye_distance_dm;
|
||||
@@ -749,8 +734,6 @@ typedef struct _meshtastic_DrawnShape {
|
||||
uint8_t bullseye_flags;
|
||||
/* Bullseye reference UID (anchor marker). Empty = anchor is self. */
|
||||
char bullseye_uid_ref[48];
|
||||
pb_callback_t vertex_lat_deltas;
|
||||
pb_callback_t vertex_lon_deltas;
|
||||
} meshtastic_DrawnShape;
|
||||
|
||||
/* Fixed point of interest: spot marker, waypoint, checkpoint, 2525 symbol,
|
||||
@@ -1085,87 +1068,6 @@ typedef struct _meshtastic_SensorFov {
|
||||
pb_callback_t model;
|
||||
} meshtastic_SensorFov;
|
||||
|
||||
/* TAKTALK chat message payload (CoT type m-t-t).
|
||||
|
||||
TAKTALK is an ATAK plugin for voice + text team messaging. The voice
|
||||
audio stream goes over UDP/RTP and is NOT carried by the mesh — only
|
||||
the text envelope (this message) is. `from_voice` marks messages sent
|
||||
via push-to-talk speech-to-text so receivers can render a mic icon
|
||||
next to the text.
|
||||
|
||||
Wire shape inside <event type="m-t-t">/<detail>:
|
||||
<callsign>...</callsign> - mapped to TAKPacketV2.callsign
|
||||
<lang>English</lang> - lang
|
||||
<text>...</text> - text
|
||||
<chatroom-id>1</chatroom-id> - chatroom_id
|
||||
<voice/> - presence sets from_voice = true */
|
||||
typedef struct _meshtastic_TakTalkMessage {
|
||||
/* The text body of the TAKTALK message (speech-to-text transcript when
|
||||
from_voice = true, typed message otherwise). */
|
||||
pb_callback_t text;
|
||||
/* TAKTALK chatroom identifier. May be a short id like "1" for the
|
||||
default room or a UUID like "30b2755c-c547-44ef-a0cc-cdbd8a15616f"
|
||||
for custom rooms (resolved by TakTalkRoomData broadcasts).
|
||||
Empty = broadcast room. */
|
||||
pb_callback_t chatroom_id;
|
||||
/* BCP-47-ish language tag or human-readable name (e.g. "en", "English").
|
||||
Empty = unspecified. */
|
||||
pb_callback_t lang;
|
||||
/* True when the source CoT carried a <voice/> marker, i.e. the message
|
||||
originated as push-to-talk speech-to-text. Lets receivers show a mic
|
||||
icon. Proto3 only encodes when true so empty payload cost is 0 bytes. */
|
||||
bool from_voice;
|
||||
} meshtastic_TakTalkMessage;
|
||||
|
||||
/* TAKTALK room/membership broadcast (CoT type y-).
|
||||
|
||||
Announces a TAKTALK chatroom's friendly name and roster so peers can
|
||||
resolve room UUIDs (used in TakTalkMessage.chatroom_id and
|
||||
GeoChat.room_id) to a display name and participant list. Not a chat
|
||||
message itself — these events are emitted by TAKTALK when rooms are
|
||||
created or memberships change. */
|
||||
typedef struct _meshtastic_TakTalkRoomData {
|
||||
/* Callsign of the device broadcasting the room state (typically the
|
||||
room owner / latest writer).
|
||||
|
||||
DEPRECATED in v0.3.2: always equals TAKPacketV2.callsign, so the wire
|
||||
byte was redundant. Builders stop emitting this field in v0.3.2;
|
||||
parsers still read it for one release so v0.3.1-encoded packets decode
|
||||
cleanly. To be removed entirely in v0.4.x. */
|
||||
pb_callback_t sender_callsign;
|
||||
/* Room UUID, matches TakTalkMessage.chatroom_id / GeoChat.room_id on
|
||||
messages routed into this room. */
|
||||
pb_callback_t room_id;
|
||||
/* Friendly display name for the room (e.g. "test", "Alpha Team"). */
|
||||
pb_callback_t room_name;
|
||||
/* Member callsigns. Wire-encoded as repeated strings; the underlying
|
||||
CoT carries them as a single <chatroom-participants>A,B,C</> element
|
||||
which parsers split / builders join on ','. */
|
||||
pb_callback_t participants;
|
||||
} meshtastic_TakTalkRoomData;
|
||||
|
||||
/* ATAK directed-routing recipient list (CoT <marti><dest callsign='X'/>…</marti>).
|
||||
|
||||
Present when an event is addressed to specific TAK users rather than the
|
||||
broadcast group. TAKTALK gates voice TTS on this element matching the
|
||||
receiver's callsign; directed b-t-f chats use it for the same purpose. A
|
||||
missing <marti> means "broadcast to all peers", which is the default for
|
||||
PLI, alerts, drawings, and most situational-awareness events.
|
||||
|
||||
Carried as repeated strings (not indexes into a per-packet table) because
|
||||
the typical event has 1-2 destinations and table overhead would erase the
|
||||
savings. Receivers that need the original XML element rebuild it from
|
||||
dest_callsign on emit. */
|
||||
typedef struct _meshtastic_Marti {
|
||||
/* Recipient callsigns. Order is preserved end-to-end so receivers can show
|
||||
primary-vs-cc distinction the same way ATAK does.
|
||||
|
||||
If dest_callsign is [TAKPacketV2.callsign] (self-addressed, unusual but
|
||||
legal — e.g. ATAK echoing back to its own room), the builder still emits
|
||||
the element so loopback shapes round-trip cleanly. */
|
||||
pb_callback_t dest_callsign;
|
||||
} meshtastic_Marti;
|
||||
|
||||
typedef PB_BYTES_ARRAY_T(220) meshtastic_TAKPacketV2_raw_detail_t;
|
||||
/* ATAK v2 packet with expanded CoT field support and zstd dictionary compression.
|
||||
Sent on ATAK_PLUGIN_V2 port. The wire payload is:
|
||||
@@ -1187,14 +1089,7 @@ typedef struct _meshtastic_TAKPacketV2 {
|
||||
int32_t latitude_i;
|
||||
/* Longitude, multiply by 1e-7 to get degrees in floating point */
|
||||
int32_t longitude_i;
|
||||
/* Altitude in meters (HAE). ATAK's "no altitude" sentinel is hae=9999999.0.
|
||||
|
||||
NOTE: an earlier v0.4.0 attempt made this `optional` to omit the 9999999
|
||||
sentinel from the wire, but measurement showed it was net-negative: the
|
||||
zstd dictionary already compresses the literal 9999999 to ~nothing, while
|
||||
proto3 `optional` forces a genuine 0 m HAE (common on routes/drawings that
|
||||
carry hae="0.0" or omit hae → parsed as 0) to encode explicitly (+2 bytes),
|
||||
which REGRESSED the worst-case route fixture. Kept as a plain field. */
|
||||
/* Altitude in meters (HAE) */
|
||||
int32_t altitude;
|
||||
/* Speed in cm/s */
|
||||
uint32_t speed;
|
||||
@@ -1240,18 +1135,10 @@ typedef struct _meshtastic_TAKPacketV2 {
|
||||
/* Sensor field-of-view cone (camera, FLIR, laser, etc.). From <sensor>. */
|
||||
bool has_sensor_fov;
|
||||
meshtastic_SensorFov sensor_fov;
|
||||
/* Directed-routing recipient list (CoT <marti><dest callsign='X'/>…</marti>).
|
||||
Empty / unset = broadcast to all peers (the default for situational-awareness
|
||||
events). Populated for TAKTALK m-t-t, directed b-t-f DMs, and any other CoT
|
||||
shape that ATAK addresses to specific recipients. TAKTALK gates voice TTS
|
||||
playback on this element matching the receiver's callsign, so dropping it
|
||||
silently breaks voice messaging end-to-end.
|
||||
|
||||
See Marti. */
|
||||
bool has_marti;
|
||||
meshtastic_Marti marti;
|
||||
pb_size_t which_payload_variant;
|
||||
union {
|
||||
/* Position report (true = PLI, no extra fields beyond the common ones above) */
|
||||
bool pli;
|
||||
/* ATAK GeoChat message */
|
||||
meshtastic_GeoChat chat;
|
||||
/* Aircraft track data (ADS-B, military air) */
|
||||
@@ -1276,14 +1163,6 @@ typedef struct _meshtastic_TAKPacketV2 {
|
||||
meshtastic_EmergencyAlert emergency;
|
||||
/* Task / engage request. See TaskRequest. */
|
||||
meshtastic_TaskRequest task;
|
||||
/* TAKTALK chat message (CoT type m-t-t). See TakTalkMessage.
|
||||
Voice audio itself rides UDP/RTP outside the mesh; this carries the
|
||||
text envelope plus a from_voice marker for receiver UX. */
|
||||
meshtastic_TakTalkMessage taktalk;
|
||||
/* TAKTALK room/membership broadcast (CoT type y-). See TakTalkRoomData.
|
||||
Resolves room UUIDs (used in TakTalkMessage.chatroom_id and
|
||||
GeoChat.room_id) to display name + roster on receivers. */
|
||||
meshtastic_TakTalkRoomData taktalk_room;
|
||||
} payload_variant;
|
||||
} meshtastic_TAKPacketV2;
|
||||
|
||||
@@ -1306,8 +1185,8 @@ extern "C" {
|
||||
#define _meshtastic_CotHow_ARRAYSIZE ((meshtastic_CotHow)(meshtastic_CotHow_CotHow_m_s+1))
|
||||
|
||||
#define _meshtastic_CotType_MIN meshtastic_CotType_CotType_Other
|
||||
#define _meshtastic_CotType_MAX meshtastic_CotType_CotType_y
|
||||
#define _meshtastic_CotType_ARRAYSIZE ((meshtastic_CotType)(meshtastic_CotType_CotType_y+1))
|
||||
#define _meshtastic_CotType_MAX meshtastic_CotType_CotType_t_s
|
||||
#define _meshtastic_CotType_ARRAYSIZE ((meshtastic_CotType)(meshtastic_CotType_CotType_t_s+1))
|
||||
|
||||
#define _meshtastic_GeoPointSource_MIN meshtastic_GeoPointSource_GeoPointSource_Unspecified
|
||||
#define _meshtastic_GeoPointSource_MAX meshtastic_GeoPointSource_GeoPointSource_NETWORK
|
||||
@@ -1403,9 +1282,6 @@ extern "C" {
|
||||
|
||||
#define meshtastic_SensorFov_type_ENUMTYPE meshtastic_SensorFov_SensorType
|
||||
|
||||
|
||||
|
||||
|
||||
#define meshtastic_TAKPacketV2_cot_type_id_ENUMTYPE meshtastic_CotType
|
||||
#define meshtastic_TAKPacketV2_how_ENUMTYPE meshtastic_CotHow
|
||||
#define meshtastic_TAKPacketV2_team_ENUMTYPE meshtastic_Team
|
||||
@@ -1416,14 +1292,14 @@ extern "C" {
|
||||
|
||||
/* Initializer values for message structs */
|
||||
#define meshtastic_TAKPacket_init_default {0, false, meshtastic_Contact_init_default, false, meshtastic_Group_init_default, false, meshtastic_Status_init_default, 0, {meshtastic_PLI_init_default}}
|
||||
#define meshtastic_GeoChat_init_default {"", false, "", false, "", "", _meshtastic_GeoChat_ReceiptType_MIN, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}}
|
||||
#define meshtastic_GeoChat_init_default {"", false, "", false, "", "", _meshtastic_GeoChat_ReceiptType_MIN}
|
||||
#define meshtastic_Group_init_default {_meshtastic_MemberRole_MIN, _meshtastic_Team_MIN}
|
||||
#define meshtastic_Status_init_default {0}
|
||||
#define meshtastic_Contact_init_default {"", ""}
|
||||
#define meshtastic_PLI_init_default {0, 0, 0, 0, 0}
|
||||
#define meshtastic_AircraftTrack_init_default {"", "", "", "", 0, "", 0, 0, ""}
|
||||
#define meshtastic_CotGeoPoint_init_default {0, 0}
|
||||
#define meshtastic_DrawnShape_init_default {_meshtastic_DrawnShape_Kind_MIN, _meshtastic_DrawnShape_StyleMode_MIN, 0, 0, 0, _meshtastic_Team_MIN, 0, 0, _meshtastic_Team_MIN, 0, 0, 0, 0, 0, 0, "", {{NULL}, NULL}, {{NULL}, NULL}}
|
||||
#define meshtastic_DrawnShape_init_default {_meshtastic_DrawnShape_Kind_MIN, _meshtastic_DrawnShape_StyleMode_MIN, 0, 0, 0, _meshtastic_Team_MIN, 0, 0, _meshtastic_Team_MIN, 0, 0, 0, {meshtastic_CotGeoPoint_init_default, meshtastic_CotGeoPoint_init_default, meshtastic_CotGeoPoint_init_default, meshtastic_CotGeoPoint_init_default, meshtastic_CotGeoPoint_init_default, meshtastic_CotGeoPoint_init_default, meshtastic_CotGeoPoint_init_default, meshtastic_CotGeoPoint_init_default, meshtastic_CotGeoPoint_init_default, meshtastic_CotGeoPoint_init_default, meshtastic_CotGeoPoint_init_default, meshtastic_CotGeoPoint_init_default, meshtastic_CotGeoPoint_init_default, meshtastic_CotGeoPoint_init_default, meshtastic_CotGeoPoint_init_default, meshtastic_CotGeoPoint_init_default, meshtastic_CotGeoPoint_init_default, meshtastic_CotGeoPoint_init_default, meshtastic_CotGeoPoint_init_default, meshtastic_CotGeoPoint_init_default, meshtastic_CotGeoPoint_init_default, meshtastic_CotGeoPoint_init_default, meshtastic_CotGeoPoint_init_default, meshtastic_CotGeoPoint_init_default, meshtastic_CotGeoPoint_init_default, meshtastic_CotGeoPoint_init_default, meshtastic_CotGeoPoint_init_default, meshtastic_CotGeoPoint_init_default, meshtastic_CotGeoPoint_init_default, meshtastic_CotGeoPoint_init_default, meshtastic_CotGeoPoint_init_default, meshtastic_CotGeoPoint_init_default}, 0, 0, 0, 0, ""}
|
||||
#define meshtastic_Marker_init_default {_meshtastic_Marker_Kind_MIN, _meshtastic_Team_MIN, 0, 0, "", "", "", ""}
|
||||
#define meshtastic_RangeAndBearing_init_default {false, meshtastic_CotGeoPoint_init_default, "", 0, 0, _meshtastic_Team_MIN, 0, 0}
|
||||
#define meshtastic_Route_init_default {_meshtastic_Route_Method_MIN, _meshtastic_Route_Direction_MIN, "", 0, 0, {meshtastic_Route_Link_init_default, meshtastic_Route_Link_init_default, meshtastic_Route_Link_init_default, meshtastic_Route_Link_init_default, meshtastic_Route_Link_init_default, meshtastic_Route_Link_init_default, meshtastic_Route_Link_init_default, meshtastic_Route_Link_init_default, meshtastic_Route_Link_init_default, meshtastic_Route_Link_init_default, meshtastic_Route_Link_init_default, meshtastic_Route_Link_init_default, meshtastic_Route_Link_init_default, meshtastic_Route_Link_init_default, meshtastic_Route_Link_init_default, meshtastic_Route_Link_init_default}, 0}
|
||||
@@ -1434,19 +1310,16 @@ extern "C" {
|
||||
#define meshtastic_TaskRequest_init_default {"", "", "", _meshtastic_TaskRequest_Priority_MIN, _meshtastic_TaskRequest_Status_MIN, ""}
|
||||
#define meshtastic_TAKEnvironment_init_default {0, 0, 0}
|
||||
#define meshtastic_SensorFov_init_default {_meshtastic_SensorFov_SensorType_MIN, 0, false, 0, 0, 0, 0, 0, {{NULL}, NULL}}
|
||||
#define meshtastic_TakTalkMessage_init_default {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, 0}
|
||||
#define meshtastic_TakTalkRoomData_init_default {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}}
|
||||
#define meshtastic_Marti_init_default {{{NULL}, NULL}}
|
||||
#define meshtastic_TAKPacketV2_init_default {_meshtastic_CotType_MIN, _meshtastic_CotHow_MIN, "", _meshtastic_Team_MIN, _meshtastic_MemberRole_MIN, 0, 0, 0, 0, 0, 0, _meshtastic_GeoPointSource_MIN, _meshtastic_GeoPointSource_MIN, "", "", 0, "", "", "", "", "", "", "", {{NULL}, NULL}, false, meshtastic_TAKEnvironment_init_default, false, meshtastic_SensorFov_init_default, false, meshtastic_Marti_init_default, 0, {meshtastic_GeoChat_init_default}}
|
||||
#define meshtastic_TAKPacketV2_init_default {_meshtastic_CotType_MIN, _meshtastic_CotHow_MIN, "", _meshtastic_Team_MIN, _meshtastic_MemberRole_MIN, 0, 0, 0, 0, 0, 0, _meshtastic_GeoPointSource_MIN, _meshtastic_GeoPointSource_MIN, "", "", 0, "", "", "", "", "", "", "", {{NULL}, NULL}, false, meshtastic_TAKEnvironment_init_default, false, meshtastic_SensorFov_init_default, 0, {0}}
|
||||
#define meshtastic_TAKPacket_init_zero {0, false, meshtastic_Contact_init_zero, false, meshtastic_Group_init_zero, false, meshtastic_Status_init_zero, 0, {meshtastic_PLI_init_zero}}
|
||||
#define meshtastic_GeoChat_init_zero {"", false, "", false, "", "", _meshtastic_GeoChat_ReceiptType_MIN, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}}
|
||||
#define meshtastic_GeoChat_init_zero {"", false, "", false, "", "", _meshtastic_GeoChat_ReceiptType_MIN}
|
||||
#define meshtastic_Group_init_zero {_meshtastic_MemberRole_MIN, _meshtastic_Team_MIN}
|
||||
#define meshtastic_Status_init_zero {0}
|
||||
#define meshtastic_Contact_init_zero {"", ""}
|
||||
#define meshtastic_PLI_init_zero {0, 0, 0, 0, 0}
|
||||
#define meshtastic_AircraftTrack_init_zero {"", "", "", "", 0, "", 0, 0, ""}
|
||||
#define meshtastic_CotGeoPoint_init_zero {0, 0}
|
||||
#define meshtastic_DrawnShape_init_zero {_meshtastic_DrawnShape_Kind_MIN, _meshtastic_DrawnShape_StyleMode_MIN, 0, 0, 0, _meshtastic_Team_MIN, 0, 0, _meshtastic_Team_MIN, 0, 0, 0, 0, 0, 0, "", {{NULL}, NULL}, {{NULL}, NULL}}
|
||||
#define meshtastic_DrawnShape_init_zero {_meshtastic_DrawnShape_Kind_MIN, _meshtastic_DrawnShape_StyleMode_MIN, 0, 0, 0, _meshtastic_Team_MIN, 0, 0, _meshtastic_Team_MIN, 0, 0, 0, {meshtastic_CotGeoPoint_init_zero, meshtastic_CotGeoPoint_init_zero, meshtastic_CotGeoPoint_init_zero, meshtastic_CotGeoPoint_init_zero, meshtastic_CotGeoPoint_init_zero, meshtastic_CotGeoPoint_init_zero, meshtastic_CotGeoPoint_init_zero, meshtastic_CotGeoPoint_init_zero, meshtastic_CotGeoPoint_init_zero, meshtastic_CotGeoPoint_init_zero, meshtastic_CotGeoPoint_init_zero, meshtastic_CotGeoPoint_init_zero, meshtastic_CotGeoPoint_init_zero, meshtastic_CotGeoPoint_init_zero, meshtastic_CotGeoPoint_init_zero, meshtastic_CotGeoPoint_init_zero, meshtastic_CotGeoPoint_init_zero, meshtastic_CotGeoPoint_init_zero, meshtastic_CotGeoPoint_init_zero, meshtastic_CotGeoPoint_init_zero, meshtastic_CotGeoPoint_init_zero, meshtastic_CotGeoPoint_init_zero, meshtastic_CotGeoPoint_init_zero, meshtastic_CotGeoPoint_init_zero, meshtastic_CotGeoPoint_init_zero, meshtastic_CotGeoPoint_init_zero, meshtastic_CotGeoPoint_init_zero, meshtastic_CotGeoPoint_init_zero, meshtastic_CotGeoPoint_init_zero, meshtastic_CotGeoPoint_init_zero, meshtastic_CotGeoPoint_init_zero, meshtastic_CotGeoPoint_init_zero}, 0, 0, 0, 0, ""}
|
||||
#define meshtastic_Marker_init_zero {_meshtastic_Marker_Kind_MIN, _meshtastic_Team_MIN, 0, 0, "", "", "", ""}
|
||||
#define meshtastic_RangeAndBearing_init_zero {false, meshtastic_CotGeoPoint_init_zero, "", 0, 0, _meshtastic_Team_MIN, 0, 0}
|
||||
#define meshtastic_Route_init_zero {_meshtastic_Route_Method_MIN, _meshtastic_Route_Direction_MIN, "", 0, 0, {meshtastic_Route_Link_init_zero, meshtastic_Route_Link_init_zero, meshtastic_Route_Link_init_zero, meshtastic_Route_Link_init_zero, meshtastic_Route_Link_init_zero, meshtastic_Route_Link_init_zero, meshtastic_Route_Link_init_zero, meshtastic_Route_Link_init_zero, meshtastic_Route_Link_init_zero, meshtastic_Route_Link_init_zero, meshtastic_Route_Link_init_zero, meshtastic_Route_Link_init_zero, meshtastic_Route_Link_init_zero, meshtastic_Route_Link_init_zero, meshtastic_Route_Link_init_zero, meshtastic_Route_Link_init_zero}, 0}
|
||||
@@ -1457,10 +1330,7 @@ extern "C" {
|
||||
#define meshtastic_TaskRequest_init_zero {"", "", "", _meshtastic_TaskRequest_Priority_MIN, _meshtastic_TaskRequest_Status_MIN, ""}
|
||||
#define meshtastic_TAKEnvironment_init_zero {0, 0, 0}
|
||||
#define meshtastic_SensorFov_init_zero {_meshtastic_SensorFov_SensorType_MIN, 0, false, 0, 0, 0, 0, 0, {{NULL}, NULL}}
|
||||
#define meshtastic_TakTalkMessage_init_zero {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, 0}
|
||||
#define meshtastic_TakTalkRoomData_init_zero {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}}
|
||||
#define meshtastic_Marti_init_zero {{{NULL}, NULL}}
|
||||
#define meshtastic_TAKPacketV2_init_zero {_meshtastic_CotType_MIN, _meshtastic_CotHow_MIN, "", _meshtastic_Team_MIN, _meshtastic_MemberRole_MIN, 0, 0, 0, 0, 0, 0, _meshtastic_GeoPointSource_MIN, _meshtastic_GeoPointSource_MIN, "", "", 0, "", "", "", "", "", "", "", {{NULL}, NULL}, false, meshtastic_TAKEnvironment_init_zero, false, meshtastic_SensorFov_init_zero, false, meshtastic_Marti_init_zero, 0, {meshtastic_GeoChat_init_zero}}
|
||||
#define meshtastic_TAKPacketV2_init_zero {_meshtastic_CotType_MIN, _meshtastic_CotHow_MIN, "", _meshtastic_Team_MIN, _meshtastic_MemberRole_MIN, 0, 0, 0, 0, 0, 0, _meshtastic_GeoPointSource_MIN, _meshtastic_GeoPointSource_MIN, "", "", 0, "", "", "", "", "", "", "", {{NULL}, NULL}, false, meshtastic_TAKEnvironment_init_zero, false, meshtastic_SensorFov_init_zero, 0, {0}}
|
||||
|
||||
/* Field tags (for use in manual encoding/decoding) */
|
||||
#define meshtastic_GeoChat_message_tag 1
|
||||
@@ -1468,9 +1338,6 @@ extern "C" {
|
||||
#define meshtastic_GeoChat_to_callsign_tag 3
|
||||
#define meshtastic_GeoChat_receipt_for_uid_tag 4
|
||||
#define meshtastic_GeoChat_receipt_type_tag 5
|
||||
#define meshtastic_GeoChat_lang_tag 6
|
||||
#define meshtastic_GeoChat_room_id_tag 7
|
||||
#define meshtastic_GeoChat_voice_profile_id_tag 8
|
||||
#define meshtastic_Group_role_tag 1
|
||||
#define meshtastic_Group_team_tag 2
|
||||
#define meshtastic_Status_battery_tag 1
|
||||
@@ -1510,13 +1377,12 @@ extern "C" {
|
||||
#define meshtastic_DrawnShape_fill_color_tag 9
|
||||
#define meshtastic_DrawnShape_fill_argb_tag 10
|
||||
#define meshtastic_DrawnShape_labels_on_tag 11
|
||||
#define meshtastic_DrawnShape_vertices_tag 12
|
||||
#define meshtastic_DrawnShape_truncated_tag 13
|
||||
#define meshtastic_DrawnShape_bullseye_distance_dm_tag 14
|
||||
#define meshtastic_DrawnShape_bullseye_bearing_ref_tag 15
|
||||
#define meshtastic_DrawnShape_bullseye_flags_tag 16
|
||||
#define meshtastic_DrawnShape_bullseye_uid_ref_tag 17
|
||||
#define meshtastic_DrawnShape_vertex_lat_deltas_tag 18
|
||||
#define meshtastic_DrawnShape_vertex_lon_deltas_tag 19
|
||||
#define meshtastic_Marker_kind_tag 1
|
||||
#define meshtastic_Marker_color_tag 2
|
||||
#define meshtastic_Marker_color_argb_tag 3
|
||||
@@ -1601,15 +1467,6 @@ extern "C" {
|
||||
#define meshtastic_SensorFov_elevation_deg_tag 6
|
||||
#define meshtastic_SensorFov_roll_deg_tag 7
|
||||
#define meshtastic_SensorFov_model_tag 8
|
||||
#define meshtastic_TakTalkMessage_text_tag 1
|
||||
#define meshtastic_TakTalkMessage_chatroom_id_tag 2
|
||||
#define meshtastic_TakTalkMessage_lang_tag 3
|
||||
#define meshtastic_TakTalkMessage_from_voice_tag 4
|
||||
#define meshtastic_TakTalkRoomData_sender_callsign_tag 1
|
||||
#define meshtastic_TakTalkRoomData_room_id_tag 2
|
||||
#define meshtastic_TakTalkRoomData_room_name_tag 3
|
||||
#define meshtastic_TakTalkRoomData_participants_tag 4
|
||||
#define meshtastic_Marti_dest_callsign_tag 1
|
||||
#define meshtastic_TAKPacketV2_cot_type_id_tag 1
|
||||
#define meshtastic_TAKPacketV2_how_tag 2
|
||||
#define meshtastic_TAKPacketV2_callsign_tag 3
|
||||
@@ -1636,7 +1493,7 @@ extern "C" {
|
||||
#define meshtastic_TAKPacketV2_remarks_tag 24
|
||||
#define meshtastic_TAKPacketV2_environment_tag 25
|
||||
#define meshtastic_TAKPacketV2_sensor_fov_tag 26
|
||||
#define meshtastic_TAKPacketV2_marti_tag 29
|
||||
#define meshtastic_TAKPacketV2_pli_tag 30
|
||||
#define meshtastic_TAKPacketV2_chat_tag 31
|
||||
#define meshtastic_TAKPacketV2_aircraft_tag 32
|
||||
#define meshtastic_TAKPacketV2_raw_detail_tag 33
|
||||
@@ -1647,8 +1504,6 @@ extern "C" {
|
||||
#define meshtastic_TAKPacketV2_casevac_tag 38
|
||||
#define meshtastic_TAKPacketV2_emergency_tag 39
|
||||
#define meshtastic_TAKPacketV2_task_tag 40
|
||||
#define meshtastic_TAKPacketV2_taktalk_tag 41
|
||||
#define meshtastic_TAKPacketV2_taktalk_room_tag 42
|
||||
|
||||
/* Struct field encoding specification for nanopb */
|
||||
#define meshtastic_TAKPacket_FIELDLIST(X, a) \
|
||||
@@ -1672,11 +1527,8 @@ X(a, STATIC, SINGULAR, STRING, message, 1) \
|
||||
X(a, STATIC, OPTIONAL, STRING, to, 2) \
|
||||
X(a, STATIC, OPTIONAL, STRING, to_callsign, 3) \
|
||||
X(a, STATIC, SINGULAR, STRING, receipt_for_uid, 4) \
|
||||
X(a, STATIC, SINGULAR, UENUM, receipt_type, 5) \
|
||||
X(a, CALLBACK, OPTIONAL, STRING, lang, 6) \
|
||||
X(a, CALLBACK, OPTIONAL, STRING, room_id, 7) \
|
||||
X(a, CALLBACK, OPTIONAL, STRING, voice_profile_id, 8)
|
||||
#define meshtastic_GeoChat_CALLBACK pb_default_field_callback
|
||||
X(a, STATIC, SINGULAR, UENUM, receipt_type, 5)
|
||||
#define meshtastic_GeoChat_CALLBACK NULL
|
||||
#define meshtastic_GeoChat_DEFAULT NULL
|
||||
|
||||
#define meshtastic_Group_FIELDLIST(X, a) \
|
||||
@@ -1736,15 +1588,15 @@ X(a, STATIC, SINGULAR, UINT32, stroke_weight_x10, 8) \
|
||||
X(a, STATIC, SINGULAR, UENUM, fill_color, 9) \
|
||||
X(a, STATIC, SINGULAR, FIXED32, fill_argb, 10) \
|
||||
X(a, STATIC, SINGULAR, BOOL, labels_on, 11) \
|
||||
X(a, STATIC, REPEATED, MESSAGE, vertices, 12) \
|
||||
X(a, STATIC, SINGULAR, BOOL, truncated, 13) \
|
||||
X(a, STATIC, SINGULAR, UINT32, bullseye_distance_dm, 14) \
|
||||
X(a, STATIC, SINGULAR, UINT32, bullseye_bearing_ref, 15) \
|
||||
X(a, STATIC, SINGULAR, UINT32, bullseye_flags, 16) \
|
||||
X(a, STATIC, SINGULAR, STRING, bullseye_uid_ref, 17) \
|
||||
X(a, CALLBACK, REPEATED, SINT32, vertex_lat_deltas, 18) \
|
||||
X(a, CALLBACK, REPEATED, SINT32, vertex_lon_deltas, 19)
|
||||
#define meshtastic_DrawnShape_CALLBACK pb_default_field_callback
|
||||
X(a, STATIC, SINGULAR, STRING, bullseye_uid_ref, 17)
|
||||
#define meshtastic_DrawnShape_CALLBACK NULL
|
||||
#define meshtastic_DrawnShape_DEFAULT NULL
|
||||
#define meshtastic_DrawnShape_vertices_MSGTYPE meshtastic_CotGeoPoint
|
||||
|
||||
#define meshtastic_Marker_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, UENUM, kind, 1) \
|
||||
@@ -1874,27 +1726,6 @@ X(a, CALLBACK, SINGULAR, STRING, model, 8)
|
||||
#define meshtastic_SensorFov_CALLBACK pb_default_field_callback
|
||||
#define meshtastic_SensorFov_DEFAULT NULL
|
||||
|
||||
#define meshtastic_TakTalkMessage_FIELDLIST(X, a) \
|
||||
X(a, CALLBACK, SINGULAR, STRING, text, 1) \
|
||||
X(a, CALLBACK, SINGULAR, STRING, chatroom_id, 2) \
|
||||
X(a, CALLBACK, SINGULAR, STRING, lang, 3) \
|
||||
X(a, STATIC, SINGULAR, BOOL, from_voice, 4)
|
||||
#define meshtastic_TakTalkMessage_CALLBACK pb_default_field_callback
|
||||
#define meshtastic_TakTalkMessage_DEFAULT NULL
|
||||
|
||||
#define meshtastic_TakTalkRoomData_FIELDLIST(X, a) \
|
||||
X(a, CALLBACK, SINGULAR, STRING, sender_callsign, 1) \
|
||||
X(a, CALLBACK, SINGULAR, STRING, room_id, 2) \
|
||||
X(a, CALLBACK, SINGULAR, STRING, room_name, 3) \
|
||||
X(a, CALLBACK, REPEATED, STRING, participants, 4)
|
||||
#define meshtastic_TakTalkRoomData_CALLBACK pb_default_field_callback
|
||||
#define meshtastic_TakTalkRoomData_DEFAULT NULL
|
||||
|
||||
#define meshtastic_Marti_FIELDLIST(X, a) \
|
||||
X(a, CALLBACK, REPEATED, STRING, dest_callsign, 1)
|
||||
#define meshtastic_Marti_CALLBACK pb_default_field_callback
|
||||
#define meshtastic_Marti_DEFAULT NULL
|
||||
|
||||
#define meshtastic_TAKPacketV2_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, UENUM, cot_type_id, 1) \
|
||||
X(a, STATIC, SINGULAR, UENUM, how, 2) \
|
||||
@@ -1922,7 +1753,7 @@ X(a, STATIC, SINGULAR, STRING, cot_type_str, 23) \
|
||||
X(a, CALLBACK, SINGULAR, STRING, remarks, 24) \
|
||||
X(a, STATIC, OPTIONAL, MESSAGE, environment, 25) \
|
||||
X(a, STATIC, OPTIONAL, MESSAGE, sensor_fov, 26) \
|
||||
X(a, STATIC, OPTIONAL, MESSAGE, marti, 29) \
|
||||
X(a, STATIC, ONEOF, BOOL, (payload_variant,pli,payload_variant.pli), 30) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,chat,payload_variant.chat), 31) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,aircraft,payload_variant.aircraft), 32) \
|
||||
X(a, STATIC, ONEOF, BYTES, (payload_variant,raw_detail,payload_variant.raw_detail), 33) \
|
||||
@@ -1932,14 +1763,11 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,rab,payload_variant.rab), 3
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,route,payload_variant.route), 37) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,casevac,payload_variant.casevac), 38) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,emergency,payload_variant.emergency), 39) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,task,payload_variant.task), 40) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,taktalk,payload_variant.taktalk), 41) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,taktalk_room,payload_variant.taktalk_room), 42)
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,task,payload_variant.task), 40)
|
||||
#define meshtastic_TAKPacketV2_CALLBACK pb_default_field_callback
|
||||
#define meshtastic_TAKPacketV2_DEFAULT NULL
|
||||
#define meshtastic_TAKPacketV2_environment_MSGTYPE meshtastic_TAKEnvironment
|
||||
#define meshtastic_TAKPacketV2_sensor_fov_MSGTYPE meshtastic_SensorFov
|
||||
#define meshtastic_TAKPacketV2_marti_MSGTYPE meshtastic_Marti
|
||||
#define meshtastic_TAKPacketV2_payload_variant_chat_MSGTYPE meshtastic_GeoChat
|
||||
#define meshtastic_TAKPacketV2_payload_variant_aircraft_MSGTYPE meshtastic_AircraftTrack
|
||||
#define meshtastic_TAKPacketV2_payload_variant_shape_MSGTYPE meshtastic_DrawnShape
|
||||
@@ -1949,8 +1777,6 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,taktalk_room,payload_variant
|
||||
#define meshtastic_TAKPacketV2_payload_variant_casevac_MSGTYPE meshtastic_CasevacReport
|
||||
#define meshtastic_TAKPacketV2_payload_variant_emergency_MSGTYPE meshtastic_EmergencyAlert
|
||||
#define meshtastic_TAKPacketV2_payload_variant_task_MSGTYPE meshtastic_TaskRequest
|
||||
#define meshtastic_TAKPacketV2_payload_variant_taktalk_MSGTYPE meshtastic_TakTalkMessage
|
||||
#define meshtastic_TAKPacketV2_payload_variant_taktalk_room_MSGTYPE meshtastic_TakTalkRoomData
|
||||
|
||||
extern const pb_msgdesc_t meshtastic_TAKPacket_msg;
|
||||
extern const pb_msgdesc_t meshtastic_GeoChat_msg;
|
||||
@@ -1971,9 +1797,6 @@ extern const pb_msgdesc_t meshtastic_EmergencyAlert_msg;
|
||||
extern const pb_msgdesc_t meshtastic_TaskRequest_msg;
|
||||
extern const pb_msgdesc_t meshtastic_TAKEnvironment_msg;
|
||||
extern const pb_msgdesc_t meshtastic_SensorFov_msg;
|
||||
extern const pb_msgdesc_t meshtastic_TakTalkMessage_msg;
|
||||
extern const pb_msgdesc_t meshtastic_TakTalkRoomData_msg;
|
||||
extern const pb_msgdesc_t meshtastic_Marti_msg;
|
||||
extern const pb_msgdesc_t meshtastic_TAKPacketV2_msg;
|
||||
|
||||
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
|
||||
@@ -1996,27 +1819,20 @@ extern const pb_msgdesc_t meshtastic_TAKPacketV2_msg;
|
||||
#define meshtastic_TaskRequest_fields &meshtastic_TaskRequest_msg
|
||||
#define meshtastic_TAKEnvironment_fields &meshtastic_TAKEnvironment_msg
|
||||
#define meshtastic_SensorFov_fields &meshtastic_SensorFov_msg
|
||||
#define meshtastic_TakTalkMessage_fields &meshtastic_TakTalkMessage_msg
|
||||
#define meshtastic_TakTalkRoomData_fields &meshtastic_TakTalkRoomData_msg
|
||||
#define meshtastic_Marti_fields &meshtastic_Marti_msg
|
||||
#define meshtastic_TAKPacketV2_fields &meshtastic_TAKPacketV2_msg
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
/* meshtastic_TAKPacket_size depends on runtime parameters */
|
||||
/* meshtastic_GeoChat_size depends on runtime parameters */
|
||||
/* meshtastic_DrawnShape_size depends on runtime parameters */
|
||||
/* meshtastic_CasevacReport_size depends on runtime parameters */
|
||||
/* meshtastic_ZMistEntry_size depends on runtime parameters */
|
||||
/* meshtastic_SensorFov_size depends on runtime parameters */
|
||||
/* meshtastic_TakTalkMessage_size depends on runtime parameters */
|
||||
/* meshtastic_TakTalkRoomData_size depends on runtime parameters */
|
||||
/* meshtastic_Marti_size depends on runtime parameters */
|
||||
/* meshtastic_TAKPacketV2_size depends on runtime parameters */
|
||||
#define MESHTASTIC_MESHTASTIC_ATAK_PB_H_MAX_SIZE meshtastic_Route_size
|
||||
#define meshtastic_AircraftTrack_size 134
|
||||
#define meshtastic_Contact_size 242
|
||||
#define meshtastic_CotGeoPoint_size 12
|
||||
#define meshtastic_DrawnShape_size 553
|
||||
#define meshtastic_EmergencyAlert_size 100
|
||||
#define meshtastic_GeoChat_size 495
|
||||
#define meshtastic_Group_size 4
|
||||
#define meshtastic_Marker_size 191
|
||||
#define meshtastic_PLI_size 31
|
||||
@@ -2025,6 +1841,7 @@ extern const pb_msgdesc_t meshtastic_TAKPacketV2_msg;
|
||||
#define meshtastic_Route_size 1379
|
||||
#define meshtastic_Status_size 3
|
||||
#define meshtastic_TAKEnvironment_size 18
|
||||
#define meshtastic_TAKPacket_size 756
|
||||
#define meshtastic_TaskRequest_size 132
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -290,17 +290,15 @@ typedef enum _meshtastic_Config_LoRaConfig_RegionCode {
|
||||
meshtastic_Config_LoRaConfig_RegionCode_BR_902 = 26,
|
||||
/* ITU Region 1 Amateur Radio 2m band (144-146 MHz) */
|
||||
meshtastic_Config_LoRaConfig_RegionCode_ITU1_2M = 27,
|
||||
/* ITU Region 2 Amateur Radio 2m band (144-148 MHz) */
|
||||
meshtastic_Config_LoRaConfig_RegionCode_ITU2_2M = 28,
|
||||
/* ITU Region 2 / 3 Amateur Radio 2m band (144-148 MHz) */
|
||||
meshtastic_Config_LoRaConfig_RegionCode_ITU23_2M = 28,
|
||||
/* EU 866MHz band (Band no. 47b of 2006/771/EC and subsequent amendments) for Non-specific short-range devices (SRD) */
|
||||
meshtastic_Config_LoRaConfig_RegionCode_EU_866 = 29,
|
||||
/* EU 874MHz and 917MHz bands (Band no. 1 and 4 of 2022/172/EC and subsequent amendments) for Non-specific short-range devices (SRD) */
|
||||
meshtastic_Config_LoRaConfig_RegionCode_EU_874 = 30,
|
||||
meshtastic_Config_LoRaConfig_RegionCode_EU_917 = 31,
|
||||
/* EU 868MHz band, with narrow presets */
|
||||
meshtastic_Config_LoRaConfig_RegionCode_EU_N_868 = 32,
|
||||
/* ITU Region 3 Amateur Radio 2m band (144-148 MHz) */
|
||||
meshtastic_Config_LoRaConfig_RegionCode_ITU3_2M = 33
|
||||
meshtastic_Config_LoRaConfig_RegionCode_EU_N_868 = 32
|
||||
} meshtastic_Config_LoRaConfig_RegionCode;
|
||||
|
||||
/* Standard predefined channel settings
|
||||
@@ -736,8 +734,8 @@ extern "C" {
|
||||
#define _meshtastic_Config_DisplayConfig_CompassOrientation_ARRAYSIZE ((meshtastic_Config_DisplayConfig_CompassOrientation)(meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_270_INVERTED+1))
|
||||
|
||||
#define _meshtastic_Config_LoRaConfig_RegionCode_MIN meshtastic_Config_LoRaConfig_RegionCode_UNSET
|
||||
#define _meshtastic_Config_LoRaConfig_RegionCode_MAX meshtastic_Config_LoRaConfig_RegionCode_ITU3_2M
|
||||
#define _meshtastic_Config_LoRaConfig_RegionCode_ARRAYSIZE ((meshtastic_Config_LoRaConfig_RegionCode)(meshtastic_Config_LoRaConfig_RegionCode_ITU3_2M+1))
|
||||
#define _meshtastic_Config_LoRaConfig_RegionCode_MAX meshtastic_Config_LoRaConfig_RegionCode_EU_N_868
|
||||
#define _meshtastic_Config_LoRaConfig_RegionCode_ARRAYSIZE ((meshtastic_Config_LoRaConfig_RegionCode)(meshtastic_Config_LoRaConfig_RegionCode_EU_N_868+1))
|
||||
|
||||
#define _meshtastic_Config_LoRaConfig_ModemPreset_MIN meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST
|
||||
#define _meshtastic_Config_LoRaConfig_ModemPreset_MAX meshtastic_Config_LoRaConfig_ModemPreset_NARROW_SLOW
|
||||
|
||||
@@ -325,10 +325,6 @@ typedef enum _meshtastic_HardwareModel {
|
||||
meshtastic_HardwareModel_T_IMPULSE_PLUS = 135,
|
||||
/* Lilygo T-Echo Card */
|
||||
meshtastic_HardwareModel_T_ECHO_CARD = 136,
|
||||
/* Seeed Tracker L2 */
|
||||
meshtastic_HardwareModel_SEEED_WIO_TRACKER_L2 = 137,
|
||||
/* Elecrow CrowPanel Advance P4 models, ESP32-P4 and TFT with SX1262 radio plugin */
|
||||
meshtastic_HardwareModel_CROWPANEL_P4 = 138,
|
||||
/* ------------------------------------------------------------------------------------------------------------------------------------------
|
||||
Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits.
|
||||
------------------------------------------------------------------------------------------------------------------------------------------ */
|
||||
|
||||
@@ -793,13 +793,21 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef RF95_FAN_EN
|
||||
#ifdef RADIO_FAN_EN
|
||||
#ifdef RADIO_FAN_PWM
|
||||
#if defined(ARCH_ESP32)
|
||||
ledcWrite(1, c.payload_variant.lora.pa_fan_disabled ? 0 : (pa_fan_percentage * 2.55));
|
||||
#elif defined(ARCH_NRF52)
|
||||
analogWrite(RADIO_FAN_EN, c.payload_variant.lora.pa_fan_disabled ? 0 : (pa_fan_percentage * 2.55));
|
||||
#endif
|
||||
#else
|
||||
// Turn PA off if disabled by config
|
||||
if (c.payload_variant.lora.pa_fan_disabled) {
|
||||
digitalWrite(RF95_FAN_EN, LOW ^ 0);
|
||||
digitalWrite(RADIO_FAN_EN, LOW ^ 0);
|
||||
} else {
|
||||
digitalWrite(RF95_FAN_EN, HIGH ^ 0);
|
||||
digitalWrite(RADIO_FAN_EN, HIGH ^ 0);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
config.lora = validatedLora;
|
||||
|
||||
|
||||
@@ -83,11 +83,7 @@ void CannedMessageModule::LaunchWithDestination(NodeNum newDest, uint8_t newChan
|
||||
// Do NOT override explicit broadcast replies
|
||||
// Only reuse lastDest in LaunchRepeatDestination()
|
||||
|
||||
if (newDest == 0) {
|
||||
dest = NODENUM_BROADCAST;
|
||||
} else {
|
||||
dest = newDest;
|
||||
}
|
||||
dest = newDest;
|
||||
channel = newChannel;
|
||||
|
||||
lastDest = dest;
|
||||
@@ -127,11 +123,7 @@ void CannedMessageModule::LaunchFreetextWithDestination(NodeNum newDest, uint8_t
|
||||
// Do NOT override explicit broadcast replies
|
||||
// Only reuse lastDest in LaunchRepeatDestination()
|
||||
|
||||
if (newDest == 0) {
|
||||
dest = NODENUM_BROADCAST;
|
||||
} else {
|
||||
dest = newDest;
|
||||
}
|
||||
dest = newDest;
|
||||
channel = newChannel;
|
||||
|
||||
lastDest = dest;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include "StatusLEDModule.h"
|
||||
#include "MeshService.h"
|
||||
#include "configuration.h"
|
||||
#include "mesh/RadioInterface.h"
|
||||
#include <Arduino.h>
|
||||
|
||||
/*
|
||||
@@ -18,9 +17,6 @@ StatusLEDModule::StatusLEDModule() : concurrency::OSThread("StatusLEDModule")
|
||||
if (inputBroker)
|
||||
inputObserver.observe(inputBroker);
|
||||
#endif
|
||||
#ifdef LED_LORA
|
||||
loraRxObserver.observe(&RadioInterface::loraRxPacketObservable);
|
||||
#endif
|
||||
#ifdef NEOPIXEL_STATUS_POWER_PIN
|
||||
powerPixel.begin();
|
||||
powerPixel.clear();
|
||||
@@ -94,18 +90,6 @@ int StatusLEDModule::handleInputEvent(const InputEvent *event)
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#ifdef LED_LORA
|
||||
int StatusLEDModule::handleLoRaRx(uint32_t)
|
||||
{
|
||||
// Briefly flash LED_LORA on each received packet. Turn it on now (we share the main thread with
|
||||
// the radio's receive handler, so this is safe) and wake runOnce() at flash end to turn it off.
|
||||
digitalWrite(LED_LORA, LED_STATE_ON);
|
||||
LORA_LED_state = LED_STATE_ON;
|
||||
LORA_LED_starttime = millis();
|
||||
setIntervalFromNow(LORA_RX_LED_FLASH_MS);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int32_t StatusLEDModule::runOnce()
|
||||
{
|
||||
@@ -131,12 +115,6 @@ int32_t StatusLEDModule::runOnce()
|
||||
CHARGE_LED_state = LED_STATE_OFF;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
#if defined(LED_HEARTBEAT)
|
||||
// If we are using the heartbeat, as in the Thinknode M4, we need to explicitly turn off the charge LED
|
||||
// This probably implies that in the future we need to stop re-using this bool for multiple purposes.
|
||||
CHARGE_LED_state = LED_STATE_OFF;
|
||||
#endif
|
||||
}
|
||||
// If we want a LED to be dedicated to the simple hearbeat, we can use that instead of the charge LED
|
||||
#if defined(LED_HEARTBEAT)
|
||||
@@ -164,7 +142,6 @@ int32_t StatusLEDModule::runOnce()
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef LED_PAIRING
|
||||
if (!config.bluetooth.enabled || PAIRING_LED_starttime + 30 * 1000 < millis() || doing_fast_blink) {
|
||||
PAIRING_LED_state = LED_STATE_OFF;
|
||||
} else if (ble_state == unpaired) {
|
||||
@@ -179,7 +156,6 @@ int32_t StatusLEDModule::runOnce()
|
||||
} else {
|
||||
PAIRING_LED_state = LED_STATE_ON;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Override if disabled in config
|
||||
if (config.device.led_heartbeat_disabled) {
|
||||
@@ -251,20 +227,6 @@ int32_t StatusLEDModule::runOnce()
|
||||
digitalWrite(Battery_LED_4, chargeIndicatorLED4);
|
||||
#endif
|
||||
|
||||
#ifdef LED_LORA
|
||||
// End the LoRa-RX flash once its duration has elapsed; otherwise make sure we come back
|
||||
// exactly at flash end (only ever clamp my_interval down, so other LED timing is preserved).
|
||||
if (LORA_LED_state == LED_STATE_ON) {
|
||||
uint32_t elapsed = millis() - LORA_LED_starttime;
|
||||
if (elapsed >= LORA_RX_LED_FLASH_MS) {
|
||||
digitalWrite(LED_LORA, LED_STATE_OFF);
|
||||
LORA_LED_state = LED_STATE_OFF;
|
||||
} else if ((uint32_t)my_interval > LORA_RX_LED_FLASH_MS - elapsed) {
|
||||
my_interval = LORA_RX_LED_FLASH_MS - elapsed;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return (my_interval);
|
||||
}
|
||||
|
||||
|
||||
@@ -43,9 +43,6 @@ class StatusLEDModule : private concurrency::OSThread
|
||||
#if !MESHTASTIC_EXCLUDE_INPUTBROKER
|
||||
int handleInputEvent(const InputEvent *arg);
|
||||
#endif
|
||||
#ifdef LED_LORA
|
||||
int handleLoRaRx(uint32_t sender);
|
||||
#endif
|
||||
|
||||
void setPowerLED(bool);
|
||||
|
||||
@@ -68,10 +65,6 @@ class StatusLEDModule : private concurrency::OSThread
|
||||
CallbackObserver<StatusLEDModule, const InputEvent *> inputObserver =
|
||||
CallbackObserver<StatusLEDModule, const InputEvent *>(this, &StatusLEDModule::handleInputEvent);
|
||||
#endif
|
||||
#ifdef LED_LORA
|
||||
CallbackObserver<StatusLEDModule, uint32_t> loraRxObserver =
|
||||
CallbackObserver<StatusLEDModule, uint32_t>(this, &StatusLEDModule::handleLoRaRx);
|
||||
#endif
|
||||
|
||||
private:
|
||||
bool CHARGE_LED_state = LED_STATE_OFF;
|
||||
@@ -84,11 +77,6 @@ class StatusLEDModule : private concurrency::OSThread
|
||||
uint32_t lastUserbuttonTime = 0;
|
||||
uint32_t POWER_LED_starttime = 0;
|
||||
bool doing_fast_blink = false;
|
||||
#ifdef LED_LORA
|
||||
static constexpr uint32_t LORA_RX_LED_FLASH_MS = 100;
|
||||
bool LORA_LED_state = LED_STATE_OFF;
|
||||
uint32_t LORA_LED_starttime = 0;
|
||||
#endif
|
||||
|
||||
enum PowerState { discharging, charging, charged, critical };
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#endif
|
||||
|
||||
#include "esp_mac.h"
|
||||
#include "freertosinc.h"
|
||||
#include "meshUtils.h"
|
||||
#include "sleep.h"
|
||||
#include "soc/rtc.h"
|
||||
@@ -262,8 +261,6 @@ void cpuDeepSleep(uint32_t msecToWake)
|
||||
// We want RTC peripherals to stay on
|
||||
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
|
||||
|
||||
// User shutdown (DELAY_FOREVER / portMAX_DELAY): no RTC timer — align with nRF52 system_off semantics.
|
||||
if (msecToWake != portMAX_DELAY)
|
||||
esp_sleep_enable_timer_wakeup(msecToWake * 1000ULL); // call expects usecs
|
||||
esp_deep_sleep_start();
|
||||
esp_sleep_enable_timer_wakeup(msecToWake * 1000ULL); // call expects usecs
|
||||
esp_deep_sleep_start(); // TBD mA sleep current (battery)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
#include "configuration.h"
|
||||
|
||||
#ifdef RADIOMASTER_NOMAD_GEMINI
|
||||
|
||||
#include "RadioExternalPa.h"
|
||||
#include <Arduino.h>
|
||||
|
||||
/**
|
||||
* RadioMaster Nomad Gemini external analog PA driver.
|
||||
*
|
||||
* The Nomad's PA is biased by an analog control voltage on the APC2 pin
|
||||
* (RADIO_PA_APC2_PIN = GPIO26 = ESP32 DAC channel 2), driven with dacWrite()
|
||||
* (0-255 -> 0-3.3V). The DAC is essentially a fixed bias; the actual output power
|
||||
* is set by driving the LR1121 chip at a (negative) output power and letting the PA
|
||||
* add ~25-31 dB of gain.
|
||||
*
|
||||
* The calibration below is derived from the ExpressLRS hardware target
|
||||
* "TX/Radiomaster Nomad.json" (power_values = APC2 DAC codes, power_values2 = chip
|
||||
* output dBm). These values reproduce ELRS behaviour but have NOT been validated on
|
||||
* a bench against a power meter for Meshtastic — verify before trusting at 1 W, both
|
||||
* for PA safety and for regulatory compliance.
|
||||
*
|
||||
* TODO: dual-band (Gemini) operation uses ELRS power_values_dual and a second radio;
|
||||
* once JANUS_RADIO is implemented, branch on freqHz / active radio here.
|
||||
*/
|
||||
|
||||
// total dBm corresponds to the ELRS power presets 10/25/50/100/250/500/1000 mW.
|
||||
static const struct {
|
||||
int8_t totalDbm; // desired total radiated power
|
||||
int8_t chipDbm; // LR1121 output power register (ELRS power_values2)
|
||||
uint8_t apc2; // APC2 DAC code (ELRS power_values)
|
||||
} NOMAD_PA_CAL[] = {
|
||||
{10, -17, 120}, // 10 mW
|
||||
{14, -16, 120}, // 25 mW
|
||||
{17, -14, 120}, // 50 mW
|
||||
{20, -11, 120}, // 100 mW
|
||||
{24, -7, 120}, // 250 mW
|
||||
{27, -3, 120}, // 500 mW
|
||||
{30, 5, 95}, // 1000 mW (1 W)
|
||||
};
|
||||
static const size_t NOMAD_PA_CAL_N = sizeof(NOMAD_PA_CAL) / sizeof(NOMAD_PA_CAL[0]);
|
||||
|
||||
// APC2 bias chosen for the currently-configured power level; applied on TX, dropped
|
||||
// to 0 for RX/idle/sleep so the PA only draws current while transmitting.
|
||||
static uint8_t nomadApc2Level = 0;
|
||||
|
||||
// Runs at the start of setup(), before the LoRa radio is initialized.
|
||||
void earlyInitVariant()
|
||||
{
|
||||
dacWrite(RADIO_PA_APC2_PIN, 0); // bias the PA off until we actually transmit
|
||||
nomadApc2Level = 0;
|
||||
}
|
||||
|
||||
int8_t radioExternalPaMapPower(int8_t requestedTotalDbm, float freqHz)
|
||||
{
|
||||
(void)freqHz; // single-band for now (see dual-band TODO above)
|
||||
|
||||
if (requestedTotalDbm <= NOMAD_PA_CAL[0].totalDbm) {
|
||||
nomadApc2Level = NOMAD_PA_CAL[0].apc2;
|
||||
return NOMAD_PA_CAL[0].chipDbm;
|
||||
}
|
||||
const size_t last = NOMAD_PA_CAL_N - 1;
|
||||
if (requestedTotalDbm >= NOMAD_PA_CAL[last].totalDbm) {
|
||||
nomadApc2Level = NOMAD_PA_CAL[last].apc2;
|
||||
return NOMAD_PA_CAL[last].chipDbm;
|
||||
}
|
||||
|
||||
// Piecewise-linear interpolation of chip dBm between the bracketing points.
|
||||
for (size_t i = 1; i < NOMAD_PA_CAL_N; i++) {
|
||||
if (requestedTotalDbm <= NOMAD_PA_CAL[i].totalDbm) {
|
||||
const int t0 = NOMAD_PA_CAL[i - 1].totalDbm, t1 = NOMAD_PA_CAL[i].totalDbm;
|
||||
const int c0 = NOMAD_PA_CAL[i - 1].chipDbm, c1 = NOMAD_PA_CAL[i].chipDbm;
|
||||
const int chip = c0 + ((c1 - c0) * (requestedTotalDbm - t0) + (t1 - t0) / 2) / (t1 - t0); // round-to-nearest
|
||||
nomadApc2Level = NOMAD_PA_CAL[i - 1].apc2; // only the top point lowers the bias
|
||||
return (int8_t)chip;
|
||||
}
|
||||
}
|
||||
nomadApc2Level = NOMAD_PA_CAL[last].apc2; // unreachable
|
||||
return NOMAD_PA_CAL[last].chipDbm;
|
||||
}
|
||||
|
||||
void radioExternalPaTxEnable()
|
||||
{
|
||||
dacWrite(RADIO_PA_APC2_PIN, nomadApc2Level);
|
||||
}
|
||||
|
||||
void radioExternalPaRxIdle()
|
||||
{
|
||||
dacWrite(RADIO_PA_APC2_PIN, 0);
|
||||
}
|
||||
|
||||
void radioExternalPaSleep()
|
||||
{
|
||||
dacWrite(RADIO_PA_APC2_PIN, 0);
|
||||
}
|
||||
|
||||
#endif // RADIOMASTER_NOMAD_GEMINI
|
||||
@@ -12,7 +12,7 @@
|
||||
#define LORA_MISO 19
|
||||
#define LORA_MOSI 23
|
||||
#define LORA_CS 5
|
||||
#define RF95_FAN_EN 17
|
||||
#define RADIO_FAN_EN 17
|
||||
|
||||
// This is a LED_WS2812 not a standard LED
|
||||
#define HAS_NEOPIXEL // Enable the use of neopixels
|
||||
|
||||
@@ -46,7 +46,8 @@
|
||||
FAN is active at 250mW on it's ExpressLRS Firmware.
|
||||
This FAN has TACHO signal on Pin 27 for use with PWM.
|
||||
*/
|
||||
#define RF95_FAN_EN 2
|
||||
#define RADIO_FAN_EN 2
|
||||
#define RADIO_FAN_PWM
|
||||
|
||||
/*
|
||||
LED PIN setup and it has a NeoPixel LED.
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
This unit has a FAN built-in.
|
||||
FAN is active at 250mW on it's ExpressLRS Firmware.
|
||||
*/
|
||||
#define RF95_FAN_EN 2
|
||||
#define RADIO_FAN_EN 2
|
||||
|
||||
/*
|
||||
LED PIN setup.
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
[env:radiomaster_nomad_gemini]
|
||||
extends = esp32_base
|
||||
board = esp32doit-devkit-v1
|
||||
build_flags =
|
||||
${esp32_base.build_flags}
|
||||
-DRADIOMASTER_NOMAD_GEMINI
|
||||
-DPRIVATE_HW
|
||||
-DVTABLES_IN_FLASH=1
|
||||
-DCONFIG_DISABLE_HAL_LOCKS=1
|
||||
-O2
|
||||
-Ivariants/esp32/radiomaster_nomad_gemini
|
||||
-DMESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR=1
|
||||
-DMESHTASTIC_EXCLUDE_I2C=1
|
||||
-DRADIOLIB_EXCLUDE_SX128X=1
|
||||
-DRADIOLIB_EXCLUDE_SX127X=1
|
||||
-DRADIOLIB_EXCLUDE_SX126X=1
|
||||
board_build.f_cpu = 240000000L
|
||||
upload_protocol = esptool
|
||||
lib_deps =
|
||||
${esp32_base.lib_deps}
|
||||
@@ -0,0 +1,56 @@
|
||||
#include "RadioLib.h"
|
||||
|
||||
static const uint32_t rfswitch_dio_pins[] = {RADIOLIB_LR11X0_DIO5, RADIOLIB_LR11X0_DIO6, RADIOLIB_LR11X0_DIO7,
|
||||
RADIOLIB_LR11X0_DIO8, RADIOLIB_NC};
|
||||
|
||||
static const Module::RfSwitchMode_t rfswitch_table[] = {
|
||||
// mode DIO5 DIO6 DIO7 DIO8
|
||||
{LR11x0::MODE_STBY, {LOW, LOW, LOW, LOW}}, {LR11x0::MODE_RX, {LOW, LOW, HIGH, LOW}},
|
||||
{LR11x0::MODE_TX, {LOW, LOW, LOW, HIGH}}, {LR11x0::MODE_TX_HP, {LOW, LOW, LOW, HIGH}},
|
||||
{LR11x0::MODE_TX_HF, {LOW, HIGH, LOW, LOW}}, {LR11x0::MODE_GNSS, {LOW, LOW, LOW, LOW}},
|
||||
{LR11x0::MODE_WIFI, {HIGH, LOW, LOW, LOW}}, END_OF_MODE_TABLE,
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
DIO5: RXEN 2.4GHz
|
||||
DIO6: TXEN 2.4GHz
|
||||
DIO7: RXEN 900MHz
|
||||
DIO8: TXEN 900MHz
|
||||
|
||||
|
||||
"radio_dcdc": true,
|
||||
"radio_rfo_hf": true,
|
||||
|
||||
"power_apc2": 26,
|
||||
"power_min": 0,
|
||||
"power_high": 6,
|
||||
"power_max": 6,
|
||||
"power_default": 3,
|
||||
"power_control": 3, POWER_OUTPUT_DACWRITE // use internal dacWrite function to set value on GPIO_PIN_RFamp_APC2
|
||||
[0, 1, 2, 3, 4, 5, 6 ] // 0-6
|
||||
"power_values": [120, 120, 120, 120, 120, 120, 95] // DAC Value
|
||||
"power_values2": [-17, -16, -14, -11, -7, -3, 5 ] // 900M
|
||||
"power_values_dual": [-18, -14, -8, -6, -2, 3, 5 ] // 2.4G
|
||||
|
||||
// default value 0 means direct!
|
||||
#define POWER_OUTPUT_DACWRITE (hardware_int(HARDWARE_power_control)==3)
|
||||
#define POWER_OUTPUT_VALUES hardware_i16_array(HARDWARE_power_values)
|
||||
#define POWER_OUTPUT_VALUES_COUNT hardware_int(HARDWARE_power_values_count)
|
||||
#define POWER_OUTPUT_VALUES2 hardware_i16_array(HARDWARE_power_values2)
|
||||
#define POWER_OUTPUT_VALUES_DUAL hardware_i16_array(HARDWARE_power_values_dual)
|
||||
#define POWER_OUTPUT_VALUES_DUAL_COUNT hardware_int(HARDWARE_power_values_dual_count)
|
||||
|
||||
#define GPIO_PIN_FAN_EN hardware_pin(HARDWARE_misc_fan_en)
|
||||
|
||||
case PWR_10mW: return 10;
|
||||
case PWR_25mW: return 14;
|
||||
case PWR_50mW: return 17;
|
||||
case PWR_100mW: return 20;
|
||||
case PWR_250mW: return 24;
|
||||
case PWR_500mW: return 27;
|
||||
case PWR_1000mW: return 30;
|
||||
|
||||
95 -> +25dBm
|
||||
120 -> +24dBm
|
||||
*/
|
||||
@@ -0,0 +1,68 @@
|
||||
#define HAS_SCREEN 0
|
||||
#define HAS_WIRE 0
|
||||
#define HAS_GPS 0
|
||||
#undef GPS_RX_PIN
|
||||
#undef GPS_TX_PIN
|
||||
|
||||
#define PIN_SPI_MISO 33
|
||||
#define PIN_SPI_MOSI 32
|
||||
#define PIN_SPI_SCK 25
|
||||
#define PIN_SPI_NSS 27
|
||||
|
||||
#define LORA_RESET 15
|
||||
#define LORA_DIO1 37
|
||||
#define LORA_DIO2 36
|
||||
#define LORA_SCK PIN_SPI_SCK
|
||||
#define LORA_MISO PIN_SPI_MISO
|
||||
#define LORA_MOSI PIN_SPI_MOSI
|
||||
#define LORA_CS PIN_SPI_NSS
|
||||
|
||||
// supported modules list
|
||||
#define USE_LR1121
|
||||
|
||||
#define LR1121_IRQ_PIN LORA_DIO1
|
||||
#define LR1121_NRESET_PIN LORA_RESET
|
||||
#define LR1121_BUSY_PIN LORA_DIO2
|
||||
#define LR1121_SPI_NSS_PIN LORA_CS
|
||||
#define LR1121_SPI_SCK_PIN LORA_SCK
|
||||
#define LR1121_SPI_MOSI_PIN LORA_MOSI
|
||||
#define LR1121_SPI_MISO_PIN LORA_MISO
|
||||
|
||||
// Caps for the LR1121 *chip* output. The external analog PA (driven via the APC2
|
||||
// DAC pin, see RADIO_PA_APC2_PIN below) provides the rest of the gain, so the chip
|
||||
// itself is driven low. See src/platform/extra_variants/radiomaster_nomad_gemini.
|
||||
#define LR1110_MAX_POWER 5
|
||||
// 2.4G Part
|
||||
#define LR1120_MAX_POWER 5
|
||||
|
||||
// not yet implemented
|
||||
#define JANUS_RADIO
|
||||
#define LR1121_IRQ2_PIN 34
|
||||
#define LR1121_NRESET2_PIN 21
|
||||
#define LR1121_BUSY2_PIN 39
|
||||
#define LR1121_SPI_NSS2_PIN 13
|
||||
|
||||
// TODO: check if this is correct
|
||||
// #define LR11X0_DIO3_TCXO_VOLTAGE 1.6
|
||||
#define LR11X0_DIO_AS_RF_SWITCH
|
||||
|
||||
#define HAS_NEOPIXEL // Enable the use of neopixels
|
||||
#define NEOPIXEL_COUNT 2 // How many neopixels are connected
|
||||
#define NEOPIXEL_DATA 22 // GPIO pin used to send data to the neopixels
|
||||
#define NEOPIXEL_TYPE (NEO_GRB + NEO_KHZ800) // Type of neopixels in use
|
||||
#define ENABLE_AMBIENTLIGHTING // Turn on Ambient Lighting
|
||||
|
||||
// Primary button is GPIO14 (ELRS "button"); GPIO12 is the second button ("button2").
|
||||
// NOTE: GPIO34 is the second radio's DIO1 (LR1121_IRQ2_PIN) and is input-only with no
|
||||
// internal pull resistor, so it must NOT be reused as a button.
|
||||
#define BUTTON_PIN 14
|
||||
#define BUTTON_NEED_PULLUP
|
||||
|
||||
#undef EXT_NOTIFY_OUT
|
||||
|
||||
#define RADIO_FAN_EN 2
|
||||
|
||||
// Analog PA bias control (ELRS APC2). GPIO26 = ESP32 DAC channel 2, driven with
|
||||
// dacWrite() (0-255 -> 0-3.3V). Defining this enables the external-PA driver in
|
||||
// src/platform/extra_variants/radiomaster_nomad_gemini/variant.cpp.
|
||||
#define RADIO_PA_APC2_PIN 26
|
||||
@@ -18,9 +18,7 @@
|
||||
#define BATTERY_PIN 8
|
||||
#define ADC_CHANNEL ADC1_GPIO8_CHANNEL
|
||||
|
||||
#define ADC_MULTIPLIER 2.0
|
||||
|
||||
#define OCV_ARRAY 4100, 4050, 3990, 3890, 3800, 3720, 3630, 3530, 3420, 3300, 3100
|
||||
#define ADC_MULTIPLIER 2.0 // 2.0 + 10% for correction of display undervoltage.
|
||||
|
||||
#define PIN_BUZZER 9
|
||||
|
||||
|
||||
@@ -9,6 +9,4 @@ void initVariant()
|
||||
{
|
||||
pinMode(LED_PAIRING, OUTPUT);
|
||||
digitalWrite(LED_PAIRING, !LED_STATE_ON); // Turn off the LED to start
|
||||
pinMode(LED_LORA, OUTPUT);
|
||||
digitalWrite(LED_LORA, !LED_STATE_ON); // Turn off the LED to start
|
||||
}
|
||||
@@ -37,9 +37,6 @@ extends = env:picomputer-s3
|
||||
build_flags =
|
||||
${env:picomputer-s3.build_flags}
|
||||
-D MESHTASTIC_EXCLUDE_WEBSERVER=1
|
||||
; device-ui's I2CKeyboardScanner unconditionally calls Wire.begin(I2C_SDA, I2C_SCL);
|
||||
-D I2C_SDA=8
|
||||
-D I2C_SCL=9
|
||||
-D INPUTDRIVER_MATRIX_TYPE=1
|
||||
-D USE_PIN_BUZZER=PIN_BUZZER
|
||||
-D USE_SX127x
|
||||
|
||||
@@ -19,14 +19,14 @@ custom_meshtastic_support_level = 1
|
||||
custom_meshtastic_display_name = RAK WisMesh Tap V2
|
||||
custom_meshtastic_images = rak-wismesh-tap-v2.svg
|
||||
custom_meshtastic_tags = RAK
|
||||
custom_meshtastic_partition_scheme = 16MB
|
||||
custom_meshtastic_partition_scheme = 8MB
|
||||
custom_meshtastic_has_mui = true
|
||||
|
||||
extends = esp32s3_base
|
||||
board = wiscore_rak3312
|
||||
board_check = true
|
||||
upload_protocol = esptool
|
||||
board_build.partitions = default_16MB.csv
|
||||
board_build.partitions = default_8MB.csv
|
||||
|
||||
build_flags =
|
||||
${esp32s3_base.build_flags}
|
||||
|
||||
@@ -53,7 +53,6 @@
|
||||
#define BATTERY_PIN 1
|
||||
#define ADC_CHANNEL ADC1_GPIO1_CHANNEL
|
||||
#define ADC_MULTIPLIER 1.667
|
||||
#define OCV_ARRAY 4160, 4020, 3940, 3870, 3810, 3760, 3740, 3720, 3680, 3620, 2990
|
||||
|
||||
#define PIN_BUZZER 38
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@
|
||||
// Fan control
|
||||
#define FAN_CTRL_PIN 41
|
||||
// Meshtastic standard fan control pin macro
|
||||
#define RF95_FAN_EN FAN_CTRL_PIN
|
||||
#define RADIO_FAN_EN FAN_CTRL_PIN
|
||||
|
||||
// PA Ramp Time - T-Beam 1W requires >800us stabilization (default is 200us)
|
||||
// Value 0x05 = RADIOLIB_SX126X_PA_RAMP_800U
|
||||
|
||||
@@ -55,9 +55,9 @@ build_flags =
|
||||
-D HAS_TFT=1
|
||||
-D USE_I2S_BUZZER
|
||||
-D RAM_SIZE=5120
|
||||
-D LV_LVGL_H_INCLUDE_SIMPLE
|
||||
-D LV_CONF_INCLUDE_SIMPLE
|
||||
-D LV_COMP_CONF_INCLUDE_SIMPLE
|
||||
-D LV_LVGL_H_INCLUDE_SIMPLE
|
||||
-D LV_CONF_INCLUDE_SIMPLE
|
||||
-D LV_COMP_CONF_INCLUDE_SIMPLE
|
||||
-D LV_USE_SYSMON=0
|
||||
-D LV_USE_PROFILER=0
|
||||
-D LV_USE_PERF_MONITOR=0
|
||||
@@ -72,7 +72,6 @@ build_flags =
|
||||
; -D CALIBRATE_TOUCH=0
|
||||
-D LGFX_SCREEN_WIDTH=240
|
||||
-D LGFX_SCREEN_HEIGHT=320
|
||||
-D LGFX_BUFSIZE=153600
|
||||
-D DISPLAY_SIZE=320x240 ; landscape mode
|
||||
-D LGFX_DRIVER=LGFX_TDECK
|
||||
-D GFX_DRIVER_INC=\"graphics/LGFX/LGFX_T_DECK.h\"
|
||||
@@ -80,11 +79,13 @@ build_flags =
|
||||
; -D GFX_DRIVER_INC=\"graphics/LVGL/LVGL_T_DECK.h\"
|
||||
; -D LV_USE_ST7789=1
|
||||
-D VIEW_320x240
|
||||
; -D USE_DOUBLE_BUFFER
|
||||
-D USE_PACKET_API
|
||||
-D MAP_FULL_REDRAW
|
||||
; -D CUSTOM_TOUCH_DRIVER
|
||||
-D CUSTOM_TOUCH_DRIVER
|
||||
|
||||
lib_deps =
|
||||
${env:t-deck.lib_deps}
|
||||
${device-ui_base.lib_deps}
|
||||
;https://github.com/bitbank2/bb_captouch/archive/refs/tags/1.3.1.zip
|
||||
# renovate: datasource=github-tags depName=bb_captouch packageName=bitbank2/bb_captouch
|
||||
https://github.com/bitbank2/bb_captouch/archive/refs/tags/1.3.1.zip
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
[portduino_base]
|
||||
platform =
|
||||
# renovate: datasource=git-refs depName=platform-native packageName=https://github.com/meshtastic/platform-native gitBranch=develop
|
||||
https://github.com/meshtastic/platform-native/archive/61067ac3774e4fe27aa9762c72cebea507f116c8.zip
|
||||
https://github.com/meshtastic/platform-native/archive/cab4b21d902973e43c938dab3cf4844ba02547ec.zip
|
||||
framework = arduino
|
||||
|
||||
build_src_filter =
|
||||
|
||||
@@ -56,8 +56,8 @@ void initVariant()
|
||||
digitalWrite(DHT_POWER, HIGH);
|
||||
pinMode(Battery_POWER, OUTPUT);
|
||||
digitalWrite(Battery_POWER, HIGH);
|
||||
pinMode(PIN_GPS_EN, OUTPUT);
|
||||
digitalWrite(PIN_GPS_EN, HIGH);
|
||||
pinMode(GPS_POWER, OUTPUT);
|
||||
digitalWrite(GPS_POWER, HIGH);
|
||||
}
|
||||
|
||||
// called from main-nrf52.cpp during the cpuDeepSleep() function
|
||||
@@ -74,11 +74,12 @@ void variant_shutdown()
|
||||
digitalWrite(DHT_POWER, LOW);
|
||||
digitalWrite(ACC_POWER, LOW);
|
||||
digitalWrite(Battery_POWER, LOW);
|
||||
digitalWrite(GPS_POWER, LOW);
|
||||
|
||||
// This sets the pin to OUTPUT and LOW for the pins *not* in the if block.
|
||||
for (int pin = 0; pin < 48; pin++) {
|
||||
if (pin == PIN_POWER_USB || pin == BUTTON_PIN || pin == PIN_EN1 || pin == PIN_EN2 || pin == DHT_POWER ||
|
||||
pin == ACC_POWER || pin == Battery_POWER || pin == PIN_GPS_EN || pin == LR1110_SPI_MISO_PIN ||
|
||||
pin == ACC_POWER || pin == Battery_POWER || pin == GPS_POWER || pin == LR1110_SPI_MISO_PIN ||
|
||||
pin == LR1110_SPI_MOSI_PIN || pin == LR1110_SPI_SCK_PIN || pin == LR1110_SPI_NSS_PIN || pin == LR1110_BUSY_PIN ||
|
||||
pin == LR1110_NRESET_PIN || pin == LR1110_IRQ_PIN || pin == GPS_TX_PIN || pin == GPS_RX_PIN || pin == LED_GREEN ||
|
||||
pin == LED_RED || pin == LED_BLUE) {
|
||||
@@ -100,4 +101,4 @@ void variant_shutdown()
|
||||
nrf_gpio_cfg_input(PIN_POWER_USB, NRF_GPIO_PIN_PULLDOWN); // Configure the pin to be woken up as an input
|
||||
nrf_gpio_pin_sense_t sense2 = NRF_GPIO_PIN_SENSE_HIGH;
|
||||
nrf_gpio_cfg_sense_set(PIN_POWER_USB, sense2);
|
||||
}
|
||||
}
|
||||
@@ -37,8 +37,7 @@ extern "C" {
|
||||
|
||||
// Power Pin
|
||||
#define NRF_APM
|
||||
#define PIN_GPS_EN 14
|
||||
#define GPS_EN_ACTIVE HIGH
|
||||
#define GPS_POWER 14
|
||||
#define PIN_POWER_USB 31
|
||||
#define EXT_PWR_DETECT PIN_POWER_USB
|
||||
#define PIN_POWER_DONE 24
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
[VERSION]
|
||||
major = 2
|
||||
minor = 7
|
||||
build = 27
|
||||
build = 25
|
||||
|
||||
Reference in New Issue
Block a user