mirror of
https://github.com/meshtastic/firmware.git
synced 2025-12-24 03:31:14 +00:00
Compare commits
263 Commits
v1.3.41.80
...
v1.3.44.4f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4fa8d02b08 | ||
|
|
43fb0d80f1 | ||
|
|
b25ace14e5 | ||
|
|
8734751bc4 | ||
|
|
5559a1edb0 | ||
|
|
bf503354f3 | ||
|
|
7b10441a28 | ||
|
|
994e396c00 | ||
|
|
6e22ee9061 | ||
|
|
b5fb0f60b0 | ||
|
|
a7fe69ed6b | ||
|
|
7f05298172 | ||
|
|
92a2505056 | ||
|
|
aae9d2fcf6 | ||
|
|
b59e928589 | ||
|
|
1db08b3b0e | ||
|
|
2cf3c105a1 | ||
|
|
505e4e8176 | ||
|
|
49a9973548 | ||
|
|
18af9d734d | ||
|
|
3e22aafea8 | ||
|
|
434db4347b | ||
|
|
b2c3b405b1 | ||
|
|
4bc8f6a6b9 | ||
|
|
4534d17d79 | ||
|
|
f88dde2f60 | ||
|
|
f8982ddaf8 | ||
|
|
784cd8c6f1 | ||
|
|
c3ab8f12cf | ||
|
|
b5adb7babc | ||
|
|
62c809a596 | ||
|
|
d2fe4426c1 | ||
|
|
984f0ca12c | ||
|
|
9d3eba9ea4 | ||
|
|
323f81eaba | ||
|
|
8d0e25fd82 | ||
|
|
20eaddee58 | ||
|
|
30b1bd85d9 | ||
|
|
09cce094d1 | ||
|
|
33a208e3c4 | ||
|
|
dd4c4fba80 | ||
|
|
a17c40ad09 | ||
|
|
9d73e606ac | ||
|
|
da12360105 | ||
|
|
ee1ae627a3 | ||
|
|
137a8dcfdf | ||
|
|
b2d753ed86 | ||
|
|
6e40102f26 | ||
|
|
511fe23b8a | ||
|
|
e433895873 | ||
|
|
5572195af9 | ||
|
|
cb956cd35b | ||
|
|
b551c7738e | ||
|
|
3d45c4dbd8 | ||
|
|
8681489cb7 | ||
|
|
ed328766b2 | ||
|
|
fb852ee6eb | ||
|
|
a6ee708b90 | ||
|
|
c9398e7b8a | ||
|
|
b591e35442 | ||
|
|
e50e15dc04 | ||
|
|
d4e65d8607 | ||
|
|
63ced7da7c | ||
|
|
03868d05db | ||
|
|
186374525a | ||
|
|
f116585c2a | ||
|
|
f4945729bc | ||
|
|
a3c76232c8 | ||
|
|
5bc41118e2 | ||
|
|
9445a96b3a | ||
|
|
a5761069ca | ||
|
|
2d4bfe183c | ||
|
|
bf4115a80f | ||
|
|
b2e84dfd29 | ||
|
|
004f6fa4d6 | ||
|
|
cefd4cd647 | ||
|
|
fd2ae61e3e | ||
|
|
7cda61ca01 | ||
|
|
98e1d52eaa | ||
|
|
1d09beb8a7 | ||
|
|
d44cce2928 | ||
|
|
51b3d4d06e | ||
|
|
a17ddaa951 | ||
|
|
9bd925226c | ||
|
|
e34ada3ff1 | ||
|
|
1ec1ff0773 | ||
|
|
7f935717db | ||
|
|
5b1d3a0c51 | ||
|
|
484f340023 | ||
|
|
ab0cf025c5 | ||
|
|
b384d9ea88 | ||
|
|
bb2094c4de | ||
|
|
6708121ba6 | ||
|
|
46a9bb3f7d | ||
|
|
62498d0935 | ||
|
|
c70184fbed | ||
|
|
4d2cb45f9f | ||
|
|
e5605cc6fe | ||
|
|
f7331a2e41 | ||
|
|
838271a14f | ||
|
|
b6b23907ed | ||
|
|
b240b9a088 | ||
|
|
b3a484f1e5 | ||
|
|
f3042ddf37 | ||
|
|
54816231e9 | ||
|
|
1c168d7d62 | ||
|
|
063c4904ff | ||
|
|
fefcbb147b | ||
|
|
53d48e8f61 | ||
|
|
ce5bce5cdc | ||
|
|
3597685b23 | ||
|
|
dc097c7230 | ||
|
|
b148781e4b | ||
|
|
5d8826e8ef | ||
|
|
39a51c7fbb | ||
|
|
129edde338 | ||
|
|
93cc278eee | ||
|
|
c34198264a | ||
|
|
054b12325d | ||
|
|
0f7a126828 | ||
|
|
7ff72fb981 | ||
|
|
0fe99595a9 | ||
|
|
b2ff628cec | ||
|
|
86a3bd6db8 | ||
|
|
73a5357d0e | ||
|
|
2faf507c0d | ||
|
|
cf124d97b8 | ||
|
|
482c0766af | ||
|
|
7e5a26fde5 | ||
|
|
e85af2f732 | ||
|
|
4df81008bc | ||
|
|
803dc69ccd | ||
|
|
42308cca5b | ||
|
|
ea991a4eee | ||
|
|
04db2d4410 | ||
|
|
076c1ed2ee | ||
|
|
75aa4ea325 | ||
|
|
e54be07dc0 | ||
|
|
d439d00e25 | ||
|
|
c4bea793af | ||
|
|
b53dcb932e | ||
|
|
371428d6ab | ||
|
|
1970d0c00f | ||
|
|
1dd7aa935f | ||
|
|
6b40f9d95c | ||
|
|
b3717d0396 | ||
|
|
82ba95833b | ||
|
|
28384df702 | ||
|
|
aee06f4738 | ||
|
|
ab282765d4 | ||
|
|
5d464badc8 | ||
|
|
68282682de | ||
|
|
2696b04138 | ||
|
|
31dc37150b | ||
|
|
e66d9d0add | ||
|
|
067bde321b | ||
|
|
84ec364ac2 | ||
|
|
32990856e3 | ||
|
|
a1bd5c9ea0 | ||
|
|
51f0e7879a | ||
|
|
0bdb90d133 | ||
|
|
e98c11ff89 | ||
|
|
8f84d7089c | ||
|
|
b0712c4186 | ||
|
|
8f92383ce4 | ||
|
|
c571fc9e24 | ||
|
|
05126bc6dc | ||
|
|
de56a370c6 | ||
|
|
daf189bf4b | ||
|
|
d95ec7e6b9 | ||
|
|
ac235bcabb | ||
|
|
ab4b3a50ee | ||
|
|
7f0fb2a2b6 | ||
|
|
ade1edfdfc | ||
|
|
4723faa95f | ||
|
|
93f83b0fcb | ||
|
|
8f84f7c0a5 | ||
|
|
48e4101f1c | ||
|
|
e6bb79f4c1 | ||
|
|
0bef3464f5 | ||
|
|
3c038a8c50 | ||
|
|
b8eb751316 | ||
|
|
5332db1eca | ||
|
|
9deda962aa | ||
|
|
c53434539b | ||
|
|
7f179deaf3 | ||
|
|
da29fa139f | ||
|
|
1d8a562fd9 | ||
|
|
0dbf97afab | ||
|
|
e5720fba3e | ||
|
|
498ac00b92 | ||
|
|
226a2dfe04 | ||
|
|
7e9a233296 | ||
|
|
ae311c838e | ||
|
|
de769db3bc | ||
|
|
5fa96c7fd1 | ||
|
|
2ee0c9a67a | ||
|
|
347af0210e | ||
|
|
d8455d687c | ||
|
|
34fef4c4e7 | ||
|
|
18bb373219 | ||
|
|
2f74f9ca15 | ||
|
|
5775c390f3 | ||
|
|
80826b8712 | ||
|
|
664d18cf58 | ||
|
|
bc2cddcb11 | ||
|
|
4949bda606 | ||
|
|
b4f75ad042 | ||
|
|
af4d11e17b | ||
|
|
e8f4a8b739 | ||
|
|
fae6693f8f | ||
|
|
0646ecdec4 | ||
|
|
544c89460f | ||
|
|
15089f5b01 | ||
|
|
8ef510035d | ||
|
|
864b1f754c | ||
|
|
883a2ebac0 | ||
|
|
bbe5b2e42c | ||
|
|
1b316b111f | ||
|
|
d0720620e8 | ||
|
|
cf4947d898 | ||
|
|
b5a8efa16b | ||
|
|
b38ae783b9 | ||
|
|
cbd8346c93 | ||
|
|
c0bfb979fd | ||
|
|
7c5a36ce38 | ||
|
|
fc729b0cbb | ||
|
|
0b81a25fda | ||
|
|
011db443ba | ||
|
|
b73e240f4d | ||
|
|
6de77ee310 | ||
|
|
0a8293a2d6 | ||
|
|
d0ad5dd4cf | ||
|
|
ab342ce904 | ||
|
|
140250ef03 | ||
|
|
ed90275370 | ||
|
|
e8b28faaf1 | ||
|
|
afcc7b6a56 | ||
|
|
e27a507a28 | ||
|
|
207f701f0a | ||
|
|
dd8cb1c7fb | ||
|
|
ccf93b8c23 | ||
|
|
4c6f3ead60 | ||
|
|
2d81d359b8 | ||
|
|
1f96d5d957 | ||
|
|
033f45d4da | ||
|
|
ae2c514ee7 | ||
|
|
e0d3ac01b0 | ||
|
|
7c202b6069 | ||
|
|
bfd1fecc2a | ||
|
|
ade66cd8f4 | ||
|
|
adc50f40b1 | ||
|
|
eac2613743 | ||
|
|
4a0c18c4cd | ||
|
|
e376a3a28e | ||
|
|
a6bdff53c9 | ||
|
|
b5c5483ced | ||
|
|
cc054a13e2 | ||
|
|
c446a0f222 | ||
|
|
3102777a71 | ||
|
|
ed95f382cf | ||
|
|
52e4f93760 | ||
|
|
bf3306fbc8 |
20
.github/workflows/main_matrix.yml
vendored
20
.github/workflows/main_matrix.yml
vendored
@@ -12,7 +12,7 @@ on:
|
||||
branches: [master]
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
- "**.yml"
|
||||
#- "**.yml"
|
||||
|
||||
workflow_dispatch:
|
||||
|
||||
@@ -126,12 +126,12 @@ jobs:
|
||||
- name: Upgrade python tools
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -U platformio adafruit-nrfutil littlefs-python
|
||||
pip install -U platformio adafruit-nrfutil
|
||||
|
||||
- name: Upgrade platformio
|
||||
run: |
|
||||
pio upgrade
|
||||
|
||||
|
||||
- name: Pull web ui
|
||||
uses: dsaltares/fetch-gh-release-asset@master
|
||||
with:
|
||||
@@ -147,7 +147,15 @@ jobs:
|
||||
|
||||
- name: Build ESP32
|
||||
run: bin/build-esp32.sh ${{ matrix.board }}
|
||||
|
||||
|
||||
- name: Pull OTA Firmware
|
||||
uses: dsaltares/fetch-gh-release-asset@master
|
||||
with:
|
||||
repo: "meshtastic/Meshtastic-OTA"
|
||||
file: "firmware.bin"
|
||||
target: "release/bleota.bin"
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Get release version string
|
||||
run: echo "::set-output name=version::$(./bin/buildinfo.py long)"
|
||||
id: version
|
||||
@@ -216,6 +224,7 @@ jobs:
|
||||
path: |
|
||||
release/*.uf2
|
||||
release/*.elf
|
||||
release/*.zip
|
||||
retention-days: 90
|
||||
|
||||
build-rpi2040:
|
||||
@@ -360,7 +369,7 @@ jobs:
|
||||
id: version
|
||||
|
||||
- name: Move files up
|
||||
run: mv -b -t ./ ./*tbeam-1*/littlefs*.bin ./*tbeam-1*/system-info.bin ./**/firmware*.bin ./**/*.uf2 ./**/*.elf ./**/meshtasticd_linux_amd64 ./*native*/*device-*.sh ./*native*/*device-*.bat
|
||||
run: mv -b -t ./ ./*tbeam-1*/littlefs*.bin ./*tbeam-1*/bleota.bin ./**/firmware*.bin ./*t-echo*/Meshtastic_nRF52_factory_erase.uf2 ./**/firmware-*.uf2 ./**/firmware-*-ota.zip ./**/*.elf ./**/meshtasticd_linux_amd64 ./*native*/*device-*.sh ./*native*/*device-*.bat
|
||||
|
||||
- name: Repackage in single firmware zip
|
||||
uses: actions/upload-artifact@v2
|
||||
@@ -369,6 +378,7 @@ jobs:
|
||||
path: |
|
||||
./*.bin
|
||||
./*.uf2
|
||||
./firmware-*-ota.zip
|
||||
./meshtasticd_linux_amd64
|
||||
./device-*.sh
|
||||
./device-*.bat
|
||||
|
||||
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@@ -53,7 +53,8 @@
|
||||
"iostream": "cpp",
|
||||
"esp_nimble_hci.h": "c",
|
||||
"map": "cpp",
|
||||
"random": "cpp"
|
||||
"random": "cpp",
|
||||
"*.tpp": "cpp"
|
||||
},
|
||||
"cSpell.words": [
|
||||
"Blox",
|
||||
|
||||
53
arch/esp32/esp32.ini
Normal file
53
arch/esp32/esp32.ini
Normal file
@@ -0,0 +1,53 @@
|
||||
; Common settings for ESP targes, mixin with extends = esp32_base
|
||||
[esp32_base]
|
||||
extends = arduino_base
|
||||
platform = platformio/espressif32@^5.2.0
|
||||
build_src_filter =
|
||||
${arduino_base.build_src_filter} -<platform/nrf52/> -<platform/stm32wl> -<platform/rp2040>
|
||||
upload_speed = 921600
|
||||
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
|
||||
|
||||
lib_deps =
|
||||
${arduino_base.lib_deps}
|
||||
${networking_base.lib_deps}
|
||||
${environmental_base.lib_deps}
|
||||
https://github.com/meshtastic/esp32_https_server.git#657509856ce97e9dddeffb89a559f544faefd5cd
|
||||
h2zero/NimBLE-Arduino@^1.4.0
|
||||
arduino-libraries/NTPClient@^3.1.0
|
||||
https://github.com/lewisxhe/XPowersLib.git#84b7373faea3118b6c37954d52f98b8a337148d6
|
||||
|
||||
lib_ignore =
|
||||
segger_rtt
|
||||
ESP32 BLE Arduino
|
||||
|
||||
; leave this commented out to avoid breaking Windows
|
||||
;upload_port = /dev/ttyUSB0
|
||||
;monitor_port = /dev/ttyUSB0
|
||||
|
||||
; Please don't delete these lines. JM uses them.
|
||||
;upload_port = /dev/cu.SLAB_USBtoUART
|
||||
;monitor_port = /dev/cu.SLAB_USBtoUART
|
||||
|
||||
; customize the partition table
|
||||
; http://docs.platformio.org/en/latest/platforms/espressif32.html#partition-tables
|
||||
board_build.partitions = partition-table.csv
|
||||
46
arch/esp32/esp32s3.ini
Normal file
46
arch/esp32/esp32s3.ini
Normal file
@@ -0,0 +1,46 @@
|
||||
[esp32s3_base]
|
||||
extends = arduino_base
|
||||
platform = platformio/espressif32@^5.2.0
|
||||
build_src_filter =
|
||||
${arduino_base.build_src_filter} -<platform/nrf52/> -<platform/stm32wl> -<platform/rp2040>
|
||||
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
|
||||
|
||||
lib_deps =
|
||||
${arduino_base.lib_deps}
|
||||
${networking_base.lib_deps}
|
||||
${environmental_base.lib_deps}
|
||||
https://github.com/meshtastic/esp32_https_server.git#657509856ce97e9dddeffb89a559f544faefd5cd
|
||||
h2zero/NimBLE-Arduino@^1.4.0
|
||||
arduino-libraries/NTPClient@^3.1.0
|
||||
https://github.com/lewisxhe/XPowersLib.git#84b7373faea3118b6c37954d52f98b8a337148d6
|
||||
|
||||
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
|
||||
|
||||
18
arch/nrf52/nrf52.ini
Normal file
18
arch/nrf52/nrf52.ini
Normal file
@@ -0,0 +1,18 @@
|
||||
[nrf52_base]
|
||||
; Instead of the standard nordicnrf52 platform, we use our fork which has our added variant files
|
||||
platform = platformio/nordicnrf52@^9.4.0
|
||||
|
||||
extends = arduino_base
|
||||
build_type = debug ; I'm debugging with ICE a lot now
|
||||
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>
|
||||
lib_ignore =
|
||||
BluetoothOTA
|
||||
|
||||
; Note: By default no lora device is created for this build - it uses a simulated interface
|
||||
[env:feather_nrf52832]
|
||||
extends = nrf52_base
|
||||
board = adafruit_feather_nrf52832
|
||||
14
arch/nrf52/nrf52840.ini
Normal file
14
arch/nrf52/nrf52840.ini
Normal file
@@ -0,0 +1,14 @@
|
||||
[nrf52840_base]
|
||||
extends = nrf52_base
|
||||
build_flags = ${nrf52_base.build_flags}
|
||||
lib_deps =
|
||||
${arduino_base.lib_deps}
|
||||
${environmental_base.lib_deps}
|
||||
https://github.com/Kongduino/Adafruit_nRFCrypto.git#e31a8825ea3300b163a0a3c1ddd5de34e10e1371
|
||||
|
||||
; Note: By default no lora device is created for this build - it uses a simulated interface
|
||||
[env:nrf52840dk]
|
||||
extends = nrf52840_base
|
||||
board = nrf52840_dk
|
||||
|
||||
|
||||
19
arch/portduino/portduino.ini
Normal file
19
arch/portduino/portduino.ini
Normal file
@@ -0,0 +1,19 @@
|
||||
; The Portduino based sim environment on top of any host OS, all hardware will be simulated
|
||||
[portduino_base]
|
||||
build_src_filter =
|
||||
${env.build_src_filter}
|
||||
-<platform/esp32/>
|
||||
-<nimble/>
|
||||
-<platform/nrf52/>
|
||||
-<platform/stm32wl/>
|
||||
-<platform/rp2040>
|
||||
-<mesh/http/>
|
||||
-<modules/esp32>
|
||||
-<modules/Telemetry>
|
||||
+<../variants/portduino>
|
||||
lib_deps =
|
||||
${env.lib_deps}
|
||||
${networking_base.lib_deps}
|
||||
rweather/Crypto@^0.4.0
|
||||
https://github.com/meshtastic/RadioLib.git#5582ac30578ff3f53f20630a00b2a8a4b8f92c74
|
||||
build_flags = ${arduino_base.build_flags} -Isrc/platform/portduino
|
||||
19
arch/rp2040/rp2040.ini
Normal file
19
arch/rp2040/rp2040.ini
Normal file
@@ -0,0 +1,19 @@
|
||||
; Common settings for rp2040 Processor based targets
|
||||
[rp2040_base]
|
||||
platform = https://github.com/maxgerhardt/platform-raspberrypi.git#5ce1a228e7cae453f366deb8962252b9b7356bbc
|
||||
extends = arduino_base
|
||||
board_build.core = earlephilhower
|
||||
board_build.filesystem_size = 0.5m
|
||||
build_flags =
|
||||
${arduino_base.build_flags} -Wno-unused-variable
|
||||
-Isrc/platform/rp2040
|
||||
-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>
|
||||
lib_ignore =
|
||||
BluetoothOTA
|
||||
lib_deps =
|
||||
${arduino_base.lib_deps}
|
||||
${environmental_base.lib_deps}
|
||||
https://github.com/kokke/tiny-AES-c.git#f06ac37fc31dfdaca2e0d9bec83f90d5663c319b
|
||||
18
arch/stm32/stm32wl5e.ini
Normal file
18
arch/stm32/stm32wl5e.ini
Normal file
@@ -0,0 +1,18 @@
|
||||
[stm32wl5e_base]
|
||||
platform = platformio/ststm32@^15.4.1
|
||||
board = generic_wl5e
|
||||
framework = arduino
|
||||
build_type = debug
|
||||
build_flags =
|
||||
${arduino_base.build_flags}
|
||||
-Isrc/platform/stm32wl -g
|
||||
-DHAL_SUBGHZ_MODULE_ENABLED
|
||||
# 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> -<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
|
||||
lib_ignore =
|
||||
mathertel/OneButton@^2.0.3
|
||||
BIN
bin/Meshtastic_nRF52_factory_erase.uf2
Normal file
BIN
bin/Meshtastic_nRF52_factory_erase.uf2
Normal file
Binary file not shown.
@@ -29,13 +29,11 @@ SRCELF=.pio/build/$1/firmware.elf
|
||||
cp $SRCELF $OUTDIR/$basename.elf
|
||||
|
||||
echo "Copying ESP32 bin file"
|
||||
SRCBIN=.pio/build/$1/firmware.bin
|
||||
SRCBIN=.pio/build/$1/firmware.factory.bin
|
||||
cp $SRCBIN $OUTDIR/$basename.bin
|
||||
|
||||
echo "Building Filesystem for ESP32 targets"
|
||||
pio run --environment tbeam -t buildfs
|
||||
cp .pio/build/tbeam/spiffs.bin $OUTDIR/littlefs-$VERSION.bin
|
||||
cp images/system-info.bin $OUTDIR/system-info.bin
|
||||
|
||||
cp .pio/build/tbeam/littlefs.bin $OUTDIR/littlefs-$VERSION.bin
|
||||
cp bin/device-install.* $OUTDIR
|
||||
cp bin/device-update.* $OUTDIR
|
||||
|
||||
@@ -26,7 +26,9 @@ basename=firmware-$1-$VERSION
|
||||
|
||||
pio run --environment $1 # -v
|
||||
SRCELF=.pio/build/$1/firmware.elf
|
||||
DFUPKG=.pio/build/$1/firmware.zip
|
||||
cp $SRCELF $OUTDIR/$basename.elf
|
||||
cp $DFUPKG $OUTDIR/$basename-ota.zip
|
||||
|
||||
echo "Generating NRF52 uf2 file"
|
||||
SRCHEX=.pio/build/$1/firmware.hex
|
||||
@@ -34,3 +36,4 @@ bin/uf2conv.py $SRCHEX -c -o $OUTDIR/$basename.uf2 -f 0xADA52840
|
||||
|
||||
cp bin/device-install.* $OUTDIR
|
||||
cp bin/device-update.* $OUTDIR
|
||||
cp bin/*.uf2 $OUTDIR
|
||||
|
||||
23
bin/check-dependencies.sh
Normal file
23
bin/check-dependencies.sh
Normal file
@@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Note: This is a prototype for how we could add static code analysis to the CI.
|
||||
|
||||
set -e
|
||||
|
||||
if [[ $# -gt 0 ]]; then
|
||||
# can override which environment by passing arg
|
||||
BOARDS="$@"
|
||||
else
|
||||
BOARDS="rak4631 rak4631_eink t-echo pca10059_diy_eink pico rak11200 tlora-v2 tlora-v1 tlora_v1_3 tlora-v2-1-1.6 tbeam heltec-v1 heltec-v2.0 heltec-v2.1 tbeam0.7 meshtastic-diy-v1 nano-g1 station-g1 m5stack-core m5stack-coreink tbeam-s3-core"
|
||||
fi
|
||||
|
||||
echo "BOARDS:${BOARDS}"
|
||||
|
||||
CHECK=""
|
||||
for BOARD in $BOARDS; do
|
||||
CHECK="${CHECK} -e ${BOARD}"
|
||||
done
|
||||
|
||||
echo $CHECK
|
||||
|
||||
pio pkg outdated -e $CHECK
|
||||
@@ -29,11 +29,11 @@ IF "__%FILENAME%__" == "____" (
|
||||
IF EXIST %FILENAME% (
|
||||
echo Trying to flash update %FILENAME%, but first erasing and writing system information"
|
||||
%PYTHON% -m esptool --baud 115200 erase_flash
|
||||
%PYTHON% -m esptool --baud 115200 write_flash 0x1000 system-info.bin
|
||||
%PYTHON% -m esptool --baud 115200 write_flash 0x00 %FILENAME%
|
||||
%PYTHON% -m esptool --baud 115200 write_flash 0x260000 bleota.bin
|
||||
for %%f in (littlefs-*.bin) do (
|
||||
%PYTHON% -m esptool --baud 115200 write_flash 0x2B0000 %%f
|
||||
%PYTHON% -m esptool --baud 115200 write_flash 0x300000 %%f
|
||||
)
|
||||
%PYTHON% -m esptool --baud 115200 write_flash 0x10000 %FILENAME%
|
||||
) else (
|
||||
echo "Invalid file: %FILENAME%"
|
||||
goto HELP
|
||||
|
||||
@@ -47,9 +47,10 @@ shift "$((OPTIND-1))"
|
||||
if [ -f "${FILENAME}" ]; then
|
||||
echo "Trying to flash ${FILENAME}, but first erasing and writing system information"
|
||||
"$PYTHON" -m esptool erase_flash
|
||||
"$PYTHON" -m esptool write_flash 0x1000 system-info.bin
|
||||
"$PYTHON" -m esptool write_flash 0x2B0000 littlefs-*.bin
|
||||
"$PYTHON" -m esptool write_flash 0x10000 ${FILENAME}
|
||||
"$PYTHON" -m esptool write_flash 0x00 ${FILENAME}
|
||||
"$PYTHON" -m esptool write_flash 0x260000 bleota.bin
|
||||
"$PYTHON" -m esptool write_flash 0x300000 littlefs-*.bin
|
||||
|
||||
else
|
||||
echo "Invalid file: ${FILENAME}"
|
||||
show_help
|
||||
|
||||
@@ -28,7 +28,7 @@ IF "__%FILENAME%__" == "____" (
|
||||
)
|
||||
IF EXIST %FILENAME% (
|
||||
echo Trying to flash update %FILENAME%
|
||||
%PYTHON% -m esptool --baud 115200 write_flash 0x10000 %FILENAME%
|
||||
%PYTHON% -m esptool --baud 115200 write_flash 0x00 %FILENAME%
|
||||
) else (
|
||||
echo "Invalid file: %FILENAME%"
|
||||
goto HELP
|
||||
|
||||
@@ -44,7 +44,7 @@ shift "$((OPTIND-1))"
|
||||
|
||||
if [ -f "${FILENAME}" ]; then
|
||||
echo "Trying to flash update ${FILENAME}."
|
||||
$PYTHON -m esptool --baud 115200 write_flash 0x10000 ${FILENAME}
|
||||
$PYTHON -m esptool --baud 115200 write_flash 0x00 ${FILENAME}
|
||||
else
|
||||
echo "Invalid file: ${FILENAME}"
|
||||
show_help
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
import getopt
|
||||
import sys
|
||||
import os
|
||||
from littlefs import LittleFS
|
||||
from pathlib import Path
|
||||
|
||||
print( "Building LittleFS image..." )
|
||||
|
||||
argList = sys.argv[1:]
|
||||
arxx = { argList[i]: argList[i+1] for i in range(0, len(argList)-1, 2) }
|
||||
|
||||
dataPath = arxx["-c"]
|
||||
blockSize = int(arxx["-b"])
|
||||
blockCount = int(arxx["-s"]) / blockSize
|
||||
|
||||
cwd = os.getcwd()
|
||||
|
||||
os.chdir(dataPath)
|
||||
|
||||
fileList = []
|
||||
dirList = []
|
||||
|
||||
for (dirpath, dirnames, filenames) in os.walk('.'):
|
||||
for f in filenames:
|
||||
if (f[:1] != '.'):
|
||||
fileList.append( os.path.join(dirpath, f) )
|
||||
for d in dirnames:
|
||||
if (d[:1] != '.'):
|
||||
dirList.append( os.path.join(dirpath, d) )
|
||||
|
||||
fs = LittleFS(block_size=blockSize, block_count=blockCount) # create a 448kB partition
|
||||
|
||||
for curDir in dirList:
|
||||
print( "Creating dir " + curDir )
|
||||
fs.mkdir( curDir )
|
||||
|
||||
for curFile in fileList:
|
||||
print( "Adding file " + curFile )
|
||||
with open( curFile, 'rb' ) as f:
|
||||
data = f.read()
|
||||
|
||||
with fs.open( curFile, 'wb') as fh:
|
||||
fh.write( data )
|
||||
|
||||
outName = argList[-1]
|
||||
|
||||
os.chdir(cwd)
|
||||
|
||||
with open(outName, 'wb') as fh:
|
||||
fh.write(fs.context.buffer)
|
||||
@@ -1,24 +1,70 @@
|
||||
|
||||
|
||||
import subprocess
|
||||
import configparser
|
||||
import traceback
|
||||
import sys
|
||||
from os.path import join
|
||||
from readprops import readProps
|
||||
|
||||
Import("env")
|
||||
env.Replace( MKSPIFFSTOOL=env.get("PROJECT_DIR") + '/bin/mklittlefs.py' )
|
||||
try:
|
||||
import littlefs
|
||||
except ImportError:
|
||||
env.Execute("$PYTHONEXE -m pip install littlefs-python")
|
||||
platform = env.PioPlatform()
|
||||
|
||||
def esp32_create_combined_bin(source, target, env):
|
||||
# this sub is borrowed from ESPEasy build toolchain. It's licensed under GPL V3
|
||||
# https://github.com/letscontrolit/ESPEasy/blob/mega/tools/pio/post_esp32.py
|
||||
print("Generating combined binary for serial flashing")
|
||||
|
||||
app_offset = 0x10000
|
||||
|
||||
new_file_name = env.subst("$BUILD_DIR/${PROGNAME}.factory.bin")
|
||||
sections = env.subst(env.get("FLASH_EXTRA_IMAGES"))
|
||||
firmware_name = env.subst("$BUILD_DIR/${PROGNAME}.bin")
|
||||
chip = env.get("BOARD_MCU")
|
||||
flash_size = env.BoardConfig().get("upload.flash_size")
|
||||
flash_freq = env.BoardConfig().get("build.f_flash", '40m')
|
||||
flash_freq = flash_freq.replace('000000L', 'm')
|
||||
flash_mode = env.BoardConfig().get("build.flash_mode", "dio")
|
||||
memory_type = env.BoardConfig().get("build.arduino.memory_type", "qio_qspi")
|
||||
if flash_mode == "qio" or flash_mode == "qout":
|
||||
flash_mode = "dio"
|
||||
if memory_type == "opi_opi" or memory_type == "opi_qspi":
|
||||
flash_mode = "dout"
|
||||
cmd = [
|
||||
"--chip",
|
||||
chip,
|
||||
"merge_bin",
|
||||
"-o",
|
||||
new_file_name,
|
||||
"--flash_mode",
|
||||
flash_mode,
|
||||
"--flash_freq",
|
||||
flash_freq,
|
||||
"--flash_size",
|
||||
flash_size,
|
||||
]
|
||||
|
||||
print(" Offset | File")
|
||||
for section in sections:
|
||||
sect_adr, sect_file = section.split(" ", 1)
|
||||
print(f" - {sect_adr} | {sect_file}")
|
||||
cmd += [sect_adr, sect_file]
|
||||
|
||||
print(f" - {hex(app_offset)} | {firmware_name}")
|
||||
cmd += [hex(app_offset), firmware_name]
|
||||
|
||||
print('Using esptool.py arguments: %s' % ' '.join(cmd))
|
||||
|
||||
esptool.main(cmd)
|
||||
|
||||
if (platform.name == "espressif32"):
|
||||
sys.path.append(join(platform.get_package_dir("tool-esptoolpy")))
|
||||
import esptool
|
||||
env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", esp32_create_combined_bin)
|
||||
|
||||
Import("projenv")
|
||||
|
||||
prefsLoc = projenv["PROJECT_DIR"] + "/version.properties"
|
||||
verObj = readProps(prefsLoc)
|
||||
print("Using meshtastic platformio-custom.py, firmware version " + verObj['long'])
|
||||
# print("path is" + ','.join(sys.path))
|
||||
|
||||
# General options that are passed to the C and C++ compilers
|
||||
projenv.Append(CCFLAGS=[
|
||||
|
||||
Binary file not shown.
@@ -1,7 +1,8 @@
|
||||
# FIXME! using the genpartitions based table doesn't work on TTGO so for now I stay with my old memory map
|
||||
# This is a layout for 4MB of flash
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 0x9000, 0x5000,
|
||||
otadata, data, ota, 0xe000, 0x2000,
|
||||
app0, app, ota_0, 0x10000, 0x2A0000,
|
||||
spiffs, data, spiffs, 0x2B0000,0x150000,
|
||||
nvs, data, nvs, 0x009000, 0x005000,
|
||||
otadata, data, ota, 0x00e000, 0x002000,
|
||||
app, app, ota_0, 0x010000, 0x250000,
|
||||
flashApp, app, ota_1, 0x260000, 0x0A0000,
|
||||
spiffs, data, spiffs, 0x300000, 0x100000,
|
||||
|
192
platformio.ini
192
platformio.ini
@@ -2,7 +2,8 @@
|
||||
; https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[platformio]
|
||||
default_envs = tbeam
|
||||
;default_envs = tbeam
|
||||
;default_envs = pico
|
||||
;default_envs = tbeam-s3-core
|
||||
;default_envs = tbeam0.7
|
||||
;default_envs = heltec-v1
|
||||
@@ -14,7 +15,7 @@ default_envs = tbeam
|
||||
;default_envs = tlora-v2
|
||||
;default_envs = tlora-v2-1-1.6
|
||||
;default_envs = lora-relay-v1 # nrf board
|
||||
; default_envs = t-echo
|
||||
;default_envs = t-echo
|
||||
;default_envs = nrf52840dk-geeksville
|
||||
;default_envs = native # lora-relay-v1 # nrf52840dk-geeksville # linux # or if you'd like to change the default to something like lora-relay-v1 put that here
|
||||
;default_envs = nano-g1
|
||||
@@ -24,7 +25,9 @@ default_envs = tbeam
|
||||
;default_envs = m5stack-coreink
|
||||
;default_envs = rak4631
|
||||
|
||||
extra_configs = variants/*/platformio.ini
|
||||
extra_configs =
|
||||
arch/*/*.ini
|
||||
variants/*/platformio.ini
|
||||
|
||||
[env]
|
||||
extra_scripts = bin/platformio-custom.py
|
||||
@@ -45,13 +48,11 @@ monitor_speed = 115200
|
||||
lib_deps =
|
||||
https://github.com/meshtastic/esp8266-oled-ssd1306.git#53580644255b48ebb7a737343c6b4e71c7e11cf2 ; ESP8266_SSD1306
|
||||
mathertel/OneButton@^2.0.3 ; OneButton library for non-blocking button debounce
|
||||
1202 ; CRC32, explicitly needed because dependency is missing in the ble ota update lib
|
||||
https://github.com/meshtastic/arduino-fsm.git
|
||||
https://github.com/meshtastic/TinyGPSPlus.git
|
||||
Wire ; explicitly needed here because the AXP202 library forgets to add it
|
||||
SPI
|
||||
https://github.com/meshtastic/arduino-fsm.git#7db3702bf0cfe97b783d6c72595e3f38e0b19159
|
||||
https://github.com/meshtastic/TinyGPSPlus.git#2f0d0528d737000043e949f4c3bdfb623cf0b902
|
||||
https://github.com/meshtastic/ArduinoThread.git#72921ac222eed6f526ba1682023cee290d9aa1b3
|
||||
nanopb/Nanopb@^0.4.6
|
||||
erriez/ErriezCRC32@^1.0.1
|
||||
|
||||
; Used for the code analysis in PIO Home / Inspect
|
||||
check_tool = cppcheck
|
||||
@@ -63,16 +64,18 @@ framework = arduino
|
||||
lib_deps =
|
||||
${env.lib_deps}
|
||||
; Portduino is using meshtastic fork for now
|
||||
https://github.com/jgromes/RadioLib.git
|
||||
jgromes/RadioLib@5.4.1
|
||||
https://github.com/caveman99/SparkFun_ATECCX08a_Arduino_Library.git#008e7f9d40bad66b2f7a0074aaac05b7c424339d
|
||||
|
||||
build_flags = ${env.build_flags} -Os
|
||||
-DRADIOLIB_SPI_PARANOID=0
|
||||
# -DRADIOLIB_GODMODE
|
||||
build_src_filter = ${env.build_src_filter} -<platform/portduino/>
|
||||
|
||||
; Common libs for communicating over TCP/IP networks such as MQTT
|
||||
[networking_base]
|
||||
lib_deps =
|
||||
PubSubClient
|
||||
knolleary/PubSubClient@^2.8
|
||||
meshtastic/json11@^1.0.2
|
||||
|
||||
; Common libs for environmental measurements in telemetry module
|
||||
@@ -81,177 +84,10 @@ lib_deps =
|
||||
lib_deps =
|
||||
adafruit/Adafruit BusIO@^1.11.4
|
||||
adafruit/Adafruit Unified Sensor@^1.1.4
|
||||
adafruit/Adafruit BMP280 Library@^2.6.3
|
||||
adafruit/Adafruit BMP280 Library@^2.6.6
|
||||
adafruit/Adafruit BME280 Library@^2.2.2
|
||||
adafruit/Adafruit BME680 Library@^2.0.1
|
||||
adafruit/Adafruit MCP9808 Library@^2.0.0
|
||||
adafruit/Adafruit INA260 Library@^1.5.0
|
||||
adafruit/Adafruit INA219@^1.2.0
|
||||
; Common settings for ESP targes, mixin with extends = esp32_base
|
||||
[esp32_base]
|
||||
extends = arduino_base
|
||||
platform = espressif32@3.5.0
|
||||
build_src_filter =
|
||||
${arduino_base.build_src_filter} -<platform/nrf52/> -<platform/stm32wl> -<platform/rp2040>
|
||||
upload_speed = 921600
|
||||
debug_init_break = tbreak setup
|
||||
|
||||
# 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 -lnimble -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
|
||||
lib_deps =
|
||||
${arduino_base.lib_deps}
|
||||
${networking_base.lib_deps}
|
||||
${environmental_base.lib_deps}
|
||||
https://github.com/meshtastic/esp32_https_server.git
|
||||
h2zero/NimBLE-Arduino@1.4.0
|
||||
arduino-libraries/NTPClient@^3.1.0
|
||||
lorol/LittleFS_esp32@^1.0.6
|
||||
https://github.com/lewisxhe/XPowersLib.git
|
||||
|
||||
lib_ignore =
|
||||
segger_rtt
|
||||
ESP32 BLE Arduino
|
||||
platform_packages =
|
||||
framework-arduinoespressif32@https://github.com/meshtastic/arduino-esp32.git#4cde0f5d412d2695184f32e8a47e9bea57b45276
|
||||
|
||||
; leave this commented out to avoid breaking Windows
|
||||
;upload_port = /dev/ttyUSB0
|
||||
;monitor_port = /dev/ttyUSB0
|
||||
|
||||
; Please don't delete these lines. JM uses them.
|
||||
;upload_port = /dev/cu.SLAB_USBtoUART
|
||||
;monitor_port = /dev/cu.SLAB_USBtoUART
|
||||
|
||||
; customize the partition table
|
||||
; http://docs.platformio.org/en/latest/platforms/espressif32.html#partition-tables
|
||||
board_build.partitions = partition-table.csv
|
||||
|
||||
[nrf52_base]
|
||||
; Instead of the standard nordicnrf52 platform, we use our fork which has our added variant files
|
||||
; platform = nordicnrf52 ;pending https://github.com/platformio/builder-framework-arduino-nrf5/pull/7
|
||||
platform = https://github.com/meshtastic/platform-nordicnrf52.git#merge
|
||||
|
||||
extends = arduino_base
|
||||
build_type = debug ; I'm debugging with ICE a lot now
|
||||
; note: liboberon provides the AES256 implementation for NRF52 (though not using the hardware acceleration of the NRF52840 - FIXME)
|
||||
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>
|
||||
lib_ignore =
|
||||
BluetoothOTA
|
||||
|
||||
[nrf52840_base]
|
||||
extends = nrf52_base
|
||||
build_flags = ${nrf52_base.build_flags}
|
||||
lib_deps =
|
||||
${arduino_base.lib_deps}
|
||||
${environmental_base.lib_deps}
|
||||
https://github.com/Kongduino/Adafruit_nRFCrypto.git
|
||||
|
||||
; Note: By default no lora device is created for this build - it uses a simulated interface
|
||||
[env:nrf52840dk]
|
||||
extends = nrf52840_base
|
||||
board = nrf52840_dk
|
||||
|
||||
; Note: By default no lora device is created for this build - it uses a simulated interface
|
||||
[env:feather_nrf52832]
|
||||
extends = nrf52_base
|
||||
board = adafruit_feather_nrf52832
|
||||
|
||||
; Common settings for rp2040 Processor based targets
|
||||
[rp2040_base]
|
||||
platform = https://github.com/maxgerhardt/platform-raspberrypi.git
|
||||
extends = arduino_base
|
||||
board_build.core = earlephilhower
|
||||
board_build.filesystem_size = 0.5m
|
||||
build_flags =
|
||||
${arduino_base.build_flags} -Wno-unused-variable
|
||||
-Isrc/platform/rp2040
|
||||
-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>
|
||||
lib_ignore =
|
||||
BluetoothOTA
|
||||
lib_deps =
|
||||
${arduino_base.lib_deps}
|
||||
${environmental_base.lib_deps}
|
||||
https://github.com/kokke/tiny-AES-c.git
|
||||
|
||||
[stm32wl5e_base]
|
||||
platform = ststm32
|
||||
board = generic_wl5e
|
||||
framework = arduino
|
||||
build_type = debug
|
||||
build_flags =
|
||||
${arduino_base.build_flags}
|
||||
-Isrc/platform/stm32wl -g
|
||||
-DHAL_SUBGHZ_MODULE_ENABLED
|
||||
# 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> -<mqtt/> -<graphics> -<input> -<buzz> -<modules/Telemetry> -<platform/nrf52> -<platform/portduino> -<platform/rp2040>
|
||||
lib_deps =
|
||||
${env.lib_deps}
|
||||
https://github.com/jgromes/RadioLib.git
|
||||
https://github.com/kokke/tiny-AES-c.git
|
||||
lib_ignore =
|
||||
mathertel/OneButton@^2.0.3
|
||||
|
||||
|
||||
|
||||
[esp32s3_base]
|
||||
extends = arduino_base
|
||||
platform = espressif32
|
||||
build_src_filter =
|
||||
${arduino_base.build_src_filter} -<platform/nrf52/> -<platform/stm32wl> -<platform/rp2040>
|
||||
upload_speed = 961200
|
||||
monitor_speed = 115200
|
||||
debug_init_break = tbreak setup
|
||||
|
||||
# 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
|
||||
|
||||
lib_deps =
|
||||
${arduino_base.lib_deps}
|
||||
${networking_base.lib_deps}
|
||||
${environmental_base.lib_deps}
|
||||
; https://github.com/meshtastic/esp32_https_server.git
|
||||
; PR has been submitted and can be deleted after merging ,https://github.com/meshtastic/esp32_https_server/pull/1
|
||||
https://github.com/lewisxhe/esp32_https_server.git
|
||||
h2zero/NimBLE-Arduino@1.4.0
|
||||
arduino-libraries/NTPClient@^3.1.0
|
||||
https://github.com/lewisxhe/XPowersLib.git
|
||||
|
||||
|
||||
lib_ignore =
|
||||
segger_rtt
|
||||
ESP32 BLE Arduino
|
||||
platform_packages =
|
||||
framework-arduinoespressif32@ 3.20004.220825
|
||||
|
||||
; customize the partition table
|
||||
; http://docs.platformio.org/en/latest/platforms/espressif32.html#partition-tables
|
||||
board_build.partitions = partition-table.csv
|
||||
|
||||
|
||||
Submodule protobufs updated: 0328a5269f...d3dfaa63a5
@@ -7,7 +7,7 @@ const uint8_t MESH_SERVICE_UUID_16[16u] = {0xfd, 0xea, 0x73, 0xe2, 0xca, 0x5d, 0
|
||||
0x1f, 0x46, 0xa8, 0x15, 0x18, 0xb2, 0xa1, 0x6b};
|
||||
const uint8_t TORADIO_UUID_16[16u] = {0xe7, 0x01, 0x44, 0x12, 0x66, 0x78, 0xdd, 0xa1,
|
||||
0xad, 0x4d, 0x9e, 0x12, 0xd2, 0x76, 0x5c, 0xf7};
|
||||
const uint8_t FROMRADIO_UUID_16[16u] = {0xd5, 0x54, 0xe4, 0xc5, 0x25, 0xc5, 0x31, 0xa5,
|
||||
0x55, 0x4a, 0x02, 0xee, 0xc2, 0xbc, 0xa2, 0x8b};
|
||||
const uint8_t FROMRADIO_UUID_16[16u] = {0x02, 0x00, 0x12, 0xac, 0x42, 0x02, 0x78, 0xb8,
|
||||
0xed, 0x11, 0x93, 0x49, 0x9e, 0xe6, 0x55, 0x2c};
|
||||
const uint8_t FROMNUM_UUID_16[16u] = {0x53, 0x44, 0xe3, 0x47, 0x75, 0xaa, 0x70, 0xa6,
|
||||
0x66, 0x4f, 0x00, 0xa8, 0x8c, 0xa1, 0x9d, 0xed};
|
||||
@@ -9,7 +9,7 @@
|
||||
#define MESH_SERVICE_UUID "6ba1b218-15a8-461f-9fa8-5dcae273eafd"
|
||||
|
||||
#define TORADIO_UUID "f75c76d2-129e-4dad-a1dd-7866124401e7"
|
||||
#define FROMRADIO_UUID "8ba2bcc2-ee02-4a55-a531-c525c5e454d5"
|
||||
#define FROMRADIO_UUID "2c55e69e-4993-11ed-b878-0242ac120002"
|
||||
#define FROMNUM_UUID "ed9da18c-a800-4f66-a670-aa7547e34453"
|
||||
|
||||
// NRF52 wants these constants as byte arrays
|
||||
|
||||
132
src/FSCommon.cpp
132
src/FSCommon.cpp
@@ -9,13 +9,13 @@ bool copyFile(const char* from, const char* to)
|
||||
|
||||
File f1 = FSCom.open(from, FILE_O_READ);
|
||||
if (!f1){
|
||||
DEBUG_MSG("Failed to open file");
|
||||
DEBUG_MSG("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 file");
|
||||
DEBUG_MSG("Failed to open destination file %s\n", to);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -33,17 +33,25 @@ bool copyFile(const char* from, const char* to)
|
||||
bool renameFile(const char* pathFrom, const char* pathTo)
|
||||
{
|
||||
#ifdef FSCom
|
||||
#ifdef ARCH_ESP32
|
||||
// rename was fixed for ESP32 IDF LittleFS in April
|
||||
return FSCom.rename(pathFrom, pathTo);
|
||||
#else
|
||||
if (copyFile(pathFrom, pathTo) && FSCom.remove(pathFrom) ) {
|
||||
return true;
|
||||
} else{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void listDir(const char * dirname, uint8_t levels)
|
||||
void listDir(const char * dirname, uint8_t levels, boolean del = false)
|
||||
{
|
||||
#ifdef FSCom
|
||||
#if (defined(ARCH_ESP32) || defined(ARCH_RP2040) || defined(ARCH_PORTDUINO))
|
||||
char buffer[255];
|
||||
#endif
|
||||
File root = FSCom.open(dirname, FILE_O_READ);
|
||||
if(!root){
|
||||
return;
|
||||
@@ -56,55 +64,92 @@ void listDir(const char * dirname, uint8_t levels)
|
||||
while(file){
|
||||
if(file.isDirectory() && !String(file.name()).endsWith(".")) {
|
||||
if(levels){
|
||||
listDir(file.name(), levels -1);
|
||||
#ifdef ARCH_ESP32
|
||||
listDir(file.path(), levels -1, del);
|
||||
if(del) {
|
||||
DEBUG_MSG("Removing %s\n", file.path());
|
||||
strcpy(buffer, file.path());
|
||||
file.close();
|
||||
FSCom.rmdir(buffer);
|
||||
} else {
|
||||
file.close();
|
||||
}
|
||||
#elif (defined(ARCH_RP2040) || defined(ARCH_PORTDUINO))
|
||||
listDir(file.name(), levels -1, del);
|
||||
if(del) {
|
||||
DEBUG_MSG("Removing %s\n", file.name());
|
||||
strcpy(buffer, file.name());
|
||||
file.close();
|
||||
FSCom.rmdir(buffer);
|
||||
} else {
|
||||
file.close();
|
||||
}
|
||||
#else
|
||||
listDir(file.name(), levels -1, del);
|
||||
file.close();
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
DEBUG_MSG(" %s (%i Bytes)\n", file.name(), file.size());
|
||||
#ifdef ARCH_ESP32
|
||||
if(del) {
|
||||
DEBUG_MSG("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());
|
||||
file.close();
|
||||
}
|
||||
#elif (defined(ARCH_RP2040) || defined(ARCH_PORTDUINO))
|
||||
if(del) {
|
||||
DEBUG_MSG("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());
|
||||
file.close();
|
||||
}
|
||||
#else
|
||||
DEBUG_MSG(" %s (%i Bytes)\n", file.name(), file.size());
|
||||
file.close();
|
||||
#endif
|
||||
}
|
||||
file.close();
|
||||
file = root.openNextFile();
|
||||
}
|
||||
file.close();
|
||||
#ifdef ARCH_ESP32
|
||||
if(del) {
|
||||
DEBUG_MSG("Removing %s\n", root.path());
|
||||
strcpy(buffer, root.path());
|
||||
root.close();
|
||||
FSCom.rmdir(buffer);
|
||||
} else {
|
||||
root.close();
|
||||
}
|
||||
#elif (defined(ARCH_RP2040) || defined(ARCH_PORTDUINO))
|
||||
if(del) {
|
||||
DEBUG_MSG("Removing %s\n", root.name());
|
||||
strcpy(buffer, root.name());
|
||||
root.close();
|
||||
FSCom.rmdir(buffer);
|
||||
} else {
|
||||
root.close();
|
||||
}
|
||||
#else
|
||||
root.close();
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void rmDir(const char * dirname)
|
||||
{
|
||||
#ifdef FSCom
|
||||
File file = FSCom.open(dirname, FILE_O_READ);
|
||||
if(!file){
|
||||
return;
|
||||
}
|
||||
if(!file.isDirectory()){
|
||||
file.close();
|
||||
FSCom.remove(file.name());
|
||||
// DEBUG_MSG("Remove FILE %s\n", file.name());
|
||||
return;
|
||||
}
|
||||
|
||||
file.rewindDirectory();
|
||||
while (true) {
|
||||
File entry = file.openNextFile();
|
||||
if (!entry) {
|
||||
break;
|
||||
}
|
||||
char dirpath[100]; // array to hold the result.
|
||||
strcpy(dirpath, dirname); // copy string one into the result.
|
||||
strcat(dirpath,"/"); // append string two to the result.
|
||||
strcat(dirpath,entry.name()); // append string two to the result.
|
||||
if(entry.isDirectory() && !String(entry.name()).endsWith(".")) {
|
||||
entry.close();
|
||||
// DEBUG_MSG("Descend DIR %s\n", dirpath);
|
||||
rmDir(dirpath);
|
||||
} else {
|
||||
entry.close();
|
||||
// DEBUG_MSG("Remove FILE %s\n", entry.name());
|
||||
FSCom.remove(entry.name());
|
||||
}
|
||||
}
|
||||
FSCom.rmdir(dirname);
|
||||
// DEBUG_MSG("Remove DIR %s\n", dirname);
|
||||
file.close();
|
||||
#if (defined(ARCH_ESP32) || defined(ARCH_RP2040) || defined(ARCH_PORTDUINO))
|
||||
listDir(dirname, 10, true);
|
||||
#elif defined(ARCH_NRF52)
|
||||
// nRF52 implementation of LittleFS has a recursive delete function
|
||||
FSCom.rmdir_r(dirname);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -116,8 +161,11 @@ void fsInit()
|
||||
DEBUG_MSG("ERROR filesystem mount Failed. Formatting...\n");
|
||||
assert(0); // FIXME - report failure to phone
|
||||
}
|
||||
|
||||
#ifdef ARCH_ESP32
|
||||
DEBUG_MSG("Filesystem files (%d/%d Bytes):\n", FSCom.usedBytes(), FSCom.totalBytes());
|
||||
#else
|
||||
DEBUG_MSG("Filesystem files:\n");
|
||||
#endif
|
||||
listDir("/", 10);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -23,16 +23,9 @@
|
||||
#endif
|
||||
|
||||
#if defined(ARCH_ESP32)
|
||||
#if CONFIG_IDF_TARGET_ESP32S3
|
||||
#include <LittleFS.h> //esp32s3 uses the framework's built-in LittleFS
|
||||
#define FSCom LittleFS
|
||||
#else
|
||||
// ESP32 version
|
||||
#include "LITTLEFS.h"
|
||||
#define FSCom LITTLEFS
|
||||
#endif
|
||||
|
||||
|
||||
#include "LittleFS.h"
|
||||
#define FSCom LittleFS
|
||||
#define FSBegin() FSCom.begin(true)
|
||||
#define FILE_O_WRITE "w"
|
||||
#define FILE_O_READ "r"
|
||||
@@ -47,6 +40,7 @@ using namespace Adafruit_LittleFS_Namespace;
|
||||
#endif
|
||||
|
||||
void fsInit();
|
||||
bool copyFile(const char* from, const char* to);
|
||||
bool renameFile(const char* pathFrom, const char* pathTo);
|
||||
void listDir(const char * dirname, uint8_t levels);
|
||||
void listDir(const char * dirname, uint8_t levels, boolean del);
|
||||
void rmDir(const char * dirname);
|
||||
|
||||
@@ -25,21 +25,21 @@ class GPSStatus : public Status
|
||||
public:
|
||||
GPSStatus() { statusType = STATUS_TYPE_GPS; }
|
||||
|
||||
// proposed for deprecation
|
||||
GPSStatus(bool hasLock, bool isConnected, int32_t latitude, int32_t longitude, int32_t altitude, uint32_t dop,
|
||||
uint32_t heading, uint32_t numSatellites)
|
||||
: Status()
|
||||
{
|
||||
this->hasLock = hasLock;
|
||||
this->isConnected = isConnected;
|
||||
// // proposed for deprecation
|
||||
// GPSStatus(bool hasLock, bool isConnected, int32_t latitude, int32_t longitude, int32_t altitude, uint32_t dop,
|
||||
// uint32_t heading, uint32_t numSatellites)
|
||||
// : Status()
|
||||
// {
|
||||
// this->hasLock = hasLock;
|
||||
// this->isConnected = isConnected;
|
||||
|
||||
this->p.latitude_i = latitude;
|
||||
this->p.longitude_i = longitude;
|
||||
this->p.altitude = altitude;
|
||||
this->p.PDOP = dop;
|
||||
this->p.ground_track = heading;
|
||||
this->p.sats_in_view = numSatellites;
|
||||
}
|
||||
// this->p.latitude_i = latitude;
|
||||
// this->p.longitude_i = longitude;
|
||||
// this->p.altitude = altitude;
|
||||
// this->p.PDOP = dop;
|
||||
// this->p.ground_track = heading;
|
||||
// this->p.sats_in_view = numSatellites;
|
||||
// }
|
||||
|
||||
// preferred method
|
||||
GPSStatus(bool hasLock, bool isConnected, const Position &pos) : Status()
|
||||
@@ -114,6 +114,7 @@ class GPSStatus : public Status
|
||||
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 ||
|
||||
newStatus->p.ground_speed != p.ground_speed ||
|
||||
newStatus->p.sats_in_view != p.sats_in_view);
|
||||
}
|
||||
|
||||
@@ -136,9 +137,9 @@ 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, sats=%d\n", p.timestamp,
|
||||
DEBUG_MSG("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.sats_in_view);
|
||||
p.ground_speed * 1e-2, p.sats_in_view);
|
||||
} else
|
||||
DEBUG_MSG("No GPS lock\n");
|
||||
onNewStatus.notifyObservers(this);
|
||||
|
||||
@@ -131,7 +131,7 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
||||
#endif
|
||||
// DEBUG_MSG("battery gpio %d raw val=%u scaled=%u\n", BATTERY_PIN, raw, (uint32_t)(scaled));
|
||||
last_read_value = scaled;
|
||||
return scaled * 1000;
|
||||
return scaled;
|
||||
} else {
|
||||
return last_read_value;
|
||||
}
|
||||
@@ -368,8 +368,21 @@ bool Power::axpChipInit()
|
||||
|
||||
#ifdef HAS_PMU
|
||||
|
||||
TwoWire * w = NULL;
|
||||
|
||||
// Use macro to distinguish which wire is used by PMU
|
||||
#ifdef PMU_USE_WIRE1
|
||||
w = &Wire1;
|
||||
#else
|
||||
w = &Wire;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* It is not necessary to specify the wire pin,
|
||||
* just input the wire, because the wire has been initialized in main.cpp
|
||||
*/
|
||||
if (!PMU) {
|
||||
PMU = new XPowersAXP2101(Wire, I2C_SDA, I2C_SCL);
|
||||
PMU = new XPowersAXP2101(*w);
|
||||
if (!PMU->init()) {
|
||||
DEBUG_MSG("Warning: Failed to find AXP2101 power management\n");
|
||||
delete PMU;
|
||||
@@ -380,7 +393,7 @@ bool Power::axpChipInit()
|
||||
}
|
||||
|
||||
if (!PMU) {
|
||||
PMU = new XPowersAXP192(Wire, I2C_SDA, I2C_SCL);
|
||||
PMU = new XPowersAXP192(*w);
|
||||
if (!PMU->init()) {
|
||||
DEBUG_MSG("Warning: Failed to find AXP192 power management\n");
|
||||
delete PMU;
|
||||
@@ -396,7 +409,9 @@ bool Power::axpChipInit()
|
||||
* In order not to affect other devices, if the initialization of the PMU fails, Wire needs to be re-initialized once,
|
||||
* if there are multiple devices sharing the bus.
|
||||
* * */
|
||||
Wire.begin(I2C_SDA, I2C_SCL);
|
||||
#ifndef PMU_USE_WIRE1
|
||||
w->begin(I2C_SDA, I2C_SCL);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -456,6 +471,23 @@ bool Power::axpChipInit()
|
||||
PMU->setPowerChannelVoltage(XPOWERS_DCDC3, 3300);
|
||||
PMU->enablePowerOutput(XPOWERS_DCDC3);
|
||||
|
||||
/**
|
||||
* ALDO2 cannot be turned off.
|
||||
* It is a necessary condition for sensor communication.
|
||||
* It must be turned on to properly access the sensor and screen
|
||||
* It is also responsible for the power supply of PCF8563
|
||||
*/
|
||||
PMU->setPowerChannelVoltage(XPOWERS_ALDO2, 3300);
|
||||
PMU->enablePowerOutput(XPOWERS_ALDO2);
|
||||
|
||||
// 6-axis , magnetometer ,bme280 , oled screen power channel
|
||||
PMU->setPowerChannelVoltage(XPOWERS_ALDO1, 3300);
|
||||
PMU->enablePowerOutput(XPOWERS_ALDO1);
|
||||
|
||||
// sdcard power channle
|
||||
PMU->setPowerChannelVoltage(XPOWERS_BLDO1, 3300);
|
||||
PMU->enablePowerOutput(XPOWERS_BLDO1);
|
||||
|
||||
// PMU->setPowerChannelVoltage(XPOWERS_DCDC4, 3300);
|
||||
// PMU->enablePowerOutput(XPOWERS_DCDC4);
|
||||
|
||||
|
||||
@@ -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);
|
||||
DEBUG_MSG("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
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "configuration.h"
|
||||
#include "RedirectablePrint.h"
|
||||
#include "RTC.h"
|
||||
#include "NodeDB.h"
|
||||
#include "concurrency/OSThread.h"
|
||||
// #include "wifi/WiFiServerAPI.h"
|
||||
#include <assert.h>
|
||||
@@ -30,7 +31,9 @@ size_t RedirectablePrint::write(uint8_t c)
|
||||
// optionally send chars to TCP also
|
||||
//WiFiServerPort::debugOut(c);
|
||||
|
||||
dest->write(c);
|
||||
if (!config.has_lora || config.device.serial_enabled)
|
||||
dest->write(c);
|
||||
|
||||
return 1; // We always claim one was written, rather than trusting what the
|
||||
// serial port said (which could be zero)
|
||||
}
|
||||
|
||||
@@ -20,6 +20,9 @@ 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)
|
||||
@@ -57,10 +60,15 @@ bool SerialConsole::checkIsConnected()
|
||||
*/
|
||||
bool SerialConsole::handleToRadio(const uint8_t *buf, size_t len)
|
||||
{
|
||||
// Turn off debug serial printing once the API is activated, because other threads could print and corrupt packets
|
||||
if (!config.device.debug_log_enabled)
|
||||
setDestination(&noopPrint);
|
||||
canWrite = true;
|
||||
// only talk to the API once the configuration has been loaded and we're sure the serial port is not disabled.
|
||||
if (config.has_lora && config.device.serial_enabled) {
|
||||
// Turn off debug serial printing once the API is activated, because other threads could print and corrupt packets
|
||||
if (!config.device.debug_log_enabled)
|
||||
setDestination(&noopPrint);
|
||||
canWrite = true;
|
||||
|
||||
return StreamAPI::handleToRadio(buf, len);
|
||||
}
|
||||
return StreamAPI::handleToRadio(buf, len);
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -36,6 +36,7 @@ struct ToneDuration {
|
||||
#define NOTE_A3 220
|
||||
#define NOTE_AS3 233
|
||||
#define NOTE_B3 247
|
||||
#define NOTE_CS4 277
|
||||
|
||||
const int DURATION_1_8 = 125; // 1/8 note
|
||||
const int DURATION_1_4 = 250; // 1/4 note
|
||||
@@ -65,16 +66,17 @@ void playBeep() { tone(PIN_BUZZER, NOTE_B3, DURATION_1_4); }
|
||||
#endif
|
||||
|
||||
void playStartMelody() {
|
||||
ToneDuration melody[] = {{NOTE_B3, DURATION_1_4},
|
||||
{NOTE_B3, DURATION_1_8},
|
||||
{NOTE_B3, DURATION_1_8}};
|
||||
ToneDuration melody[] = {{NOTE_FS3, DURATION_1_8},
|
||||
{NOTE_AS3, DURATION_1_8},
|
||||
{NOTE_CS4, DURATION_1_4}};
|
||||
playTones(melody, sizeof(melody) / sizeof(ToneDuration));
|
||||
}
|
||||
|
||||
|
||||
void playShutdownMelody() {
|
||||
ToneDuration melody[] = {{NOTE_B3, DURATION_1_4},
|
||||
{NOTE_G3, DURATION_1_8},
|
||||
{NOTE_D3, DURATION_1_8}};
|
||||
ToneDuration melody[] = {{NOTE_CS4, DURATION_1_8},
|
||||
{NOTE_AS3, DURATION_1_8},
|
||||
{NOTE_FS3, DURATION_1_4}};
|
||||
playTones(melody, sizeof(melody) / sizeof(ToneDuration));
|
||||
}
|
||||
#endif
|
||||
@@ -94,19 +94,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
// Define this if you know you have that controller or your "SSD1306" misbehaves.
|
||||
//#define USE_SH1106
|
||||
|
||||
// Flip the screen upside down by default as it makes more sense on T-BEAM
|
||||
// devices. Comment this out to not rotate screen 180 degrees.
|
||||
#define SCREEN_FLIP_VERTICALLY
|
||||
|
||||
// Define if screen should be mirrored left to right
|
||||
// #define SCREEN_MIRROR
|
||||
|
||||
// The m5stack I2C Keyboard (also RAK14004)
|
||||
#define CARDKB_ADDR 0x5F
|
||||
|
||||
// The older M5 Faces I2C Keyboard
|
||||
#define FACESKB_ADDR 0x88
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// SENSOR
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -115,6 +108,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#define MCP9808_ADDR 0x18
|
||||
#define INA_ADDR 0x40
|
||||
#define INA_ADDR_ALTERNATE 0x41
|
||||
#define QMC6310_ADDR 0x1C
|
||||
#define QMI8658_ADDR 0x6B
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Security
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#define ATECC608B_ADDR 0x35
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// GPS
|
||||
|
||||
@@ -9,6 +9,41 @@
|
||||
#endif
|
||||
|
||||
#if HAS_WIRE
|
||||
|
||||
void printATECCInfo()
|
||||
{
|
||||
#ifndef ARCH_PORTDUINO
|
||||
atecc.readConfigZone(false);
|
||||
|
||||
DEBUG_MSG("ATECC608B Serial Number: ");
|
||||
for (int i = 0 ; i < 9 ; i++) {
|
||||
DEBUG_MSG("%02x",atecc.serialNumber[i]);
|
||||
}
|
||||
|
||||
DEBUG_MSG(", Rev Number: ");
|
||||
for (int i = 0 ; i < 4 ; i++) {
|
||||
DEBUG_MSG("%02x",atecc.revisionNumber[i]);
|
||||
}
|
||||
DEBUG_MSG("\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");
|
||||
|
||||
if (atecc.configLockStatus && atecc.dataOTPLockStatus && atecc.slot0LockStatus) {
|
||||
if (atecc.generatePublicKey() == false) {
|
||||
DEBUG_MSG("ATECC608B Error generating public key\n");
|
||||
} else {
|
||||
DEBUG_MSG("ATECC608B Public Key: ");
|
||||
for (int i = 0 ; i < 64 ; i++) {
|
||||
DEBUG_MSG("%02x",atecc.publicKey64Bytes[i]);
|
||||
}
|
||||
DEBUG_MSG("\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
uint16_t getRegisterValue(uint8_t address, uint8_t reg, uint8_t length) {
|
||||
uint16_t value = 0x00;
|
||||
Wire.beginTransmission(address);
|
||||
@@ -79,6 +114,17 @@ void scanI2Cdevice(void)
|
||||
DEBUG_MSG("unknown display found\n");
|
||||
}
|
||||
}
|
||||
#ifndef ARCH_PORTDUINO
|
||||
if (addr == ATECC608B_ADDR){
|
||||
keystore_found = addr;
|
||||
if (atecc.begin(keystore_found) == true) {
|
||||
DEBUG_MSG("ATECC608B initialized\n");
|
||||
} else {
|
||||
DEBUG_MSG("ATECC608B initialization failed\n");
|
||||
}
|
||||
printATECCInfo();
|
||||
}
|
||||
#endif
|
||||
#ifdef RV3028_RTC
|
||||
if (addr == RV3028_RTC){
|
||||
rtc_found = addr;
|
||||
@@ -107,10 +153,6 @@ void scanI2Cdevice(void)
|
||||
kb_model = 0x00;
|
||||
}
|
||||
}
|
||||
if (addr == FACESKB_ADDR) {
|
||||
faceskb_found = addr;
|
||||
DEBUG_MSG("m5 Faces found\n");
|
||||
}
|
||||
if (addr == ST7567_ADDRESS) {
|
||||
screen_found = addr;
|
||||
DEBUG_MSG("st7567 display found\n");
|
||||
@@ -149,6 +191,14 @@ void scanI2Cdevice(void)
|
||||
nodeTelemetrySensorsMap[TelemetrySensorType_MCP9808] = addr;
|
||||
DEBUG_MSG("MCP9808 sensor found at address 0x%x\n", (uint8_t)addr);
|
||||
}
|
||||
if(addr == QMC6310_ADDR){
|
||||
DEBUG_MSG("QMC6310 3-Axis magnetic sensor found at address 0x%x\n", (uint8_t)addr);
|
||||
nodeTelemetrySensorsMap[TelemetrySensorType_QMC6310] = addr;
|
||||
}
|
||||
if(addr == QMI8658_ADDR){
|
||||
DEBUG_MSG("QMI8658 6-Axis inertial measurement sensor found at address 0x%x\n", (uint8_t)addr);
|
||||
nodeTelemetrySensorsMap[TelemetrySensorType_QMI8658] = addr;
|
||||
}
|
||||
} else if (err == 4) {
|
||||
DEBUG_MSG("Unknow error at address 0x%x\n", addr);
|
||||
}
|
||||
|
||||
107
src/gps/GPS.cpp
107
src/gps/GPS.cpp
@@ -145,8 +145,8 @@ bool GPS::setupGPS()
|
||||
if (_serial_gps && !didSerialInit) {
|
||||
didSerialInit = true;
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32S3
|
||||
// In esp32s3 framework, setRxBufferSize needs to be initialized before Serial
|
||||
#ifdef ARCH_ESP32
|
||||
// In esp32 framework, setRxBufferSize needs to be initialized before Serial
|
||||
_serial_gps->setRxBufferSize(2048); // the default is 256
|
||||
#endif
|
||||
|
||||
@@ -157,12 +157,6 @@ bool GPS::setupGPS()
|
||||
_serial_gps->begin(GPS_BAUDRATE);
|
||||
#endif
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
_serial_gps->setRxBufferSize(2048); // the default is 256
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef LILYGO_TBEAM_S3_CORE
|
||||
/*
|
||||
* T-Beam-S3-Core will be preset to use gps Probe here, and other boards will not be changed first
|
||||
*/
|
||||
@@ -251,86 +245,6 @@ bool GPS::setupGPS()
|
||||
DEBUG_MSG("WARNING: Unable to enable NMEA GGA.\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef TTGO_T_ECHO
|
||||
// Switch to 9600 baud, then close and reopen port
|
||||
_serial_gps->end();
|
||||
delay(250);
|
||||
_serial_gps->begin(4800);
|
||||
delay(250);
|
||||
_serial_gps->write("$PCAS01,1*1D\r\n");
|
||||
delay(250);
|
||||
_serial_gps->end();
|
||||
delay(250);
|
||||
_serial_gps->begin(9600);
|
||||
delay(250);
|
||||
// Initialize the L76K Chip, use GPS + GLONASS
|
||||
_serial_gps->write("$PCAS04,5*1C\r\n");
|
||||
delay(250);
|
||||
// only ask for RMC and GGA
|
||||
_serial_gps->write("$PCAS03,1,0,0,0,1,0,0,0,0,0,,,0,0*02\r\n");
|
||||
delay(250);
|
||||
// Switch to Vehicle Mode, since SoftRF enables Aviation < 2g
|
||||
_serial_gps->write("$PCAS11,3*1E\r\n");
|
||||
delay(250);
|
||||
#endif
|
||||
#ifdef GPS_UBLOX
|
||||
delay(250);
|
||||
// Set the UART port to output NMEA only
|
||||
byte _message_nmea[] = {0xB5, 0x62, 0x06, 0x00, 0x14, 0x00, 0x01, 0x00, 0x00, 0x00, 0xC0, 0x08, 0x00, 0x00,
|
||||
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");
|
||||
return true;
|
||||
}
|
||||
|
||||
// disable GGL
|
||||
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");
|
||||
return true;
|
||||
}
|
||||
|
||||
// disable GSA
|
||||
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");
|
||||
return true;
|
||||
}
|
||||
|
||||
// disable GSV
|
||||
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");
|
||||
return true;
|
||||
}
|
||||
|
||||
// disable VTG
|
||||
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");
|
||||
return true;
|
||||
}
|
||||
|
||||
// enable RMC
|
||||
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");
|
||||
return true;
|
||||
}
|
||||
|
||||
// enable GGA
|
||||
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");
|
||||
#endif
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -490,7 +404,6 @@ int32_t GPS::runOnce()
|
||||
// if we have received valid NMEA claim we are connected
|
||||
setConnected();
|
||||
} else {
|
||||
#if defined(LILYGO_TBEAM_S3_CORE)
|
||||
if(gnssModel == GNSS_MODEL_UBLOX){
|
||||
// reset the GPS on next bootup
|
||||
if(devicestate.did_gps_reset && (millis() > 60000) && !hasFlow()) {
|
||||
@@ -499,14 +412,6 @@ int32_t GPS::runOnce()
|
||||
nodeDB.saveDeviceStateToDisk();
|
||||
}
|
||||
}
|
||||
#elif defined(GPS_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");
|
||||
devicestate.did_gps_reset = false;
|
||||
nodeDB.saveDeviceStateToDisk();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// If we are overdue for an update, turn on the GPS and at least publish the current status
|
||||
@@ -608,6 +513,13 @@ int GPS::prepareDeepSleep(void *unused)
|
||||
|
||||
GnssModel_t GPS::probe()
|
||||
{
|
||||
// return immediately if the model is set by the variant.h file
|
||||
#ifdef GPS_UBLOX
|
||||
return GNSS_MODEL_UBLOX;
|
||||
#elif defined(GPS_L76K)
|
||||
return GNSS_MODEL_MTK;
|
||||
#else
|
||||
// we use autodetect, only T-BEAM S3 for now...
|
||||
uint8_t buffer[256];
|
||||
/*
|
||||
* The GNSS module information variable is temporarily placed inside the function body,
|
||||
@@ -702,6 +614,7 @@ GnssModel_t GPS::probe()
|
||||
}
|
||||
|
||||
return GNSS_MODEL_UBLOX;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if HAS_GPS
|
||||
|
||||
@@ -19,27 +19,21 @@ static int32_t toDegInt(RawDegrees d)
|
||||
|
||||
bool NMEAGPS::factoryReset()
|
||||
{
|
||||
/**
|
||||
* First use the macro definition to distinguish,
|
||||
* if there is no problem, the macro definition will be deleted
|
||||
* */
|
||||
#if defined(LILYGO_TBEAM_S3_CORE)
|
||||
if(gnssModel == GNSS_MODEL_UBLOX){
|
||||
// Factory Reset
|
||||
byte _message_reset[] = {0xB5, 0x62, 0x06, 0x09, 0x0D, 0x00, 0xFF,
|
||||
0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0xFF, 0x00, 0x00, 0x17, 0x2B, 0x7E};
|
||||
_serial_gps->write(_message_reset,sizeof(_message_reset));
|
||||
delay(1000);
|
||||
}
|
||||
#elif defined(GPS_UBLOX)
|
||||
#ifdef PIN_GPS_REINIT
|
||||
//The L76K GNSS on the T-Echo requires the RESET pin to be pulled LOW
|
||||
digitalWrite(PIN_GPS_REINIT, 0);
|
||||
pinMode(PIN_GPS_REINIT, OUTPUT);
|
||||
delay(150); //The L76K datasheet calls for at least 100MS delay
|
||||
digitalWrite(PIN_GPS_REINIT, 1);
|
||||
#endif
|
||||
|
||||
// send the UBLOX Factory Reset Command regardless of detect state, something is very wrong, just assume it's UBLOX.
|
||||
// Factory Reset
|
||||
byte _message_reset[] = {0xB5, 0x62, 0x06, 0x09, 0x0D, 0x00, 0xFF,
|
||||
0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0xFF, 0x00, 0x00, 0x17, 0x2B, 0x7E};
|
||||
_serial_gps->write(_message_reset,sizeof(_message_reset));
|
||||
delay(1000);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -223,13 +217,10 @@ bool NMEAGPS::lookForLocation()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// REDUNDANT?
|
||||
// expect gps pos lat=37.520825, lon=-122.309162, alt=158
|
||||
DEBUG_MSG("new NMEA GPS pos lat=%f, lon=%f, alt=%d, dop=%g, heading=%f\n",
|
||||
latitude * 1e-7, longitude * 1e-7, altitude, dop * 1e-2,
|
||||
heading * 1e-5);
|
||||
*/
|
||||
if (reader.speed.isUpdated() && reader.speed.isValid()) {
|
||||
p.ground_speed = reader.speed.kmph();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -47,8 +47,8 @@ void readFromRTC()
|
||||
rtc.begin();
|
||||
auto tc = rtc.getDateTime();
|
||||
tm t;
|
||||
t.tm_year = tc.year;
|
||||
t.tm_mon = tc.month;
|
||||
t.tm_year = tc.year - 1900;
|
||||
t.tm_mon = tc.month - 1;
|
||||
t.tm_mday = tc.day;
|
||||
t.tm_hour = tc.hour;
|
||||
t.tm_min = tc.minute;
|
||||
@@ -112,7 +112,7 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv)
|
||||
PCF8563_Class rtc;
|
||||
rtc.begin();
|
||||
tm *t = localtime(&tv->tv_sec);
|
||||
rtc.setDateTime(t->tm_year + 1900, t->tm_mon + 1, t->tm_wday, t->tm_hour, t->tm_min, t->tm_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);
|
||||
}
|
||||
#elif defined(ARCH_ESP32)
|
||||
|
||||
@@ -57,7 +57,6 @@ namespace graphics
|
||||
|
||||
// This means the *visible* area (sh1106 can address 132, but shows 128 for example)
|
||||
#define IDLE_FRAMERATE 1 // in fps
|
||||
#define COMPASS_DIAM 44
|
||||
|
||||
// DEBUG
|
||||
#define NUM_EXTRA_FRAMES 3 // text message and debug frame
|
||||
@@ -86,7 +85,7 @@ static char ourId[5];
|
||||
GeoCoord geoCoord;
|
||||
|
||||
// OEM Config File
|
||||
static const char *oemConfigFile = "/prefs/oem.proto";
|
||||
static const char *oemConfigFile = "/oem/oem.proto";
|
||||
OEMStore oemStore;
|
||||
|
||||
#ifdef SHOW_REDRAWS
|
||||
@@ -98,7 +97,7 @@ static uint16_t displayWidth, displayHeight;
|
||||
#define SCREEN_WIDTH displayWidth
|
||||
#define SCREEN_HEIGHT displayHeight
|
||||
|
||||
#if defined(USE_EINK) || defined(ILI9341_DRIVER)
|
||||
#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
|
||||
@@ -117,6 +116,7 @@ static uint16_t displayWidth, displayHeight;
|
||||
|
||||
#define FONT_HEIGHT_SMALL fontHeight(FONT_SMALL)
|
||||
#define FONT_HEIGHT_MEDIUM fontHeight(FONT_MEDIUM)
|
||||
#define FONT_HEIGHT_LARGE fontHeight(FONT_LARGE)
|
||||
|
||||
#define getStringCenteredX(s) ((SCREEN_WIDTH - display->getStringWidth(s)) / 2)
|
||||
|
||||
@@ -522,6 +522,8 @@ static void drawGPSAltitude(OLEDDisplay *display, int16_t x, int16_t y, const GP
|
||||
} else {
|
||||
geoCoord.updateCoords(int32_t(gps->getLatitude()), int32_t(gps->getLongitude()), int32_t(gps->getAltitude()));
|
||||
displayLine = "Altitude: " + String(geoCoord.getAltitude()) + "m";
|
||||
if (config.display.units == Config_DisplayConfig_DisplayUnits_IMPERIAL)
|
||||
displayLine = "Altitude: " + String(geoCoord.getAltitude() * METERS_TO_FEET) + "ft";
|
||||
display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(displayLine))) / 2, y, displayLine);
|
||||
}
|
||||
}
|
||||
@@ -666,6 +668,26 @@ static bool hasPosition(NodeInfo *n)
|
||||
return n->has_position && (n->position.latitude_i != 0 || n->position.longitude_i != 0);
|
||||
}
|
||||
|
||||
static uint16_t getCompassDiam(OLEDDisplay *display)
|
||||
{
|
||||
uint16_t diam = 0;
|
||||
// get the smaller of the 2 dimensions and subtract 20
|
||||
if(display->getWidth() > display->getHeight()) {
|
||||
diam = display->getHeight();
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
return diam - 20;
|
||||
};
|
||||
|
||||
/// We will skip one node - the one for us, so we just blindly loop over all
|
||||
/// nodes
|
||||
static size_t nodeIndex;
|
||||
@@ -682,7 +704,7 @@ static void drawNodeHeading(OLEDDisplay *display, int16_t compassX, int16_t comp
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
arrowPoints[i]->rotate(headingRadian);
|
||||
arrowPoints[i]->scale(COMPASS_DIAM * 0.6);
|
||||
arrowPoints[i]->scale(getCompassDiam(display) * 0.6);
|
||||
arrowPoints[i]->translate(compassX, compassY);
|
||||
}
|
||||
drawLine(display, tip, tail);
|
||||
@@ -704,7 +726,7 @@ static void drawCompassNorth(OLEDDisplay *display, int16_t compassX, int16_t com
|
||||
for (int i = 0; i < 4; i++) {
|
||||
// North on compass will be negative of heading
|
||||
rosePoints[i]->rotate(-myHeading);
|
||||
rosePoints[i]->scale(COMPASS_DIAM);
|
||||
rosePoints[i]->scale(getCompassDiam(display));
|
||||
rosePoints[i]->translate(compassX, compassY);
|
||||
}
|
||||
drawLine(display, N1, N3);
|
||||
@@ -769,7 +791,7 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
|
||||
const char *fields[] = {username, distStr, signalStr, lastStr, NULL};
|
||||
|
||||
// coordinates for the center of the compass/circle
|
||||
int16_t compassX = x + SCREEN_WIDTH - COMPASS_DIAM / 2 - 5, compassY = y + SCREEN_HEIGHT / 2;
|
||||
int16_t compassX = x + SCREEN_WIDTH - getCompassDiam(display) / 2 - 5, compassY = y + SCREEN_HEIGHT / 2;
|
||||
bool hasNodeHeading = false;
|
||||
|
||||
if (ourNode && hasPosition(ourNode)) {
|
||||
@@ -783,10 +805,18 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
|
||||
Position &p = node->position;
|
||||
float d =
|
||||
GeoCoord::latLongToMeter(DegD(p.latitude_i), DegD(p.longitude_i), DegD(op.latitude_i), DegD(op.longitude_i));
|
||||
if (d < 2000)
|
||||
snprintf(distStr, sizeof(distStr), "%.0f m", d);
|
||||
else
|
||||
snprintf(distStr, sizeof(distStr), "%.1f km", d / 1000);
|
||||
|
||||
if (config.display.units == Config_DisplayConfig_DisplayUnits_IMPERIAL) {
|
||||
if (d < (2 * MILES_TO_FEET))
|
||||
snprintf(distStr, sizeof(distStr), "%.0f ft", d * METERS_TO_FEET);
|
||||
else
|
||||
snprintf(distStr, sizeof(distStr), "%.1f mi", d * METERS_TO_FEET / MILES_TO_FEET);
|
||||
} else {
|
||||
if (d < 2000)
|
||||
snprintf(distStr, sizeof(distStr), "%.0f m", d);
|
||||
else
|
||||
snprintf(distStr, sizeof(distStr), "%.1f km", d / 1000);
|
||||
}
|
||||
|
||||
float bearingToOther =
|
||||
GeoCoord::bearing(DegD(op.latitude_i), DegD(op.longitude_i), DegD(p.latitude_i), DegD(p.longitude_i));
|
||||
@@ -802,7 +832,7 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
|
||||
// Debug info for gps lock errors
|
||||
// DEBUG_MSG("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, COMPASS_DIAM / 2);
|
||||
display->drawCircle(compassX, compassY, getCompassDiam(display) / 2);
|
||||
|
||||
// Must be after distStr is populated
|
||||
drawColumns(display, x, y, fields);
|
||||
@@ -936,8 +966,12 @@ void Screen::setup()
|
||||
|
||||
#ifdef SCREEN_MIRROR
|
||||
dispdev.mirrorScreen();
|
||||
#elif defined(SCREEN_FLIP_VERTICALLY)
|
||||
dispdev.flipScreenVertically();
|
||||
#else
|
||||
// Standard behaviour is to FLIP the screen (needed on T-Beam). If this config item is set, unflip it, and thereby logically flip it.
|
||||
// If you have a headache now, you're welcome.
|
||||
if (!config.display.flip_screen) {
|
||||
dispdev.flipScreenVertically();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Get our hardware ID
|
||||
@@ -1071,7 +1105,6 @@ int32_t Screen::runOnce()
|
||||
// otherwise that breaks animations.
|
||||
if (targetFramerate != IDLE_FRAMERATE && ui.getUiState()->frameState == FIXED) {
|
||||
// oldFrameState = ui.getUiState()->frameState;
|
||||
DEBUG_MSG("Setting idle framerate\n");
|
||||
targetFramerate = IDLE_FRAMERATE;
|
||||
|
||||
ui.setTargetFPS(targetFramerate);
|
||||
@@ -1297,7 +1330,6 @@ void Screen::handleOnPress()
|
||||
// If we are in a transition, the press must have bounced, drop it.
|
||||
if (ui.getUiState()->frameState == FIXED) {
|
||||
ui.nextFrame();
|
||||
DEBUG_MSG("Setting LastScreenTransition\n");
|
||||
lastScreenTransition = millis();
|
||||
setFastFramerate();
|
||||
}
|
||||
@@ -1309,8 +1341,6 @@ void Screen::handleOnPress()
|
||||
|
||||
void Screen::setFastFramerate()
|
||||
{
|
||||
DEBUG_MSG("Setting fast framerate\n");
|
||||
|
||||
// We are about to start a transition so speed up fps
|
||||
targetFramerate = SCREEN_TRANSITION_FRAMERATE;
|
||||
|
||||
@@ -1635,6 +1665,9 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
|
||||
// adjust Brightness cycle trough 1 to 254 as long as attachDuringLongPress is true
|
||||
void Screen::adjustBrightness()
|
||||
{
|
||||
if (!useDisplay)
|
||||
return;
|
||||
|
||||
if (brightness == 254) {
|
||||
brightness = 0;
|
||||
} else {
|
||||
|
||||
@@ -57,6 +57,16 @@ class Screen
|
||||
#define BRIGHTNESS_DEFAULT 150
|
||||
#endif
|
||||
|
||||
// Meters to feet conversion
|
||||
#ifndef METERS_TO_FEET
|
||||
#define METERS_TO_FEET 3.28
|
||||
#endif
|
||||
|
||||
// Feet to miles conversion
|
||||
#ifndef MILES_TO_FEET
|
||||
#define MILES_TO_FEET 5280
|
||||
#endif
|
||||
|
||||
namespace graphics
|
||||
{
|
||||
|
||||
@@ -213,27 +223,29 @@ class Screen : public concurrency::OSThread
|
||||
LASTCHAR = ch;
|
||||
|
||||
switch (last) { // conversion depending on first UTF8-character
|
||||
case 0xC2: {
|
||||
SKIPREST = false;
|
||||
return (uint8_t)ch;
|
||||
}
|
||||
case 0xC3: {
|
||||
SKIPREST = false;
|
||||
return (uint8_t)(ch | 0xC0);
|
||||
}
|
||||
// map UTF-8 cyrillic chars to it Windows-1251 (CP-1251) ASCII codes
|
||||
// note: in this case we must use compatible font - provided ArialMT_Plain_10/16/24 by 'ThingPulse/esp8266-oled-ssd1306' library
|
||||
// have empty chars for non-latin ASCII symbols
|
||||
case 0xD0: {
|
||||
SKIPREST = false;
|
||||
if (ch == 129) return (uint8_t)(168); // Ё
|
||||
if (ch > 143 && ch < 192) return (uint8_t)(ch + 48);
|
||||
}
|
||||
case 0xD1: {
|
||||
SKIPREST = false;
|
||||
if (ch == 145) return (uint8_t)(184); // ё
|
||||
if (ch > 127 && ch < 144) return (uint8_t)(ch + 112);
|
||||
}
|
||||
case 0xC2: {
|
||||
SKIPREST = false;
|
||||
return (uint8_t)ch;
|
||||
}
|
||||
case 0xC3: {
|
||||
SKIPREST = false;
|
||||
return (uint8_t)(ch | 0xC0);
|
||||
}
|
||||
// map UTF-8 cyrillic chars to it Windows-1251 (CP-1251) ASCII codes
|
||||
// note: in this case we must use compatible font - provided ArialMT_Plain_10/16/24 by 'ThingPulse/esp8266-oled-ssd1306' library
|
||||
// have empty chars for non-latin ASCII symbols
|
||||
case 0xD0: {
|
||||
SKIPREST = false;
|
||||
if (ch == 129) return (uint8_t)(168); // Ё
|
||||
if (ch > 143 && ch < 192) return (uint8_t)(ch + 48);
|
||||
break;
|
||||
}
|
||||
case 0xD1: {
|
||||
SKIPREST = false;
|
||||
if (ch == 145) return (uint8_t)(184); // ё
|
||||
if (ch > 127 && ch < 144) return (uint8_t)(ch + 112);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// We want to strip out prefix chars for two-byte char formats
|
||||
|
||||
@@ -22,13 +22,23 @@ void TFTDisplay::display(void)
|
||||
{
|
||||
concurrency::LockGuard g(spiLock);
|
||||
|
||||
// FIXME - only draw bits have changed (use backbuf similar to the other displays)
|
||||
// tft.drawBitmap(0, 0, buffer, 128, 64, TFT_YELLOW, TFT_BLACK);
|
||||
for (uint16_t y = 0; y < displayHeight; y++) {
|
||||
for (uint16_t x = 0; x < displayWidth; x++) {
|
||||
uint16_t x,y;
|
||||
|
||||
for (y = 0; y < displayHeight; y++) {
|
||||
for (x = 0; x < displayWidth; x++) {
|
||||
// get src pixel in the page based ordering the OLED lib uses FIXME, super inefficent
|
||||
auto isset = buffer[x + (y / 8) * displayWidth] & (1 << (y & 7));
|
||||
tft.drawPixel(x, y, isset ? TFT_WHITE : TFT_BLACK);
|
||||
auto dblbuf_isset = buffer_back[x + (y / 8) * displayWidth] & (1 << (y & 7));
|
||||
if (isset != dblbuf_isset) {
|
||||
tft.drawPixel(x, y, isset ? TFT_WHITE : TFT_BLACK);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Copy the Buffer to the Back Buffer
|
||||
for (y = 0; y < (displayHeight / 8); y++) {
|
||||
for (x = 0; x < displayWidth; x++) {
|
||||
uint16_t pos = x + y * displayWidth;
|
||||
buffer_back[pos] = buffer[pos];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
#pragma once
|
||||
#include "Observer.h"
|
||||
|
||||
#define ANYKEY 0xFF
|
||||
#define MATRIXKEY 0xFE
|
||||
|
||||
typedef struct _InputEvent {
|
||||
const char* source;
|
||||
char inputEvent;
|
||||
char kbchar;
|
||||
} InputEvent;
|
||||
class InputBroker :
|
||||
public Observable<const InputEvent *>
|
||||
|
||||
@@ -16,6 +16,5 @@ void CardKbI2cImpl::init()
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_MSG("registerSource\n");
|
||||
inputBroker->registerSource(this);
|
||||
}
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
#include "facesKbI2cImpl.h"
|
||||
#include "InputBroker.h"
|
||||
|
||||
FacesKbI2cImpl *facesKbI2cImpl;
|
||||
|
||||
FacesKbI2cImpl::FacesKbI2cImpl() :
|
||||
KbI2cBase("facesKB")
|
||||
{
|
||||
}
|
||||
|
||||
void FacesKbI2cImpl::init()
|
||||
{
|
||||
if (faceskb_found != FACESKB_ADDR)
|
||||
{
|
||||
// Input device is not detected.
|
||||
return;
|
||||
}
|
||||
|
||||
inputBroker->registerSource(this);
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
#pragma once
|
||||
#include "kbI2cBase.h"
|
||||
#include "main.h"
|
||||
|
||||
/**
|
||||
* @brief The idea behind this class to have static methods for the event handlers.
|
||||
* Check attachInterrupt() at RotaryEncoderInteruptBase.cpp
|
||||
* Technically you can have as many rotary encoders hardver attached
|
||||
* to your device as you wish, but you always need to have separate event
|
||||
* handlers, thus you need to have a RotaryEncoderInterrupt implementation.
|
||||
*/
|
||||
class FacesKbI2cImpl :
|
||||
public KbI2cBase
|
||||
{
|
||||
public:
|
||||
FacesKbI2cImpl();
|
||||
void init();
|
||||
};
|
||||
|
||||
extern FacesKbI2cImpl *facesKbI2cImpl;
|
||||
@@ -3,49 +3,113 @@
|
||||
#include <Wire.h>
|
||||
|
||||
extern uint8_t cardkb_found;
|
||||
extern uint8_t kb_model;
|
||||
|
||||
KbI2cBase::KbI2cBase(const char *name) : concurrency::OSThread(name)
|
||||
{
|
||||
this->_originName = name;
|
||||
}
|
||||
|
||||
uint8_t read_from_14004(uint8_t reg, uint8_t *data, uint8_t length)
|
||||
{
|
||||
uint8_t readflag = 0;
|
||||
Wire.beginTransmission(CARDKB_ADDR);
|
||||
Wire.write(reg);
|
||||
Wire.endTransmission(); // stop transmitting
|
||||
delay(20);
|
||||
Wire.requestFrom(CARDKB_ADDR, (int)length);
|
||||
int i = 0;
|
||||
while ( Wire.available() ) // slave may send less than requested
|
||||
{
|
||||
data[i++] = Wire.read(); // receive a byte as a proper uint8_t
|
||||
readflag = 1;
|
||||
}
|
||||
return readflag;
|
||||
}
|
||||
|
||||
void write_to_14004(uint8_t reg, uint8_t data)
|
||||
{
|
||||
Wire.beginTransmission(CARDKB_ADDR);
|
||||
Wire.write(reg);
|
||||
Wire.write(data);
|
||||
Wire.endTransmission(); // stop transmitting
|
||||
}
|
||||
|
||||
int32_t KbI2cBase::runOnce()
|
||||
{
|
||||
InputEvent e;
|
||||
e.inputEvent = ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
|
||||
e.source = this->_originName;
|
||||
|
||||
Wire.requestFrom(CARDKB_ADDR, 1);
|
||||
|
||||
while (Wire.available()) {
|
||||
char c = Wire.read();
|
||||
switch (c) {
|
||||
case 0x1b: // ESC
|
||||
e.inputEvent = ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL;
|
||||
break;
|
||||
case 0x08: // Back
|
||||
e.inputEvent = ModuleConfig_CannedMessageConfig_InputEventChar_BACK;
|
||||
break;
|
||||
case 0xb5: // Up
|
||||
e.inputEvent = ModuleConfig_CannedMessageConfig_InputEventChar_UP;
|
||||
break;
|
||||
case 0xb6: // Down
|
||||
e.inputEvent = ModuleConfig_CannedMessageConfig_InputEventChar_DOWN;
|
||||
break;
|
||||
case 0xb4: // Left
|
||||
e.inputEvent = ModuleConfig_CannedMessageConfig_InputEventChar_LEFT;
|
||||
break;
|
||||
case 0xb7: // Right
|
||||
e.inputEvent = ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT;
|
||||
break;
|
||||
case 0x0d: // Enter
|
||||
e.inputEvent = ModuleConfig_CannedMessageConfig_InputEventChar_SELECT;
|
||||
break;
|
||||
}
|
||||
if (cardkb_found != CARDKB_ADDR){
|
||||
// Input device is not detected.
|
||||
return INT32_MAX;
|
||||
}
|
||||
|
||||
if (e.inputEvent != ModuleConfig_CannedMessageConfig_InputEventChar_NONE) {
|
||||
this->notifyObservers(&e);
|
||||
if (kb_model == 0x02) {
|
||||
// RAK14004
|
||||
uint8_t rDataBuf[8] = {0};
|
||||
uint8_t PrintDataBuf = 0;
|
||||
if (read_from_14004(0x01, rDataBuf, 0x04) == 1) {
|
||||
for (uint8_t aCount = 0; aCount < 0x04; aCount++) {
|
||||
for (uint8_t bCount = 0; bCount < 0x04; bCount++ ) {
|
||||
if (((rDataBuf[aCount] >> bCount) & 0x01) == 0x01) {
|
||||
PrintDataBuf = aCount * 0x04 + bCount + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (PrintDataBuf != 0) {
|
||||
DEBUG_MSG("RAK14004 key 0x%x pressed\n", PrintDataBuf);
|
||||
InputEvent e;
|
||||
e.inputEvent = MATRIXKEY;
|
||||
e.source = this->_originName;
|
||||
e.kbchar = PrintDataBuf;
|
||||
this->notifyObservers(&e);
|
||||
}
|
||||
} else {
|
||||
// m5 cardkb
|
||||
Wire.requestFrom(CARDKB_ADDR, 1);
|
||||
|
||||
while (Wire.available()) {
|
||||
char c = Wire.read();
|
||||
InputEvent e;
|
||||
e.inputEvent = ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
|
||||
e.source = this->_originName;
|
||||
switch (c) {
|
||||
case 0x1b: // ESC
|
||||
e.inputEvent = ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL;
|
||||
break;
|
||||
case 0x08: // Back
|
||||
e.inputEvent = ModuleConfig_CannedMessageConfig_InputEventChar_BACK;
|
||||
e.kbchar = c;
|
||||
break;
|
||||
case 0xb5: // Up
|
||||
e.inputEvent = ModuleConfig_CannedMessageConfig_InputEventChar_UP;
|
||||
break;
|
||||
case 0xb6: // Down
|
||||
e.inputEvent = ModuleConfig_CannedMessageConfig_InputEventChar_DOWN;
|
||||
break;
|
||||
case 0xb4: // Left
|
||||
e.inputEvent = ModuleConfig_CannedMessageConfig_InputEventChar_LEFT;
|
||||
e.kbchar = c;
|
||||
break;
|
||||
case 0xb7: // Right
|
||||
e.inputEvent = ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT;
|
||||
e.kbchar = c;
|
||||
break;
|
||||
case 0x0d: // Enter
|
||||
e.inputEvent = ModuleConfig_CannedMessageConfig_InputEventChar_SELECT;
|
||||
break;
|
||||
case 0x00: //nopress
|
||||
e.inputEvent = ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
|
||||
break;
|
||||
default: // all other keys
|
||||
e.inputEvent = ANYKEY;
|
||||
e.kbchar = c;
|
||||
break;
|
||||
}
|
||||
|
||||
if (e.inputEvent != ModuleConfig_CannedMessageConfig_InputEventChar_NONE) {
|
||||
this->notifyObservers(&e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 500;
|
||||
}
|
||||
|
||||
37
src/main.cpp
37
src/main.cpp
@@ -36,7 +36,7 @@
|
||||
#include "nimble/NimbleBluetooth.h"
|
||||
#endif
|
||||
|
||||
#if HAS_WIFI
|
||||
#if HAS_WIFI || defined(ARCH_PORTDUINO)
|
||||
#include "mesh/wifi/WiFiServerAPI.h"
|
||||
#include "mqtt/MQTT.h"
|
||||
#endif
|
||||
@@ -45,6 +45,9 @@
|
||||
#include "RF95Interface.h"
|
||||
#include "SX1262Interface.h"
|
||||
#include "SX1268Interface.h"
|
||||
#if !HAS_RADIO && defined(ARCH_PORTDUINO)
|
||||
#include "platform/portduino/SimRadio.h"
|
||||
#endif
|
||||
|
||||
#if HAS_BUTTON
|
||||
#include "ButtonThread.h"
|
||||
@@ -74,12 +77,15 @@ uint8_t cardkb_found;
|
||||
// 0x02 for RAK14004 and 0x00 for cardkb
|
||||
uint8_t kb_model;
|
||||
|
||||
// The I2C address of the Faces Keyboard (if found)
|
||||
uint8_t faceskb_found;
|
||||
|
||||
// The I2C address of the RTC Module (if found)
|
||||
uint8_t rtc_found;
|
||||
|
||||
// Keystore Chips
|
||||
uint8_t keystore_found;
|
||||
#ifndef ARCH_PORTDUINO
|
||||
ATECCX08A atecc;
|
||||
#endif
|
||||
|
||||
bool eink_found = true;
|
||||
|
||||
uint32_t serialSinceMsec;
|
||||
@@ -87,7 +93,7 @@ uint32_t serialSinceMsec;
|
||||
bool pmu_found;
|
||||
|
||||
// Array map of sensor types (as array index) and i2c address as value we'll find in the i2c scan
|
||||
uint8_t nodeTelemetrySensorsMap[TelemetrySensorType_LPS22+1] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
uint8_t nodeTelemetrySensorsMap[TelemetrySensorType_QMI8658+1] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
Router *router = NULL; // Users of router don't care what sort of subclass implements that API
|
||||
|
||||
@@ -157,9 +163,7 @@ void setup()
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_PORT
|
||||
if (!config.has_device || config.device.serial_enabled) {
|
||||
consoleInit(); // Set serial baud rate and init our mesh console
|
||||
}
|
||||
#endif
|
||||
|
||||
serialSinceMsec = millis();
|
||||
@@ -216,6 +220,10 @@ void setup()
|
||||
// router = new DSRRouter();
|
||||
router = new ReliableRouter();
|
||||
|
||||
#ifdef I2C_SDA1
|
||||
Wire1.begin(I2C_SDA1, I2C_SCL1);
|
||||
#endif
|
||||
|
||||
#ifdef I2C_SDA
|
||||
Wire.begin(I2C_SDA, I2C_SCL);
|
||||
#elif HAS_WIRE
|
||||
@@ -231,6 +239,7 @@ void setup()
|
||||
delay(1);
|
||||
#endif
|
||||
|
||||
// We need to scan here to decide if we have a screen for nodeDB.init()
|
||||
scanI2Cdevice();
|
||||
#ifdef RAK4630
|
||||
// scanEInkDevice();
|
||||
@@ -271,6 +280,14 @@ void setup()
|
||||
powerStatus->observe(&power->newStatus);
|
||||
power->setup(); // Must be after status handler is installed, so that handler gets notified of the initial configuration
|
||||
|
||||
/*
|
||||
* Repeat the scanning for I2C devices after power initialization.
|
||||
* Boards with an PMU need to be powered on to correctly scan to the device address, such as t-beam-s3-core
|
||||
*/
|
||||
if ((HW_VENDOR == HardwareModel_LILYGO_TBEAM_S3_CORE) || (HW_VENDOR == HardwareModel_TBEAM)) {
|
||||
scanI2Cdevice();
|
||||
}
|
||||
|
||||
// Init our SPI controller (must be before screen and lora)
|
||||
initSPI();
|
||||
#ifndef ARCH_ESP32
|
||||
@@ -324,7 +341,7 @@ void setup()
|
||||
DEBUG_MSG("GPS FactoryReset requested\n");
|
||||
if (gps->factoryReset()) { // If we don't succeed try again next time
|
||||
devicestate.did_gps_reset = true;
|
||||
nodeDB.saveToDisk();
|
||||
nodeDB.saveToDisk(SEGMENT_DEVICESTATE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -388,7 +405,7 @@ void setup()
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !HAS_RADIO
|
||||
#ifdef ARCH_PORTDUINO
|
||||
if (!rIf) {
|
||||
rIf = new SimRadio;
|
||||
if (!rIf->init()) {
|
||||
@@ -414,7 +431,7 @@ void setup()
|
||||
#endif
|
||||
|
||||
#ifdef ARCH_PORTDUINO
|
||||
initApiServer();
|
||||
initApiServer(TCPPort);
|
||||
#endif
|
||||
|
||||
// Start airtime logger thread.
|
||||
|
||||
13
src/main.h
13
src/main.h
@@ -6,20 +6,29 @@
|
||||
#include "PowerStatus.h"
|
||||
#include "graphics/Screen.h"
|
||||
#include "mesh/generated/telemetry.pb.h"
|
||||
#ifndef ARCH_PORTDUINO
|
||||
#include <SparkFun_ATECCX08a_Arduino_Library.h>
|
||||
#endif
|
||||
|
||||
extern uint8_t screen_found;
|
||||
extern uint8_t screen_model;
|
||||
extern uint8_t cardkb_found;
|
||||
extern uint8_t kb_model;
|
||||
extern uint8_t faceskb_found;
|
||||
extern uint8_t rtc_found;
|
||||
extern uint8_t keystore_found;
|
||||
|
||||
extern bool eink_found;
|
||||
extern bool pmu_found;
|
||||
extern bool isCharging;
|
||||
extern bool isUSBPowered;
|
||||
|
||||
extern uint8_t nodeTelemetrySensorsMap[TelemetrySensorType_LPS22+1];
|
||||
#ifndef ARCH_PORTDUINO
|
||||
extern ATECCX08A atecc;
|
||||
#endif
|
||||
|
||||
extern uint8_t nodeTelemetrySensorsMap[TelemetrySensorType_QMI8658+1];
|
||||
|
||||
extern int TCPPort; // set by Portduino
|
||||
|
||||
// Global Screen singleton.
|
||||
extern graphics::Screen *screen;
|
||||
|
||||
@@ -112,7 +112,7 @@ void MeshModule::callPlugins(const MeshPacket &mp, RxSource src)
|
||||
bool rxChannelOk = !pi.boundChannel || (mp.from == 0) ||
|
||||
!ch ||
|
||||
strlen(ch->settings.name) > 0 ||
|
||||
strcmp(ch->settings.name, pi.boundChannel);
|
||||
(strcasecmp(ch->settings.name, pi.boundChannel) == 0);
|
||||
|
||||
if (!rxChannelOk) {
|
||||
// no one should have already replied!
|
||||
|
||||
@@ -90,7 +90,7 @@ void MeshService::loop()
|
||||
}
|
||||
|
||||
/// The radioConfig object just changed, call this to force the hw to change to the new settings
|
||||
bool MeshService::reloadConfig()
|
||||
bool MeshService::reloadConfig(int saveWhat)
|
||||
{
|
||||
// If we can successfully set this radio to these settings, save them to disk
|
||||
|
||||
@@ -98,7 +98,7 @@ bool MeshService::reloadConfig()
|
||||
bool didReset = nodeDB.resetRadioConfig(); // Don't let the phone send us fatally bad settings
|
||||
|
||||
configChanged.notifyObservers(NULL); // This will cause radio hardware to change freqs etc
|
||||
nodeDB.saveToDisk();
|
||||
nodeDB.saveToDisk(saveWhat);
|
||||
|
||||
return didReset;
|
||||
}
|
||||
@@ -113,7 +113,7 @@ void MeshService::reloadOwner()
|
||||
// update everyone else
|
||||
if (nodeInfoModule)
|
||||
nodeInfoModule->sendOurNodeInfo();
|
||||
nodeDB.saveToDisk();
|
||||
nodeDB.saveToDisk(SEGMENT_DEVICESTATE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -123,6 +123,29 @@ void MeshService::reloadOwner()
|
||||
*/
|
||||
void MeshService::handleToRadio(MeshPacket &p)
|
||||
{
|
||||
#ifdef ARCH_PORTDUINO
|
||||
// Simulates device is receiving a packet via the LoRa chip
|
||||
if (p.decoded.portnum == PortNum_SIMULATOR_APP) {
|
||||
// Simulator packet (=Compressed packet) is encapsulated in a MeshPacket, so need to unwrap first
|
||||
Compressed scratch;
|
||||
Compressed *decoded = NULL;
|
||||
if (p.which_payload_variant == MeshPacket_decoded_tag) {
|
||||
memset(&scratch, 0, sizeof(scratch));
|
||||
p.decoded.payload.size = pb_decode_from_bytes(p.decoded.payload.bytes, p.decoded.payload.size, &Compressed_msg, &scratch);
|
||||
if (p.decoded.payload.size) {
|
||||
decoded = &scratch;
|
||||
// Extract the original payload and replace
|
||||
memcpy(&p.decoded.payload, &decoded->data, sizeof(decoded->data));
|
||||
// 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");
|
||||
}
|
||||
// Let SimRadio receive as if it did via its LoRa chip
|
||||
SimRadio::instance->startReceive(&p);
|
||||
return;
|
||||
}
|
||||
#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");
|
||||
p.from = 0;
|
||||
|
||||
@@ -10,6 +10,9 @@
|
||||
#include "MeshTypes.h"
|
||||
#include "Observer.h"
|
||||
#include "PointerQueue.h"
|
||||
#ifdef ARCH_PORTDUINO
|
||||
#include "../platform/portduino/SimRadio.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Top level app for this service. keeps the mesh, the radio config and the queue of received packets.
|
||||
@@ -63,7 +66,7 @@ class MeshService
|
||||
/** The radioConfig object just changed, call this to force the hw to change to the new settings
|
||||
* @return true if client devices should be sent a new set of radio configs
|
||||
*/
|
||||
bool reloadConfig();
|
||||
bool reloadConfig(int saveWhat=SEGMENT_CONFIG | SEGMENT_MODULECONFIG | SEGMENT_DEVICESTATE | SEGMENT_CHANNELS);
|
||||
|
||||
/// The owner User record just got updated, update our node DB and broadcast the info into the mesh
|
||||
void reloadOwner();
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "mesh-pb-constants.h"
|
||||
#include <pb_decode.h>
|
||||
#include <pb_encode.h>
|
||||
#include <ErriezCRC32.h>
|
||||
|
||||
#ifdef ARCH_ESP32
|
||||
#include "mesh/http/WiFiAPClient.h"
|
||||
@@ -128,7 +129,7 @@ bool NodeDB::factoryReset()
|
||||
// second, install default state (this will deal with the duplicate mac address issue)
|
||||
installDefaultDeviceState();
|
||||
installDefaultConfig();
|
||||
// third, write to disk
|
||||
// third, write everything to disk
|
||||
saveToDisk();
|
||||
#ifdef ARCH_ESP32
|
||||
// This will erase what's in NVS including ssl keys, persistant variables and ble pairing
|
||||
@@ -225,13 +226,20 @@ void NodeDB::installDefaultChannels()
|
||||
channelFile.version = DEVICESTATE_CUR_VER;
|
||||
}
|
||||
|
||||
void NodeDB::resetNodes()
|
||||
{
|
||||
devicestate.node_db_count = 0;
|
||||
memset(devicestate.node_db, 0, sizeof(devicestate.node_db));
|
||||
saveDeviceStateToDisk();
|
||||
}
|
||||
|
||||
void NodeDB::installDefaultDeviceState()
|
||||
{
|
||||
DEBUG_MSG("Installing default DeviceState\n");
|
||||
memset(&devicestate, 0, sizeof(DeviceState));
|
||||
|
||||
*numNodes = 0; // Forget node DB
|
||||
|
||||
*numNodes = 0;
|
||||
|
||||
// init our devicestate with valid flags so protobuf writing/reading will work
|
||||
devicestate.has_my_node = true;
|
||||
devicestate.has_owner = true;
|
||||
@@ -261,6 +269,12 @@ void NodeDB::init()
|
||||
DEBUG_MSG("Initializing NodeDB\n");
|
||||
loadFromDisk();
|
||||
|
||||
uint32_t devicestateCRC = crc32Buffer(&devicestate, sizeof(devicestate));
|
||||
uint32_t configCRC = crc32Buffer(&config, sizeof(config));
|
||||
uint32_t channelFileCRC = crc32Buffer(&channelFile, sizeof(channelFile));
|
||||
|
||||
int saveWhat = 0;
|
||||
|
||||
myNodeInfo.max_channels = MAX_NUM_CHANNELS; // tell others the max # of channels we can understand
|
||||
|
||||
myNodeInfo.error_code = CriticalErrorCode_NONE; // For the error code, only show values from this boot (discard value from flash)
|
||||
@@ -298,7 +312,15 @@ void NodeDB::init()
|
||||
|
||||
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);
|
||||
saveToDisk();
|
||||
|
||||
if (devicestateCRC != crc32Buffer(&devicestate, sizeof(devicestate)))
|
||||
saveWhat |= SEGMENT_DEVICESTATE;
|
||||
if (configCRC != crc32Buffer(&config, sizeof(config)))
|
||||
saveWhat |= SEGMENT_CONFIG;
|
||||
if (channelFileCRC != crc32Buffer(&channelFile, sizeof(channelFile)))
|
||||
saveWhat |= SEGMENT_CHANNELS;
|
||||
|
||||
saveToDisk(saveWhat);
|
||||
}
|
||||
|
||||
// We reserve a few nodenums for future use
|
||||
@@ -431,7 +453,6 @@ bool saveProto(const char *filename, size_t protoSize, size_t objSize, const pb_
|
||||
} else {
|
||||
okay = true;
|
||||
}
|
||||
|
||||
f.close();
|
||||
|
||||
// brief window of risk here ;-)
|
||||
@@ -454,7 +475,7 @@ void NodeDB::saveChannelsToDisk()
|
||||
#ifdef FSCom
|
||||
FSCom.mkdir("/prefs");
|
||||
#endif
|
||||
saveProto(channelFileName, ChannelFile_size, sizeof(ChannelFile), ChannelFile_fields, &channelFile);
|
||||
saveProto(channelFileName, ChannelFile_size, sizeof(channelFile), ChannelFile_fields, &channelFile);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -468,34 +489,41 @@ void NodeDB::saveDeviceStateToDisk()
|
||||
}
|
||||
}
|
||||
|
||||
void NodeDB::saveToDisk()
|
||||
void NodeDB::saveToDisk(int saveWhat)
|
||||
{
|
||||
if (!devicestate.no_save) {
|
||||
#ifdef FSCom
|
||||
FSCom.mkdir("/prefs");
|
||||
#endif
|
||||
saveProto(prefFileName, DeviceState_size, sizeof(devicestate), DeviceState_fields, &devicestate);
|
||||
if (saveWhat & SEGMENT_DEVICESTATE) {
|
||||
saveDeviceStateToDisk();
|
||||
}
|
||||
|
||||
// save all config segments
|
||||
config.has_device = true;
|
||||
config.has_display = true;
|
||||
config.has_lora = true;
|
||||
config.has_position = true;
|
||||
config.has_power = true;
|
||||
config.has_network = true;
|
||||
config.has_bluetooth = true;
|
||||
saveProto(configFileName, LocalConfig_size, sizeof(LocalConfig), LocalConfig_fields, &config);
|
||||
if (saveWhat & SEGMENT_CONFIG) {
|
||||
config.has_device = true;
|
||||
config.has_display = true;
|
||||
config.has_lora = true;
|
||||
config.has_position = true;
|
||||
config.has_power = true;
|
||||
config.has_network = true;
|
||||
config.has_bluetooth = true;
|
||||
saveProto(configFileName, LocalConfig_size, sizeof(config), LocalConfig_fields, &config);
|
||||
}
|
||||
|
||||
moduleConfig.has_canned_message = true;
|
||||
moduleConfig.has_external_notification = true;
|
||||
moduleConfig.has_mqtt = true;
|
||||
moduleConfig.has_range_test = true;
|
||||
moduleConfig.has_serial = true;
|
||||
moduleConfig.has_store_forward = true;
|
||||
moduleConfig.has_telemetry = true;
|
||||
saveProto(moduleConfigFileName, LocalModuleConfig_size, sizeof(LocalModuleConfig), LocalModuleConfig_fields, &moduleConfig);
|
||||
if (saveWhat & SEGMENT_MODULECONFIG) {
|
||||
moduleConfig.has_canned_message = true;
|
||||
moduleConfig.has_external_notification = true;
|
||||
moduleConfig.has_mqtt = true;
|
||||
moduleConfig.has_range_test = true;
|
||||
moduleConfig.has_serial = true;
|
||||
moduleConfig.has_store_forward = true;
|
||||
moduleConfig.has_telemetry = true;
|
||||
saveProto(moduleConfigFileName, LocalModuleConfig_size, sizeof(moduleConfig), LocalModuleConfig_fields, &moduleConfig);
|
||||
}
|
||||
|
||||
saveChannelsToDisk();
|
||||
if (saveWhat & SEGMENT_CHANNELS) {
|
||||
saveChannelsToDisk();
|
||||
}
|
||||
} else {
|
||||
DEBUG_MSG("***** DEVELOPMENT MODE - DO NOT RELEASE - not saving to flash *****\n");
|
||||
}
|
||||
@@ -671,11 +699,23 @@ NodeInfo *NodeDB::getOrCreateNode(NodeNum n)
|
||||
|
||||
if (!info) {
|
||||
if (*numNodes >= MAX_NUM_NODES) {
|
||||
screen->print("error: node_db full!\n");
|
||||
DEBUG_MSG("ERROR! could not create new node, node_db is full! (%d nodes)", *numNodes);
|
||||
return NULL;
|
||||
screen->print("warning: node_db full! erasing oldest entry\n");
|
||||
// look for oldest node and erase it
|
||||
uint32_t oldest = UINT32_MAX;
|
||||
int oldestIndex = -1;
|
||||
for (int i = 0; i < *numNodes; i++) {
|
||||
if (nodes[i].last_heard < oldest) {
|
||||
oldest = nodes[i].last_heard;
|
||||
oldestIndex = i;
|
||||
}
|
||||
}
|
||||
// Shove the remaining nodes down the chain
|
||||
for (int i = oldestIndex; i < *numNodes - 1; i++) {
|
||||
nodes[i] = nodes[i + 1];
|
||||
}
|
||||
(*numNodes)--;
|
||||
}
|
||||
// add the node
|
||||
// add the node at the end
|
||||
info = &nodes[(*numNodes)++];
|
||||
|
||||
// everything is missing except the nodenum
|
||||
|
||||
@@ -13,7 +13,12 @@ DeviceState versions used to be defined in the .proto file but really only this
|
||||
#define here.
|
||||
*/
|
||||
|
||||
#define DEVICESTATE_CUR_VER 18
|
||||
#define SEGMENT_CONFIG 1
|
||||
#define SEGMENT_MODULECONFIG 2
|
||||
#define SEGMENT_DEVICESTATE 4
|
||||
#define SEGMENT_CHANNELS 8
|
||||
|
||||
#define DEVICESTATE_CUR_VER 19
|
||||
#define DEVICESTATE_MIN_VER DEVICESTATE_CUR_VER
|
||||
|
||||
extern DeviceState devicestate;
|
||||
@@ -52,7 +57,7 @@ class NodeDB
|
||||
void init();
|
||||
|
||||
/// write to flash
|
||||
void saveToDisk(), saveChannelsToDisk(), saveDeviceStateToDisk();
|
||||
void saveToDisk(int saveWhat=SEGMENT_CONFIG | SEGMENT_MODULECONFIG | SEGMENT_DEVICESTATE | SEGMENT_CHANNELS), saveChannelsToDisk(), saveDeviceStateToDisk();
|
||||
|
||||
/** Reinit radio config if needed, because either:
|
||||
* a) sometimes a buggy android app might send us bogus settings or
|
||||
@@ -115,7 +120,7 @@ class NodeDB
|
||||
/// Return the number of nodes we've heard from recently (within the last 2 hrs?)
|
||||
size_t getNumOnlineNodes();
|
||||
|
||||
void initConfigIntervals(), initModuleConfigIntervals();
|
||||
void initConfigIntervals(), initModuleConfigIntervals(), resetNodes();
|
||||
|
||||
bool factoryReset();
|
||||
|
||||
@@ -205,4 +210,4 @@ inline uint32_t getConfiguredOrDefaultMs(uint32_t configuredInterval, uint32_t d
|
||||
*/
|
||||
extern uint32_t radioGeneration;
|
||||
|
||||
#define Module_Config_size (ModuleConfig_CannedMessageConfig_size + ModuleConfig_ExternalNotificationConfig_size + ModuleConfig_MQTTConfig_size + ModuleConfig_RangeTestConfig_size + ModuleConfig_SerialConfig_size + ModuleConfig_StoreForwardConfig_size + ModuleConfig_TelemetryConfig_size + ModuleConfig_size)
|
||||
#define Module_Config_size (ModuleConfig_CannedMessageConfig_size + ModuleConfig_ExternalNotificationConfig_size + ModuleConfig_MQTTConfig_size + ModuleConfig_RangeTestConfig_size + ModuleConfig_SerialConfig_size + ModuleConfig_StoreForwardConfig_size + ModuleConfig_TelemetryConfig_size + ModuleConfig_size)
|
||||
|
||||
@@ -79,17 +79,17 @@ bool PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
|
||||
memset(&toRadioScratch, 0, sizeof(toRadioScratch));
|
||||
if (pb_decode_from_bytes(buf, bufLength, ToRadio_fields, &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);
|
||||
handleStartConfig();
|
||||
break;
|
||||
case ToRadio_disconnect_tag:
|
||||
DEBUG_MSG("Disconnecting from phone\n");
|
||||
close();
|
||||
break;
|
||||
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);
|
||||
handleStartConfig();
|
||||
break;
|
||||
case ToRadio_disconnect_tag:
|
||||
DEBUG_MSG("Disconnecting from phone\n");
|
||||
close();
|
||||
break;
|
||||
default:
|
||||
// Ignore nop messages
|
||||
// DEBUG_MSG("Error: unexpected ToRadio variant\n");
|
||||
@@ -109,15 +109,17 @@ bool PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
|
||||
*
|
||||
* Our sending states progress in the following sequence (the client app ASSUMES THIS SEQUENCE, DO NOT CHANGE IT):
|
||||
* STATE_SEND_MY_INFO, // send our my info record
|
||||
* STATE_SEND_CHANNELS
|
||||
* STATE_SEND_NODEINFO, // states progress in this order as the device sends to the client
|
||||
STATE_SEND_CONFIG,
|
||||
STATE_SEND_MODULE_CONFIG,
|
||||
STATE_SEND_COMPLETE_ID,
|
||||
STATE_SEND_PACKETS // send packets or debug strings
|
||||
*/
|
||||
size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
{
|
||||
if (!available()) {
|
||||
DEBUG_MSG("getFromRadio=not available\n");
|
||||
// DEBUG_MSG("getFromRadio=not available\n");
|
||||
return 0;
|
||||
}
|
||||
// In case we send a FromRadio packet
|
||||
@@ -128,7 +130,7 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
case STATE_SEND_NOTHING:
|
||||
DEBUG_MSG("getFromRadio=STATE_SEND_NOTHING\n");
|
||||
break;
|
||||
|
||||
|
||||
case STATE_SEND_MY_INFO:
|
||||
DEBUG_MSG("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
|
||||
@@ -154,51 +156,63 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
// Stay in current state until done sending nodeinfos
|
||||
} else {
|
||||
DEBUG_MSG("Done sending nodeinfos\n");
|
||||
state = STATE_SEND_CONFIG;
|
||||
state = STATE_SEND_CHANNELS;
|
||||
// Go ahead and send that ID right now
|
||||
return getFromRadio(buf);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case STATE_SEND_CHANNELS:
|
||||
DEBUG_MSG("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;
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_SEND_CONFIG:
|
||||
DEBUG_MSG("getFromRadio=STATE_SEND_CONFIG\n");
|
||||
fromRadioScratch.which_payload_variant = FromRadio_config_tag;
|
||||
switch (config_state) {
|
||||
case Config_device_tag:
|
||||
fromRadioScratch.config.which_payload_variant = Config_device_tag;
|
||||
fromRadioScratch.config.payload_variant.device = config.device;
|
||||
break;
|
||||
case Config_position_tag:
|
||||
fromRadioScratch.config.which_payload_variant = Config_position_tag;
|
||||
fromRadioScratch.config.payload_variant.position = config.position;
|
||||
break;
|
||||
case Config_power_tag:
|
||||
fromRadioScratch.config.which_payload_variant = Config_power_tag;
|
||||
fromRadioScratch.config.payload_variant.power = config.power;
|
||||
fromRadioScratch.config.payload_variant.power.ls_secs = default_ls_secs;
|
||||
break;
|
||||
case Config_network_tag:
|
||||
fromRadioScratch.config.which_payload_variant = Config_network_tag;
|
||||
fromRadioScratch.config.payload_variant.network = config.network;
|
||||
break;
|
||||
case Config_display_tag:
|
||||
fromRadioScratch.config.which_payload_variant = Config_display_tag;
|
||||
fromRadioScratch.config.payload_variant.display = config.display;
|
||||
break;
|
||||
case Config_lora_tag:
|
||||
fromRadioScratch.config.which_payload_variant = Config_lora_tag;
|
||||
fromRadioScratch.config.payload_variant.lora = config.lora;
|
||||
break;
|
||||
case Config_bluetooth_tag:
|
||||
fromRadioScratch.config.which_payload_variant = Config_bluetooth_tag;
|
||||
fromRadioScratch.config.payload_variant.bluetooth = config.bluetooth;
|
||||
break;
|
||||
case Config_device_tag:
|
||||
fromRadioScratch.config.which_payload_variant = Config_device_tag;
|
||||
fromRadioScratch.config.payload_variant.device = config.device;
|
||||
break;
|
||||
case Config_position_tag:
|
||||
fromRadioScratch.config.which_payload_variant = Config_position_tag;
|
||||
fromRadioScratch.config.payload_variant.position = config.position;
|
||||
break;
|
||||
case Config_power_tag:
|
||||
fromRadioScratch.config.which_payload_variant = Config_power_tag;
|
||||
fromRadioScratch.config.payload_variant.power = config.power;
|
||||
fromRadioScratch.config.payload_variant.power.ls_secs = default_ls_secs;
|
||||
break;
|
||||
case Config_network_tag:
|
||||
fromRadioScratch.config.which_payload_variant = Config_network_tag;
|
||||
fromRadioScratch.config.payload_variant.network = config.network;
|
||||
break;
|
||||
case Config_display_tag:
|
||||
fromRadioScratch.config.which_payload_variant = Config_display_tag;
|
||||
fromRadioScratch.config.payload_variant.display = config.display;
|
||||
break;
|
||||
case Config_lora_tag:
|
||||
fromRadioScratch.config.which_payload_variant = Config_lora_tag;
|
||||
fromRadioScratch.config.payload_variant.lora = config.lora;
|
||||
break;
|
||||
case Config_bluetooth_tag:
|
||||
fromRadioScratch.config.which_payload_variant = Config_bluetooth_tag;
|
||||
fromRadioScratch.config.payload_variant.bluetooth = config.bluetooth;
|
||||
break;
|
||||
}
|
||||
// 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
|
||||
// using to the app (so that even old phone apps work with new device loads).
|
||||
|
||||
|
||||
config_state++;
|
||||
// Advance when we have sent all of our config objects
|
||||
if (config_state > Config_bluetooth_tag) {
|
||||
@@ -211,37 +225,37 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
DEBUG_MSG("getFromRadio=STATE_SEND_MODULECONFIG\n");
|
||||
fromRadioScratch.which_payload_variant = FromRadio_moduleConfig_tag;
|
||||
switch (config_state) {
|
||||
case ModuleConfig_mqtt_tag:
|
||||
fromRadioScratch.moduleConfig.which_payload_variant = ModuleConfig_mqtt_tag;
|
||||
fromRadioScratch.moduleConfig.payload_variant.mqtt = moduleConfig.mqtt;
|
||||
break;
|
||||
case ModuleConfig_serial_tag:
|
||||
fromRadioScratch.moduleConfig.which_payload_variant = ModuleConfig_serial_tag;
|
||||
fromRadioScratch.moduleConfig.payload_variant.serial = moduleConfig.serial;
|
||||
break;
|
||||
case ModuleConfig_external_notification_tag:
|
||||
fromRadioScratch.moduleConfig.which_payload_variant = ModuleConfig_external_notification_tag;
|
||||
fromRadioScratch.moduleConfig.payload_variant.external_notification = moduleConfig.external_notification;
|
||||
break;
|
||||
case ModuleConfig_range_test_tag:
|
||||
fromRadioScratch.moduleConfig.which_payload_variant = ModuleConfig_range_test_tag;
|
||||
fromRadioScratch.moduleConfig.payload_variant.range_test = moduleConfig.range_test;
|
||||
break;
|
||||
case ModuleConfig_telemetry_tag:
|
||||
fromRadioScratch.moduleConfig.which_payload_variant = ModuleConfig_telemetry_tag;
|
||||
fromRadioScratch.moduleConfig.payload_variant.telemetry = moduleConfig.telemetry;
|
||||
break;
|
||||
case ModuleConfig_canned_message_tag:
|
||||
fromRadioScratch.moduleConfig.which_payload_variant = ModuleConfig_canned_message_tag;
|
||||
fromRadioScratch.moduleConfig.payload_variant.canned_message = moduleConfig.canned_message;
|
||||
break;
|
||||
case ModuleConfig_mqtt_tag:
|
||||
fromRadioScratch.moduleConfig.which_payload_variant = ModuleConfig_mqtt_tag;
|
||||
fromRadioScratch.moduleConfig.payload_variant.mqtt = moduleConfig.mqtt;
|
||||
break;
|
||||
case ModuleConfig_serial_tag:
|
||||
fromRadioScratch.moduleConfig.which_payload_variant = ModuleConfig_serial_tag;
|
||||
fromRadioScratch.moduleConfig.payload_variant.serial = moduleConfig.serial;
|
||||
break;
|
||||
case ModuleConfig_external_notification_tag:
|
||||
fromRadioScratch.moduleConfig.which_payload_variant = ModuleConfig_external_notification_tag;
|
||||
fromRadioScratch.moduleConfig.payload_variant.external_notification = moduleConfig.external_notification;
|
||||
break;
|
||||
case ModuleConfig_range_test_tag:
|
||||
fromRadioScratch.moduleConfig.which_payload_variant = ModuleConfig_range_test_tag;
|
||||
fromRadioScratch.moduleConfig.payload_variant.range_test = moduleConfig.range_test;
|
||||
break;
|
||||
case ModuleConfig_telemetry_tag:
|
||||
fromRadioScratch.moduleConfig.which_payload_variant = ModuleConfig_telemetry_tag;
|
||||
fromRadioScratch.moduleConfig.payload_variant.telemetry = moduleConfig.telemetry;
|
||||
break;
|
||||
case ModuleConfig_canned_message_tag:
|
||||
fromRadioScratch.moduleConfig.which_payload_variant = ModuleConfig_canned_message_tag;
|
||||
fromRadioScratch.moduleConfig.payload_variant.canned_message = moduleConfig.canned_message;
|
||||
break;
|
||||
}
|
||||
|
||||
config_state++;
|
||||
// Advance when we have sent all of our ModuleConfig objects
|
||||
if (config_state > ModuleConfig_canned_message_tag) {
|
||||
state = STATE_SEND_COMPLETE_ID;
|
||||
config_state = Config_device_tag;
|
||||
config_state = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -274,7 +288,8 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
if (fromRadioScratch.which_payload_variant != 0) {
|
||||
// Encapsulate as a FromRadio packet
|
||||
size_t numbytes = pb_encode_to_bytes(buf, FromRadio_size, FromRadio_fields, &fromRadioScratch);
|
||||
// DEBUG_MSG("encoding toPhone packet to phone variant=%d, %d bytes\n", fromRadioScratch.which_payloadVariant, numbytes);
|
||||
|
||||
DEBUG_MSG("encoding toPhone packet to phone variant=%d, %d bytes\n", fromRadioScratch.which_payload_variant, numbytes);
|
||||
return numbytes;
|
||||
}
|
||||
|
||||
@@ -282,7 +297,7 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PhoneAPI::handleDisconnect()
|
||||
void PhoneAPI::handleDisconnect()
|
||||
{
|
||||
DEBUG_MSG("PhoneAPI disconnect\n");
|
||||
}
|
||||
@@ -301,26 +316,25 @@ void PhoneAPI::releasePhonePacket()
|
||||
bool PhoneAPI::available()
|
||||
{
|
||||
switch (state) {
|
||||
case STATE_SEND_NOTHING:
|
||||
return false;
|
||||
case STATE_SEND_MY_INFO:
|
||||
return true;
|
||||
case STATE_SEND_CONFIG:
|
||||
return true;
|
||||
case STATE_SEND_MODULECONFIG:
|
||||
return true;
|
||||
case STATE_SEND_NODEINFO:
|
||||
if (!nodeInfoForPhone)
|
||||
nodeInfoForPhone = nodeDB.readNextInfo();
|
||||
return true; // Always say we have something, because we might need to advance our state machine
|
||||
case STATE_SEND_COMPLETE_ID:
|
||||
return true;
|
||||
case STATE_SEND_PACKETS: {
|
||||
if (!packetForPhone)
|
||||
packetForPhone = service.getForPhone();
|
||||
bool hasPacket = !!packetForPhone;
|
||||
DEBUG_MSG("available hasPacket=%d\n", hasPacket);
|
||||
return hasPacket;
|
||||
case STATE_SEND_NOTHING:
|
||||
return false;
|
||||
case STATE_SEND_MY_INFO:
|
||||
case STATE_SEND_CHANNELS:
|
||||
case STATE_SEND_CONFIG:
|
||||
case STATE_SEND_MODULECONFIG:
|
||||
case STATE_SEND_COMPLETE_ID:
|
||||
return true;
|
||||
case STATE_SEND_NODEINFO:
|
||||
if (!nodeInfoForPhone)
|
||||
nodeInfoForPhone = nodeDB.readNextInfo();
|
||||
return true; // Always say we have something, because we might need to advance our state machine
|
||||
|
||||
case STATE_SEND_PACKETS: {
|
||||
if (!packetForPhone)
|
||||
packetForPhone = service.getForPhone();
|
||||
bool hasPacket = !!packetForPhone;
|
||||
// DEBUG_MSG("available hasPacket=%d\n", hasPacket);
|
||||
return hasPacket;
|
||||
}
|
||||
default:
|
||||
assert(0); // unexpected state - FIXME, make an error code and reboot
|
||||
|
||||
@@ -16,13 +16,13 @@
|
||||
* Eventually there should be once instance of this class for each live connection (because it has a bit of state
|
||||
* for that connection)
|
||||
*/
|
||||
class PhoneAPI
|
||||
: public Observer<uint32_t> // FIXME, we shouldn't be inheriting from Observer, instead use CallbackObserver as a member
|
||||
class PhoneAPI : public Observer<uint32_t> // FIXME, we shouldn't be inheriting from Observer, instead use CallbackObserver as a member
|
||||
{
|
||||
enum State {
|
||||
STATE_SEND_NOTHING, // Initial state, don't send anything until the client starts asking for config
|
||||
STATE_SEND_MY_INFO, // send our my info record
|
||||
STATE_SEND_NODEINFO, // states progress in this order as the device sends to to the client
|
||||
STATE_SEND_CHANNELS, // Send all channels
|
||||
STATE_SEND_CONFIG, // Replacement for the old Radioconfig
|
||||
STATE_SEND_MODULECONFIG, // Send Module specific config
|
||||
STATE_SEND_COMPLETE_ID,
|
||||
@@ -31,7 +31,7 @@ class PhoneAPI
|
||||
|
||||
State state = STATE_SEND_NOTHING;
|
||||
|
||||
int8_t config_state = Config_device_tag;
|
||||
uint8_t config_state = 0;
|
||||
|
||||
/**
|
||||
* Each packet sent to the phone has an incrementing count
|
||||
|
||||
@@ -354,7 +354,6 @@ void RadioInterface::applyModemConfig()
|
||||
// Set up default configuration
|
||||
// No Sync Words in LORA mode
|
||||
Config_LoRaConfig &loraConfig = config.lora;
|
||||
auto channelSettings = channels.getPrimary();
|
||||
if (loraConfig.spread_factor == 0) {
|
||||
switch (loraConfig.modem_preset) {
|
||||
case Config_LoRaConfig_ModemPreset_SHORT_FAST:
|
||||
@@ -423,7 +422,7 @@ void RadioInterface::applyModemConfig()
|
||||
|
||||
// If user has manually specified a channel num, then use that, otherwise generate one by hashing the name
|
||||
const char *channelName = channels.getName(channels.getPrimaryIndex());
|
||||
int channel_num = channelSettings.channel_num ? channelSettings.channel_num - 1 : hash(channelName) % numChannels;
|
||||
int channel_num = (loraConfig.channel_num ? loraConfig.channel_num - 1 : hash(channelName)) % numChannels;
|
||||
|
||||
// Old frequency selection formula
|
||||
// float freq = myRegion->freqStart + ((((myRegion->freqEnd - myRegion->freqStart) / numChannels) / 2) * channel_num);
|
||||
@@ -461,12 +460,6 @@ void RadioInterface::limitPower()
|
||||
DEBUG_MSG("Set radio: final power level=%d\n", power);
|
||||
}
|
||||
|
||||
ErrorCode SimRadio::send(MeshPacket *p)
|
||||
{
|
||||
DEBUG_MSG("SimRadio.send\n");
|
||||
packetPool.release(p);
|
||||
return ERRNO_OK;
|
||||
}
|
||||
|
||||
void RadioInterface::deliverToReceiver(MeshPacket *p)
|
||||
{
|
||||
|
||||
@@ -212,11 +212,6 @@ class RadioInterface
|
||||
}
|
||||
};
|
||||
|
||||
class SimRadio : public RadioInterface
|
||||
{
|
||||
public:
|
||||
virtual ErrorCode send(MeshPacket *p) override;
|
||||
};
|
||||
|
||||
/// Debug printing for packets
|
||||
void printPacket(const char *prefix, const MeshPacket *p);
|
||||
|
||||
@@ -58,12 +58,12 @@ bool ReliableRouter::shouldFilterReceived(MeshPacket *p)
|
||||
* 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)) {
|
||||
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) {
|
||||
} else if (wasSeenRecently(p, false) && p->hop_limit == HOP_RELIABLE && !MeshModule::currentReply) {
|
||||
// retransmission on broadcast has hop_limit still equal to HOP_RELIABLE
|
||||
DEBUG_MSG("Resending implicit ack for a repeated floodmsg\n");
|
||||
MeshPacket *tosend = packetPool.allocCopy(*p);
|
||||
@@ -94,7 +94,7 @@ void ReliableRouter::sniffReceived(const MeshPacket *p, const Routing *c)
|
||||
// - not DSR routing)
|
||||
if (p->want_ack) {
|
||||
if (MeshModule::currentReply)
|
||||
DEBUG_MSG("Someone else has replied to this message, no need for a 2nd ack\n");
|
||||
DEBUG_MSG("Some other module has replied to this message, no need for a 2nd ack\n");
|
||||
else
|
||||
sendAckNak(Routing_Error_NONE, getFrom(p), p->id, p->channel);
|
||||
}
|
||||
|
||||
@@ -18,6 +18,9 @@ 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
|
||||
*/
|
||||
|
||||
@@ -103,10 +103,7 @@ void StreamAPI::emitTxBuffer(size_t len)
|
||||
|
||||
auto totalLen = len + HEADER_LEN;
|
||||
stream->write(txBuf, totalLen);
|
||||
/* for(size_t i = 0; i < totalLen; i++) {
|
||||
stream->write(txBuf[i]);
|
||||
// stream->flush();
|
||||
} */
|
||||
stream->flush();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,4 +130,4 @@ void StreamAPI::onConnectionChanged(bool connected)
|
||||
// received a packet in a while
|
||||
powerFSM.trigger(EVENT_SERIAL_DISCONNECTED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,14 +59,12 @@ typedef struct _AdminMessage {
|
||||
AdminMessage_ModuleConfigType get_module_config_request;
|
||||
/* Send the current Config in the response to this message. */
|
||||
ModuleConfig get_module_config_response;
|
||||
/* Send all channels in the response to this message */
|
||||
bool get_all_channel_request;
|
||||
/* Get the Canned Message Module messages in the response to this message. */
|
||||
bool get_canned_message_module_messages_request;
|
||||
/* Get the Canned Message Module messages in the response to this message. */
|
||||
char get_canned_message_module_messages_response[201];
|
||||
/* Request the node to send device metadata (firmware, protobuf version, etc) */
|
||||
uint32_t get_device_metadata_request;
|
||||
bool get_device_metadata_request;
|
||||
/* Device metadata response */
|
||||
DeviceMetadata get_device_metadata_response;
|
||||
/* Set the owner for this node */
|
||||
@@ -94,6 +92,9 @@ typedef struct _AdminMessage {
|
||||
bool confirm_set_channel;
|
||||
/* TODO: REPLACE */
|
||||
bool confirm_set_radio;
|
||||
/* Tell the node to reboot into the OTA Firmware in this many seconds (or <0 to cancel reboot)
|
||||
Only Implemented for ESP32 Devices. This needs to be issued to send a new main firmware via bluetooth. */
|
||||
int32_t reboot_ota_seconds;
|
||||
/* This message is only supported for the simulator porduino build.
|
||||
If received the simulator will exit successfully. */
|
||||
bool exit_simulator;
|
||||
@@ -136,7 +137,6 @@ extern "C" {
|
||||
#define AdminMessage_get_config_response_tag 6
|
||||
#define AdminMessage_get_module_config_request_tag 7
|
||||
#define AdminMessage_get_module_config_response_tag 8
|
||||
#define AdminMessage_get_all_channel_request_tag 9
|
||||
#define AdminMessage_get_canned_message_module_messages_request_tag 10
|
||||
#define AdminMessage_get_canned_message_module_messages_response_tag 11
|
||||
#define AdminMessage_get_device_metadata_request_tag 12
|
||||
@@ -150,6 +150,7 @@ extern "C" {
|
||||
#define AdminMessage_confirm_set_module_config_tag 65
|
||||
#define AdminMessage_confirm_set_channel_tag 66
|
||||
#define AdminMessage_confirm_set_radio_tag 67
|
||||
#define AdminMessage_reboot_ota_seconds_tag 95
|
||||
#define AdminMessage_exit_simulator_tag 96
|
||||
#define AdminMessage_reboot_seconds_tag 97
|
||||
#define AdminMessage_shutdown_seconds_tag 98
|
||||
@@ -166,10 +167,9 @@ X(a, STATIC, ONEOF, UENUM, (payload_variant,get_config_request,get_confi
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,get_config_response,get_config_response), 6) \
|
||||
X(a, STATIC, ONEOF, UENUM, (payload_variant,get_module_config_request,get_module_config_request), 7) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,get_module_config_response,get_module_config_response), 8) \
|
||||
X(a, STATIC, ONEOF, BOOL, (payload_variant,get_all_channel_request,get_all_channel_request), 9) \
|
||||
X(a, STATIC, ONEOF, BOOL, (payload_variant,get_canned_message_module_messages_request,get_canned_message_module_messages_request), 10) \
|
||||
X(a, STATIC, ONEOF, STRING, (payload_variant,get_canned_message_module_messages_response,get_canned_message_module_messages_response), 11) \
|
||||
X(a, STATIC, ONEOF, UINT32, (payload_variant,get_device_metadata_request,get_device_metadata_request), 12) \
|
||||
X(a, STATIC, ONEOF, BOOL, (payload_variant,get_device_metadata_request,get_device_metadata_request), 12) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,get_device_metadata_response,get_device_metadata_response), 13) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,set_owner,set_owner), 32) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,set_channel,set_channel), 33) \
|
||||
@@ -180,6 +180,7 @@ X(a, STATIC, ONEOF, BOOL, (payload_variant,confirm_set_config,confirm_s
|
||||
X(a, STATIC, ONEOF, BOOL, (payload_variant,confirm_set_module_config,confirm_set_module_config), 65) \
|
||||
X(a, STATIC, ONEOF, BOOL, (payload_variant,confirm_set_channel,confirm_set_channel), 66) \
|
||||
X(a, STATIC, ONEOF, BOOL, (payload_variant,confirm_set_radio,confirm_set_radio), 67) \
|
||||
X(a, STATIC, ONEOF, INT32, (payload_variant,reboot_ota_seconds,reboot_ota_seconds), 95) \
|
||||
X(a, STATIC, ONEOF, BOOL, (payload_variant,exit_simulator,exit_simulator), 96) \
|
||||
X(a, STATIC, ONEOF, INT32, (payload_variant,reboot_seconds,reboot_seconds), 97) \
|
||||
X(a, STATIC, ONEOF, INT32, (payload_variant,shutdown_seconds,shutdown_seconds), 98) \
|
||||
|
||||
@@ -54,7 +54,7 @@ extern const pb_msgdesc_t ChannelSet_msg;
|
||||
#define ChannelSet_fields &ChannelSet_msg
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define ChannelSet_size 559
|
||||
#define ChannelSet_size 581
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
||||
@@ -38,25 +38,8 @@ typedef PB_BYTES_ARRAY_T(32) ChannelSettings_psk_t;
|
||||
FIXME: explain how apps use channels for security.
|
||||
explain how remote settings and remote gpio are managed as an example */
|
||||
typedef struct _ChannelSettings {
|
||||
/* NOTE: this field is _independent_ and unrelated to the concepts in channel.proto.
|
||||
this is controlling the actual hardware frequency the radio is transmitting on.
|
||||
In a perfect world we would have called it something else (band?) but I forgot to make this change during the big 1.2 renaming.
|
||||
Most users should never need to be exposed to this field/concept.
|
||||
A channel number between 1 and 13 (or whatever the max is in the current
|
||||
region). If ZERO then the rule is "use the old channel name hash based
|
||||
algorithm to derive the channel number")
|
||||
If using the hash algorithm the channel number will be: hash(channel_name) %
|
||||
NUM_CHANNELS (Where num channels depends on the regulatory region).
|
||||
NUM_CHANNELS_US is 13, for other values see MeshRadio.h in the device code.
|
||||
hash a string into an integer - djb2 by Dan Bernstein. -
|
||||
http://www.cse.yorku.ca/~oz/hash.html
|
||||
unsigned long hash(char *str) {
|
||||
unsigned long hash = 5381; int c;
|
||||
while ((c = *str++) != 0)
|
||||
hash = ((hash << 5) + hash) + (unsigned char) c;
|
||||
return hash;
|
||||
} */
|
||||
uint8_t channel_num;
|
||||
/* Deprecated in favor of LoraConfig.channel_num */
|
||||
uint32_t channel_num;
|
||||
/* A simple pre-shared key for now for crypto.
|
||||
Must be either 0 bytes (no crypto), 16 bytes (AES128), or 32 bytes (AES256).
|
||||
A special shorthand is used for 1 byte long psks.
|
||||
@@ -163,8 +146,8 @@ extern const pb_msgdesc_t Channel_msg;
|
||||
#define Channel_fields &Channel_msg
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define ChannelSettings_size 59
|
||||
#define Channel_size 74
|
||||
#define ChannelSettings_size 62
|
||||
#define Channel_size 77
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
||||
@@ -108,14 +108,15 @@ typedef struct _Config_DisplayConfig {
|
||||
typedef struct _Config_LoRaConfig {
|
||||
bool use_preset;
|
||||
Config_LoRaConfig_ModemPreset modem_preset;
|
||||
uint32_t bandwidth;
|
||||
uint16_t bandwidth;
|
||||
uint32_t spread_factor;
|
||||
uint32_t coding_rate;
|
||||
uint8_t coding_rate;
|
||||
float frequency_offset;
|
||||
Config_LoRaConfig_RegionCode region;
|
||||
uint32_t hop_limit;
|
||||
bool tx_enabled;
|
||||
int32_t tx_power;
|
||||
int8_t tx_power;
|
||||
uint8_t channel_num;
|
||||
pb_size_t ignore_incoming_count;
|
||||
uint32_t ignore_incoming[3];
|
||||
} Config_LoRaConfig;
|
||||
@@ -208,7 +209,7 @@ extern "C" {
|
||||
#define Config_PowerConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define Config_NetworkConfig_init_default {0, _Config_NetworkConfig_WiFiMode_MIN, "", "", ""}
|
||||
#define Config_DisplayConfig_init_default {0, _Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _Config_DisplayConfig_DisplayUnits_MIN}
|
||||
#define Config_LoRaConfig_init_default {0, _Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, {0, 0, 0}}
|
||||
#define Config_LoRaConfig_init_default {0, _Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, {0, 0, 0}}
|
||||
#define Config_BluetoothConfig_init_default {0, _Config_BluetoothConfig_PairingMode_MIN, 0}
|
||||
#define Config_init_zero {0, {Config_DeviceConfig_init_zero}}
|
||||
#define Config_DeviceConfig_init_zero {_Config_DeviceConfig_Role_MIN, 0, 0}
|
||||
@@ -216,7 +217,7 @@ extern "C" {
|
||||
#define Config_PowerConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define Config_NetworkConfig_init_zero {0, _Config_NetworkConfig_WiFiMode_MIN, "", "", ""}
|
||||
#define Config_DisplayConfig_init_zero {0, _Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _Config_DisplayConfig_DisplayUnits_MIN}
|
||||
#define Config_LoRaConfig_init_zero {0, _Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, {0, 0, 0}}
|
||||
#define Config_LoRaConfig_init_zero {0, _Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, {0, 0, 0}}
|
||||
#define Config_BluetoothConfig_init_zero {0, _Config_BluetoothConfig_PairingMode_MIN, 0}
|
||||
|
||||
/* Field tags (for use in manual encoding/decoding) */
|
||||
@@ -242,6 +243,7 @@ extern "C" {
|
||||
#define Config_LoRaConfig_hop_limit_tag 8
|
||||
#define Config_LoRaConfig_tx_enabled_tag 9
|
||||
#define Config_LoRaConfig_tx_power_tag 10
|
||||
#define Config_LoRaConfig_channel_num_tag 11
|
||||
#define Config_LoRaConfig_ignore_incoming_tag 103
|
||||
#define Config_NetworkConfig_wifi_enabled_tag 1
|
||||
#define Config_NetworkConfig_wifi_mode_tag 2
|
||||
@@ -350,6 +352,7 @@ X(a, STATIC, SINGULAR, UENUM, region, 7) \
|
||||
X(a, STATIC, SINGULAR, UINT32, hop_limit, 8) \
|
||||
X(a, STATIC, SINGULAR, BOOL, tx_enabled, 9) \
|
||||
X(a, STATIC, SINGULAR, INT32, tx_power, 10) \
|
||||
X(a, STATIC, SINGULAR, UINT32, channel_num, 11) \
|
||||
X(a, STATIC, REPEATED, UINT32, ignore_incoming, 103)
|
||||
#define Config_LoRaConfig_CALLBACK NULL
|
||||
#define Config_LoRaConfig_DEFAULT NULL
|
||||
@@ -384,7 +387,7 @@ extern const pb_msgdesc_t Config_BluetoothConfig_msg;
|
||||
#define Config_BluetoothConfig_size 10
|
||||
#define Config_DeviceConfig_size 6
|
||||
#define Config_DisplayConfig_size 20
|
||||
#define Config_LoRaConfig_size 69
|
||||
#define Config_LoRaConfig_size 67
|
||||
#define Config_NetworkConfig_size 137
|
||||
#define Config_PositionConfig_size 30
|
||||
#define Config_PowerConfig_size 43
|
||||
|
||||
@@ -164,7 +164,7 @@ extern const pb_msgdesc_t OEMStore_msg;
|
||||
#define OEMStore_fields &OEMStore_msg
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define ChannelFile_size 614
|
||||
#define ChannelFile_size 638
|
||||
#define DeviceState_size 21800
|
||||
#define OEMStore_size 2106
|
||||
|
||||
|
||||
@@ -144,7 +144,7 @@ extern const pb_msgdesc_t LocalModuleConfig_msg;
|
||||
#define LocalModuleConfig_fields &LocalModuleConfig_msg
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define LocalConfig_size 336
|
||||
#define LocalConfig_size 334
|
||||
#define LocalModuleConfig_size 270
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#ifndef PB_MESH_PB_H_INCLUDED
|
||||
#define PB_MESH_PB_H_INCLUDED
|
||||
#include <pb.h>
|
||||
#include "channel.pb.h"
|
||||
#include "config.pb.h"
|
||||
#include "module_config.pb.h"
|
||||
#include "portnums.pb.h"
|
||||
@@ -652,6 +653,8 @@ typedef struct _FromRadio {
|
||||
bool rebooted;
|
||||
/* Include module config */
|
||||
ModuleConfig moduleConfig;
|
||||
/* One packet is sent for each channel */
|
||||
Channel channel;
|
||||
};
|
||||
} FromRadio;
|
||||
|
||||
@@ -854,6 +857,7 @@ extern "C" {
|
||||
#define FromRadio_config_complete_id_tag 7
|
||||
#define FromRadio_rebooted_tag 8
|
||||
#define FromRadio_moduleConfig_tag 9
|
||||
#define FromRadio_channel_tag 10
|
||||
#define ToRadio_packet_tag 1
|
||||
#define ToRadio_peer_info_tag 2
|
||||
#define ToRadio_want_config_id_tag 3
|
||||
@@ -1001,7 +1005,8 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,config,config), 5) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,log_record,log_record), 6) \
|
||||
X(a, STATIC, ONEOF, UINT32, (payload_variant,config_complete_id,config_complete_id), 7) \
|
||||
X(a, STATIC, ONEOF, BOOL, (payload_variant,rebooted,rebooted), 8) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,moduleConfig,moduleConfig), 9)
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,moduleConfig,moduleConfig), 9) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,channel,channel), 10)
|
||||
#define FromRadio_CALLBACK NULL
|
||||
#define FromRadio_DEFAULT NULL
|
||||
#define FromRadio_payload_variant_packet_MSGTYPE MeshPacket
|
||||
@@ -1010,6 +1015,7 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,moduleConfig,moduleConfig),
|
||||
#define FromRadio_payload_variant_config_MSGTYPE Config
|
||||
#define FromRadio_payload_variant_log_record_MSGTYPE LogRecord
|
||||
#define FromRadio_payload_variant_moduleConfig_MSGTYPE ModuleConfig
|
||||
#define FromRadio_payload_variant_channel_MSGTYPE Channel
|
||||
|
||||
#define ToRadio_FIELDLIST(X, a) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,packet,packet), 1) \
|
||||
|
||||
@@ -74,6 +74,11 @@ typedef enum _PortNum {
|
||||
Maintained by Github user a-f-G-U-C (a Meshtastic contributor)
|
||||
Project files at https://github.com/a-f-G-U-C/Meshtastic-ZPS */
|
||||
PortNum_ZPS_APP = 68,
|
||||
/* Used to let multiple instances of Linux native applications communicate
|
||||
as if they did using their LoRa chip.
|
||||
Maintained by GitHub user GUVWAF.
|
||||
Project files at https://github.com/GUVWAF/Meshtasticator */
|
||||
PortNum_SIMULATOR_APP = 69,
|
||||
/* Private applications should use portnums >= 256.
|
||||
To simplify initial development and testing you can use "PRIVATE_APP"
|
||||
in your code without needing to rebuild protobuf files (via [regen-protos.sh](https://github.com/meshtastic/Meshtastic-device/blob/master/bin/regen-protos.sh)) */
|
||||
|
||||
@@ -29,7 +29,11 @@ typedef enum _TelemetrySensorType {
|
||||
/* High accuracy temperature and humidity */
|
||||
TelemetrySensorType_SHTC3 = 7,
|
||||
/* High accuracy pressure */
|
||||
TelemetrySensorType_LPS22 = 8
|
||||
TelemetrySensorType_LPS22 = 8,
|
||||
/* 3-Axis magnetic sensor */
|
||||
TelemetrySensorType_QMC6310 = 9,
|
||||
/* 6-Axis inertial measurement sensor */
|
||||
TelemetrySensorType_QMI8658 = 10
|
||||
} TelemetrySensorType;
|
||||
|
||||
/* Struct definitions */
|
||||
@@ -81,8 +85,8 @@ typedef struct _Telemetry {
|
||||
|
||||
/* Helper constants for enums */
|
||||
#define _TelemetrySensorType_MIN TelemetrySensorType_SENSOR_UNSET
|
||||
#define _TelemetrySensorType_MAX TelemetrySensorType_LPS22
|
||||
#define _TelemetrySensorType_ARRAYSIZE ((TelemetrySensorType)(TelemetrySensorType_LPS22+1))
|
||||
#define _TelemetrySensorType_MAX TelemetrySensorType_QMI8658
|
||||
#define _TelemetrySensorType_ARRAYSIZE ((TelemetrySensorType)(TelemetrySensorType_QMI8658+1))
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -48,8 +48,6 @@ using namespace httpsserver;
|
||||
HTTPClient httpClient;
|
||||
|
||||
#define DEST_FS_USES_LITTLEFS
|
||||
#define ESP_ARDUINO_VERSION_VAL(major, minor, patch) ((major << 16) | (minor << 8) | (patch))
|
||||
#define ESP_ARDUINO_VERSION ESP_ARDUINO_VERSION_VAL(1, 0, 4)
|
||||
|
||||
// We need to specify some content-type mapping, so the resources get delivered with the
|
||||
// right content type and are displayed correctly in the browser
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "target_specific.h"
|
||||
#include <DNSServer.h>
|
||||
#include <ESPmDNS.h>
|
||||
#include <esp_wifi.h>
|
||||
#include <WiFi.h>
|
||||
#include <WiFiUdp.h>
|
||||
|
||||
@@ -109,14 +110,9 @@ bool isSoftAPForced()
|
||||
|
||||
bool isWifiAvailable()
|
||||
{
|
||||
// If wifi status is connected, return true regardless of the radio configuration.
|
||||
if (isSoftAPForced()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *wifiName = config.network.wifi_ssid;
|
||||
if (config.network.wifi_enabled && ((config.network.wifi_ssid[0]) || forcedSoftAP)) {
|
||||
|
||||
if (*wifiName) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
@@ -238,10 +234,8 @@ bool initWifi(bool forceSoftAP)
|
||||
WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));
|
||||
DEBUG_MSG("MY IP AP ADDRESS: %s\n", WiFi.softAPIP().toString().c_str());
|
||||
|
||||
#if !CONFIG_IDF_TARGET_ESP32S3
|
||||
// This is needed to improve performance.
|
||||
esp_wifi_set_ps(WIFI_PS_NONE); // Disable radio power saving
|
||||
#endif
|
||||
|
||||
dnsServer.start(53, "*", apIP);
|
||||
|
||||
@@ -254,19 +248,14 @@ bool initWifi(bool forceSoftAP)
|
||||
WiFi.setHostname(ourHost);
|
||||
WiFi.onEvent(WiFiEvent);
|
||||
|
||||
#if !CONFIG_IDF_TARGET_ESP32S3
|
||||
// This is needed to improve performance.
|
||||
esp_wifi_set_ps(WIFI_PS_NONE); // Disable radio power saving
|
||||
#endif
|
||||
|
||||
WiFi.onEvent(
|
||||
[](WiFiEvent_t event, WiFiEventInfo_t info) {
|
||||
Serial.print("\nWiFi lost connection. Reason: ");
|
||||
#if CONFIG_IDF_TARGET_ESP32S3
|
||||
Serial.println(info.wifi_sta_disconnected.reason);
|
||||
wifiDisconnectReason = info.wifi_sta_disconnected.reason;
|
||||
#else
|
||||
Serial.println(info.disconnected.reason);
|
||||
|
||||
/*
|
||||
If we are disconnected from the AP for some reason,
|
||||
save the error code.
|
||||
@@ -274,15 +263,9 @@ bool initWifi(bool forceSoftAP)
|
||||
For a reference to the codes:
|
||||
https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/wifi.html#wi-fi-reason-code
|
||||
*/
|
||||
wifiDisconnectReason = info.disconnected.reason;
|
||||
#endif
|
||||
|
||||
wifiDisconnectReason = info.wifi_sta_disconnected.reason;
|
||||
},
|
||||
#if CONFIG_IDF_TARGET_ESP32S3
|
||||
WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_DISCONNECTED);
|
||||
#else
|
||||
WiFiEvent_t::SYSTEM_EVENT_STA_DISCONNECTED);
|
||||
#endif
|
||||
|
||||
DEBUG_MSG("JOINING WIFI soon: ssid=%s\n", wifiName);
|
||||
wifiReconnect = new Periodic("WifiConnect", reconnectWiFi);
|
||||
|
||||
@@ -4,11 +4,12 @@
|
||||
|
||||
static WiFiServerPort *apiPort;
|
||||
|
||||
void initApiServer()
|
||||
void initApiServer(int port)
|
||||
{
|
||||
// Start API server on port 4403
|
||||
if (!apiPort) {
|
||||
apiPort = new WiFiServerPort();
|
||||
apiPort = new WiFiServerPort(port);
|
||||
DEBUG_MSG("API server listening on TCP port %d\n", port);
|
||||
apiPort->init();
|
||||
}
|
||||
}
|
||||
@@ -56,13 +57,11 @@ void WiFiServerPort::debugOut(char c)
|
||||
apiPort->openAPI->debugOut(c);
|
||||
}
|
||||
|
||||
#define MESHTASTIC_PORTNUM 4403
|
||||
|
||||
WiFiServerPort::WiFiServerPort() : WiFiServer(MESHTASTIC_PORTNUM), concurrency::OSThread("ApiServer") {}
|
||||
WiFiServerPort::WiFiServerPort(int port) : WiFiServer(port), concurrency::OSThread("ApiServer") {}
|
||||
|
||||
void WiFiServerPort::init()
|
||||
{
|
||||
DEBUG_MSG("API server listening on TCP port %d\n", MESHTASTIC_PORTNUM);
|
||||
begin();
|
||||
}
|
||||
|
||||
@@ -80,4 +79,4 @@ int32_t WiFiServerPort::runOnce()
|
||||
}
|
||||
|
||||
return 100; // only check occasionally for incoming connections
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ class WiFiServerPort : public WiFiServer, private concurrency::OSThread
|
||||
WiFiServerAPI *openAPI = NULL;
|
||||
|
||||
public:
|
||||
WiFiServerPort();
|
||||
explicit WiFiServerPort(int port);
|
||||
|
||||
void init();
|
||||
|
||||
@@ -55,4 +55,4 @@ class WiFiServerPort : public WiFiServer, private concurrency::OSThread
|
||||
int32_t runOnce() override;
|
||||
};
|
||||
|
||||
void initApiServer();
|
||||
void initApiServer(int port=4403);
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
#include "Channels.h"
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
#ifdef ARCH_ESP32
|
||||
#include "BleOta.h"
|
||||
#endif
|
||||
#include "Router.h"
|
||||
#include "configuration.h"
|
||||
#include "main.h"
|
||||
@@ -103,6 +106,21 @@ bool AdminModule::handleReceivedProtobuf(const MeshPacket &mp, AdminMessage *r)
|
||||
rebootAtMsec = (s < 0) ? 0 : (millis() + s * 1000);
|
||||
break;
|
||||
}
|
||||
case AdminMessage_reboot_ota_seconds_tag: {
|
||||
int32_t s = r->reboot_ota_seconds;
|
||||
#ifdef ARCH_ESP32
|
||||
if (BleOta::getOtaAppVersion().isEmpty()) {
|
||||
DEBUG_MSG("No OTA firmware available, scheduling regular reboot in %d seconds\n", s);
|
||||
}else{
|
||||
BleOta::switchToOtaApp();
|
||||
DEBUG_MSG("Rebooting to OTA in %d seconds\n", s);
|
||||
}
|
||||
#else
|
||||
DEBUG_MSG("Not on ESP32, scheduling regular reboot in %d seconds\n", s);
|
||||
#endif
|
||||
rebootAtMsec = (s < 0) ? 0 : (millis() + s * 1000);
|
||||
break;
|
||||
}
|
||||
case AdminMessage_shutdown_seconds_tag: {
|
||||
int32_t s = r->shutdown_seconds;
|
||||
DEBUG_MSG("Shutdown in %d seconds\n", s);
|
||||
@@ -120,6 +138,12 @@ bool AdminModule::handleReceivedProtobuf(const MeshPacket &mp, AdminMessage *r)
|
||||
rebootAtMsec = millis() + (5 * 1000);
|
||||
break;
|
||||
}
|
||||
case AdminMessage_nodedb_reset_tag: {
|
||||
DEBUG_MSG("Initiating node-db reset\n");
|
||||
nodeDB.resetNodes();
|
||||
rebootAtMsec = millis() + (5 * 1000);
|
||||
break;
|
||||
}
|
||||
#ifdef ARCH_PORTDUINO
|
||||
case AdminMessage_exit_simulator_tag:
|
||||
DEBUG_MSG("Exiting simulator\n");
|
||||
@@ -169,8 +193,12 @@ void AdminModule::handleSetOwner(const User &o)
|
||||
owner.is_licensed = o.is_licensed;
|
||||
}
|
||||
|
||||
if (changed) // If nothing really changed, don't broadcast on the network or write to flash
|
||||
if (changed) { // If nothing really changed, don't broadcast on the network or write to flash
|
||||
service.reloadOwner();
|
||||
DEBUG_MSG("Rebooting due to owner changes\n");
|
||||
screen->startRebootScreen();
|
||||
rebootAtMsec = millis() + (5 * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
void AdminModule::handleSetConfig(const Config &c)
|
||||
@@ -231,7 +259,7 @@ void AdminModule::handleSetConfig(const Config &c)
|
||||
break;
|
||||
}
|
||||
|
||||
service.reloadConfig();
|
||||
service.reloadConfig(SEGMENT_CONFIG);
|
||||
// Reboot 5 seconds after a config that requires rebooting is set
|
||||
if (requiresReboot) {
|
||||
DEBUG_MSG("Rebooting due to config changes\n");
|
||||
@@ -280,7 +308,7 @@ void AdminModule::handleSetModuleConfig(const ModuleConfig &c)
|
||||
break;
|
||||
}
|
||||
|
||||
service.reloadConfig();
|
||||
service.reloadConfig(SEGMENT_MODULECONFIG);
|
||||
}
|
||||
|
||||
void AdminModule::handleSetChannel(const Channel &cc)
|
||||
|
||||
@@ -2,18 +2,41 @@
|
||||
#if HAS_SCREEN
|
||||
#include "CannedMessageModule.h"
|
||||
#include "FSCommon.h"
|
||||
#include "NodeDB.h"
|
||||
#include "MeshService.h"
|
||||
#include "PowerFSM.h" // neede for button bypass
|
||||
#include "mesh/generated/cannedmessages.pb.h"
|
||||
|
||||
// TODO: reuse defined from Screen.cpp
|
||||
#ifdef OLED_RU
|
||||
#include "graphics/fonts/OLEDDisplayFontsRU.h"
|
||||
#endif
|
||||
|
||||
#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
|
||||
#else
|
||||
#ifdef OLED_RU
|
||||
#define FONT_SMALL ArialMT_Plain_10_RU
|
||||
#else
|
||||
#define FONT_SMALL ArialMT_Plain_10
|
||||
#endif
|
||||
#define FONT_MEDIUM ArialMT_Plain_16
|
||||
#define FONT_LARGE ArialMT_Plain_24
|
||||
#endif
|
||||
|
||||
#define fontHeight(font) ((font)[1] + 1) // height is position 1
|
||||
|
||||
#define FONT_HEIGHT_SMALL fontHeight(FONT_SMALL)
|
||||
#define FONT_HEIGHT_MEDIUM fontHeight(FONT_MEDIUM)
|
||||
#define FONT_HEIGHT_LARGE fontHeight(FONT_LARGE)
|
||||
|
||||
// Remove Canned message screen if no action is taken for some milliseconds
|
||||
#define INACTIVATE_AFTER_MS 20000
|
||||
|
||||
extern uint8_t cardkb_found;
|
||||
|
||||
static const char *cannedMessagesConfigFile = "/prefs/cannedConf.proto";
|
||||
|
||||
CannedMessageModuleConfig cannedMessageModuleConfig;
|
||||
@@ -30,7 +53,7 @@ CannedMessageModule::CannedMessageModule()
|
||||
{
|
||||
if (moduleConfig.canned_message.enabled) {
|
||||
this->loadProtoForModule();
|
||||
if (this->splitConfiguredMessages() <= 0) {
|
||||
if ((this->splitConfiguredMessages() <= 0) && (cardkb_found != CARDKB_ADDR)) {
|
||||
DEBUG_MSG("CannedMessageModule: No messages are configured. Module is disabled\n");
|
||||
this->runState = CANNED_MESSAGE_RUN_STATE_DISABLED;
|
||||
} else {
|
||||
@@ -116,10 +139,48 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event)
|
||||
if ((this->runState == CANNED_MESSAGE_RUN_STATE_INACTIVE) || (this->runState == CANNED_MESSAGE_RUN_STATE_DISABLED)) {
|
||||
powerFSM.trigger(EVENT_PRESS);
|
||||
} else {
|
||||
this->payload = this->runState;
|
||||
this->runState = CANNED_MESSAGE_RUN_STATE_ACTION_SELECT;
|
||||
validEvent = true;
|
||||
}
|
||||
}
|
||||
if (event->inputEvent == static_cast<char>(ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL)) {
|
||||
DEBUG_MSG("Canned message event Cancel\n");
|
||||
// emulate a timeout. Same result
|
||||
this->lastTouchMillis = 0;
|
||||
validEvent = true;
|
||||
}
|
||||
if ((event->inputEvent == static_cast<char>(ModuleConfig_CannedMessageConfig_InputEventChar_BACK)) ||
|
||||
(event->inputEvent == static_cast<char>(ModuleConfig_CannedMessageConfig_InputEventChar_LEFT)) ||
|
||||
(event->inputEvent == static_cast<char>(ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT))) {
|
||||
DEBUG_MSG("Canned message event (%x)\n",event->kbchar);
|
||||
if (this->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT) {
|
||||
// pass the pressed key
|
||||
this->payload = event->kbchar;
|
||||
this->lastTouchMillis = millis();
|
||||
validEvent = true;
|
||||
}
|
||||
}
|
||||
if (event->inputEvent == static_cast<char>(ANYKEY)) {
|
||||
DEBUG_MSG("Canned message event any key pressed\n");
|
||||
// when inactive, this will switch to the freetext mode
|
||||
if ((this->runState == CANNED_MESSAGE_RUN_STATE_INACTIVE) || (this->runState == CANNED_MESSAGE_RUN_STATE_ACTIVE) || (this->runState == CANNED_MESSAGE_RUN_STATE_DISABLED)) {
|
||||
this->runState = CANNED_MESSAGE_RUN_STATE_FREETEXT;
|
||||
}
|
||||
// pass the pressed key
|
||||
this->payload = event->kbchar;
|
||||
this->lastTouchMillis = millis();
|
||||
validEvent = true;
|
||||
}
|
||||
if (event->inputEvent == static_cast<char>(MATRIXKEY)) {
|
||||
DEBUG_MSG("Canned message event Matrix key pressed\n");
|
||||
// this will send the text immediately on matrix press
|
||||
this->runState = CANNED_MESSAGE_RUN_STATE_ACTION_SELECT;
|
||||
this->payload = event->kbchar;
|
||||
this->currentMessageIndex = event->kbchar -1;
|
||||
this->lastTouchMillis = millis();
|
||||
validEvent = true;
|
||||
}
|
||||
|
||||
if (validEvent) {
|
||||
// Let runOnce to be called immediately.
|
||||
@@ -142,7 +203,7 @@ void CannedMessageModule::sendText(NodeNum dest, const char *message, bool wantR
|
||||
p->decoded.payload.size++;
|
||||
}
|
||||
|
||||
DEBUG_MSG("Sending message id=%d, msg=%.*s\n", p->id, p->decoded.payload.size, p->decoded.payload.bytes);
|
||||
DEBUG_MSG("Sending message id=%d, dest=%x, msg=%.*s\n", p->id, p->to, p->decoded.payload.size, p->decoded.payload.bytes);
|
||||
|
||||
service.sendToMesh(p);
|
||||
}
|
||||
@@ -151,7 +212,7 @@ int32_t CannedMessageModule::runOnce()
|
||||
{
|
||||
if ((!moduleConfig.canned_message.enabled) || (this->runState == CANNED_MESSAGE_RUN_STATE_DISABLED) ||
|
||||
(this->runState == CANNED_MESSAGE_RUN_STATE_INACTIVE)) {
|
||||
return 30000; // TODO: should return MAX_VAL
|
||||
return INT32_MAX;
|
||||
}
|
||||
DEBUG_MSG("Check status\n");
|
||||
UIFrameEvent e = {false, true};
|
||||
@@ -160,33 +221,149 @@ int32_t CannedMessageModule::runOnce()
|
||||
this->runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
|
||||
e.frameChanged = true;
|
||||
this->currentMessageIndex = -1;
|
||||
this->freetext = ""; // clear freetext
|
||||
this->cursor = 0;
|
||||
this->destSelect = false;
|
||||
this->notifyObservers(&e);
|
||||
} else if ((this->runState == CANNED_MESSAGE_RUN_STATE_ACTIVE) && (millis() - this->lastTouchMillis) > INACTIVATE_AFTER_MS) {
|
||||
} else if (((this->runState == CANNED_MESSAGE_RUN_STATE_ACTIVE) || (this->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT)) && ((millis() - this->lastTouchMillis) > INACTIVATE_AFTER_MS)) {
|
||||
// Reset module
|
||||
DEBUG_MSG("Reset due the lack of activity.\n");
|
||||
DEBUG_MSG("Reset due to lack of activity.\n");
|
||||
e.frameChanged = true;
|
||||
this->currentMessageIndex = -1;
|
||||
this->freetext = ""; // clear freetext
|
||||
this->cursor = 0;
|
||||
this->destSelect = false;
|
||||
this->runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
|
||||
this->notifyObservers(&e);
|
||||
} else if (this->currentMessageIndex == -1) {
|
||||
} else if (this->runState == CANNED_MESSAGE_RUN_STATE_ACTION_SELECT) {
|
||||
if (this->payload == CANNED_MESSAGE_RUN_STATE_FREETEXT) {
|
||||
if (this->freetext.length() > 0) {
|
||||
sendText(this->dest, this->freetext.c_str(), true);
|
||||
this->runState = CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE;
|
||||
} else {
|
||||
DEBUG_MSG("Reset message is empty.\n");
|
||||
this->runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
|
||||
}
|
||||
} else {
|
||||
if ((this->messagesCount > this->currentMessageIndex) && (strlen(this->messages[this->currentMessageIndex]) > 0)) {
|
||||
sendText(NODENUM_BROADCAST, this->messages[this->currentMessageIndex], true);
|
||||
this->runState = CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE;
|
||||
} else {
|
||||
DEBUG_MSG("Reset message is empty.\n");
|
||||
this->runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
|
||||
}
|
||||
}
|
||||
e.frameChanged = true;
|
||||
this->currentMessageIndex = -1;
|
||||
this->freetext = ""; // clear freetext
|
||||
this->cursor = 0;
|
||||
this->destSelect = false;
|
||||
this->notifyObservers(&e);
|
||||
return 2000;
|
||||
} else if ((this->runState != CANNED_MESSAGE_RUN_STATE_FREETEXT) && (this->currentMessageIndex == -1)) {
|
||||
this->currentMessageIndex = 0;
|
||||
DEBUG_MSG("First touch (%d):%s\n", this->currentMessageIndex, this->getCurrentMessage());
|
||||
e.frameChanged = true;
|
||||
this->runState = CANNED_MESSAGE_RUN_STATE_ACTIVE;
|
||||
} else if (this->runState == CANNED_MESSAGE_RUN_STATE_ACTION_SELECT) {
|
||||
sendText(NODENUM_BROADCAST, this->messages[this->currentMessageIndex], true);
|
||||
this->runState = CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE;
|
||||
this->currentMessageIndex = -1;
|
||||
this->notifyObservers(&e);
|
||||
return 2000;
|
||||
} else if (this->runState == CANNED_MESSAGE_RUN_STATE_ACTION_UP) {
|
||||
this->currentMessageIndex = getPrevIndex();
|
||||
this->runState = CANNED_MESSAGE_RUN_STATE_ACTIVE;
|
||||
DEBUG_MSG("MOVE UP (%d):%s\n", this->currentMessageIndex, this->getCurrentMessage());
|
||||
if (this->messagesCount > 0) {
|
||||
this->currentMessageIndex = getPrevIndex();
|
||||
this->freetext = ""; // clear freetext
|
||||
this->cursor = 0;
|
||||
this->destSelect = false;
|
||||
this->runState = CANNED_MESSAGE_RUN_STATE_ACTIVE;
|
||||
DEBUG_MSG("MOVE UP (%d):%s\n", this->currentMessageIndex, this->getCurrentMessage());
|
||||
}
|
||||
} else if (this->runState == CANNED_MESSAGE_RUN_STATE_ACTION_DOWN) {
|
||||
this->currentMessageIndex = this->getNextIndex();
|
||||
this->runState = CANNED_MESSAGE_RUN_STATE_ACTIVE;
|
||||
DEBUG_MSG("MOVE DOWN (%d):%s\n", this->currentMessageIndex, this->getCurrentMessage());
|
||||
if (this->messagesCount > 0) {
|
||||
this->currentMessageIndex = this->getNextIndex();
|
||||
this->freetext = ""; // clear freetext
|
||||
this->cursor = 0;
|
||||
this->destSelect = false;
|
||||
this->runState = CANNED_MESSAGE_RUN_STATE_ACTIVE;
|
||||
DEBUG_MSG("MOVE DOWN (%d):%s\n", this->currentMessageIndex, this->getCurrentMessage());
|
||||
}
|
||||
} else if (this->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT) {
|
||||
e.frameChanged = true;
|
||||
switch (this->payload) {
|
||||
case 0xb4: // left
|
||||
if (this->destSelect){
|
||||
size_t numNodes = nodeDB.getNumNodes();
|
||||
if(this->dest == NODENUM_BROADCAST) {
|
||||
this->dest = nodeDB.getNodeNum();
|
||||
}
|
||||
for (unsigned int i = 0; i < numNodes; i++) {
|
||||
if (nodeDB.getNodeByIndex(i)->num == this->dest) {
|
||||
this->dest = (i > 0) ? nodeDB.getNodeByIndex(i-1)->num : nodeDB.getNodeByIndex(numNodes-1)->num;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(this->dest == nodeDB.getNodeNum()) {
|
||||
this->dest = NODENUM_BROADCAST;
|
||||
}
|
||||
}else{
|
||||
if (this->cursor > 0) {
|
||||
this->cursor--;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xb7: // right
|
||||
if (this->destSelect){
|
||||
size_t numNodes = nodeDB.getNumNodes();
|
||||
if(this->dest == NODENUM_BROADCAST) {
|
||||
this->dest = nodeDB.getNodeNum();
|
||||
}
|
||||
for (unsigned int i = 0; i < numNodes; i++) {
|
||||
if (nodeDB.getNodeByIndex(i)->num == this->dest) {
|
||||
this->dest = (i < numNodes-1) ? nodeDB.getNodeByIndex(i+1)->num : nodeDB.getNodeByIndex(0)->num;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(this->dest == nodeDB.getNodeNum()) {
|
||||
this->dest = NODENUM_BROADCAST;
|
||||
}
|
||||
}else{
|
||||
if (this->cursor < this->freetext.length()) {
|
||||
this->cursor++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x08: // backspace
|
||||
if (this->freetext.length() > 0) {
|
||||
if(this->cursor == this->freetext.length()) {
|
||||
this->freetext = this->freetext.substring(0, this->freetext.length() - 1);
|
||||
} else {
|
||||
this->freetext = this->freetext.substring(0, this->cursor - 1) + this->freetext.substring(this->cursor, this->freetext.length());
|
||||
}
|
||||
this->cursor--;
|
||||
}
|
||||
break;
|
||||
case 0x09: // tab
|
||||
if(this->destSelect) {
|
||||
this->destSelect = false;
|
||||
} else {
|
||||
this->destSelect = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if(this->cursor == this->freetext.length()) {
|
||||
this->freetext += this->payload;
|
||||
} else {
|
||||
this->freetext = this->freetext.substring(0, this->cursor)
|
||||
+ this->payload
|
||||
+ this->freetext.substring(this->cursor);
|
||||
}
|
||||
this->cursor += 1;
|
||||
if (this->freetext.length() > Constants_DATA_PAYLOAD_LEN) {
|
||||
this->cursor = Constants_DATA_PAYLOAD_LEN;
|
||||
this->freetext = this->freetext.substring(0, Constants_DATA_PAYLOAD_LEN);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
this->lastTouchMillis = millis();
|
||||
this->notifyObservers(&e);
|
||||
return INACTIVATE_AFTER_MS;
|
||||
}
|
||||
|
||||
if (this->runState == CANNED_MESSAGE_RUN_STATE_ACTIVE) {
|
||||
@@ -195,7 +372,7 @@ int32_t CannedMessageModule::runOnce()
|
||||
return INACTIVATE_AFTER_MS;
|
||||
}
|
||||
|
||||
return 30000; // TODO: should return MAX_VAL
|
||||
return INT32_MAX;
|
||||
}
|
||||
|
||||
const char *CannedMessageModule::getCurrentMessage()
|
||||
@@ -210,6 +387,19 @@ const char *CannedMessageModule::getNextMessage()
|
||||
{
|
||||
return this->messages[this->getNextIndex()];
|
||||
}
|
||||
const char* CannedMessageModule::getNodeName(NodeNum node) {
|
||||
if (node == NODENUM_BROADCAST){
|
||||
return "Broadcast";
|
||||
}else{
|
||||
NodeInfo *info = nodeDB.getNode(node);
|
||||
if(info != NULL) {
|
||||
return info->user.long_name;
|
||||
}else{
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CannedMessageModule::shouldDraw()
|
||||
{
|
||||
if (!moduleConfig.canned_message.enabled) {
|
||||
@@ -240,6 +430,8 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
|
||||
{
|
||||
displayedNodeNum = 0; // Not currently showing a node pane
|
||||
|
||||
char buffer[50];
|
||||
|
||||
if (cannedMessageModule->runState == CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE) {
|
||||
display->setTextAlignment(TEXT_ALIGN_CENTER);
|
||||
display->setFont(FONT_MEDIUM);
|
||||
@@ -247,15 +439,32 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
|
||||
} else if (cannedMessageModule->runState == CANNED_MESSAGE_RUN_STATE_DISABLED) {
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display->setFont(FONT_SMALL);
|
||||
display->drawString(10 + x, 0 + y + 16, "Canned Message\nModule disabled.");
|
||||
} else {
|
||||
display->drawString(10 + x, 0 + y + FONT_HEIGHT_SMALL, "Canned Message\nModule disabled.");
|
||||
}else if (cannedMessageModule->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT) {
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display->setFont(FONT_SMALL);
|
||||
display->drawString(0 + x, 0 + y, cannedMessageModule->getPrevMessage());
|
||||
display->setFont(FONT_MEDIUM);
|
||||
display->drawString(0 + x, 0 + y + 8, cannedMessageModule->getCurrentMessage());
|
||||
display->setFont(FONT_SMALL);
|
||||
display->drawString(0 + x, 0 + y + 24, cannedMessageModule->getNextMessage());
|
||||
if (this->destSelect) {
|
||||
display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL);
|
||||
display->setColor(BLACK);
|
||||
}
|
||||
display->drawStringf(0 + x, 0 + y, buffer, "To: %s", cannedMessageModule->getNodeName(this->dest));
|
||||
// used chars right aligned
|
||||
sprintf(buffer, "%d left", Constants_DATA_PAYLOAD_LEN - this->freetext.length());
|
||||
display->drawString(x + display->getWidth() - display->getStringWidth(buffer), y + 0, buffer);
|
||||
display->setColor(WHITE);
|
||||
display->drawStringMaxWidth(0 + x, 0 + y + FONT_HEIGHT_SMALL, x + display->getWidth(), cannedMessageModule->drawWithCursor(cannedMessageModule->freetext, cannedMessageModule->cursor));
|
||||
} else {
|
||||
if (this->messagesCount > 0) {
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display->setFont(FONT_SMALL);
|
||||
display->drawStringf(0 + x, 0 + y, buffer, "To: %s", cannedMessageModule->getNodeName(this->dest));
|
||||
display->drawString(0 + x, 0 + y + FONT_HEIGHT_SMALL, cannedMessageModule->getPrevMessage());
|
||||
display->fillRect(0 + x, 0 + y + FONT_HEIGHT_SMALL * 2, x + display->getWidth(), y + FONT_HEIGHT_SMALL);
|
||||
display->setColor(BLACK);
|
||||
display->drawString(0 + x, 0 + y + FONT_HEIGHT_SMALL * 2, cannedMessageModule->getCurrentMessage());
|
||||
display->setColor(WHITE);
|
||||
display->drawString(0 + x, 0 + y + FONT_HEIGHT_SMALL * 3, cannedMessageModule->getNextMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -281,7 +490,7 @@ bool CannedMessageModule::saveProtoForModule()
|
||||
FS.mkdir("/prefs");
|
||||
#endif
|
||||
|
||||
okay &= saveProto(cannedMessagesConfigFile, CannedMessageModuleConfig_size, sizeof(CannedMessageModuleConfig),
|
||||
okay &= saveProto(cannedMessagesConfigFile, CannedMessageModuleConfig_size, sizeof(cannedMessageModuleConfig),
|
||||
CannedMessageModuleConfig_fields, &cannedMessageModuleConfig);
|
||||
|
||||
return okay;
|
||||
@@ -354,4 +563,12 @@ void CannedMessageModule::handleSetCannedMessageModuleMessages(const char *from_
|
||||
}
|
||||
}
|
||||
|
||||
String CannedMessageModule::drawWithCursor(String text, int cursor)
|
||||
{
|
||||
String result = text.substring(0, cursor)
|
||||
+ "_"
|
||||
+ text.substring(cursor);
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -8,6 +8,7 @@ enum cannedMessageModuleRunState
|
||||
CANNED_MESSAGE_RUN_STATE_DISABLED,
|
||||
CANNED_MESSAGE_RUN_STATE_INACTIVE,
|
||||
CANNED_MESSAGE_RUN_STATE_ACTIVE,
|
||||
CANNED_MESSAGE_RUN_STATE_FREETEXT,
|
||||
CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE,
|
||||
CANNED_MESSAGE_RUN_STATE_ACTION_SELECT,
|
||||
CANNED_MESSAGE_RUN_STATE_ACTION_UP,
|
||||
@@ -34,6 +35,7 @@ class CannedMessageModule :
|
||||
const char* getCurrentMessage();
|
||||
const char* getPrevMessage();
|
||||
const char* getNextMessage();
|
||||
const char* getNodeName(NodeNum node);
|
||||
bool shouldDraw();
|
||||
void eventUp();
|
||||
void eventDown();
|
||||
@@ -42,6 +44,8 @@ class CannedMessageModule :
|
||||
void handleGetCannedMessageModuleMessages(const MeshPacket &req, AdminMessage *response);
|
||||
void handleSetCannedMessageModuleMessages(const char *from_msg);
|
||||
|
||||
String drawWithCursor(String text, int cursor);
|
||||
|
||||
protected:
|
||||
|
||||
virtual int32_t runOnce() override;
|
||||
@@ -70,6 +74,11 @@ class CannedMessageModule :
|
||||
|
||||
int currentMessageIndex = -1;
|
||||
cannedMessageModuleRunState runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
|
||||
char payload = 0x00;
|
||||
unsigned int cursor = 0;
|
||||
String freetext = ""; // Text Buffer for Freetext Editor
|
||||
bool destSelect = false; // Freetext Editor Mode
|
||||
NodeNum dest = NODENUM_BROADCAST;
|
||||
|
||||
char messageStore[CANNED_MESSAGE_MODULE_MESSAGES_SIZE+1];
|
||||
char *messages[CANNED_MESSAGE_MODULE_MESSAGE_MAX_COUNT];
|
||||
@@ -78,4 +87,4 @@ class CannedMessageModule :
|
||||
};
|
||||
|
||||
extern CannedMessageModule *cannedMessageModule;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include "input/RotaryEncoderInterruptImpl1.h"
|
||||
#include "input/UpDownInterruptImpl1.h"
|
||||
#include "input/cardKbI2cImpl.h"
|
||||
#include "input/facesKbI2cImpl.h"
|
||||
#include "modules/AdminModule.h"
|
||||
#include "modules/CannedMessageModule.h"
|
||||
#include "modules/NodeInfoModule.h"
|
||||
@@ -53,8 +52,6 @@ void setupModules()
|
||||
upDownInterruptImpl1->init();
|
||||
cardKbI2cImpl = new CardKbI2cImpl();
|
||||
cardKbI2cImpl->init();
|
||||
facesKbI2cImpl = new FacesKbI2cImpl();
|
||||
facesKbI2cImpl->init();
|
||||
#endif
|
||||
#if HAS_SCREEN
|
||||
cannedMessageModule = new CannedMessageModule();
|
||||
|
||||
@@ -58,6 +58,8 @@ MeshPacket *PositionModule::allocReply()
|
||||
NodeInfo *node = service.refreshMyNodeInfo(); // should guarantee there is now a position
|
||||
assert(node->has_position);
|
||||
|
||||
node->position.seq_number++;
|
||||
|
||||
// configuration of POSITION packet
|
||||
// consider making this a function argument?
|
||||
uint32_t pos_flags = config.position.position_flags;
|
||||
@@ -94,6 +96,15 @@ MeshPacket *PositionModule::allocReply()
|
||||
if (pos_flags & Config_PositionConfig_PositionFlags_TIMESTAMP)
|
||||
p.timestamp = node->position.timestamp;
|
||||
|
||||
if (pos_flags & Config_PositionConfig_PositionFlags_SEQ_NO)
|
||||
p.seq_number = node->position.seq_number;
|
||||
|
||||
if (pos_flags & Config_PositionConfig_PositionFlags_HEADING)
|
||||
p.ground_track = node->position.ground_track;
|
||||
|
||||
if (pos_flags & Config_PositionConfig_PositionFlags_SPEED)
|
||||
p.ground_speed = node->position.ground_speed;
|
||||
|
||||
// Strip out any time information before sending packets to other nodes - to keep the wire size small (and because other
|
||||
// nodes shouldn't trust it anyways) Note: we allow a device with a local GPS to include the time, so that gpsless
|
||||
// devices can get time.
|
||||
@@ -133,7 +144,7 @@ int32_t PositionModule::runOnce()
|
||||
if (lastGpsSend == 0 || (now - lastGpsSend) >= intervalMs) {
|
||||
|
||||
// Only send packets if the channel is less than 40% utilized.
|
||||
if (airTime->channelUtilizationPercent() < 40) {
|
||||
if (airTime->channelUtilizationPercent() < max_channel_util_percent) {
|
||||
if (node->has_position && (node->position.latitude_i != 0 || node->position.longitude_i != 0)) {
|
||||
lastGpsSend = now;
|
||||
|
||||
@@ -154,7 +165,7 @@ int32_t PositionModule::runOnce()
|
||||
} else if (config.position.position_broadcast_smart_enabled) {
|
||||
|
||||
// Only send packets if the channel is less than 25% utilized.
|
||||
if (airTime->channelUtilizationPercent() < 25) {
|
||||
if (airTime->channelUtilizationPercent() < polite_channel_util_percent) {
|
||||
|
||||
NodeInfo *node2 = service.refreshMyNodeInfo(); // should guarantee there is now a position
|
||||
|
||||
|
||||
@@ -27,8 +27,7 @@
|
||||
TXD 15
|
||||
3) Set timeout to the amount of time to wait before we consider
|
||||
your packet as "done".
|
||||
4) (Optional) In SerialModule.h set the port to PortNum_TEXT_MESSAGE_APP if you want to
|
||||
send messages to/from the general text message channel.
|
||||
4) not applicable any more
|
||||
5) Connect to your device over the serial interface at 38400 8N1.
|
||||
6) Send a packet up to 240 bytes in length. This will get relayed over the mesh network.
|
||||
7) (Optional) Set echo to 1 and any message you send out will be echoed back
|
||||
@@ -61,10 +60,20 @@ SerialModule::SerialModule() : concurrency::OSThread("SerialModule") {}
|
||||
|
||||
char serialStringChar[Constants_DATA_PAYLOAD_LEN];
|
||||
|
||||
SerialModuleRadio::SerialModuleRadio() : SinglePortModule("SerialModuleRadio", PortNum_SERIAL_APP)
|
||||
SerialModuleRadio::SerialModuleRadio() : MeshModule("SerialModuleRadio")
|
||||
{
|
||||
// restrict to the admin channel for rx
|
||||
boundChannel = Channels::serialChannel;
|
||||
|
||||
switch (moduleConfig.serial.mode)
|
||||
{
|
||||
case ModuleConfig_SerialConfig_Serial_Mode_TEXTMSG:
|
||||
ourPortNum = PortNum_TEXT_MESSAGE_APP;
|
||||
break;
|
||||
default:
|
||||
ourPortNum = PortNum_SERIAL_APP;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t SerialModule::runOnce()
|
||||
@@ -139,7 +148,9 @@ int32_t SerialModule::runOnce()
|
||||
baud = 921600;
|
||||
}
|
||||
|
||||
#ifdef ARCH_ESP32
|
||||
#ifdef ARCH_ESP32
|
||||
Serial2.setRxBufferSize(RX_BUFFER);
|
||||
|
||||
if (moduleConfig.serial.rxd && moduleConfig.serial.txd) {
|
||||
Serial2.begin(baud, SERIAL_8N1, moduleConfig.serial.rxd, moduleConfig.serial.txd);
|
||||
|
||||
@@ -159,10 +170,6 @@ int32_t SerialModule::runOnce()
|
||||
Serial2.setTimeout(TIMEOUT); // Number of MS to wait to set the timeout for the string.
|
||||
}
|
||||
|
||||
#ifdef ARCH_ESP32
|
||||
Serial2.setRxBufferSize(RX_BUFFER);
|
||||
#endif
|
||||
|
||||
serialModuleRadio = new SerialModuleRadio();
|
||||
|
||||
firstTime = 0;
|
||||
@@ -244,8 +251,6 @@ ProcessMessage SerialModuleRadio::handleReceived(const MeshPacket &mp)
|
||||
|
||||
if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_DEFAULT ||
|
||||
moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_SIMPLE) {
|
||||
// DEBUG_MSG("* * Message came from the mesh\n");
|
||||
// Serial2.println("* * Message came from the mesh");
|
||||
Serial2.printf("%s", p.payload.bytes);
|
||||
|
||||
} else if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_PROTO) {
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#include "concurrency/OSThread.h"
|
||||
#include "configuration.h"
|
||||
#include <Arduino.h>
|
||||
#include "MeshModule.h"
|
||||
#include "Router.h"
|
||||
#include <functional>
|
||||
|
||||
class SerialModule : private concurrency::OSThread
|
||||
@@ -23,16 +25,11 @@ extern SerialModule *serialModule;
|
||||
* Radio interface for SerialModule
|
||||
*
|
||||
*/
|
||||
class SerialModuleRadio : public SinglePortModule
|
||||
class SerialModuleRadio : public MeshModule
|
||||
{
|
||||
uint32_t lastRxID = 0;
|
||||
|
||||
public:
|
||||
/*
|
||||
TODO: Switch this to PortNum_SERIAL_APP once the change is able to be merged back here
|
||||
from the main code.
|
||||
*/
|
||||
|
||||
SerialModuleRadio();
|
||||
|
||||
/**
|
||||
@@ -48,6 +45,20 @@ class SerialModuleRadio : public SinglePortModule
|
||||
@return ProcessMessage::STOP if you've guaranteed you've handled this message and no other handlers should be considered for it
|
||||
*/
|
||||
virtual ProcessMessage handleReceived(const MeshPacket &mp) override;
|
||||
|
||||
PortNum ourPortNum;
|
||||
|
||||
virtual bool wantPacket(const MeshPacket *p) override { return p->decoded.portnum == ourPortNum; }
|
||||
|
||||
MeshPacket *allocDataPacket()
|
||||
{
|
||||
// Update our local node info with our position (even if we don't decide to update anyone else)
|
||||
MeshPacket *p = router->allocForSending();
|
||||
p->decoded.portnum = ourPortNum;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
extern SerialModuleRadio *serialModuleRadio;
|
||||
|
||||
@@ -13,15 +13,16 @@
|
||||
int32_t DeviceTelemetryModule::runOnce()
|
||||
{
|
||||
#ifndef ARCH_PORTDUINO
|
||||
if (firstTime) {
|
||||
// This is the first time the OSThread library has called this function, so do some setup
|
||||
firstTime = 0;
|
||||
DEBUG_MSG("Device Telemetry: Initializing\n");
|
||||
uint32_t now = millis();
|
||||
if ((lastSentToMesh == 0 || (now - lastSentToMesh) >= getConfiguredOrDefaultMs(moduleConfig.telemetry.device_update_interval))
|
||||
&& airTime->channelUtilizationPercent() < max_channel_util_percent) {
|
||||
sendTelemetry();
|
||||
lastSentToMesh = now;
|
||||
} else {
|
||||
// Just send to phone when it's not our time to send to mesh yet
|
||||
sendTelemetry(NODENUM_BROADCAST, true);
|
||||
}
|
||||
sendOurTelemetry();
|
||||
// OSThread library. Multiply the preference value by 1000 to convert seconds to miliseconds
|
||||
|
||||
return getConfiguredOrDefaultMs(moduleConfig.telemetry.device_update_interval);
|
||||
return sendToPhoneIntervalMs;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -45,7 +46,7 @@ bool DeviceTelemetryModule::handleReceivedProtobuf(const MeshPacket &mp, Telemet
|
||||
return false; // Let others look at this message also if they want
|
||||
}
|
||||
|
||||
bool DeviceTelemetryModule::sendOurTelemetry(NodeNum dest, bool wantReplies)
|
||||
bool DeviceTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
|
||||
{
|
||||
Telemetry t;
|
||||
|
||||
@@ -68,11 +69,16 @@ bool DeviceTelemetryModule::sendOurTelemetry(NodeNum dest, bool wantReplies)
|
||||
|
||||
MeshPacket *p = allocDataProtobuf(t);
|
||||
p->to = dest;
|
||||
p->decoded.want_response = wantReplies;
|
||||
p->decoded.want_response = false;
|
||||
|
||||
lastMeasurementPacket = packetPool.allocCopy(*p);
|
||||
DEBUG_MSG("Device Telemetry: Sending packet to mesh\n");
|
||||
service.sendToMesh(p, RX_SRC_LOCAL, true);
|
||||
nodeDB.updateTelemetry(nodeDB.getNodeNum(), t, RX_SRC_LOCAL);
|
||||
if (phoneOnly) {
|
||||
DEBUG_MSG("Device Telemetry: Sending packet to phone\n");
|
||||
service.sendToPhone(p);
|
||||
} else {
|
||||
DEBUG_MSG("Device Telemetry: Sending packet to mesh\n");
|
||||
service.sendToMesh(p, RX_SRC_LOCAL, true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -24,9 +24,10 @@ class DeviceTelemetryModule : private concurrency::OSThread, public ProtobufModu
|
||||
/**
|
||||
* Send our Telemetry into the mesh
|
||||
*/
|
||||
bool sendOurTelemetry(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false);
|
||||
bool sendTelemetry(NodeNum dest = NODENUM_BROADCAST, bool phoneOnly = false);
|
||||
|
||||
private:
|
||||
bool firstTime = 1;
|
||||
uint32_t sendToPhoneIntervalMs = SECONDS_IN_MINUTE * 1000; // Send to phone every minute
|
||||
uint32_t lastSentToMesh = 0;
|
||||
const MeshPacket *lastMeasurementPacket;
|
||||
};
|
||||
|
||||
@@ -27,7 +27,7 @@ int32_t StoreForwardModule::runOnce()
|
||||
if (this->busy) {
|
||||
|
||||
// Only send packets if the channel is less than 25% utilized.
|
||||
if (airTime->channelUtilizationPercent() < 25) {
|
||||
if (airTime->channelUtilizationPercent() < polite_channel_util_percent) {
|
||||
|
||||
// DEBUG_MSG("--- --- --- In busy loop 1 %d\n", this->packetHistoryTXQueue_index);
|
||||
storeForwardModule->sendPayload(this->busyTo, this->packetHistoryTXQueue_index);
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
|
||||
MQTT *mqtt;
|
||||
|
||||
String statusTopic = "msh/1/stat/";
|
||||
String cryptTopic = "msh/1/c/"; // msh/1/c/CHANNELID/NODEID
|
||||
String jsonTopic = "msh/1/json/"; // msh/1/json/CHANNELID/NODEID
|
||||
String statusTopic = "msh/2/stat/";
|
||||
String cryptTopic = "msh/2/c/"; // msh/2/c/CHANNELID/NODEID
|
||||
String jsonTopic = "msh/2/json/"; // msh/2/json/CHANNELID/NODEID
|
||||
|
||||
void MQTT::mqttCallback(char *topic, byte *payload, unsigned int length)
|
||||
{
|
||||
@@ -27,8 +27,7 @@ void MQTT::onPublish(char *topic, byte *payload, unsigned int length)
|
||||
{
|
||||
// parsing ServiceEnvelope
|
||||
ServiceEnvelope e = ServiceEnvelope_init_default;
|
||||
if (moduleConfig.mqtt.json_enabled && !pb_decode_from_bytes(payload, length, ServiceEnvelope_fields, &e)) {
|
||||
|
||||
if (!pb_decode_from_bytes(payload, length, ServiceEnvelope_fields, &e) && moduleConfig.mqtt.json_enabled) {
|
||||
// check if this is a json payload message
|
||||
using namespace json11;
|
||||
char payloadStr[length + 1];
|
||||
|
||||
@@ -75,7 +75,7 @@ class NimbleBluetoothServerCallback : public NimBLEServerCallbacks
|
||||
if (doublepressed > 0 && (doublepressed + (30 * 1000)) > millis()) {
|
||||
DEBUG_MSG("User has set BLE pairing mode to fixed-pin\n");
|
||||
config.bluetooth.mode = Config_BluetoothConfig_PairingMode_FIXED_PIN;
|
||||
nodeDB.saveToDisk();
|
||||
nodeDB.saveToDisk(SEGMENT_CONFIG);
|
||||
} else if (config.bluetooth.mode == Config_BluetoothConfig_PairingMode_RANDOM_PIN) {
|
||||
DEBUG_MSG("Using random passkey\n");
|
||||
// This is the passkey to be entered on peer - we pick a number >100,000 to ensure 6 digits
|
||||
|
||||
43
src/platform/esp32/BleOta.cpp
Normal file
43
src/platform/esp32/BleOta.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
#include "Arduino.h"
|
||||
#include "BleOta.h"
|
||||
#include <esp_ota_ops.h>
|
||||
|
||||
static const String MESHTASTIC_OTA_APP_PROJECT_NAME("Meshtastic-OTA");
|
||||
|
||||
const esp_partition_t* BleOta::findEspOtaAppPartition() {
|
||||
const esp_partition_t *part = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_OTA_0, nullptr);
|
||||
|
||||
esp_app_desc_t app_desc;
|
||||
esp_err_t ret = ESP_ERROR_CHECK_WITHOUT_ABORT(esp_ota_get_partition_description(part, &app_desc));
|
||||
|
||||
if (ret != ESP_OK || MESHTASTIC_OTA_APP_PROJECT_NAME != app_desc.project_name) {
|
||||
part = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_OTA_1, nullptr);
|
||||
ret = ESP_ERROR_CHECK_WITHOUT_ABORT(esp_ota_get_partition_description(part, &app_desc));
|
||||
}
|
||||
|
||||
if (ret == ESP_OK && MESHTASTIC_OTA_APP_PROJECT_NAME == app_desc.project_name) {
|
||||
return part;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
String BleOta::getOtaAppVersion() {
|
||||
const esp_partition_t *part = findEspOtaAppPartition();
|
||||
esp_app_desc_t app_desc;
|
||||
esp_err_t ret = ESP_ERROR_CHECK_WITHOUT_ABORT(esp_ota_get_partition_description(part, &app_desc));
|
||||
String version;
|
||||
if (ret == ESP_OK) {
|
||||
version = app_desc.version;
|
||||
}
|
||||
return version;
|
||||
}
|
||||
|
||||
bool BleOta::switchToOtaApp() {
|
||||
bool success = false;
|
||||
const esp_partition_t *part = findEspOtaAppPartition();
|
||||
if (part) {
|
||||
success = (ESP_ERROR_CHECK_WITHOUT_ABORT(esp_ota_set_boot_partition(part)) == ESP_OK);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
18
src/platform/esp32/BleOta.h
Normal file
18
src/platform/esp32/BleOta.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef BLEOTA_H
|
||||
#define BLEOTA_H
|
||||
|
||||
#include <functional>
|
||||
|
||||
class BleOta {
|
||||
public:
|
||||
explicit BleOta() {};
|
||||
|
||||
static String getOtaAppVersion();
|
||||
static bool switchToOtaApp();
|
||||
|
||||
private:
|
||||
String mUserAgent;
|
||||
static const esp_partition_t *findEspOtaAppPartition();
|
||||
};
|
||||
|
||||
#endif //BLEOTA_H
|
||||
@@ -1,16 +1,8 @@
|
||||
#include "CryptoEngine.h"
|
||||
#include "configuration.h"
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32S3
|
||||
#include "mbedtls/aes.h"
|
||||
#else
|
||||
#include "crypto/includes.h"
|
||||
#include "crypto/common.h"
|
||||
// #include "esp_system.h"
|
||||
#include "crypto/aes.h"
|
||||
#include "crypto/aes_wrap.h"
|
||||
#include "mbedtls/aes.h"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
class ESP32CryptoEngine : public CryptoEngine
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "main.h"
|
||||
|
||||
#include "nimble/NimbleBluetooth.h"
|
||||
#include "BleOta.h"
|
||||
#include "mesh/http/WiFiAPClient.h"
|
||||
|
||||
#include "sleep.h"
|
||||
@@ -63,6 +64,12 @@ void esp32Setup()
|
||||
preferences.putUInt("rebootCounter", rebootCounter);
|
||||
preferences.end();
|
||||
DEBUG_MSG("Number of Device Reboots: %d\n", rebootCounter);
|
||||
String BLEOTA=BleOta::getOtaAppVersion();
|
||||
if (BLEOTA.isEmpty()) {
|
||||
DEBUG_MSG("No OTA firmware available\n");
|
||||
}else{
|
||||
DEBUG_MSG("OTA firmware version %s\n", BLEOTA);
|
||||
}
|
||||
|
||||
// enableModemSleep();
|
||||
|
||||
|
||||
@@ -244,6 +244,9 @@ void NRF52Bluetooth::setup()
|
||||
Bluefruit.Periph.setConnectCallback(onConnect);
|
||||
Bluefruit.Periph.setDisconnectCallback(onDisconnect);
|
||||
|
||||
bledfu.setPermission(SECMODE_ENC_WITH_MITM, SECMODE_ENC_WITH_MITM);
|
||||
bledfu.begin(); // Install the DFU helper
|
||||
|
||||
// Configure and Start the Device Information Service
|
||||
DEBUG_MSG("Configuring the Device Information Service\n");
|
||||
bledis.setModel(optstr(HW_VERSION));
|
||||
@@ -254,7 +257,7 @@ void NRF52Bluetooth::setup()
|
||||
DEBUG_MSG("Configuring the Battery Service\n");
|
||||
blebas.begin();
|
||||
blebas.write(0); // Unknown battery level for now
|
||||
bledfu.begin(); // Install the DFU helper
|
||||
|
||||
|
||||
// Setup the Heart Rate Monitor service using
|
||||
// BLEService and BLECharacteristic classes
|
||||
|
||||
@@ -51,13 +51,42 @@ class PolledIrqPin : public GPIOPin
|
||||
|
||||
static GPIOPin *loraIrq;
|
||||
|
||||
int TCPPort = 4403;
|
||||
|
||||
static error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
switch (key) {
|
||||
case 'p':
|
||||
if (sscanf(arg, "%d", &TCPPort) < 1)
|
||||
return ARGP_ERR_UNKNOWN;
|
||||
else
|
||||
printf("Using TCP port %d\n", TCPPort);
|
||||
break;
|
||||
case ARGP_KEY_ARG:
|
||||
return 0;
|
||||
default:
|
||||
return ARGP_ERR_UNKNOWN;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void portduinoCustomInit() {
|
||||
static struct argp_option options[] = {{"port", 'p', "PORT", 0, "The TCP port to use."}, {0}};
|
||||
static void *childArguments;
|
||||
static char doc[] = "Meshtastic native build.";
|
||||
static char args_doc[] = "...";
|
||||
static struct argp argp = {options, parse_opt, args_doc, doc, 0, 0, 0};
|
||||
const struct argp_child child = {&argp, OPTION_ARG_OPTIONAL, 0, 0};
|
||||
portduinoAddArguments(child, childArguments);
|
||||
}
|
||||
|
||||
|
||||
/** apps run under portduino can optionally define a portduinoSetup() to
|
||||
* use portduino specific init code (such as gpioBind) to setup portduino on their host machine,
|
||||
* before running 'arduino' code.
|
||||
*/
|
||||
void portduinoSetup()
|
||||
{
|
||||
printf("Setting up Meshtastic on Porduino...\n");
|
||||
printf("Setting up Meshtastic on Portduino...\n");
|
||||
|
||||
#ifdef PORTDUINO_LINUX_HARDWARE
|
||||
SPI.begin(); // We need to create SPI
|
||||
@@ -86,6 +115,9 @@ void portduinoSetup()
|
||||
#endif
|
||||
|
||||
{
|
||||
// Set the random seed equal to TCPPort to have a different seed per instance
|
||||
randomSeed(TCPPort);
|
||||
|
||||
auto fakeBusy = new SimGPIOPin(SX126X_BUSY, "fakeBusy");
|
||||
fakeBusy->writePin(LOW);
|
||||
fakeBusy->setSilent(true);
|
||||
|
||||
255
src/platform/portduino/SimRadio.cpp
Normal file
255
src/platform/portduino/SimRadio.cpp
Normal file
@@ -0,0 +1,255 @@
|
||||
#include "SimRadio.h"
|
||||
#include "MeshService.h"
|
||||
#include "Router.h"
|
||||
|
||||
SimRadio::SimRadio()
|
||||
{
|
||||
instance = this;
|
||||
}
|
||||
|
||||
SimRadio *SimRadio::instance;
|
||||
|
||||
ErrorCode SimRadio::send(MeshPacket *p)
|
||||
{
|
||||
printPacket("enqueuing for send", p);
|
||||
|
||||
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
|
||||
packetPool.release(p);
|
||||
return res;
|
||||
}
|
||||
|
||||
// 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");
|
||||
setTransmitDelay();
|
||||
return res;
|
||||
}
|
||||
|
||||
void SimRadio::setTransmitDelay()
|
||||
{
|
||||
MeshPacket *p = txQueue.getFront();
|
||||
// We want all sending/receiving to be done by our daemon thread.
|
||||
// We use a delay here because this packet might have been sent in response to a packet we just received.
|
||||
// So we want to make sure the other side has had a chance to reconfigure its radio.
|
||||
|
||||
/* We assume if rx_snr = 0 and rx_rssi = 0, the packet was generated locally.
|
||||
* This assumption is valid because of the offset generated by the radio to account for the noise
|
||||
* floor.
|
||||
*/
|
||||
if (p->rx_snr == 0 && p->rx_rssi == 0) {
|
||||
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);
|
||||
startTransmitTimerSNR(p->rx_snr);
|
||||
}
|
||||
}
|
||||
|
||||
void SimRadio::startTransmitTimer(bool withDelay)
|
||||
{
|
||||
// If we have work to do and the timer wasn't already scheduled, schedule it now
|
||||
if (!txQueue.empty()) {
|
||||
uint32_t delayMsec = !withDelay ? 1 : getTxDelayMsec();
|
||||
// DEBUG_MSG("xmit timer %d\n", delay);
|
||||
delay(delayMsec);
|
||||
onNotify(TRANSMIT_DELAY_COMPLETED);
|
||||
} else {
|
||||
DEBUG_MSG("TX QUEUE EMPTY!\n");
|
||||
}
|
||||
}
|
||||
|
||||
void SimRadio::startTransmitTimerSNR(float snr)
|
||||
{
|
||||
// If we have work to do and the timer wasn't already scheduled, schedule it now
|
||||
if (!txQueue.empty()) {
|
||||
uint32_t delayMsec = getTxDelayMsecWeighted(snr);
|
||||
// DEBUG_MSG("xmit timer %d\n", delay);
|
||||
delay(delayMsec);
|
||||
onNotify(TRANSMIT_DELAY_COMPLETED);
|
||||
}
|
||||
}
|
||||
|
||||
void SimRadio::handleTransmitInterrupt()
|
||||
{
|
||||
// This can be null if we forced the device to enter standby mode. In that case
|
||||
// ignore the transmit interrupt
|
||||
if (sendingPacket)
|
||||
completeSending();
|
||||
}
|
||||
|
||||
void SimRadio::completeSending()
|
||||
{
|
||||
// We are careful to clear sending packet before calling printPacket because
|
||||
// that can take a long time
|
||||
auto p = sendingPacket;
|
||||
sendingPacket = NULL;
|
||||
|
||||
if (p) {
|
||||
txGood++;
|
||||
printPacket("Completed sending", p);
|
||||
|
||||
// We are done sending that packet, release it
|
||||
packetPool.release(p);
|
||||
// DEBUG_MSG("Done with send\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Could we send right now (i.e. either not actively receving or transmitting)? */
|
||||
bool SimRadio::canSendImmediately()
|
||||
{
|
||||
// We wait _if_ we are partially though receiving a packet (rather than just merely waiting for one).
|
||||
// To do otherwise would be doubly bad because not only would we drop the packet that was on the way in,
|
||||
// we almost certainly guarantee no one outside will like the packet we are sending.
|
||||
bool busyTx = sendingPacket != NULL;
|
||||
bool busyRx = isReceiving && isActivelyReceiving();
|
||||
|
||||
if (busyTx || busyRx) {
|
||||
if (busyTx)
|
||||
DEBUG_MSG("Can not send yet, busyTx\n");
|
||||
if (busyRx)
|
||||
DEBUG_MSG("Can not send yet, busyRx\n");
|
||||
return false;
|
||||
} else
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SimRadio::isActivelyReceiving()
|
||||
{
|
||||
return false; // TODO check how this should be simulated
|
||||
}
|
||||
|
||||
bool SimRadio::isChannelActive()
|
||||
{
|
||||
return false; // TODO ask simulator
|
||||
}
|
||||
|
||||
/** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */
|
||||
bool SimRadio::cancelSending(NodeNum from, PacketId id)
|
||||
{
|
||||
auto p = txQueue.remove(from, id);
|
||||
if (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);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void SimRadio::onNotify(uint32_t notification)
|
||||
{
|
||||
switch (notification) {
|
||||
case ISR_TX:
|
||||
handleTransmitInterrupt();
|
||||
DEBUG_MSG("tx complete - starting timer\n");
|
||||
startTransmitTimer();
|
||||
break;
|
||||
case ISR_RX:
|
||||
DEBUG_MSG("rx complete - starting timer\n");
|
||||
break;
|
||||
case TRANSMIT_DELAY_COMPLETED:
|
||||
DEBUG_MSG("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");
|
||||
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");
|
||||
setTransmitDelay(); // reset random delay
|
||||
} else {
|
||||
// Send any outgoing packets we have ready
|
||||
MeshPacket *txp = txQueue.dequeue();
|
||||
assert(txp);
|
||||
startSend(txp);
|
||||
// Packet has been sent, count it toward our TX airtime utilization.
|
||||
uint32_t xmitMsec = getPacketTime(txp);
|
||||
airTime->logAirtime(TX_LOG, xmitMsec);
|
||||
|
||||
delay(xmitMsec); // Model the time it is busy sending
|
||||
completeSending();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// DEBUG_MSG("done with txqueue\n");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assert(0); // We expected to receive a valid notification from the ISR
|
||||
}
|
||||
}
|
||||
|
||||
/** start an immediate transmit */
|
||||
void SimRadio::startSend(MeshPacket * txp)
|
||||
{
|
||||
printPacket("Starting low level send", txp);
|
||||
size_t numbytes = beginSending(txp);
|
||||
MeshPacket* p = packetPool.allocCopy(*txp);
|
||||
perhapsDecode(p);
|
||||
Compressed c = Compressed_init_default;
|
||||
c.portnum = p->decoded.portnum;
|
||||
// DEBUG_MSG("Sending back to simulator with portNum %d\n", p->decoded.portnum);
|
||||
if (p->decoded.payload.size <= sizeof(c.data.bytes)) {
|
||||
memcpy(&c.data.bytes, p->decoded.payload.bytes, p->decoded.payload.size);
|
||||
c.data.size = p->decoded.payload.size;
|
||||
} else {
|
||||
DEBUG_MSG("Payload size is larger than compressed message allows! Sending empty payload.\n");
|
||||
}
|
||||
p->decoded.payload.size = pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), Compressed_fields, &c);
|
||||
p->decoded.portnum = PortNum_SIMULATOR_APP;
|
||||
service.sendToPhone(p); // Sending back to simulator
|
||||
}
|
||||
|
||||
|
||||
void SimRadio::startReceive(MeshPacket *p) {
|
||||
isReceiving = true;
|
||||
size_t length = getPacketLength(p);
|
||||
uint32_t xmitMsec = getPacketTime(length);
|
||||
delay(xmitMsec); // Model the time it is busy receiving
|
||||
handleReceiveInterrupt(p);
|
||||
}
|
||||
|
||||
|
||||
void SimRadio::handleReceiveInterrupt(MeshPacket *p)
|
||||
{
|
||||
DEBUG_MSG("HANDLE RECEIVE INTERRUPT\n");
|
||||
uint32_t xmitMsec;
|
||||
assert(isReceiving);
|
||||
isReceiving = false;
|
||||
|
||||
// read the number of actually received bytes
|
||||
size_t length = getPacketLength(p);
|
||||
xmitMsec = getPacketTime(length);
|
||||
// DEBUG_MSG("Payload size %d vs length (includes header) %d\n", p->decoded.payload.size, length);
|
||||
|
||||
MeshPacket *mp = packetPool.allocCopy(*p); // keep a copy in packtPool
|
||||
mp->which_payload_variant = MeshPacket_decoded_tag; // Mark that the payload is already decoded
|
||||
|
||||
printPacket("Lora RX", mp);
|
||||
|
||||
airTime->logAirtime(RX_LOG, xmitMsec);
|
||||
|
||||
deliverToReceiver(mp);
|
||||
}
|
||||
|
||||
size_t SimRadio::getPacketLength(MeshPacket *mp) {
|
||||
auto &p = mp->decoded;
|
||||
return (size_t)p.payload.size+sizeof(PacketHeader);
|
||||
}
|
||||
|
||||
int16_t SimRadio::readData(uint8_t* data, size_t len) {
|
||||
int16_t state = RADIOLIB_ERR_NONE;
|
||||
|
||||
if(state == RADIOLIB_ERR_NONE) {
|
||||
// add null terminator
|
||||
data[len] = 0;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
87
src/platform/portduino/SimRadio.h
Normal file
87
src/platform/portduino/SimRadio.h
Normal file
@@ -0,0 +1,87 @@
|
||||
#pragma once
|
||||
|
||||
#include "RadioInterface.h"
|
||||
#include "MeshPacketQueue.h"
|
||||
#include "wifi/WiFiServerAPI.h"
|
||||
|
||||
#define RADIOLIB_EXCLUDE_HTTP
|
||||
#include <RadioLib.h>
|
||||
|
||||
class SimRadio : public RadioInterface
|
||||
{
|
||||
enum PendingISR { ISR_NONE = 0, ISR_RX, ISR_TX, TRANSMIT_DELAY_COMPLETED };
|
||||
|
||||
/**
|
||||
* Debugging counts
|
||||
*/
|
||||
uint32_t rxBad = 0, rxGood = 0, txGood = 0;
|
||||
|
||||
MeshPacketQueue txQueue = MeshPacketQueue(MAX_TX_QUEUE);
|
||||
|
||||
public:
|
||||
SimRadio();
|
||||
|
||||
/** MeshService needs this to find our active instance
|
||||
*/
|
||||
static SimRadio *instance;
|
||||
|
||||
|
||||
virtual ErrorCode send(MeshPacket *p) override;
|
||||
|
||||
/** can we detect a LoRa preamble on the current channel? */
|
||||
virtual bool isChannelActive();
|
||||
|
||||
/** are we actively receiving a packet (only called during receiving state)
|
||||
* This method is only public to facilitate debugging. Do not call.
|
||||
*/
|
||||
virtual bool isActivelyReceiving();
|
||||
|
||||
/** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */
|
||||
virtual bool cancelSending(NodeNum from, PacketId id) override;
|
||||
|
||||
/**
|
||||
* Start waiting to receive a message
|
||||
*
|
||||
* External functions can call this method to wake the device from sleep.
|
||||
*/
|
||||
virtual void startReceive(MeshPacket *p);
|
||||
|
||||
protected:
|
||||
/// are _trying_ to receive a packet currently (note - we might just be waiting for one)
|
||||
bool isReceiving = false;
|
||||
|
||||
private:
|
||||
|
||||
void setTransmitDelay();
|
||||
|
||||
/** random timer with certain min. and max. settings */
|
||||
void startTransmitTimer(bool withDelay = true);
|
||||
|
||||
/** timer scaled to SNR of to be flooded packet */
|
||||
void startTransmitTimerSNR(float snr);
|
||||
|
||||
void handleTransmitInterrupt();
|
||||
void handleReceiveInterrupt(MeshPacket *p);
|
||||
|
||||
void onNotify(uint32_t notification);
|
||||
|
||||
// start an immediate transmit
|
||||
virtual void startSend(MeshPacket *txp);
|
||||
|
||||
// derive packet length
|
||||
size_t getPacketLength(MeshPacket *p);
|
||||
|
||||
int16_t readData(uint8_t* str, size_t len);
|
||||
|
||||
protected:
|
||||
/** Could we send right now (i.e. either not actively receiving or transmitting)? */
|
||||
virtual bool canSendImmediately();
|
||||
|
||||
|
||||
/**
|
||||
* If a send was in progress finish it and return the buffer to the pool */
|
||||
void completeSending();
|
||||
|
||||
};
|
||||
|
||||
extern SimRadio *simRadio;
|
||||
@@ -5,5 +5,5 @@ build_flags = ${nrf52840_base.build_flags} -Ivariants/Dongle_nRF52840-pca10059-v
|
||||
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/Dongle_nRF52840-pca10059-v1>
|
||||
lib_deps =
|
||||
${nrf52840_base.lib_deps}
|
||||
https://github.com/ZinggJM/GxEPD2.git
|
||||
zinggjm/GxEPD2@^1.4.9
|
||||
debug_tool = jlink
|
||||
|
||||
@@ -17,5 +17,5 @@ build_flags = ${nrf52840_base.build_flags} -Ivariants/lora_relay_v1
|
||||
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/lora_relay_v1>
|
||||
lib_deps =
|
||||
${nrf52840_base.lib_deps}
|
||||
SparkFun BQ27441 LiPo Fuel Gauge Arduino Library
|
||||
TFT_eSPI
|
||||
sparkfun/SparkFun BQ27441 LiPo Fuel Gauge Arduino Library@^1.1.0
|
||||
bodmer/TFT_eSPI@^2.4.76
|
||||
@@ -19,5 +19,5 @@ build_flags = ${nrf52840_base.build_flags} -Ivariants/lora_relay_v2
|
||||
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/lora_relay_v2>
|
||||
lib_deps =
|
||||
${nrf52840_base.lib_deps}
|
||||
SparkFun BQ27441 LiPo Fuel Gauge Arduino Library
|
||||
TFT_eSPI
|
||||
sparkfun/SparkFun BQ27441 LiPo Fuel Gauge Arduino Library@^1.1.0
|
||||
bodmer/TFT_eSPI@^2.4.76
|
||||
|
||||
@@ -23,8 +23,9 @@ build_flags =
|
||||
-DTFT_BL=32
|
||||
-DSPI_FREQUENCY=40000000
|
||||
-DSPI_READ_FREQUENCY=16000000
|
||||
-DDISABLE_ALL_LIBRARY_WARNINGS
|
||||
lib_ignore =
|
||||
m5stack-core
|
||||
lib_deps =
|
||||
${esp32_base.lib_deps}
|
||||
bodmer/TFT_eSPI@^2.4.61
|
||||
bodmer/TFT_eSPI@^2.4.76
|
||||
@@ -11,8 +11,8 @@ build_flags =
|
||||
-DM5STACK
|
||||
lib_deps =
|
||||
${esp32_base.lib_deps}
|
||||
zinggjm/GxEPD2@^1.4.5
|
||||
lewisxhe/PCF8563_Library@^0.0.1
|
||||
zinggjm/GxEPD2@^1.4.9
|
||||
lewisxhe/PCF8563_Library@^1.0.1
|
||||
board_build.f_cpu = 240000000L
|
||||
upload_protocol = esptool
|
||||
upload_port = /dev/ttyACM*
|
||||
|
||||
@@ -1,23 +1,3 @@
|
||||
; The Portduino based sim environment on top of any host OS, all hardware will be simulated
|
||||
[portduino_base]
|
||||
build_src_filter =
|
||||
${env.build_src_filter}
|
||||
-<platform/esp32/>
|
||||
-<nimble/>
|
||||
-<platform/nrf52/>
|
||||
-<platform/stm32wl/>
|
||||
-<platform/rp2040>
|
||||
-<mesh/http/>
|
||||
-<modules/esp32>
|
||||
-<modules/Telemetry>
|
||||
+<../variants/portduino>
|
||||
lib_deps =
|
||||
${env.lib_deps}
|
||||
${networking_base.lib_deps}
|
||||
rweather/Crypto
|
||||
https://github.com/meshtastic/RadioLib.git#5582ac30578ff3f53f20630a00b2a8a4b8f92c74
|
||||
build_flags = ${arduino_base.build_flags} -Isrc/platform/portduino
|
||||
|
||||
[env:native]
|
||||
platform = https://github.com/meshtastic/platform-native.git
|
||||
build_flags = ${portduino_base.build_flags} -O0 -I variants/portduino
|
||||
|
||||
@@ -4,4 +4,4 @@ extends = nrf52_base
|
||||
board = ppr
|
||||
lib_deps =
|
||||
${arduino_base.lib_deps}
|
||||
UC1701
|
||||
industruino/UC1701@^1.1.0
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user