mirror of
https://github.com/meshtastic/firmware.git
synced 2026-01-04 00:52:17 +00:00
Compare commits
207 Commits
v2.2.23.56
...
v2.3.2.63d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
63df972d42 | ||
|
|
c87fdfece7 | ||
|
|
381d5230b8 | ||
|
|
a7c005ccdf | ||
|
|
71ca6f768f | ||
|
|
4cce4c7c93 | ||
|
|
9e8860d188 | ||
|
|
d30d6bd3eb | ||
|
|
94e4301f2f | ||
|
|
54818b5f8d | ||
|
|
c77c58d656 | ||
|
|
794e99c2f9 | ||
|
|
7aa013a716 | ||
|
|
a57f7730ea | ||
|
|
35754d661d | ||
|
|
79cfb1e876 | ||
|
|
155df45d92 | ||
|
|
907d075917 | ||
|
|
9c88906acc | ||
|
|
defeb8e52b | ||
|
|
6dd337a651 | ||
|
|
0a7ddb7594 | ||
|
|
4debcd5ccd | ||
|
|
fd26914d88 | ||
|
|
dfcd0d14f6 | ||
|
|
f4095ce00d | ||
|
|
7aa21f6e3f | ||
|
|
5e832e2fc6 | ||
|
|
4fa7f5a748 | ||
|
|
a6625998f5 | ||
|
|
711b85cfe8 | ||
|
|
b98176e73e | ||
|
|
aae49f5ecf | ||
|
|
0d1d79b6d1 | ||
|
|
bb57ccfc9e | ||
|
|
e27f029d09 | ||
|
|
13cc1b0252 | ||
|
|
54a2a4bcc6 | ||
|
|
611f291d4d | ||
|
|
9586606229 | ||
|
|
0de36fbfb0 | ||
|
|
0dda20bc35 | ||
|
|
52cfec29fc | ||
|
|
4d0d82f7e7 | ||
|
|
34bc22f94d | ||
|
|
cb3740708b | ||
|
|
e8ec167854 | ||
|
|
b900415218 | ||
|
|
2eb78fec53 | ||
|
|
da7cd5fc7f | ||
|
|
b06c77d46f | ||
|
|
cbc0aa16c5 | ||
|
|
876a0520a9 | ||
|
|
50cc4cfcf1 | ||
|
|
ec6bdeed81 | ||
|
|
a085c3ddb3 | ||
|
|
58cdf360f8 | ||
|
|
9c37e57e75 | ||
|
|
9d2fcbe1e1 | ||
|
|
3995e2f708 | ||
|
|
216f85ff22 | ||
|
|
2efe436102 | ||
|
|
fb16390205 | ||
|
|
333c3c1c9e | ||
|
|
724fa38a55 | ||
|
|
38ea681433 | ||
|
|
ee685b4ed7 | ||
|
|
cf11807f97 | ||
|
|
7f063fbf81 | ||
|
|
6215495ccc | ||
|
|
045dda64e7 | ||
|
|
affbd7f2b9 | ||
|
|
f9bf9e2dcc | ||
|
|
5f47ca1f32 | ||
|
|
6a27e62bcf | ||
|
|
2d5a6c1a20 | ||
|
|
c7839b469b | ||
|
|
95967a01b8 | ||
|
|
e16689a0d6 | ||
|
|
c80098f517 | ||
|
|
1f766a04aa | ||
|
|
1d31be939f | ||
|
|
4b4bd07d5c | ||
|
|
cf4753f7fd | ||
|
|
892223a297 | ||
|
|
658ed6fd28 | ||
|
|
3a8f623f8a | ||
|
|
f09e5c96fc | ||
|
|
a493ab526f | ||
|
|
b3ec3c20fb | ||
|
|
b65b9e5d65 | ||
|
|
766beefbc5 | ||
|
|
eb372c190e | ||
|
|
70df36b5db | ||
|
|
e33d014257 | ||
|
|
26691c0be7 | ||
|
|
09e08e0091 | ||
|
|
73c77b663c | ||
|
|
fb4faf790b | ||
|
|
cb7407e06b | ||
|
|
b45a912409 | ||
|
|
c7d5698dbc | ||
|
|
d1a25947e3 | ||
|
|
69dcc948b9 | ||
|
|
084b01715e | ||
|
|
af9d14c370 | ||
|
|
1032e16ea4 | ||
|
|
3da1b74a10 | ||
|
|
c0a3b20aa3 | ||
|
|
3daae24d29 | ||
|
|
dced888492 | ||
|
|
7167f1e04f | ||
|
|
dfbb4cd913 | ||
|
|
3da7c0dba7 | ||
|
|
7b70324435 | ||
|
|
94eb837ee8 | ||
|
|
a9c07a4c01 | ||
|
|
e232e3462c | ||
|
|
94794edd43 | ||
|
|
95b6f27d2a | ||
|
|
efd818fe90 | ||
|
|
576f582cd9 | ||
|
|
d5c11d1892 | ||
|
|
aaa5d61162 | ||
|
|
3efd606ea7 | ||
|
|
42286edc81 | ||
|
|
29335a18f5 | ||
|
|
51df4fc775 | ||
|
|
0f1bc98305 | ||
|
|
23926210d1 | ||
|
|
7275c21f6b | ||
|
|
ac89bb3387 | ||
|
|
07da130586 | ||
|
|
5d4d91f775 | ||
|
|
7da1153c2c | ||
|
|
585805c3b9 | ||
|
|
a4830e0ab1 | ||
|
|
763ae9f2e2 | ||
|
|
7f12505716 | ||
|
|
b4940b476d | ||
|
|
c860493e68 | ||
|
|
2dd751e339 | ||
|
|
bfce3938d2 | ||
|
|
46ad623785 | ||
|
|
e174328de3 | ||
|
|
9d37a8d17f | ||
|
|
f5ff77c2b9 | ||
|
|
72050530f1 | ||
|
|
e5bf07d4fb | ||
|
|
7ab9a94edb | ||
|
|
3c3d391044 | ||
|
|
e3063a2785 | ||
|
|
6dbb6583ef | ||
|
|
9b3e519487 | ||
|
|
495840c777 | ||
|
|
5865add857 | ||
|
|
c659292836 | ||
|
|
905718e2ac | ||
|
|
a58348369d | ||
|
|
d20fa6e927 | ||
|
|
bf88773b6b | ||
|
|
6acc63729b | ||
|
|
7aee014f5e | ||
|
|
2786db499d | ||
|
|
4ffb906fe8 | ||
|
|
f7758b4e44 | ||
|
|
e6a2c06346 | ||
|
|
ce0e5c0ce7 | ||
|
|
59bbd1ad00 | ||
|
|
4796c8edc4 | ||
|
|
f708e41ba7 | ||
|
|
d556d59308 | ||
|
|
146b5b557a | ||
|
|
0dcd3584e4 | ||
|
|
d434117ffd | ||
|
|
0f27992c5a | ||
|
|
824991c178 | ||
|
|
02192e1163 | ||
|
|
d47f55289f | ||
|
|
b98ddbddf4 | ||
|
|
6932f07310 | ||
|
|
a8d37475b6 | ||
|
|
8726cb830e | ||
|
|
8c7ee1a7bb | ||
|
|
1fe230a065 | ||
|
|
74714bf0c5 | ||
|
|
8bfe5a2bd4 | ||
|
|
9c4d1b5ac8 | ||
|
|
c2085c2c88 | ||
|
|
730429fc9b | ||
|
|
f1b314251c | ||
|
|
b2ea1e23be | ||
|
|
3ad34f8759 | ||
|
|
f95b90364a | ||
|
|
7706786541 | ||
|
|
eb2fa727a7 | ||
|
|
790f100620 | ||
|
|
0153daa8ba | ||
|
|
880afb9477 | ||
|
|
78b4a65635 | ||
|
|
eb8a12e5a2 | ||
|
|
9784758c7b | ||
|
|
e0c7f7207b | ||
|
|
23df6ddf01 | ||
|
|
7a1c565701 | ||
|
|
0bfac7b5f9 | ||
|
|
5a3180a525 |
1
.github/workflows/build_esp32.yml
vendored
1
.github/workflows/build_esp32.yml
vendored
@@ -35,6 +35,7 @@ jobs:
|
||||
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32.ini
|
||||
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32s2.ini
|
||||
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32s3.ini
|
||||
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32c3.ini
|
||||
|
||||
- name: Build ESP32
|
||||
run: bin/build-esp32.sh ${{ inputs.board }}
|
||||
|
||||
62
.github/workflows/build_esp32_c3.yml
vendored
Normal file
62
.github/workflows/build_esp32_c3.yml
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
name: Build ESP32-C3
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
board:
|
||||
required: true
|
||||
type: string
|
||||
|
||||
permissions: read-all
|
||||
|
||||
jobs:
|
||||
build-esp32-c3:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Build base
|
||||
id: base
|
||||
uses: ./.github/actions/setup-base
|
||||
|
||||
- name: Pull web ui
|
||||
uses: dsaltares/fetch-gh-release-asset@a40c8b4a0471f9ab81bdf73a010f74cc51476ad4
|
||||
with:
|
||||
repo: meshtastic/web
|
||||
file: build.tar
|
||||
target: build.tar
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Unpack web ui
|
||||
run: |
|
||||
tar -xf build.tar -C data/static
|
||||
rm build.tar
|
||||
- name: Remove debug flags for release
|
||||
if: ${{ github.event_name == 'workflow_dispatch' }}
|
||||
run: |
|
||||
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32.ini
|
||||
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32s2.ini
|
||||
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32s3.ini
|
||||
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32c3.ini
|
||||
- name: Build ESP32
|
||||
run: bin/build-esp32.sh ${{ inputs.board }}
|
||||
|
||||
- name: Pull OTA Firmware
|
||||
uses: dsaltares/fetch-gh-release-asset@a40c8b4a0471f9ab81bdf73a010f74cc51476ad4
|
||||
with:
|
||||
repo: meshtastic/firmware-ota
|
||||
file: firmware-c3.bin
|
||||
target: release/bleota-c3.bin
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Get release version string
|
||||
shell: bash
|
||||
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
||||
id: version
|
||||
|
||||
- name: Store binaries as an artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: firmware-${{ inputs.board }}-${{ steps.version.outputs.version }}.zip
|
||||
path: |
|
||||
release/*.bin
|
||||
release/*.elf
|
||||
1
.github/workflows/build_esp32_s3.yml
vendored
1
.github/workflows/build_esp32_s3.yml
vendored
@@ -34,6 +34,7 @@ jobs:
|
||||
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32.ini
|
||||
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32s2.ini
|
||||
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32s3.ini
|
||||
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32c3.ini
|
||||
- name: Build ESP32
|
||||
run: bin/build-esp32.sh ${{ inputs.board }}
|
||||
|
||||
|
||||
22
.github/workflows/main_matrix.yml
vendored
22
.github/workflows/main_matrix.yml
vendored
@@ -32,7 +32,7 @@ jobs:
|
||||
- board: meshtastic-diy-v1
|
||||
- board: rak4631
|
||||
- board: t-echo
|
||||
- board: station-g1
|
||||
- board: station-g2
|
||||
- board: m5stack-coreink
|
||||
- board: tbeam-s3-core
|
||||
- board: tlora-t3s3-v1
|
||||
@@ -67,8 +67,6 @@ jobs:
|
||||
- board: tlora-v2-1-1_6-tcxo
|
||||
- board: tlora-v2-1-1_8
|
||||
- board: tbeam
|
||||
- board: heltec-ht62-esp32c3-sx1262
|
||||
- board: heltec-v1
|
||||
- board: heltec-v2_0
|
||||
- board: heltec-v2_1
|
||||
- board: tbeam0_7
|
||||
@@ -93,16 +91,29 @@ jobs:
|
||||
- board: heltec-v3
|
||||
- board: heltec-wsl-v3
|
||||
- board: heltec-wireless-tracker
|
||||
- board: heltec-wireless-paper
|
||||
- board: heltec-wireless-tracker-V1-0
|
||||
- board: heltec-wireless-paper-v1_0
|
||||
- board: heltec-wireless-paper #v1.1
|
||||
- board: tbeam-s3-core
|
||||
- board: tlora-t3s3-v1
|
||||
- board: t-watch-s3
|
||||
- board: t-deck
|
||||
- board: picomputer-s3
|
||||
- board: station-g2
|
||||
uses: ./.github/workflows/build_esp32_s3.yml
|
||||
with:
|
||||
board: ${{ matrix.board }}
|
||||
|
||||
build-esp32-c3:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- board: heltec-ht62-esp32c3-sx1262
|
||||
uses: ./.github/workflows/build_esp32_c3.yml
|
||||
with:
|
||||
board: ${{ matrix.board }}
|
||||
|
||||
build-nrf52:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@@ -224,6 +235,7 @@ jobs:
|
||||
[
|
||||
build-esp32,
|
||||
build-esp32-s3,
|
||||
build-esp32-c3,
|
||||
build-nrf52,
|
||||
build-raspbian,
|
||||
build-native,
|
||||
@@ -249,7 +261,7 @@ jobs:
|
||||
id: version
|
||||
|
||||
- name: Move files up
|
||||
run: mv -b -t ./ ./*tbeam-2*/littlefs*.bin ./*tbeam-2*/bleota.bin ./*tbeam-s3*/bleota-s3.bin ./**/firmware*.bin ./*t-echo*/Meshtastic_nRF52_factory_erase_v2.uf2 ./**/firmware-*.uf2 ./**/firmware-*-ota.zip ./**/*.elf ./*native*/*device-*.sh ./*native*/*device-*.bat ./firmware-raspbian-*/release/meshtasticd_linux_aarch64 ./firmware-raspbian-*/bin/config-dist.yaml
|
||||
run: mv -b -t ./ ./*tbeam-2*/littlefs*.bin ./*tbeam-2*/bleota.bin ./*tbeam-s3*/bleota-s3.bin ./*esp32c3*/bleota-c3.bin ./**/firmware*.bin ./*t-echo*/Meshtastic_nRF52_factory_erase_v2.uf2 ./**/firmware-*.uf2 ./**/firmware-*-ota.zip ./**/*.elf ./*native*/*device-*.sh ./*native*/*device-*.bat ./firmware-raspbian-*/release/meshtasticd_linux_aarch64 ./firmware-raspbian-*/bin/config-dist.yaml
|
||||
|
||||
- name: Repackage in single firmware zip
|
||||
uses: actions/upload-artifact@v3
|
||||
|
||||
13
.github/workflows/package_raspbian.yml
vendored
13
.github/workflows/package_raspbian.yml
vendored
@@ -23,6 +23,14 @@ jobs:
|
||||
ref: ${{github.event.pull_request.head.ref}}
|
||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||
|
||||
- name: Pull web ui
|
||||
uses: dsaltares/fetch-gh-release-asset@a40c8b4a0471f9ab81bdf73a010f74cc51476ad4
|
||||
with:
|
||||
repo: meshtastic/web
|
||||
file: build.tar
|
||||
target: build.tar
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Get release version string
|
||||
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
||||
id: version
|
||||
@@ -37,9 +45,12 @@ jobs:
|
||||
|
||||
- name: build .debpkg
|
||||
run: |
|
||||
mkdir -p .debpkg/usr/share/doc/meshtasticd/web
|
||||
mkdir -p .debpkg/usr/sbin
|
||||
mkdir -p .debpkg/etc/meshtasticd
|
||||
mkdir -p .debpkg/usr/lib/systemd/system/
|
||||
tar -xf build.tar -C .debpkg/usr/share/doc/meshtasticd/web
|
||||
gunzip .debpkg/usr/share/doc/meshtasticd/web/*.gz
|
||||
cp release/meshtasticd_linux_aarch64 .debpkg/usr/sbin/meshtasticd
|
||||
cp bin/config-dist.yaml .debpkg/etc/meshtasticd/config.yaml
|
||||
chmod +x .debpkg/usr/sbin/meshtasticd
|
||||
@@ -52,7 +63,7 @@ jobs:
|
||||
maintainer: Jonathan Bennett
|
||||
version: ${{ steps.version.outputs.version }} # refs/tags/v*.*.*
|
||||
arch: arm64
|
||||
depends: libyaml-cpp0.7
|
||||
depends: libyaml-cpp0.7, openssl
|
||||
desc: Native Linux Meshtastic binary.
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -31,3 +31,5 @@ venv/
|
||||
release/
|
||||
.vscode/extensions.json
|
||||
/compile_commands.json
|
||||
src/mesh/raspihttp/certificate.pem
|
||||
src/mesh/raspihttp/private_key.pem
|
||||
1
.trunk/.gitignore
vendored
1
.trunk/.gitignore
vendored
@@ -6,3 +6,4 @@
|
||||
plugins
|
||||
user_trunk.yaml
|
||||
user.yaml
|
||||
tmp
|
||||
|
||||
@@ -1,34 +1,36 @@
|
||||
version: 0.1
|
||||
cli:
|
||||
version: 1.17.2
|
||||
version: 1.20.1
|
||||
plugins:
|
||||
sources:
|
||||
- id: trunk
|
||||
ref: v1.3.0
|
||||
ref: v1.4.4
|
||||
uri: https://github.com/trunk-io/plugins
|
||||
lint:
|
||||
enabled:
|
||||
- bandit@1.7.5
|
||||
- checkov@3.1.9
|
||||
- terrascan@1.18.5
|
||||
- trivy@0.47.0
|
||||
- trufflehog@3.68.5
|
||||
- yamllint@1.35.1
|
||||
- bandit@1.7.7
|
||||
- checkov@3.2.32
|
||||
- terrascan@1.19.1
|
||||
- trivy@0.49.1
|
||||
#- trufflehog@3.63.2-rc0
|
||||
- taplo@0.8.1
|
||||
- ruff@0.1.6
|
||||
- isort@5.12.0
|
||||
- markdownlint@0.37.0
|
||||
- ruff@0.3.1
|
||||
- isort@5.13.2
|
||||
- markdownlint@0.39.0
|
||||
- oxipng@9.0.0
|
||||
- svgo@3.0.5
|
||||
- actionlint@1.6.26
|
||||
- flake8@6.1.0
|
||||
- svgo@3.2.0
|
||||
- actionlint@1.6.27
|
||||
- flake8@7.0.0
|
||||
- hadolint@2.12.0
|
||||
- shfmt@3.6.0
|
||||
- shellcheck@0.9.0
|
||||
- black@23.9.1
|
||||
- black@24.2.0
|
||||
- git-diff-check
|
||||
- gitleaks@8.18.1
|
||||
- gitleaks@8.18.2
|
||||
- clang-format@16.0.3
|
||||
- prettier@3.1.0
|
||||
- prettier@3.2.5
|
||||
runtimes:
|
||||
enabled:
|
||||
- python@3.10.8
|
||||
|
||||
2
.vscode/extensions.json
vendored
2
.vscode/extensions.json
vendored
@@ -6,4 +6,4 @@
|
||||
"platformio.platformio-ide",
|
||||
"trunk.io"
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
4
.vscode/settings.json
vendored
4
.vscode/settings.json
vendored
@@ -1,5 +1,7 @@
|
||||
{
|
||||
"editor.formatOnSave": true,
|
||||
"editor.defaultFormatter": "trunk.io",
|
||||
"trunk.enableWindows": true
|
||||
"trunk.enableWindows": true,
|
||||
"files.insertFinalNewline": false,
|
||||
"files.trimFinalNewlines": false
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ extends = arduino_base
|
||||
platform = platformio/espressif32@6.3.2 # This is a temporary fix to the S3-based devices bluetooth issues until we can determine what within ESP-IDF changed and can develop a suitable patch.
|
||||
|
||||
build_src_filter =
|
||||
${arduino_base.build_src_filter} -<platform/nrf52/> -<platform/stm32wl> -<platform/rp2040> -<mesh/eth/>
|
||||
${arduino_base.build_src_filter} -<platform/nrf52/> -<platform/stm32wl> -<platform/rp2040> -<mesh/eth/> -<mesh/raspihttp>
|
||||
|
||||
upload_speed = 921600
|
||||
debug_init_break = tbreak setup
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
extends = esp32_base
|
||||
|
||||
build_src_filter =
|
||||
${esp32_base.build_src_filter} -<nimble/>
|
||||
${esp32_base.build_src_filter} -<nimble/> -<mesh/raspihttp>
|
||||
|
||||
monitor_speed = 115200
|
||||
|
||||
@@ -12,5 +12,4 @@ build_flags =
|
||||
|
||||
lib_ignore =
|
||||
${esp32_base.lib_ignore}
|
||||
NimBLE-Arduino
|
||||
|
||||
NimBLE-Arduino
|
||||
@@ -1,6 +1,6 @@
|
||||
[nrf52_base]
|
||||
; Instead of the standard nordicnrf52 platform, we use our fork which has our added variant files
|
||||
platform = platformio/nordicnrf52@^10.1.0
|
||||
platform = platformio/nordicnrf52@^10.4.0
|
||||
extends = arduino_base
|
||||
|
||||
build_type = debug ; I'm debugging with ICE a lot now
|
||||
@@ -11,7 +11,7 @@ build_flags =
|
||||
-Isrc/platform/nrf52
|
||||
|
||||
build_src_filter =
|
||||
${arduino_base.build_src_filter} -<platform/esp32/> -<platform/stm32wl> -<nimble/> -<mesh/wifi/> -<mesh/api/> -<mesh/http/> -<modules/esp32> -<platform/rp2040> -<mesh/eth/>
|
||||
${arduino_base.build_src_filter} -<platform/esp32/> -<platform/stm32wl> -<nimble/> -<mesh/wifi/> -<mesh/api/> -<mesh/http/> -<modules/esp32> -<platform/rp2040> -<mesh/eth/> -<mesh/raspihttp>
|
||||
|
||||
lib_deps=
|
||||
${arduino_base.lib_deps}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
; The Portduino based sim environment on top of any host OS, all hardware will be simulated
|
||||
[portduino_base]
|
||||
platform = https://github.com/meshtastic/platform-native.git#a28dd5a9ccd5c48a9bede46037855ff83915d74b
|
||||
platform = https://github.com/meshtastic/platform-native.git#1b8a32c60ab7495026033858d53c737f7d1cb34a
|
||||
framework = arduino
|
||||
|
||||
build_src_filter =
|
||||
@@ -12,6 +12,7 @@ build_src_filter =
|
||||
-<platform/rp2040>
|
||||
-<mesh/wifi/>
|
||||
-<mesh/http/>
|
||||
+<mesh/raspihttp/>
|
||||
-<mesh/eth/>
|
||||
-<modules/esp32>
|
||||
-<modules/Telemetry/EnvironmentTelemetry.cpp>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
; Common settings for rp2040 Processor based targets
|
||||
[rp2040_base]
|
||||
platform = https://github.com/maxgerhardt/platform-raspberrypi.git#612de5399d68b359053f1307ed223d400aea975c
|
||||
platform = https://github.com/maxgerhardt/platform-raspberrypi.git#60d6ae81fcc73c34b1493ca9e261695e471bc0c2
|
||||
extends = arduino_base
|
||||
platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#3.6.2
|
||||
platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#3.7.2
|
||||
|
||||
board_build.core = earlephilhower
|
||||
board_build.filesystem_size = 0.5m
|
||||
@@ -12,7 +12,7 @@ build_flags =
|
||||
-D__PLAT_RP2040__
|
||||
# -D _POSIX_THREADS
|
||||
build_src_filter =
|
||||
${arduino_base.build_src_filter} -<platform/esp32/> -<nimble/> -<modules/esp32> -<platform/nrf52/> -<platform/stm32wl> -<mesh/eth/> -<mesh/wifi/> -<mesh/http/>
|
||||
${arduino_base.build_src_filter} -<platform/esp32/> -<nimble/> -<modules/esp32> -<platform/nrf52/> -<platform/stm32wl> -<mesh/eth/> -<mesh/wifi/> -<mesh/http/> -<mesh/raspihttp>
|
||||
|
||||
lib_ignore =
|
||||
BluetoothOTA
|
||||
|
||||
@@ -13,7 +13,7 @@ build_flags =
|
||||
-DVECT_TAB_OFFSET=0x08000000
|
||||
|
||||
build_src_filter =
|
||||
${arduino_base.build_src_filter} -<platform/esp32/> -<nimble/> -<mesh/api/> -<mesh/wifi/> -<mesh/http/> -<modules/esp32> -<mesh/eth/> -<input> -<buzz> -<modules/Telemetry> -<platform/nrf52> -<platform/portduino> -<platform/rp2040>
|
||||
${arduino_base.build_src_filter} -<platform/esp32/> -<nimble/> -<mesh/api/> -<mesh/wifi/> -<mesh/http/> -<modules/esp32> -<mesh/eth/> -<input> -<buzz> -<modules/Telemetry> -<platform/nrf52> -<platform/portduino> -<platform/rp2040> -<mesh/raspihttp>
|
||||
|
||||
board_upload.offset_address = 0x08000000
|
||||
upload_protocol = stlink
|
||||
|
||||
@@ -13,7 +13,7 @@ if [[ $# -gt 0 ]]; then
|
||||
# can override which environment by passing arg
|
||||
BOARDS="$@"
|
||||
else
|
||||
BOARDS="tlora-v2 tlora-v1 tlora_v1_3 tlora-v2-1-1.6 tbeam heltec-v1 heltec-v2.0 heltec-v2.1 tbeam0.7 meshtastic-diy-v1 rak4631 rak4631_eink rak11200 t-echo canaryone pca10059_diy_eink"
|
||||
BOARDS="tlora-v2 tlora-v1 tlora_v1_3 tlora-v2-1-1.6 tbeam heltec-v2.0 heltec-v2.1 tbeam0.7 meshtastic-diy-v1 rak4631 rak4631_eink rak11200 t-echo canaryone pca10059_diy_eink"
|
||||
fi
|
||||
|
||||
echo "BOARDS:${BOARDS}"
|
||||
|
||||
@@ -8,7 +8,7 @@ if [[ $# -gt 0 ]]; then
|
||||
# can override which environment by passing arg
|
||||
BOARDS="$@"
|
||||
else
|
||||
BOARDS="rak4631 rak4631_eink t-echo canaryone pca10059_diy_eink pico rak11200 tlora-v2 tlora-v1 tlora_v1_3 tlora-v2-1-1.6 tbeam heltec-v1 heltec-v2.0 heltec-v2.1 tbeam0.7 meshtastic-diy-v1 nano-g1 station-g1 m5stack-core m5stack-coreink tbeam-s3-core"
|
||||
BOARDS="rak4631 rak4631_eink t-echo canaryone pca10059_diy_eink pico rak11200 tlora-v2 tlora-v1 tlora_v1_3 tlora-v2-1-1.6 tbeam heltec-v2.0 heltec-v2.1 tbeam0.7 meshtastic-diy-v1 nano-g1 station-g1 m5stack-core m5stack-coreink tbeam-s3-core"
|
||||
fi
|
||||
|
||||
echo "BOARDS:${BOARDS}"
|
||||
|
||||
@@ -117,3 +117,10 @@ Input:
|
||||
|
||||
Logging:
|
||||
LogLevel: info # debug, info, warn, error
|
||||
|
||||
Webserver:
|
||||
# Port: 443 # Port for Webserver & Webservices
|
||||
# RootPath: /usr/share/doc/meshtasticd/web # Root Dir of WebServer
|
||||
|
||||
General:
|
||||
MaxNodes: 200
|
||||
|
||||
@@ -31,9 +31,13 @@ IF EXIST %FILENAME% IF x%FILENAME:update=%==x%FILENAME% (
|
||||
%PYTHON% -m esptool --baud 115200 erase_flash
|
||||
%PYTHON% -m esptool --baud 115200 write_flash 0x00 %FILENAME%
|
||||
|
||||
@REM Account for S3 board's different OTA partition
|
||||
@REM Account for S3 and C3 board's different OTA partition
|
||||
IF x%FILENAME:s3=%==x%FILENAME% IF x%FILENAME:v3=%==x%FILENAME% IF x%FILENAME:t-deck=%==x%FILENAME% IF x%FILENAME:wireless-paper=%==x%FILENAME% IF x%FILENAME:wireless-tracker=%==x%FILENAME% (
|
||||
%PYTHON% -m esptool --baud 115200 write_flash 0x260000 bleota.bin
|
||||
IF x%FILENAME:esp32c3=%==x%FILENAME% (
|
||||
%PYTHON% -m esptool --baud 115200 write_flash 0x260000 bleota.bin
|
||||
) else (
|
||||
%PYTHON% -m esptool --baud 115200 write_flash 0x260000 bleota-c3.bin
|
||||
)
|
||||
) else (
|
||||
%PYTHON% -m esptool --baud 115200 write_flash 0x260000 bleota-s3.bin
|
||||
)
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
#!/bin/sh
|
||||
|
||||
PYTHON=${PYTHON:-$(which python3 python|head -n 1)}
|
||||
PYTHON=${PYTHON:-$(which python3 python | head -n 1)}
|
||||
|
||||
set -e
|
||||
|
||||
# Usage info
|
||||
show_help() {
|
||||
cat << EOF
|
||||
cat <<EOF
|
||||
Usage: $(basename $0) [-h] [-p ESPTOOL_PORT] [-P PYTHON] [-f FILENAME|FILENAME]
|
||||
Flash image file to device, but first erasing and writing system information"
|
||||
|
||||
@@ -18,44 +18,50 @@ Flash image file to device, but first erasing and writing system information"
|
||||
EOF
|
||||
}
|
||||
|
||||
|
||||
while getopts ":hp:P:f:" opt; do
|
||||
case "${opt}" in
|
||||
h)
|
||||
show_help
|
||||
exit 0
|
||||
;;
|
||||
p) export ESPTOOL_PORT=${OPTARG}
|
||||
;;
|
||||
P) PYTHON=${OPTARG}
|
||||
;;
|
||||
f) FILENAME=${OPTARG}
|
||||
;;
|
||||
*)
|
||||
echo "Invalid flag."
|
||||
show_help >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
case "${opt}" in
|
||||
h)
|
||||
show_help
|
||||
exit 0
|
||||
;;
|
||||
p)
|
||||
export ESPTOOL_PORT=${OPTARG}
|
||||
;;
|
||||
P)
|
||||
PYTHON=${OPTARG}
|
||||
;;
|
||||
f)
|
||||
FILENAME=${OPTARG}
|
||||
;;
|
||||
*)
|
||||
echo "Invalid flag."
|
||||
show_help >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
shift "$((OPTIND-1))"
|
||||
shift "$((OPTIND - 1))"
|
||||
|
||||
[ -z "$FILENAME" -a -n "$1" ] && {
|
||||
FILENAME=$1
|
||||
shift
|
||||
FILENAME=$1
|
||||
shift
|
||||
}
|
||||
|
||||
if [ -f "${FILENAME}" ] && [ ! -z "${FILENAME##*"update"*}" ]; then
|
||||
if [ -f "${FILENAME}" ] && [ -n "${FILENAME##*"update"*}" ]; then
|
||||
echo "Trying to flash ${FILENAME}, but first erasing and writing system information"
|
||||
"$PYTHON" -m esptool erase_flash
|
||||
"$PYTHON" -m esptool write_flash 0x00 ${FILENAME}
|
||||
"$PYTHON" -m esptool erase_flash
|
||||
"$PYTHON" -m esptool write_flash 0x00 ${FILENAME}
|
||||
# Account for S3 board's different OTA partition
|
||||
if [ ! -z "${FILENAME##*"s3"*}" ] && [ ! -z "${FILENAME##*"-v3"*}" ] && [ ! -z "${FILENAME##*"t-deck"*}" ] && [ ! -z "${FILENAME##*"wireless-paper"*}" ] && [ ! -z "${FILENAME##*"wireless-tracker"*}" ]; then
|
||||
"$PYTHON" -m esptool write_flash 0x260000 bleota.bin
|
||||
if [ -n "${FILENAME##*"s3"*}" ] && [ -n "${FILENAME##*"-v3"*}" ] && [ -n "${FILENAME##*"t-deck"*}" ] && [ -n "${FILENAME##*"wireless-paper"*}" ] && [ -n "${FILENAME##*"wireless-tracker"*}" ]; then
|
||||
if [ -n "${FILENAME##*"esp32c3"*}" ]; then
|
||||
"$PYTHON" -m esptool write_flash 0x260000 bleota.bin
|
||||
else
|
||||
"$PYTHON" -m esptool write_flash 0x260000 bleota-c3.bin
|
||||
fi
|
||||
else
|
||||
"$PYTHON" -m esptool write_flash 0x260000 bleota-s3.bin
|
||||
"$PYTHON" -m esptool write_flash 0x260000 bleota-s3.bin
|
||||
fi
|
||||
"$PYTHON" -m esptool write_flash 0x300000 littlefs-*.bin
|
||||
"$PYTHON" -m esptool write_flash 0x300000 littlefs-*.bin
|
||||
|
||||
else
|
||||
show_help
|
||||
|
||||
@@ -1 +1 @@
|
||||
cd protobufs && ..\nanopb-0.4.7\generator-bin\protoc.exe --experimental_allow_proto3_optional --nanopb_out=-v:..\src\mesh\generated -I=..\protobufs ..\protobufs\meshtastic\*.proto
|
||||
cd protobufs && ..\nanopb-0.4.7\generator-bin\protoc.exe --experimental_allow_proto3_optional "--nanopb_out=-S.cpp -v:..\src\mesh\generated\" -I=..\protobufs ..\protobufs\meshtastic\*.proto
|
||||
|
||||
@@ -8,9 +8,8 @@ echo "prebuilt binaries for your computer into nanopb-0.4.7"
|
||||
|
||||
# the nanopb tool seems to require that the .options file be in the current directory!
|
||||
cd protobufs
|
||||
../nanopb-0.4.7/generator-bin/protoc --nanopb_out=-v:../src/mesh/generated/ -I=../protobufs meshtastic/*.proto --experimental_allow_proto3_optional
|
||||
../nanopb-0.4.7/generator-bin/protoc "--nanopb_out=-S.cpp -v:../src/mesh/generated/" -I=../protobufs meshtastic/*.proto --experimental_allow_proto3_optional
|
||||
|
||||
# cd ../src/mesh/generated/meshtastic
|
||||
# sed -i 's/#include "meshtastic/#include "./g' -- *
|
||||
|
||||
# sed -i 's/meshtastic_//g' -- *
|
||||
|
||||
@@ -7,7 +7,10 @@
|
||||
"cpu": "cortex-m4",
|
||||
"extra_flags": "-DARDUINO_NRF52840_CANARY -DNRF52840_XXAA",
|
||||
"f_cpu": "64000000L",
|
||||
"hwids": [["0x239A", "0x4405"]],
|
||||
"hwids": [
|
||||
["0x239A", "0x4405"],
|
||||
["0x239A", "0x009F"]
|
||||
],
|
||||
"usb_product": "CanaryOne",
|
||||
"mcu": "nrf52840",
|
||||
"variant": "canaryone",
|
||||
|
||||
40
boards/esp32-s3-pico.json
Normal file
40
boards/esp32-s3-pico.json
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"ldscript": "esp32s3_out.ld",
|
||||
"partitions": "default_16MB.csv"
|
||||
},
|
||||
"core": "esp32",
|
||||
"extra_flags": [
|
||||
"-DARDUINO_ESP32S3_DEV",
|
||||
"-DARDUINO_USB_MODE=1",
|
||||
"-DARDUINO_RUNNING_CORE=1",
|
||||
"-DARDUINO_EVENT_RUNNING_CORE=1"
|
||||
],
|
||||
"f_cpu": "240000000L",
|
||||
"f_flash": "80000000L",
|
||||
"flash_mode": "qio",
|
||||
"hwids": [["0x303A", "0x1001"]],
|
||||
"mcu": "esp32s3",
|
||||
"variant": "esp32s3"
|
||||
},
|
||||
"connectivity": ["wifi", "bluetooth", "lora"],
|
||||
"debug": {
|
||||
"default_tool": "esp-builtin",
|
||||
"onboard_tools": ["esp-builtin"],
|
||||
"openocd_target": "esp32s3.cfg"
|
||||
},
|
||||
"frameworks": ["arduino", "espidf"],
|
||||
"name": "Waveshare ESP32-S3-Pico (16 MB FLASH, 2 MB PSRAM)",
|
||||
"upload": {
|
||||
"flash_size": "16MB",
|
||||
"maximum_ram_size": 327680,
|
||||
"maximum_size": 16777216,
|
||||
"use_1200bps_touch": true,
|
||||
"wait_for_upload_port": true,
|
||||
"require_upload_port": true,
|
||||
"speed": 921600
|
||||
},
|
||||
"url": "https://www.waveshare.com/esp32-s3-pico.htm",
|
||||
"vendor": "Waveshare"
|
||||
}
|
||||
41
boards/station-g2.json
Executable file
41
boards/station-g2.json
Executable file
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"ldscript": "esp32s3_out.ld",
|
||||
"memory_type": "qio_opi"
|
||||
},
|
||||
"core": "esp32",
|
||||
"extra_flags": [
|
||||
"-DBOARD_HAS_PSRAM",
|
||||
"-DARDUINO_USB_CDC_ON_BOOT=1",
|
||||
"-DARDUINO_USB_MODE=0",
|
||||
"-DARDUINO_RUNNING_CORE=1",
|
||||
"-DARDUINO_EVENT_RUNNING_CORE=0"
|
||||
],
|
||||
"f_cpu": "240000000L",
|
||||
"f_flash": "80000000L",
|
||||
"flash_mode": "qio",
|
||||
"hwids": [["0x303A", "0x1001"]],
|
||||
"mcu": "esp32s3",
|
||||
"variant": "station-g2"
|
||||
},
|
||||
"connectivity": ["wifi", "bluetooth", "lora"],
|
||||
"debug": {
|
||||
"default_tool": "esp-builtin",
|
||||
"onboard_tools": ["esp-builtin"],
|
||||
"openocd_target": "esp32s3.cfg"
|
||||
},
|
||||
"frameworks": ["arduino", "espidf"],
|
||||
"name": "BQ Station G2",
|
||||
"upload": {
|
||||
"flash_size": "16MB",
|
||||
"maximum_ram_size": 327680,
|
||||
"maximum_size": 16777216,
|
||||
"use_1200bps_touch": true,
|
||||
"wait_for_upload_port": true,
|
||||
"require_upload_port": true,
|
||||
"speed": 921600
|
||||
},
|
||||
"url": "https://wiki.uniteng.com/en/meshtastic/station-g2",
|
||||
"vendor": "BQ Consulting"
|
||||
}
|
||||
@@ -69,6 +69,7 @@ build_flags = -Wno-missing-field-initializers
|
||||
-DRADIOLIB_EXCLUDE_PAGER
|
||||
-DRADIOLIB_EXCLUDE_FSK4
|
||||
-DRADIOLIB_EXCLUDE_APRS
|
||||
-DRADIOLIB_EXCLUDE_LORAWAN
|
||||
|
||||
monitor_speed = 115200
|
||||
|
||||
@@ -77,8 +78,8 @@ lib_deps =
|
||||
https://github.com/meshtastic/esp8266-oled-ssd1306.git#ee628ee6c9588d4c56c9e3da35f0fc9448ad54a8 ; ESP8266_SSD1306
|
||||
mathertel/OneButton@^2.5.0 ; OneButton library for non-blocking button debounce
|
||||
https://github.com/meshtastic/arduino-fsm.git#7db3702bf0cfe97b783d6c72595e3f38e0b19159
|
||||
https://github.com/meshtastic/TinyGPSPlus.git#2044b2c51e91ab4cd8cc93b15e40658cd808dd06
|
||||
https://github.com/meshtastic/ArduinoThread.git#72921ac222eed6f526ba1682023cee290d9aa1b3
|
||||
https://github.com/meshtastic/TinyGPSPlus.git#f9f4fef2183514aa52be91d714c1455dd6f26e45
|
||||
https://github.com/meshtastic/ArduinoThread.git#1ae8778c85d0a2a729f989e0b1e7d7c4dc84eef0
|
||||
nanopb/Nanopb@^0.4.7
|
||||
erriez/ErriezCRC32@^1.0.1
|
||||
|
||||
@@ -113,9 +114,10 @@ lib_deps =
|
||||
; (not included in native / portduino)
|
||||
[environmental_base]
|
||||
lib_deps =
|
||||
adafruit/Adafruit BusIO@^1.11.4
|
||||
adafruit/Adafruit BusIO@^1.15.0
|
||||
adafruit/Adafruit Unified Sensor@^1.1.11
|
||||
adafruit/Adafruit BMP280 Library@^2.6.8
|
||||
adafruit/Adafruit BMP085 Library@^1.2.4
|
||||
adafruit/Adafruit BME280 Library@^2.2.2
|
||||
https://github.com/boschsensortec/Bosch-BSEC2-Library#v1.5.2400
|
||||
boschsensortec/BME68x Sensor Library@^1.1.40407
|
||||
@@ -129,4 +131,4 @@ lib_deps =
|
||||
adafruit/Adafruit PM25 AQI Sensor@^1.0.6
|
||||
adafruit/Adafruit MPU6050@^2.2.4
|
||||
adafruit/Adafruit LIS3DH@^1.2.4
|
||||
https://github.com/lewisxhe/BMA423_Library@^0.0.1
|
||||
https://github.com/lewisxhe/SensorLib#27fd0f721e20cd09e1f81383f0ba58a54fe84a17
|
||||
|
||||
Submodule protobufs updated: 5f28be497a...0fe69d73e6
@@ -7,16 +7,16 @@
|
||||
#include <Adafruit_LIS3DH.h>
|
||||
#include <Adafruit_MPU6050.h>
|
||||
#include <Arduino.h>
|
||||
#include <SensorBMA423.hpp>
|
||||
#include <Wire.h>
|
||||
#include <bma.h>
|
||||
|
||||
BMA423 bmaSensor;
|
||||
SensorBMA423 bmaSensor;
|
||||
bool BMA_IRQ = false;
|
||||
|
||||
#define ACCELEROMETER_CHECK_INTERVAL_MS 100
|
||||
#define ACCELEROMETER_CLICK_THRESHOLD 40
|
||||
|
||||
uint16_t readRegister(uint8_t address, uint8_t reg, uint8_t *data, uint16_t len)
|
||||
int readRegister(uint8_t address, uint8_t reg, uint8_t *data, uint8_t len)
|
||||
{
|
||||
Wire.beginTransmission(address);
|
||||
Wire.write(reg);
|
||||
@@ -29,7 +29,7 @@ uint16_t readRegister(uint8_t address, uint8_t reg, uint8_t *data, uint16_t len)
|
||||
return 0; // Pass
|
||||
}
|
||||
|
||||
uint16_t writeRegister(uint8_t address, uint8_t reg, uint8_t *data, uint16_t len)
|
||||
int writeRegister(uint8_t address, uint8_t reg, uint8_t *data, uint8_t len)
|
||||
{
|
||||
Wire.beginTransmission(address);
|
||||
Wire.write(reg);
|
||||
@@ -72,24 +72,14 @@ class AccelerometerThread : public concurrency::OSThread
|
||||
lis.setRange(LIS3DH_RANGE_2_G);
|
||||
// Adjust threshold, higher numbers are less sensitive
|
||||
lis.setClick(config.device.double_tap_as_button_press ? 2 : 1, ACCELEROMETER_CLICK_THRESHOLD);
|
||||
} else if (acceleremoter_type == ScanI2C::DeviceType::BMA423 && bmaSensor.begin(readRegister, writeRegister, delay)) {
|
||||
} else if (acceleremoter_type == ScanI2C::DeviceType::BMA423 &&
|
||||
bmaSensor.begin(accelerometer_found.address, &readRegister, &writeRegister)) {
|
||||
LOG_DEBUG("BMA423 initializing\n");
|
||||
Acfg cfg;
|
||||
cfg.odr = BMA4_OUTPUT_DATA_RATE_100HZ;
|
||||
cfg.range = BMA4_ACCEL_RANGE_2G;
|
||||
cfg.bandwidth = BMA4_ACCEL_NORMAL_AVG4;
|
||||
cfg.perf_mode = BMA4_CONTINUOUS_MODE;
|
||||
bmaSensor.setAccelConfig(cfg);
|
||||
bmaSensor.enableAccel();
|
||||
|
||||
struct bma4_int_pin_config pin_config;
|
||||
pin_config.edge_ctrl = BMA4_LEVEL_TRIGGER;
|
||||
pin_config.lvl = BMA4_ACTIVE_HIGH;
|
||||
pin_config.od = BMA4_PUSH_PULL;
|
||||
pin_config.output_en = BMA4_OUTPUT_ENABLE;
|
||||
pin_config.input_en = BMA4_INPUT_DISABLE;
|
||||
// The correct trigger interrupt needs to be configured as needed
|
||||
bmaSensor.setINTPinConfig(pin_config, BMA4_INTR1_MAP);
|
||||
bmaSensor.configAccelerometer(bmaSensor.RANGE_2G, bmaSensor.ODR_100HZ, bmaSensor.BW_NORMAL_AVG4,
|
||||
bmaSensor.PERF_CONTINUOUS_MODE);
|
||||
bmaSensor.enableAccelerometer();
|
||||
bmaSensor.configInterrupt(BMA4_LEVEL_TRIGGER, BMA4_ACTIVE_HIGH, BMA4_PUSH_PULL, BMA4_OUTPUT_ENABLE,
|
||||
BMA4_INPUT_DISABLE);
|
||||
|
||||
#ifdef BMA423_INT
|
||||
pinMode(BMA4XX_INT, INPUT);
|
||||
@@ -102,25 +92,22 @@ class AccelerometerThread : public concurrency::OSThread
|
||||
RISING); // Select the interrupt mode according to the actual circuit
|
||||
#endif
|
||||
|
||||
struct bma423_axes_remap remap_data;
|
||||
remap_data.x_axis = 0;
|
||||
remap_data.x_axis_sign = 1;
|
||||
remap_data.y_axis = 1;
|
||||
remap_data.y_axis_sign = 0;
|
||||
remap_data.z_axis = 2;
|
||||
remap_data.z_axis_sign = 1;
|
||||
#ifdef T_WATCH_S3
|
||||
// Need to raise the wrist function, need to set the correct axis
|
||||
bmaSensor.setRemapAxes(&remap_data);
|
||||
// sensor.enableFeature(BMA423_STEP_CNTR, true);
|
||||
bmaSensor.enableFeature(BMA423_TILT, true);
|
||||
bmaSensor.enableFeature(BMA423_WAKEUP, true);
|
||||
// sensor.resetStepCounter();
|
||||
bmaSensor.setReampAxes(bmaSensor.REMAP_TOP_LAYER_RIGHT_CORNER);
|
||||
#else
|
||||
bmaSensor.setReampAxes(bmaSensor.REMAP_BOTTOM_LAYER_BOTTOM_LEFT_CORNER);
|
||||
#endif
|
||||
// bmaSensor.enableFeature(bmaSensor.FEATURE_STEP_CNTR, true);
|
||||
bmaSensor.enableFeature(bmaSensor.FEATURE_TILT, true);
|
||||
bmaSensor.enableFeature(bmaSensor.FEATURE_WAKEUP, true);
|
||||
// bmaSensor.resetPedometer();
|
||||
|
||||
// Turn on feature interrupt
|
||||
bmaSensor.enableStepCountInterrupt();
|
||||
bmaSensor.enableTiltInterrupt();
|
||||
bmaSensor.enablePedometerIRQ();
|
||||
bmaSensor.enableTiltIRQ();
|
||||
// It corresponds to isDoubleClick interrupt
|
||||
bmaSensor.enableWakeupInterrupt();
|
||||
bmaSensor.enableWakeupIRQ();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,8 +128,8 @@ class AccelerometerThread : public concurrency::OSThread
|
||||
buttonPress();
|
||||
return 500;
|
||||
}
|
||||
} else if (acceleremoter_type == ScanI2C::DeviceType::BMA423 && bmaSensor.getINT()) {
|
||||
if (bmaSensor.isTilt() || bmaSensor.isDoubleClick()) {
|
||||
} else if (acceleremoter_type == ScanI2C::DeviceType::BMA423 && bmaSensor.readIrqStatus() != DEV_WIRE_NONE) {
|
||||
if (bmaSensor.isTilt() || bmaSensor.isDoubleTap()) {
|
||||
wakeScreen();
|
||||
return 500;
|
||||
}
|
||||
@@ -171,4 +158,4 @@ class AccelerometerThread : public concurrency::OSThread
|
||||
Adafruit_LIS3DH lis;
|
||||
};
|
||||
|
||||
} // namespace concurrency
|
||||
} // namespace concurrency
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
#include "configuration.h"
|
||||
#include <Arduino.h>
|
||||
|
||||
extern NodeDB nodeDB;
|
||||
|
||||
namespace meshtastic
|
||||
{
|
||||
|
||||
@@ -55,7 +53,7 @@ class GPSStatus : public Status
|
||||
#ifdef GPS_EXTRAVERBOSE
|
||||
LOG_WARN("Using fixed latitude\n");
|
||||
#endif
|
||||
meshtastic_NodeInfoLite *node = nodeDB.getMeshNode(nodeDB.getNodeNum());
|
||||
meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(nodeDB->getNodeNum());
|
||||
return node->position.latitude_i;
|
||||
} else {
|
||||
return p.latitude_i;
|
||||
@@ -68,7 +66,7 @@ class GPSStatus : public Status
|
||||
#ifdef GPS_EXTRAVERBOSE
|
||||
LOG_WARN("Using fixed longitude\n");
|
||||
#endif
|
||||
meshtastic_NodeInfoLite *node = nodeDB.getMeshNode(nodeDB.getNodeNum());
|
||||
meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(nodeDB->getNodeNum());
|
||||
return node->position.longitude_i;
|
||||
} else {
|
||||
return p.longitude_i;
|
||||
@@ -81,27 +79,18 @@ class GPSStatus : public Status
|
||||
#ifdef GPS_EXTRAVERBOSE
|
||||
LOG_WARN("Using fixed altitude\n");
|
||||
#endif
|
||||
meshtastic_NodeInfoLite *node = nodeDB.getMeshNode(nodeDB.getNodeNum());
|
||||
meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(nodeDB->getNodeNum());
|
||||
return node->position.altitude;
|
||||
} else {
|
||||
return p.altitude;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t getDOP() const
|
||||
{
|
||||
return p.PDOP;
|
||||
}
|
||||
uint32_t getDOP() const { return p.PDOP; }
|
||||
|
||||
uint32_t getHeading() const
|
||||
{
|
||||
return p.ground_track;
|
||||
}
|
||||
uint32_t getHeading() const { return p.ground_track; }
|
||||
|
||||
uint32_t getNumSatellites() const
|
||||
{
|
||||
return p.sats_in_view;
|
||||
}
|
||||
uint32_t getNumSatellites() const { return p.sats_in_view; }
|
||||
|
||||
bool matches(const GPSStatus *newStatus) const
|
||||
{
|
||||
@@ -149,4 +138,4 @@ class GPSStatus : public Status
|
||||
|
||||
} // namespace meshtastic
|
||||
|
||||
extern meshtastic::GPSStatus *gpsStatus;
|
||||
extern meshtastic::GPSStatus *gpsStatus;
|
||||
|
||||
@@ -54,6 +54,19 @@ static const adc_atten_t atten = ADC_ATTENUATION;
|
||||
#endif
|
||||
#endif // BATTERY_PIN && ARCH_ESP32
|
||||
|
||||
#ifdef EXT_CHRG_DETECT
|
||||
#ifndef EXT_CHRG_DETECT_MODE
|
||||
static const uint8_t ext_chrg_detect_mode = INPUT;
|
||||
#else
|
||||
static const uint8_t ext_chrg_detect_mode = EXT_CHRG_DETECT_MODE;
|
||||
#endif
|
||||
#ifndef EXT_CHRG_DETECT_VALUE
|
||||
static const uint8_t ext_chrg_detect_value = HIGH;
|
||||
#else
|
||||
static const uint8_t ext_chrg_detect_value = EXT_CHRG_DETECT_VALUE;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO)
|
||||
INA260Sensor ina260Sensor;
|
||||
INA219Sensor ina219Sensor;
|
||||
@@ -322,7 +335,14 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
||||
|
||||
/// Assume charging if we have a battery and external power is connected.
|
||||
/// we can't be smart enough to say 'full'?
|
||||
virtual bool isCharging() override { return isBatteryConnect() && isVbusIn(); }
|
||||
virtual bool isCharging() override
|
||||
{
|
||||
#ifdef EXT_CHRG_DETECT
|
||||
return digitalRead(EXT_CHRG_DETECT) == ext_chrg_detect_value;
|
||||
#else
|
||||
return isBatteryConnect() && isVbusIn();
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
/// If we see a battery voltage higher than physics allows - assume charger is pumping
|
||||
@@ -389,6 +409,9 @@ bool Power::analogInit()
|
||||
#ifdef EXT_PWR_DETECT
|
||||
pinMode(EXT_PWR_DETECT, INPUT);
|
||||
#endif
|
||||
#ifdef EXT_CHRG_DETECT
|
||||
pinMode(EXT_CHRG_DETECT, ext_chrg_detect_mode);
|
||||
#endif
|
||||
|
||||
#ifdef BATTERY_PIN
|
||||
LOG_DEBUG("Using analog input %d for battery level\n", BATTERY_PIN);
|
||||
@@ -473,11 +496,6 @@ bool Power::setup()
|
||||
|
||||
void Power::shutdown()
|
||||
{
|
||||
screen->setOn(false);
|
||||
#if defined(USE_EINK) && defined(PIN_EINK_EN)
|
||||
digitalWrite(PIN_EINK_EN, LOW); // power off backlight first
|
||||
#endif
|
||||
|
||||
LOG_INFO("Shutting down\n");
|
||||
|
||||
#ifdef HAS_PMU
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
* actions to be taken upon entering or exiting each state.
|
||||
*/
|
||||
#include "PowerFSM.h"
|
||||
#include "Default.h"
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
#include "configuration.h"
|
||||
@@ -45,7 +46,7 @@ static void sdsEnter()
|
||||
{
|
||||
LOG_DEBUG("Enter state: SDS\n");
|
||||
// FIXME - make sure GPS and LORA radio are off first - because we want close to zero current draw
|
||||
doDeepSleep(getConfiguredOrDefaultMs(config.power.sds_secs), false);
|
||||
doDeepSleep(Default::getConfiguredOrDefaultMs(config.power.sds_secs), false);
|
||||
}
|
||||
|
||||
extern Power *power;
|
||||
@@ -245,6 +246,7 @@ Fsm powerFSM(&stateBOOT);
|
||||
void PowerFSM_setup()
|
||||
{
|
||||
bool isRouter = (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER ? 1 : 0);
|
||||
bool isInfrastructureRole = isRouter || config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER;
|
||||
bool isTrackerOrSensor = config.device.role == meshtastic_Config_DeviceConfig_Role_TRACKER ||
|
||||
config.device.role == meshtastic_Config_DeviceConfig_Role_TAK_TRACKER ||
|
||||
config.device.role == meshtastic_Config_DeviceConfig_Role_SENSOR;
|
||||
@@ -342,13 +344,13 @@ void PowerFSM_setup()
|
||||
powerFSM.add_transition(&stateDARK, &stateDARK, EVENT_CONTACT_FROM_PHONE, NULL, "Contact from phone");
|
||||
|
||||
powerFSM.add_timed_transition(&stateON, &stateDARK,
|
||||
getConfiguredOrDefaultMs(config.display.screen_on_secs, default_screen_on_secs), NULL,
|
||||
Default::getConfiguredOrDefaultMs(config.display.screen_on_secs, default_screen_on_secs), NULL,
|
||||
"Screen-on timeout");
|
||||
powerFSM.add_timed_transition(&statePOWER, &stateDARK,
|
||||
getConfiguredOrDefaultMs(config.display.screen_on_secs, default_screen_on_secs), NULL,
|
||||
Default::getConfiguredOrDefaultMs(config.display.screen_on_secs, default_screen_on_secs), NULL,
|
||||
"Screen-on timeout");
|
||||
powerFSM.add_timed_transition(&stateDARK, &stateDARK,
|
||||
getConfiguredOrDefaultMs(config.display.screen_on_secs, default_screen_on_secs), NULL,
|
||||
Default::getConfiguredOrDefaultMs(config.display.screen_on_secs, default_screen_on_secs), NULL,
|
||||
"Screen-on timeout");
|
||||
|
||||
// We never enter light-sleep or NB states on NRF52 (because the CPU uses so little power normally)
|
||||
@@ -358,11 +360,12 @@ void PowerFSM_setup()
|
||||
// modules
|
||||
if ((isRouter || config.power.is_power_saving) && !isTrackerOrSensor) {
|
||||
powerFSM.add_timed_transition(&stateNB, &stateLS,
|
||||
getConfiguredOrDefaultMs(config.power.min_wake_secs, default_min_wake_secs), NULL,
|
||||
Default::getConfiguredOrDefaultMs(config.power.min_wake_secs, default_min_wake_secs), NULL,
|
||||
"Min wake timeout");
|
||||
powerFSM.add_timed_transition(&stateDARK, &stateLS,
|
||||
getConfiguredOrDefaultMs(config.power.wait_bluetooth_secs, default_wait_bluetooth_secs),
|
||||
NULL, "Bluetooth timeout");
|
||||
powerFSM.add_timed_transition(
|
||||
&stateDARK, &stateLS,
|
||||
Default::getConfiguredOrDefaultMs(config.power.wait_bluetooth_secs, default_wait_bluetooth_secs), NULL,
|
||||
"Bluetooth timeout");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include "Default.h"
|
||||
#include "NodeDB.h"
|
||||
#include "PowerFSM.h"
|
||||
#include "concurrency/OSThread.h"
|
||||
@@ -28,7 +29,7 @@ class PowerFSMThread : public OSThread
|
||||
timeLastPowered = millis();
|
||||
} else if (config.power.on_battery_shutdown_after_secs > 0 && config.power.on_battery_shutdown_after_secs != UINT32_MAX &&
|
||||
millis() > (timeLastPowered +
|
||||
getConfiguredOrDefaultMs(
|
||||
Default::getConfiguredOrDefaultMs(
|
||||
config.power.on_battery_shutdown_after_secs))) { // shutdown after 30 minutes unpowered
|
||||
powerFSM.trigger(EVENT_SHUTDOWN);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,11 @@
|
||||
#include "PowerFSM.h"
|
||||
#include "configuration.h"
|
||||
|
||||
#ifdef RP2040_SLOW_CLOCK
|
||||
#define Port Serial2
|
||||
#else
|
||||
#define Port Serial
|
||||
#endif
|
||||
// Defaulting to the formerly removed phone_timeout_secs value of 15 minutes
|
||||
#define SERIAL_CONNECTION_TIMEOUT (15 * 60) * 1000UL
|
||||
|
||||
@@ -31,6 +35,10 @@ SerialConsole::SerialConsole() : StreamAPI(&Port), RedirectablePrint(&Port), con
|
||||
canWrite = false; // We don't send packets to our port until it has talked to us first
|
||||
// setDestination(&noopPrint); for testing, try turning off 'all' debug output and see what leaks
|
||||
|
||||
#ifdef RP2040_SLOW_CLOCK
|
||||
Port.setTX(SERIAL2_TX);
|
||||
Port.setRX(SERIAL2_RX);
|
||||
#endif
|
||||
Port.begin(SERIAL_BAUD);
|
||||
#if defined(ARCH_NRF52) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3) || defined(ARCH_RP2040)
|
||||
time_t timeout = millis();
|
||||
@@ -64,7 +72,7 @@ bool SerialConsole::checkIsConnected()
|
||||
|
||||
/**
|
||||
* we override this to notice when we've received a protobuf over the serial
|
||||
* stream. Then we shunt off debug serial output.
|
||||
* stream. Then we shut off debug serial output.
|
||||
*/
|
||||
bool SerialConsole::handleToRadio(const uint8_t *buf, size_t len)
|
||||
{
|
||||
|
||||
@@ -111,6 +111,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#define MCP9808_ADDR 0x18
|
||||
#define INA_ADDR 0x40
|
||||
#define INA_ADDR_ALTERNATE 0x41
|
||||
#define INA_ADDR_WAVESHARE_UPS 0x43
|
||||
#define INA3221_ADDR 0x42
|
||||
#define QMC6310_ADDR 0x1C
|
||||
#define QMI8658_ADDR 0x6B
|
||||
@@ -221,4 +222,24 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef HW_VENDOR
|
||||
#error HW_VENDOR must be defined
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// global switch to turn off all optional modules for a minimzed build
|
||||
#ifdef MESHTASTIC_EXCLUDE_MODULES
|
||||
#define MESHTASTIC_EXCLUDE_AUDIO 1
|
||||
#define MESHTASTIC_EXCLUDE_DETECTIONSENSOR 1
|
||||
#define MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR 1
|
||||
#define MESHTASTIC_EXCLUDE_EXTERNALNOTIFICATION 1
|
||||
#define MESHTASTIC_EXCLUDE_PAXCOUNTER 1
|
||||
#define MESHTASTIC_EXCLUDE_POWER_TELEMETRY 1
|
||||
#define MESHTASTIC_EXCLUDE_RANGETEST 1
|
||||
#define MESHTASTIC_EXCLUDE_REMOTEHARDWARE 1
|
||||
#define MESHTASTIC_EXCLUDE_STOREFORWARD 1
|
||||
#define MESHTASTIC_EXCLUDE_ATAK 1
|
||||
#define MESHTASTIC_EXCLUDE_CANNEDMESSAGES 1
|
||||
#define MESHTASTIC_EXCLUDE_NEIGHBORINFO 1
|
||||
#define MESHTASTIC_EXCLUDE_TRACEROUTE 1
|
||||
#define MESHTASTIC_EXCLUDE_WAYPOINT 1
|
||||
#define MESHTASTIC_EXCLUDE_INPUTBROKER 1
|
||||
#define MESHTASTIC_EXCLUDE_SERIAL 1
|
||||
#endif
|
||||
|
||||
@@ -23,6 +23,7 @@ class ScanI2C
|
||||
BME_680,
|
||||
BME_280,
|
||||
BMP_280,
|
||||
BMP_085,
|
||||
INA260,
|
||||
INA219,
|
||||
INA3221,
|
||||
|
||||
@@ -183,8 +183,13 @@ void ScanI2CTwoWire::scanPort(I2CPort port)
|
||||
|
||||
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
|
||||
case ATECC608B_ADDR:
|
||||
type = ATECC608B;
|
||||
if (atecc.begin(addr.address) == true) {
|
||||
#ifdef RP2040_SLOW_CLOCK
|
||||
if (atecc.begin(addr.address, Wire, Serial2) == true)
|
||||
#else
|
||||
if (atecc.begin(addr.address) == true)
|
||||
#endif
|
||||
|
||||
{
|
||||
LOG_INFO("ATECC608B initialized\n");
|
||||
} else {
|
||||
LOG_WARN("ATECC608B initialization failed\n");
|
||||
@@ -242,6 +247,10 @@ void ScanI2CTwoWire::scanPort(I2CPort port)
|
||||
LOG_INFO("BME-280 sensor found at address 0x%x\n", (uint8_t)addr.address);
|
||||
type = BME_280;
|
||||
break;
|
||||
case 0x55:
|
||||
LOG_INFO("BMP-085 or BMP-180 sensor found at address 0x%x\n", (uint8_t)addr.address);
|
||||
type = BMP_085;
|
||||
break;
|
||||
default:
|
||||
LOG_INFO("BMP-280 sensor found at address 0x%x\n", (uint8_t)addr.address);
|
||||
type = BMP_280;
|
||||
@@ -250,6 +259,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port)
|
||||
|
||||
case INA_ADDR:
|
||||
case INA_ADDR_ALTERNATE:
|
||||
case INA_ADDR_WAVESHARE_UPS:
|
||||
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xFE), 2);
|
||||
LOG_DEBUG("Register MFG_UID: 0x%x\n", registerValue);
|
||||
if (registerValue == 0x5449) {
|
||||
|
||||
112
src/gps/GPS.cpp
112
src/gps/GPS.cpp
@@ -1,4 +1,5 @@
|
||||
#include "GPS.h"
|
||||
#include "Default.h"
|
||||
#include "NodeDB.h"
|
||||
#include "RTC.h"
|
||||
#include "configuration.h"
|
||||
@@ -255,19 +256,6 @@ bool GPS::setup()
|
||||
if (!didSerialInit) {
|
||||
#if !defined(GPS_UC6580)
|
||||
|
||||
#if defined(RAK4630) && defined(PIN_3V3_EN)
|
||||
// If we are using the RAK4630 and we have no other peripherals on the I2C bus or module interest in 3V3_S,
|
||||
// then we can safely set en_gpio turn off power to 3V3 (IO2) to hard sleep the GPS
|
||||
if (rtc_found.port == ScanI2C::DeviceType::NONE && rgb_found.type == ScanI2C::DeviceType::NONE &&
|
||||
accelerometer_found.port == ScanI2C::DeviceType::NONE && !moduleConfig.detection_sensor.enabled &&
|
||||
!moduleConfig.telemetry.air_quality_enabled && !moduleConfig.telemetry.environment_measurement_enabled &&
|
||||
config.power.device_battery_ina_address == 0 && en_gpio == 0) {
|
||||
LOG_DEBUG("Since no problematic peripherals or interested modules were found, setting power save GPS_EN to pin %i\n",
|
||||
PIN_3V3_EN);
|
||||
en_gpio = PIN_3V3_EN;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (tx_gpio && gnssModel == GNSS_MODEL_UNKNOWN) {
|
||||
LOG_DEBUG("Probing for GPS at %d \n", serialSpeeds[speedSelect]);
|
||||
gnssModel = probe(serialSpeeds[speedSelect]);
|
||||
@@ -303,6 +291,26 @@ bool GPS::setup()
|
||||
// Switch to Vehicle Mode, since SoftRF enables Aviation < 2g
|
||||
_serial_gps->write("$PCAS11,3*1E\r\n");
|
||||
delay(250);
|
||||
} else if (gnssModel == GNSS_MODEL_MTK_L76B) {
|
||||
// Waveshare Pico-GPS hat uses the L76B with 9600 baud
|
||||
// Initialize the L76B Chip, use GPS + GLONASS
|
||||
// See note in L76_Series_GNSS_Protocol_Specification, chapter 3.29
|
||||
_serial_gps->write("$PMTK353,1,1,0,0,0*2B\r\n");
|
||||
// Above command will reset the GPS and takes longer before it will accept new commands
|
||||
delay(1000);
|
||||
// only ask for RMC and GGA (GNRMC and GNGGA)
|
||||
// See note in L76_Series_GNSS_Protocol_Specification, chapter 2.1
|
||||
_serial_gps->write("$PMTK314,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*28\r\n");
|
||||
delay(250);
|
||||
// Enable SBAS
|
||||
_serial_gps->write("$PMTK301,2*2E\r\n");
|
||||
delay(250);
|
||||
// Enable PPS for 2D/3D fix only
|
||||
_serial_gps->write("$PMTK285,3,100*3F\r\n");
|
||||
delay(250);
|
||||
// Switch to Fitness Mode, for running and walking purpose with low speed (<5 m/s)
|
||||
_serial_gps->write("$PMTK886,1*29\r\n");
|
||||
delay(250);
|
||||
} else if (gnssModel == GNSS_MODEL_UC6580) {
|
||||
// The Unicore UC6580 can use a lot of sat systems, enable it to
|
||||
// use GPS L1 & L5 + BDS B1I & B2a + GLONASS L1 + GALILEO E1 & E5a + SBAS
|
||||
@@ -319,7 +327,6 @@ bool GPS::setup()
|
||||
delay(250);
|
||||
_serial_gps->write("$CFGMSG,6,1,0\r\n");
|
||||
delay(250);
|
||||
|
||||
} else if (gnssModel == GNSS_MODEL_UBLOX) {
|
||||
// Configure GNSS system to GPS+SBAS+GLONASS (Module may restart after this command)
|
||||
// We need set it because by default it is GPS only, and we want to use GLONASS too
|
||||
@@ -444,6 +451,11 @@ bool GPS::setup()
|
||||
if (getACK(0x06, 0x86, 500) != GNSS_RESPONSE_OK) {
|
||||
LOG_WARN("Unable to enable powersaving for GPS.\n");
|
||||
}
|
||||
msglen = makeUBXPacket(0x06, 0x3B, sizeof(_message_CFG_PM2), _message_CFG_PM2);
|
||||
_serial_gps->write(UBXscratch, msglen);
|
||||
if (getACK(0x06, 0x3B, 500) != GNSS_RESPONSE_OK) {
|
||||
LOG_WARN("Unable to enable powersaving details for GPS.\n");
|
||||
}
|
||||
// For M8 we want to enable NMEA vserion 4.10 so we can see the additional sats.
|
||||
if (strncmp(info.hwVersion, "00080000", 8) == 0) {
|
||||
msglen = makeUBXPacket(0x06, 0x17, sizeof(_message_NMEA), _message_NMEA);
|
||||
@@ -453,7 +465,6 @@ bool GPS::setup()
|
||||
LOG_WARN("Unable to enable NMEA 4.10.\n");
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
if (strncmp(info.hwVersion, "00040007", 8) == 0) { // This PSM mode is only for Neo-6
|
||||
msglen = makeUBXPacket(0x06, 0x11, 0x2, _message_CFG_RXM_ECO);
|
||||
@@ -477,15 +488,13 @@ bool GPS::setup()
|
||||
if (getACK(0x06, 0x11, 500) != GNSS_RESPONSE_OK) {
|
||||
LOG_WARN("Unable to enable powersaving mode for GPS.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
msglen = makeUBXPacket(0x06, 0x09, sizeof(_message_SAVE), _message_SAVE);
|
||||
_serial_gps->write(UBXscratch, msglen);
|
||||
if (getACK(0x06, 0x09, 2000) != GNSS_RESPONSE_OK) {
|
||||
LOG_WARN("Unable to save GNSS module configuration.\n");
|
||||
} else {
|
||||
LOG_INFO("GNSS module configuration saved!\n");
|
||||
msglen = makeUBXPacket(0x06, 0x3B, sizeof(_message_CFG_PM2), _message_CFG_PM2);
|
||||
_serial_gps->write(UBXscratch, msglen);
|
||||
if (getACK(0x06, 0x3B, 500) != GNSS_RESPONSE_OK) {
|
||||
LOG_WARN("Unable to enable powersaving details for GPS.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// LOG_INFO("u-blox M10 hardware found.\n");
|
||||
@@ -579,6 +588,13 @@ bool GPS::setup()
|
||||
// BBR will survive a restart, and power off for a while, but modules with small backup
|
||||
// batteries or super caps will not retain the config for a long power off time.
|
||||
}
|
||||
msglen = makeUBXPacket(0x06, 0x09, sizeof(_message_SAVE), _message_SAVE);
|
||||
_serial_gps->write(UBXscratch, msglen);
|
||||
if (getACK(0x06, 0x09, 2000) != GNSS_RESPONSE_OK) {
|
||||
LOG_WARN("Unable to save GNSS module configuration.\n");
|
||||
} else {
|
||||
LOG_INFO("GNSS module configuration saved!\n");
|
||||
}
|
||||
}
|
||||
didSerialInit = true;
|
||||
}
|
||||
@@ -629,17 +645,27 @@ void GPS::setGPSPower(bool on, bool standbyOnly, uint32_t sleepTime)
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#ifdef PIN_GPS_STANDBY // Specifically the standby pin for L76K and clones
|
||||
#ifdef PIN_GPS_STANDBY // Specifically the standby pin for L76B, L76K and clones
|
||||
if (on) {
|
||||
LOG_INFO("Waking GPS");
|
||||
LOG_INFO("Waking GPS\n");
|
||||
pinMode(PIN_GPS_STANDBY, OUTPUT);
|
||||
// Some PCB's use an inverse logic due to a transistor driver
|
||||
// Example for this is the Pico-Waveshare Lora+GPS HAT
|
||||
#ifdef PIN_GPS_STANDBY_INVERTED
|
||||
digitalWrite(PIN_GPS_STANDBY, 0);
|
||||
#else
|
||||
digitalWrite(PIN_GPS_STANDBY, 1);
|
||||
#endif
|
||||
return;
|
||||
} else {
|
||||
LOG_INFO("GPS entering sleep");
|
||||
LOG_INFO("GPS entering sleep\n");
|
||||
// notifyGPSSleep.notifyObservers(NULL);
|
||||
pinMode(PIN_GPS_STANDBY, OUTPUT);
|
||||
#ifdef PIN_GPS_STANDBY_INVERTED
|
||||
digitalWrite(PIN_GPS_STANDBY, 1);
|
||||
#else
|
||||
digitalWrite(PIN_GPS_STANDBY, 0);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
@@ -733,7 +759,7 @@ uint32_t GPS::getWakeTime() const
|
||||
if (t == UINT32_MAX)
|
||||
return t; // already maxint
|
||||
|
||||
return getConfiguredOrDefaultMs(t, default_broadcast_interval_secs);
|
||||
return Default::getConfiguredOrDefaultMs(t, default_broadcast_interval_secs);
|
||||
}
|
||||
|
||||
/** Get how long we should sleep between aqusition attempts in msecs
|
||||
@@ -749,7 +775,7 @@ uint32_t GPS::getSleepTime() const
|
||||
if (t == UINT32_MAX)
|
||||
return t; // already maxint
|
||||
|
||||
return t * 1000;
|
||||
return Default::getConfiguredOrDefaultMs(t, default_gps_update_interval);
|
||||
}
|
||||
|
||||
void GPS::publishUpdate()
|
||||
@@ -789,7 +815,7 @@ int32_t GPS::runOnce()
|
||||
LOG_WARN("GPS FactoryReset requested\n");
|
||||
if (gps->factoryReset()) { // If we don't succeed try again next time
|
||||
devicestate.did_gps_reset = true;
|
||||
nodeDB.saveToDisk(SEGMENT_DEVICESTATE);
|
||||
nodeDB->saveToDisk(SEGMENT_DEVICESTATE);
|
||||
}
|
||||
}
|
||||
GPSInitFinished = true;
|
||||
@@ -809,7 +835,7 @@ int32_t GPS::runOnce()
|
||||
if (devicestate.did_gps_reset && (millis() - lastWakeStartMsec > 60000) && !hasFlow()) {
|
||||
LOG_DEBUG("GPS is not communicating, trying factory reset on next bootup.\n");
|
||||
devicestate.did_gps_reset = false;
|
||||
nodeDB.saveDeviceStateToDisk();
|
||||
nodeDB->saveDeviceStateToDisk();
|
||||
return disable(); // Stop the GPS thread as it can do nothing useful until next reboot.
|
||||
}
|
||||
}
|
||||
@@ -920,7 +946,7 @@ GnssModel_t GPS::probe(int serialSpeed)
|
||||
uint8_t buffer[768] = {0};
|
||||
delay(100);
|
||||
|
||||
// Close all NMEA sentences , Only valid for MTK platform
|
||||
// Close all NMEA sentences , Only valid for L76K MTK platform
|
||||
_serial_gps->write("$PCAS03,0,0,0,0,0,0,0,0,0,0,,,0,0*02\r\n");
|
||||
delay(20);
|
||||
|
||||
@@ -932,6 +958,18 @@ GnssModel_t GPS::probe(int serialSpeed)
|
||||
return GNSS_MODEL_MTK;
|
||||
}
|
||||
|
||||
// Close all NMEA sentences, valid for L76B MTK platform (Waveshare Pico GPS)
|
||||
_serial_gps->write("$PMTK514,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*2E\r\n");
|
||||
delay(20);
|
||||
|
||||
// Get version information
|
||||
clearBuffer();
|
||||
_serial_gps->write("$PMTK605*31\r\n");
|
||||
if (getACK("Quectel-L76B", 500) == GNSS_RESPONSE_OK) {
|
||||
LOG_INFO("L76B GNSS init succeeded, using L76B GNSS Module\n");
|
||||
return GNSS_MODEL_MTK_L76B;
|
||||
}
|
||||
|
||||
uint8_t cfg_rate[] = {0xB5, 0x62, 0x06, 0x08, 0x00, 0x00, 0x00, 0x00};
|
||||
UBXChecksum(cfg_rate, sizeof(cfg_rate));
|
||||
clearBuffer();
|
||||
@@ -1113,7 +1151,6 @@ GPS *GPS::createGps()
|
||||
LOG_DEBUG("Using GPIO%d for GPS RX\n", new_gps->rx_gpio);
|
||||
LOG_DEBUG("Using GPIO%d for GPS TX\n", new_gps->tx_gpio);
|
||||
_serial_gps->begin(GPS_BAUDRATE, SERIAL_8N1, new_gps->rx_gpio, new_gps->tx_gpio);
|
||||
|
||||
#else
|
||||
_serial_gps->begin(GPS_BAUDRATE);
|
||||
#endif
|
||||
@@ -1172,7 +1209,16 @@ bool GPS::factoryReset()
|
||||
// byte _message_CFG_RST_COLDSTART[] = {0xB5, 0x62, 0x06, 0x04, 0x04, 0x00, 0xFF, 0xB9, 0x00, 0x00, 0xC6, 0x8B};
|
||||
// _serial_gps->write(_message_CFG_RST_COLDSTART, sizeof(_message_CFG_RST_COLDSTART));
|
||||
// delay(1000);
|
||||
} else if (gnssModel == GNSS_MODEL_MTK) {
|
||||
// send the CAS10 to perform a factory restart of the device (and other device that support PCAS statements)
|
||||
LOG_INFO("GNSS Factory Reset via PCAS10,3\n");
|
||||
_serial_gps->write("$PCAS10,3*1F\r\n");
|
||||
delay(100);
|
||||
} else {
|
||||
// fire this for good measure, if we have an L76B - won't harm other devices.
|
||||
_serial_gps->write("$PMTK104*37\r\n");
|
||||
// No PMTK_ACK for this command.
|
||||
delay(100);
|
||||
// send the UBLOX Factory Reset Command regardless of detect state, something is very wrong, just assume it's UBLOX.
|
||||
// Factory Reset
|
||||
byte _message_reset[] = {0xB5, 0x62, 0x06, 0x09, 0x0D, 0x00, 0xFF, 0xFB, 0x00, 0x00, 0x00,
|
||||
@@ -1232,7 +1278,7 @@ bool GPS::lookForLocation()
|
||||
|
||||
#ifndef TINYGPS_OPTION_NO_STATISTICS
|
||||
if (reader.failedChecksum() > lastChecksumFailCount) {
|
||||
LOG_WARN("Warning, %u new GPS checksum failures, for a total of %u.\n", reader.failedChecksum() - lastChecksumFailCount,
|
||||
LOG_WARN("%u new GPS checksum failures, for a total of %u.\n", reader.failedChecksum() - lastChecksumFailCount,
|
||||
reader.failedChecksum());
|
||||
lastChecksumFailCount = reader.failedChecksum();
|
||||
}
|
||||
|
||||
@@ -20,12 +20,7 @@ struct uBloxGnssModelInfo {
|
||||
char extension[10][30];
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
GNSS_MODEL_MTK,
|
||||
GNSS_MODEL_UBLOX,
|
||||
GNSS_MODEL_UC6580,
|
||||
GNSS_MODEL_UNKNOWN,
|
||||
} GnssModel_t;
|
||||
typedef enum { GNSS_MODEL_MTK, GNSS_MODEL_UBLOX, GNSS_MODEL_UC6580, GNSS_MODEL_UNKNOWN, GNSS_MODEL_MTK_L76B } GnssModel_t;
|
||||
|
||||
typedef enum {
|
||||
GNSS_RESPONSE_NONE,
|
||||
@@ -92,8 +87,11 @@ class GPS : private concurrency::OSThread
|
||||
|
||||
public:
|
||||
/** If !NULL we will use this serial port to construct our GPS */
|
||||
#if defined(RPI_PICO_WAVESHARE)
|
||||
static SerialUART *_serial_gps;
|
||||
#else
|
||||
static HardwareSerial *_serial_gps;
|
||||
|
||||
#endif
|
||||
static uint8_t _message_PMREQ[];
|
||||
static uint8_t _message_PMREQ_10[];
|
||||
static const uint8_t _message_CFG_RXM_PSM[];
|
||||
|
||||
@@ -376,14 +376,17 @@ void GeoCoord::convertWGS84ToOSGB36(const double lat, const double lon, double &
|
||||
}
|
||||
|
||||
/// Ported from my old java code, returns distance in meters along the globe
|
||||
/// surface (by magic?)
|
||||
/// surface (by Haversine formula)
|
||||
float GeoCoord::latLongToMeter(double lat_a, double lng_a, double lat_b, double lng_b)
|
||||
{
|
||||
double pk = (180 / 3.14169);
|
||||
double a1 = lat_a / pk;
|
||||
double a2 = lng_a / pk;
|
||||
double b1 = lat_b / pk;
|
||||
double b2 = lng_b / pk;
|
||||
// Don't do math if the points are the same
|
||||
if (lat_a == lat_b && lng_a == lng_b)
|
||||
return 0.0;
|
||||
|
||||
double a1 = lat_a / DEG_CONVERT;
|
||||
double a2 = lng_a / DEG_CONVERT;
|
||||
double b1 = lat_b / DEG_CONVERT;
|
||||
double b2 = lng_b / DEG_CONVERT;
|
||||
double cos_b1 = cos(b1);
|
||||
double cos_a1 = cos(a1);
|
||||
double t1 = cos_a1 * cos(a2) * cos_b1 * cos(b2);
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#define PI 3.1415926535897932384626433832795
|
||||
#define OLC_CODE_LEN 11
|
||||
#define DEG_CONVERT (180 / PI)
|
||||
|
||||
// Helper functions
|
||||
// Raises a number to an exponent, handling negative exponents.
|
||||
|
||||
@@ -2,121 +2,49 @@
|
||||
|
||||
#ifdef USE_EINK
|
||||
#include "EInkDisplay2.h"
|
||||
#include "GxEPD2_BW.h"
|
||||
#include "SPILock.h"
|
||||
#include "main.h"
|
||||
#include <SPI.h>
|
||||
|
||||
#if defined(HELTEC_WIRELESS_PAPER) || defined(HELTEC_WIRELESS_PAPER_V1_0)
|
||||
SPIClass *hspi = NULL;
|
||||
#endif
|
||||
/*
|
||||
The macros EINK_DISPLAY_MODEL, EINK_WIDTH, and EINK_HEIGHT are defined as build_flags in a variant's platformio.ini
|
||||
Previously, these macros were defined at the top of this file.
|
||||
|
||||
#define COLORED GxEPD_BLACK
|
||||
#define UNCOLORED GxEPD_WHITE
|
||||
For archival reasons, note that the following configurations had also been tested during this period:
|
||||
* ifdef RAK4631
|
||||
- 4.2 inch
|
||||
EINK_DISPLAY_MODEL: GxEPD2_420_M01
|
||||
EINK_WIDTH: 300
|
||||
EINK_WIDTH: 400
|
||||
|
||||
#if defined(TTGO_T_ECHO)
|
||||
#define TECHO_DISPLAY_MODEL GxEPD2_154_D67
|
||||
#elif defined(RAK4630)
|
||||
- 2.9 inch
|
||||
EINK_DISPLAY_MODEL: GxEPD2_290_T5D
|
||||
EINK_WIDTH: 296
|
||||
EINK_HEIGHT: 128
|
||||
|
||||
// GxEPD2_213_BN - RAK14000 2.13 inch b/w 250x122 - changed from GxEPD2_213_B74 - which was not going to give partial update
|
||||
// support
|
||||
#define TECHO_DISPLAY_MODEL GxEPD2_213_BN
|
||||
|
||||
// 4.2 inch 300x400 - GxEPD2_420_M01
|
||||
// #define TECHO_DISPLAY_MODEL GxEPD2_420_M01
|
||||
|
||||
// 2.9 inch 296x128 - GxEPD2_290_T5D
|
||||
// #define TECHO_DISPLAY_MODEL GxEPD2_290_T5D
|
||||
|
||||
// 1.54 inch 200x200 - GxEPD2_154_M09
|
||||
// #define TECHO_DISPLAY_MODEL GxEPD2_154_M09
|
||||
|
||||
#elif defined(MAKERPYTHON)
|
||||
// 2.9 inch 296x128 - GxEPD2_290_T5D
|
||||
#define TECHO_DISPLAY_MODEL GxEPD2_290_T5D
|
||||
|
||||
#elif defined(PCA10059)
|
||||
|
||||
// 4.2 inch 300x400 - GxEPD2_420_M01
|
||||
#define TECHO_DISPLAY_MODEL GxEPD2_420_M01
|
||||
|
||||
#elif defined(M5_COREINK)
|
||||
// M5Stack CoreInk
|
||||
// 1.54 inch 200x200 - GxEPD2_154_M09
|
||||
#define TECHO_DISPLAY_MODEL GxEPD2_154_M09
|
||||
|
||||
#elif defined(HELTEC_WIRELESS_PAPER)
|
||||
// #define TECHO_DISPLAY_MODEL GxEPD2_213_T5D
|
||||
#define TECHO_DISPLAY_MODEL GxEPD2_213_FC1
|
||||
|
||||
#elif defined(HELTEC_WIRELESS_PAPER_V1_0)
|
||||
// 2.13" 122x250 - DEPG0213BNS800
|
||||
#define TECHO_DISPLAY_MODEL GxEPD2_213_BN
|
||||
|
||||
#endif
|
||||
|
||||
GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT> *adafruitDisplay;
|
||||
- 1.54 inch
|
||||
EINK_DISPLAY_MODEL: GxEPD2_154_M09
|
||||
EINK_WIDTH: 200
|
||||
EINK_HEIGHT: 200
|
||||
*/
|
||||
|
||||
// Constructor
|
||||
EInkDisplay::EInkDisplay(uint8_t address, int sda, int scl, OLEDDISPLAY_GEOMETRY geometry, HW_I2C i2cBus)
|
||||
{
|
||||
#if defined(TTGO_T_ECHO)
|
||||
setGeometry(GEOMETRY_RAWMODE, 200, 200);
|
||||
#elif defined(RAK4630)
|
||||
|
||||
// GxEPD2_213_BN - RAK14000 2.13 inch b/w 250x122
|
||||
setGeometry(GEOMETRY_RAWMODE, 250, 122);
|
||||
|
||||
// GxEPD2_420_M01
|
||||
// setGeometry(GEOMETRY_RAWMODE, 300, 400);
|
||||
|
||||
// GxEPD2_290_T5D
|
||||
// setGeometry(GEOMETRY_RAWMODE, 296, 128);
|
||||
|
||||
// GxEPD2_154_M09
|
||||
// setGeometry(GEOMETRY_RAWMODE, 200, 200);
|
||||
|
||||
#elif defined(HELTEC_WIRELESS_PAPER_V1_0)
|
||||
|
||||
// The display's memory is actually 128px x 250px
|
||||
// Setting the buffersize manually prevents 122/8 truncating to a 15 byte width
|
||||
// (Or something like that..)
|
||||
|
||||
// Set dimensions in OLEDDisplay base class
|
||||
this->geometry = GEOMETRY_RAWMODE;
|
||||
this->displayWidth = 250;
|
||||
this->displayHeight = 122;
|
||||
this->displayBufferSize = 250 * (128 / 8);
|
||||
this->displayWidth = EINK_WIDTH;
|
||||
this->displayHeight = EINK_HEIGHT;
|
||||
|
||||
#elif defined(HELTEC_WIRELESS_PAPER)
|
||||
// GxEPD2_213_BN - 2.13 inch b/w 250x122
|
||||
setGeometry(GEOMETRY_RAWMODE, 250, 122);
|
||||
#elif defined(MAKERPYTHON)
|
||||
// GxEPD2_290_T5D
|
||||
setGeometry(GEOMETRY_RAWMODE, 296, 128);
|
||||
// Round shortest side up to nearest byte, to prevent truncation causing an undersized buffer
|
||||
uint16_t shortSide = min(EINK_WIDTH, EINK_HEIGHT);
|
||||
uint16_t longSide = max(EINK_WIDTH, EINK_HEIGHT);
|
||||
if (shortSide % 8 != 0)
|
||||
shortSide = (shortSide | 7) + 1;
|
||||
|
||||
#elif defined(PCA10059)
|
||||
|
||||
// GxEPD2_420_M01
|
||||
setGeometry(GEOMETRY_RAWMODE, 300, 400);
|
||||
|
||||
#elif defined(M5_COREINK)
|
||||
|
||||
// M5Stack_CoreInk 200x200
|
||||
// 1.54 inch 200x200 - GxEPD2_154_M09
|
||||
setGeometry(GEOMETRY_RAWMODE, EPD_HEIGHT, EPD_WIDTH);
|
||||
#elif defined(my)
|
||||
|
||||
// GxEPD2_290_T5D
|
||||
setGeometry(GEOMETRY_RAWMODE, 296, 128);
|
||||
LOG_DEBUG("GEOMETRY_RAWMODE, 296, 128\n");
|
||||
|
||||
#endif
|
||||
// setGeometry(GEOMETRY_RAWMODE, 128, 64); // old resolution
|
||||
// setGeometry(GEOMETRY_128_64); // We originally used this because I wasn't sure if rawmode worked - it does
|
||||
this->displayBufferSize = longSide * (shortSide / 8);
|
||||
}
|
||||
|
||||
// FIXME quick hack to limit drawing to a very slow rate
|
||||
uint32_t lastDrawMsec;
|
||||
|
||||
/**
|
||||
* Force a display update if we haven't drawn within the specified msecLimit
|
||||
*/
|
||||
@@ -125,13 +53,6 @@ bool EInkDisplay::forceDisplay(uint32_t msecLimit)
|
||||
// No need to grab this lock because we are on our own SPI bus
|
||||
// concurrency::LockGuard g(spiLock);
|
||||
|
||||
#if defined(USE_EINK_DYNAMIC_PARTIAL)
|
||||
// Decide if update is partial or full
|
||||
bool continueUpdate = determineRefreshMode();
|
||||
if (!continueUpdate)
|
||||
return false;
|
||||
#else
|
||||
|
||||
uint32_t now = millis();
|
||||
uint32_t sinceLast = now - lastDrawMsec;
|
||||
|
||||
@@ -140,55 +61,34 @@ bool EInkDisplay::forceDisplay(uint32_t msecLimit)
|
||||
else
|
||||
return false;
|
||||
|
||||
#endif
|
||||
|
||||
// FIXME - only draw bits have changed (use backbuf similar to the other displays)
|
||||
// tft.drawBitmap(0, 0, buffer, 128, 64, TFT_YELLOW, TFT_BLACK);
|
||||
for (uint32_t y = 0; y < displayHeight; y++) {
|
||||
for (uint32_t x = 0; x < displayWidth; x++) {
|
||||
// get src pixel in the page based ordering the OLED lib uses FIXME, super inefficient
|
||||
auto b = buffer[x + (y / 8) * displayWidth];
|
||||
auto isset = b & (1 << (y & 7));
|
||||
adafruitDisplay->drawPixel(x, y, isset ? COLORED : UNCOLORED);
|
||||
adafruitDisplay->drawPixel(x, y, isset ? GxEPD_BLACK : GxEPD_WHITE);
|
||||
}
|
||||
}
|
||||
|
||||
// Trigger the refresh in GxEPD2
|
||||
LOG_DEBUG("Updating E-Paper... ");
|
||||
|
||||
#if defined(TTGO_T_ECHO)
|
||||
adafruitDisplay->nextPage();
|
||||
#elif defined(RAK4630) || defined(MAKERPYTHON)
|
||||
|
||||
// RAK14000 2.13 inch b/w 250x122 actually now does support partial updates
|
||||
|
||||
// Full update mode (slow)
|
||||
// adafruitDisplay->display(false); // FIXME, use partial update mode
|
||||
|
||||
// Only enable for e-Paper with support for partial updates and comment out above adafruitDisplay->display(false);
|
||||
// 1.54 inch 200x200 - GxEPD2_154_M09
|
||||
// 2.13 inch 250x122 - GxEPD2_213_BN
|
||||
// 2.9 inch 296x128 - GxEPD2_290_T5D
|
||||
// 4.2 inch 300x400 - GxEPD2_420_M01
|
||||
adafruitDisplay->nextPage();
|
||||
|
||||
#elif defined(PCA10059) || defined(M5_COREINK)
|
||||
adafruitDisplay->nextPage();
|
||||
#elif defined(HELTEC_WIRELESS_PAPER_V1_0)
|
||||
adafruitDisplay->nextPage();
|
||||
#elif defined(HELTEC_WIRELESS_PAPER)
|
||||
adafruitDisplay->nextPage();
|
||||
#elif defined(PRIVATE_HW) || defined(my)
|
||||
adafruitDisplay->nextPage();
|
||||
// End the update process
|
||||
endUpdate();
|
||||
|
||||
#endif
|
||||
|
||||
// Put screen to sleep to save power (possibly not necessary because we already did poweroff inside of display)
|
||||
adafruitDisplay->hibernate();
|
||||
LOG_DEBUG("done\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// End the update process - virtual method, overriden in derived class
|
||||
void EInkDisplay::endUpdate()
|
||||
{
|
||||
// Power off display hardware, then deep-sleep (Except Wireless Paper V1.1, no deep-sleep)
|
||||
adafruitDisplay->hibernate();
|
||||
}
|
||||
|
||||
// Write the buffer to the display memory
|
||||
void EInkDisplay::display(void)
|
||||
{
|
||||
@@ -196,15 +96,9 @@ void EInkDisplay::display(void)
|
||||
// at least one forceDisplay() keyframe. This prevents flashing when we should the critical
|
||||
// bootscreen (that we want to look nice)
|
||||
|
||||
#ifdef USE_EINK_DYNAMIC_PARTIAL
|
||||
lowPriority();
|
||||
forceDisplay();
|
||||
highPriority();
|
||||
#else
|
||||
if (lastDrawMsec) {
|
||||
forceDisplay(slowUpdateMsec); // Show the first screen a few seconds after boot, then slower
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Send a command to the display (low level function)
|
||||
@@ -219,16 +113,11 @@ void EInkDisplay::setDetected(uint8_t detected)
|
||||
(void)detected;
|
||||
}
|
||||
|
||||
// Connect to the display
|
||||
// Connect to the display - variant specific
|
||||
bool EInkDisplay::connect()
|
||||
{
|
||||
LOG_INFO("Doing EInk init\n");
|
||||
|
||||
#ifdef PIN_EINK_PWR_ON
|
||||
pinMode(PIN_EINK_PWR_ON, OUTPUT);
|
||||
digitalWrite(PIN_EINK_PWR_ON, HIGH); // If we need to assert a pin to power external peripherals
|
||||
#endif
|
||||
|
||||
#ifdef PIN_EINK_EN
|
||||
// backlight power, HIGH is backlight on, LOW is off
|
||||
pinMode(PIN_EINK_EN, OUTPUT);
|
||||
@@ -237,9 +126,9 @@ bool EInkDisplay::connect()
|
||||
|
||||
#if defined(TTGO_T_ECHO)
|
||||
{
|
||||
auto lowLevel = new TECHO_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY, SPI1);
|
||||
auto lowLevel = new EINK_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY, SPI1);
|
||||
|
||||
adafruitDisplay = new GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT>(*lowLevel);
|
||||
adafruitDisplay = new GxEPD2_BW<EINK_DISPLAY_MODEL, EINK_DISPLAY_MODEL::HEIGHT>(*lowLevel);
|
||||
adafruitDisplay->init();
|
||||
adafruitDisplay->setRotation(3);
|
||||
adafruitDisplay->setPartialWindow(0, 0, displayWidth, displayHeight);
|
||||
@@ -247,15 +136,12 @@ bool EInkDisplay::connect()
|
||||
#elif defined(RAK4630) || defined(MAKERPYTHON)
|
||||
{
|
||||
if (eink_found) {
|
||||
auto lowLevel = new TECHO_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY);
|
||||
|
||||
adafruitDisplay = new GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT>(*lowLevel);
|
||||
|
||||
auto lowLevel = new EINK_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY);
|
||||
adafruitDisplay = new GxEPD2_BW<EINK_DISPLAY_MODEL, EINK_DISPLAY_MODEL::HEIGHT>(*lowLevel);
|
||||
adafruitDisplay->init(115200, true, 10, false, SPI1, SPISettings(4000000, MSBFIRST, SPI_MODE0));
|
||||
|
||||
// RAK14000 2.13 inch b/w 250x122 does actually now support partial updates
|
||||
// RAK14000 2.13 inch b/w 250x122 does actually now support fast refresh
|
||||
adafruitDisplay->setRotation(3);
|
||||
// Partial update support for 1.54, 2.13 RAK14000 b/w , 2.9 and 4.2
|
||||
// Fast refresh support for 1.54, 2.13 RAK14000 b/w , 2.9 and 4.2
|
||||
// adafruitDisplay->setRotation(1);
|
||||
adafruitDisplay->setPartialWindow(0, 0, displayWidth, displayHeight);
|
||||
} else {
|
||||
@@ -263,7 +149,7 @@ bool EInkDisplay::connect()
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(HELTEC_WIRELESS_PAPER_V1_0)
|
||||
#elif defined(HELTEC_WIRELESS_PAPER_V1_0) || defined(HELTEC_WIRELESS_PAPER)
|
||||
{
|
||||
// Is this a normal boot, or a wake from deep sleep?
|
||||
esp_sleep_wakeup_cause_t wakeReason = esp_sleep_get_wakeup_cause();
|
||||
@@ -292,182 +178,39 @@ bool EInkDisplay::connect()
|
||||
delay(100);
|
||||
|
||||
// Create GxEPD2 objects
|
||||
auto lowLevel = new TECHO_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY, *hspi);
|
||||
adafruitDisplay = new GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT>(*lowLevel);
|
||||
auto lowLevel = new EINK_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY, *hspi);
|
||||
adafruitDisplay = new GxEPD2_BW<EINK_DISPLAY_MODEL, EINK_DISPLAY_MODEL::HEIGHT>(*lowLevel);
|
||||
|
||||
// Init GxEPD2
|
||||
adafruitDisplay->init();
|
||||
adafruitDisplay->setRotation(3);
|
||||
}
|
||||
#elif defined(HELTEC_WIRELESS_PAPER)
|
||||
{
|
||||
hspi = new SPIClass(HSPI);
|
||||
hspi->begin(PIN_EINK_SCLK, -1, PIN_EINK_MOSI, PIN_EINK_CS); // SCLK, MISO, MOSI, SS
|
||||
delay(100);
|
||||
pinMode(Vext, OUTPUT);
|
||||
digitalWrite(Vext, LOW);
|
||||
delay(100);
|
||||
auto lowLevel = new TECHO_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY, *hspi);
|
||||
adafruitDisplay = new GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT>(*lowLevel);
|
||||
adafruitDisplay->init();
|
||||
adafruitDisplay->setRotation(3);
|
||||
adafruitDisplay->clearScreen(); // Clearing now, so the boot logo will draw nice and smoothe (fast refresh)
|
||||
}
|
||||
#elif defined(PCA10059)
|
||||
{
|
||||
auto lowLevel = new TECHO_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY);
|
||||
adafruitDisplay = new GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT>(*lowLevel);
|
||||
auto lowLevel = new EINK_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY);
|
||||
adafruitDisplay = new GxEPD2_BW<EINK_DISPLAY_MODEL, EINK_DISPLAY_MODEL::HEIGHT>(*lowLevel);
|
||||
adafruitDisplay->init(115200, true, 10, false, SPI1, SPISettings(4000000, MSBFIRST, SPI_MODE0));
|
||||
adafruitDisplay->setRotation(3);
|
||||
adafruitDisplay->setPartialWindow(0, 0, displayWidth, displayHeight);
|
||||
}
|
||||
#elif defined(M5_COREINK)
|
||||
auto lowLevel = new TECHO_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY);
|
||||
adafruitDisplay = new GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT>(*lowLevel);
|
||||
auto lowLevel = new EINK_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY);
|
||||
adafruitDisplay = new GxEPD2_BW<EINK_DISPLAY_MODEL, EINK_DISPLAY_MODEL::HEIGHT>(*lowLevel);
|
||||
adafruitDisplay->init(115200, true, 40, false, SPI, SPISettings(4000000, MSBFIRST, SPI_MODE0));
|
||||
adafruitDisplay->setRotation(0);
|
||||
adafruitDisplay->setPartialWindow(0, 0, EPD_WIDTH, EPD_HEIGHT);
|
||||
#elif defined(my)
|
||||
adafruitDisplay->setPartialWindow(0, 0, EINK_WIDTH, EINK_HEIGHT);
|
||||
#elif defined(my) || defined(ESP32_S3_PICO)
|
||||
{
|
||||
auto lowLevel = new TECHO_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY);
|
||||
adafruitDisplay = new GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT>(*lowLevel);
|
||||
auto lowLevel = new EINK_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY);
|
||||
adafruitDisplay = new GxEPD2_BW<EINK_DISPLAY_MODEL, EINK_DISPLAY_MODEL::HEIGHT>(*lowLevel);
|
||||
adafruitDisplay->init(115200, true, 40, false, SPI, SPISettings(4000000, MSBFIRST, SPI_MODE0));
|
||||
adafruitDisplay->setRotation(1);
|
||||
adafruitDisplay->setPartialWindow(0, 0, EPD_WIDTH, EPD_HEIGHT);
|
||||
adafruitDisplay->setPartialWindow(0, 0, EINK_WIDTH, EINK_HEIGHT);
|
||||
}
|
||||
#endif
|
||||
|
||||
// adafruitDisplay->setFullWindow();
|
||||
// adafruitDisplay->fillScreen(UNCOLORED);
|
||||
// adafruitDisplay->drawCircle(100, 100, 20, COLORED);
|
||||
// adafruitDisplay->display(false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Use a mix of full and partial refreshes, to preserve display health
|
||||
#if defined(USE_EINK_DYNAMIC_PARTIAL)
|
||||
|
||||
// Suggest that subsequent updates should use partial-refresh
|
||||
void EInkDisplay::highPriority()
|
||||
{
|
||||
isHighPriority = true;
|
||||
}
|
||||
|
||||
// Suggest that subsequent updates should use full-refresh
|
||||
void EInkDisplay::lowPriority()
|
||||
{
|
||||
isHighPriority = false;
|
||||
}
|
||||
|
||||
// configure display for partial-refresh
|
||||
void EInkDisplay::configForPartialRefresh()
|
||||
{
|
||||
// Display-specific code can go here
|
||||
#if defined(PRIVATE_HW)
|
||||
#else
|
||||
// Otherwise:
|
||||
adafruitDisplay->setPartialWindow(0, 0, adafruitDisplay->width(), adafruitDisplay->height());
|
||||
#endif
|
||||
}
|
||||
|
||||
// Configure display for full-refresh
|
||||
void EInkDisplay::configForFullRefresh()
|
||||
{
|
||||
// Display-specific code can go here
|
||||
#if defined(PRIVATE_HW)
|
||||
#else
|
||||
// Otherwise:
|
||||
adafruitDisplay->setFullWindow();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool EInkDisplay::newImageMatchesOld()
|
||||
{
|
||||
uint32_t newImageHash = 0;
|
||||
|
||||
// Generate hash: sum all bytes in the image buffer
|
||||
for (uint16_t b = 0; b < (displayWidth / 8) * displayHeight; b++) {
|
||||
newImageHash += buffer[b];
|
||||
}
|
||||
|
||||
// Compare hashes
|
||||
bool hashMatches = (newImageHash == prevImageHash);
|
||||
|
||||
// Update the cached hash
|
||||
prevImageHash = newImageHash;
|
||||
|
||||
// Return the comparison result
|
||||
return hashMatches;
|
||||
}
|
||||
|
||||
// Change between partial and full refresh config, or skip update, balancing urgency and display health.
|
||||
bool EInkDisplay::determineRefreshMode()
|
||||
{
|
||||
uint32_t now = millis();
|
||||
uint32_t sinceLast = now - lastUpdateMsec;
|
||||
|
||||
// If rate-limiting dropped a high-priority update:
|
||||
// promote this update, so it runs ASAP
|
||||
if (missedHighPriorityUpdate) {
|
||||
isHighPriority = true;
|
||||
missedHighPriorityUpdate = false;
|
||||
}
|
||||
|
||||
// Abort: if too soon for a new frame
|
||||
if (isHighPriority && partialRefreshCount > 0 && sinceLast < highPriorityLimitMsec) {
|
||||
LOG_DEBUG("Update skipped: exceeded EINK_HIGHPRIORITY_LIMIT_SECONDS\n");
|
||||
missedHighPriorityUpdate = true;
|
||||
return false;
|
||||
}
|
||||
if (!isHighPriority && sinceLast < lowPriorityLimitMsec) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if old image (partial) should be redrawn (as full), for image quality
|
||||
if (partialRefreshCount > 0 && !isHighPriority)
|
||||
needsFull = true;
|
||||
|
||||
// If too many partials, require a full-refresh (display health)
|
||||
if (partialRefreshCount >= partialRefreshLimit)
|
||||
needsFull = true;
|
||||
|
||||
// If image matches
|
||||
if (newImageMatchesOld()) {
|
||||
// If low priority: limit rate
|
||||
// otherwise, every loop() will run the hash method
|
||||
if (!isHighPriority)
|
||||
lastUpdateMsec = now;
|
||||
|
||||
// If update is *not* for display health or image quality, skip it
|
||||
if (!needsFull)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Conditions assessed - not skipping - load the appropriate config
|
||||
|
||||
// If options require a full refresh
|
||||
if (!isHighPriority || needsFull) {
|
||||
if (partialRefreshCount > 0)
|
||||
configForFullRefresh();
|
||||
|
||||
LOG_DEBUG("Conditions met for full-refresh\n");
|
||||
partialRefreshCount = 0;
|
||||
needsFull = false;
|
||||
}
|
||||
|
||||
// If options allow a partial refresh
|
||||
else {
|
||||
if (partialRefreshCount == 0)
|
||||
configForPartialRefresh();
|
||||
|
||||
LOG_DEBUG("Conditions met for partial-refresh\n");
|
||||
partialRefreshCount++;
|
||||
}
|
||||
|
||||
lastUpdateMsec = now; // Mark time for rate limiting
|
||||
return true; // Instruct calling method to continue with update
|
||||
}
|
||||
|
||||
#endif // End USE_EINK_DYNAMIC_PARTIAL
|
||||
|
||||
#endif
|
||||
@@ -1,8 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef USE_EINK
|
||||
|
||||
#include "GxEPD2_BW.h"
|
||||
#include <OLEDDisplay.h>
|
||||
|
||||
#if defined(HELTEC_WIRELESS_PAPER_V1_0)
|
||||
#if defined(HELTEC_WIRELESS_PAPER_V1_0) || defined(HELTEC_WIRELESS_PAPER)
|
||||
// Re-enable SPI after deep sleep: rtc_gpio_hold_dis()
|
||||
#include "driver/rtc_io.h"
|
||||
#endif
|
||||
@@ -10,12 +13,15 @@
|
||||
/**
|
||||
* An adapter class that allows using the GxEPD2 library as if it was an OLEDDisplay implementation.
|
||||
*
|
||||
* Note: EInkDynamicDisplay derives from this class.
|
||||
*
|
||||
* Remaining TODO:
|
||||
* optimize display() to only draw changed pixels (see other OLED subclasses for examples)
|
||||
* implement displayOn/displayOff to turn off the TFT device (and backlight)
|
||||
* Use the fast NRF52 SPI API rather than the slow standard arduino version
|
||||
*
|
||||
* turn radio back on - currently with both on spi bus is fucked? or are we leaving chip select asserted?
|
||||
* Suggestion: perhaps similar to HELTEC_WIRELESS_PAPER issue, which resolved with rtc_gpio_hold_dis()
|
||||
*/
|
||||
class EInkDisplay : public OLEDDisplay
|
||||
{
|
||||
@@ -37,7 +43,14 @@ class EInkDisplay : public OLEDDisplay
|
||||
*
|
||||
* @return true if we did draw the screen
|
||||
*/
|
||||
bool forceDisplay(uint32_t msecLimit = 1000);
|
||||
virtual bool forceDisplay(uint32_t msecLimit = 1000);
|
||||
|
||||
/**
|
||||
* Run any code needed to complete an update, after the physical refresh has completed.
|
||||
* Split from forceDisplay(), to enable async refresh in derived EInkDynamicDisplay class.
|
||||
*
|
||||
*/
|
||||
virtual void endUpdate();
|
||||
|
||||
/**
|
||||
* shim to make the abstraction happy
|
||||
@@ -55,67 +68,17 @@ class EInkDisplay : public OLEDDisplay
|
||||
// Connect to the display
|
||||
virtual bool connect() override;
|
||||
|
||||
#if defined(USE_EINK_DYNAMIC_PARTIAL)
|
||||
// Full, partial, or skip: balance urgency with display health
|
||||
// AdafruitGFX display object - instantiated in connect(), variant specific
|
||||
GxEPD2_BW<EINK_DISPLAY_MODEL, EINK_DISPLAY_MODEL::HEIGHT> *adafruitDisplay = NULL;
|
||||
|
||||
// Use partial refresh if EITHER:
|
||||
// * highPriority() was set
|
||||
// * a highPriority() update was previously skipped, for rate-limiting - (EINK_HIGHPRIORITY_LIMIT_SECONDS)
|
||||
|
||||
// Use full refresh if EITHER:
|
||||
// * lowPriority() was set
|
||||
// * too many partial updates in a row: protect display - (EINK_PARTIAL_REPEAT_LIMIT)
|
||||
// * no recent updates, and last update was partial: redraw for image quality (EINK_LOWPRIORITY_LIMIT_SECONDS)
|
||||
|
||||
// Rate limit if:
|
||||
// * lowPriority() - (EINK_LOWPRIORITY_LIMIT_SECONDS)
|
||||
// * highPriority(), if multiple partials have run back-to-back - (EINK_HIGHPRIORITY_LIMIT_SECONDS)
|
||||
|
||||
// Skip update entirely if ALL criteria met:
|
||||
// * new image matches old image
|
||||
// * lowPriority()
|
||||
// * not redrawing for image quality
|
||||
// * not refreshing for display health
|
||||
|
||||
// ------------------------------------
|
||||
|
||||
// To implement for your E-Ink display:
|
||||
// * edit configForPartialRefresh()
|
||||
// * edit configForFullRefresh()
|
||||
// * add macros to variant.h, and adjust to taste:
|
||||
|
||||
/*
|
||||
#define USE_EINK_DYNAMIC_PARTIAL
|
||||
#define EINK_LOWPRIORITY_LIMIT_SECONDS 30
|
||||
#define EINK_HIGHPRIORITY_LIMIT_SECONDS 1
|
||||
#define EINK_PARTIAL_REPEAT_LIMIT 5
|
||||
*/
|
||||
|
||||
public:
|
||||
void highPriority(); // Suggest partial refresh
|
||||
void lowPriority(); // Suggest full refresh
|
||||
|
||||
protected:
|
||||
void configForPartialRefresh(); // Display specific code to select partial refresh mode
|
||||
void configForFullRefresh(); // Display specific code to return to full refresh mode
|
||||
bool newImageMatchesOld(); // Is the new update actually different to the last image?
|
||||
bool determineRefreshMode(); // Called immediately before data written to display - choose refresh mode, or abort update
|
||||
|
||||
bool isHighPriority = true; // Does the method calling update believe that this is urgent?
|
||||
bool needsFull = false; // Is a full refresh forced? (display health)
|
||||
bool missedHighPriorityUpdate = false; // Was a high priority update skipped for rate-limiting?
|
||||
uint16_t partialRefreshCount = 0; // How many partials have occurred since last full refresh?
|
||||
uint32_t lastUpdateMsec = 0; // When did the last update occur?
|
||||
uint32_t prevImageHash = 0; // Used to check if update will change screen image (skippable or not)
|
||||
|
||||
// Set in variant.h
|
||||
const uint32_t lowPriorityLimitMsec = (uint32_t)1000 * EINK_LOWPRIORITY_LIMIT_SECONDS; // Max rate for partial refreshes
|
||||
const uint32_t highPriorityLimitMsec = (uint32_t)1000 * EINK_HIGHPRIORITY_LIMIT_SECONDS; // Max rate for full refreshes
|
||||
const uint32_t partialRefreshLimit = EINK_PARTIAL_REPEAT_LIMIT; // Max consecutive partials, before full is triggered
|
||||
|
||||
#else // !USE_EINK_DYNAMIC_PARTIAL
|
||||
// Tolerate calls to these methods anywhere, just to be safe
|
||||
void highPriority() {}
|
||||
void lowPriority() {}
|
||||
// If display uses HSPI
|
||||
#if defined(HELTEC_WIRELESS_PAPER) || defined(HELTEC_WIRELESS_PAPER_V1_0)
|
||||
SPIClass *hspi = NULL;
|
||||
#endif
|
||||
|
||||
private:
|
||||
// FIXME quick hack to limit drawing to a very slow rate
|
||||
uint32_t lastDrawMsec = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
500
src/graphics/EInkDynamicDisplay.cpp
Normal file
500
src/graphics/EInkDynamicDisplay.cpp
Normal file
@@ -0,0 +1,500 @@
|
||||
#include "configuration.h"
|
||||
|
||||
#if defined(USE_EINK) && defined(USE_EINK_DYNAMICDISPLAY)
|
||||
#include "EInkDynamicDisplay.h"
|
||||
|
||||
// Constructor
|
||||
EInkDynamicDisplay::EInkDynamicDisplay(uint8_t address, int sda, int scl, OLEDDISPLAY_GEOMETRY geometry, HW_I2C i2cBus)
|
||||
: EInkDisplay(address, sda, scl, geometry, i2cBus)
|
||||
{
|
||||
// If tracking ghost pixels, grab memory
|
||||
#ifdef EINK_LIMIT_GHOSTING_PX
|
||||
dirtyPixels = new uint8_t[EInkDisplay::displayBufferSize](); // Init with zeros
|
||||
#endif
|
||||
}
|
||||
|
||||
// Destructor
|
||||
EInkDynamicDisplay::~EInkDynamicDisplay()
|
||||
{
|
||||
// If we were tracking ghost pixels, free the memory
|
||||
#ifdef EINK_LIMIT_GHOSTING_PX
|
||||
delete[] dirtyPixels;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Screen requests a BACKGROUND frame
|
||||
void EInkDynamicDisplay::display()
|
||||
{
|
||||
addFrameFlag(BACKGROUND);
|
||||
update();
|
||||
}
|
||||
|
||||
// Screen requests a RESPONSIVE frame
|
||||
bool EInkDynamicDisplay::forceDisplay(uint32_t msecLimit)
|
||||
{
|
||||
addFrameFlag(RESPONSIVE);
|
||||
return update(); // (Unutilized) Base class promises to return true if update ran
|
||||
}
|
||||
|
||||
// Add flag for the next frame
|
||||
void EInkDynamicDisplay::addFrameFlag(frameFlagTypes flag)
|
||||
{
|
||||
// OR the new flag into the existing flags
|
||||
this->frameFlags = (frameFlagTypes)(this->frameFlags | flag);
|
||||
}
|
||||
|
||||
// GxEPD2 code to set fast refresh
|
||||
void EInkDynamicDisplay::configForFastRefresh()
|
||||
{
|
||||
// Variant-specific code can go here
|
||||
#if defined(PRIVATE_HW)
|
||||
#else
|
||||
// Otherwise:
|
||||
adafruitDisplay->setPartialWindow(0, 0, adafruitDisplay->width(), adafruitDisplay->height());
|
||||
#endif
|
||||
}
|
||||
|
||||
// GxEPD2 code to set full refresh
|
||||
void EInkDynamicDisplay::configForFullRefresh()
|
||||
{
|
||||
// Variant-specific code can go here
|
||||
#if defined(PRIVATE_HW)
|
||||
#else
|
||||
// Otherwise:
|
||||
adafruitDisplay->setFullWindow();
|
||||
#endif
|
||||
}
|
||||
|
||||
// Run any relevant GxEPD2 code, so next update will use correct refresh type
|
||||
void EInkDynamicDisplay::applyRefreshMode()
|
||||
{
|
||||
// Change from FULL to FAST
|
||||
if (currentConfig == FULL && refresh == FAST) {
|
||||
configForFastRefresh();
|
||||
currentConfig = FAST;
|
||||
}
|
||||
|
||||
// Change from FAST back to FULL
|
||||
else if (currentConfig == FAST && refresh == FULL) {
|
||||
configForFullRefresh();
|
||||
currentConfig = FULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Update fastRefreshCount
|
||||
void EInkDynamicDisplay::adjustRefreshCounters()
|
||||
{
|
||||
if (refresh == FAST)
|
||||
fastRefreshCount++;
|
||||
|
||||
else if (refresh == FULL)
|
||||
fastRefreshCount = 0;
|
||||
}
|
||||
|
||||
// Trigger the display update by calling base class
|
||||
bool EInkDynamicDisplay::update()
|
||||
{
|
||||
// Detemine the refresh mode to use, and start the update
|
||||
bool refreshApproved = determineMode();
|
||||
if (refreshApproved) {
|
||||
EInkDisplay::forceDisplay(0); // Bypass base class' own rate-limiting system
|
||||
storeAndReset(); // Store the result of this loop for next time. Note: call *before* endOrDetach()
|
||||
endOrDetach(); // endUpdate() right now, or set the async refresh flag (if FULL and HAS_EINK_ASYNCFULL)
|
||||
} else
|
||||
storeAndReset(); // No update, no post-update code, just store the results
|
||||
|
||||
return refreshApproved; // (Unutilized) Base class promises to return true if update ran
|
||||
}
|
||||
|
||||
// Figure out who runs the post-update code
|
||||
void EInkDynamicDisplay::endOrDetach()
|
||||
{
|
||||
// If the GxEPD2 version reports that it has the async modifications
|
||||
#ifdef HAS_EINK_ASYNCFULL
|
||||
if (previousRefresh == FULL) {
|
||||
asyncRefreshRunning = true; // Set the flag - picked up at start of determineMode(), next loop.
|
||||
|
||||
if (previousFrameFlags & BLOCKING)
|
||||
awaitRefresh();
|
||||
else
|
||||
LOG_DEBUG("Async full-refresh begins\n");
|
||||
}
|
||||
|
||||
// Fast Refresh
|
||||
else if (previousRefresh == FAST)
|
||||
EInkDisplay::endUpdate(); // Still block while updating, but EInkDisplay needs us to call endUpdate() ourselves.
|
||||
|
||||
// Fallback - If using an unmodified version of GxEPD2 for some reason
|
||||
#else
|
||||
if (previousRefresh == FULL || previousRefresh == FAST) { // If refresh wasn't skipped (on unspecified..)
|
||||
LOG_WARN(
|
||||
"GxEPD2 version has not been modified to support async refresh; using fallback behavior. Please update lib_deps in "
|
||||
"variant's platformio.ini file\n");
|
||||
EInkDisplay::endUpdate();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Assess situation, pick a refresh type
|
||||
bool EInkDynamicDisplay::determineMode()
|
||||
{
|
||||
checkInitialized();
|
||||
checkForPromotion();
|
||||
#if defined(HAS_EINK_ASYNCFULL)
|
||||
checkAsyncFullRefresh();
|
||||
#endif
|
||||
checkRateLimiting();
|
||||
|
||||
// If too soon for a new frame, or display busy, abort early
|
||||
if (refresh == SKIPPED)
|
||||
return false; // No refresh
|
||||
|
||||
// -- New frame is due --
|
||||
|
||||
resetRateLimiting(); // Once determineMode() ends, will have to wait again
|
||||
hashImage(); // Generate here, so we can still copy it to previousImageHash, even if we skip the comparison check
|
||||
LOG_DEBUG("determineMode(): "); // Begin log entry
|
||||
|
||||
// Once mode determined, any remaining checks will bypass
|
||||
checkCosmetic();
|
||||
checkDemandingFast();
|
||||
checkFrameMatchesPrevious();
|
||||
checkConsecutiveFastRefreshes();
|
||||
#ifdef EINK_LIMIT_GHOSTING_PX
|
||||
checkExcessiveGhosting();
|
||||
#endif
|
||||
checkFastRequested();
|
||||
|
||||
if (refresh == UNSPECIFIED)
|
||||
LOG_WARN("There was a flaw in the determineMode() logic.\n");
|
||||
|
||||
// -- Decision has been reached --
|
||||
applyRefreshMode();
|
||||
adjustRefreshCounters();
|
||||
|
||||
#ifdef EINK_LIMIT_GHOSTING_PX
|
||||
// Full refresh clears any ghosting
|
||||
if (refresh == FULL)
|
||||
resetGhostPixelTracking();
|
||||
#endif
|
||||
|
||||
// Return - call a refresh or not?
|
||||
if (refresh == SKIPPED)
|
||||
return false; // Don't trigger a refresh
|
||||
else
|
||||
return true; // Do trigger a refresh
|
||||
}
|
||||
|
||||
// Is this the very first frame?
|
||||
void EInkDynamicDisplay::checkInitialized()
|
||||
{
|
||||
if (!initialized) {
|
||||
// Undo GxEPD2_BW::partialWindow(), if set by developer in EInkDisplay::connect()
|
||||
configForFullRefresh();
|
||||
|
||||
// Clear any existing image, so we can draw logo with fast-refresh, but also to set GxEPD2_EPD::_initial_write
|
||||
adafruitDisplay->clearScreen();
|
||||
|
||||
LOG_DEBUG("initialized, ");
|
||||
initialized = true;
|
||||
|
||||
// Use a fast-refresh for the next frame; no skipping or else blank screen when waking from deep sleep
|
||||
addFrameFlag(DEMAND_FAST);
|
||||
}
|
||||
}
|
||||
|
||||
// Was a frame skipped (rate, display busy) that should have been a FAST refresh?
|
||||
void EInkDynamicDisplay::checkForPromotion()
|
||||
{
|
||||
// If a frame was skipped (rate, display busy), then promote a BACKGROUND frame
|
||||
// Because we DID want a RESPONSIVE/COSMETIC/DEMAND_FULL frame last time, we just didn't get it
|
||||
|
||||
switch (previousReason) {
|
||||
case ASYNC_REFRESH_BLOCKED_DEMANDFAST:
|
||||
addFrameFlag(DEMAND_FAST);
|
||||
break;
|
||||
case ASYNC_REFRESH_BLOCKED_COSMETIC:
|
||||
addFrameFlag(COSMETIC);
|
||||
break;
|
||||
case ASYNC_REFRESH_BLOCKED_RESPONSIVE:
|
||||
case EXCEEDED_RATELIMIT_FAST:
|
||||
addFrameFlag(RESPONSIVE);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Is it too soon for another frame of this type?
|
||||
void EInkDynamicDisplay::checkRateLimiting()
|
||||
{
|
||||
uint32_t now = millis();
|
||||
|
||||
// Sanity check: millis() overflow - just let the update run..
|
||||
if (previousRunMs > now)
|
||||
return;
|
||||
|
||||
// Skip update: too soon for BACKGROUND
|
||||
if (frameFlags == BACKGROUND) {
|
||||
if (now - previousRunMs < EINK_LIMIT_RATE_BACKGROUND_SEC * 1000) {
|
||||
refresh = SKIPPED;
|
||||
reason = EXCEEDED_RATELIMIT_FULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// No rate-limit for these special cases
|
||||
if (frameFlags & COSMETIC || frameFlags & DEMAND_FAST)
|
||||
return;
|
||||
|
||||
// Skip update: too soon for RESPONSIVE
|
||||
if (frameFlags & RESPONSIVE) {
|
||||
if (now - previousRunMs < EINK_LIMIT_RATE_RESPONSIVE_SEC * 1000) {
|
||||
refresh = SKIPPED;
|
||||
reason = EXCEEDED_RATELIMIT_FAST;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Is this frame COSMETIC (splash screens?)
|
||||
void EInkDynamicDisplay::checkCosmetic()
|
||||
{
|
||||
// If a decision was already reached, don't run the check
|
||||
if (refresh != UNSPECIFIED)
|
||||
return;
|
||||
|
||||
// A full refresh is requested for cosmetic purposes: we have a decision
|
||||
if (frameFlags & COSMETIC) {
|
||||
refresh = FULL;
|
||||
reason = FLAGGED_COSMETIC;
|
||||
LOG_DEBUG("refresh=FULL, reason=FLAGGED_COSMETIC, frameFlags=0x%x\n", frameFlags);
|
||||
}
|
||||
}
|
||||
|
||||
// Is this a one-off special circumstance, where we REALLY want a fast refresh?
|
||||
void EInkDynamicDisplay::checkDemandingFast()
|
||||
{
|
||||
// If a decision was already reached, don't run the check
|
||||
if (refresh != UNSPECIFIED)
|
||||
return;
|
||||
|
||||
// A fast refresh is demanded: we have a decision
|
||||
if (frameFlags & DEMAND_FAST) {
|
||||
refresh = FAST;
|
||||
reason = FLAGGED_DEMAND_FAST;
|
||||
LOG_DEBUG("refresh=FAST, reason=FLAGGED_DEMAND_FAST, frameFlags=0x%x\n", frameFlags);
|
||||
}
|
||||
}
|
||||
|
||||
// Does the new frame match the currently displayed image?
|
||||
void EInkDynamicDisplay::checkFrameMatchesPrevious()
|
||||
{
|
||||
// If a decision was already reached, don't run the check
|
||||
if (refresh != UNSPECIFIED)
|
||||
return;
|
||||
|
||||
// If frame is *not* a duplicate, abort the check
|
||||
if (imageHash != previousImageHash)
|
||||
return;
|
||||
|
||||
#if !defined(EINK_BACKGROUND_USES_FAST)
|
||||
// If BACKGROUND, and last update was FAST: redraw the same image in FULL (for display health + image quality)
|
||||
if (frameFlags == BACKGROUND && fastRefreshCount > 0) {
|
||||
refresh = FULL;
|
||||
reason = REDRAW_WITH_FULL;
|
||||
LOG_DEBUG("refresh=FULL, reason=REDRAW_WITH_FULL, frameFlags=0x%x\n", frameFlags);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Not redrawn, not COSMETIC, not DEMAND_FAST
|
||||
refresh = SKIPPED;
|
||||
reason = FRAME_MATCHED_PREVIOUS;
|
||||
LOG_DEBUG("refresh=SKIPPED, reason=FRAME_MATCHED_PREVIOUS, frameFlags=0x%x\n", frameFlags);
|
||||
}
|
||||
|
||||
// Have too many fast-refreshes occured consecutively, since last full refresh?
|
||||
void EInkDynamicDisplay::checkConsecutiveFastRefreshes()
|
||||
{
|
||||
// If a decision was already reached, don't run the check
|
||||
if (refresh != UNSPECIFIED)
|
||||
return;
|
||||
|
||||
// If too many FAST refreshes consecutively - force a FULL refresh
|
||||
if (fastRefreshCount >= EINK_LIMIT_FASTREFRESH) {
|
||||
refresh = FULL;
|
||||
reason = EXCEEDED_LIMIT_FASTREFRESH;
|
||||
LOG_DEBUG("refresh=FULL, reason=EXCEEDED_LIMIT_FASTREFRESH, frameFlags=0x%x\n", frameFlags);
|
||||
}
|
||||
}
|
||||
|
||||
// No objections, we can perform fast-refresh, if desired
|
||||
void EInkDynamicDisplay::checkFastRequested()
|
||||
{
|
||||
if (refresh != UNSPECIFIED)
|
||||
return;
|
||||
|
||||
if (frameFlags == BACKGROUND) {
|
||||
#ifdef EINK_BACKGROUND_USES_FAST
|
||||
// If we want BACKGROUND to use fast. (FULL only when a limit is hit)
|
||||
refresh = FAST;
|
||||
reason = BACKGROUND_USES_FAST;
|
||||
LOG_DEBUG("refresh=FAST, reason=BACKGROUND_USES_FAST, fastRefreshCount=%lu, frameFlags=0x%x\n", fastRefreshCount,
|
||||
frameFlags);
|
||||
#else
|
||||
// If we do want to use FULL for BACKGROUND updates
|
||||
refresh = FULL;
|
||||
reason = FLAGGED_BACKGROUND;
|
||||
LOG_DEBUG("refresh=FULL, reason=FLAGGED_BACKGROUND\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
// Sanity: confirm that we did ask for a RESPONSIVE frame.
|
||||
if (frameFlags & RESPONSIVE) {
|
||||
refresh = FAST;
|
||||
reason = NO_OBJECTIONS;
|
||||
LOG_DEBUG("refresh=FAST, reason=NO_OBJECTIONS, fastRefreshCount=%lu, frameFlags=0x%x\n", fastRefreshCount, frameFlags);
|
||||
}
|
||||
}
|
||||
|
||||
// Reset the timer used for rate-limiting
|
||||
void EInkDynamicDisplay::resetRateLimiting()
|
||||
{
|
||||
previousRunMs = millis();
|
||||
}
|
||||
|
||||
// Generate a hash of this frame, to compare against previous update
|
||||
void EInkDynamicDisplay::hashImage()
|
||||
{
|
||||
imageHash = 0;
|
||||
|
||||
// Sum all bytes of the image buffer together
|
||||
for (uint16_t b = 0; b < (displayWidth / 8) * displayHeight; b++) {
|
||||
imageHash += buffer[b];
|
||||
}
|
||||
}
|
||||
|
||||
// Store the results of determineMode() for future use, and reset for next call
|
||||
void EInkDynamicDisplay::storeAndReset()
|
||||
{
|
||||
previousFrameFlags = frameFlags;
|
||||
previousRefresh = refresh;
|
||||
previousReason = reason;
|
||||
|
||||
// Only store image hash if the display will update
|
||||
if (refresh != SKIPPED) {
|
||||
previousImageHash = imageHash;
|
||||
}
|
||||
|
||||
frameFlags = BACKGROUND;
|
||||
refresh = UNSPECIFIED;
|
||||
}
|
||||
|
||||
#ifdef EINK_LIMIT_GHOSTING_PX
|
||||
// Count how many ghost pixels the new image will display
|
||||
void EInkDynamicDisplay::countGhostPixels()
|
||||
{
|
||||
// If a decision was already reached, don't run the check
|
||||
if (refresh != UNSPECIFIED)
|
||||
return;
|
||||
|
||||
// Start a new count
|
||||
ghostPixelCount = 0;
|
||||
|
||||
// Check new image, bit by bit, for any white pixels at locations marked "dirty"
|
||||
for (uint16_t i = 0; i < displayBufferSize; i++) {
|
||||
for (uint8_t bit = 0; bit < 7; bit++) {
|
||||
|
||||
const bool dirty = (dirtyPixels[i] >> bit) & 1; // Has pixel location been drawn to since full-refresh?
|
||||
const bool shouldBeBlank = !((buffer[i] >> bit) & 1); // Is pixel location white in the new image?
|
||||
|
||||
// If pixel is (or has been) black since last full-refresh, and now is white: ghosting
|
||||
if (dirty && shouldBeBlank)
|
||||
ghostPixelCount++;
|
||||
|
||||
// Update the dirty status for this pixel - will this location become a ghost if set white in future?
|
||||
if (!dirty && !shouldBeBlank)
|
||||
dirtyPixels[i] |= (1 << bit);
|
||||
}
|
||||
}
|
||||
|
||||
LOG_DEBUG("ghostPixels=%hu, ", ghostPixelCount);
|
||||
}
|
||||
|
||||
// Check if ghost pixel count exceeds the defined limit
|
||||
void EInkDynamicDisplay::checkExcessiveGhosting()
|
||||
{
|
||||
// If a decision was already reached, don't run the check
|
||||
if (refresh != UNSPECIFIED)
|
||||
return;
|
||||
|
||||
countGhostPixels();
|
||||
|
||||
// If too many ghost pixels, select full refresh
|
||||
if (ghostPixelCount > EINK_LIMIT_GHOSTING_PX) {
|
||||
refresh = FULL;
|
||||
reason = EXCEEDED_GHOSTINGLIMIT;
|
||||
LOG_DEBUG("refresh=FULL, reason=EXCEEDED_GHOSTINGLIMIT, frameFlags=0x%x\n", frameFlags);
|
||||
}
|
||||
}
|
||||
|
||||
// Clear the dirty pixels array. Call when full-refresh cleans the display.
|
||||
void EInkDynamicDisplay::resetGhostPixelTracking()
|
||||
{
|
||||
// Copy the current frame into dirtyPixels[] from the display buffer
|
||||
memcpy(dirtyPixels, EInkDisplay::buffer, EInkDisplay::displayBufferSize);
|
||||
}
|
||||
#endif // EINK_LIMIT_GHOSTING_PX
|
||||
|
||||
#ifdef HAS_EINK_ASYNCFULL
|
||||
// Check the status of an "async full-refresh", and run the finish-up code if the hardware is ready
|
||||
void EInkDynamicDisplay::checkAsyncFullRefresh()
|
||||
{
|
||||
// No refresh taking place, continue with determineMode()
|
||||
if (!asyncRefreshRunning)
|
||||
return;
|
||||
|
||||
// Full refresh still running
|
||||
if (adafruitDisplay->epd2.isBusy()) {
|
||||
// No refresh
|
||||
refresh = SKIPPED;
|
||||
|
||||
// Set the reason, marking what type of frame we're skipping
|
||||
if (frameFlags & DEMAND_FAST)
|
||||
reason = ASYNC_REFRESH_BLOCKED_DEMANDFAST;
|
||||
else if (frameFlags & COSMETIC)
|
||||
reason = ASYNC_REFRESH_BLOCKED_COSMETIC;
|
||||
else if (frameFlags & RESPONSIVE)
|
||||
reason = ASYNC_REFRESH_BLOCKED_RESPONSIVE;
|
||||
else
|
||||
reason = ASYNC_REFRESH_BLOCKED_BACKGROUND;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// If we asyncRefreshRunning flag is still set, but display's BUSY pin reports the refresh is done
|
||||
adafruitDisplay->endAsyncFull(); // Run the end of nextPage() code
|
||||
EInkDisplay::endUpdate(); // Run base-class code to finish off update (NOT our derived class override)
|
||||
asyncRefreshRunning = false; // Unset the flag
|
||||
LOG_DEBUG("Async full-refresh complete\n");
|
||||
|
||||
// Note: this code only works because of a modification to meshtastic/GxEPD2.
|
||||
// It is only equipped to intercept calls to nextPage()
|
||||
}
|
||||
|
||||
// Hold control while an async refresh runs
|
||||
void EInkDynamicDisplay::awaitRefresh()
|
||||
{
|
||||
// Continually poll the BUSY pin
|
||||
while (adafruitDisplay->epd2.isBusy())
|
||||
yield();
|
||||
|
||||
// End the full-refresh process
|
||||
adafruitDisplay->endAsyncFull(); // Run the end of nextPage() code
|
||||
EInkDisplay::endUpdate(); // Run base-class code to finish off update (NOT our derived class override)
|
||||
asyncRefreshRunning = false; // Unset the flag
|
||||
}
|
||||
#endif // HAS_EINK_ASYNCFULL
|
||||
|
||||
#endif // USE_EINK_DYNAMICDISPLAY
|
||||
127
src/graphics/EInkDynamicDisplay.h
Normal file
127
src/graphics/EInkDynamicDisplay.h
Normal file
@@ -0,0 +1,127 @@
|
||||
#pragma once
|
||||
|
||||
#include "configuration.h"
|
||||
|
||||
#if defined(USE_EINK) && defined(USE_EINK_DYNAMICDISPLAY)
|
||||
|
||||
#include "EInkDisplay2.h"
|
||||
#include "GxEPD2_BW.h"
|
||||
|
||||
/*
|
||||
Derives from the EInkDisplay adapter class.
|
||||
Accepts suggestions from Screen class about frame type.
|
||||
Determines which refresh type is most suitable.
|
||||
(Full, Fast, Skip)
|
||||
*/
|
||||
|
||||
class EInkDynamicDisplay : public EInkDisplay
|
||||
{
|
||||
public:
|
||||
// Constructor
|
||||
// ( Parameters unused, passed to EInkDisplay. Maintains compatibility OLEDDisplay class )
|
||||
EInkDynamicDisplay(uint8_t address, int sda, int scl, OLEDDISPLAY_GEOMETRY geometry, HW_I2C i2cBus);
|
||||
~EInkDynamicDisplay();
|
||||
|
||||
// What kind of frame is this
|
||||
enum frameFlagTypes : uint8_t {
|
||||
BACKGROUND = (1 << 0), // For frames via display()
|
||||
RESPONSIVE = (1 << 1), // For frames via forceDisplay()
|
||||
COSMETIC = (1 << 2), // For splashes
|
||||
DEMAND_FAST = (1 << 3), // Special case only
|
||||
BLOCKING = (1 << 4), // Modifier - block while refresh runs
|
||||
};
|
||||
void addFrameFlag(frameFlagTypes flag);
|
||||
|
||||
// Set the correct frame flag, then call universal "update()" method
|
||||
void display() override;
|
||||
bool forceDisplay(uint32_t msecLimit) override; // Shadows base class. Parameter and return val unused.
|
||||
|
||||
protected:
|
||||
enum refreshTypes : uint8_t { // Which refresh operation will be used
|
||||
UNSPECIFIED,
|
||||
FULL,
|
||||
FAST,
|
||||
SKIPPED,
|
||||
};
|
||||
enum reasonTypes : uint8_t { // How was the decision reached
|
||||
NO_OBJECTIONS,
|
||||
ASYNC_REFRESH_BLOCKED_DEMANDFAST,
|
||||
ASYNC_REFRESH_BLOCKED_COSMETIC,
|
||||
ASYNC_REFRESH_BLOCKED_RESPONSIVE,
|
||||
ASYNC_REFRESH_BLOCKED_BACKGROUND,
|
||||
EXCEEDED_RATELIMIT_FAST,
|
||||
EXCEEDED_RATELIMIT_FULL,
|
||||
FLAGGED_COSMETIC,
|
||||
FLAGGED_DEMAND_FAST,
|
||||
EXCEEDED_LIMIT_FASTREFRESH,
|
||||
EXCEEDED_GHOSTINGLIMIT,
|
||||
FRAME_MATCHED_PREVIOUS,
|
||||
BACKGROUND_USES_FAST,
|
||||
FLAGGED_BACKGROUND,
|
||||
REDRAW_WITH_FULL,
|
||||
};
|
||||
|
||||
void configForFastRefresh(); // GxEPD2 code to set fast-refresh
|
||||
void configForFullRefresh(); // GxEPD2 code to set full-refresh
|
||||
bool determineMode(); // Assess situation, pick a refresh type
|
||||
void applyRefreshMode(); // Run any relevant GxEPD2 code, so next update will use correct refresh type
|
||||
void adjustRefreshCounters(); // Update fastRefreshCount
|
||||
bool update(); // Trigger the display update - determine mode, then call base class
|
||||
void endOrDetach(); // Run the post-update code, or delegate it off to checkAsyncFullRefresh()
|
||||
|
||||
// Checks as part of determineMode()
|
||||
void checkInitialized(); // Is this the very first frame?
|
||||
void checkForPromotion(); // Was a frame skipped (rate, display busy) that should have been a FAST refresh?
|
||||
void checkRateLimiting(); // Is this frame too soon?
|
||||
void checkCosmetic(); // Was the COSMETIC flag set?
|
||||
void checkDemandingFast(); // Was the DEMAND_FAST flag set?
|
||||
void checkFrameMatchesPrevious(); // Does the new frame match the existing display image?
|
||||
void checkConsecutiveFastRefreshes(); // Too many fast-refreshes consecutively?
|
||||
void checkFastRequested(); // Was the flag set for RESPONSIVE, or only BACKGROUND?
|
||||
|
||||
void resetRateLimiting(); // Set previousRunMs - this now counts as an update, for rate-limiting
|
||||
void hashImage(); // Generate a hashed version of this frame, to compare against previous update
|
||||
void storeAndReset(); // Keep results of determineMode() for later, tidy-up for next call
|
||||
|
||||
// What we are determining for this frame
|
||||
frameFlagTypes frameFlags = BACKGROUND; // Frame characteristics - determineMode() input
|
||||
refreshTypes refresh = UNSPECIFIED; // Refresh type - determineMode() output
|
||||
reasonTypes reason = NO_OBJECTIONS; // Reason - why was refresh type used
|
||||
|
||||
// What happened last time determineMode() ran
|
||||
frameFlagTypes previousFrameFlags = BACKGROUND; // (Previous) Frame flags
|
||||
refreshTypes previousRefresh = UNSPECIFIED; // (Previous) Outcome
|
||||
reasonTypes previousReason = NO_OBJECTIONS; // (Previous) Reason
|
||||
|
||||
bool initialized = false; // Have we drawn at least one frame yet?
|
||||
uint32_t previousRunMs = -1; // When did determineMode() last run (rather than rejecting for rate-limiting)
|
||||
uint32_t imageHash = 0; // Hash of the current frame. Don't bother updating if nothing has changed!
|
||||
uint32_t previousImageHash = 0; // Hash of the previous update's frame
|
||||
uint32_t fastRefreshCount = 0; // How many fast-refreshes consecutively since last full refresh?
|
||||
refreshTypes currentConfig = FULL; // Which refresh type is GxEPD2 currently configured for
|
||||
|
||||
// Optional - track ghosting, pixel by pixel
|
||||
#ifdef EINK_LIMIT_GHOSTING_PX
|
||||
void countGhostPixels(); // Count any pixels which have moved from black to white since last full-refresh
|
||||
void checkExcessiveGhosting(); // Check if ghosting exceeds defined limit
|
||||
void resetGhostPixelTracking(); // Clear the dirty pixels array. Call when full-refresh cleans the display.
|
||||
uint8_t *dirtyPixels; // Any pixels that have been black since last full-refresh (dynamically allocated mem)
|
||||
uint32_t ghostPixelCount = 0; // Number of pixels with problematic ghosting. Retained here for LOG_DEBUG use
|
||||
#endif
|
||||
|
||||
// Conditional - async full refresh - only with modified meshtastic/GxEPD2
|
||||
#if defined(HAS_EINK_ASYNCFULL)
|
||||
void checkAsyncFullRefresh(); // Check the status of "async full-refresh"; run the post-update code if the hardware is ready
|
||||
void awaitRefresh(); // Hold control while an async refresh runs
|
||||
void endUpdate() override {} // Disable base-class behavior of running post-update immediately after forceDisplay()
|
||||
bool asyncRefreshRunning = false; // Flag, checked by checkAsyncFullRefresh()
|
||||
#endif
|
||||
};
|
||||
|
||||
// Tidier calls to addFrameFlag() from outside class
|
||||
#define EINK_ADD_FRAMEFLAG(display, flag) static_cast<EInkDynamicDisplay *>(display)->addFrameFlag(EInkDynamicDisplay::flag)
|
||||
|
||||
#else // !USE_EINK_DYNAMICDISPLAY
|
||||
// Dummy-macro, removes the need for include guards
|
||||
#define EINK_ADD_FRAMEFLAG(display, flag)
|
||||
#endif
|
||||
@@ -31,6 +31,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#include "error.h"
|
||||
#include "gps/GeoCoord.h"
|
||||
#include "gps/RTC.h"
|
||||
#include "graphics/ScreenFonts.h"
|
||||
#include "graphics/images.h"
|
||||
#include "input/TouchScreenImpl1.h"
|
||||
#include "main.h"
|
||||
@@ -56,14 +57,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#include "platform/portduino/PortduinoGlue.h"
|
||||
#endif
|
||||
|
||||
#ifdef OLED_RU
|
||||
#include "fonts/OLEDDisplayFontsRU.h"
|
||||
#endif
|
||||
|
||||
#ifdef OLED_UA
|
||||
#include "fonts/OLEDDisplayFontsUA.h"
|
||||
#endif
|
||||
|
||||
using namespace meshtastic; /** @todo remove */
|
||||
|
||||
namespace graphics
|
||||
@@ -78,7 +71,7 @@ namespace graphics
|
||||
// #define SHOW_REDRAWS
|
||||
|
||||
// A text message frame + debug frame + all the node infos
|
||||
static FrameCallback normalFrames[MAX_NUM_NODES + NUM_EXTRA_FRAMES];
|
||||
FrameCallback *normalFrames;
|
||||
static uint32_t targetFramerate = IDLE_FRAMERATE;
|
||||
static char btPIN[16] = "888888";
|
||||
|
||||
@@ -111,31 +104,7 @@ static uint16_t displayWidth, displayHeight;
|
||||
#define SCREEN_WIDTH displayWidth
|
||||
#define SCREEN_HEIGHT displayHeight
|
||||
|
||||
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)) && \
|
||||
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||||
// The screen is bigger so use bigger fonts
|
||||
#define FONT_SMALL ArialMT_Plain_16 // Height: 19
|
||||
#define FONT_MEDIUM ArialMT_Plain_24 // Height: 28
|
||||
#define FONT_LARGE ArialMT_Plain_24 // Height: 28
|
||||
#else
|
||||
#ifdef OLED_RU
|
||||
#define FONT_SMALL ArialMT_Plain_10_RU
|
||||
#else
|
||||
#ifdef OLED_UA
|
||||
#define FONT_SMALL ArialMT_Plain_10_UA
|
||||
#else
|
||||
#define FONT_SMALL ArialMT_Plain_10 // Height: 13
|
||||
#endif
|
||||
#endif
|
||||
#define FONT_MEDIUM ArialMT_Plain_16 // Height: 19
|
||||
#define FONT_LARGE ArialMT_Plain_24 // Height: 28
|
||||
#endif
|
||||
|
||||
#define fontHeight(font) ((font)[1] + 1) // height is position 1
|
||||
|
||||
#define FONT_HEIGHT_SMALL fontHeight(FONT_SMALL)
|
||||
#define FONT_HEIGHT_MEDIUM fontHeight(FONT_MEDIUM)
|
||||
#define FONT_HEIGHT_LARGE fontHeight(FONT_LARGE)
|
||||
#include "graphics/ScreenFonts.h"
|
||||
|
||||
#define getStringCenteredX(s) ((SCREEN_WIDTH - display->getStringWidth(s)) / 2)
|
||||
|
||||
@@ -274,7 +243,7 @@ static void drawWelcomeScreen(OLEDDisplay *display, OLEDDisplayUiState *state, i
|
||||
if ((millis() / 10000) % 2) {
|
||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 2 - 3, "Set the region using the");
|
||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 3 - 3, "Meshtastic Android, iOS,");
|
||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 4 - 3, "Flasher or CLI client.");
|
||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 4 - 3, "Web or CLI clients.");
|
||||
} else {
|
||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 2 - 3, "Visit meshtastic.org");
|
||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 3 - 3, "for more information.");
|
||||
@@ -291,6 +260,10 @@ static void drawWelcomeScreen(OLEDDisplay *display, OLEDDisplayUiState *state, i
|
||||
/// Used on eink displays while in deep sleep
|
||||
static void drawSleepScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
// Next frame should use full-refresh, and block while running, else device will sleep before async callback
|
||||
EINK_ADD_FRAMEFLAG(display, COSMETIC);
|
||||
EINK_ADD_FRAMEFLAG(display, BLOCKING);
|
||||
|
||||
drawIconScreen("Sleeping...", display, state, x, y);
|
||||
}
|
||||
#endif
|
||||
@@ -381,7 +354,7 @@ static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state
|
||||
static char tempBuf[237];
|
||||
|
||||
const meshtastic_MeshPacket &mp = devicestate.rx_text_message;
|
||||
meshtastic_NodeInfoLite *node = nodeDB.getMeshNode(getFrom(&mp));
|
||||
meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(getFrom(&mp));
|
||||
// LOG_DEBUG("drawing text message from 0x%x: %s\n", mp.from,
|
||||
// mp.decoded.variant.data.decoded.bytes);
|
||||
|
||||
@@ -419,7 +392,7 @@ static void drawWaypointFrame(OLEDDisplay *display, OLEDDisplayUiState *state, i
|
||||
static char tempBuf[237];
|
||||
|
||||
meshtastic_MeshPacket &mp = devicestate.rx_waypoint;
|
||||
meshtastic_NodeInfoLite *node = nodeDB.getMeshNode(getFrom(&mp));
|
||||
meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(getFrom(&mp));
|
||||
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display->setFont(FONT_SMALL);
|
||||
@@ -807,16 +780,16 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
|
||||
if (state->currentFrame != prevFrame) {
|
||||
prevFrame = state->currentFrame;
|
||||
|
||||
nodeIndex = (nodeIndex + 1) % nodeDB.getNumMeshNodes();
|
||||
meshtastic_NodeInfoLite *n = nodeDB.getMeshNodeByIndex(nodeIndex);
|
||||
if (n->num == nodeDB.getNodeNum()) {
|
||||
nodeIndex = (nodeIndex + 1) % nodeDB->getNumMeshNodes();
|
||||
meshtastic_NodeInfoLite *n = nodeDB->getMeshNodeByIndex(nodeIndex);
|
||||
if (n->num == nodeDB->getNodeNum()) {
|
||||
// Don't show our node, just skip to next
|
||||
nodeIndex = (nodeIndex + 1) % nodeDB.getNumMeshNodes();
|
||||
n = nodeDB.getMeshNodeByIndex(nodeIndex);
|
||||
nodeIndex = (nodeIndex + 1) % nodeDB->getNumMeshNodes();
|
||||
n = nodeDB->getMeshNodeByIndex(nodeIndex);
|
||||
}
|
||||
}
|
||||
|
||||
meshtastic_NodeInfoLite *node = nodeDB.getMeshNodeByIndex(nodeIndex);
|
||||
meshtastic_NodeInfoLite *node = nodeDB->getMeshNodeByIndex(nodeIndex);
|
||||
|
||||
display->setFont(FONT_SMALL);
|
||||
|
||||
@@ -854,7 +827,7 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
|
||||
} else {
|
||||
strncpy(distStr, "? km", sizeof(distStr));
|
||||
}
|
||||
meshtastic_NodeInfoLite *ourNode = nodeDB.getMeshNode(nodeDB.getNodeNum());
|
||||
meshtastic_NodeInfoLite *ourNode = nodeDB->getMeshNode(nodeDB->getNodeNum());
|
||||
const char *fields[] = {username, distStr, signalStr, lastStr, NULL};
|
||||
int16_t compassX = 0, compassY = 0;
|
||||
|
||||
@@ -920,6 +893,7 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
|
||||
Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_OledType screenType, OLEDDISPLAY_GEOMETRY geometry)
|
||||
: concurrency::OSThread("Screen"), address_found(address), model(screenType), geometry(geometry), cmdQueue(32)
|
||||
{
|
||||
graphics::normalFrames = new FrameCallback[MAX_NUM_NODES + NUM_EXTRA_FRAMES];
|
||||
#if defined(USE_SH1106) || defined(USE_SH1107) || defined(USE_SH1107_128_64)
|
||||
dispdev = new SH1106Wire(address.address, -1, -1, geometry,
|
||||
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
|
||||
@@ -929,9 +903,12 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O
|
||||
#elif defined(ST7735_CS) || defined(ILI9341_DRIVER) || defined(ST7789_CS) || defined(RAK14014)
|
||||
dispdev = new TFTDisplay(address.address, -1, -1, geometry,
|
||||
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
|
||||
#elif defined(USE_EINK)
|
||||
#elif defined(USE_EINK) && !defined(USE_EINK_DYNAMICDISPLAY)
|
||||
dispdev = new EInkDisplay(address.address, -1, -1, geometry,
|
||||
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
|
||||
#elif defined(USE_EINK) && defined(USE_EINK_DYNAMICDISPLAY)
|
||||
dispdev = new EInkDynamicDisplay(address.address, -1, -1, geometry,
|
||||
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
|
||||
#elif defined(USE_ST7567)
|
||||
dispdev = new ST7567Wire(address.address, -1, -1, geometry,
|
||||
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
|
||||
@@ -955,6 +932,11 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O
|
||||
cmdQueue.setReader(this);
|
||||
}
|
||||
|
||||
Screen::~Screen()
|
||||
{
|
||||
delete[] graphics::normalFrames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the display for the unit going to the lowest power mode possible. Most screens will just
|
||||
* poweroff, but eink screens will show a "I'm sleeping" graphic, possibly with a QR code
|
||||
@@ -966,6 +948,9 @@ void Screen::doDeepSleep()
|
||||
static const int sleepFrameCount = sizeof(sleepFrames) / sizeof(sleepFrames[0]);
|
||||
ui->setFrames(sleepFrames, sleepFrameCount);
|
||||
ui->update();
|
||||
#ifdef PIN_EINK_EN
|
||||
digitalWrite(PIN_EINK_EN, LOW); // power off backlight
|
||||
#endif
|
||||
#endif
|
||||
setOn(false);
|
||||
}
|
||||
@@ -1195,6 +1180,7 @@ int32_t Screen::runOnce()
|
||||
break;
|
||||
case Cmd::STOP_BLUETOOTH_PIN_SCREEN:
|
||||
case Cmd::STOP_BOOT_SCREEN:
|
||||
EINK_ADD_FRAMEFLAG(dispdev, COSMETIC); // E-Ink: Explicitly use full-refresh for next frame
|
||||
setFrames();
|
||||
break;
|
||||
case Cmd::PRINT:
|
||||
@@ -1307,7 +1293,7 @@ void Screen::setFrames()
|
||||
#endif
|
||||
|
||||
// We don't show the node info our our node (if we have it yet - we should)
|
||||
size_t numMeshNodes = nodeDB.getNumMeshNodes();
|
||||
size_t numMeshNodes = nodeDB->getNumMeshNodes();
|
||||
if (numMeshNodes > 0)
|
||||
numMeshNodes--;
|
||||
|
||||
@@ -1375,6 +1361,7 @@ void Screen::handleStartBluetoothPinScreen(uint32_t pin)
|
||||
{
|
||||
LOG_DEBUG("showing bluetooth screen\n");
|
||||
showingNormalScreen = false;
|
||||
EINK_ADD_FRAMEFLAG(dispdev, DEMAND_FAST); // E-Ink: Explicitly use fast-refresh for next frame
|
||||
|
||||
static FrameCallback frames[] = {drawFrameBluetooth};
|
||||
snprintf(btPIN, sizeof(btPIN), "%06u", pin);
|
||||
@@ -1392,6 +1379,7 @@ void Screen::handleShutdownScreen()
|
||||
{
|
||||
LOG_DEBUG("showing shutdown screen\n");
|
||||
showingNormalScreen = false;
|
||||
EINK_ADD_FRAMEFLAG(dispdev, DEMAND_FAST); // E-Ink: Explicitly use fast-refresh for next frame
|
||||
|
||||
auto frame = [](OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -> void {
|
||||
drawFrameText(display, state, x, y, "Shutting down...");
|
||||
@@ -1405,6 +1393,7 @@ void Screen::handleRebootScreen()
|
||||
{
|
||||
LOG_DEBUG("showing reboot screen\n");
|
||||
showingNormalScreen = false;
|
||||
EINK_ADD_FRAMEFLAG(dispdev, DEMAND_FAST); // E-Ink: Explicitly use fast-refresh for next frame
|
||||
|
||||
auto frame = [](OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -> void {
|
||||
drawFrameText(display, state, x, y, "Rebooting...");
|
||||
@@ -1417,6 +1406,7 @@ void Screen::handleStartFirmwareUpdateScreen()
|
||||
{
|
||||
LOG_DEBUG("showing firmware screen\n");
|
||||
showingNormalScreen = false;
|
||||
EINK_ADD_FRAMEFLAG(dispdev, DEMAND_FAST); // E-Ink: Explicitly use fast-refresh for next frame
|
||||
|
||||
static FrameCallback frames[] = {drawFrameFirmware};
|
||||
setFrameImmediateDraw(frames);
|
||||
@@ -1529,8 +1519,7 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
||||
char channelStr[20];
|
||||
{
|
||||
concurrency::LockGuard guard(&lock);
|
||||
auto chName = channels.getPrimaryName();
|
||||
snprintf(channelStr, sizeof(channelStr), "%s", chName);
|
||||
snprintf(channelStr, sizeof(channelStr), "#%s", channels.getName(channels.getPrimaryIndex()));
|
||||
}
|
||||
|
||||
// Display power status
|
||||
@@ -1809,7 +1798,7 @@ int Screen::handleStatusUpdate(const meshtastic::Status *arg)
|
||||
if (showingNormalScreen && nodeStatus->getLastNumTotal() != nodeStatus->getNumTotal()) {
|
||||
setFrames(); // Regen the list of screens
|
||||
}
|
||||
nodeDB.updateGUI = false;
|
||||
nodeDB->updateGUI = false;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@ class Screen
|
||||
#endif
|
||||
|
||||
#include "EInkDisplay2.h"
|
||||
#include "EInkDynamicDisplay.h"
|
||||
#include "TFTDisplay.h"
|
||||
#include "TypedQueue.h"
|
||||
#include "commands.h"
|
||||
@@ -124,6 +125,8 @@ class Screen : public concurrency::OSThread
|
||||
public:
|
||||
explicit Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY);
|
||||
|
||||
~Screen();
|
||||
|
||||
Screen(const Screen &) = delete;
|
||||
Screen &operator=(const Screen &) = delete;
|
||||
|
||||
|
||||
35
src/graphics/ScreenFonts.h
Normal file
35
src/graphics/ScreenFonts.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef OLED_RU
|
||||
#include "graphics/fonts/OLEDDisplayFontsRU.h"
|
||||
#endif
|
||||
|
||||
#ifdef OLED_UA
|
||||
#include "graphics/fonts/OLEDDisplayFontsUA.h"
|
||||
#endif
|
||||
|
||||
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)) && \
|
||||
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||||
// The screen is bigger so use bigger fonts
|
||||
#define FONT_SMALL ArialMT_Plain_16 // Height: 19
|
||||
#define FONT_MEDIUM ArialMT_Plain_24 // Height: 28
|
||||
#define FONT_LARGE ArialMT_Plain_24 // Height: 28
|
||||
#else
|
||||
#ifdef OLED_RU
|
||||
#define FONT_SMALL ArialMT_Plain_10_RU
|
||||
#else
|
||||
#ifdef OLED_UA
|
||||
#define FONT_SMALL ArialMT_Plain_10_UA
|
||||
#else
|
||||
#define FONT_SMALL ArialMT_Plain_10 // Height: 13
|
||||
#endif
|
||||
#endif
|
||||
#define FONT_MEDIUM ArialMT_Plain_16 // Height: 19
|
||||
#define FONT_LARGE ArialMT_Plain_24 // Height: 28
|
||||
#endif
|
||||
|
||||
#define fontHeight(font) ((font)[1] + 1) // height is position 1
|
||||
|
||||
#define FONT_HEIGHT_SMALL fontHeight(FONT_SMALL)
|
||||
#define FONT_HEIGHT_MEDIUM fontHeight(FONT_MEDIUM)
|
||||
#define FONT_HEIGHT_LARGE fontHeight(FONT_LARGE)
|
||||
@@ -90,11 +90,9 @@ class LGFX : public lgfx::LGFX_Device
|
||||
auto cfg = _light_instance.config(); // Gets a structure for backlight settings.
|
||||
|
||||
#ifdef ST7735_BL_V03
|
||||
if (heltec_version == 3) {
|
||||
cfg.pin_bl = ST7735_BL_V03;
|
||||
} else {
|
||||
cfg.pin_bl = ST7735_BL_V05;
|
||||
}
|
||||
cfg.pin_bl = ST7735_BL_V03;
|
||||
#elif defined(ST7735_BL_V05)
|
||||
cfg.pin_bl = ST7735_BL_V05;
|
||||
#else
|
||||
cfg.pin_bl = ST7735_BL; // Pin number to which the backlight is connected
|
||||
#endif
|
||||
@@ -471,30 +469,27 @@ void TFTDisplay::sendCommand(uint8_t com)
|
||||
display(true);
|
||||
if (settingsMap[displayBacklight] > 0)
|
||||
digitalWrite(settingsMap[displayBacklight], TFT_BACKLIGHT_ON);
|
||||
#elif defined(ST7735_BACKLIGHT_EN_V03) && defined(TFT_BACKLIGHT_ON)
|
||||
if (heltec_version == 3) {
|
||||
digitalWrite(ST7735_BACKLIGHT_EN_V03, TFT_BACKLIGHT_ON);
|
||||
} else {
|
||||
digitalWrite(ST7735_BACKLIGHT_EN_V05, TFT_BACKLIGHT_ON);
|
||||
}
|
||||
#elif defined(ST7735_BL_V03)
|
||||
digitalWrite(ST7735_BL_V03, TFT_BACKLIGHT_ON);
|
||||
#elif defined(ST7735_BL_V05)
|
||||
pinMode(ST7735_BL_V05, OUTPUT);
|
||||
digitalWrite(ST7735_BL_V05, TFT_BACKLIGHT_ON);
|
||||
#endif
|
||||
#if defined(TFT_BL) && defined(TFT_BACKLIGHT_ON)
|
||||
digitalWrite(TFT_BL, TFT_BACKLIGHT_ON);
|
||||
#endif
|
||||
|
||||
#ifdef VTFT_CTRL_V03
|
||||
if (heltec_version == 3) {
|
||||
digitalWrite(VTFT_CTRL_V03, LOW);
|
||||
} else {
|
||||
digitalWrite(VTFT_CTRL_V05, LOW);
|
||||
}
|
||||
digitalWrite(VTFT_CTRL_V03, LOW);
|
||||
#endif
|
||||
|
||||
#ifdef VTFT_CTRL
|
||||
digitalWrite(VTFT_CTRL, LOW);
|
||||
#endif
|
||||
|
||||
#ifdef RAK14014
|
||||
#elif !defined(M5STACK)
|
||||
tft->setBrightness(128);
|
||||
tft->setBrightness(172);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
@@ -503,22 +498,17 @@ void TFTDisplay::sendCommand(uint8_t com)
|
||||
tft->clear();
|
||||
if (settingsMap[displayBacklight] > 0)
|
||||
digitalWrite(settingsMap[displayBacklight], !TFT_BACKLIGHT_ON);
|
||||
#elif defined(ST7735_BACKLIGHT_EN_V03) && defined(TFT_BACKLIGHT_ON)
|
||||
if (heltec_version == 3) {
|
||||
digitalWrite(ST7735_BACKLIGHT_EN_V03, !TFT_BACKLIGHT_ON);
|
||||
} else {
|
||||
digitalWrite(ST7735_BACKLIGHT_EN_V05, !TFT_BACKLIGHT_ON);
|
||||
}
|
||||
#elif defined(ST7735_BL_V03)
|
||||
digitalWrite(ST7735_BL_V03, !TFT_BACKLIGHT_ON);
|
||||
#elif defined(ST7735_BL_V05)
|
||||
pinMode(ST7735_BL_V05, OUTPUT);
|
||||
digitalWrite(ST7735_BL_V05, !TFT_BACKLIGHT_ON);
|
||||
#endif
|
||||
#if defined(TFT_BL) && defined(TFT_BACKLIGHT_ON)
|
||||
digitalWrite(TFT_BL, !TFT_BACKLIGHT_ON);
|
||||
#endif
|
||||
#ifdef VTFT_CTRL_V03
|
||||
if (heltec_version == 3) {
|
||||
digitalWrite(VTFT_CTRL_V03, HIGH);
|
||||
} else {
|
||||
digitalWrite(VTFT_CTRL_V05, HIGH);
|
||||
}
|
||||
digitalWrite(VTFT_CTRL_V03, HIGH);
|
||||
#endif
|
||||
#ifdef VTFT_CTRL
|
||||
digitalWrite(VTFT_CTRL, HIGH);
|
||||
@@ -588,14 +578,11 @@ bool TFTDisplay::connect()
|
||||
LOG_INFO("Power to TFT Backlight\n");
|
||||
#endif
|
||||
|
||||
#ifdef ST7735_BACKLIGHT_EN_V03
|
||||
if (heltec_version == 3) {
|
||||
pinMode(ST7735_BACKLIGHT_EN_V03, OUTPUT);
|
||||
digitalWrite(ST7735_BACKLIGHT_EN_V03, TFT_BACKLIGHT_ON);
|
||||
} else {
|
||||
pinMode(ST7735_BACKLIGHT_EN_V05, OUTPUT);
|
||||
digitalWrite(ST7735_BACKLIGHT_EN_V05, TFT_BACKLIGHT_ON);
|
||||
}
|
||||
#ifdef ST7735_BL_V03
|
||||
digitalWrite(ST7735_BL_V03, TFT_BACKLIGHT_ON);
|
||||
#elif defined(ST7735_BL_V05)
|
||||
pinMode(ST7735_BL_V05, OUTPUT);
|
||||
digitalWrite(ST7735_BL_V05, TFT_BACKLIGHT_ON);
|
||||
#endif
|
||||
|
||||
tft->init();
|
||||
|
||||
109
src/main.cpp
109
src/main.cpp
@@ -33,7 +33,9 @@
|
||||
// #include <driver/rtc_io.h>
|
||||
|
||||
#ifdef ARCH_ESP32
|
||||
#if !MESHTASTIC_EXCLUDE_WEBSERVER
|
||||
#include "mesh/http/WebServer.h"
|
||||
#endif
|
||||
#include "nimble/NimbleBluetooth.h"
|
||||
NimbleBluetooth *nimbleBluetooth;
|
||||
#endif
|
||||
@@ -68,6 +70,7 @@ NRF52Bluetooth *nrf52Bluetooth;
|
||||
|
||||
#ifdef ARCH_PORTDUINO
|
||||
#include "linux/LinuxHardwareI2C.h"
|
||||
#include "mesh/raspihttp/PiWebServer.h"
|
||||
#include "platform/portduino/PortduinoGlue.h"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
@@ -159,25 +162,6 @@ const char *getDeviceName()
|
||||
return name;
|
||||
}
|
||||
|
||||
#ifdef VEXT_ENABLE_V03
|
||||
|
||||
#include <soc/rtc.h>
|
||||
|
||||
static uint32_t calibrate_one(rtc_cal_sel_t cal_clk, const char *name)
|
||||
{
|
||||
const uint32_t cal_count = 1000;
|
||||
uint32_t cali_val;
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
cali_val = rtc_clk_cal(cal_clk, cal_count);
|
||||
}
|
||||
return cali_val;
|
||||
}
|
||||
|
||||
int heltec_version = 3;
|
||||
|
||||
#define CALIBRATE_ONE(cali_clk) calibrate_one(cali_clk, #cali_clk)
|
||||
#endif
|
||||
|
||||
static int32_t ledBlinker()
|
||||
{
|
||||
static bool ledOn;
|
||||
@@ -237,10 +221,11 @@ void setup()
|
||||
|
||||
initDeepSleep();
|
||||
|
||||
// Testing this fix für erratic T-Echo boot behaviour
|
||||
#if defined(TTGO_T_ECHO) && defined(PIN_EINK_PWR_ON)
|
||||
pinMode(PIN_EINK_PWR_ON, OUTPUT);
|
||||
digitalWrite(PIN_EINK_PWR_ON, HIGH);
|
||||
// power on peripherals
|
||||
#if defined(TTGO_T_ECHO) && defined(PIN_POWER_EN)
|
||||
pinMode(PIN_POWER_EN, OUTPUT);
|
||||
digitalWrite(PIN_POWER_EN, HIGH);
|
||||
// digitalWrite(PIN_POWER_EN1, INPUT);
|
||||
#endif
|
||||
|
||||
#if defined(LORA_TCXO_GPIO)
|
||||
@@ -248,56 +233,31 @@ void setup()
|
||||
digitalWrite(LORA_TCXO_GPIO, HIGH);
|
||||
#endif
|
||||
|
||||
#ifdef ST7735_BL_V03 // Heltec Wireless Tracker PCB Change Detect/Hack
|
||||
|
||||
rtc_clk_32k_enable(true);
|
||||
CALIBRATE_ONE(RTC_CAL_RTC_MUX);
|
||||
if (CALIBRATE_ONE(RTC_CAL_32K_XTAL) != 0) {
|
||||
rtc_clk_slow_freq_set(RTC_SLOW_FREQ_32K_XTAL);
|
||||
CALIBRATE_ONE(RTC_CAL_RTC_MUX);
|
||||
CALIBRATE_ONE(RTC_CAL_32K_XTAL);
|
||||
}
|
||||
|
||||
if (rtc_clk_slow_freq_get() != RTC_SLOW_FREQ_32K_XTAL) {
|
||||
heltec_version = 3;
|
||||
} else {
|
||||
heltec_version = 5;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(VEXT_ENABLE_V03)
|
||||
if (heltec_version == 3) {
|
||||
pinMode(VEXT_ENABLE_V03, OUTPUT);
|
||||
digitalWrite(VEXT_ENABLE_V03, 0); // turn on the display power
|
||||
LOG_DEBUG("HELTEC Detect Tracker V1.0\n");
|
||||
} else {
|
||||
pinMode(VEXT_ENABLE_V05, OUTPUT);
|
||||
digitalWrite(VEXT_ENABLE_V05, 1); // turn on the display power
|
||||
LOG_DEBUG("HELTEC Detect Tracker V1.1\n");
|
||||
}
|
||||
pinMode(VEXT_ENABLE_V03, OUTPUT);
|
||||
pinMode(ST7735_BL_V03, OUTPUT);
|
||||
digitalWrite(VEXT_ENABLE_V03, 0); // turn on the display power and antenna boost
|
||||
digitalWrite(ST7735_BL_V03, 1); // display backligth on
|
||||
LOG_DEBUG("HELTEC Detect Tracker V1.0\n");
|
||||
#elif defined(VEXT_ENABLE_V05)
|
||||
pinMode(VEXT_ENABLE_V05, OUTPUT);
|
||||
pinMode(ST7735_BL_V05, OUTPUT);
|
||||
digitalWrite(VEXT_ENABLE_V05, 1); // turn on the lora antenna boost
|
||||
digitalWrite(ST7735_BL_V05, 1); // turn on display backligth
|
||||
LOG_DEBUG("HELTEC Detect Tracker V1.1\n");
|
||||
#elif defined(VEXT_ENABLE)
|
||||
pinMode(VEXT_ENABLE, OUTPUT);
|
||||
digitalWrite(VEXT_ENABLE, 0); // turn on the display power
|
||||
#endif
|
||||
|
||||
#if defined(VGNSS_CTRL_V03)
|
||||
if (heltec_version == 3) {
|
||||
pinMode(VGNSS_CTRL_V03, OUTPUT);
|
||||
digitalWrite(VGNSS_CTRL_V03, LOW);
|
||||
} else {
|
||||
pinMode(VGNSS_CTRL_V05, OUTPUT);
|
||||
digitalWrite(VGNSS_CTRL_V05, LOW);
|
||||
}
|
||||
pinMode(VGNSS_CTRL_V03, OUTPUT);
|
||||
digitalWrite(VGNSS_CTRL_V03, LOW);
|
||||
#endif
|
||||
|
||||
#if defined(VTFT_CTRL_V03)
|
||||
if (heltec_version == 3) {
|
||||
pinMode(VTFT_CTRL_V03, OUTPUT);
|
||||
digitalWrite(VTFT_CTRL_V03, LOW);
|
||||
} else {
|
||||
pinMode(VTFT_CTRL_V05, OUTPUT);
|
||||
digitalWrite(VTFT_CTRL_V05, LOW);
|
||||
}
|
||||
pinMode(VTFT_CTRL_V03, OUTPUT);
|
||||
digitalWrite(VTFT_CTRL_V03, LOW);
|
||||
#endif
|
||||
|
||||
#if defined(VGNSS_CTRL)
|
||||
@@ -389,7 +349,7 @@ void setup()
|
||||
pinMode(PIN_3V3_EN, OUTPUT);
|
||||
digitalWrite(PIN_3V3_EN, HIGH);
|
||||
#endif
|
||||
#ifndef USE_EINK
|
||||
#ifdef AQ_SET_PIN
|
||||
// RAK-12039 set pin for Air quality sensor
|
||||
pinMode(AQ_SET_PIN, OUTPUT);
|
||||
digitalWrite(AQ_SET_PIN, HIGH);
|
||||
@@ -548,6 +508,7 @@ void setup()
|
||||
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::BME_680, meshtastic_TelemetrySensorType_BME680)
|
||||
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::BME_280, meshtastic_TelemetrySensorType_BME280)
|
||||
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::BMP_280, meshtastic_TelemetrySensorType_BMP280)
|
||||
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::BMP_085, meshtastic_TelemetrySensorType_BMP085)
|
||||
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::INA260, meshtastic_TelemetrySensorType_INA260)
|
||||
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::INA219, meshtastic_TelemetrySensorType_INA219)
|
||||
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::INA3221, meshtastic_TelemetrySensorType_INA3221)
|
||||
@@ -595,7 +556,7 @@ void setup()
|
||||
|
||||
// We do this as early as possible because this loads preferences from flash
|
||||
// but we need to do this after main cpu init (esp32setup), because we need the random seed set
|
||||
nodeDB.init();
|
||||
nodeDB = new NodeDB;
|
||||
|
||||
// If we're taking on the repeater role, use flood router and turn off 3V3_S rail because peripherals are not needed
|
||||
if (config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER) {
|
||||
@@ -670,7 +631,7 @@ void setup()
|
||||
#else
|
||||
// ESP32
|
||||
SPI.begin(LORA_SCK, LORA_MISO, LORA_MOSI, LORA_CS);
|
||||
LOG_WARN("SPI.begin(SCK=%d, MISO=%d, MOSI=%d, NSS=%d)\n", LORA_SCK, LORA_MISO, LORA_MOSI, LORA_CS);
|
||||
LOG_DEBUG("SPI.begin(SCK=%d, MISO=%d, MOSI=%d, NSS=%d)\n", LORA_SCK, LORA_MISO, LORA_MOSI, LORA_CS);
|
||||
SPI.setFrequency(4000000);
|
||||
#endif
|
||||
|
||||
@@ -689,7 +650,7 @@ void setup()
|
||||
} else {
|
||||
LOG_DEBUG("Running without GPS.\n");
|
||||
}
|
||||
nodeStatus->observe(&nodeDB.newStatus);
|
||||
nodeStatus->observe(&nodeDB->newStatus);
|
||||
|
||||
#ifdef HAS_I2S
|
||||
LOG_DEBUG("Starting audio thread\n");
|
||||
@@ -728,6 +689,11 @@ void setup()
|
||||
digitalWrite(SX126X_ANT_SW, 1);
|
||||
#endif
|
||||
|
||||
#ifdef PIN_PWR_DELAY_MS
|
||||
// This may be required to give the peripherals time to power up.
|
||||
delay(PIN_PWR_DELAY_MS);
|
||||
#endif
|
||||
|
||||
#ifdef ARCH_PORTDUINO
|
||||
if (settingsMap[use_sx1262]) {
|
||||
if (!rIf) {
|
||||
@@ -878,7 +844,7 @@ void setup()
|
||||
if ((config.lora.region == meshtastic_Config_LoRaConfig_RegionCode_LORA_24) && (!rIf->wideLora())) {
|
||||
LOG_WARN("Radio chip does not support 2.4GHz LoRa. Reverting to unset.\n");
|
||||
config.lora.region = meshtastic_Config_LoRaConfig_RegionCode_UNSET;
|
||||
nodeDB.saveToDisk(SEGMENT_CONFIG);
|
||||
nodeDB->saveToDisk(SEGMENT_CONFIG);
|
||||
if (!rIf->reconfigure()) {
|
||||
LOG_WARN("Reconfigure failed, rebooting\n");
|
||||
screen->startRebootScreen();
|
||||
@@ -900,12 +866,17 @@ void setup()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef ARCH_ESP32
|
||||
#if defined(ARCH_ESP32) && !MESHTASTIC_EXCLUDE_WEBSERVER
|
||||
// Start web server thread.
|
||||
webServerThread = new WebServerThread();
|
||||
#endif
|
||||
|
||||
#ifdef ARCH_PORTDUINO
|
||||
#if __has_include(<ulfius.h>)
|
||||
if (settingsMap[webserverport] != -1) {
|
||||
piwebServerThread = new PiWebServerThread();
|
||||
}
|
||||
#endif
|
||||
initApiServer(TCPPort);
|
||||
#endif
|
||||
|
||||
|
||||
@@ -70,8 +70,6 @@ extern uint32_t shutdownAtMsec;
|
||||
|
||||
extern uint32_t serialSinceMsec;
|
||||
|
||||
extern int heltec_version;
|
||||
|
||||
// If a thread does something that might need for it to be rescheduled ASAP it can set this flag
|
||||
// This will suppress the current delay and instead try to run ASAP.
|
||||
extern bool runASAP;
|
||||
|
||||
@@ -2,10 +2,13 @@
|
||||
#include "CryptoEngine.h"
|
||||
#include "DisplayFormatters.h"
|
||||
#include "NodeDB.h"
|
||||
#include "RadioInterface.h"
|
||||
#include "configuration.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "mqtt/MQTT.h"
|
||||
|
||||
/// 16 bytes of random PSK for our _public_ default channel that all devices power up on (AES128)
|
||||
static const uint8_t defaultpsk[] = {0xd4, 0xf1, 0xbb, 0x3a, 0x20, 0x29, 0x07, 0x59,
|
||||
0xf0, 0xbc, 0xff, 0xab, 0xcf, 0x4e, 0x69, 0x01};
|
||||
@@ -87,6 +90,8 @@ void Channels::initDefaultChannel(ChannelIndex chIndex)
|
||||
channelSettings.psk.bytes[0] = defaultpskIndex;
|
||||
channelSettings.psk.size = 1;
|
||||
strncpy(channelSettings.name, "", sizeof(channelSettings.name));
|
||||
channelSettings.module_settings.position_precision = 32; // default to sending location on the primary channel
|
||||
channelSettings.has_module_settings = true;
|
||||
|
||||
ch.has_settings = true;
|
||||
ch.role = meshtastic_Channel_Role_PRIMARY;
|
||||
@@ -190,6 +195,10 @@ void Channels::onConfigChanged()
|
||||
if (ch.role == meshtastic_Channel_Role_PRIMARY)
|
||||
primaryIndex = i;
|
||||
}
|
||||
if (channels.anyMqttEnabled() && mqtt && !mqtt->isEnabled()) {
|
||||
LOG_DEBUG("MQTT is enabled on at least one channel, so set MQTT thread to run immediately\n");
|
||||
mqtt->start();
|
||||
}
|
||||
}
|
||||
|
||||
meshtastic_Channel &Channels::getByIndex(ChannelIndex chIndex)
|
||||
@@ -234,6 +243,16 @@ void Channels::setChannel(const meshtastic_Channel &c)
|
||||
old = c; // slam in the new settings/role
|
||||
}
|
||||
|
||||
bool Channels::anyMqttEnabled()
|
||||
{
|
||||
for (int i = 0; i < getNumChannels(); i++)
|
||||
if (channelFile.channels[i].role != meshtastic_Channel_Role_DISABLED && channelFile.channels[i].has_settings &&
|
||||
(channelFile.channels[i].settings.downlink_enabled || channelFile.channels[i].settings.uplink_enabled))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *Channels::getName(size_t chIndex)
|
||||
{
|
||||
// Convert the short "" representation for Default into a usable string
|
||||
@@ -252,38 +271,23 @@ const char *Channels::getName(size_t chIndex)
|
||||
return channelName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a short suffix used to disambiguate channels that might have the same "name" entered by the human but different PSKs.
|
||||
* The ideas is that the PSK changing should be visible to the user so that they see they probably messed up and that's why they
|
||||
their nodes
|
||||
* aren't talking to each other.
|
||||
*
|
||||
* This string is of the form "#name-X".
|
||||
*
|
||||
* Where X is either:
|
||||
* (for custom PSKS) a letter from A to Z (base26), and formed by xoring all the bytes of the PSK together,
|
||||
*
|
||||
* This function will also need to be implemented in GUI apps that talk to the radio.
|
||||
*
|
||||
* https://github.com/meshtastic/firmware/issues/269
|
||||
*/
|
||||
const char *Channels::getPrimaryName()
|
||||
bool Channels::hasDefaultChannel()
|
||||
{
|
||||
static char buf[32];
|
||||
|
||||
char suffix;
|
||||
// auto channelSettings = getPrimary();
|
||||
// if (channelSettings.psk.size != 1) {
|
||||
// We have a standard PSK, so generate a letter based hash.
|
||||
uint8_t code = getHash(primaryIndex);
|
||||
|
||||
suffix = 'A' + (code % 26);
|
||||
/* } else {
|
||||
suffix = '0' + channelSettings.psk.bytes[0];
|
||||
} */
|
||||
|
||||
snprintf(buf, sizeof(buf), "#%s-%c", getName(primaryIndex), suffix);
|
||||
return buf;
|
||||
// If we don't use a preset or the default frequency slot, or we override the frequency, we don't have a default channel
|
||||
if (!config.lora.use_preset || !RadioInterface::uses_default_frequency_slot || config.lora.override_frequency)
|
||||
return false;
|
||||
// Check if any of the channels are using the default name and PSK
|
||||
for (size_t i = 0; i < getNumChannels(); i++) {
|
||||
const auto &ch = getByIndex(i);
|
||||
if (ch.settings.psk.size == 1 && ch.settings.psk.bytes[0] == 1) {
|
||||
const char *name = getName(i);
|
||||
const char *presetName = DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, false);
|
||||
// Check if the name is the default derived from the modem preset
|
||||
if (strcmp(name, presetName) == 0)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Given a channel hash setup crypto for decoding that channel (or the primary channel if that channel is unsecured)
|
||||
|
||||
@@ -61,25 +61,6 @@ class Channels
|
||||
|
||||
ChannelIndex getNumChannels() { return channelFile.channels_count; }
|
||||
|
||||
/**
|
||||
* Generate a short suffix used to disambiguate channels that might have the same "name" entered by the human but different
|
||||
PSKs.
|
||||
* The ideas is that the PSK changing should be visible to the user so that they see they probably messed up and that's why
|
||||
they their nodes
|
||||
* aren't talking to each other.
|
||||
*
|
||||
* This string is of the form "#name-X".
|
||||
*
|
||||
* Where X is either:
|
||||
* (for custom PSKS) a letter from A to Z (base26), and formed by xoring all the bytes of the PSK together,
|
||||
* OR (for the standard minimially secure PSKs) a number from 0 to 9.
|
||||
*
|
||||
* This function will also need to be implemented in GUI apps that talk to the radio.
|
||||
*
|
||||
* https://github.com/meshtastic/firmware/issues/269
|
||||
*/
|
||||
const char *getPrimaryName();
|
||||
|
||||
/// Called by NodeDB on initial boot when the radio config settings are unset. Set a default single channel config.
|
||||
void initDefaults();
|
||||
|
||||
@@ -102,6 +83,12 @@ class Channels
|
||||
*/
|
||||
int16_t setActiveByIndex(ChannelIndex channelIndex);
|
||||
|
||||
// Returns true if we can be reached via a channel with the default settings given a region and modem preset
|
||||
bool hasDefaultChannel();
|
||||
|
||||
// Returns true if any of our channels have enabled MQTT uplink or downlink
|
||||
bool anyMqttEnabled();
|
||||
|
||||
private:
|
||||
/** Given a channel index, change to use the crypto key specified by that index
|
||||
*
|
||||
|
||||
23
src/mesh/Default.cpp
Normal file
23
src/mesh/Default.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
#include "Default.h"
|
||||
|
||||
uint32_t Default::getConfiguredOrDefaultMs(uint32_t configuredInterval)
|
||||
{
|
||||
if (configuredInterval > 0)
|
||||
return configuredInterval * 1000;
|
||||
return default_broadcast_interval_secs * 1000;
|
||||
}
|
||||
|
||||
uint32_t Default::getConfiguredOrDefaultMs(uint32_t configuredInterval, uint32_t defaultInterval)
|
||||
{
|
||||
if (configuredInterval > 0)
|
||||
return configuredInterval * 1000;
|
||||
return defaultInterval * 1000;
|
||||
}
|
||||
|
||||
uint32_t Default::getConfiguredOrDefault(uint32_t configured, uint32_t defaultValue)
|
||||
{
|
||||
if (configured > 0)
|
||||
return configured;
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
30
src/mesh/Default.h
Normal file
30
src/mesh/Default.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
#include <NodeDB.h>
|
||||
#include <cstdint>
|
||||
#define ONE_DAY 24 * 60 * 60
|
||||
|
||||
#define default_gps_update_interval IF_ROUTER(ONE_DAY, 2 * 60)
|
||||
#define default_broadcast_interval_secs IF_ROUTER(ONE_DAY / 2, 15 * 60)
|
||||
#define default_wait_bluetooth_secs IF_ROUTER(1, 60)
|
||||
#define default_sds_secs IF_ROUTER(ONE_DAY, UINT32_MAX) // Default to forever super deep sleep
|
||||
#define default_ls_secs IF_ROUTER(ONE_DAY, 5 * 60)
|
||||
#define default_min_wake_secs 10
|
||||
#define default_screen_on_secs IF_ROUTER(1, 60 * 10)
|
||||
#define default_node_info_broadcast_secs 3 * 60 * 60
|
||||
#define min_node_info_broadcast_secs 60 * 60 // No regular broadcasts of more than once an hour
|
||||
|
||||
#define default_mqtt_address "mqtt.meshtastic.org"
|
||||
#define default_mqtt_username "meshdev"
|
||||
#define default_mqtt_password "large4cats"
|
||||
#define default_mqtt_root "msh"
|
||||
|
||||
#define IF_ROUTER(routerVal, normalVal) \
|
||||
((config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER) ? (routerVal) : (normalVal))
|
||||
|
||||
class Default
|
||||
{
|
||||
public:
|
||||
static uint32_t getConfiguredOrDefaultMs(uint32_t configuredInterval);
|
||||
static uint32_t getConfiguredOrDefaultMs(uint32_t configuredInterval, uint32_t defaultInterval);
|
||||
static uint32_t getConfiguredOrDefault(uint32_t configured, uint32_t defaultValue);
|
||||
};
|
||||
@@ -21,7 +21,7 @@ bool FloodingRouter::shouldFilterReceived(const meshtastic_MeshPacket *p)
|
||||
{
|
||||
if (wasSeenRecently(p)) { // Note: this will also add a recent packet record
|
||||
printPacket("Ignoring incoming msg, because we've already seen it", p);
|
||||
if (!moduleConfig.mqtt.enabled && config.device.role != meshtastic_Config_DeviceConfig_Role_ROUTER &&
|
||||
if (config.device.role != meshtastic_Config_DeviceConfig_Role_ROUTER &&
|
||||
config.device.role != meshtastic_Config_DeviceConfig_Role_ROUTER_CLIENT &&
|
||||
config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER) {
|
||||
// cancel rebroadcast of this message *if* there was already one, unless we're a router/repeater!
|
||||
@@ -49,15 +49,6 @@ void FloodingRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas
|
||||
|
||||
tosend->hop_limit--; // bump down the hop count
|
||||
|
||||
if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
|
||||
// If it is a traceRoute request, update the route that it went via me
|
||||
if (traceRouteModule && traceRouteModule->wantPacket(p))
|
||||
traceRouteModule->updateRoute(tosend);
|
||||
// If it is a neighborInfo packet, update last_sent_by_id
|
||||
if (neighborInfoModule && neighborInfoModule->wantPacket(p))
|
||||
neighborInfoModule->updateLastSentById(tosend);
|
||||
}
|
||||
|
||||
LOG_INFO("Rebroadcasting received floodmsg to neighbors\n");
|
||||
// Note: we are careful to resend using the original senders node id
|
||||
// We are careful not to call our hooked version of send() - because we don't want to check this again
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
#include "PacketHistory.h"
|
||||
#include "Router.h"
|
||||
#include "modules/NeighborInfoModule.h"
|
||||
#include "modules/TraceRouteModule.h"
|
||||
|
||||
/**
|
||||
* This is a mixin that extends Router with the ability to do Naive Flooding (in the standard mesh protocol sense)
|
||||
|
||||
@@ -32,7 +32,8 @@ MeshModule::~MeshModule()
|
||||
assert(0); // FIXME - remove from list of modules once someone needs this feature
|
||||
}
|
||||
|
||||
meshtastic_MeshPacket *MeshModule::allocAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex)
|
||||
meshtastic_MeshPacket *MeshModule::allocAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex,
|
||||
uint8_t hopStart, uint8_t hopLimit)
|
||||
{
|
||||
meshtastic_Routing c = meshtastic_Routing_init_default;
|
||||
|
||||
@@ -49,7 +50,7 @@ meshtastic_MeshPacket *MeshModule::allocAckNak(meshtastic_Routing_Error err, Nod
|
||||
|
||||
p->priority = meshtastic_MeshPacket_Priority_ACK;
|
||||
|
||||
p->hop_limit = config.lora.hop_limit; // Flood ACK back to original sender
|
||||
p->hop_limit = routingModule->getHopLimitForResponse(hopStart, hopLimit); // Flood ACK back to original sender
|
||||
p->to = to;
|
||||
p->decoded.request_id = idFrom;
|
||||
p->channel = chIndex;
|
||||
@@ -80,7 +81,7 @@ void MeshModule::callPlugins(meshtastic_MeshPacket &mp, RxSource src)
|
||||
bool ignoreRequest = false; // No module asked to ignore the request yet
|
||||
|
||||
// Was this message directed to us specifically? Will be false if we are sniffing someone elses packets
|
||||
auto ourNodeNum = nodeDB.getNodeNum();
|
||||
auto ourNodeNum = nodeDB->getNodeNum();
|
||||
bool toUs = mp.to == NODENUM_BROADCAST || mp.to == ourNodeNum;
|
||||
|
||||
for (auto i = modules->begin(); i != modules->end(); ++i) {
|
||||
@@ -176,7 +177,8 @@ void MeshModule::callPlugins(meshtastic_MeshPacket &mp, RxSource src)
|
||||
// SECURITY NOTE! I considered sending back a different error code if we didn't find the psk (i.e. !isDecoded)
|
||||
// but opted NOT TO. Because it is not a good idea to let remote nodes 'probe' to find out which PSKs were "good" vs
|
||||
// bad.
|
||||
routingModule->sendAckNak(meshtastic_Routing_Error_NO_RESPONSE, getFrom(&mp), mp.id, mp.channel);
|
||||
routingModule->sendAckNak(meshtastic_Routing_Error_NO_RESPONSE, getFrom(&mp), mp.id, mp.channel, mp.hop_start,
|
||||
mp.hop_limit);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,6 +219,7 @@ void setReplyTo(meshtastic_MeshPacket *p, const meshtastic_MeshPacket &to)
|
||||
assert(p->which_payload_variant == meshtastic_MeshPacket_decoded_tag); // Should already be set by now
|
||||
p->to = getFrom(&to); // Make sure that if we are sending to the local node, we use our local node addr, not 0
|
||||
p->channel = to.channel; // Use the same channel that the request came in on
|
||||
p->hop_limit = routingModule->getHopLimitForResponse(to.hop_start, to.hop_limit);
|
||||
|
||||
// No need for an ack if we are just delivering locally (it just generates an ignored ack)
|
||||
p->want_ack = (to.from != 0) ? to.want_ack : false;
|
||||
@@ -276,4 +279,4 @@ AdminMessageHandleResult MeshModule::handleAdminMessageForAllPlugins(const mesht
|
||||
}
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
}
|
||||
@@ -153,7 +153,8 @@ class MeshModule
|
||||
virtual bool wantUIFrame() { return false; }
|
||||
virtual Observable<const UIFrameEvent *> *getUIFrameObservable() { return NULL; }
|
||||
|
||||
meshtastic_MeshPacket *allocAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex);
|
||||
meshtastic_MeshPacket *allocAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex,
|
||||
uint8_t hopStart = 0, uint8_t hopLimit = 0);
|
||||
|
||||
/// Send an error response for the specified packet.
|
||||
meshtastic_MeshPacket *allocErrorResponse(meshtastic_Routing_Error err, const meshtastic_MeshPacket *p);
|
||||
|
||||
@@ -71,7 +71,7 @@ MeshService::MeshService()
|
||||
void MeshService::init()
|
||||
{
|
||||
// moved much earlier in boot (called from setup())
|
||||
// nodeDB.init();
|
||||
// nodeDB->init();
|
||||
|
||||
if (gps)
|
||||
gpsObserver.observe(&gps->newStatus);
|
||||
@@ -81,13 +81,13 @@ int MeshService::handleFromRadio(const meshtastic_MeshPacket *mp)
|
||||
{
|
||||
powerFSM.trigger(EVENT_PACKET_FOR_PHONE); // Possibly keep the node from sleeping
|
||||
|
||||
nodeDB.updateFrom(*mp); // update our DB state based off sniffing every RX packet from the radio
|
||||
nodeDB->updateFrom(*mp); // update our DB state based off sniffing every RX packet from the radio
|
||||
if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag &&
|
||||
mp->decoded.portnum == meshtastic_PortNum_TELEMETRY_APP && mp->decoded.request_id > 0) {
|
||||
LOG_DEBUG(
|
||||
"Received telemetry response. Skip sending our NodeInfo because this potentially a Repeater which will ignore our "
|
||||
"request for its NodeInfo.\n");
|
||||
} else if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag && !nodeDB.getMeshNode(mp->from)->has_user &&
|
||||
} else if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag && !nodeDB->getMeshNode(mp->from)->has_user &&
|
||||
nodeInfoModule) {
|
||||
LOG_INFO("Heard a node on channel %d we don't know, sending NodeInfo and asking for a response.\n", mp->channel);
|
||||
nodeInfoModule->sendOurNodeInfo(mp->from, true, mp->channel);
|
||||
@@ -120,10 +120,10 @@ bool MeshService::reloadConfig(int saveWhat)
|
||||
// If we can successfully set this radio to these settings, save them to disk
|
||||
|
||||
// This will also update the region as needed
|
||||
bool didReset = nodeDB.resetRadioConfig(); // Don't let the phone send us fatally bad settings
|
||||
bool didReset = nodeDB->resetRadioConfig(); // Don't let the phone send us fatally bad settings
|
||||
|
||||
configChanged.notifyObservers(NULL); // This will cause radio hardware to change freqs etc
|
||||
nodeDB.saveToDisk(saveWhat);
|
||||
nodeDB->saveToDisk(saveWhat);
|
||||
|
||||
return didReset;
|
||||
}
|
||||
@@ -133,7 +133,7 @@ void MeshService::reloadOwner(bool shouldSave)
|
||||
{
|
||||
// LOG_DEBUG("reloadOwner()\n");
|
||||
// update our local data directly
|
||||
nodeDB.updateUser(nodeDB.getNodeNum(), owner);
|
||||
nodeDB->updateUser(nodeDB->getNodeNum(), owner);
|
||||
assert(nodeInfoModule);
|
||||
// update everyone else and save to disk
|
||||
if (nodeInfoModule && shouldSave) {
|
||||
@@ -192,7 +192,7 @@ void MeshService::handleToRadio(meshtastic_MeshPacket &p)
|
||||
LOG_WARN("phone tried to pick a nodenum, we don't allow that.\n");
|
||||
p.from = 0;
|
||||
} else {
|
||||
// p.from = nodeDB.getNodeNum();
|
||||
// p.from = nodeDB->getNodeNum();
|
||||
}
|
||||
|
||||
if (p.id == 0)
|
||||
@@ -217,7 +217,7 @@ void MeshService::handleToRadio(meshtastic_MeshPacket &p)
|
||||
/** Attempt to cancel a previously sent packet from this _local_ node. Returns true if a packet was found we could cancel */
|
||||
bool MeshService::cancelSending(PacketId id)
|
||||
{
|
||||
return router->cancelSending(nodeDB.getNodeNum(), id);
|
||||
return router->cancelSending(nodeDB->getNodeNum(), id);
|
||||
}
|
||||
|
||||
ErrorCode MeshService::sendQueueStatusToPhone(const meshtastic_QueueStatus &qs, ErrorCode res, uint32_t mesh_packet_id)
|
||||
@@ -245,7 +245,7 @@ ErrorCode MeshService::sendQueueStatusToPhone(const meshtastic_QueueStatus &qs,
|
||||
void MeshService::sendToMesh(meshtastic_MeshPacket *p, RxSource src, bool ccToPhone)
|
||||
{
|
||||
uint32_t mesh_packet_id = p->id;
|
||||
nodeDB.updateFrom(*p); // update our local DB for this packet (because phone might have sent position packets etc...)
|
||||
nodeDB->updateFrom(*p); // update our local DB for this packet (because phone might have sent position packets etc...)
|
||||
|
||||
// Note: We might return !OK if our fifo was full, at that point the only option we have is to drop it
|
||||
ErrorCode res = router->sendLocal(p, src);
|
||||
@@ -265,7 +265,7 @@ void MeshService::sendToMesh(meshtastic_MeshPacket *p, RxSource src, bool ccToPh
|
||||
|
||||
void MeshService::sendNetworkPing(NodeNum dest, bool wantReplies)
|
||||
{
|
||||
meshtastic_NodeInfoLite *node = nodeDB.getMeshNode(nodeDB.getNodeNum());
|
||||
meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(nodeDB->getNodeNum());
|
||||
|
||||
assert(node);
|
||||
|
||||
@@ -320,7 +320,7 @@ void MeshService::sendMqttMessageToClientProxy(meshtastic_MqttClientProxyMessage
|
||||
|
||||
meshtastic_NodeInfoLite *MeshService::refreshLocalMeshNode()
|
||||
{
|
||||
meshtastic_NodeInfoLite *node = nodeDB.getMeshNode(nodeDB.getNodeNum());
|
||||
meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(nodeDB->getNodeNum());
|
||||
assert(node);
|
||||
|
||||
// We might not have a position yet for our local node, in that case, at least try to send the time
|
||||
@@ -359,7 +359,7 @@ int MeshService::onGPSChanged(const meshtastic::GPSStatus *newStatus)
|
||||
LOG_DEBUG("onGPSchanged() - lost validLocation\n");
|
||||
#endif
|
||||
}
|
||||
// Used fixed position if configured regalrdless of GPS lock
|
||||
// Used fixed position if configured regardless of GPS lock
|
||||
if (config.position.fixed_position) {
|
||||
LOG_WARN("Using fixed position\n");
|
||||
pos = TypeConversions::ConvertToPosition(node->position);
|
||||
@@ -373,7 +373,7 @@ int MeshService::onGPSChanged(const meshtastic::GPSStatus *newStatus)
|
||||
pos.longitude_i, pos.altitude);
|
||||
|
||||
// Update our current position in the local DB
|
||||
nodeDB.updatePosition(nodeDB.getNodeNum(), pos, RX_SRC_LOCAL);
|
||||
nodeDB->updatePosition(nodeDB->getNodeNum(), pos, RX_SRC_LOCAL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "../detect/ScanI2C.h"
|
||||
#include "Channels.h"
|
||||
#include "CryptoEngine.h"
|
||||
#include "Default.h"
|
||||
#include "FSCommon.h"
|
||||
#include "GPS.h"
|
||||
#include "MeshRadio.h"
|
||||
@@ -17,8 +18,11 @@
|
||||
#include "mesh-pb-constants.h"
|
||||
#include "modules/NeighborInfoModule.h"
|
||||
#include <ErriezCRC32.h>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <pb_decode.h>
|
||||
#include <pb_encode.h>
|
||||
#include <vector>
|
||||
|
||||
#ifdef ARCH_ESP32
|
||||
#include "mesh/wifi/WiFiAPClient.h"
|
||||
@@ -36,7 +40,7 @@
|
||||
#include <utility/bonding.h>
|
||||
#endif
|
||||
|
||||
NodeDB nodeDB;
|
||||
NodeDB *nodeDB = nullptr;
|
||||
|
||||
// we have plenty of ram so statically alloc this tempbuf (for now)
|
||||
EXT_RAM_ATTR meshtastic_DeviceState devicestate;
|
||||
@@ -46,6 +50,26 @@ meshtastic_LocalModuleConfig moduleConfig;
|
||||
meshtastic_ChannelFile channelFile;
|
||||
meshtastic_OEMStore oemStore;
|
||||
|
||||
bool meshtastic_DeviceState_callback(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_iter_t *field)
|
||||
{
|
||||
if (ostream) {
|
||||
std::vector<meshtastic_NodeInfoLite> *vec = (std::vector<meshtastic_NodeInfoLite> *)field->pData;
|
||||
for (auto item : *vec) {
|
||||
if (!pb_encode_tag_for_field(ostream, field))
|
||||
return false;
|
||||
pb_encode_submessage(ostream, meshtastic_NodeInfoLite_fields, &item);
|
||||
}
|
||||
}
|
||||
if (istream) {
|
||||
meshtastic_NodeInfoLite node; // this gets good data
|
||||
std::vector<meshtastic_NodeInfoLite> *vec = (std::vector<meshtastic_NodeInfoLite> *)field->pData;
|
||||
|
||||
if (istream->bytes_left && pb_decode(istream, meshtastic_NodeInfoLite_fields, &node))
|
||||
vec->push_back(node);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/** The current change # for radio settings. Starts at 0 on boot and any time the radio settings
|
||||
* might have changed is incremented. Allows others to detect they might now be on a new channel.
|
||||
*/
|
||||
@@ -68,7 +92,63 @@ uint32_t error_address = 0;
|
||||
|
||||
static uint8_t ourMacAddr[6];
|
||||
|
||||
NodeDB::NodeDB() : meshNodes(devicestate.node_db_lite), numMeshNodes(&devicestate.node_db_lite_count) {}
|
||||
NodeDB::NodeDB()
|
||||
{
|
||||
LOG_INFO("Initializing NodeDB\n");
|
||||
loadFromDisk();
|
||||
cleanupMeshDB();
|
||||
|
||||
uint32_t devicestateCRC = crc32Buffer(&devicestate, sizeof(devicestate));
|
||||
uint32_t configCRC = crc32Buffer(&config, sizeof(config));
|
||||
uint32_t channelFileCRC = crc32Buffer(&channelFile, sizeof(channelFile));
|
||||
|
||||
int saveWhat = 0;
|
||||
|
||||
// likewise - we always want the app requirements to come from the running appload
|
||||
myNodeInfo.min_app_version = 30200; // format is Mmmss (where M is 1+the numeric major number. i.e. 30200 means 2.2.00
|
||||
// Note! We do this after loading saved settings, so that if somehow an invalid nodenum was stored in preferences we won't
|
||||
// keep using that nodenum forever. Crummy guess at our nodenum (but we will check against the nodedb to avoid conflicts)
|
||||
pickNewNodeNum();
|
||||
|
||||
// Set our board type so we can share it with others
|
||||
owner.hw_model = HW_VENDOR;
|
||||
// Ensure user (nodeinfo) role is set to whatever we're configured to
|
||||
owner.role = config.device.role;
|
||||
|
||||
// Include our owner in the node db under our nodenum
|
||||
meshtastic_NodeInfoLite *info = getOrCreateMeshNode(getNodeNum());
|
||||
info->user = owner;
|
||||
info->has_user = true;
|
||||
|
||||
#ifdef ARCH_ESP32
|
||||
Preferences preferences;
|
||||
preferences.begin("meshtastic", false);
|
||||
myNodeInfo.reboot_count = preferences.getUInt("rebootCounter", 0);
|
||||
preferences.end();
|
||||
LOG_DEBUG("Number of Device Reboots: %d\n", myNodeInfo.reboot_count);
|
||||
#endif
|
||||
|
||||
resetRadioConfig(); // If bogus settings got saved, then fix them
|
||||
// nodeDB->LOG_DEBUG("region=%d, NODENUM=0x%x, dbsize=%d\n", config.lora.region, myNodeInfo.my_node_num, numMeshNodes);
|
||||
|
||||
if (devicestateCRC != crc32Buffer(&devicestate, sizeof(devicestate)))
|
||||
saveWhat |= SEGMENT_DEVICESTATE;
|
||||
if (configCRC != crc32Buffer(&config, sizeof(config)))
|
||||
saveWhat |= SEGMENT_CONFIG;
|
||||
if (channelFileCRC != crc32Buffer(&channelFile, sizeof(channelFile)))
|
||||
saveWhat |= SEGMENT_CHANNELS;
|
||||
|
||||
if (!devicestate.node_remote_hardware_pins) {
|
||||
meshtastic_NodeRemoteHardwarePin empty[12] = {meshtastic_RemoteHardwarePin_init_default};
|
||||
memcpy(devicestate.node_remote_hardware_pins, empty, sizeof(empty));
|
||||
}
|
||||
|
||||
if (config.position.gps_enabled) {
|
||||
config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_ENABLED;
|
||||
config.position.gps_enabled = 0;
|
||||
}
|
||||
saveToDisk(saveWhat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Most (but not always) of the time we want to treat packets 'from' the local phone (where from == 0), as if they originated on
|
||||
@@ -76,7 +156,7 @@ NodeDB::NodeDB() : meshNodes(devicestate.node_db_lite), numMeshNodes(&devicestat
|
||||
*/
|
||||
NodeNum getFrom(const meshtastic_MeshPacket *p)
|
||||
{
|
||||
return (p->from == 0) ? nodeDB.getNodeNum() : p->from;
|
||||
return (p->from == 0) ? nodeDB->getNodeNum() : p->from;
|
||||
}
|
||||
|
||||
bool NodeDB::resetRadioConfig(bool factory_reset)
|
||||
@@ -97,22 +177,6 @@ bool NodeDB::resetRadioConfig(bool factory_reset)
|
||||
|
||||
channels.onConfigChanged();
|
||||
|
||||
// temp hack for quicker testing
|
||||
// devicestate.no_save = true;
|
||||
if (devicestate.no_save) {
|
||||
LOG_DEBUG("***** DEVELOPMENT MODE - DO NOT RELEASE *****\n");
|
||||
|
||||
// Sleep quite frequently to stress test the BLE comms, broadcast position every 6 mins
|
||||
config.display.screen_on_secs = 10;
|
||||
config.power.wait_bluetooth_secs = 10;
|
||||
config.position.position_broadcast_secs = 6 * 60;
|
||||
config.power.ls_secs = 60;
|
||||
config.lora.region = meshtastic_Config_LoRaConfig_RegionCode_TW;
|
||||
|
||||
// Enter super deep sleep soon and stay there not very long
|
||||
// radioConfig.preferences.sds_secs = 60;
|
||||
}
|
||||
|
||||
// Update the global myRegion
|
||||
initRegion();
|
||||
|
||||
@@ -130,6 +194,9 @@ bool NodeDB::factoryReset()
|
||||
LOG_INFO("Performing factory reset!\n");
|
||||
// first, remove the "/prefs" (this removes most prefs)
|
||||
rmDir("/prefs");
|
||||
if (FSCom.exists("/static/rangetest.csv") && !FSCom.remove("/static/rangetest.csv")) {
|
||||
LOG_ERROR("Could not remove rangetest.csv file\n");
|
||||
}
|
||||
// second, install default state (this will deal with the duplicate mac address issue)
|
||||
installDefaultDeviceState();
|
||||
installDefaultConfig();
|
||||
@@ -196,7 +263,7 @@ void NodeDB::installDefaultConfig()
|
||||
config.position.broadcast_smart_minimum_distance = 100;
|
||||
config.position.broadcast_smart_minimum_interval_secs = 30;
|
||||
if (config.device.role != meshtastic_Config_DeviceConfig_Role_ROUTER)
|
||||
config.device.node_info_broadcast_secs = 3 * 60 * 60;
|
||||
config.device.node_info_broadcast_secs = default_node_info_broadcast_secs;
|
||||
config.device.serial_enabled = true;
|
||||
resetRadioConfig();
|
||||
strncpy(config.network.ntp_server, "0.pool.ntp.org", 32);
|
||||
@@ -365,8 +432,9 @@ void NodeDB::installDefaultChannels()
|
||||
|
||||
void NodeDB::resetNodes()
|
||||
{
|
||||
devicestate.node_db_lite_count = 1;
|
||||
std::fill(&devicestate.node_db_lite[1], &devicestate.node_db_lite[MAX_NUM_NODES - 1], meshtastic_NodeInfoLite());
|
||||
numMeshNodes = 1;
|
||||
std::fill(devicestate.node_db_lite.begin() + 1, devicestate.node_db_lite.end(), meshtastic_NodeInfoLite());
|
||||
clearLocalPosition();
|
||||
saveDeviceStateToDisk();
|
||||
if (neighborInfoModule && moduleConfig.neighbor_info.enabled)
|
||||
neighborInfoModule->resetNeighbors();
|
||||
@@ -375,41 +443,56 @@ void NodeDB::resetNodes()
|
||||
void NodeDB::removeNodeByNum(uint nodeNum)
|
||||
{
|
||||
int newPos = 0, removed = 0;
|
||||
for (int i = 0; i < *numMeshNodes; i++) {
|
||||
if (meshNodes[i].num != nodeNum)
|
||||
meshNodes[newPos++] = meshNodes[i];
|
||||
for (int i = 0; i < numMeshNodes; i++) {
|
||||
if (meshNodes->at(i).num != nodeNum)
|
||||
meshNodes->at(newPos++) = meshNodes->at(i);
|
||||
else
|
||||
removed++;
|
||||
}
|
||||
*numMeshNodes -= removed;
|
||||
numMeshNodes -= removed;
|
||||
std::fill(devicestate.node_db_lite.begin() + numMeshNodes, devicestate.node_db_lite.begin() + numMeshNodes + 1,
|
||||
meshtastic_NodeInfoLite());
|
||||
LOG_DEBUG("NodeDB::removeNodeByNum purged %d entries. Saving changes...\n", removed);
|
||||
saveDeviceStateToDisk();
|
||||
}
|
||||
|
||||
void NodeDB::clearLocalPosition()
|
||||
{
|
||||
meshtastic_NodeInfoLite *node = getMeshNode(nodeDB->getNodeNum());
|
||||
node->position.latitude_i = 0;
|
||||
node->position.longitude_i = 0;
|
||||
node->position.altitude = 0;
|
||||
node->position.time = 0;
|
||||
setLocalPosition(meshtastic_Position_init_default);
|
||||
}
|
||||
|
||||
void NodeDB::cleanupMeshDB()
|
||||
{
|
||||
int newPos = 0, removed = 0;
|
||||
for (int i = 0; i < *numMeshNodes; i++) {
|
||||
if (meshNodes[i].has_user)
|
||||
meshNodes[newPos++] = meshNodes[i];
|
||||
for (int i = 0; i < numMeshNodes; i++) {
|
||||
if (meshNodes->at(i).has_user)
|
||||
meshNodes->at(newPos++) = meshNodes->at(i);
|
||||
else
|
||||
removed++;
|
||||
}
|
||||
*numMeshNodes -= removed;
|
||||
numMeshNodes -= removed;
|
||||
std::fill(devicestate.node_db_lite.begin() + numMeshNodes, devicestate.node_db_lite.begin() + numMeshNodes + removed,
|
||||
meshtastic_NodeInfoLite());
|
||||
LOG_DEBUG("cleanupMeshDB purged %d entries\n", removed);
|
||||
}
|
||||
|
||||
void NodeDB::installDefaultDeviceState()
|
||||
{
|
||||
LOG_INFO("Installing default DeviceState\n");
|
||||
memset(&devicestate, 0, sizeof(meshtastic_DeviceState));
|
||||
// memset(&devicestate, 0, sizeof(meshtastic_DeviceState));
|
||||
|
||||
*numMeshNodes = 0;
|
||||
numMeshNodes = 0;
|
||||
meshNodes = &devicestate.node_db_lite;
|
||||
|
||||
// init our devicestate with valid flags so protobuf writing/reading will work
|
||||
devicestate.has_my_node = true;
|
||||
devicestate.has_owner = true;
|
||||
devicestate.node_db_lite_count = 0;
|
||||
// devicestate.node_db_lite_count = 0;
|
||||
devicestate.version = DEVICESTATE_CUR_VER;
|
||||
devicestate.receive_queue_count = 0; // Not yet implemented FIXME
|
||||
|
||||
@@ -423,65 +506,6 @@ void NodeDB::installDefaultDeviceState()
|
||||
memcpy(owner.macaddr, ourMacAddr, sizeof(owner.macaddr));
|
||||
}
|
||||
|
||||
void NodeDB::init()
|
||||
{
|
||||
LOG_INFO("Initializing NodeDB\n");
|
||||
loadFromDisk();
|
||||
cleanupMeshDB();
|
||||
|
||||
uint32_t devicestateCRC = crc32Buffer(&devicestate, sizeof(devicestate));
|
||||
uint32_t configCRC = crc32Buffer(&config, sizeof(config));
|
||||
uint32_t channelFileCRC = crc32Buffer(&channelFile, sizeof(channelFile));
|
||||
|
||||
int saveWhat = 0;
|
||||
|
||||
// likewise - we always want the app requirements to come from the running appload
|
||||
myNodeInfo.min_app_version = 30200; // format is Mmmss (where M is 1+the numeric major number. i.e. 30200 means 2.2.00
|
||||
// Note! We do this after loading saved settings, so that if somehow an invalid nodenum was stored in preferences we won't
|
||||
// keep using that nodenum forever. Crummy guess at our nodenum (but we will check against the nodedb to avoid conflicts)
|
||||
pickNewNodeNum();
|
||||
|
||||
// Set our board type so we can share it with others
|
||||
owner.hw_model = HW_VENDOR;
|
||||
// Ensure user (nodeinfo) role is set to whatever we're configured to
|
||||
owner.role = config.device.role;
|
||||
|
||||
// Include our owner in the node db under our nodenum
|
||||
meshtastic_NodeInfoLite *info = getOrCreateMeshNode(getNodeNum());
|
||||
info->user = owner;
|
||||
info->has_user = true;
|
||||
|
||||
#ifdef ARCH_ESP32
|
||||
Preferences preferences;
|
||||
preferences.begin("meshtastic", false);
|
||||
myNodeInfo.reboot_count = preferences.getUInt("rebootCounter", 0);
|
||||
preferences.end();
|
||||
LOG_DEBUG("Number of Device Reboots: %d\n", myNodeInfo.reboot_count);
|
||||
#endif
|
||||
|
||||
resetRadioConfig(); // If bogus settings got saved, then fix them
|
||||
LOG_DEBUG("region=%d, NODENUM=0x%x, dbsize=%d\n", config.lora.region, myNodeInfo.my_node_num, *numMeshNodes);
|
||||
|
||||
if (devicestateCRC != crc32Buffer(&devicestate, sizeof(devicestate)))
|
||||
saveWhat |= SEGMENT_DEVICESTATE;
|
||||
if (configCRC != crc32Buffer(&config, sizeof(config)))
|
||||
saveWhat |= SEGMENT_CONFIG;
|
||||
if (channelFileCRC != crc32Buffer(&channelFile, sizeof(channelFile)))
|
||||
saveWhat |= SEGMENT_CHANNELS;
|
||||
|
||||
if (!devicestate.node_remote_hardware_pins) {
|
||||
meshtastic_NodeRemoteHardwarePin empty[12] = {meshtastic_RemoteHardwarePin_init_default};
|
||||
memcpy(devicestate.node_remote_hardware_pins, empty, sizeof(empty));
|
||||
}
|
||||
|
||||
if (config.position.gps_enabled) {
|
||||
config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_ENABLED;
|
||||
config.position.gps_enabled = 0;
|
||||
}
|
||||
|
||||
saveToDisk(saveWhat);
|
||||
}
|
||||
|
||||
// We reserve a few nodenums for future use
|
||||
#define NUM_RESERVED 4
|
||||
|
||||
@@ -503,7 +527,7 @@ void NodeDB::pickNewNodeNum()
|
||||
LOG_WARN("NOTE! Our desired nodenum 0x%x is invalid or in use, so trying for 0x%x\n", nodeNum, candidate);
|
||||
nodeNum = candidate;
|
||||
}
|
||||
LOG_WARN("Using nodenum 0x%x \n", nodeNum);
|
||||
LOG_DEBUG("Using nodenum 0x%x \n", nodeNum);
|
||||
|
||||
myNodeInfo.my_node_num = nodeNum;
|
||||
}
|
||||
@@ -549,17 +573,21 @@ bool NodeDB::loadProto(const char *filename, size_t protoSize, size_t objSize, c
|
||||
void NodeDB::loadFromDisk()
|
||||
{
|
||||
// static DeviceState scratch; We no longer read into a tempbuf because this structure is 15KB of valuable RAM
|
||||
if (!loadProto(prefFileName, meshtastic_DeviceState_size, sizeof(meshtastic_DeviceState), &meshtastic_DeviceState_msg,
|
||||
&devicestate)) {
|
||||
if (!loadProto(prefFileName, sizeof(meshtastic_DeviceState) + MAX_NUM_NODES * sizeof(meshtastic_NodeInfo),
|
||||
sizeof(meshtastic_DeviceState), &meshtastic_DeviceState_msg, &devicestate)) {
|
||||
installDefaultDeviceState(); // Our in RAM copy might now be corrupt
|
||||
} else {
|
||||
if (devicestate.version < DEVICESTATE_MIN_VER) {
|
||||
LOG_WARN("Devicestate %d is old, discarding\n", devicestate.version);
|
||||
factoryReset();
|
||||
} else {
|
||||
LOG_INFO("Loaded saved devicestate version %d\n", devicestate.version);
|
||||
LOG_INFO("Loaded saved devicestate version %d, with nodecount: %d\n", devicestate.version,
|
||||
devicestate.node_db_lite.size());
|
||||
meshNodes = &devicestate.node_db_lite;
|
||||
numMeshNodes = devicestate.node_db_lite.size();
|
||||
}
|
||||
}
|
||||
meshNodes->resize(MAX_NUM_NODES);
|
||||
|
||||
if (!loadProto(configFileName, meshtastic_LocalConfig_size, sizeof(meshtastic_LocalConfig), &meshtastic_LocalConfig_msg,
|
||||
&config)) {
|
||||
@@ -638,7 +666,7 @@ bool NodeDB::saveProto(const char *filename, size_t protoSize, const pb_msgdesc_
|
||||
if (failedCounter >= 2) {
|
||||
FSCom.format();
|
||||
// After formatting, the device needs to be restarted
|
||||
nodeDB.resetRadioConfig(true);
|
||||
nodeDB->resetRadioConfig(true);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -650,68 +678,61 @@ bool NodeDB::saveProto(const char *filename, size_t protoSize, const pb_msgdesc_
|
||||
|
||||
void NodeDB::saveChannelsToDisk()
|
||||
{
|
||||
if (!devicestate.no_save) {
|
||||
#ifdef FSCom
|
||||
FSCom.mkdir("/prefs");
|
||||
FSCom.mkdir("/prefs");
|
||||
#endif
|
||||
saveProto(channelFileName, meshtastic_ChannelFile_size, &meshtastic_ChannelFile_msg, &channelFile);
|
||||
}
|
||||
saveProto(channelFileName, meshtastic_ChannelFile_size, &meshtastic_ChannelFile_msg, &channelFile);
|
||||
}
|
||||
|
||||
void NodeDB::saveDeviceStateToDisk()
|
||||
{
|
||||
if (!devicestate.no_save) {
|
||||
#ifdef FSCom
|
||||
FSCom.mkdir("/prefs");
|
||||
FSCom.mkdir("/prefs");
|
||||
#endif
|
||||
saveProto(prefFileName, meshtastic_DeviceState_size, &meshtastic_DeviceState_msg, &devicestate);
|
||||
}
|
||||
saveProto(prefFileName, sizeof(devicestate) + numMeshNodes * meshtastic_NodeInfoLite_size, &meshtastic_DeviceState_msg,
|
||||
&devicestate);
|
||||
}
|
||||
|
||||
void NodeDB::saveToDisk(int saveWhat)
|
||||
{
|
||||
if (!devicestate.no_save) {
|
||||
#ifdef FSCom
|
||||
FSCom.mkdir("/prefs");
|
||||
FSCom.mkdir("/prefs");
|
||||
#endif
|
||||
if (saveWhat & SEGMENT_DEVICESTATE) {
|
||||
saveDeviceStateToDisk();
|
||||
}
|
||||
if (saveWhat & SEGMENT_DEVICESTATE) {
|
||||
saveDeviceStateToDisk();
|
||||
}
|
||||
|
||||
if (saveWhat & SEGMENT_CONFIG) {
|
||||
config.has_device = true;
|
||||
config.has_display = true;
|
||||
config.has_lora = true;
|
||||
config.has_position = true;
|
||||
config.has_power = true;
|
||||
config.has_network = true;
|
||||
config.has_bluetooth = true;
|
||||
saveProto(configFileName, meshtastic_LocalConfig_size, &meshtastic_LocalConfig_msg, &config);
|
||||
}
|
||||
if (saveWhat & SEGMENT_CONFIG) {
|
||||
config.has_device = true;
|
||||
config.has_display = true;
|
||||
config.has_lora = true;
|
||||
config.has_position = true;
|
||||
config.has_power = true;
|
||||
config.has_network = true;
|
||||
config.has_bluetooth = true;
|
||||
saveProto(configFileName, meshtastic_LocalConfig_size, &meshtastic_LocalConfig_msg, &config);
|
||||
}
|
||||
|
||||
if (saveWhat & SEGMENT_MODULECONFIG) {
|
||||
moduleConfig.has_canned_message = true;
|
||||
moduleConfig.has_external_notification = true;
|
||||
moduleConfig.has_mqtt = true;
|
||||
moduleConfig.has_range_test = true;
|
||||
moduleConfig.has_serial = true;
|
||||
moduleConfig.has_store_forward = true;
|
||||
moduleConfig.has_telemetry = true;
|
||||
saveProto(moduleConfigFileName, meshtastic_LocalModuleConfig_size, &meshtastic_LocalModuleConfig_msg, &moduleConfig);
|
||||
}
|
||||
if (saveWhat & SEGMENT_MODULECONFIG) {
|
||||
moduleConfig.has_canned_message = true;
|
||||
moduleConfig.has_external_notification = true;
|
||||
moduleConfig.has_mqtt = true;
|
||||
moduleConfig.has_range_test = true;
|
||||
moduleConfig.has_serial = true;
|
||||
moduleConfig.has_store_forward = true;
|
||||
moduleConfig.has_telemetry = true;
|
||||
saveProto(moduleConfigFileName, meshtastic_LocalModuleConfig_size, &meshtastic_LocalModuleConfig_msg, &moduleConfig);
|
||||
}
|
||||
|
||||
if (saveWhat & SEGMENT_CHANNELS) {
|
||||
saveChannelsToDisk();
|
||||
}
|
||||
} else {
|
||||
LOG_DEBUG("***** DEVELOPMENT MODE - DO NOT RELEASE - not saving to flash *****\n");
|
||||
if (saveWhat & SEGMENT_CHANNELS) {
|
||||
saveChannelsToDisk();
|
||||
}
|
||||
}
|
||||
|
||||
const meshtastic_NodeInfoLite *NodeDB::readNextMeshNode(uint32_t &readIndex)
|
||||
{
|
||||
if (readIndex < *numMeshNodes)
|
||||
return &meshNodes[readIndex++];
|
||||
if (readIndex < numMeshNodes)
|
||||
return &meshNodes->at(readIndex++);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
@@ -741,14 +762,17 @@ uint32_t sinceReceived(const meshtastic_MeshPacket *p)
|
||||
|
||||
#define NUM_ONLINE_SECS (60 * 60 * 2) // 2 hrs to consider someone offline
|
||||
|
||||
size_t NodeDB::getNumOnlineMeshNodes()
|
||||
size_t NodeDB::getNumOnlineMeshNodes(bool localOnly)
|
||||
{
|
||||
size_t numseen = 0;
|
||||
|
||||
// FIXME this implementation is kinda expensive
|
||||
for (int i = 0; i < *numMeshNodes; i++)
|
||||
if (sinceLastSeen(&meshNodes[i]) < NUM_ONLINE_SECS)
|
||||
for (int i = 0; i < numMeshNodes; i++) {
|
||||
if (localOnly && meshNodes->at(i).via_mqtt)
|
||||
continue;
|
||||
if (sinceLastSeen(&meshNodes->at(i)) < NUM_ONLINE_SECS)
|
||||
numseen++;
|
||||
}
|
||||
|
||||
return numseen;
|
||||
}
|
||||
@@ -872,6 +896,12 @@ void NodeDB::updateFrom(const meshtastic_MeshPacket &mp)
|
||||
|
||||
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->hops_away = mp.hop_start - mp.hop_limit;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -888,9 +918,9 @@ uint8_t NodeDB::getMeshNodeChannel(NodeNum n)
|
||||
/// NOTE: This function might be called from an ISR
|
||||
meshtastic_NodeInfoLite *NodeDB::getMeshNode(NodeNum n)
|
||||
{
|
||||
for (int i = 0; i < *numMeshNodes; i++)
|
||||
if (meshNodes[i].num == n)
|
||||
return &meshNodes[i];
|
||||
for (int i = 0; i < numMeshNodes; i++)
|
||||
if (meshNodes->at(i).num == n)
|
||||
return &meshNodes->at(i);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -901,27 +931,27 @@ meshtastic_NodeInfoLite *NodeDB::getOrCreateMeshNode(NodeNum n)
|
||||
meshtastic_NodeInfoLite *lite = getMeshNode(n);
|
||||
|
||||
if (!lite) {
|
||||
if ((*numMeshNodes >= MAX_NUM_NODES) || (memGet.getFreeHeap() < meshtastic_NodeInfoLite_size * 3)) {
|
||||
if ((numMeshNodes >= MAX_NUM_NODES) || (memGet.getFreeHeap() < meshtastic_NodeInfoLite_size * 3)) {
|
||||
if (screen)
|
||||
screen->print("warning: node_db_lite full! erasing oldest entry\n");
|
||||
LOG_INFO("warning: node_db_lite full! erasing oldest entry\n");
|
||||
screen->print("Warn: node database full!\nErasing oldest entry\n");
|
||||
LOG_WARN("Node database full! Erasing oldest entry\n");
|
||||
// look for oldest node and erase it
|
||||
uint32_t oldest = UINT32_MAX;
|
||||
int oldestIndex = -1;
|
||||
for (int i = 1; i < *numMeshNodes; i++) {
|
||||
if (meshNodes[i].last_heard < oldest) {
|
||||
oldest = meshNodes[i].last_heard;
|
||||
for (int i = 1; i < numMeshNodes; i++) {
|
||||
if (!meshNodes->at(i).is_favorite && meshNodes->at(i).last_heard < oldest) {
|
||||
oldest = meshNodes->at(i).last_heard;
|
||||
oldestIndex = i;
|
||||
}
|
||||
}
|
||||
// Shove the remaining nodes down the chain
|
||||
for (int i = oldestIndex; i < *numMeshNodes - 1; i++) {
|
||||
meshNodes[i] = meshNodes[i + 1];
|
||||
for (int i = oldestIndex; i < numMeshNodes - 1; i++) {
|
||||
meshNodes->at(i) = meshNodes->at(i + 1);
|
||||
}
|
||||
(*numMeshNodes)--;
|
||||
(numMeshNodes)--;
|
||||
}
|
||||
// add the node at the end
|
||||
lite = &meshNodes[(*numMeshNodes)++];
|
||||
lite = &meshNodes->at((numMeshNodes)++);
|
||||
|
||||
// everything is missing except the nodenum
|
||||
memset(lite, 0, sizeof(*lite));
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "Observer.h"
|
||||
#include <Arduino.h>
|
||||
#include <assert.h>
|
||||
#include <vector>
|
||||
|
||||
#include "MeshTypes.h"
|
||||
#include "NodeStatus.h"
|
||||
@@ -45,21 +46,18 @@ class NodeDB
|
||||
// Eventually use a smarter datastructure
|
||||
// HashMap<NodeNum, NodeInfo> nodes;
|
||||
// Note: these two references just point into our static array we serialize to/from disk
|
||||
meshtastic_NodeInfoLite *meshNodes;
|
||||
pb_size_t *numMeshNodes;
|
||||
|
||||
public:
|
||||
std::vector<meshtastic_NodeInfoLite> *meshNodes;
|
||||
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
|
||||
Observable<const meshtastic::NodeStatus *> newStatus;
|
||||
pb_size_t numMeshNodes;
|
||||
|
||||
/// don't do mesh based algorithm for node id assignment (initially)
|
||||
/// instead just store in flash - possibly even in the initial alpha release do this hack
|
||||
NodeDB();
|
||||
|
||||
/// Called from service after app start, to do init which can only be done after OS load
|
||||
void init();
|
||||
|
||||
/// write to flash
|
||||
void saveToDisk(int saveWhat = SEGMENT_CONFIG | SEGMENT_MODULECONFIG | SEGMENT_DEVICESTATE | SEGMENT_CHANNELS),
|
||||
saveChannelsToDisk(), saveDeviceStateToDisk();
|
||||
@@ -108,8 +106,10 @@ class NodeDB
|
||||
// get channel channel index we heard a nodeNum on, defaults to 0 if not found
|
||||
uint8_t getMeshNodeChannel(NodeNum n);
|
||||
|
||||
/// Return the number of nodes we've heard from recently (within the last 2 hrs?)
|
||||
size_t getNumOnlineMeshNodes();
|
||||
/* 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 initConfigIntervals(), initModuleConfigIntervals(), resetNodes(), removeNodeByNum(uint nodeNum);
|
||||
|
||||
@@ -124,15 +124,22 @@ class NodeDB
|
||||
|
||||
meshtastic_NodeInfoLite *getMeshNodeByIndex(size_t x)
|
||||
{
|
||||
assert(x < *numMeshNodes);
|
||||
return &meshNodes[x];
|
||||
assert(x < numMeshNodes);
|
||||
return &meshNodes->at(x);
|
||||
}
|
||||
|
||||
meshtastic_NodeInfoLite *getMeshNode(NodeNum n);
|
||||
size_t getNumMeshNodes() { return *numMeshNodes; }
|
||||
size_t getNumMeshNodes() { return numMeshNodes; }
|
||||
|
||||
void setLocalPosition(meshtastic_Position position)
|
||||
void clearLocalPosition();
|
||||
|
||||
void setLocalPosition(meshtastic_Position position, bool timeOnly = false)
|
||||
{
|
||||
if (timeOnly) {
|
||||
LOG_DEBUG("Setting local position time only: time=%i\n", position.time);
|
||||
localPosition.time = position.time;
|
||||
return;
|
||||
}
|
||||
LOG_DEBUG("Setting local position: latitude=%i, longitude=%i, time=%i\n", position.latitude_i, position.longitude_i,
|
||||
position.time);
|
||||
localPosition = position;
|
||||
@@ -160,7 +167,7 @@ class NodeDB
|
||||
void installDefaultDeviceState(), installDefaultChannels(), installDefaultConfig(), installDefaultModuleConfig();
|
||||
};
|
||||
|
||||
extern NodeDB nodeDB;
|
||||
extern NodeDB *nodeDB;
|
||||
|
||||
/*
|
||||
If is_router is set, we use a number of different default values
|
||||
@@ -184,46 +191,6 @@ extern NodeDB nodeDB;
|
||||
// Our delay functions check for this for times that should never expire
|
||||
#define NODE_DELAY_FOREVER 0xffffffff
|
||||
|
||||
#define IF_ROUTER(routerVal, normalVal) \
|
||||
((config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER) ? (routerVal) : (normalVal))
|
||||
|
||||
#define ONE_DAY 24 * 60 * 60
|
||||
|
||||
#define default_gps_update_interval IF_ROUTER(ONE_DAY, 2 * 60)
|
||||
#define default_broadcast_interval_secs IF_ROUTER(ONE_DAY / 2, 15 * 60)
|
||||
#define default_wait_bluetooth_secs IF_ROUTER(1, 60)
|
||||
#define default_sds_secs IF_ROUTER(ONE_DAY, UINT32_MAX) // Default to forever super deep sleep
|
||||
#define default_ls_secs IF_ROUTER(ONE_DAY, 5 * 60)
|
||||
#define default_min_wake_secs 10
|
||||
#define default_screen_on_secs IF_ROUTER(1, 60 * 10)
|
||||
|
||||
#define default_mqtt_address "mqtt.meshtastic.org"
|
||||
#define default_mqtt_username "meshdev"
|
||||
#define default_mqtt_password "large4cats"
|
||||
#define default_mqtt_root "msh"
|
||||
|
||||
inline uint32_t getConfiguredOrDefaultMs(uint32_t configuredInterval)
|
||||
{
|
||||
if (configuredInterval > 0)
|
||||
return configuredInterval * 1000;
|
||||
return default_broadcast_interval_secs * 1000;
|
||||
}
|
||||
|
||||
inline uint32_t getConfiguredOrDefaultMs(uint32_t configuredInterval, uint32_t defaultInterval)
|
||||
{
|
||||
if (configuredInterval > 0)
|
||||
return configuredInterval * 1000;
|
||||
return defaultInterval * 1000;
|
||||
}
|
||||
|
||||
inline uint32_t getConfiguredOrDefault(uint32_t configured, uint32_t defaultValue)
|
||||
{
|
||||
if (configured > 0)
|
||||
return configured;
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/// Sometimes we will have Position objects that only have a time, so check for
|
||||
/// valid lat/lon
|
||||
static inline bool hasValidPosition(const meshtastic_NodeInfoLite *n)
|
||||
@@ -247,3 +214,5 @@ extern uint32_t error_address;
|
||||
(ModuleConfig_CannedMessageConfig_size + ModuleConfig_ExternalNotificationConfig_size + ModuleConfig_MQTTConfig_size + \
|
||||
ModuleConfig_RangeTestConfig_size + ModuleConfig_SerialConfig_size + ModuleConfig_StoreForwardConfig_size + \
|
||||
ModuleConfig_TelemetryConfig_size + ModuleConfig_size)
|
||||
|
||||
// Please do not remove this comment, it makes trunk and compiler happy at the same time.
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
#include "configuration.h"
|
||||
#include "mesh-pb-constants.h"
|
||||
|
||||
#ifdef ARCH_PORTDUINO
|
||||
#include "platform/portduino/PortduinoGlue.h"
|
||||
#endif
|
||||
|
||||
PacketHistory::PacketHistory()
|
||||
{
|
||||
recentPackets.reserve(MAX_NUM_NODES); // Prealloc the worst case # of records - to prevent heap fragmentation
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "PhoneAPI.h"
|
||||
#include "Channels.h"
|
||||
#include "Default.h"
|
||||
#include "GPS.h"
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
@@ -105,10 +106,17 @@ bool PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
|
||||
break;
|
||||
case meshtastic_ToRadio_mqttClientProxyMessage_tag:
|
||||
LOG_INFO("Got MqttClientProxy message\n");
|
||||
if (mqtt && moduleConfig.mqtt.proxy_to_client_enabled) {
|
||||
if (mqtt && moduleConfig.mqtt.proxy_to_client_enabled && moduleConfig.mqtt.enabled &&
|
||||
(channels.anyMqttEnabled() || moduleConfig.mqtt.map_reporting_enabled)) {
|
||||
mqtt->onClientProxyReceive(toRadioScratch.mqttClientProxyMessage);
|
||||
} else {
|
||||
LOG_WARN("MqttClientProxy received but proxy is not enabled, no channels have up/downlink, or map reporting "
|
||||
"not enabled\n");
|
||||
}
|
||||
break;
|
||||
case meshtastic_ToRadio_heartbeat_tag:
|
||||
LOG_DEBUG("Got client heartbeat\n");
|
||||
break;
|
||||
default:
|
||||
// Ignore nop messages
|
||||
// LOG_DEBUG("Error: unexpected ToRadio variant\n");
|
||||
@@ -413,7 +421,7 @@ bool PhoneAPI::available()
|
||||
|
||||
case STATE_SEND_NODEINFO:
|
||||
if (nodeInfoForPhone.num == 0) {
|
||||
auto nextNode = nodeDB.readNextMeshNode(readIndex);
|
||||
auto nextNode = nodeDB->readNextMeshNode(readIndex);
|
||||
if (nextNode) {
|
||||
nodeInfoForPhone = TypeConversions::ConvertToNodeInfo(nextNode);
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ template <class T> class ProtobufModule : protected SinglePortModule
|
||||
*/
|
||||
const char *getSenderShortName(const meshtastic_MeshPacket &mp)
|
||||
{
|
||||
auto node = nodeDB.getMeshNode(getFrom(&mp));
|
||||
auto node = nodeDB->getMeshNode(getFrom(&mp));
|
||||
const char *sender = (node) ? node->user.short_name : "???";
|
||||
return sender;
|
||||
}
|
||||
@@ -108,8 +108,8 @@ template <class T> class ProtobufModule : protected SinglePortModule
|
||||
// if we can't decode it, nobody can process it!
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return alterReceivedProtobuf(mp, decoded);
|
||||
return alterReceivedProtobuf(mp, decoded);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -19,7 +19,7 @@ RF95Interface::RF95Interface(LockingArduinoHal *hal, RADIOLIB_PIN_TYPE cs, RADIO
|
||||
RADIOLIB_PIN_TYPE busy)
|
||||
: RadioLibInterface(hal, cs, irq, rst, busy)
|
||||
{
|
||||
LOG_WARN("RF95Interface(cs=%d, irq=%d, rst=%d, busy=%d)\n", cs, irq, rst, busy);
|
||||
LOG_DEBUG("RF95Interface(cs=%d, irq=%d, rst=%d, busy=%d)\n", cs, irq, rst, busy);
|
||||
}
|
||||
|
||||
/** Some boards require GPIO control of tx vs rx paths */
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "RadioInterface.h"
|
||||
#include "Channels.h"
|
||||
#include "DisplayFormatters.h"
|
||||
#include "MeshRadio.h"
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
@@ -143,6 +144,7 @@ const RegionInfo regions[] = {
|
||||
};
|
||||
|
||||
const RegionInfo *myRegion;
|
||||
bool RadioInterface::uses_default_frequency_slot = true;
|
||||
|
||||
static uint8_t bytes[MAX_RHPACKETLEN];
|
||||
|
||||
@@ -302,6 +304,8 @@ void printPacket(const char *prefix, const meshtastic_MeshPacket *p)
|
||||
out += DEBUG_PORT.mt_sprintf(" rxRSSI=%i", p->rx_rssi);
|
||||
if (p->via_mqtt != 0)
|
||||
out += DEBUG_PORT.mt_sprintf(" via MQTT");
|
||||
if (p->hop_start != 0)
|
||||
out += DEBUG_PORT.mt_sprintf(" hopStart=%d", p->hop_start);
|
||||
if (p->priority != 0)
|
||||
out += DEBUG_PORT.mt_sprintf(" priority=%d", p->priority);
|
||||
|
||||
@@ -330,8 +334,8 @@ bool RadioInterface::init()
|
||||
notifyDeepSleepObserver.observe(¬ifyDeepSleep);
|
||||
|
||||
// we now expect interfaces to operate in promiscuous mode
|
||||
// radioIf.setThisAddress(nodeDB.getNodeNum()); // Note: we must do this here, because the nodenum isn't inited at constructor
|
||||
// time.
|
||||
// radioIf.setThisAddress(nodeDB->getNodeNum()); // Note: we must do this here, because the nodenum isn't inited at
|
||||
// constructor time.
|
||||
|
||||
applyModemConfig();
|
||||
|
||||
@@ -484,6 +488,10 @@ void RadioInterface::applyModemConfig()
|
||||
// channel_num is actually (channel_num - 1), since modulus (%) returns values from 0 to (numChannels - 1)
|
||||
int channel_num = (loraConfig.channel_num ? loraConfig.channel_num - 1 : hash(channelName)) % numChannels;
|
||||
|
||||
// Check if we use the default frequency slot
|
||||
RadioInterface::uses_default_frequency_slot =
|
||||
channel_num == hash(DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, false)) % numChannels;
|
||||
|
||||
// Old frequency selection formula
|
||||
// float freq = myRegion->freqStart + ((((myRegion->freqEnd - myRegion->freqStart) / numChannels) / 2) * channel_num);
|
||||
|
||||
@@ -556,11 +564,14 @@ size_t RadioInterface::beginSending(meshtastic_MeshPacket *p)
|
||||
h->to = p->to;
|
||||
h->id = p->id;
|
||||
h->channel = p->channel;
|
||||
h->next_hop = 0; // *** For future use ***
|
||||
h->relay_node = 0; // *** For future use ***
|
||||
if (p->hop_limit > HOP_MAX) {
|
||||
LOG_WARN("hop limit %d is too high, setting to %d\n", p->hop_limit, HOP_RELIABLE);
|
||||
p->hop_limit = HOP_RELIABLE;
|
||||
}
|
||||
h->flags = p->hop_limit | (p->want_ack ? PACKET_FLAGS_WANT_ACK_MASK : 0) | (p->via_mqtt ? PACKET_FLAGS_VIA_MQTT_MASK : 0);
|
||||
h->flags |= (p->hop_start << PACKET_FLAGS_HOP_START_SHIFT) & PACKET_FLAGS_HOP_START_MASK;
|
||||
|
||||
// if the sender nodenum is zero, that means uninitialized
|
||||
assert(h->from);
|
||||
@@ -569,4 +580,4 @@ size_t RadioInterface::beginSending(meshtastic_MeshPacket *p)
|
||||
|
||||
sendingPacket = p;
|
||||
return p->encrypted.size + sizeof(PacketHeader);
|
||||
}
|
||||
}
|
||||
@@ -10,9 +10,11 @@
|
||||
|
||||
#define MAX_RHPACKETLEN 256
|
||||
|
||||
#define PACKET_FLAGS_HOP_MASK 0x07
|
||||
#define PACKET_FLAGS_HOP_LIMIT_MASK 0x07
|
||||
#define PACKET_FLAGS_WANT_ACK_MASK 0x08
|
||||
#define PACKET_FLAGS_VIA_MQTT_MASK 0x10
|
||||
#define PACKET_FLAGS_HOP_START_MASK 0xE0
|
||||
#define PACKET_FLAGS_HOP_START_SHIFT 5
|
||||
|
||||
/**
|
||||
* This structure has to exactly match the wire layout when sent over the radio link. Used to keep compatibility
|
||||
@@ -32,6 +34,12 @@ typedef struct {
|
||||
|
||||
/** The channel hash - used as a hint for the decoder to limit which channels we consider */
|
||||
uint8_t channel;
|
||||
|
||||
// ***For future use*** Last byte of the NodeNum of the next-hop for this packet
|
||||
uint8_t next_hop;
|
||||
|
||||
// ***For future use*** Last byte of the NodeNum of the node that will relay/relayed this packet
|
||||
uint8_t relay_node;
|
||||
} PacketHeader;
|
||||
|
||||
/**
|
||||
@@ -173,6 +181,9 @@ class RadioInterface
|
||||
/// Some boards (1st gen Pinetab Lora module) have broken IRQ wires, so we need to poll via i2c registers
|
||||
virtual bool isIRQPending() { return false; }
|
||||
|
||||
// Whether we use the default frequency slot given our LoRa config (region and modem preset)
|
||||
static bool uses_default_frequency_slot;
|
||||
|
||||
protected:
|
||||
int8_t power = 17; // Set by applyModemConfig()
|
||||
|
||||
@@ -224,4 +235,4 @@ class RadioInterface
|
||||
};
|
||||
|
||||
/// Debug printing for packets
|
||||
void printPacket(const char *prefix, const meshtastic_MeshPacket *p);
|
||||
void printPacket(const char *prefix, const meshtastic_MeshPacket *p);
|
||||
@@ -359,8 +359,9 @@ void RadioLibInterface::handleReceiveInterrupt()
|
||||
mp->to = h->to;
|
||||
mp->id = h->id;
|
||||
mp->channel = h->channel;
|
||||
assert(HOP_MAX <= PACKET_FLAGS_HOP_MASK); // If hopmax changes, carefully check this code
|
||||
mp->hop_limit = h->flags & PACKET_FLAGS_HOP_MASK;
|
||||
assert(HOP_MAX <= PACKET_FLAGS_HOP_LIMIT_MASK); // If hopmax changes, carefully check this code
|
||||
mp->hop_limit = h->flags & PACKET_FLAGS_HOP_LIMIT_MASK;
|
||||
mp->hop_start = (h->flags & PACKET_FLAGS_HOP_START_MASK) >> PACKET_FLAGS_HOP_START_SHIFT;
|
||||
mp->want_ack = !!(h->flags & PACKET_FLAGS_WANT_ACK_MASK);
|
||||
mp->via_mqtt = !!(h->flags & PACKET_FLAGS_VIA_MQTT_MASK);
|
||||
|
||||
@@ -407,4 +408,4 @@ void RadioLibInterface::startSend(meshtastic_MeshPacket *txp)
|
||||
// bits
|
||||
enableInterrupt(isrTxLevel0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -71,12 +71,12 @@ bool ReliableRouter::shouldFilterReceived(const meshtastic_MeshPacket *p)
|
||||
i->second.nextTxMsec += iface->getPacketTime(p);
|
||||
}
|
||||
|
||||
/* Resend implicit ACKs for repeated packets (assuming the original packet was sent with HOP_RELIABLE)
|
||||
/* Resend implicit ACKs for repeated packets (hopStart equals hopLimit);
|
||||
* this way if an implicit ACK is dropped and a packet is resent we'll rebroadcast again.
|
||||
* Resending real ACKs is omitted, as you might receive a packet multiple times due to flooding and
|
||||
* flooding this ACK back to the original sender already adds redundancy. */
|
||||
if (wasSeenRecently(p, false) && p->hop_limit == HOP_RELIABLE && !MeshModule::currentReply && p->to != nodeDB.getNodeNum()) {
|
||||
// retransmission on broadcast has hop_limit still equal to HOP_RELIABLE
|
||||
bool isRepeated = p->hop_start == 0 ? (p->hop_limit == HOP_RELIABLE) : (p->hop_start == p->hop_limit);
|
||||
if (wasSeenRecently(p, false) && isRepeated && !MeshModule::currentReply && p->to != nodeDB->getNodeNum()) {
|
||||
LOG_DEBUG("Resending implicit ack for a repeated floodmsg\n");
|
||||
meshtastic_MeshPacket *tosend = packetPool.allocCopy(*p);
|
||||
tosend->hop_limit--; // bump down the hop count
|
||||
@@ -107,10 +107,11 @@ void ReliableRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas
|
||||
if (MeshModule::currentReply) {
|
||||
LOG_DEBUG("Some other module has replied to this message, no need for a 2nd ack\n");
|
||||
} else if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
|
||||
sendAckNak(meshtastic_Routing_Error_NONE, getFrom(p), p->id, p->channel);
|
||||
sendAckNak(meshtastic_Routing_Error_NONE, getFrom(p), p->id, p->channel, p->hop_start, p->hop_limit);
|
||||
} else {
|
||||
// Send a 'NO_CHANNEL' error on the primary channel if want_ack packet destined for us cannot be decoded
|
||||
sendAckNak(meshtastic_Routing_Error_NO_CHANNEL, getFrom(p), p->id, channels.getPrimaryIndex());
|
||||
sendAckNak(meshtastic_Routing_Error_NO_CHANNEL, getFrom(p), p->id, channels.getPrimaryIndex(), p->hop_start,
|
||||
p->hop_limit);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,8 +167,6 @@ bool ReliableRouter::stopRetransmission(GlobalPacketId key)
|
||||
auto old = findPendingPacket(key);
|
||||
if (old) {
|
||||
auto p = old->packet;
|
||||
auto numErased = pending.erase(key);
|
||||
assert(numErased == 1);
|
||||
/* Only when we already transmitted a packet via LoRa, we will cancel the packet in the Tx queue
|
||||
to avoid canceling a transmission if it was ACKed super fast via MQTT */
|
||||
if (old->numRetransmissions < NUM_RETRANSMISSIONS - 1) {
|
||||
@@ -176,6 +175,8 @@ bool ReliableRouter::stopRetransmission(GlobalPacketId key)
|
||||
// now free the pooled copy for retransmission too
|
||||
packetPool.release(p);
|
||||
}
|
||||
auto numErased = pending.erase(key);
|
||||
assert(numErased == 1);
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
@@ -255,4 +256,4 @@ void ReliableRouter::setNextTx(PendingPacket *pending)
|
||||
LOG_DEBUG("Setting next retransmission in %u msecs: ", d);
|
||||
printPacket("", pending->packet);
|
||||
setReceivedMessage(); // Run ASAP, so we can figure out our correct sleep time
|
||||
}
|
||||
}
|
||||
@@ -119,7 +119,7 @@ meshtastic_MeshPacket *Router::allocForSending()
|
||||
meshtastic_MeshPacket *p = packetPool.allocZeroed();
|
||||
|
||||
p->which_payload_variant = meshtastic_MeshPacket_decoded_tag; // Assume payload is decoded at start.
|
||||
p->from = nodeDB.getNodeNum();
|
||||
p->from = nodeDB->getNodeNum();
|
||||
p->to = NODENUM_BROADCAST;
|
||||
p->hop_limit = (config.lora.hop_limit >= HOP_MAX) ? HOP_MAX : config.lora.hop_limit;
|
||||
p->id = generatePacketId();
|
||||
@@ -132,9 +132,10 @@ meshtastic_MeshPacket *Router::allocForSending()
|
||||
/**
|
||||
* Send an ack or a nak packet back towards whoever sent idFrom
|
||||
*/
|
||||
void Router::sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex)
|
||||
void Router::sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex, uint8_t hopStart,
|
||||
uint8_t hopLimit)
|
||||
{
|
||||
routingModule->sendAckNak(err, to, idFrom, chIndex);
|
||||
routingModule->sendAckNak(err, to, idFrom, chIndex, hopStart, hopLimit);
|
||||
}
|
||||
|
||||
void Router::abortSendAndNak(meshtastic_Routing_Error err, meshtastic_MeshPacket *p)
|
||||
@@ -164,7 +165,7 @@ meshtastic_QueueStatus Router::getQueueStatus()
|
||||
ErrorCode Router::sendLocal(meshtastic_MeshPacket *p, RxSource src)
|
||||
{
|
||||
// No need to deliver externally if the destination is the local node
|
||||
if (p->to == nodeDB.getNodeNum()) {
|
||||
if (p->to == nodeDB->getNodeNum()) {
|
||||
printPacket("Enqueued local", p);
|
||||
enqueueReceivedMessage(p);
|
||||
return ERRNO_OK;
|
||||
@@ -181,7 +182,7 @@ ErrorCode Router::sendLocal(meshtastic_MeshPacket *p, RxSource src)
|
||||
}
|
||||
|
||||
if (!p->channel) { // don't override if a channel was requested
|
||||
p->channel = nodeDB.getMeshNodeChannel(p->to);
|
||||
p->channel = nodeDB->getMeshNodeChannel(p->to);
|
||||
LOG_DEBUG("localSend to channel %d\n", p->channel);
|
||||
}
|
||||
|
||||
@@ -204,7 +205,7 @@ void printBytes(const char *label, const uint8_t *p, size_t numbytes)
|
||||
*/
|
||||
ErrorCode Router::send(meshtastic_MeshPacket *p)
|
||||
{
|
||||
if (p->to == nodeDB.getNodeNum()) {
|
||||
if (p->to == nodeDB->getNodeNum()) {
|
||||
LOG_ERROR("BUG! send() called with packet destined for local node!\n");
|
||||
packetPool.release(p);
|
||||
return meshtastic_Routing_Error_BAD_REQUEST;
|
||||
@@ -219,7 +220,7 @@ ErrorCode Router::send(meshtastic_MeshPacket *p)
|
||||
LOG_WARN("Duty cycle limit exceeded. Aborting send for now, you can send again in %d minutes.\n", silentMinutes);
|
||||
#endif
|
||||
meshtastic_Routing_Error err = meshtastic_Routing_Error_DUTY_CYCLE_LIMIT;
|
||||
if (getFrom(p) == nodeDB.getNodeNum()) { // only send NAK to API, not to the mesh
|
||||
if (getFrom(p) == nodeDB->getNodeNum()) { // only send NAK to API, not to the mesh
|
||||
abortSendAndNak(err, p);
|
||||
} else {
|
||||
packetPool.release(p);
|
||||
@@ -240,6 +241,10 @@ ErrorCode Router::send(meshtastic_MeshPacket *p)
|
||||
// the lora we need to make sure we have replaced it with our local address
|
||||
p->from = getFrom(p);
|
||||
|
||||
// If we are the original transmitter, set the hop limit with which we start
|
||||
if (p->from == getNodeNum())
|
||||
p->hop_start = p->hop_limit;
|
||||
|
||||
// If the packet hasn't yet been encrypted, do so now (it might already be encrypted if we are just forwarding it)
|
||||
|
||||
assert(p->which_payload_variant == meshtastic_MeshPacket_encrypted_tag ||
|
||||
@@ -257,10 +262,9 @@ ErrorCode Router::send(meshtastic_MeshPacket *p)
|
||||
return encodeResult; // FIXME - this isn't a valid ErrorCode
|
||||
}
|
||||
|
||||
if (moduleConfig.mqtt.enabled) {
|
||||
LOG_INFO("Should encrypt MQTT?: %d\n", moduleConfig.mqtt.encryption_enabled);
|
||||
if (mqtt)
|
||||
mqtt->onSend(*p, *p_decoded, chIndex);
|
||||
// Only publish to MQTT if we're the original transmitter of the packet
|
||||
if (moduleConfig.mqtt.enabled && p->from == nodeDB->getNodeNum() && mqtt) {
|
||||
mqtt->onSend(*p, *p_decoded, chIndex);
|
||||
}
|
||||
packetPool.release(p_decoded);
|
||||
}
|
||||
@@ -293,8 +297,8 @@ bool perhapsDecode(meshtastic_MeshPacket *p)
|
||||
return false;
|
||||
|
||||
if (config.device.rebroadcast_mode == meshtastic_Config_DeviceConfig_RebroadcastMode_KNOWN_ONLY &&
|
||||
!nodeDB.getMeshNode(p->from)->has_user) {
|
||||
LOG_DEBUG("Node 0x%x not in NodeDB. Rebroadcast mode KNOWN_ONLY will ignore packet\n", p->from);
|
||||
(nodeDB->getMeshNode(p->from) == NULL || !nodeDB->getMeshNode(p->from)->has_user)) {
|
||||
LOG_DEBUG("Node 0x%x not in nodeDB-> Rebroadcast mode KNOWN_ONLY will ignore packet\n", p->from);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -427,7 +431,7 @@ meshtastic_Routing_Error perhapsEncode(meshtastic_MeshPacket *p)
|
||||
|
||||
NodeNum Router::getNodeNum()
|
||||
{
|
||||
return nodeDB.getNodeNum();
|
||||
return nodeDB->getNodeNum();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -436,8 +440,11 @@ NodeNum Router::getNodeNum()
|
||||
*/
|
||||
void Router::handleReceived(meshtastic_MeshPacket *p, RxSource src)
|
||||
{
|
||||
bool skipHandle = false;
|
||||
// Also, we should set the time from the ISR and it should have msec level resolution
|
||||
p->rx_time = getValidTime(RTCQualityFromNet); // store the arrival timestamp for the phone
|
||||
// Store a copy of encrypted packet for MQTT
|
||||
meshtastic_MeshPacket *p_encrypted = packetPool.allocCopy(*p);
|
||||
|
||||
// Take those raw bytes and convert them back into a well structured protobuf we can understand
|
||||
bool decoded = perhapsDecode(p);
|
||||
@@ -449,12 +456,28 @@ void Router::handleReceived(meshtastic_MeshPacket *p, RxSource src)
|
||||
printPacket("handleReceived(USER)", p);
|
||||
else
|
||||
printPacket("handleReceived(REMOTE)", p);
|
||||
|
||||
// Neighbor info module is disabled, ignore expensive neighbor info packets
|
||||
if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag &&
|
||||
p->decoded.portnum == meshtastic_PortNum_NEIGHBORINFO_APP &&
|
||||
(!moduleConfig.has_neighbor_info || !moduleConfig.neighbor_info.enabled)) {
|
||||
LOG_DEBUG("Neighbor info module is disabled, ignoring neighbor packet\n");
|
||||
cancelSending(p->from, p->id);
|
||||
skipHandle = true;
|
||||
}
|
||||
|
||||
// Publish received message to MQTT if we're not the original transmitter of the packet
|
||||
if (!skipHandle && moduleConfig.mqtt.enabled && getFrom(p) != nodeDB->getNodeNum() && mqtt)
|
||||
mqtt->onSend(*p_encrypted, *p, p->channel);
|
||||
} else {
|
||||
printPacket("packet decoding failed or skipped (no PSK?)", p);
|
||||
}
|
||||
|
||||
packetPool.release(p_encrypted); // Release the encrypted packet
|
||||
|
||||
// call modules here
|
||||
MeshModule::callPlugins(*p, src);
|
||||
if (!skipHandle)
|
||||
MeshModule::callPlugins(*p, src);
|
||||
}
|
||||
|
||||
void Router::perhapsHandleReceived(meshtastic_MeshPacket *p)
|
||||
@@ -474,4 +497,4 @@ void Router::perhapsHandleReceived(meshtastic_MeshPacket *p)
|
||||
handleReceived(p);
|
||||
|
||||
packetPool.release(p);
|
||||
}
|
||||
}
|
||||
@@ -104,7 +104,8 @@ class Router : protected concurrency::OSThread
|
||||
/**
|
||||
* Send an ack or a nak packet back towards whoever sent idFrom
|
||||
*/
|
||||
void sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex);
|
||||
void sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex, uint8_t hopStart = 0,
|
||||
uint8_t hopLimit = 0);
|
||||
|
||||
private:
|
||||
/**
|
||||
|
||||
@@ -17,7 +17,7 @@ SX126xInterface<T>::SX126xInterface(LockingArduinoHal *hal, RADIOLIB_PIN_TYPE cs
|
||||
RADIOLIB_PIN_TYPE busy)
|
||||
: RadioLibInterface(hal, cs, irq, rst, busy, &lora), lora(&module)
|
||||
{
|
||||
LOG_WARN("SX126xInterface(cs=%d, irq=%d, rst=%d, busy=%d)\n", cs, irq, rst, busy);
|
||||
LOG_DEBUG("SX126xInterface(cs=%d, irq=%d, rst=%d, busy=%d)\n", cs, irq, rst, busy);
|
||||
}
|
||||
|
||||
/// Initialise the Driver transport hardware and software.
|
||||
|
||||
@@ -17,7 +17,7 @@ SX128xInterface<T>::SX128xInterface(LockingArduinoHal *hal, RADIOLIB_PIN_TYPE cs
|
||||
RADIOLIB_PIN_TYPE busy)
|
||||
: RadioLibInterface(hal, cs, irq, rst, busy, &lora), lora(&module)
|
||||
{
|
||||
LOG_WARN("SX128xInterface(cs=%d, irq=%d, rst=%d, busy=%d)\n", cs, irq, rst, busy);
|
||||
LOG_DEBUG("SX128xInterface(cs=%d, irq=%d, rst=%d, busy=%d)\n", cs, irq, rst, busy);
|
||||
}
|
||||
|
||||
/// Initialise the Driver transport hardware and software.
|
||||
@@ -71,7 +71,7 @@ template <typename T> bool SX128xInterface<T>::init()
|
||||
if ((config.lora.region != meshtastic_Config_LoRaConfig_RegionCode_LORA_24) && (res == RADIOLIB_ERR_INVALID_FREQUENCY)) {
|
||||
LOG_WARN("Radio chip only supports 2.4GHz LoRa. Adjusting Region and rebooting.\n");
|
||||
config.lora.region = meshtastic_Config_LoRaConfig_RegionCode_LORA_24;
|
||||
nodeDB.saveToDisk(SEGMENT_CONFIG);
|
||||
nodeDB->saveToDisk(SEGMENT_CONFIG);
|
||||
delay(2000);
|
||||
#if defined(ARCH_ESP32)
|
||||
ESP.restart();
|
||||
@@ -251,9 +251,9 @@ template <typename T> void SX128xInterface<T>::startReceive()
|
||||
#endif
|
||||
|
||||
// We use the PREAMBLE_DETECTED and HEADER_VALID IRQ flag to detect whether we are actively receiving
|
||||
int err = lora.startReceive(RADIOLIB_SX128X_RX_TIMEOUT_INF, RADIOLIB_SX128X_IRQ_RX_DEFAULT |
|
||||
RADIOLIB_SX128X_IRQ_PREAMBLE_DETECTED |
|
||||
RADIOLIB_SX128X_IRQ_HEADER_VALID);
|
||||
int err =
|
||||
lora.startReceive(RADIOLIB_SX128X_RX_TIMEOUT_INF, RADIOLIB_SX128X_IRQ_RX_DEFAULT | RADIOLIB_SX128X_IRQ_PREAMBLE_DETECTED |
|
||||
RADIOLIB_SX128X_IRQ_HEADER_VALID);
|
||||
|
||||
assert(err == RADIOLIB_ERR_NONE);
|
||||
|
||||
@@ -327,4 +327,4 @@ template <typename T> bool SX128xInterface<T>::sleep()
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,9 @@ meshtastic_NodeInfo TypeConversions::ConvertToNodeInfo(const meshtastic_NodeInfo
|
||||
info.snr = lite->snr;
|
||||
info.last_heard = lite->last_heard;
|
||||
info.channel = lite->channel;
|
||||
info.via_mqtt = lite->via_mqtt;
|
||||
info.hops_away = lite->hops_away;
|
||||
info.is_favorite = lite->is_favorite;
|
||||
|
||||
if (lite->has_position) {
|
||||
info.has_position = true;
|
||||
|
||||
@@ -154,6 +154,10 @@ typedef struct _meshtastic_AdminMessage {
|
||||
char set_ringtone_message[231];
|
||||
/* Remove the node by the specified node-num from the NodeDB on the device */
|
||||
uint32_t remove_by_nodenum;
|
||||
/* Set specified node-num to be favorited on the NodeDB on the device */
|
||||
uint32_t set_favorite_node;
|
||||
/* Set specified node-num to be un-favorited on the NodeDB on the device */
|
||||
uint32_t remove_favorite_node;
|
||||
/* Begins an edit transaction for config, module config, owner, and channel settings changes
|
||||
This will delay the standard *implicit* save to the file system and subsequent reboot behavior until committed (commit_edit_settings) */
|
||||
bool begin_edit_settings;
|
||||
@@ -238,6 +242,8 @@ extern "C" {
|
||||
#define meshtastic_AdminMessage_set_canned_message_module_messages_tag 36
|
||||
#define meshtastic_AdminMessage_set_ringtone_message_tag 37
|
||||
#define meshtastic_AdminMessage_remove_by_nodenum_tag 38
|
||||
#define meshtastic_AdminMessage_set_favorite_node_tag 39
|
||||
#define meshtastic_AdminMessage_remove_favorite_node_tag 40
|
||||
#define meshtastic_AdminMessage_begin_edit_settings_tag 64
|
||||
#define meshtastic_AdminMessage_commit_edit_settings_tag 65
|
||||
#define meshtastic_AdminMessage_reboot_ota_seconds_tag 95
|
||||
@@ -277,6 +283,8 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,set_module_config,set_module
|
||||
X(a, STATIC, ONEOF, STRING, (payload_variant,set_canned_message_module_messages,set_canned_message_module_messages), 36) \
|
||||
X(a, STATIC, ONEOF, STRING, (payload_variant,set_ringtone_message,set_ringtone_message), 37) \
|
||||
X(a, STATIC, ONEOF, UINT32, (payload_variant,remove_by_nodenum,remove_by_nodenum), 38) \
|
||||
X(a, STATIC, ONEOF, UINT32, (payload_variant,set_favorite_node,set_favorite_node), 39) \
|
||||
X(a, STATIC, ONEOF, UINT32, (payload_variant,remove_favorite_node,remove_favorite_node), 40) \
|
||||
X(a, STATIC, ONEOF, BOOL, (payload_variant,begin_edit_settings,begin_edit_settings), 64) \
|
||||
X(a, STATIC, ONEOF, BOOL, (payload_variant,commit_edit_settings,commit_edit_settings), 65) \
|
||||
X(a, STATIC, ONEOF, INT32, (payload_variant,reboot_ota_seconds,reboot_ota_seconds), 95) \
|
||||
|
||||
@@ -54,7 +54,7 @@ extern const pb_msgdesc_t meshtastic_ChannelSet_msg;
|
||||
#define meshtastic_ChannelSet_fields &meshtastic_ChannelSet_msg
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define meshtastic_ChannelSet_size 594
|
||||
#define meshtastic_ChannelSet_size 658
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
||||
@@ -110,7 +110,7 @@ typedef struct _meshtastic_PLI {
|
||||
in floating point */
|
||||
int32_t longitude_i;
|
||||
/* Altitude (ATAK prefers HAE) */
|
||||
uint32_t altitude;
|
||||
int32_t altitude;
|
||||
/* Speed */
|
||||
uint32_t speed;
|
||||
/* Course in degrees */
|
||||
@@ -238,7 +238,7 @@ X(a, STATIC, SINGULAR, STRING, device_callsign, 2)
|
||||
#define meshtastic_PLI_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, SFIXED32, latitude_i, 1) \
|
||||
X(a, STATIC, SINGULAR, SFIXED32, longitude_i, 2) \
|
||||
X(a, STATIC, SINGULAR, UINT32, altitude, 3) \
|
||||
X(a, STATIC, SINGULAR, INT32, altitude, 3) \
|
||||
X(a, STATIC, SINGULAR, UINT32, speed, 4) \
|
||||
X(a, STATIC, SINGULAR, UINT32, course, 5)
|
||||
#define meshtastic_PLI_CALLBACK NULL
|
||||
@@ -263,7 +263,7 @@ extern const pb_msgdesc_t meshtastic_PLI_msg;
|
||||
#define meshtastic_Contact_size 242
|
||||
#define meshtastic_GeoChat_size 323
|
||||
#define meshtastic_Group_size 4
|
||||
#define meshtastic_PLI_size 26
|
||||
#define meshtastic_PLI_size 31
|
||||
#define meshtastic_Status_size 3
|
||||
#define meshtastic_TAKPacket_size 584
|
||||
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
PB_BIND(meshtastic_ChannelSettings, meshtastic_ChannelSettings, AUTO)
|
||||
|
||||
|
||||
PB_BIND(meshtastic_ModuleSettings, meshtastic_ModuleSettings, AUTO)
|
||||
|
||||
|
||||
PB_BIND(meshtastic_Channel, meshtastic_Channel, AUTO)
|
||||
|
||||
|
||||
@@ -30,6 +30,12 @@ typedef enum _meshtastic_Channel_Role {
|
||||
} meshtastic_Channel_Role;
|
||||
|
||||
/* Struct definitions */
|
||||
/* This message is specifically for modules to store per-channel configuration data. */
|
||||
typedef struct _meshtastic_ModuleSettings {
|
||||
/* Bits of precision for the location sent in position packets. */
|
||||
uint32_t position_precision;
|
||||
} meshtastic_ModuleSettings;
|
||||
|
||||
typedef PB_BYTES_ARRAY_T(32) meshtastic_ChannelSettings_psk_t;
|
||||
/* This information can be encoded as a QRcode/url so that other users can configure
|
||||
their radio to join the same channel.
|
||||
@@ -85,6 +91,9 @@ typedef struct _meshtastic_ChannelSettings {
|
||||
bool uplink_enabled;
|
||||
/* If true, messages seen on the internet will be forwarded to the local mesh. */
|
||||
bool downlink_enabled;
|
||||
/* Per-channel module settings. */
|
||||
bool has_module_settings;
|
||||
meshtastic_ModuleSettings module_settings;
|
||||
} meshtastic_ChannelSettings;
|
||||
|
||||
/* A pair of a channel number, mode and the (sharable) settings for that channel */
|
||||
@@ -111,22 +120,27 @@ extern "C" {
|
||||
#define _meshtastic_Channel_Role_ARRAYSIZE ((meshtastic_Channel_Role)(meshtastic_Channel_Role_SECONDARY+1))
|
||||
|
||||
|
||||
|
||||
#define meshtastic_Channel_role_ENUMTYPE meshtastic_Channel_Role
|
||||
|
||||
|
||||
/* Initializer values for message structs */
|
||||
#define meshtastic_ChannelSettings_init_default {0, {0, {0}}, "", 0, 0, 0}
|
||||
#define meshtastic_ChannelSettings_init_default {0, {0, {0}}, "", 0, 0, 0, false, meshtastic_ModuleSettings_init_default}
|
||||
#define meshtastic_ModuleSettings_init_default {0}
|
||||
#define meshtastic_Channel_init_default {0, false, meshtastic_ChannelSettings_init_default, _meshtastic_Channel_Role_MIN}
|
||||
#define meshtastic_ChannelSettings_init_zero {0, {0, {0}}, "", 0, 0, 0}
|
||||
#define meshtastic_ChannelSettings_init_zero {0, {0, {0}}, "", 0, 0, 0, false, meshtastic_ModuleSettings_init_zero}
|
||||
#define meshtastic_ModuleSettings_init_zero {0}
|
||||
#define meshtastic_Channel_init_zero {0, false, meshtastic_ChannelSettings_init_zero, _meshtastic_Channel_Role_MIN}
|
||||
|
||||
/* Field tags (for use in manual encoding/decoding) */
|
||||
#define meshtastic_ModuleSettings_position_precision_tag 1
|
||||
#define meshtastic_ChannelSettings_channel_num_tag 1
|
||||
#define meshtastic_ChannelSettings_psk_tag 2
|
||||
#define meshtastic_ChannelSettings_name_tag 3
|
||||
#define meshtastic_ChannelSettings_id_tag 4
|
||||
#define meshtastic_ChannelSettings_uplink_enabled_tag 5
|
||||
#define meshtastic_ChannelSettings_downlink_enabled_tag 6
|
||||
#define meshtastic_ChannelSettings_module_settings_tag 7
|
||||
#define meshtastic_Channel_index_tag 1
|
||||
#define meshtastic_Channel_settings_tag 2
|
||||
#define meshtastic_Channel_role_tag 3
|
||||
@@ -138,9 +152,16 @@ X(a, STATIC, SINGULAR, BYTES, psk, 2) \
|
||||
X(a, STATIC, SINGULAR, STRING, name, 3) \
|
||||
X(a, STATIC, SINGULAR, FIXED32, id, 4) \
|
||||
X(a, STATIC, SINGULAR, BOOL, uplink_enabled, 5) \
|
||||
X(a, STATIC, SINGULAR, BOOL, downlink_enabled, 6)
|
||||
X(a, STATIC, SINGULAR, BOOL, downlink_enabled, 6) \
|
||||
X(a, STATIC, OPTIONAL, MESSAGE, module_settings, 7)
|
||||
#define meshtastic_ChannelSettings_CALLBACK NULL
|
||||
#define meshtastic_ChannelSettings_DEFAULT NULL
|
||||
#define meshtastic_ChannelSettings_module_settings_MSGTYPE meshtastic_ModuleSettings
|
||||
|
||||
#define meshtastic_ModuleSettings_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, UINT32, position_precision, 1)
|
||||
#define meshtastic_ModuleSettings_CALLBACK NULL
|
||||
#define meshtastic_ModuleSettings_DEFAULT NULL
|
||||
|
||||
#define meshtastic_Channel_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, INT32, index, 1) \
|
||||
@@ -151,15 +172,18 @@ X(a, STATIC, SINGULAR, UENUM, role, 3)
|
||||
#define meshtastic_Channel_settings_MSGTYPE meshtastic_ChannelSettings
|
||||
|
||||
extern const pb_msgdesc_t meshtastic_ChannelSettings_msg;
|
||||
extern const pb_msgdesc_t meshtastic_ModuleSettings_msg;
|
||||
extern const pb_msgdesc_t meshtastic_Channel_msg;
|
||||
|
||||
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
|
||||
#define meshtastic_ChannelSettings_fields &meshtastic_ChannelSettings_msg
|
||||
#define meshtastic_ModuleSettings_fields &meshtastic_ModuleSettings_msg
|
||||
#define meshtastic_Channel_fields &meshtastic_Channel_msg
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define meshtastic_ChannelSettings_size 62
|
||||
#define meshtastic_Channel_size 77
|
||||
#define meshtastic_ChannelSettings_size 70
|
||||
#define meshtastic_Channel_size 85
|
||||
#define meshtastic_ModuleSettings_size 6
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
||||
@@ -317,9 +317,6 @@ typedef struct _meshtastic_Config_PositionConfig {
|
||||
uint32_t gps_en_gpio;
|
||||
/* Set where GPS is enabled, disabled, or not present */
|
||||
meshtastic_Config_PositionConfig_GpsMode gps_mode;
|
||||
/* Set GPS precision in bits per channel, or 0 for disabled */
|
||||
pb_size_t channel_precision_count;
|
||||
uint32_t channel_precision[8];
|
||||
} meshtastic_Config_PositionConfig;
|
||||
|
||||
/* Power Config\
|
||||
@@ -587,7 +584,7 @@ extern "C" {
|
||||
/* Initializer values for message structs */
|
||||
#define meshtastic_Config_init_default {0, {meshtastic_Config_DeviceConfig_init_default}}
|
||||
#define meshtastic_Config_DeviceConfig_init_default {_meshtastic_Config_DeviceConfig_Role_MIN, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN, 0, 0, 0, 0}
|
||||
#define meshtastic_Config_PositionConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _meshtastic_Config_PositionConfig_GpsMode_MIN, 0, {0, 0, 0, 0, 0, 0, 0, 0}}
|
||||
#define meshtastic_Config_PositionConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _meshtastic_Config_PositionConfig_GpsMode_MIN}
|
||||
#define meshtastic_Config_PowerConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define meshtastic_Config_NetworkConfig_init_default {0, "", "", "", 0, _meshtastic_Config_NetworkConfig_AddressMode_MIN, false, meshtastic_Config_NetworkConfig_IpV4Config_init_default, ""}
|
||||
#define meshtastic_Config_NetworkConfig_IpV4Config_init_default {0, 0, 0, 0}
|
||||
@@ -596,7 +593,7 @@ extern "C" {
|
||||
#define meshtastic_Config_BluetoothConfig_init_default {0, _meshtastic_Config_BluetoothConfig_PairingMode_MIN, 0}
|
||||
#define meshtastic_Config_init_zero {0, {meshtastic_Config_DeviceConfig_init_zero}}
|
||||
#define meshtastic_Config_DeviceConfig_init_zero {_meshtastic_Config_DeviceConfig_Role_MIN, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN, 0, 0, 0, 0}
|
||||
#define meshtastic_Config_PositionConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _meshtastic_Config_PositionConfig_GpsMode_MIN, 0, {0, 0, 0, 0, 0, 0, 0, 0}}
|
||||
#define meshtastic_Config_PositionConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _meshtastic_Config_PositionConfig_GpsMode_MIN}
|
||||
#define meshtastic_Config_PowerConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define meshtastic_Config_NetworkConfig_init_zero {0, "", "", "", 0, _meshtastic_Config_NetworkConfig_AddressMode_MIN, false, meshtastic_Config_NetworkConfig_IpV4Config_init_zero, ""}
|
||||
#define meshtastic_Config_NetworkConfig_IpV4Config_init_zero {0, 0, 0, 0}
|
||||
@@ -628,7 +625,6 @@ extern "C" {
|
||||
#define meshtastic_Config_PositionConfig_broadcast_smart_minimum_interval_secs_tag 11
|
||||
#define meshtastic_Config_PositionConfig_gps_en_gpio_tag 12
|
||||
#define meshtastic_Config_PositionConfig_gps_mode_tag 13
|
||||
#define meshtastic_Config_PositionConfig_channel_precision_tag 14
|
||||
#define meshtastic_Config_PowerConfig_is_power_saving_tag 1
|
||||
#define meshtastic_Config_PowerConfig_on_battery_shutdown_after_secs_tag 2
|
||||
#define meshtastic_Config_PowerConfig_adc_multiplier_override_tag 3
|
||||
@@ -732,8 +728,7 @@ X(a, STATIC, SINGULAR, UINT32, tx_gpio, 9) \
|
||||
X(a, STATIC, SINGULAR, UINT32, broadcast_smart_minimum_distance, 10) \
|
||||
X(a, STATIC, SINGULAR, UINT32, broadcast_smart_minimum_interval_secs, 11) \
|
||||
X(a, STATIC, SINGULAR, UINT32, gps_en_gpio, 12) \
|
||||
X(a, STATIC, SINGULAR, UENUM, gps_mode, 13) \
|
||||
X(a, STATIC, REPEATED, UINT32, channel_precision, 14)
|
||||
X(a, STATIC, SINGULAR, UENUM, gps_mode, 13)
|
||||
#define meshtastic_Config_PositionConfig_CALLBACK NULL
|
||||
#define meshtastic_Config_PositionConfig_DEFAULT NULL
|
||||
|
||||
@@ -839,7 +834,7 @@ extern const pb_msgdesc_t meshtastic_Config_BluetoothConfig_msg;
|
||||
#define meshtastic_Config_LoRaConfig_size 80
|
||||
#define meshtastic_Config_NetworkConfig_IpV4Config_size 20
|
||||
#define meshtastic_Config_NetworkConfig_size 196
|
||||
#define meshtastic_Config_PositionConfig_size 110
|
||||
#define meshtastic_Config_PositionConfig_size 62
|
||||
#define meshtastic_Config_PowerConfig_size 40
|
||||
#define meshtastic_Config_size 199
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#error Regenerate this file with the current version of nanopb generator.
|
||||
#endif
|
||||
|
||||
PB_BIND(meshtastic_DeviceState, meshtastic_DeviceState, 4)
|
||||
PB_BIND(meshtastic_DeviceState, meshtastic_DeviceState, 2)
|
||||
|
||||
|
||||
PB_BIND(meshtastic_NodeInfoLite, meshtastic_NodeInfoLite, AUTO)
|
||||
@@ -4,6 +4,7 @@
|
||||
#ifndef PB_MESHTASTIC_MESHTASTIC_DEVICEONLY_PB_H_INCLUDED
|
||||
#define PB_MESHTASTIC_MESHTASTIC_DEVICEONLY_PB_H_INCLUDED
|
||||
#include <pb.h>
|
||||
#include <vector>
|
||||
#include "meshtastic/channel.pb.h"
|
||||
#include "meshtastic/localonly.pb.h"
|
||||
#include "meshtastic/mesh.pb.h"
|
||||
@@ -65,6 +66,13 @@ typedef struct _meshtastic_NodeInfoLite {
|
||||
meshtastic_DeviceMetrics device_metrics;
|
||||
/* local channel index we heard that node on. Only populated if its not the default channel. */
|
||||
uint8_t channel;
|
||||
/* True if we witnessed the node over MQTT instead of LoRA transport */
|
||||
bool via_mqtt;
|
||||
/* Number of hops away from us this node is (0 if adjacent) */
|
||||
uint8_t hops_away;
|
||||
/* True if node is in our favorites list
|
||||
Persists between NodeDB internal clean ups */
|
||||
bool is_favorite;
|
||||
} meshtastic_NodeInfoLite;
|
||||
|
||||
/* The on-disk saved channels */
|
||||
@@ -137,7 +145,8 @@ typedef struct _meshtastic_DeviceState {
|
||||
NodeDB.cpp in the device code. */
|
||||
uint32_t version;
|
||||
/* Used only during development.
|
||||
Indicates developer is testing and changes should never be saved to flash. */
|
||||
Indicates developer is testing and changes should never be saved to flash.
|
||||
Deprecated in 2.3.1 */
|
||||
bool no_save;
|
||||
/* Some GPS receivers seem to have bogus settings from the factory, so we always do one factory reset. */
|
||||
bool did_gps_reset;
|
||||
@@ -150,8 +159,7 @@ typedef struct _meshtastic_DeviceState {
|
||||
pb_size_t node_remote_hardware_pins_count;
|
||||
meshtastic_NodeRemoteHardwarePin node_remote_hardware_pins[12];
|
||||
/* New lite version of NodeDB to decrease memory footprint */
|
||||
pb_size_t node_db_lite_count;
|
||||
meshtastic_NodeInfoLite node_db_lite[100];
|
||||
std::vector<meshtastic_NodeInfoLite> node_db_lite;
|
||||
} meshtastic_DeviceState;
|
||||
|
||||
|
||||
@@ -174,14 +182,14 @@ extern "C" {
|
||||
|
||||
|
||||
/* Initializer values for message structs */
|
||||
#define meshtastic_DeviceState_init_default {false, meshtastic_MyNodeInfo_init_default, false, meshtastic_User_init_default, 0, {meshtastic_MeshPacket_init_default}, false, meshtastic_MeshPacket_init_default, 0, 0, 0, false, meshtastic_MeshPacket_init_default, 0, {meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default}, 0, {meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default}}
|
||||
#define meshtastic_NodeInfoLite_init_default {0, false, meshtastic_User_init_default, false, meshtastic_PositionLite_init_default, 0, 0, false, meshtastic_DeviceMetrics_init_default, 0}
|
||||
#define meshtastic_DeviceState_init_default {false, meshtastic_MyNodeInfo_init_default, false, meshtastic_User_init_default, 0, {meshtastic_MeshPacket_init_default}, false, meshtastic_MeshPacket_init_default, 0, 0, 0, false, meshtastic_MeshPacket_init_default, 0, {meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default}, {{NULL}, NULL}}
|
||||
#define meshtastic_NodeInfoLite_init_default {0, false, meshtastic_User_init_default, false, meshtastic_PositionLite_init_default, 0, 0, false, meshtastic_DeviceMetrics_init_default, 0, 0, 0, 0}
|
||||
#define meshtastic_PositionLite_init_default {0, 0, 0, 0, _meshtastic_Position_LocSource_MIN}
|
||||
#define meshtastic_ChannelFile_init_default {0, {meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default}, 0}
|
||||
#define meshtastic_OEMStore_init_default {0, 0, {0, {0}}, _meshtastic_ScreenFonts_MIN, "", {0, {0}}, false, meshtastic_LocalConfig_init_default, false, meshtastic_LocalModuleConfig_init_default}
|
||||
#define meshtastic_NodeRemoteHardwarePin_init_default {0, false, meshtastic_RemoteHardwarePin_init_default}
|
||||
#define meshtastic_DeviceState_init_zero {false, meshtastic_MyNodeInfo_init_zero, false, meshtastic_User_init_zero, 0, {meshtastic_MeshPacket_init_zero}, false, meshtastic_MeshPacket_init_zero, 0, 0, 0, false, meshtastic_MeshPacket_init_zero, 0, {meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero}, 0, {meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero}}
|
||||
#define meshtastic_NodeInfoLite_init_zero {0, false, meshtastic_User_init_zero, false, meshtastic_PositionLite_init_zero, 0, 0, false, meshtastic_DeviceMetrics_init_zero, 0}
|
||||
#define meshtastic_DeviceState_init_zero {false, meshtastic_MyNodeInfo_init_zero, false, meshtastic_User_init_zero, 0, {meshtastic_MeshPacket_init_zero}, false, meshtastic_MeshPacket_init_zero, 0, 0, 0, false, meshtastic_MeshPacket_init_zero, 0, {meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero}, {{NULL}, NULL}}
|
||||
#define meshtastic_NodeInfoLite_init_zero {0, false, meshtastic_User_init_zero, false, meshtastic_PositionLite_init_zero, 0, 0, false, meshtastic_DeviceMetrics_init_zero, 0, 0, 0, 0}
|
||||
#define meshtastic_PositionLite_init_zero {0, 0, 0, 0, _meshtastic_Position_LocSource_MIN}
|
||||
#define meshtastic_ChannelFile_init_zero {0, {meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero}, 0}
|
||||
#define meshtastic_OEMStore_init_zero {0, 0, {0, {0}}, _meshtastic_ScreenFonts_MIN, "", {0, {0}}, false, meshtastic_LocalConfig_init_zero, false, meshtastic_LocalModuleConfig_init_zero}
|
||||
@@ -200,6 +208,9 @@ extern "C" {
|
||||
#define meshtastic_NodeInfoLite_last_heard_tag 5
|
||||
#define meshtastic_NodeInfoLite_device_metrics_tag 6
|
||||
#define meshtastic_NodeInfoLite_channel_tag 7
|
||||
#define meshtastic_NodeInfoLite_via_mqtt_tag 8
|
||||
#define meshtastic_NodeInfoLite_hops_away_tag 9
|
||||
#define meshtastic_NodeInfoLite_is_favorite_tag 10
|
||||
#define meshtastic_ChannelFile_channels_tag 1
|
||||
#define meshtastic_ChannelFile_version_tag 2
|
||||
#define meshtastic_OEMStore_oem_icon_width_tag 1
|
||||
@@ -234,8 +245,9 @@ X(a, STATIC, SINGULAR, BOOL, no_save, 9) \
|
||||
X(a, STATIC, SINGULAR, BOOL, did_gps_reset, 11) \
|
||||
X(a, STATIC, OPTIONAL, MESSAGE, rx_waypoint, 12) \
|
||||
X(a, STATIC, REPEATED, MESSAGE, node_remote_hardware_pins, 13) \
|
||||
X(a, STATIC, REPEATED, MESSAGE, node_db_lite, 14)
|
||||
#define meshtastic_DeviceState_CALLBACK NULL
|
||||
X(a, CALLBACK, REPEATED, MESSAGE, node_db_lite, 14)
|
||||
extern bool meshtastic_DeviceState_callback(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_t *field);
|
||||
#define meshtastic_DeviceState_CALLBACK meshtastic_DeviceState_callback
|
||||
#define meshtastic_DeviceState_DEFAULT NULL
|
||||
#define meshtastic_DeviceState_my_node_MSGTYPE meshtastic_MyNodeInfo
|
||||
#define meshtastic_DeviceState_owner_MSGTYPE meshtastic_User
|
||||
@@ -252,7 +264,10 @@ X(a, STATIC, OPTIONAL, MESSAGE, position, 3) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, snr, 4) \
|
||||
X(a, STATIC, SINGULAR, FIXED32, last_heard, 5) \
|
||||
X(a, STATIC, OPTIONAL, MESSAGE, device_metrics, 6) \
|
||||
X(a, STATIC, SINGULAR, UINT32, channel, 7)
|
||||
X(a, STATIC, SINGULAR, UINT32, channel, 7) \
|
||||
X(a, STATIC, SINGULAR, BOOL, via_mqtt, 8) \
|
||||
X(a, STATIC, SINGULAR, UINT32, hops_away, 9) \
|
||||
X(a, STATIC, SINGULAR, BOOL, is_favorite, 10)
|
||||
#define meshtastic_NodeInfoLite_CALLBACK NULL
|
||||
#define meshtastic_NodeInfoLite_DEFAULT NULL
|
||||
#define meshtastic_NodeInfoLite_user_MSGTYPE meshtastic_User
|
||||
@@ -312,11 +327,11 @@ extern const pb_msgdesc_t meshtastic_NodeRemoteHardwarePin_msg;
|
||||
#define meshtastic_NodeRemoteHardwarePin_fields &meshtastic_NodeRemoteHardwarePin_msg
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define meshtastic_ChannelFile_size 638
|
||||
#define meshtastic_DeviceState_size 17062
|
||||
#define meshtastic_NodeInfoLite_size 153
|
||||
/* meshtastic_DeviceState_size depends on runtime parameters */
|
||||
#define meshtastic_ChannelFile_size 702
|
||||
#define meshtastic_NodeInfoLite_size 160
|
||||
#define meshtastic_NodeRemoteHardwarePin_size 29
|
||||
#define meshtastic_OEMStore_size 3294
|
||||
#define meshtastic_OEMStore_size 3278
|
||||
#define meshtastic_PositionLite_size 28
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -180,8 +180,8 @@ extern const pb_msgdesc_t meshtastic_LocalModuleConfig_msg;
|
||||
#define meshtastic_LocalModuleConfig_fields &meshtastic_LocalModuleConfig_msg
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define meshtastic_LocalConfig_size 517
|
||||
#define meshtastic_LocalModuleConfig_size 631
|
||||
#define meshtastic_LocalConfig_size 469
|
||||
#define meshtastic_LocalModuleConfig_size 663
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
||||
@@ -60,6 +60,9 @@ PB_BIND(meshtastic_Neighbor, meshtastic_Neighbor, AUTO)
|
||||
PB_BIND(meshtastic_DeviceMetadata, meshtastic_DeviceMetadata, AUTO)
|
||||
|
||||
|
||||
PB_BIND(meshtastic_Heartbeat, meshtastic_Heartbeat, AUTO)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -75,6 +75,8 @@ typedef enum _meshtastic_HardwareModel {
|
||||
meshtastic_HardwareModel_CANARYONE = 29,
|
||||
/* Waveshare RP2040 LoRa - https://www.waveshare.com/rp2040-lora.htm */
|
||||
meshtastic_HardwareModel_RP2040_LORA = 30,
|
||||
/* B&Q Consulting Station G2: https://wiki.uniteng.com/en/meshtastic/station-g2 */
|
||||
meshtastic_HardwareModel_STATION_G2 = 31,
|
||||
/* ---------------------------------------------------------------------------
|
||||
Less common/prototype boards listed here (needs one more byte over the air)
|
||||
--------------------------------------------------------------------------- */
|
||||
@@ -380,6 +382,8 @@ typedef struct _meshtastic_Position {
|
||||
/* A sequence number, incremented with each Position message to help
|
||||
detect lost updates if needed */
|
||||
uint32_t seq_number;
|
||||
/* Indicates the bits of precision set by the sending node */
|
||||
uint32_t precision_bits;
|
||||
} meshtastic_Position;
|
||||
|
||||
/* Broadcast when a newly powered mesh node wants to find a node num it can use
|
||||
@@ -528,11 +532,9 @@ typedef PB_BYTES_ARRAY_T(256) meshtastic_MeshPacket_encrypted_t;
|
||||
typedef struct _meshtastic_MeshPacket {
|
||||
/* The sending node number.
|
||||
Note: Our crypto implementation uses this field as well.
|
||||
See [crypto](/docs/overview/encryption) for details.
|
||||
FIXME - really should be fixed32 instead, this encoding only hurts the ble link though. */
|
||||
See [crypto](/docs/overview/encryption) for details. */
|
||||
uint32_t from;
|
||||
/* The (immediatSee Priority description for more details.y should be fixed32 instead, this encoding only
|
||||
hurts the ble link though. */
|
||||
/* The (immediate) destination for this packet */
|
||||
uint32_t to;
|
||||
/* (Usually) If set, this indicates the index in the secondary_channels table that this packet was sent/received on.
|
||||
If unset, packet was on the primary channel.
|
||||
@@ -556,9 +558,7 @@ typedef struct _meshtastic_MeshPacket {
|
||||
needs to be unique for a few minutes (long enough to last for the length of
|
||||
any ACK or the completion of a mesh broadcast flood).
|
||||
Note: Our crypto implementation uses this id as well.
|
||||
See [crypto](/docs/overview/encryption) for details.
|
||||
FIXME - really should be fixed32 instead, this encoding only
|
||||
hurts the ble link though. */
|
||||
See [crypto](/docs/overview/encryption) for details. */
|
||||
uint32_t id;
|
||||
/* The time this message was received by the esp32 (secs since 1970).
|
||||
Note: this field is _never_ sent on the radio link itself (to save space) Times
|
||||
@@ -593,6 +593,9 @@ typedef struct _meshtastic_MeshPacket {
|
||||
meshtastic_MeshPacket_Delayed delayed;
|
||||
/* Describes whether this packet passed via MQTT somewhere along the path it currently took. */
|
||||
bool via_mqtt;
|
||||
/* Hop limit with which the original packet started. Sent via LoRa using three bits in the unencrypted header.
|
||||
When receiving a packet, the difference between hop_start and hop_limit gives how many hops it traveled. */
|
||||
uint8_t hop_start;
|
||||
} meshtastic_MeshPacket;
|
||||
|
||||
/* The bluetooth to device link:
|
||||
@@ -631,6 +634,13 @@ typedef struct _meshtastic_NodeInfo {
|
||||
meshtastic_DeviceMetrics device_metrics;
|
||||
/* local channel index we heard that node on. Only populated if its not the default channel. */
|
||||
uint8_t channel;
|
||||
/* True if we witnessed the node over MQTT instead of LoRA transport */
|
||||
bool via_mqtt;
|
||||
/* Number of hops away from us this node is (0 if adjacent) */
|
||||
uint8_t hops_away;
|
||||
/* True if node is in our favorites list
|
||||
Persists between NodeDB internal clean ups */
|
||||
bool is_favorite;
|
||||
} meshtastic_NodeInfo;
|
||||
|
||||
/* Unique local debugging info for this node
|
||||
@@ -675,32 +685,6 @@ typedef struct _meshtastic_QueueStatus {
|
||||
uint32_t mesh_packet_id;
|
||||
} meshtastic_QueueStatus;
|
||||
|
||||
/* Packets/commands to the radio will be written (reliably) to the toRadio characteristic.
|
||||
Once the write completes the phone can assume it is handled. */
|
||||
typedef struct _meshtastic_ToRadio {
|
||||
pb_size_t which_payload_variant;
|
||||
union {
|
||||
/* Send this packet on the mesh */
|
||||
meshtastic_MeshPacket packet;
|
||||
/* Phone wants radio to send full node db to the phone, This is
|
||||
typically the first packet sent to the radio when the phone gets a
|
||||
bluetooth connection. The radio will respond by sending back a
|
||||
MyNodeInfo, a owner, a radio config and a series of
|
||||
FromRadio.node_infos, and config_complete
|
||||
the integer you write into this field will be reported back in the
|
||||
config_complete_id response this allows clients to never be confused by
|
||||
a stale old partially sent config. */
|
||||
uint32_t want_config_id;
|
||||
/* Tell API server we are disconnecting now.
|
||||
This is useful for serial links where there is no hardware/protocol based notification that the client has dropped the link.
|
||||
(Sending this message is optional for clients) */
|
||||
bool disconnect;
|
||||
meshtastic_XModem xmodemPacket;
|
||||
/* MQTT Client Proxy Message (for client / phone subscribed to MQTT sending to device) */
|
||||
meshtastic_MqttClientProxyMessage mqttClientProxyMessage;
|
||||
};
|
||||
} meshtastic_ToRadio;
|
||||
|
||||
typedef PB_BYTES_ARRAY_T(237) meshtastic_Compressed_data_t;
|
||||
/* Compressed message payload */
|
||||
typedef struct _meshtastic_Compressed {
|
||||
@@ -808,6 +792,40 @@ typedef struct _meshtastic_FromRadio {
|
||||
};
|
||||
} meshtastic_FromRadio;
|
||||
|
||||
/* A heartbeat message is sent to the node from the client to keep the connection alive.
|
||||
This is currently only needed to keep serial connections alive, but can be used by any PhoneAPI. */
|
||||
typedef struct _meshtastic_Heartbeat {
|
||||
char dummy_field;
|
||||
} meshtastic_Heartbeat;
|
||||
|
||||
/* Packets/commands to the radio will be written (reliably) to the toRadio characteristic.
|
||||
Once the write completes the phone can assume it is handled. */
|
||||
typedef struct _meshtastic_ToRadio {
|
||||
pb_size_t which_payload_variant;
|
||||
union {
|
||||
/* Send this packet on the mesh */
|
||||
meshtastic_MeshPacket packet;
|
||||
/* Phone wants radio to send full node db to the phone, This is
|
||||
typically the first packet sent to the radio when the phone gets a
|
||||
bluetooth connection. The radio will respond by sending back a
|
||||
MyNodeInfo, a owner, a radio config and a series of
|
||||
FromRadio.node_infos, and config_complete
|
||||
the integer you write into this field will be reported back in the
|
||||
config_complete_id response this allows clients to never be confused by
|
||||
a stale old partially sent config. */
|
||||
uint32_t want_config_id;
|
||||
/* Tell API server we are disconnecting now.
|
||||
This is useful for serial links where there is no hardware/protocol based notification that the client has dropped the link.
|
||||
(Sending this message is optional for clients) */
|
||||
bool disconnect;
|
||||
meshtastic_XModem xmodemPacket;
|
||||
/* MQTT Client Proxy Message (for client / phone subscribed to MQTT sending to device) */
|
||||
meshtastic_MqttClientProxyMessage mqttClientProxyMessage;
|
||||
/* Heartbeat message (used to keep the device connection awake on serial) */
|
||||
meshtastic_Heartbeat heartbeat;
|
||||
};
|
||||
} meshtastic_ToRadio;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -881,16 +899,17 @@ extern "C" {
|
||||
#define meshtastic_DeviceMetadata_hw_model_ENUMTYPE meshtastic_HardwareModel
|
||||
|
||||
|
||||
|
||||
/* Initializer values for message structs */
|
||||
#define meshtastic_Position_init_default {0, 0, 0, 0, _meshtastic_Position_LocSource_MIN, _meshtastic_Position_AltSource_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define meshtastic_Position_init_default {0, 0, 0, 0, _meshtastic_Position_LocSource_MIN, _meshtastic_Position_AltSource_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define meshtastic_User_init_default {"", "", "", {0}, _meshtastic_HardwareModel_MIN, 0, _meshtastic_Config_DeviceConfig_Role_MIN}
|
||||
#define meshtastic_RouteDiscovery_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}}
|
||||
#define meshtastic_Routing_init_default {0, {meshtastic_RouteDiscovery_init_default}}
|
||||
#define meshtastic_Data_init_default {_meshtastic_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0}
|
||||
#define meshtastic_Waypoint_init_default {0, 0, 0, 0, 0, "", "", 0}
|
||||
#define meshtastic_MqttClientProxyMessage_init_default {"", 0, {{0, {0}}}, 0}
|
||||
#define meshtastic_MeshPacket_init_default {0, 0, 0, 0, {meshtastic_Data_init_default}, 0, 0, 0, 0, 0, _meshtastic_MeshPacket_Priority_MIN, 0, _meshtastic_MeshPacket_Delayed_MIN, 0}
|
||||
#define meshtastic_NodeInfo_init_default {0, false, meshtastic_User_init_default, false, meshtastic_Position_init_default, 0, 0, false, meshtastic_DeviceMetrics_init_default, 0}
|
||||
#define meshtastic_MeshPacket_init_default {0, 0, 0, 0, {meshtastic_Data_init_default}, 0, 0, 0, 0, 0, _meshtastic_MeshPacket_Priority_MIN, 0, _meshtastic_MeshPacket_Delayed_MIN, 0, 0}
|
||||
#define meshtastic_NodeInfo_init_default {0, false, meshtastic_User_init_default, false, meshtastic_Position_init_default, 0, 0, false, meshtastic_DeviceMetrics_init_default, 0, 0, 0, 0}
|
||||
#define meshtastic_MyNodeInfo_init_default {0, 0, 0}
|
||||
#define meshtastic_LogRecord_init_default {"", 0, "", _meshtastic_LogRecord_Level_MIN}
|
||||
#define meshtastic_QueueStatus_init_default {0, 0, 0, 0}
|
||||
@@ -900,15 +919,16 @@ extern "C" {
|
||||
#define meshtastic_NeighborInfo_init_default {0, 0, 0, 0, {meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default}}
|
||||
#define meshtastic_Neighbor_init_default {0, 0, 0, 0}
|
||||
#define meshtastic_DeviceMetadata_init_default {"", 0, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_Role_MIN, 0, _meshtastic_HardwareModel_MIN, 0}
|
||||
#define meshtastic_Position_init_zero {0, 0, 0, 0, _meshtastic_Position_LocSource_MIN, _meshtastic_Position_AltSource_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define meshtastic_Heartbeat_init_default {0}
|
||||
#define meshtastic_Position_init_zero {0, 0, 0, 0, _meshtastic_Position_LocSource_MIN, _meshtastic_Position_AltSource_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define meshtastic_User_init_zero {"", "", "", {0}, _meshtastic_HardwareModel_MIN, 0, _meshtastic_Config_DeviceConfig_Role_MIN}
|
||||
#define meshtastic_RouteDiscovery_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}}
|
||||
#define meshtastic_Routing_init_zero {0, {meshtastic_RouteDiscovery_init_zero}}
|
||||
#define meshtastic_Data_init_zero {_meshtastic_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0}
|
||||
#define meshtastic_Waypoint_init_zero {0, 0, 0, 0, 0, "", "", 0}
|
||||
#define meshtastic_MqttClientProxyMessage_init_zero {"", 0, {{0, {0}}}, 0}
|
||||
#define meshtastic_MeshPacket_init_zero {0, 0, 0, 0, {meshtastic_Data_init_zero}, 0, 0, 0, 0, 0, _meshtastic_MeshPacket_Priority_MIN, 0, _meshtastic_MeshPacket_Delayed_MIN, 0}
|
||||
#define meshtastic_NodeInfo_init_zero {0, false, meshtastic_User_init_zero, false, meshtastic_Position_init_zero, 0, 0, false, meshtastic_DeviceMetrics_init_zero, 0}
|
||||
#define meshtastic_MeshPacket_init_zero {0, 0, 0, 0, {meshtastic_Data_init_zero}, 0, 0, 0, 0, 0, _meshtastic_MeshPacket_Priority_MIN, 0, _meshtastic_MeshPacket_Delayed_MIN, 0, 0}
|
||||
#define meshtastic_NodeInfo_init_zero {0, false, meshtastic_User_init_zero, false, meshtastic_Position_init_zero, 0, 0, false, meshtastic_DeviceMetrics_init_zero, 0, 0, 0, 0}
|
||||
#define meshtastic_MyNodeInfo_init_zero {0, 0, 0}
|
||||
#define meshtastic_LogRecord_init_zero {"", 0, "", _meshtastic_LogRecord_Level_MIN}
|
||||
#define meshtastic_QueueStatus_init_zero {0, 0, 0, 0}
|
||||
@@ -918,6 +938,7 @@ extern "C" {
|
||||
#define meshtastic_NeighborInfo_init_zero {0, 0, 0, 0, {meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero}}
|
||||
#define meshtastic_Neighbor_init_zero {0, 0, 0, 0}
|
||||
#define meshtastic_DeviceMetadata_init_zero {"", 0, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_Role_MIN, 0, _meshtastic_HardwareModel_MIN, 0}
|
||||
#define meshtastic_Heartbeat_init_zero {0}
|
||||
|
||||
/* Field tags (for use in manual encoding/decoding) */
|
||||
#define meshtastic_Position_latitude_i_tag 1
|
||||
@@ -942,6 +963,7 @@ extern "C" {
|
||||
#define meshtastic_Position_sensor_id_tag 20
|
||||
#define meshtastic_Position_next_update_tag 21
|
||||
#define meshtastic_Position_seq_number_tag 22
|
||||
#define meshtastic_Position_precision_bits_tag 23
|
||||
#define meshtastic_User_id_tag 1
|
||||
#define meshtastic_User_long_name_tag 2
|
||||
#define meshtastic_User_short_name_tag 3
|
||||
@@ -987,6 +1009,7 @@ extern "C" {
|
||||
#define meshtastic_MeshPacket_rx_rssi_tag 12
|
||||
#define meshtastic_MeshPacket_delayed_tag 13
|
||||
#define meshtastic_MeshPacket_via_mqtt_tag 14
|
||||
#define meshtastic_MeshPacket_hop_start_tag 15
|
||||
#define meshtastic_NodeInfo_num_tag 1
|
||||
#define meshtastic_NodeInfo_user_tag 2
|
||||
#define meshtastic_NodeInfo_position_tag 3
|
||||
@@ -994,6 +1017,9 @@ extern "C" {
|
||||
#define meshtastic_NodeInfo_last_heard_tag 5
|
||||
#define meshtastic_NodeInfo_device_metrics_tag 6
|
||||
#define meshtastic_NodeInfo_channel_tag 7
|
||||
#define meshtastic_NodeInfo_via_mqtt_tag 8
|
||||
#define meshtastic_NodeInfo_hops_away_tag 9
|
||||
#define meshtastic_NodeInfo_is_favorite_tag 10
|
||||
#define meshtastic_MyNodeInfo_my_node_num_tag 1
|
||||
#define meshtastic_MyNodeInfo_reboot_count_tag 8
|
||||
#define meshtastic_MyNodeInfo_min_app_version_tag 11
|
||||
@@ -1005,11 +1031,6 @@ extern "C" {
|
||||
#define meshtastic_QueueStatus_free_tag 2
|
||||
#define meshtastic_QueueStatus_maxlen_tag 3
|
||||
#define meshtastic_QueueStatus_mesh_packet_id_tag 4
|
||||
#define meshtastic_ToRadio_packet_tag 1
|
||||
#define meshtastic_ToRadio_want_config_id_tag 3
|
||||
#define meshtastic_ToRadio_disconnect_tag 4
|
||||
#define meshtastic_ToRadio_xmodemPacket_tag 5
|
||||
#define meshtastic_ToRadio_mqttClientProxyMessage_tag 6
|
||||
#define meshtastic_Compressed_portnum_tag 1
|
||||
#define meshtastic_Compressed_data_tag 2
|
||||
#define meshtastic_Neighbor_node_id_tag 1
|
||||
@@ -1044,6 +1065,12 @@ extern "C" {
|
||||
#define meshtastic_FromRadio_xmodemPacket_tag 12
|
||||
#define meshtastic_FromRadio_metadata_tag 13
|
||||
#define meshtastic_FromRadio_mqttClientProxyMessage_tag 14
|
||||
#define meshtastic_ToRadio_packet_tag 1
|
||||
#define meshtastic_ToRadio_want_config_id_tag 3
|
||||
#define meshtastic_ToRadio_disconnect_tag 4
|
||||
#define meshtastic_ToRadio_xmodemPacket_tag 5
|
||||
#define meshtastic_ToRadio_mqttClientProxyMessage_tag 6
|
||||
#define meshtastic_ToRadio_heartbeat_tag 7
|
||||
|
||||
/* Struct field encoding specification for nanopb */
|
||||
#define meshtastic_Position_FIELDLIST(X, a) \
|
||||
@@ -1068,7 +1095,8 @@ X(a, STATIC, SINGULAR, UINT32, fix_type, 18) \
|
||||
X(a, STATIC, SINGULAR, UINT32, sats_in_view, 19) \
|
||||
X(a, STATIC, SINGULAR, UINT32, sensor_id, 20) \
|
||||
X(a, STATIC, SINGULAR, UINT32, next_update, 21) \
|
||||
X(a, STATIC, SINGULAR, UINT32, seq_number, 22)
|
||||
X(a, STATIC, SINGULAR, UINT32, seq_number, 22) \
|
||||
X(a, STATIC, SINGULAR, UINT32, precision_bits, 23)
|
||||
#define meshtastic_Position_CALLBACK NULL
|
||||
#define meshtastic_Position_DEFAULT NULL
|
||||
|
||||
@@ -1143,7 +1171,8 @@ X(a, STATIC, SINGULAR, BOOL, want_ack, 10) \
|
||||
X(a, STATIC, SINGULAR, UENUM, priority, 11) \
|
||||
X(a, STATIC, SINGULAR, INT32, rx_rssi, 12) \
|
||||
X(a, STATIC, SINGULAR, UENUM, delayed, 13) \
|
||||
X(a, STATIC, SINGULAR, BOOL, via_mqtt, 14)
|
||||
X(a, STATIC, SINGULAR, BOOL, via_mqtt, 14) \
|
||||
X(a, STATIC, SINGULAR, UINT32, hop_start, 15)
|
||||
#define meshtastic_MeshPacket_CALLBACK NULL
|
||||
#define meshtastic_MeshPacket_DEFAULT NULL
|
||||
#define meshtastic_MeshPacket_payload_variant_decoded_MSGTYPE meshtastic_Data
|
||||
@@ -1155,7 +1184,10 @@ X(a, STATIC, OPTIONAL, MESSAGE, position, 3) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, snr, 4) \
|
||||
X(a, STATIC, SINGULAR, FIXED32, last_heard, 5) \
|
||||
X(a, STATIC, OPTIONAL, MESSAGE, device_metrics, 6) \
|
||||
X(a, STATIC, SINGULAR, UINT32, channel, 7)
|
||||
X(a, STATIC, SINGULAR, UINT32, channel, 7) \
|
||||
X(a, STATIC, SINGULAR, BOOL, via_mqtt, 8) \
|
||||
X(a, STATIC, SINGULAR, UINT32, hops_away, 9) \
|
||||
X(a, STATIC, SINGULAR, BOOL, is_favorite, 10)
|
||||
#define meshtastic_NodeInfo_CALLBACK NULL
|
||||
#define meshtastic_NodeInfo_DEFAULT NULL
|
||||
#define meshtastic_NodeInfo_user_MSGTYPE meshtastic_User
|
||||
@@ -1219,12 +1251,14 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,packet,packet), 1) \
|
||||
X(a, STATIC, ONEOF, UINT32, (payload_variant,want_config_id,want_config_id), 3) \
|
||||
X(a, STATIC, ONEOF, BOOL, (payload_variant,disconnect,disconnect), 4) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,xmodemPacket,xmodemPacket), 5) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,mqttClientProxyMessage,mqttClientProxyMessage), 6)
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,mqttClientProxyMessage,mqttClientProxyMessage), 6) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,heartbeat,heartbeat), 7)
|
||||
#define meshtastic_ToRadio_CALLBACK NULL
|
||||
#define meshtastic_ToRadio_DEFAULT NULL
|
||||
#define meshtastic_ToRadio_payload_variant_packet_MSGTYPE meshtastic_MeshPacket
|
||||
#define meshtastic_ToRadio_payload_variant_xmodemPacket_MSGTYPE meshtastic_XModem
|
||||
#define meshtastic_ToRadio_payload_variant_mqttClientProxyMessage_MSGTYPE meshtastic_MqttClientProxyMessage
|
||||
#define meshtastic_ToRadio_payload_variant_heartbeat_MSGTYPE meshtastic_Heartbeat
|
||||
|
||||
#define meshtastic_Compressed_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, UENUM, portnum, 1) \
|
||||
@@ -1263,6 +1297,11 @@ X(a, STATIC, SINGULAR, BOOL, hasRemoteHardware, 10)
|
||||
#define meshtastic_DeviceMetadata_CALLBACK NULL
|
||||
#define meshtastic_DeviceMetadata_DEFAULT NULL
|
||||
|
||||
#define meshtastic_Heartbeat_FIELDLIST(X, a) \
|
||||
|
||||
#define meshtastic_Heartbeat_CALLBACK NULL
|
||||
#define meshtastic_Heartbeat_DEFAULT NULL
|
||||
|
||||
extern const pb_msgdesc_t meshtastic_Position_msg;
|
||||
extern const pb_msgdesc_t meshtastic_User_msg;
|
||||
extern const pb_msgdesc_t meshtastic_RouteDiscovery_msg;
|
||||
@@ -1281,6 +1320,7 @@ extern const pb_msgdesc_t meshtastic_Compressed_msg;
|
||||
extern const pb_msgdesc_t meshtastic_NeighborInfo_msg;
|
||||
extern const pb_msgdesc_t meshtastic_Neighbor_msg;
|
||||
extern const pb_msgdesc_t meshtastic_DeviceMetadata_msg;
|
||||
extern const pb_msgdesc_t meshtastic_Heartbeat_msg;
|
||||
|
||||
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
|
||||
#define meshtastic_Position_fields &meshtastic_Position_msg
|
||||
@@ -1301,20 +1341,22 @@ extern const pb_msgdesc_t meshtastic_DeviceMetadata_msg;
|
||||
#define meshtastic_NeighborInfo_fields &meshtastic_NeighborInfo_msg
|
||||
#define meshtastic_Neighbor_fields &meshtastic_Neighbor_msg
|
||||
#define meshtastic_DeviceMetadata_fields &meshtastic_DeviceMetadata_msg
|
||||
#define meshtastic_Heartbeat_fields &meshtastic_Heartbeat_msg
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define meshtastic_Compressed_size 243
|
||||
#define meshtastic_Data_size 270
|
||||
#define meshtastic_DeviceMetadata_size 46
|
||||
#define meshtastic_FromRadio_size 510
|
||||
#define meshtastic_Heartbeat_size 0
|
||||
#define meshtastic_LogRecord_size 81
|
||||
#define meshtastic_MeshPacket_size 323
|
||||
#define meshtastic_MeshPacket_size 326
|
||||
#define meshtastic_MqttClientProxyMessage_size 501
|
||||
#define meshtastic_MyNodeInfo_size 18
|
||||
#define meshtastic_NeighborInfo_size 258
|
||||
#define meshtastic_Neighbor_size 22
|
||||
#define meshtastic_NodeInfo_size 263
|
||||
#define meshtastic_Position_size 137
|
||||
#define meshtastic_NodeInfo_size 277
|
||||
#define meshtastic_Position_size 144
|
||||
#define meshtastic_QueueStatus_size 23
|
||||
#define meshtastic_RouteDiscovery_size 40
|
||||
#define meshtastic_Routing_size 42
|
||||
|
||||
@@ -6,10 +6,13 @@
|
||||
#error Regenerate this file with the current version of nanopb generator.
|
||||
#endif
|
||||
|
||||
PB_BIND(meshtastic_ModuleConfig, meshtastic_ModuleConfig, AUTO)
|
||||
PB_BIND(meshtastic_ModuleConfig, meshtastic_ModuleConfig, 2)
|
||||
|
||||
|
||||
PB_BIND(meshtastic_ModuleConfig_MQTTConfig, meshtastic_ModuleConfig_MQTTConfig, AUTO)
|
||||
PB_BIND(meshtastic_ModuleConfig_MQTTConfig, meshtastic_ModuleConfig_MQTTConfig, 2)
|
||||
|
||||
|
||||
PB_BIND(meshtastic_ModuleConfig_MapReportSettings, meshtastic_ModuleConfig_MapReportSettings, AUTO)
|
||||
|
||||
|
||||
PB_BIND(meshtastic_ModuleConfig_RemoteHardwareConfig, meshtastic_ModuleConfig_RemoteHardwareConfig, AUTO)
|
||||
@@ -84,6 +84,14 @@ typedef enum _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar {
|
||||
} meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar;
|
||||
|
||||
/* Struct definitions */
|
||||
/* Settings for reporting unencrypted information about our node to a map via MQTT */
|
||||
typedef struct _meshtastic_ModuleConfig_MapReportSettings {
|
||||
/* How often we should report our info to the map (in seconds) */
|
||||
uint32_t publish_interval_secs;
|
||||
/* Bits of precision for the location sent (default of 32 is full precision). */
|
||||
uint32_t position_precision;
|
||||
} meshtastic_ModuleConfig_MapReportSettings;
|
||||
|
||||
/* MQTT Client Config */
|
||||
typedef struct _meshtastic_ModuleConfig_MQTTConfig {
|
||||
/* If a meshtastic node is able to reach the internet it will normally attempt to gateway any channels that are marked as
|
||||
@@ -111,9 +119,14 @@ typedef struct _meshtastic_ModuleConfig_MQTTConfig {
|
||||
bool tls_enabled;
|
||||
/* The root topic to use for MQTT messages. Default is "msh".
|
||||
This is useful if you want to use a single MQTT server for multiple meshtastic networks and separate them via ACLs */
|
||||
char root[16];
|
||||
char root[32];
|
||||
/* If true, we can use the connected phone / client to proxy messages to MQTT instead of a direct connection */
|
||||
bool proxy_to_client_enabled;
|
||||
/* If true, we will periodically report unencrypted information about our node to a map via MQTT */
|
||||
bool map_reporting_enabled;
|
||||
/* Settings for reporting information about our node to a map via MQTT */
|
||||
bool has_map_report_settings;
|
||||
meshtastic_ModuleConfig_MapReportSettings map_report_settings;
|
||||
} meshtastic_ModuleConfig_MQTTConfig;
|
||||
|
||||
/* NeighborInfoModule Config */
|
||||
@@ -427,6 +440,7 @@ extern "C" {
|
||||
|
||||
|
||||
|
||||
|
||||
#define meshtastic_ModuleConfig_AudioConfig_bitrate_ENUMTYPE meshtastic_ModuleConfig_AudioConfig_Audio_Baud
|
||||
|
||||
|
||||
@@ -447,7 +461,8 @@ extern "C" {
|
||||
|
||||
/* Initializer values for message structs */
|
||||
#define meshtastic_ModuleConfig_init_default {0, {meshtastic_ModuleConfig_MQTTConfig_init_default}}
|
||||
#define meshtastic_ModuleConfig_MQTTConfig_init_default {0, "", "", "", 0, 0, 0, "", 0}
|
||||
#define meshtastic_ModuleConfig_MQTTConfig_init_default {0, "", "", "", 0, 0, 0, "", 0, 0, false, meshtastic_ModuleConfig_MapReportSettings_init_default}
|
||||
#define meshtastic_ModuleConfig_MapReportSettings_init_default {0, 0}
|
||||
#define meshtastic_ModuleConfig_RemoteHardwareConfig_init_default {0, 0, 0, {meshtastic_RemoteHardwarePin_init_default, meshtastic_RemoteHardwarePin_init_default, meshtastic_RemoteHardwarePin_init_default, meshtastic_RemoteHardwarePin_init_default}}
|
||||
#define meshtastic_ModuleConfig_NeighborInfoConfig_init_default {0, 0}
|
||||
#define meshtastic_ModuleConfig_DetectionSensorConfig_init_default {0, 0, 0, 0, "", 0, 0, 0}
|
||||
@@ -462,7 +477,8 @@ extern "C" {
|
||||
#define meshtastic_ModuleConfig_AmbientLightingConfig_init_default {0, 0, 0, 0, 0}
|
||||
#define meshtastic_RemoteHardwarePin_init_default {0, "", _meshtastic_RemoteHardwarePinType_MIN}
|
||||
#define meshtastic_ModuleConfig_init_zero {0, {meshtastic_ModuleConfig_MQTTConfig_init_zero}}
|
||||
#define meshtastic_ModuleConfig_MQTTConfig_init_zero {0, "", "", "", 0, 0, 0, "", 0}
|
||||
#define meshtastic_ModuleConfig_MQTTConfig_init_zero {0, "", "", "", 0, 0, 0, "", 0, 0, false, meshtastic_ModuleConfig_MapReportSettings_init_zero}
|
||||
#define meshtastic_ModuleConfig_MapReportSettings_init_zero {0, 0}
|
||||
#define meshtastic_ModuleConfig_RemoteHardwareConfig_init_zero {0, 0, 0, {meshtastic_RemoteHardwarePin_init_zero, meshtastic_RemoteHardwarePin_init_zero, meshtastic_RemoteHardwarePin_init_zero, meshtastic_RemoteHardwarePin_init_zero}}
|
||||
#define meshtastic_ModuleConfig_NeighborInfoConfig_init_zero {0, 0}
|
||||
#define meshtastic_ModuleConfig_DetectionSensorConfig_init_zero {0, 0, 0, 0, "", 0, 0, 0}
|
||||
@@ -478,6 +494,8 @@ extern "C" {
|
||||
#define meshtastic_RemoteHardwarePin_init_zero {0, "", _meshtastic_RemoteHardwarePinType_MIN}
|
||||
|
||||
/* Field tags (for use in manual encoding/decoding) */
|
||||
#define meshtastic_ModuleConfig_MapReportSettings_publish_interval_secs_tag 1
|
||||
#define meshtastic_ModuleConfig_MapReportSettings_position_precision_tag 2
|
||||
#define meshtastic_ModuleConfig_MQTTConfig_enabled_tag 1
|
||||
#define meshtastic_ModuleConfig_MQTTConfig_address_tag 2
|
||||
#define meshtastic_ModuleConfig_MQTTConfig_username_tag 3
|
||||
@@ -487,6 +505,8 @@ extern "C" {
|
||||
#define meshtastic_ModuleConfig_MQTTConfig_tls_enabled_tag 7
|
||||
#define meshtastic_ModuleConfig_MQTTConfig_root_tag 8
|
||||
#define meshtastic_ModuleConfig_MQTTConfig_proxy_to_client_enabled_tag 9
|
||||
#define meshtastic_ModuleConfig_MQTTConfig_map_reporting_enabled_tag 10
|
||||
#define meshtastic_ModuleConfig_MQTTConfig_map_report_settings_tag 11
|
||||
#define meshtastic_ModuleConfig_NeighborInfoConfig_enabled_tag 1
|
||||
#define meshtastic_ModuleConfig_NeighborInfoConfig_update_interval_tag 2
|
||||
#define meshtastic_ModuleConfig_DetectionSensorConfig_enabled_tag 1
|
||||
@@ -623,9 +643,18 @@ X(a, STATIC, SINGULAR, BOOL, encryption_enabled, 5) \
|
||||
X(a, STATIC, SINGULAR, BOOL, json_enabled, 6) \
|
||||
X(a, STATIC, SINGULAR, BOOL, tls_enabled, 7) \
|
||||
X(a, STATIC, SINGULAR, STRING, root, 8) \
|
||||
X(a, STATIC, SINGULAR, BOOL, proxy_to_client_enabled, 9)
|
||||
X(a, STATIC, SINGULAR, BOOL, proxy_to_client_enabled, 9) \
|
||||
X(a, STATIC, SINGULAR, BOOL, map_reporting_enabled, 10) \
|
||||
X(a, STATIC, OPTIONAL, MESSAGE, map_report_settings, 11)
|
||||
#define meshtastic_ModuleConfig_MQTTConfig_CALLBACK NULL
|
||||
#define meshtastic_ModuleConfig_MQTTConfig_DEFAULT NULL
|
||||
#define meshtastic_ModuleConfig_MQTTConfig_map_report_settings_MSGTYPE meshtastic_ModuleConfig_MapReportSettings
|
||||
|
||||
#define meshtastic_ModuleConfig_MapReportSettings_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, UINT32, publish_interval_secs, 1) \
|
||||
X(a, STATIC, SINGULAR, UINT32, position_precision, 2)
|
||||
#define meshtastic_ModuleConfig_MapReportSettings_CALLBACK NULL
|
||||
#define meshtastic_ModuleConfig_MapReportSettings_DEFAULT NULL
|
||||
|
||||
#define meshtastic_ModuleConfig_RemoteHardwareConfig_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, BOOL, enabled, 1) \
|
||||
@@ -764,6 +793,7 @@ X(a, STATIC, SINGULAR, UENUM, type, 3)
|
||||
|
||||
extern const pb_msgdesc_t meshtastic_ModuleConfig_msg;
|
||||
extern const pb_msgdesc_t meshtastic_ModuleConfig_MQTTConfig_msg;
|
||||
extern const pb_msgdesc_t meshtastic_ModuleConfig_MapReportSettings_msg;
|
||||
extern const pb_msgdesc_t meshtastic_ModuleConfig_RemoteHardwareConfig_msg;
|
||||
extern const pb_msgdesc_t meshtastic_ModuleConfig_NeighborInfoConfig_msg;
|
||||
extern const pb_msgdesc_t meshtastic_ModuleConfig_DetectionSensorConfig_msg;
|
||||
@@ -781,6 +811,7 @@ extern const pb_msgdesc_t meshtastic_RemoteHardwarePin_msg;
|
||||
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
|
||||
#define meshtastic_ModuleConfig_fields &meshtastic_ModuleConfig_msg
|
||||
#define meshtastic_ModuleConfig_MQTTConfig_fields &meshtastic_ModuleConfig_MQTTConfig_msg
|
||||
#define meshtastic_ModuleConfig_MapReportSettings_fields &meshtastic_ModuleConfig_MapReportSettings_msg
|
||||
#define meshtastic_ModuleConfig_RemoteHardwareConfig_fields &meshtastic_ModuleConfig_RemoteHardwareConfig_msg
|
||||
#define meshtastic_ModuleConfig_NeighborInfoConfig_fields &meshtastic_ModuleConfig_NeighborInfoConfig_msg
|
||||
#define meshtastic_ModuleConfig_DetectionSensorConfig_fields &meshtastic_ModuleConfig_DetectionSensorConfig_msg
|
||||
@@ -801,7 +832,8 @@ extern const pb_msgdesc_t meshtastic_RemoteHardwarePin_msg;
|
||||
#define meshtastic_ModuleConfig_CannedMessageConfig_size 49
|
||||
#define meshtastic_ModuleConfig_DetectionSensorConfig_size 44
|
||||
#define meshtastic_ModuleConfig_ExternalNotificationConfig_size 42
|
||||
#define meshtastic_ModuleConfig_MQTTConfig_size 222
|
||||
#define meshtastic_ModuleConfig_MQTTConfig_size 254
|
||||
#define meshtastic_ModuleConfig_MapReportSettings_size 12
|
||||
#define meshtastic_ModuleConfig_NeighborInfoConfig_size 8
|
||||
#define meshtastic_ModuleConfig_PaxcounterConfig_size 8
|
||||
#define meshtastic_ModuleConfig_RangeTestConfig_size 10
|
||||
@@ -809,7 +841,7 @@ extern const pb_msgdesc_t meshtastic_RemoteHardwarePin_msg;
|
||||
#define meshtastic_ModuleConfig_SerialConfig_size 28
|
||||
#define meshtastic_ModuleConfig_StoreForwardConfig_size 22
|
||||
#define meshtastic_ModuleConfig_TelemetryConfig_size 36
|
||||
#define meshtastic_ModuleConfig_size 225
|
||||
#define meshtastic_ModuleConfig_size 257
|
||||
#define meshtastic_RemoteHardwarePin_size 21
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -9,4 +9,7 @@
|
||||
PB_BIND(meshtastic_ServiceEnvelope, meshtastic_ServiceEnvelope, AUTO)
|
||||
|
||||
|
||||
PB_BIND(meshtastic_MapReport, meshtastic_MapReport, AUTO)
|
||||
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#define PB_MESHTASTIC_MESHTASTIC_MQTT_PB_H_INCLUDED
|
||||
#include <pb.h>
|
||||
#include "meshtastic/mesh.pb.h"
|
||||
#include "meshtastic/config.pb.h"
|
||||
|
||||
#if PB_PROTO_HEADER_VERSION != 40
|
||||
#error Regenerate this file with the current version of nanopb generator.
|
||||
@@ -23,6 +24,38 @@ typedef struct _meshtastic_ServiceEnvelope {
|
||||
char *gateway_id;
|
||||
} meshtastic_ServiceEnvelope;
|
||||
|
||||
/* Information about a node intended to be reported unencrypted to a map using MQTT. */
|
||||
typedef struct _meshtastic_MapReport {
|
||||
/* A full name for this user, i.e. "Kevin Hester" */
|
||||
char long_name[40];
|
||||
/* A VERY short name, ideally two characters.
|
||||
Suitable for a tiny OLED screen */
|
||||
char short_name[5];
|
||||
/* Role of the node that applies specific settings for a particular use-case */
|
||||
meshtastic_Config_DeviceConfig_Role role;
|
||||
/* Hardware model of the node, i.e. T-Beam, Heltec V3, etc... */
|
||||
meshtastic_HardwareModel hw_model;
|
||||
/* Device firmware version string */
|
||||
char firmware_version[18];
|
||||
/* The region code for the radio (US, CN, EU433, etc...) */
|
||||
meshtastic_Config_LoRaConfig_RegionCode region;
|
||||
/* Modem preset used by the radio (LongFast, MediumSlow, etc...) */
|
||||
meshtastic_Config_LoRaConfig_ModemPreset modem_preset;
|
||||
/* Whether the node has a channel with default PSK and name (LongFast, MediumSlow, etc...)
|
||||
and it uses the default frequency slot given the region and modem preset. */
|
||||
bool has_default_channel;
|
||||
/* Latitude: multiply by 1e-7 to get degrees in floating point */
|
||||
int32_t latitude_i;
|
||||
/* Longitude: multiply by 1e-7 to get degrees in floating point */
|
||||
int32_t longitude_i;
|
||||
/* Altitude in meters above MSL */
|
||||
int32_t altitude;
|
||||
/* Indicates the bits of precision for latitude and longitude set by the sending node */
|
||||
uint32_t position_precision;
|
||||
/* Number of online nodes (heard in the last 2 hours) this node has in its list that were received locally (not via MQTT) */
|
||||
uint16_t num_online_local_nodes;
|
||||
} meshtastic_MapReport;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -30,12 +63,27 @@ extern "C" {
|
||||
|
||||
/* Initializer values for message structs */
|
||||
#define meshtastic_ServiceEnvelope_init_default {NULL, NULL, NULL}
|
||||
#define meshtastic_MapReport_init_default {"", "", _meshtastic_Config_DeviceConfig_Role_MIN, _meshtastic_HardwareModel_MIN, "", _meshtastic_Config_LoRaConfig_RegionCode_MIN, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, 0, 0}
|
||||
#define meshtastic_ServiceEnvelope_init_zero {NULL, NULL, NULL}
|
||||
#define meshtastic_MapReport_init_zero {"", "", _meshtastic_Config_DeviceConfig_Role_MIN, _meshtastic_HardwareModel_MIN, "", _meshtastic_Config_LoRaConfig_RegionCode_MIN, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, 0, 0}
|
||||
|
||||
/* Field tags (for use in manual encoding/decoding) */
|
||||
#define meshtastic_ServiceEnvelope_packet_tag 1
|
||||
#define meshtastic_ServiceEnvelope_channel_id_tag 2
|
||||
#define meshtastic_ServiceEnvelope_gateway_id_tag 3
|
||||
#define meshtastic_MapReport_long_name_tag 1
|
||||
#define meshtastic_MapReport_short_name_tag 2
|
||||
#define meshtastic_MapReport_role_tag 3
|
||||
#define meshtastic_MapReport_hw_model_tag 4
|
||||
#define meshtastic_MapReport_firmware_version_tag 5
|
||||
#define meshtastic_MapReport_region_tag 6
|
||||
#define meshtastic_MapReport_modem_preset_tag 7
|
||||
#define meshtastic_MapReport_has_default_channel_tag 8
|
||||
#define meshtastic_MapReport_latitude_i_tag 9
|
||||
#define meshtastic_MapReport_longitude_i_tag 10
|
||||
#define meshtastic_MapReport_altitude_tag 11
|
||||
#define meshtastic_MapReport_position_precision_tag 12
|
||||
#define meshtastic_MapReport_num_online_local_nodes_tag 13
|
||||
|
||||
/* Struct field encoding specification for nanopb */
|
||||
#define meshtastic_ServiceEnvelope_FIELDLIST(X, a) \
|
||||
@@ -46,13 +94,33 @@ X(a, POINTER, SINGULAR, STRING, gateway_id, 3)
|
||||
#define meshtastic_ServiceEnvelope_DEFAULT NULL
|
||||
#define meshtastic_ServiceEnvelope_packet_MSGTYPE meshtastic_MeshPacket
|
||||
|
||||
#define meshtastic_MapReport_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, STRING, long_name, 1) \
|
||||
X(a, STATIC, SINGULAR, STRING, short_name, 2) \
|
||||
X(a, STATIC, SINGULAR, UENUM, role, 3) \
|
||||
X(a, STATIC, SINGULAR, UENUM, hw_model, 4) \
|
||||
X(a, STATIC, SINGULAR, STRING, firmware_version, 5) \
|
||||
X(a, STATIC, SINGULAR, UENUM, region, 6) \
|
||||
X(a, STATIC, SINGULAR, UENUM, modem_preset, 7) \
|
||||
X(a, STATIC, SINGULAR, BOOL, has_default_channel, 8) \
|
||||
X(a, STATIC, SINGULAR, SFIXED32, latitude_i, 9) \
|
||||
X(a, STATIC, SINGULAR, SFIXED32, longitude_i, 10) \
|
||||
X(a, STATIC, SINGULAR, INT32, altitude, 11) \
|
||||
X(a, STATIC, SINGULAR, UINT32, position_precision, 12) \
|
||||
X(a, STATIC, SINGULAR, UINT32, num_online_local_nodes, 13)
|
||||
#define meshtastic_MapReport_CALLBACK NULL
|
||||
#define meshtastic_MapReport_DEFAULT NULL
|
||||
|
||||
extern const pb_msgdesc_t meshtastic_ServiceEnvelope_msg;
|
||||
extern const pb_msgdesc_t meshtastic_MapReport_msg;
|
||||
|
||||
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
|
||||
#define meshtastic_ServiceEnvelope_fields &meshtastic_ServiceEnvelope_msg
|
||||
#define meshtastic_MapReport_fields &meshtastic_MapReport_msg
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
/* meshtastic_ServiceEnvelope_size depends on runtime parameters */
|
||||
#define meshtastic_MapReport_size 108
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user