Compare commits

...

361 Commits

Author SHA1 Message Date
Jm Casler
2fe124eb17 Bump to 1.3.3 2022-03-02 20:50:09 -08:00
Jm Casler
a450aac3b5 Merge branch 'master' of https://github.com/meshtastic/Meshtastic-device 2022-03-02 20:42:06 -08:00
Jm Casler
958f20da1a Update to 1.3.2 2022-03-02 20:42:05 -08:00
Jm Casler
ef4c01f4ea Merge pull request #1271 from mc-hamster/router
Update PERIODS_TO_LOG
2022-03-02 20:39:10 -08:00
Jm Casler
97c76cde3c Merge branch 'master' into router 2022-03-02 20:39:01 -08:00
Jm Casler
2ab0548dda Merge branch 'router' of https://github.com/mc-hamster/Meshtastic-device into router 2022-03-02 20:38:15 -08:00
Jm Casler
75bf2cc9c6 Update PERIODS_TO_LOG 2022-03-02 20:38:14 -08:00
Jm Casler
ee533b2d5c Bumping to 1.3.1 2022-03-02 19:02:08 -08:00
Jm Casler
52960f5fa2 Merge pull request #1269 from mc-hamster/router
Fix tophone build error
2022-03-02 18:55:43 -08:00
Jm Casler
5c281154fd Merge branch 'meshtastic:master' into router 2022-03-02 18:55:26 -08:00
Jm Casler
2c7b3acbb9 Fix tophone build error 2022-03-02 18:55:11 -08:00
Jm Casler
cf928fca93 Merge pull request #1268 from mc-hamster/router
Added router to mynodeinfo
2022-03-02 18:52:52 -08:00
Jm Casler
8eaaf842ab Merge branch 'meshtastic:master' into router 2022-03-02 18:52:25 -08:00
Jm Casler
09edd7f89b updating proto submodule to latest 2022-03-02 18:49:46 -08:00
Ben Meadors
556fc6210d Moved power fsm thread out of main (#1265) 2022-03-01 12:40:21 -06:00
Jm Casler
4d8c0c11dc Added router to mynodeinfo 2022-02-28 22:44:51 -08:00
Jm Casler
950b54aaba Merge pull request #1263 from mc-hamster/router
Add rssi to printPacket
2022-02-28 22:06:01 -08:00
Jm Casler
4b87a82eb3 Merge branch 'meshtastic:master' into router 2022-02-28 22:05:20 -08:00
Jm Casler
2fa8f45d74 updating proto submodule to latest 2022-02-28 22:03:39 -08:00
Jm Casler
4209fc8b2c updating proto submodule to latest 2022-02-28 19:35:59 -08:00
Jm Casler
6d4d2bb6fa Merge branch 'router' of https://github.com/mc-hamster/Meshtastic-device into router 2022-02-28 17:47:11 -08:00
Jm Casler
32ef354c22 Add rssi to printPacket 2022-02-28 17:47:09 -08:00
Jm Casler
a0395c1027 Merge pull request #1261 from mc-hamster/router
Add rssi meta data to the rf95 interface
2022-02-28 17:09:00 -08:00
Jm Casler
1f43132b52 Merge branch 'master' into router 2022-02-28 17:08:43 -08:00
Jm Casler
ac8ba706f0 Add rssi meta data to the rf95 interface 2022-02-28 17:07:31 -08:00
Ben Meadors
ca4c1c9d7c Moved button thread to its own file (#1260)
* Moved button thread to its own file

* Move some debug code blocks into their own files

* Shutdown refactoring

* Removed GENIEBLOCKS
2022-02-28 15:19:38 -06:00
Jm Casler
7b8746d596 Merge pull request #1259 from puzzled-pancake/master
Added comments on ANZ added 1w limit
2022-02-27 14:48:12 -08:00
puzzled-pancake
91b0fcb257 Added comments on ANZ added 1w limit
Added comments 
https://iotalliance.org.nz/wp-content/uploads/sites/4/2019/05/IoT-Spectrum-in-NZ-Briefing-Paper.pdf
https://www.iot.org.au/wp/wp-content/uploads/2016/12/IoTSpectrumFactSheet.pdf

As noted 1w limit on both
2022-02-28 10:39:48 +13:00
Jm Casler
768c26bb1b Merge pull request #1258 from mc-hamster/router
Add role to generated proto
2022-02-27 12:56:49 -08:00
Jm Casler
e5e13d78c3 Add role to generated proto 2022-02-27 12:56:18 -08:00
Jm Casler
a2eb148c50 Revert "Merge pull request #1257 from mc-hamster/router"
This reverts commit 33ed9476f8, reversing
changes made to 10fefe7c7b.
2022-02-27 12:50:50 -08:00
Jm Casler
33ed9476f8 Merge pull request #1257 from mc-hamster/router
Remove incomplete ReliableRouter implementation
2022-02-27 12:46:59 -08:00
Jm Casler
92d5dedc63 Remove incomplete ReliableRouter implementation 2022-02-27 12:46:23 -08:00
Jm Casler
10fefe7c7b updating proto submodule to latest 2022-02-27 10:01:40 -08:00
Jm Casler
92ffbca339 updating proto submodule to latest 2022-02-27 09:57:09 -08:00
Jm Casler
7c868c78cc updating proto submodule to latest 2022-02-27 09:52:31 -08:00
Jm Casler
3f2baeb56e Merge pull request #1256 from mc-hamster/router
Rename Plugin to Module in ui related areas.
2022-02-27 02:26:41 -08:00
Jm Casler
ebba628736 Rename Plugin to Module in ui related areas. 2022-02-27 02:26:22 -08:00
Jm Casler
2a02b4594f Merge pull request #1255 from mc-hamster/router
more rename plugin to module
2022-02-27 02:21:51 -08:00
Jm Casler
1e689b86b5 Merge branch 'router' of https://github.com/mc-hamster/Meshtastic-device into router 2022-02-27 02:21:26 -08:00
Jm Casler
e53abbfb2b more rename plugin to module 2022-02-27 02:21:02 -08:00
Jm Casler
6f086bd3ba Merge pull request #1254 from mc-hamster/router
More renaming plugin to module
2022-02-27 01:49:57 -08:00
Jm Casler
3c5e49d8f4 More renaming plugin to module 2022-02-27 01:49:24 -08:00
Jm Casler
7a5ae40289 Merge pull request #1253 from mc-hamster/router
Rename plugins in /esp32
2022-02-27 01:27:39 -08:00
Jm Casler
a83cfffd3a Rename plugins in /esp32 2022-02-27 01:27:17 -08:00
Jm Casler
031b3665f8 Merge pull request #1252 from mc-hamster/router
CannedMessages from plugin to module
2022-02-27 01:21:17 -08:00
Jm Casler
206ae4e2b8 Merge branch 'router' of https://github.com/mc-hamster/Meshtastic-device into router 2022-02-27 01:20:54 -08:00
Jm Casler
24556f2803 CannedMessages from plugin to module 2022-02-27 01:20:23 -08:00
Jm Casler
ffa7a36a03 Merge pull request #1251 from mc-hamster/router
Update canned messages from plugin to module
2022-02-27 01:10:07 -08:00
Jm Casler
ba7644e376 Update canned messages from plugin to module 2022-02-27 01:09:36 -08:00
Jm Casler
ebc9fef222 updating proto submodule to latest 2022-02-27 01:00:35 -08:00
Jm Casler
dee577cb5c Merge pull request #1250 from mc-hamster/router
Update _plugin_ in radioconfig to _module_
2022-02-27 00:52:58 -08:00
Jm Casler
ed5dea9f85 Update _plugin_ in radioconfig to _module_ 2022-02-27 00:52:25 -08:00
Jm Casler
eeacb280d1 updating proto submodule to latest 2022-02-27 00:48:54 -08:00
Jm Casler
bc27dbde98 updating proto submodule to latest 2022-02-27 00:38:07 -08:00
Jm Casler
9b1bf7787c Merge pull request #1249 from mc-hamster/router
"plugin(s)" renamed to "module(s)" in comments and debug
2022-02-27 00:30:31 -08:00
Jm Casler
71bf9de638 Merge branch 'router' of https://github.com/mc-hamster/Meshtastic-device into router 2022-02-27 00:29:15 -08:00
Jm Casler
3a04a0ee7a "plugin(s)" renamed to "module(s)" in comments and debug 2022-02-27 00:29:05 -08:00
Jm Casler
e218740488 Merge pull request #1248 from mc-hamster/router
mv plugins/ to modules/
2022-02-27 00:18:53 -08:00
Jm Casler
86e767eec2 Update filenames from plugins to modules 2022-02-27 00:18:35 -08:00
Jm Casler
d57704b3bd Merge branch 'meshtastic:master' into router 2022-02-26 23:56:51 -08:00
Jm Casler
218a208ab7 mv plugins/ to modules/ 2022-02-26 23:56:26 -08:00
Jm Casler
c5c12bcc6b Merge pull request #1244 from puzzled-pancake/master
Added NZ865 Frequency
2022-02-26 21:36:58 -08:00
Jm Casler
0e686e4645 Merge pull request #1247 from mc-hamster/router
regen protos for NZ regioncode
2022-02-26 21:33:58 -08:00
Jm Casler
9050fe7f90 regen protos for NZ regioncode 2022-02-26 21:32:52 -08:00
Jm Casler
c511fa2fe6 updating proto submodule to latest 2022-02-26 21:28:05 -08:00
puzzled-pancake
9b44d2e999 Update RadioInterface.cpp 2022-02-27 18:12:27 +13:00
Jm Casler
01a86133ea Merge branch 'master' into master 2022-02-26 21:07:44 -08:00
Jm Casler
338c30fe9a Merge pull request #1245 from mc-hamster/router
Rename environmental_monitoring to telemetry
2022-02-26 21:07:28 -08:00
Jm Casler
ac43a1b182 Rename environmental measurement to telemetry 2022-02-26 20:52:22 -08:00
Jm Casler
5bff62e428 Delete environmental_measurement.pb.h 2022-02-26 20:31:16 -08:00
Jm Casler
a0f80c1a2a Delete environmental_measurement.pb.c 2022-02-26 20:31:05 -08:00
puzzled-pancake
f9bcddafef Update RadioInterface.cpp 2022-02-27 17:30:11 +13:00
puzzled-pancake
a25beff241 Update RadioInterface.cpp 2022-02-27 17:29:25 +13:00
Jm Casler
529707489a Rename EnvironmentalMeasurementPlugin.h to Telemetry.h 2022-02-26 20:19:14 -08:00
Jm Casler
ceccbd3ef2 Rename Telemetry to Telemetry.cpp 2022-02-26 20:18:50 -08:00
Jm Casler
59ce0c7d09 Rename EnvironmentalMeasurementPlugin.cpp to Telemetry 2022-02-26 20:18:32 -08:00
puzzled-pancake
f2a31cc678 Update RadioInterface.cpp
Add NZ 866
2022-02-27 17:01:25 +13:00
Ben Meadors
c97541d4fc Turns out this workflow is needed on the target branch 2022-02-25 17:25:43 -06:00
Ben Meadors
fc54f2f63d Temporary 1.2 legacy PR checks (#1243)
* Temporary 1.2 legacy PR checks
2022-02-25 16:13:28 -06:00
Andre Kirchhoff
c3cee236bd add m-flasher to README (#1241) 2022-02-25 08:22:59 -06:00
Mark Trevor Birss
c5a8cc6d3f Add 1.54, 2.9 and 4.2 inch e-Paper support for RAK4361 boards - with partial updates for faster screen transitions (#1240)
* Update platformio.ini
2022-02-25 07:03:52 -06:00
Jm Casler
2e402a726b Merge pull request #1238 from mc-hamster/group-chat
Remove chat groups
2022-02-24 20:08:51 -08:00
Jm Casler
ca8598f8b7 Merge branch 'meshtastic:master' into group-chat 2022-02-24 20:05:46 -08:00
Jm Casler
b6d7eadea3 Remove chat groups 2022-02-24 20:05:27 -08:00
Jm Casler
cd9def6850 Add my test ssid 2022-02-22 19:01:24 -08:00
Jm Casler
060eac7ab9 Merge pull request #1235 from mc-hamster/group-chat
remove test code
2022-02-22 17:18:19 -08:00
Jm Casler
d95d874258 Merge branch 'meshtastic:master' into group-chat 2022-02-22 17:17:56 -08:00
Jm Casler
e52f94820e remove test code 2022-02-22 17:16:45 -08:00
Jm Casler
31f4ec5d6c updating proto submodule to latest 2022-02-22 17:10:01 -08:00
Balázs Kelemen
bb15ed903d Cleanup docker readme. (#1233)
Cleanup docker readme.
2022-02-22 06:18:54 -06:00
Jm Casler
ef2bc2b9fc Merge pull request #1232 from prampec/extend_canned_message_length
Canned message - Extend messages length
2022-02-21 22:10:40 -08:00
Balazs Kelemen
972c2bb329 Revert "Canned message - Fixes"
This reverts commit 54ff8f2db3.
2022-02-22 07:08:44 +01:00
Balazs Kelemen
54ff8f2db3 Canned message - Fixes 2022-02-21 23:53:56 +01:00
Balazs Kelemen
a36889abba Canned message - Extend messages length 2022-02-21 22:04:58 +01:00
Jm Casler
eb66ba2510 Merge pull request #1230 from mc-hamster/group-chat
Add debug output of the group names.
2022-02-20 10:48:42 -08:00
Jm Casler
1e6e3805ad Add debug output of the group names. 2022-02-20 10:47:57 -08:00
Jm Casler
0133186f70 Merge pull request #1227 from mc-hamster/group-chat
Add STATE_SEND_GROUPS to PhoneAPI::available
2022-02-20 08:23:34 -08:00
Jm Casler
b15ef2749f Add STATE_SEND_GROUPS to PhoneAPI::available 2022-02-20 08:23:05 -08:00
Jm Casler
7b2042f391 Merge pull request #1226 from mc-hamster/group-chat
Fix webserver crash with new filesystem & Add groups to payloadVariant
2022-02-20 02:45:09 -08:00
Jm Casler
3d4fc63ecc Fix webserver crash with new filesystem 2022-02-20 02:44:13 -08:00
Jm Casler
3fdd425634 Add groups to payloadVariant 2022-02-20 01:33:49 -08:00
Jm Casler
d416f28341 updating proto submodule to latest 2022-02-20 01:32:50 -08:00
Jm Casler
06064d92cd Merge pull request #1225 from mc-hamster/group-chat
Add ourGroupInfo to NodeDB
2022-02-20 00:05:13 -08:00
Jm Casler
837c0e3717 Merge branch 'meshtastic:master' into group-chat 2022-02-20 00:04:46 -08:00
Jm Casler
389a8f1401 Add ourGroupInfo to NodeDB 2022-02-20 00:04:32 -08:00
Jm Casler
d32989cd7e Merge pull request #1224 from mc-hamster/group-chat
Plumbing for the GroupPlugin
2022-02-19 23:50:39 -08:00
Jm Casler
e969e83037 Merge branch 'meshtastic:master' into group-chat 2022-02-19 23:50:14 -08:00
Jm Casler
57d824cf5d updating proto submodule to latest 2022-02-19 23:48:21 -08:00
Jm Casler
e34190b497 Plumbing for the GroupPlugin 2022-02-19 23:43:32 -08:00
Jm Casler
701668804a updating proto submodule to latest 2022-02-19 23:17:48 -08:00
Jm Casler
a7aa82e732 updating proto submodule to latest 2022-02-19 23:10:51 -08:00
Jm Casler
1075b95f79 updating proto submodule to latest 2022-02-19 22:55:36 -08:00
Ben Meadors
29e70a80c6 Add rak eink variant (#1221) 2022-02-19 07:32:15 -06:00
Mark Trevor Birss
8303500b74 Add RAK4361_5005_RAK14000 board variant and enable e-Paper module (#1199)
* Create platformio.ini

* Create variant.cpp

* Create variant.h

* Update EInkDisplay2.cpp

* Update build-all.sh
2022-02-19 07:30:30 -06:00
Thomas Göttgens
e7e001c159 Install littlefs-python during pio run (#1220)
Install only if it is missing from the ENV. Caveat: this python module is essentially lib binding and needs Cython and a working compiler as well. this MAY or MAY NOT work.
2022-02-18 11:42:24 -06:00
Thomas Göttgens
54f062e94d Add littlefs dependancy to release flow as well (#1217) 2022-02-16 07:22:40 -06:00
Sacha Weatherstone
717491752b Merge branch 'master' of github.com:meshtastic/meshtastic-device 2022-02-16 17:52:37 +11:00
Sacha Weatherstone
9cdc6ae860 Add bug report issue template 2022-02-16 17:52:14 +11:00
Jm Casler
4941fd30f7 Merge pull request #1216 from mc-hamster/Radio&Band-Refactor
Fix bug in frequency formulas
2022-02-15 18:49:45 -08:00
Jm Casler
5ddd280f92 Merge branch 'master' into Radio&Band-Refactor 2022-02-15 18:49:38 -08:00
Jm Casler
3a621ef262 Fix bug in frequency formulas 2022-02-15 18:48:54 -08:00
Sacha Weatherstone
0c946609d5 Remove old CI script 2022-02-16 11:39:29 +11:00
Jm Casler
554729dab2 Merge pull request #1214 from mc-hamster/Radio&Band-Refactor
Fix typo in default channel (Thanks Andre!)
2022-02-15 07:37:21 -08:00
Jm Casler
ae6d0686bd Merge branch 'Radio&Band-Refactor' of https://github.com/mc-hamster/Meshtastic-device into Radio&Band-Refactor 2022-02-15 07:36:29 -08:00
Jm Casler
57bbd912b1 Fix typo in default channel (Thanks Andre!) 2022-02-15 07:36:28 -08:00
Jm Casler
6befed1176 Merge pull request #1213 from mc-hamster/Radio&Band-Refactor
Remove hw_model_deprecated
2022-02-14 20:38:20 -08:00
Jm Casler
1ba7f009dd Remove hw_model_deprecated 2022-02-14 20:37:44 -08:00
Jm Casler
eae8720068 updating proto submodule to latest 2022-02-14 20:35:44 -08:00
Jm Casler
18e95e6bb4 updating proto submodule to latest 2022-02-14 20:08:29 -08:00
Jm Casler
01e86512aa Merge pull request #1212 from mc-hamster/Radio&Band-Refactor
Remove old style of region code fix
2022-02-14 20:01:14 -08:00
Jm Casler
9fda734743 Merge branch 'Radio&Band-Refactor' of https://github.com/mc-hamster/Meshtastic-device into Radio&Band-Refactor 2022-02-14 20:00:52 -08:00
Jm Casler
04d16b82ba Remove old style of region code fix 2022-02-14 20:00:46 -08:00
Jm Casler
4206982572 Merge pull request #1211 from mc-hamster/Radio&Band-Refactor
Remove legacyRadio and Legacy Preferences
2022-02-14 19:59:39 -08:00
Jm Casler
b99d793e23 Remove legacyRadio and Legacy Preferences 2022-02-14 19:58:54 -08:00
Jm Casler
71d5e6c478 updating proto submodule to latest 2022-02-14 19:55:19 -08:00
Jm Casler
111d7ecd5e Merge pull request #1210 from mc-hamster/Radio&Band-Refactor
Remove myNodeInfo.num_bands. It's not used by android.
2022-02-14 19:45:53 -08:00
Jm Casler
1de086819c Remove myNodeInfo.num_bands. It's not used by android. 2022-02-14 19:45:26 -08:00
Jm Casler
af1804ea62 updating proto submodule to latest 2022-02-14 19:42:03 -08:00
Jm Casler
fe87682d69 Merge pull request #1209 from mc-hamster/Radio&Band-Refactor
New bands, new band plans and new channel configurations
2022-02-14 19:33:03 -08:00
Jm Casler
96b5537217 New bands, new band plans and new channel configurations 2022-02-14 19:32:31 -08:00
Jm Casler
449926cff9 Merge pull request #1208 from mc-hamster/Radio&Band-Refactor
Change the default pre shared key to break backward compatibility of default channel
2022-02-14 18:06:47 -08:00
Jm Casler
d4e5a3c67c Merge branch 'Radio&Band-Refactor' of https://github.com/mc-hamster/Meshtastic-device into Radio&Band-Refactor 2022-02-14 18:06:12 -08:00
Jm Casler
2428ca09fc Change the default pre shared key to break backward compatibility of default channel 2022-02-14 18:06:05 -08:00
Jm Casler
346712fbf3 Merge pull request #1207 from mc-hamster/Radio&Band-Refactor
Updated modem configuration
2022-02-14 18:01:58 -08:00
Jm Casler
a1ad1e7973 Updated modem configuration 2022-02-14 18:01:34 -08:00
Jm Casler
806a61251b updating proto submodule to latest 2022-02-14 17:59:43 -08:00
Jm Casler
34eee247e9 Merge pull request #1206 from mc-hamster/Radio&Band-Refactor
Rename EU865 to EU868 & Add TH and IN
2022-02-14 17:58:14 -08:00
Jm Casler
ee95594f74 Rename EU865 to EU868 & Add TH and IN 2022-02-14 17:01:13 -08:00
Jm Casler
7f3ad672b8 updating proto submodule to latest 2022-02-14 16:59:24 -08:00
Jm Casler
7cda49aba5 updating proto submodule to latest 2022-02-14 16:56:57 -08:00
Thomas Göttgens
8e9b852faa Littlefs rebased to Master (#1205)
* Littlefs
2022-02-14 11:45:29 -06:00
Ben Meadors
6b4907e841 Added after-checks 2022-02-14 11:27:33 -06:00
Ben Meadors
1808e9b3d8 Pick up littlefs instead of spiffs bin 2022-02-14 10:39:31 -06:00
Ben Meadors
1dd53eeaf5 Set max parallel workers on jobs to favor esp32 2022-02-14 10:36:16 -06:00
Ben Meadors
892d9a34c7 Add littlefs-python package for ESP32 target 2022-02-14 10:21:28 -06:00
Ben Meadors
ab96579904 Github action runs on job matrix now for parallel operation (both build and check) (#1202)
* Build matrix for parallel jobs
2022-02-13 14:10:59 -06:00
Ben Meadors
3f83acdbef Ignore version.properties on ci-build 2022-02-10 21:13:36 -06:00
Ben Meadors
9db7c62a49 1.2.55 release 2022-02-10 21:02:43 -06:00
Ben Meadors
d79dc631f1 Fixed RAK11200 configuration and added to build-all (#1192)
* Fixed RAK11200 configuration and added to build-all 

Co-authored-by: Mike Kinney <mike.kinney@gmail.com>
2022-02-10 20:21:36 -06:00
Ben Meadors
7ea6babb7f Add workflow_dispatch back 2022-02-10 16:23:34 -06:00
Garth Vander Houwen
0b4b901504 Merge pull request #1196 from meshtastic/mkinney-patch-1
Update main.yml
2022-02-10 14:09:49 -08:00
mkinney
cc7b5cf136 Update main.yml 2022-02-10 14:06:09 -08:00
Clemens H / OE1RFC / datacop
e3df4fe4b4 fix: log error if node_db is full instead of firmware crash (#1191) 2022-02-10 11:44:58 -06:00
Jm Casler
288f2be8ea bump to 1.2.54 2022-02-09 16:46:26 -08:00
Ben Meadors
c867af8522 Adjusted adc_multiplier for heltec2.1 and added adc_mulitplier_override (#1183) 2022-02-09 13:37:48 -06:00
Ric Letson
856f2f9589 MCP9808 sensor implementation (#1188)
* MCP9808 Sensor Implementation Initial Test
2022-02-08 11:03:34 -06:00
Ben Meadors
e649bc84e1 Fix PR artifact permissions (#1190) 2022-02-08 10:29:57 -06:00
Ben Meadors
bbcd59ec7b Specify branch for PR artifact storage (#1187) 2022-02-07 12:44:10 -06:00
Ben Meadors
e11fd593ae Update github action to flatten firmware zip and attach artifacts (#1186) 2022-02-07 11:15:03 -06:00
Thomas Göttgens
868af9dd6b Get rid of log clutter during oled screen animation (#1182) 2022-02-03 07:22:46 -06:00
Garth Vander Houwen
10800a6914 Merge pull request #1180 from meshtastic/create-pull-request/patch
Changes by create-pull-request action
2022-02-02 19:59:41 -08:00
thebentern
e567fe7322 [create-pull-request] automated change 2022-02-03 03:21:12 +00:00
Ben Meadors
365120e9c2 Added RAK11200 board variant support (#1177)
* Added RAK11200 board variant support
2022-02-02 12:41:07 -06:00
Ben Meadors
b21b7de04b Clear bluetooth bonds on multi-press and factory_reset (#1176)
* Clear bluetooth bonds on multi-press and factory_reset
2022-02-01 18:32:26 -06:00
github-actions[bot]
dd31a829fb Update and regen protobufs (#1175)
* Update and regen protobufs
2022-02-01 09:41:56 -06:00
Thomas Göttgens
9a505c27fa add missing Config definition for PRIVATE_HW (#1174) 2022-02-01 08:08:03 -06:00
Ben Meadors
ed9cd7b03d Update nimble (#1173) 2022-01-31 20:56:31 -06:00
Ben Meadors
66413d8b7f Refactored sensors (#1172)
* Refactored sensors
2022-01-31 20:24:32 -06:00
Jm Casler
e4fe2c159a Merge pull request #1165 from joshpirihi/master
Allow publishing of decrypted packets to MQTT
2022-01-28 21:10:00 -08:00
Jm Casler
f5e0718052 Merge branch 'master' into master 2022-01-28 20:13:46 -08:00
Jm Casler
64ff48c4a5 Merge pull request #1163 from caveman99/caveman99-patch-1
Fixed typo
2022-01-28 13:05:52 -08:00
Jm Casler
50969c4e42 Merge branch 'master' into caveman99-patch-1 2022-01-28 13:05:45 -08:00
Jm Casler
5288f1846a Merge pull request #1166 from rnauber/fix_nullptrderef
Prevent null pointer dereference in setup() if radio is not available.
2022-01-28 13:05:25 -08:00
Jm Casler
c545155b03 Merge branch 'master' into fix_nullptrderef 2022-01-28 13:05:11 -08:00
Vladislav Osmanov
a4e9fca80c DIY versions cleaning - moved to the one folder (#1167) 2022-01-28 14:58:27 -06:00
Richard Nauber
3611293a98 Prevent null pointer dereference in setup() if radio is not available. 2022-01-28 21:02:02 +01:00
joshpirihi
dc7f376778 Correct a comment 2022-01-29 06:40:17 +13:00
Joshua Pirihi
ff2cad9cac Allow publishing of decrypted mqtt packets 2022-01-29 06:06:49 +13:00
Joshua Pirihi
b781fb613c Allow publishing of decrypted mqtt packets 2022-01-29 06:03:48 +13:00
Thomas Göttgens
0a1125d7e4 Merge branch 'master' into caveman99-patch-1 2022-01-28 08:44:46 +01:00
Thomas Göttgens
ed2de3b885 Fixed typo 2022-01-28 08:43:48 +01:00
Jm Casler
19c1f9fa59 Bump to 1.2.53 2022-01-27 18:41:29 -08:00
Jm Casler
266d6ad205 Proto regen for .53 2022-01-27 17:52:03 -08:00
Jm Casler
66cd824437 Merge pull request #1162 from mkinney/remote_hw
gpio read and write work as expected
2022-01-27 17:49:23 -08:00
mkinney
e2db4f6927 Merge branch 'master' into remote_hw 2022-01-27 17:40:29 -08:00
Jm Casler
56fb141ed0 updating proto submodule to latest 2022-01-27 17:40:00 -08:00
Mike Kinney
e8e209be25 gpio read and write work as expected 2022-01-28 00:11:16 +00:00
mkinney
c278a0e299 Merge pull request #1149 from caveman99/caveman99-patch-1
accept one or more environment definitions
2022-01-27 11:39:43 -08:00
mkinney
fbc25c3a13 Merge branch 'master' into caveman99-patch-1 2022-01-27 11:09:57 -08:00
mkinney
b7f04f4c91 Merge pull request #1159 from meshtastic/create-pull-request/patch
Changes by create-pull-request action
2022-01-27 11:09:46 -08:00
mkinney
d5377a0f19 Merge branch 'master' into create-pull-request/patch 2022-01-27 10:40:01 -08:00
Jm Casler
dafc1092aa Merge pull request #1158 from meshtastic/thebentern-patch-2
Ignore markdown and yml for continuous integration
2022-01-27 10:37:09 -08:00
Jm Casler
477b666998 Merge branch 'master' into thebentern-patch-2 2022-01-27 10:37:04 -08:00
Jm Casler
dbcd720391 Merge pull request #1154 from osmanovv/patch-1
Fix MISO/MOSI pins for DIY v1.1
2022-01-27 10:36:38 -08:00
Ben Meadors
59c2bcd978 Merge branch 'master' into thebentern-patch-2 2022-01-27 12:33:55 -06:00
mkinney
aea6675e64 [create-pull-request] automated change 2022-01-27 18:32:55 +00:00
mkinney
8bff696bef Merge branch 'master' into patch-1 2022-01-27 10:28:21 -08:00
mkinney
da0ec09bf4 Merge pull request #1157 from meshtastic/thebentern-patch-1
Create pr instead of commit
2022-01-27 10:28:03 -08:00
Ben Meadors
2c99020037 Ignore markdown and yml for continuous integration 2022-01-27 11:59:08 -06:00
Ben Meadors
14419cbd02 Create pr instead of commit 2022-01-27 11:54:32 -06:00
Ben Meadors
1bfa6839e2 Use correct path to mesh (#1155) 2022-01-27 08:57:49 -06:00
Ben Meadors
a61676504f Attempt to only update proto (#1153) 2022-01-27 07:51:51 -06:00
Vladislav Osmanov
f4d3de086a Fix MISO/MOSI pins for DIY v1.1 2022-01-27 16:49:55 +03:00
Thomas Göttgens
af249da1a3 accept one or more environment definitions
This is a non breaking change. Up till now you could either specify ONE board to check or run with default settings hich would check a sensible set. With this change you can provide a space-separated list of boards to check, this facilitates parallel CI executions better.
2022-01-27 09:18:31 +01:00
Jm Casler
7613c7bf83 Merge pull request #1148 from mc-hamster/master
position plugin - only send if channel utilization is <50 percent
2022-01-26 22:40:52 -08:00
Jm Casler
e4608e0a10 position plugin - only send if channel utilization is <50 percent 2022-01-26 22:32:33 -08:00
Jm Casler
d26549c7c2 Merge pull request #1147 from mc-hamster/master
rangeTestPlugin - only send if channelUtilization is less than 25%
2022-01-26 22:20:35 -08:00
Jm Casler
697d52b9bd rangeTestPlugin - only send if channelUtilization is less than 25% 2022-01-26 22:20:13 -08:00
Ben Meadors
7a9450b250 Only update protos (#1145) 2022-01-26 16:17:30 -06:00
Jm Casler
6d372743f5 updating proto submodule to latest 2022-01-26 13:35:46 -08:00
mkinney
c2b309195d Merge pull request #1144 from meshtastic/update-protos-action
Update protobufs and regenerate classes action
2022-01-26 13:24:58 -08:00
Ben Meadors
3c7670186a Update protobufs and regenerate classes 2022-01-26 14:25:30 -06:00
Ben Meadors
b51be320dd BME680 support (#1142) 2022-01-25 14:22:48 -06:00
Thomas Göttgens
409ad9c2c3 Split platformio.ini into one file for each board, only leaving platform definitions and a handful of stale (?) boards around.. (#1141) 2022-01-25 08:56:16 -06:00
mkinney
eaa5252cdb Merge pull request #1138 from mkinney/fix_some_cpp_warnings
Fix some cpp warnings
2022-01-24 15:34:58 -08:00
Mike Kinney
3d718f45d5 fail the build if we have any cppcheck warnings 2022-01-24 21:35:24 +00:00
mkinney
a8dab94087 Merge branch 'master' into fix_some_cpp_warnings 2022-01-24 13:27:33 -08:00
mkinney
5a348da0e9 Merge pull request #1139 from caveman99/master
use the new version of Screen lib when building
2022-01-24 13:27:18 -08:00
Thomas Göttgens
115b835b83 Merge branch 'master' into master 2022-01-24 21:57:54 +01:00
Thomas Göttgens
9df42799ff Tryfix: Local replica for build problem (#1)
* Tryfix: Local replica for build problem

* Update platformio.ini

* use the real repo again
2022-01-24 21:56:31 +01:00
mkinney
e1d3c01199 Merge branch 'master' into fix_some_cpp_warnings 2022-01-24 12:52:21 -08:00
mkinney
bdcc0f252b Merge pull request #1140 from costonisp/master
added a new variant heltec_2.1
2022-01-24 12:44:49 -08:00
Mike Kinney
437aa1e9af make check a different job on ci 2022-01-24 20:04:31 +00:00
Mike Kinney
6883bc7afc fix more warnings; add to CI; suppress some warnings 2022-01-24 19:58:07 +00:00
co sto
a2eef895bd Create variant.h 2022-01-24 20:40:28 +01:00
co sto
64671c8ce7 Delete variants/heltev_v2.1 directory 2022-01-24 20:38:51 +01:00
Thomas Göttgens
252a27174e New checkout for library 2022-01-24 20:28:16 +01:00
Mike Kinney
7c362af3de more warning fixes 2022-01-24 18:39:17 +00:00
co sto
c6b851a2e6 Update variant.h 2022-01-24 19:01:23 +01:00
co sto
ec4346aba3 Update variant.h 2022-01-24 18:59:09 +01:00
co sto
791186a264 Create variant.h 2022-01-24 18:58:32 +01:00
co sto
ab947f06aa Delete .heltec_v2.1 2022-01-24 18:55:51 +01:00
co sto
cfa0ceb604 Create .heltec_v2.1 2022-01-24 18:55:26 +01:00
co sto
c7686ad57e Delete variant.h 2022-01-24 18:46:35 +01:00
co sto
8732b7cb4d Add files via upload 2022-01-24 18:45:51 +01:00
co sto
fe9dcbb316 Delete heltec_v2.1 2022-01-24 18:40:15 +01:00
co sto
38d1a381e6 Create heltec_v2.1 2022-01-24 18:35:25 +01:00
co sto
0b2f1d5675 Update platformio.ini 2022-01-24 18:33:31 +01:00
Mike Kinney
caaa235c5d more cppcheck warnings fixes 2022-01-24 17:24:40 +00:00
Thomas Göttgens
9a0126cde1 use the new version of Screen lib when building 2022-01-24 17:37:33 +01:00
co sto
39d0c0fd8f Merge branch 'meshtastic:master' into master 2022-01-24 14:00:33 +01:00
mkinney
be0b9979bc Merge pull request #3 from meshtastic/master
refresh branch from master
2022-01-23 23:02:02 -08:00
Mike Kinney
b3210f6c2c fix some cppcheck warnings 2022-01-24 07:00:14 +00:00
Jm Casler
2357240d84 Merge pull request #1136 from osmanovv/diy-v11
Meshtastic DIY v1.1 new schematic
2022-01-23 20:43:00 -08:00
co sto
c2f0048931 Merge branch 'meshtastic:master' into master 2022-01-24 00:14:42 +01:00
Vladislav Osmanov
d1ba314065 Meshtastic DIY v1.1 new schematic 2022-01-23 23:44:58 +03:00
Jm Casler
8a79ede285 Merge pull request #1135 from mc-hamster/master
Protos regened for reply and tapback
2022-01-23 09:31:26 -08:00
Jm Casler
c8ecd6ac8e Protos regened for reply and tapback 2022-01-23 09:30:44 -08:00
Jm Casler
13226adb2a updating proto submodule to latest 2022-01-23 09:10:33 -08:00
Ben Meadors
e706aae41d Added NRF/RAK support for env plugin (#1133)
* Added NRF/RAK support for env plugin

* Added Environmental mixin to platform io
2022-01-23 10:05:39 -06:00
co sto
91ad0df11c Update variant.h 2022-01-23 17:04:55 +01:00
co sto
976627d974 Merge branch 'meshtastic:master' into master 2022-01-23 14:20:29 +01:00
Jm Casler
6830f9861a Merge pull request #1132 from mc-hamster/master
set the routerMessage buffer to Constants_DATA_PAYLOAD_LEN
2022-01-23 02:14:55 -08:00
Jm Casler
2db307fc8d Merge branch 'meshtastic:master' into master 2022-01-23 01:05:36 -08:00
Jm Casler
7fae43e1a5 Merge branch 'master' of https://github.com/mc-hamster/Meshtastic-device 2022-01-23 01:05:09 -08:00
Jm Casler
8b60226497 set the routerMessage buffer to Constants_DATA_PAYLOAD_LEN 2022-01-23 01:05:07 -08:00
Jm Casler
ab8083dec4 Merge pull request #1131 from mc-hamster/master
Fixes PIO code inspector
2022-01-23 01:01:50 -08:00
Jm Casler
a561713a48 Merge branch 'meshtastic:master' into master 2022-01-23 00:29:54 -08:00
Jm Casler
00f3996cee Merge branch 'master' of https://github.com/mc-hamster/Meshtastic-device 2022-01-23 00:29:24 -08:00
Jm Casler
9e4e79c5d7 Fixes PIO code inspector 2022-01-23 00:29:16 -08:00
Ben Meadors
61e1b8d859 Set lastMeasurementPacket as one we're sending (#1130) 2022-01-22 19:24:47 -06:00
mkinney
165e8e8cba Merge pull request #1127 from mkinney/add_docker
initial dockerfile and notes
2022-01-22 14:02:19 -08:00
mkinney
635fbcf0d5 Merge branch 'master' into add_docker 2022-01-22 13:34:29 -08:00
mkinney
815222ad80 Merge pull request #1128 from osmanovv/diy-rfm95
RFM95/SX127x support in DIY
2022-01-22 13:34:17 -08:00
mkinney
64a9f15b1c Merge branch 'master' into add_docker 2022-01-22 13:16:20 -08:00
Ben Meadors
abcdf39b20 Merge branch 'master' into diy-rfm95 2022-01-22 15:09:57 -06:00
Ben Meadors
16ee75313a BME280 support for environment and screen re-org (#1129) 2022-01-22 15:09:17 -06:00
Vladislav Osmanov
bfd9938507 RFM95/SX127x support in DIY 2022-01-22 16:13:52 +03:00
Mike Kinney
01f5f1b5ba initial dockerfile and notes 2022-01-22 00:01:32 -08:00
Ben Meadors
b6706c7ac1 Admin message shutdown feature (#1124)
* Shutdown via proto admin message
2022-01-21 15:03:26 -06:00
Thomas Göttgens
7723b30951 Custom_ArialMT_Plain_10 not used anywhere (#1122) 2022-01-21 09:53:57 -06:00
Ben Meadors
6d34151590 Admin message shutdown protobufs (#1119)
* Updated protos for admin message shutdown protobufs
2022-01-20 21:43:15 -06:00
co sto
2230cbbe2a Correction for wrong battery display on tlora_v2_1_16 board (#1120)
* Update variant.h
2022-01-20 20:47:30 -06:00
co sto
b49ba55658 Merge branch 'master' into master 2022-01-21 02:37:39 +01:00
co sto
0864154157 Update platformio.ini 2022-01-21 02:26:59 +01:00
co sto
c4f64b1592 Update variant.h 2022-01-21 02:09:25 +01:00
co sto
001d054924 Update platformio.ini 2022-01-21 02:07:29 +01:00
mkinney
5e590a4a5e Merge pull request #1118 from meshtastic/mkinney-patch-1
Update README.md
2022-01-20 10:57:17 -08:00
mkinney
22a2fe2cb4 Update README.md
add github downloads badge
2022-01-20 10:16:18 -08:00
mkinney
f047ae6792 Update README.md
add ci badge
2022-01-20 10:04:43 -08:00
Ben Meadors
e1ef495071 Add tlora-v2-1-1.6 to default envs for consistency (#1117) 2022-01-20 08:34:03 -06:00
Jm Casler
209c6253a6 updating proto submodule to latest 2022-01-19 18:18:55 -08:00
mkinney
1acabb9d35 Merge pull request #1110 from prampec/master
Temporary fix on canned messages total length.
2022-01-19 16:14:56 -08:00
mkinney
420495cb2d Merge branch 'master' into master 2022-01-19 15:45:58 -08:00
Ben Meadors
9309824874 RAK / NRF shutdown functionality on user button long press (#1113) 2022-01-19 17:10:02 -06:00
Balázs Kelemen
4fc443e760 Merge branch 'meshtastic:master' into master 2022-01-19 17:22:34 +01:00
Balazs Kelemen
53399f06e5 Canned message plugin status fix. 2022-01-19 09:55:06 +01:00
Ben Meadors
4e3fda87a1 Initial configuration.h -> variants refactor (#1104)
* Initial configuration to variants refactor
2022-01-18 18:35:42 -06:00
Balazs Kelemen
1ff3b3326c Temporary fix on canned messages total length. 2022-01-18 23:15:54 +01:00
mkinney
9f0ddda6ca Merge pull request #1107 from mkinney/fix_warning
change name of define because MAX_BLOCKSIZE is already taken
2022-01-17 23:14:26 -08:00
mkinney
8e3d30bd7f Merge branch 'master' into fix_warning 2022-01-17 22:44:01 -08:00
mkinney
6ca3186bff Merge pull request #1106 from mkinney/add_more_env_sensors
add DHT22
2022-01-17 22:17:48 -08:00
Mike Kinney
68fadfe26c change name of define because MAX_BLOCKSIZE is already taken 2022-01-18 06:13:43 +00:00
Jm Casler
92bcdb5e53 updating proto submodule to latest 2022-01-17 09:23:29 -08:00
Jm Casler
04b1948ee9 Merge pull request #1105 from prampec/master
CannedMessagePlugin typo fix.
2022-01-16 22:46:57 -08:00
Mike Kinney
6fdc16017a revert the cheking for esptool 2022-01-17 02:31:25 +00:00
Mike Kinney
7f759d6bb5 Merge remote-tracking branch 'prampec/master' into add_more_env_sensors 2022-01-17 00:03:14 +00:00
Mike Kinney
1f227797c1 updated file after updating protobufs 2022-01-16 23:54:10 +00:00
Mike Kinney
ab87c0a9ee updating proto 2022-01-16 23:49:18 +00:00
Mike Kinney
6d960918e2 minor change to re-trigger ci 2022-01-16 15:22:17 -08:00
Mike Kinney
5797e32461 add support for other 2 sensors 2022-01-16 15:16:03 -08:00
Mike Kinney
41da6c3b99 add DHT22 2022-01-16 15:06:34 -08:00
Balazs Kelemen
fe3a352511 CannedMessagePlugin typo fix. 2022-01-16 23:18:40 +01:00
Jm Casler
b53f4214bc Merge pull request #1099 from mc-hamster/master
AirTime - fix bug in array shifter
2022-01-15 15:28:39 -08:00
Jm Casler
b6b1bcc5ad Merge branch 'meshtastic:master' into master 2022-01-15 15:27:45 -08:00
Jm Casler
91117ca7c6 AirTime - fix bug in array shifter 2022-01-15 15:27:25 -08:00
Jm Casler
2d8e55a34e Merge pull request #1098 from mc-hamster/master
Airtime - calculate ms in a hour in preprocessor
2022-01-15 12:24:50 -08:00
Jm Casler
3a7292d3d0 Merge branch 'meshtastic:master' into master 2022-01-15 12:24:31 -08:00
Jm Casler
3fea1c4e5f Merge branch 'master' of https://github.com/mc-hamster/Meshtastic-device 2022-01-15 12:24:17 -08:00
Jm Casler
c2435470c1 Airtime - calculate ms in a hour in preprocessor 2022-01-15 12:24:16 -08:00
Jm Casler
1c993c10a1 Merge pull request #1097 from mc-hamster/master
airtime - reuse some functions
2022-01-15 11:20:33 -08:00
Jm Casler
0a62ce23af Merge branch 'master' into master 2022-01-15 11:20:21 -08:00
Jm Casler
38efb8b3ad Merge branch 'master' of https://github.com/mc-hamster/Meshtastic-device 2022-01-15 11:19:52 -08:00
Jm Casler
9ee7f5e0bd airtime - reuse some functions 2022-01-15 11:19:50 -08:00
Jm Casler
c798e1a2da Merge pull request #1096 from mc-hamster/master
Airtime - removed debug message
2022-01-15 09:51:46 -08:00
Jm Casler
7eb4713422 Merge branch 'meshtastic:master' into master 2022-01-15 09:51:10 -08:00
Jm Casler
a9ed26fdbc Merge pull request #1090 from prampec/CannedMessagePlugin
Canned message plugin
2022-01-15 09:50:39 -08:00
Jm Casler
a7451b6abe Airtime - removed debug message 2022-01-15 09:50:10 -08:00
Jm Casler
e61db642bc Merge pull request #1095 from mc-hamster/master
Add airtime tx calculation as a 1hr rolling window
2022-01-15 09:45:12 -08:00
Jm Casler
25a540c28b Add airtime tx calculation as a 1hr rolling window 2022-01-15 09:44:29 -08:00
Jm Casler
1993b8f8a6 updating proto submodule to latest 2022-01-15 09:34:11 -08:00
Jm Casler
38dd5612fd Merge branch 'master' into CannedMessagePlugin 2022-01-15 09:20:10 -08:00
Jm Casler
8a63c6f3a3 Merge pull request #1094 from mc-hamster/master
Fix borked airtime report in /json/reports
2022-01-15 08:25:46 -08:00
Jm Casler
778d13dee7 Merge branch 'meshtastic:master' into master 2022-01-15 08:25:11 -08:00
Jm Casler
2fd0d2baff Fixed borked airtime report in /json/reports
For: https://github.com/meshtastic/Meshtastic-device/issues/1086
2022-01-15 08:24:39 -08:00
Jm Casler
399792803a Merge pull request #1092 from mkinney/add_quotes_in_device_install
add quotes around PYTHON; add check for esptool
2022-01-15 07:49:30 -08:00
Mike Kinney
8a6bbcb985 add quotes around PYTHON; add check for esptool 2022-01-14 10:40:18 -08:00
Jm Casler
419349e13e Merge branch 'master' into CannedMessagePlugin 2022-01-13 17:31:12 -08:00
Jm Casler
6b0770fdd5 Merge pull request #1088 from markbirss/master
Fix SSD1306 OLED pinout on TLORA_V1_3
2022-01-13 17:22:21 -08:00
Jm Casler
ee2b05da78 Merge branch 'master' into master 2022-01-13 16:56:06 -08:00
Jm Casler
d900847bab updating proto submodule to latest 2022-01-13 16:55:20 -08:00
Ben Meadors
8b56ebd566 Merge branch 'master' into CannedMessagePlugin 2022-01-13 13:20:02 -06:00
Balazs Kelemen
a1f80f024e CannedMessagePlugin merge fix 2022-01-13 14:19:55 +01:00
Balazs Kelemen
41de8a1309 Relocate 'input' folder. 2022-01-13 14:17:21 +01:00
Balazs Kelemen
33f08364e4 Reset plugin in case of inactivity. 2022-01-13 14:17:21 +01:00
Balazs Kelemen
c5b95ed3c0 Screen update event. 2022-01-13 14:17:21 +01:00
Balazs Kelemen
f7c8cabdfe Screen drawing routine goes to Plugin. 2022-01-13 14:17:20 +01:00
Balazs Kelemen
0f1c424731 Rotary get rid of duplicate methods. 2022-01-13 14:17:20 +01:00
Balazs Kelemen
3fa00f603b Make all variables configurable. 2022-01-13 14:17:16 +01:00
Balazs Kelemen
f5004a66a1 Introduce InputBroker 2022-01-13 14:15:53 +01:00
Balazs Kelemen
b832b82ec6 Use init() instead of constructor. 2022-01-13 14:15:53 +01:00
Balazs Kelemen
fbd5b8b721 Canned message bugfixes. 2022-01-13 14:15:53 +01:00
Balazs Kelemen
772dfe39dc Combine rotary with canned messages. 2022-01-13 14:15:53 +01:00
Balazs Kelemen
c7e62142e9 RotaryEncoderInterruptBase 2022-01-13 14:15:53 +01:00
Balazs Kelemen
6eb2b33124 Fix rotary glitch. 2022-01-13 14:15:53 +01:00
Balazs Kelemen
b3ddf16d64 Display sending state. 2022-01-13 14:15:53 +01:00
Balazs Kelemen
4a29aef19e Show previous and next message in list. 2022-01-13 14:15:53 +01:00
Balazs Kelemen
7b8849493f Adding screen frame 2022-01-13 14:15:53 +01:00
Balazs Kelemen
2b588f1567 CannedMessagePlugin initial commit 2022-01-13 14:15:53 +01:00
Mark Trevor Birss
975f7c0332 Fix SSD1306 OLED pinout on TLORA_V1_3
The V1.3 board OLED pinout changed from V1
Now on pin SDA(21) and SCL(22) not SDA(4) and SCL(15)

LILYGO Product Page
http://www.lilygo.cn/prod_view.aspx?TypeId=50060&Id=1253&FId=t3:50060:3

Product Pin
https://ae01.alicdn.com/kf/H098cb5d5159841b398fcfd4ebf705725W.jpg
2022-01-13 10:28:02 +02:00
224 changed files with 5994 additions and 3456 deletions

76
.github/ISSUE_TEMPLATE/Bug Report.yml vendored Normal file
View File

@@ -0,0 +1,76 @@
name: Bug Report
description: File a bug report
title: "[Bug]: "
labels: ["bug", "triage"]
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report!
- type: dropdown
id: category
attributes:
label: Category
description: How would you catagorize this issue?
multiple: true
options:
- Hardware Compatibility
- BLE
- Serial
- WiFi
- Other
validations:
required: true
- type: dropdown
id: hardware
attributes:
label: Hardware
description: What hardware are you encountering this issue on?
multiple: true
options:
- Not Applicable
- T-Beam
- T-Beam 0.7
- T-Lora v1
- T-Lora v1.3
- T-Lora v2 1.6
- T-Echo
- Rak4631
- Rak11200
- Heltec v1
- Heltec v2
- Heltec v2.1
- Relay v1
- Relay v2
- DIY
- Other
validations:
required: true
- type: input
id: version
attributes:
label: Firmware Version
description: This can be found on the device's screen or via one of the apps.
placeholder: x.x.x.yyyyyyy
validations:
required: true
- type: textarea
id: body
attributes:
label: Description
description: Please provide details on what steps you performed for this to happen.
validations:
required: true
- type: textarea
id: logs
attributes:
label: Relevant log output
description: If you have any log output to help in diagnosing your bug, please provide it here.
render: Shell
validations:
required: false

View File

@@ -1,38 +0,0 @@
---
name: Bug report or feature proposal
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
Please - if you just have a question (i.e. not a bug report or a feature proposal), post in our [forum](https://meshtastic.discourse.group/) instead.
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Device info:**
- Device model: [e.g. TBEAM]
- Software Version [e.g. 0.7.8]
**Smartphone information (if relevant):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- App Version [e.g. 0.7.2]
**Additional context**
Add any other context about the problem here.

View File

@@ -1,39 +0,0 @@
name: 'Common init'
# WARNING due to https://github.com/actions/runner/issues/646
# this code can't work - must copy and paste into workflows for now because 'uses' is not supported
runs:
using: "composite"
steps:
- 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
# Don't cache for now because I want to be lazy with portuino updates githashes
# - 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

View File

@@ -1,21 +1,11 @@
name: Continuous Integration
name: Continuous Integration (Legacy serial build)
on:
# Triggers the workflow on push or pull request events but only for the master branch
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
# setup:
# runs-on: ubuntu-latest
# steps:
workflow_dispatch:
# - name: Startup
# run: echo "No action setup currently needed, skipping..."
jobs:
ci-build:
# needs: setup
ci-check:
runs-on: ubuntu-latest
steps:
@@ -23,6 +13,12 @@ jobs:
uses: actions/checkout@v2
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
@@ -36,9 +32,42 @@ jobs:
path: ~/.cache/pip
key: ${{ runner.os }}-pip
#- name: Install linux apt packages
# run: |
# sudo apt-get install -y libgpiod-dev
- 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@v2
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
@@ -81,22 +110,23 @@ jobs:
echo "Simulator started, launching python test..."
python3 -c 'from meshtastic.test import testSimulator; testSimulator()'
# - name: Build for tbeam
# run: platformio run -e tbeam
# - name: Build for heltec
# run: platformio run -e heltec
# - name: Build for wisblock RAK4631
# run: platformio run -e rak4631
- 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: built
path: release/archive/firmware-*.zip
retention-days: 30
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
@@ -104,3 +134,18 @@ jobs:
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

345
.github/workflows/main_matrix.yml vendored Normal file
View File

@@ -0,0 +1,345 @@
name: Continuous Integration
on:
# # Triggers the workflow on push but only for the master branch
push:
branches: [ master ]
paths-ignore:
- '**.md'
- '**.yml'
- 'version.properties'
# Note: This is different from "pull_request". Need to specify ref when doing checkouts.
pull_request_target:
branches: [ master ]
paths-ignore:
- '**.md'
- '**.yml'
workflow_dispatch:
jobs:
check:
strategy:
fail-fast: false
matrix:
include:
- board: rak11200
- board: tlora-v2
- board: tlora-v1
- board: tlora_v1_3
- board: tlora-v2-1-1.6
- board: tbeam
- board: heltec-v1
- board: heltec-v2.0
- board: heltec-v2.1
- board: tbeam0.7
- board: meshtastic-diy-v1
- board: rak4631_5005
- board: rak4631_19003
- board: rak4631_5005_eink
- board: t-echo
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
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 ${{ matrix.board }}
run: bin/check-all.sh ${{ matrix.board }}
build-esp32:
strategy:
fail-fast: false
matrix:
include:
- board: rak11200
- board: tlora-v2
- board: tlora-v1
- board: tlora_v1_3
- board: tlora-v2-1-1.6
- board: tbeam
- board: heltec-v1
- board: heltec-v2.0
- board: heltec-v2.1
- board: tbeam0.7
- board: meshtastic-diy-v1
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
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
run: |
python -m pip install --upgrade pip
pip install -U platformio meshtastic adafruit-nrfutil littlefs-python
- 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
- name: Build ESP32
run: bin/build-esp32.sh ${{ matrix.board }}
- 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-${{ matrix.board }}-${{ steps.version.outputs.version }}.zip
path: |
release/*.bin
release/*.elf
retention-days: 90
build-nrf52:
strategy:
fail-fast: false
max-parallel: 2
matrix:
include:
- board: rak4631_5005
- board: rak4631_19003
- board: rak4631_5005_eink
- board: t-echo
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
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
run: |
python -m pip install --upgrade pip
pip install -U platformio meshtastic adafruit-nrfutil
- name: Upgrade platformio
run: |
pio upgrade
- name: Build NRF52
run: bin/build-nrf52.sh ${{ matrix.board }}
- 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-${{ matrix.board }}-${{ steps.version.outputs.version }}.zip
path: |
release/*.uf2
release/*.elf
retention-days: 90
build-native:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
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
run: |
python -m pip install --upgrade pip
pip install -U platformio meshtastic adafruit-nrfutil
- name: Upgrade platformio
run: |
pio upgrade
# 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: Build Native
run: bin/build-native.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-native-${{ steps.version.outputs.version }}.zip
path: |
release/meshtasticd_linux_amd64
release/device-*.sh
release/device-*.bat
retention-days: 90
after-checks:
runs-on: ubuntu-latest
needs: [check]
steps:
- name: Checkout code
uses: actions/checkout@v2
with:
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
gather-artifacts:
runs-on: ubuntu-latest
needs: [build-esp32, build-nrf52, build-native]
steps:
- name: Checkout code
uses: actions/checkout@v2
with:
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
- uses: actions/download-artifact@v2
with:
path: ./
- name: Get release version string
run: echo "::set-output name=version::$(./bin/buildinfo.py long)"
id: version
- name: Move files up
run: mv -b -t ./ ./*tbeam-*/littlefs*.bin ./*tbeam-*/system-info.bin ./**/firmware*.bin ./**/*.uf2 ./**/*.elf ./**/meshtasticd_linux_amd64 ./*native*/*device-*.sh ./*native*/*device-*.bat
- name: Repackage in single firmware zip
uses: actions/upload-artifact@v2
with:
name: firmware-${{ steps.version.outputs.version }}
path: |
./*.bin
./*.uf2
./meshtasticd_linux_amd64
./device-*.sh
./device-*.bat
retention-days: 90
- uses: actions/download-artifact@v2
with:
name: firmware-${{ steps.version.outputs.version }}
path: ./output
# For diagnostics
- name: Show artifacts
run: ls -lR
- name: Zip firmware
run: zip -j -r ./firmware-${{ steps.version.outputs.version }}.zip ./output
- name: Repackage in single elfs zip
uses: actions/upload-artifact@v2
with:
name: debug-elfs-${{ steps.version.outputs.version }}.zip
path: ./*.elf
retention-days: 90
- name: Create 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,7 +1,7 @@
name: Make Release
on:
# Can optionally take parameters from the github UI, more info here https://github.blog/changelog/2020-07-06-github-actions-manual-triggers-with-workflow_dispatch/#:~:text=You%20can%20now%20create%20workflows,the%20workflow%20is%20run%20on.
# workflow_dispatch:
workflow_dispatch:
# inputs:
# Only want to run if version.properties is bumped in master
@@ -37,7 +37,7 @@ jobs:
# if: steps.cache-pip.outputs.cache-hit != 'true'
run: |
python -m pip install --upgrade pip
pip install -U platformio meshtastic adafruit-nrfutil
pip install -U platformio meshtastic adafruit-nrfutil littlefs-python
- name: Upgrade platformio
run: |

View File

@@ -1,4 +1,4 @@
name: "Update protobufs"
name: "Update protobufs and regenerate classes"
on: workflow_dispatch
jobs:
@@ -11,14 +11,23 @@ jobs:
with:
submodules: true
- name: Update Submodule
- name: Update submodule
run: |
git pull --recurse-submodules
git submodule update --remote --recursive
- name: Commit update
git submodule update --remote proto
- name: Download nanopb
run: |
git config --global user.name 'github-actions'
git config --global user.email 'bot@noreply.github.com'
git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}
git add proto
git commit -m "Update protobuf submodule" && git push || echo "No changes to commit"
wget https://jpa.kapsi.fi/nanopb/download/nanopb-0.4.4-linux-x86.tar.gz
tar xvzf nanopb-0.4.4-linux-x86.tar.gz
mv nanopb-0.4.4-linux-x86 nanopb-0.4.4
- name: Re-generate protocol buffers
run: |
./bin/regen-protos.sh
- name: Create pull request
uses: peter-evans/create-pull-request@v3
with:
add-paths: |
proto
src/mesh

3
.gitignore vendored
View File

@@ -26,3 +26,6 @@ __pycache__
*.swp
*.swo
*~
venv/
release/

View File

@@ -1,8 +1,11 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"platformio.platformio-ide",
"xaver.clang-format"
]
}
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"platformio.platformio-ide",
"xaver.clang-format"
],
"unwantedRecommendations": [
"ms-vscode.cpptools-extension-pack"
]
}

16
Dockerfile Normal file
View File

@@ -0,0 +1,16 @@
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"]

72
README-docker.md Normal file
View File

@@ -0,0 +1,72 @@
## What is Docker used for
Developers can simulate Device hardware by compiling and running
a linux native binary application. If you do not own a Linux
machine, or you just want to separate things, you might want
to run simulator inside a docker container
## The Image
To build docker image, type
`docker build -t meshtastic/device .`
## Usage
To run a container, type
`docker run --rm -p 4403:4403 meshtastic/device`
or, to get an interactive shell on the docker created container:
`docker run -it -p 4403:4403 meshtastic/device bash`
You might want to mount your local development folder:
`docker run -it --mount type=bind,source=/PathToMyProjects/Meshtastic/Meshtastic-device-mybranch,target=/Meshtastic-device-mybranch -p 4403:4403 meshtastic/device bash`
## Build the native application
Linux native application should be built inside the container.
For this you must run container with interactive console
"-it", as seen above.
First, some environment variables need to be set up with command:
`. ~/.platformio/penv/bin/activate`
You also want to make some adjustments in the bin/build-all.sh to conform the amd64 build:
```
sed -i 's/^BOARDS_ESP32.*/BOARDS_ESP32=""/' bin/build-all.sh
sed -i 's/^BOARDS_NRF52.*/BOARDS_NRF52=""/' bin/build-all.sh
sed -i 's/echo "Building SPIFFS.*/exit/' bin/build-all.sh
```
You can build amd64 image with command
`bin/build-all.sh`
## Executing the application interactively
The built binary file should be found under name
`release/latest/bins/universal/meshtastic_linux_amd64`.
If this is not the case, you can also use direct program name:
`.pio/build/native/program`
To use python cli against exposed port 4403,
type this in the host machine:
`meshtastic --info --host localhost`
## Stop the container
Run this to get the ID:
`docker ps`
Stop the container with command:
`docker kill <id>`
> Tip: you can just use the first few characters of the ID in docker commands

View File

@@ -1,11 +1,18 @@
# Meshtastic-device
[![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 all releases](https://img.shields.io/github/downloads/meshtastic/meshtastic-device/total)
## This repository contains the device firmware used in the [Meshtastic](https://meshtastic.org) project.
Update Instructions
[Using Meshtastic Flasher](https://meshtastic.org/docs/getting-started/meshtastic-flasher)
Manual Method
[For ESP32 devices click here](https://meshtastic.org/docs/getting-started/flashing-esp32)
[For nRF52 devices click here](https://meshtastic.org/docs/getting-started/flashing-nrf52)
For developer information and specific building instructions, please see the [developer doccumentation](https://meshtastic.org/docs/developers)
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`
SHORT_VERSION=`bin/buildinfo.py short`
BOARDS_ESP32="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"
#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
BOARDS_NRF52="rak4631_5005 rak4631_19003 t-echo"
BOARDS_NRF52="rak4631_5005 rak4631_5005_eink rak4631_19003 t-echo"
#BOARDS_NRF52=""
OUTDIR=release/latest
@@ -28,7 +28,7 @@ function do_build() {
BOARD=$1
isNrf=$3
echo "Building for $BOARD with $PLATFORMIO_BUILD_FLAGS"
echo "Building for $BOARD ($isNrf) with $PLATFORMIO_BUILD_FLAGS"
rm -f .pio/build/$BOARD/firmware.*
# The shell vars the build tool expects to find
@@ -59,6 +59,7 @@ function do_boards() {
declare isNrf=$2
for board in $boards; do
# Build universal
echo "about to build $board $isNrf"
do_build $board "" "$isNrf"
done
}
@@ -75,12 +76,12 @@ do_boards "$BOARDS_NRF52" "true"
pio run --environment native
cp .pio/build/native/program $OUTDIR/bins/universal/meshtasticd_linux_amd64
echo "Building SPIFFS for ESP32 targets"
echo "Building Filesystem for ESP32 targets"
pio run --environment tbeam -t buildfs
cp .pio/build/tbeam/spiffs.bin $OUTDIR/bins/universal/spiffs-$VERSION.bin
cp .pio/build/tbeam/spiffs.bin $OUTDIR/bins/universal/littlefs-$VERSION.bin
# keep the bins in archive also
cp $OUTDIR/bins/universal/spiffs* $OUTDIR/bins/universal/firmware* $OUTDIR/elfs/universal/firmware* $ARCHIVEDIR
cp $OUTDIR/bins/universal/littlefs* $OUTDIR/bins/universal/firmware* $OUTDIR/elfs/universal/firmware* $ARCHIVEDIR
echo Updating android bins $OUTDIR/forandroid
rm -rf $OUTDIR/forandroid
@@ -102,9 +103,9 @@ XML
echo Generating $ARCHIVEDIR/firmware-$VERSION.zip
rm -f $ARCHIVEDIR/firmware-$VERSION.zip
zip --junk-paths $ARCHIVEDIR/firmware-$VERSION.zip $ARCHIVEDIR/spiffs-$VERSION.bin $OUTDIR/bins/universal/firmware-*-$VERSION.* $OUTDIR/bins/universal/meshtasticd* images/system-info.bin bin/device-install.* bin/device-update.*
zip --junk-paths $ARCHIVEDIR/firmware-$VERSION.zip $ARCHIVEDIR/littlefs-$VERSION.bin $OUTDIR/bins/universal/firmware-*-$VERSION.* $OUTDIR/bins/universal/meshtasticd* images/system-info.bin bin/device-install.* bin/device-update.*
echo Generating $ARCHIVEDIR/elfs-$VERSION.zip
rm -f $ARCHIVEDIR/elfs-$VERSION.zip
zip --junk-paths $ARCHIVEDIR/elfs-$VERSION.zip $OUTDIR/elfs/universal/firmware-*-$VERSION.*
zip --junk-paths $ARCHIVEDIR/elfs-$VERSION.zip $OUTDIR/elfs/universal/firmware-*-$VERSION.*
echo BUILT ALL

43
bin/build-esp32.sh Executable file
View File

@@ -0,0 +1,43 @@
#!/usr/bin/env bash
set -e
VERSION=`bin/buildinfo.py long`
SHORT_VERSION=`bin/buildinfo.py short`
OUTDIR=release/
rm -f $OUTDIR/firmware*
rm -r $OUTDIR/* || true
# Make sure our submodules are current
git submodule update
# Important to pull latest version of libs into all device flavors, otherwise some devices might be stale
platformio lib update
echo "Building for $1 with $PLATFORMIO_BUILD_FLAGS"
rm -f .pio/build/$1/firmware.*
# The shell vars the build tool expects to find
export APP_VERSION=$VERSION
# Are we building a universal/regionless rom?
export HW_VERSION="1.0"
basename=firmware-$1-$VERSION
pio run --environment $1 # -v
SRCELF=.pio/build/$1/firmware.elf
cp $SRCELF $OUTDIR/$basename.elf
echo "Copying ESP32 bin file"
SRCBIN=.pio/build/$1/firmware.bin
cp $SRCBIN $OUTDIR/$basename.bin
echo "Building Filesystem for ESP32 targets"
pio run --environment tbeam -t buildfs
cp .pio/build/tbeam/spiffs.bin $OUTDIR/littlefs-$VERSION.bin
cp images/system-info.bin $OUTDIR/system-info.bin
cp bin/device-install.* $OUTDIR
cp bin/device-update.* $OUTDIR

26
bin/build-native.sh Executable file
View File

@@ -0,0 +1,26 @@
#!/usr/bin/env bash
set -e
VERSION=`bin/buildinfo.py long`
SHORT_VERSION=`bin/buildinfo.py short`
OUTDIR=release/
rm -f $OUTDIR/firmware*
mkdir -p $OUTDIR/
rm -r $OUTDIR/* || true
# Make sure our submodules are current
git submodule update
# Important to pull latest version of libs into all device flavors, otherwise some devices might be stale
platformio lib update
pio run --environment native
cp .pio/build/native/program $OUTDIR/meshtasticd_linux_amd64
cp bin/device-install.* $OUTDIR
cp bin/device-update.* $OUTDIR

37
bin/build-nrf52.sh Executable file
View File

@@ -0,0 +1,37 @@
#!/usr/bin/env bash
set -e
VERSION=`bin/buildinfo.py long`
SHORT_VERSION=`bin/buildinfo.py short`
OUTDIR=release/
rm -f $OUTDIR/firmware*
rm -r $OUTDIR/* || true
# Make sure our submodules are current
git submodule update
# Important to pull latest version of libs into all device flavors, otherwise some devices might be stale
platformio lib update
echo "Building for $1 with $PLATFORMIO_BUILD_FLAGS"
rm -f .pio/build/$1/firmware.*
# The shell vars the build tool expects to find
export APP_VERSION=$VERSION
export HW_VERSION="1.0"
basename=firmware-$1-$VERSION
pio run --environment $1 # -v
SRCELF=.pio/build/$1/firmware.elf
cp $SRCELF $OUTDIR/$basename.elf
echo "Generating NRF52 uf2 file"
SRCHEX=.pio/build/$1/firmware.hex
bin/uf2conv.py $SRCHEX -c -o $OUTDIR/$basename.uf2 -f 0xADA52840
cp bin/device-install.* $OUTDIR
cp bin/device-update.* $OUTDIR

26
bin/check-all.sh Executable file
View File

@@ -0,0 +1,26 @@
#!/usr/bin/env bash
# Note: This is a prototype for how we could add static code analysis to the CI.
set -e
VERSION=`bin/buildinfo.py long`
# The shell vars the build tool expects to find
export APP_VERSION=$VERSION
if [[ $# -gt 0 ]]; then
# can override which environment by passing arg
BOARDS="$@"
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"
fi
echo "BOARDS:${BOARDS}"
CHECK=""
for BOARD in $BOARDS; do
CHECK="${CHECK} -e ${BOARD}"
done
pio check --flags "-DAPP_VERSION=${APP_VERSION} --suppressions-list=suppressions.txt" $CHECK --skip-packages --pattern="src/" --fail-on-defect=low --fail-on-defect=medium --fail-on-defect=high

View File

@@ -30,7 +30,7 @@ IF EXIST %FILENAME% (
echo Trying to flash update %FILENAME%, but first erasing and writing system information"
%PYTHON% -m esptool --baud 921600 erase_flash
%PYTHON% -m esptool --baud 921600 write_flash 0x1000 system-info.bin
for %%f in (spiffs-*.bin) do (
for %%f in (littlefs-*.bin) do (
%PYTHON% -m esptool --baud 921600 write_flash 0x00390000 %%f
)
%PYTHON% -m esptool --baud 921600 write_flash 0x10000 %FILENAME%

View File

@@ -11,7 +11,7 @@ Usage: $(basename $0) [-h] [-p ESPTOOL_PORT] [-P PYTHON] [-f FILENAME|FILENAME]
Flash image file to device, but first erasing and writing system information"
-h Display this help and exit
-p ESPTOOL_PORT Set the environment variable for ESPTOOL_PORT. If not set, ESPTOOL iterates all ports (Dangerrous).
-p ESPTOOL_PORT Set the environment variable for ESPTOOL_PORT. If not set, ESPTOOL iterates all ports (Dangerous).
-P PYTHON Specify alternate python interpreter to use to invoke esptool. (Default: "$PYTHON")
-f FILENAME The .bin file to flash. Custom to your device type and region.
EOF
@@ -46,10 +46,10 @@ shift "$((OPTIND-1))"
if [ -f "${FILENAME}" ]; then
echo "Trying to flash ${FILENAME}, but first erasing and writing system information"
$PYTHON -m esptool erase_flash
$PYTHON -m esptool write_flash 0x1000 system-info.bin
$PYTHON -m esptool write_flash 0x00390000 spiffs-*.bin
$PYTHON -m esptool write_flash 0x10000 ${FILENAME}
"$PYTHON" -m esptool erase_flash
"$PYTHON" -m esptool write_flash 0x1000 system-info.bin
"$PYTHON" -m esptool write_flash 0x00390000 littlefs-*.bin
"$PYTHON" -m esptool write_flash 0x10000 ${FILENAME}
else
echo "Invalid file: ${FILENAME}"
show_help

51
bin/mklittlefs.py Executable file
View File

@@ -0,0 +1,51 @@
#!/usr/bin/env python3
import getopt
import sys
import os
from littlefs import LittleFS
from pathlib import Path
print( "Building LittleFS image..." )
argList = sys.argv[1:]
arxx = { argList[i]: argList[i+1] for i in range(0, len(argList)-1, 2) }
dataPath = arxx["-c"]
blockSize = int(arxx["-b"])
blockCount = int(arxx["-s"]) / blockSize
cwd = os.getcwd()
os.chdir(dataPath)
fileList = []
dirList = []
for (dirpath, dirnames, filenames) in os.walk('.'):
for f in filenames:
if (f[:1] != '.'):
fileList.append( os.path.join(dirpath, f) )
for d in dirnames:
if (d[:1] != '.'):
dirList.append( os.path.join(dirpath, d) )
fs = LittleFS(block_size=blockSize, block_count=blockCount) # create a 448kB partition
for curDir in dirList:
print( "Creating dir " + curDir )
fs.mkdir( curDir )
for curFile in fileList:
print( "Adding file " + curFile )
with open( curFile, 'rb' ) as f:
data = f.read()
with fs.open( curFile, 'wb') as fh:
fh.write( data )
outName = argList[-1]
os.chdir(cwd)
with open(outName, 'wb') as fh:
fh.write(fs.context.buffer)

View File

@@ -6,6 +6,13 @@ import traceback
import sys
from readprops import readProps
Import("env")
env.Replace( MKSPIFFSTOOL=env.get("PROJECT_DIR") + '/bin/mklittlefs.py' )
try:
import littlefs
except ImportError:
env.Execute("$PYTHONEXE -m pip install --user littlefs-python")
Import("projenv")
prefsLoc = projenv["PROJECT_DIR"] + "/version.properties"

View File

@@ -0,0 +1,39 @@
{
"build": {
"arduino":{
"ldscript": "esp32_out.ld"
},
"core": "esp32",
"extra_flags": "-DARDUINO_ESP32_DEV",
"f_cpu": "240000000L",
"f_flash": "40000000L",
"flash_mode": "dio",
"mcu": "esp32",
"variant": "WisCore_RAK11200_Board"
},
"connectivity": [
"wifi",
"bluetooth",
"ethernet",
"can"
],
"frameworks": [
"arduino",
"espidf"
],
"name": "WisCore RAK11200 Board",
"upload": {
"flash_size": "4MB",
"maximum_ram_size": 327680,
"maximum_size": 4194304,
"protocols": [
"esptool",
"espota",
"ftdi"
],
"require_upload_port": true,
"speed": 460800
},
"url": "https://www.rakwireless.com",
"vendor": "RAKwireless"
}

View File

@@ -63,7 +63,7 @@ You probably don't care about this section - skip to the next one.
## Multichannel support
* DONE cleanup the external notification and serial plugins
* DONE cleanup the external notification and serial modules
* non ack version of stress test fails sometimes!
* tx fault test has a bug #734 - * turn off fault 8: https://github.com/meshtastic/Meshtastic-device/issues/734
* DONE move device types into an enum in nodeinfo
@@ -71,7 +71,7 @@ You probably don't care about this section - skip to the next one.
* nrf52 should preserve local time across reset
* cdcacm bug on nrf52: emittx thinks it emitted but client sees nothing. works again later
* nrf52: segger logs have errors in formatting that should be impossible (because not going through serial, try stalling on segger)
* DONE call RouterPlugin for *all* packets - not just Router packets
* DONE call RouterModule for *all* packets - not just Router packets
* DONE generate channel hash from the name of the channel+the psk (not just one or the other)
* DONE send a hint that can be used to select which channel to try and hash against with each message
* DONE remove deprecated
@@ -79,13 +79,13 @@ You probably don't care about this section - skip to the next one.
* DONE set mynodeinfo.max_channels
* DONE set mynodeinfo.num_bands (formerly num_channels)
* DONE fix sniffing of non Routing packets
* DONE enable remote setttings access by moving settings operations into a regular plugin (move settings ops out of PhoneAPI)
* DONE enable remote setttings access by moving settings operations into a regular module (move settings ops out of PhoneAPI)
* DONE move portnum up?
* DONE remove region specific builds from the firmware
* DONE test single channel without python
* DONE Use "default" for name if name is empty
* DONE fix python data packet receiving (nothing showing in log?)
* DONE implement 'get channels' Admin plugin operation
* DONE implement 'get channels' Admin module operation
* DONE use get-channels from python
* DONE use get channels & get settings from android
* DONE use set-channel from python
@@ -98,7 +98,7 @@ You probably don't care about this section - skip to the next one.
* DONE fix setch-fast in python tool
* age out pendingrequests in the python API
* DONE stress test channel download from python, sometimes it seems like we don't get all replies, bug was due to simultaneous android connection
* DONE combine acks and responses in a single message if possible (do routing plugin LAST and drop ACK if someone else has already replied)
* DONE combine acks and responses in a single message if possible (do routing module LAST and drop ACK if someone else has already replied)
* DONE don't send packets we received from the phone BACK TOWARDS THE PHONE (possibly use fromnode 0 for packets the phone sends?)
* DONE fix 1.1.50 android debug panel display
* DONE test android channel setting
@@ -118,7 +118,7 @@ You probably don't care about this section - skip to the next one.
* use single byte 'well known' channel names for admin, gpio, etc...
* use presence of gpio channel to enable gpio ops, same for serial etc...
* DONE restrict gpio & serial & settings operations to the admin channel (unless local to the current node)
* DONE add channel restrictions for plugins (and restrict routing plugin to the "control" channel)
* DONE add channel restrictions for modules (and restrict routing module to the "control" channel)
* stress test multi channel
* DONE investigate @mc-hamster report of heap corruption
* DONE use set-user from android
@@ -134,7 +134,7 @@ You probably don't care about this section - skip to the next one.
* allow chaning packets in single transmission - to increase airtime efficiency and amortize packet overhead
* DONE move most parts of meshpacket into the Data packet, so that we can chain multiple Data for sending when they all have a common destination and key.
* when selecting a MeshPacket for transmit, scan the TX queue for any Data packets we can merge together as a WirePayload. In the low level send/rx code expand that into multiple MeshPackets as needed (thus 'hiding' from MeshPacket that over the wire we send multiple datapackets
* DONE confirm we are still calling the plugins for messages inbound from the phone (or generated locally)
* DONE confirm we are still calling the modules for messages inbound from the phone (or generated locally)
* DONE confirm we are still multi hop routing flood broadcasts
* DONE confirm we are still doing resends on unicast reliable packets
* add history to routed packets: https://meshtastic.discourse.group/t/packet-source-tracking/2764/2
@@ -142,7 +142,7 @@ You probably don't care about this section - skip to the next one.
* DONE move acks into routing
* DONE make all subpackets different versions of data
* DONE move routing control into a data packet
* have phoneapi done via plugin (will allow multiple simultaneous API clients - stop disabling BLE while using phone API)
* have phoneapi done via module (will allow multiple simultaneous API clients - stop disabling BLE while using phone API)
* use reference counting and dynamic sizing for meshpackets. - use https://docs.microsoft.com/en-us/cpp/cpp/how-to-create-and-use-shared-ptr-instances?view=msvc-160 (already used in arduino)
* let multiple PhoneAPI endpoints work at once
* allow multiple simultaneous bluetooth connections (create the bluetooth phoneapi instance dynamically based on client id)
@@ -182,13 +182,13 @@ For app cleanup:
* DONE require a recent python api to talk to these new device loads
* DONE require a recent android app to talk to these new device loads
* DONE fix handleIncomingPosition
* DONE move want_replies handling into plugins
* DONE move want_replies handling into modules
* DONE on android for received positions handle either old or new positions / user messages
* DONE on android side send old or new positions as needed / user messages
* DONE test python side handle new position/user messages
* DONE make a gpio example. --gpiowrb 4 1, --gpiord 0x444, --gpiowatch 0x3ff
* DONE fix position sending to use new plugin
* DONE Add SinglePortNumPlugin - as the new most useful baseclass
* DONE fix position sending to use new module
* DONE Add SinglePortNumModule - as the new most useful baseclass
* DONE move positions into regular data packets (use new app framework)
* DONE move user info into regular data packets (use new app framework)
* DONE test that positions, text messages and user info still work

View File

@@ -11,19 +11,27 @@
[platformio]
default_envs = tbeam
;default_envs = tbeam0.7
;default_envs = heltec-v2.0
;default_envs = heltec-v1
;default_envs = heltec-v2.0
;default_envs = heltec-v2.1
;default_envs = tlora-v1
;default_envs = tlora-v1
;default_envs = tlora_v1_3
;default_envs = tlora-v2
;default_envs = tlora-v2-1-1.6
;default_envs = lora-relay-v1 # nrf board
;default_envs = t-echo
;default_envs = nrf52840dk-geeksville
;default_envs = native # lora-relay-v1 # nrf52840dk-geeksville # linux # or if you'd like to change the default to something like lora-relay-v1 put that here
;default_envs = rak4631
;default_envs = rak4630
;default_envs = rak4631_5005
;default_envs = rak4631_5005_eink
;default_envs = rak4631_19003
;default_envs = meshtastic-diy-v1
;default_envs = meshtastic-diy-v1.1
; board specific config can be moved to the respective 'variants' file.
; See https://docs.platformio.org/en/latest/projectconf/section_platformio.html#extra-configs
extra_configs = variants/*/platformio.ini
[common]
; common is not currently used
@@ -70,7 +78,7 @@ debug_tool = jlink
; monitor adapter_khz 10000
lib_deps =
https://github.com/meshtastic/esp8266-oled-ssd1306.git#35d796226b853b0c0ff818b2f1aa3d35e7296a96 ; ESP8266_SSD1306
https://github.com/meshtastic/esp8266-oled-ssd1306.git#d90231dedbb2f52bd7a32fb8ed8edec52cf4a8cb ; ESP8266_SSD1306
https://github.com/meshtastic/OneButton.git#3bcba9492d01e2a8a86f46700ab16f96dd2cf1f5 ; OneButton library for non-blocking button debounce
1202 ; CRC32, explicitly needed because dependency is missing in the ble ota update lib
https://github.com/meshtastic/arduino-fsm.git
@@ -82,8 +90,12 @@ lib_deps =
SPI
https://github.com/geeksville/ArduinoThread.git#72921ac222eed6f526ba1682023cee290d9aa1b3
PubSubClient
; Common settings for conventional (non Portduino) Ardino targets
; Used for the code analysis in PIO Home / Inspect
check_tool = cppcheck
check_skip_packages = yes
; Common settings for conventional (non Portduino) Arduino targets
[arduino_base]
framework = arduino
@@ -96,6 +108,17 @@ build_flags = ${env.build_flags} -Os
src_filter = ${env.src_filter} -<portduino/>
; Common libs for environmental measurements (not included in native / portduino)
[environmental]
lib_deps =
adafruit/DHT sensor library@^1.4.1
adafruit/Adafruit Unified Sensor@^1.1.4
paulstoffregen/OneWire@^2.3.5
robtillaart/DS18B20@^0.1.11
adafruit/Adafruit BME280 Library@^2.2.2
adafruit/Adafruit BME680 Library@^2.0.1
adafruit/Adafruit MCP9808 Library@^2.0.0
; Common settings for ESP targes, mixin with extends = esp32_base
[esp32_base]
extends = arduino_base
@@ -114,14 +137,12 @@ build_flags =
-DAXP_DEBUG_PORT=Serial
lib_deps =
${arduino_base.lib_deps}
${environmental.lib_deps}
https://github.com/meshtastic/esp32_https_server.git
adafruit/DHT sensor library@^1.4.1
adafruit/Adafruit Unified Sensor@^1.1.4
paulstoffregen/OneWire@^2.3.5
robtillaart/DS18B20@^0.1.11
h2zero/NimBLE-Arduino@1.3.4
h2zero/NimBLE-Arduino@1.3.6
tobozo/ESP32-targz@^1.1.4
arduino-libraries/NTPClient#531eff39d9fbc831f3d03f706a161739203fbe2a
lorol/LittleFS_esp32@^1.0.6
# Hmm - this doesn't work yet
# board_build.ldscript = linker/esp32.extram.bss.ld
@@ -150,78 +171,6 @@ board_build.partitions = partition-table.csv
; -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG
; The 1.0 release of the TBEAM board
[env:tbeam]
extends = esp32_base
board = ttgo-t-beam
lib_deps =
${esp32_base.lib_deps}
build_flags =
${esp32_base.build_flags} -D TBEAM_V10
; The original TBEAM board without the AXP power chip and a few other changes
; Note: I've heard reports this didn't work. Disabled until someone with a 0.7 can test and debug.
[env:tbeam0.7]
extends = esp32_base
board = ttgo-t-beam
build_flags =
${esp32_base.build_flags} -D TBEAM_V07
[env:heltec-v1]
;build_type = debug ; to make it possible to step through our jtag debugger
extends = esp32_base
board = heltec_wifi_lora_32
build_flags =
${esp32_base.build_flags} -D HELTEC_V1
[env:heltec-v2.0]
;build_type = debug ; to make it possible to step through our jtag debugger
extends = esp32_base
board = heltec_wifi_lora_32_V2
build_flags =
${esp32_base.build_flags} -D HELTEC_V2_0
[env:heltec-v2.1]
;build_type = debug ; to make it possible to step through our jtag debugger
extends = esp32_base
board = heltec_wifi_lora_32_V2
build_flags =
${esp32_base.build_flags} -D HELTEC_V2_1
[env:tlora-v1]
extends = esp32_base
board = ttgo-lora32-v1
build_flags =
${esp32_base.build_flags} -D TLORA_V1
; note: the platformio definition for lora32-v2 seems stale, it is missing a pins_arduino.h file, therefore I don't think it works
[env:tlora_v1_3]
extends = esp32_base
board = ttgo-lora32-v1
build_flags =
${esp32_base.build_flags} -D TLORA_V1_3
[env:tlora-v2]
extends = esp32_base
board = ttgo-lora32-v1
build_flags =
${esp32_base.build_flags} -D TLORA_V2
[env:tlora-v2-1-1.6]
extends = esp32_base
board = ttgo-lora32-v1
build_flags =
${esp32_base.build_flags} -D TLORA_V2_1_16
; Meshtastic DIY v1 by Nano VHF Schematic based on ESP32-WROOM-32 (38 pins) devkit & EBYTE E22 SX1262/SX1268 module
[env:meshtastic-diy-v1]
extends = esp32_base
board = esp32doit-devkit-v1
build_flags =
${esp32_base.build_flags}
-D DIY_V1
-D EBYTE_E22
; The Heltec Cubecell plus
; IMPORTANT NOTE: This target doesn't yet work and probably won't ever work. I'm keeping it around for now.
; For more details see my post in the forum.
@@ -247,7 +196,7 @@ build_flags =
-Isdk-nrfxlib/crypto/nrf_oberon/include -Lsdk-nrfxlib/crypto/nrf_oberon/lib/cortex-m4/hard-float/ -lliboberon_3.0.7
;-DCFG_DEBUG=3
src_filter =
${arduino_base.src_filter} -<esp32/> -<nimble/> -<mesh/wifi/> -<mesh/http/> -<plugins/esp32> -<mqtt/>
${arduino_base.src_filter} -<esp32/> -<nimble/> -<mesh/wifi/> -<mesh/http/> -<modules/esp32> -<mqtt/>
lib_ignore =
BluetoothOTA
; monitor_port = /dev/ttyACM1
@@ -291,42 +240,17 @@ extends = nrf52_base
build_flags = ${nrf52_base.build_flags}
lib_deps =
${arduino_base.lib_deps}
${environmental.lib_deps}
Adafruit nRFCrypto
# Adafruit TinyUSB Arduino
# add Adafruit nRFCrypto platform IO automated scan is broken
[env:lora_isp4520]
extends = nrf52_base
board = lora_isp4520
# add our variants files to the include and src paths
build_flags = ${nrf52_base.build_flags} -Ivariants/lora_isp4520
# No screen and GPS on the board. We still need RTC.cpp for the RTC clock.
src_filter = ${nrf52_base.src_filter} +<../variants/lora_isp4520> -<graphics> -<gps> +<gps/GPS.cpp> +<gps/RTC.cpp>
lib_ignore = ${nrf52_base.lib_ignore}
ESP8266_SSD1306
SparkFun Ublox Arduino Library
AXP202X_Library
TinyGPSPlus
upload_protocol = jlink
monitor_port = /dev/ttyUSB0
; The NRF52840-dk development board
; Note: By default no lora device is created for this build - it uses a simulated interface
[env:nrf52840dk]
extends = nrf52840_base
board = nrf52840_dk
; The NRF52840-dk development board, but @geeksville's board - which has a busted oscilliator
[env:nrf52840dk-geeksville]
extends = nrf52840_base
board = nrf52840_dk_modified
# add our variants files to the include and src paths
build_flags = ${nrf52_base.build_flags} -Ivariants/pca10056-rc-clock
src_filter = ${nrf52_base.src_filter} +<../variants/pca10056-rc-clock>
; Note: By default no lora device is created for this build - it uses a simulated interface
[env:feather_nrf52832]
extends = nrf52_base
@@ -343,161 +267,3 @@ monitor_speed = 115200
# For experimenting with RAM sizes
# board_build.ldscript = linker/nrf52840_s140_sim832.ld
; The very slick RAK wireless RAK 4631 / 4630 board
[env:rak4631_5005]
extends = nrf52840_base
board = wiscore_rak4631
# add our variants files to the include and src paths
# define build flags for the TFT_eSPI library
build_flags = ${nrf52840_base.build_flags} -Ivariants/WisCore_RAK4631_Board -D RAK_BASE_5005
src_filter = ${nrf52_base.src_filter} +<../variants/WisCore_RAK4631_Board>
debug_tool = jlink
[env:rak4631_19003]
extends = nrf52840_base
board = wiscore_rak4631
# add our variants files to the include and src paths
# define build flags for the TFT_eSPI library
build_flags = ${nrf52840_base.build_flags} -Ivariants/WisCore_RAK4631_Board -D RAK_BASE_19003
src_filter = ${nrf52_base.src_filter} +<../variants/WisCore_RAK4631_Board>
debug_tool = jlink
; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm)
;upload_protocol = jlink
; Note, this board is not yet supported! It will not work without futher development.
; THIS IS UNTESTED (I don't have this board), but other developers can use it as a starting point
[env:rak4600]
extends = nrf52_base
board = wiscore_rak4600
# add our variants files to the include and src paths
# define build flags for the TFT_eSPI library
build_flags = ${nrf52_base.build_flags} -Ivariants/WisCore_RAK4600_Board
src_filter = ${nrf52_base.src_filter} +<../variants/WisCore_RAK4600_Board>
lib_deps =
${arduino_base.lib_deps}
; The PPR board
[env:ppr]
extends = nrf52_base
board = ppr
lib_deps =
${arduino_base.lib_deps}
UC1701
; The PPR board
[env:ppr1]
extends = nrf52_base
board = ppr1
build_flags = ${nrf52_base.build_flags} -Ivariants/ppr1
src_filter = ${nrf52_base.src_filter} +<../variants/ppr1>
lib_deps =
${arduino_base.lib_deps}
; First prototype eink/nrf52840/sx1262 device
[env:t-echo]
extends = nrf52840_base
board = t-echo
debug_tool = jlink
upload_protocol = jlink
# add our variants files to the include and src paths
# define build flags for the TFT_eSPI library - NOTE: WE NOT LONGER USE TFT_eSPI, it was for an earlier version of the TTGO eink screens
# -DBUSY_PIN=3 -DRST_PIN=2 -DDC_PIN=28 -DCS_PIN=30
# add -DCFG_SYSVIEW if you want to use the Segger systemview tool for OS profiling.
build_flags = ${nrf52840_base.build_flags} -Ivariants/t-echo
src_filter = ${nrf52_base.src_filter} +<../variants/t-echo>
lib_deps =
${nrf52840_base.lib_deps}
https://github.com/geeksville/GxEPD2.git
adafruit/Adafruit BusIO
;upload_protocol = fs
; First prototype eink/nrf52840/sx1262 device (removed from build because didn't ship in quantity)
;[env:eink0.1]
;extends = nrf52840_base
;board = eink0.1
;# add our variants files to the include and src paths
;# define build flags for the TFT_eSPI library
;build_flags = ${nrf52_base.build_flags} -Ivariants/eink0.1
; -DBUSY_PIN=3 -DRST_PIN=2 -DDC_PIN=28 -DCS_PIN=30
;src_filter = ${nrf52_base.src_filter} +<../variants/eink0.1>
;lib_deps =
; ${nrf52840_base.lib_deps}
; https://github.com/geeksville/EPD_Libraries.git
; TFT_eSPI
; The https://github.com/BigCorvus/SX1262-LoRa-BLE-Relay board by @BigCorvus
[env:lora-relay-v1]
extends = nrf52840_base
board = lora-relay-v1
# add our variants files to the include and src paths
# define build flags for the TFT_eSPI library
build_flags = ${nrf52840_base.build_flags} -Ivariants/lora_relay_v1
-DUSER_SETUP_LOADED
-DTFT_WIDTH=80
-DTFT_HEIGHT=160
-DST7735_GREENTAB160x80
-DST7735_DRIVER
-DTFT_CS=ST7735_CS
-DTFT_DC=ST7735_RS
-DTFT_RST=ST7735_RESET
-DSPI_FREQUENCY=27000000
src_filter = ${nrf52_base.src_filter} +<../variants/lora_relay_v1>
lib_deps =
${nrf52840_base.lib_deps}
SparkFun BQ27441 LiPo Fuel Gauge Arduino Library
TFT_eSPI
; The https://github.com/BigCorvus/LoRa-BLE-Relay-v2 board by @BigCorvus
[env:lora-relay-v2]
extends = nrf52840_base
board = lora-relay-v2
# add our variants files to the include and src paths
# define build flags for the TFT_eSPI library
build_flags = ${nrf52840_base.build_flags} -Ivariants/lora_relay_v2
-DUSER_SETUP_LOADED
-DTFT_WIDTH=80
-DTFT_HEIGHT=160
-DST7735_GREENTAB160x80
-DST7735_DRIVER
-DTFT_CS=ST7735_CS
-DTFT_DC=ST7735_RS
-DTFT_RST=ST7735_RESET
-DSPI_FREQUENCY=27000000
-DTFT_WR=ST7735_SDA
-DTFT_SCLK=ST7735_SCK
src_filter = ${nrf52_base.src_filter} +<../variants/lora_relay_v2>
lib_deps =
${nrf52840_base.lib_deps}
SparkFun BQ27441 LiPo Fuel Gauge Arduino Library
TFT_eSPI
; The Portduino based sim environment on top of any host OS, all hardware will be simulated
[env:native]
platform = https://github.com/geeksville/platform-native.git
src_filter = ${env.src_filter} -<esp32/> -<nimble/> -<nrf52/> -<mesh/http/> -<plugins/esp32>
build_flags = ${arduino_base.build_flags} -O0
framework = arduino
board = cross_platform
lib_deps =
${arduino_base.lib_deps}
rweather/Crypto
; The Portduino based sim environment on top of a linux OS and touching linux hardware devices
[env:linux]
platform = https://github.com/geeksville/platform-native.git
src_filter = ${env.src_filter} -<esp32/> -<nimble/> -<nrf52/> -<mesh/http/> -<plugins/esp32>
build_flags = ${arduino_base.build_flags} -O0 -lgpiod
framework = arduino
board = linux_hardware
lib_deps =
${arduino_base.lib_deps}
rweather/Crypto
; The GenieBlocks LORA prototype board
; note: @geeksville disabled because genieblocks_lora is not checked into the boards directory, please send in a PR to add it ;-)
;[env:genieblocks_lora]
;extends = esp32_base
;board = genieblocks_lora
;build_flags =
; ${esp32_base.build_flags} -D GENIEBLOCKS

2
proto

Submodule proto updated: 18fc4cdb52...f6ba3722be

220
src/ButtonThread.h Normal file
View File

@@ -0,0 +1,220 @@
#include "configuration.h"
#include "concurrency/OSThread.h"
#include "PowerFSM.h"
#include "RadioLibInterface.h"
#include "graphics/Screen.h"
#include "power.h"
#include "buzz.h"
#include <OneButton.h>
#ifndef NO_ESP32
#include "nimble/BluetoothUtil.h"
#endif
namespace concurrency
{
/**
* Watch a GPIO and if we get an IRQ, wake the main thread.
* Use to add wake on button press
*/
void wakeOnIrq(int irq, int mode)
{
attachInterrupt(
irq,
[] {
BaseType_t higherWake = 0;
mainDelay.interruptFromISR(&higherWake);
},
FALLING);
}
class ButtonThread : public concurrency::OSThread
{
// Prepare for button presses
#ifdef BUTTON_PIN
OneButton userButton;
#endif
#ifdef BUTTON_PIN_ALT
OneButton userButtonAlt;
#endif
#ifdef BUTTON_PIN_TOUCH
OneButton userButtonTouch;
#endif
static bool shutdown_on_long_stop;
public:
static uint32_t longPressTime;
// callback returns the period for the next callback invocation (or 0 if we should no longer be called)
ButtonThread() : OSThread("Button")
{
#ifdef BUTTON_PIN
userButton = OneButton(BUTTON_PIN, 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, INPUT_PULLUP_SENSE);
#endif
userButton.attachClick(userButtonPressed);
userButton.attachDuringLongPress(userButtonPressedLong);
userButton.attachDoubleClick(userButtonDoublePressed);
userButton.attachMultiClick(userButtonMultiPressed);
userButton.attachLongPressStart(userButtonPressedLongStart);
userButton.attachLongPressStop(userButtonPressedLongStop);
wakeOnIrq(BUTTON_PIN, FALLING);
#endif
#ifdef BUTTON_PIN_ALT
userButtonAlt = OneButton(BUTTON_PIN_ALT, 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_ALT, INPUT_PULLUP_SENSE);
#endif
userButtonAlt.attachClick(userButtonPressed);
userButtonAlt.attachDuringLongPress(userButtonPressedLong);
userButtonAlt.attachDoubleClick(userButtonDoublePressed);
userButtonAlt.attachLongPressStart(userButtonPressedLongStart);
userButtonAlt.attachLongPressStop(userButtonPressedLongStop);
wakeOnIrq(BUTTON_PIN_ALT, FALLING);
#endif
#ifdef BUTTON_PIN_TOUCH
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.attachDuringLongPress(touchPressedLong);
userButtonTouch.attachDoubleClick(touchDoublePressed);
userButtonTouch.attachLongPressStart(touchPressedLongStart);
userButtonTouch.attachLongPressStop(touchPressedLongStop);
wakeOnIrq(BUTTON_PIN_TOUCH, FALLING);
#endif
}
protected:
/// If the button is pressed we suppress CPU sleep until release
int32_t runOnce() override
{
canSleep = true; // Assume we should not keep the board awake
#ifdef BUTTON_PIN
userButton.tick();
canSleep &= userButton.isIdle();
#endif
#ifdef BUTTON_PIN_ALT
userButtonAlt.tick();
canSleep &= userButtonAlt.isIdle();
#endif
#ifdef BUTTON_PIN_TOUCH
userButtonTouch.tick();
canSleep &= userButtonTouch.isIdle();
#endif
// if (!canSleep) DEBUG_MSG("Supressing sleep!\n");
// else DEBUG_MSG("sleep ok\n");
return 5;
}
private:
static void touchPressed()
{
screen->forceDisplay();
DEBUG_MSG("touch press!\n");
}
static void touchDoublePressed()
{
DEBUG_MSG("touch double press!\n");
}
static void touchPressedLong()
{
DEBUG_MSG("touch press long!\n");
}
static void touchDoublePressedLong()
{
DEBUG_MSG("touch double pressed!\n");
}
static void touchPressedLongStart()
{
DEBUG_MSG("touch long press start!\n");
}
static void touchPressedLongStop()
{
DEBUG_MSG("touch long press stop!\n");
}
static void userButtonPressed()
{
// DEBUG_MSG("press!\n");
powerFSM.trigger(EVENT_PRESS);
}
static void userButtonPressedLong()
{
// DEBUG_MSG("Long press!\n");
#ifndef NRF52_SERIES
screen->adjustBrightness();
#endif
// If user button is held down for 5 seconds, shutdown the device.
if (millis() - longPressTime > 5 * 1000) {
#ifdef TBEAM_V10
if (axp192_found == true) {
setLed(false);
power->shutdown();
}
#elif NRF52_SERIES
// Do actual shutdown when button released, otherwise the button release
// may wake the board immediatedly.
if (!shutdown_on_long_stop) {
screen->startShutdownScreen();
DEBUG_MSG("Shutdown from long press");
playBeep();
ledOff(PIN_LED1);
ledOff(PIN_LED2);
shutdown_on_long_stop = true;
}
#endif
} else {
// DEBUG_MSG("Long press %u\n", (millis() - longPressTime));
}
}
static void userButtonDoublePressed()
{
#ifndef NO_ESP32
disablePin();
#elif defined(HAS_EINK)
digitalWrite(PIN_EINK_EN,digitalRead(PIN_EINK_EN) == LOW);
#endif
}
static void userButtonMultiPressed()
{
#ifndef NO_ESP32
clearNVS();
#endif
#ifdef NRF52_SERIES
clearBonds();
#endif
}
static void userButtonPressedLongStart()
{
DEBUG_MSG("Long press start!\n");
longPressTime = millis();
}
static void userButtonPressedLongStop()
{
DEBUG_MSG("Long press stop!\n");
longPressTime = 0;
if (shutdown_on_long_stop) {
playShutdownMelody();
delay(3000);
power->shutdown();
}
}
};
}

61
src/DebugConfiguration.h Normal file
View File

@@ -0,0 +1,61 @@
// DEBUG LED
#ifndef LED_INVERTED
#define LED_INVERTED 0 // define as 1 if LED is active low (on)
#endif
// -----------------------------------------------------------------------------
// DEBUG
// -----------------------------------------------------------------------------
#ifdef CONSOLE_MAX_BAUD
#define SERIAL_BAUD CONSOLE_MAX_BAUD
#else
#define SERIAL_BAUD 921600 // Serial debug baud rate
#endif
#include "SerialConsole.h"
#define DEBUG_PORT (*console) // Serial debug port
// What platforms should use SEGGER?
#ifdef NRF52_SERIES
// Always include the SEGGER code on NRF52 - because useful for debugging
#include "SEGGER_RTT.h"
// The channel we send stdout data to
#define SEGGER_STDOUT_CH 0
// Debug printing to segger console
#define SEGGER_MSG(...) SEGGER_RTT_printf(SEGGER_STDOUT_CH, __VA_ARGS__)
// If we are not on a NRF52840 (which has built in USB-ACM serial support) and we don't have serial pins hooked up, then we MUST
// use SEGGER for debug output
#if !defined(PIN_SERIAL_RX) && !defined(NRF52840_XXAA)
// No serial ports on this board - ONLY use segger in memory console
#define USE_SEGGER
#endif
#else
#define SERIAL0_RX_GPIO 3 // Always GPIO3 on ESP32
#endif
#ifdef USE_SEGGER
#define DEBUG_MSG(...) SEGGER_RTT_printf(0, __VA_ARGS__)
#else
#ifdef DEBUG_PORT
#define DEBUG_MSG(...) DEBUG_PORT.logDebug(__VA_ARGS__)
#else
#define DEBUG_MSG(...)
#endif
#endif
// -----------------------------------------------------------------------------
// AXP192 (Rev1-specific options)
// -----------------------------------------------------------------------------
#define GPS_POWER_CTRL_CH 3
#define LORA_POWER_CTRL_CH 2
// Default Bluetooth PIN
#define defaultBLEPin 123456

View File

@@ -3,20 +3,20 @@
void fsInit()
{
#ifdef FS
if (!FSBegin())
#ifdef FSCom
if (!FSBegin())
{
DEBUG_MSG("ERROR filesystem mount Failed\n");
assert(0); // FIXME - report failure to phone
}
DEBUG_MSG("Filesystem files:\n");
File dir = FS.open("/");
File dir = FSCom.open("/");
File f = dir.openNextFile();
while (f) {
DEBUG_MSG(" %s\n", f.name());
f.close();
f = dir.openNextFile();
f = dir.openNextFile();
}
#endif
}

View File

@@ -7,22 +7,22 @@
#ifdef PORTDUINO
// Portduino version
#include "PortduinoFS.h"
#define FS PortduinoFS
#define FSCom PortduinoFS
#define FSBegin() true
#define FILE_O_WRITE "w"
#define FILE_O_READ "r"
#elif !defined(NO_ESP32)
// ESP32 version
#include "SPIFFS.h"
#define FS SPIFFS
#define FSBegin() FS.begin(true)
#include "LITTLEFS.h"
#define FSCom LITTLEFS
#define FSBegin() FSCom.begin(true)
#define FILE_O_WRITE "w"
#define FILE_O_READ "r"
#else
// NRF52 version
#include "InternalFileSystem.h"
#define FS InternalFS
#define FSBegin() FS.begin()
#define FSCom InternalFS
#define FSBegin() FSCom.begin()
using namespace Adafruit_LittleFS_Namespace;
#endif

View File

@@ -42,7 +42,7 @@ class GPSStatus : public Status
}
// preferred method
GPSStatus(bool hasLock, bool isConnected, Position pos)
GPSStatus(bool hasLock, bool isConnected, const Position& pos)
: Status()
{
this->hasLock = hasLock;
@@ -63,7 +63,9 @@ class GPSStatus : public Status
int32_t getLatitude() const {
if (radioConfig.preferences.fixed_position){
#if GPS_EXTRAVERBOSE
DEBUG_MSG("WARNING: Using fixed latitude\n");
#endif
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
return node->position.latitude_i;
} else {
@@ -73,7 +75,9 @@ class GPSStatus : public Status
int32_t getLongitude() const {
if (radioConfig.preferences.fixed_position){
#if GPS_EXTRAVERBOSE
DEBUG_MSG("WARNING: Using fixed longitude\n");
#endif
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
return node->position.longitude_i;
} else {
@@ -83,7 +87,9 @@ class GPSStatus : public Status
int32_t getAltitude() const {
if (radioConfig.preferences.fixed_position){
#if GPS_EXTRAVERBOSE
DEBUG_MSG("WARNING: Using fixed altitude\n");
#endif
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
return node->position.altitude;
} else {
@@ -149,4 +155,4 @@ class GPSStatus : public Status
} // namespace meshtastic
extern meshtastic::GPSStatus *gpsStatus;
extern meshtastic::GPSStatus *gpsStatus;

View File

@@ -47,7 +47,7 @@ template <class Callback, class T> class CallbackObserver : public Observer<T>
CallbackObserver(Callback *_objPtr, ObserverCallback _method) : objPtr(_objPtr), method(_method) {}
protected:
virtual int onNotify(T arg) { return (objPtr->*method)(arg); }
virtual int onNotify(T arg) override { return (objPtr->*method)(arg); }
};
/**
@@ -104,4 +104,4 @@ template <class T> void Observer<T>::observe(Observable<T> *o)
observed = o;
o->addObserver(this);
}
}

View File

@@ -75,7 +75,7 @@ class AnalogBatteryLevel : public HasBatteryLevel
*
* FIXME - use a lipo lookup table, the current % full is super wrong
*/
virtual int getBattPercentage()
virtual int getBattPercentage() override
{
float v = getBattVoltage();
@@ -94,12 +94,16 @@ class AnalogBatteryLevel : public HasBatteryLevel
/**
* The raw voltage of the batteryin millivolts or NAN if unknown
*/
virtual float getBattVoltage()
virtual float getBattVoltage() override
{
#ifndef ADC_MULTIPLIER
#define ADC_MULTIPLIER 2.0
#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
// Do not call analogRead() often.
@@ -109,7 +113,7 @@ class AnalogBatteryLevel : public HasBatteryLevel
uint32_t raw = analogRead(BATTERY_PIN);
float scaled;
#ifndef VBAT_RAW_TO_SCALED
scaled = 1000.0 * ADC_MULTIPLIER * (AREF_VOLTAGE / 1024.0) * raw;
scaled = 1000.0 * operativeAdcMultiplier * (AREF_VOLTAGE / 1024.0) * raw;
#else
scaled = VBAT_RAW_TO_SCALED(raw); //defined in variant.h
#endif
@@ -127,15 +131,15 @@ class AnalogBatteryLevel : public HasBatteryLevel
/**
* return true if there is a battery installed in this unit
*/
virtual bool isBatteryConnect() { return getBattPercentage() != -1; }
virtual bool isBatteryConnect() override { return getBattPercentage() != -1; }
/// If we see a battery voltage higher than physics allows - assume charger is pumping
/// in power
virtual bool isVBUSPlug() { return getBattVoltage() > chargingVolt; }
virtual bool isVBUSPlug() override { return getBattVoltage() > chargingVolt; }
/// Assume charging if we have a battery and external power is connected.
/// we can't be smart enough to say 'full'?
virtual bool isChargeing() { return isBatteryConnect() && isVBUSPlug(); }
virtual bool isChargeing() override { return isBatteryConnect() && isVBUSPlug(); }
private:
/// If we see a battery voltage higher than physics allows - assume charger is pumping
@@ -149,7 +153,10 @@ class AnalogBatteryLevel : public HasBatteryLevel
AnalogBatteryLevel analogLevel;
Power::Power() : OSThread("Power") {}
Power::Power() : OSThread("Power") {
statusHandler = {};
low_voltage_counter = 0;
}
bool Power::analogInit()
{
@@ -232,18 +239,18 @@ void Power::readPowerStatus()
}
// Notify any status instances that are observing us
const PowerStatus powerStatus =
const PowerStatus powerStatus2 =
PowerStatus(hasBattery ? OptTrue : OptFalse, batteryLevel->isVBUSPlug() ? OptTrue : OptFalse,
batteryLevel->isChargeing() ? OptTrue : OptFalse, batteryVoltageMv, batteryChargePercent);
DEBUG_MSG("Battery: usbPower=%d, isCharging=%d, batMv=%d, batPct=%d\n", powerStatus.getHasUSB(),
powerStatus.getIsCharging(), powerStatus.getBatteryVoltageMv(), powerStatus.getBatteryChargePercent());
newStatus.notifyObservers(&powerStatus);
DEBUG_MSG("Battery: usbPower=%d, isCharging=%d, batMv=%d, batPct=%d\n", powerStatus2.getHasUSB(),
powerStatus2.getIsCharging(), powerStatus2.getBatteryVoltageMv(), powerStatus2.getBatteryChargePercent());
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
// 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
if (powerStatus.getHasBattery() && !powerStatus.getHasUSB()){
if (powerStatus2.getHasBattery() && !powerStatus2.getHasUSB()){
if (batteryLevel->getBattVoltage() < MIN_BAT_MILLIVOLTS){
low_voltage_counter++;
if (low_voltage_counter>3)
@@ -254,13 +261,13 @@ void Power::readPowerStatus()
}
#else
// If we have a battery at all and it is less than 10% full, force deep sleep
if (powerStatus.getHasBattery() && !powerStatus.getHasUSB() && batteryLevel->getBattVoltage() < MIN_BAT_MILLIVOLTS)
if (powerStatus2.getHasBattery() && !powerStatus2.getHasUSB() && batteryLevel->getBattVoltage() < MIN_BAT_MILLIVOLTS)
powerFSM.trigger(EVENT_LOW_BATTERY);
#endif
} else {
// No power sensing on this board - tell everyone else we have no idea what is happening
const PowerStatus powerStatus = PowerStatus(OptUnknown, OptUnknown, OptUnknown, -1, -1);
newStatus.notifyObservers(&powerStatus);
const PowerStatus powerStatus3 = PowerStatus(OptUnknown, OptUnknown, OptUnknown, -1, -1);
newStatus.notifyObservers(&powerStatus3);
}
}

View File

@@ -63,7 +63,6 @@ static void lsIdle()
// DEBUG_MSG("lsIdle begin ls_secs=%u\n", getPref_ls_secs());
#ifndef NO_ESP32
esp_sleep_source_t wakeCause = ESP_SLEEP_WAKEUP_UNDEFINED;
// Do we have more sleeping to do?
if (secsSlept < getPref_ls_secs()) {
@@ -73,14 +72,14 @@ static void lsIdle()
// If some other service would stall sleep, don't let sleep happen yet
if (doPreflightSleep()) {
setLed(false); // Never leave led on while in light sleep
wakeCause = doLightSleep(sleepTime * 1000LL);
esp_sleep_source_t wakeCause2 = doLightSleep(sleepTime * 1000LL);
switch (wakeCause) {
switch (wakeCause2) {
case ESP_SLEEP_WAKEUP_TIMER:
// Normal case: timer expired, we should just go back to sleep ASAP
setLed(true); // briefly turn on led
wakeCause = doLightSleep(1); // leave led on for 1ms
wakeCause2 = doLightSleep(1); // leave led on for 1ms
secsSlept += sleepTime;
// DEBUG_MSG("sleeping, flash led!\n");
@@ -94,7 +93,7 @@ static void lsIdle()
default:
// We woke for some other reason (button press, device interrupt)
// uint64_t status = esp_sleep_get_ext1_wakeup_status();
DEBUG_MSG("wakeCause %d\n", wakeCause);
DEBUG_MSG("wakeCause2 %d\n", wakeCause2);
#ifdef BUTTON_PIN
bool pressed = !digitalRead(BUTTON_PIN);

38
src/PowerFSMThread.h Normal file
View File

@@ -0,0 +1,38 @@
#include "configuration.h"
#include "concurrency/OSThread.h"
#include "main.h"
#include "PowerFSM.h"
#include "power.h"
#include "NodeDB.h"
namespace concurrency
{
/// Wrapper to convert our powerFSM stuff into a 'thread'
class PowerFSMThread : public OSThread
{
public:
// callback returns the period for the next callback invocation (or 0 if we should no longer be called)
PowerFSMThread() : OSThread("PowerFSM") {}
protected:
int32_t runOnce() override
{
powerFSM.run_machine();
/// If we are in power state we force the CPU to wake every 10ms to check for serial characters (we don't yet wake
/// cpu for serial rx - FIXME)
auto state = powerFSM.getState();
canSleep = (state != &statePOWER) && (state != &stateSERIAL);
if (powerStatus->getHasUSB()) {
timeLastPowered = millis();
} else if (radioConfig.preferences.on_battery_shutdown_after_secs > 0 &&
millis() > timeLastPowered + (1000 * radioConfig.preferences.on_battery_shutdown_after_secs)) { //shutdown after 30 minutes unpowered
powerFSM.trigger(EVENT_SHUTDOWN);
}
return 10;
}
};
}

7
src/RF95Configuration.h Normal file
View File

@@ -0,0 +1,7 @@
// TODO refactor this out with better radio configuration system
#ifdef USE_RF95
#define RF95_RESET LORA_RESET
#define RF95_IRQ LORA_DIO0 // on SX1262 version this is a no connect DIO0
#define RF95_DIO1 LORA_DIO1 // Note: not really used for RF95
#define RF95_DIO2 LORA_DIO2 // Note: not really used for RF95
#endif

View File

@@ -22,7 +22,7 @@ class RedirectablePrint : public Print
volatile bool inDebugPrint = false;
public:
RedirectablePrint(Print *_dest) : dest(_dest) {}
explicit RedirectablePrint(Print *_dest) : dest(_dest) {}
/**
* Set a new destination
@@ -56,4 +56,4 @@ class NoopPrint : public Print
/**
* A printer that doesn't go anywhere
*/
extern NoopPrint noopPrint;
extern NoopPrint noopPrint;

View File

@@ -15,9 +15,9 @@ class SerialConsole : public StreamAPI, public RedirectablePrint
* we override this to notice when we've received a protobuf over the serial stream. Then we shunt off
* debug serial output.
*/
virtual bool handleToRadio(const uint8_t *buf, size_t len);
virtual bool handleToRadio(const uint8_t *buf, size_t len) override;
virtual size_t write(uint8_t c)
virtual size_t write(uint8_t c) override
{
if (c == '\n') // prefix any newlines with carriage return
RedirectablePrint::write('\r');
@@ -27,7 +27,7 @@ class SerialConsole : public StreamAPI, public RedirectablePrint
protected:
/// Check the current underlying physical link to see if the client is currently connected
virtual bool checkIsConnected();
virtual bool checkIsConnected() override;
};
// A simple wrapper to allow non class aware code write to the console

View File

@@ -2,21 +2,20 @@
#include "NodeDB.h"
#include "configuration.h"
AirTime *airTime;
AirTime *airTime = NULL;
// Don't read out of this directly. Use the helper functions.
void AirTime::logAirtime(reportTypes reportType, uint32_t airtime_ms)
{
// TODO: Is the airtimes array still necessary? It's now in myNodeInfo anyway
if (reportType == TX_LOG) {
DEBUG_MSG("AirTime - Packet transmitted : %ums\n", airtime_ms);
this->airtimes.periodTX[0] = this->airtimes.periodTX[0] + airtime_ms;
myNodeInfo.air_period_tx[0] = myNodeInfo.air_period_tx[0] + airtime_ms;
this->utilizationTX[this->getPeriodUtilHour()] = this->utilizationTX[this->getPeriodUtilHour()] + airtime_ms;
} else if (reportType == RX_LOG) {
DEBUG_MSG("AirTime - Packet received : %ums\n", airtime_ms);
this->airtimes.periodRX[0] = this->airtimes.periodRX[0] + airtime_ms;
@@ -26,8 +25,8 @@ void AirTime::logAirtime(reportTypes reportType, uint32_t airtime_ms)
this->airtimes.periodRX_ALL[0] = this->airtimes.periodRX_ALL[0] + airtime_ms;
}
uint8_t channelUtilPeriod = (getSecondsSinceBoot() / 10) % CHANNEL_UTILIZATION_PERIODS;
this->channelUtilization[channelUtilPeriod] = channelUtilization[channelUtilPeriod] + airtime_ms;
// Log all airtime type for channel utilization
this->channelUtilization[this->getPeriodUtilMinute()] = channelUtilization[this->getPeriodUtilMinute()] + airtime_ms;
}
uint8_t AirTime::currentPeriodIndex()
@@ -35,21 +34,29 @@ uint8_t AirTime::currentPeriodIndex()
return ((getSecondsSinceBoot() / SECONDS_PER_PERIOD) % PERIODS_TO_LOG);
}
uint8_t AirTime::getPeriodUtilMinute() {
return (getSecondsSinceBoot() / 10) % CHANNEL_UTILIZATION_PERIODS;
}
uint8_t AirTime::getPeriodUtilHour() {
return (getSecondsSinceBoot() / 60) % MINUTES_IN_HOUR;
}
void AirTime::airtimeRotatePeriod()
{
if (this->airtimes.lastPeriodIndex != currentPeriodIndex()) {
DEBUG_MSG("Rotating airtimes to a new period = %u\n", currentPeriodIndex());
if (this->airtimes.lastPeriodIndex != this->currentPeriodIndex()) {
DEBUG_MSG("Rotating airtimes to a new period = %u\n", this->currentPeriodIndex());
for (int i = PERIODS_TO_LOG - 2; i >= 0; --i) {
this->airtimes.periodTX[i + 1] = this->airtimes.periodTX[i];
this->airtimes.periodRX[i + 1] = this->airtimes.periodRX[i];
this->airtimes.periodRX_ALL[i + 1] = this->airtimes.periodRX_ALL[i];
myNodeInfo.air_period_tx[i + 1] = myNodeInfo.air_period_tx[i];
myNodeInfo.air_period_rx[i + 1] = myNodeInfo.air_period_rx[i];
myNodeInfo.air_period_tx[i + 1] = this->airtimes.periodTX[i];
myNodeInfo.air_period_rx[i + 1] = this->airtimes.periodRX[i];
}
this->airtimes.periodTX[0] = 0;
this->airtimes.periodRX[0] = 0;
this->airtimes.periodRX_ALL[0] = 0;
@@ -57,7 +64,7 @@ void AirTime::airtimeRotatePeriod()
myNodeInfo.air_period_tx[0] = 0;
myNodeInfo.air_period_rx[0] = 0;
this->airtimes.lastPeriodIndex = currentPeriodIndex();
this->airtimes.lastPeriodIndex = this->currentPeriodIndex();
}
}
@@ -100,25 +107,53 @@ float AirTime::channelUtilizationPercent()
return (float(sum) / float(CHANNEL_UTILIZATION_PERIODS * 10 * 1000)) * 100;
}
AirTime::AirTime() : concurrency::OSThread("AirTime") {}
float AirTime::utilizationTXPercent()
{
uint32_t sum = 0;
for (uint32_t i = 0; i < MINUTES_IN_HOUR; i++) {
sum += this->utilizationTX[i];
}
return (float(sum) / float(MS_IN_HOUR)) * 100;
}
AirTime::AirTime() : concurrency::OSThread("AirTime"),airtimes({}) {
}
int32_t AirTime::runOnce()
{
secSinceBoot++;
uint8_t utilPeriod = (getSecondsSinceBoot() / 10) % CHANNEL_UTILIZATION_PERIODS;
uint8_t utilPeriod = this->getPeriodUtilMinute();
uint8_t utilPeriodTX = this->getPeriodUtilHour();
if (firstTime) {
airtimeRotatePeriod();
// Init utilizationTX window to all 0
for (uint32_t i = 0; i < MINUTES_IN_HOUR; i++) {
this->utilizationTX[i] = 0;
}
// Init channelUtilization window to all 0
for (uint32_t i = 0; i < CHANNEL_UTILIZATION_PERIODS; i++) {
this->channelUtilization[i] = 0;
}
// Init airtime windows to all 0
for (int i = 0; i < myNodeInfo.air_period_rx_count; i++) {
this->airtimes.periodTX[i] = 0;
this->airtimes.periodRX[i] = 0;
this->airtimes.periodRX_ALL[i] = 0;
// myNodeInfo.air_period_tx[i] = 0;
// myNodeInfo.air_period_rx[i] = 0;
}
firstTime = false;
lastUtilPeriod = utilPeriod;
} else {
this->airtimeRotatePeriod();
// Reset the channelUtilization window when we roll over
if (lastUtilPeriod != utilPeriod) {
@@ -127,9 +162,26 @@ int32_t AirTime::runOnce()
this->channelUtilization[utilPeriod] = 0;
}
if (lastUtilPeriodTX != utilPeriodTX) {
lastUtilPeriodTX = utilPeriodTX;
this->utilizationTX[utilPeriodTX] = 0;
}
// Update channel_utilization every second.
myNodeInfo.channel_utilization = airTime->channelUtilizationPercent();
}
// Update channel_utilization every second.
myNodeInfo.air_util_tx = airTime->utilizationTXPercent();
}
/*
DEBUG_MSG("utilPeriodTX %d TX Airtime %3.2f%\n", utilPeriodTX, airTime->utilizationTXPercent());
for (uint32_t i = 0; i < MINUTES_IN_HOUR; i++) {
DEBUG_MSG(
"%d,", this->utilizationTX[i]
);
}
DEBUG_MSG("\n");
*/
return (1000 * 1);
}
}

View File

@@ -26,7 +26,10 @@
#define CHANNEL_UTILIZATION_PERIODS 6
#define SECONDS_PER_PERIOD 3600
#define PERIODS_TO_LOG 24
#define PERIODS_TO_LOG 8
#define MINUTES_IN_HOUR 60
#define SECONDS_IN_MINUTE 60
#define MS_IN_HOUR (MINUTES_IN_HOUR * SECONDS_IN_MINUTE * 1000)
enum reportTypes { TX_LOG, RX_LOG, RX_ALL_LOG };
@@ -43,9 +46,12 @@ class AirTime : private concurrency::OSThread
void logAirtime(reportTypes reportType, uint32_t airtime_ms);
float channelUtilizationPercent();
uint32_t channelUtilization[CHANNEL_UTILIZATION_PERIODS];
float utilizationTXPercent();
float UtilizationPercentTX();
uint32_t channelUtilization[CHANNEL_UTILIZATION_PERIODS] = {0};
uint32_t utilizationTX[MINUTES_IN_HOUR] = {0};
uint8_t currentPeriodIndex();
void airtimeRotatePeriod();
uint8_t getPeriodsToLog();
uint32_t getSecondsPerPeriod();
@@ -55,6 +61,7 @@ class AirTime : private concurrency::OSThread
private:
bool firstTime = true;
uint8_t lastUtilPeriod = 0;
uint8_t lastUtilPeriodTX = 0;
uint32_t secSinceBoot = 0;
struct airtimeStruct {
@@ -64,8 +71,12 @@ class AirTime : private concurrency::OSThread
uint8_t lastPeriodIndex;
} airtimes;
uint8_t getPeriodUtilMinute();
uint8_t getPeriodUtilHour();
uint8_t currentPeriodIndex();
protected:
virtual int32_t runOnce() override;
};
extern AirTime *airTime;
extern AirTime *airTime;

View File

@@ -13,4 +13,5 @@ enum class Cmd {
STOP_BLUETOOTH_PIN_SCREEN,
STOP_BOOT_SCREEN,
PRINT,
START_SHUTDOWN_SCREEN,
};

View File

@@ -7,9 +7,8 @@
namespace concurrency
{
BinarySemaphoreFreeRTOS::BinarySemaphoreFreeRTOS()
BinarySemaphoreFreeRTOS::BinarySemaphoreFreeRTOS() : semaphore(xSemaphoreCreateBinary())
{
semaphore = xSemaphoreCreateBinary();
assert(semaphore);
}
@@ -38,4 +37,4 @@ IRAM_ATTR void BinarySemaphoreFreeRTOS::giveFromISR(BaseType_t *pxHigherPriority
} // namespace concurrency
#endif
#endif

View File

@@ -6,9 +6,8 @@ namespace concurrency
{
#ifdef HAS_FREE_RTOS
Lock::Lock()
Lock::Lock() : handle(xSemaphoreCreateBinary())
{
handle = xSemaphoreCreateBinary();
assert(handle);
assert(xSemaphoreGive(handle));
}

View File

@@ -10,7 +10,7 @@ namespace concurrency {
class LockGuard
{
public:
LockGuard(Lock *lock);
explicit LockGuard(Lock *lock);
~LockGuard();
LockGuard(const LockGuard &) = delete;

View File

@@ -39,7 +39,7 @@ class NotifiedWorkerThread : public OSThread
virtual void onNotify(uint32_t notification) = 0;
/// just calls checkNotification()
virtual int32_t runOnce();
virtual int32_t runOnce() override;
/// Sometimes we might want to check notifications independently of when our thread was getting woken up (i.e. if we are about to change
/// radio transmit/receive modes we want to handle any pending interrupts first). You can call this method and if any notifications are currently

View File

@@ -18,7 +18,7 @@ class Periodic : public OSThread
Periodic(const char *name, int32_t (*_callback)()) : OSThread(name), callback(_callback) {}
protected:
int32_t runOnce() { return callback(); }
int32_t runOnce() override { return callback(); }
};
} // namespace concurrency

View File

@@ -45,10 +45,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// If we are using the JTAG port for debugging, some pins must be left free for that (and things like GPS have to be disabled)
// we don't support jtag on the ttgo - access to gpio 12 is a PITA
#ifdef ARDUINO_HELTEC_WIFI_LORA_32_V2
//#define USE_JTAG
#endif
#define REQUIRE_RADIO true // If true, we will fail to start if the radio is not found
/// Convert a preprocessor name into a quoted string
@@ -88,18 +84,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define BUTTON_PIN_TOUCH PIN_BUTTON_TOUCH
#endif
// FIXME, use variant.h defs for all of this!!! (even on the ESP32 targets)
#elif defined(CubeCell_BoardPlus)
//
// Standard definitions for CubeCell targets
//
#define NO_ESP32 // Don't use ESP32 libs (mainly bluetooth)
#define LED_PIN -1 // FIXME totally bogus
#define BUTTON_PIN -1
#else
//
@@ -169,338 +153,59 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR HardwareModel_TBEAM
// #define BUTTON_NEED_PULLUP // if set we need to turn on the internal CPU pullup during sleep
#define I2C_SDA 21
#define I2C_SCL 22
#define BUTTON_PIN 38 // The middle button GPIO on the T-Beam
//#define BUTTON_PIN_ALT 13 // Alternate GPIO for an external button if needed. Does anyone use this? It is not documented anywhere.
#define EXT_NOTIFY_OUT 13 // Default pin to use for Ext Notify Plugin.
#define LED_INVERTED 1
#define LED_PIN 4 // Newer tbeams (1.1) have an extra led on GPIO4
// TTGO uses a common pinout for their SX1262 vs RF95 modules - both can be enabled and we will probe at runtime for RF95 and if
// not found then probe for SX1262
#define USE_RF95
#define USE_SX1262
#define LORA_DIO0 26 // a No connect on the SX1262 module
#define LORA_RESET 23
#define LORA_DIO1 33 // SX1262 IRQ
#define LORA_DIO2 32 // SX1262 BUSY
#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled
#ifdef USE_SX1262
#define SX126X_CS RF95_NSS // FIXME - we really should define LORA_CS instead
#define SX126X_DIO1 LORA_DIO1
#define SX126X_BUSY LORA_DIO2
#define SX126X_RESET LORA_RESET
#define SX126X_E22 // Not really an E22 but TTGO seems to be trying to clone that
// Internally the TTGO module hooks the SX1262-DIO2 in to control the TX/RX switch (which is the default for the sx1262interface
// code)
#endif
// Leave undefined to disable our PMU IRQ handler. DO NOT ENABLE THIS because the pmuirq can cause sperious interrupts
// and waking from light sleep
// #define PMU_IRQ 35
#define AXP192_SLAVE_ADDRESS 0x34
#elif defined(TBEAM_V07)
// This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR HardwareModel_TBEAM0p7
// #define BUTTON_NEED_PULLUP // if set we need to turn on the internal CPU pullup during sleep
#define I2C_SDA 21
#define I2C_SCL 22
#define BUTTON_PIN 39
#define BATTERY_PIN 35 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
#define EXT_NOTIFY_OUT 13 // Default pin to use for Ext Notify Plugin.
#define USE_RF95
#define LORA_DIO0 26 // a No connect on the SX1262 module
#define LORA_RESET 23
#define LORA_DIO1 33 // Not really used
#define LORA_DIO2 32 // Not really used
// This board has different GPS pins than all other boards
#undef GPS_RX_PIN
#undef GPS_TX_PIN
#define GPS_RX_PIN 12
#define GPS_TX_PIN 15
#elif defined(DIY_V1)
// This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR HardwareModel_DIY_V1
// For OLED LCD
#define I2C_SDA 21
#define I2C_SCL 22
// GPS
#undef GPS_RX_PIN
#define GPS_RX_PIN 15
//#undef GPS_TX_PIN
//#define GPS_TX_PIN 12 // not connected
#define BUTTON_PIN 39 // The middle button GPIO on the T-Beam
#define EXT_NOTIFY_OUT 12 // Overridden default pin to use for Ext Notify Plugin (#975).
#define LED_PIN 2 // add status LED (compatible with core-pcb and DIY targets)
#define LORA_DIO0 26 // a No connect on the SX1262/SX1268 module
#define LORA_RESET 23 // RST for SX1276, and for SX1262/SX1268
#define LORA_DIO1 33 // IRQ for SX1262/SX1268
#define LORA_DIO2 32 // BUSY for SX1262/SX1268
#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262/SX1268, if DIO3 is high the TXCO is enabled
#define RF95_SCK 5
#define RF95_MISO 19
#define RF95_MOSI 27
#define RF95_NSS 18
// supported modules list
#define USE_SX1262
#define USE_SX1268
#define USE_LLCC68
// common pinouts for SX126X modules
#define SX126X_CS 18 // NSS for SX126X
#define SX126X_DIO1 LORA_DIO1
#define SX126X_BUSY LORA_DIO2
#define SX126X_RESET LORA_RESET
#define SX126X_RXEN 14
#define SX126X_TXEN 13
#ifdef EBYTE_E22
// Internally the TTGO module hooks the SX126x-DIO2 in to control the TX/RX switch
// (which is the default for the sx1262interface code)
#define SX126X_E22
#endif
#elif defined(RAK_11200)
// This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR HardwareModel_RAK11200
#elif defined(ARDUINO_HELTEC_WIFI_LORA_32_V2)
// the default ESP32 Pin of 15 is the Oled SCL, set to 36 and 37 and works fine.
// Tested on Neo6m module.
#undef GPS_RX_PIN
#undef GPS_TX_PIN
#define GPS_RX_PIN 36
#define GPS_TX_PIN 37
#ifndef USE_JTAG // gpio15 is TDO for JTAG, so no I2C on this board while doing jtag
#define I2C_SDA 4 // I2C pins for this board
#define I2C_SCL 15
#endif
#define RESET_OLED 16 // If defined, this pin will be used to reset the display controller
#define VEXT_ENABLE 21 // active low, powers the oled display and the lora antenna boost
#define LED_PIN 25 // If defined we will blink this LED
#define BUTTON_PIN 0 // If defined, this will be used for user button presses
#define USE_RF95
#define LORA_DIO0 26 // a No connect on the SX1262 module
#ifndef USE_JTAG
#define LORA_RESET 14
#endif
#define LORA_DIO1 35 // Not really used
#define LORA_DIO2 34 // Not really used
// ratio of voltage divider = 3.20 (R1=100k, R2=220k)
#define ADC_MULTIPLIER 3.2
#ifdef HELTEC_V2_0
// This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR HardwareModel_HELTEC_V2_0
#define BATTERY_PIN 13 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
#endif
#ifdef HELTEC_V2_1
// This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR HardwareModel_HELTEC_V2_1
#define BATTERY_PIN 37 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
#define EXT_NOTIFY_OUT 13 // Default pin to use for Ext Notify Plugin.
#endif
#elif defined(ARDUINO_HELTEC_WIFI_LORA_32)
// the default ESP32 Pin of 15 is the Oled SCL, set to 36 and 37 and works fine.
// Tested on Neo6m module.
#undef GPS_RX_PIN
#undef GPS_TX_PIN
#define GPS_RX_PIN 36
#define GPS_TX_PIN 37
#ifndef USE_JTAG // gpio15 is TDO for JTAG, so no I2C on this board while doing jtag
#define I2C_SDA 4 // I2C pins for this board
#define I2C_SCL 15
#endif
#define RESET_OLED 16 // If defined, this pin will be used to reset the display controller
#define LED_PIN 25 // If defined we will blink this LED
#define BUTTON_PIN 0 // If defined, this will be used for user button presses
#define USE_RF95
#define LORA_DIO0 26 // a No connect on the SX1262 module
#ifndef USE_JTAG
#define LORA_RESET 14
#endif
#define LORA_DIO1 33 // Not really used
#define LORA_DIO2 32 // Not really used
// ratio of voltage divider = 3.20 (R1=100k, R2=220k)
#define ADC_MULTIPLIER 3.2
// This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR HardwareModel_HELTEC_V1
#define BATTERY_PIN 13 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
#elif defined(TLORA_V1)
// This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR HardwareModel_TLORA_V1
#undef GPS_RX_PIN
#undef GPS_TX_PIN
#define GPS_RX_PIN 36
#define GPS_TX_PIN 37
#define I2C_SDA 4 // I2C pins for this board
#define I2C_SCL 15
#define RESET_OLED 16 // If defined, this pin will be used to reset the display controller
// #define VEXT_ENABLE 21 // active low, powers the oled display and the lora antenna boost
#define LED_PIN 2 // If defined we will blink this LED
#define BUTTON_PIN 0 // If defined, this will be used for user button presses
#define BUTTON_NEED_PULLUP
#define EXT_NOTIFY_OUT 13 // Default pin to use for Ext Notify Plugin.
#define USE_RF95
#define LORA_DIO0 26 // a No connect on the SX1262 module
#define LORA_RESET 14
#define LORA_DIO1 35 // Not really used
#define LORA_DIO2 34 // Not really used
#elif defined(TLORA_V2)
// This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR HardwareModel_TLORA_V2
#undef GPS_RX_PIN
#undef GPS_TX_PIN
#define GPS_RX_PIN 36
#define GPS_TX_PIN 13 // per @eugene
#define BATTERY_PIN 35 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
#define I2C_SDA 21 // I2C pins for this board
#define I2C_SCL 22
#define RESET_OLED 16 // If defined, this pin will be used to reset the display controller
#define VEXT_ENABLE 21 // active low, powers the oled display and the lora antenna boost
#define LED_PIN 25 // If defined we will blink this LED
#define BUTTON_PIN \
0 // If defined, this will be used for user button presses, if your board doesn't have a physical switch, you can wire one
// between this pin and ground
#define BUTTON_NEED_PULLUP
#define USE_RF95
#define LORA_DIO0 26 // a No connect on the SX1262 module
#define LORA_RESET 14
#define LORA_DIO1 35 // Not really used
#define LORA_DIO2 34 // Not really used
#elif defined(TLORA_V1_3)
// This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR HardwareModel_TLORA_V1_1p3
#undef GPS_RX_PIN
#undef GPS_TX_PIN
#define GPS_RX_PIN 36
#define GPS_TX_PIN 13 // per @eugene
#define BATTERY_PIN 35 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
#define I2C_SDA 4 // I2C pins for this board
#define I2C_SCL 15
#define RESET_OLED 16 // If defined, this pin will be used to reset the display controller
#define VEXT_ENABLE 21 // active low, powers the oled display and the lora antenna boost
#define LED_PIN 25 // If defined we will blink this LED
#define BUTTON_PIN 36
#define BUTTON_NEED_PULLUP
#define USE_RF95
#define LORA_DIO0 26 // a No connect on the SX1262 module
#define LORA_RESET 14
#define LORA_DIO1 35 // Not really used
#define LORA_DIO2 34 // Not really used
#elif defined(TLORA_V2_1_16)
// This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR HardwareModel_TLORA_V2_1_1p6
#undef GPS_RX_PIN
#undef GPS_TX_PIN
#define GPS_RX_PIN 15 // per @der_bear on the forum, 36 is incorrect for this board type and 15 is a better pick
#define GPS_TX_PIN 13
#define BATTERY_PIN 35 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
#define I2C_SDA 21 // I2C pins for this board
#define I2C_SCL 22
#define RESET_OLED 16 // If defined, this pin will be used to reset the display controller
#define VEXT_ENABLE 21 // active low, powers the oled display and the lora antenna boost
#define LED_PIN 25 // If defined we will blink this LED
#define BUTTON_PIN 12 // If defined, this will be used for user button presses,
#define BUTTON_NEED_PULLUP
#define USE_RF95
#define LORA_DIO0 26 // a No connect on the SX1262 module
#define LORA_RESET 14
#define LORA_DIO1 35 // Not really used
#define LORA_DIO2 34 // Not really used
#elif defined(GENIEBLOCKS)
// This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR HardwareModel_GENIEBLOCKS
#undef GPS_RX_PIN
#undef GPS_TX_PIN
#define GPS_RX_PIN 5
#define GPS_TX_PIN 18
#define GPS_RESET_N 10
#define GPS_EXTINT 23 // On MAX-M8 module pin name is EXTINT. On L70 module pin name is STANDBY.
#define BATTERY_PIN 39 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
#define BATTERY_EN_PIN 14 // Voltage voltage divider enable pin connected to mosfet
#define I2C_SDA 4 // I2C pins for this board
#define I2C_SCL 2
#define LED_PIN 12 // If defined we will blink this LED
//#define BUTTON_PIN 36 // If defined, this will be used for user button presses (ToDo problem on that line on debug screen -->
// Long press start!) #define BUTTON_NEED_PULLUP //GPIOs 34 to 39 are GPIs input only pins. These pins dont have internal
// pull-ups or pull-down resistors.
#define USE_RF95
#define LORA_DIO0 38 // a No connect on the SX1262 module
#define LORA_RESET 9
#define RF95_SCK 22
#define RF95_MISO 19
#define RF95_MOSI 13
#define RF95_NSS 21
#elif defined(PRIVATE_HW)
// This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR HardwareModel_PRIVATE_HW
#endif
@@ -533,100 +238,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define HW_VENDOR HardwareModel_PORTDUINO
#define USE_SIM_RADIO
// Pine64 uses a common pinout for their SX1262 vs RF95 modules - both can be enabled and we will probe at runtime for RF95 and if
// not found then probe for SX1262. Currently the RF95 code is disabled because I think the RF95 module won't need to ship.
// #define USE_RF95
#define USE_SX1262
// Fake SPI device selections
#define RF95_SCK 5
#define RF95_MISO 19
#define RF95_MOSI 27
#define RF95_NSS RADIOLIB_NC // the ch341f spi controller does CS for us
#define LORA_DIO0 26 // a No connect on the SX1262 module
#define LORA_RESET 14
#define LORA_DIO1 33 // SX1262 IRQ, called DIO0 on pinelora schematic, pin 7 on ch341f "ack" - FIXME, enable hwints in linux
#define LORA_DIO2 32 // SX1262 BUSY, actually connected to "DIO5" on pinelora schematic, pin 8 on ch341f "slct"
#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled
#ifdef USE_SX1262
#define SX126X_CS 20 // CS0 on pinelora schematic, hooked to gpio D0 on ch341f
#define SX126X_DIO1 LORA_DIO1
#define SX126X_BUSY LORA_DIO2
#define SX126X_RESET LORA_RESET
// HOPE RFM90 does not have a TCXO therefore not SX126X_E22
#endif
#endif
// DEBUG LED
#ifndef LED_INVERTED
#define LED_INVERTED 0 // define as 1 if LED is active low (on)
#endif
#ifdef USE_RF95
#define RF95_RESET LORA_RESET
#define RF95_IRQ LORA_DIO0 // on SX1262 version this is a no connect DIO0
#define RF95_DIO1 LORA_DIO1 // Note: not really used for RF95
#define RF95_DIO2 LORA_DIO2 // Note: not really used for RF95
#endif
// -----------------------------------------------------------------------------
// DEBUG
// -----------------------------------------------------------------------------
#ifdef CONSOLE_MAX_BAUD
#define SERIAL_BAUD CONSOLE_MAX_BAUD
#else
#define SERIAL_BAUD 921600 // Serial debug baud rate
#endif
#include "SerialConsole.h"
#define DEBUG_PORT (*console) // Serial debug port
// What platforms should use SEGGER?
#ifdef NRF52_SERIES
// Always include the SEGGER code on NRF52 - because useful for debugging
#include "SEGGER_RTT.h"
// The channel we send stdout data to
#define SEGGER_STDOUT_CH 0
// Debug printing to segger console
#define SEGGER_MSG(...) SEGGER_RTT_printf(SEGGER_STDOUT_CH, __VA_ARGS__)
// If we are not on a NRF52840 (which has built in USB-ACM serial support) and we don't have serial pins hooked up, then we MUST
// use SEGGER for debug output
#if !defined(PIN_SERIAL_RX) && !defined(NRF52840_XXAA)
// No serial ports on this board - ONLY use segger in memory console
#define USE_SEGGER
#endif
#else
#define SERIAL0_RX_GPIO 3 // Always GPIO3 on ESP32
#endif
#ifdef USE_SEGGER
#define DEBUG_MSG(...) SEGGER_RTT_printf(0, __VA_ARGS__)
#else
#ifdef DEBUG_PORT
#define DEBUG_MSG(...) DEBUG_PORT.logDebug(__VA_ARGS__)
#else
#define DEBUG_MSG(...)
#endif
#endif
// -----------------------------------------------------------------------------
// AXP192 (Rev1-specific options)
// -----------------------------------------------------------------------------
#define GPS_POWER_CTRL_CH 3
#define LORA_POWER_CTRL_CH 2
// Default Bluetooth PIN
#define defaultBLEPin 123456
#include "variant.h"
#include "RF95Configuration.h"
#include "DebugConfiguration.h"

19
src/debug/axpDebug.h Normal file
View File

@@ -0,0 +1,19 @@
#if 0
// Turn off for now
uint32_t axpDebugRead()
{
axp.debugCharging();
DEBUG_MSG("vbus current %f\n", axp.getVbusCurrent());
DEBUG_MSG("charge current %f\n", axp.getBattChargeCurrent());
DEBUG_MSG("bat voltage %f\n", axp.getBattVoltage());
DEBUG_MSG("batt pct %d\n", axp.getBattPercentage());
DEBUG_MSG("is battery connected %d\n", axp.isBatteryConnect());
DEBUG_MSG("is USB connected %d\n", axp.isVBUSPlug());
DEBUG_MSG("is charging %d\n", axp.isChargeing());
return 30 * 1000;
}
Periodic axpDebugOutput(axpDebugRead);
axpDebugOutput.setup();
#endif

44
src/debug/i2cScan.h Normal file
View File

@@ -0,0 +1,44 @@
#include "../configuration.h"
#include "../main.h"
#include <Wire.h>
#ifndef NO_WIRE
void scanI2Cdevice(void)
{
byte err, addr;
int nDevices = 0;
for (addr = 1; addr < 127; addr++) {
Wire.beginTransmission(addr);
err = Wire.endTransmission();
if (err == 0) {
DEBUG_MSG("I2C device found at address 0x%x\n", addr);
nDevices++;
if (addr == SSD1306_ADDRESS) {
screen_found = addr;
DEBUG_MSG("ssd1306 display found\n");
}
if (addr == ST7567_ADDRESS) {
screen_found = addr;
DEBUG_MSG("st7567 display found\n");
}
#ifdef AXP192_SLAVE_ADDRESS
if (addr == AXP192_SLAVE_ADDRESS) {
axp192_found = true;
DEBUG_MSG("axp192 PMU found\n");
}
#endif
} else if (err == 4) {
DEBUG_MSG("Unknow error at address 0x%x\n", addr);
}
}
if (nDevices == 0)
DEBUG_MSG("No I2C devices found\n");
else
DEBUG_MSG("done\n");
}
#else
void scanI2Cdevice(void) {}
#endif

View File

@@ -58,7 +58,7 @@ int update_size_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_
return 0;
}
#define MAX_BLOCKSIZE 512
#define MAX_BLOCKSIZE_FOR_BT 512
/// Handle writes to data
int update_data_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
@@ -66,7 +66,7 @@ int update_data_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_
concurrency::LockGuard g(updateLock);
static uint8_t
data[MAX_BLOCKSIZE]; // we temporarily copy here because I'm worried that a fast sender might be able overwrite srcbuf
data[MAX_BLOCKSIZE_FOR_BT]; // we temporarily copy here because I'm worried that a fast sender might be able overwrite srcbuf
uint16_t len = 0;
@@ -104,8 +104,8 @@ int update_crc32_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble
} else {
if (Update.end()) {
if (update_region == U_SPIFFS) {
DEBUG_MSG("SPIFFS updated!\n");
nodeDB.saveToDisk(); // Since we just wiped spiffs, we need to save our current state
DEBUG_MSG("Filesystem updated!\n");
nodeDB.saveToDisk(); // Since we just wiped the filesystem, we need to save our current state
} else {
DEBUG_MSG("Appload updated, rebooting in 5 seconds!\n");
rebootAtMsec = millis() + 5000;

View File

@@ -32,7 +32,7 @@ class ESP32CryptoEngine : public CryptoEngine
* @param bytes a _static_ buffer that will remain valid for the life of this crypto instance (i.e. this class will cache the
* provided pointer)
*/
virtual void setKey(const CryptoKey &k)
virtual void setKey(const CryptoKey &k) override
{
CryptoEngine::setKey(k);
@@ -47,7 +47,7 @@ class ESP32CryptoEngine : public CryptoEngine
*
* @param bytes is updated in place
*/
virtual void encrypt(uint32_t fromNode, uint64_t packetNum, size_t numBytes, uint8_t *bytes)
virtual void encrypt(uint32_t fromNode, uint64_t packetNum, size_t numBytes, uint8_t *bytes) override
{
if (key.length > 0) {
uint8_t stream_block[16];
@@ -66,7 +66,7 @@ class ESP32CryptoEngine : public CryptoEngine
}
}
virtual void decrypt(uint32_t fromNode, uint64_t packetNum, size_t numBytes, uint8_t *bytes)
virtual void decrypt(uint32_t fromNode, uint64_t packetNum, size_t numBytes, uint8_t *bytes) override
{
// DEBUG_MSG("ESP32 decrypt!\n");

View File

@@ -14,9 +14,9 @@
*/
class SimpleAllocator
{
uint8_t bytes[POOL_SIZE];
uint8_t bytes[POOL_SIZE] = {};
uint32_t nextFree;
uint32_t nextFree = 0;
public:
SimpleAllocator();
@@ -37,6 +37,6 @@ void *operator new(size_t size, SimpleAllocator &p);
*/
class AllocatorScope {
public:
AllocatorScope(SimpleAllocator &a);
explicit AllocatorScope(SimpleAllocator &a);
~AllocatorScope();
};

View File

@@ -11,10 +11,10 @@ class Air530GPS : public NMEAGPS
{
protected:
/// If possible force the GPS into sleep/low power mode
virtual void sleep();
virtual void sleep() override;
/// wake the GPS into normal operation mode
virtual void wake();
virtual void wake() override;
private:
/// Send a NMEA cmd with checksum

View File

@@ -145,7 +145,7 @@ class GPS : private concurrency::OSThread
*/
void publishUpdate();
virtual int32_t runOnce();
virtual int32_t runOnce() override;
};
// Creates an instance of the GPS class.

View File

@@ -171,7 +171,7 @@ void GeoCoord::latLongToMGRS(const double lat, const double lon, MGRS &mgrs) {
* Based on: https://www.movable-type.co.uk/scripts/latlong-os-gridref.html
*/
void GeoCoord::latLongToOSGR(const double lat, const double lon, OSGR &osgr) {
char letter[] = "ABCDEFGHJKLMNOPQRSTUVWXYZ"; // No 'I' in OSGR
const char letter[] = "ABCDEFGHJKLMNOPQRSTUVWXYZ"; // No 'I' in OSGR
double a = 6377563.396; // Airy 1830 semi-major axis
double b = 6356256.909; // Airy 1830 semi-minor axis
double f0 = 0.9996012717; // National Grid point scale factor on the central meridian
@@ -419,12 +419,12 @@ float GeoCoord::rangeRadiansToMeters(double range_radians) {
}
// Find distance from point to passed in point
int32_t GeoCoord::distanceTo(GeoCoord pointB) {
int32_t GeoCoord::distanceTo(const GeoCoord& pointB) {
return latLongToMeter(this->getLatitude() * 1e-7, this->getLongitude() * 1e-7, pointB.getLatitude() * 1e-7, pointB.getLongitude() * 1e-7);
}
// Find bearing from point to passed in point
int32_t GeoCoord::bearingTo(GeoCoord pointB) {
int32_t GeoCoord::bearingTo(const GeoCoord& pointB) {
return bearing(this->getLatitude() * 1e-7, this->getLongitude() * 1e-7, pointB.getLatitude() * 1e-7, pointB.getLongitude() * 1e-7);
}
@@ -447,4 +447,4 @@ std::shared_ptr<GeoCoord> GeoCoord::pointAtDistance(double bearing, double range
return std::make_shared<GeoCoord>(double(lat), double(lon), this->getAltitude());
}
}

View File

@@ -86,11 +86,11 @@ class GeoCoord {
int32_t _longitude = 0;
int32_t _altitude = 0;
DMS _dms;
UTM _utm;
MGRS _mgrs;
OSGR _osgr;
OLC _olc;
DMS _dms = {};
UTM _utm = {};
MGRS _mgrs = {};
OSGR _osgr = {};
OLC _olc = {};
bool _dirty = true;
@@ -119,8 +119,8 @@ class GeoCoord {
static float rangeMetersToRadians(double range_meters);
// Point to point conversions
int32_t distanceTo(GeoCoord pointB);
int32_t bearingTo(GeoCoord pointB);
int32_t distanceTo(const GeoCoord& pointB);
int32_t bearingTo(const GeoCoord& pointB);
std::shared_ptr<GeoCoord> pointAtDistance(double bearing, double range);
// Lat lon alt getters

View File

@@ -23,14 +23,14 @@ class NMEAGPS : public GPS
#endif
public:
virtual bool setupGPS();
virtual bool setupGPS() override;
protected:
/** Subclasses should look for serial rx characters here and feed it to their GPS parser
*
* Return true if we received a valid message from the GPS
*/
virtual bool whileIdle();
virtual bool whileIdle() override;
/**
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
@@ -38,7 +38,7 @@ class NMEAGPS : public GPS
*
* @return true if we've acquired a time
*/
virtual bool lookForTime();
virtual bool lookForTime() override;
/**
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
@@ -46,7 +46,7 @@ class NMEAGPS : public GPS
*
* @return true if we've acquired a new location
*/
virtual bool lookForLocation();
virtual bool lookForLocation() override;
virtual bool hasLock();
virtual bool hasLock() override;
};

View File

@@ -22,22 +22,22 @@ class UBloxGPS : public GPS
*
* @return true for success
*/
bool factoryReset();
bool factoryReset() override;
protected:
/**
* Returns true if we succeeded
*/
virtual bool setupGPS();
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();
virtual bool whileIdle() override;
/** Idle processing while GPS is looking for lock */
virtual void whileActive();
virtual void whileActive() override;
/**
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
@@ -45,7 +45,7 @@ class UBloxGPS : public GPS
*
* @return true if we've acquired a time
*/
virtual bool lookForTime();
virtual bool lookForTime() override;
/**
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
@@ -53,12 +53,12 @@ class UBloxGPS : public GPS
*
* @return true if we've acquired a new location
*/
virtual bool lookForLocation();
virtual bool hasLock();
virtual bool lookForLocation() override;
virtual bool hasLock() override;
/// If possible force the GPS into sleep/low power mode
virtual void sleep();
virtual void wake();
virtual void sleep() override;
virtual void wake() override;
private:
/// Attempt to connect to our GPS, returns false if no gps is present

View File

@@ -9,14 +9,45 @@
#define COLORED GxEPD_BLACK
#define UNCOLORED GxEPD_WHITE
#if defined(TTGO_T_ECHO)
#define TECHO_DISPLAY_MODEL GxEPD2_154_D67
#elif defined(RAK4630)
//GxEPD2_213_B74 - RAK14000 2.13 inch b/w 250x128
#define TECHO_DISPLAY_MODEL GxEPD2_213_B74
//4.2 inch 300x400 - GxEPD2_420_M01
//#define TECHO_DISPLAY_MODEL GxEPD2_420_M01
//2.9 inch 296x128 - GxEPD2_290_T5D
//#define TECHO_DISPLAY_MODEL GxEPD2_290_T5D
//1.54 inch 200x200 - GxEPD2_154_M09
//#define TECHO_DISPLAY_MODEL GxEPD2_154_M09
#endif
GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT> *adafruitDisplay;
EInkDisplay::EInkDisplay(uint8_t address, int sda, int scl)
{
#if defined(TTGO_T_ECHO)
setGeometry(GEOMETRY_RAWMODE, TECHO_DISPLAY_MODEL::WIDTH, TECHO_DISPLAY_MODEL::HEIGHT);
#elif defined(RAK4630)
//GxEPD2_213_B74 - RAK14000 2.13 inch b/w 250x128
setGeometry(GEOMETRY_RAWMODE, 250, 122);
//GxEPD2_420_M01
//setGeometry(GEOMETRY_RAWMODE, 300, 400);
//GxEPD2_290_T5D
//setGeometry(GEOMETRY_RAWMODE, 296, 128);
//GxEPD2_154_M09
//setGeometry(GEOMETRY_RAWMODE, 200, 200);
#endif
// setGeometry(GEOMETRY_RAWMODE, 128, 64); // old resolution
// setGeometry(GEOMETRY_128_64); // We originally used this because I wasn't sure if rawmode worked - it does
}
@@ -40,8 +71,8 @@ bool EInkDisplay::forceDisplay(uint32_t msecLimit)
// FIXME - only draw bits have changed (use backbuf similar to the other displays)
// tft.drawBitmap(0, 0, buffer, 128, 64, TFT_YELLOW, TFT_BLACK);
for (uint8_t y = 0; y < displayHeight; y++) {
for (uint8_t x = 0; x < displayWidth; x++) {
for (uint64_t y = 0; y < displayHeight; y++) {
for (uint64_t x = 0; x < displayWidth; x++) {
// get src pixel in the page based ordering the OLED lib uses FIXME, super inefficent
auto b = buffer[x + (y / 8) * displayWidth];
@@ -50,9 +81,28 @@ bool EInkDisplay::forceDisplay(uint32_t msecLimit)
}
}
DEBUG_MSG("Updating eink... ");
#if defined(TTGO_T_ECHO)
DEBUG_MSG("Updating T-ECHO E-Paper... ");
#elif defined(RAK4630)
DEBUG_MSG("Updating RAK4361_5005 E-Paper... ");
#endif
#if defined(TTGO_T_ECHO)
// ePaper.Reset(); // wake the screen from sleep
adafruitDisplay->display(false); // FIXME, use partial update mode
#elif defined(RAK4630)
//RAK14000 2.13 inch b/w 250x122 does not support partial updates
adafruitDisplay->display(false); // FIXME, use partial update mode
//Only enable for e-Paper with support for partial updates and comment out above adafruitDisplay->display(false);
// 1.54 inch 200x200 - GxEPD2_154_M09
// 2.9 inch 296x128 - GxEPD2_290_T5D
// 4.2 inch 300x400 - GxEPD2_420_M01
//adafruitDisplay->nextPage();
#endif
// Put screen to sleep to save power (possibly not necessary because we already did poweroff inside of display)
adafruitDisplay->hibernate();
DEBUG_MSG("done\n");
@@ -97,14 +147,33 @@ bool EInkDisplay::connect()
pinMode(PIN_EINK_EN, OUTPUT);
#endif
auto lowLevel = new TECHO_DISPLAY_MODEL(PIN_EINK_CS,
PIN_EINK_DC,
PIN_EINK_RES,
PIN_EINK_BUSY, SPI1);
#if defined(TTGO_T_ECHO)
{
auto lowLevel = new TECHO_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY, SPI1);
adafruitDisplay = new GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT>(*lowLevel);
adafruitDisplay->init();
adafruitDisplay->setRotation(3);
}
#elif defined(RAK4630)
{
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->init(115200, true, 10, false, SPI1, SPISettings(4000000, MSBFIRST, SPI_MODE0));
//RAK14000 2.13 inch b/w 250x122 does not support partial updates
adafruitDisplay->setRotation(3);
//For 1.54, 2.9 and 4.2
//adafruitDisplay->setRotation(1);
adafruitDisplay->setPartialWindow(0, 0, displayWidth, displayHeight);
}
#endif
//adafruitDisplay->setFullWindow();
//adafruitDisplay->fillScreen(UNCOLORED);
//adafruitDisplay->drawCircle(100, 100, 20, COLORED);

View File

@@ -25,7 +25,7 @@ class EInkDisplay : public OLEDDisplay
EInkDisplay(uint8_t address, int sda, int scl);
// Write the buffer to the display memory (for eink we only do this occasionally)
virtual void display(void);
virtual void display(void) override;
/**
* Force a display update if we haven't drawn within the specified msecLimit
@@ -36,13 +36,13 @@ class EInkDisplay : public OLEDDisplay
protected:
// the header size of the buffer used, e.g. for the SPI command header
virtual int getBufferOffset(void) { return 0; }
virtual int getBufferOffset(void) override { return 0; }
// Send a command to the display (low level function)
virtual void sendCommand(uint8_t com);
virtual void sendCommand(uint8_t com) override;
// Connect to the display
virtual bool connect();
virtual bool connect() override;
};

View File

@@ -26,14 +26,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "MeshService.h"
#include "NodeDB.h"
#include "Screen.h"
#include "fonts.h"
#include "gps/GeoCoord.h"
#include "gps/RTC.h"
#include "graphics/images.h"
#include "main.h"
#include "mesh-pb-constants.h"
#include "mesh/Channels.h"
#include "plugins/TextMessagePlugin.h"
#include "modules/TextMessageModule.h"
#include "sleep.h"
#include "target_specific.h"
#include "utils.h"
@@ -68,9 +67,9 @@ uint8_t imgBattery[16] = {0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
// Threshold values for the GPS lock accuracy bar display
uint32_t dopThresholds[5] = {2000, 1000, 500, 200, 100};
// At some point, we're going to ask all of the plugins if they would like to display a screen frame
// we'll need to hold onto pointers for the plugins that can draw a frame.
std::vector<MeshPlugin *> pluginFrames;
// At some point, we're going to ask all of the modules if they would like to display a screen frame
// we'll need to hold onto pointers for the modules that can draw a frame.
std::vector<MeshPlugin *> moduleFrames;
// Stores the last 4 of our hardware ID, to make finding the device for pairing easier
static char ourId[5];
@@ -177,9 +176,9 @@ static void drawSleepScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int
}
#endif
static void drawPluginFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
static void drawModuleFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
uint8_t plugin_frame;
uint8_t module_frame;
// there's a little but in the UI transition code
// where it invokes the function at the correct offset
// in the array of "drawScreen" functions; however,
@@ -188,14 +187,14 @@ static void drawPluginFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int
if (state->frameState == IN_TRANSITION && state->transitionFrameRelationship == INCOMING) {
// if we're transitioning from the end of the frame list back around to the first
// frame, then we want this to be `0`
plugin_frame = state->transitionFrameTarget;
module_frame = state->transitionFrameTarget;
} else {
// otherwise, just display the plugin frame that's aligned with the current frame
plugin_frame = state->currentFrame;
// DEBUG_MSG("Screen is not in transition. Frame: %d\n\n", plugin_frame);
// otherwise, just display the module frame that's aligned with the current frame
module_frame = state->currentFrame;
// DEBUG_MSG("Screen is not in transition. Frame: %d\n\n", module_frame);
}
// DEBUG_MSG("Drawing Plugin Frame %d\n\n", plugin_frame);
MeshPlugin &pi = *pluginFrames.at(plugin_frame);
// DEBUG_MSG("Drawing Module Frame %d\n\n", module_frame);
MeshPlugin &pi = *moduleFrames.at(module_frame);
pi.drawFrame(display, state, x, y);
}
@@ -219,6 +218,14 @@ static void drawFrameBluetooth(OLEDDisplay *display, OLEDDisplayUiState *state,
display->drawString(64 + x, 48 + y, buf);
}
static void drawFrameShutdown(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->setFont(FONT_MEDIUM);
display->drawString(64 + x, 26 + y, "Shutting down...");
}
static void drawFrameFirmware(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
display->setTextAlignment(TEXT_ALIGN_CENTER);
@@ -252,11 +259,11 @@ static void drawCriticalFaultFrame(OLEDDisplay *display, OLEDDisplayUiState *sta
display->drawString(0 + x, FONT_HEIGHT_MEDIUM + y, "For help, please post on\nmeshtastic.discourse.group");
}
// Ignore messages orginating from phone (from the current node 0x0) unless range test or store and forward plugin 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)
{
return packet->from != 0 && !radioConfig.preferences.range_test_plugin_enabled &&
!radioConfig.preferences.store_forward_plugin_enabled;
return packet->from != 0 && !radioConfig.preferences.range_test_module_enabled &&
!radioConfig.preferences.store_forward_module_enabled;
}
/// Draw the last text message we received
@@ -442,10 +449,10 @@ static void drawGPScoordinates(OLEDDisplay *display, int16_t x, int16_t y, const
if (gpsFormat == GpsCoordinateFormat_GpsFormatDec) { // Decimal Degrees
sprintf(coordinateLine, "%f %f", geoCoord.getLatitude() * 1e-7, geoCoord.getLongitude() * 1e-7);
} else if (gpsFormat == GpsCoordinateFormat_GpsFormatUTM) { // Universal Transverse Mercator
sprintf(coordinateLine, "%2i%1c %06i %07i", geoCoord.getUTMZone(), geoCoord.getUTMBand(),
sprintf(coordinateLine, "%2i%1c %06u %07u", geoCoord.getUTMZone(), geoCoord.getUTMBand(),
geoCoord.getUTMEasting(), geoCoord.getUTMNorthing());
} else if (gpsFormat == GpsCoordinateFormat_GpsFormatMGRS) { // Military Grid Reference System
sprintf(coordinateLine, "%2i%1c %1c%1c %05i %05i", geoCoord.getMGRSZone(), geoCoord.getMGRSBand(),
sprintf(coordinateLine, "%2i%1c %1c%1c %05u %05u", geoCoord.getMGRSZone(), geoCoord.getMGRSBand(),
geoCoord.getMGRSEast100k(), geoCoord.getMGRSNorth100k(), geoCoord.getMGRSEasting(),
geoCoord.getMGRSNorthing());
} else if (gpsFormat == GpsCoordinateFormat_GpsFormatOLC) { // Open Location Code
@@ -454,7 +461,7 @@ static void drawGPScoordinates(OLEDDisplay *display, int16_t x, int16_t y, const
if (geoCoord.getOSGRE100k() == 'I' || geoCoord.getOSGRN100k() == 'I') // OSGR is only valid around the UK region
sprintf(coordinateLine, "%s", "Out of Boundary");
else
sprintf(coordinateLine, "%1c%1c %05i %05i", geoCoord.getOSGRE100k(), geoCoord.getOSGRN100k(),
sprintf(coordinateLine, "%1c%1c %05u %05u", geoCoord.getOSGRE100k(), geoCoord.getOSGRN100k(),
geoCoord.getOSGREasting(), geoCoord.getOSGRNorthing());
}
@@ -472,9 +479,9 @@ static void drawGPScoordinates(OLEDDisplay *display, int16_t x, int16_t y, const
} else {
char latLine[22];
char lonLine[22];
sprintf(latLine, "%2i° %2i' %2.4f\" %1c", geoCoord.getDMSLatDeg(), geoCoord.getDMSLatMin(), geoCoord.getDMSLatSec(),
sprintf(latLine, "%2i° %2i' %2u\" %1c", geoCoord.getDMSLatDeg(), geoCoord.getDMSLatMin(), geoCoord.getDMSLatSec(),
geoCoord.getDMSLatCP());
sprintf(lonLine, "%3i° %2i' %2.4f\" %1c", geoCoord.getDMSLonDeg(), geoCoord.getDMSLonMin(), geoCoord.getDMSLonSec(),
sprintf(lonLine, "%3i° %2i' %2u\" %1c", geoCoord.getDMSLonDeg(), geoCoord.getDMSLonMin(), geoCoord.getDMSLonSec(),
geoCoord.getDMSLonCP());
display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(latLine))) / 2, y - FONT_HEIGHT_SMALL * 1, latLine);
display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(lonLine))) / 2, y, lonLine);
@@ -644,7 +651,6 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
static char distStr[20];
strcpy(distStr, "? km"); // might not have location data
float headingRadian;
NodeInfo *ourNode = nodeDB.getNode(nodeDB.getNodeNum());
const char *fields[] = {username, distStr, signalStr, lastStr, NULL};
@@ -672,7 +678,7 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
// it. currently we don't do this and instead draw north up only.
float bearingToOther =
GeoCoord::bearing(DegD(p.latitude_i), DegD(p.longitude_i), DegD(op.latitude_i), DegD(op.longitude_i));
headingRadian = bearingToOther - myHeading;
float headingRadian = bearingToOther - myHeading;
drawNodeHeading(display, compassX, compassY, headingRadian);
}
}
@@ -818,8 +824,11 @@ void Screen::setup()
powerStatusObserver.observe(&powerStatus->onNewStatus);
gpsStatusObserver.observe(&gpsStatus->onNewStatus);
nodeStatusObserver.observe(&nodeStatus->onNewStatus);
if (textMessagePlugin)
textMessageObserver.observe(textMessagePlugin);
if (textMessageModule)
textMessageObserver.observe(textMessageModule);
// Modules can notify screen about refresh
MeshPlugin::observeUIEvents(&uiFrameEventObserver);
}
void Screen::forceDisplay()
@@ -878,6 +887,9 @@ int32_t Screen::runOnce()
handlePrint(cmd.print_text);
free(cmd.print_text);
break;
case Cmd::START_SHUTDOWN_SCREEN:
handleShutdownScreen();
break;
default:
DEBUG_MSG("BUG: invalid cmd\n");
}
@@ -930,20 +942,20 @@ int32_t Screen::runOnce()
void Screen::drawDebugInfoTrampoline(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
Screen *screen = reinterpret_cast<Screen *>(state->userData);
screen->debugInfo.drawFrame(display, state, x, y);
Screen *screen2 = reinterpret_cast<Screen *>(state->userData);
screen2->debugInfo.drawFrame(display, state, x, y);
}
void Screen::drawDebugInfoSettingsTrampoline(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
Screen *screen = reinterpret_cast<Screen *>(state->userData);
screen->debugInfo.drawFrameSettings(display, state, x, y);
Screen *screen2 = reinterpret_cast<Screen *>(state->userData);
screen2->debugInfo.drawFrameSettings(display, state, x, y);
}
void Screen::drawDebugInfoWiFiTrampoline(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
Screen *screen = reinterpret_cast<Screen *>(state->userData);
screen->debugInfo.drawFrameWiFi(display, state, x, y);
Screen *screen2 = reinterpret_cast<Screen *>(state->userData);
screen2->debugInfo.drawFrameWiFi(display, state, x, y);
}
/* show a message that the SSL cert is being built
@@ -964,9 +976,9 @@ void Screen::setFrames()
DEBUG_MSG("showing standard frames\n");
showingNormalScreen = true;
pluginFrames = MeshPlugin::GetMeshPluginsWithUIFrames();
DEBUG_MSG("Showing %d plugin frames\n", pluginFrames.size());
int totalFrameCount = MAX_NUM_NODES + NUM_EXTRA_FRAMES + pluginFrames.size();
moduleFrames = MeshPlugin::GetMeshModulesWithUIFrames();
DEBUG_MSG("Showing %d module frames\n", moduleFrames.size());
int totalFrameCount = MAX_NUM_NODES + NUM_EXTRA_FRAMES + moduleFrames.size();
DEBUG_MSG("Total frame count: %d\n", totalFrameCount);
// We don't show the node info our our node (if we have it yet - we should)
@@ -976,23 +988,23 @@ void Screen::setFrames()
size_t numframes = 0;
// put all of the plugin frames first.
// put all of the module frames first.
// this is a little bit of a dirty hack; since we're going to call
// the same drawPluginFrame handler here for all of these plugin frames
// the same drawModuleFrame handler here for all of these module frames
// and then we'll just assume that the state->currentFrame value
// is the same offset into the pluginFrames vector
// so that we can invoke the plugin's callback
for (auto i = pluginFrames.begin(); i != pluginFrames.end(); ++i) {
normalFrames[numframes++] = drawPluginFrame;
// is the same offset into the moduleFrames vector
// so that we can invoke the module's callback
for (auto i = moduleFrames.begin(); i != moduleFrames.end(); ++i) {
normalFrames[numframes++] = drawModuleFrame;
}
DEBUG_MSG("Added plugins. numframes: %d\n", numframes);
DEBUG_MSG("Added modules. numframes: %d\n", numframes);
// If we have a critical fault, show it first
if (myNodeInfo.error_code)
normalFrames[numframes++] = drawCriticalFaultFrame;
// If we have a text message - show it next, unless it's a phone message and we aren't using any special plugins
// If we have a text message - show it next, unless it's a phone message and we aren't using any special modules
if (devicestate.has_rx_text_message && shouldDrawMessage(&devicestate.rx_text_message)) {
normalFrames[numframes++] = drawTextMessageFrame;
}
@@ -1037,13 +1049,25 @@ void Screen::handleStartBluetoothPinScreen(uint32_t pin)
static FrameCallback btFrames[] = {drawFrameBluetooth};
snprintf(btPIN, sizeof(btPIN), "%06lu", pin);
snprintf(btPIN, sizeof(btPIN), "%06u", pin);
ui.disableAllIndicators();
ui.setFrames(btFrames, 1);
setFastFramerate();
}
void Screen::handleShutdownScreen()
{
DEBUG_MSG("showing shutdown screen\n");
showingNormalScreen = false;
static FrameCallback shutdownFrames[] = {drawFrameShutdown};
ui.disableAllIndicators();
ui.setFrames(shutdownFrames, 1);
setFastFramerate();
}
void Screen::handleStartFirmwareUpdateScreen()
{
DEBUG_MSG("showing firmware screen\n");
@@ -1457,4 +1481,23 @@ int Screen::handleTextMessage(const MeshPacket *packet)
return 0;
}
int Screen::handleUIFrameEvent(const UIFrameEvent *event)
{
if (showingNormalScreen) {
if (event->frameChanged)
{
setFrames(); // Regen the list of screens (will show new text message)
}
else if (event->needRedraw)
{
setFastFramerate();
// TODO: We might also want switch to corresponding frame,
// but we don't know the exact frame number.
//ui.switchToFrame(0);
}
}
return 0;
}
} // namespace graphics

View File

@@ -40,6 +40,7 @@ class Screen
#include "concurrency/OSThread.h"
#include "power.h"
#include <string>
#include "mesh/MeshPlugin.h"
// 0 to 255, though particular variants might define different defaults
#ifndef BRIGHTNESS_DEFAULT
@@ -90,9 +91,11 @@ class Screen : public concurrency::OSThread
CallbackObserver<Screen, const meshtastic::Status *>(this, &Screen::handleStatusUpdate);
CallbackObserver<Screen, const MeshPacket *> textMessageObserver =
CallbackObserver<Screen, const MeshPacket *>(this, &Screen::handleTextMessage);
CallbackObserver<Screen, const UIFrameEvent *> uiFrameEventObserver =
CallbackObserver<Screen, const UIFrameEvent *>(this, &Screen::handleUIFrameEvent);
public:
Screen(uint8_t address, int sda = -1, int scl = -1);
explicit Screen(uint8_t address, int sda = -1, int scl = -1);
Screen(const Screen &) = delete;
Screen &operator=(const Screen &) = delete;
@@ -148,6 +151,12 @@ class Screen : public concurrency::OSThread
enqueueCmd(cmd);
}
void startShutdownScreen()
{
ScreenCmd cmd;
cmd.cmd = Cmd::START_SHUTDOWN_SCREEN;
enqueueCmd(cmd);
}
/// Stops showing the bluetooth PIN screen.
void stopBluetoothPinScreen() { enqueueCmd(ScreenCmd{.cmd = Cmd::STOP_BLUETOOTH_PIN_SCREEN}); }
@@ -218,6 +227,7 @@ class Screen : public concurrency::OSThread
int handleStatusUpdate(const meshtastic::Status *arg);
int handleTextMessage(const MeshPacket *arg);
int handleUIFrameEvent(const UIFrameEvent *arg);
/// Used to force (super slow) eink displays to draw critical frames
void forceDisplay();
@@ -258,7 +268,7 @@ class Screen : public concurrency::OSThread
void handleStartBluetoothPinScreen(uint32_t pin);
void handlePrint(const char *text);
void handleStartFirmwareUpdateScreen();
void handleShutdownScreen();
/// Rebuilds our list of frames (screens) to default ones.
void setFrames();
@@ -303,4 +313,4 @@ class Screen : public concurrency::OSThread
};
} // namespace graphics
#endif
#endif

View File

@@ -21,15 +21,15 @@ class TFTDisplay : public OLEDDisplay
TFTDisplay(uint8_t address, int sda, int scl);
// Write the buffer to the display memory
virtual void display(void);
virtual void display(void) override;
protected:
// the header size of the buffer used, e.g. for the SPI command header
virtual int getBufferOffset(void) { return 0; }
virtual int getBufferOffset(void) override { return 0; }
// Send a command to the display (low level function)
virtual void sendCommand(uint8_t com);
virtual void sendCommand(uint8_t com) override;
// Connect to the display
virtual bool connect();
virtual bool connect() override;
};

View File

@@ -1,425 +0,0 @@
#pragma once
const uint8_t Custom_ArialMT_Plain_10[] PROGMEM = {
0x0A, // Width: 10
0x0A, // Height: 10
0x20, // First Char: 32
0xE0, // Numbers of Chars: 224
// Jump Table:
0xFF, 0xFF, 0x00, 0x03, // 32:65535
0x00, 0x00, 0x04, 0x03, // 33:0
0x00, 0x04, 0x05, 0x04, // 34:4
0x00, 0x09, 0x09, 0x06, // 35:9
0x00, 0x12, 0x0A, 0x06, // 36:18
0x00, 0x1C, 0x10, 0x09, // 37:28
0x00, 0x2C, 0x0E, 0x07, // 38:44
0x00, 0x3A, 0x01, 0x02, // 39:58
0x00, 0x3B, 0x06, 0x03, // 40:59
0x00, 0x41, 0x06, 0x03, // 41:65
0x00, 0x47, 0x05, 0x04, // 42:71
0x00, 0x4C, 0x09, 0x06, // 43:76
0x00, 0x55, 0x04, 0x03, // 44:85
0x00, 0x59, 0x03, 0x03, // 45:89
0x00, 0x5C, 0x04, 0x03, // 46:92
0x00, 0x60, 0x05, 0x03, // 47:96
0x00, 0x65, 0x0A, 0x06, // 48:101
0x00, 0x6F, 0x08, 0x06, // 49:111
0x00, 0x77, 0x0A, 0x06, // 50:119
0x00, 0x81, 0x0A, 0x06, // 51:129
0x00, 0x8B, 0x0B, 0x06, // 52:139
0x00, 0x96, 0x0A, 0x06, // 53:150
0x00, 0xA0, 0x0A, 0x06, // 54:160
0x00, 0xAA, 0x09, 0x06, // 55:170
0x00, 0xB3, 0x0A, 0x06, // 56:179
0x00, 0xBD, 0x0A, 0x06, // 57:189
0x00, 0xC7, 0x04, 0x03, // 58:199
0x00, 0xCB, 0x04, 0x03, // 59:203
0x00, 0xCF, 0x0A, 0x06, // 60:207
0x00, 0xD9, 0x09, 0x06, // 61:217
0x00, 0xE2, 0x09, 0x06, // 62:226
0x00, 0xEB, 0x0B, 0x06, // 63:235
0x00, 0xF6, 0x14, 0x0A, // 64:246
0x01, 0x0A, 0x0E, 0x07, // 65:266
0x01, 0x18, 0x0C, 0x07, // 66:280
0x01, 0x24, 0x0C, 0x07, // 67:292
0x01, 0x30, 0x0B, 0x07, // 68:304
0x01, 0x3B, 0x0C, 0x07, // 69:315
0x01, 0x47, 0x09, 0x06, // 70:327
0x01, 0x50, 0x0D, 0x08, // 71:336
0x01, 0x5D, 0x0C, 0x07, // 72:349
0x01, 0x69, 0x04, 0x03, // 73:361
0x01, 0x6D, 0x08, 0x05, // 74:365
0x01, 0x75, 0x0E, 0x07, // 75:373
0x01, 0x83, 0x0C, 0x06, // 76:387
0x01, 0x8F, 0x10, 0x08, // 77:399
0x01, 0x9F, 0x0C, 0x07, // 78:415
0x01, 0xAB, 0x0E, 0x08, // 79:427
0x01, 0xB9, 0x0B, 0x07, // 80:441
0x01, 0xC4, 0x0E, 0x08, // 81:452
0x01, 0xD2, 0x0C, 0x07, // 82:466
0x01, 0xDE, 0x0C, 0x07, // 83:478
0x01, 0xEA, 0x0B, 0x06, // 84:490
0x01, 0xF5, 0x0C, 0x07, // 85:501
0x02, 0x01, 0x0D, 0x07, // 86:513
0x02, 0x0E, 0x11, 0x09, // 87:526
0x02, 0x1F, 0x0E, 0x07, // 88:543
0x02, 0x2D, 0x0D, 0x07, // 89:557
0x02, 0x3A, 0x0C, 0x06, // 90:570
0x02, 0x46, 0x06, 0x03, // 91:582
0x02, 0x4C, 0x06, 0x03, // 92:588
0x02, 0x52, 0x04, 0x03, // 93:594
0x02, 0x56, 0x09, 0x05, // 94:598
0x02, 0x5F, 0x0C, 0x06, // 95:607
0x02, 0x6B, 0x03, 0x03, // 96:619
0x02, 0x6E, 0x0A, 0x06, // 97:622
0x02, 0x78, 0x0A, 0x06, // 98:632
0x02, 0x82, 0x0A, 0x05, // 99:642
0x02, 0x8C, 0x0A, 0x06, // 100:652
0x02, 0x96, 0x0A, 0x06, // 101:662
0x02, 0xA0, 0x05, 0x03, // 102:672
0x02, 0xA5, 0x0A, 0x06, // 103:677
0x02, 0xAF, 0x0A, 0x06, // 104:687
0x02, 0xB9, 0x04, 0x02, // 105:697
0x02, 0xBD, 0x04, 0x02, // 106:701
0x02, 0xC1, 0x08, 0x05, // 107:705
0x02, 0xC9, 0x04, 0x02, // 108:713
0x02, 0xCD, 0x10, 0x08, // 109:717
0x02, 0xDD, 0x0A, 0x06, // 110:733
0x02, 0xE7, 0x0A, 0x06, // 111:743
0x02, 0xF1, 0x0A, 0x06, // 112:753
0x02, 0xFB, 0x0A, 0x06, // 113:763
0x03, 0x05, 0x05, 0x03, // 114:773
0x03, 0x0A, 0x08, 0x05, // 115:778
0x03, 0x12, 0x06, 0x03, // 116:786
0x03, 0x18, 0x0A, 0x06, // 117:792
0x03, 0x22, 0x09, 0x05, // 118:802
0x03, 0x2B, 0x0E, 0x07, // 119:811
0x03, 0x39, 0x0A, 0x05, // 120:825
0x03, 0x43, 0x09, 0x05, // 121:835
0x03, 0x4C, 0x0A, 0x05, // 122:844
0x03, 0x56, 0x06, 0x03, // 123:854
0x03, 0x5C, 0x04, 0x03, // 124:860
0x03, 0x60, 0x05, 0x03, // 125:864
0x03, 0x65, 0x09, 0x06, // 126:869
0xFF, 0xFF, 0x00, 0x00, // 127:65535
0xFF, 0xFF, 0x00, 0x0A, // 128:65535
0xFF, 0xFF, 0x00, 0x0A, // 129:65535
0xFF, 0xFF, 0x00, 0x0A, // 130:65535
0xFF, 0xFF, 0x00, 0x0A, // 131:65535
0xFF, 0xFF, 0x00, 0x0A, // 132:65535
0xFF, 0xFF, 0x00, 0x0A, // 133:65535
0xFF, 0xFF, 0x00, 0x0A, // 134:65535
0xFF, 0xFF, 0x00, 0x0A, // 135:65535
0xFF, 0xFF, 0x00, 0x0A, // 136:65535
0xFF, 0xFF, 0x00, 0x0A, // 137:65535
0xFF, 0xFF, 0x00, 0x0A, // 138:65535
0xFF, 0xFF, 0x00, 0x0A, // 139:65535
0xFF, 0xFF, 0x00, 0x0A, // 140:65535
0xFF, 0xFF, 0x00, 0x0A, // 141:65535
0xFF, 0xFF, 0x00, 0x0A, // 142:65535
0xFF, 0xFF, 0x00, 0x0A, // 143:65535
0xFF, 0xFF, 0x00, 0x0A, // 144:65535
0xFF, 0xFF, 0x00, 0x0A, // 145:65535
0xFF, 0xFF, 0x00, 0x0A, // 146:65535
0xFF, 0xFF, 0x00, 0x0A, // 147:65535
0xFF, 0xFF, 0x00, 0x0A, // 148:65535
0xFF, 0xFF, 0x00, 0x0A, // 149:65535
0xFF, 0xFF, 0x00, 0x0A, // 150:65535
0xFF, 0xFF, 0x00, 0x0A, // 151:65535
0xFF, 0xFF, 0x00, 0x0A, // 152:65535
0xFF, 0xFF, 0x00, 0x0A, // 153:65535
0xFF, 0xFF, 0x00, 0x0A, // 154:65535
0xFF, 0xFF, 0x00, 0x0A, // 155:65535
0xFF, 0xFF, 0x00, 0x0A, // 156:65535
0xFF, 0xFF, 0x00, 0x0A, // 157:65535
0xFF, 0xFF, 0x00, 0x0A, // 158:65535
0xFF, 0xFF, 0x00, 0x0A, // 159:65535
0xFF, 0xFF, 0x00, 0x03, // 160:65535
0x03, 0x6E, 0x04, 0x03, // 161:878
0x03, 0x72, 0x0A, 0x06, // 162:882
0x03, 0x7C, 0x0C, 0x06, // 163:892
0x03, 0x88, 0x0A, 0x06, // 164:904
0x03, 0x92, 0x0A, 0x06, // 165:914
0x03, 0x9C, 0x04, 0x03, // 166:924
0x03, 0xA0, 0x0A, 0x06, // 167:928
0x03, 0xAA, 0x05, 0x03, // 168:938
0x03, 0xAF, 0x0D, 0x07, // 169:943
0x03, 0xBC, 0x07, 0x04, // 170:956
0x03, 0xC3, 0x0A, 0x06, // 171:963
0x03, 0xCD, 0x09, 0x06, // 172:973
0x03, 0xD6, 0x03, 0x03, // 173:982
0x03, 0xD9, 0x0D, 0x07, // 174:985
0x03, 0xE6, 0x0B, 0x06, // 175:998
0x03, 0xF1, 0x07, 0x04, // 176:1009
0x03, 0xF8, 0x0A, 0x05, // 177:1016
0x04, 0x02, 0x05, 0x03, // 178:1026
0x04, 0x07, 0x05, 0x03, // 179:1031
0x04, 0x0C, 0x05, 0x03, // 180:1036
0x04, 0x11, 0x0A, 0x06, // 181:1041
0x04, 0x1B, 0x09, 0x05, // 182:1051
0x04, 0x24, 0x03, 0x03, // 183:1060
0x04, 0x27, 0x06, 0x03, // 184:1063
0x04, 0x2D, 0x05, 0x03, // 185:1069
0x04, 0x32, 0x07, 0x04, // 186:1074
0x04, 0x39, 0x0A, 0x06, // 187:1081
0x04, 0x43, 0x10, 0x08, // 188:1091
0x04, 0x53, 0x10, 0x08, // 189:1107
0x04, 0x63, 0x10, 0x08, // 190:1123
0x04, 0x73, 0x0A, 0x06, // 191:1139
0x04, 0x7D, 0x0E, 0x07, // 192:1149
0x04, 0x8B, 0x0E, 0x07, // 193:1163
0x04, 0x99, 0x0E, 0x07, // 194:1177
0x04, 0xA7, 0x0E, 0x07, // 195:1191
0x04, 0xB5, 0x0E, 0x07, // 196:1205
0x04, 0xC3, 0x0E, 0x07, // 197:1219
0x04, 0xD1, 0x12, 0x0A, // 198:1233
0x04, 0xE3, 0x0C, 0x07, // 199:1251
0x04, 0xEF, 0x0C, 0x07, // 200:1263
0x04, 0xFB, 0x0C, 0x07, // 201:1275
0x05, 0x07, 0x0C, 0x07, // 202:1287
0x05, 0x13, 0x0C, 0x07, // 203:1299
0x05, 0x1F, 0x05, 0x03, // 204:1311
0x05, 0x24, 0x04, 0x03, // 205:1316
0x05, 0x28, 0x04, 0x03, // 206:1320
0x05, 0x2C, 0x05, 0x03, // 207:1324
0x05, 0x31, 0x0B, 0x07, // 208:1329
0x05, 0x3C, 0x0C, 0x07, // 209:1340
0x05, 0x48, 0x0E, 0x08, // 210:1352
0x05, 0x56, 0x0E, 0x08, // 211:1366
0x05, 0x64, 0x0E, 0x08, // 212:1380
0x05, 0x72, 0x0E, 0x08, // 213:1394
0x05, 0x80, 0x0E, 0x08, // 214:1408
0x05, 0x8E, 0x0A, 0x06, // 215:1422
0x05, 0x98, 0x0D, 0x08, // 216:1432
0x05, 0xA5, 0x0C, 0x07, // 217:1445
0x05, 0xB1, 0x0C, 0x07, // 218:1457
0x05, 0xBD, 0x0C, 0x07, // 219:1469
0x05, 0xC9, 0x0C, 0x07, // 220:1481
0x05, 0xD5, 0x0D, 0x07, // 221:1493
0x05, 0xE2, 0x0B, 0x07, // 222:1506
0x05, 0xED, 0x0C, 0x06, // 223:1517
0x05, 0xF9, 0x0A, 0x06, // 224:1529
0x06, 0x03, 0x0A, 0x06, // 225:1539
0x06, 0x0D, 0x0A, 0x06, // 226:1549
0x06, 0x17, 0x0A, 0x06, // 227:1559
0x06, 0x21, 0x0A, 0x06, // 228:1569
0x06, 0x2B, 0x0A, 0x06, // 229:1579
0x06, 0x35, 0x10, 0x09, // 230:1589
0x06, 0x45, 0x0A, 0x05, // 231:1605
0x06, 0x4F, 0x0A, 0x06, // 232:1615
0x06, 0x59, 0x0A, 0x06, // 233:1625
0x06, 0x63, 0x0A, 0x06, // 234:1635
0x06, 0x6D, 0x0A, 0x06, // 235:1645
0x06, 0x77, 0x05, 0x03, // 236:1655
0x06, 0x7C, 0x04, 0x03, // 237:1660
0x06, 0x80, 0x05, 0x03, // 238:1664
0x06, 0x85, 0x05, 0x03, // 239:1669
0x06, 0x8A, 0x0A, 0x06, // 240:1674
0x06, 0x94, 0x0A, 0x06, // 241:1684
0x06, 0x9E, 0x0A, 0x06, // 242:1694
0x06, 0xA8, 0x0A, 0x06, // 243:1704
0x06, 0xB2, 0x0A, 0x06, // 244:1714
0x06, 0xBC, 0x0A, 0x06, // 245:1724
0x06, 0xC6, 0x0A, 0x06, // 246:1734
0x06, 0xD0, 0x09, 0x05, // 247:1744
0x06, 0xD9, 0x0A, 0x06, // 248:1753
0x06, 0xE3, 0x0A, 0x06, // 249:1763
0x06, 0xED, 0x0A, 0x06, // 250:1773
0x06, 0xF7, 0x0A, 0x06, // 251:1783
0x07, 0x01, 0x0A, 0x06, // 252:1793
0x07, 0x0B, 0x09, 0x05, // 253:1803
0x07, 0x14, 0x0A, 0x06, // 254:1812
0x07, 0x1E, 0x09, 0x05, // 255:1822
// Font Data:
0x00, 0x00, 0xF8, 0x02, // 33
0x38, 0x00, 0x00, 0x00, 0x38, // 34
0xA0, 0x03, 0xE0, 0x00, 0xB8, 0x03, 0xE0, 0x00, 0xB8, // 35
0x30, 0x01, 0x28, 0x02, 0xF8, 0x07, 0x48, 0x02, 0x90, 0x01, // 36
0x00, 0x00, 0x30, 0x00, 0x48, 0x00, 0x30, 0x03, 0xC0, 0x00, 0xB0, 0x01, 0x48, 0x02, 0x80, 0x01, // 37
0x80, 0x01, 0x50, 0x02, 0x68, 0x02, 0xA8, 0x02, 0x18, 0x01, 0x80, 0x03, 0x80, 0x02, // 38
0x38, // 39
0xE0, 0x03, 0x10, 0x04, 0x08, 0x08, // 40
0x08, 0x08, 0x10, 0x04, 0xE0, 0x03, // 41
0x28, 0x00, 0x18, 0x00, 0x28, // 42
0x40, 0x00, 0x40, 0x00, 0xF0, 0x01, 0x40, 0x00, 0x40, // 43
0x00, 0x00, 0x00, 0x06, // 44
0x80, 0x00, 0x80, // 45
0x00, 0x00, 0x00, 0x02, // 46
0x00, 0x03, 0xE0, 0x00, 0x18, // 47
0xF0, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x02, 0xF0, 0x01, // 48
0x00, 0x00, 0x20, 0x00, 0x10, 0x00, 0xF8, 0x03, // 49
0x10, 0x02, 0x08, 0x03, 0x88, 0x02, 0x48, 0x02, 0x30, 0x02, // 50
0x10, 0x01, 0x08, 0x02, 0x48, 0x02, 0x48, 0x02, 0xB0, 0x01, // 51
0xC0, 0x00, 0xA0, 0x00, 0x90, 0x00, 0x88, 0x00, 0xF8, 0x03, 0x80, // 52
0x60, 0x01, 0x38, 0x02, 0x28, 0x02, 0x28, 0x02, 0xC8, 0x01, // 53
0xF0, 0x01, 0x28, 0x02, 0x28, 0x02, 0x28, 0x02, 0xD0, 0x01, // 54
0x08, 0x00, 0x08, 0x03, 0xC8, 0x00, 0x38, 0x00, 0x08, // 55
0xB0, 0x01, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0xB0, 0x01, // 56
0x70, 0x01, 0x88, 0x02, 0x88, 0x02, 0x88, 0x02, 0xF0, 0x01, // 57
0x00, 0x00, 0x20, 0x02, // 58
0x00, 0x00, 0x20, 0x06, // 59
0x00, 0x00, 0x40, 0x00, 0xA0, 0x00, 0xA0, 0x00, 0x10, 0x01, // 60
0xA0, 0x00, 0xA0, 0x00, 0xA0, 0x00, 0xA0, 0x00, 0xA0, // 61
0x00, 0x00, 0x10, 0x01, 0xA0, 0x00, 0xA0, 0x00, 0x40, // 62
0x10, 0x00, 0x08, 0x00, 0x08, 0x00, 0xC8, 0x02, 0x48, 0x00, 0x30, // 63
0x00, 0x00, 0xC0, 0x03, 0x30, 0x04, 0xD0, 0x09, 0x28, 0x0A, 0x28, 0x0A, 0xC8, 0x0B, 0x68, 0x0A, 0x10, 0x05, 0xE0, 0x04, // 64
0x00, 0x02, 0xC0, 0x01, 0xB0, 0x00, 0x88, 0x00, 0xB0, 0x00, 0xC0, 0x01, 0x00, 0x02, // 65
0x00, 0x00, 0xF8, 0x03, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0xF0, 0x01, // 66
0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x02, 0x10, 0x01, // 67
0x00, 0x00, 0xF8, 0x03, 0x08, 0x02, 0x08, 0x02, 0x10, 0x01, 0xE0, // 68
0x00, 0x00, 0xF8, 0x03, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, // 69
0x00, 0x00, 0xF8, 0x03, 0x48, 0x00, 0x48, 0x00, 0x08, // 70
0x00, 0x00, 0xE0, 0x00, 0x10, 0x01, 0x08, 0x02, 0x48, 0x02, 0x50, 0x01, 0xC0, // 71
0x00, 0x00, 0xF8, 0x03, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0xF8, 0x03, // 72
0x00, 0x00, 0xF8, 0x03, // 73
0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0xF8, 0x01, // 74
0x00, 0x00, 0xF8, 0x03, 0x80, 0x00, 0x60, 0x00, 0x90, 0x00, 0x08, 0x01, 0x00, 0x02, // 75
0x00, 0x00, 0xF8, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, // 76
0x00, 0x00, 0xF8, 0x03, 0x30, 0x00, 0xC0, 0x01, 0x00, 0x02, 0xC0, 0x01, 0x30, 0x00, 0xF8, 0x03, // 77
0x00, 0x00, 0xF8, 0x03, 0x30, 0x00, 0x40, 0x00, 0x80, 0x01, 0xF8, 0x03, // 78
0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x02, 0x08, 0x02, 0xF0, 0x01, // 79
0x00, 0x00, 0xF8, 0x03, 0x48, 0x00, 0x48, 0x00, 0x48, 0x00, 0x30, // 80
0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x03, 0x08, 0x03, 0xF0, 0x02, // 81
0x00, 0x00, 0xF8, 0x03, 0x48, 0x00, 0x48, 0x00, 0xC8, 0x00, 0x30, 0x03, // 82
0x00, 0x00, 0x30, 0x01, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0x90, 0x01, // 83
0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0xF8, 0x03, 0x08, 0x00, 0x08, // 84
0x00, 0x00, 0xF8, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0xF8, 0x01, // 85
0x08, 0x00, 0x70, 0x00, 0x80, 0x01, 0x00, 0x02, 0x80, 0x01, 0x70, 0x00, 0x08, // 86
0x18, 0x00, 0xE0, 0x01, 0x00, 0x02, 0xF0, 0x01, 0x08, 0x00, 0xF0, 0x01, 0x00, 0x02, 0xE0, 0x01, 0x18, // 87
0x00, 0x02, 0x08, 0x01, 0x90, 0x00, 0x60, 0x00, 0x90, 0x00, 0x08, 0x01, 0x00, 0x02, // 88
0x08, 0x00, 0x10, 0x00, 0x20, 0x00, 0xC0, 0x03, 0x20, 0x00, 0x10, 0x00, 0x08, // 89
0x08, 0x03, 0x88, 0x02, 0xC8, 0x02, 0x68, 0x02, 0x38, 0x02, 0x18, 0x02, // 90
0x00, 0x00, 0xF8, 0x0F, 0x08, 0x08, // 91
0x18, 0x00, 0xE0, 0x00, 0x00, 0x03, // 92
0x08, 0x08, 0xF8, 0x0F, // 93
0x40, 0x00, 0x30, 0x00, 0x08, 0x00, 0x30, 0x00, 0x40, // 94
0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, // 95
0x08, 0x00, 0x10, // 96
0x00, 0x00, 0x00, 0x03, 0xA0, 0x02, 0xA0, 0x02, 0xE0, 0x03, // 97
0x00, 0x00, 0xF8, 0x03, 0x20, 0x02, 0x20, 0x02, 0xC0, 0x01, // 98
0x00, 0x00, 0xC0, 0x01, 0x20, 0x02, 0x20, 0x02, 0x40, 0x01, // 99
0x00, 0x00, 0xC0, 0x01, 0x20, 0x02, 0x20, 0x02, 0xF8, 0x03, // 100
0x00, 0x00, 0xC0, 0x01, 0xA0, 0x02, 0xA0, 0x02, 0xC0, 0x02, // 101
0x20, 0x00, 0xF0, 0x03, 0x28, // 102
0x00, 0x00, 0xC0, 0x05, 0x20, 0x0A, 0x20, 0x0A, 0xE0, 0x07, // 103
0x00, 0x00, 0xF8, 0x03, 0x20, 0x00, 0x20, 0x00, 0xC0, 0x03, // 104
0x00, 0x00, 0xE8, 0x03, // 105
0x00, 0x08, 0xE8, 0x07, // 106
0xF8, 0x03, 0x80, 0x00, 0xC0, 0x01, 0x20, 0x02, // 107
0x00, 0x00, 0xF8, 0x03, // 108
0x00, 0x00, 0xE0, 0x03, 0x20, 0x00, 0x20, 0x00, 0xE0, 0x03, 0x20, 0x00, 0x20, 0x00, 0xC0, 0x03, // 109
0x00, 0x00, 0xE0, 0x03, 0x20, 0x00, 0x20, 0x00, 0xC0, 0x03, // 110
0x00, 0x00, 0xC0, 0x01, 0x20, 0x02, 0x20, 0x02, 0xC0, 0x01, // 111
0x00, 0x00, 0xE0, 0x0F, 0x20, 0x02, 0x20, 0x02, 0xC0, 0x01, // 112
0x00, 0x00, 0xC0, 0x01, 0x20, 0x02, 0x20, 0x02, 0xE0, 0x0F, // 113
0x00, 0x00, 0xE0, 0x03, 0x20, // 114
0x40, 0x02, 0xA0, 0x02, 0xA0, 0x02, 0x20, 0x01, // 115
0x20, 0x00, 0xF8, 0x03, 0x20, 0x02, // 116
0x00, 0x00, 0xE0, 0x01, 0x00, 0x02, 0x00, 0x02, 0xE0, 0x03, // 117
0x20, 0x00, 0xC0, 0x01, 0x00, 0x02, 0xC0, 0x01, 0x20, // 118
0xE0, 0x01, 0x00, 0x02, 0xC0, 0x01, 0x20, 0x00, 0xC0, 0x01, 0x00, 0x02, 0xE0, 0x01, // 119
0x20, 0x02, 0x40, 0x01, 0x80, 0x00, 0x40, 0x01, 0x20, 0x02, // 120
0x20, 0x00, 0xC0, 0x09, 0x00, 0x06, 0xC0, 0x01, 0x20, // 121
0x20, 0x02, 0x20, 0x03, 0xA0, 0x02, 0x60, 0x02, 0x20, 0x02, // 122
0x80, 0x00, 0x78, 0x0F, 0x08, 0x08, // 123
0x00, 0x00, 0xF8, 0x0F, // 124
0x08, 0x08, 0x78, 0x0F, 0x80, // 125
0xC0, 0x00, 0x40, 0x00, 0xC0, 0x00, 0x80, 0x00, 0xC0, // 126
0x00, 0x00, 0xA0, 0x0F, // 161
0x00, 0x00, 0xC0, 0x01, 0xA0, 0x0F, 0x78, 0x02, 0x40, 0x01, // 162
0x40, 0x02, 0x70, 0x03, 0xC8, 0x02, 0x48, 0x02, 0x08, 0x02, 0x10, 0x02, // 163
0x00, 0x00, 0xE0, 0x01, 0x20, 0x01, 0x20, 0x01, 0xE0, 0x01, // 164
0x48, 0x01, 0x70, 0x01, 0xC0, 0x03, 0x70, 0x01, 0x48, 0x01, // 165
0x00, 0x00, 0x38, 0x0F, // 166
0xD0, 0x04, 0x28, 0x09, 0x48, 0x09, 0x48, 0x0A, 0x90, 0x05, // 167
0x08, 0x00, 0x00, 0x00, 0x08, // 168
0xE0, 0x00, 0x10, 0x01, 0x48, 0x02, 0xA8, 0x02, 0xA8, 0x02, 0x10, 0x01, 0xE0, // 169
0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x78, // 170
0x00, 0x00, 0x80, 0x01, 0x40, 0x02, 0x80, 0x01, 0x40, 0x02, // 171
0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0xE0, // 172
0x80, 0x00, 0x80, // 173
0xE0, 0x00, 0x10, 0x01, 0xE8, 0x02, 0x68, 0x02, 0xC8, 0x02, 0x10, 0x01, 0xE0, // 174
0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, // 175
0x00, 0x00, 0x38, 0x00, 0x28, 0x00, 0x38, // 176
0x40, 0x02, 0x40, 0x02, 0xF0, 0x03, 0x40, 0x02, 0x40, 0x02, // 177
0x48, 0x00, 0x68, 0x00, 0x58, // 178
0x48, 0x00, 0x58, 0x00, 0x68, // 179
0x00, 0x00, 0x10, 0x00, 0x08, // 180
0x00, 0x00, 0xE0, 0x0F, 0x00, 0x02, 0x00, 0x02, 0xE0, 0x03, // 181
0x70, 0x00, 0xF8, 0x0F, 0x08, 0x00, 0xF8, 0x0F, 0x08, // 182
0x00, 0x00, 0x40, // 183
0x00, 0x00, 0x00, 0x14, 0x00, 0x18, // 184
0x00, 0x00, 0x10, 0x00, 0x78, // 185
0x30, 0x00, 0x48, 0x00, 0x48, 0x00, 0x30, // 186
0x00, 0x00, 0x40, 0x02, 0x80, 0x01, 0x40, 0x02, 0x80, 0x01, // 187
0x00, 0x00, 0x10, 0x02, 0x78, 0x01, 0xC0, 0x00, 0x20, 0x01, 0x90, 0x01, 0xC8, 0x03, 0x00, 0x01, // 188
0x00, 0x00, 0x10, 0x02, 0x78, 0x01, 0x80, 0x00, 0x60, 0x00, 0x50, 0x02, 0x48, 0x03, 0xC0, 0x02, // 189
0x48, 0x00, 0x58, 0x00, 0x68, 0x03, 0x80, 0x00, 0x60, 0x01, 0x90, 0x01, 0xC8, 0x03, 0x00, 0x01, // 190
0x00, 0x00, 0x00, 0x06, 0x00, 0x09, 0xA0, 0x09, 0x00, 0x04, // 191
0x00, 0x02, 0xC0, 0x01, 0xB0, 0x00, 0x89, 0x00, 0xB2, 0x00, 0xC0, 0x01, 0x00, 0x02, // 192
0x00, 0x02, 0xC0, 0x01, 0xB0, 0x00, 0x8A, 0x00, 0xB1, 0x00, 0xC0, 0x01, 0x00, 0x02, // 193
0x00, 0x02, 0xC0, 0x01, 0xB2, 0x00, 0x89, 0x00, 0xB2, 0x00, 0xC0, 0x01, 0x00, 0x02, // 194
0x00, 0x02, 0xC2, 0x01, 0xB1, 0x00, 0x8A, 0x00, 0xB1, 0x00, 0xC0, 0x01, 0x00, 0x02, // 195
0x00, 0x02, 0xC0, 0x01, 0xB2, 0x00, 0x88, 0x00, 0xB2, 0x00, 0xC0, 0x01, 0x00, 0x02, // 196
0x00, 0x02, 0xC0, 0x01, 0xBE, 0x00, 0x8A, 0x00, 0xBE, 0x00, 0xC0, 0x01, 0x00, 0x02, // 197
0x00, 0x03, 0xC0, 0x00, 0xE0, 0x00, 0x98, 0x00, 0x88, 0x00, 0xF8, 0x03, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, // 198
0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x08, 0x16, 0x08, 0x1A, 0x10, 0x01, // 199
0x00, 0x00, 0xF8, 0x03, 0x49, 0x02, 0x4A, 0x02, 0x48, 0x02, 0x48, 0x02, // 200
0x00, 0x00, 0xF8, 0x03, 0x48, 0x02, 0x4A, 0x02, 0x49, 0x02, 0x48, 0x02, // 201
0x00, 0x00, 0xFA, 0x03, 0x49, 0x02, 0x4A, 0x02, 0x48, 0x02, 0x48, 0x02, // 202
0x00, 0x00, 0xF8, 0x03, 0x4A, 0x02, 0x48, 0x02, 0x4A, 0x02, 0x48, 0x02, // 203
0x00, 0x00, 0xF9, 0x03, 0x02, // 204
0x02, 0x00, 0xF9, 0x03, // 205
0x01, 0x00, 0xFA, 0x03, // 206
0x02, 0x00, 0xF8, 0x03, 0x02, // 207
0x40, 0x00, 0xF8, 0x03, 0x48, 0x02, 0x48, 0x02, 0x10, 0x01, 0xE0, // 208
0x00, 0x00, 0xFA, 0x03, 0x31, 0x00, 0x42, 0x00, 0x81, 0x01, 0xF8, 0x03, // 209
0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x09, 0x02, 0x0A, 0x02, 0x08, 0x02, 0xF0, 0x01, // 210
0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x0A, 0x02, 0x09, 0x02, 0x08, 0x02, 0xF0, 0x01, // 211
0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x0A, 0x02, 0x09, 0x02, 0x0A, 0x02, 0xF0, 0x01, // 212
0x00, 0x00, 0xF0, 0x01, 0x0A, 0x02, 0x09, 0x02, 0x0A, 0x02, 0x09, 0x02, 0xF0, 0x01, // 213
0x00, 0x00, 0xF0, 0x01, 0x0A, 0x02, 0x08, 0x02, 0x0A, 0x02, 0x08, 0x02, 0xF0, 0x01, // 214
0x10, 0x01, 0xA0, 0x00, 0xE0, 0x00, 0xA0, 0x00, 0x10, 0x01, // 215
0x00, 0x00, 0xF0, 0x02, 0x08, 0x03, 0xC8, 0x02, 0x28, 0x02, 0x18, 0x03, 0xE8, // 216
0x00, 0x00, 0xF8, 0x01, 0x01, 0x02, 0x02, 0x02, 0x00, 0x02, 0xF8, 0x01, // 217
0x00, 0x00, 0xF8, 0x01, 0x02, 0x02, 0x01, 0x02, 0x00, 0x02, 0xF8, 0x01, // 218
0x00, 0x00, 0xF8, 0x01, 0x02, 0x02, 0x01, 0x02, 0x02, 0x02, 0xF8, 0x01, // 219
0x00, 0x00, 0xF8, 0x01, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0xF8, 0x01, // 220
0x08, 0x00, 0x10, 0x00, 0x20, 0x00, 0xC2, 0x03, 0x21, 0x00, 0x10, 0x00, 0x08, // 221
0x00, 0x00, 0xF8, 0x03, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0xE0, // 222
0x00, 0x00, 0xF0, 0x03, 0x08, 0x01, 0x48, 0x02, 0xB0, 0x02, 0x80, 0x01, // 223
0x00, 0x00, 0x00, 0x03, 0xA4, 0x02, 0xA8, 0x02, 0xE0, 0x03, // 224
0x00, 0x00, 0x00, 0x03, 0xA8, 0x02, 0xA4, 0x02, 0xE0, 0x03, // 225
0x00, 0x00, 0x00, 0x03, 0xA8, 0x02, 0xA4, 0x02, 0xE8, 0x03, // 226
0x00, 0x00, 0x08, 0x03, 0xA4, 0x02, 0xA8, 0x02, 0xE4, 0x03, // 227
0x00, 0x00, 0x00, 0x03, 0xA8, 0x02, 0xA0, 0x02, 0xE8, 0x03, // 228
0x00, 0x00, 0x00, 0x03, 0xAE, 0x02, 0xAA, 0x02, 0xEE, 0x03, // 229
0x00, 0x00, 0x40, 0x03, 0xA0, 0x02, 0xA0, 0x02, 0xC0, 0x01, 0xA0, 0x02, 0xA0, 0x02, 0xC0, 0x02, // 230
0x00, 0x00, 0xC0, 0x01, 0x20, 0x16, 0x20, 0x1A, 0x40, 0x01, // 231
0x00, 0x00, 0xC0, 0x01, 0xA4, 0x02, 0xA8, 0x02, 0xC0, 0x02, // 232
0x00, 0x00, 0xC0, 0x01, 0xA8, 0x02, 0xA4, 0x02, 0xC0, 0x02, // 233
0x00, 0x00, 0xC0, 0x01, 0xA8, 0x02, 0xA4, 0x02, 0xC8, 0x02, // 234
0x00, 0x00, 0xC0, 0x01, 0xA8, 0x02, 0xA0, 0x02, 0xC8, 0x02, // 235
0x00, 0x00, 0xE4, 0x03, 0x08, // 236
0x08, 0x00, 0xE4, 0x03, // 237
0x08, 0x00, 0xE4, 0x03, 0x08, // 238
0x08, 0x00, 0xE0, 0x03, 0x08, // 239
0x00, 0x00, 0xC0, 0x01, 0x28, 0x02, 0x38, 0x02, 0xE0, 0x01, // 240
0x00, 0x00, 0xE8, 0x03, 0x24, 0x00, 0x28, 0x00, 0xC4, 0x03, // 241
0x00, 0x00, 0xC0, 0x01, 0x24, 0x02, 0x28, 0x02, 0xC0, 0x01, // 242
0x00, 0x00, 0xC0, 0x01, 0x28, 0x02, 0x24, 0x02, 0xC0, 0x01, // 243
0x00, 0x00, 0xC0, 0x01, 0x28, 0x02, 0x24, 0x02, 0xC8, 0x01, // 244
0x00, 0x00, 0xC8, 0x01, 0x24, 0x02, 0x28, 0x02, 0xC4, 0x01, // 245
0x00, 0x00, 0xC0, 0x01, 0x28, 0x02, 0x20, 0x02, 0xC8, 0x01, // 246
0x40, 0x00, 0x40, 0x00, 0x50, 0x01, 0x40, 0x00, 0x40, // 247
0x00, 0x00, 0xC0, 0x02, 0xA0, 0x03, 0x60, 0x02, 0xA0, 0x01, // 248
0x00, 0x00, 0xE0, 0x01, 0x04, 0x02, 0x08, 0x02, 0xE0, 0x03, // 249
0x00, 0x00, 0xE0, 0x01, 0x08, 0x02, 0x04, 0x02, 0xE0, 0x03, // 250
0x00, 0x00, 0xE8, 0x01, 0x04, 0x02, 0x08, 0x02, 0xE0, 0x03, // 251
0x00, 0x00, 0xE0, 0x01, 0x08, 0x02, 0x00, 0x02, 0xE8, 0x03, // 252
0x20, 0x00, 0xC0, 0x09, 0x08, 0x06, 0xC4, 0x01, 0x20, // 253
0x00, 0x00, 0xF8, 0x0F, 0x20, 0x02, 0x20, 0x02, 0xC0, 0x01, // 254
0x20, 0x00, 0xC8, 0x09, 0x00, 0x06, 0xC8, 0x01, 0x20 // 255
};

18
src/input/InputBroker.cpp Normal file
View File

@@ -0,0 +1,18 @@
#include "InputBroker.h"
InputBroker *inputBroker;
InputBroker::InputBroker()
{
};
void InputBroker::registerSource(Observable<const InputEvent *> *source)
{
this->inputEventObserver.observe(source);
}
int InputBroker::handleInputEvent(const InputEvent *event)
{
this->notifyObservers(event);
return 0;
}

22
src/input/InputBroker.h Normal file
View File

@@ -0,0 +1,22 @@
#pragma once
#include "Observer.h"
typedef struct _InputEvent {
const char* source;
char inputEvent;
} InputEvent;
class InputBroker :
public Observable<const InputEvent *>
{
CallbackObserver<InputBroker, const InputEvent *> inputEventObserver =
CallbackObserver<InputBroker, const InputEvent *>(this, &InputBroker::handleInputEvent);
public:
InputBroker();
void registerSource(Observable<const InputEvent *> *source);
protected:
int handleInputEvent(const InputEvent *event);
};
extern InputBroker *inputBroker;

View File

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

View File

@@ -0,0 +1,57 @@
#pragma once
#include "SinglePortPlugin.h" // TODO: what header file to include?
#include "InputBroker.h"
enum RotaryEncoderInterruptBaseStateType
{
ROTARY_EVENT_OCCURRED,
ROTARY_EVENT_CLEARED
};
enum RotaryEncoderInterruptBaseActionType
{
ROTARY_ACTION_NONE,
ROTARY_ACTION_PRESSED,
ROTARY_ACTION_CW,
ROTARY_ACTION_CCW
};
class RotaryEncoderInterruptBase :
public Observable<const InputEvent *>,
private concurrency::OSThread
{
public:
explicit RotaryEncoderInterruptBase(
const char *name);
void init(
uint8_t pinA, uint8_t pinB, uint8_t pinPress,
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 intAHandler();
void intBHandler();
protected:
virtual int32_t runOnce() override;
RotaryEncoderInterruptBaseStateType intHandler(
bool actualPinRaising,
int otherPinLevel,
RotaryEncoderInterruptBaseActionType action,
RotaryEncoderInterruptBaseStateType state);
volatile RotaryEncoderInterruptBaseStateType rotaryStateCW = ROTARY_EVENT_CLEARED;
volatile RotaryEncoderInterruptBaseStateType rotaryStateCCW = ROTARY_EVENT_CLEARED;
volatile int rotaryLevelA = LOW;
volatile int rotaryLevelB = LOW;
volatile RotaryEncoderInterruptBaseActionType action = ROTARY_ACTION_NONE;
private:
uint8_t _pinA = 0;
uint8_t _pinB = 0;
char _eventCw = InputEventChar_KEY_NONE;
char _eventCcw = InputEventChar_KEY_NONE;
char _eventPressed = InputEventChar_KEY_NONE;
const char *_originName;
};

View File

@@ -0,0 +1,51 @@
#include "RotaryEncoderInterruptImpl1.h"
#include "InputBroker.h"
RotaryEncoderInterruptImpl1 *rotaryEncoderInterruptImpl1;
RotaryEncoderInterruptImpl1::RotaryEncoderInterruptImpl1() :
RotaryEncoderInterruptBase(
"rotEnc1")
{
}
void RotaryEncoderInterruptImpl1::init()
{
if (!radioConfig.preferences.rotary1_enabled)
{
// Input device is disabled.
return;
}
uint8_t pinA = radioConfig.preferences.rotary1_pin_a;
uint8_t pinB = radioConfig.preferences.rotary1_pin_b;
uint8_t pinPress = radioConfig.preferences.rotary1_pin_press;
char eventCw =
static_cast<char>(radioConfig.preferences.rotary1_event_cw);
char eventCcw =
static_cast<char>(radioConfig.preferences.rotary1_event_ccw);
char eventPressed =
static_cast<char>(radioConfig.preferences.rotary1_event_press);
//radioConfig.preferences.ext_notification_module_output
RotaryEncoderInterruptBase::init(
pinA, pinB, pinPress,
eventCw, eventCcw, eventPressed,
RotaryEncoderInterruptImpl1::handleIntA,
RotaryEncoderInterruptImpl1::handleIntB,
RotaryEncoderInterruptImpl1::handleIntPressed);
inputBroker->registerSource(this);
}
void RotaryEncoderInterruptImpl1::handleIntA()
{
rotaryEncoderInterruptImpl1->intAHandler();
}
void RotaryEncoderInterruptImpl1::handleIntB()
{
rotaryEncoderInterruptImpl1->intBHandler();
}
void RotaryEncoderInterruptImpl1::handleIntPressed()
{
rotaryEncoderInterruptImpl1->intPressHandler();
}

View File

@@ -0,0 +1,22 @@
#pragma once
#include "RotaryEncoderInterruptBase.h"
/**
* @brief The idea behind this class to have static methods for the event handlers.
* Check attachInterrupt() at RotaryEncoderInteruptBase.cpp
* Technically you can have as many rotary encoders hardver attached
* to your device as you wish, but you always need to have separate event
* handlers, thus you need to have a RotaryEncoderInterrupt implementation.
*/
class RotaryEncoderInterruptImpl1 :
public RotaryEncoderInterruptBase
{
public:
RotaryEncoderInterruptImpl1();
void init();
static void handleIntA();
static void handleIntB();
static void handleIntPressed();
};
extern RotaryEncoderInterruptImpl1 *rotaryEncoderInterruptImpl1;

View File

@@ -18,10 +18,12 @@
#include "concurrency/Periodic.h"
#include "graphics/Screen.h"
#include "main.h"
#include "plugins/Plugins.h"
#include "modules/Modules.h"
#include "sleep.h"
#include "shutdown.h"
#include "target_specific.h"
#include <OneButton.h>
#include "debug/i2cScan.h"
#include "debug/axpDebug.h"
#include <Wire.h>
// #include <driver/rtc_io.h>
@@ -42,9 +44,8 @@
#include "SX1268Interface.h"
#include "LLCC68Interface.h"
#ifdef NRF52_SERIES
#include "variant.h"
#endif
#include "ButtonThread.h"
#include "PowerFSMThread.h"
using namespace concurrency;
@@ -67,50 +68,6 @@ bool axp192_found;
Router *router = NULL; // Users of router don't care what sort of subclass implements that API
// -----------------------------------------------------------------------------
// Application
// -----------------------------------------------------------------------------
#ifndef NO_WIRE
void scanI2Cdevice(void)
{
byte err, addr;
int nDevices = 0;
for (addr = 1; addr < 127; addr++) {
Wire.beginTransmission(addr);
err = Wire.endTransmission();
if (err == 0) {
DEBUG_MSG("I2C device found at address 0x%x\n", addr);
nDevices++;
if (addr == SSD1306_ADDRESS) {
screen_found = addr;
DEBUG_MSG("ssd1306 display found\n");
}
if (addr == ST7567_ADDRESS) {
screen_found = addr;
DEBUG_MSG("st7567 display found\n");
}
#ifdef AXP192_SLAVE_ADDRESS
if (addr == AXP192_SLAVE_ADDRESS) {
axp192_found = true;
DEBUG_MSG("axp192 PMU found\n");
}
#endif
} else if (err == 4) {
DEBUG_MSG("Unknow error at address 0x%x\n", addr);
}
}
if (nDevices == 0)
DEBUG_MSG("No I2C devices found\n");
else
DEBUG_MSG("done\n");
}
#else
void scanI2Cdevice(void) {}
#endif
const char *getDeviceName()
{
uint8_t dmac[6];
@@ -136,232 +93,6 @@ static int32_t ledBlinker()
uint32_t timeLastPowered = 0;
/// Wrapper to convert our powerFSM stuff into a 'thread'
class PowerFSMThread : public OSThread
{
public:
// callback returns the period for the next callback invocation (or 0 if we should no longer be called)
PowerFSMThread() : OSThread("PowerFSM") {}
protected:
int32_t runOnce()
{
powerFSM.run_machine();
/// If we are in power state we force the CPU to wake every 10ms to check for serial characters (we don't yet wake
/// cpu for serial rx - FIXME)
auto state = powerFSM.getState();
canSleep = (state != &statePOWER) && (state != &stateSERIAL);
if (powerStatus->getHasUSB()) {
timeLastPowered = millis();
} else if (radioConfig.preferences.on_battery_shutdown_after_secs > 0 &&
millis() > timeLastPowered + (1000 * radioConfig.preferences.on_battery_shutdown_after_secs)) { //shutdown after 30 minutes unpowered
powerFSM.trigger(EVENT_SHUTDOWN);
}
return 10;
}
};
/**
* Watch a GPIO and if we get an IRQ, wake the main thread.
* Use to add wake on button press
*/
void wakeOnIrq(int irq, int mode)
{
attachInterrupt(
irq,
[] {
BaseType_t higherWake = 0;
mainDelay.interruptFromISR(&higherWake);
},
FALLING);
}
class ButtonThread : public OSThread
{
// Prepare for button presses
#ifdef BUTTON_PIN
OneButton userButton;
#endif
#ifdef BUTTON_PIN_ALT
OneButton userButtonAlt;
#endif
#ifdef BUTTON_PIN_TOUCH
OneButton userButtonTouch;
#endif
static bool shutdown_on_long_stop;
public:
static uint32_t longPressTime;
// callback returns the period for the next callback invocation (or 0 if we should no longer be called)
ButtonThread() : OSThread("Button")
{
#ifdef BUTTON_PIN
userButton = OneButton(BUTTON_PIN, 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, INPUT_PULLUP_SENSE);
#endif
userButton.attachClick(userButtonPressed);
userButton.attachDuringLongPress(userButtonPressedLong);
userButton.attachDoubleClick(userButtonDoublePressed);
userButton.attachMultiClick(userButtonMultiPressed);
userButton.attachLongPressStart(userButtonPressedLongStart);
userButton.attachLongPressStop(userButtonPressedLongStop);
wakeOnIrq(BUTTON_PIN, FALLING);
#endif
#ifdef BUTTON_PIN_ALT
userButtonAlt = OneButton(BUTTON_PIN_ALT, 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_ALT, INPUT_PULLUP_SENSE);
#endif
userButtonAlt.attachClick(userButtonPressed);
userButtonAlt.attachDuringLongPress(userButtonPressedLong);
userButtonAlt.attachDoubleClick(userButtonDoublePressed);
userButtonAlt.attachLongPressStart(userButtonPressedLongStart);
userButtonAlt.attachLongPressStop(userButtonPressedLongStop);
wakeOnIrq(BUTTON_PIN_ALT, FALLING);
#endif
#ifdef BUTTON_PIN_TOUCH
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.attachDuringLongPress(touchPressedLong);
userButtonTouch.attachDoubleClick(touchDoublePressed);
userButtonTouch.attachLongPressStart(touchPressedLongStart);
userButtonTouch.attachLongPressStop(touchPressedLongStop);
wakeOnIrq(BUTTON_PIN_TOUCH, FALLING);
#endif
}
protected:
/// If the button is pressed we suppress CPU sleep until release
int32_t runOnce()
{
canSleep = true; // Assume we should not keep the board awake
#ifdef BUTTON_PIN
userButton.tick();
canSleep &= userButton.isIdle();
#endif
#ifdef BUTTON_PIN_ALT
userButtonAlt.tick();
canSleep &= userButtonAlt.isIdle();
#endif
#ifdef BUTTON_PIN_TOUCH
userButtonTouch.tick();
canSleep &= userButtonTouch.isIdle();
#endif
// if (!canSleep) DEBUG_MSG("Supressing sleep!\n");
// else DEBUG_MSG("sleep ok\n");
return 5;
}
private:
static void touchPressed()
{
screen->forceDisplay();
DEBUG_MSG("touch press!\n");
}
static void touchDoublePressed()
{
DEBUG_MSG("touch double press!\n");
}
static void touchPressedLong()
{
DEBUG_MSG("touch press long!\n");
}
static void touchDoublePressedLong()
{
DEBUG_MSG("touch double pressed!\n");
}
static void touchPressedLongStart()
{
DEBUG_MSG("touch long press start!\n");
}
static void touchPressedLongStop()
{
DEBUG_MSG("touch long press stop!\n");
}
static void userButtonPressed()
{
// DEBUG_MSG("press!\n");
powerFSM.trigger(EVENT_PRESS);
}
static void userButtonPressedLong()
{
// DEBUG_MSG("Long press!\n");
screen->adjustBrightness();
// If user button is held down for 5 seconds, shutdown the device.
if (millis() - longPressTime > 5 * 1000) {
#ifdef TBEAM_V10
if (axp192_found == true) {
setLed(false);
power->shutdown();
}
#elif NRF52_SERIES
// Do actual shutdown when button released, otherwise the button release
// may wake the board immediatedly.
if (!shutdown_on_long_stop) {
DEBUG_MSG("Shutdown from long press");
playBeep();
ledOff(PIN_LED1);
ledOff(PIN_LED2);
shutdown_on_long_stop = true;
}
#endif
} else {
// DEBUG_MSG("Long press %u\n", (millis() - longPressTime));
}
}
static void userButtonDoublePressed()
{
#ifndef NO_ESP32
disablePin();
#elif defined(HAS_EINK)
digitalWrite(PIN_EINK_EN,digitalRead(PIN_EINK_EN) == LOW);
#endif
}
static void userButtonMultiPressed()
{
#ifndef NO_ESP32
clearNVS();
#endif
}
static void userButtonPressedLongStart()
{
DEBUG_MSG("Long press start!\n");
longPressTime = millis();
}
static void userButtonPressedLongStop()
{
DEBUG_MSG("Long press stop!\n");
longPressTime = 0;
if (shutdown_on_long_stop) {
playShutdownMelody();
power->shutdown();
}
}
};
bool ButtonThread::shutdown_on_long_stop = false;
static Periodic *ledPeriodic;
@@ -507,22 +238,6 @@ void setup()
readFromRTC(); // read the main CPU RTC at first (in case we can't get GPS time)
#ifdef GENIEBLOCKS
Im intentionally breaking your build so you see this note.Feel free to revert if not correct.I think you can
remove this GPS_RESET_N code by instead defining PIN_GPS_RESET and
use the shared code in GPS.cpp instead.- geeksville
// gps setup
pinMode(GPS_RESET_N, OUTPUT);
pinMode(GPS_EXTINT, OUTPUT);
digitalWrite(GPS_RESET_N, HIGH);
digitalWrite(GPS_EXTINT, LOW);
// battery setup
// If we want to read battery level, we need to set BATTERY_EN_PIN pin to low.
// ToDo: For low power consumption after read battery level, set that pin to high.
pinMode(BATTERY_EN_PIN, OUTPUT);
digitalWrite(BATTERY_EN_PIN, LOW);
#endif
gps = createGps();
if (gps)
@@ -534,8 +249,8 @@ void setup()
service.init();
// Now that the mesh service is created, create any plugins
setupPlugins();
// Now that the mesh service is created, create any modules
setupModules();
// Do this after service.init (because that clears error_code)
#ifdef AXP192_SLAVE_ADDRESS
@@ -658,16 +373,16 @@ void setup()
if (!rIf)
RECORD_CRITICALERROR(CriticalErrorCode_NoRadio);
else
else{
router->addInterface(rIf);
// Calculate and save the bit rate to myNodeInfo
// TODO: This needs to be added what ever method changes the channel from the phone.
myNodeInfo.bitrate = (float(Constants_DATA_PAYLOAD_LEN) /
(float(rIf->getPacketTime(Constants_DATA_PAYLOAD_LEN)))
) * 1000;
DEBUG_MSG("myNodeInfo.bitrate = %f bytes / sec\n", myNodeInfo.bitrate);
// Calculate and save the bit rate to myNodeInfo
// TODO: This needs to be added what ever method changes the channel from the phone.
myNodeInfo.bitrate = (float(Constants_DATA_PAYLOAD_LEN) /
(float(rIf->getPacketTime(Constants_DATA_PAYLOAD_LEN)))
) * 1000;
DEBUG_MSG("myNodeInfo.bitrate = %f bytes / sec\n", myNodeInfo.bitrate);
}
// This must be _after_ service.init because we need our preferences loaded from flash to have proper timeout values
PowerFSM_setup(); // we will transition to ON in a couple of seconds, FIXME, only do this for cold boots, not waking from SDS
@@ -677,40 +392,8 @@ void setup()
setCPUFast(false); // 80MHz is fine for our slow peripherals
}
#if 0
// Turn off for now
uint32_t axpDebugRead()
{
axp.debugCharging();
DEBUG_MSG("vbus current %f\n", axp.getVbusCurrent());
DEBUG_MSG("charge current %f\n", axp.getBattChargeCurrent());
DEBUG_MSG("bat voltage %f\n", axp.getBattVoltage());
DEBUG_MSG("batt pct %d\n", axp.getBattPercentage());
DEBUG_MSG("is battery connected %d\n", axp.isBatteryConnect());
DEBUG_MSG("is USB connected %d\n", axp.isVBUSPlug());
DEBUG_MSG("is charging %d\n", axp.isChargeing());
return 30 * 1000;
}
Periodic axpDebugOutput(axpDebugRead);
axpDebugOutput.setup();
#endif
uint32_t rebootAtMsec; // If not zero we will reboot at this time (used to reboot shortly after the update completes)
void rebootCheck()
{
if (rebootAtMsec && millis() > rebootAtMsec) {
#ifndef NO_ESP32
DEBUG_MSG("Rebooting for update\n");
ESP.restart();
#else
DEBUG_MSG("FIXME implement reboot for this platform");
#endif
}
}
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
// This will supress the current delay and instead try to run ASAP.
@@ -730,7 +413,7 @@ void loop()
#ifdef NRF52_SERIES
nrf52Loop();
#endif
rebootCheck();
powerCommandsCheck();
// For debugging
// if (rIf) ((RadioLibInterface *)rIf)->isActivelyReceiving();

View File

@@ -5,6 +5,7 @@
#include "PowerStatus.h"
#include "graphics/Screen.h"
extern uint8_t screen_found;
extern bool axp192_found;
extern bool isCharging;
extern bool isUSBPowered;
@@ -20,10 +21,13 @@ extern graphics::Screen *screen;
// Return a human readable string of the form "Meshtastic_ab13"
const char *getDeviceName();
extern uint32_t timeLastPowered;
extern uint32_t rebootAtMsec;
extern uint32_t shutdownAtMsec;
// If a thread does something that might need for it to be rescheduled ASAP it can set this flag
// This will supress the current delay and instead try to run ASAP.
extern bool runASAP;
void nrf52Setup(), esp32Setup(), nrf52Loop(), esp32Loop();
void nrf52Setup(), esp32Setup(), nrf52Loop(), esp32Loop(), clearBonds();

View File

@@ -247,7 +247,7 @@ static int mem_test(uint32_t *_start, size_t len, bool doRead = true, bool doWri
{
volatile uint32_t *addr;
volatile uint32_t *start = (volatile uint32_t *)_start;
volatile uint32_t *end = start + len / sizeof(uint32_t);
const volatile uint32_t *end = start + len / sizeof(uint32_t);
uint32_t pattern = 0;
uint32_t val;
uint32_t readback;
@@ -315,4 +315,4 @@ void doMemTest()
assert(0); // FIXME report error better
iter++;
}
}

View File

@@ -7,7 +7,7 @@
/// 16 bytes of random PSK for our _public_ default channel that all devices power up on (AES128)
static const uint8_t defaultpsk[] = {0xd4, 0xf1, 0xbb, 0x3a, 0x20, 0x29, 0x07, 0x59,
0xf0, 0xbc, 0xff, 0xab, 0xcf, 0x4e, 0x69, 0xbf};
0xf0, 0xbc, 0xff, 0xab, 0xcf, 0x4e, 0x69, 0x01};
Channels channels;
@@ -84,10 +84,7 @@ void Channels::initDefaultChannel(ChannelIndex chIndex)
Channel &ch = getByIndex(chIndex);
ChannelSettings &channelSettings = ch.settings;
// radioConfig.modem_config = RadioConfig_ModemConfig_Bw125Cr45Sf128; // medium range and fast
// channelSettings.modem_config = ChannelSettings_ModemConfig_Bw500Cr45Sf128; // short range and fast, but wide
// bandwidth so incompatible radios can talk together
channelSettings.modem_config = ChannelSettings_ModemConfig_Bw125Cr48Sf4096; // slow and long range
channelSettings.modem_config = ChannelSettings_ModemConfig_LongFast; // Default to Long Range & Fast
channelSettings.tx_power = 0; // default
uint8_t defaultpskIndex = 1;
@@ -102,7 +99,7 @@ void Channels::initDefaultChannel(ChannelIndex chIndex)
CryptoKey Channels::getKey(ChannelIndex chIndex)
{
Channel &ch = getByIndex(chIndex);
ChannelSettings &channelSettings = ch.settings;
const ChannelSettings &channelSettings = ch.settings;
assert(ch.has_settings);
CryptoKey k;
@@ -206,7 +203,7 @@ void Channels::setChannel(const Channel &c)
const char *Channels::getName(size_t chIndex)
{
// Convert the short "" representation for Default into a usable string
ChannelSettings &channelSettings = getByIndex(chIndex).settings;
const ChannelSettings &channelSettings = getByIndex(chIndex).settings;
const char *channelName = channelSettings.name;
if (!*channelName) { // emptystring
// Per mesh.proto spec, if bandwidth is specified we must ignore modemConfig enum, we assume that in that case
@@ -216,24 +213,27 @@ const char *Channels::getName(size_t chIndex)
channelName = "Unset";
else
switch (channelSettings.modem_config) {
case ChannelSettings_ModemConfig_Bw125Cr45Sf128:
case ChannelSettings_ModemConfig_ShortSlow:
channelName = "ShortSlow";
break;
case ChannelSettings_ModemConfig_Bw500Cr45Sf128:
case ChannelSettings_ModemConfig_ShortFast:
channelName = "ShortFast";
break;
case ChannelSettings_ModemConfig_Bw31_25Cr48Sf512:
channelName = "LongFast";
break;
case ChannelSettings_ModemConfig_Bw125Cr48Sf4096:
channelName = "LongSlow";
break;
case ChannelSettings_ModemConfig_Bw250Cr46Sf2048:
case ChannelSettings_ModemConfig_MidSlow:
channelName = "MediumSlow";
break;
case ChannelSettings_ModemConfig_Bw250Cr47Sf1024:
case ChannelSettings_ModemConfig_MidFast:
channelName = "MediumFast";
break;
case ChannelSettings_ModemConfig_LongFast:
channelName = "LongFast";
break;
case ChannelSettings_ModemConfig_LongSlow:
channelName = "LongSlow";
break;
case ChannelSettings_ModemConfig_VLongSlow:
channelName = "VLongSlow";
break;
default:
channelName = "Invalid";
break;

View File

@@ -26,9 +26,12 @@ class Channels
ChannelIndex activeChannelIndex = 0;
/// the precomputed hashes for each of our channels, or -1 for invalid
int16_t hashes[MAX_NUM_CHANNELS];
int16_t hashes[MAX_NUM_CHANNELS] = {};
public:
Channels() {}
/// Well known channel names
static const char *adminChannel, *gpioChannel, *serialChannel;
@@ -134,4 +137,4 @@ class Channels
};
/// Singleton channel table
extern Channels channels;
extern Channels channels;

View File

@@ -20,9 +20,9 @@ class CryptoEngine
{
protected:
/** Our per packet nonce */
uint8_t nonce[16];
uint8_t nonce[16] = {0};
CryptoKey key;
CryptoKey key = {};
public:
virtual ~CryptoEngine() {}

View File

@@ -8,14 +8,14 @@ class DSRRouter : public ReliableRouter
* Every (non duplicate) packet this node receives will be passed through this method. This allows subclasses to
* update routing tables etc... based on what we overhear (even for messages not destined to our node)
*/
virtual void sniffReceived(const MeshPacket *p, const Routing *c);
virtual void sniffReceived(const MeshPacket *p, const Routing *c) override;
/**
* Send a packet on a suitable interface. This routine will
* later free() the packet to pool. This routine is not allowed to stall.
* If the txmit queue is full it might return an error
*/
virtual ErrorCode send(MeshPacket *p);
virtual ErrorCode send(MeshPacket *p) override;
private:
/**
@@ -77,4 +77,4 @@ class DSRRouter : public ReliableRouter
* when the discovery is complete.
*/
void startDiscovery(NodeNum dest);
};
};

View File

@@ -1,5 +1,5 @@
#include "configuration.h"
#include "FloodingRouter.h"
#include "configuration.h"
#include "mesh-pb-constants.h"
FloodingRouter::FloodingRouter() {}
@@ -27,11 +27,41 @@ bool FloodingRouter::shouldFilterReceived(MeshPacket *p)
return Router::shouldFilterReceived(p);
}
bool FloodingRouter::inRangeOfRouter()
{
uint32_t maximum_router_sec = 300;
// FIXME : Scale minimum_snr to accomodate different modem configurations.
float minimum_snr = 2;
for (int i = 0; i < myNodeInfo.router_count; i++) {
// A router has been seen and the heartbeat was heard within the last 300 seconds
if (
((myNodeInfo.router_sec[i] > 0) && (myNodeInfo.router_sec[i] < maximum_router_sec)) &&
(myNodeInfo.router_snr[i] > minimum_snr)
) {
return true;
}
}
return false;
}
void FloodingRouter::sniffReceived(const MeshPacket *p, const Routing *c)
{
// If a broadcast, possibly _also_ send copies out into the mesh.
// (FIXME, do something smarter than naive flooding here)
if (p->to == NODENUM_BROADCAST && p->hop_limit > 0 && getFrom(p) != getNodeNum()) {
bool rebroadcastPacket = true;
if (radioConfig.preferences.role == Role_Repeater || radioConfig.preferences.role == Role_Router) {
rebroadcastPacket = true;
} else if ((radioConfig.preferences.role == Role_Default) && inRangeOfRouter()) {
DEBUG_MSG("Role_Default - rx_snr > 13\n");
rebroadcastPacket = false;
}
if ((p->to == NODENUM_BROADCAST) && (p->hop_limit > 0) && (getFrom(p) != getNodeNum() && rebroadcastPacket)) {
if (p->id != 0) {
MeshPacket *tosend = packetPool.allocCopy(*p); // keep a copy because we will be sending it

View File

@@ -41,7 +41,7 @@ class FloodingRouter : public Router, protected PacketHistory
* later free() the packet to pool. This routine is not allowed to stall.
* If the txmit queue is full it might return an error
*/
virtual ErrorCode send(MeshPacket *p);
virtual ErrorCode send(MeshPacket *p) override;
protected:
/**
@@ -50,10 +50,18 @@ class FloodingRouter : public Router, protected PacketHistory
* Called immedately on receiption, before any further processing.
* @return true to abandon the packet
*/
virtual bool shouldFilterReceived(MeshPacket *p);
virtual bool shouldFilterReceived(MeshPacket *p) override;
/**
* Are we in range of a router?
*
* "range" here may not be the right term.
* @return true if we're in range of a router
*/
virtual bool inRangeOfRouter();
/**
* Look for broadcasts we need to rebroadcast
*/
virtual void sniffReceived(const MeshPacket *p, const Routing *c);
virtual void sniffReceived(const MeshPacket *p, const Routing *c) override;
};

View File

@@ -58,7 +58,7 @@ template <class T> class MemoryDynamic : public Allocator<T>
{
public:
/// Return a buffer for use by others
virtual void release(T *p)
virtual void release(T *p) override
{
assert(p);
free(p);
@@ -66,7 +66,7 @@ template <class T> class MemoryDynamic : public Allocator<T>
protected:
// Alloc some storage
virtual T *alloc(TickType_t maxWait)
virtual T *alloc(TickType_t maxWait) override
{
T *p = (T *)malloc(sizeof(T));
assert(p);
@@ -87,7 +87,7 @@ template <class T> class MemoryPool : public Allocator<T>
size_t maxElements;
public:
MemoryPool(size_t _maxElements) : dead(_maxElements), maxElements(_maxElements)
explicit MemoryPool(size_t _maxElements) : dead(_maxElements), maxElements(_maxElements)
{
buf = new T[maxElements];
@@ -99,7 +99,7 @@ template <class T> class MemoryPool : public Allocator<T>
~MemoryPool() { delete[] buf; }
/// Return a buffer for use by others
virtual void release(T *p)
void release(T *p)
{
assert(p >= buf &&
(size_t)(p - buf) <

View File

@@ -18,7 +18,7 @@ class MeshPacketQueue
bool replaceLowerPriorityPacket(MeshPacket *mp);
public:
MeshPacketQueue(size_t _maxLen);
explicit MeshPacketQueue(size_t _maxLen);
/** enqueue a packet, return false if full */
bool enqueue(MeshPacket *p);
@@ -30,4 +30,4 @@ class MeshPacketQueue
/** 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);
};
};

View File

@@ -3,15 +3,15 @@
#include "Channels.h"
#include "MeshService.h"
#include "NodeDB.h"
#include "plugins/RoutingPlugin.h"
#include "modules/RoutingModule.h"
#include <assert.h>
std::vector<MeshPlugin *> *MeshPlugin::plugins;
std::vector<MeshPlugin *> *MeshPlugin::modules;
const MeshPacket *MeshPlugin::currentRequest;
/**
* If any of the current chain of plugins has already sent a reply, it will be here. This is useful to allow
* If any of the current chain of modules has already sent a reply, it will be here. This is useful to allow
* the RoutingPlugin to avoid sending redundant acks
*/
MeshPacket *MeshPlugin::currentReply;
@@ -19,17 +19,17 @@ MeshPacket *MeshPlugin::currentReply;
MeshPlugin::MeshPlugin(const char *_name) : name(_name)
{
// Can't trust static initalizer order, so we check each time
if (!plugins)
plugins = new std::vector<MeshPlugin *>();
if (!modules)
modules = new std::vector<MeshPlugin *>();
plugins->push_back(this);
modules->push_back(this);
}
void MeshPlugin::setup() {}
MeshPlugin::~MeshPlugin()
{
assert(0); // FIXME - remove from list of plugins once someone needs this feature
assert(0); // FIXME - remove from list of modules once someone needs this feature
}
MeshPacket *MeshPlugin::allocAckNak(Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex)
@@ -68,10 +68,10 @@ MeshPacket *MeshPlugin::allocErrorResponse(Routing_Error err, const MeshPacket *
void MeshPlugin::callPlugins(const MeshPacket &mp, RxSource src)
{
// DEBUG_MSG("In call plugins\n");
bool pluginFound = false;
// DEBUG_MSG("In call modules\n");
bool moduleFound = false;
// We now allow **encrypted** packets to pass through the plugins
// We now allow **encrypted** packets to pass through the modules
bool isDecoded = mp.which_payloadVariant == MeshPacket_decoded_tag;
currentReply = NULL; // No reply yet
@@ -80,12 +80,12 @@ void MeshPlugin::callPlugins(const MeshPacket &mp, RxSource src)
auto ourNodeNum = nodeDB.getNodeNum();
bool toUs = mp.to == NODENUM_BROADCAST || mp.to == ourNodeNum;
for (auto i = plugins->begin(); i != plugins->end(); ++i) {
for (auto i = modules->begin(); i != modules->end(); ++i) {
auto &pi = **i;
pi.currentRequest = &mp;
/// We only call plugins that are interested in the packet (and the message is destined to us or we are promiscious)
/// We only call modules that are interested in the packet (and the message is destined to us or we are promiscious)
bool wantsPacket = (isDecoded || pi.encryptedOk) && (pi.isPromiscuous || toUs) && pi.wantPacket(&mp);
if ((src == RX_SRC_LOCAL) && !(pi.loopbackOk)) {
@@ -96,15 +96,15 @@ void MeshPlugin::callPlugins(const MeshPacket &mp, RxSource src)
assert(!pi.myReply); // If it is !null it means we have a bug, because it should have been sent the previous time
if (wantsPacket) {
DEBUG_MSG("Plugin '%s' wantsPacket=%d\n", pi.name, wantsPacket);
DEBUG_MSG("Module '%s' wantsPacket=%d\n", pi.name, wantsPacket);
pluginFound = true;
moduleFound = true;
/// received channel (or NULL if not decoded)
Channel *ch = isDecoded ? &channels.getByIndex(mp.channel) : NULL;
/// Is the channel this packet arrived on acceptable? (security check)
/// Note: we can't know channel names for encrypted packets, so those are NEVER sent to boundChannel plugins
/// Note: we can't know channel names for encrypted packets, so those are NEVER sent to boundChannel modules
/// Also: if a packet comes in on the local PC interface, we don't check for bound channels, because it is TRUSTED and it needs to
/// to be able to fetch the initial admin packets without yet knowing any channels.
@@ -128,7 +128,7 @@ void MeshPlugin::callPlugins(const MeshPacket &mp, RxSource src)
ProcessMessage handled = pi.handleReceived(mp);
// Possibly send replies (but only if the message was directed to us specifically, i.e. not for promiscious
// sniffing) also: we only let the one plugin send a reply, once that happens, remaining plugins are not
// sniffing) also: we only let the one module send a reply, once that happens, remaining modules are not
// considered
// NOTE: we send a reply *even if the (non broadcast) request was from us* which is unfortunate but necessary
@@ -137,9 +137,9 @@ void MeshPlugin::callPlugins(const MeshPacket &mp, RxSource src)
// any other node.
if (mp.decoded.want_response && toUs && (getFrom(&mp) != ourNodeNum || mp.to == ourNodeNum) && !currentReply) {
pi.sendResponse(mp);
DEBUG_MSG("Plugin '%s' sent a response\n", pi.name);
DEBUG_MSG("Module '%s' sent a response\n", pi.name);
} else {
DEBUG_MSG("Plugin '%s' considered\n", pi.name);
DEBUG_MSG("Module '%s' considered\n", pi.name);
}
// If the requester didn't ask for a response we might need to discard unused replies to prevent memory leaks
@@ -150,7 +150,7 @@ void MeshPlugin::callPlugins(const MeshPacket &mp, RxSource src)
}
if (handled == ProcessMessage::STOP) {
DEBUG_MSG("Plugin '%s' handled and skipped other processing\n", pi.name);
DEBUG_MSG("Module '%s' handled and skipped other processing\n", pi.name);
break;
}
}
@@ -173,13 +173,13 @@ void MeshPlugin::callPlugins(const MeshPacket &mp, RxSource src)
// SECURITY NOTE! I considered sending back a different error code if we didn't find the psk (i.e. !isDecoded)
// but opted NOT TO. Because it is not a good idea to let remote nodes 'probe' to find out which PSKs were "good" vs
// bad.
routingPlugin->sendAckNak(Routing_Error_NO_RESPONSE, getFrom(&mp), mp.id, mp.channel);
routingModule->sendAckNak(Routing_Error_NO_RESPONSE, getFrom(&mp), mp.id, mp.channel);
}
}
if (!pluginFound)
DEBUG_MSG("No plugins interested in portnum=%d, src=%s\n",
mp.decoded.portnum,
if (!moduleFound)
DEBUG_MSG("No modules interested in portnum=%d, src=%s\n",
mp.decoded.portnum,
(src == RX_SRC_LOCAL) ? "LOCAL":"REMOTE");
}
@@ -201,8 +201,8 @@ void MeshPlugin::sendResponse(const MeshPacket &req)
setReplyTo(r, req);
currentReply = r;
} else {
// Ignore - this is now expected behavior for routing plugin (because it ignores some replies)
// DEBUG_MSG("WARNING: Client requested response but this plugin did not provide\n");
// Ignore - this is now expected behavior for routing module (because it ignores some replies)
// DEBUG_MSG("WARNING: Client requested response but this module did not provide\n");
}
}
@@ -222,16 +222,61 @@ void setReplyTo(MeshPacket *p, const MeshPacket &to)
p->decoded.request_id = to.id;
}
std::vector<MeshPlugin *> MeshPlugin::GetMeshPluginsWithUIFrames()
std::vector<MeshPlugin *> MeshPlugin::GetMeshModulesWithUIFrames()
{
std::vector<MeshPlugin *> pluginsWithUIFrames;
for (auto i = plugins->begin(); i != plugins->end(); ++i) {
auto &pi = **i;
if (pi.wantUIFrame()) {
DEBUG_MSG("Plugin wants a UI Frame\n");
pluginsWithUIFrames.push_back(&pi);
std::vector<MeshPlugin *> modulesWithUIFrames;
if (modules) {
for (auto i = modules->begin(); i != modules->end(); ++i) {
auto &pi = **i;
if (pi.wantUIFrame()) {
DEBUG_MSG("Module wants a UI Frame\n");
modulesWithUIFrames.push_back(&pi);
}
}
}
return pluginsWithUIFrames;
return modulesWithUIFrames;
}
void MeshPlugin::observeUIEvents(
Observer<const UIFrameEvent *> *observer)
{
if (modules) {
for (auto i = modules->begin(); i != modules->end(); ++i) {
auto &pi = **i;
Observable<const UIFrameEvent *> *observable =
pi.getUIFrameObservable();
if (observable != NULL) {
DEBUG_MSG("Module wants a UI Frame\n");
observer->observe(observable);
}
}
}
}
AdminMessageHandleResult MeshPlugin::handleAdminMessageForAllPlugins(const MeshPacket &mp, AdminMessage *request, AdminMessage *response)
{
AdminMessageHandleResult handled = AdminMessageHandleResult::NOT_HANDLED;
if (modules) {
for (auto i = modules->begin(); i != modules->end(); ++i) {
auto &pi = **i;
AdminMessageHandleResult h = pi.handleAdminMessageForModule(mp, request, response);
if (h == AdminMessageHandleResult::HANDLED_WITH_RESPONSE)
{
// In case we have a response it always has priority.
DEBUG_MSG("Reply prepared by module '%s' of variant: %d\n",
pi.name,
response->which_variant);
handled = h;
}
else if ((handled != AdminMessageHandleResult::HANDLED_WITH_RESPONSE) &&
(h == AdminMessageHandleResult::HANDLED))
{
// In case the message is handled it should be populated, but will not overwrite
// a result with response.
handled = h;
}
}
}
return handled;
}

View File

@@ -21,19 +21,40 @@ enum class ProcessMessage
STOP = 1,
};
/** A baseclass for any mesh "plugin".
/**
* Used by modules to return the result of the AdminMessage handling.
* If request is handled, then module should return HANDLED,
* If response is also prepared for the request, then HANDLED_WITH_RESPONSE
* should be returned.
*/
enum class AdminMessageHandleResult
{
NOT_HANDLED = 0,
HANDLED = 1,
HANDLED_WITH_RESPONSE = 2,
};
/*
* This struct is used by Screen to figure out whether screen frame should be updated.
*/
typedef struct _UIFrameEvent {
bool frameChanged;
bool needRedraw;
} UIFrameEvent;
/** A baseclass for any mesh "module".
*
* A plugin allows you to add new features to meshtastic device code, without needing to know messaging details.
* A module allows you to add new features to meshtastic device code, without needing to know messaging details.
*
* A key concept for this is that your plugin should use a particular "portnum" for each message type you want to receive
* A key concept for this is that your module should use a particular "portnum" for each message type you want to receive
* and handle.
*
* Interally we use plugins to implement the core meshtastic text messaging and gps position sharing features. You
* can use these classes as examples for how to write your own custom plugin. See here: (FIXME)
* Interally we use modules to implement the core meshtastic text messaging and gps position sharing features. You
* can use these classes as examples for how to write your own custom module. See here: (FIXME)
*/
class MeshPlugin
{
static std::vector<MeshPlugin *> *plugins;
static std::vector<MeshPlugin *> *modules;
public:
/** Constructor
@@ -47,24 +68,27 @@ class MeshPlugin
*/
static void callPlugins(const MeshPacket &mp, RxSource src = RX_SRC_RADIO);
static std::vector<MeshPlugin *> GetMeshPluginsWithUIFrames();
static std::vector<MeshPlugin *> GetMeshModulesWithUIFrames();
static void observeUIEvents(Observer<const UIFrameEvent *> *observer);
static AdminMessageHandleResult handleAdminMessageForAllPlugins(
const MeshPacket &mp, AdminMessage *request, AdminMessage *response);
#ifndef NO_SCREEN
virtual void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { return; }
#endif
protected:
const char *name;
/** Most plugins only care about packets that are destined for their node (i.e. broadcasts or has their node as the specific
/** Most modules only care about packets that are destined for their node (i.e. broadcasts or has their node as the specific
recipient) But some plugs might want to 'sniff' packets that are merely being routed (passing through the current node). Those
plugins can set this to true and their handleReceived() will be called for every packet.
modules can set this to true and their handleReceived() will be called for every packet.
*/
bool isPromiscuous = false;
/** Also receive a copy of LOCALLY GENERATED messages - most plugins should leave
/** Also receive a copy of LOCALLY GENERATED messages - most modules should leave
* this setting disabled - see issue #877 */
bool loopbackOk = false;
/** Most plugins only understand decrypted packets. For plugins that also want to see encrypted packets, they should set this
/** Most modules only understand decrypted packets. For modules that also want to see encrypted packets, they should set this
* flag */
bool encryptedOk = false;
@@ -77,11 +101,11 @@ class MeshPlugin
const char *boundChannel = NULL;
/**
* If this plugin is currently handling a request currentRequest will be preset
* If this module is currently handling a request currentRequest will be preset
* to the packet with the request. This is mostly useful for reply handlers.
*
* Note: this can be static because we are guaranteed to be processing only one
* plugin at a time.
* plumodulegin at a time.
*/
static const MeshPacket *currentRequest;
@@ -91,7 +115,7 @@ class MeshPlugin
MeshPacket *myReply = NULL;
/**
* Initialize your plugin. This setup function is called once after all hardware and mesh protocol layers have
* Initialize your module. This setup function is called once after all hardware and mesh protocol layers have
* been initialized
*/
virtual void setup();
@@ -119,16 +143,30 @@ class MeshPlugin
* @return true if you want to be alloced a UI screen frame
*/
virtual bool wantUIFrame() { return false; }
virtual Observable<const UIFrameEvent *>* getUIFrameObservable() { return NULL; }
MeshPacket *allocAckNak(Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex);
/// Send an error response for the specified packet.
MeshPacket *allocErrorResponse(Routing_Error err, const MeshPacket *p);
/**
* @brief An admin message arrived to AdminModule. Module was asked whether it want to handle the request.
*
* @param mp The mesh packet arrived.
* @param request The AdminMessage request extracted from the packet.
* @param response The prepared response
* @return AdminMessageHandleResult
* HANDLED if message was handled
* HANDLED_WITH_RESPONSE if a response is also prepared and to be sent.
*/
virtual AdminMessageHandleResult handleAdminMessageForModule(
const MeshPacket &mp, AdminMessage *request, AdminMessage *response) { return AdminMessageHandleResult::NOT_HANDLED; };
private:
/**
* If any of the current chain of plugins has already sent a reply, it will be here. This is useful to allow
* the RoutingPlugin to avoid sending redundant acks
* If any of the current chain of modules has already sent a reply, it will be here. This is useful to allow
* the RoutingModule to avoid sending redundant acks
*/
static MeshPacket *currentReply;
@@ -144,4 +182,4 @@ class MeshPlugin
/** set the destination and packet parameters of packet p intended as a reply to a particular "to" packet
* This ensures that if the request packet was sent reliably, the reply is sent that way as well.
*/
void setReplyTo(MeshPacket *p, const MeshPacket &to);
void setReplyTo(MeshPacket *p, const MeshPacket &to);

View File

@@ -8,10 +8,13 @@
// Map from old region names to new region enums
struct RegionInfo {
RegionCode code;
uint8_t numChannels;
uint8_t powerLimit; // Or zero for not set
float freq;
float freqStart;
float freqEnd;
float dutyCycle;
float spacing;
uint8_t powerLimit; // Or zero for not set
bool audioPermitted;
bool freqSwitching;
const char *name; // EU433 etc
};

View File

@@ -12,8 +12,8 @@
#include "RTC.h"
#include "main.h"
#include "mesh-pb-constants.h"
#include "plugins/NodeInfoPlugin.h"
#include "plugins/PositionPlugin.h"
#include "modules/NodeInfoModule.h"
#include "modules/PositionModule.h"
#include "power.h"
/*
@@ -115,10 +115,10 @@ void MeshService::reloadOwner()
// DEBUG_MSG("reloadOwner()\n");
// update our local data directly
nodeDB.updateUser(nodeDB.getNodeNum(), owner);
assert(nodeInfoPlugin);
assert(nodeInfoModule);
// update everyone else
if (nodeInfoPlugin)
nodeInfoPlugin->sendOurNodeInfo();
if (nodeInfoModule)
nodeInfoModule->sendOurNodeInfo();
nodeDB.saveToDisk();
}
@@ -175,14 +175,14 @@ void MeshService::sendNetworkPing(NodeNum dest, bool wantReplies)
assert(node);
if (node->has_position) {
if (positionPlugin) {
if (positionModule) {
DEBUG_MSG("Sending position ping to 0x%x, wantReplies=%d\n", dest, wantReplies);
positionPlugin->sendOurPosition(dest, wantReplies);
positionModule->sendOurPosition(dest, wantReplies);
}
} else {
if (nodeInfoPlugin) {
if (nodeInfoModule) {
DEBUG_MSG("Sending nodeinfo ping to 0x%x, wantReplies=%d\n", dest, wantReplies);
nodeInfoPlugin->sendOurNodeInfo(dest, wantReplies);
nodeInfoModule->sendOurNodeInfo(dest, wantReplies);
}
}
}

View File

@@ -91,7 +91,7 @@ class MeshService
/// Handle a packet that just arrived from the radio. This method does _ReliableRouternot_ free the provided packet. If it
/// needs to keep the packet around it makes a copy
int handleFromRadio(const MeshPacket *p);
friend class RoutingPlugin;
friend class RoutingModule;
};
extern MeshService service;

View File

@@ -1,8 +1,6 @@
#include "configuration.h"
#include <assert.h>
#include "FS.h"
#include "Channels.h"
#include "CryptoEngine.h"
#include "FSCommon.h"
@@ -21,11 +19,16 @@
#ifndef NO_ESP32
#include "mesh/http/WiFiAPClient.h"
#include "plugins/esp32/StoreForwardPlugin.h"
#include "modules/esp32/StoreForwardModule.h"
#include <Preferences.h>
#include <nvs_flash.h>
#endif
#ifdef NRF52_SERIES
#include <bluefruit.h>
#include <utility/bonding.h>
#endif
NodeDB nodeDB;
// we have plenty of ram so statically alloc this tempbuf (for now)
@@ -90,6 +93,16 @@ bool NodeDB::resetRadioConfig()
#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
didFactoryReset = true;
}
@@ -214,35 +227,8 @@ void NodeDB::init()
info->user = owner;
info->has_user = true;
// removed from 1.2 (though we do use old values if found)
// We set these _after_ loading from disk - because they come from the build and are more trusted than
// what is stored in flash
// if (xstr(HW_VERSION)[0])
// strncpy(myNodeInfo.region, optstr(HW_VERSION), sizeof(myNodeInfo.region));
// else DEBUG_MSG("This build does not specify a HW_VERSION\n"); // Eventually new builds will no longer include this build
// flag
// DEBUG_MSG("legacy region %d\n", devicestate.legacyRadio.preferences.region);
if (radioConfig.preferences.region == RegionCode_Unset)
radioConfig.preferences.region = devicestate.legacyRadio.preferences.region;
// Check for the old style of region code strings, if found, convert to the new enum.
// Those strings will look like "1.0-EU433"
if (radioConfig.preferences.region == RegionCode_Unset && strncmp(myNodeInfo.region, "1.0-", 4) == 0) {
const char *regionStr = myNodeInfo.region + 4; // EU433 or whatever
for (const RegionInfo *r = regions; r->code != RegionCode_Unset; r++)
if (strcmp(r->name, regionStr) == 0) {
radioConfig.preferences.region = r->code;
break;
}
}
strncpy(myNodeInfo.firmware_version, optstr(APP_VERSION), sizeof(myNodeInfo.firmware_version));
// hw_model is no longer stored in myNodeInfo (as of 1.2.11) - we now store it as an enum in nodeinfo
myNodeInfo.hw_model_deprecated[0] = '\0';
// strncpy(myNodeInfo.hw_model, HW_VENDOR, sizeof(myNodeInfo.hw_model));
#ifndef NO_ESP32
Preferences preferences;
preferences.begin("meshtastic", false);
@@ -297,16 +283,16 @@ static const char *channelfile = "/prefs/channels.proto";
/** Load a protobuf from a file, return true for success */
bool loadProto(const char *filename, size_t protoSize, size_t objSize, const pb_msgdesc_t *fields, void *dest_struct)
{
#ifdef FS
#ifdef FSCom
// static DeviceState scratch; We no longer read into a tempbuf because this structure is 15KB of valuable RAM
auto f = FS.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 = FS.open(filename);
f = FSCom.open(filename);
}
bool okay = false;
@@ -359,11 +345,11 @@ void NodeDB::loadFromDisk()
/** 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)
{
#ifdef FS
#ifdef FSCom
// static DeviceState scratch; We no longer read into a tempbuf because this structure is 15KB of valuable RAM
String filenameTmp = filename;
filenameTmp += ".tmp";
auto f = FS.open(filenameTmp.c_str(), FILE_O_WRITE);
auto f = FSCom.open(filenameTmp.c_str(), FILE_O_WRITE);
bool okay = false;
if (f) {
DEBUG_MSG("Saving %s\n", filename);
@@ -378,9 +364,9 @@ bool saveProto(const char *filename, size_t protoSize, size_t objSize, const pb_
f.close();
// brief window of risk here ;-)
if (!FS.remove(filename))
if (!FSCom.remove(filename))
DEBUG_MSG("Warning: Can't remove old pref file\n");
if (!FS.rename(filenameTmp.c_str(), filename))
if (!FSCom.rename(filenameTmp.c_str(), filename))
DEBUG_MSG("Error: can't rename new pref file\n");
} else {
DEBUG_MSG("Can't write prefs\n");
@@ -394,8 +380,8 @@ bool saveProto(const char *filename, size_t protoSize, size_t objSize, const pb_
void NodeDB::saveChannelsToDisk()
{
if (!devicestate.no_save) {
#ifdef FS
FS.mkdir("/prefs");
#ifdef FSCom
FSCom.mkdir("/prefs");
#endif
saveProto(channelfile, ChannelFile_size, sizeof(ChannelFile), ChannelFile_fields, &channelFile);
}
@@ -404,15 +390,15 @@ void NodeDB::saveChannelsToDisk()
void NodeDB::saveToDisk()
{
if (!devicestate.no_save) {
#ifdef FS
FS.mkdir("/prefs");
#ifdef FSCom
FSCom.mkdir("/prefs");
#endif
bool okay = saveProto(preffile, DeviceState_size, sizeof(devicestate), DeviceState_fields, &devicestate);
okay &= saveProto(radiofile, RadioConfig_size, sizeof(RadioConfig), RadioConfig_fields, &radioConfig);
saveProto(preffile, DeviceState_size, sizeof(devicestate), DeviceState_fields, &devicestate);
saveProto(radiofile, RadioConfig_size, sizeof(RadioConfig), RadioConfig_fields, &radioConfig);
saveChannelsToDisk();
// remove any pre 1.2 pref files, turn on after 1.2 is in beta
// if(okay) FS.remove(preffileOld);
// if(okay) FSCom.remove(preffileOld);
} else {
DEBUG_MSG("***** DEVELOPMENT MODE - DO NOT RELEASE - not saving to flash *****\n");
}
@@ -459,14 +445,17 @@ size_t NodeDB::getNumOnlineNodes()
void NodeDB::updatePosition(uint32_t nodeId, const Position &p, RxSource src)
{
NodeInfo *info = getOrCreateNode(nodeId);
if (!info) {
return;
}
if (src == RX_SRC_LOCAL) {
// Local packet, fully authoritative
DEBUG_MSG("updatePosition LOCAL pos@%x:5, time=%u, latI=%d, lonI=%d\n",
DEBUG_MSG("updatePosition LOCAL pos@%x:5, time=%u, latI=%d, lonI=%d\n",
p.pos_timestamp, p.time, p.latitude_i, p.longitude_i);
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) {
// FIXME SPECIAL TIME SETTING PACKET FROM EUD TO RADIO
// (stop-gap fix for issue #900)
@@ -479,7 +468,7 @@ void NodeDB::updatePosition(uint32_t nodeId, const Position &p, RxSource src)
// recorded based on the packet rxTime
//
// FIXME perhaps handle RX_SRC_USER separately?
DEBUG_MSG("updatePosition REMOTE node=0x%x time=%u, latI=%d, lonI=%d\n",
DEBUG_MSG("updatePosition REMOTE node=0x%x time=%u, latI=%d, lonI=%d\n",
nodeId, p.time, p.latitude_i, p.longitude_i);
// First, back up fields that we want to protect from overwrite
@@ -502,6 +491,9 @@ void NodeDB::updatePosition(uint32_t nodeId, const Position &p, RxSource src)
void NodeDB::updateUser(uint32_t nodeId, const User &p)
{
NodeInfo *info = getOrCreateNode(nodeId);
if (!info) {
return;
}
DEBUG_MSG("old user %s/%s/%s\n", info->user.id, info->user.long_name, info->user.short_name);
@@ -531,6 +523,9 @@ void NodeDB::updateFrom(const MeshPacket &mp)
DEBUG_MSG("Update DB node 0x%x, rx_time=%u\n", mp.from, mp.rx_time);
NodeInfo *info = getOrCreateNode(getFrom(&mp));
if (!info) {
return;
}
if (mp.rx_time) // if the packet has a valid timestamp use it to update our last_heard
info->last_heard = mp.rx_time;
@@ -557,8 +552,12 @@ NodeInfo *NodeDB::getOrCreateNode(NodeNum n)
NodeInfo *info = getNode(n);
if (!info) {
if (*numNodes >= MAX_NUM_NODES) {
screen->print("error: node_db full!\n");
DEBUG_MSG("ERROR! could not create new node, node_db is full! (%d nodes)", *numNodes);
return NULL;
}
// add the node
assert(*numNodes < MAX_NUM_NODES);
info = &nodes[(*numNodes)++];
// everything is missing except the nodenum

View File

@@ -1,4 +1,3 @@
#include "configuration.h"
#include "PhoneAPI.h"
#include "Channels.h"
#include "GPS.h"
@@ -6,6 +5,7 @@
#include "NodeDB.h"
#include "PowerFSM.h"
#include "RadioInterface.h"
#include "configuration.h"
#include <assert.h>
#if FromRadio_size > MAX_TO_FROM_RADIO_SIZE

View File

@@ -24,6 +24,7 @@ class PhoneAPI
STATE_SEND_NOTHING, // (Eventual) Initial state, don't send anything until the client starts asking for config
// (disconnected)
STATE_SEND_MY_INFO, // send our my info record
STATE_SEND_GROUPS,
// STATE_SEND_RADIO, // in 1.2 we now send this as a regular mesh packet
// STATE_SEND_OWNER, no need to send Owner specially, it is just part of the nodedb
STATE_SEND_NODEINFO, // states progress in this order as the device sends to to the client
@@ -45,7 +46,7 @@ class PhoneAPI
/// We temporarily keep the nodeInfo here between the call to available and getFromRadio
const NodeInfo *nodeInfoForPhone = NULL;
ToRadio toRadioScratch; // this is a static scratch object, any data must be copied elsewhere before returning
ToRadio toRadioScratch = {0}; // this is a static scratch object, any data must be copied elsewhere before returning
/// Use to ensure that clients don't get confused about old messages from the radio
uint32_t config_nonce = 0;
@@ -58,7 +59,7 @@ class PhoneAPI
// Call this when the client drops the connection, resets the state to STATE_SEND_NOTHING
// Unregisters our observer. A closed connection **can** be reopened by calling init again.
virtual void close();
void close();
/**
* Handle a ToRadio protobuf
@@ -86,7 +87,7 @@ class PhoneAPI
protected:
/// Our fromradio packet while it is being assembled
FromRadio fromRadioScratch;
FromRadio fromRadioScratch = {};
/** the last msec we heard from the client on the other side of this link */
uint32_t lastContactMsec = 0;
@@ -123,5 +124,5 @@ class PhoneAPI
bool handleToRadioPacket(MeshPacket &p);
/// If the mesh service tells us fromNum has changed, tell the phone
virtual int onNotify(uint32_t newValue);
virtual int onNotify(uint32_t newValue) override;
};

View File

@@ -8,7 +8,7 @@
template <class T> class PointerQueue : public TypedQueue<T *>
{
public:
PointerQueue(int maxElements) : TypedQueue<T *>(maxElements) {}
explicit PointerQueue(int maxElements) : TypedQueue<T *>(maxElements) {}
// returns a ptr or null if the queue was empty
T *dequeuePtr(TickType_t maxWait = portMAX_DELAY)

View File

@@ -2,10 +2,10 @@
#include "SinglePortPlugin.h"
/**
* A base class for mesh plugins that assume that they are sending/receiving one particular protobuf based
* A base class for mesh modules that assume that they are sending/receiving one particular protobuf based
* payload. Using one particular app ID.
*
* If you are using protobufs to encode your packets (recommended) you can use this as a baseclass for your plugin
* If you are using protobufs to encode your packets (recommended) you can use this as a baseclass for your module
* and avoid a bunch of boilerplate code.
*/
template <class T> class ProtobufPlugin : protected SinglePortPlugin
@@ -51,7 +51,7 @@ template <class T> class ProtobufPlugin : protected SinglePortPlugin
@return ProcessMessage::STOP if you've guaranteed you've handled this message and no other handlers should be considered for it
*/
virtual ProcessMessage handleReceived(const MeshPacket &mp)
virtual ProcessMessage handleReceived(const MeshPacket &mp) override
{
// FIXME - we currently update position data in the DB only if the message was a broadcast or destined to us
// it would be better to update even if the message was destined to others.
@@ -67,7 +67,7 @@ template <class T> class ProtobufPlugin : protected SinglePortPlugin
if (pb_decode_from_bytes(p.payload.bytes, p.payload.size, fields, &scratch))
decoded = &scratch;
else
DEBUG_MSG("Error decoding protobuf plugin!\n");
DEBUG_MSG("Error decoding protobuf module!\n");
}
return handleReceivedProtobuf(mp, decoded) ? ProcessMessage::STOP : ProcessMessage::CONTINUE;

View File

@@ -140,6 +140,8 @@ bool RF95Interface::reconfigure()
void RF95Interface::addReceiveMetadata(MeshPacket *mp)
{
mp->rx_snr = lora->getSNR();
mp->rx_rssi = lround(lora->getRSSI());
}
void RF95Interface::setStandby()

View File

@@ -9,31 +9,31 @@
*/
class RF95Interface : public RadioLibInterface
{
RadioLibRF95 *lora; // Either a RFM95 or RFM96 depending on what was stuffed on this board
RadioLibRF95 *lora = NULL; // Either a RFM95 or RFM96 depending on what was stuffed on this board
public:
RF95Interface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, SPIClass &spi);
bool isIRQPending() { return lora->getPendingIRQ(); }
bool isIRQPending() override { return lora->getPendingIRQ(); }
/// Initialise the Driver transport hardware and software.
/// Make sure the Driver is properly configured before calling init().
/// \return true if initialisation succeeded.
virtual bool init();
virtual bool init() override;
/// Apply any radio provisioning changes
/// Make sure the Driver is properly configured before calling init().
/// \return true if initialisation succeeded.
virtual bool reconfigure();
virtual bool reconfigure() override;
/// Prepare hardware for sleep. Call this _only_ for deep sleep, not needed for light sleep.
virtual bool sleep();
virtual bool sleep() override;
protected:
/**
* Glue functions called from ISR land
*/
virtual void disableInterrupt();
virtual void disableInterrupt() override;
/**
* Enable a particular ISR callback glue function
@@ -41,26 +41,26 @@ class RF95Interface : public RadioLibInterface
virtual void enableInterrupt(void (*callback)()) { lora->setDio0Action(callback); }
/** are we actively receiving a packet (only called during receiving state) */
virtual bool isActivelyReceiving();
virtual bool isActivelyReceiving() override;
/**
* Start waiting to receive a message
*/
virtual void startReceive();
virtual void startReceive() override;
/**
* Add SNR data to received messages
*/
virtual void addReceiveMetadata(MeshPacket *mp);
virtual void addReceiveMetadata(MeshPacket *mp) override;
virtual void setStandby();
virtual void setStandby() override;
/**
* We override to turn on transmitter power as needed.
*/
virtual void configHardwareForSend();
virtual void configHardwareForSend() override;
private:
/** Some boards require GPIO control of tx vs rx paths */
void setTransmitEnable(bool txon);
};
};

View File

@@ -1,4 +1,3 @@
#include "configuration.h"
#include "RadioInterface.h"
#include "Channels.h"
#include "MeshRadio.h"
@@ -6,45 +5,95 @@
#include "NodeDB.h"
#include "Router.h"
#include "assert.h"
#include "configuration.h"
#include "sleep.h"
#include <assert.h>
#include <pb_decode.h>
#include <pb_encode.h>
#define RDEF(name, freq, spacing, num_ch, power_limit) \
#define RDEF(name, freq_start, freq_end, duty_cycle, spacing, power_limit, audio_permitted, frequency_switching) \
{ \
RegionCode_##name, num_ch, power_limit, freq, spacing, #name \
RegionCode_##name, freq_start, freq_end, duty_cycle, spacing, power_limit, audio_permitted, frequency_switching, #name \
}
const RegionInfo regions[] = {
RDEF(US, 903.08f, 2.16f, 13, 0), RDEF(EU433, 433.175f, 0.2f, 8, 0), RDEF(EU865, 865.2f, 0.3f, 10, 0),
RDEF(CN, 470.0f, 2.0f, 20, 0),
RDEF(JP, 920.0f, 0.5f, 10, 13), // See https://github.com/meshtastic/Meshtastic-device/issues/346 power level 13
RDEF(ANZ, 916.0f, 0.5f, 20, 0), // AU/NZ channel settings 915-928MHz
RDEF(KR, 921.9f, 0.2f, 8, 0), // KR channel settings (KR920-923) Start from TTN download channel
// freq. (921.9f is for download, others are for uplink)
RDEF(TW, 923.0f, 0.2f, 10, 0), // TW channel settings (AS2 bandplan 923-925MHz)
RDEF(RU, 868.9f, 0.2f, 2, 20), // See notes below
RDEF(Unset, 903.08f, 2.16f, 13, 0) // Assume US freqs if unset, Must be last
/*
https://link.springer.com/content/pdf/bbm%3A978-1-4842-4357-2%2F1.pdf
https://www.thethingsnetwork.org/docs/lorawan/regional-parameters/
*/
RDEF(US, 902.0f, 928.0f, 100, 0, 30, true, false),
/*
https://lora-alliance.org/wp-content/uploads/2020/11/lorawan_regional_parameters_v1.0.3reva_0.pdf
*/
RDEF(EU433, 433.0f, 434.0f, 10, 0, 12, true, false),
/*
https://www.thethingsnetwork.org/docs/lorawan/duty-cycle/
https://www.thethingsnetwork.org/docs/lorawan/regional-parameters/
https://www.legislation.gov.uk/uksi/1999/930/schedule/6/part/III/made/data.xht?view=snippet&wrap=true
audio_permitted = false per regulation
*/
RDEF(EU868, 869.4f, 869.65f, 10, 0, 16, false, false),
/*
https://lora-alliance.org/wp-content/uploads/2020/11/lorawan_regional_parameters_v1.0.3reva_0.pdf
*/
RDEF(CN, 470.0f, 510.0f, 100, 0, 19, true, false),
/*
https://lora-alliance.org/wp-content/uploads/2020/11/lorawan_regional_parameters_v1.0.3reva_0.pdf
*/
RDEF(JP, 920.8f, 927.8f, 100, 0, 16, true, false),
/*
https://www.iot.org.au/wp/wp-content/uploads/2016/12/IoTSpectrumFactSheet.pdf
https://iotalliance.org.nz/wp-content/uploads/sites/4/2019/05/IoT-Spectrum-in-NZ-Briefing-Paper.pdf
*/
RDEF(ANZ, 915.0f, 928.0f, 100, 0, 30, true, false),
/*
https://digital.gov.ru/uploaded/files/prilozhenie-12-k-reshenyu-gkrch-18-46-03-1.pdf
Note:
- We do LBT, so 100% is allowed.
*/
RDEF(RU, 868.7f, 869.2f, 100, 0, 20, true, false),
/*
???
*/
RDEF(KR, 920.0f, 923.0f, 100, 0, 0, true, false),
/*
???
*/
RDEF(TW, 920.0f, 925.0f, 100, 0, 0, true, false),
/*
https://lora-alliance.org/wp-content/uploads/2020/11/lorawan_regional_parameters_v1.0.3reva_0.pdf
*/
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://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),
/*
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),
/*
This needs to be last. Same as US.
*/
RDEF(Unset, 902.0f, 928.0f, 100, 0, 30, true, false)
};
/* Notes about the RU bandplan (from @denis-d in https://meshtastic.discourse.group/t/russian-band-plan-proposal/2786/2):
According to Annex 12 to GKRCh (National Radio Frequency Commission) decision № 18-46-03-1 (September 11th 2018)
https://digital.gov.ru/uploaded/files/prilozhenie-12-k-reshenyu-gkrch-18-46-03-1.pdf 1 We have 3 options for 868 MHz:
864,0 - 865,0 MHz ERP 25mW, Duty Cycle 0.1% (3.6 sec in hour) or LBT (Listen Before Talk), prohibited in airports.
866,0 - 868,0 MHz ERP 25mW, Duty Cycle 1% or LBT, PSD (Power Spectrum Density) 1000mW/MHz, prohibited in airports
868,7 - 869,2 MHz ERP 100mW, Duty Cycle 10% or LBT, no resctrictions
and according to RP2-1.0.2 LoRaWAN® Regional Parameters RP2-1.0.2 LoRaWAN® Regional Parameters - LoRa Alliance®
I propose to use following meshtastic bandplan:
1 channel - central frequency 868.9MHz 125kHz band
Protective band - 75kHz
2 channel - central frequency 869.1MHz 125kHz band
RDEF(RU, 868.9f, 0.2f, 2, 20)
*/
const RegionInfo *myRegion;
void initRegion()
@@ -54,8 +103,6 @@ void initRegion()
;
myRegion = r;
DEBUG_MSG("Wanted region %d, using %s\n", radioConfig.preferences.region, r->name);
myNodeInfo.num_bands = myRegion->numChannels; // Tell our android app how many channels we have
}
/**
@@ -172,6 +219,9 @@ void printPacket(const char *prefix, const MeshPacket *p)
if (p->rx_snr != 0.0) {
DEBUG_MSG(" rxSNR=%g", p->rx_snr);
}
if (p->rx_rssi != 0) {
DEBUG_MSG(" rxSNR=%g", p->rx_rssi);
}
if (p->priority != 0)
DEBUG_MSG(" priority=%d", p->priority);
@@ -274,38 +324,40 @@ void RadioInterface::applyModemConfig()
auto channelSettings = channels.getPrimary();
if (channelSettings.spread_factor == 0) {
switch (channelSettings.modem_config) {
case ChannelSettings_ModemConfig_Bw125Cr45Sf128: ///< Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. Default medium
///< range
bw = 125;
cr = 5;
case ChannelSettings_ModemConfig_ShortFast:
bw = 250;
cr = 8;
sf = 7;
break;
case ChannelSettings_ModemConfig_Bw500Cr45Sf128: ///< Bw = 500 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. Fast+short
///< range
bw = 500;
cr = 5;
sf = 7;
case ChannelSettings_ModemConfig_ShortSlow:
bw = 250;
cr = 8;
sf = 8;
break;
case ChannelSettings_ModemConfig_Bw31_25Cr48Sf512: ///< Bw = 31.25 kHz, Cr = 4/8, Sf = 512chips/symbol, CRC on. Slow+long
///< range
bw = 31.25;
case ChannelSettings_ModemConfig_MidFast:
bw = 250;
cr = 8;
sf = 9;
break;
case ChannelSettings_ModemConfig_Bw125Cr48Sf4096:
case ChannelSettings_ModemConfig_MidSlow:
bw = 250;
cr = 8;
sf = 10;
break;
case ChannelSettings_ModemConfig_LongFast:
bw = 250;
cr = 8;
sf = 11;
break;
case ChannelSettings_ModemConfig_LongSlow:
bw = 125;
cr = 8;
sf = 12;
break;
case ChannelSettings_ModemConfig_Bw250Cr46Sf2048:
bw = 250;
cr = 6;
sf = 11;
break;
case ChannelSettings_ModemConfig_Bw250Cr47Sf1024:
bw = 250;
cr = 7;
sf = 10;
case ChannelSettings_ModemConfig_VLongSlow:
bw = 31.25;
cr = 8;
sf = 12;
break;
default:
assert(0); // Unknown enum
@@ -322,25 +374,26 @@ void RadioInterface::applyModemConfig()
}
power = channelSettings.tx_power;
shortPacketMsec = getPacketTime(sizeof(PacketHeader));
assert(myRegion); // Should have been found in init
// Calculate the number of channels
uint32_t numChannels = floor((myRegion->freqEnd - myRegion->freqStart) / (myRegion->spacing + (bw / 1000)));
// If user has manually specified a channel num, then use that, otherwise generate one by hashing the name
const char *channelName = channels.getName(channels.getPrimaryIndex());
int channel_num = channelSettings.channel_num ? channelSettings.channel_num - 1 : hash(channelName) % myRegion->numChannels;
float freq = myRegion->freq + radioConfig.preferences.frequency_offset + myRegion->spacing * channel_num;
int channel_num = channelSettings.channel_num ? channelSettings.channel_num - 1 : hash(channelName) % numChannels;
float freq = myRegion->freqStart + ((((myRegion->freqEnd - myRegion->freqStart) / numChannels) / 2) * channel_num);
saveChannelNum(channel_num);
saveFreq(freq);
DEBUG_MSG("Set radio: name=%s, config=%u, ch=%d, power=%d\n", channelName, channelSettings.modem_config, channel_num, power);
DEBUG_MSG("Radio myRegion->freq: %f\n", myRegion->freq);
DEBUG_MSG("Radio myRegion->spacing: %f\n", myRegion->spacing);
DEBUG_MSG("Radio myRegion->numChannels: %d\n", myRegion->numChannels);
DEBUG_MSG("Radio myRegion->freqStart / myRegion->freqEnd: %f -> %f (%f mhz)\n", myRegion->freqStart, myRegion->freqEnd,
myRegion->freqEnd - myRegion->freqStart);
DEBUG_MSG("Radio myRegion->numChannels: %d\n", numChannels);
DEBUG_MSG("Radio channel_num: %d\n", channel_num);
DEBUG_MSG("Radio frequency: %f\n", getFreq()); // the frequency could be overridden in RadioInterface::getFreq() for some modules
DEBUG_MSG("Radio frequency: %f\n", getFreq());
DEBUG_MSG("Short packet time: %u msec\n", shortPacketMsec);
}
@@ -404,4 +457,4 @@ size_t RadioInterface::beginSending(MeshPacket *p)
sendingPacket = p;
return p->encrypted.size + sizeof(PacketHeader);
}
}

View File

@@ -205,8 +205,8 @@ class RadioInterface
class SimRadio : public RadioInterface
{
public:
virtual ErrorCode send(MeshPacket *p);
virtual ErrorCode send(MeshPacket *p) override;
};
/// Debug printing for packets
void printPacket(const char *prefix, const MeshPacket *p);
void printPacket(const char *prefix, const MeshPacket *p);

View File

@@ -4,10 +4,6 @@
#include "RadioInterface.h"
#include "MeshPacketQueue.h"
#ifdef CubeCell_BoardPlus
#define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED
#endif
#define RADIOLIB_EXCLUDE_HTTP
#include <RadioLib.h>
@@ -58,7 +54,7 @@ class LockingModule : public Module
\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);
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
@@ -99,7 +95,7 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified
PhysicalLayer *iface;
/// are _trying_ to receive a packet currently (note - we might just be waiting for one)
bool isReceiving;
bool isReceiving = false;
public:
/** Our ISR code currently needs this to find our active instance
@@ -120,14 +116,14 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified
RadioLibInterface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy, SPIClass &spi,
PhysicalLayer *iface = NULL);
virtual ErrorCode send(MeshPacket *p);
virtual ErrorCode send(MeshPacket *p) override;
/**
* Return true if we think the board can go to sleep (i.e. our tx queue is empty, we are not sending or receiving)
*
* This method must be used before putting the CPU into deep or light sleep.
*/
virtual bool canSleep();
virtual bool canSleep() override;
/**
* Start waiting to receive a message
@@ -142,7 +138,7 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified
virtual bool isActivelyReceiving() = 0;
/** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */
virtual bool cancelSending(NodeNum from, PacketId id);
virtual bool cancelSending(NodeNum from, PacketId id) override;
private:
/** if we have something waiting to send, start a short random timer so we can come check for collision before actually doing
@@ -157,7 +153,7 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified
static void timerCallback(void *p1, uint32_t p2);
virtual void onNotify(uint32_t notification);
virtual void onNotify(uint32_t notification) override;
/** start an immediate transmit
* This method is virtual so subclasses can hook as needed, subclasses should not call directly
@@ -187,4 +183,4 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified
virtual void addReceiveMetadata(MeshPacket *mp) = 0;
virtual void setStandby() = 0;
};
};

View File

@@ -16,7 +16,7 @@ class RadioLibRF95: public SX1278 {
\param mod Instance of Module that will be used to communicate with the %LoRa chip.
*/
RadioLibRF95(Module* mod);
explicit RadioLibRF95(Module* mod);
// basic methods

View File

@@ -13,7 +13,7 @@ struct GlobalPacketId {
bool operator==(const GlobalPacketId &p) const { return node == p.node && id == p.id; }
GlobalPacketId(const MeshPacket *p)
explicit GlobalPacketId(const MeshPacket *p)
{
node = getFrom(p);
id = p->id;
@@ -33,10 +33,10 @@ struct PendingPacket {
MeshPacket *packet;
/** The next time we should try to retransmit this packet */
uint32_t nextTxMsec;
uint32_t nextTxMsec = 0;
/** Starts at NUM_RETRANSMISSIONS -1(normally 3) and counts down. Once zero it will be removed from the list */
uint8_t numRetransmissions;
uint8_t numRetransmissions = 0;
/** True if we have started trying to find a route - for DSR usage
* While trying to find a route we don't actually send the data packet. We just leave it here pending until
@@ -45,7 +45,7 @@ struct PendingPacket {
bool wantRoute = false;
PendingPacket() {}
PendingPacket(MeshPacket *p);
explicit PendingPacket(MeshPacket *p);
};
class GlobalPacketIdHashFunction
@@ -74,10 +74,10 @@ class ReliableRouter : public FloodingRouter
* later free() the packet to pool. This routine is not allowed to stall.
* If the txmit queue is full it might return an error
*/
virtual ErrorCode send(MeshPacket *p);
virtual ErrorCode send(MeshPacket *p) override;
/** Do our retransmission handling */
virtual int32_t runOnce()
virtual int32_t runOnce() override
{
// Note: We must doRetransmissions FIRST, because it might queue up work for the base class runOnce implementation
auto d = doRetransmissions();
@@ -91,7 +91,7 @@ class ReliableRouter : public FloodingRouter
/**
* Look for acks/naks or someone retransmitting us
*/
virtual void sniffReceived(const MeshPacket *p, const Routing *c);
virtual void sniffReceived(const MeshPacket *p, const Routing *c) override;
/**
* Try to find the pending packet record for this ID (or NULL if not found)
@@ -102,7 +102,7 @@ class ReliableRouter : public FloodingRouter
/**
* We hook this method so we can see packets before FloodingRouter says they should be discarded
*/
virtual bool shouldFilterReceived(MeshPacket *p);
virtual bool shouldFilterReceived(MeshPacket *p) override;
/**
* Add p to the list of packets to retransmit occasionally. We will free it once we stop retransmitting.

View File

@@ -6,7 +6,7 @@
#include "RTC.h"
#include "main.h"
#include "mesh-pb-constants.h"
#include "plugins/RoutingPlugin.h"
#include "modules/RoutingModule.h"
#if defined(HAS_WIFI) || defined(PORTDUINO)
#include "mqtt/MQTT.h"
@@ -132,7 +132,7 @@ MeshPacket *Router::allocForSending()
*/
void Router::sendAckNak(Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex)
{
routingPlugin->sendAckNak(err, to, idFrom, chIndex);
routingModule->sendAckNak(err, to, idFrom, chIndex);
}
void Router::abortSendAndNak(Routing_Error err, MeshPacket *p)
@@ -210,6 +210,33 @@ ErrorCode Router::send(MeshPacket *p)
if (p->which_payloadVariant == MeshPacket_decoded_tag) {
ChannelIndex chIndex = p->channel; // keep as a local because we are about to change it
#if defined(HAS_WIFI) || defined(PORTDUINO)
//check if we should send decrypted packets to mqtt
//truth table:
/* mqtt_server mqtt_encryption_enabled should_encrypt
* not set 0 1
* not set 1 1
* set 0 0
* set 1 1
*
* => so we only decrypt mqtt if they have a custom mqtt server AND mqtt_encryption_enabled is FALSE
*/
bool shouldActuallyEncrypt = true;
if (*radioConfig.preferences.mqtt_server && !radioConfig.preferences.mqtt_encryption_enabled) {
shouldActuallyEncrypt = false;
}
DEBUG_MSG("Should encrypt MQTT?: %d\n", shouldActuallyEncrypt);
//the packet is currently in a decrypted state. send it now if they want decrypted packets
if (mqtt && !shouldActuallyEncrypt)
mqtt->onSend(*p, chIndex);
#endif
auto encodeResult = perhapsEncode(p);
if (encodeResult != Routing_Error_NONE) {
abortSendAndNak(encodeResult, p);
@@ -217,7 +244,9 @@ ErrorCode Router::send(MeshPacket *p)
}
#if defined(HAS_WIFI) || defined(PORTDUINO)
if (mqtt)
//the packet is now encrypted.
//check if we should send encrypted packets to mqtt
if (mqtt && shouldActuallyEncrypt)
mqtt->onSend(*p, chIndex);
#endif
}
@@ -347,7 +376,7 @@ void Router::handleReceived(MeshPacket *p, RxSource src)
printPacket("packet decoding failed (no PSK?)", p);
}
// call plugins here
// call modules here
MeshPlugin::callPlugins(*p, src);
}
@@ -368,4 +397,4 @@ void Router::perhapsHandleReceived(MeshPacket *p)
handleReceived(p);
packetPool.release(p);
}
}

View File

@@ -37,7 +37,7 @@ class Router : protected concurrency::OSThread
* do idle processing
* Mostly looking in our incoming rxPacket queue and calling handleReceived.
*/
virtual int32_t runOnce();
virtual int32_t runOnce() override;
/**
* Works like send, but if we are sending to the local node, we directly put the message in the receive queue.
@@ -71,7 +71,7 @@ class Router : protected concurrency::OSThread
void enqueueReceivedMessage(MeshPacket *p);
protected:
friend class RoutingPlugin;
friend class RoutingModule;
/**
* Send a packet on a suitable interface. This routine will
@@ -85,7 +85,7 @@ class Router : protected concurrency::OSThread
/**
* Should this incoming filter be dropped?
*
* FIXME, move this into the new RoutingPlugin and do the filtering there using the regular plugin logic
* FIXME, move this into the new RoutingModule and do the filtering there using the regular module logic
*
* Called immedately on receiption, before any further processing.
* @return true to abandon the packet
@@ -143,4 +143,4 @@ extern Router *router;
/// Generate a unique packet id
// FIXME, move this someplace better
PacketId generatePacketId();
PacketId generatePacketId();

View File

@@ -9,7 +9,7 @@ class SX1268Interface : public SX126xInterface<SX1268>
{
public:
/// override frequency of the SX1268 module regardless of the region (use EU433 value)
virtual float getFreq() { return 433.175f; }
virtual float getFreq() override { return 433.175f; }
SX1268Interface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy, SPIClass &spi);
};
};

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