Compare commits

...

335 Commits

Author SHA1 Message Date
Jm Casler
3c6a2f7bb6 Bump to 1.3.19 2022-06-16 05:24:08 -07:00
Thomas Göttgens
1996a2a193 Merge pull request #1520 from meshtastic/radiolib-fix
Tryfix Portduino Radiolib
2022-06-16 12:30:23 +02:00
Thomas Göttgens
b40abbf3ad Tryfix Portduino Radiolib 2022-06-16 12:22:01 +02:00
Jm Casler
8684fd1c49 Bump to .18 2022-06-15 19:00:40 -07:00
Thomas Göttgens
2a6633a666 Merge pull request #1518 from meshtastic/create-pull-request/patch
TEST: Push out LocalConfig Object on app Handshake
2022-06-15 19:43:05 +02:00
caveman99
0943e5f500 [create-pull-request] automated change 2022-06-15 17:40:08 +00:00
Ben Meadors
a1dc350231 Changed default baud to 115200 (#1517)
Co-authored-by: Thomas Göttgens <tgoettgens@gmail.com>
2022-06-15 11:44:37 -05:00
Thomas Göttgens
d5a258cebd Merge pull request #1516 from meshtastic/LocalConfig
add file version to local savefiles
2022-06-15 18:05:52 +02:00
Thomas Göttgens
125f76d984 Don't use rmdir_r but roll our own version. 2022-06-15 17:52:37 +02:00
Thomas Göttgens
b127479961 - Refactored factory reset a bit to not installDefaultDeviceState twice on ESP32
- clear BLE bonds on settings version increase
2022-06-15 17:09:42 +02:00
Thomas Göttgens
d18aa2e7cb add file version to local savefiles 2022-06-15 16:52:04 +02:00
Thomas Göttgens
d301144efe Merge pull request #1515 from meshtastic/create-pull-request/patch
Changes by create-pull-request action
2022-06-15 16:45:11 +02:00
caveman99
058b5ceddd [create-pull-request] automated change 2022-06-15 14:44:33 +00:00
Thomas Göttgens
e85baf00c4 Merge pull request #1511 from meshtastic/radiolib-fix
Set TX Power to some meaningful value
2022-06-13 23:24:37 +02:00
Thomas Göttgens
4a6cad6e46 Set TX Power to some meaningful value 2022-06-13 23:00:50 +02:00
Thomas Göttgens
bc05f98685 Merge pull request #1499 from meshtastic/radiolib-fix
new radiolib version (use upstream)
2022-06-13 21:33:51 +02:00
Thomas Göttgens
6e671d808a Our mod was accepted by RadioLib 2022-06-13 21:25:27 +02:00
Thomas Göttgens
1df3dd5f78 Merge branch 'master' of github.com:meshtastic/Meshtastic-device 2022-06-13 21:21:46 +02:00
Jm Casler
c9822dee93 Update to 1.13.17 2022-06-13 09:38:33 -07:00
Thomas Göttgens
e1783df49f Merge branch 'radiolib-fix' of github.com:meshtastic/Meshtastic-device
# Conflicts:
#	src/mesh/RadioLibInterface.h
2022-06-13 16:13:13 +02:00
Thomas Göttgens
6b8afdadc2 New variant of Radiolib patch 2022-06-13 16:10:16 +02:00
Thomas Göttgens
f918548e44 Merge branch 'master' of github.com:meshtastic/Meshtastic-device 2022-06-13 16:08:50 +02:00
GUVWAF
a1b07ed6aa Introduce contention window (CW) (#1500)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2022-06-13 08:21:18 -05:00
Thomas Göttgens
b059fb9e8e Merge branch 'master' of github.com:meshtastic/Meshtastic-device 2022-06-13 12:23:51 +02:00
Ben Meadors
553b35d0ad Consolidate power saving prefs (#1507)
* Fixed conversion linter warning

* Power saving consolidation

* Whoops
2022-06-12 19:56:32 -05:00
Thomas Göttgens
04478081c6 Merge pull request #1508 from meshtastic/crpytfix
Remove nRF Crypt Debug
2022-06-12 23:52:16 +02:00
Thomas Göttgens
7bd07db2a8 Remove nRF Crypt Debug 2022-06-12 23:35:59 +02:00
Thomas Göttgens
5c44c4f772 Remove Debug Code for Encryption 2022-06-12 23:29:27 +02:00
Thomas Göttgens
7ff940409e Merge branch 'master' of github.com:meshtastic/Meshtastic-device 2022-06-12 23:28:04 +02:00
Ben Meadors
cb5c32490c Merge branch 'master' into radiolib-fix 2022-06-12 15:27:58 -05:00
Thomas Göttgens
e0b63c6692 Merge pull request #1506 from meshtastic/1504-proposal-default-short-name-to-mac-last-4
implement #1504
2022-06-12 22:05:04 +02:00
Thomas Göttgens
dc8d1d9a84 implement #1504 2022-06-12 21:52:46 +02:00
Thomas Göttgens
710e2694ef Merge branch 'master' into radiolib-fix 2022-06-12 20:32:00 +02:00
Thomas Göttgens
7594140afc actual change to our interface 2022-06-12 20:31:23 +02:00
Thomas Göttgens
e793d933c6 Merge branch 'master' of github.com:meshtastic/Meshtastic-device 2022-06-12 20:28:39 +02:00
Thomas Göttgens
61427528b6 Merge pull request #1505 from meshtastic/caveman99-patch-1
fix C++ warnings
2022-06-12 18:39:46 +02:00
Thomas Göttgens
47ad27f9f6 fix C++ warnings
The cast throws errors about ambiguous conversions. There's a prototype of requestFrom(uint8_t address, uint8_t length) so just use that one.
2022-06-12 17:59:16 +02:00
Thomas Göttgens
77f096e56c Merge branch 'master' of github.com:meshtastic/Meshtastic-device 2022-06-12 17:37:43 +02:00
Ben Meadors
5106433572 Removed phone_timeout_secs pref references (#1503) 2022-06-12 09:44:23 -05:00
Ben Meadors
4458b470aa Don't enable environmental telemetry by default (#1502)
* INA219 + INA260 support in telemetry

* Protobuf update

* Fixes + debug statement

* Fix size

* Fix conversion from mv

* Added getRegisterValue for i2cscan

* Accidentally left this in

* Removed line
2022-06-12 07:14:33 -05:00
Ben Meadors
90957e6994 INA260 + INA219 sensor support (#1501)
* INA219 + INA260 support in telemetry

* Protobuf update

* Fixes + debug statement

* Fix size

* Fix conversion from mv

* Added getRegisterValue for i2cscan
2022-06-11 16:44:56 -05:00
Thomas Göttgens
b73fd32f71 Merge branch 'master' into radiolib-fix 2022-06-10 20:39:50 +02:00
Thomas Göttgens
2a3272b7d0 patch radiolib on-the-fly while building. 2022-06-10 20:38:56 +02:00
Ben Meadors
3fd756900a Refactoring some of the i2c boilerplate (#1498)
* Refactoring some of the i2c boilerplate

* Default value

* Debug statement
2022-06-10 12:04:04 -05:00
Thomas Göttgens
beb8bc9e72 Merge pull request #1496 from benner/fix/NodeDB_without_FSCom
Compile when FSCom is not defined (NodeDB.cpp)
2022-06-07 22:22:20 +02:00
Thomas Göttgens
1ad5cdc93c Merge branch 'master' into fix/NodeDB_without_FSCom 2022-06-07 21:57:26 +02:00
Nerijus Bendžiūnas
e8e72d2e08 Compile when FSCom is not defined (NodeDB.cpp) 2022-06-07 20:55:05 +03:00
Thomas Göttgens
1d0badd468 Merge pull request #1495 from benner/fix/typo
Correctly print script name in platformio-custom.py
2022-06-07 11:39:47 +02:00
Nerijus Bendžiūnas
9e87be4f22 Correctly print script name in platformio-custom.py 2022-06-07 12:26:01 +03:00
Jm Casler
97899aed26 1.3.16 2022-06-06 22:10:18 -07:00
Thomas Göttgens
0ee4ba4975 Merge pull request #1494 from meshtastic/fix-1493
fixes power LED on T-Echo and T-Beam
2022-06-06 19:23:23 +02:00
Thomas Göttgens
bbcccde787 Merge branch 'fix-1493' of github.com:meshtastic/Meshtastic-device 2022-06-06 19:15:14 +02:00
Thomas Göttgens
42c285bc31 Merge branch 'master' of github.com:meshtastic/Meshtastic-device 2022-06-06 19:14:43 +02:00
Thomas Göttgens
c831242f25 fix nrf build 2022-06-06 19:14:30 +02:00
Thomas Göttgens
3c6f36c8f7 Merge branch 'master' into fix-1493 2022-06-06 18:57:51 +02:00
Thomas Göttgens
dfde6cc9c1 Merge pull request #1490 from meshtastic/CryptFix
Crypt fix. Please leave branch open
2022-06-06 18:57:27 +02:00
Thomas Göttgens
7816800012 Merge branch 'master' into CryptFix 2022-06-06 18:49:38 +02:00
Thomas Göttgens
ebf132ad21 Bug-1493 2022-06-06 18:48:22 +02:00
Thomas Göttgens
67cf3018b5 Merge branch 'master' of github.com:meshtastic/Meshtastic-device 2022-06-06 18:27:28 +02:00
Ben Meadors
eafbef0c2f Scan for i2c sensors in environmental telemetry if enabled (#1492)
* Scan for i2c sensors in environmental telemetry if enabled

* Update TelemetrySensor.h

* Added surpression.

* Remove suppression and fix real bug

* Interrogate BME sensor id registers
2022-06-05 09:50:06 -05:00
Ben Meadors
4ab831c103 Fix nagging bool linter warnings (#1491) 2022-06-04 07:28:58 -05:00
Thomas Göttgens
3df5ec0b11 Merge pull request #1479 from meshtastic/ProtoFix
If we get an unreadable buffer, don't try to process it.
2022-06-04 11:07:00 +02:00
Thomas Göttgens
c5c2765fb4 Merge branch 'master' into ProtoFix 2022-06-04 10:49:36 +02:00
Thomas Göttgens
df9e9bc223 Bugfix for nRF Crypto 90% done, includes heavy debug code, do not merge for now. 2022-06-04 10:37:24 +02:00
Thomas Göttgens
1ff0032c20 Merge branch 'master' of github.com:meshtastic/Meshtastic-device 2022-06-04 10:35:42 +02:00
Jm Casler
18024f1d25 Merge pull request #1489 from mc-hamster/master
Disabled the unset welcome screen
2022-06-04 01:19:44 -07:00
Jm Casler
313c50d6cf Merge branch 'master' into master 2022-06-03 21:55:27 -07:00
Jm Casler
80e08f6de9 Disabled the unset welcome screen 2022-06-03 21:51:47 -07:00
Jm Casler
5a256323e2 Merge pull request #1488 from mc-hamster/master
Change default screen on to 10 minutes
2022-06-03 20:57:23 -07:00
Jm Casler
45495c51e6 Merge branch 'meshtastic:master' into master 2022-06-03 20:38:28 -07:00
Jm Casler
40ded630d0 Change default screen on to 10 minutes 2022-06-03 20:38:13 -07:00
Jm Casler
432d06741e Update version.properties 2022-06-03 18:49:18 -07:00
Jm Casler
03b7f2f837 Merge pull request #1487 from meshtastic/create-pull-request/patch
Changes by create-pull-request action
2022-06-03 18:47:52 -07:00
mc-hamster
2e1b895791 [create-pull-request] automated change 2022-06-04 01:47:29 +00:00
Jm Casler
9821a0535b Bump to 1.3.14 2022-06-03 14:32:32 -07:00
Thomas Göttgens
0b666b827d Merge branch 'master' of github.com:meshtastic/Meshtastic-device 2022-06-03 15:38:50 +02:00
Thomas Göttgens
235cacf9b9 Merge pull request #1485 from markbirss/master
Update EInkDisplay2.cpp
2022-06-03 15:09:56 +02:00
Mark Trevor Birss
db28a1562e Update EInkDisplay2.cpp
Fix E-Ink not powering up bug at startup
2022-06-03 14:21:27 +02:00
Jm Casler
f61d2d9eb4 Merge pull request #1484 from meshtastic/create-pull-request/patch
Changes by create-pull-request action
2022-06-02 18:12:35 -07:00
mc-hamster
5aef58e87f [create-pull-request] automated change 2022-06-03 01:07:08 +00:00
Thomas Göttgens
77a2054254 Merge pull request #1480 from markbirss/master
Add M5Stack CoreInk 1.54 inch e-Ink - HopeRF95 Support
2022-06-01 20:56:05 +02:00
Mark Trevor Birss
48ee995e0d Update EInkDisplay2.cpp 2022-06-01 20:33:51 +02:00
Mark Trevor Birss
c7dfd245e3 Update EInkDisplay2.cpp 2022-06-01 20:31:39 +02:00
Mark Trevor Birss
4e813b098a Update platformio.ini 2022-06-01 20:30:21 +02:00
Thomas Göttgens
e57dbdd26c Merge branch 'master' into master 2022-06-01 20:28:12 +02:00
Mark Trevor Birss
9512ea45de Update EInkDisplay2.cpp 2022-06-01 19:27:38 +02:00
Mark Trevor Birss
0d09767efd Update variant.h 2022-06-01 18:11:06 +02:00
Mark Trevor Birss
5828e6f423 Update variant.h 2022-06-01 18:08:40 +02:00
Mark Trevor Birss
c7a9ce7f49 Update variant.h 2022-06-01 18:08:13 +02:00
Mark Trevor Birss
95f091041b Update variant.h 2022-06-01 17:53:19 +02:00
Mark Trevor Birss
f33e6a0e66 Update platformio.ini 2022-06-01 17:49:10 +02:00
Mark Trevor Birss
fe8bfdb762 Update variant.h 2022-06-01 17:48:31 +02:00
Thomas Göttgens
e8afd4fb4b If we get an unreadable buffer, don't try to process it. 2022-06-01 17:09:57 +02:00
Ben Meadors
71a43a97cc Bump to 13 2022-06-01 06:06:40 -05:00
Mark Trevor Birss
b34b26518b Update EInkDisplay2.cpp 2022-06-01 11:28:18 +02:00
Mark Trevor Birss
b9f25eb85c Update EInkDisplay2.cpp 2022-06-01 11:21:09 +02:00
Mark Trevor Birss
a7fbe024e4 Create variant.h 2022-06-01 11:12:45 +02:00
Mark Trevor Birss
1f7fee8e2a Create platformio.ini 2022-06-01 11:10:49 +02:00
Mark Trevor Birss
b8e7c6ee7a Update platformio.ini 2022-06-01 11:09:21 +02:00
Thomas Göttgens
32245a1a8d Merge pull request #1477 from meshtastic/create-pull-request/patch
Changes by create-pull-request action
2022-05-30 21:40:52 +02:00
Thomas Göttgens
f6982ca726 fix building with new peotobuf structure. 2022-05-30 21:12:27 +02:00
caveman99
03bbc5eff4 [create-pull-request] automated change 2022-05-30 19:00:01 +00:00
Ben Meadors
0767c0b0e8 Converted to jgromes/RadioLib upstream and pegged to latest ref (#1472)
* Converted to jgromes/RadioLib upstream and pegged to latest ref
2022-05-29 19:30:20 -05:00
Thomas Göttgens
0d574e35c6 Merge pull request #1473 from meshtastic/LocalConfig
fixed typo in AdminModule
2022-05-29 16:40:14 +02:00
Thomas Göttgens
b88e75cf2a Fixed Typo in get Config 2022-05-29 16:31:30 +02:00
Jm Casler
6306c53bfe Bump to .12 2022-05-27 12:21:59 -07:00
Jm Casler
8db57601bf Merge pull request #1471 from meshtastic/create-pull-request/patch
Changes by create-pull-request action
2022-05-27 12:20:31 -07:00
mc-hamster
1b8830e7df [create-pull-request] automated change 2022-05-27 19:19:57 +00:00
Jm Casler
0411401184 Bump to .11 2022-05-25 20:47:48 -07:00
Jm Casler
5678221ead Merge pull request #1429 from mc-hamster/compression
Compression
2022-05-24 18:19:11 -07:00
Jm Casler
c5f3cad0f9 Fixed missing brackets 2022-05-24 18:06:53 -07:00
Jm Casler
f3c15eb6cc Completed compression. Tested between two devices. 2022-05-24 17:42:46 -07:00
Jm Casler
e218bba87e Merge branch 'meshtastic:master' into compression 2022-05-24 16:48:28 -07:00
Jm Casler
c04d62158b Merge pull request #1469 from meshtastic/create-pull-request/patch
Changes by create-pull-request action
2022-05-24 08:38:31 -07:00
Thomas Göttgens
03affc9e73 Merge branch 'master' into create-pull-request/patch 2022-05-24 10:54:38 +02:00
Thomas Göttgens
25bf97316d Merge pull request #1468 from meshtastic/LocalConfig
make sure all segments are enabled and saved
2022-05-24 10:26:26 +02:00
Jm Casler
76ef240a3d Merge branch 'master' into LocalConfig 2022-05-24 00:21:46 -07:00
Jm Casler
3f171b29f7 Merge pull request #1466 from LucyHosking/master
Implemented hidden SSID
2022-05-24 00:21:32 -07:00
Jm Casler
dca6c27c9d Update from config.payloadVariant to config.wifi 2022-05-23 22:08:33 -07:00
Jm Casler
2631a9324e Update from radioConfig.preferences to config.lora 2022-05-23 22:06:38 -07:00
Jm Casler
c64f4bbb11 Merge pull request #97 from meshtastic/new-compression
Update compression branch
2022-05-23 21:19:11 -07:00
Jm Casler
94f7e7037d Merge branch 'compression' into new-compression 2022-05-23 21:18:45 -07:00
mc-hamster
a0b4b4efa1 [create-pull-request] automated change 2022-05-24 04:10:51 +00:00
Ben Meadors
d68d85590b Merge branch 'master' into master 2022-05-22 07:50:32 -05:00
Thomas Göttgens
800a4200ef make sure all segments are enabled and saved 2022-05-22 13:54:24 +02:00
Thomas Göttgens
9c50a76ea2 Merge pull request #1464 from meshtastic/LocalConfig
Segemented config works for me (TM)
2022-05-22 13:41:47 +02:00
Thomas Göttgens
4a41694ec5 Merge branch 'LocalConfig' of github.com:meshtastic/Meshtastic-device 2022-05-22 13:28:32 +02:00
Thomas Göttgens
6bb3861e95 Moduleconfig also changed to localConfig Model. 2022-05-22 13:27:56 +02:00
Thomas Göttgens
e8262540d4 Merge branch 'master' of github.com:meshtastic/Meshtastic-device 2022-05-22 13:06:08 +02:00
Thomas Göttgens
2b6f632a50 Merge branch 'master' into master 2022-05-22 13:03:13 +02:00
Thomas Göttgens
bddab68110 Merge pull request #1467 from meshtastic/create-pull-request/patch
Changes by create-pull-request action
2022-05-22 13:01:45 +02:00
caveman99
c4f69cbcc0 [create-pull-request] automated change 2022-05-22 10:59:47 +00:00
Thomas Göttgens
85f5c7a40b Merge branch 'master' of github.com:meshtastic/Meshtastic-device 2022-05-22 12:17:09 +02:00
LucyHosking
e0c5e4d441 Implemented hidden SSID
https://github.com/meshtastic/Meshtastic-device/issues/1308
2022-05-21 20:10:36 -07:00
Sacha Weatherstone
8dfdc11af9 Merge branch 'master' into LocalConfig 2022-05-22 12:57:26 +10:00
Jm Casler
ba1937de39 Merge pull request #1465 from meshtastic/create-pull-request/patch
Changes by create-pull-request action
2022-05-21 19:14:23 -07:00
mc-hamster
2e45d4f0fd [create-pull-request] automated change 2022-05-22 00:44:37 +00:00
Jm Casler
b1f309545e Delete proto 2022-05-21 17:39:50 -07:00
Jm Casler
22764425f7 updating proto submodule to latest 2022-05-21 17:10:24 -07:00
Thomas Göttgens
5e8d49d24b missed one 2022-05-21 22:51:34 +02:00
Thomas Göttgens
53e9f4df46 Segemented config works for me (TM)
Small GPS Fix that cropped up while testing included.
2022-05-21 22:38:33 +02:00
Garth Vander Houwen
33938f73a6 Merge pull request #1463 from meshtastic/create-pull-request/patch
Changes by create-pull-request action
2022-05-21 13:01:09 -07:00
caveman99
e4484270b1 [create-pull-request] automated change 2022-05-21 19:46:36 +00:00
Garth Vander Houwen
964510ef52 Merge pull request #1462 from meshtastic/garthvh-patch-1
Update GitHub action Submodule
2022-05-21 12:45:50 -07:00
Garth Vander Houwen
b108540b08 Update GitHub action 2022-05-21 12:24:50 -07:00
Thomas Göttgens
db35b92b6f Merge pull request #1461 from meshtastic/UBXFIX
remove duplicate GPS setting
2022-05-21 21:05:14 +02:00
Thomas Göttgens
5d22efd8a8 remove duplicate GPS setting 2022-05-21 20:52:43 +02:00
Thomas Göttgens
49ccb77e43 Merge pull request #1457 from meshtastic/UBXFIX
Streamline GPS Init
2022-05-18 18:13:40 +01:00
Thomas Göttgens
3d0d45a695 More UBX stuff from 1.2 2022-05-18 18:29:26 +02:00
Thomas Göttgens
2e39900f78 Merge branch 'UBXFIX' of github.com:meshtastic/Meshtastic-device 2022-05-18 18:18:32 +02:00
Thomas Göttgens
5e82423331 More UBX fixes 2022-05-18 18:16:23 +02:00
Thomas Göttgens
dd8111e737 Merge branch 'master' of github.com:meshtastic/Meshtastic-device 2022-05-18 18:13:51 +02:00
Thomas Göttgens
9b02841506 Merge branch 'master' into UBXFIX 2022-05-18 15:19:27 +01:00
Thomas Göttgens
3c5a096873 Streamline GPS Init 2022-05-18 16:16:59 +02:00
Thomas Göttgens
93521f7b39 Merge pull request #1454 from meshtastic/t-echo
fix GPS and Buttons on T-Echo and log UBX (1.3)
2022-05-17 20:10:42 +01:00
Thomas Göttgens
bdcdc1485c Merge branch 't-echo' of github.com:meshtastic/Meshtastic-device 2022-05-17 20:55:29 +02:00
Thomas Göttgens
fdc10acfdd Merge branch 'master' of github.com:meshtastic/Meshtastic-device 2022-05-17 20:54:17 +02:00
Thomas Göttgens
ac93e3196e Don't try to be too smart 2022-05-17 20:53:57 +02:00
Thomas Göttgens
e5439c21ab Merge branch 'master' into t-echo 2022-05-17 18:55:35 +01:00
Thomas Göttgens
7f9bb5748e log UBX Init 2022-05-17 19:54:29 +02:00
Thomas Göttgens
894b091553 Fix ubox gps too or at least log errors 2022-05-17 19:48:48 +02:00
Thomas Göttgens
7576270423 switch GPS back to 9600 baud, seems to work better now we only use the 2 sentences 2022-05-17 19:09:12 +02:00
Thomas Göttgens
6b8f83cd71 don't wake t-echo through the touch button 2022-05-17 13:01:15 +02:00
Thomas Göttgens
fdc3a6e432 Merge pull request #1453 from meshtastic/PIO6-fix
Make PIO6 happy again
2022-05-17 10:42:46 +01:00
Thomas Göttgens
49d8c581bd missed one here as well... 2022-05-17 11:26:03 +02:00
Thomas Göttgens
c15da3c104 Make PIO6 happy again 2022-05-17 11:14:21 +02:00
Sacha Weatherstone
12c46ced45 update protobufs 2022-05-13 10:41:05 +10:00
Sacha Weatherstone
3ed9a05ac6 Update max channels in protos & remove batt_lvl from position flags 2022-05-13 10:30:01 +10:00
Sacha Weatherstone
3b4c8ad0e2 fix max message sizes for unused protobufs 2022-05-12 23:12:37 +10:00
Sacha Weatherstone
d9e2e09149 Fix NTP server initialization 2022-05-12 23:05:06 +10:00
Sacha Weatherstone
97713b2daa Increased NTP update frequency to 12 hours 2022-05-12 22:45:27 +10:00
Sacha Weatherstone
7799e1b7e6 Increased NTP update frequency to 1024 seconds 2022-05-12 22:06:36 +10:00
Sacha Weatherstone
38913bb661 Consistency fixes & repo cleanup 2022-05-12 20:45:30 +10:00
Sacha Weatherstone
14cbc439ab Update README.md 2022-05-12 20:04:10 +10:00
Sacha Weatherstone
6d15b9b82a Update main_matrix.yml 2022-05-12 20:03:53 +10:00
Sacha Weatherstone
2035ddf5a9 Add ntp server config option, remove old region logic 2022-05-11 18:30:29 +10:00
Thomas Göttgens
e91dedaab5 Merge pull request #1447 from meshtastic/create-pull-request/patch
Changes by create-pull-request action
2022-05-10 11:03:24 +01:00
Thomas Göttgens
54bf02352f Merge branch 'master' into create-pull-request/patch 2022-05-10 10:46:36 +01:00
Thomas Göttgens
3f415e3e8e Merge pull request #1448 from meshtastic/M5STACK
Make M5Stack Canon Hardware
2022-05-10 10:45:47 +01:00
Thomas Göttgens
7133e6e89b Use canon HW Identifier for M5 2022-05-10 11:10:32 +02:00
Thomas Göttgens
e1d49a3632 Buzzer Support for M5Stack 2022-05-10 11:07:49 +02:00
caveman99
f26fb9408e [create-pull-request] automated change 2022-05-10 08:20:52 +00:00
Thomas Göttgens
1e48989e2d Merge pull request #1446 from meshtastic/RAK14006
Support detecting RAK14006 KB
2022-05-09 20:29:29 +01:00
Thomas Göttgens
e48285a33a Support detecting RAK14006 KB 2022-05-09 20:12:49 +02:00
Thomas Göttgens
7f0fd642ec Merge pull request #1445 from meshtastic/M5Stack
Support M5Stack
2022-05-09 19:05:46 +01:00
Thomas Göttgens
5ee8c56c94 Support M5Stack with LORA868 (RA01H) Module and TFT Display (PRIVATE_HW, Canon Hardware TBD) 2022-05-09 19:50:39 +02:00
Sacha Weatherstone
4940822ae8 Merge pull request #1444 from GUVWAF/master
Optimize retransmission timer
2022-05-09 09:33:16 +10:00
Sacha Weatherstone
8b42b78033 Merge branch 'master' into master 2022-05-08 00:23:18 +10:00
GUVWAF
a7f4263db4 Optimize retransmission timer
Based on airtime of packet + transmit, processing and CAD delays
2022-05-07 15:43:35 +02:00
GUVWAF
348e78718d Call cancelSending in stopRetransmission
This also removes pending packet from txQueue if it was already in there
2022-05-07 15:39:14 +02:00
Sacha Weatherstone
0ec6771cf7 Fix build when BATTERY_PIN is set 2022-05-07 20:47:52 +10:00
Sacha Weatherstone
5e7b372345 Satisfy cppcheck 2022-05-07 20:36:15 +10:00
Sacha Weatherstone
6b0ce6b729 Finish config transition 2022-05-07 20:31:21 +10:00
Sacha Weatherstone
c07976438b fix old submodule 2022-05-07 13:37:58 +10:00
Sacha Weatherstone
eb6dd6b53d Merge branch 'master' of github.com:meshtastic/Meshtastic-device 2022-05-07 13:34:36 +10:00
Sacha Weatherstone
ea86f76393 Move LoRa config out of primary channel 2022-05-07 13:34:06 +10:00
Thomas Göttgens
b699e5e6cd Merge pull request #1441 from meshtastic/patch-1-1
Enable Malloc Support in nanopb
2022-05-06 21:26:38 +01:00
Thomas Göttgens
4fb0cfa909 Enable Malloc Support in nanopb 2022-05-06 22:16:51 +02:00
Thomas Göttgens
bb5b10eef3 Merge pull request #1440 from meshtastic/NO-SCREEN
Make #define NO_SCREEN work again
2022-05-06 14:50:54 +01:00
Thomas Göttgens
b5cc304336 Make #define NO_SCREEN work again 2022-05-06 15:41:37 +02:00
Thomas Göttgens
1812843363 Merge pull request #1439 from meshtastic/RAK18001
RAK18001 Buzzer Support
2022-05-06 13:31:37 +01:00
Thomas Göttgens
628740d6d1 Support Buzzer in Slot C 2022-05-06 14:20:46 +02:00
Thomas Göttgens
251365dca7 Merge branch 'master' of github.com:meshtastic/Meshtastic-device 2022-05-06 14:05:51 +02:00
Ben Meadors
223c706e91 Use meshtastic fork of arduino thread lib 2022-05-05 13:54:21 -05:00
Rockwell Schrock
5e109d9648 Fix typo in calculation of NUM_ONLINE_SECS constant (#1436)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2022-05-05 13:46:39 -05:00
Ben Meadors
2b769279ae Moving platform-native into meshtastic fork (#1437) 2022-05-05 13:20:16 -05:00
Thomas Göttgens
8f8eff6f95 Merge branch 'master' of github.com:meshtastic/Meshtastic-device 2022-05-05 08:33:03 +02:00
Thomas Göttgens
02fe597f3f Merge pull request #1432 from meshtastic/patch-1
Forgot the readFromRTC for PCF8563 (T-Echo)
2022-05-04 16:25:47 +01:00
Thomas Göttgens
4d611ba2f0 Forgot the readFromRTC for PCF8563 (T-Echo) 2022-05-04 17:06:06 +02:00
Thomas Göttgens
403a0b2ddc Merge branch 'master' of github.com:meshtastic/Meshtastic-device 2022-05-04 09:17:06 +02:00
Sacha Weatherstone
211273cc08 Fix expected values in config setters 2022-05-04 12:52:44 +10:00
Sacha Weatherstone
8ba0a9bf87 Fix config switch 2022-05-03 22:16:50 +10:00
Sacha Weatherstone
f84286d138 Split config structure in two 2022-05-02 22:00:24 +10:00
Jm Casler
b980f3e311 Merge branch 'meshtastic:master' into compression 2022-05-01 21:02:07 -07:00
Sacha Weatherstone
399e053ebd workaround for undefined payload type on phoneapi 2022-05-02 13:04:05 +10:00
Jm Casler
d6b20ea623 Merge branch 'meshtastic:master' into compression 2022-05-01 19:35:26 -07:00
Ben Meadors
caac2ecb83 Compute config size and account for reloadconfig (#1428)
* Compute config size and account for reloadconfig

* Reload config and config_size
2022-05-01 20:30:19 -05:00
Sacha Weatherstone
7ae8601ba5 fix warnings 2022-05-02 10:24:28 +10:00
Sacha Weatherstone
8f038ced15 add handleSetConfig, remove team 2022-05-02 08:53:44 +10:00
Sacha Weatherstone
3a1f20821e Remove team and provision set_config 2022-05-02 08:35:31 +10:00
Sacha Weatherstone
057131b459 Merge pull request #1427 from meshtastic/radioconfig-refactor-telemetry
Radioconfig refactor telemetry
2022-05-02 08:16:06 +10:00
Ben Meadors
1040b0988a Removed unused members causing warnings 2022-05-01 15:37:34 -05:00
Ben Meadors
2ca0290662 Admin message implementation 2022-05-01 15:35:01 -05:00
Ben Meadors
163774bb1f Moved refactored prefs 2022-05-01 14:26:05 -05:00
Ben Meadors
6a8724213e Adafruit bus io is now required for sensor libs 2022-05-01 14:22:04 -05:00
Ben Meadors
cf64da21fb Move adc multiplier code into battery pin region to surpress warning 2022-05-01 14:21:30 -05:00
Sacha Weatherstone
c0d40895f8 Config rework - Init GetConfigResponse 2022-05-01 16:12:48 +10:00
Sacha Weatherstone
50326fbb6b Config rework - Init getConfig 2022-05-01 12:41:26 +10:00
Sacha Weatherstone
98cd19ea0f Config rework - Init getConfig 2022-05-01 12:39:48 +10:00
Mark Trevor Birss
8e996e3e63 Enable TXEN and RXEN for Waveshare LoRa Module (#1422)
This change enables RXEN TXEN for the use of the Waveshare Core1262-868M Anti-Interference SX1262 LoRa Module, EU868 Band
https://www.waveshare.com/core1262-868m.htm
2022-04-29 14:23:17 -05:00
Ben Meadors
53cc090814 Move sx1262 fixes upstream (#1421) 2022-04-29 07:46:44 -05:00
Thomas Göttgens
bfc2d30a46 Merge pull request #1419 from meshtastic/PCF8563
RTC Module support for T-Echo and others with PCF8563
2022-04-28 08:29:07 +02:00
Thomas Göttgens
516dff5b09 RTC Module support for T-Echo and others with PCF8563 2022-04-28 08:18:03 +02:00
mkinney
4df0e910b8 Update main_matrix.yml
add nano-g1
2022-04-27 10:23:20 -07:00
mkinney
3a5f492106 add nano_g1 to build (#1417) 2022-04-27 12:20:10 -05:00
Thomas Göttgens
2dbb9075a3 Merge pull request #1408 from Pedestrian11/patch-1
TTGO_T_ECHO to use batteries, PIN_EINK_PWR_ON must be set to high
2022-04-27 15:45:01 +02:00
Thomas Göttgens
e5715a0048 Merge branch 'master' into patch-1 2022-04-27 15:32:05 +02:00
Thomas Göttgens
629db8c718 Fix build errors and add a bit of failsafe 2022-04-27 15:30:27 +02:00
Ben Meadors
cc2a84afcd Bump version for release 2022-04-27 07:03:09 -05:00
Thomas Göttgens
6c1dc0d71a Merge pull request #1415 from meshtastic/RAK12002
I2C RTC Support (RAK12002)
2022-04-27 11:17:31 +02:00
Thomas Göttgens
9e97fac252 - implement generic support for on-device battery powered RTC Modules.
- implement support for I2C RV-3028 based RTC modules like the RAK12002
- pretty print some debug timestamps
2022-04-27 11:05:08 +02:00
Thomas Göttgens
3a9086dfc5 We may have RAK modules in Slot D pulling IO5 to Low permanently (like the RAK12002 RTC Module). React to assumed Long presses of the device button only 30 seconds after bootup to prevent a reboot loop. This is Particularly important for button-less RAK19003 Baseboard. 2022-04-27 11:02:45 +02:00
Thomas Göttgens
a0f34a8d0a Make Debug Log less spammy 2022-04-27 11:00:26 +02:00
Ben Meadors
359b41d869 Position fwd phone (#1413)
* Correct factory reset code for NRF (from 1.2)

* Changes from 1.2

* Update proto ref

* Whoops

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2022-04-26 19:40:24 -05:00
Thomas Göttgens
04723bd1a0 Merge pull request #1412 from meshtastic/nrf-softcrypt
use a tiny software AES lib if user wants AES-256
2022-04-26 21:45:54 +02:00
Thomas Göttgens
89d6990a92 Merge branch 'nrf-softcrypt' of github.com:meshtastic/Meshtastic-device into nrf-softcrypt 2022-04-26 21:30:21 +02:00
Thomas Göttgens
96f20287ff fix scope error 2022-04-26 21:30:14 +02:00
Thomas Göttgens
d8ba25747b Merge branch 'master' into nrf-softcrypt 2022-04-26 21:25:01 +02:00
Thomas Göttgens
e66c01f0e6 Merge branch 'nrf-softcrypt' of github.com:meshtastic/Meshtastic-device into nrf-softcrypt 2022-04-26 21:24:29 +02:00
Thomas Göttgens
aaea2e7456 make cppcheck happy 2022-04-26 21:24:21 +02:00
Ben Meadors
92185e763d Bump version for another 1.3 release 2022-04-26 14:10:17 -05:00
Thomas Göttgens
4de5944474 Merge branch 'master' into nrf-softcrypt 2022-04-26 17:52:33 +02:00
Thomas Göttgens
76e48178c8 use a tiny software AES lib if user needs AES-256 2022-04-26 17:50:50 +02:00
Ben Meadors
75e7bccdfb Fix assert execution halt in nrf devices (#1410) 2022-04-26 06:49:05 -05:00
Ben Meadors
3786b1ee15 Reboot implementation for nrf devices (#1411) 2022-04-26 06:48:26 -05:00
Thomas Göttgens
f2dec07c8d Merge pull request #1409 from meshtastic/gps-check
GPS Fixes
2022-04-26 13:17:04 +02:00
Thomas Göttgens
701707a01b - Bounds Check is working on big integers, don't throw away valid coordinates.
- Set ublox chips back to NMEA mode if they have been configured wrongly before.
2022-04-26 13:00:11 +02:00
Pedestrian
13fa7c1628 TTGO_T_ECHO to use batteries, PIN_EINK_PWR_ON must be set to high 2022-04-26 17:43:32 +08:00
Thomas Göttgens
b957001629 Merge branch 'master' of github.com:meshtastic/Meshtastic-device 2022-04-25 21:38:28 +02:00
Jm Casler
9b6b224af4 Merge branch 'meshtastic:master' into compression 2022-04-25 08:04:51 -07:00
Jm Casler
4785367915 Temp work on compression 2022-04-25 08:02:51 -07:00
Thomas Göttgens
d640478289 Merge pull request #1405 from meshtastic/rak-hw-crypto
use nRF52 Hardware Cryptography
2022-04-25 11:43:05 +02:00
Thomas Göttgens
b8b1a5cfb7 Merge branch 'master' into rak-hw-crypto 2022-04-25 11:14:04 +02:00
Thomas Göttgens
770f17f382 use nRF Hardware Cryptography. Removes the need for the sdk-nrfxlib submodule 2022-04-25 11:01:54 +02:00
Sacha Weatherstone
8ea3ebf74b Update README.md 2022-04-25 18:45:47 +10:00
Sacha Weatherstone
cbf238652e Update README.md 2022-04-25 16:51:39 +10:00
Thomas Göttgens
c17cd47689 Update main_matrix.yml (#1402) 2022-04-25 16:48:04 +10:00
Thomas Göttgens
d2c278a856 Update main_matrix.yml (#1401) 2022-04-25 16:24:08 +10:00
Thomas Göttgens
213d9512f1 WIP: unify the RAK targets into one firmware (#1350)
* First steps to unify GPS Lib for RAK 1910 and RAK 12500

* Technicalities. Out with the old and build the new.

* Adapt Matrix

* We use 0.4.5 now

* While we're at it, yank the RAK815, it's EOL

* Satisfy CI - for now

* - yank UBX library, talk to GPS chip with NMEA only.
- more autodetect going on, this time for the Eink Display.

TODO: actually do something with the scan findings.

* i swear this works on windows! :-)

* these are only there to make CI happy

* don't update eink display if not detected.

* Replace Oberon Crypt Library with modified Adafruit Library. This elimintaes the need for the sdk-nfxlib submodule.

* - Revert auto screen selection (incomplete)
- Revert nrF crypto engine (needs more work)
- add separate defines for not-auto-selecting screen lib.

* Define 2 new variants for RAK - with or without epaper

* Update variants

Co-authored-by: Sacha Weatherstone <sachaw100@hotmail.com>
Co-authored-by: Ben Meadors <thebentern@tuta.io>
2022-04-25 15:13:41 +10:00
Andre Kirchhoff
81588d8bdc Merge pull request #1400 from meshtastic/min_app_version-1.3
update minimum_app_version to 1.3.0
2022-04-24 20:17:23 -03:00
Andre Kirchhoff
3c1407c7d2 bump minimum app version requirement to 1.3.0 2022-04-24 19:52:32 -03:00
Ben Meadors
98c8eaaaf0 Moved sender short name method into protobuf module (#1398)
* Moved sender short name method into protobuf module

* Correct factory reset code for NRF (from 1.2)

* Use the correct fs abstraction

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2022-04-24 16:12:25 -05:00
Jm Casler
e7a825d1ba Merge pull request #1394 from GUVWAF/master
Implement listen-before-talk mechanism
2022-04-23 11:08:48 -07:00
GUVWAF
1d2551350d Merge branch 'master' of https://github.com/GUVWAF/Meshtastic-device 2022-04-23 19:01:53 +02:00
GUVWAF
a13157ebde Rename setRandomDelay() function 2022-04-23 18:57:45 +02:00
Ben Meadors
a0971ebe9c Merge branch 'master' into master 2022-04-23 08:46:02 -05:00
Ben Meadors
8733bcb52e Peg espressif platform version to 3.5.0 2022-04-23 08:42:26 -05:00
Thomas Göttgens
7c12234a9c Merge branch 'master' of github.com:meshtastic/Meshtastic-device 2022-04-23 10:12:32 +02:00
Ben Meadors
823e6cb1ed Merge branch 'master' into master 2022-04-22 07:56:50 -05:00
Ben Meadors
29e378a11e Link to open collective from contributors badge 2022-04-22 07:49:26 -05:00
GUVWAF
692278343b Merge branch 'master' of https://github.com/GUVWAF/Meshtastic-device 2022-04-20 20:16:39 +02:00
GUVWAF
c60d4c1ecc Implement listen-before-talk mechanism
- Function setRandomDelay() calls either startTransmitTimer() or startTransmitTimerSNR()
- After coming back from Rx/Tx-ing, call setRandomDelay()
- If channel is currently busy, call setRandomDelay()
2022-04-20 20:09:12 +02:00
GUVWAF
6d01f9aa89 Add isChannelActive() function to radio interface 2022-04-20 20:04:44 +02:00
GUVWAF
616c7d7b0e Expose front() function in MeshPacketQueue 2022-04-20 19:58:52 +02:00
Thomas Göttgens
c6a2e26876 Merge branch 'master' of github.com:meshtastic/Meshtastic-device 2022-04-20 09:51:35 +02:00
Jm Casler
6b012ca5b0 Add fiscal contributors badge 2022-04-19 22:41:00 -07:00
Thomas Göttgens
93466baa87 Merge pull request #1393 from meshtastic/create-pull-request/patch
Changes by create-pull-request action
2022-04-19 23:08:29 +02:00
Thomas Göttgens
137328f567 Merge branch 'master' into create-pull-request/patch 2022-04-19 22:52:44 +02:00
Thomas Göttgens
838f00c7d7 Merge pull request #1391 from D4rk4/master
Brother EP-44 support
2022-04-19 22:52:16 +02:00
Dmitry Galenko
293921e95a Brother EP-44 support 2022-04-19 22:37:04 +02:00
caveman99
b82bf5c729 [create-pull-request] automated change 2022-04-19 20:26:22 +00:00
Jm Casler
90df7c2488 bump to 1.3.8 2022-04-18 17:20:03 -07:00
Jm Casler
8c1a81c03a Merge branch 'compression' into master 2022-04-18 17:02:45 -07:00
Jm Casler
6fe9f0b42f Disable compression / decompression (for testing) 2022-04-18 17:00:36 -07:00
Thomas Göttgens
43f6f61472 Merge pull request #1387 from meshtastic/patch-1
tryfix #1363
2022-04-18 23:01:07 +02:00
Thomas Göttgens
ed62b6916c tryfix #1363
Ask for the register several times and only go on if the answer is the same in 2 consecutive tries.
2022-04-18 22:46:45 +02:00
Thomas Göttgens
cf45e4fce5 Merge pull request #1386 from meshtastic/patch-1
Remove References to Pre-1.2 Preffile
2022-04-18 22:19:58 +02:00
Thomas Göttgens
136e2e96f7 Remove References to Pre-1.2 Preffile
1.3+ need a clean install anyway, so no point migrating these any more.
2022-04-18 21:55:58 +02:00
Jm Casler
7c071e2361 updating proto submodule to latest 2022-04-18 12:29:20 -07:00
Thomas Göttgens
0b85e97087 Merge pull request #1385 from meshtastic/oem-screen
Enable OEM Bootlogo, needs protobuf update
2022-04-18 18:43:47 +02:00
Thomas Göttgens
81d1cc1003 Merge branch 'oem-screen' of github.com:meshtastic/Meshtastic-device into oem-screen 2022-04-18 18:27:37 +02:00
Thomas Göttgens
748416d9e3 protobuf update 2022-04-18 18:27:17 +02:00
Thomas Göttgens
da6d49385c Merge branch 'master' into oem-screen 2022-04-18 18:18:19 +02:00
Thomas Göttgens
f279f9614e Enable OEM Bootlogo, needs protobuf update 2022-04-18 18:11:17 +02:00
Sacha Weatherstone
9097475149 Add Repobeats stats image to readme 2022-04-18 23:56:16 +10:00
Jm Casler
5327d6162a remove targz library 2022-04-15 23:17:30 -07:00
Jm Casler
5d7990667d Max nodes to 64 and remove targz 2022-04-15 23:16:40 -07:00
Jm Casler
79a41bd81c updating proto submodule to latest 2022-04-15 22:30:21 -07:00
Jm Casler
6a3d81eff8 Merge pull request #1383 from mc-hamster/compression
Change to unishox library
2022-04-15 20:46:04 -07:00
Jm Casler
7cd66b2b68 Merge branch 'meshtastic:master' into compression 2022-04-15 20:45:44 -07:00
Jm Casler
8124ecbfd8 Change to unishox library 2022-04-15 18:11:17 -07:00
Jm Casler
7df1a64b52 Merge pull request #1382 from mc-hamster/compression
Updated welcome screen w/ text, pages and logo
2022-04-14 21:33:19 -07:00
Jm Casler
e51b7c3c32 Merge branch 'meshtastic:master' into compression 2022-04-14 21:32:52 -07:00
Jm Casler
0c285aac6e enable welcome text 2022-04-14 21:32:00 -07:00
Jm Casler
fbeb554186 Merge branch 'compression' of https://github.com/mc-hamster/Meshtastic-device into compression 2022-04-14 21:31:38 -07:00
Jm Casler
87da779478 Updated welcome screen w/ text, pages and logo
Updated welcome screen w/ text, pages and logo
2022-04-14 21:31:31 -07:00
Jm Casler
1082c5d771 Merge pull request #1381 from mc-hamster/compression
Fix for welcome screen going over ble pairing
2022-04-14 21:05:21 -07:00
Jm Casler
3933d24d62 Merge branch 'meshtastic:master' into compression 2022-04-14 21:03:18 -07:00
Jm Casler
fc0508f254 Fix for welcome screen going over ble pairing 2022-04-14 21:02:52 -07:00
Jm Casler
bb22b6ec58 bump to 1.3.7 2022-04-14 16:15:19 -07:00
Jm Casler
ddb9678377 Merge pull request #1380 from mc-hamster/compression
Compression WIP
2022-04-14 16:14:31 -07:00
Jm Casler
dc20cbb672 one more fix for cppcheck 2022-04-14 15:57:31 -07:00
Jm Casler
a10ea604af Fixes for cppcheck errors 2022-04-14 15:51:48 -07:00
Jm Casler
fb1caa51d0 Merge branch 'meshtastic:master' into compression 2022-04-13 21:59:42 -07:00
Jm Casler
7e977aea00 Add welcome screen feature toggle 2022-04-13 21:59:25 -07:00
Jm Casler
ecc114f1cd temp work on compression 2022-04-13 19:23:35 -07:00
Balázs Kelemen
b76424db50 Make Observer to be able to observe multiple Observables. (#1234)
* Make Observer to be able to observe multiple Observables.

* Fix Observer destructor cleanup.

Co-authored-by: Sacha Weatherstone <sachaw100@hotmail.com>
2022-04-14 08:43:06 +10:00
Jm Casler
b056081d3c Merge branch 'meshtastic:master' into compression 2022-04-12 21:14:25 -07:00
Jm Casler
a4bdef4151 compression WIP
compression works. next is to store it in the proto as a oneof and then decompress it on use.
2022-04-11 22:12:04 -07:00
Jm Casler
478274aff1 Beginning of compression 2022-04-11 20:09:48 -07:00
Thomas Göttgens
06aae85e45 Merge branch 'master' of github.com:meshtastic/Meshtastic-device 2022-04-06 13:06:15 +02:00
Thomas Göttgens
a2df441e1f Merge branch 'master' of github.com:meshtastic/Meshtastic-device
# Conflicts:
#	variants/heltec_v1/variant.h
2022-04-05 11:03:51 +02:00
Thomas Göttgens
d246c31548 GPS Pin Changes on V 2.0 and V1 too. 2022-04-02 12:16:42 +02:00
Thomas Göttgens
19589bf12d Merge branch 'master' of github.com:meshtastic/Meshtastic-device 2022-04-02 12:05:30 +02:00
Thomas Göttgens
ba984aebfa Varaible GPS Thread Timing, keep default of 100 msec 2022-04-02 12:05:07 +02:00
177 changed files with 6304 additions and 3527 deletions

View File

@@ -1,11 +0,0 @@
# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.162.0/containers/ubuntu/.devcontainer/base.Dockerfile
# [Choice] Ubuntu version: bionic, focal
ARG VARIANT="focal"
FROM mcr.microsoft.com/vscode/devcontainers/base:0-${VARIANT}
# [Optional] Uncomment this section to install additional OS packages.
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
&& apt-get -y install python3-distutils python3-pip
RUN pip3 install platformio meshtastic adafruit-nrfutil
RUN wget https://github.com/protocolbuffers/protobuf/releases/download/v3.15.8/protoc-3.15.8-linux-x86_64.zip -O /tmp/protoc.zip && cd /tmp && unzip protoc.zip && chmod a+x bin/protoc && cp bin/protoc /usr/local/bin

View File

@@ -1,32 +0,0 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.162.0/containers/ubuntu
{
"name": "Ubuntu",
"build": {
"dockerfile": "Dockerfile",
// Update 'VARIANT' to pick an Ubuntu version: focal, bionic
"args": { "VARIANT": "focal" }
},
// Set *default* container specific settings.json values on container create.
"settings": {
"terminal.integrated.shell.linux": "/bin/bash"
},
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"platformio.platformio-ide",
"xaver.clang-format"
],
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
// Use 'postCreateCommand' to run commands after the container is created.
// "postCreateCommand": "uname -a",
// Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
"remoteUser": "vscode",
"postCreateCommand": "git submodule update --init"
}

View File

@@ -1,146 +0,0 @@
name: Continuous Integration (Legacy serial build)
on:
# Triggers the workflow on push or pull request events but only for the master branch
workflow_dispatch:
jobs:
ci-check:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
submodules: "recursive"
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
- name: Install cppcheck
run: |
sudo apt-get install -y cppcheck
- name: Setup Python
uses: actions/setup-python@v2
with:
python-version: 3.x
- name: Cache python libs
uses: actions/cache@v1
id: cache-pip # needed in if test
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip
- name: Upgrade python tools and install platformio
run: |
python -m pip install --upgrade pip
pip install -U platformio
- name: Upgrade platformio
run: |
pio upgrade
- name: Check everything
run: bin/check-all.sh
ci-build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
submodules: "recursive"
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
- name: Setup Python
uses: actions/setup-python@v2
with:
python-version: 3.x
- name: Cache python libs
uses: actions/cache@v1
id: cache-pip # needed in if test
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip
- name: Upgrade python tools
# We actually want to run this every time
# if: steps.cache-pip.outputs.cache-hit != 'true'
run: |
python -m pip install --upgrade pip
pip install -U platformio meshtastic adafruit-nrfutil
# - name: Cache platformio
# uses: actions/cache@v1
# id: cache-platformio # needed in if test
# with:
# path: ~/.platformio
# key: ${{ runner.os }}-platformio
- name: Upgrade platformio
run: |
pio upgrade
- name: Pull web ui
uses: dsaltares/fetch-gh-release-asset@master
with:
repo: "meshtastic/meshtastic-web"
file: "build.tar"
target: "build.tar"
token: ${{ secrets.GITHUB_TOKEN }}
- name: Unpack web ui
run: |
tar -xf build.tar -C data/static
rm build.tar
# We now run integration test before other build steps (to quickly see runtime failures)
- name: Build for native
run: platformio run -e native
- name: Integration test
run: |
.pio/build/native/program &
sleep 20 # 5 seconds was not enough
echo "Simulator started, launching python test..."
python3 -c 'from meshtastic.test import testSimulator; testSimulator()'
- name: Cat bin/build-all.sh
run: |
cat bin/build-all.sh
- name: Build everything
run: bin/build-all.sh
- name: Get release version string
run: echo "::set-output name=version::$(./bin/buildinfo.py long)"
id: version
- name: Store binaries as an artifact
uses: actions/upload-artifact@v2
with:
name: firmware-${{ steps.version.outputs.version }}.zip
path: release/archive/firmware-${{ steps.version.outputs.version }}.zip
retention-days: 90
- name: Store debugging elf files as an artifact
uses: actions/upload-artifact@v2
with:
name: debug-elfs
path: release/archive/elfs-*.zip
retention-days: 7
- name: Download firmware.zip
uses: actions/download-artifact@master
with:
name: firmware-${{ steps.version.outputs.version }}.zip
path: ./
- name: Pull request artifacts
if: ${{ github.event_name == 'pull_request_target' || github.event_name == 'pull_request' }}
uses: gavv/pull-request-artifacts@v1.0.0
with:
commit: ${{ (github.event.pull_request_target || github.event.pull_request).head.sha }}
repo-token: ${{ secrets.GITHUB_TOKEN }}
artifacts-branch: artifacts
artifacts: ./firmware-${{ steps.version.outputs.version }}.zip

View File

@@ -1,4 +1,4 @@
name: Continuous Integration name: CI
on: on:
# # Triggers the workflow on push but only for the master branch # # Triggers the workflow on push but only for the master branch
push: push:
@@ -34,10 +34,10 @@ jobs:
- board: heltec-v2.1 - board: heltec-v2.1
- board: tbeam0.7 - board: tbeam0.7
- board: meshtastic-diy-v1 - board: meshtastic-diy-v1
- board: rak4631_5005 - board: rak4631
- board: rak4631_19003 - board: rak4631_eink
- board: rak4631_5005_eink
- board: t-echo - board: t-echo
- board: nano-g1
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@@ -92,6 +92,7 @@ jobs:
- board: heltec-v2.1 - board: heltec-v2.1
- board: tbeam0.7 - board: tbeam0.7
- board: meshtastic-diy-v1 - board: meshtastic-diy-v1
- board: nano-g1
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@@ -117,7 +118,8 @@ jobs:
- name: Upgrade python tools - name: Upgrade python tools
run: | run: |
python -m pip install --upgrade pip python -m pip install --upgrade pip
pip install -U platformio meshtastic adafruit-nrfutil littlefs-python pip install -U platformio adafruit-nrfutil littlefs-python
pip install -U --pre meshtastic
- name: Upgrade platformio - name: Upgrade platformio
run: | run: |
@@ -158,9 +160,8 @@ jobs:
max-parallel: 2 max-parallel: 2
matrix: matrix:
include: include:
- board: rak4631_5005 - board: rak4631
- board: rak4631_19003 - board: rak4631_eink
- board: rak4631_5005_eink
- board: t-echo - board: t-echo
- board: pca10059_diy_eink - board: pca10059_diy_eink
@@ -188,7 +189,8 @@ jobs:
- name: Upgrade python tools - name: Upgrade python tools
run: | run: |
python -m pip install --upgrade pip python -m pip install --upgrade pip
pip install -U platformio meshtastic adafruit-nrfutil pip install -U platformio adafruit-nrfutil
pip install -U --pre meshtastic
- name: Upgrade platformio - name: Upgrade platformio
run: | run: |
@@ -235,7 +237,8 @@ jobs:
- name: Upgrade python tools - name: Upgrade python tools
run: | run: |
python -m pip install --upgrade pip python -m pip install --upgrade pip
pip install -U platformio meshtastic adafruit-nrfutil pip install -U platformio adafruit-nrfutil
pip install -U --pre meshtastic
- name: Upgrade platformio - name: Upgrade platformio
run: | run: |

View File

@@ -13,7 +13,7 @@ jobs:
- name: Update submodule - name: Update submodule
run: | run: |
git submodule update --remote proto git submodule update --remote protobufs
- name: Download nanopb - name: Download nanopb
run: | run: |
@@ -29,5 +29,5 @@ jobs:
uses: peter-evans/create-pull-request@v3 uses: peter-evans/create-pull-request@v3
with: with:
add-paths: | add-paths: |
proto protobufs
src/mesh src/mesh

10
.gitmodules vendored
View File

@@ -1,9 +1,3 @@
[submodule "proto"] [submodule "protobufs"]
path = proto path = protobufs
url = https://github.com/meshtastic/Meshtastic-protobufs.git url = https://github.com/meshtastic/Meshtastic-protobufs.git
[submodule "sdk-nrfxlib"]
path = sdk-nrfxlib
url = https://github.com/nrfconnect/sdk-nrfxlib.git
[submodule "design"]
path = design
url = https://github.com/meshtastic/meshtastic-design.git

View File

@@ -51,7 +51,8 @@
"iterator": "cpp", "iterator": "cpp",
"shared_mutex": "cpp", "shared_mutex": "cpp",
"iostream": "cpp", "iostream": "cpp",
"esp_nimble_hci.h": "c" "esp_nimble_hci.h": "c",
"map": "cpp"
}, },
"cSpell.words": [ "cSpell.words": [
"Blox", "Blox",
@@ -73,10 +74,5 @@
"cmake.configureOnOpen": true, "cmake.configureOnOpen": true,
"protoc": { "protoc": {
"compile_on_save": false, "compile_on_save": false,
"compile_all_path": "/home/kevinh/development/meshtastic/meshtastic-esp32/proto",
"options": [
"--java_out=/tmp",
"-I=/home/kevinh/development/meshtastic/meshtastic-esp32/proto"
]
} }
} }

View File

@@ -1,16 +0,0 @@
FROM ubuntu
MAINTAINER Kevin Hester <kevinh@geeksville.com>
RUN apt-get update
RUN DEBIAN_FRONTEND=noninteractive TZ=Etc/UTC apt-get -y install wget python3 g++ zip python3-venv git vim
RUN wget https://raw.githubusercontent.com/platformio/platformio-core-installer/master/get-platformio.py -O get-platformio.py; chmod +x get-platformio.py
RUN python3 get-platformio.py
RUN git clone https://github.com/meshtastic/Meshtastic-device.git
RUN cd Meshtastic-device; git submodule update --init --recursive
# only build the simulator
RUN sed -i 's/^BOARDS_ESP32.*/BOARDS_ESP32=""/' Meshtastic-device/bin/build-all.sh
RUN sed -i 's/^BOARDS_NRF52.*/BOARDS_NRF52=""/' Meshtastic-device/bin/build-all.sh
RUN sed -i 's/echo "Building Filesystem.*/exit/' Meshtastic-device/bin/build-all.sh
RUN . ~/.platformio/penv/bin/activate; cd Meshtastic-device; ./bin/build-all.sh
CMD ["/Meshtastic-device/release/latest/bins/universal/meshtasticd_linux_amd64"]

View File

@@ -1,19 +1,19 @@
# Meshtastic-device # Meshtastic Firmware
[![Open in Visual Studio Code](https://open.vscode.dev/badges/open-in-vscode.svg)](https://open.vscode.dev/meshtastic/Meshtastic-device)
[![Continuous Integration](https://github.com/meshtastic/Meshtastic-device/actions/workflows/main.yml/badge.svg)](https://github.com/meshtastic/Meshtastic-device/actions/workflows/main.yml) ![GitHub release downloads](https://img.shields.io/github/downloads/meshtastic/meshtastic-device/total)
![GitHub all releases](https://img.shields.io/github/downloads/meshtastic/meshtastic-device/total) [![CI](https://img.shields.io/github/workflow/status/meshtastic/Meshtastic-device/CI?label=actions&logo=github&color=yellow)](https://github.com/meshtastic/repo/actions/workflows/main_matrix.yml)
[![CLA assistant](https://cla-assistant.io/readme/badge/meshtastic/Meshtastic-device)](https://cla-assistant.io/meshtastic/Meshtastic-device) [![CLA assistant](https://cla-assistant.io/readme/badge/meshtastic/Meshtastic-device)](https://cla-assistant.io/meshtastic/Meshtastic-device)
[![Fiscal Contributors](https://opencollective.com/meshtastic/tiers/badge.svg?label=Fiscal%20Contributors&color=deeppink)](https://opencollective.com/meshtastic/)
[![Vercel](https://img.shields.io/static/v1?label=Powered%20by&message=Vercel&style=flat&logo=vercel&color=000000)](https://vercel.com?utm_source=meshtastic&utm_campaign=oss)
## This repository contains the device firmware used in the [Meshtastic](https://meshtastic.org) project. ## Overview
Update Instructions This repository contains the device firmware for the Meshtastic project.
[Using Meshtastic Flasher](https://meshtastic.org/docs/getting-started/meshtastic-flasher)
Manual Method **[Building Instructions](https://meshtastic.org/docs/developers/Firmware/build)**
**[Flashing Instructions](https://meshtastic.org/docs/getting-started/flashing-firmware/)**
[For ESP32 devices click here](https://meshtastic.org/docs/getting-started/flashing-esp32) ## Stats
[For nRF52 devices click here](https://meshtastic.org/docs/getting-started/flashing-nrf52) ![Alt](https://repobeats.axiom.co/api/embed/99a2cf5622bb4807f9e8c3b86589f1133cce58a2.svg 'Repobeats analytics image')
For developer information and specific building instructions, please see the [developer documentation](https://meshtastic.org/docs/developers)

View File

@@ -5,11 +5,11 @@ set -e
VERSION=`bin/buildinfo.py long` VERSION=`bin/buildinfo.py long`
SHORT_VERSION=`bin/buildinfo.py short` SHORT_VERSION=`bin/buildinfo.py short`
BOARDS_ESP32="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" BOARDS_ESP32="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"
#BOARDS_ESP32=tbeam #BOARDS_ESP32=tbeam
# FIXME note nrf52840dk build is for some reason only generating a BIN file but not a HEX file nrf52840dk-geeksville is fine # FIXME note nrf52840dk build is for some reason only generating a BIN file but not a HEX file nrf52840dk-geeksville is fine
BOARDS_NRF52="rak4631_5005 rak4631_5005_eink rak4631_19003 t-echo pca10059_diy_eink" BOARDS_NRF52="rak4631 rak4631_eink t-echo pca10059_diy_eink"
#BOARDS_NRF52="" #BOARDS_NRF52=""
OUTDIR=release/latest OUTDIR=release/latest

View File

@@ -13,7 +13,7 @@ if [[ $# -gt 0 ]]; then
# can override which environment by passing arg # can override which environment by passing arg
BOARDS="$@" BOARDS="$@"
else else
BOARDS="tlora-v2 tlora-v1 tlora_v1_3 tlora-v2-1-1.6 tbeam heltec-v1 heltec-v2.0 heltec-v2.1 tbeam0.7 meshtastic-diy-v1 rak4631_5005 rak4631_19003 rak11200 t-echo pca10059_diy_eink" BOARDS="tlora-v2 tlora-v1 tlora_v1_3 tlora-v2-1-1.6 tbeam heltec-v1 heltec-v2.0 heltec-v2.1 tbeam0.7 meshtastic-diy-v1 rak4631 rak4631_eink rak11200 t-echo pca10059_diy_eink"
fi fi
echo "BOARDS:${BOARDS}" echo "BOARDS:${BOARDS}"

View File

@@ -28,12 +28,12 @@ IF "__%FILENAME%__" == "____" (
) )
IF EXIST %FILENAME% ( IF EXIST %FILENAME% (
echo Trying to flash update %FILENAME%, but first erasing and writing system information" echo Trying to flash update %FILENAME%, but first erasing and writing system information"
%PYTHON% -m esptool --baud 921600 erase_flash %PYTHON% -m esptool --baud 115200 erase_flash
%PYTHON% -m esptool --baud 921600 write_flash 0x1000 system-info.bin %PYTHON% -m esptool --baud 115200 write_flash 0x1000 system-info.bin
for %%f in (littlefs-*.bin) do ( for %%f in (littlefs-*.bin) do (
%PYTHON% -m esptool --baud 921600 write_flash 0x00390000 %%f %PYTHON% -m esptool --baud 115200 write_flash 0x00390000 %%f
) )
%PYTHON% -m esptool --baud 921600 write_flash 0x10000 %FILENAME% %PYTHON% -m esptool --baud 115200 write_flash 0x10000 %FILENAME%
) else ( ) else (
echo "Invalid file: %FILENAME%" echo "Invalid file: %FILENAME%"
goto HELP goto HELP

View File

@@ -28,9 +28,9 @@ IF "__%FILENAME%__" == "____" (
) )
IF EXIST %FILENAME% ( IF EXIST %FILENAME% (
echo Trying to flash update %FILENAME% echo Trying to flash update %FILENAME%
%PYTHON% -m esptool --baud 921600 write_flash 0x10000 %FILENAME% %PYTHON% -m esptool --baud 115200 write_flash 0x10000 %FILENAME%
echo Erasing the otadata partition, which will turn off flash flippy-flop and force the first image to be used echo Erasing the otadata partition, which will turn off flash flippy-flop and force the first image to be used
%PYTHON% -m esptool --baud 921600 erase_region 0xe000 0x2000 %PYTHON% -m esptool --baud 115200 erase_region 0xe000 0x2000
) else ( ) else (
echo "Invalid file: %FILENAME%" echo "Invalid file: %FILENAME%"
goto HELP goto HELP

View File

@@ -44,9 +44,9 @@ shift "$((OPTIND-1))"
if [ -f "${FILENAME}" ]; then if [ -f "${FILENAME}" ]; then
echo "Trying to flash update ${FILENAME}." echo "Trying to flash update ${FILENAME}."
$PYTHON -m esptool --baud 921600 write_flash 0x10000 ${FILENAME} $PYTHON -m esptool --baud 115200 write_flash 0x10000 ${FILENAME}
echo "Erasing the otadata partition, which will turn off flash flippy-flop and force the first image to be used" echo "Erasing the otadata partition, which will turn off flash flippy-flop and force the first image to be used"
$PYTHON -m esptool --baud 921600 erase_region 0xe000 0x2000 $PYTHON -m esptool --baud 115200 erase_region 0xe000 0x2000
else else
echo "Invalid file: ${FILENAME}" echo "Invalid file: ${FILENAME}"
show_help show_help

View File

@@ -17,7 +17,7 @@ Import("projenv")
prefsLoc = projenv["PROJECT_DIR"] + "/version.properties" prefsLoc = projenv["PROJECT_DIR"] + "/version.properties"
verObj = readProps(prefsLoc) verObj = readProps(prefsLoc)
print("Using meshtastic platform-custom.py, firmare version " + verObj['long']) print("Using meshtastic platformio-custom.py, firmare version " + verObj['long'])
# print("path is" + ','.join(sys.path)) # print("path is" + ','.join(sys.path))
# General options that are passed to the C and C++ compilers # General options that are passed to the C and C++ compilers

View File

@@ -1,3 +1,3 @@
#!/usr/bin/env bash #!/usr/bin/env bash
esptool.py --baud 921600 read_flash 0x1000 0xf000 system-info.img esptool.py --baud 115200 read_flash 0x1000 0xf000 system-info.img

View File

@@ -1 +1 @@
cd proto && ..\nanopb-0.4.5\generator-bin\protoc.exe --nanopb_out=-v:..\src\mesh\generated -I=..\proto *.proto cd protobufs && ..\nanopb-0.4.5\generator-bin\protoc.exe --nanopb_out=-v:..\src\mesh\generated -I=..\protobufs *.proto

View File

@@ -7,8 +7,8 @@ echo "meshtastic-device root directory if the following step fails, you should d
echo "prebuilt binaries for your computer into nanopb-0.4.5" echo "prebuilt binaries for your computer into nanopb-0.4.5"
# the nanopb tool seems to require that the .options file be in the current directory! # the nanopb tool seems to require that the .options file be in the current directory!
cd proto cd protobufs
../nanopb-0.4.5/generator-bin/protoc --nanopb_out=-v:../src/mesh/generated -I=../proto *.proto ../nanopb-0.4.5/generator-bin/protoc --nanopb_out=-v:../src/mesh/generated -I=../protobufs *.proto
#echo "Regenerating protobuf documentation - if you see an error message" #echo "Regenerating protobuf documentation - if you see an error message"
#echo "you can ignore it unless doing a new protobuf release to github." #echo "you can ignore it unless doing a new protobuf release to github."

View File

@@ -1,55 +0,0 @@
{
"build": {
"arduino":{
"ldscript": "nrf52832_s132_v6.ld"
},
"core": "nRF5",
"cpu": "cortex-m4",
"extra_flags": "-DNRF52832_XXAA -DNRF52",
"f_cpu": "64000000L",
"hwids": [
[
"0x10c4",
"0xea60"
]
],
"usb_product": "RAK815",
"mcu": "nrf52832",
"variant": "rak815",
"bsp": {
"name": "adafruit"
},
"softdevice": {
"sd_flags": "-DS132",
"sd_name": "s132",
"sd_version": "6.1.1",
"sd_fwid": "0x00B7"
}
},
"connectivity": [
"bluetooth"
],
"debug": {
"jlink_device": "nRF52832_xxAA",
"svd_path": "nrf52.svd"
},
"frameworks": [
"arduino"
],
"name": "RAK RAK815",
"upload": {
"maximum_ram_size": 65536,
"maximum_size": 524288,
"require_upload_port": true,
"speed": 115200,
"protocol": "nrfutil",
"protocols": [
"jlink",
"nrfjprog",
"nrfutil",
"stlink"
]
},
"url": "https://store.rakwireless.com/products/rak815-hybrid-location-tracker",
"vendor": "RAK"
}

1
design

Submodule design deleted from 73ba05ceef

View File

@@ -16,13 +16,11 @@ default_envs = tbeam
;default_envs = t-echo ;default_envs = t-echo
;default_envs = nrf52840dk-geeksville ;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 = 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 = rak4631_5005
;default_envs = rak4631_5005_eink
;default_envs = rak4631_19003
;default_envs = nano-g1 ;default_envs = nano-g1
;default_envs = pca10059_diy_eink ;default_envs = pca10059_diy_eink
;default_envs = meshtastic-diy-v1 ;default_envs = meshtastic-diy-v1
;default_envs = meshtastic-diy-v1.1 ;default_envs = meshtastic-diy-v1.1
;default_envs = m5stack-coreink
extra_configs = variants/*/platformio.ini extra_configs = variants/*/platformio.ini
@@ -38,24 +36,20 @@ build_flags = -Wno-missing-field-initializers
-Isrc -Isrc/mesh -Isrc/gps -Isrc/buzz -Wl,-Map,.pio/build/output.map -Isrc -Isrc/mesh -Isrc/gps -Isrc/buzz -Wl,-Map,.pio/build/output.map
-DUSE_THREAD_NAMES -DUSE_THREAD_NAMES
-DTINYGPS_OPTION_NO_CUSTOM_FIELDS -DTINYGPS_OPTION_NO_CUSTOM_FIELDS
-DPB_ENABLE_MALLOC=1
monitor_speed = 921600 monitor_speed = 115200
lib_deps = lib_deps =
https://github.com/meshtastic/esp8266-oled-ssd1306.git#53580644255b48ebb7a737343c6b4e71c7e11cf2 ; ESP8266_SSD1306 https://github.com/meshtastic/esp8266-oled-ssd1306.git#53580644255b48ebb7a737343c6b4e71c7e11cf2 ; ESP8266_SSD1306
mathertel/OneButton@^2.0.3 ; OneButton library for non-blocking button debounce 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 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/arduino-fsm.git
https://github.com/meshtastic/SparkFun_Ublox_Arduino_Library.git#31015a55e630a2df77d9d714669c621a5bf355ad
https://github.com/meshtastic/RadioLib.git#5582ac30578ff3f53f20630a00b2a8a4b8f92c74
https://github.com/meshtastic/TinyGPSPlus.git https://github.com/meshtastic/TinyGPSPlus.git
https://github.com/meshtastic/AXP202X_Library.git#8404abb6d4b486748636bc6ad72d2a47baaf5460
Wire ; explicitly needed here because the AXP202 library forgets to add it Wire ; explicitly needed here because the AXP202 library forgets to add it
SPI SPI
https://github.com/geeksville/ArduinoThread.git#72921ac222eed6f526ba1682023cee290d9aa1b3 https://github.com/meshtastic/ArduinoThread.git#72921ac222eed6f526ba1682023cee290d9aa1b3
PubSubClient
nanopb/Nanopb@^0.4.6 nanopb/Nanopb@^0.4.6
meshtastic/json11@^1.0.2
; Used for the code analysis in PIO Home / Inspect ; Used for the code analysis in PIO Home / Inspect
check_tool = cppcheck check_tool = cppcheck
@@ -66,13 +60,24 @@ check_skip_packages = yes
framework = arduino framework = arduino
lib_deps = lib_deps =
${env.lib_deps} ${env.lib_deps}
; Portduino is using meshtastic fork for now
https://github.com/jgromes/RadioLib.git
build_flags = ${env.build_flags} -Os build_flags = ${env.build_flags} -Os
# -DRADIOLIB_GODMODE # -DRADIOLIB_GODMODE
src_filter = ${env.src_filter} -<portduino/> build_src_filter = ${env.build_src_filter} -<portduino/>
; Common libs for environmental measurements (not included in native / portduino) ; Common libs for communicating over TCP/IP networks such as MQTT
[environmental] [networking_base]
lib_deps = lib_deps =
PubSubClient
meshtastic/json11@^1.0.2
; Common libs for environmental measurements in telemetry module
; (not included in native / portduino)
[environmental_base]
lib_deps =
adafruit/Adafruit BusIO@^1.11.4
adafruit/DHT sensor library@^1.4.1 adafruit/DHT sensor library@^1.4.1
adafruit/Adafruit Unified Sensor@^1.1.4 adafruit/Adafruit Unified Sensor@^1.1.4
paulstoffregen/OneWire@^2.3.5 paulstoffregen/OneWire@^2.3.5
@@ -80,15 +85,17 @@ lib_deps =
adafruit/Adafruit BME280 Library@^2.2.2 adafruit/Adafruit BME280 Library@^2.2.2
adafruit/Adafruit BME680 Library@^2.0.1 adafruit/Adafruit BME680 Library@^2.0.1
adafruit/Adafruit MCP9808 Library@^2.0.0 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 ; Common settings for ESP targes, mixin with extends = esp32_base
[esp32_base] [esp32_base]
extends = arduino_base extends = arduino_base
platform = espressif32 platform = espressif32@3.5.0
src_filter = build_src_filter =
${arduino_base.src_filter} -<nrf52/> ${arduino_base.build_src_filter} -<nrf52/>
upload_speed = 921600 upload_speed = 115200
debug_init_break = tbreak setup debug_init_break = tbreak setup
# Remove -DMYNEWT_VAL_BLE_HS_LOG_LVL=LOG_LEVEL_CRITICAL for low level BLE logging. # 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 # 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 # This overrides the BLE logging default of LOG_LEVEL_INFO (1) from: .pio/libdeps/tbeam/NimBLE-Arduino/src/esp_nimble_cfg.h
@@ -99,22 +106,28 @@ build_flags =
-DAXP_DEBUG_PORT=Serial -DUSE_NEW_ESP32_BLUETOOTH -DAXP_DEBUG_PORT=Serial -DUSE_NEW_ESP32_BLUETOOTH
lib_deps = lib_deps =
${arduino_base.lib_deps} ${arduino_base.lib_deps}
${environmental.lib_deps} ${networking_base.lib_deps}
${environmental_base.lib_deps}
https://github.com/meshtastic/esp32_https_server.git https://github.com/meshtastic/esp32_https_server.git
h2zero/NimBLE-Arduino@1.3.7 h2zero/NimBLE-Arduino@1.3.7
tobozo/ESP32-targz@^1.1.4
arduino-libraries/NTPClient@^3.1.0 arduino-libraries/NTPClient@^3.1.0
lorol/LittleFS_esp32@^1.0.6 lorol/LittleFS_esp32@^1.0.6
https://github.com/meshtastic/AXP202X_Library.git#8404abb6d4b486748636bc6ad72d2a47baaf5460
lib_ignore = lib_ignore =
segger_rtt segger_rtt
ESP32 BLE Arduino ESP32 BLE Arduino
platform_packages = platform_packages =
framework-arduinoespressif32@https://github.com/meshtastic/arduino-esp32.git#4cde0f5d412d2695184f32e8a47e9bea57b45276 framework-arduinoespressif32@https://github.com/meshtastic/arduino-esp32.git#4cde0f5d412d2695184f32e8a47e9bea57b45276
; leave this commented out to avoid breaking Windows
; leave this commented out to avoid breaking Windows
;upload_port = /dev/ttyUSB0 ;upload_port = /dev/ttyUSB0
;monitor_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 ; customize the partition table
; http://docs.platformio.org/en/latest/platforms/espressif32.html#partition-tables ; http://docs.platformio.org/en/latest/platforms/espressif32.html#partition-tables
board_build.partitions = partition-table.csv board_build.partitions = partition-table.csv
@@ -129,10 +142,9 @@ 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) ; note: liboberon provides the AES256 implementation for NRF52 (though not using the hardware acceleration of the NRF52840 - FIXME)
build_flags = build_flags =
${arduino_base.build_flags} -Wno-unused-variable ${arduino_base.build_flags} -Wno-unused-variable
-Isrc/nrf52 -Isrc/nrf52
-Isdk-nrfxlib/crypto/nrf_oberon/include -Lsdk-nrfxlib/crypto/nrf_oberon/lib/cortex-m4/hard-float/ -lliboberon_3.0.7 build_src_filter =
src_filter = ${arduino_base.build_src_filter} -<esp32/> -<nimble/> -<mesh/wifi/> -<mesh/http/> -<modules/esp32> -<mqtt/>
${arduino_base.src_filter} -<esp32/> -<nimble/> -<mesh/wifi/> -<mesh/http/> -<modules/esp32> -<mqtt/>
lib_ignore = lib_ignore =
BluetoothOTA BluetoothOTA
@@ -141,8 +153,8 @@ extends = nrf52_base
build_flags = ${nrf52_base.build_flags} build_flags = ${nrf52_base.build_flags}
lib_deps = lib_deps =
${arduino_base.lib_deps} ${arduino_base.lib_deps}
${environmental.lib_deps} ${environmental_base.lib_deps}
Adafruit nRFCrypto https://github.com/Kongduino/Adafruit_nRFCrypto.git
; Note: By default no lora device is created for this build - it uses a simulated interface ; Note: By default no lora device is created for this build - it uses a simulated interface
[env:nrf52840dk] [env:nrf52840dk]
@@ -153,10 +165,3 @@ board = nrf52840_dk
[env:feather_nrf52832] [env:feather_nrf52832]
extends = nrf52_base extends = nrf52_base
board = adafruit_feather_nrf52832 board = adafruit_feather_nrf52832
[env:rak815]
extends = nrf52_base
board = rak815
debug_tool = jlink
upload_protocol = jlink
monitor_speed = 115200

1
proto

Submodule proto deleted from 870a62b27e

1
protobufs Submodule

Submodule protobufs added at a7bbc35866

Submodule sdk-nrfxlib deleted from e6e02cb83d

View File

@@ -1,10 +1,10 @@
#include "configuration.h"
#include "concurrency/OSThread.h"
#include "PowerFSM.h" #include "PowerFSM.h"
#include "RadioLibInterface.h" #include "RadioLibInterface.h"
#include "buzz.h"
#include "concurrency/OSThread.h"
#include "configuration.h"
#include "graphics/Screen.h" #include "graphics/Screen.h"
#include "power.h" #include "power.h"
#include "buzz.h"
#include <OneButton.h> #include <OneButton.h>
#ifndef NO_ESP32 #ifndef NO_ESP32
@@ -78,14 +78,9 @@ class ButtonThread : public concurrency::OSThread
#ifdef BUTTON_PIN_TOUCH #ifdef BUTTON_PIN_TOUCH
userButtonTouch = OneButton(BUTTON_PIN_TOUCH, true, true); userButtonTouch = OneButton(BUTTON_PIN_TOUCH, true, true);
#ifdef INPUT_PULLUP_SENSE
// Some platforms (nrf52) have a SENSE variant which allows wake from sleep - override what OneButton did
pinMode(BUTTON_PIN_TOUCH, INPUT_PULLUP_SENSE);
#endif
userButtonTouch.attachClick(touchPressed); userButtonTouch.attachClick(touchPressed);
wakeOnIrq(BUTTON_PIN_TOUCH, FALLING); wakeOnIrq(BUTTON_PIN_TOUCH, FALLING);
#endif #endif
} }
protected: protected:
@@ -114,16 +109,17 @@ class ButtonThread : public concurrency::OSThread
private: private:
static void touchPressed() static void touchPressed()
{ {
screen->forceDisplay(); screen->forceDisplay();
DEBUG_MSG("touch press!\n"); DEBUG_MSG("touch press!\n");
} }
static void userButtonPressed() static void userButtonPressed()
{ {
// DEBUG_MSG("press!\n"); // DEBUG_MSG("press!\n");
#ifdef BUTTON_PIN #ifdef BUTTON_PIN
if ((BUTTON_PIN != radioConfig.preferences.inputbroker_pin_press) || !radioConfig.preferences.canned_message_module_enabled) { if ((BUTTON_PIN != moduleConfig.canned_message.inputbroker_pin_press) ||
!moduleConfig.canned_message.enabled) {
powerFSM.trigger(EVENT_PRESS); powerFSM.trigger(EVENT_PRESS);
} }
#endif #endif
@@ -135,7 +131,7 @@ class ButtonThread : public concurrency::OSThread
screen->adjustBrightness(); screen->adjustBrightness();
#endif #endif
// If user button is held down for 5 seconds, shutdown the device. // If user button is held down for 5 seconds, shutdown the device.
if (millis() - longPressTime > 5 * 1000) { if ((millis() - longPressTime > 5 * 1000) && (longPressTime > 0)) {
#ifdef TBEAM_V10 #ifdef TBEAM_V10
if (axp192_found == true) { if (axp192_found == true) {
setLed(false); setLed(false);
@@ -144,7 +140,7 @@ class ButtonThread : public concurrency::OSThread
#elif NRF52_SERIES #elif NRF52_SERIES
// Do actual shutdown when button released, otherwise the button release // Do actual shutdown when button released, otherwise the button release
// may wake the board immediatedly. // may wake the board immediatedly.
if (!shutdown_on_long_stop) { if ((!shutdown_on_long_stop) && (millis() > 30 * 1000)) {
screen->startShutdownScreen(); screen->startShutdownScreen();
DEBUG_MSG("Shutdown from long press"); DEBUG_MSG("Shutdown from long press");
playBeep(); playBeep();
@@ -163,7 +159,7 @@ class ButtonThread : public concurrency::OSThread
#ifndef NO_ESP32 #ifndef NO_ESP32
disablePin(); disablePin();
#elif defined(HAS_EINK) #elif defined(HAS_EINK)
digitalWrite(PIN_EINK_EN,digitalRead(PIN_EINK_EN) == LOW); digitalWrite(PIN_EINK_EN, digitalRead(PIN_EINK_EN) == LOW);
#endif #endif
} }
@@ -177,23 +173,26 @@ class ButtonThread : public concurrency::OSThread
#endif #endif
} }
static void userButtonPressedLongStart() static void userButtonPressedLongStart()
{ {
DEBUG_MSG("Long press start!\n"); if (millis() > 30 * 1000) {
longPressTime = millis(); DEBUG_MSG("Long press start!\n");
longPressTime = millis();
}
} }
static void userButtonPressedLongStop() static void userButtonPressedLongStop()
{ {
DEBUG_MSG("Long press stop!\n"); if (millis() > 30 * 1000) {
longPressTime = 0; DEBUG_MSG("Long press stop!\n");
if (shutdown_on_long_stop) { longPressTime = 0;
playShutdownMelody(); if (shutdown_on_long_stop) {
delay(3000); playShutdownMelody();
power->shutdown(); delay(3000);
power->shutdown();
}
} }
} }
}; };
} } // namespace concurrency

View File

@@ -10,7 +10,7 @@
#ifdef CONSOLE_MAX_BAUD #ifdef CONSOLE_MAX_BAUD
#define SERIAL_BAUD CONSOLE_MAX_BAUD #define SERIAL_BAUD CONSOLE_MAX_BAUD
#else #else
#define SERIAL_BAUD 921600 // Serial debug baud rate #define SERIAL_BAUD 115200 // Serial debug baud rate
#endif #endif
#include "SerialConsole.h" #include "SerialConsole.h"

View File

@@ -28,6 +28,34 @@ void listDir(const char * dirname, uint8_t levels)
#endif #endif
} }
void rmDir(const char * dirname)
#ifdef FSCom
{
File root = FSCom.open(dirname);
if(!root){
return;
}
if(!root.isDirectory()){
return;
}
File file = root.openNextFile();
while(file){
if(file.isDirectory() && !String(file.name()).endsWith(".")) {
file.close();
rmDir(file.name());
FSCom.rmdir(file.name());
} else {
file.close();
FSCom.remove(file.name());
}
file.close();
file = root.openNextFile();
}
file.close();
#endif
}
void fsInit() void fsInit()
{ {
#ifdef FSCom #ifdef FSCom

View File

@@ -26,4 +26,6 @@
using namespace Adafruit_LittleFS_Namespace; using namespace Adafruit_LittleFS_Namespace;
#endif #endif
void fsInit(); void fsInit();
void listDir(const char * dirname, uint8_t levels);
void rmDir(const char * dirname);

View File

@@ -1,7 +1,7 @@
#pragma once #pragma once
#include "NodeDB.h"
#include "Status.h" #include "Status.h"
#include "configuration.h" #include "configuration.h"
#include "NodeDB.h"
#include <Arduino.h> #include <Arduino.h>
extern NodeDB nodeDB; extern NodeDB nodeDB;
@@ -17,8 +17,8 @@ class GPSStatus : public Status
CallbackObserver<GPSStatus, const GPSStatus *> statusObserver = CallbackObserver<GPSStatus, const GPSStatus *> statusObserver =
CallbackObserver<GPSStatus, const GPSStatus *>(this, &GPSStatus::updateStatus); CallbackObserver<GPSStatus, const GPSStatus *>(this, &GPSStatus::updateStatus);
bool hasLock = false; // default to false, until we complete our first read bool hasLock = false; // default to false, until we complete our first read
bool isConnected = false; // Do we have a GPS we are talking to bool isConnected = false; // Do we have a GPS we are talking to
Position p = Position_init_default; Position p = Position_init_default;
@@ -42,8 +42,7 @@ class GPSStatus : public Status
} }
// preferred method // preferred method
GPSStatus(bool hasLock, bool isConnected, const Position& pos) GPSStatus(bool hasLock, bool isConnected, const Position &pos) : Status()
: Status()
{ {
this->hasLock = hasLock; this->hasLock = hasLock;
this->isConnected = isConnected; this->isConnected = isConnected;
@@ -61,9 +60,10 @@ class GPSStatus : public Status
bool getIsConnected() const { return isConnected; } bool getIsConnected() const { return isConnected; }
int32_t getLatitude() const { int32_t getLatitude() const
if (radioConfig.preferences.fixed_position){ {
#if GPS_EXTRAVERBOSE if (config.position.fixed_position) {
#ifdef GPS_EXTRAVERBOSE
DEBUG_MSG("WARNING: Using fixed latitude\n"); DEBUG_MSG("WARNING: Using fixed latitude\n");
#endif #endif
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum()); NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
@@ -73,9 +73,10 @@ class GPSStatus : public Status
} }
} }
int32_t getLongitude() const { int32_t getLongitude() const
if (radioConfig.preferences.fixed_position){ {
#if GPS_EXTRAVERBOSE if (config.position.fixed_position) {
#ifdef GPS_EXTRAVERBOSE
DEBUG_MSG("WARNING: Using fixed longitude\n"); DEBUG_MSG("WARNING: Using fixed longitude\n");
#endif #endif
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum()); NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
@@ -85,9 +86,10 @@ class GPSStatus : public Status
} }
} }
int32_t getAltitude() const { int32_t getAltitude() const
if (radioConfig.preferences.fixed_position){ {
#if GPS_EXTRAVERBOSE if (config.position.fixed_position) {
#ifdef GPS_EXTRAVERBOSE
DEBUG_MSG("WARNING: Using fixed altitude\n"); DEBUG_MSG("WARNING: Using fixed altitude\n");
#endif #endif
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum()); NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
@@ -105,18 +107,13 @@ class GPSStatus : public Status
bool matches(const GPSStatus *newStatus) const bool matches(const GPSStatus *newStatus) const
{ {
#if GPS_EXTRAVERBOSE #ifdef GPS_EXTRAVERBOSE
DEBUG_MSG("GPSStatus.match() new pos@%x to old pos@%x\n", DEBUG_MSG("GPSStatus.match() new pos@%x to old pos@%x\n", newStatus->p.pos_timestamp, p.pos_timestamp);
newStatus->p.pos_timestamp, p.pos_timestamp);
#endif #endif
return (newStatus->hasLock != hasLock || return (newStatus->hasLock != hasLock || newStatus->isConnected != isConnected ||
newStatus->isConnected != isConnected || newStatus->p.latitude_i != p.latitude_i || newStatus->p.longitude_i != p.longitude_i ||
newStatus->p.latitude_i != p.latitude_i || newStatus->p.altitude != p.altitude || newStatus->p.altitude_hae != p.altitude_hae ||
newStatus->p.longitude_i != p.longitude_i || newStatus->p.PDOP != p.PDOP || newStatus->p.ground_track != p.ground_track ||
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.sats_in_view != p.sats_in_view); newStatus->p.sats_in_view != p.sats_in_view);
} }
@@ -125,8 +122,7 @@ class GPSStatus : public Status
// Only update the status if values have actually changed // Only update the status if values have actually changed
bool isDirty = matches(newStatus); bool isDirty = matches(newStatus);
if (isDirty && p.pos_timestamp && if (isDirty && p.pos_timestamp && (newStatus->p.pos_timestamp == p.pos_timestamp)) {
(newStatus->p.pos_timestamp == p.pos_timestamp)) {
// We can NEVER be in two locations at the same time! (also PR #886) // We can NEVER be in two locations at the same time! (also PR #886)
DEBUG_MSG("BUG!! positional timestamp unchanged from prev solution\n"); DEBUG_MSG("BUG!! positional timestamp unchanged from prev solution\n");
} }
@@ -140,11 +136,9 @@ class GPSStatus : public Status
if (isDirty) { if (isDirty) {
if (hasLock) { if (hasLock) {
// In debug logs, identify position by @timestamp:stage (stage 3 = notify) // 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", DEBUG_MSG("New GPS pos@%x:3 lat=%f, lon=%f, alt=%d, pdop=%.2f, track=%.2f, sats=%d\n", p.pos_timestamp,
p.pos_timestamp, p.latitude_i * 1e-7, p.longitude_i * 1e-7, p.altitude, p.PDOP * 1e-2, p.ground_track * 1e-5,
p.latitude_i * 1e-7, p.longitude_i * 1e-7, p.sats_in_view);
p.altitude, p.PDOP * 1e-2, p.ground_track * 1e-5,
p.sats_in_view);
} else } else
DEBUG_MSG("No GPS lock\n"); DEBUG_MSG("No GPS lock\n");
onNewStatus.notifyObservers(this); onNewStatus.notifyObservers(this);

View File

@@ -11,13 +11,13 @@ template <class T> class Observable;
*/ */
template <class T> class Observer template <class T> class Observer
{ {
Observable<T> *observed = NULL; std::list<Observable<T> *> observed;
public: public:
virtual ~Observer(); virtual ~Observer();
/// Stop watching our current obserable /// Stop watching the obserable
void unobserve(); void unobserve(Observable<T> *o);
/// Start watching a specified observable /// Start watching a specified observable
void observe(Observable<T> *o); void observe(Observable<T> *o);
@@ -87,21 +87,21 @@ template <class T> class Observable
template <class T> Observer<T>::~Observer() template <class T> Observer<T>::~Observer()
{ {
unobserve(); for (typename std::list<Observable<T> *>::const_iterator iterator = observed.begin(); iterator != observed.end();
++iterator) {
(*iterator)->removeObserver(this);
}
observed.clear();
} }
template <class T> void Observer<T>::unobserve() template <class T> void Observer<T>::unobserve(Observable<T> *o)
{ {
if (observed) o->removeObserver(this);
observed->removeObserver(this); observed.remove(o);
observed = NULL;
} }
template <class T> void Observer<T>::observe(Observable<T> *o) template <class T> void Observer<T>::observe(Observable<T> *o)
{ {
// We can only watch one thing at a time observed.push_back(o);
assert(!observed);
observed = o;
o->addObserver(this); o->addObserver(this);
} }

View File

@@ -1,10 +1,11 @@
#include "configuration.h"
#include "power.h" #include "power.h"
#include "NodeDB.h" #include "NodeDB.h"
#include "PowerFSM.h" #include "PowerFSM.h"
#include "configuration.h"
#include "main.h" #include "main.h"
#include "sleep.h" #include "sleep.h"
#include "utils.h" #include "utils.h"
#include "buzz/buzz.h"
#ifdef TBEAM_V10 #ifdef TBEAM_V10
// FIXME. nasty hack cleanup how we load axp192 // FIXME. nasty hack cleanup how we load axp192
@@ -13,27 +14,28 @@
AXP20X_Class axp; AXP20X_Class axp;
#else #else
// Copy of the base class defined in axp20x.h. // Copy of the base class defined in axp20x.h.
// I'd rather not inlude axp20x.h as it brings Wire dependency. // I'd rather not inlude axp20x.h as it brings Wire dependency.
class HasBatteryLevel { class HasBatteryLevel
public: {
/** public:
* Battery state of charge, from 0 to 100 or -1 for unknown /**
*/ * Battery state of charge, from 0 to 100 or -1 for unknown
virtual int getBattPercentage() { return -1; } */
virtual int getBattPercentage() { return -1; }
/** /**
* The raw voltage of the battery or NAN if unknown * The raw voltage of the battery or NAN if unknown
*/ */
virtual float getBattVoltage() { return NAN; } virtual float getBattVoltage() { return NAN; }
/** /**
* return true if there is a battery installed in this unit * return true if there is a battery installed in this unit
*/ */
virtual bool isBatteryConnect() { return false; } virtual bool isBatteryConnect() { return false; }
virtual bool isVBUSPlug() { return false; } virtual bool isVBUSPlug() { return false; }
virtual bool isChargeing() { return false; } virtual bool isChargeing() { return false; }
}; };
#endif #endif
@@ -99,24 +101,24 @@ class AnalogBatteryLevel : public HasBatteryLevel
#ifndef ADC_MULTIPLIER #ifndef ADC_MULTIPLIER
#define ADC_MULTIPLIER 2.0 #define ADC_MULTIPLIER 2.0
#endif #endif
// Override variant or default ADC_MULTIPLIER if we have the override pref
float operativeAdcMultiplier = radioConfig.preferences.adc_multiplier_override > 0 ?
radioConfig.preferences.adc_multiplier_override :
ADC_MULTIPLIER;
#ifdef BATTERY_PIN #ifdef BATTERY_PIN
// Do not call analogRead() often. // Override variant or default ADC_MULTIPLIER if we have the override pref
float operativeAdcMultiplier = config.power.adc_multiplier_override > 0
? config.power.adc_multiplier_override
: ADC_MULTIPLIER;
// Do not call analogRead() often.
const uint32_t min_read_interval = 5000; const uint32_t min_read_interval = 5000;
if (millis() - last_read_time_ms > min_read_interval) { if (millis() - last_read_time_ms > min_read_interval) {
last_read_time_ms = millis(); last_read_time_ms = millis();
uint32_t raw = analogRead(BATTERY_PIN); uint32_t raw = analogRead(BATTERY_PIN);
float scaled; float scaled;
#ifndef VBAT_RAW_TO_SCALED #ifndef VBAT_RAW_TO_SCALED
scaled = 1000.0 * operativeAdcMultiplier * (AREF_VOLTAGE / 1024.0) * raw; scaled = 1000.0 * operativeAdcMultiplier * (AREF_VOLTAGE / 1024.0) * raw;
#else #else
scaled = VBAT_RAW_TO_SCALED(raw); //defined in variant.h scaled = VBAT_RAW_TO_SCALED(raw); // defined in variant.h
#endif #endif
// DEBUG_MSG("battery gpio %d raw val=%u scaled=%u\n", BATTERY_PIN, raw, (uint32_t)(scaled)); // DEBUG_MSG("battery gpio %d raw val=%u scaled=%u\n", BATTERY_PIN, raw, (uint32_t)(scaled));
last_read_value = scaled; last_read_value = scaled;
return scaled; return scaled;
@@ -153,7 +155,8 @@ class AnalogBatteryLevel : public HasBatteryLevel
AnalogBatteryLevel analogLevel; AnalogBatteryLevel analogLevel;
Power::Power() : OSThread("Power") { Power::Power() : OSThread("Power")
{
statusHandler = {}; statusHandler = {};
low_voltage_counter = 0; low_voltage_counter = 0;
} }
@@ -172,7 +175,7 @@ bool Power::analogInit()
#endif #endif
#ifdef NRF52_SERIES #ifdef NRF52_SERIES
#ifdef VBAT_AR_INTERNAL #ifdef VBAT_AR_INTERNAL
analogReference(VBAT_AR_INTERNAL); analogReference(VBAT_AR_INTERNAL);
#else #else
analogReference(AR_INTERNAL); // 3.6V analogReference(AR_INTERNAL); // 3.6V
#endif #endif
@@ -181,9 +184,10 @@ bool Power::analogInit()
#ifndef BATTERY_SENSE_RESOLUTION_BITS #ifndef BATTERY_SENSE_RESOLUTION_BITS
#define BATTERY_SENSE_RESOLUTION_BITS 10 #define BATTERY_SENSE_RESOLUTION_BITS 10
#endif #endif
// adcStart(BATTERY_PIN); // adcStart(BATTERY_PIN);
analogReadResolution(BATTERY_SENSE_RESOLUTION_BITS); // Default of 12 is not very linear. Recommended to use 10 or 11 depending on needed resolution. analogReadResolution(BATTERY_SENSE_RESOLUTION_BITS); // Default of 12 is not very linear. Recommended to use 10 or 11
// depending on needed resolution.
batteryLevel = &analogLevel; batteryLevel = &analogLevel;
return true; return true;
#else #else
@@ -208,8 +212,12 @@ void Power::shutdown()
{ {
#ifdef TBEAM_V10 #ifdef TBEAM_V10
DEBUG_MSG("Shutting down\n"); DEBUG_MSG("Shutting down\n");
axp.setChgLEDMode(AXP20X_LED_OFF);
axp.shutdown(); axp.shutdown();
#elif NRF52_SERIES #elif NRF52_SERIES
playBeep();
ledOff(PIN_LED1);
ledOff(PIN_LED2);
doDeepSleep(DELAY_FOREVER); doDeepSleep(DELAY_FOREVER);
#endif #endif
} }
@@ -246,24 +254,23 @@ void Power::readPowerStatus()
powerStatus2.getIsCharging(), powerStatus2.getBatteryVoltageMv(), powerStatus2.getBatteryChargePercent()); powerStatus2.getIsCharging(), powerStatus2.getBatteryVoltageMv(), powerStatus2.getBatteryChargePercent());
newStatus.notifyObservers(&powerStatus2); newStatus.notifyObservers(&powerStatus2);
// If we have a battery at all and it is less than 10% full, force deep sleep if we have more than 3 low readings in a row
// If we have a battery at all and it is less than 10% full, force deep sleep if we have more than 3 low readings in a row // Supect fluctuating voltage on the RAK4631 to force it to deep sleep even if battery is at 85% after only a few days
// Supect fluctuating voltage on the RAK4631 to force it to deep sleep even if battery is at 85% after only a few days #ifdef NRF52_SERIES
#ifdef NRF52_SERIES if (powerStatus2.getHasBattery() && !powerStatus2.getHasUSB()) {
if (powerStatus2.getHasBattery() && !powerStatus2.getHasUSB()){ if (batteryLevel->getBattVoltage() < MIN_BAT_MILLIVOLTS) {
if (batteryLevel->getBattVoltage() < MIN_BAT_MILLIVOLTS){
low_voltage_counter++; low_voltage_counter++;
if (low_voltage_counter>3) if (low_voltage_counter > 3)
powerFSM.trigger(EVENT_LOW_BATTERY); powerFSM.trigger(EVENT_LOW_BATTERY);
} else { } else {
low_voltage_counter = 0; low_voltage_counter = 0;
} }
} }
#else #else
// If we have a battery at all and it is less than 10% full, force deep sleep // If we have a battery at all and it is less than 10% full, force deep sleep
if (powerStatus2.getHasBattery() && !powerStatus2.getHasUSB() && batteryLevel->getBattVoltage() < MIN_BAT_MILLIVOLTS) if (powerStatus2.getHasBattery() && !powerStatus2.getHasUSB() && batteryLevel->getBattVoltage() < MIN_BAT_MILLIVOLTS)
powerFSM.trigger(EVENT_LOW_BATTERY); powerFSM.trigger(EVENT_LOW_BATTERY);
#endif #endif
} else { } else {
// No power sensing on this board - tell everyone else we have no idea what is happening // No power sensing on this board - tell everyone else we have no idea what is happening
const PowerStatus powerStatus3 = PowerStatus(OptUnknown, OptUnknown, OptUnknown, -1, -1); const PowerStatus powerStatus3 = PowerStatus(OptUnknown, OptUnknown, OptUnknown, -1, -1);
@@ -355,40 +362,58 @@ bool Power::axp192Init()
DEBUG_MSG("DCDC3: %s\n", axp.isDCDC3Enable() ? "ENABLE" : "DISABLE"); DEBUG_MSG("DCDC3: %s\n", axp.isDCDC3Enable() ? "ENABLE" : "DISABLE");
DEBUG_MSG("Exten: %s\n", axp.isExtenEnable() ? "ENABLE" : "DISABLE"); DEBUG_MSG("Exten: %s\n", axp.isExtenEnable() ? "ENABLE" : "DISABLE");
if (radioConfig.preferences.charge_current == ChargeCurrent_MAUnset) { switch (config.power.charge_current) {
case Config_PowerConfig_ChargeCurrent_MAUnset:
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_450MA); axp.setChargeControlCur(AXP1XX_CHARGE_CUR_450MA);
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA100) { break;
case Config_PowerConfig_ChargeCurrent_MA100:
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_100MA); axp.setChargeControlCur(AXP1XX_CHARGE_CUR_100MA);
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA190) { break;
case Config_PowerConfig_ChargeCurrent_MA190:
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_190MA); axp.setChargeControlCur(AXP1XX_CHARGE_CUR_190MA);
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA280) { break;
case Config_PowerConfig_ChargeCurrent_MA280:
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_280MA); axp.setChargeControlCur(AXP1XX_CHARGE_CUR_280MA);
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA360) { break;
case Config_PowerConfig_ChargeCurrent_MA360:
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_360MA); axp.setChargeControlCur(AXP1XX_CHARGE_CUR_360MA);
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA450) { break;
case Config_PowerConfig_ChargeCurrent_MA450:
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_450MA); axp.setChargeControlCur(AXP1XX_CHARGE_CUR_450MA);
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA550) { break;
case Config_PowerConfig_ChargeCurrent_MA550:
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_550MA); axp.setChargeControlCur(AXP1XX_CHARGE_CUR_550MA);
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA630) { break;
case Config_PowerConfig_ChargeCurrent_MA630:
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_630MA); axp.setChargeControlCur(AXP1XX_CHARGE_CUR_630MA);
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA700) { break;
case Config_PowerConfig_ChargeCurrent_MA700:
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_700MA); axp.setChargeControlCur(AXP1XX_CHARGE_CUR_700MA);
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA780) { break;
case Config_PowerConfig_ChargeCurrent_MA780:
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_780MA); axp.setChargeControlCur(AXP1XX_CHARGE_CUR_780MA);
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA880) { break;
case Config_PowerConfig_ChargeCurrent_MA880:
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_880MA); axp.setChargeControlCur(AXP1XX_CHARGE_CUR_880MA);
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA960) { break;
case Config_PowerConfig_ChargeCurrent_MA960:
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_960MA); axp.setChargeControlCur(AXP1XX_CHARGE_CUR_960MA);
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA1000) { break;
case Config_PowerConfig_ChargeCurrent_MA1000:
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_1000MA); axp.setChargeControlCur(AXP1XX_CHARGE_CUR_1000MA);
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA1080) { break;
case Config_PowerConfig_ChargeCurrent_MA1080:
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_1080MA); axp.setChargeControlCur(AXP1XX_CHARGE_CUR_1080MA);
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA1160) { break;
case Config_PowerConfig_ChargeCurrent_MA1160:
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_1160MA); axp.setChargeControlCur(AXP1XX_CHARGE_CUR_1160MA);
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA1240) { break;
case Config_PowerConfig_ChargeCurrent_MA1240:
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_1240MA); axp.setChargeControlCur(AXP1XX_CHARGE_CUR_1240MA);
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA1320) { break;
case Config_PowerConfig_ChargeCurrent_MA1320:
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_1320MA); axp.setChargeControlCur(AXP1XX_CHARGE_CUR_1320MA);
break;
} }
#if 0 #if 0

View File

@@ -12,29 +12,29 @@
static bool isPowered() static bool isPowered()
{ {
// Completely circumvents the battery / power sensing logic and assumes constant power source // Completely circumvents the battery / power sensing logic and assumes constant power source
if (radioConfig.preferences.is_always_powered) { if (config.power.is_always_powered) {
return true; return true;
} }
bool isRouter = (radioConfig.preferences.role == Role_Router ? 1 : 0); bool isRouter = (config.device.role == Config_DeviceConfig_Role_Router ? 1 : 0);
// If we are not a router and we already have AC power go to POWER state after init, otherwise go to ON // If we are not a router and we already have AC power go to POWER state after init, otherwise go to ON
// We assume routers might be powered all the time, but from a low current (solar) source // We assume routers might be powered all the time, but from a low current (solar) source
bool isLowPower = radioConfig.preferences.is_low_power || isRouter; bool isPowerSavingMode = config.power.is_power_saving || isRouter;
/* To determine if we're externally powered, assumptions /* To determine if we're externally powered, assumptions
1) If we're powered up and there's no battery, we must be getting power externally. (because we'd be dead otherwise) 1) If we're powered up and there's no battery, we must be getting power externally. (because we'd be dead otherwise)
2) If we detect USB power from the power management chip, we must be getting power externally. 2) If we detect USB power from the power management chip, we must be getting power externally.
*/ */
return !isLowPower && powerStatus && (!powerStatus->getHasBattery() || powerStatus->getHasUSB()); return !isPowerSavingMode && powerStatus && (!powerStatus->getHasBattery() || powerStatus->getHasUSB());
} }
static void sdsEnter() static void sdsEnter()
{ {
DEBUG_MSG("Enter state: SDS\n"); DEBUG_MSG("Enter state: SDS\n");
// FIXME - make sure GPS and LORA radio are off first - because we want close to zero current draw // FIXME - make sure GPS and LORA radio are off first - because we want close to zero current draw
doDeepSleep(getPref_sds_secs() * 1000LL); doDeepSleep(config.power.sds_secs ? config.power.sds_secs : default_sds_secs * 1000LL);
} }
extern Power *power; extern Power *power;
@@ -51,7 +51,8 @@ static uint32_t secsSlept;
static void lsEnter() static void lsEnter()
{ {
DEBUG_MSG("lsEnter begin, ls_secs=%u\n", getPref_ls_secs()); DEBUG_MSG("lsEnter begin, ls_secs=%u\n",
config.power.ls_secs ? config.power.ls_secs : default_ls_secs);
screen->setOn(false); screen->setOn(false);
secsSlept = 0; // How long have we been sleeping this time secsSlept = 0; // How long have we been sleeping this time
@@ -65,7 +66,7 @@ static void lsIdle()
#ifndef NO_ESP32 #ifndef NO_ESP32
// Do we have more sleeping to do? // Do we have more sleeping to do?
if (secsSlept < getPref_ls_secs()) { if (secsSlept < config.power.ls_secs ? config.power.ls_secs : default_ls_secs * 1000) {
// Briefly come out of sleep long enough to blink the led once every few seconds // Briefly come out of sleep long enough to blink the led once every few seconds
uint32_t sleepTime = 30; uint32_t sleepTime = 30;
@@ -78,7 +79,7 @@ static void lsIdle()
case ESP_SLEEP_WAKEUP_TIMER: case ESP_SLEEP_WAKEUP_TIMER:
// Normal case: timer expired, we should just go back to sleep ASAP // Normal case: timer expired, we should just go back to sleep ASAP
setLed(true); // briefly turn on led setLed(true); // briefly turn on led
wakeCause2 = doLightSleep(1); // leave led on for 1ms wakeCause2 = doLightSleep(1); // leave led on for 1ms
secsSlept += sleepTime; secsSlept += sleepTime;
@@ -238,7 +239,7 @@ Fsm powerFSM(&stateBOOT);
void PowerFSM_setup() void PowerFSM_setup()
{ {
bool isRouter = (radioConfig.preferences.role == Role_Router ? 1 : 0); bool isRouter = (config.device.role == Config_DeviceConfig_Role_Router ? 1 : 0);
bool hasPower = isPowered(); bool hasPower = isPowered();
DEBUG_MSG("PowerFSM init, USB power=%d\n", hasPower); DEBUG_MSG("PowerFSM init, USB power=%d\n", hasPower);
@@ -332,7 +333,10 @@ void PowerFSM_setup()
powerFSM.add_transition(&stateDARK, &stateON, EVENT_FIRMWARE_UPDATE, NULL, "Got firmware update"); powerFSM.add_transition(&stateDARK, &stateON, EVENT_FIRMWARE_UPDATE, NULL, "Got firmware update");
powerFSM.add_transition(&stateON, &stateON, EVENT_FIRMWARE_UPDATE, NULL, "Got firmware update"); powerFSM.add_transition(&stateON, &stateON, EVENT_FIRMWARE_UPDATE, NULL, "Got firmware update");
powerFSM.add_timed_transition(&stateON, &stateDARK, getPref_screen_on_secs() * 1000, NULL, "Screen-on timeout"); powerFSM.add_timed_transition(&stateON, &stateDARK,
config.display.screen_on_secs ? config.display.screen_on_secs
: 60 * 1000 * 10,
NULL, "Screen-on timeout");
// On most boards we use light-sleep to be our main state, but on NRF52 we just stay in DARK // On most boards we use light-sleep to be our main state, but on NRF52 we just stay in DARK
State *lowPowerState = &stateLS; State *lowPowerState = &stateLS;
@@ -343,13 +347,18 @@ void PowerFSM_setup()
// We never enter light-sleep or NB states on NRF52 (because the CPU uses so little power normally) // We never enter light-sleep or NB states on NRF52 (because the CPU uses so little power normally)
// See: https://github.com/meshtastic/Meshtastic-device/issues/1071 // See: https://github.com/meshtastic/Meshtastic-device/issues/1071
if (isRouter || radioConfig.preferences.is_power_saving) { if (isRouter || config.power.is_power_saving) {
powerFSM.add_timed_transition(&stateNB, &stateLS,
// I don't think this transition is correct, turning off for now - @geeksville config.power.min_wake_secs ? config.power.min_wake_secs
// powerFSM.add_timed_transition(&stateDARK, &stateNB, getPref_phone_timeout_secs() * 1000, NULL, "Phone timeout"); : default_min_wake_secs * 1000,
powerFSM.add_timed_transition(&stateNB, &stateLS, getPref_min_wake_secs() * 1000, NULL, "Min wake timeout"); NULL, "Min wake timeout");
powerFSM.add_timed_transition(&stateDARK, &stateLS, getPref_wait_bluetooth_secs() * 1000, NULL, "Bluetooth timeout"); powerFSM.add_timed_transition(&stateDARK, &stateLS,
meshSds = getPref_mesh_sds_timeout_secs(); config.power.wait_bluetooth_secs
? config.power.wait_bluetooth_secs
: default_wait_bluetooth_secs * 1000,
NULL, "Bluetooth timeout");
meshSds = config.power.mesh_sds_timeout_secs ? config.power.mesh_sds_timeout_secs
: default_mesh_sds_timeout_secs;
} else { } else {

View File

@@ -1,9 +1,9 @@
#include "configuration.h"
#include "concurrency/OSThread.h"
#include "main.h"
#include "PowerFSM.h"
#include "power.h"
#include "NodeDB.h" #include "NodeDB.h"
#include "PowerFSM.h"
#include "concurrency/OSThread.h"
#include "configuration.h"
#include "main.h"
#include "power.h"
namespace concurrency namespace concurrency
{ {
@@ -26,13 +26,16 @@ class PowerFSMThread : public OSThread
if (powerStatus->getHasUSB()) { if (powerStatus->getHasUSB()) {
timeLastPowered = millis(); timeLastPowered = millis();
} else if (radioConfig.preferences.on_battery_shutdown_after_secs > 0 && } else if (config.power.on_battery_shutdown_after_secs > 0 &&
millis() > timeLastPowered + (1000 * radioConfig.preferences.on_battery_shutdown_after_secs)) { //shutdown after 30 minutes unpowered millis() >
timeLastPowered +
(1000 *
config.power.on_battery_shutdown_after_secs)) { // shutdown after 30 minutes unpowered
powerFSM.trigger(EVENT_SHUTDOWN); powerFSM.trigger(EVENT_SHUTDOWN);
} }
return 10; return 10;
} }
}; };
} } // namespace concurrency

View File

@@ -72,7 +72,7 @@ size_t RedirectablePrint::logDebug(const char *format, ...)
// If we are the first message on a report, include the header // If we are the first message on a report, include the header
if (!isContinuationMessage) { if (!isContinuationMessage) {
uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityFromNet); uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice);
if (rtc_sec > 0) { if (rtc_sec > 0) {
long hms = rtc_sec % SEC_PER_DAY; long hms = rtc_sec % SEC_PER_DAY;
// hms += tz.tz_dsttime * SEC_PER_HOUR; // hms += tz.tz_dsttime * SEC_PER_HOUR;

View File

@@ -1,9 +1,11 @@
#include "configuration.h"
#include "SerialConsole.h" #include "SerialConsole.h"
#include "NodeDB.h" #include "NodeDB.h"
#include "PowerFSM.h" #include "PowerFSM.h"
#include "configuration.h"
#define Port Serial #define Port Serial
// Defaulting to the formerly removed phone_timeout_secs value of 15 minutes
#define SERIAL_CONNECTION_TIMEOUT (15 * 60) * 1000UL
SerialConsole *console; SerialConsole *console;
@@ -41,11 +43,12 @@ SerialConsole::SerialConsole() : StreamAPI(&Port), RedirectablePrint(&Port)
emitRebooted(); emitRebooted();
} }
// For the serial port we can't really detect if any client is on the other side, so instead just look for recent messages // For the serial port we can't really detect if any client is on the other side, so instead just look for recent messages
bool SerialConsole::checkIsConnected() bool SerialConsole::checkIsConnected()
{ {
uint32_t now = millis(); uint32_t now = millis();
return (now - lastContactMsec) < getPref_phone_timeout_secs() * 1000UL; return (now - lastContactMsec) < SERIAL_CONNECTION_TIMEOUT;
} }
/** /**
@@ -55,10 +58,9 @@ bool SerialConsole::checkIsConnected()
bool SerialConsole::handleToRadio(const uint8_t *buf, size_t len) 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 // Turn off debug serial printing once the API is activated, because other threads could print and corrupt packets
if (!radioConfig.preferences.debug_log_enabled) if (!config.device.debug_log_enabled)
setDestination(&noopPrint); setDestination(&noopPrint);
canWrite = true; canWrite = true;
return StreamAPI::handleToRadio(buf, len); return StreamAPI::handleToRadio(buf, len);
} }

View File

@@ -1,10 +1,6 @@
#include "buzz.h" #include "buzz.h"
#include "configuration.h" #include "configuration.h"
#ifdef NRF52_SERIES
#include "variant.h"
#endif
#ifndef PIN_BUZZER #ifndef PIN_BUZZER
// Noop methods for boards w/o buzzer // Noop methods for boards w/o buzzer
@@ -12,8 +8,13 @@ void playBeep(){};
void playStartMelody(){}; void playStartMelody(){};
void playShutdownMelody(){}; void playShutdownMelody(){};
#else
#ifdef M5STACK
#include "Speaker.h"
TONE Tone;
#else #else
#include "Tone.h" #include "Tone.h"
#endif
extern "C" void delay(uint32_t dwMs); extern "C" void delay(uint32_t dwMs);
@@ -42,13 +43,26 @@ const int DURATION_1_4 = 250; // 1/4 note
void playTones(const ToneDuration *tone_durations, int size) { void playTones(const ToneDuration *tone_durations, int size) {
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
const auto &tone_duration = tone_durations[i]; const auto &tone_duration = tone_durations[i];
#ifdef M5STACK
Tone.tone(tone_duration.frequency_khz);
delay(tone_duration.duration_ms);
Tone.mute();
#else
tone(PIN_BUZZER, tone_duration.frequency_khz, tone_duration.duration_ms); tone(PIN_BUZZER, tone_duration.frequency_khz, tone_duration.duration_ms);
#endif
// to distinguish the notes, set a minimum time between them. // to distinguish the notes, set a minimum time between them.
delay(1.3 * tone_duration.duration_ms); delay(1.3 * tone_duration.duration_ms);
} }
} }
#ifdef M5STACK
void playBeep() {
ToneDuration melody[] = {{NOTE_B3, DURATION_1_4}};
playTones(melody, sizeof(melody) / sizeof(ToneDuration));
}
#else
void playBeep() { tone(PIN_BUZZER, NOTE_B3, DURATION_1_4); } void playBeep() { tone(PIN_BUZZER, NOTE_B3, DURATION_1_4); }
#endif
void playStartMelody() { void playStartMelody() {
ToneDuration melody[] = {{NOTE_B3, DURATION_1_4}, ToneDuration melody[] = {{NOTE_B3, DURATION_1_4},

View File

@@ -25,6 +25,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#pragma once #pragma once
#include <Arduino.h> #include <Arduino.h>
#ifdef RV3028_RTC
#include "Melopero_RV3028.h"
#endif
#ifdef PCF8563_RTC
#include "pcf8563.h"
#endif
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Version // Version
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@@ -114,6 +122,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#endif #endif
#ifndef TTGO_T_ECHO
#define GPS_UBLOX
#endif
// //
// Standard definitions for !ESP32 targets // Standard definitions for !ESP32 targets
// //
@@ -125,6 +137,16 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define RTC_DATA_ATTR #define RTC_DATA_ATTR
#endif #endif
// -----------------------------------------------------------------------------
// Feature toggles
// -----------------------------------------------------------------------------
// Disable use of the NTP library and related features
//#define DISABLE_NTP
// Disable the welcome screen and allow
#define DISABLE_WELCOME_UNSET
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// OLED & Input // OLED & Input
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@@ -149,6 +171,15 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// The older M5 Faces I2C Keyboard // The older M5 Faces I2C Keyboard
#define FACESKB_ADDR 0x88 #define FACESKB_ADDR 0x88
// -----------------------------------------------------------------------------
// SENSOR
// -----------------------------------------------------------------------------
#define BME_ADDR 0x76
#define BME_ADDR_ALTERNATE 0x77
#define MCP9808_ADDR 0x18
#define INA_ADDR 0x40
#define INA_ADDR_ALTERNATE 0x41
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// GPS // GPS
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@@ -248,6 +279,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define HW_VENDOR HardwareModel_NRF52840_PCA10059 #define HW_VENDOR HardwareModel_NRF52840_PCA10059
#elif defined(M5STACK)
#define HW_VENDOR HardwareModel_M5STACK
#elif NRF52_SERIES #elif NRF52_SERIES
#define HW_VENDOR HardwareModel_NRF52_UNKNOWN #define HW_VENDOR HardwareModel_NRF52_UNKNOWN

60
src/debug/einkScan.h Normal file
View File

@@ -0,0 +1,60 @@
#include "../configuration.h"
#ifdef RAK4630
#include "../main.h"
#include <SPI.h>
void d_writeCommand(uint8_t c)
{
SPI1.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0));
if (PIN_EINK_DC >= 0) digitalWrite(PIN_EINK_DC, LOW);
if (PIN_EINK_CS >= 0) digitalWrite(PIN_EINK_CS, LOW);
SPI1.transfer(c);
if (PIN_EINK_CS >= 0) digitalWrite(PIN_EINK_CS, HIGH);
if (PIN_EINK_DC >= 0) digitalWrite(PIN_EINK_DC, HIGH);
SPI1.endTransaction();
}
void d_writeData(uint8_t d)
{
SPI1.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0));
if (PIN_EINK_CS >= 0) digitalWrite(PIN_EINK_CS, LOW);
SPI1.transfer(d);
if (PIN_EINK_CS >= 0) digitalWrite(PIN_EINK_CS, HIGH);
SPI1.endTransaction();
}
unsigned long d_waitWhileBusy(uint16_t busy_time)
{
if (PIN_EINK_BUSY >= 0)
{
delay(1); // add some margin to become active
unsigned long start = micros();
while (1)
{
if (digitalRead(PIN_EINK_BUSY) != HIGH) break;
delay(1);
if (digitalRead(PIN_EINK_BUSY) != HIGH) break;
if (micros() - start > 10000000) break;
}
unsigned long elapsed = micros() - start;
(void) start;
return elapsed;
}
else return busy_time;
}
void scanEInkDevice(void)
{
SPI1.begin();
d_writeCommand(0x22);
d_writeData(0x83);
d_writeCommand(0x20);
eink_found = (d_waitWhileBusy(150) > 0) ? true : false;
if(eink_found)
DEBUG_MSG("EInk display found\n");
else
DEBUG_MSG("EInk display not found\n");
SPI1.end();
}
#endif

View File

@@ -1,32 +1,59 @@
#include "../configuration.h" #include "../configuration.h"
#include "../main.h" #include "../main.h"
#include <Wire.h> #include <Wire.h>
#include "mesh/generated/telemetry.pb.h"
#ifndef NO_WIRE #ifndef NO_WIRE
uint16_t getRegisterValue(uint8_t address, uint8_t reg, uint8_t length) {
uint16_t value = 0x00;
Wire.beginTransmission(address);
Wire.write(reg);
Wire.endTransmission();
delay(20);
Wire.requestFrom(address, length);
DEBUG_MSG("Wire.available() = %d\n", Wire.available());
if (Wire.available() == 2) {
// Read MSB, then LSB
value = (uint16_t)Wire.read() << 8;
value |= Wire.read();
} else if (Wire.available()) {
value = Wire.read();
}
return value;
}
uint8_t oled_probe(byte addr) uint8_t oled_probe(byte addr)
{ {
uint8_t r = 0; uint8_t r = 0;
uint8_t r_prev = 0;
uint8_t c = 0;
uint8_t o_probe = 0; uint8_t o_probe = 0;
Wire.beginTransmission(addr); do {
Wire.write(0x00); r_prev = r;
Wire.endTransmission(); Wire.beginTransmission(addr);
Wire.requestFrom((int)addr, 1); Wire.write(0x00);
if (Wire.available()) { Wire.endTransmission();
r = Wire.read(); Wire.requestFrom((int)addr, 1);
} if (Wire.available()) {
r &= 0x0f; r = Wire.read();
if (r == 0x08 || r == 0x00) { }
o_probe = 2; // SH1106 r &= 0x0f;
} else if ( r == 0x03 || r == 0x06 || r == 0x07) {
o_probe = 1; // SSD1306 if (r == 0x08 || r == 0x00) {
} o_probe = 2; // SH1106
DEBUG_MSG("0x%x subtype probed\n", r); } else if ( r == 0x03 || r == 0x06 || r == 0x07) {
o_probe = 1; // SSD1306
}
c++;
} while ((r != r_prev) && (c < 4));
DEBUG_MSG("0x%x subtype probed in %i tries \n", r, c);
return o_probe; return o_probe;
} }
void scanI2Cdevice(void) void scanI2Cdevice(void)
{ {
byte err, addr; byte err, addr;
uint16_t registerValue = 0x00;
int nDevices = 0; int nDevices = 0;
for (addr = 1; addr < 127; addr++) { for (addr = 1; addr < 127; addr++) {
Wire.beginTransmission(addr); Wire.beginTransmission(addr);
@@ -47,9 +74,33 @@ void scanI2Cdevice(void)
DEBUG_MSG("unknown display found\n"); DEBUG_MSG("unknown display found\n");
} }
} }
#ifdef RV3028_RTC
if (addr == RV3028_RTC){
rtc_found = addr;
DEBUG_MSG("RV3028 RTC found\n");
Melopero_RV3028 rtc;
rtc.initI2C();
rtc.writeToRegister(0x35,0x07); // no Clkout
rtc.writeToRegister(0x37,0xB4);
}
#endif
#ifdef PCF8563_RTC
if (addr == PCF8563_RTC){
rtc_found = addr;
DEBUG_MSG("PCF8563 RTC found\n");
}
#endif
if (addr == CARDKB_ADDR) { if (addr == CARDKB_ADDR) {
cardkb_found = addr; cardkb_found = addr;
DEBUG_MSG("m5 cardKB found\n"); // Do we have the RAK14006 instead?
registerValue = getRegisterValue(addr, 0x04, 1);
if (registerValue == 0x02) { // KEYPAD_VERSION
DEBUG_MSG("RAK14004 found\n");
kb_model = 0x02;
} else {
DEBUG_MSG("m5 cardKB found\n");
kb_model = 0x00;
}
} }
if (addr == FACESKB_ADDR) { if (addr == FACESKB_ADDR) {
faceskb_found = addr; faceskb_found = addr;
@@ -65,6 +116,31 @@ void scanI2Cdevice(void)
DEBUG_MSG("axp192 PMU found\n"); DEBUG_MSG("axp192 PMU found\n");
} }
#endif #endif
if (addr == BME_ADDR || addr == BME_ADDR_ALTERNATE) {
registerValue = getRegisterValue(addr, 0xD0, 1); // GET_ID
if (registerValue == 0x61) {
DEBUG_MSG("BME-680 sensor found at address 0x%x\n", (uint8_t)addr);
nodeTelemetrySensorsMap[TelemetrySensorType_BME680] = addr;
} else if (registerValue == 0x60) {
DEBUG_MSG("BME-280 sensor found at address 0x%x\n", (uint8_t)addr);
nodeTelemetrySensorsMap[TelemetrySensorType_BME280] = addr;
}
}
if (addr == INA_ADDR || addr == INA_ADDR_ALTERNATE) {
registerValue = getRegisterValue(addr, 0xFE, 2);
DEBUG_MSG("Register MFG_UID: 0x%x\n", registerValue);
if (registerValue == 0x5449) {
DEBUG_MSG("INA260 sensor found at address 0x%x\n", (uint8_t)addr);
nodeTelemetrySensorsMap[TelemetrySensorType_INA260] = addr;
} else { // Assume INA219 if INA260 ID is not found
DEBUG_MSG("INA219 sensor found at address 0x%x\n", (uint8_t)addr);
nodeTelemetrySensorsMap[TelemetrySensorType_INA219] = addr;
}
}
if (addr == MCP9808_ADDR) {
nodeTelemetrySensorsMap[TelemetrySensorType_MCP9808] = addr;
DEBUG_MSG("MCP9808 sensor found at address 0x%x\n", (uint8_t)addr);
}
} else if (err == 4) { } else if (err == 4) {
DEBUG_MSG("Unknow error at address 0x%x\n", addr); DEBUG_MSG("Unknow error at address 0x%x\n", addr);
} }
@@ -73,7 +149,7 @@ void scanI2Cdevice(void)
if (nDevices == 0) if (nDevices == 0)
DEBUG_MSG("No I2C devices found\n"); DEBUG_MSG("No I2C devices found\n");
else else
DEBUG_MSG("done\n"); DEBUG_MSG("%i I2C devices found\n",nDevices);
} }
#else #else
void scanI2Cdevice(void) {} void scanI2Cdevice(void) {}

View File

@@ -23,9 +23,6 @@
// proccess at once // proccess at once
// static uint8_t trBytes[_max(_max(_max(_max(ToRadio_size, RadioConfig_size), User_size), MyNodeInfo_size), FromRadio_size)]; // static uint8_t trBytes[_max(_max(_max(_max(ToRadio_size, RadioConfig_size), User_size), MyNodeInfo_size), FromRadio_size)];
static uint8_t fromRadioBytes[FromRadio_size]; static uint8_t fromRadioBytes[FromRadio_size];
static uint8_t toRadioBytes[ToRadio_size];
static bool bleConnected;
NimBLECharacteristic *FromNumCharacteristic; NimBLECharacteristic *FromNumCharacteristic;
NimBLEServer *bleServer; NimBLEServer *bleServer;

View File

@@ -54,7 +54,7 @@ class ESP32CryptoEngine : public CryptoEngine
static uint8_t scratch[MAX_BLOCKSIZE]; static uint8_t scratch[MAX_BLOCKSIZE];
size_t nc_off = 0; size_t nc_off = 0;
// DEBUG_MSG("ESP32 crypt fr=%x, num=%x, numBytes=%d!\n", fromNode, (uint32_t) packetId, numBytes); DEBUG_MSG("ESP32 crypt fr=%x, num=%x, numBytes=%d!\n", fromNode, (uint32_t) packetId, numBytes);
initNonce(fromNode, packetId); initNonce(fromNode, packetId);
assert(numBytes <= MAX_BLOCKSIZE); assert(numBytes <= MAX_BLOCKSIZE);
memcpy(scratch, bytes, numBytes); memcpy(scratch, bytes, numBytes);
@@ -68,8 +68,6 @@ class ESP32CryptoEngine : public CryptoEngine
virtual void decrypt(uint32_t fromNode, uint64_t packetId, size_t numBytes, uint8_t *bytes) override virtual void decrypt(uint32_t fromNode, uint64_t packetId, size_t numBytes, uint8_t *bytes) override
{ {
// DEBUG_MSG("ESP32 decrypt!\n");
// For CTR, the implementation is the same // For CTR, the implementation is the same
encrypt(fromNode, packetId, numBytes, bytes); encrypt(fromNode, packetId, numBytes, bytes);
} }

View File

@@ -1,7 +1,7 @@
#include "configuration.h"
#include "GPS.h" #include "GPS.h"
#include "NodeDB.h" #include "NodeDB.h"
#include "RTC.h" #include "RTC.h"
#include "configuration.h"
#include "sleep.h" #include "sleep.h"
#include <assert.h> #include <assert.h>
@@ -16,18 +16,49 @@ HardwareSerial *GPS::_serial_gps = &Serial1;
HardwareSerial *GPS::_serial_gps = NULL; HardwareSerial *GPS::_serial_gps = NULL;
#endif #endif
#ifdef GPS_I2C_ADDRESS
uint8_t GPS::i2cAddress = GPS_I2C_ADDRESS;
#else
uint8_t GPS::i2cAddress = 0;
#endif
GPS *gps; GPS *gps;
/// Multiple GPS instances might use the same serial port (in sequence), but we can /// Multiple GPS instances might use the same serial port (in sequence), but we can
/// only init that port once. /// only init that port once.
static bool didSerialInit; static bool didSerialInit;
bool GPS::getACK(uint8_t c, uint8_t i) {
uint8_t b;
uint8_t ack = 0;
const uint8_t ackP[2] = {c, i};
uint8_t buf[10] = {0xB5, 0x62, 0x05, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00};
unsigned long startTime = millis();
for (int j = 2; j < 6; j++) {
buf[8] += buf[j];
buf[9] += buf[8];
}
for (int j = 0; j < 2; j++) {
buf[6 + j] = ackP[j];
buf[8] += buf[6 + j];
buf[9] += buf[8];
}
while (1) {
if (ack > 9) {
return true;
}
if (millis() - startTime > 1000) {
return false;
}
if (_serial_gps->available()) {
b = _serial_gps->read();
if (b == buf[ack]) {
ack++;
}
else {
ack = 0;
}
}
}
}
bool GPS::setupGPS() bool GPS::setupGPS()
{ {
if (_serial_gps && !didSerialInit) { if (_serial_gps && !didSerialInit) {
@@ -43,13 +74,17 @@ bool GPS::setupGPS()
_serial_gps->setRxBufferSize(2048); // the default is 256 _serial_gps->setRxBufferSize(2048); // the default is 256
#endif #endif
#ifdef TTGO_T_ECHO #ifdef TTGO_T_ECHO
// Switch to 4800 baud, then close and reopen port // Switch to 9600 baud, then close and reopen port
_serial_gps->write("$PCAS01,0*1C\r\n");
delay(250);
_serial_gps->end(); _serial_gps->end();
delay(250); delay(250);
_serial_gps->begin(4800); _serial_gps->begin(4800);
delay(250); 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 // Initialize the L76K Chip, use GPS + GLONASS
_serial_gps->write("$PCAS04,5*1C\r\n"); _serial_gps->write("$PCAS04,5*1C\r\n");
delay(250); delay(250);
@@ -59,7 +94,62 @@ bool GPS::setupGPS()
// Switch to Vehicle Mode, since SoftRF enables Aviation < 2g // Switch to Vehicle Mode, since SoftRF enables Aviation < 2g
_serial_gps->write("$PCAS11,3*1E\r\n"); _serial_gps->write("$PCAS11,3*1E\r\n");
delay(250); 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 #endif
} }
@@ -95,11 +185,19 @@ bool GPS::setup()
GPS::~GPS() GPS::~GPS()
{ {
// we really should unregister our sleep observer // we really should unregister our sleep observer
notifySleepObserver.unobserve(); notifySleepObserver.unobserve(&notifySleep);
notifyDeepSleepObserver.unobserve(); notifyDeepSleepObserver.unobserve(&notifyDeepSleep);
} }
bool GPS::hasLock() { return hasValidLocation; } bool GPS::hasLock()
{
return hasValidLocation;
}
bool GPS::hasFlow()
{
return hasGPS;
}
// Allow defining the polarity of the WAKE output. default is active high // Allow defining the polarity of the WAKE output. default is active high
#ifndef GPS_WAKE_ACTIVE #ifndef GPS_WAKE_ACTIVE
@@ -169,14 +267,16 @@ void GPS::setAwake(bool on)
*/ */
uint32_t GPS::getWakeTime() const uint32_t GPS::getWakeTime() const
{ {
uint32_t t = radioConfig.preferences.gps_attempt_time; uint32_t t = config.position.gps_attempt_time;
if (t == UINT32_MAX) if (t == UINT32_MAX)
return t; // already maxint return t; // already maxint
if (t == 0) if (t == 0)
t = (radioConfig.preferences.role == Role_Router) ? 5 * 60 : 15 * 60; // Allow up to 15 mins for each attempt (probably will be much t = (config.device.role == Config_DeviceConfig_Role_Router)
// less if we can find sats) or less if a router ? 5 * 60
: 15 * 60; // Allow up to 15 mins for each attempt (probably will be much
// less if we can find sats) or less if a router
t *= 1000; // msecs t *= 1000; // msecs
@@ -187,18 +287,18 @@ uint32_t GPS::getWakeTime() const
*/ */
uint32_t GPS::getSleepTime() const uint32_t GPS::getSleepTime() const
{ {
uint32_t t = radioConfig.preferences.gps_update_interval; uint32_t t = config.position.gps_update_interval;
bool gps_disabled = radioConfig.preferences.gps_disabled; bool gps_disabled = config.position.gps_disabled;
bool loc_share_disabled = radioConfig.preferences.location_share_disabled;
if (gps_disabled || loc_share_disabled) if (gps_disabled)
t = UINT32_MAX; // Sleep forever now t = UINT32_MAX; // Sleep forever now
if (t == UINT32_MAX) if (t == UINT32_MAX)
return t; // already maxint return t; // already maxint
if (t == 0) // default - unset in preferences if (t == 0) // default - unset in preferences
t = (radioConfig.preferences.role == Role_Router) ? 24 * 60 * 60 : 2 * 60; // 2 mins or once per day for routers t = (config.device.role == Config_DeviceConfig_Role_Router) ? 24 * 60 * 60
: 2 * 60; // 2 mins or once per day for routers
t *= 1000; t *= 1000;
@@ -211,12 +311,10 @@ void GPS::publishUpdate()
shouldPublish = false; shouldPublish = false;
// In debug logs, identify position by @timestamp:stage (stage 2 = publish) // In debug logs, identify position by @timestamp:stage (stage 2 = publish)
DEBUG_MSG("publishing pos@%x:2, hasVal=%d, GPSlock=%d\n", DEBUG_MSG("publishing pos@%x:2, hasVal=%d, GPSlock=%d\n", p.pos_timestamp, hasValidLocation, hasLock());
p.pos_timestamp, hasValidLocation, hasLock());
// Notify any status instances that are observing us // Notify any status instances that are observing us
const meshtastic::GPSStatus status = const meshtastic::GPSStatus status = meshtastic::GPSStatus(hasValidLocation, isConnected(), p);
meshtastic::GPSStatus(hasValidLocation, isConnected(), p);
newStatus.notifyObservers(&status); newStatus.notifyObservers(&status);
} }
} }
@@ -226,6 +324,15 @@ int32_t GPS::runOnce()
if (whileIdle()) { if (whileIdle()) {
// if we have received valid NMEA claim we are connected // if we have received valid NMEA claim we are connected
setConnected(); setConnected();
} else {
#ifdef 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.saveToDisk();
}
#endif
} }
// If we are overdue for an update, turn on the GPS and at least publish the current status // If we are overdue for an update, turn on the GPS and at least publish the current status
@@ -325,10 +432,6 @@ int GPS::prepareDeepSleep(void *unused)
return 0; return 0;
} }
#ifdef GPS_TX_PIN
#include "UBloxGPS.h"
#endif
#ifndef NO_GPS #ifndef NO_GPS
#include "NMEAGPS.h" #include "NMEAGPS.h"
#endif #endif
@@ -339,31 +442,15 @@ GPS *createGps()
#ifdef NO_GPS #ifdef NO_GPS
return nullptr; return nullptr;
#else #else
if (!radioConfig.preferences.gps_disabled){ if (!config.position.gps_disabled) {
#ifdef GPS_ALTITUDE_HAE #ifdef GPS_ALTITUDE_HAE
DEBUG_MSG("Using HAE altitude model\n"); DEBUG_MSG("Using HAE altitude model\n");
#else #else
DEBUG_MSG("Using MSL altitude model\n"); DEBUG_MSG("Using MSL altitude model\n");
#endif #endif
// If we don't have bidirectional comms, we can't even try talking to UBLOX
#ifdef GPS_TX_PIN
// Init GPS - first try ublox
UBloxGPS *ublox = new UBloxGPS();
if (!ublox->setup()) {
DEBUG_MSG("ERROR: No UBLOX GPS found\n");
delete ublox;
ublox = NULL;
} else {
DEBUG_MSG("Using UBLOX Mode\n");
return ublox;
}
#endif
if (GPS::_serial_gps) { if (GPS::_serial_gps) {
// Some boards might have only the TX line from the GPS connected, in that case, we can't configure it at all. Just // Some boards might have only the TX line from the GPS connected, in that case, we can't configure it at all. Just
// assume NMEA at 9600 baud. // assume NMEA at 9600 baud.
DEBUG_MSG("Using NMEA Mode\n");
GPS *new_gps = new NMEAGPS(); GPS *new_gps = new NMEAGPS();
new_gps->setup(); new_gps->setup();
return new_gps; return new_gps;

View File

@@ -40,9 +40,6 @@ class GPS : private concurrency::OSThread
/** If !NULL we will use this serial port to construct our GPS */ /** If !NULL we will use this serial port to construct our GPS */
static HardwareSerial *_serial_gps; static HardwareSerial *_serial_gps;
/** If !0 we will attempt to connect to the GPS over I2C */
static uint8_t i2cAddress;
Position p = Position_init_default; Position p = Position_init_default;
GPS() : concurrency::OSThread("GPS") {} GPS() : concurrency::OSThread("GPS") {}
@@ -60,6 +57,9 @@ class GPS : private concurrency::OSThread
/// Returns true if we have acquired GPS lock. /// Returns true if we have acquired GPS lock.
virtual bool hasLock(); virtual bool hasLock();
/// Returns true if there's valid data flow with the chip.
virtual bool hasFlow();
/// Return true if we are connected to a GPS /// Return true if we are connected to a GPS
bool isConnected() const { return hasGPS; } bool isConnected() const { return hasGPS; }
@@ -138,6 +138,8 @@ class GPS : private concurrency::OSThread
*/ */
uint32_t getSleepTime() const; uint32_t getSleepTime() const;
bool getACK(uint8_t c, uint8_t i);
/** /**
* Tell users we have new GPS readings * Tell users we have new GPS readings
*/ */

View File

@@ -17,6 +17,19 @@ static int32_t toDegInt(RawDegrees d)
return r; return r;
} }
bool NMEAGPS::factoryReset()
{
#ifdef GPS_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;
}
bool NMEAGPS::setupGPS() bool NMEAGPS::setupGPS()
{ {
GPS::setupGPS(); GPS::setupGPS();
@@ -64,11 +77,12 @@ The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of s
t.tm_mon = d.month() - 1; t.tm_mon = d.month() - 1;
t.tm_year = d.year() - 1900; t.tm_year = d.year() - 1900;
t.tm_isdst = false; t.tm_isdst = false;
DEBUG_MSG("NMEA GPS time %d-%d-%d %d:%d:%d\n", d.year(), d.month(), t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec); if (t.tm_mon > -1){
DEBUG_MSG("NMEA GPS time %02d-%02d-%02d %02d:%02d:%02d\n", d.year(), d.month(), t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
perhapsSetRTC(RTCQualityGPS, t); perhapsSetRTC(RTCQualityGPS, t);
return true;
return true; } else
return false;
} else } else
return false; return false;
} }
@@ -128,8 +142,16 @@ bool NMEAGPS::lookForLocation()
auto loc = reader.location.value(); auto loc = reader.location.value();
// Bail out EARLY to avoid overwriting previous good data (like #857) // Bail out EARLY to avoid overwriting previous good data (like #857)
if(toDegInt(loc.lat) == 0) { if (toDegInt(loc.lat) > 900000000) {
DEBUG_MSG("Ignoring bogus NMEA position\n"); #ifdef GPS_EXTRAVERBOSE
DEBUG_MSG("Bail out EARLY on LAT %i\n",toDegInt(loc.lat));
#endif
return false;
}
if (toDegInt(loc.lng) > 1800000000) {
#ifdef GPS_EXTRAVERBOSE
DEBUG_MSG("Bail out EARLY on LNG %i\n",toDegInt(loc.lng));
#endif
return false; return false;
} }
@@ -213,6 +235,10 @@ bool NMEAGPS::hasLock()
return false; return false;
} }
bool NMEAGPS::hasFlow()
{
return reader.passedChecksum() > 0;
}
bool NMEAGPS::whileIdle() bool NMEAGPS::whileIdle()
{ {

View File

@@ -25,6 +25,8 @@ class NMEAGPS : public GPS
public: public:
virtual bool setupGPS() override; virtual bool setupGPS() override;
virtual bool factoryReset() override;
protected: protected:
/** Subclasses should look for serial rx characters here and feed it to their GPS parser /** Subclasses should look for serial rx characters here and feed it to their GPS parser
* *
@@ -49,4 +51,6 @@ class NMEAGPS : public GPS
virtual bool lookForLocation() override; virtual bool lookForLocation() override;
virtual bool hasLock() override; virtual bool hasLock() override;
virtual bool hasFlow() override;
}; };

View File

@@ -1,5 +1,6 @@
#include "RTC.h" #include "RTC.h"
#include "configuration.h" #include "configuration.h"
#include "main.h"
#include <sys/time.h> #include <sys/time.h>
#include <time.h> #include <time.h>
@@ -18,14 +19,57 @@ static uint64_t zeroOffsetSecs; // GPS based time in secs since 1970 - only upda
void readFromRTC() void readFromRTC()
{ {
struct timeval tv; /* btw settimeofday() is helpfull here too*/ struct timeval tv; /* btw settimeofday() is helpfull here too*/
#ifdef RV3028_RTC
if(rtc_found == RV3028_RTC) {
uint32_t now = millis();
Melopero_RV3028 rtc;
rtc.initI2C();
tm t;
t.tm_year = rtc.getYear() - 1900;
t.tm_mon = rtc.getMonth() - 1;
t.tm_mday = rtc.getDate();
t.tm_hour = rtc.getHour();
t.tm_min = rtc.getMinute();
t.tm_sec = rtc.getSecond();
tv.tv_sec = mktime(&t);
tv.tv_usec = 0;
DEBUG_MSG("Read RTC time from RV3028 as %ld\n", tv.tv_sec);
timeStartMsec = now;
zeroOffsetSecs = tv.tv_sec;
if (currentQuality == RTCQualityNone) {
currentQuality = RTCQualityDevice;
}
}
#elif defined(PCF8563_RTC)
if(rtc_found == PCF8563_RTC) {
uint32_t now = millis();
PCF8563_Class rtc;
rtc.begin();
auto tc = rtc.getDateTime();
tm t;
t.tm_year = tc.year;
t.tm_mon = tc.month;
t.tm_mday = tc.day;
t.tm_hour = tc.hour;
t.tm_min = tc.minute;
t.tm_sec = tc.second;
tv.tv_sec = mktime(&t);
tv.tv_usec = 0;
DEBUG_MSG("Read RTC time from PCF8563 as %ld\n", tv.tv_sec);
timeStartMsec = now;
zeroOffsetSecs = tv.tv_sec;
if (currentQuality == RTCQualityNone) {
currentQuality = RTCQualityDevice;
}
}
#else
if (!gettimeofday(&tv, NULL)) { if (!gettimeofday(&tv, NULL)) {
uint32_t now = millis(); uint32_t now = millis();
DEBUG_MSG("Read RTC time as %ld\n", tv.tv_sec);
DEBUG_MSG("Read RTC time as %ld (cur millis %u) quality=%d\n", tv.tv_sec, now, currentQuality);
timeStartMsec = now; timeStartMsec = now;
zeroOffsetSecs = tv.tv_sec; zeroOffsetSecs = tv.tv_sec;
} }
#endif
} }
/// If we haven't yet set our RTC this boot, set it from a GPS derived time /// If we haven't yet set our RTC this boot, set it from a GPS derived time
@@ -55,12 +99,28 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv)
zeroOffsetSecs = tv->tv_sec; zeroOffsetSecs = tv->tv_sec;
// If this platform has a setable RTC, set it // If this platform has a setable RTC, set it
#ifndef NO_ESP32 #ifdef RV3028_RTC
if(rtc_found == RV3028_RTC) {
Melopero_RV3028 rtc;
rtc.initI2C();
tm *t = localtime(&tv->tv_sec);
rtc.setTime(t->tm_year + 1900, t->tm_mon + 1, t->tm_wday, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
DEBUG_MSG("RV3028_RTC setTime %02d-%02d-%02d %02d:%02d:%02d %ld\n", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, tv->tv_sec);
}
#elif defined(PCF8563_RTC)
if(rtc_found == PCF8563_RTC) {
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);
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(NO_ESP32)
settimeofday(tv, NULL); settimeofday(tv, NULL);
#endif #endif
// nrf52 doesn't have a readable RTC (yet - software not written) // nrf52 doesn't have a readable RTC (yet - software not written)
#if defined(PORTDUINO) || !defined(NO_ESP32) #if defined(PORTDUINO) || !defined(NO_ESP32) || defined(RV3028_RTC) || defined(PCF8563_RTC)
readFromRTC(); readFromRTC();
#endif #endif

View File

@@ -5,17 +5,21 @@
#include <Arduino.h> #include <Arduino.h>
enum RTCQuality { enum RTCQuality {
/// We haven't had our RTC set yet /// We haven't had our RTC set yet
RTCQualityNone = 0, RTCQualityNone = 0,
/// We got time from an onboard peripheral after boot.
RTCQualityDevice = 1,
/// Some other node gave us a time we can use /// Some other node gave us a time we can use
RTCQualityFromNet = 1, RTCQualityFromNet = 2,
/// Our time is based on NTP /// Our time is based on NTP
RTCQualityNTP= 2, RTCQualityNTP= 3,
/// Our time is based on our own GPS /// Our time is based on our own GPS
RTCQualityGPS = 3 RTCQualityGPS = 4
}; };
RTCQuality getRTCQuality(); RTCQuality getRTCQuality();

View File

@@ -1,328 +0,0 @@
#include "configuration.h"
#include "UBloxGPS.h"
#include "RTC.h"
#include "error.h"
#include "sleep.h"
#include <assert.h>
// if gps_update_interval below this value, do not powercycle the GPS
#define UBLOX_POWEROFF_THRESHOLD 90
#define PDOP_INVALID 9999
// #define UBX_MODE_NMEA
extern RadioConfig radioConfig;
UBloxGPS::UBloxGPS() {}
bool UBloxGPS::tryConnect()
{
bool c = false;
if (_serial_gps)
c = ublox.begin(*_serial_gps);
if (!c && i2cAddress) {
extern bool neo6M; // Super skanky - if we are talking to the device i2c we assume it is a neo7 on a RAK815, which
// supports the newer API
neo6M = true;
c = ublox.begin(Wire, i2cAddress);
}
if (c)
setConnected();
return c;
}
bool UBloxGPS::setupGPS()
{
GPS::setupGPS();
// uncomment to see debug info
// ublox.enableDebugging(Serial);
// try a second time, the ublox lib serial parsing is buggy?
// see https://github.com/meshtastic/Meshtastic-device/issues/376
for (int i = 0; (i < 3) && !tryConnect(); i++)
delay(500);
if (isConnected()) {
#ifdef UBX_MODE_NMEA
DEBUG_MSG("Connected to UBLOX GPS, downgrading to NMEA mode\n");
DEBUG_MSG("- GPS errors below are related and safe to ignore\n");
#else
DEBUG_MSG("Connected to UBLOX GPS successfully\n");
#endif
if (!setUBXMode())
RECORD_CRITICALERROR(CriticalErrorCode_UBloxInitFailed); // Don't halt the boot if saving the config fails, but do report the bug
#ifdef UBX_MODE_NMEA
return false;
#else
return true;
#endif
} else {
return false;
}
}
bool UBloxGPS::setUBXMode()
{
#ifdef UBX_MODE_NMEA
if (_serial_gps) {
ublox.setUART1Output(COM_TYPE_NMEA, 1000);
}
if (i2cAddress) {
ublox.setI2COutput(COM_TYPE_NMEA, 1000);
}
return false; // pretend initialization failed to force NMEA mode
#endif
if (_serial_gps) {
if (!ublox.setUART1Output(COM_TYPE_UBX, 1000)) // Use native API
return false;
}
if (i2cAddress) {
if (!ublox.setI2COutput(COM_TYPE_UBX, 1000))
return false;
}
if (!ublox.setNavigationFrequency(1, 1000)) // Produce 4x/sec to keep the amount of time we stall in getPVT low
return false;
// ok = ublox.setAutoPVT(false); // Not implemented on NEO-6M
// assert(ok);
// ok = ublox.setDynamicModel(DYN_MODEL_BIKE); // probably PEDESTRIAN but just in case assume bike speeds
// assert(ok);
// per https://github.com/meshtastic/Meshtastic-device/issues/376 powerSaveMode might not work with the marginal
// TTGO antennas
// if (!ublox.powerSaveMode(true, 2000)) // use power save mode, the default timeout (1100ms seems a bit too tight)
// return false;
if (!ublox.saveConfiguration(3000))
return false;
return true;
}
/**
* Reset our GPS back to factory settings
*
* @return true for success
*/
bool UBloxGPS::factoryReset()
{
bool ok = false;
// It is useful to force back into factory defaults (9600baud, NMEA to test the behavior of boards that don't have
// GPS_TX connected)
ublox.factoryReset();
delay(5000);
tryConnect(); // sets isConnected
// try a second time, the ublox lib serial parsing is buggy?
for (int i = 0; (i < 3) && !tryConnect(); i++)
delay(500);
DEBUG_MSG("GPS Factory reset success=%d\n", isConnected());
if (isConnected())
ok = setUBXMode();
return ok;
}
/** Idle processing while GPS is looking for lock */
void UBloxGPS::whileActive()
{
ublox.flushPVT(); // reset ALL freshness flags first
ublox.getT(maxWait()); // ask for new time data - hopefully ready when we come back
// Ask for a new position fix - hopefully it will have results ready by next time
// the order here is important, because we only check for has latitude when reading
//ublox.getSIV(maxWait()); // redundant with getPDOP below
ublox.getPDOP(maxWait()); // will trigger getSOL on NEO6, getP on others
ublox.getP(maxWait()); // will trigger getPosLLH on NEO6, getP on others
// the fixType flag will be checked and updated in lookForLocation()
}
/**
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
* Override this method to check for new locations
*
* @return true if we've acquired a new location
*/
bool UBloxGPS::lookForTime()
{
if (ublox.moduleQueried.gpsSecond) {
/* Convert to unix time
The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of seconds that have elapsed since January
1, 1970 (midnight UTC/GMT), not counting leap seconds (in ISO 8601: 1970-01-01T00:00:00Z).
*/
struct tm t;
t.tm_sec = ublox.getSecond(0);
t.tm_min = ublox.getMinute(0);
t.tm_hour = ublox.getHour(0);
t.tm_mday = ublox.getDay(0);
t.tm_mon = ublox.getMonth(0) - 1;
t.tm_year = ublox.getYear(0) - 1900;
t.tm_isdst = false;
perhapsSetRTC(RTCQualityGPS, t);
return true;
}
return false;
}
/**
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
* Override this method to check for new locations
*
* @return true if we've acquired a new location
*/
bool UBloxGPS::lookForLocation()
{
bool foundLocation = false;
// check if a complete GPS solution set is available for reading
// (some of these, like lat/lon are redundant and can be removed)
if ( ! (ublox.moduleQueried.fixType &&
ublox.moduleQueried.latitude &&
ublox.moduleQueried.longitude &&
ublox.moduleQueried.altitude &&
ublox.moduleQueried.pDOP &&
ublox.moduleQueried.SIV &&
ublox.moduleQueried.gpsDay))
{
// Not ready? No problem! We'll try again later.
return false;
}
fixType = ublox.getFixType();
#ifdef UBLOX_EXTRAVERBOSE
DEBUG_MSG("FixType=%d\n", fixType);
#endif
// check if GPS has an acceptable lock
if (! hasLock()) {
ublox.flushPVT(); // reset ALL freshness flags
return false;
}
// read lat/lon/alt/dop data into temporary variables to avoid
// overwriting global variables with potentially invalid data
int32_t tmp_dop = ublox.getPDOP(0); // PDOP (an accuracy metric) is reported in 10^2 units so we have to scale down when we use it
int32_t tmp_lat = ublox.getLatitude(0);
int32_t tmp_lon = ublox.getLongitude(0);
int32_t tmp_alt_msl = ublox.getAltitudeMSL(0);
int32_t tmp_alt_hae = ublox.getAltitude(0);
int32_t max_dop = PDOP_INVALID;
if (radioConfig.preferences.gps_max_dop)
max_dop = radioConfig.preferences.gps_max_dop * 100; // scaling
// Note: heading is only currently implmented in the ublox for the 8m chipset - therefore
// don't read it here - it will generate an ignored getPVT command on the 6ms
// heading = ublox.getHeading(0);
// read positional timestamp
struct tm t;
t.tm_sec = ublox.getSecond(0);
t.tm_min = ublox.getMinute(0);
t.tm_hour = ublox.getHour(0);
t.tm_mday = ublox.getDay(0);
t.tm_mon = ublox.getMonth(0) - 1;
t.tm_year = ublox.getYear(0) - 1900;
t.tm_isdst = false;
time_t tmp_ts = mktime(&t);
// FIXME - can opportunistically attempt to set RTC from GPS timestamp?
// bogus lat lon is reported as 0 or 0 (can be bogus just for one)
// Also: apparently when the GPS is initially reporting lock it can output a bogus latitude > 90 deg!
// FIXME - NULL ISLAND is a real location on Earth!
foundLocation = (tmp_lat != 0) && (tmp_lon != 0) &&
(tmp_lat <= 900000000) && (tmp_lat >= -900000000) &&
(tmp_dop < max_dop);
// only if entire dataset is valid, update globals from temp vars
if (foundLocation) {
p.location_source = Position_LocSource_LOCSRC_GPS_INTERNAL;
p.longitude_i = tmp_lon;
p.latitude_i = tmp_lat;
if (fixType > 2) {
// if fix is 2d, ignore altitude data
p.altitude = tmp_alt_msl / 1000;
p.altitude_hae = tmp_alt_hae / 1000;
p.alt_geoid_sep = (tmp_alt_hae - tmp_alt_msl) / 1000;
} else {
#ifdef GPS_EXTRAVERBOSE
DEBUG_MSG("no altitude data (fixType=%d)\n", fixType);
#endif
// clean up old values in case it's a 3d-2d fix transition
p.altitude = p.altitude_hae = p.alt_geoid_sep = 0;
}
p.pos_timestamp = tmp_ts;
p.PDOP = tmp_dop;
p.fix_type = fixType;
p.sats_in_view = ublox.getSIV(0);
// In debug logs, identify position by @timestamp:stage (stage 1 = birth)
DEBUG_MSG("lookForLocation() new pos@%x:1\n", tmp_ts);
} else {
// INVALID solution - should never happen
DEBUG_MSG("Invalid location lat/lon/hae/dop %d/%d/%d/%d - discarded\n",
tmp_lat, tmp_lon, tmp_alt_hae, tmp_dop);
}
ublox.flushPVT(); // reset ALL freshness flags at the end
return foundLocation;
}
bool UBloxGPS::hasLock()
{
if (radioConfig.preferences.gps_accept_2d)
return (fixType >= 2 && fixType <= 4);
else
return (fixType >= 3 && fixType <= 4);
}
bool UBloxGPS::whileIdle()
{
// if using i2c or serial look too see if any chars are ready
return ublox.checkUblox(); // See if new data is available. Process bytes as they come in.
}
/// If possible force the GPS into sleep/low power mode
/// Note: ublox doesn't need a wake method, because as soon as we send chars to the GPS it will wake up
void UBloxGPS::sleep()
{
if (radioConfig.preferences.gps_update_interval > UBLOX_POWEROFF_THRESHOLD) {
// Tell GPS to power down until we send it characters on serial port (we leave vcc connected)
ublox.powerOff();
// setGPSPower(false);
}
}
void UBloxGPS::wake()
{
if (radioConfig.preferences.gps_update_interval > UBLOX_POWEROFF_THRESHOLD) {
fixType = 0; // assume we have no fix yet
}
// this is idempotent
setGPSPower(true);
// Note: no delay needed because now we leave gps power on always and instead use ublox.powerOff()
// Give time for the GPS to boot
// delay(200);
}

View File

@@ -1,72 +0,0 @@
#pragma once
#include "GPS.h"
#include "Observer.h"
#include "SparkFun_Ublox_Arduino_Library.h"
/**
* A gps class that only reads from the GPS periodically (and FIXME - eventually keeps the gps powered down except when reading)
*
* When new data is available it will notify observers.
*/
class UBloxGPS : public GPS
{
SFE_UBLOX_GPS ublox;
uint8_t fixType = 0;
public:
UBloxGPS();
/**
* Reset our GPS back to factory settings
*
* @return true for success
*/
bool factoryReset() override;
protected:
/**
* Returns true if we succeeded
*/
virtual bool setupGPS() override;
/** Subclasses should look for serial rx characters here and feed it to their GPS parser
*
* Return true if we received a valid message from the GPS
*/
virtual bool whileIdle() override;
/** Idle processing while GPS is looking for lock */
virtual void whileActive() override;
/**
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
* Override this method to check for new locations
*
* @return true if we've acquired a time
*/
virtual bool lookForTime() override;
/**
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
* Override this method to check for new locations
*
* @return true if we've acquired a new location
*/
virtual bool lookForLocation() override;
virtual bool hasLock() override;
/// If possible force the GPS into sleep/low power mode
virtual void sleep() override;
virtual void wake() override;
private:
/// Attempt to connect to our GPS, returns false if no gps is present
bool tryConnect();
/// Switch to our desired operating mode and save the settings to flash
/// returns true for success
bool setUBXMode();
uint16_t maxWait() const { return i2cAddress ? 300 : 0; /*If using i2c we must poll with wait */ }
};

View File

@@ -1,6 +1,7 @@
#include "configuration.h" #include "configuration.h"
#ifdef HAS_EINK #ifdef HAS_EINK
#include "main.h"
#include "EInkDisplay2.h" #include "EInkDisplay2.h"
#include "SPILock.h" #include "SPILock.h"
#include <SPI.h> #include <SPI.h>
@@ -30,6 +31,11 @@
//4.2 inch 300x400 - GxEPD2_420_M01 //4.2 inch 300x400 - GxEPD2_420_M01
#define TECHO_DISPLAY_MODEL GxEPD2_420_M01 #define TECHO_DISPLAY_MODEL GxEPD2_420_M01
#elif defined(M5_COREINK)
//M5Stack CoreInk
//1.54 inch 200x200 - GxEPD2_154_M09
#define TECHO_DISPLAY_MODEL GxEPD2_154_M09
#endif #endif
GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT> *adafruitDisplay; GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT> *adafruitDisplay;
@@ -57,6 +63,12 @@ EInkDisplay::EInkDisplay(uint8_t address, int sda, int scl)
//GxEPD2_420_M01 //GxEPD2_420_M01
setGeometry(GEOMETRY_RAWMODE, 300, 400); setGeometry(GEOMETRY_RAWMODE, 300, 400);
#elif defined(M5_COREINK)
//M5Stack_CoreInk 200x200
//1.54 inch 200x200 - GxEPD2_154_M09
setGeometry(GEOMETRY_RAWMODE, EPD_HEIGHT, EPD_WIDTH);
#endif #endif
// setGeometry(GEOMETRY_RAWMODE, 128, 64); // old resolution // setGeometry(GEOMETRY_RAWMODE, 128, 64); // old resolution
// setGeometry(GEOMETRY_128_64); // We originally used this because I wasn't sure if rawmode worked - it does // setGeometry(GEOMETRY_128_64); // We originally used this because I wasn't sure if rawmode worked - it does
@@ -107,7 +119,7 @@ bool EInkDisplay::forceDisplay(uint32_t msecLimit)
// 4.2 inch 300x400 - GxEPD2_420_M01 // 4.2 inch 300x400 - GxEPD2_420_M01
//adafruitDisplay->nextPage(); //adafruitDisplay->nextPage();
#elif defined(PCA10059) #elif defined(PCA10059) || defined(M5_COREINK)
adafruitDisplay->nextPage(); adafruitDisplay->nextPage();
#endif #endif
@@ -171,18 +183,21 @@ bool EInkDisplay::connect()
} }
#elif defined(RAK4630) #elif defined(RAK4630)
{ {
auto lowLevel = new TECHO_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY); if (eink_found) {
auto lowLevel = new TECHO_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY);
adafruitDisplay = new GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT>(*lowLevel); adafruitDisplay = new GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT>(*lowLevel);
adafruitDisplay->init(115200, true, 10, false, SPI1, SPISettings(4000000, MSBFIRST, SPI_MODE0)); adafruitDisplay->init(115200, true, 10, false, SPI1, SPISettings(4000000, MSBFIRST, SPI_MODE0));
//RAK14000 2.13 inch b/w 250x122 does not support partial updates //RAK14000 2.13 inch b/w 250x122 does not support partial updates
adafruitDisplay->setRotation(3); adafruitDisplay->setRotation(3);
//For 1.54, 2.9 and 4.2 //For 1.54, 2.9 and 4.2
//adafruitDisplay->setRotation(1); //adafruitDisplay->setRotation(1);
//adafruitDisplay->setPartialWindow(0, 0, displayWidth, displayHeight);
adafruitDisplay->setPartialWindow(0, 0, displayWidth, displayHeight); } else {
(void)adafruitDisplay;
}
} }
#elif defined(PCA10059) #elif defined(PCA10059)
{ {
@@ -192,6 +207,13 @@ bool EInkDisplay::connect()
adafruitDisplay->setRotation(3); adafruitDisplay->setRotation(3);
adafruitDisplay->setPartialWindow(0, 0, displayWidth, displayHeight); adafruitDisplay->setPartialWindow(0, 0, displayWidth, displayHeight);
} }
#elif defined(M5_COREINK)
auto lowLevel = new TECHO_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY);
adafruitDisplay = new GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT>(*lowLevel);
delay(100);
adafruitDisplay->init(115200, true, 20, false, SPI, SPISettings(4000000, MSBFIRST, SPI_MODE0));
adafruitDisplay->setRotation(0);
adafruitDisplay->setPartialWindow(0, 0, EPD_WIDTH, EPD_HEIGHT);
#endif #endif

View File

@@ -20,6 +20,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "configuration.h" #include "configuration.h"
#ifndef NO_SCREEN
#include <OLEDDisplay.h> #include <OLEDDisplay.h>
#include "GPS.h" #include "GPS.h"
@@ -32,6 +33,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "main.h" #include "main.h"
#include "mesh-pb-constants.h" #include "mesh-pb-constants.h"
#include "mesh/Channels.h" #include "mesh/Channels.h"
#include "mesh/generated/deviceonly.pb.h"
#include "modules/TextMessageModule.h" #include "modules/TextMessageModule.h"
#include "sleep.h" #include "sleep.h"
#include "target_specific.h" #include "target_specific.h"
@@ -44,6 +46,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
using namespace meshtastic; /** @todo remove */ using namespace meshtastic; /** @todo remove */
extern bool loadProto(const char *filename, size_t protoSize, size_t objSize, const pb_msgdesc_t *fields, void *dest_struct);
namespace graphics namespace graphics
{ {
@@ -77,6 +81,10 @@ static char ourId[5];
// GeoCoord object for the screen // GeoCoord object for the screen
GeoCoord geoCoord; GeoCoord geoCoord;
// OEM Config File
static const char *oemConfigFile = "/prefs/oem.proto";
OEMStore oemStore;
#ifdef SHOW_REDRAWS #ifdef SHOW_REDRAWS
static bool heartbeat = false; static bool heartbeat = false;
#endif #endif
@@ -86,7 +94,7 @@ static uint16_t displayWidth, displayHeight;
#define SCREEN_WIDTH displayWidth #define SCREEN_WIDTH displayWidth
#define SCREEN_HEIGHT displayHeight #define SCREEN_HEIGHT displayHeight
#ifdef HAS_EINK #if defined(HAS_EINK) || defined(ILI9341_DRIVER)
// The screen is bigger so use bigger fonts // The screen is bigger so use bigger fonts
#define FONT_SMALL ArialMT_Plain_16 #define FONT_SMALL ArialMT_Plain_16
#define FONT_MEDIUM ArialMT_Plain_24 #define FONT_MEDIUM ArialMT_Plain_24
@@ -148,6 +156,55 @@ static void drawBootScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int1
drawIconScreen(region, display, state, x, y); drawIconScreen(region, display, state, x, y);
} }
static void drawOEMIconScreen(const char *upperMsg, OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
// draw an xbm image.
// Please note that everything that should be transitioned
// needs to be drawn relative to x and y
// draw centered icon left to right and centered above the one line of app text
display->drawXbm(x + (SCREEN_WIDTH - oemStore.oem_icon_width) / 2,
y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - oemStore.oem_icon_height) / 2 + 2, oemStore.oem_icon_width,
oemStore.oem_icon_height, (const uint8_t *)oemStore.oem_icon_bits.bytes);
switch (oemStore.oem_font) {
case 0:
display->setFont(FONT_SMALL);
break;
case 2:
display->setFont(FONT_LARGE);
break;
default:
display->setFont(FONT_MEDIUM);
break;
}
display->setTextAlignment(TEXT_ALIGN_LEFT);
const char *title = oemStore.oem_text;
display->drawString(x + getStringCenteredX(title), y + SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM, title);
display->setFont(FONT_SMALL);
// Draw region in upper left
if (upperMsg)
display->drawString(x + 0, y + 0, upperMsg);
// Draw version in upper right
char buf[16];
snprintf(buf, sizeof(buf), "%s",
xstr(APP_VERSION_SHORT)); // Note: we don't bother printing region or now, it makes the string too long
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(buf), y + 0, buf);
screen->forceDisplay();
// FIXME - draw serial # somewhere?
}
static void drawOEMBootScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
// Draw region in upper left
const char *region = myRegion ? myRegion->name : NULL;
drawOEMIconScreen(region, display, state, x, y);
}
// Used on boot when a certificate is being created // Used on boot when a certificate is being created
static void drawSSLScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) static void drawSSLScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{ {
@@ -172,22 +229,34 @@ static void drawSSLScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16
static void drawWelcomeScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) static void drawWelcomeScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{ {
display->setFont(FONT_SMALL); if ((millis() / 10000) % 2) {
display->setFont(FONT_SMALL);
display->setTextAlignment(TEXT_ALIGN_CENTER); display->setTextAlignment(TEXT_ALIGN_CENTER);
display->drawString(64 + x, y, "Meshtastic :)"); display->drawString(64 + x, y, "//\\ E S H T /\\ S T / C");
display->setTextAlignment(TEXT_ALIGN_LEFT); display->setTextAlignment(TEXT_ALIGN_LEFT);
display->drawString(x, y + FONT_HEIGHT_SMALL * 2 - 3, "Set the region using the"); display->drawString(x, y + FONT_HEIGHT_SMALL * 2 - 3, "Set the region using the");
display->drawString(x, y + FONT_HEIGHT_SMALL * 3 - 3, "Meshtastic Android, iOS,"); display->drawString(x, y + FONT_HEIGHT_SMALL * 3 - 3, "Meshtastic Android, iOS,");
display->drawString(x, y + FONT_HEIGHT_SMALL * 4 - 3, "Flasher or CLI client."); display->drawString(x, y + FONT_HEIGHT_SMALL * 4 - 3, "Flasher or CLI client.");
} else {
display->setFont(FONT_SMALL);
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->drawString(64 + x, y, "//\\ E S H T /\\ S T / C");
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->drawString(x, y + FONT_HEIGHT_SMALL * 2 - 3, "Visit meshtastic.org");
display->drawString(x, y + FONT_HEIGHT_SMALL * 3 - 3, "for more information.");
display->drawString(x, y + FONT_HEIGHT_SMALL * 4 - 3, "");
}
#ifndef NO_ESP32 #ifndef NO_ESP32
yield(); yield();
esp_task_wdt_reset(); esp_task_wdt_reset();
#endif #endif
} }
#ifdef HAS_EINK #ifdef HAS_EINK
@@ -284,8 +353,8 @@ static void drawCriticalFaultFrame(OLEDDisplay *display, OLEDDisplayUiState *sta
// Ignore messages orginating from phone (from the current node 0x0) unless range test or store and forward module are enabled // Ignore messages orginating from phone (from the current node 0x0) unless range test or store and forward module are enabled
static bool shouldDrawMessage(const MeshPacket *packet) static bool shouldDrawMessage(const MeshPacket *packet)
{ {
return packet->from != 0 && !radioConfig.preferences.range_test_module_enabled && return packet->from != 0 && !moduleConfig.range_test.enabled &&
!radioConfig.preferences.store_forward_module_enabled; !moduleConfig.store_forward.enabled;
} }
/// Draw the last text message we received /// Draw the last text message we received
@@ -399,7 +468,7 @@ static void drawNodes(OLEDDisplay *display, int16_t x, int16_t y, NodeStatus *no
// Draw GPS status summary // Draw GPS status summary
static void drawGPS(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus *gps) static void drawGPS(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus *gps)
{ {
if (radioConfig.preferences.fixed_position) { if (config.position.fixed_position) {
// GPS coordinates are currently fixed // GPS coordinates are currently fixed
display->drawString(x - 1, y - 2, "Fixed GPS"); display->drawString(x - 1, y - 2, "Fixed GPS");
return; return;
@@ -438,10 +507,10 @@ static void drawGPS(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus
static void drawGPSAltitude(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus *gps) static void drawGPSAltitude(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus *gps)
{ {
String displayLine = ""; String displayLine = "";
if (!gps->getIsConnected() && !radioConfig.preferences.fixed_position) { if (!gps->getIsConnected() && !config.position.fixed_position) {
// displayLine = "No GPS Module"; // displayLine = "No GPS Module";
// display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(displayLine))) / 2, y, displayLine); // display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(displayLine))) / 2, y, displayLine);
} else if (!gps->getHasLock() && !radioConfig.preferences.fixed_position) { } else if (!gps->getHasLock() && !config.position.fixed_position) {
// displayLine = "No GPS Lock"; // displayLine = "No GPS Lock";
// display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(displayLine))) / 2, y, displayLine); // display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(displayLine))) / 2, y, displayLine);
} else { } else {
@@ -454,32 +523,32 @@ static void drawGPSAltitude(OLEDDisplay *display, int16_t x, int16_t y, const GP
// Draw GPS status coordinates // Draw GPS status coordinates
static void drawGPScoordinates(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus *gps) static void drawGPScoordinates(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus *gps)
{ {
auto gpsFormat = radioConfig.preferences.gps_format; auto gpsFormat = config.display.gps_format;
String displayLine = ""; String displayLine = "";
if (!gps->getIsConnected() && !radioConfig.preferences.fixed_position) { if (!gps->getIsConnected() && !config.position.fixed_position) {
displayLine = "No GPS Module"; displayLine = "No GPS Module";
display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(displayLine))) / 2, y, displayLine); display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(displayLine))) / 2, y, displayLine);
} else if (!gps->getHasLock() && !radioConfig.preferences.fixed_position) { } else if (!gps->getHasLock() && !config.position.fixed_position) {
displayLine = "No GPS Lock"; displayLine = "No GPS Lock";
display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(displayLine))) / 2, y, displayLine); display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(displayLine))) / 2, y, displayLine);
} else { } else {
if (gpsFormat != GpsCoordinateFormat_GpsFormatDMS) { if (gpsFormat != Config_DisplayConfig_GpsCoordinateFormat_GpsFormatDMS) {
char coordinateLine[22]; char coordinateLine[22];
geoCoord.updateCoords(int32_t(gps->getLatitude()), int32_t(gps->getLongitude()), int32_t(gps->getAltitude())); geoCoord.updateCoords(int32_t(gps->getLatitude()), int32_t(gps->getLongitude()), int32_t(gps->getAltitude()));
if (gpsFormat == GpsCoordinateFormat_GpsFormatDec) { // Decimal Degrees if (gpsFormat == Config_DisplayConfig_GpsCoordinateFormat_GpsFormatDec) { // Decimal Degrees
sprintf(coordinateLine, "%f %f", geoCoord.getLatitude() * 1e-7, geoCoord.getLongitude() * 1e-7); sprintf(coordinateLine, "%f %f", geoCoord.getLatitude() * 1e-7, geoCoord.getLongitude() * 1e-7);
} else if (gpsFormat == GpsCoordinateFormat_GpsFormatUTM) { // Universal Transverse Mercator } else if (gpsFormat == Config_DisplayConfig_GpsCoordinateFormat_GpsFormatUTM) { // Universal Transverse Mercator
sprintf(coordinateLine, "%2i%1c %06u %07u", geoCoord.getUTMZone(), geoCoord.getUTMBand(), sprintf(coordinateLine, "%2i%1c %06u %07u", geoCoord.getUTMZone(), geoCoord.getUTMBand(),
geoCoord.getUTMEasting(), geoCoord.getUTMNorthing()); geoCoord.getUTMEasting(), geoCoord.getUTMNorthing());
} else if (gpsFormat == GpsCoordinateFormat_GpsFormatMGRS) { // Military Grid Reference System } else if (gpsFormat == Config_DisplayConfig_GpsCoordinateFormat_GpsFormatMGRS) { // Military Grid Reference System
sprintf(coordinateLine, "%2i%1c %1c%1c %05u %05u", geoCoord.getMGRSZone(), geoCoord.getMGRSBand(), sprintf(coordinateLine, "%2i%1c %1c%1c %05u %05u", geoCoord.getMGRSZone(), geoCoord.getMGRSBand(),
geoCoord.getMGRSEast100k(), geoCoord.getMGRSNorth100k(), geoCoord.getMGRSEasting(), geoCoord.getMGRSEast100k(), geoCoord.getMGRSNorth100k(), geoCoord.getMGRSEasting(),
geoCoord.getMGRSNorthing()); geoCoord.getMGRSNorthing());
} else if (gpsFormat == GpsCoordinateFormat_GpsFormatOLC) { // Open Location Code } else if (gpsFormat == Config_DisplayConfig_GpsCoordinateFormat_GpsFormatOLC) { // Open Location Code
geoCoord.getOLCCode(coordinateLine); geoCoord.getOLCCode(coordinateLine);
} else if (gpsFormat == GpsCoordinateFormat_GpsFormatOSGR) { // Ordnance Survey Grid Reference } else if (gpsFormat == Config_DisplayConfig_GpsCoordinateFormat_GpsFormatOSGR) { // Ordnance Survey Grid Reference
if (geoCoord.getOSGRE100k() == 'I' || geoCoord.getOSGRN100k() == 'I') // OSGR is only valid around the UK region if (geoCoord.getOSGRE100k() == 'I' || geoCoord.getOSGRN100k() == 'I') // OSGR is only valid around the UK region
sprintf(coordinateLine, "%s", "Out of Boundary"); sprintf(coordinateLine, "%s", "Out of Boundary");
else else
@@ -488,7 +557,7 @@ static void drawGPScoordinates(OLEDDisplay *display, int16_t x, int16_t y, const
} }
// If fixed position, display text "Fixed GPS" alternating with the coordinates. // If fixed position, display text "Fixed GPS" alternating with the coordinates.
if (radioConfig.preferences.fixed_position) { if (config.position.fixed_position) {
if ((millis() / 10000) % 2) { if ((millis() / 10000) % 2) {
display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(coordinateLine))) / 2, y, coordinateLine); display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(coordinateLine))) / 2, y, coordinateLine);
} else { } else {
@@ -748,12 +817,26 @@ void _screen_header()
} }
#endif #endif
// #ifdef RAK4630
// Screen::Screen(uint8_t address, int sda, int scl) : OSThread("Screen"), cmdQueue(32), dispdev(address, sda, scl),
// dispdev_oled(address, sda, scl), ui(&dispdev)
// {
// address_found = address;
// cmdQueue.setReader(this);
// if (screen_found) {
// (void)dispdev;
// AutoOLEDWire dispdev = dispdev_oled;
// (void)ui;
// OLEDDisplayUi ui(&dispdev);
// }
// }
// #else
Screen::Screen(uint8_t address, int sda, int scl) : OSThread("Screen"), cmdQueue(32), dispdev(address, sda, scl), ui(&dispdev) Screen::Screen(uint8_t address, int sda, int scl) : OSThread("Screen"), cmdQueue(32), dispdev(address, sda, scl), ui(&dispdev)
{ {
address_found = address; address_found = address;
cmdQueue.setReader(this); cmdQueue.setReader(this);
} }
// #endif
/** /**
* Prepare the display for the unit going to the lowest power mode possible. Most screens will just * Prepare the display for the unit going to the lowest power mode possible. Most screens will just
* poweroff, but eink screens will show a "I'm sleeping" graphic, possibly with a QR code * poweroff, but eink screens will show a "I'm sleeping" graphic, possibly with a QR code
@@ -801,8 +884,8 @@ void Screen::setup()
dispdev.setDetected(screen_model); dispdev.setDetected(screen_model);
#endif #endif
// I think this is not needed - redundant with ui.init // Load OEM config from Proto file if existent
// dispdev.resetOrientation(); loadProto(oemConfigFile, OEMStore_size, sizeof(oemConfigFile), OEMStore_fields, &oemStore);
// Initialising the UI will init the display too. // Initialising the UI will init the display too.
ui.init(); ui.init();
@@ -855,6 +938,7 @@ void Screen::setup()
// twice initially. // twice initially.
ui.update(); ui.update();
ui.update(); ui.update();
serialSinceMsec = millis();
// Subscribe to status updates // Subscribe to status updates
powerStatusObserver.observe(&powerStatus->onNewStatus); powerStatusObserver.observe(&powerStatus->onNewStatus);
@@ -885,7 +969,7 @@ int32_t Screen::runOnce()
return RUN_SAME; return RUN_SAME;
} }
// Show boot screen for first 3 seconds, then switch to normal operation. // Show boot screen for first 5 seconds, then switch to normal operation.
// serialSinceMsec adjusts for additional serial wait time during nRF52 bootup // serialSinceMsec adjusts for additional serial wait time during nRF52 bootup
static bool showingBootScreen = true; static bool showingBootScreen = true;
if (showingBootScreen && (millis() > (5000 + serialSinceMsec))) { if (showingBootScreen && (millis() > (5000 + serialSinceMsec))) {
@@ -894,9 +978,26 @@ int32_t Screen::runOnce()
showingBootScreen = false; showingBootScreen = false;
} }
if (radioConfig.preferences.region == RegionCode_Unset) { // If we have an OEM Boot screen, toggle after 2,5 seconds
if (strlen(oemStore.oem_text) > 0) {
static bool showingOEMBootScreen = true;
if (showingOEMBootScreen && (millis() > (2500 + serialSinceMsec))) {
DEBUG_MSG("Switch to OEM screen...\n");
// Change frames.
static FrameCallback bootOEMFrames[] = {drawOEMBootScreen};
static const int bootOEMFrameCount = sizeof(bootOEMFrames) / sizeof(bootOEMFrames[0]);
ui.setFrames(bootOEMFrames, bootOEMFrameCount);
ui.update();
ui.update();
showingOEMBootScreen = false;
}
}
#ifndef DISABLE_WELCOME_UNSET
if (showingNormalScreen && config.lora.region == Config_LoRaConfig_RegionCode_Unset) {
setWelcomeFrames(); setWelcomeFrames();
} }
#endif
// Process incoming commands. // Process incoming commands.
for (;;) { for (;;) {
@@ -966,8 +1067,8 @@ int32_t Screen::runOnce()
// standard screen switching is stopped. // standard screen switching is stopped.
if (showingNormalScreen) { if (showingNormalScreen) {
// standard screen loop handling here // standard screen loop handling here
if (radioConfig.preferences.auto_screen_carousel_secs > 0 && if (config.display.auto_screen_carousel_secs > 0 &&
(millis() - lastScreenTransition) > (radioConfig.preferences.auto_screen_carousel_secs * 1000)) { (millis() - lastScreenTransition) > (config.display.auto_screen_carousel_secs * 1000)) {
DEBUG_MSG("LastScreenTransition exceeded %ums transitioning to next frame\n", (millis() - lastScreenTransition)); DEBUG_MSG("LastScreenTransition exceeded %ums transitioning to next frame\n", (millis() - lastScreenTransition));
handleOnPress(); handleOnPress();
} }
@@ -1242,8 +1343,8 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
void DebugInfo::drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) void DebugInfo::drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{ {
#ifdef HAS_WIFI #ifdef HAS_WIFI
const char *wifiName = radioConfig.preferences.wifi_ssid; const char *wifiName = config.wifi.ssid;
const char *wifiPsw = radioConfig.preferences.wifi_password; const char *wifiPsw = config.wifi.psk;
displayedNodeNum = 0; // Not currently showing a node pane displayedNodeNum = 0; // Not currently showing a node pane
@@ -1254,7 +1355,7 @@ void DebugInfo::drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, i
if (isSoftAPForced()) { if (isSoftAPForced()) {
display->drawString(x, y, String("WiFi: Software AP (Admin)")); display->drawString(x, y, String("WiFi: Software AP (Admin)"));
} else if (radioConfig.preferences.wifi_ap_mode) { } else if (config.wifi.ap_mode) {
display->drawString(x, y, String("WiFi: Software AP")); display->drawString(x, y, String("WiFi: Software AP"));
} else if (WiFi.status() != WL_CONNECTED) { } else if (WiFi.status() != WL_CONNECTED) {
display->drawString(x, y, String("WiFi: Not Connected")); display->drawString(x, y, String("WiFi: Not Connected"));
@@ -1277,8 +1378,8 @@ void DebugInfo::drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, i
- WL_NO_SHIELD: assigned when no WiFi shield is present; - WL_NO_SHIELD: assigned when no WiFi shield is present;
*/ */
if (WiFi.status() == WL_CONNECTED || isSoftAPForced() || radioConfig.preferences.wifi_ap_mode) { if (WiFi.status() == WL_CONNECTED || isSoftAPForced() || config.wifi.ap_mode) {
if (radioConfig.preferences.wifi_ap_mode || isSoftAPForced()) { if (config.wifi.ap_mode || isSoftAPForced()) {
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "IP: " + String(WiFi.softAPIP().toString().c_str())); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "IP: " + String(WiFi.softAPIP().toString().c_str()));
// Number of connections to the AP. Default max for the esp32 is 4 // Number of connections to the AP. Default max for the esp32 is 4
@@ -1370,7 +1471,7 @@ void DebugInfo::drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, i
} }
} else { } else {
if (radioConfig.preferences.wifi_ap_mode) { if (config.wifi.ap_mode) {
if ((millis() / 10000) % 2) { if ((millis() / 10000) % 2) {
display->drawString(x, y + FONT_HEIGHT_SMALL * 2, "SSID: " + String(wifiName)); display->drawString(x, y + FONT_HEIGHT_SMALL * 2, "SSID: " + String(wifiName));
} else { } else {
@@ -1417,22 +1518,31 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
auto mode = ""; auto mode = "";
if (channels.getPrimary().modem_config == 0) { switch (config.lora.modem_preset) {
mode = "VLongSlow"; case Config_LoRaConfig_ModemPreset_ShortSlow:
} else if (channels.getPrimary().modem_config == 1) {
mode = "LongSlow";
} else if (channels.getPrimary().modem_config == 2) {
mode = "LongFast";
} else if (channels.getPrimary().modem_config == 3) {
mode = "MidSlow";
} else if (channels.getPrimary().modem_config == 4) {
mode = "MidFast";
} else if (channels.getPrimary().modem_config == 5) {
mode = "ShortSlow"; mode = "ShortSlow";
} else if (channels.getPrimary().modem_config == 6) { break;
case Config_LoRaConfig_ModemPreset_ShortFast:
mode = "ShortFast"; mode = "ShortFast";
} else { break;
case Config_LoRaConfig_ModemPreset_MidSlow:
mode = "MediumSlow";
break;
case Config_LoRaConfig_ModemPreset_MidFast:
mode = "MediumFast";
break;
case Config_LoRaConfig_ModemPreset_LongFast:
mode = "LongFast";
break;
case Config_LoRaConfig_ModemPreset_LongSlow:
mode = "LongSlow";
break;
case Config_LoRaConfig_ModemPreset_VLongSlow:
mode = "VLongSlow";
break;
default:
mode = "Custom"; mode = "Custom";
break;
} }
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(mode), y, mode); display->drawString(x + SCREEN_WIDTH - display->getStringWidth(mode), y, mode);
@@ -1459,7 +1569,7 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
else else
uptime += String(seconds) + "s "; uptime += String(seconds) + "s ";
uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityFromNet); uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice);
if (rtc_sec > 0) { if (rtc_sec > 0) {
long hms = rtc_sec % SEC_PER_DAY; long hms = rtc_sec % SEC_PER_DAY;
// hms += tz.tz_dsttime * SEC_PER_HOUR; // hms += tz.tz_dsttime * SEC_PER_HOUR;
@@ -1485,7 +1595,8 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(chUtil), y + FONT_HEIGHT_SMALL * 1, chUtil); display->drawString(x + SCREEN_WIDTH - display->getStringWidth(chUtil), y + FONT_HEIGHT_SMALL * 1, chUtil);
// Line 3 // Line 3
if (radioConfig.preferences.gps_format != GpsCoordinateFormat_GpsFormatDMS) // if DMS then don't draw altitude if (config.display.gps_format !=
Config_DisplayConfig_GpsCoordinateFormat_GpsFormatDMS) // if DMS then don't draw altitude
drawGPSAltitude(display, x, y + FONT_HEIGHT_SMALL * 2, gpsStatus); drawGPSAltitude(display, x, y + FONT_HEIGHT_SMALL * 2, gpsStatus);
// Line 4 // Line 4
@@ -1554,3 +1665,4 @@ int Screen::handleUIFrameEvent(const UIFrameEvent *event)
} }
} // namespace graphics } // namespace graphics
#endif // NO_SCREEN

View File

@@ -1,6 +1,7 @@
#pragma once #pragma once
#ifdef NO_SCREEN #ifdef NO_SCREEN
#include "power.h"
namespace graphics namespace graphics
{ {
// Noop class for boards without screen. // Noop class for boards without screen.
@@ -15,6 +16,8 @@ class Screen
void adjustBrightness(){} void adjustBrightness(){}
void doDeepSleep() {} void doDeepSleep() {}
void forceDisplay() {} void forceDisplay() {}
void startBluetoothPinScreen(uint32_t pin) {}
void stopBluetoothPinScreen() {}
}; };
} }
@@ -27,6 +30,10 @@ class Screen
#ifdef USE_ST7567 #ifdef USE_ST7567
#include <ST7567Wire.h> #include <ST7567Wire.h>
#elif defined(USE_SH1106)
#include <SH1106Wire.h>
#elif defined(USE_SSD1306)
#include <SSD1306Wire.h>
#else #else
// the SH1106/SSD1306 variant is auto-detected // the SH1106/SSD1306 variant is auto-detected
#include <AutoOLEDWire.h> #include <AutoOLEDWire.h>
@@ -297,9 +304,16 @@ class Screen : public concurrency::OSThread
/// Holds state for debug information /// Holds state for debug information
DebugInfo debugInfo; DebugInfo debugInfo;
/// Display device /// Display device
/** FIXME cleanup display abstraction */
#ifdef ST7735_CS // #ifdef RAK4630
// EInkDisplay dispdev;
// AutoOLEDWire dispdev_oled;
#ifdef USE_SH1106
SH1106Wire dispdev;
#elif defined(USE_SSD1306)
SSD1306Wire dispdev;
#elif defined(ST7735_CS) || defined(ILI9341_DRIVER)
TFTDisplay dispdev; TFTDisplay dispdev;
#elif defined(HAS_EINK) #elif defined(HAS_EINK)
EInkDisplay dispdev; EInkDisplay dispdev;

View File

@@ -1,6 +1,6 @@
#include "configuration.h" #include "configuration.h"
#ifdef ST7735_CS #if defined(ST7735_CS) || defined(ILI9341_DRIVER)
#include "SPILock.h" #include "SPILock.h"
#include "TFTDisplay.h" #include "TFTDisplay.h"
#include <SPI.h> #include <SPI.h>
@@ -10,7 +10,11 @@ static TFT_eSPI tft = TFT_eSPI(); // Invoke library, pins defined in User_Setup.
TFTDisplay::TFTDisplay(uint8_t address, int sda, int scl) TFTDisplay::TFTDisplay(uint8_t address, int sda, int scl)
{ {
setGeometry(GEOMETRY_RAWMODE, 160, 80); #ifdef SCREEN_ROTATE
setGeometry(GEOMETRY_RAWMODE, TFT_HEIGHT, TFT_WIDTH);
#else
setGeometry(GEOMETRY_RAWMODE, TFT_WIDTH, TFT_HEIGHT);
#endif
} }
// Write the buffer to the display memory // Write the buffer to the display memory
@@ -20,12 +24,10 @@ void TFTDisplay::display(void)
// FIXME - only draw bits have changed (use backbuf similar to the other displays) // FIXME - only draw bits have changed (use backbuf similar to the other displays)
// tft.drawBitmap(0, 0, buffer, 128, 64, TFT_YELLOW, TFT_BLACK); // tft.drawBitmap(0, 0, buffer, 128, 64, TFT_YELLOW, TFT_BLACK);
for (uint8_t y = 0; y < displayHeight; y++) { for (uint16_t y = 0; y < displayHeight; y++) {
for (uint8_t x = 0; x < displayWidth; x++) { for (uint16_t x = 0; x < displayWidth; x++) {
// get src pixel in the page based ordering the OLED lib uses FIXME, super inefficent // get src pixel in the page based ordering the OLED lib uses FIXME, super inefficent
auto b = buffer[x + (y / 8) * displayWidth]; auto isset = buffer[x + (y / 8) * displayWidth] & (1 << (y & 7));
auto isset = b & (1 << (y & 7));
tft.drawPixel(x, y, isset ? TFT_WHITE : TFT_BLACK); tft.drawPixel(x, y, isset ? TFT_WHITE : TFT_BLACK);
} }
} }
@@ -38,21 +40,34 @@ void TFTDisplay::sendCommand(uint8_t com)
// Drop all commands to device (we just update the buffer) // Drop all commands to device (we just update the buffer)
} }
void TFTDisplay::setDetected(uint8_t detected)
{
(void)detected;
}
// Connect to the display // Connect to the display
bool TFTDisplay::connect() bool TFTDisplay::connect()
{ {
concurrency::LockGuard g(spiLock);
DEBUG_MSG("Doing TFT init\n"); DEBUG_MSG("Doing TFT init\n");
#ifdef TFT_BL
digitalWrite(TFT_BL, HIGH);
pinMode(TFT_BL, OUTPUT);
#endif
#ifdef ST7735_BACKLIGHT_EN #ifdef ST7735_BACKLIGHT_EN
digitalWrite(ST7735_BACKLIGHT_EN, HIGH); digitalWrite(ST7735_BACKLIGHT_EN, HIGH);
pinMode(ST7735_BACKLIGHT_EN, OUTPUT); pinMode(ST7735_BACKLIGHT_EN, OUTPUT);
#endif #endif
tft.init(); tft.init();
#ifdef M5STACK
tft.setRotation(1); // M5Stack has the TFT in landscape
#else
tft.setRotation(3); // Orient horizontal and wide underneath the silkscreen name label tft.setRotation(3); // Orient horizontal and wide underneath the silkscreen name label
#endif
tft.fillScreen(TFT_BLACK); tft.fillScreen(TFT_BLACK);
// tft.drawRect(0, 0, 40, 10, TFT_PURPLE); // wide rectangle in upper left // tft.drawRect(0, 0, 40, 10, TFT_PURPLE); // wide rectangle in upper left
return true; return true;
} }

View File

@@ -22,6 +22,12 @@ class TFTDisplay : public OLEDDisplay
// Write the buffer to the display memory // Write the buffer to the display memory
virtual void display(void) override; virtual void display(void) override;
/**
* shim to make the abstraction happy
*
*/
void setDetected(uint8_t detected);
protected: protected:
// the header size of the buffer used, e.g. for the SPI command header // the header size of the buffer used, e.g. for the SPI command header

View File

@@ -1,17 +1,14 @@
#include "configuration.h"
#include "RotaryEncoderInterruptBase.h" #include "RotaryEncoderInterruptBase.h"
#include "configuration.h"
RotaryEncoderInterruptBase::RotaryEncoderInterruptBase( RotaryEncoderInterruptBase::RotaryEncoderInterruptBase(const char *name) : concurrency::OSThread(name)
const char *name) :
concurrency::OSThread(name)
{ {
this->_originName = name; this->_originName = name;
} }
void RotaryEncoderInterruptBase::init( void RotaryEncoderInterruptBase::init(
uint8_t pinA, uint8_t pinB, uint8_t pinPress, uint8_t pinA, uint8_t pinB, uint8_t pinPress, char eventCw, char eventCcw, char eventPressed,
char eventCw, char eventCcw, char eventPressed, // std::function<void(void)> onIntA, std::function<void(void)> onIntB, std::function<void(void)> onIntPress) :
// std::function<void(void)> onIntA, std::function<void(void)> onIntB, std::function<void(void)> onIntPress) :
void (*onIntA)(), void (*onIntB)(), void (*onIntPress)()) void (*onIntA)(), void (*onIntB)(), void (*onIntPress)())
{ {
this->_pinA = pinA; this->_pinA = pinA;
@@ -24,42 +21,34 @@ void RotaryEncoderInterruptBase::init(
pinMode(this->_pinA, INPUT_PULLUP); pinMode(this->_pinA, INPUT_PULLUP);
pinMode(this->_pinB, INPUT_PULLUP); pinMode(this->_pinB, INPUT_PULLUP);
// attachInterrupt(pinPress, onIntPress, RISING); // attachInterrupt(pinPress, onIntPress, RISING);
attachInterrupt(pinPress, onIntPress, RISING); attachInterrupt(pinPress, onIntPress, RISING);
attachInterrupt(this->_pinA, onIntA, CHANGE); attachInterrupt(this->_pinA, onIntA, CHANGE);
attachInterrupt(this->_pinB, onIntB, CHANGE); attachInterrupt(this->_pinB, onIntB, CHANGE);
this->rotaryLevelA = digitalRead(this->_pinA); this->rotaryLevelA = digitalRead(this->_pinA);
this->rotaryLevelB = digitalRead(this->_pinB); this->rotaryLevelB = digitalRead(this->_pinB);
DEBUG_MSG("Rotary initialized (%d, %d, %d)\n", DEBUG_MSG("Rotary initialized (%d, %d, %d)\n", this->_pinA, this->_pinB, pinPress);
this->_pinA, this->_pinB, pinPress);
} }
int32_t RotaryEncoderInterruptBase::runOnce() int32_t RotaryEncoderInterruptBase::runOnce()
{ {
InputEvent e; InputEvent e;
e.inputEvent = InputEventChar_KEY_NONE; e.inputEvent = ModuleConfig_CannedMessageConfig_InputEventChar_KEY_NONE;
e.source = this->_originName; e.source = this->_originName;
if (this->action == ROTARY_ACTION_PRESSED) if (this->action == ROTARY_ACTION_PRESSED) {
{
DEBUG_MSG("Rotary event Press\n"); DEBUG_MSG("Rotary event Press\n");
e.inputEvent = this->_eventPressed; e.inputEvent = this->_eventPressed;
} } else if (this->action == ROTARY_ACTION_CW) {
else if (this->action == ROTARY_ACTION_CW)
{
DEBUG_MSG("Rotary event CW\n"); DEBUG_MSG("Rotary event CW\n");
e.inputEvent = this->_eventCw; e.inputEvent = this->_eventCw;
} } else if (this->action == ROTARY_ACTION_CCW) {
else if (this->action == ROTARY_ACTION_CCW)
{
DEBUG_MSG("Rotary event CCW\n"); DEBUG_MSG("Rotary event CCW\n");
e.inputEvent = this->_eventCcw; e.inputEvent = this->_eventCcw;
} }
if (e.inputEvent != InputEventChar_KEY_NONE) if (e.inputEvent != ModuleConfig_CannedMessageConfig_InputEventChar_KEY_NONE) {
{
this->notifyObservers(&e); this->notifyObservers(&e);
} }
@@ -68,7 +57,6 @@ int32_t RotaryEncoderInterruptBase::runOnce()
return 30000; // TODO: technically this can be MAX_INT return 30000; // TODO: technically this can be MAX_INT
} }
void RotaryEncoderInterruptBase::intPressHandler() void RotaryEncoderInterruptBase::intPressHandler()
{ {
this->action = ROTARY_ACTION_PRESSED; this->action = ROTARY_ACTION_PRESSED;
@@ -79,66 +67,47 @@ void RotaryEncoderInterruptBase::intAHandler()
{ {
// CW rotation (at least on most common rotary encoders) // CW rotation (at least on most common rotary encoders)
int currentLevelA = digitalRead(this->_pinA); int currentLevelA = digitalRead(this->_pinA);
if (this->rotaryLevelA == currentLevelA) if (this->rotaryLevelA == currentLevelA) {
{
return; return;
} }
this->rotaryLevelA = currentLevelA; this->rotaryLevelA = currentLevelA;
this->rotaryStateCCW = intHandler( this->rotaryStateCCW = intHandler(currentLevelA == HIGH, this->rotaryLevelB, ROTARY_ACTION_CCW, this->rotaryStateCCW);
currentLevelA == HIGH,
this->rotaryLevelB,
ROTARY_ACTION_CCW,
this->rotaryStateCCW);
} }
void RotaryEncoderInterruptBase::intBHandler() void RotaryEncoderInterruptBase::intBHandler()
{ {
// CW rotation (at least on most common rotary encoders) // CW rotation (at least on most common rotary encoders)
int currentLevelB = digitalRead(this->_pinB); int currentLevelB = digitalRead(this->_pinB);
if (this->rotaryLevelB == currentLevelB) if (this->rotaryLevelB == currentLevelB) {
{
return; return;
} }
this->rotaryLevelB = currentLevelB; this->rotaryLevelB = currentLevelB;
this->rotaryStateCW = intHandler( this->rotaryStateCW = intHandler(currentLevelB == HIGH, this->rotaryLevelA, ROTARY_ACTION_CW, this->rotaryStateCW);
currentLevelB == HIGH,
this->rotaryLevelA,
ROTARY_ACTION_CW,
this->rotaryStateCW);
} }
/** /**
* @brief Rotary action implementation. * @brief Rotary action implementation.
* We assume, the following pin setup: * We assume, the following pin setup:
* A --|| * A --||
* GND --||]======== * GND --||]========
* B --|| * B --||
* *
* @return The new state for rotary pin. * @return The new state for rotary pin.
*/ */
RotaryEncoderInterruptBaseStateType RotaryEncoderInterruptBase::intHandler( RotaryEncoderInterruptBaseStateType RotaryEncoderInterruptBase::intHandler(bool actualPinRaising, int otherPinLevel,
bool actualPinRaising, RotaryEncoderInterruptBaseActionType action,
int otherPinLevel, RotaryEncoderInterruptBaseStateType state)
RotaryEncoderInterruptBaseActionType action,
RotaryEncoderInterruptBaseStateType state)
{ {
RotaryEncoderInterruptBaseStateType newState = RotaryEncoderInterruptBaseStateType newState = state;
state; if (actualPinRaising && (otherPinLevel == LOW)) {
if (actualPinRaising && (otherPinLevel == LOW)) if (state == ROTARY_EVENT_CLEARED) {
{
if (state == ROTARY_EVENT_CLEARED)
{
newState = ROTARY_EVENT_OCCURRED; newState = ROTARY_EVENT_OCCURRED;
if ((this->action != ROTARY_ACTION_PRESSED) if ((this->action != ROTARY_ACTION_PRESSED) && (this->action != action)) {
&& (this->action != action))
{
this->action = action; this->action = action;
DEBUG_MSG("Rotary action\n"); DEBUG_MSG("Rotary action\n");
} }
} }
} } else if (!actualPinRaising && (otherPinLevel == HIGH)) {
else if (!actualPinRaising && (otherPinLevel == HIGH))
{
// Logic to prevent bouncing. // Logic to prevent bouncing.
newState = ROTARY_EVENT_CLEARED; newState = ROTARY_EVENT_CLEARED;
} }

View File

@@ -1,45 +1,28 @@
#pragma once #pragma once
#include "SinglePortModule.h" // TODO: what header file to include?
#include "InputBroker.h" #include "InputBroker.h"
#include "SinglePortModule.h" // TODO: what header file to include?
enum RotaryEncoderInterruptBaseStateType enum RotaryEncoderInterruptBaseStateType { ROTARY_EVENT_OCCURRED, ROTARY_EVENT_CLEARED };
{
ROTARY_EVENT_OCCURRED,
ROTARY_EVENT_CLEARED
};
enum RotaryEncoderInterruptBaseActionType enum RotaryEncoderInterruptBaseActionType { ROTARY_ACTION_NONE, ROTARY_ACTION_PRESSED, ROTARY_ACTION_CW, ROTARY_ACTION_CCW };
{
ROTARY_ACTION_NONE,
ROTARY_ACTION_PRESSED,
ROTARY_ACTION_CW,
ROTARY_ACTION_CCW
};
class RotaryEncoderInterruptBase : class RotaryEncoderInterruptBase : public Observable<const InputEvent *>, private concurrency::OSThread
public Observable<const InputEvent *>,
private concurrency::OSThread
{ {
public: public:
explicit RotaryEncoderInterruptBase( explicit RotaryEncoderInterruptBase(const char *name);
const char *name); void init(uint8_t pinA, uint8_t pinB, uint8_t pinPress, char eventCw, char eventCcw, char eventPressed,
void init( // std::function<void(void)> onIntA, std::function<void(void)> onIntB, std::function<void(void)> onIntPress);
uint8_t pinA, uint8_t pinB, uint8_t pinPress, void (*onIntA)(), void (*onIntB)(), void (*onIntPress)());
char eventCw, char eventCcw, char eventPressed,
// std::function<void(void)> onIntA, std::function<void(void)> onIntB, std::function<void(void)> onIntPress);
void (*onIntA)(), void (*onIntB)(), void (*onIntPress)());
void intPressHandler(); void intPressHandler();
void intAHandler(); void intAHandler();
void intBHandler(); void intBHandler();
protected: protected:
virtual int32_t runOnce() override; virtual int32_t runOnce() override;
RotaryEncoderInterruptBaseStateType intHandler( RotaryEncoderInterruptBaseStateType intHandler(bool actualPinRaising, int otherPinLevel,
bool actualPinRaising, RotaryEncoderInterruptBaseActionType action,
int otherPinLevel, RotaryEncoderInterruptBaseStateType state);
RotaryEncoderInterruptBaseActionType action,
RotaryEncoderInterruptBaseStateType state);
volatile RotaryEncoderInterruptBaseStateType rotaryStateCW = ROTARY_EVENT_CLEARED; volatile RotaryEncoderInterruptBaseStateType rotaryStateCW = ROTARY_EVENT_CLEARED;
volatile RotaryEncoderInterruptBaseStateType rotaryStateCCW = ROTARY_EVENT_CLEARED; volatile RotaryEncoderInterruptBaseStateType rotaryStateCCW = ROTARY_EVENT_CLEARED;
@@ -50,8 +33,8 @@ class RotaryEncoderInterruptBase :
private: private:
uint8_t _pinA = 0; uint8_t _pinA = 0;
uint8_t _pinB = 0; uint8_t _pinB = 0;
char _eventCw = InputEventChar_KEY_NONE; char _eventCw = ModuleConfig_CannedMessageConfig_InputEventChar_KEY_NONE;
char _eventCcw = InputEventChar_KEY_NONE; char _eventCcw = ModuleConfig_CannedMessageConfig_InputEventChar_KEY_NONE;
char _eventPressed = InputEventChar_KEY_NONE; char _eventPressed = ModuleConfig_CannedMessageConfig_InputEventChar_KEY_NONE;
const char *_originName; const char *_originName;
}; };

View File

@@ -3,37 +3,26 @@
RotaryEncoderInterruptImpl1 *rotaryEncoderInterruptImpl1; RotaryEncoderInterruptImpl1 *rotaryEncoderInterruptImpl1;
RotaryEncoderInterruptImpl1::RotaryEncoderInterruptImpl1() : RotaryEncoderInterruptImpl1::RotaryEncoderInterruptImpl1() : RotaryEncoderInterruptBase("rotEnc1") {}
RotaryEncoderInterruptBase(
"rotEnc1")
{
}
void RotaryEncoderInterruptImpl1::init() void RotaryEncoderInterruptImpl1::init()
{ {
if (!radioConfig.preferences.rotary1_enabled) if (!moduleConfig.canned_message.rotary1_enabled) {
{
// Input device is disabled. // Input device is disabled.
return; return;
} }
uint8_t pinA = radioConfig.preferences.inputbroker_pin_a; uint8_t pinA = moduleConfig.canned_message.inputbroker_pin_a;
uint8_t pinB = radioConfig.preferences.inputbroker_pin_b; uint8_t pinB = moduleConfig.canned_message.inputbroker_pin_b;
uint8_t pinPress = radioConfig.preferences.inputbroker_pin_press; uint8_t pinPress = moduleConfig.canned_message.inputbroker_pin_press;
char eventCw = char eventCw = static_cast<char>(moduleConfig.canned_message.inputbroker_event_cw);
static_cast<char>(radioConfig.preferences.inputbroker_event_cw); char eventCcw = static_cast<char>(moduleConfig.canned_message.inputbroker_event_ccw);
char eventCcw = char eventPressed = static_cast<char>(moduleConfig.canned_message.inputbroker_event_press);
static_cast<char>(radioConfig.preferences.inputbroker_event_ccw);
char eventPressed =
static_cast<char>(radioConfig.preferences.inputbroker_event_press);
//radioConfig.preferences.ext_notification_module_output // moduleConfig.canned_message.ext_notification_module_output
RotaryEncoderInterruptBase::init( RotaryEncoderInterruptBase::init(pinA, pinB, pinPress, eventCw, eventCcw, eventPressed,
pinA, pinB, pinPress, RotaryEncoderInterruptImpl1::handleIntA, RotaryEncoderInterruptImpl1::handleIntB,
eventCw, eventCcw, eventPressed, RotaryEncoderInterruptImpl1::handleIntPressed);
RotaryEncoderInterruptImpl1::handleIntA,
RotaryEncoderInterruptImpl1::handleIntB,
RotaryEncoderInterruptImpl1::handleIntPressed);
inputBroker->registerSource(this); inputBroker->registerSource(this);
} }

View File

@@ -1,18 +1,14 @@
#pragma once #pragma once
#include "SinglePortModule.h" // TODO: what header file to include?
#include "InputBroker.h" #include "InputBroker.h"
#include "SinglePortModule.h" // TODO: what header file to include?
class UpDownInterruptBase : class UpDownInterruptBase : public Observable<const InputEvent *>
public Observable<const InputEvent *>
{ {
public: public:
explicit UpDownInterruptBase( explicit UpDownInterruptBase(const char *name);
const char *name); void init(uint8_t pinDown, uint8_t pinUp, uint8_t pinPress, char eventDown, char eventUp, char eventPressed,
void init( void (*onIntDown)(), void (*onIntUp)(), void (*onIntPress)());
uint8_t pinDown, uint8_t pinUp, uint8_t pinPress,
char eventDown, char eventUp, char eventPressed,
void (*onIntDown)(), void (*onIntUp)(), void (*onIntPress)());
void intPressHandler(); void intPressHandler();
void intDownHandler(); void intDownHandler();
void intUpHandler(); void intUpHandler();
@@ -20,8 +16,8 @@ class UpDownInterruptBase :
private: private:
uint8_t _pinDown = 0; uint8_t _pinDown = 0;
uint8_t _pinUp = 0; uint8_t _pinUp = 0;
char _eventDown = InputEventChar_KEY_NONE; char _eventDown = ModuleConfig_CannedMessageConfig_InputEventChar_KEY_NONE;
char _eventUp = InputEventChar_KEY_NONE; char _eventUp = ModuleConfig_CannedMessageConfig_InputEventChar_KEY_NONE;
char _eventPressed = InputEventChar_KEY_NONE; char _eventPressed = ModuleConfig_CannedMessageConfig_InputEventChar_KEY_NONE;
const char *_originName; const char *_originName;
}; };

View File

@@ -3,38 +3,26 @@
UpDownInterruptImpl1 *upDownInterruptImpl1; UpDownInterruptImpl1 *upDownInterruptImpl1;
UpDownInterruptImpl1::UpDownInterruptImpl1() : UpDownInterruptImpl1::UpDownInterruptImpl1() : UpDownInterruptBase("upDown1") {}
UpDownInterruptBase(
"upDown1")
{
}
void UpDownInterruptImpl1::init() void UpDownInterruptImpl1::init()
{ {
if (!radioConfig.preferences.updown1_enabled) if (!moduleConfig.canned_message.updown1_enabled) {
{
// Input device is disabled. // Input device is disabled.
return; return;
} }
uint8_t pinUp = radioConfig.preferences.inputbroker_pin_a; uint8_t pinUp = moduleConfig.canned_message.inputbroker_pin_a;
uint8_t pinDown = radioConfig.preferences.inputbroker_pin_b; uint8_t pinDown = moduleConfig.canned_message.inputbroker_pin_b;
uint8_t pinPress = radioConfig.preferences.inputbroker_pin_press; uint8_t pinPress = moduleConfig.canned_message.inputbroker_pin_press;
char eventDown = char eventDown = static_cast<char>(ModuleConfig_CannedMessageConfig_InputEventChar_KEY_DOWN);
static_cast<char>(InputEventChar_KEY_DOWN); char eventUp = static_cast<char>(ModuleConfig_CannedMessageConfig_InputEventChar_KEY_UP);
char eventUp = char eventPressed = static_cast<char>(ModuleConfig_CannedMessageConfig_InputEventChar_KEY_SELECT);
static_cast<char>(InputEventChar_KEY_UP);
char eventPressed =
static_cast<char>(InputEventChar_KEY_SELECT);
UpDownInterruptBase::init( UpDownInterruptBase::init(pinDown, pinUp, pinPress, eventDown, eventUp, eventPressed, UpDownInterruptImpl1::handleIntDown,
pinDown, pinUp, pinPress, UpDownInterruptImpl1::handleIntUp, UpDownInterruptImpl1::handleIntPressed);
eventDown, eventUp, eventPressed,
UpDownInterruptImpl1::handleIntDown,
UpDownInterruptImpl1::handleIntUp,
UpDownInterruptImpl1::handleIntPressed);
inputBroker->registerSource(this); inputBroker->registerSource(this);
} }

View File

@@ -1,5 +1,5 @@
#include "configuration.h"
#include "kbI2cBase.h" #include "kbI2cBase.h"
#include "configuration.h"
#include <Wire.h> #include <Wire.h>
KbI2cBase::KbI2cBase(const char *name) : concurrency::OSThread(name) KbI2cBase::KbI2cBase(const char *name) : concurrency::OSThread(name)
@@ -10,40 +10,39 @@ KbI2cBase::KbI2cBase(const char *name) : concurrency::OSThread(name)
int32_t KbI2cBase::runOnce() int32_t KbI2cBase::runOnce()
{ {
InputEvent e; InputEvent e;
e.inputEvent = InputEventChar_KEY_NONE; e.inputEvent = ModuleConfig_CannedMessageConfig_InputEventChar_KEY_NONE;
e.source = this->_originName; e.source = this->_originName;
Wire.requestFrom(CARDKB_ADDR, 1); Wire.requestFrom(CARDKB_ADDR, 1);
while(Wire.available()) { while (Wire.available()) {
char c = Wire.read(); char c = Wire.read();
switch(c) { switch (c) {
case 0x1b: // ESC case 0x1b: // ESC
e.inputEvent = InputEventChar_KEY_CANCEL; e.inputEvent = ModuleConfig_CannedMessageConfig_InputEventChar_KEY_CANCEL;
break; break;
case 0x08: // Back case 0x08: // Back
e.inputEvent = InputEventChar_KEY_BACK; e.inputEvent = ModuleConfig_CannedMessageConfig_InputEventChar_KEY_BACK;
break; break;
case 0xb5: // Up case 0xb5: // Up
e.inputEvent = InputEventChar_KEY_UP; e.inputEvent = ModuleConfig_CannedMessageConfig_InputEventChar_KEY_UP;
break; break;
case 0xb6: // Down case 0xb6: // Down
e.inputEvent = InputEventChar_KEY_DOWN; e.inputEvent = ModuleConfig_CannedMessageConfig_InputEventChar_KEY_DOWN;
break; break;
case 0xb4: // Left case 0xb4: // Left
e.inputEvent = InputEventChar_KEY_LEFT; e.inputEvent = ModuleConfig_CannedMessageConfig_InputEventChar_KEY_LEFT;
break; break;
case 0xb7: // Right case 0xb7: // Right
e.inputEvent = InputEventChar_KEY_RIGHT; e.inputEvent = ModuleConfig_CannedMessageConfig_InputEventChar_KEY_RIGHT;
break; break;
case 0x0d: // Enter case 0x0d: // Enter
e.inputEvent = InputEventChar_KEY_SELECT; e.inputEvent = ModuleConfig_CannedMessageConfig_InputEventChar_KEY_SELECT;
break; break;
} }
} }
if (e.inputEvent != InputEventChar_KEY_NONE) if (e.inputEvent != ModuleConfig_CannedMessageConfig_InputEventChar_KEY_NONE) {
{
this->notifyObservers(&e); this->notifyObservers(&e);
} }
return 500; return 500;

View File

@@ -1,4 +1,3 @@
#include "configuration.h"
#include "GPS.h" #include "GPS.h"
#include "MeshRadio.h" #include "MeshRadio.h"
#include "MeshService.h" #include "MeshService.h"
@@ -6,6 +5,7 @@
#include "PowerFSM.h" #include "PowerFSM.h"
#include "airtime.h" #include "airtime.h"
#include "buzz.h" #include "buzz.h"
#include "configuration.h"
#include "error.h" #include "error.h"
#include "power.h" #include "power.h"
// #include "rom/rtc.h" // #include "rom/rtc.h"
@@ -17,27 +17,28 @@
#include "SPILock.h" #include "SPILock.h"
#include "concurrency/OSThread.h" #include "concurrency/OSThread.h"
#include "concurrency/Periodic.h" #include "concurrency/Periodic.h"
#include "debug/axpDebug.h"
#include "debug/einkScan.h"
#include "debug/i2cScan.h"
#include "graphics/Screen.h" #include "graphics/Screen.h"
#include "main.h" #include "main.h"
#include "modules/Modules.h" #include "modules/Modules.h"
#include "sleep.h"
#include "shutdown.h" #include "shutdown.h"
#include "sleep.h"
#include "target_specific.h" #include "target_specific.h"
#include "debug/i2cScan.h"
#include "debug/axpDebug.h"
#include <Wire.h> #include <Wire.h>
// #include <driver/rtc_io.h> // #include <driver/rtc_io.h>
#include "mesh/http/WiFiAPClient.h" #include "mesh/http/WiFiAPClient.h"
#ifndef NO_ESP32 #ifndef NO_ESP32
#include "mesh/http/WebServer.h" #include "mesh/http/WebServer.h"
#ifdef USE_NEW_ESP32_BLUETOOTH #ifdef USE_NEW_ESP32_BLUETOOTH
#include "esp32/ESP32Bluetooth.h" #include "esp32/ESP32Bluetooth.h"
#else #else
#include "nimble/BluetoothUtil.h" #include "nimble/BluetoothUtil.h"
#endif #endif
#endif #endif
@@ -46,10 +47,10 @@
#include "mqtt/MQTT.h" #include "mqtt/MQTT.h"
#endif #endif
#include "LLCC68Interface.h"
#include "RF95Interface.h" #include "RF95Interface.h"
#include "SX1262Interface.h" #include "SX1262Interface.h"
#include "SX1268Interface.h" #include "SX1268Interface.h"
#include "LLCC68Interface.h"
#include "ButtonThread.h" #include "ButtonThread.h"
#include "PowerFSMThread.h" #include "PowerFSMThread.h"
@@ -74,14 +75,24 @@ uint8_t screen_model;
// The I2C address of the cardkb or RAK14004 (if found) // The I2C address of the cardkb or RAK14004 (if found)
uint8_t cardkb_found; uint8_t cardkb_found;
// 0x02 for RAK14004 and 0x00 for cardkb
uint8_t kb_model;
// The I2C address of the Faces Keyboard (if found) // The I2C address of the Faces Keyboard (if found)
uint8_t faceskb_found; uint8_t faceskb_found;
// The I2C address of the RTC Module (if found)
uint8_t rtc_found;
bool eink_found = true;
uint32_t serialSinceMsec; uint32_t serialSinceMsec;
bool axp192_found; bool axp192_found;
// Array map of sensor types (as array index) and i2c address as value we'll find in the i2c scan
uint8_t nodeTelemetrySensorsMap[12] = { 0, 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 Router *router = NULL; // Users of router don't care what sort of subclass implements that API
const char *getDeviceName() const char *getDeviceName()
@@ -120,7 +131,8 @@ RadioInterface *rIf = NULL;
/** /**
* Some platforms (nrf52) might provide an alterate version that supresses calling delay from sleep. * Some platforms (nrf52) might provide an alterate version that supresses calling delay from sleep.
*/ */
__attribute__ ((weak, noinline)) bool loopCanSleep() { __attribute__((weak, noinline)) bool loopCanSleep()
{
return true; return true;
} }
@@ -139,17 +151,23 @@ void setup()
#endif #endif
#ifdef DEBUG_PORT #ifdef DEBUG_PORT
if (!radioConfig.preferences.serial_disabled) { if (!config.device.serial_disabled) {
consoleInit(); // Set serial baud rate and init our mesh console consoleInit(); // Set serial baud rate and init our mesh console
} }
#endif #endif
serialSinceMsec = millis(); serialSinceMsec = millis();
DEBUG_MSG("\n\n//\\ E S H T /\\ S T / C\n\n"); DEBUG_MSG("\n\n//\\ E S H T /\\ S T / C\n\n");
initDeepSleep(); initDeepSleep();
// Testing this fix für erratic T-Echo boot behaviour
#if defined(TTGO_T_ECHO) && defined(PIN_EINK_PWR_ON)
pinMode(PIN_EINK_PWR_ON, OUTPUT);
digitalWrite(PIN_EINK_PWR_ON, HIGH);
#endif
#ifdef VEXT_ENABLE #ifdef VEXT_ENABLE
pinMode(VEXT_ENABLE, OUTPUT); pinMode(VEXT_ENABLE, OUTPUT);
digitalWrite(VEXT_ENABLE, 0); // turn on the display power digitalWrite(VEXT_ENABLE, 0); // turn on the display power
@@ -189,7 +207,7 @@ void setup()
fsInit(); fsInit();
//router = new DSRRouter(); // router = new DSRRouter();
router = new ReliableRouter(); router = new ReliableRouter();
#ifdef I2C_SDA #ifdef I2C_SDA
@@ -208,6 +226,9 @@ void setup()
#endif #endif
scanI2Cdevice(); scanI2Cdevice();
#ifdef RAK4630
// scanEInkDevice();
#endif
// Buttons & LED // Buttons & LED
buttonThread = new ButtonThread(); buttonThread = new ButtonThread();
@@ -279,7 +300,7 @@ void setup()
// Don't call screen setup until after nodedb is setup (because we need // Don't call screen setup until after nodedb is setup (because we need
// the current region name) // the current region name)
#if defined(ST7735_CS) || defined(HAS_EINK) #if defined(ST7735_CS) || defined(HAS_EINK) || defined(ILI9341_DRIVER)
screen->setup(); screen->setup();
#else #else
if (screen_found) if (screen_found)
@@ -292,6 +313,7 @@ void setup()
// ONCE we will factory reset the GPS for bug #327 // ONCE we will factory reset the GPS for bug #327
if (gps && !devicestate.did_gps_reset) { if (gps && !devicestate.did_gps_reset) {
DEBUG_MSG("GPS FactoryReset requested\n");
if (gps->factoryReset()) { // If we don't succeed try again next time if (gps->factoryReset()) { // If we don't succeed try again next time
devicestate.did_gps_reset = true; devicestate.did_gps_reset = true;
nodeDB.saveToDisk(); nodeDB.saveToDisk();
@@ -392,14 +414,12 @@ void setup()
if (!rIf) if (!rIf)
RECORD_CRITICALERROR(CriticalErrorCode_NoRadio); RECORD_CRITICALERROR(CriticalErrorCode_NoRadio);
else{ else {
router->addInterface(rIf); router->addInterface(rIf);
// Calculate and save the bit rate to myNodeInfo // Calculate and save the bit rate to myNodeInfo
// TODO: This needs to be added what ever method changes the channel from the phone. // TODO: This needs to be added what ever method changes the channel from the phone.
myNodeInfo.bitrate = (float(Constants_DATA_PAYLOAD_LEN) / myNodeInfo.bitrate = (float(Constants_DATA_PAYLOAD_LEN) / (float(rIf->getPacketTime(Constants_DATA_PAYLOAD_LEN)))) * 1000;
(float(rIf->getPacketTime(Constants_DATA_PAYLOAD_LEN)))
) * 1000;
DEBUG_MSG("myNodeInfo.bitrate = %f bytes / sec\n", myNodeInfo.bitrate); DEBUG_MSG("myNodeInfo.bitrate = %f bytes / sec\n", myNodeInfo.bitrate);
} }
@@ -411,7 +431,7 @@ void setup()
setCPUFast(false); // 80MHz is fine for our slow peripherals setCPUFast(false); // 80MHz is fine for our slow peripherals
} }
uint32_t rebootAtMsec; // If not zero we will reboot at this time (used to reboot shortly after the update completes) uint32_t rebootAtMsec; // If not zero we will reboot at this time (used to reboot shortly after the update completes)
uint32_t shutdownAtMsec; // If not zero we will shutdown at this time (used to shutdown from python or mobile client) uint32_t shutdownAtMsec; // If not zero we will shutdown at this time (used to shutdown from python or mobile client)
// If a thread does something that might need for it to be rescheduled ASAP it can set this flag // If a thread does something that might need for it to be rescheduled ASAP it can set this flag

View File

@@ -1,19 +1,26 @@
#pragma once #pragma once
#include <map>
#include "GPSStatus.h" #include "GPSStatus.h"
#include "NodeStatus.h" #include "NodeStatus.h"
#include "PowerStatus.h" #include "PowerStatus.h"
#include "graphics/Screen.h" #include "graphics/Screen.h"
#include "mesh/generated/telemetry.pb.h"
extern uint8_t screen_found; extern uint8_t screen_found;
extern uint8_t screen_model; extern uint8_t screen_model;
extern uint8_t cardkb_found; extern uint8_t cardkb_found;
extern uint8_t kb_model;
extern uint8_t faceskb_found; extern uint8_t faceskb_found;
extern uint8_t rtc_found;
extern bool eink_found;
extern bool axp192_found; extern bool axp192_found;
extern bool isCharging; extern bool isCharging;
extern bool isUSBPowered; extern bool isUSBPowered;
extern uint8_t nodeTelemetrySensorsMap[12];
// Global Screen singleton. // Global Screen singleton.
extern graphics::Screen *screen; extern graphics::Screen *screen;
// extern Observable<meshtastic::PowerStatus> newPowerStatus; //TODO: move this to main-esp32.cpp somehow or a helper class // extern Observable<meshtastic::PowerStatus> newPowerStatus; //TODO: move this to main-esp32.cpp somehow or a helper class

View File

@@ -1,7 +1,7 @@
#include "configuration.h"
#include "Channels.h" #include "Channels.h"
#include "CryptoEngine.h" #include "CryptoEngine.h"
#include "NodeDB.h" #include "NodeDB.h"
#include "configuration.h"
#include <assert.h> #include <assert.h>
@@ -83,10 +83,11 @@ void Channels::initDefaultChannel(ChannelIndex chIndex)
{ {
Channel &ch = getByIndex(chIndex); Channel &ch = getByIndex(chIndex);
ChannelSettings &channelSettings = ch.settings; ChannelSettings &channelSettings = ch.settings;
Config_LoRaConfig &loraConfig = config.lora;
channelSettings.modem_config = ChannelSettings_ModemConfig_LongFast; // Default to Long Range & Fast loraConfig.modem_preset = Config_LoRaConfig_ModemPreset_LongFast; // Default to Long Range & Fast
channelSettings.tx_power = 0; // default loraConfig.tx_power = 0; // default
uint8_t defaultpskIndex = 1; uint8_t defaultpskIndex = 1;
channelSettings.psk.bytes[0] = defaultpskIndex; channelSettings.psk.bytes[0] = defaultpskIndex;
channelSettings.psk.size = 1; channelSettings.psk.size = 1;
@@ -206,32 +207,32 @@ const char *Channels::getName(size_t chIndex)
const ChannelSettings &channelSettings = getByIndex(chIndex).settings; const ChannelSettings &channelSettings = getByIndex(chIndex).settings;
const char *channelName = channelSettings.name; const char *channelName = channelSettings.name;
if (!*channelName) { // emptystring if (!*channelName) { // emptystring
// Per mesh.proto spec, if bandwidth is specified we must ignore modemConfig enum, we assume that in that case // Per mesh.proto spec, if bandwidth is specified we must ignore modemPreset enum, we assume that in that case
// the app fucked up and forgot to set channelSettings.name // the app fucked up and forgot to set channelSettings.name
if (channelSettings.bandwidth != 0) if (config.lora.bandwidth != 0)
channelName = "Unset"; channelName = "Unset";
else else
switch (channelSettings.modem_config) { switch (config.lora.modem_preset) {
case ChannelSettings_ModemConfig_ShortSlow: case Config_LoRaConfig_ModemPreset_ShortSlow:
channelName = "ShortSlow"; channelName = "ShortSlow";
break; break;
case ChannelSettings_ModemConfig_ShortFast: case Config_LoRaConfig_ModemPreset_ShortFast:
channelName = "ShortFast"; channelName = "ShortFast";
break; break;
case ChannelSettings_ModemConfig_MidSlow: case Config_LoRaConfig_ModemPreset_MidSlow:
channelName = "MediumSlow"; channelName = "MediumSlow";
break; break;
case ChannelSettings_ModemConfig_MidFast: case Config_LoRaConfig_ModemPreset_MidFast:
channelName = "MediumFast"; channelName = "MediumFast";
break; break;
case ChannelSettings_ModemConfig_LongFast: case Config_LoRaConfig_ModemPreset_LongFast:
channelName = "LongFast"; channelName = "LongFast";
break; break;
case ChannelSettings_ModemConfig_LongSlow: case Config_LoRaConfig_ModemPreset_LongSlow:
channelName = "LongSlow"; channelName = "LongSlow";
break; break;
case ChannelSettings_ModemConfig_VLongSlow: case Config_LoRaConfig_ModemPreset_VLongSlow:
channelName = "VLongSlow"; channelName = "VLongSlow";
break; break;
default: default:

View File

@@ -3,11 +3,7 @@
void CryptoEngine::setKey(const CryptoKey &k) void CryptoEngine::setKey(const CryptoKey &k)
{ {
DEBUG_MSG("Installing AES%d key!\n", k.length * 8); DEBUG_MSG("Using AES%d key!\n", k.length * 8);
/* for(uint8_t i = 0; i < k.length; i++)
DEBUG_MSG("%02x ", k.bytes[i]);
DEBUG_MSG("\n"); */
key = k; key = k;
} }
@@ -36,6 +32,4 @@ void CryptoEngine::initNonce(uint32_t fromNode, uint64_t packetId)
// use memcpy to avoid breaking strict-aliasing // use memcpy to avoid breaking strict-aliasing
memcpy(nonce, &packetId, sizeof(uint64_t)); memcpy(nonce, &packetId, sizeof(uint64_t));
memcpy(nonce + sizeof(uint64_t), &fromNode, sizeof(uint32_t)); memcpy(nonce + sizeof(uint64_t), &fromNode, sizeof(uint32_t));
//*((uint64_t *)&nonce[0]) = packetId;
//*((uint32_t *)&nonce[8]) = fromNode;
} }

View File

@@ -32,7 +32,7 @@ void FloodingRouter::sniffReceived(const MeshPacket *p, const Routing *c)
if ((p->to == NODENUM_BROADCAST) && (p->hop_limit > 0) && (getFrom(p) != getNodeNum())) { if ((p->to == NODENUM_BROADCAST) && (p->hop_limit > 0) && (getFrom(p) != getNodeNum())) {
if (p->id != 0) { if (p->id != 0) {
if (radioConfig.preferences.role != Role_ClientMute) { if (config.device.role != Config_DeviceConfig_Role_ClientMute) {
MeshPacket *tosend = packetPool.allocCopy(*p); // keep a copy because we will be sending it MeshPacket *tosend = packetPool.allocCopy(*p); // keep a copy because we will be sending it
tosend->hop_limit--; // bump down the hop count tosend->hop_limit--; // bump down the hop count

View File

@@ -72,6 +72,16 @@ MeshPacket *MeshPacketQueue::dequeue()
return p; return p;
} }
MeshPacket *MeshPacketQueue::getFront()
{
if (empty()) {
return NULL;
}
auto *p = queue.front();
return p;
}
/** Attempt to find and remove a packet from this queue. Returns a pointer to the removed packet, or NULL if not found */ /** Attempt to find and remove a packet from this queue. Returns a pointer to the removed packet, or NULL if not found */
MeshPacket *MeshPacketQueue::remove(NodeNum from, PacketId id) MeshPacket *MeshPacketQueue::remove(NodeNum from, PacketId id)
{ {

View File

@@ -28,6 +28,8 @@ class MeshPacketQueue
MeshPacket *dequeue(); MeshPacket *dequeue();
MeshPacket *getFront();
/** Attempt to find and remove a packet from this queue. Returns the packet which was removed from the queue */ /** Attempt to find and remove a packet from this queue. Returns the packet which was removed from the queue */
MeshPacket *remove(NodeNum from, PacketId id); MeshPacket *remove(NodeNum from, PacketId id);
}; };

View File

@@ -7,7 +7,7 @@
// Map from old region names to new region enums // Map from old region names to new region enums
struct RegionInfo { struct RegionInfo {
RegionCode code; Config_LoRaConfig_RegionCode code;
float freqStart; float freqStart;
float freqEnd; float freqEnd;
float dutyCycle; float dutyCycle;

View File

@@ -71,17 +71,7 @@ int MeshService::handleFromRadio(const MeshPacket *mp)
printPacket("Forwarding to phone", mp); printPacket("Forwarding to phone", mp);
nodeDB.updateFrom(*mp); // update our DB state based off sniffing every RX packet from the radio nodeDB.updateFrom(*mp); // update our DB state based off sniffing every RX packet from the radio
fromNum++; sendToPhone((MeshPacket *)mp);
if (toPhoneQueue.numFree() == 0) {
DEBUG_MSG("NOTE: tophone queue is full, discarding oldest\n");
MeshPacket *d = toPhoneQueue.dequeuePtr(0);
if (d)
releaseToPool(d);
}
MeshPacket *copied = packetPool.allocCopy(*mp);
assert(toPhoneQueue.enqueue(copied, 0)); // FIXME, instead of failing for full queue, delete the oldest mssages
return 0; return 0;
} }
@@ -161,12 +151,16 @@ bool MeshService::cancelSending(PacketId id)
return router->cancelSending(nodeDB.getNodeNum(), id); return router->cancelSending(nodeDB.getNodeNum(), id);
} }
void MeshService::sendToMesh(MeshPacket *p, RxSource src) void MeshService::sendToMesh(MeshPacket *p, RxSource src, bool ccToPhone)
{ {
nodeDB.updateFrom(*p); // update our local DB for this packet (because phone might have sent position packets etc...) nodeDB.updateFrom(*p); // update our local DB for this packet (because phone might have sent position packets etc...)
// Note: We might return !OK if our fifo was full, at that point the only option we have is to drop it // Note: We might return !OK if our fifo was full, at that point the only option we have is to drop it
router->sendLocal(p, src); router->sendLocal(p, src);
if (ccToPhone) {
sendToPhone(p);
}
} }
void MeshService::sendNetworkPing(NodeNum dest, bool wantReplies) void MeshService::sendNetworkPing(NodeNum dest, bool wantReplies)
@@ -187,6 +181,21 @@ void MeshService::sendNetworkPing(NodeNum dest, bool wantReplies)
} }
} }
void MeshService::sendToPhone(MeshPacket *p)
{
if (toPhoneQueue.numFree() == 0) {
DEBUG_MSG("NOTE: tophone queue is full, discarding oldest\n");
MeshPacket *d = toPhoneQueue.dequeuePtr(0);
if (d)
releaseToPool(d);
}
MeshPacket *copied = packetPool.allocCopy(*p);
perhapsDecode(copied);
assert(toPhoneQueue.enqueue(copied, 0)); // FIXME, instead of failing for full queue, delete the oldest mssages
fromNum++;
}
NodeInfo *MeshService::refreshMyNodeInfo() NodeInfo *MeshService::refreshMyNodeInfo()
{ {
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum()); NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
@@ -224,10 +233,10 @@ int MeshService::onGPSChanged(const meshtastic::GPSStatus *newStatus)
} else { } else {
// The GPS has lost lock, if we are fixed position we should just keep using // The GPS has lost lock, if we are fixed position we should just keep using
// the old position // the old position
#if GPS_EXTRAVERBOSE #ifdef GPS_EXTRAVERBOSE
DEBUG_MSG("onGPSchanged() - lost validLocation\n"); DEBUG_MSG("onGPSchanged() - lost validLocation\n");
#endif #endif
if (radioConfig.preferences.fixed_position) { if (config.position.fixed_position) {
DEBUG_MSG("WARNING: Using fixed position\n"); DEBUG_MSG("WARNING: Using fixed position\n");
pos = node->position; pos = node->position;
} }
@@ -239,8 +248,8 @@ int MeshService::onGPSChanged(const meshtastic::GPSStatus *newStatus)
pos.time = getValidTime(RTCQualityGPS); pos.time = getValidTime(RTCQualityGPS);
// In debug logs, identify position by @timestamp:stage (stage 4 = nodeDB) // In debug logs, identify position by @timestamp:stage (stage 4 = nodeDB)
DEBUG_MSG("onGPSChanged() pos@%x, time=%u, lat=%d, lon=%d, alt=%d\n", DEBUG_MSG("onGPSChanged() pos@%x, time=%u, lat=%d, lon=%d, alt=%d\n", pos.pos_timestamp, pos.time, pos.latitude_i,
pos.pos_timestamp, pos.time, pos.latitude_i, pos.longitude_i, pos.altitude); pos.longitude_i, pos.altitude);
// Update our current position in the local DB // Update our current position in the local DB
nodeDB.updatePosition(nodeDB.getNodeNum(), pos, RX_SRC_LOCAL); nodeDB.updatePosition(nodeDB.getNodeNum(), pos, RX_SRC_LOCAL);

View File

@@ -75,7 +75,7 @@ class MeshService
/// Send a packet into the mesh - note p must have been allocated from packetPool. We will return it to that pool after /// Send a packet into the mesh - note p must have been allocated from packetPool. We will return it to that pool after
/// sending. This is the ONLY function you should use for sending messages into the mesh, because it also updates the nodedb /// sending. This is the ONLY function you should use for sending messages into the mesh, because it also updates the nodedb
/// cache /// cache
void sendToMesh(MeshPacket *p, RxSource src = RX_SRC_LOCAL); void sendToMesh(MeshPacket *p, RxSource src = RX_SRC_LOCAL, bool ccToPhone = false);
/** Attempt to cancel a previously sent packet from this _local_ node. Returns true if a packet was found we could cancel */ /** Attempt to cancel a previously sent packet from this _local_ node. Returns true if a packet was found we could cancel */
bool cancelSending(PacketId id); bool cancelSending(PacketId id);
@@ -83,6 +83,9 @@ class MeshService
/// Pull the latest power and time info into my nodeinfo /// Pull the latest power and time info into my nodeinfo
NodeInfo *refreshMyNodeInfo(); NodeInfo *refreshMyNodeInfo();
/// Send a packet to the phone
void sendToPhone(MeshPacket *p);
private: private:
/// Called when our gps position has changed - updates nodedb and sends Location message out into the mesh /// Called when our gps position has changed - updates nodedb and sends Location message out into the mesh
/// returns 0 to allow futher processing /// returns 0 to allow futher processing

View File

@@ -34,7 +34,8 @@ NodeDB nodeDB;
// we have plenty of ram so statically alloc this tempbuf (for now) // we have plenty of ram so statically alloc this tempbuf (for now)
EXT_RAM_ATTR DeviceState devicestate; EXT_RAM_ATTR DeviceState devicestate;
MyNodeInfo &myNodeInfo = devicestate.my_node; MyNodeInfo &myNodeInfo = devicestate.my_node;
RadioConfig radioConfig; LocalConfig config;
LocalModuleConfig moduleConfig;
ChannelFile channelFile; ChannelFile channelFile;
/** The current change # for radio settings. Starts at 0 on boot and any time the radio settings /** The current change # for radio settings. Starts at 0 on boot and any time the radio settings
@@ -47,7 +48,7 @@ DeviceState versions used to be defined in the .proto file but really only this
#define here. #define here.
*/ */
#define DEVICESTATE_CUR_VER 11 #define DEVICESTATE_CUR_VER 13
#define DEVICESTATE_MIN_VER DEVICESTATE_CUR_VER #define DEVICESTATE_MIN_VER DEVICESTATE_CUR_VER
// FIXME - move this somewhere else // FIXME - move this somewhere else
@@ -86,23 +87,24 @@ bool NodeDB::resetRadioConfig()
radioGeneration++; radioGeneration++;
radioConfig.has_preferences = true; // radioConfig.has_preferences = true;
if (radioConfig.preferences.factory_reset) { if (config.device.factory_reset) {
DEBUG_MSG("Performing factory reset!\n"); DEBUG_MSG("Performing factory reset!\n");
// first, remove the "/prefs" (this removes most prefs)
rmDir("/prefs");
// second, install default state (this will deal with the duplicate mac address issue)
installDefaultDeviceState(); installDefaultDeviceState();
// third, write to disk
saveToDisk();
#ifndef NO_ESP32 #ifndef NO_ESP32
// This will erase what's in NVS including ssl keys, persistant variables and ble pairing // This will erase what's in NVS including ssl keys, persistant variables and ble pairing
nvs_flash_erase(); nvs_flash_erase();
#endif #endif
#ifdef NRF52_SERIES #ifdef NRF52_SERIES
FSCom.rmdir_r("/prefs");
Bluefruit.begin(); Bluefruit.begin();
DEBUG_MSG("Clearing bluetooth bonds!\n"); DEBUG_MSG("Clearing bluetooth bonds!\n");
bond_print_list(BLE_GAP_ROLE_PERIPH); bond_print_list(BLE_GAP_ROLE_PERIPH);
bond_print_list(BLE_GAP_ROLE_CENTRAL); bond_print_list(BLE_GAP_ROLE_CENTRAL);
Bluefruit.Periph.clearBonds(); Bluefruit.Periph.clearBonds();
Bluefruit.Central.clearBonds(); Bluefruit.Central.clearBonds();
#endif #endif
@@ -123,11 +125,11 @@ bool NodeDB::resetRadioConfig()
DEBUG_MSG("***** DEVELOPMENT MODE - DO NOT RELEASE *****\n"); DEBUG_MSG("***** DEVELOPMENT MODE - DO NOT RELEASE *****\n");
// Sleep quite frequently to stress test the BLE comms, broadcast position every 6 mins // Sleep quite frequently to stress test the BLE comms, broadcast position every 6 mins
radioConfig.preferences.screen_on_secs = 10; config.display.screen_on_secs = 10;
radioConfig.preferences.wait_bluetooth_secs = 10; config.power.wait_bluetooth_secs = 10;
radioConfig.preferences.position_broadcast_secs = 6 * 60; config.position.position_broadcast_secs = 6 * 60;
radioConfig.preferences.ls_secs = 60; config.power.ls_secs = 60;
radioConfig.preferences.region = RegionCode_TW; config.lora.region = Config_LoRaConfig_RegionCode_TW;
// Enter super deep sleep soon and stay there not very long // Enter super deep sleep soon and stay there not very long
// radioConfig.preferences.mesh_sds_timeout_secs = 10; // radioConfig.preferences.mesh_sds_timeout_secs = 10;
@@ -140,30 +142,48 @@ bool NodeDB::resetRadioConfig()
return didFactoryReset; return didFactoryReset;
} }
void NodeDB::installDefaultRadioConfig() void NodeDB::installDefaultConfig()
{ {
memset(&radioConfig, 0, sizeof(radioConfig)); memset(&config, 0, sizeof(LocalConfig));
radioConfig.has_preferences = true; config.version = DEVICESTATE_CUR_VER;
config.has_device = true;
config.has_display = true;
config.has_lora = true;
config.has_position = true;
config.has_power = true;
config.has_wifi = true;
config.lora.region = Config_LoRaConfig_RegionCode_Unset;
config.lora.modem_preset = Config_LoRaConfig_ModemPreset_LongFast;
resetRadioConfig(); resetRadioConfig();
strncpy(config.device.ntp_server, "0.pool.ntp.org", 32);
// for backward compat, default position flags are ALT+MSL
config.position.position_flags =
(Config_PositionConfig_PositionFlags_POS_ALTITUDE | Config_PositionConfig_PositionFlags_POS_ALT_MSL);
}
// for backward compat, default position flags are BAT+ALT+MSL (0x23 = 35) void NodeDB::installDefaultModuleConfig()
radioConfig.preferences.position_flags = (PositionFlags_POS_BATTERY | {
PositionFlags_POS_ALTITUDE | PositionFlags_POS_ALT_MSL); memset(&moduleConfig, 0, sizeof(ModuleConfig));
moduleConfig.version = DEVICESTATE_CUR_VER;
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;
} }
void NodeDB::installDefaultChannels() void NodeDB::installDefaultChannels()
{ {
memset(&channelFile, 0, sizeof(channelFile)); memset(&channelFile, 0, sizeof(ChannelFile));
channelFile.version = DEVICESTATE_CUR_VER;
} }
void NodeDB::installDefaultDeviceState() void NodeDB::installDefaultDeviceState()
{ {
// We try to preserve the region setting because it will really bum users out if we discard it memset(&devicestate, 0, sizeof(DeviceState));
String oldRegion = myNodeInfo.region;
RegionCode oldRegionCode = radioConfig.preferences.region;
memset(&devicestate, 0, sizeof(devicestate));
*numNodes = 0; // Forget node DB *numNodes = 0; // Forget node DB
@@ -185,19 +205,13 @@ void NodeDB::installDefaultDeviceState()
// Set default owner name // Set default owner name
pickNewNodeNum(); // based on macaddr now pickNewNodeNum(); // based on macaddr now
sprintf(owner.long_name, "Unknown %02x%02x", ourMacAddr[4], ourMacAddr[5]); sprintf(owner.long_name, "Unknown %02x%02x", ourMacAddr[4], ourMacAddr[5]);
sprintf(owner.short_name, "?%02X", (unsigned)(myNodeInfo.my_node_num & 0xff)); sprintf(owner.short_name, "%02x%02x", ourMacAddr[4], ourMacAddr[5]);
sprintf(owner.id, "!%08x", getNodeNum()); // Default node ID now based on nodenum sprintf(owner.id, "!%08x", getNodeNum()); // Default node ID now based on nodenum
memcpy(owner.macaddr, ourMacAddr, sizeof(owner.macaddr)); memcpy(owner.macaddr, ourMacAddr, sizeof(owner.macaddr));
// Restore region if possible
if (oldRegionCode != RegionCode_Unset)
radioConfig.preferences.region = oldRegionCode;
if (oldRegion.length()) // If the old style region was set, try to keep it up-to-date
strcpy(myNodeInfo.region, oldRegion.c_str());
installDefaultChannels(); installDefaultChannels();
installDefaultRadioConfig(); installDefaultConfig();
} }
void NodeDB::init() void NodeDB::init()
@@ -215,7 +229,7 @@ void NodeDB::init()
myNodeInfo.error_address = 0; myNodeInfo.error_address = 0;
// likewise - we always want the app requirements to come from the running appload // likewise - we always want the app requirements to come from the running appload
myNodeInfo.min_app_version = 20200; // format is Mmmss (where M is 1+the numeric major number. i.e. 20120 means 1.1.20 myNodeInfo.min_app_version = 20300; // format is Mmmss (where M is 1+the numeric major number. i.e. 20120 means 1.1.20
// Note! We do this after loading saved settings, so that if somehow an invalid nodenum was stored in preferences we won't // Note! We do this after loading saved settings, so that if somehow an invalid nodenum was stored in preferences we won't
// keep using that nodenum forever. Crummy guess at our nodenum (but we will check against the nodedb to avoid conflicts) // keep using that nodenum forever. Crummy guess at our nodenum (but we will check against the nodedb to avoid conflicts)
@@ -239,14 +253,14 @@ void NodeDB::init()
DEBUG_MSG("Number of Device Reboots: %d\n", myNodeInfo.reboot_count); DEBUG_MSG("Number of Device Reboots: %d\n", myNodeInfo.reboot_count);
/* The ESP32 has a wifi radio. This will need to be modified at some point so /* The ESP32 has a wifi radio. This will need to be modified at some point so
* the test isn't so simplistic. * the test isn't so simplistic.
*/ */
myNodeInfo.has_wifi = true; myNodeInfo.has_wifi = true;
#endif #endif
resetRadioConfig(); // If bogus settings got saved, then fix them resetRadioConfig(); // If bogus settings got saved, then fix them
DEBUG_MSG("region=%d, NODENUM=0x%x, dbsize=%d\n", radioConfig.preferences.region, myNodeInfo.my_node_num, *numNodes); DEBUG_MSG("region=%d, NODENUM=0x%x, dbsize=%d\n", config.lora.region, myNodeInfo.my_node_num, *numNodes);
} }
// We reserve a few nodenums for future use // We reserve a few nodenums for future use
@@ -276,28 +290,20 @@ void NodeDB::pickNewNodeNum()
myNodeInfo.my_node_num = r; myNodeInfo.my_node_num = r;
} }
static const char *preffileOld = "/db.proto";
static const char *preffile = "/prefs/db.proto"; static const char *preffile = "/prefs/db.proto";
static const char *radiofile = "/prefs/radio.proto"; static const char *configfile = "/prefs/config.proto";
static const char *moduleConfigfile = "/prefs/module.proto";
static const char *channelfile = "/prefs/channels.proto"; static const char *channelfile = "/prefs/channels.proto";
// const char *preftmp = "/db.proto.tmp";
/** Load a protobuf from a file, return true for success */ /** Load a protobuf from a file, return true for success */
bool loadProto(const char *filename, size_t protoSize, size_t objSize, const pb_msgdesc_t *fields, void *dest_struct) bool loadProto(const char *filename, size_t protoSize, size_t objSize, const pb_msgdesc_t *fields, void *dest_struct)
{ {
bool okay = false;
#ifdef FSCom #ifdef FSCom
// static DeviceState scratch; We no longer read into a tempbuf because this structure is 15KB of valuable RAM // static DeviceState scratch; We no longer read into a tempbuf because this structure is 15KB of valuable RAM
auto f = FSCom.open(filename); auto f = FSCom.open(filename);
// FIXME, temporary hack until every node in the universe is 1.2 or later - look for prefs in the old location (so we can
// preserve region)
if (!f && filename == preffile) {
filename = preffileOld;
f = FSCom.open(filename);
}
bool okay = false;
if (f) { if (f) {
DEBUG_MSG("Loading %s\n", filename); DEBUG_MSG("Loading %s\n", filename);
pb_istream_t stream = {&readcb, &f, protoSize}; pb_istream_t stream = {&readcb, &f, protoSize};
@@ -330,29 +336,66 @@ void NodeDB::loadFromDisk()
if (devicestate.version < DEVICESTATE_MIN_VER) { if (devicestate.version < DEVICESTATE_MIN_VER) {
DEBUG_MSG("Warn: devicestate %d is old, discarding\n", devicestate.version); DEBUG_MSG("Warn: devicestate %d is old, discarding\n", devicestate.version);
installDefaultDeviceState(); installDefaultDeviceState();
#ifndef NO_ESP32
// This will erase what's in NVS including ssl keys, persistant variables and ble pairing
nvs_flash_erase();
#endif
#ifdef NRF52_SERIES
Bluefruit.begin();
DEBUG_MSG("Clearing bluetooth bonds!\n");
bond_print_list(BLE_GAP_ROLE_PERIPH);
bond_print_list(BLE_GAP_ROLE_CENTRAL);
Bluefruit.Periph.clearBonds();
Bluefruit.Central.clearBonds();
#endif
} else { } else {
DEBUG_MSG("Loaded saved preferences version %d\n", devicestate.version); DEBUG_MSG("Loaded saved devicestate version %d\n", devicestate.version);
} }
} }
if (!loadProto(radiofile, RadioConfig_size, sizeof(RadioConfig), RadioConfig_fields, &radioConfig)) { if (!loadProto(configfile, LocalConfig_size, sizeof(LocalConfig), LocalConfig_fields, &config)) {
installDefaultRadioConfig(); // Our in RAM copy might now be corrupt installDefaultConfig(); // Our in RAM copy might now be corrupt
} else {
if (config.version < DEVICESTATE_MIN_VER) {
DEBUG_MSG("Warn: config %d is old, discarding\n", config.version);
installDefaultConfig();
} else {
DEBUG_MSG("Loaded saved config version %d\n", config.version);
}
}
if (!loadProto(moduleConfigfile, LocalModuleConfig_size, sizeof(LocalModuleConfig), LocalModuleConfig_fields, &moduleConfig)) {
installDefaultModuleConfig(); // Our in RAM copy might now be corrupt
} else {
if (moduleConfig.version < DEVICESTATE_MIN_VER) {
DEBUG_MSG("Warn: moduleConfig %d is old, discarding\n", moduleConfig.version);
installDefaultModuleConfig();
} else {
DEBUG_MSG("Loaded saved moduleConfig version %d\n", moduleConfig.version);
}
} }
if (!loadProto(channelfile, ChannelFile_size, sizeof(ChannelFile), ChannelFile_fields, &channelFile)) { if (!loadProto(channelfile, ChannelFile_size, sizeof(ChannelFile), ChannelFile_fields, &channelFile)) {
installDefaultChannels(); // Our in RAM copy might now be corrupt installDefaultChannels(); // Our in RAM copy might now be corrupt
} else {
if (channelFile.version < DEVICESTATE_MIN_VER) {
DEBUG_MSG("Warn: channelFile %d is old, discarding\n", channelFile.version);
installDefaultChannels();
} else {
DEBUG_MSG("Loaded saved channelFile version %d\n", channelFile.version);
}
} }
} }
/** Save a protobuf from a file, return true for success */ /** Save a protobuf from a file, return true for success */
bool saveProto(const char *filename, size_t protoSize, size_t objSize, const pb_msgdesc_t *fields, const void *dest_struct) bool saveProto(const char *filename, size_t protoSize, size_t objSize, const pb_msgdesc_t *fields, const void *dest_struct)
{ {
bool okay = false;
#ifdef FSCom #ifdef FSCom
// static DeviceState scratch; We no longer read into a tempbuf because this structure is 15KB of valuable RAM // static DeviceState scratch; We no longer read into a tempbuf because this structure is 15KB of valuable RAM
String filenameTmp = filename; String filenameTmp = filename;
filenameTmp += ".tmp"; filenameTmp += ".tmp";
auto f = FSCom.open(filenameTmp.c_str(), FILE_O_WRITE); auto f = FSCom.open(filenameTmp.c_str(), FILE_O_WRITE);
bool okay = false;
if (f) { if (f) {
DEBUG_MSG("Saving %s\n", filename); DEBUG_MSG("Saving %s\n", filename);
pb_ostream_t stream = {&writecb, &f, protoSize}; pb_ostream_t stream = {&writecb, &f, protoSize};
@@ -366,7 +409,7 @@ bool saveProto(const char *filename, size_t protoSize, size_t objSize, const pb_
f.close(); f.close();
// brief window of risk here ;-) // brief window of risk here ;-)
if (!FSCom.remove(filename)) if (FSCom.exists(filename) && !FSCom.remove(filename))
DEBUG_MSG("Warning: Can't remove old pref file\n"); DEBUG_MSG("Warning: Can't remove old pref file\n");
if (!FSCom.rename(filenameTmp.c_str(), filename)) if (!FSCom.rename(filenameTmp.c_str(), filename))
DEBUG_MSG("Error: can't rename new pref file\n"); DEBUG_MSG("Error: can't rename new pref file\n");
@@ -396,11 +439,27 @@ void NodeDB::saveToDisk()
FSCom.mkdir("/prefs"); FSCom.mkdir("/prefs");
#endif #endif
saveProto(preffile, DeviceState_size, sizeof(devicestate), DeviceState_fields, &devicestate); saveProto(preffile, DeviceState_size, sizeof(devicestate), DeviceState_fields, &devicestate);
saveProto(radiofile, RadioConfig_size, sizeof(RadioConfig), RadioConfig_fields, &radioConfig);
// 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_wifi = true;
saveProto(configfile, LocalConfig_size, sizeof(LocalConfig), 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(moduleConfigfile, LocalModuleConfig_size, sizeof(LocalModuleConfig), LocalModuleConfig_fields, &moduleConfig);
saveChannelsToDisk(); saveChannelsToDisk();
// remove any pre 1.2 pref files, turn on after 1.2 is in beta
// if(okay) FSCom.remove(preffileOld);
} else { } else {
DEBUG_MSG("***** DEVELOPMENT MODE - DO NOT RELEASE - not saving to flash *****\n"); DEBUG_MSG("***** DEVELOPMENT MODE - DO NOT RELEASE - not saving to flash *****\n");
} }
@@ -426,7 +485,7 @@ uint32_t sinceLastSeen(const NodeInfo *n)
return delta; return delta;
} }
#define NUM_ONLINE_SECS (60 & 60 * 2) // 2 hrs to consider someone offline #define NUM_ONLINE_SECS (60 * 60 * 2) // 2 hrs to consider someone offline
size_t NodeDB::getNumOnlineNodes() size_t NodeDB::getNumOnlineNodes()
{ {
@@ -453,12 +512,11 @@ void NodeDB::updatePosition(uint32_t nodeId, const Position &p, RxSource src)
if (src == RX_SRC_LOCAL) { if (src == RX_SRC_LOCAL) {
// Local packet, fully authoritative // Local packet, fully authoritative
DEBUG_MSG("updatePosition LOCAL pos@%x, time=%u, latI=%d, lonI=%d, alt=%d\n", DEBUG_MSG("updatePosition LOCAL pos@%x, time=%u, latI=%d, lonI=%d, alt=%d\n", p.pos_timestamp, p.time, p.latitude_i,
p.pos_timestamp, p.time, p.latitude_i, p.longitude_i, p.altitude); p.longitude_i, p.altitude);
info->position = p; info->position = p;
} else if ((p.time > 0) && !p.latitude_i && !p.longitude_i && !p.pos_timestamp && } else if ((p.time > 0) && !p.latitude_i && !p.longitude_i && !p.pos_timestamp && !p.location_source) {
!p.location_source) {
// FIXME SPECIAL TIME SETTING PACKET FROM EUD TO RADIO // FIXME SPECIAL TIME SETTING PACKET FROM EUD TO RADIO
// (stop-gap fix for issue #900) // (stop-gap fix for issue #900)
DEBUG_MSG("updatePosition SPECIAL time setting time=%u\n", p.time); DEBUG_MSG("updatePosition SPECIAL time setting time=%u\n", p.time);
@@ -470,8 +528,7 @@ void NodeDB::updatePosition(uint32_t nodeId, const Position &p, RxSource src)
// recorded based on the packet rxTime // recorded based on the packet rxTime
// //
// FIXME perhaps handle RX_SRC_USER separately? // FIXME perhaps handle RX_SRC_USER separately?
DEBUG_MSG("updatePosition REMOTE node=0x%x time=%u, latI=%d, lonI=%d\n", DEBUG_MSG("updatePosition REMOTE node=0x%x time=%u, latI=%d, lonI=%d\n", nodeId, p.time, p.latitude_i, p.longitude_i);
nodeId, p.time, p.latitude_i, p.longitude_i);
// First, back up fields that we want to protect from overwrite // First, back up fields that we want to protect from overwrite
uint32_t tmp_time = info->position.time; uint32_t tmp_time = info->position.time;
@@ -480,7 +537,7 @@ void NodeDB::updatePosition(uint32_t nodeId, const Position &p, RxSource src)
info->position = p; info->position = p;
// Last, restore any fields that may have been overwritten // Last, restore any fields that may have been overwritten
if (! info->position.time) if (!info->position.time)
info->position.time = tmp_time; info->position.time = tmp_time;
} }
info->has_position = true; info->has_position = true;
@@ -488,7 +545,6 @@ void NodeDB::updatePosition(uint32_t nodeId, const Position &p, RxSource src)
notifyObservers(true); // Force an update whether or not our node counts have changed notifyObservers(true); // Force an update whether or not our node counts have changed
} }
/** Update telemetry info for this node based on received metrics /** Update telemetry info for this node based on received metrics
* We only care about device telemetry here * We only care about device telemetry here
*/ */
@@ -600,7 +656,7 @@ void recordCriticalError(CriticalErrorCode code, uint32_t address, const char *f
// Print error to screen and serial port // Print error to screen and serial port
String lcd = String("Critical error ") + code + "!\n"; String lcd = String("Critical error ") + code + "!\n";
screen->print(lcd.c_str()); screen->print(lcd.c_str());
if(filename) if (filename)
DEBUG_MSG("NOTE! Recording critical error %d at %s:%lx\n", code, filename, address); DEBUG_MSG("NOTE! Recording critical error %d at %s:%lx\n", code, filename, address);
else else
DEBUG_MSG("NOTE! Recording critical error %d, address=%lx\n", code, address); DEBUG_MSG("NOTE! Recording critical error %d, address=%lx\n", code, address);

View File

@@ -11,7 +11,8 @@
extern DeviceState devicestate; extern DeviceState devicestate;
extern ChannelFile channelFile; extern ChannelFile channelFile;
extern MyNodeInfo &myNodeInfo; extern MyNodeInfo &myNodeInfo;
extern RadioConfig radioConfig; extern LocalConfig config;
extern LocalModuleConfig moduleConfig;
extern User &owner; extern User &owner;
/// Given a node, return how many seconds in the past (vs now) that we last heard from it /// Given a node, return how many seconds in the past (vs now) that we last heard from it
@@ -63,7 +64,7 @@ class NodeDB
/** Update telemetry info for this node based on received metrics /** Update telemetry info for this node based on received metrics
*/ */
void updateTelemetry(uint32_t nodeId, const Telemetry &t, RxSource src = RX_SRC_RADIO); void updateTelemetry(uint32_t nodeId, const Telemetry &t, RxSource src = RX_SRC_RADIO);
/** Update user info for this node based on received user data /** Update user info for this node based on received user data
*/ */
@@ -122,7 +123,8 @@ class NodeDB
void loadFromDisk(); void loadFromDisk();
/// Reinit device state from scratch (not loading from disk) /// Reinit device state from scratch (not loading from disk)
void installDefaultDeviceState(), installDefaultRadioConfig(), installDefaultChannels(); void installDefaultDeviceState(), installDefaultChannels(), installDefaultConfig(),
installDefaultModuleConfig();
}; };
/** /**
@@ -136,7 +138,7 @@ extern NodeDB nodeDB;
/* /*
If is_router is set, we use a number of different default values If is_router is set, we use a number of different default values
# FIXME - after tuning, move these params into the on-device defaults based on is_router and is_low_power # FIXME - after tuning, move these params into the on-device defaults based on is_router and is_power_saving
# prefs.position_broadcast_secs = FIXME possibly broadcast only once an hr # prefs.position_broadcast_secs = FIXME possibly broadcast only once an hr
prefs.wait_bluetooth_secs = 1 # Don't stay in bluetooth mode prefs.wait_bluetooth_secs = 1 # Don't stay in bluetooth mode
@@ -146,11 +148,11 @@ extern NodeDB nodeDB;
prefs.ls_secs = oneday prefs.ls_secs = oneday
prefs.position_broadcast_secs = 12 hours # send either position or owner every 12hrs prefs.position_broadcast_secs = 12 hours # send either position or owner every 12hrs
# get a new GPS position once per day # get a new GPS position once per day
prefs.gps_update_interval = oneday prefs.gps_update_interval = oneday
prefs.is_low_power = True prefs.is_power_saving = True
# allow up to five minutes for each new GPS lock attempt # allow up to five minutes for each new GPS lock attempt
prefs.gps_attempt_time = 300 prefs.gps_attempt_time = 300
@@ -159,33 +161,26 @@ extern NodeDB nodeDB;
// Our delay functions check for this for times that should never expire // Our delay functions check for this for times that should never expire
#define NODE_DELAY_FOREVER 0xffffffff #define NODE_DELAY_FOREVER 0xffffffff
#define IF_ROUTER(routerVal, normalVal) ((radioConfig.preferences.role == Role_Router) ? (routerVal) : (normalVal)) #define IF_ROUTER(routerVal, normalVal) ((config.device.role == Config_DeviceConfig_Role_Router) ? (routerVal) : (normalVal))
#define PREF_GET(name, defaultVal) \ #define default_broadcast_interval_secs IF_ROUTER(12 * 60 * 60, 15 * 60)
inline uint32_t getPref_##name() { return radioConfig.preferences.name ? radioConfig.preferences.name : (defaultVal); } #define default_wait_bluetooth_secs IF_ROUTER(1, 60)
#define default_mesh_sds_timeout_secs IF_ROUTER(NODE_DELAY_FOREVER, 2 * 60 * 60)
PREF_GET(position_broadcast_secs, IF_ROUTER(12 * 60 * 60, 15 * 60)) #define default_sds_secs 365 * 24 * 60 * 60
// Defaulting Telemetry to the same as position interval for now #define default_ls_secs IF_ROUTER(24 * 60 * 60, 5 * 60)
PREF_GET(telemetry_module_device_update_interval, IF_ROUTER(12 * 60 * 60, 15 * 60)) #define default_min_wake_secs 10
PREF_GET(telemetry_module_environment_update_interval, IF_ROUTER(12 * 60 * 60, 15 * 60))
// Each time we wake into the DARK state allow 1 minute to send and receive BLE packets to the phone inline uint32_t getIntervalOrDefaultMs(uint32_t interval)
PREF_GET(wait_bluetooth_secs, IF_ROUTER(1, 60)) {
if (interval > 0)
return interval * 1000;
return default_broadcast_interval_secs * 1000;
}
PREF_GET(screen_on_secs, 60) /** The current change # for radio settings. Starts at 0 on boot and any time the radio settings
PREF_GET(mesh_sds_timeout_secs, IF_ROUTER(NODE_DELAY_FOREVER, 2 * 60 * 60))
PREF_GET(sds_secs, 365 * 24 * 60 * 60)
// We default to sleeping (with bluetooth off for 5 minutes at a time). This seems to be a good tradeoff between
// latency for the user sending messages and power savings because of not having to run (expensive) ESP32 bluetooth
PREF_GET(ls_secs, IF_ROUTER(24 * 60 * 60, 5 * 60))
PREF_GET(phone_timeout_secs, 15 * 60)
PREF_GET(min_wake_secs, 10)
/** The current change # for radio settings. Starts at 0 on boot and any time the radio settings
* might have changed is incremented. Allows others to detect they might now be on a new channel. * might have changed is incremented. Allows others to detect they might now be on a new channel.
*/ */
extern uint32_t radioGeneration; 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)

View File

@@ -48,7 +48,7 @@ void PhoneAPI::close()
if (state != STATE_SEND_NOTHING) { if (state != STATE_SEND_NOTHING) {
state = STATE_SEND_NOTHING; state = STATE_SEND_NOTHING;
unobserve(); unobserve(&service.fromNumChanged);
releasePhonePacket(); // Don't leak phone packets on shutdown releasePhonePacket(); // Don't leak phone packets on shutdown
onConnectionChanged(false); onConnectionChanged(false);

View File

@@ -48,6 +48,17 @@ template <class T> class ProtobufModule : protected SinglePortModule
return p; return p;
} }
/**
* Gets the short name from the sender of the mesh packet
* Returns "???" if unknown sender
*/
const char *getSenderShortName(const MeshPacket &mp)
{
auto node = nodeDB.getNode(getFrom(&mp));
const char *sender = (node) ? node->user.short_name : "???";
return sender;
}
private: private:
/** Called to handle a particular incoming message /** Called to handle a particular incoming message
@@ -66,10 +77,13 @@ template <class T> class ProtobufModule : protected SinglePortModule
T *decoded = NULL; T *decoded = NULL;
if (mp.which_payloadVariant == MeshPacket_decoded_tag && mp.decoded.portnum == ourPortNum) { if (mp.which_payloadVariant == MeshPacket_decoded_tag && mp.decoded.portnum == ourPortNum) {
memset(&scratch, 0, sizeof(scratch)); memset(&scratch, 0, sizeof(scratch));
if (pb_decode_from_bytes(p.payload.bytes, p.payload.size, fields, &scratch)) if (pb_decode_from_bytes(p.payload.bytes, p.payload.size, fields, &scratch)) {
decoded = &scratch; decoded = &scratch;
else } else {
DEBUG_MSG("Error decoding protobuf module!\n"); DEBUG_MSG("Error decoding protobuf module!\n");
// if we can't decode it, nobody can process it!
return ProcessMessage::STOP;
}
} }
return handleReceivedProtobuf(mp, decoded) ? ProcessMessage::STOP : ProcessMessage::CONTINUE; return handleReceivedProtobuf(mp, decoded) ? ProcessMessage::STOP : ProcessMessage::CONTINUE;

View File

@@ -76,13 +76,13 @@ bool RF95Interface::init()
DEBUG_MSG("Current limit set to %f\n", currentLimit); DEBUG_MSG("Current limit set to %f\n", currentLimit);
DEBUG_MSG("Current limit set result %d\n", res); DEBUG_MSG("Current limit set result %d\n", res);
if (res == ERR_NONE) if (res == RADIOLIB_ERR_NONE)
res = lora->setCRC(SX126X_LORA_CRC_ON); res = lora->setCRC(RADIOLIB_SX126X_LORA_CRC_ON);
if (res == ERR_NONE) if (res == RADIOLIB_ERR_NONE)
startReceive(); // start receiving startReceive(); // start receiving
return res == ERR_NONE; return res == RADIOLIB_ERR_NONE;
} }
void INTERRUPT_ATTR RF95Interface::disableInterrupt() void INTERRUPT_ATTR RF95Interface::disableInterrupt()
@@ -99,39 +99,39 @@ bool RF95Interface::reconfigure()
// configure publicly accessible settings // configure publicly accessible settings
int err = lora->setSpreadingFactor(sf); int err = lora->setSpreadingFactor(sf);
if (err != ERR_NONE) if (err != RADIOLIB_ERR_NONE)
RECORD_CRITICALERROR(CriticalErrorCode_InvalidRadioSetting); RECORD_CRITICALERROR(CriticalErrorCode_InvalidRadioSetting);
err = lora->setBandwidth(bw); err = lora->setBandwidth(bw);
if (err != ERR_NONE) if (err != RADIOLIB_ERR_NONE)
RECORD_CRITICALERROR(CriticalErrorCode_InvalidRadioSetting); RECORD_CRITICALERROR(CriticalErrorCode_InvalidRadioSetting);
err = lora->setCodingRate(cr); err = lora->setCodingRate(cr);
if (err != ERR_NONE) if (err != RADIOLIB_ERR_NONE)
RECORD_CRITICALERROR(CriticalErrorCode_InvalidRadioSetting); RECORD_CRITICALERROR(CriticalErrorCode_InvalidRadioSetting);
err = lora->setSyncWord(syncWord); err = lora->setSyncWord(syncWord);
assert(err == ERR_NONE); assert(err == RADIOLIB_ERR_NONE);
err = lora->setCurrentLimit(currentLimit); err = lora->setCurrentLimit(currentLimit);
assert(err == ERR_NONE); assert(err == RADIOLIB_ERR_NONE);
err = lora->setPreambleLength(preambleLength); err = lora->setPreambleLength(preambleLength);
assert(err == ERR_NONE); assert(err == RADIOLIB_ERR_NONE);
err = lora->setFrequency(getFreq()); err = lora->setFrequency(getFreq());
if (err != ERR_NONE) if (err != RADIOLIB_ERR_NONE)
RECORD_CRITICALERROR(CriticalErrorCode_InvalidRadioSetting); RECORD_CRITICALERROR(CriticalErrorCode_InvalidRadioSetting);
if (power > MAX_POWER) // This chip has lower power limits than some if (power > MAX_POWER) // This chip has lower power limits than some
power = MAX_POWER; power = MAX_POWER;
err = lora->setOutputPower(power); err = lora->setOutputPower(power);
if (err != ERR_NONE) if (err != RADIOLIB_ERR_NONE)
RECORD_CRITICALERROR(CriticalErrorCode_InvalidRadioSetting); RECORD_CRITICALERROR(CriticalErrorCode_InvalidRadioSetting);
startReceive(); // restart receiving startReceive(); // restart receiving
return ERR_NONE; return RADIOLIB_ERR_NONE;
} }
/** /**
@@ -147,7 +147,7 @@ void RF95Interface::addReceiveMetadata(MeshPacket *mp)
void RF95Interface::setStandby() void RF95Interface::setStandby()
{ {
int err = lora->standby(); int err = lora->standby();
assert(err == ERR_NONE); assert(err == RADIOLIB_ERR_NONE);
isReceiving = false; // If we were receiving, not any more isReceiving = false; // If we were receiving, not any more
disableInterrupt(); disableInterrupt();
@@ -168,7 +168,7 @@ void RF95Interface::startReceive()
setTransmitEnable(false); setTransmitEnable(false);
setStandby(); setStandby();
int err = lora->startReceive(); int err = lora->startReceive();
assert(err == ERR_NONE); assert(err == RADIOLIB_ERR_NONE);
isReceiving = true; isReceiving = true;
@@ -176,6 +176,24 @@ void RF95Interface::startReceive()
enableInterrupt(isrRxLevel0); enableInterrupt(isrRxLevel0);
} }
bool RF95Interface::isChannelActive()
{
// check if we can detect a LoRa preamble on the current channel
int16_t result;
setTransmitEnable(false);
setStandby(); // needed for smooth transition
result = lora->scanChannel();
if (result == RADIOLIB_PREAMBLE_DETECTED) {
// DEBUG_MSG("Channel is busy!\n");
return true;
}
assert(result != RADIOLIB_ERR_WRONG_MODEM);
// DEBUG_MSG("Channel is free!\n");
return false;
}
/** Could we send right now (i.e. either not actively receving or transmitting)? */ /** Could we send right now (i.e. either not actively receving or transmitting)? */
bool RF95Interface::isActivelyReceiving() bool RF95Interface::isActivelyReceiving()
{ {

View File

@@ -13,8 +13,9 @@ class RF95Interface : public RadioLibInterface
public: public:
RF95Interface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, SPIClass &spi); RF95Interface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, SPIClass &spi);
bool isIRQPending() override { return lora->getPendingIRQ(); } //TODO: Verify that this irq flag works with RFM95 / SX1276 radios the way it used to
bool isIRQPending() override { return lora->getIRQFlags() & RADIOLIB_SX127X_MASK_IRQ_FLAG_VALID_HEADER; }
/// Initialise the Driver transport hardware and software. /// Initialise the Driver transport hardware and software.
/// Make sure the Driver is properly configured before calling init(). /// Make sure the Driver is properly configured before calling init().
@@ -40,6 +41,9 @@ class RF95Interface : public RadioLibInterface
*/ */
virtual void enableInterrupt(void (*callback)()) { lora->setDio0Action(callback); } virtual void enableInterrupt(void (*callback)()) { lora->setDio0Action(callback); }
/** can we detect a LoRa preamble on the current channel? */
virtual bool isChannelActive() override;
/** are we actively receiving a packet (only called during receiving state) */ /** are we actively receiving a packet (only called during receiving state) */
virtual bool isActivelyReceiving() override; virtual bool isActivelyReceiving() override;

View File

@@ -13,7 +13,8 @@
#define RDEF(name, freq_start, freq_end, duty_cycle, spacing, power_limit, audio_permitted, frequency_switching) \ #define RDEF(name, freq_start, freq_end, duty_cycle, spacing, power_limit, audio_permitted, frequency_switching) \
{ \ { \
RegionCode_##name, freq_start, freq_end, duty_cycle, spacing, power_limit, audio_permitted, frequency_switching, #name \ Config_LoRaConfig_RegionCode_##name, freq_start, freq_end, duty_cycle, spacing, power_limit, audio_permitted, \
frequency_switching, #name \
} }
const RegionInfo regions[] = { const RegionInfo regions[] = {
@@ -76,15 +77,15 @@ const RegionInfo regions[] = {
*/ */
RDEF(IN, 865.0f, 867.0f, 100, 0, 30, true, false), RDEF(IN, 865.0f, 867.0f, 100, 0, 30, true, false),
/* /*
https://rrf.rsm.govt.nz/smart-web/smart/page/-smart/domain/licence/LicenceSummary.wdk?id=219752 https://rrf.rsm.govt.nz/smart-web/smart/page/-smart/domain/licence/LicenceSummary.wdk?id=219752
https://iotalliance.org.nz/wp-content/uploads/sites/4/2019/05/IoT-Spectrum-in-NZ-Briefing-Paper.pdf https://iotalliance.org.nz/wp-content/uploads/sites/4/2019/05/IoT-Spectrum-in-NZ-Briefing-Paper.pdf
*/ */
RDEF(NZ865, 864.0f, 868.0f, 100, 0, 0, true, false), RDEF(NZ865, 864.0f, 868.0f, 100, 0, 0, true, false),
/* /*
https://lora-alliance.org/wp-content/uploads/2020/11/lorawan_regional_parameters_v1.0.3reva_0.pdf https://lora-alliance.org/wp-content/uploads/2020/11/lorawan_regional_parameters_v1.0.3reva_0.pdf
*/ */
RDEF(TH, 920.0f, 925.0f, 100, 0, 16, true, false), RDEF(TH, 920.0f, 925.0f, 100, 0, 16, true, false),
/* /*
@@ -99,10 +100,10 @@ const RegionInfo *myRegion;
void initRegion() void initRegion()
{ {
const RegionInfo *r = regions; const RegionInfo *r = regions;
for (; r->code != RegionCode_Unset && r->code != radioConfig.preferences.region; r++) for (; r->code != Config_LoRaConfig_RegionCode_Unset && r->code != config.lora.region; r++)
; ;
myRegion = r; myRegion = r;
DEBUG_MSG("Wanted region %d, using %s\n", radioConfig.preferences.region, r->name); DEBUG_MSG("Wanted region %d, using %s\n", config.lora.region, r->name);
} }
/** /**
@@ -158,59 +159,53 @@ uint32_t RadioInterface::getPacketTime(MeshPacket *p)
/** The delay to use for retransmitting dropped packets */ /** The delay to use for retransmitting dropped packets */
uint32_t RadioInterface::getRetransmissionMsec(const MeshPacket *p) uint32_t RadioInterface::getRetransmissionMsec(const MeshPacket *p)
{ {
assert(shortPacketMsec); // Better be non zero assert(slotTimeMsec); // Better be non zero
static uint8_t bytes[MAX_RHPACKETLEN];
// was 20 and 22 secs respectively, but now with shortPacketMsec as 2269, this should give the same range size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), Data_fields, &p->decoded);
return random(9 * shortPacketMsec, 10 * shortPacketMsec); uint32_t packetAirtime = getPacketTime(numbytes + sizeof(PacketHeader));
// Make sure enough time has elapsed for this packet to be sent and an ACK is received.
// DEBUG_MSG("Waiting for flooding message with airtime %d and slotTime is %d\n", packetAirtime, slotTimeMsec);
float channelUtil = airTime->channelUtilizationPercent();
uint8_t CWsize = map(channelUtil, 0, 100, CWmin, CWmax);
// Assuming we pick max. of CWsize and there will be a receiver with SNR at half the range
return 2*packetAirtime + (pow(2, CWsize) + pow(2, int((CWmax+CWmin)/2))) * slotTimeMsec + PROCESSING_TIME_MSEC;
} }
/** The delay to use when we want to send something but the ether is busy */ /** The delay to use when we want to send something */
uint32_t RadioInterface::getTxDelayMsec() uint32_t RadioInterface::getTxDelayMsec()
{ {
/** At the low end we want to pick a delay large enough that anyone who just completed sending (some other node) /** We wait a random multiple of 'slotTimes' (see definition in header file) in order to avoid collisions.
* has had enough time to switch their radio back into receive mode. The pool to take a random multiple from is the contention window (CW), which size depends on the
*/ current channel utilization. */
const uint32_t MIN_TX_WAIT_MSEC = 100; float channelUtil = airTime->channelUtilizationPercent();
uint8_t CWsize = map(channelUtil, 0, 100, CWmin, CWmax);
/** // DEBUG_MSG("Current channel utilization is %f so setting CWsize to %d\n", channelUtil, CWsize);
* At the high end, this value is used to spread node attempts across time so when they are replying to a packet return random(0, pow(2, CWsize)) * slotTimeMsec;
* they don't both check that the airwaves are clear at the same moment. As long as they are off by some amount
* one of the two will be first to start transmitting and the other will see that. I bet 500ms is more than enough
* to guarantee this.
*/
// const uint32_t MAX_TX_WAIT_MSEC = 2000; // stress test would still fail occasionally with 1000
return random((MIN_TX_WAIT_MSEC), (MIN_TX_WAIT_MSEC + shortPacketMsec));
} }
/** The delay to use when we want to flood a message */
/** The delay to use when we want to send something but the ether is busy */
uint32_t RadioInterface::getTxDelayMsecWeighted(float snr) uint32_t RadioInterface::getTxDelayMsecWeighted(float snr)
{ {
/** At the low end we want to pick a delay large enough that anyone who just completed sending (some other node)
* has had enough time to switch their radio back into receive mode.
*/
const uint32_t MIN_TX_WAIT_MSEC = 100;
// The minimum value for a LoRa SNR // The minimum value for a LoRa SNR
const uint32_t SNR_MIN = -20; const uint32_t SNR_MIN = -20;
// The maximum value for a LoRa SNR // The maximum value for a LoRa SNR
const uint32_t SNR_MAX = 15; const uint32_t SNR_MAX = 15;
// high SNR = Long Delay // high SNR = large CW size (Long Delay)
// low SNR = Short Delay // low SNR = small CW size (Short Delay)
uint32_t delay = 0; uint32_t delay = 0;
uint8_t CWsize = map(snr, SNR_MIN, SNR_MAX, CWmin, CWmax);
if (radioConfig.preferences.role == Role_Router || radioConfig.preferences.role == Role_RouterClient) { // DEBUG_MSG("rx_snr of %f so setting CWsize to:%d\n", snr, CWsize);
delay = map(snr, SNR_MIN, SNR_MAX, MIN_TX_WAIT_MSEC, (MIN_TX_WAIT_MSEC + (shortPacketMsec / 2))); if (config.device.role == Config_DeviceConfig_Role_Router ||
config.device.role == Config_DeviceConfig_Role_RouterClient) {
delay = random(0, 2*CWsize) * slotTimeMsec;
DEBUG_MSG("rx_snr found in packet. As a router, setting tx delay:%d\n", delay); DEBUG_MSG("rx_snr found in packet. As a router, setting tx delay:%d\n", delay);
} else { } else {
delay = map(snr, SNR_MIN, SNR_MAX, MIN_TX_WAIT_MSEC + (shortPacketMsec / 2), (MIN_TX_WAIT_MSEC + shortPacketMsec * 2)); delay = random(0, pow(2, CWsize)) * slotTimeMsec;
DEBUG_MSG("rx_snr found in packet. Setting tx delay:%d\n", delay); DEBUG_MSG("rx_snr found in packet. Setting tx delay:%d\n", delay);
} }
return delay; return delay;
} }
@@ -251,7 +246,7 @@ void printPacket(const char *prefix, const MeshPacket *p)
DEBUG_MSG(" rxSNR=%g", p->rx_snr); DEBUG_MSG(" rxSNR=%g", p->rx_snr);
} }
if (p->rx_rssi != 0) { if (p->rx_rssi != 0) {
DEBUG_MSG(" rxSNR=%g", p->rx_rssi); DEBUG_MSG(" rxRSSI=%g", p->rx_rssi);
} }
if (p->priority != 0) if (p->priority != 0)
DEBUG_MSG(" priority=%d", p->priority); DEBUG_MSG(" priority=%d", p->priority);
@@ -351,41 +346,41 @@ void RadioInterface::applyModemConfig()
{ {
// Set up default configuration // Set up default configuration
// No Sync Words in LORA mode // No Sync Words in LORA mode
Config_LoRaConfig &loraConfig = config.lora;
auto channelSettings = channels.getPrimary(); auto channelSettings = channels.getPrimary();
if (channelSettings.spread_factor == 0) { if (loraConfig.spread_factor == 0) {
switch (channelSettings.modem_config) { switch (loraConfig.modem_preset) {
case ChannelSettings_ModemConfig_ShortFast: case Config_LoRaConfig_ModemPreset_ShortFast:
bw = 250; bw = 250;
cr = 8; cr = 8;
sf = 7; sf = 7;
break; break;
case ChannelSettings_ModemConfig_ShortSlow: case Config_LoRaConfig_ModemPreset_ShortSlow:
bw = 250; bw = 250;
cr = 8; cr = 8;
sf = 8; sf = 8;
break; break;
case ChannelSettings_ModemConfig_MidFast: case Config_LoRaConfig_ModemPreset_MidFast:
bw = 250; bw = 250;
cr = 8; cr = 8;
sf = 9; sf = 9;
break; break;
case ChannelSettings_ModemConfig_MidSlow: case Config_LoRaConfig_ModemPreset_MidSlow:
bw = 250; bw = 250;
cr = 8; cr = 8;
sf = 10; sf = 10;
break; break;
case ChannelSettings_ModemConfig_LongFast: case Config_LoRaConfig_ModemPreset_LongFast:
bw = 250; bw = 250;
cr = 8; cr = 8;
sf = 11; sf = 11;
break; break;
case ChannelSettings_ModemConfig_LongSlow: case Config_LoRaConfig_ModemPreset_LongSlow:
bw = 125; bw = 125;
cr = 8; cr = 8;
sf = 12; sf = 12;
break; break;
case ChannelSettings_ModemConfig_VLongSlow: case Config_LoRaConfig_ModemPreset_VLongSlow:
bw = 31.25; bw = 31.25;
cr = 8; cr = 8;
sf = 12; sf = 12;
@@ -394,9 +389,9 @@ void RadioInterface::applyModemConfig()
assert(0); // Unknown enum assert(0); // Unknown enum
} }
} else { } else {
sf = channelSettings.spread_factor; sf = loraConfig.spread_factor;
cr = channelSettings.coding_rate; cr = loraConfig.coding_rate;
bw = channelSettings.bandwidth; bw = loraConfig.bandwidth;
if (bw == 31) // This parameter is not an integer if (bw == 31) // This parameter is not an integer
bw = 31.25; bw = 31.25;
@@ -404,10 +399,15 @@ void RadioInterface::applyModemConfig()
bw = 62.5; bw = 62.5;
} }
power = channelSettings.tx_power; power = loraConfig.tx_power;
shortPacketMsec = getPacketTime(sizeof(PacketHeader));
assert(myRegion); // Should have been found in init assert(myRegion); // Should have been found in init
if ((power == 0) || (power > myRegion->powerLimit))
power = myRegion->powerLimit;
if (power == 0)
power = 17; // Default to default power if we don't have a valid power
// Calculate the number of channels // Calculate the number of channels
uint32_t numChannels = floor((myRegion->freqEnd - myRegion->freqStart) / (myRegion->spacing + (bw / 1000))); uint32_t numChannels = floor((myRegion->freqEnd - myRegion->freqStart) / (myRegion->spacing + (bw / 1000)));
@@ -419,13 +419,13 @@ void RadioInterface::applyModemConfig()
saveChannelNum(channel_num); saveChannelNum(channel_num);
saveFreq(freq); saveFreq(freq);
DEBUG_MSG("Set radio: name=%s, config=%u, ch=%d, power=%d\n", channelName, channelSettings.modem_config, channel_num, power); DEBUG_MSG("Set radio: name=%s, config=%u, ch=%d, power=%d\n", channelName, loraConfig.modem_preset, channel_num, power);
DEBUG_MSG("Radio myRegion->freqStart / myRegion->freqEnd: %f -> %f (%f mhz)\n", myRegion->freqStart, myRegion->freqEnd, DEBUG_MSG("Radio myRegion->freqStart / myRegion->freqEnd: %f -> %f (%f mhz)\n", myRegion->freqStart, myRegion->freqEnd,
myRegion->freqEnd - myRegion->freqStart); myRegion->freqEnd - myRegion->freqStart);
DEBUG_MSG("Radio myRegion->numChannels: %d\n", numChannels); DEBUG_MSG("Radio myRegion->numChannels: %d\n", numChannels);
DEBUG_MSG("Radio channel_num: %d\n", channel_num); DEBUG_MSG("Radio channel_num: %d\n", channel_num);
DEBUG_MSG("Radio frequency: %f\n", getFreq()); DEBUG_MSG("Radio frequency: %f\n", getFreq());
DEBUG_MSG("Short packet time: %u msec\n", shortPacketMsec); DEBUG_MSG("Slot time: %u msec\n", slotTimeMsec);
} }
/** /**

View File

@@ -52,8 +52,6 @@ class RadioInterface
CallbackObserver<RadioInterface, void *> notifyDeepSleepObserver = CallbackObserver<RadioInterface, void *> notifyDeepSleepObserver =
CallbackObserver<RadioInterface, void *>(this, &RadioInterface::notifyDeepSleepCb); CallbackObserver<RadioInterface, void *>(this, &RadioInterface::notifyDeepSleepCb);
/// Number of msecs we expect our shortest actual packet to be over the wire (used in retry timeout calcs)
uint32_t shortPacketMsec;
protected: protected:
bool disabled = false; bool disabled = false;
@@ -61,8 +59,16 @@ class RadioInterface
float bw = 125; float bw = 125;
uint8_t sf = 9; uint8_t sf = 9;
uint8_t cr = 7; uint8_t cr = 7;
/** Slottime is the minimum time to wait, consisting of:
- CAD duration (maximum of SX126x and SX127x);
- roundtrip air propagation time (assuming max. 30km between nodes);
- Tx/Rx turnaround time (maximum of SX126x and SX127x);
- MAC processing time (measured on T-beam) */
uint32_t slotTimeMsec = 8.5 * pow(2, sf)/bw + 0.2 + 0.4 + 7;
uint16_t preambleLength = 32; // 8 is default, but we use longer to increase the amount of sleep time when receiving uint16_t preambleLength = 32; // 8 is default, but we use longer to increase the amount of sleep time when receiving
const uint32_t PROCESSING_TIME_MSEC = 4500; // time to construct, process and construct a packet again (empirically determined)
const uint8_t CWmin = 2; // minimum CWsize
const uint8_t CWmax = 8; // maximum CWsize
MeshPacket *sendingPacket = NULL; // The packet we are currently sending MeshPacket *sendingPacket = NULL; // The packet we are currently sending
uint32_t lastTxStart = 0L; uint32_t lastTxStart = 0L;
@@ -126,10 +132,10 @@ class RadioInterface
/** The delay to use for retransmitting dropped packets */ /** The delay to use for retransmitting dropped packets */
uint32_t getRetransmissionMsec(const MeshPacket *p); uint32_t getRetransmissionMsec(const MeshPacket *p);
/** The delay to use when we want to send something but the ether is busy */ /** The delay to use when we want to send something */
uint32_t getTxDelayMsec(); uint32_t getTxDelayMsec();
/** The delay to use when we want to send something but the ether is busy. Use a weighted scale based on SNR */ /** The delay to use when we want to flood a message. Use a weighted scale based on SNR */
uint32_t getTxDelayMsecWeighted(float snr); uint32_t getTxDelayMsecWeighted(float snr);

View File

@@ -11,6 +11,8 @@
// FIXME, we default to 4MHz SPI, SPI mode 0, check if the datasheet says it can really do that // FIXME, we default to 4MHz SPI, SPI mode 0, check if the datasheet says it can really do that
static SPISettings spiSettings(4000000, MSBFIRST, SPI_MODE0); static SPISettings spiSettings(4000000, MSBFIRST, SPI_MODE0);
#ifdef PORTDUINO
void LockingModule::SPItransfer(uint8_t cmd, uint8_t reg, uint8_t *dataOut, uint8_t *dataIn, uint8_t numBytes) void LockingModule::SPItransfer(uint8_t cmd, uint8_t reg, uint8_t *dataOut, uint8_t *dataIn, uint8_t numBytes)
{ {
concurrency::LockGuard g(spiLock); concurrency::LockGuard g(spiLock);
@@ -18,6 +20,24 @@ void LockingModule::SPItransfer(uint8_t cmd, uint8_t reg, uint8_t *dataOut, uint
Module::SPItransfer(cmd, reg, dataOut, dataIn, numBytes); Module::SPItransfer(cmd, reg, dataOut, dataIn, numBytes);
} }
#else
void LockingModule::SPIbeginTransaction()
{
spiLock->lock();
Module::SPIbeginTransaction();
}
void LockingModule::SPIendTransaction()
{
spiLock->unlock();
Module::SPIendTransaction();
}
#endif
RadioLibInterface::RadioLibInterface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy, RadioLibInterface::RadioLibInterface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy,
SPIClass &spi, PhysicalLayer *_iface) SPIClass &spi, PhysicalLayer *_iface)
: NotifiedWorkerThread("RadioIf"), module(cs, irq, rst, busy, spi, spiSettings), iface(_iface) : NotifiedWorkerThread("RadioIf"), module(cs, irq, rst, busy, spi, spiSettings), iface(_iface)
@@ -93,262 +113,291 @@ bool RadioLibInterface::canSendImmediately()
/// bluetooth comms code. If the txmit queue is empty it might return an error /// bluetooth comms code. If the txmit queue is empty it might return an error
ErrorCode RadioLibInterface::send(MeshPacket *p) ErrorCode RadioLibInterface::send(MeshPacket *p)
{ {
if (radioConfig.preferences.region != RegionCode_Unset) {
if (disabled || radioConfig.preferences.is_lora_tx_disabled) {
DEBUG_MSG("send - lora_tx_disabled\n");
packetPool.release(p);
return ERRNO_DISABLED;
}
} else { #ifndef DISABLE_WELCOME_UNSET
DEBUG_MSG("send - lora_tx_disabled because RegionCode_Unset\n");
if (config.lora.region != Config_LoRaConfig_RegionCode_Unset) {
if (disabled || config.lora.tx_disabled) {
if (config.lora.region != Config_LoRaConfig_RegionCode_Unset) {
if (disabled || config.lora.tx_disabled) {
DEBUG_MSG("send - lora_tx_disabled\n");
packetPool.release(p);
return ERRNO_DISABLED;
}
} else {
DEBUG_MSG("send - lora_tx_disabled because RegionCode_Unset\n");
packetPool.release(p);
return ERRNO_DISABLED;
}
}
}
#else
if (disabled || config.lora.tx_disabled) {
DEBUG_MSG("send - lora_tx_disabled\n");
packetPool.release(p); packetPool.release(p);
return ERRNO_DISABLED; return ERRNO_DISABLED;
} }
// Sometimes when testing it is useful to be able to never turn on the xmitter #endif
// Sometimes when testing it is useful to be able to never turn on the xmitter
#ifndef LORA_DISABLE_SENDING #ifndef LORA_DISABLE_SENDING
printPacket("enqueuing for send", p); printPacket("enqueuing for send", p);
DEBUG_MSG("txGood=%d,rxGood=%d,rxBad=%d\n", txGood, rxGood, rxBad); DEBUG_MSG("txGood=%d,rxGood=%d,rxBad=%d\n", txGood, rxGood, rxBad);
ErrorCode res = txQueue.enqueue(p) ? ERRNO_OK : ERRNO_UNKNOWN; 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();
if (res != ERRNO_OK) { // we weren't able to queue it, so we must drop it to prevent leaks
packetPool.release(p);
return res; return res;
}
// 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 not 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);
}
return res;
#else #else
packetPool.release(p); packetPool.release(p);
return ERRNO_DISABLED; return ERRNO_DISABLED;
#endif #endif
} }
bool RadioLibInterface::canSleep() bool RadioLibInterface::canSleep()
{ {
bool res = txQueue.empty(); bool res = txQueue.empty();
if (!res) // only print debug messages if we are vetoing sleep if (!res) // only print debug messages if we are vetoing sleep
DEBUG_MSG("radio wait to sleep, txEmpty=%d\n", res); DEBUG_MSG("radio wait to sleep, txEmpty=%d\n", res);
return res; return res;
} }
/** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */ /** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */
bool RadioLibInterface::cancelSending(NodeNum from, PacketId id) bool RadioLibInterface::cancelSending(NodeNum from, PacketId id)
{ {
auto p = txQueue.remove(from, id); auto p = txQueue.remove(from, id);
if (p) if (p)
packetPool.release(p); // free the packet we just removed packetPool.release(p); // free the packet we just removed
bool result = (p != NULL); bool result = (p != NULL);
DEBUG_MSG("cancelSending id=0x%x, removed=%d\n", id, result); DEBUG_MSG("cancelSending id=0x%x, removed=%d\n", id, result);
return result; return result;
} }
/** radio helper thread callback. /** radio helper thread callback.
We never immediately transmit after any operation (either Rx or Tx). Instead we should wait a random multiple of
'slotTimes' (see definition in RadioInterface.h) taken from a contention window (CW) to lower the chance of collision.
The CW size is determined by setTransmitDelay() and depends either on the current channel utilization or SNR in case
of a flooding message. After this, we perform channel activity detection (CAD) and reset the transmit delay if it is
currently active.
*/
void RadioLibInterface::onNotify(uint32_t notification)
{
switch (notification) {
case ISR_TX:
handleTransmitInterrupt();
startReceive();
// DEBUG_MSG("tx complete - starting timer\n");
startTransmitTimer();
break;
case ISR_RX:
handleReceiveInterrupt();
startReceive();
// DEBUG_MSG("rx complete - starting timer\n");
startTransmitTimer();
break;
case TRANSMIT_DELAY_COMPLETED:
// DEBUG_MSG("delay done\n");
We never immediately transmit after any operation (either rx or tx). Instead we should start receiving and // If we are not currently in receive mode, then restart the random delay (this can happen if the main thread
wait a random delay of 50 to 200 ms to make sure we are not stomping on someone else. The 50ms delay at the beginning ensures all // has placed the unit into standby) FIXME, how will this work if the chipset is in sleep mode?
possible listeners have had time to finish processing the previous packet and now have their radio in RX state. The up to 200ms if (!txQueue.empty()) {
random delay gives a chance for all possible senders to have high odds of detecting that someone else started transmitting first if (!canSendImmediately()) {
and then they will wait until that packet finishes. // 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);
NOTE: the large flood rebroadcast delay might still be needed even with this approach. Because we might not be able to hear other // Packet has been sent, count it toward our TX airtime utilization.
transmitters that we are potentially stomping on. Requires further thought. uint32_t xmitMsec = getPacketTime(txp);
airTime->logAirtime(TX_LOG, xmitMsec);
FIXME, the MIN_TX_WAIT_MSEC and MAX_TX_WAIT_MSEC values should be tuned via logic analyzer later. }
*/ }
void RadioLibInterface::onNotify(uint32_t notification)
{
switch (notification) {
case ISR_TX:
handleTransmitInterrupt();
startReceive();
// DEBUG_MSG("tx complete - starting timer\n");
startTransmitTimer();
break;
case ISR_RX:
handleReceiveInterrupt();
startReceive();
// DEBUG_MSG("rx complete - starting timer\n");
startTransmitTimer();
break;
case TRANSMIT_DELAY_COMPLETED:
// DEBUG_MSG("delay done\n");
// If we are not currently in receive mode, then restart the timer and try again later (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()) {
startTransmitTimer(); // try again in a little while
} else { } else {
// Send any outgoing packets we have ready // DEBUG_MSG("done with txqueue\n");
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);
} }
} else { break;
// DEBUG_MSG("done with txqueue\n"); default:
} assert(0); // We expected to receive a valid notification from the ISR
break;
default:
assert(0); // We expected to receive a valid notification from the ISR
}
}
void RadioLibInterface::startTransmitTimer(bool withDelay)
{
// If we have work to do and the timer wasn't already scheduled, schedule it now
if (!txQueue.empty()) {
uint32_t delay = !withDelay ? 1 : getTxDelayMsec();
// DEBUG_MSG("xmit timer %d\n", delay);
notifyLater(delay, TRANSMIT_DELAY_COMPLETED, false); // This will implicitly enable
}
}
void RadioLibInterface::startTransmitTimerSNR(float snr)
{
// If we have work to do and the timer wasn't already scheduled, schedule it now
if (!txQueue.empty()) {
uint32_t delay = getTxDelayMsecWeighted(snr);
// DEBUG_MSG("xmit timer %d\n", delay);
notifyLater(delay, TRANSMIT_DELAY_COMPLETED, false); // This will implicitly enable
}
}
void RadioLibInterface::handleTransmitInterrupt()
{
// DEBUG_MSG("handling lora TX interrupt\n");
// This can be null if we forced the device to enter standby mode. In that case
// ignore the transmit interrupt
if (sendingPacket)
completeSending();
}
void RadioLibInterface::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");
}
}
void RadioLibInterface::handleReceiveInterrupt()
{
uint32_t xmitMsec;
assert(isReceiving);
isReceiving = false;
// read the number of actually received bytes
size_t length = iface->getPacketLength();
xmitMsec = getPacketTime(length);
int state = iface->readData(radiobuf, length);
if (state != ERR_NONE) {
DEBUG_MSG("ignoring received packet due to error=%d\n", state);
rxBad++;
airTime->logAirtime(RX_ALL_LOG, xmitMsec);
} else {
// Skip the 4 headers that are at the beginning of the rxBuf
int32_t payloadLen = length - sizeof(PacketHeader);
const uint8_t *payload = radiobuf + sizeof(PacketHeader);
// check for short packets
if (payloadLen < 0) {
DEBUG_MSG("ignoring received packet too short\n");
rxBad++;
airTime->logAirtime(RX_ALL_LOG, xmitMsec);
} else {
const PacketHeader *h = (PacketHeader *)radiobuf;
rxGood++;
// Note: we deliver _all_ packets to our router (i.e. our interface is intentionally promiscuous).
// This allows the router and other apps on our node to sniff packets (usually routing) between other
// nodes.
MeshPacket *mp = packetPool.allocZeroed();
mp->from = h->from;
mp->to = h->to;
mp->id = h->id;
mp->channel = h->channel;
assert(HOP_MAX <= PACKET_FLAGS_HOP_MASK); // If hopmax changes, carefully check this code
mp->hop_limit = h->flags & PACKET_FLAGS_HOP_MASK;
mp->want_ack = !!(h->flags & PACKET_FLAGS_WANT_ACK_MASK);
addReceiveMetadata(mp);
mp->which_payloadVariant = MeshPacket_encrypted_tag; // Mark that the payload is still encrypted at this point
assert(((uint32_t)payloadLen) <= sizeof(mp->encrypted.bytes));
memcpy(mp->encrypted.bytes, payload, payloadLen);
mp->encrypted.size = payloadLen;
printPacket("Lora RX", mp);
// xmitMsec = getPacketTime(mp);
airTime->logAirtime(RX_LOG, xmitMsec);
deliverToReceiver(mp);
} }
} }
}
/** start an immediate transmit */ void RadioLibInterface::setTransmitDelay()
void RadioLibInterface::startSend(MeshPacket *txp) {
{ MeshPacket *p = txQueue.getFront();
printPacket("Starting low level send", txp); // We want all sending/receiving to be done by our daemon thread.
if (disabled || radioConfig.preferences.is_lora_tx_disabled) { // We use a delay here because this packet might have been sent in response to a packet we just received.
DEBUG_MSG("startSend is dropping tx packet because we are disabled\n"); // So we want to make sure the other side has had a chance to reconfigure its radio.
packetPool.release(txp);
} else {
setStandby(); // Cancel any already in process receives
configHardwareForSend(); // must be after setStandby /* 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);
}
}
size_t numbytes = beginSending(txp); void RadioLibInterface::startTransmitTimer(bool withDelay)
{
// If we have work to do and the timer wasn't already scheduled, schedule it now
if (!txQueue.empty()) {
uint32_t delay = !withDelay ? 1 : getTxDelayMsec();
// DEBUG_MSG("xmit timer %d\n", delay);
notifyLater(delay, TRANSMIT_DELAY_COMPLETED, false); // This will implicitly enable
}
}
int res = iface->startTransmit(radiobuf, numbytes); void RadioLibInterface::startTransmitTimerSNR(float snr)
if (res != ERR_NONE) { {
RECORD_CRITICALERROR(CriticalErrorCode_RadioSpiBug); // If we have work to do and the timer wasn't already scheduled, schedule it now
if (!txQueue.empty()) {
uint32_t delay = getTxDelayMsecWeighted(snr);
// DEBUG_MSG("xmit timer %d\n", delay);
notifyLater(delay, TRANSMIT_DELAY_COMPLETED, false); // This will implicitly enable
}
}
// This send failed, but make sure to 'complete' it properly void RadioLibInterface::handleTransmitInterrupt()
{
// DEBUG_MSG("handling lora TX interrupt\n");
// This can be null if we forced the device to enter standby mode. In that case
// ignore the transmit interrupt
if (sendingPacket)
completeSending(); completeSending();
startReceive(); // Restart receive mode (because startTransmit failed to put us in xmit mode)
}
// Must be done AFTER, starting transmit, because startTransmit clears (possibly stale) interrupt pending register bits
enableInterrupt(isrTxLevel0);
} }
}
void RadioLibInterface::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");
}
}
void RadioLibInterface::handleReceiveInterrupt()
{
uint32_t xmitMsec;
assert(isReceiving);
isReceiving = false;
// read the number of actually received bytes
size_t length = iface->getPacketLength();
xmitMsec = getPacketTime(length);
int state = iface->readData(radiobuf, length);
if (state != RADIOLIB_ERR_NONE) {
DEBUG_MSG("ignoring received packet due to error=%d\n", state);
rxBad++;
airTime->logAirtime(RX_ALL_LOG, xmitMsec);
} else {
// Skip the 4 headers that are at the beginning of the rxBuf
int32_t payloadLen = length - sizeof(PacketHeader);
const uint8_t *payload = radiobuf + sizeof(PacketHeader);
// check for short packets
if (payloadLen < 0) {
DEBUG_MSG("ignoring received packet too short\n");
rxBad++;
airTime->logAirtime(RX_ALL_LOG, xmitMsec);
} else {
const PacketHeader *h = (PacketHeader *)radiobuf;
rxGood++;
// Note: we deliver _all_ packets to our router (i.e. our interface is intentionally promiscuous).
// This allows the router and other apps on our node to sniff packets (usually routing) between other
// nodes.
MeshPacket *mp = packetPool.allocZeroed();
mp->from = h->from;
mp->to = h->to;
mp->id = h->id;
mp->channel = h->channel;
assert(HOP_MAX <= PACKET_FLAGS_HOP_MASK); // If hopmax changes, carefully check this code
mp->hop_limit = h->flags & PACKET_FLAGS_HOP_MASK;
mp->want_ack = !!(h->flags & PACKET_FLAGS_WANT_ACK_MASK);
addReceiveMetadata(mp);
mp->which_payloadVariant = MeshPacket_encrypted_tag; // Mark that the payload is still encrypted at this point
assert(((uint32_t)payloadLen) <= sizeof(mp->encrypted.bytes));
memcpy(mp->encrypted.bytes, payload, payloadLen);
mp->encrypted.size = payloadLen;
printPacket("Lora RX", mp);
// xmitMsec = getPacketTime(mp);
airTime->logAirtime(RX_LOG, xmitMsec);
deliverToReceiver(mp);
}
}
}
/** start an immediate transmit */
void RadioLibInterface::startSend(MeshPacket * txp)
{
printPacket("Starting low level send", txp);
if (disabled || config.lora.tx_disabled) {
DEBUG_MSG("startSend is dropping tx packet because we are disabled\n");
packetPool.release(txp);
} else {
setStandby(); // Cancel any already in process receives
configHardwareForSend(); // must be after setStandby
size_t numbytes = beginSending(txp);
int res = iface->startTransmit(radiobuf, numbytes);
if (res != RADIOLIB_ERR_NONE) {
RECORD_CRITICALERROR(CriticalErrorCode_RadioSpiBug);
// This send failed, but make sure to 'complete' it properly
completeSending();
startReceive(); // Restart receive mode (because startTransmit failed to put us in xmit mode)
}
// Must be done AFTER, starting transmit, because startTransmit clears (possibly stale) interrupt pending register
// bits
enableInterrupt(isrTxLevel0);
}
}

View File

@@ -40,21 +40,13 @@ class LockingModule : public Module
: Module(cs, irq, rst, gpio, spi, spiSettings) : Module(cs, irq, rst, gpio, spi, spiSettings)
{ {
} }
/*! #ifdef PORTDUINO
\brief SPI single transfer method. void SPItransfer(uint8_t cmd, uint8_t reg, uint8_t *dataOut, uint8_t *dataIn, uint8_t numBytes) override;
#else
\param cmd SPI access command (read/write/burst/...). void SPIbeginTransaction() override;
void SPIendTransaction() override;
\param reg Address of SPI register to transfer to/from. #endif
\param dataOut Data that will be transfered from master to slave.
\param dataIn Data that was transfered from slave to master.
\param numBytes Number of bytes to transfer.
*/
virtual void SPItransfer(uint8_t cmd, uint8_t reg, uint8_t *dataOut, uint8_t *dataIn, uint8_t numBytes) override;
}; };
class RadioLibInterface : public RadioInterface, protected concurrency::NotifiedWorkerThread class RadioLibInterface : public RadioInterface, protected concurrency::NotifiedWorkerThread
@@ -132,6 +124,9 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified
*/ */
virtual void startReceive() = 0; virtual void startReceive() = 0;
/** can we detect a LoRa preamble on the current channel? */
virtual bool isChannelActive() = 0;
/** are we actively receiving a packet (only called during receiving state) /** are we actively receiving a packet (only called during receiving state)
* This method is only public to facilitate debugging. Do not call. * This method is only public to facilitate debugging. Do not call.
*/ */
@@ -141,18 +136,14 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified
virtual bool cancelSending(NodeNum from, PacketId id) override; virtual bool cancelSending(NodeNum from, PacketId id) override;
private: private:
/** if we have something waiting to send, start a short random timer so we can come check for collision before actually doing /** if we have something waiting to send, start a short (random) timer so we can come check for collision before actually doing
* the transmit * the transmit */
* void setTransmitDelay();
* If the timer was already running, we just wait for that one to occur.
* */ /** random timer with certain min. and max. settings */
void startTransmitTimer(bool withDelay = true); void startTransmitTimer(bool withDelay = true);
/** if we have something waiting to send, start a short scaled timer based on SNR so we can come check for collision before actually doing /** timer scaled to SNR of to be flooded packet */
* the transmit
*
* If the timer was already running, we just wait for that one to occur.
* */
void startTransmitTimerSNR(float snr); void startTransmitTimerSNR(float snr);
void handleTransmitInterrupt(); void handleTransmitInterrupt();

View File

@@ -15,7 +15,7 @@ int16_t RadioLibRF95::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_
{ {
// execute common part // execute common part
int16_t state = SX127x::begin(RF95_CHIP_VERSION, syncWord, preambleLength); int16_t state = SX127x::begin(RF95_CHIP_VERSION, syncWord, preambleLength);
if (state != ERR_NONE) if (state != RADIOLIB_ERR_NONE)
state = SX127x::begin(RF95_ALT_VERSION, syncWord, preambleLength); state = SX127x::begin(RF95_ALT_VERSION, syncWord, preambleLength);
RADIOLIB_ASSERT(state); RADIOLIB_ASSERT(state);
@@ -30,7 +30,7 @@ int16_t RadioLibRF95::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_
RADIOLIB_ASSERT(state); RADIOLIB_ASSERT(state);
#ifdef RF95_TCXO #ifdef RF95_TCXO
state = _mod->SPIsetRegValue(SX127X_REG_TCXO, 0x10 | _mod->SPIgetRegValue(SX127X_REG_TCXO)); state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_TCXO, 0x10 | _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_TCXO));
RADIOLIB_ASSERT(state); RADIOLIB_ASSERT(state);
#endif #endif
@@ -72,7 +72,7 @@ int16_t RadioLibRF95::setFrequency(float freq)
bool RadioLibRF95::isReceiving() bool RadioLibRF95::isReceiving()
{ {
// 0x0b == Look for header info valid, signal synchronized or signal detected // 0x0b == Look for header info valid, signal synchronized or signal detected
uint8_t reg = readReg(SX127X_REG_MODEM_STAT); uint8_t reg = readReg(RADIOLIB_SX127X_REG_MODEM_STAT);
// Serial.printf("reg %x\n", reg); // Serial.printf("reg %x\n", reg);
return (reg & (RH_RF95_MODEM_STATUS_SIGNAL_DETECTED | RH_RF95_MODEM_STATUS_SIGNAL_SYNCHRONIZED | return (reg & (RH_RF95_MODEM_STATUS_SIGNAL_DETECTED | RH_RF95_MODEM_STATUS_SIGNAL_SYNCHRONIZED |
RH_RF95_MODEM_STATUS_HEADER_INFO_VALID)) != 0; RH_RF95_MODEM_STATUS_HEADER_INFO_VALID)) != 0;

View File

@@ -43,7 +43,7 @@ class RadioLibRF95: public SX1278 {
\returns \ref status_codes \returns \ref status_codes
*/ */
int16_t begin(float freq = 915.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = SX127X_SYNC_WORD, int8_t power = 17, uint16_t preambleLength = 8, uint8_t gain = 0); int16_t begin(float freq = 915.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX127X_SYNC_WORD, int8_t power = 17, uint16_t preambleLength = 8, uint8_t gain = 0);
// configuration methods // configuration methods

View File

@@ -1,7 +1,7 @@
#include "configuration.h"
#include "ReliableRouter.h" #include "ReliableRouter.h"
#include "MeshModule.h" #include "MeshModule.h"
#include "MeshTypes.h" #include "MeshTypes.h"
#include "configuration.h"
#include "mesh-pb-constants.h" #include "mesh-pb-constants.h"
// ReliableRouter::ReliableRouter() {} // ReliableRouter::ReliableRouter() {}
@@ -14,11 +14,11 @@ ErrorCode ReliableRouter::send(MeshPacket *p)
{ {
if (p->want_ack) { if (p->want_ack) {
// If someone asks for acks on broadcast, we need the hop limit to be at least one, so that first node that receives our // If someone asks for acks on broadcast, we need the hop limit to be at least one, so that first node that receives our
// message will rebroadcast. But asking for hop_limit 0 in that context means the client app has no preference on hop counts // message will rebroadcast. But asking for hop_limit 0 in that context means the client app has no preference on hop
// and we want this message to get through the whole mesh, so use the default. // counts and we want this message to get through the whole mesh, so use the default.
if (p->to == NODENUM_BROADCAST && p->hop_limit == 0) { if (p->to == NODENUM_BROADCAST && p->hop_limit == 0) {
if (radioConfig.preferences.hop_limit && radioConfig.preferences.hop_limit <= HOP_MAX) { if (config.lora.hop_limit && config.lora.hop_limit <= HOP_MAX) {
p->hop_limit = (radioConfig.preferences.hop_limit >= HOP_MAX) ? HOP_MAX : radioConfig.preferences.hop_limit; p->hop_limit = (config.lora.hop_limit >= HOP_MAX) ? HOP_MAX : config.lora.hop_limit;
} else { } else {
p->hop_limit = HOP_RELIABLE; p->hop_limit = HOP_RELIABLE;
} }
@@ -41,9 +41,9 @@ bool ReliableRouter::shouldFilterReceived(MeshPacket *p)
// If this is the first time we saw this, cancel any retransmissions we have queued up and generate an internal ack for // If this is the first time we saw this, cancel any retransmissions we have queued up and generate an internal ack for
// the original sending process. // the original sending process.
// FIXME - we might want to turn off this "optimization", it does save lots of airtime but it assumes that once we've heard one // FIXME - we might want to turn off this "optimization", it does save lots of airtime but it assumes that once we've
// one adjacent node hear our packet that a) probably other adjacent nodes heard it and b) we can trust those nodes to reach // heard one one adjacent node hear our packet that a) probably other adjacent nodes heard it and b) we can trust those
// our destination. Both of which might be incorrect. // nodes to reach our destination. Both of which might be incorrect.
auto key = GlobalPacketId(getFrom(p), p->id); auto key = GlobalPacketId(getFrom(p), p->id);
auto old = findPendingPacket(key); auto old = findPendingPacket(key);
if (old) { if (old) {
@@ -53,8 +53,7 @@ bool ReliableRouter::shouldFilterReceived(MeshPacket *p)
sendAckNak(Routing_Error_NONE, getFrom(p), p->id, old->packet->channel); sendAckNak(Routing_Error_NONE, getFrom(p), p->id, old->packet->channel);
stopRetransmission(key); stopRetransmission(key);
} } else {
else {
DEBUG_MSG("didn't find pending packet\n"); DEBUG_MSG("didn't find pending packet\n");
} }
} }
@@ -151,7 +150,7 @@ bool ReliableRouter::stopRetransmission(GlobalPacketId key)
if (old) { if (old) {
auto numErased = pending.erase(key); auto numErased = pending.erase(key);
assert(numErased == 1); assert(numErased == 1);
packetPool.release(old->packet); cancelSending(getFrom(old->packet), old->packet->id);
return true; return true;
} else } else
return false; return false;

View File

@@ -1,12 +1,15 @@
#include "configuration.h"
#include "Router.h" #include "Router.h"
#include "Channels.h" #include "Channels.h"
#include "CryptoEngine.h" #include "CryptoEngine.h"
#include "NodeDB.h" #include "NodeDB.h"
#include "RTC.h" #include "RTC.h"
#include "configuration.h"
#include "main.h" #include "main.h"
#include "mesh-pb-constants.h" #include "mesh-pb-constants.h"
#include "modules/RoutingModule.h" #include "modules/RoutingModule.h"
extern "C" {
#include "mesh/compression/unishox2.h"
}
#if defined(HAS_WIFI) || defined(PORTDUINO) #if defined(HAS_WIFI) || defined(PORTDUINO)
#include "mqtt/MQTT.h" #include "mqtt/MQTT.h"
@@ -115,8 +118,8 @@ MeshPacket *Router::allocForSending()
p->which_payloadVariant = MeshPacket_decoded_tag; // Assume payload is decoded at start. p->which_payloadVariant = MeshPacket_decoded_tag; // Assume payload is decoded at start.
p->from = nodeDB.getNodeNum(); p->from = nodeDB.getNodeNum();
p->to = NODENUM_BROADCAST; p->to = NODENUM_BROADCAST;
if (radioConfig.preferences.hop_limit && radioConfig.preferences.hop_limit <= HOP_MAX) { if (config.lora.hop_limit && config.lora.hop_limit <= HOP_MAX) {
p->hop_limit = (radioConfig.preferences.hop_limit >= HOP_MAX) ? HOP_MAX : radioConfig.preferences.hop_limit; p->hop_limit = (config.lora.hop_limit >= HOP_MAX) ? HOP_MAX : config.lora.hop_limit;
} else { } else {
p->hop_limit = HOP_RELIABLE; p->hop_limit = HOP_RELIABLE;
} }
@@ -210,29 +213,27 @@ ErrorCode Router::send(MeshPacket *p)
if (p->which_payloadVariant == MeshPacket_decoded_tag) { if (p->which_payloadVariant == MeshPacket_decoded_tag) {
ChannelIndex chIndex = p->channel; // keep as a local because we are about to change it ChannelIndex chIndex = p->channel; // keep as a local because we are about to change it
#if defined(HAS_WIFI) || defined(PORTDUINO) #if defined(HAS_WIFI) || defined(PORTDUINO)
//check if we should send decrypted packets to mqtt // check if we should send decrypted packets to mqtt
//truth table: // truth table:
/* mqtt_server mqtt_encryption_enabled should_encrypt /* mqtt_server mqtt_encryption_enabled should_encrypt
* not set 0 1 * not set 0 1
* not set 1 1 * not set 1 1
* set 0 0 * set 0 0
* set 1 1 * set 1 1
* *
* => so we only decrypt mqtt if they have a custom mqtt server AND mqtt_encryption_enabled is FALSE * => so we only decrypt mqtt if they have a custom mqtt server AND mqtt_encryption_enabled is FALSE
*/ */
bool shouldActuallyEncrypt = true; bool shouldActuallyEncrypt = true;
if (*radioConfig.preferences.mqtt_server && !radioConfig.preferences.mqtt_encryption_enabled) { if (*moduleConfig.mqtt.address && !moduleConfig.mqtt.encryption_enabled) {
shouldActuallyEncrypt = false; shouldActuallyEncrypt = false;
} }
DEBUG_MSG("Should encrypt MQTT?: %d\n", shouldActuallyEncrypt); DEBUG_MSG("Should encrypt MQTT?: %d\n", shouldActuallyEncrypt);
//the packet is currently in a decrypted state. send it now if they want decrypted packets // the packet is currently in a decrypted state. send it now if they want decrypted packets
if (mqtt && !shouldActuallyEncrypt) if (mqtt && !shouldActuallyEncrypt)
mqtt->onSend(*p, chIndex); mqtt->onSend(*p, chIndex);
#endif #endif
@@ -244,8 +245,8 @@ ErrorCode Router::send(MeshPacket *p)
} }
#if defined(HAS_WIFI) || defined(PORTDUINO) #if defined(HAS_WIFI) || defined(PORTDUINO)
//the packet is now encrypted. // the packet is now encrypted.
//check if we should send encrypted packets to mqtt // check if we should send encrypted packets to mqtt
if (mqtt && shouldActuallyEncrypt) if (mqtt && shouldActuallyEncrypt)
mqtt->onSend(*p, chIndex); mqtt->onSend(*p, chIndex);
#endif #endif
@@ -273,10 +274,13 @@ void Router::sniffReceived(const MeshPacket *p, const Routing *c)
bool perhapsDecode(MeshPacket *p) bool perhapsDecode(MeshPacket *p)
{ {
// DEBUG_MSG("\n\n** perhapsDecode payloadVariant - %d\n\n", p->which_payloadVariant);
if (p->which_payloadVariant == MeshPacket_decoded_tag) if (p->which_payloadVariant == MeshPacket_decoded_tag)
return true; // If packet was already decoded just return return true; // If packet was already decoded just return
//assert(p->which_payloadVariant == MeshPacket_encrypted_tag); // assert(p->which_payloadVariant == MeshPacket_encrypted_tag);
// Try to find a channel that works with this hash // Try to find a channel that works with this hash
for (ChannelIndex chIndex = 0; chIndex < channels.getNumChannels(); chIndex++) { for (ChannelIndex chIndex = 0; chIndex < channels.getNumChannels(); chIndex++) {
@@ -302,6 +306,34 @@ bool perhapsDecode(MeshPacket *p)
// parsing was successful // parsing was successful
p->which_payloadVariant = MeshPacket_decoded_tag; // change type to decoded p->which_payloadVariant = MeshPacket_decoded_tag; // change type to decoded
p->channel = chIndex; // change to store the index instead of the hash p->channel = chIndex; // change to store the index instead of the hash
/*
if (p->decoded.portnum == PortNum_TEXT_MESSAGE_APP) {
DEBUG_MSG("\n\n** TEXT_MESSAGE_APP\n");
} else if (p->decoded.portnum == PortNum_TEXT_MESSAGE_COMPRESSED_APP) {
DEBUG_MSG("\n\n** PortNum_TEXT_MESSAGE_COMPRESSED_APP\n");
}
*/
// Decompress if needed. jm
if (p->decoded.portnum == PortNum_TEXT_MESSAGE_COMPRESSED_APP) {
// Decompress the payload
char compressed_in[Constants_DATA_PAYLOAD_LEN] = {};
char decompressed_out[Constants_DATA_PAYLOAD_LEN] = {};
int decompressed_len;
memcpy(compressed_in, p->decoded.payload.bytes, p->decoded.payload.size);
decompressed_len = unishox2_decompress_simple(compressed_in, p->decoded.payload.size, decompressed_out);
// DEBUG_MSG("\n\n**\n\nDecompressed length - %d \n", decompressed_len);
memcpy(p->decoded.payload.bytes, decompressed_out, decompressed_len);
// Switch the port from PortNum_TEXT_MESSAGE_COMPRESSED_APP to PortNum_TEXT_MESSAGE_APP
p->decoded.portnum = PortNum_TEXT_MESSAGE_APP;
}
printPacket("decoded message", p); printPacket("decoded message", p);
return true; return true;
} }
@@ -320,10 +352,43 @@ Routing_Error perhapsEncode(MeshPacket *p)
if (p->which_payloadVariant == MeshPacket_decoded_tag) { if (p->which_payloadVariant == MeshPacket_decoded_tag) {
static uint8_t bytes[MAX_RHPACKETLEN]; // we have to use a scratch buffer because a union static uint8_t bytes[MAX_RHPACKETLEN]; // we have to use a scratch buffer because a union
// printPacket("pre encrypt", p); // portnum valid here
size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), Data_fields, &p->decoded); size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), Data_fields, &p->decoded);
// Only allow encryption on the text message app.
// TODO: Allow modules to opt into compression.
if (p->decoded.portnum == PortNum_TEXT_MESSAGE_APP) {
char original_payload[Constants_DATA_PAYLOAD_LEN];
memcpy(original_payload, p->decoded.payload.bytes, p->decoded.payload.size);
char compressed_out[Constants_DATA_PAYLOAD_LEN] = {0};
int compressed_len;
compressed_len = unishox2_compress_simple(original_payload, p->decoded.payload.size, compressed_out);
DEBUG_MSG("Original length - %d \n", p->decoded.payload.size);
DEBUG_MSG("Compressed length - %d \n", compressed_len);
DEBUG_MSG("Original message - %s \n", p->decoded.payload.bytes);
// If the compressed length is greater than or equal to the original size, don't use the compressed form
if (compressed_len >= p->decoded.payload.size) {
DEBUG_MSG("Not using compressing message.\n");
// Set the uncompressed payload varient anyway. Shouldn't hurt?
// p->decoded.which_payloadVariant = Data_payload_tag;
// Otherwise we use the compressor
} else {
DEBUG_MSG("Using compressed message.\n");
// Copy the compressed data into the meshpacket
p->decoded.payload.size = compressed_len;
memcpy(p->decoded.payload.bytes, compressed_out, compressed_len);
p->decoded.portnum = PortNum_TEXT_MESSAGE_COMPRESSED_APP;
}
}
if (numbytes > MAX_RHPACKETLEN) if (numbytes > MAX_RHPACKETLEN)
return Routing_Error_TOO_LARGE; return Routing_Error_TOO_LARGE;
@@ -382,8 +447,8 @@ void Router::handleReceived(MeshPacket *p, RxSource src)
void Router::perhapsHandleReceived(MeshPacket *p) void Router::perhapsHandleReceived(MeshPacket *p)
{ {
assert(radioConfig.has_preferences); // assert(radioConfig.has_preferences);
bool ignore = is_in_repeated(radioConfig.preferences.ignore_incoming, p->from); bool ignore = is_in_repeated(config.lora.ignore_incoming, p->from);
if (ignore) if (ignore)
DEBUG_MSG("Ignoring incoming message, 0x%x is in our ignore list\n", p->from); DEBUG_MSG("Ignoring incoming message, 0x%x is in our ignore list\n", p->from);

View File

@@ -64,15 +64,15 @@ bool SX126xInterface<T>::init()
#ifdef SX126X_TXEN #ifdef SX126X_TXEN
// lora.begin sets Dio2 as RF switch control, which is not true if we are manually controlling RX and TX // lora.begin sets Dio2 as RF switch control, which is not true if we are manually controlling RX and TX
if (res == ERR_NONE) if (res == RADIOLIB_ERR_NONE)
res = lora.setDio2AsRfSwitch(false); res = lora.setDio2AsRfSwitch(true);
#endif #endif
#if 0 #if 0
// Read/write a register we are not using (only used for FSK mode) to test SPI comms // Read/write a register we are not using (only used for FSK mode) to test SPI comms
uint8_t crcLSB = 0; uint8_t crcLSB = 0;
int err = lora.readRegister(SX126X_REG_CRC_POLYNOMIAL_LSB, &crcLSB, 1); int err = lora.readRegister(SX126X_REG_CRC_POLYNOMIAL_LSB, &crcLSB, 1);
if(err != ERR_NONE) if(err != RADIOLIB_ERR_NONE)
RECORD_CRITICALERROR(CriticalErrorCode_SX1262Failure); RECORD_CRITICALERROR(CriticalErrorCode_SX1262Failure);
//if(crcLSB != 0x0f) //if(crcLSB != 0x0f)
@@ -80,11 +80,11 @@ bool SX126xInterface<T>::init()
crcLSB = 0x5a; crcLSB = 0x5a;
err = lora.writeRegister(SX126X_REG_CRC_POLYNOMIAL_LSB, &crcLSB, 1); err = lora.writeRegister(SX126X_REG_CRC_POLYNOMIAL_LSB, &crcLSB, 1);
if(err != ERR_NONE) if(err != RADIOLIB_ERR_NONE)
RECORD_CRITICALERROR(CriticalErrorCode_SX1262Failure); RECORD_CRITICALERROR(CriticalErrorCode_SX1262Failure);
err = lora.readRegister(SX126X_REG_CRC_POLYNOMIAL_LSB, &crcLSB, 1); err = lora.readRegister(SX126X_REG_CRC_POLYNOMIAL_LSB, &crcLSB, 1);
if(err != ERR_NONE) if(err != RADIOLIB_ERR_NONE)
RECORD_CRITICALERROR(CriticalErrorCode_SX1262Failure); RECORD_CRITICALERROR(CriticalErrorCode_SX1262Failure);
if(crcLSB != 0x5a) if(crcLSB != 0x5a)
@@ -92,13 +92,13 @@ bool SX126xInterface<T>::init()
// If we got this far register accesses (and therefore SPI comms) are good // If we got this far register accesses (and therefore SPI comms) are good
#endif #endif
if (res == ERR_NONE) if (res == RADIOLIB_ERR_NONE)
res = lora.setCRC(SX126X_LORA_CRC_ON); res = lora.setCRC(RADIOLIB_SX126X_LORA_CRC_ON);
if (res == ERR_NONE) if (res == RADIOLIB_ERR_NONE)
startReceive(); // start receiving startReceive(); // start receiving
return res == ERR_NONE; return res == RADIOLIB_ERR_NONE;
} }
template<typename T> template<typename T>
@@ -111,42 +111,43 @@ bool SX126xInterface<T>::reconfigure()
// configure publicly accessible settings // configure publicly accessible settings
int err = lora.setSpreadingFactor(sf); int err = lora.setSpreadingFactor(sf);
if (err != ERR_NONE) if (err != RADIOLIB_ERR_NONE)
RECORD_CRITICALERROR(CriticalErrorCode_InvalidRadioSetting); RECORD_CRITICALERROR(CriticalErrorCode_InvalidRadioSetting);
err = lora.setBandwidth(bw); err = lora.setBandwidth(bw);
if (err != ERR_NONE) if (err != RADIOLIB_ERR_NONE)
RECORD_CRITICALERROR(CriticalErrorCode_InvalidRadioSetting); RECORD_CRITICALERROR(CriticalErrorCode_InvalidRadioSetting);
err = lora.setCodingRate(cr); err = lora.setCodingRate(cr);
if (err != ERR_NONE) if (err != RADIOLIB_ERR_NONE)
RECORD_CRITICALERROR(CriticalErrorCode_InvalidRadioSetting); RECORD_CRITICALERROR(CriticalErrorCode_InvalidRadioSetting);
// Hmm - seems to lower SNR when the signal levels are high. Leaving off for now... // Hmm - seems to lower SNR when the signal levels are high. Leaving off for now...
err = lora.setRxGain(true); // TODO: Confirm gain registers are okay now
assert(err == ERR_NONE); // err = lora.setRxGain(true);
// assert(err == RADIOLIB_ERR_NONE);
err = lora.setSyncWord(syncWord); err = lora.setSyncWord(syncWord);
assert(err == ERR_NONE); assert(err == RADIOLIB_ERR_NONE);
err = lora.setCurrentLimit(currentLimit); err = lora.setCurrentLimit(currentLimit);
assert(err == ERR_NONE); assert(err == RADIOLIB_ERR_NONE);
err = lora.setPreambleLength(preambleLength); err = lora.setPreambleLength(preambleLength);
assert(err == ERR_NONE); assert(err == RADIOLIB_ERR_NONE);
err = lora.setFrequency(getFreq()); err = lora.setFrequency(getFreq());
if (err != ERR_NONE) if (err != RADIOLIB_ERR_NONE)
RECORD_CRITICALERROR(CriticalErrorCode_InvalidRadioSetting); RECORD_CRITICALERROR(CriticalErrorCode_InvalidRadioSetting);
if (power > 22) // This chip has lower power limits than some if (power > 22) // This chip has lower power limits than some
power = 22; power = 22;
err = lora.setOutputPower(power); err = lora.setOutputPower(power);
assert(err == ERR_NONE); assert(err == RADIOLIB_ERR_NONE);
startReceive(); // restart receiving startReceive(); // restart receiving
return ERR_NONE; return RADIOLIB_ERR_NONE;
} }
template<typename T> template<typename T>
@@ -161,7 +162,7 @@ void SX126xInterface<T>::setStandby()
checkNotification(); // handle any pending interrupts before we force standby checkNotification(); // handle any pending interrupts before we force standby
int err = lora.standby(); int err = lora.standby();
assert(err == ERR_NONE); assert(err == RADIOLIB_ERR_NONE);
#ifdef SX126X_RXEN // we have RXEN/TXEN control - turn off RX and TX power #ifdef SX126X_RXEN // we have RXEN/TXEN control - turn off RX and TX power
digitalWrite(SX126X_RXEN, LOW); digitalWrite(SX126X_RXEN, LOW);
@@ -194,6 +195,9 @@ void SX126xInterface<T>::configHardwareForSend()
#ifdef SX126X_TXEN // we have RXEN/TXEN control - turn on TX power / off RX power #ifdef SX126X_TXEN // we have RXEN/TXEN control - turn on TX power / off RX power
digitalWrite(SX126X_TXEN, HIGH); digitalWrite(SX126X_TXEN, HIGH);
#endif #endif
#ifdef SX126X_RXEN
digitalWrite(SX126X_RXEN, LOW);
#endif
RadioLibInterface::configHardwareForSend(); RadioLibInterface::configHardwareForSend();
} }
@@ -213,11 +217,14 @@ void SX126xInterface<T>::startReceive()
#ifdef SX126X_RXEN // we have RXEN/TXEN control - turn on RX power / off TX power #ifdef SX126X_RXEN // we have RXEN/TXEN control - turn on RX power / off TX power
digitalWrite(SX126X_RXEN, HIGH); digitalWrite(SX126X_RXEN, HIGH);
#endif #endif
#ifdef SX126X_TXEN
digitalWrite(SX126X_TXEN, LOW);
#endif
// int err = lora.startReceive(); // int err = lora.startReceive();
int err = lora.startReceiveDutyCycleAuto(); // We use a 32 bit preamble so this should save some power by letting radio sit in int err = lora.startReceiveDutyCycleAuto(); // We use a 32 bit preamble so this should save some power by letting radio sit in
// standby mostly. // standby mostly.
assert(err == ERR_NONE); assert(err == RADIOLIB_ERR_NONE);
isReceiving = true; isReceiving = true;
@@ -226,6 +233,23 @@ void SX126xInterface<T>::startReceive()
#endif #endif
} }
/** Could we send right now (i.e. either not actively receving or transmitting)? */
template<typename T>
bool SX126xInterface<T>::isChannelActive()
{
// check if we can detect a LoRa preamble on the current channel
int16_t result;
setStandby();
result = lora.scanChannel();
if (result == RADIOLIB_PREAMBLE_DETECTED)
return true;
assert(result != RADIOLIB_ERR_WRONG_MODEM);
return false;
}
/** Could we send right now (i.e. either not actively receving or transmitting)? */ /** Could we send right now (i.e. either not actively receving or transmitting)? */
template<typename T> template<typename T>
bool SX126xInterface<T>::isActivelyReceiving() bool SX126xInterface<T>::isActivelyReceiving()
@@ -236,7 +260,7 @@ bool SX126xInterface<T>::isActivelyReceiving()
// never even get a valid header, so we don't want preamble to get set and stay set due to noise on the network. // never even get a valid header, so we don't want preamble to get set and stay set due to noise on the network.
uint16_t irq = lora.getIrqStatus(); uint16_t irq = lora.getIrqStatus();
bool hasPreamble = (irq & SX126X_IRQ_HEADER_VALID); bool hasPreamble = (irq & RADIOLIB_SX126X_IRQ_HEADER_VALID);
// this is not correct - often always true - need to add an extra conditional // this is not correct - often always true - need to add an extra conditional
// size_t bytesPending = lora.getPacketLength(); // size_t bytesPending = lora.getPacketLength();
@@ -266,4 +290,4 @@ bool SX126xInterface<T>::sleep()
#endif #endif
return true; return true;
} }

View File

@@ -46,6 +46,9 @@ class SX126xInterface : public RadioLibInterface
*/ */
virtual void enableInterrupt(void (*callback)()) { lora.setDio1Action(callback); } virtual void enableInterrupt(void (*callback)()) { lora.setDio1Action(callback); }
/** can we detect a LoRa preamble on the current channel? */
virtual bool isChannelActive() override;
/** are we actively receiving a packet (only called during receiving state) */ /** are we actively receiving a packet (only called during receiving state) */
virtual bool isActivelyReceiving() override; virtual bool isActivelyReceiving() override;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,278 @@
/*
* Copyright (C) 2020 Siara Logics (cc)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Arundale Ramanathan
*
*/
/**
* @file unishox2.h
* @author Arundale Ramanathan, James Z. M. Gao
* @brief API for Unishox2 Compression and Decompression
*
* This file describes each function of the Unishox2 API \n
* For finding out how this API can be used in your program, \n
* please see test_unishox2.c.
*/
#ifndef unishox2
#define unishox2
#define UNISHOX_VERSION "2.0" ///< Unicode spec version
/**
* Macro switch to enable/disable output buffer length parameter in low level api \n
* Disabled by default \n
* When this macro is defined, the all the API functions \n
* except the simple API functions accept an additional parameter olen \n
* that enables the developer to pass the size of the output buffer provided \n
* so that the api function may not write beyond that length. \n
* This can be disabled if the developer knows that the buffer provided is sufficient enough \n
* so no additional parameter is passed and the program is faster since additional check \n
* for output length is not performed at each step \n
* The simple api, i.e. unishox2_(de)compress_simple will always omit the buffer length
*/
#ifndef UNISHOX_API_WITH_OUTPUT_LEN
# define UNISHOX_API_WITH_OUTPUT_LEN 0
#endif
/// Upto 8 bits of initial magic bit sequence can be included. Bit count can be specified with UNISHOX_MAGIC_BIT_LEN
#ifndef UNISHOX_MAGIC_BITS
# define UNISHOX_MAGIC_BITS 0xFF
#endif
/// Desired length of Magic bits defined by UNISHOX_MAGIC_BITS
#ifdef UNISHOX_MAGIC_BIT_LEN
# if UNISHOX_MAGIC_BIT_LEN < 0 || 9 <= UNISHOX_MAGIC_BIT_LEN
# error "UNISHOX_MAGIC_BIT_LEN need between [0, 8)"
# endif
#else
# define UNISHOX_MAGIC_BIT_LEN 1
#endif
//enum {USX_ALPHA = 0, USX_SYM, USX_NUM, USX_DICT, USX_DELTA};
/// Default Horizontal codes. When composition of text is know beforehand, the other hcodes in this section can be used to achieve more compression.
#define USX_HCODES_DFLT (const unsigned char[]) {0x00, 0x40, 0x80, 0xC0, 0xE0}
/// Length of each default hcode
#define USX_HCODE_LENS_DFLT (const unsigned char[]) {2, 2, 2, 3, 3}
/// Horizontal codes preset for English Alphabet content only
#define USX_HCODES_ALPHA_ONLY (const unsigned char[]) {0x00, 0x00, 0x00, 0x00, 0x00}
/// Length of each Alpha only hcode
#define USX_HCODE_LENS_ALPHA_ONLY (const unsigned char[]) {0, 0, 0, 0, 0}
/// Horizontal codes preset for Alpha Numeric content only
#define USX_HCODES_ALPHA_NUM_ONLY (const unsigned char[]) {0x00, 0x00, 0x80, 0x00, 0x00}
/// Length of each Alpha numeric hcode
#define USX_HCODE_LENS_ALPHA_NUM_ONLY (const unsigned char[]) {1, 0, 1, 0, 0}
/// Horizontal codes preset for Alpha Numeric and Symbol content only
#define USX_HCODES_ALPHA_NUM_SYM_ONLY (const unsigned char[]) {0x00, 0x80, 0xC0, 0x00, 0x00}
/// Length of each Alpha numeric and symbol hcodes
#define USX_HCODE_LENS_ALPHA_NUM_SYM_ONLY (const unsigned char[]) {1, 2, 2, 0, 0}
/// Horizontal codes preset favouring Alphabet content
#define USX_HCODES_FAVOR_ALPHA (const unsigned char[]) {0x00, 0x80, 0xA0, 0xC0, 0xE0}
/// Length of each hcode favouring Alpha content
#define USX_HCODE_LENS_FAVOR_ALPHA (const unsigned char[]) {1, 3, 3, 3, 3}
/// Horizontal codes preset favouring repeating sequences
#define USX_HCODES_FAVOR_DICT (const unsigned char[]) {0x00, 0x40, 0xC0, 0x80, 0xE0}
/// Length of each hcode favouring repeating sequences
#define USX_HCODE_LENS_FAVOR_DICT (const unsigned char[]) {2, 2, 3, 2, 3}
/// Horizontal codes preset favouring symbols
#define USX_HCODES_FAVOR_SYM (const unsigned char[]) {0x80, 0x00, 0xA0, 0xC0, 0xE0}
/// Length of each hcode favouring symbols
#define USX_HCODE_LENS_FAVOR_SYM (const unsigned char[]) {3, 1, 3, 3, 3}
//#define USX_HCODES_FAVOR_UMLAUT {0x00, 0x40, 0xE0, 0xC0, 0x80}
//#define USX_HCODE_LENS_FAVOR_UMLAUT {2, 2, 3, 3, 2}
/// Horizontal codes preset favouring umlaut letters
#define USX_HCODES_FAVOR_UMLAUT (const unsigned char[]) {0x80, 0xA0, 0xC0, 0xE0, 0x00}
/// Length of each hcode favouring umlaut letters
#define USX_HCODE_LENS_FAVOR_UMLAUT (const unsigned char[]) {3, 3, 3, 3, 1}
/// Horizontal codes preset for no repeating sequences
#define USX_HCODES_NO_DICT (const unsigned char[]) {0x00, 0x40, 0x80, 0x00, 0xC0}
/// Length of each hcode for no repeating sequences
#define USX_HCODE_LENS_NO_DICT (const unsigned char[]) {2, 2, 2, 0, 2}
/// Horizontal codes preset for no Unicode characters
#define USX_HCODES_NO_UNI (const unsigned char[]) {0x00, 0x40, 0x80, 0xC0, 0x00}
/// Length of each hcode for no Unicode characters
#define USX_HCODE_LENS_NO_UNI (const unsigned char[]) {2, 2, 2, 2, 0}
/// Default frequently occuring sequences. When composition of text is know beforehand, the other sequences in this section can be used to achieve more compression.
#define USX_FREQ_SEQ_DFLT (const char *[]) {"\": \"", "\": ", "</", "=\"", "\":\"", "://"}
/// Frequently occuring sequences in text content
#define USX_FREQ_SEQ_TXT (const char *[]) {" the ", " and ", "tion", " with", "ing", "ment"}
/// Frequently occuring sequences in URL content
#define USX_FREQ_SEQ_URL (const char *[]) {"https://", "www.", ".com", "http://", ".org", ".net"}
/// Frequently occuring sequences in JSON content
#define USX_FREQ_SEQ_JSON (const char *[]) {"\": \"", "\": ", "\",", "}}}", "\":\"", "}}"}
/// Frequently occuring sequences in HTML content
#define USX_FREQ_SEQ_HTML (const char *[]) {"</", "=\"", "div", "href", "class", "<p>"}
/// Frequently occuring sequences in XML content
#define USX_FREQ_SEQ_XML (const char *[]) {"</", "=\"", "\">", "<?xml version=\"1.0\"", "xmlns:", "://"}
/// Commonly occuring templates (ISO Date/Time, ISO Date, US Phone number, ISO Time, Unused)
#define USX_TEMPLATES (const char *[]) {"tfff-of-tfTtf:rf:rf.fffZ", "tfff-of-tf", "(fff) fff-ffff", "tf:rf:rf", 0}
/// Default preset parameter set. When composition of text is know beforehand, the other parameter sets in this section can be used to achieve more compression.
#define USX_PSET_DFLT USX_HCODES_DFLT, USX_HCODE_LENS_DFLT, USX_FREQ_SEQ_DFLT, USX_TEMPLATES
/// Preset parameter set for English Alphabet only content
#define USX_PSET_ALPHA_ONLY USX_HCODES_ALPHA_ONLY, USX_HCODE_LENS_ALPHA_ONLY, USX_FREQ_SEQ_TXT, USX_TEMPLATES
/// Preset parameter set for Alpha numeric content
#define USX_PSET_ALPHA_NUM_ONLY USX_HCODES_ALPHA_NUM_ONLY, USX_HCODE_LENS_ALPHA_NUM_ONLY, USX_FREQ_SEQ_TXT, USX_TEMPLATES
/// Preset parameter set for Alpha numeric and symbol content
#define USX_PSET_ALPHA_NUM_SYM_ONLY USX_HCODES_ALPHA_NUM_SYM_ONLY, USX_HCODE_LENS_ALPHA_NUM_SYM_ONLY, USX_FREQ_SEQ_DFLT, USX_TEMPLATES
/// Preset parameter set for Alpha numeric symbol content having predominantly text
#define USX_PSET_ALPHA_NUM_SYM_ONLY_TXT USX_HCODES_ALPHA_NUM_SYM_ONLY, USX_HCODE_LENS_ALPHA_NUM_SYM_ONLY, USX_FREQ_SEQ_DFLT, USX_TEMPLATES
/// Preset parameter set favouring Alphabet content
#define USX_PSET_FAVOR_ALPHA USX_HCODES_FAVOR_ALPHA, USX_HCODE_LENS_FAVOR_ALPHA, USX_FREQ_SEQ_TXT, USX_TEMPLATES
/// Preset parameter set favouring repeating sequences
#define USX_PSET_FAVOR_DICT USX_HCODES_FAVOR_DICT, USX_HCODE_LENS_FAVOR_DICT, USX_FREQ_SEQ_DFLT, USX_TEMPLATES
/// Preset parameter set favouring symbols
#define USX_PSET_FAVOR_SYM USX_HCODES_FAVOR_SYM, USX_HCODE_LENS_FAVOR_SYM, USX_FREQ_SEQ_DFLT, USX_TEMPLATES
/// Preset parameter set favouring unlaut letters
#define USX_PSET_FAVOR_UMLAUT USX_HCODES_FAVOR_UMLAUT, USX_HCODE_LENS_FAVOR_UMLAUT, USX_FREQ_SEQ_DFLT, USX_TEMPLATES
/// Preset parameter set for when there are no repeating sequences
#define USX_PSET_NO_DICT USX_HCODES_NO_DICT, USX_HCODE_LENS_NO_DICT, USX_FREQ_SEQ_DFLT, USX_TEMPLATES
/// Preset parameter set for when there are no unicode symbols
#define USX_PSET_NO_UNI USX_HCODES_NO_UNI, USX_HCODE_LENS_NO_UNI, USX_FREQ_SEQ_DFLT, USX_TEMPLATES
/// Preset parameter set for when there are no unicode symbols favouring text
#define USX_PSET_NO_UNI_FAVOR_TEXT USX_HCODES_NO_UNI, USX_HCODE_LENS_NO_UNI, USX_FREQ_SEQ_TXT, USX_TEMPLATES
/// Preset parameter set favouring URL content
#define USX_PSET_URL USX_HCODES_DFLT, USX_HCODE_LENS_DFLT, USX_FREQ_SEQ_URL, USX_TEMPLATES
/// Preset parameter set favouring JSON content
#define USX_PSET_JSON USX_HCODES_DFLT, USX_HCODE_LENS_DFLT, USX_FREQ_SEQ_JSON, USX_TEMPLATES
/// Preset parameter set favouring JSON content having no Unicode symbols
#define USX_PSET_JSON_NO_UNI USX_HCODES_NO_UNI, USX_HCODE_LENS_NO_UNI, USX_FREQ_SEQ_JSON, USX_TEMPLATES
/// Preset parameter set favouring XML content
#define USX_PSET_XML USX_HCODES_DFLT, USX_HCODE_LENS_DFLT, USX_FREQ_SEQ_XML, USX_TEMPLATES
/// Preset parameter set favouring HTML content
#define USX_PSET_HTML USX_HCODES_DFLT, USX_HCODE_LENS_DFLT, USX_FREQ_SEQ_HTML, USX_TEMPLATES
/**
* This structure is used when a string array needs to be compressed.
* This is passed as a parameter to the unishox2_decompress_lines() function
*/
struct us_lnk_lst {
char *data;
struct us_lnk_lst *previous;
};
/**
* This macro is for internal use, but builds upon the macro UNISHOX_API_WITH_OUTPUT_LEN
* When the macro UNISHOX_API_WITH_OUTPUT_LEN is defined, the all the API functions
* except the simple API functions accept an additional parameter olen
* that enables the developer to pass the size of the output buffer provided
* so that the api function may not write beyond that length.
* This can be disabled if the developer knows that the buffer provided is sufficient enough
* so no additional parameter is passed and the program is faster since additional check
* for output length is not performed at each step
*/
#if defined(UNISHOX_API_WITH_OUTPUT_LEN) && UNISHOX_API_WITH_OUTPUT_LEN != 0
# define UNISHOX_API_OUT_AND_LEN(out, olen) out, olen
#else
# define UNISHOX_API_OUT_AND_LEN(out, olen) out
#endif
/**
* Simple API for compressing a string
* @param[in] in Input ASCII / UTF-8 string
* @param[in] len length in bytes
* @param[out] out output buffer - should be large enough to hold compressed output
*/
extern int unishox2_compress_simple(const char *in, int len, char *out);
/**
* Simple API for decompressing a string
* @param[in] in Input compressed bytes (output of unishox2_compress functions)
* @param[in] len length of 'in' in bytes
* @param[out] out output buffer for ASCII / UTF-8 string - should be large enough
*/
extern int unishox2_decompress_simple(const char *in, int len, char *out);
/**
* Comprehensive API for compressing a string
*
* Presets are available for the last four parameters so they can be passed as single parameter. \n
* See USX_PSET_* macros. Example call: \n
* unishox2_compress(in, len, out, olen, USX_PSET_ALPHA_ONLY);
*
* @param[in] in Input ASCII / UTF-8 string
* @param[in] len length in bytes
* @param[out] out output buffer - should be large enough to hold compressed output
* @param[in] olen length of 'out' buffer in bytes. Can be omitted if sufficient buffer is provided
* @param[in] usx_hcodes Horizontal codes (array of bytes). See macro section for samples.
* @param[in] usx_hcode_lens Length of each element in usx_hcodes array
* @param[in] usx_freq_seq Frequently occuring sequences. See USX_FREQ_SEQ_* macros for samples
* @param[in] usx_templates Templates of frequently occuring patterns. See USX_TEMPLATES macro.
*/
extern int unishox2_compress(const char *in, int len, UNISHOX_API_OUT_AND_LEN(char *out, int olen),
const unsigned char usx_hcodes[], const unsigned char usx_hcode_lens[],
const char *usx_freq_seq[], const char *usx_templates[]);
/**
* Comprehensive API for de-compressing a string
*
* Presets are available for the last four parameters so they can be passed as single parameter. \n
* See USX_PSET_* macros. Example call: \n
* unishox2_decompress(in, len, out, olen, USX_PSET_ALPHA_ONLY);
*
* @param[in] in Input compressed bytes (output of unishox2_compress functions)
* @param[in] len length of 'in' in bytes
* @param[out] out output buffer - should be large enough to hold de-compressed output
* @param[in] olen length of 'out' buffer in bytes. Can be omitted if sufficient buffer is provided
* @param[in] usx_hcodes Horizontal codes (array of bytes). See macro section for samples.
* @param[in] usx_hcode_lens Length of each element in usx_hcodes array
* @param[in] usx_freq_seq Frequently occuring sequences. See USX_FREQ_SEQ_* macros for samples
* @param[in] usx_templates Templates of frequently occuring patterns. See USX_TEMPLATES macro.
*/
extern int unishox2_decompress(const char *in, int len, UNISHOX_API_OUT_AND_LEN(char *out, int olen),
const unsigned char usx_hcodes[], const unsigned char usx_hcode_lens[],
const char *usx_freq_seq[], const char *usx_templates[]);
/**
* More Comprehensive API for compressing array of strings
*
* See unishox2_compress() function for parameter definitions. \n
* This function takes an additional parameter, i.e. 'prev_lines' - the usx_lnk_lst structure \n
* See -g parameter in test_unishox2.c to find out how this can be used. \n
* This function is used when an array of strings need to be compressed \n
* and stored in a compressed array of bytes for use as a constant in other programs \n
* where each element of the array can be decompressed and used at runtime.
*/
extern int unishox2_compress_lines(const char *in, int len, UNISHOX_API_OUT_AND_LEN(char *out, int olen),
const unsigned char usx_hcodes[], const unsigned char usx_hcode_lens[],
const char *usx_freq_seq[], const char *usx_templates[],
struct us_lnk_lst *prev_lines);
/**
* More Comprehensive API for de-compressing array of strings \n
* This function is not be used in conjuction with unishox2_compress_lines()
*
* See unishox2_decompress() function for parameter definitions. \n
* Typically an array is compressed using unishox2_compress_lines() and \n
* a header (.h) file is generated using the resultant compressed array. \n
* This header file can be used in another program with another decompress \n
* routine which takes this compressed array as parameter and index to be \n
* decompressed.
*/
extern int unishox2_decompress_lines(const char *in, int len, UNISHOX_API_OUT_AND_LEN(char *out, int olen),
const unsigned char usx_hcodes[], const unsigned char usx_hcode_lens[],
const char *usx_freq_seq[], const char *usx_templates[],
struct us_lnk_lst *prev_lines);
#endif

View File

@@ -6,7 +6,9 @@
#error Regenerate this file with the current version of nanopb generator. #error Regenerate this file with the current version of nanopb generator.
#endif #endif
PB_BIND(AdminMessage, AdminMessage, 2) PB_BIND(AdminMessage, AdminMessage, AUTO)

View File

@@ -5,30 +5,56 @@
#define PB_ADMIN_PB_H_INCLUDED #define PB_ADMIN_PB_H_INCLUDED
#include <pb.h> #include <pb.h>
#include "channel.pb.h" #include "channel.pb.h"
#include "config.pb.h"
#include "mesh.pb.h" #include "mesh.pb.h"
#include "radioconfig.pb.h" #include "module_config.pb.h"
#if PB_PROTO_HEADER_VERSION != 40 #if PB_PROTO_HEADER_VERSION != 40
#error Regenerate this file with the current version of nanopb generator. #error Regenerate this file with the current version of nanopb generator.
#endif #endif
/* Enum definitions */
typedef enum _AdminMessage_ConfigType {
AdminMessage_ConfigType_DEVICE_CONFIG = 0,
AdminMessage_ConfigType_POSITION_CONFIG = 1,
AdminMessage_ConfigType_POWER_CONFIG = 2,
AdminMessage_ConfigType_WIFI_CONFIG = 3,
AdminMessage_ConfigType_DISPLAY_CONFIG = 4,
AdminMessage_ConfigType_LORA_CONFIG = 5
} AdminMessage_ConfigType;
typedef enum _AdminMessage_ModuleConfigType {
AdminMessage_ModuleConfigType_MQTT_CONFIG = 0,
AdminMessage_ModuleConfigType_SERIAL_CONFIG = 1,
AdminMessage_ModuleConfigType_EXTNOTIF_CONFIG = 2,
AdminMessage_ModuleConfigType_STOREFORWARD_CONFIG = 3,
AdminMessage_ModuleConfigType_RANGETEST_CONFIG = 4,
AdminMessage_ModuleConfigType_TELEMETRY_CONFIG = 5,
AdminMessage_ModuleConfigType_CANNEDMSG_CONFIG = 6
} AdminMessage_ModuleConfigType;
/* Struct definitions */ /* Struct definitions */
/* This message is handled by the Admin module and is responsible for all settings/channel read/write operations. /* This message is handled by the Admin module and is responsible for all settings/channel read/write operations.
This message is used to do settings operations to both remote AND local nodes. This message is used to do settings operations to both remote AND local nodes.
(Prior to 1.2 these operations were done via special ToRadio operations) */ (Prior to 1.2 these operations were done via special ToRadio operations) */
typedef struct _AdminMessage { typedef struct _AdminMessage {
/* Set the radio provisioning for this node */ /* Set the owner for this node */
pb_size_t which_variant; pb_size_t which_variant;
union { union {
RadioConfig set_radio;
User set_owner; User set_owner;
Channel set_channel; Channel set_channel;
bool get_radio_request;
RadioConfig get_radio_response;
uint32_t get_channel_request; uint32_t get_channel_request;
Channel get_channel_response; Channel get_channel_response;
bool get_owner_request; bool get_owner_request;
User get_owner_response; User get_owner_response;
AdminMessage_ConfigType get_config_request;
Config get_config_response;
Config set_config;
bool confirm_set_config;
AdminMessage_ModuleConfigType get_module_config_request;
ModuleConfig get_module_config_response;
ModuleConfig set_module_config;
bool confirm_set_module_config;
bool confirm_set_channel; bool confirm_set_channel;
bool confirm_set_radio; bool confirm_set_radio;
bool exit_simulator; bool exit_simulator;
@@ -50,24 +76,39 @@ typedef struct _AdminMessage {
} AdminMessage; } AdminMessage;
/* Helper constants for enums */
#define _AdminMessage_ConfigType_MIN AdminMessage_ConfigType_DEVICE_CONFIG
#define _AdminMessage_ConfigType_MAX AdminMessage_ConfigType_LORA_CONFIG
#define _AdminMessage_ConfigType_ARRAYSIZE ((AdminMessage_ConfigType)(AdminMessage_ConfigType_LORA_CONFIG+1))
#define _AdminMessage_ModuleConfigType_MIN AdminMessage_ModuleConfigType_MQTT_CONFIG
#define _AdminMessage_ModuleConfigType_MAX AdminMessage_ModuleConfigType_CANNEDMSG_CONFIG
#define _AdminMessage_ModuleConfigType_ARRAYSIZE ((AdminMessage_ModuleConfigType)(AdminMessage_ModuleConfigType_CANNEDMSG_CONFIG+1))
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
/* Initializer values for message structs */ /* Initializer values for message structs */
#define AdminMessage_init_default {0, {RadioConfig_init_default}} #define AdminMessage_init_default {0, {User_init_default}}
#define AdminMessage_init_zero {0, {RadioConfig_init_zero}} #define AdminMessage_init_zero {0, {User_init_zero}}
/* Field tags (for use in manual encoding/decoding) */ /* Field tags (for use in manual encoding/decoding) */
#define AdminMessage_set_radio_tag 1
#define AdminMessage_set_owner_tag 2 #define AdminMessage_set_owner_tag 2
#define AdminMessage_set_channel_tag 3 #define AdminMessage_set_channel_tag 3
#define AdminMessage_get_radio_request_tag 4
#define AdminMessage_get_radio_response_tag 5
#define AdminMessage_get_channel_request_tag 6 #define AdminMessage_get_channel_request_tag 6
#define AdminMessage_get_channel_response_tag 7 #define AdminMessage_get_channel_response_tag 7
#define AdminMessage_get_owner_request_tag 8 #define AdminMessage_get_owner_request_tag 8
#define AdminMessage_get_owner_response_tag 9 #define AdminMessage_get_owner_response_tag 9
#define AdminMessage_get_config_request_tag 10
#define AdminMessage_get_config_response_tag 11
#define AdminMessage_set_config_tag 12
#define AdminMessage_confirm_set_config_tag 13
#define AdminMessage_get_module_config_request_tag 14
#define AdminMessage_get_module_config_response_tag 15
#define AdminMessage_set_module_config_tag 16
#define AdminMessage_confirm_set_module_config_tag 17
#define AdminMessage_confirm_set_channel_tag 32 #define AdminMessage_confirm_set_channel_tag 32
#define AdminMessage_confirm_set_radio_tag 33 #define AdminMessage_confirm_set_radio_tag 33
#define AdminMessage_exit_simulator_tag 34 #define AdminMessage_exit_simulator_tag 34
@@ -88,15 +129,20 @@ extern "C" {
/* Struct field encoding specification for nanopb */ /* Struct field encoding specification for nanopb */
#define AdminMessage_FIELDLIST(X, a) \ #define AdminMessage_FIELDLIST(X, a) \
X(a, STATIC, ONEOF, MESSAGE, (variant,set_radio,set_radio), 1) \
X(a, STATIC, ONEOF, MESSAGE, (variant,set_owner,set_owner), 2) \ X(a, STATIC, ONEOF, MESSAGE, (variant,set_owner,set_owner), 2) \
X(a, STATIC, ONEOF, MESSAGE, (variant,set_channel,set_channel), 3) \ X(a, STATIC, ONEOF, MESSAGE, (variant,set_channel,set_channel), 3) \
X(a, STATIC, ONEOF, BOOL, (variant,get_radio_request,get_radio_request), 4) \
X(a, STATIC, ONEOF, MESSAGE, (variant,get_radio_response,get_radio_response), 5) \
X(a, STATIC, ONEOF, UINT32, (variant,get_channel_request,get_channel_request), 6) \ X(a, STATIC, ONEOF, UINT32, (variant,get_channel_request,get_channel_request), 6) \
X(a, STATIC, ONEOF, MESSAGE, (variant,get_channel_response,get_channel_response), 7) \ X(a, STATIC, ONEOF, MESSAGE, (variant,get_channel_response,get_channel_response), 7) \
X(a, STATIC, ONEOF, BOOL, (variant,get_owner_request,get_owner_request), 8) \ X(a, STATIC, ONEOF, BOOL, (variant,get_owner_request,get_owner_request), 8) \
X(a, STATIC, ONEOF, MESSAGE, (variant,get_owner_response,get_owner_response), 9) \ X(a, STATIC, ONEOF, MESSAGE, (variant,get_owner_response,get_owner_response), 9) \
X(a, STATIC, ONEOF, UENUM, (variant,get_config_request,get_config_request), 10) \
X(a, STATIC, ONEOF, MESSAGE, (variant,get_config_response,get_config_response), 11) \
X(a, STATIC, ONEOF, MESSAGE, (variant,set_config,set_config), 12) \
X(a, STATIC, ONEOF, BOOL, (variant,confirm_set_config,confirm_set_config), 13) \
X(a, STATIC, ONEOF, UENUM, (variant,get_module_config_request,get_module_config_request), 14) \
X(a, STATIC, ONEOF, MESSAGE, (variant,get_module_config_response,get_module_config_response), 15) \
X(a, STATIC, ONEOF, MESSAGE, (variant,set_module_config,set_module_config), 16) \
X(a, STATIC, ONEOF, BOOL, (variant,confirm_set_module_config,confirm_set_module_config), 17) \
X(a, STATIC, ONEOF, BOOL, (variant,confirm_set_channel,confirm_set_channel), 32) \ X(a, STATIC, ONEOF, BOOL, (variant,confirm_set_channel,confirm_set_channel), 32) \
X(a, STATIC, ONEOF, BOOL, (variant,confirm_set_radio,confirm_set_radio), 33) \ X(a, STATIC, ONEOF, BOOL, (variant,confirm_set_radio,confirm_set_radio), 33) \
X(a, STATIC, ONEOF, BOOL, (variant,exit_simulator,exit_simulator), 34) \ X(a, STATIC, ONEOF, BOOL, (variant,exit_simulator,exit_simulator), 34) \
@@ -116,12 +162,14 @@ X(a, STATIC, ONEOF, STRING, (variant,set_canned_message_module_part4,set_
X(a, STATIC, ONEOF, INT32, (variant,shutdown_seconds,shutdown_seconds), 51) X(a, STATIC, ONEOF, INT32, (variant,shutdown_seconds,shutdown_seconds), 51)
#define AdminMessage_CALLBACK NULL #define AdminMessage_CALLBACK NULL
#define AdminMessage_DEFAULT NULL #define AdminMessage_DEFAULT NULL
#define AdminMessage_variant_set_radio_MSGTYPE RadioConfig
#define AdminMessage_variant_set_owner_MSGTYPE User #define AdminMessage_variant_set_owner_MSGTYPE User
#define AdminMessage_variant_set_channel_MSGTYPE Channel #define AdminMessage_variant_set_channel_MSGTYPE Channel
#define AdminMessage_variant_get_radio_response_MSGTYPE RadioConfig
#define AdminMessage_variant_get_channel_response_MSGTYPE Channel #define AdminMessage_variant_get_channel_response_MSGTYPE Channel
#define AdminMessage_variant_get_owner_response_MSGTYPE User #define AdminMessage_variant_get_owner_response_MSGTYPE User
#define AdminMessage_variant_get_config_response_MSGTYPE Config
#define AdminMessage_variant_set_config_MSGTYPE Config
#define AdminMessage_variant_get_module_config_response_MSGTYPE ModuleConfig
#define AdminMessage_variant_set_module_config_MSGTYPE ModuleConfig
extern const pb_msgdesc_t AdminMessage_msg; extern const pb_msgdesc_t AdminMessage_msg;
@@ -129,7 +177,7 @@ extern const pb_msgdesc_t AdminMessage_msg;
#define AdminMessage_fields &AdminMessage_msg #define AdminMessage_fields &AdminMessage_msg
/* Maximum encoded size of messages (where known) */ /* Maximum encoded size of messages (where known) */
#define AdminMessage_size 598 #define AdminMessage_size 204
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ } /* extern "C" */

View File

@@ -6,7 +6,7 @@
#error Regenerate this file with the current version of nanopb generator. #error Regenerate this file with the current version of nanopb generator.
#endif #endif
PB_BIND(ChannelSet, ChannelSet, AUTO) PB_BIND(ChannelSet, ChannelSet, 2)

View File

@@ -5,6 +5,7 @@
#define PB_APPONLY_PB_H_INCLUDED #define PB_APPONLY_PB_H_INCLUDED
#include <pb.h> #include <pb.h>
#include "channel.pb.h" #include "channel.pb.h"
#include "config.pb.h"
#if PB_PROTO_HEADER_VERSION != 40 #if PB_PROTO_HEADER_VERSION != 40
#error Regenerate this file with the current version of nanopb generator. #error Regenerate this file with the current version of nanopb generator.
@@ -17,8 +18,12 @@
No DISABLED channels are included. No DISABLED channels are included.
This abstraction is used only on the the 'app side' of the world (ie python, javascript and android etc) to show a group of Channels as a (long) URL */ This abstraction is used only on the the 'app side' of the world (ie python, javascript and android etc) to show a group of Channels as a (long) URL */
typedef struct _ChannelSet { typedef struct _ChannelSet {
/* TODO: REPLACE */ /* Channel list with settings */
pb_callback_t settings; pb_size_t settings_count;
ChannelSettings settings[8];
/* LoRa config */
bool has_lora_config;
Config_LoRaConfig lora_config;
} ChannelSet; } ChannelSet;
@@ -27,18 +32,21 @@ extern "C" {
#endif #endif
/* Initializer values for message structs */ /* Initializer values for message structs */
#define ChannelSet_init_default {{{NULL}, NULL}} #define ChannelSet_init_default {0, {ChannelSettings_init_default, ChannelSettings_init_default, ChannelSettings_init_default, ChannelSettings_init_default, ChannelSettings_init_default, ChannelSettings_init_default, ChannelSettings_init_default, ChannelSettings_init_default}, false, Config_LoRaConfig_init_default}
#define ChannelSet_init_zero {{{NULL}, NULL}} #define ChannelSet_init_zero {0, {ChannelSettings_init_zero, ChannelSettings_init_zero, ChannelSettings_init_zero, ChannelSettings_init_zero, ChannelSettings_init_zero, ChannelSettings_init_zero, ChannelSettings_init_zero, ChannelSettings_init_zero}, false, Config_LoRaConfig_init_zero}
/* Field tags (for use in manual encoding/decoding) */ /* Field tags (for use in manual encoding/decoding) */
#define ChannelSet_settings_tag 1 #define ChannelSet_settings_tag 1
#define ChannelSet_lora_config_tag 2
/* Struct field encoding specification for nanopb */ /* Struct field encoding specification for nanopb */
#define ChannelSet_FIELDLIST(X, a) \ #define ChannelSet_FIELDLIST(X, a) \
X(a, CALLBACK, REPEATED, MESSAGE, settings, 1) X(a, STATIC, REPEATED, MESSAGE, settings, 1) \
#define ChannelSet_CALLBACK pb_default_field_callback X(a, STATIC, OPTIONAL, MESSAGE, lora_config, 2)
#define ChannelSet_CALLBACK NULL
#define ChannelSet_DEFAULT NULL #define ChannelSet_DEFAULT NULL
#define ChannelSet_settings_MSGTYPE ChannelSettings #define ChannelSet_settings_MSGTYPE ChannelSettings
#define ChannelSet_lora_config_MSGTYPE Config_LoRaConfig
extern const pb_msgdesc_t ChannelSet_msg; extern const pb_msgdesc_t ChannelSet_msg;
@@ -46,7 +54,7 @@ extern const pb_msgdesc_t ChannelSet_msg;
#define ChannelSet_fields &ChannelSet_msg #define ChannelSet_fields &ChannelSet_msg
/* Maximum encoded size of messages (where known) */ /* Maximum encoded size of messages (where known) */
/* ChannelSet_size depends on runtime parameters */ #define ChannelSet_size 573
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ } /* extern "C" */

View File

@@ -14,4 +14,3 @@ PB_BIND(Channel, Channel, AUTO)

View File

@@ -10,16 +10,6 @@
#endif #endif
/* Enum definitions */ /* Enum definitions */
typedef enum _ChannelSettings_ModemConfig {
ChannelSettings_ModemConfig_VLongSlow = 0,
ChannelSettings_ModemConfig_LongSlow = 1,
ChannelSettings_ModemConfig_LongFast = 2,
ChannelSettings_ModemConfig_MidSlow = 3,
ChannelSettings_ModemConfig_MidFast = 4,
ChannelSettings_ModemConfig_ShortSlow = 5,
ChannelSettings_ModemConfig_ShortFast = 6
} ChannelSettings_ModemConfig;
typedef enum _Channel_Role { typedef enum _Channel_Role {
Channel_Role_DISABLED = 0, Channel_Role_DISABLED = 0,
Channel_Role_PRIMARY = 1, Channel_Role_PRIMARY = 1,
@@ -48,28 +38,6 @@ typedef PB_BYTES_ARRAY_T(32) ChannelSettings_psk_t;
FIXME: explain how apps use channels for security. FIXME: explain how apps use channels for security.
explain how remote settings and remote gpio are managed as an example */ explain how remote settings and remote gpio are managed as an example */
typedef struct _ChannelSettings { typedef struct _ChannelSettings {
/* If zero then, use default max legal continuous power (ie. something that won't
burn out the radio hardware)
In most cases you should use zero here.
Units are in dBm. */
int8_t tx_power;
/* Note: This is the 'old' mechanism for specifying channel parameters.
Either modem_config or bandwidth/spreading/coding will be specified - NOT BOTH.
As a heuristic: If bandwidth is specified, do not use modem_config.
Because protobufs take ZERO space when the value is zero this works out nicely.
This value is replaced by bandwidth/spread_factor/coding_rate.
If you'd like to experiment with other options add them to MeshRadio.cpp in the device code. */
ChannelSettings_ModemConfig modem_config;
/* Bandwidth in MHz
Certain bandwidth numbers are 'special' and will be converted to the
appropriate floating point value: 31 -> 31.25MHz */
ChannelSettings_psk_t psk;
/* A number from 7 to 12.
Indicates number of chirps per symbol as 1<<spread_factor. */
char name[12];
/* The denominator of the coding rate.
ie for 4/8, the value is 8. 5/8 the value is 5. */
uint16_t bandwidth;
/* NOTE: this field is _independent_ and unrelated to the concepts in channel.proto. /* 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. 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. 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.
@@ -88,7 +56,7 @@ typedef struct _ChannelSettings {
hash = ((hash << 5) + hash) + (unsigned char) c; hash = ((hash << 5) + hash) + (unsigned char) c;
return hash; return hash;
} */ } */
uint32_t spread_factor; ChannelSettings_psk_t psk;
/* A simple pre-shared key for now for crypto. /* A simple pre-shared key for now for crypto.
Must be either 0 bytes (no crypto), 16 bytes (AES128), or 32 bytes (AES256). Must be either 0 bytes (no crypto), 16 bytes (AES128), or 32 bytes (AES256).
A special shorthand is used for 1 byte long psks. A special shorthand is used for 1 byte long psks.
@@ -99,7 +67,7 @@ typedef struct _ChannelSettings {
`1` = The special "default" channel key: {0xd4, 0xf1, 0xbb, 0x3a, 0x20, 0x29, 0x07, 0x59, 0xf0, 0xbc, 0xff, 0xab, 0xcf, 0x4e, 0x69, 0xbf} `1` = The special "default" channel key: {0xd4, 0xf1, 0xbb, 0x3a, 0x20, 0x29, 0x07, 0x59, 0xf0, 0xbc, 0xff, 0xab, 0xcf, 0x4e, 0x69, 0xbf}
`2` through 10 = The default channel key, except with 1 through 9 added to the last byte. `2` through 10 = The default channel key, except with 1 through 9 added to the last byte.
Shown to user as simple1 through 10 */ Shown to user as simple1 through 10 */
uint8_t coding_rate; char name[12];
/* A SHORT name that will be packed into the URL. /* A SHORT name that will be packed into the URL.
Less than 12 bytes. Less than 12 bytes.
Something for end users to call the channel Something for end users to call the channel
@@ -107,7 +75,7 @@ typedef struct _ChannelSettings {
is the special (minimally secure) "Default"channel. is the special (minimally secure) "Default"channel.
In user interfaces it should be rendered as a local language translation of "X". In user interfaces it should be rendered as a local language translation of "X".
For channel_num hashing empty string will be treated as "X". For channel_num hashing empty string will be treated as "X".
Where "X" is selected based on the English words listed above for ModemConfig */ Where "X" is selected based on the English words listed above for ModemPreset */
uint8_t channel_num; uint8_t channel_num;
/* Used to construct a globally unique channel ID. /* Used to construct a globally unique channel ID.
The full globally unique ID will be: "name.id" where ID is shown as base36. The full globally unique ID will be: "name.id" where ID is shown as base36.
@@ -142,10 +110,6 @@ typedef struct _Channel {
/* Helper constants for enums */ /* Helper constants for enums */
#define _ChannelSettings_ModemConfig_MIN ChannelSettings_ModemConfig_VLongSlow
#define _ChannelSettings_ModemConfig_MAX ChannelSettings_ModemConfig_ShortFast
#define _ChannelSettings_ModemConfig_ARRAYSIZE ((ChannelSettings_ModemConfig)(ChannelSettings_ModemConfig_ShortFast+1))
#define _Channel_Role_MIN Channel_Role_DISABLED #define _Channel_Role_MIN Channel_Role_DISABLED
#define _Channel_Role_MAX Channel_Role_SECONDARY #define _Channel_Role_MAX Channel_Role_SECONDARY
#define _Channel_Role_ARRAYSIZE ((Channel_Role)(Channel_Role_SECONDARY+1)) #define _Channel_Role_ARRAYSIZE ((Channel_Role)(Channel_Role_SECONDARY+1))
@@ -156,19 +120,14 @@ extern "C" {
#endif #endif
/* Initializer values for message structs */ /* Initializer values for message structs */
#define ChannelSettings_init_default {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0, 0, 0, 0} #define ChannelSettings_init_default {{0, {0}}, "", 0, 0, 0, 0}
#define Channel_init_default {0, false, ChannelSettings_init_default, _Channel_Role_MIN} #define Channel_init_default {0, false, ChannelSettings_init_default, _Channel_Role_MIN}
#define ChannelSettings_init_zero {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0, 0, 0, 0} #define ChannelSettings_init_zero {{0, {0}}, "", 0, 0, 0, 0}
#define Channel_init_zero {0, false, ChannelSettings_init_zero, _Channel_Role_MIN} #define Channel_init_zero {0, false, ChannelSettings_init_zero, _Channel_Role_MIN}
/* Field tags (for use in manual encoding/decoding) */ /* Field tags (for use in manual encoding/decoding) */
#define ChannelSettings_tx_power_tag 1
#define ChannelSettings_modem_config_tag 3
#define ChannelSettings_psk_tag 4 #define ChannelSettings_psk_tag 4
#define ChannelSettings_name_tag 5 #define ChannelSettings_name_tag 5
#define ChannelSettings_bandwidth_tag 6
#define ChannelSettings_spread_factor_tag 7
#define ChannelSettings_coding_rate_tag 8
#define ChannelSettings_channel_num_tag 9 #define ChannelSettings_channel_num_tag 9
#define ChannelSettings_id_tag 10 #define ChannelSettings_id_tag 10
#define ChannelSettings_uplink_enabled_tag 16 #define ChannelSettings_uplink_enabled_tag 16
@@ -179,13 +138,8 @@ extern "C" {
/* Struct field encoding specification for nanopb */ /* Struct field encoding specification for nanopb */
#define ChannelSettings_FIELDLIST(X, a) \ #define ChannelSettings_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, INT32, tx_power, 1) \
X(a, STATIC, SINGULAR, UENUM, modem_config, 3) \
X(a, STATIC, SINGULAR, BYTES, psk, 4) \ X(a, STATIC, SINGULAR, BYTES, psk, 4) \
X(a, STATIC, SINGULAR, STRING, name, 5) \ X(a, STATIC, SINGULAR, STRING, name, 5) \
X(a, STATIC, SINGULAR, UINT32, bandwidth, 6) \
X(a, STATIC, SINGULAR, UINT32, spread_factor, 7) \
X(a, STATIC, SINGULAR, UINT32, coding_rate, 8) \
X(a, STATIC, SINGULAR, UINT32, channel_num, 9) \ X(a, STATIC, SINGULAR, UINT32, channel_num, 9) \
X(a, STATIC, SINGULAR, FIXED32, id, 10) \ X(a, STATIC, SINGULAR, FIXED32, id, 10) \
X(a, STATIC, SINGULAR, BOOL, uplink_enabled, 16) \ X(a, STATIC, SINGULAR, BOOL, uplink_enabled, 16) \
@@ -209,8 +163,8 @@ extern const pb_msgdesc_t Channel_msg;
#define Channel_fields &Channel_msg #define Channel_fields &Channel_msg
/* Maximum encoded size of messages (where known) */ /* Maximum encoded size of messages (where known) */
#define ChannelSettings_size 87 #define ChannelSettings_size 61
#define Channel_size 102 #define Channel_size 76
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ } /* extern "C" */

View File

@@ -0,0 +1,36 @@
/* Automatically generated nanopb constant definitions */
/* Generated by nanopb-0.4.5 */
#include "config.pb.h"
#if PB_PROTO_HEADER_VERSION != 40
#error Regenerate this file with the current version of nanopb generator.
#endif
PB_BIND(Config, Config, AUTO)
PB_BIND(Config_DeviceConfig, Config_DeviceConfig, AUTO)
PB_BIND(Config_PositionConfig, Config_PositionConfig, AUTO)
PB_BIND(Config_PowerConfig, Config_PowerConfig, AUTO)
PB_BIND(Config_WiFiConfig, Config_WiFiConfig, AUTO)
PB_BIND(Config_DisplayConfig, Config_DisplayConfig, AUTO)
PB_BIND(Config_LoRaConfig, Config_LoRaConfig, 2)

View File

@@ -0,0 +1,363 @@
/* Automatically generated nanopb header */
/* Generated by nanopb-0.4.5 */
#ifndef PB_CONFIG_PB_H_INCLUDED
#define PB_CONFIG_PB_H_INCLUDED
#include <pb.h>
#if PB_PROTO_HEADER_VERSION != 40
#error Regenerate this file with the current version of nanopb generator.
#endif
/* Enum definitions */
typedef enum _Config_DeviceConfig_Role {
Config_DeviceConfig_Role_Client = 0,
Config_DeviceConfig_Role_ClientMute = 1,
Config_DeviceConfig_Role_Router = 2,
Config_DeviceConfig_Role_RouterClient = 3
} Config_DeviceConfig_Role;
typedef enum _Config_PositionConfig_PositionFlags {
Config_PositionConfig_PositionFlags_POS_UNDEFINED = 0,
Config_PositionConfig_PositionFlags_POS_ALTITUDE = 1,
Config_PositionConfig_PositionFlags_POS_ALT_MSL = 2,
Config_PositionConfig_PositionFlags_POS_GEO_SEP = 4,
Config_PositionConfig_PositionFlags_POS_DOP = 8,
Config_PositionConfig_PositionFlags_POS_HVDOP = 16,
Config_PositionConfig_PositionFlags_POS_SATINVIEW = 32,
Config_PositionConfig_PositionFlags_POS_SEQ_NOS = 64,
Config_PositionConfig_PositionFlags_POS_TIMESTAMP = 128
} Config_PositionConfig_PositionFlags;
typedef enum _Config_PowerConfig_ChargeCurrent {
Config_PowerConfig_ChargeCurrent_MAUnset = 0,
Config_PowerConfig_ChargeCurrent_MA100 = 1,
Config_PowerConfig_ChargeCurrent_MA190 = 2,
Config_PowerConfig_ChargeCurrent_MA280 = 3,
Config_PowerConfig_ChargeCurrent_MA360 = 4,
Config_PowerConfig_ChargeCurrent_MA450 = 5,
Config_PowerConfig_ChargeCurrent_MA550 = 6,
Config_PowerConfig_ChargeCurrent_MA630 = 7,
Config_PowerConfig_ChargeCurrent_MA700 = 8,
Config_PowerConfig_ChargeCurrent_MA780 = 9,
Config_PowerConfig_ChargeCurrent_MA880 = 10,
Config_PowerConfig_ChargeCurrent_MA960 = 11,
Config_PowerConfig_ChargeCurrent_MA1000 = 12,
Config_PowerConfig_ChargeCurrent_MA1080 = 13,
Config_PowerConfig_ChargeCurrent_MA1160 = 14,
Config_PowerConfig_ChargeCurrent_MA1240 = 15,
Config_PowerConfig_ChargeCurrent_MA1320 = 16
} Config_PowerConfig_ChargeCurrent;
typedef enum _Config_DisplayConfig_GpsCoordinateFormat {
Config_DisplayConfig_GpsCoordinateFormat_GpsFormatDec = 0,
Config_DisplayConfig_GpsCoordinateFormat_GpsFormatDMS = 1,
Config_DisplayConfig_GpsCoordinateFormat_GpsFormatUTM = 2,
Config_DisplayConfig_GpsCoordinateFormat_GpsFormatMGRS = 3,
Config_DisplayConfig_GpsCoordinateFormat_GpsFormatOLC = 4,
Config_DisplayConfig_GpsCoordinateFormat_GpsFormatOSGR = 5
} Config_DisplayConfig_GpsCoordinateFormat;
typedef enum _Config_LoRaConfig_RegionCode {
Config_LoRaConfig_RegionCode_Unset = 0,
Config_LoRaConfig_RegionCode_US = 1,
Config_LoRaConfig_RegionCode_EU433 = 2,
Config_LoRaConfig_RegionCode_EU868 = 3,
Config_LoRaConfig_RegionCode_CN = 4,
Config_LoRaConfig_RegionCode_JP = 5,
Config_LoRaConfig_RegionCode_ANZ = 6,
Config_LoRaConfig_RegionCode_KR = 7,
Config_LoRaConfig_RegionCode_TW = 8,
Config_LoRaConfig_RegionCode_RU = 9,
Config_LoRaConfig_RegionCode_IN = 10,
Config_LoRaConfig_RegionCode_NZ865 = 11,
Config_LoRaConfig_RegionCode_TH = 12
} Config_LoRaConfig_RegionCode;
typedef enum _Config_LoRaConfig_ModemPreset {
Config_LoRaConfig_ModemPreset_LongFast = 0,
Config_LoRaConfig_ModemPreset_LongSlow = 1,
Config_LoRaConfig_ModemPreset_VLongSlow = 2,
Config_LoRaConfig_ModemPreset_MidSlow = 3,
Config_LoRaConfig_ModemPreset_MidFast = 4,
Config_LoRaConfig_ModemPreset_ShortSlow = 5,
Config_LoRaConfig_ModemPreset_ShortFast = 6
} Config_LoRaConfig_ModemPreset;
/* Struct definitions */
typedef struct _Config_DeviceConfig {
Config_DeviceConfig_Role role;
bool serial_disabled;
bool factory_reset;
bool debug_log_enabled;
char ntp_server[33];
} Config_DeviceConfig;
typedef struct _Config_DisplayConfig {
uint32_t screen_on_secs;
Config_DisplayConfig_GpsCoordinateFormat gps_format;
uint32_t auto_screen_carousel_secs;
} Config_DisplayConfig;
typedef struct _Config_LoRaConfig {
int32_t tx_power;
Config_LoRaConfig_ModemPreset modem_preset;
uint32_t bandwidth;
uint32_t spread_factor;
uint32_t coding_rate;
float frequency_offset;
Config_LoRaConfig_RegionCode region;
uint32_t hop_limit;
bool tx_disabled;
pb_size_t ignore_incoming_count;
uint32_t ignore_incoming[3];
} Config_LoRaConfig;
typedef struct _Config_PositionConfig {
uint32_t position_broadcast_secs;
bool position_broadcast_smart_disabled;
bool fixed_position;
bool gps_disabled;
uint32_t gps_update_interval;
uint32_t gps_attempt_time;
uint32_t position_flags;
} Config_PositionConfig;
typedef struct _Config_PowerConfig {
Config_PowerConfig_ChargeCurrent charge_current;
bool is_power_saving;
bool is_always_powered;
uint32_t on_battery_shutdown_after_secs;
float adc_multiplier_override;
uint32_t wait_bluetooth_secs;
uint32_t mesh_sds_timeout_secs;
uint32_t sds_secs;
uint32_t ls_secs;
uint32_t min_wake_secs;
} Config_PowerConfig;
typedef struct _Config_WiFiConfig {
char ssid[33];
char psk[64];
bool ap_mode;
bool ap_hidden;
} Config_WiFiConfig;
typedef struct _Config {
/* TODO: REPLACE */
pb_size_t which_payloadVariant;
union {
Config_DeviceConfig device;
Config_PositionConfig position;
Config_PowerConfig power;
Config_WiFiConfig wifi;
Config_DisplayConfig display;
Config_LoRaConfig lora;
} payloadVariant;
} Config;
/* Helper constants for enums */
#define _Config_DeviceConfig_Role_MIN Config_DeviceConfig_Role_Client
#define _Config_DeviceConfig_Role_MAX Config_DeviceConfig_Role_RouterClient
#define _Config_DeviceConfig_Role_ARRAYSIZE ((Config_DeviceConfig_Role)(Config_DeviceConfig_Role_RouterClient+1))
#define _Config_PositionConfig_PositionFlags_MIN Config_PositionConfig_PositionFlags_POS_UNDEFINED
#define _Config_PositionConfig_PositionFlags_MAX Config_PositionConfig_PositionFlags_POS_TIMESTAMP
#define _Config_PositionConfig_PositionFlags_ARRAYSIZE ((Config_PositionConfig_PositionFlags)(Config_PositionConfig_PositionFlags_POS_TIMESTAMP+1))
#define _Config_PowerConfig_ChargeCurrent_MIN Config_PowerConfig_ChargeCurrent_MAUnset
#define _Config_PowerConfig_ChargeCurrent_MAX Config_PowerConfig_ChargeCurrent_MA1320
#define _Config_PowerConfig_ChargeCurrent_ARRAYSIZE ((Config_PowerConfig_ChargeCurrent)(Config_PowerConfig_ChargeCurrent_MA1320+1))
#define _Config_DisplayConfig_GpsCoordinateFormat_MIN Config_DisplayConfig_GpsCoordinateFormat_GpsFormatDec
#define _Config_DisplayConfig_GpsCoordinateFormat_MAX Config_DisplayConfig_GpsCoordinateFormat_GpsFormatOSGR
#define _Config_DisplayConfig_GpsCoordinateFormat_ARRAYSIZE ((Config_DisplayConfig_GpsCoordinateFormat)(Config_DisplayConfig_GpsCoordinateFormat_GpsFormatOSGR+1))
#define _Config_LoRaConfig_RegionCode_MIN Config_LoRaConfig_RegionCode_Unset
#define _Config_LoRaConfig_RegionCode_MAX Config_LoRaConfig_RegionCode_TH
#define _Config_LoRaConfig_RegionCode_ARRAYSIZE ((Config_LoRaConfig_RegionCode)(Config_LoRaConfig_RegionCode_TH+1))
#define _Config_LoRaConfig_ModemPreset_MIN Config_LoRaConfig_ModemPreset_LongFast
#define _Config_LoRaConfig_ModemPreset_MAX Config_LoRaConfig_ModemPreset_ShortFast
#define _Config_LoRaConfig_ModemPreset_ARRAYSIZE ((Config_LoRaConfig_ModemPreset)(Config_LoRaConfig_ModemPreset_ShortFast+1))
#ifdef __cplusplus
extern "C" {
#endif
/* Initializer values for message structs */
#define Config_init_default {0, {Config_DeviceConfig_init_default}}
#define Config_DeviceConfig_init_default {_Config_DeviceConfig_Role_MIN, 0, 0, 0, ""}
#define Config_PositionConfig_init_default {0, 0, 0, 0, 0, 0, 0}
#define Config_PowerConfig_init_default {_Config_PowerConfig_ChargeCurrent_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define Config_WiFiConfig_init_default {"", "", 0, 0}
#define Config_DisplayConfig_init_default {0, _Config_DisplayConfig_GpsCoordinateFormat_MIN, 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}}
#define Config_init_zero {0, {Config_DeviceConfig_init_zero}}
#define Config_DeviceConfig_init_zero {_Config_DeviceConfig_Role_MIN, 0, 0, 0, ""}
#define Config_PositionConfig_init_zero {0, 0, 0, 0, 0, 0, 0}
#define Config_PowerConfig_init_zero {_Config_PowerConfig_ChargeCurrent_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define Config_WiFiConfig_init_zero {"", "", 0, 0}
#define Config_DisplayConfig_init_zero {0, _Config_DisplayConfig_GpsCoordinateFormat_MIN, 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}}
/* Field tags (for use in manual encoding/decoding) */
#define Config_DeviceConfig_role_tag 1
#define Config_DeviceConfig_serial_disabled_tag 2
#define Config_DeviceConfig_factory_reset_tag 3
#define Config_DeviceConfig_debug_log_enabled_tag 4
#define Config_DeviceConfig_ntp_server_tag 5
#define Config_DisplayConfig_screen_on_secs_tag 1
#define Config_DisplayConfig_gps_format_tag 2
#define Config_DisplayConfig_auto_screen_carousel_secs_tag 3
#define Config_LoRaConfig_tx_power_tag 1
#define Config_LoRaConfig_modem_preset_tag 2
#define Config_LoRaConfig_bandwidth_tag 3
#define Config_LoRaConfig_spread_factor_tag 4
#define Config_LoRaConfig_coding_rate_tag 5
#define Config_LoRaConfig_frequency_offset_tag 6
#define Config_LoRaConfig_region_tag 7
#define Config_LoRaConfig_hop_limit_tag 8
#define Config_LoRaConfig_tx_disabled_tag 9
#define Config_LoRaConfig_ignore_incoming_tag 103
#define Config_PositionConfig_position_broadcast_secs_tag 1
#define Config_PositionConfig_position_broadcast_smart_disabled_tag 2
#define Config_PositionConfig_fixed_position_tag 3
#define Config_PositionConfig_gps_disabled_tag 5
#define Config_PositionConfig_gps_update_interval_tag 6
#define Config_PositionConfig_gps_attempt_time_tag 7
#define Config_PositionConfig_position_flags_tag 10
#define Config_PowerConfig_charge_current_tag 1
#define Config_PowerConfig_is_power_saving_tag 2
#define Config_PowerConfig_is_always_powered_tag 3
#define Config_PowerConfig_on_battery_shutdown_after_secs_tag 4
#define Config_PowerConfig_adc_multiplier_override_tag 6
#define Config_PowerConfig_wait_bluetooth_secs_tag 7
#define Config_PowerConfig_mesh_sds_timeout_secs_tag 9
#define Config_PowerConfig_sds_secs_tag 10
#define Config_PowerConfig_ls_secs_tag 11
#define Config_PowerConfig_min_wake_secs_tag 12
#define Config_WiFiConfig_ssid_tag 1
#define Config_WiFiConfig_psk_tag 2
#define Config_WiFiConfig_ap_mode_tag 3
#define Config_WiFiConfig_ap_hidden_tag 4
#define Config_device_tag 1
#define Config_position_tag 2
#define Config_power_tag 3
#define Config_wifi_tag 4
#define Config_display_tag 5
#define Config_lora_tag 6
/* Struct field encoding specification for nanopb */
#define Config_FIELDLIST(X, a) \
X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,device,payloadVariant.device), 1) \
X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,position,payloadVariant.position), 2) \
X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,power,payloadVariant.power), 3) \
X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,wifi,payloadVariant.wifi), 4) \
X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,display,payloadVariant.display), 5) \
X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,lora,payloadVariant.lora), 6)
#define Config_CALLBACK NULL
#define Config_DEFAULT NULL
#define Config_payloadVariant_device_MSGTYPE Config_DeviceConfig
#define Config_payloadVariant_position_MSGTYPE Config_PositionConfig
#define Config_payloadVariant_power_MSGTYPE Config_PowerConfig
#define Config_payloadVariant_wifi_MSGTYPE Config_WiFiConfig
#define Config_payloadVariant_display_MSGTYPE Config_DisplayConfig
#define Config_payloadVariant_lora_MSGTYPE Config_LoRaConfig
#define Config_DeviceConfig_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UENUM, role, 1) \
X(a, STATIC, SINGULAR, BOOL, serial_disabled, 2) \
X(a, STATIC, SINGULAR, BOOL, factory_reset, 3) \
X(a, STATIC, SINGULAR, BOOL, debug_log_enabled, 4) \
X(a, STATIC, SINGULAR, STRING, ntp_server, 5)
#define Config_DeviceConfig_CALLBACK NULL
#define Config_DeviceConfig_DEFAULT NULL
#define Config_PositionConfig_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UINT32, position_broadcast_secs, 1) \
X(a, STATIC, SINGULAR, BOOL, position_broadcast_smart_disabled, 2) \
X(a, STATIC, SINGULAR, BOOL, fixed_position, 3) \
X(a, STATIC, SINGULAR, BOOL, gps_disabled, 5) \
X(a, STATIC, SINGULAR, UINT32, gps_update_interval, 6) \
X(a, STATIC, SINGULAR, UINT32, gps_attempt_time, 7) \
X(a, STATIC, SINGULAR, UINT32, position_flags, 10)
#define Config_PositionConfig_CALLBACK NULL
#define Config_PositionConfig_DEFAULT NULL
#define Config_PowerConfig_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UENUM, charge_current, 1) \
X(a, STATIC, SINGULAR, BOOL, is_power_saving, 2) \
X(a, STATIC, SINGULAR, BOOL, is_always_powered, 3) \
X(a, STATIC, SINGULAR, UINT32, on_battery_shutdown_after_secs, 4) \
X(a, STATIC, SINGULAR, FLOAT, adc_multiplier_override, 6) \
X(a, STATIC, SINGULAR, UINT32, wait_bluetooth_secs, 7) \
X(a, STATIC, SINGULAR, UINT32, mesh_sds_timeout_secs, 9) \
X(a, STATIC, SINGULAR, UINT32, sds_secs, 10) \
X(a, STATIC, SINGULAR, UINT32, ls_secs, 11) \
X(a, STATIC, SINGULAR, UINT32, min_wake_secs, 12)
#define Config_PowerConfig_CALLBACK NULL
#define Config_PowerConfig_DEFAULT NULL
#define Config_WiFiConfig_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, STRING, ssid, 1) \
X(a, STATIC, SINGULAR, STRING, psk, 2) \
X(a, STATIC, SINGULAR, BOOL, ap_mode, 3) \
X(a, STATIC, SINGULAR, BOOL, ap_hidden, 4)
#define Config_WiFiConfig_CALLBACK NULL
#define Config_WiFiConfig_DEFAULT NULL
#define Config_DisplayConfig_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UINT32, screen_on_secs, 1) \
X(a, STATIC, SINGULAR, UENUM, gps_format, 2) \
X(a, STATIC, SINGULAR, UINT32, auto_screen_carousel_secs, 3)
#define Config_DisplayConfig_CALLBACK NULL
#define Config_DisplayConfig_DEFAULT NULL
#define Config_LoRaConfig_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, INT32, tx_power, 1) \
X(a, STATIC, SINGULAR, UENUM, modem_preset, 2) \
X(a, STATIC, SINGULAR, UINT32, bandwidth, 3) \
X(a, STATIC, SINGULAR, UINT32, spread_factor, 4) \
X(a, STATIC, SINGULAR, UINT32, coding_rate, 5) \
X(a, STATIC, SINGULAR, FLOAT, frequency_offset, 6) \
X(a, STATIC, SINGULAR, UENUM, region, 7) \
X(a, STATIC, SINGULAR, UINT32, hop_limit, 8) \
X(a, STATIC, SINGULAR, BOOL, tx_disabled, 9) \
X(a, STATIC, REPEATED, UINT32, ignore_incoming, 103)
#define Config_LoRaConfig_CALLBACK NULL
#define Config_LoRaConfig_DEFAULT NULL
extern const pb_msgdesc_t Config_msg;
extern const pb_msgdesc_t Config_DeviceConfig_msg;
extern const pb_msgdesc_t Config_PositionConfig_msg;
extern const pb_msgdesc_t Config_PowerConfig_msg;
extern const pb_msgdesc_t Config_WiFiConfig_msg;
extern const pb_msgdesc_t Config_DisplayConfig_msg;
extern const pb_msgdesc_t Config_LoRaConfig_msg;
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
#define Config_fields &Config_msg
#define Config_DeviceConfig_fields &Config_DeviceConfig_msg
#define Config_PositionConfig_fields &Config_PositionConfig_msg
#define Config_PowerConfig_fields &Config_PowerConfig_msg
#define Config_WiFiConfig_fields &Config_WiFiConfig_msg
#define Config_DisplayConfig_fields &Config_DisplayConfig_msg
#define Config_LoRaConfig_fields &Config_LoRaConfig_msg
/* Maximum encoded size of messages (where known) */
#define Config_DeviceConfig_size 42
#define Config_DisplayConfig_size 14
#define Config_LoRaConfig_size 67
#define Config_PositionConfig_size 30
#define Config_PowerConfig_size 47
#define Config_WiFiConfig_size 103
#define Config_size 105
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif

View File

@@ -12,4 +12,8 @@ PB_BIND(DeviceState, DeviceState, 4)
PB_BIND(ChannelFile, ChannelFile, 2) PB_BIND(ChannelFile, ChannelFile, 2)
PB_BIND(OEMStore, OEMStore, 2)

View File

@@ -11,12 +11,27 @@
#error Regenerate this file with the current version of nanopb generator. #error Regenerate this file with the current version of nanopb generator.
#endif #endif
/* Enum definitions */
/* TODO: REPLACE */
typedef enum _ScreenFonts {
/* TODO: REPLACE */
ScreenFonts_FONT_SMALL = 0,
/* TODO: REPLACE */
ScreenFonts_FONT_MEDIUM = 1,
/* TODO: REPLACE */
ScreenFonts_FONT_LARGE = 2
} ScreenFonts;
/* Struct definitions */ /* Struct definitions */
/* The on-disk saved channels */ /* The on-disk saved channels */
typedef struct _ChannelFile { typedef struct _ChannelFile {
/* The channels our node knows about */ /* The channels our node knows about */
pb_size_t channels_count; pb_size_t channels_count;
Channel channels[8]; Channel channels[8];
/* A version integer used to invalidate old save files when we make
incompatible changes This integer is set at build time and is private to
NodeDB.cpp in the device code. */
uint32_t version;
} ChannelFile; } ChannelFile;
/* This message is never sent over the wire, but it is used for serializing DB /* This message is never sent over the wire, but it is used for serializing DB
@@ -53,6 +68,28 @@ typedef struct _DeviceState {
bool did_gps_reset; bool did_gps_reset;
} DeviceState; } DeviceState;
typedef PB_BYTES_ARRAY_T(2048) OEMStore_oem_icon_bits_t;
/* This can be used for customizing the firmware distribution. If populated,
show a secondary bootup screen with cuatom logo and text for 2.5 seconds. */
typedef struct _OEMStore {
/* The Logo width in Px */
uint32_t oem_icon_width;
/* The Logo height in Px */
uint32_t oem_icon_height;
/* The Logo in xbm bytechar format */
OEMStore_oem_icon_bits_t oem_icon_bits;
/* Use this font for the OEM text. */
ScreenFonts oem_font;
/* Use this font for the OEM text. */
char oem_text[40];
} OEMStore;
/* Helper constants for enums */
#define _ScreenFonts_MIN ScreenFonts_FONT_SMALL
#define _ScreenFonts_MAX ScreenFonts_FONT_LARGE
#define _ScreenFonts_ARRAYSIZE ((ScreenFonts)(ScreenFonts_FONT_LARGE+1))
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@@ -60,12 +97,15 @@ extern "C" {
/* Initializer values for message structs */ /* Initializer values for message structs */
#define DeviceState_init_default {false, MyNodeInfo_init_default, false, User_init_default, 0, {NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default}, 0, {MeshPacket_init_default}, false, MeshPacket_init_default, 0, 0, 0} #define DeviceState_init_default {false, MyNodeInfo_init_default, false, User_init_default, 0, {NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default}, 0, {MeshPacket_init_default}, false, MeshPacket_init_default, 0, 0, 0}
#define ChannelFile_init_default {0, {Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default}} #define ChannelFile_init_default {0, {Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default}, 0}
#define OEMStore_init_default {0, 0, {0, {0}}, _ScreenFonts_MIN, ""}
#define DeviceState_init_zero {false, MyNodeInfo_init_zero, false, User_init_zero, 0, {NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero}, 0, {MeshPacket_init_zero}, false, MeshPacket_init_zero, 0, 0, 0} #define DeviceState_init_zero {false, MyNodeInfo_init_zero, false, User_init_zero, 0, {NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero}, 0, {MeshPacket_init_zero}, false, MeshPacket_init_zero, 0, 0, 0}
#define ChannelFile_init_zero {0, {Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero}} #define ChannelFile_init_zero {0, {Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero}, 0}
#define OEMStore_init_zero {0, 0, {0, {0}}, _ScreenFonts_MIN, ""}
/* Field tags (for use in manual encoding/decoding) */ /* Field tags (for use in manual encoding/decoding) */
#define ChannelFile_channels_tag 1 #define ChannelFile_channels_tag 1
#define ChannelFile_version_tag 2
#define DeviceState_my_node_tag 2 #define DeviceState_my_node_tag 2
#define DeviceState_owner_tag 3 #define DeviceState_owner_tag 3
#define DeviceState_node_db_tag 4 #define DeviceState_node_db_tag 4
@@ -74,6 +114,11 @@ extern "C" {
#define DeviceState_version_tag 8 #define DeviceState_version_tag 8
#define DeviceState_no_save_tag 9 #define DeviceState_no_save_tag 9
#define DeviceState_did_gps_reset_tag 11 #define DeviceState_did_gps_reset_tag 11
#define OEMStore_oem_icon_width_tag 1
#define OEMStore_oem_icon_height_tag 2
#define OEMStore_oem_icon_bits_tag 3
#define OEMStore_oem_font_tag 4
#define OEMStore_oem_text_tag 5
/* Struct field encoding specification for nanopb */ /* Struct field encoding specification for nanopb */
#define DeviceState_FIELDLIST(X, a) \ #define DeviceState_FIELDLIST(X, a) \
@@ -94,21 +139,34 @@ X(a, STATIC, SINGULAR, BOOL, did_gps_reset, 11)
#define DeviceState_rx_text_message_MSGTYPE MeshPacket #define DeviceState_rx_text_message_MSGTYPE MeshPacket
#define ChannelFile_FIELDLIST(X, a) \ #define ChannelFile_FIELDLIST(X, a) \
X(a, STATIC, REPEATED, MESSAGE, channels, 1) X(a, STATIC, REPEATED, MESSAGE, channels, 1) \
X(a, STATIC, SINGULAR, UINT32, version, 2)
#define ChannelFile_CALLBACK NULL #define ChannelFile_CALLBACK NULL
#define ChannelFile_DEFAULT NULL #define ChannelFile_DEFAULT NULL
#define ChannelFile_channels_MSGTYPE Channel #define ChannelFile_channels_MSGTYPE Channel
#define OEMStore_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UINT32, oem_icon_width, 1) \
X(a, STATIC, SINGULAR, UINT32, oem_icon_height, 2) \
X(a, STATIC, SINGULAR, BYTES, oem_icon_bits, 3) \
X(a, STATIC, SINGULAR, UENUM, oem_font, 4) \
X(a, STATIC, SINGULAR, STRING, oem_text, 5)
#define OEMStore_CALLBACK NULL
#define OEMStore_DEFAULT NULL
extern const pb_msgdesc_t DeviceState_msg; extern const pb_msgdesc_t DeviceState_msg;
extern const pb_msgdesc_t ChannelFile_msg; extern const pb_msgdesc_t ChannelFile_msg;
extern const pb_msgdesc_t OEMStore_msg;
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */ /* Defines for backwards compatibility with code written before nanopb-0.4.0 */
#define DeviceState_fields &DeviceState_msg #define DeviceState_fields &DeviceState_msg
#define ChannelFile_fields &ChannelFile_msg #define ChannelFile_fields &ChannelFile_msg
#define OEMStore_fields &OEMStore_msg
/* Maximum encoded size of messages (where known) */ /* Maximum encoded size of messages (where known) */
#define ChannelFile_size 832 #define ChannelFile_size 630
#define DeviceState_size 23903 #define DeviceState_size 23728
#define OEMStore_size 2106
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ } /* extern "C" */

View File

@@ -1,24 +1,15 @@
/* Automatically generated nanopb constant definitions */ /* Automatically generated nanopb constant definitions */
/* Generated by nanopb-0.4.5 */ /* Generated by nanopb-0.4.5 */
#include "radioconfig.pb.h" #include "localonly.pb.h"
#if PB_PROTO_HEADER_VERSION != 40 #if PB_PROTO_HEADER_VERSION != 40
#error Regenerate this file with the current version of nanopb generator. #error Regenerate this file with the current version of nanopb generator.
#endif #endif
PB_BIND(RadioConfig, RadioConfig, 2) PB_BIND(LocalConfig, LocalConfig, 2)
PB_BIND(RadioConfig_UserPreferences, RadioConfig_UserPreferences, 2)
PB_BIND(LocalModuleConfig, LocalModuleConfig, 2)

View File

@@ -0,0 +1,148 @@
/* Automatically generated nanopb header */
/* Generated by nanopb-0.4.5 */
#ifndef PB_LOCALONLY_PB_H_INCLUDED
#define PB_LOCALONLY_PB_H_INCLUDED
#include <pb.h>
#include "config.pb.h"
#include "module_config.pb.h"
#if PB_PROTO_HEADER_VERSION != 40
#error Regenerate this file with the current version of nanopb generator.
#endif
/* Struct definitions */
typedef struct _LocalConfig {
/* The part of the config that is specific to the Device */
bool has_device;
Config_DeviceConfig device;
/* The part of the config that is specific to the GPS Position */
bool has_position;
Config_PositionConfig position;
/* The part of the config that is specific to the Power settings */
bool has_power;
Config_PowerConfig power;
/* The part of the config that is specific to the Wifi Settings */
bool has_wifi;
Config_WiFiConfig wifi;
/* The part of the config that is specific to the Display */
bool has_display;
Config_DisplayConfig display;
/* The part of the config that is specific to the Lora Radio */
bool has_lora;
Config_LoRaConfig lora;
/* A version integer used to invalidate old save files when we make
incompatible changes This integer is set at build time and is private to
NodeDB.cpp in the device code. */
uint32_t version;
} LocalConfig;
typedef struct _LocalModuleConfig {
/* The part of the config that is specific to the MQTT module */
bool has_mqtt;
ModuleConfig_MQTTConfig mqtt;
/* The part of the config that is specific to the Serial module */
bool has_serial;
ModuleConfig_SerialConfig serial;
/* The part of the config that is specific to the ExternalNotification module */
bool has_external_notification;
ModuleConfig_ExternalNotificationConfig external_notification;
/* The part of the config that is specific to the Store & Forward module */
bool has_store_forward;
ModuleConfig_StoreForwardConfig store_forward;
/* The part of the config that is specific to the RangeTest module */
bool has_range_test;
ModuleConfig_RangeTestConfig range_test;
/* The part of the config that is specific to the Telemetry module */
bool has_telemetry;
ModuleConfig_TelemetryConfig telemetry;
/* The part of the config that is specific to the Canned Message module */
bool has_canned_message;
ModuleConfig_CannedMessageConfig canned_message;
/* A version integer used to invalidate old save files when we make
incompatible changes This integer is set at build time and is private to
NodeDB.cpp in the device code. */
uint32_t version;
} LocalModuleConfig;
#ifdef __cplusplus
extern "C" {
#endif
/* Initializer values for message structs */
#define LocalConfig_init_default {false, Config_DeviceConfig_init_default, false, Config_PositionConfig_init_default, false, Config_PowerConfig_init_default, false, Config_WiFiConfig_init_default, false, Config_DisplayConfig_init_default, false, Config_LoRaConfig_init_default, 0}
#define LocalModuleConfig_init_default {false, ModuleConfig_MQTTConfig_init_default, false, ModuleConfig_SerialConfig_init_default, false, ModuleConfig_ExternalNotificationConfig_init_default, false, ModuleConfig_StoreForwardConfig_init_default, false, ModuleConfig_RangeTestConfig_init_default, false, ModuleConfig_TelemetryConfig_init_default, false, ModuleConfig_CannedMessageConfig_init_default, 0}
#define LocalConfig_init_zero {false, Config_DeviceConfig_init_zero, false, Config_PositionConfig_init_zero, false, Config_PowerConfig_init_zero, false, Config_WiFiConfig_init_zero, false, Config_DisplayConfig_init_zero, false, Config_LoRaConfig_init_zero, 0}
#define LocalModuleConfig_init_zero {false, ModuleConfig_MQTTConfig_init_zero, false, ModuleConfig_SerialConfig_init_zero, false, ModuleConfig_ExternalNotificationConfig_init_zero, false, ModuleConfig_StoreForwardConfig_init_zero, false, ModuleConfig_RangeTestConfig_init_zero, false, ModuleConfig_TelemetryConfig_init_zero, false, ModuleConfig_CannedMessageConfig_init_zero, 0}
/* Field tags (for use in manual encoding/decoding) */
#define LocalConfig_device_tag 1
#define LocalConfig_position_tag 2
#define LocalConfig_power_tag 3
#define LocalConfig_wifi_tag 4
#define LocalConfig_display_tag 5
#define LocalConfig_lora_tag 6
#define LocalConfig_version_tag 7
#define LocalModuleConfig_mqtt_tag 1
#define LocalModuleConfig_serial_tag 2
#define LocalModuleConfig_external_notification_tag 3
#define LocalModuleConfig_store_forward_tag 4
#define LocalModuleConfig_range_test_tag 5
#define LocalModuleConfig_telemetry_tag 6
#define LocalModuleConfig_canned_message_tag 7
#define LocalModuleConfig_version_tag 8
/* Struct field encoding specification for nanopb */
#define LocalConfig_FIELDLIST(X, a) \
X(a, STATIC, OPTIONAL, MESSAGE, device, 1) \
X(a, STATIC, OPTIONAL, MESSAGE, position, 2) \
X(a, STATIC, OPTIONAL, MESSAGE, power, 3) \
X(a, STATIC, OPTIONAL, MESSAGE, wifi, 4) \
X(a, STATIC, OPTIONAL, MESSAGE, display, 5) \
X(a, STATIC, OPTIONAL, MESSAGE, lora, 6) \
X(a, STATIC, SINGULAR, UINT32, version, 7)
#define LocalConfig_CALLBACK NULL
#define LocalConfig_DEFAULT NULL
#define LocalConfig_device_MSGTYPE Config_DeviceConfig
#define LocalConfig_position_MSGTYPE Config_PositionConfig
#define LocalConfig_power_MSGTYPE Config_PowerConfig
#define LocalConfig_wifi_MSGTYPE Config_WiFiConfig
#define LocalConfig_display_MSGTYPE Config_DisplayConfig
#define LocalConfig_lora_MSGTYPE Config_LoRaConfig
#define LocalModuleConfig_FIELDLIST(X, a) \
X(a, STATIC, OPTIONAL, MESSAGE, mqtt, 1) \
X(a, STATIC, OPTIONAL, MESSAGE, serial, 2) \
X(a, STATIC, OPTIONAL, MESSAGE, external_notification, 3) \
X(a, STATIC, OPTIONAL, MESSAGE, store_forward, 4) \
X(a, STATIC, OPTIONAL, MESSAGE, range_test, 5) \
X(a, STATIC, OPTIONAL, MESSAGE, telemetry, 6) \
X(a, STATIC, OPTIONAL, MESSAGE, canned_message, 7) \
X(a, STATIC, SINGULAR, UINT32, version, 8)
#define LocalModuleConfig_CALLBACK NULL
#define LocalModuleConfig_DEFAULT NULL
#define LocalModuleConfig_mqtt_MSGTYPE ModuleConfig_MQTTConfig
#define LocalModuleConfig_serial_MSGTYPE ModuleConfig_SerialConfig
#define LocalModuleConfig_external_notification_MSGTYPE ModuleConfig_ExternalNotificationConfig
#define LocalModuleConfig_store_forward_MSGTYPE ModuleConfig_StoreForwardConfig
#define LocalModuleConfig_range_test_MSGTYPE ModuleConfig_RangeTestConfig
#define LocalModuleConfig_telemetry_MSGTYPE ModuleConfig_TelemetryConfig
#define LocalModuleConfig_canned_message_MSGTYPE ModuleConfig_CannedMessageConfig
extern const pb_msgdesc_t LocalConfig_msg;
extern const pb_msgdesc_t LocalModuleConfig_msg;
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
#define LocalConfig_fields &LocalConfig_msg
#define LocalModuleConfig_fields &LocalModuleConfig_msg
/* Maximum encoded size of messages (where known) */
#define LocalConfig_size 321
#define LocalModuleConfig_size 288
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif

Some files were not shown because too many files have changed in this diff Show More