mirror of
https://github.com/meshtastic/firmware.git
synced 2026-01-07 18:37:52 +00:00
Compare commits
242 Commits
v2.1.21.97
...
v2.2.9.473
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
47301a5ac0 | ||
|
|
0d023ea215 | ||
|
|
b5e952db24 | ||
|
|
a1c433748a | ||
|
|
04b2ab82dc | ||
|
|
e96ba7cbcf | ||
|
|
61f6fb22c5 | ||
|
|
db7b77c76e | ||
|
|
350090ec0d | ||
|
|
cdac643749 | ||
|
|
1a2c7f00e1 | ||
|
|
7eff5e7bcb | ||
|
|
17207681ef | ||
|
|
94f7c7e472 | ||
|
|
0a12d67d19 | ||
|
|
3175a3d630 | ||
|
|
4e9bf75340 | ||
|
|
e8970ad66b | ||
|
|
f737ee59ec | ||
|
|
6d211815d9 | ||
|
|
1bae926576 | ||
|
|
a1514b8b64 | ||
|
|
8b82ae6fe3 | ||
|
|
822c150e0d | ||
|
|
0731902744 | ||
|
|
b53cb38a09 | ||
|
|
b02dd0e964 | ||
|
|
c608f0ba81 | ||
|
|
e1839e33f2 | ||
|
|
d6d51bc3f4 | ||
|
|
44a77a10e1 | ||
|
|
8255128eae | ||
|
|
d7a98519f4 | ||
|
|
e256520336 | ||
|
|
fcf798df98 | ||
|
|
dcdf9b64de | ||
|
|
fd563e41f1 | ||
|
|
0fa3685161 | ||
|
|
899f9dd7bf | ||
|
|
9af4ecf48f | ||
|
|
cfb6a1394c | ||
|
|
1254031f7d | ||
|
|
c91e306659 | ||
|
|
4ff343b20f | ||
|
|
134fc75b67 | ||
|
|
fb23e479ac | ||
|
|
5a61695016 | ||
|
|
3bcab0e223 | ||
|
|
17617ce031 | ||
|
|
97f0c734e0 | ||
|
|
e943fffe8c | ||
|
|
ffcb131171 | ||
|
|
bb1fe7cad3 | ||
|
|
ad40493a39 | ||
|
|
ac62330e1c | ||
|
|
53f6a43661 | ||
|
|
7ad94da1c6 | ||
|
|
ecdb75aae0 | ||
|
|
7c98445ca3 | ||
|
|
b21368ecfa | ||
|
|
1a178c7d33 | ||
|
|
5d6f0ea6c4 | ||
|
|
5bd861f3d8 | ||
|
|
6d93fab495 | ||
|
|
6803fd7949 | ||
|
|
a61f969773 | ||
|
|
79cfc4b725 | ||
|
|
cf762bbd42 | ||
|
|
3d2c419d0d | ||
|
|
903f619609 | ||
|
|
2e3f762d3d | ||
|
|
a42266f74b | ||
|
|
a605c69eb4 | ||
|
|
282cc0b16a | ||
|
|
4ab67f3668 | ||
|
|
312028b161 | ||
|
|
ecd48db69c | ||
|
|
03dc36ea12 | ||
|
|
c2ae38405e | ||
|
|
2a1d8c40b4 | ||
|
|
e2441c425a | ||
|
|
00ffe73ebd | ||
|
|
3355019de3 | ||
|
|
5bb207d88b | ||
|
|
5453e4d123 | ||
|
|
7f1b58a222 | ||
|
|
39357b2686 | ||
|
|
d6b629ae04 | ||
|
|
7b1aeb60cd | ||
|
|
5c7c1cd253 | ||
|
|
8cfe130df3 | ||
|
|
feef86942d | ||
|
|
5f3a8b4924 | ||
|
|
0fcaaf39b0 | ||
|
|
a55eac5c20 | ||
|
|
b47c9c165a | ||
|
|
ecceb10910 | ||
|
|
6fc76103a0 | ||
|
|
f35c7be917 | ||
|
|
364364263b | ||
|
|
ef957bfac5 | ||
|
|
5d78795065 | ||
|
|
2dbdda204f | ||
|
|
4767bd5497 | ||
|
|
05efd68097 | ||
|
|
a90eef432f | ||
|
|
929b8f6209 | ||
|
|
5d76771fab | ||
|
|
91eb64d7b7 | ||
|
|
03fe4c629a | ||
|
|
144dfe9805 | ||
|
|
18899fd168 | ||
|
|
fcfd83bc89 | ||
|
|
a3d2b6166c | ||
|
|
fb5f2e48a5 | ||
|
|
d29c975e3c | ||
|
|
c44986127e | ||
|
|
6e0b6684ee | ||
|
|
84ddfea491 | ||
|
|
3d6fb13f9a | ||
|
|
54c48329c8 | ||
|
|
ede31a2080 | ||
|
|
9470d4694b | ||
|
|
2074c76780 | ||
|
|
9f6584bd67 | ||
|
|
dd69de9f32 | ||
|
|
616553ed72 | ||
|
|
1986267d65 | ||
|
|
1d0ac2caf7 | ||
|
|
746d7268a2 | ||
|
|
9a7777dbdb | ||
|
|
0fe99b0caa | ||
|
|
f9798b7dda | ||
|
|
23fb377fd7 | ||
|
|
4808a5c57f | ||
|
|
d25c368985 | ||
|
|
a5f3dea40b | ||
|
|
f026c3308c | ||
|
|
ed4e7a4cee | ||
|
|
95f67d70ea | ||
|
|
e3260c1d19 | ||
|
|
98f3be0665 | ||
|
|
dc31024764 | ||
|
|
5bbcb40f7a | ||
|
|
8218a729e0 | ||
|
|
cbc3e605dd | ||
|
|
94c41a4fed | ||
|
|
1afe9f75bd | ||
|
|
402f8ba524 | ||
|
|
04bbdc6b8a | ||
|
|
0084c0881d | ||
|
|
8552cc44b9 | ||
|
|
684cce7640 | ||
|
|
114eb0c952 | ||
|
|
bed2bfa074 | ||
|
|
0aef8703b6 | ||
|
|
f5d323fdd3 | ||
|
|
568cc259af | ||
|
|
42039e27e7 | ||
|
|
400b71c152 | ||
|
|
b1f6ff1280 | ||
|
|
cfe5c7f31d | ||
|
|
4e54bec525 | ||
|
|
e0bf15b80e | ||
|
|
26264fd908 | ||
|
|
794948d7e4 | ||
|
|
e9cbe54eca | ||
|
|
641d117106 | ||
|
|
5f38e79b8f | ||
|
|
b238aebe38 | ||
|
|
e05c8e60d9 | ||
|
|
f1bcc300d9 | ||
|
|
06a6a992c2 | ||
|
|
11be856507 | ||
|
|
7fe815a327 | ||
|
|
191a69dd26 | ||
|
|
9eeec6c083 | ||
|
|
c4474a7b99 | ||
|
|
0821cff1c8 | ||
|
|
b799b7bf62 | ||
|
|
90ec8eae6c | ||
|
|
ba172aae32 | ||
|
|
26338b8f2b | ||
|
|
939a359e7e | ||
|
|
5a5af4707c | ||
|
|
ef5e21d3da | ||
|
|
8a49221b7f | ||
|
|
76dc805184 | ||
|
|
297708a50b | ||
|
|
a61a4fad3e | ||
|
|
c66b68b0cc | ||
|
|
04cba45c60 | ||
|
|
5aedd84c7d | ||
|
|
38c9a1ea07 | ||
|
|
0eefd0912f | ||
|
|
0cda8e6087 | ||
|
|
2cf648928a | ||
|
|
3cd7d8d6af | ||
|
|
702a83b525 | ||
|
|
32246850aa | ||
|
|
74650ca276 | ||
|
|
0141bbe772 | ||
|
|
049c587ca2 | ||
|
|
1a28225cd5 | ||
|
|
4fd756acd8 | ||
|
|
ff11506922 | ||
|
|
f35b422365 | ||
|
|
08f1ac785a | ||
|
|
146ed067a1 | ||
|
|
2e7c95a110 | ||
|
|
3a24882e76 | ||
|
|
41b07de5a2 | ||
|
|
1745722dac | ||
|
|
849599cd8e | ||
|
|
bfc567ad89 | ||
|
|
b665786c77 | ||
|
|
e60a5f1cf2 | ||
|
|
6bdf67c9be | ||
|
|
bbfd62c47e | ||
|
|
a07e30544d | ||
|
|
9716bd8bec | ||
|
|
c2168dd450 | ||
|
|
66c71250b8 | ||
|
|
5c438ae792 | ||
|
|
cdf44ce7fa | ||
|
|
d70bd23260 | ||
|
|
b42ead4400 | ||
|
|
b2704a0082 | ||
|
|
9b94701699 | ||
|
|
61661aed50 | ||
|
|
3a25d6d3b3 | ||
|
|
fd4e9daa7f | ||
|
|
b6f7b7fa47 | ||
|
|
a92a960682 | ||
|
|
5d2ab65a81 | ||
|
|
f3b7f7251c | ||
|
|
2f60bbe5f2 | ||
|
|
0261754269 | ||
|
|
e6fc2af21f | ||
|
|
ae41944a89 | ||
|
|
62259583e6 | ||
|
|
c5d87fe581 |
2
.github/workflows/main_matrix.yml
vendored
2
.github/workflows/main_matrix.yml
vendored
@@ -95,6 +95,7 @@ jobs:
|
||||
- board: tlora-t3s3-v1
|
||||
- board: t-watch-s3
|
||||
- board: t-deck
|
||||
- board: picomputer-s3
|
||||
uses: ./.github/workflows/build_esp32_s3.yml
|
||||
with:
|
||||
board: ${{ matrix.board }}
|
||||
@@ -111,6 +112,7 @@ jobs:
|
||||
- board: t-echo
|
||||
- board: pca10059_diy_eink
|
||||
- board: feather_diy
|
||||
- board: nano-g2-ultra
|
||||
uses: ./.github/workflows/build_nrf52.yml
|
||||
with:
|
||||
board: ${{ matrix.board }}
|
||||
|
||||
22
.github/workflows/trunk-check.yml
vendored
Normal file
22
.github/workflows/trunk-check.yml
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
name: Pull Request
|
||||
on: [pull_request]
|
||||
concurrency:
|
||||
group: ${{ github.head_ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions: read-all
|
||||
|
||||
jobs:
|
||||
trunk_check:
|
||||
name: Trunk Check Runner
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
checks: write # For trunk to post annotations
|
||||
contents: read # For repo checkout
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Trunk Check
|
||||
uses: trunk-io/trunk-action@v1
|
||||
2
.trunk/.gitignore
vendored
2
.trunk/.gitignore
vendored
@@ -5,4 +5,4 @@
|
||||
plugins
|
||||
user_trunk.yaml
|
||||
user.yaml
|
||||
shims
|
||||
tools
|
||||
|
||||
@@ -1,37 +1,42 @@
|
||||
version: 0.1
|
||||
cli:
|
||||
version: 1.9.1
|
||||
version: 1.13.0
|
||||
plugins:
|
||||
sources:
|
||||
- id: trunk
|
||||
ref: v0.0.17
|
||||
ref: v1.1.1
|
||||
uri: https://github.com/trunk-io/plugins
|
||||
lint:
|
||||
enabled:
|
||||
- taplo@0.7.0
|
||||
- ruff@0.0.265
|
||||
- yamllint@1.31.0
|
||||
- bandit@1.7.5
|
||||
- checkov@2.4.1
|
||||
- terrascan@1.18.3
|
||||
- trivy@0.44.1
|
||||
- trufflehog@3.48.0
|
||||
- taplo@0.8.1
|
||||
- ruff@0.0.284
|
||||
- yamllint@1.32.0
|
||||
- isort@5.12.0
|
||||
- markdownlint@0.34.0
|
||||
- markdownlint@0.35.0
|
||||
- oxipng@8.0.0
|
||||
- svgo@3.0.2
|
||||
- actionlint@1.6.24
|
||||
- flake8@6.0.0
|
||||
- actionlint@1.6.25
|
||||
- flake8@6.1.0
|
||||
- hadolint@2.12.0
|
||||
- shfmt@3.5.0
|
||||
- shfmt@3.6.0
|
||||
- shellcheck@0.9.0
|
||||
- black@23.3.0
|
||||
- black@23.7.0
|
||||
- git-diff-check
|
||||
- gitleaks@8.16.3
|
||||
- clang-format@14.0.0
|
||||
- prettier@2.8.8
|
||||
- gitleaks@8.17.0
|
||||
- clang-format@16.0.3
|
||||
- prettier@3.0.2
|
||||
disabled:
|
||||
- taplo@0.7.0
|
||||
- taplo@0.8.1
|
||||
- shellcheck@0.9.0
|
||||
- shfmt@3.5.0
|
||||
- shfmt@3.6.0
|
||||
- oxipng@8.0.0
|
||||
- actionlint@1.6.22
|
||||
- markdownlint@0.34.0
|
||||
- markdownlint@0.35.0
|
||||
- hadolint@2.12.0
|
||||
- svgo@3.0.2
|
||||
runtimes:
|
||||
|
||||
2
.vscode/extensions.json
vendored
2
.vscode/extensions.json
vendored
@@ -6,4 +6,4 @@
|
||||
"platformio.platformio-ide",
|
||||
"trunk.io"
|
||||
],
|
||||
}
|
||||
}
|
||||
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"editor.formatOnSave": true,
|
||||
"editor.defaultFormatter": "trunk.io"
|
||||
"editor.defaultFormatter": "trunk.io",
|
||||
"trunk.enableWindows": true
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
; Common settings for ESP targes, mixin with extends = esp32_base
|
||||
[esp32_base]
|
||||
extends = arduino_base
|
||||
platform = platformio/espressif32@^6.3.2
|
||||
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/>
|
||||
@@ -30,6 +30,7 @@ build_flags =
|
||||
-DCONFIG_BT_NIMBLE_MAX_CCCDS=20
|
||||
-DCONFIG_BT_NIMBLE_HOST_TASK_STACK_SIZE=5120
|
||||
-DESP_OPENSSL_SUPPRESS_LEGACY_WARNING
|
||||
-DSERIAL_BUFFER_SIZE=4096
|
||||
;-DDEBUG_HEAP
|
||||
|
||||
lib_deps =
|
||||
@@ -37,7 +38,7 @@ lib_deps =
|
||||
${networking_base.lib_deps}
|
||||
${environmental_base.lib_deps}
|
||||
https://github.com/meshtastic/esp32_https_server.git#23665b3adc080a311dcbb586ed5941b5f94d6ea2
|
||||
h2zero/NimBLE-Arduino@^1.4.0
|
||||
h2zero/NimBLE-Arduino@^1.4.1
|
||||
jgromes/RadioLib@^6.1.0
|
||||
https://github.com/lewisxhe/XPowersLib.git#84b7373faea3118b6c37954d52f98b8a337148d6
|
||||
https://github.com/meshtastic/ESP32_Codec2.git#633326c78ac251c059ab3a8c430fcdf25b41672f
|
||||
@@ -56,4 +57,4 @@ lib_ignore =
|
||||
|
||||
; customize the partition table
|
||||
; http://docs.platformio.org/en/latest/platforms/espressif32.html#partition-tables
|
||||
board_build.partitions = partition-table.csv
|
||||
board_build.partitions = partition-table.csv
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
[nrf52_base]
|
||||
; Instead of the standard nordicnrf52 platform, we use our fork which has our added variant files
|
||||
platform = platformio/nordicnrf52@^10.0.0
|
||||
platform = platformio/nordicnrf52@^10.1.0
|
||||
extends = arduino_base
|
||||
|
||||
build_type = debug ; I'm debugging with ICE a lot now
|
||||
build_flags =
|
||||
${arduino_base.build_flags} -Wno-unused-variable
|
||||
${arduino_base.build_flags}
|
||||
-DSERIAL_BUFFER_SIZE=1024
|
||||
-Wno-unused-variable
|
||||
-Isrc/platform/nrf52
|
||||
|
||||
build_src_filter =
|
||||
|
||||
@@ -4,23 +4,23 @@
|
||||
|
||||
set -e
|
||||
|
||||
VERSION=`bin/buildinfo.py long`
|
||||
VERSION=$(bin/buildinfo.py long)
|
||||
|
||||
# The shell vars the build tool expects to find
|
||||
export APP_VERSION=$VERSION
|
||||
|
||||
if [[ $# -gt 0 ]]; then
|
||||
# can override which environment by passing arg
|
||||
BOARDS="$@"
|
||||
# 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 pca10059_diy_eink"
|
||||
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 pca10059_diy_eink"
|
||||
fi
|
||||
|
||||
echo "BOARDS:${BOARDS}"
|
||||
|
||||
CHECK=""
|
||||
for BOARD in $BOARDS; do
|
||||
CHECK="${CHECK} -e ${BOARD}"
|
||||
CHECK="${CHECK} -e ${BOARD}"
|
||||
done
|
||||
|
||||
pio check --flags "-DAPP_VERSION=${APP_VERSION} --suppressions-list=suppressions.txt" $CHECK --skip-packages --pattern="src/" --fail-on-defect=low --fail-on-defect=medium --fail-on-defect=high
|
||||
pio check --flags "-DAPP_VERSION=${APP_VERSION} --suppressions-list=suppressions.txt" $CHECK --skip-packages --pattern="src/" --fail-on-defect=medium --fail-on-defect=high
|
||||
|
||||
@@ -28,8 +28,6 @@
|
||||
"flash_size": "8MB",
|
||||
"maximum_ram_size": 327680,
|
||||
"maximum_size": 8388608,
|
||||
"use_1200bps_touch": true,
|
||||
"wait_for_upload_port": true,
|
||||
"require_upload_port": true,
|
||||
"speed": 921600
|
||||
},
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"ldscript": "esp32s3_out.ld"
|
||||
"ldscript": "esp32s3_out.ld",
|
||||
"memory_type": "qio_opi"
|
||||
},
|
||||
"core": "esp32",
|
||||
"extra_flags": [
|
||||
@@ -13,7 +14,7 @@
|
||||
],
|
||||
"f_cpu": "240000000L",
|
||||
"f_flash": "80000000L",
|
||||
"flash_mode": "dio",
|
||||
"flash_mode": "qio",
|
||||
"hwids": [["0x303A", "0x1001"]],
|
||||
"mcu": "esp32s3",
|
||||
"variant": "t-deck"
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"ldscript": "esp32s3_out.ld"
|
||||
"ldscript": "esp32s3_out.ld",
|
||||
"memory_type": "qio_opi"
|
||||
},
|
||||
"core": "esp32",
|
||||
"extra_flags": [
|
||||
@@ -14,8 +15,8 @@
|
||||
],
|
||||
"f_cpu": "240000000L",
|
||||
"f_flash": "80000000L",
|
||||
"flash_mode": "dio",
|
||||
"hwids": [["0X303A", "0x1001"]],
|
||||
"flash_mode": "qio",
|
||||
"hwids": [["0x303A", "0x1001"]],
|
||||
"mcu": "esp32s3",
|
||||
"variant": "t-watch-s3"
|
||||
},
|
||||
@@ -31,8 +32,9 @@
|
||||
"maximum_size": 8388608,
|
||||
"require_upload_port": true,
|
||||
"use_1200bps_touch": true,
|
||||
"wait_for_upload_port": true
|
||||
"wait_for_upload_port": true,
|
||||
"speed": 921600
|
||||
},
|
||||
"url": "http://www.lilygo.cn/",
|
||||
"url": "https://www.lilygo.cc/en-pl/products/t-watch-s3",
|
||||
"vendor": "LilyGo"
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ check_flags =
|
||||
framework = arduino
|
||||
lib_deps =
|
||||
${env.lib_deps}
|
||||
mprograms/QMC5883LCompass@^1.1.1
|
||||
mprograms/QMC5883LCompass@^1.2.0
|
||||
end2endzone/NonBlockingRTTTL@^1.3.0
|
||||
https://github.com/meshtastic/SparkFun_ATECCX08a_Arduino_Library.git#5cf62b36c6f30bc72a07bdb2c11fc9a22d1e31da
|
||||
|
||||
@@ -107,8 +107,8 @@ lib_deps =
|
||||
[environmental_base]
|
||||
lib_deps =
|
||||
adafruit/Adafruit BusIO@^1.11.4
|
||||
adafruit/Adafruit Unified Sensor@^1.1.9
|
||||
adafruit/Adafruit BMP280 Library@^2.6.6
|
||||
adafruit/Adafruit Unified Sensor@^1.1.11
|
||||
adafruit/Adafruit BMP280 Library@^2.6.8
|
||||
adafruit/Adafruit BME280 Library@^2.2.2
|
||||
https://github.com/boschsensortec/Bosch-BSEC2-Library#v1.5.2400
|
||||
boschsensortec/BME68x Sensor Library@^1.1.40407
|
||||
@@ -117,7 +117,7 @@ lib_deps =
|
||||
adafruit/Adafruit INA219@^1.2.0
|
||||
adafruit/Adafruit SHTC3 Library@^1.0.0
|
||||
adafruit/Adafruit LPS2X@^2.0.4
|
||||
adafruit/Adafruit SHT31 Library@^2.2.0
|
||||
adafruit/Adafruit SHT31 Library@^2.2.2
|
||||
adafruit/Adafruit PM25 AQI Sensor@^1.0.6
|
||||
adafruit/Adafruit MPU6050@^2.2.4
|
||||
adafruit/Adafruit LIS3DH@^1.2.4
|
||||
|
||||
Submodule protobufs updated: 6f88374ec6...fb28d59352
75
src/AmbientLightingThread.h
Normal file
75
src/AmbientLightingThread.h
Normal file
@@ -0,0 +1,75 @@
|
||||
#include "configuration.h"
|
||||
|
||||
#ifdef HAS_NCP5623
|
||||
#include <graphics/RAKled.h>
|
||||
NCP5623 rgb;
|
||||
#endif
|
||||
|
||||
namespace concurrency
|
||||
{
|
||||
class AmbientLightingThread : public concurrency::OSThread
|
||||
{
|
||||
public:
|
||||
AmbientLightingThread(ScanI2C::DeviceType type) : OSThread("AmbientLightingThread")
|
||||
{
|
||||
// Uncomment to test module
|
||||
// moduleConfig.ambient_lighting.led_state = true;
|
||||
// moduleConfig.ambient_lighting.current = 10;
|
||||
// // Default to a color based on our node number
|
||||
// moduleConfig.ambient_lighting.red = (myNodeInfo.my_node_num & 0xFF0000) >> 16;
|
||||
// moduleConfig.ambient_lighting.green = (myNodeInfo.my_node_num & 0x00FF00) >> 8;
|
||||
// moduleConfig.ambient_lighting.blue = myNodeInfo.my_node_num & 0x0000FF;
|
||||
|
||||
#ifdef HAS_NCP5623
|
||||
_type = type;
|
||||
if (_type == ScanI2C::DeviceType::NONE) {
|
||||
LOG_DEBUG("AmbientLightingThread disabling due to no RGB leds found on I2C bus\n");
|
||||
disable();
|
||||
return;
|
||||
}
|
||||
if (!moduleConfig.ambient_lighting.led_state) {
|
||||
LOG_DEBUG("AmbientLightingThread disabling due to moduleConfig.ambient_lighting.led_state OFF\n");
|
||||
disable();
|
||||
return;
|
||||
}
|
||||
LOG_DEBUG("AmbientLightingThread initializing\n");
|
||||
if (_type == ScanI2C::NCP5623) {
|
||||
rgb.begin();
|
||||
setLighting();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
protected:
|
||||
int32_t runOnce() override
|
||||
{
|
||||
#ifdef HAS_NCP5623
|
||||
if (_type == ScanI2C::NCP5623 && moduleConfig.ambient_lighting.led_state) {
|
||||
setLighting();
|
||||
return 30000; // 30 seconds to reset from any animations that may have been running from Ext. Notification
|
||||
} else {
|
||||
return disable();
|
||||
}
|
||||
#else
|
||||
return disable();
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
ScanI2C::DeviceType _type = ScanI2C::DeviceType::NONE;
|
||||
|
||||
void setLighting()
|
||||
{
|
||||
#ifdef HAS_NCP5623
|
||||
rgb.setCurrent(moduleConfig.ambient_lighting.current);
|
||||
rgb.setRed(moduleConfig.ambient_lighting.red);
|
||||
rgb.setGreen(moduleConfig.ambient_lighting.green);
|
||||
rgb.setBlue(moduleConfig.ambient_lighting.blue);
|
||||
LOG_DEBUG("Initializing Ambient lighting w/ current=%d, red=%d, green=%d, blue=%d\n",
|
||||
moduleConfig.ambient_lighting.current, moduleConfig.ambient_lighting.red, moduleConfig.ambient_lighting.green,
|
||||
moduleConfig.ambient_lighting.blue);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace concurrency
|
||||
@@ -164,15 +164,17 @@ class ButtonThread : public concurrency::OSThread
|
||||
|
||||
static void userButtonMultiPressed()
|
||||
{
|
||||
#if defined(GPS_POWER_TOGGLE)
|
||||
if (config.position.gps_enabled) {
|
||||
LOG_DEBUG("Flag set to false for gps power\n");
|
||||
} else {
|
||||
LOG_DEBUG("Flag set to true to restore power\n");
|
||||
if (!config.device.disable_triple_click && (gps != nullptr)) {
|
||||
config.position.gps_enabled = !(config.position.gps_enabled);
|
||||
if (config.position.gps_enabled) {
|
||||
LOG_DEBUG("Flag set to true to restore power\n");
|
||||
gps->enable();
|
||||
|
||||
} else {
|
||||
LOG_DEBUG("Flag set to false for gps power\n");
|
||||
gps->disable();
|
||||
}
|
||||
}
|
||||
config.position.gps_enabled = !(config.position.gps_enabled);
|
||||
doGPSpowersave(config.position.gps_enabled);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void userButtonPressedLongStart()
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
/**
|
||||
* @file FSCommon.cpp
|
||||
* @brief This file contains functions for common filesystem operations such as copying, renaming, listing and deleting files and
|
||||
* directories.
|
||||
*
|
||||
* The functions in this file are used to perform common filesystem operations such as copying, renaming, listing and deleting
|
||||
* files and directories. These functions are used in the Meshtastic-device project to manage files and directories on the
|
||||
* device's filesystem.
|
||||
*
|
||||
*/
|
||||
#include "FSCommon.h"
|
||||
#include "configuration.h"
|
||||
|
||||
@@ -14,6 +24,13 @@ SPIClass SPI1(HSPI);
|
||||
|
||||
#endif // HAS_SDCARD
|
||||
|
||||
/**
|
||||
* @brief Copies a file from one location to another.
|
||||
*
|
||||
* @param from The path of the source file.
|
||||
* @param to The path of the destination file.
|
||||
* @return true if the file was successfully copied, false otherwise.
|
||||
*/
|
||||
bool copyFile(const char *from, const char *to)
|
||||
{
|
||||
#ifdef FSCom
|
||||
@@ -43,6 +60,14 @@ bool copyFile(const char *from, const char *to)
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Renames a file from pathFrom to pathTo.
|
||||
*
|
||||
* @param pathFrom The original path of the file.
|
||||
* @param pathTo The new path of the file.
|
||||
*
|
||||
* @return True if the file was successfully renamed, false otherwise.
|
||||
*/
|
||||
bool renameFile(const char *pathFrom, const char *pathTo)
|
||||
{
|
||||
#ifdef FSCom
|
||||
@@ -59,6 +84,13 @@ bool renameFile(const char *pathFrom, const char *pathTo)
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists the contents of a directory.
|
||||
*
|
||||
* @param dirname The name of the directory to list.
|
||||
* @param levels The number of levels of subdirectories to list.
|
||||
* @param del Whether or not to delete the contents of the directory after listing.
|
||||
*/
|
||||
void listDir(const char *dirname, uint8_t levels, bool del = false)
|
||||
{
|
||||
#ifdef FSCom
|
||||
@@ -154,6 +186,13 @@ void listDir(const char *dirname, uint8_t levels, bool del = false)
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Removes a directory and all its contents.
|
||||
*
|
||||
* This function recursively removes a directory and all its contents, including subdirectories and files.
|
||||
*
|
||||
* @param dirname The name of the directory to remove.
|
||||
*/
|
||||
void rmDir(const char *dirname)
|
||||
{
|
||||
#ifdef FSCom
|
||||
@@ -182,6 +221,9 @@ void fsInit()
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the SD card and mounts the file system.
|
||||
*/
|
||||
void setupSDCard()
|
||||
{
|
||||
#ifdef HAS_SDCARD
|
||||
@@ -212,4 +254,4 @@ void setupSDCard()
|
||||
LOG_DEBUG("Total space: %llu MB\n", SD.totalBytes() / (1024 * 1024));
|
||||
LOG_DEBUG("Used space: %llu MB\n", SD.usedBytes() / (1024 * 1024));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,16 @@ static void IRAM_ATTR onTimer()
|
||||
(*tCallback)(tParam1, tParam2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedules a hardware callback function to be executed after a specified delay.
|
||||
*
|
||||
* @param callback The function to be executed.
|
||||
* @param param1 The first parameter to be passed to the function.
|
||||
* @param param2 The second parameter to be passed to the function.
|
||||
* @param delayMsec The delay time in milliseconds before the function is executed.
|
||||
*
|
||||
* @return True if the function was successfully scheduled, false otherwise.
|
||||
*/
|
||||
bool scheduleHWCallback(PendableFunction callback, void *param1, uint32_t param2, uint32_t delayMsec)
|
||||
{
|
||||
if (!timer) {
|
||||
|
||||
@@ -1,11 +1,23 @@
|
||||
/**
|
||||
* @file Power.cpp
|
||||
* @brief This file contains the implementation of the Power class, which is responsible for managing power-related functionality
|
||||
* of the device. It includes battery level sensing, power management unit (PMU) control, and power state machine management. The
|
||||
* Power class is used by the main device class to manage power-related functionality.
|
||||
*
|
||||
* The file also includes implementations of various battery level sensors, such as the AnalogBatteryLevel class, which assumes
|
||||
* the battery voltage is attached via a voltage-divider to an analog input.
|
||||
*
|
||||
* This file is part of the Meshtastic project.
|
||||
* For more information, see: https://meshtastic.org/
|
||||
*/
|
||||
#include "power.h"
|
||||
#include "NodeDB.h"
|
||||
#include "PowerFSM.h"
|
||||
#include "buzz/buzz.h"
|
||||
#include "configuration.h"
|
||||
#include "main.h"
|
||||
#include "meshUtils.h"
|
||||
#include "sleep.h"
|
||||
#include "utils.h"
|
||||
|
||||
#ifdef DEBUG_HEAP_MQTT
|
||||
#include "mqtt/MQTT.h"
|
||||
@@ -209,10 +221,7 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
||||
/**
|
||||
* return true if there is a battery installed in this unit
|
||||
*/
|
||||
virtual bool isBatteryConnect() override
|
||||
{
|
||||
return getBatteryPercent() != -1;
|
||||
}
|
||||
virtual bool isBatteryConnect() override { return getBatteryPercent() != -1; }
|
||||
|
||||
/// If we see a battery voltage higher than physics allows - assume charger is pumping
|
||||
/// in power
|
||||
@@ -233,10 +242,7 @@ 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 { return isBatteryConnect() && isVbusIn(); }
|
||||
|
||||
private:
|
||||
/// If we see a battery voltage higher than physics allows - assume charger is pumping
|
||||
@@ -366,6 +372,11 @@ bool Power::analogInit()
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the Power class.
|
||||
*
|
||||
* @return true if the setup was successful, false otherwise.
|
||||
*/
|
||||
bool Power::setup()
|
||||
{
|
||||
bool found = axpChipInit();
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
/**
|
||||
* @file PowerFSM.cpp
|
||||
* @brief Implements the finite state machine for power management.
|
||||
*
|
||||
* This file contains the implementation of the finite state machine (FSM) for power management.
|
||||
* The FSM controls the power states of the device, including SDS (shallow deep sleep), LS (light sleep),
|
||||
* NB (normal mode), and POWER (powered mode). The FSM also handles transitions between states and
|
||||
* actions to be taken upon entering or exiting each state.
|
||||
*/
|
||||
#include "PowerFSM.h"
|
||||
#include "GPS.h"
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
#include "configuration.h"
|
||||
@@ -128,16 +136,16 @@ static void lsIdle()
|
||||
static void lsExit()
|
||||
{
|
||||
LOG_INFO("Exit state: LS\n");
|
||||
// setGPSPower(true); // restore GPS power
|
||||
if (gps)
|
||||
gps->forceWake(true);
|
||||
}
|
||||
|
||||
static void nbEnter()
|
||||
{
|
||||
LOG_DEBUG("Enter state: NB\n");
|
||||
screen->setOn(false);
|
||||
#ifdef ARCH_ESP32
|
||||
// Only ESP32 should turn off bluetooth
|
||||
setBluetoothEnable(false);
|
||||
#endif
|
||||
|
||||
// FIXME - check if we already have packets for phone and immediately trigger EVENT_PACKETS_FOR_PHONE
|
||||
}
|
||||
@@ -146,6 +154,9 @@ static void darkEnter()
|
||||
{
|
||||
setBluetoothEnable(true);
|
||||
screen->setOn(false);
|
||||
#ifdef KB_POWERON
|
||||
digitalWrite(KB_POWERON, LOW);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void serialEnter()
|
||||
@@ -158,12 +169,14 @@ static void serialEnter()
|
||||
|
||||
static void serialExit()
|
||||
{
|
||||
// Turn bluetooth back on when we leave serial stream API
|
||||
setBluetoothEnable(true);
|
||||
screen->print("Serial disconnected\n");
|
||||
}
|
||||
|
||||
static void powerEnter()
|
||||
{
|
||||
LOG_DEBUG("Enter state: POWER\n");
|
||||
// LOG_DEBUG("Enter state: POWER\n");
|
||||
if (!isPowered()) {
|
||||
// If we got here, we are in the wrong state - we should be in powered, let that state ahndle things
|
||||
LOG_INFO("Loss of power in Powered\n");
|
||||
@@ -171,6 +184,9 @@ static void powerEnter()
|
||||
} else {
|
||||
screen->setOn(true);
|
||||
setBluetoothEnable(true);
|
||||
#ifdef KB_POWERON
|
||||
digitalWrite(KB_POWERON, HIGH);
|
||||
#endif
|
||||
// within enter() the function getState() returns the state we came from
|
||||
if (strcmp(powerFSM.getState()->name, "BOOT") != 0 && strcmp(powerFSM.getState()->name, "POWER") != 0 &&
|
||||
strcmp(powerFSM.getState()->name, "DARK") != 0) {
|
||||
@@ -201,6 +217,9 @@ static void onEnter()
|
||||
LOG_DEBUG("Enter state: ON\n");
|
||||
screen->setOn(true);
|
||||
setBluetoothEnable(true);
|
||||
#ifdef KB_POWERON
|
||||
digitalWrite(KB_POWERON, HIGH);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void onIdle()
|
||||
@@ -242,7 +261,11 @@ void PowerFSM_setup()
|
||||
|
||||
// wake timer expired or a packet arrived
|
||||
// if we are a router node, we go to NB (no need for bluetooth) otherwise we go to DARK (so we can send message to phone)
|
||||
#ifdef ARCH_ESP32
|
||||
powerFSM.add_transition(&stateLS, isRouter ? &stateNB : &stateDARK, EVENT_WAKE_TIMER, NULL, "Wake timer");
|
||||
#else // Don't go into a no-bluetooth state on low power platforms
|
||||
powerFSM.add_transition(&stateLS, &stateDARK, EVENT_WAKE_TIMER, NULL, "Wake timer");
|
||||
#endif
|
||||
|
||||
// We need this transition, because we might not transition if we were waiting to enter light-sleep, because when we wake from
|
||||
// light sleep we _always_ transition to NB or dark and
|
||||
@@ -279,7 +302,8 @@ void PowerFSM_setup()
|
||||
powerFSM.add_transition(&stateLS, &stateON, EVENT_INPUT, NULL, "Input Device");
|
||||
powerFSM.add_transition(&stateNB, &stateON, EVENT_INPUT, NULL, "Input Device");
|
||||
powerFSM.add_transition(&stateDARK, &stateON, EVENT_INPUT, NULL, "Input Device");
|
||||
powerFSM.add_transition(&stateON, &stateON, EVENT_INPUT, NULL, "Input Device"); // restarts the sleep timer
|
||||
powerFSM.add_transition(&stateON, &stateON, EVENT_INPUT, NULL, "Input Device"); // restarts the sleep timer
|
||||
powerFSM.add_transition(&statePOWER, &statePOWER, EVENT_INPUT, NULL, "Input Device"); // restarts the sleep timer
|
||||
|
||||
powerFSM.add_transition(&stateDARK, &stateON, EVENT_BLUETOOTH_PAIR, NULL, "Bluetooth pairing");
|
||||
powerFSM.add_transition(&stateON, &stateON, EVENT_BLUETOOTH_PAIR, NULL, "Bluetooth pairing");
|
||||
@@ -346,10 +370,6 @@ void PowerFSM_setup()
|
||||
getConfiguredOrDefaultMs(config.power.wait_bluetooth_secs, default_wait_bluetooth_secs),
|
||||
NULL, "Bluetooth timeout");
|
||||
}
|
||||
|
||||
if (config.power.sds_secs != UINT32_MAX)
|
||||
powerFSM.add_timed_transition(lowPowerState, &stateSDS, getConfiguredOrDefaultMs(config.power.sds_secs), NULL,
|
||||
"mesh timeout");
|
||||
#endif
|
||||
|
||||
powerFSM.run_machine(); // run one iteration of the state machine, so we run our on enter tasks for the initial DARK state
|
||||
|
||||
@@ -21,7 +21,7 @@ class PowerFSMThread : public OSThread
|
||||
|
||||
/// If we are in power state we force the CPU to wake every 10ms to check for serial characters (we don't yet wake
|
||||
/// cpu for serial rx - FIXME)
|
||||
auto state = powerFSM.getState();
|
||||
const auto state = powerFSM.getState();
|
||||
canSleep = (state != &statePOWER) && (state != &stateSERIAL);
|
||||
|
||||
if (powerStatus->getHasUSB()) {
|
||||
|
||||
@@ -18,6 +18,12 @@ NoopPrint noopPrint;
|
||||
#if HAS_WIFI || HAS_ETHERNET
|
||||
extern Syslog syslog;
|
||||
#endif
|
||||
void RedirectablePrint::rpInit()
|
||||
{
|
||||
#ifdef HAS_FREE_RTOS
|
||||
inDebugPrint = xSemaphoreCreateMutexStatic(&this->_MutexStorageSpace);
|
||||
#endif
|
||||
}
|
||||
|
||||
void RedirectablePrint::setDestination(Print *_dest)
|
||||
{
|
||||
@@ -66,9 +72,12 @@ size_t RedirectablePrint::log(const char *logLevel, const char *format, ...)
|
||||
return 0;
|
||||
}
|
||||
size_t r = 0;
|
||||
|
||||
#ifdef HAS_FREE_RTOS
|
||||
if (inDebugPrint != nullptr && xSemaphoreTake(inDebugPrint, portMAX_DELAY) == pdTRUE) {
|
||||
#else
|
||||
if (!inDebugPrint) {
|
||||
inDebugPrint = true;
|
||||
#endif
|
||||
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
@@ -141,7 +150,11 @@ size_t RedirectablePrint::log(const char *logLevel, const char *format, ...)
|
||||
va_end(arg);
|
||||
|
||||
isContinuationMessage = !hasNewline;
|
||||
#ifdef HAS_FREE_RTOS
|
||||
xSemaphoreGive(inDebugPrint);
|
||||
#else
|
||||
inDebugPrint = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
return r;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "../freertosinc.h"
|
||||
#include <Print.h>
|
||||
#include <stdarg.h>
|
||||
#include <string>
|
||||
@@ -16,14 +17,19 @@ class RedirectablePrint : public Print
|
||||
/// Used to allow multiple logDebug messages to appear on a single log line
|
||||
bool isContinuationMessage = false;
|
||||
|
||||
#ifdef HAS_FREE_RTOS
|
||||
SemaphoreHandle_t inDebugPrint = nullptr;
|
||||
StaticSemaphore_t _MutexStorageSpace;
|
||||
#else
|
||||
volatile bool inDebugPrint = false;
|
||||
|
||||
#endif
|
||||
public:
|
||||
explicit RedirectablePrint(Print *_dest) : dest(_dest) {}
|
||||
|
||||
/**
|
||||
* Set a new destination
|
||||
*/
|
||||
void rpInit();
|
||||
void setDestination(Print *dest);
|
||||
|
||||
virtual size_t write(uint8_t c);
|
||||
@@ -54,4 +60,4 @@ class NoopPrint : public Print
|
||||
/**
|
||||
* A printer that doesn't go anywhere
|
||||
*/
|
||||
extern NoopPrint noopPrint;
|
||||
extern NoopPrint noopPrint;
|
||||
@@ -12,6 +12,7 @@ SerialConsole *console;
|
||||
void consoleInit()
|
||||
{
|
||||
new SerialConsole(); // Must be dynamically allocated because we are now inheriting from thread
|
||||
DEBUG_PORT.rpInit(); // Simply sets up semaphore
|
||||
}
|
||||
|
||||
void consolePrintf(const char *format, ...)
|
||||
|
||||
@@ -53,7 +53,7 @@ class OSThread : public Thread
|
||||
|
||||
static void setup();
|
||||
|
||||
int32_t disable();
|
||||
virtual int32_t disable();
|
||||
|
||||
/**
|
||||
* Wait a specified number msecs starting from the current time (rather than the last time we were run)
|
||||
@@ -87,4 +87,4 @@ extern bool hasBeenSetup;
|
||||
|
||||
void assertIsSetup();
|
||||
|
||||
} // namespace concurrency
|
||||
} // namespace concurrency
|
||||
@@ -101,6 +101,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
// I2C Keyboards (M5Stack, RAK14004, T-Deck)
|
||||
#define CARDKB_ADDR 0x5F
|
||||
#define TDECK_KB_ADDR 0x55
|
||||
#define BBQ10_KB_ADDR 0x1F
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// SENSOR
|
||||
@@ -144,9 +145,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#define GPS_BAUDRATE 9600
|
||||
|
||||
#ifndef GPS_THREAD_INTERVAL
|
||||
#define GPS_THREAD_INTERVAL 100
|
||||
#define GPS_THREAD_INTERVAL 200
|
||||
#endif
|
||||
|
||||
// convert 24-bit color to 16-bit (56K)
|
||||
#define COLOR565(r, g, b) (((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3))
|
||||
|
||||
/* Step #1: offer chance for variant-specific defines */
|
||||
#include "variant.h"
|
||||
|
||||
|
||||
@@ -30,8 +30,8 @@ ScanI2C::FoundDevice ScanI2C::firstRTC() const
|
||||
|
||||
ScanI2C::FoundDevice ScanI2C::firstKeyboard() const
|
||||
{
|
||||
ScanI2C::DeviceType types[] = {CARDKB, TDECKKB, RAK14004};
|
||||
return firstOfOrNONE(3, types);
|
||||
ScanI2C::DeviceType types[] = {CARDKB, TDECKKB, BBQ10KB, RAK14004};
|
||||
return firstOfOrNONE(4, types);
|
||||
}
|
||||
|
||||
ScanI2C::FoundDevice ScanI2C::firstAccelerometer() const
|
||||
|
||||
@@ -17,6 +17,7 @@ class ScanI2C
|
||||
RTC_PCF8563,
|
||||
CARDKB,
|
||||
TDECKKB,
|
||||
BBQ10KB,
|
||||
RAK14004,
|
||||
PMU_AXP192_AXP2101,
|
||||
BME_680,
|
||||
|
||||
@@ -213,6 +213,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port)
|
||||
break;
|
||||
|
||||
SCAN_SIMPLE_CASE(TDECK_KB_ADDR, TDECKKB, "T-Deck keyboard found\n");
|
||||
SCAN_SIMPLE_CASE(BBQ10_KB_ADDR, BBQ10KB, "BB Q10 keyboard found\n");
|
||||
SCAN_SIMPLE_CASE(ST7567_ADDRESS, SCREEN_ST7567, "st7567 display found\n");
|
||||
#ifdef HAS_NCP5623
|
||||
SCAN_SIMPLE_CASE(NCP5623_ADDR, NCP5623, "NCP5623 RGB LED found\n");
|
||||
|
||||
1286
src/gps/GPS.cpp
1286
src/gps/GPS.cpp
File diff suppressed because it is too large
Load Diff
202
src/gps/GPS.h
202
src/gps/GPS.h
@@ -2,7 +2,16 @@
|
||||
|
||||
#include "GPSStatus.h"
|
||||
#include "Observer.h"
|
||||
#include "TinyGPS++.h"
|
||||
#include "concurrency/OSThread.h"
|
||||
#include "input/RotaryEncoderInterruptImpl1.h"
|
||||
#include "input/UpDownInterruptImpl1.h"
|
||||
#include "modules/PositionModule.h"
|
||||
|
||||
// Allow defining the polarity of the ENABLE output. default is active high
|
||||
#ifndef GPS_EN_ACTIVE
|
||||
#define GPS_EN_ACTIVE 1
|
||||
#endif
|
||||
|
||||
struct uBloxGnssModelInfo {
|
||||
char swVersion[30];
|
||||
@@ -18,6 +27,13 @@ typedef enum {
|
||||
GNSS_MODEL_UNKNOWN,
|
||||
} GnssModel_t;
|
||||
|
||||
typedef enum {
|
||||
GNSS_RESPONSE_NONE,
|
||||
GNSS_RESPONSE_NAK,
|
||||
GNSS_RESPONSE_FRAME_ERRORS,
|
||||
GNSS_RESPONSE_OK,
|
||||
} GPS_RESPONSE;
|
||||
|
||||
// Generate a string representation of DOP
|
||||
const char *getDOPString(uint32_t dop);
|
||||
|
||||
@@ -28,8 +44,29 @@ const char *getDOPString(uint32_t dop);
|
||||
*/
|
||||
class GPS : private concurrency::OSThread
|
||||
{
|
||||
TinyGPSPlus reader;
|
||||
uint8_t fixQual = 0; // fix quality from GPGGA
|
||||
uint32_t lastChecksumFailCount = 0;
|
||||
|
||||
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
|
||||
// (20210908) TinyGps++ can only read the GPGSA "FIX TYPE" field
|
||||
// via optional feature "custom fields", currently disabled (bug #525)
|
||||
TinyGPSCustom gsafixtype; // custom extract fix type from GPGSA
|
||||
TinyGPSCustom gsapdop; // custom extract PDOP from GPGSA
|
||||
uint8_t fixType = 0; // fix type from GPGSA
|
||||
#endif
|
||||
private:
|
||||
uint32_t lastWakeStartMsec = 0, lastSleepStartMsec = 0, lastWhileActiveMsec = 0;
|
||||
uint32_t lastWakeStartMsec = 0, lastSleepStartMsec = 0;
|
||||
const int serialSpeeds[6] = {9600, 4800, 38400, 57600, 115200, 9600};
|
||||
|
||||
uint32_t rx_gpio = 0;
|
||||
uint32_t tx_gpio = 0;
|
||||
uint32_t en_gpio = 0;
|
||||
int32_t averageLockTime = 0;
|
||||
uint32_t GPSCycles = 0;
|
||||
|
||||
int speedSelect = 0;
|
||||
int probeTries = 2;
|
||||
|
||||
/**
|
||||
* hasValidLocation - indicates that the position variables contain a complete
|
||||
@@ -39,15 +76,17 @@ class GPS : private concurrency::OSThread
|
||||
|
||||
bool isAwake = false; // true if we want a location right now
|
||||
|
||||
bool wakeAllowed = true; // false if gps must be forced to sleep regardless of what time it is
|
||||
bool isInPowersave = false;
|
||||
|
||||
bool shouldPublish = false; // If we've changed GPS state, this will force a publish the next loop()
|
||||
|
||||
bool hasGPS = false; // Do we have a GPS we are talking to
|
||||
|
||||
bool GPSInitFinished = false; // Init thread finished?
|
||||
bool GPSInitStarted = false; // Init thread finished?
|
||||
|
||||
uint8_t numSatellites = 0;
|
||||
|
||||
CallbackObserver<GPS, void *> notifySleepObserver = CallbackObserver<GPS, void *>(this, &GPS::prepareSleep);
|
||||
CallbackObserver<GPS, void *> notifyDeepSleepObserver = CallbackObserver<GPS, void *>(this, &GPS::prepareDeepSleep);
|
||||
CallbackObserver<GPS, void *> notifyGPSSleepObserver = CallbackObserver<GPS, void *>(this, &GPS::prepareDeepSleep);
|
||||
|
||||
@@ -55,6 +94,24 @@ class GPS : private concurrency::OSThread
|
||||
/** If !NULL we will use this serial port to construct our GPS */
|
||||
static HardwareSerial *_serial_gps;
|
||||
|
||||
static const uint8_t _message_PMREQ[];
|
||||
static const uint8_t _message_CFG_RXM_PSM[];
|
||||
static const uint8_t _message_CFG_RXM_ECO[];
|
||||
static const uint8_t _message_CFG_PM2[];
|
||||
static const uint8_t _message_GNSS_7[];
|
||||
static const uint8_t _message_GNSS[];
|
||||
static const uint8_t _message_JAM[];
|
||||
static const uint8_t _message_NAVX5[];
|
||||
static const uint8_t _message_1HZ[];
|
||||
static const uint8_t _message_GGL[];
|
||||
static const uint8_t _message_GSA[];
|
||||
static const uint8_t _message_GSV[];
|
||||
static const uint8_t _message_VTG[];
|
||||
static const uint8_t _message_RMC[];
|
||||
static const uint8_t _message_GGA[];
|
||||
static const uint8_t _message_PMS[];
|
||||
static const uint8_t _message_SAVE[];
|
||||
|
||||
meshtastic_Position p = meshtastic_Position_init_default;
|
||||
|
||||
GPS() : concurrency::OSThread("GPS") {}
|
||||
@@ -69,6 +126,14 @@ class GPS : private concurrency::OSThread
|
||||
*/
|
||||
virtual bool setup();
|
||||
|
||||
// re-enable the thread
|
||||
void enable();
|
||||
|
||||
// Disable the thread
|
||||
int32_t disable() override;
|
||||
|
||||
void setGPSPower(bool on, bool standbyOnly);
|
||||
|
||||
/// Returns true if we have acquired GPS lock.
|
||||
virtual bool hasLock();
|
||||
|
||||
@@ -80,68 +145,18 @@ class GPS : private concurrency::OSThread
|
||||
|
||||
bool isPowerSaving() const { return !config.position.gps_enabled; }
|
||||
|
||||
/**
|
||||
* Restart our lock attempt - try to get and broadcast a GPS reading ASAP
|
||||
* called after the CPU wakes from light-sleep state
|
||||
*
|
||||
* Or set to false, to disallow any sort of waking
|
||||
* */
|
||||
void forceWake(bool on);
|
||||
// Empty the input buffer as quickly as possible
|
||||
void clearBuffer();
|
||||
|
||||
// Some GPS modules (ublock) require factory reset
|
||||
virtual bool factoryReset() { return true; }
|
||||
// Create a ublox packet for editing in memory
|
||||
uint8_t makeUBXPacket(uint8_t class_id, uint8_t msg_id, uint8_t payload_size, const uint8_t *msg);
|
||||
|
||||
protected:
|
||||
/// Do gps chipset specific init, return true for success
|
||||
virtual bool setupGPS();
|
||||
// scratch space for creating ublox packets
|
||||
uint8_t UBXscratch[250] = {0};
|
||||
|
||||
/// If possible force the GPS into sleep/low power mode
|
||||
virtual void sleep();
|
||||
|
||||
/// wake the GPS into normal operation mode
|
||||
virtual void wake();
|
||||
|
||||
/** Subclasses should look for serial rx characters here and feed it to their GPS parser
|
||||
*
|
||||
* Return true if we received a valid message from the GPS
|
||||
*/
|
||||
virtual bool whileIdle() = 0;
|
||||
|
||||
/** Idle processing while GPS is looking for lock, called once per secondish */
|
||||
virtual void whileActive() {}
|
||||
|
||||
/**
|
||||
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
|
||||
* Override this method to check for new locations
|
||||
*
|
||||
* @return true if we've acquired a time
|
||||
*/
|
||||
virtual bool lookForTime() = 0;
|
||||
|
||||
/**
|
||||
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
|
||||
* Override this method to check for new locations
|
||||
*
|
||||
* @return true if we've acquired a new location
|
||||
*/
|
||||
virtual bool lookForLocation() = 0;
|
||||
|
||||
/// Record that we have a GPS
|
||||
void setConnected();
|
||||
|
||||
void setNumSatellites(uint8_t n);
|
||||
|
||||
private:
|
||||
/// Prepare the GPS for the cpu entering deep or light sleep, expect to be gone for at least 100s of msecs
|
||||
/// always returns 0 to indicate okay to sleep
|
||||
int prepareSleep(void *unused);
|
||||
|
||||
/// Prepare the GPS for the cpu entering deep sleep, expect to be gone for at least 100s of msecs
|
||||
/// always returns 0 to indicate okay to sleep
|
||||
int prepareDeepSleep(void *unused);
|
||||
|
||||
// Calculate checksum
|
||||
void UBXChecksum(byte *message, size_t length);
|
||||
int getACK(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t requestedID, uint32_t waitMillis);
|
||||
GPS_RESPONSE getACK(uint8_t c, uint8_t i, uint32_t waitMillis);
|
||||
GPS_RESPONSE getACK(const char *message, uint32_t waitMillis);
|
||||
|
||||
/**
|
||||
* Switch the GPS into a mode where we are actively looking for a lock, or alternatively switch GPS into a low power mode
|
||||
@@ -149,6 +164,59 @@ class GPS : private concurrency::OSThread
|
||||
* calls sleep/wake
|
||||
*/
|
||||
void setAwake(bool on);
|
||||
virtual bool factoryReset();
|
||||
|
||||
// Creates an instance of the GPS class.
|
||||
// Returns the new instance or null if the GPS is not present.
|
||||
static GPS *createGps();
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
|
||||
* Override this method to check for new locations
|
||||
*
|
||||
* @return true if we've acquired a time
|
||||
*/
|
||||
|
||||
/**
|
||||
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
|
||||
* Override this method to check for new locations
|
||||
*
|
||||
* @return true if we've acquired a new location
|
||||
*/
|
||||
|
||||
/// Record that we have a GPS
|
||||
void setConnected();
|
||||
|
||||
/** Subclasses should look for serial rx characters here and feed it to their GPS parser
|
||||
*
|
||||
* Return true if we received a valid message from the GPS
|
||||
*/
|
||||
virtual bool whileIdle();
|
||||
|
||||
/**
|
||||
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
|
||||
* Override this method to check for new locations
|
||||
*
|
||||
* @return true if we've acquired a time
|
||||
*/
|
||||
virtual bool lookForTime();
|
||||
|
||||
/**
|
||||
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
|
||||
* Override this method to check for new locations
|
||||
*
|
||||
* @return true if we've acquired a new location
|
||||
*/
|
||||
virtual bool lookForLocation();
|
||||
|
||||
private:
|
||||
/// Prepare the GPS for the cpu entering deep sleep, expect to be gone for at least 100s of msecs
|
||||
/// always returns 0 to indicate okay to sleep
|
||||
int prepareDeepSleep(void *unused);
|
||||
|
||||
// Calculate checksum
|
||||
void UBXChecksum(uint8_t *message, size_t length);
|
||||
|
||||
/** Get how long we should stay looking for each aquisition
|
||||
*/
|
||||
@@ -158,8 +226,6 @@ class GPS : private concurrency::OSThread
|
||||
*/
|
||||
uint32_t getSleepTime() const;
|
||||
|
||||
bool getACK(uint8_t c, uint8_t i);
|
||||
|
||||
/**
|
||||
* Tell users we have new GPS readings
|
||||
*/
|
||||
@@ -169,9 +235,7 @@ class GPS : private concurrency::OSThread
|
||||
|
||||
// Get GNSS model
|
||||
String getNMEA();
|
||||
GnssModel_t probe();
|
||||
|
||||
int getAck(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t requestedID);
|
||||
GnssModel_t probe(int serialSpeed);
|
||||
|
||||
// delay counter to allow more sats before fixed position stops GPS thread
|
||||
uint8_t fixeddelayCtr = 0;
|
||||
@@ -180,8 +244,4 @@ class GPS : private concurrency::OSThread
|
||||
GnssModel_t gnssModel = GNSS_MODEL_UNKNOWN;
|
||||
};
|
||||
|
||||
// Creates an instance of the GPS class.
|
||||
// Returns the new instance or null if the GPS is not present.
|
||||
GPS *createGps();
|
||||
|
||||
extern GPS *gps;
|
||||
@@ -1,255 +0,0 @@
|
||||
#include "NMEAGPS.h"
|
||||
#include "RTC.h"
|
||||
#include "configuration.h"
|
||||
|
||||
#include <TinyGPS++.h>
|
||||
|
||||
// GPS solutions older than this will be rejected - see TinyGPSDatum::age()
|
||||
#define GPS_SOL_EXPIRY_MS 5000 // in millis. give 1 second time to combine different sentences. NMEA Frequency isn't higher anyway
|
||||
#define NMEA_MSG_GXGSA "GNGSA" // GSA message (GPGSA, GNGSA etc)
|
||||
|
||||
static int32_t toDegInt(RawDegrees d)
|
||||
{
|
||||
int32_t degMult = 10000000; // 1e7
|
||||
int32_t r = d.deg * degMult + d.billionths / 100;
|
||||
if (d.negative)
|
||||
r *= -1;
|
||||
return r;
|
||||
}
|
||||
|
||||
bool NMEAGPS::factoryReset()
|
||||
{
|
||||
#ifdef PIN_GPS_REINIT
|
||||
// The L76K GNSS on the T-Echo requires the RESET pin to be pulled LOW
|
||||
digitalWrite(PIN_GPS_REINIT, 0);
|
||||
pinMode(PIN_GPS_REINIT, OUTPUT);
|
||||
delay(150); // The L76K datasheet calls for at least 100MS delay
|
||||
digitalWrite(PIN_GPS_REINIT, 1);
|
||||
#endif
|
||||
|
||||
// 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,
|
||||
0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x17, 0x2B, 0x7E};
|
||||
_serial_gps->write(_message_reset, sizeof(_message_reset));
|
||||
delay(1000);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NMEAGPS::setupGPS()
|
||||
{
|
||||
GPS::setupGPS();
|
||||
|
||||
#ifdef PIN_GPS_PPS
|
||||
// pulse per second
|
||||
// FIXME - move into shared GPS code
|
||||
pinMode(PIN_GPS_PPS, INPUT);
|
||||
#endif
|
||||
|
||||
// Currently disabled per issue #525 (TinyGPS++ crash bug)
|
||||
// when fixed upstream, can be un-disabled to enable 3D FixType and PDOP
|
||||
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
|
||||
// see NMEAGPS.h
|
||||
gsafixtype.begin(reader, NMEA_MSG_GXGSA, 2);
|
||||
gsapdop.begin(reader, NMEA_MSG_GXGSA, 15);
|
||||
LOG_DEBUG("Using " NMEA_MSG_GXGSA " for 3DFIX and PDOP\n");
|
||||
#else
|
||||
LOG_DEBUG("GxGSA NOT available\n");
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
|
||||
* Override this method to check for new locations
|
||||
*
|
||||
* @return true if we've acquired a new location
|
||||
*/
|
||||
bool NMEAGPS::lookForTime()
|
||||
{
|
||||
auto ti = reader.time;
|
||||
auto d = reader.date;
|
||||
if (ti.isValid() && d.isValid()) { // Note: we don't check for updated, because we'll only be called if needed
|
||||
/* Convert to unix time
|
||||
The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of seconds that have elapsed since January 1, 1970
|
||||
(midnight UTC/GMT), not counting leap seconds (in ISO 8601: 1970-01-01T00:00:00Z).
|
||||
*/
|
||||
struct tm t;
|
||||
t.tm_sec = ti.second();
|
||||
t.tm_min = ti.minute();
|
||||
t.tm_hour = ti.hour();
|
||||
t.tm_mday = d.day();
|
||||
t.tm_mon = d.month() - 1;
|
||||
t.tm_year = d.year() - 1900;
|
||||
t.tm_isdst = false;
|
||||
if (t.tm_mon > -1) {
|
||||
LOG_DEBUG("NMEA GPS time %02d-%02d-%02d %02d:%02d:%02d\n", d.year(), d.month(), t.tm_mday, t.tm_hour, t.tm_min,
|
||||
t.tm_sec);
|
||||
perhapsSetRTC(RTCQualityGPS, t);
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
|
||||
* Override this method to check for new locations
|
||||
*
|
||||
* @return true if we've acquired a new location
|
||||
*/
|
||||
bool NMEAGPS::lookForLocation()
|
||||
{
|
||||
// By default, TinyGPS++ does not parse GPGSA lines, which give us
|
||||
// the 2D/3D fixType (see NMEAGPS.h)
|
||||
// At a minimum, use the fixQuality indicator in GPGGA (FIXME?)
|
||||
fixQual = reader.fixQuality();
|
||||
|
||||
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
|
||||
fixType = atoi(gsafixtype.value()); // will set to zero if no data
|
||||
// LOG_DEBUG("FIX QUAL=%d, TYPE=%d\n", fixQual, fixType);
|
||||
#endif
|
||||
|
||||
// check if GPS has an acceptable lock
|
||||
if (!hasLock())
|
||||
return false;
|
||||
|
||||
#ifdef GPS_EXTRAVERBOSE
|
||||
LOG_DEBUG("AGE: LOC=%d FIX=%d DATE=%d TIME=%d\n", reader.location.age(),
|
||||
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
|
||||
gsafixtype.age(),
|
||||
#else
|
||||
0,
|
||||
#endif
|
||||
reader.date.age(), reader.time.age());
|
||||
#endif // GPS_EXTRAVERBOSE
|
||||
|
||||
// check if a complete GPS solution set is available for reading
|
||||
// tinyGPSDatum::age() also includes isValid() test
|
||||
// FIXME
|
||||
if (!((reader.location.age() < GPS_SOL_EXPIRY_MS) &&
|
||||
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
|
||||
(gsafixtype.age() < GPS_SOL_EXPIRY_MS) &&
|
||||
#endif
|
||||
(reader.time.age() < GPS_SOL_EXPIRY_MS) && (reader.date.age() < GPS_SOL_EXPIRY_MS))) {
|
||||
LOG_WARN("SOME data is TOO OLD: LOC %u, TIME %u, DATE %u\n", reader.location.age(), reader.time.age(), reader.date.age());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Is this a new point or are we re-reading the previous one?
|
||||
if (!reader.location.isUpdated())
|
||||
return false;
|
||||
|
||||
// We know the solution is fresh and valid, so just read the data
|
||||
auto loc = reader.location.value();
|
||||
|
||||
// Bail out EARLY to avoid overwriting previous good data (like #857)
|
||||
if (toDegInt(loc.lat) > 900000000) {
|
||||
#ifdef GPS_EXTRAVERBOSE
|
||||
LOG_DEBUG("Bail out EARLY on LAT %i\n", toDegInt(loc.lat));
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
if (toDegInt(loc.lng) > 1800000000) {
|
||||
#ifdef GPS_EXTRAVERBOSE
|
||||
LOG_DEBUG("Bail out EARLY on LNG %i\n", toDegInt(loc.lng));
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
p.location_source = meshtastic_Position_LocSource_LOC_INTERNAL;
|
||||
|
||||
// Dilution of precision (an accuracy metric) is reported in 10^2 units, so we need to scale down when we use it
|
||||
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
|
||||
p.HDOP = reader.hdop.value();
|
||||
p.PDOP = TinyGPSPlus::parseDecimal(gsapdop.value());
|
||||
// LOG_DEBUG("PDOP=%d, HDOP=%d\n", p.PDOP, p.HDOP);
|
||||
#else
|
||||
// FIXME! naive PDOP emulation (assumes VDOP==HDOP)
|
||||
// correct formula is PDOP = SQRT(HDOP^2 + VDOP^2)
|
||||
p.HDOP = reader.hdop.value();
|
||||
p.PDOP = 1.41 * reader.hdop.value();
|
||||
#endif
|
||||
|
||||
// Discard incomplete or erroneous readings
|
||||
if (reader.hdop.value() == 0)
|
||||
return false;
|
||||
|
||||
p.latitude_i = toDegInt(loc.lat);
|
||||
p.longitude_i = toDegInt(loc.lng);
|
||||
|
||||
p.altitude_geoidal_separation = reader.geoidHeight.meters();
|
||||
p.altitude_hae = reader.altitude.meters() + p.altitude_geoidal_separation;
|
||||
p.altitude = reader.altitude.meters();
|
||||
|
||||
p.fix_quality = fixQual;
|
||||
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
|
||||
p.fix_type = fixType;
|
||||
#endif
|
||||
|
||||
// positional timestamp
|
||||
struct tm t;
|
||||
t.tm_sec = reader.time.second();
|
||||
t.tm_min = reader.time.minute();
|
||||
t.tm_hour = reader.time.hour();
|
||||
t.tm_mday = reader.date.day();
|
||||
t.tm_mon = reader.date.month() - 1;
|
||||
t.tm_year = reader.date.year() - 1900;
|
||||
t.tm_isdst = false;
|
||||
p.timestamp = mktime(&t);
|
||||
|
||||
// Nice to have, if available
|
||||
if (reader.satellites.isUpdated()) {
|
||||
p.sats_in_view = reader.satellites.value();
|
||||
}
|
||||
|
||||
if (reader.course.isUpdated() && reader.course.isValid()) {
|
||||
if (reader.course.value() < 36000) { // sanity check
|
||||
p.ground_track =
|
||||
reader.course.value() * 1e3; // Scale the heading (in degrees * 10^-2) to match the expected degrees * 10^-5
|
||||
} else {
|
||||
LOG_WARN("BOGUS course.value() REJECTED: %d\n", reader.course.value());
|
||||
}
|
||||
}
|
||||
|
||||
if (reader.speed.isUpdated() && reader.speed.isValid()) {
|
||||
p.ground_speed = reader.speed.kmph();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NMEAGPS::hasLock()
|
||||
{
|
||||
// Using GPGGA fix quality indicator
|
||||
if (fixQual >= 1 && fixQual <= 5) {
|
||||
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
|
||||
// Use GPGSA fix type 2D/3D (better) if available
|
||||
if (fixType == 3 || fixType == 0) // zero means "no data received"
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NMEAGPS::hasFlow()
|
||||
{
|
||||
return reader.passedChecksum() > 0;
|
||||
}
|
||||
|
||||
bool NMEAGPS::whileIdle()
|
||||
{
|
||||
bool isValid = false;
|
||||
|
||||
// First consume any chars that have piled up at the receiver
|
||||
while (_serial_gps->available() > 0) {
|
||||
int c = _serial_gps->read();
|
||||
// LOG_DEBUG("%c", c);
|
||||
isValid |= reader.encode(c);
|
||||
}
|
||||
|
||||
return isValid;
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "GPS.h"
|
||||
#include "Observer.h"
|
||||
#include "TinyGPS++.h"
|
||||
|
||||
/**
|
||||
* A gps class thatreads from a NMEA GPS stream (and FIXME - eventually keeps the gps powered down except when reading)
|
||||
*
|
||||
* When new data is available it will notify observers.
|
||||
*/
|
||||
class NMEAGPS : public GPS
|
||||
{
|
||||
TinyGPSPlus reader;
|
||||
uint8_t fixQual = 0; // fix quality from GPGGA
|
||||
|
||||
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
|
||||
// (20210908) TinyGps++ can only read the GPGSA "FIX TYPE" field
|
||||
// via optional feature "custom fields", currently disabled (bug #525)
|
||||
TinyGPSCustom gsafixtype; // custom extract fix type from GPGSA
|
||||
TinyGPSCustom gsapdop; // custom extract PDOP from GPGSA
|
||||
uint8_t fixType = 0; // fix type from GPGSA
|
||||
#endif
|
||||
|
||||
public:
|
||||
virtual bool setupGPS() override;
|
||||
|
||||
virtual bool factoryReset() override;
|
||||
|
||||
protected:
|
||||
/** Subclasses should look for serial rx characters here and feed it to their GPS parser
|
||||
*
|
||||
* Return true if we received a valid message from the GPS
|
||||
*/
|
||||
virtual bool whileIdle() override;
|
||||
|
||||
/**
|
||||
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
|
||||
* Override this method to check for new locations
|
||||
*
|
||||
* @return true if we've acquired a time
|
||||
*/
|
||||
virtual bool lookForTime() override;
|
||||
|
||||
/**
|
||||
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
|
||||
* Override this method to check for new locations
|
||||
*
|
||||
* @return true if we've acquired a new location
|
||||
*/
|
||||
virtual bool lookForLocation() override;
|
||||
|
||||
virtual bool hasLock() override;
|
||||
|
||||
virtual bool hasFlow() override;
|
||||
};
|
||||
@@ -17,6 +17,10 @@ static uint32_t
|
||||
timeStartMsec; // Once we have a GPS lock, this is where we hold the initial msec clock that corresponds to that time
|
||||
static uint64_t zeroOffsetSecs; // GPS based time in secs since 1970 - only updated once on initial lock
|
||||
|
||||
/**
|
||||
* Reads the current date and time from the RTC module and updates the system time.
|
||||
* @return True if the RTC was successfully read and the system time was updated, false otherwise.
|
||||
*/
|
||||
void readFromRTC()
|
||||
{
|
||||
struct timeval tv; /* btw settimeofday() is helpful here too*/
|
||||
@@ -83,7 +87,15 @@ void readFromRTC()
|
||||
#endif
|
||||
}
|
||||
|
||||
/// If we haven't yet set our RTC this boot, set it from a GPS derived time
|
||||
/**
|
||||
* Sets the RTC (Real-Time Clock) if the provided time is of higher quality than the current RTC time.
|
||||
*
|
||||
* @param q The quality of the provided time.
|
||||
* @param tv A pointer to a timeval struct containing the time to potentially set the RTC to.
|
||||
* @return True if the RTC was set, false otherwise.
|
||||
*
|
||||
* If we haven't yet set our RTC this boot, set it from a GPS derived time
|
||||
*/
|
||||
bool perhapsSetRTC(RTCQuality q, const struct timeval *tv)
|
||||
{
|
||||
static uint32_t lastSetMsec = 0;
|
||||
@@ -91,9 +103,8 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv)
|
||||
|
||||
bool shouldSet;
|
||||
if (q > currentQuality) {
|
||||
currentQuality = q;
|
||||
shouldSet = true;
|
||||
LOG_DEBUG("Upgrading time to RTC %ld secs (quality %d)\n", tv->tv_sec, q);
|
||||
LOG_DEBUG("Upgrading time to quality %d\n", q);
|
||||
} else if (q == RTCQualityGPS && (now - lastSetMsec) > (12 * 60 * 60 * 1000UL)) {
|
||||
// Every 12 hrs we will slam in a new GPS time, to correct for local RTC clock drift
|
||||
shouldSet = true;
|
||||
@@ -102,12 +113,12 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv)
|
||||
shouldSet = false;
|
||||
|
||||
if (shouldSet) {
|
||||
currentQuality = q;
|
||||
lastSetMsec = now;
|
||||
|
||||
// This delta value works on all platforms
|
||||
timeStartMsec = now;
|
||||
zeroOffsetSecs = tv->tv_sec;
|
||||
|
||||
// If this platform has a setable RTC, set it
|
||||
#ifdef RV3028_RTC
|
||||
if (rtc_found.address == RV3028_RTC) {
|
||||
@@ -151,6 +162,13 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the RTC time if the provided time is of higher quality than the current RTC time.
|
||||
*
|
||||
* @param q The quality of the provided time.
|
||||
* @param t The time to potentially set the RTC to.
|
||||
* @return True if the RTC was set to the provided time, false otherwise.
|
||||
*/
|
||||
bool perhapsSetRTC(RTCQuality q, struct tm &t)
|
||||
{
|
||||
/* Convert to unix time
|
||||
@@ -171,12 +189,23 @@ bool perhapsSetRTC(RTCQuality q, struct tm &t)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current time in seconds since the Unix epoch (January 1, 1970).
|
||||
*
|
||||
* @return The current time in seconds since the Unix epoch.
|
||||
*/
|
||||
uint32_t getTime()
|
||||
{
|
||||
return (((uint32_t)millis() - timeStartMsec) / 1000) + zeroOffsetSecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current time from the RTC if the quality of the time is at least minQuality.
|
||||
*
|
||||
* @param minQuality The minimum quality of the RTC time required for it to be considered valid.
|
||||
* @return The current time from the RTC if it meets the minimum quality requirement, or 0 if the time is not valid.
|
||||
*/
|
||||
uint32_t getValidTime(RTCQuality minQuality)
|
||||
{
|
||||
return (currentQuality >= minQuality) ? getTime() : 0;
|
||||
}
|
||||
}
|
||||
192
src/gps/ubx.h
Normal file
192
src/gps/ubx.h
Normal file
@@ -0,0 +1,192 @@
|
||||
const uint8_t GPS::_message_PMREQ[] PROGMEM = {
|
||||
0x00, 0x00, // 4 bytes duration of request task
|
||||
0x00, 0x00, // (milliseconds)
|
||||
0x02, 0x00, // Task flag bitfield
|
||||
0x00, 0x00 // byte index 1 = sleep mode
|
||||
};
|
||||
|
||||
const uint8_t GPS::_message_CFG_RXM_PSM[] PROGMEM = {
|
||||
0x08, // Reserved
|
||||
0x01 // Power save mode
|
||||
};
|
||||
|
||||
const uint8_t GPS::_message_CFG_RXM_ECO[] PROGMEM = {
|
||||
0x08, // Reserved
|
||||
0x04 // eco mode
|
||||
};
|
||||
|
||||
const uint8_t GPS::_message_CFG_PM2[] PROGMEM = {
|
||||
0x01, 0x06, 0x00, 0x00, // version, Reserved
|
||||
0x0e, 0x81, 0x42, 0x01, // flags
|
||||
0xE8, 0x03, 0x00, 0x00, // update period 1000 ms
|
||||
0x10, 0x27, 0x00, 0x00, // search period 10s
|
||||
0x00, 0x00, 0x00, 0x00, // Grod offset 0
|
||||
0x01, 0x00, // onTime 1 second
|
||||
0x00, 0x00, // min search time 0
|
||||
0x2C, 0x01, // reserved
|
||||
0x00, 0x00, 0x4F, 0xC1, // reserved
|
||||
0x03, 0x00, 0x87, 0x02, // reserved
|
||||
0x00, 0x00, 0xFF, 0x00, // reserved
|
||||
0x01, 0x00, 0xD6, 0x4D // reserved
|
||||
};
|
||||
|
||||
const uint8_t GPS::_message_GNSS_7[] = {
|
||||
0x00, // msgVer (0 for this version)
|
||||
0x00, // numTrkChHw (max number of hardware channels, read only, so it's always 0)
|
||||
0xff, // numTrkChUse (max number of channels to use, 0xff = max available)
|
||||
0x02, // numConfigBlocks (number of GNSS systems), most modules support maximum 3 GNSS systems
|
||||
// GNSS config format: gnssId, resTrkCh, maxTrkCh, reserved1, flags
|
||||
0x00, 0x08, 0x10, 0x00, 0x01, 0x00, 0x00, 0x01, // GPS
|
||||
0x01, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x01 // SBAS
|
||||
};
|
||||
|
||||
// It's not critical if the module doesn't acknowledge this configuration.
|
||||
// The module should operate adequately with its factory or previously saved settings.
|
||||
// It appears that there is a firmware bug in some GPS modules: When an attempt is made
|
||||
// to overwrite a saved state with identical values, no ACK/NAK is received, contrary to
|
||||
// what is specified in the Ublox documentation.
|
||||
// There is also a possibility that the module may be GPS-only.
|
||||
const uint8_t GPS::_message_GNSS[] = {
|
||||
0x00, // msgVer (0 for this version)
|
||||
0x00, // numTrkChHw (max number of hardware channels, read only, so it's always 0)
|
||||
0xff, // numTrkChUse (max number of channels to use, 0xff = max available)
|
||||
0x03, // numConfigBlocks (number of GNSS systems), most modules support maximum 3 GNSS systems
|
||||
// GNSS config format: gnssId, resTrkCh, maxTrkCh, reserved1, flags
|
||||
0x00, 0x08, 0x10, 0x00, 0x01, 0x00, 0x01, 0x01, // GPS
|
||||
0x01, 0x01, 0x03, 0x00, 0x01, 0x00, 0x01, 0x01, // SBAS
|
||||
0x06, 0x08, 0x0e, 0x00, 0x01, 0x00, 0x01, 0x01 // GLONASS
|
||||
};
|
||||
|
||||
// Enable interference resistance, because we are using LoRa, WiFi and Bluetooth on same board,
|
||||
// and we need to reduce interference from them
|
||||
const uint8_t GPS::_message_JAM[] = {
|
||||
// bbThreshold (Broadband jamming detection threshold) is set to 0x3F (63 in decimal)
|
||||
// cwThreshold (CW jamming detection threshold) is set to 0x10 (16 in decimal)
|
||||
// algorithmBits (Reserved algorithm settings) is set to 0x16B156 as recommended
|
||||
// enable (Enable interference detection) is set to 1 (enabled)
|
||||
0x3F, 0x10, 0xB1, 0x56, // config: Interference config word
|
||||
// generalBits (General settings) is set to 0x31E as recommended
|
||||
// antSetting (Antenna setting, 0=unknown, 1=passive, 2=active) is set to 0 (unknown)
|
||||
// ToDo: Set to 1 (passive) or 2 (active) if known, for example from UBX-MON-HW, or from board info
|
||||
// enable2 (Set to 1 to scan auxiliary bands, u-blox 8 / u-blox M8 only, otherwise ignored) is set to 1
|
||||
// (enabled)
|
||||
0x1E, 0x03, 0x00, 0x01 // config2: Extra settings for jamming/interference monitor
|
||||
};
|
||||
|
||||
// Configure navigation engine expert settings:
|
||||
const uint8_t GPS::_message_NAVX5[] = {
|
||||
0x00, 0x00, // msgVer (0 for this version)
|
||||
// minMax flag = 1: apply min/max SVs settings
|
||||
// minCno flag = 1: apply minimum C/N0 setting
|
||||
// initial3dfix flag = 0: apply initial 3D fix settings
|
||||
// aop flag = 1: apply aopCfg (useAOP flag) settings (AssistNow Autonomous)
|
||||
0x1B, 0x00, // mask1 (First parameters bitmask)
|
||||
// adr flag = 0: apply ADR sensor fusion on/off setting (useAdr flag)
|
||||
// If firmware is not ADR/UDR, enabling this flag will fail configuration
|
||||
// ToDo: check this with UBX-MON-VER
|
||||
0x00, 0x00, 0x00, 0x00, // mask2 (Second parameters bitmask)
|
||||
0x00, 0x00, // Reserved
|
||||
0x03, // minSVs (Minimum number of satellites for navigation) = 3
|
||||
0x10, // maxSVs (Maximum number of satellites for navigation) = 16
|
||||
0x06, // minCNO (Minimum satellite signal level for navigation) = 6 dBHz
|
||||
0x00, // Reserved
|
||||
0x00, // iniFix3D (Initial fix must be 3D) = 0 (disabled)
|
||||
0x00, 0x00, // Reserved
|
||||
0x00, // ackAiding (Issue acknowledgements for assistance message input) = 0 (disabled)
|
||||
0x00, 0x00, // Reserved
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Reserved
|
||||
0x00, // Reserved
|
||||
0x01, // aopCfg (AssistNow Autonomous configuration) = 1 (enabled)
|
||||
0x00, 0x00, // Reserved
|
||||
0x00, 0x00, // Reserved
|
||||
0x00, 0x00, 0x00, 0x00, // Reserved
|
||||
0x00, 0x00, 0x00, // Reserved
|
||||
0x01, // useAdr (Enable/disable ADR sensor fusion) = 1 (enabled)
|
||||
};
|
||||
|
||||
// Set GPS update rate to 1Hz
|
||||
// Lowering the update rate helps to save power.
|
||||
// Additionally, for some new modules like the M9/M10, an update rate lower than 5Hz
|
||||
// is recommended to avoid a known issue with satellites disappearing.
|
||||
const uint8_t GPS::_message_1HZ[] = {
|
||||
0xE8, 0x03, // Measurement Rate (1000ms for 1Hz)
|
||||
0x01, 0x00, // Navigation rate, always 1 in GPS mode
|
||||
0x01, 0x00, // Time reference
|
||||
};
|
||||
|
||||
// Disable GGL. GGL - Geographic position (latitude and longitude), which provides the current geographical
|
||||
// coordinates.
|
||||
const uint8_t GPS::_message_GGL[] = {
|
||||
0xF0, 0x01, // NMEA ID for GLL
|
||||
0x01, // I/O Target 0=I/O, 1=UART1, 2=UART2, 3=USB, 4=SPI
|
||||
0x00, // Disable
|
||||
0x01, 0x01, 0x01, 0x01 // Reserved
|
||||
};
|
||||
|
||||
// Enable GSA. GSA - GPS DOP and active satellites, used for detailing the satellites used in the positioning and
|
||||
// the DOP (Dilution of Precision)
|
||||
const uint8_t GPS::_message_GSA[] = {
|
||||
0xF0, 0x02, // NMEA ID for GSA
|
||||
0x01, // I/O Target 0=I/O, 1=UART1, 2=UART2, 3=USB, 4=SPI
|
||||
0x01, // Enable
|
||||
0x01, 0x01, 0x01, 0x01 // Reserved
|
||||
};
|
||||
|
||||
// Disable GSV. GSV - Satellites in view, details the number and location of satellites in view.
|
||||
const uint8_t GPS::_message_GSV[] = {
|
||||
0xF0, 0x03, // NMEA ID for GSV
|
||||
0x01, // I/O Target 0=I/O, 1=UART1, 2=UART2, 3=USB, 4=SPI
|
||||
0x00, // Disable
|
||||
0x01, 0x01, 0x01, 0x01 // Reserved
|
||||
};
|
||||
|
||||
// Disable VTG. VTG - Track made good and ground speed, which provides course and speed information relative to
|
||||
// the ground.
|
||||
const uint8_t GPS::_message_VTG[] = {
|
||||
0xF0, 0x05, // NMEA ID for VTG
|
||||
0x01, // I/O Target 0=I/O, 1=UART1, 2=UART2, 3=USB, 4=SPI
|
||||
0x00, // Disable
|
||||
0x01, 0x01, 0x01, 0x01 // Reserved
|
||||
};
|
||||
|
||||
// Enable RMC. RMC - Recommended Minimum data, the essential gps pvt (position, velocity, time) data.
|
||||
const uint8_t GPS::_message_RMC[] = {
|
||||
0xF0, 0x04, // NMEA ID for RMC
|
||||
0x01, // I/O Target 0=I/O, 1=UART1, 2=UART2, 3=USB, 4=SPI
|
||||
0x01, // Enable
|
||||
0x01, 0x01, 0x01, 0x01 // Reserved
|
||||
};
|
||||
|
||||
// Enable GGA. GGA - Global Positioning System Fix Data, which provides 3D location and accuracy data.
|
||||
const uint8_t GPS::_message_GGA[] = {
|
||||
0xF0, 0x00, // NMEA ID for GGA
|
||||
0x01, // I/O Target 0=I/O, 1=UART1, 2=UART2, 3=USB, 4=SPI
|
||||
0x01, // Enable
|
||||
0x01, 0x01, 0x01, 0x01 // Reserved
|
||||
};
|
||||
|
||||
// The Power Management configuration allows the GPS module to operate in different power modes for optimized
|
||||
// power consumption. The modes supported are: 0x00 = Full power: The module operates at full power with no power
|
||||
// saving. 0x01 = Balanced: The module dynamically adjusts the tracking behavior to balance power consumption.
|
||||
// 0x02 = Interval: The module operates in a periodic mode, cycling between tracking and power saving states.
|
||||
// 0x03 = Aggressive with 1 Hz: The module operates in a power saving mode with a 1 Hz update rate.
|
||||
// 0x04 = Aggressive with 2 Hz: The module operates in a power saving mode with a 2 Hz update rate.
|
||||
// 0x05 = Aggressive with 4 Hz: The module operates in a power saving mode with a 4 Hz update rate.
|
||||
// The 'period' field specifies the position update and search period. It is only valid when the powerSetupValue
|
||||
// is set to Interval; otherwise, it must be set to '0'. The 'onTime' field specifies the duration of the ON phase
|
||||
// and must be smaller than the period. It is only valid when the powerSetupValue is set to Interval; otherwise,
|
||||
// it must be set to '0'.
|
||||
const uint8_t GPS::_message_PMS[] = {
|
||||
0x00, // Version (0)
|
||||
0x03, // Power setup value
|
||||
0x00, 0x00, // period: not applicable, set to 0
|
||||
0x00, 0x00, // onTime: not applicable, set to 0
|
||||
0x97, 0x6F // reserved, generated by u-center
|
||||
};
|
||||
|
||||
const uint8_t GPS::_message_SAVE[] = {
|
||||
0x00, 0x00, 0x00, 0x00, // clearMask: no sections cleared
|
||||
0xFF, 0xFF, 0x00, 0x00, // saveMask: save all sections
|
||||
0x00, 0x00, 0x00, 0x00, // loadMask: no sections loaded
|
||||
0x0F // deviceMask: BBR, Flash, EEPROM, and SPI Flash
|
||||
};
|
||||
@@ -3,7 +3,7 @@
|
||||
#include <OLEDDisplay.h>
|
||||
|
||||
/**
|
||||
* An adapter class that allows using the TFT_eSPI library as if it was an OLEDDisplay implementation.
|
||||
* An adapter class that allows using the GxEPD2 library as if it was an OLEDDisplay implementation.
|
||||
*
|
||||
* Remaining TODO:
|
||||
* optimize display() to only draw changed pixels (see other OLED subclasses for examples)
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
#include "main.h"
|
||||
|
||||
#ifdef HAS_NCP5623
|
||||
#include <NCP5623.h>
|
||||
extern NCP5623 rgb;
|
||||
|
||||
@@ -36,11 +36,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#include "mesh-pb-constants.h"
|
||||
#include "mesh/Channels.h"
|
||||
#include "mesh/generated/meshtastic/deviceonly.pb.h"
|
||||
#include "meshUtils.h"
|
||||
#include "modules/ExternalNotificationModule.h"
|
||||
#include "modules/TextMessageModule.h"
|
||||
#include "sleep.h"
|
||||
#include "target_specific.h"
|
||||
#include "utils.h"
|
||||
|
||||
#ifdef ARCH_ESP32
|
||||
#include "esp_task_wdt.h"
|
||||
@@ -103,7 +103,8 @@ 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)
|
||||
#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
|
||||
@@ -364,7 +365,7 @@ static void drawCriticalFaultFrame(OLEDDisplay *display, OLEDDisplayUiState *sta
|
||||
// Ignore messages originating from phone (from the current node 0x0) unless range test or store and forward module are enabled
|
||||
static bool shouldDrawMessage(const meshtastic_MeshPacket *packet)
|
||||
{
|
||||
return packet->from != 0 && !moduleConfig.range_test.enabled && !moduleConfig.store_forward.enabled;
|
||||
return packet->from != 0 && !moduleConfig.store_forward.enabled;
|
||||
}
|
||||
|
||||
/// Draw the last text message we received
|
||||
@@ -373,7 +374,7 @@ static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state
|
||||
// the max length of this buffer is much longer than we can possibly print
|
||||
static char tempBuf[237];
|
||||
|
||||
meshtastic_MeshPacket &mp = devicestate.rx_text_message;
|
||||
const meshtastic_MeshPacket &mp = devicestate.rx_text_message;
|
||||
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);
|
||||
@@ -489,11 +490,12 @@ static void drawBattery(OLEDDisplay *display, int16_t x, int16_t y, uint8_t *img
|
||||
}
|
||||
|
||||
// Draw nodes status
|
||||
static void drawNodes(OLEDDisplay *display, int16_t x, int16_t y, NodeStatus *nodeStatus)
|
||||
static void drawNodes(OLEDDisplay *display, int16_t x, int16_t y, const NodeStatus *nodeStatus)
|
||||
{
|
||||
char usersString[20];
|
||||
snprintf(usersString, sizeof(usersString), "%d/%d", nodeStatus->getNumOnline(), nodeStatus->getNumTotal());
|
||||
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)
|
||||
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)) && \
|
||||
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||||
display->drawFastImage(x, y + 3, 8, 8, imgUser);
|
||||
#else
|
||||
display->drawFastImage(x, y, 8, 8, imgUser);
|
||||
@@ -856,14 +858,14 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
|
||||
bool hasNodeHeading = false;
|
||||
|
||||
if (ourNode && hasValidPosition(ourNode)) {
|
||||
meshtastic_PositionLite &op = ourNode->position;
|
||||
const meshtastic_PositionLite &op = ourNode->position;
|
||||
float myHeading = estimatedHeading(DegD(op.latitude_i), DegD(op.longitude_i));
|
||||
drawCompassNorth(display, compassX, compassY, myHeading);
|
||||
|
||||
if (hasValidPosition(node)) {
|
||||
// display direction toward node
|
||||
hasNodeHeading = true;
|
||||
meshtastic_PositionLite &p = node->position;
|
||||
const meshtastic_PositionLite &p = node->position;
|
||||
float d =
|
||||
GeoCoord::latLongToMeter(DegD(p.latitude_i), DegD(p.longitude_i), DegD(op.latitude_i), DegD(op.longitude_i));
|
||||
|
||||
@@ -1056,7 +1058,8 @@ void Screen::setup()
|
||||
nodeStatusObserver.observe(&nodeStatus->onNewStatus);
|
||||
if (textMessageModule)
|
||||
textMessageObserver.observe(textMessageModule);
|
||||
inputObserver.observe(inputBroker);
|
||||
if (inputBroker)
|
||||
inputObserver.observe(inputBroker);
|
||||
|
||||
// Modules can notify screen about refresh
|
||||
MeshModule::observeUIEvents(&uiFrameEventObserver);
|
||||
@@ -1527,7 +1530,8 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
||||
#ifdef ARCH_ESP32
|
||||
if (millis() - storeForwardModule->lastHeartbeat >
|
||||
(storeForwardModule->heartbeatInterval * 1200)) { // no heartbeat, overlap a bit
|
||||
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)
|
||||
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)) && \
|
||||
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||||
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 3 + FONT_HEIGHT_SMALL, 12, 8,
|
||||
imgQuestionL1);
|
||||
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 11 + FONT_HEIGHT_SMALL, 12, 8,
|
||||
@@ -1537,7 +1541,8 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
||||
imgQuestion);
|
||||
#endif
|
||||
} else {
|
||||
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)
|
||||
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)) && \
|
||||
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||||
display->drawFastImage(x + SCREEN_WIDTH - 18 - display->getStringWidth(ourId), y + 3 + FONT_HEIGHT_SMALL, 16, 8,
|
||||
imgSFL1);
|
||||
display->drawFastImage(x + SCREEN_WIDTH - 18 - display->getStringWidth(ourId), y + 11 + FONT_HEIGHT_SMALL, 16, 8,
|
||||
@@ -1549,7 +1554,8 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)
|
||||
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)) && \
|
||||
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||||
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 3 + FONT_HEIGHT_SMALL, 12, 8,
|
||||
imgInfoL1);
|
||||
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 11 + FONT_HEIGHT_SMALL, 12, 8,
|
||||
@@ -1895,7 +1901,7 @@ int Screen::handleUIFrameEvent(const UIFrameEvent *event)
|
||||
int Screen::handleInputEvent(const InputEvent *event)
|
||||
{
|
||||
if (showingNormalScreen && moduleFrames.size() == 0) {
|
||||
LOG_DEBUG("Screen::handleInputEvent from %s\n", event->source);
|
||||
// LOG_DEBUG("Screen::handleInputEvent from %s\n", event->source);
|
||||
if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT)) {
|
||||
showPrevFrame();
|
||||
} else if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT)) {
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
#define TFT_BACKLIGHT_ON HIGH
|
||||
#endif
|
||||
|
||||
// convert 24-bit color to 16-bit (56K)
|
||||
#define COLOR565(r, g, b) (((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3))
|
||||
#ifndef TFT_MESH
|
||||
#define TFT_MESH COLOR565(0x67, 0xEA, 0x94)
|
||||
#endif
|
||||
|
||||
#if defined(ST7735S)
|
||||
#include <LovyanGFX.hpp> // Graphics and font library for ST7735 driver chip
|
||||
@@ -108,10 +108,12 @@ class LGFX : public lgfx::LGFX_Device
|
||||
lgfx::Panel_ST7789 _panel_instance;
|
||||
lgfx::Bus_SPI _bus_instance;
|
||||
lgfx::Light_PWM _light_instance;
|
||||
#if HAS_TOUCHSCREEN
|
||||
#ifdef T_WATCH_S3
|
||||
lgfx::Touch_FT5x06 _touch_instance;
|
||||
#else
|
||||
lgfx::Touch_GT911 _touch_instance;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
public:
|
||||
@@ -126,13 +128,14 @@ class LGFX : public lgfx::LGFX_Device
|
||||
cfg.freq_write = SPI_FREQUENCY; // SPI clock for transmission (up to 80MHz, rounded to the value obtained by dividing
|
||||
// 80MHz by an integer)
|
||||
cfg.freq_read = SPI_READ_FREQUENCY; // SPI clock when receiving
|
||||
cfg.spi_3wire = false; // Set to true if reception is done on the MOSI pin
|
||||
cfg.use_lock = true; // Set to true to use transaction locking
|
||||
cfg.dma_channel = SPI_DMA_CH_AUTO; // SPI_DMA_CH_AUTO; // Set DMA channel to use (0=not use DMA / 1=1ch / 2=ch /
|
||||
cfg.pin_sclk = ST7789_SCK; // Set SPI SCLK pin number
|
||||
cfg.pin_mosi = ST7789_SDA; // Set SPI MOSI pin number
|
||||
cfg.pin_miso = ST7789_MISO; // Set SPI MISO pin number (-1 = disable)
|
||||
cfg.pin_dc = ST7789_RS; // Set SPI DC pin number (-1 = disable)
|
||||
cfg.spi_3wire = false;
|
||||
cfg.use_lock = true; // Set to true to use transaction locking
|
||||
cfg.dma_channel = SPI_DMA_CH_AUTO; // SPI_DMA_CH_AUTO; // Set DMA channel to use (0=not use DMA / 1=1ch / 2=ch /
|
||||
// SPI_DMA_CH_AUTO=auto setting)
|
||||
cfg.pin_sclk = ST7789_SCK; // Set SPI SCLK pin number
|
||||
cfg.pin_mosi = ST7789_SDA; // Set SPI MOSI pin number
|
||||
cfg.pin_miso = ST7789_MISO; // Set SPI MISO pin number (-1 = disable)
|
||||
cfg.pin_dc = ST7789_RS; // Set SPI DC pin number (-1 = disable)
|
||||
|
||||
_bus_instance.config(cfg); // applies the set value to the bus.
|
||||
_panel_instance.setBus(&_bus_instance); // set the bus on the panel.
|
||||
@@ -148,16 +151,16 @@ class LGFX : public lgfx::LGFX_Device
|
||||
// The following setting values are general initial values for each panel, so please comment out any
|
||||
// unknown items and try them.
|
||||
|
||||
cfg.panel_width = TFT_WIDTH; // actual displayable width
|
||||
cfg.panel_height = TFT_HEIGHT; // actual displayable height
|
||||
cfg.offset_x = TFT_OFFSET_X; // Panel offset amount in X direction
|
||||
cfg.offset_y = TFT_OFFSET_Y; // Panel offset amount in Y direction
|
||||
cfg.offset_rotation = 0; // Rotation direction value offset 0~7 (4~7 is mirrored)
|
||||
cfg.dummy_read_pixel = 9; // Number of bits for dummy read before pixel readout
|
||||
cfg.dummy_read_bits = 1; // Number of bits for dummy read before non-pixel data read
|
||||
cfg.readable = true; // Set to true if data can be read
|
||||
cfg.invert = true; // Set to true if the light/darkness of the panel is reversed
|
||||
cfg.rgb_order = false; // Set to true if the panel's red and blue are swapped
|
||||
cfg.panel_width = TFT_WIDTH; // actual displayable width
|
||||
cfg.panel_height = TFT_HEIGHT; // actual displayable height
|
||||
cfg.offset_x = TFT_OFFSET_X; // Panel offset amount in X direction
|
||||
cfg.offset_y = TFT_OFFSET_Y; // Panel offset amount in Y direction
|
||||
cfg.offset_rotation = TFT_OFFSET_ROTATION; // Rotation direction value offset 0~7 (4~7 is mirrored)
|
||||
cfg.dummy_read_pixel = 9; // Number of bits for dummy read before pixel readout
|
||||
cfg.dummy_read_bits = 1; // Number of bits for dummy read before non-pixel data read
|
||||
cfg.readable = true; // Set to true if data can be read
|
||||
cfg.invert = true; // Set to true if the light/darkness of the panel is reversed
|
||||
cfg.rgb_order = false; // Set to true if the panel's red and blue are swapped
|
||||
cfg.dlen_16bit =
|
||||
false; // Set to true for panels that transmit data length in 16-bit units with 16-bit parallel or SPI
|
||||
cfg.bus_shared = true; // If the bus is shared with the SD card, set to true (bus control with drawJpgFile etc.)
|
||||
@@ -181,6 +184,7 @@ class LGFX : public lgfx::LGFX_Device
|
||||
_panel_instance.setLight(&_light_instance); // Set the backlight on the panel.
|
||||
}
|
||||
|
||||
#if HAS_TOUCHSCREEN
|
||||
// Configure settings for touch screen control.
|
||||
{
|
||||
auto cfg = _touch_instance.config();
|
||||
@@ -192,7 +196,7 @@ class LGFX : public lgfx::LGFX_Device
|
||||
cfg.y_max = TFT_WIDTH - 1;
|
||||
cfg.pin_int = SCREEN_TOUCH_INT;
|
||||
cfg.bus_shared = true;
|
||||
cfg.offset_rotation = 0;
|
||||
cfg.offset_rotation = TFT_OFFSET_ROTATION;
|
||||
// cfg.freq = 2500000;
|
||||
|
||||
// I2C
|
||||
@@ -210,6 +214,7 @@ class LGFX : public lgfx::LGFX_Device
|
||||
_touch_instance.config(cfg);
|
||||
_panel_instance.setTouch(&_touch_instance);
|
||||
}
|
||||
#endif
|
||||
|
||||
setPanel(&_panel_instance); // Sets the panel to use.
|
||||
}
|
||||
@@ -217,7 +222,96 @@ class LGFX : public lgfx::LGFX_Device
|
||||
|
||||
static LGFX tft;
|
||||
|
||||
#elif defined(ST7735_CS) || defined(ILI9341_DRIVER)
|
||||
#elif defined(ILI9341_DRIVER)
|
||||
|
||||
#include <LovyanGFX.hpp> // Graphics and font library for ILI9341 driver chip
|
||||
|
||||
#if defined(ILI9341_BACKLIGHT_EN) && !defined(TFT_BL)
|
||||
#define TFT_BL ILI9341_BACKLIGHT_EN
|
||||
#endif
|
||||
|
||||
class LGFX : public lgfx::LGFX_Device
|
||||
{
|
||||
lgfx::Panel_ILI9341 _panel_instance;
|
||||
lgfx::Bus_SPI _bus_instance;
|
||||
lgfx::Light_PWM _light_instance;
|
||||
|
||||
public:
|
||||
LGFX(void)
|
||||
{
|
||||
{
|
||||
auto cfg = _bus_instance.config();
|
||||
|
||||
// configure SPI
|
||||
cfg.spi_host = ILI9341_SPI_HOST; // ESP32-S2,S3,C3 : SPI2_HOST or SPI3_HOST / ESP32 : VSPI_HOST or HSPI_HOST
|
||||
cfg.spi_mode = 0;
|
||||
cfg.freq_write = SPI_FREQUENCY; // SPI clock for transmission (up to 80MHz, rounded to the value obtained by dividing
|
||||
// 80MHz by an integer)
|
||||
cfg.freq_read = SPI_READ_FREQUENCY; // SPI clock when receiving
|
||||
cfg.spi_3wire = false; // Set to true if reception is done on the MOSI pin
|
||||
cfg.use_lock = true; // Set to true to use transaction locking
|
||||
cfg.dma_channel = SPI_DMA_CH_AUTO; // SPI_DMA_CH_AUTO; // Set DMA channel to use (0=not use DMA / 1=1ch / 2=ch /
|
||||
// SPI_DMA_CH_AUTO=auto setting)
|
||||
cfg.pin_sclk = TFT_SCLK; // Set SPI SCLK pin number
|
||||
cfg.pin_mosi = TFT_MOSI; // Set SPI MOSI pin number
|
||||
cfg.pin_miso = TFT_MISO; // Set SPI MISO pin number (-1 = disable)
|
||||
cfg.pin_dc = TFT_DC; // Set SPI DC pin number (-1 = disable)
|
||||
|
||||
_bus_instance.config(cfg); // applies the set value to the bus.
|
||||
_panel_instance.setBus(&_bus_instance); // set the bus on the panel.
|
||||
}
|
||||
|
||||
{ // Set the display panel control.
|
||||
auto cfg = _panel_instance.config(); // Gets a structure for display panel settings.
|
||||
|
||||
cfg.pin_cs = TFT_CS; // Pin number where CS is connected (-1 = disable)
|
||||
cfg.pin_rst = TFT_RST; // Pin number where RST is connected (-1 = disable)
|
||||
cfg.pin_busy = TFT_BUSY; // Pin number where BUSY is connected (-1 = disable)
|
||||
|
||||
// The following setting values are general initial values for each panel, so please comment out any
|
||||
// unknown items and try them.
|
||||
|
||||
cfg.panel_width = TFT_WIDTH; // actual displayable width
|
||||
cfg.panel_height = TFT_HEIGHT; // actual displayable height
|
||||
cfg.offset_x = TFT_OFFSET_X; // Panel offset amount in X direction
|
||||
cfg.offset_y = TFT_OFFSET_Y; // Panel offset amount in Y direction
|
||||
cfg.offset_rotation = 0; // Rotation direction value offset 0~7 (4~7 is upside down)
|
||||
cfg.dummy_read_pixel = 8; // Number of bits for dummy read before pixel readout
|
||||
cfg.dummy_read_bits = 1; // Number of bits for dummy read before non-pixel data read
|
||||
cfg.readable = true; // Set to true if data can be read
|
||||
cfg.invert = false; // Set to true if the light/darkness of the panel is reversed
|
||||
cfg.rgb_order = false; // Set to true if the panel's red and blue are swapped
|
||||
cfg.dlen_16bit =
|
||||
false; // Set to true for panels that transmit data length in 16-bit units with 16-bit parallel or SPI
|
||||
cfg.bus_shared = true; // If the bus is shared with the SD card, set to true (bus control with drawJpgFile etc.)
|
||||
|
||||
// Set the following only when the display is shifted with a driver with a variable number of pixels, such as the
|
||||
// ST7735 or ILI9163.
|
||||
cfg.memory_width = TFT_WIDTH; // Maximum width supported by the driver IC
|
||||
cfg.memory_height = TFT_HEIGHT; // Maximum height supported by the driver IC
|
||||
_panel_instance.config(cfg);
|
||||
}
|
||||
|
||||
// Set the backlight control
|
||||
{
|
||||
auto cfg = _light_instance.config(); // Gets a structure for backlight settings.
|
||||
|
||||
cfg.pin_bl = TFT_BL; // Pin number to which the backlight is connected
|
||||
cfg.invert = false; // true to invert the brightness of the backlight
|
||||
// cfg.freq = 44100; // PWM frequency of backlight
|
||||
// cfg.pwm_channel = 1; // PWM channel number to use
|
||||
|
||||
_light_instance.config(cfg);
|
||||
_panel_instance.setLight(&_light_instance); // Set the backlight on the panel.
|
||||
}
|
||||
|
||||
setPanel(&_panel_instance);
|
||||
}
|
||||
};
|
||||
|
||||
static LGFX tft;
|
||||
|
||||
#elif defined(ST7735_CS)
|
||||
#include <TFT_eSPI.h> // Graphics and font library for ILI9341 driver chip
|
||||
|
||||
static TFT_eSPI tft = TFT_eSPI(); // Invoke library, pins defined in User_Setup.h
|
||||
@@ -300,6 +394,14 @@ void TFTDisplay::sendCommand(uint8_t com)
|
||||
// Drop all other commands to device (we just update the buffer)
|
||||
}
|
||||
|
||||
void TFTDisplay::flipScreenVertically()
|
||||
{
|
||||
#if defined(T_WATCH_S3)
|
||||
LOG_DEBUG("Flip TFT vertically\n"); // T-Watch S3 right-handed orientation
|
||||
tft.setRotation(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool TFTDisplay::hasTouch(void)
|
||||
{
|
||||
#ifndef M5STACK
|
||||
@@ -335,10 +437,12 @@ bool TFTDisplay::connect()
|
||||
#endif
|
||||
|
||||
tft.init();
|
||||
#if defined(M5STACK) || defined(T_DECK)
|
||||
tft.setRotation(1); // M5Stack/T-Deck have the TFT in landscape
|
||||
#if defined(M5STACK)
|
||||
tft.setRotation(0);
|
||||
#elif defined(T_DECK) || defined(PICOMPUTER_S3)
|
||||
tft.setRotation(1); // T-Deck has the TFT in landscape
|
||||
#elif defined(T_WATCH_S3)
|
||||
tft.setRotation(0); // T-Watch S3 has the TFT in portrait
|
||||
tft.setRotation(2); // T-Watch S3 left-handed orientation
|
||||
#else
|
||||
tft.setRotation(3); // Orient horizontal and wide underneath the silkscreen name label
|
||||
#endif
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include <OLEDDisplay.h>
|
||||
|
||||
/**
|
||||
* An adapter class that allows using the TFT_eSPI library as if it was an OLEDDisplay implementation.
|
||||
* An adapter class that allows using the LovyanGFX library as if it was an OLEDDisplay implementation.
|
||||
*
|
||||
* Remaining TODO:
|
||||
* optimize display() to only draw changed pixels (see other OLED subclasses for examples)
|
||||
@@ -22,6 +22,9 @@ class TFTDisplay : public OLEDDisplay
|
||||
// Write the buffer to the display memory
|
||||
virtual void display(void) override;
|
||||
|
||||
// Turn the display upside down
|
||||
virtual void flipScreenVertically();
|
||||
|
||||
// Touch screen (static handlers)
|
||||
static bool hasTouch(void);
|
||||
static bool getTouch(int16_t *x, int16_t *y);
|
||||
|
||||
@@ -14,7 +14,8 @@ const uint8_t imgUser[] PROGMEM = {0x3C, 0x42, 0x99, 0xA5, 0xA5, 0x99, 0x42, 0x3
|
||||
const uint8_t imgPositionEmpty[] PROGMEM = {0x20, 0x30, 0x28, 0x24, 0x42, 0xFF};
|
||||
const uint8_t imgPositionSolid[] PROGMEM = {0x20, 0x30, 0x38, 0x3C, 0x7E, 0xFF};
|
||||
|
||||
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)
|
||||
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)) && \
|
||||
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||||
const uint8_t imgQuestionL1[] PROGMEM = {0xff, 0x01, 0x01, 0x32, 0x7b, 0x49, 0x49, 0x6f, 0x26, 0x01, 0x01, 0xff};
|
||||
const uint8_t imgQuestionL2[] PROGMEM = {0x0f, 0x08, 0x08, 0x08, 0x06, 0x0f, 0x0f, 0x06, 0x08, 0x08, 0x08, 0x0f};
|
||||
const uint8_t imgInfoL1[] PROGMEM = {0xff, 0x01, 0x01, 0x01, 0x1e, 0x7f, 0x1e, 0x01, 0x01, 0x01, 0x01, 0xff};
|
||||
|
||||
181
src/input/BBQ10Keyboard.cpp
Normal file
181
src/input/BBQ10Keyboard.cpp
Normal file
@@ -0,0 +1,181 @@
|
||||
// Based on arturo182 arduino_bbq10kbd library https://github.com/arturo182/arduino_bbq10kbd
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include "BBQ10Keyboard.h"
|
||||
|
||||
#define _REG_VER 1
|
||||
#define _REG_CFG 2
|
||||
#define _REG_INT 3
|
||||
#define _REG_KEY 4
|
||||
#define _REG_BKL 5
|
||||
#define _REG_DEB 6
|
||||
#define _REG_FRQ 7
|
||||
#define _REG_RST 8
|
||||
#define _REG_FIF 9
|
||||
|
||||
#define _WRITE_MASK (1 << 7)
|
||||
|
||||
#define CFG_OVERFLOW_ON (1 << 0)
|
||||
#define CFG_OVERFLOW_INT (1 << 1)
|
||||
#define CFG_CAPSLOCK_INT (1 << 2)
|
||||
#define CFG_NUMLOCK_INT (1 << 3)
|
||||
#define CFG_KEY_INT (1 << 4)
|
||||
#define CFG_PANIC_INT (1 << 5)
|
||||
#define CFG_REPORT_MODS (1 << 6)
|
||||
#define CFG_USE_MODS (1 << 7)
|
||||
|
||||
#define INT_OVERFLOW (1 << 0)
|
||||
#define INT_CAPSLOCK (1 << 1)
|
||||
#define INT_NUMLOCK (1 << 2)
|
||||
#define INT_KEY (1 << 3)
|
||||
#define INT_PANIC (1 << 4)
|
||||
|
||||
#define KEY_CAPSLOCK (1 << 5)
|
||||
#define KEY_NUMLOCK (1 << 6)
|
||||
#define KEY_COUNT_MASK (0x1F)
|
||||
|
||||
BBQ10Keyboard::BBQ10Keyboard() : m_wire(nullptr), m_addr(0), readCallback(nullptr), writeCallback(nullptr) {}
|
||||
|
||||
void BBQ10Keyboard::begin(uint8_t addr, TwoWire *wire)
|
||||
{
|
||||
m_addr = addr;
|
||||
m_wire = wire;
|
||||
|
||||
m_wire->begin();
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
void BBQ10Keyboard::begin(i2c_com_fptr_t r, i2c_com_fptr_t w, uint8_t addr)
|
||||
{
|
||||
m_addr = addr;
|
||||
m_wire = nullptr;
|
||||
writeCallback = w;
|
||||
readCallback = r;
|
||||
reset();
|
||||
}
|
||||
|
||||
void BBQ10Keyboard::reset()
|
||||
{
|
||||
if (m_wire) {
|
||||
m_wire->beginTransmission(m_addr);
|
||||
m_wire->write(_REG_RST);
|
||||
m_wire->endTransmission();
|
||||
}
|
||||
if (writeCallback) {
|
||||
uint8_t data = 0;
|
||||
writeCallback(m_addr, _REG_RST, &data, 0);
|
||||
}
|
||||
delay(100);
|
||||
writeRegister(_REG_CFG, readRegister8(_REG_CFG) | CFG_REPORT_MODS);
|
||||
delay(100);
|
||||
}
|
||||
|
||||
void BBQ10Keyboard::attachInterrupt(uint8_t pin, void (*func)(void)) const
|
||||
{
|
||||
pinMode(pin, INPUT_PULLUP);
|
||||
::attachInterrupt(digitalPinToInterrupt(pin), func, RISING);
|
||||
}
|
||||
|
||||
void BBQ10Keyboard::detachInterrupt(uint8_t pin) const
|
||||
{
|
||||
::detachInterrupt(pin);
|
||||
}
|
||||
|
||||
void BBQ10Keyboard::clearInterruptStatus()
|
||||
{
|
||||
writeRegister(_REG_INT, 0x00);
|
||||
}
|
||||
|
||||
uint8_t BBQ10Keyboard::status() const
|
||||
{
|
||||
return readRegister8(_REG_KEY);
|
||||
}
|
||||
|
||||
uint8_t BBQ10Keyboard::keyCount() const
|
||||
{
|
||||
return status() & KEY_COUNT_MASK;
|
||||
}
|
||||
|
||||
BBQ10Keyboard::KeyEvent BBQ10Keyboard::keyEvent() const
|
||||
{
|
||||
KeyEvent event = {.key = '\0', .state = StateIdle};
|
||||
|
||||
if (keyCount() == 0)
|
||||
return event;
|
||||
|
||||
const uint16_t buf = readRegister16(_REG_FIF);
|
||||
event.key = buf >> 8;
|
||||
event.state = KeyState(buf & 0xFF);
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
float BBQ10Keyboard::backlight() const
|
||||
{
|
||||
return readRegister8(_REG_BKL) / 255.0f;
|
||||
}
|
||||
|
||||
void BBQ10Keyboard::setBacklight(float value)
|
||||
{
|
||||
writeRegister(_REG_BKL, value * 255);
|
||||
}
|
||||
|
||||
uint8_t BBQ10Keyboard::readRegister8(uint8_t reg) const
|
||||
{
|
||||
if (m_wire) {
|
||||
m_wire->beginTransmission(m_addr);
|
||||
m_wire->write(reg);
|
||||
m_wire->endTransmission();
|
||||
|
||||
m_wire->requestFrom(m_addr, (uint8_t)1);
|
||||
if (m_wire->available() < 1)
|
||||
return 0;
|
||||
|
||||
return m_wire->read();
|
||||
}
|
||||
if (readCallback) {
|
||||
uint8_t data;
|
||||
readCallback(m_addr, reg, &data, 1);
|
||||
return data;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t BBQ10Keyboard::readRegister16(uint8_t reg) const
|
||||
{
|
||||
uint8_t data[2] = {0};
|
||||
// uint8_t low = 0, high = 0;
|
||||
if (m_wire) {
|
||||
m_wire->beginTransmission(m_addr);
|
||||
m_wire->write(reg);
|
||||
m_wire->endTransmission();
|
||||
|
||||
m_wire->requestFrom(m_addr, (uint8_t)2);
|
||||
if (m_wire->available() < 2)
|
||||
return 0;
|
||||
data[0] = m_wire->read();
|
||||
data[1] = m_wire->read();
|
||||
}
|
||||
if (readCallback) {
|
||||
readCallback(m_addr, reg, data, 2);
|
||||
}
|
||||
return (data[1] << 8) | data[0];
|
||||
}
|
||||
|
||||
void BBQ10Keyboard::writeRegister(uint8_t reg, uint8_t value)
|
||||
{
|
||||
uint8_t data[2];
|
||||
data[0] = reg | _WRITE_MASK;
|
||||
data[1] = value;
|
||||
|
||||
if (m_wire) {
|
||||
m_wire->beginTransmission(m_addr);
|
||||
m_wire->write(data, sizeof(uint8_t) * 2);
|
||||
m_wire->endTransmission();
|
||||
}
|
||||
if (writeCallback) {
|
||||
writeCallback(m_addr, data[0], &(data[1]), 1);
|
||||
}
|
||||
}
|
||||
51
src/input/BBQ10Keyboard.h
Normal file
51
src/input/BBQ10Keyboard.h
Normal file
@@ -0,0 +1,51 @@
|
||||
// Based on arturo182 arduino_bbq10kbd library https://github.com/arturo182/arduino_bbq10kbd
|
||||
|
||||
#include "configuration.h"
|
||||
#include <Wire.h>
|
||||
|
||||
#define KEY_MOD_ALT (0x1A)
|
||||
#define KEY_MOD_SHL (0x1B)
|
||||
#define KEY_MOD_SHR (0x1C)
|
||||
#define KEY_MOD_SYM (0x1D)
|
||||
|
||||
class BBQ10Keyboard
|
||||
{
|
||||
public:
|
||||
typedef uint8_t (*i2c_com_fptr_t)(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data, uint8_t len);
|
||||
|
||||
enum KeyState { StateIdle = 0, StatePress, StateLongPress, StateRelease };
|
||||
|
||||
struct KeyEvent {
|
||||
char key;
|
||||
KeyState state;
|
||||
};
|
||||
|
||||
BBQ10Keyboard();
|
||||
|
||||
void begin(uint8_t addr = BBQ10_KB_ADDR, TwoWire *wire = &Wire);
|
||||
|
||||
void begin(i2c_com_fptr_t r, i2c_com_fptr_t w, uint8_t addr = BBQ10_KB_ADDR);
|
||||
|
||||
void reset(void);
|
||||
|
||||
void attachInterrupt(uint8_t pin, void (*func)(void)) const;
|
||||
void detachInterrupt(uint8_t pin) const;
|
||||
void clearInterruptStatus(void);
|
||||
|
||||
uint8_t status(void) const;
|
||||
uint8_t keyCount(void) const;
|
||||
KeyEvent keyEvent(void) const;
|
||||
|
||||
float backlight() const;
|
||||
void setBacklight(float value);
|
||||
|
||||
uint8_t readRegister8(uint8_t reg) const;
|
||||
uint16_t readRegister16(uint8_t reg) const;
|
||||
void writeRegister(uint8_t reg, uint8_t value);
|
||||
|
||||
private:
|
||||
TwoWire *m_wire;
|
||||
uint8_t m_addr;
|
||||
i2c_com_fptr_t readCallback;
|
||||
i2c_com_fptr_t writeCallback;
|
||||
};
|
||||
@@ -5,12 +5,12 @@ RotaryEncoderInterruptImpl1 *rotaryEncoderInterruptImpl1;
|
||||
|
||||
RotaryEncoderInterruptImpl1::RotaryEncoderInterruptImpl1() : RotaryEncoderInterruptBase("rotEnc1") {}
|
||||
|
||||
void RotaryEncoderInterruptImpl1::init()
|
||||
bool RotaryEncoderInterruptImpl1::init()
|
||||
{
|
||||
if (!moduleConfig.canned_message.rotary1_enabled) {
|
||||
// Input device is disabled.
|
||||
disable();
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t pinA = moduleConfig.canned_message.inputbroker_pin_a;
|
||||
@@ -25,6 +25,7 @@ void RotaryEncoderInterruptImpl1::init()
|
||||
RotaryEncoderInterruptImpl1::handleIntA, RotaryEncoderInterruptImpl1::handleIntB,
|
||||
RotaryEncoderInterruptImpl1::handleIntPressed);
|
||||
inputBroker->registerSource(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
void RotaryEncoderInterruptImpl1::handleIntA()
|
||||
@@ -38,4 +39,4 @@ void RotaryEncoderInterruptImpl1::handleIntB()
|
||||
void RotaryEncoderInterruptImpl1::handleIntPressed()
|
||||
{
|
||||
rotaryEncoderInterruptImpl1->intPressHandler();
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ class RotaryEncoderInterruptImpl1 : public RotaryEncoderInterruptBase
|
||||
{
|
||||
public:
|
||||
RotaryEncoderInterruptImpl1();
|
||||
void init();
|
||||
bool init();
|
||||
static void handleIntA();
|
||||
static void handleIntB();
|
||||
static void handleIntPressed();
|
||||
|
||||
@@ -40,13 +40,13 @@ int32_t TouchScreenBase::runOnce()
|
||||
int16_t x, y;
|
||||
bool touched = getTouch(x, y);
|
||||
if (touched) {
|
||||
hapticFeedback();
|
||||
this->setInterval(20);
|
||||
_last_x = x;
|
||||
_last_y = y;
|
||||
}
|
||||
if (touched != _touchedOld) {
|
||||
if (touched) {
|
||||
hapticFeedback();
|
||||
_state = TOUCH_EVENT_OCCURRED;
|
||||
_start = millis();
|
||||
_first_x = x;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "TouchScreenImpl1.h"
|
||||
#include "InputBroker.h"
|
||||
#include "PowerFSM.h"
|
||||
#include "configuration.h"
|
||||
|
||||
TouchScreenImpl1 *touchScreenImpl1;
|
||||
@@ -61,6 +62,10 @@ void TouchScreenImpl1::onEvent(const TouchEvent &event)
|
||||
e.inputEvent = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL);
|
||||
break;
|
||||
}
|
||||
case TOUCH_ACTION_TAP: {
|
||||
powerFSM.trigger(EVENT_INPUT);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
#include "TrackballInterruptBase.h"
|
||||
#include "configuration.h"
|
||||
|
||||
TrackballInterruptBase::TrackballInterruptBase(const char *name)
|
||||
{
|
||||
this->_originName = name;
|
||||
}
|
||||
TrackballInterruptBase::TrackballInterruptBase(const char *name) : concurrency::OSThread(name), _originName(name) {}
|
||||
|
||||
void TrackballInterruptBase::init(uint8_t pinDown, uint8_t pinUp, uint8_t pinLeft, uint8_t pinRight, uint8_t pinPress,
|
||||
char eventDown, char eventUp, char eventLeft, char eventRight, char eventPressed,
|
||||
@@ -35,44 +32,64 @@ void TrackballInterruptBase::init(uint8_t pinDown, uint8_t pinUp, uint8_t pinLef
|
||||
|
||||
LOG_DEBUG("Trackball GPIO initialized (%d, %d, %d, %d, %d)\n", this->_pinUp, this->_pinDown, this->_pinLeft, this->_pinRight,
|
||||
pinPress);
|
||||
|
||||
this->setInterval(100);
|
||||
}
|
||||
|
||||
int32_t TrackballInterruptBase::runOnce()
|
||||
{
|
||||
InputEvent e;
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
|
||||
|
||||
if (this->action == TB_ACTION_PRESSED) {
|
||||
// LOG_DEBUG("Trackball event Press\n");
|
||||
e.inputEvent = this->_eventPressed;
|
||||
} else if (this->action == TB_ACTION_UP) {
|
||||
// LOG_DEBUG("Trackball event UP\n");
|
||||
e.inputEvent = this->_eventUp;
|
||||
} else if (this->action == TB_ACTION_DOWN) {
|
||||
// LOG_DEBUG("Trackball event DOWN\n");
|
||||
e.inputEvent = this->_eventDown;
|
||||
} else if (this->action == TB_ACTION_LEFT) {
|
||||
// LOG_DEBUG("Trackball event LEFT\n");
|
||||
e.inputEvent = this->_eventLeft;
|
||||
} else if (this->action == TB_ACTION_RIGHT) {
|
||||
// LOG_DEBUG("Trackball event RIGHT\n");
|
||||
e.inputEvent = this->_eventRight;
|
||||
}
|
||||
|
||||
if (e.inputEvent != meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE) {
|
||||
e.source = this->_originName;
|
||||
e.kbchar = 0x00;
|
||||
this->notifyObservers(&e);
|
||||
}
|
||||
|
||||
this->action = TB_ACTION_NONE;
|
||||
|
||||
return 100;
|
||||
}
|
||||
|
||||
void TrackballInterruptBase::intPressHandler()
|
||||
{
|
||||
InputEvent e;
|
||||
e.source = this->_originName;
|
||||
e.inputEvent = this->_eventPressed;
|
||||
this->notifyObservers(&e);
|
||||
this->action = TB_ACTION_PRESSED;
|
||||
}
|
||||
|
||||
void TrackballInterruptBase::intDownHandler()
|
||||
{
|
||||
InputEvent e;
|
||||
e.source = this->_originName;
|
||||
e.inputEvent = this->_eventDown;
|
||||
this->notifyObservers(&e);
|
||||
this->action = TB_ACTION_DOWN;
|
||||
}
|
||||
|
||||
void TrackballInterruptBase::intUpHandler()
|
||||
{
|
||||
InputEvent e;
|
||||
e.source = this->_originName;
|
||||
e.inputEvent = this->_eventUp;
|
||||
this->notifyObservers(&e);
|
||||
this->action = TB_ACTION_UP;
|
||||
}
|
||||
|
||||
void TrackballInterruptBase::intLeftHandler()
|
||||
{
|
||||
InputEvent e;
|
||||
e.source = this->_originName;
|
||||
e.inputEvent = this->_eventLeft;
|
||||
this->notifyObservers(&e);
|
||||
this->action = TB_ACTION_LEFT;
|
||||
}
|
||||
|
||||
void TrackballInterruptBase::intRightHandler()
|
||||
{
|
||||
InputEvent e;
|
||||
e.source = this->_originName;
|
||||
e.inputEvent = this->_eventRight;
|
||||
this->notifyObservers(&e);
|
||||
this->action = TB_ACTION_RIGHT;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include "InputBroker.h"
|
||||
#include "mesh/NodeDB.h"
|
||||
|
||||
class TrackballInterruptBase : public Observable<const InputEvent *>
|
||||
class TrackballInterruptBase : public Observable<const InputEvent *>, public concurrency::OSThread
|
||||
{
|
||||
public:
|
||||
explicit TrackballInterruptBase(const char *name);
|
||||
@@ -16,6 +16,20 @@ class TrackballInterruptBase : public Observable<const InputEvent *>
|
||||
void intLeftHandler();
|
||||
void intRightHandler();
|
||||
|
||||
virtual int32_t runOnce() override;
|
||||
|
||||
protected:
|
||||
enum TrackballInterruptBaseActionType {
|
||||
TB_ACTION_NONE,
|
||||
TB_ACTION_PRESSED,
|
||||
TB_ACTION_UP,
|
||||
TB_ACTION_DOWN,
|
||||
TB_ACTION_LEFT,
|
||||
TB_ACTION_RIGHT
|
||||
};
|
||||
|
||||
volatile TrackballInterruptBaseActionType action = TB_ACTION_NONE;
|
||||
|
||||
private:
|
||||
uint8_t _pinDown = 0;
|
||||
uint8_t _pinUp = 0;
|
||||
|
||||
@@ -5,12 +5,12 @@ UpDownInterruptImpl1 *upDownInterruptImpl1;
|
||||
|
||||
UpDownInterruptImpl1::UpDownInterruptImpl1() : UpDownInterruptBase("upDown1") {}
|
||||
|
||||
void UpDownInterruptImpl1::init()
|
||||
bool UpDownInterruptImpl1::init()
|
||||
{
|
||||
|
||||
if (!moduleConfig.canned_message.updown1_enabled) {
|
||||
// Input device is disabled.
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t pinUp = moduleConfig.canned_message.inputbroker_pin_a;
|
||||
@@ -24,6 +24,7 @@ void UpDownInterruptImpl1::init()
|
||||
UpDownInterruptBase::init(pinDown, pinUp, pinPress, eventDown, eventUp, eventPressed, UpDownInterruptImpl1::handleIntDown,
|
||||
UpDownInterruptImpl1::handleIntUp, UpDownInterruptImpl1::handleIntPressed);
|
||||
inputBroker->registerSource(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
void UpDownInterruptImpl1::handleIntDown()
|
||||
@@ -37,4 +38,4 @@ void UpDownInterruptImpl1::handleIntUp()
|
||||
void UpDownInterruptImpl1::handleIntPressed()
|
||||
{
|
||||
upDownInterruptImpl1->intPressHandler();
|
||||
}
|
||||
}
|
||||
@@ -5,10 +5,10 @@ class UpDownInterruptImpl1 : public UpDownInterruptBase
|
||||
{
|
||||
public:
|
||||
UpDownInterruptImpl1();
|
||||
void init();
|
||||
bool init();
|
||||
static void handleIntDown();
|
||||
static void handleIntUp();
|
||||
static void handleIntPressed();
|
||||
};
|
||||
|
||||
extern UpDownInterruptImpl1 *upDownInterruptImpl1;
|
||||
extern UpDownInterruptImpl1 *upDownInterruptImpl1;
|
||||
@@ -7,7 +7,7 @@ CardKbI2cImpl::CardKbI2cImpl() : KbI2cBase("cardKB") {}
|
||||
|
||||
void CardKbI2cImpl::init()
|
||||
{
|
||||
if (cardkb_found.address != CARDKB_ADDR && cardkb_found.address != TDECK_KB_ADDR) {
|
||||
if (cardkb_found.address == 0x00) {
|
||||
disable();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -28,20 +28,9 @@ uint8_t read_from_14004(TwoWire *i2cBus, uint8_t reg, uint8_t *data, uint8_t len
|
||||
return readflag;
|
||||
}
|
||||
|
||||
// Unused for now - flagging it off
|
||||
#if 0
|
||||
void write_to_14004(const TwoWire * i2cBus, uint8_t reg, uint8_t data)
|
||||
{
|
||||
i2cBus->beginTransmission(CARDKB_ADDR);
|
||||
i2cBus->write(reg);
|
||||
i2cBus->write(data);
|
||||
i2cBus->endTransmission(); // stop transmitting
|
||||
}
|
||||
#endif
|
||||
|
||||
int32_t KbI2cBase::runOnce()
|
||||
{
|
||||
if (cardkb_found.address != CARDKB_ADDR && cardkb_found.address != TDECK_KB_ADDR) {
|
||||
if (cardkb_found.address == 0x00) {
|
||||
// Input device is not detected.
|
||||
return INT32_MAX;
|
||||
}
|
||||
@@ -52,11 +41,19 @@ int32_t KbI2cBase::runOnce()
|
||||
#ifdef I2C_SDA1
|
||||
LOG_DEBUG("Using I2C Bus 1 (the second one)\n");
|
||||
i2cBus = &Wire1;
|
||||
if (cardkb_found.address == BBQ10_KB_ADDR) {
|
||||
Q10keyboard.begin(BBQ10_KB_ADDR, &Wire1);
|
||||
Q10keyboard.setBacklight(0);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case ScanI2C::WIRE:
|
||||
LOG_DEBUG("Using I2C Bus 0 (the first one)\n");
|
||||
i2cBus = &Wire;
|
||||
if (cardkb_found.address == BBQ10_KB_ADDR) {
|
||||
Q10keyboard.begin(BBQ10_KB_ADDR, &Wire);
|
||||
Q10keyboard.setBacklight(0);
|
||||
}
|
||||
break;
|
||||
case ScanI2C::NO_I2C:
|
||||
default:
|
||||
@@ -64,7 +61,105 @@ int32_t KbI2cBase::runOnce()
|
||||
}
|
||||
}
|
||||
|
||||
if (kb_model == 0x02) {
|
||||
switch (kb_model) {
|
||||
case 0x11: { // BB Q10
|
||||
int keyCount = Q10keyboard.keyCount();
|
||||
while (keyCount--) {
|
||||
const BBQ10Keyboard::KeyEvent key = Q10keyboard.keyEvent();
|
||||
if ((key.key != 0x00) && (key.state == BBQ10Keyboard::StateRelease)) {
|
||||
InputEvent e;
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
|
||||
e.source = this->_originName;
|
||||
switch (key.key) {
|
||||
case 'p': // TAB
|
||||
case 't': // TAB as well
|
||||
if (is_sym) {
|
||||
e.inputEvent = ANYKEY;
|
||||
e.kbchar = 0x09; // TAB Scancode
|
||||
is_sym = false; // reset sym state after second keypress
|
||||
} else {
|
||||
e.inputEvent = ANYKEY;
|
||||
e.kbchar = key.key;
|
||||
}
|
||||
break;
|
||||
case 'q': // ESC
|
||||
if (is_sym) {
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL;
|
||||
e.kbchar = 0x1b;
|
||||
is_sym = false; // reset sym state after second keypress
|
||||
} else {
|
||||
e.inputEvent = ANYKEY;
|
||||
e.kbchar = key.key;
|
||||
}
|
||||
break;
|
||||
case 0x08: // Back
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_BACK;
|
||||
e.kbchar = key.key;
|
||||
break;
|
||||
case 'e': // sym e
|
||||
if (is_sym) {
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP;
|
||||
e.kbchar = 0xb5;
|
||||
is_sym = false; // reset sym state after second keypress
|
||||
} else {
|
||||
e.inputEvent = ANYKEY;
|
||||
e.kbchar = key.key;
|
||||
}
|
||||
break;
|
||||
case 'x': // sym x
|
||||
if (is_sym) {
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN;
|
||||
e.kbchar = 0xb6;
|
||||
is_sym = false; // reset sym state after second keypress
|
||||
} else {
|
||||
e.inputEvent = ANYKEY;
|
||||
e.kbchar = key.key;
|
||||
}
|
||||
break;
|
||||
case 's': // sym s
|
||||
if (is_sym) {
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT;
|
||||
e.kbchar = 0x00; // tweak for destSelect
|
||||
is_sym = false; // reset sym state after second keypress
|
||||
} else {
|
||||
e.inputEvent = ANYKEY;
|
||||
e.kbchar = key.key;
|
||||
}
|
||||
break;
|
||||
case 'f': // sym f
|
||||
if (is_sym) {
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT;
|
||||
e.kbchar = 0x00; // tweak for destSelect
|
||||
is_sym = false; // reset sym state after second keypress
|
||||
} else {
|
||||
e.inputEvent = ANYKEY;
|
||||
e.kbchar = key.key;
|
||||
}
|
||||
break;
|
||||
case 0x13: // Code scanner says the SYM key is 0x13
|
||||
is_sym = !is_sym;
|
||||
break;
|
||||
case 0x0a: // apparently Enter on Q10 is a line feed instead of carriage return
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT;
|
||||
break;
|
||||
case 0x00: // nopress
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
|
||||
break;
|
||||
default: // all other keys
|
||||
e.inputEvent = ANYKEY;
|
||||
e.kbchar = key.key;
|
||||
is_sym = false; // reset sym state after second keypress
|
||||
break;
|
||||
}
|
||||
|
||||
if (e.inputEvent != meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE) {
|
||||
this->notifyObservers(&e);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x02: {
|
||||
// RAK14004
|
||||
uint8_t rDataBuf[8] = {0};
|
||||
uint8_t PrintDataBuf = 0;
|
||||
@@ -85,9 +180,12 @@ int32_t KbI2cBase::runOnce()
|
||||
e.kbchar = PrintDataBuf;
|
||||
this->notifyObservers(&e);
|
||||
}
|
||||
} else if (kb_model == 0x00 || kb_model == 0x10) {
|
||||
// m5 cardkb and T-Deck
|
||||
i2cBus->requestFrom(kb_model == 0x00 ? CARDKB_ADDR : TDECK_KB_ADDR, 1);
|
||||
break;
|
||||
}
|
||||
case 0x00: // CARDKB
|
||||
case 0x10: { // T-DECK
|
||||
|
||||
i2cBus->requestFrom((int)cardkb_found.address, 1);
|
||||
|
||||
while (i2cBus->available()) {
|
||||
char c = i2cBus->read();
|
||||
@@ -104,17 +202,19 @@ int32_t KbI2cBase::runOnce()
|
||||
break;
|
||||
case 0xb5: // Up
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP;
|
||||
e.kbchar = 0xb5;
|
||||
break;
|
||||
case 0xb6: // Down
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN;
|
||||
e.kbchar = 0xb6;
|
||||
break;
|
||||
case 0xb4: // Left
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT;
|
||||
e.kbchar = c;
|
||||
e.kbchar = 0xb4;
|
||||
break;
|
||||
case 0xb7: // Right
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT;
|
||||
e.kbchar = c;
|
||||
e.kbchar = 0xb7;
|
||||
break;
|
||||
case 0x0d: // Enter
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT;
|
||||
@@ -132,7 +232,9 @@ int32_t KbI2cBase::runOnce()
|
||||
this->notifyObservers(&e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LOG_WARN("Unknown kb_model 0x%02x\n", kb_model);
|
||||
}
|
||||
return 300;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "BBQ10Keyboard.h"
|
||||
#include "InputBroker.h"
|
||||
#include "Wire.h"
|
||||
#include "concurrency/OSThread.h"
|
||||
@@ -16,4 +17,7 @@ class KbI2cBase : public Observable<const InputEvent *>, public concurrency::OST
|
||||
const char *_originName;
|
||||
|
||||
TwoWire *i2cBus = 0;
|
||||
|
||||
BBQ10Keyboard Q10keyboard;
|
||||
bool is_sym = false;
|
||||
};
|
||||
|
||||
131
src/input/kbMatrixBase.cpp
Normal file
131
src/input/kbMatrixBase.cpp
Normal file
@@ -0,0 +1,131 @@
|
||||
#include "kbMatrixBase.h"
|
||||
#include "configuration.h"
|
||||
|
||||
#ifdef INPUTBROKER_MATRIX_TYPE
|
||||
|
||||
const byte keys_cols[] = KEYS_COLS;
|
||||
const byte keys_rows[] = KEYS_ROWS;
|
||||
|
||||
#if INPUTBROKER_MATRIX_TYPE == 1
|
||||
|
||||
unsigned char KeyMap[3][sizeof(keys_rows)][sizeof(keys_cols)] = {{{' ', '.', 'm', 'n', 'b', 0xb6},
|
||||
{0x0d, 'l', 'k', 'j', 'h', 0xb4},
|
||||
{'p', 'o', 'i', 'u', 'y', 0xb5},
|
||||
{0x08, 'z', 'x', 'c', 'v', 0xb7},
|
||||
{'a', 's', 'd', 'f', 'g', 0x09},
|
||||
{'q', 'w', 'e', 'r', 't', 0x1a}},
|
||||
{// SHIFT
|
||||
{':', ';', 'M', 'N', 'B', 0xb6},
|
||||
{0x0d, 'L', 'K', 'J', 'H', 0xb4},
|
||||
{'P', 'O', 'I', 'U', 'Y', 0xb5},
|
||||
{0x08, 'Z', 'X', 'C', 'V', 0xb7},
|
||||
{'A', 'S', 'D', 'F', 'G', 0x09},
|
||||
{'Q', 'W', 'E', 'R', 'T', 0x1a}},
|
||||
{// SHIFT-SHIFT
|
||||
{'_', ',', '>', '<', '"', '{'},
|
||||
{'~', '-', '*', '&', '+', '['},
|
||||
{'0', '9', '8', '7', '6', '}'},
|
||||
{'=', '(', ')', '?', '/', ']'},
|
||||
{'!', '@', '#', '$', '%', '\\'},
|
||||
{'1', '2', '3', '4', '5', 0x1a}}};
|
||||
#endif
|
||||
|
||||
KbMatrixBase::KbMatrixBase(const char *name) : concurrency::OSThread(name)
|
||||
{
|
||||
this->_originName = name;
|
||||
}
|
||||
|
||||
int32_t KbMatrixBase::runOnce()
|
||||
{
|
||||
if (!INPUTBROKER_MATRIX_TYPE) {
|
||||
// Input device is not requested.
|
||||
return disable();
|
||||
}
|
||||
|
||||
if (firstTime) {
|
||||
// This is the first time the OSThread library has called this function, so do port setup
|
||||
firstTime = 0;
|
||||
for (byte i = 0; i < sizeof(keys_rows); i++) {
|
||||
pinMode(keys_rows[i], OUTPUT);
|
||||
digitalWrite(keys_rows[i], HIGH);
|
||||
}
|
||||
for (byte i = 0; i < sizeof(keys_cols); i++) {
|
||||
pinMode(keys_cols[i], INPUT_PULLUP);
|
||||
}
|
||||
}
|
||||
|
||||
key = 0;
|
||||
|
||||
if (INPUTBROKER_MATRIX_TYPE == 1) {
|
||||
// scan for keypresses
|
||||
for (byte i = 0; i < sizeof(keys_rows); i++) {
|
||||
digitalWrite(keys_rows[i], LOW);
|
||||
for (byte j = 0; j < sizeof(keys_cols); j++) {
|
||||
if (digitalRead(keys_cols[j]) == LOW) {
|
||||
key = KeyMap[shift][i][j];
|
||||
}
|
||||
}
|
||||
digitalWrite(keys_rows[i], HIGH);
|
||||
}
|
||||
// debounce
|
||||
if (key != prevkey) {
|
||||
if (key != 0) {
|
||||
LOG_DEBUG("Key 0x%x pressed\n", key);
|
||||
// reset shift now that we have a keypress
|
||||
InputEvent e;
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
|
||||
e.source = this->_originName;
|
||||
switch (key) {
|
||||
case 0x1b: // ESC
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL;
|
||||
break;
|
||||
case 0x08: // Back
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_BACK;
|
||||
e.kbchar = key;
|
||||
break;
|
||||
case 0xb5: // Up
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP;
|
||||
break;
|
||||
case 0xb6: // Down
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN;
|
||||
break;
|
||||
case 0xb4: // Left
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT;
|
||||
e.kbchar = key;
|
||||
break;
|
||||
case 0xb7: // Right
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT;
|
||||
e.kbchar = key;
|
||||
break;
|
||||
case 0x0d: // Enter
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT;
|
||||
break;
|
||||
case 0x00: // nopress
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
|
||||
break;
|
||||
case 0x1a: // Shift
|
||||
shift++;
|
||||
if (shift > 2) {
|
||||
shift = 0;
|
||||
}
|
||||
break;
|
||||
default: // all other keys
|
||||
e.inputEvent = ANYKEY;
|
||||
e.kbchar = key;
|
||||
break;
|
||||
}
|
||||
if (e.inputEvent != meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE) {
|
||||
this->notifyObservers(&e);
|
||||
}
|
||||
}
|
||||
prevkey = key;
|
||||
}
|
||||
|
||||
} else {
|
||||
LOG_WARN("Unknown kb_model 0x%02x\n", INPUTBROKER_MATRIX_TYPE);
|
||||
return disable();
|
||||
}
|
||||
return 50; // Keyscan every 50msec to avoid key bounce
|
||||
}
|
||||
|
||||
#endif // INPUTBROKER_MATRIX_TYPE
|
||||
20
src/input/kbMatrixBase.h
Normal file
20
src/input/kbMatrixBase.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include "InputBroker.h"
|
||||
#include "concurrency/OSThread.h"
|
||||
|
||||
class KbMatrixBase : public Observable<const InputEvent *>, public concurrency::OSThread
|
||||
{
|
||||
public:
|
||||
explicit KbMatrixBase(const char *name);
|
||||
|
||||
protected:
|
||||
virtual int32_t runOnce() override;
|
||||
|
||||
private:
|
||||
const char *_originName;
|
||||
bool firstTime = 1;
|
||||
int shift = 0;
|
||||
char key = 0;
|
||||
char prevkey = 0;
|
||||
};
|
||||
20
src/input/kbMatrixImpl.cpp
Normal file
20
src/input/kbMatrixImpl.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#include "kbMatrixImpl.h"
|
||||
#include "InputBroker.h"
|
||||
|
||||
#ifdef INPUTBROKER_MATRIX_TYPE
|
||||
|
||||
KbMatrixImpl *kbMatrixImpl;
|
||||
|
||||
KbMatrixImpl::KbMatrixImpl() : KbMatrixBase("matrixKB") {}
|
||||
|
||||
void KbMatrixImpl::init()
|
||||
{
|
||||
if (!INPUTBROKER_MATRIX_TYPE) {
|
||||
disable();
|
||||
return;
|
||||
}
|
||||
|
||||
inputBroker->registerSource(this);
|
||||
}
|
||||
|
||||
#endif // INPUTBROKER_MATRIX_TYPE
|
||||
19
src/input/kbMatrixImpl.h
Normal file
19
src/input/kbMatrixImpl.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
#include "kbMatrixBase.h"
|
||||
#include "main.h"
|
||||
|
||||
/**
|
||||
* @brief The idea behind this class to have static methods for the event handlers.
|
||||
* Check attachInterrupt() at RotaryEncoderInteruptBase.cpp
|
||||
* Technically you can have as many rotary encoders hardver attached
|
||||
* to your device as you wish, but you always need to have separate event
|
||||
* handlers, thus you need to have a RotaryEncoderInterrupt implementation.
|
||||
*/
|
||||
class KbMatrixImpl : public KbMatrixBase
|
||||
{
|
||||
public:
|
||||
KbMatrixImpl();
|
||||
void init();
|
||||
};
|
||||
|
||||
extern KbMatrixImpl *kbMatrixImpl;
|
||||
46
src/main.cpp
46
src/main.cpp
@@ -73,6 +73,7 @@ NRF52Bluetooth *nrf52Bluetooth;
|
||||
|
||||
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
|
||||
#include "AccelerometerThread.h"
|
||||
#include "AmbientLightingThread.h"
|
||||
#endif
|
||||
|
||||
using namespace concurrency;
|
||||
@@ -169,6 +170,7 @@ static OSThread *buttonThread;
|
||||
uint32_t ButtonThread::longPressTime = 0;
|
||||
#endif
|
||||
static OSThread *accelerometerThread;
|
||||
static OSThread *ambientLightingThread;
|
||||
SPISettings spiSettings(4000000, MSBFIRST, SPI_MODE0);
|
||||
|
||||
RadioInterface *rIf = NULL;
|
||||
@@ -219,11 +221,6 @@ void setup()
|
||||
digitalWrite(VEXT_ENABLE, 0); // turn on the display power
|
||||
#endif
|
||||
|
||||
#ifdef VGNSS_CTRL
|
||||
pinMode(VGNSS_CTRL, OUTPUT);
|
||||
digitalWrite(VGNSS_CTRL, LOW);
|
||||
#endif
|
||||
|
||||
#if defined(VTFT_CTRL)
|
||||
pinMode(VTFT_CTRL, OUTPUT);
|
||||
digitalWrite(VTFT_CTRL, LOW);
|
||||
@@ -387,6 +384,10 @@ void setup()
|
||||
// assign an arbitrary value to distinguish from other models
|
||||
kb_model = 0x10;
|
||||
break;
|
||||
case ScanI2C::DeviceType::BBQ10KB:
|
||||
// assign an arbitrary value to distinguish from other models
|
||||
kb_model = 0x11;
|
||||
break;
|
||||
default:
|
||||
// use this as default since it's also just zero
|
||||
LOG_WARN("kb_info.type is unknown(0x%02x), setting kb_model=0x00\n", kb_info.type);
|
||||
@@ -405,14 +406,6 @@ void setup()
|
||||
// Only one supported RGB LED currently
|
||||
#ifdef HAS_NCP5623
|
||||
rgb_found = i2cScanner->find(ScanI2C::DeviceType::NCP5623);
|
||||
|
||||
// Start the RGB LED at 50%
|
||||
|
||||
if (rgb_found.type == ScanI2C::NCP5623) {
|
||||
rgb.begin();
|
||||
rgb.setCurrent(10);
|
||||
rgb.setColor(128, 128, 128);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
|
||||
@@ -480,7 +473,7 @@ void setup()
|
||||
#endif
|
||||
|
||||
// We do this as early as possible because this loads preferences from flash
|
||||
// but we need to do this after main cpu iniot (esp32setup), because we need the random seed set
|
||||
// but we need to do this after main cpu init (esp32setup), because we need the random seed set
|
||||
nodeDB.init();
|
||||
|
||||
// If we're taking on the repeater role, use flood router
|
||||
@@ -517,6 +510,12 @@ void setup()
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
|
||||
if (rgb_found.type != ScanI2C::DeviceType::NONE) {
|
||||
ambientLightingThread = new AmbientLightingThread(rgb_found.type);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef T_WATCH_S3
|
||||
drv.begin();
|
||||
drv.selectLibrary(1);
|
||||
@@ -545,6 +544,7 @@ void setup()
|
||||
#else
|
||||
// ESP32
|
||||
SPI.begin(RF95_SCK, RF95_MISO, RF95_MOSI, RF95_NSS);
|
||||
LOG_WARN("SPI.begin(SCK=%d, MISO=%d, MOSI=%d, NSS=%d)\n", RF95_SCK, RF95_MISO, RF95_MOSI, RF95_NSS);
|
||||
SPI.setFrequency(4000000);
|
||||
#endif
|
||||
|
||||
@@ -553,14 +553,12 @@ void setup()
|
||||
|
||||
readFromRTC(); // read the main CPU RTC at first (in case we can't get GPS time)
|
||||
|
||||
gps = createGps();
|
||||
|
||||
gps = GPS::createGps();
|
||||
if (gps) {
|
||||
gpsStatus->observe(&gps->newStatus);
|
||||
} else {
|
||||
LOG_WARN("No GPS found - running without GPS\n");
|
||||
LOG_DEBUG("Running without GPS.\n");
|
||||
}
|
||||
|
||||
nodeStatus->observe(&nodeDB.newStatus);
|
||||
|
||||
service.init();
|
||||
@@ -585,17 +583,6 @@ void setup()
|
||||
|
||||
screen->print("Started...\n");
|
||||
|
||||
// We have now loaded our saved preferences from flash
|
||||
|
||||
// ONCE we will factory reset the GPS for bug #327
|
||||
if (gps && !devicestate.did_gps_reset) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SX126X_ANT_SW
|
||||
// make analog PA vs not PA switch on SX126x eval board work properly
|
||||
pinMode(SX126X_ANT_SW, OUTPUT);
|
||||
@@ -750,7 +737,6 @@ void setup()
|
||||
PowerFSM_setup(); // we will transition to ON in a couple of seconds, FIXME, only do this for cold boots, not waking from SDS
|
||||
powerFSMthread = new PowerFSMThread();
|
||||
|
||||
// setBluetoothEnable(false); we now don't start bluetooth until we enter the proper state
|
||||
setCPUFast(false); // 80MHz is fine for our slow peripherals
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,21 @@
|
||||
/**
|
||||
* @file memGet.cpp
|
||||
* @brief Implementation of MemGet class that provides functions to get memory information.
|
||||
*
|
||||
* This file contains the implementation of MemGet class that provides functions to get
|
||||
* information about free heap, heap size, free psram and psram size. The functions are
|
||||
* implemented for ESP32 and NRF52 architectures. If the platform does not have heap
|
||||
* management function implemented, the functions return UINT32_MAX or 0.
|
||||
*/
|
||||
#include "memGet.h"
|
||||
#include "configuration.h"
|
||||
|
||||
MemGet memGet;
|
||||
|
||||
/**
|
||||
* Returns the amount of free heap memory in bytes.
|
||||
* @return uint32_t The amount of free heap memory in bytes.
|
||||
*/
|
||||
uint32_t MemGet::getFreeHeap()
|
||||
{
|
||||
#ifdef ARCH_ESP32
|
||||
@@ -15,6 +28,10 @@ uint32_t MemGet::getFreeHeap()
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of the heap memory in bytes.
|
||||
* @return uint32_t The size of the heap memory in bytes.
|
||||
*/
|
||||
uint32_t MemGet::getHeapSize()
|
||||
{
|
||||
#ifdef ARCH_ESP32
|
||||
@@ -27,6 +44,11 @@ uint32_t MemGet::getHeapSize()
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the amount of free psram memory in bytes.
|
||||
*
|
||||
* @return The amount of free psram memory in bytes.
|
||||
*/
|
||||
uint32_t MemGet::getFreePsram()
|
||||
{
|
||||
#ifdef ARCH_ESP32
|
||||
@@ -36,6 +58,11 @@ uint32_t MemGet::getFreePsram()
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the size of the PSRAM memory.
|
||||
*
|
||||
* @return uint32_t The size of the PSRAM memory.
|
||||
*/
|
||||
uint32_t MemGet::getPsramSize()
|
||||
{
|
||||
#ifdef ARCH_ESP32
|
||||
@@ -43,4 +70,4 @@ uint32_t MemGet::getPsramSize()
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -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 (config.device.role != meshtastic_Config_DeviceConfig_Role_ROUTER &&
|
||||
if (!moduleConfig.mqtt.enabled && 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,10 +49,13 @@ void FloodingRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas
|
||||
|
||||
tosend->hop_limit--; // bump down the hop count
|
||||
|
||||
// If it is a traceRoute request, update the route that it went via me
|
||||
if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag && traceRouteModule &&
|
||||
traceRouteModule->wantPacket(p)) {
|
||||
traceRouteModule->updateRoute(tosend);
|
||||
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");
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "PacketHistory.h"
|
||||
#include "Router.h"
|
||||
#include "modules/NeighborInfoModule.h"
|
||||
#include "modules/TraceRouteModule.h"
|
||||
|
||||
/**
|
||||
@@ -57,4 +58,4 @@ class FloodingRouter : public Router, protected PacketHistory
|
||||
* Look for broadcasts we need to rebroadcast
|
||||
*/
|
||||
virtual void sniffReceived(const meshtastic_MeshPacket *p, const meshtastic_Routing *c) override;
|
||||
};
|
||||
};
|
||||
@@ -82,8 +82,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
|
||||
if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag && !nodeDB.getMeshNode(mp->from)->has_user &&
|
||||
nodeInfoModule) {
|
||||
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 &&
|
||||
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);
|
||||
}
|
||||
@@ -315,28 +320,26 @@ meshtastic_NodeInfoLite *MeshService::refreshLocalMeshNode()
|
||||
int MeshService::onGPSChanged(const meshtastic::GPSStatus *newStatus)
|
||||
{
|
||||
// Update our local node info with our position (even if we don't decide to update anyone else)
|
||||
meshtastic_NodeInfoLite *node = refreshLocalMeshNode();
|
||||
const meshtastic_NodeInfoLite *node = refreshLocalMeshNode();
|
||||
meshtastic_Position pos = meshtastic_Position_init_default;
|
||||
|
||||
if (newStatus->getHasLock()) {
|
||||
// load data from GPS object, will add timestamp + battery further down
|
||||
pos = gps->p;
|
||||
} else {
|
||||
// The GPS has lost lock, if we are fixed position we should just keep using
|
||||
// the old position
|
||||
// The GPS has lost lock
|
||||
#ifdef GPS_EXTRAVERBOSE
|
||||
LOG_DEBUG("onGPSchanged() - lost validLocation\n");
|
||||
#endif
|
||||
if (config.position.fixed_position) {
|
||||
LOG_WARN("Using fixed position\n");
|
||||
pos = ConvertToPosition(node->position);
|
||||
}
|
||||
}
|
||||
// Used fixed position if configured regalrdless of GPS lock
|
||||
if (config.position.fixed_position) {
|
||||
LOG_WARN("Using fixed position\n");
|
||||
pos = ConvertToPosition(node->position);
|
||||
}
|
||||
|
||||
// Finally add a fresh timestamp and battery level reading
|
||||
// I KNOW this is redundant with refreshLocalMeshNode() above, but these are
|
||||
// inexpensive nonblocking calls and can be refactored in due course
|
||||
pos.time = getValidTime(RTCQualityGPS);
|
||||
// Add a fresh timestamp
|
||||
pos.time = getValidTime(RTCQualityFromNet);
|
||||
|
||||
// In debug logs, identify position by @timestamp:stage (stage 4 = nodeDB)
|
||||
LOG_DEBUG("onGPSChanged() pos@%x, time=%u, lat=%d, lon=%d, alt=%d\n", pos.timestamp, pos.time, pos.latitude_i,
|
||||
|
||||
@@ -48,6 +48,14 @@ class MeshService
|
||||
uint32_t oldFromNum = 0;
|
||||
|
||||
public:
|
||||
static bool isTextPayload(const meshtastic_MeshPacket *p)
|
||||
{
|
||||
if (moduleConfig.range_test.enabled && p->decoded.portnum == meshtastic_PortNum_RANGE_TEST_APP) {
|
||||
return true;
|
||||
}
|
||||
return p->decoded.portnum == meshtastic_PortNum_TEXT_MESSAGE_APP ||
|
||||
p->decoded.portnum == meshtastic_PortNum_DETECTION_SENSOR_APP;
|
||||
}
|
||||
/// Called when some new packets have arrived from one of the radios
|
||||
Observable<uint32_t> fromNumChanged;
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "error.h"
|
||||
#include "main.h"
|
||||
#include "mesh-pb-constants.h"
|
||||
#include "modules/NeighborInfoModule.h"
|
||||
#include <ErriezCRC32.h>
|
||||
#include <pb_decode.h>
|
||||
#include <pb_encode.h>
|
||||
@@ -63,11 +64,7 @@ uint32_t error_address = 0;
|
||||
|
||||
static uint8_t ourMacAddr[6];
|
||||
|
||||
NodeDB::NodeDB()
|
||||
: nodes(devicestate.node_db), numNodes(&devicestate.node_db_count), meshNodes(devicestate.node_db_lite),
|
||||
numMeshNodes(&devicestate.node_db_lite_count)
|
||||
{
|
||||
}
|
||||
NodeDB::NodeDB() : meshNodes(devicestate.node_db_lite), numMeshNodes(&devicestate.node_db_lite_count) {}
|
||||
|
||||
/**
|
||||
* Most (but not always) of the time we want to treat packets 'from' the local phone (where from == 0), as if they originated on
|
||||
@@ -109,7 +106,6 @@ bool NodeDB::resetRadioConfig(bool factory_reset)
|
||||
config.lora.region = meshtastic_Config_LoRaConfig_RegionCode_TW;
|
||||
|
||||
// Enter super deep sleep soon and stay there not very long
|
||||
// radioConfig.preferences.mesh_sds_timeout_secs = 10;
|
||||
// radioConfig.preferences.sds_secs = 60;
|
||||
}
|
||||
|
||||
@@ -173,6 +169,14 @@ void NodeDB::installDefaultConfig()
|
||||
config.lora.region = meshtastic_Config_LoRaConfig_RegionCode_UNSET;
|
||||
config.lora.modem_preset = meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST;
|
||||
config.lora.hop_limit = HOP_RELIABLE;
|
||||
#ifdef PIN_GPS_EN
|
||||
config.position.gps_en_gpio = PIN_GPS_EN;
|
||||
#endif
|
||||
#ifdef GPS_POWER_TOGGLE
|
||||
config.device.disable_triple_click = false;
|
||||
#else
|
||||
config.device.disable_triple_click = true;
|
||||
#endif
|
||||
config.position.gps_enabled = true;
|
||||
config.position.position_broadcast_smart_enabled = true;
|
||||
config.position.broadcast_smart_minimum_distance = 100;
|
||||
@@ -194,7 +198,9 @@ void NodeDB::installDefaultConfig()
|
||||
: meshtastic_Config_BluetoothConfig_PairingMode_FIXED_PIN;
|
||||
// for backward compat, default position flags are ALT+MSL
|
||||
config.position.position_flags =
|
||||
(meshtastic_Config_PositionConfig_PositionFlags_ALTITUDE | meshtastic_Config_PositionConfig_PositionFlags_ALTITUDE_MSL);
|
||||
(meshtastic_Config_PositionConfig_PositionFlags_ALTITUDE | meshtastic_Config_PositionConfig_PositionFlags_ALTITUDE_MSL |
|
||||
meshtastic_Config_PositionConfig_PositionFlags_SPEED | meshtastic_Config_PositionConfig_PositionFlags_HEADING |
|
||||
meshtastic_Config_PositionConfig_PositionFlags_DOP);
|
||||
|
||||
#ifdef T_WATCH_S3
|
||||
config.display.screen_on_secs = 30;
|
||||
@@ -211,7 +217,6 @@ void NodeDB::initConfigIntervals()
|
||||
config.position.position_broadcast_secs = default_broadcast_interval_secs;
|
||||
|
||||
config.power.ls_secs = default_ls_secs;
|
||||
config.power.mesh_sds_timeout_secs = default_mesh_sds_timeout_secs;
|
||||
config.power.min_wake_secs = default_min_wake_secs;
|
||||
config.power.sds_secs = default_sds_secs;
|
||||
config.power.wait_bluetooth_secs = default_wait_bluetooth_secs;
|
||||
@@ -250,6 +255,21 @@ void NodeDB::installDefaultModuleConfig()
|
||||
strncpy(moduleConfig.mqtt.username, default_mqtt_username, sizeof(moduleConfig.mqtt.username));
|
||||
strncpy(moduleConfig.mqtt.password, default_mqtt_password, sizeof(moduleConfig.mqtt.password));
|
||||
|
||||
moduleConfig.has_neighbor_info = true;
|
||||
moduleConfig.neighbor_info.enabled = false;
|
||||
|
||||
moduleConfig.has_detection_sensor = true;
|
||||
moduleConfig.detection_sensor.enabled = false;
|
||||
moduleConfig.detection_sensor.detection_triggered_high = true;
|
||||
moduleConfig.detection_sensor.minimum_broadcast_secs = 45;
|
||||
|
||||
moduleConfig.has_ambient_lighting = true;
|
||||
moduleConfig.ambient_lighting.current = 10;
|
||||
// Default to a color based on our node number
|
||||
moduleConfig.ambient_lighting.red = (myNodeInfo.my_node_num & 0xFF0000) >> 16;
|
||||
moduleConfig.ambient_lighting.green = (myNodeInfo.my_node_num & 0x00FF00) >> 8;
|
||||
moduleConfig.ambient_lighting.blue = myNodeInfo.my_node_num & 0x0000FF;
|
||||
|
||||
initModuleConfigIntervals();
|
||||
}
|
||||
|
||||
@@ -273,6 +293,7 @@ void NodeDB::initModuleConfigIntervals()
|
||||
moduleConfig.telemetry.device_update_interval = default_broadcast_interval_secs;
|
||||
moduleConfig.telemetry.environment_update_interval = default_broadcast_interval_secs;
|
||||
moduleConfig.telemetry.air_quality_interval = default_broadcast_interval_secs;
|
||||
moduleConfig.neighbor_info.update_interval = default_broadcast_interval_secs;
|
||||
}
|
||||
|
||||
void NodeDB::installDefaultChannels()
|
||||
@@ -284,12 +305,24 @@ void NodeDB::installDefaultChannels()
|
||||
|
||||
void NodeDB::resetNodes()
|
||||
{
|
||||
devicestate.node_db_count = 0;
|
||||
memset(devicestate.node_db, 0, sizeof(devicestate.node_db));
|
||||
|
||||
devicestate.node_db_lite_count = 0;
|
||||
memset(devicestate.node_db_lite, 0, sizeof(devicestate.node_db_lite));
|
||||
saveDeviceStateToDisk();
|
||||
if (neighborInfoModule && moduleConfig.neighbor_info.enabled)
|
||||
neighborInfoModule->resetNeighbors();
|
||||
}
|
||||
|
||||
void NodeDB::cleanupMeshDB()
|
||||
{
|
||||
int newPos = 0, removed = 0;
|
||||
for (int i = 0; i < *numMeshNodes; i++) {
|
||||
if (meshNodes[i].has_user)
|
||||
meshNodes[newPos++] = meshNodes[i];
|
||||
else
|
||||
removed++;
|
||||
}
|
||||
*numMeshNodes -= removed;
|
||||
LOG_DEBUG("cleanupMeshDB purged %d entries\n", removed);
|
||||
}
|
||||
|
||||
void NodeDB::installDefaultDeviceState()
|
||||
@@ -297,12 +330,11 @@ void NodeDB::installDefaultDeviceState()
|
||||
LOG_INFO("Installing default DeviceState\n");
|
||||
memset(&devicestate, 0, sizeof(meshtastic_DeviceState));
|
||||
|
||||
*numNodes = 0;
|
||||
*numMeshNodes = 0;
|
||||
|
||||
// init our devicestate with valid flags so protobuf writing/reading will work
|
||||
devicestate.has_my_node = true;
|
||||
devicestate.has_owner = true;
|
||||
devicestate.node_db_count = 0;
|
||||
devicestate.node_db_lite_count = 0;
|
||||
devicestate.version = DEVICESTATE_CUR_VER;
|
||||
devicestate.receive_queue_count = 0; // Not yet implemented FIXME
|
||||
@@ -322,6 +354,7 @@ void NodeDB::init()
|
||||
{
|
||||
LOG_INFO("Initializing NodeDB\n");
|
||||
loadFromDisk();
|
||||
cleanupMeshDB();
|
||||
|
||||
uint32_t devicestateCRC = crc32Buffer(&devicestate, sizeof(devicestate));
|
||||
uint32_t configCRC = crc32Buffer(&config, sizeof(config));
|
||||
@@ -330,11 +363,9 @@ void NodeDB::init()
|
||||
int saveWhat = 0;
|
||||
|
||||
// likewise - we always want the app requirements to come from the running appload
|
||||
myNodeInfo.min_app_version = 20300; // format is Mmmss (where M is 1+the numeric major number. i.e. 20120 means 1.1.20
|
||||
myNodeInfo.max_channels = MAX_NUM_CHANNELS; // tell others the max # of channels we can understand
|
||||
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)
|
||||
strncpy(myNodeInfo.firmware_version, optstr(APP_VERSION), sizeof(myNodeInfo.firmware_version));
|
||||
pickNewNodeNum();
|
||||
|
||||
// Set our board type so we can share it with others
|
||||
@@ -345,19 +376,6 @@ void NodeDB::init()
|
||||
info->user = owner;
|
||||
info->has_user = true;
|
||||
|
||||
if (*numNodes > 0) {
|
||||
LOG_DEBUG("Legacy NodeDB detected... Migrating to NodeDBLite\n");
|
||||
uint32_t readIndex = 0;
|
||||
const meshtastic_NodeInfo *oldNodeInfo = nodeDB.readNextNodeInfo(readIndex);
|
||||
while (oldNodeInfo != NULL) {
|
||||
migrateToNodeInfoLite(oldNodeInfo);
|
||||
oldNodeInfo = nodeDB.readNextNodeInfo(readIndex);
|
||||
}
|
||||
LOG_DEBUG("Migration complete! Clearing out legacy NodeDB...\n");
|
||||
devicestate.node_db_count = 0;
|
||||
memset(devicestate.node_db, 0, sizeof(devicestate.node_db));
|
||||
}
|
||||
|
||||
#ifdef ARCH_ESP32
|
||||
Preferences preferences;
|
||||
preferences.begin("meshtastic", false);
|
||||
@@ -367,7 +385,7 @@ void NodeDB::init()
|
||||
#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, *numNodes);
|
||||
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;
|
||||
@@ -392,25 +410,20 @@ void NodeDB::init()
|
||||
*/
|
||||
void NodeDB::pickNewNodeNum()
|
||||
{
|
||||
NodeNum r = myNodeInfo.my_node_num;
|
||||
|
||||
getMacAddr(ourMacAddr); // Make sure ourMacAddr is set
|
||||
|
||||
// Pick an initial nodenum based on the macaddr
|
||||
r = (ourMacAddr[2] << 24) | (ourMacAddr[3] << 16) | (ourMacAddr[4] << 8) | ourMacAddr[5];
|
||||
|
||||
if (r == NODENUM_BROADCAST || r < NUM_RESERVED)
|
||||
r = NUM_RESERVED; // don't pick a reserved node number
|
||||
NodeNum nodeNum = (ourMacAddr[2] << 24) | (ourMacAddr[3] << 16) | (ourMacAddr[4] << 8) | ourMacAddr[5];
|
||||
|
||||
meshtastic_NodeInfoLite *found;
|
||||
while ((found = getMeshNode(r)) && memcmp(found->user.macaddr, owner.macaddr, sizeof(owner.macaddr))) {
|
||||
// FIXME: input for random() is int, so NODENUM_BROADCAST becomes -1
|
||||
NodeNum n = random(NUM_RESERVED, NODENUM_BROADCAST); // try a new random choice
|
||||
LOG_WARN("NOTE! Our desired nodenum 0x%x is in use, so trying for 0x%x\n", r, n);
|
||||
r = n;
|
||||
while ((nodeNum == NODENUM_BROADCAST || nodeNum < NUM_RESERVED) ||
|
||||
((found = getMeshNode(nodeNum)) && memcmp(found->user.macaddr, owner.macaddr, sizeof(owner.macaddr)) != 0)) {
|
||||
NodeNum candidate = random(NUM_RESERVED, LONG_MAX); // try a new random choice
|
||||
LOG_WARN("NOTE! Our desired nodenum 0x%x is invalid or in use, so trying for 0x%x\n", nodeNum, candidate);
|
||||
nodeNum = candidate;
|
||||
}
|
||||
|
||||
myNodeInfo.my_node_num = r;
|
||||
myNodeInfo.my_node_num = nodeNum;
|
||||
}
|
||||
|
||||
static const char *prefFileName = "/prefs/db.proto";
|
||||
@@ -613,14 +626,6 @@ void NodeDB::saveToDisk(int saveWhat)
|
||||
}
|
||||
}
|
||||
|
||||
const meshtastic_NodeInfo *NodeDB::readNextNodeInfo(uint32_t &readIndex)
|
||||
{
|
||||
if (readIndex < *numNodes)
|
||||
return &nodes[readIndex++];
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const meshtastic_NodeInfoLite *NodeDB::readNextMeshNode(uint32_t &readIndex)
|
||||
{
|
||||
if (readIndex < *numMeshNodes)
|
||||
@@ -791,24 +796,13 @@ void NodeDB::updateFrom(const meshtastic_MeshPacket &mp)
|
||||
|
||||
uint8_t NodeDB::getMeshNodeChannel(NodeNum n)
|
||||
{
|
||||
meshtastic_NodeInfoLite *info = getMeshNode(n);
|
||||
const meshtastic_NodeInfoLite *info = getMeshNode(n);
|
||||
if (!info) {
|
||||
return 0; // defaults to PRIMARY
|
||||
}
|
||||
return info->channel;
|
||||
}
|
||||
|
||||
/// Find a node in our DB, return null for missing
|
||||
/// NOTE: This function might be called from an ISR
|
||||
meshtastic_NodeInfo *NodeDB::getNodeInfo(NodeNum n)
|
||||
{
|
||||
for (int i = 0; i < *numNodes; i++)
|
||||
if (nodes[i].num == n)
|
||||
return &nodes[i];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/// Find a node in our DB, return null for missing
|
||||
/// NOTE: This function might be called from an ISR
|
||||
meshtastic_NodeInfoLite *NodeDB::getMeshNode(NodeNum n)
|
||||
@@ -827,7 +821,8 @@ meshtastic_NodeInfoLite *NodeDB::getOrCreateMeshNode(NodeNum n)
|
||||
|
||||
if (!lite) {
|
||||
if ((*numMeshNodes >= MAX_NUM_NODES) || (memGet.getFreeHeap() < meshtastic_NodeInfoLite_size * 3)) {
|
||||
screen->print("warning: node_db_lite full! erasing oldest entry\n");
|
||||
if (screen)
|
||||
screen->print("warning: node_db_lite full! erasing oldest entry\n");
|
||||
// look for oldest node and erase it
|
||||
uint32_t oldest = UINT32_MAX;
|
||||
int oldestIndex = -1;
|
||||
@@ -854,57 +849,6 @@ meshtastic_NodeInfoLite *NodeDB::getOrCreateMeshNode(NodeNum n)
|
||||
return lite;
|
||||
}
|
||||
|
||||
void NodeDB::migrateToNodeInfoLite(const meshtastic_NodeInfo *node)
|
||||
{
|
||||
meshtastic_NodeInfoLite *lite = getMeshNode(node->num);
|
||||
|
||||
if (!lite) {
|
||||
if ((*numMeshNodes >= MAX_NUM_NODES) || (memGet.getFreeHeap() < meshtastic_NodeInfoLite_size * 3)) {
|
||||
screen->print("warning: node_db_lite full! erasing oldest entry\n");
|
||||
// look for oldest node and erase it
|
||||
uint32_t oldest = UINT32_MAX;
|
||||
int oldestIndex = -1;
|
||||
for (int i = 0; i < *numMeshNodes; i++) {
|
||||
if (meshNodes[i].last_heard < oldest) {
|
||||
oldest = meshNodes[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];
|
||||
}
|
||||
(*numMeshNodes)--;
|
||||
}
|
||||
// add the node at the end
|
||||
lite = &meshNodes[(*numMeshNodes)++];
|
||||
|
||||
// everything is missing except the nodenum
|
||||
memset(lite, 0, sizeof(*lite));
|
||||
lite->num = node->num;
|
||||
lite->snr = node->snr;
|
||||
lite->last_heard = node->last_heard;
|
||||
lite->channel = node->channel;
|
||||
|
||||
if (node->has_position) {
|
||||
lite->has_position = true;
|
||||
lite->position.latitude_i = node->position.latitude_i;
|
||||
lite->position.longitude_i = node->position.longitude_i;
|
||||
lite->position.altitude = node->position.altitude;
|
||||
lite->position.location_source = node->position.location_source;
|
||||
lite->position.time = node->position.time;
|
||||
}
|
||||
if (node->has_user) {
|
||||
lite->has_user = true;
|
||||
lite->user = node->user;
|
||||
}
|
||||
if (node->has_device_metrics) {
|
||||
lite->has_device_metrics = true;
|
||||
lite->device_metrics = node->device_metrics;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Record an error that should be reported via analytics
|
||||
void recordCriticalError(meshtastic_CriticalErrorCode code, uint32_t address, const char *filename)
|
||||
{
|
||||
|
||||
@@ -19,7 +19,7 @@ DeviceState versions used to be defined in the .proto file but really only this
|
||||
#define SEGMENT_DEVICESTATE 4
|
||||
#define SEGMENT_CHANNELS 8
|
||||
|
||||
#define DEVICESTATE_CUR_VER 20
|
||||
#define DEVICESTATE_CUR_VER 22
|
||||
#define DEVICESTATE_MIN_VER DEVICESTATE_CUR_VER
|
||||
|
||||
extern meshtastic_DeviceState devicestate;
|
||||
@@ -45,9 +45,6 @@ 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_NodeInfo *nodes;
|
||||
pb_size_t *numNodes;
|
||||
|
||||
meshtastic_NodeInfoLite *meshNodes;
|
||||
pb_size_t *numMeshNodes;
|
||||
|
||||
@@ -137,18 +134,6 @@ class NodeDB
|
||||
private:
|
||||
/// Find a node in our DB, create an empty NodeInfoLite if missing
|
||||
meshtastic_NodeInfoLite *getOrCreateMeshNode(NodeNum n);
|
||||
void migrateToNodeInfoLite(const meshtastic_NodeInfo *node);
|
||||
/// Find a node in our DB, return null for missing
|
||||
meshtastic_NodeInfo *getNodeInfo(NodeNum n);
|
||||
/// Allow the bluetooth layer to read our next nodeinfo record, or NULL if done reading
|
||||
const meshtastic_NodeInfo *readNextNodeInfo(uint32_t &readIndex);
|
||||
size_t getNumNodes() { return *numNodes; }
|
||||
|
||||
meshtastic_NodeInfo *getNodeByIndex(size_t x)
|
||||
{
|
||||
assert(x < *numNodes);
|
||||
return &nodes[x];
|
||||
}
|
||||
|
||||
/// Notify observers of changes to the DB
|
||||
void notifyObservers(bool forceUpdate = false)
|
||||
@@ -161,6 +146,9 @@ class NodeDB
|
||||
/// read our db from flash
|
||||
void loadFromDisk();
|
||||
|
||||
/// purge db entries without user info
|
||||
void cleanupMeshDB();
|
||||
|
||||
/// Reinit device state from scratch (not loading from disk)
|
||||
void installDefaultDeviceState(), installDefaultChannels(), installDefaultConfig(), installDefaultModuleConfig();
|
||||
};
|
||||
@@ -174,7 +162,6 @@ extern NodeDB nodeDB;
|
||||
|
||||
# prefs.position_broadcast_secs = FIXME possibly broadcast only once an hr
|
||||
prefs.wait_bluetooth_secs = 1 # Don't stay in bluetooth mode
|
||||
prefs.mesh_sds_timeout_secs = never
|
||||
# try to stay in light sleep one full day, then briefly wake and sleep again
|
||||
|
||||
prefs.ls_secs = oneday
|
||||
@@ -202,7 +189,6 @@ extern NodeDB nodeDB;
|
||||
#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_mesh_sds_timeout_secs IF_ROUTER(NODE_DELAY_FOREVER, 2 * 60 * 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
|
||||
@@ -228,10 +214,6 @@ inline uint32_t getConfiguredOrDefaultMs(uint32_t configuredInterval, uint32_t d
|
||||
|
||||
/// Sometimes we will have Position objects that only have a time, so check for
|
||||
/// valid lat/lon
|
||||
static inline bool hasValidPosition(const meshtastic_NodeInfo *n)
|
||||
{
|
||||
return n->has_position && (n->position.latitude_i != 0 || n->position.longitude_i != 0);
|
||||
}
|
||||
static inline bool hasValidPosition(const meshtastic_NodeInfoLite *n)
|
||||
{
|
||||
return n->has_position && (n->position.latitude_i != 0 || n->position.longitude_i != 0);
|
||||
|
||||
@@ -155,11 +155,18 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
// app not to send locations on our behalf.
|
||||
fromRadioScratch.which_payload_variant = meshtastic_FromRadio_my_info_tag;
|
||||
fromRadioScratch.my_info = myNodeInfo;
|
||||
state = STATE_SEND_NODEINFO;
|
||||
state = STATE_SEND_METADATA;
|
||||
|
||||
service.refreshLocalMeshNode(); // Update my NodeInfo because the client will be asking for it soon.
|
||||
break;
|
||||
|
||||
case STATE_SEND_METADATA:
|
||||
LOG_INFO("getFromRadio=STATE_SEND_METADATA\n");
|
||||
fromRadioScratch.which_payload_variant = meshtastic_FromRadio_metadata_tag;
|
||||
fromRadioScratch.metadata = getDeviceMetadata();
|
||||
state = STATE_SEND_NODEINFO;
|
||||
break;
|
||||
|
||||
case STATE_SEND_NODEINFO: {
|
||||
LOG_INFO("getFromRadio=STATE_SEND_NODEINFO\n");
|
||||
|
||||
@@ -279,6 +286,14 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_remote_hardware_tag;
|
||||
fromRadioScratch.moduleConfig.payload_variant.remote_hardware = moduleConfig.remote_hardware;
|
||||
break;
|
||||
case meshtastic_ModuleConfig_neighbor_info_tag:
|
||||
fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_neighbor_info_tag;
|
||||
fromRadioScratch.moduleConfig.payload_variant.neighbor_info = moduleConfig.neighbor_info;
|
||||
break;
|
||||
case meshtastic_ModuleConfig_detection_sensor_tag:
|
||||
fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_detection_sensor_tag;
|
||||
fromRadioScratch.moduleConfig.payload_variant.detection_sensor = moduleConfig.detection_sensor;
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("Unknown module config type %d\n", config_state);
|
||||
}
|
||||
@@ -286,15 +301,11 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
config_state++;
|
||||
// Advance when we have sent all of our ModuleConfig objects
|
||||
if (config_state > (_meshtastic_AdminMessage_ModuleConfigType_MAX + 1)) {
|
||||
state = STATE_SEND_METADATA;
|
||||
state = STATE_SEND_COMPLETE_ID;
|
||||
config_state = 0;
|
||||
}
|
||||
break;
|
||||
case STATE_SEND_METADATA:
|
||||
fromRadioScratch.which_payload_variant = meshtastic_FromRadio_metadata_tag;
|
||||
fromRadioScratch.metadata = getDeviceMetadata();
|
||||
state = STATE_SEND_COMPLETE_ID;
|
||||
break;
|
||||
|
||||
case STATE_SEND_COMPLETE_ID:
|
||||
LOG_INFO("getFromRadio=STATE_SEND_COMPLETE_ID\n");
|
||||
fromRadioScratch.which_payload_variant = meshtastic_FromRadio_config_complete_id_tag;
|
||||
|
||||
@@ -534,8 +534,8 @@ size_t RadioInterface::beginSending(meshtastic_MeshPacket *p)
|
||||
h->id = p->id;
|
||||
h->channel = p->channel;
|
||||
if (p->hop_limit > HOP_MAX) {
|
||||
LOG_WARN("hop limit %d is too high, setting to %d\n", p->hop_limit, HOP_MAX);
|
||||
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);
|
||||
|
||||
|
||||
@@ -153,7 +153,12 @@ void Router::setReceivedMessage()
|
||||
|
||||
meshtastic_QueueStatus Router::getQueueStatus()
|
||||
{
|
||||
return iface->getQueueStatus();
|
||||
if (!iface) {
|
||||
meshtastic_QueueStatus qs;
|
||||
qs.res = qs.mesh_packet_id = qs.free = qs.maxlen = 0;
|
||||
return qs;
|
||||
} else
|
||||
return iface->getQueueStatus();
|
||||
}
|
||||
|
||||
ErrorCode Router::sendLocal(meshtastic_MeshPacket *p, RxSource src)
|
||||
|
||||
@@ -53,7 +53,13 @@ typedef enum _meshtastic_AdminMessage_ModuleConfigType {
|
||||
/* TODO: REPLACE */
|
||||
meshtastic_AdminMessage_ModuleConfigType_AUDIO_CONFIG = 7,
|
||||
/* TODO: REPLACE */
|
||||
meshtastic_AdminMessage_ModuleConfigType_REMOTEHARDWARE_CONFIG = 8
|
||||
meshtastic_AdminMessage_ModuleConfigType_REMOTEHARDWARE_CONFIG = 8,
|
||||
/* TODO: REPLACE */
|
||||
meshtastic_AdminMessage_ModuleConfigType_NEIGHBORINFO_CONFIG = 9,
|
||||
/* TODO: REPLACE */
|
||||
meshtastic_AdminMessage_ModuleConfigType_AMBIENTLIGHTING_CONFIG = 10,
|
||||
/* TODO: REPLACE */
|
||||
meshtastic_AdminMessage_ModuleConfigType_DETECTIONSENSOR_CONFIG = 11
|
||||
} meshtastic_AdminMessage_ModuleConfigType;
|
||||
|
||||
/* Struct definitions */
|
||||
@@ -172,8 +178,8 @@ extern "C" {
|
||||
#define _meshtastic_AdminMessage_ConfigType_ARRAYSIZE ((meshtastic_AdminMessage_ConfigType)(meshtastic_AdminMessage_ConfigType_BLUETOOTH_CONFIG+1))
|
||||
|
||||
#define _meshtastic_AdminMessage_ModuleConfigType_MIN meshtastic_AdminMessage_ModuleConfigType_MQTT_CONFIG
|
||||
#define _meshtastic_AdminMessage_ModuleConfigType_MAX meshtastic_AdminMessage_ModuleConfigType_REMOTEHARDWARE_CONFIG
|
||||
#define _meshtastic_AdminMessage_ModuleConfigType_ARRAYSIZE ((meshtastic_AdminMessage_ModuleConfigType)(meshtastic_AdminMessage_ModuleConfigType_REMOTEHARDWARE_CONFIG+1))
|
||||
#define _meshtastic_AdminMessage_ModuleConfigType_MAX meshtastic_AdminMessage_ModuleConfigType_DETECTIONSENSOR_CONFIG
|
||||
#define _meshtastic_AdminMessage_ModuleConfigType_ARRAYSIZE ((meshtastic_AdminMessage_ModuleConfigType)(meshtastic_AdminMessage_ModuleConfigType_DETECTIONSENSOR_CONFIG+1))
|
||||
|
||||
#define meshtastic_AdminMessage_payload_variant_get_config_request_ENUMTYPE meshtastic_AdminMessage_ConfigType
|
||||
#define meshtastic_AdminMessage_payload_variant_get_module_config_request_ENUMTYPE meshtastic_AdminMessage_ModuleConfigType
|
||||
|
||||
@@ -51,8 +51,9 @@ typedef enum _meshtastic_Config_DeviceConfig_RebroadcastMode {
|
||||
} meshtastic_Config_DeviceConfig_RebroadcastMode;
|
||||
|
||||
/* Bit field of boolean configuration options, indicating which optional
|
||||
fields to include when assembling POSITION messages
|
||||
Longitude and latitude are always included (also time if GPS-synced)
|
||||
fields to include when assembling POSITION messages.
|
||||
Longitude, latitude, altitude, speed, heading, and DOP
|
||||
are always included (also time if GPS-synced)
|
||||
NOTE: the more fields are included, the larger the message will be -
|
||||
leading to longer airtime and a higher risk of packet loss */
|
||||
typedef enum _meshtastic_Config_PositionConfig_PositionFlags {
|
||||
@@ -236,6 +237,8 @@ typedef struct _meshtastic_Config_DeviceConfig {
|
||||
/* If true, device is considered to be "managed" by a mesh administrator
|
||||
Clients should then limit available configuration and administrative options inside the user interface */
|
||||
bool is_managed;
|
||||
/* Disables the triple-press of user button to enable or disable GPS */
|
||||
bool disable_triple_click;
|
||||
} meshtastic_Config_DeviceConfig;
|
||||
|
||||
/* Position Config */
|
||||
@@ -269,8 +272,10 @@ typedef struct _meshtastic_Config_PositionConfig {
|
||||
uint32_t tx_gpio;
|
||||
/* The minimum distance in meters traveled (since the last send) before we can send a position to the mesh if position_broadcast_smart_enabled */
|
||||
uint32_t broadcast_smart_minimum_distance;
|
||||
/* The minumum number of seconds (since the last send) before we can send a position to the mesh if position_broadcast_smart_enabled */
|
||||
/* The minimum number of seconds (since the last send) before we can send a position to the mesh if position_broadcast_smart_enabled */
|
||||
uint32_t broadcast_smart_minimum_interval_secs;
|
||||
/* (Re)define PIN_GPS_EN for your board. */
|
||||
uint32_t gps_en_gpio;
|
||||
} meshtastic_Config_PositionConfig;
|
||||
|
||||
/* Power Config\
|
||||
@@ -292,11 +297,6 @@ typedef struct _meshtastic_Config_PowerConfig {
|
||||
The number of seconds for to wait before turning off BLE in No Bluetooth states
|
||||
0 for default of 1 minute */
|
||||
uint32_t wait_bluetooth_secs;
|
||||
/* Mesh Super Deep Sleep Timeout Seconds
|
||||
While in Light Sleep if this value is exceeded we will lower into super deep sleep
|
||||
for sds_secs (default 1 year) or a button press
|
||||
0 for default of two hours, MAXUINT for disabled */
|
||||
uint32_t mesh_sds_timeout_secs;
|
||||
/* Super Deep Sleep Seconds
|
||||
While in Light Sleep if mesh_sds_timeout_secs is exceeded we will lower into super deep sleep
|
||||
for this value (default 1 year) or a button press
|
||||
@@ -403,7 +403,8 @@ typedef struct _meshtastic_Config_LoRaConfig {
|
||||
/* The region code for the radio (US, CN, EU433, etc...) */
|
||||
meshtastic_Config_LoRaConfig_RegionCode region;
|
||||
/* Maximum number of hops. This can't be greater than 7.
|
||||
Default of 3 */
|
||||
Default of 3
|
||||
Attempting to set a value > 7 results in the default */
|
||||
uint32_t hop_limit;
|
||||
/* Disable TX from the LoRa radio. Useful for hot-swapping antennas and other tests.
|
||||
Defaults to false */
|
||||
@@ -534,18 +535,18 @@ 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}
|
||||
#define meshtastic_Config_PositionConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define meshtastic_Config_PowerConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#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}
|
||||
#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}
|
||||
#define meshtastic_Config_DisplayConfig_init_default {0, _meshtastic_Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _meshtastic_Config_DisplayConfig_DisplayUnits_MIN, _meshtastic_Config_DisplayConfig_OledType_MIN, _meshtastic_Config_DisplayConfig_DisplayMode_MIN, 0, 0}
|
||||
#define meshtastic_Config_LoRaConfig_init_default {0, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _meshtastic_Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}}
|
||||
#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}
|
||||
#define meshtastic_Config_PositionConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define meshtastic_Config_PowerConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#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}
|
||||
#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}
|
||||
#define meshtastic_Config_DisplayConfig_init_zero {0, _meshtastic_Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _meshtastic_Config_DisplayConfig_DisplayUnits_MIN, _meshtastic_Config_DisplayConfig_OledType_MIN, _meshtastic_Config_DisplayConfig_DisplayMode_MIN, 0, 0}
|
||||
@@ -562,6 +563,7 @@ extern "C" {
|
||||
#define meshtastic_Config_DeviceConfig_node_info_broadcast_secs_tag 7
|
||||
#define meshtastic_Config_DeviceConfig_double_tap_as_button_press_tag 8
|
||||
#define meshtastic_Config_DeviceConfig_is_managed_tag 9
|
||||
#define meshtastic_Config_DeviceConfig_disable_triple_click_tag 10
|
||||
#define meshtastic_Config_PositionConfig_position_broadcast_secs_tag 1
|
||||
#define meshtastic_Config_PositionConfig_position_broadcast_smart_enabled_tag 2
|
||||
#define meshtastic_Config_PositionConfig_fixed_position_tag 3
|
||||
@@ -573,11 +575,11 @@ extern "C" {
|
||||
#define meshtastic_Config_PositionConfig_tx_gpio_tag 9
|
||||
#define meshtastic_Config_PositionConfig_broadcast_smart_minimum_distance_tag 10
|
||||
#define meshtastic_Config_PositionConfig_broadcast_smart_minimum_interval_secs_tag 11
|
||||
#define meshtastic_Config_PositionConfig_gps_en_gpio_tag 12
|
||||
#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
|
||||
#define meshtastic_Config_PowerConfig_wait_bluetooth_secs_tag 4
|
||||
#define meshtastic_Config_PowerConfig_mesh_sds_timeout_secs_tag 5
|
||||
#define meshtastic_Config_PowerConfig_sds_secs_tag 6
|
||||
#define meshtastic_Config_PowerConfig_ls_secs_tag 7
|
||||
#define meshtastic_Config_PowerConfig_min_wake_secs_tag 8
|
||||
@@ -658,7 +660,8 @@ X(a, STATIC, SINGULAR, UINT32, buzzer_gpio, 5) \
|
||||
X(a, STATIC, SINGULAR, UENUM, rebroadcast_mode, 6) \
|
||||
X(a, STATIC, SINGULAR, UINT32, node_info_broadcast_secs, 7) \
|
||||
X(a, STATIC, SINGULAR, BOOL, double_tap_as_button_press, 8) \
|
||||
X(a, STATIC, SINGULAR, BOOL, is_managed, 9)
|
||||
X(a, STATIC, SINGULAR, BOOL, is_managed, 9) \
|
||||
X(a, STATIC, SINGULAR, BOOL, disable_triple_click, 10)
|
||||
#define meshtastic_Config_DeviceConfig_CALLBACK NULL
|
||||
#define meshtastic_Config_DeviceConfig_DEFAULT NULL
|
||||
|
||||
@@ -673,7 +676,8 @@ X(a, STATIC, SINGULAR, UINT32, position_flags, 7) \
|
||||
X(a, STATIC, SINGULAR, UINT32, rx_gpio, 8) \
|
||||
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, broadcast_smart_minimum_interval_secs, 11) \
|
||||
X(a, STATIC, SINGULAR, UINT32, gps_en_gpio, 12)
|
||||
#define meshtastic_Config_PositionConfig_CALLBACK NULL
|
||||
#define meshtastic_Config_PositionConfig_DEFAULT NULL
|
||||
|
||||
@@ -682,7 +686,6 @@ X(a, STATIC, SINGULAR, BOOL, is_power_saving, 1) \
|
||||
X(a, STATIC, SINGULAR, UINT32, on_battery_shutdown_after_secs, 2) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, adc_multiplier_override, 3) \
|
||||
X(a, STATIC, SINGULAR, UINT32, wait_bluetooth_secs, 4) \
|
||||
X(a, STATIC, SINGULAR, UINT32, mesh_sds_timeout_secs, 5) \
|
||||
X(a, STATIC, SINGULAR, UINT32, sds_secs, 6) \
|
||||
X(a, STATIC, SINGULAR, UINT32, ls_secs, 7) \
|
||||
X(a, STATIC, SINGULAR, UINT32, min_wake_secs, 8) \
|
||||
@@ -774,13 +777,13 @@ extern const pb_msgdesc_t meshtastic_Config_BluetoothConfig_msg;
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define meshtastic_Config_BluetoothConfig_size 10
|
||||
#define meshtastic_Config_DeviceConfig_size 30
|
||||
#define meshtastic_Config_DeviceConfig_size 32
|
||||
#define meshtastic_Config_DisplayConfig_size 28
|
||||
#define meshtastic_Config_LoRaConfig_size 77
|
||||
#define meshtastic_Config_NetworkConfig_IpV4Config_size 20
|
||||
#define meshtastic_Config_NetworkConfig_size 195
|
||||
#define meshtastic_Config_PositionConfig_size 54
|
||||
#define meshtastic_Config_PowerConfig_size 46
|
||||
#define meshtastic_Config_PositionConfig_size 60
|
||||
#define meshtastic_Config_PowerConfig_size 40
|
||||
#define meshtastic_Config_size 198
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -75,6 +75,12 @@ typedef struct _meshtastic_LocalModuleConfig {
|
||||
/* The part of the config that is specific to the Neighbor Info module */
|
||||
bool has_neighbor_info;
|
||||
meshtastic_ModuleConfig_NeighborInfoConfig neighbor_info;
|
||||
/* The part of the config that is specific to the Ambient Lighting module */
|
||||
bool has_ambient_lighting;
|
||||
meshtastic_ModuleConfig_AmbientLightingConfig ambient_lighting;
|
||||
/* The part of the config that is specific to the Detection Sensor module */
|
||||
bool has_detection_sensor;
|
||||
meshtastic_ModuleConfig_DetectionSensorConfig detection_sensor;
|
||||
} meshtastic_LocalModuleConfig;
|
||||
|
||||
|
||||
@@ -84,9 +90,9 @@ extern "C" {
|
||||
|
||||
/* Initializer values for message structs */
|
||||
#define meshtastic_LocalConfig_init_default {false, meshtastic_Config_DeviceConfig_init_default, false, meshtastic_Config_PositionConfig_init_default, false, meshtastic_Config_PowerConfig_init_default, false, meshtastic_Config_NetworkConfig_init_default, false, meshtastic_Config_DisplayConfig_init_default, false, meshtastic_Config_LoRaConfig_init_default, false, meshtastic_Config_BluetoothConfig_init_default, 0}
|
||||
#define meshtastic_LocalModuleConfig_init_default {false, meshtastic_ModuleConfig_MQTTConfig_init_default, false, meshtastic_ModuleConfig_SerialConfig_init_default, false, meshtastic_ModuleConfig_ExternalNotificationConfig_init_default, false, meshtastic_ModuleConfig_StoreForwardConfig_init_default, false, meshtastic_ModuleConfig_RangeTestConfig_init_default, false, meshtastic_ModuleConfig_TelemetryConfig_init_default, false, meshtastic_ModuleConfig_CannedMessageConfig_init_default, 0, false, meshtastic_ModuleConfig_AudioConfig_init_default, false, meshtastic_ModuleConfig_RemoteHardwareConfig_init_default, false, meshtastic_ModuleConfig_NeighborInfoConfig_init_default}
|
||||
#define meshtastic_LocalModuleConfig_init_default {false, meshtastic_ModuleConfig_MQTTConfig_init_default, false, meshtastic_ModuleConfig_SerialConfig_init_default, false, meshtastic_ModuleConfig_ExternalNotificationConfig_init_default, false, meshtastic_ModuleConfig_StoreForwardConfig_init_default, false, meshtastic_ModuleConfig_RangeTestConfig_init_default, false, meshtastic_ModuleConfig_TelemetryConfig_init_default, false, meshtastic_ModuleConfig_CannedMessageConfig_init_default, 0, false, meshtastic_ModuleConfig_AudioConfig_init_default, false, meshtastic_ModuleConfig_RemoteHardwareConfig_init_default, false, meshtastic_ModuleConfig_NeighborInfoConfig_init_default, false, meshtastic_ModuleConfig_AmbientLightingConfig_init_default, false, meshtastic_ModuleConfig_DetectionSensorConfig_init_default}
|
||||
#define meshtastic_LocalConfig_init_zero {false, meshtastic_Config_DeviceConfig_init_zero, false, meshtastic_Config_PositionConfig_init_zero, false, meshtastic_Config_PowerConfig_init_zero, false, meshtastic_Config_NetworkConfig_init_zero, false, meshtastic_Config_DisplayConfig_init_zero, false, meshtastic_Config_LoRaConfig_init_zero, false, meshtastic_Config_BluetoothConfig_init_zero, 0}
|
||||
#define meshtastic_LocalModuleConfig_init_zero {false, meshtastic_ModuleConfig_MQTTConfig_init_zero, false, meshtastic_ModuleConfig_SerialConfig_init_zero, false, meshtastic_ModuleConfig_ExternalNotificationConfig_init_zero, false, meshtastic_ModuleConfig_StoreForwardConfig_init_zero, false, meshtastic_ModuleConfig_RangeTestConfig_init_zero, false, meshtastic_ModuleConfig_TelemetryConfig_init_zero, false, meshtastic_ModuleConfig_CannedMessageConfig_init_zero, 0, false, meshtastic_ModuleConfig_AudioConfig_init_zero, false, meshtastic_ModuleConfig_RemoteHardwareConfig_init_zero, false, meshtastic_ModuleConfig_NeighborInfoConfig_init_zero}
|
||||
#define meshtastic_LocalModuleConfig_init_zero {false, meshtastic_ModuleConfig_MQTTConfig_init_zero, false, meshtastic_ModuleConfig_SerialConfig_init_zero, false, meshtastic_ModuleConfig_ExternalNotificationConfig_init_zero, false, meshtastic_ModuleConfig_StoreForwardConfig_init_zero, false, meshtastic_ModuleConfig_RangeTestConfig_init_zero, false, meshtastic_ModuleConfig_TelemetryConfig_init_zero, false, meshtastic_ModuleConfig_CannedMessageConfig_init_zero, 0, false, meshtastic_ModuleConfig_AudioConfig_init_zero, false, meshtastic_ModuleConfig_RemoteHardwareConfig_init_zero, false, meshtastic_ModuleConfig_NeighborInfoConfig_init_zero, false, meshtastic_ModuleConfig_AmbientLightingConfig_init_zero, false, meshtastic_ModuleConfig_DetectionSensorConfig_init_zero}
|
||||
|
||||
/* Field tags (for use in manual encoding/decoding) */
|
||||
#define meshtastic_LocalConfig_device_tag 1
|
||||
@@ -108,6 +114,8 @@ extern "C" {
|
||||
#define meshtastic_LocalModuleConfig_audio_tag 9
|
||||
#define meshtastic_LocalModuleConfig_remote_hardware_tag 10
|
||||
#define meshtastic_LocalModuleConfig_neighbor_info_tag 11
|
||||
#define meshtastic_LocalModuleConfig_ambient_lighting_tag 12
|
||||
#define meshtastic_LocalModuleConfig_detection_sensor_tag 13
|
||||
|
||||
/* Struct field encoding specification for nanopb */
|
||||
#define meshtastic_LocalConfig_FIELDLIST(X, a) \
|
||||
@@ -140,7 +148,9 @@ X(a, STATIC, OPTIONAL, MESSAGE, canned_message, 7) \
|
||||
X(a, STATIC, SINGULAR, UINT32, version, 8) \
|
||||
X(a, STATIC, OPTIONAL, MESSAGE, audio, 9) \
|
||||
X(a, STATIC, OPTIONAL, MESSAGE, remote_hardware, 10) \
|
||||
X(a, STATIC, OPTIONAL, MESSAGE, neighbor_info, 11)
|
||||
X(a, STATIC, OPTIONAL, MESSAGE, neighbor_info, 11) \
|
||||
X(a, STATIC, OPTIONAL, MESSAGE, ambient_lighting, 12) \
|
||||
X(a, STATIC, OPTIONAL, MESSAGE, detection_sensor, 13)
|
||||
#define meshtastic_LocalModuleConfig_CALLBACK NULL
|
||||
#define meshtastic_LocalModuleConfig_DEFAULT NULL
|
||||
#define meshtastic_LocalModuleConfig_mqtt_MSGTYPE meshtastic_ModuleConfig_MQTTConfig
|
||||
@@ -153,6 +163,8 @@ X(a, STATIC, OPTIONAL, MESSAGE, neighbor_info, 11)
|
||||
#define meshtastic_LocalModuleConfig_audio_MSGTYPE meshtastic_ModuleConfig_AudioConfig
|
||||
#define meshtastic_LocalModuleConfig_remote_hardware_MSGTYPE meshtastic_ModuleConfig_RemoteHardwareConfig
|
||||
#define meshtastic_LocalModuleConfig_neighbor_info_MSGTYPE meshtastic_ModuleConfig_NeighborInfoConfig
|
||||
#define meshtastic_LocalModuleConfig_ambient_lighting_MSGTYPE meshtastic_ModuleConfig_AmbientLightingConfig
|
||||
#define meshtastic_LocalModuleConfig_detection_sensor_MSGTYPE meshtastic_ModuleConfig_DetectionSensorConfig
|
||||
|
||||
extern const pb_msgdesc_t meshtastic_LocalConfig_msg;
|
||||
extern const pb_msgdesc_t meshtastic_LocalModuleConfig_msg;
|
||||
@@ -162,8 +174,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 461
|
||||
#define meshtastic_LocalModuleConfig_size 547
|
||||
#define meshtastic_LocalConfig_size 463
|
||||
#define meshtastic_LocalModuleConfig_size 609
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
||||
@@ -61,6 +61,8 @@ typedef enum _meshtastic_HardwareModel {
|
||||
meshtastic_HardwareModel_NANO_G1_EXPLORER = 17,
|
||||
/* B&Q Consulting Nano G2 Ultra: https://wiki.uniteng.com/en/meshtastic/nano-g2-ultra */
|
||||
meshtastic_HardwareModel_NANO_G2_ULTRA = 18,
|
||||
/* LoRAType device: https://loratype.org/ */
|
||||
meshtastic_HardwareModel_LORA_TYPE = 19,
|
||||
/* B&Q Consulting Station Edition G1: https://uniteng.com/wiki/doku.php?id=meshtastic:station */
|
||||
meshtastic_HardwareModel_STATION_G1 = 25,
|
||||
/* RAK11310 (RP2040 + SX1262) */
|
||||
@@ -103,10 +105,14 @@ typedef enum _meshtastic_HardwareModel {
|
||||
meshtastic_HardwareModel_HELTEC_WIRELESS_TRACKER = 48,
|
||||
/* Heltec Wireless Paper with ESP32-S3 CPU and E-Ink display */
|
||||
meshtastic_HardwareModel_HELTEC_WIRELESS_PAPER = 49,
|
||||
/* LilyGo T-Deck with ESP32-S3 CPU, Keyboard, and IPS display */
|
||||
/* LilyGo T-Deck with ESP32-S3 CPU, Keyboard and IPS display */
|
||||
meshtastic_HardwareModel_T_DECK = 50,
|
||||
/* LilyGo T-Watch S3 with ESP32-S3 CPU and IPS display */
|
||||
meshtastic_HardwareModel_T_WATCH_S3 = 51,
|
||||
/* Bobricius Picomputer with ESP32-S3 CPU, Keyboard and IPS display */
|
||||
meshtastic_HardwareModel_PICOMPUTER_S3 = 52,
|
||||
/* Heltec HT-CT62 with ESP32-C3 CPU and SX1262 LoRa */
|
||||
meshtastic_HardwareModel_HELTEC_HT62 = 53,
|
||||
/* ------------------------------------------------------------------------------------------------------------------------------------------
|
||||
Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits.
|
||||
------------------------------------------------------------------------------------------------------------------------------------------ */
|
||||
@@ -149,7 +155,7 @@ typedef enum _meshtastic_CriticalErrorCode {
|
||||
/* Radio transmit hardware failure. We sent data to the radio chip, but it didn't
|
||||
reply with an interrupt. */
|
||||
meshtastic_CriticalErrorCode_TRANSMIT_FAILED = 8,
|
||||
/* We detected that the main CPU voltage dropped below the minumum acceptable value */
|
||||
/* We detected that the main CPU voltage dropped below the minimum acceptable value */
|
||||
meshtastic_CriticalErrorCode_BROWNOUT = 9,
|
||||
/* Selftest of SX1262 radio chip failed */
|
||||
meshtastic_CriticalErrorCode_SX1262_FAILURE = 10,
|
||||
@@ -293,9 +299,8 @@ typedef struct _meshtastic_Position {
|
||||
/* In meters above MSL (but see issue #359) */
|
||||
int32_t altitude;
|
||||
/* This is usually not sent over the mesh (to save space), but it is sent
|
||||
from the phone so that the local device can set its RTC If it is sent over
|
||||
the mesh (because there are devices on the mesh without GPS), it will only
|
||||
be sent by devices which has a hardware GPS clock.
|
||||
from the phone so that the local device can set its time if it is sent over
|
||||
the mesh (because there are devices on the mesh without GPS or RTC).
|
||||
seconds since 1970 */
|
||||
uint32_t time;
|
||||
/* TODO: REPLACE */
|
||||
@@ -605,60 +610,12 @@ typedef struct _meshtastic_MyNodeInfo {
|
||||
/* Tells the phone what our node number is, default starting value is
|
||||
lowbyte of macaddr, but it will be fixed if that is already in use */
|
||||
uint32_t my_node_num;
|
||||
/* Deprecated in 2.1.x (Source from device_metadata)
|
||||
Note: This flag merely means we detected a hardware GPS in our node.
|
||||
Not the same as UserPreferences.location_sharing */
|
||||
bool has_gps;
|
||||
/* Deprecated in 2.1.x
|
||||
The maximum number of 'software' channels that can be set on this node. */
|
||||
uint32_t max_channels;
|
||||
/* Deprecated in 2.1.x (Source from device_metadata)
|
||||
0.0.5 etc... */
|
||||
char firmware_version[18];
|
||||
/* An error message we'd like to report back to the mothership through analytics.
|
||||
It indicates a serious bug occurred on the device, the device coped with it,
|
||||
but we still want to tell the devs about the bug.
|
||||
This field will be cleared after the phone reads MyNodeInfo
|
||||
(i.e. it will only be reported once)
|
||||
a numeric error code to go with error message, zero means no error */
|
||||
meshtastic_CriticalErrorCode error_code;
|
||||
/* A numeric error address (nonzero if available) */
|
||||
uint32_t error_address;
|
||||
/* The total number of errors this node has ever encountered
|
||||
(well - since the last time we discarded preferences) */
|
||||
uint32_t error_count;
|
||||
/* The total number of reboots this node has ever encountered
|
||||
(well - since the last time we discarded preferences) */
|
||||
uint32_t reboot_count;
|
||||
/* Deprecated in 2.1.x
|
||||
Calculated bitrate of the current channel (in Bytes Per Second) */
|
||||
float bitrate;
|
||||
/* Deprecated in 2.1.x
|
||||
How long before we consider a message abandoned and we can clear our
|
||||
caches of any messages in flight Normally quite large to handle the worst case
|
||||
message delivery time, 5 minutes.
|
||||
Formerly called FLOOD_EXPIRE_TIME in the device code */
|
||||
uint32_t message_timeout_msec;
|
||||
/* The minimum app version that can talk to this device.
|
||||
Phone/PC apps should compare this to their build number and if too low tell the user they must update their app */
|
||||
uint32_t min_app_version;
|
||||
/* Deprecated in 2.1.x (Only used on device to keep track of utilization)
|
||||
24 time windows of 1hr each with the airtime transmitted out of the device per hour. */
|
||||
pb_size_t air_period_tx_count;
|
||||
uint32_t air_period_tx[8];
|
||||
/* Deprecated in 2.1.x (Only used on device to keep track of utilization)
|
||||
24 time windows of 1hr each with the airtime of valid packets for your mesh. */
|
||||
pb_size_t air_period_rx_count;
|
||||
uint32_t air_period_rx[8];
|
||||
/* Deprecated in 2.1.x (Source from DeviceMetadata instead)
|
||||
Is the device wifi capable? */
|
||||
bool has_wifi;
|
||||
/* Deprecated in 2.1.x (Source from DeviceMetrics telemetry payloads)
|
||||
Utilization for the current channel, including well formed TX, RX and malformed RX (aka noise). */
|
||||
float channel_utilization;
|
||||
/* Deprecated in 2.1.x (Source from DeviceMetrics telemetry payloads)
|
||||
Percent of airtime for transmission used within the last hour. */
|
||||
float air_util_tx;
|
||||
} meshtastic_MyNodeInfo;
|
||||
|
||||
/* Debug output from the device.
|
||||
@@ -729,6 +686,12 @@ typedef struct _meshtastic_Neighbor {
|
||||
uint32_t node_id;
|
||||
/* SNR of last heard message */
|
||||
float snr;
|
||||
/* Reception time (in secs since 1970) of last message that was last sent by this ID.
|
||||
Note: this is for local storage only and will not be sent out over the mesh. */
|
||||
uint32_t last_rx_time;
|
||||
/* Broadcast interval of this neighbor (in seconds).
|
||||
Note: this is for local storage only and will not be sent out over the mesh. */
|
||||
uint32_t node_broadcast_interval_secs;
|
||||
} meshtastic_Neighbor;
|
||||
|
||||
/* Full info on edges for a single node */
|
||||
@@ -737,6 +700,8 @@ typedef struct _meshtastic_NeighborInfo {
|
||||
uint32_t node_id;
|
||||
/* Field to pass neighbor info for the next sending cycle */
|
||||
uint32_t last_sent_by_id;
|
||||
/* Broadcast interval of the represented node (in seconds) */
|
||||
uint32_t node_broadcast_interval_secs;
|
||||
/* The list of out edges from this node */
|
||||
pb_size_t neighbors_count;
|
||||
meshtastic_Neighbor neighbors[10];
|
||||
@@ -871,7 +836,6 @@ extern "C" {
|
||||
#define meshtastic_MeshPacket_delayed_ENUMTYPE meshtastic_MeshPacket_Delayed
|
||||
|
||||
|
||||
#define meshtastic_MyNodeInfo_error_code_ENUMTYPE meshtastic_CriticalErrorCode
|
||||
|
||||
#define meshtastic_LogRecord_level_ENUMTYPE meshtastic_LogRecord_Level
|
||||
|
||||
@@ -896,14 +860,14 @@ extern "C" {
|
||||
#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}
|
||||
#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_MyNodeInfo_init_default {0, 0, 0, "", _meshtastic_CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0, 0, 0, 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}
|
||||
#define meshtastic_FromRadio_init_default {0, 0, {meshtastic_MeshPacket_init_default}}
|
||||
#define meshtastic_ToRadio_init_default {0, {meshtastic_MeshPacket_init_default}}
|
||||
#define meshtastic_Compressed_init_default {_meshtastic_PortNum_MIN, {0, {0}}}
|
||||
#define meshtastic_NeighborInfo_init_default {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}
|
||||
#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_User_init_zero {"", "", "", {0}, _meshtastic_HardwareModel_MIN, 0}
|
||||
@@ -914,14 +878,14 @@ extern "C" {
|
||||
#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}
|
||||
#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_MyNodeInfo_init_zero {0, 0, 0, "", _meshtastic_CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0, 0, 0, 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}
|
||||
#define meshtastic_FromRadio_init_zero {0, 0, {meshtastic_MeshPacket_init_zero}}
|
||||
#define meshtastic_ToRadio_init_zero {0, {meshtastic_MeshPacket_init_zero}}
|
||||
#define meshtastic_Compressed_init_zero {_meshtastic_PortNum_MIN, {0, {0}}}
|
||||
#define meshtastic_NeighborInfo_init_zero {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}
|
||||
#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}
|
||||
|
||||
/* Field tags (for use in manual encoding/decoding) */
|
||||
@@ -998,21 +962,8 @@ extern "C" {
|
||||
#define meshtastic_NodeInfo_device_metrics_tag 6
|
||||
#define meshtastic_NodeInfo_channel_tag 7
|
||||
#define meshtastic_MyNodeInfo_my_node_num_tag 1
|
||||
#define meshtastic_MyNodeInfo_has_gps_tag 2
|
||||
#define meshtastic_MyNodeInfo_max_channels_tag 3
|
||||
#define meshtastic_MyNodeInfo_firmware_version_tag 4
|
||||
#define meshtastic_MyNodeInfo_error_code_tag 5
|
||||
#define meshtastic_MyNodeInfo_error_address_tag 6
|
||||
#define meshtastic_MyNodeInfo_error_count_tag 7
|
||||
#define meshtastic_MyNodeInfo_reboot_count_tag 8
|
||||
#define meshtastic_MyNodeInfo_bitrate_tag 9
|
||||
#define meshtastic_MyNodeInfo_message_timeout_msec_tag 10
|
||||
#define meshtastic_MyNodeInfo_min_app_version_tag 11
|
||||
#define meshtastic_MyNodeInfo_air_period_tx_tag 12
|
||||
#define meshtastic_MyNodeInfo_air_period_rx_tag 13
|
||||
#define meshtastic_MyNodeInfo_has_wifi_tag 14
|
||||
#define meshtastic_MyNodeInfo_channel_utilization_tag 15
|
||||
#define meshtastic_MyNodeInfo_air_util_tx_tag 16
|
||||
#define meshtastic_LogRecord_message_tag 1
|
||||
#define meshtastic_LogRecord_time_tag 2
|
||||
#define meshtastic_LogRecord_source_tag 3
|
||||
@@ -1030,9 +981,12 @@ extern "C" {
|
||||
#define meshtastic_Compressed_data_tag 2
|
||||
#define meshtastic_Neighbor_node_id_tag 1
|
||||
#define meshtastic_Neighbor_snr_tag 2
|
||||
#define meshtastic_Neighbor_last_rx_time_tag 3
|
||||
#define meshtastic_Neighbor_node_broadcast_interval_secs_tag 4
|
||||
#define meshtastic_NeighborInfo_node_id_tag 1
|
||||
#define meshtastic_NeighborInfo_last_sent_by_id_tag 2
|
||||
#define meshtastic_NeighborInfo_neighbors_tag 3
|
||||
#define meshtastic_NeighborInfo_node_broadcast_interval_secs_tag 3
|
||||
#define meshtastic_NeighborInfo_neighbors_tag 4
|
||||
#define meshtastic_DeviceMetadata_firmware_version_tag 1
|
||||
#define meshtastic_DeviceMetadata_device_state_version_tag 2
|
||||
#define meshtastic_DeviceMetadata_canShutdown_tag 3
|
||||
@@ -1175,21 +1129,8 @@ X(a, STATIC, SINGULAR, UINT32, channel, 7)
|
||||
|
||||
#define meshtastic_MyNodeInfo_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, UINT32, my_node_num, 1) \
|
||||
X(a, STATIC, SINGULAR, BOOL, has_gps, 2) \
|
||||
X(a, STATIC, SINGULAR, UINT32, max_channels, 3) \
|
||||
X(a, STATIC, SINGULAR, STRING, firmware_version, 4) \
|
||||
X(a, STATIC, SINGULAR, UENUM, error_code, 5) \
|
||||
X(a, STATIC, SINGULAR, UINT32, error_address, 6) \
|
||||
X(a, STATIC, SINGULAR, UINT32, error_count, 7) \
|
||||
X(a, STATIC, SINGULAR, UINT32, reboot_count, 8) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, bitrate, 9) \
|
||||
X(a, STATIC, SINGULAR, UINT32, message_timeout_msec, 10) \
|
||||
X(a, STATIC, SINGULAR, UINT32, min_app_version, 11) \
|
||||
X(a, STATIC, REPEATED, UINT32, air_period_tx, 12) \
|
||||
X(a, STATIC, REPEATED, UINT32, air_period_rx, 13) \
|
||||
X(a, STATIC, SINGULAR, BOOL, has_wifi, 14) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, channel_utilization, 15) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, air_util_tx, 16)
|
||||
X(a, STATIC, SINGULAR, UINT32, min_app_version, 11)
|
||||
#define meshtastic_MyNodeInfo_CALLBACK NULL
|
||||
#define meshtastic_MyNodeInfo_DEFAULT NULL
|
||||
|
||||
@@ -1259,14 +1200,17 @@ X(a, STATIC, SINGULAR, BYTES, data, 2)
|
||||
#define meshtastic_NeighborInfo_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, UINT32, node_id, 1) \
|
||||
X(a, STATIC, SINGULAR, UINT32, last_sent_by_id, 2) \
|
||||
X(a, STATIC, REPEATED, MESSAGE, neighbors, 3)
|
||||
X(a, STATIC, SINGULAR, UINT32, node_broadcast_interval_secs, 3) \
|
||||
X(a, STATIC, REPEATED, MESSAGE, neighbors, 4)
|
||||
#define meshtastic_NeighborInfo_CALLBACK NULL
|
||||
#define meshtastic_NeighborInfo_DEFAULT NULL
|
||||
#define meshtastic_NeighborInfo_neighbors_MSGTYPE meshtastic_Neighbor
|
||||
|
||||
#define meshtastic_Neighbor_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, UINT32, node_id, 1) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, snr, 2)
|
||||
X(a, STATIC, SINGULAR, FLOAT, snr, 2) \
|
||||
X(a, STATIC, SINGULAR, FIXED32, last_rx_time, 3) \
|
||||
X(a, STATIC, SINGULAR, UINT32, node_broadcast_interval_secs, 4)
|
||||
#define meshtastic_Neighbor_CALLBACK NULL
|
||||
#define meshtastic_Neighbor_DEFAULT NULL
|
||||
|
||||
@@ -1331,9 +1275,9 @@ extern const pb_msgdesc_t meshtastic_DeviceMetadata_msg;
|
||||
#define meshtastic_LogRecord_size 81
|
||||
#define meshtastic_MeshPacket_size 321
|
||||
#define meshtastic_MqttClientProxyMessage_size 501
|
||||
#define meshtastic_MyNodeInfo_size 179
|
||||
#define meshtastic_NeighborInfo_size 142
|
||||
#define meshtastic_Neighbor_size 11
|
||||
#define meshtastic_MyNodeInfo_size 18
|
||||
#define meshtastic_NeighborInfo_size 258
|
||||
#define meshtastic_Neighbor_size 22
|
||||
#define meshtastic_NodeInfo_size 261
|
||||
#define meshtastic_Position_size 137
|
||||
#define meshtastic_QueueStatus_size 23
|
||||
|
||||
@@ -18,6 +18,9 @@ PB_BIND(meshtastic_ModuleConfig_RemoteHardwareConfig, meshtastic_ModuleConfig_Re
|
||||
PB_BIND(meshtastic_ModuleConfig_NeighborInfoConfig, meshtastic_ModuleConfig_NeighborInfoConfig, AUTO)
|
||||
|
||||
|
||||
PB_BIND(meshtastic_ModuleConfig_DetectionSensorConfig, meshtastic_ModuleConfig_DetectionSensorConfig, AUTO)
|
||||
|
||||
|
||||
PB_BIND(meshtastic_ModuleConfig_AudioConfig, meshtastic_ModuleConfig_AudioConfig, AUTO)
|
||||
|
||||
|
||||
|
||||
@@ -125,6 +125,33 @@ typedef struct _meshtastic_ModuleConfig_NeighborInfoConfig {
|
||||
uint32_t update_interval;
|
||||
} meshtastic_ModuleConfig_NeighborInfoConfig;
|
||||
|
||||
/* Detection Sensor Module Config */
|
||||
typedef struct _meshtastic_ModuleConfig_DetectionSensorConfig {
|
||||
/* Whether the Module is enabled */
|
||||
bool enabled;
|
||||
/* Interval in seconds of how often we can send a message to the mesh when a state change is detected */
|
||||
uint32_t minimum_broadcast_secs;
|
||||
/* Interval in seconds of how often we should send a message to the mesh with the current state regardless of changes
|
||||
When set to 0, only state changes will be broadcasted
|
||||
Works as a sort of status heartbeat for peace of mind */
|
||||
uint32_t state_broadcast_secs;
|
||||
/* Send ASCII bell with alert message
|
||||
Useful for triggering ext. notification on bell */
|
||||
bool send_bell;
|
||||
/* Friendly name used to format message sent to mesh
|
||||
Example: A name "Motion" would result in a message "Motion detected"
|
||||
Maximum length of 20 characters */
|
||||
char name[20];
|
||||
/* GPIO pin to monitor for state changes */
|
||||
uint8_t monitor_pin;
|
||||
/* Whether or not the GPIO pin state detection is triggered on HIGH (1)
|
||||
Otherwise LOW (0) */
|
||||
bool detection_triggered_high;
|
||||
/* Whether or not use INPUT_PULLUP mode for GPIO pin
|
||||
Only applicable if the board uses pull-up resistors on the pin */
|
||||
bool use_pullup;
|
||||
} meshtastic_ModuleConfig_DetectionSensorConfig;
|
||||
|
||||
/* Audio Config for codec2 voice */
|
||||
typedef struct _meshtastic_ModuleConfig_AudioConfig {
|
||||
/* Whether Audio is enabled */
|
||||
@@ -286,13 +313,14 @@ Initially created for the RAK14001 RGB LED module. */
|
||||
typedef struct _meshtastic_ModuleConfig_AmbientLightingConfig {
|
||||
/* Sets LED to on or off. */
|
||||
bool led_state;
|
||||
/* Sets the overall current for the LED, firmware side range for the RAK14001 is 1-31, but users should be given a range of 0-100% */
|
||||
/* Sets the current for the LED output. Default is 10. */
|
||||
uint8_t current;
|
||||
uint8_t red; /* Red level */
|
||||
/* Sets the green level of the LED, firmware side values are 0-255, but users should be given a range of 0-100% */
|
||||
uint8_t green; /* Green level */
|
||||
/* Sets the blue level of the LED, firmware side values are 0-255, but users should be given a range of 0-100% */
|
||||
uint8_t blue; /* Blue level */
|
||||
/* Sets the red LED level. Values are 0-255. */
|
||||
uint8_t red;
|
||||
/* Sets the green LED level. Values are 0-255. */
|
||||
uint8_t green;
|
||||
/* Sets the blue LED level. Values are 0-255. */
|
||||
uint8_t blue;
|
||||
} meshtastic_ModuleConfig_AmbientLightingConfig;
|
||||
|
||||
/* A GPIO pin definition for remote hardware module */
|
||||
@@ -342,6 +370,8 @@ typedef struct _meshtastic_ModuleConfig {
|
||||
meshtastic_ModuleConfig_NeighborInfoConfig neighbor_info;
|
||||
/* TODO: REPLACE */
|
||||
meshtastic_ModuleConfig_AmbientLightingConfig ambient_lighting;
|
||||
/* TODO: REPLACE */
|
||||
meshtastic_ModuleConfig_DetectionSensorConfig detection_sensor;
|
||||
} payload_variant;
|
||||
} meshtastic_ModuleConfig;
|
||||
|
||||
@@ -375,6 +405,7 @@ extern "C" {
|
||||
|
||||
|
||||
|
||||
|
||||
#define meshtastic_ModuleConfig_AudioConfig_bitrate_ENUMTYPE meshtastic_ModuleConfig_AudioConfig_Audio_Baud
|
||||
|
||||
#define meshtastic_ModuleConfig_SerialConfig_baud_ENUMTYPE meshtastic_ModuleConfig_SerialConfig_Serial_Baud
|
||||
@@ -397,6 +428,7 @@ extern "C" {
|
||||
#define meshtastic_ModuleConfig_MQTTConfig_init_default {0, "", "", "", 0, 0, 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}
|
||||
#define meshtastic_ModuleConfig_AudioConfig_init_default {0, 0, _meshtastic_ModuleConfig_AudioConfig_Audio_Baud_MIN, 0, 0, 0, 0}
|
||||
#define meshtastic_ModuleConfig_SerialConfig_init_default {0, 0, 0, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Baud_MIN, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Mode_MIN, 0}
|
||||
#define meshtastic_ModuleConfig_ExternalNotificationConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
@@ -410,6 +442,7 @@ extern "C" {
|
||||
#define meshtastic_ModuleConfig_MQTTConfig_init_zero {0, "", "", "", 0, 0, 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}
|
||||
#define meshtastic_ModuleConfig_AudioConfig_init_zero {0, 0, _meshtastic_ModuleConfig_AudioConfig_Audio_Baud_MIN, 0, 0, 0, 0}
|
||||
#define meshtastic_ModuleConfig_SerialConfig_init_zero {0, 0, 0, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Baud_MIN, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Mode_MIN, 0}
|
||||
#define meshtastic_ModuleConfig_ExternalNotificationConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
@@ -432,6 +465,14 @@ extern "C" {
|
||||
#define meshtastic_ModuleConfig_MQTTConfig_proxy_to_client_enabled_tag 9
|
||||
#define meshtastic_ModuleConfig_NeighborInfoConfig_enabled_tag 1
|
||||
#define meshtastic_ModuleConfig_NeighborInfoConfig_update_interval_tag 2
|
||||
#define meshtastic_ModuleConfig_DetectionSensorConfig_enabled_tag 1
|
||||
#define meshtastic_ModuleConfig_DetectionSensorConfig_minimum_broadcast_secs_tag 2
|
||||
#define meshtastic_ModuleConfig_DetectionSensorConfig_state_broadcast_secs_tag 3
|
||||
#define meshtastic_ModuleConfig_DetectionSensorConfig_send_bell_tag 4
|
||||
#define meshtastic_ModuleConfig_DetectionSensorConfig_name_tag 5
|
||||
#define meshtastic_ModuleConfig_DetectionSensorConfig_monitor_pin_tag 6
|
||||
#define meshtastic_ModuleConfig_DetectionSensorConfig_detection_triggered_high_tag 7
|
||||
#define meshtastic_ModuleConfig_DetectionSensorConfig_use_pullup_tag 8
|
||||
#define meshtastic_ModuleConfig_AudioConfig_codec2_enabled_tag 1
|
||||
#define meshtastic_ModuleConfig_AudioConfig_ptt_pin_tag 2
|
||||
#define meshtastic_ModuleConfig_AudioConfig_bitrate_tag 3
|
||||
@@ -509,6 +550,7 @@ extern "C" {
|
||||
#define meshtastic_ModuleConfig_remote_hardware_tag 9
|
||||
#define meshtastic_ModuleConfig_neighbor_info_tag 10
|
||||
#define meshtastic_ModuleConfig_ambient_lighting_tag 11
|
||||
#define meshtastic_ModuleConfig_detection_sensor_tag 12
|
||||
|
||||
/* Struct field encoding specification for nanopb */
|
||||
#define meshtastic_ModuleConfig_FIELDLIST(X, a) \
|
||||
@@ -522,7 +564,8 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,canned_message,payload_varia
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,audio,payload_variant.audio), 8) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,remote_hardware,payload_variant.remote_hardware), 9) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,neighbor_info,payload_variant.neighbor_info), 10) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,ambient_lighting,payload_variant.ambient_lighting), 11)
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,ambient_lighting,payload_variant.ambient_lighting), 11) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,detection_sensor,payload_variant.detection_sensor), 12)
|
||||
#define meshtastic_ModuleConfig_CALLBACK NULL
|
||||
#define meshtastic_ModuleConfig_DEFAULT NULL
|
||||
#define meshtastic_ModuleConfig_payload_variant_mqtt_MSGTYPE meshtastic_ModuleConfig_MQTTConfig
|
||||
@@ -536,6 +579,7 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,ambient_lighting,payload_var
|
||||
#define meshtastic_ModuleConfig_payload_variant_remote_hardware_MSGTYPE meshtastic_ModuleConfig_RemoteHardwareConfig
|
||||
#define meshtastic_ModuleConfig_payload_variant_neighbor_info_MSGTYPE meshtastic_ModuleConfig_NeighborInfoConfig
|
||||
#define meshtastic_ModuleConfig_payload_variant_ambient_lighting_MSGTYPE meshtastic_ModuleConfig_AmbientLightingConfig
|
||||
#define meshtastic_ModuleConfig_payload_variant_detection_sensor_MSGTYPE meshtastic_ModuleConfig_DetectionSensorConfig
|
||||
|
||||
#define meshtastic_ModuleConfig_MQTTConfig_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, BOOL, enabled, 1) \
|
||||
@@ -564,6 +608,18 @@ X(a, STATIC, SINGULAR, UINT32, update_interval, 2)
|
||||
#define meshtastic_ModuleConfig_NeighborInfoConfig_CALLBACK NULL
|
||||
#define meshtastic_ModuleConfig_NeighborInfoConfig_DEFAULT NULL
|
||||
|
||||
#define meshtastic_ModuleConfig_DetectionSensorConfig_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, BOOL, enabled, 1) \
|
||||
X(a, STATIC, SINGULAR, UINT32, minimum_broadcast_secs, 2) \
|
||||
X(a, STATIC, SINGULAR, UINT32, state_broadcast_secs, 3) \
|
||||
X(a, STATIC, SINGULAR, BOOL, send_bell, 4) \
|
||||
X(a, STATIC, SINGULAR, STRING, name, 5) \
|
||||
X(a, STATIC, SINGULAR, UINT32, monitor_pin, 6) \
|
||||
X(a, STATIC, SINGULAR, BOOL, detection_triggered_high, 7) \
|
||||
X(a, STATIC, SINGULAR, BOOL, use_pullup, 8)
|
||||
#define meshtastic_ModuleConfig_DetectionSensorConfig_CALLBACK NULL
|
||||
#define meshtastic_ModuleConfig_DetectionSensorConfig_DEFAULT NULL
|
||||
|
||||
#define meshtastic_ModuleConfig_AudioConfig_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, BOOL, codec2_enabled, 1) \
|
||||
X(a, STATIC, SINGULAR, UINT32, ptt_pin, 2) \
|
||||
@@ -667,6 +723,7 @@ extern const pb_msgdesc_t meshtastic_ModuleConfig_msg;
|
||||
extern const pb_msgdesc_t meshtastic_ModuleConfig_MQTTConfig_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;
|
||||
extern const pb_msgdesc_t meshtastic_ModuleConfig_AudioConfig_msg;
|
||||
extern const pb_msgdesc_t meshtastic_ModuleConfig_SerialConfig_msg;
|
||||
extern const pb_msgdesc_t meshtastic_ModuleConfig_ExternalNotificationConfig_msg;
|
||||
@@ -682,6 +739,7 @@ extern const pb_msgdesc_t meshtastic_RemoteHardwarePin_msg;
|
||||
#define meshtastic_ModuleConfig_MQTTConfig_fields &meshtastic_ModuleConfig_MQTTConfig_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
|
||||
#define meshtastic_ModuleConfig_AudioConfig_fields &meshtastic_ModuleConfig_AudioConfig_msg
|
||||
#define meshtastic_ModuleConfig_SerialConfig_fields &meshtastic_ModuleConfig_SerialConfig_msg
|
||||
#define meshtastic_ModuleConfig_ExternalNotificationConfig_fields &meshtastic_ModuleConfig_ExternalNotificationConfig_msg
|
||||
@@ -696,6 +754,7 @@ extern const pb_msgdesc_t meshtastic_RemoteHardwarePin_msg;
|
||||
#define meshtastic_ModuleConfig_AmbientLightingConfig_size 14
|
||||
#define meshtastic_ModuleConfig_AudioConfig_size 19
|
||||
#define meshtastic_ModuleConfig_CannedMessageConfig_size 49
|
||||
#define meshtastic_ModuleConfig_DetectionSensorConfig_size 44
|
||||
#define meshtastic_ModuleConfig_ExternalNotificationConfig_size 40
|
||||
#define meshtastic_ModuleConfig_MQTTConfig_size 222
|
||||
#define meshtastic_ModuleConfig_NeighborInfoConfig_size 8
|
||||
|
||||
@@ -25,73 +25,103 @@
|
||||
typedef enum _meshtastic_PortNum {
|
||||
/* Deprecated: do not use in new code (formerly called OPAQUE)
|
||||
A message sent from a device outside of the mesh, in a form the mesh does not understand
|
||||
NOTE: This must be 0, because it is documented in IMeshService.aidl to be so */
|
||||
NOTE: This must be 0, because it is documented in IMeshService.aidl to be so
|
||||
ENCODING: binary undefined */
|
||||
meshtastic_PortNum_UNKNOWN_APP = 0,
|
||||
/* A simple UTF-8 text message, which even the little micros in the mesh
|
||||
can understand and show on their screen eventually in some circumstances
|
||||
even signal might send messages in this form (see below) */
|
||||
even signal might send messages in this form (see below)
|
||||
ENCODING: UTF-8 Plaintext (?) */
|
||||
meshtastic_PortNum_TEXT_MESSAGE_APP = 1,
|
||||
/* Reserved for built-in GPIO/example app.
|
||||
See remote_hardware.proto/HardwareMessage for details on the message sent/received to this port number */
|
||||
See remote_hardware.proto/HardwareMessage for details on the message sent/received to this port number
|
||||
ENCODING: Protobuf */
|
||||
meshtastic_PortNum_REMOTE_HARDWARE_APP = 2,
|
||||
/* The built-in position messaging app.
|
||||
Payload is a [Position](/docs/developers/protobufs/api#position) message */
|
||||
Payload is a [Position](/docs/developers/protobufs/api#position) message
|
||||
ENCODING: Protobuf */
|
||||
meshtastic_PortNum_POSITION_APP = 3,
|
||||
/* The built-in user info app.
|
||||
Payload is a [User](/docs/developers/protobufs/api#user) message */
|
||||
Payload is a [User](/docs/developers/protobufs/api#user) message
|
||||
ENCODING: Protobuf */
|
||||
meshtastic_PortNum_NODEINFO_APP = 4,
|
||||
/* Protocol control packets for mesh protocol use.
|
||||
Payload is a [Routing](/docs/developers/protobufs/api#routing) message */
|
||||
Payload is a [Routing](/docs/developers/protobufs/api#routing) message
|
||||
ENCODING: Protobuf */
|
||||
meshtastic_PortNum_ROUTING_APP = 5,
|
||||
/* Admin control packets.
|
||||
Payload is a [AdminMessage](/docs/developers/protobufs/api#adminmessage) message */
|
||||
Payload is a [AdminMessage](/docs/developers/protobufs/api#adminmessage) message
|
||||
ENCODING: Protobuf */
|
||||
meshtastic_PortNum_ADMIN_APP = 6,
|
||||
/* Compressed TEXT_MESSAGE payloads. */
|
||||
/* Compressed TEXT_MESSAGE payloads.
|
||||
ENCODING: UTF-8 Plaintext (?) with Unishox2 Compression
|
||||
NOTE: The Device Firmware converts a TEXT_MESSAGE_APP to TEXT_MESSAGE_COMPRESSED_APP if the compressed
|
||||
payload is shorter. There's no need for app developers to do this themselves. Also the firmware will decompress
|
||||
any incoming TEXT_MESSAGE_COMPRESSED_APP payload and convert to TEXT_MESSAGE_APP. */
|
||||
meshtastic_PortNum_TEXT_MESSAGE_COMPRESSED_APP = 7,
|
||||
/* Waypoint payloads.
|
||||
Payload is a [Waypoint](/docs/developers/protobufs/api#waypoint) message */
|
||||
Payload is a [Waypoint](/docs/developers/protobufs/api#waypoint) message
|
||||
ENCODING: Protobuf */
|
||||
meshtastic_PortNum_WAYPOINT_APP = 8,
|
||||
/* Audio Payloads.
|
||||
Encapsulated codec2 packets. On 2.4 GHZ Bandwidths only for now */
|
||||
Encapsulated codec2 packets. On 2.4 GHZ Bandwidths only for now
|
||||
ENCODING: codec2 audio frames
|
||||
NOTE: audio frames contain a 3 byte header (0xc0 0xde 0xc2) and a one byte marker for the decompressed bitrate.
|
||||
This marker comes from the 'moduleConfig.audio.bitrate' enum minus one. */
|
||||
meshtastic_PortNum_AUDIO_APP = 9,
|
||||
/* Same as Text Message but originating from Detection Sensor Module.
|
||||
NOTE: This portnum traffic is not sent to the public MQTT starting at firmware version 2.2.9 */
|
||||
meshtastic_PortNum_DETECTION_SENSOR_APP = 10,
|
||||
/* Provides a 'ping' service that replies to any packet it receives.
|
||||
Also serves as a small example module. */
|
||||
Also serves as a small example module.
|
||||
ENCODING: ASCII Plaintext */
|
||||
meshtastic_PortNum_REPLY_APP = 32,
|
||||
/* Used for the python IP tunnel feature */
|
||||
/* Used for the python IP tunnel feature
|
||||
ENCODING: IP Packet. Handled by the python API, firmware ignores this one and pases on. */
|
||||
meshtastic_PortNum_IP_TUNNEL_APP = 33,
|
||||
/* Provides a hardware serial interface to send and receive from the Meshtastic network.
|
||||
Connect to the RX/TX pins of a device with 38400 8N1. Packets received from the Meshtastic
|
||||
network is forwarded to the RX pin while sending a packet to TX will go out to the Mesh network.
|
||||
Maximum packet size of 240 bytes.
|
||||
Module is disabled by default can be turned on by setting SERIAL_MODULE_ENABLED = 1 in SerialPlugh.cpp. */
|
||||
Module is disabled by default can be turned on by setting SERIAL_MODULE_ENABLED = 1 in SerialPlugh.cpp.
|
||||
ENCODING: binary undefined */
|
||||
meshtastic_PortNum_SERIAL_APP = 64,
|
||||
/* STORE_FORWARD_APP (Work in Progress)
|
||||
Maintained by Jm Casler (MC Hamster) : jm@casler.org */
|
||||
Maintained by Jm Casler (MC Hamster) : jm@casler.org
|
||||
ENCODING: Protobuf */
|
||||
meshtastic_PortNum_STORE_FORWARD_APP = 65,
|
||||
/* Optional port for messages for the range test module. */
|
||||
/* Optional port for messages for the range test module.
|
||||
ENCODING: ASCII Plaintext
|
||||
NOTE: This portnum traffic is not sent to the public MQTT starting at firmware version 2.2.9 */
|
||||
meshtastic_PortNum_RANGE_TEST_APP = 66,
|
||||
/* Provides a format to send and receive telemetry data from the Meshtastic network.
|
||||
Maintained by Charles Crossan (crossan007) : crossan007@gmail.com */
|
||||
Maintained by Charles Crossan (crossan007) : crossan007@gmail.com
|
||||
ENCODING: Protobuf */
|
||||
meshtastic_PortNum_TELEMETRY_APP = 67,
|
||||
/* Experimental tools for estimating node position without a GPS
|
||||
Maintained by Github user a-f-G-U-C (a Meshtastic contributor)
|
||||
Project files at https://github.com/a-f-G-U-C/Meshtastic-ZPS */
|
||||
Project files at https://github.com/a-f-G-U-C/Meshtastic-ZPS
|
||||
ENCODING: arrays of int64 fields */
|
||||
meshtastic_PortNum_ZPS_APP = 68,
|
||||
/* Used to let multiple instances of Linux native applications communicate
|
||||
as if they did using their LoRa chip.
|
||||
Maintained by GitHub user GUVWAF.
|
||||
Project files at https://github.com/GUVWAF/Meshtasticator */
|
||||
Project files at https://github.com/GUVWAF/Meshtasticator
|
||||
ENCODING: Protobuf (?) */
|
||||
meshtastic_PortNum_SIMULATOR_APP = 69,
|
||||
/* Provides a traceroute functionality to show the route a packet towards
|
||||
a certain destination would take on the mesh. */
|
||||
a certain destination would take on the mesh.
|
||||
ENCODING: Protobuf */
|
||||
meshtastic_PortNum_TRACEROUTE_APP = 70,
|
||||
/* Aggregates edge info for the network by sending out a list of each node's neighbors */
|
||||
/* Aggregates edge info for the network by sending out a list of each node's neighbors
|
||||
ENCODING: Protobuf */
|
||||
meshtastic_PortNum_NEIGHBORINFO_APP = 71,
|
||||
/* Private applications should use portnums >= 256.
|
||||
To simplify initial development and testing you can use "PRIVATE_APP"
|
||||
in your code without needing to rebuild protobuf files (via [regen-protos.sh](https://github.com/meshtastic/firmware/blob/master/bin/regen-protos.sh)) */
|
||||
meshtastic_PortNum_PRIVATE_APP = 256,
|
||||
/* ATAK Forwarder Module https://github.com/paulmandal/atak-forwarder */
|
||||
/* ATAK Forwarder Module https://github.com/paulmandal/atak-forwarder
|
||||
ENCODING: libcotshrink */
|
||||
meshtastic_PortNum_ATAK_FORWARDER = 257,
|
||||
/* Currently we limit port nums to no higher than this value */
|
||||
meshtastic_PortNum_MAX = 511
|
||||
|
||||
@@ -101,11 +101,7 @@ typedef struct _meshtastic_AirQualityMetrics {
|
||||
|
||||
/* Types of Measurements the telemetry module is equipped to handle */
|
||||
typedef struct _meshtastic_Telemetry {
|
||||
/* This is usually not sent over the mesh (to save space), but it is sent
|
||||
from the phone so that the local device can set its RTC If it is sent over
|
||||
the mesh (because there are devices on the mesh without GPS), it will only
|
||||
be sent by devices which has a hardware GPS clock (IE Mobile Phone).
|
||||
seconds since 1970 */
|
||||
/* Seconds since 1970 - or 0 for unknown/unset */
|
||||
uint32_t time;
|
||||
pb_size_t which_variant;
|
||||
union {
|
||||
|
||||
@@ -402,7 +402,6 @@ void handleStatic(HTTPRequest *req, HTTPResponse *res)
|
||||
"href=/admin>admin</a>");
|
||||
|
||||
return;
|
||||
|
||||
} else {
|
||||
res->setHeader("Content-Encoding", "gzip");
|
||||
}
|
||||
@@ -438,7 +437,6 @@ void handleStatic(HTTPRequest *req, HTTPResponse *res)
|
||||
file.close();
|
||||
|
||||
return;
|
||||
|
||||
} else {
|
||||
LOG_ERROR("This should not have happened...\n");
|
||||
res->println("ERROR: This should not have happened...");
|
||||
@@ -467,7 +465,7 @@ void handleFormUpload(HTTPRequest *req, HTTPResponse *res)
|
||||
// first semicolon, if one exists:
|
||||
size_t semicolonPos = contentType.find(";");
|
||||
if (semicolonPos != std::string::npos) {
|
||||
contentType = contentType.substr(0, semicolonPos);
|
||||
contentType.resize(semicolonPos);
|
||||
}
|
||||
|
||||
// Now, we can decide based on the content type:
|
||||
@@ -581,7 +579,6 @@ void handleReport(HTTPRequest *req, HTTPResponse *res)
|
||||
res->setHeader("Content-Type", "application/json");
|
||||
res->setHeader("Access-Control-Allow-Origin", "*");
|
||||
res->setHeader("Access-Control-Allow-Methods", "GET");
|
||||
|
||||
} else {
|
||||
res->setHeader("Content-Type", "text/html");
|
||||
res->println("<pre>");
|
||||
@@ -857,4 +854,4 @@ void handleScanNetworks(HTTPRequest *req, HTTPResponse *res)
|
||||
JSONValue *value = new JSONValue(jsonObjOuter);
|
||||
res->print(value->Stringify().c_str());
|
||||
delete value;
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,7 @@ bool pb_decode_from_bytes(const uint8_t *srcbuf, size_t srcbufsize, const pb_msg
|
||||
{
|
||||
pb_istream_t stream = pb_istream_from_buffer(srcbuf, srcbufsize);
|
||||
if (!pb_decode(&stream, fields, dest_struct)) {
|
||||
LOG_ERROR("Can't decode protobuf reason='%s', pb_msgdesc 0x%p\n", PB_GET_ERROR(&stream), fields);
|
||||
LOG_ERROR("Can't decode protobuf reason='%s', pb_msgdesc %p\n", PB_GET_ERROR(&stream), fields);
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
#define MAX_RX_TOPHONE 32
|
||||
|
||||
/// max number of nodes allowed in the mesh
|
||||
#define MAX_NUM_NODES (member_size(meshtastic_DeviceState, node_db) / member_size(meshtastic_DeviceState, node_db[0]))
|
||||
#define MAX_NUM_NODES (member_size(meshtastic_DeviceState, node_db_lite) / member_size(meshtastic_DeviceState, node_db_lite[0]))
|
||||
|
||||
/// Max number of channels allowed
|
||||
#define MAX_NUM_CHANNELS (member_size(meshtastic_ChannelFile, channels) / member_size(meshtastic_ChannelFile, channels[0]))
|
||||
|
||||
58
src/meshUtils.cpp
Normal file
58
src/meshUtils.cpp
Normal file
@@ -0,0 +1,58 @@
|
||||
#include "meshUtils.h"
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* Find the first occurrence of find in s, where the search is limited to the
|
||||
* first slen characters of s.
|
||||
* -
|
||||
* Copyright (c) 2001 Mike Barcroft <mike@FreeBSD.org>
|
||||
* Copyright (c) 1990, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Chris Torek.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
char *strnstr(const char *s, const char *find, size_t slen)
|
||||
{
|
||||
char c, sc;
|
||||
size_t len;
|
||||
|
||||
if ((c = *find++) != '\0') {
|
||||
len = strlen(find);
|
||||
do {
|
||||
do {
|
||||
if (slen-- < 1 || (sc = *s++) == '\0')
|
||||
return (NULL);
|
||||
} while (sc != c);
|
||||
if (len > slen)
|
||||
return (NULL);
|
||||
} while (strncmp(s, find, len) != 0);
|
||||
s--;
|
||||
}
|
||||
return ((char *)s);
|
||||
}
|
||||
@@ -4,4 +4,9 @@
|
||||
template <class T> constexpr const T &clamp(const T &v, const T &lo, const T &hi)
|
||||
{
|
||||
return (v < lo) ? lo : (hi < v) ? hi : v;
|
||||
}
|
||||
}
|
||||
|
||||
#if (defined(ARCH_PORTDUINO) && !defined(STRNSTR))
|
||||
#define STRNSTR
|
||||
char *strnstr(const char *s, const char *find, size_t slen);
|
||||
#endif
|
||||
@@ -368,6 +368,16 @@ void AdminModule::handleSetModuleConfig(const meshtastic_ModuleConfig &c)
|
||||
moduleConfig.has_remote_hardware = true;
|
||||
moduleConfig.remote_hardware = c.payload_variant.remote_hardware;
|
||||
break;
|
||||
case meshtastic_ModuleConfig_neighbor_info_tag:
|
||||
LOG_INFO("Setting module config: Neighbor Info\n");
|
||||
moduleConfig.has_neighbor_info = true;
|
||||
moduleConfig.neighbor_info = c.payload_variant.neighbor_info;
|
||||
break;
|
||||
case meshtastic_ModuleConfig_detection_sensor_tag:
|
||||
LOG_INFO("Setting module config: Detection Sensor\n");
|
||||
moduleConfig.has_detection_sensor = true;
|
||||
moduleConfig.detection_sensor = c.payload_variant.detection_sensor;
|
||||
break;
|
||||
}
|
||||
|
||||
saveChanges(SEGMENT_MODULECONFIG);
|
||||
@@ -503,6 +513,16 @@ void AdminModule::handleGetModuleConfig(const meshtastic_MeshPacket &req, const
|
||||
res.get_module_config_response.which_payload_variant = meshtastic_ModuleConfig_remote_hardware_tag;
|
||||
res.get_module_config_response.payload_variant.remote_hardware = moduleConfig.remote_hardware;
|
||||
break;
|
||||
case meshtastic_AdminMessage_ModuleConfigType_NEIGHBORINFO_CONFIG:
|
||||
LOG_INFO("Getting module config: Neighbor Info\n");
|
||||
res.get_module_config_response.which_payload_variant = meshtastic_ModuleConfig_neighbor_info_tag;
|
||||
res.get_module_config_response.payload_variant.neighbor_info = moduleConfig.neighbor_info;
|
||||
break;
|
||||
case meshtastic_AdminMessage_ModuleConfigType_DETECTIONSENSOR_CONFIG:
|
||||
LOG_INFO("Getting module config: Detection Sensor\n");
|
||||
res.get_module_config_response.which_payload_variant = meshtastic_ModuleConfig_detection_sensor_tag;
|
||||
res.get_module_config_response.payload_variant.detection_sensor = moduleConfig.detection_sensor;
|
||||
break;
|
||||
}
|
||||
|
||||
// NOTE: The phone app needs to know the ls_secsvalue so it can properly expect sleep behavior.
|
||||
@@ -663,4 +683,4 @@ AdminModule::AdminModule() : ProtobufModule("Admin", meshtastic_PortNum_ADMIN_AP
|
||||
{
|
||||
// restrict to the admin channel for rx
|
||||
boundChannel = Channels::adminChannel;
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,10 @@
|
||||
|
||||
#include "main.h" // for cardkb_found
|
||||
|
||||
#ifndef INPUTBROKER_MATRIX_TYPE
|
||||
#define INPUTBROKER_MATRIX_TYPE 0
|
||||
#endif
|
||||
|
||||
#ifdef OLED_RU
|
||||
#include "graphics/fonts/OLEDDisplayFontsRU.h"
|
||||
#endif
|
||||
@@ -18,7 +22,9 @@
|
||||
#include "graphics/fonts/OLEDDisplayFontsUA.h"
|
||||
#endif
|
||||
|
||||
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)
|
||||
#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
|
||||
#define FONT_MEDIUM ArialMT_Plain_24
|
||||
@@ -57,9 +63,10 @@ CannedMessageModule *cannedMessageModule;
|
||||
CannedMessageModule::CannedMessageModule()
|
||||
: SinglePortModule("canned", meshtastic_PortNum_TEXT_MESSAGE_APP), concurrency::OSThread("CannedMessageModule")
|
||||
{
|
||||
if (moduleConfig.canned_message.enabled) {
|
||||
if (moduleConfig.canned_message.enabled || CANNED_MESSAGE_MODULE_ENABLE) {
|
||||
this->loadProtoForModule();
|
||||
if ((this->splitConfiguredMessages() <= 0) && (cardkb_found.address != CARDKB_ADDR)) {
|
||||
if ((this->splitConfiguredMessages() <= 0) && (cardkb_found.address == 0x00) && !INPUTBROKER_MATRIX_TYPE &&
|
||||
!CANNED_MESSAGE_MODULE_ENABLE) {
|
||||
LOG_INFO("CannedMessageModule: No messages are configured. Module is disabled\n");
|
||||
this->runState = CANNED_MESSAGE_RUN_STATE_DISABLED;
|
||||
disable();
|
||||
@@ -134,12 +141,12 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event)
|
||||
|
||||
bool validEvent = false;
|
||||
if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP)) {
|
||||
LOG_DEBUG("Canned message event UP\n");
|
||||
// LOG_DEBUG("Canned message event UP\n");
|
||||
this->runState = CANNED_MESSAGE_RUN_STATE_ACTION_UP;
|
||||
validEvent = true;
|
||||
}
|
||||
if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN)) {
|
||||
LOG_DEBUG("Canned message event DOWN\n");
|
||||
// LOG_DEBUG("Canned message event DOWN\n");
|
||||
this->runState = CANNED_MESSAGE_RUN_STATE_ACTION_DOWN;
|
||||
validEvent = true;
|
||||
}
|
||||
@@ -163,7 +170,7 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event)
|
||||
if ((event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_BACK)) ||
|
||||
(event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT)) ||
|
||||
(event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT))) {
|
||||
LOG_DEBUG("Canned message event (%x)\n", event->kbchar);
|
||||
// LOG_DEBUG("Canned message event (%x)\n", event->kbchar);
|
||||
// tweak for left/right events generated via trackball/touch with empty kbchar
|
||||
if (!event->kbchar) {
|
||||
if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT)) {
|
||||
@@ -188,6 +195,7 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event)
|
||||
this->runState = CANNED_MESSAGE_RUN_STATE_FREETEXT;
|
||||
}
|
||||
// pass the pressed key
|
||||
// LOG_DEBUG("Canned message ANYKEY (%x)\n", event->kbchar);
|
||||
this->payload = event->kbchar;
|
||||
this->lastTouchMillis = millis();
|
||||
validEvent = true;
|
||||
@@ -217,9 +225,9 @@ void CannedMessageModule::sendText(NodeNum dest, const char *message, bool wantR
|
||||
p->want_ack = true;
|
||||
p->decoded.payload.size = strlen(message);
|
||||
memcpy(p->decoded.payload.bytes, message, p->decoded.payload.size);
|
||||
if (moduleConfig.canned_message.send_bell) {
|
||||
p->decoded.payload.bytes[p->decoded.payload.size - 1] = 7; // Bell character
|
||||
p->decoded.payload.bytes[p->decoded.payload.size] = '\0'; // Bell character
|
||||
if (moduleConfig.canned_message.send_bell && p->decoded.payload.size < meshtastic_Constants_DATA_PAYLOAD_LEN) {
|
||||
p->decoded.payload.bytes[p->decoded.payload.size] = 7; // Bell character
|
||||
p->decoded.payload.bytes[p->decoded.payload.size + 1] = '\0'; // Bell character
|
||||
p->decoded.payload.size++;
|
||||
}
|
||||
|
||||
@@ -230,8 +238,8 @@ void CannedMessageModule::sendText(NodeNum dest, const char *message, bool wantR
|
||||
|
||||
int32_t CannedMessageModule::runOnce()
|
||||
{
|
||||
if ((!moduleConfig.canned_message.enabled) || (this->runState == CANNED_MESSAGE_RUN_STATE_DISABLED) ||
|
||||
(this->runState == CANNED_MESSAGE_RUN_STATE_INACTIVE)) {
|
||||
if (((!moduleConfig.canned_message.enabled) && !CANNED_MESSAGE_MODULE_ENABLE) ||
|
||||
(this->runState == CANNED_MESSAGE_RUN_STATE_DISABLED) || (this->runState == CANNED_MESSAGE_RUN_STATE_INACTIVE)) {
|
||||
return INT32_MAX;
|
||||
}
|
||||
// LOG_DEBUG("Check status\n");
|
||||
@@ -391,9 +399,10 @@ int32_t CannedMessageModule::runOnce()
|
||||
this->freetext.substring(0, this->cursor) + this->payload + this->freetext.substring(this->cursor);
|
||||
}
|
||||
this->cursor += 1;
|
||||
if (this->freetext.length() > meshtastic_Constants_DATA_PAYLOAD_LEN) {
|
||||
this->cursor = meshtastic_Constants_DATA_PAYLOAD_LEN;
|
||||
this->freetext = this->freetext.substring(0, meshtastic_Constants_DATA_PAYLOAD_LEN);
|
||||
uint16_t maxChars = meshtastic_Constants_DATA_PAYLOAD_LEN - (moduleConfig.canned_message.send_bell ? 1 : 0);
|
||||
if (this->freetext.length() > maxChars) {
|
||||
this->cursor = maxChars;
|
||||
this->freetext = this->freetext.substring(0, maxChars);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -446,7 +455,7 @@ const char *CannedMessageModule::getNodeName(NodeNum node)
|
||||
|
||||
bool CannedMessageModule::shouldDraw()
|
||||
{
|
||||
if (!moduleConfig.canned_message.enabled) {
|
||||
if (!moduleConfig.canned_message.enabled && !CANNED_MESSAGE_MODULE_ENABLE) {
|
||||
return false;
|
||||
}
|
||||
return (currentMessageIndex != -1) || (this->runState != CANNED_MESSAGE_RUN_STATE_INACTIVE);
|
||||
@@ -492,7 +501,9 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
|
||||
}
|
||||
display->drawStringf(0 + x, 0 + y, buffer, "To: %s", cannedMessageModule->getNodeName(this->dest));
|
||||
// used chars right aligned
|
||||
snprintf(buffer, sizeof(buffer), "%d left", meshtastic_Constants_DATA_PAYLOAD_LEN - this->freetext.length());
|
||||
uint16_t charsLeft =
|
||||
meshtastic_Constants_DATA_PAYLOAD_LEN - this->freetext.length() - (moduleConfig.canned_message.send_bell ? 1 : 0);
|
||||
snprintf(buffer, sizeof(buffer), "%d left", charsLeft);
|
||||
display->drawString(x + display->getWidth() - display->getStringWidth(buffer), y + 0, buffer);
|
||||
if (this->destSelect) {
|
||||
display->drawString(x + display->getWidth() - display->getStringWidth(buffer) - 1, y + 0, buffer);
|
||||
@@ -639,4 +650,4 @@ String CannedMessageModule::drawWithCursor(String text, int cursor)
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -20,6 +20,10 @@ enum cannedMessageModuleRunState {
|
||||
*/
|
||||
#define CANNED_MESSAGE_MODULE_MESSAGES_SIZE 800
|
||||
|
||||
#ifndef CANNED_MESSAGE_MODULE_ENABLE
|
||||
#define CANNED_MESSAGE_MODULE_ENABLE 0
|
||||
#endif
|
||||
|
||||
class CannedMessageModule : public SinglePortModule, public Observable<const UIFrameEvent *>, private concurrency::OSThread
|
||||
{
|
||||
CallbackObserver<CannedMessageModule, const InputEvent *> inputObserver =
|
||||
|
||||
102
src/modules/DetectionSensorModule.cpp
Normal file
102
src/modules/DetectionSensorModule.cpp
Normal file
@@ -0,0 +1,102 @@
|
||||
#include "DetectionSensorModule.h"
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
#include "PowerFSM.h"
|
||||
#include "configuration.h"
|
||||
#include "main.h"
|
||||
|
||||
DetectionSensorModule *detectionSensorModule;
|
||||
|
||||
#define GPIO_POLLING_INTERVAL 100
|
||||
#define DELAYED_INTERVAL 1000
|
||||
|
||||
int32_t DetectionSensorModule::runOnce()
|
||||
{
|
||||
/*
|
||||
Uncomment the preferences below if you want to use the module
|
||||
without having to configure it from the PythonAPI or WebUI.
|
||||
*/
|
||||
// moduleConfig.detection_sensor.enabled = true;
|
||||
// moduleConfig.detection_sensor.monitor_pin = 10; // WisBlock PIR IO6
|
||||
// moduleConfig.detection_sensor.monitor_pin = 21; // WisBlock RAK12013 Radar IO6
|
||||
// moduleConfig.detection_sensor.minimum_broadcast_secs = 30;
|
||||
// moduleConfig.detection_sensor.state_broadcast_secs = 120;
|
||||
// moduleConfig.detection_sensor.detection_triggered_high = true;
|
||||
// strcpy(moduleConfig.detection_sensor.name, "Motion");
|
||||
|
||||
if (moduleConfig.detection_sensor.enabled == false)
|
||||
return disable();
|
||||
|
||||
if (firstTime) {
|
||||
// This is the first time the OSThread library has called this function, so do some setup
|
||||
firstTime = false;
|
||||
if (moduleConfig.detection_sensor.monitor_pin > 0) {
|
||||
pinMode(moduleConfig.detection_sensor.monitor_pin, moduleConfig.detection_sensor.use_pullup ? INPUT_PULLUP : INPUT);
|
||||
} else {
|
||||
LOG_WARN("Detection Sensor Module: Set to enabled but no monitor pin is set. Disabling module...\n");
|
||||
return disable();
|
||||
}
|
||||
LOG_INFO("Detection Sensor Module: Initializing\n");
|
||||
|
||||
return DELAYED_INTERVAL;
|
||||
}
|
||||
|
||||
// LOG_DEBUG("Detection Sensor Module: Current pin state: %i\n", digitalRead(moduleConfig.detection_sensor.monitor_pin));
|
||||
|
||||
if ((millis() - lastSentToMesh) >= getConfiguredOrDefaultMs(moduleConfig.detection_sensor.minimum_broadcast_secs) &&
|
||||
hasDetectionEvent()) {
|
||||
sendDetectionMessage();
|
||||
return DELAYED_INTERVAL;
|
||||
}
|
||||
// Even if we haven't detected an event, broadcast our current state to the mesh on the scheduled interval as a sort
|
||||
// of heartbeat. We only do this if the minimum broadcast interval is greater than zero, otherwise we'll only broadcast state
|
||||
// change detections.
|
||||
else if (moduleConfig.detection_sensor.state_broadcast_secs > 0 &&
|
||||
(millis() - lastSentToMesh) >= getConfiguredOrDefaultMs(moduleConfig.detection_sensor.state_broadcast_secs)) {
|
||||
sendCurrentStateMessage();
|
||||
return DELAYED_INTERVAL;
|
||||
}
|
||||
return GPIO_POLLING_INTERVAL;
|
||||
}
|
||||
|
||||
void DetectionSensorModule::sendDetectionMessage()
|
||||
{
|
||||
LOG_DEBUG("Detected event observed. Sending message\n");
|
||||
char *message = new char[40];
|
||||
sprintf(message, "%s detected", moduleConfig.detection_sensor.name);
|
||||
meshtastic_MeshPacket *p = allocDataPacket();
|
||||
p->want_ack = false;
|
||||
p->decoded.payload.size = strlen(message);
|
||||
memcpy(p->decoded.payload.bytes, message, p->decoded.payload.size);
|
||||
if (moduleConfig.detection_sensor.send_bell && p->decoded.payload.size < meshtastic_Constants_DATA_PAYLOAD_LEN) {
|
||||
p->decoded.payload.bytes[p->decoded.payload.size] = 7; // Bell character
|
||||
p->decoded.payload.bytes[p->decoded.payload.size + 1] = '\0'; // Bell character
|
||||
p->decoded.payload.size++;
|
||||
}
|
||||
LOG_INFO("Sending message id=%d, dest=%x, msg=%.*s\n", p->id, p->to, p->decoded.payload.size, p->decoded.payload.bytes);
|
||||
lastSentToMesh = millis();
|
||||
service.sendToMesh(p);
|
||||
delete[] message;
|
||||
}
|
||||
|
||||
void DetectionSensorModule::sendCurrentStateMessage()
|
||||
{
|
||||
char *message = new char[40];
|
||||
sprintf(message, "%s state: %i", moduleConfig.detection_sensor.name, hasDetectionEvent());
|
||||
|
||||
meshtastic_MeshPacket *p = allocDataPacket();
|
||||
p->want_ack = false;
|
||||
p->decoded.payload.size = strlen(message);
|
||||
memcpy(p->decoded.payload.bytes, message, p->decoded.payload.size);
|
||||
LOG_INFO("Sending message id=%d, dest=%x, msg=%.*s\n", p->id, p->to, p->decoded.payload.size, p->decoded.payload.bytes);
|
||||
lastSentToMesh = millis();
|
||||
service.sendToMesh(p);
|
||||
delete[] message;
|
||||
}
|
||||
|
||||
bool DetectionSensorModule::hasDetectionEvent()
|
||||
{
|
||||
bool currentState = digitalRead(moduleConfig.detection_sensor.monitor_pin);
|
||||
// LOG_DEBUG("Detection Sensor Module: Current state: %i\n", currentState);
|
||||
return moduleConfig.detection_sensor.detection_triggered_high ? currentState : !currentState;
|
||||
}
|
||||
23
src/modules/DetectionSensorModule.h
Normal file
23
src/modules/DetectionSensorModule.h
Normal file
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
#include "SinglePortModule.h"
|
||||
|
||||
class DetectionSensorModule : public SinglePortModule, private concurrency::OSThread
|
||||
{
|
||||
public:
|
||||
DetectionSensorModule()
|
||||
: SinglePortModule("detection", meshtastic_PortNum_DETECTION_SENSOR_APP), OSThread("DetectionSensorModule")
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual int32_t runOnce() override;
|
||||
|
||||
private:
|
||||
bool firstTime = true;
|
||||
uint32_t lastSentToMesh = 0;
|
||||
void sendDetectionMessage();
|
||||
void sendCurrentStateMessage();
|
||||
bool hasDetectionEvent();
|
||||
};
|
||||
|
||||
extern DetectionSensorModule *detectionSensorModule;
|
||||
@@ -1,3 +1,18 @@
|
||||
/**
|
||||
* @file ExternalNotificationModule.cpp
|
||||
* @brief Implementation of the ExternalNotificationModule class.
|
||||
*
|
||||
* This file contains the implementation of the ExternalNotificationModule class, which is responsible for handling external
|
||||
* notifications such as vibration, buzzer, and LED lights. The class provides methods to turn on and off the external
|
||||
* notification outputs and to play ringtones using PWM buzzer. It also includes default configurations and a runOnce() method to
|
||||
* handle the module's behavior.
|
||||
*
|
||||
* Documentation:
|
||||
* https://meshtastic.org/docs/settings/moduleconfig/external-notification
|
||||
*
|
||||
* @author Jm Casler & Meshtastic Team
|
||||
* @date [Insert Date]
|
||||
*/
|
||||
#include "ExternalNotificationModule.h"
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
@@ -12,7 +27,6 @@
|
||||
|
||||
#ifdef HAS_NCP5623
|
||||
#include <graphics/RAKled.h>
|
||||
NCP5623 rgb;
|
||||
|
||||
uint8_t red = 0;
|
||||
uint8_t green = 0;
|
||||
@@ -113,6 +127,16 @@ int32_t ExternalNotificationModule::runOnce()
|
||||
}
|
||||
}
|
||||
|
||||
bool ExternalNotificationModule::wantPacket(const meshtastic_MeshPacket *p)
|
||||
{
|
||||
return MeshService::isTextPayload(p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the external notification on for the specified index.
|
||||
*
|
||||
* @param index The index of the external notification to turn on.
|
||||
*/
|
||||
void ExternalNotificationModule::setExternalOn(uint8_t index)
|
||||
{
|
||||
externalCurrentState[index] = 1;
|
||||
@@ -192,8 +216,8 @@ void ExternalNotificationModule::stopNow()
|
||||
}
|
||||
|
||||
ExternalNotificationModule::ExternalNotificationModule()
|
||||
: SinglePortModule("ExternalNotificationModule", meshtastic_PortNum_TEXT_MESSAGE_APP), concurrency::OSThread(
|
||||
"ExternalNotificationModule")
|
||||
: SinglePortModule("ExternalNotificationModule", meshtastic_PortNum_TEXT_MESSAGE_APP),
|
||||
concurrency::OSThread("ExternalNotificationModule")
|
||||
{
|
||||
/*
|
||||
Uncomment the preferences below if you want to use the module
|
||||
|
||||
@@ -52,6 +52,8 @@ class ExternalNotificationModule : public SinglePortModule, private concurrency:
|
||||
|
||||
virtual int32_t runOnce() override;
|
||||
|
||||
virtual bool wantPacket(const meshtastic_MeshPacket *p) override;
|
||||
|
||||
bool isNagging = false;
|
||||
|
||||
virtual AdminMessageHandleResult handleAdminMessageForModule(const meshtastic_MeshPacket &mp,
|
||||
@@ -59,4 +61,4 @@ class ExternalNotificationModule : public SinglePortModule, private concurrency:
|
||||
meshtastic_AdminMessage *response) override;
|
||||
};
|
||||
|
||||
extern ExternalNotificationModule *externalNotificationModule;
|
||||
extern ExternalNotificationModule *externalNotificationModule;
|
||||
@@ -4,8 +4,11 @@
|
||||
#include "input/TrackballInterruptImpl1.h"
|
||||
#include "input/UpDownInterruptImpl1.h"
|
||||
#include "input/cardKbI2cImpl.h"
|
||||
#include "input/kbMatrixImpl.h"
|
||||
#include "modules/AdminModule.h"
|
||||
#include "modules/CannedMessageModule.h"
|
||||
#include "modules/DetectionSensorModule.h"
|
||||
#include "modules/NeighborInfoModule.h"
|
||||
#include "modules/NodeInfoModule.h"
|
||||
#include "modules/PositionModule.h"
|
||||
#include "modules/RemoteHardwareModule.h"
|
||||
@@ -28,7 +31,7 @@
|
||||
#if defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040)
|
||||
#include "modules/ExternalNotificationModule.h"
|
||||
#include "modules/RangeTestModule.h"
|
||||
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52)) && !defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040)) && !defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
#include "modules/SerialModule.h"
|
||||
#endif
|
||||
#endif
|
||||
@@ -47,6 +50,8 @@ void setupModules()
|
||||
waypointModule = new WaypointModule();
|
||||
textMessageModule = new TextMessageModule();
|
||||
traceRouteModule = new TraceRouteModule();
|
||||
neighborInfoModule = new NeighborInfoModule();
|
||||
detectionSensorModule = new DetectionSensorModule();
|
||||
|
||||
// Note: if the rest of meshtastic doesn't need to explicitly use your module, you do not need to assign the instance
|
||||
// to a global variable.
|
||||
@@ -55,12 +60,22 @@ void setupModules()
|
||||
new ReplyModule();
|
||||
#if HAS_BUTTON
|
||||
rotaryEncoderInterruptImpl1 = new RotaryEncoderInterruptImpl1();
|
||||
rotaryEncoderInterruptImpl1->init();
|
||||
if (!rotaryEncoderInterruptImpl1->init()) {
|
||||
delete rotaryEncoderInterruptImpl1;
|
||||
rotaryEncoderInterruptImpl1 = nullptr;
|
||||
}
|
||||
upDownInterruptImpl1 = new UpDownInterruptImpl1();
|
||||
upDownInterruptImpl1->init();
|
||||
if (!upDownInterruptImpl1->init()) {
|
||||
delete upDownInterruptImpl1;
|
||||
upDownInterruptImpl1 = nullptr;
|
||||
}
|
||||
cardKbI2cImpl = new CardKbI2cImpl();
|
||||
cardKbI2cImpl->init();
|
||||
#endif
|
||||
#ifdef INPUTBROKER_MATRIX_TYPE
|
||||
kbMatrixImpl = new KbMatrixImpl();
|
||||
kbMatrixImpl->init();
|
||||
#endif // INPUTBROKER_MATRIX_TYPE
|
||||
#endif // HAS_BUTTON
|
||||
#if HAS_TRACKBALL
|
||||
trackballInterruptImpl1 = new TrackballInterruptImpl1();
|
||||
trackballInterruptImpl1->init();
|
||||
@@ -77,7 +92,8 @@ void setupModules()
|
||||
new AirQualityTelemetryModule();
|
||||
}
|
||||
#endif
|
||||
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52)) && !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040)) && !defined(CONFIG_IDF_TARGET_ESP32S2) && \
|
||||
!defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
new SerialModule();
|
||||
#endif
|
||||
#ifdef ARCH_ESP32
|
||||
@@ -92,6 +108,9 @@ void setupModules()
|
||||
#endif
|
||||
} else {
|
||||
adminModule = new AdminModule();
|
||||
#if HAS_TELEMETRY
|
||||
new DeviceTelemetryModule();
|
||||
#endif
|
||||
traceRouteModule = new TraceRouteModule();
|
||||
}
|
||||
// NOTE! This module must be added LAST because it likes to check for replies from other modules and avoid sending extra
|
||||
|
||||
311
src/modules/NeighborInfoModule.cpp
Normal file
311
src/modules/NeighborInfoModule.cpp
Normal file
@@ -0,0 +1,311 @@
|
||||
#include "NeighborInfoModule.h"
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
#include "RTC.h"
|
||||
|
||||
#define MAX_NUM_NEIGHBORS 10 // also defined in NeighborInfo protobuf options
|
||||
NeighborInfoModule *neighborInfoModule;
|
||||
|
||||
static const char *neighborInfoConfigFile = "/prefs/neighbors.proto";
|
||||
|
||||
/*
|
||||
Prints a single neighbor info packet and associated neighbors
|
||||
Uses LOG_DEBUG, which equates to Console.log
|
||||
NOTE: For debugging only
|
||||
*/
|
||||
void NeighborInfoModule::printNeighborInfo(const char *header, const meshtastic_NeighborInfo *np)
|
||||
{
|
||||
LOG_DEBUG("%s NEIGHBORINFO PACKET from Node 0x%x to Node 0x%x (last sent by 0x%x)\n", header, np->node_id,
|
||||
nodeDB.getNodeNum(), np->last_sent_by_id);
|
||||
LOG_DEBUG("----------------\n");
|
||||
LOG_DEBUG("Packet contains %d neighbors\n", np->neighbors_count);
|
||||
for (int i = 0; i < np->neighbors_count; i++) {
|
||||
LOG_DEBUG("Neighbor %d: node_id=0x%x, snr=%.2f\n", i, np->neighbors[i].node_id, np->neighbors[i].snr);
|
||||
}
|
||||
LOG_DEBUG("----------------\n");
|
||||
}
|
||||
/*
|
||||
Prints the nodeDB nodes so we can see whose nodeInfo we have
|
||||
NOTE: for debugging only
|
||||
*/
|
||||
void NeighborInfoModule::printNodeDBNodes(const char *header)
|
||||
{
|
||||
int num_nodes = nodeDB.getNumMeshNodes();
|
||||
LOG_DEBUG("%s NODEDB SELECTION from Node 0x%x:\n", header, nodeDB.getNodeNum());
|
||||
LOG_DEBUG("----------------\n");
|
||||
LOG_DEBUG("DB contains %d nodes\n", num_nodes);
|
||||
for (int i = 0; i < num_nodes; i++) {
|
||||
const meshtastic_NodeInfoLite *dbEntry = nodeDB.getMeshNodeByIndex(i);
|
||||
LOG_DEBUG(" Node %d: node_id=0x%x, snr=%.2f\n", i, dbEntry->num, dbEntry->snr);
|
||||
}
|
||||
LOG_DEBUG("----------------\n");
|
||||
}
|
||||
|
||||
/*
|
||||
Prints the nodeDB neighbors
|
||||
NOTE: for debugging only
|
||||
*/
|
||||
void NeighborInfoModule::printNodeDBNeighbors(const char *header)
|
||||
{
|
||||
int num_neighbors = getNumNeighbors();
|
||||
LOG_DEBUG("%s NODEDB SELECTION from Node 0x%x:\n", header, nodeDB.getNodeNum());
|
||||
LOG_DEBUG("----------------\n");
|
||||
LOG_DEBUG("DB contains %d neighbors\n", num_neighbors);
|
||||
for (int i = 0; i < num_neighbors; i++) {
|
||||
const meshtastic_Neighbor *dbEntry = getNeighborByIndex(i);
|
||||
LOG_DEBUG(" Node %d: node_id=0x%x, snr=%.2f\n", i, dbEntry->node_id, dbEntry->snr);
|
||||
}
|
||||
LOG_DEBUG("----------------\n");
|
||||
}
|
||||
|
||||
/*
|
||||
Prints the nodeDB with selectors for the neighbors we've chosen to send (inefficiently)
|
||||
Uses LOG_DEBUG, which equates to Console.log
|
||||
NOTE: For debugging only
|
||||
*/
|
||||
void NeighborInfoModule::printNodeDBSelection(const char *header, const meshtastic_NeighborInfo *np)
|
||||
{
|
||||
int num_neighbors = getNumNeighbors();
|
||||
LOG_DEBUG("%s NODEDB SELECTION from Node 0x%x:\n", header, nodeDB.getNodeNum());
|
||||
LOG_DEBUG("----------------\n");
|
||||
LOG_DEBUG("Selected %d neighbors of %d DB neighbors\n", np->neighbors_count, num_neighbors);
|
||||
for (int i = 0; i < num_neighbors; i++) {
|
||||
meshtastic_Neighbor *dbEntry = getNeighborByIndex(i);
|
||||
bool chosen = false;
|
||||
for (int j = 0; j < np->neighbors_count; j++) {
|
||||
if (np->neighbors[j].node_id == dbEntry->node_id) {
|
||||
chosen = true;
|
||||
}
|
||||
}
|
||||
if (!chosen) {
|
||||
LOG_DEBUG(" Node %d: neighbor=0x%x, snr=%.2f\n", i, dbEntry->node_id, dbEntry->snr);
|
||||
} else {
|
||||
LOG_DEBUG("---> Node %d: neighbor=0x%x, snr=%.2f\n", i, dbEntry->node_id, dbEntry->snr);
|
||||
}
|
||||
}
|
||||
LOG_DEBUG("----------------\n");
|
||||
}
|
||||
|
||||
/* Send our initial owner announcement 35 seconds after we start (to give network time to setup) */
|
||||
NeighborInfoModule::NeighborInfoModule()
|
||||
: ProtobufModule("neighborinfo", meshtastic_PortNum_NEIGHBORINFO_APP, &meshtastic_NeighborInfo_msg),
|
||||
concurrency::OSThread("NeighborInfoModule"), neighbors(neighborState.neighbors),
|
||||
numNeighbors(&neighborState.neighbors_count)
|
||||
{
|
||||
ourPortNum = meshtastic_PortNum_NEIGHBORINFO_APP;
|
||||
|
||||
if (moduleConfig.neighbor_info.enabled) {
|
||||
this->loadProtoForModule();
|
||||
setIntervalFromNow(35 * 1000);
|
||||
} else {
|
||||
LOG_DEBUG("NeighborInfoModule is disabled\n");
|
||||
disable();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Collect neighbor info from the nodeDB's history, capping at a maximum number of entries and max time
|
||||
Assumes that the neighborInfo packet has been allocated
|
||||
@returns the number of entries collected
|
||||
*/
|
||||
uint32_t NeighborInfoModule::collectNeighborInfo(meshtastic_NeighborInfo *neighborInfo)
|
||||
{
|
||||
uint my_node_id = nodeDB.getNodeNum();
|
||||
neighborInfo->node_id = my_node_id;
|
||||
neighborInfo->last_sent_by_id = my_node_id;
|
||||
neighborInfo->node_broadcast_interval_secs = moduleConfig.neighbor_info.update_interval;
|
||||
|
||||
int num_neighbors = cleanUpNeighbors();
|
||||
|
||||
for (int i = 0; i < num_neighbors; i++) {
|
||||
meshtastic_Neighbor *dbEntry = getNeighborByIndex(i);
|
||||
if ((neighborInfo->neighbors_count < MAX_NUM_NEIGHBORS) && (dbEntry->node_id != my_node_id)) {
|
||||
neighborInfo->neighbors[neighborInfo->neighbors_count].node_id = dbEntry->node_id;
|
||||
neighborInfo->neighbors[neighborInfo->neighbors_count].snr = dbEntry->snr;
|
||||
// Note: we don't set the last_rx_time and node_broadcast_intervals_secs here, because we don't want to send this over
|
||||
// the mesh
|
||||
neighborInfo->neighbors_count++;
|
||||
}
|
||||
}
|
||||
printNodeDBNodes("DBSTATE");
|
||||
printNodeDBNeighbors("NEIGHBORS");
|
||||
printNodeDBSelection("COLLECTED", neighborInfo);
|
||||
return neighborInfo->neighbors_count;
|
||||
}
|
||||
|
||||
/*
|
||||
Remove neighbors from the database that we haven't heard from in a while
|
||||
@returns new number of neighbors
|
||||
*/
|
||||
size_t NeighborInfoModule::cleanUpNeighbors()
|
||||
{
|
||||
uint32_t now = getTime();
|
||||
int num_neighbors = getNumNeighbors();
|
||||
NodeNum my_node_id = nodeDB.getNodeNum();
|
||||
|
||||
// Find neighbors to remove
|
||||
std::vector<int> indices_to_remove;
|
||||
for (int i = 0; i < num_neighbors; i++) {
|
||||
meshtastic_Neighbor *dbEntry = getNeighborByIndex(i);
|
||||
// We will remove a neighbor if we haven't heard from them in twice the broadcast interval
|
||||
if ((now - dbEntry->last_rx_time > dbEntry->node_broadcast_interval_secs * 2) && (dbEntry->node_id != my_node_id)) {
|
||||
indices_to_remove.push_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
// Update the neighbor list
|
||||
for (uint i = 0; i < indices_to_remove.size(); i++) {
|
||||
int index = indices_to_remove[i];
|
||||
LOG_DEBUG("Removing neighbor with node ID 0x%x\n", neighbors[index].node_id);
|
||||
for (int j = index; j < num_neighbors - 1; j++) {
|
||||
neighbors[j] = neighbors[j + 1];
|
||||
}
|
||||
(*numNeighbors)--;
|
||||
}
|
||||
|
||||
// Save the neighbor list if we removed any neighbors
|
||||
if (indices_to_remove.size() > 0) {
|
||||
saveProtoForModule();
|
||||
}
|
||||
|
||||
return *numNeighbors;
|
||||
}
|
||||
|
||||
/* Send neighbor info to the mesh */
|
||||
void NeighborInfoModule::sendNeighborInfo(NodeNum dest, bool wantReplies)
|
||||
{
|
||||
meshtastic_NeighborInfo neighborInfo = meshtastic_NeighborInfo_init_zero;
|
||||
collectNeighborInfo(&neighborInfo);
|
||||
meshtastic_MeshPacket *p = allocDataProtobuf(neighborInfo);
|
||||
// send regardless of whether or not we have neighbors in our DB,
|
||||
// because we want to get neighbors for the next cycle
|
||||
p->to = dest;
|
||||
p->decoded.want_response = wantReplies;
|
||||
printNeighborInfo("SENDING", &neighborInfo);
|
||||
service.sendToMesh(p, RX_SRC_LOCAL, true);
|
||||
}
|
||||
|
||||
/*
|
||||
Encompasses the full construction and sending packet to mesh
|
||||
Will be used for broadcast.
|
||||
*/
|
||||
int32_t NeighborInfoModule::runOnce()
|
||||
{
|
||||
bool requestReplies = false;
|
||||
sendNeighborInfo(NODENUM_BROADCAST, requestReplies);
|
||||
return getConfiguredOrDefaultMs(moduleConfig.neighbor_info.update_interval, default_broadcast_interval_secs);
|
||||
}
|
||||
|
||||
/*
|
||||
Collect a recieved neighbor info packet from another node
|
||||
Pass it to an upper client; do not persist this data on the mesh
|
||||
*/
|
||||
bool NeighborInfoModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_NeighborInfo *np)
|
||||
{
|
||||
if (enabled) {
|
||||
printNeighborInfo("RECEIVED", np);
|
||||
updateNeighbors(mp, np);
|
||||
}
|
||||
// Allow others to handle this packet
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
Copy the content of a current NeighborInfo packet into a new one and update the last_sent_by_id to our NodeNum
|
||||
*/
|
||||
void NeighborInfoModule::updateLastSentById(meshtastic_MeshPacket *p)
|
||||
{
|
||||
auto &incoming = p->decoded;
|
||||
meshtastic_NeighborInfo scratch;
|
||||
meshtastic_NeighborInfo *updated = NULL;
|
||||
memset(&scratch, 0, sizeof(scratch));
|
||||
pb_decode_from_bytes(incoming.payload.bytes, incoming.payload.size, &meshtastic_NeighborInfo_msg, &scratch);
|
||||
updated = &scratch;
|
||||
|
||||
updated->last_sent_by_id = nodeDB.getNodeNum();
|
||||
|
||||
// Set updated last_sent_by_id to the payload of the to be flooded packet
|
||||
p->decoded.payload.size =
|
||||
pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), &meshtastic_NeighborInfo_msg, updated);
|
||||
}
|
||||
|
||||
void NeighborInfoModule::resetNeighbors()
|
||||
{
|
||||
*numNeighbors = 0;
|
||||
neighborState.neighbors_count = 0;
|
||||
memset(neighborState.neighbors, 0, sizeof(neighborState.neighbors));
|
||||
saveProtoForModule();
|
||||
}
|
||||
|
||||
void NeighborInfoModule::updateNeighbors(const meshtastic_MeshPacket &mp, const meshtastic_NeighborInfo *np)
|
||||
{
|
||||
// The last sent ID will be 0 if the packet is from the phone, which we don't count as
|
||||
// an edge. So we assume that if it's zero, then this packet is from our node.
|
||||
if (mp.which_payload_variant == meshtastic_MeshPacket_decoded_tag && mp.from) {
|
||||
getOrCreateNeighbor(mp.from, np->last_sent_by_id, np->node_broadcast_interval_secs, mp.rx_snr);
|
||||
}
|
||||
}
|
||||
|
||||
meshtastic_Neighbor *NeighborInfoModule::getOrCreateNeighbor(NodeNum originalSender, NodeNum n,
|
||||
uint32_t node_broadcast_interval_secs, float snr)
|
||||
{
|
||||
// our node and the phone are the same node (not neighbors)
|
||||
if (n == 0) {
|
||||
n = nodeDB.getNodeNum();
|
||||
}
|
||||
// look for one in the existing list
|
||||
for (int i = 0; i < (*numNeighbors); i++) {
|
||||
meshtastic_Neighbor *nbr = &neighbors[i];
|
||||
if (nbr->node_id == n) {
|
||||
// if found, update it
|
||||
nbr->snr = snr;
|
||||
nbr->last_rx_time = getTime();
|
||||
// Only if this is the original sender, the broadcast interval corresponds to it
|
||||
if (originalSender == n)
|
||||
nbr->node_broadcast_interval_secs = node_broadcast_interval_secs;
|
||||
saveProtoForModule(); // Save the updated neighbor
|
||||
return nbr;
|
||||
}
|
||||
}
|
||||
// otherwise, allocate one and assign data to it
|
||||
// TODO: max memory for the database should take neighbors into account, but currently doesn't
|
||||
if (*numNeighbors < MAX_NUM_NEIGHBORS) {
|
||||
(*numNeighbors)++;
|
||||
}
|
||||
meshtastic_Neighbor *new_nbr = &neighbors[((*numNeighbors) - 1)];
|
||||
new_nbr->node_id = n;
|
||||
new_nbr->snr = snr;
|
||||
new_nbr->last_rx_time = getTime();
|
||||
// Only if this is the original sender, the broadcast interval corresponds to it
|
||||
if (originalSender == n)
|
||||
new_nbr->node_broadcast_interval_secs = node_broadcast_interval_secs;
|
||||
saveProtoForModule(); // Save the new neighbor
|
||||
return new_nbr;
|
||||
}
|
||||
|
||||
void NeighborInfoModule::loadProtoForModule()
|
||||
{
|
||||
if (!nodeDB.loadProto(neighborInfoConfigFile, meshtastic_NeighborInfo_size, sizeof(meshtastic_NeighborInfo),
|
||||
&meshtastic_NeighborInfo_msg, &neighborState)) {
|
||||
neighborState = meshtastic_NeighborInfo_init_zero;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Save the module config to file.
|
||||
*
|
||||
* @return true On success.
|
||||
* @return false On error.
|
||||
*/
|
||||
bool NeighborInfoModule::saveProtoForModule()
|
||||
{
|
||||
bool okay = true;
|
||||
|
||||
#ifdef FS
|
||||
FS.mkdir("/prefs");
|
||||
#endif
|
||||
|
||||
okay &= nodeDB.saveProto(neighborInfoConfigFile, meshtastic_NeighborInfo_size, &meshtastic_NeighborInfo_msg, &neighborState);
|
||||
|
||||
return okay;
|
||||
}
|
||||
84
src/modules/NeighborInfoModule.h
Normal file
84
src/modules/NeighborInfoModule.h
Normal file
@@ -0,0 +1,84 @@
|
||||
#pragma once
|
||||
#include "ProtobufModule.h"
|
||||
|
||||
/*
|
||||
* Neighborinfo module for sending info on each node's 0-hop neighbors to the mesh
|
||||
*/
|
||||
class NeighborInfoModule : public ProtobufModule<meshtastic_NeighborInfo>, private concurrency::OSThread
|
||||
{
|
||||
meshtastic_Neighbor *neighbors;
|
||||
pb_size_t *numNeighbors;
|
||||
|
||||
public:
|
||||
/*
|
||||
* Expose the constructor
|
||||
*/
|
||||
NeighborInfoModule();
|
||||
|
||||
/* Reset neighbor info after clearing nodeDB*/
|
||||
void resetNeighbors();
|
||||
|
||||
bool saveProtoForModule();
|
||||
|
||||
// Let FloodingRouter call updateLastSentById upon rebroadcasting a NeighborInfo packet
|
||||
friend class FloodingRouter;
|
||||
|
||||
protected:
|
||||
// Note: this holds our local info.
|
||||
meshtastic_NeighborInfo neighborState;
|
||||
|
||||
/*
|
||||
* Called to handle a particular incoming message
|
||||
* @return true if you've guaranteed you've handled this message and no other handlers should be considered for it
|
||||
*/
|
||||
virtual bool handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_NeighborInfo *nb) override;
|
||||
|
||||
/*
|
||||
* Collect neighbor info from the nodeDB's history, capping at a maximum number of entries and max time
|
||||
* @return the number of entries collected
|
||||
*/
|
||||
uint32_t collectNeighborInfo(meshtastic_NeighborInfo *neighborInfo);
|
||||
|
||||
/*
|
||||
Remove neighbors from the database that we haven't heard from in a while
|
||||
@returns new number of neighbors
|
||||
*/
|
||||
size_t cleanUpNeighbors();
|
||||
|
||||
/* Allocate a new NeighborInfo packet */
|
||||
meshtastic_NeighborInfo *allocateNeighborInfoPacket();
|
||||
|
||||
// Find a neighbor in our DB, create an empty neighbor if missing
|
||||
meshtastic_Neighbor *getOrCreateNeighbor(NodeNum originalSender, NodeNum n, uint32_t node_broadcast_interval_secs, float snr);
|
||||
|
||||
/*
|
||||
* Send info on our node's neighbors into the mesh
|
||||
*/
|
||||
void sendNeighborInfo(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false);
|
||||
|
||||
size_t getNumNeighbors() { return *numNeighbors; }
|
||||
|
||||
meshtastic_Neighbor *getNeighborByIndex(size_t x)
|
||||
{
|
||||
assert(x < *numNeighbors);
|
||||
return &neighbors[x];
|
||||
}
|
||||
|
||||
/* update neighbors with subpacket sniffed from network */
|
||||
void updateNeighbors(const meshtastic_MeshPacket &mp, const meshtastic_NeighborInfo *np);
|
||||
|
||||
/* update a NeighborInfo packet with our NodeNum as last_sent_by_id */
|
||||
void updateLastSentById(meshtastic_MeshPacket *p);
|
||||
|
||||
void loadProtoForModule();
|
||||
|
||||
/* Does our periodic broadcast */
|
||||
int32_t runOnce() override;
|
||||
|
||||
/* These are for debugging only */
|
||||
void printNeighborInfo(const char *header, const meshtastic_NeighborInfo *np);
|
||||
void printNodeDBNodes(const char *header);
|
||||
void printNodeDBNeighbors(const char *header);
|
||||
void printNodeDBSelection(const char *header, const meshtastic_NeighborInfo *np);
|
||||
};
|
||||
extern NeighborInfoModule *neighborInfoModule;
|
||||
@@ -11,8 +11,8 @@
|
||||
PositionModule *positionModule;
|
||||
|
||||
PositionModule::PositionModule()
|
||||
: ProtobufModule("position", meshtastic_PortNum_POSITION_APP, &meshtastic_Position_msg), concurrency::OSThread(
|
||||
"PositionModule")
|
||||
: ProtobufModule("position", meshtastic_PortNum_POSITION_APP, &meshtastic_Position_msg),
|
||||
concurrency::OSThread("PositionModule")
|
||||
{
|
||||
isPromiscuous = true; // We always want to update our nodedb, even if we are sniffing on others
|
||||
setIntervalFromNow(60 * 1000); // Send our initial position 60 seconds after we start (to give GPS time to setup)
|
||||
@@ -65,7 +65,7 @@ bool PositionModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes
|
||||
meshtastic_MeshPacket *PositionModule::allocReply()
|
||||
{
|
||||
if (ignoreRequest) {
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
meshtastic_NodeInfoLite *node = service.refreshLocalMeshNode(); // should guarantee there is now a position
|
||||
@@ -142,6 +142,11 @@ void PositionModule::sendOurPosition(NodeNum dest, bool wantReplies, uint8_t cha
|
||||
service.cancelSending(prevPacketId);
|
||||
|
||||
meshtastic_MeshPacket *p = allocReply();
|
||||
if (p == nullptr) {
|
||||
LOG_WARN("allocReply returned a nullptr");
|
||||
return;
|
||||
}
|
||||
|
||||
p->to = dest;
|
||||
p->decoded.want_response = wantReplies;
|
||||
if (config.device.role == meshtastic_Config_DeviceConfig_Role_TRACKER)
|
||||
@@ -185,7 +190,7 @@ int32_t PositionModule::runOnce()
|
||||
} else if (config.position.position_broadcast_smart_enabled) {
|
||||
// Only send packets if the channel is less than 25% utilized or we're a tracker.
|
||||
if (airTime->isTxAllowedChannelUtil(config.device.role != meshtastic_Config_DeviceConfig_Role_TRACKER)) {
|
||||
meshtastic_NodeInfoLite *node2 = service.refreshLocalMeshNode(); // should guarantee there is now a position
|
||||
const meshtastic_NodeInfoLite *node2 = service.refreshLocalMeshNode(); // should guarantee there is now a position
|
||||
|
||||
if (hasValidPosition(node2)) {
|
||||
// The minimum distance to travel before we are able to send a new position packet.
|
||||
@@ -225,4 +230,41 @@ int32_t PositionModule::runOnce()
|
||||
}
|
||||
|
||||
return 5000; // to save power only wake for our callback occasionally
|
||||
}
|
||||
|
||||
void PositionModule::handleNewPosition()
|
||||
{
|
||||
meshtastic_NodeInfoLite *node = nodeDB.getMeshNode(nodeDB.getNodeNum());
|
||||
const meshtastic_NodeInfoLite *node2 = service.refreshLocalMeshNode(); // should guarantee there is now a position
|
||||
// We limit our GPS broadcasts to a max rate
|
||||
uint32_t now = millis();
|
||||
uint32_t msSinceLastSend = now - lastGpsSend;
|
||||
|
||||
if (hasValidPosition(node2)) {
|
||||
// The minimum distance to travel before we are able to send a new position packet.
|
||||
const uint32_t distanceTravelThreshold =
|
||||
config.position.broadcast_smart_minimum_distance > 0 ? config.position.broadcast_smart_minimum_distance : 100;
|
||||
|
||||
// Determine the distance in meters between two points on the globe
|
||||
float distanceTraveledSinceLastSend = GeoCoord::latLongToMeter(
|
||||
lastGpsLatitude * 1e-7, lastGpsLongitude * 1e-7, node->position.latitude_i * 1e-7, node->position.longitude_i * 1e-7);
|
||||
|
||||
if ((abs(distanceTraveledSinceLastSend) >= distanceTravelThreshold)) {
|
||||
bool requestReplies = currentGeneration != radioGeneration;
|
||||
currentGeneration = radioGeneration;
|
||||
|
||||
LOG_INFO("Sending smart pos@%x:6 to mesh (distanceTraveled=%fm, minDistanceThreshold=%im, timeElapsed=%ims)\n",
|
||||
localPosition.timestamp, abs(distanceTraveledSinceLastSend), distanceTravelThreshold, msSinceLastSend);
|
||||
sendOurPosition(NODENUM_BROADCAST, requestReplies);
|
||||
|
||||
// Set the current coords as our last ones, after we've compared distance with current and decided to send
|
||||
lastGpsLatitude = node->position.latitude_i;
|
||||
lastGpsLongitude = node->position.longitude_i;
|
||||
|
||||
/* Update lastGpsSend to now. This means if the device is stationary, then
|
||||
getPref_position_broadcast_secs will still apply.
|
||||
*/
|
||||
lastGpsSend = now;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,8 @@ class PositionModule : public ProtobufModule<meshtastic_Position>, private concu
|
||||
*/
|
||||
void sendOurPosition(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false, uint8_t channel = 0);
|
||||
|
||||
void handleNewPosition();
|
||||
|
||||
protected:
|
||||
/** Called to handle a particular incoming message
|
||||
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
/**
|
||||
* @file RangeTestModule.cpp
|
||||
* @brief Implementation of the RangeTestModule class and RangeTestModuleRadio class.
|
||||
*
|
||||
* As a sender, this module sends packets every n seconds with an incremented PacketID.
|
||||
* As a receiver, this module receives packets from multiple senders and saves them to the Filesystem.
|
||||
*
|
||||
* The RangeTestModule class is an OSThread that runs the module.
|
||||
* The RangeTestModuleRadio class handles sending and receiving packets.
|
||||
*/
|
||||
#include "RangeTestModule.h"
|
||||
#include "FSCommon.h"
|
||||
#include "MeshService.h"
|
||||
@@ -10,11 +20,6 @@
|
||||
#include "gps/GeoCoord.h"
|
||||
#include <Arduino.h>
|
||||
|
||||
/*
|
||||
As a sender, I can send packets every n seconds. These packets include an incremented PacketID.
|
||||
As a receiver, I can receive packets from multiple senders. These packets can be saved to the Filesystem.
|
||||
*/
|
||||
|
||||
RangeTestModule *rangeTestModule;
|
||||
RangeTestModuleRadio *rangeTestModuleRadio;
|
||||
|
||||
@@ -97,6 +102,12 @@ int32_t RangeTestModule::runOnce()
|
||||
return disable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a payload to a specified destination node.
|
||||
*
|
||||
* @param dest The destination node number.
|
||||
* @param wantReplies Whether or not to request replies from the destination node.
|
||||
*/
|
||||
void RangeTestModuleRadio::sendPayload(NodeNum dest, bool wantReplies)
|
||||
{
|
||||
meshtastic_MeshPacket *p = allocDataPacket();
|
||||
|
||||
@@ -29,7 +29,7 @@ class RangeTestModuleRadio : public SinglePortModule
|
||||
uint32_t lastRxID = 0;
|
||||
|
||||
public:
|
||||
RangeTestModuleRadio() : SinglePortModule("RangeTestModuleRadio", meshtastic_PortNum_TEXT_MESSAGE_APP)
|
||||
RangeTestModuleRadio() : SinglePortModule("RangeTestModuleRadio", meshtastic_PortNum_RANGE_TEST_APP)
|
||||
{
|
||||
loopbackOk = true; // Allow locally generated messages to loop back to the client
|
||||
}
|
||||
|
||||
@@ -44,9 +44,10 @@
|
||||
|
||||
*/
|
||||
|
||||
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52)) && !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040)) && !defined(CONFIG_IDF_TARGET_ESP32S2) && \
|
||||
!defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
|
||||
#define RX_BUFFER 128
|
||||
#define RX_BUFFER 256
|
||||
#define TIMEOUT 250
|
||||
#define BAUD 38400
|
||||
#define ACK 1
|
||||
@@ -86,7 +87,13 @@ SerialModuleRadio::SerialModuleRadio() : MeshModule("SerialModuleRadio")
|
||||
}
|
||||
}
|
||||
|
||||
// For the serial2 port we can't really detect if any client is on the other side, so instead just look for recent messages
|
||||
/**
|
||||
* @brief Checks if the serial connection is established.
|
||||
*
|
||||
* @return true if the serial connection is established, false otherwise.
|
||||
*
|
||||
* For the serial2 port we can't really detect if any client is on the other side, so instead just look for recent messages
|
||||
*/
|
||||
bool SerialModule::checkIsConnected()
|
||||
{
|
||||
uint32_t now = millis();
|
||||
@@ -135,7 +142,12 @@ int32_t SerialModule::runOnce()
|
||||
}
|
||||
#elif !defined(TTGO_T_ECHO)
|
||||
if (moduleConfig.serial.rxd && moduleConfig.serial.txd) {
|
||||
#ifdef ARCH_RP2040
|
||||
Serial2.setFIFOSize(RX_BUFFER);
|
||||
Serial2.setPinout(moduleConfig.serial.txd, moduleConfig.serial.rxd);
|
||||
#else
|
||||
Serial2.setPins(moduleConfig.serial.rxd, moduleConfig.serial.txd);
|
||||
#endif
|
||||
Serial2.begin(baud, SERIAL_8N1);
|
||||
Serial2.setTimeout(moduleConfig.serial.timeout > 0 ? moduleConfig.serial.timeout : TIMEOUT);
|
||||
} else {
|
||||
@@ -176,7 +188,7 @@ int32_t SerialModule::runOnce()
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifndef TTGO_T_ECHO
|
||||
#if !defined(TTGO_T_ECHO)
|
||||
else {
|
||||
while (Serial2.available()) {
|
||||
serialPayloadSize = Serial2.readBytes(serialBytes, meshtastic_Constants_DATA_PAYLOAD_LEN);
|
||||
@@ -191,6 +203,11 @@ int32_t SerialModule::runOnce()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates a new mesh packet for use as a reply to a received packet.
|
||||
*
|
||||
* @return A pointer to the newly allocated mesh packet.
|
||||
*/
|
||||
meshtastic_MeshPacket *SerialModuleRadio::allocReply()
|
||||
{
|
||||
auto reply = allocDataPacket(); // Allocate a packet for sending
|
||||
@@ -198,9 +215,15 @@ meshtastic_MeshPacket *SerialModuleRadio::allocReply()
|
||||
return reply;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a payload to a specified destination node.
|
||||
*
|
||||
* @param dest The destination node number.
|
||||
* @param wantReplies Whether or not to request replies from the destination node.
|
||||
*/
|
||||
void SerialModuleRadio::sendPayload(NodeNum dest, bool wantReplies)
|
||||
{
|
||||
meshtastic_Channel *ch = (boundChannel != NULL) ? &channels.getByName(boundChannel) : NULL;
|
||||
const meshtastic_Channel *ch = (boundChannel != NULL) ? &channels.getByName(boundChannel) : NULL;
|
||||
meshtastic_MeshPacket *p = allocReply();
|
||||
p->to = dest;
|
||||
if (ch != NULL) {
|
||||
@@ -216,6 +239,12 @@ void SerialModuleRadio::sendPayload(NodeNum dest, bool wantReplies)
|
||||
service.sendToMesh(p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a received mesh packet.
|
||||
*
|
||||
* @param mp The received mesh packet.
|
||||
* @return The processed message.
|
||||
*/
|
||||
ProcessMessage SerialModuleRadio::handleReceived(const meshtastic_MeshPacket &mp)
|
||||
{
|
||||
if (moduleConfig.serial.enabled) {
|
||||
@@ -249,7 +278,7 @@ ProcessMessage SerialModuleRadio::handleReceived(const meshtastic_MeshPacket &mp
|
||||
|
||||
if (moduleConfig.serial.mode == meshtastic_ModuleConfig_SerialConfig_Serial_Mode_DEFAULT ||
|
||||
moduleConfig.serial.mode == meshtastic_ModuleConfig_SerialConfig_Serial_Mode_SIMPLE) {
|
||||
serialPrint->printf("%s", p.payload.bytes);
|
||||
serialPrint->write(p.payload.bytes, p.payload.size);
|
||||
} else if (moduleConfig.serial.mode == meshtastic_ModuleConfig_SerialConfig_Serial_Mode_TEXTMSG) {
|
||||
meshtastic_NodeInfoLite *node = nodeDB.getMeshNode(getFrom(&mp));
|
||||
String sender = (node && node->has_user) ? node->user.short_name : "???";
|
||||
@@ -277,6 +306,11 @@ ProcessMessage SerialModuleRadio::handleReceived(const meshtastic_MeshPacket &mp
|
||||
return ProcessMessage::CONTINUE; // Let others look at this message also if they want
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the baud rate of the serial module from the module configuration.
|
||||
*
|
||||
* @return uint32_t The baud rate of the serial module.
|
||||
*/
|
||||
uint32_t SerialModule::getBaudRate()
|
||||
{
|
||||
if (moduleConfig.serial.baud == meshtastic_ModuleConfig_SerialConfig_Serial_Baud_BAUD_110) {
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
#include <Arduino.h>
|
||||
#include <functional>
|
||||
|
||||
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52)) && !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040)) && !defined(CONFIG_IDF_TARGET_ESP32S2) && \
|
||||
!defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
|
||||
class SerialModule : public StreamAPI, private concurrency::OSThread
|
||||
{
|
||||
@@ -74,4 +75,4 @@ class SerialModuleRadio : public MeshModule
|
||||
|
||||
extern SerialModuleRadio *serialModuleRadio;
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -17,7 +17,8 @@ int32_t DeviceTelemetryModule::runOnce()
|
||||
uint32_t now = millis();
|
||||
if (((lastSentToMesh == 0) ||
|
||||
((now - lastSentToMesh) >= getConfiguredOrDefaultMs(moduleConfig.telemetry.device_update_interval))) &&
|
||||
airTime->isTxAllowedChannelUtil() && airTime->isTxAllowedAirUtil()) {
|
||||
airTime->isTxAllowedChannelUtil() && airTime->isTxAllowedAirUtil() &&
|
||||
config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER) {
|
||||
sendTelemetry();
|
||||
lastSentToMesh = now;
|
||||
} else if (service.isToPhoneQueueEmpty()) {
|
||||
@@ -30,6 +31,10 @@ int32_t DeviceTelemetryModule::runOnce()
|
||||
|
||||
bool DeviceTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Telemetry *t)
|
||||
{
|
||||
// Don't worry about storing telemetry in NodeDB if we're a repeater
|
||||
if (config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER)
|
||||
return false;
|
||||
|
||||
if (t->which_variant == meshtastic_Telemetry_device_metrics_tag) {
|
||||
#ifdef DEBUG_PORT
|
||||
const char *sender = getSenderShortName(mp);
|
||||
@@ -43,7 +48,19 @@ bool DeviceTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPacket &
|
||||
return false; // Let others look at this message also if they want
|
||||
}
|
||||
|
||||
bool DeviceTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
|
||||
meshtastic_MeshPacket *DeviceTelemetryModule::allocReply()
|
||||
{
|
||||
if (ignoreRequest) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LOG_INFO("Device telemetry replying to request\n");
|
||||
|
||||
meshtastic_Telemetry telemetry = getDeviceTelemetry();
|
||||
return allocDataProtobuf(telemetry);
|
||||
}
|
||||
|
||||
meshtastic_Telemetry DeviceTelemetryModule::getDeviceTelemetry()
|
||||
{
|
||||
meshtastic_Telemetry t;
|
||||
|
||||
@@ -60,16 +77,22 @@ bool DeviceTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
|
||||
t.variant.device_metrics.channel_utilization = airTime->channelUtilizationPercent();
|
||||
t.variant.device_metrics.voltage = powerStatus->getBatteryVoltageMv() / 1000.0;
|
||||
|
||||
LOG_INFO("(Sending): air_util_tx=%f, channel_utilization=%f, battery_level=%i, voltage=%f\n",
|
||||
t.variant.device_metrics.air_util_tx, t.variant.device_metrics.channel_utilization,
|
||||
t.variant.device_metrics.battery_level, t.variant.device_metrics.voltage);
|
||||
return t;
|
||||
}
|
||||
|
||||
meshtastic_MeshPacket *p = allocDataProtobuf(t);
|
||||
bool DeviceTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
|
||||
{
|
||||
meshtastic_Telemetry telemetry = getDeviceTelemetry();
|
||||
LOG_INFO("(Sending): air_util_tx=%f, channel_utilization=%f, battery_level=%i, voltage=%f\n",
|
||||
telemetry.variant.device_metrics.air_util_tx, telemetry.variant.device_metrics.channel_utilization,
|
||||
telemetry.variant.device_metrics.battery_level, telemetry.variant.device_metrics.voltage);
|
||||
|
||||
meshtastic_MeshPacket *p = allocDataProtobuf(telemetry);
|
||||
p->to = dest;
|
||||
p->decoded.want_response = false;
|
||||
p->priority = meshtastic_MeshPacket_Priority_MIN;
|
||||
|
||||
nodeDB.updateTelemetry(nodeDB.getNodeNum(), t, RX_SRC_LOCAL);
|
||||
nodeDB.updateTelemetry(nodeDB.getNodeNum(), telemetry, RX_SRC_LOCAL);
|
||||
if (phoneOnly) {
|
||||
LOG_INFO("Sending packet to phone\n");
|
||||
service.sendToPhone(p);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user