Compare commits

..
96 changed files with 643 additions and 993 deletions
+2 -2
View File
@@ -76,7 +76,7 @@ runs:
done done
- name: PlatformIO ${{ inputs.arch }} download cache - name: PlatformIO ${{ inputs.arch }} download cache
uses: actions/cache@v5 uses: actions/cache@v4
with: with:
path: ~/.platformio/.cache path: ~/.platformio/.cache
key: pio-cache-${{ inputs.arch }}-${{ hashFiles('.github/actions/**', '**.ini') }} key: pio-cache-${{ inputs.arch }}-${{ hashFiles('.github/actions/**', '**.ini') }}
@@ -100,7 +100,7 @@ runs:
id: version id: version
- name: Store binaries as an artifact - name: Store binaries as an artifact
uses: actions/upload-artifact@v6 uses: actions/upload-artifact@v5
with: with:
name: firmware-${{ inputs.arch }}-${{ inputs.board }}-${{ steps.version.outputs.long }} name: firmware-${{ inputs.arch }}-${{ inputs.board }}-${{ steps.version.outputs.long }}
overwrite: true overwrite: true
+1 -1
View File
@@ -64,7 +64,7 @@ jobs:
PKG_VERSION: ${{ steps.version.outputs.deb }} PKG_VERSION: ${{ steps.version.outputs.deb }}
- name: Store binaries as an artifact - name: Store binaries as an artifact
uses: actions/upload-artifact@v6 uses: actions/upload-artifact@v5
with: with:
name: firmware-debian-${{ steps.version.outputs.deb }}~${{ inputs.series }}-src name: firmware-debian-${{ steps.version.outputs.deb }}~${{ inputs.series }}-src
overwrite: true overwrite: true
+4 -6
View File
@@ -56,21 +56,19 @@ jobs:
ota_firmware_source: ${{ steps.ota_dir.outputs.src || '' }} ota_firmware_source: ${{ steps.ota_dir.outputs.src || '' }}
ota_firmware_target: ${{ steps.ota_dir.outputs.tgt || '' }} ota_firmware_target: ${{ steps.ota_dir.outputs.tgt || '' }}
- name: Job summary - name: Echo manifest from release/firmware-*.mt.json to job summary
if: ${{ always() }}
env: env:
PIO_ENV: ${{ inputs.pio_env }} PIO_ENV: ${{ inputs.pio_env }}
run: | run: |
echo "## $PIO_ENV" >> $GITHUB_STEP_SUMMARY echo "## Manifest: \`$PIO_ENV\`" >> $GITHUB_STEP_SUMMARY
echo "<details><summary><strong>Manifest</strong></summary>" >> $GITHUB_STEP_SUMMARY
echo '' >> $GITHUB_STEP_SUMMARY
echo '```json' >> $GITHUB_STEP_SUMMARY echo '```json' >> $GITHUB_STEP_SUMMARY
cat release/firmware-*.mt.json >> $GITHUB_STEP_SUMMARY cat release/firmware-*.mt.json >> $GITHUB_STEP_SUMMARY
echo '' >> $GITHUB_STEP_SUMMARY echo '' >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY echo '```' >> $GITHUB_STEP_SUMMARY
echo "</details>" >> $GITHUB_STEP_SUMMARY
- name: Store binaries as an artifact - name: Store binaries as an artifact
uses: actions/upload-artifact@v6 uses: actions/upload-artifact@v5
id: upload id: upload
with: with:
name: firmware-${{ inputs.platform }}-${{ inputs.pio_env }}-${{ inputs.version }} name: firmware-${{ inputs.platform }}-${{ inputs.pio_env }}-${{ inputs.version }}
+4 -4
View File
@@ -98,7 +98,7 @@ jobs:
ref: ${{github.event.pull_request.head.ref}} ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}} repository: ${{github.event.pull_request.head.repo.full_name}}
- uses: actions/download-artifact@v7 - uses: actions/download-artifact@v6
with: with:
path: ./ path: ./
pattern: firmware-*-* pattern: firmware-*-*
@@ -111,7 +111,7 @@ jobs:
run: mv -b -t ./ ./bin/device-*.sh ./bin/device-*.bat run: mv -b -t ./ ./bin/device-*.sh ./bin/device-*.bat
- name: Repackage in single firmware zip - name: Repackage in single firmware zip
uses: actions/upload-artifact@v6 uses: actions/upload-artifact@v5
with: with:
name: firmware-${{inputs.target}}-${{ needs.version.outputs.long }} name: firmware-${{inputs.target}}-${{ needs.version.outputs.long }}
overwrite: true overwrite: true
@@ -127,7 +127,7 @@ jobs:
./Meshtastic_nRF52_factory_erase*.uf2 ./Meshtastic_nRF52_factory_erase*.uf2
retention-days: 30 retention-days: 30
- uses: actions/download-artifact@v7 - uses: actions/download-artifact@v6
with: with:
pattern: firmware-*-${{ needs.version.outputs.long }} pattern: firmware-*-${{ needs.version.outputs.long }}
merge-multiple: true merge-multiple: true
@@ -146,7 +146,7 @@ jobs:
run: zip -j -9 -r ./firmware-${{inputs.target}}-${{ needs.version.outputs.long }}.zip ./output run: zip -j -9 -r ./firmware-${{inputs.target}}-${{ needs.version.outputs.long }}.zip ./output
- name: Repackage in single elfs zip - name: Repackage in single elfs zip
uses: actions/upload-artifact@v6 uses: actions/upload-artifact@v5
with: with:
name: debug-elfs-${{inputs.target}}-${{ needs.version.outputs.long }}.zip name: debug-elfs-${{inputs.target}}-${{ needs.version.outputs.long }}.zip
overwrite: true overwrite: true
+17 -22
View File
@@ -77,21 +77,16 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
check: ${{ fromJson(needs.setup.outputs.check) }} check: ${{ fromJson(needs.setup.outputs.check) }}
# Use 'arctastic' self-hosted runner pool when checking in the main repo
runs-on: ${{ github.repository_owner == 'meshtastic' && 'arctastic' || 'ubuntu-latest' }} runs-on: ubuntu-latest
if: ${{ github.event_name != 'workflow_dispatch' && github.repository == 'meshtastic/firmware' }} if: ${{ github.event_name != 'workflow_dispatch' && github.repository == 'meshtastic/firmware' }}
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v6
with: - name: Build base
submodules: recursive id: base
ref: ${{github.event.pull_request.head.ref}} uses: ./.github/actions/setup-base
repository: ${{github.event.pull_request.head.repo.full_name}}
- name: Check ${{ matrix.check.board }} - name: Check ${{ matrix.check.board }}
uses: meshtastic/gh-action-firmware@main run: bin/check-all.sh ${{ matrix.check.board }}
with:
pio_platform: ${{ matrix.check.platform }}
pio_env: ${{ matrix.check.board }}
pio_target: check
build: build:
needs: [setup, version] needs: [setup, version]
@@ -173,7 +168,7 @@ jobs:
ref: ${{github.event.pull_request.head.ref}} ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}} repository: ${{github.event.pull_request.head.repo.full_name}}
- uses: actions/download-artifact@v7 - uses: actions/download-artifact@v6
with: with:
path: ./ path: ./
pattern: firmware-${{matrix.arch}}-* pattern: firmware-${{matrix.arch}}-*
@@ -183,7 +178,7 @@ jobs:
run: ls -R run: ls -R
- name: Repackage in single firmware zip - name: Repackage in single firmware zip
uses: actions/upload-artifact@v6 uses: actions/upload-artifact@v5
with: with:
name: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }} name: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}
overwrite: true overwrite: true
@@ -200,7 +195,7 @@ jobs:
./Meshtastic_nRF52_factory_erase*.uf2 ./Meshtastic_nRF52_factory_erase*.uf2
retention-days: 30 retention-days: 30
- uses: actions/download-artifact@v7 - uses: actions/download-artifact@v6
with: with:
name: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }} name: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}
merge-multiple: true merge-multiple: true
@@ -219,7 +214,7 @@ jobs:
run: zip -j -9 -r ./firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip ./output run: zip -j -9 -r ./firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip ./output
- name: Repackage in single elfs zip - name: Repackage in single elfs zip
uses: actions/upload-artifact@v6 uses: actions/upload-artifact@v5
with: with:
name: debug-elfs-${{matrix.arch}}-${{ needs.version.outputs.long }} name: debug-elfs-${{matrix.arch}}-${{ needs.version.outputs.long }}
overwrite: true overwrite: true
@@ -260,14 +255,14 @@ jobs:
Autogenerated by github action, developer should edit as required before publishing... Autogenerated by github action, developer should edit as required before publishing...
- name: Download source deb - name: Download source deb
uses: actions/download-artifact@v7 uses: actions/download-artifact@v6
with: with:
pattern: firmware-debian-${{ needs.version.outputs.deb }}~UNRELEASED-src pattern: firmware-debian-${{ needs.version.outputs.deb }}~UNRELEASED-src
merge-multiple: true merge-multiple: true
path: ./output/debian-src path: ./output/debian-src
- name: Download `native-tft` pio deps - name: Download `native-tft` pio deps
uses: actions/download-artifact@v7 uses: actions/download-artifact@v6
with: with:
pattern: platformio-deps-native-tft-${{ needs.version.outputs.long }} pattern: platformio-deps-native-tft-${{ needs.version.outputs.long }}
merge-multiple: true merge-multiple: true
@@ -291,7 +286,7 @@ jobs:
}' > firmware-${{ needs.version.outputs.long }}.json }' > firmware-${{ needs.version.outputs.long }}.json
- name: Save Release manifest artifact - name: Save Release manifest artifact
uses: actions/upload-artifact@v6 uses: actions/upload-artifact@v5
with: with:
name: manifest-${{ needs.version.outputs.long }} name: manifest-${{ needs.version.outputs.long }}
overwrite: true overwrite: true
@@ -332,7 +327,7 @@ jobs:
with: with:
python-version: 3.x python-version: 3.x
- uses: actions/download-artifact@v7 - uses: actions/download-artifact@v6
with: with:
pattern: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }} pattern: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}
merge-multiple: true merge-multiple: true
@@ -349,7 +344,7 @@ jobs:
- name: Zip firmware - name: Zip firmware
run: zip -j -9 -r ./firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip ./output run: zip -j -9 -r ./firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip ./output
- uses: actions/download-artifact@v7 - uses: actions/download-artifact@v6
with: with:
name: debug-elfs-${{matrix.arch}}-${{ needs.version.outputs.long }} name: debug-elfs-${{matrix.arch}}-${{ needs.version.outputs.long }}
merge-multiple: true merge-multiple: true
@@ -388,14 +383,14 @@ jobs:
python-version: 3.x python-version: 3.x
- name: Get firmware artifacts - name: Get firmware artifacts
uses: actions/download-artifact@v7 uses: actions/download-artifact@v6
with: with:
pattern: firmware-{${{ env.targets }}}-${{ needs.version.outputs.long }} pattern: firmware-{${{ env.targets }}}-${{ needs.version.outputs.long }}
merge-multiple: true merge-multiple: true
path: ./publish path: ./publish
- name: Get manifest artifact - name: Get manifest artifact
uses: actions/download-artifact@v7 uses: actions/download-artifact@v6
with: with:
pattern: manifest-${{ needs.version.outputs.long }} pattern: manifest-${{ needs.version.outputs.long }}
path: ./publish path: ./publish
+9 -9
View File
@@ -147,7 +147,7 @@ jobs:
ref: ${{github.event.pull_request.head.ref}} ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}} repository: ${{github.event.pull_request.head.repo.full_name}}
- uses: actions/download-artifact@v7 - uses: actions/download-artifact@v6
with: with:
path: ./ path: ./
pattern: firmware-${{matrix.arch}}-* pattern: firmware-${{matrix.arch}}-*
@@ -160,7 +160,7 @@ jobs:
run: mv -b -t ./ ./bin/device-*.sh ./bin/device-*.bat run: mv -b -t ./ ./bin/device-*.sh ./bin/device-*.bat
- name: Repackage in single firmware zip - name: Repackage in single firmware zip
uses: actions/upload-artifact@v6 uses: actions/upload-artifact@v5
with: with:
name: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }} name: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}
overwrite: true overwrite: true
@@ -176,7 +176,7 @@ jobs:
./Meshtastic_nRF52_factory_erase*.uf2 ./Meshtastic_nRF52_factory_erase*.uf2
retention-days: 30 retention-days: 30
- uses: actions/download-artifact@v7 - uses: actions/download-artifact@v6
with: with:
name: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }} name: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}
merge-multiple: true merge-multiple: true
@@ -195,7 +195,7 @@ jobs:
run: zip -j -9 -r ./firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip ./output run: zip -j -9 -r ./firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip ./output
- name: Repackage in single elfs zip - name: Repackage in single elfs zip
uses: actions/upload-artifact@v6 uses: actions/upload-artifact@v5
with: with:
name: debug-elfs-${{matrix.arch}}-${{ needs.version.outputs.long }} name: debug-elfs-${{matrix.arch}}-${{ needs.version.outputs.long }}
overwrite: true overwrite: true
@@ -235,14 +235,14 @@ jobs:
Autogenerated by github action, developer should edit as required before publishing... Autogenerated by github action, developer should edit as required before publishing...
- name: Download source deb - name: Download source deb
uses: actions/download-artifact@v7 uses: actions/download-artifact@v6
with: with:
pattern: firmware-debian-${{ needs.version.outputs.deb }}~UNRELEASED-src pattern: firmware-debian-${{ needs.version.outputs.deb }}~UNRELEASED-src
merge-multiple: true merge-multiple: true
path: ./output/debian-src path: ./output/debian-src
- name: Download `native-tft` pio deps - name: Download `native-tft` pio deps
uses: actions/download-artifact@v7 uses: actions/download-artifact@v6
with: with:
pattern: platformio-deps-native-tft-${{ needs.version.outputs.long }} pattern: platformio-deps-native-tft-${{ needs.version.outputs.long }}
merge-multiple: true merge-multiple: true
@@ -292,7 +292,7 @@ jobs:
with: with:
python-version: 3.x python-version: 3.x
- uses: actions/download-artifact@v7 - uses: actions/download-artifact@v6
with: with:
pattern: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }} pattern: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}
merge-multiple: true merge-multiple: true
@@ -309,7 +309,7 @@ jobs:
- name: Zip firmware - name: Zip firmware
run: zip -j -9 -r ./firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip ./output run: zip -j -9 -r ./firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip ./output
- uses: actions/download-artifact@v7 - uses: actions/download-artifact@v6
with: with:
name: debug-elfs-${{matrix.arch}}-${{ needs.version.outputs.long }} name: debug-elfs-${{matrix.arch}}-${{ needs.version.outputs.long }}
merge-multiple: true merge-multiple: true
@@ -347,7 +347,7 @@ jobs:
with: with:
python-version: 3.x python-version: 3.x
- uses: actions/download-artifact@v7 - uses: actions/download-artifact@v6
with: with:
pattern: firmware-{${{ env.targets }}}-${{ needs.version.outputs.long }} pattern: firmware-{${{ env.targets }}}-${{ needs.version.outputs.long }}
merge-multiple: true merge-multiple: true
+1 -1
View File
@@ -58,7 +58,7 @@ jobs:
id: version id: version
- name: Download artifacts - name: Download artifacts
uses: actions/download-artifact@v7 uses: actions/download-artifact@v6
with: with:
name: firmware-debian-${{ steps.version.outputs.deb }}~${{ inputs.series }}-src name: firmware-debian-${{ steps.version.outputs.deb }}~${{ inputs.series }}-src
merge-multiple: true merge-multiple: true
+1 -1
View File
@@ -56,7 +56,7 @@ jobs:
PLATFORMIO_CORE_DIR: pio/core PLATFORMIO_CORE_DIR: pio/core
- name: Store binaries as an artifact - name: Store binaries as an artifact
uses: actions/upload-artifact@v6 uses: actions/upload-artifact@v5
with: with:
name: platformio-deps-${{ inputs.pio_env }}-${{ steps.version.outputs.long }} name: platformio-deps-${{ inputs.pio_env }}-${{ steps.version.outputs.long }}
overwrite: true overwrite: true
+1 -1
View File
@@ -60,7 +60,7 @@ jobs:
id: version id: version
- name: Download artifacts - name: Download artifacts
uses: actions/download-artifact@v7 uses: actions/download-artifact@v6
with: with:
name: firmware-debian-${{ steps.version.outputs.deb }}~${{ inputs.series }}-src name: firmware-debian-${{ steps.version.outputs.deb }}~${{ inputs.series }}-src
merge-multiple: true merge-multiple: true
+1 -1
View File
@@ -50,7 +50,7 @@ jobs:
- name: Download test artifacts - name: Download test artifacts
if: needs.native-tests.result != 'skipped' if: needs.native-tests.result != 'skipped'
uses: actions/download-artifact@v7 uses: actions/download-artifact@v6
with: with:
name: platformio-test-report-${{ steps.version.outputs.long }} name: platformio-test-report-${{ steps.version.outputs.long }}
merge-multiple: true merge-multiple: true
+1 -1
View File
@@ -102,7 +102,7 @@ jobs:
PIP_DISABLE_PIP_VERSION_CHECK: 1 PIP_DISABLE_PIP_VERSION_CHECK: 1
- name: Create Bumps pull request - name: Create Bumps pull request
uses: peter-evans/create-pull-request@v8 uses: peter-evans/create-pull-request@v7
with: with:
base: ${{ github.event.repository.default_branch }} base: ${{ github.event.repository.default_branch }}
branch: create-pull-request/bump-version branch: create-pull-request/bump-version
+1 -1
View File
@@ -33,7 +33,7 @@ jobs:
# step 3 # step 3
- name: save report as pipeline artifact - name: save report as pipeline artifact
uses: actions/upload-artifact@v6 uses: actions/upload-artifact@v5
with: with:
name: report.sarif name: report.sarif
overwrite: true overwrite: true
+7 -7
View File
@@ -59,7 +59,7 @@ jobs:
id: version id: version
- name: Save coverage information - name: Save coverage information
uses: actions/upload-artifact@v6 uses: actions/upload-artifact@v5
if: always() # run this step even if previous step failed if: always() # run this step even if previous step failed
with: with:
name: lcov-coverage-info-native-simulator-test-${{ steps.version.outputs.long }} name: lcov-coverage-info-native-simulator-test-${{ steps.version.outputs.long }}
@@ -94,7 +94,7 @@ jobs:
- name: Save test results - name: Save test results
if: always() # run this step even if previous step failed if: always() # run this step even if previous step failed
uses: actions/upload-artifact@v6 uses: actions/upload-artifact@v5
with: with:
name: platformio-test-report-${{ steps.version.outputs.long }} name: platformio-test-report-${{ steps.version.outputs.long }}
overwrite: true overwrite: true
@@ -108,7 +108,7 @@ jobs:
sed -i -e "s#${PWD}#.#" coverage_tests.info # Make paths relative. sed -i -e "s#${PWD}#.#" coverage_tests.info # Make paths relative.
- name: Save coverage information - name: Save coverage information
uses: actions/upload-artifact@v6 uses: actions/upload-artifact@v5
if: always() # run this step even if previous step failed if: always() # run this step even if previous step failed
with: with:
name: lcov-coverage-info-native-platformio-tests-${{ steps.version.outputs.long }} name: lcov-coverage-info-native-platformio-tests-${{ steps.version.outputs.long }}
@@ -137,20 +137,20 @@ jobs:
id: version id: version
- name: Download test artifacts - name: Download test artifacts
uses: actions/download-artifact@v7 uses: actions/download-artifact@v6
with: with:
name: platformio-test-report-${{ steps.version.outputs.long }} name: platformio-test-report-${{ steps.version.outputs.long }}
merge-multiple: true merge-multiple: true
- name: Test Report - name: Test Report
uses: dorny/test-reporter@v2.4.0 uses: dorny/test-reporter@v2.3.0
with: with:
name: PlatformIO Tests name: PlatformIO Tests
path: testreport.xml path: testreport.xml
reporter: java-junit reporter: java-junit
- name: Download coverage artifacts - name: Download coverage artifacts
uses: actions/download-artifact@v7 uses: actions/download-artifact@v6
with: with:
pattern: lcov-coverage-info-native-*-${{ steps.version.outputs.long }} pattern: lcov-coverage-info-native-*-${{ steps.version.outputs.long }}
path: code-coverage-report path: code-coverage-report
@@ -163,7 +163,7 @@ jobs:
genhtml --quiet --legend --prefix "${PWD}" code-coverage-report/coverage_src.info --output-directory code-coverage-report genhtml --quiet --legend --prefix "${PWD}" code-coverage-report/coverage_src.info --output-directory code-coverage-report
- name: Save Code Coverage Report - name: Save Code Coverage Report
uses: actions/upload-artifact@v6 uses: actions/upload-artifact@v5
with: with:
name: code-coverage-report-${{ steps.version.outputs.long }} name: code-coverage-report-${{ steps.version.outputs.long }}
path: code-coverage-report path: code-coverage-report
+1 -1
View File
@@ -31,7 +31,7 @@ jobs:
./bin/regen-protos.sh ./bin/regen-protos.sh
- name: Create pull request - name: Create pull request
uses: peter-evans/create-pull-request@v8 uses: peter-evans/create-pull-request@v7
with: with:
branch: create-pull-request/update-protobufs branch: create-pull-request/update-protobufs
labels: submodules labels: submodules
+9 -9
View File
@@ -8,25 +8,25 @@ plugins:
uri: https://github.com/trunk-io/plugins uri: https://github.com/trunk-io/plugins
lint: lint:
enabled: enabled:
- checkov@3.2.497 - checkov@3.2.495
- renovate@42.69.2 - renovate@42.30.4
- prettier@3.7.4 - prettier@3.7.4
- trufflehog@3.92.4 - trufflehog@3.91.2
- yamllint@1.37.1 - yamllint@1.37.1
- bandit@1.9.2 - bandit@1.9.2
- trivy@0.68.2 - trivy@0.67.2
- taplo@0.10.0 - taplo@0.10.0
- ruff@0.14.10 - ruff@0.14.7
- isort@7.0.0 - isort@7.0.0
- markdownlint@0.47.0 - markdownlint@0.46.0
- oxipng@10.0.0 - oxipng@9.1.5
- svgo@4.0.0 - svgo@4.0.0
- actionlint@1.7.10 - actionlint@1.7.9
- flake8@7.3.0 - flake8@7.3.0
- hadolint@2.14.0 - hadolint@2.14.0
- shfmt@3.6.0 - shfmt@3.6.0
- shellcheck@0.11.0 - shellcheck@0.11.0
- black@25.12.0 - black@25.11.0
- git-diff-check - git-diff-check
- gitleaks@8.30.0 - gitleaks@8.30.0
- clang-format@16.0.3 - clang-format@16.0.3
+13 -3
View File
@@ -22,7 +22,7 @@ export APP_VERSION=$VERSION
basename=firmware-$1-$VERSION basename=firmware-$1-$VERSION
pio run --environment $1 -t mtjson # -v pio run --environment $1 # -v
cp $BUILDDIR/$basename.elf $OUTDIR/$basename.elf cp $BUILDDIR/$basename.elf $OUTDIR/$basename.elf
@@ -32,10 +32,20 @@ cp $BUILDDIR/$basename.factory.bin $OUTDIR/$basename.factory.bin
echo "Copying ESP32 update bin file" echo "Copying ESP32 update bin file"
cp $BUILDDIR/$basename.bin $OUTDIR/$basename.bin cp $BUILDDIR/$basename.bin $OUTDIR/$basename.bin
echo "Copying Filesystem for ESP32 targets" echo "Building Filesystem for ESP32 targets"
# If you want to build the webui, uncomment the following lines
# pio run --environment $1 -t buildfs
# cp .pio/build/$1/littlefs.bin $OUTDIR/littlefswebui-$1-$VERSION.bin
# # Remove webserver files from the filesystem and rebuild
# ls -l data/static # Diagnostic list of files
# rm -rf data/static
pio run --environment $1 -t buildfs --disable-auto-clean
cp $BUILDDIR/littlefs-$1-$VERSION.bin $OUTDIR/littlefs-$1-$VERSION.bin cp $BUILDDIR/littlefs-$1-$VERSION.bin $OUTDIR/littlefs-$1-$VERSION.bin
cp bin/device-install.* $OUTDIR/ cp bin/device-install.* $OUTDIR/
cp bin/device-update.* $OUTDIR/ cp bin/device-update.* $OUTDIR/
echo "Copying manifest" # Generate the manifest file
echo "Generating Meshtastic manifest"
TIMEFORMAT="Generated manifest in %E seconds"
time pio run --environment $1 -t mtjson --silent --disable-auto-clean
cp $BUILDDIR/$basename.mt.json $OUTDIR/$basename.mt.json cp $BUILDDIR/$basename.mt.json $OUTDIR/$basename.mt.json
+6 -4
View File
@@ -21,14 +21,13 @@ rm -f $BUILDDIR/firmware*
export APP_VERSION=$VERSION export APP_VERSION=$VERSION
basename=firmware-$1-$VERSION basename=firmware-$1-$VERSION
ota_basename=${basename}-ota
pio run --environment $1 -t mtjson # -v pio run --environment $1 # -v
cp $BUILDDIR/$basename.elf $OUTDIR/$basename.elf cp $BUILDDIR/$basename.elf $OUTDIR/$basename.elf
echo "Copying NRF52 dfu (OTA) file" echo "Copying NRF52 dfu (OTA) file"
cp $BUILDDIR/$basename.zip $OUTDIR/$ota_basename.zip cp $BUILDDIR/$basename.zip $OUTDIR/$basename.zip
echo "Copying NRF52 UF2 file" echo "Copying NRF52 UF2 file"
cp $BUILDDIR/$basename.uf2 $OUTDIR/$basename.uf2 cp $BUILDDIR/$basename.uf2 $OUTDIR/$basename.uf2
@@ -48,5 +47,8 @@ if (echo $1 | grep -q "rak4631"); then
cp $SRCHEX $OUTDIR/ cp $SRCHEX $OUTDIR/
fi fi
echo "Copying manifest" # Generate the manifest file
echo "Generating Meshtastic manifest"
TIMEFORMAT="Generated manifest in %E seconds"
time pio run --environment $1 -t mtjson --silent --disable-auto-clean
cp $BUILDDIR/$basename.mt.json $OUTDIR/$basename.mt.json cp $BUILDDIR/$basename.mt.json $OUTDIR/$basename.mt.json
+5 -2
View File
@@ -22,12 +22,15 @@ export APP_VERSION=$VERSION
basename=firmware-$1-$VERSION basename=firmware-$1-$VERSION
pio run --environment $1 -t mtjson # -v pio run --environment $1 # -v
cp $BUILDDIR/$basename.elf $OUTDIR/$basename.elf cp $BUILDDIR/$basename.elf $OUTDIR/$basename.elf
echo "Copying uf2 file" echo "Copying uf2 file"
cp $BUILDDIR/$basename.uf2 $OUTDIR/$basename.uf2 cp $BUILDDIR/$basename.uf2 $OUTDIR/$basename.uf2
echo "Copying manifest" # Generate the manifest file
echo "Generating Meshtastic manifest"
TIMEFORMAT="Generated manifest in %E seconds"
time pio run --environment $1 -t mtjson --silent --disable-auto-clean
cp $BUILDDIR/$basename.mt.json $OUTDIR/$basename.mt.json cp $BUILDDIR/$basename.mt.json $OUTDIR/$basename.mt.json
+5 -2
View File
@@ -22,12 +22,15 @@ export APP_VERSION=$VERSION
basename=firmware-$1-$VERSION basename=firmware-$1-$VERSION
pio run --environment $1 -t mtjson # -v pio run --environment $1 # -v
cp $BUILDDIR/$basename.elf $OUTDIR/$basename.elf cp $BUILDDIR/$basename.elf $OUTDIR/$basename.elf
echo "Copying STM32 bin file" echo "Copying STM32 bin file"
cp $BUILDDIR/$basename.bin $OUTDIR/$basename.bin cp $BUILDDIR/$basename.bin $OUTDIR/$basename.bin
echo "Copying manifest" # Generate the manifest file
echo "Generating Meshtastic manifest"
TIMEFORMAT="Generated manifest in %E seconds"
time pio run --environment $1 -t mtjson --silent --disable-auto-clean
cp $BUILDDIR/$basename.mt.json $OUTDIR/$basename.mt.json cp $BUILDDIR/$basename.mt.json $OUTDIR/$basename.mt.json
-2
View File
@@ -184,8 +184,6 @@ Input:
Logging: Logging:
LogLevel: info # debug, info, warn, error LogLevel: info # debug, info, warn, error
# TraceFile: /var/log/meshtasticd.json # TraceFile: /var/log/meshtasticd.json
# JSONFile: /packets.json # File location for JSON output of decoded packets
# JSONFilter: position # filter for packets to save to JSON file
# AsciiLogs: true # default if not specified is !isatty() on stdout # AsciiLogs: true # default if not specified is !isatty() on stdout
Webserver: Webserver:
+10 -17
View File
@@ -17,8 +17,6 @@ lfsbin = f"{progname.replace('firmware-', 'littlefs-')}.bin"
def manifest_gather(source, target, env): def manifest_gather(source, target, env):
out = [] out = []
board_platform = env.BoardConfig().get("platform")
needs_ota_suffix = board_platform == "nordicnrf52"
check_paths = [ check_paths = [
progname, progname,
f"{progname}.elf", f"{progname}.elf",
@@ -34,11 +32,8 @@ def manifest_gather(source, target, env):
for p in check_paths: for p in check_paths:
f = env.File(env.subst(f"$BUILD_DIR/{p}")) f = env.File(env.subst(f"$BUILD_DIR/{p}"))
if f.exists(): if f.exists():
manifest_name = p
if needs_ota_suffix and p == f"{progname}.zip":
manifest_name = f"{progname}-ota.zip"
d = { d = {
"name": manifest_name, "name": p,
"md5": f.get_content_hash(), # Returns MD5 hash "md5": f.get_content_hash(), # Returns MD5 hash
"bytes": f.get_size() # Returns file size in bytes "bytes": f.get_size() # Returns file size in bytes
} }
@@ -164,22 +159,20 @@ def load_boot_logo(source, target, env):
# Load the boot logo on TFT builds # Load the boot logo on TFT builds
if ("HAS_TFT", 1) in env.get("CPPDEFINES", []): if ("HAS_TFT", 1) in env.get("CPPDEFINES", []):
env.AddPreAction(f"$BUILD_DIR/{lfsbin}", load_boot_logo) env.AddPreAction('$BUILD_DIR/littlefs.bin', load_boot_logo)
mtjson_deps = ["buildprog"] # Rename (mv) littlefs.bin to include the PROGNAME
if platform.name == "espressif32": # This ensures the littlefs.bin is named consistently with the firmware
# Build littlefs image as part of mtjson target env.AddPostAction('$BUILD_DIR/littlefs.bin', env.VerboseAction(
# Equivalent to `pio run -t buildfs` f'mv $BUILD_DIR/littlefs.bin $BUILD_DIR/{lfsbin}',
target_lfs = env.DataToBin( f'Renaming littlefs.bin to {lfsbin}'
join("$BUILD_DIR", "${ESP32_FS_IMAGE_NAME}"), "$PROJECT_DATA_DIR" ))
)
mtjson_deps.append(target_lfs)
env.AddCustomTarget( env.AddCustomTarget(
name="mtjson", name="mtjson",
dependencies=mtjson_deps, dependencies=None,
actions=[manifest_gather], actions=[manifest_gather],
title="Meshtastic Manifest", title="Meshtastic Manifest",
description="Generating Meshtastic manifest JSON + Checksums", description="Generating Meshtastic manifest JSON + Checksums",
always_build=False, always_build=True,
) )
-3
View File
@@ -11,9 +11,6 @@ else:
prefsLoc = env["PROJECT_DIR"] + "/version.properties" prefsLoc = env["PROJECT_DIR"] + "/version.properties"
verObj = readProps(prefsLoc) verObj = readProps(prefsLoc)
env.Replace(PROGNAME=f"firmware-{env.get('PIOENV')}-{verObj['long']}") env.Replace(PROGNAME=f"firmware-{env.get('PIOENV')}-{verObj['long']}")
env.Replace(ESP32_FS_IMAGE_NAME=f"littlefs-{env.get('PIOENV')}-{verObj['long']}")
# Print the new program name for verification # Print the new program name for verification
print(f"PROGNAME: {env.get('PROGNAME')}") print(f"PROGNAME: {env.get('PROGNAME')}")
if platform.name == "espressif32":
print(f"ESP32_FS_IMAGE_NAME: {env.get('ESP32_FS_IMAGE_NAME')}")
-6
View File
@@ -10,12 +10,6 @@ Import("env")
platform = env.PioPlatform() platform = env.PioPlatform()
sys.path.append(join(platform.get_package_dir("tool-esptoolpy"))) sys.path.append(join(platform.get_package_dir("tool-esptoolpy")))
# IntelHex workaround, remove after fixed upstream
# https://github.com/platformio/platform-espressif32/issues/1632
try:
import intelhex
except ImportError:
env.Execute("$PYTHONEXE -m pip install intelhex")
import esptool import esptool
+2 -2
View File
@@ -64,7 +64,7 @@ monitor_speed = 115200
monitor_filters = direct monitor_filters = direct
lib_deps = lib_deps =
# renovate: datasource=git-refs depName=meshtastic-esp8266-oled-ssd1306 packageName=https://github.com/meshtastic/esp8266-oled-ssd1306 gitBranch=master # renovate: datasource=git-refs depName=meshtastic-esp8266-oled-ssd1306 packageName=https://github.com/meshtastic/esp8266-oled-ssd1306 gitBranch=master
https://github.com/meshtastic/esp8266-oled-ssd1306/archive/b34c6817c25d6faabb3a8a162b5d14fb75395433.zip https://github.com/meshtastic/esp8266-oled-ssd1306/archive/2887bf4a19f64d92c984dcc8fd5ca7429e425e4a.zip
# renovate: datasource=git-refs depName=meshtastic-OneButton packageName=https://github.com/meshtastic/OneButton gitBranch=master # renovate: datasource=git-refs depName=meshtastic-OneButton packageName=https://github.com/meshtastic/OneButton gitBranch=master
https://github.com/meshtastic/OneButton/archive/fa352d668c53f290cfa480a5f79ad422cd828c70.zip https://github.com/meshtastic/OneButton/archive/fa352d668c53f290cfa480a5f79ad422cd828c70.zip
# renovate: datasource=git-refs depName=meshtastic-arduino-fsm packageName=https://github.com/meshtastic/arduino-fsm gitBranch=master # renovate: datasource=git-refs depName=meshtastic-arduino-fsm packageName=https://github.com/meshtastic/arduino-fsm gitBranch=master
@@ -123,7 +123,7 @@ lib_deps =
[device-ui_base] [device-ui_base]
lib_deps = lib_deps =
# renovate: datasource=git-refs depName=meshtastic/device-ui packageName=https://github.com/meshtastic/device-ui gitBranch=master # renovate: datasource=git-refs depName=meshtastic/device-ui packageName=https://github.com/meshtastic/device-ui gitBranch=master
https://github.com/meshtastic/device-ui/archive/a8e2f947f7abaf0c5ac8e6dd189a22156335beaa.zip https://github.com/meshtastic/device-ui/archive/4fb5f24787caa841b58dbf623a52c4c5861d6722.zip
; Common libs for environmental measurements in telemetry module ; Common libs for environmental measurements in telemetry module
[environmental_base] [environmental_base]
-3
View File
@@ -31,9 +31,6 @@ const char *DisplayFormatters::getModemPresetDisplayName(meshtastic_Config_LoRaC
case meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST: case meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST:
return useShortName ? "LongF" : "LongFast"; return useShortName ? "LongF" : "LongFast";
break; break;
case meshtastic_Config_LoRaConfig_ModemPreset_LONG_TURBO:
return useShortName ? "LongT" : "LongTurbo";
break;
case meshtastic_Config_LoRaConfig_ModemPreset_LONG_MODERATE: case meshtastic_Config_LoRaConfig_ModemPreset_LONG_MODERATE:
return useShortName ? "LongM" : "LongMod"; return useShortName ? "LongM" : "LongMod";
break; break;
+62
View File
@@ -10,7 +10,10 @@
*/ */
#include "FSCommon.h" #include "FSCommon.h"
#include "SPILock.h" #include "SPILock.h"
#include "SafeFile.h"
#include "configuration.h" #include "configuration.h"
#include <pb_decode.h>
#include <pb_encode.h>
// Software SPI is used by MUI so disable SD card here until it's also implemented // Software SPI is used by MUI so disable SD card here until it's also implemented
#if defined(HAS_SDCARD) && !defined(SDCARD_USE_SOFT_SPI) #if defined(HAS_SDCARD) && !defined(SDCARD_USE_SOFT_SPI)
@@ -335,4 +338,63 @@ void setupSDCard()
LOG_DEBUG("Total space: %lu MB", (uint32_t)(SD.totalBytes() / (1024 * 1024))); LOG_DEBUG("Total space: %lu MB", (uint32_t)(SD.totalBytes() / (1024 * 1024)));
LOG_DEBUG("Used space: %lu MB", (uint32_t)(SD.usedBytes() / (1024 * 1024))); LOG_DEBUG("Used space: %lu MB", (uint32_t)(SD.usedBytes() / (1024 * 1024)));
#endif #endif
}
/** Load a protobuf from a file, return LoadFileResult */
LoadFileResult loadProto(const char *filename, size_t protoSize, size_t objSize, const pb_msgdesc_t *fields, void *dest_struct)
{
LoadFileResult state = LoadFileResult::OTHER_FAILURE;
#ifdef FSCom
concurrency::LockGuard g(spiLock);
auto f = FSCom.open(filename, FILE_O_READ);
if (f) {
LOG_INFO("Load %s", filename);
pb_istream_t stream = {&readcb, &f, protoSize};
if (fields != &meshtastic_NodeDatabase_msg) // contains a vector object
memset(dest_struct, 0, objSize);
if (!pb_decode(&stream, fields, dest_struct)) {
LOG_ERROR("Error: can't decode protobuf %s", PB_GET_ERROR(&stream));
state = LoadFileResult::DECODE_FAILED;
} else {
LOG_INFO("Loaded %s successfully", filename);
state = LoadFileResult::LOAD_SUCCESS;
}
f.close();
} else {
LOG_ERROR("Could not open / read %s", filename);
}
#else
LOG_ERROR("ERROR: Filesystem not implemented");
state = LoadFileResult::NO_FILESYSTEM;
#endif
return state;
}
/** Save a protobuf from a file, return true for success */
bool saveProto(const char *filename, size_t protoSize, const pb_msgdesc_t *fields, const void *dest_struct, bool fullAtomic)
{
bool okay = false;
#ifdef FSCom
auto f = SafeFile(filename, fullAtomic);
LOG_INFO("Save %s", filename);
pb_ostream_t stream = {&writecb, static_cast<Print *>(&f), protoSize};
if (!pb_encode(&stream, fields, dest_struct)) {
LOG_ERROR("Error: can't encode protobuf %s", PB_GET_ERROR(&stream));
} else {
okay = true;
}
bool writeSucceeded = f.close();
if (!okay || !writeSucceeded) {
LOG_ERROR("Can't write prefs!");
}
#else
LOG_ERROR("ERROR: Filesystem not implemented");
#endif
return okay;
} }
+18 -1
View File
@@ -3,6 +3,19 @@
#include "configuration.h" #include "configuration.h"
#include <vector> #include <vector>
enum LoadFileResult {
// Successfully opened the file
LOAD_SUCCESS = 1,
// File does not exist
NOT_FOUND = 2,
// Device does not have a filesystem
NO_FILESYSTEM = 3,
// File exists, but could not decode protobufs
DECODE_FAILED = 4,
// File exists, but open failed for some reason
OTHER_FAILURE = 5
};
// Cross platform filesystem API // Cross platform filesystem API
#if defined(ARCH_PORTDUINO) #if defined(ARCH_PORTDUINO)
@@ -55,4 +68,8 @@ bool renameFile(const char *pathFrom, const char *pathTo);
std::vector<meshtastic_FileInfo> getFiles(const char *dirname, uint8_t levels); std::vector<meshtastic_FileInfo> getFiles(const char *dirname, uint8_t levels);
void listDir(const char *dirname, uint8_t levels, bool del = false); void listDir(const char *dirname, uint8_t levels, bool del = false);
void rmDir(const char *dirname); void rmDir(const char *dirname);
void setupSDCard(); void setupSDCard();
LoadFileResult loadProto(const char *filename, size_t protoSize, size_t objSize, const pb_msgdesc_t *fields, void *dest_struct);
bool saveProto(const char *filename, size_t protoSize, const pb_msgdesc_t *fields, const void *dest_struct,
bool fullAtomic = true);
+1 -3
View File
@@ -532,10 +532,8 @@ void drawSystemScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x
const int labelX = x; const int labelX = x;
int barsOffset = (isHighResolution) ? 24 : 0; int barsOffset = (isHighResolution) ? 24 : 0;
#ifdef USE_EINK #ifdef USE_EINK
#ifndef T_DECK_PRO
barsOffset -= 12; barsOffset -= 12;
#endif #endif
#endif
#if defined(M5STACK_UNITC6L) #if defined(M5STACK_UNITC6L)
const int barX = x + 45 + barsOffset; const int barX = x + 45 + barsOffset;
#else #else
@@ -576,7 +574,7 @@ void drawSystemScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x
#endif #endif
// Value string // Value string
display->setTextAlignment(TEXT_ALIGN_RIGHT); display->setTextAlignment(TEXT_ALIGN_RIGHT);
display->drawString(SCREEN_WIDTH, getTextPositions(display)[line], combinedStr); display->drawString(SCREEN_WIDTH - 2, getTextPositions(display)[line], combinedStr);
}; };
// === Memory values === // === Memory values ===
+43 -61
View File
@@ -1,6 +1,7 @@
#include "configuration.h" #include "configuration.h"
#if HAS_SCREEN #if HAS_SCREEN
#include "ClockRenderer.h" #include "ClockRenderer.h"
#include "FSCommon.h"
#include "GPS.h" #include "GPS.h"
#include "MenuHandler.h" #include "MenuHandler.h"
#include "MeshRadio.h" #include "MeshRadio.h"
@@ -20,41 +21,12 @@
#include "modules/KeyVerificationModule.h" #include "modules/KeyVerificationModule.h"
#include "modules/TraceRouteModule.h" #include "modules/TraceRouteModule.h"
#include <algorithm>
#include <array>
#include <functional> #include <functional>
#include <utility>
extern uint16_t TFT_MESH; extern uint16_t TFT_MESH;
namespace graphics namespace graphics
{ {
namespace
{
// Caller must ensure the provided options array outlives the banner callback.
template <typename T, size_t N, typename Callback>
BannerOverlayOptions createStaticBannerOptions(const char *message, const MenuOption<T> (&options)[N],
std::array<const char *, N> &labels, Callback &&onSelection)
{
for (size_t i = 0; i < N; ++i) {
labels[i] = options[i].label;
}
const MenuOption<T> *optionsPtr = options;
auto callback = std::function<void(const MenuOption<T> &, int)>(std::forward<Callback>(onSelection));
BannerOverlayOptions bannerOptions;
bannerOptions.message = message;
bannerOptions.optionsArrayPtr = labels.data();
bannerOptions.optionsCount = static_cast<uint8_t>(N);
bannerOptions.bannerCallback = [optionsPtr, callback](int selected) -> void { callback(optionsPtr[selected], selected); };
return bannerOptions;
}
} // namespace
menuHandler::screenMenus menuHandler::menuQueue = menu_none; menuHandler::screenMenus menuHandler::menuQueue = menu_none;
bool test_enabled = false; bool test_enabled = false;
uint8_t test_count = 0; uint8_t test_count = 0;
@@ -226,38 +198,48 @@ void menuHandler::DeviceRolePicker()
void menuHandler::RadioPresetPicker() void menuHandler::RadioPresetPicker()
{ {
static const RadioPresetOption presetOptions[] = { static const char *optionsArray[] = {"Back", "LongSlow", "LongModerate", "LongFast", "MediumSlow",
{"Back", OptionsAction::Back}, "MediumFast", "ShortSlow", "ShortFast", "ShortTurbo"};
{"LongTurbo", OptionsAction::Select, meshtastic_Config_LoRaConfig_ModemPreset_LONG_TURBO}, enum optionsNumbers {
{"LongModerate", OptionsAction::Select, meshtastic_Config_LoRaConfig_ModemPreset_LONG_MODERATE}, Back = 0,
{"LongFast", OptionsAction::Select, meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST}, radiopreset_LongSlow = 1,
{"MediumSlow", OptionsAction::Select, meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_SLOW}, radiopreset_LongModerate = 2,
{"MediumFast", OptionsAction::Select, meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_FAST}, radiopreset_LongFast = 3,
{"ShortSlow", OptionsAction::Select, meshtastic_Config_LoRaConfig_ModemPreset_SHORT_SLOW}, radiopreset_MediumSlow = 4,
{"ShortFast", OptionsAction::Select, meshtastic_Config_LoRaConfig_ModemPreset_SHORT_FAST}, radiopreset_MediumFast = 5,
{"ShortTurbo", OptionsAction::Select, meshtastic_Config_LoRaConfig_ModemPreset_SHORT_TURBO}, radiopreset_ShortSlow = 6,
radiopreset_ShortFast = 7,
radiopreset_ShortTurbo = 8
};
BannerOverlayOptions bannerOptions;
bannerOptions.message = "Radio Preset";
bannerOptions.optionsArrayPtr = optionsArray;
bannerOptions.optionsCount = 9;
bannerOptions.bannerCallback = [](int selected) -> void {
if (selected == Back) {
menuHandler::menuQueue = menuHandler::lora_Menu;
screen->runNow();
return;
} else if (selected == radiopreset_LongSlow) {
config.lora.modem_preset = meshtastic_Config_LoRaConfig_ModemPreset_LONG_SLOW;
} else if (selected == radiopreset_LongModerate) {
config.lora.modem_preset = meshtastic_Config_LoRaConfig_ModemPreset_LONG_MODERATE;
} else if (selected == radiopreset_LongFast) {
config.lora.modem_preset = meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST;
} else if (selected == radiopreset_MediumSlow) {
config.lora.modem_preset = meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_SLOW;
} else if (selected == radiopreset_MediumFast) {
config.lora.modem_preset = meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_FAST;
} else if (selected == radiopreset_ShortSlow) {
config.lora.modem_preset = meshtastic_Config_LoRaConfig_ModemPreset_SHORT_SLOW;
} else if (selected == radiopreset_ShortFast) {
config.lora.modem_preset = meshtastic_Config_LoRaConfig_ModemPreset_SHORT_FAST;
} else if (selected == radiopreset_ShortTurbo) {
config.lora.modem_preset = meshtastic_Config_LoRaConfig_ModemPreset_SHORT_TURBO;
}
service->reloadConfig(SEGMENT_CONFIG);
rebootAtMsec = (millis() + DEFAULT_REBOOT_SECONDS * 1000);
}; };
constexpr size_t presetCount = sizeof(presetOptions) / sizeof(presetOptions[0]);
static std::array<const char *, presetCount> presetLabels{};
auto bannerOptions =
createStaticBannerOptions("Radio Preset", presetOptions, presetLabels, [](const RadioPresetOption &option, int) -> void {
if (option.action == OptionsAction::Back) {
menuHandler::menuQueue = menuHandler::lora_Menu;
screen->runNow();
return;
}
if (!option.hasValue) {
return;
}
config.lora.modem_preset = option.value;
service->reloadConfig(SEGMENT_CONFIG);
rebootAtMsec = (millis() + DEFAULT_REBOOT_SECONDS * 1000);
});
screen->showOverlayBanner(bannerOptions); screen->showOverlayBanner(bannerOptions);
} }
@@ -1808,7 +1790,7 @@ void menuHandler::handleMenuSwitch(OLEDDisplay *display)
void menuHandler::saveUIConfig() void menuHandler::saveUIConfig()
{ {
nodeDB->saveProto("/prefs/uiconfig.proto", meshtastic_DeviceUIConfig_size, &meshtastic_DeviceUIConfig_msg, &uiconfig); saveProto("/prefs/uiconfig.proto", meshtastic_DeviceUIConfig_size, &meshtastic_DeviceUIConfig_msg, &uiconfig);
} }
} // namespace graphics } // namespace graphics
-19
View File
@@ -99,24 +99,5 @@ class menuHandler
static void BluetoothToggleMenu(); static void BluetoothToggleMenu();
}; };
/* Generic Menu Options designations */
enum class OptionsAction { Back, Select };
template <typename T> struct MenuOption {
const char *label;
OptionsAction action;
bool hasValue;
T value;
MenuOption(const char *labelIn, OptionsAction actionIn, T valueIn)
: label(labelIn), action(actionIn), hasValue(true), value(valueIn)
{
}
MenuOption(const char *labelIn, OptionsAction actionIn) : label(labelIn), action(actionIn), hasValue(false), value() {}
};
using RadioPresetOption = MenuOption<meshtastic_Config_LoRaConfig_ModemPreset>;
} // namespace graphics } // namespace graphics
#endif #endif
@@ -62,22 +62,12 @@ void InkHUD::HeardApplet::populateFromNodeDB()
{ {
// Fill a collection with pointers to each node in db // Fill a collection with pointers to each node in db
std::vector<meshtastic_NodeInfoLite *> ordered; std::vector<meshtastic_NodeInfoLite *> ordered;
for (auto mn = nodeDB->meshNodes->begin(); mn != nodeDB->meshNodes->end(); ++mn) { for (int i = 1; i < maxCards(); i++) {
// Only copy if valid, and not our own node auto mn = nodeDB->getMeshNodeByIndex(i);
if (mn->num != 0 && mn->num != nodeDB->getNodeNum()) if (mn->num != 0 && mn->num != nodeDB->getNodeNum())
ordered.push_back(&*mn); ordered.push_back(&*mn);
} }
// Sort the collection by age
std::sort(ordered.begin(), ordered.end(), [](meshtastic_NodeInfoLite *top, meshtastic_NodeInfoLite *bottom) -> bool {
return (top->last_heard > bottom->last_heard);
});
// Keep the most recent entries only
// Just enough to fill the screen
if (ordered.size() > maxCards())
ordered.resize(maxCards());
// Create card info for these (stale) node observations // Create card info for these (stale) node observations
meshtastic_NodeInfoLite *ourNode = nodeDB->getMeshNode(nodeDB->getNodeNum()); meshtastic_NodeInfoLite *ourNode = nodeDB->getMeshNode(nodeDB->getNodeNum());
for (meshtastic_NodeInfoLite *node : ordered) { for (meshtastic_NodeInfoLite *node : ordered) {
@@ -1,7 +1,6 @@
#ifdef MESHTASTIC_INCLUDE_INKHUD #ifdef MESHTASTIC_INCLUDE_INKHUD
#include "./PositionsApplet.h" #include "./PositionsApplet.h"
#include "NodeDB.h"
using namespace NicheGraphics; using namespace NicheGraphics;
@@ -50,8 +49,8 @@ ProcessMessage InkHUD::PositionsApplet::handleReceived(const meshtastic_MeshPack
if (!hasPosition) if (!hasPosition)
return ProcessMessage::CONTINUE; return ProcessMessage::CONTINUE;
const int8_t hopsAway = getHopsAway(mp); bool hasHopsAway = (mp.hop_start != 0 && mp.hop_limit <= mp.hop_start); // From NodeDB::updateFrom
const bool hasHopsAway = hopsAway >= 0; uint8_t hopsAway = mp.hop_start - mp.hop_limit;
// Determine if the position packet would change anything on-screen // Determine if the position packet would change anything on-screen
// ----------------------------------------------------------------- // -----------------------------------------------------------------
@@ -53,9 +53,9 @@ void CannedMessageStore::load()
// Attempt to load the bulk canned message data from flash // Attempt to load the bulk canned message data from flash
meshtastic_CannedMessageModuleConfig cannedMessageModuleConfig; meshtastic_CannedMessageModuleConfig cannedMessageModuleConfig;
LoadFileResult result = nodeDB->loadProto("/prefs/cannedConf.proto", meshtastic_CannedMessageModuleConfig_size, LoadFileResult result = loadProto("/prefs/cannedConf.proto", meshtastic_CannedMessageModuleConfig_size,
sizeof(meshtastic_CannedMessageModuleConfig), sizeof(meshtastic_CannedMessageModuleConfig), &meshtastic_CannedMessageModuleConfig_msg,
&meshtastic_CannedMessageModuleConfig_msg, &cannedMessageModuleConfig); &cannedMessageModuleConfig);
// Abort if nothing to load // Abort if nothing to load
if (result != LoadFileResult::LOAD_SUCCESS || strlen(cannedMessageModuleConfig.messages) == 0) if (result != LoadFileResult::LOAD_SUCCESS || strlen(cannedMessageModuleConfig.messages) == 0)
@@ -129,8 +129,8 @@ void CannedMessageStore::handleSet(const meshtastic_AdminMessage *request)
#endif #endif
// Write to flash // Write to flash
nodeDB->saveProto(cannedMessagesConfigFile, meshtastic_CannedMessageModuleConfig_size, saveProto(cannedMessagesConfigFile, meshtastic_CannedMessageModuleConfig_size, &meshtastic_CannedMessageModuleConfig_msg,
&meshtastic_CannedMessageModuleConfig_msg, &cannedMessageModuleConfig); &cannedMessageModuleConfig);
// Reload from flash, to update the canned messages in RAM // Reload from flash, to update the canned messages in RAM
// (This is a lazy way to handle it) // (This is a lazy way to handle it)
-1
View File
@@ -53,7 +53,6 @@ typedef struct _InputEvent {
class InputPollable class InputPollable
{ {
public: public:
virtual ~InputPollable() = default;
virtual void pollOnce() = 0; virtual void pollOnce() = 0;
}; };
+8 -76
View File
@@ -3,9 +3,6 @@
#include "RotaryEncoderImpl.h" #include "RotaryEncoderImpl.h"
#include "InputBroker.h" #include "InputBroker.h"
#include "RotaryEncoder.h" #include "RotaryEncoder.h"
#ifdef ARCH_ESP32
#include "sleep.h"
#endif
#define ORIGIN_NAME "RotaryEncoder" #define ORIGIN_NAME "RotaryEncoder"
@@ -14,20 +11,6 @@ RotaryEncoderImpl *rotaryEncoderImpl;
RotaryEncoderImpl::RotaryEncoderImpl() RotaryEncoderImpl::RotaryEncoderImpl()
{ {
rotary = nullptr; rotary = nullptr;
#ifdef ARCH_ESP32
isFirstInit = true;
#endif
}
RotaryEncoderImpl::~RotaryEncoderImpl()
{
LOG_DEBUG("RotaryEncoderImpl destructor");
detachRotaryEncoderInterrupts();
if (rotary != nullptr) {
delete rotary;
rotary = nullptr;
}
} }
bool RotaryEncoderImpl::init() bool RotaryEncoderImpl::init()
@@ -42,22 +25,15 @@ bool RotaryEncoderImpl::init()
eventCcw = static_cast<input_broker_event>(moduleConfig.canned_message.inputbroker_event_ccw); eventCcw = static_cast<input_broker_event>(moduleConfig.canned_message.inputbroker_event_ccw);
eventPressed = static_cast<input_broker_event>(moduleConfig.canned_message.inputbroker_event_press); eventPressed = static_cast<input_broker_event>(moduleConfig.canned_message.inputbroker_event_press);
if (rotary == nullptr) { rotary = new RotaryEncoder(moduleConfig.canned_message.inputbroker_pin_a, moduleConfig.canned_message.inputbroker_pin_b,
rotary = new RotaryEncoder(moduleConfig.canned_message.inputbroker_pin_a, moduleConfig.canned_message.inputbroker_pin_b, moduleConfig.canned_message.inputbroker_pin_press);
moduleConfig.canned_message.inputbroker_pin_press); rotary->resetButton();
}
attachRotaryEncoderInterrupts(); interruptInstance = this;
auto interruptHandler = []() { inputBroker->requestPollSoon(interruptInstance); };
#ifdef ARCH_ESP32 attachInterrupt(moduleConfig.canned_message.inputbroker_pin_a, interruptHandler, CHANGE);
// Register callbacks for before and after lightsleep attachInterrupt(moduleConfig.canned_message.inputbroker_pin_b, interruptHandler, CHANGE);
// Used to detach and reattach interrupts attachInterrupt(moduleConfig.canned_message.inputbroker_pin_press, interruptHandler, CHANGE);
if (isFirstInit) {
lsObserver.observe(&notifyLightSleep);
lsEndObserver.observe(&notifyLightSleepEnd);
isFirstInit = false;
}
#endif
LOG_INFO("RotaryEncoder initialized pins(%d, %d, %d), events(%d, %d, %d)", moduleConfig.canned_message.inputbroker_pin_a, LOG_INFO("RotaryEncoder initialized pins(%d, %d, %d), events(%d, %d, %d)", moduleConfig.canned_message.inputbroker_pin_a,
moduleConfig.canned_message.inputbroker_pin_b, moduleConfig.canned_message.inputbroker_pin_press, eventCw, eventCcw, moduleConfig.canned_message.inputbroker_pin_b, moduleConfig.canned_message.inputbroker_pin_press, eventCw, eventCcw,
@@ -95,50 +71,6 @@ void RotaryEncoderImpl::pollOnce()
} }
} }
void RotaryEncoderImpl::detachRotaryEncoderInterrupts()
{
LOG_DEBUG("RotaryEncoderImpl detach button interrupts");
if (interruptInstance == this) {
detachInterrupt(moduleConfig.canned_message.inputbroker_pin_a);
detachInterrupt(moduleConfig.canned_message.inputbroker_pin_b);
detachInterrupt(moduleConfig.canned_message.inputbroker_pin_press);
interruptInstance = nullptr;
} else {
LOG_WARN("RotaryEncoderImpl: interrupts already detached");
}
}
void RotaryEncoderImpl::attachRotaryEncoderInterrupts()
{
LOG_DEBUG("RotaryEncoderImpl attach button interrupts");
if (rotary != nullptr && interruptInstance == nullptr) {
rotary->resetButton();
interruptInstance = this;
auto interruptHandler = []() { inputBroker->requestPollSoon(interruptInstance); };
attachInterrupt(moduleConfig.canned_message.inputbroker_pin_a, interruptHandler, CHANGE);
attachInterrupt(moduleConfig.canned_message.inputbroker_pin_b, interruptHandler, CHANGE);
attachInterrupt(moduleConfig.canned_message.inputbroker_pin_press, interruptHandler, CHANGE);
} else {
LOG_WARN("RotaryEncoderImpl: interrupts already attached");
}
}
#ifdef ARCH_ESP32
int RotaryEncoderImpl::beforeLightSleep(void *unused)
{
detachRotaryEncoderInterrupts();
return 0; // Indicates success;
}
int RotaryEncoderImpl::afterLightSleep(esp_sleep_wakeup_cause_t cause)
{
attachRotaryEncoderInterrupts();
return 0; // Indicates success;
}
#endif
RotaryEncoderImpl *RotaryEncoderImpl::interruptInstance; RotaryEncoderImpl *RotaryEncoderImpl::interruptInstance;
#endif #endif
+2 -23
View File
@@ -8,18 +8,12 @@
class RotaryEncoder; class RotaryEncoder;
class RotaryEncoderImpl final : public InputPollable class RotaryEncoderImpl : public InputPollable
{ {
public: public:
RotaryEncoderImpl(); RotaryEncoderImpl();
~RotaryEncoderImpl() override; bool init(void);
bool init();
virtual void pollOnce() override; virtual void pollOnce() override;
// Disconnect and reconnect interrupts for light sleep
#ifdef ARCH_ESP32
int beforeLightSleep(void *unused);
int afterLightSleep(esp_sleep_wakeup_cause_t cause);
#endif
protected: protected:
static RotaryEncoderImpl *interruptInstance; static RotaryEncoderImpl *interruptInstance;
@@ -29,21 +23,6 @@ class RotaryEncoderImpl final : public InputPollable
input_broker_event eventPressed = INPUT_BROKER_NONE; input_broker_event eventPressed = INPUT_BROKER_NONE;
RotaryEncoder *rotary; RotaryEncoder *rotary;
private:
#ifdef ARCH_ESP32
bool isFirstInit;
#endif
void detachRotaryEncoderInterrupts();
void attachRotaryEncoderInterrupts();
#ifdef ARCH_ESP32
// Get notified when lightsleep begins and ends
CallbackObserver<RotaryEncoderImpl, void *> lsObserver =
CallbackObserver<RotaryEncoderImpl, void *>(this, &RotaryEncoderImpl::beforeLightSleep);
CallbackObserver<RotaryEncoderImpl, esp_sleep_wakeup_cause_t> lsEndObserver =
CallbackObserver<RotaryEncoderImpl, esp_sleep_wakeup_cause_t>(this, &RotaryEncoderImpl::afterLightSleep);
#endif
}; };
extern RotaryEncoderImpl *rotaryEncoderImpl; extern RotaryEncoderImpl *rotaryEncoderImpl;
@@ -27,9 +27,7 @@ bool RotaryEncoderInterruptImpl1::init()
RotaryEncoderInterruptImpl1::handleIntA, RotaryEncoderInterruptImpl1::handleIntB, RotaryEncoderInterruptImpl1::handleIntA, RotaryEncoderInterruptImpl1::handleIntB,
RotaryEncoderInterruptImpl1::handleIntPressed); RotaryEncoderInterruptImpl1::handleIntPressed);
inputBroker->registerSource(this); inputBroker->registerSource(this);
#ifndef HAS_PHYSICAL_KEYBOARD
osk_found = true; osk_found = true;
#endif
return true; return true;
} }
-2
View File
@@ -45,9 +45,7 @@ void TrackballInterruptBase::init(uint8_t pinDown, uint8_t pinUp, uint8_t pinLef
LOG_DEBUG("Trackball GPIO initialized - UP:%d DOWN:%d LEFT:%d RIGHT:%d PRESS:%d", this->_pinUp, this->_pinDown, LOG_DEBUG("Trackball GPIO initialized - UP:%d DOWN:%d LEFT:%d RIGHT:%d PRESS:%d", this->_pinUp, this->_pinDown,
this->_pinLeft, this->_pinRight, pinPress); this->_pinLeft, this->_pinRight, pinPress);
#ifndef HAS_PHYSICAL_KEYBOARD
osk_found = true; osk_found = true;
#endif
this->setInterval(100); this->setInterval(100);
} }
-2
View File
@@ -29,9 +29,7 @@ bool UpDownInterruptImpl1::init()
eventDownLong, UpDownInterruptImpl1::handleIntDown, UpDownInterruptImpl1::handleIntUp, eventDownLong, UpDownInterruptImpl1::handleIntDown, UpDownInterruptImpl1::handleIntUp,
UpDownInterruptImpl1::handleIntPressed); UpDownInterruptImpl1::handleIntPressed);
inputBroker->registerSource(this); inputBroker->registerSource(this);
#ifndef HAS_PHYSICAL_KEYBOARD
osk_found = true; osk_found = true;
#endif
return true; return true;
} }
-4
View File
@@ -440,11 +440,9 @@ void setup()
LOG_INFO("\n\n//\\ E S H T /\\ S T / C\n"); LOG_INFO("\n\n//\\ E S H T /\\ S T / C\n");
#if defined(ARCH_ESP32) && defined(BOARD_HAS_PSRAM) #if defined(ARCH_ESP32) && defined(BOARD_HAS_PSRAM)
#ifndef SENSECAP_INDICATOR
// use PSRAM for malloc calls > 256 bytes // use PSRAM for malloc calls > 256 bytes
heap_caps_malloc_extmem_enable(256); heap_caps_malloc_extmem_enable(256);
#endif #endif
#endif
#if defined(DEBUG_MUTE) && defined(DEBUG_PORT) #if defined(DEBUG_MUTE) && defined(DEBUG_PORT)
DEBUG_PORT.printf("\r\n\r\n//\\ E S H T /\\ S T / C\r\n"); DEBUG_PORT.printf("\r\n\r\n//\\ E S H T /\\ S T / C\r\n");
@@ -1458,10 +1456,8 @@ void setup()
#endif #endif
#if defined(HAS_TRACKBALL) || (defined(INPUTDRIVER_ENCODER_TYPE) && INPUTDRIVER_ENCODER_TYPE == 2) #if defined(HAS_TRACKBALL) || (defined(INPUTDRIVER_ENCODER_TYPE) && INPUTDRIVER_ENCODER_TYPE == 2)
#ifndef HAS_PHYSICAL_KEYBOARD
osk_found = true; osk_found = true;
#endif #endif
#endif
#if defined(ARCH_ESP32) && !MESHTASTIC_EXCLUDE_WEBSERVER #if defined(ARCH_ESP32) && !MESHTASTIC_EXCLUDE_WEBSERVER
// Start web server thread. // Start web server thread.
-4
View File
@@ -124,10 +124,6 @@ void FloodingRouter::perhapsCancelDupe(const meshtastic_MeshPacket *p)
if (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER_LATE && iface) { if (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER_LATE && iface) {
iface->clampToLateRebroadcastWindow(getFrom(p), p->id); iface->clampToLateRebroadcastWindow(getFrom(p), p->id);
} }
if (config.device.role == meshtastic_Config_DeviceConfig_Role_CLIENT_BASE && iface && nodeDB &&
nodeDB->isFromOrToFavoritedNode(*p)) {
iface->clampToLateRebroadcastWindow(getFrom(p), p->id);
}
} }
bool FloodingRouter::isRebroadcaster() bool FloodingRouter::isRebroadcaster()
+2 -2
View File
@@ -195,7 +195,7 @@ void MeshModule::callModules(meshtastic_MeshPacket &mp, RxSource src)
// but opted NOT TO. Because it is not a good idea to let remote nodes 'probe' to find out which PSKs were "good" vs // but opted NOT TO. Because it is not a good idea to let remote nodes 'probe' to find out which PSKs were "good" vs
// bad. // bad.
routingModule->sendAckNak(meshtastic_Routing_Error_NO_RESPONSE, getFrom(&mp), mp.id, mp.channel, routingModule->sendAckNak(meshtastic_Routing_Error_NO_RESPONSE, getFrom(&mp), mp.id, mp.channel,
routingModule->getHopLimitForResponse(mp)); routingModule->getHopLimitForResponse(mp.hop_start, mp.hop_limit));
} }
} }
@@ -235,7 +235,7 @@ void setReplyTo(meshtastic_MeshPacket *p, const meshtastic_MeshPacket &to)
assert(p->which_payload_variant == meshtastic_MeshPacket_decoded_tag); // Should already be set by now assert(p->which_payload_variant == meshtastic_MeshPacket_decoded_tag); // Should already be set by now
p->to = getFrom(&to); // Make sure that if we are sending to the local node, we use our local node addr, not 0 p->to = getFrom(&to); // Make sure that if we are sending to the local node, we use our local node addr, not 0
p->channel = to.channel; // Use the same channel that the request came in on p->channel = to.channel; // Use the same channel that the request came in on
p->hop_limit = routingModule->getHopLimitForResponse(to); p->hop_limit = routingModule->getHopLimitForResponse(to.hop_start, to.hop_limit);
// No need for an ack if we are just delivering locally (it just generates an ignored ack) // No need for an ack if we are just delivering locally (it just generates an ignored ack)
p->want_ack = (to.from != 0) ? to.want_ack : false; p->want_ack = (to.from != 0) ? to.want_ack : false;
+1 -1
View File
@@ -225,4 +225,4 @@ class MeshModule
/** set the destination and packet parameters of packet p intended as a reply to a particular "to" packet /** set the destination and packet parameters of packet p intended as a reply to a particular "to" packet
* This ensures that if the request packet was sent reliably, the reply is sent that way as well. * This ensures that if the request packet was sent reliably, the reply is sent that way as well.
*/ */
void setReplyTo(meshtastic_MeshPacket *p, const meshtastic_MeshPacket &to); void setReplyTo(meshtastic_MeshPacket *p, const meshtastic_MeshPacket &to);
+5 -6
View File
@@ -93,8 +93,11 @@ int MeshService::handleFromRadio(const meshtastic_MeshPacket *mp)
} else if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag && !nodeDB->getMeshNode(mp->from)->has_user && } else if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag && !nodeDB->getMeshNode(mp->from)->has_user &&
nodeInfoModule && !isPreferredRebroadcaster && !nodeDB->isFull()) { nodeInfoModule && !isPreferredRebroadcaster && !nodeDB->isFull()) {
if (airTime->isTxAllowedChannelUtil(true)) { if (airTime->isTxAllowedChannelUtil(true)) {
const int8_t hopsUsed = getHopsAway(*mp, config.lora.hop_limit); // Hops used by the request. If somebody in between running modified firmware modified it, ignore it
if (hopsUsed > (int32_t)(config.lora.hop_limit + 2)) { auto hopStart = mp->hop_start;
auto hopLimit = mp->hop_limit;
uint8_t hopsUsed = hopStart < hopLimit ? config.lora.hop_limit : hopStart - hopLimit;
if (hopsUsed > config.lora.hop_limit + 2) {
LOG_DEBUG("Skip send NodeInfo: %d hops away is too far away", hopsUsed); LOG_DEBUG("Skip send NodeInfo: %d hops away is too far away", hopsUsed);
} else { } else {
LOG_INFO("Heard new node on ch. %d, send NodeInfo and ask for response", mp->channel); LOG_INFO("Heard new node on ch. %d, send NodeInfo and ask for response", mp->channel);
@@ -273,10 +276,6 @@ bool MeshService::trySendPosition(NodeNum dest, bool wantReplies)
if (nodeDB->hasValidPosition(node)) { if (nodeDB->hasValidPosition(node)) {
#if HAS_GPS && !MESHTASTIC_EXCLUDE_GPS #if HAS_GPS && !MESHTASTIC_EXCLUDE_GPS
if (positionModule) { if (positionModule) {
if (!config.position.fixed_position && !nodeDB->hasLocalPositionSinceBoot()) {
LOG_DEBUG("Skip position ping; no fresh position since boot");
return false;
}
LOG_INFO("Send position ping to 0x%x, wantReplies=%d, channel=%d", dest, wantReplies, node->channel); LOG_INFO("Send position ping to 0x%x, wantReplies=%d, channel=%d", dest, wantReplies, node->channel);
positionModule->sendOurPosition(dest, wantReplies, node->channel); positionModule->sendOurPosition(dest, wantReplies, node->channel);
return true; return true;
+3 -2
View File
@@ -64,7 +64,7 @@ bool NextHopRouter::shouldFilterReceived(const meshtastic_MeshPacket *p)
perhapsRebroadcast(p); perhapsRebroadcast(p);
} }
} else { } else {
bool isRepeated = getHopsAway(*p) == 0; bool isRepeated = p->hop_start > 0 && p->hop_start == p->hop_limit;
// If repeated and not in Tx queue anymore, try relaying again, or if we are the destination, send the ACK again // If repeated and not in Tx queue anymore, try relaying again, or if we are the destination, send the ACK again
if (isRepeated) { if (isRepeated) {
if (!findInTxQueue(p->from, p->id)) { if (!findInTxQueue(p->from, p->id)) {
@@ -101,7 +101,8 @@ void NextHopRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtast
bool wasAlreadyRelayer = wasRelayer(p->relay_node, p->decoded.request_id, p->to); bool wasAlreadyRelayer = wasRelayer(p->relay_node, p->decoded.request_id, p->to);
bool weWereSoleRelayer = false; bool weWereSoleRelayer = false;
bool weWereRelayer = wasRelayer(ourRelayID, p->decoded.request_id, p->to, &weWereSoleRelayer); bool weWereRelayer = wasRelayer(ourRelayID, p->decoded.request_id, p->to, &weWereSoleRelayer);
if ((weWereRelayer && wasAlreadyRelayer) || (getHopsAway(*p) == 0 && weWereSoleRelayer)) { if ((weWereRelayer && wasAlreadyRelayer) ||
(p->hop_start != 0 && p->hop_start == p->hop_limit && weWereSoleRelayer)) {
if (origTx->next_hop != p->relay_node) { // Not already set if (origTx->next_hop != p->relay_node) { // Not already set
LOG_INFO("Update next hop of 0x%x to 0x%x based on ACK/reply (was relayer %d we were sole %d)", p->from, LOG_INFO("Update next hop of 0x%x to 0x%x based on ACK/reply (was relayer %d we were sole %d)", p->from,
p->relay_node, wasAlreadyRelayer, weWereSoleRelayer); p->relay_node, wasAlreadyRelayer, weWereSoleRelayer);
+124 -158
View File
@@ -15,7 +15,6 @@
#include "RTC.h" #include "RTC.h"
#include "Router.h" #include "Router.h"
#include "SPILock.h" #include "SPILock.h"
#include "SafeFile.h"
#include "TypeConversions.h" #include "TypeConversions.h"
#include "error.h" #include "error.h"
#include "main.h" #include "main.h"
@@ -314,7 +313,7 @@ NodeDB::NodeDB()
LOG_DEBUG("Number of Device Reboots: %d", myNodeInfo.reboot_count); LOG_DEBUG("Number of Device Reboots: %d", myNodeInfo.reboot_count);
#endif #endif
resetRadioConfig(); // If bogus settings got saved, then fix them _resetRadioConfig(); // If bogus settings got saved, then fix them
// nodeDB->LOG_DEBUG("region=%d, NODENUM=0x%x, dbsize=%d", config.lora.region, myNodeInfo.my_node_num, numMeshNodes); // nodeDB->LOG_DEBUG("region=%d, NODENUM=0x%x, dbsize=%d", config.lora.region, myNodeInfo.my_node_num, numMeshNodes);
// Uncomment below to always enable UDP broadcasts // Uncomment below to always enable UDP broadcasts
@@ -425,13 +424,13 @@ NodeDB::NodeDB()
config.has_position = true; config.has_position = true;
info->has_position = true; info->has_position = true;
info->position = TypeConversions::ConvertToPositionLite(fixedGPS); info->position = TypeConversions::ConvertToPositionLite(fixedGPS);
nodeDB->setLocalPosition(fixedGPS); nodeDB->_setLocalPosition(fixedGPS);
config.position.fixed_position = true; config.position.fixed_position = true;
#endif #endif
} }
#endif #endif
sortMeshDB(); sortMeshDB();
saveToDisk(saveWhat); _saveToDisk(saveWhat);
} }
/** /**
@@ -460,7 +459,7 @@ bool isBroadcast(uint32_t dest)
return dest == NODENUM_BROADCAST || dest == NODENUM_BROADCAST_NO_LORA; return dest == NODENUM_BROADCAST || dest == NODENUM_BROADCAST_NO_LORA;
} }
void NodeDB::resetRadioConfig(bool is_fresh_install) void NodeDB::_resetRadioConfig(bool is_fresh_install)
{ {
if (is_fresh_install) { if (is_fresh_install) {
radioGeneration++; radioGeneration++;
@@ -480,6 +479,7 @@ void NodeDB::resetRadioConfig(bool is_fresh_install)
bool NodeDB::factoryReset(bool eraseBleBonds) bool NodeDB::factoryReset(bool eraseBleBonds)
{ {
FUNCTION_START("factoryReset");
LOG_INFO("Perform factory reset!"); LOG_INFO("Perform factory reset!");
// first, remove the "/prefs" (this removes most prefs) // first, remove the "/prefs" (this removes most prefs)
spiLock->lock(); spiLock->lock();
@@ -498,7 +498,7 @@ bool NodeDB::factoryReset(bool eraseBleBonds)
installDefaultModuleConfig(); installDefaultModuleConfig();
installDefaultChannels(); installDefaultChannels();
// third, write everything to disk // third, write everything to disk
saveToDisk(); _saveToDisk();
if (eraseBleBonds) { if (eraseBleBonds) {
LOG_INFO("Erase BLE bonds"); LOG_INFO("Erase BLE bonds");
#ifdef ARCH_ESP32 #ifdef ARCH_ESP32
@@ -513,6 +513,7 @@ bool NodeDB::factoryReset(bool eraseBleBonds)
Bluefruit.Central.clearBonds(); Bluefruit.Central.clearBonds();
#endif #endif
} }
FUNCTION_END;
return true; return true;
} }
@@ -649,7 +650,7 @@ void NodeDB::installDefaultConfig(bool preserveKey = false)
config.device.node_info_broadcast_secs = default_node_info_broadcast_secs; config.device.node_info_broadcast_secs = default_node_info_broadcast_secs;
config.security.serial_enabled = true; config.security.serial_enabled = true;
config.security.admin_channel_enabled = false; config.security.admin_channel_enabled = false;
resetRadioConfig(true); // This also triggers NodeInfo/Position requests since we're fresh _resetRadioConfig(true); // This also triggers NodeInfo/Position requests since we're fresh
strncpy(config.network.ntp_server, "meshtastic.pool.ntp.org", 32); strncpy(config.network.ntp_server, "meshtastic.pool.ntp.org", 32);
#if (defined(T_DECK) || defined(T_WATCH_S3) || defined(UNPHONE) || defined(PICOMPUTER_S3) || defined(SENSECAP_INDICATOR) || \ #if (defined(T_DECK) || defined(T_WATCH_S3) || defined(UNPHONE) || defined(PICOMPUTER_S3) || defined(SENSECAP_INDICATOR) || \
@@ -746,7 +747,7 @@ void NodeDB::installDefaultConfig(bool preserveKey = false)
#ifdef USERPREFS_CONFIG_DEVICE_ROLE #ifdef USERPREFS_CONFIG_DEVICE_ROLE
// Apply role-specific defaults when role is set via user preferences // Apply role-specific defaults when role is set via user preferences
installRoleDefaults(config.device.role); _installRoleDefaults(config.device.role);
#endif #endif
initConfigIntervals(); initConfigIntervals();
@@ -805,16 +806,11 @@ void NodeDB::installDefaultModuleConfig()
moduleConfig.external_notification.output_ms = 500; moduleConfig.external_notification.output_ms = 500;
moduleConfig.external_notification.nag_timeout = 2; moduleConfig.external_notification.nag_timeout = 2;
#endif #endif
#if defined(RAK4630) || defined(RAK11310) || defined(RAK3312) || defined(MUZI_BASE) || defined(ELECROW_ThinkNode_M3) || \ #if defined(RAK4630) || defined(RAK11310) || defined(RAK3312)
defined(ELECROW_ThinkNode_M6) // Default to RAK led pin 2 (blue)
// Default to PIN_LED2 for external notification output (LED color depends on device variant)
moduleConfig.external_notification.enabled = true; moduleConfig.external_notification.enabled = true;
moduleConfig.external_notification.output = PIN_LED2; moduleConfig.external_notification.output = PIN_LED2;
#if defined(MUZI_BASE) || defined(ELECROW_ThinkNode_M3)
moduleConfig.external_notification.active = false;
#else
moduleConfig.external_notification.active = true; moduleConfig.external_notification.active = true;
#endif
moduleConfig.external_notification.alert_message = true; moduleConfig.external_notification.alert_message = true;
moduleConfig.external_notification.output_ms = 1000; moduleConfig.external_notification.output_ms = 1000;
moduleConfig.external_notification.nag_timeout = default_ringtone_nag_secs; moduleConfig.external_notification.nag_timeout = default_ringtone_nag_secs;
@@ -909,7 +905,7 @@ void NodeDB::installDefaultModuleConfig()
initModuleConfigIntervals(); initModuleConfigIntervals();
} }
void NodeDB::installRoleDefaults(meshtastic_Config_DeviceConfig_Role role) void NodeDB::_installRoleDefaults(meshtastic_Config_DeviceConfig_Role role)
{ {
if (role == meshtastic_Config_DeviceConfig_Role_ROUTER) { if (role == meshtastic_Config_DeviceConfig_Role_ROUTER) {
initConfigIntervals(); initConfigIntervals();
@@ -995,6 +991,7 @@ void NodeDB::installDefaultChannels()
void NodeDB::resetNodes(bool keepFavorites) void NodeDB::resetNodes(bool keepFavorites)
{ {
FUNCTION_START("resetNodes");
if (!config.position.fixed_position) if (!config.position.fixed_position)
clearLocalPosition(); clearLocalPosition();
numMeshNodes = 1; numMeshNodes = 1;
@@ -1018,10 +1015,12 @@ void NodeDB::resetNodes(bool keepFavorites)
saveDeviceStateToDisk(); saveDeviceStateToDisk();
if (neighborInfoModule && moduleConfig.neighbor_info.enabled) if (neighborInfoModule && moduleConfig.neighbor_info.enabled)
neighborInfoModule->resetNeighbors(); neighborInfoModule->resetNeighbors();
FUNCTION_END;
} }
void NodeDB::removeNodeByNum(NodeNum nodeNum) void NodeDB::removeNodeByNum(NodeNum nodeNum)
{ {
FUNCTION_START("removeNodeByNum");
int newPos = 0, removed = 0; int newPos = 0, removed = 0;
for (int i = 0; i < numMeshNodes; i++) { for (int i = 0; i < numMeshNodes; i++) {
if (meshNodes->at(i).num != nodeNum) if (meshNodes->at(i).num != nodeNum)
@@ -1034,17 +1033,17 @@ void NodeDB::removeNodeByNum(NodeNum nodeNum)
meshtastic_NodeInfoLite()); meshtastic_NodeInfoLite());
LOG_DEBUG("NodeDB::removeNodeByNum purged %d entries. Save changes", removed); LOG_DEBUG("NodeDB::removeNodeByNum purged %d entries. Save changes", removed);
saveNodeDatabaseToDisk(); saveNodeDatabaseToDisk();
FUNCTION_END;
} }
void NodeDB::clearLocalPosition() void NodeDB::_clearLocalPosition()
{ {
meshtastic_NodeInfoLite *node = getMeshNode(nodeDB->getNodeNum()); meshtastic_NodeInfoLite *node = _getMeshNode(nodeDB->getNodeNum());
node->position.latitude_i = 0; node->position.latitude_i = 0;
node->position.longitude_i = 0; node->position.longitude_i = 0;
node->position.altitude = 0; node->position.altitude = 0;
node->position.time = 0; node->position.time = 0;
setLocalPosition(meshtastic_Position_init_default); _setLocalPosition(meshtastic_Position_init_default);
localPositionUpdatedSinceBoot = false;
} }
void NodeDB::cleanupMeshDB() void NodeDB::cleanupMeshDB()
@@ -1120,7 +1119,7 @@ void NodeDB::pickNewNodeNum()
} }
meshtastic_NodeInfoLite *found; meshtastic_NodeInfoLite *found;
while (((found = getMeshNode(nodeNum)) && memcmp(found->user.macaddr, ourMacAddr, sizeof(ourMacAddr)) != 0) || while (((found = _getMeshNode(nodeNum)) && memcmp(found->user.macaddr, ourMacAddr, sizeof(ourMacAddr)) != 0) ||
(nodeNum == NODENUM_BROADCAST || nodeNum < NUM_RESERVED)) { (nodeNum == NODENUM_BROADCAST || nodeNum < NUM_RESERVED)) {
NodeNum candidate = random(NUM_RESERVED, LONG_MAX); // try a new random choice NodeNum candidate = random(NUM_RESERVED, LONG_MAX); // try a new random choice
if (found) if (found)
@@ -1134,39 +1133,6 @@ void NodeDB::pickNewNodeNum()
myNodeInfo.my_node_num = nodeNum; myNodeInfo.my_node_num = nodeNum;
} }
/** Load a protobuf from a file, return LoadFileResult */
LoadFileResult NodeDB::loadProto(const char *filename, size_t protoSize, size_t objSize, const pb_msgdesc_t *fields,
void *dest_struct)
{
LoadFileResult state = LoadFileResult::OTHER_FAILURE;
#ifdef FSCom
concurrency::LockGuard g(spiLock);
auto f = FSCom.open(filename, FILE_O_READ);
if (f) {
LOG_INFO("Load %s", filename);
pb_istream_t stream = {&readcb, &f, protoSize};
if (fields != &meshtastic_NodeDatabase_msg) // contains a vector object
memset(dest_struct, 0, objSize);
if (!pb_decode(&stream, fields, dest_struct)) {
LOG_ERROR("Error: can't decode protobuf %s", PB_GET_ERROR(&stream));
state = LoadFileResult::DECODE_FAILED;
} else {
LOG_INFO("Loaded %s successfully", filename);
state = LoadFileResult::LOAD_SUCCESS;
}
f.close();
} else {
LOG_ERROR("Could not open / read %s", filename);
}
#else
LOG_ERROR("ERROR: Filesystem not implemented");
state = LoadFileResult::NO_FILESYSTEM;
#endif
return state;
}
void NodeDB::loadFromDisk() void NodeDB::loadFromDisk()
{ {
// Mark the current device state as completely unusable, so that if we fail reading the entire file from // Mark the current device state as completely unusable, so that if we fail reading the entire file from
@@ -1266,7 +1232,7 @@ void NodeDB::loadFromDisk()
if (backupSecurity.private_key.size > 0) { if (backupSecurity.private_key.size > 0) {
LOG_DEBUG("Restoring backup of security config"); LOG_DEBUG("Restoring backup of security config");
config.security = backupSecurity; config.security = backupSecurity;
saveToDisk(SEGMENT_CONFIG); _saveToDisk(SEGMENT_CONFIG);
} }
// Make sure we load hard coded admin keys even when the configuration file has none. // Make sure we load hard coded admin keys even when the configuration file has none.
@@ -1317,7 +1283,7 @@ void NodeDB::loadFromDisk()
if (numAdminKeys > 0) { if (numAdminKeys > 0) {
LOG_INFO("Saving %d hard coded admin keys.", numAdminKeys); LOG_INFO("Saving %d hard coded admin keys.", numAdminKeys);
config.security.admin_key_count = numAdminKeys; config.security.admin_key_count = numAdminKeys;
saveToDisk(SEGMENT_CONFIG); _saveToDisk(SEGMENT_CONFIG);
} }
state = loadProto(moduleConfigFileName, meshtastic_LocalModuleConfig_size, sizeof(meshtastic_LocalModuleConfig), state = loadProto(moduleConfigFileName, meshtastic_LocalModuleConfig_size, sizeof(meshtastic_LocalModuleConfig),
@@ -1369,7 +1335,7 @@ void NodeDB::loadFromDisk()
if (moduleConfig.paxcounter.paxcounter_update_interval == 900) if (moduleConfig.paxcounter.paxcounter_update_interval == 900)
moduleConfig.paxcounter.paxcounter_update_interval = 0; moduleConfig.paxcounter.paxcounter_update_interval = 0;
saveToDisk(SEGMENT_MODULECONFIG); _saveToDisk(SEGMENT_MODULECONFIG);
} }
#if ARCH_PORTDUINO #if ARCH_PORTDUINO
// set any config overrides // set any config overrides
@@ -1380,34 +1346,6 @@ void NodeDB::loadFromDisk()
#endif #endif
} }
/** Save a protobuf from a file, return true for success */
bool NodeDB::saveProto(const char *filename, size_t protoSize, const pb_msgdesc_t *fields, const void *dest_struct,
bool fullAtomic)
{
bool okay = false;
#ifdef FSCom
auto f = SafeFile(filename, fullAtomic);
LOG_INFO("Save %s", filename);
pb_ostream_t stream = {&writecb, static_cast<Print *>(&f), protoSize};
if (!pb_encode(&stream, fields, dest_struct)) {
LOG_ERROR("Error: can't encode protobuf %s", PB_GET_ERROR(&stream));
} else {
okay = true;
}
bool writeSucceeded = f.close();
if (!okay || !writeSucceeded) {
LOG_ERROR("Can't write prefs!");
}
#else
LOG_ERROR("ERROR: Filesystem not implemented");
#endif
return okay;
}
bool NodeDB::saveChannelsToDisk() bool NodeDB::saveChannelsToDisk()
{ {
#ifdef FSCom #ifdef FSCom
@@ -1496,7 +1434,7 @@ bool NodeDB::saveToDiskNoRetry(int saveWhat)
return success; return success;
} }
bool NodeDB::saveToDisk(int saveWhat) bool NodeDB::_saveToDisk(int saveWhat)
{ {
LOG_DEBUG("Save to disk %d", saveWhat); LOG_DEBUG("Save to disk %d", saveWhat);
bool success = saveToDiskNoRetry(saveWhat); bool success = saveToDiskNoRetry(saveWhat);
@@ -1520,10 +1458,12 @@ bool NodeDB::saveToDisk(int saveWhat)
const meshtastic_NodeInfoLite *NodeDB::readNextMeshNode(uint32_t &readIndex) const meshtastic_NodeInfoLite *NodeDB::readNextMeshNode(uint32_t &readIndex)
{ {
FUNCTION_START("readNextMeshNode");
meshtastic_NodeInfoLite *retVal = nullptr;
if (readIndex < numMeshNodes) if (readIndex < numMeshNodes)
return &meshNodes->at(readIndex++); retVal = &meshNodes->at(readIndex++);
else FUNCTION_END;
return NULL; return retVal;
} }
/// Given a node, return how many seconds in the past (vs now) that we last heard from it /// Given a node, return how many seconds in the past (vs now) that we last heard from it
@@ -1549,26 +1489,9 @@ uint32_t sinceReceived(const meshtastic_MeshPacket *p)
return delta; return delta;
} }
int8_t getHopsAway(const meshtastic_MeshPacket &p, int8_t defaultIfUnknown)
{
// Firmware prior to 2.3.0 (585805c) lacked a hop_start field. Firmware version 2.5.0 (bf34329) introduced a
// bitfield that is always present. Use the presence of the bitfield to determine if the origin's firmware
// version is guaranteed to have hop_start populated. Note that this can only be done for decoded packets as
// the bitfield is encrypted under the channel encryption key. For encrypted packets, this returns
// defaultIfUnknown when hop_start is 0.
if (p.hop_start == 0 && !(p.which_payload_variant == meshtastic_MeshPacket_decoded_tag && p.decoded.has_bitfield))
return defaultIfUnknown; // Cannot reliably determine the number of hops.
// Guard against invalid values.
if (p.hop_start < p.hop_limit)
return defaultIfUnknown;
return p.hop_start - p.hop_limit;
}
#define NUM_ONLINE_SECS (60 * 60 * 2) // 2 hrs to consider someone offline #define NUM_ONLINE_SECS (60 * 60 * 2) // 2 hrs to consider someone offline
size_t NodeDB::getNumOnlineMeshNodes(bool localOnly) size_t NodeDB::_getNumOnlineMeshNodes(bool localOnly)
{ {
size_t numseen = 0; size_t numseen = 0;
@@ -1590,8 +1513,10 @@ size_t NodeDB::getNumOnlineMeshNodes(bool localOnly)
*/ */
void NodeDB::updatePosition(uint32_t nodeId, const meshtastic_Position &p, RxSource src) void NodeDB::updatePosition(uint32_t nodeId, const meshtastic_Position &p, RxSource src)
{ {
FUNCTION_START("updatePosition");
meshtastic_NodeInfoLite *info = getOrCreateMeshNode(nodeId); meshtastic_NodeInfoLite *info = getOrCreateMeshNode(nodeId);
if (!info) { if (!info) {
FUNCTION_END;
return; return;
} }
@@ -1600,7 +1525,7 @@ void NodeDB::updatePosition(uint32_t nodeId, const meshtastic_Position &p, RxSou
LOG_INFO("updatePosition LOCAL pos@%x time=%u lat=%d lon=%d alt=%d", p.timestamp, p.time, p.latitude_i, p.longitude_i, LOG_INFO("updatePosition LOCAL pos@%x time=%u lat=%d lon=%d alt=%d", p.timestamp, p.time, p.latitude_i, p.longitude_i,
p.altitude); p.altitude);
setLocalPosition(p); _setLocalPosition(p);
info->position = TypeConversions::ConvertToPositionLite(p); info->position = TypeConversions::ConvertToPositionLite(p);
} else if ((p.time > 0) && !p.latitude_i && !p.longitude_i && !p.timestamp && !p.location_source) { } else if ((p.time > 0) && !p.latitude_i && !p.longitude_i && !p.timestamp && !p.location_source) {
// FIXME SPECIAL TIME SETTING PACKET FROM EUD TO RADIO // FIXME SPECIAL TIME SETTING PACKET FROM EUD TO RADIO
@@ -1627,7 +1552,8 @@ void NodeDB::updatePosition(uint32_t nodeId, const meshtastic_Position &p, RxSou
} }
info->has_position = true; info->has_position = true;
updateGUIforNode = info; updateGUIforNode = info;
notifyObservers(true); // Force an update whether or not our node counts have changed _notifyObservers(true); // Force an update whether or not our node counts have changed
FUNCTION_END;
} }
/** Update telemetry info for this node based on received metrics /** Update telemetry info for this node based on received metrics
@@ -1635,9 +1561,11 @@ void NodeDB::updatePosition(uint32_t nodeId, const meshtastic_Position &p, RxSou
*/ */
void NodeDB::updateTelemetry(uint32_t nodeId, const meshtastic_Telemetry &t, RxSource src) void NodeDB::updateTelemetry(uint32_t nodeId, const meshtastic_Telemetry &t, RxSource src)
{ {
FUNCTION_START("updatePosition");
meshtastic_NodeInfoLite *info = getOrCreateMeshNode(nodeId); meshtastic_NodeInfoLite *info = getOrCreateMeshNode(nodeId);
// Environment metrics should never go to NodeDb but we'll safegaurd anyway // Environment metrics should never go to NodeDb but we'll safegaurd anyway
if (!info || t.which_variant != meshtastic_Telemetry_device_metrics_tag) { if (!info || t.which_variant != meshtastic_Telemetry_device_metrics_tag) {
FUNCTION_END;
return; return;
} }
@@ -1650,7 +1578,8 @@ void NodeDB::updateTelemetry(uint32_t nodeId, const meshtastic_Telemetry &t, RxS
info->device_metrics = t.variant.device_metrics; info->device_metrics = t.variant.device_metrics;
info->has_device_metrics = true; info->has_device_metrics = true;
updateGUIforNode = info; updateGUIforNode = info;
notifyObservers(true); // Force an update whether or not our node counts have changed _notifyObservers(true); // Force an update whether or not our node counts have changed
FUNCTION_END;
} }
/** /**
@@ -1658,8 +1587,10 @@ void NodeDB::updateTelemetry(uint32_t nodeId, const meshtastic_Telemetry &t, RxS
*/ */
void NodeDB::addFromContact(meshtastic_SharedContact contact) void NodeDB::addFromContact(meshtastic_SharedContact contact)
{ {
FUNCTION_START("addFromContact");
meshtastic_NodeInfoLite *info = getOrCreateMeshNode(contact.node_num); meshtastic_NodeInfoLite *info = getOrCreateMeshNode(contact.node_num);
if (!info || !contact.has_user) { if (!info || !contact.has_user) {
FUNCTION_END;
return; return;
} }
// If the local node has this node marked as manually verified // If the local node has this node marked as manually verified
@@ -1668,6 +1599,7 @@ void NodeDB::addFromContact(meshtastic_SharedContact contact)
if ((info->bitfield & NODEINFO_BITFIELD_IS_KEY_MANUALLY_VERIFIED_MASK) && !contact.manually_verified) { if ((info->bitfield & NODEINFO_BITFIELD_IS_KEY_MANUALLY_VERIFIED_MASK) && !contact.manually_verified) {
if (contact.user.public_key.size != info->user.public_key.size || if (contact.user.public_key.size != info->user.public_key.size ||
memcmp(contact.user.public_key.bytes, info->user.public_key.bytes, info->user.public_key.size) != 0) { memcmp(contact.user.public_key.bytes, info->user.public_key.bytes, info->user.public_key.size) != 0) {
FUNCTION_END;
return; return;
} }
} }
@@ -1711,22 +1643,26 @@ void NodeDB::addFromContact(meshtastic_SharedContact contact)
// Mark the node's key as manually verified to indicate trustworthiness. // Mark the node's key as manually verified to indicate trustworthiness.
updateGUIforNode = info; updateGUIforNode = info;
sortMeshDB(); sortMeshDB();
notifyObservers(true); // Force an update whether or not our node counts have changed _notifyObservers(true); // Force an update whether or not our node counts have changed
} }
saveNodeDatabaseToDisk(); saveNodeDatabaseToDisk();
FUNCTION_END;
} }
/** Update user info and channel for this node based on received user data /** Update user info and channel for this node based on received user data
*/ */
bool NodeDB::updateUser(uint32_t nodeId, meshtastic_User &p, uint8_t channelIndex) bool NodeDB::updateUser(uint32_t nodeId, meshtastic_User &p, uint8_t channelIndex)
{ {
FUNCTION_START("updateUser");
meshtastic_NodeInfoLite *info = getOrCreateMeshNode(nodeId); meshtastic_NodeInfoLite *info = getOrCreateMeshNode(nodeId);
if (!info) { if (!info) {
FUNCTION_END;
return false; return false;
} }
#if !(MESHTASTIC_EXCLUDE_PKI) #if !(MESHTASTIC_EXCLUDE_PKI)
if (p.public_key.size == 32 && nodeId != nodeDB->getNodeNum()) { if (p.public_key.size == 32 && nodeId != getNodeNum()) {
printBytes("Incoming Pubkey: ", p.public_key.bytes, 32); printBytes("Incoming Pubkey: ", p.public_key.bytes, 32);
// Alert the user if a remote node is advertising public key that matches our own // Alert the user if a remote node is advertising public key that matches our own
@@ -1743,6 +1679,7 @@ bool NodeDB::updateUser(uint32_t nodeId, meshtastic_User &p, uint8_t channelInde
sprintf(cn->message, warning, p.long_name); sprintf(cn->message, warning, p.long_name);
service->sendClientNotification(cn); service->sendClientNotification(cn);
} }
FUNCTION_END;
return false; return false;
} }
} }
@@ -1750,6 +1687,7 @@ bool NodeDB::updateUser(uint32_t nodeId, meshtastic_User &p, uint8_t channelInde
// if the key doesn't match, don't update nodeDB at all. // if the key doesn't match, don't update nodeDB at all.
if (p.public_key.size != 32 || (memcmp(p.public_key.bytes, info->user.public_key.bytes, 32) != 0)) { if (p.public_key.size != 32 || (memcmp(p.public_key.bytes, info->user.public_key.bytes, 32) != 0)) {
LOG_WARN("Public Key mismatch, dropping NodeInfo"); LOG_WARN("Public Key mismatch, dropping NodeInfo");
FUNCTION_END;
return false; return false;
} }
LOG_INFO("Public Key set for node, not updating!"); LOG_INFO("Public Key set for node, not updating!");
@@ -1777,19 +1715,19 @@ bool NodeDB::updateUser(uint32_t nodeId, meshtastic_User &p, uint8_t channelInde
if (changed) { if (changed) {
updateGUIforNode = info; updateGUIforNode = info;
notifyObservers(true); // Force an update whether or not our node counts have changed _notifyObservers(true); // Force an update whether or not our node counts have changed
// We just changed something about a User, // We just changed something about a User,
// store our DB unless we just did so less than a minute ago // store our DB unless we just did so less than a minute ago
if (!Throttle::isWithinTimespanMs(lastNodeDbSave, ONE_MINUTE_MS)) { if (!Throttle::isWithinTimespanMs(lastNodeDbSave, ONE_MINUTE_MS)) {
saveToDisk(SEGMENT_NODEDATABASE); _saveToDisk(SEGMENT_NODEDATABASE);
lastNodeDbSave = millis(); lastNodeDbSave = millis();
} else { } else {
LOG_DEBUG("Defer NodeDB saveToDisk for now"); LOG_DEBUG("Defer NodeDB saveToDisk for now");
} }
} }
FUNCTION_END;
return changed; return changed;
} }
@@ -1797,108 +1735,121 @@ bool NodeDB::updateUser(uint32_t nodeId, meshtastic_User &p, uint8_t channelInde
/// we updateGUI and updateGUIforNode if we think our this change is big enough for a redraw /// we updateGUI and updateGUIforNode if we think our this change is big enough for a redraw
void NodeDB::updateFrom(const meshtastic_MeshPacket &mp) void NodeDB::updateFrom(const meshtastic_MeshPacket &mp)
{ {
FUNCTION_START("updateFrom");
if (mp.from == getNodeNum()) { if (mp.from == getNodeNum()) {
LOG_DEBUG("Ignore update from self"); LOG_DEBUG("Ignore update from self");
return; } else if (mp.which_payload_variant == meshtastic_MeshPacket_decoded_tag && mp.from) {
}
if (mp.which_payload_variant == meshtastic_MeshPacket_decoded_tag && mp.from) {
LOG_DEBUG("Update DB node 0x%x, rx_time=%u", mp.from, mp.rx_time); LOG_DEBUG("Update DB node 0x%x, rx_time=%u", mp.from, mp.rx_time);
meshtastic_NodeInfoLite *info = getOrCreateMeshNode(getFrom(&mp)); meshtastic_NodeInfoLite *info = getOrCreateMeshNode(getFrom(&mp));
if (!info) { if (info) {
return; if (mp.rx_time) // if the packet has a valid timestamp use it to update our last_heard
info->last_heard = mp.rx_time;
if (mp.rx_snr)
info->snr = mp.rx_snr; // keep the most recent SNR we received for this node.
info->via_mqtt = mp.via_mqtt; // Store if we received this packet via MQTT
// If hopStart was set and there wasn't someone messing with the limit in the middle, add hopsAway
if (mp.hop_start != 0 && mp.hop_limit <= mp.hop_start) {
info->has_hops_away = true;
info->hops_away = mp.hop_start - mp.hop_limit;
}
sortMeshDB();
} }
if (mp.rx_time) // if the packet has a valid timestamp use it to update our last_heard
info->last_heard = mp.rx_time;
if (mp.rx_snr)
info->snr = mp.rx_snr; // keep the most recent SNR we received for this node.
info->via_mqtt = mp.via_mqtt; // Store if we received this packet via MQTT
// If hopStart was set and there wasn't someone messing with the limit in the middle, add hopsAway
const int8_t hopsAway = getHopsAway(mp);
if (hopsAway >= 0) {
info->has_hops_away = true;
info->hops_away = hopsAway;
}
sortMeshDB();
} }
FUNCTION_END;
} }
void NodeDB::set_favorite(bool is_favorite, uint32_t nodeId) void NodeDB::set_favorite(bool is_favorite, uint32_t nodeId)
{ {
meshtastic_NodeInfoLite *lite = getMeshNode(nodeId); FUNCTION_START("set_favorite");
meshtastic_NodeInfoLite *lite = _getMeshNode(nodeId);
if (lite && lite->is_favorite != is_favorite) { if (lite && lite->is_favorite != is_favorite) {
lite->is_favorite = is_favorite; lite->is_favorite = is_favorite;
sortMeshDB(); sortMeshDB();
saveNodeDatabaseToDisk(); saveNodeDatabaseToDisk();
} }
FUNCTION_END;
} }
// returns true if nodeId is_favorite; false if not or not found
bool NodeDB::isFavorite(uint32_t nodeId) bool NodeDB::isFavorite(uint32_t nodeId)
{ {
// returns true if nodeId is_favorite; false if not or not found FUNCTION_START("set_favorite");
// NODENUM_BROADCAST will never be in the DB // NODENUM_BROADCAST will never be in the DB
if (nodeId == NODENUM_BROADCAST) if (nodeId == NODENUM_BROADCAST) {
FUNCTION_END;
return false; return false;
}
meshtastic_NodeInfoLite *lite = getMeshNode(nodeId); meshtastic_NodeInfoLite *lite = _getMeshNode(nodeId);
if (lite) { if (lite) {
FUNCTION_END;
return lite->is_favorite; return lite->is_favorite;
} }
FUNCTION_END;
return false; return false;
} }
bool NodeDB::isFromOrToFavoritedNode(const meshtastic_MeshPacket &p) bool NodeDB::isFromOrToFavoritedNode(const meshtastic_MeshPacket &p)
{ {
FUNCTION_START("isFromOrToFavoritedNode");
// This method is logically equivalent to: // This method is logically equivalent to:
// return isFavorite(p.from) || isFavorite(p.to); // return isFavorite(p.from) || isFavorite(p.to);
// but is more efficient by: // but is more efficient by:
// 1. doing only one pass through the database, instead of two // 1. doing only one pass through the database, instead of two
// 2. exiting early when a favorite is found, or if both from and to have been seen // 2. exiting early when a favorite is found, or if both from and to have been seen
if (p.to == NODENUM_BROADCAST)
return isFavorite(p.from); // we never store NODENUM_BROADCAST in the DB, so we only need to check p.from
meshtastic_NodeInfoLite *lite = NULL; meshtastic_NodeInfoLite *lite = NULL;
bool seenFrom = false; bool seenFrom = false;
bool seenTo = false; bool seenTo = false;
if (p.to == NODENUM_BROADCAST)
seenTo = true;
for (int i = 0; i < numMeshNodes; i++) { for (int i = 0; i < numMeshNodes; i++) {
lite = &meshNodes->at(i); lite = &meshNodes->at(i);
if (lite->num == p.from) { if (!seenFrom && lite->num == p.from) {
if (lite->is_favorite) if (lite->is_favorite) {
FUNCTION_END;
return true; return true;
}
seenFrom = true; seenFrom = true;
} }
if (lite->num == p.to) { if (!seenTo && lite->num == p.to) {
if (lite->is_favorite) if (lite->is_favorite) {
FUNCTION_END;
return true; return true;
}
seenTo = true; seenTo = true;
} }
if (seenFrom && seenTo) if (seenFrom && seenTo) {
FUNCTION_END;
return false; // we've seen both, and neither is a favorite, so we can stop searching early return false; // we've seen both, and neither is a favorite, so we can stop searching early
}
// Note: if we knew that sortMeshDB was always called after any change to is_favorite, we could exit early after searching // Note: if we knew that sortMeshDB was always called after any change to is_favorite, we could exit early after searching
// all favorited nodes first. // all favorited nodes first.
} }
FUNCTION_END;
return false; return false;
} }
void NodeDB::pause_sort(bool paused) void NodeDB::pause_sort(bool paused)
{ {
// Including the mutex macro for completeness, but it's possible it isn't appropriate here
FUNCTION_START("pause_sort");
sortingIsPaused = paused; sortingIsPaused = paused;
FUNCTION_END;
} }
void NodeDB::sortMeshDB() void NodeDB::sortMeshDB()
@@ -1933,10 +1884,13 @@ void NodeDB::sortMeshDB()
uint8_t NodeDB::getMeshNodeChannel(NodeNum n) uint8_t NodeDB::getMeshNodeChannel(NodeNum n)
{ {
const meshtastic_NodeInfoLite *info = getMeshNode(n); FUNCTION_START("getMeshNodeChannel");
const meshtastic_NodeInfoLite *info = _getMeshNode(n);
if (!info) { if (!info) {
FUNCTION_END;
return 0; // defaults to PRIMARY return 0; // defaults to PRIMARY
} }
FUNCTION_END;
return info->channel; return info->channel;
} }
@@ -1949,7 +1903,7 @@ std::string NodeDB::getNodeId() const
/// Find a node in our DB, return null for missing /// Find a node in our DB, return null for missing
/// NOTE: This function might be called from an ISR /// NOTE: This function might be called from an ISR
meshtastic_NodeInfoLite *NodeDB::getMeshNode(NodeNum n) meshtastic_NodeInfoLite *NodeDB::_getMeshNode(NodeNum n)
{ {
for (int i = 0; i < numMeshNodes; i++) for (int i = 0; i < numMeshNodes; i++)
if (meshNodes->at(i).num == n) if (meshNodes->at(i).num == n)
@@ -1959,7 +1913,7 @@ meshtastic_NodeInfoLite *NodeDB::getMeshNode(NodeNum n)
} }
// returns true if the maximum number of nodes is reached or we are running low on memory // returns true if the maximum number of nodes is reached or we are running low on memory
bool NodeDB::isFull() bool NodeDB::_isFull()
{ {
return (numMeshNodes >= MAX_NUM_NODES) || (memGet.getFreeHeap() < MINIMUM_SAFE_FREE_HEAP); return (numMeshNodes >= MAX_NUM_NODES) || (memGet.getFreeHeap() < MINIMUM_SAFE_FREE_HEAP);
} }
@@ -1967,7 +1921,7 @@ bool NodeDB::isFull()
/// Find a node in our DB, create an empty NodeInfo if missing /// Find a node in our DB, create an empty NodeInfo if missing
meshtastic_NodeInfoLite *NodeDB::getOrCreateMeshNode(NodeNum n) meshtastic_NodeInfoLite *NodeDB::getOrCreateMeshNode(NodeNum n)
{ {
meshtastic_NodeInfoLite *lite = getMeshNode(n); meshtastic_NodeInfoLite *lite = _getMeshNode(n);
if (!lite) { if (!lite) {
if (isFull()) { if (isFull()) {
@@ -2022,18 +1976,25 @@ meshtastic_NodeInfoLite *NodeDB::getOrCreateMeshNode(NodeNum n)
/// valid lat/lon /// valid lat/lon
bool NodeDB::hasValidPosition(const meshtastic_NodeInfoLite *n) bool NodeDB::hasValidPosition(const meshtastic_NodeInfoLite *n)
{ {
return n->has_position && (n->position.latitude_i != 0 || n->position.longitude_i != 0); FUNCTION_START("hasValidPosition");
auto retVal = n->has_position && (n->position.latitude_i != 0 || n->position.longitude_i != 0);
FUNCTION_END;
return retVal;
} }
/// If we have a node / user and they report is_licensed = true /// If we have a node / user and they report is_licensed = true
/// we consider them licensed /// we consider them licensed
UserLicenseStatus NodeDB::getLicenseStatus(uint32_t nodeNum) UserLicenseStatus NodeDB::getLicenseStatus(uint32_t nodeNum)
{ {
meshtastic_NodeInfoLite *info = getMeshNode(nodeNum); FUNCTION_START("getLicenseStatus");
meshtastic_NodeInfoLite *info = _getMeshNode(nodeNum);
if (!info || !info->has_user) { if (!info || !info->has_user) {
FUNCTION_END;
return UserLicenseStatus::NotKnown; return UserLicenseStatus::NotKnown;
} }
return info->user.is_licensed ? UserLicenseStatus::Licensed : UserLicenseStatus::NotLicensed; auto retVal = info->user.is_licensed ? UserLicenseStatus::Licensed : UserLicenseStatus::NotLicensed;
FUNCTION_END;
return retVal;
} }
#if !defined(MESHTASTIC_EXCLUDE_PKI) #if !defined(MESHTASTIC_EXCLUDE_PKI)
@@ -2055,6 +2016,7 @@ bool NodeDB::checkLowEntropyPublicKey(const meshtastic_Config_SecurityConfig_pub
bool NodeDB::backupPreferences(meshtastic_AdminMessage_BackupLocation location) bool NodeDB::backupPreferences(meshtastic_AdminMessage_BackupLocation location)
{ {
FUNCTION_START("backupPreferences");
bool success = false; bool success = false;
lastBackupAttempt = millis(); lastBackupAttempt = millis();
#ifdef FSCom #ifdef FSCom
@@ -2088,11 +2050,13 @@ bool NodeDB::backupPreferences(meshtastic_AdminMessage_BackupLocation location)
// TODO: After more mainline SD card support // TODO: After more mainline SD card support
} }
#endif #endif
FUNCTION_END;
return success; return success;
} }
bool NodeDB::restorePreferences(meshtastic_AdminMessage_BackupLocation location, int restoreWhat) bool NodeDB::restorePreferences(meshtastic_AdminMessage_BackupLocation location, int restoreWhat)
{ {
FUNCTION_START("backupPreferences");
bool success = false; bool success = false;
#ifdef FSCom #ifdef FSCom
if (location == meshtastic_AdminMessage_BackupLocation_FLASH) { if (location == meshtastic_AdminMessage_BackupLocation_FLASH) {
@@ -2100,6 +2064,7 @@ bool NodeDB::restorePreferences(meshtastic_AdminMessage_BackupLocation location,
if (!FSCom.exists(backupFileName)) { if (!FSCom.exists(backupFileName)) {
spiLock->unlock(); spiLock->unlock();
LOG_WARN("Could not restore. No backup file found"); LOG_WARN("Could not restore. No backup file found");
FUNCTION_END;
return false; return false;
} else { } else {
spiLock->unlock(); spiLock->unlock();
@@ -2125,7 +2090,7 @@ bool NodeDB::restorePreferences(meshtastic_AdminMessage_BackupLocation location,
LOG_DEBUG("Restored channels"); LOG_DEBUG("Restored channels");
} }
success = saveToDisk(restoreWhat); success = _saveToDisk(restoreWhat);
if (success) { if (success) {
LOG_INFO("Restored preferences from backup"); LOG_INFO("Restored preferences from backup");
} else { } else {
@@ -2137,6 +2102,7 @@ bool NodeDB::restorePreferences(meshtastic_AdminMessage_BackupLocation location,
} else if (location == meshtastic_AdminMessage_BackupLocation_SD) { } else if (location == meshtastic_AdminMessage_BackupLocation_SD) {
// TODO: After more mainline SD card support // TODO: After more mainline SD card support
} }
FUNCTION_END;
return success; return success;
#endif #endif
} }
+137 -68
View File
@@ -18,6 +18,13 @@
#include "PortduinoGlue.h" #include "PortduinoGlue.h"
#endif #endif
#define FUNCTION_START(FUNCTION_NAME) \
if (fakeMutex) \
LOG_ERROR("Concurrency violation in " FUNCTION_NAME); \
fakeMutex = true;
#define FUNCTION_END fakeMutex = false;
#if !defined(MESHTASTIC_EXCLUDE_PKI) #if !defined(MESHTASTIC_EXCLUDE_PKI)
// E3B0C442 is the blank hash // E3B0C442 is the blank hash
static const uint8_t LOW_ENTROPY_HASHES[][32] = { static const uint8_t LOW_ENTROPY_HASHES[][32] = {
@@ -110,23 +117,6 @@ uint32_t sinceLastSeen(const meshtastic_NodeInfoLite *n);
/// Given a packet, return how many seconds in the past (vs now) it was received /// Given a packet, return how many seconds in the past (vs now) it was received
uint32_t sinceReceived(const meshtastic_MeshPacket *p); uint32_t sinceReceived(const meshtastic_MeshPacket *p);
/// Given a packet, return the number of hops used to reach this node.
/// Returns defaultIfUnknown if the number of hops couldn't be determined.
int8_t getHopsAway(const meshtastic_MeshPacket &p, int8_t defaultIfUnknown = -1);
enum LoadFileResult {
// Successfully opened the file
LOAD_SUCCESS = 1,
// File does not exist
NOT_FOUND = 2,
// Device does not have a filesystem
NO_FILESYSTEM = 3,
// File exists, but could not decode protobufs
DECODE_FAILED = 4,
// File exists, but open failed for some reason
OTHER_FAILURE = 5
};
enum UserLicenseStatus { NotKnown, NotLicensed, Licensed }; enum UserLicenseStatus { NotKnown, NotLicensed, Licensed };
class NodeDB class NodeDB
@@ -139,7 +129,6 @@ class NodeDB
// Note: these two references just point into our static array we serialize to/from disk // Note: these two references just point into our static array we serialize to/from disk
public: public:
std::vector<meshtastic_NodeInfoLite> *meshNodes;
bool updateGUI = false; // we think the gui should definitely be redrawn, screen will clear this once handled bool updateGUI = false; // we think the gui should definitely be redrawn, screen will clear this once handled
meshtastic_NodeInfoLite *updateGUIforNode = NULL; // if currently showing this node, we think you should update the GUI meshtastic_NodeInfoLite *updateGUIforNode = NULL; // if currently showing this node, we think you should update the GUI
Observable<const meshtastic::NodeStatus *> newStatus; Observable<const meshtastic::NodeStatus *> newStatus;
@@ -155,17 +144,26 @@ class NodeDB
/// write to flash /// write to flash
/// @return true if the save was successful /// @return true if the save was successful
bool saveToDisk(int saveWhat = SEGMENT_CONFIG | SEGMENT_MODULECONFIG | SEGMENT_DEVICESTATE | SEGMENT_CHANNELS | bool saveToDisk(int saveWhat = SEGMENT_CONFIG | SEGMENT_MODULECONFIG | SEGMENT_DEVICESTATE | SEGMENT_CHANNELS |
SEGMENT_NODEDATABASE); SEGMENT_NODEDATABASE)
{
FUNCTION_START("saveToDisk");
auto retVal = _saveToDisk(saveWhat);
FUNCTION_END;
return retVal;
}
/** Reinit radio config if needed, because either: /** Reinit radio config if needed, because either:
* a) sometimes a buggy android app might send us bogus settings or * a) sometimes a buggy android app might send us bogus settings or
* b) the client set factory_reset * b) the client set factory_reset
* *
* @param factory_reset if true, reset all settings to factory defaults
* @param is_fresh_install set to true after a fresh install, to trigger NodeInfo/Position requests * @param is_fresh_install set to true after a fresh install, to trigger NodeInfo/Position requests
* @return true if the config was completely reset, in that case, we should send it back to the client
*/ */
void resetRadioConfig(bool is_fresh_install = false); void resetRadioConfig(bool is_fresh_install = false)
{
FUNCTION_START("resetRadioConfig");
_resetRadioConfig(is_fresh_install);
FUNCTION_END;
}
/// given a subpacket sniffed from the network, update our DB state /// given a subpacket sniffed from the network, update our DB state
/// we updateGUI and updateGUIforNode if we think our this change is big enough for a redraw /// we updateGUI and updateGUIforNode if we think our this change is big enough for a redraw
@@ -212,7 +210,13 @@ class NodeDB
std::string getNodeId() const; std::string getNodeId() const;
// @return last byte of a NodeNum, 0xFF if it ended at 0x00 // @return last byte of a NodeNum, 0xFF if it ended at 0x00
uint8_t getLastByteOfNodeNum(NodeNum num) { return (uint8_t)((num & 0xFF) ? (num & 0xFF) : 0xFF); } uint8_t getLastByteOfNodeNum(NodeNum num)
{
FUNCTION_START("getLastByteOfNodeNum");
auto retVal = (uint8_t)((num & 0xFF) ? (num & 0xFF) : 0xFF);
FUNCTION_END;
return retVal;
}
/// if returns false, that means our node should send a DenyNodeNum response. If true, we think the number is okay for use /// if returns false, that means our node should send a DenyNodeNum response. If true, we think the number is okay for use
// bool handleWantNodeNum(NodeNum n); // bool handleWantNodeNum(NodeNum n);
@@ -231,85 +235,105 @@ class NodeDB
/* Return the number of nodes we've heard from recently (within the last 2 hrs?) /* Return the number of nodes we've heard from recently (within the last 2 hrs?)
* @param localOnly if true, ignore nodes heard via MQTT * @param localOnly if true, ignore nodes heard via MQTT
*/ */
size_t getNumOnlineMeshNodes(bool localOnly = false); size_t getNumOnlineMeshNodes(bool localOnly = false)
{
FUNCTION_START("getNumOnlineMeshNodes");
auto retVal = _getNumOnlineMeshNodes(localOnly);
FUNCTION_END;
return retVal;
}
void initConfigIntervals(), initModuleConfigIntervals(), resetNodes(bool keepFavorites = false), void resetNodes(bool keepFavorites = false), removeNodeByNum(NodeNum nodeNum);
removeNodeByNum(NodeNum nodeNum);
bool factoryReset(bool eraseBleBonds = false); bool factoryReset(bool eraseBleBonds = false);
LoadFileResult loadProto(const char *filename, size_t protoSize, size_t objSize, const pb_msgdesc_t *fields, void installRoleDefaults(meshtastic_Config_DeviceConfig_Role role)
void *dest_struct); {
bool saveProto(const char *filename, size_t protoSize, const pb_msgdesc_t *fields, const void *dest_struct, FUNCTION_START("installRoleDefaults");
bool fullAtomic = true); _installRoleDefaults(role);
FUNCTION_END;
void installRoleDefaults(meshtastic_Config_DeviceConfig_Role role); }
const meshtastic_NodeInfoLite *readNextMeshNode(uint32_t &readIndex); const meshtastic_NodeInfoLite *readNextMeshNode(uint32_t &readIndex);
meshtastic_NodeInfoLite *getMeshNodeByIndex(size_t x) meshtastic_NodeInfoLite *getMeshNodeByIndex(size_t x)
{ {
assert(x < numMeshNodes); FUNCTION_START("getMeshNodeByIndex");
return &meshNodes->at(x); meshtastic_NodeInfoLite *retValue = nullptr;
if (x < numMeshNodes)
retValue = &meshNodes->at(x);
FUNCTION_END;
return retValue;
} }
virtual meshtastic_NodeInfoLite *getMeshNode(NodeNum n); virtual meshtastic_NodeInfoLite *getMeshNode(NodeNum n)
size_t getNumMeshNodes() { return numMeshNodes; } {
FUNCTION_START("getMeshNode");
auto retVal = _getMeshNode(n);
FUNCTION_END;
return retVal;
}
size_t getNumMeshNodes()
{
FUNCTION_START("getNumMeshNodes");
auto retVal = numMeshNodes;
FUNCTION_END;
return retVal;
}
UserLicenseStatus getLicenseStatus(uint32_t nodeNum); UserLicenseStatus getLicenseStatus(uint32_t nodeNum);
size_t getMaxNodesAllocatedSize() // returns true if the maximum number of nodes is reached or we are running low on memory
bool isFull()
{ {
meshtastic_NodeDatabase emptyNodeDatabase; FUNCTION_START("isFull");
emptyNodeDatabase.version = DEVICESTATE_CUR_VER; auto retVal = _isFull();
size_t nodeDatabaseSize; FUNCTION_END;
pb_get_encoded_size(&nodeDatabaseSize, meshtastic_NodeDatabase_fields, &emptyNodeDatabase); return retVal;
return nodeDatabaseSize + (MAX_NUM_NODES * meshtastic_NodeInfoLite_size);
} }
// returns true if the maximum number of nodes is reached or we are running low on memory void clearLocalPosition()
bool isFull(); {
FUNCTION_START("clearLocalPosition");
void clearLocalPosition(); _clearLocalPosition();
FUNCTION_END;
}
void setLocalPosition(meshtastic_Position position, bool timeOnly = false) void setLocalPosition(meshtastic_Position position, bool timeOnly = false)
{ {
if (timeOnly) { FUNCTION_START("setLocalPosition");
LOG_DEBUG("Set local position time only: time=%u timestamp=%u", position.time, position.timestamp); _setLocalPosition(position, timeOnly);
localPosition.time = position.time; FUNCTION_END;
localPosition.timestamp = position.timestamp > 0 ? position.timestamp : position.time;
return;
}
LOG_DEBUG("Set local position: lat=%i lon=%i time=%u timestamp=%u", position.latitude_i, position.longitude_i,
position.time, position.timestamp);
localPosition = position;
if (position.latitude_i != 0 || position.longitude_i != 0) {
localPositionUpdatedSinceBoot = true;
}
} }
bool hasValidPosition(const meshtastic_NodeInfoLite *n); bool hasValidPosition(const meshtastic_NodeInfoLite *n);
bool hasLocalPositionSinceBoot() const { return localPositionUpdatedSinceBoot; }
#if !defined(MESHTASTIC_EXCLUDE_PKI)
bool checkLowEntropyPublicKey(const meshtastic_Config_SecurityConfig_public_key_t &keyToTest);
#endif
bool backupPreferences(meshtastic_AdminMessage_BackupLocation location); bool backupPreferences(meshtastic_AdminMessage_BackupLocation location);
bool restorePreferences(meshtastic_AdminMessage_BackupLocation location, bool restorePreferences(meshtastic_AdminMessage_BackupLocation location,
int restoreWhat = SEGMENT_CONFIG | SEGMENT_MODULECONFIG | SEGMENT_DEVICESTATE | SEGMENT_CHANNELS); int restoreWhat = SEGMENT_CONFIG | SEGMENT_MODULECONFIG | SEGMENT_DEVICESTATE | SEGMENT_CHANNELS);
/// Notify observers of changes to the DB
void notifyObservers(bool forceUpdate = false) void notifyObservers(bool forceUpdate = false)
{ {
// Notify observers of the current node state FUNCTION_START("notifyObservers");
const meshtastic::NodeStatus status = meshtastic::NodeStatus(getNumOnlineMeshNodes(), getNumMeshNodes(), forceUpdate); _notifyObservers(forceUpdate);
newStatus.notifyObservers(&status); FUNCTION_END;
} }
private: private:
bool fakeMutex = false;
/// Notify observers of changes to the DB
void _notifyObservers(bool forceUpdate = false)
{
// Notify observers of the current node state
const meshtastic::NodeStatus status = meshtastic::NodeStatus(_getNumOnlineMeshNodes(), numMeshNodes, forceUpdate);
newStatus.notifyObservers(&status);
}
std::vector<meshtastic_NodeInfoLite> *meshNodes;
bool duplicateWarned = false; bool duplicateWarned = false;
bool localPositionUpdatedSinceBoot = false;
uint32_t lastNodeDbSave = 0; // when we last saved our db to flash uint32_t lastNodeDbSave = 0; // when we last saved our db to flash
uint32_t lastBackupAttempt = 0; // when we last tried a backup automatically or manually uint32_t lastBackupAttempt = 0; // when we last tried a backup automatically or manually
uint32_t lastSort = 0; // When last sorted the nodeDB uint32_t lastSort = 0; // When last sorted the nodeDB
@@ -342,6 +366,51 @@ class NodeDB
bool saveDeviceStateToDisk(); bool saveDeviceStateToDisk();
bool saveNodeDatabaseToDisk(); bool saveNodeDatabaseToDisk();
void sortMeshDB(); void sortMeshDB();
void initConfigIntervals(), initModuleConfigIntervals();
size_t getMaxNodesAllocatedSize()
{
meshtastic_NodeDatabase emptyNodeDatabase;
emptyNodeDatabase.version = DEVICESTATE_CUR_VER;
size_t nodeDatabaseSize;
pb_get_encoded_size(&nodeDatabaseSize, meshtastic_NodeDatabase_fields, &emptyNodeDatabase);
return nodeDatabaseSize + (MAX_NUM_NODES * meshtastic_NodeInfoLite_size);
}
bool checkLowEntropyPublicKey(const meshtastic_Config_SecurityConfig_public_key_t &keyToTest);
// wrapped private functions:
bool _saveToDisk(int saveWhat = SEGMENT_CONFIG | SEGMENT_MODULECONFIG | SEGMENT_DEVICESTATE | SEGMENT_CHANNELS |
SEGMENT_NODEDATABASE);
void _resetRadioConfig(bool is_fresh_install = false);
/* Return the number of nodes we've heard from recently (within the last 2 hrs?)
* @param localOnly if true, ignore nodes heard via MQTT
*/
size_t _getNumOnlineMeshNodes(bool localOnly = false);
void _installRoleDefaults(meshtastic_Config_DeviceConfig_Role role);
meshtastic_NodeInfoLite *_getMeshNode(NodeNum n);
bool _isFull();
void _clearLocalPosition();
void _setLocalPosition(meshtastic_Position position, bool timeOnly = false)
{
if (timeOnly) {
LOG_DEBUG("Set local position time only: time=%u timestamp=%u", position.time, position.timestamp);
localPosition.time = position.time;
localPosition.timestamp = position.timestamp > 0 ? position.timestamp : position.time;
return;
}
LOG_DEBUG("Set local position: lat=%i lon=%i time=%u timestamp=%u", position.latitude_i, position.longitude_i,
position.time, position.timestamp);
localPosition = position;
}
}; };
extern NodeDB *nodeDB; extern NodeDB *nodeDB;
+8 -21
View File
@@ -296,6 +296,11 @@ bool RadioInterface::shouldRebroadcastEarlyLikeRouter(meshtastic_MeshPacket *p)
return true; return true;
} }
// If we are a CLIENT_BASE and the packet is from or to a favorited node, we should rebroadcast early
if (config.device.role == meshtastic_Config_DeviceConfig_Role_CLIENT_BASE) {
return nodeDB->isFromOrToFavoritedNode(*p);
}
return false; return false;
} }
@@ -498,11 +503,6 @@ void RadioInterface::applyModemConfig()
cr = 5; cr = 5;
sf = 10; sf = 10;
break; break;
case meshtastic_Config_LoRaConfig_ModemPreset_LONG_TURBO:
bw = (myRegion->wideLora) ? 1625.0 : 500;
cr = 8;
sf = 11;
break;
default: // Config_LoRaConfig_ModemPreset_LONG_FAST is default. Gracefully use this is preset is something illegal. default: // Config_LoRaConfig_ModemPreset_LONG_FAST is default. Gracefully use this is preset is something illegal.
bw = (myRegion->wideLora) ? 812.5 : 250; bw = (myRegion->wideLora) ? 812.5 : 250;
cr = 5; cr = 5;
@@ -539,26 +539,13 @@ void RadioInterface::applyModemConfig()
} }
if ((myRegion->freqEnd - myRegion->freqStart) < bw / 1000) { if ((myRegion->freqEnd - myRegion->freqStart) < bw / 1000) {
const float regionSpanKHz = (myRegion->freqEnd - myRegion->freqStart) * 1000.0f; static const char *err_string = "Regional frequency range is smaller than bandwidth. Fall back to default preset";
const float requestedBwKHz = bw; LOG_ERROR(err_string);
const bool isWideRequest = requestedBwKHz >= 499.5f; // treat as 500 kHz preset
const char *presetName =
DisplayFormatters::getModemPresetDisplayName(loraConfig.modem_preset, false, loraConfig.use_preset);
char err_string[160];
if (isWideRequest) {
snprintf(err_string, sizeof(err_string), "%s region too narrow for 500kHz preset (%s). Falling back to LongFast.",
myRegion->name, presetName);
} else {
snprintf(err_string, sizeof(err_string), "%s region span %.0fkHz < requested %.0fkHz. Falling back to LongFast.",
myRegion->name, regionSpanKHz, requestedBwKHz);
}
LOG_ERROR("%s", err_string);
RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_INVALID_RADIO_SETTING); RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_INVALID_RADIO_SETTING);
meshtastic_ClientNotification *cn = clientNotificationPool.allocZeroed(); meshtastic_ClientNotification *cn = clientNotificationPool.allocZeroed();
cn->level = meshtastic_LogRecord_Level_ERROR; cn->level = meshtastic_LogRecord_Level_ERROR;
snprintf(cn->message, sizeof(cn->message), "%s", err_string); sprintf(cn->message, err_string);
service->sendClientNotification(cn); service->sendClientNotification(cn);
// Set to default modem preset // Set to default modem preset
+6 -9
View File
@@ -1,7 +1,6 @@
#include "ReliableRouter.h" #include "ReliableRouter.h"
#include "Default.h" #include "Default.h"
#include "MeshTypes.h" #include "MeshTypes.h"
#include "NodeDB.h"
#include "configuration.h" #include "configuration.h"
#include "memGet.h" #include "memGet.h"
#include "mesh-pb-constants.h" #include "mesh-pb-constants.h"
@@ -109,12 +108,12 @@ void ReliableRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas
// If this packet should always be ACKed reliably with want_ack back to the original sender, make sure we // If this packet should always be ACKed reliably with want_ack back to the original sender, make sure we
// do that unconditionally. // do that unconditionally.
sendAckNak(meshtastic_Routing_Error_NONE, getFrom(p), p->id, p->channel, sendAckNak(meshtastic_Routing_Error_NONE, getFrom(p), p->id, p->channel,
routingModule->getHopLimitForResponse(*p), true); routingModule->getHopLimitForResponse(p->hop_start, p->hop_limit), true);
} else if (!p->decoded.request_id && !p->decoded.reply_id) { } else if (!p->decoded.request_id && !p->decoded.reply_id) {
// If it's not an ACK or a reply, send an ACK. // If it's not an ACK or a reply, send an ACK.
sendAckNak(meshtastic_Routing_Error_NONE, getFrom(p), p->id, p->channel, sendAckNak(meshtastic_Routing_Error_NONE, getFrom(p), p->id, p->channel,
routingModule->getHopLimitForResponse(*p)); routingModule->getHopLimitForResponse(p->hop_start, p->hop_limit));
} else if ((getHopsAway(*p) == 0) || p->next_hop != NO_NEXT_HOP_PREFERENCE) { } else if ((p->hop_start > 0 && p->hop_start == p->hop_limit) || p->next_hop != NO_NEXT_HOP_PREFERENCE) {
// If we received the packet directly from the original sender, send a 0-hop ACK since the original sender // If we received the packet directly from the original sender, send a 0-hop ACK since the original sender
// won't overhear any implicit ACKs. If we received the packet via NextHopRouter, also send a 0-hop ACK to // won't overhear any implicit ACKs. If we received the packet via NextHopRouter, also send a 0-hop ACK to
// stop the immediate relayer's retransmissions. // stop the immediate relayer's retransmissions.
@@ -124,11 +123,11 @@ void ReliableRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas
(nodeDB->getMeshNode(p->from) == nullptr || nodeDB->getMeshNode(p->from)->user.public_key.size == 0)) { (nodeDB->getMeshNode(p->from) == nullptr || nodeDB->getMeshNode(p->from)->user.public_key.size == 0)) {
LOG_INFO("PKI packet from unknown node, send PKI_UNKNOWN_PUBKEY"); LOG_INFO("PKI packet from unknown node, send PKI_UNKNOWN_PUBKEY");
sendAckNak(meshtastic_Routing_Error_PKI_UNKNOWN_PUBKEY, getFrom(p), p->id, channels.getPrimaryIndex(), sendAckNak(meshtastic_Routing_Error_PKI_UNKNOWN_PUBKEY, getFrom(p), p->id, channels.getPrimaryIndex(),
routingModule->getHopLimitForResponse(*p)); routingModule->getHopLimitForResponse(p->hop_start, p->hop_limit));
} else { } else {
// Send a 'NO_CHANNEL' error on the primary channel if want_ack packet destined for us cannot be decoded // Send a 'NO_CHANNEL' error on the primary channel if want_ack packet destined for us cannot be decoded
sendAckNak(meshtastic_Routing_Error_NO_CHANNEL, getFrom(p), p->id, channels.getPrimaryIndex(), sendAckNak(meshtastic_Routing_Error_NO_CHANNEL, getFrom(p), p->id, channels.getPrimaryIndex(),
routingModule->getHopLimitForResponse(*p)); routingModule->getHopLimitForResponse(p->hop_start, p->hop_limit));
} }
} else if (p->next_hop == nodeDB->getLastByteOfNodeNum(getNodeNum()) && p->hop_limit > 0) { } else if (p->next_hop == nodeDB->getLastByteOfNodeNum(getNodeNum()) && p->hop_limit > 0) {
// No wantAck, but we need to ACK with hop limit of 0 if we were the next hop to stop their retransmissions // No wantAck, but we need to ACK with hop limit of 0 if we were the next hop to stop their retransmissions
@@ -151,9 +150,7 @@ void ReliableRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas
PacketId nakId = (c && c->error_reason != meshtastic_Routing_Error_NONE) ? p->decoded.request_id : 0; PacketId nakId = (c && c->error_reason != meshtastic_Routing_Error_NONE) ? p->decoded.request_id : 0;
// We intentionally don't check wasSeenRecently, because it is harmless to delete non existent retransmission records // We intentionally don't check wasSeenRecently, because it is harmless to delete non existent retransmission records
if ((ackId || nakId) && if (ackId || nakId) {
// Implicit ACKs from MQTT should not stop retransmissions
!(isFromUs(p) && p->transport_mechanism == meshtastic_MeshPacket_TransportMechanism_TRANSPORT_MQTT)) {
LOG_DEBUG("Received a %s for 0x%x, stopping retransmissions", ackId ? "ACK" : "NAK", ackId); LOG_DEBUG("Received a %s for 0x%x, stopping retransmissions", ackId ? "ACK" : "NAK", ackId);
if (ackId) { if (ackId) {
stopRetransmission(p->to, ackId); stopRetransmission(p->to, ackId);
+11 -18
View File
@@ -81,7 +81,8 @@ Router::Router() : concurrency::OSThread("Router"), fromRadioQueue(MAX_RX_FROMRA
bool Router::shouldDecrementHopLimit(const meshtastic_MeshPacket *p) bool Router::shouldDecrementHopLimit(const meshtastic_MeshPacket *p)
{ {
// First hop MUST always decrement to prevent retry issues // First hop MUST always decrement to prevent retry issues
if (getHopsAway(*p) == 0) { bool isFirstHop = (p->hop_start != 0 && p->hop_start == p->hop_limit);
if (isFirstHop) {
return true; // Always decrement on first hop return true; // Always decrement on first hop
} }
@@ -525,10 +526,6 @@ DecodeState perhapsDecode(meshtastic_MeshPacket *p)
#elif ARCH_PORTDUINO #elif ARCH_PORTDUINO
if (portduino_config.traceFilename != "" || portduino_config.logoutputlevel == level_trace) { if (portduino_config.traceFilename != "" || portduino_config.logoutputlevel == level_trace) {
LOG_TRACE("%s", MeshPacketSerializer::JsonSerialize(p, false).c_str()); LOG_TRACE("%s", MeshPacketSerializer::JsonSerialize(p, false).c_str());
} else if (portduino_config.JSONFilename != "") {
if (portduino_config.JSONFilter == (_meshtastic_PortNum)0 || portduino_config.JSONFilter == p->decoded.portnum) {
JSONFile << MeshPacketSerializer::JsonSerialize(p, false) << std::endl;
}
} }
#endif #endif
return DecodeState::DECODE_SUCCESS; return DecodeState::DECODE_SUCCESS;
@@ -744,19 +741,15 @@ void Router::handleReceived(meshtastic_MeshPacket *p, RxSource src)
MeshModule::callModules(*p, src); MeshModule::callModules(*p, src);
#if !MESHTASTIC_EXCLUDE_MQTT #if !MESHTASTIC_EXCLUDE_MQTT
if (p_encrypted == nullptr) { // Mark as pki_encrypted if it is not yet decoded and MQTT encryption is also enabled, hash matches and it's a DM not to
LOG_WARN("p_encrypted is null, skipping MQTT publish"); // us (because we would be able to decrypt it)
} else { if (decodedState == DecodeState::DECODE_FAILURE && moduleConfig.mqtt.encryption_enabled && p->channel == 0x00 &&
// Mark as pki_encrypted if it is not yet decoded and MQTT encryption is also enabled, hash matches and it's a DM not !isBroadcast(p->to) && !isToUs(p))
// to us (because we would be able to decrypt it) p_encrypted->pki_encrypted = true;
if (decodedState == DecodeState::DECODE_FAILURE && moduleConfig.mqtt.encryption_enabled && p->channel == 0x00 && // After potentially altering it, publish received message to MQTT if we're not the original transmitter of the packet
!isBroadcast(p->to) && !isToUs(p)) if ((decodedState == DecodeState::DECODE_SUCCESS || p_encrypted->pki_encrypted) && moduleConfig.mqtt.enabled &&
p_encrypted->pki_encrypted = true; !isFromUs(p) && mqtt)
// After potentially altering it, publish received message to MQTT if we're not the original transmitter of the packet mqtt->onSend(*p_encrypted, *p, p->channel);
if ((decodedState == DecodeState::DECODE_SUCCESS || p_encrypted->pki_encrypted) && moduleConfig.mqtt.enabled &&
!isFromUs(p) && mqtt)
mqtt->onSend(*p_encrypted, *p, p->channel);
}
#endif #endif
} }
+4 -8
View File
@@ -293,8 +293,7 @@ typedef enum _meshtastic_Config_LoRaConfig_RegionCode {
typedef enum _meshtastic_Config_LoRaConfig_ModemPreset { typedef enum _meshtastic_Config_LoRaConfig_ModemPreset {
/* Long Range - Fast */ /* Long Range - Fast */
meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST = 0, meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST = 0,
/* Long Range - Slow /* Long Range - Slow */
Deprecated in 2.7: Unpopular slow preset. */
meshtastic_Config_LoRaConfig_ModemPreset_LONG_SLOW = 1, meshtastic_Config_LoRaConfig_ModemPreset_LONG_SLOW = 1,
/* Very Long Range - Slow /* Very Long Range - Slow
Deprecated in 2.5: Works only with txco and is unusably slow */ Deprecated in 2.5: Works only with txco and is unusably slow */
@@ -312,10 +311,7 @@ typedef enum _meshtastic_Config_LoRaConfig_ModemPreset {
/* Short Range - Turbo /* Short Range - Turbo
This is the fastest preset and the only one with 500kHz bandwidth. This is the fastest preset and the only one with 500kHz bandwidth.
It is not legal to use in all regions due to this wider bandwidth. */ It is not legal to use in all regions due to this wider bandwidth. */
meshtastic_Config_LoRaConfig_ModemPreset_SHORT_TURBO = 8, meshtastic_Config_LoRaConfig_ModemPreset_SHORT_TURBO = 8
/* Long Range - Turbo
This preset performs similarly to LongFast, but with 500Khz bandwidth. */
meshtastic_Config_LoRaConfig_ModemPreset_LONG_TURBO = 9
} meshtastic_Config_LoRaConfig_ModemPreset; } meshtastic_Config_LoRaConfig_ModemPreset;
typedef enum _meshtastic_Config_BluetoothConfig_PairingMode { typedef enum _meshtastic_Config_BluetoothConfig_PairingMode {
@@ -693,8 +689,8 @@ extern "C" {
#define _meshtastic_Config_LoRaConfig_RegionCode_ARRAYSIZE ((meshtastic_Config_LoRaConfig_RegionCode)(meshtastic_Config_LoRaConfig_RegionCode_BR_902+1)) #define _meshtastic_Config_LoRaConfig_RegionCode_ARRAYSIZE ((meshtastic_Config_LoRaConfig_RegionCode)(meshtastic_Config_LoRaConfig_RegionCode_BR_902+1))
#define _meshtastic_Config_LoRaConfig_ModemPreset_MIN meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST #define _meshtastic_Config_LoRaConfig_ModemPreset_MIN meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST
#define _meshtastic_Config_LoRaConfig_ModemPreset_MAX meshtastic_Config_LoRaConfig_ModemPreset_LONG_TURBO #define _meshtastic_Config_LoRaConfig_ModemPreset_MAX meshtastic_Config_LoRaConfig_ModemPreset_SHORT_TURBO
#define _meshtastic_Config_LoRaConfig_ModemPreset_ARRAYSIZE ((meshtastic_Config_LoRaConfig_ModemPreset)(meshtastic_Config_LoRaConfig_ModemPreset_LONG_TURBO+1)) #define _meshtastic_Config_LoRaConfig_ModemPreset_ARRAYSIZE ((meshtastic_Config_LoRaConfig_ModemPreset)(meshtastic_Config_LoRaConfig_ModemPreset_SHORT_TURBO+1))
#define _meshtastic_Config_BluetoothConfig_PairingMode_MIN meshtastic_Config_BluetoothConfig_PairingMode_RANDOM_PIN #define _meshtastic_Config_BluetoothConfig_PairingMode_MIN meshtastic_Config_BluetoothConfig_PairingMode_RANDOM_PIN
#define _meshtastic_Config_BluetoothConfig_PairingMode_MAX meshtastic_Config_BluetoothConfig_PairingMode_NO_PIN #define _meshtastic_Config_BluetoothConfig_PairingMode_MAX meshtastic_Config_BluetoothConfig_PairingMode_NO_PIN
+1 -4
View File
@@ -417,9 +417,6 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
} }
case meshtastic_AdminMessage_enter_dfu_mode_request_tag: { case meshtastic_AdminMessage_enter_dfu_mode_request_tag: {
LOG_INFO("Client requesting to enter DFU mode"); LOG_INFO("Client requesting to enter DFU mode");
#if HAS_SCREEN
IF_SCREEN(screen->showSimpleBanner("Device is rebooting\ninto DFU mode.", 0));
#endif
#if defined(ARCH_NRF52) || defined(ARCH_RP2040) #if defined(ARCH_NRF52) || defined(ARCH_RP2040)
enterDfuMode(); enterDfuMode();
#endif #endif
@@ -1325,7 +1322,7 @@ void AdminModule::saveChanges(int saveWhat, bool shouldReboot)
void AdminModule::handleStoreDeviceUIConfig(const meshtastic_DeviceUIConfig &uicfg) void AdminModule::handleStoreDeviceUIConfig(const meshtastic_DeviceUIConfig &uicfg)
{ {
nodeDB->saveProto("/prefs/uiconfig.proto", meshtastic_DeviceUIConfig_size, &meshtastic_DeviceUIConfig_msg, &uicfg); saveProto("/prefs/uiconfig.proto", meshtastic_DeviceUIConfig_size, &meshtastic_DeviceUIConfig_msg, &uicfg);
} }
void AdminModule::handleSetHamMode(const meshtastic_HamParameters &p) void AdminModule::handleSetHamMode(const meshtastic_HamParameters &p)
+5 -5
View File
@@ -2273,9 +2273,9 @@ ProcessMessage CannedMessageModule::handleReceived(const meshtastic_MeshPacket &
void CannedMessageModule::loadProtoForModule() void CannedMessageModule::loadProtoForModule()
{ {
if (nodeDB->loadProto(cannedMessagesConfigFile, meshtastic_CannedMessageModuleConfig_size, if (loadProto(cannedMessagesConfigFile, meshtastic_CannedMessageModuleConfig_size,
sizeof(meshtastic_CannedMessageModuleConfig), &meshtastic_CannedMessageModuleConfig_msg, sizeof(meshtastic_CannedMessageModuleConfig), &meshtastic_CannedMessageModuleConfig_msg,
&cannedMessageModuleConfig) != LoadFileResult::LOAD_SUCCESS) { &cannedMessageModuleConfig) != LoadFileResult::LOAD_SUCCESS) {
installDefaultCannedMessageModuleConfig(); installDefaultCannedMessageModuleConfig();
} }
} }
@@ -2295,8 +2295,8 @@ bool CannedMessageModule::saveProtoForModule()
spiLock->unlock(); spiLock->unlock();
#endif #endif
okay &= nodeDB->saveProto(cannedMessagesConfigFile, meshtastic_CannedMessageModuleConfig_size, okay &= saveProto(cannedMessagesConfigFile, meshtastic_CannedMessageModuleConfig_size,
&meshtastic_CannedMessageModuleConfig_msg, &cannedMessageModuleConfig); &meshtastic_CannedMessageModuleConfig_msg, &cannedMessageModuleConfig);
return okay; return okay;
} }
+4 -3
View File
@@ -14,6 +14,7 @@
* @date [Insert Date] * @date [Insert Date]
*/ */
#include "ExternalNotificationModule.h" #include "ExternalNotificationModule.h"
#include "FSCommon.h"
#include "MeshService.h" #include "MeshService.h"
#include "NodeDB.h" #include "NodeDB.h"
#include "RTC.h" #include "RTC.h"
@@ -370,8 +371,8 @@ ExternalNotificationModule::ExternalNotificationModule()
if (inputBroker) // put our callback in the inputObserver list if (inputBroker) // put our callback in the inputObserver list
inputObserver.observe(inputBroker); inputObserver.observe(inputBroker);
#endif #endif
if (nodeDB->loadProto(rtttlConfigFile, meshtastic_RTTTLConfig_size, sizeof(meshtastic_RTTTLConfig), if (loadProto(rtttlConfigFile, meshtastic_RTTTLConfig_size, sizeof(meshtastic_RTTTLConfig), &meshtastic_RTTTLConfig_msg,
&meshtastic_RTTTLConfig_msg, &rtttlConfig) != LoadFileResult::LOAD_SUCCESS) { &rtttlConfig) != LoadFileResult::LOAD_SUCCESS) {
memset(rtttlConfig.ringtone, 0, sizeof(rtttlConfig.ringtone)); memset(rtttlConfig.ringtone, 0, sizeof(rtttlConfig.ringtone));
// The default ringtone is always loaded from userPrefs.jsonc // The default ringtone is always loaded from userPrefs.jsonc
strncpy(rtttlConfig.ringtone, USERPREFS_RINGTONE_RTTTL, sizeof(rtttlConfig.ringtone)); strncpy(rtttlConfig.ringtone, USERPREFS_RINGTONE_RTTTL, sizeof(rtttlConfig.ringtone));
@@ -640,7 +641,7 @@ void ExternalNotificationModule::handleSetRingtone(const char *from_msg)
} }
if (changed) { if (changed) {
nodeDB->saveProto(rtttlConfigFile, meshtastic_RTTTLConfig_size, &meshtastic_RTTTLConfig_msg, &rtttlConfig); saveProto(rtttlConfigFile, meshtastic_RTTTLConfig_size, &meshtastic_RTTTLConfig_msg, &rtttlConfig);
} }
} }
+1 -1
View File
@@ -217,7 +217,7 @@ void setupModules()
} }
#endif // HAS_BUTTON #endif // HAS_BUTTON
#if ARCH_PORTDUINO #if ARCH_PORTDUINO
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR && portduino_config.i2cdev != "") { if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
seesawRotary = new SeesawRotary("SeesawRotary"); seesawRotary = new SeesawRotary("SeesawRotary");
if (!seesawRotary->init()) { if (!seesawRotary->init()) {
delete seesawRotary; delete seesawRotary;
+1 -1
View File
@@ -170,7 +170,7 @@ bool NeighborInfoModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp,
} else { } else {
LOG_DEBUG(" Ignoring dummy neighbor info packet (single neighbor with nodeId 0, snr 0)"); LOG_DEBUG(" Ignoring dummy neighbor info packet (single neighbor with nodeId 0, snr 0)");
} }
} else if (getHopsAway(mp) == 0) { } else if (mp.hop_start != 0 && mp.hop_start == mp.hop_limit) {
LOG_DEBUG("Get or create neighbor: %u with snr %f", mp.from, mp.rx_snr); LOG_DEBUG("Get or create neighbor: %u with snr %f", mp.from, mp.rx_snr);
// If the hopLimit is the same as hopStart, then it is a neighbor // If the hopLimit is the same as hopStart, then it is a neighbor
getOrCreateNeighbor(mp.from, mp.from, 0, getOrCreateNeighbor(mp.from, mp.from, 0,
+1 -59
View File
@@ -7,41 +7,17 @@
#include "configuration.h" #include "configuration.h"
#include "main.h" #include "main.h"
#include <Throttle.h> #include <Throttle.h>
#include <algorithm>
#ifndef USERPREFS_NODEINFO_REPLY_SUPPRESS_SECS
#define USERPREFS_NODEINFO_REPLY_SUPPRESS_SECS (12 * 60 * 60)
#endif
NodeInfoModule *nodeInfoModule; NodeInfoModule *nodeInfoModule;
static constexpr uint32_t NodeInfoReplySuppressSeconds = USERPREFS_NODEINFO_REPLY_SUPPRESS_SECS;
bool NodeInfoModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_User *pptr) bool NodeInfoModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_User *pptr)
{ {
suppressReplyForCurrentRequest = false;
if (mp.from == nodeDB->getNodeNum()) { if (mp.from == nodeDB->getNodeNum()) {
LOG_WARN("Ignoring packet supposed to be from our own node: %08x", mp.from); LOG_WARN("Ignoring packet supposed to be from our own node: %08x", mp.from);
return false; return false;
} }
auto p = *pptr; auto p = *pptr;
if (mp.decoded.want_response) {
const NodeNum sender = getFrom(&mp);
const uint32_t now = mp.rx_time ? mp.rx_time : getTime();
auto it = lastNodeInfoSeen.find(sender);
if (it != lastNodeInfoSeen.end()) {
uint32_t sinceLast = now >= it->second ? now - it->second : 0;
if (sinceLast < NodeInfoReplySuppressSeconds) {
suppressReplyForCurrentRequest = true;
}
}
lastNodeInfoSeen[sender] = now;
pruneLastNodeInfoCache();
}
if (p.is_licensed != owner.is_licensed) { if (p.is_licensed != owner.is_licensed) {
LOG_WARN("Invalid nodeInfo detected, is_licensed mismatch!"); LOG_WARN("Invalid nodeInfo detected, is_licensed mismatch!");
return true; return true;
@@ -66,8 +42,6 @@ bool NodeInfoModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes
service->sendToPhone(packetCopy); service->sendToPhone(packetCopy);
} }
pruneLastNodeInfoCache();
// LOG_DEBUG("did handleReceived"); // LOG_DEBUG("did handleReceived");
return false; // Let others look at this message also if they want return false; // Let others look at this message also if they want
} }
@@ -94,11 +68,9 @@ void NodeInfoModule::sendOurNodeInfo(NodeNum dest, bool wantReplies, uint8_t cha
if (p) { // Check whether we didn't ignore it if (p) { // Check whether we didn't ignore it
p->to = dest; p->to = dest;
bool requestWantResponse = (config.device.role != meshtastic_Config_DeviceConfig_Role_TRACKER && p->decoded.want_response = (config.device.role != meshtastic_Config_DeviceConfig_Role_TRACKER &&
config.device.role != meshtastic_Config_DeviceConfig_Role_SENSOR) && config.device.role != meshtastic_Config_DeviceConfig_Role_SENSOR) &&
wantReplies; wantReplies;
p->decoded.want_response = requestWantResponse;
if (_shorterTimeout) if (_shorterTimeout)
p->priority = meshtastic_MeshPacket_Priority_DEFAULT; p->priority = meshtastic_MeshPacket_Priority_DEFAULT;
else else
@@ -117,13 +89,6 @@ void NodeInfoModule::sendOurNodeInfo(NodeNum dest, bool wantReplies, uint8_t cha
meshtastic_MeshPacket *NodeInfoModule::allocReply() meshtastic_MeshPacket *NodeInfoModule::allocReply()
{ {
if (suppressReplyForCurrentRequest) {
LOG_DEBUG("Skip send NodeInfo since we heard the requester <12h ago");
ignoreRequest = true;
suppressReplyForCurrentRequest = false;
return NULL;
}
if (!airTime->isTxAllowedChannelUtil(false)) { if (!airTime->isTxAllowedChannelUtil(false)) {
ignoreRequest = true; // Mark it as ignored for MeshModule ignoreRequest = true; // Mark it as ignored for MeshModule
LOG_DEBUG("Skip send NodeInfo > 40%% ch. util"); LOG_DEBUG("Skip send NodeInfo > 40%% ch. util");
@@ -160,29 +125,6 @@ meshtastic_MeshPacket *NodeInfoModule::allocReply()
} }
} }
void NodeInfoModule::pruneLastNodeInfoCache()
{
if (!nodeDB || !nodeDB->meshNodes)
return;
const size_t maxEntries = nodeDB->meshNodes->size();
for (auto it = lastNodeInfoSeen.begin(); it != lastNodeInfoSeen.end();) {
if (!nodeDB->getMeshNode(it->first)) {
it = lastNodeInfoSeen.erase(it);
} else {
++it;
}
}
while (!lastNodeInfoSeen.empty() && lastNodeInfoSeen.size() > maxEntries) {
auto oldestIt = std::min_element(lastNodeInfoSeen.begin(), lastNodeInfoSeen.end(),
[](const std::pair<const NodeNum, uint32_t> &lhs,
const std::pair<const NodeNum, uint32_t> &rhs) { return lhs.second < rhs.second; });
lastNodeInfoSeen.erase(oldestIt);
}
}
NodeInfoModule::NodeInfoModule() NodeInfoModule::NodeInfoModule()
: ProtobufModule("nodeinfo", meshtastic_PortNum_NODEINFO_APP, &meshtastic_User_msg), concurrency::OSThread("NodeInfo") : ProtobufModule("nodeinfo", meshtastic_PortNum_NODEINFO_APP, &meshtastic_User_msg), concurrency::OSThread("NodeInfo")
{ {
-5
View File
@@ -1,6 +1,5 @@
#pragma once #pragma once
#include "ProtobufModule.h" #include "ProtobufModule.h"
#include <map>
/** /**
* NodeInfo module for sending/receiving NodeInfos into the mesh * NodeInfo module for sending/receiving NodeInfos into the mesh
@@ -44,10 +43,6 @@ class NodeInfoModule : public ProtobufModule<meshtastic_User>, private concurren
private: private:
uint32_t lastSentToMesh = 0; // Last time we sent our NodeInfo to the mesh uint32_t lastSentToMesh = 0; // Last time we sent our NodeInfo to the mesh
bool shorterTimeout = false; bool shorterTimeout = false;
bool suppressReplyForCurrentRequest = false;
std::map<NodeNum, uint32_t> lastNodeInfoSeen;
void pruneLastNodeInfoCache();
}; };
extern NodeInfoModule *nodeInfoModule; extern NodeInfoModule *nodeInfoModule;
+9 -58
View File
@@ -45,12 +45,8 @@ bool PositionModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes
{ {
auto p = *pptr; auto p = *pptr;
const auto transport = mp.transport_mechanism; // If inbound message is a replay (or spoof!) of our own messages, we shouldn't process
if (isFromUs(&mp) && !IS_ONE_OF(transport, meshtastic_MeshPacket_TransportMechanism_TRANSPORT_INTERNAL, // (why use second-hand sources for our own data?)
meshtastic_MeshPacket_TransportMechanism_TRANSPORT_API)) {
LOG_WARN("Ignoring packet supposedly from us over external transport");
return true;
}
// FIXME this can in fact happen with packets sent from EUD (src=RX_SRC_USER) // FIXME this can in fact happen with packets sent from EUD (src=RX_SRC_USER)
// to set fixed location, EUD-GPS location or just the time (see also issue #900) // to set fixed location, EUD-GPS location or just the time (see also issue #900)
@@ -349,11 +345,6 @@ void PositionModule::sendOurPosition()
void PositionModule::sendOurPosition(NodeNum dest, bool wantReplies, uint8_t channel) void PositionModule::sendOurPosition(NodeNum dest, bool wantReplies, uint8_t channel)
{ {
if (!config.position.fixed_position && !nodeDB->hasLocalPositionSinceBoot()) {
LOG_DEBUG("Skip position send; no fresh position since boot");
return;
}
// cancel any not yet sent (now stale) position packets // cancel any not yet sent (now stale) position packets
if (prevPacketId) // if we wrap around to zero, we'll simply fail to cancel in that rare case (no big deal) if (prevPacketId) // if we wrap around to zero, we'll simply fail to cancel in that rare case (no big deal)
service->cancelSending(prevPacketId); service->cancelSending(prevPacketId);
@@ -425,14 +416,8 @@ int32_t PositionModule::runOnce()
return RUNONCE_INTERVAL; return RUNONCE_INTERVAL;
} }
bool waitingForFreshPosition = (lastGpsSend == 0) && !config.position.fixed_position && !nodeDB->hasLocalPositionSinceBoot();
if (lastGpsSend == 0 || msSinceLastSend >= intervalMs) { if (lastGpsSend == 0 || msSinceLastSend >= intervalMs) {
if (waitingForFreshPosition) { if (nodeDB->hasValidPosition(node)) {
#ifdef GPS_DEBUG
LOG_DEBUG("Skip initial position send; no fresh position since boot");
#endif
} else if (nodeDB->hasValidPosition(node)) {
lastGpsSend = now; lastGpsSend = now;
lastGpsLatitude = node->position.latitude_i; lastGpsLatitude = node->position.latitude_i;
@@ -487,53 +472,19 @@ void PositionModule::sendLostAndFoundText()
delete[] message; delete[] message;
} }
// Helper: return imprecise (truncated + centered) lat/lon as int32 using current precision
static inline void computeImpreciseLatLon(int32_t inLat, int32_t inLon, uint8_t precisionBits, int32_t &outLat, int32_t &outLon)
{
if (precisionBits > 0 && precisionBits < 32) {
// Build mask for top 'precisionBits' bits of a 32-bit unsigned field
const uint32_t mask = (precisionBits == 32) ? UINT32_MAX : (UINT32_MAX << (32 - precisionBits));
// Note: latitude_i/longitude_i are stored as signed 32-bit in meshtastic code but
// the bitmask logic used previously operated as unsigned—preserve that behavior by
// casting to uint32_t for masking, then back to int32_t.
uint32_t lat_u = static_cast<uint32_t>(inLat) & mask;
uint32_t lon_u = static_cast<uint32_t>(inLon) & mask;
// Add the "center of cell" offset used elsewhere:
// The code previously added (1 << (31 - precision)) to produce the middle of the possible location.
uint32_t center_offset = (1u << (31 - precisionBits));
lat_u += center_offset;
lon_u += center_offset;
outLat = static_cast<int32_t>(lat_u);
outLon = static_cast<int32_t>(lon_u);
} else {
// full precision: return input unchanged
outLat = inLat;
outLon = inLon;
}
}
struct SmartPosition PositionModule::getDistanceTraveledSinceLastSend(meshtastic_PositionLite currentPosition) struct SmartPosition PositionModule::getDistanceTraveledSinceLastSend(meshtastic_PositionLite currentPosition)
{ {
// The minimum distance to travel before we are able to send a new position packet.
const uint32_t distanceTravelThreshold = const uint32_t distanceTravelThreshold =
Default::getConfiguredOrDefault(config.position.broadcast_smart_minimum_distance, 100); Default::getConfiguredOrDefault(config.position.broadcast_smart_minimum_distance, 100);
int32_t lastLatImprecise, lastLonImprecise; // Determine the distance in meters between two points on the globe
int32_t currentLatImprecise, currentLonImprecise; float distanceTraveledSinceLastSend = GeoCoord::latLongToMeter(
lastGpsLatitude * 1e-7, lastGpsLongitude * 1e-7, currentPosition.latitude_i * 1e-7, currentPosition.longitude_i * 1e-7);
computeImpreciseLatLon(lastGpsLatitude, lastGpsLongitude, precision, lastLatImprecise, lastLonImprecise); return SmartPosition{.distanceTraveled = abs(distanceTraveledSinceLastSend),
computeImpreciseLatLon(currentPosition.latitude_i, currentPosition.longitude_i, precision, currentLatImprecise,
currentLonImprecise);
float distMeters = GeoCoord::latLongToMeter(lastLatImprecise * 1e-7, lastLonImprecise * 1e-7, currentLatImprecise * 1e-7,
currentLonImprecise * 1e-7);
float distanceTraveled = fabsf(distMeters);
return SmartPosition{.distanceTraveled = distanceTraveled,
.distanceThreshold = distanceTravelThreshold, .distanceThreshold = distanceTravelThreshold,
.hasTraveledOverThreshold = distanceTraveled >= distanceTravelThreshold}; .hasTraveledOverThreshold = abs(distanceTraveledSinceLastSend) >= distanceTravelThreshold};
} }
void PositionModule::handleNewPosition() void PositionModule::handleNewPosition()
+5 -10
View File
@@ -58,11 +58,12 @@ void RoutingModule::sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketI
router->sendLocal(p); // we sometimes send directly to the local node router->sendLocal(p); // we sometimes send directly to the local node
} }
uint8_t RoutingModule::getHopLimitForResponse(const meshtastic_MeshPacket &mp) uint8_t RoutingModule::getHopLimitForResponse(uint8_t hopStart, uint8_t hopLimit)
{ {
const int8_t hopsUsed = getHopsAway(mp); if (hopStart != 0) {
if (hopsUsed >= 0) { // Hops used by the request. If somebody in between running modified firmware modified it, ignore it
if (hopsUsed > (int32_t)(config.lora.hop_limit)) { uint8_t hopsUsed = hopStart < hopLimit ? config.lora.hop_limit : hopStart - hopLimit;
if (hopsUsed > config.lora.hop_limit) {
// In event mode, we never want to send packets with more than our default 3 hops. // In event mode, we never want to send packets with more than our default 3 hops.
#if !(EVENTMODE) // This falls through to the default. #if !(EVENTMODE) // This falls through to the default.
return hopsUsed; // If the request used more hops than the limit, use the same amount of hops return hopsUsed; // If the request used more hops than the limit, use the same amount of hops
@@ -74,12 +75,6 @@ uint8_t RoutingModule::getHopLimitForResponse(const meshtastic_MeshPacket &mp)
return Default::getConfiguredOrDefaultHopLimit(config.lora.hop_limit); // Use the default hop limit return Default::getConfiguredOrDefaultHopLimit(config.lora.hop_limit); // Use the default hop limit
} }
meshtastic_MeshPacket *RoutingModule::allocAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex,
uint8_t hopLimit)
{
return MeshModule::allocAckNak(err, to, idFrom, chIndex, hopLimit);
}
RoutingModule::RoutingModule() : ProtobufModule("routing", meshtastic_PortNum_ROUTING_APP, &meshtastic_Routing_msg) RoutingModule::RoutingModule() : ProtobufModule("routing", meshtastic_PortNum_ROUTING_APP, &meshtastic_Routing_msg)
{ {
isPromiscuous = true; isPromiscuous = true;
+1 -4
View File
@@ -16,11 +16,8 @@ class RoutingModule : public ProtobufModule<meshtastic_Routing>
virtual void sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex, uint8_t hopLimit = 0, virtual void sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex, uint8_t hopLimit = 0,
bool ackWantsAck = false); bool ackWantsAck = false);
meshtastic_MeshPacket *allocAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex,
uint8_t hopLimit = 0);
// Given the hopStart and hopLimit upon reception of a request, return the hop limit to use for the response // Given the hopStart and hopLimit upon reception of a request, return the hop limit to use for the response
uint8_t getHopLimitForResponse(const meshtastic_MeshPacket &mp); uint8_t getHopLimitForResponse(uint8_t hopStart, uint8_t hopLimit);
protected: protected:
friend class Router; friend class Router;
+3 -24
View File
@@ -20,17 +20,13 @@ int StatusLEDModule::handleStatusUpdate(const meshtastic::Status *arg)
switch (arg->getStatusType()) { switch (arg->getStatusType()) {
case STATUS_TYPE_POWER: { case STATUS_TYPE_POWER: {
meshtastic::PowerStatus *powerStatus = (meshtastic::PowerStatus *)arg; meshtastic::PowerStatus *powerStatus = (meshtastic::PowerStatus *)arg;
if (powerStatus->getHasUSB() || powerStatus->getIsCharging()) { if (powerStatus->getHasUSB()) {
power_state = charging; power_state = charging;
if (powerStatus->getBatteryChargePercent() >= 100) { if (powerStatus->getBatteryChargePercent() >= 100) {
power_state = charged; power_state = charged;
} }
} else { } else {
if (powerStatus->getBatteryChargePercent() > 5) { power_state = discharging;
power_state = discharging;
} else {
power_state = critical;
}
} }
break; break;
} }
@@ -62,33 +58,16 @@ int StatusLEDModule::handleStatusUpdate(const meshtastic::Status *arg)
int32_t StatusLEDModule::runOnce() int32_t StatusLEDModule::runOnce()
{ {
my_interval = 1000;
if (power_state == charging) { if (power_state == charging) {
CHARGE_LED_state = !CHARGE_LED_state; CHARGE_LED_state = !CHARGE_LED_state;
} else if (power_state == charged) { } else if (power_state == charged) {
CHARGE_LED_state = LED_STATE_ON; CHARGE_LED_state = LED_STATE_ON;
} else if (power_state == critical) {
if (POWER_LED_starttime + 30000 < millis() && !doing_fast_blink) {
doing_fast_blink = true;
POWER_LED_starttime = millis();
}
if (doing_fast_blink) {
PAIRING_LED_state = LED_STATE_OFF;
CHARGE_LED_state = !CHARGE_LED_state;
my_interval = 250;
if (POWER_LED_starttime + 2000 < millis()) {
doing_fast_blink = false;
}
} else {
CHARGE_LED_state = LED_STATE_OFF;
}
} else { } else {
CHARGE_LED_state = LED_STATE_OFF; CHARGE_LED_state = LED_STATE_OFF;
} }
if (!config.bluetooth.enabled || PAIRING_LED_starttime + 30 * 1000 < millis() || doing_fast_blink) { if (!config.bluetooth.enabled || PAIRING_LED_starttime + 30 * 1000 < millis()) {
PAIRING_LED_state = LED_STATE_OFF; PAIRING_LED_state = LED_STATE_OFF;
} else if (ble_state == unpaired) { } else if (ble_state == unpaired) {
if (slowTrack) { if (slowTrack) {
+1 -3
View File
@@ -31,10 +31,8 @@ class StatusLEDModule : private concurrency::OSThread
bool PAIRING_LED_state = LED_STATE_OFF; bool PAIRING_LED_state = LED_STATE_OFF;
uint32_t PAIRING_LED_starttime = 0; uint32_t PAIRING_LED_starttime = 0;
uint32_t POWER_LED_starttime = 0;
bool doing_fast_blink = false;
enum PowerState { discharging, charging, charged, critical }; enum PowerState { discharging, charging, charged };
PowerState power_state = discharging; PowerState power_state = discharging;
+4 -5
View File
@@ -1,6 +1,5 @@
#include "TraceRouteModule.h" #include "TraceRouteModule.h"
#include "MeshService.h" #include "MeshService.h"
#include "NodeDB.h"
#include "graphics/Screen.h" #include "graphics/Screen.h"
#include "graphics/ScreenFonts.h" #include "graphics/ScreenFonts.h"
#include "graphics/SharedUIDisplay.h" #include "graphics/SharedUIDisplay.h"
@@ -360,10 +359,10 @@ void TraceRouteModule::insertUnknownHops(meshtastic_MeshPacket &p, meshtastic_Ro
} }
// Only insert unknown hops if hop_start is valid // Only insert unknown hops if hop_start is valid
const int8_t hopsTaken = getHopsAway(p); if (p.hop_start != 0 && p.hop_limit <= p.hop_start) {
if (hopsTaken >= 0) { uint8_t hopsTaken = p.hop_start - p.hop_limit;
int8_t diff = hopsTaken - *route_count; int8_t diff = hopsTaken - *route_count;
for (int8_t i = 0; i < diff; i++) { for (uint8_t i = 0; i < diff; i++) {
if (*route_count < ROUTE_SIZE) { if (*route_count < ROUTE_SIZE) {
route[*route_count] = NODENUM_BROADCAST; // This will represent an unknown hop route[*route_count] = NODENUM_BROADCAST; // This will represent an unknown hop
*route_count += 1; *route_count += 1;
@@ -371,7 +370,7 @@ void TraceRouteModule::insertUnknownHops(meshtastic_MeshPacket &p, meshtastic_Ro
} }
// Add unknown SNR values if necessary // Add unknown SNR values if necessary
diff = *route_count - *snr_count; diff = *route_count - *snr_count;
for (int8_t i = 0; i < diff; i++) { for (uint8_t i = 0; i < diff; i++) {
if (*snr_count < ROUTE_SIZE) { if (*snr_count < ROUTE_SIZE) {
snr_list[*snr_count] = INT8_MIN; // This will represent an unknown SNR snr_list[*snr_count] = INT8_MIN; // This will represent an unknown SNR
*snr_count += 1; *snr_count += 1;
+3 -6
View File
@@ -87,13 +87,10 @@ inline void onReceiveProto(char *topic, byte *payload, size_t length)
// Generate an implicit ACK towards ourselves (handled and processed only locally!) for this message. // Generate an implicit ACK towards ourselves (handled and processed only locally!) for this message.
// We do this because packets are not rebroadcasted back into MQTT anymore and we assume that at least one node // We do this because packets are not rebroadcasted back into MQTT anymore and we assume that at least one node
// receives it when we get our own packet back. Then we'll stop our retransmissions. // receives it when we get our own packet back. Then we'll stop our retransmissions.
if (isFromUs(e.packet)) { if (isFromUs(e.packet))
auto pAck = routingModule->allocAckNak(meshtastic_Routing_Error_NONE, getFrom(e.packet), e.packet->id, ch.index); routingModule->sendAckNak(meshtastic_Routing_Error_NONE, getFrom(e.packet), e.packet->id, ch.index);
pAck->transport_mechanism = meshtastic_MeshPacket_TransportMechanism_TRANSPORT_MQTT; else
router->sendLocal(pAck);
} else {
LOG_INFO("Ignore downlink message we originally sent"); LOG_INFO("Ignore downlink message we originally sent");
}
return; return;
} }
if (isFromUs(e.packet)) { if (isFromUs(e.packet)) {
+1 -1
View File
@@ -337,7 +337,7 @@ void cpuDeepSleep(uint32_t msecToWake)
#endif #endif
#ifdef TTGO_T_ECHO #ifdef TTGO_T_ECHO
// To power off the T-Echo, the display must be set // To power off the T-Echo, the display must be set
// as an input pin; otherwise, there will be leakage current. // as an input pin; otherwise, there will be leakage current.
pinMode(PIN_EINK_CS, INPUT); pinMode(PIN_EINK_CS, INPUT);
pinMode(PIN_EINK_DC, INPUT); pinMode(PIN_EINK_DC, INPUT);
+2 -42
View File
@@ -29,7 +29,6 @@
portduino_config_struct portduino_config; portduino_config_struct portduino_config;
std::ofstream traceFile; std::ofstream traceFile;
std::ofstream JSONFile;
Ch341Hal *ch341Hal = nullptr; Ch341Hal *ch341Hal = nullptr;
char *configPath = nullptr; char *configPath = nullptr;
char *optionMac = nullptr; char *optionMac = nullptr;
@@ -279,7 +278,7 @@ void portduinoSetup()
// RAK6421-13300-S1:aabbcc123456:5ba85807d92138b7519cfb60460573af:3061e8d8 // RAK6421-13300-S1:aabbcc123456:5ba85807d92138b7519cfb60460573af:3061e8d8
// <model string>:mac address :<16 random unique bytes in hexidecimal> : crc32 // <model string>:mac address :<16 random unique bytes in hexidecimal> : crc32
// crc32 is calculated on the eeprom string up to but not including the final colon // crc32 is calculated on the eeprom string up to but not including the final colon
if (strlen(autoconf_product) < 6 && portduino_config.i2cdev != "") { if (strlen(autoconf_product) < 6) {
try { try {
char *mac_start = nullptr; char *mac_start = nullptr;
char *devID_start = nullptr; char *devID_start = nullptr;
@@ -464,7 +463,6 @@ void portduinoSetup()
if (portduino_config.lora_spi_dev != "" && portduino_config.lora_spi_dev != "ch341") { if (portduino_config.lora_spi_dev != "" && portduino_config.lora_spi_dev != "ch341") {
SPI.begin(portduino_config.lora_spi_dev.c_str()); SPI.begin(portduino_config.lora_spi_dev.c_str());
} }
if (portduino_config.traceFilename != "") { if (portduino_config.traceFilename != "") {
try { try {
traceFile.open(portduino_config.traceFilename, std::ios::out | std::ios::app); traceFile.open(portduino_config.traceFilename, std::ios::out | std::ios::app);
@@ -472,21 +470,6 @@ void portduinoSetup()
std::cout << "*** traceFile Exception " << e.what() << std::endl; std::cout << "*** traceFile Exception " << e.what() << std::endl;
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if (!traceFile.is_open()) {
std::cout << "*** traceFile open failure" << std::endl;
exit(EXIT_FAILURE);
}
} else if (portduino_config.JSONFilename != "") {
try {
JSONFile.open(portduino_config.JSONFilename, std::ios::out | std::ios::app);
} catch (std::ofstream::failure &e) {
std::cout << "*** JSONFile Exception " << e.what() << std::endl;
exit(EXIT_FAILURE);
}
if (!JSONFile.is_open()) {
std::cout << "*** JSONFile open failure" << std::endl;
exit(EXIT_FAILURE);
}
} }
if (verboseEnabled && portduino_config.logoutputlevel != level_trace) { if (verboseEnabled && portduino_config.logoutputlevel != level_trace) {
portduino_config.logoutputlevel = level_debug; portduino_config.logoutputlevel = level_debug;
@@ -534,29 +517,6 @@ bool loadConfig(const char *configPath)
portduino_config.logoutputlevel = level_error; portduino_config.logoutputlevel = level_error;
} }
portduino_config.traceFilename = yamlConfig["Logging"]["TraceFile"].as<std::string>(""); portduino_config.traceFilename = yamlConfig["Logging"]["TraceFile"].as<std::string>("");
portduino_config.JSONFilename = yamlConfig["Logging"]["JSONFile"].as<std::string>("");
portduino_config.JSONFilter = (_meshtastic_PortNum)yamlConfig["Logging"]["JSONFilter"].as<int>(0);
if (yamlConfig["Logging"]["JSONFilter"].as<std::string>("") == "textmessage")
portduino_config.JSONFilter = meshtastic_PortNum_TEXT_MESSAGE_APP;
else if (yamlConfig["Logging"]["JSONFilter"].as<std::string>("") == "telemetry")
portduino_config.JSONFilter = meshtastic_PortNum_TELEMETRY_APP;
else if (yamlConfig["Logging"]["JSONFilter"].as<std::string>("") == "nodeinfo")
portduino_config.JSONFilter = meshtastic_PortNum_NODEINFO_APP;
else if (yamlConfig["Logging"]["JSONFilter"].as<std::string>("") == "position")
portduino_config.JSONFilter = meshtastic_PortNum_POSITION_APP;
else if (yamlConfig["Logging"]["JSONFilter"].as<std::string>("") == "waypoint")
portduino_config.JSONFilter = meshtastic_PortNum_WAYPOINT_APP;
else if (yamlConfig["Logging"]["JSONFilter"].as<std::string>("") == "neighborinfo")
portduino_config.JSONFilter = meshtastic_PortNum_NEIGHBORINFO_APP;
else if (yamlConfig["Logging"]["JSONFilter"].as<std::string>("") == "traceroute")
portduino_config.JSONFilter = meshtastic_PortNum_TRACEROUTE_APP;
else if (yamlConfig["Logging"]["JSONFilter"].as<std::string>("") == "detection")
portduino_config.JSONFilter = meshtastic_PortNum_DETECTION_SENSOR_APP;
else if (yamlConfig["Logging"]["JSONFilter"].as<std::string>("") == "paxcounter")
portduino_config.JSONFilter = meshtastic_PortNum_PAXCOUNTER_APP;
else if (yamlConfig["Logging"]["JSONFilter"].as<std::string>("") == "remotehardware")
portduino_config.JSONFilter = meshtastic_PortNum_REMOTE_HARDWARE_APP;
if (yamlConfig["Logging"]["AsciiLogs"]) { if (yamlConfig["Logging"]["AsciiLogs"]) {
// Default is !isatty(1) but can be set explicitly in config.yaml // Default is !isatty(1) but can be set explicitly in config.yaml
portduino_config.ascii_logs = yamlConfig["Logging"]["AsciiLogs"].as<bool>(); portduino_config.ascii_logs = yamlConfig["Logging"]["AsciiLogs"].as<bool>();
@@ -867,4 +827,4 @@ void readGPIOFromYaml(YAML::Node sourceNode, pinMapping &destPin, int pinDefault
destPin.line = destPin.pin; destPin.line = destPin.pin;
destPin.gpiochip = portduino_config.lora_default_gpiochip; destPin.gpiochip = portduino_config.lora_default_gpiochip;
} }
} }
-29
View File
@@ -5,7 +5,6 @@
#include "LR11x0Interface.h" #include "LR11x0Interface.h"
#include "Module.h" #include "Module.h"
#include "mesh/generated/meshtastic/mesh.pb.h"
#include "platform/portduino/USBHal.h" #include "platform/portduino/USBHal.h"
#include "yaml-cpp/yaml.h" #include "yaml-cpp/yaml.h"
@@ -47,8 +46,6 @@ struct pinMapping {
}; };
extern std::ofstream traceFile; extern std::ofstream traceFile;
extern std::ofstream JSONFile;
extern Ch341Hal *ch341Hal; extern Ch341Hal *ch341Hal;
int initGPIOPin(int pinNum, std::string gpioChipname, int line); int initGPIOPin(int pinNum, std::string gpioChipname, int line);
bool loadConfig(const char *configPath); bool loadConfig(const char *configPath);
@@ -151,9 +148,6 @@ extern struct portduino_config_struct {
bool ascii_logs = !isatty(1); bool ascii_logs = !isatty(1);
bool ascii_logs_explicit = false; bool ascii_logs_explicit = false;
std::string JSONFilename;
meshtastic_PortNum JSONFilter = (_meshtastic_PortNum)0;
// Webserver // Webserver
std::string webserver_root_path = ""; std::string webserver_root_path = "";
std::string webserver_ssl_key_path = "/etc/meshtasticd/ssl/private_key.pem"; std::string webserver_ssl_key_path = "/etc/meshtasticd/ssl/private_key.pem";
@@ -419,29 +413,6 @@ extern struct portduino_config_struct {
} }
if (traceFilename != "") if (traceFilename != "")
out << YAML::Key << "TraceFile" << YAML::Value << traceFilename; out << YAML::Key << "TraceFile" << YAML::Value << traceFilename;
if (JSONFilename != "") {
out << YAML::Key << "JSONFile" << YAML::Value << JSONFilename;
if (JSONFilter == meshtastic_PortNum_TEXT_MESSAGE_APP)
out << YAML::Key << "JSONFilter" << YAML::Value << "textmessage";
else if (JSONFilter == meshtastic_PortNum_TELEMETRY_APP)
out << YAML::Key << "JSONFilter" << YAML::Value << "telemetry";
else if (JSONFilter == meshtastic_PortNum_NODEINFO_APP)
out << YAML::Key << "JSONFilter" << YAML::Value << "nodeinfo";
else if (JSONFilter == meshtastic_PortNum_POSITION_APP)
out << YAML::Key << "JSONFilter" << YAML::Value << "position";
else if (JSONFilter == meshtastic_PortNum_WAYPOINT_APP)
out << YAML::Key << "JSONFilter" << YAML::Value << "waypoint";
else if (JSONFilter == meshtastic_PortNum_NEIGHBORINFO_APP)
out << YAML::Key << "JSONFilter" << YAML::Value << "neighborinfo";
else if (JSONFilter == meshtastic_PortNum_TRACEROUTE_APP)
out << YAML::Key << "JSONFilter" << YAML::Value << "traceroute";
else if (JSONFilter == meshtastic_PortNum_DETECTION_SENSOR_APP)
out << YAML::Key << "JSONFilter" << YAML::Value << "detection";
else if (JSONFilter == meshtastic_PortNum_PAXCOUNTER_APP)
out << YAML::Key << "JSONFilter" << YAML::Value << "paxcounter";
else if (JSONFilter == meshtastic_PortNum_REMOTE_HARDWARE_APP)
out << YAML::Key << "JSONFilter" << YAML::Value << "remotehardware";
}
if (ascii_logs_explicit) { if (ascii_logs_explicit) {
out << YAML::Key << "AsciiLogs" << YAML::Value << ascii_logs; out << YAML::Key << "AsciiLogs" << YAML::Value << ascii_logs;
} }
+4 -6
View File
@@ -418,9 +418,8 @@ std::string MeshPacketSerializer::JsonSerialize(const meshtastic_MeshPacket *mp,
jsonObj["rssi"] = new JSONValue((int)mp->rx_rssi); jsonObj["rssi"] = new JSONValue((int)mp->rx_rssi);
if (mp->rx_snr != 0) if (mp->rx_snr != 0)
jsonObj["snr"] = new JSONValue((float)mp->rx_snr); jsonObj["snr"] = new JSONValue((float)mp->rx_snr);
const int8_t hopsAway = getHopsAway(*mp); if (mp->hop_start != 0 && mp->hop_limit <= mp->hop_start) {
if (hopsAway >= 0) { jsonObj["hops_away"] = new JSONValue((unsigned int)(mp->hop_start - mp->hop_limit));
jsonObj["hops_away"] = new JSONValue((unsigned int)(hopsAway));
jsonObj["hop_start"] = new JSONValue((unsigned int)(mp->hop_start)); jsonObj["hop_start"] = new JSONValue((unsigned int)(mp->hop_start));
} }
@@ -451,9 +450,8 @@ std::string MeshPacketSerializer::JsonSerializeEncrypted(const meshtastic_MeshPa
jsonObj["rssi"] = new JSONValue((int)mp->rx_rssi); jsonObj["rssi"] = new JSONValue((int)mp->rx_rssi);
if (mp->rx_snr != 0) if (mp->rx_snr != 0)
jsonObj["snr"] = new JSONValue((float)mp->rx_snr); jsonObj["snr"] = new JSONValue((float)mp->rx_snr);
const int8_t hopsAway = getHopsAway(*mp); if (mp->hop_start != 0 && mp->hop_limit <= mp->hop_start) {
if (hopsAway >= 0) { jsonObj["hops_away"] = new JSONValue((unsigned int)(mp->hop_start - mp->hop_limit));
jsonObj["hops_away"] = new JSONValue((unsigned int)(hopsAway));
jsonObj["hop_start"] = new JSONValue((unsigned int)(mp->hop_start)); jsonObj["hop_start"] = new JSONValue((unsigned int)(mp->hop_start));
} }
jsonObj["size"] = new JSONValue((unsigned int)mp->encrypted.size); jsonObj["size"] = new JSONValue((unsigned int)mp->encrypted.size);
@@ -358,9 +358,8 @@ std::string MeshPacketSerializer::JsonSerialize(const meshtastic_MeshPacket *mp,
jsonObj["rssi"] = (int)mp->rx_rssi; jsonObj["rssi"] = (int)mp->rx_rssi;
if (mp->rx_snr != 0) if (mp->rx_snr != 0)
jsonObj["snr"] = (float)mp->rx_snr; jsonObj["snr"] = (float)mp->rx_snr;
const int8_t hopsAway = getHopsAway(*mp); if (mp->hop_start != 0 && mp->hop_limit <= mp->hop_start) {
if (hopsAway >= 0) { jsonObj["hops_away"] = (unsigned int)(mp->hop_start - mp->hop_limit);
jsonObj["hops_away"] = (unsigned int)(hopsAway);
jsonObj["hop_start"] = (unsigned int)(mp->hop_start); jsonObj["hop_start"] = (unsigned int)(mp->hop_start);
} }
@@ -394,9 +393,8 @@ std::string MeshPacketSerializer::JsonSerializeEncrypted(const meshtastic_MeshPa
jsonObj["rssi"] = (int)mp->rx_rssi; jsonObj["rssi"] = (int)mp->rx_rssi;
if (mp->rx_snr != 0) if (mp->rx_snr != 0)
jsonObj["snr"] = (float)mp->rx_snr; jsonObj["snr"] = (float)mp->rx_snr;
const int8_t hopsAway = getHopsAway(*mp); if (mp->hop_start != 0 && mp->hop_limit <= mp->hop_start) {
if (hopsAway >= 0) { jsonObj["hops_away"] = (unsigned int)(mp->hop_start - mp->hop_limit);
jsonObj["hops_away"] = (unsigned int)(hopsAway);
jsonObj["hop_start"] = (unsigned int)(mp->hop_start); jsonObj["hop_start"] = (unsigned int)(mp->hop_start);
} }
jsonObj["size"] = (unsigned int)mp->encrypted.size; jsonObj["size"] = (unsigned int)mp->encrypted.size;
+6 -7
View File
@@ -605,13 +605,12 @@ void test_receiveAcksOwnSentMessages(void)
unitTest->publish(&p, nodeDB->getNodeId().c_str()); unitTest->publish(&p, nodeDB->getNodeId().c_str());
// FIXME: Better assertion for this test TEST_ASSERT_TRUE(mockRouter->packets_.empty());
// TEST_ASSERT_TRUE(mockRouter->packets_.empty()); TEST_ASSERT_EQUAL(1, mockRoutingModule->ackNacks_.size());
// TEST_ASSERT_EQUAL(1, mockRoutingModule->ackNacks_.size()); const auto &[err, to, idFrom, chIndex, hopLimit] = mockRoutingModule->ackNacks_.front();
// const auto &[err, to, idFrom, chIndex, hopLimit] = mockRoutingModule->ackNacks_.front(); TEST_ASSERT_EQUAL(meshtastic_Routing_Error_NONE, err);
// TEST_ASSERT_EQUAL(meshtastic_Routing_Error_NONE, err); TEST_ASSERT_EQUAL(myNodeInfo.my_node_num, to);
// TEST_ASSERT_EQUAL(myNodeInfo.my_node_num, to); TEST_ASSERT_EQUAL(p.id, idFrom);
// TEST_ASSERT_EQUAL(p.id, idFrom);
} }
// Should ignore our own messages from MQTT that were heard by other nodes. // Should ignore our own messages from MQTT that were heard by other nodes.
-1
View File
@@ -55,7 +55,6 @@
// "USERPREFS_MQTT_TLS_ENABLED": "false", // "USERPREFS_MQTT_TLS_ENABLED": "false",
// "USERPREFS_MQTT_ROOT_TOPIC": "event/REPLACEME", // "USERPREFS_MQTT_ROOT_TOPIC": "event/REPLACEME",
// "USERPREFS_RINGTONE_NAG_SECS": "60", // "USERPREFS_RINGTONE_NAG_SECS": "60",
// "USERPREFS_NODEINFO_REPLY_SUPPRESS_SECS": "43200",
"USERPREFS_RINGTONE_RTTTL": "24:d=32,o=5,b=565:f6,p,f6,4p,p,f6,p,f6,2p,p,b6,p,b6,p,b6,p,b6,p,b,p,b,p,b,p,b,p,b,p,b,p,b,p,b,1p.,2p.,p", "USERPREFS_RINGTONE_RTTTL": "24:d=32,o=5,b=565:f6,p,f6,4p,p,f6,p,f6,2p,p,b6,p,b6,p,b6,p,b6,p,b,p,b,p,b,p,b,p,b,p,b,p,b,p,b,1p.,2p.,p",
// "USERPREFS_NETWORK_IPV6_ENABLED": "1", // "USERPREFS_NETWORK_IPV6_ENABLED": "1",
"USERPREFS_TZ_STRING": "tzplaceholder " "USERPREFS_TZ_STRING": "tzplaceholder "
-1
View File
@@ -2,7 +2,6 @@
[env:meshtastic-dr-dev] [env:meshtastic-dr-dev]
extends = esp32_base extends = esp32_base
board = esp32doit-devkit-v1 board = esp32doit-devkit-v1
board_level = extra
board_upload.maximum_size = 4194304 board_upload.maximum_size = 4194304
board_upload.maximum_ram_size = 532480 board_upload.maximum_ram_size = 532480
build_flags = build_flags =
+1 -1
View File
@@ -5,7 +5,7 @@ custom_esp32_kind = esp32
custom_mtjson_part = custom_mtjson_part =
platform = platform =
# renovate: datasource=custom.pio depName=platformio/espressif32 packageName=platformio/platform/espressif32 # renovate: datasource=custom.pio depName=platformio/espressif32 packageName=platformio/platform/espressif32
platformio/espressif32@6.12.0 platformio/espressif32@6.11.0
extra_scripts = extra_scripts =
${env.extra_scripts} ${env.extra_scripts}
+2 -2
View File
@@ -2,7 +2,7 @@
[env:tbeam] [env:tbeam]
extends = esp32_base extends = esp32_base
board = ttgo-t-beam board = ttgo-t-beam
board_level = pr
board_check = true board_check = true
lib_deps = ${esp32_base.lib_deps} lib_deps = ${esp32_base.lib_deps}
build_flags = ${esp32_base.build_flags} build_flags = ${esp32_base.build_flags}
@@ -14,7 +14,7 @@ upload_speed = 921600
[env:tbeam-displayshield] [env:tbeam-displayshield]
extends = env:tbeam extends = env:tbeam
board_level = extra
build_flags = build_flags =
${env:tbeam.build_flags} ${env:tbeam.build_flags}
-D USE_ST7796 -D USE_ST7796
@@ -1,7 +1,6 @@
[env:link32-s3-v1] [env:link32-s3-v1]
extends = esp32s3_base extends = esp32s3_base
board = esp32-s3-devkitc-1 board = esp32-s3-devkitc-1
board_level = extra
build_flags = build_flags =
${esp32_base.build_flags} ${esp32_base.build_flags}
-D LINK_32 -D LINK_32
-2
View File
@@ -100,5 +100,3 @@
#define MODEM_DTR 8 #define MODEM_DTR 8
#define MODEM_RX 10 #define MODEM_RX 10
#define MODEM_TX 11 #define MODEM_TX 11
#define HAS_PHYSICAL_KEYBOARD 1
-1
View File
@@ -23,7 +23,6 @@
#define SCREEN_TRANSITION_FRAMERATE 5 #define SCREEN_TRANSITION_FRAMERATE 5
#define BRIGHTNESS_DEFAULT 130 // Medium Low Brightness #define BRIGHTNESS_DEFAULT 130 // Medium Low Brightness
#define USE_TFTDISPLAY 1 #define USE_TFTDISPLAY 1
#define HAS_PHYSICAL_KEYBOARD 1
#define HAS_TOUCHSCREEN 1 #define HAS_TOUCHSCREEN 1
#define SCREEN_TOUCH_INT 16 #define SCREEN_TOUCH_INT 16
-1
View File
@@ -21,7 +21,6 @@
#define SCREEN_TRANSITION_FRAMERATE 5 #define SCREEN_TRANSITION_FRAMERATE 5
#define BRIGHTNESS_DEFAULT 130 // Medium Low Brightness #define BRIGHTNESS_DEFAULT 130 // Medium Low Brightness
#define USE_TFTDISPLAY 1 #define USE_TFTDISPLAY 1
#define HAS_PHYSICAL_KEYBOARD 1
#define I2C_SDA SDA #define I2C_SDA SDA
#define I2C_SCL SCL #define I2C_SCL SCL
@@ -63,20 +63,9 @@ void initVariant()
// called from main-nrf52.cpp during the cpuDeepSleep() function // called from main-nrf52.cpp during the cpuDeepSleep() function
void variant_shutdown() void variant_shutdown()
{ {
digitalWrite(red_LED_PIN, HIGH);
digitalWrite(green_LED_PIN, HIGH);
digitalWrite(LED_BLUE, HIGH);
digitalWrite(PIN_EN1, LOW);
digitalWrite(PIN_EN2, LOW);
digitalWrite(EEPROM_POWER, LOW); digitalWrite(EEPROM_POWER, LOW);
digitalWrite(KEY_POWER, LOW); digitalWrite(KEY_POWER, LOW);
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++) { for (int pin = 0; pin < 48; pin++) {
if (pin == PIN_POWER_USB || pin == BUTTON_PIN || pin == PIN_EN1 || pin == PIN_EN2 || pin == DHT_POWER || if (pin == PIN_POWER_USB || pin == BUTTON_PIN || pin == PIN_EN1 || pin == PIN_EN2 || pin == DHT_POWER ||
pin == ACC_POWER || pin == Battery_POWER || pin == GPS_POWER || pin == LR1110_SPI_MISO_PIN || pin == ACC_POWER || pin == Battery_POWER || pin == GPS_POWER || pin == LR1110_SPI_MISO_PIN ||
@@ -54,7 +54,6 @@ extern "C" {
#define LED_POWER red_LED_PIN #define LED_POWER red_LED_PIN
#define LED_CHARGE LED_POWER // Signals the Status LED Module to handle this LED #define LED_CHARGE LED_POWER // Signals the Status LED Module to handle this LED
#define green_LED_PIN 35 #define green_LED_PIN 35
#define PIN_LED2 green_LED_PIN
#define LED_BLUE 37 #define LED_BLUE 37
#define LED_PAIRING LED_BLUE // Signals the Status LED Module to handle this LED #define LED_PAIRING LED_BLUE // Signals the Status LED Module to handle this LED
@@ -41,30 +41,3 @@ void initVariant()
pinMode(VDD_FLASH_EN, OUTPUT); pinMode(VDD_FLASH_EN, OUTPUT);
digitalWrite(VDD_FLASH_EN, HIGH); digitalWrite(VDD_FLASH_EN, HIGH);
} }
// called from main-nrf52.cpp during the cpuDeepSleep() function
void variant_shutdown()
{
// 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_GPS_EN || pin == ADC_CTRL || pin == PIN_BUTTON1 || pin == PIN_SPI_MISO || pin == PIN_SPI_MOSI ||
pin == PIN_SPI_SCK) {
continue;
}
pinMode(pin, OUTPUT);
digitalWrite(pin, LOW);
if (pin >= 32) {
NRF_P1->DIRCLR = (1 << (pin - 32));
} else {
NRF_GPIO->DIRCLR = (1 << pin);
}
}
digitalWrite(PIN_GPS_EN, LOW);
digitalWrite(ADC_CTRL, LOW);
// digitalWrite(RTC_POWER, LOW);
nrf_gpio_cfg_input(PIN_BUTTON1, NRF_GPIO_PIN_PULLUP); // Configure the pin to be woken up as an input
nrf_gpio_pin_sense_t sense1 = NRF_GPIO_PIN_SENSE_LOW;
nrf_gpio_cfg_sense_set(PIN_BUTTON1, sense1);
}
@@ -44,10 +44,8 @@ extern "C" {
#define LED_BLUE -1 #define LED_BLUE -1
#define LED_CHARGE (12) #define LED_CHARGE (12)
#define LED_PAIRING (7) #define LED_PAIRING (7)
#define PIN_LED2 LED_PAIRING
#define LED_STATE_ON HIGH #define LED_STATE_ON 1
#define LED_STATE_OFF LOW
// USB power detection // USB power detection
#define EXT_PWR_DETECT (13) #define EXT_PWR_DETECT (13)
@@ -90,16 +90,16 @@ NRF52 PRO MICRO PIN ASSIGNMENT
#define BUTTON_PIN (32 + 0) // P1.00 #define BUTTON_PIN (32 + 0) // P1.00
// GPS // GPS
#define GPS_TX_PIN (0 + 20) // P0.20 - This is data from the MCU #define PIN_GPS_TX (0 + 20) // P0.20 - This is data from the MCU
#define GPS_RX_PIN (0 + 22) // P0.22 - This is data from the GNSS #define PIN_GPS_RX (0 + 22) // P0.22 - This is data from the GNSS
#define PIN_GPS_EN (0 + 24) // P0.24 #define PIN_GPS_EN (0 + 24) // P0.24
#define GPS_UBLOX #define GPS_UBLOX
// define GPS_DEBUG // define GPS_DEBUG
// UART interfaces // UART interfaces
#define PIN_SERIAL1_TX GPS_TX_PIN #define PIN_SERIAL1_TX PIN_GPS_TX
#define PIN_SERIAL1_RX GPS_RX_PIN #define PIN_SERIAL1_RX PIN_GPS_RX
#define PIN_SERIAL2_RX (0 + 6) // P0.06 #define PIN_SERIAL2_RX (0 + 6) // P0.06
#define PIN_SERIAL2_TX (0 + 8) // P0.08 #define PIN_SERIAL2_TX (0 + 8) // P0.08
+4 -4
View File
@@ -132,13 +132,13 @@ External serial flash W25Q16JV_IQ
#define GPS_L76K #define GPS_L76K
#define PIN_GPS_STANDBY (0 + 13) // An output to wake GPS, low means allow sleep, high means force wake STANDBY #define PIN_GPS_STANDBY (0 + 13) // An output to wake GPS, low means allow sleep, high means force wake STANDBY
#define GPS_TX_PIN (0 + 10) // This is for bits going FROM the CPU #define PIN_GPS_TX (0 + 10) // This is for bits going TOWARDS the CPU
#define GPS_RX_PIN (0 + 9) // This is for bits going FROM the GPS #define PIN_GPS_RX (0 + 9) // This is for bits going TOWARDS the GPS
// #define GPS_THREAD_INTERVAL 50 // #define GPS_THREAD_INTERVAL 50
#define PIN_SERIAL1_TX GPS_TX_PIN #define PIN_SERIAL1_TX PIN_GPS_TX
#define PIN_SERIAL1_RX GPS_RX_PIN #define PIN_SERIAL1_RX PIN_GPS_RX
// PCF8563 RTC Module // PCF8563 RTC Module
#define PCF8563_RTC 0x51 #define PCF8563_RTC 0x51
+1
View File
@@ -19,6 +19,7 @@ build_type = release
build_flags = build_flags =
-include variants/nrf52840/cpp_overrides/lfs_util.h -include variants/nrf52840/cpp_overrides/lfs_util.h
${arduino_base.build_flags} ${arduino_base.build_flags}
-DSERIAL_BUFFER_SIZE=1024
-Wno-unused-variable -Wno-unused-variable
-Isrc/platform/nrf52 -Isrc/platform/nrf52
-DLFS_NO_ASSERT ; Disable LFS assertions , see https://github.com/meshtastic/firmware/pull/3818 -DLFS_NO_ASSERT ; Disable LFS assertions , see https://github.com/meshtastic/firmware/pull/3818
+1 -3
View File
@@ -1,9 +1,7 @@
[nrf52832_base] [nrf52832_base]
extends = nrf52_base extends = nrf52_base
build_flags = build_flags = ${nrf52_base.build_flags}
${nrf52_base.build_flags}
-DSERIAL_BUFFER_SIZE=1024
lib_deps = lib_deps =
${nrf52_base.lib_deps} ${nrf52_base.lib_deps}
+1 -3
View File
@@ -1,9 +1,7 @@
[nrf52840_base] [nrf52840_base]
extends = nrf52_base extends = nrf52_base
build_flags = build_flags = ${nrf52_base.build_flags}
${nrf52_base.build_flags}
-DSERIAL_BUFFER_SIZE=4096
lib_deps = lib_deps =
${nrf52_base.lib_deps} ${nrf52_base.lib_deps}
+4 -4
View File
@@ -116,13 +116,13 @@ static const uint8_t SCL = PIN_WIRE_SCL;
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
#define GPS_L76K #define GPS_L76K
#ifdef GPS_L76K #ifdef GPS_L76K
#define GPS_TX_PIN D6 // 44 #define PIN_GPS_TX D6 // 44
#define GPS_RX_PIN D7 // 43 #define PIN_GPS_RX D7 // 43
#define HAS_GPS 1 #define HAS_GPS 1
#define GPS_BAUDRATE 9600 #define GPS_BAUDRATE 9600
#define GPS_THREAD_INTERVAL 50 #define GPS_THREAD_INTERVAL 50
#define PIN_SERIAL1_TX GPS_TX_PIN #define PIN_SERIAL1_TX PIN_GPS_TX
#define PIN_SERIAL1_RX GPS_RX_PIN #define PIN_SERIAL1_RX PIN_GPS_RX
#define PIN_GPS_STANDBY D0 #define PIN_GPS_STANDBY D0
#define GPS_EN D18 // P1.05 #define GPS_EN D18 // P1.05
#endif #endif
@@ -119,14 +119,16 @@ static const uint8_t SCL = PIN_WIRE_SCL;
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
#define GPS_L76K #define GPS_L76K
#ifdef GPS_L76K #ifdef GPS_L76K
#define GPS_TX_PIN D6 // P0.26 - This is data from the MCU #define PIN_GPS_RX D6 // P0.26
#define GPS_RX_PIN D7 // P0.27 - This is data from the GNSS #define PIN_GPS_TX D7
#define HAS_GPS 1 #define HAS_GPS 1
#define GPS_BAUDRATE 9600 #define GPS_BAUDRATE 9600
#define GPS_THREAD_INTERVAL 50 #define GPS_THREAD_INTERVAL 50
#define PIN_SERIAL1_RX GPS_RX_PIN #define PIN_SERIAL1_RX PIN_GPS_TX
#define PIN_SERIAL1_TX GPS_TX_PIN #define PIN_SERIAL1_TX PIN_GPS_RX
#define GPS_RX_PIN PIN_GPS_TX
#define GPS_TX_PIN PIN_GPS_RX
#define PIN_GPS_STANDBY D0 #define PIN_GPS_STANDBY D0
// #define GPS_DEBUG // #define GPS_DEBUG
@@ -129,14 +129,16 @@ static const uint8_t SCL = PIN_WIRE_SCL;
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
#define GPS_L76K #define GPS_L76K
#ifdef GPS_L76K #ifdef GPS_L76K
#define GPS_TX_PIN D6 // P0.26 - This is data from the MCU #define PIN_GPS_RX D6 // P0.26
#define GPS_RX_PIN D7 // P0.27 - This is data from the GNSS #define PIN_GPS_TX D7
#define HAS_GPS 1 #define HAS_GPS 1
#define GPS_BAUDRATE 9600 #define GPS_BAUDRATE 9600
#define GPS_THREAD_INTERVAL 50 #define GPS_THREAD_INTERVAL 50
#define PIN_SERIAL1_RX GPS_RX_PIN #define PIN_SERIAL1_RX PIN_GPS_TX
#define PIN_SERIAL1_TX GPS_TX_PIN #define PIN_SERIAL1_TX PIN_GPS_RX
#define GPS_RX_PIN PIN_GPS_TX
#define GPS_TX_PIN PIN_GPS_RX
#define PIN_GPS_STANDBY D0 #define PIN_GPS_STANDBY D0
// #define GPS_DEBUG // #define GPS_DEBUG
@@ -147,12 +147,12 @@ static const uint8_t SCK = PIN_SPI_SCK;
*/ */
// GPS L76K // GPS L76K
#ifdef GPS_L76K #ifdef GPS_L76K
#define GPS_TX_PIN D6 // This is data from the MCU #define PIN_GPS_TX D6
#define GPS_RX_PIN D7 // This is data from the GNSS module #define PIN_GPS_RX D7
#define HAS_GPS 1 #define HAS_GPS 1
#define GPS_THREAD_INTERVAL 50 #define GPS_THREAD_INTERVAL 50
#define PIN_SERIAL1_TX GPS_TX_PIN #define PIN_SERIAL1_TX PIN_GPS_TX
#define PIN_SERIAL1_RX GPS_RX_PIN #define PIN_SERIAL1_RX PIN_GPS_RX
#define PIN_GPS_STANDBY D0 #define PIN_GPS_STANDBY D0
#else #else
#define PIN_SERIAL1_RX (-1) #define PIN_SERIAL1_RX (-1)
@@ -1,7 +1,6 @@
[env:feather_rp2040_rfm95] [env:feather_rp2040_rfm95]
extends = rp2040_base extends = rp2040_base
board = adafruit_feather board = adafruit_feather
board_level = extra
upload_protocol = picotool upload_protocol = picotool
# add our variants files to the include and src paths # add our variants files to the include and src paths
build_flags = build_flags =
+3 -4
View File
@@ -2,12 +2,12 @@
[rp2040_base] [rp2040_base]
platform = platform =
# TODO renovate # TODO renovate
https://github.com/maxgerhardt/platform-raspberrypi#cc24cfef37ed22ca9f2a6aead28c2deb76c39f24 https://github.com/maxgerhardt/platform-raspberrypi#76ecf3c7e9dd4503af0331154c4ca1cddc4b03e5
; For arduino-pico >= 5.4.4 ; For arduino-pico >= 4.4.3
extends = arduino_base extends = arduino_base
platform_packages = platform_packages =
# TODO renovate # TODO renovate
arduino-pico@https://github.com/earlephilhower/arduino-pico/releases/download/5.4.4/rp2040-5.4.4.zip framework-arduinopico@https://github.com/earlephilhower/arduino-pico#4.4.3
board_build.core = earlephilhower board_build.core = earlephilhower
board_build.filesystem_size = 0.5m board_build.filesystem_size = 0.5m
@@ -17,7 +17,6 @@ build_flags =
-Isrc/platform/rp2xx0/hardware_rosc/include -Isrc/platform/rp2xx0/hardware_rosc/include
-Isrc/platform/rp2xx0/pico_sleep/include -Isrc/platform/rp2xx0/pico_sleep/include
-D__PLAT_RP2040__ -D__PLAT_RP2040__
-D__FREERTOS=1
# -D _POSIX_THREADS # -D _POSIX_THREADS
build_src_filter = build_src_filter =
${arduino_base.build_src_filter} -<platform/esp32/> -<nimble/> -<modules/esp32> -<platform/nrf52/> -<platform/stm32wl> -<mesh/eth/> -<mesh/wifi/> -<mesh/http/> -<mesh/raspihttp> ${arduino_base.build_src_filter} -<platform/esp32/> -<nimble/> -<modules/esp32> -<platform/nrf52/> -<platform/stm32wl> -<mesh/eth/> -<mesh/wifi/> -<mesh/http/> -<mesh/raspihttp>
+3 -4
View File
@@ -2,12 +2,12 @@
[rp2350_base] [rp2350_base]
platform = platform =
# TODO renovate # TODO renovate
https://github.com/maxgerhardt/platform-raspberrypi#cc24cfef37ed22ca9f2a6aead28c2deb76c39f24 https://github.com/maxgerhardt/platform-raspberrypi#76ecf3c7e9dd4503af0331154c4ca1cddc4b03e5
; For arduino-pico >= 5.4.4 ; For arduino-pico >= 4.4.3
extends = arduino_base extends = arduino_base
platform_packages = platform_packages =
# TODO renovate # TODO renovate
arduino-pico@https://github.com/earlephilhower/arduino-pico/releases/download/5.4.4/rp2040-5.4.4.zip framework-arduinopico@https://github.com/earlephilhower/arduino-pico#4.4.3
board_build.core = earlephilhower board_build.core = earlephilhower
board_build.filesystem_size = 0.5m board_build.filesystem_size = 0.5m
@@ -15,7 +15,6 @@ build_flags =
${arduino_base.build_flags} -Wno-unused-variable -Wcast-align ${arduino_base.build_flags} -Wno-unused-variable -Wcast-align
-Isrc/platform/rp2xx0 -Isrc/platform/rp2xx0
-D__PLAT_RP2350__ -D__PLAT_RP2350__
-D__FREERTOS=1
build_src_filter = build_src_filter =
${arduino_base.build_src_filter} -<platform/esp32/> -<nimble/> -<modules/esp32> -<platform/nrf52/> -<platform/stm32wl> -<mesh/eth/> -<mesh/wifi/> -<mesh/http/> -<mesh/raspihttp> -<platform/rp2xx0/pico_sleep> -<platform/rp2xx0/hardware_rosc> ${arduino_base.build_src_filter} -<platform/esp32/> -<nimble/> -<modules/esp32> -<platform/nrf52/> -<platform/stm32wl> -<mesh/eth/> -<mesh/wifi/> -<mesh/http/> -<mesh/raspihttp> -<platform/rp2xx0/pico_sleep> -<platform/rp2xx0/hardware_rosc>