mirror of
https://github.com/meshtastic/firmware.git
synced 2025-12-14 06:42:34 +00:00
Compare commits
343 Commits
v2.0.6.97f
...
v2.0.13.7e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7e27729dae | ||
|
|
d49f19a67c | ||
|
|
c33569f833 | ||
|
|
7936c7c8ae | ||
|
|
2f3f19fda7 | ||
|
|
c89ca50cc4 | ||
|
|
867e55b9e7 | ||
|
|
28b1616630 | ||
|
|
42122f3d0f | ||
|
|
f905763161 | ||
|
|
bd2b766a36 | ||
|
|
bd51cbd721 | ||
|
|
e3fd17772d | ||
|
|
440b965e71 | ||
|
|
cf0fb13a12 | ||
|
|
c0166773e8 | ||
|
|
fc775012ea | ||
|
|
d7a71e46aa | ||
|
|
721f87af7e | ||
|
|
a354cebd88 | ||
|
|
97680ca730 | ||
|
|
17a2589b35 | ||
|
|
4f71ab07c9 | ||
|
|
1f6a8eae86 | ||
|
|
ab9d0ba543 | ||
|
|
e13fb9919e | ||
|
|
a3b93a4dcf | ||
|
|
6b0f18e1e4 | ||
|
|
312ef790fc | ||
|
|
713f7d5996 | ||
|
|
3985008e06 | ||
|
|
8f2155f8f9 | ||
|
|
1fc5d70221 | ||
|
|
e7d425ef6e | ||
|
|
9c1cfe9358 | ||
|
|
0181e186ac | ||
|
|
86748bf88e | ||
|
|
5fd00b2538 | ||
|
|
5cec370cf5 | ||
|
|
81ee6dd799 | ||
|
|
49172e416e | ||
|
|
57f185c26b | ||
|
|
3a8ffe7ac2 | ||
|
|
d8b85f9a09 | ||
|
|
4d7402839e | ||
|
|
8465467aa8 | ||
|
|
2a0b8093ea | ||
|
|
96fa5dafb8 | ||
|
|
be2d3f7769 | ||
|
|
b283e526bf | ||
|
|
03c5dfc7a8 | ||
|
|
52cfd62031 | ||
|
|
c98dc4cae0 | ||
|
|
f21212dd3e | ||
|
|
0e0ccad489 | ||
|
|
9f1c77da76 | ||
|
|
7c1c49b8ab | ||
|
|
f4099261df | ||
|
|
450e7362f6 | ||
|
|
0b9c8e62ea | ||
|
|
09efbb75b1 | ||
|
|
e5d9f1f946 | ||
|
|
2400dd43b3 | ||
|
|
988d5af69b | ||
|
|
78b6916b1b | ||
|
|
9740f0a505 | ||
|
|
b64a74c0c5 | ||
|
|
d9f0dc7ea4 | ||
|
|
30ae4c2a38 | ||
|
|
d077be1496 | ||
|
|
4f26a2a74a | ||
|
|
41f9636ba3 | ||
|
|
b544163c3f | ||
|
|
6d989a29dd | ||
|
|
8914d1a184 | ||
|
|
1cfc7b800b | ||
|
|
cab5fcf5ae | ||
|
|
cad5c9b70c | ||
|
|
5867038abf | ||
|
|
42b24d4510 | ||
|
|
d750109d00 | ||
|
|
7f0a8d329f | ||
|
|
64895cc7eb | ||
|
|
52903f83e3 | ||
|
|
e0002ef2d5 | ||
|
|
021fc8235c | ||
|
|
0305c7394f | ||
|
|
bca70d10d0 | ||
|
|
1077846e8d | ||
|
|
63c8ca9ca5 | ||
|
|
523b132100 | ||
|
|
2d62cbe345 | ||
|
|
b55fe549e3 | ||
|
|
9a04aaa811 | ||
|
|
092a753a6f | ||
|
|
8a9af37d82 | ||
|
|
74e6eb34bd | ||
|
|
11f1508d85 | ||
|
|
19436b7d54 | ||
|
|
69ff724f0f | ||
|
|
3d3aba584e | ||
|
|
ef1fb877ba | ||
|
|
f1cdfd163d | ||
|
|
8364c2b147 | ||
|
|
8193215294 | ||
|
|
e73ae7cdac | ||
|
|
65aad62702 | ||
|
|
3eefd46ca1 | ||
|
|
115cb05d3b | ||
|
|
44d5c69ba8 | ||
|
|
5ccd66864b | ||
|
|
0b5cae5393 | ||
|
|
be91b08b3e | ||
|
|
c7c5671cca | ||
|
|
979d12d607 | ||
|
|
110c80d045 | ||
|
|
38a1315599 | ||
|
|
8ebe0edc5a | ||
|
|
a8f93d5f47 | ||
|
|
96c272d3d1 | ||
|
|
45e6e86ff9 | ||
|
|
f73b8661de | ||
|
|
3c5710e65b | ||
|
|
4e4a74379e | ||
|
|
41a1dfec79 | ||
|
|
1a949b7ca6 | ||
|
|
840079c25b | ||
|
|
887405cc08 | ||
|
|
d633212f70 | ||
|
|
02def448bc | ||
|
|
7baf30dcb8 | ||
|
|
e09b12ca58 | ||
|
|
1736dada7d | ||
|
|
7f3a624ee3 | ||
|
|
475c87b0e4 | ||
|
|
541f4aa998 | ||
|
|
ab6c4e61a6 | ||
|
|
6ea0963f4b | ||
|
|
259d442d8f | ||
|
|
b134f0bb46 | ||
|
|
63cf01223c | ||
|
|
2505bdbc21 | ||
|
|
d9d8c7eb74 | ||
|
|
3b19040590 | ||
|
|
14be4ee9f0 | ||
|
|
94cb100e3f | ||
|
|
f632933b93 | ||
|
|
e25d05689b | ||
|
|
5c859da4e4 | ||
|
|
6c5602e88d | ||
|
|
b4735f4224 | ||
|
|
3b9b33a5ee | ||
|
|
430908f5d6 | ||
|
|
6f6ca64cfd | ||
|
|
d0243d2cd0 | ||
|
|
796e58161d | ||
|
|
e56f17c658 | ||
|
|
b808ffa9ab | ||
|
|
506bae4a8b | ||
|
|
f6ee6265e6 | ||
|
|
7539d92857 | ||
|
|
21fff392b4 | ||
|
|
580ec590fa | ||
|
|
5c9996dfa1 | ||
|
|
34f9324766 | ||
|
|
3f988c8b69 | ||
|
|
2ac2b6d1b6 | ||
|
|
b8657158be | ||
|
|
70f5f8301b | ||
|
|
adb8d773d4 | ||
|
|
a289406863 | ||
|
|
1a3f2a8ab5 | ||
|
|
23d6b815f5 | ||
|
|
e1feb5eb30 | ||
|
|
cb8247559d | ||
|
|
28b954017f | ||
|
|
16d826d6c7 | ||
|
|
2f7c18303d | ||
|
|
b9df41c55f | ||
|
|
4801260440 | ||
|
|
606262e55d | ||
|
|
0064d18e64 | ||
|
|
6f5a6d5cb4 | ||
|
|
e0194528dd | ||
|
|
30240ac14b | ||
|
|
090e1660fe | ||
|
|
92c9b34d4f | ||
|
|
fb41b0f5c8 | ||
|
|
3f50371ff3 | ||
|
|
812b321154 | ||
|
|
815f9bfc5f | ||
|
|
86ff23d13c | ||
|
|
201b786f77 | ||
|
|
8074955841 | ||
|
|
0992093f4d | ||
|
|
6978e57991 | ||
|
|
755c0b7008 | ||
|
|
7396d0f241 | ||
|
|
220859d0aa | ||
|
|
941786669b | ||
|
|
4eb620d47b | ||
|
|
9794995d7a | ||
|
|
055146602a | ||
|
|
86d7860d86 | ||
|
|
0f2d0d1f07 | ||
|
|
ab6a5a5e07 | ||
|
|
44a33ed463 | ||
|
|
fab08b6451 | ||
|
|
d9cd3dd3e1 | ||
|
|
c75ea87f6b | ||
|
|
706ddf6e95 | ||
|
|
aec091e7aa | ||
|
|
cea8393a7f | ||
|
|
8f94463eac | ||
|
|
a0f5e44967 | ||
|
|
feb7181767 | ||
|
|
a0c1e9cdc6 | ||
|
|
7d1b6f63b5 | ||
|
|
ab6b6514cb | ||
|
|
0e6285edf2 | ||
|
|
8b58eaac20 | ||
|
|
8cbf292373 | ||
|
|
80d0b63c3a | ||
|
|
f5120a29ec | ||
|
|
efc3f4c0ee | ||
|
|
bd2bfd6822 | ||
|
|
e40625d2ad | ||
|
|
eae347ddac | ||
|
|
ae2ca1d89c | ||
|
|
34c73da886 | ||
|
|
88c3ab2636 | ||
|
|
6a5dd26907 | ||
|
|
4de557b4db | ||
|
|
d9eb9758e2 | ||
|
|
d566457f0c | ||
|
|
79ff0659c0 | ||
|
|
af9d4328eb | ||
|
|
8c66940b78 | ||
|
|
c577e09183 | ||
|
|
4a6f269b4b | ||
|
|
bbaeeb7ce9 | ||
|
|
54686905dc | ||
|
|
3cde75f97b | ||
|
|
6c84b3f01c | ||
|
|
68f6cfde0c | ||
|
|
1c8181dc75 | ||
|
|
270746e303 | ||
|
|
72f1416b30 | ||
|
|
a788f16e91 | ||
|
|
f2229e6977 | ||
|
|
05f81922e6 | ||
|
|
06be74ae7c | ||
|
|
72504a5e8b | ||
|
|
e8c034e988 | ||
|
|
aa19718ba4 | ||
|
|
088ab106dd | ||
|
|
110c3f619a | ||
|
|
d1cc503ca8 | ||
|
|
eae7f8a786 | ||
|
|
bb24b86018 | ||
|
|
d3b3a4c148 | ||
|
|
46f1cee2a8 | ||
|
|
0386af721d | ||
|
|
de6b752db8 | ||
|
|
92fd5511ec | ||
|
|
8507125e98 | ||
|
|
59ec7f31ab | ||
|
|
627b21f3f2 | ||
|
|
64cc6e0b91 | ||
|
|
779d2352bd | ||
|
|
0162db12b8 | ||
|
|
91ff7b9032 | ||
|
|
643f99f577 | ||
|
|
152288b4cc | ||
|
|
45b518baf2 | ||
|
|
24cc479f95 | ||
|
|
5fbc630061 | ||
|
|
0c65c73f90 | ||
|
|
95eca75336 | ||
|
|
0f0dbc3274 | ||
|
|
edb674759f | ||
|
|
e3d8c5c7a6 | ||
|
|
f3d6f26a28 | ||
|
|
1a0d51495d | ||
|
|
32d9a397aa | ||
|
|
60e6dc1134 | ||
|
|
06d34daeab | ||
|
|
a00187b97f | ||
|
|
ba1f68d758 | ||
|
|
d4c0977a70 | ||
|
|
1a19d71e95 | ||
|
|
21c10934fc | ||
|
|
13cca91097 | ||
|
|
b335b1c66b | ||
|
|
a42a9bf4fe | ||
|
|
cc2653bfb5 | ||
|
|
fc5bf5a68f | ||
|
|
0f7e6b8964 | ||
|
|
63d7338311 | ||
|
|
37f716d27b | ||
|
|
03bfdec1e1 | ||
|
|
0f2a835359 | ||
|
|
2a84d39e40 | ||
|
|
b14289e976 | ||
|
|
1fef6f0656 | ||
|
|
183ec2124f | ||
|
|
aeb9bfa063 | ||
|
|
b84c7ae49b | ||
|
|
61598c5942 | ||
|
|
a3a24e0216 | ||
|
|
31ec2da0e9 | ||
|
|
53da7cb036 | ||
|
|
911083c49d | ||
|
|
27a10b395f | ||
|
|
b1f3e117d1 | ||
|
|
7570cdbd22 | ||
|
|
28ff2efdef | ||
|
|
bb1a9192eb | ||
|
|
1787e2c775 | ||
|
|
470e711383 | ||
|
|
eb4f682ad1 | ||
|
|
4b63730efb | ||
|
|
c857474116 | ||
|
|
8ff5dacc3c | ||
|
|
fb89828990 | ||
|
|
c7529f9a3e | ||
|
|
dbefa71bc8 | ||
|
|
7907404028 | ||
|
|
72e17b558c | ||
|
|
628028475c | ||
|
|
05e992ad67 | ||
|
|
bba6bf387e | ||
|
|
4d32f7c5ad | ||
|
|
0dff05e881 | ||
|
|
f3c5a01daf | ||
|
|
7ca104cef6 | ||
|
|
fe95247d56 | ||
|
|
f1179d31ba | ||
|
|
c7681cb24d | ||
|
|
abe60b96f1 | ||
|
|
206520f179 | ||
|
|
330ac3be68 | ||
|
|
3b1e34efa1 |
7
.github/workflows/build_esp32.yml
vendored
7
.github/workflows/build_esp32.yml
vendored
@@ -29,6 +29,13 @@ jobs:
|
||||
tar -xf build.tar -C data/static
|
||||
rm build.tar
|
||||
|
||||
- name: Remove debug flags for release
|
||||
if: ${{ github.event_name == 'workflow_dispatch' }}
|
||||
run: |
|
||||
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32.ini
|
||||
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32s2.ini
|
||||
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32s3.ini
|
||||
|
||||
- name: Build ESP32
|
||||
run: bin/build-esp32.sh ${{ inputs.board }}
|
||||
|
||||
|
||||
3
.github/workflows/main_matrix.yml
vendored
3
.github/workflows/main_matrix.yml
vendored
@@ -32,6 +32,7 @@ jobs:
|
||||
- board: station-g1
|
||||
- board: m5stack-coreink
|
||||
- board: tbeam-s3-core
|
||||
- board: tlora-t3s3-v1
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
@@ -53,6 +54,7 @@ jobs:
|
||||
- board: tlora-v1
|
||||
- board: tlora_v1_3
|
||||
- board: tlora-v2-1-1.6
|
||||
- board: tlora-v2-1-1.8
|
||||
- board: tbeam
|
||||
- board: heltec-v1
|
||||
- board: heltec-v2.0
|
||||
@@ -67,6 +69,7 @@ jobs:
|
||||
- board: m5stack-core
|
||||
- board: m5stack-coreink
|
||||
- board: tbeam-s3-core
|
||||
- board: tlora-t3s3-v1
|
||||
uses: ./.github/workflows/build_esp32.yml
|
||||
with:
|
||||
board: ${{ matrix.board }}
|
||||
|
||||
6
.github/workflows/update_protobufs.yml
vendored
6
.github/workflows/update_protobufs.yml
vendored
@@ -17,9 +17,9 @@ jobs:
|
||||
|
||||
- name: Download nanopb
|
||||
run: |
|
||||
wget https://jpa.kapsi.fi/nanopb/download/nanopb-0.4.6-linux-x86.tar.gz
|
||||
tar xvzf nanopb-0.4.6-linux-x86.tar.gz
|
||||
mv nanopb-0.4.6-linux-x86 nanopb-0.4.6
|
||||
wget https://jpa.kapsi.fi/nanopb/download/nanopb-0.4.7-linux-x86.tar.gz
|
||||
tar xvzf nanopb-0.4.7-linux-x86.tar.gz
|
||||
mv nanopb-0.4.7-linux-x86 nanopb-0.4.7
|
||||
|
||||
- name: Re-generate protocol buffers
|
||||
run: |
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -29,3 +29,4 @@ __pycache__
|
||||
|
||||
venv/
|
||||
release/
|
||||
.vscode/extensions.json
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Meshtastic Firmware
|
||||
|
||||

|
||||
[](https://github.com/meshtastic/firmware/actions/workflows/main_matrix.yml)
|
||||
[](https://github.com/meshtastic/firmware/actions/workflows/ci.yml)
|
||||
[](https://cla-assistant.io/meshtastic/firmware)
|
||||
[](https://opencollective.com/meshtastic/)
|
||||
[](https://vercel.com?utm_source=meshtastic&utm_campaign=oss)
|
||||
|
||||
@@ -26,6 +26,7 @@ build_flags =
|
||||
-DCONFIG_NIMBLE_CPP_LOG_LEVEL=2
|
||||
-DCONFIG_BT_NIMBLE_MAX_CCCDS=20
|
||||
-DESP_OPENSSL_SUPPRESS_LEGACY_WARNING
|
||||
-DDEBUG_HEAP
|
||||
|
||||
lib_deps =
|
||||
${arduino_base.lib_deps}
|
||||
@@ -34,6 +35,7 @@ lib_deps =
|
||||
https://github.com/meshtastic/esp32_https_server.git#23665b3adc080a311dcbb586ed5941b5f94d6ea2
|
||||
h2zero/NimBLE-Arduino@^1.4.0
|
||||
https://github.com/lewisxhe/XPowersLib.git#84b7373faea3118b6c37954d52f98b8a337148d6
|
||||
caveman99/ESP32 Codec2@^1.0.1
|
||||
|
||||
lib_ignore =
|
||||
segger_rtt
|
||||
|
||||
47
arch/esp32/esp32s2.ini
Normal file
47
arch/esp32/esp32s2.ini
Normal file
@@ -0,0 +1,47 @@
|
||||
[esp32s2_base]
|
||||
extends = arduino_base
|
||||
platform = platformio/espressif32@^5.2.0
|
||||
build_src_filter =
|
||||
${arduino_base.build_src_filter} -<platform/nrf52/> -<platform/stm32wl> -<platform/rp2040> -<mesh/eth/> -<nimble/>
|
||||
upload_speed = 961200
|
||||
monitor_speed = 115200
|
||||
debug_init_break = tbreak setup
|
||||
monitor_filters = esp32_exception_decoder
|
||||
board_build.filesystem = littlefs
|
||||
|
||||
# Remove -DMYNEWT_VAL_BLE_HS_LOG_LVL=LOG_LEVEL_CRITICAL for low level BLE logging.
|
||||
# See library directory for BLE logging possible values: .pio/libdeps/tbeam/NimBLE-Arduino/src/log_common/log_common.h
|
||||
# This overrides the BLE logging default of LOG_LEVEL_INFO (1) from: .pio/libdeps/tbeam/NimBLE-Arduino/src/esp_nimble_cfg.h
|
||||
build_flags =
|
||||
${arduino_base.build_flags}
|
||||
-Wall
|
||||
-Wextra
|
||||
-Isrc/platform/esp32
|
||||
-std=c++11
|
||||
-DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG
|
||||
-DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG
|
||||
-DMYNEWT_VAL_BLE_HS_LOG_LVL=LOG_LEVEL_CRITICAL
|
||||
-DAXP_DEBUG_PORT=Serial
|
||||
-DCONFIG_BT_NIMBLE_ENABLED
|
||||
-DCONFIG_NIMBLE_CPP_LOG_LEVEL=2
|
||||
-DCONFIG_BT_NIMBLE_MAX_CCCDS=20
|
||||
-DESP_OPENSSL_SUPPRESS_LEGACY_WARNING
|
||||
-DHAS_BLUETOOTH=0
|
||||
-DDEBUG_HEAP
|
||||
|
||||
lib_deps =
|
||||
${arduino_base.lib_deps}
|
||||
${networking_base.lib_deps}
|
||||
${environmental_base.lib_deps}
|
||||
https://github.com/meshtastic/esp32_https_server.git#23665b3adc080a311dcbb586ed5941b5f94d6ea2
|
||||
https://github.com/lewisxhe/XPowersLib.git#84b7373faea3118b6c37954d52f98b8a337148d6
|
||||
caveman99/ESP32 Codec2@^1.0.1
|
||||
|
||||
lib_ignore =
|
||||
segger_rtt
|
||||
ESP32 BLE Arduino
|
||||
|
||||
; customize the partition table
|
||||
; http://docs.platformio.org/en/latest/platforms/espressif32.html#partition-tables
|
||||
board_build.partitions = partition-table.csv
|
||||
|
||||
@@ -26,6 +26,7 @@ build_flags =
|
||||
-DCONFIG_NIMBLE_CPP_LOG_LEVEL=2
|
||||
-DCONFIG_BT_NIMBLE_MAX_CCCDS=20
|
||||
-DESP_OPENSSL_SUPPRESS_LEGACY_WARNING
|
||||
-DDEBUG_HEAP
|
||||
|
||||
lib_deps =
|
||||
${arduino_base.lib_deps}
|
||||
@@ -34,6 +35,7 @@ lib_deps =
|
||||
https://github.com/meshtastic/esp32_https_server.git#23665b3adc080a311dcbb586ed5941b5f94d6ea2
|
||||
h2zero/NimBLE-Arduino@^1.4.0
|
||||
https://github.com/lewisxhe/XPowersLib.git#84b7373faea3118b6c37954d52f98b8a337148d6
|
||||
caveman99/ESP32 Codec2@^1.0.1
|
||||
|
||||
lib_ignore =
|
||||
segger_rtt
|
||||
|
||||
@@ -8,7 +8,7 @@ build_flags =
|
||||
${arduino_base.build_flags} -Wno-unused-variable
|
||||
-Isrc/platform/nrf52
|
||||
build_src_filter =
|
||||
${arduino_base.build_src_filter} -<platform/esp32/> -<platform/stm32wl> -<nimble/> -<mesh/wifi/> -<mesh/http/> -<modules/esp32> -<mqtt/> -<platform/rp2040> -<mesh/eth/>
|
||||
${arduino_base.build_src_filter} -<platform/esp32/> -<platform/stm32wl> -<nimble/> -<mesh/api/> -<mesh/http/> -<modules/esp32> -<mqtt/> -<platform/rp2040> -<mesh/eth/>
|
||||
lib_ignore =
|
||||
BluetoothOTA
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
; Common settings for rp2040 Processor based targets
|
||||
[rp2040_base]
|
||||
platform = https://github.com/maxgerhardt/platform-raspberrypi.git#5ce1a228e7cae453f366deb8962252b9b7356bbc
|
||||
platform = https://github.com/maxgerhardt/platform-raspberrypi.git#20c7dbfcfe6677c5305fa28ecf5e3870321cb157
|
||||
platform_packages =
|
||||
earlephilhower/toolchain-rp2040-earlephilhower@^5.100300.221223
|
||||
extends = arduino_base
|
||||
board_build.core = earlephilhower
|
||||
board_build.filesystem_size = 0.5m
|
||||
@@ -10,7 +12,7 @@ build_flags =
|
||||
-D__PLAT_RP2040__
|
||||
# -D _POSIX_THREADS
|
||||
build_src_filter =
|
||||
${arduino_base.build_src_filter} -<platform/esp32/> -<nimble/> -<mesh/wifi/> -<mesh/http/> -<modules/esp32> -<mqtt/> -<platform/nrf52/> -<platform/stm32wl> -<mesh/eth/>
|
||||
${arduino_base.build_src_filter} -<platform/esp32/> -<nimble/> -<mesh/api/> -<mesh/http/> -<modules/esp32> -<mqtt/> -<platform/nrf52/> -<platform/stm32wl> -<mesh/eth/>
|
||||
lib_ignore =
|
||||
BluetoothOTA
|
||||
lib_deps =
|
||||
|
||||
@@ -10,7 +10,7 @@ build_flags =
|
||||
# Arduino/PlatformIO framework-arduinoststm32 package does not presently have SUBGHZSPI support
|
||||
# -DPIN_SPI_MOSI=PINSUBGHZSPIMOSI -DPIN_SPI_MISO=PINSUBGHZSPIMISO -DPIN_SPI_SCK=PINSUBGHZSPISCK
|
||||
build_src_filter =
|
||||
${arduino_base.build_src_filter} -<platform/esp32/> -<nimble/> -<mesh/wifi/> -<mesh/http/> -<modules/esp32> -<mesh/eth/> -<mqtt/> -<graphics> -<input> -<buzz> -<modules/Telemetry> -<platform/nrf52> -<platform/portduino> -<platform/rp2040>
|
||||
${arduino_base.build_src_filter} -<platform/esp32/> -<nimble/> -<mesh/api/> -<mesh/http/> -<modules/esp32> -<mesh/eth/> -<mqtt/> -<graphics> -<input> -<buzz> -<modules/Telemetry> -<platform/nrf52> -<platform/portduino> -<platform/rp2040>
|
||||
lib_deps =
|
||||
${env.lib_deps}
|
||||
https://github.com/kokke/tiny-AES-c.git#f06ac37fc31dfdaca2e0d9bec83f90d5663c319b
|
||||
|
||||
@@ -45,7 +45,7 @@ shift "$((OPTIND-1))"
|
||||
shift
|
||||
}
|
||||
|
||||
if [ -f "${FILENAME}" ] && [[ "${FILENAME}" != *"update"* ]]; then
|
||||
if [ -f "${FILENAME}" ] && [ ! -z "${FILENAME##*"update"*}" ]; then
|
||||
echo "Trying to flash ${FILENAME}, but first erasing and writing system information"
|
||||
"$PYTHON" -m esptool erase_flash
|
||||
"$PYTHON" -m esptool write_flash 0x00 ${FILENAME}
|
||||
|
||||
@@ -43,7 +43,7 @@ shift "$((OPTIND-1))"
|
||||
shift
|
||||
}
|
||||
|
||||
if [ -f "${FILENAME}" ] && [[ $FILENAME == *"update"* ]]; then
|
||||
if [ -f "${FILENAME}" ] && [ -z "${FILENAME##*"update"*}" ]; then
|
||||
printf "Trying to flash update ${FILENAME}"
|
||||
$PYTHON -m esptool --baud 115200 write_flash 0x10000 ${FILENAME}
|
||||
else
|
||||
|
||||
@@ -1 +1 @@
|
||||
cd protobufs && ..\nanopb-0.4.6\generator-bin\protoc.exe --nanopb_out=-v:..\src\mesh\generated -I=..\protobufs *.proto
|
||||
cd protobufs && ..\nanopb-0.4.7\generator-bin\protoc.exe --nanopb_out=-v:..\src\mesh\generated -I=..\protobufs *.proto
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
|
||||
set -e
|
||||
|
||||
echo "This script requires https://jpa.kapsi.fi/nanopb/download/ version 0.4.6 to be located in the"
|
||||
echo "This script requires https://jpa.kapsi.fi/nanopb/download/ version 0.4.7 to be located in the"
|
||||
echo "firmware root directory if the following step fails, you should download the correct"
|
||||
echo "prebuilt binaries for your computer into nanopb-0.4.6"
|
||||
echo "prebuilt binaries for your computer into nanopb-0.4.7"
|
||||
|
||||
# the nanopb tool seems to require that the .options file be in the current directory!
|
||||
cd protobufs
|
||||
../nanopb-0.4.6/generator-bin/protoc --nanopb_out=-v:../src/mesh/generated -I=../protobufs *.proto
|
||||
../nanopb-0.4.7/generator-bin/protoc --nanopb_out=-v:../src/mesh/generated -I=../protobufs *.proto
|
||||
|
||||
#echo "Regenerating protobuf documentation - if you see an error message"
|
||||
#echo "you can ignore it unless doing a new protobuf release to github."
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino":{
|
||||
"arduino": {
|
||||
"ldscript": "esp32s3_out.ld"
|
||||
},
|
||||
"core": "esp32",
|
||||
@@ -8,9 +8,7 @@
|
||||
"-DBOARD_HAS_PSRAM",
|
||||
"-DLILYGO_TBEAM_S3_CORE",
|
||||
"-DARDUINO_USB_CDC_ON_BOOT=1",
|
||||
"-DARDUINO_USB_DFU_ON_BOOT=1",
|
||||
"-DARDUINO_USB_MSC_ON_BOOT=1",
|
||||
"-DARDUINO_USB_MODE=1",
|
||||
"-DARDUINO_USB_MODE=0",
|
||||
"-DARDUINO_RUNNING_CORE=1",
|
||||
"-DARDUINO_EVENT_RUNNING_CORE=1"
|
||||
],
|
||||
|
||||
47
boards/tlora-t3s3-v1.json
Normal file
47
boards/tlora-t3s3-v1.json
Normal file
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"ldscript": "esp32s3_out.ld"
|
||||
},
|
||||
"core": "esp32",
|
||||
"extra_flags": [
|
||||
"-DLILYGO_T3S3_V1",
|
||||
"-DARDUINO_USB_CDC_ON_BOOT=1",
|
||||
"-DARDUINO_USB_MODE=0",
|
||||
"-DARDUINO_RUNNING_CORE=1",
|
||||
"-DARDUINO_EVENT_RUNNING_CORE=1"
|
||||
],
|
||||
"f_cpu": "240000000L",
|
||||
"f_flash": "80000000L",
|
||||
"flash_mode": "dio",
|
||||
"hwids": [
|
||||
[
|
||||
"0X303A",
|
||||
"0x1001"
|
||||
]
|
||||
],
|
||||
"mcu": "esp32s3",
|
||||
"variant": "tlora-t3s3-v1"
|
||||
},
|
||||
"connectivity": [
|
||||
"wifi"
|
||||
],
|
||||
"debug": {
|
||||
"openocd_target": "esp32s3.cfg"
|
||||
},
|
||||
"frameworks": [
|
||||
"arduino",
|
||||
"espidf"
|
||||
],
|
||||
"name": "LilyGo TLora-T3S3-V1",
|
||||
"upload": {
|
||||
"flash_size": "4MB",
|
||||
"maximum_ram_size": 327680,
|
||||
"maximum_size": 4194304,
|
||||
"wait_for_upload_port": true,
|
||||
"require_upload_port": true,
|
||||
"speed": 921600
|
||||
},
|
||||
"url": "http://www.lilygo.cn/",
|
||||
"vendor": "LilyGo"
|
||||
}
|
||||
@@ -10,7 +10,6 @@
|
||||
;default_envs = heltec-v2.0
|
||||
;default_envs = heltec-v2.1
|
||||
;default_envs = tlora-v1
|
||||
;default_envs = tlora-v1
|
||||
;default_envs = tlora_v1_3
|
||||
;default_envs = tlora-v2
|
||||
;default_envs = tlora-v2-1-1.6
|
||||
@@ -66,7 +65,8 @@ lib_deps =
|
||||
https://github.com/meshtastic/ArduinoThread.git#72921ac222eed6f526ba1682023cee290d9aa1b3
|
||||
nanopb/Nanopb@^0.4.6
|
||||
erriez/ErriezCRC32@^1.0.1
|
||||
jgromes/RadioLib@^5.5.0
|
||||
; jgromes/RadioLib@^5.5.1
|
||||
https://github.com/jgromes/RadioLib.git#395844922c5d88d5db0481a9c91479931172428d
|
||||
|
||||
; Used for the code analysis in PIO Home / Inspect
|
||||
check_tool = cppcheck
|
||||
@@ -82,6 +82,7 @@ framework = arduino
|
||||
lib_deps =
|
||||
${env.lib_deps}
|
||||
mprograms/QMC5883LCompass@^1.1.1
|
||||
end2endzone/NonBlockingRTTTL@^1.3.0
|
||||
https://github.com/meshtastic/SparkFun_ATECCX08a_Arduino_Library.git#52b5282639d08a8cbd4b748363089eed6102dc76
|
||||
|
||||
build_flags = ${env.build_flags} -Os -DRADIOLIB_SPI_PARANOID=0
|
||||
@@ -107,3 +108,4 @@ 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
|
||||
|
||||
Submodule protobufs updated: afa4605699...e00b5ba7d0
@@ -51,6 +51,7 @@ class ButtonThread : public concurrency::OSThread
|
||||
pinMode(BUTTON_PIN, INPUT_PULLUP_SENSE);
|
||||
#endif
|
||||
userButton.attachClick(userButtonPressed);
|
||||
userButton.setClickTicks(300);
|
||||
userButton.attachDuringLongPress(userButtonPressedLong);
|
||||
userButton.attachDoubleClick(userButtonDoublePressed);
|
||||
userButton.attachMultiClick(userButtonMultiPressed);
|
||||
@@ -97,8 +98,8 @@ class ButtonThread : public concurrency::OSThread
|
||||
userButtonTouch.tick();
|
||||
canSleep &= userButtonTouch.isIdle();
|
||||
#endif
|
||||
// if (!canSleep) DEBUG_MSG("Supressing sleep!\n");
|
||||
// else DEBUG_MSG("sleep ok\n");
|
||||
// if (!canSleep) LOG_DEBUG("Supressing sleep!\n");
|
||||
// else LOG_DEBUG("sleep ok\n");
|
||||
|
||||
return 5;
|
||||
}
|
||||
@@ -107,12 +108,12 @@ class ButtonThread : public concurrency::OSThread
|
||||
static void touchPressed()
|
||||
{
|
||||
screen->forceDisplay();
|
||||
DEBUG_MSG("touch press!\n");
|
||||
LOG_DEBUG("touch press!\n");
|
||||
}
|
||||
|
||||
static void userButtonPressed()
|
||||
{
|
||||
// DEBUG_MSG("press!\n");
|
||||
// LOG_DEBUG("press!\n");
|
||||
#ifdef BUTTON_PIN
|
||||
if ((BUTTON_PIN != moduleConfig.canned_message.inputbroker_pin_press) ||
|
||||
!moduleConfig.canned_message.enabled) {
|
||||
@@ -122,7 +123,7 @@ class ButtonThread : public concurrency::OSThread
|
||||
}
|
||||
static void userButtonPressedLong()
|
||||
{
|
||||
// DEBUG_MSG("Long press!\n");
|
||||
// LOG_DEBUG("Long press!\n");
|
||||
#ifdef ARCH_ESP32
|
||||
screen->adjustBrightness();
|
||||
#endif
|
||||
@@ -138,7 +139,7 @@ class ButtonThread : public concurrency::OSThread
|
||||
// may wake the board immediatedly.
|
||||
if ((!shutdown_on_long_stop) && (millis() > 30 * 1000)) {
|
||||
screen->startShutdownScreen();
|
||||
DEBUG_MSG("Shutdown from long press");
|
||||
LOG_INFO("Shutdown from long press");
|
||||
playBeep();
|
||||
#ifdef PIN_LED1
|
||||
ledOff(PIN_LED1);
|
||||
@@ -153,15 +154,27 @@ class ButtonThread : public concurrency::OSThread
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
// DEBUG_MSG("Long press %u\n", (millis() - longPressTime));
|
||||
// LOG_DEBUG("Long press %u\n", (millis() - longPressTime));
|
||||
}
|
||||
}
|
||||
|
||||
static void userButtonDoublePressed()
|
||||
{
|
||||
#if defined(USE_EINK) && defined(PIN_EINK_EN)
|
||||
#if defined(USE_EINK) && defined(PIN_EINK_EN)
|
||||
digitalWrite(PIN_EINK_EN, digitalRead(PIN_EINK_EN) == LOW);
|
||||
#endif
|
||||
#endif
|
||||
#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");
|
||||
}
|
||||
config.position.gps_enabled = !(config.position.gps_enabled);
|
||||
doGPSpowersave(config.position.gps_enabled);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void userButtonMultiPressed()
|
||||
@@ -174,7 +187,7 @@ class ButtonThread : public concurrency::OSThread
|
||||
static void userButtonPressedLongStart()
|
||||
{
|
||||
if (millis() > 30 * 1000) {
|
||||
DEBUG_MSG("Long press start!\n");
|
||||
LOG_DEBUG("Long press start!\n");
|
||||
longPressTime = millis();
|
||||
}
|
||||
}
|
||||
@@ -182,7 +195,7 @@ class ButtonThread : public concurrency::OSThread
|
||||
static void userButtonPressedLongStop()
|
||||
{
|
||||
if (millis() > 30 * 1000) {
|
||||
DEBUG_MSG("Long press stop!\n");
|
||||
LOG_DEBUG("Long press stop!\n");
|
||||
longPressTime = 0;
|
||||
if (shutdown_on_long_stop) {
|
||||
playShutdownMelody();
|
||||
|
||||
@@ -13,17 +13,33 @@
|
||||
#define SERIAL_BAUD 115200 // Serial debug baud rate
|
||||
#endif
|
||||
|
||||
#define MESHTASTIC_LOG_LEVEL_DEBUG "DEBUG"
|
||||
#define MESHTASTIC_LOG_LEVEL_INFO "INFO "
|
||||
#define MESHTASTIC_LOG_LEVEL_WARN "WARN "
|
||||
#define MESHTASTIC_LOG_LEVEL_ERROR "ERROR"
|
||||
#define MESHTASTIC_LOG_LEVEL_TRACE "TRACE"
|
||||
|
||||
#include "SerialConsole.h"
|
||||
|
||||
#define DEBUG_PORT (*console) // Serial debug port
|
||||
|
||||
#ifdef USE_SEGGER
|
||||
#define DEBUG_MSG(...) SEGGER_RTT_printf(0, __VA_ARGS__)
|
||||
#define LOG_DEBUG(...) SEGGER_RTT_printf(0, __VA_ARGS__)
|
||||
#define LOG_INFO(...) SEGGER_RTT_printf(0, __VA_ARGS__)
|
||||
#define LOG_WARN(...) SEGGER_RTT_printf(0, __VA_ARGS__)
|
||||
#define LOG_ERROR(...) SEGGER_RTT_printf(0, __VA_ARGS__)
|
||||
#else
|
||||
#ifdef DEBUG_PORT
|
||||
#define DEBUG_MSG(...) DEBUG_PORT.logDebug(__VA_ARGS__)
|
||||
#define LOG_DEBUG(...) DEBUG_PORT.log(MESHTASTIC_LOG_LEVEL_DEBUG, __VA_ARGS__)
|
||||
#define LOG_INFO(...) DEBUG_PORT.log(MESHTASTIC_LOG_LEVEL_INFO, __VA_ARGS__)
|
||||
#define LOG_WARN(...) DEBUG_PORT.log(MESHTASTIC_LOG_LEVEL_WARN, __VA_ARGS__)
|
||||
#define LOG_ERROR(...) DEBUG_PORT.log(MESHTASTIC_LOG_LEVEL_ERROR, __VA_ARGS__)
|
||||
#define LOG_TRACE(...) DEBUG_PORT.log(MESHTASTIC_LOG_TRACE, __VA_ARGS__)
|
||||
#else
|
||||
#define DEBUG_MSG(...)
|
||||
#define LOG_DEBUG(...)
|
||||
#define LOG_INFO(...)
|
||||
#define LOG_WARN(...)
|
||||
#define LOG_ERROR(...)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
@@ -21,13 +21,13 @@ bool copyFile(const char* from, const char* to)
|
||||
|
||||
File f1 = FSCom.open(from, FILE_O_READ);
|
||||
if (!f1){
|
||||
DEBUG_MSG("Failed to open source file %s\n", from);
|
||||
LOG_ERROR("Failed to open source file %s\n", from);
|
||||
return false;
|
||||
}
|
||||
|
||||
File f2 = FSCom.open(to, FILE_O_WRITE);
|
||||
if (!f2) {
|
||||
DEBUG_MSG("Failed to open destination file %s\n", to);
|
||||
LOG_ERROR("Failed to open destination file %s\n", to);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ void listDir(const char * dirname, uint8_t levels, boolean del = false)
|
||||
#ifdef ARCH_ESP32
|
||||
listDir(file.path(), levels -1, del);
|
||||
if(del) {
|
||||
DEBUG_MSG("Removing %s\n", file.path());
|
||||
LOG_DEBUG("Removing %s\n", file.path());
|
||||
strcpy(buffer, file.path());
|
||||
file.close();
|
||||
FSCom.rmdir(buffer);
|
||||
@@ -89,7 +89,7 @@ void listDir(const char * dirname, uint8_t levels, boolean del = false)
|
||||
#elif (defined(ARCH_RP2040) || defined(ARCH_PORTDUINO))
|
||||
listDir(file.name(), levels -1, del);
|
||||
if(del) {
|
||||
DEBUG_MSG("Removing %s\n", file.name());
|
||||
LOG_DEBUG("Removing %s\n", file.name());
|
||||
strcpy(buffer, file.name());
|
||||
file.close();
|
||||
FSCom.rmdir(buffer);
|
||||
@@ -104,26 +104,26 @@ void listDir(const char * dirname, uint8_t levels, boolean del = false)
|
||||
} else {
|
||||
#ifdef ARCH_ESP32
|
||||
if(del) {
|
||||
DEBUG_MSG("Deleting %s\n", file.path());
|
||||
LOG_DEBUG("Deleting %s\n", file.path());
|
||||
strcpy(buffer, file.path());
|
||||
file.close();
|
||||
FSCom.remove(buffer);
|
||||
} else {
|
||||
DEBUG_MSG(" %s (%i Bytes)\n", file.path(), file.size());
|
||||
LOG_DEBUG(" %s (%i Bytes)\n", file.path(), file.size());
|
||||
file.close();
|
||||
}
|
||||
#elif (defined(ARCH_RP2040) || defined(ARCH_PORTDUINO))
|
||||
if(del) {
|
||||
DEBUG_MSG("Deleting %s\n", file.name());
|
||||
LOG_DEBUG("Deleting %s\n", file.name());
|
||||
strcpy(buffer, file.name());
|
||||
file.close();
|
||||
FSCom.remove(buffer);
|
||||
} else {
|
||||
DEBUG_MSG(" %s (%i Bytes)\n", file.name(), file.size());
|
||||
LOG_DEBUG(" %s (%i Bytes)\n", file.name(), file.size());
|
||||
file.close();
|
||||
}
|
||||
#else
|
||||
DEBUG_MSG(" %s (%i Bytes)\n", file.name(), file.size());
|
||||
LOG_DEBUG(" %s (%i Bytes)\n", file.name(), file.size());
|
||||
file.close();
|
||||
#endif
|
||||
}
|
||||
@@ -131,7 +131,7 @@ void listDir(const char * dirname, uint8_t levels, boolean del = false)
|
||||
}
|
||||
#ifdef ARCH_ESP32
|
||||
if(del) {
|
||||
DEBUG_MSG("Removing %s\n", root.path());
|
||||
LOG_DEBUG("Removing %s\n", root.path());
|
||||
strcpy(buffer, root.path());
|
||||
root.close();
|
||||
FSCom.rmdir(buffer);
|
||||
@@ -140,7 +140,7 @@ void listDir(const char * dirname, uint8_t levels, boolean del = false)
|
||||
}
|
||||
#elif (defined(ARCH_RP2040) || defined(ARCH_PORTDUINO))
|
||||
if(del) {
|
||||
DEBUG_MSG("Removing %s\n", root.name());
|
||||
LOG_DEBUG("Removing %s\n", root.name());
|
||||
strcpy(buffer, root.name());
|
||||
root.close();
|
||||
FSCom.rmdir(buffer);
|
||||
@@ -170,13 +170,13 @@ void fsInit()
|
||||
#ifdef FSCom
|
||||
if (!FSBegin())
|
||||
{
|
||||
DEBUG_MSG("ERROR filesystem mount Failed. Formatting...\n");
|
||||
assert(0); // FIXME - report failure to phone
|
||||
LOG_ERROR("Filesystem mount Failed.\n");
|
||||
// assert(0); This auto-formats the partition, so no need to fail here.
|
||||
}
|
||||
#ifdef ARCH_ESP32
|
||||
DEBUG_MSG("Filesystem files (%d/%d Bytes):\n", FSCom.usedBytes(), FSCom.totalBytes());
|
||||
LOG_DEBUG("Filesystem files (%d/%d Bytes):\n", FSCom.usedBytes(), FSCom.totalBytes());
|
||||
#else
|
||||
DEBUG_MSG("Filesystem files:\n");
|
||||
LOG_DEBUG("Filesystem files:\n");
|
||||
#endif
|
||||
listDir("/", 10);
|
||||
#endif
|
||||
@@ -189,29 +189,29 @@ void setupSDCard()
|
||||
SDHandler.begin(SPI_SCK, SPI_MISO, SPI_MOSI);
|
||||
|
||||
if (!SD.begin(SDCARD_CS, SDHandler)) {
|
||||
DEBUG_MSG("No SD_MMC card detected\n");
|
||||
LOG_DEBUG("No SD_MMC card detected\n");
|
||||
return ;
|
||||
}
|
||||
uint8_t cardType = SD.cardType();
|
||||
if (cardType == CARD_NONE) {
|
||||
DEBUG_MSG("No SD_MMC card attached\n");
|
||||
LOG_DEBUG("No SD_MMC card attached\n");
|
||||
return ;
|
||||
}
|
||||
DEBUG_MSG("SD_MMC Card Type: ");
|
||||
LOG_DEBUG("SD_MMC Card Type: ");
|
||||
if (cardType == CARD_MMC) {
|
||||
DEBUG_MSG("MMC\n");
|
||||
LOG_DEBUG("MMC\n");
|
||||
} else if (cardType == CARD_SD) {
|
||||
DEBUG_MSG("SDSC\n");
|
||||
LOG_DEBUG("SDSC\n");
|
||||
} else if (cardType == CARD_SDHC) {
|
||||
DEBUG_MSG("SDHC\n");
|
||||
LOG_DEBUG("SDHC\n");
|
||||
} else {
|
||||
DEBUG_MSG("UNKNOWN\n");
|
||||
LOG_DEBUG("UNKNOWN\n");
|
||||
}
|
||||
|
||||
uint64_t cardSize = SD.cardSize() / (1024 * 1024);
|
||||
DEBUG_MSG("SD Card Size: %lluMB\n", cardSize);
|
||||
DEBUG_MSG("Total space: %llu MB\n", SD.totalBytes() / (1024 * 1024));
|
||||
DEBUG_MSG("Used space: %llu MB\n", SD.usedBytes() / (1024 * 1024));
|
||||
LOG_DEBUG("SD Card Size: %lluMB\n", cardSize);
|
||||
LOG_DEBUG("Total space: %llu MB\n", SD.totalBytes() / (1024 * 1024));
|
||||
LOG_DEBUG("Used space: %llu MB\n", SD.usedBytes() / (1024 * 1024));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
// RP2040
|
||||
#include "LittleFS.h"
|
||||
#define FSCom LittleFS
|
||||
#define FSBegin() FSCom.begin()
|
||||
#define FSBegin() FSCom.begin() // set autoformat
|
||||
#define FILE_O_WRITE "w"
|
||||
#define FILE_O_READ "r"
|
||||
#endif
|
||||
@@ -26,7 +26,7 @@
|
||||
// ESP32 version
|
||||
#include "LittleFS.h"
|
||||
#define FSCom LittleFS
|
||||
#define FSBegin() FSCom.begin(true)
|
||||
#define FSBegin() FSCom.begin(true) // format on failure
|
||||
#define FILE_O_WRITE "w"
|
||||
#define FILE_O_READ "r"
|
||||
#endif
|
||||
@@ -35,7 +35,7 @@
|
||||
// NRF52 version
|
||||
#include "InternalFileSystem.h"
|
||||
#define FSCom InternalFS
|
||||
#define FSBegin() FSCom.begin()
|
||||
#define FSBegin() FSCom.begin() // InternalFS formats on failure
|
||||
using namespace Adafruit_LittleFS_Namespace;
|
||||
#endif
|
||||
|
||||
|
||||
@@ -20,16 +20,19 @@ class GPSStatus : public Status
|
||||
bool hasLock = false; // default to false, until we complete our first read
|
||||
bool isConnected = false; // Do we have a GPS we are talking to
|
||||
|
||||
bool isPowerSaving = false; //Are we in power saving state
|
||||
|
||||
Position p = Position_init_default;
|
||||
|
||||
public:
|
||||
GPSStatus() { statusType = STATUS_TYPE_GPS; }
|
||||
|
||||
// preferred method
|
||||
GPSStatus(bool hasLock, bool isConnected, const Position &pos) : Status()
|
||||
GPSStatus(bool hasLock, bool isConnected, bool isPowerSaving, const Position &pos) : Status()
|
||||
{
|
||||
this->hasLock = hasLock;
|
||||
this->isConnected = isConnected;
|
||||
this->isPowerSaving = isPowerSaving;
|
||||
|
||||
// all-in-one struct copy
|
||||
this->p = pos;
|
||||
@@ -44,11 +47,13 @@ class GPSStatus : public Status
|
||||
|
||||
bool getIsConnected() const { return isConnected; }
|
||||
|
||||
bool getIsPowerSaving() const { return isPowerSaving;}
|
||||
|
||||
int32_t getLatitude() const
|
||||
{
|
||||
if (config.position.fixed_position) {
|
||||
#ifdef GPS_EXTRAVERBOSE
|
||||
DEBUG_MSG("WARNING: Using fixed latitude\n");
|
||||
LOG_WARN("Using fixed latitude\n");
|
||||
#endif
|
||||
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
|
||||
return node->position.latitude_i;
|
||||
@@ -61,7 +66,7 @@ class GPSStatus : public Status
|
||||
{
|
||||
if (config.position.fixed_position) {
|
||||
#ifdef GPS_EXTRAVERBOSE
|
||||
DEBUG_MSG("WARNING: Using fixed longitude\n");
|
||||
LOG_WARN("Using fixed longitude\n");
|
||||
#endif
|
||||
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
|
||||
return node->position.longitude_i;
|
||||
@@ -74,7 +79,7 @@ class GPSStatus : public Status
|
||||
{
|
||||
if (config.position.fixed_position) {
|
||||
#ifdef GPS_EXTRAVERBOSE
|
||||
DEBUG_MSG("WARNING: Using fixed altitude\n");
|
||||
LOG_WARN("Using fixed altitude\n");
|
||||
#endif
|
||||
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
|
||||
return node->position.altitude;
|
||||
@@ -92,9 +97,9 @@ class GPSStatus : public Status
|
||||
bool matches(const GPSStatus *newStatus) const
|
||||
{
|
||||
#ifdef GPS_EXTRAVERBOSE
|
||||
DEBUG_MSG("GPSStatus.match() new pos@%x to old pos@%x\n", newStatus->p.pos_timestamp, p.pos_timestamp);
|
||||
LOG_DEBUG("GPSStatus.match() new pos@%x to old pos@%x\n", newStatus->p.pos_timestamp, p.pos_timestamp);
|
||||
#endif
|
||||
return (newStatus->hasLock != hasLock || newStatus->isConnected != isConnected ||
|
||||
return (newStatus->hasLock != hasLock || newStatus->isConnected != isConnected || newStatus->isPowerSaving !=isPowerSaving ||
|
||||
newStatus->p.latitude_i != p.latitude_i || newStatus->p.longitude_i != p.longitude_i ||
|
||||
newStatus->p.altitude != p.altitude || newStatus->p.altitude_hae != p.altitude_hae ||
|
||||
newStatus->p.PDOP != p.PDOP || newStatus->p.ground_track != p.ground_track ||
|
||||
@@ -109,7 +114,7 @@ class GPSStatus : public Status
|
||||
|
||||
if (isDirty && p.timestamp && (newStatus->p.timestamp == p.timestamp)) {
|
||||
// We can NEVER be in two locations at the same time! (also PR #886)
|
||||
DEBUG_MSG("BUG!! positional timestamp unchanged from prev solution\n");
|
||||
LOG_ERROR("BUG: Positional timestamp unchanged from prev solution\n");
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
@@ -121,11 +126,11 @@ class GPSStatus : public Status
|
||||
if (isDirty) {
|
||||
if (hasLock) {
|
||||
// In debug logs, identify position by @timestamp:stage (stage 3 = notify)
|
||||
DEBUG_MSG("New GPS pos@%x:3 lat=%f, lon=%f, alt=%d, pdop=%.2f, track=%.2f, speed=%.2f, sats=%d\n", p.timestamp,
|
||||
LOG_DEBUG("New GPS pos@%x:3 lat=%f, lon=%f, alt=%d, pdop=%.2f, track=%.2f, speed=%.2f, sats=%d\n", p.timestamp,
|
||||
p.latitude_i * 1e-7, p.longitude_i * 1e-7, p.altitude, p.PDOP * 1e-2, p.ground_track * 1e-5,
|
||||
p.ground_speed * 1e-2, p.sats_in_view);
|
||||
} else
|
||||
DEBUG_MSG("No GPS lock\n");
|
||||
LOG_DEBUG("No GPS lock\n");
|
||||
onNewStatus.notifyObservers(this);
|
||||
}
|
||||
return 0;
|
||||
|
||||
@@ -70,7 +70,7 @@ namespace meshtastic {
|
||||
numTotal = newStatus->getNumTotal();
|
||||
}
|
||||
if(isDirty || newStatus->forceUpdate) {
|
||||
DEBUG_MSG("Node status update: %d online, %d total\n", numOnline, numTotal);
|
||||
LOG_DEBUG("Node status update: %d online, %d total\n", numOnline, numTotal);
|
||||
onNewStatus.notifyObservers(this);
|
||||
}
|
||||
return 0;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <assert.h>
|
||||
#include <list>
|
||||
|
||||
template <class T> class Observable;
|
||||
|
||||
113
src/Power.cpp
113
src/Power.cpp
@@ -102,6 +102,10 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
||||
#define ADC_MULTIPLIER 2.0
|
||||
#endif
|
||||
|
||||
#ifndef BATTERY_SENSE_SAMPLES
|
||||
#define BATTERY_SENSE_SAMPLES 30
|
||||
#endif
|
||||
|
||||
#ifdef BATTERY_PIN
|
||||
// Override variant or default ADC_MULTIPLIER if we have the override pref
|
||||
float operativeAdcMultiplier = config.power.adc_multiplier_override > 0
|
||||
@@ -112,16 +116,12 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
||||
if (millis() - last_read_time_ms > min_read_interval) {
|
||||
last_read_time_ms = millis();
|
||||
|
||||
#ifdef BATTERY_SENSE_SAMPLES
|
||||
//Set the number of samples, it has an effect of increasing sensitivity, especially in complex electromagnetic environment.
|
||||
uint32_t raw = 0;
|
||||
for(uint32_t i=0; i<BATTERY_SENSE_SAMPLES;i++){
|
||||
for(uint32_t i=0; i<BATTERY_SENSE_SAMPLES; i++){
|
||||
raw += analogRead(BATTERY_PIN);
|
||||
}
|
||||
raw = raw/BATTERY_SENSE_SAMPLES;
|
||||
#else
|
||||
uint32_t raw = analogRead(BATTERY_PIN);
|
||||
#endif
|
||||
|
||||
float scaled;
|
||||
#ifndef VBAT_RAW_TO_SCALED
|
||||
@@ -129,7 +129,7 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
||||
#else
|
||||
scaled = VBAT_RAW_TO_SCALED(raw); // defined in variant.h
|
||||
#endif
|
||||
// DEBUG_MSG("battery gpio %d raw val=%u scaled=%u\n", BATTERY_PIN, raw, (uint32_t)(scaled));
|
||||
// LOG_DEBUG("battery gpio %d raw val=%u scaled=%u\n", BATTERY_PIN, raw, (uint32_t)(scaled));
|
||||
last_read_value = scaled;
|
||||
return scaled;
|
||||
} else {
|
||||
@@ -182,12 +182,15 @@ Power::Power() : OSThread("Power")
|
||||
{
|
||||
statusHandler = {};
|
||||
low_voltage_counter = 0;
|
||||
#ifdef DEBUG_HEAP
|
||||
lastheap = ESP.getFreeHeap();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Power::analogInit()
|
||||
{
|
||||
#ifdef BATTERY_PIN
|
||||
DEBUG_MSG("Using analog input %d for battery level\n", BATTERY_PIN);
|
||||
LOG_DEBUG("Using analog input %d for battery level\n", BATTERY_PIN);
|
||||
|
||||
// disable any internal pullups
|
||||
pinMode(BATTERY_PIN, INPUT);
|
||||
@@ -239,7 +242,7 @@ void Power::shutdown()
|
||||
#endif
|
||||
|
||||
#ifdef HAS_PMU
|
||||
DEBUG_MSG("Shutting down\n");
|
||||
LOG_INFO("Shutting down\n");
|
||||
if(PMU) {
|
||||
PMU->setChargingLedMode(XPOWERS_CHG_LED_OFF);
|
||||
PMU->shutdown();
|
||||
@@ -280,9 +283,25 @@ void Power::readPowerStatus()
|
||||
const PowerStatus powerStatus2 =
|
||||
PowerStatus(hasBattery ? OptTrue : OptFalse, batteryLevel->isVbusIn() ? OptTrue : OptFalse,
|
||||
batteryLevel->isCharging() ? OptTrue : OptFalse, batteryVoltageMv, batteryChargePercent);
|
||||
DEBUG_MSG("Battery: usbPower=%d, isCharging=%d, batMv=%d, batPct=%d\n", powerStatus2.getHasUSB(),
|
||||
LOG_DEBUG("Battery: usbPower=%d, isCharging=%d, batMv=%d, batPct=%d\n", powerStatus2.getHasUSB(),
|
||||
powerStatus2.getIsCharging(), powerStatus2.getBatteryVoltageMv(), powerStatus2.getBatteryChargePercent());
|
||||
newStatus.notifyObservers(&powerStatus2);
|
||||
#ifdef DEBUG_HEAP
|
||||
if (lastheap != ESP.getFreeHeap()) {
|
||||
LOG_DEBUG("Threads running:");
|
||||
int running = 0;
|
||||
for(int i = 0; i < MAX_THREADS; i++){
|
||||
auto thread = concurrency::mainController.get(i);
|
||||
if((thread != nullptr) && (thread->enabled)) {
|
||||
LOG_DEBUG(" %s", thread->ThreadName.c_str());
|
||||
running++;
|
||||
}
|
||||
}
|
||||
LOG_DEBUG("\n");
|
||||
LOG_DEBUG("Heap status: %d/%d bytes free (%d), running %d/%d threads\n", ESP.getFreeHeap(), ESP.getHeapSize(), ESP.getFreeHeap() - lastheap, running, concurrency::mainController.size(false));
|
||||
lastheap = ESP.getFreeHeap();
|
||||
}
|
||||
#endif
|
||||
|
||||
// If we have a battery at all and it is less than 10% full, force deep sleep if we have more than 3 low readings in a row
|
||||
// Supect fluctuating voltage on the RAK4631 to force it to deep sleep even if battery is at 85% after only a few days
|
||||
@@ -290,8 +309,12 @@ void Power::readPowerStatus()
|
||||
if (powerStatus2.getHasBattery() && !powerStatus2.getHasUSB()) {
|
||||
if (batteryLevel->getBattVoltage() < MIN_BAT_MILLIVOLTS) {
|
||||
low_voltage_counter++;
|
||||
if (low_voltage_counter > 3)
|
||||
powerFSM.trigger(EVENT_LOW_BATTERY);
|
||||
LOG_DEBUG("Warning RAK4631 Low voltage counter: %d/10\n", low_voltage_counter);
|
||||
if (low_voltage_counter > 10) {
|
||||
// We can't trigger deep sleep on NRF52, it's freezing the board
|
||||
//powerFSM.trigger(EVENT_LOW_BATTERY);
|
||||
LOG_DEBUG("Low voltage detected, but not triggering deep sleep\n");
|
||||
}
|
||||
} else {
|
||||
low_voltage_counter = 0;
|
||||
}
|
||||
@@ -320,12 +343,12 @@ int32_t Power::runOnce()
|
||||
PMU->getIrqStatus();
|
||||
|
||||
if(PMU->isVbusRemoveIrq()){
|
||||
DEBUG_MSG("USB unplugged\n");
|
||||
LOG_INFO("USB unplugged\n");
|
||||
powerFSM.trigger(EVENT_POWER_DISCONNECTED);
|
||||
}
|
||||
|
||||
if (PMU->isVbusInsertIrq()) {
|
||||
DEBUG_MSG("USB plugged In\n");
|
||||
LOG_INFO("USB plugged In\n");
|
||||
powerFSM.trigger(EVENT_POWER_CONNECTED);
|
||||
}
|
||||
|
||||
@@ -333,20 +356,20 @@ int32_t Power::runOnce()
|
||||
Other things we could check if we cared...
|
||||
|
||||
if (PMU->isBatChagerStartIrq()) {
|
||||
DEBUG_MSG("Battery start charging\n");
|
||||
LOG_DEBUG("Battery start charging\n");
|
||||
}
|
||||
if (PMU->isBatChagerDoneIrq()) {
|
||||
DEBUG_MSG("Battery fully charged\n");
|
||||
LOG_DEBUG("Battery fully charged\n");
|
||||
}
|
||||
if (PMU->isBatInsertIrq()) {
|
||||
DEBUG_MSG("Battery inserted\n");
|
||||
LOG_DEBUG("Battery inserted\n");
|
||||
}
|
||||
if (PMU->isBatRemoveIrq()) {
|
||||
DEBUG_MSG("Battery removed\n");
|
||||
LOG_DEBUG("Battery removed\n");
|
||||
}
|
||||
*/
|
||||
if (PMU->isPekeyLongPressIrq()) {
|
||||
DEBUG_MSG("PEK long button press\n");
|
||||
LOG_DEBUG("PEK long button press\n");
|
||||
screen->setOn(false);
|
||||
}
|
||||
|
||||
@@ -388,22 +411,22 @@ bool Power::axpChipInit()
|
||||
if (!PMU) {
|
||||
PMU = new XPowersAXP2101(*w);
|
||||
if (!PMU->init()) {
|
||||
DEBUG_MSG("Warning: Failed to find AXP2101 power management\n");
|
||||
LOG_WARN("Failed to find AXP2101 power management\n");
|
||||
delete PMU;
|
||||
PMU = NULL;
|
||||
} else {
|
||||
DEBUG_MSG("AXP2101 PMU init succeeded, using AXP2101 PMU\n");
|
||||
LOG_INFO("AXP2101 PMU init succeeded, using AXP2101 PMU\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (!PMU) {
|
||||
PMU = new XPowersAXP192(*w);
|
||||
if (!PMU->init()) {
|
||||
DEBUG_MSG("Warning: Failed to find AXP192 power management\n");
|
||||
LOG_WARN("Failed to find AXP192 power management\n");
|
||||
delete PMU;
|
||||
PMU = NULL;
|
||||
} else {
|
||||
DEBUG_MSG("AXP192 PMU init succeeded, using AXP192 PMU\n");
|
||||
LOG_INFO("AXP192 PMU init succeeded, using AXP192 PMU\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -455,6 +478,9 @@ bool Power::axpChipInit()
|
||||
// Set constant current charging current
|
||||
PMU->setChargerConstantCurr(XPOWERS_AXP192_CHG_CUR_450MA);
|
||||
|
||||
//Set up the charging voltage
|
||||
PMU->setChargeTargetVoltage(XPOWERS_AXP192_CHG_VOL_4V2);
|
||||
|
||||
} else if (PMU->getChipModel() == XPOWERS_AXP2101) {
|
||||
|
||||
// t-beam s3 core
|
||||
@@ -507,6 +533,8 @@ bool Power::axpChipInit()
|
||||
//Set the constant current charging current of AXP2101, temporarily use 500mA by default
|
||||
PMU->setChargerConstantCurr(XPOWERS_AXP2101_CHG_CUR_500MA);
|
||||
|
||||
//Set up the charging voltage
|
||||
PMU->setChargeTargetVoltage(XPOWERS_AXP2101_CHG_VOL_4V2);
|
||||
}
|
||||
|
||||
|
||||
@@ -520,53 +548,54 @@ bool Power::axpChipInit()
|
||||
PMU->enableVbusVoltageMeasure();
|
||||
PMU->enableBattVoltageMeasure();
|
||||
|
||||
DEBUG_MSG("=======================================================================\n");
|
||||
LOG_DEBUG("=======================================================================\n");
|
||||
if (PMU->isChannelAvailable(XPOWERS_DCDC1)) {
|
||||
DEBUG_MSG("DC1 : %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_DCDC1) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_DCDC1));
|
||||
LOG_DEBUG("DC1 : %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_DCDC1) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_DCDC1));
|
||||
}
|
||||
if (PMU->isChannelAvailable(XPOWERS_DCDC2)) {
|
||||
DEBUG_MSG("DC2 : %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_DCDC2) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_DCDC2));
|
||||
LOG_DEBUG("DC2 : %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_DCDC2) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_DCDC2));
|
||||
}
|
||||
if (PMU->isChannelAvailable(XPOWERS_DCDC3)) {
|
||||
DEBUG_MSG("DC3 : %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_DCDC3) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_DCDC3));
|
||||
LOG_DEBUG("DC3 : %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_DCDC3) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_DCDC3));
|
||||
}
|
||||
if (PMU->isChannelAvailable(XPOWERS_DCDC4)) {
|
||||
DEBUG_MSG("DC4 : %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_DCDC4) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_DCDC4));
|
||||
LOG_DEBUG("DC4 : %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_DCDC4) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_DCDC4));
|
||||
}
|
||||
if (PMU->isChannelAvailable(XPOWERS_LDO2)) {
|
||||
DEBUG_MSG("LDO2 : %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_LDO2) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_LDO2));
|
||||
LOG_DEBUG("LDO2 : %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_LDO2) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_LDO2));
|
||||
}
|
||||
if (PMU->isChannelAvailable(XPOWERS_LDO3)) {
|
||||
DEBUG_MSG("LDO3 : %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_LDO3) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_LDO3));
|
||||
LOG_DEBUG("LDO3 : %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_LDO3) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_LDO3));
|
||||
}
|
||||
if (PMU->isChannelAvailable(XPOWERS_ALDO1)) {
|
||||
DEBUG_MSG("ALDO1: %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_ALDO1) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_ALDO1));
|
||||
LOG_DEBUG("ALDO1: %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_ALDO1) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_ALDO1));
|
||||
}
|
||||
if (PMU->isChannelAvailable(XPOWERS_ALDO2)) {
|
||||
DEBUG_MSG("ALDO2: %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_ALDO2) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_ALDO2));
|
||||
LOG_DEBUG("ALDO2: %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_ALDO2) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_ALDO2));
|
||||
}
|
||||
if (PMU->isChannelAvailable(XPOWERS_ALDO3)) {
|
||||
DEBUG_MSG("ALDO3: %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_ALDO3) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_ALDO3));
|
||||
LOG_DEBUG("ALDO3: %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_ALDO3) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_ALDO3));
|
||||
}
|
||||
if (PMU->isChannelAvailable(XPOWERS_ALDO4)) {
|
||||
DEBUG_MSG("ALDO4: %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_ALDO4) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_ALDO4));
|
||||
LOG_DEBUG("ALDO4: %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_ALDO4) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_ALDO4));
|
||||
}
|
||||
if (PMU->isChannelAvailable(XPOWERS_BLDO1)) {
|
||||
DEBUG_MSG("BLDO1: %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_BLDO1) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_BLDO1));
|
||||
LOG_DEBUG("BLDO1: %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_BLDO1) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_BLDO1));
|
||||
}
|
||||
if (PMU->isChannelAvailable(XPOWERS_BLDO2)) {
|
||||
DEBUG_MSG("BLDO2: %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_BLDO2) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_BLDO2));
|
||||
LOG_DEBUG("BLDO2: %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_BLDO2) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_BLDO2));
|
||||
}
|
||||
DEBUG_MSG("=======================================================================\n");
|
||||
|
||||
|
||||
//Set up the charging voltage, AXP2101/AXP192 4.2V gear is the same
|
||||
// XPOWERS_AXP192_CHG_VOL_4V2 = XPOWERS_AXP2101_CHG_VOL_4V2
|
||||
PMU->setChargeTargetVoltage(XPOWERS_AXP192_CHG_VOL_4V2);
|
||||
LOG_DEBUG("=======================================================================\n");
|
||||
|
||||
// We can safely ignore this approach for most (or all) boards because MCU turned off
|
||||
// earlier than battery discharged to 2.6V.
|
||||
//
|
||||
// Unfortanly for now we can't use this killswitch for RAK4630-based boards because they have a bug with
|
||||
// battery voltage measurement. Probably it sometimes drops to low values.
|
||||
#ifndef RAK4630
|
||||
// Set PMU shutdown voltage at 2.6V to maximize battery utilization
|
||||
PMU->setSysPowerDownVoltage(2600);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef PMU_IRQ
|
||||
|
||||
@@ -32,16 +32,16 @@ static bool isPowered()
|
||||
|
||||
static void sdsEnter()
|
||||
{
|
||||
DEBUG_MSG("Enter state: SDS\n");
|
||||
LOG_INFO("Enter state: SDS\n");
|
||||
// FIXME - make sure GPS and LORA radio are off first - because we want close to zero current draw
|
||||
doDeepSleep(config.power.sds_secs * 1000);
|
||||
doDeepSleep(getConfiguredOrDefaultMs(config.power.sds_secs));
|
||||
}
|
||||
|
||||
extern Power *power;
|
||||
|
||||
static void shutdownEnter()
|
||||
{
|
||||
DEBUG_MSG("Enter state: SHUTDOWN\n");
|
||||
LOG_INFO("Enter state: SHUTDOWN\n");
|
||||
power->shutdown();
|
||||
}
|
||||
|
||||
@@ -51,16 +51,16 @@ static uint32_t secsSlept;
|
||||
|
||||
static void lsEnter()
|
||||
{
|
||||
DEBUG_MSG("lsEnter begin, ls_secs=%u\n", config.power.ls_secs);
|
||||
LOG_INFO("lsEnter begin, ls_secs=%u\n", config.power.ls_secs);
|
||||
screen->setOn(false);
|
||||
secsSlept = 0; // How long have we been sleeping this time
|
||||
|
||||
// DEBUG_MSG("lsEnter end\n");
|
||||
// LOG_INFO("lsEnter end\n");
|
||||
}
|
||||
|
||||
static void lsIdle()
|
||||
{
|
||||
// DEBUG_MSG("lsIdle begin ls_secs=%u\n", getPref_ls_secs());
|
||||
// LOG_INFO("lsIdle begin ls_secs=%u\n", getPref_ls_secs());
|
||||
|
||||
#ifdef ARCH_ESP32
|
||||
|
||||
@@ -82,7 +82,7 @@ static void lsIdle()
|
||||
wakeCause2 = doLightSleep(1); // leave led on for 1ms
|
||||
|
||||
secsSlept += sleepTime;
|
||||
// DEBUG_MSG("sleeping, flash led!\n");
|
||||
// LOG_INFO("sleeping, flash led!\n");
|
||||
break;
|
||||
|
||||
case ESP_SLEEP_WAKEUP_UART:
|
||||
@@ -93,7 +93,7 @@ static void lsIdle()
|
||||
default:
|
||||
// We woke for some other reason (button press, device interrupt)
|
||||
// uint64_t status = esp_sleep_get_ext1_wakeup_status();
|
||||
DEBUG_MSG("wakeCause2 %d\n", wakeCause2);
|
||||
LOG_INFO("wakeCause2 %d\n", wakeCause2);
|
||||
|
||||
#ifdef BUTTON_PIN
|
||||
bool pressed = !digitalRead(BUTTON_PIN);
|
||||
@@ -117,7 +117,7 @@ static void lsIdle()
|
||||
} else {
|
||||
// Time to stop sleeping!
|
||||
setLed(false);
|
||||
DEBUG_MSG("reached ls_secs, servicing loop()\n");
|
||||
LOG_INFO("Reached ls_secs, servicing loop()\n");
|
||||
powerFSM.trigger(EVENT_WAKE_TIMER);
|
||||
}
|
||||
#endif
|
||||
@@ -125,7 +125,7 @@ static void lsIdle()
|
||||
|
||||
static void lsExit()
|
||||
{
|
||||
DEBUG_MSG("Exit state: LS\n");
|
||||
LOG_INFO("Exit state: LS\n");
|
||||
// setGPSPower(true); // restore GPS power
|
||||
if (gps)
|
||||
gps->forceWake(true);
|
||||
@@ -133,7 +133,7 @@ static void lsExit()
|
||||
|
||||
static void nbEnter()
|
||||
{
|
||||
DEBUG_MSG("Enter state: NB\n");
|
||||
LOG_INFO("Enter state: NB\n");
|
||||
screen->setOn(false);
|
||||
setBluetoothEnable(false);
|
||||
|
||||
@@ -148,7 +148,7 @@ static void darkEnter()
|
||||
|
||||
static void serialEnter()
|
||||
{
|
||||
DEBUG_MSG("Enter state: SERIAL\n");
|
||||
LOG_INFO("Enter state: SERIAL\n");
|
||||
setBluetoothEnable(false);
|
||||
screen->setOn(true);
|
||||
screen->print("Serial connected\n");
|
||||
@@ -161,10 +161,10 @@ static void serialExit()
|
||||
|
||||
static void powerEnter()
|
||||
{
|
||||
DEBUG_MSG("Enter state: POWER\n");
|
||||
LOG_INFO("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
|
||||
DEBUG_MSG("Loss of power in Powered\n");
|
||||
LOG_INFO("Loss of power in Powered\n");
|
||||
powerFSM.trigger(EVENT_POWER_DISCONNECTED);
|
||||
} else {
|
||||
screen->setOn(true);
|
||||
@@ -177,7 +177,7 @@ static void powerIdle()
|
||||
{
|
||||
if (!isPowered()) {
|
||||
// If we got here, we are in the wrong state
|
||||
DEBUG_MSG("Loss of power in Powered\n");
|
||||
LOG_INFO("Loss of power in Powered\n");
|
||||
powerFSM.trigger(EVENT_POWER_DISCONNECTED);
|
||||
}
|
||||
}
|
||||
@@ -191,7 +191,7 @@ static void powerExit()
|
||||
|
||||
static void onEnter()
|
||||
{
|
||||
DEBUG_MSG("Enter state: ON\n");
|
||||
LOG_INFO("Enter state: ON\n");
|
||||
screen->setOn(true);
|
||||
setBluetoothEnable(true);
|
||||
|
||||
@@ -221,7 +221,7 @@ static void screenPress()
|
||||
|
||||
static void bootEnter()
|
||||
{
|
||||
DEBUG_MSG("Enter state: BOOT\n");
|
||||
LOG_INFO("Enter state: BOOT\n");
|
||||
}
|
||||
|
||||
State stateSHUTDOWN(shutdownEnter, NULL, NULL, "SHUTDOWN");
|
||||
@@ -240,7 +240,7 @@ void PowerFSM_setup()
|
||||
bool isRouter = (config.device.role == Config_DeviceConfig_Role_ROUTER ? 1 : 0);
|
||||
bool hasPower = isPowered();
|
||||
|
||||
DEBUG_MSG("PowerFSM init, USB power=%d\n", hasPower ? 1 : 0);
|
||||
LOG_INFO("PowerFSM init, USB power=%d\n", hasPower ? 1 : 0);
|
||||
powerFSM.add_timed_transition(&stateBOOT, hasPower ? &statePOWER : &stateON, 3 * 1000, NULL, "boot timeout");
|
||||
|
||||
// wake timer expired or a packet arrived
|
||||
@@ -324,17 +324,10 @@ void PowerFSM_setup()
|
||||
|
||||
powerFSM.add_transition(&stateDARK, &stateDARK, EVENT_CONTACT_FROM_PHONE, NULL, "Contact from phone");
|
||||
|
||||
// each time we get a new update packet make sure we are staying in the ON state so the screen stays awake (also we don't
|
||||
// shutdown bluetooth if is_router)
|
||||
powerFSM.add_transition(&stateDARK, &stateON, EVENT_FIRMWARE_UPDATE, NULL, "Got firmware update");
|
||||
powerFSM.add_transition(&stateON, &stateON, EVENT_FIRMWARE_UPDATE, NULL, "Got firmware update");
|
||||
|
||||
powerFSM.add_timed_transition(&stateON, &stateDARK, getConfiguredOrDefaultMs(config.display.screen_on_secs, default_screen_on_secs), NULL, "Screen-on timeout");
|
||||
|
||||
// On most boards we use light-sleep to be our main state, but on NRF52 we just stay in DARK
|
||||
State *lowPowerState = &stateLS;
|
||||
|
||||
#ifdef ARCH_ESP32
|
||||
State *lowPowerState = &stateLS;
|
||||
// We never enter light-sleep or NB states on NRF52 (because the CPU uses so little power normally)
|
||||
|
||||
// See: https://github.com/meshtastic/firmware/issues/1071
|
||||
@@ -343,12 +336,10 @@ void PowerFSM_setup()
|
||||
powerFSM.add_timed_transition(&stateDARK, &stateLS, getConfiguredOrDefaultMs(config.power.wait_bluetooth_secs, default_wait_bluetooth_secs), NULL, "Bluetooth timeout");
|
||||
}
|
||||
|
||||
#elif defined (ARCH_NRF52)
|
||||
lowPowerState = &stateDARK;
|
||||
if (config.power.sds_secs != UINT32_MAX)
|
||||
powerFSM.add_timed_transition(lowPowerState, &stateSDS, getConfiguredOrDefaultMs(config.power.sds_secs), NULL, "mesh timeout");
|
||||
#endif
|
||||
|
||||
if (config.power.sds_secs != UINT32_MAX)
|
||||
powerFSM.add_timed_transition(lowPowerState, &stateSDS, config.power.sds_secs * 1000, NULL, "mesh timeout");
|
||||
|
||||
powerFSM.run_machine(); // run one interation of the state machine, so we run our on enter tasks for the initial DARK state
|
||||
}
|
||||
|
||||
@@ -27,10 +27,8 @@ class PowerFSMThread : public OSThread
|
||||
if (powerStatus->getHasUSB()) {
|
||||
timeLastPowered = millis();
|
||||
} else if (config.power.on_battery_shutdown_after_secs > 0 &&
|
||||
millis() >
|
||||
timeLastPowered +
|
||||
(1000 *
|
||||
config.power.on_battery_shutdown_after_secs)) { // shutdown after 30 minutes unpowered
|
||||
config.power.on_battery_shutdown_after_secs != UINT32_MAX &&
|
||||
millis() > (timeLastPowered + getConfiguredOrDefaultMs(config.power.on_battery_shutdown_after_secs))) { // shutdown after 30 minutes unpowered
|
||||
powerFSM.trigger(EVENT_SHUTDOWN);
|
||||
}
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ class PowerStatus : public Status
|
||||
isCharging = newStatus->isCharging;
|
||||
}
|
||||
if (isDirty) {
|
||||
// DEBUG_MSG("Battery %dmV %d%%\n", batteryVoltageMv, batteryChargePercent);
|
||||
// LOG_DEBUG("Battery %dmV %d%%\n", batteryVoltageMv, batteryChargePercent);
|
||||
onNewStatus.notifyObservers(this);
|
||||
}
|
||||
return 0;
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include "RTC.h"
|
||||
#include "NodeDB.h"
|
||||
#include "concurrency/OSThread.h"
|
||||
// #include "wifi/WiFiServerAPI.h"
|
||||
#include <assert.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
@@ -27,10 +26,6 @@ size_t RedirectablePrint::write(uint8_t c)
|
||||
SEGGER_RTT_PutChar(SEGGER_STDOUT_CH, c);
|
||||
#endif
|
||||
|
||||
// FIXME - clean this up, the whole relationship of this class to SerialConsole to TCP/bluetooth debug log output is kinda messed up. But for now, just have this hack to
|
||||
// optionally send chars to TCP also
|
||||
//WiFiServerPort::debugOut(c);
|
||||
|
||||
if (!config.has_lora || config.device.serial_enabled)
|
||||
dest->write(c);
|
||||
|
||||
@@ -58,7 +53,7 @@ size_t RedirectablePrint::vprintf(const char *format, va_list arg)
|
||||
return len;
|
||||
}
|
||||
|
||||
size_t RedirectablePrint::logDebug(const char *format, ...)
|
||||
size_t RedirectablePrint::log(const char *logLevel, const char *format, ...)
|
||||
{
|
||||
size_t r = 0;
|
||||
|
||||
@@ -86,9 +81,9 @@ size_t RedirectablePrint::logDebug(const char *format, ...)
|
||||
int min = (hms % SEC_PER_HOUR) / SEC_PER_MIN;
|
||||
int sec = (hms % SEC_PER_HOUR) % SEC_PER_MIN; // or hms % SEC_PER_MIN
|
||||
|
||||
r += printf("%02d:%02d:%02d %u ", hour, min, sec, millis() / 1000);
|
||||
r += printf("%s | %02d:%02d:%02d %u ", logLevel, hour, min, sec, millis() / 1000);
|
||||
} else
|
||||
r += printf("??:??:?? %u ", millis() / 1000);
|
||||
r += printf("%s | ??:??:?? %u ", logLevel, millis() / 1000);
|
||||
|
||||
auto thread = concurrency::OSThread::currentThread;
|
||||
if (thread) {
|
||||
@@ -99,7 +94,6 @@ size_t RedirectablePrint::logDebug(const char *format, ...)
|
||||
print("] ");
|
||||
}
|
||||
}
|
||||
|
||||
r += vprintf(format, arg);
|
||||
va_end(arg);
|
||||
|
||||
@@ -109,3 +103,31 @@ size_t RedirectablePrint::logDebug(const char *format, ...)
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void RedirectablePrint::hexDump(const char *logLevel, unsigned char *buf, uint16_t len) {
|
||||
const char alphabet[17] = "0123456789abcdef";
|
||||
log(logLevel, " +------------------------------------------------+ +----------------+\n");
|
||||
log(logLevel, " |.0 .1 .2 .3 .4 .5 .6 .7 .8 .9 .a .b .c .d .e .f | | ASCII |\n");
|
||||
for (uint16_t i = 0; i < len; i += 16) {
|
||||
if (i % 128 == 0)
|
||||
log(logLevel, " +------------------------------------------------+ +----------------+\n");
|
||||
char s[] = "| | | |\n";
|
||||
uint8_t ix = 1, iy = 52;
|
||||
for (uint8_t j = 0; j < 16; j++) {
|
||||
if (i + j < len) {
|
||||
uint8_t c = buf[i + j];
|
||||
s[ix++] = alphabet[(c >> 4) & 0x0F];
|
||||
s[ix++] = alphabet[c & 0x0F];
|
||||
ix++;
|
||||
if (c > 31 && c < 128) s[iy++] = c;
|
||||
else s[iy++] = '.';
|
||||
}
|
||||
}
|
||||
uint8_t index = i / 16;
|
||||
if (i < 256) log(logLevel, " ");
|
||||
log(logLevel, "%02x",index);
|
||||
log(logLevel, ".");
|
||||
log(logLevel, s);
|
||||
}
|
||||
log(logLevel, " +------------------------------------------------+ +----------------+\n");
|
||||
}
|
||||
|
||||
@@ -33,14 +33,13 @@ class RedirectablePrint : public Print
|
||||
* If the provide format string ends with a newline we assume it is the final print of a single
|
||||
* log message. Otherwise we assume more prints will come before the log message ends. This
|
||||
* allows you to call logDebug a few times to build up a single log message line if you wish.
|
||||
*
|
||||
* FIXME, eventually add log levels (INFO, WARN, ERROR) and subsystems. Move into
|
||||
* a different class.
|
||||
*/
|
||||
size_t logDebug(const char * format, ...) __attribute__ ((format (printf, 2, 3)));
|
||||
size_t log(const char *logLevel, const char *format, ...) __attribute__ ((format (printf, 3, 4)));
|
||||
|
||||
/** like printf but va_list based */
|
||||
size_t vprintf(const char *format, va_list arg);
|
||||
|
||||
void hexDump(const char *logLevel, unsigned char *buf, uint16_t len);
|
||||
};
|
||||
|
||||
class NoopPrint : public Print
|
||||
|
||||
@@ -20,12 +20,10 @@ void consolePrintf(const char *format, ...)
|
||||
va_start(arg, format);
|
||||
console->vprintf(format, arg);
|
||||
va_end(arg);
|
||||
#ifdef ARCH_ESP32
|
||||
console->flush();
|
||||
#endif
|
||||
}
|
||||
|
||||
SerialConsole::SerialConsole() : StreamAPI(&Port), RedirectablePrint(&Port)
|
||||
SerialConsole::SerialConsole() : StreamAPI(&Port), RedirectablePrint(&Port), concurrency::OSThread("SerialConsole")
|
||||
{
|
||||
assert(!console);
|
||||
console = this;
|
||||
@@ -33,7 +31,7 @@ SerialConsole::SerialConsole() : StreamAPI(&Port), RedirectablePrint(&Port)
|
||||
// setDestination(&noopPrint); for testing, try turning off 'all' debug output and see what leaks
|
||||
|
||||
Port.begin(SERIAL_BAUD);
|
||||
#ifdef ARCH_NRF52
|
||||
#if defined(ARCH_NRF52) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||
time_t timeout = millis();
|
||||
while (!Port) {
|
||||
if ((millis() - timeout) < 5000) {
|
||||
@@ -46,6 +44,14 @@ SerialConsole::SerialConsole() : StreamAPI(&Port), RedirectablePrint(&Port)
|
||||
emitRebooted();
|
||||
}
|
||||
|
||||
int32_t SerialConsole::runOnce()
|
||||
{
|
||||
return runOncePart();
|
||||
}
|
||||
|
||||
void SerialConsole::flush() {
|
||||
Port.flush();
|
||||
}
|
||||
|
||||
// For the serial port we can't really detect if any client is on the other side, so instead just look for recent messages
|
||||
bool SerialConsole::checkIsConnected()
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* Provides both debug printing and, if the client starts sending protobufs to us, switches to send/receive protobufs
|
||||
* (and starts dropping debug printing - FIXME, eventually those prints should be encapsulated in protobufs).
|
||||
*/
|
||||
class SerialConsole : public StreamAPI, public RedirectablePrint
|
||||
class SerialConsole : public StreamAPI, public RedirectablePrint, private concurrency::OSThread
|
||||
{
|
||||
public:
|
||||
SerialConsole();
|
||||
@@ -24,6 +24,10 @@ class SerialConsole : public StreamAPI, public RedirectablePrint
|
||||
return RedirectablePrint::write(c);
|
||||
}
|
||||
|
||||
virtual int32_t runOnce() override;
|
||||
|
||||
void flush();
|
||||
|
||||
protected:
|
||||
|
||||
/// Check the current underlying physical link to see if the client is currently connected
|
||||
|
||||
@@ -10,18 +10,18 @@ void AirTime::logAirtime(reportTypes reportType, uint32_t airtime_ms)
|
||||
{
|
||||
|
||||
if (reportType == TX_LOG) {
|
||||
DEBUG_MSG("AirTime - Packet transmitted : %ums\n", airtime_ms);
|
||||
LOG_DEBUG("AirTime - Packet transmitted : %ums\n", airtime_ms);
|
||||
this->airtimes.periodTX[0] = this->airtimes.periodTX[0] + airtime_ms;
|
||||
myNodeInfo.air_period_tx[0] = myNodeInfo.air_period_tx[0] + airtime_ms;
|
||||
|
||||
this->utilizationTX[this->getPeriodUtilHour()] = this->utilizationTX[this->getPeriodUtilHour()] + airtime_ms;
|
||||
|
||||
} else if (reportType == RX_LOG) {
|
||||
DEBUG_MSG("AirTime - Packet received : %ums\n", airtime_ms);
|
||||
LOG_DEBUG("AirTime - Packet received : %ums\n", airtime_ms);
|
||||
this->airtimes.periodRX[0] = this->airtimes.periodRX[0] + airtime_ms;
|
||||
myNodeInfo.air_period_rx[0] = myNodeInfo.air_period_rx[0] + airtime_ms;
|
||||
} else if (reportType == RX_ALL_LOG) {
|
||||
DEBUG_MSG("AirTime - Packet received (noise?) : %ums\n", airtime_ms);
|
||||
LOG_DEBUG("AirTime - Packet received (noise?) : %ums\n", airtime_ms);
|
||||
this->airtimes.periodRX_ALL[0] = this->airtimes.periodRX_ALL[0] + airtime_ms;
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ void AirTime::airtimeRotatePeriod()
|
||||
{
|
||||
|
||||
if (this->airtimes.lastPeriodIndex != this->currentPeriodIndex()) {
|
||||
DEBUG_MSG("Rotating airtimes to a new period = %u\n", this->currentPeriodIndex());
|
||||
LOG_DEBUG("Rotating airtimes to a new period = %u\n", this->currentPeriodIndex());
|
||||
|
||||
for (int i = PERIODS_TO_LOG - 2; i >= 0; --i) {
|
||||
this->airtimes.periodTX[i + 1] = this->airtimes.periodTX[i];
|
||||
@@ -101,7 +101,7 @@ float AirTime::channelUtilizationPercent()
|
||||
uint32_t sum = 0;
|
||||
for (uint32_t i = 0; i < CHANNEL_UTILIZATION_PERIODS; i++) {
|
||||
sum += this->channelUtilization[i];
|
||||
// DEBUG_MSG("ChanUtilArray %u %u\n", i, this->channelUtilization[i]);
|
||||
// LOG_DEBUG("ChanUtilArray %u %u\n", i, this->channelUtilization[i]);
|
||||
}
|
||||
|
||||
return (float(sum) / float(CHANNEL_UTILIZATION_PERIODS * 10 * 1000)) * 100;
|
||||
@@ -117,6 +117,45 @@ float AirTime::utilizationTXPercent()
|
||||
return (float(sum) / float(MS_IN_HOUR)) * 100;
|
||||
}
|
||||
|
||||
bool AirTime::isTxAllowedChannelUtil(bool polite)
|
||||
{
|
||||
uint8_t percentage = (polite ? polite_channel_util_percent : max_channel_util_percent);
|
||||
if (channelUtilizationPercent() < percentage) {
|
||||
return true;
|
||||
} else {
|
||||
LOG_WARN("Channel utilization is >%d percent. Skipping this opportunity to send.\n", percentage);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool AirTime::isTxAllowedAirUtil()
|
||||
{
|
||||
if (!config.lora.override_duty_cycle && myRegion->dutyCycle < 100) {
|
||||
if (utilizationTXPercent() < myRegion->dutyCycle * polite_duty_cycle_percent / 100) {
|
||||
return true;
|
||||
} else {
|
||||
LOG_WARN("Tx air utilization is >%d percent. Skipping this opportunity to send.\n", myRegion->dutyCycle * polite_duty_cycle_percent / 100);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get the amount of minutes we have to be silent before we can send again
|
||||
uint8_t AirTime::getSilentMinutes(float txPercent, float dutyCycle)
|
||||
{
|
||||
float newTxPercent = txPercent;
|
||||
for (int8_t i = MINUTES_IN_HOUR-1; i >= 0; --i) {
|
||||
newTxPercent -= ((float)this->utilizationTX[i] / (MS_IN_MINUTE * MINUTES_IN_HOUR / 100));
|
||||
if (newTxPercent < dutyCycle)
|
||||
return MINUTES_IN_HOUR-1-i;
|
||||
}
|
||||
|
||||
return MINUTES_IN_HOUR;
|
||||
}
|
||||
|
||||
|
||||
AirTime::AirTime() : concurrency::OSThread("AirTime"),airtimes({}) {
|
||||
}
|
||||
|
||||
@@ -175,13 +214,13 @@ int32_t AirTime::runOnce()
|
||||
myNodeInfo.air_util_tx = airTime->utilizationTXPercent();
|
||||
}
|
||||
/*
|
||||
DEBUG_MSG("utilPeriodTX %d TX Airtime %3.2f%\n", utilPeriodTX, airTime->utilizationTXPercent());
|
||||
LOG_DEBUG("utilPeriodTX %d TX Airtime %3.2f%\n", utilPeriodTX, airTime->utilizationTXPercent());
|
||||
for (uint32_t i = 0; i < MINUTES_IN_HOUR; i++) {
|
||||
DEBUG_MSG(
|
||||
LOG_DEBUG(
|
||||
"%d,", this->utilizationTX[i]
|
||||
);
|
||||
}
|
||||
DEBUG_MSG("\n");
|
||||
LOG_DEBUG("\n");
|
||||
*/
|
||||
return (1000 * 1);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "configuration.h"
|
||||
#include <Arduino.h>
|
||||
#include <functional>
|
||||
#include "MeshRadio.h"
|
||||
|
||||
/*
|
||||
TX_LOG - Time on air this device has transmitted
|
||||
@@ -29,6 +30,7 @@
|
||||
#define PERIODS_TO_LOG 8
|
||||
#define MINUTES_IN_HOUR 60
|
||||
#define SECONDS_IN_MINUTE 60
|
||||
#define MS_IN_MINUTE (SECONDS_IN_MINUTE * 1000)
|
||||
#define MS_IN_HOUR (MINUTES_IN_HOUR * SECONDS_IN_MINUTE * 1000)
|
||||
|
||||
|
||||
@@ -57,12 +59,18 @@ class AirTime : private concurrency::OSThread
|
||||
uint32_t getSecondsPerPeriod();
|
||||
uint32_t getSecondsSinceBoot();
|
||||
uint32_t *airtimeReport(reportTypes reportType);
|
||||
uint8_t getSilentMinutes(float txPercent, float dutyCycle);
|
||||
bool isTxAllowedChannelUtil(bool polite=false);
|
||||
bool isTxAllowedAirUtil();
|
||||
|
||||
private:
|
||||
bool firstTime = true;
|
||||
uint8_t lastUtilPeriod = 0;
|
||||
uint8_t lastUtilPeriodTX = 0;
|
||||
uint32_t secSinceBoot = 0;
|
||||
uint8_t max_channel_util_percent = 40;
|
||||
uint8_t polite_channel_util_percent = 25;
|
||||
uint8_t polite_duty_cycle_percent = 50; // half of Duty Cycle allowance is ok for metadata
|
||||
|
||||
struct airtimeStruct {
|
||||
uint32_t periodTX[PERIODS_TO_LOG]; // AirTime transmitted
|
||||
|
||||
@@ -13,12 +13,12 @@ InterruptableDelay::~InterruptableDelay() {}
|
||||
*/
|
||||
bool InterruptableDelay::delay(uint32_t msec)
|
||||
{
|
||||
// DEBUG_MSG("delay %u ", msec);
|
||||
// LOG_DEBUG("delay %u ", msec);
|
||||
|
||||
// sem take will return false if we timed out (i.e. were not interrupted)
|
||||
bool r = semaphore.take(msec);
|
||||
|
||||
// DEBUG_MSG("interrupt=%d\n", r);
|
||||
// LOG_DEBUG("interrupt=%d\n", r);
|
||||
return !r;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include "configuration.h"
|
||||
#include "NotifiedWorkerThread.h"
|
||||
#include "main.h"
|
||||
#include <assert.h>
|
||||
|
||||
namespace concurrency
|
||||
{
|
||||
@@ -33,11 +32,11 @@ IRAM_ATTR bool NotifiedWorkerThread::notifyCommon(uint32_t v, bool overwrite)
|
||||
|
||||
notification = v;
|
||||
if (debugNotification)
|
||||
DEBUG_MSG("setting notification %d\n", v);
|
||||
LOG_DEBUG("setting notification %d\n", v);
|
||||
return true;
|
||||
} else {
|
||||
if (debugNotification)
|
||||
DEBUG_MSG("dropping notification %d\n", v);
|
||||
LOG_DEBUG("dropping notification %d\n", v);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -66,7 +65,7 @@ bool NotifiedWorkerThread::notifyLater(uint32_t delay, uint32_t v, bool overwrit
|
||||
if (didIt) { // If we didn't already have something queued, override the delay to be larger
|
||||
setIntervalFromNow(delay); // a new version of setInterval relative to the current time
|
||||
if (debugNotification)
|
||||
DEBUG_MSG("delaying notification %u\n", delay);
|
||||
LOG_DEBUG("delaying notification %u\n", delay);
|
||||
}
|
||||
|
||||
return didIt;
|
||||
|
||||
@@ -61,21 +61,31 @@ bool OSThread::shouldRun(unsigned long time)
|
||||
bool r = Thread::shouldRun(time);
|
||||
|
||||
if (showRun && r)
|
||||
DEBUG_MSG("Thread %s: run\n", ThreadName.c_str());
|
||||
LOG_DEBUG("Thread %s: run\n", ThreadName.c_str());
|
||||
|
||||
if (showWaiting && enabled && !r)
|
||||
DEBUG_MSG("Thread %s: wait %lu\n", ThreadName.c_str(), interval);
|
||||
LOG_DEBUG("Thread %s: wait %lu\n", ThreadName.c_str(), interval);
|
||||
|
||||
if (showDisabled && !enabled)
|
||||
DEBUG_MSG("Thread %s: disabled\n", ThreadName.c_str());
|
||||
LOG_DEBUG("Thread %s: disabled\n", ThreadName.c_str());
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void OSThread::run()
|
||||
{
|
||||
#ifdef DEBUG_HEAP
|
||||
auto heap = ESP.getFreeHeap();
|
||||
#endif
|
||||
currentThread = this;
|
||||
auto newDelay = runOnce();
|
||||
#ifdef DEBUG_HEAP
|
||||
auto newHeap = ESP.getFreeHeap();
|
||||
if (newHeap < heap)
|
||||
LOG_DEBUG("------ Thread %s leaked heap %d -> %d (%d) ------\n", ThreadName.c_str(), heap, newHeap, newHeap - heap);
|
||||
if (heap < newHeap)
|
||||
LOG_DEBUG("++++++ Thread %s freed heap %d -> %d (%d) ++++++\n", ThreadName.c_str(), heap, newHeap, newHeap - heap);
|
||||
#endif
|
||||
|
||||
runned();
|
||||
|
||||
@@ -85,6 +95,14 @@ void OSThread::run()
|
||||
currentThread = NULL;
|
||||
}
|
||||
|
||||
int32_t OSThread::disable()
|
||||
{
|
||||
enabled = false;
|
||||
setInterval(INT32_MAX);
|
||||
|
||||
return INT32_MAX;
|
||||
}
|
||||
|
||||
/**
|
||||
* This flag is set **only** when setup() starts, to provide a way for us to check for sloppy static constructor calls.
|
||||
* Call assertIsSetup() to force a crash if someone tries to create an instance too early.
|
||||
|
||||
@@ -53,6 +53,8 @@ class OSThread : public Thread
|
||||
|
||||
static void setup();
|
||||
|
||||
int32_t disable();
|
||||
|
||||
/**
|
||||
* Wait a specified number msecs starting from the current time (rather than the last time we were run)
|
||||
*/
|
||||
|
||||
@@ -114,6 +114,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#define SHTC3_ADDR 0x70
|
||||
#define LPS22HB_ADDR 0x5C
|
||||
#define LPS22HB_ADDR_ALT 0x5D
|
||||
#define SHT31_ADDR 0x44
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Security
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
uint32_t axpDebugRead()
|
||||
{
|
||||
axp.debugCharging();
|
||||
DEBUG_MSG("vbus current %f\n", axp.getVbusCurrent());
|
||||
DEBUG_MSG("charge current %f\n", axp.getBattChargeCurrent());
|
||||
DEBUG_MSG("bat voltage %f\n", axp.getBattVoltage());
|
||||
DEBUG_MSG("batt pct %d\n", axp.getBattPercentage());
|
||||
DEBUG_MSG("is battery connected %d\n", axp.isBatteryConnect());
|
||||
DEBUG_MSG("is USB connected %d\n", axp.isVBUSPlug());
|
||||
DEBUG_MSG("is charging %d\n", axp.isChargeing());
|
||||
LOG_DEBUG("vbus current %f\n", axp.getVbusCurrent());
|
||||
LOG_DEBUG("charge current %f\n", axp.getBattChargeCurrent());
|
||||
LOG_DEBUG("bat voltage %f\n", axp.getBattVoltage());
|
||||
LOG_DEBUG("batt pct %d\n", axp.getBattPercentage());
|
||||
LOG_DEBUG("is battery connected %d\n", axp.isBatteryConnect());
|
||||
LOG_DEBUG("is USB connected %d\n", axp.isVBUSPlug());
|
||||
LOG_DEBUG("is charging %d\n", axp.isChargeing());
|
||||
|
||||
return 30 * 1000;
|
||||
}
|
||||
|
||||
@@ -52,9 +52,9 @@ void scanEInkDevice(void)
|
||||
d_writeCommand(0x20);
|
||||
eink_found = (d_waitWhileBusy(150) > 0) ? true : false;
|
||||
if(eink_found)
|
||||
DEBUG_MSG("EInk display found\n");
|
||||
LOG_DEBUG("EInk display found\n");
|
||||
else
|
||||
DEBUG_MSG("EInk display not found\n");
|
||||
LOG_DEBUG("EInk display not found\n");
|
||||
SPI1.end();
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -15,30 +15,30 @@ void printATECCInfo()
|
||||
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
|
||||
atecc.readConfigZone(false);
|
||||
|
||||
DEBUG_MSG("ATECC608B Serial Number: ");
|
||||
LOG_DEBUG("ATECC608B Serial Number: ");
|
||||
for (int i = 0 ; i < 9 ; i++) {
|
||||
DEBUG_MSG("%02x",atecc.serialNumber[i]);
|
||||
LOG_DEBUG("%02x",atecc.serialNumber[i]);
|
||||
}
|
||||
|
||||
DEBUG_MSG(", Rev Number: ");
|
||||
LOG_DEBUG(", Rev Number: ");
|
||||
for (int i = 0 ; i < 4 ; i++) {
|
||||
DEBUG_MSG("%02x",atecc.revisionNumber[i]);
|
||||
LOG_DEBUG("%02x",atecc.revisionNumber[i]);
|
||||
}
|
||||
DEBUG_MSG("\n");
|
||||
LOG_DEBUG("\n");
|
||||
|
||||
DEBUG_MSG("ATECC608B Config %s",atecc.configLockStatus ? "Locked" : "Unlocked");
|
||||
DEBUG_MSG(", Data %s",atecc.dataOTPLockStatus ? "Locked" : "Unlocked");
|
||||
DEBUG_MSG(", Slot 0 %s\n",atecc.slot0LockStatus ? "Locked" : "Unlocked");
|
||||
LOG_DEBUG("ATECC608B Config %s",atecc.configLockStatus ? "Locked" : "Unlocked");
|
||||
LOG_DEBUG(", Data %s",atecc.dataOTPLockStatus ? "Locked" : "Unlocked");
|
||||
LOG_DEBUG(", Slot 0 %s\n",atecc.slot0LockStatus ? "Locked" : "Unlocked");
|
||||
|
||||
if (atecc.configLockStatus && atecc.dataOTPLockStatus && atecc.slot0LockStatus) {
|
||||
if (atecc.generatePublicKey() == false) {
|
||||
DEBUG_MSG("ATECC608B Error generating public key\n");
|
||||
LOG_DEBUG("ATECC608B Error generating public key\n");
|
||||
} else {
|
||||
DEBUG_MSG("ATECC608B Public Key: ");
|
||||
LOG_DEBUG("ATECC608B Public Key: ");
|
||||
for (int i = 0 ; i < 64 ; i++) {
|
||||
DEBUG_MSG("%02x",atecc.publicKey64Bytes[i]);
|
||||
LOG_DEBUG("%02x",atecc.publicKey64Bytes[i]);
|
||||
}
|
||||
DEBUG_MSG("\n");
|
||||
LOG_DEBUG("\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -51,7 +51,7 @@ uint16_t getRegisterValue(uint8_t address, uint8_t reg, uint8_t length) {
|
||||
Wire.endTransmission();
|
||||
delay(20);
|
||||
Wire.requestFrom(address, length);
|
||||
DEBUG_MSG("Wire.available() = %d\n", Wire.available());
|
||||
LOG_DEBUG("Wire.available() = %d\n", Wire.available());
|
||||
if (Wire.available() == 2) {
|
||||
// Read MSB, then LSB
|
||||
value = (uint16_t)Wire.read() << 8;
|
||||
@@ -86,7 +86,7 @@ uint8_t oled_probe(byte addr)
|
||||
}
|
||||
c++;
|
||||
} while ((r != r_prev) && (c < 4));
|
||||
DEBUG_MSG("0x%x subtype probed in %i tries \n", r, c);
|
||||
LOG_DEBUG("0x%x subtype probed in %i tries \n", r, c);
|
||||
return o_probe;
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ void scanI2Cdevice()
|
||||
Wire.beginTransmission(addr);
|
||||
err = Wire.endTransmission();
|
||||
if (err == 0) {
|
||||
DEBUG_MSG("I2C device found at address 0x%x\n", addr);
|
||||
LOG_DEBUG("I2C device found at address 0x%x\n", addr);
|
||||
|
||||
nDevices++;
|
||||
|
||||
@@ -107,20 +107,20 @@ void scanI2Cdevice()
|
||||
screen_found = addr;
|
||||
screen_model = oled_probe(addr);
|
||||
if (screen_model == 1) {
|
||||
DEBUG_MSG("ssd1306 display found\n");
|
||||
LOG_INFO("ssd1306 display found\n");
|
||||
} else if (screen_model == 2) {
|
||||
DEBUG_MSG("sh1106 display found\n");
|
||||
LOG_INFO("sh1106 display found\n");
|
||||
} else {
|
||||
DEBUG_MSG("unknown display found\n");
|
||||
LOG_INFO("unknown display found\n");
|
||||
}
|
||||
}
|
||||
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
|
||||
if (addr == ATECC608B_ADDR) {
|
||||
keystore_found = addr;
|
||||
if (atecc.begin(keystore_found) == true) {
|
||||
DEBUG_MSG("ATECC608B initialized\n");
|
||||
LOG_INFO("ATECC608B initialized\n");
|
||||
} else {
|
||||
DEBUG_MSG("ATECC608B initialization failed\n");
|
||||
LOG_WARN("ATECC608B initialization failed\n");
|
||||
}
|
||||
printATECCInfo();
|
||||
}
|
||||
@@ -128,7 +128,7 @@ void scanI2Cdevice()
|
||||
#ifdef RV3028_RTC
|
||||
if (addr == RV3028_RTC){
|
||||
rtc_found = addr;
|
||||
DEBUG_MSG("RV3028 RTC found\n");
|
||||
LOG_INFO("RV3028 RTC found\n");
|
||||
Melopero_RV3028 rtc;
|
||||
rtc.initI2C();
|
||||
rtc.writeToRegister(0x35,0x07); // no Clkout
|
||||
@@ -138,7 +138,7 @@ void scanI2Cdevice()
|
||||
#ifdef PCF8563_RTC
|
||||
if (addr == PCF8563_RTC){
|
||||
rtc_found = addr;
|
||||
DEBUG_MSG("PCF8563 RTC found\n");
|
||||
LOG_INFO("PCF8563 RTC found\n");
|
||||
}
|
||||
#endif
|
||||
if (addr == CARDKB_ADDR) {
|
||||
@@ -146,82 +146,86 @@ void scanI2Cdevice()
|
||||
// Do we have the RAK14006 instead?
|
||||
registerValue = getRegisterValue(addr, 0x04, 1);
|
||||
if (registerValue == 0x02) { // KEYPAD_VERSION
|
||||
DEBUG_MSG("RAK14004 found\n");
|
||||
LOG_INFO("RAK14004 found\n");
|
||||
kb_model = 0x02;
|
||||
} else {
|
||||
DEBUG_MSG("m5 cardKB found\n");
|
||||
LOG_INFO("m5 cardKB found\n");
|
||||
kb_model = 0x00;
|
||||
}
|
||||
}
|
||||
if (addr == ST7567_ADDRESS) {
|
||||
screen_found = addr;
|
||||
DEBUG_MSG("st7567 display found\n");
|
||||
LOG_INFO("st7567 display found\n");
|
||||
}
|
||||
#ifdef HAS_PMU
|
||||
if (addr == XPOWERS_AXP192_AXP2101_ADDRESS) {
|
||||
pmu_found = true;
|
||||
DEBUG_MSG("axp192/axp2101 PMU found\n");
|
||||
LOG_INFO("axp192/axp2101 PMU found\n");
|
||||
}
|
||||
#endif
|
||||
if (addr == BME_ADDR || addr == BME_ADDR_ALTERNATE) {
|
||||
registerValue = getRegisterValue(addr, 0xD0, 1); // GET_ID
|
||||
if (registerValue == 0x61) {
|
||||
DEBUG_MSG("BME-680 sensor found at address 0x%x\n", (uint8_t)addr);
|
||||
LOG_INFO("BME-680 sensor found at address 0x%x\n", (uint8_t)addr);
|
||||
nodeTelemetrySensorsMap[TelemetrySensorType_BME680] = addr;
|
||||
} else if (registerValue == 0x60) {
|
||||
DEBUG_MSG("BME-280 sensor found at address 0x%x\n", (uint8_t)addr);
|
||||
LOG_INFO("BME-280 sensor found at address 0x%x\n", (uint8_t)addr);
|
||||
nodeTelemetrySensorsMap[TelemetrySensorType_BME280] = addr;
|
||||
} else {
|
||||
DEBUG_MSG("BMP-280 sensor found at address 0x%x\n", (uint8_t)addr);
|
||||
LOG_INFO("BMP-280 sensor found at address 0x%x\n", (uint8_t)addr);
|
||||
nodeTelemetrySensorsMap[TelemetrySensorType_BMP280] = addr;
|
||||
}
|
||||
}
|
||||
if (addr == INA_ADDR || addr == INA_ADDR_ALTERNATE) {
|
||||
registerValue = getRegisterValue(addr, 0xFE, 2);
|
||||
DEBUG_MSG("Register MFG_UID: 0x%x\n", registerValue);
|
||||
LOG_DEBUG("Register MFG_UID: 0x%x\n", registerValue);
|
||||
if (registerValue == 0x5449) {
|
||||
DEBUG_MSG("INA260 sensor found at address 0x%x\n", (uint8_t)addr);
|
||||
LOG_INFO("INA260 sensor found at address 0x%x\n", (uint8_t)addr);
|
||||
nodeTelemetrySensorsMap[TelemetrySensorType_INA260] = addr;
|
||||
} else { // Assume INA219 if INA260 ID is not found
|
||||
DEBUG_MSG("INA219 sensor found at address 0x%x\n", (uint8_t)addr);
|
||||
LOG_INFO("INA219 sensor found at address 0x%x\n", (uint8_t)addr);
|
||||
nodeTelemetrySensorsMap[TelemetrySensorType_INA219] = addr;
|
||||
}
|
||||
}
|
||||
if (addr == MCP9808_ADDR) {
|
||||
nodeTelemetrySensorsMap[TelemetrySensorType_MCP9808] = addr;
|
||||
DEBUG_MSG("MCP9808 sensor found\n");
|
||||
LOG_INFO("MCP9808 sensor found\n");
|
||||
}
|
||||
if (addr == SHT31_ADDR) {
|
||||
LOG_INFO("SHT31 sensor found\n");
|
||||
nodeTelemetrySensorsMap[TelemetrySensorType_SHT31] = addr;
|
||||
}
|
||||
if (addr == SHTC3_ADDR) {
|
||||
DEBUG_MSG("SHTC3 sensor found\n");
|
||||
LOG_INFO("SHTC3 sensor found\n");
|
||||
nodeTelemetrySensorsMap[TelemetrySensorType_SHTC3] = addr;
|
||||
}
|
||||
if (addr == LPS22HB_ADDR || addr == LPS22HB_ADDR_ALT) {
|
||||
DEBUG_MSG("LPS22HB sensor found\n");
|
||||
LOG_INFO("LPS22HB sensor found\n");
|
||||
nodeTelemetrySensorsMap[TelemetrySensorType_LPS22] = addr;
|
||||
}
|
||||
|
||||
// High rate sensors, will be processed internally
|
||||
if (addr == QMC6310_ADDR) {
|
||||
DEBUG_MSG("QMC6310 Highrate 3-Axis magnetic sensor found\n");
|
||||
LOG_INFO("QMC6310 Highrate 3-Axis magnetic sensor found\n");
|
||||
nodeTelemetrySensorsMap[TelemetrySensorType_QMC6310] = addr;
|
||||
}
|
||||
if (addr == QMI8658_ADDR) {
|
||||
DEBUG_MSG("QMI8658 Highrate 6-Axis inertial measurement sensor found\n");
|
||||
LOG_INFO("QMI8658 Highrate 6-Axis inertial measurement sensor found\n");
|
||||
nodeTelemetrySensorsMap[TelemetrySensorType_QMI8658] = addr;
|
||||
}
|
||||
if (addr == QMC5883L_ADDR) {
|
||||
DEBUG_MSG("QMC5883L Highrate 3-Axis magnetic sensor found\n");
|
||||
LOG_INFO("QMC5883L Highrate 3-Axis magnetic sensor found\n");
|
||||
nodeTelemetrySensorsMap[TelemetrySensorType_QMC5883L] = addr;
|
||||
}
|
||||
} else if (err == 4) {
|
||||
DEBUG_MSG("Unknow error at address 0x%x\n", addr);
|
||||
LOG_ERROR("Unknow error at address 0x%x\n", addr);
|
||||
}
|
||||
}
|
||||
|
||||
if (nDevices == 0)
|
||||
DEBUG_MSG("No I2C devices found\n");
|
||||
LOG_INFO("No I2C devices found\n");
|
||||
else
|
||||
DEBUG_MSG("%i I2C devices found\n",nDevices);
|
||||
LOG_INFO("%i I2C devices found\n",nDevices);
|
||||
}
|
||||
#else
|
||||
void scanI2Cdevice() {}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include "RTC.h"
|
||||
#include "configuration.h"
|
||||
#include "sleep.h"
|
||||
#include <assert.h>
|
||||
|
||||
// If we have a serial GPS port it will not be null
|
||||
#ifdef GPS_SERIAL_NUM
|
||||
@@ -203,7 +202,7 @@ if (!config.position.tx_gpio)
|
||||
0x80, 0x25, 0x00, 0x00, 0x07, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0xAF};
|
||||
_serial_gps->write(_message_nmea, sizeof(_message_nmea));
|
||||
if (!getACK(0x06, 0x00)) {
|
||||
DEBUG_MSG("WARNING: Unable to enable NMEA Mode.\n");
|
||||
LOG_WARN("Unable to enable NMEA Mode.\n");
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
@@ -214,7 +213,7 @@ if (!config.position.tx_gpio)
|
||||
byte _message_GGL[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x05, 0x3A};
|
||||
_serial_gps->write(_message_GGL, sizeof(_message_GGL));
|
||||
if (!getACK(0x06, 0x01)) {
|
||||
DEBUG_MSG("WARNING: Unable to disable NMEA GGL.\n");
|
||||
LOG_WARN("Unable to disable NMEA GGL.\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -222,7 +221,7 @@ if (!config.position.tx_gpio)
|
||||
byte _message_GSA[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x02, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x06, 0x41};
|
||||
_serial_gps->write(_message_GSA, sizeof(_message_GSA));
|
||||
if (!getACK(0x06, 0x01)) {
|
||||
DEBUG_MSG("WARNING: Unable to disable NMEA GSA.\n");
|
||||
LOG_WARN("Unable to disable NMEA GSA.\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -230,7 +229,7 @@ if (!config.position.tx_gpio)
|
||||
byte _message_GSV[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x03, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x07, 0x48};
|
||||
_serial_gps->write(_message_GSV, sizeof(_message_GSV));
|
||||
if (!getACK(0x06, 0x01)) {
|
||||
DEBUG_MSG("WARNING: Unable to disable NMEA GSV.\n");
|
||||
LOG_WARN("Unable to disable NMEA GSV.\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -238,7 +237,7 @@ if (!config.position.tx_gpio)
|
||||
byte _message_VTG[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x05, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x09, 0x56};
|
||||
_serial_gps->write(_message_VTG, sizeof(_message_VTG));
|
||||
if (!getACK(0x06, 0x01)) {
|
||||
DEBUG_MSG("WARNING: Unable to disable NMEA VTG.\n");
|
||||
LOG_WARN("Unable to disable NMEA VTG.\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -246,7 +245,7 @@ if (!config.position.tx_gpio)
|
||||
byte _message_RMC[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x09, 0x54};
|
||||
_serial_gps->write(_message_RMC, sizeof(_message_RMC));
|
||||
if (!getACK(0x06, 0x01)) {
|
||||
DEBUG_MSG("WARNING: Unable to enable NMEA RMC.\n");
|
||||
LOG_WARN("Unable to enable NMEA RMC.\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -254,7 +253,7 @@ if (!config.position.tx_gpio)
|
||||
byte _message_GGA[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x05, 0x38};
|
||||
_serial_gps->write(_message_GGA, sizeof(_message_GGA));
|
||||
if (!getACK(0x06, 0x01)) {
|
||||
DEBUG_MSG("WARNING: Unable to enable NMEA GGA.\n");
|
||||
LOG_WARN("Unable to enable NMEA GGA.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -270,21 +269,30 @@ bool GPS::setup()
|
||||
pinMode(PIN_GPS_EN, OUTPUT);
|
||||
#endif
|
||||
|
||||
#ifdef HAS_PMU
|
||||
if(config.position.gps_enabled){
|
||||
setGPSPower(true);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef PIN_GPS_RESET
|
||||
digitalWrite(PIN_GPS_RESET, 1); // assert for 10ms
|
||||
pinMode(PIN_GPS_RESET, OUTPUT);
|
||||
delay(10);
|
||||
digitalWrite(PIN_GPS_RESET, 0);
|
||||
#endif
|
||||
|
||||
setAwake(true); // Wake GPS power before doing any init
|
||||
bool ok = setupGPS();
|
||||
|
||||
if (ok) {
|
||||
notifySleepObserver.observe(¬ifySleep);
|
||||
notifyDeepSleepObserver.observe(¬ifyDeepSleep);
|
||||
notifyGPSSleepObserver.observe(¬ifyGPSSleep);
|
||||
}
|
||||
if (config.position.gps_enabled==false) {
|
||||
setAwake(false);
|
||||
doGPSpowersave(false);
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
@@ -293,6 +301,7 @@ GPS::~GPS()
|
||||
// we really should unregister our sleep observer
|
||||
notifySleepObserver.unobserve(¬ifySleep);
|
||||
notifyDeepSleepObserver.unobserve(¬ifyDeepSleep);
|
||||
notifyGPSSleepObserver.observe(¬ifyGPSSleep);
|
||||
}
|
||||
|
||||
bool GPS::hasLock()
|
||||
@@ -351,12 +360,12 @@ void GPS::setNumSatellites(uint8_t n)
|
||||
void GPS::setAwake(bool on)
|
||||
{
|
||||
if (!wakeAllowed && on) {
|
||||
DEBUG_MSG("Inhibiting because !wakeAllowed\n");
|
||||
LOG_WARN("Inhibiting because !wakeAllowed\n");
|
||||
on = false;
|
||||
}
|
||||
|
||||
if (isAwake != on) {
|
||||
DEBUG_MSG("WANT GPS=%d\n", on);
|
||||
LOG_DEBUG("WANT GPS=%d\n", on);
|
||||
if (on) {
|
||||
lastWakeStartMsec = millis();
|
||||
wake();
|
||||
@@ -402,10 +411,10 @@ void GPS::publishUpdate()
|
||||
shouldPublish = false;
|
||||
|
||||
// In debug logs, identify position by @timestamp:stage (stage 2 = publish)
|
||||
DEBUG_MSG("publishing pos@%x:2, hasVal=%d, GPSlock=%d\n", p.timestamp, hasValidLocation, hasLock());
|
||||
LOG_DEBUG("publishing pos@%x:2, hasVal=%d, GPSlock=%d\n", p.timestamp, hasValidLocation, hasLock());
|
||||
|
||||
// Notify any status instances that are observing us
|
||||
const meshtastic::GPSStatus status = meshtastic::GPSStatus(hasValidLocation, isConnected(), p);
|
||||
const meshtastic::GPSStatus status = meshtastic::GPSStatus(hasValidLocation, isConnected(), isPowerSaving(), p);
|
||||
newStatus.notifyObservers(&status);
|
||||
}
|
||||
}
|
||||
@@ -416,10 +425,10 @@ int32_t GPS::runOnce()
|
||||
// if we have received valid NMEA claim we are connected
|
||||
setConnected();
|
||||
} else {
|
||||
if(gnssModel == GNSS_MODEL_UBLOX){
|
||||
if((config.position.gps_enabled == 1) && (gnssModel == GNSS_MODEL_UBLOX)){
|
||||
// reset the GPS on next bootup
|
||||
if(devicestate.did_gps_reset && (millis() > 60000) && !hasFlow()) {
|
||||
DEBUG_MSG("GPS is not communicating, trying factory reset on next bootup.\n");
|
||||
LOG_DEBUG("GPS is not communicating, trying factory reset on next bootup.\n");
|
||||
devicestate.did_gps_reset = false;
|
||||
nodeDB.saveDeviceStateToDisk();
|
||||
}
|
||||
@@ -437,7 +446,7 @@ int32_t GPS::runOnce()
|
||||
|
||||
// While we are awake
|
||||
if (isAwake) {
|
||||
// DEBUG_MSG("looking for location\n");
|
||||
// LOG_DEBUG("looking for location\n");
|
||||
if ((now - lastWhileActiveMsec) > 5000) {
|
||||
lastWhileActiveMsec = now;
|
||||
whileActive();
|
||||
@@ -452,7 +461,7 @@ int32_t GPS::runOnce()
|
||||
|
||||
bool gotLoc = lookForLocation();
|
||||
if (gotLoc && !hasValidLocation) { // declare that we have location ASAP
|
||||
DEBUG_MSG("hasValidLocation RISING EDGE\n");
|
||||
LOG_DEBUG("hasValidLocation RISING EDGE\n");
|
||||
hasValidLocation = true;
|
||||
shouldPublish = true;
|
||||
}
|
||||
@@ -463,13 +472,13 @@ int32_t GPS::runOnce()
|
||||
bool tooLong = wakeTime != UINT32_MAX && (now - lastWakeStartMsec) > wakeTime;
|
||||
|
||||
// Once we get a location we no longer desperately want an update
|
||||
// DEBUG_MSG("gotLoc %d, tooLong %d, gotTime %d\n", gotLoc, tooLong, gotTime);
|
||||
// LOG_DEBUG("gotLoc %d, tooLong %d, gotTime %d\n", gotLoc, tooLong, gotTime);
|
||||
if ((gotLoc && gotTime) || tooLong) {
|
||||
|
||||
if (tooLong) {
|
||||
// we didn't get a location during this ack window, therefore declare loss of lock
|
||||
if (hasValidLocation) {
|
||||
DEBUG_MSG("hasValidLocation FALLING EDGE (last read: %d)\n", gotLoc);
|
||||
LOG_DEBUG("hasValidLocation FALLING EDGE (last read: %d)\n", gotLoc);
|
||||
}
|
||||
p = Position_init_default;
|
||||
hasValidLocation = false;
|
||||
@@ -491,7 +500,7 @@ int32_t GPS::runOnce()
|
||||
void GPS::forceWake(bool on)
|
||||
{
|
||||
if (on) {
|
||||
DEBUG_MSG("Allowing GPS lock\n");
|
||||
LOG_DEBUG("Allowing GPS lock\n");
|
||||
// lastSleepStartMsec = 0; // Force an update ASAP
|
||||
wakeAllowed = true;
|
||||
} else {
|
||||
@@ -506,7 +515,7 @@ void GPS::forceWake(bool on)
|
||||
/// Prepare the GPS for the cpu entering deep or light sleep, expect to be gone for at least 100s of msecs
|
||||
int GPS::prepareSleep(void *unused)
|
||||
{
|
||||
DEBUG_MSG("GPS prepare sleep!\n");
|
||||
LOG_INFO("GPS prepare sleep!\n");
|
||||
forceWake(false);
|
||||
|
||||
return 0;
|
||||
@@ -515,9 +524,10 @@ int GPS::prepareSleep(void *unused)
|
||||
/// Prepare the GPS for the cpu entering deep or light sleep, expect to be gone for at least 100s of msecs
|
||||
int GPS::prepareDeepSleep(void *unused)
|
||||
{
|
||||
DEBUG_MSG("GPS deep sleep!\n");
|
||||
LOG_INFO("GPS deep sleep!\n");
|
||||
|
||||
// For deep sleep we also want abandon any lock attempts (because we want minimum power)
|
||||
getSleepTime();
|
||||
setAwake(false);
|
||||
|
||||
return 0;
|
||||
@@ -557,7 +567,7 @@ GnssModel_t GPS::probe()
|
||||
if(index != -1){
|
||||
ver = ver.substring(index);
|
||||
if (ver.startsWith("$GPTXT,01,01,02")) {
|
||||
DEBUG_MSG("L76K GNSS init succeeded, using L76K GNSS Module\n");
|
||||
LOG_INFO("L76K GNSS init succeeded, using L76K GNSS Module\n");
|
||||
return GNSS_MODEL_MTK;
|
||||
}
|
||||
}
|
||||
@@ -569,7 +579,7 @@ GnssModel_t GPS::probe()
|
||||
_serial_gps->write(cfg_rate, sizeof(cfg_rate));
|
||||
// Check that the returned response class and message ID are correct
|
||||
if (!getAck(buffer, 256, 0x06, 0x08)) {
|
||||
DEBUG_MSG("Warning: Failed to find UBlox & MTK GNSS Module\n");
|
||||
LOG_WARN("Failed to find UBlox & MTK GNSS Module\n");
|
||||
return GNSS_MODEL_UNKONW;
|
||||
}
|
||||
|
||||
@@ -600,12 +610,12 @@ GnssModel_t GPS::probe()
|
||||
break;
|
||||
}
|
||||
|
||||
DEBUG_MSG("Module Info : \n");
|
||||
DEBUG_MSG("Soft version: %s\n",info.swVersion);
|
||||
DEBUG_MSG("Hard version: %s\n",info.hwVersion);
|
||||
DEBUG_MSG("Extensions:%d\n",info.extensionNo);
|
||||
LOG_DEBUG("Module Info : \n");
|
||||
LOG_DEBUG("Soft version: %s\n",info.swVersion);
|
||||
LOG_DEBUG("Hard version: %s\n",info.hwVersion);
|
||||
LOG_DEBUG("Extensions:%d\n",info.extensionNo);
|
||||
for (int i = 0; i < info.extensionNo; i++) {
|
||||
DEBUG_MSG(" %s\n",info.extension[i]);
|
||||
LOG_DEBUG(" %s\n",info.extension[i]);
|
||||
}
|
||||
|
||||
memset(buffer,0,sizeof(buffer));
|
||||
@@ -614,15 +624,15 @@ GnssModel_t GPS::probe()
|
||||
for (int i = 0; i < info.extensionNo; ++i) {
|
||||
if (!strncmp(info.extension[i], "OD=", 3)) {
|
||||
strcpy((char *)buffer, &(info.extension[i][3]));
|
||||
DEBUG_MSG("GetModel:%s\n",(char *)buffer);
|
||||
LOG_DEBUG("GetModel:%s\n",(char *)buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (strlen((char*)buffer)) {
|
||||
DEBUG_MSG("UBlox GNSS init succeeded, using UBlox %s GNSS Module\n" , buffer);
|
||||
LOG_INFO("UBlox GNSS init succeeded, using UBlox %s GNSS Module\n" , buffer);
|
||||
}else{
|
||||
DEBUG_MSG("UBlox GNSS init succeeded, using UBlox GNSS Module\n");
|
||||
LOG_INFO("UBlox GNSS init succeeded, using UBlox GNSS Module\n");
|
||||
}
|
||||
|
||||
return GNSS_MODEL_UBLOX;
|
||||
@@ -641,9 +651,9 @@ GPS *createGps()
|
||||
#else
|
||||
if (config.position.gps_enabled) {
|
||||
#ifdef GPS_ALTITUDE_HAE
|
||||
DEBUG_MSG("Using HAE altitude model\n");
|
||||
LOG_DEBUG("Using HAE altitude model\n");
|
||||
#else
|
||||
DEBUG_MSG("Using MSL altitude model\n");
|
||||
LOG_DEBUG("Using MSL altitude model\n");
|
||||
#endif
|
||||
if (GPS::_serial_gps) {
|
||||
// Some boards might have only the TX line from the GPS connected, in that case, we can't configure it at all. Just
|
||||
@@ -653,6 +663,11 @@ GPS *createGps()
|
||||
return new_gps;
|
||||
}
|
||||
}
|
||||
else{
|
||||
GPS *new_gps = new NMEAGPS();
|
||||
new_gps->setup();
|
||||
return new_gps;
|
||||
}
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ class GPS : private concurrency::OSThread
|
||||
|
||||
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);
|
||||
|
||||
public:
|
||||
/** If !NULL we will use this serial port to construct our GPS */
|
||||
@@ -77,6 +78,8 @@ class GPS : private concurrency::OSThread
|
||||
/// Return true if we are connected to a GPS
|
||||
bool isConnected() const { return hasGPS; }
|
||||
|
||||
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
|
||||
|
||||
@@ -53,9 +53,9 @@ bool NMEAGPS::setupGPS()
|
||||
// see NMEAGPS.h
|
||||
gsafixtype.begin(reader, NMEA_MSG_GXGSA, 2);
|
||||
gsapdop.begin(reader, NMEA_MSG_GXGSA, 15);
|
||||
DEBUG_MSG("Using " NMEA_MSG_GXGSA " for 3DFIX and PDOP\n");
|
||||
LOG_DEBUG("Using " NMEA_MSG_GXGSA " for 3DFIX and PDOP\n");
|
||||
#else
|
||||
DEBUG_MSG("GxGSA NOT available\n");
|
||||
LOG_DEBUG("GxGSA NOT available\n");
|
||||
#endif
|
||||
|
||||
return true;
|
||||
@@ -85,7 +85,7 @@ The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of s
|
||||
t.tm_year = d.year() - 1900;
|
||||
t.tm_isdst = false;
|
||||
if (t.tm_mon > -1){
|
||||
DEBUG_MSG("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);
|
||||
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
|
||||
@@ -109,7 +109,7 @@ bool NMEAGPS::lookForLocation()
|
||||
|
||||
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
|
||||
fixType = atoi(gsafixtype.value()); // will set to zero if no data
|
||||
// DEBUG_MSG("FIX QUAL=%d, TYPE=%d\n", fixQual, fixType);
|
||||
// LOG_DEBUG("FIX QUAL=%d, TYPE=%d\n", fixQual, fixType);
|
||||
#endif
|
||||
|
||||
// check if GPS has an acceptable lock
|
||||
@@ -117,7 +117,7 @@ bool NMEAGPS::lookForLocation()
|
||||
return false;
|
||||
|
||||
#ifdef GPS_EXTRAVERBOSE
|
||||
DEBUG_MSG("AGE: LOC=%d FIX=%d DATE=%d TIME=%d\n",
|
||||
LOG_DEBUG("AGE: LOC=%d FIX=%d DATE=%d TIME=%d\n",
|
||||
reader.location.age(),
|
||||
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
|
||||
gsafixtype.age(),
|
||||
@@ -137,7 +137,7 @@ bool NMEAGPS::lookForLocation()
|
||||
(reader.time.age() < GPS_SOL_EXPIRY_MS) &&
|
||||
(reader.date.age() < GPS_SOL_EXPIRY_MS)))
|
||||
{
|
||||
DEBUG_MSG("SOME data is TOO OLD: LOC %u, TIME %u, DATE %u\n", reader.location.age(), reader.time.age(), reader.date.age());
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -151,13 +151,13 @@ bool NMEAGPS::lookForLocation()
|
||||
// Bail out EARLY to avoid overwriting previous good data (like #857)
|
||||
if (toDegInt(loc.lat) > 900000000) {
|
||||
#ifdef GPS_EXTRAVERBOSE
|
||||
DEBUG_MSG("Bail out EARLY on LAT %i\n",toDegInt(loc.lat));
|
||||
LOG_DEBUG("Bail out EARLY on LAT %i\n",toDegInt(loc.lat));
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
if (toDegInt(loc.lng) > 1800000000) {
|
||||
#ifdef GPS_EXTRAVERBOSE
|
||||
DEBUG_MSG("Bail out EARLY on LNG %i\n",toDegInt(loc.lng));
|
||||
LOG_DEBUG("Bail out EARLY on LNG %i\n",toDegInt(loc.lng));
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
@@ -168,7 +168,7 @@ bool NMEAGPS::lookForLocation()
|
||||
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
|
||||
p.HDOP = reader.hdop.value();
|
||||
p.PDOP = TinyGPSPlus::parseDecimal(gsapdop.value());
|
||||
// DEBUG_MSG("PDOP=%d, HDOP=%d\n", p.PDOP, p.HDOP);
|
||||
// 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)
|
||||
@@ -212,7 +212,7 @@ bool NMEAGPS::lookForLocation()
|
||||
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 {
|
||||
DEBUG_MSG("BOGUS course.value() REJECTED: %d\n",
|
||||
LOG_WARN("BOGUS course.value() REJECTED: %d\n",
|
||||
reader.course.value());
|
||||
}
|
||||
}
|
||||
@@ -251,7 +251,7 @@ bool NMEAGPS::whileIdle()
|
||||
// First consume any chars that have piled up at the receiver
|
||||
while (_serial_gps->available() > 0) {
|
||||
int c = _serial_gps->read();
|
||||
// DEBUG_MSG("%c", c);
|
||||
// LOG_DEBUG("%c", c);
|
||||
isValid |= reader.encode(c);
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ void readFromRTC()
|
||||
t.tm_sec = rtc.getSecond();
|
||||
tv.tv_sec = mktime(&t);
|
||||
tv.tv_usec = 0;
|
||||
DEBUG_MSG("Read RTC time from RV3028 as %ld\n", tv.tv_sec);
|
||||
LOG_DEBUG("Read RTC time from RV3028 as %ld\n", tv.tv_sec);
|
||||
timeStartMsec = now;
|
||||
zeroOffsetSecs = tv.tv_sec;
|
||||
if (currentQuality == RTCQualityNone) {
|
||||
@@ -59,7 +59,7 @@ void readFromRTC()
|
||||
t.tm_sec = tc.second;
|
||||
tv.tv_sec = mktime(&t);
|
||||
tv.tv_usec = 0;
|
||||
DEBUG_MSG("Read RTC time from PCF8563 as %ld\n", tv.tv_sec);
|
||||
LOG_DEBUG("Read RTC time from PCF8563 as %ld\n", tv.tv_sec);
|
||||
timeStartMsec = now;
|
||||
zeroOffsetSecs = tv.tv_sec;
|
||||
if (currentQuality == RTCQualityNone) {
|
||||
@@ -69,7 +69,7 @@ void readFromRTC()
|
||||
#else
|
||||
if (!gettimeofday(&tv, NULL)) {
|
||||
uint32_t now = millis();
|
||||
DEBUG_MSG("Read RTC time as %ld\n", tv.tv_sec);
|
||||
LOG_DEBUG("Read RTC time as %ld\n", tv.tv_sec);
|
||||
timeStartMsec = now;
|
||||
zeroOffsetSecs = tv.tv_sec;
|
||||
}
|
||||
@@ -86,11 +86,11 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv)
|
||||
if (q > currentQuality) {
|
||||
currentQuality = q;
|
||||
shouldSet = true;
|
||||
DEBUG_MSG("Upgrading time to RTC %ld secs (quality %d)\n", tv->tv_sec, q);
|
||||
LOG_DEBUG("Upgrading time to RTC %ld secs (quality %d)\n", tv->tv_sec, 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;
|
||||
DEBUG_MSG("Reapplying external time to correct clock drift %ld secs\n", tv->tv_sec);
|
||||
LOG_DEBUG("Reapplying external time to correct clock drift %ld secs\n", tv->tv_sec);
|
||||
}
|
||||
else
|
||||
shouldSet = false;
|
||||
@@ -109,7 +109,7 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv)
|
||||
rtc.initI2C();
|
||||
tm *t = localtime(&tv->tv_sec);
|
||||
rtc.setTime(t->tm_year + 1900, t->tm_mon + 1, t->tm_wday, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
|
||||
DEBUG_MSG("RV3028_RTC setTime %02d-%02d-%02d %02d:%02d:%02d %ld\n", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, tv->tv_sec);
|
||||
LOG_DEBUG("RV3028_RTC setTime %02d-%02d-%02d %02d:%02d:%02d %ld\n", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, tv->tv_sec);
|
||||
}
|
||||
#elif defined(PCF8563_RTC)
|
||||
if(rtc_found == PCF8563_RTC) {
|
||||
@@ -121,7 +121,7 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv)
|
||||
#endif
|
||||
tm *t = localtime(&tv->tv_sec);
|
||||
rtc.setDateTime(t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
|
||||
DEBUG_MSG("PCF8563_RTC setDateTime %02d-%02d-%02d %02d:%02d:%02d %ld\n", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, tv->tv_sec);
|
||||
LOG_DEBUG("PCF8563_RTC setDateTime %02d-%02d-%02d %02d:%02d:%02d %ld\n", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, tv->tv_sec);
|
||||
}
|
||||
#elif defined(ARCH_ESP32)
|
||||
settimeofday(tv, NULL);
|
||||
@@ -149,9 +149,9 @@ bool perhapsSetRTC(RTCQuality q, struct tm &t)
|
||||
tv.tv_sec = res;
|
||||
tv.tv_usec = 0; // time.centisecond() * (10 / 1000);
|
||||
|
||||
// DEBUG_MSG("Got time from GPS month=%d, year=%d, unixtime=%ld\n", t.tm_mon, t.tm_year, tv.tv_sec);
|
||||
// LOG_DEBUG("Got time from GPS month=%d, year=%d, unixtime=%ld\n", t.tm_mon, t.tm_year, tv.tv_sec);
|
||||
if (t.tm_year < 0 || t.tm_year >= 300) {
|
||||
// DEBUG_MSG("Ignoring invalid GPS month=%d, year=%d, unixtime=%ld\n", t.tm_mon, t.tm_year, tv.tv_sec);
|
||||
// LOG_DEBUG("Ignoring invalid GPS month=%d, year=%d, unixtime=%ld\n", t.tm_mon, t.tm_year, tv.tv_sec);
|
||||
return false;
|
||||
} else {
|
||||
return perhapsSetRTC(q, &tv);
|
||||
|
||||
@@ -103,7 +103,7 @@ bool EInkDisplay::forceDisplay(uint32_t msecLimit)
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_MSG("Updating E-Paper... ");
|
||||
LOG_DEBUG("Updating E-Paper... ");
|
||||
|
||||
#if defined(TTGO_T_ECHO)
|
||||
// ePaper.Reset(); // wake the screen from sleep
|
||||
@@ -128,11 +128,11 @@ bool EInkDisplay::forceDisplay(uint32_t msecLimit)
|
||||
|
||||
// Put screen to sleep to save power (possibly not necessary because we already did poweroff inside of display)
|
||||
adafruitDisplay->hibernate();
|
||||
DEBUG_MSG("done\n");
|
||||
LOG_DEBUG("done\n");
|
||||
|
||||
return true;
|
||||
} else {
|
||||
// DEBUG_MSG("Skipping eink display\n");
|
||||
// LOG_DEBUG("Skipping eink display\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -162,7 +162,7 @@ void EInkDisplay::setDetected(uint8_t detected)
|
||||
// Connect to the display
|
||||
bool EInkDisplay::connect()
|
||||
{
|
||||
DEBUG_MSG("Doing EInk init\n");
|
||||
LOG_INFO("Doing EInk init\n");
|
||||
|
||||
#ifdef PIN_EINK_PWR_ON
|
||||
digitalWrite(PIN_EINK_PWR_ON, HIGH); // If we need to assert a pin to power external peripherals
|
||||
|
||||
@@ -35,6 +35,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#include "mesh/Channels.h"
|
||||
#include "mesh/generated/deviceonly.pb.h"
|
||||
#include "modules/TextMessageModule.h"
|
||||
#include "modules/ExternalNotificationModule.h"
|
||||
#include "sleep.h"
|
||||
#include "target_specific.h"
|
||||
#include "utils.h"
|
||||
@@ -42,6 +43,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#ifdef ARCH_ESP32
|
||||
#include "esp_task_wdt.h"
|
||||
#include "mesh/http/WiFiAPClient.h"
|
||||
#include "modules/esp32/StoreForwardModule.h"
|
||||
#endif
|
||||
|
||||
#ifdef OLED_RU
|
||||
@@ -95,17 +97,17 @@ static uint16_t displayWidth, displayHeight;
|
||||
|
||||
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS)
|
||||
// The screen is bigger so use bigger fonts
|
||||
#define FONT_SMALL ArialMT_Plain_16
|
||||
#define FONT_MEDIUM ArialMT_Plain_24
|
||||
#define FONT_LARGE ArialMT_Plain_24
|
||||
#define FONT_SMALL ArialMT_Plain_16 // Height: 19
|
||||
#define FONT_MEDIUM ArialMT_Plain_24 // Height: 28
|
||||
#define FONT_LARGE ArialMT_Plain_24 // Height: 28
|
||||
#else
|
||||
#ifdef OLED_RU
|
||||
#define FONT_SMALL ArialMT_Plain_10_RU
|
||||
#else
|
||||
#define FONT_SMALL ArialMT_Plain_10
|
||||
#define FONT_SMALL ArialMT_Plain_10 // Height: 13
|
||||
#endif
|
||||
#define FONT_MEDIUM ArialMT_Plain_16
|
||||
#define FONT_LARGE ArialMT_Plain_24
|
||||
#define FONT_MEDIUM ArialMT_Plain_16 // Height: 19
|
||||
#define FONT_LARGE ArialMT_Plain_24 // Height: 28
|
||||
#endif
|
||||
|
||||
#define fontHeight(font) ((font)[1] + 1) // height is position 1
|
||||
@@ -274,9 +276,9 @@ static void drawModuleFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int
|
||||
} else {
|
||||
// otherwise, just display the module frame that's aligned with the current frame
|
||||
module_frame = state->currentFrame;
|
||||
// DEBUG_MSG("Screen is not in transition. Frame: %d\n\n", module_frame);
|
||||
// LOG_DEBUG("Screen is not in transition. Frame: %d\n\n", module_frame);
|
||||
}
|
||||
// DEBUG_MSG("Drawing Module Frame %d\n\n", module_frame);
|
||||
// LOG_DEBUG("Drawing Module Frame %d\n\n", module_frame);
|
||||
MeshModule &pi = *moduleFrames.at(module_frame);
|
||||
pi.drawFrame(display, state, x, y);
|
||||
}
|
||||
@@ -329,11 +331,8 @@ static void drawFrameFirmware(OLEDDisplay *display, OLEDDisplayUiState *state, i
|
||||
display->drawString(64 + x, y, "Updating");
|
||||
|
||||
display->setFont(FONT_SMALL);
|
||||
if ((millis() / 1000) % 2) {
|
||||
display->drawString(64 + x, FONT_HEIGHT_SMALL + y + 2, "Please wait . . .");
|
||||
} else {
|
||||
display->drawString(64 + x, FONT_HEIGHT_SMALL + y + 2, "Please wait . . ");
|
||||
}
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display->drawStringMaxWidth(0 + x, 2 + y + FONT_HEIGHT_SMALL *2, x + display->getWidth(), "Please be patient and do not power off.");
|
||||
}
|
||||
|
||||
/// Draw the last text message we received
|
||||
@@ -364,25 +363,30 @@ static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state
|
||||
{
|
||||
displayedNodeNum = 0; // Not currently showing a node pane
|
||||
|
||||
// the max length of this buffer is much longer than we can possibly print
|
||||
static char tempBuf[237];
|
||||
|
||||
MeshPacket &mp = devicestate.rx_text_message;
|
||||
NodeInfo *node = nodeDB.getNode(getFrom(&mp));
|
||||
// DEBUG_MSG("drawing text message from 0x%x: %s\n", mp.from,
|
||||
// LOG_DEBUG("drawing text message from 0x%x: %s\n", mp.from,
|
||||
// mp.decoded.variant.data.decoded.bytes);
|
||||
|
||||
// Demo for drawStringMaxWidth:
|
||||
// with the third parameter you can define the width after which words will
|
||||
// be wrapped. Currently only spaces and "-" are allowed for wrapping
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display->setFont(FONT_MEDIUM);
|
||||
String sender = (node && node->has_user) ? node->user.short_name : "???";
|
||||
display->drawString(0 + x, 0 + y, sender);
|
||||
display->setFont(FONT_SMALL);
|
||||
|
||||
// the max length of this buffer is much longer than we can possibly print
|
||||
static char tempBuf[96];
|
||||
snprintf(tempBuf, sizeof(tempBuf), " %s", mp.decoded.payload.bytes);
|
||||
|
||||
display->drawStringMaxWidth(4 + x, 10 + y, SCREEN_WIDTH - (6 + x), tempBuf);
|
||||
if (config.display.displaymode == Config_DisplayConfig_DisplayMode_INVERTED) {
|
||||
display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL);
|
||||
display->setColor(BLACK);
|
||||
}
|
||||
display->drawStringf(0 + x, 0 + y, tempBuf, "From: %s", (node && node->has_user) ? node->user.short_name : "???");
|
||||
if(config.display.heading_bold) {
|
||||
display->drawStringf(1 + x, 0 + y, tempBuf, "From: %s", (node && node->has_user) ? node->user.short_name : "???");
|
||||
}
|
||||
display->setColor(WHITE);
|
||||
snprintf(tempBuf, sizeof(tempBuf), "%s", mp.decoded.payload.bytes);
|
||||
display->drawStringMaxWidth(0 + x, 0 + y + FONT_HEIGHT_SMALL, x + display->getWidth(), tempBuf);
|
||||
}
|
||||
|
||||
/// Draw a series of fields in a column, wrapping to multiple colums if needed
|
||||
@@ -395,6 +399,10 @@ static void drawColumns(OLEDDisplay *display, int16_t x, int16_t y, const char *
|
||||
int xo = x, yo = y;
|
||||
while (*f) {
|
||||
display->drawString(xo, yo, *f);
|
||||
if ((display->getColor() == BLACK) && config.display.heading_bold)
|
||||
display->drawString(xo + 1, yo, *f);
|
||||
|
||||
display->setColor(WHITE);
|
||||
yo += FONT_HEIGHT_SMALL;
|
||||
if (yo > SCREEN_HEIGHT - FONT_HEIGHT_SMALL) {
|
||||
xo += SCREEN_WIDTH / 2;
|
||||
@@ -463,8 +471,14 @@ static void drawNodes(OLEDDisplay *display, int16_t x, int16_t y, NodeStatus *no
|
||||
{
|
||||
char usersString[20];
|
||||
sprintf(usersString, "%d/%d", nodeStatus->getNumOnline(), nodeStatus->getNumTotal());
|
||||
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS)
|
||||
display->drawFastImage(x, y + 3, 8, 8, imgUser);
|
||||
#else
|
||||
display->drawFastImage(x, y, 8, 8, imgUser);
|
||||
#endif
|
||||
display->drawString(x + 10, y - 2, usersString);
|
||||
if(config.display.heading_bold)
|
||||
display->drawString(x + 11, y - 2, usersString);
|
||||
}
|
||||
|
||||
// Draw GPS status summary
|
||||
@@ -473,15 +487,21 @@ static void drawGPS(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus
|
||||
if (config.position.fixed_position) {
|
||||
// GPS coordinates are currently fixed
|
||||
display->drawString(x - 1, y - 2, "Fixed GPS");
|
||||
if(config.display.heading_bold)
|
||||
display->drawString(x, y - 2, "Fixed GPS");
|
||||
return;
|
||||
}
|
||||
if (!gps->getIsConnected()) {
|
||||
display->drawString(x, y - 2, "No GPS");
|
||||
if(config.display.heading_bold)
|
||||
display->drawString(x + 1, y - 2, "No GPS");
|
||||
return;
|
||||
}
|
||||
display->drawFastImage(x, y, 6, 8, gps->getHasLock() ? imgPositionSolid : imgPositionEmpty);
|
||||
if (!gps->getHasLock()) {
|
||||
display->drawString(x + 8, y - 2, "No sats");
|
||||
if(config.display.heading_bold)
|
||||
display->drawString(x + 9, y - 2, "No sats");
|
||||
return;
|
||||
} else {
|
||||
char satsString[3];
|
||||
@@ -503,9 +523,28 @@ static void drawGPS(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus
|
||||
// Draw the number of satellites
|
||||
sprintf(satsString, "%u", gps->getNumSatellites());
|
||||
display->drawString(x + 34, y - 2, satsString);
|
||||
if(config.display.heading_bold)
|
||||
display->drawString(x + 35, y - 2, satsString);
|
||||
}
|
||||
}
|
||||
|
||||
//Draw status when gps is disabled by PMU
|
||||
static void drawGPSpowerstat(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus *gps)
|
||||
{
|
||||
#ifdef HAS_PMU
|
||||
String displayLine = "GPS disabled";
|
||||
int16_t xPos = display->getStringWidth(displayLine);
|
||||
|
||||
if (!config.position.gps_enabled){
|
||||
display->drawString(x + xPos, y, displayLine);
|
||||
#ifdef GPS_POWER_TOGGLE
|
||||
display->drawString(x + xPos, y - 2 + FONT_HEIGHT_SMALL, " by button");
|
||||
#endif
|
||||
//display->drawString(x + xPos, y + 2, displayLine);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void drawGPSAltitude(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus *gps)
|
||||
{
|
||||
String displayLine = "";
|
||||
@@ -668,17 +707,22 @@ static bool hasPosition(NodeInfo *n)
|
||||
static uint16_t getCompassDiam(OLEDDisplay *display)
|
||||
{
|
||||
uint16_t diam = 0;
|
||||
uint16_t offset = 0;
|
||||
|
||||
if (config.display.displaymode != Config_DisplayConfig_DisplayMode_DEFAULT)
|
||||
offset = FONT_HEIGHT_SMALL;
|
||||
|
||||
// get the smaller of the 2 dimensions and subtract 20
|
||||
if(display->getWidth() > display->getHeight()) {
|
||||
diam = display->getHeight();
|
||||
if(display->getWidth() > (display->getHeight() - offset)) {
|
||||
diam = display->getHeight() - offset;
|
||||
// if 2/3 of the other size would be smaller, use that
|
||||
if (diam > (display->getWidth() * 2 / 3)) {
|
||||
diam = display->getWidth() * 2 / 3;
|
||||
}
|
||||
} else {
|
||||
diam = display->getWidth();
|
||||
if (diam > (display->getHeight() * 2 / 3)) {
|
||||
diam = display->getHeight() * 2 / 3;
|
||||
if (diam > ((display->getHeight() - offset) * 2 / 3)) {
|
||||
diam = (display->getHeight() - offset) * 2 / 3;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -758,6 +802,10 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
|
||||
// The coordinates define the left starting point of the text
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
|
||||
if (config.display.displaymode == Config_DisplayConfig_DisplayMode_INVERTED) {
|
||||
display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL);
|
||||
}
|
||||
|
||||
const char *username = node->has_user ? node->user.long_name : "Unknown Name";
|
||||
|
||||
static char signalStr[20];
|
||||
@@ -786,9 +834,16 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
|
||||
strcpy(distStr, "? km"); // might not have location data
|
||||
NodeInfo *ourNode = nodeDB.getNode(nodeDB.getNodeNum());
|
||||
const char *fields[] = {username, distStr, signalStr, lastStr, NULL};
|
||||
int16_t compassX = 0, compassY = 0;
|
||||
|
||||
// coordinates for the center of the compass/circle
|
||||
int16_t compassX = x + SCREEN_WIDTH - getCompassDiam(display) / 2 - 5, compassY = y + SCREEN_HEIGHT / 2;
|
||||
if (config.display.displaymode == Config_DisplayConfig_DisplayMode_DEFAULT) {
|
||||
compassX = x + SCREEN_WIDTH - getCompassDiam(display) / 2 - 5;
|
||||
compassY = y + SCREEN_HEIGHT / 2;
|
||||
} else {
|
||||
compassX = x + SCREEN_WIDTH - getCompassDiam(display) / 2 - 5;
|
||||
compassY = y + FONT_HEIGHT_SMALL + (SCREEN_HEIGHT - FONT_HEIGHT_SMALL) / 2;
|
||||
}
|
||||
bool hasNodeHeading = false;
|
||||
|
||||
if (ourNode && hasPosition(ourNode)) {
|
||||
@@ -824,40 +879,21 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
|
||||
drawNodeHeading(display, compassX, compassY, bearingToOther);
|
||||
}
|
||||
}
|
||||
if (!hasNodeHeading)
|
||||
if (!hasNodeHeading) {
|
||||
// direction to node is unknown so display question mark
|
||||
// Debug info for gps lock errors
|
||||
// DEBUG_MSG("ourNode %d, ourPos %d, theirPos %d\n", !!ourNode, ourNode && hasPosition(ourNode), hasPosition(node));
|
||||
// LOG_DEBUG("ourNode %d, ourPos %d, theirPos %d\n", !!ourNode, ourNode && hasPosition(ourNode), hasPosition(node));
|
||||
display->drawString(compassX - FONT_HEIGHT_SMALL / 4, compassY - FONT_HEIGHT_SMALL / 2, "?");
|
||||
}
|
||||
display->drawCircle(compassX, compassY, getCompassDiam(display) / 2);
|
||||
|
||||
if (config.display.displaymode == Config_DisplayConfig_DisplayMode_INVERTED) {
|
||||
display->setColor(BLACK);
|
||||
}
|
||||
// Must be after distStr is populated
|
||||
drawColumns(display, x, y, fields);
|
||||
}
|
||||
|
||||
#if 0
|
||||
void _screen_header()
|
||||
{
|
||||
if (!disp)
|
||||
return;
|
||||
|
||||
// Message count
|
||||
//snprintf(buffer, sizeof(buffer), "#%03d", ttn_get_count() % 1000);
|
||||
//display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
//display->drawString(0, 2, buffer);
|
||||
|
||||
// Datetime
|
||||
display->setTextAlignment(TEXT_ALIGN_CENTER);
|
||||
display->drawString(display->getWidth()/2, 2, gps.getTimeStr());
|
||||
|
||||
// Satellite count
|
||||
display->setTextAlignment(TEXT_ALIGN_RIGHT);
|
||||
char buffer[10];
|
||||
display->drawString(display->getWidth() - SATELLITE_IMAGE_WIDTH - 4, 2, itoa(gps.satellites.value(), buffer, 10));
|
||||
display->drawXbm(display->getWidth() - SATELLITE_IMAGE_WIDTH, 0, SATELLITE_IMAGE_WIDTH, SATELLITE_IMAGE_HEIGHT, SATELLITE_IMAGE);
|
||||
}
|
||||
#endif
|
||||
|
||||
// #ifdef RAK4630
|
||||
// Screen::Screen(uint8_t address, int sda, int scl) : OSThread("Screen"), cmdQueue(32), dispdev(address, sda, scl),
|
||||
// dispdev_oled(address, sda, scl), ui(&dispdev)
|
||||
@@ -900,14 +936,14 @@ void Screen::handleSetOn(bool on)
|
||||
|
||||
if (on != screenOn) {
|
||||
if (on) {
|
||||
DEBUG_MSG("Turning on screen\n");
|
||||
LOG_INFO("Turning on screen\n");
|
||||
dispdev.displayOn();
|
||||
dispdev.displayOn();
|
||||
enabled = true;
|
||||
setInterval(0); // Draw ASAP
|
||||
runASAP = true;
|
||||
} else {
|
||||
DEBUG_MSG("Turning off screen\n");
|
||||
LOG_INFO("Turning off screen\n");
|
||||
dispdev.displayOff();
|
||||
enabled = false;
|
||||
}
|
||||
@@ -1020,7 +1056,7 @@ int32_t Screen::runOnce()
|
||||
// serialSinceMsec adjusts for additional serial wait time during nRF52 bootup
|
||||
static bool showingBootScreen = true;
|
||||
if (showingBootScreen && (millis() > (logo_timeout + serialSinceMsec))) {
|
||||
DEBUG_MSG("Done with boot screen...\n");
|
||||
LOG_INFO("Done with boot screen...\n");
|
||||
stopBootScreen();
|
||||
showingBootScreen = false;
|
||||
}
|
||||
@@ -1029,7 +1065,7 @@ int32_t Screen::runOnce()
|
||||
if (strlen(oemStore.oem_text) > 0) {
|
||||
static bool showingOEMBootScreen = true;
|
||||
if (showingOEMBootScreen && (millis() > ((logo_timeout / 2) + serialSinceMsec))) {
|
||||
DEBUG_MSG("Switch to OEM screen...\n");
|
||||
LOG_INFO("Switch to OEM screen...\n");
|
||||
// Change frames.
|
||||
static FrameCallback bootOEMFrames[] = {drawOEMBootScreen};
|
||||
static const int bootOEMFrameCount = sizeof(bootOEMFrames) / sizeof(bootOEMFrames[0]);
|
||||
@@ -1062,7 +1098,13 @@ int32_t Screen::runOnce()
|
||||
handleSetOn(false);
|
||||
break;
|
||||
case Cmd::ON_PRESS:
|
||||
// If a nag notification is running, stop it
|
||||
if (moduleConfig.external_notification.enabled && (externalNotificationModule->nagCycleCutoff != UINT32_MAX)) {
|
||||
externalNotificationModule->stopNow();
|
||||
} else {
|
||||
// Don't advance the screen if we just wanted to switch off the nag notification
|
||||
handleOnPress();
|
||||
}
|
||||
break;
|
||||
case Cmd::START_BLUETOOTH_PIN_SCREEN:
|
||||
handleStartBluetoothPinScreen(cmd.bluetooth_pin);
|
||||
@@ -1085,7 +1127,7 @@ int32_t Screen::runOnce()
|
||||
handleRebootScreen();
|
||||
break;
|
||||
default:
|
||||
DEBUG_MSG("BUG: invalid cmd\n");
|
||||
LOG_ERROR("Invalid screen cmd\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1116,12 +1158,12 @@ int32_t Screen::runOnce()
|
||||
// standard screen loop handling here
|
||||
if (config.display.auto_screen_carousel_secs > 0 &&
|
||||
(millis() - lastScreenTransition) > (config.display.auto_screen_carousel_secs * 1000)) {
|
||||
DEBUG_MSG("LastScreenTransition exceeded %ums transitioning to next frame\n", (millis() - lastScreenTransition));
|
||||
LOG_DEBUG("LastScreenTransition exceeded %ums transitioning to next frame\n", (millis() - lastScreenTransition));
|
||||
handleOnPress();
|
||||
}
|
||||
}
|
||||
|
||||
// DEBUG_MSG("want fps %d, fixed=%d\n", targetFramerate,
|
||||
// LOG_DEBUG("want fps %d, fixed=%d\n", targetFramerate,
|
||||
// ui.getUiState()->frameState); If we are scrolling we need to be called
|
||||
// soon, otherwise just 1 fps (to save CPU) We also ask to be called twice
|
||||
// as fast as we really need so that any rounding errors still result with
|
||||
@@ -1152,7 +1194,7 @@ void Screen::drawDebugInfoWiFiTrampoline(OLEDDisplay *display, OLEDDisplayUiStat
|
||||
void Screen::setSSLFrames()
|
||||
{
|
||||
if (address_found) {
|
||||
// DEBUG_MSG("showing SSL frames\n");
|
||||
// LOG_DEBUG("showing SSL frames\n");
|
||||
static FrameCallback sslFrames[] = {drawSSLScreen};
|
||||
ui.setFrames(sslFrames, 1);
|
||||
ui.update();
|
||||
@@ -1164,7 +1206,7 @@ void Screen::setSSLFrames()
|
||||
void Screen::setWelcomeFrames()
|
||||
{
|
||||
if (address_found) {
|
||||
// DEBUG_MSG("showing Welcome frames\n");
|
||||
// LOG_DEBUG("showing Welcome frames\n");
|
||||
ui.disableAllIndicators();
|
||||
|
||||
static FrameCallback welcomeFrames[] = {drawWelcomeScreen};
|
||||
@@ -1176,13 +1218,13 @@ void Screen::setWelcomeFrames()
|
||||
// restore our regular frame list
|
||||
void Screen::setFrames()
|
||||
{
|
||||
DEBUG_MSG("showing standard frames\n");
|
||||
LOG_DEBUG("showing standard frames\n");
|
||||
showingNormalScreen = true;
|
||||
|
||||
moduleFrames = MeshModule::GetMeshModulesWithUIFrames();
|
||||
DEBUG_MSG("Showing %d module frames\n", moduleFrames.size());
|
||||
LOG_DEBUG("Showing %d module frames\n", moduleFrames.size());
|
||||
int totalFrameCount = MAX_NUM_NODES + NUM_EXTRA_FRAMES + moduleFrames.size();
|
||||
DEBUG_MSG("Total frame count: %d\n", totalFrameCount);
|
||||
LOG_DEBUG("Total frame count: %d\n", totalFrameCount);
|
||||
|
||||
// We don't show the node info our our node (if we have it yet - we should)
|
||||
size_t numnodes = nodeStatus->getNumTotal();
|
||||
@@ -1201,7 +1243,7 @@ void Screen::setFrames()
|
||||
normalFrames[numframes++] = drawModuleFrame;
|
||||
}
|
||||
|
||||
DEBUG_MSG("Added modules. numframes: %d\n", numframes);
|
||||
LOG_DEBUG("Added modules. numframes: %d\n", numframes);
|
||||
|
||||
// If we have a critical fault, show it first
|
||||
if (myNodeInfo.error_code)
|
||||
@@ -1234,7 +1276,7 @@ void Screen::setFrames()
|
||||
}
|
||||
#endif
|
||||
|
||||
DEBUG_MSG("Finished building frames. numframes: %d\n", numframes);
|
||||
LOG_DEBUG("Finished building frames. numframes: %d\n", numframes);
|
||||
|
||||
ui.setFrames(normalFrames, numframes);
|
||||
ui.enableAllIndicators();
|
||||
@@ -1247,7 +1289,7 @@ void Screen::setFrames()
|
||||
|
||||
void Screen::handleStartBluetoothPinScreen(uint32_t pin)
|
||||
{
|
||||
DEBUG_MSG("showing bluetooth screen\n");
|
||||
LOG_DEBUG("showing bluetooth screen\n");
|
||||
showingNormalScreen = false;
|
||||
|
||||
static FrameCallback btFrames[] = {drawFrameBluetooth};
|
||||
@@ -1261,7 +1303,7 @@ void Screen::handleStartBluetoothPinScreen(uint32_t pin)
|
||||
|
||||
void Screen::handleShutdownScreen()
|
||||
{
|
||||
DEBUG_MSG("showing shutdown screen\n");
|
||||
LOG_DEBUG("showing shutdown screen\n");
|
||||
showingNormalScreen = false;
|
||||
|
||||
static FrameCallback shutdownFrames[] = {drawFrameShutdown};
|
||||
@@ -1273,7 +1315,7 @@ void Screen::handleShutdownScreen()
|
||||
|
||||
void Screen::handleRebootScreen()
|
||||
{
|
||||
DEBUG_MSG("showing reboot screen\n");
|
||||
LOG_DEBUG("showing reboot screen\n");
|
||||
showingNormalScreen = false;
|
||||
|
||||
static FrameCallback rebootFrames[] = {drawFrameReboot};
|
||||
@@ -1285,7 +1327,7 @@ void Screen::handleRebootScreen()
|
||||
|
||||
void Screen::handleStartFirmwareUpdateScreen()
|
||||
{
|
||||
DEBUG_MSG("showing firmware screen\n");
|
||||
LOG_DEBUG("showing firmware screen\n");
|
||||
showingNormalScreen = false;
|
||||
|
||||
static FrameCallback btFrames[] = {drawFrameFirmware};
|
||||
@@ -1316,7 +1358,7 @@ void Screen::handlePrint(const char *text)
|
||||
{
|
||||
// the string passed into us probably has a newline, but that would confuse the logging system
|
||||
// so strip it
|
||||
DEBUG_MSG("Screen: %.*s\n", strlen(text) - 1, text);
|
||||
LOG_DEBUG("Screen: %.*s\n", strlen(text) - 1, text);
|
||||
if (!useDisplay || !showingNormalScreen)
|
||||
return;
|
||||
|
||||
@@ -1357,6 +1399,11 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
||||
// The coordinates define the left starting point of the text
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
|
||||
if (config.display.displaymode == Config_DisplayConfig_DisplayMode_INVERTED) {
|
||||
display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL);
|
||||
display->setColor(BLACK);
|
||||
}
|
||||
|
||||
char channelStr[20];
|
||||
{
|
||||
concurrency::LockGuard guard(&lock);
|
||||
@@ -1365,19 +1412,71 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
||||
}
|
||||
|
||||
// Display power status
|
||||
if (powerStatus->getHasBattery())
|
||||
drawBattery(display, x, y + 2, imgBattery, powerStatus);
|
||||
else if (powerStatus->knowsUSB())
|
||||
if (powerStatus->getHasBattery()) {
|
||||
if (config.display.displaymode == Config_DisplayConfig_DisplayMode_DEFAULT) {
|
||||
drawBattery(display, x , y + 2, imgBattery, powerStatus);
|
||||
} else {
|
||||
drawBattery(display, x + 1, y + 3, imgBattery, powerStatus);
|
||||
}
|
||||
} else if (powerStatus->knowsUSB()) {
|
||||
if (config.display.displaymode == Config_DisplayConfig_DisplayMode_DEFAULT) {
|
||||
display->drawFastImage(x, y + 2, 16, 8, powerStatus->getHasUSB() ? imgUSB : imgPower);
|
||||
} else {
|
||||
display->drawFastImage(x + 1, y + 3, 16, 8, powerStatus->getHasUSB() ? imgUSB : imgPower);
|
||||
}
|
||||
}
|
||||
// Display nodes status
|
||||
if (config.display.displaymode == Config_DisplayConfig_DisplayMode_DEFAULT) {
|
||||
drawNodes(display, x + (SCREEN_WIDTH * 0.25), y + 2, nodeStatus);
|
||||
} else {
|
||||
drawNodes(display, x + (SCREEN_WIDTH * 0.25), y + 3, nodeStatus);
|
||||
}
|
||||
// Display GPS status
|
||||
if (!config.position.gps_enabled){
|
||||
int16_t yPos = y + 2;
|
||||
#ifdef GPS_POWER_TOGGLE
|
||||
yPos = (y + 10 + FONT_HEIGHT_SMALL);
|
||||
#endif
|
||||
drawGPSpowerstat(display, x, yPos, gpsStatus);
|
||||
} else {
|
||||
if (config.display.displaymode == Config_DisplayConfig_DisplayMode_DEFAULT) {
|
||||
drawGPS(display, x + (SCREEN_WIDTH * 0.63), y + 2, gpsStatus);
|
||||
} else {
|
||||
drawGPS(display, x + (SCREEN_WIDTH * 0.63), y + 3, gpsStatus);
|
||||
}
|
||||
}
|
||||
|
||||
display->setColor(WHITE);
|
||||
// Draw the channel name
|
||||
display->drawString(x, y + FONT_HEIGHT_SMALL, channelStr);
|
||||
// Draw our hardware ID to assist with bluetooth pairing
|
||||
display->drawFastImage(x + SCREEN_WIDTH - (10) - display->getStringWidth(ourId), y + 2 + FONT_HEIGHT_SMALL, 8, 8, imgInfo);
|
||||
// Draw our hardware ID to assist with bluetooth pairing. Either prefix with Info or S&F Logo
|
||||
if (moduleConfig.store_forward.enabled) {
|
||||
#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)
|
||||
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, imgQuestionL2);
|
||||
#else
|
||||
display->drawFastImage(x + SCREEN_WIDTH - 10 - display->getStringWidth(ourId), y + 2 + FONT_HEIGHT_SMALL, 8, 8, imgQuestion);
|
||||
#endif
|
||||
} else {
|
||||
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS)
|
||||
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, imgSFL2);
|
||||
#else
|
||||
display->drawFastImage(x + SCREEN_WIDTH - 13 - display->getStringWidth(ourId), y + 2 + FONT_HEIGHT_SMALL, 11, 8, imgSF);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS)
|
||||
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, imgInfoL2);
|
||||
#else
|
||||
display->drawFastImage(x + SCREEN_WIDTH - 10 - display->getStringWidth(ourId), y + 2 + FONT_HEIGHT_SMALL, 8, 8, imgInfo);
|
||||
#endif
|
||||
}
|
||||
|
||||
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(ourId), y + FONT_HEIGHT_SMALL, ourId);
|
||||
|
||||
// Draw any log messages
|
||||
@@ -1404,14 +1503,29 @@ void DebugInfo::drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, i
|
||||
// The coordinates define the left starting point of the text
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
|
||||
if (config.display.displaymode == Config_DisplayConfig_DisplayMode_INVERTED) {
|
||||
display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL);
|
||||
display->setColor(BLACK);
|
||||
}
|
||||
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
display->drawString(x, y, String("WiFi: Not Connected"));
|
||||
if(config.display.heading_bold)
|
||||
display->drawString(x + 1, y, String("WiFi: Not Connected"));
|
||||
} else {
|
||||
display->drawString(x, y, String("WiFi: Connected"));
|
||||
if(config.display.heading_bold)
|
||||
display->drawString(x + 1, y, String("WiFi: Connected"));
|
||||
|
||||
display->drawString(x + SCREEN_WIDTH - display->getStringWidth("RSSI " + String(WiFi.RSSI())), y,
|
||||
"RSSI " + String(WiFi.RSSI()));
|
||||
if(config.display.heading_bold) {
|
||||
display->drawString(x + SCREEN_WIDTH - display->getStringWidth("RSSI " + String(WiFi.RSSI())) - 1, y,
|
||||
"RSSI " + String(WiFi.RSSI()));
|
||||
}
|
||||
}
|
||||
|
||||
display->setColor(WHITE);
|
||||
|
||||
/*
|
||||
- WL_CONNECTED: assigned when connected to a WiFi network;
|
||||
@@ -1521,6 +1635,11 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
|
||||
// The coordinates define the left starting point of the text
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
|
||||
if (config.display.displaymode == Config_DisplayConfig_DisplayMode_INVERTED) {
|
||||
display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL);
|
||||
display->setColor(BLACK);
|
||||
}
|
||||
|
||||
char batStr[20];
|
||||
if (powerStatus->getHasBattery()) {
|
||||
int batV = powerStatus->getBatteryVoltageMv() / 1000;
|
||||
@@ -1531,9 +1650,13 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
|
||||
|
||||
// Line 1
|
||||
display->drawString(x, y, batStr);
|
||||
if(config.display.heading_bold)
|
||||
display->drawString(x + 1, y, batStr);
|
||||
} else {
|
||||
// Line 1
|
||||
display->drawString(x, y, String("USB"));
|
||||
if(config.display.heading_bold)
|
||||
display->drawString(x + 1, y, String("USB"));
|
||||
}
|
||||
|
||||
auto mode = "";
|
||||
@@ -1566,6 +1689,8 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
|
||||
}
|
||||
|
||||
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(mode), y, mode);
|
||||
if(config.display.heading_bold)
|
||||
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(mode) - 1, y, mode);
|
||||
|
||||
// Line 2
|
||||
uint32_t currentMillis = millis();
|
||||
@@ -1578,6 +1703,8 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
|
||||
// minutes %= 60;
|
||||
// hours %= 24;
|
||||
|
||||
display->setColor(WHITE);
|
||||
|
||||
// Show uptime as days, hours, minutes OR seconds
|
||||
String uptime;
|
||||
if (days >= 2)
|
||||
@@ -1613,7 +1740,7 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
|
||||
char chUtil[13];
|
||||
sprintf(chUtil, "ChUtil %2.0f%%", airTime->channelUtilizationPercent());
|
||||
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(chUtil), y + FONT_HEIGHT_SMALL * 1, chUtil);
|
||||
|
||||
if (config.position.gps_enabled) {
|
||||
// Line 3
|
||||
if (config.display.gps_format !=
|
||||
Config_DisplayConfig_GpsCoordinateFormat_DMS) // if DMS then don't draw altitude
|
||||
@@ -1621,7 +1748,9 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
|
||||
|
||||
// Line 4
|
||||
drawGPScoordinates(display, x, y + FONT_HEIGHT_SMALL * 3, gpsStatus);
|
||||
|
||||
} else {
|
||||
drawGPSpowerstat(display, x - (SCREEN_WIDTH / 4), y + FONT_HEIGHT_SMALL * 2, gpsStatus);
|
||||
}
|
||||
/* Display a heartbeat pixel that blinks every time the frame is redrawn */
|
||||
#ifdef SHOW_REDRAWS
|
||||
if (heartbeat)
|
||||
@@ -1649,7 +1778,7 @@ void Screen::adjustBrightness()
|
||||
|
||||
int Screen::handleStatusUpdate(const meshtastic::Status *arg)
|
||||
{
|
||||
// DEBUG_MSG("Screen got status update %d\n", arg->getStatusType());
|
||||
// LOG_DEBUG("Screen got status update %d\n", arg->getStatusType());
|
||||
switch (arg->getStatusType()) {
|
||||
case STATUS_TYPE_NODE:
|
||||
if (showingNormalScreen && nodeStatus->getLastNumTotal() != nodeStatus->getNumTotal()) {
|
||||
|
||||
@@ -21,6 +21,7 @@ class Screen
|
||||
void startBluetoothPinScreen(uint32_t pin) {}
|
||||
void stopBluetoothPinScreen() {}
|
||||
void startRebootScreen() {}
|
||||
void startFirmwareUpdateScreen() {}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ void TFTDisplay::setDetected(uint8_t detected)
|
||||
bool TFTDisplay::connect()
|
||||
{
|
||||
concurrency::LockGuard g(spiLock);
|
||||
DEBUG_MSG("Doing TFT init\n");
|
||||
LOG_INFO("Doing TFT init\n");
|
||||
|
||||
#ifdef TFT_BL
|
||||
digitalWrite(TFT_BL, HIGH);
|
||||
|
||||
@@ -12,36 +12,18 @@ const uint8_t imgPower[] PROGMEM = { 0x40, 0x40, 0x40, 0x58, 0x48, 0x08,
|
||||
const uint8_t imgUser[] PROGMEM = { 0x3C, 0x42, 0x99, 0xA5, 0xA5, 0x99, 0x42, 0x3C };
|
||||
const uint8_t imgPositionEmpty[] PROGMEM = { 0x20, 0x30, 0x28, 0x24, 0x42, 0xFF };
|
||||
const uint8_t imgPositionSolid[] PROGMEM = { 0x20, 0x30, 0x38, 0x3C, 0x7E, 0xFF };
|
||||
const uint8_t imgInfo[] PROGMEM = { 0xFF, 0x81, 0x81, 0xB5, 0xB5, 0x81, 0x81, 0xFF };
|
||||
|
||||
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS)
|
||||
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 };
|
||||
const uint8_t imgInfoL2[] PROGMEM = { 0x0f, 0x08, 0x08, 0x08, 0x06, 0x0f, 0x0f, 0x06, 0x08, 0x08, 0x08, 0x0f };
|
||||
const uint8_t imgSFL1[] PROGMEM = { 0xb6, 0x8f, 0x19, 0x11, 0x31, 0xe3, 0xc2, 0x01, 0x01, 0xf9, 0xf9, 0x89, 0x89, 0x89, 0x09, 0xeb};
|
||||
const uint8_t imgSFL2[] PROGMEM = { 0x0e, 0x09, 0x09, 0x09, 0x09, 0x09, 0x08, 0x08, 0x00, 0x0f, 0x0f, 0x00, 0x08, 0x08, 0x08, 0x0f};
|
||||
#else
|
||||
const uint8_t imgInfo[] PROGMEM = { 0xff, 0x81, 0x00, 0xfb, 0xfb, 0x00, 0x81, 0xff };
|
||||
const uint8_t imgQuestion[] PROGMEM = { 0xbf, 0x41, 0xc0, 0x8b, 0xdb, 0x70, 0xa1, 0xdf };
|
||||
const uint8_t imgSF[] PROGMEM = { 0xd2, 0xb7, 0xad, 0xbb, 0x92, 0x01, 0xfd, 0xfd, 0x15, 0x85, 0xf5};
|
||||
#endif
|
||||
|
||||
#include "img/icon.xbm"
|
||||
|
||||
// We now programmatically draw our compass
|
||||
#if 0
|
||||
const
|
||||
#include "img/compass.xbm"
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
const uint8_t activeSymbol[] PROGMEM = {
|
||||
B00000000,
|
||||
B00000000,
|
||||
B00011000,
|
||||
B00100100,
|
||||
B01000010,
|
||||
B01000010,
|
||||
B00100100,
|
||||
B00011000
|
||||
};
|
||||
|
||||
const uint8_t inactiveSymbol[] PROGMEM = {
|
||||
B00000000,
|
||||
B00000000,
|
||||
B00000000,
|
||||
B00000000,
|
||||
B00011000,
|
||||
B00011000,
|
||||
B00000000,
|
||||
B00000000
|
||||
};
|
||||
#endif
|
||||
@@ -1,28 +0,0 @@
|
||||
#define compass_width 48
|
||||
#define compass_height 48
|
||||
static char compass_bits[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00,
|
||||
0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00,
|
||||
0x00, 0x00, 0xFC, 0x3F, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x01, 0x00,
|
||||
0x00, 0xC0, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0x0F, 0x00,
|
||||
0x00, 0xF8, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0xFC, 0x07, 0xE0, 0x3F, 0x00,
|
||||
0x00, 0xFE, 0x01, 0x80, 0x7F, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x7F, 0x00,
|
||||
0x00, 0x7F, 0x00, 0x00, 0xFE, 0x00, 0x80, 0x3F, 0x00, 0x00, 0xFC, 0x01,
|
||||
0x80, 0x1F, 0x00, 0x00, 0xF8, 0x01, 0x80, 0x0F, 0x00, 0x00, 0xF0, 0x01,
|
||||
0xC0, 0x0F, 0x00, 0x00, 0xF0, 0x03, 0xC0, 0x07, 0x00, 0x00, 0xE0, 0x03,
|
||||
0xC0, 0x07, 0x00, 0x00, 0xE0, 0x03, 0xC0, 0x07, 0x00, 0x00, 0xE0, 0x03,
|
||||
0xFC, 0x07, 0x00, 0x00, 0xE0, 0x3F, 0xFC, 0x07, 0x00, 0x00, 0xE0, 0x3F,
|
||||
0xFC, 0x07, 0x00, 0x00, 0xE0, 0x3F, 0xFC, 0x07, 0x00, 0x00, 0xE0, 0x3F,
|
||||
0xC0, 0x07, 0x00, 0x00, 0xE0, 0x03, 0xC0, 0x07, 0x00, 0x00, 0xE0, 0x03,
|
||||
0xC0, 0x07, 0x00, 0x00, 0xE0, 0x03, 0xC0, 0x0F, 0x00, 0x00, 0xF0, 0x03,
|
||||
0x80, 0x0F, 0x00, 0x00, 0xF0, 0x01, 0x80, 0x1F, 0x00, 0x00, 0xF8, 0x01,
|
||||
0x80, 0x3F, 0x00, 0x00, 0xFC, 0x01, 0x00, 0x7F, 0x00, 0x00, 0xFE, 0x00,
|
||||
0x00, 0xFE, 0x00, 0x00, 0x7F, 0x00, 0x00, 0xFE, 0x01, 0x80, 0x7F, 0x00,
|
||||
0x00, 0xFC, 0x07, 0xE0, 0x3F, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x1F, 0x00,
|
||||
0x00, 0xF0, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0x03, 0x00,
|
||||
0x00, 0x80, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0xFC, 0x3F, 0x00, 0x00,
|
||||
0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00,
|
||||
0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
@@ -1,6 +0,0 @@
|
||||
#define pin_width 13
|
||||
#define pin_height 13
|
||||
static char pin_bits[] = {
|
||||
0x00, 0x00, 0xF0, 0x01, 0xF8, 0x03, 0xFC, 0x07, 0xBC, 0x07, 0xBC, 0x07,
|
||||
0xFC, 0x07, 0xF8, 0x03, 0xF8, 0x03, 0xF0, 0x01, 0xE0, 0x00, 0xE0, 0x00,
|
||||
0x00, 0x00, };
|
||||
@@ -28,7 +28,7 @@ void RotaryEncoderInterruptBase::init(
|
||||
|
||||
this->rotaryLevelA = digitalRead(this->_pinA);
|
||||
this->rotaryLevelB = digitalRead(this->_pinB);
|
||||
DEBUG_MSG("Rotary initialized (%d, %d, %d)\n", this->_pinA, this->_pinB, pinPress);
|
||||
LOG_INFO("Rotary initialized (%d, %d, %d)\n", this->_pinA, this->_pinB, pinPress);
|
||||
}
|
||||
|
||||
int32_t RotaryEncoderInterruptBase::runOnce()
|
||||
@@ -38,13 +38,13 @@ int32_t RotaryEncoderInterruptBase::runOnce()
|
||||
e.source = this->_originName;
|
||||
|
||||
if (this->action == ROTARY_ACTION_PRESSED) {
|
||||
DEBUG_MSG("Rotary event Press\n");
|
||||
LOG_DEBUG("Rotary event Press\n");
|
||||
e.inputEvent = this->_eventPressed;
|
||||
} else if (this->action == ROTARY_ACTION_CW) {
|
||||
DEBUG_MSG("Rotary event CW\n");
|
||||
LOG_DEBUG("Rotary event CW\n");
|
||||
e.inputEvent = this->_eventCw;
|
||||
} else if (this->action == ROTARY_ACTION_CCW) {
|
||||
DEBUG_MSG("Rotary event CCW\n");
|
||||
LOG_DEBUG("Rotary event CCW\n");
|
||||
e.inputEvent = this->_eventCcw;
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ int32_t RotaryEncoderInterruptBase::runOnce()
|
||||
|
||||
this->action = ROTARY_ACTION_NONE;
|
||||
|
||||
return 30000; // TODO: technically this can be MAX_INT
|
||||
return INT32_MAX;
|
||||
}
|
||||
|
||||
void RotaryEncoderInterruptBase::intPressHandler()
|
||||
@@ -104,7 +104,7 @@ RotaryEncoderInterruptBaseStateType RotaryEncoderInterruptBase::intHandler(bool
|
||||
newState = ROTARY_EVENT_OCCURRED;
|
||||
if ((this->action != ROTARY_ACTION_PRESSED) && (this->action != action)) {
|
||||
this->action = action;
|
||||
DEBUG_MSG("Rotary action\n");
|
||||
LOG_DEBUG("Rotary action\n");
|
||||
}
|
||||
}
|
||||
} else if (!actualPinRaising && (otherPinLevel == HIGH)) {
|
||||
|
||||
@@ -7,7 +7,7 @@ enum RotaryEncoderInterruptBaseStateType { ROTARY_EVENT_OCCURRED, ROTARY_EVENT_C
|
||||
|
||||
enum RotaryEncoderInterruptBaseActionType { ROTARY_ACTION_NONE, ROTARY_ACTION_PRESSED, ROTARY_ACTION_CW, ROTARY_ACTION_CCW };
|
||||
|
||||
class RotaryEncoderInterruptBase : public Observable<const InputEvent *>, private concurrency::OSThread
|
||||
class RotaryEncoderInterruptBase : public Observable<const InputEvent *>, public concurrency::OSThread
|
||||
{
|
||||
public:
|
||||
explicit RotaryEncoderInterruptBase(const char *name);
|
||||
|
||||
@@ -9,6 +9,7 @@ void RotaryEncoderInterruptImpl1::init()
|
||||
{
|
||||
if (!moduleConfig.canned_message.rotary1_enabled) {
|
||||
// Input device is disabled.
|
||||
disable();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ void UpDownInterruptBase::init(
|
||||
attachInterrupt(this->_pinDown, onIntDown, RISING);
|
||||
attachInterrupt(this->_pinUp, onIntUp, RISING);
|
||||
|
||||
DEBUG_MSG("GPIO initialized (%d, %d, %d)\n",
|
||||
LOG_DEBUG("GPIO initialized (%d, %d, %d)\n",
|
||||
this->_pinDown, this->_pinUp, pinPress);
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ void UpDownInterruptBase::intPressHandler()
|
||||
{
|
||||
InputEvent e;
|
||||
e.source = this->_originName;
|
||||
DEBUG_MSG("GPIO event Press\n");
|
||||
LOG_DEBUG("GPIO event Press\n");
|
||||
e.inputEvent = this->_eventPressed;
|
||||
this->notifyObservers(&e);
|
||||
}
|
||||
@@ -43,7 +43,7 @@ void UpDownInterruptBase::intDownHandler()
|
||||
{
|
||||
InputEvent e;
|
||||
e.source = this->_originName;
|
||||
DEBUG_MSG("GPIO event Down\n");
|
||||
LOG_DEBUG("GPIO event Down\n");
|
||||
e.inputEvent = this->_eventDown;
|
||||
this->notifyObservers(&e);
|
||||
}
|
||||
@@ -52,7 +52,7 @@ void UpDownInterruptBase::intUpHandler()
|
||||
{
|
||||
InputEvent e;
|
||||
e.source = this->_originName;
|
||||
DEBUG_MSG("GPIO event Up\n");
|
||||
LOG_DEBUG("GPIO event Up\n");
|
||||
e.inputEvent = this->_eventUp;
|
||||
this->notifyObservers(&e);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ void CardKbI2cImpl::init()
|
||||
{
|
||||
if (cardkb_found != CARDKB_ADDR)
|
||||
{
|
||||
// Input device is not detected.
|
||||
disable();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ int32_t KbI2cBase::runOnce()
|
||||
}
|
||||
}
|
||||
if (PrintDataBuf != 0) {
|
||||
DEBUG_MSG("RAK14004 key 0x%x pressed\n", PrintDataBuf);
|
||||
LOG_DEBUG("RAK14004 key 0x%x pressed\n", PrintDataBuf);
|
||||
InputEvent e;
|
||||
e.inputEvent = MATRIXKEY;
|
||||
e.source = this->_originName;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
class KbI2cBase :
|
||||
public Observable<const InputEvent *>,
|
||||
private concurrency::OSThread
|
||||
public concurrency::OSThread
|
||||
{
|
||||
public:
|
||||
explicit KbI2cBase(const char *name);
|
||||
|
||||
67
src/main.cpp
67
src/main.cpp
@@ -8,8 +8,6 @@
|
||||
#include "configuration.h"
|
||||
#include "error.h"
|
||||
#include "power.h"
|
||||
// #include "rom/rtc.h"
|
||||
//#include "DSRRouter.h"
|
||||
#include "ReliableRouter.h"
|
||||
// #include "debug.h"
|
||||
#include "FSCommon.h"
|
||||
@@ -38,12 +36,12 @@
|
||||
#endif
|
||||
|
||||
#if HAS_WIFI
|
||||
#include "mesh/wifi/WiFiServerAPI.h"
|
||||
#include "mesh/api/WiFiServerAPI.h"
|
||||
#include "mqtt/MQTT.h"
|
||||
#endif
|
||||
|
||||
#if HAS_ETHERNET
|
||||
#include "mesh/eth/ethServerAPI.h"
|
||||
#include "mesh/api/ethServerAPI.h"
|
||||
#include "mqtt/MQTT.h"
|
||||
#endif
|
||||
|
||||
@@ -176,7 +174,7 @@ void setup()
|
||||
|
||||
serialSinceMsec = millis();
|
||||
|
||||
DEBUG_MSG("\n\n//\\ E S H T /\\ S T / C\n\n");
|
||||
LOG_INFO("\n\n//\\ E S H T /\\ S T / C\n\n");
|
||||
|
||||
initDeepSleep();
|
||||
|
||||
@@ -217,7 +215,6 @@ void setup()
|
||||
|
||||
fsInit();
|
||||
|
||||
// router = new DSRRouter();
|
||||
router = new ReliableRouter();
|
||||
|
||||
#ifdef I2C_SDA1
|
||||
@@ -242,10 +239,9 @@ void setup()
|
||||
#ifdef RAK4630
|
||||
// We need to enable 3.3V periphery in order to scan it
|
||||
pinMode(PIN_3V3_EN, OUTPUT);
|
||||
digitalWrite(PIN_3V3_EN, 1);
|
||||
digitalWrite(PIN_3V3_EN, HIGH);
|
||||
#endif
|
||||
|
||||
|
||||
// Currently only the tbeam has a PMU
|
||||
// PMU initialization needs to be placed before scanI2Cdevice
|
||||
power = new Power();
|
||||
@@ -260,7 +256,7 @@ void setup()
|
||||
Wire1.beginTransmission(PCF8563_RTC);
|
||||
if (Wire1.endTransmission() == 0){
|
||||
rtc_found = PCF8563_RTC;
|
||||
DEBUG_MSG("PCF8563 RTC found\n");
|
||||
LOG_INFO("PCF8563 RTC found\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -286,7 +282,7 @@ void setup()
|
||||
#endif
|
||||
|
||||
// Hello
|
||||
DEBUG_MSG("Meshtastic hwvendor=%d, swver=%s\n", HW_VENDOR, optstr(APP_VERSION));
|
||||
LOG_INFO("Meshtastic hwvendor=%d, swver=%s\n", HW_VENDOR, optstr(APP_VERSION));
|
||||
|
||||
#ifdef ARCH_ESP32
|
||||
// Don't init display if we don't have one or we are waking headless due to a timer event
|
||||
@@ -329,7 +325,7 @@ void setup()
|
||||
if (gps)
|
||||
gpsStatus->observe(&gps->newStatus);
|
||||
else
|
||||
DEBUG_MSG("Warning: No GPS found - running without GPS\n");
|
||||
LOG_WARN("No GPS found - running without GPS\n");
|
||||
|
||||
nodeStatus->observe(&nodeDB.newStatus);
|
||||
|
||||
@@ -359,7 +355,7 @@ void setup()
|
||||
|
||||
// ONCE we will factory reset the GPS for bug #327
|
||||
if (gps && !devicestate.did_gps_reset) {
|
||||
DEBUG_MSG("GPS FactoryReset requested\n");
|
||||
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);
|
||||
@@ -378,24 +374,24 @@ void setup()
|
||||
if (!rIf) {
|
||||
rIf = new RF95Interface(RF95_NSS, RF95_IRQ, RF95_RESET, SPI);
|
||||
if (!rIf->init()) {
|
||||
DEBUG_MSG("Warning: Failed to find RF95 radio\n");
|
||||
LOG_WARN("Failed to find RF95 radio\n");
|
||||
delete rIf;
|
||||
rIf = NULL;
|
||||
} else {
|
||||
DEBUG_MSG("RF95 Radio init succeeded, using RF95 radio\n");
|
||||
LOG_INFO("RF95 Radio init succeeded, using RF95 radio\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(USE_SX1280) && !defined(ARCH_PORTDUINO)
|
||||
#if defined(USE_SX1280)
|
||||
if (!rIf) {
|
||||
rIf = new SX1280Interface(SX128X_CS, SX128X_DIO1, SX128X_RESET, SX128X_BUSY, SPI);
|
||||
if (!rIf->init()) {
|
||||
DEBUG_MSG("Warning: Failed to find SX1280 radio\n");
|
||||
LOG_WARN("Failed to find SX1280 radio\n");
|
||||
delete rIf;
|
||||
rIf = NULL;
|
||||
} else {
|
||||
DEBUG_MSG("SX1280 Radio init succeeded, using SX1280 radio\n");
|
||||
LOG_INFO("SX1280 Radio init succeeded, using SX1280 radio\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -404,11 +400,11 @@ void setup()
|
||||
if (!rIf) {
|
||||
rIf = new SX1262Interface(SX126X_CS, SX126X_DIO1, SX126X_RESET, SX126X_BUSY, SPI);
|
||||
if (!rIf->init()) {
|
||||
DEBUG_MSG("Warning: Failed to find SX1262 radio\n");
|
||||
LOG_WARN("Failed to find SX1262 radio\n");
|
||||
delete rIf;
|
||||
rIf = NULL;
|
||||
} else {
|
||||
DEBUG_MSG("SX1262 Radio init succeeded, using SX1262 radio\n");
|
||||
LOG_INFO("SX1262 Radio init succeeded, using SX1262 radio\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -417,11 +413,11 @@ void setup()
|
||||
if (!rIf) {
|
||||
rIf = new SX1268Interface(SX126X_CS, SX126X_DIO1, SX126X_RESET, SX126X_BUSY, SPI);
|
||||
if (!rIf->init()) {
|
||||
DEBUG_MSG("Warning: Failed to find SX1268 radio\n");
|
||||
LOG_WARN("Failed to find SX1268 radio\n");
|
||||
delete rIf;
|
||||
rIf = NULL;
|
||||
} else {
|
||||
DEBUG_MSG("SX1268 Radio init succeeded, using SX1268 radio\n");
|
||||
LOG_INFO("SX1268 Radio init succeeded, using SX1268 radio\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -430,11 +426,11 @@ void setup()
|
||||
if (!rIf) {
|
||||
rIf = new LLCC68Interface(SX126X_CS, SX126X_DIO1, SX126X_RESET, SX126X_BUSY, SPI);
|
||||
if (!rIf->init()) {
|
||||
DEBUG_MSG("Warning: Failed to find LLCC68 radio\n");
|
||||
LOG_WARN("Failed to find LLCC68 radio\n");
|
||||
delete rIf;
|
||||
rIf = NULL;
|
||||
} else {
|
||||
DEBUG_MSG("LLCC68 Radio init succeeded, using LLCC68 radio\n");
|
||||
LOG_INFO("LLCC68 Radio init succeeded, using LLCC68 radio\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -443,15 +439,28 @@ void setup()
|
||||
if (!rIf) {
|
||||
rIf = new SimRadio;
|
||||
if (!rIf->init()) {
|
||||
DEBUG_MSG("Warning: Failed to find simulated radio\n");
|
||||
LOG_WARN("Failed to find simulated radio\n");
|
||||
delete rIf;
|
||||
rIf = NULL;
|
||||
} else {
|
||||
DEBUG_MSG("Using SIMULATED radio!\n");
|
||||
LOG_INFO("Using SIMULATED radio!\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// check if the radio chip matches the selected region
|
||||
|
||||
if((config.lora.region == Config_LoRaConfig_RegionCode_LORA_24) && (!rIf->wideLora())){
|
||||
LOG_WARN("Radio chip does not support 2.4GHz LoRa. Reverting to unset.\n");
|
||||
config.lora.region = Config_LoRaConfig_RegionCode_UNSET;
|
||||
nodeDB.saveToDisk(SEGMENT_CONFIG);
|
||||
if(!rIf->reconfigure()) {
|
||||
LOG_WARN("Reconfigure failed, rebooting\n");
|
||||
screen->startRebootScreen();
|
||||
rebootAtMsec = millis() + 5000;
|
||||
}
|
||||
}
|
||||
|
||||
#if HAS_WIFI || HAS_ETHERNET
|
||||
mqttInit();
|
||||
#endif
|
||||
@@ -484,7 +493,7 @@ void setup()
|
||||
// Calculate and save the bit rate to myNodeInfo
|
||||
// TODO: This needs to be added what ever method changes the channel from the phone.
|
||||
myNodeInfo.bitrate = (float(Constants_DATA_PAYLOAD_LEN) / (float(rIf->getPacketTime(Constants_DATA_PAYLOAD_LEN)))) * 1000;
|
||||
DEBUG_MSG("myNodeInfo.bitrate = %f bytes / sec\n", myNodeInfo.bitrate);
|
||||
LOG_DEBUG("myNodeInfo.bitrate = %f bytes / sec\n", myNodeInfo.bitrate);
|
||||
}
|
||||
|
||||
// This must be _after_ service.init because we need our preferences loaded from flash to have proper timeout values
|
||||
@@ -537,13 +546,13 @@ void loop()
|
||||
long delayMsec = mainController.runOrDelay();
|
||||
|
||||
/* if (mainController.nextThread && delayMsec)
|
||||
DEBUG_MSG("Next %s in %ld\n", mainController.nextThread->ThreadName.c_str(),
|
||||
LOG_DEBUG("Next %s in %ld\n", mainController.nextThread->ThreadName.c_str(),
|
||||
mainController.nextThread->tillRun(millis())); */
|
||||
|
||||
// We want to sleep as long as possible here - because it saves power
|
||||
if (!runASAP && loopCanSleep()) {
|
||||
// if(delayMsec > 100) DEBUG_MSG("sleeping %ld\n", delayMsec);
|
||||
// if(delayMsec > 100) LOG_DEBUG("sleeping %ld\n", delayMsec);
|
||||
mainDelay.delay(delayMsec);
|
||||
}
|
||||
// if (didWake) DEBUG_MSG("wake!\n");
|
||||
// if (didWake) LOG_DEBUG("wake!\n");
|
||||
}
|
||||
|
||||
318
src/memtest.cpp
318
src/memtest.cpp
@@ -1,318 +0,0 @@
|
||||
/*
|
||||
* mtest - Perform a memory test
|
||||
*
|
||||
* (C) Copyright 2000
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*/
|
||||
#include "configuration.h"
|
||||
|
||||
/*
|
||||
* Perform a memory test. A more complete alternative test can be
|
||||
* configured using CONFIG_CMD_MTEST_ALTERNATIVE. The complete test
|
||||
* loops until interrupted by ctrl-c or by a failure of one of the
|
||||
* sub-tests.
|
||||
*/
|
||||
#ifdef CONFIG_CMD_MTEST_ALTERNATIVE
|
||||
static int mem_test(uint32_t _start, uint32_t _end, uint32_t pattern_unused)
|
||||
{
|
||||
volatile uint32_t *start = (volatile uint32_t *)_start;
|
||||
volatile uint32_t *end = (volatile uint32_t *)_end;
|
||||
volatile uint32_t *addr;
|
||||
uint32_t val;
|
||||
uint32_t readback;
|
||||
vu_long addr_mask;
|
||||
vu_long offset;
|
||||
vu_long test_offset;
|
||||
vu_long pattern;
|
||||
vu_long temp;
|
||||
vu_long anti_pattern;
|
||||
vu_long num_words;
|
||||
#ifdef CFG_MEMTEST_SCRATCH
|
||||
volatile uint32_t *dummy = (vu_long *)CFG_MEMTEST_SCRATCH;
|
||||
#else
|
||||
volatile uint32_t *dummy = start;
|
||||
#endif
|
||||
int j;
|
||||
int iterations = 1;
|
||||
static const uint32_t bitpattern[] = {
|
||||
0x00000001, /* single bit */
|
||||
0x00000003, /* two adjacent bits */
|
||||
0x00000007, /* three adjacent bits */
|
||||
0x0000000F, /* four adjacent bits */
|
||||
0x00000005, /* two non-adjacent bits */
|
||||
0x00000015, /* three non-adjacent bits */
|
||||
0x00000055, /* four non-adjacent bits */
|
||||
0xaaaaaaaa, /* alternating 1/0 */
|
||||
};
|
||||
/* XXX: enforce alignment of start and end? */
|
||||
for (;;) {
|
||||
if (ctrlc()) {
|
||||
putchar('\n');
|
||||
return 1;
|
||||
}
|
||||
printf("Iteration: %6d\r", iterations);
|
||||
iterations++;
|
||||
/*
|
||||
* Data line test: write a pattern to the first
|
||||
* location, write the 1's complement to a 'parking'
|
||||
* address (changes the state of the data bus so a
|
||||
* floating bus doen't give a false OK), and then
|
||||
* read the value back. Note that we read it back
|
||||
* into a variable because the next time we read it,
|
||||
* it might be right (been there, tough to explain to
|
||||
* the quality guys why it prints a failure when the
|
||||
* "is" and "should be" are obviously the same in the
|
||||
* error message).
|
||||
*
|
||||
* Rather than exhaustively testing, we test some
|
||||
* patterns by shifting '1' bits through a field of
|
||||
* '0's and '0' bits through a field of '1's (i.e.
|
||||
* pattern and ~pattern).
|
||||
*/
|
||||
addr = start;
|
||||
/* XXX */
|
||||
if (addr == dummy)
|
||||
++addr;
|
||||
for (j = 0; j < sizeof(bitpattern) / sizeof(bitpattern[0]); j++) {
|
||||
val = bitpattern[j];
|
||||
for (; val != 0; val <<= 1) {
|
||||
*addr = val;
|
||||
*dummy = ~val; /* clear the test data off of the bus */
|
||||
readback = *addr;
|
||||
if (readback != val) {
|
||||
printf("FAILURE (data line): "
|
||||
"expected 0x%08lx, actual 0x%08lx at address 0x%p\n",
|
||||
val, readback, addr);
|
||||
}
|
||||
*addr = ~val;
|
||||
*dummy = val;
|
||||
readback = *addr;
|
||||
if (readback != ~val) {
|
||||
printf("FAILURE (data line): "
|
||||
"Is 0x%08lx, should be 0x%08lx at address 0x%p\n",
|
||||
readback, ~val, addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Based on code whose Original Author and Copyright
|
||||
* information follows: Copyright (c) 1998 by Michael
|
||||
* Barr. This software is placed into the public
|
||||
* domain and may be used for any purpose. However,
|
||||
* this notice must not be changed or removed and no
|
||||
* warranty is either expressed or implied by its
|
||||
* publication or distribution.
|
||||
*/
|
||||
/*
|
||||
* Address line test
|
||||
*
|
||||
* Description: Test the address bus wiring in a
|
||||
* memory region by performing a walking
|
||||
* 1's test on the relevant bits of the
|
||||
* address and checking for aliasing.
|
||||
* This test will find single-bit
|
||||
* address failures such as stuck -high,
|
||||
* stuck-low, and shorted pins. The base
|
||||
* address and size of the region are
|
||||
* selected by the caller.
|
||||
*
|
||||
* Notes: For best results, the selected base
|
||||
* address should have enough LSB 0's to
|
||||
* guarantee single address bit changes.
|
||||
* For example, to test a 64-Kbyte
|
||||
* region, select a base address on a
|
||||
* 64-Kbyte boundary. Also, select the
|
||||
* region size as a power-of-two if at
|
||||
* all possible.
|
||||
*
|
||||
* Returns: 0 if the test succeeds, 1 if the test fails.
|
||||
*
|
||||
* ## NOTE ## Be sure to specify start and end
|
||||
* addresses such that addr_mask has
|
||||
* lots of bits set. For example an
|
||||
* address range of 01000000 02000000 is
|
||||
* bad while a range of 01000000
|
||||
* 01ffffff is perfect.
|
||||
*/
|
||||
addr_mask = ((uint32_t)end - (uint32_t)start) / sizeof(vu_long);
|
||||
pattern = (vu_long)0xaaaaaaaa;
|
||||
anti_pattern = (vu_long)0x55555555;
|
||||
debug("%s:%d: addr mask = 0x%.8lx\n", __FUNCTION__, __LINE__, addr_mask);
|
||||
/*
|
||||
* Write the default pattern at each of the
|
||||
* power-of-two offsets.
|
||||
*/
|
||||
for (offset = 1; (offset & addr_mask) != 0; offset <<= 1)
|
||||
start[offset] = pattern;
|
||||
/*
|
||||
* Check for address bits stuck high.
|
||||
*/
|
||||
test_offset = 0;
|
||||
start[test_offset] = anti_pattern;
|
||||
for (offset = 1; (offset & addr_mask) != 0; offset <<= 1) {
|
||||
temp = start[offset];
|
||||
if (temp != pattern) {
|
||||
printf("\nFAILURE: Address bit stuck high @ 0x%.8lx:"
|
||||
" expected 0x%.8lx, actual 0x%.8lx\n",
|
||||
(uint32_t)&start[offset], pattern, temp);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
start[test_offset] = pattern;
|
||||
/*
|
||||
* Check for addr bits stuck low or shorted.
|
||||
*/
|
||||
for (test_offset = 1; (test_offset & addr_mask) != 0; test_offset <<= 1) {
|
||||
start[test_offset] = anti_pattern;
|
||||
for (offset = 1; (offset & addr_mask) != 0; offset <<= 1) {
|
||||
temp = start[offset];
|
||||
if ((temp != pattern) && (offset != test_offset)) {
|
||||
printf("\nFAILURE: Address bit stuck low or shorted @"
|
||||
" 0x%.8lx: expected 0x%.8lx, actual 0x%.8lx\n",
|
||||
(uint32_t)&start[offset], pattern, temp);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
start[test_offset] = pattern;
|
||||
}
|
||||
/*
|
||||
* Description: Test the integrity of a physical
|
||||
* memory device by performing an
|
||||
* increment/decrement test over the
|
||||
* entire region. In the process every
|
||||
* storage bit in the device is tested
|
||||
* as a zero and a one. The base address
|
||||
* and the size of the region are
|
||||
* selected by the caller.
|
||||
*
|
||||
* Returns: 0 if the test succeeds, 1 if the test fails.
|
||||
*/
|
||||
num_words = ((uint32_t)end - (uint32_t)start) / sizeof(vu_long) + 1;
|
||||
/*
|
||||
* Fill memory with a known pattern.
|
||||
*/
|
||||
for (pattern = 1, offset = 0; offset < num_words; pattern++, offset++) {
|
||||
start[offset] = pattern;
|
||||
}
|
||||
/*
|
||||
* Check each location and invert it for the second pass.
|
||||
*/
|
||||
for (pattern = 1, offset = 0; offset < num_words; pattern++, offset++) {
|
||||
temp = start[offset];
|
||||
if (temp != pattern) {
|
||||
printf("\nFAILURE (read/write) @ 0x%.8lx:"
|
||||
" expected 0x%.8lx, actual 0x%.8lx)\n",
|
||||
(uint32_t)&start[offset], pattern, temp);
|
||||
return 1;
|
||||
}
|
||||
anti_pattern = ~pattern;
|
||||
start[offset] = anti_pattern;
|
||||
}
|
||||
/*
|
||||
* Check each location for the inverted pattern and zero it.
|
||||
*/
|
||||
for (pattern = 1, offset = 0; offset < num_words; pattern++, offset++) {
|
||||
anti_pattern = ~pattern;
|
||||
temp = start[offset];
|
||||
if (temp != anti_pattern) {
|
||||
printf("\nFAILURE (read/write): @ 0x%.8lx:"
|
||||
" expected 0x%.8lx, actual 0x%.8lx)\n",
|
||||
(uint32_t)&start[offset], anti_pattern, temp);
|
||||
return 1;
|
||||
}
|
||||
start[offset] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
static int mem_test(uint32_t *_start, size_t len, bool doRead = true, bool doWrite = true)
|
||||
{
|
||||
volatile uint32_t *addr;
|
||||
volatile uint32_t *start = (volatile uint32_t *)_start;
|
||||
const volatile uint32_t *end = start + len / sizeof(uint32_t);
|
||||
uint32_t pattern = 0;
|
||||
uint32_t val;
|
||||
uint32_t readback;
|
||||
uint32_t incr;
|
||||
int rcode = 0;
|
||||
incr = 1;
|
||||
|
||||
//DEBUG_MSG("memtest read=%d, write=%d\n", doRead, doWrite);
|
||||
|
||||
if (doWrite) {
|
||||
//DEBUG_MSG("writing\n");
|
||||
for (addr = start, val = pattern; addr < end; addr++) {
|
||||
*addr = val;
|
||||
val += incr;
|
||||
}
|
||||
}
|
||||
|
||||
if (doRead) {
|
||||
//DEBUG_MSG("reading\n");
|
||||
for (addr = start, val = pattern; addr < end; addr++) {
|
||||
readback = *addr;
|
||||
if (readback != val) {
|
||||
DEBUG_MSG("Mem error @ 0x%08X: "
|
||||
"found 0x%08lX, expected 0x%08lX\n",
|
||||
addr, readback, val);
|
||||
rcode++;
|
||||
}
|
||||
val += incr;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Flip the pattern each time to make lots of zeros and
|
||||
* then, the next time, lots of ones. We decrement
|
||||
* the "negative" patterns and increment the "positive"
|
||||
* patterns to preserve this feature.
|
||||
*/
|
||||
if(pattern & 0x80000000) {
|
||||
pattern = -pattern; /* complement & increment */
|
||||
}
|
||||
else {
|
||||
pattern = ~pattern;
|
||||
}
|
||||
#endif
|
||||
|
||||
return rcode;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define TESTBUF_LEN 16384
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
void doMemTest()
|
||||
{
|
||||
static uint32_t *testBuf;
|
||||
static int iter;
|
||||
|
||||
if (!testBuf)
|
||||
testBuf = (uint32_t *)malloc(TESTBUF_LEN);
|
||||
|
||||
assert(testBuf);
|
||||
if (mem_test(testBuf, TESTBUF_LEN, iter % 2 == 1, iter % 2 == 0) > 0)
|
||||
assert(0); // FIXME report error better
|
||||
|
||||
iter++;
|
||||
}
|
||||
@@ -106,30 +106,30 @@ CryptoKey Channels::getKey(ChannelIndex chIndex)
|
||||
k.length = channelSettings.psk.size;
|
||||
if (k.length == 0) {
|
||||
if (ch.role == Channel_Role_SECONDARY) {
|
||||
DEBUG_MSG("Unset PSK for secondary channel %s. using primary key\n", ch.settings.name);
|
||||
LOG_DEBUG("Unset PSK for secondary channel %s. using primary key\n", ch.settings.name);
|
||||
k = getKey(primaryIndex);
|
||||
} else
|
||||
DEBUG_MSG("Warning: User disabled encryption\n");
|
||||
LOG_WARN("User disabled encryption\n");
|
||||
} else if (k.length == 1) {
|
||||
// Convert the short single byte variants of psk into variant that can be used more generally
|
||||
|
||||
uint8_t pskIndex = k.bytes[0];
|
||||
DEBUG_MSG("Expanding short PSK #%d\n", pskIndex);
|
||||
LOG_DEBUG("Expanding short PSK #%d\n", pskIndex);
|
||||
if (pskIndex == 0)
|
||||
k.length = 0; // Turn off encryption
|
||||
else if (oemStore.oem_aes_key.size > 1) {
|
||||
// Use the OEM key
|
||||
DEBUG_MSG("Using OEM Key with %d bytes\n", oemStore.oem_aes_key.size);
|
||||
LOG_DEBUG("Using OEM Key with %d bytes\n", oemStore.oem_aes_key.size);
|
||||
memcpy(k.bytes, oemStore.oem_aes_key.bytes , oemStore.oem_aes_key.size);
|
||||
k.length = oemStore.oem_aes_key.size;
|
||||
// Bump up the last byte of PSK as needed
|
||||
uint8_t *last = k.bytes + oemStore.oem_aes_key.size - 1;
|
||||
*last = *last + pskIndex - 1; // index of 1 means no change vs defaultPSK
|
||||
if (k.length < 16) {
|
||||
DEBUG_MSG("Warning: OEM provided a too short AES128 key - padding\n");
|
||||
LOG_WARN("OEM provided a too short AES128 key - padding\n");
|
||||
k.length = 16;
|
||||
} else if (k.length < 32 && k.length != 16) {
|
||||
DEBUG_MSG("Warning: OEM provided a too short AES256 key - padding\n");
|
||||
LOG_WARN("OEM provided a too short AES256 key - padding\n");
|
||||
k.length = 32;
|
||||
}
|
||||
} else {
|
||||
@@ -142,12 +142,12 @@ CryptoKey Channels::getKey(ChannelIndex chIndex)
|
||||
} else if (k.length < 16) {
|
||||
// Error! The user specified only the first few bits of an AES128 key. So by convention we just pad the rest of the
|
||||
// key with zeros
|
||||
DEBUG_MSG("Warning: User provided a too short AES128 key - padding\n");
|
||||
LOG_WARN("User provided a too short AES128 key - padding\n");
|
||||
k.length = 16;
|
||||
} else if (k.length < 32 && k.length != 16) {
|
||||
// Error! The user specified only the first few bits of an AES256 key. So by convention we just pad the rest of the
|
||||
// key with zeros
|
||||
DEBUG_MSG("Warning: User provided a too short AES256 key - padding\n");
|
||||
LOG_WARN("User provided a too short AES256 key - padding\n");
|
||||
k.length = 32;
|
||||
}
|
||||
}
|
||||
@@ -191,9 +191,31 @@ void Channels::onConfigChanged()
|
||||
|
||||
Channel &Channels::getByIndex(ChannelIndex chIndex)
|
||||
{
|
||||
assert(chIndex < channelFile.channels_count); // This should be equal to MAX_NUM_CHANNELS
|
||||
// remove this assert cause malformed packets can make our firmware reboot here.
|
||||
if (chIndex < channelFile.channels_count) { // This should be equal to MAX_NUM_CHANNELS
|
||||
Channel *ch = channelFile.channels + chIndex;
|
||||
return *ch;
|
||||
} else {
|
||||
LOG_ERROR("Invalid channel index %d > %d, malformed packet received?\n", chIndex , channelFile.channels_count);
|
||||
|
||||
static Channel *ch = (Channel *)malloc(sizeof(Channel));
|
||||
memset(ch, 0, sizeof(Channel));
|
||||
// ch.index -1 means we don't know the channel locally and need to look it up by settings.name
|
||||
// not sure this is handled right everywhere
|
||||
ch->index = -1;
|
||||
return *ch;
|
||||
}
|
||||
}
|
||||
|
||||
Channel &Channels::getByName(const char* chName)
|
||||
{
|
||||
for (ChannelIndex i = 0; i < getNumChannels(); i++) {
|
||||
if (strcasecmp(getGlobalId(i), chName) == 0) {
|
||||
return channelFile.channels[i];
|
||||
}
|
||||
}
|
||||
|
||||
return getByIndex(getPrimaryIndex());
|
||||
}
|
||||
|
||||
void Channels::setChannel(const Channel &c)
|
||||
@@ -297,11 +319,11 @@ const char *Channels::getPrimaryName()
|
||||
bool Channels::decryptForHash(ChannelIndex chIndex, ChannelHash channelHash)
|
||||
{
|
||||
if (chIndex > getNumChannels() || getHash(chIndex) != channelHash) {
|
||||
// DEBUG_MSG("Skipping channel %d (hash %x) due to invalid hash/index, want=%x\n", chIndex, getHash(chIndex),
|
||||
// LOG_DEBUG("Skipping channel %d (hash %x) due to invalid hash/index, want=%x\n", chIndex, getHash(chIndex),
|
||||
// channelHash);
|
||||
return false;
|
||||
} else {
|
||||
DEBUG_MSG("Using channel %d (hash 0x%x)\n", chIndex, channelHash);
|
||||
LOG_DEBUG("Using channel %d (hash 0x%x)\n", chIndex, channelHash);
|
||||
setCrypto(chIndex);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -40,6 +40,9 @@ class Channels
|
||||
/** Return the Channel for a specified index */
|
||||
Channel &getByIndex(ChannelIndex chIndex);
|
||||
|
||||
/** Return the Channel for a specified name, return primary if not found. */
|
||||
Channel &getByName(const char* chName);
|
||||
|
||||
/** Using the index inside the channel, update the specified channel's settings and role. If this channel is being promoted
|
||||
* to be primary, force all other channels to be secondary.
|
||||
*/
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
void CryptoEngine::setKey(const CryptoKey &k)
|
||||
{
|
||||
DEBUG_MSG("Using AES%d key!\n", k.length * 8);
|
||||
LOG_DEBUG("Using AES%d key!\n", k.length * 8);
|
||||
key = k;
|
||||
}
|
||||
|
||||
@@ -14,12 +14,12 @@ void CryptoEngine::setKey(const CryptoKey &k)
|
||||
*/
|
||||
void CryptoEngine::encrypt(uint32_t fromNode, uint64_t packetId, size_t numBytes, uint8_t *bytes)
|
||||
{
|
||||
DEBUG_MSG("WARNING: noop encryption!\n");
|
||||
LOG_WARN("noop encryption!\n");
|
||||
}
|
||||
|
||||
void CryptoEngine::decrypt(uint32_t fromNode, uint64_t packetId, size_t numBytes, uint8_t *bytes)
|
||||
{
|
||||
DEBUG_MSG("WARNING: noop decryption!\n");
|
||||
LOG_WARN("noop decryption!\n");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,7 +17,7 @@ ErrorCode FloodingRouter::send(MeshPacket *p)
|
||||
return Router::send(p);
|
||||
}
|
||||
|
||||
bool FloodingRouter::shouldFilterReceived(MeshPacket *p)
|
||||
bool FloodingRouter::shouldFilterReceived(const 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);
|
||||
@@ -32,26 +32,32 @@ void FloodingRouter::sniffReceived(const MeshPacket *p, const Routing *c)
|
||||
bool isAck = ((c && c->error_reason == Routing_Error_NONE)); // consider only ROUTING_APP message without error as ACK
|
||||
if (isAck && p->to != getNodeNum()) {
|
||||
// do not flood direct message that is ACKed
|
||||
DEBUG_MSG("Receiving an ACK not for me, but don't need to rebroadcast this direct message anymore.\n");
|
||||
LOG_DEBUG("Receiving an ACK not for me, but don't need to rebroadcast this direct message anymore.\n");
|
||||
Router::cancelSending(p->to, p->decoded.request_id); // cancel rebroadcast for this DM
|
||||
} else if ((p->to != getNodeNum()) && (p->hop_limit > 0) && (getFrom(p) != getNodeNum())) {
|
||||
}
|
||||
if ((p->to != getNodeNum()) && (p->hop_limit > 0) && (getFrom(p) != getNodeNum())) {
|
||||
if (p->id != 0) {
|
||||
if (config.device.role != Config_DeviceConfig_Role_CLIENT_MUTE) {
|
||||
MeshPacket *tosend = packetPool.allocCopy(*p); // keep a copy because we will be sending it
|
||||
|
||||
tosend->hop_limit--; // bump down the hop count
|
||||
|
||||
printPacket("Rebroadcasting received floodmsg to neighbors", p);
|
||||
// If it is a traceRoute request, update the route that it went via me
|
||||
if (p->which_payload_variant == MeshPacket_decoded_tag && traceRouteModule->wantPacket(p)) {
|
||||
traceRouteModule->updateRoute(tosend);
|
||||
}
|
||||
|
||||
LOG_INFO("Rebroadcasting received floodmsg to neighbors", p);
|
||||
// Note: we are careful to resend using the original senders node id
|
||||
// We are careful not to call our hooked version of send() - because we don't want to check this again
|
||||
Router::send(tosend);
|
||||
|
||||
} else {
|
||||
DEBUG_MSG("Not rebroadcasting. Role = Role_ClientMute\n");
|
||||
LOG_DEBUG("Not rebroadcasting. Role = Role_ClientMute\n");
|
||||
}
|
||||
|
||||
} else {
|
||||
DEBUG_MSG("Ignoring a simple (0 id) broadcast\n");
|
||||
LOG_DEBUG("Ignoring a simple (0 id) broadcast\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "PacketHistory.h"
|
||||
#include "Router.h"
|
||||
#include "modules/TraceRouteModule.h"
|
||||
|
||||
/**
|
||||
* This is a mixin that extends Router with the ability to do Naive Flooding (in the standard mesh protocol sense)
|
||||
@@ -50,7 +51,7 @@ class FloodingRouter : public Router, protected PacketHistory
|
||||
* Called immedately on receiption, before any further processing.
|
||||
* @return true to abandon the packet
|
||||
*/
|
||||
virtual bool shouldFilterReceived(MeshPacket *p) override;
|
||||
virtual bool shouldFilterReceived(const MeshPacket *p) override;
|
||||
|
||||
/**
|
||||
* Look for broadcasts we need to rebroadcast
|
||||
|
||||
@@ -2,12 +2,23 @@
|
||||
#include "SX126xInterface.cpp"
|
||||
#include "SX128xInterface.h"
|
||||
#include "SX128xInterface.cpp"
|
||||
#include "api/ServerAPI.h"
|
||||
#include "api/ServerAPI.cpp"
|
||||
|
||||
// We need this declaration for proper linking in derived classes
|
||||
template class SX126xInterface<SX1262>;
|
||||
template class SX126xInterface<SX1268>;
|
||||
template class SX126xInterface<LLCC68>;
|
||||
|
||||
#if defined(RADIOLIB_GODMODE)
|
||||
template class SX128xInterface<SX1280>;
|
||||
|
||||
#if HAS_ETHERNET
|
||||
#include "api/ethServerAPI.h"
|
||||
template class ServerAPI<EthernetClient>;
|
||||
template class APIServerPort<ethServerAPI, EthernetServer>;
|
||||
#endif
|
||||
|
||||
#if HAS_WIFI
|
||||
#include "api/WiFiServerAPI.h"
|
||||
template class ServerAPI<WiFiClient>;
|
||||
template class APIServerPort<WiFiServerAPI, WiFiServer>;
|
||||
#endif
|
||||
@@ -44,15 +44,15 @@ MeshPacket *MeshModule::allocAckNak(Routing_Error err, NodeNum to, PacketId idFr
|
||||
// auto p = allocDataProtobuf(c);
|
||||
MeshPacket *p = router->allocForSending();
|
||||
p->decoded.portnum = PortNum_ROUTING_APP;
|
||||
p->decoded.payload.size = pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), Routing_fields, &c);
|
||||
p->decoded.payload.size = pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), &Routing_msg, &c);
|
||||
|
||||
p->priority = MeshPacket_Priority_ACK;
|
||||
|
||||
p->hop_limit = 0; // Assume just immediate neighbors for now
|
||||
p->hop_limit = config.lora.hop_limit; // Flood ACK back to original sender
|
||||
p->to = to;
|
||||
p->decoded.request_id = idFrom;
|
||||
p->channel = chIndex;
|
||||
DEBUG_MSG("Alloc an err=%d,to=0x%x,idFrom=0x%x,id=0x%x\n", err, to, idFrom, p->id);
|
||||
LOG_ERROR("Alloc an err=%d,to=0x%x,idFrom=0x%x,id=0x%x\n", err, to, idFrom, p->id);
|
||||
|
||||
return p;
|
||||
}
|
||||
@@ -68,7 +68,7 @@ MeshPacket *MeshModule::allocErrorResponse(Routing_Error err, const MeshPacket *
|
||||
|
||||
void MeshModule::callPlugins(const MeshPacket &mp, RxSource src)
|
||||
{
|
||||
// DEBUG_MSG("In call modules\n");
|
||||
// LOG_DEBUG("In call modules\n");
|
||||
bool moduleFound = false;
|
||||
|
||||
// We now allow **encrypted** packets to pass through the modules
|
||||
@@ -96,7 +96,7 @@ void MeshModule::callPlugins(const MeshPacket &mp, RxSource src)
|
||||
assert(!pi.myReply); // If it is !null it means we have a bug, because it should have been sent the previous time
|
||||
|
||||
if (wantsPacket) {
|
||||
DEBUG_MSG("Module '%s' wantsPacket=%d\n", pi.name, wantsPacket);
|
||||
LOG_DEBUG("Module '%s' wantsPacket=%d\n", pi.name, wantsPacket);
|
||||
|
||||
moduleFound = true;
|
||||
|
||||
@@ -134,20 +134,20 @@ void MeshModule::callPlugins(const MeshPacket &mp, RxSource src)
|
||||
// any other node.
|
||||
if (mp.decoded.want_response && toUs && (getFrom(&mp) != ourNodeNum || mp.to == ourNodeNum) && !currentReply) {
|
||||
pi.sendResponse(mp);
|
||||
DEBUG_MSG("Module '%s' sent a response\n", pi.name);
|
||||
LOG_INFO("Module '%s' sent a response\n", pi.name);
|
||||
} else {
|
||||
DEBUG_MSG("Module '%s' considered\n", pi.name);
|
||||
LOG_DEBUG("Module '%s' considered\n", pi.name);
|
||||
}
|
||||
|
||||
// If the requester didn't ask for a response we might need to discard unused replies to prevent memory leaks
|
||||
if (pi.myReply) {
|
||||
DEBUG_MSG("Discarding an unneeded response\n");
|
||||
LOG_DEBUG("Discarding an unneeded response\n");
|
||||
packetPool.release(pi.myReply);
|
||||
pi.myReply = NULL;
|
||||
}
|
||||
|
||||
if (handled == ProcessMessage::STOP) {
|
||||
DEBUG_MSG("Module '%s' handled and skipped other processing\n", pi.name);
|
||||
LOG_DEBUG("Module '%s' handled and skipped other processing\n", pi.name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -165,7 +165,7 @@ void MeshModule::callPlugins(const MeshPacket &mp, RxSource src)
|
||||
// Note: if the message started with the local node we don't want to send a no response reply
|
||||
|
||||
// No one wanted to reply to this requst, tell the requster that happened
|
||||
DEBUG_MSG("No one responded, send a nak\n");
|
||||
LOG_DEBUG("No one responded, send a nak\n");
|
||||
|
||||
// SECURITY NOTE! I considered sending back a different error code if we didn't find the psk (i.e. !isDecoded)
|
||||
// but opted NOT TO. Because it is not a good idea to let remote nodes 'probe' to find out which PSKs were "good" vs
|
||||
@@ -175,7 +175,7 @@ void MeshModule::callPlugins(const MeshPacket &mp, RxSource src)
|
||||
}
|
||||
|
||||
if (!moduleFound)
|
||||
DEBUG_MSG("No modules interested in portnum=%d, src=%s\n",
|
||||
LOG_DEBUG("No modules interested in portnum=%d, src=%s\n",
|
||||
mp.decoded.portnum,
|
||||
(src == RX_SRC_LOCAL) ? "LOCAL":"REMOTE");
|
||||
}
|
||||
@@ -199,7 +199,7 @@ void MeshModule::sendResponse(const MeshPacket &req)
|
||||
currentReply = r;
|
||||
} else {
|
||||
// Ignore - this is now expected behavior for routing module (because it ignores some replies)
|
||||
// DEBUG_MSG("WARNING: Client requested response but this module did not provide\n");
|
||||
// LOG_WARN("Client requested response but this module did not provide\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -227,7 +227,7 @@ std::vector<MeshModule *> MeshModule::GetMeshModulesWithUIFrames()
|
||||
for (auto i = modules->begin(); i != modules->end(); ++i) {
|
||||
auto &pi = **i;
|
||||
if (pi.wantUIFrame()) {
|
||||
DEBUG_MSG("Module wants a UI Frame\n");
|
||||
LOG_DEBUG("Module wants a UI Frame\n");
|
||||
modulesWithUIFrames.push_back(&pi);
|
||||
}
|
||||
}
|
||||
@@ -244,7 +244,7 @@ void MeshModule::observeUIEvents(
|
||||
Observable<const UIFrameEvent *> *observable =
|
||||
pi.getUIFrameObservable();
|
||||
if (observable != NULL) {
|
||||
DEBUG_MSG("Module wants a UI Frame\n");
|
||||
LOG_DEBUG("Module wants a UI Frame\n");
|
||||
observer->observe(observable);
|
||||
}
|
||||
}
|
||||
@@ -261,7 +261,7 @@ AdminMessageHandleResult MeshModule::handleAdminMessageForAllPlugins(const MeshP
|
||||
if (h == AdminMessageHandleResult::HANDLED_WITH_RESPONSE)
|
||||
{
|
||||
// In case we have a response it always has priority.
|
||||
DEBUG_MSG("Reply prepared by module '%s' of variant: %d\n",
|
||||
LOG_DEBUG("Reply prepared by module '%s' of variant: %d\n",
|
||||
pi.name,
|
||||
response->which_payload_variant);
|
||||
handled = h;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "configuration.h"
|
||||
#include "MeshPacketQueue.h"
|
||||
#include <assert.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
#include "MeshTypes.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <queue>
|
||||
|
||||
|
||||
@@ -26,6 +25,12 @@ class MeshPacketQueue
|
||||
/** return true if the queue is empty */
|
||||
bool empty();
|
||||
|
||||
/** return amount of free packets in Queue */
|
||||
size_t getFree() { return maxLen - queue.size(); }
|
||||
|
||||
/** return total size of the Queue */
|
||||
size_t getMaxLen() { return maxLen; }
|
||||
|
||||
MeshPacket *dequeue();
|
||||
|
||||
MeshPacket *getFront();
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include <string>
|
||||
|
||||
#include "GPS.h"
|
||||
//#include "MeshBluetoothService.h"
|
||||
#include "../concurrency/Periodic.h"
|
||||
#include "BluetoothCommon.h" // needed for updateBatteryLevel, FIXME, eventually when we pull mesh out into a lib we shouldn't be whacking bluetooth from here
|
||||
#include "MeshService.h"
|
||||
@@ -52,11 +51,15 @@ FIXME in the initial proof of concept we just skip the entire want/deny flow and
|
||||
|
||||
MeshService service;
|
||||
|
||||
static MemoryDynamic<QueueStatus> staticQueueStatusPool;
|
||||
|
||||
Allocator<QueueStatus> &queueStatusPool = staticQueueStatusPool;
|
||||
|
||||
#include "Router.h"
|
||||
|
||||
MeshService::MeshService() : toPhoneQueue(MAX_RX_TOPHONE)
|
||||
MeshService::MeshService() : toPhoneQueue(MAX_RX_TOPHONE), toPhoneQueueStatusQueue(MAX_RX_TOPHONE)
|
||||
{
|
||||
// assert(MAX_RX_TOPHONE == 32); // FIXME, delete this, just checking my clever macro
|
||||
lastQueueStatus = { 0, 0, 16, 0 };
|
||||
}
|
||||
|
||||
void MeshService::init()
|
||||
@@ -83,6 +86,11 @@ int MeshService::handleFromRadio(const MeshPacket *mp)
|
||||
/// Do idle processing (mostly processing messages which have been queued from the radio)
|
||||
void MeshService::loop()
|
||||
{
|
||||
if (lastQueueStatus.free == 0) { // check if there is now free space in TX queue
|
||||
QueueStatus qs = router->getQueueStatus();
|
||||
if (qs.free != lastQueueStatus.free)
|
||||
(void)sendQueueStatusToPhone(qs, 0, 0);
|
||||
}
|
||||
if (oldFromNum != fromNum) { // We don't want to generate extra notifies for multiple new packets
|
||||
fromNumChanged.notifyObservers(fromNum);
|
||||
oldFromNum = fromNum;
|
||||
@@ -106,7 +114,7 @@ bool MeshService::reloadConfig(int saveWhat)
|
||||
/// The owner User record just got updated, update our node DB and broadcast the info into the mesh
|
||||
void MeshService::reloadOwner(bool shouldSave)
|
||||
{
|
||||
// DEBUG_MSG("reloadOwner()\n");
|
||||
// LOG_DEBUG("reloadOwner()\n");
|
||||
// update our local data directly
|
||||
nodeDB.updateUser(nodeDB.getNodeNum(), owner);
|
||||
assert(nodeInfoModule);
|
||||
@@ -140,7 +148,7 @@ void MeshService::handleToRadio(MeshPacket &p)
|
||||
// Switch the port from PortNum_SIMULATOR_APP back to the original PortNum
|
||||
p.decoded.portnum = decoded->portnum;
|
||||
} else
|
||||
DEBUG_MSG("Error decoding protobuf for simulator message!\n");
|
||||
LOG_ERROR("Error decoding protobuf for simulator message!\n");
|
||||
}
|
||||
// Let SimRadio receive as if it did via its LoRa chip
|
||||
SimRadio::instance->startReceive(&p);
|
||||
@@ -148,7 +156,7 @@ void MeshService::handleToRadio(MeshPacket &p)
|
||||
}
|
||||
#endif
|
||||
if (p.from != 0) { // We don't let phones assign nodenums to their sent messages
|
||||
DEBUG_MSG("Warning: phone tried to pick a nodenum, we don't allow that.\n");
|
||||
LOG_WARN("phone tried to pick a nodenum, we don't allow that.\n");
|
||||
p.from = 0;
|
||||
} else {
|
||||
// p.from = nodeDB.getNodeNum();
|
||||
@@ -179,12 +187,43 @@ bool MeshService::cancelSending(PacketId id)
|
||||
return router->cancelSending(nodeDB.getNodeNum(), id);
|
||||
}
|
||||
|
||||
ErrorCode MeshService::sendQueueStatusToPhone(const QueueStatus &qs, ErrorCode res, uint32_t mesh_packet_id)
|
||||
{
|
||||
QueueStatus *copied = queueStatusPool.allocCopy(qs);
|
||||
|
||||
copied->res = res;
|
||||
copied->mesh_packet_id = mesh_packet_id;
|
||||
|
||||
if (toPhoneQueueStatusQueue.numFree() == 0) {
|
||||
LOG_DEBUG("NOTE: tophone queue status queue is full, discarding oldest\n");
|
||||
QueueStatus *d = toPhoneQueueStatusQueue.dequeuePtr(0);
|
||||
if (d)
|
||||
releaseQueueStatusToPool(d);
|
||||
}
|
||||
|
||||
lastQueueStatus = *copied;
|
||||
|
||||
res = toPhoneQueueStatusQueue.enqueue(copied, 0);
|
||||
fromNum++;
|
||||
|
||||
return res ? ERRNO_OK : ERRNO_UNKNOWN;
|
||||
}
|
||||
|
||||
void MeshService::sendToMesh(MeshPacket *p, RxSource src, bool ccToPhone)
|
||||
{
|
||||
uint32_t mesh_packet_id = p->id;
|
||||
nodeDB.updateFrom(*p); // update our local DB for this packet (because phone might have sent position packets etc...)
|
||||
|
||||
// Note: We might return !OK if our fifo was full, at that point the only option we have is to drop it
|
||||
router->sendLocal(p, src);
|
||||
ErrorCode res = router->sendLocal(p, src);
|
||||
|
||||
/* NOTE(pboldin): Prepare and send QueueStatus message to the phone as a
|
||||
* high-priority message. */
|
||||
QueueStatus qs = router->getQueueStatus();
|
||||
ErrorCode r = sendQueueStatusToPhone(qs, res, mesh_packet_id);
|
||||
if (r != ERRNO_OK) {
|
||||
LOG_DEBUG("Can't send status to phone");
|
||||
}
|
||||
|
||||
if (ccToPhone) {
|
||||
sendToPhone(p);
|
||||
@@ -198,12 +237,12 @@ void MeshService::sendNetworkPing(NodeNum dest, bool wantReplies)
|
||||
|
||||
if (node->has_position && (node->position.latitude_i != 0 || node->position.longitude_i != 0)) {
|
||||
if (positionModule) {
|
||||
DEBUG_MSG("Sending position ping to 0x%x, wantReplies=%d\n", dest, wantReplies);
|
||||
LOG_INFO("Sending position ping to 0x%x, wantReplies=%d\n", dest, wantReplies);
|
||||
positionModule->sendOurPosition(dest, wantReplies);
|
||||
}
|
||||
} else {
|
||||
if (nodeInfoModule) {
|
||||
DEBUG_MSG("Sending nodeinfo ping to 0x%x, wantReplies=%d\n", dest, wantReplies);
|
||||
LOG_INFO("Sending nodeinfo ping to 0x%x, wantReplies=%d\n", dest, wantReplies);
|
||||
nodeInfoModule->sendOurNodeInfo(dest, wantReplies);
|
||||
}
|
||||
}
|
||||
@@ -212,7 +251,7 @@ void MeshService::sendNetworkPing(NodeNum dest, bool wantReplies)
|
||||
void MeshService::sendToPhone(MeshPacket *p)
|
||||
{
|
||||
if (toPhoneQueue.numFree() == 0) {
|
||||
DEBUG_MSG("NOTE: tophone queue is full, discarding oldest\n");
|
||||
LOG_WARN("ToPhone queue is full, discarding oldest\n");
|
||||
MeshPacket *d = toPhoneQueue.dequeuePtr(0);
|
||||
if (d)
|
||||
releaseToPool(d);
|
||||
@@ -220,7 +259,7 @@ void MeshService::sendToPhone(MeshPacket *p)
|
||||
|
||||
MeshPacket *copied = packetPool.allocCopy(*p);
|
||||
perhapsDecode(copied);
|
||||
assert(toPhoneQueue.enqueue(copied, 0)); // FIXME, instead of failing for full queue, delete the oldest mssages
|
||||
assert(toPhoneQueue.enqueue(copied, 0));
|
||||
fromNum++;
|
||||
}
|
||||
|
||||
@@ -241,8 +280,7 @@ NodeInfo *MeshService::refreshMyNodeInfo()
|
||||
node->last_heard =
|
||||
getValidTime(RTCQualityFromNet); // This nodedb timestamp might be stale, so update it if our clock is kinda valid
|
||||
|
||||
// For the time in the position field, only set that if we have a real GPS clock
|
||||
position.time = getValidTime(RTCQualityGPS);
|
||||
position.time = getValidTime(RTCQualityFromNet);
|
||||
|
||||
updateBatteryLevel(powerStatus->getBatteryChargePercent());
|
||||
|
||||
@@ -262,10 +300,10 @@ int MeshService::onGPSChanged(const meshtastic::GPSStatus *newStatus)
|
||||
// The GPS has lost lock, if we are fixed position we should just keep using
|
||||
// the old position
|
||||
#ifdef GPS_EXTRAVERBOSE
|
||||
DEBUG_MSG("onGPSchanged() - lost validLocation\n");
|
||||
LOG_DEBUG("onGPSchanged() - lost validLocation\n");
|
||||
#endif
|
||||
if (config.position.fixed_position) {
|
||||
DEBUG_MSG("WARNING: Using fixed position\n");
|
||||
LOG_WARN("Using fixed position\n");
|
||||
pos = node->position;
|
||||
}
|
||||
}
|
||||
@@ -276,7 +314,7 @@ int MeshService::onGPSChanged(const meshtastic::GPSStatus *newStatus)
|
||||
pos.time = getValidTime(RTCQualityGPS);
|
||||
|
||||
// In debug logs, identify position by @timestamp:stage (stage 4 = nodeDB)
|
||||
DEBUG_MSG("onGPSChanged() pos@%x, time=%u, lat=%d, lon=%d, alt=%d\n", pos.timestamp, pos.time, pos.latitude_i,
|
||||
LOG_DEBUG("onGPSChanged() pos@%x, time=%u, lat=%d, lon=%d, alt=%d\n", pos.timestamp, pos.time, pos.latitude_i,
|
||||
pos.longitude_i, pos.altitude);
|
||||
|
||||
// Update our current position in the local DB
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
#include "../platform/portduino/SimRadio.h"
|
||||
#endif
|
||||
|
||||
extern Allocator<QueueStatus> &queueStatusPool;
|
||||
|
||||
/**
|
||||
* Top level app for this service. keeps the mesh, the radio config and the queue of received packets.
|
||||
*
|
||||
@@ -29,6 +31,12 @@ class MeshService
|
||||
/// FIXME - save this to flash on deep sleep
|
||||
PointerQueue<MeshPacket> toPhoneQueue;
|
||||
|
||||
// keep list of QueueStatus packets to be send to the phone
|
||||
PointerQueue<QueueStatus> toPhoneQueueStatusQueue;
|
||||
|
||||
// This holds the last QueueStatus send
|
||||
QueueStatus lastQueueStatus;
|
||||
|
||||
/// The current nonce for the newest packet which has been queued for the phone
|
||||
uint32_t fromNum = 0;
|
||||
|
||||
@@ -56,6 +64,12 @@ class MeshService
|
||||
/// Allows the bluetooth handler to free packets after they have been sent
|
||||
void releaseToPool(MeshPacket *p) { packetPool.release(p); }
|
||||
|
||||
/// Return the next QueueStatus packet destined to the phone.
|
||||
QueueStatus *getQueueStatusForPhone() { return toPhoneQueueStatusQueue.dequeuePtr(0); }
|
||||
|
||||
// Release QueueStatus packet to pool
|
||||
void releaseQueueStatusToPool(QueueStatus *p) { queueStatusPool.release(p); }
|
||||
|
||||
/**
|
||||
* Given a ToRadio buffer parse it and properly handle it (setup radio, owner or send packet into the mesh)
|
||||
* Called by PhoneAPI.handleToRadio. Note: p is a scratch buffer, this function is allowed to write to it but it can not keep
|
||||
@@ -100,6 +114,8 @@ class MeshService
|
||||
/// needs to keep the packet around it makes a copy
|
||||
int handleFromRadio(const MeshPacket *p);
|
||||
friend class RoutingModule;
|
||||
|
||||
ErrorCode sendQueueStatusToPhone(const QueueStatus &qs, ErrorCode res, uint32_t mesh_packet_id);
|
||||
};
|
||||
|
||||
extern MeshService service;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "configuration.h"
|
||||
#include <assert.h>
|
||||
|
||||
#include "Channels.h"
|
||||
#include "CryptoEngine.h"
|
||||
@@ -86,7 +85,7 @@ bool NodeDB::resetRadioConfig(bool factory_reset)
|
||||
}
|
||||
|
||||
if (channelFile.channels_count != MAX_NUM_CHANNELS) {
|
||||
DEBUG_MSG("Setting default channel and radio preferences!\n");
|
||||
LOG_INFO("Setting default channel and radio preferences!\n");
|
||||
|
||||
channels.initDefaults();
|
||||
}
|
||||
@@ -96,7 +95,7 @@ bool NodeDB::resetRadioConfig(bool factory_reset)
|
||||
// temp hack for quicker testing
|
||||
// devicestate.no_save = true;
|
||||
if (devicestate.no_save) {
|
||||
DEBUG_MSG("***** DEVELOPMENT MODE - DO NOT RELEASE *****\n");
|
||||
LOG_DEBUG("***** DEVELOPMENT MODE - DO NOT RELEASE *****\n");
|
||||
|
||||
// Sleep quite frequently to stress test the BLE comms, broadcast position every 6 mins
|
||||
config.display.screen_on_secs = 10;
|
||||
@@ -114,7 +113,7 @@ bool NodeDB::resetRadioConfig(bool factory_reset)
|
||||
initRegion();
|
||||
|
||||
if (didFactoryReset) {
|
||||
DEBUG_MSG("Rebooting due to factory reset");
|
||||
LOG_INFO("Rebooting due to factory reset");
|
||||
screen->startRebootScreen();
|
||||
rebootAtMsec = millis() + (5 * 1000);
|
||||
}
|
||||
@@ -124,7 +123,7 @@ bool NodeDB::resetRadioConfig(bool factory_reset)
|
||||
|
||||
bool NodeDB::factoryReset()
|
||||
{
|
||||
DEBUG_MSG("Performing factory reset!\n");
|
||||
LOG_INFO("Performing factory reset!\n");
|
||||
// first, remove the "/prefs" (this removes most prefs)
|
||||
rmDir("/prefs");
|
||||
// second, install default state (this will deal with the duplicate mac address issue)
|
||||
@@ -140,7 +139,7 @@ bool NodeDB::factoryReset()
|
||||
#endif
|
||||
#ifdef ARCH_NRF52
|
||||
Bluefruit.begin();
|
||||
DEBUG_MSG("Clearing bluetooth bonds!\n");
|
||||
LOG_INFO("Clearing bluetooth bonds!\n");
|
||||
bond_print_list(BLE_GAP_ROLE_PERIPH);
|
||||
bond_print_list(BLE_GAP_ROLE_CENTRAL);
|
||||
Bluefruit.Periph.clearBonds();
|
||||
@@ -151,7 +150,7 @@ bool NodeDB::factoryReset()
|
||||
|
||||
void NodeDB::installDefaultConfig()
|
||||
{
|
||||
DEBUG_MSG("Installing default LocalConfig\n");
|
||||
LOG_INFO("Installing default LocalConfig\n");
|
||||
memset(&config, 0, sizeof(LocalConfig));
|
||||
config.version = DEVICESTATE_CUR_VER;
|
||||
config.has_device = true;
|
||||
@@ -162,6 +161,7 @@ void NodeDB::installDefaultConfig()
|
||||
config.has_network = true;
|
||||
config.has_bluetooth = true;
|
||||
config.lora.tx_enabled = true; // FIXME: maybe false in the future, and setting region to enable it. (unset region forces it off)
|
||||
config.lora.override_duty_cycle = false;
|
||||
config.lora.region = Config_LoRaConfig_RegionCode_UNSET;
|
||||
config.lora.modem_preset = Config_LoRaConfig_ModemPreset_LONG_FAST;
|
||||
config.lora.hop_limit = HOP_RELIABLE;
|
||||
@@ -202,7 +202,7 @@ void NodeDB::initConfigIntervals()
|
||||
|
||||
void NodeDB::installDefaultModuleConfig()
|
||||
{
|
||||
DEBUG_MSG("Installing default ModuleConfig\n");
|
||||
LOG_INFO("Installing default ModuleConfig\n");
|
||||
memset(&moduleConfig, 0, sizeof(ModuleConfig));
|
||||
|
||||
moduleConfig.version = DEVICESTATE_CUR_VER;
|
||||
@@ -214,9 +214,9 @@ void NodeDB::installDefaultModuleConfig()
|
||||
moduleConfig.has_external_notification = true;
|
||||
moduleConfig.has_canned_message = true;
|
||||
|
||||
strncpy(moduleConfig.mqtt.address, default_mqtt_address, sizeof(default_mqtt_address));
|
||||
strncpy(moduleConfig.mqtt.username, default_mqtt_username, sizeof(default_mqtt_username));
|
||||
strncpy(moduleConfig.mqtt.password, default_mqtt_password, sizeof(default_mqtt_password));
|
||||
strncpy(moduleConfig.mqtt.address, default_mqtt_address, sizeof(moduleConfig.mqtt.address));
|
||||
strncpy(moduleConfig.mqtt.username, default_mqtt_username, sizeof(moduleConfig.mqtt.username));
|
||||
strncpy(moduleConfig.mqtt.password, default_mqtt_password, sizeof(moduleConfig.mqtt.password));
|
||||
|
||||
initModuleConfigIntervals();
|
||||
}
|
||||
@@ -229,7 +229,7 @@ void NodeDB::initModuleConfigIntervals()
|
||||
|
||||
void NodeDB::installDefaultChannels()
|
||||
{
|
||||
DEBUG_MSG("Installing default ChannelFile\n");
|
||||
LOG_INFO("Installing default ChannelFile\n");
|
||||
memset(&channelFile, 0, sizeof(ChannelFile));
|
||||
channelFile.version = DEVICESTATE_CUR_VER;
|
||||
}
|
||||
@@ -243,7 +243,7 @@ void NodeDB::resetNodes()
|
||||
|
||||
void NodeDB::installDefaultDeviceState()
|
||||
{
|
||||
DEBUG_MSG("Installing default DeviceState\n");
|
||||
LOG_INFO("Installing default DeviceState\n");
|
||||
memset(&devicestate, 0, sizeof(DeviceState));
|
||||
|
||||
*numNodes = 0;
|
||||
@@ -274,7 +274,7 @@ void NodeDB::installDefaultDeviceState()
|
||||
|
||||
void NodeDB::init()
|
||||
{
|
||||
DEBUG_MSG("Initializing NodeDB\n");
|
||||
LOG_INFO("Initializing NodeDB\n");
|
||||
loadFromDisk();
|
||||
|
||||
uint32_t devicestateCRC = crc32Buffer(&devicestate, sizeof(devicestate));
|
||||
@@ -310,7 +310,7 @@ void NodeDB::init()
|
||||
preferences.begin("meshtastic", false);
|
||||
myNodeInfo.reboot_count = preferences.getUInt("rebootCounter", 0);
|
||||
preferences.end();
|
||||
DEBUG_MSG("Number of Device Reboots: %d\n", myNodeInfo.reboot_count);
|
||||
LOG_DEBUG("Number of Device Reboots: %d\n", myNodeInfo.reboot_count);
|
||||
|
||||
/* The ESP32 has a wifi radio. This will need to be modified at some point so
|
||||
* the test isn't so simplistic.
|
||||
@@ -319,7 +319,7 @@ void NodeDB::init()
|
||||
#endif
|
||||
|
||||
resetRadioConfig(); // If bogus settings got saved, then fix them
|
||||
DEBUG_MSG("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, *numNodes);
|
||||
|
||||
if (devicestateCRC != crc32Buffer(&devicestate, sizeof(devicestate)))
|
||||
saveWhat |= SEGMENT_DEVICESTATE;
|
||||
@@ -351,7 +351,7 @@ void NodeDB::pickNewNodeNum()
|
||||
NodeInfo *found;
|
||||
while ((found = getNode(r)) && memcmp(found->user.macaddr, owner.macaddr, sizeof(owner.macaddr))) {
|
||||
NodeNum n = random(NUM_RESERVED, NODENUM_BROADCAST); // try a new random choice
|
||||
DEBUG_MSG("NOTE! Our desired nodenum 0x%x is in use, so trying for 0x%x\n", r, n);
|
||||
LOG_DEBUG("NOTE! Our desired nodenum 0x%x is in use, so trying for 0x%x\n", r, n);
|
||||
r = n;
|
||||
}
|
||||
|
||||
@@ -366,7 +366,7 @@ static const char *oemConfigFile = "/oem/oem.proto";
|
||||
|
||||
|
||||
/** Load a protobuf from a file, return true for success */
|
||||
bool loadProto(const char *filename, size_t protoSize, size_t objSize, const pb_msgdesc_t *fields, void *dest_struct)
|
||||
bool NodeDB::loadProto(const char *filename, size_t protoSize, size_t objSize, const pb_msgdesc_t *fields, void *dest_struct)
|
||||
{
|
||||
bool okay = false;
|
||||
#ifdef FSCom
|
||||
@@ -375,24 +375,24 @@ bool loadProto(const char *filename, size_t protoSize, size_t objSize, const pb_
|
||||
auto f = FSCom.open(filename, FILE_O_READ);
|
||||
|
||||
if (f) {
|
||||
DEBUG_MSG("Loading %s\n", filename);
|
||||
LOG_INFO("Loading %s\n", filename);
|
||||
pb_istream_t stream = {&readcb, &f, protoSize};
|
||||
|
||||
// DEBUG_MSG("Preload channel name=%s\n", channelSettings.name);
|
||||
// LOG_DEBUG("Preload channel name=%s\n", channelSettings.name);
|
||||
|
||||
memset(dest_struct, 0, objSize);
|
||||
if (!pb_decode(&stream, fields, dest_struct)) {
|
||||
DEBUG_MSG("Error: can't decode protobuf %s\n", PB_GET_ERROR(&stream));
|
||||
LOG_ERROR("Error: can't decode protobuf %s\n", PB_GET_ERROR(&stream));
|
||||
} else {
|
||||
okay = true;
|
||||
}
|
||||
|
||||
f.close();
|
||||
} else {
|
||||
DEBUG_MSG("No %s preferences found\n", filename);
|
||||
LOG_INFO("No %s preferences found\n", filename);
|
||||
}
|
||||
#else
|
||||
DEBUG_MSG("ERROR: Filesystem not implemented\n");
|
||||
LOG_ERROR("ERROR: Filesystem not implemented\n");
|
||||
#endif
|
||||
return okay;
|
||||
}
|
||||
@@ -400,56 +400,56 @@ bool loadProto(const char *filename, size_t protoSize, size_t objSize, const pb_
|
||||
void NodeDB::loadFromDisk()
|
||||
{
|
||||
// static DeviceState scratch; We no longer read into a tempbuf because this structure is 15KB of valuable RAM
|
||||
if (!loadProto(prefFileName, DeviceState_size, sizeof(devicestate), DeviceState_fields, &devicestate)) {
|
||||
if (!loadProto(prefFileName, DeviceState_size, sizeof(DeviceState), &DeviceState_msg, &devicestate)) {
|
||||
installDefaultDeviceState(); // Our in RAM copy might now be corrupt
|
||||
} else {
|
||||
if (devicestate.version < DEVICESTATE_MIN_VER) {
|
||||
DEBUG_MSG("Warn: devicestate %d is old, discarding\n", devicestate.version);
|
||||
LOG_WARN("Devicestate %d is old, discarding\n", devicestate.version);
|
||||
factoryReset();
|
||||
} else {
|
||||
DEBUG_MSG("Loaded saved devicestate version %d\n", devicestate.version);
|
||||
LOG_INFO("Loaded saved devicestate version %d\n", devicestate.version);
|
||||
}
|
||||
}
|
||||
|
||||
if (!loadProto(configFileName, LocalConfig_size, sizeof(LocalConfig), LocalConfig_fields, &config)) {
|
||||
if (!loadProto(configFileName, LocalConfig_size, sizeof(LocalConfig), &LocalConfig_msg, &config)) {
|
||||
installDefaultConfig(); // Our in RAM copy might now be corrupt
|
||||
} else {
|
||||
if (config.version < DEVICESTATE_MIN_VER) {
|
||||
DEBUG_MSG("Warn: config %d is old, discarding\n", config.version);
|
||||
LOG_WARN("config %d is old, discarding\n", config.version);
|
||||
installDefaultConfig();
|
||||
} else {
|
||||
DEBUG_MSG("Loaded saved config version %d\n", config.version);
|
||||
LOG_INFO("Loaded saved config version %d\n", config.version);
|
||||
}
|
||||
}
|
||||
|
||||
if (!loadProto(moduleConfigFileName, LocalModuleConfig_size, sizeof(LocalModuleConfig), LocalModuleConfig_fields, &moduleConfig)) {
|
||||
if (!loadProto(moduleConfigFileName, LocalModuleConfig_size, sizeof(LocalModuleConfig), &LocalModuleConfig_msg, &moduleConfig)) {
|
||||
installDefaultModuleConfig(); // Our in RAM copy might now be corrupt
|
||||
} else {
|
||||
if (moduleConfig.version < DEVICESTATE_MIN_VER) {
|
||||
DEBUG_MSG("Warn: moduleConfig %d is old, discarding\n", moduleConfig.version);
|
||||
LOG_WARN("moduleConfig %d is old, discarding\n", moduleConfig.version);
|
||||
installDefaultModuleConfig();
|
||||
} else {
|
||||
DEBUG_MSG("Loaded saved moduleConfig version %d\n", moduleConfig.version);
|
||||
LOG_INFO("Loaded saved moduleConfig version %d\n", moduleConfig.version);
|
||||
}
|
||||
}
|
||||
|
||||
if (!loadProto(channelFileName, ChannelFile_size, sizeof(ChannelFile), ChannelFile_fields, &channelFile)) {
|
||||
if (!loadProto(channelFileName, ChannelFile_size, sizeof(ChannelFile), &ChannelFile_msg, &channelFile)) {
|
||||
installDefaultChannels(); // Our in RAM copy might now be corrupt
|
||||
} else {
|
||||
if (channelFile.version < DEVICESTATE_MIN_VER) {
|
||||
DEBUG_MSG("Warn: channelFile %d is old, discarding\n", channelFile.version);
|
||||
LOG_WARN("channelFile %d is old, discarding\n", channelFile.version);
|
||||
installDefaultChannels();
|
||||
} else {
|
||||
DEBUG_MSG("Loaded saved channelFile version %d\n", channelFile.version);
|
||||
LOG_INFO("Loaded saved channelFile version %d\n", channelFile.version);
|
||||
}
|
||||
}
|
||||
|
||||
if (loadProto(oemConfigFile, OEMStore_size, sizeof(OEMStore), OEMStore_fields, &oemStore))
|
||||
DEBUG_MSG("Loaded OEMStore\n");
|
||||
if (loadProto(oemConfigFile, OEMStore_size, sizeof(OEMStore), &OEMStore_msg, &oemStore))
|
||||
LOG_INFO("Loaded OEMStore\n");
|
||||
}
|
||||
|
||||
/** Save a protobuf from a file, return true for success */
|
||||
bool saveProto(const char *filename, size_t protoSize, size_t objSize, const pb_msgdesc_t *fields, const void *dest_struct)
|
||||
bool NodeDB::saveProto(const char *filename, size_t protoSize, const pb_msgdesc_t *fields, const void *dest_struct)
|
||||
{
|
||||
bool okay = false;
|
||||
#ifdef FSCom
|
||||
@@ -458,11 +458,11 @@ bool saveProto(const char *filename, size_t protoSize, size_t objSize, const pb_
|
||||
filenameTmp += ".tmp";
|
||||
auto f = FSCom.open(filenameTmp.c_str(), FILE_O_WRITE);
|
||||
if (f) {
|
||||
DEBUG_MSG("Saving %s\n", filename);
|
||||
LOG_INFO("Saving %s\n", filename);
|
||||
pb_ostream_t stream = {&writecb, &f, protoSize};
|
||||
|
||||
if (!pb_encode(&stream, fields, dest_struct)) {
|
||||
DEBUG_MSG("Error: can't encode protobuf %s\n", PB_GET_ERROR(&stream));
|
||||
LOG_ERROR("Error: can't encode protobuf %s\n", PB_GET_ERROR(&stream));
|
||||
} else {
|
||||
okay = true;
|
||||
}
|
||||
@@ -470,11 +470,11 @@ bool saveProto(const char *filename, size_t protoSize, size_t objSize, const pb_
|
||||
|
||||
// brief window of risk here ;-)
|
||||
if (FSCom.exists(filename) && !FSCom.remove(filename))
|
||||
DEBUG_MSG("Warning: Can't remove old pref file\n");
|
||||
LOG_WARN("Can't remove old pref file\n");
|
||||
if (!renameFile(filenameTmp.c_str(), filename))
|
||||
DEBUG_MSG("Error: can't rename new pref file\n");
|
||||
LOG_ERROR("Error: can't rename new pref file\n");
|
||||
} else {
|
||||
DEBUG_MSG("Can't write prefs\n");
|
||||
LOG_ERROR("Can't write prefs\n");
|
||||
#ifdef ARCH_NRF52
|
||||
static uint8_t failedCounter = 0;
|
||||
failedCounter++;
|
||||
@@ -486,7 +486,7 @@ bool saveProto(const char *filename, size_t protoSize, size_t objSize, const pb_
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
DEBUG_MSG("ERROR: Filesystem not implemented\n");
|
||||
LOG_ERROR("ERROR: Filesystem not implemented\n");
|
||||
#endif
|
||||
return okay;
|
||||
}
|
||||
@@ -497,7 +497,7 @@ void NodeDB::saveChannelsToDisk()
|
||||
#ifdef FSCom
|
||||
FSCom.mkdir("/prefs");
|
||||
#endif
|
||||
saveProto(channelFileName, ChannelFile_size, sizeof(channelFile), ChannelFile_fields, &channelFile);
|
||||
saveProto(channelFileName, ChannelFile_size, &ChannelFile_msg, &channelFile);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -507,7 +507,7 @@ void NodeDB::saveDeviceStateToDisk()
|
||||
#ifdef FSCom
|
||||
FSCom.mkdir("/prefs");
|
||||
#endif
|
||||
saveProto(prefFileName, DeviceState_size, sizeof(devicestate), DeviceState_fields, &devicestate);
|
||||
saveProto(prefFileName, DeviceState_size, &DeviceState_msg, &devicestate);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -529,7 +529,7 @@ void NodeDB::saveToDisk(int saveWhat)
|
||||
config.has_power = true;
|
||||
config.has_network = true;
|
||||
config.has_bluetooth = true;
|
||||
saveProto(configFileName, LocalConfig_size, sizeof(config), LocalConfig_fields, &config);
|
||||
saveProto(configFileName, LocalConfig_size, &LocalConfig_msg, &config);
|
||||
}
|
||||
|
||||
if (saveWhat & SEGMENT_MODULECONFIG) {
|
||||
@@ -540,14 +540,14 @@ void NodeDB::saveToDisk(int saveWhat)
|
||||
moduleConfig.has_serial = true;
|
||||
moduleConfig.has_store_forward = true;
|
||||
moduleConfig.has_telemetry = true;
|
||||
saveProto(moduleConfigFileName, LocalModuleConfig_size, sizeof(moduleConfig), LocalModuleConfig_fields, &moduleConfig);
|
||||
saveProto(moduleConfigFileName, LocalModuleConfig_size, &LocalModuleConfig_msg, &moduleConfig);
|
||||
}
|
||||
|
||||
if (saveWhat & SEGMENT_CHANNELS) {
|
||||
saveChannelsToDisk();
|
||||
}
|
||||
} else {
|
||||
DEBUG_MSG("***** DEVELOPMENT MODE - DO NOT RELEASE - not saving to flash *****\n");
|
||||
LOG_DEBUG("***** DEVELOPMENT MODE - DO NOT RELEASE - not saving to flash *****\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -598,14 +598,14 @@ void NodeDB::updatePosition(uint32_t nodeId, const Position &p, RxSource src)
|
||||
|
||||
if (src == RX_SRC_LOCAL) {
|
||||
// Local packet, fully authoritative
|
||||
DEBUG_MSG("updatePosition LOCAL pos@%x, time=%u, latI=%d, lonI=%d, alt=%d\n", p.timestamp, p.time, p.latitude_i,
|
||||
LOG_INFO("updatePosition LOCAL pos@%x, time=%u, latI=%d, lonI=%d, alt=%d\n", p.timestamp, p.time, p.latitude_i,
|
||||
p.longitude_i, p.altitude);
|
||||
info->position = p;
|
||||
|
||||
} else if ((p.time > 0) && !p.latitude_i && !p.longitude_i && !p.timestamp && !p.location_source) {
|
||||
// FIXME SPECIAL TIME SETTING PACKET FROM EUD TO RADIO
|
||||
// (stop-gap fix for issue #900)
|
||||
DEBUG_MSG("updatePosition SPECIAL time setting time=%u\n", p.time);
|
||||
LOG_DEBUG("updatePosition SPECIAL time setting time=%u\n", p.time);
|
||||
info->position.time = p.time;
|
||||
|
||||
} else {
|
||||
@@ -614,7 +614,7 @@ void NodeDB::updatePosition(uint32_t nodeId, const Position &p, RxSource src)
|
||||
// recorded based on the packet rxTime
|
||||
//
|
||||
// FIXME perhaps handle RX_SRC_USER separately?
|
||||
DEBUG_MSG("updatePosition REMOTE node=0x%x time=%u, latI=%d, lonI=%d\n", nodeId, p.time, p.latitude_i, p.longitude_i);
|
||||
LOG_INFO("updatePosition REMOTE node=0x%x time=%u, latI=%d, lonI=%d\n", nodeId, p.time, p.latitude_i, p.longitude_i);
|
||||
|
||||
// First, back up fields that we want to protect from overwrite
|
||||
uint32_t tmp_time = info->position.time;
|
||||
@@ -644,9 +644,9 @@ void NodeDB::updateTelemetry(uint32_t nodeId, const Telemetry &t, RxSource src)
|
||||
|
||||
if (src == RX_SRC_LOCAL) {
|
||||
// Local packet, fully authoritative
|
||||
DEBUG_MSG("updateTelemetry LOCAL\n");
|
||||
LOG_DEBUG("updateTelemetry LOCAL\n");
|
||||
} else {
|
||||
DEBUG_MSG("updateTelemetry REMOTE node=0x%x \n", nodeId);
|
||||
LOG_DEBUG("updateTelemetry REMOTE node=0x%x \n", nodeId);
|
||||
}
|
||||
info->device_metrics = t.variant.device_metrics;
|
||||
info->has_device_metrics = true;
|
||||
@@ -663,13 +663,13 @@ void NodeDB::updateUser(uint32_t nodeId, const User &p)
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_MSG("old user %s/%s/%s\n", info->user.id, info->user.long_name, info->user.short_name);
|
||||
LOG_DEBUG("old user %s/%s/%s\n", info->user.id, info->user.long_name, info->user.short_name);
|
||||
|
||||
bool changed = memcmp(&info->user, &p,
|
||||
sizeof(info->user)); // Both of these blocks start as filled with zero so I think this is okay
|
||||
|
||||
info->user = p;
|
||||
DEBUG_MSG("updating changed=%d user %s/%s/%s\n", changed, info->user.id, info->user.long_name, info->user.short_name);
|
||||
LOG_DEBUG("updating changed=%d user %s/%s/%s\n", changed, info->user.id, info->user.long_name, info->user.short_name);
|
||||
info->has_user = true;
|
||||
|
||||
if (changed) {
|
||||
@@ -688,7 +688,7 @@ void NodeDB::updateUser(uint32_t nodeId, const User &p)
|
||||
void NodeDB::updateFrom(const MeshPacket &mp)
|
||||
{
|
||||
if (mp.which_payload_variant == MeshPacket_decoded_tag && mp.from) {
|
||||
DEBUG_MSG("Update DB node 0x%x, rx_time=%u\n", mp.from, mp.rx_time);
|
||||
LOG_DEBUG("Update DB node 0x%x, rx_time=%u\n", mp.from, mp.rx_time);
|
||||
|
||||
NodeInfo *info = getOrCreateNode(getFrom(&mp));
|
||||
if (!info) {
|
||||
@@ -755,9 +755,9 @@ void recordCriticalError(CriticalErrorCode code, uint32_t address, const char *f
|
||||
String lcd = String("Critical error ") + code + "!\n";
|
||||
screen->print(lcd.c_str());
|
||||
if (filename)
|
||||
DEBUG_MSG("NOTE! Recording critical error %d at %s:%lu\n", code, filename, address);
|
||||
LOG_ERROR("NOTE! Recording critical error %d at %s:%lu\n", code, filename, address);
|
||||
else
|
||||
DEBUG_MSG("NOTE! Recording critical error %d, address=0x%lx\n", code, address);
|
||||
LOG_ERROR("NOTE! Recording critical error %d, address=0x%lx\n", code, address);
|
||||
|
||||
// Record error to DB
|
||||
myNodeInfo.error_code = code;
|
||||
@@ -766,7 +766,7 @@ void recordCriticalError(CriticalErrorCode code, uint32_t address, const char *f
|
||||
|
||||
// Currently portuino is mostly used for simulation. Make sue the user notices something really bad happend
|
||||
#ifdef ARCH_PORTDUINO
|
||||
DEBUG_MSG("A critical failure occurred, portduino is exiting...");
|
||||
LOG_ERROR("A critical failure occurred, portduino is exiting...");
|
||||
exit(2);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -125,6 +125,9 @@ class NodeDB
|
||||
|
||||
bool factoryReset();
|
||||
|
||||
bool loadProto(const char *filename, size_t protoSize, size_t objSize, const pb_msgdesc_t *fields, void *dest_struct);
|
||||
bool saveProto(const char *filename, size_t protoSize, const pb_msgdesc_t *fields, const void *dest_struct);
|
||||
|
||||
private:
|
||||
/// Find a node in our DB, create an empty NodeInfo if missing
|
||||
NodeInfo *getOrCreateNode(NodeNum n);
|
||||
|
||||
@@ -14,7 +14,7 @@ PacketHistory::PacketHistory()
|
||||
bool PacketHistory::wasSeenRecently(const MeshPacket *p, bool withUpdate)
|
||||
{
|
||||
if (p->id == 0) {
|
||||
DEBUG_MSG("Ignoring message with zero id\n");
|
||||
LOG_DEBUG("Ignoring message with zero id\n");
|
||||
return false; // Not a floodable message ID, so we don't care
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ bool PacketHistory::wasSeenRecently(const MeshPacket *p, bool withUpdate)
|
||||
}
|
||||
|
||||
if (seenRecently) {
|
||||
DEBUG_MSG("Found existing packet record for fr=0x%x,to=0x%x,id=0x%x\n", p->from, p->to, p->id);
|
||||
LOG_DEBUG("Found existing packet record for fr=0x%x,to=0x%x,id=0x%x\n", p->from, p->to, p->id);
|
||||
}
|
||||
|
||||
if (withUpdate) {
|
||||
@@ -61,7 +61,7 @@ bool PacketHistory::wasSeenRecently(const MeshPacket *p, bool withUpdate)
|
||||
void PacketHistory::clearExpiredRecentPackets() {
|
||||
uint32_t now = millis();
|
||||
|
||||
DEBUG_MSG("recentPackets size=%ld\n", recentPackets.size());
|
||||
LOG_DEBUG("recentPackets size=%ld\n", recentPackets.size());
|
||||
|
||||
for (auto it = recentPackets.begin(); it != recentPackets.end(); ) {
|
||||
if ((now - it->rxTimeMsec) >= FLOOD_EXPIRE_TIME) {
|
||||
@@ -71,5 +71,5 @@ void PacketHistory::clearExpiredRecentPackets() {
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_MSG("recentPackets size=%ld (after clearing expired packets)\n", recentPackets.size());
|
||||
LOG_DEBUG("recentPackets size=%ld (after clearing expired packets)\n", recentPackets.size());
|
||||
}
|
||||
@@ -6,7 +6,6 @@
|
||||
#include "PowerFSM.h"
|
||||
#include "RadioInterface.h"
|
||||
#include "configuration.h"
|
||||
#include <assert.h>
|
||||
|
||||
#if FromRadio_size > MAX_TO_FROM_RADIO_SIZE
|
||||
#error FromRadio is too big
|
||||
@@ -37,7 +36,7 @@ void PhoneAPI::handleStartConfig()
|
||||
// even if we were already connected - restart our state machine
|
||||
state = STATE_SEND_MY_INFO;
|
||||
|
||||
DEBUG_MSG("Starting API client config\n");
|
||||
LOG_INFO("Starting API client config\n");
|
||||
nodeInfoForPhone = NULL; // Don't keep returning old nodeinfos
|
||||
nodeDB.resetReadPointer(); // FIXME, this read pointer should be moved out of nodeDB and into this class - because
|
||||
// this will break once we have multiple instances of PhoneAPI running independently
|
||||
@@ -50,6 +49,7 @@ void PhoneAPI::close()
|
||||
|
||||
unobserve(&service.fromNumChanged);
|
||||
releasePhonePacket(); // Don't leak phone packets on shutdown
|
||||
releaseQueueStatusPhonePacket();
|
||||
|
||||
onConnectionChanged(false);
|
||||
}
|
||||
@@ -60,7 +60,7 @@ void PhoneAPI::checkConnectionTimeout()
|
||||
if (isConnected()) {
|
||||
bool newContact = checkIsConnected();
|
||||
if (!newContact) {
|
||||
DEBUG_MSG("Lost phone connection\n");
|
||||
LOG_INFO("Lost phone connection\n");
|
||||
close();
|
||||
}
|
||||
}
|
||||
@@ -77,26 +77,26 @@ bool PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
|
||||
// return (lastContactMsec != 0) &&
|
||||
|
||||
memset(&toRadioScratch, 0, sizeof(toRadioScratch));
|
||||
if (pb_decode_from_bytes(buf, bufLength, ToRadio_fields, &toRadioScratch)) {
|
||||
if (pb_decode_from_bytes(buf, bufLength, &ToRadio_msg, &toRadioScratch)) {
|
||||
switch (toRadioScratch.which_payload_variant) {
|
||||
case ToRadio_packet_tag:
|
||||
return handleToRadioPacket(toRadioScratch.packet);
|
||||
case ToRadio_want_config_id_tag:
|
||||
config_nonce = toRadioScratch.want_config_id;
|
||||
DEBUG_MSG("Client wants config, nonce=%u\n", config_nonce);
|
||||
LOG_INFO("Client wants config, nonce=%u\n", config_nonce);
|
||||
handleStartConfig();
|
||||
break;
|
||||
case ToRadio_disconnect_tag:
|
||||
DEBUG_MSG("Disconnecting from phone\n");
|
||||
LOG_INFO("Disconnecting from phone\n");
|
||||
close();
|
||||
break;
|
||||
default:
|
||||
// Ignore nop messages
|
||||
// DEBUG_MSG("Error: unexpected ToRadio variant\n");
|
||||
// LOG_DEBUG("Error: unexpected ToRadio variant\n");
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
DEBUG_MSG("Error: ignoring malformed toradio\n");
|
||||
LOG_ERROR("Error: ignoring malformed toradio\n");
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -119,7 +119,7 @@ bool PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
|
||||
size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
{
|
||||
if (!available()) {
|
||||
// DEBUG_MSG("getFromRadio=not available\n");
|
||||
// LOG_DEBUG("getFromRadio=not available\n");
|
||||
return 0;
|
||||
}
|
||||
// In case we send a FromRadio packet
|
||||
@@ -128,11 +128,11 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
// Advance states as needed
|
||||
switch (state) {
|
||||
case STATE_SEND_NOTHING:
|
||||
DEBUG_MSG("getFromRadio=STATE_SEND_NOTHING\n");
|
||||
LOG_INFO("getFromRadio=STATE_SEND_NOTHING\n");
|
||||
break;
|
||||
|
||||
case STATE_SEND_MY_INFO:
|
||||
DEBUG_MSG("getFromRadio=STATE_SEND_MY_INFO\n");
|
||||
LOG_INFO("getFromRadio=STATE_SEND_MY_INFO\n");
|
||||
// If the user has specified they don't want our node to share its location, make sure to tell the phone
|
||||
// app not to send locations on our behalf.
|
||||
myNodeInfo.has_gps = gps && gps->isConnected(); // Update with latest GPS connect info
|
||||
@@ -144,18 +144,18 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
break;
|
||||
|
||||
case STATE_SEND_NODEINFO: {
|
||||
DEBUG_MSG("getFromRadio=STATE_SEND_NODEINFO\n");
|
||||
LOG_INFO("getFromRadio=STATE_SEND_NODEINFO\n");
|
||||
const NodeInfo *info = nodeInfoForPhone;
|
||||
nodeInfoForPhone = NULL; // We just consumed a nodeinfo, will need a new one next time
|
||||
|
||||
if (info) {
|
||||
DEBUG_MSG("Sending nodeinfo: num=0x%x, lastseen=%u, id=%s, name=%s\n", info->num, info->last_heard, info->user.id,
|
||||
LOG_INFO("Sending nodeinfo: num=0x%x, lastseen=%u, id=%s, name=%s\n", info->num, info->last_heard, info->user.id,
|
||||
info->user.long_name);
|
||||
fromRadioScratch.which_payload_variant = FromRadio_node_info_tag;
|
||||
fromRadioScratch.node_info = *info;
|
||||
// Stay in current state until done sending nodeinfos
|
||||
} else {
|
||||
DEBUG_MSG("Done sending nodeinfos\n");
|
||||
LOG_INFO("Done sending nodeinfos\n");
|
||||
state = STATE_SEND_CHANNELS;
|
||||
// Go ahead and send that ID right now
|
||||
return getFromRadio(buf);
|
||||
@@ -164,19 +164,19 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
}
|
||||
|
||||
case STATE_SEND_CHANNELS:
|
||||
DEBUG_MSG("getFromRadio=STATE_SEND_CHANNELS\n");
|
||||
LOG_INFO("getFromRadio=STATE_SEND_CHANNELS\n");
|
||||
fromRadioScratch.which_payload_variant = FromRadio_channel_tag;
|
||||
fromRadioScratch.channel = channels.getByIndex(config_state);
|
||||
config_state++;
|
||||
// Advance when we have sent all of our Channels
|
||||
if (config_state >= MAX_NUM_CHANNELS) {
|
||||
state = STATE_SEND_CONFIG;
|
||||
config_state = Config_device_tag;
|
||||
config_state = _AdminMessage_ConfigType_MIN + 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_SEND_CONFIG:
|
||||
DEBUG_MSG("getFromRadio=STATE_SEND_CONFIG\n");
|
||||
LOG_INFO("getFromRadio=STATE_SEND_CONFIG\n");
|
||||
fromRadioScratch.which_payload_variant = FromRadio_config_tag;
|
||||
switch (config_state) {
|
||||
case Config_device_tag:
|
||||
@@ -208,6 +208,8 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
fromRadioScratch.config.which_payload_variant = Config_bluetooth_tag;
|
||||
fromRadioScratch.config.payload_variant.bluetooth = config.bluetooth;
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("Unknown config type %d\n", config_state);
|
||||
}
|
||||
// NOTE: The phone app needs to know the ls_secs value so it can properly expect sleep behavior.
|
||||
// So even if we internally use 0 to represent 'use default' we still need to send the value we are
|
||||
@@ -215,14 +217,14 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
|
||||
config_state++;
|
||||
// Advance when we have sent all of our config objects
|
||||
if (config_state > Config_bluetooth_tag) {
|
||||
if (config_state > (_AdminMessage_ConfigType_MAX + 1)) {
|
||||
state = STATE_SEND_MODULECONFIG;
|
||||
config_state = ModuleConfig_mqtt_tag;
|
||||
config_state = _AdminMessage_ModuleConfigType_MIN + 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_SEND_MODULECONFIG:
|
||||
DEBUG_MSG("getFromRadio=STATE_SEND_MODULECONFIG\n");
|
||||
LOG_INFO("getFromRadio=STATE_SEND_MODULECONFIG\n");
|
||||
fromRadioScratch.which_payload_variant = FromRadio_moduleConfig_tag;
|
||||
switch (config_state) {
|
||||
case ModuleConfig_mqtt_tag:
|
||||
@@ -237,6 +239,10 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
fromRadioScratch.moduleConfig.which_payload_variant = ModuleConfig_external_notification_tag;
|
||||
fromRadioScratch.moduleConfig.payload_variant.external_notification = moduleConfig.external_notification;
|
||||
break;
|
||||
case ModuleConfig_store_forward_tag:
|
||||
fromRadioScratch.moduleConfig.which_payload_variant = ModuleConfig_store_forward_tag;
|
||||
fromRadioScratch.moduleConfig.payload_variant.store_forward = moduleConfig.store_forward;
|
||||
break;
|
||||
case ModuleConfig_range_test_tag:
|
||||
fromRadioScratch.moduleConfig.which_payload_variant = ModuleConfig_range_test_tag;
|
||||
fromRadioScratch.moduleConfig.payload_variant.range_test = moduleConfig.range_test;
|
||||
@@ -253,18 +259,24 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
fromRadioScratch.moduleConfig.which_payload_variant = ModuleConfig_audio_tag;
|
||||
fromRadioScratch.moduleConfig.payload_variant.audio = moduleConfig.audio;
|
||||
break;
|
||||
case ModuleConfig_remote_hardware_tag:
|
||||
fromRadioScratch.moduleConfig.which_payload_variant = ModuleConfig_remote_hardware_tag;
|
||||
fromRadioScratch.moduleConfig.payload_variant.remote_hardware = moduleConfig.remote_hardware;
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("Unknown module config type %d\n", config_state);
|
||||
}
|
||||
|
||||
config_state++;
|
||||
// Advance when we have sent all of our ModuleConfig objects
|
||||
if (config_state > ModuleConfig_audio_tag) {
|
||||
if (config_state > (_AdminMessage_ModuleConfigType_MAX + 1)) {
|
||||
state = STATE_SEND_COMPLETE_ID;
|
||||
config_state = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_SEND_COMPLETE_ID:
|
||||
DEBUG_MSG("getFromRadio=STATE_SEND_COMPLETE_ID\n");
|
||||
LOG_INFO("getFromRadio=STATE_SEND_COMPLETE_ID\n");
|
||||
fromRadioScratch.which_payload_variant = FromRadio_config_complete_id_tag;
|
||||
fromRadioScratch.config_complete_id = config_nonce;
|
||||
config_nonce = 0;
|
||||
@@ -273,37 +285,42 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
|
||||
case STATE_SEND_PACKETS:
|
||||
// Do we have a message from the mesh?
|
||||
DEBUG_MSG("getFromRadio=STATE_SEND_PACKETS\n");
|
||||
if (packetForPhone) {
|
||||
LOG_INFO("getFromRadio=STATE_SEND_PACKETS\n");
|
||||
if (queueStatusPacketForPhone) {
|
||||
|
||||
fromRadioScratch.which_payload_variant = FromRadio_queueStatus_tag;
|
||||
fromRadioScratch.queueStatus = *queueStatusPacketForPhone;
|
||||
releaseQueueStatusPhonePacket();
|
||||
} else if (packetForPhone) {
|
||||
printPacket("phone downloaded packet", packetForPhone);
|
||||
|
||||
// Encapsulate as a FromRadio packet
|
||||
fromRadioScratch.which_payload_variant = FromRadio_packet_tag;
|
||||
fromRadioScratch.packet = *packetForPhone;
|
||||
}
|
||||
releasePhonePacket();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0); // unexpected state - FIXME, make an error code and reboot
|
||||
LOG_ERROR("getFromRadio unexpected state %d\n", state);
|
||||
}
|
||||
|
||||
// Do we have a message from the mesh?
|
||||
if (fromRadioScratch.which_payload_variant != 0) {
|
||||
// Encapsulate as a FromRadio packet
|
||||
size_t numbytes = pb_encode_to_bytes(buf, FromRadio_size, FromRadio_fields, &fromRadioScratch);
|
||||
size_t numbytes = pb_encode_to_bytes(buf, FromRadio_size, &FromRadio_msg, &fromRadioScratch);
|
||||
|
||||
DEBUG_MSG("encoding toPhone packet to phone variant=%d, %d bytes\n", fromRadioScratch.which_payload_variant, numbytes);
|
||||
LOG_DEBUG("encoding toPhone packet to phone variant=%d, %d bytes\n", fromRadioScratch.which_payload_variant, numbytes);
|
||||
return numbytes;
|
||||
}
|
||||
|
||||
DEBUG_MSG("no FromRadio packet available\n");
|
||||
LOG_DEBUG("no FromRadio packet available\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PhoneAPI::handleDisconnect()
|
||||
{
|
||||
DEBUG_MSG("PhoneAPI disconnect\n");
|
||||
LOG_INFO("PhoneAPI disconnect\n");
|
||||
}
|
||||
|
||||
void PhoneAPI::releasePhonePacket()
|
||||
@@ -314,6 +331,14 @@ void PhoneAPI::releasePhonePacket()
|
||||
}
|
||||
}
|
||||
|
||||
void PhoneAPI::releaseQueueStatusPhonePacket()
|
||||
{
|
||||
if (queueStatusPacketForPhone) {
|
||||
service.releaseQueueStatusToPool(queueStatusPacketForPhone);
|
||||
queueStatusPacketForPhone = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if we have data available to send to the phone
|
||||
*/
|
||||
@@ -334,14 +359,20 @@ bool PhoneAPI::available()
|
||||
return true; // Always say we have something, because we might need to advance our state machine
|
||||
|
||||
case STATE_SEND_PACKETS: {
|
||||
if (!queueStatusPacketForPhone)
|
||||
queueStatusPacketForPhone = service.getQueueStatusForPhone();
|
||||
bool hasPacket = !!queueStatusPacketForPhone;
|
||||
if (hasPacket)
|
||||
return true;
|
||||
|
||||
if (!packetForPhone)
|
||||
packetForPhone = service.getForPhone();
|
||||
bool hasPacket = !!packetForPhone;
|
||||
// DEBUG_MSG("available hasPacket=%d\n", hasPacket);
|
||||
hasPacket = !!packetForPhone;
|
||||
// LOG_DEBUG("available hasPacket=%d\n", hasPacket);
|
||||
return hasPacket;
|
||||
}
|
||||
default:
|
||||
assert(0); // unexpected state - FIXME, make an error code and reboot
|
||||
LOG_ERROR("PhoneAPI::available unexpected state %d\n", state);
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -365,10 +396,10 @@ int PhoneAPI::onNotify(uint32_t newValue)
|
||||
// from idle)
|
||||
|
||||
if (state == STATE_SEND_PACKETS) {
|
||||
DEBUG_MSG("Telling client we have new packets %u\n", newValue);
|
||||
LOG_INFO("Telling client we have new packets %u\n", newValue);
|
||||
onNowHasData(newValue);
|
||||
} else
|
||||
DEBUG_MSG("(Client not yet interested in packets)\n");
|
||||
LOG_DEBUG("(Client not yet interested in packets)\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -42,6 +42,9 @@ class PhoneAPI : public Observer<uint32_t> // FIXME, we shouldn't be inheriting
|
||||
/// downloads it
|
||||
MeshPacket *packetForPhone = NULL;
|
||||
|
||||
// Keep QueueStatus packet just as packetForPhone
|
||||
QueueStatus *queueStatusPacketForPhone = NULL;
|
||||
|
||||
/// We temporarily keep the nodeInfo here between the call to available and getFromRadio
|
||||
const NodeInfo *nodeInfoForPhone = NULL;
|
||||
|
||||
@@ -83,9 +86,6 @@ class PhoneAPI : public Observer<uint32_t> // FIXME, we shouldn't be inheriting
|
||||
|
||||
void setInitialState() { state = STATE_SEND_MY_INFO; }
|
||||
|
||||
/// emit a debugging log character, FIXME - implement
|
||||
void debugOut(char c) { }
|
||||
|
||||
protected:
|
||||
/// Our fromradio packet while it is being assembled
|
||||
FromRadio fromRadioScratch = {};
|
||||
@@ -115,6 +115,8 @@ class PhoneAPI : public Observer<uint32_t> // FIXME, we shouldn't be inheriting
|
||||
private:
|
||||
void releasePhonePacket();
|
||||
|
||||
void releaseQueueStatusPhonePacket();
|
||||
|
||||
/// begin a new connection
|
||||
void handleStartConfig();
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ template <class T> class ProtobufModule : protected SinglePortModule
|
||||
|
||||
p->decoded.payload.size =
|
||||
pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), fields, &payload);
|
||||
// DEBUG_MSG("did encode\n");
|
||||
// LOG_DEBUG("did encode\n");
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ template <class T> class ProtobufModule : protected SinglePortModule
|
||||
// it would be better to update even if the message was destined to others.
|
||||
|
||||
auto &p = mp.decoded;
|
||||
DEBUG_MSG("Received %s from=0x%0x, id=0x%x, portnum=%d, payloadlen=%d\n", name, mp.from, mp.id, p.portnum,
|
||||
LOG_INFO("Received %s from=0x%0x, id=0x%x, portnum=%d, payloadlen=%d\n", name, mp.from, mp.id, p.portnum,
|
||||
p.payload.size);
|
||||
|
||||
T scratch;
|
||||
@@ -80,7 +80,7 @@ template <class T> class ProtobufModule : protected SinglePortModule
|
||||
if (pb_decode_from_bytes(p.payload.bytes, p.payload.size, fields, &scratch)) {
|
||||
decoded = &scratch;
|
||||
} else {
|
||||
DEBUG_MSG("Error decoding protobuf module!\n");
|
||||
LOG_ERROR("Error decoding protobuf module!\n");
|
||||
// if we can't decode it, nobody can process it!
|
||||
return ProcessMessage::STOP;
|
||||
}
|
||||
|
||||
@@ -68,17 +68,17 @@ bool RF95Interface::init()
|
||||
setTransmitEnable(false);
|
||||
|
||||
int res = lora->begin(getFreq(), bw, sf, cr, syncWord, power, currentLimit, preambleLength);
|
||||
DEBUG_MSG("RF95 init result %d\n", res);
|
||||
LOG_INFO("RF95 init result %d\n", res);
|
||||
|
||||
DEBUG_MSG("Frequency set to %f\n", getFreq());
|
||||
DEBUG_MSG("Bandwidth set to %f\n", bw);
|
||||
DEBUG_MSG("Power output set to %d\n", power);
|
||||
LOG_INFO("Frequency set to %f\n", getFreq());
|
||||
LOG_INFO("Bandwidth set to %f\n", bw);
|
||||
LOG_INFO("Power output set to %d\n", power);
|
||||
|
||||
// current limit was removed from module' ctor
|
||||
// override default value (60 mA)
|
||||
res = lora->setCurrentLimit(currentLimit);
|
||||
DEBUG_MSG("Current limit set to %f\n", currentLimit);
|
||||
DEBUG_MSG("Current limit set result %d\n", res);
|
||||
LOG_DEBUG("Current limit set to %f\n", currentLimit);
|
||||
LOG_DEBUG("Current limit set result %d\n", res);
|
||||
|
||||
if (res == RADIOLIB_ERR_NONE)
|
||||
res = lora->setCRC(RADIOLIB_SX126X_LORA_CRC_ON);
|
||||
@@ -190,12 +190,12 @@ bool RF95Interface::isChannelActive()
|
||||
result = lora->scanChannel();
|
||||
|
||||
if (result == RADIOLIB_PREAMBLE_DETECTED) {
|
||||
// DEBUG_MSG("Channel is busy!\n");
|
||||
// LOG_DEBUG("Channel is busy!\n");
|
||||
return true;
|
||||
}
|
||||
assert(result != RADIOLIB_ERR_WRONG_MODEM);
|
||||
|
||||
// DEBUG_MSG("Channel is free!\n");
|
||||
// LOG_DEBUG("Channel is free!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
#include "Router.h"
|
||||
#include "assert.h"
|
||||
#include "configuration.h"
|
||||
#include "main.h"
|
||||
#include "sleep.h"
|
||||
@@ -111,13 +110,15 @@ const RegionInfo regions[] = {
|
||||
|
||||
const RegionInfo *myRegion;
|
||||
|
||||
static uint8_t bytes[MAX_RHPACKETLEN];
|
||||
|
||||
void initRegion()
|
||||
{
|
||||
const RegionInfo *r = regions;
|
||||
for (; r->code != Config_LoRaConfig_RegionCode_UNSET && r->code != config.lora.region; r++)
|
||||
;
|
||||
myRegion = r;
|
||||
DEBUG_MSG("Wanted region %d, using %s\n", config.lora.region, r->name);
|
||||
LOG_INFO("Wanted region %d, using %s\n", config.lora.region, r->name);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -157,28 +158,30 @@ uint32_t RadioInterface::getPacketTime(uint32_t pl)
|
||||
|
||||
uint32_t msecs = tPacket * 1000;
|
||||
|
||||
DEBUG_MSG("(bw=%d, sf=%d, cr=4/%d) packet symLen=%d ms, payloadSize=%u, time %d ms\n", (int)bw, sf, cr, (int)(tSym * 1000),
|
||||
LOG_DEBUG("(bw=%d, sf=%d, cr=4/%d) packet symLen=%d ms, payloadSize=%u, time %d ms\n", (int)bw, sf, cr, (int)(tSym * 1000),
|
||||
pl, msecs);
|
||||
return msecs;
|
||||
}
|
||||
|
||||
uint32_t RadioInterface::getPacketTime(MeshPacket *p)
|
||||
{
|
||||
assert(p->which_payload_variant == MeshPacket_encrypted_tag); // It should have already been encoded by now
|
||||
uint32_t pl = p->encrypted.size + sizeof(PacketHeader);
|
||||
|
||||
uint32_t pl = 0;
|
||||
if(p->which_payload_variant == MeshPacket_encrypted_tag) {
|
||||
pl = p->encrypted.size + sizeof(PacketHeader);
|
||||
} else {
|
||||
size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), &Data_msg, &p->decoded);
|
||||
pl = numbytes + sizeof(PacketHeader);
|
||||
}
|
||||
return getPacketTime(pl);
|
||||
}
|
||||
|
||||
/** The delay to use for retransmitting dropped packets */
|
||||
uint32_t RadioInterface::getRetransmissionMsec(const MeshPacket *p)
|
||||
{
|
||||
assert(slotTimeMsec); // Better be non zero
|
||||
static uint8_t bytes[MAX_RHPACKETLEN];
|
||||
size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), Data_fields, &p->decoded);
|
||||
size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), &Data_msg, &p->decoded);
|
||||
uint32_t packetAirtime = getPacketTime(numbytes + sizeof(PacketHeader));
|
||||
// Make sure enough time has elapsed for this packet to be sent and an ACK is received.
|
||||
// DEBUG_MSG("Waiting for flooding message with airtime %d and slotTime is %d\n", packetAirtime, slotTimeMsec);
|
||||
// LOG_DEBUG("Waiting for flooding message with airtime %d and slotTime is %d\n", packetAirtime, slotTimeMsec);
|
||||
float channelUtil = airTime->channelUtilizationPercent();
|
||||
uint8_t CWsize = map(channelUtil, 0, 100, CWmin, CWmax);
|
||||
// Assuming we pick max. of CWsize and there will be a receiver with SNR at half the range
|
||||
@@ -193,7 +196,7 @@ uint32_t RadioInterface::getTxDelayMsec()
|
||||
current channel utilization. */
|
||||
float channelUtil = airTime->channelUtilizationPercent();
|
||||
uint8_t CWsize = map(channelUtil, 0, 100, CWmin, CWmax);
|
||||
// DEBUG_MSG("Current channel utilization is %f so setting CWsize to %d\n", channelUtil, CWsize);
|
||||
// LOG_DEBUG("Current channel utilization is %f so setting CWsize to %d\n", channelUtil, CWsize);
|
||||
return random(0, pow(2, CWsize)) * slotTimeMsec;
|
||||
}
|
||||
|
||||
@@ -210,14 +213,14 @@ uint32_t RadioInterface::getTxDelayMsecWeighted(float snr)
|
||||
// low SNR = small CW size (Short Delay)
|
||||
uint32_t delay = 0;
|
||||
uint8_t CWsize = map(snr, SNR_MIN, SNR_MAX, CWmin, CWmax);
|
||||
// DEBUG_MSG("rx_snr of %f so setting CWsize to:%d\n", snr, CWsize);
|
||||
// LOG_DEBUG("rx_snr of %f so setting CWsize to:%d\n", snr, CWsize);
|
||||
if (config.device.role == Config_DeviceConfig_Role_ROUTER ||
|
||||
config.device.role == Config_DeviceConfig_Role_ROUTER_CLIENT) {
|
||||
delay = random(0, 2*CWsize) * slotTimeMsec;
|
||||
DEBUG_MSG("rx_snr found in packet. As a router, setting tx delay:%d\n", delay);
|
||||
LOG_DEBUG("rx_snr found in packet. As a router, setting tx delay:%d\n", delay);
|
||||
} else {
|
||||
delay = random(0, pow(2, CWsize)) * slotTimeMsec;
|
||||
DEBUG_MSG("rx_snr found in packet. Setting tx delay:%d\n", delay);
|
||||
LOG_DEBUG("rx_snr found in packet. Setting tx delay:%d\n", delay);
|
||||
}
|
||||
|
||||
return delay;
|
||||
@@ -225,55 +228,52 @@ uint32_t RadioInterface::getTxDelayMsecWeighted(float snr)
|
||||
|
||||
void printPacket(const char *prefix, const MeshPacket *p)
|
||||
{
|
||||
DEBUG_MSG("%s (id=0x%08x fr=0x%02x to=0x%02x, WantAck=%d, HopLim=%d Ch=0x%x", prefix, p->id, p->from & 0xff, p->to & 0xff,
|
||||
LOG_DEBUG("%s (id=0x%08x fr=0x%02x to=0x%02x, WantAck=%d, HopLim=%d Ch=0x%x", prefix, p->id, p->from & 0xff, p->to & 0xff,
|
||||
p->want_ack, p->hop_limit, p->channel);
|
||||
if (p->which_payload_variant == MeshPacket_decoded_tag) {
|
||||
auto &s = p->decoded;
|
||||
|
||||
DEBUG_MSG(" Portnum=%d", s.portnum);
|
||||
LOG_DEBUG(" Portnum=%d", s.portnum);
|
||||
|
||||
if (s.want_response)
|
||||
DEBUG_MSG(" WANTRESP");
|
||||
LOG_DEBUG(" WANTRESP");
|
||||
|
||||
if (s.source != 0)
|
||||
DEBUG_MSG(" source=%08x", s.source);
|
||||
LOG_DEBUG(" source=%08x", s.source);
|
||||
|
||||
if (s.dest != 0)
|
||||
DEBUG_MSG(" dest=%08x", s.dest);
|
||||
LOG_DEBUG(" dest=%08x", s.dest);
|
||||
|
||||
if (s.request_id)
|
||||
DEBUG_MSG(" requestId=%0x", s.request_id);
|
||||
LOG_DEBUG(" requestId=%0x", s.request_id);
|
||||
|
||||
/* now inside Data and therefore kinda opaque
|
||||
if (s.which_ackVariant == SubPacket_success_id_tag)
|
||||
DEBUG_MSG(" successId=%08x", s.ackVariant.success_id);
|
||||
LOG_DEBUG(" successId=%08x", s.ackVariant.success_id);
|
||||
else if (s.which_ackVariant == SubPacket_fail_id_tag)
|
||||
DEBUG_MSG(" failId=%08x", s.ackVariant.fail_id); */
|
||||
LOG_DEBUG(" failId=%08x", s.ackVariant.fail_id); */
|
||||
} else {
|
||||
DEBUG_MSG(" encrypted");
|
||||
LOG_DEBUG(" encrypted");
|
||||
}
|
||||
|
||||
if (p->rx_time != 0) {
|
||||
DEBUG_MSG(" rxtime=%u", p->rx_time);
|
||||
LOG_DEBUG(" rxtime=%u", p->rx_time);
|
||||
}
|
||||
if (p->rx_snr != 0.0) {
|
||||
DEBUG_MSG(" rxSNR=%g", p->rx_snr);
|
||||
LOG_DEBUG(" rxSNR=%g", p->rx_snr);
|
||||
}
|
||||
if (p->rx_rssi != 0) {
|
||||
DEBUG_MSG(" rxRSSI=%g", p->rx_rssi);
|
||||
LOG_DEBUG(" rxRSSI=%g", p->rx_rssi);
|
||||
}
|
||||
if (p->priority != 0)
|
||||
DEBUG_MSG(" priority=%d", p->priority);
|
||||
LOG_DEBUG(" priority=%d", p->priority);
|
||||
|
||||
DEBUG_MSG(")\n");
|
||||
LOG_DEBUG(")\n");
|
||||
}
|
||||
|
||||
RadioInterface::RadioInterface()
|
||||
{
|
||||
assert(sizeof(PacketHeader) == 16); // make sure the compiler did what we expected
|
||||
|
||||
// Can't print strings this early - serial not setup yet
|
||||
// DEBUG_MSG("Set meshradio defaults name=%s\n", channelSettings.name);
|
||||
}
|
||||
|
||||
bool RadioInterface::reconfigure()
|
||||
@@ -284,7 +284,7 @@ bool RadioInterface::reconfigure()
|
||||
|
||||
bool RadioInterface::init()
|
||||
{
|
||||
DEBUG_MSG("Starting meshradio init...\n");
|
||||
LOG_INFO("Starting meshradio init...\n");
|
||||
|
||||
configChangedObserver.observe(&service.configChanged);
|
||||
preflightSleepObserver.observe(&preflightSleep);
|
||||
@@ -384,7 +384,7 @@ void RadioInterface::applyModemConfig()
|
||||
cr = 8;
|
||||
sf = 10;
|
||||
break;
|
||||
case Config_LoRaConfig_ModemPreset_LONG_FAST:
|
||||
default: // Config_LoRaConfig_ModemPreset_LONG_FAST is default. Gracefully use this is preset is something illegal.
|
||||
bw = (myRegion->wideLora) ? 812.5 : 250;
|
||||
cr = 8;
|
||||
sf = 11;
|
||||
@@ -399,8 +399,6 @@ void RadioInterface::applyModemConfig()
|
||||
cr = 8;
|
||||
sf = 12;
|
||||
break;
|
||||
default:
|
||||
assert(0); // Unknown enum
|
||||
}
|
||||
} else {
|
||||
sf = loraConfig.spread_factor;
|
||||
@@ -422,7 +420,6 @@ void RadioInterface::applyModemConfig()
|
||||
}
|
||||
|
||||
power = loraConfig.tx_power;
|
||||
assert(myRegion); // Should have been found in init
|
||||
|
||||
if ((power == 0) || ((power > myRegion->powerLimit) && !devicestate.owner.is_licensed))
|
||||
power = myRegion->powerLimit;
|
||||
@@ -449,13 +446,13 @@ void RadioInterface::applyModemConfig()
|
||||
saveChannelNum(channel_num);
|
||||
saveFreq(freq + config.lora.frequency_offset);
|
||||
|
||||
DEBUG_MSG("Radio freq=%.3f, config.lora.frequency_offset=%.3f\n", freq, config.lora.frequency_offset);
|
||||
DEBUG_MSG("Set radio: region=%s, name=%s, config=%u, ch=%d, power=%d\n", myRegion->name, channelName, loraConfig.modem_preset, channel_num, power);
|
||||
DEBUG_MSG("Radio myRegion->freqStart -> myRegion->freqEnd: %f -> %f (%f mhz)\n", myRegion->freqStart, myRegion->freqEnd, myRegion->freqEnd - myRegion->freqStart);
|
||||
DEBUG_MSG("Radio myRegion->numChannels: %d x %.3fkHz\n", numChannels, bw);
|
||||
DEBUG_MSG("Radio channel_num: %d\n", channel_num);
|
||||
DEBUG_MSG("Radio frequency: %f\n", getFreq());
|
||||
DEBUG_MSG("Slot time: %u msec\n", slotTimeMsec);
|
||||
LOG_INFO("Radio freq=%.3f, config.lora.frequency_offset=%.3f\n", freq, config.lora.frequency_offset);
|
||||
LOG_INFO("Set radio: region=%s, name=%s, config=%u, ch=%d, power=%d\n", myRegion->name, channelName, loraConfig.modem_preset, channel_num, power);
|
||||
LOG_INFO("Radio myRegion->freqStart -> myRegion->freqEnd: %f -> %f (%f mhz)\n", myRegion->freqStart, myRegion->freqEnd, myRegion->freqEnd - myRegion->freqStart);
|
||||
LOG_INFO("Radio myRegion->numChannels: %d x %.3fkHz\n", numChannels, bw);
|
||||
LOG_INFO("Radio channel_num: %d\n", channel_num);
|
||||
LOG_INFO("Radio frequency: %f\n", getFreq());
|
||||
LOG_INFO("Slot time: %u msec\n", slotTimeMsec);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -470,11 +467,11 @@ void RadioInterface::limitPower()
|
||||
maxPower = myRegion->powerLimit;
|
||||
|
||||
if ((power > maxPower) && !devicestate.owner.is_licensed) {
|
||||
DEBUG_MSG("Lowering transmit power because of regulatory limits\n");
|
||||
LOG_INFO("Lowering transmit power because of regulatory limits\n");
|
||||
power = maxPower;
|
||||
}
|
||||
|
||||
DEBUG_MSG("Set radio: final power level=%d\n", power);
|
||||
LOG_INFO("Set radio: final power level=%d\n", power);
|
||||
}
|
||||
|
||||
|
||||
@@ -491,7 +488,7 @@ size_t RadioInterface::beginSending(MeshPacket *p)
|
||||
{
|
||||
assert(!sendingPacket);
|
||||
|
||||
// DEBUG_MSG("sending queued packet on mesh (txGood=%d,rxGood=%d,rxBad=%d)\n", rf95.txGood(), rf95.rxGood(), rf95.rxBad());
|
||||
// LOG_DEBUG("sending queued packet on mesh (txGood=%d,rxGood=%d,rxBad=%d)\n", rf95.txGood(), rf95.rxGood(), rf95.rxBad());
|
||||
assert(p->which_payload_variant == MeshPacket_encrypted_tag); // It should have already been encoded by now
|
||||
|
||||
lastTxStart = millis();
|
||||
@@ -502,7 +499,10 @@ size_t RadioInterface::beginSending(MeshPacket *p)
|
||||
h->to = p->to;
|
||||
h->id = p->id;
|
||||
h->channel = p->channel;
|
||||
assert(p->hop_limit <= HOP_MAX);
|
||||
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;
|
||||
}
|
||||
h->flags = p->hop_limit | (p->want_ack ? PACKET_FLAGS_WANT_ACK_MASK : 0);
|
||||
|
||||
// if the sender nodenum is zero, that means uninitialized
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "../concurrency/NotifiedWorkerThread.h"
|
||||
#include "MemoryPool.h"
|
||||
#include "MeshTypes.h"
|
||||
#include "Observer.h"
|
||||
@@ -97,6 +96,8 @@ class RadioInterface
|
||||
*/
|
||||
virtual bool canSleep() { return true; }
|
||||
|
||||
virtual bool wideLora() { return false; }
|
||||
|
||||
/// Prepare hardware for sleep. Call this _only_ for deep sleep, not needed for light sleep.
|
||||
virtual bool sleep() { return true; }
|
||||
|
||||
@@ -114,6 +115,13 @@ class RadioInterface
|
||||
*/
|
||||
virtual ErrorCode send(MeshPacket *p) = 0;
|
||||
|
||||
/** Return TX queue status */
|
||||
virtual QueueStatus getQueueStatus() {
|
||||
QueueStatus qs;
|
||||
qs.res = qs.mesh_packet_id = qs.free = qs.maxlen = 0;
|
||||
return qs;
|
||||
}
|
||||
|
||||
/** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */
|
||||
virtual bool cancelSending(NodeNum from, PacketId id) { return false; }
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "NodeDB.h"
|
||||
#include "SPILock.h"
|
||||
#include "configuration.h"
|
||||
#include "main.h"
|
||||
#include "error.h"
|
||||
#include "mesh-pb-constants.h"
|
||||
#include <pb_decode.h>
|
||||
@@ -81,19 +82,17 @@ bool RadioLibInterface::canSendImmediately()
|
||||
|
||||
if (busyTx || busyRx) {
|
||||
if (busyTx)
|
||||
DEBUG_MSG("Can not send yet, busyTx\n");
|
||||
LOG_WARN("Can not send yet, busyTx\n");
|
||||
// If we've been trying to send the same packet more than one minute and we haven't gotten a
|
||||
// TX IRQ from the radio, the radio is probably broken.
|
||||
if (busyTx && (millis() - lastTxStart > 60000)) {
|
||||
DEBUG_MSG("Hardware Failure! busyTx for more than 60s\n");
|
||||
LOG_ERROR("Hardware Failure! busyTx for more than 60s\n");
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_TRANSMIT_FAILED);
|
||||
#ifdef ARCH_ESP32
|
||||
if (busyTx && (millis() - lastTxStart > 65000)) // After 5s more, reboot
|
||||
ESP.restart();
|
||||
#endif
|
||||
// reboot in 5 seconds when this condition occurs.
|
||||
rebootAtMsec = lastTxStart + 65000;
|
||||
}
|
||||
if (busyRx)
|
||||
DEBUG_MSG("Can not send yet, busyRx\n");
|
||||
LOG_WARN("Can not send yet, busyRx\n");
|
||||
return false;
|
||||
} else
|
||||
return true;
|
||||
@@ -112,13 +111,13 @@ ErrorCode RadioLibInterface::send(MeshPacket *p)
|
||||
|
||||
if (config.lora.region != Config_LoRaConfig_RegionCode_UNSET) {
|
||||
if (disabled || !config.lora.tx_enabled) {
|
||||
DEBUG_MSG("send - !config.lora.tx_enabled\n");
|
||||
LOG_WARN("send - !config.lora.tx_enabled\n");
|
||||
packetPool.release(p);
|
||||
return ERRNO_DISABLED;
|
||||
}
|
||||
|
||||
} else {
|
||||
DEBUG_MSG("send - lora tx disable because RegionCode_Unset\n");
|
||||
LOG_WARN("send - lora tx disable because RegionCode_Unset\n");
|
||||
packetPool.release(p);
|
||||
return ERRNO_DISABLED;
|
||||
}
|
||||
@@ -128,7 +127,7 @@ ErrorCode RadioLibInterface::send(MeshPacket *p)
|
||||
#else
|
||||
|
||||
if (disabled || !config.lora.tx_enabled) {
|
||||
DEBUG_MSG("send - !config.lora.tx_enabled\n");
|
||||
LOG_WARN("send - !config.lora.tx_enabled\n");
|
||||
packetPool.release(p);
|
||||
return ERRNO_DISABLED;
|
||||
}
|
||||
@@ -139,7 +138,7 @@ ErrorCode RadioLibInterface::send(MeshPacket *p)
|
||||
#ifndef LORA_DISABLE_SENDING
|
||||
printPacket("enqueuing for send", p);
|
||||
|
||||
DEBUG_MSG("txGood=%d,rxGood=%d,rxBad=%d\n", txGood, rxGood, rxBad);
|
||||
LOG_DEBUG("txGood=%d,rxGood=%d,rxBad=%d\n", txGood, rxGood, rxBad);
|
||||
ErrorCode res = txQueue.enqueue(p) ? ERRNO_OK : ERRNO_UNKNOWN;
|
||||
|
||||
if (res != ERRNO_OK) { // we weren't able to queue it, so we must drop it to prevent leaks
|
||||
@@ -149,7 +148,7 @@ ErrorCode RadioLibInterface::send(MeshPacket *p)
|
||||
|
||||
// set (random) transmit delay to let others reconfigure their radio,
|
||||
// to avoid collisions and implement timing-based flooding
|
||||
// DEBUG_MSG("Set random delay before transmitting.\n");
|
||||
// LOG_DEBUG("Set random delay before transmitting.\n");
|
||||
setTransmitDelay();
|
||||
|
||||
return res;
|
||||
@@ -159,11 +158,22 @@ ErrorCode RadioLibInterface::send(MeshPacket *p)
|
||||
#endif
|
||||
}
|
||||
|
||||
QueueStatus RadioLibInterface::getQueueStatus()
|
||||
{
|
||||
QueueStatus qs;
|
||||
|
||||
qs.res = qs.mesh_packet_id = 0;
|
||||
qs.free = txQueue.getFree();
|
||||
qs.maxlen = txQueue.getMaxLen();
|
||||
|
||||
return qs;
|
||||
}
|
||||
|
||||
bool RadioLibInterface::canSleep()
|
||||
{
|
||||
bool res = txQueue.empty();
|
||||
if (!res) // only print debug messages if we are vetoing sleep
|
||||
DEBUG_MSG("radio wait to sleep, txEmpty=%d\n", res);
|
||||
LOG_DEBUG("radio wait to sleep, txEmpty=%d\n", res);
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -176,7 +186,7 @@ ErrorCode RadioLibInterface::send(MeshPacket *p)
|
||||
packetPool.release(p); // free the packet we just removed
|
||||
|
||||
bool result = (p != NULL);
|
||||
DEBUG_MSG("cancelSending id=0x%x, removed=%d\n", id, result);
|
||||
LOG_DEBUG("cancelSending id=0x%x, removed=%d\n", id, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -193,27 +203,27 @@ ErrorCode RadioLibInterface::send(MeshPacket *p)
|
||||
case ISR_TX:
|
||||
handleTransmitInterrupt();
|
||||
startReceive();
|
||||
// DEBUG_MSG("tx complete - starting timer\n");
|
||||
// LOG_DEBUG("tx complete - starting timer\n");
|
||||
startTransmitTimer();
|
||||
break;
|
||||
case ISR_RX:
|
||||
handleReceiveInterrupt();
|
||||
startReceive();
|
||||
// DEBUG_MSG("rx complete - starting timer\n");
|
||||
// LOG_DEBUG("rx complete - starting timer\n");
|
||||
startTransmitTimer();
|
||||
break;
|
||||
case TRANSMIT_DELAY_COMPLETED:
|
||||
// DEBUG_MSG("delay done\n");
|
||||
// LOG_DEBUG("delay done\n");
|
||||
|
||||
// If we are not currently in receive mode, then restart the random delay (this can happen if the main thread
|
||||
// has placed the unit into standby) FIXME, how will this work if the chipset is in sleep mode?
|
||||
if (!txQueue.empty()) {
|
||||
if (!canSendImmediately()) {
|
||||
// DEBUG_MSG("Currently Rx/Tx-ing: set random delay\n");
|
||||
// LOG_DEBUG("Currently Rx/Tx-ing: set random delay\n");
|
||||
setTransmitDelay(); // currently Rx/Tx-ing: reset random delay
|
||||
} else {
|
||||
if (isChannelActive()) { // check if there is currently a LoRa packet on the channel
|
||||
// DEBUG_MSG("Channel is active: set random delay\n");
|
||||
// LOG_DEBUG("Channel is active: set random delay\n");
|
||||
setTransmitDelay(); // reset random delay
|
||||
} else {
|
||||
// Send any outgoing packets we have ready
|
||||
@@ -227,7 +237,7 @@ ErrorCode RadioLibInterface::send(MeshPacket *p)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// DEBUG_MSG("done with txqueue\n");
|
||||
// LOG_DEBUG("done with txqueue\n");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -250,7 +260,7 @@ ErrorCode RadioLibInterface::send(MeshPacket *p)
|
||||
startTransmitTimer(true);
|
||||
} else {
|
||||
// If there is a SNR, start a timer scaled based on that SNR.
|
||||
DEBUG_MSG("rx_snr found. hop_limit:%d rx_snr:%f\n", p->hop_limit, p->rx_snr);
|
||||
LOG_DEBUG("rx_snr found. hop_limit:%d rx_snr:%f\n", p->hop_limit, p->rx_snr);
|
||||
startTransmitTimerSNR(p->rx_snr);
|
||||
}
|
||||
}
|
||||
@@ -260,7 +270,7 @@ ErrorCode RadioLibInterface::send(MeshPacket *p)
|
||||
// If we have work to do and the timer wasn't already scheduled, schedule it now
|
||||
if (!txQueue.empty()) {
|
||||
uint32_t delay = !withDelay ? 1 : getTxDelayMsec();
|
||||
// DEBUG_MSG("xmit timer %d\n", delay);
|
||||
// LOG_DEBUG("xmit timer %d\n", delay);
|
||||
notifyLater(delay, TRANSMIT_DELAY_COMPLETED, false); // This will implicitly enable
|
||||
}
|
||||
}
|
||||
@@ -270,14 +280,14 @@ ErrorCode RadioLibInterface::send(MeshPacket *p)
|
||||
// If we have work to do and the timer wasn't already scheduled, schedule it now
|
||||
if (!txQueue.empty()) {
|
||||
uint32_t delay = getTxDelayMsecWeighted(snr);
|
||||
// DEBUG_MSG("xmit timer %d\n", delay);
|
||||
// LOG_DEBUG("xmit timer %d\n", delay);
|
||||
notifyLater(delay, TRANSMIT_DELAY_COMPLETED, false); // This will implicitly enable
|
||||
}
|
||||
}
|
||||
|
||||
void RadioLibInterface::handleTransmitInterrupt()
|
||||
{
|
||||
// DEBUG_MSG("handling lora TX interrupt\n");
|
||||
// LOG_DEBUG("handling lora TX interrupt\n");
|
||||
// This can be null if we forced the device to enter standby mode. In that case
|
||||
// ignore the transmit interrupt
|
||||
if (sendingPacket)
|
||||
@@ -297,7 +307,7 @@ ErrorCode RadioLibInterface::send(MeshPacket *p)
|
||||
|
||||
// We are done sending that packet, release it
|
||||
packetPool.release(p);
|
||||
// DEBUG_MSG("Done with send\n");
|
||||
// LOG_DEBUG("Done with send\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -307,7 +317,7 @@ ErrorCode RadioLibInterface::send(MeshPacket *p)
|
||||
|
||||
// when this is called, we should be in receive mode - if we are not, just jump out instead of bombing. Possible Race Condition?
|
||||
if (!isReceiving) {
|
||||
DEBUG_MSG("*** WAS_ASSERT *** handleReceiveInterrupt called when not in receive mode\n");
|
||||
LOG_DEBUG("*** WAS_ASSERT *** handleReceiveInterrupt called when not in receive mode\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -320,7 +330,7 @@ ErrorCode RadioLibInterface::send(MeshPacket *p)
|
||||
|
||||
int state = iface->readData(radiobuf, length);
|
||||
if (state != RADIOLIB_ERR_NONE) {
|
||||
DEBUG_MSG("ignoring received packet due to error=%d\n", state);
|
||||
LOG_ERROR("ignoring received packet due to error=%d\n", state);
|
||||
rxBad++;
|
||||
|
||||
airTime->logAirtime(RX_ALL_LOG, xmitMsec);
|
||||
@@ -332,7 +342,7 @@ ErrorCode RadioLibInterface::send(MeshPacket *p)
|
||||
|
||||
// check for short packets
|
||||
if (payloadLen < 0) {
|
||||
DEBUG_MSG("ignoring received packet too short\n");
|
||||
LOG_WARN("ignoring received packet too short\n");
|
||||
rxBad++;
|
||||
airTime->logAirtime(RX_ALL_LOG, xmitMsec);
|
||||
} else {
|
||||
@@ -362,7 +372,6 @@ ErrorCode RadioLibInterface::send(MeshPacket *p)
|
||||
|
||||
printPacket("Lora RX", mp);
|
||||
|
||||
// xmitMsec = getPacketTime(mp);
|
||||
airTime->logAirtime(RX_LOG, xmitMsec);
|
||||
|
||||
deliverToReceiver(mp);
|
||||
@@ -375,7 +384,7 @@ ErrorCode RadioLibInterface::send(MeshPacket *p)
|
||||
{
|
||||
printPacket("Starting low level send", txp);
|
||||
if (disabled || !config.lora.tx_enabled) {
|
||||
DEBUG_MSG("startSend is dropping tx packet because we are disabled\n");
|
||||
LOG_WARN("startSend is dropping tx packet because we are disabled\n");
|
||||
packetPool.release(txp);
|
||||
} else {
|
||||
setStandby(); // Cancel any already in process receives
|
||||
@@ -386,6 +395,7 @@ ErrorCode RadioLibInterface::send(MeshPacket *p)
|
||||
|
||||
int res = iface->startTransmit(radiobuf, numbytes);
|
||||
if (res != RADIOLIB_ERR_NONE) {
|
||||
LOG_ERROR("startTransmit failed, error=%d\n", res);
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_RADIO_SPI_BUG);
|
||||
|
||||
// This send failed, but make sure to 'complete' it properly
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "../concurrency/OSThread.h"
|
||||
#include "concurrency/NotifiedWorkerThread.h"
|
||||
#include "RadioInterface.h"
|
||||
#include "MeshPacketQueue.h"
|
||||
|
||||
#define RADIOLIB_EXCLUDE_HTTP
|
||||
#include <RadioLib.h>
|
||||
|
||||
// ESP32 has special rules about ISR code
|
||||
@@ -154,6 +153,8 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified
|
||||
*/
|
||||
virtual void startSend(MeshPacket *txp);
|
||||
|
||||
QueueStatus getQueueStatus();
|
||||
|
||||
protected:
|
||||
|
||||
/** Do any hardware setup needed on entry into send configuration for the radio. Subclasses can customize */
|
||||
|
||||
@@ -22,8 +22,8 @@ int16_t RadioLibRF95::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_
|
||||
// current limit was removed from module' ctor
|
||||
// override default value (60 mA)
|
||||
state = setCurrentLimit(currentLimit);
|
||||
DEBUG_MSG("Current limit set to %f\n", currentLimit);
|
||||
DEBUG_MSG("Current limit set result %d\n", state);
|
||||
LOG_DEBUG("Current limit set to %f\n", currentLimit);
|
||||
LOG_DEBUG("Current limit set result %d\n", state);
|
||||
|
||||
// configure settings not accessible by API
|
||||
state = config();
|
||||
|
||||
@@ -66,10 +66,5 @@ class RadioLibRF95: public SX1278 {
|
||||
// since default current limit for SX126x/127x in updated RadioLib is 60mA
|
||||
// use the previous value
|
||||
float currentLimit = 100;
|
||||
|
||||
#ifndef RADIOLIB_GODMODE
|
||||
private:
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ ErrorCode ReliableRouter::send(MeshPacket *p)
|
||||
return FloodingRouter::send(p);
|
||||
}
|
||||
|
||||
bool ReliableRouter::shouldFilterReceived(MeshPacket *p)
|
||||
bool ReliableRouter::shouldFilterReceived(const MeshPacket *p)
|
||||
{
|
||||
// Note: do not use getFrom() here, because we want to ignore messages sent from phone
|
||||
if (p->from == getNodeNum()) {
|
||||
@@ -37,35 +37,29 @@ bool ReliableRouter::shouldFilterReceived(MeshPacket *p)
|
||||
// If this is the first time we saw this, cancel any retransmissions we have queued up and generate an internal ack for
|
||||
// the original sending process.
|
||||
|
||||
// FIXME - we might want to turn off this "optimization", it does save lots of airtime but it assumes that once we've
|
||||
// heard one one adjacent node hear our packet that a) probably other adjacent nodes heard it and b) we can trust those
|
||||
// nodes to reach our destination. Both of which might be incorrect.
|
||||
// This "optimization", does save lots of airtime. For DMs, you also get a real ACK back
|
||||
// from the intended recipient.
|
||||
auto key = GlobalPacketId(getFrom(p), p->id);
|
||||
auto old = findPendingPacket(key);
|
||||
if (old) {
|
||||
DEBUG_MSG("generating implicit ack\n");
|
||||
LOG_DEBUG("generating implicit ack\n");
|
||||
// NOTE: we do NOT check p->wantAck here because p is the INCOMING rebroadcast and that packet is not expected to be
|
||||
// marked as wantAck
|
||||
sendAckNak(Routing_Error_NONE, getFrom(p), p->id, old->packet->channel);
|
||||
|
||||
stopRetransmission(key);
|
||||
} else {
|
||||
DEBUG_MSG("didn't find pending packet\n");
|
||||
LOG_DEBUG("didn't find pending packet\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* send acks for repeated packets that want acks and are destined for us
|
||||
* this way if an ACK is dropped and a packet is resent we'll ACK the resent packet
|
||||
* make sure wasSeenRecently _doesn't_ update
|
||||
* finding the channel requires decoding the packet. */
|
||||
if (p->want_ack && (p->to == getNodeNum()) && wasSeenRecently(p, false) && !MeshModule::currentReply) {
|
||||
if (perhapsDecode(p)) {
|
||||
sendAckNak(Routing_Error_NONE, getFrom(p), p->id, p->channel);
|
||||
DEBUG_MSG("acking a repeated want_ack packet\n");
|
||||
}
|
||||
} else if (wasSeenRecently(p, false) && p->hop_limit == HOP_RELIABLE && !MeshModule::currentReply && p->to != nodeDB.getNodeNum()) {
|
||||
/* Resend implicit ACKs for repeated packets (assuming the original packet was sent with HOP_RELIABLE)
|
||||
* this way if an implicit ACK is dropped and a packet is resent we'll rebroadcast again.
|
||||
* Resending real ACKs is omitted, as you might receive a packet multiple times due to flooding and
|
||||
* flooding this ACK back to the original sender already adds redundancy. */
|
||||
if (wasSeenRecently(p, false) && p->hop_limit == HOP_RELIABLE && !MeshModule::currentReply && p->to != nodeDB.getNodeNum()) {
|
||||
// retransmission on broadcast has hop_limit still equal to HOP_RELIABLE
|
||||
DEBUG_MSG("Resending implicit ack for a repeated floodmsg\n");
|
||||
LOG_DEBUG("Resending implicit ack for a repeated floodmsg\n");
|
||||
MeshPacket *tosend = packetPool.allocCopy(*p);
|
||||
tosend->hop_limit--; // bump down the hop count
|
||||
Router::send(tosend);
|
||||
@@ -90,11 +84,10 @@ void ReliableRouter::sniffReceived(const MeshPacket *p, const Routing *c)
|
||||
{
|
||||
NodeNum ourNode = getNodeNum();
|
||||
|
||||
if (p->to == ourNode) { // ignore ack/nak/want_ack packets that are not address to us (we only handle 0 hop reliability
|
||||
// - not DSR routing)
|
||||
if (p->to == ourNode) { // ignore ack/nak/want_ack packets that are not address to us (we only handle 0 hop reliability)
|
||||
if (p->want_ack) {
|
||||
if (MeshModule::currentReply)
|
||||
DEBUG_MSG("Some other module has replied to this message, no need for a 2nd ack\n");
|
||||
LOG_DEBUG("Some other module has replied to this message, no need for a 2nd ack\n");
|
||||
else
|
||||
if (p->which_payload_variant == MeshPacket_decoded_tag)
|
||||
sendAckNak(Routing_Error_NONE, getFrom(p), p->id, p->channel);
|
||||
@@ -112,10 +105,10 @@ void ReliableRouter::sniffReceived(const MeshPacket *p, const Routing *c)
|
||||
// We intentionally don't check wasSeenRecently, because it is harmless to delete non existent retransmission records
|
||||
if (ackId || nakId) {
|
||||
if (ackId) {
|
||||
DEBUG_MSG("Received an ack for 0x%x, stopping retransmissions\n", ackId);
|
||||
LOG_DEBUG("Received an ack for 0x%x, stopping retransmissions\n", ackId);
|
||||
stopRetransmission(p->to, ackId);
|
||||
} else {
|
||||
DEBUG_MSG("Received a nak for 0x%x, stopping retransmissions\n", nakId);
|
||||
LOG_DEBUG("Received a nak for 0x%x, stopping retransmissions\n", nakId);
|
||||
stopRetransmission(p->to, nakId);
|
||||
}
|
||||
}
|
||||
@@ -197,15 +190,14 @@ int32_t ReliableRouter::doRetransmissions()
|
||||
// FIXME, handle 51 day rolloever here!!!
|
||||
if (p.nextTxMsec <= now) {
|
||||
if (p.numRetransmissions == 0) {
|
||||
DEBUG_MSG("Reliable send failed, returning a nak for fr=0x%x,to=0x%x,id=0x%x\n", p.packet->from, p.packet->to,
|
||||
LOG_DEBUG("Reliable send failed, returning a nak for fr=0x%x,to=0x%x,id=0x%x\n", p.packet->from, p.packet->to,
|
||||
p.packet->id);
|
||||
sendAckNak(Routing_Error_MAX_RETRANSMIT, getFrom(p.packet), p.packet->id, p.packet->channel);
|
||||
// Note: we don't stop retransmission here, instead the Nak packet gets processed in sniffReceived - which
|
||||
// allows the DSR version to still be able to look at the PendingPacket
|
||||
// Note: we don't stop retransmission here, instead the Nak packet gets processed in sniffReceived
|
||||
stopRetransmission(it->first);
|
||||
stillValid = false; // just deleted it
|
||||
} else {
|
||||
DEBUG_MSG("Sending reliable retransmission fr=0x%x,to=0x%x,id=0x%x, tries left=%d\n", p.packet->from,
|
||||
LOG_DEBUG("Sending reliable retransmission fr=0x%x,to=0x%x,id=0x%x, tries left=%d\n", p.packet->from,
|
||||
p.packet->to, p.packet->id, p.numRetransmissions);
|
||||
|
||||
// Note: we call the superclass version because we don't want to have our version of send() add a new
|
||||
@@ -234,7 +226,7 @@ void ReliableRouter::setNextTx(PendingPacket *pending)
|
||||
assert(iface);
|
||||
auto d = iface->getRetransmissionMsec(pending->packet);
|
||||
pending->nextTxMsec = millis() + d;
|
||||
DEBUG_MSG("Setting next retransmission in %u msecs: ", d);
|
||||
LOG_DEBUG("Setting next retransmission in %u msecs: ", d);
|
||||
printPacket("", pending->packet);
|
||||
setReceivedMessage(); // Run ASAP, so we can figure out our correct sleep time
|
||||
}
|
||||
|
||||
@@ -38,12 +38,6 @@ struct PendingPacket {
|
||||
/** Starts at NUM_RETRANSMISSIONS -1(normally 3) and counts down. Once zero it will be removed from the list */
|
||||
uint8_t numRetransmissions = 0;
|
||||
|
||||
/** True if we have started trying to find a route - for DSR usage
|
||||
* While trying to find a route we don't actually send the data packet. We just leave it here pending until
|
||||
* we have a route or we've failed to find one.
|
||||
*/
|
||||
bool wantRoute = false;
|
||||
|
||||
PendingPacket() {}
|
||||
explicit PendingPacket(MeshPacket *p);
|
||||
};
|
||||
@@ -102,7 +96,7 @@ class ReliableRouter : public FloodingRouter
|
||||
/**
|
||||
* We hook this method so we can see packets before FloodingRouter says they should be discarded
|
||||
*/
|
||||
virtual bool shouldFilterReceived(MeshPacket *p) override;
|
||||
virtual bool shouldFilterReceived(const MeshPacket *p) override;
|
||||
|
||||
/**
|
||||
* Add p to the list of packets to retransmit occasionally. We will free it once we stop retransmitting.
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "Channels.h"
|
||||
#include "CryptoEngine.h"
|
||||
#include "NodeDB.h"
|
||||
#include "MeshRadio.h"
|
||||
#include "RTC.h"
|
||||
#include "configuration.h"
|
||||
#include "main.h"
|
||||
@@ -21,7 +22,6 @@ extern "C" {
|
||||
* DONE: Implement basic interface and use it elsewhere in app
|
||||
* Add naive flooding mixin (& drop duplicate rx broadcasts), add tools for sending broadcasts with incrementing sequence #s
|
||||
* Add an optional adjacent node only 'send with ack' mixin. If we timeout waiting for the ack, call handleAckTimeout(packet)
|
||||
* Add DSR mixin
|
||||
*
|
||||
**/
|
||||
|
||||
@@ -39,6 +39,8 @@ static MemoryDynamic<MeshPacket> staticPool;
|
||||
|
||||
Allocator<MeshPacket> &packetPool = staticPool;
|
||||
|
||||
static uint8_t bytes[MAX_RHPACKETLEN];
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
@@ -48,9 +50,9 @@ Router::Router() : concurrency::OSThread("Router"), fromRadioQueue(MAX_RX_FROMRA
|
||||
{
|
||||
// This is called pre main(), don't touch anything here, the following code is not safe
|
||||
|
||||
/* DEBUG_MSG("Size of NodeInfo %d\n", sizeof(NodeInfo));
|
||||
DEBUG_MSG("Size of SubPacket %d\n", sizeof(SubPacket));
|
||||
DEBUG_MSG("Size of MeshPacket %d\n", sizeof(MeshPacket)); */
|
||||
/* LOG_DEBUG("Size of NodeInfo %d\n", sizeof(NodeInfo));
|
||||
LOG_DEBUG("Size of SubPacket %d\n", sizeof(SubPacket));
|
||||
LOG_DEBUG("Size of MeshPacket %d\n", sizeof(MeshPacket)); */
|
||||
|
||||
fromRadioQueue.setReader(this);
|
||||
}
|
||||
@@ -67,7 +69,7 @@ int32_t Router::runOnce()
|
||||
perhapsHandleReceived(mp);
|
||||
}
|
||||
|
||||
// DEBUG_MSG("sleeping forever!\n");
|
||||
// LOG_DEBUG("sleeping forever!\n");
|
||||
return INT32_MAX; // Wait a long time - until we get woken for the message queue
|
||||
}
|
||||
|
||||
@@ -94,8 +96,7 @@ PacketId generatePacketId()
|
||||
static uint32_t i; // Note: trying to keep this in noinit didn't help for working across reboots
|
||||
static bool didInit = false;
|
||||
|
||||
assert(sizeof(PacketId) == 4 || sizeof(PacketId) == 1); // only supported values
|
||||
uint32_t numPacketId = sizeof(PacketId) == 1 ? UINT8_MAX : UINT32_MAX; // 0 is consider invalid
|
||||
uint32_t numPacketId = UINT32_MAX;
|
||||
|
||||
if (!didInit) {
|
||||
didInit = true;
|
||||
@@ -103,7 +104,7 @@ PacketId generatePacketId()
|
||||
// pick a random initial sequence number at boot (to prevent repeated reboots always starting at 0)
|
||||
// Note: we mask the high order bit to ensure that we never pass a 'negative' number to random
|
||||
i = random(numPacketId & 0x7fffffff);
|
||||
DEBUG_MSG("Initial packet id %u, numPacketId %u\n", i, numPacketId);
|
||||
LOG_DEBUG("Initial packet id %u, numPacketId %u\n", i, numPacketId);
|
||||
}
|
||||
|
||||
i++;
|
||||
@@ -136,18 +137,23 @@ void Router::sendAckNak(Routing_Error err, NodeNum to, PacketId idFrom, ChannelI
|
||||
|
||||
void Router::abortSendAndNak(Routing_Error err, MeshPacket *p)
|
||||
{
|
||||
DEBUG_MSG("Error=%d, returning NAK and dropping packet.\n", err);
|
||||
sendAckNak(Routing_Error_NO_INTERFACE, getFrom(p), p->id, p->channel);
|
||||
LOG_ERROR("Error=%d, returning NAK and dropping packet.\n", err);
|
||||
sendAckNak(err, getFrom(p), p->id, p->channel);
|
||||
packetPool.release(p);
|
||||
}
|
||||
|
||||
void Router::setReceivedMessage()
|
||||
{
|
||||
// DEBUG_MSG("set interval to ASAP\n");
|
||||
// LOG_DEBUG("set interval to ASAP\n");
|
||||
setInterval(0); // Run ASAP, so we can figure out our correct sleep time
|
||||
runASAP = true;
|
||||
}
|
||||
|
||||
QueueStatus Router::getQueueStatus()
|
||||
{
|
||||
return iface->getQueueStatus();
|
||||
}
|
||||
|
||||
ErrorCode Router::sendLocal(MeshPacket *p, RxSource src)
|
||||
{
|
||||
// No need to deliver externally if the destination is the local node
|
||||
@@ -173,10 +179,10 @@ ErrorCode Router::sendLocal(MeshPacket *p, RxSource src)
|
||||
|
||||
void printBytes(const char *label, const uint8_t *p, size_t numbytes)
|
||||
{
|
||||
DEBUG_MSG("%s: ", label);
|
||||
LOG_DEBUG("%s: ", label);
|
||||
for (size_t i = 0; i < numbytes; i++)
|
||||
DEBUG_MSG("%02x ", p[i]);
|
||||
DEBUG_MSG("\n");
|
||||
LOG_DEBUG("%02x ", p[i]);
|
||||
LOG_DEBUG("\n");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -186,7 +192,27 @@ void printBytes(const char *label, const uint8_t *p, size_t numbytes)
|
||||
*/
|
||||
ErrorCode Router::send(MeshPacket *p)
|
||||
{
|
||||
assert(p->to != nodeDB.getNodeNum()); // should have already been handled by sendLocal
|
||||
if (p->to == nodeDB.getNodeNum()) {
|
||||
LOG_ERROR("BUG! send() called with packet destined for local node!\n");
|
||||
packetPool.release(p);
|
||||
return Routing_Error_BAD_REQUEST;
|
||||
} // should have already been handled by sendLocal
|
||||
|
||||
// Abort sending if we are violating the duty cycle
|
||||
if (!config.lora.override_duty_cycle && myRegion->dutyCycle < 100) {
|
||||
float hourlyTxPercent = airTime->utilizationTXPercent();
|
||||
if (hourlyTxPercent > myRegion->dutyCycle) {
|
||||
uint8_t silentMinutes = airTime->getSilentMinutes(hourlyTxPercent, myRegion->dutyCycle);
|
||||
LOG_WARN("Duty cycle limit exceeded. Aborting send for now, you can send again in %d minutes.\n", silentMinutes);
|
||||
Routing_Error err = Routing_Error_DUTY_CYCLE_LIMIT;
|
||||
if (getFrom(p) == nodeDB.getNodeNum()) { // only send NAK to API, not to the mesh
|
||||
abortSendAndNak(err, p);
|
||||
} else {
|
||||
packetPool.release(p);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
// PacketId nakId = p->decoded.which_ackVariant == SubPacket_fail_id_tag ? p->decoded.ackVariant.fail_id : 0;
|
||||
// assert(!nakId); // I don't think we ever send 0hop naks over the wire (other than to the phone), test that assumption with
|
||||
@@ -209,7 +235,10 @@ ErrorCode Router::send(MeshPacket *p)
|
||||
if (p->which_payload_variant == MeshPacket_decoded_tag) {
|
||||
ChannelIndex chIndex = p->channel; // keep as a local because we are about to change it
|
||||
|
||||
bool shouldActuallyEncrypt = true;
|
||||
|
||||
#if HAS_WIFI || HAS_ETHERNET
|
||||
if(moduleConfig.mqtt.enabled) {
|
||||
// check if we should send decrypted packets to mqtt
|
||||
|
||||
// truth table:
|
||||
@@ -222,16 +251,16 @@ ErrorCode Router::send(MeshPacket *p)
|
||||
* => so we only decrypt mqtt if they have a custom mqtt server AND mqtt_encryption_enabled is FALSE
|
||||
*/
|
||||
|
||||
bool shouldActuallyEncrypt = true;
|
||||
if (*moduleConfig.mqtt.address && !moduleConfig.mqtt.encryption_enabled) {
|
||||
shouldActuallyEncrypt = false;
|
||||
}
|
||||
|
||||
DEBUG_MSG("Should encrypt MQTT?: %d\n", shouldActuallyEncrypt);
|
||||
LOG_INFO("Should encrypt MQTT?: %d\n", shouldActuallyEncrypt);
|
||||
|
||||
// the packet is currently in a decrypted state. send it now if they want decrypted packets
|
||||
if (mqtt && !shouldActuallyEncrypt)
|
||||
mqtt->onSend(*p, chIndex);
|
||||
}
|
||||
#endif
|
||||
|
||||
auto encodeResult = perhapsEncode(p);
|
||||
@@ -241,10 +270,12 @@ ErrorCode Router::send(MeshPacket *p)
|
||||
}
|
||||
|
||||
#if HAS_WIFI || HAS_ETHERNET
|
||||
if (moduleConfig.mqtt.enabled) {
|
||||
// the packet is now encrypted.
|
||||
// check if we should send encrypted packets to mqtt
|
||||
if (mqtt && shouldActuallyEncrypt)
|
||||
mqtt->onSend(*p, chIndex);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -264,14 +295,13 @@ bool Router::cancelSending(NodeNum from, PacketId id)
|
||||
*/
|
||||
void Router::sniffReceived(const MeshPacket *p, const Routing *c)
|
||||
{
|
||||
DEBUG_MSG("FIXME-update-db Sniffing packet\n");
|
||||
// FIXME, update nodedb here for any packet that passes through us
|
||||
}
|
||||
|
||||
bool perhapsDecode(MeshPacket *p)
|
||||
{
|
||||
|
||||
// DEBUG_MSG("\n\n** perhapsDecode payloadVariant - %d\n\n", p->which_payloadVariant);
|
||||
// LOG_DEBUG("\n\n** perhapsDecode payloadVariant - %d\n\n", p->which_payloadVariant);
|
||||
|
||||
if (p->which_payload_variant == MeshPacket_decoded_tag)
|
||||
return true; // If packet was already decoded just return
|
||||
@@ -283,7 +313,6 @@ bool perhapsDecode(MeshPacket *p)
|
||||
// Try to use this hash/channel pair
|
||||
if (channels.decryptForHash(chIndex, p->channel)) {
|
||||
// Try to decrypt the packet if we can
|
||||
static uint8_t bytes[MAX_RHPACKETLEN];
|
||||
size_t rawSize = p->encrypted.size;
|
||||
assert(rawSize <= sizeof(bytes));
|
||||
memcpy(bytes, p->encrypted.bytes,
|
||||
@@ -294,23 +323,15 @@ bool perhapsDecode(MeshPacket *p)
|
||||
|
||||
// Take those raw bytes and convert them back into a well structured protobuf we can understand
|
||||
memset(&p->decoded, 0, sizeof(p->decoded));
|
||||
if (!pb_decode_from_bytes(bytes, rawSize, Data_fields, &p->decoded)) {
|
||||
DEBUG_MSG("Invalid protobufs in received mesh packet (bad psk?)!\n");
|
||||
if (!pb_decode_from_bytes(bytes, rawSize, &Data_msg, &p->decoded)) {
|
||||
LOG_ERROR("Invalid protobufs in received mesh packet (bad psk?)!\n");
|
||||
} else if (p->decoded.portnum == PortNum_UNKNOWN_APP) {
|
||||
DEBUG_MSG("Invalid portnum (bad psk?)!\n");
|
||||
LOG_ERROR("Invalid portnum (bad psk?)!\n");
|
||||
} else {
|
||||
// parsing was successful
|
||||
p->which_payload_variant = MeshPacket_decoded_tag; // change type to decoded
|
||||
p->channel = chIndex; // change to store the index instead of the hash
|
||||
|
||||
/*
|
||||
if (p->decoded.portnum == PortNum_TEXT_MESSAGE_APP) {
|
||||
DEBUG_MSG("\n\n** TEXT_MESSAGE_APP\n");
|
||||
} else if (p->decoded.portnum == PortNum_TEXT_MESSAGE_COMPRESSED_APP) {
|
||||
DEBUG_MSG("\n\n** PortNum_TEXT_MESSAGE_COMPRESSED_APP\n");
|
||||
}
|
||||
*/
|
||||
|
||||
// Decompress if needed. jm
|
||||
if (p->decoded.portnum == PortNum_TEXT_MESSAGE_COMPRESSED_APP) {
|
||||
// Decompress the payload
|
||||
@@ -322,7 +343,7 @@ bool perhapsDecode(MeshPacket *p)
|
||||
|
||||
decompressed_len = unishox2_decompress_simple(compressed_in, p->decoded.payload.size, decompressed_out);
|
||||
|
||||
// DEBUG_MSG("\n\n**\n\nDecompressed length - %d \n", decompressed_len);
|
||||
// LOG_DEBUG("\n\n**\n\nDecompressed length - %d \n", decompressed_len);
|
||||
|
||||
memcpy(p->decoded.payload.bytes, decompressed_out, decompressed_len);
|
||||
|
||||
@@ -336,7 +357,7 @@ bool perhapsDecode(MeshPacket *p)
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_MSG("No suitable channel found for decoding, hash was 0x%x!\n", p->channel);
|
||||
LOG_WARN("No suitable channel found for decoding, hash was 0x%x!\n", p->channel);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -346,9 +367,8 @@ Routing_Error perhapsEncode(MeshPacket *p)
|
||||
{
|
||||
// If the packet is not yet encrypted, do so now
|
||||
if (p->which_payload_variant == MeshPacket_decoded_tag) {
|
||||
static uint8_t bytes[MAX_RHPACKETLEN]; // we have to use a scratch buffer because a union
|
||||
|
||||
size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), Data_fields, &p->decoded);
|
||||
size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), &Data_msg, &p->decoded);
|
||||
|
||||
// Only allow encryption on the text message app.
|
||||
// TODO: Allow modules to opt into compression.
|
||||
@@ -362,20 +382,20 @@ Routing_Error perhapsEncode(MeshPacket *p)
|
||||
int compressed_len;
|
||||
compressed_len = unishox2_compress_simple(original_payload, p->decoded.payload.size, compressed_out);
|
||||
|
||||
DEBUG_MSG("Original length - %d \n", p->decoded.payload.size);
|
||||
DEBUG_MSG("Compressed length - %d \n", compressed_len);
|
||||
DEBUG_MSG("Original message - %s \n", p->decoded.payload.bytes);
|
||||
LOG_DEBUG("Original length - %d \n", p->decoded.payload.size);
|
||||
LOG_DEBUG("Compressed length - %d \n", compressed_len);
|
||||
LOG_DEBUG("Original message - %s \n", p->decoded.payload.bytes);
|
||||
|
||||
// If the compressed length is greater than or equal to the original size, don't use the compressed form
|
||||
if (compressed_len >= p->decoded.payload.size) {
|
||||
|
||||
DEBUG_MSG("Not using compressing message.\n");
|
||||
LOG_DEBUG("Not using compressing message.\n");
|
||||
// Set the uncompressed payload varient anyway. Shouldn't hurt?
|
||||
// p->decoded.which_payloadVariant = Data_payload_tag;
|
||||
|
||||
// Otherwise we use the compressor
|
||||
} else {
|
||||
DEBUG_MSG("Using compressed message.\n");
|
||||
LOG_DEBUG("Using compressed message.\n");
|
||||
// Copy the compressed data into the meshpacket
|
||||
|
||||
p->decoded.payload.size = compressed_len;
|
||||
@@ -447,9 +467,9 @@ void Router::perhapsHandleReceived(MeshPacket *p)
|
||||
bool ignore = is_in_repeated(config.lora.ignore_incoming, p->from);
|
||||
|
||||
if (ignore)
|
||||
DEBUG_MSG("Ignoring incoming message, 0x%x is in our ignore list\n", p->from);
|
||||
LOG_DEBUG("Ignoring incoming message, 0x%x is in our ignore list\n", p->from);
|
||||
else if (ignore |= shouldFilterReceived(p)) {
|
||||
DEBUG_MSG("Incoming message was filtered 0x%x\n", p->from);
|
||||
LOG_DEBUG("Incoming message was filtered 0x%x\n", p->from);
|
||||
}
|
||||
|
||||
// Note: we avoid calling shouldFilterReceived if we are supposed to ignore certain nodes - because some overrides might
|
||||
|
||||
@@ -55,6 +55,9 @@ class Router : protected concurrency::OSThread
|
||||
*/
|
||||
MeshPacket *allocForSending();
|
||||
|
||||
/** Return Underlying interface's TX queue status */
|
||||
QueueStatus getQueueStatus();
|
||||
|
||||
/**
|
||||
* @return our local nodenum */
|
||||
NodeNum getNodeNum();
|
||||
@@ -90,7 +93,7 @@ class Router : protected concurrency::OSThread
|
||||
* Called immedately on receiption, before any further processing.
|
||||
* @return true to abandon the packet
|
||||
*/
|
||||
virtual bool shouldFilterReceived(MeshPacket *p) { return false; }
|
||||
virtual bool shouldFilterReceived(const MeshPacket *p) { return false; }
|
||||
|
||||
/**
|
||||
* Every (non duplicate) packet this node receives will be passed through this method. This allows subclasses to
|
||||
|
||||
@@ -12,7 +12,7 @@ SX126xInterface<T>::SX126xInterface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq,
|
||||
SPIClass &spi)
|
||||
: RadioLibInterface(cs, irq, rst, busy, spi, &lora), lora(&module)
|
||||
{
|
||||
DEBUG_MSG("SX126xInterface(cs=%d, irq=%d, rst=%d, busy=%d)\n", cs, irq, rst, busy);
|
||||
LOG_WARN("SX126xInterface(cs=%d, irq=%d, rst=%d, busy=%d)\n", cs, irq, rst, busy);
|
||||
}
|
||||
|
||||
/// Initialise the Driver transport hardware and software.
|
||||
@@ -55,22 +55,22 @@ bool SX126xInterface<T>::init()
|
||||
|
||||
int res = lora.begin(getFreq(), bw, sf, cr, syncWord, power, preambleLength, tcxoVoltage, useRegulatorLDO);
|
||||
// \todo Display actual typename of the adapter, not just `SX126x`
|
||||
DEBUG_MSG("SX126x init result %d\n", res);
|
||||
LOG_INFO("SX126x init result %d\n", res);
|
||||
|
||||
DEBUG_MSG("Frequency set to %f\n", getFreq());
|
||||
DEBUG_MSG("Bandwidth set to %f\n", bw);
|
||||
DEBUG_MSG("Power output set to %d\n", power);
|
||||
LOG_INFO("Frequency set to %f\n", getFreq());
|
||||
LOG_INFO("Bandwidth set to %f\n", bw);
|
||||
LOG_INFO("Power output set to %d\n", power);
|
||||
|
||||
// current limit was removed from module' ctor
|
||||
// override default value (60 mA)
|
||||
res = lora.setCurrentLimit(currentLimit);
|
||||
DEBUG_MSG("Current limit set to %f\n", currentLimit);
|
||||
DEBUG_MSG("Current limit set result %d\n", res);
|
||||
LOG_DEBUG("Current limit set to %f\n", currentLimit);
|
||||
LOG_DEBUG("Current limit set result %d\n", res);
|
||||
|
||||
#if defined(SX126X_TXEN) && (SX126X_TXEN != RADIOLIB_NC)
|
||||
// lora.begin sets Dio2 as RF switch control, which is not true if we are manually controlling RX and TX
|
||||
if (res == RADIOLIB_ERR_NONE)
|
||||
res = lora.setDio2AsRfSwitch(false);
|
||||
res = lora.setDio2AsRfSwitch(true);
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
@@ -170,7 +170,7 @@ void SX126xInterface<T>::setStandby()
|
||||
int err = lora.standby();
|
||||
|
||||
if (err != RADIOLIB_ERR_NONE)
|
||||
DEBUG_MSG("SX126x standby failed with error %d\n", err);
|
||||
LOG_DEBUG("SX126x standby failed with error %d\n", err);
|
||||
|
||||
assert(err == RADIOLIB_ERR_NONE);
|
||||
|
||||
@@ -192,7 +192,7 @@ void SX126xInterface<T>::setStandby()
|
||||
template<typename T>
|
||||
void SX126xInterface<T>::addReceiveMetadata(MeshPacket *mp)
|
||||
{
|
||||
// DEBUG_MSG("PacketStatus %x\n", lora.getPacketStatus());
|
||||
// LOG_DEBUG("PacketStatus %x\n", lora.getPacketStatus());
|
||||
mp->rx_snr = lora.getSNR();
|
||||
mp->rx_rssi = lround(lora.getRSSI());
|
||||
}
|
||||
@@ -275,7 +275,7 @@ bool SX126xInterface<T>::isActivelyReceiving()
|
||||
// this is not correct - often always true - need to add an extra conditional
|
||||
// size_t bytesPending = lora.getPacketLength();
|
||||
|
||||
// if (hasPreamble) DEBUG_MSG("rx hasPreamble\n");
|
||||
// if (hasPreamble) LOG_DEBUG("rx hasPreamble\n");
|
||||
return hasPreamble;
|
||||
}
|
||||
|
||||
@@ -284,7 +284,7 @@ bool SX126xInterface<T>::sleep()
|
||||
{
|
||||
// Not keeping config is busted - next time nrf52 board boots lora sending fails tcxo related? - see datasheet
|
||||
// \todo Display actual typename of the adapter, not just `SX126x`
|
||||
DEBUG_MSG("sx126x entering sleep mode (FIXME, don't keep config)\n");
|
||||
LOG_DEBUG("sx126x entering sleep mode (FIXME, don't keep config)\n");
|
||||
setStandby(); // Stop any pending operations
|
||||
|
||||
// turn off TCXO if it was powered
|
||||
|
||||
@@ -2,12 +2,8 @@
|
||||
#include "SX1280Interface.h"
|
||||
#include "error.h"
|
||||
|
||||
#if defined(RADIOLIB_GODMODE)
|
||||
|
||||
SX1280Interface::SX1280Interface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy,
|
||||
SPIClass &spi)
|
||||
: SX128xInterface(cs, irq, rst, busy, spi)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -6,12 +6,9 @@
|
||||
* Our adapter for SX1280 radios
|
||||
*/
|
||||
|
||||
#if defined(RADIOLIB_GODMODE)
|
||||
|
||||
class SX1280Interface : public SX128xInterface<SX1280>
|
||||
{
|
||||
public:
|
||||
SX1280Interface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy, SPIClass &spi);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,9 +1,8 @@
|
||||
#include "configuration.h"
|
||||
#include "SX128xInterface.h"
|
||||
#include "mesh/NodeDB.h"
|
||||
#include "error.h"
|
||||
|
||||
#if defined(RADIOLIB_GODMODE)
|
||||
|
||||
// Particular boards might define a different max power based on what their hardware can do
|
||||
#ifndef SX128X_MAX_POWER
|
||||
#define SX128X_MAX_POWER 13
|
||||
@@ -27,11 +26,16 @@ bool SX128xInterface<T>::init()
|
||||
pinMode(SX128X_POWER_EN, OUTPUT);
|
||||
#endif
|
||||
|
||||
#ifdef SX128X_RXEN // set not rx or tx mode
|
||||
#ifdef RF95_FAN_EN
|
||||
pinMode(RF95_FAN_EN, OUTPUT);
|
||||
digitalWrite(RF95_FAN_EN, 1);
|
||||
#endif
|
||||
|
||||
#if defined(SX128X_RXEN) && (SX128X_RXEN != RADIOLIB_NC) // set not rx or tx mode
|
||||
digitalWrite(SX128X_RXEN, LOW); // Set low before becoming an output
|
||||
pinMode(SX128X_RXEN, OUTPUT);
|
||||
#endif
|
||||
#ifdef SX128X_TXEN
|
||||
#if defined(SX128X_TXEN) && (SX128X_TXEN != RADIOLIB_NC)
|
||||
digitalWrite(SX128X_TXEN, LOW);
|
||||
pinMode(SX128X_TXEN, OUTPUT);
|
||||
#endif
|
||||
@@ -46,19 +50,29 @@ bool SX128xInterface<T>::init()
|
||||
|
||||
limitPower();
|
||||
|
||||
preambleLength = 12; // 12 is the default for this chip, 32 does not RX at all
|
||||
|
||||
int res = lora.begin(getFreq(), bw, sf, cr, syncWord, power, preambleLength);
|
||||
// \todo Display actual typename of the adapter, not just `SX128x`
|
||||
DEBUG_MSG("SX128x init result %d\n", res);
|
||||
LOG_INFO("SX128x init result %d\n", res);
|
||||
|
||||
DEBUG_MSG("Frequency set to %f\n", getFreq());
|
||||
DEBUG_MSG("Bandwidth set to %f\n", bw);
|
||||
DEBUG_MSG("Power output set to %d\n", power);
|
||||
|
||||
#ifdef SX128X_TXEN
|
||||
// lora.begin sets Dio2 as RF switch control, which is not true if we are manually controlling RX and TX
|
||||
if (res == RADIOLIB_ERR_NONE)
|
||||
res = lora.setDio2AsRfSwitch(true);
|
||||
if((config.lora.region != Config_LoRaConfig_RegionCode_LORA_24) && (res == RADIOLIB_ERR_INVALID_FREQUENCY)) {
|
||||
LOG_WARN("Radio chip only supports 2.4GHz LoRa. Adjusting Region and rebooting.\n");
|
||||
config.lora.region = Config_LoRaConfig_RegionCode_LORA_24;
|
||||
nodeDB.saveToDisk(SEGMENT_CONFIG);
|
||||
delay(2000);
|
||||
#if defined(ARCH_ESP32)
|
||||
ESP.restart();
|
||||
#elif defined(ARCH_NRF52)
|
||||
NVIC_SystemReset();
|
||||
#else
|
||||
LOG_ERROR("FIXME implement reboot for this platform. Skipping for now.\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
LOG_INFO("Frequency set to %f\n", getFreq());
|
||||
LOG_INFO("Bandwidth set to %f\n", bw);
|
||||
LOG_INFO("Power output set to %d\n", power);
|
||||
|
||||
if (res == RADIOLIB_ERR_NONE)
|
||||
res = lora.setCRC(2);
|
||||
@@ -122,18 +136,28 @@ void INTERRUPT_ATTR SX128xInterface<T>::disableInterrupt()
|
||||
lora.clearDio1Action();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool SX128xInterface<T>::wideLora()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void SX128xInterface<T>::setStandby()
|
||||
{
|
||||
checkNotification(); // handle any pending interrupts before we force standby
|
||||
|
||||
int err = lora.standby();
|
||||
|
||||
if (err != RADIOLIB_ERR_NONE)
|
||||
LOG_ERROR("SX128x standby failed with error %d\n", err);
|
||||
|
||||
assert(err == RADIOLIB_ERR_NONE);
|
||||
|
||||
#ifdef SX128X_RXEN // we have RXEN/TXEN control - turn off RX and TX power
|
||||
#if defined(SX128X_RXEN) && (SX128X_RXEN != RADIOLIB_NC) // we have RXEN/TXEN control - turn off RX and TX power
|
||||
digitalWrite(SX128X_RXEN, LOW);
|
||||
#endif
|
||||
#ifdef SX128X_TXEN
|
||||
#if defined(SX128X_TXEN) && (SX128X_TXEN != RADIOLIB_NC)
|
||||
digitalWrite(SX128X_TXEN, LOW);
|
||||
#endif
|
||||
|
||||
@@ -148,7 +172,7 @@ void SX128xInterface<T>::setStandby()
|
||||
template<typename T>
|
||||
void SX128xInterface<T>::addReceiveMetadata(MeshPacket *mp)
|
||||
{
|
||||
// DEBUG_MSG("PacketStatus %x\n", lora.getPacketStatus());
|
||||
// LOG_DEBUG("PacketStatus %x\n", lora.getPacketStatus());
|
||||
mp->rx_snr = lora.getSNR();
|
||||
mp->rx_rssi = lround(lora.getRSSI());
|
||||
}
|
||||
@@ -158,10 +182,10 @@ void SX128xInterface<T>::addReceiveMetadata(MeshPacket *mp)
|
||||
template<typename T>
|
||||
void SX128xInterface<T>::configHardwareForSend()
|
||||
{
|
||||
#ifdef SX128X_TXEN // we have RXEN/TXEN control - turn on TX power / off RX power
|
||||
#if defined(SX128X_TXEN) && (SX128X_TXEN != RADIOLIB_NC) // we have RXEN/TXEN control - turn on TX power / off RX power
|
||||
digitalWrite(SX128X_TXEN, HIGH);
|
||||
#endif
|
||||
#ifdef SX128X_RXEN
|
||||
#if defined(SX128X_RXEN) && (SX128X_RXEN != RADIOLIB_NC)
|
||||
digitalWrite(SX128X_RXEN, LOW);
|
||||
#endif
|
||||
|
||||
@@ -180,10 +204,10 @@ void SX128xInterface<T>::startReceive()
|
||||
|
||||
setStandby();
|
||||
|
||||
#ifdef SX128X_RXEN // we have RXEN/TXEN control - turn on RX power / off TX power
|
||||
#if defined(SX128X_RXEN) && (SX128X_RXEN != RADIOLIB_NC) // we have RXEN/TXEN control - turn on RX power / off TX power
|
||||
digitalWrite(SX128X_RXEN, HIGH);
|
||||
#endif
|
||||
#ifdef SX128X_TXEN
|
||||
#if defined(SX128X_TXEN) && (SX128X_TXEN != RADIOLIB_NC)
|
||||
digitalWrite(SX128X_TXEN, LOW);
|
||||
#endif
|
||||
|
||||
@@ -219,8 +243,6 @@ bool SX128xInterface<T>::isChannelActive()
|
||||
template<typename T>
|
||||
bool SX128xInterface<T>::isActivelyReceiving()
|
||||
{
|
||||
// return isChannelActive();
|
||||
|
||||
uint16_t irq = lora.getIrqStatus();
|
||||
bool hasPreamble = (irq & RADIOLIB_SX128X_IRQ_HEADER_VALID);
|
||||
return hasPreamble;
|
||||
@@ -231,7 +253,7 @@ bool SX128xInterface<T>::sleep()
|
||||
{
|
||||
// Not keeping config is busted - next time nrf52 board boots lora sending fails tcxo related? - see datasheet
|
||||
// \todo Display actual typename of the adapter, not just `SX128x`
|
||||
DEBUG_MSG("SX128x entering sleep mode (FIXME, don't keep config)\n");
|
||||
LOG_DEBUG("SX128x entering sleep mode (FIXME, don't keep config)\n");
|
||||
setStandby(); // Stop any pending operations
|
||||
|
||||
// turn off TCXO if it was powered
|
||||
@@ -248,5 +270,3 @@ bool SX128xInterface<T>::sleep()
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,7 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#if defined(RADIOLIB_GODMODE)
|
||||
|
||||
#include "RadioLibInterface.h"
|
||||
|
||||
/**
|
||||
@@ -19,6 +17,8 @@ class SX128xInterface : public RadioLibInterface
|
||||
/// \return true if initialisation succeeded.
|
||||
virtual bool init() override;
|
||||
|
||||
virtual bool wideLora() override;
|
||||
|
||||
/// Apply any radio provisioning changes
|
||||
/// Make sure the Driver is properly configured before calling init().
|
||||
/// \return true if initialisation succeeded.
|
||||
@@ -27,9 +27,9 @@ class SX128xInterface : public RadioLibInterface
|
||||
/// Prepare hardware for sleep. Call this _only_ for deep sleep, not needed for light sleep.
|
||||
virtual bool sleep() override;
|
||||
|
||||
protected:
|
||||
bool isIRQPending() override { return lora.getIrqStatus() != 0; }
|
||||
|
||||
float currentLimit = 140; // Higher OCP limit for SX128x PA
|
||||
protected:
|
||||
|
||||
/**
|
||||
* Specific module instance
|
||||
@@ -71,5 +71,3 @@ class SX128xInterface : public RadioLibInterface
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -18,9 +18,6 @@ class SinglePortModule : public MeshModule
|
||||
SinglePortModule(const char *_name, PortNum _ourPortNum) : MeshModule(_name), ourPortNum(_ourPortNum) {}
|
||||
|
||||
protected:
|
||||
uint32_t max_channel_util_percent = 40;
|
||||
uint32_t polite_channel_util_percent = 25;
|
||||
|
||||
/**
|
||||
* @return true if you want to receive the specified portnum
|
||||
*/
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#define START2 0xc3
|
||||
#define HEADER_LEN 4
|
||||
|
||||
int32_t StreamAPI::runOnce()
|
||||
int32_t StreamAPI::runOncePart()
|
||||
{
|
||||
auto result = readStream();
|
||||
writeStream();
|
||||
@@ -95,7 +95,7 @@ void StreamAPI::writeStream()
|
||||
void StreamAPI::emitTxBuffer(size_t len)
|
||||
{
|
||||
if (len != 0) {
|
||||
// DEBUG_MSG("emit tx %d\n", len);
|
||||
// LOG_DEBUG("emit tx %d\n", len);
|
||||
txBuf[0] = START1;
|
||||
txBuf[1] = START2;
|
||||
txBuf[2] = (len >> 8) & 0xff;
|
||||
@@ -114,8 +114,8 @@ void StreamAPI::emitRebooted()
|
||||
fromRadioScratch.which_payload_variant = FromRadio_rebooted_tag;
|
||||
fromRadioScratch.rebooted = true;
|
||||
|
||||
// DEBUG_MSG("Emitting reboot packet for serial shell\n");
|
||||
emitTxBuffer(pb_encode_to_bytes(txBuf + HEADER_LEN, FromRadio_size, FromRadio_fields, &fromRadioScratch));
|
||||
// LOG_DEBUG("Emitting reboot packet for serial shell\n");
|
||||
emitTxBuffer(pb_encode_to_bytes(txBuf + HEADER_LEN, FromRadio_size, &FromRadio_msg, &fromRadioScratch));
|
||||
}
|
||||
|
||||
/// Hookable to find out when connection changes
|
||||
|
||||
@@ -28,7 +28,7 @@ valid utf8 encoding. This makes it a bit easier to start a device outputting reg
|
||||
after it has received a valid packet from the PC, turn off unencoded debug printing and switch to this packet encoding.
|
||||
|
||||
*/
|
||||
class StreamAPI : public PhoneAPI, protected concurrency::OSThread
|
||||
class StreamAPI : public PhoneAPI
|
||||
{
|
||||
/**
|
||||
* The stream we read/write from
|
||||
@@ -42,13 +42,13 @@ class StreamAPI : public PhoneAPI, protected concurrency::OSThread
|
||||
uint32_t lastRxMsec = 0;
|
||||
|
||||
public:
|
||||
StreamAPI(Stream *_stream) : concurrency::OSThread("StreamAPI"), stream(_stream) {}
|
||||
StreamAPI(Stream *_stream) : stream(_stream) {}
|
||||
|
||||
/**
|
||||
* Currently we require frequent invocation from loop() to check for arrived serial packets and to send new packets to the
|
||||
* phone.
|
||||
*/
|
||||
virtual int32_t runOnce() override;
|
||||
virtual int32_t runOncePart();
|
||||
|
||||
private:
|
||||
/**
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user