mirror of
https://github.com/meshtastic/firmware.git
synced 2025-12-19 09:12:45 +00:00
Compare commits
10 Commits
trunk-io/u
...
refactor-n
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
90e2083d2c | ||
|
|
af1d4e08ff | ||
|
|
d772cd4431 | ||
|
|
b7b8071056 | ||
|
|
4a3d28f06b | ||
|
|
0f4210d2e8 | ||
|
|
dc6e109329 | ||
|
|
10141b2562 | ||
|
|
770085ddf7 | ||
|
|
833f950edc |
4
.github/actions/build-variant/action.yml
vendored
4
.github/actions/build-variant/action.yml
vendored
@@ -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
|
||||||
|
|||||||
2
.github/workflows/build_debian_src.yml
vendored
2
.github/workflows/build_debian_src.yml
vendored
@@ -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
|
||||||
|
|||||||
2
.github/workflows/build_firmware.yml
vendored
2
.github/workflows/build_firmware.yml
vendored
@@ -68,7 +68,7 @@ jobs:
|
|||||||
echo '```' >> $GITHUB_STEP_SUMMARY
|
echo '```' >> $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 }}
|
||||||
|
|||||||
8
.github/workflows/build_one_target.yml
vendored
8
.github/workflows/build_one_target.yml
vendored
@@ -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
|
||||||
|
|||||||
39
.github/workflows/main_matrix.yml
vendored
39
.github/workflows/main_matrix.yml
vendored
@@ -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
|
||||||
|
|||||||
18
.github/workflows/merge_queue.yml
vendored
18
.github/workflows/merge_queue.yml
vendored
@@ -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
|
||||||
|
|||||||
2
.github/workflows/package_obs.yml
vendored
2
.github/workflows/package_obs.yml
vendored
@@ -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
|
||||||
|
|||||||
2
.github/workflows/package_pio_deps.yml
vendored
2
.github/workflows/package_pio_deps.yml
vendored
@@ -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
|
||||||
|
|||||||
2
.github/workflows/package_ppa.yml
vendored
2
.github/workflows/package_ppa.yml
vendored
@@ -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
|
||||||
|
|||||||
2
.github/workflows/pr_tests.yml
vendored
2
.github/workflows/pr_tests.yml
vendored
@@ -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
|
||||||
|
|||||||
2
.github/workflows/release_channels.yml
vendored
2
.github/workflows/release_channels.yml
vendored
@@ -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
|
||||||
|
|||||||
2
.github/workflows/sec_sast_semgrep_cron.yml
vendored
2
.github/workflows/sec_sast_semgrep_cron.yml
vendored
@@ -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
|
||||||
|
|||||||
12
.github/workflows/test_native.yml
vendored
12
.github/workflows/test_native.yml
vendored
@@ -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,7 +137,7 @@ 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
|
||||||
@@ -150,7 +150,7 @@ jobs:
|
|||||||
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
|
||||||
|
|||||||
2
.github/workflows/update_protobufs.yml
vendored
2
.github/workflows/update_protobufs.yml
vendored
@@ -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,24 +9,24 @@ plugins:
|
|||||||
lint:
|
lint:
|
||||||
enabled:
|
enabled:
|
||||||
- checkov@3.2.495
|
- checkov@3.2.495
|
||||||
- renovate@42.64.1
|
- renovate@42.30.4
|
||||||
- prettier@3.7.4
|
- prettier@3.7.4
|
||||||
- trufflehog@3.92.3
|
- 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.9
|
- 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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
@@ -47,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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -159,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,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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')}")
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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/862ed040c4ab44f0dfbbe492691f144886102588.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]
|
||||||
|
|||||||
Submodule protobufs updated: 9beb80f1d3...4095e59890
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
@@ -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);
|
||||||
@@ -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 ===
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -53,7 +53,6 @@ typedef struct _InputEvent {
|
|||||||
class InputPollable
|
class InputPollable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~InputPollable() = default;
|
|
||||||
virtual void pollOnce() = 0;
|
virtual void pollOnce() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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(¬ifyLightSleep);
|
|
||||||
lsEndObserver.observe(¬ifyLightSleepEnd);
|
|
||||||
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
|
||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
@@ -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,15 +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)
|
||||||
// Default to PIN_LED2 for external notification output (LED color depends on device variant)
|
// Default to RAK led pin 2 (blue)
|
||||||
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;
|
||||||
@@ -908,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();
|
||||||
@@ -994,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;
|
||||||
@@ -1017,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)
|
||||||
@@ -1033,16 +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);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeDB::cleanupMeshDB()
|
void NodeDB::cleanupMeshDB()
|
||||||
@@ -1118,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)
|
||||||
@@ -1132,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
|
||||||
@@ -1264,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.
|
||||||
@@ -1315,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),
|
||||||
@@ -1367,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
|
||||||
@@ -1378,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
|
||||||
@@ -1494,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);
|
||||||
@@ -1518,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,7 +1491,7 @@ uint32_t sinceReceived(const meshtastic_MeshPacket *p)
|
|||||||
|
|
||||||
#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;
|
||||||
|
|
||||||
@@ -1571,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1581,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
|
||||||
@@ -1608,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
|
||||||
@@ -1616,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1631,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1639,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
|
||||||
@@ -1649,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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1692,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
|
||||||
@@ -1724,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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1731,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!");
|
||||||
@@ -1758,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1778,107 +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
|
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
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()
|
||||||
@@ -1913,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1929,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)
|
||||||
@@ -1939,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);
|
||||||
}
|
}
|
||||||
@@ -1947,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()) {
|
||||||
@@ -2002,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)
|
||||||
@@ -2035,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
|
||||||
@@ -2068,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) {
|
||||||
@@ -2080,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();
|
||||||
@@ -2105,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 {
|
||||||
@@ -2117,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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,19 +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);
|
||||||
|
|
||||||
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
|
||||||
@@ -135,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;
|
||||||
@@ -151,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
|
||||||
@@ -208,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);
|
||||||
@@ -227,79 +235,104 @@ 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasValidPosition(const meshtastic_NodeInfoLite *n);
|
bool hasValidPosition(const meshtastic_NodeInfoLite *n);
|
||||||
|
|
||||||
#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;
|
||||||
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
|
||||||
@@ -333,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;
|
||||||
|
|||||||
@@ -503,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;
|
||||||
@@ -544,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
|
||||||
|
|||||||
@@ -150,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);
|
||||||
|
|||||||
@@ -526,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;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -1322,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)
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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)
|
||||||
@@ -476,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()
|
||||||
|
|||||||
@@ -75,12 +75,6 @@ uint8_t RoutingModule::getHopLimitForResponse(uint8_t hopStart, uint8_t hopLimit
|
|||||||
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;
|
||||||
|
|||||||
@@ -16,9 +16,6 @@ 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(uint8_t hopStart, uint8_t hopLimit);
|
uint8_t getHopLimitForResponse(uint8_t hopStart, uint8_t hopLimit);
|
||||||
|
|
||||||
|
|||||||
@@ -26,11 +26,7 @@ int StatusLEDModule::handleStatusUpdate(const meshtastic::Status *arg)
|
|||||||
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) {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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)) {
|
||||||
|
|||||||
@@ -14,11 +14,11 @@
|
|||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
|
#ifdef NIMBLE_TWO
|
||||||
#include "NimBLEAdvertising.h"
|
#include "NimBLEAdvertising.h"
|
||||||
#ifdef CONFIG_BT_NIMBLE_EXT_ADV
|
|
||||||
#include "NimBLEExtAdvertising.h"
|
#include "NimBLEExtAdvertising.h"
|
||||||
#endif
|
|
||||||
#include "PowerStatus.h"
|
#include "PowerStatus.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(CONFIG_NIMBLE_CPP_IDF)
|
#if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||||
#include "host/ble_gap.h"
|
#include "host/ble_gap.h"
|
||||||
@@ -26,12 +26,15 @@
|
|||||||
#include "nimble/nimble/host/include/host/ble_gap.h"
|
#include "nimble/nimble/host/include/host/ble_gap.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C6)
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
constexpr uint16_t kPreferredBleMtu = 517;
|
constexpr uint16_t kPreferredBleMtu = 517;
|
||||||
constexpr uint16_t kPreferredBleTxOctets = 251;
|
constexpr uint16_t kPreferredBleTxOctets = 251;
|
||||||
constexpr uint16_t kPreferredBleTxTimeUs = (kPreferredBleTxOctets + 14) * 8;
|
constexpr uint16_t kPreferredBleTxTimeUs = (kPreferredBleTxOctets + 14) * 8;
|
||||||
} // namespace
|
} // namespace
|
||||||
|
#endif
|
||||||
|
|
||||||
// Debugging options: careful, they slow things down quite a bit!
|
// Debugging options: careful, they slow things down quite a bit!
|
||||||
// #define DEBUG_NIMBLE_ON_READ_TIMING // uncomment to time onRead duration
|
// #define DEBUG_NIMBLE_ON_READ_TIMING // uncomment to time onRead duration
|
||||||
@@ -310,9 +313,11 @@ class BluetoothPhoneAPI : public PhoneAPI, public concurrency::OSThread
|
|||||||
{
|
{
|
||||||
PhoneAPI::onNowHasData(fromRadioNum);
|
PhoneAPI::onNowHasData(fromRadioNum);
|
||||||
|
|
||||||
#ifdef DEBUG_NIMBLE_NOTIFY
|
|
||||||
int currentNotifyCount = notifyCount.fetch_add(1);
|
int currentNotifyCount = notifyCount.fetch_add(1);
|
||||||
|
|
||||||
uint8_t cc = bleServer->getConnectedCount();
|
uint8_t cc = bleServer->getConnectedCount();
|
||||||
|
|
||||||
|
#ifdef DEBUG_NIMBLE_NOTIFY
|
||||||
// This logging slows things down when there are lots of packets going to the phone, like initial connection:
|
// This logging slows things down when there are lots of packets going to the phone, like initial connection:
|
||||||
LOG_DEBUG("BLE notify(%d) fromNum: %d connections: %d", currentNotifyCount, fromRadioNum, cc);
|
LOG_DEBUG("BLE notify(%d) fromNum: %d connections: %d", currentNotifyCount, fromRadioNum, cc);
|
||||||
#endif
|
#endif
|
||||||
@@ -321,7 +326,13 @@ class BluetoothPhoneAPI : public PhoneAPI, public concurrency::OSThread
|
|||||||
put_le32(val, fromRadioNum);
|
put_le32(val, fromRadioNum);
|
||||||
|
|
||||||
fromNumCharacteristic->setValue(val, sizeof(val));
|
fromNumCharacteristic->setValue(val, sizeof(val));
|
||||||
|
#ifdef NIMBLE_TWO
|
||||||
|
// NOTE: I don't have any NIMBLE_TWO devices, but this line makes me suspicious, and I suspect it needs to just be
|
||||||
|
// notify().
|
||||||
fromNumCharacteristic->notify(val, sizeof(val), BLE_HS_CONN_HANDLE_NONE);
|
fromNumCharacteristic->notify(val, sizeof(val), BLE_HS_CONN_HANDLE_NONE);
|
||||||
|
#else
|
||||||
|
fromNumCharacteristic->notify();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check the current underlying physical link to see if the client is currently connected
|
/// Check the current underlying physical link to see if the client is currently connected
|
||||||
@@ -386,7 +397,12 @@ static uint8_t lastToRadio[MAX_TO_FROM_RADIO_SIZE];
|
|||||||
|
|
||||||
class NimbleBluetoothToRadioCallback : public NimBLECharacteristicCallbacks
|
class NimbleBluetoothToRadioCallback : public NimBLECharacteristicCallbacks
|
||||||
{
|
{
|
||||||
void onWrite(NimBLECharacteristic *pCharacteristic, NimBLEConnInfo &) override
|
#ifdef NIMBLE_TWO
|
||||||
|
virtual void onWrite(NimBLECharacteristic *pCharacteristic, NimBLEConnInfo &connInfo)
|
||||||
|
#else
|
||||||
|
virtual void onWrite(NimBLECharacteristic *pCharacteristic)
|
||||||
|
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
// CAUTION: This callback runs in the NimBLE task!!! Don't do anything except communicate with the main task's runOnce.
|
// CAUTION: This callback runs in the NimBLE task!!! Don't do anything except communicate with the main task's runOnce.
|
||||||
// Assumption: onWrite is serialized by NimBLE, so we don't need to lock here against multiple concurrent onWrite calls.
|
// Assumption: onWrite is serialized by NimBLE, so we don't need to lock here against multiple concurrent onWrite calls.
|
||||||
@@ -433,7 +449,11 @@ class NimbleBluetoothToRadioCallback : public NimBLECharacteristicCallbacks
|
|||||||
|
|
||||||
class NimbleBluetoothFromRadioCallback : public NimBLECharacteristicCallbacks
|
class NimbleBluetoothFromRadioCallback : public NimBLECharacteristicCallbacks
|
||||||
{
|
{
|
||||||
void onRead(NimBLECharacteristic *pCharacteristic, NimBLEConnInfo &) override
|
#ifdef NIMBLE_TWO
|
||||||
|
virtual void onRead(NimBLECharacteristic *pCharacteristic, NimBLEConnInfo &connInfo)
|
||||||
|
#else
|
||||||
|
virtual void onRead(NimBLECharacteristic *pCharacteristic)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
// CAUTION: This callback runs in the NimBLE task!!! Don't do anything except communicate with the main task's runOnce.
|
// CAUTION: This callback runs in the NimBLE task!!! Don't do anything except communicate with the main task's runOnce.
|
||||||
|
|
||||||
@@ -541,27 +561,32 @@ class NimbleBluetoothFromRadioCallback : public NimBLECharacteristicCallbacks
|
|||||||
|
|
||||||
class NimbleBluetoothServerCallback : public NimBLEServerCallbacks
|
class NimbleBluetoothServerCallback : public NimBLEServerCallbacks
|
||||||
{
|
{
|
||||||
|
#ifdef NIMBLE_TWO
|
||||||
public:
|
public:
|
||||||
explicit NimbleBluetoothServerCallback(NimbleBluetooth *ble) : ble(ble) {}
|
NimbleBluetoothServerCallback(NimbleBluetooth *ble) { this->ble = ble; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NimbleBluetooth *ble;
|
NimbleBluetooth *ble;
|
||||||
|
|
||||||
uint32_t onPassKeyDisplay() override
|
virtual uint32_t onPassKeyDisplay()
|
||||||
|
#else
|
||||||
|
virtual uint32_t onPassKeyRequest()
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
uint32_t passkey = config.bluetooth.fixed_pin;
|
uint32_t passkey = config.bluetooth.fixed_pin;
|
||||||
|
|
||||||
if (config.bluetooth.mode == meshtastic_Config_BluetoothConfig_PairingMode_RANDOM_PIN) {
|
if (config.bluetooth.mode == meshtastic_Config_BluetoothConfig_PairingMode_RANDOM_PIN) {
|
||||||
LOG_INFO("Use random passkey");
|
LOG_INFO("Use random passkey");
|
||||||
|
// This is the passkey to be entered on peer - we pick a number >100,000 to ensure 6 digits
|
||||||
passkey = random(100000, 999999);
|
passkey = random(100000, 999999);
|
||||||
}
|
}
|
||||||
LOG_INFO("*** Enter passkey %06u on the peer side ***", passkey);
|
LOG_INFO("*** Enter passkey %d on the peer side ***", passkey);
|
||||||
|
|
||||||
powerFSM.trigger(EVENT_BLUETOOTH_PAIR);
|
powerFSM.trigger(EVENT_BLUETOOTH_PAIR);
|
||||||
meshtastic::BluetoothStatus newStatus(std::to_string(passkey));
|
meshtastic::BluetoothStatus newStatus(std::to_string(passkey));
|
||||||
bluetoothStatus->updateStatus(&newStatus);
|
bluetoothStatus->updateStatus(&newStatus);
|
||||||
|
|
||||||
#if HAS_SCREEN
|
#if HAS_SCREEN // Todo: migrate this display code back into Screen class, and observe bluetoothStatus
|
||||||
if (screen) {
|
if (screen) {
|
||||||
screen->startAlert([passkey](OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -> void {
|
screen->startAlert([passkey](OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -> void {
|
||||||
char btPIN[16] = "888888";
|
char btPIN[16] = "888888";
|
||||||
@@ -590,29 +615,39 @@ class NimbleBluetoothServerCallback : public NimBLEServerCallbacks
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
passkeyShowing = true;
|
passkeyShowing = true;
|
||||||
|
|
||||||
return passkey;
|
return passkey;
|
||||||
}
|
}
|
||||||
|
|
||||||
void onAuthenticationComplete(NimBLEConnInfo &connInfo) override
|
#ifdef NIMBLE_TWO
|
||||||
|
virtual void onAuthenticationComplete(NimBLEConnInfo &connInfo)
|
||||||
|
#else
|
||||||
|
virtual void onAuthenticationComplete(ble_gap_conn_desc *desc)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
LOG_INFO("BLE authentication complete");
|
LOG_INFO("BLE authentication complete");
|
||||||
|
|
||||||
meshtastic::BluetoothStatus newStatus(meshtastic::BluetoothStatus::ConnectionState::CONNECTED);
|
meshtastic::BluetoothStatus newStatus(meshtastic::BluetoothStatus::ConnectionState::CONNECTED);
|
||||||
bluetoothStatus->updateStatus(&newStatus);
|
bluetoothStatus->updateStatus(&newStatus);
|
||||||
|
|
||||||
|
// Todo: migrate this display code back into Screen class, and observe bluetoothStatus
|
||||||
if (passkeyShowing) {
|
if (passkeyShowing) {
|
||||||
passkeyShowing = false;
|
passkeyShowing = false;
|
||||||
if (screen) {
|
if (screen)
|
||||||
screen->endAlert();
|
screen->endAlert();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Store the connection handle for future use
|
||||||
|
#ifdef NIMBLE_TWO
|
||||||
nimbleBluetoothConnHandle = connInfo.getConnHandle();
|
nimbleBluetoothConnHandle = connInfo.getConnHandle();
|
||||||
|
#else
|
||||||
|
nimbleBluetoothConnHandle = desc->conn_handle;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void onConnect(NimBLEServer *pServer, NimBLEConnInfo &connInfo) override
|
#ifdef NIMBLE_TWO
|
||||||
|
virtual void onConnect(NimBLEServer *pServer, NimBLEConnInfo &connInfo)
|
||||||
{
|
{
|
||||||
LOG_INFO("BLE incoming connection %s", connInfo.getAddress().toString().c_str());
|
LOG_INFO("BLE incoming connection %s", connInfo.getAddress().toString().c_str());
|
||||||
|
|
||||||
@@ -637,12 +672,21 @@ class NimbleBluetoothServerCallback : public NimBLEServerCallbacks
|
|||||||
LOG_INFO("BLE conn %u initial MTU %u (target %u)", connHandle, connInfo.getMTU(), kPreferredBleMtu);
|
LOG_INFO("BLE conn %u initial MTU %u (target %u)", connHandle, connInfo.getMTU(), kPreferredBleMtu);
|
||||||
pServer->updateConnParams(connHandle, 6, 12, 0, 200);
|
pServer->updateConnParams(connHandle, 6, 12, 0, 200);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void onDisconnect(NimBLEServer *pServer, NimBLEConnInfo &connInfo, int reason) override
|
#ifdef NIMBLE_TWO
|
||||||
|
virtual void onDisconnect(NimBLEServer *pServer, NimBLEConnInfo &connInfo, int reason)
|
||||||
{
|
{
|
||||||
LOG_INFO("BLE disconnect reason: %d", reason);
|
LOG_INFO("BLE disconnect reason: %d", reason);
|
||||||
|
#else
|
||||||
|
virtual void onDisconnect(NimBLEServer *pServer, ble_gap_conn_desc *desc)
|
||||||
|
{
|
||||||
|
LOG_INFO("BLE disconnect");
|
||||||
|
#endif
|
||||||
|
#ifdef NIMBLE_TWO
|
||||||
if (ble->isDeInit)
|
if (ble->isDeInit)
|
||||||
return;
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
meshtastic::BluetoothStatus newStatus(meshtastic::BluetoothStatus::ConnectionState::DISCONNECTED);
|
meshtastic::BluetoothStatus newStatus(meshtastic::BluetoothStatus::ConnectionState::DISCONNECTED);
|
||||||
bluetoothStatus->updateStatus(&newStatus);
|
bluetoothStatus->updateStatus(&newStatus);
|
||||||
@@ -666,69 +710,35 @@ class NimbleBluetoothServerCallback : public NimBLEServerCallbacks
|
|||||||
bluetoothPhoneAPI->writeCount = 0;
|
bluetoothPhoneAPI->writeCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clear the last ToRadio packet buffer to avoid rejecting first packet from new connection
|
||||||
memset(lastToRadio, 0, sizeof(lastToRadio));
|
memset(lastToRadio, 0, sizeof(lastToRadio));
|
||||||
|
|
||||||
nimbleBluetoothConnHandle = BLE_HS_CONN_HANDLE_NONE;
|
nimbleBluetoothConnHandle = BLE_HS_CONN_HANDLE_NONE; // BLE_HS_CONN_HANDLE_NONE means "no connection"
|
||||||
|
|
||||||
|
#ifdef NIMBLE_TWO
|
||||||
|
// Restart Advertising
|
||||||
ble->startAdvertising();
|
ble->startAdvertising();
|
||||||
|
#else
|
||||||
|
NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising();
|
||||||
|
if (!pAdvertising->start(0)) {
|
||||||
|
if (pAdvertising->isAdvertising()) {
|
||||||
|
LOG_DEBUG("BLE advertising already running");
|
||||||
|
} else {
|
||||||
|
LOG_ERROR("BLE failed to restart advertising");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static NimbleBluetoothToRadioCallback *toRadioCallbacks;
|
static NimbleBluetoothToRadioCallback *toRadioCallbacks;
|
||||||
static NimbleBluetoothFromRadioCallback *fromRadioCallbacks;
|
static NimbleBluetoothFromRadioCallback *fromRadioCallbacks;
|
||||||
|
|
||||||
void NimbleBluetooth::startAdvertising()
|
|
||||||
{
|
|
||||||
#if defined(CONFIG_BT_NIMBLE_EXT_ADV)
|
|
||||||
NimBLEExtAdvertising *pAdvertising = NimBLEDevice::getAdvertising();
|
|
||||||
NimBLEExtAdvertisement legacyAdvertising;
|
|
||||||
|
|
||||||
legacyAdvertising.setLegacyAdvertising(true);
|
|
||||||
legacyAdvertising.setScannable(true);
|
|
||||||
legacyAdvertising.setConnectable(true);
|
|
||||||
legacyAdvertising.setFlags(BLE_HS_ADV_F_DISC_GEN);
|
|
||||||
if (powerStatus->getHasBattery() == 1) {
|
|
||||||
legacyAdvertising.setCompleteServices(NimBLEUUID((uint16_t)0x180f));
|
|
||||||
}
|
|
||||||
legacyAdvertising.setCompleteServices(NimBLEUUID(MESH_SERVICE_UUID));
|
|
||||||
legacyAdvertising.setMinInterval(500);
|
|
||||||
legacyAdvertising.setMaxInterval(1000);
|
|
||||||
|
|
||||||
NimBLEExtAdvertisement legacyScanResponse;
|
|
||||||
legacyScanResponse.setLegacyAdvertising(true);
|
|
||||||
legacyScanResponse.setConnectable(true);
|
|
||||||
legacyScanResponse.setName(getDeviceName());
|
|
||||||
|
|
||||||
if (!pAdvertising->setInstanceData(0, legacyAdvertising)) {
|
|
||||||
LOG_ERROR("BLE failed to set legacyAdvertising");
|
|
||||||
} else if (!pAdvertising->setScanResponseData(0, legacyScanResponse)) {
|
|
||||||
LOG_ERROR("BLE failed to set legacyScanResponse");
|
|
||||||
} else if (!pAdvertising->start(0, 0, 0)) {
|
|
||||||
LOG_ERROR("BLE failed to start legacyAdvertising");
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising();
|
|
||||||
pAdvertising->reset();
|
|
||||||
pAdvertising->addServiceUUID(MESH_SERVICE_UUID);
|
|
||||||
if (powerStatus->getHasBattery() == 1) {
|
|
||||||
pAdvertising->addServiceUUID(NimBLEUUID((uint16_t)0x180f));
|
|
||||||
}
|
|
||||||
|
|
||||||
NimBLEAdvertisementData scan;
|
|
||||||
scan.setName(getDeviceName());
|
|
||||||
pAdvertising->setScanResponseData(scan);
|
|
||||||
pAdvertising->enableScanResponse(true);
|
|
||||||
|
|
||||||
if (!pAdvertising->start(0)) {
|
|
||||||
LOG_ERROR("BLE failed to start advertising");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
LOG_DEBUG("BLE Advertising started");
|
|
||||||
}
|
|
||||||
|
|
||||||
void NimbleBluetooth::shutdown()
|
void NimbleBluetooth::shutdown()
|
||||||
{
|
{
|
||||||
|
// No measurable power saving for ESP32 during light-sleep(?)
|
||||||
#ifndef ARCH_ESP32
|
#ifndef ARCH_ESP32
|
||||||
|
// Shutdown bluetooth for minimum power draw
|
||||||
LOG_INFO("Disable bluetooth");
|
LOG_INFO("Disable bluetooth");
|
||||||
NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising();
|
NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising();
|
||||||
pAdvertising->reset();
|
pAdvertising->reset();
|
||||||
@@ -736,6 +746,7 @@ void NimbleBluetooth::shutdown()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Proper shutdown for ESP32. Needs reboot to reverse.
|
||||||
void NimbleBluetooth::deinit()
|
void NimbleBluetooth::deinit()
|
||||||
{
|
{
|
||||||
#ifdef ARCH_ESP32
|
#ifdef ARCH_ESP32
|
||||||
@@ -749,17 +760,21 @@ void NimbleBluetooth::deinit()
|
|||||||
digitalWrite(BLE_LED, LOW);
|
digitalWrite(BLE_LED, LOW);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef NIMBLE_TWO
|
||||||
|
NimBLEDevice::deinit();
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Has initial setup been completed
|
||||||
bool NimbleBluetooth::isActive()
|
bool NimbleBluetooth::isActive()
|
||||||
{
|
{
|
||||||
return bleServer != nullptr;
|
return bleServer;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NimbleBluetooth::isConnected()
|
bool NimbleBluetooth::isConnected()
|
||||||
{
|
{
|
||||||
return bleServer && bleServer->getConnectedCount() > 0;
|
return bleServer->getConnectedCount() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int NimbleBluetooth::getRssi()
|
int NimbleBluetooth::getRssi()
|
||||||
@@ -803,7 +818,7 @@ void NimbleBluetooth::setup()
|
|||||||
LOG_INFO("Init the NimBLE bluetooth module");
|
LOG_INFO("Init the NimBLE bluetooth module");
|
||||||
|
|
||||||
NimBLEDevice::init(getDeviceName());
|
NimBLEDevice::init(getDeviceName());
|
||||||
NimBLEDevice::setPower(9);
|
NimBLEDevice::setPower(ESP_PWR_LVL_P9);
|
||||||
|
|
||||||
#if NIMBLE_ENABLE_2M_PHY && (defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C6))
|
#if NIMBLE_ENABLE_2M_PHY && (defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C6))
|
||||||
int mtuResult = NimBLEDevice::setMTU(kPreferredBleMtu);
|
int mtuResult = NimBLEDevice::setMTU(kPreferredBleMtu);
|
||||||
@@ -836,7 +851,11 @@ void NimbleBluetooth::setup()
|
|||||||
NimBLEDevice::setSecurityIOCap(BLE_HS_IO_DISPLAY_ONLY);
|
NimBLEDevice::setSecurityIOCap(BLE_HS_IO_DISPLAY_ONLY);
|
||||||
}
|
}
|
||||||
bleServer = NimBLEDevice::createServer();
|
bleServer = NimBLEDevice::createServer();
|
||||||
auto *serverCallbacks = new NimbleBluetoothServerCallback(this);
|
#ifdef NIMBLE_TWO
|
||||||
|
NimbleBluetoothServerCallback *serverCallbacks = new NimbleBluetoothServerCallback(this);
|
||||||
|
#else
|
||||||
|
NimbleBluetoothServerCallback *serverCallbacks = new NimbleBluetoothServerCallback();
|
||||||
|
#endif
|
||||||
bleServer->setCallbacks(serverCallbacks, true);
|
bleServer->setCallbacks(serverCallbacks, true);
|
||||||
setupService();
|
setupService();
|
||||||
startAdvertising();
|
startAdvertising();
|
||||||
@@ -881,7 +900,11 @@ void NimbleBluetooth::setupService()
|
|||||||
NimBLEService *batteryService = bleServer->createService(NimBLEUUID((uint16_t)0x180f)); // 0x180F is the Battery Service
|
NimBLEService *batteryService = bleServer->createService(NimBLEUUID((uint16_t)0x180f)); // 0x180F is the Battery Service
|
||||||
BatteryCharacteristic = batteryService->createCharacteristic( // 0x2A19 is the Battery Level characteristic)
|
BatteryCharacteristic = batteryService->createCharacteristic( // 0x2A19 is the Battery Level characteristic)
|
||||||
(uint16_t)0x2a19, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::NOTIFY, 1);
|
(uint16_t)0x2a19, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::NOTIFY, 1);
|
||||||
|
#ifdef NIMBLE_TWO
|
||||||
NimBLE2904 *batteryLevelDescriptor = BatteryCharacteristic->create2904();
|
NimBLE2904 *batteryLevelDescriptor = BatteryCharacteristic->create2904();
|
||||||
|
#else
|
||||||
|
NimBLE2904 *batteryLevelDescriptor = (NimBLE2904 *)BatteryCharacteristic->createDescriptor((uint16_t)0x2904);
|
||||||
|
#endif
|
||||||
batteryLevelDescriptor->setFormat(NimBLE2904::FORMAT_UINT8);
|
batteryLevelDescriptor->setFormat(NimBLE2904::FORMAT_UINT8);
|
||||||
batteryLevelDescriptor->setNamespace(1);
|
batteryLevelDescriptor->setNamespace(1);
|
||||||
batteryLevelDescriptor->setUnit(0x27ad);
|
batteryLevelDescriptor->setUnit(0x27ad);
|
||||||
@@ -889,12 +912,54 @@ void NimbleBluetooth::setupService()
|
|||||||
batteryService->start();
|
batteryService->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NimbleBluetooth::startAdvertising()
|
||||||
|
{
|
||||||
|
#ifdef NIMBLE_TWO
|
||||||
|
NimBLEExtAdvertising *pAdvertising = NimBLEDevice::getAdvertising();
|
||||||
|
NimBLEExtAdvertisement legacyAdvertising;
|
||||||
|
|
||||||
|
legacyAdvertising.setLegacyAdvertising(true);
|
||||||
|
legacyAdvertising.setScannable(true);
|
||||||
|
legacyAdvertising.setConnectable(true);
|
||||||
|
legacyAdvertising.setFlags(BLE_HS_ADV_F_DISC_GEN);
|
||||||
|
if (powerStatus->getHasBattery() == 1) {
|
||||||
|
legacyAdvertising.setCompleteServices(NimBLEUUID((uint16_t)0x180f));
|
||||||
|
}
|
||||||
|
legacyAdvertising.setCompleteServices(NimBLEUUID(MESH_SERVICE_UUID));
|
||||||
|
legacyAdvertising.setMinInterval(500);
|
||||||
|
legacyAdvertising.setMaxInterval(1000);
|
||||||
|
|
||||||
|
NimBLEExtAdvertisement legacyScanResponse;
|
||||||
|
legacyScanResponse.setLegacyAdvertising(true);
|
||||||
|
legacyScanResponse.setConnectable(true);
|
||||||
|
legacyScanResponse.setName(getDeviceName());
|
||||||
|
|
||||||
|
if (!pAdvertising->setInstanceData(0, legacyAdvertising)) {
|
||||||
|
LOG_ERROR("BLE failed to set legacyAdvertising");
|
||||||
|
} else if (!pAdvertising->setScanResponseData(0, legacyScanResponse)) {
|
||||||
|
LOG_ERROR("BLE failed to set legacyScanResponse");
|
||||||
|
} else if (!pAdvertising->start(0, 0, 0)) {
|
||||||
|
LOG_ERROR("BLE failed to start legacyAdvertising");
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising();
|
||||||
|
pAdvertising->reset();
|
||||||
|
pAdvertising->addServiceUUID(MESH_SERVICE_UUID);
|
||||||
|
pAdvertising->addServiceUUID(NimBLEUUID((uint16_t)0x180f)); // 0x180F is the Battery Service
|
||||||
|
pAdvertising->start(0);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/// Given a level between 0-100, update the BLE attribute
|
/// Given a level between 0-100, update the BLE attribute
|
||||||
void updateBatteryLevel(uint8_t level)
|
void updateBatteryLevel(uint8_t level)
|
||||||
{
|
{
|
||||||
if ((config.bluetooth.enabled == true) && bleServer && nimbleBluetooth->isConnected()) {
|
if ((config.bluetooth.enabled == true) && bleServer && nimbleBluetooth->isConnected()) {
|
||||||
BatteryCharacteristic->setValue(&level, 1);
|
BatteryCharacteristic->setValue(&level, 1);
|
||||||
|
#ifdef NIMBLE_TWO
|
||||||
BatteryCharacteristic->notify(&level, 1, BLE_HS_CONN_HANDLE_NONE);
|
BatteryCharacteristic->notify(&level, 1, BLE_HS_CONN_HANDLE_NONE);
|
||||||
|
#else
|
||||||
|
BatteryCharacteristic->notify();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -909,7 +974,11 @@ void NimbleBluetooth::sendLog(const uint8_t *logMessage, size_t length)
|
|||||||
if (!bleServer || !isConnected() || length > 512) {
|
if (!bleServer || !isConnected() || length > 512) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
#ifdef NIMBLE_TWO
|
||||||
logRadioCharacteristic->notify(logMessage, length, BLE_HS_CONN_HANDLE_NONE);
|
logRadioCharacteristic->notify(logMessage, length, BLE_HS_CONN_HANDLE_NONE);
|
||||||
|
#else
|
||||||
|
logRadioCharacteristic->notify(logMessage, length, true);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void clearNVS()
|
void clearNVS()
|
||||||
|
|||||||
@@ -12,11 +12,16 @@ class NimbleBluetooth : BluetoothApi
|
|||||||
bool isConnected();
|
bool isConnected();
|
||||||
int getRssi();
|
int getRssi();
|
||||||
void sendLog(const uint8_t *logMessage, size_t length);
|
void sendLog(const uint8_t *logMessage, size_t length);
|
||||||
|
#if defined(NIMBLE_TWO)
|
||||||
void startAdvertising();
|
void startAdvertising();
|
||||||
|
#endif
|
||||||
bool isDeInit = false;
|
bool isDeInit = false;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setupService();
|
void setupService();
|
||||||
|
#if !defined(NIMBLE_TWO)
|
||||||
|
void startAdvertising();
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
void setBluetoothEnable(bool enable);
|
void setBluetoothEnable(bool enable);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -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>();
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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 =
|
||||||
|
|||||||
@@ -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}
|
||||||
@@ -38,7 +38,6 @@ build_flags =
|
|||||||
-DAXP_DEBUG_PORT=Serial
|
-DAXP_DEBUG_PORT=Serial
|
||||||
-DCONFIG_BT_NIMBLE_ENABLED
|
-DCONFIG_BT_NIMBLE_ENABLED
|
||||||
-DCONFIG_BT_NIMBLE_MAX_BONDS=6 # default is 3
|
-DCONFIG_BT_NIMBLE_MAX_BONDS=6 # default is 3
|
||||||
-DCONFIG_BT_NIMBLE_ROLE_CENTRAL_DISABLED
|
|
||||||
-DCONFIG_NIMBLE_CPP_LOG_LEVEL=2
|
-DCONFIG_NIMBLE_CPP_LOG_LEVEL=2
|
||||||
-DCONFIG_BT_NIMBLE_MAX_CCCDS=20
|
-DCONFIG_BT_NIMBLE_MAX_CCCDS=20
|
||||||
-DCONFIG_BT_NIMBLE_HOST_TASK_STACK_SIZE=8192
|
-DCONFIG_BT_NIMBLE_HOST_TASK_STACK_SIZE=8192
|
||||||
@@ -60,7 +59,7 @@ lib_deps =
|
|||||||
# renovate: datasource=git-refs depName=meshtastic-esp32_https_server packageName=https://github.com/meshtastic/esp32_https_server gitBranch=master
|
# renovate: datasource=git-refs depName=meshtastic-esp32_https_server packageName=https://github.com/meshtastic/esp32_https_server gitBranch=master
|
||||||
https://github.com/meshtastic/esp32_https_server/archive/3223704846752e6d545139204837bdb2a55459ca.zip
|
https://github.com/meshtastic/esp32_https_server/archive/3223704846752e6d545139204837bdb2a55459ca.zip
|
||||||
# renovate: datasource=custom.pio depName=NimBLE-Arduino packageName=h2zero/library/NimBLE-Arduino
|
# renovate: datasource=custom.pio depName=NimBLE-Arduino packageName=h2zero/library/NimBLE-Arduino
|
||||||
h2zero/NimBLE-Arduino@^2.3.7
|
h2zero/NimBLE-Arduino@^1.4.3
|
||||||
# renovate: datasource=git-refs depName=libpax packageName=https://github.com/dbinfrago/libpax gitBranch=master
|
# renovate: datasource=git-refs depName=libpax packageName=https://github.com/dbinfrago/libpax gitBranch=master
|
||||||
https://github.com/dbinfrago/libpax/archive/3cdc0371c375676a97967547f4065607d4c53fd1.zip
|
https://github.com/dbinfrago/libpax/archive/3cdc0371c375676a97967547f4065607d4c53fd1.zip
|
||||||
# renovate: datasource=github-tags depName=XPowersLib packageName=lewisxhe/XPowersLib
|
# renovate: datasource=github-tags depName=XPowersLib packageName=lewisxhe/XPowersLib
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
[env:tbeam]
|
[env:tbeam]
|
||||||
extends = esp32_base
|
extends = esp32_base
|
||||||
board = ttgo-t-beam
|
board = ttgo-t-beam
|
||||||
board_level = extra
|
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}
|
||||||
|
|||||||
@@ -4,8 +4,3 @@ custom_esp32_kind = esp32c3
|
|||||||
|
|
||||||
monitor_speed = 115200
|
monitor_speed = 115200
|
||||||
monitor_filters = esp32_c3_exception_decoder
|
monitor_filters = esp32_c3_exception_decoder
|
||||||
|
|
||||||
build_flags =
|
|
||||||
${esp32_base.build_flags}
|
|
||||||
-DCONFIG_BT_NIMBLE_EXT_ADV=1
|
|
||||||
-DCONFIG_BT_NIMBLE_MAX_EXT_ADV_INSTANCES=2
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ build_unflags =
|
|||||||
lib_deps =
|
lib_deps =
|
||||||
${esp32c6_base.lib_deps}
|
${esp32c6_base.lib_deps}
|
||||||
adafruit/Adafruit NeoPixel@^1.12.3
|
adafruit/Adafruit NeoPixel@^1.12.3
|
||||||
h2zero/NimBLE-Arduino@^2.3.7
|
h2zero/NimBLE-Arduino@^2.3.6
|
||||||
build_flags =
|
build_flags =
|
||||||
${esp32c6_base.build_flags}
|
${esp32c6_base.build_flags}
|
||||||
-D M5STACK_UNITC6L
|
-D M5STACK_UNITC6L
|
||||||
@@ -24,6 +24,7 @@ build_flags =
|
|||||||
-D HAS_BLUETOOTH=1
|
-D HAS_BLUETOOTH=1
|
||||||
-DCONFIG_BT_NIMBLE_EXT_ADV=1
|
-DCONFIG_BT_NIMBLE_EXT_ADV=1
|
||||||
-DCONFIG_BT_NIMBLE_MAX_EXT_ADV_INSTANCES=2
|
-DCONFIG_BT_NIMBLE_MAX_EXT_ADV_INSTANCES=2
|
||||||
|
-D NIMBLE_TWO
|
||||||
monitor_speed=115200
|
monitor_speed=115200
|
||||||
lib_ignore =
|
lib_ignore =
|
||||||
NonBlockingRTTTL
|
NonBlockingRTTTL
|
||||||
|
|||||||
@@ -3,8 +3,3 @@ extends = esp32_base
|
|||||||
custom_esp32_kind = esp32s3
|
custom_esp32_kind = esp32s3
|
||||||
|
|
||||||
monitor_speed = 115200
|
monitor_speed = 115200
|
||||||
|
|
||||||
build_flags =
|
|
||||||
${esp32_base.build_flags}
|
|
||||||
-DCONFIG_BT_NIMBLE_EXT_ADV=1
|
|
||||||
-DCONFIG_BT_NIMBLE_MAX_EXT_ADV_INSTANCES=2
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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,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,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}
|
||||||
|
|||||||
@@ -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 =
|
||||||
|
|||||||
Reference in New Issue
Block a user